@chances-ai/wire 24.0.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.
Files changed (93) hide show
  1. package/dist/rpc/acp/adapter.d.ts +32 -0
  2. package/dist/rpc/acp/adapter.d.ts.map +1 -0
  3. package/dist/rpc/acp/adapter.js +185 -0
  4. package/dist/rpc/acp/adapter.js.map +1 -0
  5. package/dist/rpc/acp/engine-driver.d.ts +128 -0
  6. package/dist/rpc/acp/engine-driver.d.ts.map +1 -0
  7. package/dist/rpc/acp/engine-driver.js +550 -0
  8. package/dist/rpc/acp/engine-driver.js.map +1 -0
  9. package/dist/rpc/acp/event-map.d.ts +22 -0
  10. package/dist/rpc/acp/event-map.d.ts.map +1 -0
  11. package/dist/rpc/acp/event-map.js +205 -0
  12. package/dist/rpc/acp/event-map.js.map +1 -0
  13. package/dist/rpc/acp/load-sdk.d.ts +3 -0
  14. package/dist/rpc/acp/load-sdk.d.ts.map +1 -0
  15. package/dist/rpc/acp/load-sdk.js +24 -0
  16. package/dist/rpc/acp/load-sdk.js.map +1 -0
  17. package/dist/rpc/acp/workspace-query.d.ts +41 -0
  18. package/dist/rpc/acp/workspace-query.d.ts.map +1 -0
  19. package/dist/rpc/acp/workspace-query.js +89 -0
  20. package/dist/rpc/acp/workspace-query.js.map +1 -0
  21. package/dist/rpc/driver.d.ts +42 -0
  22. package/dist/rpc/driver.d.ts.map +1 -0
  23. package/dist/rpc/driver.js +7 -0
  24. package/dist/rpc/driver.js.map +1 -0
  25. package/dist/rpc/event-map.d.ts +8 -0
  26. package/dist/rpc/event-map.d.ts.map +1 -0
  27. package/dist/rpc/event-map.js +91 -0
  28. package/dist/rpc/event-map.js.map +1 -0
  29. package/dist/rpc/index.d.ts +13 -0
  30. package/dist/rpc/index.d.ts.map +1 -0
  31. package/dist/rpc/index.js +18 -0
  32. package/dist/rpc/index.js.map +1 -0
  33. package/dist/rpc/lines.d.ts +2 -0
  34. package/dist/rpc/lines.d.ts.map +1 -0
  35. package/dist/rpc/lines.js +24 -0
  36. package/dist/rpc/lines.js.map +1 -0
  37. package/dist/rpc/protocol.d.ts +315 -0
  38. package/dist/rpc/protocol.d.ts.map +1 -0
  39. package/dist/rpc/protocol.js +70 -0
  40. package/dist/rpc/protocol.js.map +1 -0
  41. package/dist/rpc/rpc-server.d.ts +56 -0
  42. package/dist/rpc/rpc-server.d.ts.map +1 -0
  43. package/dist/rpc/rpc-server.js +305 -0
  44. package/dist/rpc/rpc-server.js.map +1 -0
  45. package/dist/rpc/stdout-guard.d.ts +5 -0
  46. package/dist/rpc/stdout-guard.d.ts.map +1 -0
  47. package/dist/rpc/stdout-guard.js +31 -0
  48. package/dist/rpc/stdout-guard.js.map +1 -0
  49. package/dist/rpc/writer.d.ts +34 -0
  50. package/dist/rpc/writer.d.ts.map +1 -0
  51. package/dist/rpc/writer.js +85 -0
  52. package/dist/rpc/writer.js.map +1 -0
  53. package/dist/serve/acp-session-host.d.ts +120 -0
  54. package/dist/serve/acp-session-host.d.ts.map +1 -0
  55. package/dist/serve/acp-session-host.js +276 -0
  56. package/dist/serve/acp-session-host.js.map +1 -0
  57. package/dist/serve/auth.d.ts +21 -0
  58. package/dist/serve/auth.d.ts.map +1 -0
  59. package/dist/serve/auth.js +58 -0
  60. package/dist/serve/auth.js.map +1 -0
  61. package/dist/serve/highlight.d.ts +25 -0
  62. package/dist/serve/highlight.d.ts.map +1 -0
  63. package/dist/serve/highlight.js +28 -0
  64. package/dist/serve/highlight.js.map +1 -0
  65. package/dist/serve/index.d.ts +14 -0
  66. package/dist/serve/index.d.ts.map +1 -0
  67. package/dist/serve/index.js +23 -0
  68. package/dist/serve/index.js.map +1 -0
  69. package/dist/serve/pairing.d.ts +25 -0
  70. package/dist/serve/pairing.d.ts.map +1 -0
  71. package/dist/serve/pairing.js +10 -0
  72. package/dist/serve/pairing.js.map +1 -0
  73. package/dist/serve/relay-frames.d.ts +29 -0
  74. package/dist/serve/relay-frames.d.ts.map +1 -0
  75. package/dist/serve/relay-frames.js +54 -0
  76. package/dist/serve/relay-frames.js.map +1 -0
  77. package/dist/serve/relay.d.ts +146 -0
  78. package/dist/serve/relay.d.ts.map +1 -0
  79. package/dist/serve/relay.js +475 -0
  80. package/dist/serve/relay.js.map +1 -0
  81. package/dist/serve/replay-hub.d.ts +102 -0
  82. package/dist/serve/replay-hub.d.ts.map +1 -0
  83. package/dist/serve/replay-hub.js +176 -0
  84. package/dist/serve/replay-hub.js.map +1 -0
  85. package/dist/serve/tls.d.ts +20 -0
  86. package/dist/serve/tls.d.ts.map +1 -0
  87. package/dist/serve/tls.js +64 -0
  88. package/dist/serve/tls.js.map +1 -0
  89. package/dist/serve/ws-transport.d.ts +64 -0
  90. package/dist/serve/ws-transport.d.ts.map +1 -0
  91. package/dist/serve/ws-transport.js +92 -0
  92. package/dist/serve/ws-transport.js.map +1 -0
  93. package/package.json +42 -0
