@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
@@ -1,1477 +0,0 @@
1
- import { l as sessionBindingIdentity } from "./session-binding-record-Bcvslnhf.js";
2
- import { c as resolveCodexAppServerLocalHomeDir, i as assertCodexThreadForkParams, l as resolveCodexAppServerUserHomeDir, s as resolveCodexAppServerHomeDir, x as readCodexPluginConfig } from "./protocol-5bh1G-H7.js";
3
- import { n as isCodexThreadReadMissingError } from "./rpc-error-ttN_QjEm.js";
4
- import { t as CODEX_CONTROL_METHODS } from "./capabilities-8vx68WLH.js";
5
- import { C as readPageParams, D as unwrapNodeInvokePayload, E as toCatalogSession, S as readGatewayParams, T as requireOnlyKeys, _ as parseCatalogPage, a as CODEX_APP_SERVER_THREAD_TURNS_LIST_COMMAND, b as readBoundedOptionalString, c as CatalogParamsError, d as NODE_INVOKE_TIMEOUT_MS, g as normalizeLimit, h as isInteractiveThreadSource, i as CODEX_APP_SERVER_THREADS_LIST_COMMAND, l as MAX_CURSOR_LENGTH, m as filterCatalogPageByTitle, n as readLegacyCodexHistoryPage, o as CODEX_CATALOG_TRANSCRIPT_READ_COMMAND, p as catalogError, r as CODEX_APP_SERVER_THREADS_CAPABILITY, s as CODEX_LOCAL_SESSION_HOST_ID, t as readCodexThreadHistoryPage, u as MAX_TRANSCRIPT_PAGE_BYTES, v as parseJsonParams, x as readControlCursor, y as parseTranscriptPage } from "./thread-history-page-D0JIp48V.js";
6
- import { i as projectCodexUserItemText } from "./transcript-history-projection-v17wXgdK.js";
7
- import { r as codexUpstreamContinueResult } from "./session-upstream-marker-D15C9NHp.js";
8
- import { i as replaceCodexCatalogConnectionHomes, t as buildCodexAppServerConnectionFingerprint } from "./plugin-app-cache-key-d0eKxy7b.js";
9
- import { n as withTimeout } from "./timeout-BVw8aaM1.js";
10
- import { n as codexCatalogHomeId, t as canonicalCodexCatalogHome } from "./session-catalog-home-id-CwhLdC03.js";
11
- import { n as readCodexSessionMeta, t as isOpenClawManagedCodexThread } from "./session-catalog-provenance-D-dIfRAH.js";
12
- import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
13
- import { resolveDefaultAgentDir } from "openclaw/plugin-sdk/agent-harness-registration";
14
- import { listAgentIds, resolveAgentDir, resolveDefaultAgentId, resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
15
- import { z } from "zod";
16
- import fs from "node:fs";
17
- import path from "node:path";
18
- import { publishSessionCatalogHost, sessionCatalogPaging } from "openclaw/plugin-sdk/session-catalog-paging";
19
- import { decodeNodePtyResumeParams, decodeNodePtyStartParams, resolveNodeHostExecutable, runNodePtyCommand } from "openclaw/plugin-sdk/node-host";
20
- import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
21
- //#region extensions/codex/src/session-catalog-create.ts
22
- const CODEX_AGENT_RUNTIME_ID = "codex";
23
- const CODEX_CATALOG_DEFAULT_MODEL_REF = "openai/gpt-5.6-sol";
24
- function resolveCodexCatalogCreateSession(modelConfig, config, requestedAgentId) {
25
- if (!config) return;
26
- const agentId = requestedAgentId ?? resolveDefaultAgentId(config);
27
- const defaultModel = modelConfig.resolveDefaultModelForAgent({
28
- cfg: config,
29
- agentId
30
- });
31
- return "error" in modelConfig.resolveAllowedModelRef({
32
- cfg: config,
33
- catalog: [],
34
- raw: CODEX_CATALOG_DEFAULT_MODEL_REF,
35
- defaultProvider: defaultModel.provider,
36
- defaultModel: defaultModel.model,
37
- agentId
38
- }) ? void 0 : {
39
- model: CODEX_CATALOG_DEFAULT_MODEL_REF,
40
- agentRuntime: CODEX_AGENT_RUNTIME_ID
41
- };
42
- }
43
- //#endregion
44
- //#region extensions/codex/src/session-catalog-node-lookup.ts
45
- async function lookupNodeCodexCatalogRecord(params) {
46
- let cursor;
47
- const seenCursors = /* @__PURE__ */ new Set();
48
- for (let pageIndex = 0; pageIndex < 100; pageIndex += 1) {
49
- const raw = await params.runtime.nodes.invoke({
50
- nodeId: params.nodeId,
51
- command: CODEX_APP_SERVER_THREADS_LIST_COMMAND,
52
- params: {
53
- agentId: params.agentId,
54
- limit: 100,
55
- ...cursor ? { cursor } : {}
56
- },
57
- timeoutMs: NODE_INVOKE_TIMEOUT_MS,
58
- scopes: ["operator.write"]
59
- });
60
- const page = parseCatalogPage(unwrapNodeInvokePayload(raw));
61
- const record = page.sessions.find((candidate) => candidate.threadId === params.threadId);
62
- if (record) return {
63
- kind: "found",
64
- record
65
- };
66
- const nextCursor = page.nextCursor?.trim();
67
- if (!nextCursor) break;
68
- if (seenCursors.has(nextCursor)) return { kind: "cursor-cycle" };
69
- seenCursors.add(nextCursor);
70
- cursor = nextCursor;
71
- }
72
- return { kind: "missing" };
73
- }
74
- //#endregion
75
- //#region extensions/codex/src/session-catalog-terminal.ts
76
- const CODEX_TERMINAL_RESUME_COMMAND = "codex.terminal.resume.v1";
77
- const CODEX_TERMINAL_START_COMMAND = "codex.terminal.start.v1";
78
- function createCodexTerminalStartNodeHostCommand() {
79
- return {
80
- command: CODEX_TERMINAL_START_COMMAND,
81
- cap: CODEX_APP_SERVER_THREADS_CAPABILITY,
82
- dangerous: false,
83
- duplex: true,
84
- isAvailable: ({ env }) => Boolean(resolveNodeHostExecutable("codex", {
85
- env,
86
- strategy: "direct"
87
- })),
88
- handle: async (paramsJSON, io) => {
89
- if (!io) throw new Error("Codex terminal command requires duplex transport");
90
- const params = decodeNodePtyStartParams(paramsJSON);
91
- const resolution = resolveNodeHostExecutable("codex", { strategy: "direct" });
92
- if (!resolution) throw new Error("Codex CLI is unavailable; install codex on this node and reconnect");
93
- return JSON.stringify(await runNodePtyCommand({
94
- file: resolution.executable,
95
- args: params.initialMessage !== void 0 ? ["--", params.initialMessage] : [],
96
- cwd: params.cwd,
97
- requiredCwd: true,
98
- cols: params.cols,
99
- rows: params.rows
100
- }, io));
101
- }
102
- };
103
- }
104
- function resolveCodexCatalogTerminalHome(sources) {
105
- const runtimeConfig = sources.getRuntimeConfig();
106
- if (!runtimeConfig) throw new Error("OpenClaw runtime config is unavailable");
107
- const agentDir = sources.source?.agentDir ?? (sources.agentId ? resolveAgentDir(runtimeConfig, sources.agentId) : resolveDefaultAgentDir(runtimeConfig));
108
- const startOptions = sources.source?.appServer.start ?? sources.resolveRuntimeOptions({ pluginConfig: sources.getPluginConfig() }).start;
109
- return resolveCodexAppServerLocalHomeDir(startOptions, agentDir);
110
- }
111
- function resolveLocalCodexTerminalExecutable(env = process.env) {
112
- return resolveLocalCodexTerminalResolution(env)?.executable;
113
- }
114
- function resolveLocalCodexTerminalResolution(env = process.env) {
115
- return resolveNodeHostExecutable("codex", {
116
- env,
117
- pathEnv: env.PATH ?? env.Path ?? "",
118
- strategy: "fallback"
119
- });
120
- }
121
- function codexNodeTerminalCapability(node) {
122
- const commands = node.invocableCommands ?? node.commands;
123
- return {
124
- canOpenTerminalCodex: node.connected === true && commands?.includes("codex.terminal.resume.v1") === true,
125
- canStartTerminal: node.connected === true && node.invocableCommands?.includes("codex.terminal.start.v1") === true
126
- };
127
- }
128
- function createCodexTerminalNodeHostCommand(bindRequest, configSources) {
129
- return {
130
- command: CODEX_TERMINAL_RESUME_COMMAND,
131
- cap: CODEX_APP_SERVER_THREADS_CAPABILITY,
132
- dangerous: false,
133
- duplex: true,
134
- isAvailable: ({ env }) => Boolean(resolveNodeHostExecutable("codex", {
135
- env,
136
- pathEnv: env.PATH ?? env.Path ?? "",
137
- strategy: "direct"
138
- })),
139
- handle: async (paramsJSON, io) => {
140
- if (!io) throw new Error("Codex terminal command requires duplex transport");
141
- const request = bindRequest(paramsJSON);
142
- const resume = decodeNodePtyResumeParams(request.paramsJSON, (value) => {
143
- if (typeof value !== "string" || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu.test(value)) throw new CatalogParamsError("threadId must be a UUID");
144
- return value;
145
- });
146
- const record = await request.control.requireEligibleThread(resume.threadId);
147
- const resolution = resolveNodeHostExecutable("codex", {
148
- env: process.env,
149
- pathEnv: process.env.PATH ?? process.env.Path ?? "",
150
- strategy: "direct"
151
- });
152
- if (!resolution) throw new Error("Codex CLI is unavailable");
153
- return JSON.stringify(await runNodePtyCommand({
154
- file: resolution.executable,
155
- args: ["resume", resume.threadId],
156
- ...record.cwd ? { cwd: record.cwd } : {},
157
- env: { CODEX_HOME: resolveCodexCatalogTerminalHome({
158
- ...configSources,
159
- agentId: request.agentId
160
- }) },
161
- cols: resume.cols,
162
- rows: resume.rows
163
- }, io));
164
- }
165
- };
166
- }
167
- async function openCodexCatalogTerminal(params) {
168
- const title = `codex resume ${params.threadId.slice(0, 8)}…`;
169
- if (params.hostId === "gateway:local" || params.hostId.startsWith(`gateway:local:`)) {
170
- const record = await params.control.requireEligibleThread(params.threadId);
171
- const resolution = resolveLocalCodexTerminalResolution();
172
- if (!resolution) throw new CatalogParamsError("Codex CLI is unavailable");
173
- return {
174
- kind: "local",
175
- argv: [
176
- resolution.executable,
177
- "resume",
178
- params.threadId
179
- ],
180
- ...record.cwd ? { cwd: record.cwd } : {},
181
- env: { CODEX_HOME: resolveCodexCatalogTerminalHome(params) },
182
- ...resolution.pathEnv ? { pathEnv: resolution.pathEnv } : {},
183
- title
184
- };
185
- }
186
- if (!params.hostId.startsWith("node:")) throw new CatalogParamsError("hostId is invalid");
187
- const nodeId = params.hostId.slice(5);
188
- if (!(await params.api.runtime.nodes.list()).nodes.find((candidate) => {
189
- const commands = candidate.invocableCommands ?? candidate.commands;
190
- return candidate.nodeId === nodeId && candidate.connected === true && commands?.includes("codex.appServer.threads.list.v1") === true && commands.includes("codex.terminal.resume.v1");
191
- })) throw new CatalogParamsError("paired-node Codex terminal is unavailable");
192
- const lookup = await lookupNodeCodexCatalogRecord({
193
- agentId: params.agentId,
194
- runtime: params.api.runtime,
195
- nodeId,
196
- threadId: params.threadId
197
- });
198
- if (lookup.kind !== "found" || !isInteractiveThreadSource(lookup.record.source)) throw new CatalogParamsError("Codex session is not a non-archived interactive Codex session");
199
- const record = lookup.record;
200
- return {
201
- kind: "node",
202
- nodeId,
203
- command: CODEX_TERMINAL_RESUME_COMMAND,
204
- uploadPathStyle: "native",
205
- paramsJSON: JSON.stringify({
206
- agentId: params.agentId,
207
- threadId: params.threadId
208
- }),
209
- ...record.cwd ? { cwd: record.cwd } : {},
210
- title
211
- };
212
- }
213
- async function startCodexCatalogTerminal(params) {
214
- if (params.nodeId) return {
215
- kind: "node",
216
- nodeId: params.nodeId,
217
- command: CODEX_TERMINAL_START_COMMAND,
218
- uploadPathStyle: "native",
219
- paramsJSON: JSON.stringify({
220
- cwd: params.cwd,
221
- initialMessage: params.initialMessage
222
- }),
223
- cwd: params.cwd,
224
- title: "codex"
225
- };
226
- const resolution = resolveLocalCodexTerminalResolution();
227
- if (!resolution) throw new CatalogParamsError("Codex CLI is unavailable; install Codex or add codex to PATH, then try again");
228
- return {
229
- kind: "local",
230
- argv: [resolution.executable, ...params.initialMessage !== void 0 ? ["--", params.initialMessage] : []],
231
- cwd: params.cwd,
232
- env: { CODEX_HOME: resolveCodexCatalogTerminalHome(params) },
233
- ...resolution.pathEnv ? { pathEnv: resolution.pathEnv } : {},
234
- title: "codex"
235
- };
236
- }
237
- //#endregion
238
- //#region extensions/codex/src/session-catalog-transcript-item.ts
239
- const CODEX_MESSAGE_TYPES = /* @__PURE__ */ new Map([
240
- ["userMessage", "userMessage"],
241
- ["agentMessage", "agentMessage"],
242
- ["reasoning", "reasoning"]
243
- ]);
244
- const CODEX_TOOL_TYPES = /* @__PURE__ */ new Set([
245
- "commandExecution",
246
- "fileChange",
247
- "mcpToolCall",
248
- "dynamicToolCall",
249
- "collabAgentToolCall",
250
- "webSearch",
251
- "imageView",
252
- "imageGeneration"
253
- ]);
254
- function toGenericTranscriptItem(item) {
255
- let type = CODEX_MESSAGE_TYPES.get(item.type);
256
- if (!type && CODEX_TOOL_TYPES.has(item.type)) type = item.result !== void 0 || Boolean(item.aggregatedOutput) ? "toolResult" : "toolCall";
257
- type ??= "other";
258
- const fallback = item.title ?? item.name ?? item.tool ?? item.command ?? item.query ?? void 0;
259
- const resultText = item.aggregatedOutput || (item.result === void 0 ? void 0 : JSON.stringify(item.result, null, 2));
260
- const changesText = Array.isArray(item.changes) ? item.changes.map((change) => `${change.kind}: ${change.path}`).join("\n") || void 0 : void 0;
261
- const text = item.type === "userMessage" ? projectCodexUserItemText(item) : item.text || resultText || changesText || fallback;
262
- return {
263
- id: item.id,
264
- type,
265
- ...text ? { text } : {},
266
- raw: item
267
- };
268
- }
269
- //#endregion
270
- //#region extensions/codex/src/session-catalog-transcript.ts
271
- const transcriptPageSchema = z.strictObject({
272
- items: z.array(z.strictObject({
273
- id: z.string(),
274
- type: z.enum([
275
- "userMessage",
276
- "agentMessage",
277
- "reasoning",
278
- "toolCall",
279
- "toolResult",
280
- "other"
281
- ]),
282
- text: z.string().optional(),
283
- raw: z.record(z.string(), z.json()).optional(),
284
- truncated: z.boolean().optional()
285
- })),
286
- nextCursor: z.string().optional()
287
- });
288
- function parseCodexCatalogTranscriptPage(value) {
289
- return transcriptPageSchema.parse(value);
290
- }
291
- function projectTranscriptPage(items, limit) {
292
- const projected = items.map(toGenericTranscriptItem);
293
- const page = sessionCatalogPaging.boundTranscriptPage(projected.toReversed(), limit, 0).items;
294
- for (const [index, item] of page.entries()) if (item.text !== projected[index]?.text && projected[index]?.text) item.truncated = true;
295
- return page;
296
- }
297
- function pageFitsNodeTransport(page) {
298
- return Buffer.byteLength(JSON.stringify({ payloadJSON: JSON.stringify(page) }), "utf8") <= MAX_TRANSCRIPT_PAGE_BYTES;
299
- }
300
- /** The legacy API can anchor a turn, but cannot continue within that turn. */
301
- async function readLegacyCodexTranscriptPage(readTurns, request) {
302
- return readLegacyCodexHistoryPage(readTurns, request, {
303
- project: (entries, limit) => projectTranscriptPage(entries.map(({ item }) => item), limit),
304
- fits: pageFitsNodeTransport
305
- });
306
- }
307
- /** Uses the native store's item cursor whenever that store supports item history. */
308
- async function readCodexCatalogTranscriptPage(control, request) {
309
- const thread = await control.requireEligibleThread(request.threadId);
310
- return readCodexThreadHistoryPage(control, thread, request, {
311
- project: (entries, limit) => projectTranscriptPage(entries.map(({ item }) => item), limit),
312
- fits: pageFitsNodeTransport
313
- });
314
- }
315
- //#endregion
316
- //#region extensions/codex/src/session-catalog-listing.ts
317
- async function listVisiblePage(params) {
318
- const excluded = params.excludedThreadIds;
319
- const sessions = [];
320
- let cursor = params.cursor;
321
- let nextCursor;
322
- let backwardsCursor;
323
- const seenCursors = /* @__PURE__ */ new Set();
324
- for (let pageIndex = 0; pageIndex < 20; pageIndex += 1) {
325
- params.signal?.throwIfAborted();
326
- let excludedFromPage = false;
327
- const rawPage = await params.control.listPage({
328
- limit: params.limit - sessions.length,
329
- ...cursor ? { cursor } : {},
330
- ...params.searchTerm ? { searchTerm: params.searchTerm } : {},
331
- ...params.cwd ? { cwd: params.cwd } : {}
332
- });
333
- params.signal?.throwIfAborted();
334
- const page = filterCatalogPageByTitle(parseCatalogPage(rawPage), params.searchTerm);
335
- if (pageIndex === 0) backwardsCursor = page.backwardsCursor;
336
- for (const managed of rawPage.managedThreads ?? []) {
337
- excludedFromPage = true;
338
- params.signal?.throwIfAborted();
339
- await params.onExcludedThread?.(managed);
340
- }
341
- for (const session of page.sessions) {
342
- if (!excluded?.has(session.threadId)) {
343
- sessions.push(session);
344
- continue;
345
- }
346
- excludedFromPage = true;
347
- params.signal?.throwIfAborted();
348
- await params.onExcludedThread?.({ threadId: session.threadId });
349
- }
350
- nextCursor = page.nextCursor;
351
- if (!nextCursor || sessions.length >= params.limit || !excludedFromPage) break;
352
- if (seenCursors.has(nextCursor)) throw new Error("Codex session catalog returned a repeated exclusion cursor");
353
- seenCursors.add(nextCursor);
354
- cursor = nextCursor;
355
- }
356
- return {
357
- sessions: sessions.slice(0, params.limit),
358
- ...nextCursor ? { nextCursor } : {},
359
- ...backwardsCursor ? { backwardsCursor } : {}
360
- };
361
- }
362
- async function listGatewayHost(params) {
363
- const hostId = params.source?.hostId ?? "gateway:local";
364
- const label = params.source?.label ?? "Local Codex";
365
- const sourceHomeId = params.source?.sourceHomeId ?? "gateway:local";
366
- try {
367
- const page = await listVisiblePage({
368
- control: params.control,
369
- cursor: params.query.cursors?.[hostId],
370
- excludedThreadIds: params.excludedThreadIds,
371
- limit: params.query.limitPerHost,
372
- onExcludedThread: params.onExcludedThread,
373
- searchTerm: params.query.search,
374
- signal: params.signal
375
- });
376
- params.signal?.throwIfAborted();
377
- const { listAdoptedSessionEntries } = await import("./session-catalog-adoption-tcZi1IfX.js");
378
- const { sessionCatalogAdoptedSourceKey } = await import("openclaw/plugin-sdk/session-catalog");
379
- params.signal?.throwIfAborted();
380
- const adoptedSessions = await listAdoptedSessionEntries({
381
- agentId: params.agentId,
382
- bindingStore: params.bindingStore,
383
- config: params.config,
384
- runtime: params.runtime,
385
- sessionEntries: params.sessionEntries
386
- });
387
- return {
388
- hostId,
389
- label,
390
- kind: "gateway",
391
- connected: true,
392
- ...page,
393
- sessions: page.sessions.map((session) => {
394
- const adopted = adoptedSessions.get(sessionCatalogAdoptedSourceKey(sourceHomeId, session.threadId)) ?? (hostId === "gateway:local" ? adoptedSessions.get(sessionCatalogAdoptedSourceKey("gateway:local", session.threadId)) : void 0);
395
- const sourced = params.source ? Object.assign({}, session, { sourceHomeId: params.source.sourceHomeId }) : session;
396
- return adopted ? Object.assign({}, sourced, { sessionKey: adopted.key }) : sourced;
397
- })
398
- };
399
- } catch (error) {
400
- return {
401
- hostId,
402
- label,
403
- kind: "gateway",
404
- connected: false,
405
- sessions: [],
406
- error: catalogError("APP_SERVER_UNAVAILABLE", error)
407
- };
408
- }
409
- }
410
- /** Lists Gateway-local and paired-node Codex sessions with per-host failures. */
411
- async function listCodexSessionCatalog(params) {
412
- const agentId = resolveSessionAgentIdsStrict({
413
- config: params.config ?? {},
414
- agentId: params.agentId
415
- }).sessionAgentId;
416
- const query = readGatewayParams(params.query);
417
- const requestedHostIds = query.hostIds ? new Set(query.hostIds) : void 0;
418
- const localSources = params.localHomes?.filter((source) => !requestedHostIds || requestedHostIds.has(source.hostId)) ?? (params.includeLocal !== false && (!requestedHostIds || requestedHostIds.has("gateway:local")) ? [void 0] : []);
419
- const managedThreads = await params.bindingStore.managedThreads?.snapshot();
420
- params.signal?.throwIfAborted();
421
- const fallbackSource = params.control.homesForAgent(agentId)[0];
422
- const localHosts = localSources.map((source) => (() => {
423
- const ownershipSource = source ?? fallbackSource;
424
- const managedThreadIds = ownershipSource ? managedThreads?.get(ownershipSource.sourceHomeId) : void 0;
425
- return listGatewayHost({
426
- agentId,
427
- bindingStore: params.bindingStore,
428
- config: params.config,
429
- control: params.control.forRequest(agentId, ownershipSource),
430
- query,
431
- runtime: params.runtime,
432
- sessionEntries: params.sessionEntries,
433
- signal: params.signal,
434
- excludedThreadIds: managedThreadIds,
435
- ...ownershipSource && params.bindingStore.managedThreads ? { onExcludedThread: async ({ threadId, rolloutPath }) => {
436
- if (!managedThreadIds?.has(threadId)) await params.bindingStore.managedThreads?.mark({
437
- sourceHomeId: ownershipSource.sourceHomeId,
438
- threadId,
439
- ...rolloutPath ? { rolloutPath } : {}
440
- });
441
- } } : {},
442
- ...source ? { source } : {}
443
- });
444
- })());
445
- for (const host of localHosts) publishSessionCatalogHost(params, host);
446
- if (!(!requestedHostIds || query.hostIds?.some((hostId) => hostId.startsWith("node:")))) return { hosts: await Promise.all(localHosts) };
447
- let nodes;
448
- try {
449
- nodes = (await (params.listNodes?.() ?? params.runtime.nodes.list())).nodes.filter((node) => node.gatewayLocal !== true && (node.commands?.includes("codex.appServer.threads.list.v1") || codexNodeTerminalCapability(node).canStartTerminal) && (!requestedHostIds || requestedHostIds.has(`node:${node.nodeId}`))).slice(0, 100 - localHosts.length);
450
- } catch (error) {
451
- const registryHost = {
452
- hostId: "node:registry",
453
- label: "Paired nodes",
454
- kind: "node",
455
- connected: false,
456
- canStartTerminal: false,
457
- sessions: [],
458
- error: catalogError("NODE_LIST_FAILED", error)
459
- };
460
- params.onHost?.(registryHost);
461
- return { hosts: [...await Promise.all(localHosts), registryHost] };
462
- }
463
- params.signal?.throwIfAborted();
464
- const { listNodeAdoptedSessionEntries } = await import("./session-catalog-node-adoption-B1tgDW-m.js");
465
- const { compareNodeLabels, listPairedNode } = await import("./session-catalog-node-continue-Ci-DXyJP.js");
466
- params.signal?.throwIfAborted();
467
- const adoptedNodeSessions = listNodeAdoptedSessionEntries({
468
- agentId,
469
- config: params.config,
470
- runtime: params.runtime,
471
- sessionEntries: params.sessionEntries
472
- });
473
- const nodeHosts = nodes.toSorted(compareNodeLabels).map((node) => listPairedNode({
474
- agentId,
475
- runtime: params.runtime,
476
- node,
477
- query,
478
- adoptedSessions: adoptedNodeSessions,
479
- terminalCapabilities: codexNodeTerminalCapability(node),
480
- waitUntil: params.waitUntil,
481
- signal: params.signal,
482
- ...params.onHost ? { onHost: params.onHost } : {}
483
- }));
484
- return { hosts: await Promise.all([...localHosts, ...nodeHosts]) };
485
- }
486
- /** Builds the node-local read-only Codex app-server catalog command. */
487
- function createCodexSessionCatalogNodeHostCommands(controlFactory, configSources, bindingStore) {
488
- const bindRequest = (paramsJSON) => {
489
- const parsed = parseJsonParams(paramsJSON);
490
- if (!isRecord(parsed)) throw new CatalogParamsError("Codex session catalog parameters must be an object");
491
- const requestedAgentId = readBoundedOptionalString(parsed, "agentId", 256);
492
- const config = configSources.getRuntimeConfig() ?? {};
493
- const agentId = resolveSessionAgentIdsStrict({
494
- config,
495
- agentId: requestedAgentId
496
- }).sessionAgentId;
497
- if (!listAgentIds(config).includes(agentId)) throw new CatalogParamsError(`unknown Codex session catalog agent: ${agentId}`);
498
- const request = { ...parsed };
499
- delete request.agentId;
500
- const source = controlFactory.homesForAgent(agentId)[0];
501
- return {
502
- agentId,
503
- control: controlFactory.forRequest(agentId, source),
504
- sourceHomeId: source?.sourceHomeId,
505
- params: request,
506
- paramsJSON: JSON.stringify(request)
507
- };
508
- };
509
- const commands = [
510
- {
511
- command: CODEX_APP_SERVER_THREADS_LIST_COMMAND,
512
- cap: CODEX_APP_SERVER_THREADS_CAPABILITY,
513
- dangerous: false,
514
- handle: async (paramsJSON) => {
515
- const request = bindRequest(paramsJSON);
516
- const pageParams = readPageParams(request.params);
517
- try {
518
- const managedThreads = await bindingStore?.managedThreads?.snapshot();
519
- const sourceHomeId = request.sourceHomeId;
520
- const managedThreadIds = sourceHomeId ? managedThreads?.get(sourceHomeId) : void 0;
521
- const page = await listVisiblePage({
522
- control: request.control,
523
- cursor: pageParams.cursor,
524
- cwd: pageParams.cwd,
525
- excludedThreadIds: managedThreadIds,
526
- limit: pageParams.limit,
527
- ...sourceHomeId && bindingStore?.managedThreads ? { onExcludedThread: async ({ threadId, rolloutPath }) => {
528
- if (!managedThreadIds?.has(threadId)) await bindingStore.managedThreads?.mark({
529
- sourceHomeId,
530
- threadId,
531
- ...rolloutPath ? { rolloutPath } : {}
532
- });
533
- } } : {},
534
- searchTerm: pageParams.searchTerm
535
- });
536
- return JSON.stringify(page);
537
- } catch {
538
- throw new Error("Codex app-server catalog is unavailable");
539
- }
540
- }
541
- },
542
- {
543
- command: CODEX_APP_SERVER_THREAD_TURNS_LIST_COMMAND,
544
- cap: CODEX_APP_SERVER_THREADS_CAPABILITY,
545
- dangerous: false,
546
- handle: async (paramsJSON) => {
547
- const request = bindRequest(paramsJSON);
548
- const action = readNodeTranscriptParams(request.params);
549
- try {
550
- await request.control.requireEligibleThread(action.threadId);
551
- const page = parseTranscriptPage(await request.control.listTurnPage({
552
- threadId: action.threadId,
553
- limit: action.limit,
554
- sortDirection: "desc",
555
- itemsView: "full",
556
- ...action.cursor ? { cursor: action.cursor } : {}
557
- }));
558
- return JSON.stringify(page);
559
- } catch (error) {
560
- if (error instanceof CatalogParamsError) throw error;
561
- throw new Error("Codex app-server transcript is unavailable", { cause: error });
562
- }
563
- }
564
- },
565
- {
566
- command: CODEX_CATALOG_TRANSCRIPT_READ_COMMAND,
567
- cap: CODEX_APP_SERVER_THREADS_CAPABILITY,
568
- dangerous: false,
569
- handle: async (paramsJSON) => {
570
- const request = bindRequest(paramsJSON);
571
- const action = readNodeTranscriptParams(request.params);
572
- try {
573
- return JSON.stringify(await readCodexCatalogTranscriptPage(request.control, action));
574
- } catch (error) {
575
- if (error instanceof CatalogParamsError) throw error;
576
- throw new Error("Codex app-server transcript is unavailable", { cause: error });
577
- }
578
- }
579
- },
580
- createCodexTerminalNodeHostCommand(bindRequest, configSources),
581
- createCodexTerminalStartNodeHostCommand()
582
- ];
583
- return process.env.OPENCLAW_NODE_EXEC_HOST?.trim().toLowerCase() === "app" ? commands.filter(({ command }) => command !== CODEX_CATALOG_TRANSCRIPT_READ_COMMAND) : commands;
584
- }
585
- function readNodeTranscriptParams(value) {
586
- if (!isRecord(value)) throw new CatalogParamsError("Codex session read parameters must be an object");
587
- requireOnlyKeys(value, /* @__PURE__ */ new Set([
588
- "threadId",
589
- "cursor",
590
- "limit"
591
- ]));
592
- const threadId = readBoundedOptionalString(value, "threadId", 256);
593
- if (!threadId) throw new CatalogParamsError("threadId is required");
594
- const cursor = readBoundedOptionalString(value, "cursor", MAX_CURSOR_LENGTH);
595
- return {
596
- threadId,
597
- limit: readBoundedLimit(value.limit, "limit", 20, 50),
598
- ...cursor ? { cursor } : {}
599
- };
600
- }
601
- function readBoundedLimit(value, key, fallback, max) {
602
- if (value === void 0) return fallback;
603
- if (!Number.isInteger(value) || value < 1 || value > max) throw new CatalogParamsError(`${key} must be an integer from 1 to ${max}`);
604
- return value;
605
- }
606
- /** Reads the persisted transcript for a Gateway-local or paired-node Codex session. */
607
- async function readCodexSessionTranscript(params) {
608
- const cursor = readControlCursor(params.cursor, "transcript request");
609
- const limit = readBoundedLimit(params.limit, "limit", 20, 50);
610
- if (params.source || params.hostId === "gateway:local") {
611
- const page = await readCodexCatalogTranscriptPage(params.control, {
612
- threadId: params.threadId,
613
- limit,
614
- cursor
615
- });
616
- return {
617
- hostId: params.hostId,
618
- label: params.source?.label ?? "Local Codex",
619
- threadId: params.threadId,
620
- ...page
621
- };
622
- }
623
- const nodeId = params.hostId.slice(5);
624
- const node = (await params.runtime.nodes.list()).nodes.find((candidate) => candidate.nodeId === nodeId && candidate.connected === true && candidate.commands?.includes("codex.appServer.thread.turns.list.v1"));
625
- if (!node) throw new CatalogParamsError("paired-node Codex session host is offline or unavailable");
626
- const invoke = async (command, request) => unwrapNodeInvokePayload(await params.runtime.nodes.invoke({
627
- nodeId,
628
- command,
629
- params: {
630
- agentId: params.agentId,
631
- threadId: params.threadId,
632
- ...request
633
- },
634
- timeoutMs: NODE_INVOKE_TIMEOUT_MS,
635
- scopes: ["operator.write"]
636
- }));
637
- const page = node.commands?.includes("codex.sessionCatalog.transcript.read.v1") ? parseCodexCatalogTranscriptPage(await invoke(CODEX_CATALOG_TRANSCRIPT_READ_COMMAND, {
638
- cursor,
639
- limit
640
- })) : await readLegacyCodexTranscriptPage(async ({ cursor: turnCursor, limit: turnLimit }) => parseTranscriptPage(await invoke(CODEX_APP_SERVER_THREAD_TURNS_LIST_COMMAND, {
641
- cursor: turnCursor,
642
- limit: turnLimit
643
- })), {
644
- threadId: params.threadId,
645
- cursor,
646
- limit
647
- });
648
- const { nodeLabel } = await import("./session-catalog-node-continue-Ci-DXyJP.js");
649
- return {
650
- hostId: params.hostId,
651
- label: nodeLabel(node),
652
- threadId: params.threadId,
653
- ...page
654
- };
655
- }
656
- //#endregion
657
- //#region extensions/codex/src/session-upstream-activity.ts
658
- const CODEX_UPSTREAM_TURN_LIMIT = 100;
659
- function readMarker(probe) {
660
- if (!isRecord(probe.marker)) return;
661
- const turnId = probe.marker.turnId;
662
- if (turnId !== null && typeof turnId !== "string") return;
663
- const count = probe.marker.userMessageCount;
664
- if (count !== void 0 && (!Number.isSafeInteger(count) || count < 0)) return;
665
- return {
666
- turnId,
667
- ...count === void 0 ? {} : { userMessageCount: count }
668
- };
669
- }
670
- function upstreamConnectionFingerprint(probe) {
671
- return isRecord(probe.upstreamRef) && typeof probe.upstreamRef.connectionFingerprint === "string" ? probe.upstreamRef.connectionFingerprint : void 0;
672
- }
673
- function classifyCodexUpstreamTurns(params) {
674
- const marker = readMarker(params.probe);
675
- if (!marker) return;
676
- const newest = params.turns[0];
677
- if (!newest?.id) return;
678
- const markerIndex = marker.turnId === null ? -1 : params.turns.findIndex((turn) => turn.id === marker.turnId);
679
- const candidateTurns = markerIndex < 0 ? params.turns : params.turns.slice(0, markerIndex + 1);
680
- const newestUserMessageCount = countUserMessages(newest);
681
- if (!(marker.turnId !== newest.id || marker.userMessageCount === void 0 || newestUserMessageCount > marker.userMessageCount)) return;
682
- const ownTexts = new Set(params.probe.ownRecentUserTexts);
683
- let humanTurns = 0;
684
- let occurredAt;
685
- for (const turn of candidateTurns) {
686
- const userMessages = turn.items.filter((item) => item.type === "userMessage");
687
- const alreadySeen = turn.id === marker.turnId ? marker.userMessageCount ?? userMessages.length : 0;
688
- for (const item of userMessages.slice(alreadySeen)) {
689
- const texts = normalizeUserMessageTexts(item);
690
- if (ownTexts.has(texts.join(" ")) || texts.length > 1 && texts.every((text) => ownTexts.has(text))) continue;
691
- humanTurns += 1;
692
- if (occurredAt === void 0) {
693
- const timestampSeconds = turn.completedAt ?? turn.startedAt;
694
- occurredAt = typeof timestampSeconds === "number" && Number.isFinite(timestampSeconds) ? timestampSeconds * 1e3 : params.now ?? Date.now();
695
- }
696
- }
697
- }
698
- const activityId = `${newest.id}:${newestUserMessageCount}`;
699
- return {
700
- kind: "activity",
701
- sessionKey: params.probe.sessionKey,
702
- humanTurns,
703
- nextMarker: {
704
- turnId: newest.id,
705
- userMessageCount: newestUserMessageCount
706
- },
707
- ...humanTurns > 0 ? {
708
- occurredAt: occurredAt ?? params.now ?? Date.now(),
709
- dedupeId: activityId
710
- } : {}
711
- };
712
- }
713
- function countUserMessages(turn) {
714
- return turn.items.filter((item) => item.type === "userMessage").length;
715
- }
716
- function normalizeUserMessageTexts(item) {
717
- const typed = item;
718
- const contentTexts = typed.content?.filter((input) => input.type === "text").map((input) => input.text.trim().replace(/\s+/g, " ")).filter(Boolean);
719
- return contentTexts?.length ? contentTexts : [(typed.text ?? "").trim().replace(/\s+/g, " ")];
720
- }
721
- async function checkCodexUpstreamActivity(probes, control, resolveThreadId = (probe) => probe.threadId) {
722
- return await control.withPinnedConnection(async (pinned) => {
723
- const activities = [];
724
- for (const probe of probes) {
725
- const fingerprint = upstreamConnectionFingerprint(probe);
726
- if (probe.upstreamKind !== "codex-app-server" || !fingerprint || fingerprint !== pinned.connectionFingerprint) continue;
727
- try {
728
- const threadId = resolveThreadId(probe);
729
- const page = await pinned.listTurnPage({
730
- threadId,
731
- limit: CODEX_UPSTREAM_TURN_LIMIT,
732
- sortDirection: "desc",
733
- itemsView: "full"
734
- });
735
- const marker = readMarker(probe);
736
- if (page.data.length === 0 && marker) {
737
- try {
738
- await pinned.readThread(threadId, false);
739
- } catch (error) {
740
- if (isCodexThreadReadMissingError(error, threadId)) activities.push({
741
- kind: "missing",
742
- sessionKey: probe.sessionKey
743
- });
744
- }
745
- continue;
746
- }
747
- const activity = classifyCodexUpstreamTurns({
748
- probe,
749
- turns: page.data
750
- });
751
- if (activity) activities.push(activity);
752
- } catch {}
753
- }
754
- return activities;
755
- });
756
- }
757
- function createChecker(params) {
758
- const resolveThreadId = (probe) => {
759
- const config = params.getRuntimeConfig();
760
- const sessionId = params.api.runtime.agent.session.getSessionEntry({
761
- agentId: probe.agentId,
762
- sessionKey: probe.sessionKey,
763
- readConsistency: "latest"
764
- })?.sessionId?.trim();
765
- if (!sessionId) return probe.threadId;
766
- const binding = params.bindingStore.read(sessionBindingIdentity({
767
- sessionId,
768
- sessionKey: probe.sessionKey,
769
- config
770
- }));
771
- return binding?.connectionScope === "supervision" && binding.supervisionSourceThreadId === probe.threadId ? binding.threadId : probe.threadId;
772
- };
773
- return async (probes) => {
774
- const groups = /* @__PURE__ */ new Map();
775
- for (const probe of probes) {
776
- const fingerprint = upstreamConnectionFingerprint(probe);
777
- if (!fingerprint) continue;
778
- const control = params.control.forUpstream(probe.agentId, fingerprint);
779
- if (!control) continue;
780
- const key = `${probe.agentId}\0${fingerprint}`;
781
- const group = groups.get(key) ?? {
782
- control,
783
- probes: []
784
- };
785
- group.probes.push(probe);
786
- groups.set(key, group);
787
- }
788
- return (await Promise.all([...groups.values()].map((group) => checkCodexUpstreamActivity(group.probes, group.control, resolveThreadId)))).flat();
789
- };
790
- }
791
- //#endregion
792
- //#region extensions/codex/src/session-catalog-homes.ts
793
- function existingCatalogHomeCandidates(value, label) {
794
- const codexHome = canonicalCodexCatalogHome(value);
795
- try {
796
- if (!fs.statSync(codexHome).isDirectory()) return [];
797
- } catch {
798
- return [];
799
- }
800
- return [{
801
- codexHome,
802
- label: `Local Codex · ${label ?? path.basename(codexHome)}`
803
- }];
804
- }
805
- /** Resolves every local Codex store the operator already owns, without path disclosure. */
806
- function resolveCodexCatalogHomes(params) {
807
- const { config, env, ownerAgentId, pluginConfig } = params;
808
- const ownerAgentDir = resolveAgentDir(config, ownerAgentId, env);
809
- const configuredHomes = readCodexPluginConfig(pluginConfig).sessionCatalog?.homes ?? [];
810
- const base = params.resolveRuntimeOptions({
811
- pluginConfig,
812
- env,
813
- agentDir: ownerAgentDir,
814
- config
815
- });
816
- const primaryCodexHome = canonicalCodexCatalogHome(resolveCodexAppServerLocalHomeDir(base.start, ownerAgentDir, env));
817
- const processUserHome = canonicalCodexCatalogHome(resolveCodexAppServerUserHomeDir(env));
818
- const processHomeConfigured = Boolean(env.CODEX_HOME?.trim());
819
- const candidates = [{
820
- codexHome: primaryCodexHome,
821
- label: "Local Codex",
822
- usesProcessHomeFallback: base.start.transport === "stdio" && base.start.homeScope === "user" && !processHomeConfigured
823
- }];
824
- if (base.start.transport === "stdio") {
825
- candidates.push({
826
- codexHome: processUserHome,
827
- label: "Local Codex · user",
828
- usesProcessHomeFallback: !processHomeConfigured
829
- });
830
- const agentIds = listAgentIds(config).toSorted((left, right) => left === ownerAgentId ? -1 : right === ownerAgentId ? 1 : left.localeCompare(right));
831
- candidates.push(...agentIds.flatMap((agentId) => existingCatalogHomeCandidates(resolveCodexAppServerHomeDir(resolveAgentDir(config, agentId, env)), agentId)), ...configuredHomes.flatMap((entry) => {
832
- const { path: home, label } = typeof entry === "string" ? { path: entry } : entry;
833
- return existingCatalogHomeCandidates(home, label);
834
- }));
835
- }
836
- const seen = /* @__PURE__ */ new Set();
837
- const homes = [];
838
- for (const candidate of candidates) {
839
- if (seen.has(candidate.codexHome)) continue;
840
- seen.add(candidate.codexHome);
841
- const sourceHomeId = codexCatalogHomeId(candidate.codexHome);
842
- const primary = homes.length === 0;
843
- homes.push({
844
- sourceHomeId,
845
- hostId: primary ? CODEX_LOCAL_SESSION_HOST_ID : `${CODEX_LOCAL_SESSION_HOST_ID}:${sourceHomeId}`,
846
- label: candidate.label,
847
- agentDir: ownerAgentDir,
848
- appServer: primary ? base : {
849
- ...base,
850
- start: {
851
- ...base.start,
852
- homeScope: "user",
853
- env: {
854
- ...base.start.env,
855
- CODEX_HOME: candidate.codexHome
856
- }
857
- }
858
- },
859
- ...base.connectionClass === "remote" ? {} : { localSessionsRoot: path.join(candidate.codexHome, "sessions") },
860
- usesProcessHomeFallback: candidate.usesProcessHomeFallback ?? false
861
- });
862
- if (homes.length >= 100) break;
863
- }
864
- return homes;
865
- }
866
- /** Discovers Codex homes once per immutable Gateway config generation. */
867
- function createCodexCatalogHomeResolver(params) {
868
- const env = params.env ?? process.env;
869
- const homesByConfig = /* @__PURE__ */ new WeakMap();
870
- const buildSnapshot = (config) => {
871
- const pluginConfig = params.getPluginConfig();
872
- const homesByAgent = new Map(listAgentIds(config).map((agentId) => [agentId, resolveCodexCatalogHomes({
873
- config,
874
- pluginConfig,
875
- ownerAgentId: agentId,
876
- env,
877
- resolveRuntimeOptions: params.resolveRuntimeOptions
878
- })]));
879
- replaceCodexCatalogConnectionHomes([...homesByAgent.values()].flatMap((homes) => homes.filter((home) => home.appServer.start.transport === "stdio").map((home) => ({
880
- agentDir: home.agentDir,
881
- fingerprint: buildCodexAppServerConnectionFingerprint(home.appServer, home.agentDir),
882
- codexHome: resolveCodexAppServerLocalHomeDir(home.appServer.start, home.agentDir, env)
883
- }))));
884
- homesByConfig.set(config, homesByAgent);
885
- return homesByAgent;
886
- };
887
- let lastSnapshot = buildSnapshot(params.config);
888
- return { forAgent(agentId) {
889
- const config = params.getRuntimeConfig();
890
- if (!config) return lastSnapshot.get(agentId) ?? [];
891
- const cached = homesByConfig.get(config);
892
- if (cached) return cached.get(agentId) ?? [];
893
- lastSnapshot = buildSnapshot(config);
894
- return lastSnapshot.get(agentId) ?? [];
895
- } };
896
- }
897
- //#endregion
898
- //#region extensions/codex/src/session-catalog-control.ts
899
- const CODEX_SESSION_CATALOG_LIST_TTL_MS = 32e3;
900
- const CODEX_SESSION_CATALOG_LIST_CACHE_MAX_ENTRIES = 32;
901
- function codexCatalogPageCacheKey(params, agentId, source) {
902
- return JSON.stringify([
903
- agentId,
904
- source?.sourceHomeId ?? null,
905
- params.cursor ?? null,
906
- params.limit ?? null,
907
- params.searchTerm?.trim().toLocaleLowerCase() || null,
908
- params.cwd?.trim() || null
909
- ]);
910
- }
911
- function createCodexCatalogRequestSnapshot(requestTimeoutMs, request) {
912
- return {
913
- requestTimeoutMs,
914
- listThreads: (params, timeoutMs) => request(CODEX_CONTROL_METHODS.listThreads, params, timeoutMs),
915
- listThreadTurns: (params) => request(CODEX_CONTROL_METHODS.listThreadTurns, params),
916
- listThreadItems: (params) => request(CODEX_CONTROL_METHODS.listThreadItems, params),
917
- forkThread: (params, assertCurrent) => request(CODEX_CONTROL_METHODS.forkThread, assertCodexThreadForkParams(params), void 0, assertCurrent),
918
- readThread: async (threadId, includeTurns, timeoutMs) => (await request(CODEX_CONTROL_METHODS.readThread, {
919
- threadId,
920
- includeTurns
921
- }, timeoutMs)).thread,
922
- archiveThread: async (threadId, assertCurrent) => {
923
- await request(CODEX_CONTROL_METHODS.archiveThread, { threadId }, void 0, assertCurrent);
924
- }
925
- };
926
- }
927
- function createCodexSessionCatalogControlFromRequests(params) {
928
- return {
929
- forkContext: params.forkContext,
930
- ...params.clientId ? { clientId: params.clientId } : {},
931
- ...params.connectionFingerprint ? { connectionFingerprint: params.connectionFingerprint } : {},
932
- withPinnedConnection: params.withPinnedConnection,
933
- async requireEligibleThread(threadId) {
934
- const requests = params.createRequestSnapshot();
935
- const deadline = params.now() + requests.requestTimeoutMs;
936
- const unverified = () => new CatalogParamsError("Codex session eligibility could not be verified. Refresh the catalog and verify the session in its native Codex home before retrying.");
937
- const remaining = () => {
938
- const timeoutMs = Math.ceil(deadline - params.now());
939
- if (timeoutMs <= 0) throw unverified();
940
- return timeoutMs;
941
- };
942
- const verify = async () => {
943
- if (params.sourceHomeId && await params.managedThreads?.has(params.sourceHomeId, threadId)) throw unverified();
944
- const root = params.localSessionsRoot;
945
- const thread = root ? await requests.readThread(threadId, false, remaining()) : void 0;
946
- if (root && (!thread || thread.id !== threadId || !isInteractiveThreadSource(thread.source))) throw unverified();
947
- let cursor;
948
- const seenCursors = /* @__PURE__ */ new Set();
949
- for (let pageIndex = 0; pageIndex < 100; pageIndex += 1) {
950
- const page = await requests.listThreads({
951
- archived: false,
952
- limit: 100,
953
- modelProviders: [],
954
- sortKey: root ? "recency_at" : "updated_at",
955
- sortDirection: "desc",
956
- ...root ? {
957
- useStateDbOnly: true,
958
- ...thread?.cwd ? { cwd: thread.cwd } : {}
959
- } : {},
960
- ...cursor ? { cursor } : {}
961
- }, remaining());
962
- remaining();
963
- const candidate = page.data.find((value) => value.id === threadId);
964
- if (candidate) {
965
- if (!isInteractiveThreadSource(candidate.source)) throw unverified();
966
- if (root && thread) {
967
- const rolloutPath = thread.path;
968
- if (!rolloutPath || !candidate.path || rolloutPath.replace(/\.zst$/u, "") !== candidate.path.replace(/\.zst$/u, "")) throw unverified();
969
- const metadata = await readCodexSessionMeta(root, rolloutPath, threadId);
970
- remaining();
971
- if (!metadata || !isInteractiveThreadSource(metadata.source) || metadata.originator === "openclaw") throw unverified();
972
- return thread;
973
- }
974
- return candidate;
975
- }
976
- const nextCursor = readControlCursor(page.nextCursor, "next response");
977
- if (!nextCursor || seenCursors.has(nextCursor)) throw unverified();
978
- seenCursors.add(nextCursor);
979
- cursor = nextCursor;
980
- }
981
- throw unverified();
982
- };
983
- return await withTimeout(verify(), requests.requestTimeoutMs, "Codex session eligibility could not be verified", unverified);
984
- },
985
- retireConnection: params.retireConnection,
986
- async listPage(pageParams) {
987
- const limit = normalizeLimit(pageParams.limit, "limit");
988
- const search = pageParams.searchTerm?.trim().toLocaleLowerCase() || void 0;
989
- const cwd = pageParams.cwd?.trim() || void 0;
990
- const maxPages = search ? 20 : 1;
991
- const sessions = [];
992
- const managedThreads = [];
993
- let cursor = readControlCursor(pageParams.cursor, "request");
994
- let nextCursor;
995
- let backwardsCursor;
996
- const seenCursors = new Set(cursor ? [cursor] : []);
997
- const requests = params.createRequestSnapshot();
998
- const deadline = params.now() + requests.requestTimeoutMs;
999
- const { sanitizeTerminalText } = await import("openclaw/plugin-sdk/text-chunking");
1000
- for (let pageIndex = 0; pageIndex < maxPages; pageIndex += 1) {
1001
- const remainingTimeoutMs = Math.ceil(deadline - params.now());
1002
- if (remainingTimeoutMs <= 0) throw new Error("Codex session catalog listing timed out");
1003
- const response = await requests.listThreads({
1004
- archived: false,
1005
- limit: limit - sessions.length,
1006
- modelProviders: [],
1007
- sortKey: "updated_at",
1008
- sortDirection: "desc",
1009
- ...cwd ? { cwd } : {},
1010
- ...cursor ? { cursor } : {}
1011
- }, remainingTimeoutMs);
1012
- if (pageIndex === 0) backwardsCursor = readControlCursor(response.backwardsCursor, "backwards response");
1013
- for (const thread of response.data) {
1014
- if (await isOpenClawManagedCodexThread(thread, params.localSessionsRoot)) {
1015
- const rolloutPath = typeof thread.path === "string" ? thread.path.trim() : "";
1016
- managedThreads.push({
1017
- threadId: thread.id,
1018
- ...rolloutPath ? { rolloutPath } : {}
1019
- });
1020
- continue;
1021
- }
1022
- const session = toCatalogSession(thread, false, sanitizeTerminalText);
1023
- if (session && (!search || (session.name ?? session.fallbackName)?.toLocaleLowerCase().includes(search))) sessions.push(session);
1024
- }
1025
- nextCursor = readControlCursor(response.nextCursor, "next response");
1026
- if (!nextCursor || sessions.length >= limit) break;
1027
- if (seenCursors.has(nextCursor)) throw new Error("Codex session catalog returned a repeated search cursor");
1028
- seenCursors.add(nextCursor);
1029
- cursor = nextCursor;
1030
- }
1031
- return {
1032
- sessions,
1033
- ...managedThreads.length > 0 ? { managedThreads } : {},
1034
- ...nextCursor ? { nextCursor } : {},
1035
- ...backwardsCursor ? { backwardsCursor } : {}
1036
- };
1037
- },
1038
- async listDescendantPage(listParams) {
1039
- const requests = params.createRequestSnapshot();
1040
- return await requests.listThreads(listParams, requests.requestTimeoutMs);
1041
- },
1042
- async readThread(threadId, includeTurns = false) {
1043
- return await params.createRequestSnapshot().readThread(threadId, includeTurns);
1044
- },
1045
- async listTurnPage(listParams) {
1046
- return await params.createRequestSnapshot().listThreadTurns(listParams);
1047
- },
1048
- listItemPage: (listParams) => params.createRequestSnapshot().listThreadItems(listParams),
1049
- async forkThread(forkParams, assertCurrent) {
1050
- return await params.createRequestSnapshot().forkThread(forkParams, assertCurrent);
1051
- },
1052
- async archiveThread(threadId, assertCurrent) {
1053
- await params.createRequestSnapshot().archiveThread(threadId, assertCurrent);
1054
- }
1055
- };
1056
- }
1057
- /** Builds the passive catalog over the Codex plugin's canonical shared client. */
1058
- function createCodexSessionCatalogControl(params) {
1059
- const now = params.now ?? Date.now;
1060
- const getPluginConfig = () => params.getPluginConfig();
1061
- const homeResolver = createCodexCatalogHomeResolver({
1062
- config: params.getRuntimeConfig() ?? params.config ?? {},
1063
- getRuntimeConfig: params.getRuntimeConfig,
1064
- getPluginConfig: params.getPluginConfig,
1065
- resolveRuntimeOptions: params.resolveRuntimeOptions,
1066
- ...params.env ? { env: params.env } : {}
1067
- });
1068
- const requestOptionsByConfig = /* @__PURE__ */ new WeakMap();
1069
- const catalogPagesByConfig = /* @__PURE__ */ new WeakMap();
1070
- const resolveRequestOptions = (startOptions, agentId, source) => {
1071
- const runtimeConfig = params.getRuntimeConfig();
1072
- const agentDir = source?.agentDir ?? resolveAgentDir(runtimeConfig ?? {}, agentId);
1073
- const resolvedStartOptions = source?.appServer.start ?? startOptions;
1074
- if (!runtimeConfig) return {
1075
- agentDir,
1076
- config: void 0,
1077
- startOptions: structuredClone(resolvedStartOptions)
1078
- };
1079
- let byAgent = requestOptionsByConfig.get(runtimeConfig);
1080
- const cacheKey = `${agentId ?? ""}\0${source?.sourceHomeId ?? ""}`;
1081
- const cached = byAgent?.get(cacheKey);
1082
- if (cached) return cached;
1083
- const resolved = {
1084
- agentDir,
1085
- config: structuredClone(runtimeConfig),
1086
- startOptions: structuredClone(resolvedStartOptions)
1087
- };
1088
- if (!byAgent) {
1089
- byAgent = /* @__PURE__ */ new Map();
1090
- requestOptionsByConfig.set(runtimeConfig, byAgent);
1091
- }
1092
- byAgent.set(cacheKey, resolved);
1093
- return resolved;
1094
- };
1095
- const createRequestSnapshot = (agentId, source) => {
1096
- const pluginConfig = getPluginConfig();
1097
- const runtime = source?.appServer ?? params.resolveRuntimeOptions({ pluginConfig });
1098
- const requestOptions = resolveRequestOptions(runtime.start, agentId, source);
1099
- return createCodexCatalogRequestSnapshot(runtime.requestTimeoutMs, async (method, requestParams, timeoutMs, assertCurrent) => {
1100
- const { codexControlRequest } = await import("./command-rpc-CR5EOEZX.js").then((n) => n.n);
1101
- return await codexControlRequest(pluginConfig, method, requestParams, {
1102
- ...requestOptions,
1103
- assertCurrent,
1104
- ...timeoutMs === void 0 ? {} : { timeoutMs }
1105
- });
1106
- });
1107
- };
1108
- const forRequest = (agentId, source) => {
1109
- const withPinnedConnection = async (run) => {
1110
- const pluginConfig = getPluginConfig();
1111
- const runtime = source?.appServer ?? params.resolveRuntimeOptions({ pluginConfig });
1112
- const { agentDir, config: runtimeConfig, startOptions } = resolveRequestOptions(runtime.start, agentId, source);
1113
- const { getLeasedSharedCodexAppServerClient, releaseLeasedSharedCodexAppServerClient, retireSharedCodexAppServerClientIfCurrent } = await import("./shared-client-CscigXXL.js").then((n) => n.y);
1114
- const { resolveCodexAppServerClientInstanceId } = await import("./client-B57KWPQx.js").then((n) => n.n);
1115
- const { requestCodexAppServerClientJson } = await import("./request-B7hEkBGq.js").then((n) => n.a);
1116
- const client = await getLeasedSharedCodexAppServerClient({
1117
- agentDir,
1118
- config: runtimeConfig,
1119
- startOptions,
1120
- timeoutMs: runtime.requestTimeoutMs
1121
- });
1122
- try {
1123
- const requests = createCodexCatalogRequestSnapshot(runtime.requestTimeoutMs, async (method, requestParams, timeoutMs, assertCurrent) => await requestCodexAppServerClientJson({
1124
- client,
1125
- method,
1126
- requestParams,
1127
- config: runtimeConfig,
1128
- timeoutMs: timeoutMs ?? runtime.requestTimeoutMs,
1129
- assertCurrent
1130
- }));
1131
- const pinnedControl = createCodexSessionCatalogControlFromRequests({
1132
- forkContext: {
1133
- client,
1134
- appServer: runtime,
1135
- pluginConfig,
1136
- agentDir,
1137
- localSessionsRoot: source?.localSessionsRoot
1138
- },
1139
- clientId: resolveCodexAppServerClientInstanceId(client),
1140
- retireConnection: () => {
1141
- retireSharedCodexAppServerClientIfCurrent(client);
1142
- },
1143
- connectionFingerprint: buildCodexAppServerConnectionFingerprint(runtime, agentDir),
1144
- createRequestSnapshot: () => requests,
1145
- ...source?.localSessionsRoot ? { localSessionsRoot: source.localSessionsRoot } : {},
1146
- sourceHomeId: source?.sourceHomeId,
1147
- managedThreads: params.managedThreads,
1148
- now,
1149
- withPinnedConnection: async (nestedRun) => await nestedRun(pinnedControl)
1150
- });
1151
- return await run(pinnedControl);
1152
- } finally {
1153
- releaseLeasedSharedCodexAppServerClient(client);
1154
- }
1155
- };
1156
- const control = createCodexSessionCatalogControlFromRequests({
1157
- createRequestSnapshot: () => createRequestSnapshot(agentId, source),
1158
- ...source?.localSessionsRoot ? { localSessionsRoot: source.localSessionsRoot } : {},
1159
- now,
1160
- withPinnedConnection
1161
- });
1162
- return {
1163
- ...control,
1164
- requireEligibleThread: (threadId) => withPinnedConnection((pinned) => pinned.requireEligibleThread(threadId)),
1165
- async listPage(pageParams) {
1166
- const runtimeConfig = params.getRuntimeConfig();
1167
- if (!runtimeConfig) return await control.listPage(pageParams);
1168
- let cache = catalogPagesByConfig.get(runtimeConfig);
1169
- if (!cache) {
1170
- cache = /* @__PURE__ */ new Map();
1171
- catalogPagesByConfig.set(runtimeConfig, cache);
1172
- }
1173
- const key = codexCatalogPageCacheKey(pageParams, agentId, source);
1174
- const cached = cache.get(key);
1175
- if (cached) {
1176
- cache.delete(key);
1177
- cache.set(key, cached);
1178
- if (cached.expiresAt > now()) return cached.value ?? await cached.page;
1179
- }
1180
- if (cached) cache.delete(key);
1181
- const page = control.listPage(pageParams);
1182
- const staleValue = cached?.value;
1183
- const entry = {
1184
- expiresAt: Number.POSITIVE_INFINITY,
1185
- page,
1186
- ...staleValue ? { value: staleValue } : {}
1187
- };
1188
- cache.set(key, entry);
1189
- pruneMapToMaxSize(cache, CODEX_SESSION_CATALOG_LIST_CACHE_MAX_ENTRIES);
1190
- const settle = (value) => {
1191
- if (cache.get(key) === entry) {
1192
- entry.value = value;
1193
- entry.expiresAt = now() + CODEX_SESSION_CATALOG_LIST_TTL_MS;
1194
- }
1195
- return value;
1196
- };
1197
- const restore = () => {
1198
- if (cache.get(key) !== entry) return;
1199
- if (staleValue) cache.set(key, {
1200
- expiresAt: now(),
1201
- page: Promise.resolve(staleValue),
1202
- value: staleValue
1203
- });
1204
- else cache.delete(key);
1205
- };
1206
- if (staleValue) {
1207
- page.then(settle, restore);
1208
- return staleValue;
1209
- }
1210
- try {
1211
- return settle(await page);
1212
- } catch (error) {
1213
- restore();
1214
- throw error;
1215
- }
1216
- }
1217
- };
1218
- };
1219
- const homesForAgent = (agentId) => homeResolver.forAgent(agentId);
1220
- const forUpstream = (agentId, connectionFingerprint) => {
1221
- const source = homesForAgent(agentId).find((home) => buildCodexAppServerConnectionFingerprint(home.appServer, home.agentDir) === connectionFingerprint);
1222
- return source ? forRequest(agentId, source) : void 0;
1223
- };
1224
- return {
1225
- forRequest,
1226
- forUpstream,
1227
- homesForAgent
1228
- };
1229
- }
1230
- //#endregion
1231
- //#region extensions/codex/src/session-catalog.ts
1232
- /** Allows read-only catalog and transcript commands on supported paired-node platforms. */
1233
- function createCodexSessionCatalogNodeInvokePolicies() {
1234
- return [{
1235
- commands: [
1236
- CODEX_APP_SERVER_THREADS_LIST_COMMAND,
1237
- CODEX_APP_SERVER_THREAD_TURNS_LIST_COMMAND,
1238
- CODEX_CATALOG_TRANSCRIPT_READ_COMMAND,
1239
- CODEX_TERMINAL_RESUME_COMMAND,
1240
- CODEX_TERMINAL_START_COMMAND
1241
- ],
1242
- defaultPlatforms: [
1243
- "macos",
1244
- "linux",
1245
- "windows"
1246
- ],
1247
- handle: (context) => {
1248
- if (context.command === "codex.terminal.start.v1") return context.client?.scopes?.includes("operator.admin") && context.config.gateway?.cliAgents?.enabled === true && context.config.gateway?.terminal?.enabled !== false ? { ok: true } : {
1249
- ok: false,
1250
- message: "Native terminal start requires operator.admin and enabled CLI agents and terminals"
1251
- };
1252
- return context.command === "codex.terminal.resume.v1" ? { ok: true } : context.invokeNode();
1253
- }
1254
- }];
1255
- }
1256
- function toGenericCatalogHost(host, localTerminalAvailable) {
1257
- const local = isLocalCodexCatalogHost(host.hostId);
1258
- return {
1259
- hostId: host.hostId,
1260
- label: host.label,
1261
- kind: host.kind,
1262
- connected: host.connected,
1263
- ...host.nodeId ? { nodeId: host.nodeId } : {},
1264
- sessions: host.sessions.map((session) => {
1265
- const continuableStatus = !session.archived && (session.status === "idle" || session.status === "notLoaded");
1266
- const canContinue = (local || host.canContinueCodex === true) && continuableStatus && isInteractiveThreadSource(session.source);
1267
- const canArchive = local && continuableStatus && isInteractiveThreadSource(session.source);
1268
- const canOpenTerminal = isInteractiveThreadSource(session.source) && (local ? localTerminalAvailable : host.canOpenTerminalCodex === true);
1269
- const name = session.name ?? session.fallbackName;
1270
- return {
1271
- threadId: session.threadId,
1272
- ...session.sourceHomeId ? { sourceHomeId: session.sourceHomeId } : {},
1273
- ...name ? { name } : {},
1274
- ...session.cwd ? { cwd: session.cwd } : {},
1275
- status: session.status,
1276
- ...session.createdAt != null ? { createdAt: session.createdAt } : {},
1277
- ...session.updatedAt != null ? { updatedAt: session.updatedAt } : {},
1278
- ...session.recencyAt != null ? { recencyAt: session.recencyAt } : {},
1279
- ...session.source ? { source: session.source } : {},
1280
- ...session.modelProvider ? { modelProvider: session.modelProvider } : {},
1281
- ...session.cliVersion ? { cliVersion: session.cliVersion } : {},
1282
- ...session.gitBranch ? { gitBranch: session.gitBranch } : {},
1283
- archived: session.archived,
1284
- ...session.sessionKey ? { sessionKey: session.sessionKey } : {},
1285
- canContinue,
1286
- canArchive,
1287
- canOpenTerminal
1288
- };
1289
- }),
1290
- ...host.nextCursor ? { nextCursor: host.nextCursor } : {},
1291
- ...host.error ? { error: host.error } : {}
1292
- };
1293
- }
1294
- function isLocalCodexCatalogHost(hostId) {
1295
- return hostId === "gateway:local" || hostId.startsWith(`gateway:local:`);
1296
- }
1297
- function resolveLocalCatalogHomeForThread(params) {
1298
- if (params.homes.length === 0) throw new CatalogParamsError("local Codex sessions are unavailable in isolated state");
1299
- const exact = params.sourceHomeId ? params.homes.filter((home) => home.sourceHomeId === params.sourceHomeId) : params.homes.filter((home) => home.hostId === params.hostId);
1300
- if (exact.length === 0 || params.sourceHomeId && exact[0]?.hostId !== params.hostId) throw new CatalogParamsError("Codex session source home is unavailable");
1301
- return exact[0];
1302
- }
1303
- function registerCodexSessionCatalog(params) {
1304
- const catalogHomes = (agentId, allowProcessHomeFallback) => {
1305
- const homes = params.control.homesForAgent(agentId);
1306
- return allowProcessHomeFallback === false ? homes.filter((home) => !home.usesProcessHomeFallback) : homes;
1307
- };
1308
- const resolveRequestAgentId = (agentId) => resolveSessionAgentIdsStrict({
1309
- config: params.getRuntimeConfig() ?? params.api.config,
1310
- agentId
1311
- }).sessionAgentId;
1312
- const bindRequest = (request) => {
1313
- const agentId = resolveRequestAgentId(request.agentId);
1314
- const source = isLocalCodexCatalogHost(request.hostId) ? resolveLocalCatalogHomeForThread({
1315
- homes: [...catalogHomes(agentId, request.allowProcessHomeFallback)],
1316
- hostId: request.hostId,
1317
- ...request.sourceHomeId ? { sourceHomeId: request.sourceHomeId } : {}
1318
- }) : void 0;
1319
- return {
1320
- agentId,
1321
- source,
1322
- control: params.control.forRequest(agentId, source)
1323
- };
1324
- };
1325
- const bindLocalRequest = (request) => {
1326
- const bound = bindRequest(request);
1327
- if (!bound.source) throw new CatalogParamsError("Codex session catalog hostId is invalid");
1328
- return {
1329
- ...bound,
1330
- source: bound.source
1331
- };
1332
- };
1333
- const checkUpstreamActivity = createChecker(params);
1334
- params.api.registerSessionCatalog({
1335
- id: "codex",
1336
- label: "Codex",
1337
- supportsProcessHomeIsolation: true,
1338
- resolveCreateSession: ({ agentId }) => resolveCodexCatalogCreateSession(params.api.runtime.modelConfig, params.getRuntimeConfig() ?? params.api.config, agentId),
1339
- list: async (query) => {
1340
- const localTerminalAvailable = resolveLocalCodexTerminalExecutable() !== void 0;
1341
- const { agentId: requestedAgentId, allowProcessHomeFallback, listNodes, onHost, waitUntil, signal, sessionEntries, ...gatewayQuery } = query;
1342
- const agentId = resolveRequestAgentId(requestedAgentId);
1343
- const localHomes = [...catalogHomes(agentId, allowProcessHomeFallback)];
1344
- const mapHost = (host) => ({
1345
- ...toGenericCatalogHost(host, localTerminalAvailable),
1346
- canStartTerminal: host.kind === "gateway" ? localTerminalAvailable && host.hostId === "gateway:local" && localHomes.some((home) => home.hostId === host.hostId && home.appServer.start.transport === "stdio") : host.canStartTerminal === true
1347
- });
1348
- return (await listCodexSessionCatalog({
1349
- agentId,
1350
- bindingStore: params.bindingStore,
1351
- config: params.getRuntimeConfig(),
1352
- runtime: params.api.runtime,
1353
- control: params.control,
1354
- query: gatewayQuery,
1355
- listNodes,
1356
- waitUntil,
1357
- signal,
1358
- sessionEntries,
1359
- localHomes,
1360
- ...onHost ? { onHost: (host) => onHost(mapHost(host)) } : {}
1361
- })).hosts.map(mapHost);
1362
- },
1363
- read: async (request) => {
1364
- const { agentId, source, control } = bindRequest(request);
1365
- return await readCodexSessionTranscript({
1366
- agentId,
1367
- runtime: params.api.runtime,
1368
- control,
1369
- hostId: request.hostId,
1370
- threadId: request.threadId,
1371
- cursor: request.cursor,
1372
- limit: request.limit ?? 20,
1373
- ...source ? { source } : {}
1374
- });
1375
- },
1376
- continueSession: async (request) => {
1377
- const config = params.getRuntimeConfig();
1378
- if (!config) throw new Error("OpenClaw runtime config is unavailable");
1379
- if (request.hostId.startsWith("node:")) return await continueNodeCodexSession({
1380
- agentId: resolveRequestAgentId(request.agentId),
1381
- api: params.api,
1382
- config,
1383
- hostId: request.hostId,
1384
- threadId: request.threadId,
1385
- clientScopes: request.clientScopes
1386
- });
1387
- if (!isLocalCodexCatalogHost(request.hostId)) throw new CatalogParamsError("Codex session catalog hostId is invalid");
1388
- const { agentId, source, control } = bindLocalRequest(request);
1389
- let upstreamBaseline;
1390
- const continued = await continueLocalCodexSession({
1391
- agentId,
1392
- api: params.api,
1393
- bindingStore: params.bindingStore,
1394
- config,
1395
- control,
1396
- threadId: request.threadId,
1397
- hostId: source.hostId,
1398
- sourceHomeId: source.sourceHomeId,
1399
- ...source.hostId === "gateway:local" ? { allowLegacy: true } : {},
1400
- onContinued: (baseline) => {
1401
- upstreamBaseline = baseline;
1402
- }
1403
- });
1404
- return codexUpstreamContinueResult(continued.sessionKey, request.threadId, upstreamBaseline);
1405
- },
1406
- checkUpstreamActivity: (probes, policy) => checkUpstreamActivity(probes.filter((probe) => !isLocalCodexCatalogHost(probe.hostId) || policy?.allowProcessHomeFallback !== false || catalogHomes(probe.agentId, false).some((home) => home.hostId === probe.hostId))),
1407
- archive: async (request) => {
1408
- if (request.confirmNoOtherRunner !== true) throw new CatalogParamsError("archive requires confirmation that no other runner is active");
1409
- if (!isLocalCodexCatalogHost(request.hostId)) throw new CatalogParamsError("paired-node Codex sessions are view-only");
1410
- const config = params.getRuntimeConfig();
1411
- if (!config) throw new Error("OpenClaw runtime config is unavailable");
1412
- const { agentId, source, control } = bindLocalRequest(request);
1413
- await archiveLocalCodexSession({
1414
- agentId,
1415
- bindingStore: params.bindingStore,
1416
- config,
1417
- control,
1418
- runtime: params.api.runtime,
1419
- threadId: request.threadId,
1420
- hostId: source.hostId,
1421
- sourceHomeId: source.sourceHomeId,
1422
- ...source.hostId === "gateway:local" ? { allowLegacy: true } : {}
1423
- });
1424
- return { ok: true };
1425
- },
1426
- openTerminal: async (request) => {
1427
- const { agentId, source, control } = bindRequest(request);
1428
- return await openCodexCatalogTerminal({
1429
- api: params.api,
1430
- control,
1431
- getPluginConfig: params.getPluginConfig,
1432
- getRuntimeConfig: params.getRuntimeConfig,
1433
- resolveRuntimeOptions: params.resolveRuntimeOptions,
1434
- ...source ? { source } : {},
1435
- ...request,
1436
- agentId
1437
- });
1438
- },
1439
- startTerminalSession: async (request) => {
1440
- if (!request.nodeId && request.hostId && request.hostId !== "gateway:local") throw new CatalogParamsError("Codex terminal host is unavailable; select the local machine or a connected node");
1441
- const source = request.nodeId ? void 0 : resolveLocalCatalogHomeForThread({
1442
- homes: [...catalogHomes(request.agentId, request.allowProcessHomeFallback)],
1443
- hostId: request.hostId ?? "gateway:local"
1444
- });
1445
- if (source && source.appServer.start.transport !== "stdio") throw new CatalogParamsError("Native terminal start requires a local Codex source");
1446
- return await startCodexCatalogTerminal({
1447
- getPluginConfig: params.getPluginConfig,
1448
- getRuntimeConfig: params.getRuntimeConfig,
1449
- resolveRuntimeOptions: params.resolveRuntimeOptions,
1450
- ...request,
1451
- source
1452
- });
1453
- }
1454
- });
1455
- }
1456
- const codexSessionCatalogRuntime = {
1457
- register: registerCodexSessionCatalog,
1458
- list: listCodexSessionCatalog,
1459
- readTranscript: readCodexSessionTranscript,
1460
- continueLocal: continueLocalCodexSession,
1461
- continueNode: continueNodeCodexSession,
1462
- archiveLocal: archiveLocalCodexSession
1463
- };
1464
- async function continueLocalCodexSession(...args) {
1465
- const { continueLocalCodexSession: run } = await import("./session-catalog-adoption-tcZi1IfX.js");
1466
- return run(...args);
1467
- }
1468
- async function archiveLocalCodexSession(...args) {
1469
- const { archiveLocalCodexSession: run } = await import("./session-catalog-archive-CwKg8Xz2.js");
1470
- return run(...args);
1471
- }
1472
- async function continueNodeCodexSession(...args) {
1473
- const { continueNodeCodexSession: run } = await import("./session-catalog-node-continue-Ci-DXyJP.js");
1474
- return run(...args);
1475
- }
1476
- //#endregion
1477
- export { lookupNodeCodexCatalogRecord as a, createCodexSessionCatalogNodeHostCommands as i, createCodexSessionCatalogNodeInvokePolicies as n, createCodexSessionCatalogControl as r, codexSessionCatalogRuntime as t };