@openclaw/codex 2026.9.5 → 2026.9.7

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 (174) hide show
  1. package/README.md +2 -0
  2. package/assets/icon.png +0 -0
  3. package/dist/.setup/{account-usage-runtime-C2MOIvfq.mjs → account-usage-runtime-DFhbh1zz.mjs} +6 -6
  4. package/dist/.setup/{apply-CJ0ZfmBG.mjs → apply-D3GcSoSa.mjs} +35 -55
  5. package/dist/.setup/{attempt-client-cleanup-BpYKdTA0.mjs → attempt-client-cleanup-DOP-cW5j.mjs} +179 -73
  6. package/dist/.setup/attempt-workspace-context-C5HigshI.mjs +164 -0
  7. package/dist/.setup/{auth-binding-DhLWa_7K.mjs → auth-binding-BLWz7stm.mjs} +14 -1
  8. package/dist/.setup/{auth-cache-key-QirmgiCo.mjs → auth-cache-key-Dbvq-QgB.mjs} +41 -111
  9. package/dist/.setup/{auth-profile-WqZtZfXN.mjs → auth-profile-B0okYl2D.mjs} +1 -2
  10. package/dist/.setup/auth-profile-health-oHizqgye.mjs +53 -0
  11. package/dist/.setup/auth-profile-recovery-BREezV0L.mjs +14 -0
  12. package/dist/.setup/auth-start-options-BPIPeEX8.mjs +44 -0
  13. package/dist/.setup/{binding-connection-Bm38niE8.mjs → binding-connection-DTtN1KrX.mjs} +2 -2
  14. package/dist/.setup/{binding-connection.runtime-CnRMC0ta.mjs → binding-connection.runtime-6TpgD1M6.mjs} +5 -5
  15. package/dist/.setup/{bounded-turn-BtlZcivC.mjs → bounded-turn-CbjoN2OW.mjs} +140 -37
  16. package/dist/.setup/bounded-turn-isolation-B8K_ylqk.mjs +14 -0
  17. package/dist/.setup/{build-state-Xx9ybZqa.mjs → build-state-Da1_z0kd.mjs} +1 -1
  18. package/dist/.setup/{capabilities-_vXcZGSx.mjs → capabilities-B3WEZl4e.mjs} +2 -10
  19. package/dist/.setup/{client-vXs2929Q.mjs → client-N0JpgSzF.mjs} +635 -872
  20. package/dist/.setup/client-catalog-response-5HHLdcde.mjs +285 -0
  21. package/dist/.setup/{command-dispatch-naHIZwwF.mjs → command-dispatch-BeAoaovI.mjs} +9 -8
  22. package/dist/.setup/{command-formatters-CGEkdawF.mjs → command-formatters-R3ckE3Co.mjs} +36 -64
  23. package/dist/.setup/{command-handlers-BtAJEW1X.mjs → command-handlers-ylTMS00z.mjs} +301 -488
  24. package/dist/.setup/{command-rpc-DHFpn4le.mjs → command-rpc-CGJGUQ6Y.mjs} +40 -28
  25. package/dist/.setup/compact-C2WamavS.mjs +776 -0
  26. package/dist/.setup/{config-CedDWjM-.mjs → config-DKhXquav.mjs} +26 -28
  27. package/dist/.setup/{config-options-BsanJ8QG.mjs → config-options-CzyWLTJt.mjs} +68 -65
  28. package/dist/.setup/{config-parsing-CcB9iPoq.mjs → config-parsing-b088LyhT.mjs} +57 -60
  29. package/dist/.setup/{config-runtime-CeAhl_h4.mjs → config-runtime-C0NbLms1.mjs} +2 -2
  30. package/dist/.setup/{config-security-BRQ2mgW9.mjs → config-security-CE-FcGw9.mjs} +51 -215
  31. package/dist/.setup/{config-utils-DujwEnhg.mjs → config-utils-D0CXecki.mjs} +3 -13
  32. package/dist/.setup/context-engine-projection-PezSESth.mjs +387 -0
  33. package/dist/.setup/{conversation-binding-DhzrpTM6.mjs → conversation-binding-3Min8qvP.mjs} +71 -105
  34. package/dist/.setup/{conversation-binding-data-CrcyZk6O.mjs → conversation-binding-data-C746z5Pn.mjs} +8 -12
  35. package/dist/.setup/{conversation-control-DN53ns41.mjs → conversation-control-CEP8X5JC.mjs} +30 -69
  36. package/dist/.setup/{cyber-failover-DYwbmf1o.mjs → cyber-failover-XV0nNRZu.mjs} +1 -1
  37. package/dist/.setup/{cyber-failover-notice-e9G3J9-e.mjs → cyber-failover-notice-RNpGpTyP.mjs} +1 -1
  38. package/dist/.setup/{dynamic-tools-D16lOp67.mjs → dynamic-tools-DzlsLUuS.mjs} +3136 -3167
  39. package/dist/.setup/{effective-mcp-catalog-K6kLCN8X.mjs → effective-mcp-catalog-CxUtC-xG.mjs} +8 -17
  40. package/dist/.setup/{ephemeral-turn-R1gA8Sn6.mjs → ephemeral-turn-CDsPJOa2.mjs} +9 -6
  41. package/dist/.setup/event-projector-assistant-message-CigreO4K.mjs +69 -0
  42. package/dist/.setup/{event-projector-usage-C7Ntzs-f.mjs → event-projector-usage-03R0I2dM.mjs} +4 -26
  43. package/dist/.setup/event-projector-values-DJSz8BTk.mjs +106 -0
  44. package/dist/.setup/incognito-session-DWYapfwf.mjs +2 -0
  45. package/dist/.setup/{inference-context-fulhZuz8.mjs → inference-context-D-9gWlTR.mjs} +16 -18
  46. package/dist/.setup/inference-dispatch-CMZtjQyz.mjs +359 -0
  47. package/dist/.setup/inference-metadata-CgIf7sOx.mjs +81 -0
  48. package/dist/.setup/inference-proxy-DhcXOgUE.mjs +561 -0
  49. package/dist/.setup/{isolated-completion-B6srt48J.mjs → isolated-completion-Dm3PzxJk.mjs} +15 -11
  50. package/dist/.setup/launch-args-DbFCehO7.mjs +196 -0
  51. package/dist/.setup/{managed-binary-DP6Rib3P.mjs → managed-binary-kiWRhNRE.mjs} +16 -9
  52. package/dist/.setup/{model-catalog-DkvUuBey.mjs → model-catalog-PAuZgJC6.mjs} +14 -14
  53. package/dist/.setup/model-runtime-BdqzOMkU.mjs +11 -0
  54. package/dist/.setup/{models-BDFgm_G-.mjs → models-DHXZtVVk.mjs} +9 -18
  55. package/dist/.setup/{native-auth-BLZGqFjw.mjs → native-auth-CuG53tu4.mjs} +5 -5
  56. package/dist/.setup/{native-execution-policy-YBMHSzC4.mjs → native-execution-policy-BxZJy5mP.mjs} +6 -31
  57. package/dist/.setup/{native-subagent-monitor-B1hxzIOy.mjs → native-subagent-monitor-Dpsmf2wz.mjs} +4422 -3808
  58. package/dist/.setup/native-subagent-pending-assignments-DwkCzLvD.mjs +203 -0
  59. package/dist/.setup/native-task-assignments-DMQ0g3hu.mjs +194 -0
  60. package/dist/.setup/{node-cli-sessions-Cl8b2ZF3.mjs → node-cli-sessions-HC4W6FLI.mjs} +99 -111
  61. package/dist/.setup/node-exec-server.runtime-BgBfWQqo.mjs +244 -0
  62. package/dist/.setup/{plan-xD7WKYTM.mjs → plan-Y-QIvrKB.mjs} +118 -163
  63. package/dist/.setup/{plugin-activation-r8nq5Jzp.mjs → plugin-activation-cNHRfaxU.mjs} +10 -47
  64. package/dist/.setup/{plugin-app-cache-key-BOxKP7db.mjs → plugin-app-cache-key-BL9B5H0L.mjs} +9 -42
  65. package/dist/.setup/{plugin-inventory-DUle8DLz.mjs → plugin-inventory-Cky2XJUw.mjs} +32 -23
  66. package/dist/.setup/{plugin-marketplace-discovery-P-Vndfqq.mjs → plugin-marketplace-discovery-D_dV9FXa.mjs} +22 -25
  67. package/dist/.setup/{plugin-metadata-cache-DsS5buNa.mjs → plugin-metadata-cache-DsjsL1dr.mjs} +328 -318
  68. package/dist/.setup/protocol-CANUwXJ3.mjs +17 -0
  69. package/dist/.setup/provider-DH8NSzGt.mjs +51 -0
  70. package/dist/.setup/{provider-capabilities-B8J4Dy-O.mjs → provider-capabilities-CAxoF-X1.mjs} +35 -12
  71. package/dist/.setup/{rate-limits-DOEGYRNs.mjs → rate-limits-B7-X2TgG.mjs} +123 -166
  72. package/dist/.setup/{request-BioXJLYa.mjs → request-BHZ1nz8d.mjs} +25 -16
  73. package/dist/.setup/responses-oauth-twnuTaAa.mjs +93 -0
  74. package/dist/.setup/rpc-error-BlD2vuzn.mjs +31 -0
  75. package/dist/.setup/{run-attempt-rlA07pUv.mjs → run-attempt-D8RZUOzY.mjs} +2046 -1454
  76. package/dist/.setup/{run-attempt-lifecycle-B7JbY4-F.mjs → run-attempt-lifecycle-C-6O3Exn.mjs} +10 -24
  77. package/dist/.setup/{runtime-artifact-Dy38Z5iU.mjs → runtime-artifact-DDQ-HGXf.mjs} +43 -47
  78. package/dist/.setup/runtime-artifact-connection-D68qQn1m.mjs +78 -0
  79. package/dist/.setup/sandbox-guard-DjCz2eOw.mjs +126 -0
  80. package/dist/.setup/scope-DOC1Xjc8.mjs +6 -0
  81. package/dist/.setup/session-binding-DGCYAfvD.mjs +443 -0
  82. package/dist/.setup/{session-binding-record-TH3xA0zj.mjs → session-binding-record-Oe9L-CNY.mjs} +73 -132
  83. package/dist/.setup/{session-binding-sidecars-CKYEcfNn.mjs → session-binding-sidecars-jo6H8dFr.mjs} +242 -60
  84. package/dist/.setup/{session-catalog-fUdWDx-U.mjs → session-catalog-4sCdv5qx.mjs} +598 -452
  85. package/dist/.setup/{session-catalog-adoption-CR_whkEW.mjs → session-catalog-adoption-BU_pHWG7.mjs} +59 -26
  86. package/dist/.setup/{session-catalog-archive-CwZaPacf.mjs → session-catalog-archive-spHfihri.mjs} +7 -7
  87. package/dist/.setup/session-catalog-events-DePDzzjc.mjs +139 -0
  88. package/dist/.setup/session-catalog-home-id-vlih0B_g.mjs +22 -0
  89. package/dist/.setup/{session-catalog-index-B141u15s.mjs → session-catalog-index-CZvDzC6z.mjs} +286 -182
  90. package/dist/.setup/{session-catalog-index-order-Cc5BzlQr.mjs → session-catalog-index-order-BcQpHks3.mjs} +2 -2
  91. package/dist/.setup/{session-catalog-index-state-BAuDztHN.mjs → session-catalog-index-state-TeO7EyO-.mjs} +6 -2
  92. package/dist/.setup/session-catalog-limits-DDxOsQeC.mjs +14 -0
  93. package/dist/.setup/session-catalog-list-request-CvtxrYSe.mjs +170 -0
  94. package/dist/.setup/session-catalog-native-projection-DjhwGL6x.mjs +178 -0
  95. package/dist/.setup/{session-catalog-node-adoption-BVRsYOSh.mjs → session-catalog-node-adoption-DgXvSGu0.mjs} +30 -35
  96. package/dist/.setup/{session-catalog-node-continue-Dowv8osw.mjs → session-catalog-node-continue-DjKXHBbi.mjs} +25 -18
  97. package/dist/.setup/session-catalog-node-lookup-CtAXI5W5.mjs +56 -0
  98. package/dist/.setup/{session-catalog-native-projection-ChV3cCtm.mjs → session-catalog-parsing-CPGaPYr-.mjs} +14 -180
  99. package/dist/.setup/{session-catalog-projection-C1Bj9Jl-.mjs → session-catalog-projection-Cr5qP5Dj.mjs} +15 -5
  100. package/dist/.setup/session-catalog-provenance-DoAvktcj.mjs +95 -0
  101. package/dist/.setup/{session-cli-DIj-IE-E.mjs → session-cli-Cn_nCqfq.mjs} +11 -24
  102. package/dist/.setup/{session-history-C--SrLI8.mjs → session-history-D83lJWHG.mjs} +16 -23
  103. package/dist/.setup/{session-history-import-JHXT5Xfi.mjs → session-history-import-WhX-X33a.mjs} +7 -10
  104. package/dist/.setup/session-history-read-Ov3StuL4.mjs +133 -0
  105. package/dist/.setup/{session-history.worker-CpNj7H_P.mjs → session-history.worker-MnPKncqP.mjs} +14 -23
  106. package/dist/.setup/session-initialization-6aveB9qb.mjs +22 -0
  107. package/dist/.setup/{session-permission-policy-DhurXY0l.mjs → session-permission-policy-Ci_fVX6y.mjs} +4 -8
  108. package/dist/.setup/{session-retirement-CU87AOg9.mjs → session-retirement-qMTxkNx2.mjs} +31 -12
  109. package/dist/.setup/{settled-turn-context-fmwouT5I.mjs → settled-turn-context-D4yj4rxf.mjs} +1 -1
  110. package/dist/.setup/{settled-turn-finalizer-CiY2bLFK.mjs → settled-turn-finalizer-BsvEabkw.mjs} +17 -13
  111. package/dist/.setup/{shared-client-BpTtuLQ5.mjs → shared-client-DqyTMYug.mjs} +826 -485
  112. package/dist/.setup/shared-client-lifecycle-DJIgqgMw.mjs +153 -0
  113. package/dist/.setup/{side-question-DSCZyoBD.mjs → side-question-C4kCmQy1.mjs} +206 -334
  114. package/dist/.setup/{source-Bjp4UQij.mjs → source-CS_7GFJZ.mjs} +82 -139
  115. package/dist/.setup/spawn-error-CL3n6MAa.mjs +57 -0
  116. package/dist/.setup/{thread-archive-guard-jmecf6OJ.mjs → thread-archive-guard-C9frICzX.mjs} +10 -3
  117. package/dist/.setup/thread-lifecycle-DPflntEJ.mjs +2362 -0
  118. package/dist/.setup/{incognito-session-uhrBF6wJ.mjs → thread-ownership-queue-Dp24d7-F.mjs} +1 -2
  119. package/dist/.setup/{thread-ownership-skomxnIt.mjs → thread-ownership-roNP0l1c.mjs} +47 -10
  120. package/dist/.setup/thread-policy-DTd-DtkX.mjs +109 -0
  121. package/dist/.setup/thread-requests-B_bRnMGN.mjs +2102 -0
  122. package/dist/.setup/{thread-resume-BkNpj9Pz.mjs → thread-resume-CdDaoc7T.mjs} +6 -6
  123. package/dist/.setup/timeout-CXOfNoaX.mjs +46 -0
  124. package/dist/.setup/transcript-history-projection-DRSifI-1.mjs +201 -0
  125. package/dist/.setup/{transcript-mirror-attestation-CzM-94NC.mjs → transcript-mirror-attestation-YSegaktH.mjs} +3 -4
  126. package/dist/.setup/{transcript-mirror-D4qp_leP.mjs → transcript-mirror-kxmCYsuF.mjs} +224 -206
  127. package/dist/.setup/{transport-stdio-Cmx94Oiy.mjs → transport-stdio-Bdegpn2V.mjs} +138 -75
  128. package/dist/.setup/transport-websocket-BTBE-LD9.mjs +211 -0
  129. package/dist/.setup/{upstream-prompt-provenance-LphB8slG.mjs → upstream-prompt-provenance-fXkKbPVC.mjs} +3 -9
  130. package/dist/.setup/{upstream-session-fork-D3UKxgVD.mjs → upstream-session-fork-CBeVjBpT.mjs} +48 -40
  131. package/dist/.setup/{usage-BOgBEKso.mjs → usage-BMzNxeR_.mjs} +5 -4
  132. package/dist/.setup/{usage-limit-error-C0ow7DOc.mjs → usage-limit-error-QXerDo3i.mjs} +5 -20
  133. package/dist/.setup/{web-search-provider.runtime-CTGuJt6i.mjs → web-search-provider.runtime-P77OUeoo.mjs} +10 -20
  134. package/dist/api.js +25 -16
  135. package/dist/catalog-page-worker-entrypoint.js +12 -0
  136. package/dist/catalog-page.worker.js +9 -0
  137. package/dist/cli-metadata.js +1 -1
  138. package/dist/doctor-contract-api.js +50 -8
  139. package/dist/harness.js +344 -1
  140. package/dist/index.js +345 -346
  141. package/dist/media-understanding-provider.js +9 -22
  142. package/dist/migration-provider-api.js +1 -1
  143. package/dist/provider-discovery.js +1 -1
  144. package/dist/session-history-worker-runtime.js +16 -33
  145. package/dist/session-history.worker.js +1 -1
  146. package/openclaw.plugin.json +14 -2
  147. package/package.json +11 -7
  148. package/dist/.setup/attempt-context-VXVwTCfS.mjs +0 -636
  149. package/dist/.setup/compact-C3i3qlzj.mjs +0 -687
  150. package/dist/.setup/event-projector-assistant-message-DNUR1s0A.mjs +0 -105
  151. package/dist/.setup/event-projector-items-DyTQ_XqL.mjs +0 -200
  152. package/dist/.setup/harness-rxaaoN-o.mjs +0 -349
  153. package/dist/.setup/history-rejection-B4nOXNXF.mjs +0 -13
  154. package/dist/.setup/image-payload-sanitizer-tupAr-2o.mjs +0 -79
  155. package/dist/.setup/inference-proxy-CC15HuSi.mjs +0 -311
  156. package/dist/.setup/launch-args-DnMak49W.mjs +0 -111
  157. package/dist/.setup/local-runtime-attribution-B_2mnqhb.mjs +0 -19
  158. package/dist/.setup/native-subagent-history-YXaL6dMd.mjs +0 -135
  159. package/dist/.setup/native-subagent-task-ids-DsuOonKv.mjs +0 -411
  160. package/dist/.setup/node-exec-server.runtime-BaViBKNz.mjs +0 -226
  161. package/dist/.setup/plugin-approval-roundtrip-CjfzafAZ.mjs +0 -122
  162. package/dist/.setup/provider-fFh_-VR3.mjs +0 -50
  163. package/dist/.setup/rolldown-runtime-8H4AJuhK.mjs +0 -14
  164. package/dist/.setup/sandbox-guard-BBP-RbTf.mjs +0 -166
  165. package/dist/.setup/session-binding-_0W_fHRr.mjs +0 -721
  166. package/dist/.setup/session-catalog-events-jMcYfQyd.mjs +0 -250
  167. package/dist/.setup/session-history-read-B3ZfSUbF.mjs +0 -50
  168. package/dist/.setup/session-initialization-DH1z6fXn.mjs +0 -75
  169. package/dist/.setup/thread-history-page-BTx-4xsg.mjs +0 -83
  170. package/dist/.setup/thread-lifecycle-Cik28qWn.mjs +0 -4904
  171. package/dist/.setup/thread-policy-Cjs4B8xf.mjs +0 -54
  172. package/dist/.setup/timeout-DZF05XrR.mjs +0 -63
  173. package/dist/.setup/transcript-history-projection-DHNBDhCU.mjs +0 -243
  174. package/dist/.setup/version-CoqzXPgK.mjs +0 -12
