/**
 * Shared SSH port-forward tunnel + remote computer-helper provisioning.
 *
 * Two layers live here:
 *
 *  1. `startSSHTunnel` — the generic `ssh -L localPort:127.0.0.1:remotePort -N`
 *     spawn, extracted verbatim from the browser CDP driver so both the browser
 *     and `agents computer --device` reach a remote loopback service through one
 *     hardened tunnel. Behavior for the browser caller is unchanged (default,
 *     foreground, stderr-captured).
 *
 *  2. Remote computer-helper orchestration — resolve a registered device to an
 *     ssh target, push the cross-published Windows daemon exe, register it as a
 *     LOGON scheduled task (interactive session so real-desktop UIA/screenshot
 *     works and it survives the ssh disconnect), and open a tunnel the TS RPC
 *     client drives via TCP. Everything rides the existing `ssh-exec` /
 *     `devices/connect` primitives — no parallel SSH implementation.
 */
import { type ChildProcess } from 'child_process';
import { type DeviceProfile } from '../devices/registry.js';
export interface StartTunnelOptions {
    /**
     * Detach the tunnel so it OUTLIVES this CLI process. Used by
     * `agents computer start --device` — the tunnel must persist across separate
     * verb invocations (`apps`, `click`, …) until `stop --device` tears it down.
     * The browser driver leaves this false: it holds the tunnel for the lifetime
     * of one CDP session and kills it on cleanup.
     */
    detached?: boolean;
    extraSshArgs?: string[];
}
/** Build the ssh argv (after the `ssh` program name) for an `-L` tunnel. Pure.
 *
 * Composes the shared hardened baseline (`SSH_OPTS`) rather than re-listing it,
 * so the tunnel inherits the same options — crucially the keepalive, which lets
 * a dropped `-N` tunnel exit instead of lingering as a zombie on the laptop. */
export declare function buildTunnelArgs(user: string, host: string, localPort: number, remotePort: number, extraSshArgs?: string[]): string[];
/**
 * Spawn `ssh -L localPort:127.0.0.1:remotePort -N user@host`.
 *
 * Foreground (default): stderr is captured so a tunnel that dies inside 500ms
 * rejects with the ssh error — the browser driver's original contract. Detached
 * mode ignores stdio and `unref`s the child so the parent can exit while the
 * tunnel lives; liveness is then confirmed by the caller probing the service.
 */
export declare function startSSHTunnel(user: string, host: string, localPort: number, remotePort: number, opts?: StartTunnelOptions): Promise<ChildProcess>;
/** Loopback TCP port the Windows daemon binds on the remote (Program.cs default). */
export declare const REMOTE_HELPER_PORT = 8765;
/** Task Scheduler task name for the daemon. Stable so setup/stop pair up. */
export declare const REMOTE_TASK_NAME = "AgentsComputerHelper";
/** Basename of the cross-published exe under native/computer-win/dist. */
export declare const WIN_HELPER_EXE = "computer-helper-win.exe";
/** Basename of the daemon's shared-secret token file under %LOCALAPPDATA%\agents. */
export declare const WIN_HELPER_TOKEN_FILE = "helper-token";
/**
 * Locate a locally built Windows daemon exe — a repo-checkout build output from
 * `scripts/build-win.sh`, or one bundled next to the package. Local paths are
 * only the first candidate; npm-installed CLIs have neither and fall through to
 * the release-asset download (`ensureWinHelperExe`).
 */
export declare function resolveWinHelperExe(): string | null;
/** GitHub repo whose `computer-win/v<version>` releases carry the exe as an asset. */
export declare const WIN_HELPER_RELEASE_REPO = "phnx-labs/agi-cli";
/** Cache dir for downloaded helper exes, one subdir per release tag. */
export declare function winHelperCacheDir(version: string): string;
/** Release-asset URLs for the exe + its checksum at one exact `computer-win/v<version>` tag. */
export declare function winHelperAssetUrls(version: string): {
    exe: string;
    sha256: string;
};
/**
 * Parse the published `.sha256` asset — `sha256sum` format (`<hex>  <name>`) or
 * a bare hex digest. Throws on anything that does not lead with 64 hex chars.
 */
/**
 * Download the exe release asset for this HELPER version, verify its sha256
 * against the published `.sha256` asset, and cache it under the agents cache
 * dir. Only the exact `computer-win/v<version>` tag is consulted — a missing
 * asset is a hard error naming that tag, never a silent fallback to another
 * release. The version is the HELPER's own, not the CLI's.
 */
export declare function downloadWinHelperExe(version: string): Promise<string>;
/**
 * Resolve the helper exe for `setup --device`: local build outputs first (repo
 * checkout / bundled), then the checksum-verified release-asset download for
 * the running CLI version. Throws with the tag it checked when neither exists.
 */
