agent-embassy 1.5.0 → 1.6.1

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.
Files changed (52) hide show
  1. package/CHANGELOG.md +29 -1
  2. package/CONTRIBUTING.md +11 -3
  3. package/README.md +4 -2
  4. package/README.zh-CN.md +4 -2
  5. package/SECURITY.md +30 -9
  6. package/dist/src/gateway/cli.d.ts +1 -1
  7. package/dist/src/gateway/cli.js +4 -1
  8. package/dist/src/gateway/cli.js.map +1 -1
  9. package/dist/src/gateway/codex-app-server.d.ts +43 -2
  10. package/dist/src/gateway/codex-app-server.js +539 -3
  11. package/dist/src/gateway/codex-app-server.js.map +1 -1
  12. package/dist/src/gateway/compatibility.d.ts +31 -3
  13. package/dist/src/gateway/compatibility.js +100 -29
  14. package/dist/src/gateway/compatibility.js.map +1 -1
  15. package/dist/src/gateway/dashboard-copy.d.ts +1 -1
  16. package/dist/src/gateway/dashboard-copy.en.d.ts +6 -0
  17. package/dist/src/gateway/dashboard-copy.en.js +6 -0
  18. package/dist/src/gateway/dashboard-copy.en.js.map +1 -1
  19. package/dist/src/gateway/dashboard-copy.js +6 -0
  20. package/dist/src/gateway/dashboard-copy.js.map +1 -1
  21. package/dist/src/gateway/dashboard-copy.zh-CN.d.ts +6 -0
  22. package/dist/src/gateway/dashboard-copy.zh-CN.js +6 -0
  23. package/dist/src/gateway/dashboard-copy.zh-CN.js.map +1 -1
  24. package/dist/src/gateway/dashboard-model.d.ts +27 -7
  25. package/dist/src/gateway/dashboard-model.js +78 -25
  26. package/dist/src/gateway/dashboard-model.js.map +1 -1
  27. package/dist/src/gateway/dashboard.d.ts +3 -0
  28. package/dist/src/gateway/dashboard.js +15 -3
  29. package/dist/src/gateway/dashboard.js.map +1 -1
  30. package/dist/src/gateway/deepseek-detect.d.ts +13 -0
  31. package/dist/src/gateway/deepseek-detect.js +125 -0
  32. package/dist/src/gateway/deepseek-detect.js.map +1 -0
  33. package/dist/src/gateway/live-dashboard-app/app.js +12 -11
  34. package/dist/src/gateway/providers.d.ts +13 -2
  35. package/dist/src/gateway/providers.js +370 -24
  36. package/dist/src/gateway/providers.js.map +1 -1
  37. package/dist/src/gateway/server.d.ts +2 -0
  38. package/dist/src/gateway/server.js +6 -0
  39. package/dist/src/gateway/server.js.map +1 -1
  40. package/dist/src/gateway/service.d.ts +21 -2
  41. package/dist/src/gateway/service.js +122 -38
  42. package/dist/src/gateway/service.js.map +1 -1
  43. package/dist/src/gateway/types.d.ts +4 -3
  44. package/dist/src/gateway/types.js +17 -14
  45. package/dist/src/gateway/types.js.map +1 -1
  46. package/docs/CONFIGURATION.md +2 -2
  47. package/docs/CONFIGURATION.zh-CN.md +2 -2
  48. package/docs/DASHBOARD.md +10 -4
  49. package/docs/DASHBOARD.zh-CN.md +1 -1
  50. package/docs/GATEWAY-ARCHITECTURE.md +40 -14
  51. package/package.json +1 -1
  52. package/skills/embassy-peer/SKILL.md +1 -1
@@ -1,8 +1,9 @@
1
1
  import path from "node:path";
2
+ import { chmod, lstat, mkdir, mkdtemp, readdir, realpath, rmdir, } from "node:fs/promises";
2
3
  import { BridgeError } from "../errors.js";
