@openclaw/codex 2026.9.5 → 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 (120) hide show
  1. package/dist/.setup/{account-usage-runtime-C2MOIvfq.mjs → account-usage-runtime-Eem_WGqY.mjs} +5 -5
  2. package/dist/.setup/{apply-CJ0ZfmBG.mjs → apply-DDOi8uNx.mjs} +22 -28
  3. package/dist/.setup/{attempt-client-cleanup-BpYKdTA0.mjs → attempt-client-cleanup-CEv1cKwF.mjs} +58 -43
  4. package/dist/.setup/attempt-workspace-context-DUVEn_CS.mjs +331 -0
  5. package/dist/.setup/{auth-cache-key-QirmgiCo.mjs → auth-cache-key-B2mpaI9D.mjs} +9 -81
  6. package/dist/.setup/auth-profile-health-oHizqgye.mjs +53 -0
  7. package/dist/.setup/auth-profile-recovery-BREezV0L.mjs +14 -0
  8. package/dist/.setup/{binding-connection-Bm38niE8.mjs → binding-connection-ThoatDcb.mjs} +1 -1
  9. package/dist/.setup/{binding-connection.runtime-CnRMC0ta.mjs → binding-connection.runtime-yoHrABt-.mjs} +4 -4
  10. package/dist/.setup/{bounded-turn-BtlZcivC.mjs → bounded-turn-B2HScEgT.mjs} +138 -32
  11. package/dist/.setup/{build-state-Xx9ybZqa.mjs → build-state-C7EnDVgr.mjs} +1 -1
  12. package/dist/.setup/{capabilities-_vXcZGSx.mjs → capabilities-CDXOOFdZ.mjs} +1 -1
  13. package/dist/.setup/{client-vXs2929Q.mjs → client-Cs08OXVQ.mjs} +583 -559
  14. package/dist/.setup/client-catalog-response-BMgt_4q4.mjs +285 -0
  15. package/dist/.setup/{command-dispatch-naHIZwwF.mjs → command-dispatch-B4JuOsOk.mjs} +8 -4
  16. package/dist/.setup/{command-formatters-CGEkdawF.mjs → command-formatters-Bmqvr9tO.mjs} +8 -4
  17. package/dist/.setup/{command-handlers-BtAJEW1X.mjs → command-handlers-DW7Lx9oH.mjs} +106 -172
  18. package/dist/.setup/{command-rpc-DHFpn4le.mjs → command-rpc-DixIj3HW.mjs} +36 -21
  19. package/dist/.setup/{compact-C3i3qlzj.mjs → compact-Du5UvtxA.mjs} +14 -21
  20. package/dist/.setup/{config-CedDWjM-.mjs → config-BoTP_mrL.mjs} +3 -3
  21. package/dist/.setup/{config-options-BsanJ8QG.mjs → config-options-BvaRs51b.mjs} +46 -30
  22. package/dist/.setup/{config-runtime-CeAhl_h4.mjs → config-runtime-C8Rw1m1m.mjs} +1 -1
  23. package/dist/.setup/{config-security-BRQ2mgW9.mjs → config-security-BEReZ6go.mjs} +35 -120
  24. package/dist/.setup/{conversation-binding-DhzrpTM6.mjs → conversation-binding-DP-gMrBP.mjs} +21 -32
  25. package/dist/.setup/{conversation-control-DN53ns41.mjs → conversation-control-uK9Jomlc.mjs} +28 -67
  26. package/dist/.setup/{dynamic-tools-D16lOp67.mjs → dynamic-tools-BDXl-8Cw.mjs} +848 -578
  27. package/dist/.setup/{effective-mcp-catalog-K6kLCN8X.mjs → effective-mcp-catalog-CvnvnGIe.mjs} +3 -3
  28. package/dist/.setup/{ephemeral-turn-R1gA8Sn6.mjs → ephemeral-turn-poidXgek.mjs} +9 -6
  29. package/dist/.setup/{event-projector-assistant-message-DNUR1s0A.mjs → event-projector-assistant-message-BsruvNrH.mjs} +2 -4
  30. package/dist/.setup/{event-projector-items-DyTQ_XqL.mjs → event-projector-items-C6L_5ZiT.mjs} +42 -8
  31. package/dist/.setup/{event-projector-usage-C7Ntzs-f.mjs → event-projector-usage-CnBS8Wa3.mjs} +1 -1
  32. package/dist/.setup/{harness-rxaaoN-o.mjs → harness-a_MsE4-_.mjs} +23 -17
  33. package/dist/.setup/{inference-context-fulhZuz8.mjs → inference-context-D96l9-ew.mjs} +1 -1
  34. package/dist/.setup/inference-proxy-b-aJMSxm.mjs +601 -0
  35. package/dist/.setup/{isolated-completion-B6srt48J.mjs → isolated-completion-BIZFhTNG.mjs} +17 -10
  36. package/dist/.setup/launch-args-DbFCehO7.mjs +196 -0
  37. package/dist/.setup/{managed-binary-DP6Rib3P.mjs → managed-binary-BnshlFag.mjs} +13 -2
  38. package/dist/.setup/{model-catalog-DkvUuBey.mjs → model-catalog-CfXJf9Ay.mjs} +9 -10
  39. package/dist/.setup/{models-BDFgm_G-.mjs → models-KnqBv0hE.mjs} +3 -3
  40. package/dist/.setup/{native-auth-BLZGqFjw.mjs → native-auth-rWbGbMn3.mjs} +4 -4
  41. package/dist/.setup/{native-subagent-history-YXaL6dMd.mjs → native-subagent-history-0nYYgo0k.mjs} +26 -13
  42. package/dist/.setup/{native-subagent-monitor-B1hxzIOy.mjs → native-subagent-monitor-D3filLY2.mjs} +145 -317
  43. package/dist/.setup/{native-subagent-task-ids-DsuOonKv.mjs → native-subagent-task-ids-wb8CKZGN.mjs} +69 -39
  44. package/dist/.setup/{node-cli-sessions-Cl8b2ZF3.mjs → node-cli-sessions-r3avj02l.mjs} +86 -68
  45. package/dist/.setup/node-exec-server.runtime-BDwWXVpK.mjs +247 -0
  46. package/dist/.setup/{plan-xD7WKYTM.mjs → plan-CN3VwfNU.mjs} +74 -76
  47. package/dist/.setup/{plugin-activation-r8nq5Jzp.mjs → plugin-activation-DT3MNtqj.mjs} +7 -16
  48. package/dist/.setup/{plugin-app-cache-key-BOxKP7db.mjs → plugin-app-cache-key-B2CsSdnV.mjs} +4 -20
  49. package/dist/.setup/{plugin-approval-roundtrip-CjfzafAZ.mjs → plugin-approval-roundtrip-C0MZzCuP.mjs} +1 -1
  50. package/dist/.setup/{plugin-inventory-DUle8DLz.mjs → plugin-inventory-BoRei8Z4.mjs} +16 -7
  51. package/dist/.setup/{plugin-marketplace-discovery-P-Vndfqq.mjs → plugin-marketplace-discovery-CDOi8IFs.mjs} +4 -1
  52. package/dist/.setup/{plugin-metadata-cache-DsS5buNa.mjs → plugin-metadata-cache-Ctmo83k_.mjs} +224 -154
  53. package/dist/.setup/protocol-CANUwXJ3.mjs +17 -0
  54. package/dist/.setup/{provider-fFh_-VR3.mjs → provider-BOsxQHOM.mjs} +9 -5
  55. package/dist/.setup/{provider-capabilities-B8J4Dy-O.mjs → provider-capabilities-BfE88FZ5.mjs} +31 -3
  56. package/dist/.setup/{rate-limits-DOEGYRNs.mjs → rate-limits-CMU3DUD0.mjs} +116 -137
  57. package/dist/.setup/{request-BioXJLYa.mjs → request-D2L0zMrq.mjs} +23 -15
  58. package/dist/.setup/{run-attempt-rlA07pUv.mjs → run-attempt-BHu11r7h.mjs} +1197 -617
  59. package/dist/.setup/{runtime-artifact-Dy38Z5iU.mjs → runtime-artifact-CLZ8udh-.mjs} +29 -45
  60. package/dist/.setup/{sandbox-guard-BBP-RbTf.mjs → sandbox-guard-C2sRMOEY.mjs} +1 -1
  61. package/dist/.setup/{session-binding-_0W_fHRr.mjs → session-binding-Cm0apEbd.mjs} +3 -32
  62. package/dist/.setup/{session-binding-record-TH3xA0zj.mjs → session-binding-record-BGoz8wOK.mjs} +22 -3
  63. package/dist/.setup/{session-binding-sidecars-CKYEcfNn.mjs → session-binding-sidecars-BlB5EvIS.mjs} +48 -45
  64. package/dist/.setup/{session-catalog-fUdWDx-U.mjs → session-catalog-Pno1xGcl.mjs} +482 -182
  65. package/dist/.setup/{session-catalog-adoption-CR_whkEW.mjs → session-catalog-adoption-BI6UTDZT.mjs} +57 -25
  66. package/dist/.setup/{session-catalog-archive-CwZaPacf.mjs → session-catalog-archive-lHBqzhaO.mjs} +6 -6
  67. package/dist/.setup/{session-catalog-events-jMcYfQyd.mjs → session-catalog-events-Bj6j94E_.mjs} +122 -25
  68. package/dist/.setup/{session-catalog-index-B141u15s.mjs → session-catalog-index-B9_VQIUz.mjs} +178 -78
  69. package/dist/.setup/{session-catalog-index-order-Cc5BzlQr.mjs → session-catalog-index-order-hcdz07yN.mjs} +2 -2
  70. package/dist/.setup/{session-catalog-index-state-BAuDztHN.mjs → session-catalog-index-state-Dgh8ORJm.mjs} +5 -2
  71. package/dist/.setup/{session-catalog-native-projection-ChV3cCtm.mjs → session-catalog-native-projection-DowriLid.mjs} +30 -13
  72. package/dist/.setup/{session-catalog-node-adoption-BVRsYOSh.mjs → session-catalog-node-adoption-ITddWx_X.mjs} +24 -12
  73. package/dist/.setup/{session-catalog-node-continue-Dowv8osw.mjs → session-catalog-node-continue-6g6qi4A9.mjs} +22 -13
  74. package/dist/.setup/{session-catalog-projection-C1Bj9Jl-.mjs → session-catalog-projection-zK_PUsiE.mjs} +13 -5
  75. package/dist/.setup/{session-cli-DIj-IE-E.mjs → session-cli-irrD-uo7.mjs} +4 -4
  76. package/dist/.setup/{session-history-C--SrLI8.mjs → session-history-BrqhSCf9.mjs} +17 -22
  77. package/dist/.setup/{session-history-import-JHXT5Xfi.mjs → session-history-import-D-3wAgOP.mjs} +4 -4
  78. package/dist/.setup/{session-history.worker-CpNj7H_P.mjs → session-history.worker-CaCh0xF_.mjs} +5 -18
  79. package/dist/.setup/{session-initialization-DH1z6fXn.mjs → session-initialization-rcgbZiid.mjs} +2 -2
  80. package/dist/.setup/{session-permission-policy-DhurXY0l.mjs → session-permission-policy-BI1QK_98.mjs} +2 -2
  81. package/dist/.setup/{session-retirement-CU87AOg9.mjs → session-retirement-BH-S6qkJ.mjs} +25 -6
  82. package/dist/.setup/{settled-turn-finalizer-CiY2bLFK.mjs → settled-turn-finalizer-DiAi6Kx6.mjs} +8 -8
  83. package/dist/.setup/{shared-client-BpTtuLQ5.mjs → shared-client-DA4VR4Eb.mjs} +59 -89
  84. package/dist/.setup/{side-question-DSCZyoBD.mjs → side-question-BJ1wSDcB.mjs} +147 -211
  85. package/dist/.setup/{source-Bjp4UQij.mjs → source-CUzJq5WN.mjs} +9 -9
  86. package/dist/.setup/spawn-error-CL3n6MAa.mjs +57 -0
  87. package/dist/.setup/{thread-archive-guard-jmecf6OJ.mjs → thread-archive-guard-C9frICzX.mjs} +10 -3
  88. package/dist/.setup/{thread-history-page-BTx-4xsg.mjs → thread-history-page-DoVpnHim.mjs} +1 -1
  89. package/dist/.setup/{thread-lifecycle-Cik28qWn.mjs → thread-lifecycle-B3mfz1TG.mjs} +172 -2271
  90. package/dist/.setup/{thread-ownership-skomxnIt.mjs → thread-ownership-DcTtAcXj.mjs} +4 -2
  91. package/dist/.setup/{thread-policy-Cjs4B8xf.mjs → thread-policy-DGuQsuFC.mjs} +19 -3
  92. package/dist/.setup/thread-requests-BLvGkP2R.mjs +2205 -0
  93. package/dist/.setup/{thread-resume-BkNpj9Pz.mjs → thread-resume-DIBXwOpE.mjs} +6 -6
  94. package/dist/.setup/{timeout-DZF05XrR.mjs → timeout-C910MdAB.mjs} +19 -2
  95. package/dist/.setup/{transcript-history-projection-DHNBDhCU.mjs → transcript-history-projection-ZZpkFkJ_.mjs} +94 -64
  96. package/dist/.setup/{transcript-mirror-D4qp_leP.mjs → transcript-mirror-BtHDBp1G.mjs} +218 -198
  97. package/dist/.setup/{transport-stdio-Cmx94Oiy.mjs → transport-stdio-h2VHOskC.mjs} +135 -55
  98. package/dist/.setup/{upstream-session-fork-D3UKxgVD.mjs → upstream-session-fork-BUr4OUbC.mjs} +44 -36
  99. package/dist/.setup/{usage-BOgBEKso.mjs → usage-BML0r-ua.mjs} +5 -4
  100. package/dist/.setup/{usage-limit-error-C0ow7DOc.mjs → usage-limit-error-DUMbefVY.mjs} +4 -4
  101. package/dist/.setup/{web-search-provider.runtime-CTGuJt6i.mjs → web-search-provider.runtime-CDKlN-Rv.mjs} +4 -3
  102. package/dist/api.js +23 -12
  103. package/dist/catalog-page-worker-entrypoint.js +12 -0
  104. package/dist/catalog-page.worker.js +9 -0
  105. package/dist/cli-metadata.js +1 -1
  106. package/dist/doctor-contract-api.js +2 -2
  107. package/dist/harness.js +1 -1
  108. package/dist/index.js +221 -170
  109. package/dist/media-understanding-provider.js +2 -2
  110. package/dist/migration-provider-api.js +1 -1
  111. package/dist/provider-discovery.js +1 -1
  112. package/dist/session-history-worker-runtime.js +15 -32
  113. package/dist/session-history.worker.js +1 -1
  114. package/package.json +9 -6
  115. package/dist/.setup/attempt-context-VXVwTCfS.mjs +0 -636
  116. package/dist/.setup/inference-proxy-CC15HuSi.mjs +0 -311
  117. package/dist/.setup/launch-args-DnMak49W.mjs +0 -111
  118. package/dist/.setup/node-exec-server.runtime-BaViBKNz.mjs +0 -226
  119. package/dist/.setup/version-CoqzXPgK.mjs +0 -12
  120. package/dist/.setup/{native-execution-policy-YBMHSzC4.mjs → native-execution-policy-umd0tgh4.mjs} +1 -1
