@agentcomms/events-daemon 0.0.0-stage → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2486 @@
1
+ import { a as number, c as unknown, o as strictObject, s as string, t as McpServer } from "./mcp-DXXb3Vv3-B0sHZfig.mjs";
2
+ import { a as EventDomainError, c as JUDGE_KIND_LOCAL_ENDPOINT, f as validateLocalEndpoint, g as parseIpLiteral, h as assertApprovedAddressSet, l as JUDGE_KIND_TYPESAFE, n as canonicalWebhookTarget, o as JUDGE_KINDS } from "./webhook-target-DyDTwWhV.mjs";
3
+ import { createHash, randomBytes } from "node:crypto";
4
+ import { chmod, lstat, mkdir, open, readFile, realpath, rm, writeFile } from "node:fs/promises";
5
+ import { createConnection } from "node:net";
6
+ import { CommsError, ERROR_REGISTRY, canonicalDisclosureBinding, canonicalJson, isCommsError, neutralise, resolvePaths, sha256Hex } from "@agentcomms/core";
7
+ import { constants } from "node:fs";
8
+ import { basename, dirname, join } from "node:path";
9
+ import { TEST_CLOUD_EVENT, canonicaliseAgenticCondition, canonicaliseCondition, catalogueEntry, compileMapping, isJsonValue, parsePointer, validateCloudEventType } from "@agentcomms/events";
10
+ //#region src/network/error-sink.ts
11
+ /**
12
+ * Keeps an owned network resource from turning a later transport error into an uncaught exception.
13
+ * Operation-specific listeners still translate errors into their own result while they are active.
14
+ */
15
+ function installErrorSink(resource) {
16
+ resource.on("error", () => void 0);
17
+ return resource;
18
+ }
19
+ //#endregion
20
+ //#region src/runtime/paths.ts
21
+ const DIRECTORY_MODE = 448;
22
+ const FILE_MODE = 384;
23
+ var EventPathError = class extends Error {
24
+ code;
25
+ path;
26
+ constructor(code, path) {
27
+ super(`Event state path is not safe: ${path}`);
28
+ this.name = "EventPathError";
29
+ this.code = code;
30
+ this.path = path;
31
+ }
32
+ };
33
+ const nodePathIo = {
34
+ mkdir,
35
+ lstat,
36
+ chmod,
37
+ open,
38
+ async isReparsePoint() {
39
+ return false;
40
+ },
41
+ async isCurrentUserOnly() {
42
+ return false;
43
+ }
44
+ };
45
+ function eventPaths(stateDir) {
46
+ const root = join(stateDir, "events");
47
+ return {
48
+ stateDir,
49
+ root,
50
+ database: join(root, "events.sqlite"),
51
+ databaseWal: join(root, "events.sqlite-wal"),
52
+ databaseShm: join(root, "events.sqlite-shm"),
53
+ lock: join(root, "events.lock"),
54
+ socketDir: join(root, "socket"),
55
+ controlSocket: join(root, "socket", "control.sock"),
56
+ controlToken: join(root, "control.token"),
57
+ instance: join(root, "instance.json"),
58
+ secretsDir: join(root, "secrets")
59
+ };
60
+ }
61
+ async function ensureEventPaths(paths, options = {}) {
62
+ const io = options.io ?? nodePathIo;
63
+ const platform = options.platform ?? process.platform;
64
+ await ensureOwnerOnlyDirectory(paths.stateDir, {
65
+ io,
66
+ platform
67
+ });
68
+ await ensureOwnerOnlyDirectory(paths.root, {
69
+ io,
70
+ platform
71
+ });
72
+ return paths;
73
+ }
74
+ /** Creates and verifies the private directory that contains the Unix control socket. */
75
+ async function ensureEventSocketDirectory(paths, options = {}) {
76
+ const io = options.io ?? nodePathIo;
77
+ const platform = options.platform ?? process.platform;
78
+ await ensureOwnerOnlyDirectory(paths.socketDir, {
79
+ io,
80
+ platform
81
+ });
82
+ }
83
+ async function ensureOwnerOnlyFile(path, options = {}) {
84
+ const io = options.io ?? nodePathIo;
85
+ const platform = options.platform ?? process.platform;
86
+ let exists = true;
87
+ try {
88
+ await io.lstat(path);
89
+ } catch (error) {
90
+ if (error.code !== "ENOENT") throw error;
91
+ exists = false;
92
+ }
93
+ if (!exists) {
94
+ const noFollow = platform === "win32" ? 0 : constants.O_NOFOLLOW;
95
+ try {
96
+ await (await io.open(path, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | noFollow, FILE_MODE)).close();
97
+ } catch (error) {
98
+ if (error.code !== "EEXIST") throw error;
99
+ }
100
+ }
101
+ await verifyOwnerOnly(path, {
102
+ io,
103
+ platform,
104
+ kind: "file"
105
+ });
106
+ }
107
+ async function ensureOwnerOnlyDirectory(path, options) {
108
+ await options.io.mkdir(path, {
109
+ recursive: true,
110
+ mode: DIRECTORY_MODE
111
+ });
112
+ await verifyOwnerOnly(path, {
113
+ ...options,
114
+ kind: "directory"
115
+ });
116
+ }
117
+ async function verifyOwnerOnly(path, options) {
118
+ const info = await options.io.lstat(path);
119
+ if (info.isSymbolicLink()) throw new EventPathError("EVENT_PATH_LINK", path);
120
+ if (await options.io.isReparsePoint?.(path) === true) throw new EventPathError("EVENT_PATH_REPARSE_POINT", path);
121
+ if (options.kind === "directory" && !info.isDirectory()) throw new EventPathError("EVENT_PATH_TYPE", path);
122
+ if (options.kind === "file" && !info.isFile()) throw new EventPathError("EVENT_PATH_TYPE", path);
123
+ if (options.platform === "win32") {
124
+ if (await options.io.isCurrentUserOnly?.(path) !== true) throw new EventPathError("EVENT_PATH_PERMISSIONS", path);
125
+ return;
126
+ }
127
+ if ((info.mode & 63) !== 0) throw new EventPathError("EVENT_PATH_PERMISSIONS", path);
128
+ }
129
+ //#endregion
130
+ //#region src/control/endpoint.ts
131
+ const nodeEndpointIo = {
132
+ lstat,
133
+ realpath
134
+ };
135
+ /** The longest Unix socket path the platform's `sun_path` holds, in bytes, leaving room for its terminating NUL. */
136
+ function maxSocketPathBytes(platform = process.platform) {
137
+ return platform === "linux" || platform === "android" ? 107 : 103;
138
+ }
139
+ /** The control endpoint for this state directory. */
140
+ function controlEndpoint(paths, platform = process.platform) {
141
+ if (platform !== "win32") return paths.controlSocket;
142
+ return `\\\\.\\pipe\\agent-communications-events-${createHash("sha256").update(paths.root).digest("hex")}`;
143
+ }
144
+ /** Refuses on a platform where the control boundary D12 requires cannot be built. */
145
+ function assertControlSupported(platform = process.platform) {
146
+ if (platform !== "win32") return;
147
+ throw new CommsError("CONFIG", "the local event service does not run on Windows in this release", {
148
+ hint: "Its control channel needs a named pipe that only your Windows account can open, which Node cannot create. Run it on macOS or Linux for now.",
149
+ details: { reason: "WINDOWS_CONTROL_UNAVAILABLE" }
150
+ });
151
+ }
152
+ function refused(reason, path, message) {
153
+ return new CommsError("CONFIG", message, {
154
+ hint: "Pin a private state directory with --state-dir, one only your account can reach, and run it again.",
155
+ details: {
156
+ reason,
157
+ path
158
+ }
159
+ });
160
+ }
161
+ function currentUid(options) {
162
+ const uid = options.uid ?? (typeof process.getuid === "function" ? process.getuid() : void 0);
163
+ if (uid === void 0) throw new CommsError("CONFIG", "this platform reports no user id for the local event service to check");
164
+ return uid;
165
+ }
166
+ /** The socket path fits the platform's limit, or a named refusal — never a silently truncated path. */
167
+ function assertSocketPathFits(socketPath, platform = process.platform) {
168
+ const bytes = Buffer.byteLength(socketPath, "utf8");
169
+ if (bytes <= maxSocketPathBytes(platform)) return;
170
+ throw new CommsError("CONFIG", `the local event control socket path is ${bytes} bytes; this system allows ${maxSocketPathBytes(platform)}`, {
171
+ hint: "Pin a shorter state directory with --state-dir and run it again.",
172
+ details: {
173
+ reason: "SOCKET_PATH_TOO_LONG",
174
+ bytes,
175
+ limit: maxSocketPathBytes(platform)
176
+ }
177
+ });
178
+ }
179
+ /**
180
+ * The socket directory is a real directory owned by this uid with mode 0700, and every ancestor is owned by this uid
181
+ * or root and is either not writable by others or sticky — so nobody else can reach, rename or replace it.
182
+ */
183
+ async function verifyPrivateSocketDirectory(paths, options = {}) {
184
+ assertControlSupported(options.platform ?? process.platform);
185
+ const io = options.io ?? nodeEndpointIo;
186
+ const uid = currentUid(options);
187
+ const directory = paths.socketDir;
188
+ const info = await statOrRefuse(io, directory);
189
+ if (info.isSymbolicLink() || !info.isDirectory()) throw refused("SOCKET_DIRECTORY_NOT_DIRECTORY", directory, "the local event socket directory is not a directory");
190
+ if (info.uid !== uid) throw refused("SOCKET_DIRECTORY_OWNER", directory, "the local event socket directory belongs to another user");
191
+ if ((info.mode & 511) !== 448) throw refused("SOCKET_DIRECTORY_MODE", directory, "the local event socket directory is reachable by other users");
192
+ for (let ancestor = await io.realpath(dirname(directory));; ancestor = dirname(ancestor)) {
193
+ const parent = await statOrRefuse(io, ancestor);
194
+ if (parent.uid !== uid && parent.uid !== 0) throw refused("SOCKET_ANCESTOR_OWNER", ancestor, "a directory above the local event socket belongs to another user");
195
+ if ((parent.mode & 18) !== 0 && (parent.mode & 512) === 0) throw refused("SOCKET_ANCESTOR_WRITABLE", ancestor, "a directory above the local event socket can be changed by other users");
196
+ if (dirname(ancestor) === ancestor) break;
197
+ }
198
+ }
199
+ /** The socket itself is this uid's, mode 0600, and a socket — checked by a client before it sends the token. */
200
+ async function verifyControlSocket(socketPath, options = {}) {
201
+ const io = options.io ?? nodeEndpointIo;
202
+ const uid = currentUid(options);
203
+ const info = await statOrRefuse(io, socketPath);
204
+ if (info.isSymbolicLink() || !info.isSocket()) throw refused("SOCKET_NOT_SOCKET", socketPath, "the local event control endpoint is not a socket");
205
+ if (info.uid !== uid) throw refused("SOCKET_OWNER", socketPath, "the local event control socket belongs to another user");
206
+ if ((info.mode & 63) !== 0) throw refused("SOCKET_MODE", socketPath, "the local event control socket is reachable by other users");
207
+ }
208
+ async function statOrRefuse(io, path) {
209
+ try {
210
+ return await io.lstat(path);
211
+ } catch (error) {
212
+ if (error.code === "ENOENT") throw new CommsError("NOT_FOUND", "the local event service is not running", { hint: "Start the local event service in a terminal before requesting its runtime controls." });
213
+ throw error;
214
+ }
215
+ }
216
+ //#endregion
217
+ //#region src/control/instance.ts
218
+ function tokenFingerprint(token) {
219
+ return createHash("sha256").update(token).digest("hex");
220
+ }
221
+ function newInstanceRecord(endpoint, token) {
222
+ return {
223
+ instanceId: randomBytes(16).toString("hex"),
224
+ pid: process.pid,
225
+ processStart: `${process.pid}:${Math.trunc(process.uptime() * 1e3)}`,
226
+ endpoint,
227
+ tokenFingerprint: tokenFingerprint(token)
228
+ };
229
+ }
230
+ async function mayRecoverStaleInstance(check) {
231
+ if (!await check.ownershipMatches(check.record)) return false;
232
+ if (await check.isProcessLive(check.record)) return false;
233
+ return !await check.authenticatedProbe(check.record);
234
+ }
235
+ async function readInstance(paths) {
236
+ let text;
237
+ try {
238
+ text = await readFile(paths.instance, "utf8");
239
+ } catch (error) {
240
+ if (error.code === "ENOENT") return null;
241
+ throw error;
242
+ }
243
+ try {
244
+ const parsed = JSON.parse(text);
245
+ if (!isInstanceRecord(parsed)) throw new Error("invalid local event instance record");
246
+ return parsed;
247
+ } catch {
248
+ throw new Error(`invalid local event instance record ${basename(paths.instance)}`);
249
+ }
250
+ }
251
+ async function writeInstance(paths, record) {
252
+ await writeFile(paths.instance, `${JSON.stringify(record)}\n`, {
253
+ encoding: "utf8",
254
+ mode: 384
255
+ });
256
+ await chmod(paths.instance, 384);
257
+ }
258
+ async function removeInstance(paths, instanceId) {
259
+ if ((await readInstance(paths))?.instanceId === instanceId) await rm(paths.instance, { force: true });
260
+ }
261
+ async function processIsLive(record) {
262
+ try {
263
+ process.kill(record.pid, 0);
264
+ return true;
265
+ } catch (error) {
266
+ return error.code !== "ESRCH";
267
+ }
268
+ }
269
+ function isInstanceRecord(value) {
270
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
271
+ const record = value;
272
+ return typeof record.instanceId === "string" && /^[0-9a-f]{32}$/.test(record.instanceId) && typeof record.pid === "number" && Number.isInteger(record.pid) && record.pid > 0 && typeof record.processStart === "string" && record.processStart.length > 0 && typeof record.endpoint === "string" && record.endpoint.length > 0 && typeof record.tokenFingerprint === "string" && /^[0-9a-f]{64}$/.test(record.tokenFingerprint);
273
+ }
274
+ //#endregion
275
+ //#region src/control/protocol.ts
276
+ const CONTROL_PROTOCOL_VERSIONS = [1];
277
+ function controlFailure(code, message, hint) {
278
+ return {
279
+ ok: false,
280
+ error: {
281
+ code,
282
+ message,
283
+ ...hint === void 0 ? {} : { hint },
284
+ retryable: false
285
+ }
286
+ };
287
+ }
288
+ function negotiateVersion(clientVersions, serverVersions = CONTROL_PROTOCOL_VERSIONS) {
289
+ const shared = clientVersions.filter((version) => Number.isSafeInteger(version) && serverVersions.includes(version));
290
+ if (shared.length === 0) return {
291
+ ok: false,
292
+ code: "PROTOCOL_UNSUPPORTED"
293
+ };
294
+ return {
295
+ ok: true,
296
+ version: Math.max(...shared)
297
+ };
298
+ }
299
+ function malformed() {
300
+ return /* @__PURE__ */ new Error("malformed local control frame");
301
+ }
302
+ function encodeControlFrame(value) {
303
+ const payload = new TextEncoder().encode(JSON.stringify(value));
304
+ if (payload.byteLength > 65536) throw new Error("local control frame is too large");
305
+ const frame = new Uint8Array(4 + payload.byteLength);
306
+ new DataView(frame.buffer).setUint32(0, payload.byteLength, false);
307
+ frame.set(payload, 4);
308
+ return frame;
309
+ }
310
+ /** Decodes exactly one complete length-prefixed control frame. */
311
+ function decodeControlFrame(frame) {
312
+ if (frame.byteLength < 4) throw malformed();
313
+ const length = new DataView(frame.buffer, frame.byteOffset, frame.byteLength).getUint32(0, false);
314
+ if (length > 65536) throw new Error("local control frame is too large");
315
+ if (frame.byteLength !== length + 4) throw malformed();
316
+ try {
317
+ return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(frame.subarray(4)));
318
+ } catch {
319
+ throw malformed();
320
+ }
321
+ }
322
+ /** Incrementally separates complete frames without buffering an unbounded peer payload. */
323
+ var ControlFrameReader = class {
324
+ #buffer = /* @__PURE__ */ new Uint8Array();
325
+ push(chunk) {
326
+ let buffered = this.#buffer;
327
+ let offset = 0;
328
+ const values = [];
329
+ while (offset < chunk.byteLength || buffered.byteLength >= 4) {
330
+ if (buffered.byteLength < 4) {
331
+ const remainingHeader = 4 - buffered.byteLength;
332
+ const take = Math.min(remainingHeader, chunk.byteLength - offset);
333
+ buffered = append(buffered, chunk.subarray(offset, offset + take));
334
+ offset += take;
335
+ if (buffered.byteLength < 4) break;
336
+ }
337
+ const length = new DataView(buffered.buffer, buffered.byteOffset, buffered.byteLength).getUint32(0, false);
338
+ if (length > 65536) throw new Error("local control frame is too large");
339
+ const frameLength = length + 4;
340
+ if (buffered.byteLength < frameLength) {
341
+ const take = Math.min(frameLength - buffered.byteLength, chunk.byteLength - offset);
342
+ buffered = append(buffered, chunk.subarray(offset, offset + take));
343
+ offset += take;
344
+ if (buffered.byteLength < frameLength) break;
345
+ }
346
+ values.push(decodeControlFrame(buffered.subarray(0, frameLength)));
347
+ buffered = buffered.subarray(frameLength);
348
+ }
349
+ this.#buffer = buffered.slice();
350
+ return values;
351
+ }
352
+ };
353
+ function append(first, second) {
354
+ const joined = new Uint8Array(first.byteLength + second.byteLength);
355
+ joined.set(first);
356
+ joined.set(second, first.byteLength);
357
+ return joined;
358
+ }
359
+ function isControlHello(value) {
360
+ if (!isRecord$3(value) || !isRecord$3(value.hello)) return false;
361
+ const { supportedVersions, token, client } = value.hello;
362
+ return Array.isArray(supportedVersions) && supportedVersions.length > 0 && supportedVersions.length <= 8 && supportedVersions.every((version) => Number.isSafeInteger(version)) && typeof token === "string" && token.length === 64 && isRecord$3(client) && typeof client.name === "string" && client.name.length > 0 && client.name.length <= 128;
363
+ }
364
+ function isControlRequest(value) {
365
+ if (!isRecord$3(value)) return false;
366
+ return Number.isSafeInteger(value.version) && typeof value.requestId === "string" && value.requestId.length > 0 && value.requestId.length <= 128 && typeof value.session === "string" && value.session.length > 0 && value.session.length <= 256 && typeof value.operation === "string" && value.operation.length > 0 && value.operation.length <= 128 && isRecord$3(value.args);
367
+ }
368
+ function isRecord$3(value) {
369
+ return typeof value === "object" && value !== null && !Array.isArray(value);
370
+ }
371
+ //#endregion
372
+ //#region src/control/client.ts
373
+ var EventControlClient = class {
374
+ #paths;
375
+ #clientName;
376
+ constructor(options = {}) {
377
+ this.#paths = eventPaths(options.stateDir ?? resolvePaths().stateDir);
378
+ this.#clientName = options.clientName ?? "events-cli";
379
+ }
380
+ async request(operation, args = {}) {
381
+ assertControlSupported();
382
+ const record = await readInstance(this.#paths);
383
+ if (!record) throw notRunning();
384
+ await verifyOwnEndpoint(this.#paths, record);
385
+ const token = await readToken(this.#paths, record);
386
+ try {
387
+ return await requestControl(record, token, this.#clientName, operation, args);
388
+ } catch (error) {
389
+ if (isMissingOwner(error)) throw notRunning();
390
+ throw error;
391
+ }
392
+ }
393
+ };
394
+ /** Proves the instance names this state directory's own private socket, before any token is sent to it. */
395
+ async function verifyOwnEndpoint(paths, record) {
396
+ if (record.endpoint !== controlEndpoint(paths)) throw notRunning();
397
+ await verifyPrivateSocketDirectory(paths);
398
+ await verifyControlSocket(record.endpoint);
399
+ }
400
+ async function probeControl(paths, record, token) {
401
+ try {
402
+ await verifyOwnEndpoint(paths, record);
403
+ await requestControl(record, token, "events-owner-probe", "status", {});
404
+ return true;
405
+ } catch {
406
+ return false;
407
+ }
408
+ }
409
+ async function requestControl(record, token, clientName, operation, args) {
410
+ const socket = await connect(record.endpoint);
411
+ try {
412
+ const hello = await exchange(socket, { hello: {
413
+ supportedVersions: CONTROL_PROTOCOL_VERSIONS,
414
+ token,
415
+ client: { name: clientName }
416
+ } });
417
+ if (!hello.ok || hello.version === void 0 || hello.session === void 0) throw controlError(hello);
418
+ const reply = await exchange(socket, {
419
+ version: hello.version,
420
+ requestId: randomBytes(16).toString("base64url"),
421
+ session: hello.session,
422
+ operation,
423
+ args
424
+ });
425
+ if (!reply.ok) throw controlError(reply);
426
+ return reply.data;
427
+ } finally {
428
+ socket.end();
429
+ }
430
+ }
431
+ async function readToken(paths, record) {
432
+ let token;
433
+ try {
434
+ token = (await readFile(paths.controlToken, "utf8")).trim();
435
+ } catch (error) {
436
+ if (error.code === "ENOENT") throw notRunning();
437
+ throw error;
438
+ }
439
+ if (!/^[0-9a-f]{64}$/.test(token) || tokenFingerprint(token) !== record.tokenFingerprint) throw notRunning();
440
+ return token;
441
+ }
442
+ function connect(endpoint) {
443
+ return new Promise((resolve, reject) => {
444
+ const socket = createConnection(endpoint);
445
+ installErrorSink(socket);
446
+ socket.once("connect", () => {
447
+ socket.off("error", reject);
448
+ resolve(socket);
449
+ });
450
+ socket.once("error", reject);
451
+ });
452
+ }
453
+ function exchange(socket, value) {
454
+ return new Promise((resolve, reject) => {
455
+ const reader = new ControlFrameReader();
456
+ const onData = (chunk) => {
457
+ try {
458
+ const frame = reader.push(chunk)[0];
459
+ if (frame === void 0) return;
460
+ cleanup();
461
+ resolve(frame);
462
+ } catch (error) {
463
+ cleanup();
464
+ reject(error);
465
+ }
466
+ };
467
+ const onError = (error) => {
468
+ cleanup();
469
+ reject(error);
470
+ };
471
+ const cleanup = () => {
472
+ socket.off("data", onData);
473
+ socket.off("error", onError);
474
+ };
475
+ socket.on("data", onData);
476
+ socket.once("error", onError);
477
+ socket.write(encodeControlFrame(value));
478
+ });
479
+ }
480
+ function controlError(reply) {
481
+ if (!reply.ok) {
482
+ const options = {
483
+ ...reply.error.hint === void 0 ? {} : { hint: reply.error.hint },
484
+ ...reply.error.details === void 0 ? {} : { details: reply.error.details }
485
+ };
486
+ const code = reply.error.code;
487
+ if (code === "PROTOCOL_UNSUPPORTED") return new CommsError("CONFIG", reply.error.message, options);
488
+ if (Object.hasOwn(ERROR_REGISTRY, code)) return new CommsError(code, reply.error.message, options);
489
+ return new CommsError("BAD_DATA", reply.error.message, options);
490
+ }
491
+ return new CommsError("BAD_DATA", "local control hello was malformed");
492
+ }
493
+ function notRunning() {
494
+ return new CommsError("NOT_FOUND", "the local event service is not running", { hint: "Start the local event service in a terminal before requesting its runtime controls." });
495
+ }
496
+ function isMissingOwner(error) {
497
+ const code = error?.code;
498
+ return code === "ECONNREFUSED" || code === "ENOENT" || code === "ECONNRESET";
499
+ }
500
+ //#endregion
501
+ //#region src/operations/approval-view.ts
502
+ /** Returns the daemon-authoritative preview and fresh challenge; it never claims an approval. */
503
+ async function approvalView(approvalId, digest, options = {}) {
504
+ return new EventControlClient({ stateDir: options.stateDir }).request("approvalView", {
505
+ approvalId,
506
+ digest
507
+ });
508
+ }
509
+ //#endregion
510
+ //#region src/operations/catalogue.ts
511
+ /** Lists the held Phase A catalogue through the owner without opening event SQLite in a client. */
512
+ async function catalogueList(options = {}) {
513
+ return new EventControlClient({ stateDir: options.stateDir }).request("catalogue-list");
514
+ }
515
+ /** Shows one selectable catalogue definition through the owner. */
516
+ async function catalogueShow(type, options = {}) {
517
+ return new EventControlClient({ stateDir: options.stateDir }).request("catalogue-show", { type });
518
+ }
519
+ //#endregion
520
+ //#region src/operations/deliveries.ts
521
+ async function deliveriesList(options = {}) {
522
+ return new EventControlClient({ stateDir: options.stateDir }).request("deliveriesList");
523
+ }
524
+ async function retryDelivery(deliveryId, options = {}) {
525
+ return new EventControlClient({ stateDir: options.stateDir }).request("retryDelivery", { deliveryId });
526
+ }
527
+ async function dropDelivery(deliveryId, options = {}) {
528
+ return new EventControlClient({ stateDir: options.stateDir }).request("dropDelivery", { deliveryId });
529
+ }
530
+ async function heldList(options = {}) {
531
+ return new EventControlClient({ stateDir: options.stateDir }).request("heldList");
532
+ }
533
+ /** Terminal/app-only operation; Task 5 intentionally provides no MCP adapter. */
534
+ async function decideHeld(decisionId, decision, options = {}) {
535
+ return new EventControlClient({
536
+ stateDir: options.stateDir,
537
+ clientName: "interactive-terminal"
538
+ }).request("decideHeld", {
539
+ decisionId,
540
+ decision
541
+ });
542
+ }
543
+ //#endregion
544
+ //#region src/operations/disable-all.ts
545
+ async function disableAll(options = {}) {
546
+ return await new EventControlClient({ stateDir: options.stateDir }).request("disable-all");
547
+ }
548
+ //#endregion
549
+ //#region src/domain/activation-failure-codes.ts
550
+ /** Codes persisted by the activation writers. Database rows from older or damaged state are not trusted as codes. */
551
+ const ACTIVATION_FAILURE = {
552
+ ACCOUNT_REMOVED: "ACCOUNT_REMOVED",
553
+ APPROVAL_ABSENT: "APPROVAL_ABSENT",
554
+ APPROVAL_BINDING_DRIFT: "APPROVAL_BINDING_DRIFT",
555
+ AUTHORIZATION_REVOKED: "AUTHORIZATION_REVOKED",
556
+ COMPLETION_TIMEOUT: "COMPLETION_TIMEOUT",
557
+ STALE_GENERATION: "STALE_GENERATION",
558
+ STALE_POINTER: "STALE_POINTER"
559
+ };
560
+ const ACTIVATION_FAILURE_CODES = Object.values(ACTIVATION_FAILURE);
561
+ const ACTIVATION_FAILURE_CODE_SET = new Set(ACTIVATION_FAILURE_CODES);
562
+ function isActivationFailureCode(value) {
563
+ return typeof value === "string" && ACTIVATION_FAILURE_CODE_SET.has(value);
564
+ }
565
+ [...ACTIVATION_FAILURE_CODES];
566
+ /**
567
+ * The transport binding mirrors the root `additionalProperties: false` in doctor-v1.schema.json. Keeping this at
568
+ * the production projection boundary makes an accidental diagnostic field fail closed before CLI or MCP can render
569
+ * it; nested fields are constructed from closed object literals in the projection below that boundary.
570
+ */
571
+ const DOCTOR_REPORT_V1_KEYS = [
572
+ "schemaVersion",
573
+ "owner",
574
+ "switch",
575
+ "lineages",
576
+ "superseded",
577
+ "points",
578
+ "awaitingReapproval",
579
+ "activationIntents",
580
+ "sources",
581
+ "recovery",
582
+ "judgeBoundary",
583
+ "whatsapp"
584
+ ];
585
+ function assertDoctorReportV1(report) {
586
+ if (Object.keys(report).some((key) => !DOCTOR_REPORT_V1_KEYS.includes(key))) throw new Error("doctor-v1 report is closed");
587
+ return report;
588
+ }
589
+ const DOCTOR_REPORT_V2_KEYS = [
590
+ "schemaVersion",
591
+ "owner",
592
+ "switch",
593
+ "lineages",
594
+ "superseded",
595
+ "points",
596
+ "awaitingReapproval",
597
+ "activationIntents",
598
+ "sources",
599
+ "recovery",
600
+ "judgeBoundary",
601
+ "judge",
602
+ "whatsapp"
603
+ ];
604
+ function assertDoctorReportV2(report) {
605
+ if (Object.keys(report).some((key) => !DOCTOR_REPORT_V2_KEYS.includes(key))) throw new Error("doctor-v2 report is closed");
606
+ return report;
607
+ }
608
+ async function doctor(options = {}) {
609
+ return await new EventControlClient({ stateDir: options.stateDir }).request("doctor");
610
+ }
611
+ //#endregion
612
+ //#region src/operations/enable-all.ts
613
+ /** The disclosure approval/activation route lands with the immutable activation work in Batch 3. */
614
+ async function enableAll(options = {}) {
615
+ return await new EventControlClient({ stateDir: options.stateDir }).request("enable-all");
616
+ }
617
+ //#endregion
618
+ //#region src/operations/judges.ts
619
+ function request(operation, args, options) {
620
+ return new EventControlClient({ stateDir: options.stateDir }).request(operation, args);
621
+ }
622
+ function judgesList(options = {}) {
623
+ return request("judgesList", {}, options);
624
+ }
625
+ function addJudge(document, options = {}) {
626
+ return request("addJudge", { document }, options);
627
+ }
628
+ function updateJudge(document, options = {}) {
629
+ return request("updateJudge", { document }, options);
630
+ }
631
+ function removeJudge(judgeId, options = {}) {
632
+ return request("removeJudge", { judgeId }, options);
633
+ }
634
+ function judgeTest(judgeId, version, options = {}) {
635
+ return request("judgeTest", {
636
+ judgeId,
637
+ version
638
+ }, options);
639
+ }
640
+ function budgetShow(options = {}) {
641
+ return request("budgetShow", {}, options);
642
+ }
643
+ function updateBudget(document, options = {}) {
644
+ return request("updateBudget", { document }, options);
645
+ }
646
+ function judgeKindsList(options = {}) {
647
+ return request("judgeKindsList", {}, options);
648
+ }
649
+ function enableJudgeKind(kind, options = {}) {
650
+ return request("enableJudgeKind", { kind }, options);
651
+ }
652
+ function disableJudgeKind(kind, options = {}) {
653
+ return request("disableJudgeKind", { kind }, options);
654
+ }
655
+ function judgeModelStatus(options = {}) {
656
+ return request("judgeModelStatus", {}, options);
657
+ }
658
+ function removeJudgeModel(options = {}) {
659
+ return request("removeJudgeModel", {}, options);
660
+ }
661
+ //#endregion
662
+ //#region src/operations/pause.ts
663
+ async function pause(options = {}) {
664
+ return await new EventControlClient({ stateDir: options.stateDir }).request("pause");
665
+ }
666
+ async function resume(options = {}) {
667
+ return await new EventControlClient({ stateDir: options.stateDir }).request("resume");
668
+ }
669
+ //#endregion
670
+ //#region src/operations/rule-test.ts
671
+ /** Calls the owner-local deterministic catalogue test; neither this operation nor its caller can supply event bytes. */
672
+ async function ruleTest(document, catalogue, options = {}) {
673
+ return new EventControlClient({ stateDir: options.stateDir }).request("ruleTest", {
674
+ document,
675
+ catalogue
676
+ });
677
+ }
678
+ /** Retained projections stay behind the owner boundary and are intentionally a human-only capability. */
679
+ async function ruleTestRetained(eventId, ruleId, ruleVersion, options = {}) {
680
+ return new EventControlClient({ stateDir: options.stateDir }).request("ruleTestRetained", {
681
+ eventId,
682
+ ruleId,
683
+ ruleVersion
684
+ });
685
+ }
686
+ //#endregion
687
+ //#region src/operations/rules.ts
688
+ async function rulesList(options = {}) {
689
+ return new EventControlClient({ stateDir: options.stateDir }).request("rules-list");
690
+ }
691
+ async function ruleShow(ruleId, options = {}) {
692
+ return new EventControlClient({ stateDir: options.stateDir }).request("rule-show", { ruleId });
693
+ }
694
+ async function createRule(document, options = {}) {
695
+ return new EventControlClient({ stateDir: options.stateDir }).request("rule-create", { document });
696
+ }
697
+ async function updateRule(document, options = {}) {
698
+ return new EventControlClient({ stateDir: options.stateDir }).request("rule-update", { document });
699
+ }
700
+ async function enableRule(ruleId, version, options = {}) {
701
+ return new EventControlClient({ stateDir: options.stateDir }).request("rule-enable", {
702
+ ruleId,
703
+ version
704
+ });
705
+ }
706
+ async function disableRule(ruleId, options = {}) {
707
+ return new EventControlClient({ stateDir: options.stateDir }).request("rule-disable", { ruleId });
708
+ }
709
+ async function removeRule(ruleId, options = {}) {
710
+ return new EventControlClient({ stateDir: options.stateDir }).request("rule-remove", { ruleId });
711
+ }
712
+ //#endregion
713
+ //#region src/operations/sources.ts
714
+ async function sourcesList(options = {}) {
715
+ return new EventControlClient({ stateDir: options.stateDir }).request("sources-list");
716
+ }
717
+ async function sourceShow(source, options = {}) {
718
+ return new EventControlClient({ stateDir: options.stateDir }).request("source-show", { source });
719
+ }
720
+ //#endregion
721
+ //#region src/runtime/sqlite.ts
722
+ /** The oldest Node the event daemon runs on. Stated in `engines`, and checked before the module is imported. */
723
+ const MIN_NODE = "22.16.0";
724
+ function parts(version) {
725
+ return version.replace(/^v/, "").split(/[.-]/).slice(0, 3).map((part) => Number.parseInt(part, 10) || 0);
726
+ }
727
+ /** Whether `version` (default: this Node's) is `MIN_NODE` or newer. */
728
+ function nodeSupportsSqlite(version = process.versions.node) {
729
+ const have = parts(version);
730
+ const need = parts(MIN_NODE);
731
+ for (let index = 0; index < 3; index += 1) if ((have[index] ?? 0) !== (need[index] ?? 0)) return (have[index] ?? 0) > (need[index] ?? 0);
732
+ return true;
733
+ }
734
+ /** Refuses to go on under a Node too old for its SQLite, saying which Node it is and what it needs. */
735
+ function requireSupportedNode(version = process.versions.node) {
736
+ if (nodeSupportsSqlite(version)) return;
737
+ throw new CommsError("CONFIG", `the local event service needs Node ${MIN_NODE} or newer, and this is Node ${version}`, {
738
+ hint: `It keeps its state in Node's own SQLite, which Node ${MIN_NODE} is the first to have complete. Install a newer Node — the current 22 or 24 release — and run it again.`,
739
+ details: {
740
+ reason: "NODE_TOO_OLD",
741
+ node: version,
742
+ needs: MIN_NODE
743
+ }
744
+ });
745
+ }
746
+ let loaded = null;
747
+ function loadSqlite() {
748
+ try {
749
+ requireSupportedNode();
750
+ } catch (error) {
751
+ return Promise.reject(error);
752
+ }
753
+ if (!loaded) {
754
+ loaded = (async () => {
755
+ const original = process.emitWarning;
756
+ process.emitWarning = function filtered(warning, ...rest) {
757
+ if ((typeof warning === "string" ? warning : warning.message).includes("SQLite is an experimental feature")) return;
758
+ return original.call(process, warning, ...rest);
759
+ };
760
+ try {
761
+ return await import("node:sqlite");
762
+ } catch (error) {
763
+ throw new CommsError("CONFIG", `this Node (${process.versions.node}) has no usable built-in SQLite`, {
764
+ hint: `The local event service needs Node ${MIN_NODE} or newer, run without flags that turn built-in modules off.`,
765
+ cause: error
766
+ });
767
+ } finally {
768
+ process.emitWarning = original;
769
+ }
770
+ })();
771
+ loaded.catch(() => {
772
+ loaded = null;
773
+ });
774
+ }
775
+ return loaded;
776
+ }
777
+ //#endregion
778
+ //#region src/operations/status.ts
779
+ /** Reports an owner through its authenticated control boundary, without opening its SQLite database in the client. */
780
+ async function status(options = {}) {
781
+ requireSupportedNode();
782
+ try {
783
+ return await new EventControlClient({ stateDir: options.stateDir }).request("status");
784
+ } catch (error) {
785
+ if (isCommsError(error) && error.code === "NOT_FOUND") return { owner: "not-running" };
786
+ throw error;
787
+ }
788
+ }
789
+ //#endregion
790
+ //#region src/operations/stop.ts
791
+ /** Requests a clean foreground-owner shutdown through the authenticated local control protocol. */
792
+ async function stop(options = {}) {
793
+ return await new EventControlClient({ stateDir: options.stateDir }).request("stop");
794
+ }
795
+ //#endregion
796
+ //#region src/operations/subscribers.ts
797
+ async function subscribersList(options = {}) {
798
+ return new EventControlClient({ stateDir: options.stateDir }).request("subscribersList");
799
+ }
800
+ async function addSubscriber(document, options = {}) {
801
+ return new EventControlClient({ stateDir: options.stateDir }).request("addSubscriber", { document });
802
+ }
803
+ async function updateSubscriber(document, options = {}) {
804
+ return new EventControlClient({ stateDir: options.stateDir }).request("updateSubscriber", { document });
805
+ }
806
+ async function removeSubscriber(subscriberId, options = {}) {
807
+ return new EventControlClient({ stateDir: options.stateDir }).request("removeSubscriber", { subscriberId });
808
+ }
809
+ //#endregion
810
+ //#region src/operations/target-test.ts
811
+ /** The owner constructs the fixed synthetic payload; callers name only the exact immutable target version. */
812
+ async function targetTest(targetId, targetVersion, options = {}) {
813
+ return new EventControlClient({ stateDir: options.stateDir }).request("targetTest", {
814
+ targetId,
815
+ targetVersion
816
+ });
817
+ }
818
+ //#endregion
819
+ //#region src/operations/targets.ts
820
+ async function targetsList(options = {}) {
821
+ return new EventControlClient({ stateDir: options.stateDir }).request("targets-list");
822
+ }
823
+ async function addTarget(document, options = {}) {
824
+ return new EventControlClient({ stateDir: options.stateDir }).request("target-add", { document });
825
+ }
826
+ async function updateTarget(document, options = {}) {
827
+ return new EventControlClient({ stateDir: options.stateDir }).request("target-update", { document });
828
+ }
829
+ async function removeTarget(targetId, options = {}) {
830
+ return new EventControlClient({ stateDir: options.stateDir }).request("target-remove", { targetId });
831
+ }
832
+ //#endregion
833
+ //#region src/version.ts
834
+ /** The package version, read from package.json at build time. */
835
+ const VERSION = "0.17.0";
836
+ //#endregion
837
+ //#region src/mcp/server.ts
838
+ function reply(data) {
839
+ const structured = JSON.parse(JSON.stringify(data));
840
+ return {
841
+ structuredContent: structured,
842
+ content: [{
843
+ type: "text",
844
+ text: JSON.stringify(structured)
845
+ }]
846
+ };
847
+ }
848
+ /** Creates the local event service's deliberately content-free MCP surface. */
849
+ async function createEventsMcpServer(options = {}) {
850
+ const server = new McpServer({
851
+ name: "agent-events",
852
+ version: VERSION
853
+ });
854
+ const b3 = (operation, args, throughOwner) => options.b3Registrar === void 0 ? throughOwner() : options.b3Registrar.owner.handle({
855
+ operation,
856
+ args
857
+ });
858
+ server.registerTool("events_status", {
859
+ title: "Local event service status",
860
+ description: "Reports whether the local event service has an owner.",
861
+ inputSchema: {},
862
+ annotations: {
863
+ readOnlyHint: true,
864
+ destructiveHint: false,
865
+ idempotentHint: true,
866
+ openWorldHint: false
867
+ }
868
+ }, async () => reply(await status({ stateDir: options.stateDir })));
869
+ const runtimeTool = (name, title, description, operation, annotations) => {
870
+ server.registerTool(name, {
871
+ title,
872
+ description,
873
+ inputSchema: {},
874
+ annotations: {
875
+ readOnlyHint: false,
876
+ openWorldHint: false,
877
+ ...annotations
878
+ }
879
+ }, async () => reply(await operation(options)));
880
+ };
881
+ runtimeTool("events_stop", "Stop local event owner", "Requests a clean stop from the local owner.", stop, {
882
+ destructiveHint: true,
883
+ idempotentHint: true
884
+ });
885
+ runtimeTool("events_pause", "Pause local event work", "Pauses polling, evaluation and delivery claims without purging state.", pause, {
886
+ destructiveHint: false,
887
+ idempotentHint: true
888
+ });
889
+ runtimeTool("events_resume", "Resume local event work", "Resumes work retained by an operational pause.", resume, {
890
+ destructiveHint: false,
891
+ idempotentHint: true
892
+ });
893
+ runtimeTool("events_disable_all", "Disable all local event work", "Disables collection, advances the global generation and purges B1 work.", disableAll, {
894
+ destructiveHint: true,
895
+ idempotentHint: true
896
+ });
897
+ runtimeTool("events_enable_all", "Prepare global enablement", "Reports that a standing disclosure approval is required before enablement.", enableAll, {
898
+ destructiveHint: false,
899
+ idempotentHint: true
900
+ });
901
+ runtimeTool("events_doctor", "Local event service doctor", "Reports content-free lineage, retry, recovery, judge authority, hold-clock and protocol health.", doctor, {
902
+ destructiveHint: false,
903
+ idempotentHint: true
904
+ });
905
+ const controlTool = (name, title, description, inputSchema, operation, destructiveHint = false) => {
906
+ server.registerTool(name, {
907
+ title,
908
+ description,
909
+ inputSchema,
910
+ annotations: {
911
+ readOnlyHint: !destructiveHint,
912
+ destructiveHint,
913
+ idempotentHint: !destructiveHint,
914
+ openWorldHint: false
915
+ }
916
+ }, async (args) => reply(await operation(args)));
917
+ };
918
+ /** B3 selectors are closed: an omitted field is not permission to smuggle an approval-flow selector or a document. */
919
+ const strictControlTool = (name, title, description, inputSchema, operation, destructiveHint = false) => {
920
+ server.registerTool(name, {
921
+ title,
922
+ description,
923
+ inputSchema: strictObject(inputSchema),
924
+ annotations: {
925
+ readOnlyHint: !destructiveHint,
926
+ destructiveHint,
927
+ idempotentHint: !destructiveHint,
928
+ openWorldHint: false
929
+ }
930
+ }, async (args) => reply(await operation(args)));
931
+ };
932
+ strictControlTool("events_catalogue_list", "List local event catalogue", "Lists selectable local event definitions.", {}, () => catalogueList(options));
933
+ strictControlTool("events_approval_view", "View pending disclosure approval", "Returns the daemon-authoritative preview and fresh challenge without claiming it.", {
934
+ approvalId: string().min(1),
935
+ digest: string().min(1)
936
+ }, (args) => approvalView(args.approvalId, args.digest, options));
937
+ strictControlTool("events_rule_test", "Test a rule with a catalogue example", "Locally evaluates one selectable catalogue example without provider or judge I/O.", {
938
+ document: unknown(),
939
+ catalogue: strictObject({
940
+ type: string().min(1),
941
+ version: number().int().positive(),
942
+ exampleIndex: number().int().min(0)
943
+ })
944
+ }, (args) => ruleTest(args.document, args.catalogue, options));
945
+ server.registerTool("events_target_test", {
946
+ title: "Test one active target",
947
+ description: "Sends the fixed synthetic event only to one exact active target version.",
948
+ inputSchema: strictObject({
949
+ targetId: string().min(1),
950
+ targetVersion: number().int().positive()
951
+ }),
952
+ annotations: {
953
+ readOnlyHint: false,
954
+ destructiveHint: false,
955
+ idempotentHint: false,
956
+ openWorldHint: true
957
+ }
958
+ }, async (args) => reply(await targetTest(args.targetId, args.targetVersion, options)));
959
+ strictControlTool("events_subscribers_list", "List subscribers", "Lists immutable subscriber metadata.", {}, () => subscribersList(options));
960
+ strictControlTool("events_subscriber_add", "Add subscriber", "Creates one immutable subscriber version.", { document: unknown() }, (args) => addSubscriber(args.document, options), true);
961
+ strictControlTool("events_subscriber_update", "Update subscriber", "Creates one replacement immutable subscriber version.", { document: unknown() }, (args) => updateSubscriber(args.document, options), true);
962
+ strictControlTool("events_subscriber_remove", "Remove subscriber", "Revokes every live version of one subscriber and closes its streams.", { subscriberId: string().min(1) }, (args) => removeSubscriber(args.subscriberId, options), true);
963
+ strictControlTool("events_judges_list", "List judges", "Lists content-free immutable judge metadata.", {}, () => judgesList(options));
964
+ strictControlTool("events_judge_add", "Add judge", "Creates an immutable, initially inactive judge version.", { document: unknown() }, (args) => b3("addJudge", { document: args.document }, () => addJudge(args.document, options)), true);
965
+ strictControlTool("events_judge_update", "Update judge", "Creates an immutable replacement judge version.", { document: unknown() }, (args) => b3("updateJudge", { document: args.document }, () => updateJudge(args.document, options)), true);
966
+ strictControlTool("events_judge_remove", "Remove judge", "Removes every live immutable version of one judge.", { judgeId: string().min(1) }, (args) => b3("removeJudge", { judgeId: args.judgeId }, () => removeJudge(args.judgeId, options)), true);
967
+ strictControlTool("events_judge_test", "Test judge", "Tests one active exact judge version with the daemon-fixed synthetic event.", {
968
+ judgeId: string().min(1),
969
+ version: number().int().positive()
970
+ }, (args) => judgeTest(args.judgeId, args.version, options));
971
+ strictControlTool("events_budget_show", "Show budget", "Lists immutable judge budgets and the active singleton.", {}, () => budgetShow(options));
972
+ strictControlTool("events_budget_update", "Update budget", "Creates a pending immutable global budget and prepares its approval.", { document: unknown() }, (args) => b3("updateBudget", { document: args.document }, () => updateBudget(args.document, options)), true);
973
+ strictControlTool("events_judge_kinds_list", "List judge kinds", "Lists disabled/enabled judge kinds and the typed Laya E2 seam.", {}, () => judgeKindsList(options));
974
+ strictControlTool("events_judge_kind_enable", "Enable judge kind", "Prepares, but never approves or claims, judge-kind enablement.", { kind: string().min(1) }, (args) => b3("enableJudgeKind", { kind: args.kind }, () => enableJudgeKind(args.kind, options)), true);
975
+ strictControlTool("events_judge_kind_disable", "Disable judge kind", "Immediately disables one available judge kind; Laya remains typed E2-unavailable.", { kind: string().min(1) }, (args) => {
976
+ const kind = args.kind;
977
+ return b3("disableJudgeKind", { kind }, () => disableJudgeKind(kind, options));
978
+ }, true);
979
+ strictControlTool("events_judge_model_status", "Judge model status", "Returns the typed Phase-E2 unavailable result.", {}, () => judgeModelStatus(options));
980
+ strictControlTool("events_judge_model_remove", "Remove judge model", "Returns the typed Phase-E2 unavailable result.", {}, () => removeJudgeModel(options), true);
981
+ strictControlTool("events_deliveries_list", "List deliveries", "Lists content-free delivery metadata.", {}, () => deliveriesList(options));
982
+ strictControlTool("events_delivery_retry", "Retry delivery", "Retries one exact retryable delivery.", { deliveryId: string().min(1) }, (args) => retryDelivery(args.deliveryId, options), true);
983
+ strictControlTool("events_delivery_drop", "Drop delivery", "Drops one exact dead-letter delivery and its retained payload.", { deliveryId: string().min(1) }, (args) => dropDelivery(args.deliveryId, options), true);
984
+ strictControlTool("events_held_list", "List held decisions", "Lists content-free held-decision metadata; only a terminal/app may resolve one.", {}, () => heldList(options));
985
+ controlTool("events_catalogue_show", "Show local event definition", "Shows one selectable local event definition.", { type: string() }, (args) => catalogueShow(args.type, options));
986
+ controlTool("events_sources_list", "List event sources", "Lists configured local event sources.", {}, () => sourcesList(options));
987
+ controlTool("events_source_show", "Show event source", "Shows one configured local event source.", { source: string() }, (args) => sourceShow(args.source, options));
988
+ controlTool("events_rules_list", "List event rules", "Lists immutable local event rule versions.", {}, () => rulesList(options));
989
+ controlTool("events_rule_show", "Show event rule", "Shows immutable versions of one event rule.", { ruleId: string() }, (args) => ruleShow(args.ruleId, options));
990
+ controlTool("events_rule_create", "Create inert event rule", "Creates an inert immutable event rule version.", { document: unknown() }, (args) => createRule(args.document, options), true);
991
+ controlTool("events_rule_update", "Update event rule", "Creates another inert immutable event rule version.", { document: unknown() }, (args) => updateRule(args.document, options), true);
992
+ controlTool("events_rule_enable", "Prepare event rule enablement", "Prepares the standing disclosure for a rule version.", {
993
+ ruleId: string(),
994
+ version: number().int().positive()
995
+ }, (args) => enableRule(args.ruleId, args.version, options), true);
996
+ controlTool("events_rule_disable", "Disable event rule", "Immediately disables the active event rule.", { ruleId: string() }, (args) => disableRule(args.ruleId, options), true);
997
+ controlTool("events_rule_remove", "Remove event rule", "Immediately removes the active event rule.", { ruleId: string() }, (args) => removeRule(args.ruleId, options), true);
998
+ controlTool("events_targets_list", "List event targets", "Lists immutable local event target versions.", {}, () => targetsList(options));
999
+ controlTool("events_target_add", "Add inert event target", "Creates an inert immutable dry-run target.", { document: unknown() }, (args) => addTarget(args.document, options), true);
1000
+ controlTool("events_target_update", "Update event target", "Creates another inert immutable dry-run target version.", { document: unknown() }, (args) => updateTarget(args.document, options), true);
1001
+ controlTool("events_target_remove", "Remove event target", "Revokes every live version of a dry-run target.", { targetId: string() }, (args) => removeTarget(args.targetId, options), true);
1002
+ return {
1003
+ server,
1004
+ async connectStdio() {
1005
+ const { StdioServerTransport } = await import("./stdio-CD7QQBAh.mjs");
1006
+ await server.connect(new StdioServerTransport());
1007
+ }
1008
+ };
1009
+ }
1010
+ //#endregion
1011
+ //#region src/domain/judges.ts
1012
+ const TYPESAFE_SYSTEM_ONE_ENDPOINT = "https://api.typesafe.ai/v1/systemone";
1013
+ const JUDGE_BUDGET_ID = "judge-budget";
1014
+ /** Provider record: docs/superpowers/plans/2026-10-10-events-phase-e-provider-record.md, read 2026-10-10. */
1015
+ const APPROVED_TYPESAFE_MODELS = ["jev-1.13.0"];
1016
+ /** Phase E's closed registry. The lifecycle module owns the literal vocabulary; this registry owns its availability. */
1017
+ const JUDGE_KIND_DEFINITIONS = [
1018
+ {
1019
+ kind: JUDGE_KINDS[0],
1020
+ availability: "available"
1021
+ },
1022
+ {
1023
+ kind: JUDGE_KINDS[1],
1024
+ availability: "unavailable",
1025
+ unavailableCode: "E2_REQUIRED"
1026
+ },
1027
+ {
1028
+ kind: JUDGE_KINDS[2],
1029
+ availability: "available"
1030
+ }
1031
+ ];
1032
+ function fail$3(message, code = "VERSION_DOCUMENT_INVALID") {
1033
+ throw new EventDomainError(code, message);
1034
+ }
1035
+ function record$1(value, name) {
1036
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return fail$3(`${name} is an object`);
1037
+ try {
1038
+ return JSON.parse(canonicalJson(value));
1039
+ } catch {
1040
+ return fail$3(`${name} is canonical JSON`);
1041
+ }
1042
+ }
1043
+ function exactKeys$1(value, keys, name) {
1044
+ const found = Object.keys(value).sort();
1045
+ const wanted = [...keys].sort();
1046
+ if (found.length !== wanted.length || found.some((key, index) => key !== wanted[index])) fail$3(`${name} has exactly its canonical fields`);
1047
+ }
1048
+ function text$1(value, name) {
1049
+ if (typeof value !== "string" || value.length === 0) return fail$3(`${name} is a non-empty string`);
1050
+ return value;
1051
+ }
1052
+ function positiveInteger$2(value, name) {
1053
+ if (!Number.isSafeInteger(value) || value < 1) return fail$3(`${name} is a positive safe integer`);
1054
+ return value;
1055
+ }
1056
+ function protocol(value, name) {
1057
+ if (value.protocol === "noul") {
1058
+ exactKeys$1(value, ["protocol"], name);
1059
+ return { protocol: "noul" };
1060
+ }
1061
+ if (value.protocol !== "json-score") return fail$3(`${name} has protocol noul or json-score`);
1062
+ exactKeys$1(value, ["protocol", "scorePointer"], name);
1063
+ const scorePointer = text$1(value.scorePointer, `${name} scorePointer`);
1064
+ const parsed = parsePointer(scorePointer);
1065
+ if (!parsed.ok || parsed.value.includes("*")) return fail$3(`${name} scorePointer is one concrete JSON Pointer`);
1066
+ return {
1067
+ protocol: "json-score",
1068
+ scorePointer
1069
+ };
1070
+ }
1071
+ function identity(value, name) {
1072
+ return {
1073
+ judgeId: text$1(value.judgeId, `${name} id`),
1074
+ version: positiveInteger$2(value.version, `${name} version`)
1075
+ };
1076
+ }
1077
+ function localAddress(value) {
1078
+ if (!Array.isArray(value) || value.length !== 1) return fail$3("a local judge approvedAddressSet has one exact literal");
1079
+ const entry = text$1(value[0], "a local judge approvedAddressSet entry");
1080
+ try {
1081
+ assertApprovedAddressSet([entry]);
1082
+ return [parseIpLiteral(entry).address];
1083
+ } catch {
1084
+ return fail$3("a local judge approvedAddressSet has one valid literal");
1085
+ }
1086
+ }
1087
+ /** The one canonical, immutable judge document form. E2's laya seam is recognised but intentionally unavailable. */
1088
+ function canonicalJudge(value) {
1089
+ const judge = record$1(value, "a judge document");
1090
+ const kind = judge.kind;
1091
+ if (!JUDGE_KINDS.includes(kind)) return fail$3("a judge document has a known judge kind");
1092
+ if (kind === "laya") return fail$3("laya is unavailable until E2", "E2_REQUIRED");
1093
+ if (kind === "typesafe") {
1094
+ exactKeys$1(judge, [
1095
+ "judgeId",
1096
+ "version",
1097
+ "kind",
1098
+ "provider",
1099
+ "model",
1100
+ "endpoint",
1101
+ "promptTemplate",
1102
+ "protocol"
1103
+ ], "a typesafe judge document");
1104
+ if (judge.provider !== "typesafe") return fail$3("a typesafe judge names the TypeSafe Jev adapter");
1105
+ if (!APPROVED_TYPESAFE_MODELS.includes(judge.model)) return fail$3("a typesafe judge names one concrete model listed in the provider record");
1106
+ if (judge.endpoint !== "https://api.typesafe.ai/v1/systemone") return fail$3("a typesafe judge has its fixed System One endpoint");
1107
+ if (protocol({ protocol: judge.protocol }, "a typesafe judge document").protocol !== "noul") return fail$3("a typesafe judge uses the noul protocol");
1108
+ return {
1109
+ ...identity(judge, "a typesafe judge"),
1110
+ kind: JUDGE_KIND_TYPESAFE,
1111
+ provider: JUDGE_KIND_TYPESAFE,
1112
+ model: judge.model,
1113
+ endpoint: TYPESAFE_SYSTEM_ONE_ENDPOINT,
1114
+ promptTemplate: text$1(judge.promptTemplate, "a typesafe judge prompt template"),
1115
+ protocol: "noul"
1116
+ };
1117
+ }
1118
+ const localProtocol = protocol(judge.protocol === "json-score" ? {
1119
+ protocol: judge.protocol,
1120
+ scorePointer: judge.scorePointer
1121
+ } : { protocol: judge.protocol }, "a local judge document");
1122
+ exactKeys$1(judge, localProtocol.protocol === "json-score" ? [
1123
+ "judgeId",
1124
+ "version",
1125
+ "kind",
1126
+ "provider",
1127
+ "model",
1128
+ "endpoint",
1129
+ "approvedAddressSet",
1130
+ "promptTemplate",
1131
+ "protocol",
1132
+ "scorePointer"
1133
+ ] : [
1134
+ "judgeId",
1135
+ "version",
1136
+ "kind",
1137
+ "provider",
1138
+ "model",
1139
+ "endpoint",
1140
+ "approvedAddressSet",
1141
+ "promptTemplate",
1142
+ "protocol"
1143
+ ], "a local judge document");
1144
+ const approvedAddressSet = localAddress(judge.approvedAddressSet);
1145
+ const endpoint = text$1(judge.endpoint, "a local judge endpoint");
1146
+ try {
1147
+ const local = validateLocalEndpoint(endpoint, approvedAddressSet);
1148
+ if (local.url.search !== "") return fail$3("a local judge endpoint has no query");
1149
+ return {
1150
+ ...identity(judge, "a local judge"),
1151
+ kind: JUDGE_KIND_LOCAL_ENDPOINT,
1152
+ provider: text$1(judge.provider, "a local judge provider"),
1153
+ model: text$1(judge.model, "a local judge model"),
1154
+ endpoint: local.url.href,
1155
+ approvedAddressSet,
1156
+ promptTemplate: text$1(judge.promptTemplate, "a local judge prompt template"),
1157
+ ...localProtocol
1158
+ };
1159
+ } catch (error) {
1160
+ if (error instanceof EventDomainError) throw error;
1161
+ return fail$3("a local judge has a literal loopback endpoint and its exact approved address");
1162
+ }
1163
+ }
1164
+ function limits(value, name) {
1165
+ const limit = record$1(value, name);
1166
+ exactKeys$1(limit, [
1167
+ "callsPerRollingHour",
1168
+ "inputTokensPerRolling30Days",
1169
+ "concurrency"
1170
+ ], name);
1171
+ return {
1172
+ callsPerRollingHour: positiveInteger$2(limit.callsPerRollingHour, `${name} callsPerRollingHour`),
1173
+ inputTokensPerRolling30Days: positiveInteger$2(limit.inputTokensPerRolling30Days, `${name} inputTokensPerRolling30Days`),
1174
+ concurrency: positiveInteger$2(limit.concurrency, `${name} concurrency`)
1175
+ };
1176
+ }
1177
+ /** The singleton's complete global and per-provider rolling ceilings, with no implicit defaults. */
1178
+ function canonicalJudgeBudget(value) {
1179
+ const budget = record$1(value, "a judge budget document");
1180
+ exactKeys$1(budget, [
1181
+ "budgetId",
1182
+ "version",
1183
+ "global",
1184
+ "providers"
1185
+ ], "a judge budget document");
1186
+ if (budget.budgetId !== "judge-budget") return fail$3(`a judge budget id is ${JUDGE_BUDGET_ID}`);
1187
+ if (!Array.isArray(budget.providers)) return fail$3("judge budget providers are an array");
1188
+ const providers = budget.providers.map((entry) => {
1189
+ const provider = record$1(entry, "a judge provider budget");
1190
+ exactKeys$1(provider, [
1191
+ "provider",
1192
+ "callsPerRollingHour",
1193
+ "inputTokensPerRolling30Days",
1194
+ "concurrency"
1195
+ ], "a judge provider budget");
1196
+ return {
1197
+ provider: text$1(provider.provider, "a judge provider id"),
1198
+ callsPerRollingHour: positiveInteger$2(provider.callsPerRollingHour, "a judge provider budget callsPerRollingHour"),
1199
+ inputTokensPerRolling30Days: positiveInteger$2(provider.inputTokensPerRolling30Days, "a judge provider budget inputTokensPerRolling30Days"),
1200
+ concurrency: positiveInteger$2(provider.concurrency, "a judge provider budget concurrency")
1201
+ };
1202
+ });
1203
+ if ([...providers].sort((left, right) => left.provider < right.provider ? -1 : left.provider > right.provider ? 1 : 0).some((entry, index) => entry.provider !== providers[index]?.provider) || new Set(providers.map((entry) => entry.provider)).size !== providers.length) return fail$3("judge budget providers are sorted and duplicate-free");
1204
+ return {
1205
+ budgetId: JUDGE_BUDGET_ID,
1206
+ version: positiveInteger$2(budget.version, "a judge budget version"),
1207
+ global: limits(budget.global, "a global judge budget"),
1208
+ providers
1209
+ };
1210
+ }
1211
+ /** The closed kind registry lookup, including E2's intentionally unavailable laya slot. */
1212
+ function judgeKindDefinition(kind) {
1213
+ const definition = JUDGE_KIND_DEFINITIONS.find((candidate) => candidate.kind === kind);
1214
+ if (definition === void 0) return fail$3("a judge kind has a registry definition");
1215
+ return definition;
1216
+ }
1217
+ /** Canonicalises one inert kind-enablement version; no pointer or availability change happens here. */
1218
+ function canonicalJudgeKindEnablement(value) {
1219
+ const enablement = record$1(value, "a judge-kind document");
1220
+ if (!JUDGE_KINDS.includes(enablement.kind)) return fail$3("a judge-kind document has a known judge kind");
1221
+ const kind = enablement.kind;
1222
+ if (judgeKindDefinition(kind).availability === "unavailable") return fail$3("laya is unavailable until E2", "E2_REQUIRED");
1223
+ const id = `judge-kind:${kind}`;
1224
+ if (enablement.id !== id) return fail$3(`a judge-kind document id is ${id}`);
1225
+ if (kind === "typesafe") {
1226
+ exactKeys$1(enablement, [
1227
+ "id",
1228
+ "kind",
1229
+ "version",
1230
+ "endpoint"
1231
+ ], "a typesafe judge-kind document");
1232
+ if (enablement.endpoint !== "https://api.typesafe.ai/v1/systemone") return fail$3("a typesafe judge-kind document has the fixed System One endpoint");
1233
+ return {
1234
+ id: "judge-kind:typesafe",
1235
+ kind: JUDGE_KIND_TYPESAFE,
1236
+ version: positiveInteger$2(enablement.version, "a judge-kind version"),
1237
+ endpoint: TYPESAFE_SYSTEM_ONE_ENDPOINT
1238
+ };
1239
+ }
1240
+ exactKeys$1(enablement, [
1241
+ "id",
1242
+ "kind",
1243
+ "version"
1244
+ ], "a local-endpoint judge-kind document");
1245
+ return {
1246
+ id: "judge-kind:local-endpoint",
1247
+ kind: JUDGE_KIND_LOCAL_ENDPOINT,
1248
+ version: positiveInteger$2(enablement.version, "a judge-kind version")
1249
+ };
1250
+ }
1251
+ //#endregion
1252
+ //#region src/domain/source-options.ts
1253
+ function fail$2(message) {
1254
+ throw new EventDomainError("VERSION_DOCUMENT_INVALID", message);
1255
+ }
1256
+ function isRecord$2(value) {
1257
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1258
+ }
1259
+ function exactKeys(value, keys, name) {
1260
+ if (Object.keys(value).find((key) => !keys.includes(key)) !== void 0) fail$2(`${name} has a field it does not define`);
1261
+ for (const key of keys) if (!Object.hasOwn(value, key)) fail$2(`${name} has a ${key} field`);
1262
+ }
1263
+ function compareUtf8(left, right) {
1264
+ const leftBytes = new TextEncoder().encode(left);
1265
+ const rightBytes = new TextEncoder().encode(right);
1266
+ const length = Math.min(leftBytes.byteLength, rightBytes.byteLength);
1267
+ for (let index = 0; index < length; index += 1) {
1268
+ const difference = (leftBytes[index] ?? 0) - (rightBytes[index] ?? 0);
1269
+ if (difference !== 0) return difference;
1270
+ }
1271
+ return leftBytes.byteLength - rightBytes.byteLength;
1272
+ }
1273
+ function canonicalIds(value, name) {
1274
+ if (!Array.isArray(value) || value.length === 0 || !value.every((entry) => typeof entry === "string" && entry !== "")) return fail$2(`${name} is a non-empty id array`);
1275
+ const ids = [...value];
1276
+ for (let index = 1; index < ids.length; index += 1) if (compareUtf8(ids[index - 1], ids[index]) >= 0) return fail$2(`${name} is duplicate-free and sorted by raw UTF-8 bytes`);
1277
+ return ids;
1278
+ }
1279
+ function canonicalLabels(value) {
1280
+ if (value === "inbox" || value === "any") return value;
1281
+ const labels = canonicalIds(value, "Gmail label ids");
1282
+ if (labels.includes("INBOX")) return fail$2("the Gmail INBOX selector is written as labels: inbox");
1283
+ return labels;
1284
+ }
1285
+ /** Validates the Gmail source shape without silently reordering an authority-bound label array. */
1286
+ function normaliseGmailSourceOptions(value) {
1287
+ if (!isRecord$2(value) || value.channel !== "gmail") return fail$2("a Gmail source option names the Gmail channel");
1288
+ exactKeys(value, [
1289
+ "channel",
1290
+ "labels",
1291
+ "includeSpamTrash"
1292
+ ], "a Gmail source option");
1293
+ if (typeof value.includeSpamTrash !== "boolean") return fail$2("Gmail includeSpamTrash is a boolean");
1294
+ return {
1295
+ channel: "gmail",
1296
+ labels: canonicalLabels(value.labels),
1297
+ includeSpamTrash: value.includeSpamTrash
1298
+ };
1299
+ }
1300
+ /** Validates the Phase-D Slack source shape, retaining only canonical conversation ids. */
1301
+ function normaliseSlackSourceOptions(value) {
1302
+ if (!isRecord$2(value) || value.channel !== "slack") return fail$2("a Slack source option names the Slack channel");
1303
+ exactKeys(value, ["channel", "conversations"], "a Slack source option");
1304
+ return {
1305
+ channel: "slack",
1306
+ conversations: canonicalIds(value.conversations, "Slack conversations")
1307
+ };
1308
+ }
1309
+ /** Validates Resend's fixed-order, non-empty event-kind set. */
1310
+ function normaliseResendSourceOptions(value) {
1311
+ if (!isRecord$2(value) || value.channel !== "resend") return fail$2("a Resend source option names the Resend channel");
1312
+ exactKeys(value, ["channel", "kinds"], "a Resend source option");
1313
+ if (!Array.isArray(value.kinds) || value.kinds.length === 0) return fail$2("Resend kinds are a non-empty array");
1314
+ const kinds = [...value.kinds];
1315
+ if (!kinds.every((kind) => kind === "received" || kind === "status")) return fail$2("Resend kinds are received and status");
1316
+ const expected = [...new Set(kinds)].sort((left, right) => left === "received" ? -1 : right === "received" ? 1 : 0);
1317
+ if (expected.length !== kinds.length || expected.some((kind, index) => kind !== kinds[index])) return fail$2("Resend kinds are duplicate-free and ordered received, status");
1318
+ return {
1319
+ channel: "resend",
1320
+ kinds
1321
+ };
1322
+ }
1323
+ /** Validates the raw WhatsApp chat selector; JIDs stay raw authority-bound strings. */
1324
+ function normaliseWhatsAppSourceOptions(value) {
1325
+ if (!isRecord$2(value) || value.channel !== "whatsapp") return fail$2("a WhatsApp source option names the WhatsApp channel");
1326
+ exactKeys(value, ["channel", "chats"], "a WhatsApp source option");
1327
+ return {
1328
+ channel: "whatsapp",
1329
+ chats: value.chats === "all-allowed" ? "all-allowed" : canonicalIds(value.chats, "WhatsApp chats")
1330
+ };
1331
+ }
1332
+ /** D4's closed four-channel source-options union. */
1333
+ function normaliseSourceOptions(value) {
1334
+ if (!isRecord$2(value)) return fail$2("a source option is an object");
1335
+ switch (value.channel) {
1336
+ case "gmail": return normaliseGmailSourceOptions(value);
1337
+ case "slack": return normaliseSlackSourceOptions(value);
1338
+ case "resend": return normaliseResendSourceOptions(value);
1339
+ case "whatsapp": return normaliseWhatsAppSourceOptions(value);
1340
+ default: return fail$2("a source option has a known channel");
1341
+ }
1342
+ }
1343
+ function labelSet(options) {
1344
+ if (options.labels === "any") return null;
1345
+ return new Set(options.labels === "inbox" ? ["INBOX"] : options.labels);
1346
+ }
1347
+ function classifySubset(before, after) {
1348
+ const previous = new Set(before);
1349
+ const next = new Set(after);
1350
+ if (previous.size === next.size && [...previous].every((value) => next.has(value))) return "same";
1351
+ return [...next].every((value) => previous.has(value)) ? "tightening" : "loosening";
1352
+ }
1353
+ /** D2's field-by-field Gmail narrowing rule. Any additive change keeps the whole edit a loosening. */
1354
+ function classifyGmailSourceOptionChange(before, after) {
1355
+ const previous = normaliseGmailSourceOptions(before);
1356
+ const next = normaliseGmailSourceOptions(after);
1357
+ if (previous.labels === next.labels && previous.includeSpamTrash === next.includeSpamTrash) return "same";
1358
+ if (previous.labels === "any") {
1359
+ if (next.labels === "any") return previous.includeSpamTrash === next.includeSpamTrash ? "same" : next.includeSpamTrash ? "loosening" : "tightening";
1360
+ return !previous.includeSpamTrash && next.includeSpamTrash ? "loosening" : "tightening";
1361
+ }
1362
+ if (next.labels === "any") return "loosening";
1363
+ const previousLabels = labelSet(previous);
1364
+ const nextLabels = labelSet(next);
1365
+ const added = [...nextLabels].some((label) => !previousLabels.has(label));
1366
+ const removed = [...previousLabels].some((label) => !nextLabels.has(label));
1367
+ const spamLoosened = !previous.includeSpamTrash && next.includeSpamTrash;
1368
+ const spamTightened = previous.includeSpamTrash && !next.includeSpamTrash;
1369
+ if (added || spamLoosened) return "loosening";
1370
+ if (removed || spamTightened) return "tightening";
1371
+ return "same";
1372
+ }
1373
+ /** D2/D4's one source-option classifier; different source variants can never become a derived edge. */
1374
+ function classifySourceOptionChange(before, after) {
1375
+ const previous = normaliseSourceOptions(before);
1376
+ const next = normaliseSourceOptions(after);
1377
+ if (previous.channel !== next.channel) return fail$2("source options for a derived edit name the same channel");
1378
+ switch (previous.channel) {
1379
+ case "gmail": return classifyGmailSourceOptionChange(previous, next);
1380
+ case "slack":
1381
+ if (next.channel !== "slack") return fail$2("source options for a derived edit name the same channel");
1382
+ return classifySubset(previous.conversations, next.conversations);
1383
+ case "resend":
1384
+ if (next.channel !== "resend") return fail$2("source options for a derived edit name the same channel");
1385
+ return classifySubset(previous.kinds, next.kinds);
1386
+ case "whatsapp":
1387
+ if (next.channel !== "whatsapp") return fail$2("source options for a derived edit name the same channel");
1388
+ if (previous.chats === "all-allowed") return next.chats === "all-allowed" ? "same" : "tightening";
1389
+ if (next.chats === "all-allowed") return "loosening";
1390
+ return classifySubset(previous.chats, next.chats);
1391
+ }
1392
+ }
1393
+ //#endregion
1394
+ //#region src/domain/sse-subscriber.ts
1395
+ function fail$1(message) {
1396
+ throw new EventDomainError("VERSION_DOCUMENT_INVALID", message);
1397
+ }
1398
+ function record(value, name) {
1399
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return fail$1(`${name} is an object`);
1400
+ try {
1401
+ return JSON.parse(canonicalJson(value));
1402
+ } catch {
1403
+ return fail$1(`${name} is canonical JSON`);
1404
+ }
1405
+ }
1406
+ function text(value, name) {
1407
+ if (typeof value !== "string" || value.length === 0) return fail$1(`${name} is a non-empty string`);
1408
+ return value;
1409
+ }
1410
+ function positiveInteger$1(value, name) {
1411
+ if (!Number.isSafeInteger(value) || value < 1) return fail$1(`${name} is a positive safe integer`);
1412
+ return value;
1413
+ }
1414
+ function canonicalOrigin(value) {
1415
+ const origin = text(value, "an SSE allowed Origin");
1416
+ let parsed;
1417
+ try {
1418
+ parsed = new URL(origin);
1419
+ } catch {
1420
+ return fail$1("an SSE allowed Origin is a URL origin");
1421
+ }
1422
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || parsed.origin !== origin) return fail$1("an SSE allowed Origin is an exact http or https origin");
1423
+ return origin;
1424
+ }
1425
+ /** Canonicalises listener authority, exact browser origins and replay retention; bearer bytes are absent. */
1426
+ function canonicalSseSubscriber(value) {
1427
+ const subscriber = record(value, "an SSE subscriber document");
1428
+ if (subscriber.kind !== "sse") return fail$1("an SSE subscriber document has kind sse");
1429
+ const authority = record(subscriber.authority, "an SSE subscriber authority");
1430
+ const host = text(authority.host, "an SSE subscriber authority host");
1431
+ if (host !== "127.0.0.1" && host !== "::1") return fail$1("an SSE subscriber authority host is literal loopback");
1432
+ const origins = Array.isArray(subscriber.origins) ? subscriber.origins.map(canonicalOrigin) : fail$1("SSE allowed Origins are an array");
1433
+ if (origins.length === 0 || new Set(origins).size !== origins.length || [...origins].sort().some((origin, index) => origin !== origins[index])) return fail$1("SSE allowed Origins are non-empty, sorted and duplicate-free");
1434
+ const retentionMs = positiveInteger$1(subscriber.retentionMs, "SSE replay retention");
1435
+ if (retentionMs > 6048e5) return fail$1("SSE replay retention is at most seven days");
1436
+ const port = positiveInteger$1(authority.port, "an SSE subscriber authority port");
1437
+ if (port > 65535) return fail$1("an SSE subscriber authority port is at most 65535");
1438
+ return {
1439
+ subscriberId: text(subscriber.subscriberId, "an SSE subscriber id"),
1440
+ version: positiveInteger$1(subscriber.version, "an SSE subscriber version"),
1441
+ kind: "sse",
1442
+ authority: {
1443
+ host,
1444
+ port
1445
+ },
1446
+ origins,
1447
+ retentionMs
1448
+ };
1449
+ }
1450
+ /** Canonicalises a target's immutable binding to an SSE subscriber version. */
1451
+ function canonicalSseTarget(value) {
1452
+ const target = record(value, "an SSE target document");
1453
+ if (target.kind !== "sse") return fail$1("an SSE target document has kind sse");
1454
+ if (target.representation !== "plain" && target.representation !== "enveloped") return fail$1("an SSE target representation is plain or enveloped");
1455
+ return {
1456
+ targetId: text(target.targetId, "an SSE target id"),
1457
+ version: positiveInteger$1(target.version, "an SSE target version"),
1458
+ kind: "sse",
1459
+ subscriberId: text(target.subscriberId, "an SSE target subscriber id"),
1460
+ subscriberVersion: positiveInteger$1(target.subscriberVersion, "an SSE target subscriber version"),
1461
+ representation: target.representation
1462
+ };
1463
+ }
1464
+ /** Maps an exact target/subscriber binding to Task 2's closed delivery union. */
1465
+ function sseDeliveryTarget(input) {
1466
+ return {
1467
+ kind: "sse",
1468
+ targetId: input.targetId,
1469
+ targetVersion: input.version,
1470
+ subscriberId: input.subscriber.subscriberId,
1471
+ subscriberVersion: input.subscriber.version,
1472
+ representation: input.representation
1473
+ };
1474
+ }
1475
+ //#endregion
1476
+ //#region src/domain/activation-documents.ts
1477
+ function isRecord$1(value) {
1478
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1479
+ }
1480
+ function fail(message, code = "VERSION_DOCUMENT_INVALID") {
1481
+ throw new EventDomainError(code, message);
1482
+ }
1483
+ function requiredText(value, name) {
1484
+ if (typeof value !== "string" || value.length === 0) return fail(`${name} is a non-empty string`);
1485
+ return value;
1486
+ }
1487
+ function positiveInteger(value, name) {
1488
+ if (!Number.isSafeInteger(value) || value < 1) return fail(`${name} is a positive safe integer`);
1489
+ return value;
1490
+ }
1491
+ function cloneJsonRecord(value, name) {
1492
+ if (!isRecord$1(value)) return fail(`${name} is a JSON object`);
1493
+ try {
1494
+ return JSON.parse(canonicalJson(value));
1495
+ } catch {
1496
+ return fail(`${name} is canonical JSON`);
1497
+ }
1498
+ }
1499
+ function canonicalJsonValue(value, name) {
1500
+ if (!isJsonValue(value)) return fail(`${name} is a JSON value`);
1501
+ try {
1502
+ return JSON.parse(canonicalJson(value));
1503
+ } catch {
1504
+ return fail(`${name} is canonical JSON`);
1505
+ }
1506
+ }
1507
+ function compareText(left, right) {
1508
+ return left < right ? -1 : left > right ? 1 : 0;
1509
+ }
1510
+ function canonicalStringSet(value, name) {
1511
+ if (!Array.isArray(value) || value.length === 0) return fail(`${name} is a non-empty array`);
1512
+ const values = value.map((entry) => requiredText(entry, name));
1513
+ const sorted = [...new Set(values)].sort(compareText);
1514
+ if (sorted.length !== values.length) return fail(`${name} has no duplicate values`);
1515
+ return sorted;
1516
+ }
1517
+ /** The canonical immutable target document — stored, and embedded in every rule that names it. */
1518
+ function canonicalTarget(value) {
1519
+ const target = cloneJsonRecord(value, "a target document");
1520
+ switch (target.kind) {
1521
+ case "dry-run": {
1522
+ const retentionMs = positiveInteger(target.retentionMs, "a dry-run retention");
1523
+ if (retentionMs > 864e5) return fail("a dry-run retention is at most 24 hours");
1524
+ return {
1525
+ targetId: requiredText(target.targetId, "a target id"),
1526
+ version: positiveInteger(target.version, "a target version"),
1527
+ kind: "dry-run",
1528
+ retentionMs
1529
+ };
1530
+ }
1531
+ case "webhook": return canonicalWebhookTarget(target);
1532
+ case "sse": return canonicalSseTarget(target);
1533
+ default: return fail("a target document has a known kind");
1534
+ }
1535
+ }
1536
+ /** The one canonical form of a subscriber version — stored, and embedded in every rule that names it. */
1537
+ function canonicalSubscriber(value) {
1538
+ const subscriber = cloneJsonRecord(value, "a subscriber document");
1539
+ if (subscriber.kind !== "sse") return fail("a subscriber document has a known kind");
1540
+ return canonicalSseSubscriber(subscriber);
1541
+ }
1542
+ function canonicalRetention(value) {
1543
+ const retention = cloneJsonRecord(value, "rule retention");
1544
+ const result = {
1545
+ ingestMs: positiveInteger(retention.ingestMs, "ingest retention"),
1546
+ holdMs: positiveInteger(retention.holdMs, "hold retention"),
1547
+ deliveryMs: positiveInteger(retention.deliveryMs, "delivery retention"),
1548
+ dryrunMs: positiveInteger(retention.dryrunMs, "dry-run retention"),
1549
+ sseReplayMs: positiveInteger(retention.sseReplayMs, "SSE replay retention"),
1550
+ deadLetterMs: positiveInteger(retention.deadLetterMs, "dead-letter retention"),
1551
+ decisionMetadataMs: positiveInteger(retention.decisionMetadataMs, "decision metadata retention")
1552
+ };
1553
+ if (result.holdMs > result.ingestMs) return fail("hold retention cannot outlive ingest retention");
1554
+ if (result.dryrunMs > 864e5) return fail("dry-run retention is at most 24 hours");
1555
+ return result;
1556
+ }
1557
+ function canonicalRuleSource(value) {
1558
+ const source = cloneJsonRecord(value, "rule source");
1559
+ const options = normaliseSourceOptions(source.options);
1560
+ if (source.channel !== options.channel) return fail("rule source channel and source options channel agree");
1561
+ const accountIds = canonicalStringSet(source.accountIds, "rule account ids");
1562
+ switch (options.channel) {
1563
+ case "gmail": return {
1564
+ channel: "gmail",
1565
+ accountIds,
1566
+ options
1567
+ };
1568
+ case "slack": return {
1569
+ channel: "slack",
1570
+ accountIds,
1571
+ options
1572
+ };
1573
+ case "resend": return {
1574
+ channel: "resend",
1575
+ accountIds,
1576
+ options
1577
+ };
1578
+ case "whatsapp": return {
1579
+ channel: "whatsapp",
1580
+ accountIds,
1581
+ options
1582
+ };
1583
+ }
1584
+ }
1585
+ /** Validates a Phase-D full rule shape and returns its canonical data-only form. */
1586
+ function canonicalFullRuleDocument(value) {
1587
+ const rule = cloneJsonRecord(value, "a rule document");
1588
+ const source = canonicalRuleSource(rule.source);
1589
+ const event = cloneJsonRecord(rule.event, "rule event");
1590
+ const eventType = requiredText(event.type, "an event type");
1591
+ if (eventType === TEST_CLOUD_EVENT.type || eventType === "io.agentcomms.control.installation-reset.v1") return fail("operational, test and reset controls are not selectable rule event types", "EVENT_TYPE_NOT_SELECTABLE");
1592
+ const eventVersion = positiveInteger(event.version, "an event version");
1593
+ const definition = catalogueEntry(eventType, eventVersion);
1594
+ if (!definition.ok) return fail(definition.issues[0]?.message ?? "the event type is not selectable", definition.issues[0]?.code);
1595
+ if (!eventType.startsWith(`${source.channel}.`)) return fail("a rule event type belongs to its source channel", "SOURCE_CHANNEL_UNSUPPORTED");
1596
+ const condition = canonicaliseCondition(definition.value, rule.condition);
1597
+ if (!condition.ok) return fail(condition.issues[0]?.message ?? "the rule condition is not valid");
1598
+ let agentic;
1599
+ if (rule.agentic !== void 0) {
1600
+ const canonical = canonicaliseAgenticCondition(definition.value, condition.value, rule.agentic);
1601
+ if (!canonical.ok) return fail(canonical.issues[0]?.message ?? "the rule agentic condition is not valid");
1602
+ agentic = {
1603
+ ...canonical.value,
1604
+ judge: canonicalJudge(canonical.value.judge)
1605
+ };
1606
+ }
1607
+ const mapping = canonicalJsonValue(rule.mapping, "rule mapping");
1608
+ const compiledMapping = compileMapping(definition.value, mapping);
1609
+ if (!compiledMapping.ok) return fail(compiledMapping.issues[0]?.message ?? "the rule mapping is not valid");
1610
+ const targets = Array.isArray(rule.targets) ? rule.targets.map(canonicalTarget) : fail("rule targets are an array");
1611
+ if (targets.length === 0) return fail("a B1 rule has at least one dry-run target");
1612
+ const subscribers = Array.isArray(rule.subscribers) ? rule.subscribers.map(canonicalSubscriber) : fail("rule subscribers are an array");
1613
+ for (const target of targets) {
1614
+ if (target.kind !== "sse") continue;
1615
+ if (subscribers.find((subscriber) => subscriber.subscriberId === target.subscriberId && subscriber.version === target.subscriberVersion) === void 0) return fail("an SSE target embeds its exact subscriber version");
1616
+ }
1617
+ const judges = Array.isArray(rule.judges) ? rule.judges.map(canonicalJudge) : fail("rule judges are an array");
1618
+ if (judges.length !== 0) return fail("rule judges are represented only by the optional agentic sibling");
1619
+ let cloudEventType;
1620
+ if (rule.cloudEventType !== void 0) {
1621
+ const chosen = validateCloudEventType(rule.cloudEventType);
1622
+ if (!chosen.ok) return fail(chosen.issues[0]?.message ?? "the rule cloudEventType is not valid");
1623
+ cloudEventType = chosen.value;
1624
+ }
1625
+ return {
1626
+ ruleId: requiredText(rule.ruleId, "a rule id"),
1627
+ version: positiveInteger(rule.version, "a rule version"),
1628
+ source,
1629
+ event: {
1630
+ type: eventType,
1631
+ version: eventVersion
1632
+ },
1633
+ condition: condition.value,
1634
+ ...agentic === void 0 ? {} : { agentic },
1635
+ mapping,
1636
+ ...cloudEventType === void 0 ? {} : { cloudEventType },
1637
+ targets,
1638
+ subscribers,
1639
+ judges,
1640
+ deliveryRateCap: positiveInteger(rule.deliveryRateCap, "rule delivery rate cap"),
1641
+ retention: canonicalRetention(rule.retention)
1642
+ };
1643
+ }
1644
+ function canonicalEnableAll(value) {
1645
+ const document = cloneJsonRecord(value, "an enable-all document");
1646
+ if (!Array.isArray(document.ruleVersions)) return fail("enable-all rule versions are an array");
1647
+ const sorted = [...document.ruleVersions.map((entry) => {
1648
+ const row = cloneJsonRecord(entry, "an enable-all rule version");
1649
+ return {
1650
+ ruleId: requiredText(row.ruleId, "an enable-all rule id"),
1651
+ ruleVersion: positiveInteger(row.ruleVersion, "an enable-all rule version")
1652
+ };
1653
+ })].sort((left, right) => compareText(left.ruleId, right.ruleId) || left.ruleVersion - right.ruleVersion);
1654
+ for (let index = 1; index < sorted.length; index += 1) {
1655
+ const previous = sorted[index - 1];
1656
+ const current = sorted[index];
1657
+ if (previous.ruleId === current.ruleId && previous.ruleVersion === current.ruleVersion) return fail("enable-all rule versions are duplicate-free");
1658
+ }
1659
+ return {
1660
+ documentVersion: 1,
1661
+ kind: "enable-all",
1662
+ switchGeneration: Number.isSafeInteger(document.switchGeneration) && document.switchGeneration >= 0 ? document.switchGeneration : fail("an enable-all switch generation is a non-negative safe integer"),
1663
+ ruleVersions: sorted
1664
+ };
1665
+ }
1666
+ /** Validates exactly one v1 activation document and normalises only D2's unordered enable-all list. */
1667
+ function normaliseActivationDocument(value) {
1668
+ const document = cloneJsonRecord(value, "an activation document");
1669
+ if (document.documentVersion !== 1) return fail("an activation document has documentVersion 1");
1670
+ if (Object.hasOwn(document, "versions")) return fail("activation-document versions are derived, never supplied");
1671
+ switch (document.kind) {
1672
+ case "rule": return {
1673
+ documentVersion: 1,
1674
+ kind: "rule",
1675
+ rule: canonicalFullRuleDocument(document.rule)
1676
+ };
1677
+ case "judge-budget": return {
1678
+ documentVersion: 1,
1679
+ kind: "judge-budget",
1680
+ budget: canonicalJudgeBudget(document.budget)
1681
+ };
1682
+ case "judge-kind": return {
1683
+ documentVersion: 1,
1684
+ kind: "judge-kind",
1685
+ enablement: canonicalJudgeKindEnablement(document.enablement)
1686
+ };
1687
+ case "enable-all": return canonicalEnableAll(document);
1688
+ default: return fail("an activation document has a known kind");
1689
+ }
1690
+ }
1691
+ /** Core's recursively key-sorted canonical JSON for a complete v1 activation document. */
1692
+ function canonicalActivationDocument(document) {
1693
+ return canonicalJson(normaliseActivationDocument(document));
1694
+ }
1695
+ /** The lowercase SHA-256 disclosure digest of one canonical activation document. */
1696
+ function activationDocumentDigest(document) {
1697
+ return sha256Hex(canonicalActivationDocument(document));
1698
+ }
1699
+ function compareVersions(left, right) {
1700
+ return compareText(left.kind, right.kind) || compareText(left.id, right.id) || left.version - right.version;
1701
+ }
1702
+ function derivedVersions(document) {
1703
+ switch (document.kind) {
1704
+ case "rule": return [
1705
+ {
1706
+ kind: "rule",
1707
+ id: document.rule.ruleId,
1708
+ version: document.rule.version
1709
+ },
1710
+ ...document.rule.targets.map((target) => ({
1711
+ kind: "target",
1712
+ id: target.targetId,
1713
+ version: target.version
1714
+ })),
1715
+ ...document.rule.subscribers.map((subscriber) => ({
1716
+ kind: "subscriber",
1717
+ id: subscriber.subscriberId,
1718
+ version: subscriber.version
1719
+ })),
1720
+ ...document.rule.agentic === void 0 ? [] : [{
1721
+ kind: "judge",
1722
+ id: document.rule.agentic.judge.judgeId,
1723
+ version: document.rule.agentic.judge.version
1724
+ }]
1725
+ ];
1726
+ case "judge-budget": return [{
1727
+ kind: "judge-budget",
1728
+ id: document.budget.budgetId,
1729
+ version: document.budget.version
1730
+ }];
1731
+ case "judge-kind": return [{
1732
+ kind: "judge-kind",
1733
+ id: document.enablement.kind,
1734
+ version: document.enablement.version
1735
+ }];
1736
+ case "enable-all": return document.ruleVersions.map((rule) => ({
1737
+ kind: "rule",
1738
+ id: rule.ruleId,
1739
+ version: rule.ruleVersion
1740
+ }));
1741
+ }
1742
+ }
1743
+ /** Derives, rather than accepts, the exact core standing-disclosure binding for an activation intent. */
1744
+ function disclosureBindingFor(activationIntentId, input) {
1745
+ const document = normaliseActivationDocument(input);
1746
+ const versions = derivedVersions(document).sort(compareVersions);
1747
+ for (let index = 1; index < versions.length; index += 1) if (compareVersions(versions[index - 1], versions[index]) === 0) return fail("an activation document cannot derive duplicate disclosure versions");
1748
+ return canonicalDisclosureBinding({
1749
+ activationIntentId: requiredText(activationIntentId, "an activation intent id"),
1750
+ activationKind: document.kind,
1751
+ digest: sha256Hex(canonicalJson(document)),
1752
+ versions
1753
+ });
1754
+ }
1755
+ //#endregion
1756
+ //#region src/runtime/control-operation-registry.ts
1757
+ /**
1758
+ * The owner control protocol's complete wire vocabulary. Capability rows deliberately name operation *functions*,
1759
+ * while authenticated control frames name these wires. The owner dispatcher, contract schema and vectors consume this
1760
+ * one registry instead of recreating either vocabulary at a protocol boundary.
1761
+ */
1762
+ const OWNER_CONTROL_WIRE_OPERATIONS = [
1763
+ {
1764
+ capabilityOperation: "status",
1765
+ wireOperation: "status",
1766
+ desktopCallable: true,
1767
+ family: "owner"
1768
+ },
1769
+ {
1770
+ capabilityOperation: "stop",
1771
+ wireOperation: "stop",
1772
+ desktopCallable: true,
1773
+ family: "owner"
1774
+ },
1775
+ {
1776
+ capabilityOperation: "pause",
1777
+ wireOperation: "pause",
1778
+ desktopCallable: true,
1779
+ family: "owner"
1780
+ },
1781
+ {
1782
+ capabilityOperation: "resume",
1783
+ wireOperation: "resume",
1784
+ desktopCallable: true,
1785
+ family: "owner"
1786
+ },
1787
+ {
1788
+ capabilityOperation: "disableAll",
1789
+ wireOperation: "disable-all",
1790
+ desktopCallable: true,
1791
+ family: "owner"
1792
+ },
1793
+ {
1794
+ capabilityOperation: "enableAll",
1795
+ wireOperation: "enable-all",
1796
+ desktopCallable: true,
1797
+ family: "owner"
1798
+ },
1799
+ {
1800
+ capabilityOperation: "doctor",
1801
+ wireOperation: "doctor",
1802
+ desktopCallable: true,
1803
+ family: "owner"
1804
+ },
1805
+ {
1806
+ capabilityOperation: "catalogueList",
1807
+ wireOperation: "catalogue-list",
1808
+ desktopCallable: true,
1809
+ family: "owner"
1810
+ },
1811
+ {
1812
+ capabilityOperation: "catalogueShow",
1813
+ wireOperation: "catalogue-show",
1814
+ desktopCallable: true,
1815
+ family: "owner"
1816
+ },
1817
+ {
1818
+ capabilityOperation: "sourcesList",
1819
+ wireOperation: "sources-list",
1820
+ desktopCallable: true,
1821
+ family: "owner"
1822
+ },
1823
+ {
1824
+ capabilityOperation: "sourceShow",
1825
+ wireOperation: "source-show",
1826
+ desktopCallable: true,
1827
+ family: "owner"
1828
+ },
1829
+ {
1830
+ capabilityOperation: "rulesList",
1831
+ wireOperation: "rules-list",
1832
+ desktopCallable: true,
1833
+ family: "owner"
1834
+ },
1835
+ {
1836
+ capabilityOperation: "ruleShow",
1837
+ wireOperation: "rule-show",
1838
+ desktopCallable: true,
1839
+ family: "owner"
1840
+ },
1841
+ {
1842
+ capabilityOperation: "createRule",
1843
+ wireOperation: "rule-create",
1844
+ desktopCallable: true,
1845
+ family: "owner"
1846
+ },
1847
+ {
1848
+ capabilityOperation: "updateRule",
1849
+ wireOperation: "rule-update",
1850
+ desktopCallable: true,
1851
+ family: "owner"
1852
+ },
1853
+ {
1854
+ capabilityOperation: "enableRule",
1855
+ wireOperation: "rule-enable",
1856
+ desktopCallable: true,
1857
+ family: "owner"
1858
+ },
1859
+ {
1860
+ capabilityOperation: "disableRule",
1861
+ wireOperation: "rule-disable",
1862
+ desktopCallable: true,
1863
+ family: "owner"
1864
+ },
1865
+ {
1866
+ capabilityOperation: "removeRule",
1867
+ wireOperation: "rule-remove",
1868
+ desktopCallable: true,
1869
+ family: "owner"
1870
+ },
1871
+ {
1872
+ capabilityOperation: "targetsList",
1873
+ wireOperation: "targets-list",
1874
+ desktopCallable: true,
1875
+ family: "owner"
1876
+ },
1877
+ {
1878
+ capabilityOperation: "addTarget",
1879
+ wireOperation: "target-add",
1880
+ desktopCallable: true,
1881
+ family: "owner"
1882
+ },
1883
+ {
1884
+ capabilityOperation: "updateTarget",
1885
+ wireOperation: "target-update",
1886
+ desktopCallable: true,
1887
+ family: "owner"
1888
+ },
1889
+ {
1890
+ capabilityOperation: "removeTarget",
1891
+ wireOperation: "target-remove",
1892
+ desktopCallable: true,
1893
+ family: "owner"
1894
+ },
1895
+ {
1896
+ capabilityOperation: "approve",
1897
+ wireOperation: "approve",
1898
+ desktopCallable: true,
1899
+ family: "owner"
1900
+ },
1901
+ {
1902
+ capabilityOperation: "approvalView",
1903
+ wireOperation: "approvalView",
1904
+ desktopCallable: true,
1905
+ family: "b3"
1906
+ },
1907
+ {
1908
+ capabilityOperation: "ruleTest",
1909
+ wireOperation: "ruleTest",
1910
+ desktopCallable: true,
1911
+ family: "b3"
1912
+ },
1913
+ {
1914
+ capabilityOperation: "ruleTestRetained",
1915
+ wireOperation: "ruleTestRetained",
1916
+ desktopCallable: true,
1917
+ family: "b3"
1918
+ },
1919
+ {
1920
+ capabilityOperation: "targetTest",
1921
+ wireOperation: "targetTest",
1922
+ desktopCallable: true,
1923
+ family: "b3"
1924
+ },
1925
+ {
1926
+ capabilityOperation: "targetResume",
1927
+ wireOperation: "targetResume",
1928
+ desktopCallable: true,
1929
+ family: "b3"
1930
+ },
1931
+ {
1932
+ capabilityOperation: "subscribersList",
1933
+ wireOperation: "subscribersList",
1934
+ desktopCallable: true,
1935
+ family: "b3"
1936
+ },
1937
+ {
1938
+ capabilityOperation: "addSubscriber",
1939
+ wireOperation: "addSubscriber",
1940
+ desktopCallable: true,
1941
+ family: "b3"
1942
+ },
1943
+ {
1944
+ capabilityOperation: "updateSubscriber",
1945
+ wireOperation: "updateSubscriber",
1946
+ desktopCallable: true,
1947
+ family: "b3"
1948
+ },
1949
+ {
1950
+ capabilityOperation: "removeSubscriber",
1951
+ wireOperation: "removeSubscriber",
1952
+ desktopCallable: true,
1953
+ family: "b3"
1954
+ },
1955
+ {
1956
+ capabilityOperation: "judgesList",
1957
+ wireOperation: "judgesList",
1958
+ desktopCallable: true,
1959
+ family: "b3"
1960
+ },
1961
+ {
1962
+ capabilityOperation: "addJudge",
1963
+ wireOperation: "addJudge",
1964
+ desktopCallable: true,
1965
+ family: "b3"
1966
+ },
1967
+ {
1968
+ capabilityOperation: "updateJudge",
1969
+ wireOperation: "updateJudge",
1970
+ desktopCallable: true,
1971
+ family: "b3"
1972
+ },
1973
+ {
1974
+ capabilityOperation: "removeJudge",
1975
+ wireOperation: "removeJudge",
1976
+ desktopCallable: true,
1977
+ family: "b3"
1978
+ },
1979
+ {
1980
+ capabilityOperation: "judgeTest",
1981
+ wireOperation: "judgeTest",
1982
+ desktopCallable: true,
1983
+ family: "b3"
1984
+ },
1985
+ {
1986
+ capabilityOperation: "budgetShow",
1987
+ wireOperation: "budgetShow",
1988
+ desktopCallable: true,
1989
+ family: "b3"
1990
+ },
1991
+ {
1992
+ capabilityOperation: "updateBudget",
1993
+ wireOperation: "updateBudget",
1994
+ desktopCallable: true,
1995
+ family: "b3"
1996
+ },
1997
+ {
1998
+ capabilityOperation: "judgeKindsList",
1999
+ wireOperation: "judgeKindsList",
2000
+ desktopCallable: true,
2001
+ family: "b3"
2002
+ },
2003
+ {
2004
+ capabilityOperation: "enableJudgeKind",
2005
+ wireOperation: "enableJudgeKind",
2006
+ desktopCallable: true,
2007
+ family: "b3"
2008
+ },
2009
+ {
2010
+ capabilityOperation: "disableJudgeKind",
2011
+ wireOperation: "disableJudgeKind",
2012
+ desktopCallable: true,
2013
+ family: "b3"
2014
+ },
2015
+ {
2016
+ capabilityOperation: "judgeModelStatus",
2017
+ wireOperation: "judgeModelStatus",
2018
+ desktopCallable: true,
2019
+ family: "b3"
2020
+ },
2021
+ {
2022
+ capabilityOperation: "removeJudgeModel",
2023
+ wireOperation: "removeJudgeModel",
2024
+ desktopCallable: true,
2025
+ family: "b3"
2026
+ },
2027
+ {
2028
+ capabilityOperation: "deliveriesList",
2029
+ wireOperation: "deliveriesList",
2030
+ desktopCallable: true,
2031
+ family: "b3"
2032
+ },
2033
+ {
2034
+ capabilityOperation: "retryDelivery",
2035
+ wireOperation: "retryDelivery",
2036
+ desktopCallable: true,
2037
+ family: "b3"
2038
+ },
2039
+ {
2040
+ capabilityOperation: "dropDelivery",
2041
+ wireOperation: "dropDelivery",
2042
+ desktopCallable: true,
2043
+ family: "b3"
2044
+ },
2045
+ {
2046
+ capabilityOperation: "heldList",
2047
+ wireOperation: "heldList",
2048
+ desktopCallable: true,
2049
+ family: "b3"
2050
+ },
2051
+ {
2052
+ capabilityOperation: "decideHeld",
2053
+ wireOperation: "decideHeld",
2054
+ desktopCallable: true,
2055
+ family: "b3"
2056
+ },
2057
+ {
2058
+ capabilityOperation: "targetSecretCreate",
2059
+ wireOperation: "targetSecretCreate",
2060
+ desktopCallable: true,
2061
+ family: "b3"
2062
+ },
2063
+ {
2064
+ capabilityOperation: "targetSecretRotate",
2065
+ wireOperation: "targetSecretRotate",
2066
+ desktopCallable: true,
2067
+ family: "b3"
2068
+ },
2069
+ {
2070
+ capabilityOperation: "targetUrlSet",
2071
+ wireOperation: "targetUrlSet",
2072
+ desktopCallable: true,
2073
+ family: "b3"
2074
+ },
2075
+ {
2076
+ capabilityOperation: "subscriberTokenCreate",
2077
+ wireOperation: "subscriberTokenCreate",
2078
+ desktopCallable: true,
2079
+ family: "b3"
2080
+ },
2081
+ {
2082
+ capabilityOperation: "subscriberTokenRotate",
2083
+ wireOperation: "subscriberTokenRotate",
2084
+ desktopCallable: true,
2085
+ family: "b3"
2086
+ },
2087
+ {
2088
+ capabilityOperation: "judgeKeySet",
2089
+ wireOperation: "judgeKeySet",
2090
+ desktopCallable: true,
2091
+ family: "b3"
2092
+ },
2093
+ {
2094
+ capabilityOperation: "judgeKeyRotate",
2095
+ wireOperation: "judgeKeyRotate",
2096
+ desktopCallable: true,
2097
+ family: "b3"
2098
+ },
2099
+ {
2100
+ capabilityOperation: "migrateSecrets",
2101
+ wireOperation: "migrateSecrets",
2102
+ desktopCallable: true,
2103
+ family: "b3"
2104
+ },
2105
+ {
2106
+ capabilityOperation: "dryrunList",
2107
+ wireOperation: "dryrun-list",
2108
+ desktopCallable: true,
2109
+ family: "owner"
2110
+ },
2111
+ {
2112
+ capabilityOperation: "dryrunShow",
2113
+ wireOperation: "dryrun-show",
2114
+ desktopCallable: true,
2115
+ family: "owner"
2116
+ },
2117
+ {
2118
+ capabilityOperation: "approveChallenge",
2119
+ wireOperation: "approve-challenge",
2120
+ desktopCallable: false,
2121
+ family: "owner"
2122
+ }
2123
+ ];
2124
+ /** The owner switch reads its case labels from the registry above; it introduces no second wire vocabulary. */
2125
+ const OWNER_CONTROL_WIRES = Object.freeze(Object.fromEntries(OWNER_CONTROL_WIRE_OPERATIONS.flatMap(({ capabilityOperation, wireOperation }) => capabilityOperation === void 0 ? [] : [[capabilityOperation, wireOperation]])));
2126
+ const OWNER_CONTROL_WIRE_OPERATION_SET = new Set(OWNER_CONTROL_WIRE_OPERATIONS.map(({ wireOperation }) => wireOperation));
2127
+ const B3_CONTROL_WIRE_OPERATION_SET = new Set(OWNER_CONTROL_WIRE_OPERATIONS.filter((entry) => entry.family === "b3").map(({ wireOperation }) => wireOperation));
2128
+ function isOwnerControlWireOperation(value) {
2129
+ return OWNER_CONTROL_WIRE_OPERATION_SET.has(value);
2130
+ }
2131
+ function isB3ControlWireOperation(value) {
2132
+ return B3_CONTROL_WIRE_OPERATION_SET.has(value);
2133
+ }
2134
+ //#endregion
2135
+ //#region src/operations/b3-contract.ts
2136
+ /**
2137
+ * The data-only promise B3 makes before any public B3 registration exists. Task 5 consumes these rows when it wires
2138
+ * Commander and MCP; Task 9 adds the language-neutral schema and vectors without changing their vocabulary.
2139
+ */
2140
+ const B3_EXCEPTION_REASON_SECRET = "secret material must never enter model input or output; the person completes this operation at the terminal or app.";
2141
+ /** C may replace this only after the daemon verifies its future non-forgeable secret-window capability. */
2142
+ const B3_SECRET_TERMINAL_ORIGIN = "interactive-terminal";
2143
+ Object.freeze(["both", "exception"]);
2144
+ /**
2145
+ * The complete set of daemon capabilities a desktop control client can invoke. `run` and the MCP-server entry
2146
+ * point are deliberately absent: they start processes rather than call a running owner's control protocol. The
2147
+ * contract drift test derives this set from capabilities.json, which is the repository-wide authority.
2148
+ */
2149
+ const B3_DESKTOP_CONTROL_OPERATIONS = Object.freeze(OWNER_CONTROL_WIRE_OPERATIONS.filter((entry) => entry.desktopCallable).map(({ wireOperation }) => wireOperation));
2150
+ const both = (id, cli, mcp, operation) => ({
2151
+ id,
2152
+ cli,
2153
+ mcp,
2154
+ operation,
2155
+ status: "both"
2156
+ });
2157
+ const exception = (id, cli, operation, reason, secret) => ({
2158
+ id,
2159
+ cli,
2160
+ mcp: null,
2161
+ operation,
2162
+ status: "exception",
2163
+ reason,
2164
+ ...secret ? { secret } : {}
2165
+ });
2166
+ const B3_CAPABILITIES = Object.freeze([
2167
+ both("events-daemon.approval.view", "approval view <approval-id> --digest <digest>", "events_approval_view", "approvalView"),
2168
+ both("events-daemon.rule.test", "rule test <document> <catalogue-example>", "events_rule_test", "ruleTest"),
2169
+ exception("events-daemon.rule.test-retained", "rule test-retained <event-id> --rule <rule-id> --version <n>", "ruleTestRetained", "Retained sender content may be selected only by a person outside model context."),
2170
+ both("events-daemon.target.test", "target test <target-id> --version <n>", "events_target_test", "targetTest"),
2171
+ exception("events-daemon.target.resume", "target resume <target-id> --version <n>", "targetResume", "A person, not model context, decides to reopen a degraded target reset barrier."),
2172
+ both("events-daemon.subscribers.list", "subscribers list", "events_subscribers_list", "subscribersList"),
2173
+ both("events-daemon.subscriber.add", "subscriber add <document>", "events_subscriber_add", "addSubscriber"),
2174
+ both("events-daemon.subscriber.update", "subscriber update <document>", "events_subscriber_update", "updateSubscriber"),
2175
+ both("events-daemon.subscriber.remove", "subscriber remove <subscriber-id>", "events_subscriber_remove", "removeSubscriber"),
2176
+ both("events-daemon.judges.list", "judges list", "events_judges_list", "judgesList"),
2177
+ both("events-daemon.judge.add", "judge add <document>", "events_judge_add", "addJudge"),
2178
+ both("events-daemon.judge.update", "judge update <document>", "events_judge_update", "updateJudge"),
2179
+ both("events-daemon.judge.remove", "judge remove <judge-id>", "events_judge_remove", "removeJudge"),
2180
+ both("events-daemon.judge.test", "judge test <judge-id> --version <n>", "events_judge_test", "judgeTest"),
2181
+ both("events-daemon.budget.show", "budget show", "events_budget_show", "budgetShow"),
2182
+ both("events-daemon.budget.update", "budget update <document>", "events_budget_update", "updateBudget"),
2183
+ both("events-daemon.judge-kinds.list", "judge kinds list", "events_judge_kinds_list", "judgeKindsList"),
2184
+ both("events-daemon.judge-kind.enable", "judge kind enable <kind>", "events_judge_kind_enable", "enableJudgeKind"),
2185
+ both("events-daemon.judge-kind.disable", "judge kind disable <kind>", "events_judge_kind_disable", "disableJudgeKind"),
2186
+ both("events-daemon.judge-model.status", "judge model status", "events_judge_model_status", "judgeModelStatus"),
2187
+ both("events-daemon.judge-model.remove", "judge model remove", "events_judge_model_remove", "removeJudgeModel"),
2188
+ both("events-daemon.deliveries.list", "deliveries list", "events_deliveries_list", "deliveriesList"),
2189
+ both("events-daemon.delivery.retry", "delivery retry <delivery-id>", "events_delivery_retry", "retryDelivery"),
2190
+ both("events-daemon.delivery.drop", "delivery drop <delivery-id>", "events_delivery_drop", "dropDelivery"),
2191
+ both("events-daemon.held.list", "held list", "events_held_list", "heldList"),
2192
+ exception("events-daemon.held.decide", "held decide <decision-id> <accept|reject>", "decideHeld", "A held model decision can be resolved only by a person at terminal/app, never by model context."),
2193
+ exception("events-daemon.target-secret.create", "target secret create <target-id> --version <n>", "targetSecretCreate", B3_EXCEPTION_REASON_SECRET, true),
2194
+ exception("events-daemon.target-secret.rotate", "target secret rotate <target-id> --version <n>", "targetSecretRotate", B3_EXCEPTION_REASON_SECRET, true),
2195
+ exception("events-daemon.target-url.set", "target url set <target-id> (--predecessor-version <n> | --draft <inert-target-document>) --new-version <n>", "targetUrlSet", B3_EXCEPTION_REASON_SECRET, true),
2196
+ exception("events-daemon.subscriber-token.create", "subscriber token create <subscriber-id> --version <n>", "subscriberTokenCreate", B3_EXCEPTION_REASON_SECRET, true),
2197
+ exception("events-daemon.subscriber-token.rotate", "subscriber token rotate <subscriber-id> --version <n>", "subscriberTokenRotate", B3_EXCEPTION_REASON_SECRET, true),
2198
+ exception("events-daemon.judge-key.set", "judge key set <judge-id> --version <n>", "judgeKeySet", B3_EXCEPTION_REASON_SECRET, true),
2199
+ exception("events-daemon.judge-key.rotate", "judge key rotate <judge-id> --version <n>", "judgeKeyRotate", B3_EXCEPTION_REASON_SECRET, true),
2200
+ exception("events-daemon.secrets.migrate", "secrets migrate --to keychain|file", "migrateSecrets", B3_EXCEPTION_REASON_SECRET, true)
2201
+ ]);
2202
+ const B3_SECRET_OPERATIONS = new Set(B3_CAPABILITIES.filter((capability) => capability.secret === true).map(({ operation }) => operation));
2203
+ /** The owner accepts only the B3 operation vocabulary that its future CLI/MCP registrars may expose. */
2204
+ function isB3ControlOperation(value) {
2205
+ return isB3ControlWireOperation(value);
2206
+ }
2207
+ function isB3SecretOperation(value) {
2208
+ return B3_SECRET_OPERATIONS.has(value);
2209
+ }
2210
+ const B3_APPROVAL_VIEW_VARIANTS = Object.freeze([
2211
+ "READY",
2212
+ "STALE_APPROVAL",
2213
+ "DIGEST_MISMATCH",
2214
+ "CHALLENGE_EXPIRED"
2215
+ ]);
2216
+ Object.freeze(["accept", "reject"]);
2217
+ Object.freeze(["file", "keychain"]);
2218
+ Object.freeze(["terminal-approval", "app-approval-screen"]);
2219
+ const B3_JUDGE_UNAVAILABLE_VARIANTS = Object.freeze([{
2220
+ code: "E_REQUIRED",
2221
+ phase: "E"
2222
+ }, {
2223
+ code: "E2_REQUIRED",
2224
+ phase: "E2"
2225
+ }]);
2226
+ Object.freeze(["unavailable"]);
2227
+ Object.freeze([{
2228
+ kind: "held-list",
2229
+ decisions: []
2230
+ }]);
2231
+ Object.freeze([{
2232
+ kind: "unavailable",
2233
+ code: "HOLDS_UNAVAILABLE",
2234
+ phase: "E"
2235
+ }]);
2236
+ Object.freeze([{
2237
+ kind: "unavailable",
2238
+ code: "APP_SECRET_CAPABILITY_UNAVAILABLE"
2239
+ }]);
2240
+ Object.freeze(["running", "not-running"]);
2241
+ Object.freeze([
2242
+ "pending",
2243
+ "pending-completion",
2244
+ "completed",
2245
+ "failed",
2246
+ "cancelled"
2247
+ ]);
2248
+ Object.freeze([
2249
+ "rule",
2250
+ "judge-budget",
2251
+ "judge-kind",
2252
+ "enable-all"
2253
+ ]);
2254
+ Object.freeze([
2255
+ "rule",
2256
+ "judge-budget",
2257
+ "judge-kind",
2258
+ "enable-all"
2259
+ ]);
2260
+ Object.freeze([
2261
+ "rule",
2262
+ "target",
2263
+ "subscriber",
2264
+ "judge",
2265
+ "judge-budget",
2266
+ "judge-kind"
2267
+ ]);
2268
+ Object.freeze(["delivery-retried", "delivery-dropped"]);
2269
+ Object.freeze(["not-evaluated"]);
2270
+ Object.freeze([
2271
+ "matched",
2272
+ "condition-false",
2273
+ "mapping-rejected"
2274
+ ]);
2275
+ Object.freeze(["plain", "enveloped"]);
2276
+ /** Runtime coverage source: a desktop wire has exactly one result branch and vector. */
2277
+ const B3_CONTROL_V1_RESULT_OPERATIONS = B3_DESKTOP_CONTROL_OPERATIONS;
2278
+ /** The stable data-only error vocabulary; messages and provider detail deliberately do not cross this contract. */
2279
+ const B3_CONTROL_ERROR_CODES = Object.freeze([
2280
+ "USAGE",
2281
+ "BAD_DATA",
2282
+ "APPROVAL_VOID",
2283
+ "NOT_FOUND",
2284
+ "CONFIG"
2285
+ ]);
2286
+ const B3_CONTROL_V1_SCHEMA_VERSION = "b3-control-v1";
2287
+ /** Kept beside the union so a TypeScript change cannot silently leave the language-neutral schema/vector set behind. */
2288
+ const B3_CONTROL_V1_OPERATION_SPECS = Object.freeze(B3_DESKTOP_CONTROL_OPERATIONS.map((operation) => ({
2289
+ operation,
2290
+ desktopCallable: true,
2291
+ secret: B3_SECRET_OPERATIONS.has(operation)
2292
+ })));
2293
+ /** E owns this gate; B3 records the obligation without pretending a temporary fixture proves future build/shipping. */
2294
+ const B3_CONTROL_V1_SUCCESSOR_REQUIREMENT = "E imports its real code and this contract, lands the build/ship negative gate before any owner registration or callable judge, and requires B3 merged.";
2295
+ function isRecord(value) {
2296
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2297
+ }
2298
+ new Set(B3_DESKTOP_CONTROL_OPERATIONS);
2299
+ Object.freeze({
2300
+ status: [
2301
+ "owner",
2302
+ "enabled",
2303
+ "paused",
2304
+ "switchGeneration",
2305
+ "activationIntents"
2306
+ ],
2307
+ stop: ["stopping"],
2308
+ pause: [
2309
+ "enabled",
2310
+ "paused",
2311
+ "switchGeneration"
2312
+ ],
2313
+ resume: [
2314
+ "enabled",
2315
+ "paused",
2316
+ "switchGeneration"
2317
+ ],
2318
+ "disable-all": [
2319
+ "enabled",
2320
+ "paused",
2321
+ "switchGeneration"
2322
+ ],
2323
+ "enable-all": [
2324
+ "intentId",
2325
+ "approvalId",
2326
+ "binding",
2327
+ "kind",
2328
+ "status",
2329
+ "replacementOfVersion"
2330
+ ],
2331
+ "catalogue-show": [
2332
+ "type",
2333
+ "version",
2334
+ "channel"
2335
+ ],
2336
+ "source-show": ["source", "accounts"],
2337
+ "rule-create": [
2338
+ "id",
2339
+ "kind",
2340
+ "objectId",
2341
+ "version",
2342
+ "document",
2343
+ "digest",
2344
+ "state"
2345
+ ],
2346
+ "rule-update": [
2347
+ "id",
2348
+ "kind",
2349
+ "objectId",
2350
+ "version",
2351
+ "document",
2352
+ "digest",
2353
+ "state"
2354
+ ],
2355
+ "rule-enable": [
2356
+ "intentId",
2357
+ "approvalId",
2358
+ "binding",
2359
+ "kind",
2360
+ "status",
2361
+ "replacementOfVersion"
2362
+ ],
2363
+ "rule-disable": ["ruleId", "disabled"],
2364
+ "rule-remove": ["ruleId", "disabled"],
2365
+ "target-add": [
2366
+ "id",
2367
+ "kind",
2368
+ "objectId",
2369
+ "version",
2370
+ "document",
2371
+ "digest",
2372
+ "state"
2373
+ ],
2374
+ "target-update": [
2375
+ "id",
2376
+ "kind",
2377
+ "objectId",
2378
+ "version",
2379
+ "document",
2380
+ "digest",
2381
+ "state"
2382
+ ],
2383
+ "target-remove": ["targetId", "removed"],
2384
+ approve: [
2385
+ "intentId",
2386
+ "status",
2387
+ "usedAt"
2388
+ ],
2389
+ ruleTest: [
2390
+ "agentic",
2391
+ "outcome",
2392
+ "rendered"
2393
+ ],
2394
+ ruleTestRetained: [
2395
+ "agentic",
2396
+ "outcome",
2397
+ "rendered"
2398
+ ],
2399
+ targetTest: [
2400
+ "attempts",
2401
+ "targetId",
2402
+ "targetVersion"
2403
+ ],
2404
+ targetResume: ["id", "resetEpoch"],
2405
+ addSubscriber: [
2406
+ "id",
2407
+ "kind",
2408
+ "objectId",
2409
+ "version",
2410
+ "document",
2411
+ "digest",
2412
+ "state"
2413
+ ],
2414
+ updateSubscriber: [
2415
+ "id",
2416
+ "kind",
2417
+ "objectId",
2418
+ "version",
2419
+ "document",
2420
+ "digest",
2421
+ "state"
2422
+ ],
2423
+ removeSubscriber: ["subscriberId", "removed"],
2424
+ retryDelivery: [
2425
+ "kind",
2426
+ "deliveryId",
2427
+ "nextAt"
2428
+ ],
2429
+ dropDelivery: ["kind", "deliveryId"],
2430
+ "dryrun-show": [
2431
+ "deliveryId",
2432
+ "ruleId",
2433
+ "ruleVersion",
2434
+ "targetId",
2435
+ "targetVersion",
2436
+ "eventId",
2437
+ "accountId",
2438
+ "deliveredAt",
2439
+ "expiresAt",
2440
+ "record"
2441
+ ]
2442
+ });
2443
+ /**
2444
+ * The terminal and desktop fixture boundary. This formats only daemon-authored identifiers and a canonical, neutralised
2445
+ * preview representation; it never consumes a secret operation or claims the approval.
2446
+ */
2447
+ function renderB3ApprovalPreviewV1(value) {
2448
+ if (!isRecord(value) || typeof value.kind !== "string" || !B3_APPROVAL_VIEW_VARIANTS.includes(value.kind)) throw new TypeError("an approval preview has an unknown B3 v1 variant");
2449
+ if (value.kind !== "READY") return {
2450
+ kind: value.kind,
2451
+ structured: {},
2452
+ terminal: `Approval view: ${value.kind}`
2453
+ };
2454
+ if (typeof value.approvalId !== "string" || typeof value.digest !== "string" || !isRecord(value.challenge) || typeof value.challenge.approvalId !== "string" || typeof value.challenge.digest !== "string" || typeof value.challenge.challenge !== "string" || typeof value.challenge.expiresAt !== "number") throw new TypeError("a ready approval preview is malformed");
2455
+ normaliseActivationDocument(value.preview);
2456
+ return {
2457
+ kind: "READY",
2458
+ structured: {
2459
+ approvalId: value.approvalId,
2460
+ digest: value.digest,
2461
+ preview: value.preview,
2462
+ challenge: {
2463
+ approvalId: value.challenge.approvalId,
2464
+ digest: value.challenge.digest,
2465
+ challenge: value.challenge.challenge,
2466
+ expiresAt: value.challenge.expiresAt
2467
+ }
2468
+ },
2469
+ terminal: [
2470
+ `Approval ${value.approvalId}`,
2471
+ `Digest ${value.digest}`,
2472
+ `Preview ${neutralise(canonicalJson(value.preview)).text}`,
2473
+ `Challenge ${value.challenge.challenge}`,
2474
+ `Expires ${new Date(value.challenge.expiresAt).toISOString()}`
2475
+ ].join("\n")
2476
+ };
2477
+ }
2478
+ /** No desktop, secret value, network client or judge implementation crosses this boundary. */
2479
+ const B3_CONTROL_CONTRACT = Object.freeze({
2480
+ version: B3_CONTROL_V1_SCHEMA_VERSION,
2481
+ capabilities: B3_CAPABILITIES,
2482
+ approvalView: B3_APPROVAL_VIEW_VARIANTS,
2483
+ judgeUnavailable: B3_JUDGE_UNAVAILABLE_VARIANTS
2484
+ });
2485
+ //#endregion
2486
+ export { createRule as $, assertSocketPathFits as $t, normaliseWhatsAppSourceOptions as A, deliveriesList as At, removeTarget as B, ControlFrameReader as Bt, canonicalSseSubscriber as C, assertDoctorReportV1 as Ct, normaliseResendSourceOptions as D, isActivationFailureCode as Dt, normaliseGmailSourceOptions as E, ACTIVATION_FAILURE as Et, canonicalJudgeBudget as F, catalogueShow as Ft, removeSubscriber as G, negotiateVersion as Gt, updateTarget as H, encodeControlFrame as Ht, canonicalJudgeKindEnablement as I, approvalView as It, stop as J, processIsLive as Jt, subscribersList as K, mayRecoverStaleInstance as Kt, judgeKindDefinition as L, EventControlClient as Lt, JUDGE_BUDGET_ID as M, heldList as Mt, JUDGE_KIND_DEFINITIONS as N, retryDelivery as Nt, normaliseSlackSourceOptions as O, disableAll as Ot, canonicalJudge as P, catalogueList as Pt, sourcesList as Q, assertControlSupported as Qt, createEventsMcpServer as R, probeControl as Rt, normaliseActivationDocument as S, enableAll as St, classifySourceOptionChange as T, doctor as Tt, targetTest as U, isControlHello as Ut, targetsList as V, controlFailure as Vt, addSubscriber as W, isControlRequest as Wt, loadSqlite as X, removeInstance as Xt, status as Y, readInstance as Yt, sourceShow as Z, writeInstance as Zt, activationDocumentDigest as _, judgesList as _t, B3_CONTROL_V1_OPERATION_SPECS as a, ensureOwnerOnlyFile as an, updateRule as at, canonicalTarget as b, updateBudget as bt, B3_CONTROL_V1_SUCCESSOR_REQUIREMENT as c, pause as ct, B3_SECRET_TERMINAL_ORIGIN as d, budgetShow as dt, controlEndpoint as en, disableRule as et, isB3ControlOperation as f, disableJudgeKind as ft, isOwnerControlWireOperation as g, judgeTest as gt, OWNER_CONTROL_WIRES as h, judgeModelStatus as ht, B3_CONTROL_ERROR_CODES as i, ensureEventSocketDirectory as in, rulesList as it, APPROVED_TYPESAFE_MODELS as j, dropDelivery as jt, normaliseSourceOptions as k, decideHeld as kt, B3_DESKTOP_CONTROL_OPERATIONS as l, resume as lt, renderB3ApprovalPreviewV1 as m, judgeKindsList as mt, B3_CAPABILITIES as n, verifyPrivateSocketDirectory as nn, removeRule as nt, B3_CONTROL_V1_RESULT_OPERATIONS as o, eventPaths as on, ruleTest as ot, isB3SecretOperation as p, enableJudgeKind as pt, updateSubscriber as q, newInstanceRecord as qt, B3_CONTROL_CONTRACT as r, ensureEventPaths as rn, ruleShow as rt, B3_CONTROL_V1_SCHEMA_VERSION as s, installErrorSink as sn, ruleTestRetained as st, B3_APPROVAL_VIEW_VARIANTS as t, verifyControlSocket as tn, enableRule as tt, B3_JUDGE_UNAVAILABLE_VARIANTS as u, addJudge as ut, canonicalFullRuleDocument as v, removeJudge as vt, sseDeliveryTarget as w, assertDoctorReportV2 as wt, disclosureBindingFor as x, updateJudge as xt, canonicalSubscriber as y, removeJudgeModel as yt, addTarget as z, CONTROL_PROTOCOL_VERSIONS as zt };