3
4
  import { CLAUDE_PEER_COMPATIBILITY, ClaudePeerAdapter, } from "./claude-peer.js";
4
- import { certifiedCompatibilityVersions, compatibilityProbeNames, evaluateCompatibilityAttestation, isCompatibilityAttestation, isCompatibilityVersion, sharesCompatibilityMajor, UNKNOWN_COMPATIBILITY_VERSION, } from "./compatibility.js";
5
- import { CODEX_APP_SERVER_WRITABLE_VERSIONS, CodexAppServerConnector, CodexConnectorError, } from "./codex-app-server.js";
5
+ import { certifiedCompatibilityVersions, compatibilityCoversWrites, compatibilityProbeNames, evaluateCompatibilityAttestation, isCompatibilityAttestation, isCompatibilityVersion, sharesCompatibilityMajor, UNKNOWN_COMPATIBILITY_VERSION, } from "./compatibility.js";
6
+ import { CODEX_APP_SERVER_WRITABLE_VERSIONS, CodexAppServerConnector, CodexConnectorError, codexWriteProbeFailure, } from "./codex-app-server.js";
6
7
  import { LocalCodexTransportError } from "./codex-local-transport.js";
7
8
  import { ClaudeNativeHelperSupervisor, } from "./claude-helper-supervisor.js";
8
9
  import { isDashboardLocale } from "./locale.js";
@@ -24,6 +25,12 @@ const DEFAULT_CODEX_RECOVERY_INITIAL_MS = 250;
24
25
  const DEFAULT_CODEX_RECOVERY_MAX_MS = 5_000;
25
26
  const MAX_CODEX_ENDPOINT_REFRESH_CANDIDATES = 3;
