@agentproto/acp 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/tunnel/frames.ts","../../src/tunnel/server.ts","../../src/tunnel/client.ts","../../src/tunnel/ws-adapter.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Tunnel frame protocol — agentproto/tunnel/v1.\n *\n * Bidirectional, event-shaped frames over a single duplex transport\n * (typically a WebSocket). Each frame is one JSON object per message.\n * The protocol is deliberately NOT JSON-RPC: process I/O is a\n * continuous event stream, not a request/response pattern, so we drop\n * the `id` / response correlation and let the underlying child-process\n * lifecycle drive everything.\n *\n * # Roles\n *\n * host — the orchestrator (e.g. Guilde API). Sends `spawn`,\n * `stdin`, `kill`, `resize`. Receives `stdout`, `stderr`,\n * `exit`, `error`. Holds the ACP client; sees the duplex\n * stream as a `ChildProcess`-shaped duck.\n *\n * daemon — the local executor (e.g. `agentproto serve` on a user's\n * laptop). Receives spawn-side frames; spawns real\n * subprocesses; relays I/O back. Owns the actual file\n * system, environment, network egress.\n *\n * # Identifiers\n *\n * execId — host-chosen UUID per spawned process. Lets one tunnel\n * multiplex many concurrent agent CLIs (one daemon serving\n * several conversations).\n *\n * # Encoding\n *\n * - Each WS message is one JSON object. Binary frames are not used;\n * stdout/stdin payloads are base64-encoded utf-safe strings.\n * - Why base64 and not raw text: claude-code & friends emit JSON-RPC\n * ACP traffic over stdio. A child can also emit non-utf8 bytes\n * (debug logs, terminal control codes when in TTY mode). Base64\n * keeps the wire JSON-clean and bytewise-faithful.\n * - All frames carry `t` (type) and a per-type payload. Versioning\n * is per-tunnel via `hello.version`, not per-frame.\n *\n * # Lifecycle\n *\n * 1. Daemon connects to host's WS endpoint with bearer token.\n * 2. Daemon sends `hello { version, capabilities, label? }`.\n * 3. Host sends `spawn` for each child it wants on this daemon.\n * 4. Daemon spawns, replies with `spawned { execId, pid }` (or\n * `error { execId, message }`).\n * 5. stdout/stderr/exit notifications flow daemon→host;\n * stdin/resize/kill flow host→daemon.\n * 6. Either side can send `ping`; receiver MUST `pong` back. Used\n * to detect half-open connections.\n * 7. On disconnect, daemon SHOULD kill all children associated with\n * this tunnel (host can re-spawn after reconnect).\n */\n\nexport const TUNNEL_VERSION = \"agentproto/tunnel/v1\" as const\n\n// ─── host → daemon ──────────────────────────────────────────────\n\nexport interface SpawnFrame {\n t: \"spawn\"\n execId: string\n command: string\n args: readonly string[]\n /**\n * Working directory on the daemon side. Daemon SHOULD reject\n * absolute paths that escape its declared `--root` (see\n * `agentproto serve --root`); host MUST pass paths that exist\n * on the daemon.\n */\n cwd?: string\n /**\n * Environment overrides. Daemon merges these atop its own\n * process.env. Daemon MAY redact values from logs but MUST forward\n * them verbatim into the child.\n */\n env?: Readonly<Record<string, string>>\n /**\n * When true, the daemon allocates a PTY instead of plain pipes.\n * Required for binaries that detect `isTTY` (REPLs, claude\n * interactive). When false (default), stdin/stdout/stderr are\n * separate pipes — the right choice for ACP wrappers that speak\n * line-delimited JSON-RPC.\n */\n pty?: boolean\n /** Initial PTY column width. Ignored when `pty` is false. Default 80. */\n cols?: number\n /** Initial PTY row height. Ignored when `pty` is false. Default 24. */\n rows?: number\n}\n\nexport interface StdinFrame {\n t: \"stdin\"\n execId: string\n /** Base64-encoded payload bytes. Empty string is a no-op. */\n data: string\n}\n\nexport interface KillFrame {\n t: \"kill\"\n execId: string\n /** Default \"SIGTERM\". POSIX names; Windows daemons translate. */\n signal?: string\n}\n\nexport interface ResizeFrame {\n t: \"resize\"\n execId: string\n cols: number\n rows: number\n}\n\n/**\n * Generic HTTP-over-tunnel request (HOST → DAEMON). Lets the host\n * proxy arbitrary HTTP traffic (MCP JSON-RPC today, anything tomorrow)\n * through the daemon's local network stack without exposing a public\n * URL. The daemon forwards to its configured \"http upstream\" (default:\n * its own gateway on `127.0.0.1:<port>`) and replies with an\n * `HttpResponseFrame` carrying the same `reqId`.\n */\nexport interface HttpRequestFrame {\n t: \"http_request\"\n /** Correlates the response. Host-chosen, MUST be unique per inflight request. */\n reqId: string\n /** HTTP method (GET / POST / PUT / DELETE / PATCH / OPTIONS). */\n method: string\n /** Path + querystring, e.g. `/mcp` or `/mcp?session=abc`.\n * Daemon prepends its upstream base. Absolute URLs are rejected. */\n path: string\n /** Forwarded request headers. Hop-by-hop headers (Connection,\n * Keep-Alive, Transfer-Encoding, Upgrade, Proxy-*) MUST be stripped\n * before forwarding; daemon SHOULD also drop them defensively. */\n headers?: Readonly<Record<string, string>>\n /** Base64-encoded request body. Omitted when no body. */\n body?: string\n /** Per-request timeout in ms. Daemon SHOULD enforce + reply with\n * `error: { code: \"timeout\" }` when exceeded. Default 30_000. */\n timeoutMs?: number\n}\n\n/**\n * Generic HTTP-over-tunnel response (DAEMON → HOST). Mirrors\n * `HttpRequestFrame` — see its docs.\n *\n * Two-frame protocol:\n * - SHORT RESPONSES (most HTTP): daemon emits a single `http_response`\n * with body inline. The buffered `forwardHttp` resolves directly\n * from this frame.\n * - STREAMED RESPONSES (text/event-stream, long-lived chunked\n * transfers, large downloads): daemon emits `http_response_head`\n * first with status+headers, then one or more `http_response_chunk`\n * frames, the last of which has `end: true`. The streaming\n * `forwardHttpStream` builds a `ReadableStream` from the chunks.\n *\n * Hosts that only support the legacy buffered API can detect the\n * stream protocol by looking for `http_response_head` and either\n * pull the chunks into a buffer (compat) or refuse to handle.\n */\nexport interface HttpResponseFrame {\n t: \"http_response\"\n reqId: string\n /** HTTP status code (e.g. 200, 404, 500). Set even on transport\n * failure (then `error` is also set and status SHOULD be 502/504). */\n status: number\n headers?: Readonly<Record<string, string>>\n /** Base64-encoded response body. */\n body?: string\n /** Set when the daemon failed to complete the upstream call. */\n error?: Readonly<{\n code: string\n message: string\n }>\n}\n\n/**\n * Streaming HTTP response head (DAEMON → HOST). Sent ONCE per\n * streaming response, before any chunk frames. Carries status +\n * headers so the host can finalize the response shape (e.g. write\n * Content-Type) before any body bytes arrive.\n */\nexport interface HttpResponseHeadFrame {\n t: \"http_response_head\"\n reqId: string\n status: number\n headers?: Readonly<Record<string, string>>\n}\n\n/**\n * Streaming HTTP response body chunk (DAEMON → HOST). Each chunk\n * carries some bytes of the response body. The terminal chunk has\n * `end: true` and MAY include final bytes. An immediate `end: true`\n * with no data signals empty-body close.\n *\n * `error` set on a chunk frame indicates the daemon's upstream\n * failed mid-stream; host SHOULD propagate it as a stream error.\n */\nexport interface HttpResponseChunkFrame {\n t: \"http_response_chunk\"\n reqId: string\n /** Base64-encoded chunk bytes. Omitted on pure end-of-stream\n * markers (those carry `end: true` only). */\n data?: string\n /** Set on the last chunk. After this frame the host SHOULD ignore\n * any further frames for this reqId. */\n end?: boolean\n /** Set when the upstream failed mid-stream. Host surfaces this as\n * a stream error and closes the readable. */\n error?: Readonly<{\n code: string\n message: string\n }>\n}\n\n// ─── daemon → host ──────────────────────────────────────────────\n\nexport interface HelloFrame {\n t: \"hello\"\n version: typeof TUNNEL_VERSION\n /**\n * Daemon-declared capabilities. Hosts MAY refuse to dispatch\n * features the daemon hasn't claimed.\n */\n capabilities: Readonly<{\n pty: boolean\n /** Daemon can bridge browser-WS upgrades to its local upstream via\n * `ws_open` / `ws_message` / `ws_close`. Hosts MUST gate\n * `forwardWebSocket()` on this — older daemons ignore the frames. */\n wsForward?: boolean\n /**\n * Identifiers of the capabilities the daemon serves — its registered\n * agent adapters / tool surfaces. Lets a host that fronts several\n * daemons enumerate and route by what each one can do, without a\n * round-trip. Omitted by older daemons (host treats as \"unknown\",\n * not \"none\"). Advisory: the authoritative surface is still the\n * daemon's live `tools/list` over the HTTP relay.\n */\n tools?: ReadonlyArray<string>\n /** Future: file-transfer, port-forward, etc. */\n }>\n /** User-friendly daemon label, surfaced in host UIs. */\n label?: string\n /** Daemon process info — diagnostics only, not authoritative. */\n daemon?: Readonly<{\n name: string\n version: string\n platform: string\n nodeVersion?: string\n }>\n}\n\nexport interface SpawnedFrame {\n t: \"spawned\"\n execId: string\n pid: number\n}\n\nexport interface StdoutFrame {\n t: \"stdout\"\n execId: string\n /** Base64-encoded payload bytes. */\n data: string\n}\n\nexport interface StderrFrame {\n t: \"stderr\"\n execId: string\n /** Base64-encoded payload bytes. */\n data: string\n}\n\nexport interface ExitFrame {\n t: \"exit\"\n execId: string\n /** Null when killed by signal. */\n code: number | null\n /** POSIX signal name when killed by signal; null otherwise. */\n signal: string | null\n}\n\n// ─── either direction ───────────────────────────────────────────\n\nexport interface ErrorFrame {\n t: \"error\"\n /** Omitted for tunnel-level errors not tied to a specific exec. */\n execId?: string\n /** Stable machine-readable code, e.g. \"spawn_failed\", \"unknown_exec\". */\n code: string\n /** Human-readable diagnostic. */\n message: string\n}\n\nexport interface PingFrame {\n t: \"ping\"\n /** Echoed verbatim in the matching pong. */\n nonce: string\n}\n\nexport interface PongFrame {\n t: \"pong\"\n nonce: string\n}\n\n/**\n * HOST → DAEMON. Graceful drain signal sent during host rollover (e.g.\n * Kubernetes preStop). On receipt the daemon SHOULD:\n * 1. Stop accepting new in-flight work where it can.\n * 2. Close the WS cleanly (does not need to wait — host will follow\n * up with a `close(1012, \"service_restart\")` ~2 s later as a\n * hard backstop).\n * 3. Reconnect IMMEDIATELY without the usual exponential backoff —\n * the host is mid-deploy, the new replica is already listening.\n *\n * Backward-compatible: daemons that don't know the frame just ignore\n * it (parseFrame returns null for unknown types). The host's close\n * then triggers the daemon's normal backoff loop — worst case ~30 s\n * reconnect gap instead of ~2 s with the handler.\n */\nexport interface ReconnectSoonFrame {\n t: \"reconnect_soon\"\n /** Hint of how long the host plans to wait before forcing close.\n * Optional — daemons MAY use it to decide whether to finish\n * in-flight work or close immediately. */\n reasonMs?: number\n}\n\n// ─── WebSocket forwarding ───────────────────────────────────────\n//\n// Mirrors the HTTP-forwarding shape but for full-duplex upgrades.\n// The daemon opens a WS connection to its local upstream (typically\n// `ws://127.0.0.1:<port>${path}`), then proxies frames in both\n// directions. Each open is correlated by `reqId`.\n//\n// Capabilities: daemons MUST set `hello.capabilities.wsForward = true`\n// to opt in. Hosts that don't see it MUST NOT send `ws_open`. Older\n// daemons silently ignore unknown frames, so misrouted `ws_open` on a\n// non-capable daemon is benign (the host's open will time out).\n\n/**\n * HOST → DAEMON. Open a WS connection to the daemon's upstream.\n * Path semantics match `HttpRequestFrame` — absolute URLs rejected,\n * daemon prepends its `ws://<upstream>` base. Headers forwarded as-is\n * (cookies are typically NOT forwarded since the daemon's upstream is\n * loopback; cookie passthrough is opt-in via daemon config).\n */\nexport interface WsOpenFrame {\n t: \"ws_open\"\n /** Correlates every WS frame in both directions for this connection. */\n reqId: string\n /** Path + querystring on the daemon-local upstream, e.g.\n * `/sessions/abc/pty?cols=80&rows=24`. */\n path: string\n /** Optional registered upstream to dial instead of the daemon's\n * default gateway — a NAME the daemon resolves to a base URL (never\n * a URL itself, so the host can't point the daemon at an arbitrary\n * origin). Used to reach an imported local service (e.g. a browser\n * capability server) by alias. Absent ⇒ the daemon's own gateway. */\n upstream?: string\n /** Headers to set on the upstream WS request. Hop-by-hop headers\n * (Connection, Upgrade, Sec-WebSocket-*) MUST be stripped — the\n * daemon's `ws` client manages those. */\n headers?: Readonly<Record<string, string>>\n /** Subprotocols requested by the browser; forwarded to upstream. */\n protocols?: readonly string[]\n}\n\n/**\n * DAEMON → HOST. Result of a `ws_open`. On success the upstream WS is\n * connected and frames can flow. On failure `error` is set; no further\n * frames for this `reqId` will arrive.\n */\nexport interface WsOpenAckFrame {\n t: \"ws_open_ack\"\n reqId: string\n /** HTTP status from the upstream upgrade. 101 on success; 4xx/5xx\n * when the upstream refused the upgrade. */\n status: number\n /** Selected subprotocol, if any. */\n protocol?: string\n /** Set when the daemon couldn't open the upstream (DNS failure,\n * refused, timeout). Distinct from a clean upstream-side close,\n * which arrives as `ws_close`. */\n error?: Readonly<{\n code: string\n message: string\n }>\n}\n\n/**\n * Either direction. One application-level WS frame's payload. Text\n * frames carry UTF-8 bytes (`binary: false`); binary frames carry\n * arbitrary bytes (`binary: true`). The `data` field is base64-encoded\n * either way so the transport stays JSON.\n */\nexport interface WsMessageFrame {\n t: \"ws_message\"\n reqId: string\n /** Base64-encoded WS frame payload. */\n data: string\n /** True for binary frames; false (or omitted) for text. */\n binary?: boolean\n}\n\n/**\n * Either direction. Close the bridged WS connection. Includes the\n * close code (1000 normal, 1006 abnormal, etc.) and optional reason.\n * After sending or receiving this frame, neither side will send\n * further frames for `reqId`.\n */\nexport interface WsCloseFrame {\n t: \"ws_close\"\n reqId: string\n /** WebSocket close code. */\n code: number\n reason?: string\n}\n\n// ─── union + guards ─────────────────────────────────────────────\n\nexport type HostToDaemonFrame =\n | SpawnFrame\n | StdinFrame\n | KillFrame\n | ResizeFrame\n | HttpRequestFrame\n | WsOpenFrame\n | WsMessageFrame\n | WsCloseFrame\n | PingFrame\n | PongFrame\n | ErrorFrame\n | ReconnectSoonFrame\n\nexport type DaemonToHostFrame =\n | HelloFrame\n | SpawnedFrame\n | StdoutFrame\n | StderrFrame\n | ExitFrame\n | HttpResponseFrame\n | HttpResponseHeadFrame\n | HttpResponseChunkFrame\n | WsOpenAckFrame\n | WsMessageFrame\n | WsCloseFrame\n | PingFrame\n | PongFrame\n | ErrorFrame\n\nexport type TunnelFrame = HostToDaemonFrame | DaemonToHostFrame\n\nconst KNOWN_TYPES = new Set<TunnelFrame[\"t\"]>([\n \"spawn\",\n \"stdin\",\n \"kill\",\n \"resize\",\n \"http_request\",\n \"http_response\",\n \"http_response_head\",\n \"http_response_chunk\",\n \"ws_open\",\n \"ws_open_ack\",\n \"ws_message\",\n \"ws_close\",\n \"ping\",\n \"pong\",\n \"error\",\n \"hello\",\n \"spawned\",\n \"stdout\",\n \"stderr\",\n \"exit\",\n \"reconnect_soon\",\n])\n\n/**\n * Parse a raw WS message into a `TunnelFrame`. Returns null when the\n * payload isn't a valid frame — callers MUST handle null defensively\n * (typically: send an `error` frame and ignore). We don't throw so\n * one bad frame can't tear down the tunnel.\n */\nexport function parseFrame(raw: string): TunnelFrame | null {\n let parsed: unknown\n try {\n parsed = JSON.parse(raw)\n } catch {\n return null\n }\n if (\n !parsed ||\n typeof parsed !== \"object\" ||\n !(\"t\" in parsed) ||\n typeof (parsed as { t: unknown }).t !== \"string\"\n ) {\n return null\n }\n const t = (parsed as { t: string }).t\n if (!KNOWN_TYPES.has(t as TunnelFrame[\"t\"])) return null\n return parsed as TunnelFrame\n}\n\nexport function encodeFrame(frame: TunnelFrame): string {\n return JSON.stringify(frame)\n}\n\n/**\n * Encode raw bytes for an `stdin` / `stdout` / `stderr` frame's `data`\n * field. Centralised so both sides agree on the encoding.\n */\nexport function encodeData(bytes: Uint8Array | string): string {\n const buf =\n typeof bytes === \"string\" ? Buffer.from(bytes, \"utf8\") : Buffer.from(bytes)\n return buf.toString(\"base64\")\n}\n\nexport function decodeData(data: string): Buffer {\n return Buffer.from(data, \"base64\")\n}\n","/**\n * Tunnel server (daemon side).\n *\n * Sits on the local machine that actually owns the binaries (e.g. the\n * user's laptop running `agentproto serve`). Accepts spawn frames from\n * a remote host, spawns the requested child via node:child_process,\n * pipes stdio back as `stdout`/`stderr` frames, and reports lifecycle\n * via `spawned`/`exit`/`error`.\n *\n * Transport-agnostic: the caller passes a `FrameSink`. For WebSocket\n * callers, see `wrapWebSocket()` in ./ws-adapter.ts.\n *\n * Security: this process MUST refuse spawn requests by default unless\n * the caller installed an `authorize(spawn)` hook. We don't expose a\n * \"trust everything\" mode — every host integration is responsible for\n * deciding what the remote may exec. The hook gets the full SpawnFrame\n * and can mutate it (e.g. force `cwd` into a workspace) or reject.\n */\n\nimport { spawn, type ChildProcess } from \"node:child_process\"\nimport { hostname, platform } from \"node:os\"\nimport {\n TUNNEL_VERSION,\n decodeData,\n encodeData,\n encodeFrame,\n parseFrame,\n type ExitFrame,\n type HttpRequestFrame,\n type HttpResponseFrame,\n type SpawnFrame,\n type StderrFrame,\n type StdoutFrame,\n type TunnelFrame,\n type WsOpenFrame,\n} from \"./frames.js\"\nimport type { FrameSink } from \"./transport.js\"\n\n/**\n * Default ceiling for an upstream WS dial. An upstream that accepts the TCP\n * connection but never completes (or rejects) the WebSocket upgrade would\n * otherwise leave the `ws_open` pending forever — the host never gets an ack or\n * a reject. Bounded so a hung upstream surfaces as a 504 instead.\n */\nexport const DEFAULT_WS_DIAL_TIMEOUT_MS = 10_000\n\n/**\n * Default ceiling for an `http_request` forward when the frame carries no\n * `timeoutMs`. Covers connect + buffered body (or connect + headers for a\n * stream, after which the bound is handed to `httpStreamIdleTimeoutMs`).\n */\nexport const DEFAULT_HTTP_FORWARD_TIMEOUT_MS = 30_000\n\nexport interface TunnelServerOptions {\n sink: FrameSink\n /**\n * Authorization hook. Called for each `spawn` frame BEFORE the\n * subprocess is created. Return the (possibly mutated) frame to\n * proceed; throw or return null to reject. Rejection causes an\n * `error` frame with code \"spawn_unauthorized\".\n *\n * No default — callers MUST decide. Pass `(req) => req` to allow\n * everything (useful for tests; never for production).\n */\n authorize: (req: SpawnFrame) => SpawnFrame | null | Promise<SpawnFrame | null>\n /**\n * Upstream HTTP base URL for `http_request` frames. The daemon\n * appends the frame's `path` and forwards. Typically the local\n * gateway address — `http://127.0.0.1:18790`. When omitted, the\n * daemon replies to any `http_request` with\n * `error: { code: \"http_upstream_not_configured\" }`.\n */\n httpUpstream?: string\n /**\n * Default ceiling for an `http_request` forward (connect + buffered body, or\n * connect + headers for a stream) when the frame carries no `timeoutMs`.\n * Defaults to DEFAULT_HTTP_FORWARD_TIMEOUT_MS. Disarmed once a streaming\n * response is detected — see `httpStreamIdleTimeoutMs` for the stream phase.\n */\n httpForwardTimeoutMs?: number\n /**\n * Idle ceiling between chunks of a STREAMING response (SSE / ndjson). A\n * stalled upstream that sends headers then hangs forever between chunks would\n * otherwise block indefinitely (the regular timeout is disarmed for streams,\n * since they're long-lived by design). Counts time since the last byte and\n * resets on every chunk, so a heartbeating stream is never cut. Omitted ⇒ no\n * idle bound (current behaviour); set it to guard against silent stalls.\n */\n httpStreamIdleTimeoutMs?: number\n /** User-friendly label sent in the hello frame. */\n label?: string\n /**\n * Capability identifiers advertised in the hello frame — the agent\n * adapters / tool surfaces this daemon serves (e.g. the gateway's\n * registered adapter ids). Lets a multi-daemon host enumerate and\n * route by capability without a round-trip. Omit to advertise none.\n */\n tools?: ReadonlyArray<string>\n /**\n * Whether this daemon advertises PTY support. Set to true only when\n * `spawnPty` is also provided.\n */\n pty?: boolean\n /**\n * Factory for PTY-backed processes. When provided (and `pty: true`),\n * spawn frames with `pty: true` use this instead of node:child_process.\n * Injected from the CLI layer so the ACP package stays native-free.\n */\n spawnPty?: (opts: {\n command: string\n args: string[]\n cwd?: string\n env?: Record<string, string>\n cols: number\n rows: number\n }) => PtyProcess\n /**\n * Optional hook fired once per successful spawn — after authorize\n * passed and the ChildProcess has emitted its `spawn` event.\n * Lets the daemon adopt this child into a higher-level registry\n * (e.g. @agentproto/runtime's sessions registry, AIP-46) so the\n * spawn shows up in /sessions, the LocalDaemonSessionsCard, and\n * the CLI TUI alongside spawns originated locally.\n *\n * The hook is fire-and-forget — the tunnel doesn't await its\n * return. Errors from the hook are swallowed so an observer\n * registry hiccup never breaks the tunnel exchange.\n */\n onChildSpawned?: (info: {\n execId: string\n child: ChildProcess\n request: SpawnFrame\n }) => void\n /**\n * Optional hook fired when the host sends a `reconnect_soon` frame —\n * graceful drain signal during host rollover. The daemon SHOULD\n * close + reconnect immediately (skipping any backoff) so the new\n * host replica picks it up. Default: ignore (the host follows up\n * with `close(1012)` and the daemon's own reconnect supervisor\n * handles it via normal backoff, ~30 s gap).\n *\n * Implementations typically call into their connection supervisor\n * to mark the next reconnect as \"no-backoff\" then close the sink.\n * `reasonMs` is the host's hint for how long it will wait before\n * forcing close — daemons MAY use it to drain in-flight RPCs first.\n */\n onReconnectSoon?: (info: { reasonMs?: number }) => void\n /**\n * Factory that dials a WS connection to the local upstream. When\n * provided (and `httpUpstream` is set), the daemon advertises\n * `wsForward` capability and handles `ws_open` frames by piping the\n * upstream WS through the tunnel. Injected so `@agentproto/acp`\n * stays free of a hard `ws` dependency — the CLI provides this\n * factory using its already-pulled-in `ws` package.\n */\n dialUpstreamWs?: (params: {\n url: string\n protocols?: readonly string[]\n headers?: Readonly<Record<string, string>>\n /**\n * Aborted when the dial exceeds `wsDialTimeoutMs` (or the tunnel tears down\n * mid-dial). A cooperating implementation SHOULD abort the in-flight upgrade\n * and reject so the socket isn't left half-open; even if it doesn't, the\n * server bounds the wait independently and rejects the `ws_open`.\n */\n signal?: AbortSignal\n }) => Promise<UpstreamWebSocket>\n /**\n * Ceiling for `dialUpstreamWs` to resolve before the `ws_open` is rejected\n * with 504 `upstream_ws_timeout`. Defaults to DEFAULT_WS_DIAL_TIMEOUT_MS.\n */\n wsDialTimeoutMs?: number\n /**\n * Resolve a named upstream (a `ws_open` frame's `upstream` field) to an\n * HTTP base URL the daemon should dial instead of `httpUpstream`. Lets a\n * host reach an imported local service by alias (e.g. a browser capability\n * server) without ever naming a raw origin — the daemon owns the name→URL\n * mapping. Return undefined for an unknown alias (the open is rejected).\n * Omitted ⇒ every `ws_open` dials the default `httpUpstream`.\n */\n resolveWsUpstream?: (\n upstream: string\n ) => string | undefined | Promise<string | undefined>\n}\n\n/**\n * Minimal upstream WS surface — satisfied by the `ws` library's\n * client socket. Daemons supplying `dialUpstreamWs` resolve into\n * one of these as soon as the WS is OPEN. `protocol` is the\n * subprotocol negotiated by the upstream (empty string when none).\n */\nexport interface UpstreamWebSocket {\n readonly protocol: string\n /** Send a frame to the upstream. */\n send(data: Buffer | string, opts: { binary: boolean }): void\n /** Close the upstream connection. */\n close(code?: number, reason?: string): void\n /** Subscribe to inbound frames. */\n onMessage(handler: (data: Buffer, isBinary: boolean) => void): void\n /** Subscribe to upstream close. */\n onClose(handler: (code: number, reason: string) => void): void\n /** Subscribe to transport errors. */\n onError(handler: (err: Error) => void): void\n}\n\n/** Minimal PTY process surface — satisfied by node-pty's IPty. */\nexport interface PtyProcess {\n readonly pid: number\n write(data: string): void\n resize(cols: number, rows: number): void\n kill(signal?: string): void\n onData(handler: (data: string) => void): void\n onExit(handler: (event: { exitCode: number; signal?: number }) => void): void\n}\n\nexport interface TunnelServer {\n /** Currently-live execId → ChildProcess. Read-only diagnostic. */\n readonly children: ReadonlyMap<string, ChildProcess>\n /** Kill all live children and close the sink. */\n close(): Promise<void>\n}\n\nexport function createTunnelServer(opts: TunnelServerOptions): TunnelServer {\n const children = new Map<string, ChildProcess>()\n // PTY-backed processes keyed by execId (separate from pipe-based children).\n const ptyProcs = new Map<string, PtyProcess>()\n // Per-reqId map of bridged upstream WS connections. Each entry's\n // lifecycle starts at ws_open (we send open_ack on success) and ends\n // at ws_close (either direction). On tunnel teardown we close all.\n const upstreamWs = new Map<string, UpstreamWebSocket>()\n let closed = false\n\n // Greet the host immediately so it can fail fast on version\n // mismatch before issuing spawns.\n opts.sink.send({\n t: \"hello\",\n version: TUNNEL_VERSION,\n capabilities: {\n pty: opts.pty === true,\n wsForward: opts.dialUpstreamWs !== undefined && !!opts.httpUpstream,\n ...(opts.tools && opts.tools.length ? { tools: opts.tools } : {}),\n },\n label: opts.label,\n daemon: {\n name: \"agentproto\",\n version: \"0.1.0-alpha\",\n platform: `${platform()}/${hostname()}`,\n nodeVersion: process.version,\n },\n })\n\n const offFrame = opts.sink.onFrame((frame) => {\n handleFrame(frame).catch((err) => {\n const message = err instanceof Error ? err.message : String(err)\n opts.sink.send({ t: \"error\", code: \"internal\", message })\n })\n })\n\n const offClose = opts.sink.onClose(() => {\n closed = true\n for (const [, child] of children) child.kill(\"SIGTERM\")\n children.clear()\n for (const [, pty] of ptyProcs) pty.kill()\n ptyProcs.clear()\n for (const [, ws] of upstreamWs) {\n try {\n ws.close(1001, \"tunnel_closed\")\n } catch {\n /* socket may already be dead */\n }\n }\n upstreamWs.clear()\n offFrame()\n offClose()\n })\n\n async function handleFrame(frame: TunnelFrame): Promise<void> {\n switch (frame.t) {\n case \"spawn\":\n await handleSpawn(frame)\n return\n case \"stdin\": {\n const pty = ptyProcs.get(frame.execId)\n if (pty) {\n pty.write(Buffer.from(frame.data, \"base64\").toString(\"utf8\"))\n return\n }\n const child = children.get(frame.execId)\n if (!child || !child.stdin) {\n opts.sink.send({\n t: \"error\",\n execId: frame.execId,\n code: \"unknown_exec\",\n message: `No live exec '${frame.execId}'`,\n })\n return\n }\n child.stdin.write(Buffer.from(frame.data, \"base64\"))\n return\n }\n case \"kill\": {\n const pty = ptyProcs.get(frame.execId)\n if (pty) {\n pty.kill(frame.signal ?? \"SIGTERM\")\n return\n }\n const child = children.get(frame.execId)\n if (!child) {\n opts.sink.send({\n t: \"error\",\n execId: frame.execId,\n code: \"unknown_exec\",\n message: `No live exec '${frame.execId}'`,\n })\n return\n }\n child.kill((frame.signal as NodeJS.Signals | undefined) ?? \"SIGTERM\")\n return\n }\n case \"resize\": {\n ptyProcs.get(frame.execId)?.resize(frame.cols, frame.rows)\n return\n }\n case \"http_request\":\n // Fire-and-forget — the handler emits its own http_response\n // frame (or error). Errors that escape handleHttpRequest\n // bubble to the outer .catch and become a generic `error`\n // frame, but the per-request error path inside the handler\n // produces an http_response with `error:` set, which is what\n // the host's forwardHttp expects.\n await handleHttpRequest(frame)\n return\n case \"ws_open\":\n await handleWsOpen(frame)\n return\n case \"ws_message\": {\n const ws = upstreamWs.get(frame.reqId)\n if (!ws) {\n // Stale frame for a closed bridge — silently drop. Sending\n // an error frame would race with our own ws_close on the\n // teardown path.\n return\n }\n try {\n ws.send(decodeData(frame.data), { binary: frame.binary === true })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n opts.sink.send({\n t: \"ws_close\",\n reqId: frame.reqId,\n code: 1011,\n reason: `send_failed: ${message}`,\n })\n try {\n ws.close(1011, \"send_failed\")\n } catch {\n /* defensive */\n }\n upstreamWs.delete(frame.reqId)\n }\n return\n }\n case \"ws_close\": {\n const ws = upstreamWs.get(frame.reqId)\n if (!ws) return\n upstreamWs.delete(frame.reqId)\n try {\n ws.close(frame.code, frame.reason)\n } catch {\n /* socket may already be dead */\n }\n return\n }\n case \"ping\":\n opts.sink.send({ t: \"pong\", nonce: frame.nonce })\n return\n case \"reconnect_soon\":\n // Host is shutting down this replica (e.g. k8s preStop). Fire\n // the supervisor hook so the daemon CLI can drop the WS +\n // reconnect without exponential backoff. We do NOT close the\n // sink here — that's the supervisor's call (it may want to\n // drain in-flight RPCs first using the `reasonMs` hint).\n try {\n opts.onReconnectSoon?.({\n ...(frame.reasonMs !== undefined ? { reasonMs: frame.reasonMs } : {}),\n })\n } catch {\n /* defensive — supervisor hook must never break the tunnel */\n }\n return\n case \"pong\":\n case \"error\":\n // Daemon doesn't act on these; host-side concern.\n return\n default:\n opts.sink.send({\n t: \"error\",\n code: \"unknown_frame\",\n message: `Daemon received unexpected frame type '${(frame as { t: string }).t}'`,\n })\n }\n }\n\n async function handleSpawn(req: SpawnFrame): Promise<void> {\n if (closed) return\n let approved: SpawnFrame | null\n try {\n approved = await opts.authorize(req)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n opts.sink.send({\n t: \"error\",\n execId: req.execId,\n code: \"spawn_unauthorized\",\n message,\n })\n return\n }\n if (!approved) {\n opts.sink.send({\n t: \"error\",\n execId: req.execId,\n code: \"spawn_unauthorized\",\n message: \"Authorize hook rejected the spawn request.\",\n })\n return\n }\n\n // PTY path — use injected spawnPty factory when pty:true is requested.\n if (approved.pty && opts.spawnPty) {\n let pty: PtyProcess\n try {\n pty = opts.spawnPty({\n command: approved.command,\n args: [...approved.args],\n cwd: approved.cwd,\n env: approved.env ? { ...approved.env } : undefined,\n cols: approved.cols ?? 80,\n rows: approved.rows ?? 24,\n })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n opts.sink.send({ t: \"error\", execId: req.execId, code: \"spawn_failed\", message })\n return\n }\n\n ptyProcs.set(req.execId, pty)\n opts.sink.send({ t: \"spawned\", execId: req.execId, pid: pty.pid })\n\n pty.onData(data => {\n opts.sink.send({ t: \"stdout\", execId: req.execId, data: encodeData(data) })\n })\n pty.onExit(({ exitCode, signal }) => {\n opts.sink.send({\n t: \"exit\",\n execId: req.execId,\n code: exitCode,\n signal: signal != null ? String(signal) : null,\n })\n ptyProcs.delete(req.execId)\n })\n\n if (opts.onChildSpawned) {\n try {\n // PTY processes can't be adopted as ChildProcess — pass a no-op shim\n // so the hook fires (for session visibility) without crashing.\n opts.onChildSpawned({\n execId: req.execId,\n child: { pid: pty.pid } as unknown as ChildProcess,\n request: approved,\n })\n } catch { /* fire-and-forget */ }\n }\n return\n }\n\n let child: ChildProcess\n try {\n child = spawn(approved.command, [...approved.args], {\n cwd: approved.cwd,\n env: { ...process.env, ...(approved.env ?? {}) },\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n // detached:false so SIGINT/SIGTERM on the daemon kills children too.\n })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n opts.sink.send({\n t: \"error\",\n execId: req.execId,\n code: \"spawn_failed\",\n message,\n })\n return\n }\n\n children.set(req.execId, child)\n\n if (typeof child.pid === \"number\") {\n opts.sink.send({ t: \"spawned\", execId: req.execId, pid: child.pid })\n } else {\n // Pid is null when spawn synchronously failed. The 'error'\n // event below will fire with the real cause; we still report\n // a placeholder spawned to keep the lifecycle predictable.\n opts.sink.send({ t: \"spawned\", execId: req.execId, pid: -1 })\n }\n\n // Notify the higher-level registry (when wired) — this is what\n // makes tunnel-driven spawns visible in the daemon's\n // /sessions list alongside spawns originated locally. Errors\n // from the observer never break the tunnel.\n if (opts.onChildSpawned) {\n try {\n opts.onChildSpawned({ execId: req.execId, child, request: approved })\n } catch (err) {\n // Hook is fire-and-forget — log + continue.\n // Use console.warn directly because tunnel server has no\n // logger context.\n console.warn(\n `[tunnel-server] onChildSpawned hook threw for execId=${req.execId}: ${\n err instanceof Error ? err.message : String(err)\n }`\n )\n }\n }\n\n child.stdout?.on(\"data\", (chunk: Buffer) => {\n const f: StdoutFrame = {\n t: \"stdout\",\n execId: req.execId,\n data: encodeData(chunk),\n }\n opts.sink.send(f)\n })\n child.stderr?.on(\"data\", (chunk: Buffer) => {\n const f: StderrFrame = {\n t: \"stderr\",\n execId: req.execId,\n data: encodeData(chunk),\n }\n opts.sink.send(f)\n })\n\n child.on(\"error\", (err) => {\n opts.sink.send({\n t: \"error\",\n execId: req.execId,\n code: \"child_error\",\n message: err.message,\n })\n })\n\n child.on(\"exit\", (code, signal) => {\n const f: ExitFrame = {\n t: \"exit\",\n execId: req.execId,\n code,\n signal,\n }\n opts.sink.send(f)\n children.delete(req.execId)\n })\n }\n\n /**\n * Open a bridged WS connection to the local upstream. Same path-\n * safety rules as `handleHttpRequest` (no absolute URLs, no `..`),\n * same hop-by-hop header stripping. The `dialUpstreamWs` factory\n * resolves to an `UpstreamWebSocket` once the upgrade is OPEN — we\n * then emit `ws_open_ack` to the host and start piping frames.\n */\n async function handleWsOpen(req: WsOpenFrame): Promise<void> {\n if (closed) return\n const reject = (\n status: number,\n code: string,\n message: string\n ): void => {\n opts.sink.send({\n t: \"ws_open_ack\",\n reqId: req.reqId,\n status,\n error: { code, message },\n })\n }\n if (!opts.dialUpstreamWs || !opts.httpUpstream) {\n reject(\n 502,\n \"ws_upstream_not_configured\",\n \"Daemon does not support WS forwarding — start with `--upstream ws://…` (or upgrade).\"\n )\n return\n }\n if (\n !req.path.startsWith(\"/\") ||\n req.path.startsWith(\"//\") ||\n req.path.includes(\"..\")\n ) {\n reject(\n 400,\n \"invalid_path\",\n `Daemon WS forward requires a safe relative path; got '${req.path}'.`\n )\n return\n }\n const HOP_BY_HOP = new Set([\n \"connection\",\n \"upgrade\",\n \"sec-websocket-version\",\n \"sec-websocket-key\",\n \"sec-websocket-extensions\",\n \"sec-websocket-protocol\",\n \"host\",\n \"content-length\",\n ])\n const headers: Record<string, string> = {}\n for (const [k, v] of Object.entries(req.headers ?? {})) {\n if (HOP_BY_HOP.has(k.toLowerCase())) continue\n headers[k] = v\n }\n // Pick the HTTP base: a named upstream (resolved by the daemon to an\n // imported service's origin) when the frame carries one, else the\n // default gateway. The host names an alias, never a URL, so it can't\n // steer the daemon at an arbitrary origin.\n let httpBase = opts.httpUpstream\n if (req.upstream) {\n const resolved = await opts.resolveWsUpstream?.(req.upstream)\n if (!resolved) {\n reject(\n 502,\n \"unknown_ws_upstream\",\n `No WS upstream registered for '${req.upstream}'.`\n )\n return\n }\n httpBase = resolved\n }\n // Map the http upstream base to a ws scheme. The daemon's upstream\n // is conventionally http://127.0.0.1:<port>; the same host accepts\n // WS upgrades on the same port, so ws://… works.\n const base = httpBase.replace(/^http(s?):\\/\\//, \"ws$1://\")\n const url = `${base.replace(/\\/$/, \"\")}${req.path}`\n\n // Bound the dial: a hung upstream that never finishes the upgrade must not\n // strand the ws_open. Abort the dial (cooperating impls cancel the real\n // socket) AND race the timeout independently, so even an impl that ignores\n // the signal still yields a 504.\n const dialTimeoutMs = opts.wsDialTimeoutMs ?? DEFAULT_WS_DIAL_TIMEOUT_MS\n const dialAbort = new AbortController()\n let dialTimedOut = false\n let dialTimer: ReturnType<typeof setTimeout> | null = null\n const dialPromise = opts.dialUpstreamWs({\n url,\n ...(req.protocols && req.protocols.length > 0\n ? { protocols: req.protocols }\n : {}),\n headers,\n signal: dialAbort.signal,\n })\n const timeoutPromise = new Promise<never>((_resolve, rej) => {\n dialTimer = setTimeout(() => {\n dialTimedOut = true\n dialAbort.abort(new Error(\"ws_dial_timeout\"))\n rej(new Error(`upstream WS dial timed out after ${dialTimeoutMs}ms`))\n }, dialTimeoutMs)\n if (typeof dialTimer !== \"number\") dialTimer.unref()\n })\n\n let upstream: UpstreamWebSocket\n try {\n upstream = await Promise.race([dialPromise, timeoutPromise])\n } catch (err) {\n if (dialTimer) clearTimeout(dialTimer)\n if (dialTimedOut) {\n // The timeout won the race. If the abandoned dial ever resolves, close\n // the orphaned socket so it doesn't leak.\n dialPromise.then(\n sock => {\n try {\n sock.close(1001, \"dial_timeout\")\n } catch {\n /* defensive */\n }\n },\n () => {},\n )\n reject(\n 504,\n \"upstream_ws_timeout\",\n `Upstream did not complete the WS upgrade within ${dialTimeoutMs}ms.`,\n )\n return\n }\n const message = err instanceof Error ? err.message : String(err)\n // Try to extract an HTTP status from a `ws` error like\n // `Unexpected server response: 404`.\n const m = message.match(/Unexpected server response: (\\d+)/)\n const status = m ? Number.parseInt(m[1]!, 10) : 502\n reject(status, \"upstream_ws_failed\", message)\n return\n }\n if (dialTimer) clearTimeout(dialTimer)\n // Race: caller already abandoned us (tunnel closed mid-upgrade).\n if (closed) {\n try {\n upstream.close(1001, \"tunnel_closed\")\n } catch {\n /* defensive */\n }\n return\n }\n upstreamWs.set(req.reqId, upstream)\n opts.sink.send({\n t: \"ws_open_ack\",\n reqId: req.reqId,\n status: 101,\n ...(upstream.protocol ? { protocol: upstream.protocol } : {}),\n })\n\n upstream.onMessage((data, isBinary) => {\n if (!opts.sink.isOpen) return\n opts.sink.send({\n t: \"ws_message\",\n reqId: req.reqId,\n data: encodeData(data),\n binary: isBinary,\n })\n })\n upstream.onClose((code, reason) => {\n if (!upstreamWs.has(req.reqId)) return\n upstreamWs.delete(req.reqId)\n if (opts.sink.isOpen) {\n opts.sink.send({\n t: \"ws_close\",\n reqId: req.reqId,\n code,\n ...(reason ? { reason } : {}),\n })\n }\n })\n upstream.onError(err => {\n // Errors typically precede a close; emit a stable error code in\n // the close frame so the host can distinguish from clean close.\n if (!upstreamWs.has(req.reqId)) return\n upstreamWs.delete(req.reqId)\n if (opts.sink.isOpen) {\n opts.sink.send({\n t: \"ws_close\",\n reqId: req.reqId,\n code: 1011,\n reason: `upstream_error: ${err.message}`,\n })\n }\n try {\n upstream.close(1011, \"upstream_error\")\n } catch {\n /* defensive */\n }\n })\n }\n\n async function handleHttpRequest(req: HttpRequestFrame): Promise<void> {\n if (closed) return\n const respond = (\n partial:\n | { status: number; headers?: HttpResponseFrame[\"headers\"]; body?: string }\n | { error: HttpResponseFrame[\"error\"]; status: number }\n ): void => {\n opts.sink.send({\n t: \"http_response\",\n reqId: req.reqId,\n ...partial,\n } as HttpResponseFrame)\n }\n\n // Reject if no upstream is configured. Better explicit error\n // than a confusing 502 from a missing fetch target.\n if (!opts.httpUpstream) {\n respond({\n status: 502,\n error: {\n code: \"http_upstream_not_configured\",\n message:\n \"Daemon was not started with an http upstream — cannot forward HTTP frames.\",\n },\n })\n return\n }\n\n // Path-only is required to keep the daemon from being a generic\n // SSRF amplifier. Absolute URLs (including protocol-relative `//`)\n // and parent-traversal are rejected. Querystrings are fine.\n if (\n !req.path.startsWith(\"/\") ||\n req.path.startsWith(\"//\") ||\n req.path.includes(\"..\")\n ) {\n respond({\n status: 400,\n error: {\n code: \"invalid_path\",\n message: `Daemon http forward requires a safe relative path; got '${req.path}'.`,\n },\n })\n return\n }\n\n // Strip hop-by-hop headers defensively before forwarding —\n // they're meaningful only to the previous transport hop.\n const HOP_BY_HOP = new Set([\n \"connection\",\n \"keep-alive\",\n \"transfer-encoding\",\n \"upgrade\",\n \"proxy-authenticate\",\n \"proxy-authorization\",\n \"te\",\n \"trailer\",\n \"host\", // upstream sets its own based on the URL\n \"content-length\", // fetch recomputes\n ])\n const headers: Record<string, string> = {}\n for (const [k, v] of Object.entries(req.headers ?? {})) {\n if (HOP_BY_HOP.has(k.toLowerCase())) continue\n headers[k] = v\n }\n\n const url = `${opts.httpUpstream.replace(/\\/$/, \"\")}${req.path}`\n const controller = new AbortController()\n const timeoutMs =\n req.timeoutMs ??\n opts.httpForwardTimeoutMs ??\n DEFAULT_HTTP_FORWARD_TIMEOUT_MS\n // For streaming responses (SSE / long-poll), the daemon-side\n // request must NOT abort on the regular timeout — the stream is\n // *meant* to be long-lived. We arm the timer initially, then\n // disarm it as soon as we detect a streaming response so the\n // stream can run indefinitely (the host enforces its own teardown\n // via tunnel close / explicit cancel).\n let timer: ReturnType<typeof setTimeout> | null = setTimeout(\n () => controller.abort(),\n timeoutMs\n )\n const clearTimer = () => {\n if (timer) {\n clearTimeout(timer)\n timer = null\n }\n }\n try {\n const upstreamRes = await fetch(url, {\n method: req.method,\n headers,\n body:\n req.body === undefined ? undefined : decodeData(req.body),\n signal: controller.signal,\n // node fetch follows redirects by default — fine for MCP, the\n // upstream gateway doesn't redirect anyway.\n })\n const outHeaders: Record<string, string> = {}\n upstreamRes.headers.forEach((value, key) => {\n if (HOP_BY_HOP.has(key.toLowerCase())) return\n outHeaders[key] = value\n })\n\n // Streaming detection — SSE responses MUST go through the\n // chunked-frame protocol so the host can pipe bytes to the\n // browser in real time. Anything else stays on the buffered\n // path for now (small JSON responses are simpler that way; we\n // can widen streaming to all responses later once it's proven).\n const contentType = (outHeaders[\"content-type\"] ?? \"\").toLowerCase()\n const isStream =\n contentType.startsWith(\"text/event-stream\") ||\n contentType.includes(\"application/x-ndjson\")\n\n if (isStream && upstreamRes.body) {\n // Disarm the request-level timeout — SSE streams are\n // long-lived by design. The host closing the tunnel (or the\n // upstream closing its end) is what terminates us now.\n clearTimer()\n opts.sink.send({\n t: \"http_response_head\",\n reqId: req.reqId,\n status: upstreamRes.status,\n headers: outHeaders,\n })\n const reader = upstreamRes.body.getReader()\n // Inter-chunk idle bound: the request timeout is disarmed for streams,\n // so without this a stalled upstream (headers sent, then silence) hangs\n // forever. The timer resets per chunk, so a heartbeating stream is never\n // cut. `IDLE` is the sentinel for \"no byte arrived within the window\".\n const idleMs = opts.httpStreamIdleTimeoutMs\n const IDLE = Symbol(\"idle\")\n type ReadResult = Awaited<ReturnType<typeof reader.read>>\n const readChunk = async (): Promise<ReadResult | typeof IDLE> => {\n if (!idleMs) return reader.read()\n let idleTimer: ReturnType<typeof setTimeout> | null = null\n const idle = new Promise<typeof IDLE>(resolve => {\n idleTimer = setTimeout(() => resolve(IDLE), idleMs)\n if (typeof idleTimer !== \"number\") idleTimer.unref()\n })\n try {\n return await Promise.race([reader.read(), idle])\n } finally {\n if (idleTimer) clearTimeout(idleTimer)\n }\n }\n try {\n while (true) {\n const chunk = await readChunk()\n if (chunk === IDLE) {\n try {\n await reader.cancel()\n } catch {\n /* ignore */\n }\n opts.sink.send({\n t: \"http_response_chunk\",\n reqId: req.reqId,\n end: true,\n error: {\n code: \"upstream_stream_idle_timeout\",\n message: `No data from upstream for ${idleMs}ms.`,\n },\n })\n return\n }\n const { value, done } = chunk\n if (done) {\n opts.sink.send({\n t: \"http_response_chunk\",\n reqId: req.reqId,\n end: true,\n })\n return\n }\n if (value && value.byteLength > 0) {\n opts.sink.send({\n t: \"http_response_chunk\",\n reqId: req.reqId,\n data: encodeData(Buffer.from(value)),\n })\n }\n // Stop streaming if the tunnel sink closed under us — no\n // point feeding chunks into the void.\n if (!opts.sink.isOpen) {\n try {\n await reader.cancel()\n } catch {\n /* ignore */\n }\n return\n }\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n opts.sink.send({\n t: \"http_response_chunk\",\n reqId: req.reqId,\n end: true,\n error: { code: \"upstream_stream_failed\", message },\n })\n }\n return\n }\n\n // Buffered path (unchanged): small responses + non-SSE traffic.\n const buf = Buffer.from(await upstreamRes.arrayBuffer())\n respond({\n status: upstreamRes.status,\n headers: outHeaders,\n body: buf.length > 0 ? encodeData(buf) : \"\",\n })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n const aborted = err instanceof Error && err.name === \"AbortError\"\n respond({\n status: aborted ? 504 : 502,\n error: {\n code: aborted ? \"timeout\" : \"upstream_fetch_failed\",\n message,\n },\n })\n } finally {\n clearTimer()\n }\n }\n\n return {\n children,\n async close() {\n if (closed) return\n closed = true\n for (const [, child] of children) child.kill(\"SIGTERM\")\n children.clear()\n opts.sink.close(\"server.close\")\n },\n }\n}\n\n// Re-exports for convenience — server-only callers don't need to\n// reach into ./frames for these.\nexport { encodeFrame, parseFrame }\n","/**\n * Tunnel client (host side).\n *\n * Sits on the orchestrator (e.g. Guilde API). Speaks to a remote daemon\n * over a `FrameSink`. Exposes `spawn(command, args, opts)` that returns\n * an object shaped like Node's `ChildProcess` — same `.stdin` /\n * `.stdout` / `.stderr` / `.on('exit')` / `.kill()` surface. This lets\n * the existing ACP protocol arm drive remote subprocesses with zero\n * code changes; the arm thinks it's talking to a local child.\n *\n * The duck is intentionally minimal — only the methods the ACP arm\n * actually calls. If you need the full ChildProcess interface, wrap\n * this with a node:stream.Readable shim.\n */\n\nimport { EventEmitter } from \"node:events\"\nimport { Readable, Writable } from \"node:stream\"\nimport { randomUUID } from \"node:crypto\"\nimport {\n TUNNEL_VERSION,\n decodeData,\n encodeData,\n type ExitFrame,\n type HelloFrame,\n type HttpRequestFrame,\n type HttpResponseFrame,\n type SpawnFrame,\n type SpawnedFrame,\n type StderrFrame,\n type StdoutFrame,\n type TunnelFrame,\n type WsOpenFrame,\n} from \"./frames.js\"\nimport type { FrameSink } from \"./transport.js\"\n\n/** Resolved response from `forwardHttp`. Mirrors `HttpResponseFrame`\n * but with the body decoded back to a Buffer for the caller. */\nexport interface TunnelHttpResponse {\n status: number\n headers: Readonly<Record<string, string>>\n body: Buffer\n /** Set when the daemon failed to complete the upstream call. */\n error?: Readonly<{\n code: string\n message: string\n }>\n}\n\n/** Resolved response from `forwardHttpStream`. Body is a Web\n * `ReadableStream<Uint8Array>` — consume it to receive chunks as\n * they arrive from the daemon's upstream (SSE, long-poll, NDJSON).\n * The stream closes when the daemon's upstream closes OR an upstream\n * error occurs (surfaced as a stream error on the reader). */\nexport interface TunnelHttpStreamResponse {\n status: number\n headers: Readonly<Record<string, string>>\n body: ReadableStream<Uint8Array>\n}\n\nexport interface TunnelHttpRequest {\n method: string\n path: string\n headers?: Readonly<Record<string, string>>\n body?: Buffer | Uint8Array | string\n /** Per-request timeout in ms. Default 30_000. */\n timeoutMs?: number\n}\n\nexport interface TunnelWebSocketOpenRequest {\n /** Path + querystring on the daemon-local upstream. Daemon prepends\n * its `ws://<upstream>` base; absolute URLs are rejected. */\n path: string\n /** Optional registered upstream to dial instead of the daemon's default\n * gateway — a NAME the daemon resolves to a base URL (e.g. an imported\n * service alias). The host never names a raw origin. */\n upstream?: string\n /** Headers forwarded to the upstream upgrade. Hop-by-hop / Sec-* are\n * stripped by the daemon. Cookies are NOT forwarded unless the\n * daemon was started with `--upstream-cookies`. */\n headers?: Readonly<Record<string, string>>\n /** Subprotocols requested. Echoed in `protocol` on success. */\n protocols?: readonly string[]\n /** How long to wait for the upstream upgrade before erroring. The\n * message stream itself has no timeout (WS lives as long as either\n * end keeps it open). Default 30_000. */\n openTimeoutMs?: number\n}\n\n/**\n * Bridged WS connection. Mirrors the surface of a browser WebSocket\n * minus URL/protocol bookkeeping — the host already chose those when\n * calling `forwardWebSocket`. Messages are typed as text (UTF-8 string)\n * or binary (Uint8Array); the bridge preserves the upstream's framing.\n */\nexport interface TunnelWebSocket {\n /** True until `close` runs in either direction. */\n readonly readyState: \"open\" | \"closing\" | \"closed\"\n /** Selected subprotocol from the upstream's upgrade response, if any. */\n readonly protocol: string | null\n /** Send a frame to the daemon's upstream. No-op when not open. */\n send(data: string | Uint8Array): void\n /** Initiate a clean close. Idempotent. */\n close(code?: number, reason?: string): void\n /** Subscribe to inbound frames. Returns an unsubscribe fn. */\n onMessage(\n listener: (data: Buffer, isBinary: boolean) => void\n ): () => void\n /** Subscribe to close. Fires exactly once (after either side closes\n * OR the tunnel itself drops). Returns an unsubscribe fn. */\n onClose(listener: (code: number, reason: string) => void): () => void\n /** Subscribe to transport-level errors. Closes follow shortly. */\n onError(listener: (err: Error) => void): () => void\n}\n\nexport interface TunnelClientOptions {\n sink: FrameSink\n /**\n * Reject the `spawn` call if the daemon hasn't sent its `hello`\n * within this window. Defaults to 10s — generous for high-latency\n * tunnels but fast enough that misconfigured daemons fail loudly.\n */\n helloTimeoutMs?: number\n}\n\nexport interface TunnelSpawnOptions {\n cwd?: string\n env?: Readonly<Record<string, string>>\n /** Allocate a PTY on the daemon. Requires `hello.capabilities.pty`. */\n pty?: boolean\n /** Initial PTY column width (ignored when `pty` is false). Default 80. */\n cols?: number\n /** Initial PTY row height (ignored when `pty` is false). Default 24. */\n rows?: number\n}\n\n/**\n * Minimal ChildProcess-shaped duck. Covers the surface our ACP arm\n * calls; expand only when a real consumer needs more.\n */\nexport interface TunnelChildProcess {\n readonly execId: string\n readonly pid: number | null\n readonly stdin: Writable\n readonly stdout: Readable\n readonly stderr: Readable\n /** \"exit\" → (code, signal). \"error\" → (Error). */\n on(event: \"exit\", listener: (code: number | null, signal: string | null) => void): this\n on(event: \"error\", listener: (err: Error) => void): this\n kill(signal?: NodeJS.Signals | number): boolean\n /** Send a terminal resize to the daemon. No-op if the exec isn't PTY-backed. */\n resize(cols: number, rows: number): void\n}\n\nexport interface TunnelClient {\n /**\n * Resolves once the daemon has sent its `hello` frame, OR rejects\n * with a tunnel-level error. Subsequent calls return the cached\n * promise.\n */\n ready(): Promise<HelloFrame>\n spawn(\n command: string,\n args: readonly string[],\n opts?: TunnelSpawnOptions\n ): Promise<TunnelChildProcess>\n /**\n * Forward an HTTP request through the tunnel to the daemon's\n * configured upstream (typically `http://127.0.0.1:<port>`). The\n * daemon completes the upstream call and replies with the response,\n * which this promise resolves to. Rejects on tunnel-transport\n * failure; the daemon-reported HTTP status (incl. 5xx) is returned\n * in the resolved value.\n *\n * Streaming responses (text/event-stream, NDJSON) are buffered into\n * the returned Buffer. For real streaming, use `forwardHttpStream`.\n */\n forwardHttp(req: TunnelHttpRequest): Promise<TunnelHttpResponse>\n /**\n * Stream an HTTP response through the tunnel. The promise resolves\n * as soon as the response head (status + headers) arrives — the\n * body chunks then flow through `body` (a ReadableStream) until the\n * daemon's upstream closes. Required for SSE / NDJSON / long-poll\n * upstreams where buffering until the end would defeat the point.\n * For one-shot HTTP, prefer `forwardHttp`.\n */\n forwardHttpStream(req: TunnelHttpRequest): Promise<TunnelHttpStreamResponse>\n /**\n * Open a bridged WebSocket through the tunnel. The promise resolves\n * once the daemon has completed the upstream upgrade; from that\n * point messages flow via the returned `TunnelWebSocket`.\n *\n * Rejects on:\n * - missing `hello.capabilities.wsForward` — older daemon, no bridge\n * - upstream upgrade failure (4xx/5xx) — `cause` carries the status\n * - timeout waiting for `ws_open_ack`\n */\n forwardWebSocket(req: TunnelWebSocketOpenRequest): Promise<TunnelWebSocket>\n close(): Promise<void>\n}\n\nexport function createTunnelClient(opts: TunnelClientOptions): TunnelClient {\n const helloTimeoutMs = opts.helloTimeoutMs ?? 10_000\n let hello: HelloFrame | null = null\n let helloPromise: Promise<HelloFrame> | null = null\n\n // Per-execId routing tables. We dispatch incoming frames to the\n // right child duck by execId; spawn awaits its own `spawned` /\n // `error` reply via these one-shot resolvers.\n const childByExec = new Map<string, TunnelChildDuck>()\n const spawnPending = new Map<\n string,\n { resolve: (frame: SpawnedFrame) => void; reject: (err: Error) => void }\n >()\n\n // Inflight HTTP forwards keyed by reqId. Each entry's mode depends\n // on which API the caller used:\n // - \"buffered\": forwardHttp(). Resolves once the full body has\n // arrived (either as a single `http_response` frame, OR as\n // `http_response_head` + chunks that get concatenated here).\n // - \"stream\": forwardHttpStream(). Resolves on `http_response_head`\n // with a ReadableStream that's fed by subsequent chunk frames.\n // For backward-compat with daemons that emit a single\n // `http_response`, we synthesize a one-chunk stream + end.\n // Either mode handles either server response shape — the daemon's\n // streaming decision is purely server-side (Content-Type based), and\n // the client adapts.\n type HttpPending =\n | {\n mode: \"buffered\"\n resolve: (resp: TunnelHttpResponse) => void\n reject: (err: Error) => void\n timer: ReturnType<typeof setTimeout>\n // Set when daemon starts a chunked response.\n streamHead: {\n status: number\n headers: Record<string, string>\n } | null\n streamChunks: Buffer[]\n }\n | {\n mode: \"stream\"\n resolveHead: (resp: TunnelHttpStreamResponse) => void\n reject: (err: Error) => void\n timer: ReturnType<typeof setTimeout>\n // Set once the head arrives — drains pendingChunks into it.\n controller: ReadableStreamDefaultController<Uint8Array> | null\n pendingChunks: Buffer[]\n headEmitted: boolean\n // Goes true after `end: true` so a late close-of-tunnel doesn't\n // try to error a closed controller.\n ended: boolean\n }\n const httpPending = new Map<string, HttpPending>()\n\n // Per-reqId routing for bridged WS connections. Lifecycle:\n // 1. forwardWebSocket() inserts a `wsOpenPending` entry + sends ws_open\n // 2. Daemon emits ws_open_ack → we resolve the open promise into a\n // TunnelWebSocketDuck, move it to `wsByReq`, drop the pending entry\n // 3. Bidirectional ws_message frames route to the duck\n // 4. ws_close in either direction tears the duck down + drops from the map\n // 5. Tunnel close errors all open WSes with code 1006\n type WsPending = {\n resolve: (ws: TunnelWebSocket) => void\n reject: (err: Error) => void\n timer: ReturnType<typeof setTimeout>\n }\n const wsOpenPending = new Map<string, WsPending>()\n const wsByReq = new Map<string, TunnelWebSocketDuck>()\n\n const offFrame = opts.sink.onFrame((frame) => routeIncoming(frame))\n const offClose = opts.sink.onClose(() => {\n for (const [, duck] of childByExec) duck.__handleSinkClosed()\n childByExec.clear()\n for (const [, p] of spawnPending) {\n p.reject(new Error(\"Tunnel closed before spawn completed.\"))\n }\n spawnPending.clear()\n for (const [, p] of httpPending) {\n clearTimeout(p.timer)\n if (p.mode === \"buffered\") {\n p.reject(new Error(\"Tunnel closed before HTTP response arrived.\"))\n } else {\n // For an active stream, error the controller so the consumer's\n // reader.read() rejects instead of hanging forever. If the head\n // hasn't been emitted yet, reject the head promise too.\n if (!p.headEmitted) {\n p.reject(new Error(\"Tunnel closed before HTTP response head arrived.\"))\n } else if (p.controller && !p.ended) {\n try {\n p.controller.error(new Error(\"Tunnel closed mid-stream.\"))\n } catch {\n /* already closed */\n }\n }\n }\n }\n httpPending.clear()\n for (const [, p] of wsOpenPending) {\n clearTimeout(p.timer)\n p.reject(new Error(\"Tunnel closed before WS upgrade completed.\"))\n }\n wsOpenPending.clear()\n for (const [, duck] of wsByReq) {\n duck.__handleSinkClosed()\n }\n wsByReq.clear()\n offFrame()\n offClose()\n })\n\n function routeIncoming(frame: TunnelFrame): void {\n switch (frame.t) {\n case \"hello\":\n if (frame.version !== TUNNEL_VERSION) {\n // Mismatch — surface via the ready() rejection. We don't\n // tear down the sink because the caller may want to\n // negotiate a fallback.\n throw new Error(\n `Tunnel daemon speaks ${frame.version}; this client speaks ${TUNNEL_VERSION}.`\n )\n }\n hello = frame\n return\n case \"spawned\": {\n const pending = spawnPending.get(frame.execId)\n if (pending) {\n spawnPending.delete(frame.execId)\n pending.resolve(frame)\n }\n return\n }\n case \"stdout\": {\n const duck = childByExec.get(frame.execId)\n duck?.__pushStdout(decodeData((frame as StdoutFrame).data))\n return\n }\n case \"stderr\": {\n const duck = childByExec.get(frame.execId)\n duck?.__pushStderr(decodeData((frame as StderrFrame).data))\n return\n }\n case \"exit\": {\n const duck = childByExec.get(frame.execId)\n duck?.__handleExit(frame as ExitFrame)\n childByExec.delete(frame.execId)\n return\n }\n case \"error\": {\n if (frame.execId) {\n const pending = spawnPending.get(frame.execId)\n if (pending) {\n spawnPending.delete(frame.execId)\n pending.reject(new Error(`${frame.code}: ${frame.message}`))\n return\n }\n const duck = childByExec.get(frame.execId)\n duck?.__pushError(new Error(`${frame.code}: ${frame.message}`))\n return\n }\n // Tunnel-level error: nowhere to surface it cleanly here.\n // Callers that care should wrap the FrameSink and observe\n // tunnel-error frames themselves.\n return\n }\n case \"http_response\": {\n // Buffered response from the daemon — single-frame body.\n const pending = httpPending.get(frame.reqId)\n if (!pending) return\n httpPending.delete(frame.reqId)\n clearTimeout(pending.timer)\n const body = frame.body ? decodeData(frame.body) : Buffer.alloc(0)\n if (pending.mode === \"buffered\") {\n pending.resolve({\n status: frame.status,\n headers: frame.headers ?? {},\n body,\n ...(frame.error ? { error: frame.error } : {}),\n })\n } else {\n // Caller asked for a stream but the daemon decided to send\n // a single buffered response. Synthesize a one-chunk stream\n // so the same consumer code path works.\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n if (body.length > 0) controller.enqueue(new Uint8Array(body))\n controller.close()\n },\n })\n pending.resolveHead({\n status: frame.status,\n headers: frame.headers ?? {},\n body: stream,\n })\n }\n return\n }\n case \"http_response_head\": {\n const pending = httpPending.get(frame.reqId)\n if (!pending) return\n const headers = frame.headers ?? {}\n if (pending.mode === \"stream\") {\n // Wire a ReadableStream whose controller drains any chunks\n // we've buffered while waiting for the head frame (rare —\n // chunks shouldn't precede the head — but harmless).\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n pending.controller = controller\n for (const chunk of pending.pendingChunks) {\n if (chunk.length > 0) controller.enqueue(new Uint8Array(chunk))\n }\n pending.pendingChunks = []\n },\n cancel: () => {\n // Consumer abandoned the stream — clean up the pending\n // entry. We don't send a cancel frame to the daemon\n // (the protocol doesn't define one), so the daemon will\n // keep streaming until its upstream closes; we simply\n // drop frames we still receive.\n if (httpPending.get(frame.reqId) === pending) {\n clearTimeout(pending.timer)\n httpPending.delete(frame.reqId)\n }\n },\n })\n pending.headEmitted = true\n // Stream is long-lived — disarm the buffered-mode timeout\n // (it was a safety net for a stuck buffered response).\n clearTimeout(pending.timer)\n pending.resolveHead({\n status: frame.status,\n headers,\n body: stream,\n })\n } else {\n // Buffered caller, streaming server — start accumulating\n // chunks; we'll resolve once `end: true` arrives.\n pending.streamHead = { status: frame.status, headers }\n }\n return\n }\n case \"http_response_chunk\": {\n const pending = httpPending.get(frame.reqId)\n if (!pending) return\n const data = frame.data ? decodeData(frame.data) : Buffer.alloc(0)\n if (pending.mode === \"stream\") {\n if (frame.error) {\n // Upstream error mid-stream — surface it on the reader.\n try {\n pending.controller?.error(\n new Error(`${frame.error.code}: ${frame.error.message}`)\n )\n } catch {\n /* already closed */\n }\n pending.ended = true\n clearTimeout(pending.timer)\n httpPending.delete(frame.reqId)\n return\n }\n if (pending.controller) {\n if (data.length > 0) {\n try {\n pending.controller.enqueue(new Uint8Array(data))\n } catch {\n /* reader detached — drop */\n }\n }\n if (frame.end) {\n try {\n pending.controller.close()\n } catch {\n /* already closed */\n }\n pending.ended = true\n clearTimeout(pending.timer)\n httpPending.delete(frame.reqId)\n }\n } else {\n // Head hasn't been processed yet — buffer until it is.\n if (data.length > 0) pending.pendingChunks.push(data)\n if (frame.end) {\n // Race: chunk-end before head. Defer closing until head\n // creates the controller.\n pending.ended = true\n }\n }\n } else {\n // Buffered mode — accumulate chunks; resolve on end.\n if (data.length > 0) pending.streamChunks.push(data)\n if (frame.error) {\n clearTimeout(pending.timer)\n httpPending.delete(frame.reqId)\n const concatenated = Buffer.concat(pending.streamChunks)\n pending.resolve({\n status: pending.streamHead?.status ?? 502,\n headers: pending.streamHead?.headers ?? {},\n body: concatenated,\n error: frame.error,\n })\n return\n }\n if (frame.end) {\n clearTimeout(pending.timer)\n httpPending.delete(frame.reqId)\n const concatenated = Buffer.concat(pending.streamChunks)\n pending.resolve({\n status: pending.streamHead?.status ?? 200,\n headers: pending.streamHead?.headers ?? {},\n body: concatenated,\n })\n }\n }\n return\n }\n case \"ws_open_ack\": {\n const pending = wsOpenPending.get(frame.reqId)\n if (!pending) return\n wsOpenPending.delete(frame.reqId)\n clearTimeout(pending.timer)\n if (frame.error || frame.status !== 101) {\n const code = frame.error?.code ?? `http_${frame.status}`\n const msg =\n frame.error?.message ??\n `Upstream WS upgrade returned ${frame.status}`\n pending.reject(new Error(`${code}: ${msg}`))\n return\n }\n const duck = new TunnelWebSocketDuck(\n frame.reqId,\n frame.protocol ?? null,\n opts.sink,\n () => wsByReq.delete(frame.reqId)\n )\n wsByReq.set(frame.reqId, duck)\n pending.resolve(duck)\n return\n }\n case \"ws_message\": {\n const duck = wsByReq.get(frame.reqId)\n if (!duck) return // stale frame after close — drop\n duck.__handleMessage(decodeData(frame.data), frame.binary === true)\n return\n }\n case \"ws_close\": {\n // Resolve a pending open if the daemon closes before acking\n // (e.g. upstream refused mid-upgrade and emitted close).\n const pending = wsOpenPending.get(frame.reqId)\n if (pending) {\n wsOpenPending.delete(frame.reqId)\n clearTimeout(pending.timer)\n pending.reject(\n new Error(\n `WS closed before upgrade (code ${frame.code}${frame.reason ? `: ${frame.reason}` : \"\"})`\n )\n )\n return\n }\n const duck = wsByReq.get(frame.reqId)\n if (duck) {\n wsByReq.delete(frame.reqId)\n duck.__handleClose(frame.code, frame.reason ?? \"\")\n }\n return\n }\n case \"ping\":\n opts.sink.send({ t: \"pong\", nonce: frame.nonce })\n return\n case \"pong\":\n case \"spawn\":\n case \"stdin\":\n case \"kill\":\n case \"resize\":\n case \"http_request\":\n case \"ws_open\":\n // Not expected on the host side; ignore.\n return\n }\n }\n\n return {\n ready() {\n if (hello) return Promise.resolve(hello)\n if (helloPromise) return helloPromise\n helloPromise = new Promise<HelloFrame>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(\n new Error(\n `Tunnel daemon did not send hello within ${helloTimeoutMs}ms.`\n )\n )\n }, helloTimeoutMs)\n // Rebind sink listener so we resolve on the next hello.\n const off = opts.sink.onFrame((frame) => {\n if (frame.t !== \"hello\") return\n clearTimeout(timer)\n off()\n if (frame.version !== TUNNEL_VERSION) {\n reject(\n new Error(\n `Tunnel daemon speaks ${frame.version}; client speaks ${TUNNEL_VERSION}.`\n )\n )\n return\n }\n hello = frame\n resolve(frame)\n })\n })\n return helloPromise\n },\n\n async spawn(command, args, spawnOpts) {\n if (!hello) await this.ready()\n if (spawnOpts?.pty && hello?.capabilities.pty !== true) {\n throw new Error(\n `Tunnel daemon '${hello?.label ?? \"(unnamed)\"}' does not advertise PTY support.`\n )\n }\n const execId = randomUUID()\n const req: SpawnFrame = {\n t: \"spawn\",\n execId,\n command,\n args,\n cwd: spawnOpts?.cwd,\n env: spawnOpts?.env,\n pty: spawnOpts?.pty,\n ...(spawnOpts?.pty ? { cols: spawnOpts.cols ?? 80, rows: spawnOpts.rows ?? 24 } : {}),\n }\n const spawnedFrame = await new Promise<SpawnedFrame>(\n (resolve, reject) => {\n spawnPending.set(execId, { resolve, reject })\n opts.sink.send(req)\n }\n )\n const duck = new TunnelChildDuck(execId, spawnedFrame.pid, opts.sink)\n childByExec.set(execId, duck)\n return duck\n },\n\n async forwardHttp(req: TunnelHttpRequest): Promise<TunnelHttpResponse> {\n if (!hello) await this.ready()\n const reqId = randomUUID()\n const timeoutMs = req.timeoutMs ?? 30_000\n const body =\n req.body === undefined\n ? undefined\n : encodeData(\n typeof req.body === \"string\" ? req.body : Buffer.from(req.body)\n )\n const frame: HttpRequestFrame = {\n t: \"http_request\",\n reqId,\n method: req.method,\n path: req.path,\n ...(req.headers ? { headers: req.headers } : {}),\n ...(body !== undefined ? { body } : {}),\n timeoutMs,\n }\n return new Promise<TunnelHttpResponse>((resolve, reject) => {\n // Belt-and-suspenders timeout: in addition to the daemon-side\n // enforcement, we time out client-side at timeoutMs + 5s so a\n // misbehaving daemon can't stall this promise forever.\n const timer = setTimeout(() => {\n httpPending.delete(reqId)\n reject(\n new Error(\n `Tunnel forwardHttp(${req.method} ${req.path}) timed out after ${timeoutMs + 5_000}ms.`\n )\n )\n }, timeoutMs + 5_000)\n httpPending.set(reqId, {\n mode: \"buffered\",\n resolve,\n reject,\n timer,\n streamHead: null,\n streamChunks: [],\n })\n opts.sink.send(frame)\n })\n },\n\n async forwardHttpStream(\n req: TunnelHttpRequest\n ): Promise<TunnelHttpStreamResponse> {\n if (!hello) await this.ready()\n const reqId = randomUUID()\n // Streaming requests don't enforce a body-completion timeout —\n // SSE / long-poll streams are *meant* to stay open. We do gate\n // the HEAD on a generous-but-finite window so a daemon that\n // silently drops the request still surfaces an error rather\n // than hanging forever; once head arrives, the timer is cleared.\n const headTimeoutMs = req.timeoutMs ?? 30_000\n const body =\n req.body === undefined\n ? undefined\n : encodeData(\n typeof req.body === \"string\" ? req.body : Buffer.from(req.body)\n )\n // Daemon-side request timeout: pass a very large number so the\n // daemon doesn't kill its own fetch before the stream completes.\n // Daemon detects SSE content-type and disarms its timer anyway,\n // but for non-SSE callers using forwardHttpStream this keeps\n // things safe.\n const frame: HttpRequestFrame = {\n t: \"http_request\",\n reqId,\n method: req.method,\n path: req.path,\n ...(req.headers ? { headers: req.headers } : {}),\n ...(body !== undefined ? { body } : {}),\n timeoutMs: 24 * 60 * 60 * 1000, // 24h — effectively \"forever\"\n }\n return new Promise<TunnelHttpStreamResponse>((resolveHead, reject) => {\n const timer = setTimeout(() => {\n if (httpPending.has(reqId)) {\n httpPending.delete(reqId)\n reject(\n new Error(\n `Tunnel forwardHttpStream(${req.method} ${req.path}) head did not arrive within ${headTimeoutMs}ms.`\n )\n )\n }\n }, headTimeoutMs)\n httpPending.set(reqId, {\n mode: \"stream\",\n resolveHead,\n reject,\n timer,\n controller: null,\n pendingChunks: [],\n headEmitted: false,\n ended: false,\n })\n opts.sink.send(frame)\n })\n },\n\n async forwardWebSocket(\n req: TunnelWebSocketOpenRequest\n ): Promise<TunnelWebSocket> {\n const h = await this.ready()\n if (h.capabilities.wsForward !== true) {\n throw new Error(\n `Tunnel daemon '${h.label ?? \"(unnamed)\"}' does not advertise wsForward capability. Update the daemon to forward browser WS upgrades.`\n )\n }\n const reqId = randomUUID()\n const timeoutMs = req.openTimeoutMs ?? 30_000\n const frame: WsOpenFrame = {\n t: \"ws_open\",\n reqId,\n path: req.path,\n ...(req.upstream ? { upstream: req.upstream } : {}),\n ...(req.headers ? { headers: req.headers } : {}),\n ...(req.protocols && req.protocols.length > 0\n ? { protocols: req.protocols }\n : {}),\n }\n return new Promise<TunnelWebSocket>((resolve, reject) => {\n const timer = setTimeout(() => {\n if (!wsOpenPending.has(reqId)) return\n wsOpenPending.delete(reqId)\n reject(\n new Error(\n `Tunnel forwardWebSocket(${req.path}) did not receive ws_open_ack within ${timeoutMs}ms.`\n )\n )\n }, timeoutMs)\n wsOpenPending.set(reqId, { resolve, reject, timer })\n opts.sink.send(frame)\n })\n },\n\n async close() {\n opts.sink.close(\"client.close\")\n },\n }\n}\n\n/**\n * Internal ChildProcess duck. Public methods mirror the subset of\n * Node's ChildProcess that our ACP arm calls; double-underscored\n * methods are control hooks for the client.\n */\nclass TunnelChildDuck extends EventEmitter implements TunnelChildProcess {\n readonly execId: string\n pid: number | null\n readonly stdin: Writable\n readonly stdout: Readable\n readonly stderr: Readable\n private readonly sink: FrameSink\n private exited = false\n\n constructor(execId: string, pid: number, sink: FrameSink) {\n super()\n this.execId = execId\n this.pid = pid > 0 ? pid : null\n this.sink = sink\n\n // stdout / stderr are passive Readables — consumers attach\n // listeners and we push() data as it arrives.\n this.stdout = new Readable({ read() {} })\n this.stderr = new Readable({ read() {} })\n\n // stdin is a Writable that converts each chunk to a `stdin` frame.\n this.stdin = new Writable({\n write(chunk: Buffer | string, _enc, cb) {\n sink.send({\n t: \"stdin\",\n execId,\n data: encodeData(chunk),\n })\n cb()\n },\n // Sending an empty stdin frame on `final` mirrors the local\n // semantics of closing a child's stdin (signal EOF). Daemons\n // ignore empty payloads, so this is safe even if the child\n // doesn't care about EOF.\n final(cb) {\n sink.send({ t: \"stdin\", execId, data: \"\" })\n cb()\n },\n })\n }\n\n __pushStdout(buf: Buffer): void {\n this.stdout.push(buf)\n }\n\n __pushStderr(buf: Buffer): void {\n this.stderr.push(buf)\n }\n\n __pushError(err: Error): void {\n this.emit(\"error\", err)\n }\n\n __handleExit(frame: ExitFrame): void {\n if (this.exited) return\n this.exited = true\n this.stdout.push(null)\n this.stderr.push(null)\n this.emit(\"exit\", frame.code, frame.signal)\n }\n\n __handleSinkClosed(): void {\n if (this.exited) return\n this.exited = true\n this.stdout.push(null)\n this.stderr.push(null)\n this.emit(\n \"exit\",\n null,\n \"SIGHUP\" // surrogate signal — the tunnel went away\n )\n }\n\n kill(signal: NodeJS.Signals | number = \"SIGTERM\"): boolean {\n if (this.exited) return false\n this.sink.send({\n t: \"kill\",\n execId: this.execId,\n signal: typeof signal === \"string\" ? signal : `SIG${signal}`,\n })\n return true\n }\n\n resize(cols: number, rows: number): void {\n if (this.exited) return\n this.sink.send({ t: \"resize\", execId: this.execId, cols, rows })\n }\n}\n\n/**\n * Internal duck for a bridged WS. Mirrors the `TunnelWebSocket`\n * interface; double-underscored methods are control hooks called by\n * the client's frame router.\n *\n * Listener semantics:\n * - `onMessage` fires for every `ws_message` frame routed here\n * - `onClose` fires exactly once, either when the daemon emits\n * `ws_close`, when the caller calls `.close()`, or when the\n * underlying tunnel disappears (with code 1006 in that case)\n * - `onError` fires for transport-level errors; close follows\n */\nclass TunnelWebSocketDuck implements TunnelWebSocket {\n readonly protocol: string | null\n private _readyState: \"open\" | \"closing\" | \"closed\" = \"open\"\n private readonly reqId: string\n private readonly sink: FrameSink\n private readonly onCleanup: () => void\n private readonly messageListeners = new Set<\n (data: Buffer, isBinary: boolean) => void\n >()\n private readonly closeListeners = new Set<\n (code: number, reason: string) => void\n >()\n private readonly errorListeners = new Set<(err: Error) => void>()\n\n constructor(\n reqId: string,\n protocol: string | null,\n sink: FrameSink,\n onCleanup: () => void\n ) {\n this.reqId = reqId\n this.protocol = protocol\n this.sink = sink\n this.onCleanup = onCleanup\n }\n\n get readyState(): \"open\" | \"closing\" | \"closed\" {\n return this._readyState\n }\n\n send(data: string | Uint8Array): void {\n if (this._readyState !== \"open\") return\n const bytes =\n typeof data === \"string\" ? Buffer.from(data, \"utf8\") : Buffer.from(data)\n this.sink.send({\n t: \"ws_message\",\n reqId: this.reqId,\n data: encodeData(bytes),\n binary: typeof data !== \"string\",\n })\n }\n\n close(code: number = 1000, reason?: string): void {\n if (this._readyState === \"closed\") return\n if (this._readyState === \"open\") {\n this._readyState = \"closing\"\n this.sink.send({\n t: \"ws_close\",\n reqId: this.reqId,\n code,\n ...(reason ? { reason } : {}),\n })\n }\n // Fire local close immediately so the caller's onClose handler\n // runs without waiting for the daemon's echo. The daemon's later\n // ws_close (if any) is dropped because routeIncoming has already\n // removed us from wsByReq via __handleClose.\n this.__handleClose(code, reason ?? \"\")\n }\n\n onMessage(\n listener: (data: Buffer, isBinary: boolean) => void\n ): () => void {\n this.messageListeners.add(listener)\n return () => this.messageListeners.delete(listener)\n }\n\n onClose(listener: (code: number, reason: string) => void): () => void {\n this.closeListeners.add(listener)\n return () => this.closeListeners.delete(listener)\n }\n\n onError(listener: (err: Error) => void): () => void {\n this.errorListeners.add(listener)\n return () => this.errorListeners.delete(listener)\n }\n\n __handleMessage(data: Buffer, isBinary: boolean): void {\n if (this._readyState !== \"open\") return\n for (const l of this.messageListeners) {\n try {\n l(data, isBinary)\n } catch {\n /* listener threw — don't let it tear down siblings */\n }\n }\n }\n\n __handleClose(code: number, reason: string): void {\n if (this._readyState === \"closed\") return\n this._readyState = \"closed\"\n this.onCleanup()\n for (const l of this.closeListeners) {\n try {\n l(code, reason)\n } catch {\n /* swallow */\n }\n }\n this.messageListeners.clear()\n this.closeListeners.clear()\n this.errorListeners.clear()\n }\n\n __handleSinkClosed(): void {\n if (this._readyState === \"closed\") return\n for (const l of this.errorListeners) {\n try {\n l(new Error(\"Tunnel closed mid-WS.\"))\n } catch {\n /* swallow */\n }\n }\n this.__handleClose(1006, \"tunnel_closed\")\n }\n}\n","/**\n * Adapter from a WebSocket-shaped object to a `FrameSink`. Works with\n * both the browser-native WebSocket API and the `ws` library's server\n * sockets — anything with `send`, `close`, and `addEventListener`-style\n * `message`/`close` events.\n *\n * Why a duck-typed shape and not `import(\"ws\")`: the cli, the host,\n * and (eventually) browser hosts all need to wrap WS instances they\n * obtained themselves. Importing `ws` in this package would force\n * every consumer to install it even when running in environments\n * (Bun, Deno, browser) that ship native WebSocket.\n */\n\nimport { encodeFrame, parseFrame, type TunnelFrame } from \"./frames.js\"\nimport type { FrameSink } from \"./transport.js\"\n\nexport interface WebSocketLike {\n send(data: string): void\n close(code?: number, reason?: string): void\n readyState: number\n addEventListener(\n event: \"message\",\n handler: (ev: { data: string | ArrayBuffer | Buffer }) => void\n ): void\n addEventListener(event: \"close\", handler: () => void): void\n addEventListener(event: \"error\", handler: (ev: { message?: string }) => void): void\n removeEventListener(event: string, handler: (...args: never[]) => void): void\n}\n\nconst READY_OPEN = 1\n\nexport function wrapWebSocket(ws: WebSocketLike): FrameSink {\n const frameHandlers = new Set<(frame: TunnelFrame) => void>()\n const closeHandlers = new Set<(reason?: string) => void>()\n let isOpen = ws.readyState === READY_OPEN\n\n // The `ws` library delivers Buffer; the browser delivers string or\n // ArrayBuffer. We coerce to string and parse — everything we send is\n // JSON text, so non-text payloads are protocol violations and get\n // dropped.\n const onMessage = (ev: { data: string | ArrayBuffer | Buffer }): void => {\n let text: string\n if (typeof ev.data === \"string\") text = ev.data\n else if (ev.data instanceof ArrayBuffer) text = Buffer.from(ev.data).toString(\"utf8\")\n else text = (ev.data as Buffer).toString(\"utf8\")\n const frame = parseFrame(text)\n if (!frame) return\n for (const h of frameHandlers) h(frame)\n }\n\n const onClose = (): void => {\n if (!isOpen) return\n isOpen = false\n for (const h of closeHandlers) h(\"transport.closed\")\n frameHandlers.clear()\n closeHandlers.clear()\n }\n\n const onError = (ev: { message?: string }): void => {\n if (!isOpen) return\n isOpen = false\n for (const h of closeHandlers) h(ev.message ?? \"transport.error\")\n frameHandlers.clear()\n closeHandlers.clear()\n }\n\n ws.addEventListener(\"message\", onMessage)\n ws.addEventListener(\"close\", onClose)\n ws.addEventListener(\"error\", onError)\n\n return {\n get isOpen() {\n return isOpen\n },\n send(frame) {\n if (!isOpen) return\n try {\n ws.send(encodeFrame(frame))\n } catch {\n // Send-on-closed-socket is a benign race; rely on the close\n // handler to flip isOpen and let listeners drain naturally.\n }\n },\n close(reason) {\n if (!isOpen) return\n try {\n ws.close(1000, reason)\n } catch {\n // ignore\n }\n },\n onFrame(handler) {\n frameHandlers.add(handler)\n return () => frameHandlers.delete(handler)\n },\n onClose(handler) {\n closeHandlers.add(handler)\n return () => closeHandlers.delete(handler)\n },\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/tunnel/frames.ts","../../src/tunnel/e2e.ts","../../src/tunnel/tunnel-e2e.ts","../../src/tunnel/server.ts","../../src/tunnel/client.ts","../../src/tunnel/ws-adapter.ts"],"names":["b64"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Tunnel frame protocol — agentproto/tunnel/v1.\n *\n * Bidirectional, event-shaped frames over a single duplex transport\n * (typically a WebSocket). Each frame is one JSON object per message.\n * The protocol is deliberately NOT JSON-RPC: process I/O is a\n * continuous event stream, not a request/response pattern, so we drop\n * the `id` / response correlation and let the underlying child-process\n * lifecycle drive everything.\n *\n * # Roles\n *\n * host — the orchestrator (e.g. Guilde API). Sends `spawn`,\n * `stdin`, `kill`, `resize`. Receives `stdout`, `stderr`,\n * `exit`, `error`. Holds the ACP client; sees the duplex\n * stream as a `ChildProcess`-shaped duck.\n *\n * daemon — the local executor (e.g. `agentproto serve` on a user's\n * laptop). Receives spawn-side frames; spawns real\n * subprocesses; relays I/O back. Owns the actual file\n * system, environment, network egress.\n *\n * # Identifiers\n *\n * execId — host-chosen UUID per spawned process. Lets one tunnel\n * multiplex many concurrent agent CLIs (one daemon serving\n * several conversations).\n *\n * # Encoding\n *\n * - Each WS message is one JSON object. Binary frames are not used;\n * stdout/stdin payloads are base64-encoded utf-safe strings.\n * - Why base64 and not raw text: claude-code & friends emit JSON-RPC\n * ACP traffic over stdio. A child can also emit non-utf8 bytes\n * (debug logs, terminal control codes when in TTY mode). Base64\n * keeps the wire JSON-clean and bytewise-faithful.\n * - All frames carry `t` (type) and a per-type payload. Versioning\n * is per-tunnel via `hello.version`, not per-frame.\n *\n * # Lifecycle\n *\n * 1. Daemon connects to host's WS endpoint with bearer token.\n * 2. Daemon sends `hello { version, capabilities, label? }`.\n * 3. Host sends `spawn` for each child it wants on this daemon.\n * 4. Daemon spawns, replies with `spawned { execId, pid }` (or\n * `error { execId, message }`).\n * 5. stdout/stderr/exit notifications flow daemon→host;\n * stdin/resize/kill flow host→daemon.\n * 6. Either side can send `ping`; receiver MUST `pong` back. Used\n * to detect half-open connections.\n * 7. On disconnect, daemon SHOULD kill all children associated with\n * this tunnel (host can re-spawn after reconnect).\n */\n\nexport const TUNNEL_VERSION = \"agentproto/tunnel/v1\" as const\n\n// ─── host → daemon ──────────────────────────────────────────────\n\nexport interface SpawnFrame {\n t: \"spawn\"\n execId: string\n command: string\n args: readonly string[]\n /**\n * Working directory on the daemon side. Daemon SHOULD reject\n * absolute paths that escape its declared `--root` (see\n * `agentproto serve --root`); host MUST pass paths that exist\n * on the daemon.\n */\n cwd?: string\n /**\n * Environment overrides. Daemon merges these atop its own\n * process.env. Daemon MAY redact values from logs but MUST forward\n * them verbatim into the child.\n */\n env?: Readonly<Record<string, string>>\n /**\n * When true, the daemon allocates a PTY instead of plain pipes.\n * Required for binaries that detect `isTTY` (REPLs, claude\n * interactive). When false (default), stdin/stdout/stderr are\n * separate pipes — the right choice for ACP wrappers that speak\n * line-delimited JSON-RPC.\n */\n pty?: boolean\n /** Initial PTY column width. Ignored when `pty` is false. Default 80. */\n cols?: number\n /** Initial PTY row height. Ignored when `pty` is false. Default 24. */\n rows?: number\n}\n\nexport interface StdinFrame {\n t: \"stdin\"\n execId: string\n /** Base64-encoded payload bytes. Empty string is a no-op. */\n data: string\n}\n\nexport interface KillFrame {\n t: \"kill\"\n execId: string\n /** Default \"SIGTERM\". POSIX names; Windows daemons translate. */\n signal?: string\n}\n\nexport interface ResizeFrame {\n t: \"resize\"\n execId: string\n cols: number\n rows: number\n}\n\n/**\n * Generic HTTP-over-tunnel request (HOST → DAEMON). Lets the host\n * proxy arbitrary HTTP traffic (MCP JSON-RPC today, anything tomorrow)\n * through the daemon's local network stack without exposing a public\n * URL. The daemon forwards to its configured \"http upstream\" (default:\n * its own gateway on `127.0.0.1:<port>`) and replies with an\n * `HttpResponseFrame` carrying the same `reqId`.\n */\nexport interface HttpRequestFrame {\n t: \"http_request\"\n /** Correlates the response. Host-chosen, MUST be unique per inflight request. */\n reqId: string\n /** HTTP method (GET / POST / PUT / DELETE / PATCH / OPTIONS). */\n method: string\n /** Path + querystring, e.g. `/mcp` or `/mcp?session=abc`.\n * Daemon prepends its upstream base. Absolute URLs are rejected. */\n path: string\n /** Forwarded request headers. Hop-by-hop headers (Connection,\n * Keep-Alive, Transfer-Encoding, Upgrade, Proxy-*) MUST be stripped\n * before forwarding; daemon SHOULD also drop them defensively. */\n headers?: Readonly<Record<string, string>>\n /** Base64-encoded request body. Omitted when no body. */\n body?: string\n /** Per-request timeout in ms. Daemon SHOULD enforce + reply with\n * `error: { code: \"timeout\" }` when exceeded. Default 30_000. */\n timeoutMs?: number\n}\n\n/**\n * Generic HTTP-over-tunnel response (DAEMON → HOST). Mirrors\n * `HttpRequestFrame` — see its docs.\n *\n * Two-frame protocol:\n * - SHORT RESPONSES (most HTTP): daemon emits a single `http_response`\n * with body inline. The buffered `forwardHttp` resolves directly\n * from this frame.\n * - STREAMED RESPONSES (text/event-stream, long-lived chunked\n * transfers, large downloads): daemon emits `http_response_head`\n * first with status+headers, then one or more `http_response_chunk`\n * frames, the last of which has `end: true`. The streaming\n * `forwardHttpStream` builds a `ReadableStream` from the chunks.\n *\n * Hosts that only support the legacy buffered API can detect the\n * stream protocol by looking for `http_response_head` and either\n * pull the chunks into a buffer (compat) or refuse to handle.\n */\nexport interface HttpResponseFrame {\n t: \"http_response\"\n reqId: string\n /** HTTP status code (e.g. 200, 404, 500). Set even on transport\n * failure (then `error` is also set and status SHOULD be 502/504). */\n status: number\n headers?: Readonly<Record<string, string>>\n /** Base64-encoded response body. */\n body?: string\n /** Set when the daemon failed to complete the upstream call. */\n error?: Readonly<{\n code: string\n message: string\n }>\n}\n\n/**\n * Streaming HTTP response head (DAEMON → HOST). Sent ONCE per\n * streaming response, before any chunk frames. Carries status +\n * headers so the host can finalize the response shape (e.g. write\n * Content-Type) before any body bytes arrive.\n */\nexport interface HttpResponseHeadFrame {\n t: \"http_response_head\"\n reqId: string\n status: number\n headers?: Readonly<Record<string, string>>\n}\n\n/**\n * Streaming HTTP response body chunk (DAEMON → HOST). Each chunk\n * carries some bytes of the response body. The terminal chunk has\n * `end: true` and MAY include final bytes. An immediate `end: true`\n * with no data signals empty-body close.\n *\n * `error` set on a chunk frame indicates the daemon's upstream\n * failed mid-stream; host SHOULD propagate it as a stream error.\n */\nexport interface HttpResponseChunkFrame {\n t: \"http_response_chunk\"\n reqId: string\n /** Base64-encoded chunk bytes. Omitted on pure end-of-stream\n * markers (those carry `end: true` only). */\n data?: string\n /** Set on the last chunk. After this frame the host SHOULD ignore\n * any further frames for this reqId. */\n end?: boolean\n /** Set when the upstream failed mid-stream. Host surfaces this as\n * a stream error and closes the readable. */\n error?: Readonly<{\n code: string\n message: string\n }>\n}\n\n// ─── daemon → host ──────────────────────────────────────────────\n\nexport interface HelloFrame {\n t: \"hello\"\n version: typeof TUNNEL_VERSION\n /**\n * Daemon-declared capabilities. Hosts MAY refuse to dispatch\n * features the daemon hasn't claimed.\n */\n capabilities: Readonly<{\n pty: boolean\n /** Daemon can bridge browser-WS upgrades to its local upstream via\n * `ws_open` / `ws_message` / `ws_close`. Hosts MUST gate\n * `forwardWebSocket()` on this — older daemons ignore the frames. */\n wsForward?: boolean\n /**\n * Identifiers of the capabilities the daemon serves — its registered\n * agent adapters / tool surfaces. Lets a host that fronts several\n * daemons enumerate and route by what each one can do, without a\n * round-trip. Omitted by older daemons (host treats as \"unknown\",\n * not \"none\"). Advisory: the authoritative surface is still the\n * daemon's live `tools/list` over the HTTP relay.\n */\n tools?: ReadonlyArray<string>\n /**\n * Set when this daemon's tunnel channel is E2E-encrypted (design:\n * tunnel-e2e/v1). Informational confirmation only — this `hello` is\n * itself carried INSIDE the already-established encrypted channel (the\n * `wrapE2E` box), so a host that decrypts it has, by definition, already\n * completed the token-authenticated handshake. The negotiation that turns\n * a channel encrypted happens BEFORE this frame, over `e2e_handshake`\n * frames on the raw sink — not by advertising a capability here. A host\n * may surface this flag in its UI (\"this daemon is end-to-end encrypted\").\n * Absent ⇒ plaintext tunnel (today's behaviour). See ./tunnel-e2e.ts.\n */\n e2e?: boolean\n /** Future: file-transfer, port-forward, etc. */\n }>\n /** User-friendly daemon label, surfaced in host UIs. */\n label?: string\n /** Daemon process info — diagnostics only, not authoritative. */\n daemon?: Readonly<{\n name: string\n version: string\n platform: string\n nodeVersion?: string\n }>\n}\n\nexport interface SpawnedFrame {\n t: \"spawned\"\n execId: string\n pid: number\n}\n\nexport interface StdoutFrame {\n t: \"stdout\"\n execId: string\n /** Base64-encoded payload bytes. */\n data: string\n}\n\nexport interface StderrFrame {\n t: \"stderr\"\n execId: string\n /** Base64-encoded payload bytes. */\n data: string\n}\n\nexport interface ExitFrame {\n t: \"exit\"\n execId: string\n /** Null when killed by signal. */\n code: number | null\n /** POSIX signal name when killed by signal; null otherwise. */\n signal: string | null\n}\n\n// ─── either direction ───────────────────────────────────────────\n\nexport interface ErrorFrame {\n t: \"error\"\n /** Omitted for tunnel-level errors not tied to a specific exec. */\n execId?: string\n /** Stable machine-readable code, e.g. \"spawn_failed\", \"unknown_exec\". */\n code: string\n /** Human-readable diagnostic. */\n message: string\n}\n\nexport interface PingFrame {\n t: \"ping\"\n /** Echoed verbatim in the matching pong. */\n nonce: string\n}\n\nexport interface PongFrame {\n t: \"pong\"\n nonce: string\n}\n\n/**\n * HOST → DAEMON. Graceful drain signal sent during host rollover (e.g.\n * Kubernetes preStop). On receipt the daemon SHOULD:\n * 1. Stop accepting new in-flight work where it can.\n * 2. Close the WS cleanly (does not need to wait — host will follow\n * up with a `close(1012, \"service_restart\")` ~2 s later as a\n * hard backstop).\n * 3. Reconnect IMMEDIATELY without the usual exponential backoff —\n * the host is mid-deploy, the new replica is already listening.\n *\n * Backward-compatible: daemons that don't know the frame just ignore\n * it (parseFrame returns null for unknown types). The host's close\n * then triggers the daemon's normal backoff loop — worst case ~30 s\n * reconnect gap instead of ~2 s with the handler.\n */\nexport interface ReconnectSoonFrame {\n t: \"reconnect_soon\"\n /** Hint of how long the host plans to wait before forcing close.\n * Optional — daemons MAY use it to decide whether to finish\n * in-flight work or close immediately. */\n reasonMs?: number\n}\n\n// ─── WebSocket forwarding ───────────────────────────────────────\n//\n// Mirrors the HTTP-forwarding shape but for full-duplex upgrades.\n// The daemon opens a WS connection to its local upstream (typically\n// `ws://127.0.0.1:<port>${path}`), then proxies frames in both\n// directions. Each open is correlated by `reqId`.\n//\n// Capabilities: daemons MUST set `hello.capabilities.wsForward = true`\n// to opt in. Hosts that don't see it MUST NOT send `ws_open`. Older\n// daemons silently ignore unknown frames, so misrouted `ws_open` on a\n// non-capable daemon is benign (the host's open will time out).\n\n/**\n * HOST → DAEMON. Open a WS connection to the daemon's upstream.\n * Path semantics match `HttpRequestFrame` — absolute URLs rejected,\n * daemon prepends its `ws://<upstream>` base. Headers forwarded as-is\n * (cookies are typically NOT forwarded since the daemon's upstream is\n * loopback; cookie passthrough is opt-in via daemon config).\n */\nexport interface WsOpenFrame {\n t: \"ws_open\"\n /** Correlates every WS frame in both directions for this connection. */\n reqId: string\n /** Path + querystring on the daemon-local upstream, e.g.\n * `/sessions/abc/pty?cols=80&rows=24`. */\n path: string\n /** Optional registered upstream to dial instead of the daemon's\n * default gateway — a NAME the daemon resolves to a base URL (never\n * a URL itself, so the host can't point the daemon at an arbitrary\n * origin). Used to reach an imported local service (e.g. a browser\n * capability server) by alias. Absent ⇒ the daemon's own gateway. */\n upstream?: string\n /** Headers to set on the upstream WS request. Hop-by-hop headers\n * (Connection, Upgrade, Sec-WebSocket-*) MUST be stripped — the\n * daemon's `ws` client manages those. */\n headers?: Readonly<Record<string, string>>\n /** Subprotocols requested by the browser; forwarded to upstream. */\n protocols?: readonly string[]\n}\n\n/**\n * DAEMON → HOST. Result of a `ws_open`. On success the upstream WS is\n * connected and frames can flow. On failure `error` is set; no further\n * frames for this `reqId` will arrive.\n */\nexport interface WsOpenAckFrame {\n t: \"ws_open_ack\"\n reqId: string\n /** HTTP status from the upstream upgrade. 101 on success; 4xx/5xx\n * when the upstream refused the upgrade. */\n status: number\n /** Selected subprotocol, if any. */\n protocol?: string\n /** Set when the daemon couldn't open the upstream (DNS failure,\n * refused, timeout). Distinct from a clean upstream-side close,\n * which arrives as `ws_close`. */\n error?: Readonly<{\n code: string\n message: string\n }>\n}\n\n/**\n * Either direction. One application-level WS frame's payload. Text\n * frames carry UTF-8 bytes (`binary: false`); binary frames carry\n * arbitrary bytes (`binary: true`). The `data` field is base64-encoded\n * either way so the transport stays JSON.\n */\nexport interface WsMessageFrame {\n t: \"ws_message\"\n reqId: string\n /** Base64-encoded WS frame payload. */\n data: string\n /** True for binary frames; false (or omitted) for text. */\n binary?: boolean\n}\n\n/**\n * Either direction. Close the bridged WS connection. Includes the\n * close code (1000 normal, 1006 abnormal, etc.) and optional reason.\n * After sending or receiving this frame, neither side will send\n * further frames for `reqId`.\n */\nexport interface WsCloseFrame {\n t: \"ws_close\"\n reqId: string\n /** WebSocket close code. */\n code: number\n reason?: string\n}\n\n// ─── E2E pairing envelopes ──────────────────────────────────────\n//\n// When a tunnel runs over an end-to-end pairing (design: DESIGN §5), the\n// real tunnel/v1 frames above are AEAD-encrypted and carried inside these\n// two envelope frames — the rendezvous relaying the bytes sees only opaque\n// ciphertext. `wrapE2E` in ./e2e.ts produces and consumes them; the tunnel\n// client/server never see them, they only ever see decrypted inner frames.\n//\n// These are added to the frame union (and KNOWN_TYPES) so the transport\n// adapter — which drops any frame `parseFrame` doesn't recognise — forwards\n// them intact to the E2E layer. A tunnel peer that is NOT E2E-wrapped will\n// parse them (they're known types) but has no handler for them, so it ignores\n// them cleanly rather than misinterpreting the bytes as a real frame. The\n// wrapped side is the strict one: it rejects any inbound frame that is not an\n// `e2e` envelope (see `wrapE2E`), which is what prevents a downgrade to\n// plaintext.\n\n/**\n * Either direction. One AEAD-encrypted inner tunnel frame. `n` is the\n * sender's per-direction, strictly-monotonic frame counter — it is the basis\n * of the GCM nonce and lets the receiver detect replay (a repeated/older `n`),\n * reorder, or drops (a gap in `n`). `d` is base64(ciphertext ‖ 16-byte GCM\n * tag). The plaintext, once decrypted, is itself an `encodeFrame`'d\n * `TunnelFrame`.\n */\nexport interface E2eFrame {\n t: \"e2e\"\n n: number\n d: string\n}\n\n/**\n * Either direction. An opaque handshake message exchanged BEFORE the channel\n * is wrapped. `d` is base64 of a transport-agnostic handshake message (the\n * `pair/v1` hello or reply, produced by `@agentproto/secrets/pairing`). The\n * E2E layer here treats it as opaque bytes handed to an injected driver, so\n * this package never depends on the crypto package.\n */\nexport interface E2eHandshakeFrame {\n t: \"e2e_handshake\"\n d: string\n}\n\n// ─── union + guards ─────────────────────────────────────────────\n\nexport type HostToDaemonFrame =\n | SpawnFrame\n | StdinFrame\n | KillFrame\n | ResizeFrame\n | HttpRequestFrame\n | WsOpenFrame\n | WsMessageFrame\n | WsCloseFrame\n | PingFrame\n | PongFrame\n | ErrorFrame\n | ReconnectSoonFrame\n | E2eFrame\n | E2eHandshakeFrame\n\nexport type DaemonToHostFrame =\n | HelloFrame\n | SpawnedFrame\n | StdoutFrame\n | StderrFrame\n | ExitFrame\n | HttpResponseFrame\n | HttpResponseHeadFrame\n | HttpResponseChunkFrame\n | WsOpenAckFrame\n | WsMessageFrame\n | WsCloseFrame\n | PingFrame\n | PongFrame\n | ErrorFrame\n | E2eFrame\n | E2eHandshakeFrame\n\nexport type TunnelFrame = HostToDaemonFrame | DaemonToHostFrame\n\nconst KNOWN_TYPES = new Set<TunnelFrame[\"t\"]>([\n \"spawn\",\n \"stdin\",\n \"kill\",\n \"resize\",\n \"http_request\",\n \"http_response\",\n \"http_response_head\",\n \"http_response_chunk\",\n \"ws_open\",\n \"ws_open_ack\",\n \"ws_message\",\n \"ws_close\",\n \"ping\",\n \"pong\",\n \"error\",\n \"hello\",\n \"spawned\",\n \"stdout\",\n \"stderr\",\n \"exit\",\n \"reconnect_soon\",\n \"e2e\",\n \"e2e_handshake\",\n])\n\n/**\n * Parse a raw WS message into a `TunnelFrame`. Returns null when the\n * payload isn't a valid frame — callers MUST handle null defensively\n * (typically: send an `error` frame and ignore). We don't throw so\n * one bad frame can't tear down the tunnel.\n */\nexport function parseFrame(raw: string): TunnelFrame | null {\n let parsed: unknown\n try {\n parsed = JSON.parse(raw)\n } catch {\n return null\n }\n if (\n !parsed ||\n typeof parsed !== \"object\" ||\n !(\"t\" in parsed) ||\n typeof (parsed as { t: unknown }).t !== \"string\"\n ) {\n return null\n }\n const t = (parsed as { t: string }).t\n if (!KNOWN_TYPES.has(t as TunnelFrame[\"t\"])) return null\n return parsed as TunnelFrame\n}\n\nexport function encodeFrame(frame: TunnelFrame): string {\n return JSON.stringify(frame)\n}\n\n/**\n * Encode raw bytes for an `stdin` / `stdout` / `stderr` frame's `data`\n * field. Centralised so both sides agree on the encoding.\n */\nexport function encodeData(bytes: Uint8Array | string): string {\n const buf =\n typeof bytes === \"string\" ? Buffer.from(bytes, \"utf8\") : Buffer.from(bytes)\n return buf.toString(\"base64\")\n}\n\nexport function decodeData(data: string): Buffer {\n return Buffer.from(data, \"base64\")\n}\n","/**\n * End-to-end AEAD wrapper for a `FrameSink` (design: DESIGN §5).\n *\n * `wrapE2E(inner, keys)` returns a `FrameSink` that is byte-for-byte\n * transparent to the tunnel client/server above it — they send and receive\n * ordinary `TunnelFrame`s — while everything crossing `inner` (the real\n * transport, typically a WebSocket spliced through an untrusted rendezvous) is\n * AES-256-GCM ciphertext wrapped in `e2e` envelope frames. The rendezvous sees\n * only opaque bytes, their sizes, and their timing.\n *\n * There is deliberately NO new application protocol: the existing\n * `agentproto/tunnel/v1` frames are reused verbatim, serialized with\n * `encodeFrame`, encrypted, and carried inside `e2e` envelopes. So\n * `createTunnelClient` / `createTunnelServer` work unchanged over a wrapped\n * sink.\n *\n * Nonce discipline (the security-critical part):\n * - Two independent AES-256-GCM keys, one per direction (`sendKey` /\n * `recvKey`), already assigned by the handshake — so a frame can never be\n * reflected back and decrypt.\n * - A per-direction, strictly-monotonic 64-bit counter `n` is the GCM nonce\n * (never randomly chosen — GCM nonce reuse is catastrophic, and a counter\n * under one key can never repeat). `n` is also bound as AEAD associated\n * data, so it can't be edited without failing the tag.\n * - The receiver requires `n` to be exactly the next expected value.\n * Anything else — an older/repeated `n` (replay), a higher `n` (a dropped\n * or reordered frame) — is a typed `E2eError` that closes the channel.\n * The GCM tag itself catches any bit-flip inside the ciphertext.\n *\n * This module depends only on `node:crypto` and the frame codec — never on the\n * crypto/handshake package. It consumes opaque key material and, for the\n * handshake-over-sink helpers, an opaque driver callback.\n */\n\nimport { createCipheriv, createDecipheriv } from \"node:crypto\"\nimport {\n encodeFrame,\n parseFrame,\n type TunnelFrame,\n} from \"./frames.js\"\nimport type { FrameSink } from \"./transport.js\"\n\n/** The two symmetric session keys, already role-adjusted by the handshake\n * (this side's `sendKey` is the peer's `recvKey`). Each is 32 bytes for\n * AES-256-GCM. */\nexport interface E2eKeys {\n sendKey: Uint8Array\n recvKey: Uint8Array\n}\n\n/** Stable failure codes for the AEAD channel. */\nexport type E2eErrorCode =\n | \"replay\" // an inbound `n` we have already passed — a replayed/duplicated frame\n | \"reorder\" // an inbound `n` ahead of the next expected — a dropped or reordered frame\n | \"auth\" // GCM tag mismatch — the ciphertext or its bound counter was altered\n | \"decode\" // the envelope, or the decrypted plaintext, was not a valid frame\n | \"not_e2e\" // an inbound frame that is not an `e2e` envelope — a downgrade attempt\n | \"overflow\" // the send counter reached the rekey limit (2^32); rekey required\n\n/** Raised for every E2E channel failure. Surfaced via `onSecurityError` and as\n * the `onClose` reason — the channel always closes on any of these, so no\n * tampered or out-of-order frame is ever delivered to the tunnel above. */\nexport class E2eError extends Error {\n readonly code: E2eErrorCode\n constructor(code: E2eErrorCode, message: string) {\n super(message)\n this.name = \"E2eError\"\n this.code = code\n }\n}\n\nexport interface WrapE2EOptions {\n /**\n * Called once, with the typed error, the first time an inbound frame fails\n * an AEAD or counter check (or a send overflows). The channel is closed\n * immediately afterwards. Optional — the same reason is also delivered to\n * `onClose` listeners, so consumers that only care about closure can ignore\n * this.\n */\n onSecurityError?: (err: E2eError) => void\n /**\n * Frame count at which sends must stop and rekey. Defaults to 2^32 — the\n * point at which a 64-bit-counter/one-key regime should rotate keys. v1 has\n * no rekey, so it errors here instead of ever reusing a nonce. Unreachable\n * in practice; the guard exists so it can never be violated.\n */\n maxFrames?: number\n}\n\n/** A wrapped sink also exposes its direction counters, so a later phase can\n * trigger a rekey as they approach the limit. */\nexport interface E2eFrameSink extends FrameSink {\n /** Number of frames this side has encrypted and sent. */\n readonly sentCount: number\n /** Number of frames this side has decrypted and delivered. */\n readonly recvCount: number\n}\n\n/** Default rekey ceiling: 2^32 frames per direction. */\nexport const DEFAULT_E2E_MAX_FRAMES = 0x1_0000_0000\n\nconst TAG_LEN = 16\nconst NONCE_LEN = 12\n\n/** GCM nonce for counter `n`: 12 bytes, the 64-bit big-endian counter in the\n * low 8 bytes (high 4 bytes zero). Direction separation comes from the key,\n * not the nonce, so a per-direction counter never collides with itself. */\nfunction nonceFor(n: number): Buffer {\n const nonce = Buffer.alloc(NONCE_LEN)\n nonce.writeBigUInt64BE(BigInt(n), NONCE_LEN - 8)\n return nonce\n}\n\n/** Associated data binding the counter into the tag: the 64-bit BE counter. */\nfunction aadFor(n: number): Buffer {\n const aad = Buffer.alloc(8)\n aad.writeBigUInt64BE(BigInt(n))\n return aad\n}\n\n/**\n * Wrap `inner` so the tunnel above it exchanges plaintext `TunnelFrame`s while\n * the wire carries AEAD ciphertext. Transparent: pass the result anywhere a\n * `FrameSink` is expected.\n */\nexport function wrapE2E(\n inner: FrameSink,\n keys: E2eKeys,\n opts: WrapE2EOptions = {}\n): E2eFrameSink {\n const maxFrames = opts.maxFrames ?? DEFAULT_E2E_MAX_FRAMES\n const sendKey = Buffer.from(keys.sendKey)\n const recvKey = Buffer.from(keys.recvKey)\n const frameHandlers = new Set<(frame: TunnelFrame) => void>()\n const closeHandlers = new Set<(reason?: string) => void>()\n\n let sentCount = 0\n let recvExpected = 0\n let recvCount = 0\n let open = inner.isOpen\n let failed = false\n\n /** Fail the channel: fire the typed error, close the transport, notify\n * close listeners. Idempotent — the first failure wins. */\n const fail = (err: E2eError): void => {\n if (failed) return\n failed = true\n opts.onSecurityError?.(err)\n closeChannel(err.message)\n }\n\n const closeChannel = (reason?: string): void => {\n if (!open) return\n open = false\n inner.close(reason)\n for (const h of closeHandlers) h(reason)\n frameHandlers.clear()\n closeHandlers.clear()\n }\n\n const onInner = (frame: TunnelFrame): void => {\n if (!open) return\n if (frame.t !== \"e2e\") {\n // A wrapped endpoint must never accept a plaintext (or handshake) frame\n // once the channel is live — that would be a downgrade. Fail closed.\n fail(\n new E2eError(\n \"not_e2e\",\n `expected an e2e envelope, received a plaintext \"${frame.t}\" frame`\n )\n )\n return\n }\n\n const n = frame.n\n if (typeof n !== \"number\" || !Number.isInteger(n) || n < 0) {\n fail(new E2eError(\"decode\", \"e2e envelope has an invalid counter\"))\n return\n }\n if (n < recvExpected) {\n fail(new E2eError(\"replay\", `replayed frame: counter ${n} < expected ${recvExpected}`))\n return\n }\n if (n > recvExpected) {\n fail(new E2eError(\"reorder\", `out-of-order or dropped frame: counter ${n} > expected ${recvExpected}`))\n return\n }\n\n let buf: Buffer\n try {\n buf = Buffer.from(frame.d, \"base64\")\n } catch {\n fail(new E2eError(\"decode\", \"e2e envelope payload is not valid base64\"))\n return\n }\n if (buf.length < TAG_LEN) {\n fail(new E2eError(\"decode\", \"e2e envelope payload is too short to hold a tag\"))\n return\n }\n const ct = buf.subarray(0, buf.length - TAG_LEN)\n const tag = buf.subarray(buf.length - TAG_LEN)\n\n let plaintext: Buffer\n try {\n const decipher = createDecipheriv(\"aes-256-gcm\", recvKey, nonceFor(n))\n decipher.setAAD(aadFor(n))\n decipher.setAuthTag(tag)\n plaintext = Buffer.concat([decipher.update(ct), decipher.final()])\n } catch {\n fail(new E2eError(\"auth\", `frame ${n} failed authentication — tampered ciphertext or wrong key`))\n return\n }\n\n // Advance ONLY after a successful decrypt, so a rejected frame never\n // desynchronises the counter (an attacker can't push us past a good frame).\n recvExpected = n + 1\n recvCount += 1\n\n const decoded = parseFrame(plaintext.toString(\"utf8\"))\n if (!decoded) {\n // AEAD guarantees integrity, so this means an authenticated-but-garbage\n // payload — only reachable via a bug on the far side. Fail closed rather\n // than hand undefined up to the tunnel.\n fail(new E2eError(\"decode\", \"decrypted payload was not a valid tunnel frame\"))\n return\n }\n for (const h of frameHandlers) h(decoded)\n }\n\n const unsubInner = inner.onFrame(onInner)\n const unsubClose = inner.onClose(reason => {\n if (!open) return\n open = false\n for (const h of closeHandlers) h(reason)\n frameHandlers.clear()\n closeHandlers.clear()\n })\n\n return {\n get isOpen() {\n return open\n },\n get sentCount() {\n return sentCount\n },\n get recvCount() {\n return recvCount\n },\n send(frame) {\n if (!open || failed) return\n if (sentCount >= maxFrames) {\n fail(\n new E2eError(\n \"overflow\",\n `send counter reached the rekey limit (${maxFrames}); a rekey is required`\n )\n )\n return\n }\n const n = sentCount\n const plaintext = Buffer.from(encodeFrame(frame), \"utf8\")\n const cipher = createCipheriv(\"aes-256-gcm\", sendKey, nonceFor(n))\n cipher.setAAD(aadFor(n))\n const ct = Buffer.concat([cipher.update(plaintext), cipher.final()])\n const tag = cipher.getAuthTag()\n sentCount += 1\n inner.send({ t: \"e2e\", n, d: Buffer.concat([ct, tag]).toString(\"base64\") })\n },\n close(reason) {\n unsubInner()\n unsubClose()\n closeChannel(reason)\n },\n onFrame(handler) {\n frameHandlers.add(handler)\n return () => frameHandlers.delete(handler)\n },\n onClose(handler) {\n closeHandlers.add(handler)\n return () => closeHandlers.delete(handler)\n },\n }\n}\n\n// ─── handshake over a raw sink ──────────────────────────────────\n//\n// A tiny driver-based helper that runs the two-message `pair/v1` handshake\n// over a raw `FrameSink` using `e2e_handshake` envelopes, then hands back a\n// `wrapE2E`-wrapped sink. The crypto lives entirely in the injected callbacks\n// (backed by `@agentproto/secrets/pairing`), so this stays crypto-agnostic.\n\nexport interface HandshakeOverSinkOptions {\n /** How long to wait for the peer's handshake message before failing.\n * Default 10s. */\n timeoutMs?: number\n /** Forwarded to `wrapE2E`. */\n wrap?: WrapE2EOptions\n}\n\nconst DEFAULT_HANDSHAKE_TIMEOUT_MS = 10_000\n\nfunction b64(bytes: Uint8Array): string {\n return Buffer.from(bytes).toString(\"base64\")\n}\n\n/**\n * Wait for a single `e2e_handshake` frame on `sink`, returning its decoded\n * payload bytes. Rejects on timeout or if the transport closes first. Any\n * other frame type arriving mid-handshake is a protocol violation and rejects\n * — the channel is not yet wrapped, so a stray plaintext frame is illegitimate.\n */\nfunction awaitHandshakeFrame(\n sink: FrameSink,\n timeoutMs: number\n): Promise<Uint8Array> {\n return new Promise((resolve, reject) => {\n let settled = false\n const finish = (fn: () => void): void => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n unsubFrame()\n unsubClose()\n fn()\n }\n const timer = setTimeout(\n () => finish(() => reject(new E2eError(\"decode\", \"handshake timed out\"))),\n timeoutMs\n )\n const unsubFrame = sink.onFrame(frame => {\n if (frame.t !== \"e2e_handshake\") {\n finish(() =>\n reject(\n new E2eError(\n \"not_e2e\",\n `expected an e2e_handshake frame, received \"${frame.t}\"`\n )\n )\n )\n return\n }\n finish(() => resolve(Buffer.from(frame.d, \"base64\")))\n })\n const unsubClose = sink.onClose(reason =>\n finish(() =>\n reject(new E2eError(\"decode\", `transport closed during handshake: ${reason ?? \"unknown\"}`))\n )\n )\n })\n}\n\n/**\n * Client side of the handshake-over-sink. Sends the `hello` bytes, awaits the\n * daemon's single reply, runs `deriveKeys` (which verifies the reply and yields\n * the session keys), and returns a wrapped sink. Rejects — closing the sink —\n * if `deriveKeys` throws (e.g. a bad daemon signature).\n */\nexport async function clientHandshakeOverSink(\n sink: FrameSink,\n hello: Uint8Array,\n deriveKeys: (reply: Uint8Array) => E2eKeys,\n opts: HandshakeOverSinkOptions = {}\n): Promise<E2eFrameSink> {\n const timeoutMs = opts.timeoutMs ?? DEFAULT_HANDSHAKE_TIMEOUT_MS\n const replyPromise = awaitHandshakeFrame(sink, timeoutMs)\n sink.send({ t: \"e2e_handshake\", d: b64(hello) })\n const reply = await replyPromise\n let keys: E2eKeys\n try {\n keys = deriveKeys(reply)\n } catch (err) {\n sink.close(\"handshake failed\")\n throw err\n }\n return wrapE2E(sink, keys, opts.wrap)\n}\n\n/**\n * Daemon side of the handshake-over-sink. Awaits the client `hello`, runs\n * `respond` (which validates it and yields the reply bytes + session keys),\n * sends the reply, and returns a wrapped sink. Rejects — closing the sink — if\n * `respond` throws (e.g. a rejected offer token or tampered hello).\n */\nexport async function daemonHandshakeOverSink(\n sink: FrameSink,\n respond: (hello: Uint8Array) => { reply: Uint8Array; keys: E2eKeys },\n opts: HandshakeOverSinkOptions = {}\n): Promise<E2eFrameSink> {\n const timeoutMs = opts.timeoutMs ?? DEFAULT_HANDSHAKE_TIMEOUT_MS\n const hello = await awaitHandshakeFrame(sink, timeoutMs)\n let result: { reply: Uint8Array; keys: E2eKeys }\n try {\n result = respond(hello)\n } catch (err) {\n sink.close(\"handshake failed\")\n throw err\n }\n sink.send({ t: \"e2e_handshake\", d: b64(result.reply) })\n return wrapE2E(sink, result.keys, opts.wrap)\n}\n","/**\n * Opt-in E2E negotiation for the reverse `serve --connect` tunnel\n * (design: tunnel-e2e/v1).\n *\n * The plaintext reverse tunnel lets a host terminate the WS and read every\n * `agentproto/tunnel/v1` frame. These helpers upgrade that channel to the\n * `wrapE2E` AEAD box using a short, token-authenticated ephemeral handshake, so\n * even a trusted host loses plaintext visibility — while staying fully\n * backward-compatible: with an old peer (or the feature off) the channel stays\n * exactly as it is today.\n *\n * ## Negotiation, and why it lives before the tunnel `hello`\n *\n * `createTunnelServer` emits the tunnel `hello` as its very first frame, and we\n * want that `hello` — and everything after it — INSIDE the encrypted box. So the\n * negotiation cannot ride on the `hello`; it runs first, on the raw sink, over\n * `e2e_handshake` frames:\n *\n * ```\n * daemon → host: e2e_handshake(offer) // daemon advertises e2e + its ephemeral\n * host → daemon: e2e_handshake(accept) // host advertises e2e + its ephemeral\n * … both wrapE2E(sink) and speak tunnel/v1 encrypted from here …\n * ```\n *\n * The daemon (initiator) offers e2e ONLY when configured to; the host accepts\n * ONLY when it too supports it. If either doesn't, we fall back to plaintext:\n * - **Old host**: never sends an `accept`. `e2e_handshake` is a known frame\n * type with no handler on an unwrapped peer, so the daemon's offer is\n * ignored, and after `timeoutMs` the daemon falls back to plaintext on the\n * same still-open sink. One stray, ignored frame — behaviour is otherwise\n * identical to today.\n * - **Daemon with e2e off**: never sends an `offer`; it emits the plaintext\n * `hello` first. An e2e-capable host detects a non-handshake first frame and\n * falls back, re-injecting that frame into its plaintext client.\n *\n * ## Fail-closed vs. fall-back\n *\n * A silent peer (timeout) is a COMPATIBILITY signal → fall back to plaintext. A\n * peer that DID answer but whose handshake is invalid (a wrong `tunnel.token`, a\n * tampered message) is a SECURITY signal → the injected crypto throws and we\n * close the sink and propagate, never downgrading to plaintext. Distinguishing\n * these two is the whole point of returning `null` on timeout but throwing on a\n * bad handshake.\n *\n * This module is crypto-agnostic: all key material comes from injected callbacks\n * (backed by `@agentproto/secrets/pairing`'s `tunnel-handshake`). It depends only\n * on `wrapE2E` + the frame codec, so `@agentproto/acp` never imports the crypto\n * package — exactly as the pairing handshake-over-sink helpers do.\n */\n\nimport { wrapE2E, E2eError, type E2eKeys, type E2eFrameSink, type WrapE2EOptions } from \"./e2e.js\"\nimport type { FrameSink } from \"./transport.js\"\nimport type { TunnelFrame } from \"./frames.js\"\n\n/** Default negotiation timeout: how long the daemon waits for the host's\n * `accept` (or the host waits for the daemon's first frame) before concluding\n * the peer does not support e2e and falling back to plaintext. */\nexport const DEFAULT_TUNNEL_E2E_TIMEOUT_MS = 8_000\n\nexport interface TunnelE2EOptions {\n /** Negotiation timeout in ms. Default `DEFAULT_TUNNEL_E2E_TIMEOUT_MS`. */\n timeoutMs?: number\n /** Forwarded to `wrapE2E`. */\n wrap?: WrapE2EOptions\n}\n\nfunction b64(bytes: Uint8Array): string {\n return Buffer.from(bytes).toString(\"base64\")\n}\n\n/**\n * Await the first frame on `sink`. Resolves with the frame, or `null` on\n * timeout, and rejects (with the close reason) if the transport closes first.\n * Leaves the sink untouched on timeout so the caller can fall back on it.\n */\nfunction awaitFirstFrame(sink: FrameSink, timeoutMs: number): Promise<TunnelFrame | null> {\n return new Promise((resolve, reject) => {\n let settled = false\n const finish = (fn: () => void): void => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n unsubFrame()\n unsubClose()\n fn()\n }\n const timer = setTimeout(() => finish(() => resolve(null)), timeoutMs)\n const unsubFrame = sink.onFrame(frame => finish(() => resolve(frame)))\n const unsubClose = sink.onClose(reason =>\n finish(() =>\n reject(new E2eError(\"decode\", `transport closed during e2e negotiation: ${reason ?? \"unknown\"}`)),\n ),\n )\n })\n}\n\n// ─── daemon (initiator) side ────────────────────────────────────\n\n/**\n * Daemon side of the tunnel-e2e negotiation. Sends the `offer` bytes as an\n * `e2e_handshake` frame, awaits the host's single reply, and:\n *\n * - **reply arrives** → runs `deriveKeys` (which verifies the reply and yields\n * the session keys) and returns a `wrapE2E`-wrapped sink. If `deriveKeys`\n * throws — a wrong `tunnel.token`, a tampered accept — this CLOSES the sink\n * and rethrows: a security failure must NOT silently downgrade to plaintext.\n * - **timeout (peer silent)** → returns `null`. The peer is an old/plaintext\n * host; the sink is left open so the caller falls back to plaintext on it.\n * - **a non-handshake frame arrives first** → protocol violation (a compliant\n * old host stays silent until it receives the tunnel `hello`); closes the\n * sink and throws.\n */\nexport async function connectSinkE2E(\n sink: FrameSink,\n offer: Uint8Array,\n deriveKeys: (reply: Uint8Array) => E2eKeys,\n opts: TunnelE2EOptions = {},\n): Promise<E2eFrameSink | null> {\n const timeoutMs = opts.timeoutMs ?? DEFAULT_TUNNEL_E2E_TIMEOUT_MS\n const firstPromise = awaitFirstFrame(sink, timeoutMs)\n sink.send({ t: \"e2e_handshake\", d: b64(offer) })\n const first = await firstPromise\n if (first === null) {\n // Peer never answered — treat as \"does not support e2e\" and fall back.\n return null\n }\n if (first.t !== \"e2e_handshake\") {\n sink.close(\"e2e negotiation: unexpected frame\")\n throw new E2eError(\n \"not_e2e\",\n `expected an e2e_handshake accept, received \"${first.t}\"`,\n )\n }\n let keys: E2eKeys\n try {\n keys = deriveKeys(Buffer.from(first.d, \"base64\"))\n } catch (err) {\n // Wrong token / tampered accept → fail closed, never downgrade.\n sink.close(\"e2e handshake failed\")\n throw err\n }\n return wrapE2E(sink, keys, opts.wrap)\n}\n\n// ─── host (responder) side ──────────────────────────────────────\n\n/** Outcome of the host-side negotiation. On the plaintext branch, `sink` is a\n * view of the original transport that will replay any already-read frame to the\n * first subscriber — so the host can hand it straight to a plaintext tunnel\n * client without losing the daemon's `hello`. */\nexport type AcceptSinkE2EResult =\n | { e2e: true; sink: E2eFrameSink }\n | { e2e: false; sink: FrameSink }\n\n/**\n * Host side of the tunnel-e2e negotiation. Awaits the daemon's first frame:\n *\n * - **`e2e_handshake` offer** → runs `respond` (which verifies the offer and\n * yields the reply bytes + session keys), sends the reply, and returns a\n * `wrapE2E`-wrapped sink. A `respond` throw — wrong token, tampered offer —\n * closes the sink and rethrows (fail closed).\n * - **any other frame** (the daemon emitted a plaintext `hello` — it isn't\n * doing e2e) → returns `{ e2e: false }` with a sink that replays that frame,\n * so the caller's plaintext client still sees it.\n * - **timeout** → `{ e2e: false }` on the raw sink (nothing to replay).\n */\nexport async function acceptSinkE2E(\n sink: FrameSink,\n respond: (offer: Uint8Array) => { reply: Uint8Array; keys: E2eKeys },\n opts: TunnelE2EOptions = {},\n): Promise<AcceptSinkE2EResult> {\n const timeoutMs = opts.timeoutMs ?? DEFAULT_TUNNEL_E2E_TIMEOUT_MS\n const first = await awaitFirstFrame(sink, timeoutMs)\n if (first === null) {\n return { e2e: false, sink }\n }\n if (first.t !== \"e2e_handshake\") {\n // Daemon isn't offering e2e — hand back a sink that re-delivers this frame.\n return { e2e: false, sink: prependFrame(sink, first) }\n }\n let result: { reply: Uint8Array; keys: E2eKeys }\n try {\n result = respond(Buffer.from(first.d, \"base64\"))\n } catch (err) {\n sink.close(\"e2e handshake failed\")\n throw err\n }\n sink.send({ t: \"e2e_handshake\", d: b64(result.reply) })\n return { e2e: true, sink: wrapE2E(sink, result.keys, opts.wrap) }\n}\n\n/**\n * A thin `FrameSink` view of `inner` that re-delivers one already-consumed\n * `frame` to the FIRST `onFrame` subscriber before forwarding live frames. Used\n * on the host's plaintext-fallback path: the negotiation read the daemon's first\n * frame (its `hello`) off the raw sink, so it must be replayed to the plaintext\n * client that subscribes next. The replay runs BEFORE we subscribe to `inner`,\n * so a buffering transport's queued frames still arrive in order after it.\n */\nfunction prependFrame(inner: FrameSink, frame: TunnelFrame): FrameSink {\n let replayed = false\n return {\n get isOpen() {\n return inner.isOpen\n },\n send(f) {\n inner.send(f)\n },\n close(reason) {\n inner.close(reason)\n },\n onFrame(handler) {\n if (!replayed) {\n replayed = true\n handler(frame)\n }\n return inner.onFrame(handler)\n },\n onClose(handler) {\n return inner.onClose(handler)\n },\n }\n}\n","/**\n * Tunnel server (daemon side).\n *\n * Sits on the local machine that actually owns the binaries (e.g. the\n * user's laptop running `agentproto serve`). Accepts spawn frames from\n * a remote host, spawns the requested child via node:child_process,\n * pipes stdio back as `stdout`/`stderr` frames, and reports lifecycle\n * via `spawned`/`exit`/`error`.\n *\n * Transport-agnostic: the caller passes a `FrameSink`. For WebSocket\n * callers, see `wrapWebSocket()` in ./ws-adapter.ts.\n *\n * Security: this process MUST refuse spawn requests by default unless\n * the caller installed an `authorize(spawn)` hook. We don't expose a\n * \"trust everything\" mode — every host integration is responsible for\n * deciding what the remote may exec. The hook gets the full SpawnFrame\n * and can mutate it (e.g. force `cwd` into a workspace) or reject.\n */\n\nimport { spawn, type ChildProcess } from \"node:child_process\"\nimport { hostname, platform } from \"node:os\"\nimport {\n TUNNEL_VERSION,\n decodeData,\n encodeData,\n encodeFrame,\n parseFrame,\n type ExitFrame,\n type HttpRequestFrame,\n type HttpResponseFrame,\n type SpawnFrame,\n type StderrFrame,\n type StdoutFrame,\n type TunnelFrame,\n type WsOpenFrame,\n} from \"./frames.js\"\nimport type { FrameSink } from \"./transport.js\"\n\n/**\n * Default ceiling for an upstream WS dial. An upstream that accepts the TCP\n * connection but never completes (or rejects) the WebSocket upgrade would\n * otherwise leave the `ws_open` pending forever — the host never gets an ack or\n * a reject. Bounded so a hung upstream surfaces as a 504 instead.\n */\nexport const DEFAULT_WS_DIAL_TIMEOUT_MS = 10_000\n\n/**\n * Default ceiling for an `http_request` forward when the frame carries no\n * `timeoutMs`. Covers connect + buffered body (or connect + headers for a\n * stream, after which the bound is handed to `httpStreamIdleTimeoutMs`).\n */\nexport const DEFAULT_HTTP_FORWARD_TIMEOUT_MS = 30_000\n\nexport interface TunnelServerOptions {\n sink: FrameSink\n /**\n * Authorization hook. Called for each `spawn` frame BEFORE the\n * subprocess is created. Return the (possibly mutated) frame to\n * proceed; throw or return null to reject. Rejection causes an\n * `error` frame with code \"spawn_unauthorized\".\n *\n * No default — callers MUST decide. Pass `(req) => req` to allow\n * everything (useful for tests; never for production).\n */\n authorize: (req: SpawnFrame) => SpawnFrame | null | Promise<SpawnFrame | null>\n /**\n * Upstream HTTP base URL for `http_request` frames. The daemon\n * appends the frame's `path` and forwards. Typically the local\n * gateway address — `http://127.0.0.1:18790`. When omitted, the\n * daemon replies to any `http_request` with\n * `error: { code: \"http_upstream_not_configured\" }`.\n */\n httpUpstream?: string\n /**\n * Headers merged into EVERY forwarded `http_request` before it hits the\n * upstream, overriding any same-named header from the frame. Used by the E2E\n * pairing serve path to inject the daemon's own bearer token so a\n * peer-authenticated pairing passes the gateway's mutating-route token gate\n * (`checkSessionsToken` has no loopback bypass) — see DESIGN §5. Omitted for\n * the trusted `serve --connect` host, which needs no injection. The pairing\n * layer never learns or transports the user's daemon bearer beyond this hop.\n */\n httpInjectHeaders?: Readonly<Record<string, string>>\n /**\n * Default ceiling for an `http_request` forward (connect + buffered body, or\n * connect + headers for a stream) when the frame carries no `timeoutMs`.\n * Defaults to DEFAULT_HTTP_FORWARD_TIMEOUT_MS. Disarmed once a streaming\n * response is detected — see `httpStreamIdleTimeoutMs` for the stream phase.\n */\n httpForwardTimeoutMs?: number\n /**\n * Idle ceiling between chunks of a STREAMING response (SSE / ndjson). A\n * stalled upstream that sends headers then hangs forever between chunks would\n * otherwise block indefinitely (the regular timeout is disarmed for streams,\n * since they're long-lived by design). Counts time since the last byte and\n * resets on every chunk, so a heartbeating stream is never cut. Omitted ⇒ no\n * idle bound (current behaviour); set it to guard against silent stalls.\n */\n httpStreamIdleTimeoutMs?: number\n /** User-friendly label sent in the hello frame. */\n label?: string\n /**\n * Capability identifiers advertised in the hello frame — the agent\n * adapters / tool surfaces this daemon serves (e.g. the gateway's\n * registered adapter ids). Lets a multi-daemon host enumerate and\n * route by capability without a round-trip. Omit to advertise none.\n */\n tools?: ReadonlyArray<string>\n /**\n * Set when the `sink` is an E2E-encrypted channel (a `wrapE2E` box). Purely\n * informational — surfaced to the host as `hello.capabilities.e2e` so it can\n * confirm/display that the tunnel is end-to-end encrypted. The encryption\n * itself is established by the handshake BEFORE this server is constructed\n * (see ./tunnel-e2e.ts); this flag does not turn anything on. Default false.\n */\n e2e?: boolean\n /**\n * Whether this daemon advertises PTY support. Set to true only when\n * `spawnPty` is also provided.\n */\n pty?: boolean\n /**\n * Factory for PTY-backed processes. When provided (and `pty: true`),\n * spawn frames with `pty: true` use this instead of node:child_process.\n * Injected from the CLI layer so the ACP package stays native-free.\n */\n spawnPty?: (opts: {\n command: string\n args: string[]\n cwd?: string\n env?: Record<string, string>\n cols: number\n rows: number\n }) => PtyProcess\n /**\n * Optional hook fired once per successful spawn — after authorize\n * passed and the ChildProcess has emitted its `spawn` event.\n * Lets the daemon adopt this child into a higher-level registry\n * (e.g. @agentproto/runtime's sessions registry, AIP-46) so the\n * spawn shows up in /sessions, the LocalDaemonSessionsCard, and\n * the CLI TUI alongside spawns originated locally.\n *\n * The hook is fire-and-forget — the tunnel doesn't await its\n * return. Errors from the hook are swallowed so an observer\n * registry hiccup never breaks the tunnel exchange.\n */\n onChildSpawned?: (info: {\n execId: string\n child: ChildProcess\n request: SpawnFrame\n }) => void\n /**\n * Optional hook fired when the host sends a `reconnect_soon` frame —\n * graceful drain signal during host rollover. The daemon SHOULD\n * close + reconnect immediately (skipping any backoff) so the new\n * host replica picks it up. Default: ignore (the host follows up\n * with `close(1012)` and the daemon's own reconnect supervisor\n * handles it via normal backoff, ~30 s gap).\n *\n * Implementations typically call into their connection supervisor\n * to mark the next reconnect as \"no-backoff\" then close the sink.\n * `reasonMs` is the host's hint for how long it will wait before\n * forcing close — daemons MAY use it to drain in-flight RPCs first.\n */\n onReconnectSoon?: (info: { reasonMs?: number }) => void\n /**\n * Factory that dials a WS connection to the local upstream. When\n * provided (and `httpUpstream` is set), the daemon advertises\n * `wsForward` capability and handles `ws_open` frames by piping the\n * upstream WS through the tunnel. Injected so `@agentproto/acp`\n * stays free of a hard `ws` dependency — the CLI provides this\n * factory using its already-pulled-in `ws` package.\n */\n dialUpstreamWs?: (params: {\n url: string\n protocols?: readonly string[]\n headers?: Readonly<Record<string, string>>\n /**\n * Aborted when the dial exceeds `wsDialTimeoutMs` (or the tunnel tears down\n * mid-dial). A cooperating implementation SHOULD abort the in-flight upgrade\n * and reject so the socket isn't left half-open; even if it doesn't, the\n * server bounds the wait independently and rejects the `ws_open`.\n */\n signal?: AbortSignal\n }) => Promise<UpstreamWebSocket>\n /**\n * Ceiling for `dialUpstreamWs` to resolve before the `ws_open` is rejected\n * with 504 `upstream_ws_timeout`. Defaults to DEFAULT_WS_DIAL_TIMEOUT_MS.\n */\n wsDialTimeoutMs?: number\n /**\n * Resolve a named upstream (a `ws_open` frame's `upstream` field) to an\n * HTTP base URL the daemon should dial instead of `httpUpstream`. Lets a\n * host reach an imported local service by alias (e.g. a browser capability\n * server) without ever naming a raw origin — the daemon owns the name→URL\n * mapping. Return undefined for an unknown alias (the open is rejected).\n * Omitted ⇒ every `ws_open` dials the default `httpUpstream`.\n */\n resolveWsUpstream?: (\n upstream: string\n ) => string | undefined | Promise<string | undefined>\n}\n\n/**\n * Minimal upstream WS surface — satisfied by the `ws` library's\n * client socket. Daemons supplying `dialUpstreamWs` resolve into\n * one of these as soon as the WS is OPEN. `protocol` is the\n * subprotocol negotiated by the upstream (empty string when none).\n */\nexport interface UpstreamWebSocket {\n readonly protocol: string\n /** Send a frame to the upstream. */\n send(data: Buffer | string, opts: { binary: boolean }): void\n /** Close the upstream connection. */\n close(code?: number, reason?: string): void\n /** Subscribe to inbound frames. */\n onMessage(handler: (data: Buffer, isBinary: boolean) => void): void\n /** Subscribe to upstream close. */\n onClose(handler: (code: number, reason: string) => void): void\n /** Subscribe to transport errors. */\n onError(handler: (err: Error) => void): void\n}\n\n/** Minimal PTY process surface — satisfied by node-pty's IPty. */\nexport interface PtyProcess {\n readonly pid: number\n write(data: string): void\n resize(cols: number, rows: number): void\n kill(signal?: string): void\n onData(handler: (data: string) => void): void\n onExit(handler: (event: { exitCode: number; signal?: number }) => void): void\n}\n\nexport interface TunnelServer {\n /** Currently-live execId → ChildProcess. Read-only diagnostic. */\n readonly children: ReadonlyMap<string, ChildProcess>\n /** Kill all live children and close the sink. */\n close(): Promise<void>\n}\n\nexport function createTunnelServer(opts: TunnelServerOptions): TunnelServer {\n const children = new Map<string, ChildProcess>()\n // PTY-backed processes keyed by execId (separate from pipe-based children).\n const ptyProcs = new Map<string, PtyProcess>()\n // Per-reqId map of bridged upstream WS connections. Each entry's\n // lifecycle starts at ws_open (we send open_ack on success) and ends\n // at ws_close (either direction). On tunnel teardown we close all.\n const upstreamWs = new Map<string, UpstreamWebSocket>()\n let closed = false\n\n // Greet the host immediately so it can fail fast on version\n // mismatch before issuing spawns.\n opts.sink.send({\n t: \"hello\",\n version: TUNNEL_VERSION,\n capabilities: {\n pty: opts.pty === true,\n wsForward: opts.dialUpstreamWs !== undefined && !!opts.httpUpstream,\n ...(opts.tools && opts.tools.length ? { tools: opts.tools } : {}),\n ...(opts.e2e === true ? { e2e: true } : {}),\n },\n label: opts.label,\n daemon: {\n name: \"agentproto\",\n version: \"0.1.0-alpha\",\n platform: `${platform()}/${hostname()}`,\n nodeVersion: process.version,\n },\n })\n\n const offFrame = opts.sink.onFrame((frame) => {\n handleFrame(frame).catch((err) => {\n const message = err instanceof Error ? err.message : String(err)\n opts.sink.send({ t: \"error\", code: \"internal\", message })\n })\n })\n\n const offClose = opts.sink.onClose(() => {\n closed = true\n for (const [, child] of children) child.kill(\"SIGTERM\")\n children.clear()\n for (const [, pty] of ptyProcs) pty.kill()\n ptyProcs.clear()\n for (const [, ws] of upstreamWs) {\n try {\n ws.close(1001, \"tunnel_closed\")\n } catch {\n /* socket may already be dead */\n }\n }\n upstreamWs.clear()\n offFrame()\n offClose()\n })\n\n async function handleFrame(frame: TunnelFrame): Promise<void> {\n switch (frame.t) {\n case \"spawn\":\n await handleSpawn(frame)\n return\n case \"stdin\": {\n const pty = ptyProcs.get(frame.execId)\n if (pty) {\n pty.write(Buffer.from(frame.data, \"base64\").toString(\"utf8\"))\n return\n }\n const child = children.get(frame.execId)\n if (!child || !child.stdin) {\n opts.sink.send({\n t: \"error\",\n execId: frame.execId,\n code: \"unknown_exec\",\n message: `No live exec '${frame.execId}'`,\n })\n return\n }\n child.stdin.write(Buffer.from(frame.data, \"base64\"))\n return\n }\n case \"kill\": {\n const pty = ptyProcs.get(frame.execId)\n if (pty) {\n pty.kill(frame.signal ?? \"SIGTERM\")\n return\n }\n const child = children.get(frame.execId)\n if (!child) {\n opts.sink.send({\n t: \"error\",\n execId: frame.execId,\n code: \"unknown_exec\",\n message: `No live exec '${frame.execId}'`,\n })\n return\n }\n child.kill((frame.signal as NodeJS.Signals | undefined) ?? \"SIGTERM\")\n return\n }\n case \"resize\": {\n ptyProcs.get(frame.execId)?.resize(frame.cols, frame.rows)\n return\n }\n case \"http_request\":\n // Fire-and-forget — the handler emits its own http_response\n // frame (or error). Errors that escape handleHttpRequest\n // bubble to the outer .catch and become a generic `error`\n // frame, but the per-request error path inside the handler\n // produces an http_response with `error:` set, which is what\n // the host's forwardHttp expects.\n await handleHttpRequest(frame)\n return\n case \"ws_open\":\n await handleWsOpen(frame)\n return\n case \"ws_message\": {\n const ws = upstreamWs.get(frame.reqId)\n if (!ws) {\n // Stale frame for a closed bridge — silently drop. Sending\n // an error frame would race with our own ws_close on the\n // teardown path.\n return\n }\n try {\n ws.send(decodeData(frame.data), { binary: frame.binary === true })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n opts.sink.send({\n t: \"ws_close\",\n reqId: frame.reqId,\n code: 1011,\n reason: `send_failed: ${message}`,\n })\n try {\n ws.close(1011, \"send_failed\")\n } catch {\n /* defensive */\n }\n upstreamWs.delete(frame.reqId)\n }\n return\n }\n case \"ws_close\": {\n const ws = upstreamWs.get(frame.reqId)\n if (!ws) return\n upstreamWs.delete(frame.reqId)\n try {\n ws.close(frame.code, frame.reason)\n } catch {\n /* socket may already be dead */\n }\n return\n }\n case \"ping\":\n opts.sink.send({ t: \"pong\", nonce: frame.nonce })\n return\n case \"reconnect_soon\":\n // Host is shutting down this replica (e.g. k8s preStop). Fire\n // the supervisor hook so the daemon CLI can drop the WS +\n // reconnect without exponential backoff. We do NOT close the\n // sink here — that's the supervisor's call (it may want to\n // drain in-flight RPCs first using the `reasonMs` hint).\n try {\n opts.onReconnectSoon?.({\n ...(frame.reasonMs !== undefined ? { reasonMs: frame.reasonMs } : {}),\n })\n } catch {\n /* defensive — supervisor hook must never break the tunnel */\n }\n return\n case \"pong\":\n case \"error\":\n // Daemon doesn't act on these; host-side concern.\n return\n default:\n opts.sink.send({\n t: \"error\",\n code: \"unknown_frame\",\n message: `Daemon received unexpected frame type '${(frame as { t: string }).t}'`,\n })\n }\n }\n\n async function handleSpawn(req: SpawnFrame): Promise<void> {\n if (closed) return\n let approved: SpawnFrame | null\n try {\n approved = await opts.authorize(req)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n opts.sink.send({\n t: \"error\",\n execId: req.execId,\n code: \"spawn_unauthorized\",\n message,\n })\n return\n }\n if (!approved) {\n opts.sink.send({\n t: \"error\",\n execId: req.execId,\n code: \"spawn_unauthorized\",\n message: \"Authorize hook rejected the spawn request.\",\n })\n return\n }\n\n // PTY path — use injected spawnPty factory when pty:true is requested.\n if (approved.pty && opts.spawnPty) {\n let pty: PtyProcess\n try {\n pty = opts.spawnPty({\n command: approved.command,\n args: [...approved.args],\n cwd: approved.cwd,\n env: approved.env ? { ...approved.env } : undefined,\n cols: approved.cols ?? 80,\n rows: approved.rows ?? 24,\n })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n opts.sink.send({ t: \"error\", execId: req.execId, code: \"spawn_failed\", message })\n return\n }\n\n ptyProcs.set(req.execId, pty)\n opts.sink.send({ t: \"spawned\", execId: req.execId, pid: pty.pid })\n\n pty.onData(data => {\n opts.sink.send({ t: \"stdout\", execId: req.execId, data: encodeData(data) })\n })\n pty.onExit(({ exitCode, signal }) => {\n opts.sink.send({\n t: \"exit\",\n execId: req.execId,\n code: exitCode,\n signal: signal != null ? String(signal) : null,\n })\n ptyProcs.delete(req.execId)\n })\n\n if (opts.onChildSpawned) {\n try {\n // PTY processes can't be adopted as ChildProcess — pass a no-op shim\n // so the hook fires (for session visibility) without crashing.\n opts.onChildSpawned({\n execId: req.execId,\n child: { pid: pty.pid } as unknown as ChildProcess,\n request: approved,\n })\n } catch { /* fire-and-forget */ }\n }\n return\n }\n\n let child: ChildProcess\n try {\n child = spawn(approved.command, [...approved.args], {\n cwd: approved.cwd,\n env: { ...process.env, ...(approved.env ?? {}) },\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n // detached:false so SIGINT/SIGTERM on the daemon kills children too.\n })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n opts.sink.send({\n t: \"error\",\n execId: req.execId,\n code: \"spawn_failed\",\n message,\n })\n return\n }\n\n children.set(req.execId, child)\n\n if (typeof child.pid === \"number\") {\n opts.sink.send({ t: \"spawned\", execId: req.execId, pid: child.pid })\n } else {\n // Pid is null when spawn synchronously failed. The 'error'\n // event below will fire with the real cause; we still report\n // a placeholder spawned to keep the lifecycle predictable.\n opts.sink.send({ t: \"spawned\", execId: req.execId, pid: -1 })\n }\n\n // Notify the higher-level registry (when wired) — this is what\n // makes tunnel-driven spawns visible in the daemon's\n // /sessions list alongside spawns originated locally. Errors\n // from the observer never break the tunnel.\n if (opts.onChildSpawned) {\n try {\n opts.onChildSpawned({ execId: req.execId, child, request: approved })\n } catch (err) {\n // Hook is fire-and-forget — log + continue.\n // Use console.warn directly because tunnel server has no\n // logger context.\n console.warn(\n `[tunnel-server] onChildSpawned hook threw for execId=${req.execId}: ${\n err instanceof Error ? err.message : String(err)\n }`\n )\n }\n }\n\n child.stdout?.on(\"data\", (chunk: Buffer) => {\n const f: StdoutFrame = {\n t: \"stdout\",\n execId: req.execId,\n data: encodeData(chunk),\n }\n opts.sink.send(f)\n })\n child.stderr?.on(\"data\", (chunk: Buffer) => {\n const f: StderrFrame = {\n t: \"stderr\",\n execId: req.execId,\n data: encodeData(chunk),\n }\n opts.sink.send(f)\n })\n\n child.on(\"error\", (err) => {\n opts.sink.send({\n t: \"error\",\n execId: req.execId,\n code: \"child_error\",\n message: err.message,\n })\n })\n\n child.on(\"exit\", (code, signal) => {\n const f: ExitFrame = {\n t: \"exit\",\n execId: req.execId,\n code,\n signal,\n }\n opts.sink.send(f)\n children.delete(req.execId)\n })\n }\n\n /**\n * Open a bridged WS connection to the local upstream. Same path-\n * safety rules as `handleHttpRequest` (no absolute URLs, no `..`),\n * same hop-by-hop header stripping. The `dialUpstreamWs` factory\n * resolves to an `UpstreamWebSocket` once the upgrade is OPEN — we\n * then emit `ws_open_ack` to the host and start piping frames.\n */\n async function handleWsOpen(req: WsOpenFrame): Promise<void> {\n if (closed) return\n const reject = (\n status: number,\n code: string,\n message: string\n ): void => {\n opts.sink.send({\n t: \"ws_open_ack\",\n reqId: req.reqId,\n status,\n error: { code, message },\n })\n }\n if (!opts.dialUpstreamWs || !opts.httpUpstream) {\n reject(\n 502,\n \"ws_upstream_not_configured\",\n \"Daemon does not support WS forwarding — start with `--upstream ws://…` (or upgrade).\"\n )\n return\n }\n if (\n !req.path.startsWith(\"/\") ||\n req.path.startsWith(\"//\") ||\n req.path.includes(\"..\")\n ) {\n reject(\n 400,\n \"invalid_path\",\n `Daemon WS forward requires a safe relative path; got '${req.path}'.`\n )\n return\n }\n const HOP_BY_HOP = new Set([\n \"connection\",\n \"upgrade\",\n \"sec-websocket-version\",\n \"sec-websocket-key\",\n \"sec-websocket-extensions\",\n \"sec-websocket-protocol\",\n \"host\",\n \"content-length\",\n ])\n const headers: Record<string, string> = {}\n for (const [k, v] of Object.entries(req.headers ?? {})) {\n if (HOP_BY_HOP.has(k.toLowerCase())) continue\n headers[k] = v\n }\n // Pick the HTTP base: a named upstream (resolved by the daemon to an\n // imported service's origin) when the frame carries one, else the\n // default gateway. The host names an alias, never a URL, so it can't\n // steer the daemon at an arbitrary origin.\n let httpBase = opts.httpUpstream\n if (req.upstream) {\n const resolved = await opts.resolveWsUpstream?.(req.upstream)\n if (!resolved) {\n reject(\n 502,\n \"unknown_ws_upstream\",\n `No WS upstream registered for '${req.upstream}'.`\n )\n return\n }\n httpBase = resolved\n }\n // Map the http upstream base to a ws scheme. The daemon's upstream\n // is conventionally http://127.0.0.1:<port>; the same host accepts\n // WS upgrades on the same port, so ws://… works.\n const base = httpBase.replace(/^http(s?):\\/\\//, \"ws$1://\")\n const url = `${base.replace(/\\/$/, \"\")}${req.path}`\n\n // Bound the dial: a hung upstream that never finishes the upgrade must not\n // strand the ws_open. Abort the dial (cooperating impls cancel the real\n // socket) AND race the timeout independently, so even an impl that ignores\n // the signal still yields a 504.\n const dialTimeoutMs = opts.wsDialTimeoutMs ?? DEFAULT_WS_DIAL_TIMEOUT_MS\n const dialAbort = new AbortController()\n let dialTimedOut = false\n let dialTimer: ReturnType<typeof setTimeout> | null = null\n const dialPromise = opts.dialUpstreamWs({\n url,\n ...(req.protocols && req.protocols.length > 0\n ? { protocols: req.protocols }\n : {}),\n headers,\n signal: dialAbort.signal,\n })\n const timeoutPromise = new Promise<never>((_resolve, rej) => {\n dialTimer = setTimeout(() => {\n dialTimedOut = true\n dialAbort.abort(new Error(\"ws_dial_timeout\"))\n rej(new Error(`upstream WS dial timed out after ${dialTimeoutMs}ms`))\n }, dialTimeoutMs)\n if (typeof dialTimer !== \"number\") dialTimer.unref()\n })\n\n let upstream: UpstreamWebSocket\n try {\n upstream = await Promise.race([dialPromise, timeoutPromise])\n } catch (err) {\n if (dialTimer) clearTimeout(dialTimer)\n if (dialTimedOut) {\n // The timeout won the race. If the abandoned dial ever resolves, close\n // the orphaned socket so it doesn't leak.\n dialPromise.then(\n sock => {\n try {\n sock.close(1001, \"dial_timeout\")\n } catch {\n /* defensive */\n }\n },\n () => {},\n )\n reject(\n 504,\n \"upstream_ws_timeout\",\n `Upstream did not complete the WS upgrade within ${dialTimeoutMs}ms.`,\n )\n return\n }\n const message = err instanceof Error ? err.message : String(err)\n // Try to extract an HTTP status from a `ws` error like\n // `Unexpected server response: 404`.\n const m = message.match(/Unexpected server response: (\\d+)/)\n const status = m ? Number.parseInt(m[1]!, 10) : 502\n reject(status, \"upstream_ws_failed\", message)\n return\n }\n if (dialTimer) clearTimeout(dialTimer)\n // Race: caller already abandoned us (tunnel closed mid-upgrade).\n if (closed) {\n try {\n upstream.close(1001, \"tunnel_closed\")\n } catch {\n /* defensive */\n }\n return\n }\n upstreamWs.set(req.reqId, upstream)\n opts.sink.send({\n t: \"ws_open_ack\",\n reqId: req.reqId,\n status: 101,\n ...(upstream.protocol ? { protocol: upstream.protocol } : {}),\n })\n\n upstream.onMessage((data, isBinary) => {\n if (!opts.sink.isOpen) return\n opts.sink.send({\n t: \"ws_message\",\n reqId: req.reqId,\n data: encodeData(data),\n binary: isBinary,\n })\n })\n upstream.onClose((code, reason) => {\n if (!upstreamWs.has(req.reqId)) return\n upstreamWs.delete(req.reqId)\n if (opts.sink.isOpen) {\n opts.sink.send({\n t: \"ws_close\",\n reqId: req.reqId,\n code,\n ...(reason ? { reason } : {}),\n })\n }\n })\n upstream.onError(err => {\n // Errors typically precede a close; emit a stable error code in\n // the close frame so the host can distinguish from clean close.\n if (!upstreamWs.has(req.reqId)) return\n upstreamWs.delete(req.reqId)\n if (opts.sink.isOpen) {\n opts.sink.send({\n t: \"ws_close\",\n reqId: req.reqId,\n code: 1011,\n reason: `upstream_error: ${err.message}`,\n })\n }\n try {\n upstream.close(1011, \"upstream_error\")\n } catch {\n /* defensive */\n }\n })\n }\n\n async function handleHttpRequest(req: HttpRequestFrame): Promise<void> {\n if (closed) return\n const respond = (\n partial:\n | { status: number; headers?: HttpResponseFrame[\"headers\"]; body?: string }\n | { error: HttpResponseFrame[\"error\"]; status: number }\n ): void => {\n opts.sink.send({\n t: \"http_response\",\n reqId: req.reqId,\n ...partial,\n } as HttpResponseFrame)\n }\n\n // Reject if no upstream is configured. Better explicit error\n // than a confusing 502 from a missing fetch target.\n if (!opts.httpUpstream) {\n respond({\n status: 502,\n error: {\n code: \"http_upstream_not_configured\",\n message:\n \"Daemon was not started with an http upstream — cannot forward HTTP frames.\",\n },\n })\n return\n }\n\n // Path-only is required to keep the daemon from being a generic\n // SSRF amplifier. Absolute URLs (including protocol-relative `//`)\n // and parent-traversal are rejected. Querystrings are fine.\n if (\n !req.path.startsWith(\"/\") ||\n req.path.startsWith(\"//\") ||\n req.path.includes(\"..\")\n ) {\n respond({\n status: 400,\n error: {\n code: \"invalid_path\",\n message: `Daemon http forward requires a safe relative path; got '${req.path}'.`,\n },\n })\n return\n }\n\n // Strip hop-by-hop headers defensively before forwarding —\n // they're meaningful only to the previous transport hop.\n const HOP_BY_HOP = new Set([\n \"connection\",\n \"keep-alive\",\n \"transfer-encoding\",\n \"upgrade\",\n \"proxy-authenticate\",\n \"proxy-authorization\",\n \"te\",\n \"trailer\",\n \"host\", // upstream sets its own based on the URL\n \"content-length\", // fetch recomputes\n ])\n const headers: Record<string, string> = {}\n for (const [k, v] of Object.entries(req.headers ?? {})) {\n if (HOP_BY_HOP.has(k.toLowerCase())) continue\n headers[k] = v\n }\n // Daemon-injected headers (e.g. an internal bearer so a peer-authenticated\n // pairing passes the gateway's mutating-route token gate — DESIGN §5). These\n // win over any forwarded header of the same (case-insensitive) name.\n if (opts.httpInjectHeaders) {\n for (const [k, v] of Object.entries(opts.httpInjectHeaders)) {\n const lower = k.toLowerCase()\n for (const existing of Object.keys(headers)) {\n if (existing.toLowerCase() === lower) delete headers[existing]\n }\n headers[k] = v\n }\n }\n\n const url = `${opts.httpUpstream.replace(/\\/$/, \"\")}${req.path}`\n const controller = new AbortController()\n const timeoutMs =\n req.timeoutMs ??\n opts.httpForwardTimeoutMs ??\n DEFAULT_HTTP_FORWARD_TIMEOUT_MS\n // For streaming responses (SSE / long-poll), the daemon-side\n // request must NOT abort on the regular timeout — the stream is\n // *meant* to be long-lived. We arm the timer initially, then\n // disarm it as soon as we detect a streaming response so the\n // stream can run indefinitely (the host enforces its own teardown\n // via tunnel close / explicit cancel).\n let timer: ReturnType<typeof setTimeout> | null = setTimeout(\n () => controller.abort(),\n timeoutMs\n )\n const clearTimer = () => {\n if (timer) {\n clearTimeout(timer)\n timer = null\n }\n }\n try {\n const upstreamRes = await fetch(url, {\n method: req.method,\n headers,\n body:\n req.body === undefined ? undefined : decodeData(req.body),\n signal: controller.signal,\n // node fetch follows redirects by default — fine for MCP, the\n // upstream gateway doesn't redirect anyway.\n })\n const outHeaders: Record<string, string> = {}\n upstreamRes.headers.forEach((value, key) => {\n if (HOP_BY_HOP.has(key.toLowerCase())) return\n outHeaders[key] = value\n })\n\n // Streaming detection — SSE responses MUST go through the\n // chunked-frame protocol so the host can pipe bytes to the\n // browser in real time. Anything else stays on the buffered\n // path for now (small JSON responses are simpler that way; we\n // can widen streaming to all responses later once it's proven).\n const contentType = (outHeaders[\"content-type\"] ?? \"\").toLowerCase()\n const isStream =\n contentType.startsWith(\"text/event-stream\") ||\n contentType.includes(\"application/x-ndjson\")\n\n if (isStream && upstreamRes.body) {\n // Disarm the request-level timeout — SSE streams are\n // long-lived by design. The host closing the tunnel (or the\n // upstream closing its end) is what terminates us now.\n clearTimer()\n opts.sink.send({\n t: \"http_response_head\",\n reqId: req.reqId,\n status: upstreamRes.status,\n headers: outHeaders,\n })\n const reader = upstreamRes.body.getReader()\n // Inter-chunk idle bound: the request timeout is disarmed for streams,\n // so without this a stalled upstream (headers sent, then silence) hangs\n // forever. The timer resets per chunk, so a heartbeating stream is never\n // cut. `IDLE` is the sentinel for \"no byte arrived within the window\".\n const idleMs = opts.httpStreamIdleTimeoutMs\n const IDLE = Symbol(\"idle\")\n type ReadResult = Awaited<ReturnType<typeof reader.read>>\n const readChunk = async (): Promise<ReadResult | typeof IDLE> => {\n if (!idleMs) return reader.read()\n let idleTimer: ReturnType<typeof setTimeout> | null = null\n const idle = new Promise<typeof IDLE>(resolve => {\n idleTimer = setTimeout(() => resolve(IDLE), idleMs)\n if (typeof idleTimer !== \"number\") idleTimer.unref()\n })\n try {\n return await Promise.race([reader.read(), idle])\n } finally {\n if (idleTimer) clearTimeout(idleTimer)\n }\n }\n try {\n while (true) {\n const chunk = await readChunk()\n if (chunk === IDLE) {\n try {\n await reader.cancel()\n } catch {\n /* ignore */\n }\n opts.sink.send({\n t: \"http_response_chunk\",\n reqId: req.reqId,\n end: true,\n error: {\n code: \"upstream_stream_idle_timeout\",\n message: `No data from upstream for ${idleMs}ms.`,\n },\n })\n return\n }\n const { value, done } = chunk\n if (done) {\n opts.sink.send({\n t: \"http_response_chunk\",\n reqId: req.reqId,\n end: true,\n })\n return\n }\n if (value && value.byteLength > 0) {\n opts.sink.send({\n t: \"http_response_chunk\",\n reqId: req.reqId,\n data: encodeData(Buffer.from(value)),\n })\n }\n // Stop streaming if the tunnel sink closed under us — no\n // point feeding chunks into the void.\n if (!opts.sink.isOpen) {\n try {\n await reader.cancel()\n } catch {\n /* ignore */\n }\n return\n }\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n opts.sink.send({\n t: \"http_response_chunk\",\n reqId: req.reqId,\n end: true,\n error: { code: \"upstream_stream_failed\", message },\n })\n }\n return\n }\n\n // Buffered path (unchanged): small responses + non-SSE traffic.\n const buf = Buffer.from(await upstreamRes.arrayBuffer())\n respond({\n status: upstreamRes.status,\n headers: outHeaders,\n body: buf.length > 0 ? encodeData(buf) : \"\",\n })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n const aborted = err instanceof Error && err.name === \"AbortError\"\n respond({\n status: aborted ? 504 : 502,\n error: {\n code: aborted ? \"timeout\" : \"upstream_fetch_failed\",\n message,\n },\n })\n } finally {\n clearTimer()\n }\n }\n\n return {\n children,\n async close() {\n if (closed) return\n closed = true\n for (const [, child] of children) child.kill(\"SIGTERM\")\n children.clear()\n opts.sink.close(\"server.close\")\n },\n }\n}\n\n// Re-exports for convenience — server-only callers don't need to\n// reach into ./frames for these.\nexport { encodeFrame, parseFrame }\n","/**\n * Tunnel client (host side).\n *\n * Sits on the orchestrator (e.g. Guilde API). Speaks to a remote daemon\n * over a `FrameSink`. Exposes `spawn(command, args, opts)` that returns\n * an object shaped like Node's `ChildProcess` — same `.stdin` /\n * `.stdout` / `.stderr` / `.on('exit')` / `.kill()` surface. This lets\n * the existing ACP protocol arm drive remote subprocesses with zero\n * code changes; the arm thinks it's talking to a local child.\n *\n * The duck is intentionally minimal — only the methods the ACP arm\n * actually calls. If you need the full ChildProcess interface, wrap\n * this with a node:stream.Readable shim.\n */\n\nimport { EventEmitter } from \"node:events\"\nimport { Readable, Writable } from \"node:stream\"\nimport { randomUUID } from \"node:crypto\"\nimport {\n TUNNEL_VERSION,\n decodeData,\n encodeData,\n type ExitFrame,\n type HelloFrame,\n type HttpRequestFrame,\n type HttpResponseFrame,\n type SpawnFrame,\n type SpawnedFrame,\n type StderrFrame,\n type StdoutFrame,\n type TunnelFrame,\n type WsOpenFrame,\n} from \"./frames.js\"\nimport type { FrameSink } from \"./transport.js\"\n\n/** Resolved response from `forwardHttp`. Mirrors `HttpResponseFrame`\n * but with the body decoded back to a Buffer for the caller. */\nexport interface TunnelHttpResponse {\n status: number\n headers: Readonly<Record<string, string>>\n body: Buffer\n /** Set when the daemon failed to complete the upstream call. */\n error?: Readonly<{\n code: string\n message: string\n }>\n}\n\n/** Resolved response from `forwardHttpStream`. Body is a Web\n * `ReadableStream<Uint8Array>` — consume it to receive chunks as\n * they arrive from the daemon's upstream (SSE, long-poll, NDJSON).\n * The stream closes when the daemon's upstream closes OR an upstream\n * error occurs (surfaced as a stream error on the reader). */\nexport interface TunnelHttpStreamResponse {\n status: number\n headers: Readonly<Record<string, string>>\n body: ReadableStream<Uint8Array>\n}\n\nexport interface TunnelHttpRequest {\n method: string\n path: string\n headers?: Readonly<Record<string, string>>\n body?: Buffer | Uint8Array | string\n /** Per-request timeout in ms. Default 30_000. */\n timeoutMs?: number\n}\n\nexport interface TunnelWebSocketOpenRequest {\n /** Path + querystring on the daemon-local upstream. Daemon prepends\n * its `ws://<upstream>` base; absolute URLs are rejected. */\n path: string\n /** Optional registered upstream to dial instead of the daemon's default\n * gateway — a NAME the daemon resolves to a base URL (e.g. an imported\n * service alias). The host never names a raw origin. */\n upstream?: string\n /** Headers forwarded to the upstream upgrade. Hop-by-hop / Sec-* are\n * stripped by the daemon. Cookies are NOT forwarded unless the\n * daemon was started with `--upstream-cookies`. */\n headers?: Readonly<Record<string, string>>\n /** Subprotocols requested. Echoed in `protocol` on success. */\n protocols?: readonly string[]\n /** How long to wait for the upstream upgrade before erroring. The\n * message stream itself has no timeout (WS lives as long as either\n * end keeps it open). Default 30_000. */\n openTimeoutMs?: number\n}\n\n/**\n * Bridged WS connection. Mirrors the surface of a browser WebSocket\n * minus URL/protocol bookkeeping — the host already chose those when\n * calling `forwardWebSocket`. Messages are typed as text (UTF-8 string)\n * or binary (Uint8Array); the bridge preserves the upstream's framing.\n */\nexport interface TunnelWebSocket {\n /** True until `close` runs in either direction. */\n readonly readyState: \"open\" | \"closing\" | \"closed\"\n /** Selected subprotocol from the upstream's upgrade response, if any. */\n readonly protocol: string | null\n /** Send a frame to the daemon's upstream. No-op when not open. */\n send(data: string | Uint8Array): void\n /** Initiate a clean close. Idempotent. */\n close(code?: number, reason?: string): void\n /** Subscribe to inbound frames. Returns an unsubscribe fn. */\n onMessage(\n listener: (data: Buffer, isBinary: boolean) => void\n ): () => void\n /** Subscribe to close. Fires exactly once (after either side closes\n * OR the tunnel itself drops). Returns an unsubscribe fn. */\n onClose(listener: (code: number, reason: string) => void): () => void\n /** Subscribe to transport-level errors. Closes follow shortly. */\n onError(listener: (err: Error) => void): () => void\n}\n\nexport interface TunnelClientOptions {\n sink: FrameSink\n /**\n * Reject the `spawn` call if the daemon hasn't sent its `hello`\n * within this window. Defaults to 10s — generous for high-latency\n * tunnels but fast enough that misconfigured daemons fail loudly.\n */\n helloTimeoutMs?: number\n}\n\nexport interface TunnelSpawnOptions {\n cwd?: string\n env?: Readonly<Record<string, string>>\n /** Allocate a PTY on the daemon. Requires `hello.capabilities.pty`. */\n pty?: boolean\n /** Initial PTY column width (ignored when `pty` is false). Default 80. */\n cols?: number\n /** Initial PTY row height (ignored when `pty` is false). Default 24. */\n rows?: number\n}\n\n/**\n * Minimal ChildProcess-shaped duck. Covers the surface our ACP arm\n * calls; expand only when a real consumer needs more.\n */\nexport interface TunnelChildProcess {\n readonly execId: string\n readonly pid: number | null\n readonly stdin: Writable\n readonly stdout: Readable\n readonly stderr: Readable\n /** \"exit\" → (code, signal). \"error\" → (Error). */\n on(event: \"exit\", listener: (code: number | null, signal: string | null) => void): this\n on(event: \"error\", listener: (err: Error) => void): this\n kill(signal?: NodeJS.Signals | number): boolean\n /** Send a terminal resize to the daemon. No-op if the exec isn't PTY-backed. */\n resize(cols: number, rows: number): void\n}\n\nexport interface TunnelClient {\n /**\n * Resolves once the daemon has sent its `hello` frame, OR rejects\n * with a tunnel-level error. Subsequent calls return the cached\n * promise.\n */\n ready(): Promise<HelloFrame>\n spawn(\n command: string,\n args: readonly string[],\n opts?: TunnelSpawnOptions\n ): Promise<TunnelChildProcess>\n /**\n * Forward an HTTP request through the tunnel to the daemon's\n * configured upstream (typically `http://127.0.0.1:<port>`). The\n * daemon completes the upstream call and replies with the response,\n * which this promise resolves to. Rejects on tunnel-transport\n * failure; the daemon-reported HTTP status (incl. 5xx) is returned\n * in the resolved value.\n *\n * Streaming responses (text/event-stream, NDJSON) are buffered into\n * the returned Buffer. For real streaming, use `forwardHttpStream`.\n */\n forwardHttp(req: TunnelHttpRequest): Promise<TunnelHttpResponse>\n /**\n * Stream an HTTP response through the tunnel. The promise resolves\n * as soon as the response head (status + headers) arrives — the\n * body chunks then flow through `body` (a ReadableStream) until the\n * daemon's upstream closes. Required for SSE / NDJSON / long-poll\n * upstreams where buffering until the end would defeat the point.\n * For one-shot HTTP, prefer `forwardHttp`.\n */\n forwardHttpStream(req: TunnelHttpRequest): Promise<TunnelHttpStreamResponse>\n /**\n * Open a bridged WebSocket through the tunnel. The promise resolves\n * once the daemon has completed the upstream upgrade; from that\n * point messages flow via the returned `TunnelWebSocket`.\n *\n * Rejects on:\n * - missing `hello.capabilities.wsForward` — older daemon, no bridge\n * - upstream upgrade failure (4xx/5xx) — `cause` carries the status\n * - timeout waiting for `ws_open_ack`\n */\n forwardWebSocket(req: TunnelWebSocketOpenRequest): Promise<TunnelWebSocket>\n close(): Promise<void>\n}\n\nexport function createTunnelClient(opts: TunnelClientOptions): TunnelClient {\n const helloTimeoutMs = opts.helloTimeoutMs ?? 10_000\n let hello: HelloFrame | null = null\n let helloPromise: Promise<HelloFrame> | null = null\n\n // Per-execId routing tables. We dispatch incoming frames to the\n // right child duck by execId; spawn awaits its own `spawned` /\n // `error` reply via these one-shot resolvers.\n const childByExec = new Map<string, TunnelChildDuck>()\n const spawnPending = new Map<\n string,\n { resolve: (frame: SpawnedFrame) => void; reject: (err: Error) => void }\n >()\n\n // Inflight HTTP forwards keyed by reqId. Each entry's mode depends\n // on which API the caller used:\n // - \"buffered\": forwardHttp(). Resolves once the full body has\n // arrived (either as a single `http_response` frame, OR as\n // `http_response_head` + chunks that get concatenated here).\n // - \"stream\": forwardHttpStream(). Resolves on `http_response_head`\n // with a ReadableStream that's fed by subsequent chunk frames.\n // For backward-compat with daemons that emit a single\n // `http_response`, we synthesize a one-chunk stream + end.\n // Either mode handles either server response shape — the daemon's\n // streaming decision is purely server-side (Content-Type based), and\n // the client adapts.\n type HttpPending =\n | {\n mode: \"buffered\"\n resolve: (resp: TunnelHttpResponse) => void\n reject: (err: Error) => void\n timer: ReturnType<typeof setTimeout>\n // Set when daemon starts a chunked response.\n streamHead: {\n status: number\n headers: Record<string, string>\n } | null\n streamChunks: Buffer[]\n }\n | {\n mode: \"stream\"\n resolveHead: (resp: TunnelHttpStreamResponse) => void\n reject: (err: Error) => void\n timer: ReturnType<typeof setTimeout>\n // Set once the head arrives — drains pendingChunks into it.\n controller: ReadableStreamDefaultController<Uint8Array> | null\n pendingChunks: Buffer[]\n headEmitted: boolean\n // Goes true after `end: true` so a late close-of-tunnel doesn't\n // try to error a closed controller.\n ended: boolean\n }\n const httpPending = new Map<string, HttpPending>()\n\n // Per-reqId routing for bridged WS connections. Lifecycle:\n // 1. forwardWebSocket() inserts a `wsOpenPending` entry + sends ws_open\n // 2. Daemon emits ws_open_ack → we resolve the open promise into a\n // TunnelWebSocketDuck, move it to `wsByReq`, drop the pending entry\n // 3. Bidirectional ws_message frames route to the duck\n // 4. ws_close in either direction tears the duck down + drops from the map\n // 5. Tunnel close errors all open WSes with code 1006\n type WsPending = {\n resolve: (ws: TunnelWebSocket) => void\n reject: (err: Error) => void\n timer: ReturnType<typeof setTimeout>\n }\n const wsOpenPending = new Map<string, WsPending>()\n const wsByReq = new Map<string, TunnelWebSocketDuck>()\n\n const offFrame = opts.sink.onFrame((frame) => routeIncoming(frame))\n const offClose = opts.sink.onClose(() => {\n for (const [, duck] of childByExec) duck.__handleSinkClosed()\n childByExec.clear()\n for (const [, p] of spawnPending) {\n p.reject(new Error(\"Tunnel closed before spawn completed.\"))\n }\n spawnPending.clear()\n for (const [, p] of httpPending) {\n clearTimeout(p.timer)\n if (p.mode === \"buffered\") {\n p.reject(new Error(\"Tunnel closed before HTTP response arrived.\"))\n } else {\n // For an active stream, error the controller so the consumer's\n // reader.read() rejects instead of hanging forever. If the head\n // hasn't been emitted yet, reject the head promise too.\n if (!p.headEmitted) {\n p.reject(new Error(\"Tunnel closed before HTTP response head arrived.\"))\n } else if (p.controller && !p.ended) {\n try {\n p.controller.error(new Error(\"Tunnel closed mid-stream.\"))\n } catch {\n /* already closed */\n }\n }\n }\n }\n httpPending.clear()\n for (const [, p] of wsOpenPending) {\n clearTimeout(p.timer)\n p.reject(new Error(\"Tunnel closed before WS upgrade completed.\"))\n }\n wsOpenPending.clear()\n for (const [, duck] of wsByReq) {\n duck.__handleSinkClosed()\n }\n wsByReq.clear()\n offFrame()\n offClose()\n })\n\n function routeIncoming(frame: TunnelFrame): void {\n switch (frame.t) {\n case \"hello\":\n if (frame.version !== TUNNEL_VERSION) {\n // Mismatch — surface via the ready() rejection. We don't\n // tear down the sink because the caller may want to\n // negotiate a fallback.\n throw new Error(\n `Tunnel daemon speaks ${frame.version}; this client speaks ${TUNNEL_VERSION}.`\n )\n }\n hello = frame\n return\n case \"spawned\": {\n const pending = spawnPending.get(frame.execId)\n if (pending) {\n spawnPending.delete(frame.execId)\n pending.resolve(frame)\n }\n return\n }\n case \"stdout\": {\n const duck = childByExec.get(frame.execId)\n duck?.__pushStdout(decodeData((frame as StdoutFrame).data))\n return\n }\n case \"stderr\": {\n const duck = childByExec.get(frame.execId)\n duck?.__pushStderr(decodeData((frame as StderrFrame).data))\n return\n }\n case \"exit\": {\n const duck = childByExec.get(frame.execId)\n duck?.__handleExit(frame as ExitFrame)\n childByExec.delete(frame.execId)\n return\n }\n case \"error\": {\n if (frame.execId) {\n const pending = spawnPending.get(frame.execId)\n if (pending) {\n spawnPending.delete(frame.execId)\n pending.reject(new Error(`${frame.code}: ${frame.message}`))\n return\n }\n const duck = childByExec.get(frame.execId)\n duck?.__pushError(new Error(`${frame.code}: ${frame.message}`))\n return\n }\n // Tunnel-level error: nowhere to surface it cleanly here.\n // Callers that care should wrap the FrameSink and observe\n // tunnel-error frames themselves.\n return\n }\n case \"http_response\": {\n // Buffered response from the daemon — single-frame body.\n const pending = httpPending.get(frame.reqId)\n if (!pending) return\n httpPending.delete(frame.reqId)\n clearTimeout(pending.timer)\n const body = frame.body ? decodeData(frame.body) : Buffer.alloc(0)\n if (pending.mode === \"buffered\") {\n pending.resolve({\n status: frame.status,\n headers: frame.headers ?? {},\n body,\n ...(frame.error ? { error: frame.error } : {}),\n })\n } else {\n // Caller asked for a stream but the daemon decided to send\n // a single buffered response. Synthesize a one-chunk stream\n // so the same consumer code path works.\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n if (body.length > 0) controller.enqueue(new Uint8Array(body))\n controller.close()\n },\n })\n pending.resolveHead({\n status: frame.status,\n headers: frame.headers ?? {},\n body: stream,\n })\n }\n return\n }\n case \"http_response_head\": {\n const pending = httpPending.get(frame.reqId)\n if (!pending) return\n const headers = frame.headers ?? {}\n if (pending.mode === \"stream\") {\n // Wire a ReadableStream whose controller drains any chunks\n // we've buffered while waiting for the head frame (rare —\n // chunks shouldn't precede the head — but harmless).\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n pending.controller = controller\n for (const chunk of pending.pendingChunks) {\n if (chunk.length > 0) controller.enqueue(new Uint8Array(chunk))\n }\n pending.pendingChunks = []\n },\n cancel: () => {\n // Consumer abandoned the stream — clean up the pending\n // entry. We don't send a cancel frame to the daemon\n // (the protocol doesn't define one), so the daemon will\n // keep streaming until its upstream closes; we simply\n // drop frames we still receive.\n if (httpPending.get(frame.reqId) === pending) {\n clearTimeout(pending.timer)\n httpPending.delete(frame.reqId)\n }\n },\n })\n pending.headEmitted = true\n // Stream is long-lived — disarm the buffered-mode timeout\n // (it was a safety net for a stuck buffered response).\n clearTimeout(pending.timer)\n pending.resolveHead({\n status: frame.status,\n headers,\n body: stream,\n })\n } else {\n // Buffered caller, streaming server — start accumulating\n // chunks; we'll resolve once `end: true` arrives.\n pending.streamHead = { status: frame.status, headers }\n }\n return\n }\n case \"http_response_chunk\": {\n const pending = httpPending.get(frame.reqId)\n if (!pending) return\n const data = frame.data ? decodeData(frame.data) : Buffer.alloc(0)\n if (pending.mode === \"stream\") {\n if (frame.error) {\n // Upstream error mid-stream — surface it on the reader.\n try {\n pending.controller?.error(\n new Error(`${frame.error.code}: ${frame.error.message}`)\n )\n } catch {\n /* already closed */\n }\n pending.ended = true\n clearTimeout(pending.timer)\n httpPending.delete(frame.reqId)\n return\n }\n if (pending.controller) {\n if (data.length > 0) {\n try {\n pending.controller.enqueue(new Uint8Array(data))\n } catch {\n /* reader detached — drop */\n }\n }\n if (frame.end) {\n try {\n pending.controller.close()\n } catch {\n /* already closed */\n }\n pending.ended = true\n clearTimeout(pending.timer)\n httpPending.delete(frame.reqId)\n }\n } else {\n // Head hasn't been processed yet — buffer until it is.\n if (data.length > 0) pending.pendingChunks.push(data)\n if (frame.end) {\n // Race: chunk-end before head. Defer closing until head\n // creates the controller.\n pending.ended = true\n }\n }\n } else {\n // Buffered mode — accumulate chunks; resolve on end.\n if (data.length > 0) pending.streamChunks.push(data)\n if (frame.error) {\n clearTimeout(pending.timer)\n httpPending.delete(frame.reqId)\n const concatenated = Buffer.concat(pending.streamChunks)\n pending.resolve({\n status: pending.streamHead?.status ?? 502,\n headers: pending.streamHead?.headers ?? {},\n body: concatenated,\n error: frame.error,\n })\n return\n }\n if (frame.end) {\n clearTimeout(pending.timer)\n httpPending.delete(frame.reqId)\n const concatenated = Buffer.concat(pending.streamChunks)\n pending.resolve({\n status: pending.streamHead?.status ?? 200,\n headers: pending.streamHead?.headers ?? {},\n body: concatenated,\n })\n }\n }\n return\n }\n case \"ws_open_ack\": {\n const pending = wsOpenPending.get(frame.reqId)\n if (!pending) return\n wsOpenPending.delete(frame.reqId)\n clearTimeout(pending.timer)\n if (frame.error || frame.status !== 101) {\n const code = frame.error?.code ?? `http_${frame.status}`\n const msg =\n frame.error?.message ??\n `Upstream WS upgrade returned ${frame.status}`\n pending.reject(new Error(`${code}: ${msg}`))\n return\n }\n const duck = new TunnelWebSocketDuck(\n frame.reqId,\n frame.protocol ?? null,\n opts.sink,\n () => wsByReq.delete(frame.reqId)\n )\n wsByReq.set(frame.reqId, duck)\n pending.resolve(duck)\n return\n }\n case \"ws_message\": {\n const duck = wsByReq.get(frame.reqId)\n if (!duck) return // stale frame after close — drop\n duck.__handleMessage(decodeData(frame.data), frame.binary === true)\n return\n }\n case \"ws_close\": {\n // Resolve a pending open if the daemon closes before acking\n // (e.g. upstream refused mid-upgrade and emitted close).\n const pending = wsOpenPending.get(frame.reqId)\n if (pending) {\n wsOpenPending.delete(frame.reqId)\n clearTimeout(pending.timer)\n pending.reject(\n new Error(\n `WS closed before upgrade (code ${frame.code}${frame.reason ? `: ${frame.reason}` : \"\"})`\n )\n )\n return\n }\n const duck = wsByReq.get(frame.reqId)\n if (duck) {\n wsByReq.delete(frame.reqId)\n duck.__handleClose(frame.code, frame.reason ?? \"\")\n }\n return\n }\n case \"ping\":\n opts.sink.send({ t: \"pong\", nonce: frame.nonce })\n return\n case \"pong\":\n case \"spawn\":\n case \"stdin\":\n case \"kill\":\n case \"resize\":\n case \"http_request\":\n case \"ws_open\":\n // Not expected on the host side; ignore.\n return\n }\n }\n\n return {\n ready() {\n if (hello) return Promise.resolve(hello)\n if (helloPromise) return helloPromise\n helloPromise = new Promise<HelloFrame>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(\n new Error(\n `Tunnel daemon did not send hello within ${helloTimeoutMs}ms.`\n )\n )\n }, helloTimeoutMs)\n // Rebind sink listener so we resolve on the next hello.\n const off = opts.sink.onFrame((frame) => {\n if (frame.t !== \"hello\") return\n clearTimeout(timer)\n off()\n if (frame.version !== TUNNEL_VERSION) {\n reject(\n new Error(\n `Tunnel daemon speaks ${frame.version}; client speaks ${TUNNEL_VERSION}.`\n )\n )\n return\n }\n hello = frame\n resolve(frame)\n })\n })\n return helloPromise\n },\n\n async spawn(command, args, spawnOpts) {\n if (!hello) await this.ready()\n if (spawnOpts?.pty && hello?.capabilities.pty !== true) {\n throw new Error(\n `Tunnel daemon '${hello?.label ?? \"(unnamed)\"}' does not advertise PTY support.`\n )\n }\n const execId = randomUUID()\n const req: SpawnFrame = {\n t: \"spawn\",\n execId,\n command,\n args,\n cwd: spawnOpts?.cwd,\n env: spawnOpts?.env,\n pty: spawnOpts?.pty,\n ...(spawnOpts?.pty ? { cols: spawnOpts.cols ?? 80, rows: spawnOpts.rows ?? 24 } : {}),\n }\n const spawnedFrame = await new Promise<SpawnedFrame>(\n (resolve, reject) => {\n spawnPending.set(execId, { resolve, reject })\n opts.sink.send(req)\n }\n )\n const duck = new TunnelChildDuck(execId, spawnedFrame.pid, opts.sink)\n childByExec.set(execId, duck)\n return duck\n },\n\n async forwardHttp(req: TunnelHttpRequest): Promise<TunnelHttpResponse> {\n if (!hello) await this.ready()\n const reqId = randomUUID()\n const timeoutMs = req.timeoutMs ?? 30_000\n const body =\n req.body === undefined\n ? undefined\n : encodeData(\n typeof req.body === \"string\" ? req.body : Buffer.from(req.body)\n )\n const frame: HttpRequestFrame = {\n t: \"http_request\",\n reqId,\n method: req.method,\n path: req.path,\n ...(req.headers ? { headers: req.headers } : {}),\n ...(body !== undefined ? { body } : {}),\n timeoutMs,\n }\n return new Promise<TunnelHttpResponse>((resolve, reject) => {\n // Belt-and-suspenders timeout: in addition to the daemon-side\n // enforcement, we time out client-side at timeoutMs + 5s so a\n // misbehaving daemon can't stall this promise forever.\n const timer = setTimeout(() => {\n httpPending.delete(reqId)\n reject(\n new Error(\n `Tunnel forwardHttp(${req.method} ${req.path}) timed out after ${timeoutMs + 5_000}ms.`\n )\n )\n }, timeoutMs + 5_000)\n httpPending.set(reqId, {\n mode: \"buffered\",\n resolve,\n reject,\n timer,\n streamHead: null,\n streamChunks: [],\n })\n opts.sink.send(frame)\n })\n },\n\n async forwardHttpStream(\n req: TunnelHttpRequest\n ): Promise<TunnelHttpStreamResponse> {\n if (!hello) await this.ready()\n const reqId = randomUUID()\n // Streaming requests don't enforce a body-completion timeout —\n // SSE / long-poll streams are *meant* to stay open. We do gate\n // the HEAD on a generous-but-finite window so a daemon that\n // silently drops the request still surfaces an error rather\n // than hanging forever; once head arrives, the timer is cleared.\n const headTimeoutMs = req.timeoutMs ?? 30_000\n const body =\n req.body === undefined\n ? undefined\n : encodeData(\n typeof req.body === \"string\" ? req.body : Buffer.from(req.body)\n )\n // Daemon-side request timeout: pass a very large number so the\n // daemon doesn't kill its own fetch before the stream completes.\n // Daemon detects SSE content-type and disarms its timer anyway,\n // but for non-SSE callers using forwardHttpStream this keeps\n // things safe.\n const frame: HttpRequestFrame = {\n t: \"http_request\",\n reqId,\n method: req.method,\n path: req.path,\n ...(req.headers ? { headers: req.headers } : {}),\n ...(body !== undefined ? { body } : {}),\n timeoutMs: 24 * 60 * 60 * 1000, // 24h — effectively \"forever\"\n }\n return new Promise<TunnelHttpStreamResponse>((resolveHead, reject) => {\n const timer = setTimeout(() => {\n if (httpPending.has(reqId)) {\n httpPending.delete(reqId)\n reject(\n new Error(\n `Tunnel forwardHttpStream(${req.method} ${req.path}) head did not arrive within ${headTimeoutMs}ms.`\n )\n )\n }\n }, headTimeoutMs)\n httpPending.set(reqId, {\n mode: \"stream\",\n resolveHead,\n reject,\n timer,\n controller: null,\n pendingChunks: [],\n headEmitted: false,\n ended: false,\n })\n opts.sink.send(frame)\n })\n },\n\n async forwardWebSocket(\n req: TunnelWebSocketOpenRequest\n ): Promise<TunnelWebSocket> {\n const h = await this.ready()\n if (h.capabilities.wsForward !== true) {\n throw new Error(\n `Tunnel daemon '${h.label ?? \"(unnamed)\"}' does not advertise wsForward capability. Update the daemon to forward browser WS upgrades.`\n )\n }\n const reqId = randomUUID()\n const timeoutMs = req.openTimeoutMs ?? 30_000\n const frame: WsOpenFrame = {\n t: \"ws_open\",\n reqId,\n path: req.path,\n ...(req.upstream ? { upstream: req.upstream } : {}),\n ...(req.headers ? { headers: req.headers } : {}),\n ...(req.protocols && req.protocols.length > 0\n ? { protocols: req.protocols }\n : {}),\n }\n return new Promise<TunnelWebSocket>((resolve, reject) => {\n const timer = setTimeout(() => {\n if (!wsOpenPending.has(reqId)) return\n wsOpenPending.delete(reqId)\n reject(\n new Error(\n `Tunnel forwardWebSocket(${req.path}) did not receive ws_open_ack within ${timeoutMs}ms.`\n )\n )\n }, timeoutMs)\n wsOpenPending.set(reqId, { resolve, reject, timer })\n opts.sink.send(frame)\n })\n },\n\n async close() {\n opts.sink.close(\"client.close\")\n },\n }\n}\n\n/**\n * Internal ChildProcess duck. Public methods mirror the subset of\n * Node's ChildProcess that our ACP arm calls; double-underscored\n * methods are control hooks for the client.\n */\nclass TunnelChildDuck extends EventEmitter implements TunnelChildProcess {\n readonly execId: string\n pid: number | null\n readonly stdin: Writable\n readonly stdout: Readable\n readonly stderr: Readable\n private readonly sink: FrameSink\n private exited = false\n\n constructor(execId: string, pid: number, sink: FrameSink) {\n super()\n this.execId = execId\n this.pid = pid > 0 ? pid : null\n this.sink = sink\n\n // stdout / stderr are passive Readables — consumers attach\n // listeners and we push() data as it arrives.\n this.stdout = new Readable({ read() {} })\n this.stderr = new Readable({ read() {} })\n\n // stdin is a Writable that converts each chunk to a `stdin` frame.\n this.stdin = new Writable({\n write(chunk: Buffer | string, _enc, cb) {\n sink.send({\n t: \"stdin\",\n execId,\n data: encodeData(chunk),\n })\n cb()\n },\n // Sending an empty stdin frame on `final` mirrors the local\n // semantics of closing a child's stdin (signal EOF). Daemons\n // ignore empty payloads, so this is safe even if the child\n // doesn't care about EOF.\n final(cb) {\n sink.send({ t: \"stdin\", execId, data: \"\" })\n cb()\n },\n })\n }\n\n __pushStdout(buf: Buffer): void {\n this.stdout.push(buf)\n }\n\n __pushStderr(buf: Buffer): void {\n this.stderr.push(buf)\n }\n\n __pushError(err: Error): void {\n this.emit(\"error\", err)\n }\n\n __handleExit(frame: ExitFrame): void {\n if (this.exited) return\n this.exited = true\n this.stdout.push(null)\n this.stderr.push(null)\n this.emit(\"exit\", frame.code, frame.signal)\n }\n\n __handleSinkClosed(): void {\n if (this.exited) return\n this.exited = true\n this.stdout.push(null)\n this.stderr.push(null)\n this.emit(\n \"exit\",\n null,\n \"SIGHUP\" // surrogate signal — the tunnel went away\n )\n }\n\n kill(signal: NodeJS.Signals | number = \"SIGTERM\"): boolean {\n if (this.exited) return false\n this.sink.send({\n t: \"kill\",\n execId: this.execId,\n signal: typeof signal === \"string\" ? signal : `SIG${signal}`,\n })\n return true\n }\n\n resize(cols: number, rows: number): void {\n if (this.exited) return\n this.sink.send({ t: \"resize\", execId: this.execId, cols, rows })\n }\n}\n\n/**\n * Internal duck for a bridged WS. Mirrors the `TunnelWebSocket`\n * interface; double-underscored methods are control hooks called by\n * the client's frame router.\n *\n * Listener semantics:\n * - `onMessage` fires for every `ws_message` frame routed here\n * - `onClose` fires exactly once, either when the daemon emits\n * `ws_close`, when the caller calls `.close()`, or when the\n * underlying tunnel disappears (with code 1006 in that case)\n * - `onError` fires for transport-level errors; close follows\n */\nclass TunnelWebSocketDuck implements TunnelWebSocket {\n readonly protocol: string | null\n private _readyState: \"open\" | \"closing\" | \"closed\" = \"open\"\n private readonly reqId: string\n private readonly sink: FrameSink\n private readonly onCleanup: () => void\n private readonly messageListeners = new Set<\n (data: Buffer, isBinary: boolean) => void\n >()\n private readonly closeListeners = new Set<\n (code: number, reason: string) => void\n >()\n private readonly errorListeners = new Set<(err: Error) => void>()\n\n constructor(\n reqId: string,\n protocol: string | null,\n sink: FrameSink,\n onCleanup: () => void\n ) {\n this.reqId = reqId\n this.protocol = protocol\n this.sink = sink\n this.onCleanup = onCleanup\n }\n\n get readyState(): \"open\" | \"closing\" | \"closed\" {\n return this._readyState\n }\n\n send(data: string | Uint8Array): void {\n if (this._readyState !== \"open\") return\n const bytes =\n typeof data === \"string\" ? Buffer.from(data, \"utf8\") : Buffer.from(data)\n this.sink.send({\n t: \"ws_message\",\n reqId: this.reqId,\n data: encodeData(bytes),\n binary: typeof data !== \"string\",\n })\n }\n\n close(code: number = 1000, reason?: string): void {\n if (this._readyState === \"closed\") return\n if (this._readyState === \"open\") {\n this._readyState = \"closing\"\n this.sink.send({\n t: \"ws_close\",\n reqId: this.reqId,\n code,\n ...(reason ? { reason } : {}),\n })\n }\n // Fire local close immediately so the caller's onClose handler\n // runs without waiting for the daemon's echo. The daemon's later\n // ws_close (if any) is dropped because routeIncoming has already\n // removed us from wsByReq via __handleClose.\n this.__handleClose(code, reason ?? \"\")\n }\n\n onMessage(\n listener: (data: Buffer, isBinary: boolean) => void\n ): () => void {\n this.messageListeners.add(listener)\n return () => this.messageListeners.delete(listener)\n }\n\n onClose(listener: (code: number, reason: string) => void): () => void {\n this.closeListeners.add(listener)\n return () => this.closeListeners.delete(listener)\n }\n\n onError(listener: (err: Error) => void): () => void {\n this.errorListeners.add(listener)\n return () => this.errorListeners.delete(listener)\n }\n\n __handleMessage(data: Buffer, isBinary: boolean): void {\n if (this._readyState !== \"open\") return\n for (const l of this.messageListeners) {\n try {\n l(data, isBinary)\n } catch {\n /* listener threw — don't let it tear down siblings */\n }\n }\n }\n\n __handleClose(code: number, reason: string): void {\n if (this._readyState === \"closed\") return\n this._readyState = \"closed\"\n this.onCleanup()\n for (const l of this.closeListeners) {\n try {\n l(code, reason)\n } catch {\n /* swallow */\n }\n }\n this.messageListeners.clear()\n this.closeListeners.clear()\n this.errorListeners.clear()\n }\n\n __handleSinkClosed(): void {\n if (this._readyState === \"closed\") return\n for (const l of this.errorListeners) {\n try {\n l(new Error(\"Tunnel closed mid-WS.\"))\n } catch {\n /* swallow */\n }\n }\n this.__handleClose(1006, \"tunnel_closed\")\n }\n}\n","/**\n * Adapter from a WebSocket-shaped object to a `FrameSink`. Works with\n * both the browser-native WebSocket API and the `ws` library's server\n * sockets — anything with `send`, `close`, and `addEventListener`-style\n * `message`/`close` events.\n *\n * Why a duck-typed shape and not `import(\"ws\")`: the cli, the host,\n * and (eventually) browser hosts all need to wrap WS instances they\n * obtained themselves. Importing `ws` in this package would force\n * every consumer to install it even when running in environments\n * (Bun, Deno, browser) that ship native WebSocket.\n */\n\nimport { encodeFrame, parseFrame, type TunnelFrame } from \"./frames.js\"\nimport type { FrameSink } from \"./transport.js\"\n\nexport interface WebSocketLike {\n send(data: string): void\n close(code?: number, reason?: string): void\n readyState: number\n addEventListener(\n event: \"message\",\n handler: (ev: { data: string | ArrayBuffer | Buffer }) => void\n ): void\n addEventListener(event: \"close\", handler: () => void): void\n addEventListener(event: \"error\", handler: (ev: { message?: string }) => void): void\n removeEventListener(event: string, handler: (...args: never[]) => void): void\n}\n\nconst READY_OPEN = 1\n\nexport function wrapWebSocket(ws: WebSocketLike): FrameSink {\n const frameHandlers = new Set<(frame: TunnelFrame) => void>()\n const closeHandlers = new Set<(reason?: string) => void>()\n let isOpen = ws.readyState === READY_OPEN\n\n // The `ws` library delivers Buffer; the browser delivers string or\n // ArrayBuffer. We coerce to string and parse — everything we send is\n // JSON text, so non-text payloads are protocol violations and get\n // dropped.\n const onMessage = (ev: { data: string | ArrayBuffer | Buffer }): void => {\n let text: string\n if (typeof ev.data === \"string\") text = ev.data\n else if (ev.data instanceof ArrayBuffer) text = Buffer.from(ev.data).toString(\"utf8\")\n else text = (ev.data as Buffer).toString(\"utf8\")\n const frame = parseFrame(text)\n if (!frame) return\n for (const h of frameHandlers) h(frame)\n }\n\n const onClose = (): void => {\n if (!isOpen) return\n isOpen = false\n for (const h of closeHandlers) h(\"transport.closed\")\n frameHandlers.clear()\n closeHandlers.clear()\n }\n\n const onError = (ev: { message?: string }): void => {\n if (!isOpen) return\n isOpen = false\n for (const h of closeHandlers) h(ev.message ?? \"transport.error\")\n frameHandlers.clear()\n closeHandlers.clear()\n }\n\n ws.addEventListener(\"message\", onMessage)\n ws.addEventListener(\"close\", onClose)\n ws.addEventListener(\"error\", onError)\n\n return {\n get isOpen() {\n return isOpen\n },\n send(frame) {\n if (!isOpen) return\n try {\n ws.send(encodeFrame(frame))\n } catch {\n // Send-on-closed-socket is a benign race; rely on the close\n // handler to flip isOpen and let listeners drain naturally.\n }\n },\n close(reason) {\n if (!isOpen) return\n try {\n ws.close(1000, reason)\n } catch {\n // ignore\n }\n },\n onFrame(handler) {\n frameHandlers.add(handler)\n return () => frameHandlers.delete(handler)\n },\n onClose(handler) {\n closeHandlers.add(handler)\n return () => closeHandlers.delete(handler)\n },\n }\n}\n"]}