@openclaw/codex 2026.9.4 → 2026.9.6

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 (160) hide show
  1. package/assets/activity.svg +30 -0
  2. package/assets/icon.png +0 -0
  3. package/dist/.setup/account-usage-runtime-Eem_WGqY.mjs +75 -0
  4. package/dist/{apply-CvT8tW5i.js → .setup/apply-DDOi8uNx.mjs} +24 -30
  5. package/dist/.setup/async-questions-DdhOCwGi.mjs +27 -0
  6. package/dist/{attempt-client-cleanup-DKHzbwt5.js → .setup/attempt-client-cleanup-CEv1cKwF.mjs} +79 -49
  7. package/dist/.setup/attempt-terminal-gZrxQ35N.mjs +5 -0
  8. package/dist/.setup/attempt-workspace-context-DUVEn_CS.mjs +331 -0
  9. package/dist/{auth-binding-CWlKVccJ.js → .setup/auth-binding-DhLWa_7K.mjs} +1 -1
  10. package/dist/{auth-cache-key-7orQae_j.js → .setup/auth-cache-key-B2mpaI9D.mjs} +9 -81
  11. package/dist/{auth-profile-CwzO4_RG.js → .setup/auth-profile-WqZtZfXN.mjs} +1 -1
  12. package/dist/.setup/auth-profile-health-oHizqgye.mjs +53 -0
  13. package/dist/.setup/auth-profile-recovery-BREezV0L.mjs +14 -0
  14. package/dist/.setup/binding-connection-ThoatDcb.mjs +50 -0
  15. package/dist/.setup/binding-connection.runtime-yoHrABt-.mjs +48 -0
  16. package/dist/{bounded-turn-C_Hneydj.js → .setup/bounded-turn-B2HScEgT.mjs} +143 -32
  17. package/dist/{build-state-BCmg9-5p.js → .setup/build-state-C7EnDVgr.mjs} +1 -1
  18. package/dist/{capabilities-8vx68WLH.js → .setup/capabilities-CDXOOFdZ.mjs} +1 -1
  19. package/dist/{client-B57KWPQx.js → .setup/client-Cs08OXVQ.mjs} +705 -512
  20. package/dist/.setup/client-catalog-response-BMgt_4q4.mjs +285 -0
  21. package/dist/{command-dispatch-BpduNGVf.js → .setup/command-dispatch-B4JuOsOk.mjs} +8 -4
  22. package/dist/{command-formatters-lxlkNZgU.js → .setup/command-formatters-Bmqvr9tO.mjs} +8 -4
  23. package/dist/{command-handlers-tiL9iWj7.js → .setup/command-handlers-DW7Lx9oH.mjs} +137 -186
  24. package/dist/{command-rpc-CR5EOEZX.js → .setup/command-rpc-DixIj3HW.mjs} +47 -23
  25. package/dist/{compact-B_H3AOd7.js → .setup/compact-Du5UvtxA.mjs} +29 -51
  26. package/dist/{config-oIORaQ5T.js → .setup/config-BoTP_mrL.mjs} +5 -4
  27. package/dist/{config-options-CXMq1T-C.js → .setup/config-options-BvaRs51b.mjs} +50 -446
  28. package/dist/{protocol-5bh1G-H7.js → .setup/config-parsing-CcB9iPoq.mjs} +9 -51
  29. package/dist/{config-runtime-D0zGNIHu.js → .setup/config-runtime-C8Rw1m1m.mjs} +2 -2
  30. package/dist/.setup/config-security-BEReZ6go.mjs +380 -0
  31. package/dist/{conversation-binding-DsB4-O7U.js → .setup/conversation-binding-DP-gMrBP.mjs} +29 -38
  32. package/dist/{conversation-binding-data-BiodpIzq.js → .setup/conversation-binding-data-CrcyZk6O.mjs} +1 -1
  33. package/dist/{conversation-control-CtUu1b3m.js → .setup/conversation-control-uK9Jomlc.mjs} +32 -67
  34. package/dist/.setup/cyber-failover-DYwbmf1o.mjs +123 -0
  35. package/dist/.setup/cyber-failover-notice-e9G3J9-e.mjs +17 -0
  36. package/dist/{dynamic-tools-CmN5RAip.js → .setup/dynamic-tools-BDXl-8Cw.mjs} +936 -620
  37. package/dist/{effective-mcp-catalog-Bd73bqA8.js → .setup/effective-mcp-catalog-CvnvnGIe.mjs} +3 -3
  38. package/dist/{ephemeral-turn-D78_VmzO.js → .setup/ephemeral-turn-poidXgek.mjs} +9 -7
  39. package/dist/{event-projector-assistant-message-BmBM4qBV.js → .setup/event-projector-assistant-message-BsruvNrH.mjs} +8 -7
  40. package/dist/{event-projector-items-5VhsECCO.js → .setup/event-projector-items-C6L_5ZiT.mjs} +42 -8
  41. package/dist/{attempt-notifications-C9XufG6l.js → .setup/event-projector-usage-CnBS8Wa3.mjs} +102 -9
  42. package/dist/{harness-C7rRa7bm.js → .setup/harness-a_MsE4-_.mjs} +81 -21
  43. package/dist/{inference-context-Dr_mzvk4.js → .setup/inference-context-D96l9-ew.mjs} +1 -1
  44. package/dist/.setup/inference-proxy-b-aJMSxm.mjs +601 -0
  45. package/dist/{isolated-completion-DWVb5U2J.js → .setup/isolated-completion-BIZFhTNG.mjs} +18 -11
  46. package/dist/.setup/launch-args-DbFCehO7.mjs +196 -0
  47. package/dist/{managed-binary-D22rNEcR.js → .setup/managed-binary-BnshlFag.mjs} +14 -3
  48. package/dist/{managed-thread-store-D1t5jh3G.js → .setup/managed-thread-store-BMqgThVL.mjs} +48 -14
  49. package/dist/{model-catalog-Dq2n8f_p.js → .setup/model-catalog-CfXJf9Ay.mjs} +36 -12
  50. package/dist/{models-PCKOim-h.js → .setup/models-KnqBv0hE.mjs} +3 -3
  51. package/dist/.setup/native-auth-rWbGbMn3.mjs +57 -0
  52. package/dist/{native-subagent-history-DjtPloaU.js → .setup/native-subagent-history-0nYYgo0k.mjs} +43 -35
  53. package/dist/.setup/native-subagent-monitor-D3filLY2.mjs +4859 -0
  54. package/dist/{native-subagent-task-ids-BzTdT0Uw.js → .setup/native-subagent-task-ids-wb8CKZGN.mjs} +98 -44
  55. package/dist/{node-cli-sessions-DKaOmVUh.js → .setup/node-cli-sessions-r3avj02l.mjs} +86 -68
  56. package/dist/.setup/node-exec-server.runtime-BDwWXVpK.mjs +247 -0
  57. package/dist/{plan-7uG-Fp36.js → .setup/plan-CN3VwfNU.mjs} +133 -119
  58. package/dist/{plugin-activation-BYQculil.js → .setup/plugin-activation-DT3MNtqj.mjs} +7 -16
  59. package/dist/{plugin-app-cache-key-d0eKxy7b.js → .setup/plugin-app-cache-key-B2CsSdnV.mjs} +32 -44
  60. package/dist/{plugin-approval-roundtrip-Bz3FT8W5.js → .setup/plugin-approval-roundtrip-C0MZzCuP.mjs} +1 -1
  61. package/dist/{plugin-inventory-oL4Na1ZG.js → .setup/plugin-inventory-BoRei8Z4.mjs} +21 -11
  62. package/dist/{plugin-marketplace-discovery-P-Vndfqq.js → .setup/plugin-marketplace-discovery-CDOi8IFs.mjs} +4 -1
  63. package/dist/{plugin-metadata-cache-ClPJpRio.js → .setup/plugin-metadata-cache-Ctmo83k_.mjs} +226 -141
  64. package/dist/.setup/protocol-CANUwXJ3.mjs +17 -0
  65. package/dist/{provider-MQ8PVkuE.js → .setup/provider-BOsxQHOM.mjs} +9 -5
  66. package/dist/{provider-capabilities-BvCUL69A.js → .setup/provider-capabilities-BfE88FZ5.mjs} +31 -3
  67. package/dist/{rate-limits-CBMmWBr9.js → .setup/rate-limits-CMU3DUD0.mjs} +174 -151
  68. package/dist/{request-B7hEkBGq.js → .setup/request-D2L0zMrq.mjs} +130 -42
  69. package/dist/{run-attempt-CvsAAGa0.js → .setup/run-attempt-BHu11r7h.mjs} +1628 -966
  70. package/dist/.setup/run-attempt-lifecycle-B7JbY4-F.mjs +71 -0
  71. package/dist/{runtime-artifact-BJ0rXBZ_.js → .setup/runtime-artifact-CLZ8udh-.mjs} +29 -45
  72. package/dist/{sandbox-guard-BxgyoM8M.js → .setup/sandbox-guard-C2sRMOEY.mjs} +3 -3
  73. package/dist/{session-binding-CI8UuilT.js → .setup/session-binding-Cm0apEbd.mjs} +36 -83
  74. package/dist/{session-binding-record-Bcvslnhf.js → .setup/session-binding-record-BGoz8wOK.mjs} +202 -5
  75. package/dist/.setup/session-binding-sidecars-BlB5EvIS.mjs +546 -0
  76. package/dist/.setup/session-catalog-Pno1xGcl.mjs +2764 -0
  77. package/dist/{session-catalog-adoption-tcZi1IfX.js → .setup/session-catalog-adoption-BI6UTDZT.mjs} +58 -26
  78. package/dist/{session-catalog-archive-CwKg8Xz2.js → .setup/session-catalog-archive-lHBqzhaO.mjs} +6 -6
  79. package/dist/.setup/session-catalog-events-Bj6j94E_.mjs +347 -0
  80. package/dist/.setup/session-catalog-index-B9_VQIUz.mjs +1170 -0
  81. package/dist/.setup/session-catalog-index-order-hcdz07yN.mjs +48 -0
  82. package/dist/.setup/session-catalog-index-state-Dgh8ORJm.mjs +183 -0
  83. package/dist/{thread-history-page-D0JIp48V.js → .setup/session-catalog-native-projection-DowriLid.mjs} +223 -95
  84. package/dist/{session-catalog-node-adoption-B1tgDW-m.js → .setup/session-catalog-node-adoption-ITddWx_X.mjs} +25 -13
  85. package/dist/{session-catalog-node-continue-Ci-DXyJP.js → .setup/session-catalog-node-continue-6g6qi4A9.mjs} +24 -15
  86. package/dist/.setup/session-catalog-projection-zK_PUsiE.mjs +422 -0
  87. package/dist/{session-cli-DNN_jhGc.js → .setup/session-cli-irrD-uo7.mjs} +3 -3
  88. package/dist/{session-history-Cz-tOOYj.js → .setup/session-history-BrqhSCf9.mjs} +19 -19
  89. package/dist/{session-history-import-DwyijFI6.js → .setup/session-history-import-D-3wAgOP.mjs} +4 -4
  90. package/dist/{session-history-read-cxPUxyVV.js → .setup/session-history-read-B3ZfSUbF.mjs} +2 -2
  91. package/dist/{session-history.worker-BeK1YOyT.js → .setup/session-history.worker-CaCh0xF_.mjs} +10 -24
  92. package/dist/{session-initialization-Ct0_Hzmg.js → .setup/session-initialization-rcgbZiid.mjs} +2 -2
  93. package/dist/{session-permission-policy-BBmXA8Eg.js → .setup/session-permission-policy-BI1QK_98.mjs} +2 -2
  94. package/dist/{session-retirement-B2YfbAAT.js → .setup/session-retirement-BH-S6qkJ.mjs} +26 -7
  95. package/dist/{settled-turn-context-Du6gdUDd.js → .setup/settled-turn-context-fmwouT5I.mjs} +2 -2
  96. package/dist/{settled-turn-finalizer-Dn91stmc.js → .setup/settled-turn-finalizer-DiAi6Kx6.mjs} +12 -12
  97. package/dist/{shared-client-CscigXXL.js → .setup/shared-client-DA4VR4Eb.mjs} +332 -221
  98. package/dist/{side-question-BGMJQf4U.js → .setup/side-question-BJ1wSDcB.mjs} +183 -230
  99. package/dist/{source-CElXU0Oy.js → .setup/source-CUzJq5WN.mjs} +11 -10
  100. package/dist/.setup/spawn-error-CL3n6MAa.mjs +57 -0
  101. package/dist/{thread-archive-guard-DfpBr-Sz.js → .setup/thread-archive-guard-C9frICzX.mjs} +10 -3
  102. package/dist/.setup/thread-history-page-DoVpnHim.mjs +83 -0
  103. package/dist/{thread-lifecycle-DXl1-I6b.js → .setup/thread-lifecycle-B3mfz1TG.mjs} +347 -2318
  104. package/dist/{thread-ownership-BsDRTsyp.js → .setup/thread-ownership-DcTtAcXj.mjs} +6 -4
  105. package/dist/{thread-policy-BuEQfE0g.js → .setup/thread-policy-DGuQsuFC.mjs} +19 -3
  106. package/dist/.setup/thread-requests-BLvGkP2R.mjs +2205 -0
  107. package/dist/{thread-resume-DsDOZpFg.js → .setup/thread-resume-DIBXwOpE.mjs} +8 -5
  108. package/dist/.setup/timeout-C910MdAB.mjs +80 -0
  109. package/dist/{transcript-history-projection-v17wXgdK.js → .setup/transcript-history-projection-ZZpkFkJ_.mjs} +96 -61
  110. package/dist/{transcript-mirror-C5CKgNy6.js → .setup/transcript-mirror-BtHDBp1G.mjs} +224 -195
  111. package/dist/{transcript-mirror-attestation-DibE0krH.js → .setup/transcript-mirror-attestation-CzM-94NC.mjs} +4 -1
  112. package/dist/{transport-stdio-BGjHoYLr.js → .setup/transport-stdio-h2VHOskC.mjs} +274 -89
  113. package/dist/{upstream-session-fork-BZerMte_.js → .setup/upstream-session-fork-BUr4OUbC.mjs} +51 -42
  114. package/dist/{usage-tCk-mg_x.js → .setup/usage-BML0r-ua.mjs} +5 -4
  115. package/dist/.setup/usage-limit-error-DUMbefVY.mjs +166 -0
  116. package/dist/{web-search-provider.runtime-B7bGbGWq.js → .setup/web-search-provider.runtime-CDKlN-Rv.mjs} +4 -3
  117. package/dist/api.js +23 -12
  118. package/dist/catalog-page-worker-entrypoint.js +12 -0
  119. package/dist/catalog-page.worker.js +9 -0
  120. package/dist/cli-metadata.js +1 -1
  121. package/dist/doctor-contract-api.js +8 -528
  122. package/dist/harness.js +1 -1
  123. package/dist/index.js +306 -215
  124. package/dist/media-understanding-provider.js +3 -3
  125. package/dist/migration-provider-api.js +1 -1
  126. package/dist/native-tool-policy.js +12 -0
  127. package/dist/provider-discovery.js +18 -0
  128. package/dist/session-history-worker-runtime.js +36 -35
  129. package/dist/session-history.worker.js +2 -2
  130. package/dist/web-search-contract-api.js +1 -1
  131. package/openclaw.plugin.json +354 -69
  132. package/package.json +14 -8
  133. package/dist/attempt-context-D44yeDII.js +0 -636
  134. package/dist/binding-connection-D3udKbIE.js +0 -60
  135. package/dist/event-projector-usage-BfXmpOec.js +0 -102
  136. package/dist/inference-proxy-HGXKUIre.js +0 -311
  137. package/dist/launch-args-RXQwn8zV.js +0 -90
  138. package/dist/native-subagent-history-owner-Pcp7JuVF.js +0 -34
  139. package/dist/native-subagent-monitor-fQ7eIXEf.js +0 -2978
  140. package/dist/node-exec-server.runtime-Cl2vapEi.js +0 -226
  141. package/dist/rpc-error-ttN_QjEm.js +0 -30
  142. package/dist/session-catalog-ct-AH01I.js +0 -1477
  143. package/dist/session-catalog-home-id-CwhLdC03.js +0 -18
  144. package/dist/session-catalog-provenance-D-dIfRAH.js +0 -96
  145. package/dist/timeout-BVw8aaM1.js +0 -33
  146. package/dist/version-omm6IPI3.js +0 -12
  147. /package/dist/{auth-profile-selection-DFu9e167.js → .setup/auth-profile-selection-DFu9e167.mjs} +0 -0
  148. /package/dist/{config-utils-DujwEnhg.js → .setup/config-utils-DujwEnhg.mjs} +0 -0
  149. /package/dist/{context-compaction-activity-CMla5FPJ.js → .setup/context-compaction-activity-CMla5FPJ.mjs} +0 -0
  150. /package/dist/{elicitation-input-DPoK8F7w.js → .setup/elicitation-input-DPoK8F7w.mjs} +0 -0
  151. /package/dist/{history-rejection-B4nOXNXF.js → .setup/history-rejection-B4nOXNXF.mjs} +0 -0
  152. /package/dist/{image-payload-sanitizer-tupAr-2o.js → .setup/image-payload-sanitizer-tupAr-2o.mjs} +0 -0
  153. /package/dist/{incognito-session-uhrBF6wJ.js → .setup/incognito-session-uhrBF6wJ.mjs} +0 -0
  154. /package/dist/{local-runtime-attribution-B_2mnqhb.js → .setup/local-runtime-attribution-B_2mnqhb.mjs} +0 -0
  155. /package/dist/{native-execution-policy-umd0tgh4.js → .setup/native-execution-policy-umd0tgh4.mjs} +0 -0
  156. /package/dist/{rolldown-runtime-8H4AJuhK.js → .setup/rolldown-runtime-8H4AJuhK.mjs} +0 -0
  157. /package/dist/{session-binding-meta-B7aEMU7g.js → .setup/session-binding-meta-B7aEMU7g.mjs} +0 -0
  158. /package/dist/{session-upstream-marker-D15C9NHp.js → .setup/session-upstream-marker-D15C9NHp.mjs} +0 -0
  159. /package/dist/{upstream-prompt-provenance-LphB8slG.js → .setup/upstream-prompt-provenance-LphB8slG.mjs} +0 -0
  160. /package/dist/{web-search-provider.shared-BrZmlqyR.js → .setup/web-search-provider.shared-BrZmlqyR.mjs} +0 -0
