agent-embassy 1.2.0 → 1.4.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.
Files changed (109) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/CONTRIBUTING.md +50 -16
  3. package/README.md +57 -25
  4. package/README.zh-CN.md +45 -23
  5. package/SECURITY.md +68 -48
  6. package/dist/src/gateway/claude-helper-protocol.d.ts +1 -0
  7. package/dist/src/gateway/claude-helper-protocol.js +4 -2
  8. package/dist/src/gateway/claude-helper-protocol.js.map +1 -1
  9. package/dist/src/gateway/claude-helper-supervisor.d.ts +1 -0
  10. package/dist/src/gateway/claude-helper-supervisor.js +3 -1
  11. package/dist/src/gateway/claude-helper-supervisor.js.map +1 -1
  12. package/dist/src/gateway/claude-runtime.d.ts +0 -2
  13. package/dist/src/gateway/claude-runtime.js +6 -17
  14. package/dist/src/gateway/claude-runtime.js.map +1 -1
  15. package/dist/src/gateway/cli-copy.d.ts +1 -1
  16. package/dist/src/gateway/cli-copy.en.d.ts +4 -1
  17. package/dist/src/gateway/cli-copy.en.js +7 -3
  18. package/dist/src/gateway/cli-copy.en.js.map +1 -1
  19. package/dist/src/gateway/cli-copy.js +3 -0
  20. package/dist/src/gateway/cli-copy.js.map +1 -1
  21. package/dist/src/gateway/cli-copy.zh-CN.d.ts +4 -1
  22. package/dist/src/gateway/cli-copy.zh-CN.js +7 -3
  23. package/dist/src/gateway/cli-copy.zh-CN.js.map +1 -1
  24. package/dist/src/gateway/cli.d.ts +2 -5
  25. package/dist/src/gateway/cli.js +41 -67
  26. package/dist/src/gateway/cli.js.map +1 -1
  27. package/dist/src/gateway/codex-app-server.d.ts +2 -8
  28. package/dist/src/gateway/codex-app-server.js +36 -62
  29. package/dist/src/gateway/codex-app-server.js.map +1 -1
  30. package/dist/src/gateway/codex-local-transport.d.ts +4 -10
  31. package/dist/src/gateway/codex-local-transport.js +13 -16
  32. package/dist/src/gateway/codex-local-transport.js.map +1 -1
  33. package/dist/src/gateway/compatibility.d.ts +0 -27
  34. package/dist/src/gateway/compatibility.js +1 -101
  35. package/dist/src/gateway/compatibility.js.map +1 -1
  36. package/dist/src/gateway/config.d.ts +1 -4
  37. package/dist/src/gateway/config.js +0 -10
  38. package/dist/src/gateway/config.js.map +1 -1
  39. package/dist/src/gateway/control.d.ts +2 -21
  40. package/dist/src/gateway/control.js +7 -36
  41. package/dist/src/gateway/control.js.map +1 -1
  42. package/dist/src/gateway/dashboard-copy.d.ts +1 -1
  43. package/dist/src/gateway/dashboard-copy.en.d.ts +21 -8
  44. package/dist/src/gateway/dashboard-copy.en.js +40 -27
  45. package/dist/src/gateway/dashboard-copy.en.js.map +1 -1
  46. package/dist/src/gateway/dashboard-copy.js +21 -8
  47. package/dist/src/gateway/dashboard-copy.js.map +1 -1
  48. package/dist/src/gateway/dashboard-copy.zh-CN.d.ts +21 -8
  49. package/dist/src/gateway/dashboard-copy.zh-CN.js +40 -27
  50. package/dist/src/gateway/dashboard-copy.zh-CN.js.map +1 -1
  51. package/dist/src/gateway/dashboard-model.d.ts +4 -9
  52. package/dist/src/gateway/dashboard-model.js +159 -46
  53. package/dist/src/gateway/dashboard-model.js.map +1 -1
  54. package/dist/src/gateway/dashboard.js +27 -16
  55. package/dist/src/gateway/dashboard.js.map +1 -1
  56. package/dist/src/gateway/instance-lease.d.ts +2 -3
  57. package/dist/src/gateway/instance-lease.js +17 -140
  58. package/dist/src/gateway/instance-lease.js.map +1 -1
  59. package/dist/src/gateway/live-dashboard-app/app.js +62 -63
  60. package/dist/src/gateway/live-dashboard-command.d.ts +5 -1
  61. package/dist/src/gateway/live-dashboard-command.js +8 -6
  62. package/dist/src/gateway/live-dashboard-command.js.map +1 -1
  63. package/dist/src/gateway/live-dashboard-http.d.ts +0 -4
  64. package/dist/src/gateway/live-dashboard-http.js +20 -94
  65. package/dist/src/gateway/live-dashboard-http.js.map +1 -1
  66. package/dist/src/gateway/live-dashboard-protocol.d.ts +1 -5
  67. package/dist/src/gateway/live-dashboard-protocol.js +0 -42
  68. package/dist/src/gateway/live-dashboard-protocol.js.map +1 -1
  69. package/dist/src/gateway/live-dashboard-server.d.ts +2 -2
  70. package/dist/src/gateway/live-dashboard-server.js +18 -4
  71. package/dist/src/gateway/live-dashboard-server.js.map +1 -1
  72. package/dist/src/gateway/live-dashboard.d.ts +3 -6
  73. package/dist/src/gateway/live-dashboard.js +6 -42
  74. package/dist/src/gateway/live-dashboard.js.map +1 -1
  75. package/dist/src/gateway/progress-watch-machine.d.ts +6 -5
  76. package/dist/src/gateway/progress-watch-machine.js +6 -6
  77. package/dist/src/gateway/progress-watch-machine.js.map +1 -1
  78. package/dist/src/gateway/provenance-envelope.d.ts +1 -0
  79. package/dist/src/gateway/provenance-envelope.js +11 -4
  80. package/dist/src/gateway/provenance-envelope.js.map +1 -1
  81. package/dist/src/gateway/providers.d.ts +2 -21
  82. package/dist/src/gateway/providers.js +21 -261
  83. package/dist/src/gateway/providers.js.map +1 -1
  84. package/dist/src/gateway/server.js +0 -3
  85. package/dist/src/gateway/server.js.map +1 -1
  86. package/dist/src/gateway/service.d.ts +5 -15
  87. package/dist/src/gateway/service.js +101 -265
  88. package/dist/src/gateway/service.js.map +1 -1
  89. package/dist/src/gateway/store.d.ts +9 -21
  90. package/dist/src/gateway/store.js +360 -140
  91. package/dist/src/gateway/store.js.map +1 -1
  92. package/dist/src/gateway/types.d.ts +1 -6
  93. package/dist/src/gateway/types.js.map +1 -1
  94. package/docs/CONFIGURATION.md +102 -0
  95. package/docs/CONFIGURATION.zh-CN.md +72 -0
  96. package/docs/DASHBOARD.md +103 -0
  97. package/docs/DASHBOARD.zh-CN.md +47 -0
  98. package/docs/DELIVERY.md +84 -0
  99. package/docs/DELIVERY.zh-CN.md +53 -0
  100. package/docs/GATEWAY-ARCHITECTURE.md +249 -153
  101. package/package.json +8 -4
  102. package/skills/embassy-peer/SKILL.md +25 -10
  103. package/dist/src/gateway/claude-compatibility-scratch.d.ts +0 -18
  104. package/dist/src/gateway/claude-compatibility-scratch.js +0 -158
  105. package/dist/src/gateway/claude-compatibility-scratch.js.map +0 -1
  106. package/dist/src/gateway/live-dashboard-bootstrap.d.ts +0 -36
  107. package/dist/src/gateway/live-dashboard-bootstrap.js +0 -176
  108. package/dist/src/gateway/live-dashboard-bootstrap.js.map +0 -1
  109. package/docs/DESIGN.md +0 -134