@@ -1,38 +1,105 @@
1
- import { C as codexCatalogThreadName, D as normalizeLimit, M as readControlCursor, T as filterCatalogPageByTitle, V as CODEX_CATALOG_MAX_ROWS, c as getCodexCatalogSource, g as CatalogParamsError, r as projectCodexCatalogNativeThread, u as setCodexCatalogSource, v as MAX_CWD_LENGTH, w as codexCatalogThreadStatus, x as boundedCatalogString } from "./session-catalog-native-projection-ChV3cCtm.mjs";
2
- import { i as retainCodexCatalogRow, n as codexCatalogRowRecency, r as compareCodexCatalogRows, t as CodexCatalogOrdering } from "./session-catalog-index-order-Cc5BzlQr.mjs";
3
- import { n as CodexCatalogPersistence, r as codexCatalogMetadataPage } from "./session-catalog-index-state-BAuDztHN.mjs";
4
- import { a as withCodexCatalogListRequest, s as CodexCatalogAvailability } from "./session-catalog-fUdWDx-U.mjs";
5
- import { i as subscribeCodexCatalogEvents } from "./session-catalog-events-jMcYfQyd.mjs";
6
- import { CodexCatalogProjectionCapacityError, CodexCatalogProjections, i as scanCodexCatalogRollouts, mergeCodexCatalogRolloutRow, n as isCodexCatalogRolloutPathCovered, projectCodexCatalogThread, r as readCodexCatalogRollout, t as codexCatalogRolloutLogicalPath } from "./session-catalog-projection-C1Bj9Jl-.mjs";
1
+ import { S as readControlCursor, _ as normalizeLimit, c as MAX_CWD_LENGTH, d as boundedCatalogString, h as filterCatalogPageByTitle, m as codexCatalogThreadStatus, o as CatalogParamsError, p as codexCatalogThreadName } from "./session-catalog-parsing-CPGaPYr-.mjs";
2
+ import { t as CODEX_CATALOG_MAX_ROWS } from "./session-catalog-limits-DDxOsQeC.mjs";
3
+ import { i as retainCodexCatalogRow, n as codexCatalogRowRecency, r as compareCodexCatalogRows, t as CodexCatalogOrdering } from "./session-catalog-index-order-BcQpHks3.mjs";
4
+ import { n as CodexCatalogPersistence, r as codexCatalogMetadataPage } from "./session-catalog-index-state-TeO7EyO-.mjs";
5
+ import { i as CodexCatalogAvailability, r as withCodexCatalogListRequest } from "./session-catalog-list-request-CvtxrYSe.mjs";
6
+ import { a as reportCodexCatalogSpawnFailure, n as findCodexAppServerSpawnError } from "./spawn-error-CL3n6MAa.mjs";
7
+ import { l as getCodexCatalogSource, p as setCodexCatalogSource, r as projectCodexCatalogNativeThread, u as hasLiveCodexCatalogSource } from "./session-catalog-native-projection-DjhwGL6x.mjs";
8
+ import { i as subscribeCodexCatalogEvents } from "./session-catalog-events-DePDzzjc.mjs";
9
+ import { CodexCatalogProjectionCapacityError, CodexCatalogProjections, a as resolveCodexCatalogRolloutFingerprint, i as readCodexCatalogRollout, mergeCodexCatalogRolloutRow, n as indexCodexCatalogRowsByRollout, o as scanCodexCatalogRollouts, projectCodexCatalogThread, r as isCodexCatalogRolloutPathCovered, t as codexCatalogRolloutLogicalPath } from "./session-catalog-projection-Cr5qP5Dj.mjs";
7
10
  import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
