agent-embassy 1.7.0 → 1.8.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.
- package/CHANGELOG.md +32 -0
- package/CONTRIBUTING.md +51 -47
- package/README.md +26 -9
- package/README.zh-CN.md +22 -9
- package/SECURITY.md +48 -35
- package/dist/src/gateway/acp-client.d.ts +12 -19
- package/dist/src/gateway/acp-client.js +90 -65
- package/dist/src/gateway/acp-client.js.map +1 -1
- package/dist/src/gateway/acp-provider.d.ts +11 -10
- package/dist/src/gateway/acp-provider.js +165 -53
- package/dist/src/gateway/acp-provider.js.map +1 -1
- package/dist/src/gateway/claude-helper-client.d.ts +2 -43
- package/dist/src/gateway/claude-helper-client.js +1 -211
- package/dist/src/gateway/claude-helper-client.js.map +1 -1
- package/dist/src/gateway/claude-helper-protocol.d.ts +16 -74
- package/dist/src/gateway/claude-helper-protocol.js +99 -378
- package/dist/src/gateway/claude-helper-protocol.js.map +1 -1
- package/dist/src/gateway/claude-helper-supervisor.d.ts +56 -44
- package/dist/src/gateway/claude-helper-supervisor.js +265 -456
- package/dist/src/gateway/claude-helper-supervisor.js.map +1 -1
- package/dist/src/gateway/claude-helper.js +184 -210
- package/dist/src/gateway/claude-helper.js.map +1 -1
- package/dist/src/gateway/claude-peer.d.ts +20 -87
- package/dist/src/gateway/claude-peer.js +310 -1009
- package/dist/src/gateway/claude-peer.js.map +1 -1
- package/dist/src/gateway/claude-runtime.d.ts +13 -15
- package/dist/src/gateway/claude-runtime.js +14 -168
- package/dist/src/gateway/claude-runtime.js.map +1 -1
- package/dist/src/gateway/cli-copy.en.d.ts +2 -2
- package/dist/src/gateway/cli-copy.en.js +4 -2
- package/dist/src/gateway/cli-copy.en.js.map +1 -1
- package/dist/src/gateway/cli-copy.zh-CN.d.ts +2 -2
- package/dist/src/gateway/cli-copy.zh-CN.js +4 -2
- package/dist/src/gateway/cli-copy.zh-CN.js.map +1 -1
- package/dist/src/gateway/cli.d.ts +7 -2
- package/dist/src/gateway/cli.js +277 -575
- package/dist/src/gateway/cli.js.map +1 -1
- package/dist/src/gateway/codex-app-server.d.ts +5 -227
- package/dist/src/gateway/codex-app-server.js +18 -1463
- package/dist/src/gateway/codex-app-server.js.map +1 -1
- package/dist/src/gateway/codex-doctor.d.ts +36 -0
- package/dist/src/gateway/codex-doctor.js +127 -0
- package/dist/src/gateway/codex-doctor.js.map +1 -0
- package/dist/src/gateway/codex-local-transport.d.ts +6 -6
- package/dist/src/gateway/codex-local-transport.js +13 -10
- package/dist/src/gateway/codex-local-transport.js.map +1 -1
- package/dist/src/gateway/codex-stateless-transport.d.ts +114 -0
- package/dist/src/gateway/codex-stateless-transport.js +1108 -0
- package/dist/src/gateway/codex-stateless-transport.js.map +1 -0
- package/dist/src/gateway/config.d.ts +2 -9
- package/dist/src/gateway/config.js +62 -100
- package/dist/src/gateway/config.js.map +1 -1
- package/dist/src/gateway/control.d.ts +36 -90
- package/dist/src/gateway/control.js +465 -1123
- package/dist/src/gateway/control.js.map +1 -1
- package/dist/src/gateway/dashboard-copy.d.ts +1 -1
- package/dist/src/gateway/dashboard-copy.en.d.ts +8 -26
- package/dist/src/gateway/dashboard-copy.en.js +19 -37
- package/dist/src/gateway/dashboard-copy.en.js.map +1 -1
- package/dist/src/gateway/dashboard-copy.js +8 -26
- package/dist/src/gateway/dashboard-copy.js.map +1 -1
- package/dist/src/gateway/dashboard-copy.zh-CN.d.ts +8 -26
- package/dist/src/gateway/dashboard-copy.zh-CN.js +19 -37
- package/dist/src/gateway/dashboard-copy.zh-CN.js.map +1 -1
- package/dist/src/gateway/dashboard-model.d.ts +8 -22
- package/dist/src/gateway/dashboard-model.js +44 -130
- package/dist/src/gateway/dashboard-model.js.map +1 -1
- package/dist/src/gateway/dashboard.d.ts +0 -6
- package/dist/src/gateway/dashboard.js +3 -7
- package/dist/src/gateway/dashboard.js.map +1 -1
- package/dist/src/gateway/live-dashboard-app/app.js +20 -34
- package/dist/src/gateway/live-dashboard-command.js +2 -2
- package/dist/src/gateway/live-dashboard-command.js.map +1 -1
- package/dist/src/gateway/live-dashboard-http.d.ts +1 -1
- package/dist/src/gateway/live-dashboard-http.js +2 -2
- package/dist/src/gateway/live-dashboard-http.js.map +1 -1
- package/dist/src/gateway/progress-watch-machine.d.ts +1 -37
- package/dist/src/gateway/progress-watch-machine.js +4 -15
- package/dist/src/gateway/progress-watch-machine.js.map +1 -1
- package/dist/src/gateway/providers.d.ts +58 -191
- package/dist/src/gateway/providers.js +637 -2434
- package/dist/src/gateway/providers.js.map +1 -1
- package/dist/src/gateway/server.d.ts +16 -25
- package/dist/src/gateway/server.js +165 -240
- package/dist/src/gateway/server.js.map +1 -1
- package/dist/src/gateway/service.d.ts +149 -427
- package/dist/src/gateway/service.js +1639 -5662
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/state-v2-to-v3.d.ts +23 -0
- package/dist/src/gateway/state-v2-to-v3.js +994 -0
- package/dist/src/gateway/state-v2-to-v3.js.map +1 -0
- package/dist/src/gateway/store.d.ts +54 -309
- package/dist/src/gateway/store.js +1560 -3510
- package/dist/src/gateway/store.js.map +1 -1
- package/dist/src/gateway/types.d.ts +181 -225
- package/dist/src/gateway/types.js +115 -251
- package/dist/src/gateway/types.js.map +1 -1
- package/docs/CONFIGURATION.md +22 -9
- package/docs/CONFIGURATION.zh-CN.md +21 -9
- package/docs/DASHBOARD.md +10 -10
- package/docs/DASHBOARD.zh-CN.md +3 -3
- package/docs/DELIVERY.md +4 -4
- package/docs/DELIVERY.zh-CN.md +4 -4
- package/docs/GATEWAY-ARCHITECTURE.md +158 -187
- package/package.json +1 -1
- package/skills/embassy-peer/SKILL.md +28 -22
- package/dist/src/gateway/codex-registration-generation.d.ts +0 -5
- package/dist/src/gateway/codex-registration-generation.js +0 -19
- package/dist/src/gateway/codex-registration-generation.js.map +0 -1
- package/dist/src/gateway/codex-registration-succession.d.ts +0 -209
- package/dist/src/gateway/codex-registration-succession.js +0 -588
- package/dist/src/gateway/codex-registration-succession.js.map +0 -1
- package/dist/src/gateway/compatibility.d.ts +0 -22
- package/dist/src/gateway/compatibility.js +0 -23
- package/dist/src/gateway/compatibility.js.map +0 -1
- package/dist/src/gateway/delivery-machine.d.ts +0 -235
- package/dist/src/gateway/delivery-machine.js +0 -540
- package/dist/src/gateway/delivery-machine.js.map +0 -1
|
@@ -1,537 +1,346 @@
|
|
|
1
|
+
import { fork } from "node:child_process";
|
|
1
2
|
import { randomBytes } from "node:crypto";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
2
4
|
import { BridgeError } from "../errors.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"denied",
|
|
9
|
-
"expired",
|
|
10
|
-
"ambiguous",
|
|
11
|
-
"completed",
|
|
12
|
-
"failed",
|
|
13
|
-
"cancelled",
|
|
14
|
-
]);
|
|
15
|
-
const PUBLIC_ALIAS = /^[a-z][a-z0-9_-]{0,31}@[a-z0-9](?:[a-z0-9.-]{0,61}[a-z0-9])?$/;
|
|
16
|
-
const CONVERSATION_ID = /^conv_[A-Za-z0-9_-]{16,64}$/;
|
|
17
|
-
const MAX_RAW_BODY_BYTES = 16 * 1024;
|
|
5
|
+
import { gatewayRegistrationIngressPrefixes, isGatewayProvider } from "./types.js";
|
|
6
|
+
import { assertClaudeNativeHelperIpcSize, CLAUDE_NATIVE_HELPER_MAX_REQUESTS, isClaudeNativeHelperChildMessage, } from "./claude-helper-protocol.js";
|
|
7
|
+
const TIMEOUT = 5_000, CLOSE_TIMEOUT = 2_000;
|
|
8
|
+
const ALIAS = /^[a-z][a-z0-9_-]{0,31}@[a-z0-9](?:[a-z0-9.-]{0,61}[a-z0-9])?$/;
|
|
9
|
+
const CONVERSATION = /^conv_[A-Za-z0-9_-]{16,64}$/;
|
|
18
10
|
function fault(code, recoverable = false) {
|
|
19
|
-
return new BridgeError(code, "The supervised native Claude
|
|
11
|
+
return new BridgeError(code, "The supervised native Claude helper could not complete its bounded operation.", recoverable);
|
|
20
12
|
}
|
|
21
|
-
|
|
22
|
-
|
|
13
|
+
const id = () => randomBytes(18).toString("base64url");
|
|
14
|
+
function requireOk(result) {
|
|
15
|
+
if (!("ok" in result) || result.ok !== true)
|
|
23
16
|
throw fault("CLAUDE_NATIVE_HELPER_INVALID_RESPONSE");
|
|
17
|
+
}
|
|
18
|
+
export class ClaudeNativeHelperClient {
|
|
19
|
+
child;
|
|
20
|
+
callbacks;
|
|
21
|
+
pid;
|
|
22
|
+
registration;
|
|
23
|
+
generation = "";
|
|
24
|
+
#pending = new Map();
|
|
25
|
+
#exit;
|
|
26
|
+
#resolveExit;
|
|
27
|
+
#closed = false;
|
|
28
|
+
#exited = false;
|
|
29
|
+
constructor(child, registration, callbacks) {
|
|
30
|
+
this.child = child;
|
|
31
|
+
this.callbacks = callbacks;
|
|
32
|
+
if (!Number.isSafeInteger(child.pid) || child.pid <= 0)
|
|
33
|
+
throw fault("CLAUDE_NATIVE_HELPER_PID_INVALID");
|
|
34
|
+
this.pid = child.pid;
|
|
35
|
+
this.registration = registration;
|
|
36
|
+
this.#exit = new Promise((resolve) => { this.#resolveExit = resolve; });
|
|
37
|
+
child.on("message", (value) => this.#message(value));
|
|
38
|
+
child.once("error", () => this.#fail(fault("CLAUDE_NATIVE_HELPER_SPAWN_FAILED")));
|
|
39
|
+
child.once("exit", (code, signal) => {
|
|
40
|
+
if (this.#exited)
|
|
41
|
+
return;
|
|
42
|
+
this.#exited = true;
|
|
43
|
+
this.#fail(fault("CLAUDE_NATIVE_HELPER_EXITED"));
|
|
44
|
+
this.#resolveExit();
|
|
45
|
+
callbacks.onExit({ code, signal });
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
static async start(options) {
|
|
49
|
+
const child = fork(options.entryPath ?? fileURLToPath(new URL("./claude-helper.js", import.meta.url)), [], {
|
|
50
|
+
cwd: "/", env: { LANG: "C", LC_ALL: "C", TZ: "UTC" }, execPath: process.execPath,
|
|
51
|
+
execArgv: [], serialization: "json", stdio: ["ignore", "ignore", "ignore", "ipc"],
|
|
52
|
+
});
|
|
53
|
+
const client = new ClaudeNativeHelperClient(child, options.registration, options.callbacks);
|
|
54
|
+
const init = { protocolVersion: 1, type: "initialize", requestId: id(),
|
|
55
|
+
runtime: options.runtime, hostId: options.hostId, locale: options.locale, deliveryNotices: options.deliveryNotices,
|
|
56
|
+
maxPendingMessages: options.maxPendingMessages, registration: options.registration };
|
|
57
|
+
try {
|
|
58
|
+
const result = await client.#send(init);
|
|
59
|
+
if (!("generation" in result))
|
|
60
|
+
throw fault("CLAUDE_NATIVE_HELPER_INVALID_RESPONSE");
|
|
61
|
+
client.generation = result.generation;
|
|
62
|
+
return client;
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
await client.forceClose();
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
request(command, timeoutMs = TIMEOUT) {
|
|
70
|
+
return this.#send({ protocolVersion: 1, type: "request", requestId: id(), command }, timeoutMs);
|
|
71
|
+
}
|
|
72
|
+
async close() {
|
|
73
|
+
if (!this.#closed) {
|
|
74
|
+
try {
|
|
75
|
+
await this.request({ method: "close" }, CLOSE_TIMEOUT);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
this.child.kill("SIGTERM");
|
|
79
|
+
}
|
|
80
|
+
this.#closed = true;
|
|
81
|
+
}
|
|
82
|
+
await this.#awaitExit();
|
|
83
|
+
}
|
|
84
|
+
async forceClose() { this.#closed = true; if (!this.#exited)
|
|
85
|
+
this.child.kill("SIGTERM"); await this.#awaitExit(); }
|
|
86
|
+
async #awaitExit() {
|
|
87
|
+
const timer = setTimeout(() => this.child.kill("SIGKILL"), CLOSE_TIMEOUT);
|
|
88
|
+
timer.unref();
|
|
89
|
+
await this.#exit;
|
|
90
|
+
clearTimeout(timer);
|
|
91
|
+
}
|
|
92
|
+
async #send(message, timeoutMs = TIMEOUT) {
|
|
93
|
+
if (this.#closed || this.#exited || !this.child.connected || this.child.killed)
|
|
94
|
+
throw fault("CLAUDE_NATIVE_HELPER_UNAVAILABLE", true);
|
|
95
|
+
if (this.#pending.size >= CLAUDE_NATIVE_HELPER_MAX_REQUESTS)
|
|
96
|
+
throw fault("CLAUDE_NATIVE_HELPER_REQUEST_CAPACITY", true);
|
|
97
|
+
if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 60_000)
|
|
98
|
+
throw fault("CLAUDE_NATIVE_HELPER_TIMEOUT_INVALID");
|
|
99
|
+
assertClaudeNativeHelperIpcSize(message);
|
|
100
|
+
const pending = new Promise((resolve, reject) => {
|
|
101
|
+
const timer = setTimeout(() => {
|
|
102
|
+
this.#pending.delete(message.requestId);
|
|
103
|
+
reject(fault("CLAUDE_NATIVE_HELPER_REQUEST_TIMEOUT"));
|
|
104
|
+
}, timeoutMs);
|
|
105
|
+
timer.unref();
|
|
106
|
+
this.#pending.set(message.requestId, { resolve, reject, timer });
|
|
107
|
+
});
|
|
108
|
+
this.child.send(message, (error) => {
|
|
109
|
+
if (error === null)
|
|
110
|
+
return;
|
|
111
|
+
const entry = this.#pending.get(message.requestId);
|
|
112
|
+
if (entry) {
|
|
113
|
+
clearTimeout(entry.timer);
|
|
114
|
+
this.#pending.delete(message.requestId);
|
|
115
|
+
entry.reject(fault("CLAUDE_NATIVE_HELPER_IPC_FAILED", true));
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
return await pending;
|
|
119
|
+
}
|
|
120
|
+
#message(value) {
|
|
121
|
+
try {
|
|
122
|
+
assertClaudeNativeHelperIpcSize(value);
|
|
123
|
+
if (!isClaudeNativeHelperChildMessage(value))
|
|
124
|
+
throw fault("CLAUDE_NATIVE_HELPER_PROTOCOL_INVALID");
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
this.#fail(error);
|
|
128
|
+
this.child.kill("SIGTERM");
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const message = value;
|
|
132
|
+
if (message.type === "event") {
|
|
133
|
+
this.callbacks.onEvent(message.value);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const pending = this.#pending.get(message.requestId);
|
|
137
|
+
if (!pending)
|
|
138
|
+
return;
|
|
139
|
+
clearTimeout(pending.timer);
|
|
140
|
+
this.#pending.delete(message.requestId);
|
|
141
|
+
if (message.ok)
|
|
142
|
+
pending.resolve(message.result);
|
|
143
|
+
else
|
|
144
|
+
pending.reject(fault(message.error.code, message.error.recoverable));
|
|
24
145
|
}
|
|
146
|
+
#fail(error) { for (const pending of this.#pending.values()) {
|
|
147
|
+
clearTimeout(pending.timer);
|
|
148
|
+
pending.reject(error);
|
|
149
|
+
} this.#pending.clear(); }
|
|
25
150
|
}
|
|
151
|
+
export const createClaudeNativeHelper = ClaudeNativeHelperClient.start;
|
|
26
152
|
export class ClaudeNativeHelperSupervisor {
|
|
27
|
-
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#maxPendingMessages;
|
|
32
|
-
#maxHelpers;
|
|
33
|
-
#callbacks;
|
|
153
|
+
options;
|
|
154
|
+
#helpers = new Map();
|
|
155
|
+
#receipts = new Map();
|
|
156
|
+
#preparations = new Set();
|
|
34
157
|
#factory;
|
|
35
|
-
#helpersByAlias = new Map();
|
|
36
|
-
#helpersByGeneration = new Map();
|
|
37
|
-
#receiptOwners = new Map();
|
|
38
|
-
#pendingDispatches = new Map();
|
|
39
158
|
#closed = false;
|
|
40
159
|
constructor(options) {
|
|
41
|
-
this
|
|
42
|
-
this.#runtime = { ...options.runtime };
|
|
43
|
-
this.#locale = options.locale;
|
|
44
|
-
this.#deliveryNotices = options.deliveryNotices;
|
|
45
|
-
this.#maxPendingMessages = options.maxPendingMessages;
|
|
46
|
-
this.#maxHelpers = options.maxHelpers;
|
|
47
|
-
this.#callbacks = options.callbacks;
|
|
160
|
+
this.options = options;
|
|
48
161
|
this.#factory = options.factory ?? createClaudeNativeHelper;
|
|
49
162
|
}
|
|
50
|
-
get size() {
|
|
51
|
-
return this.#helpersByAlias.size;
|
|
52
|
-
}
|
|
163
|
+
get size() { return this.#helpers.size; }
|
|
53
164
|
async advertise(input) {
|
|
54
|
-
this.#
|
|
55
|
-
|
|
165
|
+
if (this.#closed)
|
|
166
|
+
throw fault("CLAUDE_NATIVE_HELPER_SUPERVISOR_CLOSED");
|
|
167
|
+
if (!isGatewayProvider(input.sourceProvider) || !gatewayRegistrationIngressPrefixes[input.sourceProvider] ||
|
|
168
|
+
!input.alias.startsWith(gatewayRegistrationIngressPrefixes[input.sourceProvider]))
|
|
56
169
|
throw fault("PROVENANCE_ENVELOPE_INVALID");
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (incumbent.sourceProvider !== input.sourceProvider) {
|
|
170
|
+
const old = this.#helpers.get(input.alias);
|
|
171
|
+
if (old) {
|
|
172
|
+
if (old.sourceProvider !== input.sourceProvider)
|
|
61
173
|
throw fault("PROVENANCE_ENVELOPE_INVALID");
|
|
62
|
-
}
|
|
63
174
|
return;
|
|
64
175
|
}
|
|
65
|
-
if (this.#
|
|
176
|
+
if (this.#helpers.size >= this.options.maxHelpers)
|
|
66
177
|
throw fault("CLAUDE_NATIVE_HELPER_CAPACITY", true);
|
|
67
|
-
|
|
68
|
-
let record;
|
|
178
|
+
let helper, earlyExit = false;
|
|
69
179
|
const buffered = [];
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
deliveryNotices: this.#deliveryNotices,
|
|
76
|
-
maxPendingMessages: this.#maxPendingMessages,
|
|
77
|
-
registration: input,
|
|
78
|
-
callbacks: {
|
|
79
|
-
onEvent: (event) => {
|
|
80
|
-
if (record === undefined)
|
|
81
|
-
buffered.push(event);
|
|
82
|
-
else
|
|
83
|
-
this.#onEvent(record, event);
|
|
84
|
-
},
|
|
85
|
-
onExit: () => {
|
|
86
|
-
if (record === undefined)
|
|
87
|
-
exitedBeforeReady = true;
|
|
88
|
-
else
|
|
89
|
-
this.#onExit(record);
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
});
|
|
93
|
-
if (this.#closed || exitedBeforeReady) {
|
|
180
|
+
const client = await this.#factory({ runtime: this.options.runtime, hostId: "this-mac", locale: this.options.locale,
|
|
181
|
+
deliveryNotices: this.options.deliveryNotices, maxPendingMessages: this.options.maxPendingMessages, registration: input,
|
|
182
|
+
callbacks: { onEvent: (event) => helper ? this.#event(helper, event) : buffered.push(event),
|
|
183
|
+
onExit: () => helper ? this.#exit(helper) : earlyExit = true } });
|
|
184
|
+
if (this.#closed || earlyExit) {
|
|
94
185
|
await client.forceClose().catch(() => undefined);
|
|
95
186
|
throw fault("CLAUDE_NATIVE_HELPER_UNAVAILABLE", true);
|
|
96
187
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
activeAlias: input.alias,
|
|
100
|
-
sourceProvider: input.sourceProvider,
|
|
101
|
-
activeGeneration: client.generation,
|
|
102
|
-
authorizedRoutes: new Map(),
|
|
103
|
-
closing: false,
|
|
104
|
-
};
|
|
105
|
-
this.#helpersByAlias.set(input.alias, record);
|
|
106
|
-
this.#helpersByGeneration.set(client.generation, record);
|
|
188
|
+
helper = { client, alias: input.alias, sourceProvider: input.sourceProvider, closing: false };
|
|
189
|
+
this.#helpers.set(input.alias, helper);
|
|
107
190
|
for (const event of buffered)
|
|
108
|
-
this.#
|
|
109
|
-
try {
|
|
110
|
-
ok(await client.request({
|
|
111
|
-
method: "resume_generation",
|
|
112
|
-
generation: client.generation,
|
|
113
|
-
}));
|
|
114
|
-
}
|
|
115
|
-
catch (error) {
|
|
116
|
-
// The child may have activated before the response was lost. Preserve
|
|
117
|
-
// exact ownership in the supervisor so ordinary rollback can close it.
|
|
118
|
-
throw error;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
currentGeneration(alias) {
|
|
122
|
-
const helper = this.#helpersByAlias.get(alias);
|
|
123
|
-
if (helper === undefined || helper.closing) {
|
|
124
|
-
throw fault("CODEX_PEER_GENERATION_MISMATCH");
|
|
125
|
-
}
|
|
126
|
-
return helper.activeGeneration;
|
|
191
|
+
this.#event(helper, event);
|
|
127
192
|
}
|
|
128
193
|
async updateStatus(alias, status) {
|
|
129
|
-
const helper = this.#
|
|
130
|
-
if (helper
|
|
131
|
-
|
|
132
|
-
ok(await helper.client.request({ method: "update_status", alias, status }));
|
|
194
|
+
const helper = this.#helpers.get(alias);
|
|
195
|
+
if (helper && !helper.closing)
|
|
196
|
+
requireOk(await helper.client.request({ method: "update_status", alias, status }));
|
|
133
197
|
}
|
|
134
198
|
async unadvertise(alias) {
|
|
135
|
-
const helper = this.#
|
|
136
|
-
if (helper
|
|
199
|
+
const helper = this.#helpers.get(alias);
|
|
200
|
+
if (!helper)
|
|
137
201
|
return;
|
|
138
202
|
helper.closing = true;
|
|
139
203
|
let failure;
|
|
140
204
|
try {
|
|
141
|
-
|
|
205
|
+
requireOk(await helper.client.request({ method: "unadvertise", alias }));
|
|
142
206
|
}
|
|
143
207
|
catch (error) {
|
|
144
208
|
failure = error;
|
|
145
209
|
}
|
|
146
|
-
await helper.client.close().catch((error) => {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
this.#removeHelper(helper);
|
|
150
|
-
if (failure !== undefined)
|
|
210
|
+
await helper.client.close().catch((error) => { failure ??= error; });
|
|
211
|
+
this.#remove(helper);
|
|
212
|
+
if (failure)
|
|
151
213
|
throw failure;
|
|
152
214
|
}
|
|
153
|
-
async
|
|
154
|
-
if (
|
|
155
|
-
!
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
if (
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
if (helper.authorizedRoutes.get(input.binding.routeHandle) !== authority) {
|
|
184
|
-
ok(await helper.client.request({
|
|
185
|
-
method: "authorize_route",
|
|
186
|
-
alias: input.selectedAlias,
|
|
187
|
-
routeHandle: input.binding.routeHandle,
|
|
188
|
-
stateRoot: input.stateRoot,
|
|
189
|
-
}));
|
|
190
|
-
helper.authorizedRoutes.set(input.binding.routeHandle, authority);
|
|
215
|
+
async prepareDispatch(input) {
|
|
216
|
+
if (!ALIAS.test(input.sourceAlias) || !ALIAS.test(input.targetAlias) || !CONVERSATION.test(input.conversationId) ||
|
|
217
|
+
!isGatewayProvider(input.sourceProvider))
|
|
218
|
+
throw fault("PROVENANCE_ENVELOPE_INVALID");
|
|
219
|
+
if (Buffer.byteLength(input.text) > 16 * 1024)
|
|
220
|
+
throw fault("PROVENANCE_ENVELOPE_TOO_LARGE");
|
|
221
|
+
const helper = this.#helpers.get(input.sourceAlias);
|
|
222
|
+
if (!helper || helper.closing)
|
|
223
|
+
throw fault("CLAUDE_NATIVE_HELPER_UNAVAILABLE", true);
|
|
224
|
+
if (helper.sourceProvider !== input.sourceProvider)
|
|
225
|
+
throw fault("PROVENANCE_ENVELOPE_INVALID");
|
|
226
|
+
if (input.authorization === "selected_route" && !input.stateRoot)
|
|
227
|
+
throw fault("CLAUDE_ROUTE_UNAVAILABLE", true);
|
|
228
|
+
const result = await helper.client.request({ method: "prepare_dispatch", binding: input.binding,
|
|
229
|
+
authorization: input.authorization, ...(input.authorization === "selected_route" ? { stateRoot: input.stateRoot } : {}),
|
|
230
|
+
messageId: input.messageId, sourceAlias: helper.alias, sourceProvider: helper.sourceProvider,
|
|
231
|
+
targetAlias: input.targetAlias, conversationId: input.conversationId, text: input.text,
|
|
232
|
+
expectsReply: input.expectsReply, deadlineAt: input.deadlineAt,
|
|
233
|
+
...(input.progressWatchActive ? { progressWatchActive: true } : {}) }, this.#deadline(input.deadlineAt));
|
|
234
|
+
if (!("preparationId" in result))
|
|
235
|
+
throw fault("CLAUDE_NATIVE_HELPER_INVALID_RESPONSE");
|
|
236
|
+
let state = "prepared";
|
|
237
|
+
let tracked;
|
|
238
|
+
const cancel = async () => {
|
|
239
|
+
if (state !== "prepared")
|
|
240
|
+
return;
|
|
241
|
+
state = "consumed";
|
|
242
|
+
this.#preparations.delete(tracked);
|
|
243
|
+
try {
|
|
244
|
+
requireOk(await helper.client.request({ method: "cancel_dispatch", preparationId: result.preparationId }));
|
|
191
245
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
evidence: "none",
|
|
196
|
-
});
|
|
197
|
-
try {
|
|
198
|
-
const result = await helper.client.request({
|
|
199
|
-
method: "dispatch",
|
|
200
|
-
binding: input.binding,
|
|
201
|
-
authorization: input.authorization,
|
|
202
|
-
messageId: input.messageId,
|
|
203
|
-
sourceAlias: helper.activeAlias,
|
|
204
|
-
sourceProvider: helper.sourceProvider,
|
|
205
|
-
targetAlias: input.targetAlias,
|
|
206
|
-
conversationId: input.conversationId,
|
|
207
|
-
text: input.text,
|
|
208
|
-
expectsReply: input.expectsReply,
|
|
209
|
-
deadlineAt: input.deadlineAt,
|
|
210
|
-
...(input.progressWatchActive === true
|
|
211
|
-
? { progressWatchActive: true }
|
|
212
|
-
: {}),
|
|
213
|
-
}, Math.max(1, Math.min(60_000, Date.parse(input.deadlineAt) - Date.now())));
|
|
214
|
-
if (!("state" in result) ||
|
|
215
|
-
![
|
|
216
|
-
"pending",
|
|
217
|
-
"accepted",
|
|
218
|
-
"deferred",
|
|
219
|
-
"delivered",
|
|
220
|
-
"failed",
|
|
221
|
-
"ambiguous",
|
|
222
|
-
"cancelled",
|
|
223
|
-
].includes(String(result.state))) {
|
|
224
|
-
throw fault("CLAUDE_NATIVE_HELPER_INVALID_RESPONSE");
|
|
246
|
+
catch (error) {
|
|
247
|
+
if (!(error instanceof BridgeError) || error.code !== "CLAUDE_NATIVE_PREPARATION_UNKNOWN")
|
|
248
|
+
throw error;
|
|
225
249
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
const results = await Promise.allSettled([...new Set(this.#helpersByAlias.values())].map(async (helper) => {
|
|
239
|
-
helper.authorizedRoutes.delete(routeHandle);
|
|
240
|
-
ok(await helper.client.request({ method: "release_route", routeHandle }));
|
|
241
|
-
}));
|
|
242
|
-
const failed = results.find((result) => result.status === "rejected");
|
|
243
|
-
if (failed !== undefined)
|
|
244
|
-
throw failed.reason;
|
|
250
|
+
};
|
|
251
|
+
const perform = () => {
|
|
252
|
+
if (state !== "prepared")
|
|
253
|
+
return Promise.resolve({ state: "failed", safeErrorCode: "CLAUDE_NATIVE_PREPARATION_CONSUMED" });
|
|
254
|
+
state = "consumed";
|
|
255
|
+
this.#preparations.delete(tracked);
|
|
256
|
+
return helper.client.request({ method: "perform_dispatch", preparationId: result.preparationId }, this.#deadline(input.deadlineAt)).then((value) => "state" in value ? value : { state: "ambiguous", safeErrorCode: "CLAUDE_NATIVE_HELPER_INVALID_RESPONSE" }, (error) => error instanceof BridgeError && ["CLAUDE_NATIVE_PREPARATION_UNKNOWN", "CLAUDE_NATIVE_PREPARATION_MISMATCH", "CLAUDE_PEER_PREPARATION_CONSUMED"].includes(error.code)
|
|
257
|
+
? { state: "failed", safeErrorCode: error.code } : { state: "ambiguous", safeErrorCode: "CLAUDE_NATIVE_HELPER_PERFORM_UNCERTAIN" });
|
|
258
|
+
};
|
|
259
|
+
tracked = { helper, cancel };
|
|
260
|
+
this.#preparations.add(tracked);
|
|
261
|
+
return Object.freeze({ frameBytes: result.frameBytes, sha256: result.sha256, perform, cancel });
|
|
245
262
|
}
|
|
246
263
|
async updateInboundStatus(receiptHandle, status, diagnosticCode) {
|
|
247
|
-
const owner = this.#
|
|
264
|
+
const owner = this.#receipt(receiptHandle);
|
|
248
265
|
try {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
receiptHandle: owner.childHandle,
|
|
252
|
-
status,
|
|
253
|
-
...(diagnosticCode === undefined ? {} : { diagnosticCode }),
|
|
254
|
-
}));
|
|
266
|
+
requireOk(await owner.helper.client.request({ method: "update_inbound_status",
|
|
267
|
+
receiptHandle: owner.childHandle, status, ...(diagnosticCode ? { diagnosticCode } : {}) }));
|
|
255
268
|
if (status !== "held")
|
|
256
|
-
this.#
|
|
269
|
+
this.#receipts.delete(receiptHandle);
|
|
257
270
|
}
|
|
258
271
|
catch (error) {
|
|
259
|
-
if (status !== "held" &&
|
|
260
|
-
(
|
|
261
|
-
this.#receiptOwners.delete(receiptHandle);
|
|
262
|
-
}
|
|
272
|
+
if (status !== "held" && (!(error instanceof BridgeError) || !error.recoverable))
|
|
273
|
+
this.#receipts.delete(receiptHandle);
|
|
263
274
|
throw error;
|
|
264
275
|
}
|
|
265
276
|
}
|
|
266
277
|
async notifyInboundProgress(receiptHandle, progress) {
|
|
267
|
-
const owner = this.#
|
|
268
|
-
|
|
269
|
-
method: "notify_inbound_progress",
|
|
270
|
-
receiptHandle: owner.childHandle,
|
|
271
|
-
progress,
|
|
272
|
-
}));
|
|
278
|
+
const owner = this.#receipt(receiptHandle);
|
|
279
|
+
requireOk(await owner.helper.client.request({ method: "notify_inbound_progress", receiptHandle: owner.childHandle, progress }));
|
|
273
280
|
}
|
|
274
281
|
async releaseInboundReceipt(receiptHandle) {
|
|
275
|
-
const owner = this.#
|
|
276
|
-
if (owner
|
|
282
|
+
const owner = this.#receipts.get(receiptHandle);
|
|
283
|
+
if (!owner)
|
|
277
284
|
return false;
|
|
278
|
-
this.#
|
|
279
|
-
const result = await owner.helper.client.request({
|
|
280
|
-
|
|
281
|
-
receiptHandle: owner.childHandle,
|
|
282
|
-
});
|
|
283
|
-
return "released" in result && result.released === true;
|
|
284
|
-
}
|
|
285
|
-
async quiesceAll() {
|
|
286
|
-
const results = await Promise.allSettled([...new Set(this.#helpersByAlias.values())].map(async (helper) => {
|
|
287
|
-
ok(await helper.client.request({
|
|
288
|
-
method: "quiesce_generation",
|
|
289
|
-
generation: helper.activeGeneration,
|
|
290
|
-
}));
|
|
291
|
-
}));
|
|
292
|
-
const failed = results.find((result) => result.status === "rejected");
|
|
293
|
-
if (failed !== undefined)
|
|
294
|
-
throw failed.reason;
|
|
295
|
-
}
|
|
296
|
-
async quiesceGeneration(generation) {
|
|
297
|
-
const helper = this.#requireGeneration(generation);
|
|
298
|
-
ok(await helper.client.request({ method: "quiesce_generation", generation }));
|
|
299
|
-
}
|
|
300
|
-
async observeBarrier(generation) {
|
|
301
|
-
const helper = this.#requireGeneration(generation);
|
|
302
|
-
const result = await helper.client.request({ method: "observe_barrier", generation });
|
|
303
|
-
if (!("clean" in result) || !("generation" in result)) {
|
|
304
|
-
throw fault("CLAUDE_NATIVE_HELPER_INVALID_RESPONSE");
|
|
305
|
-
}
|
|
306
|
-
return result;
|
|
307
|
-
}
|
|
308
|
-
async prepareGeneration(input) {
|
|
309
|
-
const helper = this.#helpersByGeneration.get(input.currentGeneration);
|
|
310
|
-
if (helper === undefined ||
|
|
311
|
-
helper.activeGeneration !== input.currentGeneration ||
|
|
312
|
-
helper.prepared !== undefined) {
|
|
313
|
-
throw fault("CODEX_PEER_SUCCESSION_CAPACITY");
|
|
314
|
-
}
|
|
315
|
-
ok(await helper.client.request({
|
|
316
|
-
method: "prepare_generation",
|
|
317
|
-
alias: input.alias,
|
|
318
|
-
cwd: input.cwd,
|
|
319
|
-
generation: input.generation,
|
|
320
|
-
}));
|
|
321
|
-
helper.prepared = { alias: input.alias, generation: input.generation };
|
|
322
|
-
this.#helpersByGeneration.set(input.generation, helper);
|
|
323
|
-
}
|
|
324
|
-
async publishPrepared(input) {
|
|
325
|
-
const helper = this.#requireGeneration(input.currentGeneration);
|
|
326
|
-
if (this.#requireGeneration(input.preparedGeneration) !== helper) {
|
|
327
|
-
throw fault("CODEX_PEER_SUCCESSION_GENERATION_MISMATCH");
|
|
328
|
-
}
|
|
329
|
-
const result = await helper.client.request({
|
|
330
|
-
method: "publish_prepared",
|
|
331
|
-
...input,
|
|
332
|
-
});
|
|
333
|
-
if (!("publication" in result)) {
|
|
334
|
-
throw fault("CLAUDE_NATIVE_HELPER_INVALID_RESPONSE");
|
|
335
|
-
}
|
|
336
|
-
return result.publication;
|
|
337
|
-
}
|
|
338
|
-
async activatePrepared(generation) {
|
|
339
|
-
const helper = this.#requireGeneration(generation);
|
|
340
|
-
const prepared = helper.prepared;
|
|
341
|
-
if (prepared?.generation !== generation) {
|
|
342
|
-
throw fault("CODEX_PEER_SUCCESSION_GENERATION_MISMATCH");
|
|
343
|
-
}
|
|
344
|
-
const oldAlias = helper.activeAlias;
|
|
345
|
-
const oldGeneration = helper.activeGeneration;
|
|
346
|
-
ok(await helper.client.request({ method: "activate_prepared", generation }));
|
|
347
|
-
this.#helpersByAlias.delete(oldAlias);
|
|
348
|
-
helper.retiredGeneration = oldGeneration;
|
|
349
|
-
helper.activeAlias = prepared.alias;
|
|
350
|
-
helper.activeGeneration = prepared.generation;
|
|
351
|
-
delete helper.prepared;
|
|
352
|
-
helper.authorizedRoutes.clear();
|
|
353
|
-
this.#helpersByAlias.set(helper.activeAlias, helper);
|
|
354
|
-
}
|
|
355
|
-
async cleanupPrepared(generation) {
|
|
356
|
-
const helper = this.#requireGeneration(generation);
|
|
357
|
-
ok(await helper.client.request({ method: "cleanup_prepared", generation }));
|
|
358
|
-
if (helper.prepared?.generation === generation)
|
|
359
|
-
delete helper.prepared;
|
|
360
|
-
this.#helpersByGeneration.delete(generation);
|
|
361
|
-
}
|
|
362
|
-
async resumeGeneration(generation) {
|
|
363
|
-
const helper = this.#requireGeneration(generation);
|
|
364
|
-
ok(await helper.client.request({ method: "resume_generation", generation }));
|
|
365
|
-
}
|
|
366
|
-
async rollbackPrepared(input) {
|
|
367
|
-
const helper = this.#requireGeneration(input.resumeGeneration);
|
|
368
|
-
if (this.#requireGeneration(input.preparedGeneration) !== helper) {
|
|
369
|
-
throw fault("CODEX_PEER_SUCCESSION_GENERATION_MISMATCH");
|
|
370
|
-
}
|
|
371
|
-
ok(await helper.client.request({ method: "rollback_prepared", ...input }));
|
|
372
|
-
if (helper.prepared?.generation === input.preparedGeneration) {
|
|
373
|
-
delete helper.prepared;
|
|
374
|
-
}
|
|
375
|
-
this.#helpersByGeneration.delete(input.preparedGeneration);
|
|
376
|
-
}
|
|
377
|
-
async retireGeneration(input) {
|
|
378
|
-
const helper = this.#requireGeneration(input.protectedActiveGeneration);
|
|
379
|
-
if (this.#requireGeneration(input.retiredGeneration) !== helper) {
|
|
380
|
-
throw fault("CODEX_PEER_SUCCESSION_GENERATION_MISMATCH");
|
|
381
|
-
}
|
|
382
|
-
ok(await helper.client.request({ method: "retire_generation", ...input }));
|
|
383
|
-
if (helper.retiredGeneration === input.retiredGeneration) {
|
|
384
|
-
delete helper.retiredGeneration;
|
|
385
|
-
}
|
|
386
|
-
this.#helpersByGeneration.delete(input.retiredGeneration);
|
|
387
|
-
}
|
|
388
|
-
async purgeGenerationReplies(generation) {
|
|
389
|
-
const helper = this.#requireGeneration(generation);
|
|
390
|
-
const result = await helper.client.request({
|
|
391
|
-
method: "purge_generation_replies",
|
|
392
|
-
generation,
|
|
393
|
-
});
|
|
394
|
-
if (!("purged" in result) || !Number.isSafeInteger(result.purged)) {
|
|
395
|
-
throw fault("CLAUDE_NATIVE_HELPER_INVALID_RESPONSE");
|
|
396
|
-
}
|
|
397
|
-
return result.purged;
|
|
285
|
+
this.#receipts.delete(receiptHandle);
|
|
286
|
+
const result = await owner.helper.client.request({ method: "release_inbound_receipt", receiptHandle: owner.childHandle });
|
|
287
|
+
return "released" in result && result.released;
|
|
398
288
|
}
|
|
399
289
|
async close() {
|
|
400
290
|
if (this.#closed)
|
|
401
291
|
return;
|
|
402
292
|
this.#closed = true;
|
|
403
|
-
|
|
293
|
+
await Promise.allSettled([...this.#preparations].map((item) => item.cancel()));
|
|
294
|
+
const helpers = [...this.#helpers.values()];
|
|
404
295
|
for (const helper of helpers)
|
|
405
296
|
helper.closing = true;
|
|
406
|
-
const results = await Promise.allSettled(helpers.map(
|
|
297
|
+
const results = await Promise.allSettled(helpers.map((helper) => helper.client.close()));
|
|
407
298
|
for (const helper of helpers)
|
|
408
|
-
this.#
|
|
299
|
+
this.#remove(helper);
|
|
409
300
|
const failed = results.find((result) => result.status === "rejected");
|
|
410
|
-
if (failed
|
|
301
|
+
if (failed)
|
|
411
302
|
throw failed.reason;
|
|
412
303
|
}
|
|
413
|
-
#
|
|
304
|
+
#event(helper, event) {
|
|
414
305
|
if (helper.closing || this.#closed)
|
|
415
306
|
return;
|
|
416
|
-
const callbacks = this
|
|
417
|
-
if (event.event === "delivery") {
|
|
418
|
-
const pending = this.#pendingDispatches.get(event.value.messageId);
|
|
419
|
-
if (pending?.helper !== helper)
|
|
420
|
-
return;
|
|
421
|
-
if (event.value.state === "transport_uncertain") {
|
|
422
|
-
pending.evidence = "transport_uncertain";
|
|
423
|
-
}
|
|
424
|
-
else if (event.value.state === "transport_written" ||
|
|
425
|
-
event.value.state === "held") {
|
|
426
|
-
pending.evidence = "transport_written";
|
|
427
|
-
}
|
|
428
|
-
if (TERMINAL_DELIVERY_STATES.has(event.value.state)) {
|
|
429
|
-
this.#pendingDispatches.delete(event.value.messageId);
|
|
430
|
-
}
|
|
431
|
-
callbacks?.onDelivery({ ...event.value });
|
|
432
|
-
return;
|
|
433
|
-
}
|
|
434
|
-
if (event.event === "claude_reply") {
|
|
435
|
-
callbacks?.onClaudeReply({
|
|
436
|
-
endpoint: { ...this.#identity, routeHandle: event.value.routeHandle },
|
|
437
|
-
text: event.value.text,
|
|
438
|
-
});
|
|
439
|
-
return;
|
|
440
|
-
}
|
|
307
|
+
const callbacks = this.options.callbacks();
|
|
441
308
|
if (event.event === "protocol_notice") {
|
|
442
|
-
callbacks?.onProtocolNotice?.(
|
|
309
|
+
callbacks?.onProtocolNotice?.(event.value);
|
|
443
310
|
return;
|
|
444
311
|
}
|
|
445
|
-
if (event.value.targetAlias !== helper.
|
|
312
|
+
if (event.value.targetAlias !== helper.alias) {
|
|
446
313
|
callbacks?.onProtocolNotice?.({ code: "CLAUDE_NATIVE_HELPER_TARGET_MISMATCH" });
|
|
447
314
|
return;
|
|
448
315
|
}
|
|
449
316
|
let receiptHandle;
|
|
450
|
-
if (event.value.receiptHandle
|
|
451
|
-
if (this.#
|
|
452
|
-
void helper.client
|
|
453
|
-
.
|
|
454
|
-
method: "update_inbound_status",
|
|
455
|
-
receiptHandle: event.value.receiptHandle,
|
|
456
|
-
status: "expired",
|
|
457
|
-
diagnosticCode: "CLAUDE_NATIVE_INGRESS_CAPACITY",
|
|
458
|
-
})
|
|
459
|
-
.catch(() => undefined);
|
|
317
|
+
if (event.value.receiptHandle) {
|
|
318
|
+
if (this.#receipts.size >= this.options.maxPendingMessages) {
|
|
319
|
+
void helper.client.request({ method: "update_inbound_status",
|
|
320
|
+
receiptHandle: event.value.receiptHandle, status: "expired", diagnosticCode: "CLAUDE_NATIVE_INGRESS_CAPACITY" }).catch(() => undefined);
|
|
460
321
|
return;
|
|
461
322
|
}
|
|
462
|
-
receiptHandle = `nrc_${
|
|
463
|
-
this.#
|
|
464
|
-
helper,
|
|
465
|
-
childHandle: event.value.receiptHandle,
|
|
466
|
-
});
|
|
323
|
+
receiptHandle = `nrc_${id()}`;
|
|
324
|
+
this.#receipts.set(receiptHandle, { helper, childHandle: event.value.receiptHandle });
|
|
467
325
|
}
|
|
468
|
-
callbacks?.onClaudeMessage?.({
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
targetAlias: event.value.targetAlias,
|
|
472
|
-
text: event.value.text,
|
|
473
|
-
...(receiptHandle === undefined ? {} : { receiptHandle }),
|
|
474
|
-
});
|
|
475
|
-
}
|
|
476
|
-
#onExit(helper) {
|
|
477
|
-
const intentional = helper.closing || this.#closed;
|
|
478
|
-
if (intentional) {
|
|
479
|
-
this.#removeHelper(helper);
|
|
480
|
-
return;
|
|
481
|
-
}
|
|
482
|
-
const callbacks = this.#callbacks();
|
|
483
|
-
for (const [messageId, pending] of this.#pendingDispatches) {
|
|
484
|
-
if (pending.helper !== helper)
|
|
485
|
-
continue;
|
|
486
|
-
this.#pendingDispatches.delete(messageId);
|
|
487
|
-
callbacks?.onDelivery({
|
|
488
|
-
messageId,
|
|
489
|
-
state: pending.evidence === "transport_written"
|
|
490
|
-
? "unconfirmed"
|
|
491
|
-
: pending.evidence === "transport_uncertain"
|
|
492
|
-
? "ambiguous"
|
|
493
|
-
: "failed",
|
|
494
|
-
safeErrorCode: "CLAUDE_NATIVE_HELPER_EXITED",
|
|
495
|
-
});
|
|
496
|
-
}
|
|
497
|
-
callbacks?.onProtocolNotice?.({ code: "CLAUDE_NATIVE_HELPER_EXITED" });
|
|
498
|
-
this.#removeHelper(helper);
|
|
326
|
+
callbacks?.onClaudeMessage?.({ endpoint: { ...this.options.identity, routeHandle: event.value.routeHandle },
|
|
327
|
+
sourceAlias: event.value.sourceAlias, targetAlias: event.value.targetAlias, text: event.value.text,
|
|
328
|
+
...(receiptHandle ? { receiptHandle } : {}) });
|
|
499
329
|
}
|
|
500
|
-
#
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
for (const [
|
|
506
|
-
if (candidate === helper)
|
|
507
|
-
this.#helpersByGeneration.delete(generation);
|
|
508
|
-
}
|
|
509
|
-
for (const [handle, owner] of this.#receiptOwners) {
|
|
330
|
+
#exit(helper) { if (!helper.closing && !this.#closed)
|
|
331
|
+
this.options.callbacks()?.onProtocolNotice?.({ code: "CLAUDE_NATIVE_HELPER_EXITED" }); this.#remove(helper); }
|
|
332
|
+
#remove(helper) {
|
|
333
|
+
if (this.#helpers.get(helper.alias) === helper)
|
|
334
|
+
this.#helpers.delete(helper.alias);
|
|
335
|
+
for (const [id, owner] of this.#receipts)
|
|
510
336
|
if (owner.helper === helper)
|
|
511
|
-
this.#
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
this.#pendingDispatches.delete(messageId);
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
#requireGeneration(generation) {
|
|
519
|
-
const helper = this.#helpersByGeneration.get(generation);
|
|
520
|
-
if (helper === undefined || helper.closing) {
|
|
521
|
-
throw fault("CODEX_PEER_SUCCESSION_GENERATION_MISMATCH");
|
|
522
|
-
}
|
|
523
|
-
return helper;
|
|
524
|
-
}
|
|
525
|
-
#requireReceipt(receiptHandle) {
|
|
526
|
-
const owner = this.#receiptOwners.get(receiptHandle);
|
|
527
|
-
if (owner === undefined || owner.helper.closing) {
|
|
528
|
-
throw fault("CLAUDE_PEER_RECEIPT_UNKNOWN");
|
|
529
|
-
}
|
|
530
|
-
return owner;
|
|
531
|
-
}
|
|
532
|
-
#assertOpen() {
|
|
533
|
-
if (this.#closed)
|
|
534
|
-
throw fault("CLAUDE_NATIVE_HELPER_SUPERVISOR_CLOSED");
|
|
337
|
+
this.#receipts.delete(id);
|
|
338
|
+
for (const prepared of [...this.#preparations])
|
|
339
|
+
if (prepared.helper === helper)
|
|
340
|
+
this.#preparations.delete(prepared);
|
|
535
341
|
}
|
|
342
|
+
#receipt(id) { const owner = this.#receipts.get(id); if (!owner || owner.helper.closing)
|
|
343
|
+
throw fault("CLAUDE_PEER_RECEIPT_UNKNOWN"); return owner; }
|
|
344
|
+
#deadline(value) { return Math.max(1, Math.min(60_000, Date.parse(value) - Date.now())); }
|
|
536
345
|
}
|
|
537
346
|
//# sourceMappingURL=claude-helper-supervisor.js.map
|