26
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
+ ]);
27
34
  const CLAUDE_CLEAN_PREWRITE_RETRY_CODES = new Set([
28
35
  "CLAUDE_PEER_TARGET_UNKNOWN",
29
36
  "CLAUDE_PEER_TARGET_STALE",
@@ -85,6 +92,99 @@ function passedProbe(name) {
85
92
  function failedProbe(name, safeErrorCode) {
86
93
  return { name, outcome: "fail", safeErrorCode };
87
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
+ }
88
188
  function exactLocalHost(hostId) {
89
189
  if ((hostId ?? LOCAL_HOST) !== LOCAL_HOST) {
90
190
  throw new BridgeError("GATEWAY_REMOTE_PROVIDER_DISABLED", "This provider is restricted to the exact local host boundary.");
@@ -1840,6 +1940,16 @@ function validateCodexFactory(factory, options = {}) {
1840
1940
  throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "The local Codex provider requires exact schema and write attestations.");
1841
1941
  }
1842
1942
  }
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
+ }
1843
1953
  function codexRouteState(observation) {
1844
1954
  if (observation.connection !== "ready")
1845
1955
  return "stale";
@@ -1897,11 +2007,16 @@ export class LocalCodexGatewayProvider {
1897
2007
  endpointActivationRetry;
1898
2008
  endpointActivationRetryTimer;
1899
2009
  callbackDrainFrozen = false;
2010
+ writeProbeObservationsByGeneration = new Map();
2011
+ writeProbeResults = new Map();
2012
+ writeProbeDecline;
2013
+ writeProbeOverflow;
1900
2014
  compatibilityAttested;
1901
2015
  compatibilityFailureCode;
1902
2016
  endpointUnavailable = false;
1903
2017
  pendingEndpointAttestation;
1904
2018
  pendingEndpointRefreshEvent;
2019
+ pendingEndpointRefreshSelectorClaimed = false;
1905
2020
  initialized = false;
1906
2021
  closing = false;
1907
2022
  closed = false;
@@ -1910,7 +2025,9 @@ export class LocalCodexGatewayProvider {
1910
2025
  this.factory = options.factory;
1911
2026
  this.refreshFactory = options.refreshFactory;
1912
2027
  exactLocalHost(options.factory.hostId);
1913
- this.compatibilityAttested = CODEX_APP_SERVER_WRITABLE_VERSIONS.includes(options.factory.appServerVersion);
2028
+ this.compatibilityAttested =
2029
+ options.factory.writableReady &&
2030
+ options.factory.writeCompatibility !== null;
1914
2031
  this.maxCallbacks = positiveBounded(options.maxCallbackEvents, MAX_CODEX_CALLBACKS, 4_096);
1915
2032
  this.maxRoutes = positiveBounded(options.maxRoutes, MAX_CODEX_ROUTES, 256);
1916
2033
  this.maxReplyBytes = positiveBounded(options.maxReplyBytes, MAX_TRANSIENT_REPLY_BYTES, 1024 * 1024);
@@ -1961,6 +2078,7 @@ export class LocalCodexGatewayProvider {
1961
2078
  if (attestation.tier === "incompatible") {
1962
2079
  this.pendingEndpointAttestation = undefined;
1963
2080
  this.pendingEndpointRefreshEvent = undefined;
2081
+ this.pendingEndpointRefreshSelectorClaimed = false;
1964
2082
  this.clearEndpointActivationRetry();
1965
2083
  this.compatibilityAttested = false;
1966
2084
  this.endpointUnavailable = true;
@@ -1968,29 +2086,57 @@ export class LocalCodexGatewayProvider {
1968
2086
  attestation.safeErrorCode ?? "CODEX_COMPATIBILITY_CHECK_FAILED";
1969
2087
  return;
1970
2088
  }
1971
- const writableCertified = attestation.tier === "certified" &&
1972
- CODEX_APP_SERVER_WRITABLE_VERSIONS.includes(attestation.version) &&
1973
- this.factory.writableReady &&
1974
- this.factory.writeCompatibility !== null;
2089
+ const writesEnabled = codexFactoryWritesEnabled(this.factory, attestation, this.latestWriteCompatibilityProbeObservation(this.factory.endpointGeneration)?.outcome === "pass");
1975
2090
  const schemaObserved = attestation.tier === "schema_attested" &&
1976
2091
  !this.factory.writableReady &&
1977
2092
  this.factory.writeCompatibility === null;
1978
- if ((!writableCertified && !schemaObserved) ||
2093
+ if ((!writesEnabled && !schemaObserved) ||
1979
2094
  (this.endpointUnavailable && pending === undefined) ||
1980
2095
  !pendingMatches) {
1981
2096
  throw new BridgeError("CODEX_COMPATIBILITY_ATTESTATION_MISMATCH", "The Codex compatibility attestation does not match this endpoint.");
1982
2097
  }
1983
2098
  this.pendingEndpointAttestation = undefined;
1984
2099
  this.pendingEndpointRefreshEvent = undefined;
2100
+ this.pendingEndpointRefreshSelectorClaimed = false;
1985
2101
  this.clearEndpointActivationRetry();
1986
- this.compatibilityAttested = writableCertified;
1987
- this.endpointUnavailable = !writableCertified;
2102
+ this.compatibilityAttested = writesEnabled;
2103
+ this.endpointUnavailable = !writesEnabled;
1988
2104
  this.compatibilityFailureCode = undefined;
1989
2105
  }
1990
- async runCompatibilityProbes() {
1991
- return await this.runCompatibilityProbesFor(this.factory);
2106
+ releaseEndpointRefreshSelectorClaim(endpointGeneration) {
2107
+ const event = this.pendingEndpointRefreshEvent;
2108
+ if (event?.current.endpointGeneration === endpointGeneration &&
2109
+ this.pendingEndpointAttestation !== undefined) {
2110
+ this.pendingEndpointRefreshSelectorClaimed = false;
2111
+ }
2112
+ }
2113
+ rearmEndpointRefreshActivation(endpointGeneration) {
2114
+ const event = this.pendingEndpointRefreshEvent;
2115
+ if (event?.current.endpointGeneration === endpointGeneration &&
2116
+ this.pendingEndpointAttestation !== undefined &&
2117
+ !this.closing &&
2118
+ !this.closed) {
2119
+ this.publishEndpointRefresh(event);
2120
+ }
2121
+ }
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
+ });
1992
2138
  }
1993
- async runCompatibilityProbesFor(factory) {
2139
+ async runCompatibilityProbesFor(factory, context) {
1994
2140
  const [installation, control, initialize, threadList] = compatibilityProbeNames.codex;
1995
2141
  let transport;
1996
2142
  let connector;
@@ -2000,6 +2146,9 @@ export class LocalCodexGatewayProvider {
2000
2146
  stage = "initialize";
2001
2147
  connector = await CodexAppServerConnector.connect({
2002
2148
  compatibility: factory.schemaCompatibility,
2149
+ ...(context === undefined
2150
+ ? {}
2151
+ : { writeCompatibilityProbe: true }),
2003
2152
  writesEnabled: false,
2004
2153
  route: {
2005
2154
  endpointGeneration: factory.endpointGeneration,
@@ -2013,16 +2162,25 @@ export class LocalCodexGatewayProvider {
2013
2162
  });
2014
2163
  stage = "thread_list";
2015
2164
  await connector.observeLoadedThread(connector.guard());
2016
- return [
2165
+ const requiredProbes = [
2017
2166
  passedProbe(installation),
2018
2167
  passedProbe(control),
2019
2168
  passedProbe(initialize),
2020
2169
  passedProbe(threadList),
2021
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;
2022
2177
  }
2023
2178
  catch (error) {
2024
- if (this.isEndpointGenerationChanged(error))
2179
+ if (this.isEndpointGenerationChanged(error) ||
2180
+ (error instanceof BridgeError &&
2181
+ error.code === "CODEX_FACTORY_ATTESTATION_INVALID")) {
2025
2182
  throw error;
2183
+ }
2026
2184
  if (stage === "transport") {
2027
2185
  const availabilityFailure = error instanceof LocalCodexTransportError &&
2028
2186
  [
@@ -2066,6 +2224,164 @@ export class LocalCodexGatewayProvider {
2066
2224
  }
2067
2225
  }
2068
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
+ }
2069
2385
  async initialize(callbacks) {
2070
2386
  if (this.closed || this.initialized) {
2071
2387
  throw new BridgeError("CODEX_PROVIDER_INITIALIZATION_REJECTED", "The local Codex provider cannot be initialized in this state.");
@@ -2079,7 +2395,7 @@ export class LocalCodexGatewayProvider {
2079
2395
  safeErrorCode: this.compatibilityFailureCode,
2080
2396
  };
2081
2397
  }
2082
- return this.factory.writeCompatibility === null
2398
+ return !this.compatibilityAttested
2083
2399
  ? {
2084
2400
  health: "degraded",
2085
2401
  compatibility: "compatible",
@@ -2124,9 +2440,13 @@ export class LocalCodexGatewayProvider {
2124
2440
  throw selectionError;
2125
2441
  }
2126
2442
  };
2443
+ const retainedEndpointRefresh = this.retainedEndpointRefreshResult();
2127
2444
  if (this.endpointRefresh !== undefined) {
2128
2445
  route = await stageRefreshedRoute(await this.refreshEndpoint("selector"));
2129
2446
  }
2447
+ else if (retainedEndpointRefresh !== undefined) {
2448
+ route = await stageRefreshedRoute(retainedEndpointRefresh);
2449
+ }
2130
2450
  else if (this.endpointUnavailable &&
2131
2451
  this.pendingEndpointAttestation === undefined) {
2132
2452
  route = await stageRefreshedRoute(await this.refreshEndpoint("selector"));
@@ -2259,10 +2579,6 @@ export class LocalCodexGatewayProvider {
2259
2579
  route.endpointGeneration !== this.factory.endpointGeneration) {
2260
2580
  return { state: "failed", safeErrorCode: "CODEX_ROUTE_UNAVAILABLE" };
2261
2581
  }
2262
- if (!this.factory.writableReady ||
2263
- this.factory.writeCompatibility === null) {
2264
- return { state: "failed", safeErrorCode: "CODEX_WRITES_DISABLED" };
2265
- }
2266
2582
  const guard = route.connector.guard();
2267
2583
  if (!guard.writableReady) {
2268
2584
  return { state: "failed", safeErrorCode: "CODEX_WRITES_DISABLED" };
@@ -2385,6 +2701,7 @@ export class LocalCodexGatewayProvider {
2385
2701
  this.routesRequiringRecovery.clear();
2386
2702
  this.clearEndpointActivationRetry();
2387
2703
  this.pendingEndpointRefreshEvent = undefined;
2704
+ this.pendingEndpointRefreshSelectorClaimed = false;
2388
2705
  this.pendingEndpointAttestation = undefined;
2389
2706
  const refreshResult = this.endpointRefresh === undefined
2390
2707
  ? []
@@ -2413,6 +2730,7 @@ export class LocalCodexGatewayProvider {
2413
2730
  this.callbackQueue.length = 0;
2414
2731
  this.pendingEndpointAttestation = undefined;
2415
2732
  this.pendingEndpointRefreshEvent = undefined;
2733
+ this.pendingEndpointRefreshSelectorClaimed = false;
2416
2734
  this.trackedRoutes.clear();
2417
2735
  this.routeAliases.clear();
2418
2736
  this.expectsReply.clear();
@@ -2462,7 +2780,9 @@ export class LocalCodexGatewayProvider {
2462
2780
  }
2463
2781
  const admittedFactory = this.factory;
2464
2782
  const creation = (async () => {
2465
- const route = await this.createRoute(threadId, admittedFactory, queueInitialObservation);
2783
+ const route = await this.createRoute(threadId, admittedFactory, queueInitialObservation, this.pendingEndpointAttestation === undefined
2784
+ ? this.compatibilityAttested
2785
+ : codexFactoryWritesEnabled(admittedFactory, this.pendingEndpointAttestation, this.latestWriteCompatibilityProbeObservation(admittedFactory.endpointGeneration)?.outcome === "pass"));
2466
2786
  if (this.closing || this.closed) {
2467
2787
  await this.closeRoute(route);
2468
2788
  throw new BridgeError("CODEX_PROVIDER_UNAVAILABLE", "The local Codex provider closed during route creation.");
@@ -2486,13 +2806,12 @@ export class LocalCodexGatewayProvider {
2486
2806
  this.routeCreations.delete(threadId);
2487
2807
  }
2488
2808
  }
2489
- async createRoute(threadId, factory, queueInitialObservation) {
2809
+ async createRoute(threadId, factory, queueInitialObservation, writesEnabled) {
2490
2810
  let transport;
2491
2811
  let connector;
2492
2812
  const generation = Symbol(threadId);
2493
2813
  try {
2494
2814
  transport = await factory.connectTransport();
2495
- const writesEnabled = factory.writableReady && factory.writeCompatibility !== null;
2496
2815
  connector = await CodexAppServerConnector.connect({
2497
2816
  compatibility: factory.writeCompatibility ?? factory.schemaCompatibility,
2498
2817
  writesEnabled,
@@ -2663,6 +2982,21 @@ export class LocalCodexGatewayProvider {
2663
2982
  event.current.endpointGeneration === this.factory.endpointGeneration &&
2664
2983
  event.routes.some((route) => route.routeHandle === routeHandle));
2665
2984
  }
2985
+ retainedEndpointRefreshResult() {
2986
+ const event = this.pendingEndpointRefreshEvent;
2987
+ if (event === undefined ||
2988
+ this.pendingEndpointRefreshSelectorClaimed ||
2989
+ this.pendingEndpointAttestation === undefined ||
2990
+ event.current.endpointGeneration !== this.factory.endpointGeneration) {
2991
+ return undefined;
2992
+ }
2993
+ return {
2994
+ event,
2995
+ delivery: "selector",
2996
+ selectorClaimed: false,
2997
+ published: true,
2998
+ };
2999
+ }
2666
3000
  async refreshEndpoint(delivery) {
2667
3001
  if (this.refreshFactory === undefined || this.closing || this.closed) {
2668
3002
  return undefined;
@@ -2707,6 +3041,7 @@ export class LocalCodexGatewayProvider {
2707
3041
  this.compatibilityAttested = false;
2708
3042
  this.pendingEndpointAttestation = undefined;
2709
3043
  this.pendingEndpointRefreshEvent = undefined;
3044
+ this.pendingEndpointRefreshSelectorClaimed = false;
2710
3045
  for (const routeHandle of this.trackedRoutes) {
2711
3046
  this.routesRequiringRecovery.add(routeHandle);
2712
3047
  }
@@ -2721,7 +3056,9 @@ export class LocalCodexGatewayProvider {
2721
3056
  },
2722
3057
  delivery: "callback",
2723
3058
  selectorClaimed: true,
3059
+ published: false,
2724
3060
  };
3061
+ result.published = true;
2725
3062
  this.emitEndpointRefresh(result.event);
2726
3063
  for (const routeHandle of this.routesRequiringRecovery) {
2727
3064
  if (this.trackedRoutes.has(routeHandle)) {
@@ -2742,7 +3079,7 @@ export class LocalCodexGatewayProvider {
2742
3079
  if (this.closing || this.closed)
2743
3080
  break;
2744
3081
  try {
2745
- const route = await this.createRoute(routeHandle, replacementFactory, false);
3082
+ const route = await this.createRoute(routeHandle, replacementFactory, false, codexFactoryWritesEnabled(replacementFactory, attestation, this.latestWriteCompatibilityProbeObservation(replacementFactory.endpointGeneration)?.outcome === "pass"));
2746
3083
  if (this.closing || this.closed) {
2747
3084
  await this.closeRoute(route);
2748
3085
  break;
@@ -2790,12 +3127,15 @@ export class LocalCodexGatewayProvider {
2790
3127
  },
2791
3128
  delivery: this.endpointRefreshDelivery ?? "callback",
2792
3129
  selectorClaimed: false,
3130
+ published: false,
2793
3131
  };
2794
3132
  if (result.event.outcome === "compatible") {
2795
3133
  this.pendingEndpointRefreshEvent = result.event;
3134
+ this.pendingEndpointRefreshSelectorClaimed = false;
2796
3135
  }
2797
3136
  if (result.delivery === "callback") {
2798
3137
  result.selectorClaimed = true;
3138
+ result.published = true;
2799
3139
  this.publishEndpointRefresh(result.event);
2800
3140
  }
2801
3141
  for (const routeHandle of this.routesRequiringRecovery) {
@@ -2914,11 +3254,16 @@ export class LocalCodexGatewayProvider {
2914
3254
  return false;
2915
3255
  }
2916
3256
  result.selectorClaimed = true;
3257
+ if (this.pendingEndpointRefreshEvent === result.event) {
3258
+ this.pendingEndpointRefreshSelectorClaimed = true;
3259
+ }
2917
3260
  return true;
2918
3261
  }
2919
3262
  emitSelectorRefreshFallback(result, staleRouteHandle) {
2920
3263
  if (result.delivery !== "selector" || !result.selectorClaimed)
2921
3264
  return;
3265
+ if (result.published)
3266
+ return;
2922
3267
  let event = result.event;
2923
3268
  if (staleRouteHandle !== undefined &&
2924
3269
  event.outcome === "compatible" &&
@@ -2930,6 +3275,7 @@ export class LocalCodexGatewayProvider {
2930
3275
  result.event = event;
2931
3276
  this.pendingEndpointRefreshEvent = event;
2932
3277
  }
3278
+ result.published = true;
2933
3279
  this.publishEndpointRefresh(event);
2934
3280
  }
2935
3281
  publishEndpointRefresh(event) {