@@ -1,38 +1,87 @@
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 { 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";
7
8
  import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
8
9
  import { createHash } from "node:crypto";
9
10
  import { isDeepStrictEqual } from "node:util";
10
11
  import { embeddedAgentLog } from "openclaw/plugin-sdk/agent-harness-registration";
11
12
  import { setImmediate as setImmediate$1 } from "node:timers/promises";
12
- import { toErrorObject } from "openclaw/plugin-sdk/error-runtime";
13
+ import { coerceErrorMessage, toErrorObject } from "openclaw/plugin-sdk/error-runtime";
13
14
  import { sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
14
15
  //#region extensions/codex/src/session-catalog-currency.ts
16
+ const SAFETY_INTERVAL_MS = 9e5;
15
17
  /** One periodic reconciliation cycle per home, without a recursive watcher inventory. */
16
18
  var CodexCatalogCurrency = class {
17
19
  constructor(options) {
18
20
  this.options = options;
19
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;
20
56
  }
21
57
  start() {
22
58
  if (this.closed || this.timer) return;
59
+ this.nextNativeAt = Date.now() + SAFETY_INTERVAL_MS;
60
+ this.nextFilesAt = this.nextNativeAt;
23
61
  this.timer = setInterval(() => {
24
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;
25
71
  const run = async () => {
26
- await this.options.reconcileFiles();
27
- await this.options.reconcileNative();
72
+ if (filesDue) await this.options.reconcileFiles();
73
+ if (nativeDue) await this.options.reconcileNative(full);
28
74
  };
29
- this.running = (this.options.runBackground ? this.options.runBackground(run) : run()).catch((error) => this.options.report(error)).finally(() => {
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(() => {
30
78
  this.running = void 0;
31
79
  });
32
80
  }, 3e4);
33
81
  this.timer.unref();
34
82
  if (this.options.local) {
35
83
  this.initial = setTimeout(() => {
84
+ this.initial = void 0;
36
85
  this.options.reconcileFiles().catch((error) => this.options.report(error));
37
86
  }, 0);
38
87
  this.initial.unref();
@@ -40,8 +89,12 @@ var CodexCatalogCurrency = class {
40
89
  }
41
90
  close() {
42
91
  this.closed = true;
92
+ this.cancelHydration();
43
93
  clearInterval(this.timer);
94
+ this.timer = void 0;
44
95
  clearTimeout(this.initial);
96
+ this.initial = void 0;
97
+ return this.running;
45
98
  }
46
99
  };
47
100
  //#endregion
@@ -118,6 +171,9 @@ var CodexCatalogIndexEvents = class {
118
171
  this.pending = /* @__PURE__ */ new Map();
119
172
  this.upserting = /* @__PURE__ */ new Set();
120
173
  }
174
+ hasActiveWork() {
175
+ return this.pending.size > 0 || this.upserting.size > 0;
176
+ }
121
177
  handle(event, readThread, source) {
122
178
  if (this.closed || !isRecord(event.params)) return;
123
179
  const params = event.params;
@@ -161,7 +217,7 @@ var CodexCatalogIndexEvents = class {
161
217
  }
162
218
  if (event.method === "turn/started" || event.method === "turn/completed" || event.method === "thread/unarchived" || event.method === "thread/reverted") {
163
219
  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);
220
+ this.enqueueRefresh(id, readThread, source, event.method === "turn/started" ? this.owner.reserveTurnStartOrder() : void 0);
165
221
  }
166
222
  }
167
223
  hasCapacity() {
@@ -169,10 +225,12 @@ var CodexCatalogIndexEvents = class {
169
225
  this.owner.report(/* @__PURE__ */ new Error("Codex catalog event queue reached its resident row limit"));
170
226
  return false;
171
227
  }
172
- enqueueRefresh(id, readThread, sourceOrder) {
228
+ enqueueRefresh(id, readThread, source, sourceOrder) {
229
+ this.owner.requestNativeRefresh();
173
230
  const existing = this.pending.get(id);
174
231
  if (existing) {
175
232
  existing.readThread = readThread;
233
+ existing.source = source;
176
234
  existing.dirty = true;
177
235
  existing.sourceOrder = sourceOrder ?? existing.sourceOrder;
178
236
  return;
@@ -180,6 +238,7 @@ var CodexCatalogIndexEvents = class {
180
238
  if (!this.hasCapacity()) return;
181
239
  const pending = {
182
240
  readThread,
241
+ source,
183
242
  dirty: true,
184
243
  sourceOrder,
185
244
  promise: Promise.resolve()
@@ -190,12 +249,17 @@ var CodexCatalogIndexEvents = class {
190
249
  while (!this.closed && pending.dirty) {
191
250
  pending.dirty = false;
192
251
  const observedSourceOrder = pending.sourceOrder;
252
+ const observedSource = pending.source;
193
253
  try {
254
+ if (observedSource.closed) throw new Error("Codex catalog observation source closed before its metadata read");
194
255
  const published = await this.owner.refresh(id, pending.readThread, observedSourceOrder);
195
256
  if (published && pending.sourceOrder === observedSourceOrder) pending.sourceOrder = void 0;
196
257
  else if (!published && pending.sourceOrder !== void 0) pending.dirty = true;
197
258
  } catch (error) {
198
- this.owner.report(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);
199
263
  }
200
264
  }
201
265
  } finally {
@@ -288,6 +352,9 @@ var CodexCatalogObservations = class {
288
352
  this.mutations = /* @__PURE__ */ new Map();
289
353
  this.observations = /* @__PURE__ */ new Map();
290
354
  }
355
+ hasActiveWork() {
356
+ return this.observations.size > 0;
357
+ }
291
358
  mark(threadId) {
292
359
  this.revision++;
293
360
  if (this.observations.size) {
@@ -331,9 +398,9 @@ function prepareCodexCatalogQuery(params, prepared) {
331
398
  const { complete, frontier } = availability;
332
399
  if (!complete && !frontier) return;
333
400
  if (!complete && frontier && anchor?.backwards && compareCodexCatalogRows(frontier, anchor) < 0) return;
334
- const candidates = ordered.filter((row) => {
401
+ const candidates = complete && !cwd && !search ? ordered : ordered.filter((row) => {
335
402
  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));
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));
337
404
  });
338
405
  const selected = anchor?.backwards ? candidates.filter((row) => row.threadId !== anchor.threadId) : candidates;
339
406
  let start = 0;
@@ -376,6 +443,36 @@ function prepareCodexCatalogQuery(params, prepared) {
376
443
  }
377
444
  //#endregion
378
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
+ }
379
476
  /** The resident limit bounds storage, never authoritative discovery. */
380
477
  var CodexCatalogNativePages = class {
381
478
  constructor(settings, status) {
@@ -634,7 +731,7 @@ var CodexCatalogIndex = class {
634
731
  this.currency = new CodexCatalogCurrency({
635
732
  local: Boolean(options.localSessionsRoot),
636
733
  reconcileFiles: () => this.reconcile(),
637
- reconcileNative: () => this.reconcileNative(),
734
+ reconcileNative: (full) => this.reconcileNative(full),
638
735
  runBackground: options.runBackground,
639
736
  report: (error) => this.report(error)
640
737
  });
@@ -647,18 +744,24 @@ var CodexCatalogIndex = class {
647
744
  },
648
745
  updateSettings: (id, settings, source) => this.liveSettings.update(id, settings, source),
649
746
  rename: (id, name) => {
747
+ this.currency.requestNativeRefresh();
650
748
  this.names.update(id, name);
651
749
  const row = this.rows.get(id);
652
750
  if (row && !this.closed) this.put(row);
653
751
  },
654
752
  upsert: (thread) => this.upsertThread(thread),
655
753
  reserveTurnStartOrder: () => this.ordering.reserveEvent(),
754
+ requestNativeRefresh: () => this.currency.requestNativeRefresh(),
656
755
  refresh: (id, readThread, sourceOrder) => this.refreshThread(id, readThread, sourceOrder),
657
756
  archive: (id) => this.archive(id),
658
- remove: (id) => this.remove(id),
757
+ remove: (id) => {
758
+ this.currency.requestNativeRefresh();
759
+ this.remove(id);
760
+ },
659
761
  report: (error) => this.report(error)
660
762
  });
661
763
  this.unsubscribe = subscribeCodexCatalogEvents(options.homeId, (event, readThread, source) => this.events.handle(event, readThread, source), {
764
+ onEphemeralThread: (id) => this.remove(id),
662
765
  onClose: (source) => {
663
766
  this.liveStatus.invalidate(source);
664
767
  this.liveSettings.invalidate(source);
@@ -687,7 +790,7 @@ var CodexCatalogIndex = class {
687
790
  }
688
791
  }
689
792
  report(error) {
690
- if (!this.closed) embeddedAgentLog.warn("Codex resident catalog background update failed", { error });
793
+ if (!this.closed && !this.currency.stopForTerminalFailure(error)) embeddedAgentLog.warn("Codex resident catalog background update failed", { error });
691
794
  }
692
795
  withName(row) {
693
796
  const known = this.names.get(row.threadId);
@@ -729,8 +832,8 @@ var CodexCatalogIndex = class {
729
832
  }
730
833
  async initialize() {
731
834
  this.assertCurrent();
732
- clearImmediate(this.background);
733
- this.background = void 0;
835
+ this.currency.assertRunnable();
836
+ this.currency.cancelHydration();
734
837
  if (this.initialized && !this.needsNativeRefresh) return;
735
838
  if (!this.initializing) {
736
839
  this.availability.begin();
@@ -743,7 +846,7 @@ var CodexCatalogIndex = class {
743
846
  if (!this.initialized) {
744
847
  let observedRevision;
745
848
  do
746
- observedRevision = await this.observations.observe((isCurrent) => this.hydrate(isCurrent, this.availability.complete));
849
+ observedRevision = await this.hydrate(this.availability.complete);
747
850
  while (observedRevision !== this.sourceRevision);
748
851
  this.needsNativeRefresh = false;
749
852
  }
@@ -758,6 +861,7 @@ var CodexCatalogIndex = class {
758
861
  })().catch((error) => {
759
862
  this.failure = { error };
760
863
  this.availability.fail(error);
864
+ this.currency.stopForTerminalFailure(error);
761
865
  throw error;
762
866
  }).finally(() => {
763
867
  this.initializing = void 0;
@@ -800,13 +904,8 @@ var CodexCatalogIndex = class {
800
904
  await this.restoring;
801
905
  }
802
906
  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();
907
+ if (this.initialized && !this.needsNativeRefresh || this.initializing || this.closed) return;
908
+ this.currency.scheduleHydration(() => this.initialize());
810
909
  }
811
910
  captureFields() {
812
911
  return {
@@ -823,79 +922,71 @@ var CodexCatalogIndex = class {
823
922
  if (current && current.page.sessions[0]?.name !== session.name) this.put(current);
824
923
  }
825
924
  }
826
- reconcileNative() {
925
+ reconcileNative(full = true) {
827
926
  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
- }
927
+ if (!this.reconcilingNative) this.reconcilingNative = this.hydrate(true, !full).then(() => void 0).finally(() => {
928
+ this.reconcilingNative = void 0;
929
+ });
836
930
  return this.reconcilingNative;
837
931
  }
838
- async hydrate(isCurrent, useStateDbOnly = false) {
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) {
839
937
  this.assertCurrent();
840
938
  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;
939
+ let observedRevision;
845
940
  let frontier;
846
941
  const batchOrder = this.ordering.captureBatch(this.availability.complete);
847
- const remaining = new Map(this.rows);
848
- const cursors = /* @__PURE__ */ new Set();
849
- do {
942
+ const remaining = incremental ? void 0 : new Map(this.rows);
943
+ const pages = readCodexCatalogHydrationPages(async (params, remainingRows) => {
850
944
  this.assertCurrent();
851
945
  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));
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) {
861
953
  this.assertCurrent();
862
- if (firstPage) {
863
- observedRevision = this.sourceRevision;
864
- firstPage = false;
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);
865
960
  }
866
- for (const id of page.excludedThreadIds ?? []) if (isCurrent(id)) this.remove(id);
867
961
  for (const row of page.rows) {
868
962
  const position = sourceOrder++;
869
963
  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);
964
+ remaining?.delete(row.threadId);
874
965
  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;
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);
876
972
  this.observations.mark(row.threadId);
877
973
  this.put({
878
974
  ...row,
879
975
  sourceOrder: batchOrder(row, previous, position),
880
976
  ...fingerprint ? { fingerprint } : {}
881
977
  });
978
+ changed ||= this.rows.get(row.threadId) !== previous;
882
979
  frontier = this.rows.get(row.threadId) ?? frontier;
883
980
  }
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) {
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)) {
894
985
  for (const [id, row] of remaining) if (isCurrent(id) && this.rows.get(id) === row) this.remove(id);
895
986
  }
896
987
  this.availability.publish(frontier, true);
897
988
  await this.persistence.finishHydration(this.overflow);
898
- return observedRevision;
989
+ return observedRevision ?? this.sourceRevision;
899
990
  }
900
991
  reconcile() {
901
992
  if (!this.reconciling) this.reconciling = this.observations.observe((isCurrent) => this.reconcileFiles(isCurrent)).finally(() => {
@@ -907,7 +998,7 @@ var CodexCatalogIndex = class {
907
998
  const root = this.options.localSessionsRoot;
908
999
  if (!root || !this.initialized || this.closed) return;
909
1000
  this.assertCurrent();
910
- const byPath = new Map([...this.rows.values()].flatMap((row) => row.rolloutPath ? [[codexCatalogRolloutLogicalPath(row.rolloutPath), row]] : []));
1001
+ const byPath = indexCodexCatalogRowsByRollout(this.rows.values());
911
1002
  const { files, present } = await scanCodexCatalogRollouts(root, new Set(byPath.keys()));
912
1003
  this.assertCurrent();
913
1004
  const observed = new Map(files);
@@ -915,6 +1006,7 @@ var CodexCatalogIndex = class {
915
1006
  const previous = byPath.get(codexCatalogRolloutLogicalPath(file));
916
1007
  const known = this.observedFiles.get(file) ?? previous?.fingerprint;
917
1008
  if (known?.mtimeMs === fingerprint.mtimeMs && known.size === fingerprint.size) continue;
1009
+ this.currency.requestNativeRefresh();
918
1010
  observed.delete(file);
919
1011
  if (known) observed.set(file, known);
920
1012
  let thread;
@@ -951,7 +1043,10 @@ var CodexCatalogIndex = class {
951
1043
  this.put(mergeCodexCatalogRolloutRow(row, existing, fingerprint));
952
1044
  await setImmediate$1();
953
1045
  }
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);
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
+ }
955
1050
  this.observedFiles = observed;
956
1051
  }
957
1052
  upsertThread(thread) {
@@ -962,6 +1057,7 @@ var CodexCatalogIndex = class {
962
1057
  return Promise.resolve();
963
1058
  }
964
1059
  try {
1060
+ this.currency.requestNativeRefresh();
965
1061
  return this.upsertPreparedThread(projectCodexCatalogNativeThread(thread, sanitizeTerminalText));
966
1062
  } catch (error) {
967
1063
  return Promise.reject(toErrorObject(error, "Codex catalog projection failed"));
@@ -996,7 +1092,7 @@ var CodexCatalogIndex = class {
996
1092
  if (projected.excludedThreadIds?.includes(thread.id)) this.remove(thread.id);
997
1093
  if (row) {
998
1094
  const previous = this.rows.get(thread.id);
999
- const fingerprint = previous?.rolloutPath && row.rolloutPath && codexCatalogRolloutLogicalPath(previous.rolloutPath) === codexCatalogRolloutLogicalPath(row.rolloutPath) ? previous.fingerprint : void 0;
1095
+ const fingerprint = resolveCodexCatalogRolloutFingerprint(row.rolloutPath, previous);
1000
1096
  this.observations.mark(thread.id);
1001
1097
  this.put({
1002
1098
  ...row,
@@ -1008,6 +1104,7 @@ var CodexCatalogIndex = class {
1008
1104
  }
1009
1105
  archive(threadId) {
1010
1106
  if (this.closed) return;
1107
+ this.currency.requestNativeRefresh();
1011
1108
  this.observations.mark(threadId);
1012
1109
  this.liveStatus.delete(threadId);
1013
1110
  this.liveSettings.delete(threadId);
@@ -1022,6 +1119,9 @@ var CodexCatalogIndex = class {
1022
1119
  get(threadId) {
1023
1120
  return this.rows.get(threadId);
1024
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
+ }
1025
1125
  async list(params, deadline = performance.now() + (this.options.requestTimeoutMs ?? 6e4)) {
1026
1126
  return await withCodexCatalogListRequest(async (request) => {
1027
1127
  const expiresAt = request.constrainDeadline(deadline);
@@ -1048,7 +1148,6 @@ var CodexCatalogIndex = class {
1048
1148
  this.liveSettings.invalidate();
1049
1149
  this.unsubscribe();
1050
1150
  this.currency.close();
1051
- clearImmediate(this.background);
1052
1151
  return this.persistence.retire();
1053
1152
  }
1054
1153
  async close() {
@@ -1058,6 +1157,7 @@ var CodexCatalogIndex = class {
1058
1157
  this.restoring,
1059
1158
  this.reconciling,
1060
1159
  this.reconcilingNative,
1160
+ this.currency.close(),
1061
1161
  writes,
1062
1162
  this.events.close()
1063
1163
  ]);
@@ -1,4 +1,4 @@
1
- import { V as CODEX_CATALOG_MAX_ROWS } from "./session-catalog-native-projection-ChV3cCtm.mjs";
1
+ import { U as CODEX_CATALOG_MAX_ROWS } from "./session-catalog-native-projection-DowriLid.mjs";
2
2
  //#region extensions/codex/src/session-catalog-index-order.ts
3
3
  function codexCatalogRowRecency(row) {
4
4
  return row.recencyAt ?? row.updatedAt ?? 0;
@@ -21,7 +21,7 @@ var CodexCatalogOrdering = class {
21
21
  this.nextEventOrder = -1;
22
22
  }
23
23
  read(rows) {
24
- return this.ordered ??= [...rows.values()].toSorted(compareCodexCatalogRows);
24
+ return this.ordered ??= [...rows.values()].filter((row) => !row.archived && row.page.sessions.length > 0).toSorted(compareCodexCatalogRows);
25
25
  }
26
26
  invalidate() {
27
27
  this.ordered = void 0;
@@ -1,5 +1,5 @@
1
- import { H as detachCodexCatalogString, O as parseCatalogPage } from "./session-catalog-native-projection-ChV3cCtm.mjs";
2
- import { i as retainCodexCatalogRow } from "./session-catalog-index-order-Cc5BzlQr.mjs";
1
+ import { A as parseCatalogPage, W as detachCodexCatalogString } from "./session-catalog-native-projection-DowriLid.mjs";
2
+ import { i as retainCodexCatalogRow } from "./session-catalog-index-order-hcdz07yN.mjs";
3
3
  import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
4
4
  import { createHash } from "node:crypto";
5
5
  import { setImmediate } from "node:timers/promises";
@@ -109,6 +109,9 @@ var CodexCatalogPersistence = class {
109
109
  this.failed = false;
110
110
  this.retired = false;
111
111
  }
112
+ hasActiveWork() {
113
+ return this.writing !== void 0 || this.pending.size > 0;
114
+ }
112
115
  async readSnapshot() {
113
116
  await this.drain();
114
117
  return await readCodexCatalogSnapshot(this.state);
@@ -1,6 +1,6 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
2
- import { n as defineCodexBuildState } from "./build-state-Xx9ybZqa.mjs";
3
- import { m as isJsonObject } from "./config-security-BRQ2mgW9.mjs";
2
+ import { n as defineCodexBuildState } from "./build-state-C7EnDVgr.mjs";
3
+ import { i as isJsonObject } from "./protocol-CANUwXJ3.mjs";
4
4
  import { asFiniteNumber, isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
5
5
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
6
6
  //#region extensions/codex/src/app-server/protocol-session-source.ts
@@ -254,9 +254,12 @@ function parseCatalogSession(value, options = {}) {
254
254
  function parseCatalogPage(value, options = {}) {
255
255
  if (!isRecord(value) || !Array.isArray(value.sessions) || value.sessions.length > 100) throw new Error("Codex session catalog returned an invalid page");
256
256
  const nextCursor = parseOptionalCatalogString(value.nextCursor, "next cursor", MAX_CURSOR_LENGTH);
257
+ const sourceHomeId = parseOptionalCatalogString(value.sourceHomeId, "source home id", 256);
257
258
  const backwardsCursor = parseOptionalCatalogString(value.backwardsCursor, "backwards cursor", MAX_CURSOR_LENGTH);
258
259
  return {
259
260
  sessions: value.sessions.map((session) => parseCatalogSession(session, options)),
261
+ ...sourceHomeId ? { sourceHomeId } : {},
262
+ ...typeof value.canContinueCodex === "boolean" ? { canContinueCodex: value.canContinueCodex } : {},
260
263
  ...nextCursor ? { nextCursor } : {},
261
264
  ...backwardsCursor ? { backwardsCursor } : {}
262
265
  };
@@ -320,6 +323,7 @@ const getSources = defineCodexBuildState("openclaw.codexCatalogSources", () => (
320
323
  clients: /* @__PURE__ */ new WeakMap(),
321
324
  values: /* @__PURE__ */ new WeakMap()
322
325
  }));
326
+ const getEphemeralObservers = defineCodexBuildState("openclaw.codexCatalogEphemeralObservers", () => /* @__PURE__ */ new WeakMap());
323
327
  /** A passive lifetime fact; the token never retains its client or a lease. */
324
328
  function codexCatalogSourceForClient(client) {
325
329
  const { clients } = getSources();
@@ -333,8 +337,14 @@ function codexCatalogSourceForClient(client) {
333
337
  function closeCodexCatalogClientSource(client) {
334
338
  const { clients } = getSources();
335
339
  const source = clients.get(client);
336
- if (source) source.closed = true;
337
- else clients.set(client, { closed: true });
340
+ if (source) {
341
+ source.closed = true;
342
+ getEphemeralObservers().delete(source);
343
+ } else clients.set(client, { closed: true });
344
+ }
345
+ /** The catalog observer is bound once per physical source and released on closure. */
346
+ function observeCodexCatalogEphemeralThreads(source, observer) {
347
+ getEphemeralObservers().set(source, observer);
338
348
  }
339
349
  function getCodexCatalogSource(value) {
340
350
  return value !== null && typeof value === "object" ? getSources().values.get(value) : void 0;
@@ -356,6 +366,7 @@ function recordCodexCatalogResponseSource(method, result, source) {
356
366
  } else if ((method === "thread/read" || method === "thread/start" || method === "thread/fork" || method === "thread/resume") && "thread" in result && result.thread !== null && typeof result.thread === "object") {
357
367
  setCodexCatalogSource(result, source);
358
368
  setCodexCatalogSource(result.thread, source);
369
+ if ("ephemeral" in result.thread && result.thread.ephemeral === true && "id" in result.thread && typeof result.thread.id === "string") getEphemeralObservers().get(source)?.(result.thread.id);
359
370
  }
360
371
  }
361
372
  //#endregion
@@ -363,7 +374,8 @@ function recordCodexCatalogResponseSource(method, result, source) {
363
374
  var session_catalog_native_projection_exports = /* @__PURE__ */ __exportAll({
364
375
  CODEX_CATALOG_NATIVE_PAGE_LIMIT: () => 64,
365
376
  projectCodexCatalogNativeResponse: () => projectCodexCatalogNativeResponse,
366
- projectCodexCatalogNativeThread: () => projectCodexCatalogNativeThread
377
+ projectCodexCatalogNativeThread: () => projectCodexCatalogNativeThread,
378
+ reuseCodexCatalogPreview: () => reuseCodexCatalogPreview
367
379
  });
368
380
  const CODEX_CATALOG_NATIVE_PAGE_LIMIT = 64;
369
381
  const STRING_FIELDS = [
@@ -421,14 +433,9 @@ function projectCodexCatalogNativeThread(thread, sanitize, cachedPreview) {
421
433
  const value = thread[field];
422
434
  if (value === null || typeof value === "number" && Number.isFinite(value)) row[field] = value;
423
435
  }
424
- const preview = cachedPreview?.({
425
- id,
426
- path: typeof row.path === "string" ? row.path : null,
427
- updatedAt: typeof row.updatedAt === "number" ? row.updatedAt : null,
428
- recencyAt: typeof row.recencyAt === "number" ? row.recencyAt : null
429
- });
430
436
  const rawPreview = thread.preview;
431
- if (preview !== void 0 && preview.length <= 500 && !(typeof rawPreview === "string" && Boolean(rawPreview) !== Boolean(preview))) row.preview = preview;
437
+ const preview = reuseCodexCatalogPreview(row, typeof rawPreview === "string" ? Boolean(rawPreview) : void 0, cachedPreview);
438
+ if (preview !== void 0) row.preview = preview;
432
439
  else if (typeof rawPreview === "string") row.preview = rawPreview ? truncateCodexCatalogPreview(selectCodexCatalogPreviewInput(rawPreview), sanitize) : "";
433
440
  else if (rawPreview === null) row.preview = null;
434
441
  const source = typeof thread.source === "string" ? detachCodexCatalogString(thread.source.slice(0, 500)) : void 0;
@@ -468,5 +475,15 @@ function projectCodexCatalogNativeResponse(response, sanitize, cachedPreview, re
468
475
  }
469
476
  return page;
470
477
  }
478
+ /** Reuse resident text without transferring a cache or an unbounded native preview. */
479
+ function reuseCodexCatalogPreview(thread, rawPreviewNonempty, cachedPreview) {
480
+ const preview = cachedPreview?.({
481
+ id: thread.id,
482
+ path: typeof thread.path === "string" ? thread.path : null,
483
+ updatedAt: typeof thread.updatedAt === "number" ? thread.updatedAt : null,
484
+ recencyAt: typeof thread.recencyAt === "number" ? thread.recencyAt : null
485
+ });
486
+ return preview !== void 0 && preview.length <= 500 && (rawPreviewNonempty === void 0 || rawPreviewNonempty === Boolean(preview)) ? preview : void 0;
487
+ }
471
488
  //#endregion
472
- export { parseTranscriptPage as A, unwrapNodeInvokePayload as B, codexCatalogThreadName as C, normalizeLimit as D, isInteractiveThreadSource as E, requireBoundThread as F, detachCodexCatalogString as H, requireOnlyKeys as I, selectCodexCatalogPreviewInput as L, readControlCursor as M, readGatewayParams as N, parseCatalogPage as O, readPageParams as P, toCatalogSession as R, catalogError as S, filterCatalogPageByTitle as T, session_catalog_limits_exports as U, CODEX_CATALOG_MAX_ROWS as V, CODEX_INTERACTIVE_THREAD_SOURCE_KINDS as W, MAX_CURSOR_LENGTH as _, closeCodexCatalogClientSource as a, NODE_INVOKE_TIMEOUT_MS as b, getCodexCatalogSource as c, CODEX_APP_SERVER_THREADS_CAPABILITY as d, CODEX_APP_SERVER_THREADS_LIST_COMMAND as f, CatalogParamsError as g, CODEX_LOCAL_SESSION_HOST_ID as h, session_catalog_native_projection_exports as i, readBoundedOptionalString as j, parseJsonParams as k, recordCodexCatalogResponseSource as l, CODEX_CATALOG_TRANSCRIPT_READ_COMMAND as m, projectCodexCatalogNativeResponse as n, codexCatalogSourceForClient as o, CODEX_APP_SERVER_THREAD_TURNS_LIST_COMMAND as p, projectCodexCatalogNativeThread as r, copyCodexCatalogSource as s, CODEX_CATALOG_NATIVE_PAGE_LIMIT as t, setCodexCatalogSource as u, MAX_CWD_LENGTH as v, codexCatalogThreadStatus as w, boundedCatalogString as x, MAX_TRANSCRIPT_PAGE_BYTES as y, truncateCodexCatalogPreview as z };
489
+ export { parseCatalogPage as A, toCatalogSession as B, boundedCatalogString as C, filterCatalogPageByTitle as D, codexCatalogThreadStatus as E, readGatewayParams as F, session_catalog_limits_exports as G, unwrapNodeInvokePayload as H, readPageParams as I, CODEX_INTERACTIVE_THREAD_SOURCE_KINDS as K, requireBoundThread as L, parseTranscriptPage as M, readBoundedOptionalString as N, isInteractiveThreadSource as O, readControlCursor as P, requireOnlyKeys as R, NODE_INVOKE_TIMEOUT_MS as S, codexCatalogThreadName as T, CODEX_CATALOG_MAX_ROWS as U, truncateCodexCatalogPreview as V, detachCodexCatalogString as W, CODEX_LOCAL_SESSION_HOST_ID as _, session_catalog_native_projection_exports as a, MAX_CWD_LENGTH as b, copyCodexCatalogSource as c, recordCodexCatalogResponseSource as d, setCodexCatalogSource as f, CODEX_CATALOG_TRANSCRIPT_READ_COMMAND as g, CODEX_APP_SERVER_THREAD_TURNS_LIST_COMMAND as h, reuseCodexCatalogPreview as i, parseJsonParams as j, normalizeLimit as k, getCodexCatalogSource as l, CODEX_APP_SERVER_THREADS_LIST_COMMAND as m, projectCodexCatalogNativeResponse as n, closeCodexCatalogClientSource as o, CODEX_APP_SERVER_THREADS_CAPABILITY as p, projectCodexCatalogNativeThread as r, codexCatalogSourceForClient as s, CODEX_CATALOG_NATIVE_PAGE_LIMIT as t, observeCodexCatalogEphemeralThreads as u, CatalogParamsError as v, catalogError as w, MAX_TRANSCRIPT_PAGE_BYTES as x, MAX_CURSOR_LENGTH as y, selectCodexCatalogPreviewInput as z };