@cleocode/runtime 2026.5.130 → 2026.5.131

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.
@@ -0,0 +1,1545 @@
1
+ import { DomainHandler, Middleware, DispatchRequest, DispatchResponse, Gateway, GatewayStreamEvent, Source, DispatchResponseMeta, CanonicalDomain, Tier } from '@cleocode/contracts/gateway';
2
+ import { BackgroundJobManager } from '@cleocode/core/store/background-jobs.js';
3
+ import { Subsystem, OperationDef, SuggestedNextOp, Resolution } from '@cleocode/contracts';
4
+ import { Server } from 'node:http';
5
+ import '@cleocode/contracts/operations/orchestrate';
6
+ import * as _cleocode_core_internal from '@cleocode/core/internal';
7
+ import { EngineResult, ProblemDetails } from '@cleocode/core';
8
+ import { GatewayRpcRequestFrame, GatewayRpcErrorFrame, GatewayRpcErrorCode, GatewayRpcResponseFrame } from '@cleocode/contracts/gateway/rpc';
9
+ import { Server as Server$1 } from 'node:net';
10
+
11
+ /**
12
+ * Central Dispatcher -- Routes requests through middleware to domain handlers.
13
+ *
14
+ * The dispatcher is the single entry point for the CLI adapter.
15
+ * It resolves operations, validates parameters, runs the middleware pipeline,
16
+ * and delegates to the appropriate domain handler.
17
+ *
18
+ * Flow: DispatchRequest → resolve → param validation → middleware → handler
19
+ *
20
+ * ## T1088 — Dialectic Evaluator Hook (PSYCHE Wave 3)
21
+ *
22
+ * After each successful mutate operation, the dispatcher fires a background
23
+ * `evaluateDialectic` call via `setImmediate` if all of the following apply:
24
+ *
25
+ * 1. The response indicates `success: true`.
26
+ * 2. The request gateway is `"mutate"` (state-modifying user-facing commands).
27
+ * 3. A `sessionId` is present on the request (identifies conversation context).
28
+ * 4. The in-memory rate limiter allows the evaluation (1 per 10s per session).
29
+ *
30
+ * Errors from the background evaluation are caught and logged at `warn` level
31
+ * so they never affect the caller.
32
+ *
33
+ * @epic T4820
34
+ * @task T1088
35
+ */
36
+
37
+ interface DispatcherConfig {
38
+ handlers: Map<string, DomainHandler>;
39
+ middlewares?: Middleware[];
40
+ }
41
+ declare class Dispatcher {
42
+ private handlers;
43
+ private pipeline;
44
+ constructor(config: DispatcherConfig);
45
+ dispatch(request: DispatchRequest): Promise<DispatchResponse>;
46
+ }
47
+
48
+ /**
49
+ * `node:http` server binding for the framework-agnostic HTTP gateway adapter.
50
+ *
51
+ * The HTTP adapter ({@link routeUnary} + the SSE primitives) is deliberately
52
+ * framework-agnostic — it owns NO port binding and NO `Request`/`Response`
53
+ * lifecycle, so an embedder (a SvelteKit route, a test harness) can drive it
54
+ * directly. The **daemon**, however, is itself the embedder: it must expose the
55
+ * gateway to external HTTP clients over a real listening socket. This module is
56
+ * that thin embedder — a minimal `node:http` server that parses the request URL
57
+ * into a `(gateway, domain, operation)` triple, reads the JSON body, and routes
58
+ * it through {@link routeUnary}. It deliberately stays in the runtime (no
59
+ * SvelteKit / no `@cleocode/cleo` / no drizzle dependency) so the daemon can
60
+ * host the gateway without reaching across a package boundary.
61
+ *
62
+ * Routing contract (intentionally minimal — the wire vocabulary is the same as
63
+ * every other transport, only the framing differs):
64
+ *
65
+ * `POST /<gateway>/<domain>/<operation>` with a JSON body → operation params
66
+ *
67
+ * where `<gateway>` is `query` | `mutate`. A non-POST method, an unparseable
68
+ * path, or a body that is not a JSON object is rejected at the wire edge with a
69
+ * LAFS-shaped error envelope — the injected {@link GatewayHandler} is never
70
+ * invoked with a malformed request.
71
+ *
72
+ * @packageDocumentation
73
+ * @module @cleocode/runtime/gateway/http
74
+ *
75
+ * @task T11451
76
+ * @epic T11254
77
+ * @saga T11243 SG-RUNTIME-UNIFICATION
78
+ */
79
+
80
+ /**
81
+ * Options for {@link startHttpServer}.
82
+ *
83
+ * Mirrors the connection-oriented {@link RpcServerOptions} shape: the caller
84
+ * resolves the bind coordinates so the runtime stays free of any
85
+ * `@cleocode/paths` dependency.
86
+ */
87
+ interface HttpServerOptions {
88
+ /**
89
+ * TCP port to bind. `0` selects an ephemeral port (the bound port is then
90
+ * readable from {@link HttpServerHandle.port}).
91
+ */
92
+ port: number;
93
+ /**
94
+ * Host/interface to bind. Defaults to `127.0.0.1` (loopback only) — the
95
+ * gateway is local-process-facing; exposing it on a public interface is an
96
+ * explicit caller decision.
97
+ */
98
+ host?: string;
99
+ }
100
+ /**
101
+ * A live HTTP server handle returned by {@link startHttpServer}.
102
+ *
103
+ * Exposes the bound {@link Server}, the actually-bound `port` (resolved even
104
+ * when `0` was requested), and an idempotent {@link close}. The adapter never
105
+ * calls `process.exit` — lifecycle stays with the caller (R3 contract).
106
+ */
107
+ interface HttpServerHandle {
108
+ /** The bound `node:http` server. */
109
+ server: Server;
110
+ /** The actually-bound TCP port (resolved when `0` was requested). */
111
+ port: number;
112
+ /** Host/interface the server is bound to. */
113
+ host: string;
114
+ /** Close the server + all live connections; resolves once fully closed. */
115
+ close(): Promise<void>;
116
+ }
117
+ /**
118
+ * The result of parsing a request line into routing coordinates: either a
119
+ * resolved unary triple or a rejection reason for the wire edge.
120
+ */
121
+ type ParsedRoute = {
122
+ ok: true;
123
+ gateway: Gateway;
124
+ domain: string;
125
+ operation: string;
126
+ } | {
127
+ ok: false;
128
+ status: number;
129
+ code: string;
130
+ message: string;
131
+ };
132
+ /**
133
+ * Parse `POST /<gateway>/<domain>/<operation>` into a routing triple.
134
+ *
135
+ * Rejects a non-POST method (`405`) and any path that does not resolve to a
136
+ * known `(gateway, domain, operation)` triple (`404`). The gateway segment is
137
+ * validated against the two CQRS gateways so a client cannot smuggle an
138
+ * arbitrary value into the dispatch request.
139
+ *
140
+ * @param method - The HTTP request method.
141
+ * @param url - The HTTP request URL (path + query).
142
+ * @returns The parsed route, or a typed rejection for the wire edge.
143
+ */
144
+ declare function parseHttpRoute(method: string | undefined, url: string | undefined): ParsedRoute;
145
+ /**
146
+ * Start a `node:http` server that hosts the gateway over HTTP for external
147
+ * clients.
148
+ *
149
+ * Binds {@link HttpServerOptions.port} on {@link HttpServerOptions.host}
150
+ * (default loopback), routes every `POST /<gateway>/<domain>/<operation>`
151
+ * through the injected {@link GatewayHandler} via {@link routeUnary}, and
152
+ * resolves once listening. The returned {@link HttpServerHandle} exposes an
153
+ * idempotent `close()` for deterministic teardown (daemon shutdown, tests). The
154
+ * adapter never calls `process.exit`.
155
+ *
156
+ * The caller assembles the handler (via `createGatewayHandler` with its domain
157
+ * handlers + middleware) and injects it here — this server never builds
158
+ * handlers itself, keeping the runtime free of any `@cleocode/cleo` dependency.
159
+ *
160
+ * @param handler - The transport-neutral gateway handler to route through.
161
+ * @param opts - Bind coordinates.
162
+ * @returns A promise resolving to the live {@link HttpServerHandle}.
163
+ */
164
+ declare function startHttpServer(handler: GatewayHandler, opts: HttpServerOptions): Promise<HttpServerHandle>;
165
+
166
+ /**
167
+ * NDJSON codec for the CLI-RPC transport.
168
+ *
169
+ * Implements the SAME framing discipline as the FROZEN `supervisor-ipc` v1.0
170
+ * contract — one zod-validated JSON envelope per newline-delimited line, with
171
+ * an explicit `protocol_version` negotiation step — but for the gateway-RPC
172
+ * frame set (`@cleocode/contracts/gateway/rpc`). The supervisor-ipc module is
173
+ * frozen and is NOT edited; this codec re-applies its pattern.
174
+ *
175
+ * The codec is intentionally socket-agnostic: it owns line buffering, JSON
176
+ * parse, zod decode, and version negotiation, returning typed results the
177
+ * server maps onto `node:net` reads/writes. This keeps the parse/validate logic
178
+ * unit-testable without binding a real socket.
179
+ *
180
+ * @task T11449
181
+ * @epic T11254
182
+ * @saga T11243
183
+ */
184
+
185
+ /**
186
+ * Encode any RPC frame to a single NDJSON line (JSON + trailing `\n`).
187
+ *
188
+ * @param frame - The response or error frame to serialize.
189
+ * @returns A newline-terminated JSON string ready to write to the socket.
190
+ */
191
+ declare function encodeFrame(frame: GatewayRpcResponseFrame | GatewayRpcErrorFrame): string;
192
+ /**
193
+ * Build a protocol-level error frame.
194
+ *
195
+ * @param id - Correlation id (`'0'` when the originating frame's id is unknown).
196
+ * @param code - One of the frozen {@link GatewayRpcErrorCode} values.
197
+ * @param message - Human-readable detail.
198
+ * @returns A fully-formed {@link GatewayRpcErrorFrame}.
199
+ */
200
+ declare function buildErrorFrame(id: string, code: GatewayRpcErrorCode, message: string): GatewayRpcErrorFrame;
201
+ /**
202
+ * The discriminated outcome of decoding a single inbound NDJSON line.
203
+ *
204
+ * - `request` — a valid, version-matched request frame ready to route.
205
+ * - `error` — a protocol-level error frame the server should write straight
206
+ * back (parse failure, version mismatch, or malformed frame). The
207
+ * server never routes these to the gateway.
208
+ */
209
+ type DecodeResult = {
210
+ kind: 'request';
211
+ frame: GatewayRpcRequestFrame;
212
+ } | {
213
+ kind: 'error';
214
+ frame: GatewayRpcErrorFrame;
215
+ };
216
+ /**
217
+ * Decode + validate a single inbound NDJSON line into a routable request or a
218
+ * protocol-level error frame.
219
+ *
220
+ * Steps (the supervisor-ipc pattern, applied to gateway frames):
221
+ * 1. JSON parse — failure → `E_RPC_PARSE`.
222
+ * 2. zod decode against {@link GatewayRpcFrameSchema} — failure → `E_RPC_BAD_FRAME`.
223
+ * 3. version negotiation via {@link isFrozenGatewayRpcVersion} —
224
+ * mismatch → `E_RPC_BAD_VERSION`.
225
+ * 4. direction must be `request` (a server never receives response/error
226
+ * frames) — otherwise → `E_RPC_BAD_FRAME`.
227
+ *
228
+ * The best-effort correlation `id` is recovered from the raw JSON when possible
229
+ * so the client can match the error to its request even on a decode failure.
230
+ *
231
+ * @param line - One trimmed NDJSON line (no trailing newline).
232
+ * @returns A {@link DecodeResult}.
233
+ */
234
+ declare function decodeLine(line: string): DecodeResult;
235
+ /**
236
+ * A streaming line splitter for the NDJSON wire.
237
+ *
238
+ * `node:net` sockets deliver arbitrary chunk boundaries; a single `data` event
239
+ * may carry a partial line or several lines. This buffer accumulates bytes and
240
+ * yields only complete lines (split on `\n`), matching the supervisor-ipc
241
+ * client's `readline`-style framing without depending on `readline` (so it can
242
+ * be driven directly off socket chunks).
243
+ */
244
+ declare class LineBuffer {
245
+ /** Pending bytes that have not yet completed a line. */
246
+ private buffer;
247
+ /**
248
+ * Push a decoded UTF-8 chunk; return every complete line it completes.
249
+ *
250
+ * @param chunk - A UTF-8 string chunk from the socket.
251
+ * @returns Zero or more complete lines (trailing newline stripped, blanks
252
+ * skipped).
253
+ */
254
+ push(chunk: string): string[];
255
+ }
256
+
257
+ /**
258
+ * Wire + lifecycle types for the `@cleocode/runtime/gateway/rpc` adapter.
259
+ *
260
+ * The RPC wire frames themselves are defined (zod) in
261
+ * `@cleocode/contracts/gateway/rpc`; this module holds only the
262
+ * runtime-adapter-local option/handle shapes (no external dependency, mirroring
263
+ * the MCP adapter's `types.ts`).
264
+ *
265
+ * @task T11449
266
+ * @epic T11254
267
+ * @saga T11243
268
+ */
269
+
270
+ /**
271
+ * Options for {@link startRpcServer}.
272
+ *
273
+ * Mirrors the MCP adapter's `McpServerOptions` shape (a transport-local options
274
+ * bag), adapted for a connection-oriented unix-socket server rather than a
275
+ * single stdio stream.
276
+ */
277
+ interface RpcServerOptions {
278
+ /**
279
+ * Absolute path to the unix-domain socket to bind. The caller resolves this
280
+ * (e.g. under the CLEO home using
281
+ * {@link GATEWAY_RPC_CHANNEL_BASENAME}) so the runtime stays free of any
282
+ * `@cleocode/paths` dependency.
283
+ */
284
+ socketPath: string;
285
+ /**
286
+ * Whether to `unlink` a stale socket file at {@link socketPath} before
287
+ * binding. Defaults to `true` (a crashed prior server leaves a stale node).
288
+ */
289
+ removeStaleSocket?: boolean;
290
+ }
291
+ /**
292
+ * A live RPC server handle returned by {@link startRpcServer}.
293
+ *
294
+ * Exposes the bound {@link Server} and an idempotent {@link close} so callers
295
+ * (daemon, tests) can tear down deterministically. The adapter never calls
296
+ * `process.exit` — lifecycle stays with the caller (R3 contract).
297
+ */
298
+ interface RpcServerHandle {
299
+ /** The bound `node:net` server. */
300
+ server: Server$1;
301
+ /** Absolute path of the bound unix socket. */
302
+ socketPath: string;
303
+ /** Close the server + all live connections; resolves once fully closed. */
304
+ close(): Promise<void>;
305
+ }
306
+
307
+ /**
308
+ * CLI-RPC unix-socket transport adapter — routes NDJSON frames through the gateway.
309
+ *
310
+ * Serves the gateway over a long-lived unix-domain socket using newline-delimited
311
+ * JSON (NDJSON): one zod-validated {@link GatewayRpcFrame} per line. Any local
312
+ * client (the `cleo` CLI talking to a warm daemon, Studio's server process, a
313
+ * test harness) can open the socket, write `request` frames, and read back
314
+ * `response`/`error` frames — without paying the per-invocation cold-start of
315
+ * spawning a fresh `cleo` process.
316
+ *
317
+ * This is the THIRD transport adapter, mirroring the just-merged MCP stdio
318
+ * adapter (`packages/runtime/src/gateway/mcp/`):
319
+ *
320
+ * RPC request frame { direction:'request', request:{…} }
321
+ * → decode + validate (`@cleocode/contracts/gateway/rpc`)
322
+ * → DispatchRequest { source: 'rpc', … } (re-validated at the boundary)
323
+ * → injected {@link GatewayHandler}.handle()
324
+ * → DispatchResponse (LAFS envelope) → RPC response frame
325
+ *
326
+ * The adapter owns ONLY wire concerns: socket lifecycle, line framing, version
327
+ * negotiation, error rendering, and per-connection cleanup. All domain logic
328
+ * (resolution, validation, middleware, handler execution) lives behind the
329
+ * {@link GatewayHandler} — exactly mirroring the CLI and MCP adapters. There is
330
+ * NO `process.exit` and NO error-render inside the handlers (R3 contract); the
331
+ * adapter never calls `process.exit` at all (lifecycle is the caller's).
332
+ *
333
+ * The request `source` is forced to `'rpc'` regardless of what the client sent,
334
+ * so a client cannot impersonate another transport.
335
+ *
336
+ * @task T11449
337
+ * @epic T11254
338
+ * @saga T11243
339
+ */
340
+
341
+ /**
342
+ * Route a single decoded request frame through the gateway handler and build
343
+ * the correlated response frame.
344
+ *
345
+ * The request's `source` is forced to `'rpc'`; the frame `id` is reused as the
346
+ * response correlation id (and, when the client omitted a `requestId` shaped
347
+ * for tracing, the frame id flows through as the dispatch `requestId`). Thrown
348
+ * handler errors are caught and rendered as a protocol-level `E_RPC_INTERNAL`
349
+ * error frame — never propagated as an unhandled rejection or `process.exit`.
350
+ *
351
+ * @param handler - The injected transport-neutral gateway handler.
352
+ * @param frame - A validated, version-matched request frame.
353
+ * @returns The response or error frame to write back on the same connection.
354
+ */
355
+ declare function routeFrame(handler: GatewayHandler, frame: GatewayRpcRequestFrame): Promise<GatewayRpcResponseFrame | ReturnType<typeof buildErrorFrame>>;
356
+ /**
357
+ * Start the CLI-RPC unix-socket server over the gateway.
358
+ *
359
+ * Binds {@link RpcServerOptions.socketPath}, accepts connections, and routes
360
+ * each inbound NDJSON `request` frame through the injected {@link GatewayHandler}.
361
+ * The caller assembles the handler (via `createGatewayHandler` with its domain
362
+ * handlers + middleware) and injects it here — this adapter never builds
363
+ * handlers itself, keeping the runtime free of any `@cleocode/cleo` dependency.
364
+ *
365
+ * Returns once the socket is listening. The returned {@link RpcServerHandle}
366
+ * exposes an idempotent `close()` for deterministic teardown (daemon shutdown,
367
+ * tests). The adapter never calls `process.exit`.
368
+ *
369
+ * @param handler - The transport-neutral gateway handler to route through.
370
+ * @param opts - Socket path + lifecycle options.
371
+ * @returns A promise resolving to the live {@link RpcServerHandle}.
372
+ */
373
+ declare function startRpcServer(handler: GatewayHandler, opts: RpcServerOptions): Promise<RpcServerHandle>;
374
+
375
+ /**
376
+ * The gateway as a supervised **daemon subsystem**.
377
+ *
378
+ * R3-T7 (this task) closes the loop between the two R-track halves: the R3
379
+ * gateway (dispatcher + the four transport adapters) and the R2 daemon
380
+ * (`defineSubsystem` + the `SubsystemRegistry`). It expresses the
381
+ * external-facing gateway as a uniform {@link Subsystem} so the R2 daemon
382
+ * registry drives its `start → healthProbe → shutdown` lifecycle exactly like
383
+ * every other long-running concern (Studio supervision, the GC cron, …). One
384
+ * gateway subsystem is registered per scope (project / global) → one
385
+ * external-facing gateway process per scope.
386
+ *
387
+ * Which transports the daemon hosts:
388
+ * - the **RPC unix socket** (`@cleocode/runtime/gateway/rpc`) — the canonical
389
+ * local-client wire: the `cleo` CLI, Studio's server process, and test
390
+ * harnesses open it to dispatch without paying a cold `cleo` spawn.
391
+ * - the **HTTP server** (`@cleocode/runtime/gateway/http` via the daemon-local
392
+ * `startHttpServer` embedder) — for external clients that speak HTTP rather
393
+ * than the unix-socket NDJSON wire.
394
+ *
395
+ * The CLI and MCP adapters are intentionally NOT hosted by the daemon: the CLI
396
+ * adapter is in-process to the `cleo` binary, and the MCP adapter is a stdio
397
+ * server an MCP client spawns and owns — neither is a long-lived,
398
+ * daemon-supervised listener. The two external-facing listeners (RPC + HTTP)
399
+ * are the ones the daemon owns.
400
+ *
401
+ * This subsystem adds NO behavior to the adapters themselves — it only wires
402
+ * their existing `start*Server` / `close()` lifecycle (and their already-merged
403
+ * routing) into the daemon registry's uniform lifecycle. It carries NO
404
+ * `@cleocode/cleo` dependency and NO drizzle-orm (the runtime invariant): the
405
+ * caller injects the assembled {@link GatewayHandler} and the resolved bind
406
+ * coordinates; this module only orchestrates listeners.
407
+ *
408
+ * @packageDocumentation
409
+ * @module @cleocode/runtime/gateway
410
+ *
411
+ * @task T11451 (R3-T7)
412
+ * @epic T11254
413
+ * @saga T11243 SG-RUNTIME-UNIFICATION
414
+ */
415
+
416
+ /** The scope a single gateway process serves — one external-facing process per scope. */
417
+ type GatewayScope = 'project' | 'global';
418
+ /**
419
+ * Configuration for one scoped gateway subsystem.
420
+ *
421
+ * The caller injects the assembled, transport-neutral {@link GatewayHandler}
422
+ * (built with `createGatewayHandler` from its domain handlers + middleware) and
423
+ * the resolved bind coordinates for each hosted transport. The runtime never
424
+ * resolves paths/ports itself — that keeps it free of `@cleocode/paths` and of
425
+ * any policy decision about where a scope's socket/port lives.
426
+ */
427
+ interface GatewaySubsystemOptions {
428
+ /** The scope this gateway process serves (`project` | `global`). */
429
+ scope: GatewayScope;
430
+ /** The transport-neutral gateway handler every hosted transport routes through. */
431
+ handler: GatewayHandler;
432
+ /**
433
+ * RPC unix-socket transport options. When omitted, the RPC transport is not
434
+ * hosted (a deployment that only wants HTTP). At least one transport MUST be
435
+ * configured.
436
+ */
437
+ rpc?: RpcServerOptions;
438
+ /**
439
+ * HTTP transport options. When omitted, the HTTP transport is not hosted (a
440
+ * deployment that only wants the local RPC socket). At least one transport
441
+ * MUST be configured.
442
+ */
443
+ http?: HttpServerOptions;
444
+ }
445
+ /**
446
+ * The live context a started gateway subsystem threads from `start` into
447
+ * `healthProbe`/`shutdown`: the bound transport handles plus the owning pid.
448
+ *
449
+ * `void`-typed contexts are common for subsystems, but the gateway needs to
450
+ * carry its bound handles so `shutdown` can close exactly what `start` opened
451
+ * (and `healthProbe` can report the bound coordinates).
452
+ */
453
+ interface GatewaySubsystemContext {
454
+ /** The OS pid hosting the listeners (this daemon process). */
455
+ readonly pid: number;
456
+ /** The bound RPC server handle, when the RPC transport is hosted. */
457
+ readonly rpc?: RpcServerHandle;
458
+ /** The bound HTTP server handle, when the HTTP transport is hosted. */
459
+ readonly http?: HttpServerHandle;
460
+ }
461
+ /**
462
+ * The stable subsystem name (and supervised `child_id`) of a scoped gateway.
463
+ *
464
+ * Suffixed with the scope so a single daemon process supervising both scopes
465
+ * (project + global) registers two distinct, non-colliding subsystems. The
466
+ * `child_id` matches the id the Rust supervisor tracks the listener under.
467
+ *
468
+ * @param scope - The gateway scope.
469
+ * @returns The subsystem name, e.g. `gateway-project`.
470
+ */
471
+ declare function gatewaySubsystemName(scope: GatewayScope): string;
472
+ /**
473
+ * Declare the external-facing gateway as a supervised daemon {@link Subsystem}.
474
+ *
475
+ * The returned subsystem (frozen by {@link defineSubsystem}) is registered with
476
+ * a `SubsystemRegistry`, which then drives its lifecycle uniformly:
477
+ *
478
+ * - `start()` — binds the configured transports (RPC unix socket and/or
479
+ * HTTP server) over the injected handler, in a fixed order (RPC then HTTP).
480
+ * If the second listener fails to bind, the first is rolled back so a failed
481
+ * start leaves no half-open listener — then the error is re-thrown for the
482
+ * registry's `onError` sink.
483
+ * - `healthProbe()` — reports a single {@link SubsystemHealth} row keyed on the
484
+ * scoped `child_id`, `running` while the configured listeners are live, with
485
+ * a `detail` summarizing the bound coordinates. Projects losslessly onto the
486
+ * supervisor's `ChildStatus`.
487
+ * - `shutdown()` — closes every bound listener (best-effort, idempotent) in
488
+ * reverse bind order (HTTP then RPC).
489
+ *
490
+ * One subsystem instance is declared per scope, so registering the project and
491
+ * global gateways yields two supervised listeners → one external-facing gateway
492
+ * process surface per scope (AC1).
493
+ *
494
+ * @param opts - The scoped gateway configuration (handler + per-transport bind
495
+ * coordinates).
496
+ * @returns A frozen {@link Subsystem} ready to `register()` with a
497
+ * `SubsystemRegistry`.
498
+ * @throws {TypeError} When neither the RPC nor the HTTP transport is configured
499
+ * (a gateway with no hosted transport serves nothing).
500
+ *
501
+ * @example
502
+ * ```ts
503
+ * const registry = new SubsystemRegistry();
504
+ * registry.register(
505
+ * defineGatewaySubsystem({
506
+ * scope: 'project',
507
+ * handler: createGatewayHandler(dispatcherConfig),
508
+ * rpc: { socketPath: '/run/cleo/cleo-gateway-rpc-project.sock' },
509
+ * http: { port: 7777 },
510
+ * }),
511
+ * );
512
+ * await registry.startAll(); // binds the RPC socket + HTTP server
513
+ * const health = await registry.aggregateHealth();
514
+ * await registry.shutdownAll(); // closes both listeners
515
+ * ```
516
+ */
517
+ declare function defineGatewaySubsystem(opts: GatewaySubsystemOptions): Subsystem<GatewaySubsystemContext>;
518
+
519
+ /**
520
+ * Centralized engine error helper for the transport-agnostic gateway.
521
+ *
522
+ * Every domain handler (and the engine barrel) imports `engineError()` /
523
+ * `engineSuccess()` from this module to produce consistently typed error
524
+ * results with correct exit codes and pino logging.
525
+ *
526
+ * The STRING_TO_EXIT map is the canonical mapping from string error codes
527
+ * to numeric exit codes. It mirrors ERROR_CODE_TO_EXIT in cli.ts.
528
+ *
529
+ * @remarks
530
+ * Relocated from `packages/cleo/src/dispatch/engines/_error.ts` into
531
+ * `@cleocode/runtime/gateway` (R3-K1 · T11455 · SG-RUNTIME-UNIFICATION) so the
532
+ * runtime owns the shared handler dependencies and can assemble the handler map
533
+ * without importing `@cleocode/cleo`. A thin re-export shim remains at the old
534
+ * `engines/_error.ts` path so in-package import sites compile unchanged.
535
+ *
536
+ * Error codes are organized into numeric ranges:
537
+ * - 1-9: General errors (invalid input, file, dependency, validation)
538
+ * - 10-19: Hierarchy errors (parent, depth, siblings, circular deps)
539
+ * - 20-29: Concurrency errors (checksum, modification, collision)
540
+ * - 30-39: Session errors (scope, claims, active task)
541
+ * - 40-47: Verification errors (gates, agents, rounds)
542
+ * - 50-54: Context safeguard (warning through emergency)
543
+ * - 60-67: Orchestrator / protocol errors
544
+ * - 70-79: Nexus errors
545
+ * - 80-94: Lifecycle, artifact, provenance errors
546
+ * - 95-99: Adapter errors
547
+ * - 100+: Special informational codes (not errors)
548
+ */
549
+
550
+ /**
551
+ * Canonical mapping from string error codes to numeric exit codes.
552
+ *
553
+ * Source of truth: src/types/exit-codes.ts (ExitCode enum).
554
+ * Must stay in sync with ERROR_CODE_TO_EXIT in src/dispatch/adapters/cli.ts.
555
+ */
556
+ declare const STRING_TO_EXIT: Record<string, number>;
557
+ /**
558
+ * Create a typed engine error result with pino logging and correct exit code.
559
+ *
560
+ * @remarks
561
+ * The exit code is derived from the {@link STRING_TO_EXIT} mapping. If the
562
+ * code is not found in the map, exit code 1 (general error) is used.
563
+ * Pino logging is automatically triggered at the appropriate level
564
+ * (error for internal issues, warn for user/domain errors, debug for
565
+ * informational codes). Logging is suppressed under Vitest to keep
566
+ * test output clean.
567
+ *
568
+ * @param code - String error code (e.g., 'E_NOT_FOUND')
569
+ * @param message - Human-readable error message
570
+ * @param options - Optional details, fix command, and alternatives
571
+ * @returns EngineResult with success=false and properly structured error
572
+ *
573
+ * @example
574
+ * ```typescript
575
+ * import { engineError } from './_error.js';
576
+ *
577
+ * return engineError('E_NOT_FOUND', `Task ${id} not found`, {
578
+ * fix: `cleo show ${id}`,
579
+ * details: { taskId: id },
580
+ * });
581
+ * ```
582
+ */
583
+ declare function engineError<T>(code: string, message: string, options?: {
584
+ exitCode?: number;
585
+ details?: Record<string, unknown>;
586
+ fix?: string;
587
+ alternatives?: Array<{
588
+ action: string;
589
+ command: string;
590
+ }>;
591
+ problemDetails?: ProblemDetails;
592
+ }): EngineResult<T>;
593
+
594
+ /**
595
+ * Minimal meta shape carrying the request ID for RFC 7807 `instance` population.
596
+ *
597
+ * Callers may pass the dispatch-layer `DispatchRequest.requestId` (or any
598
+ * other correlation identifier) so that the resulting `problemDetails.instance`
599
+ * URI uniquely identifies the specific error occurrence.
600
+ */
601
+ interface ErrorMeta {
602
+ /** Unique request identifier (used as the RFC 7807 `instance` field). */
603
+ requestId?: string;
604
+ }
605
+ /**
606
+ * Convert any caught value into an {@link EngineResult}, forwarding the rich
607
+ * `fix`, `details`, and `alternatives` fields when the caught value is a
608
+ * `CleoError` (or structurally compatible object).
609
+ *
610
+ * @remarks
611
+ * This is the canonical catch-block helper for all dispatch engines. It
612
+ * replaces the previous pattern of:
613
+ * ```typescript
614
+ * const code = (err as { code?: number })?.code;
615
+ * if (code === 4) return engineError('E_NOT_FOUND', …);
616
+ * …
617
+ * ```
618
+ * with a single call that preserves every field the core layer attached.
619
+ *
620
+ * The `fallbackCode` is used when the numeric `err.code` is not present in
621
+ * the {@link STRING_TO_EXIT} mapping (e.g. unknown exit codes, plain `Error`
622
+ * instances, or values thrown by non-CLEO code).
623
+ *
624
+ * RFC 7807 `problemDetails` is always populated from the resolved code, message,
625
+ * and exit code. The optional `meta.requestId` is forwarded to the `instance`
626
+ * field so every error occurrence is uniquely identifiable.
627
+ *
628
+ * @param err - The caught value (unknown type)
629
+ * @param fallbackCode - String error code to use when mapping fails
630
+ * @param fallbackMessage - Human-readable message when `err.message` is absent
631
+ * @param meta - Optional dispatch meta carrying `requestId` for RFC 7807 `instance`
632
+ * @returns EngineResult with all available rich fields propagated
633
+ *
634
+ * @example
635
+ * ```typescript
636
+ * import { cleoErrorToEngineError } from './_error.js';
637
+ *
638
+ * } catch (err: unknown) {
639
+ * return cleoErrorToEngineError(err, 'E_NOT_INITIALIZED', 'Task database not initialized');
640
+ * }
641
+ * ```
642
+ *
643
+ * @example With requestId for RFC 7807 instance field:
644
+ * ```typescript
645
+ * } catch (err: unknown) {
646
+ * return cleoErrorToEngineError(err, 'E_NOT_FOUND', 'Not found', { requestId });
647
+ * }
648
+ * ```
649
+ */
650
+ declare function cleoErrorToEngineError<T>(err: unknown, fallbackCode: string, fallbackMessage: string, meta?: ErrorMeta): EngineResult<T>;
651
+
652
+ /**
653
+ * Parse all templates from the repo's .github/ISSUE_TEMPLATE/ directory.
654
+ *
655
+ * @remarks
656
+ * Delegates to the core template parser and adapts the result to the
657
+ * dispatch EngineResult type.
658
+ *
659
+ * @param projectRoot - Absolute path to the project root
660
+ * @returns EngineResult containing the parsed template configuration
661
+ *
662
+ * @example
663
+ * ```typescript
664
+ * const result = parseIssueTemplates('/path/to/project');
665
+ * if (result.success) {
666
+ * console.log(result.data.templates);
667
+ * }
668
+ * ```
669
+ */
670
+ declare function parseIssueTemplates(projectRoot: string): EngineResult<_cleocode_core_internal.TemplateConfig>;
671
+ /**
672
+ * Get template config for a specific subcommand (bug/feature/help).
673
+ *
674
+ * @remarks
675
+ * Looks up a specific template by subcommand name from the project's
676
+ * issue template directory.
677
+ *
678
+ * @param projectRoot - Absolute path to the project root
679
+ * @param subcommand - Template subcommand identifier (e.g. "bug", "feature")
680
+ * @returns EngineResult containing the matched issue template
681
+ *
682
+ * @example
683
+ * ```typescript
684
+ * const result = getTemplateForSubcommand('/path/to/project', 'bug');
685
+ * ```
686
+ */
687
+ declare function getTemplateForSubcommand(projectRoot: string, subcommand: string): EngineResult<_cleocode_core_internal.IssueTemplate>;
688
+ /**
689
+ * Generate and cache the config as .cleo/issue-templates.json.
690
+ *
691
+ * @remarks
692
+ * Parses all templates and writes the resulting config to disk for caching.
693
+ *
694
+ * @param projectRoot - Absolute path to the project root
695
+ * @returns EngineResult containing the generated template configuration
696
+ *
697
+ * @example
698
+ * ```typescript
699
+ * const result = await generateTemplateConfig('/path/to/project');
700
+ * ```
701
+ */
702
+ declare function generateTemplateConfig(projectRoot: string): Promise<EngineResult<_cleocode_core_internal.TemplateConfig>>;
703
+ /**
704
+ * Validate that labels exist on a GitHub repo.
705
+ *
706
+ * @remarks
707
+ * Compares a set of required labels against the labels found on the repo.
708
+ *
709
+ * @param labels - Labels required by the template
710
+ * @param repoLabels - Labels that exist on the GitHub repo
711
+ * @returns EngineResult with existing and missing label lists
712
+ *
713
+ * @example
714
+ * ```typescript
715
+ * const result = validateLabels(['bug', 'enhancement'], repoLabels);
716
+ * ```
717
+ */
718
+ declare function validateLabels(labels: string[], repoLabels: string[]): EngineResult<{
719
+ existing: string[];
720
+ missing: string[];
721
+ }>;
722
+
723
+ /**
724
+ * Shared exit-code mapping utilities for the transport-agnostic gateway.
725
+ *
726
+ * Provides a canonical reverse lookup from numeric exit code to string error code,
727
+ * shared between the gateway engine helpers and every transport adapter (CLI,
728
+ * MCP, RPC, HTTP).
729
+ *
730
+ * @remarks
731
+ * Relocated from `packages/cleo/src/dispatch/lib/exit-codes.ts` into
732
+ * `@cleocode/runtime/gateway` (R3-K1 · T11455 · SG-RUNTIME-UNIFICATION) so the
733
+ * runtime can host the shared handler dependencies without importing
734
+ * `@cleocode/cleo`. A thin re-export shim remains at the old path.
735
+ *
736
+ * The forward mapping (string → number) lives in `engine-error.ts` as
737
+ * `STRING_TO_EXIT`. This module derives the inverse on first call and memoises
738
+ * it so engines can resolve a caught `CleoError.code` (numeric) to the
739
+ * string code expected by `engineError()`.
740
+ *
741
+ * @task T374
742
+ * @task T11455
743
+ * @epic T335
744
+ */
745
+ /**
746
+ * Map a numeric CleoError exit code to the canonical string engine error code.
747
+ *
748
+ * @remarks
749
+ * Returns `undefined` when the numeric code is not present in the
750
+ * `STRING_TO_EXIT` map, allowing callers to fall back to their own default.
751
+ *
752
+ * @param numericCode - Numeric exit code from a caught `CleoError.code`
753
+ * @returns Canonical string error code (e.g. `'E_NOT_FOUND'`), or `undefined`
754
+ *
755
+ * @example
756
+ * ```typescript
757
+ * import { mapNumericExitCodeToString } from '../lib/exit-codes.js';
758
+ *
759
+ * const code = mapNumericExitCodeToString(4) ?? 'E_NOT_INITIALIZED';
760
+ * // → 'E_NOT_FOUND'
761
+ * ```
762
+ */
763
+ declare function mapNumericExitCodeToString(numericCode: number | undefined): string | undefined;
764
+
765
+ /**
766
+ * Wire + lifecycle types for the `@cleocode/runtime/gateway/http` adapter.
767
+ *
768
+ * The HTTP transport carries the SAME gateway payloads as every other transport
769
+ * — request/response shapes are owned by `@cleocode/contracts/gateway` (R3-T2 ·
770
+ * T11446) and the streaming frame by `GatewayStreamEvent`. This module holds
771
+ * only the runtime-adapter-local option/handle shapes (mirroring the MCP and RPC
772
+ * adapters' `types.ts`), so the runtime stays framework-agnostic and free of any
773
+ * `@cleocode/cleo` / SvelteKit / drizzle dependency.
774
+ *
775
+ * @task T11450
776
+ * @epic T11254
777
+ * @saga T11243
778
+ */
779
+
780
+ /**
781
+ * Where on the wire the `(gateway, domain, operation)` triple of an HTTP unary
782
+ * request is sourced from. The adapter is framework-agnostic, so the embedder
783
+ * (SvelteKit route, daemon HTTP server, test harness) supplies the resolved
784
+ * coordinates explicitly rather than the adapter parsing a URL itself.
785
+ */
786
+ interface HttpUnaryRequest {
787
+ /** CQRS gateway — `'mutate'` (write) or `'query'` (read). */
788
+ gateway: Gateway;
789
+ /** Target canonical domain (e.g. `'tasks'`). */
790
+ domain: string;
791
+ /** Domain operation name (e.g. `'show'`). */
792
+ operation: string;
793
+ /** Decoded JSON request body → operation params. */
794
+ params?: Record<string, unknown>;
795
+ /**
796
+ * Optional caller-supplied request id for tracing. When omitted the adapter
797
+ * mints a fresh UUID.
798
+ */
799
+ requestId?: string;
800
+ /** Bound session id, if any (forwarded into the dispatch request). */
801
+ sessionId?: string;
802
+ }
803
+ /**
804
+ * The result of routing one HTTP unary request through the gateway: the LAFS
805
+ * {@link DispatchResponse} JSON body plus the HTTP status the embedder should
806
+ * set (200 on success, 4xx/5xx mapped from the dispatch error).
807
+ *
808
+ * The adapter never writes the response itself (no framework coupling) — it
809
+ * returns this so the embedder serializes it onto its own `Response`.
810
+ */
811
+ interface HttpUnaryResult {
812
+ /** HTTP status code derived from the dispatch outcome. */
813
+ status: number;
814
+ /** The LAFS envelope to serialize as the JSON response body. */
815
+ body: DispatchResponse;
816
+ }
817
+
818
+ /**
819
+ * HTTP transport adapter — serves gateway unary + SSE over HTTP.
820
+ *
821
+ * The fourth and final gateway transport (after CLI, MCP, RPC). Unlike the
822
+ * connection-oriented RPC/MCP adapters, the HTTP adapter is framework-agnostic
823
+ * by design: it does NOT bind a port or own a `Request`/`Response` lifecycle.
824
+ * Instead it exposes two pure routing primitives the embedder (a SvelteKit
825
+ * route handler, the daemon's HTTP server, a test harness) calls directly:
826
+ *
827
+ * - {@link routeUnary} — one POST → `source: 'http'` {@link DispatchRequest}
828
+ * → injected {@link GatewayHandler} → `{ status, body }` (LAFS envelope).
829
+ * - the SSE primitives in `./sse.js` (`createSseStream`) for streaming ops.
830
+ *
831
+ * This keeps the runtime free of any HTTP-server / SvelteKit / `@cleocode/cleo`
832
+ * dependency: the embedder owns wire concerns (parsing the URL into a
833
+ * `(gateway, domain, operation)` triple, setting headers, `process.exit`,
834
+ * error-render at the edge), exactly mirroring how the CLI adapter wraps the
835
+ * same handler. There is NO `process.exit` and NO error-render in the handlers
836
+ * (R3 contract); the adapter never calls `process.exit` at all.
837
+ *
838
+ * The request `source` is forced to `'http'` regardless of what the embedder
839
+ * passes, so a client cannot impersonate another transport.
840
+ *
841
+ * @packageDocumentation
842
+ * @module @cleocode/runtime/gateway/http
843
+ *
844
+ * @task T11450
845
+ * @epic T11254
846
+ * @saga T11243
847
+ */
848
+
849
+ /**
850
+ * Map a LAFS dispatch error code to an HTTP status code.
851
+ *
852
+ * The canonical machine-readable error code (`E_NOT_FOUND`, `E_VALIDATION_…`,
853
+ * `E_FORBIDDEN`, …) is the source of truth; the numeric LAFS exit code is a
854
+ * secondary hint. Unknown error codes fall back to `500`. A successful envelope
855
+ * is always `200`.
856
+ *
857
+ * @param response - The dispatch response.
858
+ * @returns The HTTP status the embedder should set.
859
+ */
860
+ declare function statusForResponse(response: DispatchResponse): number;
861
+ /**
862
+ * Route a single HTTP unary request through the gateway handler.
863
+ *
864
+ * Builds a `source: 'http'` {@link DispatchRequest} from the embedder-resolved
865
+ * `(gateway, domain, operation, params)` triple and delegates to the injected
866
+ * {@link GatewayHandler}. A thrown handler error is trapped and rendered as a
867
+ * `500` LAFS error envelope — never propagated as an unhandled rejection or
868
+ * `process.exit`. The `source` is always forced to `'http'`.
869
+ *
870
+ * @param handler - The injected transport-neutral gateway handler.
871
+ * @param req - The embedder-resolved unary request coordinates + body params.
872
+ * @returns The HTTP status + LAFS response body for the embedder to serialize.
873
+ */
874
+ declare function routeUnary(handler: GatewayHandler, req: HttpUnaryRequest): Promise<HttpUnaryResult>;
875
+
876
+ /**
877
+ * Server-Sent Events (SSE) wire primitives for the `@cleocode/runtime/gateway/http`
878
+ * adapter.
879
+ *
880
+ * The HTTP transport is the only gateway transport that streams: long-running
881
+ * and subscription operations emit a sequence of {@link GatewayStreamEvent}
882
+ * frames terminated by a `done` or `error` frame. This module owns ONLY the SSE
883
+ * wire encoding + the `ReadableStream` lifecycle plumbing; the actual frame
884
+ * production (polling a DB, tailing a job, etc.) lives in the caller's async
885
+ * source. Keeping the encode/stream concern here lets BOTH the gateway-routed
886
+ * streaming ops AND the existing Studio SSE endpoints (which carry their own
887
+ * domain event shapes) share one tested, leak-free stream builder.
888
+ *
889
+ * Two encoders are provided so an existing stream can adopt this plumbing
890
+ * WITHOUT changing its observed bytes:
891
+ * - {@link encodeStreamEvent} — the canonical `data: <json>\n\n` form for
892
+ * {@link GatewayStreamEvent} frames (gateway-routed streaming ops).
893
+ * - {@link encodeSseFrame} — a generic `event:`/`id:`/`data:` writer for any
894
+ * payload, so endpoints with a bespoke wire (a named `event:` field, a
895
+ * `data:`-only frame) keep an IDENTICAL byte stream while still routing their
896
+ * lifecycle through the shared, abort-safe builder.
897
+ *
898
+ * @packageDocumentation
899
+ * @module @cleocode/runtime/gateway/http/sse
900
+ *
901
+ * @task T11450
902
+ * @epic T11254
903
+ * @saga T11243
904
+ */
905
+
906
+ /**
907
+ * One generic SSE frame: an optional named `event`, an optional `id`, and a
908
+ * `data` payload that is JSON-serialized.
909
+ *
910
+ * This is intentionally NOT {@link GatewayStreamEvent} — it is the raw wire
911
+ * shape so a bespoke endpoint can reproduce its exact existing bytes (e.g. a
912
+ * named `event: task-updated` line, or a `data:`-only frame with no `event`).
913
+ */
914
+ interface SseFrame {
915
+ /** Optional SSE `event:` field name (omitted → a `data:`-only frame). */
916
+ event?: string;
917
+ /** Optional SSE `id:` field for client-side last-event-id resumption. */
918
+ id?: string;
919
+ /** The frame payload; JSON-serialized into the `data:` field. */
920
+ data: unknown;
921
+ }
922
+ /**
923
+ * Encode a generic {@link SseFrame} to its SSE wire bytes.
924
+ *
925
+ * Field order is `event:` (if present) → `id:` (if present) → `data:`, matching
926
+ * the SSE spec record layout, then a blank line. When `event` is omitted the
927
+ * frame is a `data:`-only record — byte-identical to a handwritten
928
+ * `data: <json>\n\n`.
929
+ *
930
+ * @param frame - The frame to serialize.
931
+ * @returns The SSE record as a string (UTF-8 caller-encoded).
932
+ */
933
+ declare function encodeSseFrame(frame: SseFrame): string;
934
+ /**
935
+ * Encode a canonical {@link GatewayStreamEvent} as a `data:`-only SSE record.
936
+ *
937
+ * Gateway-routed streaming ops carry the discriminator + sequence inside the
938
+ * JSON payload (`{ kind, seq, data, error, requestId }`), so no named SSE
939
+ * `event:` field is used — the client demultiplexes on `kind`/`seq`. The
940
+ * monotonic `seq` is also surfaced as the SSE `id:` so a reconnecting client can
941
+ * send `Last-Event-ID`.
942
+ *
943
+ * @param frame - The gateway stream event to serialize.
944
+ * @returns The SSE record as a string.
945
+ */
946
+ declare function encodeStreamEvent(frame: GatewayStreamEvent): string;
947
+ /** The standard SSE response headers (no caching, no proxy buffering). */
948
+ declare const SSE_HEADERS: Readonly<Record<string, string>>;
949
+ /**
950
+ * A push-style SSE controller handed to an {@link SseSource} so it can emit
951
+ * frames and close the stream without touching the underlying
952
+ * `ReadableStreamDefaultController`.
953
+ */
954
+ interface SseEmitter {
955
+ /** Emit one generic SSE frame; a no-op once the stream is closed. */
956
+ send(frame: SseFrame): void;
957
+ /** Emit one canonical {@link GatewayStreamEvent}; a no-op once closed. */
958
+ sendStreamEvent(frame: GatewayStreamEvent): void;
959
+ /**
960
+ * Emit a pre-encoded SSE record verbatim; a no-op once closed. For endpoints
961
+ * that own their own wire encoder (e.g. a bespoke `data: <json>\n\n`) and want
962
+ * to keep emitting byte-identical records while still routing lifecycle
963
+ * through this builder.
964
+ */
965
+ sendRaw(record: string): void;
966
+ /** Whether the stream has been closed (client disconnect or `close()`). */
967
+ readonly closed: boolean;
968
+ /** Close the stream; idempotent. */
969
+ close(): void;
970
+ }
971
+ /**
972
+ * A teardown callback returned by an {@link SseSource}, invoked exactly once when
973
+ * the stream ends (client disconnect, `emitter.close()`, or producer completion).
974
+ */
975
+ type SseTeardown = () => void;
976
+ /**
977
+ * A frame source for {@link createSseStream}. Receives an {@link SseEmitter} and
978
+ * MAY return an {@link SseTeardown} callback (return nothing to skip teardown).
979
+ *
980
+ * The source is started SYNCHRONOUSLY inside `ReadableStream.start`, mirroring
981
+ * the existing Studio endpoints (which schedule timers inside `start`). A source
982
+ * may push frames immediately and/or schedule async work.
983
+ */
984
+ type SseSource = (emitter: SseEmitter) => SseTeardown | undefined;
985
+ /**
986
+ * Build a `text/event-stream` {@link ReadableStream} driven by an
987
+ * {@link SseSource}.
988
+ *
989
+ * This is the shared, abort-safe stream builder every SSE endpoint routes
990
+ * through. It guarantees:
991
+ * - frames are dropped (never throw) after the stream closes;
992
+ * - the source's teardown callback runs exactly once;
993
+ * - an optional {@link AbortSignal} (the request's) closes the stream on client
994
+ * disconnect, with its listener removed on teardown.
995
+ *
996
+ * The byte output is fully controlled by what the source emits — so an endpoint
997
+ * adopting this builder reproduces its prior wire exactly by emitting the same
998
+ * frames in the same order.
999
+ *
1000
+ * @param source - The frame producer.
1001
+ * @param signal - Optional request abort signal that closes the stream on
1002
+ * client disconnect.
1003
+ * @returns A ReadableStream of UTF-8 SSE bytes for a `Response` body.
1004
+ */
1005
+ declare function createSseStream(source: SseSource, signal?: AbortSignal): ReadableStream<Uint8Array>;
1006
+
1007
+ /**
1008
+ * Singleton accessor for the gateway {@link BackgroundJobManager}.
1009
+ *
1010
+ * @remarks
1011
+ * Relocated from `packages/cleo/src/dispatch/lib/job-manager-accessor.ts` into
1012
+ * `@cleocode/runtime/gateway` (R3-K1 · T11455 · SG-RUNTIME-UNIFICATION) so the
1013
+ * `admin` domain handler resolves the job-manager singleton from the runtime
1014
+ * layer rather than a cleo-internal path. A thin re-export shim remains at the
1015
+ * old path so any existing import site compiles unchanged.
1016
+ *
1017
+ * Long-lived hosts (e.g. the daemon) call {@link setJobManager} once at startup;
1018
+ * short-lived CLI invocations leave the singleton `null`, and consumers handle
1019
+ * the absence gracefully.
1020
+ *
1021
+ * @task T4820
1022
+ * @task T11455
1023
+ */
1024
+
1025
+ /**
1026
+ * Register the process-wide {@link BackgroundJobManager} singleton.
1027
+ *
1028
+ * @param manager - The manager instance to expose to gateway consumers.
1029
+ */
1030
+ declare function setJobManager(manager: BackgroundJobManager): void;
1031
+ /**
1032
+ * Retrieve the registered {@link BackgroundJobManager} singleton.
1033
+ *
1034
+ * @returns The registered manager, or `null` when running in a short-lived
1035
+ * host (e.g. a one-shot CLI invocation) that never called {@link setJobManager}.
1036
+ */
1037
+ declare function getJobManager(): BackgroundJobManager | null;
1038
+
1039
+ /**
1040
+ * MCP wire types for the `@cleocode/runtime/gateway/mcp` transport adapter.
1041
+ *
1042
+ * A deliberately-minimal subset of the Model Context Protocol shapes the
1043
+ * adapter needs — no external MCP SDK dependency. Mirrors the legacy
1044
+ * `@cleocode/mcp-adapter` `types.ts` so the wire surface is unchanged.
1045
+ *
1046
+ * @task T11448
1047
+ * @epic T11254
1048
+ * @saga T11243
1049
+ */
1050
+ /** JSON Schema property descriptor surfaced for a single tool input field. */
1051
+ interface McpInputProperty {
1052
+ /** JSON Schema primitive type (`'string'`, `'number'`, …). */
1053
+ type: string;
1054
+ /** Human-readable description shown in MCP clients. */
1055
+ description: string;
1056
+ /** Allowed values (JSON Schema `enum`) for finite-domain string params. */
1057
+ enum?: readonly string[];
1058
+ }
1059
+ /**
1060
+ * MCP tool definition shape (minimal — no external MCP SDK dependency).
1061
+ * Structurally compatible with the legacy `@cleocode/mcp-adapter` `McpTool`.
1062
+ */
1063
+ interface McpTool {
1064
+ /** Stable tool name (snake_case, e.g. `cleo_sentient_status`). */
1065
+ name: string;
1066
+ /** Human-readable description shown in MCP clients. */
1067
+ description: string;
1068
+ /** JSON Schema for the tool's input parameters. */
1069
+ inputSchema: {
1070
+ type: 'object';
1071
+ properties: Record<string, McpInputProperty>;
1072
+ required?: string[];
1073
+ };
1074
+ }
1075
+ /** A single content block returned by a tool handler. */
1076
+ interface McpContent {
1077
+ type: 'text';
1078
+ text: string;
1079
+ }
1080
+ /** Result returned by a tool handler over the MCP wire. */
1081
+ interface McpToolResult {
1082
+ content: McpContent[];
1083
+ isError?: boolean;
1084
+ }
1085
+
1086
+ /**
1087
+ * MCP stdio transport adapter — routes `tools/call` through the gateway.
1088
+ *
1089
+ * Serves the Model Context Protocol over stdio (newline-delimited JSON-RPC 2.0)
1090
+ * so any MCP-compatible client (Claude Code, LLM-agnostic tools) can discover
1091
+ * and invoke CLEO operations. Unlike the legacy standalone `@cleocode/mcp-adapter`
1092
+ * — which called the `@cleocode/core` SDK directly — this adapter is a thin
1093
+ * TRANSPORT over the unified gateway:
1094
+ *
1095
+ * MCP `tools/call` { name, arguments }
1096
+ * → {@link GatewayOperationKey} (via the `mcpExposed` registry subset)
1097
+ * → DispatchRequest { source: 'mcp', gateway, domain, operation, params }
1098
+ * → injected {@link GatewayHandler}.handle()
1099
+ * → DispatchResponse (LAFS envelope) → MCP tool result (JSON text content)
1100
+ *
1101
+ * The adapter owns ONLY wire concerns: JSON-RPC framing, the stdio read loop,
1102
+ * `tools/list` generation, error rendering, and `process.exit` on stream close.
1103
+ * All domain logic (resolution, validation, middleware, handler execution) lives
1104
+ * behind the {@link GatewayHandler} — exactly mirroring how the CLI adapter
1105
+ * wraps the same handler. `process.exit` and error-render stay HERE, never in
1106
+ * the handlers (R3-T4 contract).
1107
+ *
1108
+ * `tools/list` is generated from the OPERATIONS registry behind the default-deny
1109
+ * `mcpExposed` flag, so the external tool surface is identical to the historical
1110
+ * standalone adapter (no behavior change).
1111
+ *
1112
+ * @task T11448
1113
+ * @epic T11254
1114
+ * @saga T11243
1115
+ */
1116
+
1117
+ /**
1118
+ * Route a single MCP `tools/call` through the gateway handler.
1119
+ *
1120
+ * Resolves the tool name to a `(domain, operation)` key against the exposed
1121
+ * (`mcpExposed`) registry subset, builds a `source: 'mcp'` {@link DispatchRequest},
1122
+ * and delegates to the injected {@link GatewayHandler}. Unknown tool names and
1123
+ * thrown handler errors are rendered as MCP error results — never propagated as
1124
+ * `process.exit` from this layer.
1125
+ *
1126
+ * @param handler - The injected transport-neutral gateway handler.
1127
+ * @param toolName - The MCP `tools/call` tool name.
1128
+ * @param args - The parsed tool arguments (already JSON-decoded by the client).
1129
+ * @returns An MCP {@link McpToolResult}.
1130
+ */
1131
+ declare function callTool(handler: GatewayHandler, toolName: string, args: Record<string, unknown>): Promise<McpToolResult>;
1132
+ /**
1133
+ * Options for {@link startMcpServer}.
1134
+ */
1135
+ interface McpServerOptions {
1136
+ /** Inbound stream (defaults to `process.stdin`). */
1137
+ input?: NodeJS.ReadableStream;
1138
+ /** Outbound stream (defaults to `process.stdout`). */
1139
+ output?: NodeJS.WritableStream;
1140
+ /**
1141
+ * Whether to call `process.exit(0)` when the input stream closes.
1142
+ * Defaults to `true` (production stdio). Tests pass `false`.
1143
+ */
1144
+ exitOnClose?: boolean;
1145
+ }
1146
+ /**
1147
+ * Start the MCP stdio server over the gateway.
1148
+ *
1149
+ * Reads newline-delimited JSON-RPC 2.0 requests from the input stream, routes
1150
+ * `tools/call` through the injected {@link GatewayHandler}, and writes responses
1151
+ * to the output stream. Each inbound line must be one complete JSON-RPC request.
1152
+ *
1153
+ * The caller assembles the {@link GatewayHandler} (via `createGatewayHandler`
1154
+ * with its domain handlers + middleware) and injects it here — this adapter
1155
+ * never builds handlers itself, keeping the runtime free of any
1156
+ * `@cleocode/cleo` dependency.
1157
+ *
1158
+ * @param handler - The transport-neutral gateway handler to route through.
1159
+ * @param opts - Optional stream + lifecycle overrides (defaults to stdio).
1160
+ */
1161
+ declare function startMcpServer(handler: GatewayHandler, opts?: McpServerOptions): void;
1162
+
1163
+ /**
1164
+ * MCP tool-name <-> gateway-operation mapping.
1165
+ *
1166
+ * The MCP wire protocol identifies a tool by a single flat `name` string
1167
+ * (snake_case, e.g. `cleo_sentient_propose_list`), whereas the gateway routes
1168
+ * on a `(gateway, domain, operation)` triple (e.g.
1169
+ * `query / sentient / propose.list`). This module is the bijective bridge
1170
+ * between the two surfaces:
1171
+ *
1172
+ * gateway op → MCP tool name {@link operationToToolName}
1173
+ * MCP tool name → domain+operation {@link toolNameToOperationKey}
1174
+ *
1175
+ * ## Naming convention (frozen — matches the legacy `@cleocode/mcp-adapter`)
1176
+ *
1177
+ * `cleo_<domain>_<operation>` where every `.` and `-` in the dotted operation
1178
+ * name becomes `_`. The three historically-exposed tools therefore map as:
1179
+ *
1180
+ * | gateway op | MCP tool name |
1181
+ * |-----------------------------|--------------------------------|
1182
+ * | `sentient` · `status` | `cleo_sentient_status` |
1183
+ * | `sentient` · `propose.list` | `cleo_sentient_propose_list` |
1184
+ * | `sentient` · `propose.enable` | `cleo_sentient_propose_enable` |
1185
+ *
1186
+ * Preserving this exact mapping is what guarantees R3-T4's "no behavior change
1187
+ * to the MCP tool surface" acceptance criterion.
1188
+ *
1189
+ * @task T11448
1190
+ * @epic T11254
1191
+ * @saga T11243
1192
+ */
1193
+
1194
+ /** Prefix every CLEO MCP tool name carries. */
1195
+ declare const MCP_TOOL_PREFIX = "cleo_";
1196
+ /**
1197
+ * Identifies a gateway operation by its `(domain, operation)` pair. The CQRS
1198
+ * gateway resolves which `Gateway` ('query' | 'mutate') the pair belongs to via
1199
+ * the operation registry, so the MCP adapter does not need to carry it.
1200
+ */
1201
+ interface GatewayOperationKey {
1202
+ /** Canonical domain (e.g. `'sentient'`). */
1203
+ readonly domain: string;
1204
+ /** Dotted operation name (e.g. `'propose.list'`). */
1205
+ readonly operation: string;
1206
+ }
1207
+ /**
1208
+ * Derive the flat MCP tool name for a gateway operation.
1209
+ *
1210
+ * @param op - An {@link OperationDef} (or any object carrying `domain` +
1211
+ * `operation`) from the registry.
1212
+ * @returns The MCP tool name, e.g. `'cleo_sentient_propose_list'`.
1213
+ */
1214
+ declare function operationToToolName(op: Pick<OperationDef, 'domain' | 'operation'>): string;
1215
+ /**
1216
+ * Resolve an MCP tool name back to its `(domain, operation)` gateway key.
1217
+ *
1218
+ * The reverse of {@link operationToToolName} cannot recover dots vs dashes from
1219
+ * the snake_case wire form, so resolution is performed against the provided
1220
+ * `exposed` set (the same `mcpExposed: true` subset used to build `tools/list`).
1221
+ * This keeps the mapping exact and rejects unknown tool names.
1222
+ *
1223
+ * @param toolName - The MCP `tools/call` tool name.
1224
+ * @param exposed - The exposed operation defs (the `mcpExposed` subset).
1225
+ * @returns The matching {@link GatewayOperationKey}, or `undefined` when the
1226
+ * tool name does not correspond to any exposed operation.
1227
+ */
1228
+ declare function toolNameToOperationKey(toolName: string, exposed: readonly OperationDef[]): GatewayOperationKey | undefined;
1229
+
1230
+ /**
1231
+ * MCP `tools/list` generation from the OPERATIONS registry.
1232
+ *
1233
+ * The MCP tool surface is **default-deny**: only {@link OperationDef} entries
1234
+ * that explicitly set `mcpExposed: true` are surfaced. This replaces the legacy
1235
+ * `@cleocode/mcp-adapter`'s hand-maintained `ALL_TOOLS` array with a single
1236
+ * generation point driven by the canonical registry — promoting a new tool is
1237
+ * now one `mcpExposed: true` edit in `@cleocode/contracts`, not a fork-and-copy
1238
+ * into a standalone adapter.
1239
+ *
1240
+ * @task T11448
1241
+ * @epic T11254
1242
+ * @saga T11243
1243
+ */
1244
+
1245
+ /**
1246
+ * The subset of OPERATIONS surfaced over MCP (default-deny `mcpExposed` filter).
1247
+ *
1248
+ * @returns Every {@link OperationDef} with `mcpExposed === true`, in registry
1249
+ * order. Empty when no operation opts in.
1250
+ */
1251
+ declare function exposedOperations(): OperationDef[];
1252
+ /**
1253
+ * Convert a single exposed {@link OperationDef} into its MCP tool definition.
1254
+ *
1255
+ * @param op - An operation with `mcpExposed === true`.
1256
+ * @returns The MCP {@link McpTool} (name + description + inputSchema).
1257
+ */
1258
+ declare function operationToMcpTool(op: OperationDef): McpTool;
1259
+ /**
1260
+ * Generate the full MCP `tools/list` payload from the registry.
1261
+ *
1262
+ * @returns Every exposed operation rendered as an {@link McpTool}, in registry
1263
+ * order (stable across calls).
1264
+ */
1265
+ declare function buildToolsList(): McpTool[];
1266
+
1267
+ /**
1268
+ * Dispatch-local metadata factory.
1269
+ *
1270
+ * Generates LAFS-conformant metadata for dispatch layer responses.
1271
+ * Generates LAFS-conformant metadata for dispatch responses.
1272
+ *
1273
+ * @task T4772
1274
+ */
1275
+
1276
+ /**
1277
+ * Create metadata for a dispatch response.
1278
+ *
1279
+ * @param gateway - Gateway name (e.g., 'query', 'mutate')
1280
+ * @param domain - Domain name (e.g., 'tasks', 'session')
1281
+ * @param operation - Operation name (e.g., 'show', 'list')
1282
+ * @param startTime - Timestamp from Date.now() at start of request
1283
+ * @param source - Where the request originated
1284
+ * @param requestId - Optional pre-generated request ID
1285
+ * @param sessionId - Optional session ID to include in metadata
1286
+ * @param originSessionId - Optional root workflow/saga session ID
1287
+ * @param executionSessionId - Optional execution-attempt session ID
1288
+ * @returns Metadata conforming to DispatchResponse['meta']
1289
+ *
1290
+ * @task T4772
1291
+ * @task T4959
1292
+ */
1293
+ declare function createDispatchMeta(gateway: string, domain: string, operation: string, startTime: number, source?: Source, requestId?: string, sessionId?: string | null, originSessionId?: string | null, executionSessionId?: string | null): DispatchResponse['meta'];
1294
+
1295
+ /**
1296
+ * nexus-decorator — stamps `meta._nexus` on every nexus-domain dispatch response.
1297
+ *
1298
+ * Wave 2 of the Nexus Restructure (T9146). Reads `getNexusDescriptor(opId)` from
1299
+ * the W1 SSoT (`NEXUS_SCOPE_MAP`) and injects the namespaced `_nexus` block into
1300
+ * `DispatchResponse['meta']`.
1301
+ *
1302
+ * Usage:
1303
+ * ```ts
1304
+ * const decorated = stampNexusMeta(response, operation, params);
1305
+ * ```
1306
+ *
1307
+ * The `suggestedNext` field uses a structured form (not literal display strings).
1308
+ * Display strings are derived by `formatSuggestedNext()` for human/markdown renderers.
1309
+ *
1310
+ * Typed-registry gate: `validateSuggestedNext()` fails the build (throws at import-time
1311
+ * in test mode) if any `suggestedNext.op` is absent from `NEXUS_SCOPE_MAP`.
1312
+ *
1313
+ * @remarks
1314
+ * Relocated from `packages/cleo/src/dispatch/nexus-decorator.ts` into
1315
+ * `@cleocode/runtime/gateway` (R3-K1 · T11455 · SG-RUNTIME-UNIFICATION) so the
1316
+ * nexus domain handler can import it from the runtime layer rather than a
1317
+ * cleo-internal path. The module is pure (`@cleocode/contracts` only). A thin
1318
+ * re-export shim remains at the old path for the renderer / CLI import sites.
1319
+ *
1320
+ * @task T9146
1321
+ * @task T11455
1322
+ * @module runtime/gateway/nexus-decorator
1323
+ */
1324
+
1325
+ /**
1326
+ * Assert that every `suggestedNext.op` in a list resolves to a known
1327
+ * NEXUS_SCOPE_MAP entry.
1328
+ *
1329
+ * Throws `TypeError` at runtime (caught by tests and CI) if an unknown op
1330
+ * is referenced — acting as a build-time gate when imported in test suites.
1331
+ *
1332
+ * @throws {TypeError} if any `op` is absent from `NEXUS_SCOPE_MAP`
1333
+ * @task T9146
1334
+ */
1335
+ declare function validateSuggestedNext(suggestions: ReadonlyArray<SuggestedNextOp>): void;
1336
+ /**
1337
+ * Derive a human-readable display string from a {@link SuggestedNextOp}.
1338
+ *
1339
+ * Example: `"cleo nexus context --project-id myproj (read-only, no confirmation needed)"`
1340
+ */
1341
+ declare function formatSuggestedNext(s: SuggestedNextOp): string;
1342
+ /**
1343
+ * Stamp `meta._nexus` onto a nexus-domain {@link DispatchResponse}.
1344
+ *
1345
+ * Call this after every nexus handler produces its `DispatchResponse`. The
1346
+ * function is a pure transformer — it returns a new object with `meta._nexus`
1347
+ * merged in.
1348
+ *
1349
+ * @param response - The original dispatch response from the nexus handler.
1350
+ * @param operation - The nexus operation key (must be a `keyof NexusOps`).
1351
+ * @param params - Raw params passed to the handler (used for binding-source resolution).
1352
+ * @param isTopLevel - Whether this is a top-level CLI invocation (not a sub-call).
1353
+ * @returns A new `DispatchResponse` with `meta._nexus` populated.
1354
+ *
1355
+ * @task T9146
1356
+ */
1357
+ declare function stampNexusMeta(response: DispatchResponse, operation: string, params: Record<string, unknown>, isTopLevel?: boolean): DispatchResponse;
1358
+ /**
1359
+ * Pick the decorator-stamped fields (`_nexus`, `deprecated`) from a dispatch
1360
+ * response's `meta` so they can be forwarded via `cliOutput`'s `extensions`
1361
+ * option into the emitted LAFS envelope.
1362
+ *
1363
+ * Without this, `cliOutput(response.data, ...)` discards `response.meta._nexus`
1364
+ * + `response.meta.deprecated` (T9393 defect). Canonical CLI meta fields
1365
+ * (`operation`, `requestId`, `timestamp`) are intentionally NOT forwarded —
1366
+ * those are produced by {@link createCliMeta} on the CLI side.
1367
+ *
1368
+ * @task T9393
1369
+ */
1370
+ declare function pickDecoratorMetaExtensions(responseMeta: DispatchResponseMeta | undefined): Record<string, unknown>;
1371
+ /**
1372
+ * Build CLI envelope extensions for nexus commands that bypass the dispatcher
1373
+ * (e.g. `cleo nexus status` SSoT-EXEMPT path). Runs the same {@link stampNexusMeta}
1374
+ * logic against a synthetic response so the resulting envelope still carries
1375
+ * `meta._nexus` (and `meta.deprecated` for alias shims).
1376
+ *
1377
+ * Use this only where the command does NOT call `dispatchRaw`. When you have a
1378
+ * real dispatch response, use {@link pickDecoratorMetaExtensions} on
1379
+ * `response.meta` instead — that path already ran the decorator.
1380
+ *
1381
+ * @task T9393
1382
+ */
1383
+ declare function buildNexusMetaExtensions(operation: string, params?: Record<string, unknown>): Record<string, unknown>;
1384
+
1385
+ /**
1386
+ * Gateway-level path constants shared by domain handlers.
1387
+ *
1388
+ * @remarks
1389
+ * The `orchestrate` and `admin` (smoke-provider) domain handlers join a handful
1390
+ * of well-known `.cleo/` path segments when locating workflow definitions and
1391
+ * the BRAIN database. Those constants were previously defined in
1392
+ * `packages/cleo/src/cli/paths.ts` (a CLI-internal leaf), which coupled the
1393
+ * handler subgraph to `@cleocode/cleo`.
1394
+ *
1395
+ * To let `@cleocode/runtime` assemble the handler map WITHOUT importing
1396
+ * `@cleocode/cleo` (R3-K1 · T11455 · SG-RUNTIME-UNIFICATION), the constants the
1397
+ * handlers actually consume are hosted here as the canonical source. The
1398
+ * CLI-side `cli/paths.ts` re-exports them so the rest of the CLI (backup /
1399
+ * restore / doctor) keeps importing from its established surface — there is a
1400
+ * single definition, no drift.
1401
+ *
1402
+ * @task T090
1403
+ * @task T11455
1404
+ */
1405
+ /** Name of the project-local CLEO data directory (`.cleo`). */
1406
+ declare const CLEO_DIR_NAME: ".cleo";
1407
+ /** Subdirectory under `.cleo/` that stores CANT workflow definitions. */
1408
+ declare const WORKFLOWS_SUBDIR: "workflows";
1409
+ /** Project-local SQLite database filename for cognitive memory (BRAIN). */
1410
+ declare const BRAIN_DB_FILENAME: "brain.db";
1411
+
1412
+ /**
1413
+ * Unified CQRS Dispatch Layer -- Middleware Pipeline
1414
+ *
1415
+ * Provides compose() to chain multiple Middleware functions together
1416
+ * into a single executable pipeline.
1417
+ *
1418
+ * @epic T4820
1419
+ * @task T4815
1420
+ */
1421
+
1422
+ /**
1423
+ * Composes an array of Middleware functions into a single Middleware function.
1424
+ * Execution flows through the array from first to last, and returns bubble
1425
+ * back up from last to first.
1426
+ *
1427
+ * @remarks
1428
+ * Uses an index-tracked dispatch function to prevent `next()` from being
1429
+ * called multiple times within a single middleware. If the array is empty,
1430
+ * a passthrough middleware that immediately calls `next()` is returned.
1431
+ *
1432
+ * @param middlewares - Array of middleware functions to chain
1433
+ * @returns A single composed Middleware function
1434
+ *
1435
+ * @example
1436
+ * ```typescript
1437
+ * import { compose } from './pipeline.js';
1438
+ *
1439
+ * const pipeline = compose([sanitizer, rateLimiter, protocolEnforcement]);
1440
+ * const response = await pipeline(request, handler);
1441
+ * ```
1442
+ */
1443
+ declare function compose(middlewares: Middleware[]): Middleware;
1444
+
1445
+ /**
1446
+ * Unified CQRS Dispatch Layer -- Operation Registry (shim)
1447
+ *
1448
+ * The `OPERATIONS` data array was relocated to
1449
+ * `@cleocode/contracts/dispatch/operations-registry` in T10061 / T9833b
1450
+ * (E-CLI-BOUNDARY · Saga T9831 SG-ARCH-SOLID). This file is now a thin
1451
+ * re-export shim that:
1452
+ *
1453
+ * 1. Re-exports `OPERATIONS` from contracts so every downstream consumer
1454
+ * that already imports `{ OPERATIONS }` from this path continues to
1455
+ * compile unchanged.
1456
+ * 2. Keeps the pure utility / derivation functions (`resolve`,
1457
+ * `validateRequiredParams`, `getByDomain`, etc.) that operate on
1458
+ * the data and are rightly colocated with the CLI package.
1459
+ *
1460
+ * @epic T4820
1461
+ * @task T4814, T5241, T5615, T10061
1462
+ */
1463
+
1464
+ /** The single source of truth for all operations in CLEO (data lives in @cleocode/contracts). */
1465
+ declare const OPERATIONS: OperationDef[];
1466
+ /**
1467
+ * Derive a gateway operation matrix from the registry.
1468
+ *
1469
+ * Returns `Record<string, string[]>` containing:
1470
+ * - All canonical domains with their operations
1471
+ *
1472
+ * This is the SINGLE derivation point — gateways use this instead of
1473
+ * maintaining independent operation lists.
1474
+ */
1475
+ declare function deriveGatewayMatrix(gateway: Gateway): Record<string, string[]>;
1476
+ /**
1477
+ * Get all accepted domain names for a gateway (canonical only).
1478
+ */
1479
+ declare function getGatewayDomains(gateway: Gateway): string[];
1480
+ /**
1481
+ * Resolves a domain + operation to its registered definition.
1482
+ */
1483
+ declare function resolve(gateway: Gateway, domain: string, operation: string): Resolution | undefined;
1484
+ /**
1485
+ * Validates that all required parameters are present in the request.
1486
+ * Returns an array of missing parameter keys.
1487
+ */
1488
+ declare function validateRequiredParams(def: OperationDef, params?: Record<string, unknown>): string[];
1489
+ /** Get all operations for a specific canonical domain. */
1490
+ declare function getByDomain(domain: CanonicalDomain): OperationDef[];
1491
+ /** Get all operations for a specific gateway. */
1492
+ declare function getByGateway(gateway: Gateway): OperationDef[];
1493
+ /** Get all operations available at or below a specific tier. */
1494
+ declare function getByTier(tier: Tier): OperationDef[];
1495
+ /** Get a list of canonical domains that actually have operations registered. */
1496
+ declare function getActiveDomains(): CanonicalDomain[];
1497
+ /**
1498
+ * Returns summary counts of operations for module validation.
1499
+ */
1500
+ declare function getCounts(): {
1501
+ query: number;
1502
+ mutate: number;
1503
+ total: number;
1504
+ };
1505
+
1506
+ /**
1507
+ * `@cleocode/runtime/gateway` — the transport-agnostic CQRS dispatch core.
1508
+ *
1509
+ * Relocated from `packages/cleo/src/dispatch` (R3-T3 · T11447 ·
1510
+ * SG-RUNTIME-UNIFICATION) so the dispatcher is owned by the runtime layer and
1511
+ * can be driven by ANY transport adapter — CLI, MCP, RPC, HTTP — not just the
1512
+ * CLI. Mirrors the `@cleocode/runtime/daemon` subpath (R2).
1513
+ *
1514
+ * The CLI adapter (`packages/cleo/src/dispatch/adapters/cli.ts`) and the
1515
+ * domain handlers + transport-specific middleware stay in `packages/cleo`; they
1516
+ * are INJECTED into the {@link Dispatcher} via {@link DispatcherConfig}. The
1517
+ * gateway contract itself lives in `@cleocode/contracts/gateway` (R3-T2).
1518
+ *
1519
+ * `packages/cleo/src/dispatch/{dispatcher,registry,lib/meta,middleware/pipeline}.ts`
1520
+ * remain as thin re-export shims pointing here, so the in-package import sites
1521
+ * (cli adapter, ~18 registry consumers, getCliDispatcher) compile unchanged.
1522
+ *
1523
+ * @epic T4820
1524
+ * @task T11447
1525
+ * @saga T11243
1526
+ */
1527
+
1528
+ /**
1529
+ * Transport-agnostic gateway entrypoint. Wraps a configured {@link Dispatcher}
1530
+ * (`compose(middlewares) → DomainHandler`) behind a single `handle()` call that
1531
+ * every transport adapter (CLI/MCP/RPC/HTTP) invokes uniformly. The adapter
1532
+ * owns wire concerns (error-render, `process.exit`, serialization); the handler
1533
+ * only resolves, validates, runs middleware, and returns a {@link DispatchResponse}.
1534
+ */
1535
+ interface GatewayHandler {
1536
+ /** Route one gateway request through the dispatch pipeline. */
1537
+ handle(req: DispatchRequest): Promise<DispatchResponse>;
1538
+ }
1539
+ /**
1540
+ * Build a {@link GatewayHandler} from a {@link DispatcherConfig} (injected
1541
+ * domain handlers + middleware). The returned handler is transport-neutral.
1542
+ */
1543
+ declare function createGatewayHandler(config: DispatcherConfig): GatewayHandler;
1544
+
1545
+ export { getByDomain as $, type GatewayHandler as A, BRAIN_DB_FILENAME as B, CLEO_DIR_NAME as C, Dispatcher as D, type DecodeResult, type ErrorMeta as E, type GatewayScope as F, type GatewayOperationKey as G, type HttpServerHandle as H, type GatewaySubsystemContext as I, type GatewaySubsystemOptions as J, STRING_TO_EXIT as K, buildNexusMetaExtensions as L, LineBuffer, MCP_TOOL_PREFIX as M, cleoErrorToEngineError as N, OPERATIONS as O, compose as P, createDispatchMeta as Q, createGatewayHandler as R, type RpcServerHandle, type RpcServerOptions, SSE_HEADERS as S, defineGatewaySubsystem as T, deriveGatewayMatrix as U, engineError as V, WORKFLOWS_SUBDIR as W, formatSuggestedNext as X, gatewaySubsystemName as Y, generateTemplateConfig as Z, getActiveDomains as _, type HttpServerOptions as a, getByGateway as a0, getByTier as a1, getCounts as a2, getGatewayDomains as a3, getJobManager as a4, getTemplateForSubcommand as a5, mapNumericExitCodeToString as a6, parseIssueTemplates as a7, pickDecoratorMetaExtensions as a8, resolve as a9, setJobManager as aa, stampNexusMeta as ab, validateLabels as ac, validateRequiredParams as ad, validateSuggestedNext as ae, type HttpUnaryRequest as b, buildErrorFrame, type HttpUnaryResult as c, type SseEmitter as d, decodeLine, type SseFrame as e, encodeFrame, type SseSource as f, createSseStream as g, encodeSseFrame as h, encodeStreamEvent as i, statusForResponse as j, type McpContent as k, type McpInputProperty as l, type McpServerOptions as m, type McpTool as n, type McpToolResult as o, parseHttpRoute as p, buildToolsList as q, routeUnary as r, routeFrame, startHttpServer as s, startRpcServer, callTool as t, exposedOperations as u, operationToMcpTool as v, operationToToolName as w, startMcpServer as x, toolNameToOperationKey as y, type DispatcherConfig as z };