/** * Interactive-terminal launcher: turn a vended SSM session payload into a real * TTY by driving the locally installed `session-manager-plugin`. * * Node-only: spawns a child process with an inherited TTY, which is why it * lives behind `@indigoai-us/hq-cloud/outposts/node` rather than the portable * entry point (mirrors `ssh.ts`). * * Deliberately box-flavor-agnostic: it takes the SESSION PAYLOAD, not an * outpostId — hq-cli's `hq agents terminal` reuses the same launcher with the * `/v1/agents/{uid}/terminal` response, and `hq outposts terminal` with the * `/outpost/terminal` one (the two routes vend the identical shape). * * SECURITY: the plugin's argv carries the StartSession response JSON — the * one-time `tokenValue` included. That is the plugin's own contract (the AWS * CLI passes exactly the same argv), and the token is single-use and * short-lived, but it means the credential is briefly visible in local `ps` * output. Never LOG any of these values; nothing in this module prints them. */ import { spawn as nodeSpawn } from "node:child_process"; /** * The subset of the terminal-session payload the launcher needs. Structurally * satisfied by `OutpostTerminalSession` and by the agents-route response. */ export interface TerminalSessionPayload { sessionId: string; /** SENSITIVE — one-time session credential. Never print, log, or persist. */ tokenValue: string; streamUrl: string; region: string; /** SSM control-plane endpoint, e.g. `https://ssm.us-east-1.amazonaws.com`. */ endpoint: string; /** Echo of the StartSession request (session resume support). */ request: { Target: string; DocumentName?: string; Parameters?: Record; }; } /** The binary the launcher drives. Installed separately from the AWS CLI. */ export declare const SESSION_MANAGER_PLUGIN_BINARY = "session-manager-plugin"; /** Printed when the plugin binary is missing — the #1 first-run failure. */ export declare const SESSION_MANAGER_PLUGIN_INSTALL_HINT: string; /** * Build the plugin's positional argv — the AWS CLI's exact contract: * 1. the StartSession RESPONSE json ({SessionId, TokenValue, StreamUrl}) * 2. the region * 3. the literal operation name `StartSession` * 4. the AWS profile name (empty — no client-side AWS identity exists) * 5. the StartSession REQUEST json (lets the plugin resume a dropped session) * 6. the SSM control-plane endpoint */ export declare function buildSessionManagerPluginArgs(session: TerminalSessionPayload): string[]; /** Injectable seam so tests never spawn a real process (repo ESM policy: no builtin spies). */ export interface LaunchSessionManagerPluginDeps { spawn?: typeof nodeSpawn; } /** A launch that never ran (missing binary / spawn failure), with a user-facing hint. */ export declare class SessionManagerPluginLaunchError extends Error { constructor(message: string); } /** * Hand the TTY to `session-manager-plugin` and resolve with its exit code once * the session ends. stdio is inherited, so the caller's terminal IS the * session; Ctrl-C is forwarded to the remote shell by the plugin (the parent * ignores SIGINT for the duration instead of dying and orphaning the TTY). * * Rejects with {@link SessionManagerPluginLaunchError} when the plugin cannot * start at all — ENOENT carries the install hint. */ export declare function launchSessionManagerPlugin(session: TerminalSessionPayload, deps?: LaunchSessionManagerPluginDeps): Promise; /** One attempt outcome for {@link waitForTerminalSession}'s poll loop. */ export type TerminalSessionAttempt = { kind: "ready"; session: T; } | { kind: "starting"; state: "starting-instance" | "awaiting-ssm"; retryAfterSeconds?: number; }; export interface WaitForTerminalSessionOptions { /** Called once per `starting` result — render a status line to stderr. */ onStatus?: (state: "starting-instance" | "awaiting-ssm") => void; /** Fallback poll interval when the server names no retryAfterSeconds. */ pollMs?: number; /** Overall budget before giving up (box start + SSM registration ≈ 1-2 min). */ timeoutMs?: number; sleep?: (ms: number) => Promise; now?: () => number; } /** The poll budget ran out — the box never came up in time. */ export declare class TerminalSessionTimeoutError extends Error { constructor(timeoutMs: number); } /** * The canonical 202-retry loop shared by `hq outposts terminal` and * `hq agents terminal`: call `attempt()` until it reports `ready`, sleeping * the server-suggested `retryAfterSeconds` (else `pollMs`) between calls, * bounded by `timeoutMs`. Both CLIs map their own wire types into * {@link TerminalSessionAttempt}; errors from `attempt()` propagate untouched. */ export declare function waitForTerminalSession(attempt: () => Promise>, options?: WaitForTerminalSessionOptions): Promise; //# sourceMappingURL=terminal.d.ts.map