@@ -1,8 +1,7 @@
1
- import { createHash, randomBytes } from "node:crypto";
1
+ import { createHash } from "node:crypto";
2
2
  import path from "node:path";
3
3
  import { BridgeError } from "../errors.js";
4
4
  import { CLAUDE_PEER_COMPATIBILITY, ClaudePeerAdapter, } from "./claude-peer.js";
5
- import { startClaudeCompatibilityScratch, } from "./claude-compatibility-scratch.js";
6
5
  import { certifiedCompatibilityVersions, compatibilityProbeNames, evaluateCompatibilityAttestation, sharesCompatibilityMajor, } from "./compatibility.js";
7
6
  import { CODEX_APP_SERVER_WRITABLE_VERSIONS, CodexAppServerConnector, CodexConnectorError, } from "./codex-app-server.js";
8
7
  import { LocalCodexTransportError } from "./codex-local-transport.js";
@@ -25,9 +24,6 @@ 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
26
  const COMPATIBILITY_PROBE_THREAD_ID = "00000000-0000-7000-8000-000000000000";
28
- const COMPATIBILITY_TURN_TIMEOUT_MS = 60_000;
29
- const CLAUDE_CERTIFICATION_TIMEOUT_MS = 10_000;
30
- const CLAUDE_CERTIFICATION_DISCOVERY_POLL_MS = 100;
31
27
  const CLAUDE_CLEAN_PREWRITE_RETRY_CODES = new Set([
32
28
  "CLAUDE_PEER_TARGET_UNKNOWN",
33
29
  "CLAUDE_PEER_TARGET_STALE",
@@ -109,7 +105,8 @@ function invokeCallback(operation) {
109
105
  }
110
106
  }
111
107
  function validateAttestedClaudeRuntime(runtime) {
112
- if (!sharesCompatibilityMajor(runtime.claudeCodeVersion, CLAUDE_PEER_COMPATIBILITY.claudeCodeVersion) ||
108
+ if (runtime.claudeCodeVersion !==
109
+ CLAUDE_PEER_COMPATIBILITY.claudeCodeVersion ||
113
110
  [
114
111
  runtime.claudeExecutable,
115
112
  runtime.sessionsDir,
@@ -146,7 +143,6 @@ export class LocalClaudeGatewayProvider {
146
143
  now;
147
144
  selectedStateRoots = new Map();
148
145
  nativeHelpers;
149
- compatibilityScratchFactory;
150
146
  discovered = new Map();
151
147
  selected = new Map();
152
148
  /** Exact live same-UID sessions observed through native inbound frames. */
@@ -179,7 +175,6 @@ export class LocalClaudeGatewayProvider {
179
175
  retiredNativeCodexListener;
180
176
  /** Fences discovery callbacks and monitor restarts across listener rotation. */
181
177
  nativeCodexSuccessionFreeze;
182
- compatibilityCertificationInFlight = false;
183
178
  initialized = false;
184
179
  closed = false;
185
180
  constructor(options) {
@@ -205,9 +200,6 @@ export class LocalClaudeGatewayProvider {
205
200
  locale,
206
201
  deliveryNotices,
207
202
  })))(options.runtime, options.locale ?? "en", options.deliveryNotices ?? "merged");
208
- this.compatibilityScratchFactory =
209
- options.compatibilityScratchFactory ??
210
- (() => startClaudeCompatibilityScratch(options.runtime));
211
203
  this.nativeHelpers =
212
204
  options.nativeHelpers === undefined
213
205
  ? undefined
@@ -258,90 +250,6 @@ export class LocalClaudeGatewayProvider {
258
250
  ];
259
251
  }
260
252
  }
261
- async runCompatibilityCertification(input) {
262
- void input.routeHandle;
263
- void input.withTurn;
264
- const depth = "wire";
265
- let scratch;
266
- let listener;
267
- if (this.compatibilityCertificationInFlight) {
268
- return {
269
- depth,
270
- outcome: "fail",
271
- certifiedAt: new Date(this.now()).toISOString(),
272
- safeErrorCode: "CLAUDE_CERTIFICATION_BUSY",
273
- };
274
- }
275
- this.compatibilityCertificationInFlight = true;
276
- try {
277
- this.assertReady();
278
- scratch = await this.compatibilityScratchFactory();
279
- const deadlineAt = this.now() + CLAUDE_CERTIFICATION_TIMEOUT_MS;
280
- let targetId;
281
- while (this.now() < deadlineAt) {
282
- scratch.assertRunning();
283
- const discovery = await this.peer.discover();
284
- if (discovery.truncated) {
285
- throw new BridgeError("CLAUDE_CERTIFICATION_DISCOVERY_INCOMPLETE", "The scratch session could not be proven from a complete registry scan.", true);
286
- }
287
- const matches = discovery.peers.filter((peer) => peer.alias === scratch?.name && peer.targetId === scratch?.sessionId);
288
- if (matches.length > 1) {
289
- throw new BridgeError("CLAUDE_CERTIFICATION_TARGET_COLLISION", "The scratch session identity was not unique.");
290
- }
291
- if (matches.length === 1) {
292
- targetId = matches[0]?.targetId;
293
- break;
294
- }
295
- await new Promise((resolve) => {
296
- const timer = setTimeout(resolve, CLAUDE_CERTIFICATION_DISCOVERY_POLL_MS);
297
- timer.unref();
298
- });
299
- }
300
- if (targetId === undefined) {
301
- throw new BridgeError("CLAUDE_CERTIFICATION_TARGET_UNAVAILABLE", "The bounded scratch session did not publish a discoverable peer record.", true);
302
- }
303
- await this.peer.assertTargetWorkspaceDisjoint(targetId, input.controllerStateRoot);
304
- listener = await this.peer.listen({
305
- onMessage: () => undefined,
306
- onReceipt: () => undefined,
307
- });
308
- const sent = await this.peer.send(targetId, "[embassy compat-certify] ignore", {
309
- listener,
310
- receiptDeadlineAt: deadlineAt,
311
- });
312
- if (sent.transportStatus !== "transport_written" ||
313
- sent.receiptStatus !== "pending") {
314
- throw new BridgeError("CLAUDE_CERTIFICATION_WRITE_UNCONFIRMED", "The scratch diagnostic frame was not accepted for receipt tracking.", true);
315
- }
316
- // A direct `crossSessionInbound: accept` write emits no native
317
- // peer_message_status frame. That status family describes the optional
318
- // approval lifecycle, not universal delivery acknowledgement. For this
319
- // wire-depth certification, the strongest portable evidence is the
320
- // confirmed write to the exact, uniquely discovered scratch session.
321
- return {
322
- depth,
323
- outcome: "pass",
324
- certifiedAt: new Date(this.now()).toISOString(),
325
- };
326
- }
327
- catch (error) {
328
- const observedCode = error instanceof BridgeError && /^[A-Z][A-Z0-9_]{0,63}$/.test(error.code)
329
- ? error.code
330
- : "CLAUDE_CERTIFICATION_FAILED";
331
- return {
332
- depth,
333
- outcome: "fail",
334
- certifiedAt: new Date(this.now()).toISOString(),
335
- safeErrorCode: observedCode,
336
- };
337
- }
338
- finally {
339
- await listener?.close().catch(() => undefined);
340
- await scratch?.close().catch(() => undefined);
341
- await this.peer.discover().catch(() => undefined);
342
- this.compatibilityCertificationInFlight = false;
343
- }
344
- }
345
253
  async initialize(callbacks) {
346
254
  if (this.closed) {
347
255
  throw new BridgeError("CLAUDE_PROVIDER_CLOSED", "The local Claude provider is closed.");
@@ -871,9 +779,7 @@ export class LocalClaudeGatewayProvider {
871
779
  const selectedAlias = this.selected.get(input.binding.routeHandle);
872
780
  const stateRoot = this.selectedStateRoots.get(input.binding.routeHandle);
873
781
  if (input.authorization === "selected_route" &&
874
- (selectedAlias === undefined ||
875
- selectedAlias !== input.targetAlias ||
876
- stateRoot === undefined)) {
782
+ (selectedAlias === undefined || stateRoot === undefined)) {
877
783
  return { state: "failed", safeErrorCode: "CLAUDE_ROUTE_UNAVAILABLE" };
878
784
  }
879
785
  if (input.authorization === "selected_route") {
@@ -919,29 +825,17 @@ export class LocalClaudeGatewayProvider {
919
825
  return { state: "failed", safeErrorCode: "CLAUDE_ROUTE_UNAVAILABLE" };
920
826
  }
921
827
  if (input.authorization === "native_reply") {
922
- try {
923
- await this.refreshClaudeDiscovery();
924
- }
925
- catch {
926
- return { state: "failed", safeErrorCode: "CLAUDE_ROUTE_UNAVAILABLE" };
927
- }
928
828
  const observedRoute = this.nativeInbound.get(input.binding.routeHandle);
929
- const current = this.discovered.get(input.binding.routeHandle);
930
829
  if (observedRoute === undefined ||
931
- observedRoute.listenerGeneration !== activeListener.generation ||
932
- current?.alias !== observedRoute.alias) {
830
+ observedRoute.listenerGeneration !== activeListener.generation) {
933
831
  this.nativeInbound.delete(input.binding.routeHandle);
934
832
  return { state: "failed", safeErrorCode: "CLAUDE_NATIVE_REPLY_STALE" };
935
833
  }
936
- if (observedRoute.alias !== input.targetAlias) {
937
- return { state: "failed", safeErrorCode: "CLAUDE_ROUTE_UNAVAILABLE" };
938
- }
939
834
  }
940
835
  else {
941
836
  const selectedAlias = this.selected.get(input.binding.routeHandle);
942
837
  const stateRoot = this.selectedStateRoots.get(input.binding.routeHandle);
943
838
  if (selectedAlias === undefined ||
944
- selectedAlias !== input.targetAlias ||
945
839
  stateRoot === undefined) {
946
840
  return { state: "failed", safeErrorCode: "CLAUDE_ROUTE_UNAVAILABLE" };
947
841
  }
@@ -970,6 +864,9 @@ export class LocalClaudeGatewayProvider {
970
864
  targetAlias: input.targetAlias,
971
865
  conversationId: input.conversationId,
972
866
  body: input.text,
867
+ ...(input.progressWatchActive === true
868
+ ? { progressWatchActive: true }
869
+ : {}),
973
870
  });
974
871
  }
975
872
  catch (error) {
@@ -987,8 +884,8 @@ export class LocalClaudeGatewayProvider {
987
884
  }
988
885
  this.selectedDispatchEpoch.set(input.binding.routeHandle, (this.selectedDispatchEpoch.get(input.binding.routeHandle) ?? 0) + 1);
989
886
  // The exact workspace attestation is refreshed before every send. A
990
- // clean failure keeps the route busy until a later authoritative idle
991
- // observation wakes the one bounded retry.
887
+ // clean prewrite failure remains retryable within the message deadline;
888
+ // retry timing does not depend on the model turn's observed state.
992
889
  this.selectedObservationDirty.add(input.binding.routeHandle);
993
890
  this.emitClaudeRouteObservation(input.binding.routeHandle, "busy");
994
891
  try {
@@ -1558,29 +1455,16 @@ export class LocalClaudeGatewayProvider {
1558
1455
  this.discovered.set(peer.targetId, row);
1559
1456
  rows.push(row);
1560
1457
  }
1561
- for (const [routeHandle, route] of this.nativeInbound) {
1562
- const current = this.discovered.get(routeHandle);
1563
- if (current !== undefined) {
1564
- // The stable session UUID owns native reply authority. A rename only
1565
- // updates its current public coordinate.
1566
- this.nativeInbound.set(routeHandle, {
1567
- alias: current.alias,
1568
- listenerGeneration: route.listenerGeneration,
1569
- });
1570
- }
1571
- else if (!discovery.truncated) {
1572
- this.nativeInbound.delete(routeHandle);
1573
- }
1574
- }
1575
1458
  for (const [routeHandle, selectedAlias] of this.selected) {
1576
1459
  const row = this.discovered.get(routeHandle);
1577
1460
  if (row === undefined) {
1578
1461
  this.emitClaudeRouteObservation(routeHandle, "busy", "CLAUDE_PEER_NOT_OBSERVED", true);
1579
1462
  }
1580
1463
  else {
1581
- if (row.alias !== selectedAlias) {
1464
+ if (!discovery.truncated && row.alias !== selectedAlias) {
1582
1465
  // A Claude rename changes only the live name index. The native
1583
- // session UUID remains the selected logical route.
1466
+ // session UUID remains the selected logical route. An incomplete
1467
+ // scan is display evidence only and cannot rename dispatch authority.
1584
1468
  this.selected.set(routeHandle, row.alias);
1585
1469
  }
1586
1470
  if (row.state === "idle" &&
@@ -1665,7 +1549,8 @@ function validateCodexFactory(factory) {
1665
1549
  if (factory.hostId !== LOCAL_HOST ||
1666
1550
  factory.protocol !== "codex-app-server" ||
1667
1551
  factory.protocolVersion !== factory.appServerVersion ||
1668
- (!certified && !schemaCandidate) ||
1552
+ (!certified &&
1553
+ (!schemaCandidate || write !== null || factory.writableReady)) ||
1669
1554
  schema.appServerVersion !== factory.appServerVersion ||
1670
1555
  schema.endpointGeneration !== factory.endpointGeneration ||
1671
1556
  schema.protocol !== "app-server-v2-stable" ||
@@ -1714,7 +1599,6 @@ function codexRouteSafeCode(observation) {
1714
1599
  export class LocalCodexGatewayProvider {
1715
1600
  factory;
1716
1601
  refreshFactory;
1717
- compatibilityPolicy;
1718
1602
  maxCallbacks;
1719
1603
  maxRoutes;
1720
1604
  maxReplyBytes;
@@ -1735,8 +1619,6 @@ export class LocalCodexGatewayProvider {
1735
1619
  trackedRoutes = new Set();
1736
1620
  retiredEndpointGeneration;
1737
1621
  expectsReply = new Map();
1738
- compatibilityCertifyingRoutes = new Set();
1739
- compatibilityTurns = new Map();
1740
1622
  callbackQueue = [];
1741
1623
  callbackScheduled = false;
1742
1624
  callbacks;
@@ -1756,8 +1638,6 @@ export class LocalCodexGatewayProvider {
1756
1638
  validateCodexFactory(options.factory);
1757
1639
  this.factory = options.factory;
1758
1640
  this.refreshFactory = options.refreshFactory;
1759
- this.compatibilityPolicy =
1760
- options.compatibilityPolicy ?? options.factory.compatibilityPolicy;
1761
1641
  exactLocalHost(options.factory.hostId);
1762
1642
  this.compatibilityAttested = CODEX_APP_SERVER_WRITABLE_VERSIONS.includes(options.factory.appServerVersion);
1763
1643
  this.maxCallbacks = positiveBounded(options.maxCallbackEvents, MAX_CODEX_CALLBACKS, 4_096);
@@ -1795,7 +1675,8 @@ export class LocalCodexGatewayProvider {
1795
1675
  const pending = this.pendingEndpointAttestation;
1796
1676
  if (attestation.surface !== "codex" ||
1797
1677
  attestation.version !== this.factory.appServerVersion ||
1798
- attestation.tier === "incompatible" ||
1678
+ attestation.tier !== "certified" ||
1679
+ !CODEX_APP_SERVER_WRITABLE_VERSIONS.includes(attestation.version) ||
1799
1680
  (this.endpointUnavailable && pending === undefined) ||
1800
1681
  (pending !== undefined &&
1801
1682
  (attestation.checkedAt !== pending.checkedAt ||
@@ -1885,107 +1766,6 @@ export class LocalCodexGatewayProvider {
1885
1766
  }
1886
1767
  }
1887
1768
  }
1888
- async runCompatibilityCertification(input) {
1889
- void input.controllerStateRoot;
1890
- const certifiedAt = this.now().toISOString();
1891
- const depth = input.withTurn ? "turn" : "thread_ops";
1892
- const routeHandle = input.routeHandle;
1893
- if (routeHandle === undefined || this.compatibilityCertifyingRoutes.has(routeHandle)) {
1894
- return {
1895
- depth,
1896
- outcome: "fail",
1897
- certifiedAt,
1898
- safeErrorCode: "CODEX_CERTIFICATION_ROUTE_REQUIRED",
1899
- };
1900
- }
1901
- this.assertReady();
1902
- const route = this.routes.get(routeHandle);
1903
- if (route === undefined || !this.observeRouteSuccessionBarrier(routeHandle).clean) {
1904
- return {
1905
- depth,
1906
- outcome: "fail",
1907
- certifiedAt,
1908
- safeErrorCode: "CODEX_CERTIFICATION_ROUTE_BUSY",
1909
- };
1910
- }
1911
- this.compatibilityCertifyingRoutes.add(routeHandle);
1912
- try {
1913
- const loaded = await route.connector.observeLoadedThread(route.connector.guard());
1914
- if (!loaded.selectedThreadLoaded) {
1915
- return {
1916
- depth,
1917
- outcome: "fail",
1918
- certifiedAt: this.now().toISOString(),
1919
- safeErrorCode: "CODEX_CERTIFICATION_THREAD_UNAVAILABLE",
1920
- };
1921
- }
1922
- await route.connector.certifyThreadOperations(route.connector.guard());
1923
- if (!input.withTurn) {
1924
- return {
1925
- depth,
1926
- outcome: "pass",
1927
- certifiedAt: this.now().toISOString(),
1928
- };
1929
- }
1930
- const messageId = `compat_${randomBytes(12).toString("hex")}`;
1931
- const result = new Promise((resolve) => {
1932
- const timer = setTimeout(() => {
1933
- this.compatibilityTurns.delete(messageId);
1934
- resolve({
1935
- messageId,
1936
- outcome: "expired",
1937
- replyCode: "REPLY_UNAVAILABLE",
1938
- text: null,
1939
- });
1940
- }, COMPATIBILITY_TURN_TIMEOUT_MS);
1941
- timer.unref();
1942
- this.compatibilityTurns.set(messageId, { resolve, timer });
1943
- });
1944
- try {
1945
- const disposition = await route.connector.submitMessage(route.connector.guard(), {
1946
- deadlineAt: new Date(this.now().getTime() + COMPATIBILITY_TURN_TIMEOUT_MS).toISOString(),
1947
- messageId,
1948
- text: "reply OK",
1949
- });
1950
- if (disposition.disposition !== "started") {
1951
- throw new BridgeError("CODEX_CERTIFICATION_TURN_NOT_STARTED", "The bounded certification turn did not start on the exact idle route.");
1952
- }
1953
- const settled = await result;
1954
- if (settled.outcome !== "completed" ||
1955
- settled.text?.trim() !== "OK") {
1956
- return {
1957
- depth,
1958
- outcome: "fail",
1959
- certifiedAt: this.now().toISOString(),
1960
- safeErrorCode: "CODEX_CERTIFICATION_TURN_FAILED",
1961
- };
1962
- }
1963
- return {
1964
- depth,
1965
- outcome: "pass",
1966
- certifiedAt: this.now().toISOString(),
1967
- };
1968
- }
1969
- finally {
1970
- const pending = this.compatibilityTurns.get(messageId);
1971
- if (pending !== undefined) {
1972
- clearTimeout(pending.timer);
1973
- this.compatibilityTurns.delete(messageId);
1974
- }
1975
- }
1976
- }
1977
- catch {
1978
- return {
1979
- depth,
1980
- outcome: "fail",
1981
- certifiedAt: this.now().toISOString(),
1982
- safeErrorCode: "CODEX_CERTIFICATION_FAILED",
1983
- };
1984
- }
1985
- finally {
1986
- this.compatibilityCertifyingRoutes.delete(routeHandle);
1987
- }
1988
- }
1989
1769
  async initialize(callbacks) {
1990
1770
  if (this.closed || this.initialized) {
1991
1771
  throw new BridgeError("CODEX_PROVIDER_INITIALIZATION_REJECTED", "The local Codex provider cannot be initialized in this state.");
@@ -2172,9 +1952,6 @@ export class LocalCodexGatewayProvider {
2172
1952
  route.endpointGeneration !== this.factory.endpointGeneration) {
2173
1953
  return { state: "failed", safeErrorCode: "CODEX_ROUTE_UNAVAILABLE" };
2174
1954
  }
2175
- if (this.compatibilityCertifyingRoutes.has(input.binding.routeHandle)) {
2176
- return { state: "deferred", safeErrorCode: "CODEX_ROUTE_HELD" };
2177
- }
2178
1955
  if (!this.factory.writableReady ||
2179
1956
  this.factory.writeCompatibility === null) {
2180
1957
  return { state: "failed", safeErrorCode: "CODEX_WRITES_DISABLED" };
@@ -2197,6 +1974,9 @@ export class LocalCodexGatewayProvider {
2197
1974
  targetAlias: input.targetAlias,
2198
1975
  conversationId: input.conversationId,
2199
1976
  body: input.text,
1977
+ ...(input.progressWatchActive === true
1978
+ ? { progressWatchActive: true }
1979
+ : {}),
2200
1980
  });
2201
1981
  }
2202
1982
  catch (error) {
@@ -2321,17 +2101,6 @@ export class LocalCodexGatewayProvider {
2321
2101
  this.closed = true;
2322
2102
  this.closing = false;
2323
2103
  this.callbackQueue.length = 0;
2324
- for (const [messageId, pending] of this.compatibilityTurns) {
2325
- clearTimeout(pending.timer);
2326
- pending.resolve({
2327
- messageId,
2328
- outcome: "abandoned",
2329
- replyCode: "REPLY_UNAVAILABLE",
2330
- text: null,
2331
- });
2332
- }
2333
- this.compatibilityTurns.clear();
2334
- this.compatibilityCertifyingRoutes.clear();
2335
2104
  this.pendingEndpointAttestation = undefined;
2336
2105
  this.pendingEndpointRefreshEvent = undefined;
2337
2106
  this.trackedRoutes.clear();
@@ -2723,8 +2492,7 @@ export class LocalCodexGatewayProvider {
2723
2492
  candidate = await refreshFactory();
2724
2493
  validateCodexFactory(candidate);
2725
2494
  if (candidate.hostId !== previous.hostId ||
2726
- candidate.protocol !== previousFactory.protocol ||
2727
- candidate.compatibilityPolicy !== this.compatibilityPolicy) {
2495
+ candidate.protocol !== previousFactory.protocol) {
2728
2496
  throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "The replacement Codex factory moved outside its pinned boundary.");
2729
2497
  }
2730
2498
  if (candidate === previousFactory ||
@@ -2744,7 +2512,6 @@ export class LocalCodexGatewayProvider {
2744
2512
  surface: "codex",
2745
2513
  version: candidate.appServerVersion,
2746
2514
  checkedAt: this.now().toISOString(),
2747
- policy: this.compatibilityPolicy,
2748
2515
  certifiedVersions: certifiedCompatibilityVersions.codex,
2749
2516
  probes,
2750
2517
  });
@@ -2881,13 +2648,6 @@ export class LocalCodexGatewayProvider {
2881
2648
  invokeCallback(() => callbacks.onEndpointRefresh?.(event));
2882
2649
  }
2883
2650
  onTurnResult(endpointGeneration, result) {
2884
- const certification = this.compatibilityTurns.get(result.messageId);
2885
- if (certification !== undefined) {
2886
- clearTimeout(certification.timer);
2887
- this.compatibilityTurns.delete(result.messageId);
2888
- certification.resolve(result);
2889
- return;
2890
- }
2891
2651
  const wantsReply = this.expectsReply.get(result.messageId) === true;
2892
2652
  this.expectsReply.delete(result.messageId);
2893
2653
  let replyText;