@@ -0,0 +1,1170 @@
1
+ import { C as boundedCatalogString, D as filterCatalogPageByTitle, E as codexCatalogThreadStatus, P as readControlCursor, T as codexCatalogThreadName, U as CODEX_CATALOG_MAX_ROWS, b as MAX_CWD_LENGTH, f as setCodexCatalogSource, k as normalizeLimit, l as getCodexCatalogSource, r as projectCodexCatalogNativeThread, v as CatalogParamsError } from "./session-catalog-native-projection-DowriLid.mjs";
2
+ import { i as subscribeCodexCatalogEvents } from "./session-catalog-events-Bj6j94E_.mjs";
3
+ import { i as retainCodexCatalogRow, n as codexCatalogRowRecency, r as compareCodexCatalogRows, t as CodexCatalogOrdering } from "./session-catalog-index-order-hcdz07yN.mjs";
4
+ import { n as CodexCatalogPersistence, r as codexCatalogMetadataPage } from "./session-catalog-index-state-Dgh8ORJm.mjs";
5
+ import { a as withCodexCatalogListRequest, s as CodexCatalogAvailability } from "./session-catalog-Pno1xGcl.mjs";
6
+ import { a as reportCodexCatalogSpawnFailure, n as findCodexAppServerSpawnError } from "./spawn-error-CL3n6MAa.mjs";
7
+ 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-zK_PUsiE.mjs";
8
+ import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
9
+ import { createHash } from "node:crypto";
10
+ import { isDeepStrictEqual } from "node:util";
11
+ import { embeddedAgentLog } from "openclaw/plugin-sdk/agent-harness-registration";
12
+ import { setImmediate as setImmediate$1 } from "node:timers/promises";
13
+ import { coerceErrorMessage, toErrorObject } from "openclaw/plugin-sdk/error-runtime";
14
+ import { sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
15
+ //#region extensions/codex/src/session-catalog-currency.ts
16
+ const SAFETY_INTERVAL_MS = 9e5;
17
+ /** One periodic reconciliation cycle per home, without a recursive watcher inventory. */
18
+ var CodexCatalogCurrency = class {
19
+ constructor(options) {
20
+ this.options = options;
21
+ this.closed = false;
22
+ this.nativeDirty = false;
23
+ this.nextNativeAt = 0;
24
+ this.nextFilesAt = 0;
25
+ }
26
+ hasActiveWork() {
27
+ return this.hydration !== void 0 || this.initial !== void 0 || this.running !== void 0;
28
+ }
29
+ assertRunnable() {
30
+ if (this.terminalFailure) throw this.terminalFailure;
31
+ }
32
+ stopForTerminalFailure(error) {
33
+ const failure = findCodexAppServerSpawnError(error);
34
+ if (!failure) return false;
35
+ if (!this.closed) {
36
+ this.terminalFailure = failure;
37
+ this.close();
38
+ reportCodexCatalogSpawnFailure(failure);
39
+ }
40
+ return true;
41
+ }
42
+ scheduleHydration(run) {
43
+ if (this.closed || this.hydration) return;
44
+ this.hydration = setImmediate(() => {
45
+ this.hydration = void 0;
46
+ (this.options.runBackground ? this.options.runBackground(run) : run()).catch((error) => this.options.report(error));
47
+ });
48
+ this.hydration.unref();
49
+ }
50
+ cancelHydration() {
51
+ clearImmediate(this.hydration);
52
+ this.hydration = void 0;
53
+ }
54
+ requestNativeRefresh() {
55
+ this.nativeDirty = true;
56
+ }
57
+ start() {
58
+ if (this.closed || this.timer) return;
59
+ this.nextNativeAt = Date.now() + SAFETY_INTERVAL_MS;
60
+ this.nextFilesAt = this.nextNativeAt;
61
+ this.timer = setInterval(() => {
62
+ if (this.running) return;
63
+ const startedAt = Date.now();
64
+ const full = startedAt >= this.nextNativeAt;
65
+ const filesDue = this.options.local && startedAt >= this.nextFilesAt;
66
+ if (!full && !filesDue && !this.nativeDirty) return;
67
+ const nativeDue = full || this.nativeDirty;
68
+ this.nativeDirty = false;
69
+ if (full) this.nextNativeAt = startedAt + SAFETY_INTERVAL_MS;
70
+ if (filesDue) this.nextFilesAt = startedAt + SAFETY_INTERVAL_MS;
71
+ const run = async () => {
72
+ if (filesDue) await this.options.reconcileFiles();
73
+ if (nativeDue) await this.options.reconcileNative(full);
74
+ };
75
+ this.running = (this.options.runBackground ? this.options.runBackground(run) : run()).catch((error) => {
76
+ this.options.report(new Error(`Codex catalog reconciliation failed; waiting for new activity or the next safety cycle: ${coerceErrorMessage(error)}`, { cause: error }));
77
+ }).finally(() => {
78
+ this.running = void 0;
79
+ });
80
+ }, 3e4);
81
+ this.timer.unref();
82
+ if (this.options.local) {
83
+ this.initial = setTimeout(() => {
84
+ this.initial = void 0;
85
+ this.options.reconcileFiles().catch((error) => this.options.report(error));
86
+ }, 0);
87
+ this.initial.unref();
88
+ }
89
+ }
90
+ close() {
91
+ this.closed = true;
92
+ this.cancelHydration();
93
+ clearInterval(this.timer);
94
+ this.timer = void 0;
95
+ clearTimeout(this.initial);
96
+ this.initial = void 0;
97
+ return this.running;
98
+ }
99
+ };
100
+ //#endregion
101
+ //#region extensions/codex/src/session-catalog-index-cursor.ts
102
+ function readCodexCatalogCursor(homeId, params) {
103
+ const queryId = createHash("sha256").update(JSON.stringify([
104
+ homeId,
105
+ params.cwd?.trim() ?? "",
106
+ params.searchTerm?.trim().toLocaleLowerCase() ?? ""
107
+ ])).digest("hex").slice(0, 16);
108
+ const encoded = readControlCursor(params.cursor, "request");
109
+ if (!encoded) return {
110
+ kind: "resident",
111
+ queryId
112
+ };
113
+ const invalid = () => new CatalogParamsError("invalid Codex resident catalog cursor");
114
+ let value;
115
+ try {
116
+ value = JSON.parse(Buffer.from(encoded, "base64url").toString());
117
+ } catch {
118
+ throw invalid();
119
+ }
120
+ if (!Array.isArray(value) || value.length !== 5 || value[0] !== queryId) throw invalid();
121
+ if (value[1] === "native") {
122
+ if (value[2] !== null && typeof value[2] !== "string" || typeof value[3] !== "boolean" || value[4] !== null && (typeof value[4] !== "string" || !value[4] || value[4].length > 256)) throw invalid();
123
+ return {
124
+ kind: "native",
125
+ queryId,
126
+ backwards: value[3],
127
+ ...value[2] !== null ? { cursor: readControlCursor(value[2], "native request") } : {},
128
+ ...value[4] !== null ? { anchorThreadId: value[4] } : {}
129
+ };
130
+ }
131
+ if (typeof value[1] !== "number" || !Number.isFinite(value[1]) || typeof value[2] !== "string" || value[2].length > 256 || typeof value[3] !== "number" || !Number.isSafeInteger(value[3]) || typeof value[4] !== "boolean") throw invalid();
132
+ return {
133
+ kind: "resident",
134
+ queryId,
135
+ anchor: {
136
+ updatedAt: value[1],
137
+ recencyAt: value[1],
138
+ threadId: value[2],
139
+ sourceOrder: value[3],
140
+ backwards: value[4]
141
+ }
142
+ };
143
+ }
144
+ function encodeCodexResidentCursor(queryId, row, backwards) {
145
+ return Buffer.from(JSON.stringify([
146
+ queryId,
147
+ codexCatalogRowRecency(row),
148
+ row.threadId,
149
+ row.sourceOrder ?? 0,
150
+ backwards
151
+ ])).toString("base64url");
152
+ }
153
+ function encodeCodexNativeCursor(cursor) {
154
+ const value = Buffer.from(JSON.stringify([
155
+ cursor.queryId,
156
+ "native",
157
+ cursor.cursor ?? null,
158
+ cursor.backwards,
159
+ cursor.anchorThreadId ?? null
160
+ ])).toString("base64url");
161
+ readControlCursor(value, "native continuation");
162
+ return value;
163
+ }
164
+ //#endregion
165
+ //#region extensions/codex/src/session-catalog-index-events.ts
166
+ /** Event scheduling only; the index owns row publication and stale-read fencing. */
167
+ var CodexCatalogIndexEvents = class {
168
+ constructor(owner) {
169
+ this.owner = owner;
170
+ this.closed = false;
171
+ this.pending = /* @__PURE__ */ new Map();
172
+ this.upserting = /* @__PURE__ */ new Set();
173
+ }
174
+ hasActiveWork() {
175
+ return this.pending.size > 0 || this.upserting.size > 0;
176
+ }
177
+ handle(event, readThread, source) {
178
+ if (this.closed || !isRecord(event.params)) return;
179
+ const params = event.params;
180
+ if (event.method === "thread/started") {
181
+ if (!isRecord(params.thread) || typeof params.thread.id !== "string") return;
182
+ const thread = params.thread;
183
+ if (!thread.ephemeral && !thread.preview?.trim() && thread.recencyAt == null) return;
184
+ if (!this.hasCapacity()) return;
185
+ const operation = this.owner.upsert(setCodexCatalogSource(thread, source)).catch((error) => this.owner.report(error)).finally(() => this.upserting.delete(operation));
186
+ this.upserting.add(operation);
187
+ return;
188
+ }
189
+ const id = boundedCatalogString(params.threadId, 256);
190
+ if (!id) return;
191
+ if (event.method === "thread/archived" || event.method === "thread/deleted") {
192
+ const pending = this.pending.get(id);
193
+ if (pending) {
194
+ pending.dirty = false;
195
+ pending.sourceOrder = void 0;
196
+ }
197
+ if (event.method === "thread/deleted") this.owner.remove(id);
198
+ else this.owner.archive(id);
199
+ return;
200
+ }
201
+ if (event.method === "thread/name/updated") {
202
+ this.owner.rename(id, codexCatalogThreadName(params.threadName ?? null) ?? null);
203
+ return;
204
+ }
205
+ if (event.method === "thread/status/changed") {
206
+ if (!isRecord(params.status)) return;
207
+ this.owner.updateStatus(id, codexCatalogThreadStatus(params.status), source);
208
+ return;
209
+ }
210
+ if (event.method === "thread/settings/updated") {
211
+ const settings = params.threadSettings;
212
+ if (isRecord(settings)) this.owner.updateSettings(id, {
213
+ ...typeof settings.cwd === "string" ? { cwd: settings.cwd } : {},
214
+ ...typeof settings.modelProvider === "string" ? { modelProvider: settings.modelProvider } : {}
215
+ }, source);
216
+ return;
217
+ }
218
+ if (event.method === "turn/started" || event.method === "turn/completed" || event.method === "thread/unarchived" || event.method === "thread/reverted") {
219
+ if (event.method !== "thread/unarchived" && this.owner.get(id)?.archived) return;
220
+ this.enqueueRefresh(id, readThread, source, event.method === "turn/started" ? this.owner.reserveTurnStartOrder() : void 0);
221
+ }
222
+ }
223
+ hasCapacity() {
224
+ if (this.pending.size + this.upserting.size < 2e4) return true;
225
+ this.owner.report(/* @__PURE__ */ new Error("Codex catalog event queue reached its resident row limit"));
226
+ return false;
227
+ }
228
+ enqueueRefresh(id, readThread, source, sourceOrder) {
229
+ this.owner.requestNativeRefresh();
230
+ const existing = this.pending.get(id);
231
+ if (existing) {
232
+ existing.readThread = readThread;
233
+ existing.source = source;
234
+ existing.dirty = true;
235
+ existing.sourceOrder = sourceOrder ?? existing.sourceOrder;
236
+ return;
237
+ }
238
+ if (!this.hasCapacity()) return;
239
+ const pending = {
240
+ readThread,
241
+ source,
242
+ dirty: true,
243
+ sourceOrder,
244
+ promise: Promise.resolve()
245
+ };
246
+ this.pending.set(id, pending);
247
+ pending.promise = Promise.resolve().then(async () => {
248
+ try {
249
+ while (!this.closed && pending.dirty) {
250
+ pending.dirty = false;
251
+ const observedSourceOrder = pending.sourceOrder;
252
+ const observedSource = pending.source;
253
+ try {
254
+ if (observedSource.closed) throw new Error("Codex catalog observation source closed before its metadata read");
255
+ const published = await this.owner.refresh(id, pending.readThread, observedSourceOrder);
256
+ if (published && pending.sourceOrder === observedSourceOrder) pending.sourceOrder = void 0;
257
+ else if (!published && pending.sourceOrder !== void 0) pending.dirty = true;
258
+ } catch (error) {
259
+ if (observedSource.closed) {
260
+ if (pending.source === observedSource) pending.dirty = false;
261
+ this.owner.report(new Error("Codex catalog observation interrupted by client closure; metadata refresh deferred to the current catalog owner", { cause: error }));
262
+ } else this.owner.report(error);
263
+ }
264
+ }
265
+ } finally {
266
+ this.pending.delete(id);
267
+ }
268
+ });
269
+ }
270
+ async close() {
271
+ this.closed = true;
272
+ await Promise.allSettled([...this.upserting, ...[...this.pending.values()].map((entry) => entry.promise)]);
273
+ }
274
+ };
275
+ //#endregion
276
+ //#region extensions/codex/src/session-catalog-index-field.ts
277
+ /** Orders field observations independently from catalog row publication. */
278
+ var CodexCatalogField = class {
279
+ constructor() {
280
+ this.revision = 0;
281
+ this.minimumCapture = 0;
282
+ this.entries = /* @__PURE__ */ new Map();
283
+ }
284
+ capture() {
285
+ return ++this.revision;
286
+ }
287
+ update(threadId, value) {
288
+ this.put(threadId, {
289
+ revision: ++this.revision,
290
+ value
291
+ });
292
+ }
293
+ observe(threadId, value, capturedRevision) {
294
+ if (capturedRevision < this.minimumCapture || (this.entries.get(threadId)?.revision ?? 0) > capturedRevision) return false;
295
+ this.put(threadId, {
296
+ revision: capturedRevision,
297
+ value
298
+ });
299
+ return true;
300
+ }
301
+ get(threadId) {
302
+ return this.entries.get(threadId)?.value;
303
+ }
304
+ some(predicate) {
305
+ for (const entry of this.entries.values()) if (entry.value !== void 0 && predicate(entry.value)) return true;
306
+ return false;
307
+ }
308
+ delete(threadId) {
309
+ this.put(threadId, { revision: ++this.revision });
310
+ }
311
+ deleteWhere(predicate) {
312
+ for (const [threadId, entry] of this.entries) if (entry.value !== void 0 && predicate(entry.value)) this.delete(threadId);
313
+ }
314
+ invalidate() {
315
+ this.minimumCapture = ++this.revision;
316
+ this.entries.clear();
317
+ }
318
+ put(threadId, entry) {
319
+ const id = boundedCatalogString(threadId, 256);
320
+ if (!id) return;
321
+ this.entries.delete(id);
322
+ this.entries.set(id, entry);
323
+ if (this.entries.size > 2e4) {
324
+ const oldest = this.entries.entries().next().value;
325
+ if (oldest) {
326
+ this.minimumCapture = Math.max(this.minimumCapture, oldest[1].revision);
327
+ this.entries.delete(oldest[0]);
328
+ }
329
+ }
330
+ }
331
+ };
332
+ //#endregion
333
+ //#region extensions/codex/src/session-catalog-index-names.ts
334
+ function applyCodexCatalogName(row, name) {
335
+ if (name === void 0) return row;
336
+ return {
337
+ ...row,
338
+ page: { sessions: row.page.sessions.map(({ fallbackName: _fallback, ...session }) => ({
339
+ ...session,
340
+ name,
341
+ ...!name && row.preview ? { fallbackName: row.preview } : {}
342
+ })) }
343
+ };
344
+ }
345
+ //#endregion
346
+ //#region extensions/codex/src/session-catalog-index-observations.ts
347
+ /** Fences asynchronous observations against later catalog mutations. */
348
+ var CodexCatalogObservations = class {
349
+ constructor() {
350
+ this.revision = 0;
351
+ this.minimumCapture = 0;
352
+ this.mutations = /* @__PURE__ */ new Map();
353
+ this.observations = /* @__PURE__ */ new Map();
354
+ }
355
+ hasActiveWork() {
356
+ return this.observations.size > 0;
357
+ }
358
+ mark(threadId) {
359
+ this.revision++;
360
+ if (this.observations.size) {
361
+ const id = boundedCatalogString(threadId, 256);
362
+ if (!id) return;
363
+ this.mutations.delete(id);
364
+ this.mutations.set(id, this.revision);
365
+ if (this.mutations.size > 2e4) {
366
+ const oldest = this.mutations.entries().next().value;
367
+ this.minimumCapture = Math.max(this.minimumCapture, oldest[1]);
368
+ this.mutations.delete(oldest[0]);
369
+ }
370
+ }
371
+ }
372
+ async observe(read) {
373
+ const token = Symbol("catalog observation");
374
+ const revision = this.revision;
375
+ this.observations.set(token, revision);
376
+ try {
377
+ return await read((id) => revision >= this.minimumCapture && (this.mutations.get(id) ?? 0) <= revision);
378
+ } finally {
379
+ this.observations.delete(token);
380
+ const oldest = this.observations.values().next().value ?? Infinity;
381
+ for (const [id, changed] of this.mutations) {
382
+ if (changed > oldest) break;
383
+ this.mutations.delete(id);
384
+ }
385
+ }
386
+ }
387
+ };
388
+ //#endregion
389
+ //#region extensions/codex/src/session-catalog-index-query.ts
390
+ /** Keyset pagination remains valid when the anchor row is archived or deleted. */
391
+ function prepareCodexCatalogQuery(params, prepared) {
392
+ const limit = Math.min(normalizeLimit(params.limit, "limit"), 64);
393
+ const cwd = params.cwd?.trim();
394
+ const search = params.searchTerm?.trim().toLocaleLowerCase();
395
+ const { queryId, anchor } = prepared;
396
+ const cursor = (row, backwards) => encodeCodexResidentCursor(queryId, row, backwards);
397
+ return (ordered, liveStatus, liveSettings, availability) => {
398
+ const { complete, frontier } = availability;
399
+ if (!complete && !frontier) return;
400
+ if (!complete && frontier && anchor?.backwards && compareCodexCatalogRows(frontier, anchor) < 0) return;
401
+ const candidates = complete && !cwd && !search ? ordered : ordered.filter((row) => {
402
+ const session = row.page.sessions[0];
403
+ 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));
404
+ });
405
+ const selected = anchor?.backwards ? candidates.filter((row) => row.threadId !== anchor.threadId) : candidates;
406
+ let start = 0;
407
+ let end;
408
+ const after = (row) => !anchor || compareCodexCatalogRows(row, anchor) > 0;
409
+ if (anchor) {
410
+ const at = selected.findIndex(after);
411
+ const boundary = at < 0 ? selected.length : at;
412
+ if (anchor.backwards) {
413
+ end = boundary;
414
+ start = Math.max(0, boundary - limit);
415
+ } else start = boundary;
416
+ }
417
+ let page = selected.slice(start, end ?? start + limit);
418
+ if (anchor?.backwards && !page.length) {
419
+ start = 0;
420
+ page = candidates.slice(0, limit);
421
+ }
422
+ const first = page[0];
423
+ const last = page.at(-1);
424
+ let continuation = last && (anchor?.backwards ? !complete || candidates.some((row) => compareCodexCatalogRows(row, last) > 0) : start + page.length < selected.length) ? last : void 0;
425
+ if (!complete && !continuation) {
426
+ if (!anchor?.backwards && !last && (!frontier || !after(frontier))) return;
427
+ continuation = frontier && (!last || compareCodexCatalogRows(frontier, last) > 0) ? frontier : last;
428
+ }
429
+ return {
430
+ sessions: page.flatMap((row) => row.page.sessions.map(({ status: _storedStatus, activeFlags: _storedFlags, ...session }) => {
431
+ const live = liveStatus.get(row.threadId);
432
+ return {
433
+ ...session,
434
+ ...liveSettings.get(row.threadId),
435
+ status: live?.status ?? "notLoaded",
436
+ ...live?.activeFlags ? { activeFlags: [...live.activeFlags] } : {}
437
+ };
438
+ })),
439
+ ...continuation ? { nextCursor: cursor(continuation, false) } : {},
440
+ ...first && start > 0 ? { backwardsCursor: cursor(first, true) } : {}
441
+ };
442
+ };
443
+ }
444
+ //#endregion
445
+ //#region extensions/codex/src/session-catalog-native-page.ts
446
+ /** Background walks share bounded native pages; the index decides when a prefix is current. */
447
+ async function* readCodexCatalogHydrationPages(read, useStateDbOnly) {
448
+ let cursor;
449
+ let offset = 0;
450
+ const cursors = /* @__PURE__ */ new Set();
451
+ do {
452
+ const page = await read({
453
+ archived: false,
454
+ modelProviders: [],
455
+ sortKey: "recency_at",
456
+ sortDirection: "desc",
457
+ limit: 64,
458
+ ...useStateDbOnly ? { useStateDbOnly } : {},
459
+ ...cursor ? { cursor } : {}
460
+ }, Math.max(0, CODEX_CATALOG_MAX_ROWS - offset));
461
+ cursor = readControlCursor(page.nextCursor, "hydration response");
462
+ if (cursor && cursors.has(cursor)) throw new Error("Codex catalog repeated a hydration cursor");
463
+ if (cursor) {
464
+ cursors.add(cursor);
465
+ if (cursors.size > 2e4) cursors.delete(cursors.values().next().value);
466
+ }
467
+ yield {
468
+ ...page,
469
+ nextCursor: cursor,
470
+ offset
471
+ };
472
+ offset += page.rows.length;
473
+ await setImmediate$1();
474
+ } while (cursor);
475
+ }
476
+ /** The resident limit bounds storage, never authoritative discovery. */
477
+ var CodexCatalogNativePages = class {
478
+ constructor(settings, status) {
479
+ this.settings = settings;
480
+ this.status = status;
481
+ }
482
+ async list(params, prepared, options, request) {
483
+ const limit = Math.min(normalizeLimit(params.limit, "limit"), 64);
484
+ const cwd = params.cwd?.trim();
485
+ let position = prepared.kind === "native" ? prepared : {
486
+ kind: "native",
487
+ queryId: prepared.queryId,
488
+ backwards: prepared.anchor?.backwards ?? false,
489
+ ...prepared.anchor ? { anchorThreadId: prepared.anchor.threadId } : {}
490
+ };
491
+ const at = (cursor, backwards, anchorThreadId) => ({
492
+ kind: "native",
493
+ queryId: prepared.queryId,
494
+ backwards,
495
+ ...cursor ? { cursor } : {},
496
+ ...anchorThreadId ? { anchorThreadId } : {}
497
+ });
498
+ while (request.hasPages) {
499
+ options.assertCurrent();
500
+ const filterCwdLocally = Boolean(cwd && this.settings.hasLiveCwd());
501
+ const ascending = position.backwards && !position.anchorThreadId;
502
+ const pageLimit = position.anchorThreadId ? 64 : limit;
503
+ const statusRevision = this.status.capture();
504
+ const page = await request.read(Number.POSITIVE_INFINITY, () => options.readNative({
505
+ archived: false,
506
+ modelProviders: [],
507
+ useStateDbOnly: true,
508
+ sortKey: "recency_at",
509
+ sortDirection: ascending ? "asc" : "desc",
510
+ limit: pageLimit,
511
+ ...cwd && !filterCwdLocally ? { cwd } : {},
512
+ ...position.cursor ? { cursor: position.cursor } : {}
513
+ }, pageLimit, request));
514
+ options.assertCurrent();
515
+ for (const row of page.rows) this.status.observe(row, statusRevision);
516
+ if (cwd && !filterCwdLocally && this.settings.hasLiveCwd()) continue;
517
+ let rows = ascending ? page.rows.toReversed() : page.rows;
518
+ let next = (ascending ? page.backwardsCursor : page.nextCursor) ? at(ascending ? page.backwardsCursor : page.nextCursor, false) : void 0;
519
+ let previous = (ascending ? page.nextCursor : page.backwardsCursor) ? at(ascending ? page.nextCursor : page.backwardsCursor, true) : void 0;
520
+ if (position.anchorThreadId) {
521
+ const anchor = rows.findIndex((row) => row.threadId === position.anchorThreadId);
522
+ if (anchor < 0) {
523
+ if (!page.nextCursor || page.nextCursor === position.cursor) throw new CatalogParamsError("Codex catalog changed; refresh before continuing this page");
524
+ position = at(page.nextCursor, position.backwards, position.anchorThreadId);
525
+ continue;
526
+ }
527
+ const start = position.backwards ? Math.max(0, anchor - limit) : anchor + 1;
528
+ const end = position.backwards ? anchor : Math.min(rows.length, start + limit);
529
+ const selected = rows.slice(start, end);
530
+ if (!selected.length) {
531
+ const continuation = position.backwards ? previous : next;
532
+ if (continuation) {
533
+ position = continuation;
534
+ continue;
535
+ }
536
+ }
537
+ const first = selected[0];
538
+ const last = selected.at(-1);
539
+ if (first && last) {
540
+ next = end < rows.length ? at(position.cursor, false, last.threadId) : next;
541
+ previous = start > 0 ? at(position.cursor, true, first.threadId) : previous;
542
+ }
543
+ rows = selected;
544
+ } else if (!position.cursor && !position.backwards) previous = void 0;
545
+ const projected = filterCatalogPageByTitle({ sessions: rows.flatMap((row) => row.page.sessions).map(({ status: _storedStatus, activeFlags: _storedFlags, ...session }) => {
546
+ const live = this.status.get(session.threadId);
547
+ return Object.assign(session, this.settings.get(session.threadId), {
548
+ status: live?.status ?? "notLoaded",
549
+ ...live?.activeFlags ? { activeFlags: [...live.activeFlags] } : {}
550
+ });
551
+ }).filter((session) => !cwd || session.cwd === cwd) }, params.searchTerm);
552
+ const continuation = position.backwards ? previous : next;
553
+ if ((params.searchTerm || filterCwdLocally) && !projected.sessions.length && continuation) {
554
+ if (encodeCodexNativeCursor(continuation) === encodeCodexNativeCursor(position)) throw new CatalogParamsError("Codex catalog repeated a native continuation");
555
+ position = continuation;
556
+ continue;
557
+ }
558
+ const managedThreads = rows.flatMap((row) => row.page.managedThreads ?? []);
559
+ return {
560
+ ...projected,
561
+ ...managedThreads.length ? { managedThreads } : {},
562
+ ...next ? { nextCursor: encodeCodexNativeCursor(next) } : {},
563
+ ...previous ? { backwardsCursor: encodeCodexNativeCursor(previous) } : {}
564
+ };
565
+ }
566
+ const continuation = encodeCodexNativeCursor(position);
567
+ return {
568
+ sessions: [],
569
+ ...position.backwards ? { backwardsCursor: continuation } : { nextCursor: continuation }
570
+ };
571
+ }
572
+ };
573
+ //#endregion
574
+ //#region extensions/codex/src/session-catalog-settings.ts
575
+ const MAX_SETTINGS_SOURCE_WITNESSES = 64;
576
+ /** Live settings overlay native stored metadata only while a supporting source stays open. */
577
+ var CodexCatalogSettingsIndex = class {
578
+ constructor() {
579
+ this.values = new CodexCatalogField();
580
+ }
581
+ update(threadId, settings, source) {
582
+ if (source.closed) return;
583
+ const cwd = boundedCatalogString(settings.cwd, MAX_CWD_LENGTH);
584
+ const modelProvider = boundedCatalogString(settings.modelProvider, 500, "truncate");
585
+ if (!cwd && !modelProvider) return;
586
+ const bounded = {
587
+ ...cwd ? { cwd } : {},
588
+ ...modelProvider ? { modelProvider } : {}
589
+ };
590
+ const current = this.values.get(threadId);
591
+ const sources = /* @__PURE__ */ new Set();
592
+ if (current && current.settings.cwd === bounded.cwd && current.settings.modelProvider === bounded.modelProvider) {
593
+ for (const witness of current.sources) if (!witness.closed) sources.add(witness);
594
+ }
595
+ if (sources.size < MAX_SETTINGS_SOURCE_WITNESSES) sources.add(source);
596
+ this.values.update(threadId, {
597
+ settings: bounded,
598
+ sources
599
+ });
600
+ }
601
+ get(threadId) {
602
+ const current = this.values.get(threadId);
603
+ if (current) {
604
+ for (const source of current.sources) if (!source.closed) return current.settings;
605
+ }
606
+ }
607
+ hasLiveCwd() {
608
+ return this.values.some(({ settings, sources }) => {
609
+ if (settings.cwd) {
610
+ for (const source of sources) if (!source.closed) return true;
611
+ }
612
+ return false;
613
+ });
614
+ }
615
+ delete(threadId) {
616
+ this.values.delete(threadId);
617
+ }
618
+ withdraw(threadId, source) {
619
+ const current = this.values.get(threadId);
620
+ if (!current?.sources.delete(source)) return;
621
+ for (const witness of current.sources) if (!witness.closed) return;
622
+ this.values.delete(threadId);
623
+ }
624
+ invalidate(source) {
625
+ if (!source) {
626
+ this.values.invalidate();
627
+ return;
628
+ }
629
+ this.values.deleteWhere((entry) => {
630
+ entry.sources.delete(source);
631
+ for (const witness of entry.sources) if (!witness.closed) return false;
632
+ return true;
633
+ });
634
+ }
635
+ };
636
+ //#endregion
637
+ //#region extensions/codex/src/session-catalog-status.ts
638
+ const MAX_STATUS_SOURCE_WITNESSES = 64;
639
+ /** Equivalent broadcasts retain at most 64 source witnesses for each bounded resident row. */
640
+ var CodexCatalogStatusIndex = class {
641
+ constructor() {
642
+ this.values = new CodexCatalogField();
643
+ }
644
+ capture() {
645
+ return this.values.capture();
646
+ }
647
+ update(threadId, status, source) {
648
+ const next = this.next(threadId, status, source);
649
+ if (next) this.values.update(threadId, next);
650
+ }
651
+ observe(row, revision) {
652
+ const session = row.page.sessions[0];
653
+ const source = getCodexCatalogSource(row);
654
+ if (session && source) {
655
+ const next = this.next(row.threadId, {
656
+ status: session.status,
657
+ ...session.activeFlags ? { activeFlags: session.activeFlags } : {}
658
+ }, source);
659
+ if (next) this.values.observe(row.threadId, next, revision);
660
+ }
661
+ }
662
+ get(threadId) {
663
+ const current = this.values.get(threadId);
664
+ if (current) {
665
+ for (const source of current.sources) if (!source.closed) return current.status;
666
+ }
667
+ }
668
+ delete(threadId) {
669
+ this.values.delete(threadId);
670
+ }
671
+ invalidate(source) {
672
+ if (!source) {
673
+ this.values.invalidate();
674
+ return;
675
+ }
676
+ this.values.deleteWhere((entry) => {
677
+ entry.sources.delete(source);
678
+ for (const witness of entry.sources) if (!witness.closed) return false;
679
+ return true;
680
+ });
681
+ }
682
+ next(threadId, status, source) {
683
+ if (source.closed) return;
684
+ const current = this.values.get(threadId);
685
+ const sources = new Set([...current?.sources ?? []].filter((witness) => !witness.closed));
686
+ if (status.status === "notLoaded" && current && current.status.status !== "notLoaded" && sources.size) {
687
+ sources.delete(source);
688
+ if (sources.size) return {
689
+ status: current.status,
690
+ sources
691
+ };
692
+ }
693
+ const flags = status.activeFlags ?? [];
694
+ const previousFlags = current?.status.activeFlags ?? [];
695
+ if (current?.status.status === status.status && flags.length === previousFlags.length && flags.every((flag, index) => flag === previousFlags[index])) {
696
+ if (sources.size < MAX_STATUS_SOURCE_WITNESSES) sources.add(source);
697
+ return {
698
+ status,
699
+ sources
700
+ };
701
+ }
702
+ return {
703
+ status,
704
+ sources: /* @__PURE__ */ new Set([source])
705
+ };
706
+ }
707
+ };
708
+ //#endregion
709
+ //#region extensions/codex/src/session-catalog-index.ts
710
+ /** One home owns resident queries and authoritative overflow discovery. */
711
+ var CodexCatalogIndex = class {
712
+ constructor(options) {
713
+ this.options = options;
714
+ this.rows = /* @__PURE__ */ new Map();
715
+ this.availability = new CodexCatalogAvailability();
716
+ this.liveStatus = new CodexCatalogStatusIndex();
717
+ this.liveSettings = new CodexCatalogSettingsIndex();
718
+ this.nativePages = new CodexCatalogNativePages(this.liveSettings, this.liveStatus);
719
+ this.names = new CodexCatalogField();
720
+ this.initialized = false;
721
+ this.overflow = false;
722
+ this.needsNativeRefresh = false;
723
+ this.restored = false;
724
+ this.closed = false;
725
+ this.projections = new CodexCatalogProjections();
726
+ this.observedFiles = /* @__PURE__ */ new Map();
727
+ this.obsoleteStoredKeys = /* @__PURE__ */ new Set();
728
+ this.sourceRevision = 0;
729
+ this.ordering = new CodexCatalogOrdering();
730
+ this.observations = new CodexCatalogObservations();
731
+ this.currency = new CodexCatalogCurrency({
732
+ local: Boolean(options.localSessionsRoot),
733
+ reconcileFiles: () => this.reconcile(),
734
+ reconcileNative: (full) => this.reconcileNative(full),
735
+ runBackground: options.runBackground,
736
+ report: (error) => this.report(error)
737
+ });
738
+ this.persistence = new CodexCatalogPersistence(options.state, (error) => this.report(error));
739
+ this.events = new CodexCatalogIndexEvents({
740
+ get: (id) => this.rows.get(id),
741
+ updateStatus: (id, status, source) => {
742
+ this.liveStatus.update(id, status, source);
743
+ if (status.status === "notLoaded") this.liveSettings.withdraw(id, source);
744
+ },
745
+ updateSettings: (id, settings, source) => this.liveSettings.update(id, settings, source),
746
+ rename: (id, name) => {
747
+ this.currency.requestNativeRefresh();
748
+ this.names.update(id, name);
749
+ const row = this.rows.get(id);
750
+ if (row && !this.closed) this.put(row);
751
+ },
752
+ upsert: (thread) => this.upsertThread(thread),
753
+ reserveTurnStartOrder: () => this.ordering.reserveEvent(),
754
+ requestNativeRefresh: () => this.currency.requestNativeRefresh(),
755
+ refresh: (id, readThread, sourceOrder) => this.refreshThread(id, readThread, sourceOrder),
756
+ archive: (id) => this.archive(id),
757
+ remove: (id) => {
758
+ this.currency.requestNativeRefresh();
759
+ this.remove(id);
760
+ },
761
+ report: (error) => this.report(error)
762
+ });
763
+ this.unsubscribe = subscribeCodexCatalogEvents(options.homeId, (event, readThread, source) => this.events.handle(event, readThread, source), {
764
+ onEphemeralThread: (id) => this.remove(id),
765
+ onClose: (source) => {
766
+ this.liveStatus.invalidate(source);
767
+ this.liveSettings.invalidate(source);
768
+ },
769
+ onResume: (response, source) => {
770
+ this.liveSettings.update(response.thread.id, response, source);
771
+ return this.upsertThread(setCodexCatalogSource(response.thread, source));
772
+ },
773
+ onRemoteReady: () => {
774
+ if (this.closed || options.localSessionsRoot) return;
775
+ this.sourceRevision++;
776
+ if (!this.initializing) {
777
+ this.initialized = false;
778
+ this.scheduleHydration();
779
+ }
780
+ }
781
+ });
782
+ }
783
+ assertCurrent() {
784
+ if (this.closed) throw new Error("Codex resident catalog is closed");
785
+ try {
786
+ this.options.assertCurrent();
787
+ } catch (error) {
788
+ this.close();
789
+ throw error;
790
+ }
791
+ }
792
+ report(error) {
793
+ if (!this.closed && !this.currency.stopForTerminalFailure(error)) embeddedAgentLog.warn("Codex resident catalog background update failed", { error });
794
+ }
795
+ withName(row) {
796
+ const known = this.names.get(row.threadId);
797
+ return applyCodexCatalogName(row, known !== void 0 ? known : this.rows.get(row.threadId)?.page.sessions[0]?.name);
798
+ }
799
+ put(candidate) {
800
+ if (this.closed) return;
801
+ const previous = this.rows.get(candidate.threadId);
802
+ const preview = candidate.preview ?? previous?.preview;
803
+ const patched = this.withName({
804
+ ...candidate,
805
+ ...preview !== void 0 ? { preview } : {}
806
+ });
807
+ const row = {
808
+ ...patched,
809
+ page: codexCatalogMetadataPage(patched.page),
810
+ ...patched.rolloutPath ? { rolloutPath: codexCatalogRolloutLogicalPath(patched.rolloutPath) } : {},
811
+ sourceOrder: this.ordering.position(patched, previous)
812
+ };
813
+ if (isDeepStrictEqual(previous, row)) return;
814
+ const oldest = retainCodexCatalogRow(this.rows, row);
815
+ this.overflow ||= this.rows.size >= CODEX_CATALOG_MAX_ROWS;
816
+ this.ordering.invalidate();
817
+ if (oldest?.threadId === row.threadId) return;
818
+ if (oldest) this.evict(oldest.threadId);
819
+ this.persistence.put(row);
820
+ }
821
+ evict(threadId) {
822
+ this.rows.delete(threadId);
823
+ this.ordering.invalidate();
824
+ this.persistence.remove(threadId);
825
+ }
826
+ remove(threadId) {
827
+ this.observations.mark(threadId);
828
+ this.evict(threadId);
829
+ this.liveStatus.delete(threadId);
830
+ this.liveSettings.delete(threadId);
831
+ this.names.delete(threadId);
832
+ }
833
+ async initialize() {
834
+ this.assertCurrent();
835
+ this.currency.assertRunnable();
836
+ this.currency.cancelHydration();
837
+ if (this.initialized && !this.needsNativeRefresh) return;
838
+ if (!this.initializing) {
839
+ this.availability.begin();
840
+ const sourceRevision = this.sourceRevision;
841
+ this.initializing = (async () => {
842
+ await this.restore();
843
+ await this.persistence.pruneObsolete(this.obsoleteStoredKeys, this.rows.values());
844
+ this.obsoleteStoredKeys.clear();
845
+ await this.reconcilingNative?.catch((error) => this.report(error));
846
+ if (!this.initialized) {
847
+ let observedRevision;
848
+ do
849
+ observedRevision = await this.hydrate(this.availability.complete);
850
+ while (observedRevision !== this.sourceRevision);
851
+ this.needsNativeRefresh = false;
852
+ }
853
+ if (this.needsNativeRefresh) {
854
+ await this.reconcile();
855
+ await this.reconcileNative();
856
+ this.needsNativeRefresh = false;
857
+ }
858
+ this.initialized = true;
859
+ this.failure = void 0;
860
+ this.currency.start();
861
+ })().catch((error) => {
862
+ this.failure = { error };
863
+ this.availability.fail(error);
864
+ this.currency.stopForTerminalFailure(error);
865
+ throw error;
866
+ }).finally(() => {
867
+ this.initializing = void 0;
868
+ if (this.failure && sourceRevision !== this.sourceRevision) this.scheduleHydration();
869
+ });
870
+ }
871
+ return this.initializing;
872
+ }
873
+ async restore() {
874
+ if (this.restored) return;
875
+ this.restoring ??= this.observations.observe(async (isCurrent) => {
876
+ try {
877
+ const snapshot = await this.persistence.readSnapshot();
878
+ this.assertCurrent();
879
+ if (snapshot.cleanupIncomplete) this.persistence.invalidate(/* @__PURE__ */ new Error("Codex catalog obsolete snapshot exceeds its cleanup limit"));
880
+ for (const key of snapshot.obsolete) this.obsoleteStoredKeys.add(key);
881
+ for (const row of snapshot.rows) if (isCurrent(row.threadId)) {
882
+ const restored = row.rolloutPath ? {
883
+ ...row,
884
+ rolloutPath: codexCatalogRolloutLogicalPath(row.rolloutPath)
885
+ } : row;
886
+ const patched = this.withName(restored);
887
+ if (patched !== restored) this.persistence.put(patched);
888
+ const evicted = retainCodexCatalogRow(this.rows, patched);
889
+ if (evicted) this.evict(evicted.threadId);
890
+ this.ordering.restore(row);
891
+ }
892
+ this.overflow ||= snapshot.overflow || this.rows.size >= 2e4;
893
+ if (snapshot.complete) {
894
+ this.availability.publish(void 0, true);
895
+ this.initialized = true;
896
+ this.needsNativeRefresh = true;
897
+ this.currency.start();
898
+ }
899
+ } catch (error) {
900
+ this.persistence.invalidate(error);
901
+ }
902
+ this.restored = true;
903
+ });
904
+ await this.restoring;
905
+ }
906
+ scheduleHydration() {
907
+ if (this.initialized && !this.needsNativeRefresh || this.initializing || this.closed) return;
908
+ this.currency.scheduleHydration(() => this.initialize());
909
+ }
910
+ captureFields() {
911
+ return {
912
+ status: this.liveStatus.capture(),
913
+ name: this.names.capture()
914
+ };
915
+ }
916
+ observeFields(row, revision) {
917
+ const session = row.page.sessions[0];
918
+ if (!session) return;
919
+ this.liveStatus.observe(row, revision.status);
920
+ if (session.name !== void 0 && this.names.observe(row.threadId, session.name, revision.name)) {
921
+ const current = this.rows.get(row.threadId);
922
+ if (current && current.page.sessions[0]?.name !== session.name) this.put(current);
923
+ }
924
+ }
925
+ reconcileNative(full = true) {
926
+ if (!this.options.localSessionsRoot && this.initializing && !this.initialized) return this.initializing;
927
+ if (!this.reconcilingNative) this.reconcilingNative = this.hydrate(true, !full).then(() => void 0).finally(() => {
928
+ this.reconcilingNative = void 0;
929
+ });
930
+ return this.reconcilingNative;
931
+ }
932
+ hydrate(useStateDbOnly = false, incremental = false) {
933
+ const run = () => this.observations.observe((isCurrent) => this.hydratePages(isCurrent, useStateDbOnly, incremental));
934
+ return this.options.runNativeWalk?.(run) ?? run();
935
+ }
936
+ async hydratePages(isCurrent, useStateDbOnly, incremental) {
937
+ this.assertCurrent();
938
+ const files = this.options.localSessionsRoot && !useStateDbOnly ? (await scanCodexCatalogRollouts(this.options.localSessionsRoot, /* @__PURE__ */ new Set())).files : /* @__PURE__ */ new Map();
939
+ let observedRevision;
940
+ let frontier;
941
+ const batchOrder = this.ordering.captureBatch(this.availability.complete);
942
+ const remaining = incremental ? void 0 : new Map(this.rows);
943
+ const pages = readCodexCatalogHydrationPages(async (params, remainingRows) => {
944
+ this.assertCurrent();
945
+ const fieldRevision = this.captureFields();
946
+ return {
947
+ ...await this.options.readNative(params, remainingRows),
948
+ fieldRevision,
949
+ sourceRevision: this.sourceRevision
950
+ };
951
+ }, useStateDbOnly);
952
+ for await (const page of pages) {
953
+ this.assertCurrent();
954
+ observedRevision ??= page.sourceRevision;
955
+ let sourceOrder = page.offset;
956
+ let changed = false;
957
+ for (const id of page.excludedThreadIds ?? []) if (isCurrent(id)) {
958
+ changed ||= this.rows.has(id);
959
+ this.remove(id);
960
+ }
961
+ for (const row of page.rows) {
962
+ const position = sourceOrder++;
963
+ if (position >= 2e4) continue;
964
+ remaining?.delete(row.threadId);
965
+ const previous = this.rows.get(row.threadId);
966
+ this.observeFields(row, page.fieldRevision);
967
+ if (!isCurrent(row.threadId)) {
968
+ changed = true;
969
+ continue;
970
+ }
971
+ const fingerprint = resolveCodexCatalogRolloutFingerprint(row.rolloutPath, useStateDbOnly ? previous : void 0, files);
972
+ this.observations.mark(row.threadId);
973
+ this.put({
974
+ ...row,
975
+ sourceOrder: batchOrder(row, previous, position),
976
+ ...fingerprint ? { fingerprint } : {}
977
+ });
978
+ changed ||= this.rows.get(row.threadId) !== previous;
979
+ frontier = this.rows.get(row.threadId) ?? frontier;
980
+ }
981
+ if (incremental && (!changed && page.rows.length > 0 || sourceOrder >= 2e4)) break;
982
+ if (page.nextCursor) this.availability.publish(frontier);
983
+ }
984
+ if (remaining && (!useStateDbOnly || !this.options.localSessionsRoot)) {
985
+ for (const [id, row] of remaining) if (isCurrent(id) && this.rows.get(id) === row) this.remove(id);
986
+ }
987
+ this.availability.publish(frontier, true);
988
+ await this.persistence.finishHydration(this.overflow);
989
+ return observedRevision ?? this.sourceRevision;
990
+ }
991
+ reconcile() {
992
+ if (!this.reconciling) this.reconciling = this.observations.observe((isCurrent) => this.reconcileFiles(isCurrent)).finally(() => {
993
+ this.reconciling = void 0;
994
+ });
995
+ return this.reconciling;
996
+ }
997
+ async reconcileFiles(isCurrent) {
998
+ const root = this.options.localSessionsRoot;
999
+ if (!root || !this.initialized || this.closed) return;
1000
+ this.assertCurrent();
1001
+ const byPath = indexCodexCatalogRowsByRollout(this.rows.values());
1002
+ const { files, present } = await scanCodexCatalogRollouts(root, new Set(byPath.keys()));
1003
+ this.assertCurrent();
1004
+ const observed = new Map(files);
1005
+ for (const [file, fingerprint] of files) {
1006
+ const previous = byPath.get(codexCatalogRolloutLogicalPath(file));
1007
+ const known = this.observedFiles.get(file) ?? previous?.fingerprint;
1008
+ if (known?.mtimeMs === fingerprint.mtimeMs && known.size === fingerprint.size) continue;
1009
+ this.currency.requestNativeRefresh();
1010
+ observed.delete(file);
1011
+ if (known) observed.set(file, known);
1012
+ let thread;
1013
+ try {
1014
+ thread = await readCodexCatalogRollout(root, file);
1015
+ } catch (error) {
1016
+ this.assertCurrent();
1017
+ this.report(error);
1018
+ continue;
1019
+ }
1020
+ this.assertCurrent();
1021
+ if (!thread) {
1022
+ observed.set(file, fingerprint);
1023
+ continue;
1024
+ }
1025
+ if (!isCurrent(thread.id)) continue;
1026
+ const existing = this.rows.get(thread.id);
1027
+ if (existing?.rolloutPath && codexCatalogRolloutLogicalPath(existing.rolloutPath) !== codexCatalogRolloutLogicalPath(file)) {
1028
+ observed.set(file, fingerprint);
1029
+ continue;
1030
+ }
1031
+ if (!existing && !thread.preview) {
1032
+ observed.set(file, fingerprint);
1033
+ continue;
1034
+ }
1035
+ thread.preview ||= existing?.preview;
1036
+ const projected = await projectCodexCatalogThread(thread, root);
1037
+ this.assertCurrent();
1038
+ if (!isCurrent(thread.id)) continue;
1039
+ observed.set(file, fingerprint);
1040
+ const row = projected.rows[0];
1041
+ if (!row) continue;
1042
+ this.observations.mark(row.threadId);
1043
+ this.put(mergeCodexCatalogRolloutRow(row, existing, fingerprint));
1044
+ await setImmediate$1();
1045
+ }
1046
+ for (const row of byPath.values()) if (row.rolloutPath && isCodexCatalogRolloutPathCovered(root, row.rolloutPath) && !present.has(codexCatalogRolloutLogicalPath(row.rolloutPath)) && this.rows.get(row.threadId) === row) {
1047
+ this.currency.requestNativeRefresh();
1048
+ this.remove(row.threadId);
1049
+ }
1050
+ this.observedFiles = observed;
1051
+ }
1052
+ upsertThread(thread) {
1053
+ if (this.closed) return Promise.resolve();
1054
+ try {
1055
+ this.assertCurrent();
1056
+ } catch {
1057
+ return Promise.resolve();
1058
+ }
1059
+ try {
1060
+ this.currency.requestNativeRefresh();
1061
+ return this.upsertPreparedThread(projectCodexCatalogNativeThread(thread, sanitizeTerminalText));
1062
+ } catch (error) {
1063
+ return Promise.reject(toErrorObject(error, "Codex catalog projection failed"));
1064
+ }
1065
+ }
1066
+ upsertPreparedThread(prepared) {
1067
+ return this.projections.run(() => {
1068
+ this.observations.mark(prepared.id);
1069
+ const fields = this.captureFields();
1070
+ return this.observations.observe((isCurrent) => this.projectThread(prepared, isCurrent, fields));
1071
+ }).then(() => void 0).catch((error) => {
1072
+ if (!(error instanceof CodexCatalogProjectionCapacityError)) throw error;
1073
+ this.report(error);
1074
+ });
1075
+ }
1076
+ refreshThread(id, readThread, sourceOrder) {
1077
+ this.assertCurrent();
1078
+ this.observations.mark(id);
1079
+ const fields = this.captureFields();
1080
+ return this.projections.run(() => this.observations.observe((isCurrent) => readThread(id).then((thread) => {
1081
+ const prepared = projectCodexCatalogNativeThread(thread, sanitizeTerminalText);
1082
+ if (prepared.id !== id) throw new Error("Codex catalog refresh returned a different thread");
1083
+ return this.closed ? true : this.projectThread(prepared, isCurrent, fields, sourceOrder);
1084
+ })));
1085
+ }
1086
+ async projectThread(thread, isCurrent, fieldRevision, sourceOrder) {
1087
+ const projected = await projectCodexCatalogThread(thread, this.options.localSessionsRoot);
1088
+ if (this.closed) return true;
1089
+ const row = projected.rows[0];
1090
+ if (row) this.observeFields(row, fieldRevision);
1091
+ if (!isCurrent(thread.id)) return false;
1092
+ if (projected.excludedThreadIds?.includes(thread.id)) this.remove(thread.id);
1093
+ if (row) {
1094
+ const previous = this.rows.get(thread.id);
1095
+ const fingerprint = resolveCodexCatalogRolloutFingerprint(row.rolloutPath, previous);
1096
+ this.observations.mark(thread.id);
1097
+ this.put({
1098
+ ...row,
1099
+ ...sourceOrder !== void 0 ? { sourceOrder } : {},
1100
+ ...fingerprint ? { fingerprint } : {}
1101
+ });
1102
+ }
1103
+ return true;
1104
+ }
1105
+ archive(threadId) {
1106
+ if (this.closed) return;
1107
+ this.currency.requestNativeRefresh();
1108
+ this.observations.mark(threadId);
1109
+ this.liveStatus.delete(threadId);
1110
+ this.liveSettings.delete(threadId);
1111
+ this.names.delete(threadId);
1112
+ const row = this.rows.get(threadId);
1113
+ if (row) this.put({
1114
+ ...row,
1115
+ archived: true
1116
+ });
1117
+ else this.persistence.remove(threadId);
1118
+ }
1119
+ get(threadId) {
1120
+ return this.rows.get(threadId);
1121
+ }
1122
+ hasActiveWork() {
1123
+ return Boolean(this.initializing || !this.restored && this.restoring || this.reconciling || this.reconcilingNative || this.currency.hasActiveWork() || this.observations.hasActiveWork() || this.events.hasActiveWork() || this.persistence.hasActiveWork());
1124
+ }
1125
+ async list(params, deadline = performance.now() + (this.options.requestTimeoutMs ?? 6e4)) {
1126
+ return await withCodexCatalogListRequest(async (request) => {
1127
+ const expiresAt = request.constrainDeadline(deadline);
1128
+ const cursor = readCodexCatalogCursor(this.options.homeId, params);
1129
+ const query = cursor.kind === "resident" ? prepareCodexCatalogQuery(params, cursor) : void 0;
1130
+ await this.availability.until(this.restore(), expiresAt);
1131
+ this.assertCurrent();
1132
+ this.scheduleHydration();
1133
+ for (;;) {
1134
+ this.assertCurrent();
1135
+ const ordered = this.ordering.read(this.rows);
1136
+ const page = query?.(ordered, this.liveStatus, this.liveSettings, this.availability);
1137
+ if (cursor.kind === "native" || this.overflow && (params.cwd || params.searchTerm || page && !page.nextCursor)) return await this.nativePages.list(params, cursor, this.options, request);
1138
+ if (page) return page;
1139
+ await this.availability.next(expiresAt);
1140
+ }
1141
+ });
1142
+ }
1143
+ /** Fence future publications before a replacement opens the same persisted home. */
1144
+ retire() {
1145
+ this.closed = true;
1146
+ this.availability.fail(/* @__PURE__ */ new Error("Codex resident catalog is closed"));
1147
+ this.liveStatus.invalidate();
1148
+ this.liveSettings.invalidate();
1149
+ this.unsubscribe();
1150
+ this.currency.close();
1151
+ return this.persistence.retire();
1152
+ }
1153
+ async close() {
1154
+ const writes = this.retire();
1155
+ await Promise.allSettled([
1156
+ this.initializing,
1157
+ this.restoring,
1158
+ this.reconciling,
1159
+ this.reconcilingNative,
1160
+ this.currency.close(),
1161
+ writes,
1162
+ this.events.close()
1163
+ ]);
1164
+ this.rows.clear();
1165
+ this.observedFiles.clear();
1166
+ this.ordering.invalidate();
1167
+ }
1168
+ };
1169
+ //#endregion
1170
+ export { CodexCatalogIndex };