agent-embassy 1.6.1 → 1.7.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 +20 -0
- package/README.md +9 -9
- package/README.zh-CN.md +9 -9
- package/SECURITY.md +34 -77
- package/dist/src/gateway/acp-client.d.ts +117 -0
- package/dist/src/gateway/acp-client.js +382 -0
- package/dist/src/gateway/acp-client.js.map +1 -0
- package/dist/src/gateway/acp-provider.d.ts +65 -0
- package/dist/src/gateway/acp-provider.js +163 -0
- package/dist/src/gateway/acp-provider.js.map +1 -0
- package/dist/src/gateway/claude-helper-protocol.d.ts +3 -1
- package/dist/src/gateway/claude-helper-protocol.js +15 -5
- package/dist/src/gateway/claude-helper-protocol.js.map +1 -1
- package/dist/src/gateway/claude-helper-supervisor.d.ts +3 -1
- package/dist/src/gateway/claude-helper-supervisor.js +16 -2
- package/dist/src/gateway/claude-helper-supervisor.js.map +1 -1
- package/dist/src/gateway/claude-helper.js +4 -3
- package/dist/src/gateway/claude-helper.js.map +1 -1
- package/dist/src/gateway/claude-peer.d.ts +1 -1
- package/dist/src/gateway/claude-peer.js +11 -13
- package/dist/src/gateway/claude-peer.js.map +1 -1
- package/dist/src/gateway/claude-runtime.d.ts +0 -20
- package/dist/src/gateway/claude-runtime.js +6 -127
- package/dist/src/gateway/claude-runtime.js.map +1 -1
- package/dist/src/gateway/cli-copy.en.d.ts +1 -1
- package/dist/src/gateway/cli-copy.en.js +2 -2
- package/dist/src/gateway/cli-copy.zh-CN.d.ts +1 -1
- package/dist/src/gateway/cli-copy.zh-CN.js +2 -2
- package/dist/src/gateway/cli.d.ts +1 -1
- package/dist/src/gateway/cli.js +26 -5
- package/dist/src/gateway/cli.js.map +1 -1
- package/dist/src/gateway/codex-app-server.d.ts +5 -74
- package/dist/src/gateway/codex-app-server.js +9 -599
- package/dist/src/gateway/codex-app-server.js.map +1 -1
- package/dist/src/gateway/codex-local-transport.d.ts +8 -26
- package/dist/src/gateway/codex-local-transport.js +26 -76
- package/dist/src/gateway/codex-local-transport.js.map +1 -1
- package/dist/src/gateway/compatibility.d.ts +6 -66
- package/dist/src/gateway/compatibility.js +14 -296
- package/dist/src/gateway/compatibility.js.map +1 -1
- package/dist/src/gateway/config.d.ts +9 -0
- package/dist/src/gateway/config.js +6 -2
- package/dist/src/gateway/config.js.map +1 -1
- package/dist/src/gateway/control.d.ts +16 -1
- package/dist/src/gateway/control.js +89 -57
- 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 +14 -44
- package/dist/src/gateway/dashboard-copy.en.js +37 -67
- package/dist/src/gateway/dashboard-copy.en.js.map +1 -1
- package/dist/src/gateway/dashboard-copy.js +14 -44
- package/dist/src/gateway/dashboard-copy.js.map +1 -1
- package/dist/src/gateway/dashboard-copy.zh-CN.d.ts +14 -44
- package/dist/src/gateway/dashboard-copy.zh-CN.js +37 -67
- package/dist/src/gateway/dashboard-copy.zh-CN.js.map +1 -1
- package/dist/src/gateway/dashboard-model.d.ts +38 -76
- package/dist/src/gateway/dashboard-model.js +158 -256
- package/dist/src/gateway/dashboard-model.js.map +1 -1
- package/dist/src/gateway/dashboard.d.ts +0 -3
- package/dist/src/gateway/dashboard.js +75 -76
- package/dist/src/gateway/dashboard.js.map +1 -1
- package/dist/src/gateway/deepseek-detect.d.ts +7 -6
- package/dist/src/gateway/deepseek-detect.js +31 -115
- package/dist/src/gateway/deepseek-detect.js.map +1 -1
- package/dist/src/gateway/live-dashboard-app/app.js +166 -621
- package/dist/src/gateway/live-dashboard-command.js +2 -4
- package/dist/src/gateway/live-dashboard-command.js.map +1 -1
- package/dist/src/gateway/live-dashboard-http.d.ts +1 -2
- package/dist/src/gateway/live-dashboard-http.js +14 -15
- package/dist/src/gateway/live-dashboard-http.js.map +1 -1
- package/dist/src/gateway/progress-watch-machine.d.ts +1 -4
- package/dist/src/gateway/progress-watch-machine.js.map +1 -1
- package/dist/src/gateway/provenance-envelope.d.ts +3 -2
- package/dist/src/gateway/provenance-envelope.js +44 -11
- package/dist/src/gateway/provenance-envelope.js.map +1 -1
- package/dist/src/gateway/providers.d.ts +12 -85
- package/dist/src/gateway/providers.js +72 -835
- package/dist/src/gateway/providers.js.map +1 -1
- package/dist/src/gateway/server.d.ts +8 -9
- package/dist/src/gateway/server.js +51 -99
- package/dist/src/gateway/server.js.map +1 -1
- package/dist/src/gateway/service.d.ts +22 -49
- package/dist/src/gateway/service.js +196 -437
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/store.d.ts +20 -29
- package/dist/src/gateway/store.js +281 -827
- package/dist/src/gateway/store.js.map +1 -1
- package/dist/src/gateway/types.d.ts +55 -55
- package/dist/src/gateway/types.js +49 -91
- package/dist/src/gateway/types.js.map +1 -1
- package/docs/CONFIGURATION.md +11 -10
- package/docs/CONFIGURATION.zh-CN.md +10 -9
- package/docs/DASHBOARD.md +4 -38
- package/docs/DASHBOARD.zh-CN.md +4 -2
- package/docs/GATEWAY-ARCHITECTURE.md +61 -119
- package/package.json +1 -1
- package/skills/embassy-peer/SKILL.md +6 -6
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { chmod, lstat, mkdir, mkdtemp, readdir, realpath, rmdir, } from "node:fs/promises";
|
|
3
2
|
import { BridgeError } from "../errors.js";
|
|
4
3
|
import { CLAUDE_PEER_COMPATIBILITY, ClaudePeerAdapter, } from "./claude-peer.js";
|
|
5
|
-
import {
|
|
6
|
-
import { CODEX_APP_SERVER_WRITABLE_VERSIONS, CodexAppServerConnector, CodexConnectorError, codexWriteProbeFailure, } from "./codex-app-server.js";
|
|
4
|
+
import { CodexAppServerConnector, CodexConnectorError, } from "./codex-app-server.js";
|
|
7
5
|
import { LocalCodexTransportError } from "./codex-local-transport.js";
|
|
8
6
|
import { ClaudeNativeHelperSupervisor, } from "./claude-helper-supervisor.js";
|
|
9
7
|
import { isDashboardLocale } from "./locale.js";
|
|
10
8
|
import { composeProvenanceEnvelope } from "./provenance-envelope.js";
|
|
9
|
+
import { gatewayRegistrationIngressPrefixes } from "./types.js";
|
|
11
10
|
const LOCAL_HOST = "this-mac";
|
|
12
11
|
const STABLE_CLAUDE_ENDPOINT_GENERATION = "claude_local_endpoint";
|
|
13
12
|
const NATIVE_CLAUDE_NAME = /^[a-z][a-z0-9_-]{0,31}$/;
|
|
@@ -24,13 +23,6 @@ const DEFAULT_CODEX_CLEANUP_POLL_MS = 25;
|
|
|
24
23
|
const DEFAULT_CODEX_RECOVERY_INITIAL_MS = 250;
|
|
25
24
|
const DEFAULT_CODEX_RECOVERY_MAX_MS = 5_000;
|
|
26
25
|
const MAX_CODEX_ENDPOINT_REFRESH_CANDIDATES = 3;
|
|
27
|
-
const COMPATIBILITY_PROBE_THREAD_ID = "00000000-0000-7000-8000-000000000000";
|
|
28
|
-
const CODEX_WRITE_PROBE_DIRECTORY_PREFIX = ".codex-write-probe-";
|
|
29
|
-
const CODEX_WRITE_PROBE_ROOT = "write-probes";
|
|
30
|
-
const MAX_CODEX_WRITE_PROBE_ATTEMPTS = 16;
|
|
31
|
-
const CODEX_WRITE_PROBE_TRANSIENT_ERRNOS = new Set([
|
|
32
|
-
"EAGAIN", "EIO", "EMFILE", "ENFILE",
|
|
33
|
-
]);
|
|
34
26
|
const CLAUDE_CLEAN_PREWRITE_RETRY_CODES = new Set([
|
|
35
27
|
"CLAUDE_PEER_TARGET_UNKNOWN",
|
|
36
28
|
"CLAUDE_PEER_TARGET_STALE",
|
|
@@ -86,105 +78,6 @@ function claudeCleanPrewriteResult(error) {
|
|
|
86
78
|
: "CLAUDE_DISPATCH_PREWRITE_FAILED",
|
|
87
79
|
};
|
|
88
80
|
}
|
|
89
|
-
function passedProbe(name) {
|
|
90
|
-
return { name, outcome: "pass" };
|
|
91
|
-
}
|
|
92
|
-
function failedProbe(name, safeErrorCode) {
|
|
93
|
-
return { name, outcome: "fail", safeErrorCode };
|
|
94
|
-
}
|
|
95
|
-
function systemErrorCode(error) {
|
|
96
|
-
return typeof error === "object" &&
|
|
97
|
-
error !== null &&
|
|
98
|
-
"code" in error &&
|
|
99
|
-
typeof error.code === "string"
|
|
100
|
-
? error.code
|
|
101
|
-
: undefined;
|
|
102
|
-
}
|
|
103
|
-
function transientCodexWriteProbeError(error) {
|
|
104
|
-
return CODEX_WRITE_PROBE_TRANSIENT_ERRNOS.has(systemErrorCode(error) ?? "");
|
|
105
|
-
}
|
|
106
|
-
function safeCodexWriteProbeFilesystemFailure(error) {
|
|
107
|
-
return (transientCodexWriteProbeError(error) ||
|
|
108
|
-
systemErrorCode(error) === "ENOTEMPTY" ||
|
|
109
|
-
(error instanceof BridgeError &&
|
|
110
|
-
error.code === "CODEX_WRITE_PROBE_THREAD_SETUP_FAILED"));
|
|
111
|
-
}
|
|
112
|
-
async function attestCodexWriteProbeDirectory(directory) {
|
|
113
|
-
try {
|
|
114
|
-
const resolved = path.resolve(directory);
|
|
115
|
-
const [metadata, canonical, entries] = await Promise.all([
|
|
116
|
-
lstat(resolved, { bigint: true }),
|
|
117
|
-
realpath(resolved),
|
|
118
|
-
readdir(resolved),
|
|
119
|
-
]);
|
|
120
|
-
const uid = process.getuid?.();
|
|
121
|
-
if (uid === undefined ||
|
|
122
|
-
!metadata.isDirectory() ||
|
|
123
|
-
canonical !== resolved ||
|
|
124
|
-
metadata.uid !== BigInt(uid) ||
|
|
125
|
-
(metadata.mode & 511n) !== 448n) {
|
|
126
|
-
throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "The disposable Codex probe directory crossed its ownership, mode, or canonical-path boundary.");
|
|
127
|
-
}
|
|
128
|
-
if (entries.length !== 0) {
|
|
129
|
-
throw new BridgeError("CODEX_WRITE_PROBE_THREAD_SETUP_FAILED", "The disposable Codex probe directory was not empty.");
|
|
130
|
-
}
|
|
131
|
-
return {
|
|
132
|
-
dev: metadata.dev,
|
|
133
|
-
ino: metadata.ino,
|
|
134
|
-
mode: metadata.mode & 511n,
|
|
135
|
-
mtimeNs: metadata.mtimeNs,
|
|
136
|
-
uid: metadata.uid,
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
catch (error) {
|
|
140
|
-
if (error instanceof BridgeError)
|
|
141
|
-
throw error;
|
|
142
|
-
if (transientCodexWriteProbeError(error)) {
|
|
143
|
-
throw new BridgeError("CODEX_WRITE_PROBE_THREAD_SETUP_FAILED", "A transient filesystem error prevented disposable probe attestation.");
|
|
144
|
-
}
|
|
145
|
-
throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "The disposable Codex probe directory could not be attested safely.");
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
async function attestCodexWriteProbeRoot(root) {
|
|
149
|
-
try {
|
|
150
|
-
const resolved = path.resolve(root);
|
|
151
|
-
const [metadata, canonical] = await Promise.all([
|
|
152
|
-
lstat(resolved, { bigint: true }),
|
|
153
|
-
realpath(resolved),
|
|
154
|
-
]);
|
|
155
|
-
const uid = process.getuid?.();
|
|
156
|
-
if (uid === undefined ||
|
|
157
|
-
!metadata.isDirectory() ||
|
|
158
|
-
canonical !== resolved ||
|
|
159
|
-
metadata.uid !== BigInt(uid) ||
|
|
160
|
-
(metadata.mode & 511n) !== 448n) {
|
|
161
|
-
throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "A controller-owned Codex probe root changed outside its exact owned-directory boundary.");
|
|
162
|
-
}
|
|
163
|
-
return {
|
|
164
|
-
dev: metadata.dev,
|
|
165
|
-
ino: metadata.ino,
|
|
166
|
-
mode: metadata.mode & 511n,
|
|
167
|
-
uid: metadata.uid,
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
catch (error) {
|
|
171
|
-
if (error instanceof BridgeError)
|
|
172
|
-
throw error;
|
|
173
|
-
if (transientCodexWriteProbeError(error)) {
|
|
174
|
-
return null;
|
|
175
|
-
}
|
|
176
|
-
throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "A controller-owned Codex probe root could not be attested.");
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
function sameCodexWriteProbeDirectory(before, after) {
|
|
180
|
-
return sameCodexWriteProbeRoot(before, after) && before.mtimeNs === after.mtimeNs;
|
|
181
|
-
}
|
|
182
|
-
function sameCodexWriteProbeRoot(before, after) {
|
|
183
|
-
return (before.dev === after.dev &&
|
|
184
|
-
before.ino === after.ino &&
|
|
185
|
-
before.mode === after.mode &&
|
|
186
|
-
before.uid === after.uid);
|
|
187
|
-
}
|
|
188
81
|
function exactLocalHost(hostId) {
|
|
189
82
|
if ((hostId ?? LOCAL_HOST) !== LOCAL_HOST) {
|
|
190
83
|
throw new BridgeError("GATEWAY_REMOTE_PROVIDER_DISABLED", "This provider is restricted to the exact local host boundary.");
|
|
@@ -226,18 +119,6 @@ function invokeCallback(operation) {
|
|
|
226
119
|
}
|
|
227
120
|
}
|
|
228
121
|
function validateAttestedClaudeRuntime(runtime) {
|
|
229
|
-
if (runtime.versionEvidenceFailure !== undefined) {
|
|
230
|
-
throw new BridgeError(runtime.versionEvidenceFailure, "The local Claude provider requires bounded, internally consistent runtime version evidence.");
|
|
231
|
-
}
|
|
232
|
-
const majorEvidence = runtime.claudeCodeVersion === UNKNOWN_COMPATIBILITY_VERSION
|
|
233
|
-
? runtime.launcherVersionEvidence
|
|
234
|
-
: runtime.claudeCodeVersion;
|
|
235
|
-
if (majorEvidence === undefined ||
|
|
236
|
-
!sharesCompatibilityMajor(majorEvidence, CLAUDE_PEER_COMPATIBILITY.claudeCodeVersion)) {
|
|
237
|
-
throw new BridgeError(majorEvidence === undefined
|
|
238
|
-
? "CLAUDE_VERSION_UNPARSEABLE"
|
|
239
|
-
: "CLAUDE_PEER_VERSION_UNSUPPORTED", "The local Claude provider requires a positively observed supported runtime major.");
|
|
240
|
-
}
|
|
241
122
|
validateClaudeRuntimePathEvidence(runtime);
|
|
242
123
|
}
|
|
243
124
|
function validateClaudeRuntimePathEvidence(runtime) {
|
|
@@ -286,135 +167,17 @@ function isClaudeRegistryAvailabilityError(error) {
|
|
|
286
167
|
error.code === "EPERM" ||
|
|
287
168
|
error.code === "UNSAFE_PEER_DIRECTORY");
|
|
288
169
|
}
|
|
289
|
-
/**
|
|
290
|
-
* A bounded observation-only surface for an installed provider generation
|
|
291
|
-
* whose protocol cannot be used safely. It deliberately performs no provider
|
|
292
|
-
* discovery, listener construction, route selection, or message write.
|
|
293
|
-
*/
|
|
294
|
-
export class IncompatibleGatewayProvider {
|
|
295
|
-
identity;
|
|
296
|
-
protocol = "not-attested";
|
|
297
|
-
protocolVersion = "unknown";
|
|
298
|
-
version;
|
|
299
|
-
probes;
|
|
300
|
-
safeErrorCode;
|
|
301
|
-
initialized = false;
|
|
302
|
-
closed = false;
|
|
303
|
-
constructor(options) {
|
|
304
|
-
const attestation = evaluateCompatibilityAttestation({
|
|
305
|
-
surface: options.identity.provider,
|
|
306
|
-
version: options.version,
|
|
307
|
-
checkedAt: "2000-01-01T00:00:00.000Z",
|
|
308
|
-
certifiedVersions: certifiedCompatibilityVersions[options.identity.provider],
|
|
309
|
-
probes: options.probes,
|
|
310
|
-
});
|
|
311
|
-
if (attestation.tier !== "incompatible" ||
|
|
312
|
-
attestation.safeErrorCode !== options.safeErrorCode) {
|
|
313
|
-
throw new BridgeError("INCOMPATIBLE_PROVIDER_EVIDENCE_INVALID", "A disabled provider requires exact bounded incompatibility evidence.");
|
|
314
|
-
}
|
|
315
|
-
exactLocalHost(options.identity.hostId);
|
|
316
|
-
this.identity = Object.freeze({ ...options.identity });
|
|
317
|
-
this.version = options.version;
|
|
318
|
-
this.probes = Object.freeze(options.probes.map((probe) => Object.freeze({ ...probe })));
|
|
319
|
-
this.safeErrorCode = options.safeErrorCode;
|
|
320
|
-
}
|
|
321
|
-
compatibilitySurface() {
|
|
322
|
-
return { surface: this.identity.provider, version: this.version };
|
|
323
|
-
}
|
|
324
|
-
async runCompatibilityProbes() {
|
|
325
|
-
return this.probes;
|
|
326
|
-
}
|
|
327
|
-
acceptCompatibilityAttestation(attestation) {
|
|
328
|
-
if (!isCompatibilityAttestation(attestation) ||
|
|
329
|
-
attestation.surface !== this.identity.provider ||
|
|
330
|
-
attestation.version !== this.version ||
|
|
331
|
-
attestation.tier !== "incompatible" ||
|
|
332
|
-
attestation.safeErrorCode !== this.safeErrorCode ||
|
|
333
|
-
attestation.probes.length !== this.probes.length ||
|
|
334
|
-
attestation.probes.some((probe, index) => probe.name !== this.probes[index]?.name ||
|
|
335
|
-
probe.outcome !== this.probes[index]?.outcome ||
|
|
336
|
-
probe.safeErrorCode !== this.probes[index]?.safeErrorCode)) {
|
|
337
|
-
throw new BridgeError("INCOMPATIBLE_PROVIDER_ATTESTATION_MISMATCH", "The compatibility attestation does not match this disabled provider surface.");
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
async initialize(_callbacks) {
|
|
341
|
-
if (this.closed || this.initialized) {
|
|
342
|
-
throw new BridgeError("INCOMPATIBLE_PROVIDER_UNAVAILABLE", "The disabled provider surface cannot be initialized again.");
|
|
343
|
-
}
|
|
344
|
-
this.initialized = true;
|
|
345
|
-
return {
|
|
346
|
-
health: "degraded",
|
|
347
|
-
compatibility: "incompatible",
|
|
348
|
-
safeErrorCode: this.safeErrorCode,
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
async discoverClaudePeers() {
|
|
352
|
-
throw this.unavailable();
|
|
353
|
-
}
|
|
354
|
-
async selectRoute(_input) {
|
|
355
|
-
throw this.unavailable();
|
|
356
|
-
}
|
|
357
|
-
async assertWorkspaceDisjoint(_routeHandle, _stateRoot) {
|
|
358
|
-
throw this.unavailable();
|
|
359
|
-
}
|
|
360
|
-
async resolveReplyAddress(_address) {
|
|
361
|
-
throw this.unavailable();
|
|
362
|
-
}
|
|
363
|
-
async advertiseNativeCodexPeer(_input) {
|
|
364
|
-
throw this.unavailable();
|
|
365
|
-
}
|
|
366
|
-
async dispatch(_input) {
|
|
367
|
-
throw this.unavailable();
|
|
368
|
-
}
|
|
369
|
-
async releaseRoute(_routeHandle) { }
|
|
370
|
-
async close() {
|
|
371
|
-
this.closed = true;
|
|
372
|
-
}
|
|
373
|
-
unavailable() {
|
|
374
|
-
return new BridgeError(this.safeErrorCode, "This provider surface is observation-only because its compatibility boundary did not pass.");
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
export function createIncompatibleClaudeGatewayProvider(options) {
|
|
378
|
-
validateClaudeRuntimePathEvidence(options.runtime);
|
|
379
|
-
const [launcher, version, ...unobserved] = compatibilityProbeNames.claude;
|
|
380
|
-
return new IncompatibleGatewayProvider({
|
|
381
|
-
identity: {
|
|
382
|
-
provider: "claude",
|
|
383
|
-
hostId: LOCAL_HOST,
|
|
384
|
-
endpointGeneration: STABLE_CLAUDE_ENDPOINT_GENERATION,
|
|
385
|
-
},
|
|
386
|
-
version: options.version,
|
|
387
|
-
probes: [
|
|
388
|
-
passedProbe(launcher),
|
|
389
|
-
failedProbe(version, options.safeErrorCode),
|
|
390
|
-
...unobserved.map((name) => failedProbe(name, options.safeErrorCode)),
|
|
391
|
-
],
|
|
392
|
-
safeErrorCode: options.safeErrorCode,
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
export function createIncompatibleCodexGatewayProvider(options) {
|
|
396
|
-
const [installation, ...unobserved] = compatibilityProbeNames.codex;
|
|
397
|
-
return new IncompatibleGatewayProvider({
|
|
398
|
-
identity: options.identity,
|
|
399
|
-
version: options.version,
|
|
400
|
-
probes: [
|
|
401
|
-
passedProbe(installation),
|
|
402
|
-
...unobserved.map((name) => failedProbe(name, options.safeErrorCode)),
|
|
403
|
-
],
|
|
404
|
-
safeErrorCode: options.safeErrorCode,
|
|
405
|
-
});
|
|
406
|
-
}
|
|
407
170
|
export class LocalClaudeGatewayProvider {
|
|
408
171
|
identity;
|
|
409
172
|
protocol = "claude-peer";
|
|
410
173
|
protocolVersion = `${CLAUDE_PEER_COMPATIBILITY.peerProtocol}`;
|
|
411
174
|
peer;
|
|
412
|
-
runtimeVersion;
|
|
413
175
|
maxPending;
|
|
414
176
|
discoveryPollMs;
|
|
415
177
|
now;
|
|
416
178
|
selectedStateRoots = new Map();
|
|
417
179
|
nativeHelpers;
|
|
180
|
+
nativeHelperSourceProvider;
|
|
418
181
|
discovered = new Map();
|
|
419
182
|
selected = new Map();
|
|
420
183
|
/** Exact live same-UID sessions observed through native inbound frames. */
|
|
@@ -448,25 +211,12 @@ export class LocalClaudeGatewayProvider {
|
|
|
448
211
|
retiredNativeCodexListener;
|
|
449
212
|
/** Fences discovery callbacks and monitor restarts across listener rotation. */
|
|
450
213
|
nativeCodexSuccessionFreeze;
|
|
451
|
-
/**
|
|
452
|
-
|
|
453
|
-
compatibilityFailureCode;
|
|
214
|
+
/** External registry trust/availability failures degrade Claude only. */
|
|
215
|
+
unavailableCode;
|
|
454
216
|
initialized = false;
|
|
455
217
|
closed = false;
|
|
456
218
|
constructor(options) {
|
|
457
219
|
validateAttestedClaudeRuntime(options.runtime);
|
|
458
|
-
const compatibilityVersion = options.compatibilityVersion ??
|
|
459
|
-
(options.runtime.claudeCodeVersion === UNKNOWN_COMPATIBILITY_VERSION
|
|
460
|
-
? options.runtime.launcherVersionEvidence
|
|
461
|
-
: options.runtime.claudeCodeVersion);
|
|
462
|
-
if (compatibilityVersion === undefined ||
|
|
463
|
-
!isCompatibilityVersion(compatibilityVersion) ||
|
|
464
|
-
(compatibilityVersion !== options.runtime.claudeCodeVersion &&
|
|
465
|
-
!(options.runtime.claudeCodeVersion ===
|
|
466
|
-
UNKNOWN_COMPATIBILITY_VERSION &&
|
|
467
|
-
options.runtime.launcherVersionEvidence === compatibilityVersion))) {
|
|
468
|
-
throw new BridgeError("CLAUDE_RUNTIME_ATTESTATION_INVALID", "Claude compatibility classification requires exact bounded launcher evidence.");
|
|
469
|
-
}
|
|
470
220
|
if (options.locale !== undefined && !isDashboardLocale(options.locale)) {
|
|
471
221
|
throw new BridgeError("DASHBOARD_LOCALE_UNSUPPORTED", "The Claude provider notice locale is unsupported.");
|
|
472
222
|
}
|
|
@@ -476,15 +226,12 @@ export class LocalClaudeGatewayProvider {
|
|
|
476
226
|
hostId,
|
|
477
227
|
endpointGeneration: STABLE_CLAUDE_ENDPOINT_GENERATION,
|
|
478
228
|
};
|
|
479
|
-
this.runtimeVersion = compatibilityVersion;
|
|
480
229
|
this.maxPending = positiveBounded(options.maxPendingMessages, MAX_CLAUDE_PENDING, 4_096);
|
|
481
230
|
this.discoveryPollMs = positiveBounded(options.discoveryPollMs, DEFAULT_CLAUDE_DISCOVERY_POLL_MS, 30_000);
|
|
482
231
|
this.now = options.now ?? Date.now;
|
|
483
232
|
const protocolRuntime = {
|
|
484
233
|
claudeExecutable: options.runtime.claudeExecutable,
|
|
485
|
-
claudeCodeVersion: options.runtime.claudeCodeVersion
|
|
486
|
-
? options.runtime.launcherVersionEvidence
|
|
487
|
-
: options.runtime.claudeCodeVersion,
|
|
234
|
+
claudeCodeVersion: options.runtime.claudeCodeVersion,
|
|
488
235
|
sessionsDir: options.runtime.sessionsDir,
|
|
489
236
|
socketDir: options.runtime.socketDir,
|
|
490
237
|
};
|
|
@@ -506,60 +253,19 @@ export class LocalClaudeGatewayProvider {
|
|
|
506
253
|
deliveryNotices: options.deliveryNotices ?? "merged",
|
|
507
254
|
maxPendingMessages: this.maxPending,
|
|
508
255
|
maxHelpers: positiveBounded(options.nativeHelpers.maxHelpers, 256, 128),
|
|
509
|
-
callbacks: () => this.
|
|
256
|
+
callbacks: () => this.callbacks,
|
|
510
257
|
...(options.nativeHelpers.factory === undefined
|
|
511
258
|
? {}
|
|
512
259
|
: { factory: options.nativeHelpers.factory }),
|
|
513
260
|
});
|
|
514
|
-
|
|
515
|
-
compatibilitySurface() {
|
|
516
|
-
return { surface: "claude", version: this.runtimeVersion };
|
|
517
|
-
}
|
|
518
|
-
async runCompatibilityProbes() {
|
|
519
|
-
const [launcher, version, registry, socket, protocol] = compatibilityProbeNames.claude;
|
|
520
|
-
try {
|
|
521
|
-
const discovery = await this.peer.discover();
|
|
522
|
-
this.registryObservation = claudeRegistryObservation(discovery);
|
|
523
|
-
return [
|
|
524
|
-
passedProbe(launcher),
|
|
525
|
-
passedProbe(version),
|
|
526
|
-
passedProbe(registry),
|
|
527
|
-
passedProbe(socket),
|
|
528
|
-
passedProbe(protocol),
|
|
529
|
-
];
|
|
530
|
-
}
|
|
531
|
-
catch (error) {
|
|
532
|
-
if (!isClaudeRegistryAvailabilityError(error))
|
|
533
|
-
throw error;
|
|
534
|
-
this.registryObservation = unavailableClaudeRegistryObservation();
|
|
535
|
-
// A missing or unreadable registry is provider-local incompatibility:
|
|
536
|
-
// keep the broker and the other surface alive, but fence this provider
|
|
537
|
-
// before listener construction can turn the same missing path into a
|
|
538
|
-
// broker-wide startup failure.
|
|
539
|
-
return [
|
|
540
|
-
passedProbe(launcher),
|
|
541
|
-
passedProbe(version),
|
|
542
|
-
failedProbe(registry, "CLAUDE_REGISTRY_UNAVAILABLE"),
|
|
543
|
-
failedProbe(socket, "CLAUDE_REGISTRY_UNAVAILABLE"),
|
|
544
|
-
passedProbe(protocol),
|
|
545
|
-
];
|
|
546
|
-
}
|
|
261
|
+
this.nativeHelperSourceProvider = options.nativeHelperSourceProvider;
|
|
547
262
|
}
|
|
548
263
|
latestRegistryObservation() {
|
|
549
264
|
return this.registryObservation;
|
|
550
265
|
}
|
|
551
|
-
|
|
552
|
-
if (
|
|
553
|
-
|
|
554
|
-
attestation.version !== this.runtimeVersion) {
|
|
555
|
-
throw new BridgeError("CLAUDE_COMPATIBILITY_ATTESTATION_MISMATCH", "The Claude compatibility attestation does not match this runtime.");
|
|
556
|
-
}
|
|
557
|
-
this.compatibilityBlocked = attestation.tier === "incompatible";
|
|
558
|
-
this.compatibilityFailureCode = attestation.safeErrorCode;
|
|
559
|
-
if (this.compatibilityBlocked) {
|
|
560
|
-
if (this.monitorTimer !== undefined)
|
|
561
|
-
clearTimeout(this.monitorTimer);
|
|
562
|
-
this.monitorTimer = undefined;
|
|
266
|
+
activateEndpointGeneration(endpointGeneration) {
|
|
267
|
+
if (endpointGeneration !== this.identity.endpointGeneration) {
|
|
268
|
+
throw new BridgeError("CLAUDE_ENDPOINT_ACTIVATION_MISMATCH", "Only the exact current Claude endpoint generation can be activated.");
|
|
563
269
|
}
|
|
564
270
|
}
|
|
565
271
|
async initialize(callbacks) {
|
|
@@ -570,17 +276,9 @@ export class LocalClaudeGatewayProvider {
|
|
|
570
276
|
throw new BridgeError("CLAUDE_PROVIDER_ALREADY_INITIALIZED", "The local Claude provider can be initialized only once.");
|
|
571
277
|
}
|
|
572
278
|
this.callbacks = callbacks;
|
|
573
|
-
if (this.compatibilityBlocked) {
|
|
574
|
-
this.initialized = true;
|
|
575
|
-
return {
|
|
576
|
-
health: "degraded",
|
|
577
|
-
compatibility: "incompatible",
|
|
578
|
-
safeErrorCode: this.compatibilityFailureCode ?? "CLAUDE_COMPATIBILITY_CHECK_FAILED",
|
|
579
|
-
};
|
|
580
|
-
}
|
|
581
279
|
if (this.nativeHelpers !== undefined) {
|
|
582
280
|
this.initialized = true;
|
|
583
|
-
return { health: "healthy"
|
|
281
|
+
return { health: "healthy" };
|
|
584
282
|
}
|
|
585
283
|
try {
|
|
586
284
|
let listenerGeneration;
|
|
@@ -615,18 +313,16 @@ export class LocalClaudeGatewayProvider {
|
|
|
615
313
|
}
|
|
616
314
|
this.activeNativeCodexListener = listenerGeneration;
|
|
617
315
|
this.initialized = true;
|
|
618
|
-
return { health: "healthy"
|
|
316
|
+
return { health: "healthy" };
|
|
619
317
|
}
|
|
620
318
|
catch (error) {
|
|
621
319
|
if (error instanceof BridgeError &&
|
|
622
320
|
error.code === "UNSAFE_PEER_DIRECTORY") {
|
|
623
|
-
this.
|
|
624
|
-
this.compatibilityFailureCode = "CLAUDE_REGISTRY_UNAVAILABLE";
|
|
321
|
+
this.unavailableCode = "CLAUDE_REGISTRY_UNAVAILABLE";
|
|
625
322
|
this.registryObservation = unavailableClaudeRegistryObservation();
|
|
626
323
|
this.initialized = true;
|
|
627
324
|
return {
|
|
628
325
|
health: "degraded",
|
|
629
|
-
compatibility: "incompatible",
|
|
630
326
|
safeErrorCode: "CLAUDE_REGISTRY_UNAVAILABLE",
|
|
631
327
|
};
|
|
632
328
|
}
|
|
@@ -671,12 +367,16 @@ export class LocalClaudeGatewayProvider {
|
|
|
671
367
|
}
|
|
672
368
|
return { routeHandle: resolved.targetId };
|
|
673
369
|
}
|
|
674
|
-
async
|
|
370
|
+
async advertiseNativeSourcePeer(input) {
|
|
675
371
|
if (this.nativeHelpers !== undefined) {
|
|
676
372
|
this.assertReady();
|
|
677
373
|
await this.nativeHelpers.advertise(input);
|
|
678
374
|
return;
|
|
679
375
|
}
|
|
376
|
+
if (input.sourceProvider !== "codex" &&
|
|
377
|
+
input.sourceProvider !== this.nativeHelperSourceProvider) {
|
|
378
|
+
throw new BridgeError("CLAUDE_NATIVE_HELPER_UNAVAILABLE", "A non-Codex source requires a supervised native Claude helper.", true);
|
|
379
|
+
}
|
|
680
380
|
const registration = this.nativeCodexRegistration(input);
|
|
681
381
|
await this.serializeNativeCodexRegistration(async () => {
|
|
682
382
|
this.assertReady();
|
|
@@ -763,7 +463,7 @@ export class LocalClaudeGatewayProvider {
|
|
|
763
463
|
this.retiredNativeCodexListener !== undefined) {
|
|
764
464
|
throw new BridgeError("CODEX_PEER_SUCCESSION_CAPACITY", "Only one distinct prepared or retired Codex generation is allowed.");
|
|
765
465
|
}
|
|
766
|
-
const registration = this.nativeCodexRegistration(input);
|
|
466
|
+
const registration = this.nativeCodexRegistration({ ...input, sourceProvider: "codex" });
|
|
767
467
|
this.nativeCodexPreparationInFlight = input.generation;
|
|
768
468
|
let prepared;
|
|
769
469
|
try {
|
|
@@ -1027,7 +727,7 @@ export class LocalClaudeGatewayProvider {
|
|
|
1027
727
|
}
|
|
1028
728
|
return purged;
|
|
1029
729
|
}
|
|
1030
|
-
async
|
|
730
|
+
async unadvertiseNativeSourcePeer(alias) {
|
|
1031
731
|
if (this.nativeHelpers !== undefined) {
|
|
1032
732
|
await this.nativeHelpers.unadvertise(alias);
|
|
1033
733
|
return;
|
|
@@ -1043,7 +743,7 @@ export class LocalClaudeGatewayProvider {
|
|
|
1043
743
|
active.provisionalIngressForwarded = false;
|
|
1044
744
|
});
|
|
1045
745
|
}
|
|
1046
|
-
async
|
|
746
|
+
async updateNativeSourcePeerStatus(alias, status) {
|
|
1047
747
|
if (this.nativeHelpers !== undefined) {
|
|
1048
748
|
await this.nativeHelpers.updateStatus(alias, status);
|
|
1049
749
|
return;
|
|
@@ -1105,10 +805,10 @@ export class LocalClaudeGatewayProvider {
|
|
|
1105
805
|
active.inboundQuiesced = true;
|
|
1106
806
|
}
|
|
1107
807
|
async dispatch(input) {
|
|
1108
|
-
if (this.
|
|
808
|
+
if (this.unavailableCode !== undefined) {
|
|
1109
809
|
return {
|
|
1110
810
|
state: "failed",
|
|
1111
|
-
safeErrorCode: this.
|
|
811
|
+
safeErrorCode: this.unavailableCode,
|
|
1112
812
|
};
|
|
1113
813
|
}
|
|
1114
814
|
if (this.nativeHelpers !== undefined) {
|
|
@@ -1182,7 +882,8 @@ export class LocalClaudeGatewayProvider {
|
|
|
1182
882
|
return { state: "failed", safeErrorCode: "CLAUDE_ROUTE_UNAVAILABLE" };
|
|
1183
883
|
}
|
|
1184
884
|
}
|
|
1185
|
-
if (activeListener.registration?.alias !== input.sourceAlias
|
|
885
|
+
if (activeListener.registration?.alias !== input.sourceAlias ||
|
|
886
|
+
activeListener.registration.sourceProvider !== input.sourceProvider) {
|
|
1186
887
|
return { state: "failed", safeErrorCode: "CLAUDE_ROUTE_UNAVAILABLE" };
|
|
1187
888
|
}
|
|
1188
889
|
if (this.activeNativeCodexListener !== activeListener ||
|
|
@@ -1201,7 +902,8 @@ export class LocalClaudeGatewayProvider {
|
|
|
1201
902
|
let content;
|
|
1202
903
|
try {
|
|
1203
904
|
content = composeProvenanceEnvelope({
|
|
1204
|
-
|
|
905
|
+
sourceProvider: input.sourceProvider,
|
|
906
|
+
recipientProvider: this.identity.provider,
|
|
1205
907
|
sourceAlias: input.sourceAlias,
|
|
1206
908
|
targetAlias: input.targetAlias,
|
|
1207
909
|
conversationId: input.conversationId,
|
|
@@ -1392,7 +1094,7 @@ export class LocalClaudeGatewayProvider {
|
|
|
1392
1094
|
}
|
|
1393
1095
|
}
|
|
1394
1096
|
assertReady() {
|
|
1395
|
-
if (!this.initialized || this.closed || this.
|
|
1097
|
+
if (!this.initialized || this.closed || this.unavailableCode !== undefined) {
|
|
1396
1098
|
throw new BridgeError("CLAUDE_PROVIDER_UNAVAILABLE", "The local Claude provider is not available.", true);
|
|
1397
1099
|
}
|
|
1398
1100
|
}
|
|
@@ -1407,13 +1109,14 @@ export class LocalClaudeGatewayProvider {
|
|
|
1407
1109
|
throw new BridgeError("INVALID_CODEX_PEER_ALIAS", "The native Codex peer alias must target this host.");
|
|
1408
1110
|
}
|
|
1409
1111
|
const name = input.alias.slice(0, -suffix.length);
|
|
1410
|
-
|
|
1411
|
-
|
|
1112
|
+
const prefix = gatewayRegistrationIngressPrefixes[input.sourceProvider];
|
|
1113
|
+
if (prefix === undefined || !name.startsWith(prefix) || !NATIVE_CLAUDE_NAME.test(name)) {
|
|
1114
|
+
throw new BridgeError("INVALID_CODEX_PEER_ALIAS", "The native source peer alias must use its provider prefix.");
|
|
1412
1115
|
}
|
|
1413
1116
|
if (!path.isAbsolute(input.cwd) || input.cwd.includes("\0")) {
|
|
1414
1117
|
throw new BridgeError("INVALID_CODEX_PEER_CWD", "A native Codex peer requires an absolute working directory.");
|
|
1415
1118
|
}
|
|
1416
|
-
return { alias: input.alias, cwd: input.cwd, name };
|
|
1119
|
+
return { alias: input.alias, sourceProvider: input.sourceProvider, cwd: input.cwd, name };
|
|
1417
1120
|
}
|
|
1418
1121
|
requireActiveNativeCodexListener() {
|
|
1419
1122
|
this.assertReady();
|
|
@@ -1451,7 +1154,7 @@ export class LocalClaudeGatewayProvider {
|
|
|
1451
1154
|
await this.rejectNativeInboundReceipt(listenerGeneration, message.receiptHandle, diagnosticCode);
|
|
1452
1155
|
}
|
|
1453
1156
|
};
|
|
1454
|
-
if (this.
|
|
1157
|
+
if (this.unavailableCode !== undefined ||
|
|
1455
1158
|
this.closed ||
|
|
1456
1159
|
listenerGeneration.listener.closed ||
|
|
1457
1160
|
!this.ownsNativeCodexListener(listenerGeneration)) {
|
|
@@ -1801,7 +1504,6 @@ export class LocalClaudeGatewayProvider {
|
|
|
1801
1504
|
routeHandle: peer.targetId,
|
|
1802
1505
|
kind: "interactive",
|
|
1803
1506
|
state: claudeRouteState(peer),
|
|
1804
|
-
compatibility: "compatible",
|
|
1805
1507
|
};
|
|
1806
1508
|
this.discovered.set(peer.targetId, row);
|
|
1807
1509
|
rows.push(row);
|
|
@@ -1891,65 +1593,15 @@ export class LocalClaudeGatewayProvider {
|
|
|
1891
1593
|
export function createLocalClaudeGatewayProvider(options) {
|
|
1892
1594
|
return new LocalClaudeGatewayProvider(options);
|
|
1893
1595
|
}
|
|
1894
|
-
function
|
|
1895
|
-
if (version === UNKNOWN_COMPATIBILITY_VERSION) {
|
|
1896
|
-
return "CODEX_APP_SERVER_VERSION_UNPARSEABLE";
|
|
1897
|
-
}
|
|
1898
|
-
if (!isCompatibilityVersion(version)) {
|
|
1899
|
-
throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "The local Codex factory version evidence is malformed.");
|
|
1900
|
-
}
|
|
1901
|
-
return CODEX_APP_SERVER_WRITABLE_VERSIONS.some((certifiedVersion) => sharesCompatibilityMajor(certifiedVersion, version))
|
|
1902
|
-
? undefined
|
|
1903
|
-
: "CODEX_APP_SERVER_VERSION_UNSUPPORTED";
|
|
1904
|
-
}
|
|
1905
|
-
function validateCodexFactory(factory, options = {}) {
|
|
1906
|
-
const schema = factory.schemaCompatibility;
|
|
1907
|
-
const write = factory.writeCompatibility;
|
|
1908
|
-
const versionFailure = codexVersionFailureCode(factory.appServerVersion);
|
|
1909
|
-
const certified = CODEX_APP_SERVER_WRITABLE_VERSIONS.includes(factory.appServerVersion);
|
|
1910
|
-
const schemaCandidate = schema.observedSchemaCandidate === true &&
|
|
1911
|
-
CODEX_APP_SERVER_WRITABLE_VERSIONS.some((version) => sharesCompatibilityMajor(version, factory.appServerVersion));
|
|
1912
|
-
const unsupportedVersionInvalid = versionFailure !== undefined &&
|
|
1913
|
-
(options.allowUnsupportedVersion !== true ||
|
|
1914
|
-
write !== null ||
|
|
1915
|
-
factory.writableReady);
|
|
1916
|
-
const supportedSchemaInvalid = versionFailure === undefined &&
|
|
1917
|
-
((!certified &&
|
|
1918
|
-
(!schemaCandidate || write !== null || factory.writableReady)) ||
|
|
1919
|
-
schema.protocol !== "app-server-v2-stable" ||
|
|
1920
|
-
schema.steering?.method !== "turn/steer" ||
|
|
1921
|
-
schema.steering.requestSchema !== "expected-turn-id-text-v1" ||
|
|
1922
|
-
schema.steering.deliveryBoundary !== "next-tool-call-boundary" ||
|
|
1923
|
-
(write !== null &&
|
|
1924
|
-
(write.appServerVersion !== schema.appServerVersion ||
|
|
1925
|
-
write.endpointGeneration !== schema.endpointGeneration ||
|
|
1926
|
-
write.protocol !== schema.protocol ||
|
|
1927
|
-
write.observedSchemaCandidate !== schema.observedSchemaCandidate ||
|
|
1928
|
-
write.steering?.method !== schema.steering.method ||
|
|
1929
|
-
write.steering.requestSchema !== schema.steering.requestSchema ||
|
|
1930
|
-
write.steering.deliveryBoundary !==
|
|
1931
|
-
schema.steering.deliveryBoundary)) ||
|
|
1932
|
-
factory.writableReady !== (write !== null));
|
|
1596
|
+
function validateCodexFactory(factory) {
|
|
1933
1597
|
if (factory.hostId !== LOCAL_HOST ||
|
|
1934
1598
|
factory.protocol !== "codex-app-server" ||
|
|
1935
1599
|
factory.protocolVersion !== factory.appServerVersion ||
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
supportedSchemaInvalid) {
|
|
1940
|
-
throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "The local Codex provider requires exact schema and write attestations.");
|
|
1600
|
+
factory.appServerVersion.length === 0 ||
|
|
1601
|
+
factory.endpointGeneration.length === 0) {
|
|
1602
|
+
throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "The local Codex provider requires exact managed endpoint identity.");
|
|
1941
1603
|
}
|
|
1942
1604
|
}
|
|
1943
|
-
function codexFactoryWritesEnabled(factory, attestation, writeProbePassed = false) {
|
|
1944
|
-
return ((attestation.tier === "certified" &&
|
|
1945
|
-
CODEX_APP_SERVER_WRITABLE_VERSIONS.includes(attestation.version) &&
|
|
1946
|
-
factory.writableReady &&
|
|
1947
|
-
factory.writeCompatibility !== null) ||
|
|
1948
|
-
(!factory.writableReady &&
|
|
1949
|
-
factory.writeCompatibility === null &&
|
|
1950
|
-
writeProbePassed &&
|
|
1951
|
-
compatibilityCoversWrites(attestation)));
|
|
1952
|
-
}
|
|
1953
1605
|
function codexRouteState(observation) {
|
|
1954
1606
|
if (observation.connection !== "ready")
|
|
1955
1607
|
return "stale";
|
|
@@ -1971,9 +1623,6 @@ function codexRouteSafeCode(observation) {
|
|
|
1971
1623
|
if (codexRouteState(observation) === "stale") {
|
|
1972
1624
|
return "CODEX_ROUTE_STALE";
|
|
1973
1625
|
}
|
|
1974
|
-
if (!observation.writableReady) {
|
|
1975
|
-
return "CODEX_WRITES_DISABLED";
|
|
1976
|
-
}
|
|
1977
1626
|
return undefined;
|
|
1978
1627
|
}
|
|
1979
1628
|
export class LocalCodexGatewayProvider {
|
|
@@ -2007,14 +1656,7 @@ export class LocalCodexGatewayProvider {
|
|
|
2007
1656
|
endpointActivationRetry;
|
|
2008
1657
|
endpointActivationRetryTimer;
|
|
2009
1658
|
callbackDrainFrozen = false;
|
|
2010
|
-
writeProbeObservationsByGeneration = new Map();
|
|
2011
|
-
writeProbeResults = new Map();
|
|
2012
|
-
writeProbeDecline;
|
|
2013
|
-
writeProbeOverflow;
|
|
2014
|
-
compatibilityAttested;
|
|
2015
|
-
compatibilityFailureCode;
|
|
2016
1659
|
endpointUnavailable = false;
|
|
2017
|
-
pendingEndpointAttestation;
|
|
2018
1660
|
pendingEndpointRefreshEvent;
|
|
2019
1661
|
pendingEndpointRefreshSelectorClaimed = false;
|
|
2020
1662
|
initialized = false;
|
|
@@ -2025,9 +1667,6 @@ export class LocalCodexGatewayProvider {
|
|
|
2025
1667
|
this.factory = options.factory;
|
|
2026
1668
|
this.refreshFactory = options.refreshFactory;
|
|
2027
1669
|
exactLocalHost(options.factory.hostId);
|
|
2028
|
-
this.compatibilityAttested =
|
|
2029
|
-
options.factory.writableReady &&
|
|
2030
|
-
options.factory.writeCompatibility !== null;
|
|
2031
1670
|
this.maxCallbacks = positiveBounded(options.maxCallbackEvents, MAX_CODEX_CALLBACKS, 4_096);
|
|
2032
1671
|
this.maxRoutes = positiveBounded(options.maxRoutes, MAX_CODEX_ROUTES, 256);
|
|
2033
1672
|
this.maxReplyBytes = positiveBounded(options.maxReplyBytes, MAX_TRANSIENT_REPLY_BYTES, 1024 * 1024);
|
|
@@ -2056,352 +1695,39 @@ export class LocalCodexGatewayProvider {
|
|
|
2056
1695
|
get protocolVersion() {
|
|
2057
1696
|
return this.factory.protocolVersion;
|
|
2058
1697
|
}
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
(attestation.checkedAt === pending.checkedAt &&
|
|
2066
|
-
attestation.tier === pending.tier &&
|
|
2067
|
-
attestation.safeErrorCode === pending.safeErrorCode &&
|
|
2068
|
-
attestation.probes.length === pending.probes.length &&
|
|
2069
|
-
attestation.probes.every((probe, index) => probe.name === pending.probes[index]?.name &&
|
|
2070
|
-
probe.outcome === pending.probes[index]?.outcome &&
|
|
2071
|
-
probe.safeErrorCode === pending.probes[index]?.safeErrorCode));
|
|
2072
|
-
if (!isCompatibilityAttestation(attestation) ||
|
|
2073
|
-
attestation.surface !== "codex" ||
|
|
2074
|
-
attestation.version !== this.factory.appServerVersion ||
|
|
2075
|
-
!pendingMatches) {
|
|
2076
|
-
throw new BridgeError("CODEX_COMPATIBILITY_ATTESTATION_MISMATCH", "The Codex compatibility attestation does not match this endpoint.");
|
|
2077
|
-
}
|
|
2078
|
-
if (attestation.tier === "incompatible") {
|
|
2079
|
-
this.pendingEndpointAttestation = undefined;
|
|
2080
|
-
this.pendingEndpointRefreshEvent = undefined;
|
|
2081
|
-
this.pendingEndpointRefreshSelectorClaimed = false;
|
|
2082
|
-
this.clearEndpointActivationRetry();
|
|
2083
|
-
this.compatibilityAttested = false;
|
|
2084
|
-
this.endpointUnavailable = true;
|
|
2085
|
-
this.compatibilityFailureCode =
|
|
2086
|
-
attestation.safeErrorCode ?? "CODEX_COMPATIBILITY_CHECK_FAILED";
|
|
2087
|
-
return;
|
|
2088
|
-
}
|
|
2089
|
-
const writesEnabled = codexFactoryWritesEnabled(this.factory, attestation, this.latestWriteCompatibilityProbeObservation(this.factory.endpointGeneration)?.outcome === "pass");
|
|
2090
|
-
const schemaObserved = attestation.tier === "schema_attested" &&
|
|
2091
|
-
!this.factory.writableReady &&
|
|
2092
|
-
this.factory.writeCompatibility === null;
|
|
2093
|
-
if ((!writesEnabled && !schemaObserved) ||
|
|
2094
|
-
(this.endpointUnavailable && pending === undefined) ||
|
|
2095
|
-
!pendingMatches) {
|
|
2096
|
-
throw new BridgeError("CODEX_COMPATIBILITY_ATTESTATION_MISMATCH", "The Codex compatibility attestation does not match this endpoint.");
|
|
1698
|
+
activateEndpointGeneration(endpointGeneration) {
|
|
1699
|
+
const event = this.pendingEndpointRefreshEvent;
|
|
1700
|
+
if (event === undefined ||
|
|
1701
|
+
event.current.endpointGeneration !== endpointGeneration ||
|
|
1702
|
+
this.factory.endpointGeneration !== endpointGeneration) {
|
|
1703
|
+
throw new BridgeError("CODEX_ENDPOINT_ACTIVATION_MISMATCH", "Only the exact pending managed Codex generation can be activated.");
|
|
2097
1704
|
}
|
|
2098
|
-
this.pendingEndpointAttestation = undefined;
|
|
2099
1705
|
this.pendingEndpointRefreshEvent = undefined;
|
|
2100
1706
|
this.pendingEndpointRefreshSelectorClaimed = false;
|
|
2101
1707
|
this.clearEndpointActivationRetry();
|
|
2102
|
-
this.
|
|
2103
|
-
this.endpointUnavailable = !writesEnabled;
|
|
2104
|
-
this.compatibilityFailureCode = undefined;
|
|
1708
|
+
this.endpointUnavailable = false;
|
|
2105
1709
|
}
|
|
2106
1710
|
releaseEndpointRefreshSelectorClaim(endpointGeneration) {
|
|
2107
1711
|
const event = this.pendingEndpointRefreshEvent;
|
|
2108
|
-
if (event?.current.endpointGeneration === endpointGeneration
|
|
2109
|
-
this.pendingEndpointAttestation !== undefined) {
|
|
1712
|
+
if (event?.current.endpointGeneration === endpointGeneration) {
|
|
2110
1713
|
this.pendingEndpointRefreshSelectorClaimed = false;
|
|
2111
1714
|
}
|
|
2112
1715
|
}
|
|
2113
1716
|
rearmEndpointRefreshActivation(endpointGeneration) {
|
|
2114
1717
|
const event = this.pendingEndpointRefreshEvent;
|
|
2115
1718
|
if (event?.current.endpointGeneration === endpointGeneration &&
|
|
2116
|
-
this.pendingEndpointAttestation !== undefined &&
|
|
2117
1719
|
!this.closing &&
|
|
2118
1720
|
!this.closed) {
|
|
2119
1721
|
this.publishEndpointRefresh(event);
|
|
2120
1722
|
}
|
|
2121
1723
|
}
|
|
2122
|
-
latestWriteCompatibilityProbeObservation(endpointGeneration) {
|
|
2123
|
-
return (this.writeProbeObservationsByGeneration.get(endpointGeneration) ??
|
|
2124
|
-
(this.writeProbeOverflow?.endpointGeneration === endpointGeneration
|
|
2125
|
-
? this.writeProbeOverflow.observation
|
|
2126
|
-
: undefined) ??
|
|
2127
|
-
(this.writeProbeDecline?.endpointGeneration === endpointGeneration
|
|
2128
|
-
? this.writeProbeDecline.observation
|
|
2129
|
-
: undefined));
|
|
2130
|
-
}
|
|
2131
|
-
async runCompatibilityProbes(context) {
|
|
2132
|
-
return await this.runCompatibilityProbesFor(this.factory, context === undefined
|
|
2133
|
-
? undefined
|
|
2134
|
-
: {
|
|
2135
|
-
stateRoot: path.resolve(context.stateRoot),
|
|
2136
|
-
forbiddenCodexThreadIds: [...context.forbiddenCodexThreadIds],
|
|
2137
|
-
});
|
|
2138
|
-
}
|
|
2139
|
-
async runCompatibilityProbesFor(factory, context) {
|
|
2140
|
-
const [installation, control, initialize, threadList] = compatibilityProbeNames.codex;
|
|
2141
|
-
let transport;
|
|
2142
|
-
let connector;
|
|
2143
|
-
let stage = "transport";
|
|
2144
|
-
try {
|
|
2145
|
-
transport = await factory.connectTransport();
|
|
2146
|
-
stage = "initialize";
|
|
2147
|
-
connector = await CodexAppServerConnector.connect({
|
|
2148
|
-
compatibility: factory.schemaCompatibility,
|
|
2149
|
-
...(context === undefined
|
|
2150
|
-
? {}
|
|
2151
|
-
: { writeCompatibilityProbe: true }),
|
|
2152
|
-
writesEnabled: false,
|
|
2153
|
-
route: {
|
|
2154
|
-
endpointGeneration: factory.endpointGeneration,
|
|
2155
|
-
threadId: COMPATIBILITY_PROBE_THREAD_ID,
|
|
2156
|
-
},
|
|
2157
|
-
transport,
|
|
2158
|
-
maxReplyBytes: this.maxReplyBytes,
|
|
2159
|
-
now: this.now,
|
|
2160
|
-
onEvent: () => undefined,
|
|
2161
|
-
onTurnResult: () => undefined,
|
|
2162
|
-
});
|
|
2163
|
-
stage = "thread_list";
|
|
2164
|
-
await connector.observeLoadedThread(connector.guard());
|
|
2165
|
-
const requiredProbes = [
|
|
2166
|
-
passedProbe(installation),
|
|
2167
|
-
passedProbe(control),
|
|
2168
|
-
passedProbe(initialize),
|
|
2169
|
-
passedProbe(threadList),
|
|
2170
|
-
];
|
|
2171
|
-
if (context === undefined)
|
|
2172
|
-
return requiredProbes;
|
|
2173
|
-
const result = await this.runCodexWriteProbe(factory, connector, context);
|
|
2174
|
-
return result.outcome === "pass"
|
|
2175
|
-
? [...requiredProbes, passedProbe("write_attestation")]
|
|
2176
|
-
: requiredProbes;
|
|
2177
|
-
}
|
|
2178
|
-
catch (error) {
|
|
2179
|
-
if (this.isEndpointGenerationChanged(error) ||
|
|
2180
|
-
(error instanceof BridgeError &&
|
|
2181
|
-
error.code === "CODEX_FACTORY_ATTESTATION_INVALID")) {
|
|
2182
|
-
throw error;
|
|
2183
|
-
}
|
|
2184
|
-
if (stage === "transport") {
|
|
2185
|
-
const availabilityFailure = error instanceof LocalCodexTransportError &&
|
|
2186
|
-
[
|
|
2187
|
-
"MANAGED_CODEX_UNAVAILABLE",
|
|
2188
|
-
"LOCAL_APP_SERVER_NOT_RUNNING",
|
|
2189
|
-
"SPAWN_FAILED",
|
|
2190
|
-
"SPAWN_TIMEOUT",
|
|
2191
|
-
"PROXY_STDERR_LIMIT",
|
|
2192
|
-
"TRANSPORT_CONNECT_FAILED",
|
|
2193
|
-
].includes(error.code);
|
|
2194
|
-
if (!availabilityFailure)
|
|
2195
|
-
throw error;
|
|
2196
|
-
const installationUnavailable = error instanceof LocalCodexTransportError &&
|
|
2197
|
-
error.code === "MANAGED_CODEX_UNAVAILABLE";
|
|
2198
|
-
return [
|
|
2199
|
-
installationUnavailable
|
|
2200
|
-
? failedProbe(installation, "CODEX_INSTALLATION_INVALID")
|
|
2201
|
-
: passedProbe(installation),
|
|
2202
|
-
failedProbe(control, installationUnavailable
|
|
2203
|
-
? "CODEX_COMPAT_PROBE_BLOCKED"
|
|
2204
|
-
: "CODEX_CONTROL_SOCKET_UNAVAILABLE"),
|
|
2205
|
-
failedProbe(initialize, "CODEX_COMPAT_PROBE_BLOCKED"),
|
|
2206
|
-
failedProbe(threadList, "CODEX_COMPAT_PROBE_BLOCKED"),
|
|
2207
|
-
];
|
|
2208
|
-
}
|
|
2209
|
-
return [
|
|
2210
|
-
passedProbe(installation),
|
|
2211
|
-
passedProbe(control),
|
|
2212
|
-
stage === "initialize"
|
|
2213
|
-
? failedProbe(initialize, "CODEX_INITIALIZE_SCHEMA_REJECTED")
|
|
2214
|
-
: passedProbe(initialize),
|
|
2215
|
-
failedProbe(threadList, "CODEX_THREAD_LIST_SCHEMA_REJECTED"),
|
|
2216
|
-
];
|
|
2217
|
-
}
|
|
2218
|
-
finally {
|
|
2219
|
-
if (connector !== undefined) {
|
|
2220
|
-
await connector.close();
|
|
2221
|
-
}
|
|
2222
|
-
else if (transport !== undefined) {
|
|
2223
|
-
await transport.close();
|
|
2224
|
-
}
|
|
2225
|
-
}
|
|
2226
|
-
}
|
|
2227
|
-
async runCodexWriteProbe(factory, connector, context) {
|
|
2228
|
-
const key = `${factory.appServerVersion}\0${factory.endpointGeneration}`;
|
|
2229
|
-
const cached = this.writeProbeResults.get(key);
|
|
2230
|
-
if (cached !== undefined)
|
|
2231
|
-
return await cached;
|
|
2232
|
-
if (this.writeProbeOverflow?.key === key) {
|
|
2233
|
-
if (this.writeProbeResults.size >= MAX_CODEX_WRITE_PROBE_ATTEMPTS) {
|
|
2234
|
-
return this.writeProbeOverflow.observation;
|
|
2235
|
-
}
|
|
2236
|
-
this.writeProbeOverflow = undefined;
|
|
2237
|
-
}
|
|
2238
|
-
if (this.writeProbeResults.size >= MAX_CODEX_WRITE_PROBE_ATTEMPTS) {
|
|
2239
|
-
const observation = Object.freeze(codexWriteProbeFailure("CODEX_WRITE_PROBE_CAPACITY_EXHAUSTED"));
|
|
2240
|
-
this.writeProbeOverflow = Object.freeze({
|
|
2241
|
-
endpointGeneration: factory.endpointGeneration,
|
|
2242
|
-
key,
|
|
2243
|
-
observation,
|
|
2244
|
-
});
|
|
2245
|
-
if (this.callbacks !== undefined) {
|
|
2246
|
-
invokeCallback(() => this.callbacks?.onProtocolNotice?.({
|
|
2247
|
-
code: observation.safeErrorCode,
|
|
2248
|
-
}));
|
|
2249
|
-
}
|
|
2250
|
-
return observation;
|
|
2251
|
-
}
|
|
2252
|
-
const pending = this.executeCodexWriteProbe(connector, context).then((result) => {
|
|
2253
|
-
const observation = Object.freeze({ ...result });
|
|
2254
|
-
if (observation.outcome === "fail" &&
|
|
2255
|
-
(observation.safeErrorCode ===
|
|
2256
|
-
"CODEX_WRITE_PROBE_MODEL_PIN_UNAVAILABLE" ||
|
|
2257
|
-
observation.safeErrorCode ===
|
|
2258
|
-
"CODEX_WRITE_PROBE_RATE_LIMIT_CONSTRAINED")) {
|
|
2259
|
-
this.writeProbeResults.delete(key);
|
|
2260
|
-
this.writeProbeDecline = Object.freeze({
|
|
2261
|
-
endpointGeneration: factory.endpointGeneration,
|
|
2262
|
-
observation,
|
|
2263
|
-
});
|
|
2264
|
-
}
|
|
2265
|
-
else {
|
|
2266
|
-
this.writeProbeObservationsByGeneration.set(factory.endpointGeneration, observation);
|
|
2267
|
-
}
|
|
2268
|
-
if (observation.outcome === "fail" && this.callbacks !== undefined) {
|
|
2269
|
-
invokeCallback(() => this.callbacks?.onProtocolNotice?.({
|
|
2270
|
-
code: observation.safeErrorCode,
|
|
2271
|
-
}));
|
|
2272
|
-
}
|
|
2273
|
-
return observation;
|
|
2274
|
-
});
|
|
2275
|
-
this.writeProbeResults.set(key, pending);
|
|
2276
|
-
return await pending;
|
|
2277
|
-
}
|
|
2278
|
-
async executeCodexWriteProbe(connector, context) {
|
|
2279
|
-
const stateRoot = path.resolve(context.stateRoot);
|
|
2280
|
-
const rootBefore = await attestCodexWriteProbeRoot(stateRoot);
|
|
2281
|
-
if (rootBefore === null) {
|
|
2282
|
-
return codexWriteProbeFailure("CODEX_WRITE_PROBE_THREAD_SETUP_FAILED");
|
|
2283
|
-
}
|
|
2284
|
-
const probeRoot = path.join(stateRoot, CODEX_WRITE_PROBE_ROOT);
|
|
2285
|
-
let probeRootBefore;
|
|
2286
|
-
try {
|
|
2287
|
-
let created = false;
|
|
2288
|
-
try {
|
|
2289
|
-
await mkdir(probeRoot, { mode: 0o700 });
|
|
2290
|
-
created = true;
|
|
2291
|
-
}
|
|
2292
|
-
catch (error) {
|
|
2293
|
-
if (systemErrorCode(error) !== "EEXIST")
|
|
2294
|
-
throw error;
|
|
2295
|
-
}
|
|
2296
|
-
if (created)
|
|
2297
|
-
await chmod(probeRoot, 0o700);
|
|
2298
|
-
const evidence = await attestCodexWriteProbeRoot(probeRoot);
|
|
2299
|
-
if (evidence === null) {
|
|
2300
|
-
return codexWriteProbeFailure("CODEX_WRITE_PROBE_THREAD_SETUP_FAILED");
|
|
2301
|
-
}
|
|
2302
|
-
probeRootBefore = evidence;
|
|
2303
|
-
}
|
|
2304
|
-
catch (error) {
|
|
2305
|
-
if (error instanceof BridgeError &&
|
|
2306
|
-
error.code === "CODEX_FACTORY_ATTESTATION_INVALID") {
|
|
2307
|
-
throw error;
|
|
2308
|
-
}
|
|
2309
|
-
if (transientCodexWriteProbeError(error)) {
|
|
2310
|
-
return codexWriteProbeFailure("CODEX_WRITE_PROBE_THREAD_SETUP_FAILED");
|
|
2311
|
-
}
|
|
2312
|
-
throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "The controller-owned Codex probe root could not be established safely.");
|
|
2313
|
-
}
|
|
2314
|
-
let cwd;
|
|
2315
|
-
let before;
|
|
2316
|
-
let result = codexWriteProbeFailure("CODEX_WRITE_PROBE_THREAD_SETUP_FAILED");
|
|
2317
|
-
try {
|
|
2318
|
-
cwd = await mkdtemp(path.join(probeRoot, CODEX_WRITE_PROBE_DIRECTORY_PREFIX));
|
|
2319
|
-
if (path.dirname(cwd) !== probeRoot) {
|
|
2320
|
-
throw new Error("probe directory escaped its dedicated root");
|
|
2321
|
-
}
|
|
2322
|
-
await chmod(cwd, 0o700);
|
|
2323
|
-
before = await attestCodexWriteProbeDirectory(cwd);
|
|
2324
|
-
result = await connector.runWriteCompatibilityProbe({
|
|
2325
|
-
cwd,
|
|
2326
|
-
forbiddenThreadIds: [
|
|
2327
|
-
...new Set([
|
|
2328
|
-
COMPATIBILITY_PROBE_THREAD_ID,
|
|
2329
|
-
...context.forbiddenCodexThreadIds,
|
|
2330
|
-
...this.trackedRoutes,
|
|
2331
|
-
]),
|
|
2332
|
-
],
|
|
2333
|
-
});
|
|
2334
|
-
}
|
|
2335
|
-
catch (error) {
|
|
2336
|
-
if (!safeCodexWriteProbeFilesystemFailure(error)) {
|
|
2337
|
-
if (error instanceof BridgeError)
|
|
2338
|
-
throw error;
|
|
2339
|
-
throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "The disposable Codex probe directory could not be established safely.");
|
|
2340
|
-
}
|
|
2341
|
-
result = codexWriteProbeFailure("CODEX_WRITE_PROBE_THREAD_SETUP_FAILED");
|
|
2342
|
-
}
|
|
2343
|
-
let unchanged = false;
|
|
2344
|
-
let removed = false;
|
|
2345
|
-
if (cwd !== undefined && before !== undefined) {
|
|
2346
|
-
try {
|
|
2347
|
-
const after = await attestCodexWriteProbeDirectory(cwd);
|
|
2348
|
-
unchanged = sameCodexWriteProbeDirectory(before, after);
|
|
2349
|
-
await rmdir(cwd);
|
|
2350
|
-
try {
|
|
2351
|
-
await lstat(cwd);
|
|
2352
|
-
}
|
|
2353
|
-
catch (error) {
|
|
2354
|
-
removed = systemErrorCode(error) === "ENOENT";
|
|
2355
|
-
}
|
|
2356
|
-
}
|
|
2357
|
-
catch (error) {
|
|
2358
|
-
if (!safeCodexWriteProbeFilesystemFailure(error)) {
|
|
2359
|
-
if (error instanceof BridgeError)
|
|
2360
|
-
throw error;
|
|
2361
|
-
throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "The disposable Codex probe directory could not be re-attested safely.");
|
|
2362
|
-
}
|
|
2363
|
-
// Never remove a path after its exact ownership evidence changed.
|
|
2364
|
-
}
|
|
2365
|
-
}
|
|
2366
|
-
if (cwd !== undefined && !removed) {
|
|
2367
|
-
result = codexWriteProbeFailure("CODEX_WRITE_PROBE_CLEANUP_UNCONFIRMED", result);
|
|
2368
|
-
}
|
|
2369
|
-
else if (cwd !== undefined && !unchanged) {
|
|
2370
|
-
result = codexWriteProbeFailure("CODEX_WRITE_PROBE_TOOL_ACTIVITY_OBSERVED", result);
|
|
2371
|
-
}
|
|
2372
|
-
const [probeRootAfter, rootAfter] = await Promise.all([
|
|
2373
|
-
attestCodexWriteProbeRoot(probeRoot),
|
|
2374
|
-
attestCodexWriteProbeRoot(stateRoot),
|
|
2375
|
-
]);
|
|
2376
|
-
if (probeRootAfter === null || rootAfter === null) {
|
|
2377
|
-
return codexWriteProbeFailure("CODEX_WRITE_PROBE_THREAD_SETUP_FAILED", result);
|
|
2378
|
-
}
|
|
2379
|
-
if (!sameCodexWriteProbeRoot(probeRootBefore, probeRootAfter) ||
|
|
2380
|
-
!sameCodexWriteProbeRoot(rootBefore, rootAfter)) {
|
|
2381
|
-
throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "A controller-owned Codex probe root changed while the disposable probe ran.");
|
|
2382
|
-
}
|
|
2383
|
-
return result;
|
|
2384
|
-
}
|
|
2385
1724
|
async initialize(callbacks) {
|
|
2386
1725
|
if (this.closed || this.initialized) {
|
|
2387
1726
|
throw new BridgeError("CODEX_PROVIDER_INITIALIZATION_REJECTED", "The local Codex provider cannot be initialized in this state.");
|
|
2388
1727
|
}
|
|
2389
1728
|
this.callbacks = callbacks;
|
|
2390
1729
|
this.initialized = true;
|
|
2391
|
-
|
|
2392
|
-
return {
|
|
2393
|
-
health: "degraded",
|
|
2394
|
-
compatibility: "incompatible",
|
|
2395
|
-
safeErrorCode: this.compatibilityFailureCode,
|
|
2396
|
-
};
|
|
2397
|
-
}
|
|
2398
|
-
return !this.compatibilityAttested
|
|
2399
|
-
? {
|
|
2400
|
-
health: "degraded",
|
|
2401
|
-
compatibility: "compatible",
|
|
2402
|
-
safeErrorCode: "CODEX_MONITOR_ONLY",
|
|
2403
|
-
}
|
|
2404
|
-
: { health: "healthy", compatibility: "compatible" };
|
|
1730
|
+
return { health: "healthy" };
|
|
2405
1731
|
}
|
|
2406
1732
|
async selectRoute(input) {
|
|
2407
1733
|
if (!this.initialized || this.closing || this.closed) {
|
|
@@ -2423,9 +1749,8 @@ export class LocalCodexGatewayProvider {
|
|
|
2423
1749
|
let selectorRefreshReserved = false;
|
|
2424
1750
|
let route;
|
|
2425
1751
|
const stageRefreshedRoute = async (result) => {
|
|
2426
|
-
if (result === undefined
|
|
2427
|
-
|
|
2428
|
-
throw new BridgeError("CODEX_ROUTE_SETUP_REJECTED", "The exact Codex endpoint replacement was not compatibility-attested.");
|
|
1752
|
+
if (result === undefined) {
|
|
1753
|
+
throw new BridgeError("CODEX_ROUTE_SETUP_REJECTED", "The exact Codex endpoint replacement could not be established.");
|
|
2429
1754
|
}
|
|
2430
1755
|
refreshResult = result;
|
|
2431
1756
|
selectorRefreshReserved = this.reserveSelectorRefresh(result);
|
|
@@ -2448,7 +1773,7 @@ export class LocalCodexGatewayProvider {
|
|
|
2448
1773
|
route = await stageRefreshedRoute(retainedEndpointRefresh);
|
|
2449
1774
|
}
|
|
2450
1775
|
else if (this.endpointUnavailable &&
|
|
2451
|
-
this.
|
|
1776
|
+
this.pendingEndpointRefreshEvent === undefined) {
|
|
2452
1777
|
route = await stageRefreshedRoute(await this.refreshEndpoint("selector"));
|
|
2453
1778
|
}
|
|
2454
1779
|
else {
|
|
@@ -2566,7 +1891,6 @@ export class LocalCodexGatewayProvider {
|
|
|
2566
1891
|
this.closed ||
|
|
2567
1892
|
this.endpointUnavailable ||
|
|
2568
1893
|
this.endpointRefresh !== undefined ||
|
|
2569
|
-
!this.compatibilityAttested ||
|
|
2570
1894
|
input.authorization !== "selected_route" ||
|
|
2571
1895
|
!sameEndpoint(input.binding, this.identity)) {
|
|
2572
1896
|
return { state: "failed", safeErrorCode: "CODEX_ROUTE_UNAVAILABLE" };
|
|
@@ -2580,9 +1904,6 @@ export class LocalCodexGatewayProvider {
|
|
|
2580
1904
|
return { state: "failed", safeErrorCode: "CODEX_ROUTE_UNAVAILABLE" };
|
|
2581
1905
|
}
|
|
2582
1906
|
const guard = route.connector.guard();
|
|
2583
|
-
if (!guard.writableReady) {
|
|
2584
|
-
return { state: "failed", safeErrorCode: "CODEX_WRITES_DISABLED" };
|
|
2585
|
-
}
|
|
2586
1907
|
if (strictDeadline(input.deadlineAt, this.now().getTime()) === undefined) {
|
|
2587
1908
|
return { state: "failed", safeErrorCode: "MESSAGE_EXPIRED" };
|
|
2588
1909
|
}
|
|
@@ -2592,7 +1913,8 @@ export class LocalCodexGatewayProvider {
|
|
|
2592
1913
|
let content;
|
|
2593
1914
|
try {
|
|
2594
1915
|
content = composeProvenanceEnvelope({
|
|
2595
|
-
|
|
1916
|
+
sourceProvider: input.sourceProvider,
|
|
1917
|
+
recipientProvider: this.identity.provider,
|
|
2596
1918
|
sourceAlias: input.sourceAlias,
|
|
2597
1919
|
targetAlias: input.targetAlias,
|
|
2598
1920
|
conversationId: input.conversationId,
|
|
@@ -2702,7 +2024,6 @@ export class LocalCodexGatewayProvider {
|
|
|
2702
2024
|
this.clearEndpointActivationRetry();
|
|
2703
2025
|
this.pendingEndpointRefreshEvent = undefined;
|
|
2704
2026
|
this.pendingEndpointRefreshSelectorClaimed = false;
|
|
2705
|
-
this.pendingEndpointAttestation = undefined;
|
|
2706
2027
|
const refreshResult = this.endpointRefresh === undefined
|
|
2707
2028
|
? []
|
|
2708
2029
|
: await Promise.allSettled([this.endpointRefresh]);
|
|
@@ -2728,7 +2049,6 @@ export class LocalCodexGatewayProvider {
|
|
|
2728
2049
|
this.closed = true;
|
|
2729
2050
|
this.closing = false;
|
|
2730
2051
|
this.callbackQueue.length = 0;
|
|
2731
|
-
this.pendingEndpointAttestation = undefined;
|
|
2732
2052
|
this.pendingEndpointRefreshEvent = undefined;
|
|
2733
2053
|
this.pendingEndpointRefreshSelectorClaimed = false;
|
|
2734
2054
|
this.trackedRoutes.clear();
|
|
@@ -2741,13 +2061,12 @@ export class LocalCodexGatewayProvider {
|
|
|
2741
2061
|
this.closing ||
|
|
2742
2062
|
this.closed ||
|
|
2743
2063
|
this.endpointUnavailable ||
|
|
2744
|
-
this.endpointRefresh !== undefined
|
|
2745
|
-
!this.compatibilityAttested) {
|
|
2064
|
+
this.endpointRefresh !== undefined) {
|
|
2746
2065
|
throw new BridgeError("CODEX_PROVIDER_UNAVAILABLE", "The local Codex provider is unavailable.", true);
|
|
2747
2066
|
}
|
|
2748
2067
|
}
|
|
2749
|
-
async ensureRoute(threadId, queueInitialObservation = true,
|
|
2750
|
-
if (
|
|
2068
|
+
async ensureRoute(threadId, queueInitialObservation = true, allowPendingEndpointActivation = false) {
|
|
2069
|
+
if (allowPendingEndpointActivation) {
|
|
2751
2070
|
if (!this.initialized || this.closing || this.closed) {
|
|
2752
2071
|
throw new BridgeError("CODEX_PROVIDER_UNAVAILABLE", "The local Codex provider is unavailable.", true);
|
|
2753
2072
|
}
|
|
@@ -2758,7 +2077,7 @@ export class LocalCodexGatewayProvider {
|
|
|
2758
2077
|
const pendingRelease = this.routeReleases.get(threadId);
|
|
2759
2078
|
if (pendingRelease !== undefined) {
|
|
2760
2079
|
await pendingRelease;
|
|
2761
|
-
return await this.ensureRoute(threadId, queueInitialObservation,
|
|
2080
|
+
return await this.ensureRoute(threadId, queueInitialObservation, allowPendingEndpointActivation);
|
|
2762
2081
|
}
|
|
2763
2082
|
const existing = this.routes.get(threadId);
|
|
2764
2083
|
if (existing !== undefined) {
|
|
@@ -2770,7 +2089,7 @@ export class LocalCodexGatewayProvider {
|
|
|
2770
2089
|
// a fresh one. The identity-checked release lets automatic recovery and
|
|
2771
2090
|
// an explicit selector join the same cleanup safely.
|
|
2772
2091
|
await this.releaseRouteInternal(threadId);
|
|
2773
|
-
return await this.ensureRoute(threadId, queueInitialObservation,
|
|
2092
|
+
return await this.ensureRoute(threadId, queueInitialObservation, allowPendingEndpointActivation);
|
|
2774
2093
|
}
|
|
2775
2094
|
const pending = this.routeCreations.get(threadId);
|
|
2776
2095
|
if (pending !== undefined)
|
|
@@ -2780,14 +2099,12 @@ export class LocalCodexGatewayProvider {
|
|
|
2780
2099
|
}
|
|
2781
2100
|
const admittedFactory = this.factory;
|
|
2782
2101
|
const creation = (async () => {
|
|
2783
|
-
const route = await this.createRoute(threadId, admittedFactory, queueInitialObservation
|
|
2784
|
-
? this.compatibilityAttested
|
|
2785
|
-
: codexFactoryWritesEnabled(admittedFactory, this.pendingEndpointAttestation, this.latestWriteCompatibilityProbeObservation(admittedFactory.endpointGeneration)?.outcome === "pass"));
|
|
2102
|
+
const route = await this.createRoute(threadId, admittedFactory, queueInitialObservation);
|
|
2786
2103
|
if (this.closing || this.closed) {
|
|
2787
2104
|
await this.closeRoute(route);
|
|
2788
2105
|
throw new BridgeError("CODEX_PROVIDER_UNAVAILABLE", "The local Codex provider closed during route creation.");
|
|
2789
2106
|
}
|
|
2790
|
-
if (!
|
|
2107
|
+
if (!allowPendingEndpointActivation &&
|
|
2791
2108
|
(this.endpointUnavailable ||
|
|
2792
2109
|
this.endpointRefresh !== undefined ||
|
|
2793
2110
|
admittedFactory !== this.factory ||
|
|
@@ -2806,15 +2123,14 @@ export class LocalCodexGatewayProvider {
|
|
|
2806
2123
|
this.routeCreations.delete(threadId);
|
|
2807
2124
|
}
|
|
2808
2125
|
}
|
|
2809
|
-
async createRoute(threadId, factory, queueInitialObservation
|
|
2126
|
+
async createRoute(threadId, factory, queueInitialObservation) {
|
|
2810
2127
|
let transport;
|
|
2811
2128
|
let connector;
|
|
2812
2129
|
const generation = Symbol(threadId);
|
|
2813
2130
|
try {
|
|
2814
2131
|
transport = await factory.connectTransport();
|
|
2815
2132
|
connector = await CodexAppServerConnector.connect({
|
|
2816
|
-
compatibility:
|
|
2817
|
-
writesEnabled,
|
|
2133
|
+
compatibility: { endpointGeneration: factory.endpointGeneration },
|
|
2818
2134
|
route: {
|
|
2819
2135
|
endpointGeneration: factory.endpointGeneration,
|
|
2820
2136
|
threadId,
|
|
@@ -2919,12 +2235,11 @@ export class LocalCodexGatewayProvider {
|
|
|
2919
2235
|
}
|
|
2920
2236
|
try {
|
|
2921
2237
|
if (this.endpointUnavailable) {
|
|
2922
|
-
if (this.
|
|
2238
|
+
if (this.pendingEndpointRefreshEvent !== undefined) {
|
|
2923
2239
|
throw new BridgeError("CODEX_ENDPOINT_REFRESH_PENDING", "The replacement Codex endpoint is awaiting controller activation.", true);
|
|
2924
2240
|
}
|
|
2925
2241
|
const refreshed = await this.refreshEndpoint("callback");
|
|
2926
|
-
if (refreshed?.event.
|
|
2927
|
-
refreshed.event.routes.some((route) => route.routeHandle === threadId)) {
|
|
2242
|
+
if (refreshed?.event.routes.some((route) => route.routeHandle === threadId)) {
|
|
2928
2243
|
this.routesRequiringRecovery.delete(threadId);
|
|
2929
2244
|
this.routeRecoveryAttempts.delete(threadId);
|
|
2930
2245
|
return;
|
|
@@ -2954,8 +2269,7 @@ export class LocalCodexGatewayProvider {
|
|
|
2954
2269
|
if (this.isEndpointGenerationChanged(error)) {
|
|
2955
2270
|
this.endpointUnavailable = true;
|
|
2956
2271
|
const refreshed = await this.refreshEndpoint("callback").catch(() => undefined);
|
|
2957
|
-
if (refreshed?.event.
|
|
2958
|
-
refreshed.event.routes.some((route) => route.routeHandle === threadId)) {
|
|
2272
|
+
if (refreshed?.event.routes.some((route) => route.routeHandle === threadId)) {
|
|
2959
2273
|
this.routesRequiringRecovery.delete(threadId);
|
|
2960
2274
|
this.routeRecoveryAttempts.delete(threadId);
|
|
2961
2275
|
return;
|
|
@@ -2986,7 +2300,6 @@ export class LocalCodexGatewayProvider {
|
|
|
2986
2300
|
const event = this.pendingEndpointRefreshEvent;
|
|
2987
2301
|
if (event === undefined ||
|
|
2988
2302
|
this.pendingEndpointRefreshSelectorClaimed ||
|
|
2989
|
-
this.pendingEndpointAttestation === undefined ||
|
|
2990
2303
|
event.current.endpointGeneration !== this.factory.endpointGeneration) {
|
|
2991
2304
|
return undefined;
|
|
2992
2305
|
}
|
|
@@ -3033,40 +2346,7 @@ export class LocalCodexGatewayProvider {
|
|
|
3033
2346
|
try {
|
|
3034
2347
|
const resolved = await this.resolveEndpointRefreshCandidate(refreshFactory, previousFactory, previous);
|
|
3035
2348
|
candidate = resolved.factory;
|
|
3036
|
-
const { attestation, identity: candidateIdentity } = resolved;
|
|
3037
2349
|
await this.retireEndpointGeneration(previousFactory, previous.endpointGeneration);
|
|
3038
|
-
if (attestation.tier === "incompatible") {
|
|
3039
|
-
await candidate.close();
|
|
3040
|
-
candidate = undefined;
|
|
3041
|
-
this.compatibilityAttested = false;
|
|
3042
|
-
this.pendingEndpointAttestation = undefined;
|
|
3043
|
-
this.pendingEndpointRefreshEvent = undefined;
|
|
3044
|
-
this.pendingEndpointRefreshSelectorClaimed = false;
|
|
3045
|
-
for (const routeHandle of this.trackedRoutes) {
|
|
3046
|
-
this.routesRequiringRecovery.add(routeHandle);
|
|
3047
|
-
}
|
|
3048
|
-
if (this.closing || this.closed)
|
|
3049
|
-
return undefined;
|
|
3050
|
-
const result = {
|
|
3051
|
-
event: {
|
|
3052
|
-
outcome: "incompatible",
|
|
3053
|
-
previous,
|
|
3054
|
-
candidate: candidateIdentity,
|
|
3055
|
-
attestation,
|
|
3056
|
-
},
|
|
3057
|
-
delivery: "callback",
|
|
3058
|
-
selectorClaimed: true,
|
|
3059
|
-
published: false,
|
|
3060
|
-
};
|
|
3061
|
-
result.published = true;
|
|
3062
|
-
this.emitEndpointRefresh(result.event);
|
|
3063
|
-
for (const routeHandle of this.routesRequiringRecovery) {
|
|
3064
|
-
if (this.trackedRoutes.has(routeHandle)) {
|
|
3065
|
-
this.scheduleRouteRecovery(routeHandle);
|
|
3066
|
-
}
|
|
3067
|
-
}
|
|
3068
|
-
return result;
|
|
3069
|
-
}
|
|
3070
2350
|
if (this.closing || this.closed) {
|
|
3071
2351
|
await candidate.close();
|
|
3072
2352
|
candidate = undefined;
|
|
@@ -3079,7 +2359,7 @@ export class LocalCodexGatewayProvider {
|
|
|
3079
2359
|
if (this.closing || this.closed)
|
|
3080
2360
|
break;
|
|
3081
2361
|
try {
|
|
3082
|
-
const route = await this.createRoute(routeHandle, replacementFactory, false
|
|
2362
|
+
const route = await this.createRoute(routeHandle, replacementFactory, false);
|
|
3083
2363
|
if (this.closing || this.closed) {
|
|
3084
2364
|
await this.closeRoute(route);
|
|
3085
2365
|
break;
|
|
@@ -3105,9 +2385,7 @@ export class LocalCodexGatewayProvider {
|
|
|
3105
2385
|
this.factory = replacementFactory;
|
|
3106
2386
|
candidate = undefined;
|
|
3107
2387
|
this.retiredEndpointGeneration = undefined;
|
|
3108
|
-
this.compatibilityAttested = false;
|
|
3109
2388
|
this.endpointUnavailable = true;
|
|
3110
|
-
this.pendingEndpointAttestation = attestation;
|
|
3111
2389
|
for (const staged of stagedRoutes) {
|
|
3112
2390
|
this.routes.set(staged.routeHandle, staged.route);
|
|
3113
2391
|
this.routesRequiringRecovery.delete(staged.routeHandle);
|
|
@@ -3119,20 +2397,16 @@ export class LocalCodexGatewayProvider {
|
|
|
3119
2397
|
}
|
|
3120
2398
|
const result = {
|
|
3121
2399
|
event: {
|
|
3122
|
-
outcome: "compatible",
|
|
3123
2400
|
previous,
|
|
3124
2401
|
current: this.identity,
|
|
3125
|
-
attestation,
|
|
3126
2402
|
routes: refreshedRoutes,
|
|
3127
2403
|
},
|
|
3128
2404
|
delivery: this.endpointRefreshDelivery ?? "callback",
|
|
3129
2405
|
selectorClaimed: false,
|
|
3130
2406
|
published: false,
|
|
3131
2407
|
};
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
this.pendingEndpointRefreshSelectorClaimed = false;
|
|
3135
|
-
}
|
|
2408
|
+
this.pendingEndpointRefreshEvent = result.event;
|
|
2409
|
+
this.pendingEndpointRefreshSelectorClaimed = false;
|
|
3136
2410
|
if (result.delivery === "callback") {
|
|
3137
2411
|
result.selectorClaimed = true;
|
|
3138
2412
|
result.published = true;
|
|
@@ -3163,10 +2437,7 @@ export class LocalCodexGatewayProvider {
|
|
|
3163
2437
|
let candidate;
|
|
3164
2438
|
try {
|
|
3165
2439
|
candidate = await refreshFactory();
|
|
3166
|
-
|
|
3167
|
-
validateCodexFactory(candidate, {
|
|
3168
|
-
allowUnsupportedVersion: versionFailure !== undefined,
|
|
3169
|
-
});
|
|
2440
|
+
validateCodexFactory(candidate);
|
|
3170
2441
|
if (candidate.hostId !== previous.hostId ||
|
|
3171
2442
|
candidate.protocol !== previousFactory.protocol) {
|
|
3172
2443
|
throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "The replacement Codex factory moved outside its pinned boundary.");
|
|
@@ -3176,41 +2447,12 @@ export class LocalCodexGatewayProvider {
|
|
|
3176
2447
|
if (candidate !== previousFactory)
|
|
3177
2448
|
await candidate.close();
|
|
3178
2449
|
candidate = undefined;
|
|
3179
|
-
if (this.endpointUnavailable &&
|
|
3180
|
-
this.compatibilityFailureCode === undefined &&
|
|
3181
|
-
!this.factory.writableReady &&
|
|
3182
|
-
this.factory.writeCompatibility === null) {
|
|
3183
|
-
throw new BridgeError("CODEX_MONITOR_ONLY", "This Codex App Server remains monitor-only until a write-attested generation is available.");
|
|
3184
|
-
}
|
|
3185
2450
|
if (attempt + 1 < MAX_CODEX_ENDPOINT_REFRESH_CANDIDATES) {
|
|
3186
2451
|
continue;
|
|
3187
2452
|
}
|
|
3188
2453
|
throw new BridgeError("CODEX_ENDPOINT_GENERATION_CHURN", "The Codex endpoint did not stabilize within its bounded refresh window.", true);
|
|
3189
2454
|
}
|
|
3190
|
-
|
|
3191
|
-
// outside the tested major is classified from OS-attested factory
|
|
3192
|
-
// evidence alone; no connector or transport may touch that protocol.
|
|
3193
|
-
const probes = versionFailure === undefined
|
|
3194
|
-
? await this.runCompatibilityProbesFor(candidate)
|
|
3195
|
-
: compatibilityProbeNames.codex.map((name, index) => index === 0
|
|
3196
|
-
? passedProbe(name)
|
|
3197
|
-
: failedProbe(name, versionFailure));
|
|
3198
|
-
const attestation = evaluateCompatibilityAttestation({
|
|
3199
|
-
surface: "codex",
|
|
3200
|
-
version: candidate.appServerVersion,
|
|
3201
|
-
checkedAt: this.now().toISOString(),
|
|
3202
|
-
certifiedVersions: certifiedCompatibilityVersions.codex,
|
|
3203
|
-
probes,
|
|
3204
|
-
});
|
|
3205
|
-
return {
|
|
3206
|
-
factory: candidate,
|
|
3207
|
-
identity: {
|
|
3208
|
-
provider: "codex",
|
|
3209
|
-
hostId: previous.hostId,
|
|
3210
|
-
endpointGeneration: candidate.endpointGeneration,
|
|
3211
|
-
},
|
|
3212
|
-
attestation,
|
|
3213
|
-
};
|
|
2455
|
+
return { factory: candidate };
|
|
3214
2456
|
}
|
|
3215
2457
|
catch (error) {
|
|
3216
2458
|
if (candidate !== undefined && candidate !== previousFactory) {
|
|
@@ -3266,7 +2508,6 @@ export class LocalCodexGatewayProvider {
|
|
|
3266
2508
|
return;
|
|
3267
2509
|
let event = result.event;
|
|
3268
2510
|
if (staleRouteHandle !== undefined &&
|
|
3269
|
-
event.outcome === "compatible" &&
|
|
3270
2511
|
event.routes.some((route) => route.routeHandle === staleRouteHandle)) {
|
|
3271
2512
|
event = {
|
|
3272
2513
|
...event,
|
|
@@ -3280,9 +2521,7 @@ export class LocalCodexGatewayProvider {
|
|
|
3280
2521
|
}
|
|
3281
2522
|
publishEndpointRefresh(event) {
|
|
3282
2523
|
this.emitEndpointRefresh(event);
|
|
3283
|
-
|
|
3284
|
-
this.armEndpointActivationRetry(event);
|
|
3285
|
-
}
|
|
2524
|
+
this.armEndpointActivationRetry(event);
|
|
3286
2525
|
}
|
|
3287
2526
|
armEndpointActivationRetry(event) {
|
|
3288
2527
|
this.clearEndpointActivationRetry();
|
|
@@ -3295,8 +2534,7 @@ export class LocalCodexGatewayProvider {
|
|
|
3295
2534
|
this.closing ||
|
|
3296
2535
|
this.closed ||
|
|
3297
2536
|
pending.attempt >= 3 ||
|
|
3298
|
-
|
|
3299
|
-
this.pendingEndpointAttestation === undefined)) {
|
|
2537
|
+
this.pendingEndpointRefreshEvent !== pending.event) {
|
|
3300
2538
|
this.clearEndpointActivationRetry();
|
|
3301
2539
|
return;
|
|
3302
2540
|
}
|
|
@@ -3308,8 +2546,7 @@ export class LocalCodexGatewayProvider {
|
|
|
3308
2546
|
const current = this.endpointActivationRetry;
|
|
3309
2547
|
if (current === undefined || current.event !== pending.event)
|
|
3310
2548
|
return;
|
|
3311
|
-
if (current.event
|
|
3312
|
-
this.pendingEndpointAttestation === undefined) {
|
|
2549
|
+
if (this.pendingEndpointRefreshEvent !== current.event) {
|
|
3313
2550
|
this.clearEndpointActivationRetry();
|
|
3314
2551
|
return;
|
|
3315
2552
|
}
|