@@ -0,0 +1,146 @@
1
+ /**
2
+ * (v17 M0 / docs/6.1 §3.1) The `chances serve` relay — a THIN local HTTP/WS
3
+ * server projecting the engine onto web + mobile clients. The relay carries NO
4
+ * agent logic (auth, framing, replay, static serving only — all agent work
5
+ * stays in the engine via the `EngineHost` seam — projected onto the ACP wire by
6
+ * `AcpEngineDriver`/`AcpSessionHost` (M1 binding; `/rpc`→`/acp` hard cutover at M3).
7
+ *
8
+ * Runtime: the relay runs on a RUNTIME-PORTABLE stack — `node:http` for HTTP
9
+ * and the `ws` package for the WebSocket control channel. Both run identically
10
+ * under Node, Bun, and `bun --compile` binaries, so `chances serve` works from
11
+ * the npm `chances` (Node) bin as well as the compiled binary. (Earlier M0/M1
12
+ * used `Bun.serve`/`Bun.file`, which threw `Bun is not defined` under the Node
13
+ * entry — v18 fix.) The transport adapters in `ws-transport.ts` were already
14
+ * runtime-agnostic; only this file changed.
15
+ *
16
+ * The bind default is `127.0.0.1` and NEVER `0.0.0.0` (R1 N1 / §7): LAN exposure
17
+ * is an explicit, loud opt-in that lands together with auth in M3 — there is no
18
+ * auth yet, so binding the wider interface would be a footgun.
19
+ *
20
+ * Pure pieces (`resolveBindAddress`, `handleRequest`, `serveStatic`) stay
21
+ * `(Request) → Response`/`Promise<Response | null>`, so routing + static
22
+ * resolution are unit-tested without a real socket (§11 — no timing flakiness).
23
+ * `startRelay` bridges them onto `node:http` (`IncomingMessage` ⇆ `Request`,
24
+ * `Response` ⇆ `ServerResponse`).
25
+ *
26
+ * M2 (docs/6.2) wires the WS `/acp` control channel onto ONE persistent
27
+ * {@link AcpSessionHost} (built once when `control` is present), NOT a per-socket
28
+ * session. Each accepted socket *attaches* to that session — replaying the gap
29
+ * since its `Last-Event-ID` cursor (read from the `?last_event_id=N` query
30
+ * param), then joining the fan-out. The M1 single-controller `409` is GONE:
31
+ * every socket may drive, the engine serializes turns (`AGENT_BUSY`), and a
32
+ * half-dead socket is a harmless dead fan-out target (dropped on a guarded send)
33
+ * rather than a lockout. The relay still carries no agent logic of its own.
34
+ */
35
+ import type { EngineHost } from "../rpc/index.js";
36
+ /** Loopback — the only safe default before auth (M3). */
37
+ export declare const LOOPBACK = "127.0.0.1";
38
+ /** Default relay port. Arbitrary high port; overridable via `--port`. */
39
+ export declare const DEFAULT_PORT = 4517;
40
+ export interface BindOptions {
41
+ /** Listen port. Omitted ⇒ {@link DEFAULT_PORT}. */
42
+ port?: number;
43
+ /** (v21 M4) Listen interface. Omitted ⇒ {@link LOOPBACK}. A non-loopback host
44
+ * REQUIRES `tls` + a pairing token (fail-closed in {@link startRelay}). */
45
+ host?: string;
46
+ /** (v21 M4) Self-signed TLS material (PEM). When present the relay serves
47
+ * HTTPS/WSS; the CLI generates + caches it for a non-loopback bind. */
48
+ tls?: {
49
+ cert: string;
50
+ key: string;
51
+ };
52
+ }
53
+ export interface BindAddress {
54
+ hostname: string;
55
+ port: number;
56
+ }
57
+ /**
58
+ * Resolve the bind address. Defaults to {@link LOOPBACK} (unchanged); a
59
+ * non-loopback `host` is the v21 M4 opt-in for LAN exposure — {@link startRelay}
60
+ * then REQUIRES TLS + a pairing token (fail-closed), so a wider bind can never run
61
+ * unencrypted/unauthenticated.
62
+ */
63
+ export declare function resolveBindAddress(opts?: BindOptions): BindAddress;
64
+ /** Loopback aliases that need no TLS/auth — the trust boundary is the machine
65
+ * itself (any local process is already you). */
66
+ export declare function isLoopbackHost(host: string): boolean;
67
+ export interface RelayDeps {
68
+ /** Agent version surfaced in `/health` + the ACP `initialize` agent info. */
69
+ version: string;
70
+ }
71
+ /**
72
+ * The relay's HTTP request handler. Routes only `GET /health`; the WS `/acp`
73
+ * upgrade is handled by `startRelay`'s `upgrade` listener (it needs the raw
74
+ * socket) and static SPA assets are tried before this fallback. Pure
75
+ * `(Request) → Response`, so routing is unit-testable without a socket.
76
+ */
77
+ export declare function handleRequest(req: Request, deps: RelayDeps): Response;
78
+ /**
79
+ * Serve a built SPA from `staticDir` (the web-ui `vite build` output): an exact
80
+ * file match, else the SPA `index.html` fallback for extension-less client
81
+ * routes (so a deep link / refresh still loads the app). Returns `null` when
82
+ * nothing matches, so the caller can fall through to {@link handleRequest}.
83
+ *
84
+ * Path traversal is rejected by resolving the candidate and requiring it to
85
+ * stay within `staticDir`. Async (file existence) but called only on the
86
+ * non-upgrade path, so it never blocks the WS handshake.
87
+ */
88
+ export declare function serveStatic(req: Request, staticDir: string): Promise<Response | null>;
89
+ export interface RelayHandle extends BindAddress {
90
+ /** `http://<hostname>:<port>` — the base URL the relay is listening on. */
91
+ url: string;
92
+ /** Gracefully shut the persistent session (cancel turn, deny pending, flush
93
+ * the final frames to still-open sockets) THEN close sockets + the server +
94
+ * release the port. Idempotent. Awaitable so the caller can let the engine
95
+ * settle before the runtime is disposed (codex M2 SHOULD). */
96
+ stop(): Promise<void>;
97
+ }
98
+ /**
99
+ * Control-channel wiring for the WS `/acp` endpoint (M1; `/rpc`→`/acp` at M3).
100
+ * When present, the
101
+ * relay accepts a control socket and binds it to the engine via the `EngineHost`
102
+ * seam (projected onto ACP by `AcpEngineDriver`/`AcpSessionHost`). Omitted ⇒ a
103
+ * health-only relay (M0 behaviour).
104
+ */
105
+ export interface RpcRelayDeps {
106
+ /** The engine seam. The relay wraps it with {@link perConnectionHost} so a
107
+ * single socket close never tears down the shared runtime. */
108
+ host: EngineHost;
109
+ /** Surfaced in the ACP `initialize` agent info response. */
110
+ agent: {
111
+ name: string;
112
+ version: string;
113
+ };
114
+ /** Auto-approve every tool permission (trusted automation). Default false. */
115
+ autoApprove?: boolean;
116
+ /** stderr-style sink for routed `log` events + relay diagnostics. */
117
+ logSink?: (line: string) => void;
118
+ /** (v21 M4) Pairing token required on every WS `/acp` upgrade. When present, a
119
+ * connect without / with a wrong token is rejected with `401` at the edge
120
+ * (constant-time check, before the session). Undefined ⇒ loopback, no auth
121
+ * (the trust boundary is the local machine) — backward-compatible. */
122
+ pairingToken?: string;
123
+ /** (v21 M4 §5) Enable the single-controller lease (default false ⇒ fan-out:
124
+ * any paired device drives, the engine serializes turns via AGENT_BUSY). */
125
+ controllerLease?: boolean;
126
+ }
127
+ /**
128
+ * Start the relay on `node:http` + `ws`. Thin wrapper over {@link handleRequest}
129
+ * + {@link serveStatic} for HTTP routes; when `control` is supplied it also
130
+ * serves the WS `/acp` control channel (M1). `async` because `node:http`'s
131
+ * `listen` is asynchronous — the returned handle's `port`/`url` reflect the
132
+ * ACTUALLY-bound port (resolving `port: 0` → a random free port). Returns a
133
+ * handle the CLI keeps alive until SIGINT.
134
+ */
135
+ export declare function startRelay(opts: BindOptions & RelayDeps & {
136
+ control?: RpcRelayDeps;
137
+ staticDir?: string;
138
+ }): Promise<RelayHandle>;
139
+ /** Parse a `--port <n>` flag out of a positional token list (CLI helper). Returns
140
+ * undefined when absent or malformed (caller falls back to {@link DEFAULT_PORT}). */
141
+ export declare function parsePortFlag(tokens: readonly string[]): number | undefined;
142
+ /** Parse a `--host <addr>` flag (CLI helper, v21 M4). Returns undefined when
143
+ * absent (caller stays on {@link LOOPBACK}); a value beginning with `-` is the
144
+ * next flag, not an address, so it is rejected. */
145
+ export declare function parseHostFlag(tokens: readonly string[]): string | undefined;
146
+ //# sourceMappingURL=relay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay.d.ts","sourceRoot":"","sources":["../../src/serve/relay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AASH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAMlD,yDAAyD;AACzD,eAAO,MAAM,QAAQ,cAAc,CAAC;AACpC,yEAAyE;AACzE,eAAO,MAAM,YAAY,OAAO,CAAC;AAEjC,MAAM,WAAW,WAAW;IAC1B,mDAAmD;IACnD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;gFAC4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;4EACwE;IACxE,GAAG,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;CACrC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,GAAE,WAAgB,GAAG,WAAW,CAKtE;AAED;iDACiD;AACjD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOpD;AAED,MAAM,WAAW,SAAS;IACxB,6EAA6E;IAC7E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,GAAG,QAAQ,CASrE;AA6BD;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAuB3F;AA0BD,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC9C,2EAA2E;IAC3E,GAAG,EAAE,MAAM,CAAC;IACZ;;;mEAG+D;IAC/D,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B;mEAC+D;IAC/D,IAAI,EAAE,UAAU,CAAC;IACjB,4DAA4D;IAC5D,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,8EAA8E;IAC9E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,qEAAqE;IACrE,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC;;;2EAGuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;iFAC6E;IAC7E,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAmFD;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,WAAW,GAAG,SAAS,GAAG;IAAE,OAAO,CAAC,EAAE,YAAY,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7E,OAAO,CAAC,WAAW,CAAC,CAwLtB;AAED;sFACsF;AACtF,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAO3E;AAED;;oDAEoD;AACpD,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAM3E"}
@@ -0,0 +1,475 @@
1
+ /**
2
+ * (v17 M0 / docs/6.1 §3.1) The `chances serve` relay — a THIN local HTTP/WS
3
+ * server projecting the engine onto web + mobile clients. The relay carries NO
4
+ * agent logic (auth, framing, replay, static serving only — all agent work
5
+ * stays in the engine via the `EngineHost` seam — projected onto the ACP wire by
6
+ * `AcpEngineDriver`/`AcpSessionHost` (M1 binding; `/rpc`→`/acp` hard cutover at M3).
7
+ *
8
+ * Runtime: the relay runs on a RUNTIME-PORTABLE stack — `node:http` for HTTP
9
+ * and the `ws` package for the WebSocket control channel. Both run identically
10
+ * under Node, Bun, and `bun --compile` binaries, so `chances serve` works from
11
+ * the npm `chances` (Node) bin as well as the compiled binary. (Earlier M0/M1
12
+ * used `Bun.serve`/`Bun.file`, which threw `Bun is not defined` under the Node
13
+ * entry — v18 fix.) The transport adapters in `ws-transport.ts` were already
14
+ * runtime-agnostic; only this file changed.
15
+ *
16
+ * The bind default is `127.0.0.1` and NEVER `0.0.0.0` (R1 N1 / §7): LAN exposure
17
+ * is an explicit, loud opt-in that lands together with auth in M3 — there is no
18
+ * auth yet, so binding the wider interface would be a footgun.
19
+ *
20
+ * Pure pieces (`resolveBindAddress`, `handleRequest`, `serveStatic`) stay
21
+ * `(Request) → Response`/`Promise<Response | null>`, so routing + static
22
+ * resolution are unit-tested without a real socket (§11 — no timing flakiness).
23
+ * `startRelay` bridges them onto `node:http` (`IncomingMessage` ⇆ `Request`,
24
+ * `Response` ⇆ `ServerResponse`).
25
+ *
26
+ * M2 (docs/6.2) wires the WS `/acp` control channel onto ONE persistent
27
+ * {@link AcpSessionHost} (built once when `control` is present), NOT a per-socket
28
+ * session. Each accepted socket *attaches* to that session — replaying the gap
29
+ * since its `Last-Event-ID` cursor (read from the `?last_event_id=N` query
30
+ * param), then joining the fan-out. The M1 single-controller `409` is GONE:
31
+ * every socket may drive, the engine serializes turns (`AGENT_BUSY`), and a
32
+ * half-dead socket is a harmless dead fan-out target (dropped on a guarded send)
33
+ * rather than a lockout. The relay still carries no agent logic of its own.
34
+ */
35
+ import { createServer } from "node:http";
36
+ import { createServer as createSecureServer } from "node:https";
37
+ import { readFile, realpath, stat } from "node:fs/promises";
38
+ import { extname, isAbsolute, join, relative, resolve } from "node:path";
39
+ import { WebSocket, WebSocketServer } from "ws";
40
+ import { perConnectionHost } from "./ws-transport.js";
41
+ import { AcpSessionHost } from "./acp-session-host.js";
42
+ import { parseClientId, parseLastEventId } from "./relay-frames.js";
43
+ import { checkToken, extractToken } from "./auth.js";
44
+ /** Loopback — the only safe default before auth (M3). */
45
+ export const LOOPBACK = "127.0.0.1";
46
+ /** Default relay port. Arbitrary high port; overridable via `--port`. */
47
+ export const DEFAULT_PORT = 4517;
48
+ /**
49
+ * Resolve the bind address. Defaults to {@link LOOPBACK} (unchanged); a
50
+ * non-loopback `host` is the v21 M4 opt-in for LAN exposure — {@link startRelay}
51
+ * then REQUIRES TLS + a pairing token (fail-closed), so a wider bind can never run
52
+ * unencrypted/unauthenticated.
53
+ */
54
+ export function resolveBindAddress(opts = {}) {
55
+ return {
56
+ hostname: opts.host ?? LOOPBACK,
57
+ port: opts.port ?? DEFAULT_PORT,
58
+ };
59
+ }
60
+ /** Loopback aliases that need no TLS/auth — the trust boundary is the machine
61
+ * itself (any local process is already you). */
62
+ export function isLoopbackHost(host) {
63
+ if (host === "::1" || host === "localhost")
64
+ return true;
65
+ // The WHOLE 127.0.0.0/8 block is loopback (127.0.0.1 … 127.255.255.255), not
66
+ // just 127.0.0.1 — else 127.0.0.2 would be treated as an exposed bind and
67
+ // forced through TLS+token (codex M4-review SHOULD).
68
+ const m = /^127\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
69
+ return m !== null && m.slice(1).every((o) => Number(o) <= 255);
70
+ }
71
+ /**
72
+ * The relay's HTTP request handler. Routes only `GET /health`; the WS `/acp`
73
+ * upgrade is handled by `startRelay`'s `upgrade` listener (it needs the raw
74
+ * socket) and static SPA assets are tried before this fallback. Pure
75
+ * `(Request) → Response`, so routing is unit-testable without a socket.
76
+ */
77
+ export function handleRequest(req, deps) {
78
+ const url = new URL(req.url);
79
+ if (req.method === "GET" && url.pathname === "/health") {
80
+ return Response.json({ status: "ok", agent: "chances", version: deps.version });
81
+ }
82
+ // The WS `/acp` upgrade (web/desktop control channel) is intercepted in
83
+ // `startRelay`'s `upgrade` listener; static SPA assets are tried in the
84
+ // request listener before falling through here. Everything else is Not Found.
85
+ return new Response("Not Found", { status: 404 });
86
+ }
87
+ /** Extension → `Content-Type`. `Bun.file`/`new Response(file)` set this for us;
88
+ * with `node:fs` we must map it ourselves. Unknown ⇒ a safe binary default. */
89
+ const CONTENT_TYPES = {
90
+ ".html": "text/html; charset=utf-8",
91
+ ".js": "text/javascript; charset=utf-8",
92
+ ".mjs": "text/javascript; charset=utf-8",
93
+ ".css": "text/css; charset=utf-8",
94
+ ".json": "application/json; charset=utf-8",
95
+ ".map": "application/json; charset=utf-8",
96
+ ".svg": "image/svg+xml",
97
+ ".png": "image/png",
98
+ ".jpg": "image/jpeg",
99
+ ".jpeg": "image/jpeg",
100
+ ".gif": "image/gif",
101
+ ".webp": "image/webp",
102
+ ".ico": "image/x-icon",
103
+ ".woff": "font/woff",
104
+ ".woff2": "font/woff2",
105
+ ".ttf": "font/ttf",
106
+ ".wasm": "application/wasm",
107
+ ".txt": "text/plain; charset=utf-8",
108
+ };
109
+ function contentTypeFor(filePath) {
110
+ return CONTENT_TYPES[extname(filePath).toLowerCase()] ?? "application/octet-stream";
111
+ }
112
+ /**
113
+ * Serve a built SPA from `staticDir` (the web-ui `vite build` output): an exact
114
+ * file match, else the SPA `index.html` fallback for extension-less client
115
+ * routes (so a deep link / refresh still loads the app). Returns `null` when
116
+ * nothing matches, so the caller can fall through to {@link handleRequest}.
117
+ *
118
+ * Path traversal is rejected by resolving the candidate and requiring it to
119
+ * stay within `staticDir`. Async (file existence) but called only on the
120
+ * non-upgrade path, so it never blocks the WS handshake.
121
+ */
122
+ export async function serveStatic(req, staticDir) {
123
+ if (req.method !== "GET" && req.method !== "HEAD")
124
+ return null;
125
+ const base = resolve(staticDir);
126
+ // The realpath of the root anchors the symlink-escape check below. If the
127
+ // staticDir itself doesn't exist, serve nothing.
128
+ const realBase = await realpath(base).catch(() => null);
129
+ if (realBase === null)
130
+ return null;
131
+ const pathname = new URL(req.url).pathname;
132
+ const candidate = pathname === "/" ? "index.html" : pathname.replace(/^\/+/, "");
133
+ const filePath = resolve(join(base, candidate));
134
+ // Lexical guard: reject anything resolving outside the root (`../../etc/...`).
135
+ if (!isWithin(base, filePath))
136
+ return null;
137
+ const direct = await servableFile(filePath, realBase);
138
+ if (direct)
139
+ return direct;
140
+ // SPA fallback: an extension-less route (client-side path) → index.html.
141
+ if (extname(pathname) === "") {
142
+ const index = await servableFile(join(base, "index.html"), realBase);
143
+ if (index)
144
+ return index;
145
+ }
146
+ return null;
147
+ }
148
+ /**
149
+ * Serve `filePath` only if it exists AND its REAL path stays within `realBase`
150
+ * — a symlink inside the static root that points outside it (codex R2 SHOULD-1)
151
+ * is rejected, which the lexical resolve check alone can't catch.
152
+ */
153
+ async function servableFile(filePath, realBase) {
154
+ const st = await stat(filePath).catch(() => null);
155
+ if (!st || !st.isFile())
156
+ return null;
157
+ const real = await realpath(filePath).catch(() => null);
158
+ if (real === null || !isWithin(realBase, real))
159
+ return null;
160
+ const data = await readFile(filePath).catch(() => null);
161
+ if (data === null)
162
+ return null;
163
+ // `Uint8Array` body keeps the Response Web-API portable across Node/Bun.
164
+ return new Response(new Uint8Array(data), { headers: { "content-type": contentTypeFor(filePath) } });
165
+ }
166
+ /** Platform-correct containment: is `target` `base` itself or strictly inside it?
167
+ * Uses `path.relative` (not a hardcoded `/` prefix, which breaks on Windows
168
+ * back-slash paths — codex v17 holistic SHOULD-FIX). */
169
+ function isWithin(base, target) {
170
+ const rel = relative(base, target);
171
+ return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
172
+ }
173
+ /** Reconstruct an absolute URL from a `node:http` request (its `url` is the
174
+ * path+query only) by resolving `req.url` against the relay's OWN bound base.
175
+ * The `Host` header is deliberately NOT trusted (codex v18 SHOULD-FIX) — only
176
+ * the pathname/method are read downstream, and the relay is loopback-bound.
177
+ * May throw on a malformed `req.url`; callers parse inside a guard. */
178
+ function requestUrl(req, baseUrl) {
179
+ return new URL(req.url ?? "/", baseUrl).toString();
180
+ }
181
+ /** `node:http` headers → Web `Headers` so the pure handlers see one shape. */
182
+ function toWebHeaders(headers) {
183
+ const out = new Headers();
184
+ for (const [key, value] of Object.entries(headers)) {
185
+ if (Array.isArray(value))
186
+ for (const v of value)
187
+ out.append(key, v);
188
+ else if (value !== undefined)
189
+ out.set(key, value);
190
+ }
191
+ return out;
192
+ }
193
+ /** Pipe a Web `Response` (from the pure handlers) onto a `node:http` response. */
194
+ async function writeWebResponse(res, response) {
195
+ res.statusCode = response.status;
196
+ response.headers.forEach((value, key) => res.setHeader(key, value));
197
+ const body = Buffer.from(await response.arrayBuffer());
198
+ res.end(body);
199
+ }
200
+ /**
201
+ * Adapt a `ws` WebSocket to the {@link ServerSocket} tri-state `send` the
202
+ * {@link ReplayHub} fan-out uses: `>0` sent, `-1` enqueued-but-backpressured,
203
+ * `0` dropped/dead. `ws` has no `drain` event, so once buffered bytes cross the
204
+ * high-water mark we poll `bufferedAmount` and fire `onWritable` when it falls
205
+ * below the low-water mark — faithful backpressure without an unbounded in-memory
206
+ * `ws` send queue. At loopback (single user) this path is essentially never hit.
207
+ */
208
+ function nodeServerSocket(ws, onWritable) {
209
+ const HIGH_WATER = 1 << 20; // 1 MiB queued ⇒ report backpressure
210
+ const LOW_WATER = 1 << 16; // drained below 64 KiB ⇒ resume writers
211
+ let pollTimer;
212
+ const stopPoll = () => {
213
+ if (pollTimer) {
214
+ clearInterval(pollTimer);
215
+ pollTimer = undefined;
216
+ }
217
+ };
218
+ return {
219
+ get bufferedAmount() {
220
+ return ws.bufferedAmount;
221
+ },
222
+ send(data) {
223
+ if (ws.readyState !== WebSocket.OPEN)
224
+ return 0;
225
+ try {
226
+ ws.send(data);
227
+ }
228
+ catch {
229
+ return 0; // socket closing mid-write — treat as dropped
230
+ }
231
+ if (ws.bufferedAmount >= HIGH_WATER) {
232
+ if (!pollTimer) {
233
+ pollTimer = setInterval(() => {
234
+ if (ws.readyState !== WebSocket.OPEN || ws.bufferedAmount <= LOW_WATER) {
235
+ stopPoll();
236
+ onWritable();
237
+ }
238
+ }, 10);
239
+ pollTimer.unref?.();
240
+ }
241
+ return -1;
242
+ }
243
+ return 1;
244
+ },
245
+ close(code, reason) {
246
+ stopPoll();
247
+ try {
248
+ ws.close(code, reason);
249
+ }
250
+ catch {
251
+ /* already closing */
252
+ }
253
+ },
254
+ };
255
+ }
256
+ /**
257
+ * Start the relay on `node:http` + `ws`. Thin wrapper over {@link handleRequest}
258
+ * + {@link serveStatic} for HTTP routes; when `control` is supplied it also
259
+ * serves the WS `/acp` control channel (M1). `async` because `node:http`'s
260
+ * `listen` is asynchronous — the returned handle's `port`/`url` reflect the
261
+ * ACTUALLY-bound port (resolving `port: 0` → a random free port). Returns a
262
+ * handle the CLI keeps alive until SIGINT.
263
+ */
264
+ export async function startRelay(opts) {
265
+ const { hostname, port } = resolveBindAddress(opts);
266
+ const control = opts.control;
267
+ const staticDir = opts.staticDir;
268
+ const tls = opts.tls;
269
+ // (v21 M4) Fail-closed: a non-loopback bind MUST be both encrypted (TLS) and
270
+ // authenticated (a pairing token), or the agent would be exposed to the LAN in
271
+ // cleartext with no auth. Refuse to start otherwise. Loopback is unchanged
272
+ // (plain HTTP, no token — the trust boundary is the local machine).
273
+ if (!isLoopbackHost(hostname)) {
274
+ if (!tls)
275
+ throw new Error(`serve: refusing to bind ${hostname} without TLS — a non-loopback bind requires a self-signed cert (loopback stays plain HTTP)`);
276
+ if (!control?.pairingToken)
277
+ throw new Error(`serve: refusing to bind ${hostname} without a pairing token — run \`chances serve --new-token\` first`);
278
+ }
279
+ const deps = { version: opts.version };
280
+ const scheme = tls ? "https" : "http";
281
+ // The relay's own base — `req.url` is resolved against this (never the Host
282
+ // header) when bridging requests onto the pure handlers.
283
+ const baseUrl = `${scheme}://${hostname}:${port}`;
284
+ const httpServer = tls
285
+ ? createSecureServer({ cert: tls.cert, key: tls.key }, (req, res) => {
286
+ void serveHttp(req, res);
287
+ })
288
+ : createServer((req, res) => {
289
+ void serveHttp(req, res);
290
+ });
291
+ async function serveHttp(req, res) {
292
+ try {
293
+ const request = new Request(requestUrl(req, baseUrl), {
294
+ method: req.method ?? "GET",
295
+ headers: toWebHeaders(req.headers),
296
+ });
297
+ const pathname = new URL(request.url).pathname;
298
+ // API routes win over the SPA: `serveStatic`'s extension-less index
299
+ // fallback would otherwise shadow `/health` (it has no extension).
300
+ if (pathname === "/health") {
301
+ await writeWebResponse(res, handleRequest(request, deps));
302
+ return;
303
+ }
304
+ // A non-upgrade hit on the control endpoint (a real upgrade goes to the
305
+ // `upgrade` listener, never here) — tell the caller to upgrade.
306
+ if (control && pathname === "/acp") {
307
+ await writeWebResponse(res, new Response("Expected a WebSocket upgrade", { status: 426 }));
308
+ return;
309
+ }
310
+ if (staticDir) {
311
+ const asset = await serveStatic(request, staticDir);
312
+ if (asset) {
313
+ await writeWebResponse(res, asset);
314
+ return;
315
+ }
316
+ }
317
+ await writeWebResponse(res, handleRequest(request, deps));
318
+ }
319
+ catch {
320
+ if (!res.headersSent) {
321
+ res.statusCode = 500;
322
+ res.end("Internal Server Error");
323
+ }
324
+ }
325
+ }
326
+ // ONE persistent session for the whole `serve` process (M2). Built once when
327
+ // a control host is present; sockets attach/detach over it. `perConnectionHost`
328
+ // makes the AcpEngineDriver's own `host.dispose()` a NO-OP so the runtime is
329
+ // torn down EXACTLY ONCE by `main()`'s `disposeRuntime` on exit (the session is
330
+ // persistent, so per-session dispose would double-tear-down the shared
331
+ // runtime). `AcpSessionHost.shutdown()` still ends the queue + runs the engine's
332
+ // graceful turn/permission shutdown.
333
+ let sessionHost;
334
+ // The WS control channel rides `noServer` mode: we own the `upgrade` event so
335
+ // we can validate the path before `ws` takes the socket.
336
+ let wss;
337
+ if (control) {
338
+ sessionHost = new AcpSessionHost({
339
+ host: perConnectionHost(control.host),
340
+ agent: control.agent,
341
+ ...(control.autoApprove !== undefined ? { autoApprove: control.autoApprove } : {}),
342
+ ...(control.logSink ? { logSink: control.logSink } : {}),
343
+ ...(control.controllerLease !== undefined ? { controllerLease: control.controllerLease } : {}),
344
+ });
345
+ const host = sessionHost;
346
+ wss = new WebSocketServer({ noServer: true });
347
+ wss.on("connection", (ws, req) => {
348
+ // Drain is dormant in M2 — the ReplayHub never parks the writer (the ring
349
+ // is the durable buffer), so `onWritable` is a no-op.
350
+ const socket = nodeServerSocket(ws, () => { });
351
+ // Cursor for the replay/reconnect: `?last_event_id=N` query param (a
352
+ // browser WebSocket cannot set headers), header fallback for non-browser.
353
+ const lastSeq = parseLastEventId(req.url ?? "/acp", req.headers);
354
+ const clientId = parseClientId(req.url ?? "/acp");
355
+ const attachment = host.attach(socket, lastSeq, clientId);
356
+ ws.on("message", (data, isBinary) => {
357
+ // The ACP wire is JSON-RPC NDJSON text; ignore binary frames (and empty
358
+ // text frames) rather than feeding them to the line parser (codex v18
359
+ // SHOULD-FIX — the prior `!isBinary || text` leaked binary frames in).
360
+ if (isBinary)
361
+ return;
362
+ const text = Array.isArray(data) ? Buffer.concat(data).toString() : data.toString();
363
+ if (text)
364
+ host.onMessage(text, clientId);
365
+ });
366
+ // Without an `error` listener, a transport/protocol error on the socket
367
+ // throws as an UNHANDLED EventEmitter error and crashes the relay (codex
368
+ // v18 MUST-FIX). Just DETACH — the session + any in-flight turn survive a
369
+ // socket drop (M2); a `close` event usually follows, and `detach` is
370
+ // idempotent.
371
+ ws.on("error", (err) => {
372
+ control.logSink?.(`relay: /acp socket error: ${err.message}\n`);
373
+ attachment.detach();
374
+ });
375
+ ws.on("close", () => attachment.detach());
376
+ });
377
+ httpServer.on("upgrade", (req, socket, head) => {
378
+ // Never let a malformed upgrade request throw OUT of this event handler
379
+ // (it would be an unhandled exception) — guard the URL parse and drop the
380
+ // socket on failure (codex v18 SHOULD-FIX).
381
+ let pathname;
382
+ try {
383
+ pathname = new URL(requestUrl(req, baseUrl)).pathname;
384
+ }
385
+ catch {
386
+ socket.destroy();
387
+ return;
388
+ }
389
+ if (pathname !== "/acp") {
390
+ socket.destroy();
391
+ return;
392
+ }
393
+ // (v21 M4) Pairing-token auth at the edge: when a token is configured (any
394
+ // non-loopback bind requires one — Stage 2), reject an absent/wrong token
395
+ // with a 401 BEFORE the upgrade, so it never reaches the session. Loopback
396
+ // runs with `pairingToken` undefined, so this is a no-op there.
397
+ if (control.pairingToken !== undefined && !checkToken(extractToken(req.url, req.headers, baseUrl), control.pairingToken)) {
398
+ socket.write("HTTP/1.1 401 Unauthorized\r\nConnection: close\r\n\r\n");
399
+ socket.destroy();
400
+ return;
401
+ }
402
+ // No 409: every socket attaches + fans out (M2). A reconnecting or 2nd
403
+ // client just joins; the engine serializes turns via AGENT_BUSY.
404
+ wss.handleUpgrade(req, socket, head, (ws) => wss.emit("connection", ws, req));
405
+ });
406
+ }
407
+ await new Promise((resolveListen, rejectListen) => {
408
+ const onError = (err) => rejectListen(err);
409
+ httpServer.once("error", onError);
410
+ httpServer.listen(port, hostname, () => {
411
+ httpServer.removeListener("error", onError);
412
+ resolveListen();
413
+ });
414
+ });
415
+ const addr = httpServer.address();
416
+ const boundPort = addr && typeof addr === "object" ? addr.port : port;
417
+ return {
418
+ hostname,
419
+ port: boundPort,
420
+ url: `${scheme}://${hostname}:${boundPort}`,
421
+ stop: async () => {
422
+ // AWAIT the engine's graceful shutdown FIRST (end the persistent queue →
423
+ // cancel the turn, deny pending, flush the terminal `result` to the
424
+ // still-open sockets) so an in-flight browser-driven turn settles before
425
+ // the caller lets `main()`'s `disposeRuntime` tear the runtime down (codex
426
+ // M2 SHOULD — the prior fire-and-forget raced disposal). `host.dispose`
427
+ // inside this is a no-op via perConnectionHost, so the runtime is still
428
+ // disposed exactly once, by `main()`.
429
+ try {
430
+ await sessionHost?.shutdown();
431
+ }
432
+ catch {
433
+ /* best-effort — never block the socket/server close on it */
434
+ }
435
+ for (const client of wss?.clients ?? []) {
436
+ try {
437
+ client.terminate();
438
+ }
439
+ catch {
440
+ /* already gone */
441
+ }
442
+ }
443
+ wss?.close();
444
+ // Force-close lingering keep-alive sockets so the port frees promptly
445
+ // (node 18.2+; absent under some runtimes — guard with `?.`).
446
+ httpServer.closeAllConnections?.();
447
+ httpServer.close();
448
+ },
449
+ };
450
+ }
451
+ /** Parse a `--port <n>` flag out of a positional token list (CLI helper). Returns
452
+ * undefined when absent or malformed (caller falls back to {@link DEFAULT_PORT}). */
453
+ export function parsePortFlag(tokens) {
454
+ const i = tokens.indexOf("--port");
455
+ if (i < 0)
456
+ return undefined;
457
+ const raw = tokens[i + 1];
458
+ if (raw === undefined)
459
+ return undefined;
460
+ const n = Number.parseInt(raw, 10);
461
+ return Number.isInteger(n) && n > 0 && n < 65536 ? n : undefined;
462
+ }
463
+ /** Parse a `--host <addr>` flag (CLI helper, v21 M4). Returns undefined when
464
+ * absent (caller stays on {@link LOOPBACK}); a value beginning with `-` is the
465
+ * next flag, not an address, so it is rejected. */
466
+ export function parseHostFlag(tokens) {
467
+ const i = tokens.indexOf("--host");
468
+ if (i < 0)
469
+ return undefined;
470
+ const raw = tokens[i + 1];
471
+ if (raw === undefined || raw.startsWith("-"))
472
+ return undefined;
473
+ return raw;
474
+ }
475
+ //# sourceMappingURL=relay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay.js","sourceRoot":"","sources":["../../src/serve/relay.ts"],"names":[],"mappings":"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"}