/**
 * Host readiness + bootstrap.
 *
 * Before a dispatch we ensure the box is reachable and has agents-cli. Enrollment
 * can additionally install/upgrade agents-cli to match the local version (version
 * parity) using the same shape as scripts/sandbox.sh. We never copy `.history`.
 */
import type { Host } from './types.js';
/** Resolve this CLI's own version by walking up to the nearest package.json. */
export declare function localCliVersion(): string | null;
/** ssh command that confirms reachability and echoes the OS. POSIX boxes answer
 * `uname -s`; a Windows target has no `uname` (ssh lands in cmd.exe/PowerShell),
 * so it runs a tiny PowerShell probe. Pure/exported so both branches are
 * unit-testable without ssh. */
export declare function buildProbeCommand(os?: string): string;
/**
 * Reachability + OS probe over ssh. `os` is the caller's hint (device-registry
 * platform / enrolled `HostEntry.os`); when it marks the host Windows we take
 * the PowerShell path and report that known platform, otherwise POSIX + uname.
 */
export declare function probeHost(target: string, os?: string, extraSshArgs?: string[]): {
    reachable: boolean;
    os?: string;
};
/** ssh command that prints the remote agents-cli version. Pure/exported. */
export declare function buildRemoteVersionCommand(os?: string): string;
/** Remote agents-cli version (PATH-resolved on the remote), or null if not installed. */
export declare function remoteAgentsVersion(target: string, os?: string, extraSshArgs?: string[]): string | null;
/** ssh command that installs/upgrades agents-cli to `spec` then `agents setup`.
 * PowerShell has no `tail`/`[ -d ]`/`||`, so the Windows branch uses native
 * equivalents (`Select-Object -Last`, `Test-Path`). Pure/exported. */
export declare function buildBootstrapCommand(spec: string, os?: string): string;
/** Install (or upgrade to) a specific agents-cli version on the remote, then `agents setup`. */
export declare function bootstrapAgentsCli(target: string, version: string | null, os?: string, extraSshArgs?: string[]): {
    ok: boolean;
    output: string;
};
export interface ReadyProbe {
    /** ssh connected and the remote login shell ran (our sentinel came back). */
    reachable: boolean;
    /** Remote agents-cli version (no leading `v`), or null if not installed. */
    version: string | null;
    /** Raw `agents view`/`list` output, for installed-agent checks. */
    view: string;
    /** True when the ssh probe timed out before the sentinel arrived. */
    timedOut?: boolean;
}
/**
 * Answer every readiness question in ONE ssh round-trip: reachable? (the login
 * shell ran and echoed our sentinel), agents-cli version, and the installed-agent
 * listing. This replaces three sequential probes (`true` + `agents --version` +
 * `agents view`) — 3 handshakes collapse to 1. Reachability keys off the sentinel
 * rather than the exit code, so a command that ran-but-failed is never mistaken
 * for a dead connection (only ssh's own failure drops the sentinel).
 */
/**
 * The one-shot readiness command (version + sentinel + agent listing). The
 * Windows branch emits the sentinel with `Write-Output` and branches on
 * `$LASTEXITCODE` (no `printf`/`||`); `parseReadyProbe` keys off the sentinel
 * substring, so the missing leading newline vs the POSIX `printf '\n…'` form is
 * absorbed by its `.trim()`. Pure/exported so both branches are unit-testable.
 */
export declare function buildReadyProbeCommand(os?: string): string;
export declare function readyProbe(target: string, os?: string, extraSshArgs?: string[]): ReadyProbe;
/** Pure parser for `readyProbe` output (unit-tested without ssh). */
export declare function parseReadyProbe(stdout: string): ReadyProbe;
/** True if `view` output lists the named agent (word-boundary, case-insensitive). */
export declare function viewHasAgent(view: string, agent: string): boolean;
/**
 * True when `version` is a concrete pin the remote must already have installed
 * (e.g. `0.145.0`, `2.1.207`). Aliases (`latest` / `oldest` / `pinned` /
 * `default` / `all` / `any`) resolve against the remote's own install set and
 * are not preflight-checked here.
 */
export declare function isConcreteVersionPin(version?: string | null): boolean;
/**
 * Installed version strings for `agent` from `agents view --json` output.
 * Returns `[]` when the agent row is absent, `undefined` when `view` is not
 * JSON (text `agents list` fallback) so callers can degrade.
 */
export declare function viewAgentVersions(view: string, agent: string): string[] | undefined;
/**
 * Whether a concrete `agent@version` is installed according to remote view
 * output. JSON path is authoritative; text listing falls back to a whole-token
 * version match. `undefined` only when the text path has the agent but no
 * version token to confirm against (callers treat that as unverified).
 */
export declare function viewHasAgentVersion(view: string, agent: string, version: string): boolean | undefined;
/** Actionable fail-loud message for a missing remote pin (RUSH-2313). */
export declare function missingPinnedVersionMessage(hostName: string, agent: string, version: string, installed?: string[]): string;
/** Account eligibility extracted from one device's `agents view --json`. */
export interface ViewAgentAccountEligibility {
    /** At least one account can launch immediately. */
    signedIn: boolean | undefined;
    /** At least one account can launch immediately or enter the harness login flow. */
    pickerEligible: boolean | undefined;
}
/**
 * Read the two account gates automatic placement needs from `agents view
 * --json`. A picker may route to a signed-out version because launching it is
 * the login flow, but it must not route to a device whose every signed-in
 * account is throttled.
 *
 * The sign-in gate reads the per-version `launchable` field — the strict
 * per-version launch truth (`isLaunchableSignedIn`) — so a remote box is judged
 * by the SAME launchability the local candidate uses (`collectRunCandidates` →
 * `isLaunchableSignedIn`), not the display `signedIn` that inherits the
 * active/global HOME login and passes a box that dies at spawn (PHNX-3466). An
 * older remote CLI omits `launchable`, so it falls back to `signedIn` — the
 * pre-fix behavior, so a rolling fleet does not regress.
 */
export declare function viewAgentAccountEligibility(view: string, agent: string, now?: number): ViewAgentAccountEligibility;
export declare function viewAgentSignedIn(view: string, agent: string): boolean | undefined;
export interface EnsureReadyOptions {
    agent: string;
    /**
     * Explicit version pin (e.g. `"0.145.0"`). Concrete pins fail loud when the
     * remote does not have that version installed so a detached `--no-follow`
     * dispatch never reports "Dispatched" for a pin the box cannot run
     * (RUSH-2313). Aliases (`latest` / …) are left for the remote CLI to resolve.
     */
    version?: string;
    /** Throw instead of warn when the agent isn't installed remotely. */
    requireAgent?: boolean;
}
/**
 * Pure readiness verdict for the agent/version half of {@link ensureHostReady}
 * (unit-tested without SSH). Returns warnings for soft agent-missing cases, or
 * throws (via the caller's `throw new Error`) when a concrete pin is missing.
 */
export declare function evaluateHostAgentInstall(view: string, opts: EnsureReadyOptions, hostName: string): {
    warnings: string[];
};
/**
 * Verify a host can run the agent: reachable + agents-cli present. Throws with an
 * actionable message otherwise. Agent-not-installed is a warning by default (the
 * remote `agents run` will surface it); pass requireAgent to make it fatal.
 * A concrete `version` pin always fails loud when that version is absent
 * (RUSH-2313) — never a silent "Dispatched" for a pin the box cannot run.
 *
 * One ssh round-trip (`readyProbe`) covers all three checks.
 */
export declare function ensureHostReady(host: Host, opts: EnsureReadyOptions): {
    warnings: string[];
};