8
11
  import { createHash } from "node:crypto";
9
12
  import { isDeepStrictEqual } from "node:util";
10
13
  import { embeddedAgentLog } from "openclaw/plugin-sdk/agent-harness-registration";
14
+ import { coerceErrorMessage, toErrorObject } from "openclaw/plugin-sdk/error-runtime";
11
15
  import { setImmediate as setImmediate$1 } from "node:timers/promises";
12
- import { toErrorObject } from "openclaw/plugin-sdk/error-runtime";
13
16
  import { sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
14
17
  //#region extensions/codex/src/session-catalog-currency.ts
18
+ const SAFETY_INTERVAL_MS = 9e5;
15
19
  /** One periodic reconciliation cycle per home, without a recursive watcher inventory. */
16
20
  var CodexCatalogCurrency = class {
17
21
  constructor(options) {
18
22
  this.options = options;
19
23
  this.closed = false;
24
+ this.nativeDirty = false;
25
+ this.nextNativeAt = 0;
26
+ this.nextFilesAt = 0;
27
+ }
28
+ hasActiveWork() {
29
+ return this.hydration !== void 0 || this.initial !== void 0 || this.running !== void 0 || this.safetyRefresh !== void 0;
30
+ }
31
+ assertRunnable() {
32
+ if (this.terminalFailure) throw this.terminalFailure;
33
+ }
34
+ stopForTerminalFailure(error) {
35
+ const failure = findCodexAppServerSpawnError(error);
36
+ if (!failure) return false;
37
+ if (!this.closed) {
38
+ this.terminalFailure = failure;
39
+ this.close();
40
+ reportCodexCatalogSpawnFailure(failure);
41
+ }
42
+ return true;
43
+ }
44
+ scheduleHydration(run) {
45
+ if (this.closed || this.hydration) return;
46
+ this.hydration = setImmediate(() => {
47
+ this.hydration = void 0;
48
+ (this.options.runBackground ? this.options.runBackground(run) : run()).catch((error) => this.options.report(error));
49
+ });
50
+ this.hydration.unref();
51
+ }
52
+ cancelHydration() {
53
+ clearImmediate(this.hydration);
54
+ this.hydration = void 0;
55
+ }
56
+ requestNativeRefresh() {
57
+ this.nativeDirty = true;
58
+ }
59
+ /** Full safety walks serve catalog demand; an idle resident index does not start one. */
60
+ refreshNativeIfDue() {
61
+ if (this.closed || !this.timer || Date.now() < this.nextNativeAt) return Promise.resolve();
62
+ if (this.safetyRefresh) return this.safetyRefresh;
63
+ const refresh = async () => {
64
+ if (this.running) await this.running;
65
+ if (this.closed || Date.now() < this.nextNativeAt) return;
66
+ const run = () => this.options.reconcileNative(true);
67
+ await Promise.resolve().then(() => this.options.runBackground ? this.options.runBackground(run) : run()).catch((error) => {
68
+ this.options.report(new Error(`Codex catalog reconciliation failed; waiting for the next safety interval and catalog demand: ${coerceErrorMessage(error)}`, { cause: error }));
69
+ });
70
+ this.nextNativeAt = Date.now() + SAFETY_INTERVAL_MS;
71
+ };
72
+ this.safetyRefresh = refresh().finally(() => {
73
+ this.safetyRefresh = void 0;
74
+ });
75
+ return this.safetyRefresh;
20
76
  }
21
77
  start() {
22
78
  if (this.closed || this.timer) return;
79
+ this.nextNativeAt = Date.now() + SAFETY_INTERVAL_MS;
80
+ this.nextFilesAt = this.nextNativeAt;
23
81
  this.timer = setInterval(() => {
24
82
  if (this.running) return;
83
+ const startedAt = Date.now();
84
+ const filesDue = this.options.local && startedAt >= this.nextFilesAt;
85
+ const nativeDue = this.nativeDirty && !this.safetyRefresh;
86
+ if (!filesDue && !nativeDue) return;
87
+ if (nativeDue) this.nativeDirty = false;
88
+ if (filesDue) this.nextFilesAt = startedAt + SAFETY_INTERVAL_MS;
25
89
  const run = async () => {
26
- await this.options.reconcileFiles();
27
- await this.options.reconcileNative();
90
+ if (filesDue) await this.options.reconcileFiles();
91
+ if (nativeDue) await this.options.reconcileNative(false);
28
92
  };
29
- this.running = (this.options.runBackground ? this.options.runBackground(run) : run()).catch((error) => this.options.report(error)).finally(() => {
93
+ this.running = (this.options.runBackground ? this.options.runBackground(run) : run()).catch((error) => {
94
+ this.options.report(new Error(`Codex catalog reconciliation failed; waiting for new activity or the next file safety cycle: ${coerceErrorMessage(error)}`, { cause: error }));
95
+ }).finally(() => {
30
96
  this.running = void 0;
31
97
  });
32
98
  }, 3e4);
33
99
  this.timer.unref();
34
100
  if (this.options.local) {
35
101
  this.initial = setTimeout(() => {
102
+ this.initial = void 0;
36
103
  this.options.reconcileFiles().catch((error) => this.options.report(error));
37
104
  }, 0);
38
105
  this.initial.unref();
@@ -40,8 +107,13 @@ var CodexCatalogCurrency = class {
40
107
  }
41
108
  close() {
42
109
  this.closed = true;
110
+ this.cancelHydration();
43
111
  clearInterval(this.timer);
112
+ this.timer = void 0;
44
113
  clearTimeout(this.initial);
114
+ this.initial = void 0;
115
+ if (this.running && this.safetyRefresh) return Promise.allSettled([this.running, this.safetyRefresh]).then(() => {});
116
+ return this.running ?? this.safetyRefresh;
45
117
  }
46
118
  };
47
119
  //#endregion
@@ -118,6 +190,9 @@ var CodexCatalogIndexEvents = class {
118
190
  this.pending = /* @__PURE__ */ new Map();
119
191
  this.upserting = /* @__PURE__ */ new Set();
120
192
  }
193
+ hasActiveWork() {
194
+ return this.pending.size > 0 || this.upserting.size > 0;
195
+ }
121
196
  handle(event, readThread, source) {
122
197
  if (this.closed || !isRecord(event.params)) return;
123
198
  const params = event.params;
@@ -161,7 +236,7 @@ var CodexCatalogIndexEvents = class {
161
236
  }
162
237
  if (event.method === "turn/started" || event.method === "turn/completed" || event.method === "thread/unarchived" || event.method === "thread/reverted") {
163
238
  if (event.method !== "thread/unarchived" && this.owner.get(id)?.archived) return;
164
- this.enqueueRefresh(id, readThread, event.method === "turn/started" ? this.owner.reserveTurnStartOrder() : void 0);
239
+ this.enqueueRefresh(id, readThread, source, event.method === "turn/started" ? this.owner.reserveTurnStartOrder() : void 0);
165
240
  }
166
241
  }
167
242
  hasCapacity() {
@@ -169,10 +244,12 @@ var CodexCatalogIndexEvents = class {
169
244
  this.owner.report(/* @__PURE__ */ new Error("Codex catalog event queue reached its resident row limit"));
170
245
  return false;
171
246
  }
172
- enqueueRefresh(id, readThread, sourceOrder) {
247
+ enqueueRefresh(id, readThread, source, sourceOrder) {
248
+ this.owner.requestNativeRefresh();
173
249
  const existing = this.pending.get(id);
174
250
  if (existing) {
175
251
  existing.readThread = readThread;
252
+ existing.source = source;
176
253
  existing.dirty = true;
177
254
  existing.sourceOrder = sourceOrder ?? existing.sourceOrder;
178
255
  return;
@@ -180,6 +257,7 @@ var CodexCatalogIndexEvents = class {
180
257
  if (!this.hasCapacity()) return;
181
258
  const pending = {
182
259
  readThread,
260
+ source,
183
261
  dirty: true,
184
262
  sourceOrder,
185
263
  promise: Promise.resolve()
@@ -190,12 +268,17 @@ var CodexCatalogIndexEvents = class {
190
268
  while (!this.closed && pending.dirty) {
191
269
  pending.dirty = false;
192
270
  const observedSourceOrder = pending.sourceOrder;
271
+ const observedSource = pending.source;
193
272
  try {
273
+ if (observedSource.closed) throw new Error("Codex catalog observation source closed before its metadata read");
194
274
  const published = await this.owner.refresh(id, pending.readThread, observedSourceOrder);
195
275
  if (published && pending.sourceOrder === observedSourceOrder) pending.sourceOrder = void 0;
196
276
  else if (!published && pending.sourceOrder !== void 0) pending.dirty = true;
197
277
  } catch (error) {
198
- this.owner.report(error);
278
+ if (observedSource.closed) {
279
+ if (pending.source === observedSource) pending.dirty = false;
280
+ this.owner.report(new Error("Codex catalog observation interrupted by client closure; metadata refresh deferred to the current catalog owner", { cause: error }), "deferred");
281
+ } else this.owner.report(error);
199
282
  }
200
283
  }
201
284
  } finally {
@@ -288,6 +371,9 @@ var CodexCatalogObservations = class {
288
371
  this.mutations = /* @__PURE__ */ new Map();
289
372
  this.observations = /* @__PURE__ */ new Map();
290
373
  }
374
+ hasActiveWork() {
375
+ return this.observations.size > 0;
376
+ }
291
377
  mark(threadId) {
292
378
  this.revision++;
293
379
  if (this.observations.size) {
@@ -319,6 +405,83 @@ var CodexCatalogObservations = class {
319
405
  }
320
406
  };
321
407
  //#endregion
408
+ //#region extensions/codex/src/session-catalog-status.ts
409
+ function applyCodexCatalogLiveFields({ status: _storedStatus, activeFlags: _storedFlags, ...session }, live, settings) {
410
+ return {
411
+ ...session,
412
+ ...settings,
413
+ status: live?.status ?? "notLoaded",
414
+ ...live?.activeFlags ? { activeFlags: [...live.activeFlags] } : {}
415
+ };
416
+ }
417
+ const MAX_STATUS_SOURCE_WITNESSES = 64;
418
+ /** Equivalent broadcasts retain at most 64 source witnesses for each bounded resident row. */
419
+ var CodexCatalogStatusIndex = class {
420
+ constructor() {
421
+ this.values = new CodexCatalogField();
422
+ }
423
+ capture() {
424
+ return this.values.capture();
425
+ }
426
+ update(threadId, status, source) {
427
+ const next = this.next(threadId, status, source);
428
+ if (next) this.values.update(threadId, next);
429
+ }
430
+ observe(row, revision) {
431
+ const session = row.page.sessions[0];
432
+ const source = getCodexCatalogSource(row);
433
+ if (session && source) {
434
+ const next = this.next(row.threadId, {
435
+ status: session.status,
436
+ ...session.activeFlags ? { activeFlags: session.activeFlags } : {}
437
+ }, source);
438
+ if (next) this.values.observe(row.threadId, next, revision);
439
+ }
440
+ }
441
+ get(threadId) {
442
+ const current = this.values.get(threadId);
443
+ return current && hasLiveCodexCatalogSource(current.sources) ? current.status : void 0;
444
+ }
445
+ delete(threadId) {
446
+ this.values.delete(threadId);
447
+ }
448
+ invalidate(source) {
449
+ if (!source) {
450
+ this.values.invalidate();
451
+ return;
452
+ }
453
+ this.values.deleteWhere((entry) => {
454
+ entry.sources.delete(source);
455
+ return !hasLiveCodexCatalogSource(entry.sources);
456
+ });
457
+ }
458
+ next(threadId, status, source) {
459
+ if (source.closed) return;
460
+ const current = this.values.get(threadId);
461
+ const sources = new Set([...current?.sources ?? []].filter((witness) => !witness.closed));
462
+ if (status.status === "notLoaded" && current && current.status.status !== "notLoaded" && sources.size) {
463
+ sources.delete(source);
464
+ if (sources.size) return {
465
+ status: current.status,
466
+ sources
467
+ };
468
+ }
469
+ const flags = status.activeFlags ?? [];
470
+ const previousFlags = current?.status.activeFlags ?? [];
471
+ if (current?.status.status === status.status && flags.length === previousFlags.length && flags.every((flag, index) => flag === previousFlags[index])) {
472
+ if (sources.size < MAX_STATUS_SOURCE_WITNESSES) sources.add(source);
473
+ return {
474
+ status,
475
+ sources
476
+ };
477
+ }
478
+ return {
479
+ status,
480
+ sources: /* @__PURE__ */ new Set([source])
481
+ };
482
+ }
483
+ };
484
+ //#endregion
322
485
  //#region extensions/codex/src/session-catalog-index-query.ts
323
486
  /** Keyset pagination remains valid when the anchor row is archived or deleted. */
324
487
  function prepareCodexCatalogQuery(params, prepared) {
@@ -331,9 +494,9 @@ function prepareCodexCatalogQuery(params, prepared) {
331
494
  const { complete, frontier } = availability;
332
495
  if (!complete && !frontier) return;
333
496
  if (!complete && frontier && anchor?.backwards && compareCodexCatalogRows(frontier, anchor) < 0) return;
334
- const candidates = ordered.filter((row) => {
497
+ const candidates = complete && !cwd && !search ? ordered : ordered.filter((row) => {
335
498
  const session = row.page.sessions[0];
336
- return !row.archived && session && (complete || !frontier || compareCodexCatalogRows(row, frontier) <= 0) && (!cwd || (liveSettings.get(row.threadId)?.cwd ?? session.cwd) === cwd) && (!search || (session.name ?? session.fallbackName)?.toLocaleLowerCase().includes(search));
499
+ return session && (complete || !frontier || compareCodexCatalogRows(row, frontier) <= 0) && (!cwd || (liveSettings.get(row.threadId)?.cwd ?? session.cwd) === cwd) && (!search || (session.name ?? session.fallbackName)?.toLocaleLowerCase().includes(search));
337
500
  });
338
501
  const selected = anchor?.backwards ? candidates.filter((row) => row.threadId !== anchor.threadId) : candidates;
339
502
  let start = 0;
@@ -360,15 +523,7 @@ function prepareCodexCatalogQuery(params, prepared) {
360
523
  continuation = frontier && (!last || compareCodexCatalogRows(frontier, last) > 0) ? frontier : last;
361
524
  }
362
525
  return {
363
- sessions: page.flatMap((row) => row.page.sessions.map(({ status: _storedStatus, activeFlags: _storedFlags, ...session }) => {
364
- const live = liveStatus.get(row.threadId);
365
- return {
366
- ...session,
367
- ...liveSettings.get(row.threadId),
368
- status: live?.status ?? "notLoaded",
369
- ...live?.activeFlags ? { activeFlags: [...live.activeFlags] } : {}
370
- };
371
- })),
526
+ sessions: page.flatMap((row) => row.page.sessions.map((session) => applyCodexCatalogLiveFields(session, liveStatus.get(row.threadId), liveSettings.get(row.threadId)))),
372
527
  ...continuation ? { nextCursor: cursor(continuation, false) } : {},
373
528
  ...first && start > 0 ? { backwardsCursor: cursor(first, true) } : {}
374
529
  };
@@ -376,6 +531,36 @@ function prepareCodexCatalogQuery(params, prepared) {
376
531
  }
377
532
  //#endregion
378
533
  //#region extensions/codex/src/session-catalog-native-page.ts
534
+ /** Background walks share bounded native pages; the index decides when a prefix is current. */
535
+ async function* readCodexCatalogHydrationPages(read, useStateDbOnly) {
536
+ let cursor;
537
+ let offset = 0;
538
+ const cursors = /* @__PURE__ */ new Set();
539
+ do {
540
+ const page = await read({
541
+ archived: false,
542
+ modelProviders: [],
543
+ sortKey: "recency_at",
544
+ sortDirection: "desc",
545
+ limit: 64,
546
+ ...useStateDbOnly ? { useStateDbOnly } : {},
547
+ ...cursor ? { cursor } : {}
548
+ }, Math.max(0, CODEX_CATALOG_MAX_ROWS - offset));
549
+ cursor = readControlCursor(page.nextCursor, "hydration response");
550
+ if (cursor && cursors.has(cursor)) throw new Error("Codex catalog repeated a hydration cursor");
551
+ if (cursor) {
552
+ cursors.add(cursor);
553
+ if (cursors.size > 2e4) cursors.delete(cursors.values().next().value);
554
+ }
555
+ yield {
556
+ ...page,
557
+ nextCursor: cursor,
558
+ offset
559
+ };
560
+ offset += page.rows.length;
561
+ await setImmediate$1();
562
+ } while (cursor);
563
+ }
379
564
  /** The resident limit bounds storage, never authoritative discovery. */
380
565
  var CodexCatalogNativePages = class {
381
566
  constructor(settings, status) {
@@ -445,13 +630,7 @@ var CodexCatalogNativePages = class {
445
630
  }
446
631
  rows = selected;
447
632
  } else if (!position.cursor && !position.backwards) previous = void 0;
448
- const projected = filterCatalogPageByTitle({ sessions: rows.flatMap((row) => row.page.sessions).map(({ status: _storedStatus, activeFlags: _storedFlags, ...session }) => {
449
- const live = this.status.get(session.threadId);
450
- return Object.assign(session, this.settings.get(session.threadId), {
451
- status: live?.status ?? "notLoaded",
452
- ...live?.activeFlags ? { activeFlags: [...live.activeFlags] } : {}
453
- });
454
- }).filter((session) => !cwd || session.cwd === cwd) }, params.searchTerm);
633
+ const projected = filterCatalogPageByTitle({ sessions: rows.flatMap((row) => row.page.sessions).map((session) => applyCodexCatalogLiveFields(session, this.status.get(session.threadId), this.settings.get(session.threadId))).filter((session) => !cwd || session.cwd === cwd) }, params.searchTerm);
455
634
  const continuation = position.backwards ? previous : next;
456
635
  if ((params.searchTerm || filterCwdLocally) && !projected.sessions.length && continuation) {
457
636
  if (encodeCodexNativeCursor(continuation) === encodeCodexNativeCursor(position)) throw new CatalogParamsError("Codex catalog repeated a native continuation");
@@ -503,17 +682,10 @@ var CodexCatalogSettingsIndex = class {
503
682
  }
504
683
  get(threadId) {
505
684
  const current = this.values.get(threadId);
506
- if (current) {
507
- for (const source of current.sources) if (!source.closed) return current.settings;
508
- }
685
+ return current && hasLiveCodexCatalogSource(current.sources) ? current.settings : void 0;
509
686
  }
510
687
  hasLiveCwd() {
511
- return this.values.some(({ settings, sources }) => {
512
- if (settings.cwd) {
513
- for (const source of sources) if (!source.closed) return true;
514
- }
515
- return false;
516
- });
688
+ return this.values.some(({ settings, sources }) => Boolean(settings.cwd) && hasLiveCodexCatalogSource(sources));
517
689
  }
518
690
  delete(threadId) {
519
691
  this.values.delete(threadId);
@@ -521,8 +693,7 @@ var CodexCatalogSettingsIndex = class {
521
693
  withdraw(threadId, source) {
522
694
  const current = this.values.get(threadId);
523
695
  if (!current?.sources.delete(source)) return;
524
- for (const witness of current.sources) if (!witness.closed) return;
525
- this.values.delete(threadId);
696
+ if (!hasLiveCodexCatalogSource(current.sources)) this.values.delete(threadId);
526
697
  }
527
698
  invalidate(source) {
528
699
  if (!source) {
@@ -531,84 +702,11 @@ var CodexCatalogSettingsIndex = class {
531
702
  }
532
703
  this.values.deleteWhere((entry) => {
533
704
  entry.sources.delete(source);
534
- for (const witness of entry.sources) if (!witness.closed) return false;
535
- return true;
705
+ return !hasLiveCodexCatalogSource(entry.sources);
536
706
  });
537
707
  }
538
708
  };
539
709
  //#endregion
540
- //#region extensions/codex/src/session-catalog-status.ts
541
- const MAX_STATUS_SOURCE_WITNESSES = 64;
542
- /** Equivalent broadcasts retain at most 64 source witnesses for each bounded resident row. */
543
- var CodexCatalogStatusIndex = class {
544
- constructor() {
545
- this.values = new CodexCatalogField();
546
- }
547
- capture() {
548
- return this.values.capture();
549
- }
550
- update(threadId, status, source) {
551
- const next = this.next(threadId, status, source);
552
- if (next) this.values.update(threadId, next);
553
- }
554
- observe(row, revision) {
555
- const session = row.page.sessions[0];
556
- const source = getCodexCatalogSource(row);
557
- if (session && source) {
558
- const next = this.next(row.threadId, {
559
- status: session.status,
560
- ...session.activeFlags ? { activeFlags: session.activeFlags } : {}
561
- }, source);
562
- if (next) this.values.observe(row.threadId, next, revision);
563
- }
564
- }
565
- get(threadId) {
566
- const current = this.values.get(threadId);
567
- if (current) {
568
- for (const source of current.sources) if (!source.closed) return current.status;
569
- }
570
- }
571
- delete(threadId) {
572
- this.values.delete(threadId);
573
- }
574
- invalidate(source) {
575
- if (!source) {
576
- this.values.invalidate();
577
- return;
578
- }
579
- this.values.deleteWhere((entry) => {
580
- entry.sources.delete(source);
581
- for (const witness of entry.sources) if (!witness.closed) return false;
582
- return true;
583
- });
584
- }
585
- next(threadId, status, source) {
586
- if (source.closed) return;
587
- const current = this.values.get(threadId);
588
- const sources = new Set([...current?.sources ?? []].filter((witness) => !witness.closed));
589
- if (status.status === "notLoaded" && current && current.status.status !== "notLoaded" && sources.size) {
590
- sources.delete(source);
591
- if (sources.size) return {
592
- status: current.status,
593
- sources
594
- };
595
- }
596
- const flags = status.activeFlags ?? [];
597
- const previousFlags = current?.status.activeFlags ?? [];
598
- if (current?.status.status === status.status && flags.length === previousFlags.length && flags.every((flag, index) => flag === previousFlags[index])) {
599
- if (sources.size < MAX_STATUS_SOURCE_WITNESSES) sources.add(source);
600
- return {
601
- status,
602
- sources
603
- };
604
- }
605
- return {
606
- status,
607
- sources: /* @__PURE__ */ new Set([source])
608
- };
609
- }
610
- };
611
- //#endregion
612
710
  //#region extensions/codex/src/session-catalog-index.ts
613
711
  /** One home owns resident queries and authoritative overflow discovery. */
614
712
  var CodexCatalogIndex = class {
@@ -634,7 +732,7 @@ var CodexCatalogIndex = class {
634
732
  this.currency = new CodexCatalogCurrency({
635
733
  local: Boolean(options.localSessionsRoot),
636
734
  reconcileFiles: () => this.reconcile(),
637
- reconcileNative: () => this.reconcileNative(),
735
+ reconcileNative: (full) => this.reconcileNative(full),
638
736
  runBackground: options.runBackground,
639
737
  report: (error) => this.report(error)
640
738
  });
@@ -647,18 +745,24 @@ var CodexCatalogIndex = class {
647
745
  },
648
746
  updateSettings: (id, settings, source) => this.liveSettings.update(id, settings, source),
649
747
  rename: (id, name) => {
748
+ this.currency.requestNativeRefresh();
650
749
  this.names.update(id, name);
651
750
  const row = this.rows.get(id);
652
751
  if (row && !this.closed) this.put(row);
653
752
  },
654
753
  upsert: (thread) => this.upsertThread(thread),
655
754
  reserveTurnStartOrder: () => this.ordering.reserveEvent(),
755
+ requestNativeRefresh: () => this.currency.requestNativeRefresh(),
656
756
  refresh: (id, readThread, sourceOrder) => this.refreshThread(id, readThread, sourceOrder),
657
757
  archive: (id) => this.archive(id),
658
- remove: (id) => this.remove(id),
659
- report: (error) => this.report(error)
758
+ remove: (id) => {
759
+ this.currency.requestNativeRefresh();
760
+ this.remove(id);
761
+ },
762
+ report: (error, disposition) => this.report(error, disposition)
660
763
  });
661
764
  this.unsubscribe = subscribeCodexCatalogEvents(options.homeId, (event, readThread, source) => this.events.handle(event, readThread, source), {
765
+ onEphemeralThread: (id) => this.remove(id),
662
766
  onClose: (source) => {
663
767
  this.liveStatus.invalidate(source);
664
768
  this.liveSettings.invalidate(source);
@@ -686,8 +790,8 @@ var CodexCatalogIndex = class {
686
790
  throw error;
687
791
  }
688
792
  }
689
- report(error) {
690
- if (!this.closed) embeddedAgentLog.warn("Codex resident catalog background update failed", { error });
793
+ report(error, disposition) {
794
+ if (!this.closed && !this.currency.stopForTerminalFailure(error)) embeddedAgentLog.warn(disposition === "deferred" ? "Codex resident catalog metadata refresh interrupted; deferred for automatic recovery" : "Codex resident catalog background update failed", { error });
691
795
  }
692
796
  withName(row) {
693
797
  const known = this.names.get(row.threadId);
@@ -729,8 +833,8 @@ var CodexCatalogIndex = class {
729
833
  }
730
834
  async initialize() {
731
835
  this.assertCurrent();
732
- clearImmediate(this.background);
733
- this.background = void 0;
836
+ this.currency.assertRunnable();
837
+ this.currency.cancelHydration();
734
838
  if (this.initialized && !this.needsNativeRefresh) return;
735
839
  if (!this.initializing) {
736
840
  this.availability.begin();
@@ -743,7 +847,7 @@ var CodexCatalogIndex = class {
743
847
  if (!this.initialized) {
744
848
  let observedRevision;
745
849
  do
746
- observedRevision = await this.observations.observe((isCurrent) => this.hydrate(isCurrent, this.availability.complete));
850
+ observedRevision = await this.hydrate(this.availability.complete);
747
851
  while (observedRevision !== this.sourceRevision);
748
852
  this.needsNativeRefresh = false;
749
853
  }
@@ -758,6 +862,7 @@ var CodexCatalogIndex = class {
758
862
  })().catch((error) => {
759
863
  this.failure = { error };
760
864
  this.availability.fail(error);
865
+ this.currency.stopForTerminalFailure(error);
761
866
  throw error;
762
867
  }).finally(() => {
763
868
  this.initializing = void 0;
@@ -800,13 +905,8 @@ var CodexCatalogIndex = class {
800
905
  await this.restoring;
801
906
  }
802
907
  scheduleHydration() {
803
- if (this.initialized && !this.needsNativeRefresh || this.initializing || this.background || this.closed) return;
804
- this.background = setImmediate(() => {
805
- this.background = void 0;
806
- const run = () => this.initialize();
807
- (this.options.runBackground ? this.options.runBackground(run) : run()).catch((error) => this.report(error));
808
- });
809
- this.background.unref();
908
+ if (this.initialized && !this.needsNativeRefresh || this.initializing || this.closed) return;
909
+ this.currency.scheduleHydration(() => this.initialize());
810
910
  }
811
911
  captureFields() {
812
912
  return {
@@ -823,79 +923,71 @@ var CodexCatalogIndex = class {
823
923
  if (current && current.page.sessions[0]?.name !== session.name) this.put(current);
824
924
  }
825
925
  }
826
- reconcileNative() {
926
+ reconcileNative(full = true) {
827
927
  if (!this.options.localSessionsRoot && this.initializing && !this.initialized) return this.initializing;
828
- if (!this.reconcilingNative) {
829
- const refresh = this.observations.observe(async (isCurrent) => {
830
- await this.hydrate(isCurrent, true);
831
- });
832
- this.reconcilingNative = refresh.finally(() => {
833
- this.reconcilingNative = void 0;
834
- });
835
- }
928
+ if (!this.reconcilingNative) this.reconcilingNative = this.hydrate(true, !full).then(() => void 0).finally(() => {
929
+ this.reconcilingNative = void 0;
930
+ });
836
931
  return this.reconcilingNative;
837
932
  }
838
- async hydrate(isCurrent, useStateDbOnly = false) {
933
+ hydrate(useStateDbOnly = false, incremental = false) {
934
+ const run = () => this.observations.observe((isCurrent) => this.hydratePages(isCurrent, useStateDbOnly, incremental));
935
+ return this.options.runNativeWalk?.(run) ?? run();
936
+ }
937
+ async hydratePages(isCurrent, useStateDbOnly, incremental) {
839
938
  this.assertCurrent();
840
939
  const files = this.options.localSessionsRoot && !useStateDbOnly ? (await scanCodexCatalogRollouts(this.options.localSessionsRoot, /* @__PURE__ */ new Set())).files : /* @__PURE__ */ new Map();
841
- let cursor;
842
- let observedRevision = this.sourceRevision;
843
- let firstPage = true;
844
- let sourceOrder = 0;
940
+ let observedRevision;
845
941
  let frontier;
846
942
  const batchOrder = this.ordering.captureBatch(this.availability.complete);
847
- const remaining = new Map(this.rows);
848
- const cursors = /* @__PURE__ */ new Set();
849
- do {
943
+ const remaining = incremental ? void 0 : new Map(this.rows);
944
+ const pages = readCodexCatalogHydrationPages(async (params, remainingRows) => {
850
945
  this.assertCurrent();
851
946
  const fieldRevision = this.captureFields();
852
- const page = await this.options.readNative({
853
- archived: false,
854
- modelProviders: [],
855
- sortKey: "recency_at",
856
- sortDirection: "desc",
857
- limit: 64,
858
- ...useStateDbOnly ? { useStateDbOnly } : {},
859
- ...cursor ? { cursor } : {}
860
- }, Math.max(0, CODEX_CATALOG_MAX_ROWS - sourceOrder));
947
+ return {
948
+ ...await this.options.readNative(params, remainingRows),
949
+ fieldRevision,
950
+ sourceRevision: this.sourceRevision
951
+ };
952
+ }, useStateDbOnly);
953
+ for await (const page of pages) {
861
954
  this.assertCurrent();
862
- if (firstPage) {
863
- observedRevision = this.sourceRevision;
864
- firstPage = false;
955
+ observedRevision ??= page.sourceRevision;
956
+ let sourceOrder = page.offset;
957
+ let changed = false;
958
+ for (const id of page.excludedThreadIds ?? []) if (isCurrent(id)) {
959
+ changed ||= this.rows.has(id);
960
+ this.remove(id);
865
961
  }
866
- for (const id of page.excludedThreadIds ?? []) if (isCurrent(id)) this.remove(id);
867
962
  for (const row of page.rows) {
868
963
  const position = sourceOrder++;
869
964
  if (position >= 2e4) continue;
870
- remaining.delete(row.threadId);
871
- this.observeFields(row, fieldRevision);
872
- if (!isCurrent(row.threadId)) continue;
873
- const logicalPath = row.rolloutPath && codexCatalogRolloutLogicalPath(row.rolloutPath);
965
+ remaining?.delete(row.threadId);
874
966
  const previous = this.rows.get(row.threadId);
875
- const fingerprint = logicalPath ? files.get(logicalPath) ?? files.get(`${logicalPath}.zst`) ?? (useStateDbOnly && previous?.rolloutPath && codexCatalogRolloutLogicalPath(previous.rolloutPath) === logicalPath ? previous.fingerprint : void 0) : void 0;
967
+ this.observeFields(row, page.fieldRevision);
968
+ if (!isCurrent(row.threadId)) {
969
+ changed = true;
970
+ continue;
971
+ }
972
+ const fingerprint = resolveCodexCatalogRolloutFingerprint(row.rolloutPath, useStateDbOnly ? previous : void 0, files);
876
973
  this.observations.mark(row.threadId);
877
974
  this.put({
878
975
  ...row,
879
976
  sourceOrder: batchOrder(row, previous, position),
880
977
  ...fingerprint ? { fingerprint } : {}
881
978
  });
979
+ changed ||= this.rows.get(row.threadId) !== previous;
882
980
  frontier = this.rows.get(row.threadId) ?? frontier;
883
981
  }
884
- cursor = readControlCursor(page.nextCursor, "hydration response");
885
- if (cursor && cursors.has(cursor)) throw new Error("Codex catalog repeated a hydration cursor");
886
- if (cursor) {
887
- cursors.add(cursor);
888
- if (cursors.size > 2e4) cursors.delete(cursors.values().next().value);
889
- this.availability.publish(frontier);
890
- }
891
- await setImmediate$1();
892
- } while (cursor);
893
- if (!useStateDbOnly || !this.options.localSessionsRoot) {
982
+ if (incremental && (!changed && page.rows.length > 0 || sourceOrder >= 2e4)) break;
983
+ if (page.nextCursor) this.availability.publish(frontier);
984
+ }
985
+ if (remaining && (!useStateDbOnly || !this.options.localSessionsRoot)) {
894
986
  for (const [id, row] of remaining) if (isCurrent(id) && this.rows.get(id) === row) this.remove(id);
895
987
  }
896
988
  this.availability.publish(frontier, true);
897
989
  await this.persistence.finishHydration(this.overflow);
898
- return observedRevision;
990
+ return observedRevision ?? this.sourceRevision;
899
991
  }
900
992
  reconcile() {
901
993
  if (!this.reconciling) this.reconciling = this.observations.observe((isCurrent) => this.reconcileFiles(isCurrent)).finally(() => {
@@ -907,7 +999,7 @@ var CodexCatalogIndex = class {
907
999
  const root = this.options.localSessionsRoot;
908
1000
  if (!root || !this.initialized || this.closed) return;
909
1001
  this.assertCurrent();
910
- const byPath = new Map([...this.rows.values()].flatMap((row) => row.rolloutPath ? [[codexCatalogRolloutLogicalPath(row.rolloutPath), row]] : []));
1002
+ const byPath = indexCodexCatalogRowsByRollout(this.rows.values());
911
1003
  const { files, present } = await scanCodexCatalogRollouts(root, new Set(byPath.keys()));
912
1004
  this.assertCurrent();
913
1005
  const observed = new Map(files);
@@ -915,6 +1007,7 @@ var CodexCatalogIndex = class {
915
1007
  const previous = byPath.get(codexCatalogRolloutLogicalPath(file));
916
1008
  const known = this.observedFiles.get(file) ?? previous?.fingerprint;
917
1009
  if (known?.mtimeMs === fingerprint.mtimeMs && known.size === fingerprint.size) continue;
1010
+ this.currency.requestNativeRefresh();
918
1011
  observed.delete(file);
919
1012
  if (known) observed.set(file, known);
920
1013
  let thread;
@@ -951,7 +1044,10 @@ var CodexCatalogIndex = class {
951
1044
  this.put(mergeCodexCatalogRolloutRow(row, existing, fingerprint));
952
1045
  await setImmediate$1();
953
1046
  }
954
- for (const row of byPath.values()) if (row.rolloutPath && isCodexCatalogRolloutPathCovered(root, row.rolloutPath) && !present.has(codexCatalogRolloutLogicalPath(row.rolloutPath)) && this.rows.get(row.threadId) === row) this.remove(row.threadId);
1047
+ for (const row of byPath.values()) if (row.rolloutPath && isCodexCatalogRolloutPathCovered(root, row.rolloutPath) && !present.has(codexCatalogRolloutLogicalPath(row.rolloutPath)) && this.rows.get(row.threadId) === row) {
1048
+ this.currency.requestNativeRefresh();
1049
+ this.remove(row.threadId);
1050
+ }
955
1051
  this.observedFiles = observed;
956
1052
  }
957
1053
  upsertThread(thread) {
@@ -962,6 +1058,7 @@ var CodexCatalogIndex = class {
962
1058
  return Promise.resolve();
963
1059
  }
964
1060
  try {
1061
+ this.currency.requestNativeRefresh();
965
1062
  return this.upsertPreparedThread(projectCodexCatalogNativeThread(thread, sanitizeTerminalText));
966
1063
  } catch (error) {
967
1064
  return Promise.reject(toErrorObject(error, "Codex catalog projection failed"));
@@ -996,7 +1093,7 @@ var CodexCatalogIndex = class {
996
1093
  if (projected.excludedThreadIds?.includes(thread.id)) this.remove(thread.id);
997
1094
  if (row) {
998
1095
  const previous = this.rows.get(thread.id);
999
- const fingerprint = previous?.rolloutPath && row.rolloutPath && codexCatalogRolloutLogicalPath(previous.rolloutPath) === codexCatalogRolloutLogicalPath(row.rolloutPath) ? previous.fingerprint : void 0;
1096
+ const fingerprint = resolveCodexCatalogRolloutFingerprint(row.rolloutPath, previous);
1000
1097
  this.observations.mark(thread.id);
1001
1098
  this.put({
1002
1099
  ...row,
@@ -1008,6 +1105,7 @@ var CodexCatalogIndex = class {
1008
1105
  }
1009
1106
  archive(threadId) {
1010
1107
  if (this.closed) return;
1108
+ this.currency.requestNativeRefresh();
1011
1109
  this.observations.mark(threadId);
1012
1110
  this.liveStatus.delete(threadId);
1013
1111
  this.liveSettings.delete(threadId);
@@ -1022,6 +1120,9 @@ var CodexCatalogIndex = class {
1022
1120
  get(threadId) {
1023
1121
  return this.rows.get(threadId);
1024
1122
  }
1123
+ hasActiveWork() {
1124
+ return Boolean(this.initializing || !this.restored && this.restoring || this.reconciling || this.reconcilingNative || this.currency.hasActiveWork() || this.observations.hasActiveWork() || this.events.hasActiveWork() || this.persistence.hasActiveWork());
1125
+ }
1025
1126
  async list(params, deadline = performance.now() + (this.options.requestTimeoutMs ?? 6e4)) {
1026
1127
  return await withCodexCatalogListRequest(async (request) => {
1027
1128
  const expiresAt = request.constrainDeadline(deadline);
@@ -1035,7 +1136,10 @@ var CodexCatalogIndex = class {
1035
1136
  const ordered = this.ordering.read(this.rows);
1036
1137
  const page = query?.(ordered, this.liveStatus, this.liveSettings, this.availability);
1037
1138
  if (cursor.kind === "native" || this.overflow && (params.cwd || params.searchTerm || page && !page.nextCursor)) return await this.nativePages.list(params, cursor, this.options, request);
1038
- if (page) return page;
1139
+ if (page) {
1140
+ this.currency.refreshNativeIfDue();
1141
+ return page;
1142
+ }
1039
1143
  await this.availability.next(expiresAt);
1040
1144
  }
1041
1145
  });
@@ -1048,7 +1152,6 @@ var CodexCatalogIndex = class {
1048
1152
  this.liveSettings.invalidate();
1049
1153
  this.unsubscribe();
1050
1154
  this.currency.close();
1051
- clearImmediate(this.background);
1052
1155
  return this.persistence.retire();
1053
1156
  }
1054
1157
  async close() {
@@ -1058,6 +1161,7 @@ var CodexCatalogIndex = class {
1058
1161
  this.restoring,
1059
1162
  this.reconciling,
1060
1163
  this.reconcilingNative,
1164
+ this.currency.close(),
1061
1165
  writes,
1062
1166
  this.events.close()
1063
1167
  ]);