@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,48 @@
1
+ import { U as CODEX_CATALOG_MAX_ROWS } from "./session-catalog-native-projection-DowriLid.mjs";
2
+ //#region extensions/codex/src/session-catalog-index-order.ts
3
+ function codexCatalogRowRecency(row) {
4
+ return row.recencyAt ?? row.updatedAt ?? 0;
5
+ }
6
+ function compareCodexCatalogRows(a, b) {
7
+ return codexCatalogRowRecency(b) - codexCatalogRowRecency(a) || (a.sourceOrder ?? 0) - (b.sourceOrder ?? 0) || (a.threadId < b.threadId ? 1 : a.threadId > b.threadId ? -1 : 0);
8
+ }
9
+ /** Admission and restoration share the archived-oldest eviction policy. */
10
+ function retainCodexCatalogRow(rows, candidate) {
11
+ rows.set(candidate.threadId, candidate);
12
+ if (rows.size <= 2e4) return;
13
+ let oldest;
14
+ for (const row of rows.values()) if (!oldest || (row.archived !== oldest.archived ? row.archived : compareCodexCatalogRows(row, oldest) > 0)) oldest = row;
15
+ if (oldest) rows.delete(oldest.threadId);
16
+ return oldest;
17
+ }
18
+ /** Stable positions keep issued cursors independent of later native page offsets. */
19
+ var CodexCatalogOrdering = class {
20
+ constructor() {
21
+ this.nextEventOrder = -1;
22
+ }
23
+ read(rows) {
24
+ return this.ordered ??= [...rows.values()].filter((row) => !row.archived && row.page.sessions.length > 0).toSorted(compareCodexCatalogRows);
25
+ }
26
+ invalidate() {
27
+ this.ordered = void 0;
28
+ }
29
+ restore(row) {
30
+ this.nextEventOrder = Math.min(this.nextEventOrder, (row.sourceOrder ?? 0) - 1);
31
+ }
32
+ reserveEvent() {
33
+ return this.nextEventOrder--;
34
+ }
35
+ unchangedPosition(row, previous) {
36
+ return previous && codexCatalogRowRecency(row) <= codexCatalogRowRecency(previous) ? previous.sourceOrder : void 0;
37
+ }
38
+ position(row, previous) {
39
+ return row.sourceOrder ?? this.unchangedPosition(row, previous) ?? this.reserveEvent();
40
+ }
41
+ captureBatch(hasCompleteSnapshot) {
42
+ const base = hasCompleteSnapshot ? this.nextEventOrder - CODEX_CATALOG_MAX_ROWS : 0;
43
+ if (hasCompleteSnapshot) this.nextEventOrder = base - 1;
44
+ return (row, previous, position) => this.unchangedPosition(row, previous) ?? base + position;
45
+ }
46
+ };
47
+ //#endregion
48
+ export { retainCodexCatalogRow as i, codexCatalogRowRecency as n, compareCodexCatalogRows as r, CodexCatalogOrdering as t };
@@ -0,0 +1,183 @@
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
+ import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
4
+ import { createHash } from "node:crypto";
5
+ import { setImmediate } from "node:timers/promises";
6
+ //#region extensions/codex/src/session-catalog-index-state.ts
7
+ const CODEX_CATALOG_STATE_NAMESPACE = "session-catalog-resident";
8
+ /** Durable metadata never asserts that a native process is still running. */
9
+ function codexCatalogMetadataPage(page) {
10
+ return { sessions: page.sessions.map(({ status: _status, activeFlags: _flags, ...session }) => ({
11
+ ...session,
12
+ status: "notLoaded"
13
+ })) };
14
+ }
15
+ function readStoredCodexCatalogRow(value) {
16
+ if (!isRecord(value) || value.version !== 1 || value.kind !== "row" || !isRecord(value.row)) return;
17
+ const row = value.row;
18
+ if (typeof row.threadId !== "string" || !row.threadId || row.threadId.length > 256 || typeof row.archived !== "boolean" || typeof row.nativeMetadata !== "boolean" || row.preview !== void 0 && (typeof row.preview !== "string" || row.preview.length > 500) || row.sourceOrder !== void 0 && (typeof row.sourceOrder !== "number" || !Number.isSafeInteger(row.sourceOrder)) || row.rolloutPath !== void 0 && (typeof row.rolloutPath !== "string" || row.rolloutPath.length > 4096) || !(row.updatedAt === null || typeof row.updatedAt === "number" && Number.isFinite(row.updatedAt)) || !(row.recencyAt === null || typeof row.recencyAt === "number" && Number.isFinite(row.recencyAt))) return;
19
+ try {
20
+ const page = parseCatalogPage(row.page);
21
+ if (page.sessions.length > 1 || page.sessions.some((session) => session.threadId !== row.threadId)) return;
22
+ const fingerprint = isRecord(row.fingerprint) && typeof row.fingerprint.mtimeMs === "number" && Number.isFinite(row.fingerprint.mtimeMs) && typeof row.fingerprint.size === "number" && Number.isFinite(row.fingerprint.size) ? {
23
+ mtimeMs: row.fingerprint.mtimeMs,
24
+ size: row.fingerprint.size
25
+ } : void 0;
26
+ return {
27
+ threadId: detachCodexCatalogString(row.threadId),
28
+ updatedAt: row.updatedAt,
29
+ recencyAt: row.recencyAt,
30
+ archived: row.archived,
31
+ nativeMetadata: row.nativeMetadata,
32
+ page: codexCatalogMetadataPage(page),
33
+ ...typeof row.preview === "string" ? { preview: detachCodexCatalogString(row.preview) } : {},
34
+ ...typeof row.sourceOrder === "number" ? { sourceOrder: row.sourceOrder } : {},
35
+ ...typeof row.rolloutPath === "string" ? { rolloutPath: detachCodexCatalogString(row.rolloutPath) } : {},
36
+ ...fingerprint ? { fingerprint } : {}
37
+ };
38
+ } catch {
39
+ return;
40
+ }
41
+ }
42
+ /** An incomplete cache cannot prove which native rows precede an issued cursor. */
43
+ async function readCodexCatalogSnapshot(state) {
44
+ const entries = await state?.entries() ?? [];
45
+ const rows = /* @__PURE__ */ new Map();
46
+ const keys = /* @__PURE__ */ new Map();
47
+ const obsolete = /* @__PURE__ */ new Set();
48
+ let cleanupIncomplete = false;
49
+ let valid = true;
50
+ const discard = (key) => {
51
+ if (obsolete.has(key)) return;
52
+ if ((key === "complete" || obsolete.size - Number(obsolete.has("complete")) < 2e4) && Buffer.byteLength(key) <= 512) obsolete.add(detachCodexCatalogString(key));
53
+ else {
54
+ cleanupIncomplete = true;
55
+ obsolete.add("complete");
56
+ }
57
+ };
58
+ let complete = false;
59
+ let overflow = false;
60
+ for (const entry of entries) {
61
+ if (Buffer.byteLength(entry.key) > 512) {
62
+ valid = false;
63
+ discard(entry.key);
64
+ continue;
65
+ }
66
+ if (entry.value?.version === 1 && entry.value.kind === "complete") {
67
+ complete = true;
68
+ overflow ||= entry.value.overflow === true;
69
+ continue;
70
+ }
71
+ const row = readStoredCodexCatalogRow(entry.value);
72
+ if (row) {
73
+ const evicted = retainCodexCatalogRow(rows, row);
74
+ if (evicted) {
75
+ discard(evicted === row ? entry.key : keys.get(evicted.threadId));
76
+ keys.delete(evicted.threadId);
77
+ }
78
+ if (evicted !== row) keys.set(row.threadId, detachCodexCatalogString(entry.key));
79
+ } else {
80
+ valid = false;
81
+ discard(entry.key);
82
+ }
83
+ }
84
+ complete &&= valid;
85
+ if (!complete) {
86
+ rows.clear();
87
+ for (const entry of entries) discard(entry.key);
88
+ if (entries.length) obsolete.add("complete");
89
+ }
90
+ return {
91
+ rows: [...rows.values()],
92
+ complete,
93
+ overflow,
94
+ obsolete,
95
+ cleanupIncomplete
96
+ };
97
+ }
98
+ /** Serializes reconstructible cache writes without blocking resident queries. */
99
+ var CodexCatalogPersistence = class {
100
+ invalidate(error) {
101
+ if (!this.failed) this.report(error);
102
+ this.failed = true;
103
+ this.queue("complete", void 0);
104
+ }
105
+ constructor(state, report) {
106
+ this.state = state;
107
+ this.report = report;
108
+ this.pending = /* @__PURE__ */ new Map();
109
+ this.failed = false;
110
+ this.retired = false;
111
+ }
112
+ hasActiveWork() {
113
+ return this.writing !== void 0 || this.pending.size > 0;
114
+ }
115
+ async readSnapshot() {
116
+ await this.drain();
117
+ return await readCodexCatalogSnapshot(this.state);
118
+ }
119
+ key(threadId) {
120
+ return `thread:${createHash("sha256").update(threadId).digest("hex")}`;
121
+ }
122
+ put(row) {
123
+ if (!this.state || this.retired) return;
124
+ this.queue(this.key(row.threadId), {
125
+ version: 1,
126
+ kind: "row",
127
+ row
128
+ });
129
+ }
130
+ remove(threadId) {
131
+ this.queue(this.key(threadId), void 0);
132
+ }
133
+ async pruneObsolete(keys, currentRows) {
134
+ const currentKeys = new Set(Array.from(currentRows, (row) => this.key(row.threadId)));
135
+ for (const key of keys) if (!currentKeys.has(key)) this.queue(key, void 0);
136
+ await this.drain();
137
+ }
138
+ async finishHydration(overflow = false) {
139
+ await this.drain();
140
+ if (!this.failed) {
141
+ this.queue("complete", {
142
+ version: 1,
143
+ kind: "complete",
144
+ ...overflow ? { overflow: true } : {}
145
+ });
146
+ await this.drain();
147
+ }
148
+ }
149
+ async drain() {
150
+ while (this.writing) await this.writing;
151
+ }
152
+ retire() {
153
+ this.retired = true;
154
+ return this.drain();
155
+ }
156
+ queue(key, value) {
157
+ if (!this.state || this.retired && (!this.writing || key !== "complete" || value !== void 0)) return;
158
+ if (key !== "complete" && !this.pending.has(key) && this.pending.size - Number(this.pending.has("complete")) >= 2e4) {
159
+ this.invalidate(/* @__PURE__ */ new Error("Codex catalog persistence queue reached its resident row limit"));
160
+ return;
161
+ }
162
+ this.pending.set(key, value);
163
+ this.writing ??= this.writePending();
164
+ }
165
+ async writePending() {
166
+ try {
167
+ await setImmediate();
168
+ for (const [key, value] of this.pending) {
169
+ this.pending.delete(key);
170
+ try {
171
+ if (value) await this.state.register(key, value);
172
+ else await this.state.delete(key);
173
+ } catch (error) {
174
+ if (!this.failed) this.invalidate(error);
175
+ }
176
+ }
177
+ } finally {
178
+ this.writing = void 0;
179
+ }
180
+ }
181
+ };
182
+ //#endregion
183
+ export { CodexCatalogPersistence as n, codexCatalogMetadataPage as r, CODEX_CATALOG_STATE_NAMESPACE as t };
@@ -1,6 +1,24 @@
1
- import { n as CODEX_INTERACTIVE_THREAD_SOURCE_KINDS, t as CODEX_INTERACTIVE_CUSTOM_THREAD_SOURCES } from "./protocol-5bh1G-H7.js";
1
+ import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
2
+ import { n as defineCodexBuildState } from "./build-state-C7EnDVgr.mjs";
3
+ import { i as isJsonObject } from "./protocol-CANUwXJ3.mjs";
2
4
  import { asFiniteNumber, isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
3
5
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
6
+ //#region extensions/codex/src/app-server/protocol-session-source.ts
7
+ const CODEX_INTERACTIVE_THREAD_SOURCE_KINDS = ["cli", "vscode"];
8
+ const CODEX_INTERACTIVE_CUSTOM_THREAD_SOURCES = ["atlas", "chatgpt"];
9
+ //#endregion
10
+ //#region extensions/codex/src/session-catalog-limits.ts
11
+ var session_catalog_limits_exports = /* @__PURE__ */ __exportAll({
12
+ CODEX_CATALOG_MAX_ROWS: () => CODEX_CATALOG_MAX_ROWS,
13
+ CODEX_CATALOG_MAX_STATE_KEY_BYTES: () => 512,
14
+ detachCodexCatalogString: () => detachCodexCatalogString
15
+ });
16
+ const CODEX_CATALOG_MAX_ROWS = 2e4;
17
+ /** Preserve UTF-16 code units without retaining an oversized source string. */
18
+ function detachCodexCatalogString(value) {
19
+ return Buffer.from(value, "utf16le").toString("utf16le");
20
+ }
21
+ //#endregion
4
22
  //#region extensions/codex/src/session-catalog-parsing.ts
5
23
  const DEFAULT_PAGE_LIMIT = 50;
6
24
  const CODEX_APP_SERVER_THREADS_CAPABILITY = "codex-app-server-threads";
@@ -16,6 +34,7 @@ const MAX_HOST_ID_LENGTH = 256;
16
34
  const MAX_CWD_LENGTH = 4096;
17
35
  const MAX_SESSION_NAME_LENGTH = 500;
18
36
  const MAX_SESSION_PREVIEW_LENGTH = 500;
37
+ const SESSION_PREVIEW_PREFIX_LENGTH = 2048;
19
38
  const MAX_SESSION_KEY_LENGTH = 1024;
20
39
  const MAX_METADATA_LENGTH = 500;
21
40
  const MAX_ACTIVE_FLAGS = 16;
@@ -24,19 +43,29 @@ var CatalogParamsError = class extends Error {};
24
43
  function readControlCursor(value, label) {
25
44
  if (value === void 0 || value === null) return;
26
45
  if (typeof value !== "string" || !value.trim() || value.length > 4096) throw new CatalogParamsError(`invalid Codex session catalog ${label} cursor`);
27
- return value;
46
+ return detachCodexCatalogString(value);
28
47
  }
29
48
  function boundedCatalogString(value, maxLength, overflow = "omit") {
30
49
  if (typeof value !== "string") return;
31
50
  const normalized = value.trim();
32
51
  if (!normalized) return;
33
- if (normalized.length <= maxLength) return normalized;
34
- return overflow === "truncate" ? truncateUtf16Safe(normalized, maxLength) : void 0;
52
+ if (normalized.length <= maxLength) return detachCodexCatalogString(normalized);
53
+ return overflow === "truncate" ? detachCodexCatalogString(truncateUtf16Safe(normalized, maxLength)) : void 0;
35
54
  }
36
55
  function catalogPreview(value, sanitize) {
37
56
  if (typeof value !== "string") return;
38
57
  return boundedCatalogString(sanitize(value.replace(/\s+/g, " ")), MAX_SESSION_PREVIEW_LENGTH, "truncate");
39
58
  }
59
+ /** Select a bounded input only for the canonical terminal sanitizer. */
60
+ function selectCodexCatalogPreviewInput(value) {
61
+ if (value.length <= SESSION_PREVIEW_PREFIX_LENGTH) return value;
62
+ const prefix = value.slice(0, SESSION_PREVIEW_PREFIX_LENGTH).replace(/\s+/g, " ").trim();
63
+ return prefix.length > MAX_SESSION_PREVIEW_LENGTH && !/\p{Cc}/u.test(prefix) ? prefix : value;
64
+ }
65
+ /** Detach the small preview from V8's potentially large sliced-string backing store. */
66
+ function truncateCodexCatalogPreview(value, sanitize) {
67
+ return Buffer.from(catalogPreview(value, sanitize) ?? "", "utf8").toString("utf8");
68
+ }
40
69
  function normalizeInteractiveThreadSource(source) {
41
70
  if (CODEX_INTERACTIVE_THREAD_SOURCE_KINDS.some((kind) => kind === source) || CODEX_INTERACTIVE_CUSTOM_THREAD_SOURCES.some((kind) => kind === source)) return source;
42
71
  if (isRecord(source) && CODEX_INTERACTIVE_CUSTOM_THREAD_SOURCES.some((kind) => kind === source.custom)) return source.custom;
@@ -44,36 +73,45 @@ function normalizeInteractiveThreadSource(source) {
44
73
  function isInteractiveThreadSource(source) {
45
74
  return normalizeInteractiveThreadSource(source) !== void 0;
46
75
  }
47
- function toCatalogSession(thread, archived, sanitize) {
76
+ function codexCatalogThreadName(value) {
77
+ return value === null ? null : boundedCatalogString(value, MAX_SESSION_NAME_LENGTH, "truncate");
78
+ }
79
+ function codexCatalogThreadStatus(status) {
80
+ const activeFlags = [];
81
+ if (status?.type === "active" && Array.isArray(status.activeFlags)) for (const flag of status.activeFlags) {
82
+ const normalized = boundedCatalogString(flag, 128);
83
+ if (normalized) activeFlags.push(normalized);
84
+ if (activeFlags.length === MAX_ACTIVE_FLAGS) break;
85
+ }
86
+ return {
87
+ status: boundedCatalogString(status?.type, 64) ?? "notLoaded",
88
+ ...activeFlags.length ? { activeFlags } : {}
89
+ };
90
+ }
91
+ function toCatalogSession(thread, archived, sanitize, preparedPreview) {
48
92
  const source = normalizeInteractiveThreadSource(thread.source);
49
93
  if (!source) return;
50
- const record = thread;
51
94
  const threadId = boundedCatalogString(thread.id, 256);
52
95
  if (!threadId) return;
53
- const activeFlags = thread.status?.type === "active" ? thread.status.activeFlags?.flatMap((flag) => {
54
- const normalized = boundedCatalogString(flag, 128);
55
- return normalized ? [normalized] : [];
56
- }).slice(0, MAX_ACTIVE_FLAGS) : void 0;
57
- const gitInfo = isRecord(record.gitInfo) ? record.gitInfo : void 0;
96
+ const gitInfo = isRecord(thread.gitInfo) ? thread.gitInfo : void 0;
58
97
  const sessionId = boundedCatalogString(thread.sessionId, 256);
59
- const name = boundedCatalogString(thread.name, MAX_SESSION_NAME_LENGTH, "truncate");
60
- const fallbackName = name ? void 0 : catalogPreview(thread.preview, sanitize);
98
+ const name = codexCatalogThreadName(thread.name);
99
+ const fallbackName = name ? void 0 : preparedPreview ? preparedPreview.value : catalogPreview(thread.preview, sanitize);
61
100
  const cwd = boundedCatalogString(thread.cwd, MAX_CWD_LENGTH);
62
- const modelProvider = boundedCatalogString(record.modelProvider, MAX_METADATA_LENGTH, "truncate");
63
- const cliVersion = boundedCatalogString(record.cliVersion, MAX_METADATA_LENGTH, "truncate");
101
+ const modelProvider = boundedCatalogString(thread.modelProvider, MAX_METADATA_LENGTH, "truncate");
102
+ const cliVersion = boundedCatalogString(thread.cliVersion, MAX_METADATA_LENGTH, "truncate");
64
103
  const gitBranch = boundedCatalogString(gitInfo?.branch, MAX_METADATA_LENGTH, "truncate");
65
104
  return {
66
105
  threadId,
67
- status: thread.status?.type ?? "notLoaded",
106
+ ...codexCatalogThreadStatus(thread.status),
68
107
  archived,
69
108
  ...sessionId ? { sessionId } : {},
70
109
  ...thread.name === null ? { name: null } : name ? { name } : {},
71
110
  ...fallbackName ? { fallbackName } : {},
72
111
  ...cwd ? { cwd } : {},
73
- ...activeFlags?.length ? { activeFlags } : {},
74
112
  ...typeof thread.createdAt === "number" && Number.isFinite(thread.createdAt) ? { createdAt: thread.createdAt } : {},
75
113
  ...typeof thread.updatedAt === "number" && Number.isFinite(thread.updatedAt) ? { updatedAt: thread.updatedAt } : {},
76
- ...typeof record.recencyAt === "number" && Number.isFinite(record.recencyAt) ? { recencyAt: record.recencyAt } : record.recencyAt === null ? { recencyAt: null } : {},
114
+ ...typeof thread.recencyAt === "number" && Number.isFinite(thread.recencyAt) ? { recencyAt: thread.recencyAt } : thread.recencyAt === null ? { recencyAt: null } : {},
77
115
  source,
78
116
  ...modelProvider ? { modelProvider } : {},
79
117
  ...cliVersion ? { cliVersion } : {},
@@ -169,7 +207,7 @@ function parseJsonParams(paramsJSON) {
169
207
  function parseOptionalCatalogString(value, field, maxLength) {
170
208
  if (value === void 0) return;
171
209
  if (typeof value !== "string" || value.length > maxLength) throw new Error(`Codex session catalog returned an invalid ${field}`);
172
- return value;
210
+ return detachCodexCatalogString(value);
173
211
  }
174
212
  function parseCatalogSession(value, options = {}) {
175
213
  if (!isRecord(value) || typeof value.threadId !== "string" || !value.threadId.trim() || value.threadId.length > 256 || value.archived !== false) throw new Error("Codex session catalog returned an invalid session");
@@ -195,7 +233,7 @@ function parseCatalogSession(value, options = {}) {
195
233
  const updatedAt = asFiniteNumber(value.updatedAt);
196
234
  const recencyAt = value.recencyAt === null ? null : asFiniteNumber(value.recencyAt);
197
235
  return {
198
- threadId: value.threadId,
236
+ threadId: detachCodexCatalogString(value.threadId),
199
237
  status,
200
238
  archived: value.archived,
201
239
  ...sessionId !== void 0 ? { sessionId } : {},
@@ -216,9 +254,12 @@ function parseCatalogSession(value, options = {}) {
216
254
  function parseCatalogPage(value, options = {}) {
217
255
  if (!isRecord(value) || !Array.isArray(value.sessions) || value.sessions.length > 100) throw new Error("Codex session catalog returned an invalid page");
218
256
  const nextCursor = parseOptionalCatalogString(value.nextCursor, "next cursor", MAX_CURSOR_LENGTH);
257
+ const sourceHomeId = parseOptionalCatalogString(value.sourceHomeId, "source home id", 256);
219
258
  const backwardsCursor = parseOptionalCatalogString(value.backwardsCursor, "backwards cursor", MAX_CURSOR_LENGTH);
220
259
  return {
221
260
  sessions: value.sessions.map((session) => parseCatalogSession(session, options)),
261
+ ...sourceHomeId ? { sourceHomeId } : {},
262
+ ...typeof value.canContinueCodex === "boolean" ? { canContinueCodex: value.canContinueCodex } : {},
222
263
  ...nextCursor ? { nextCursor } : {},
223
264
  ...backwardsCursor ? { backwardsCursor } : {}
224
265
  };
@@ -277,85 +318,172 @@ function requireBoundThread(entry) {
277
318
  return entry.boundThreadId;
278
319
  }
279
320
  //#endregion
280
- //#region extensions/codex/src/app-server/thread-history-page.ts
281
- const TURN_ITEM_CURSOR_PREFIX = "turn-item:";
282
- function encodeTurnItemCursor(turnCursor, itemId) {
283
- return TURN_ITEM_CURSOR_PREFIX + Buffer.from(JSON.stringify([turnCursor, itemId])).toString("base64url");
284
- }
285
- function decodeTurnItemCursor(cursor) {
286
- if (!cursor?.startsWith(TURN_ITEM_CURSOR_PREFIX)) return { turnCursor: cursor };
287
- let value;
288
- try {
289
- value = JSON.parse(Buffer.from(cursor.slice(10), "base64url").toString());
290
- } catch {
291
- throw new CatalogParamsError("invalid Codex transcript item cursor");
321
+ //#region extensions/codex/src/session-catalog-source.ts
322
+ const getSources = defineCodexBuildState("openclaw.codexCatalogSources", () => ({
323
+ clients: /* @__PURE__ */ new WeakMap(),
324
+ values: /* @__PURE__ */ new WeakMap()
325
+ }));
326
+ const getEphemeralObservers = defineCodexBuildState("openclaw.codexCatalogEphemeralObservers", () => /* @__PURE__ */ new WeakMap());
327
+ /** A passive lifetime fact; the token never retains its client or a lease. */
328
+ function codexCatalogSourceForClient(client) {
329
+ const { clients } = getSources();
330
+ let source = clients.get(client);
331
+ if (!source) {
332
+ source = { closed: false };
333
+ clients.set(client, source);
292
334
  }
293
- if (!Array.isArray(value) || value.length !== 2 || typeof value[0] !== "string" || !value[0] || typeof value[1] !== "string" || !value[1]) throw new CatalogParamsError("invalid Codex transcript item cursor");
294
- return {
295
- turnCursor: value[0],
296
- itemId: value[1]
297
- };
335
+ return source;
298
336
  }
299
- /** Legacy stores expose only turn cursors; an item identity preserves paging across appends. */
300
- async function readLegacyCodexHistoryPage(readTurns, request, projection) {
301
- const { turnCursor, itemId } = decodeTurnItemCursor(request.cursor);
302
- const page = parseTranscriptPage(await readTurns({
303
- threadId: request.threadId,
304
- limit: 1,
305
- sortDirection: "desc",
306
- itemsView: "full",
307
- ...turnCursor ? { cursor: turnCursor } : {}
308
- }));
309
- const source = page.data.flatMap(({ items, ...turn }) => items.toReversed().map((item) => ({
310
- turnId: turn.id,
311
- item,
312
- turn
313
- })));
314
- const anchorIndex = itemId ? source.findIndex(({ item }) => item.id === itemId) : -1;
315
- if (itemId && anchorIndex < 0) throw new CatalogParamsError("Codex transcript changed; refresh the session before loading older items");
316
- const remaining = source.slice(anchorIndex + 1);
317
- const items = projection.project(remaining.slice(0, request.limit), request.limit);
318
- const result = () => {
319
- const lastSource = remaining[items.length - 1];
320
- const partial = lastSource !== void 0 && items.length < remaining.length;
321
- const nativeCursor = partial ? page.backwardsCursor : page.nextCursor;
322
- const cursor = nativeCursor ? partial ? encodeTurnItemCursor(nativeCursor, lastSource.item.id) : nativeCursor : void 0;
323
- if (partial && !cursor) throw new Error("Codex app-server did not provide a transcript continuation anchor");
324
- return {
325
- items,
326
- ...cursor ? { nextCursor: cursor } : {}
327
- };
337
+ function closeCodexCatalogClientSource(client) {
338
+ const { clients } = getSources();
339
+ const source = clients.get(client);
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);
348
+ }
349
+ function getCodexCatalogSource(value) {
350
+ return value !== null && typeof value === "object" ? getSources().values.get(value) : void 0;
351
+ }
352
+ function setCodexCatalogSource(value, source) {
353
+ if (source) getSources().values.set(value, source);
354
+ return value;
355
+ }
356
+ /** Source attribution survives projection without becoming serialized row data. */
357
+ function copyCodexCatalogSource(from, to) {
358
+ return setCodexCatalogSource(to, getCodexCatalogSource(from));
359
+ }
360
+ /** Stamp the final decoded objects, including any bounded catalog DTO replacement. */
361
+ function recordCodexCatalogResponseSource(method, result, source) {
362
+ if (result === null || typeof result !== "object") return;
363
+ if (method === "thread/list" && "data" in result && Array.isArray(result.data)) {
364
+ setCodexCatalogSource(result, source);
365
+ for (const thread of result.data) if (thread !== null && typeof thread === "object") setCodexCatalogSource(thread, source);
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") {
367
+ setCodexCatalogSource(result, source);
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);
370
+ }
371
+ }
372
+ //#endregion
373
+ //#region extensions/codex/src/session-catalog-native-projection.ts
374
+ var session_catalog_native_projection_exports = /* @__PURE__ */ __exportAll({
375
+ CODEX_CATALOG_NATIVE_PAGE_LIMIT: () => 64,
376
+ projectCodexCatalogNativeResponse: () => projectCodexCatalogNativeResponse,
377
+ projectCodexCatalogNativeThread: () => projectCodexCatalogNativeThread,
378
+ reuseCodexCatalogPreview: () => reuseCodexCatalogPreview
379
+ });
380
+ const CODEX_CATALOG_NATIVE_PAGE_LIMIT = 64;
381
+ const STRING_FIELDS = [
382
+ [
383
+ "name",
384
+ 500,
385
+ "truncate"
386
+ ],
387
+ [
388
+ "cwd",
389
+ MAX_CWD_LENGTH,
390
+ "omit"
391
+ ],
392
+ [
393
+ "modelProvider",
394
+ 500,
395
+ "truncate"
396
+ ],
397
+ [
398
+ "cliVersion",
399
+ 500,
400
+ "truncate"
401
+ ]
402
+ ];
403
+ /** Drop unused native fields before catalog-owned asynchronous work can retain them. */
404
+ function projectCodexCatalogNativeThread(thread, sanitize, cachedPreview) {
405
+ if (!isJsonObject(thread)) throw new Error("Codex catalog response contains an invalid thread");
406
+ const id = boundedCatalogString(thread.id, 256);
407
+ if (!id) throw new Error("Codex catalog response contains an invalid thread id");
408
+ const row = {
409
+ id,
410
+ projectId: boundedCatalogString(thread.projectId, 256, "omit") ?? null
328
411
  };
329
- let bounded = result();
330
- while (!projection.fits(bounded)) {
331
- if (items.length <= 1) throw new Error("Codex transcript item exceeds the safe response size");
332
- items.pop();
333
- bounded = result();
412
+ const sessionId = boundedCatalogString(thread.sessionId, 256, "omit");
413
+ if (sessionId) row.sessionId = sessionId;
414
+ if (thread.ephemeral === true) return copyCodexCatalogSource(thread, {
415
+ ...row,
416
+ ephemeral: true
417
+ });
418
+ for (const [field, limit, overflow] of STRING_FIELDS) {
419
+ const value = thread[field];
420
+ const bounded = boundedCatalogString(value, limit, overflow);
421
+ if (value === null || bounded !== void 0) row[field] = bounded ?? null;
334
422
  }
335
- return bounded;
336
- }
337
- /** Callers authorize the thread; this reader owns native cursor and response-size semantics. */
338
- async function readCodexThreadHistoryPage(control, thread, request, projection) {
339
- if (thread.historyMode !== "paginated") return readLegacyCodexHistoryPage((params) => control.listTurnPage(params), request, projection);
340
- let limit = request.limit;
341
- for (;;) {
342
- const page = await control.listItemPage({
343
- threadId: request.threadId,
344
- limit,
345
- sortDirection: "desc",
346
- ...request.cursor ? { cursor: request.cursor } : {}
347
- });
348
- const nextCursor = readControlCursor(page.nextCursor, "transcript next response");
349
- const items = projection.project(page.data, limit);
350
- const result = {
351
- items,
352
- ...nextCursor ? { nextCursor } : {}
353
- };
354
- const fittingCount = items.length - (projection.fits(result) ? 0 : 1);
355
- if (fittingCount === page.data.length) return result;
356
- if (fittingCount < 1) throw new Error("Codex transcript item exceeds the safe response size");
357
- limit = fittingCount;
423
+ if (typeof thread.path === "string") {
424
+ if (thread.path.length > 4096) throw new Error("Codex catalog rollout path exceeds its length limit");
425
+ row.path = detachCodexCatalogString(thread.path);
426
+ } else if (thread.path === null) row.path = null;
427
+ if (typeof thread.originator === "string") row.originator = detachCodexCatalogString(thread.originator.slice(0, 500));
428
+ for (const field of [
429
+ "createdAt",
430
+ "updatedAt",
431
+ "recencyAt"
432
+ ]) {
433
+ const value = thread[field];
434
+ if (value === null || typeof value === "number" && Number.isFinite(value)) row[field] = value;
358
435
  }
436
+ const rawPreview = thread.preview;
437
+ const preview = reuseCodexCatalogPreview(row, typeof rawPreview === "string" ? Boolean(rawPreview) : void 0, cachedPreview);
438
+ if (preview !== void 0) row.preview = preview;
439
+ else if (typeof rawPreview === "string") row.preview = rawPreview ? truncateCodexCatalogPreview(selectCodexCatalogPreviewInput(rawPreview), sanitize) : "";
440
+ else if (rawPreview === null) row.preview = null;
441
+ const source = typeof thread.source === "string" ? detachCodexCatalogString(thread.source.slice(0, 500)) : void 0;
442
+ if (source === "cli" || source === "vscode" || source === "exec" || source === "appServer" || source === "unknown") row.source = source;
443
+ else if (isJsonObject(thread.source) && typeof thread.source.custom === "string" && thread.source.custom.length <= 500) row.source = { custom: detachCodexCatalogString(thread.source.custom) };
444
+ if (isJsonObject(thread.gitInfo)) {
445
+ const branch = boundedCatalogString(thread.gitInfo.branch, 500, "truncate");
446
+ if (branch !== void 0) row.gitInfo = { branch };
447
+ }
448
+ if (isJsonObject(thread.status)) {
449
+ const type = boundedCatalogString(thread.status.type, 64);
450
+ if (type === "active" || type === "idle" || type === "notLoaded" || type === "systemError") {
451
+ const activeFlags = type === "active" && Array.isArray(thread.status.activeFlags) ? thread.status.activeFlags.slice(0, 16).flatMap((flag) => {
452
+ const bounded = boundedCatalogString(flag, 128, "omit");
453
+ return bounded ? [bounded] : [];
454
+ }) : void 0;
455
+ row.status = type === "active" ? {
456
+ type,
457
+ ...activeFlags ? { activeFlags } : {}
458
+ } : { type };
459
+ }
460
+ }
461
+ return copyCodexCatalogSource(thread, row);
462
+ }
463
+ /** Keep only the admitted prefix before an RPC promise retains its response. */
464
+ function projectCodexCatalogNativeResponse(response, sanitize, cachedPreview, remainingRows = 64) {
465
+ if (!Array.isArray(response.data) || response.data.length > 64) throw new Error("Codex catalog response exceeds its native page limit");
466
+ const limit = Number.isFinite(remainingRows) ? Math.max(0, Math.min(64, Math.floor(remainingRows))) : 0;
467
+ const page = { data: response.data.slice(0, limit).map((thread) => projectCodexCatalogNativeThread(thread, sanitize, cachedPreview)) };
468
+ for (const field of ["nextCursor", "backwardsCursor"]) {
469
+ const value = response[field];
470
+ if (value === null) page[field] = null;
471
+ else if (value !== void 0) {
472
+ if (typeof value !== "string" || value.length > 4096) throw new Error("Codex catalog response contains an invalid cursor");
473
+ page[field] = detachCodexCatalogString(value);
474
+ }
475
+ }
476
+ return page;
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;
359
487
  }
360
488
  //#endregion
361
- export { readPageParams as C, unwrapNodeInvokePayload as D, toCatalogSession as E, readGatewayParams as S, requireOnlyKeys as T, parseCatalogPage as _, CODEX_APP_SERVER_THREAD_TURNS_LIST_COMMAND as a, readBoundedOptionalString as b, CatalogParamsError as c, NODE_INVOKE_TIMEOUT_MS as d, boundedCatalogString as f, normalizeLimit as g, isInteractiveThreadSource as h, CODEX_APP_SERVER_THREADS_LIST_COMMAND as i, MAX_CURSOR_LENGTH as l, filterCatalogPageByTitle as m, readLegacyCodexHistoryPage as n, CODEX_CATALOG_TRANSCRIPT_READ_COMMAND as o, catalogError as p, CODEX_APP_SERVER_THREADS_CAPABILITY as r, CODEX_LOCAL_SESSION_HOST_ID as s, readCodexThreadHistoryPage as t, MAX_TRANSCRIPT_PAGE_BYTES as u, parseJsonParams as v, requireBoundThread as w, readControlCursor as x, parseTranscriptPage as y };
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 };