@cleocode/runtime 2026.6.12 → 2026.6.14
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.
- package/dist/{chunk-WSQQ5DQL.js → chunk-3K3LFSDF.js} +83 -3
- package/dist/chunk-3K3LFSDF.js.map +1 -0
- package/dist/{chunk-5ZXRYEQ5.js → chunk-KQBVXGOL.js} +21 -4
- package/dist/chunk-KQBVXGOL.js.map +1 -0
- package/dist/chunk-L5BLVQDA.js +91 -0
- package/dist/chunk-L5BLVQDA.js.map +1 -0
- package/dist/chunk-Q7X4XH2V.js +902 -0
- package/dist/chunk-Q7X4XH2V.js.map +1 -0
- package/dist/{chunk-R4XBXUQN.js → chunk-XJOMQIXL.js} +5 -76
- package/dist/chunk-XJOMQIXL.js.map +1 -0
- package/dist/daemon/index.d.ts +191 -2
- package/dist/daemon/index.js +7 -1
- package/dist/gateway/http/index.d.ts +2 -1
- package/dist/gateway/http/index.js +30 -3
- package/dist/gateway/index.d.ts +3 -2
- package/dist/gateway/index.js +60 -16
- package/dist/gateway/index.js.map +1 -1
- package/dist/gateway/mcp/index.d.ts +2 -1
- package/dist/gateway/mcp/index.js +2 -1
- package/dist/gateway/rpc/index.d.ts +569 -10
- package/dist/gateway/rpc/index.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +3 -3
- package/dist/chunk-5ZXRYEQ5.js.map +0 -1
- package/dist/chunk-R4XBXUQN.js.map +0 -1
- package/dist/chunk-WSQQ5DQL.js.map +0 -1
- package/dist/chunk-YZBIPGMH.js +0 -305
- package/dist/chunk-YZBIPGMH.js.map +0 -1
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { DomainHandler, Middleware, DispatchRequest, DispatchResponse, Gateway, GatewayStreamEvent, Source, DispatchResponseMeta, CanonicalDomain, Tier } from '@cleocode/contracts/gateway';
|
|
2
2
|
import { BackgroundJobManager } from '@cleocode/core/store/background-jobs.js';
|
|
3
3
|
import { Subsystem, OperationDef, SuggestedNextOp, Resolution } from '@cleocode/contracts';
|
|
4
|
-
import { Server } from 'node:http';
|
|
4
|
+
import { IncomingMessage, Server } from 'node:http';
|
|
5
5
|
import '@cleocode/contracts/operations/orchestrate';
|
|
6
6
|
import * as _cleocode_core_internal from '@cleocode/core/internal';
|
|
7
7
|
import { EngineResult, ProblemDetails } from '@cleocode/core';
|
|
8
8
|
import { GatewayRpcRequestFrame, GatewayRpcErrorFrame, GatewayRpcErrorCode, GatewayRpcResponseFrame } from '@cleocode/contracts/gateway/rpc';
|
|
9
9
|
import { Server as Server$1 } from 'node:net';
|
|
10
|
+
import { Duplex } from 'node:stream';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Central Dispatcher -- Routes requests through middleware to domain handlers.
|
|
@@ -45,6 +46,246 @@ declare class Dispatcher {
|
|
|
45
46
|
dispatch(request: DispatchRequest): Promise<DispatchResponse>;
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
/**
|
|
50
|
+
* WebSocket terminal/PTY endpoint on the `/v1` gateway HTTP listener (T11922 ·
|
|
51
|
+
* M5 realtime transport, WS half).
|
|
52
|
+
*
|
|
53
|
+
* The SSE half (T11921) gives the gateway a SERVER→CLIENT push stream; this
|
|
54
|
+
* module adds the BIDIRECTIONAL realtime transport an interactive TUI / terminal
|
|
55
|
+
* session needs: a WebSocket upgrade on the SAME `node:http` listener
|
|
56
|
+
* ({@link import('./listen.js').startHttpServer}) that bridges a PTY both
|
|
57
|
+
* directions over WS frames.
|
|
58
|
+
*
|
|
59
|
+
* Design constraints (all four ACs of T11922):
|
|
60
|
+
*
|
|
61
|
+
* - **AC1 — upgrade on the existing listener.** The WS endpoint is NOT a second
|
|
62
|
+
* server: it attaches to the daemon's existing HTTP server via its
|
|
63
|
+
* `'upgrade'` event ({@link attachWsPtyEndpoint}), so it inherits the loopback
|
|
64
|
+
* bind + the daemon's lifecycle. The endpoint path is `/v1/terminal/pty`.
|
|
65
|
+
* - **AC2 — bidirectional PTY bridge with backpressure.** Inbound WS frames are
|
|
66
|
+
* written to the PTY stdin; PTY output is framed back to the client. A control
|
|
67
|
+
* frame (`{type:'resize',cols,rows}`) resizes the PTY. Backpressure is honored
|
|
68
|
+
* on the socket write path (pause-on-`false`-write, resume on `'drain'`).
|
|
69
|
+
* - **AC3 — leak-free, deterministic teardown.** Every open/close/error/abort
|
|
70
|
+
* path routes through ONE idempotent `teardown()` that kills the PTY, removes
|
|
71
|
+
* its listeners, and ends the socket exactly once. A server `close()` tears
|
|
72
|
+
* down every live session.
|
|
73
|
+
* - **AC4 — auth/origin enforced at the upgrade edge; no secrets on the wire.**
|
|
74
|
+
* The upgrade is rejected with a `401`/`403` BEFORE any PTY is spawned unless
|
|
75
|
+
* it comes from loopback AND (when a token is configured) presents the bearer
|
|
76
|
+
* token AND (when an origin allowlist is configured) presents an allowed
|
|
77
|
+
* `Origin`. The spawned PTY runs under a MINIMAL, explicitly-constructed env
|
|
78
|
+
* ({@link scrubPtyEnv}) — the daemon's secret-bearing `process.env` is NEVER
|
|
79
|
+
* inherited, so a secret cannot be exfiltrated through the terminal stream.
|
|
80
|
+
*
|
|
81
|
+
* To keep the **publish surface clean** (D11142 dependency-discipline):
|
|
82
|
+
* - There is NO `ws` dependency. The minimal RFC 6455 server framing needed
|
|
83
|
+
* (accept handshake, decode masked client frames, encode unmasked server
|
|
84
|
+
* frames, close/ping/pong) is implemented over the raw `node:net` socket the
|
|
85
|
+
* `'upgrade'` event hands us. This adds ZERO weight to `@cleocode/runtime`.
|
|
86
|
+
* - `node-pty` is an OPTIONAL, dynamically-loaded dependency (same pattern as
|
|
87
|
+
* {@link import('../../../../core/src/llm/pi/gondolin-loader.js')} and
|
|
88
|
+
* `packages/core/src/tools/pty.ts`): the npm specifier is held in a variable,
|
|
89
|
+
* its shape is declared LOCALLY (no `import type`), and absence is a graceful
|
|
90
|
+
* close frame ("PTY backend unavailable") — NOT a crash. The endpoint always
|
|
91
|
+
* upgrades; it bridges a PTY only when the backend is present.
|
|
92
|
+
*
|
|
93
|
+
* @packageDocumentation
|
|
94
|
+
* @module @cleocode/runtime/gateway/http/ws-pty
|
|
95
|
+
*
|
|
96
|
+
* @task T11922
|
|
97
|
+
* @epic T11769
|
|
98
|
+
* @saga T10400
|
|
99
|
+
* @see ./sse.ts — the SSE half (server→client push) on the same listener
|
|
100
|
+
*/
|
|
101
|
+
|
|
102
|
+
/** The canonical WS terminal/PTY endpoint path on the `/v1` facade. */
|
|
103
|
+
declare const WS_PTY_PATH = "/v1/terminal/pty";
|
|
104
|
+
/**
|
|
105
|
+
* The install hint surfaced to the client (as a WS close reason) when the PTY
|
|
106
|
+
* backend is unavailable. `node-pty` is OPTIONAL — the endpoint still upgrades
|
|
107
|
+
* and then closes cleanly with this reason rather than crashing the daemon.
|
|
108
|
+
*/
|
|
109
|
+
declare const NODE_PTY_INSTALL_HINT: string;
|
|
110
|
+
/** A disposable subscription handle returned by `node-pty`'s event registrars. */
|
|
111
|
+
interface PtyDisposable {
|
|
112
|
+
dispose(): void;
|
|
113
|
+
}
|
|
114
|
+
/** The minimal structural shape of a spawned `node-pty` process the bridge uses. */
|
|
115
|
+
interface NodePtyProcess {
|
|
116
|
+
/** Subscribe to interleaved stdout/stderr output. */
|
|
117
|
+
onData(cb: (data: string) => void): PtyDisposable | undefined;
|
|
118
|
+
/** Subscribe to process exit. */
|
|
119
|
+
onExit(cb: (e: {
|
|
120
|
+
exitCode: number;
|
|
121
|
+
signal?: number;
|
|
122
|
+
}) => void): PtyDisposable | undefined;
|
|
123
|
+
/** Write to the PTY stdin. */
|
|
124
|
+
write(data: string): void;
|
|
125
|
+
/** Resize the PTY. */
|
|
126
|
+
resize(cols: number, rows: number): void;
|
|
127
|
+
/** Kill the underlying process (idempotent host-side; signal optional). */
|
|
128
|
+
kill(signal?: string): void;
|
|
129
|
+
}
|
|
130
|
+
/** The minimal structural shape of the `node-pty` module the bridge uses. */
|
|
131
|
+
interface NodePtyModule {
|
|
132
|
+
spawn(file: string, args: readonly string[], options: {
|
|
133
|
+
readonly name?: string;
|
|
134
|
+
readonly cols?: number;
|
|
135
|
+
readonly rows?: number;
|
|
136
|
+
readonly cwd?: string;
|
|
137
|
+
readonly env?: Record<string, string>;
|
|
138
|
+
}): NodePtyProcess;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Attempt to lazily load `node-pty`. Returns `null` when the optional dep is not
|
|
142
|
+
* installed, fails to load, or does not expose the `spawn` surface — so the
|
|
143
|
+
* caller closes the WS cleanly with {@link NODE_PTY_INSTALL_HINT} instead of
|
|
144
|
+
* crashing. NEVER throws.
|
|
145
|
+
*
|
|
146
|
+
* The import specifier is held in a variable (passed to the {@link importer}
|
|
147
|
+
* seam) so bundlers / TS do not treat the missing optional dep as a hard,
|
|
148
|
+
* statically-resolved dependency (same technique as the gondolin loader).
|
|
149
|
+
*
|
|
150
|
+
* @returns The shape-checked module, or `null` when unavailable.
|
|
151
|
+
*/
|
|
152
|
+
declare function loadNodePty(): Promise<NodePtyModule | null>;
|
|
153
|
+
/**
|
|
154
|
+
* Build the MINIMAL environment the bridged PTY runs under (AC4).
|
|
155
|
+
*
|
|
156
|
+
* Starts EMPTY, copies only the small {@link PASSTHROUGH_KEYS} allowlist from the
|
|
157
|
+
* parent, pins `PATH` to {@link TRUSTED_PATH}, and forces `TERM=xterm-256color`
|
|
158
|
+
* for a sane terminal. The daemon's secrets are NEVER forwarded.
|
|
159
|
+
*
|
|
160
|
+
* @param parentEnv - The parent process environment (defaults to `process.env`).
|
|
161
|
+
* @returns The scrubbed, secret-free env for the PTY.
|
|
162
|
+
*/
|
|
163
|
+
declare function scrubPtyEnv(parentEnv?: NodeJS.ProcessEnv): Record<string, string>;
|
|
164
|
+
/**
|
|
165
|
+
* Derive the `Sec-WebSocket-Accept` response header value from a client
|
|
166
|
+
* `Sec-WebSocket-Key` per RFC 6455 §4.2.2 (SHA-1 of key + GUID, base64).
|
|
167
|
+
*
|
|
168
|
+
* @param key - The client's `Sec-WebSocket-Key` header value.
|
|
169
|
+
* @returns The base64 accept hash.
|
|
170
|
+
*/
|
|
171
|
+
declare function computeAcceptKey(key: string): string;
|
|
172
|
+
/**
|
|
173
|
+
* Encode a WS data frame (server→client, UNMASKED per RFC 6455 §5.1). Used for
|
|
174
|
+
* `text` (PTY output) and `close` control frames.
|
|
175
|
+
*
|
|
176
|
+
* @param opcode - The WS opcode (e.g. {@link OPCODE_TEXT}).
|
|
177
|
+
* @param payload - The frame payload bytes.
|
|
178
|
+
* @returns The framed bytes ready to write to the socket.
|
|
179
|
+
*/
|
|
180
|
+
declare function encodeWsFrame(opcode: number, payload: Buffer): Buffer;
|
|
181
|
+
/** One decoded inbound WS frame. */
|
|
182
|
+
interface DecodedFrame {
|
|
183
|
+
/** The frame opcode. */
|
|
184
|
+
opcode: number;
|
|
185
|
+
/** The unmasked payload bytes. */
|
|
186
|
+
payload: Buffer;
|
|
187
|
+
/** Total bytes consumed from the input buffer (header + payload). */
|
|
188
|
+
consumed: number;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Decode a single inbound (client→server, MASKED) WS frame from a buffer.
|
|
192
|
+
*
|
|
193
|
+
* Returns `null` when the buffer does not yet hold a complete frame (the caller
|
|
194
|
+
* waits for more bytes). Client frames MUST be masked (RFC 6455 §5.3); the mask
|
|
195
|
+
* is applied to recover the payload. Fragmentation is not expected from a
|
|
196
|
+
* terminal client, so a non-FIN frame is decoded as-is (its opcode handled by
|
|
197
|
+
* the caller). NEVER throws on a partial buffer.
|
|
198
|
+
*
|
|
199
|
+
* @param buf - The accumulated inbound bytes.
|
|
200
|
+
* @returns The decoded frame, or `null` when more bytes are needed.
|
|
201
|
+
*/
|
|
202
|
+
declare function decodeWsFrame(buf: Buffer): DecodedFrame | null;
|
|
203
|
+
/** Configuration for the WS terminal/PTY endpoint. */
|
|
204
|
+
interface WsPtyOptions {
|
|
205
|
+
/**
|
|
206
|
+
* Optional bearer token an upgrade MUST present (as `Authorization: Bearer
|
|
207
|
+
* <token>` or `?token=<token>`). When omitted, no token is required (loopback
|
|
208
|
+
* is still enforced unconditionally).
|
|
209
|
+
*/
|
|
210
|
+
token?: string;
|
|
211
|
+
/**
|
|
212
|
+
* Optional `Origin` allowlist. When non-empty, an upgrade MUST present an
|
|
213
|
+
* `Origin` header whose value is in the set, else it is rejected `403`. When
|
|
214
|
+
* omitted/empty, the `Origin` header is not checked (loopback already bounds
|
|
215
|
+
* the surface).
|
|
216
|
+
*/
|
|
217
|
+
allowedOrigins?: readonly string[];
|
|
218
|
+
/** The shell launched for the PTY (default `process.env.SHELL` or `/bin/sh`). */
|
|
219
|
+
shell?: string;
|
|
220
|
+
/** Working directory for the PTY (default `process.cwd()`). */
|
|
221
|
+
cwd?: string;
|
|
222
|
+
}
|
|
223
|
+
/** The decision of the upgrade-edge gate. */
|
|
224
|
+
type GateDecision = {
|
|
225
|
+
ok: true;
|
|
226
|
+
} | {
|
|
227
|
+
ok: false;
|
|
228
|
+
status: number;
|
|
229
|
+
reason: string;
|
|
230
|
+
};
|
|
231
|
+
/**
|
|
232
|
+
* Authorize a WS upgrade at the edge (AC4) — BEFORE any PTY is spawned.
|
|
233
|
+
*
|
|
234
|
+
* Enforced unconditionally:
|
|
235
|
+
* - the connection MUST originate from loopback (`127.0.0.1` / `::1`); a
|
|
236
|
+
* non-loopback peer is rejected `403` (the gateway is local-process-facing).
|
|
237
|
+
*
|
|
238
|
+
* Enforced when configured:
|
|
239
|
+
* - a `token` (matched against `Authorization: Bearer` or `?token=`); a missing
|
|
240
|
+
* or mismatched token is rejected `401`.
|
|
241
|
+
* - an `Origin` allowlist; a missing or disallowed `Origin` is rejected `403`.
|
|
242
|
+
*
|
|
243
|
+
* @param req - The inbound upgrade request.
|
|
244
|
+
* @param remoteAddress - The socket's remote address.
|
|
245
|
+
* @param opts - The endpoint auth configuration.
|
|
246
|
+
* @returns A {@link GateDecision} — `{ok:true}` to proceed, else a typed reject.
|
|
247
|
+
*/
|
|
248
|
+
declare function authorizeUpgrade(req: IncomingMessage, remoteAddress: string | undefined, opts: WsPtyOptions): GateDecision;
|
|
249
|
+
/** Whether a request path is the WS terminal/PTY endpoint. */
|
|
250
|
+
declare function isWsPtyPath(url: string | undefined): boolean;
|
|
251
|
+
/**
|
|
252
|
+
* A handle returned by {@link attachWsPtyEndpoint} so the caller can detach the
|
|
253
|
+
* `'upgrade'` listener and tear down every live session on server close (AC3).
|
|
254
|
+
*/
|
|
255
|
+
interface WsPtyEndpointHandle {
|
|
256
|
+
/** The number of live WS-PTY sessions (for tests / health). */
|
|
257
|
+
readonly sessionCount: number;
|
|
258
|
+
/** Detach the listener and tear down every live session. Idempotent. */
|
|
259
|
+
close(): void;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* The shape of the HTTP server's `'upgrade'` event surface this module needs.
|
|
263
|
+
* Declared structurally so the module does not couple to a concrete `Server`.
|
|
264
|
+
*/
|
|
265
|
+
interface UpgradableServer {
|
|
266
|
+
on(event: 'upgrade', listener: (req: IncomingMessage, socket: Duplex, head: Buffer) => void): void;
|
|
267
|
+
removeListener(event: 'upgrade', listener: (req: IncomingMessage, socket: Duplex, head: Buffer) => void): void;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Attach the WS terminal/PTY endpoint (AC1) to an existing HTTP server's
|
|
271
|
+
* `'upgrade'` event.
|
|
272
|
+
*
|
|
273
|
+
* Every upgrade to {@link WS_PTY_PATH} is gated ({@link authorizeUpgrade}, AC4)
|
|
274
|
+
* BEFORE any PTY is spawned; a rejected upgrade gets a raw `401`/`403` and the
|
|
275
|
+
* socket is destroyed. An accepted upgrade completes the RFC 6455 handshake and
|
|
276
|
+
* bridges a PTY bidirectionally ({@link bridgePty}, AC2). An upgrade to any OTHER
|
|
277
|
+
* path is left for other upgrade handlers (this listener only claims its own
|
|
278
|
+
* path and never destroys a foreign socket).
|
|
279
|
+
*
|
|
280
|
+
* Each live session is tracked so {@link WsPtyEndpointHandle.close} tears every
|
|
281
|
+
* one down deterministically on server close (AC3).
|
|
282
|
+
*
|
|
283
|
+
* @param server - The HTTP server whose `'upgrade'` event to attach to.
|
|
284
|
+
* @param opts - The endpoint auth + PTY configuration.
|
|
285
|
+
* @returns A handle to detach + tear down on server close.
|
|
286
|
+
*/
|
|
287
|
+
declare function attachWsPtyEndpoint(server: UpgradableServer, opts?: WsPtyOptions): WsPtyEndpointHandle;
|
|
288
|
+
|
|
48
289
|
/**
|
|
49
290
|
* `node:http` server binding for the framework-agnostic HTTP gateway adapter.
|
|
50
291
|
*
|
|
@@ -96,6 +337,18 @@ interface HttpServerOptions {
|
|
|
96
337
|
* explicit caller decision.
|
|
97
338
|
*/
|
|
98
339
|
host?: string;
|
|
340
|
+
/**
|
|
341
|
+
* WebSocket terminal/PTY endpoint configuration (T11922 · M5 WS half). When
|
|
342
|
+
* provided, a WS upgrade handler for {@link WS_PTY_PATH} (`/v1/terminal/pty`)
|
|
343
|
+
* is attached to this server's `'upgrade'` event — gated at the edge (loopback
|
|
344
|
+
* + optional token/origin) and bridging a PTY bidirectionally over WS frames.
|
|
345
|
+
* When OMITTED, no upgrade handler is attached and the server stays a pure
|
|
346
|
+
* unary+SSE HTTP listener (the capability is opt-in — the daemon enables it
|
|
347
|
+
* explicitly). The optional `node-pty` backend is loaded dynamically; if it is
|
|
348
|
+
* absent, the endpoint still upgrades and reports a clean "PTY backend
|
|
349
|
+
* unavailable" close rather than crashing.
|
|
350
|
+
*/
|
|
351
|
+
wsPty?: WsPtyOptions;
|
|
99
352
|
}
|
|
100
353
|
/**
|
|
101
354
|
* A live HTTP server handle returned by {@link startHttpServer}.
|
|
@@ -115,14 +368,24 @@ interface HttpServerHandle {
|
|
|
115
368
|
close(): Promise<void>;
|
|
116
369
|
}
|
|
117
370
|
/**
|
|
118
|
-
* The result of parsing a request line into routing coordinates:
|
|
119
|
-
*
|
|
371
|
+
* The result of parsing a request line into routing coordinates: a resolved
|
|
372
|
+
* unary triple, a recognized health probe, or a rejection for the wire edge.
|
|
120
373
|
*/
|
|
121
374
|
type ParsedRoute = {
|
|
122
375
|
ok: true;
|
|
376
|
+
kind: 'unary';
|
|
377
|
+
gateway: Gateway;
|
|
378
|
+
domain: string;
|
|
379
|
+
operation: string;
|
|
380
|
+
} | {
|
|
381
|
+
ok: true;
|
|
382
|
+
kind: 'stream';
|
|
123
383
|
gateway: Gateway;
|
|
124
384
|
domain: string;
|
|
125
385
|
operation: string;
|
|
386
|
+
} | {
|
|
387
|
+
ok: true;
|
|
388
|
+
kind: 'health';
|
|
126
389
|
} | {
|
|
127
390
|
ok: false;
|
|
128
391
|
status: number;
|
|
@@ -130,12 +393,33 @@ type ParsedRoute = {
|
|
|
130
393
|
message: string;
|
|
131
394
|
};
|
|
132
395
|
/**
|
|
133
|
-
* Parse
|
|
396
|
+
* Parse a gateway request line into a routing decision.
|
|
397
|
+
*
|
|
398
|
+
* Two POST routing vocabularies are accepted (the wire payload is identical to
|
|
399
|
+
* every other transport — only the framing differs):
|
|
400
|
+
*
|
|
401
|
+
* - `POST /v1/<domain>/<operation>` — the **versioned REST facade** (T11919).
|
|
402
|
+
* The gateway (`query` | `mutate`) is INFERRED from the registry, so the
|
|
403
|
+
* client need not name it. An unregistered `(domain, operation)` pair is a
|
|
404
|
+
* `404`.
|
|
405
|
+
* - `POST /<gateway>/<domain>/<operation>` — the **legacy** form, where the
|
|
406
|
+
* client names the gateway segment explicitly (validated against the two
|
|
407
|
+
* CQRS gateways so a client cannot smuggle an arbitrary value).
|
|
408
|
+
*
|
|
409
|
+
* Two GET routing vocabularies are accepted:
|
|
134
410
|
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
411
|
+
* - `GET /v1/health` — the liveness probe.
|
|
412
|
+
* - `GET /v1/<domain>/<operation>` — the **SSE streaming** endpoint (T11921),
|
|
413
|
+
* recognized only when the `(domain, operation)` pair is registered AND
|
|
414
|
+
* flagged `streaming: true` in {@link OPERATIONS} (resolved via
|
|
415
|
+
* {@link resolveStreamRoute}). The SAME pair is dispatched UNARY over POST,
|
|
416
|
+
* so the streaming GET co-exists with the unary POST route. A GET to a
|
|
417
|
+
* unary-only op is a `405` (method-not-allowed), distinguishing "route
|
|
418
|
+
* exists, this method is unsupported" from "no such route" (`404`).
|
|
419
|
+
*
|
|
420
|
+
* A non-POST/GET method is rejected at the edge (`405`); a path that resolves to
|
|
421
|
+
* neither vocabulary is a `404`. The injected {@link GatewayHandler} is never
|
|
422
|
+
* invoked with a malformed request.
|
|
139
423
|
*
|
|
140
424
|
* @param method - The HTTP request method.
|
|
141
425
|
* @param url - The HTTP request URL (path + query).
|
|
@@ -348,11 +632,38 @@ interface RpcServerHandle {
|
|
|
348
632
|
* handler errors are caught and rendered as a protocol-level `E_RPC_INTERNAL`
|
|
349
633
|
* error frame — never propagated as an unhandled rejection or `process.exit`.
|
|
350
634
|
*
|
|
635
|
+
* ## Connection-scoped session binding (T11640 · Epic T11638)
|
|
636
|
+
*
|
|
637
|
+
* The daemon serves many connections over one process, so it cannot rely on the
|
|
638
|
+
* single-process session-context singleton for identity. Instead, a frame on a
|
|
639
|
+
* connection that declares a `sessionId` binds it into the `{connId → sessionId}`
|
|
640
|
+
* registry, and the whole dispatch runs inside {@link runWithConnectionHandle}
|
|
641
|
+
* so `core`'s `resolveCurrentSession` resolves THIS connection's session (its
|
|
642
|
+
* highest-precedence tier) rather than "whoever wrote the DB last". When a frame
|
|
643
|
+
* carries no `sessionId`, no binding is performed and resolution transparently
|
|
644
|
+
* falls through to the env / active tiers — preserving existing behavior for
|
|
645
|
+
* anonymous frames.
|
|
646
|
+
*
|
|
647
|
+
* ### Intra-connection bleed safety
|
|
648
|
+
*
|
|
649
|
+
* Frames on one connection are dispatched CONCURRENTLY (each `routeFrame` is
|
|
650
|
+
* fired without awaiting the prior one), and registry binding is last-write-wins.
|
|
651
|
+
* To stop a still-in-flight Frame A from resolving a sibling Frame B's session,
|
|
652
|
+
* the frame's OWN declared `sessionId` is snapshotted into the per-frame
|
|
653
|
+
* connection handle ({@link runWithConnectionHandle}'s third arg) — that snapshot
|
|
654
|
+
* is authoritative for the dispatch, so a later re-bind of the same `connId`
|
|
655
|
+
* cannot retroactively change who Frame A is. The registry binding remains only
|
|
656
|
+
* for the late-binding path used by frames that declare no session of their own.
|
|
657
|
+
*
|
|
351
658
|
* @param handler - The injected transport-neutral gateway handler.
|
|
352
659
|
* @param frame - A validated, version-matched request frame.
|
|
660
|
+
* @param connId - The opaque per-connection id (bound at accept-time). Omitted
|
|
661
|
+
* only by direct/test callers that route a single frame outside a socket; a
|
|
662
|
+
* fresh ephemeral id is minted so the call still runs in an isolated
|
|
663
|
+
* connection-handle scope.
|
|
353
664
|
* @returns The response or error frame to write back on the same connection.
|
|
354
665
|
*/
|
|
355
|
-
declare function routeFrame(handler: GatewayHandler, frame: GatewayRpcRequestFrame): Promise<GatewayRpcResponseFrame | ReturnType<typeof buildErrorFrame>>;
|
|
666
|
+
declare function routeFrame(handler: GatewayHandler, frame: GatewayRpcRequestFrame, connId?: string): Promise<GatewayRpcResponseFrame | ReturnType<typeof buildErrorFrame>>;
|
|
356
667
|
/**
|
|
357
668
|
* Start the CLI-RPC unix-socket server over the gateway.
|
|
358
669
|
*
|
|
@@ -1004,6 +1315,112 @@ type SseSource = (emitter: SseEmitter) => SseTeardown | undefined;
|
|
|
1004
1315
|
*/
|
|
1005
1316
|
declare function createSseStream(source: SseSource, signal?: AbortSignal): ReadableStream<Uint8Array>;
|
|
1006
1317
|
|
|
1318
|
+
/**
|
|
1319
|
+
* Streaming-operation source adapters for the gateway HTTP/SSE transport (T11921).
|
|
1320
|
+
*
|
|
1321
|
+
* A streaming operation (`OperationDef.streaming === true`, served as
|
|
1322
|
+
* `GET /v1/<domain>/<operation>`) needs a *producer*: an async source that tails
|
|
1323
|
+
* an event origin (the agent/worker/board lifecycle bus) and feeds
|
|
1324
|
+
* {@link GatewayStreamEvent} frames into the shared, abort-safe
|
|
1325
|
+
* {@link createSseStream} builder. This module owns ONLY that producer concern —
|
|
1326
|
+
* the wire encoding + stream lifecycle live in `./sse.ts`, and the route parsing
|
|
1327
|
+
* lives in `./listen.ts`.
|
|
1328
|
+
*
|
|
1329
|
+
* The runtime is deliberately DB-free (the runtime invariant — no drizzle, no
|
|
1330
|
+
* `@cleocode/cleo`), so a source here MUST NOT open a store directly. Instead the
|
|
1331
|
+
* listener resolves a source by `<domain>.<operation>` key from the
|
|
1332
|
+
* {@link STREAM_SOURCES} registry; an embedder that owns a richer origin (the
|
|
1333
|
+
* daemon, a SvelteKit route) can inject its own source into the listener at
|
|
1334
|
+
* boot. The default source shipped here is a bounded tick/heartbeat producer that
|
|
1335
|
+
* proves the pipe end-to-end without reaching across the package boundary — and
|
|
1336
|
+
* is exactly what the in-process test exercises.
|
|
1337
|
+
*
|
|
1338
|
+
* Secrets never touch the wire: a source emits only the public lifecycle payload
|
|
1339
|
+
* it is handed; credential resolution (if any) happens server-side before the
|
|
1340
|
+
* frame is built, exactly as it does for a unary dispatch.
|
|
1341
|
+
*
|
|
1342
|
+
* @packageDocumentation
|
|
1343
|
+
* @module @cleocode/runtime/gateway/http/stream-sources
|
|
1344
|
+
*
|
|
1345
|
+
* @task T11921
|
|
1346
|
+
* @epic T11769
|
|
1347
|
+
* @saga T10400
|
|
1348
|
+
*/
|
|
1349
|
+
|
|
1350
|
+
/**
|
|
1351
|
+
* The bind coordinates a {@link GatewayStreamSource} receives: the resolved
|
|
1352
|
+
* `(domain, operation)` of the streaming route, the already-validated request
|
|
1353
|
+
* params, and the request id (so emitted frames correlate back to the origin
|
|
1354
|
+
* request).
|
|
1355
|
+
*/
|
|
1356
|
+
interface StreamSourceContext {
|
|
1357
|
+
/** The canonical domain segment of the streaming route. */
|
|
1358
|
+
domain: string;
|
|
1359
|
+
/** The operation segment of the streaming route. */
|
|
1360
|
+
operation: string;
|
|
1361
|
+
/** The decoded query params for the streaming request. */
|
|
1362
|
+
params: Record<string, unknown>;
|
|
1363
|
+
/** The request id stamped on every emitted {@link GatewayStreamEvent}. */
|
|
1364
|
+
requestId: string;
|
|
1365
|
+
}
|
|
1366
|
+
/**
|
|
1367
|
+
* A teardown callback a {@link GatewayStreamSource} MAY return; invoked exactly
|
|
1368
|
+
* once when the stream ends (client disconnect, terminal frame, completion).
|
|
1369
|
+
*/
|
|
1370
|
+
type StreamSourceTeardown = () => void;
|
|
1371
|
+
/**
|
|
1372
|
+
* A producer for one streaming operation. Receives an {@link SseEmitter}
|
|
1373
|
+
* (`sendStreamEvent` emits one canonical {@link GatewayStreamEvent}) plus the
|
|
1374
|
+
* resolved {@link StreamSourceContext}, and MAY return a teardown callback.
|
|
1375
|
+
*
|
|
1376
|
+
* The source is started synchronously inside the stream builder, mirroring the
|
|
1377
|
+
* Studio SSE endpoints; it may push frames immediately and/or schedule async
|
|
1378
|
+
* work. It MUST drop frames once `emitter.closed` is true (the emitter already
|
|
1379
|
+
* guards this) and MUST clean up timers/listeners in its teardown so a client
|
|
1380
|
+
* disconnect closes the stream leak-free.
|
|
1381
|
+
*/
|
|
1382
|
+
type GatewayStreamSource = (emitter: SseEmitter, context: StreamSourceContext) => StreamSourceTeardown | undefined;
|
|
1383
|
+
/**
|
|
1384
|
+
* The default `orchestrate.events` source: a bounded tick/heartbeat producer.
|
|
1385
|
+
*
|
|
1386
|
+
* Emits a monotonic sequence of `data` {@link GatewayStreamEvent} frames at
|
|
1387
|
+
* {@link DEFAULT_TICK_INTERVAL_MS}, then a terminal `done` frame once the
|
|
1388
|
+
* `ticks` budget is exhausted; a client disconnect tears the timer down before
|
|
1389
|
+
* then. It carries no DB handle and no secret — each frame's payload is a public
|
|
1390
|
+
* heartbeat (`{ tick, ts }`) standing in for an agent/worker/board lifecycle
|
|
1391
|
+
* event until the daemon injects its real origin-tailing source.
|
|
1392
|
+
*
|
|
1393
|
+
* A first frame is emitted SYNCHRONOUSLY so a client (and the test) observes a
|
|
1394
|
+
* well-formed `data:` frame immediately, without waiting a full interval.
|
|
1395
|
+
*
|
|
1396
|
+
* @param emitter - The SSE emitter for this stream.
|
|
1397
|
+
* @param context - The resolved streaming-route context.
|
|
1398
|
+
* @returns A teardown that clears the tick timer.
|
|
1399
|
+
*/
|
|
1400
|
+
declare const tickStreamSource: GatewayStreamSource;
|
|
1401
|
+
/**
|
|
1402
|
+
* Register (or override) the {@link GatewayStreamSource} for a streaming op.
|
|
1403
|
+
*
|
|
1404
|
+
* Lets an embedder that owns a richer event origin (the daemon tailing the
|
|
1405
|
+
* agent/worker/board lifecycle bus, a SvelteKit route reading a store) replace
|
|
1406
|
+
* the default tick source for a given `(domain, operation)` without changing the
|
|
1407
|
+
* listener. Idempotent — a later call wins.
|
|
1408
|
+
*
|
|
1409
|
+
* @param domain - The canonical domain of the streaming op.
|
|
1410
|
+
* @param operation - The operation name of the streaming op.
|
|
1411
|
+
* @param source - The producer to serve this streaming route with.
|
|
1412
|
+
*/
|
|
1413
|
+
declare function registerStreamSource(domain: string, operation: string, source: GatewayStreamSource): void;
|
|
1414
|
+
/**
|
|
1415
|
+
* Resolve the {@link GatewayStreamSource} registered for a streaming op.
|
|
1416
|
+
*
|
|
1417
|
+
* @param domain - The canonical domain of the streaming op.
|
|
1418
|
+
* @param operation - The operation name of the streaming op.
|
|
1419
|
+
* @returns The registered source, or `undefined` when none is registered (the
|
|
1420
|
+
* listener then closes the stream with a single terminal `error` frame).
|
|
1421
|
+
*/
|
|
1422
|
+
declare function resolveStreamSource(domain: string, operation: string): GatewayStreamSource | undefined;
|
|
1423
|
+
|
|
1007
1424
|
/**
|
|
1008
1425
|
* Singleton accessor for the gateway {@link BackgroundJobManager}.
|
|
1009
1426
|
*
|
|
@@ -1481,6 +1898,51 @@ declare function getGatewayDomains(gateway: Gateway): string[];
|
|
|
1481
1898
|
* Resolves a domain + operation to its registered definition.
|
|
1482
1899
|
*/
|
|
1483
1900
|
declare function resolve(gateway: Gateway, domain: string, operation: string): Resolution | undefined;
|
|
1901
|
+
/**
|
|
1902
|
+
* Infer the CQRS {@link Gateway} for a `(domain, operation)` pair from the
|
|
1903
|
+
* registry, without the caller naming `query`/`mutate` up front.
|
|
1904
|
+
*
|
|
1905
|
+
* This backs the versioned `/v1/<domain>/<operation>` REST facade (T11919),
|
|
1906
|
+
* where — unlike the legacy `/<gateway>/<domain>/<operation>` form — the client
|
|
1907
|
+
* does not spell the gateway segment: the registry is the single source of truth
|
|
1908
|
+
* for whether an operation is a read (`query`) or a write (`mutate`). Each
|
|
1909
|
+
* `(domain, operation)` pair maps to exactly one gateway in {@link OPERATIONS},
|
|
1910
|
+
* so the inference is unambiguous.
|
|
1911
|
+
*
|
|
1912
|
+
* @param domain - The canonical domain segment (e.g. `'tasks'`).
|
|
1913
|
+
* @param operation - The operation segment (e.g. `'show'`).
|
|
1914
|
+
* @returns The owning gateway, or `undefined` when no registered operation
|
|
1915
|
+
* matches the pair (the wire edge then renders a `404`).
|
|
1916
|
+
*/
|
|
1917
|
+
declare function inferGateway(domain: string, operation: string): Gateway | undefined;
|
|
1918
|
+
/**
|
|
1919
|
+
* The result of resolving a streaming route: the owning gateway plus the matched
|
|
1920
|
+
* {@link OperationDef} (so the caller has the op's tier/params on hand without a
|
|
1921
|
+
* second lookup).
|
|
1922
|
+
*/
|
|
1923
|
+
interface StreamResolution {
|
|
1924
|
+
/** The CQRS gateway the streaming op is registered under. */
|
|
1925
|
+
gateway: Gateway;
|
|
1926
|
+
/** The matched streaming operation definition. */
|
|
1927
|
+
def: OperationDef;
|
|
1928
|
+
}
|
|
1929
|
+
/**
|
|
1930
|
+
* Resolve a `(domain, operation)` pair to a registered **streaming** operation.
|
|
1931
|
+
*
|
|
1932
|
+
* Backs the `GET /v1/<domain>/<operation>` SSE route (T11921): the listener only
|
|
1933
|
+
* opens a `text/event-stream` for a `(domain, operation)` pair that is BOTH
|
|
1934
|
+
* registered AND explicitly flagged `streaming: true` in {@link OPERATIONS}. A
|
|
1935
|
+
* unary-only op (or an unknown pair) resolves to `undefined`, so the listener
|
|
1936
|
+
* never streams an operation that was not declared streamable — a GET to a
|
|
1937
|
+
* unary op stays a `405` (method-not-allowed) rather than silently opening a
|
|
1938
|
+
* never-ending stream.
|
|
1939
|
+
*
|
|
1940
|
+
* @param domain - The canonical domain segment (e.g. `'orchestrate'`).
|
|
1941
|
+
* @param operation - The operation segment (e.g. `'events'`).
|
|
1942
|
+
* @returns The streaming resolution, or `undefined` when no registered op
|
|
1943
|
+
* matches the pair OR the matched op is not flagged `streaming: true`.
|
|
1944
|
+
*/
|
|
1945
|
+
declare function resolveStreamRoute(domain: string, operation: string): StreamResolution | undefined;
|
|
1484
1946
|
/**
|
|
1485
1947
|
* Validates that all required parameters are present in the request.
|
|
1486
1948
|
* Returns an array of missing parameter keys.
|
|
@@ -1503,6 +1965,103 @@ declare function getCounts(): {
|
|
|
1503
1965
|
total: number;
|
|
1504
1966
|
};
|
|
1505
1967
|
|
|
1968
|
+
/**
|
|
1969
|
+
* Daemon-side gateway server bootstrap — the call-site `cleo daemon serve`
|
|
1970
|
+
* drives (T11919).
|
|
1971
|
+
*
|
|
1972
|
+
* The HTTP gateway adapter (`./http/listen.ts`, T11254) and the supervised
|
|
1973
|
+
* `defineGatewaySubsystem` unit (`./daemon-subsystem.ts`, T11451) both already
|
|
1974
|
+
* exist, but nothing started them: the daemon had no `serve` call-site. This
|
|
1975
|
+
* module is that thin bootstrap — it assembles a {@link SubsystemRegistry} with
|
|
1976
|
+
* one scoped gateway subsystem hosting the HTTP transport (loopback by default)
|
|
1977
|
+
* over an INJECTED {@link GatewayHandler}, starts it, and returns a live handle
|
|
1978
|
+
* with the bound port + an idempotent `close()`.
|
|
1979
|
+
*
|
|
1980
|
+
* It carries NO `@cleocode/cleo` dependency and NO drizzle (the runtime
|
|
1981
|
+
* invariant): the caller (`cleo daemon serve`) injects the assembled CLI gateway
|
|
1982
|
+
* handler and the resolved bind coordinates. Secrets never touch the wire —
|
|
1983
|
+
* sealed-handle resolution happens server-side inside the dispatched handler,
|
|
1984
|
+
* exactly as it does for an in-process CLI call. The HTTP listener binds
|
|
1985
|
+
* `127.0.0.1` by default (loopback only); exposing it on a public interface is
|
|
1986
|
+
* an explicit caller decision.
|
|
1987
|
+
*
|
|
1988
|
+
* The streaming transports (SSE — T11921, WS — T11922) extend the SAME
|
|
1989
|
+
* subsystem: when their listeners land they bind alongside the unary HTTP server
|
|
1990
|
+
* here, so this bootstrap deliberately owns only transport assembly + lifecycle,
|
|
1991
|
+
* leaving the per-route seam to the adapter (`parseHttpRoute`).
|
|
1992
|
+
*
|
|
1993
|
+
* @packageDocumentation
|
|
1994
|
+
* @module @cleocode/runtime/gateway
|
|
1995
|
+
*
|
|
1996
|
+
* @task T11919
|
|
1997
|
+
* @epic T11769
|
|
1998
|
+
* @saga T10400
|
|
1999
|
+
*/
|
|
2000
|
+
|
|
2001
|
+
/**
|
|
2002
|
+
* Options for {@link serveGateway}.
|
|
2003
|
+
*
|
|
2004
|
+
* The caller injects the assembled {@link GatewayHandler} and resolves the bind
|
|
2005
|
+
* coordinates so the runtime stays free of `@cleocode/paths`/`@cleocode/cleo`.
|
|
2006
|
+
*/
|
|
2007
|
+
interface ServeGatewayOptions {
|
|
2008
|
+
/** The transport-neutral gateway handler every hosted transport routes through. */
|
|
2009
|
+
handler: GatewayHandler;
|
|
2010
|
+
/** TCP port to bind. `0` selects an ephemeral port (readable from the handle). */
|
|
2011
|
+
port: number;
|
|
2012
|
+
/** Host/interface to bind. Defaults to `127.0.0.1` (loopback only). */
|
|
2013
|
+
host?: string;
|
|
2014
|
+
/** The scope this gateway process serves. Defaults to `'global'`. */
|
|
2015
|
+
scope?: GatewayScope;
|
|
2016
|
+
}
|
|
2017
|
+
/**
|
|
2018
|
+
* A live gateway server handle returned by {@link serveGateway}.
|
|
2019
|
+
*
|
|
2020
|
+
* Exposes the actually-bound `port`/`host` (resolved even when `0` was
|
|
2021
|
+
* requested) and an idempotent {@link close} for deterministic teardown
|
|
2022
|
+
* (daemon shutdown, tests). Mirrors the lower-level
|
|
2023
|
+
* {@link import('./http/listen.js').HttpServerHandle} so a test can boot, probe,
|
|
2024
|
+
* and tear down on an ephemeral port.
|
|
2025
|
+
*/
|
|
2026
|
+
interface ServeGatewayHandle {
|
|
2027
|
+
/** The actually-bound HTTP port (resolved when `0` was requested). */
|
|
2028
|
+
port: number;
|
|
2029
|
+
/** Host/interface the HTTP listener is bound to. */
|
|
2030
|
+
host: string;
|
|
2031
|
+
/** The scope the gateway process serves. */
|
|
2032
|
+
scope: GatewayScope;
|
|
2033
|
+
/** Stop every bound listener (best-effort, idempotent); resolves once closed. */
|
|
2034
|
+
close(): Promise<void>;
|
|
2035
|
+
}
|
|
2036
|
+
/**
|
|
2037
|
+
* Boot the HTTP gateway as a supervised subsystem and return a live handle.
|
|
2038
|
+
*
|
|
2039
|
+
* Declares one scoped gateway subsystem hosting the HTTP transport (loopback
|
|
2040
|
+
* default) over the injected handler via {@link defineGatewaySubsystem}, starts
|
|
2041
|
+
* it, and reads the actually-bound port from the start context (so the caller —
|
|
2042
|
+
* and tests — learn the ephemeral port when `0` was requested). The returned
|
|
2043
|
+
* `close()` drives the subsystem's `shutdown(context)` so teardown is the same
|
|
2044
|
+
* lifecycle the daemon registry uses for every other supervised concern.
|
|
2045
|
+
*
|
|
2046
|
+
* Using `defineGatewaySubsystem` directly (rather than a full
|
|
2047
|
+
* `SubsystemRegistry`) keeps the bound HTTP handle in reach for the port
|
|
2048
|
+
* resolution while still routing through the canonical start→shutdown contract.
|
|
2049
|
+
*
|
|
2050
|
+
* @param opts - The injected handler + resolved bind coordinates.
|
|
2051
|
+
* @returns A promise resolving to the live {@link ServeGatewayHandle}.
|
|
2052
|
+
*
|
|
2053
|
+
* @example
|
|
2054
|
+
* ```ts
|
|
2055
|
+
* const handle = await serveGateway({
|
|
2056
|
+
* handler: createCliGatewayHandler(),
|
|
2057
|
+
* port: 0, // ephemeral
|
|
2058
|
+
* });
|
|
2059
|
+
* // POST http://127.0.0.1:${handle.port}/v1/tasks/show
|
|
2060
|
+
* await handle.close();
|
|
2061
|
+
* ```
|
|
2062
|
+
*/
|
|
2063
|
+
declare function serveGateway(opts: ServeGatewayOptions): Promise<ServeGatewayHandle>;
|
|
2064
|
+
|
|
1506
2065
|
/**
|
|
1507
2066
|
* `@cleocode/runtime/gateway` — the transport-agnostic CQRS dispatch core.
|
|
1508
2067
|
*
|
|
@@ -1542,4 +2101,4 @@ interface GatewayHandler {
|
|
|
1542
2101
|
*/
|
|
1543
2102
|
declare function createGatewayHandler(config: DispatcherConfig): GatewayHandler;
|
|
1544
2103
|
|
|
1545
|
-
export {
|
|
2104
|
+
export { type ErrorMeta as $, startHttpServer as A, statusForResponse as B, tickStreamSource as C, type GatewayOperationKey as D, type DecodeResult, type McpContent as E, type McpInputProperty as F, type GateDecision as G, type HttpServerHandle as H, type McpServerOptions as I, type McpTool as J, type McpToolResult as K, buildToolsList as L, LineBuffer, MCP_TOOL_PREFIX as M, NODE_PTY_INSTALL_HINT as N, callTool as O, exposedOperations as P, operationToMcpTool as Q, operationToToolName as R, type RpcServerHandle, type RpcServerOptions, SSE_HEADERS as S, startMcpServer as T, type UpgradableServer as U, toolNameToOperationKey as V, WS_PTY_PATH as W, BRAIN_DB_FILENAME as X, CLEO_DIR_NAME as Y, Dispatcher as Z, type DispatcherConfig as _, type GatewayStreamSource as a, type GatewayHandler as a0, type GatewayScope as a1, type GatewaySubsystemContext as a2, type GatewaySubsystemOptions as a3, OPERATIONS as a4, STRING_TO_EXIT as a5, type ServeGatewayHandle as a6, type ServeGatewayOptions as a7, type StreamResolution as a8, WORKFLOWS_SUBDIR as a9, setJobManager as aA, stampNexusMeta as aB, validateLabels as aC, validateRequiredParams as aD, validateSuggestedNext as aE, buildNexusMetaExtensions as aa, cleoErrorToEngineError as ab, compose as ac, createDispatchMeta as ad, createGatewayHandler as ae, defineGatewaySubsystem as af, deriveGatewayMatrix as ag, engineError as ah, formatSuggestedNext as ai, gatewaySubsystemName as aj, generateTemplateConfig as ak, getActiveDomains as al, getByDomain as am, getByGateway as an, getByTier as ao, getCounts as ap, getGatewayDomains as aq, getJobManager as ar, getTemplateForSubcommand as as, inferGateway as at, mapNumericExitCodeToString as au, parseIssueTemplates as av, pickDecoratorMetaExtensions as aw, resolve as ax, resolveStreamRoute as ay, serveGateway as az, type HttpServerOptions as b, buildErrorFrame, type HttpUnaryRequest as c, type HttpUnaryResult as d, decodeLine, type SseEmitter as e, encodeFrame, type SseFrame as f, type SseSource as g, type StreamSourceContext as h, type StreamSourceTeardown as i, type WsPtyEndpointHandle as j, type WsPtyOptions as k, attachWsPtyEndpoint as l, authorizeUpgrade as m, computeAcceptKey as n, createSseStream as o, decodeWsFrame as p, encodeSseFrame as q, encodeStreamEvent as r, routeFrame, encodeWsFrame as s, startRpcServer, isWsPtyPath as t, loadNodePty as u, parseHttpRoute as v, registerStreamSource as w, resolveStreamSource as x, routeUnary as y, scrubPtyEnv as z };
|