export declare function ensureWinHelperExe(version?: string): Promise<string>;
/** Persisted per-device tunnel state so verbs can reconnect after `start --device`. */
export interface RemoteTunnelState {
    device: string;
    target: string;
    localPort: number;
    remotePort: number;
    tunnelPid: number;
    token: string | null;
    taskName: string;
    startedAt: number;
}
/** State file path for a device. Device names are ssh-alias safe (validated). */
export declare function remoteStatePath(device: string): string;
export declare function readRemoteState(device: string): RemoteTunnelState | null;
export declare function writeRemoteState(state: RemoteTunnelState): void;
export declare function clearRemoteState(device: string): void;
/**
 * Local file holding the shared-secret token for a device's helper daemon.
 * Written at `setup --device` (0600), read at `start --device` so the RPC client
 * authenticates. The remote daemon reads the same value from its own
 * `--token-file`; the CLI is the source of truth and never round-trips it back.
 */
export declare function helperTokenPath(device: string): string;
export declare function readHelperToken(device: string): string | null;
export declare function writeHelperToken(device: string, token: string): void;
export declare function clearHelperToken(device: string): void;
/** Resolve a registered device to its ssh pieces, or throw a clear error. */
export declare function resolveRemoteDevice(name: string): Promise<{
    device: DeviceProfile;
    target: string;
    user: string;
    host: string;
}>;
/**
 * PowerShell that resolves the destination under %LOCALAPPDATA%\agents and
 * stops any running instance first so the file is not locked. The caller copies
 * the exe with scp and then verifies the byte count separately.
 */
export declare function buildPushScript(): string;
/** PowerShell that verifies scp wrote the expected number of bytes. */
export declare function buildVerifyPushScript(remotePath: string, expectedBytes: number): string;
/**
 * PowerShell that registers the daemon as a LOGON scheduled task. Interactive
 * logon type + Highest run level so the daemon runs in the real desktop session
 * (UIAutomation and ScreenCapture need a live session, not Session 0) and
 * survives ssh disconnect — the same rationale as the browser WMI launch. The
 * task is started immediately so the caller need not log out/in.
 */
/**
 * PowerShell that writes the shared-secret token under %LOCALAPPDATA%\agents
 * with an owner-only ACL (inheritance removed, read granted only to the current
 * user) and echoes the resolved path so the caller can pass it to `--token-file`.
 */
export declare function buildWriteTokenScript(token: string): string;
export declare function buildRegisterTaskScript(port: number, taskName: string, tokenPath: string): string;
/** PowerShell that unregisters the task and stops any running daemon process. */
export declare function buildUnregisterTaskScript(taskName: string): string;
/** Convert a Windows path returned by PowerShell into the scp/SFTP path form. */
export declare function scpRemotePath(remotePath: string): string;
/**
 * Build the scp argv used for the helper exe transfer. Exported so tests can
 * assert the real binary copy path keeps BatchMode and does not route bytes
 * through a PowerShell decoder.
 */
export declare function buildScpArgs(target: string, remotePath: string, filePath: string, extraSshArgs?: string[]): string[];
/**
 * `setup --device`: push the exe, then register + start the LOGON task. Remote
 * PowerShell hops go through `sshExec` (BatchMode key auth — the same hardening
 * the browser driver and `agents ssh` use), and the large exe rides a binary
 * scp transfer. Throws with the remote stderr on any failure.
 */
export declare function setupRemoteHelper(name: string): Promise<{
    target: string;
    taskName: string;
}>;
/** Reserve a free local TCP port by binding :0 and reading the assigned port. */
export declare function pickFreePort(): Promise<number>;
/**
 * `start --device`: open a detached ssh -L tunnel to the remote daemon, verify it
 * answers over TCP, and persist the tunnel state so verbs can reconnect. Returns
 * the state (and leaves the tunnel running in the background).
 */
export declare function startRemoteTunnel(name: string): Promise<RemoteTunnelState>;
/**
 * `stop --device`: kill the local tunnel, unregister the remote task (best-effort
 * — the box may be offline), and clear the persisted state.
 */
export declare function stopRemoteHelper(name: string): Promise<{
    tunnelKilled: boolean;
    taskRemoved: boolean;
}>;
/**
 * Point this process's RPC client at a device's live tunnel by setting
 * COMPUTER_HELPER_TCP / COMPUTER_HELPER_TOKEN from persisted state. Called for
 * remote verbs (`apps --device`, `click --device`, …) so the shared
 * openComputerClient() transparently selects the TcpClient transport — no
 * per-verb wiring. Exits with guidance when there is no active tunnel.
 */
export declare function hydrateRemoteEnvFromState(name: string): void;
/** Generate a shared-secret token (reserved for token-file provisioning). */
export declare function generateToken(): string;
