@openclaw/codex 2026.9.8 → 2026.10.1-beta.1

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 (151) hide show
  1. package/README.md +8 -0
  2. package/dist/.setup/{account-usage-runtime-G348lY1q.mjs → account-usage-runtime-C4GFoef_.mjs} +5 -5
  3. package/dist/.setup/app-server-policy-Bg4FZw1f.mjs +23 -0
  4. package/dist/.setup/{apply-Cqb-YoCS.mjs → apply-D02fLpgN.mjs} +48 -39
  5. package/dist/.setup/attempt-client-cleanup-yLjGwbwT.mjs +155 -0
  6. package/dist/.setup/{attempt-workspace-context-BJ5Z_olH.mjs → attempt-workspace-context-CbSzT6V2.mjs} +11 -15
  7. package/dist/.setup/{auth-binding-BLWz7stm.mjs → auth-binding-BoMwpuPN.mjs} +17 -25
  8. package/dist/.setup/{auth-cache-key-Dnps4W4_.mjs → auth-cache-key-CEd9QlIs.mjs} +244 -82
  9. package/dist/.setup/{auth-profile-B0okYl2D.mjs → auth-profile-CgHQ8Vot.mjs} +2 -1
  10. package/dist/.setup/{auth-profile-selection-DFu9e167.mjs → auth-profile-selection-hr8ocLtz.mjs} +5 -7
  11. package/dist/.setup/{binding-connection-DTtN1KrX.mjs → binding-connection-C-08ez1w.mjs} +2 -2
  12. package/dist/.setup/{binding-connection.runtime-6TpgD1M6.mjs → binding-connection.runtime-Dn2p-fdy.mjs} +3 -3
  13. package/dist/.setup/{bounded-turn-BNunZPtz.mjs → bounded-turn-DlHlNTyS.mjs} +14 -13
  14. package/dist/.setup/{bounded-turn-isolation-B8K_ylqk.mjs → bounded-turn-isolation-DklXNk3k.mjs} +4 -4
  15. package/dist/.setup/{build-state-DIQ5O_-S.mjs → build-state-CIi3Ckqu.mjs} +1 -1
  16. package/dist/.setup/{capabilities-B3WEZl4e.mjs → capabilities-kQntafj_.mjs} +1 -1
  17. package/dist/.setup/{client-qyUBJlGZ.mjs → client-CBzEVDyb.mjs} +438 -160
  18. package/dist/.setup/{client-catalog-response-DRvx_wCC.mjs → client-catalog-response-CmvIiDdj.mjs} +57 -25
  19. package/dist/.setup/command-authorization-AikPDtcc.mjs +15 -0
  20. package/dist/.setup/{command-dispatch-Btrs1D6f.mjs → command-dispatch-BE_RdMou.mjs} +3 -3
  21. package/dist/.setup/{command-formatters-R3ckE3Co.mjs → command-formatters-DV3DHhdr.mjs} +7 -5
  22. package/dist/.setup/{command-handlers-DvlCHJch.mjs → command-handlers-DNoRq5Ps.mjs} +82 -144
  23. package/dist/.setup/{command-rpc-skzRq4wD.mjs → command-rpc-B6xsq2dB.mjs} +23 -31
  24. package/dist/.setup/{compact-8ttks5U5.mjs → compact-BLSAd-ru.mjs} +117 -65
  25. package/dist/.setup/{plugin-metadata-cache-BRwtRct9.mjs → computer-use-DpolvQHw.mjs} +65 -202
  26. package/dist/.setup/{config-DKhXquav.mjs → config-0Gxk3_eq.mjs} +5 -6
  27. package/dist/.setup/{config-options-CzyWLTJt.mjs → config-options-HG_Rr3W_.mjs} +13 -23
  28. package/dist/.setup/{config-parsing-b088LyhT.mjs → config-parsing-BQq-CHTF.mjs} +41 -4
  29. package/dist/.setup/{config-runtime-C0NbLms1.mjs → config-runtime-cUYrqu_a.mjs} +2 -2
  30. package/dist/.setup/{config-security-CE-FcGw9.mjs → config-security-KAPScztc.mjs} +20 -36
  31. package/dist/.setup/{context-engine-projection-PezSESth.mjs → context-engine-projection-CsgYSQhW.mjs} +11 -14
  32. package/dist/.setup/{conversation-binding-74LaGGH-.mjs → conversation-binding-CgSSD1Qz.mjs} +36 -48
  33. package/dist/.setup/{conversation-binding-data-C746z5Pn.mjs → conversation-binding-data-DJ4ix-W5.mjs} +1 -1
  34. package/dist/.setup/{conversation-control-OrN6zuaY.mjs → conversation-control-tCg763cI.mjs} +19 -21
  35. package/dist/.setup/{cyber-failover-XV0nNRZu.mjs → cyber-failover-Bb1J6hS1.mjs} +1 -1
  36. package/dist/.setup/{cyber-failover-notice-RNpGpTyP.mjs → cyber-failover-notice-XR03ef31.mjs} +1 -1
  37. package/dist/.setup/doctor-start-options-DPW9JxIE.mjs +63 -0
  38. package/dist/.setup/dynamic-tool-build-CVrx02cH.mjs +463 -0
  39. package/dist/.setup/{dynamic-tools-Db2sY5cZ.mjs → dynamic-tools-DdsymYGQ.mjs} +238 -878
  40. package/dist/.setup/{effective-mcp-catalog-Bi6-SQ7i.mjs → effective-mcp-catalog-BysTBZCW.mjs} +83 -11
  41. package/dist/.setup/{elicitation-input-DPoK8F7w.mjs → elicitation-input-r9axtppm.mjs} +4 -2
  42. package/dist/.setup/{ephemeral-turn-DiCS1ijR.mjs → ephemeral-turn-oPKxs3ia.mjs} +2 -2
  43. package/dist/.setup/{event-projector-assistant-message-MV_1dj-3.mjs → event-projector-assistant-message-YCL2wspu.mjs} +2 -2
  44. package/dist/.setup/{event-projector-values-DJSz8BTk.mjs → event-projector-values-DTqZHizf.mjs} +2 -12
  45. package/dist/.setup/{inference-dispatch-CMZtjQyz.mjs → inference-dispatch-B5UKEUyC.mjs} +12 -21
  46. package/dist/.setup/{inference-proxy-DhcXOgUE.mjs → inference-proxy-DUO5E2QQ.mjs} +6 -5
  47. package/dist/.setup/{isolated-completion-D80IXfQF.mjs → isolated-completion-D5gbKm6k.mjs} +8 -8
  48. package/dist/.setup/{managed-binary-kiWRhNRE.mjs → managed-binary-C1VFoVPf.mjs} +31 -38
  49. package/dist/.setup/mcp-app-session-preparation-CdqsXwZX.mjs +223 -0
  50. package/dist/.setup/mcp-tool-metadata-j10HhfTC.mjs +43 -0
  51. package/dist/.setup/{model-catalog-DiC0Tkha.mjs → model-catalog-Dj_uvusa.mjs} +7 -7
  52. package/dist/.setup/{models-DfLmPV0k.mjs → models-Du_i5G_t.mjs} +10 -7
  53. package/dist/.setup/{native-auth-CuG53tu4.mjs → native-auth-Cjb9y7IZ.mjs} +5 -6
  54. package/dist/.setup/{native-execution-policy-BxZJy5mP.mjs → native-execution-policy-ClzpdG3D.mjs} +1 -12
  55. package/dist/.setup/native-mcp-app-DV7VbfzF.mjs +310 -0
  56. package/dist/.setup/{native-subagent-monitor-BwkQXf9e.mjs → native-subagent-monitor-CCEFO6qK.mjs} +235 -318
  57. package/dist/.setup/{native-subagent-pending-assignments-DwkCzLvD.mjs → native-subagent-pending-assignments-BDqhOdJp.mjs} +0 -4
  58. package/dist/.setup/{native-task-assignments-DMQ0g3hu.mjs → native-task-assignments-C6KVqiN1.mjs} +9 -8
  59. package/dist/.setup/{node-cli-sessions-HC4W6FLI.mjs → node-cli-sessions-B5oNDkUS.mjs} +11 -17
  60. package/dist/.setup/{node-exec-server.runtime-BgBfWQqo.mjs → node-exec-server.runtime-0xSEjKYt.mjs} +2 -2
  61. package/dist/.setup/{plan-DPdMk1Oy.mjs → plan-CUHSIOep.mjs} +67 -89
  62. package/dist/.setup/{plugin-activation-cNHRfaxU.mjs → plugin-activation-BcyBv8PG.mjs} +4 -4
  63. package/dist/.setup/{plugin-app-cache-key-BL9B5H0L.mjs → plugin-app-cache-key-BW8rd98k.mjs} +11 -15
  64. package/dist/.setup/plugin-approval-roundtrip-uAR-oQfr.mjs +109 -0
  65. package/dist/.setup/{plugin-inventory-Cky2XJUw.mjs → plugin-inventory-Bf0_piTw.mjs} +29 -51
  66. package/dist/.setup/{plugin-marketplace-discovery-D_dV9FXa.mjs → plugin-marketplace-discovery-SQPhSuic.mjs} +2 -16
  67. package/dist/.setup/plugin-metadata-cache-DWnB7VMj.mjs +84 -0
  68. package/dist/.setup/plugin-thread-config-deadline-CdRzGJt4.mjs +124 -0
  69. package/dist/.setup/{provider-D6F_7p1I.mjs → provider-BP8ZaZqn.mjs} +4 -4
  70. package/dist/.setup/provider-capabilities-Z5ZbBxqP.mjs +50 -0
  71. package/dist/.setup/{rate-limits-B7-X2TgG.mjs → rate-limits-CMPy24F5.mjs} +1 -5
  72. package/dist/.setup/{request-BZOfsSXW.mjs → request-BH3FvYUE.mjs} +189 -49
  73. package/dist/.setup/rpc-error-hmWM21RB.mjs +57 -0
  74. package/dist/.setup/{run-attempt-dYJhjZrp.mjs → run-attempt-CgvFoW7R.mjs} +553 -727
  75. package/dist/.setup/{run-attempt-lifecycle-C-6O3Exn.mjs → run-attempt-lifecycle-BuZgVbDA.mjs} +19 -3
  76. package/dist/.setup/{runtime-artifact-DDQ-HGXf.mjs → runtime-artifact-CUTOOnKw.mjs} +5 -6
  77. package/dist/.setup/{runtime-artifact-connection-D68qQn1m.mjs → runtime-artifact-connection-CADz3_BY.mjs} +5 -4
  78. package/dist/.setup/{sandbox-guard-DjCz2eOw.mjs → sandbox-guard-WqE8yPge.mjs} +3 -3
  79. package/dist/.setup/service-tier-normalization-Cei89SW6.mjs +15 -0
  80. package/dist/.setup/{session-binding-DGCYAfvD.mjs → session-binding-Ce7BqiPN.mjs} +92 -102
  81. package/dist/.setup/session-binding-meta-Lkm5Lpf4.mjs +15 -0
  82. package/dist/.setup/session-binding-record-BZB8RgcF.mjs +179 -0
  83. package/dist/.setup/session-binding-record-codec-z4ZpDn6E.mjs +216 -0
  84. package/dist/.setup/{session-binding-sidecars-jo6H8dFr.mjs → session-binding-sidecars-BrdV95Fg.mjs} +8 -2
  85. package/dist/.setup/{session-catalog-adoption-BU_pHWG7.mjs → session-catalog-adoption-CPIP4S_y.mjs} +34 -18
  86. package/dist/.setup/{session-catalog-archive-spHfihri.mjs → session-catalog-archive-DcgwvSbF.mjs} +24 -29
  87. package/dist/.setup/{session-catalog-events-BMCFMZw-.mjs → session-catalog-events-KIXOoSnQ.mjs} +5 -5
  88. package/dist/.setup/{session-catalog-index-DwJjnF5k.mjs → session-catalog-index-DPICGlxr.mjs} +361 -72
  89. package/dist/.setup/{session-catalog-index-order-BcQpHks3.mjs → session-catalog-index-order-nhyO0wdW.mjs} +1 -1
  90. package/dist/.setup/{session-catalog-limits-DDxOsQeC.mjs → session-catalog-limits-DEU36Qlo.mjs} +1 -1
  91. package/dist/.setup/{session-catalog-index-state-TeO7EyO-.mjs → session-catalog-list-request-tXephOB4.mjs} +180 -6
  92. package/dist/.setup/{session-catalog-native-projection-CuaFZuQE.mjs → session-catalog-native-projection-CTBd4EUm.mjs} +7 -6
  93. package/dist/.setup/{session-catalog-node-adoption-DgXvSGu0.mjs → session-catalog-node-adoption-7-WEQTB1.mjs} +12 -2
  94. package/dist/.setup/{session-catalog-node-continue-DjKXHBbi.mjs → session-catalog-node-continue-DLWBwAAO.mjs} +11 -15
  95. package/dist/.setup/{session-catalog-node-lookup-CtAXI5W5.mjs → session-catalog-node-lookup-Uufckwcm.mjs} +2 -2
  96. package/dist/.setup/{session-catalog-parsing-CPGaPYr-.mjs → session-catalog-parsing-B-qWJh2x.mjs} +70 -28
  97. package/dist/.setup/{session-catalog-projection-CGfzfP93.mjs → session-catalog-projection-CE0_Hffi.mjs} +6 -122
  98. package/dist/.setup/{session-catalog-provenance-DoAvktcj.mjs → session-catalog-provenance-CmsOE5mh.mjs} +6 -1
  99. package/dist/.setup/{session-cli-DlmBHYIe.mjs → session-cli-kH4vuGod.mjs} +1 -2
  100. package/dist/.setup/{session-history-D83lJWHG.mjs → session-history-BogBHKLk.mjs} +1 -1
  101. package/dist/.setup/{session-history-import-WhX-X33a.mjs → session-history-import-NWKPa4ZO.mjs} +4 -4
  102. package/dist/.setup/{session-history-read-Ov3StuL4.mjs → session-history-read-CNN8zwbD.mjs} +8 -19
  103. package/dist/.setup/{session-history.worker-MnPKncqP.mjs → session-history.worker-Cq_4DYgN.mjs} +3 -3
  104. package/dist/.setup/{session-initialization-6aveB9qb.mjs → session-initialization-D6dtFQkE.mjs} +2 -2
  105. package/dist/.setup/{session-permission-policy-Ci_fVX6y.mjs → session-permission-policy-BxIUJ0Zd.mjs} +8 -37
  106. package/dist/.setup/{session-retirement-LlYWBKTJ.mjs → session-retirement-aC60o6P3.mjs} +14 -15
  107. package/dist/.setup/{settled-turn-context-D4yj4rxf.mjs → settled-turn-context-BZsMjkIO.mjs} +13 -6
  108. package/dist/.setup/{settled-turn-finalizer-DW9W3gza.mjs → settled-turn-finalizer-CDxCejjC.mjs} +8 -8
  109. package/dist/.setup/{shared-client-CJCTeFpQ.mjs → shared-client-DJJ3ljH2.mjs} +291 -272
  110. package/dist/.setup/{provider-capabilities-DG5qbsUZ.mjs → shell-dynamic-tools-Do9lIAT1.mjs} +16 -55
  111. package/dist/.setup/{side-question-BLeGj7TQ.mjs → side-question-B7T0_GEC.mjs} +99 -91
  112. package/dist/.setup/{source-CJis_1EF.mjs → source-DH70LqN0.mjs} +24 -40
  113. package/dist/.setup/{thread-lifecycle-_bAbjedG.mjs → thread-lifecycle-DkcoX9q-.mjs} +262 -305
  114. package/dist/.setup/{thread-ownership-B6pPt21M.mjs → thread-ownership-0aRHD9iK.mjs} +10 -8
  115. package/dist/.setup/{thread-policy-gNPzzpVp.mjs → thread-policy-CXZV97TS.mjs} +22 -21
  116. package/dist/.setup/{thread-requests-OWGOiDaV.mjs → thread-requests-COrRJcZb.mjs} +107 -98
  117. package/dist/.setup/{thread-resume-GOry0AYh.mjs → thread-resume-rx7J68Rx.mjs} +10 -18
  118. package/dist/.setup/{transcript-history-projection-DRSifI-1.mjs → transcript-history-projection-B9a7HwUV.mjs} +11 -16
  119. package/dist/.setup/{transcript-mirror-kxmCYsuF.mjs → transcript-mirror-BfLRARNL.mjs} +64 -67
  120. package/dist/.setup/{transport-stdio-Bdegpn2V.mjs → transport-stdio-a0HDa2Mj.mjs} +27 -8
  121. package/dist/.setup/{transport-websocket-BTBE-LD9.mjs → transport-websocket-zqJ0Cmtn.mjs} +3 -8
  122. package/dist/.setup/{attempt-client-cleanup-B-S7ngS_.mjs → turn-router-CX1-EoCp.mjs} +75 -170
  123. package/dist/.setup/{upstream-session-fork-gkdRj2yH.mjs → upstream-session-fork-LYlaQnbt.mjs} +35 -46
  124. package/dist/.setup/{usage-CApUvLOV.mjs → usage-Dmx7B0W2.mjs} +4 -4
  125. package/dist/.setup/{usage-limit-error-wSMQkbpV.mjs → usage-limit-error-M8jVnITZ.mjs} +4 -4
  126. package/dist/.setup/{web-search-provider.runtime-UKgeiBUG.mjs → web-search-provider.runtime-CsVmqbFm.mjs} +4 -20
  127. package/dist/.setup/websocket-data-XlRvt8Ys.mjs +6 -0
  128. package/dist/.setup/workspace-write-sandbox-probe-DmUHLrrl.mjs +118 -0
  129. package/dist/api.js +34 -54
  130. package/dist/catalog-page.worker.js +1 -1
  131. package/dist/cli-metadata.js +1 -1
  132. package/dist/doctor-contract-api.js +15 -27
  133. package/dist/harness.js +37 -22
  134. package/dist/index.js +2880 -276
  135. package/dist/media-understanding-provider.js +2 -2
  136. package/dist/migration-provider-api.js +1 -1
  137. package/dist/native-session-binding-api.js +2 -0
  138. package/dist/provider-discovery.js +1 -1
  139. package/dist/session-history-worker-runtime.js +33 -4
  140. package/dist/session-history.worker.js +1 -1
  141. package/openclaw.plugin.json +3 -3
  142. package/package.json +6 -6
  143. package/dist/.setup/config-utils-D0CXecki.mjs +0 -57
  144. package/dist/.setup/incognito-session-DWYapfwf.mjs +0 -2
  145. package/dist/.setup/managed-thread-store-BMqgThVL.mjs +0 -100
  146. package/dist/.setup/rpc-error-BlD2vuzn.mjs +0 -31
  147. package/dist/.setup/session-binding-meta-B7aEMU7g.mjs +0 -6
  148. package/dist/.setup/session-binding-record-Oe9L-CNY.mjs +0 -375
  149. package/dist/.setup/session-catalog-BFafIiF6.mjs +0 -2599
  150. package/dist/.setup/session-catalog-list-request-CvtxrYSe.mjs +0 -170
  151. package/dist/.setup/shared-client-lifecycle-7xgtlo15.mjs +0 -153
package/dist/index.js CHANGED
@@ -1,52 +1,76 @@
1
1
  import { registerCodexCliMetadata } from "./cli-metadata.js";
2
- import { j as CODEX_INTERACTIVE_THREAD_SOURCE_KINDS } from "./.setup/session-catalog-parsing-CPGaPYr-.mjs";
3
- import { i as isJsonObject } from "./.setup/protocol-CANUwXJ3.mjs";
4
- import { f as readCurrentCodexAppServerBinding, h as readCurrentNativePendingAssignments, m as readCurrentCodexNativeSubagentSubmissions, n as assertCodexBindingMayBeReplaced, p as readCurrentCodexAppServerBindings, v as sessionBindingIdentity } from "./.setup/session-binding-record-Oe9L-CNY.mjs";
5
- import { n as defineCodexBuildState } from "./.setup/build-state-DIQ5O_-S.mjs";
2
+ import { A as unwrapNodeInvokePayload, C as readGatewayParams, E as requireOnlyKeys, S as readControlCursor, _ as normalizeLimit, a as CODEX_LOCAL_SESSION_HOST_ID, b as parseTranscriptPage, f as catalogError, g as isInteractiveThreadSource, h as filterCatalogPageByTitle, i as CODEX_CATALOG_TRANSCRIPT_READ_COMMAND, j as CODEX_INTERACTIVE_THREAD_SOURCE_KINDS, l as MAX_TRANSCRIPT_PAGE_BYTES, n as CODEX_APP_SERVER_THREADS_LIST_COMMAND, o as CatalogParamsError, r as CODEX_APP_SERVER_THREAD_TURNS_LIST_COMMAND, s as MAX_CURSOR_LENGTH, t as CODEX_APP_SERVER_THREADS_CAPABILITY, u as NODE_INVOKE_TIMEOUT_MS, v as parseCatalogPage, w as readPageParams, x as readBoundedOptionalString, y as parseJsonParams } from "./.setup/session-catalog-parsing-B-qWJh2x.mjs";
3
+ import { i as isJsonObject, n as assertCodexThreadForkParams } from "./.setup/protocol-CANUwXJ3.mjs";
4
+ import { d as readCurrentCodexNativeSubagentSubmissions, f as readCurrentNativePendingAssignments, l as readCurrentCodexAppServerBinding, m as sessionBindingIdentity, n as assertCodexBindingMayBeReplaced, u as readCurrentCodexAppServerBindings } from "./.setup/session-binding-record-BZB8RgcF.mjs";
5
+ import { n as defineCodexBuildState } from "./.setup/build-state-CIi3Ckqu.mjs";
6
6
  import { createCodexAppServerAgentHarness, createCodexAppServerNativeCompaction } from "./harness.js";
7
7
  import { buildCodexMediaUnderstandingProvider } from "./media-understanding-provider.js";
8
8
  import codexProviderDiscovery from "./provider-discovery.js";
9
- import { n as createCodexAuthProfileSelection } from "./.setup/auth-profile-selection-DFu9e167.mjs";
10
- import { t as assertCodexAppServerConnectionSecurity } from "./.setup/config-security-CE-FcGw9.mjs";
11
- import { d as readCodexPluginConfig } from "./.setup/config-parsing-b088LyhT.mjs";
12
- import { r as createCodexAppServerConfig, t as codexAppServerStartOptionsKey } from "./.setup/config-options-CzyWLTJt.mjs";
13
- import { o as setManagedCodexPluginRoot } from "./.setup/managed-binary-kiWRhNRE.mjs";
14
- import { l as createCodexDesktopGenerationService, s as resolveCodexAppServerFallbackApiKeyCacheKey } from "./.setup/auth-cache-key-Dnps4W4_.mjs";
15
- import { n as CODEX_MANAGED_THREAD_NAMESPACE, r as createCodexManagedThreadStore, t as CODEX_MANAGED_THREAD_MAX_ENTRIES } from "./.setup/managed-thread-store-BMqgThVL.mjs";
16
- import { n as CODEX_APP_SERVER_BINDING_NAMESPACE, t as CODEX_APP_SERVER_BINDING_MAX_ENTRIES } from "./.setup/session-binding-meta-B7aEMU7g.mjs";
17
- import { f as retireSharedCodexAppServerClientsBeforeDesktopGeneration } from "./.setup/shared-client-lifecycle-7xgtlo15.mjs";
18
- import { s as createCodexAppServerProcessReaperService } from "./.setup/transport-stdio-Bdegpn2V.mjs";
9
+ import { n as createCodexAuthProfileSelection } from "./.setup/auth-profile-selection-hr8ocLtz.mjs";
10
+ import { t as assertCodexAppServerConnectionSecurity } from "./.setup/config-security-KAPScztc.mjs";
11
+ import { d as readCodexPluginConfig } from "./.setup/config-parsing-BQq-CHTF.mjs";
12
+ import { n as resolveCodexAppServerLocalHomeDir, r as resolveCodexAppServerUserHomeDir, t as resolveCodexAppServerHomeDir } from "./.setup/auth-start-options-BPIPeEX8.mjs";
13
+ import { r as createCodexAppServerConfig, t as codexAppServerStartOptionsKey } from "./.setup/config-options-HG_Rr3W_.mjs";
14
+ import { o as setManagedCodexPluginRoot } from "./.setup/managed-binary-C1VFoVPf.mjs";
15
+ import { O as createCodexDesktopGenerationService, T as retireSharedCodexAppServerClientsBeforeDesktopGeneration, m as hasActiveSharedCodexAppServerWork, p as getSharedCodexAppServerClientState, s as resolveCodexAppServerFallbackApiKeyCacheKey } from "./.setup/auth-cache-key-CEd9QlIs.mjs";
16
+ import { i as CODEX_APP_SERVER_BINDING_NAMESPACE, r as CODEX_APP_SERVER_BINDING_MAX_ENTRIES } from "./.setup/session-binding-meta-Lkm5Lpf4.mjs";
17
+ import { s as createCodexAppServerProcessReaperService } from "./.setup/transport-stdio-a0HDa2Mj.mjs";
19
18
  import { n as codexNativeProfileRecoveryService } from "./.setup/auth-profile-health-oHizqgye.mjs";
20
19
  import { n as withCodexConversationThreadActivity } from "./.setup/thread-ownership-queue-Dp24d7-F.mjs";
21
- import { c as canMutateCodexHost, n as filterCodexMarketplacePlugins, o as CODEX_NATIVE_EXECUTION_AUTH_ERROR, t as discoverCodexMarketplacePlugins } from "./.setup/plugin-marketplace-discovery-D_dV9FXa.mjs";
22
- import { o as formatCodexDisplayText } from "./.setup/command-formatters-R3ckE3Co.mjs";
23
- import { a as readCodexConversationBindingDataRecord, i as readCodexConversationBindingData, o as resolveCodexDefaultWorkspaceDir } from "./.setup/conversation-binding-data-C746z5Pn.mjs";
24
- import { t as isIncognitoSessionKey } from "./.setup/incognito-session-DWYapfwf.mjs";
25
- import { t as buildCodexMigrationProvider } from "./.setup/provider-D6F_7p1I.mjs";
26
- import { t as CODEX_CONTROL_METHODS } from "./.setup/capabilities-B3WEZl4e.mjs";
20
+ import { a as canMutateCodexHost, r as CODEX_NATIVE_EXECUTION_AUTH_ERROR } from "./.setup/command-authorization-AikPDtcc.mjs";
21
+ import { o as formatCodexDisplayText } from "./.setup/command-formatters-DV3DHhdr.mjs";
22
+ import { a as readCodexConversationBindingDataRecord, i as readCodexConversationBindingData, o as resolveCodexDefaultWorkspaceDir } from "./.setup/conversation-binding-data-DJ4ix-W5.mjs";
23
+ import { t as buildCodexMigrationProvider } from "./.setup/provider-BP8ZaZqn.mjs";
24
+ import { r as CodexAppServerRpcError, s as isCodexThreadReadMissingError } from "./.setup/rpc-error-hmWM21RB.mjs";
25
+ import { t as CODEX_CONTROL_METHODS } from "./.setup/capabilities-kQntafj_.mjs";
26
+ import { n as filterCodexMarketplacePlugins, t as discoverCodexMarketplacePlugins } from "./.setup/plugin-marketplace-discovery-SQPhSuic.mjs";
27
27
  import { t as assertCodexArchiveDescendantsUnowned } from "./.setup/thread-archive-guard-C9frICzX.mjs";
28
- import { a as createCodexCliSessionNodeInvokePolicies, c as resolveCodexCliSessionForBindingOnNode, i as createCodexCliSessionNodeHostCommands, l as resumeCodexCliSessionOnNode, s as listCodexCliSessionsOnNode } from "./.setup/node-cli-sessions-HC4W6FLI.mjs";
29
- import { t as CODEX_CATALOG_MAX_ROWS } from "./.setup/session-catalog-limits-DDxOsQeC.mjs";
30
- import { t as CODEX_CATALOG_STATE_NAMESPACE } from "./.setup/session-catalog-index-state-TeO7EyO-.mjs";
31
- import { i as createCodexSessionCatalogNodeHostCommands, n as createCodexSessionCatalogNodeInvokePolicies, r as createCodexSessionCatalogControl, t as codexSessionCatalogRuntime } from "./.setup/session-catalog-BFafIiF6.mjs";
32
- import { i as requestCodexAppServerJson } from "./.setup/request-BZOfsSXW.mjs";
28
+ import { a as createCodexCliSessionNodeInvokePolicies, c as resolveCodexCliSessionForBindingOnNode, i as createCodexCliSessionNodeHostCommands, l as resumeCodexCliSessionOnNode, s as listCodexCliSessionsOnNode } from "./.setup/node-cli-sessions-B5oNDkUS.mjs";
29
+ import { n as codexCatalogHomeIdFromCanonicalPath } from "./.setup/session-catalog-home-id-vlih0B_g.mjs";
30
+ import { t as CODEX_CATALOG_MAX_ROWS } from "./.setup/session-catalog-limits-DEU36Qlo.mjs";
31
+ import { a as CodexCatalogLoadingError, n as currentCodexCatalogListRequest, o as CODEX_CATALOG_STATE_NAMESPACE, r as withCodexCatalogListRequest, t as CodexCatalogListRequest } from "./.setup/session-catalog-list-request-tXephOB4.mjs";
32
+ import { i as withTimeout$1 } from "./.setup/timeout-CXOfNoaX.mjs";
33
+ import { t as lookupNodeCodexCatalogRecord } from "./.setup/session-catalog-node-lookup-Uufckwcm.mjs";
34
+ import { r as projectCodexUserItemText } from "./.setup/transcript-history-projection-B9a7HwUV.mjs";
35
+ import { r as codexUpstreamContinueResult } from "./.setup/session-upstream-marker-D15C9NHp.mjs";
36
+ import { t as buildCodexAppServerConnectionFingerprint } from "./.setup/plugin-app-cache-key-BW8rd98k.mjs";
37
+ import { n as readCodexSessionMeta } from "./.setup/session-catalog-provenance-CmsOE5mh.mjs";
38
+ import { t as codexCatalogResidentHomeKey } from "./.setup/session-catalog-events-KIXOoSnQ.mjs";
39
+ import { a as setCodexCatalogConnectionHomeResolver } from "./.setup/binding-connection-C-08ez1w.mjs";
40
+ import { n as findCodexAppServerSpawnError } from "./.setup/spawn-error-CL3n6MAa.mjs";
41
+ import { r as requestCodexAppServerJson } from "./.setup/request-BH3FvYUE.mjs";
33
42
  import { t as createCodexWebSearchProviderBase } from "./.setup/web-search-provider.shared-BrZmlqyR.mjs";
34
43
  import { normalizePluginsConfig, resolveEffectiveEnableState, resolveLivePluginConfigObject, resolvePluginConfigObject } from "openclaw/plugin-sdk/plugin-config-runtime";
35
44
  import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
36
45
  import { asBoolean, asOptionalRecord, asSafeIntegerInRange, isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
46
+ import { createHash, randomUUID } from "node:crypto";
37
47
  import { isDeepStrictEqual } from "node:util";
38
- import { resolveDefaultAgentDir } from "openclaw/plugin-sdk/agent-harness-registration";
48
+ import { embeddedAgentLog, resolveDefaultAgentDir } from "openclaw/plugin-sdk/agent-harness-registration";
49
+ import { listAgentIds, resolveAgentDir, resolveDefaultAgentId, resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
50
+ import { z } from "zod";
51
+ import path from "node:path";
52
+ import fs from "node:fs/promises";
39
53
  import { coerceErrorMessage, formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
40
- import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
54
+ import { canonicalPathFromExistingAncestor } from "openclaw/plugin-sdk/file-access-runtime";
41
55
  import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
56
+ import { scheduler } from "node:timers/promises";
57
+ import { isIncognitoSessionKey } from "openclaw/plugin-sdk/session-key-runtime";
42
58
  import { jsonResult } from "openclaw/plugin-sdk/tool-results";
43
59
  import { Type } from "typebox";
44
60
  import { readStringParam } from "openclaw/plugin-sdk/param-readers";
61
+ import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
62
+ import { AsyncLocalStorage } from "node:async_hooks";
63
+ import { isMainThread, threadId } from "node:worker_threads";
64
+ import { areDiagnosticsEnabledForProcess, createSubsystemLogger } from "openclaw/plugin-sdk/diagnostic-runtime";
65
+ import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
66
+ import { publishSessionCatalogHost, sessionCatalogPaging } from "openclaw/plugin-sdk/session-catalog-paging";
67
+ import { raceWithTimeout } from "openclaw/plugin-sdk/time-runtime";
68
+ import { decodeNodePtyResumeParams, decodeNodePtyStartParams, resolveNodeHostExecutable, runNodePtyCommand } from "openclaw/plugin-sdk/node-host";
45
69
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
46
70
  //#region extensions/codex/src/account-usage.ts
47
71
  function registerCodexAccountUsage(api) {
48
72
  api.registerGatewayMethod("codex.accountUsage", async (options) => {
49
- const { handleCodexAccountUsage } = await import("./.setup/account-usage-runtime-G348lY1q.mjs");
73
+ const { handleCodexAccountUsage } = await import("./.setup/account-usage-runtime-C4GFoef_.mjs");
50
74
  await handleCodexAccountUsage(options);
51
75
  }, { scope: "operator.admin" });
52
76
  }
@@ -58,7 +82,7 @@ function createCodexAppServerConnectionHealthService(options) {
58
82
  let abortController;
59
83
  let monitor;
60
84
  const run = async (ctx, signal) => {
61
- const { resolveCodexAppServerRuntimeOptions } = await import("./.setup/config-runtime-C0NbLms1.mjs").then((n) => n.t);
85
+ const { resolveCodexAppServerRuntimeOptions } = await import("./.setup/config-runtime-cUYrqu_a.mjs").then((n) => n.t);
62
86
  let consecutiveFailures = 0;
63
87
  while (!signal.aborted) {
64
88
  let pluginConfig;
@@ -74,8 +98,9 @@ function createCodexAppServerConnectionHealthService(options) {
74
98
  return;
75
99
  }
76
100
  if (runtime.start.transport !== "websocket") return;
77
- const { getLeasedSharedCodexAppServerClient, releaseLeasedSharedCodexAppServerClient } = await import("./.setup/shared-client-CJCTeFpQ.mjs").then((n) => n.v);
78
- const { isUnsupportedCodexAppServerVersionError } = await import("./.setup/client-qyUBJlGZ.mjs").then((n) => n.n);
101
+ const { getLeasedSharedCodexAppServerClient, releaseLeasedSharedCodexAppServerClient } = await import("./.setup/shared-client-DJJ3ljH2.mjs").then((n) => n.v);
102
+ const { sleepWithAbort } = await import("openclaw/plugin-sdk/runtime-env");
103
+ const { isUnsupportedCodexAppServerVersionError } = await import("./.setup/client-CBzEVDyb.mjs").then((n) => n.n);
79
104
  if (signal.aborted) return;
80
105
  let leasedClient;
81
106
  try {
@@ -105,7 +130,7 @@ function createCodexAppServerConnectionHealthService(options) {
105
130
  }
106
131
  if (!signal.aborted) {
107
132
  const exponentialDelayMs = Math.min(INITIAL_RECONNECT_DELAY_MS * 2 ** Math.max(0, consecutiveFailures - 1), MAX_RECONNECT_DELAY_MS);
108
- await waitForReconnect(Math.min(Math.round(exponentialDelayMs * (.75 + Math.random() * .5)), MAX_RECONNECT_DELAY_MS), signal);
133
+ await sleepWithAbort(Math.min(Math.round(exponentialDelayMs * (.75 + Math.random() * .5)), MAX_RECONNECT_DELAY_MS), signal, { ref: false }).catch(() => void 0);
109
134
  }
110
135
  }
111
136
  };
@@ -142,7 +167,7 @@ function isPermanentCodexAppServerConnectionFailure(error, isUnsupportedCodexApp
142
167
  }
143
168
  function waitForCodexAppServerClose(client, signal) {
144
169
  return new Promise((resolve) => {
145
- if (signal.aborted) {
170
+ if (signal.aborted || client.getCloseError()) {
146
171
  resolve();
147
172
  return;
148
173
  }
@@ -155,46 +180,113 @@ function waitForCodexAppServerClose(client, signal) {
155
180
  signal.addEventListener("abort", finish, { once: true });
156
181
  });
157
182
  }
158
- function waitForReconnect(delayMs, signal) {
159
- return new Promise((resolve) => {
160
- if (signal.aborted) {
161
- resolve();
162
- return;
183
+ //#endregion
184
+ //#region extensions/codex/src/app-server/managed-thread-store.ts
185
+ const CODEX_MANAGED_THREAD_NAMESPACE = "app-server-managed-threads";
186
+ const CODEX_MANAGED_THREAD_MAX_ENTRIES = 2e4;
187
+ const managedThreadSchema = z.object({
188
+ version: z.literal(1),
189
+ kind: z.literal("managed-thread"),
190
+ sourceHomeId: z.string().min(1),
191
+ threadId: z.string().min(1),
192
+ rolloutPath: z.string().min(1).optional()
193
+ });
194
+ function managedThreadStoreKey(sourceHomeId, threadId) {
195
+ return `sha256:${createHash("sha256").update("openclaw:codex-managed-thread:v1\0").update(sourceHomeId).update("\0").update(threadId).digest("hex")}`;
196
+ }
197
+ /** Durable ownership index for Codex threads created by OpenClaw. */
198
+ function createCodexManagedThreadStore(state) {
199
+ const byHome = /* @__PURE__ */ new Map();
200
+ const memberships = /* @__PURE__ */ new Map();
201
+ let hydration;
202
+ const remember = ({ sourceHomeId, threadId }) => {
203
+ const key = managedThreadStoreKey(sourceHomeId, threadId);
204
+ if (memberships.has(key)) return key;
205
+ memberships.set(key, {
206
+ sourceHomeId,
207
+ threadId
208
+ });
209
+ let ids = byHome.get(sourceHomeId);
210
+ if (!ids) {
211
+ ids = /* @__PURE__ */ new Set();
212
+ byHome.set(sourceHomeId, ids);
163
213
  }
164
- const finish = () => {
165
- clearTimeout(timer);
166
- signal.removeEventListener("abort", finish);
167
- resolve();
168
- };
169
- const timer = setTimeout(finish, delayMs);
170
- timer.unref();
171
- signal.addEventListener("abort", finish, { once: true });
172
- });
214
+ ids.add(threadId);
215
+ if (memberships.size > 2e4) {
216
+ const oldest = memberships.entries().next().value;
217
+ if (oldest) {
218
+ memberships.delete(oldest[0]);
219
+ const oldestHome = byHome.get(oldest[1].sourceHomeId);
220
+ oldestHome?.delete(oldest[1].threadId);
221
+ if (oldestHome?.size === 0) byHome.delete(oldest[1].sourceHomeId);
222
+ }
223
+ }
224
+ return key;
225
+ };
226
+ const snapshot = async () => {
227
+ hydration ??= state.entries().then((entries) => {
228
+ const marked = new Map(memberships);
229
+ memberships.clear();
230
+ byHome.clear();
231
+ for (const entry of entries.toSorted((a, b) => a.createdAt - b.createdAt)) {
232
+ const parsed = managedThreadSchema.safeParse(entry.value);
233
+ if (parsed.success) marked.delete(remember(parsed.data));
234
+ }
235
+ for (const membership of marked.values()) remember(membership);
236
+ }).catch((error) => {
237
+ hydration = void 0;
238
+ throw error;
239
+ });
240
+ await hydration;
241
+ return byHome;
242
+ };
243
+ return {
244
+ async has(sourceHomeId, threadId) {
245
+ return (await snapshot()).get(sourceHomeId)?.has(threadId) ?? false;
246
+ },
247
+ async mark(params) {
248
+ try {
249
+ const value = managedThreadSchema.parse({
250
+ version: 1,
251
+ kind: "managed-thread",
252
+ sourceHomeId: params.sourceHomeId.trim(),
253
+ threadId: params.threadId.trim(),
254
+ ...params.rolloutPath?.trim() ? { rolloutPath: params.rolloutPath.trim() } : {}
255
+ });
256
+ await state.registerIfAbsent(managedThreadStoreKey(value.sourceHomeId, value.threadId), value);
257
+ remember(value);
258
+ return true;
259
+ } catch (error) {
260
+ embeddedAgentLog.warn("failed to record Codex managed thread ownership", { error });
261
+ return false;
262
+ }
263
+ },
264
+ snapshot
265
+ };
173
266
  }
174
267
  //#endregion
175
268
  //#region extensions/codex/src/app-server/session-binding-store.ts
269
+ /** Binding reads with lazy mutation, lease, and auth machinery. */
176
270
  /** Keeps lifecycle/auth loading behind mutations while sharing the canonical read codec. */
177
271
  function createLazyCodexAppServerBindingStore(state, managedThreadState) {
178
272
  let resolved;
179
- const store = () => resolved ??= import("./.setup/session-binding-DGCYAfvD.mjs").then((n) => n.s).then(({ createCodexAppServerBindingStore }) => createCodexAppServerBindingStore(state));
273
+ const store = () => resolved ??= import("./.setup/session-binding-Ce7BqiPN.mjs").then((n) => n.i).then(({ createCodexAppServerBindingStore }) => createCodexAppServerBindingStore(state));
180
274
  const managedThreads = managedThreadState ? createCodexManagedThreadStore(managedThreadState) : void 0;
181
275
  return {
182
276
  ...managedThreads ? { managedThreads } : {},
183
277
  read: (identity) => readCurrentCodexAppServerBinding(state, identity),
184
- get readMany() {
185
- return state.lookupMany ? (identities) => readCurrentCodexAppServerBindings(state, identities) : void 0;
186
- },
278
+ readMany: (identities) => readCurrentCodexAppServerBindings(state.asyncReads, identities),
187
279
  readNativeSubagentAssignments: (identity, owner) => readCurrentNativePendingAssignments(state, identity, owner),
188
280
  readNativeSubagentSubmissions: (identity, owner) => readCurrentCodexNativeSubagentSubmissions(state, identity, owner),
189
281
  hasOtherThreadOwner: async (threadId, currentIdentity) => (await store()).hasOtherThreadOwner(threadId, currentIdentity),
190
- mutate: async (identity, mutation, assertCurrent) => (await store()).mutate(identity, mutation, assertCurrent),
282
+ mutate: async (identity, mutation, assertCurrent, authority) => (await store()).mutate(identity, mutation, assertCurrent, authority),
191
283
  prepareSessionGenerationReclaim: async (identity) => (await store()).prepareSessionGenerationReclaim(identity),
192
- adoptSessionGeneration: async (identity, previousSessionId, assertCurrent) => (await store()).adoptSessionGeneration(identity, previousSessionId, assertCurrent),
284
+ adoptSessionGeneration: async (identity, previousSessionId, assertCurrent, authority) => (await store()).adoptSessionGeneration(identity, previousSessionId, assertCurrent, authority),
193
285
  resetSessionGeneration: async (identity) => (await store()).resetSessionGeneration(identity),
194
286
  retireSessionGeneration: async (identity) => (await store()).retireSessionGeneration(identity),
195
287
  withSessionDeletion: async (identity, assertCurrent, run) => (await store()).withSessionDeletion(identity, assertCurrent, run),
196
288
  withThreadArchiveFence: async (run) => (await store()).withThreadArchiveFence(run),
197
- withLease: async (identity, run) => (await store()).withLease(identity, run)
289
+ withLease: async (identity, run, options) => (await store()).withLease(identity, run, options)
198
290
  };
199
291
  }
200
292
  //#endregion
@@ -226,7 +318,7 @@ function createCodexCommand(options) {
226
318
  ...ctx,
227
319
  gatewayClientScopes: ctx.gatewayClientScopes?.slice()
228
320
  };
229
- const { handleCodexCommand } = await import("./.setup/command-dispatch-Btrs1D6f.mjs");
321
+ const { handleCodexCommand } = await import("./.setup/command-dispatch-BE_RdMou.mjs");
230
322
  return handleCodexCommand(commandContext, options);
231
323
  }
232
324
  };
@@ -258,7 +350,7 @@ async function handleCodexConversationInboundClaim(event, ctx, options) {
258
350
  return {
259
351
  handled: true,
260
352
  reply: (await getNodeConversationState().queue.enqueue(`${data.nodeId}:${data.sessionId}`, async () => {
261
- const { resolveCodexNativeSandboxBlock } = await import("./.setup/sandbox-guard-DjCz2eOw.mjs").then((n) => n.r);
353
+ const { resolveCodexNativeSandboxBlock } = await import("./.setup/sandbox-guard-WqE8yPge.mjs").then((n) => n.r);
262
354
  const blocked = resolveCodexNativeSandboxBlock({
263
355
  config: options.config,
264
356
  sessionKey,
@@ -295,7 +387,7 @@ async function handleCodexConversationInboundClaim(event, ctx, options) {
295
387
  return {
296
388
  handled: true,
297
389
  reply: (await withCodexConversationThreadActivity(data.bindingId, async () => {
298
- const { resolveCodexNativeExecutionBlock } = await import("./.setup/sandbox-guard-DjCz2eOw.mjs").then((n) => n.r);
390
+ const { resolveCodexNativeExecutionBlock } = await import("./.setup/sandbox-guard-WqE8yPge.mjs").then((n) => n.r);
299
391
  const nativeExecutionBlock = resolveCodexNativeExecutionBlock({
300
392
  config: options.config,
301
393
  sessionKey,
@@ -304,7 +396,7 @@ async function handleCodexConversationInboundClaim(event, ctx, options) {
304
396
  });
305
397
  if (nativeExecutionBlock) return { reply: { text: nativeExecutionBlock } };
306
398
  const { getSessionBindingService } = await import("openclaw/plugin-sdk/conversation-binding-runtime");
307
- const { runBoundTurnWithMissingThreadRecovery } = await import("./.setup/conversation-binding-74LaGGH-.mjs");
399
+ const { runBoundTurnWithMissingThreadRecovery } = await import("./.setup/conversation-binding-CgSSD1Qz.mjs");
308
400
  const current = options.bindingStore.read(identity);
309
401
  if (!isCurrentPublicBinding(publicBinding, getSessionBindingService()) || expected && (!current || current.threadId !== expected.threadId || current.conversationStartId !== expected.conversationStartId) || !expected && current && data.start?.id && current.conversationStartId !== data.start.id) return { reply: { text: "This Codex conversation was detached or changed before its message could run." } };
310
402
  return await runBoundTurnWithMissingThreadRecovery({
@@ -338,7 +430,7 @@ async function handleCodexConversationBindingResolved(event, options) {
338
430
  const binding = options.bindingStore.read(identity);
339
431
  assertCodexBindingMayBeReplaced(binding, "clearing a denied conversation binding");
340
432
  if (binding && (!data.start?.id || binding.conversationStartId === data.start.id)) await withCodexConversationThreadActivity(identity.bindingId, async () => {
341
- const { retireCodexConversationThreadBinding } = await import("./.setup/thread-ownership-B6pPt21M.mjs").then((n) => n.o);
433
+ const { retireCodexConversationThreadBinding } = await import("./.setup/thread-ownership-0aRHD9iK.mjs").then((n) => n.o);
342
434
  return retireCodexConversationThreadBinding({
343
435
  bindingStore: options.bindingStore,
344
436
  identity,
@@ -373,7 +465,7 @@ function createCodexPluginsTool(options) {
373
465
  const query = typeof params.query === "string" ? params.query : "";
374
466
  const marketplace = typeof params.marketplace === "string" ? params.marketplace.trim() : void 0;
375
467
  const limit = typeof params.limit === "number" && Number.isInteger(params.limit) ? Math.max(1, Math.min(params.limit, 20)) : 12;
376
- const { codexBindingConnectionSelection, resolveCodexBindingAppServerConnection } = await import("./.setup/binding-connection-DTtN1KrX.mjs").then((n) => n.n);
468
+ const { codexBindingConnectionSelection, resolveCodexBindingAppServerConnection } = await import("./.setup/binding-connection-C-08ez1w.mjs").then((n) => n.n);
377
469
  const pluginConfig = options.getPluginConfig();
378
470
  const config = runtimeConfig();
379
471
  const identity = options.context.sessionId ? sessionBindingIdentity({
@@ -390,7 +482,7 @@ function createCodexPluginsTool(options) {
390
482
  if (runtimeConfig() !== config || !isDeepStrictEqual(options.getPluginConfig(), pluginConfig) || !isDeepStrictEqual(codexBindingConnectionSelection(readBinding()), selection)) throw new Error("Codex plugin discovery ownership changed; retry the request.");
391
483
  };
392
484
  const workspaceDir = binding?.cwd?.trim() || options.context.workspaceDir?.trim() || resolveCodexDefaultWorkspaceDir(pluginConfig);
393
- const request = options.request ?? (await import("./.setup/command-rpc-skzRq4wD.mjs").then((n) => n.n)).codexControlRequest;
485
+ const request = options.request ?? (await import("./.setup/command-rpc-B6xsq2dB.mjs").then((n) => n.n)).codexControlRequest;
394
486
  const connection = await resolveCodexBindingAppServerConnection({
395
487
  binding,
396
488
  pluginConfig,
@@ -565,15 +657,16 @@ function createCodexThreadsTool(options) {
565
657
  const admissionPlugin = readCodexPluginConfig(admissionConfig);
566
658
  const supervision = admissionPlugin.supervision;
567
659
  const mayReadRawTranscripts = supervision?.enabled !== true || supervision.allowRawTranscripts === true;
660
+ const threadResult = (response) => jsonResult(mayReadRawTranscripts ? response : redactNativeThreadResponse(response));
568
661
  if ((action === "fork" || action === "rename" || action === "archive" || action === "unarchive") && supervision?.enabled === true && supervision.allowWriteControls !== true) throw new Error("Codex native thread mutations are disabled for this codex plugin supervision config.");
569
662
  const run = async (archiveAdmission) => {
570
- const request = options.request ?? (await import("./.setup/command-rpc-skzRq4wD.mjs").then((n) => n.n)).codexControlRequest;
663
+ const request = options.request ?? (await import("./.setup/command-rpc-B6xsq2dB.mjs").then((n) => n.n)).codexControlRequest;
571
664
  const { isModelSelectionLocked, ModelSelectionLockedError } = await import("openclaw/plugin-sdk/model-session-runtime");
572
- const { codexBindingConnectionSelection, resolveCodexBindingAppServerConnection } = await import("./.setup/binding-connection-DTtN1KrX.mjs").then((n) => n.n);
573
- const { resolveCodexSupervisionAppServerRuntimeOptions } = await import("./.setup/config-runtime-C0NbLms1.mjs").then((n) => n.t);
665
+ const { codexBindingConnectionSelection, resolveCodexBindingAppServerConnection } = await import("./.setup/binding-connection-C-08ez1w.mjs").then((n) => n.n);
666
+ const { resolveCodexSupervisionAppServerRuntimeOptions } = await import("./.setup/config-runtime-cUYrqu_a.mjs").then((n) => n.t);
574
667
  const requestOptions = async () => {
575
668
  const pluginConfig = admissionConfig;
576
- const plugin = readCodexPluginConfig(pluginConfig);
669
+ const plugin = admissionPlugin;
577
670
  const base = baseRequestOptions();
578
671
  const session = currentSession();
579
672
  const identity = session ? currentIdentity(session.sessionId) : void 0;
@@ -626,7 +719,7 @@ function createCodexThreadsTool(options) {
626
719
  ...cursor ? { cursor } : {},
627
720
  ...searchTerm ? { searchTerm } : {}
628
721
  });
629
- return jsonResult(mayReadRawTranscripts ? response : redactNativeThreadResponse(response));
722
+ return threadResult(response);
630
723
  }
631
724
  const threadId = archiveAdmission?.threadId ?? readThreadId(params);
632
725
  if (action === "read") {
@@ -636,7 +729,7 @@ function createCodexThreadsTool(options) {
636
729
  threadId,
637
730
  includeTurns
638
731
  });
639
- return jsonResult(mayReadRawTranscripts ? response : redactNativeThreadResponse(response));
732
+ return threadResult(response);
640
733
  }
641
734
  if (action === "rename") {
642
735
  const name = readStringParam(params, "name", {
@@ -655,7 +748,7 @@ function createCodexThreadsTool(options) {
655
748
  }
656
749
  if (action === "unarchive") {
657
750
  const response = await scopedRequest(CODEX_CONTROL_METHODS.unarchiveThread, { threadId });
658
- return jsonResult(mayReadRawTranscripts ? response : redactNativeThreadResponse(response));
751
+ return threadResult(response);
659
752
  }
660
753
  const session = archiveAdmission?.session ?? currentSession();
661
754
  const binding = currentBinding(session);
@@ -699,8 +792,8 @@ function createCodexThreadsTool(options) {
699
792
  const usesSupervisionConnection = binding?.connectionScope === "supervision" || admissionPlugin.appServer?.homeScope !== "user" && supervision?.enabled === true;
700
793
  if (attach && usesSupervisionConnection) throw new Error("Supervised Codex forks must stay detached; set attach=false.");
701
794
  const forkOptions = await requestOptions();
702
- const { retainCodexAppServerBindingSubscription, rollbackCodexAppServerBindingSubscription } = await import("./.setup/thread-ownership-B6pPt21M.mjs").then((n) => n.o);
703
- const { closeCodexStartupClientBestEffort } = await import("./.setup/attempt-client-cleanup-B-S7ngS_.mjs").then((n) => n.a);
795
+ const { retainCodexAppServerBindingSubscription, rollbackCodexAppServerBindingSubscription } = await import("./.setup/thread-ownership-0aRHD9iK.mjs").then((n) => n.o);
796
+ const { closeCodexStartupClientBestEffort } = await import("./.setup/attempt-client-cleanup-yLjGwbwT.mjs").then((n) => n.a);
704
797
  if (attach) {
705
798
  assertCodexBindingMayBeReplaced(binding, "attaching a different native fork");
706
799
  assertThreadIdle(await request(admissionConfig, CODEX_CONTROL_METHODS.readThread, {
@@ -763,7 +856,7 @@ function createCodexThreadsTool(options) {
763
856
  thread: response.thread,
764
857
  attached: attach
765
858
  };
766
- return jsonResult(mayReadRawTranscripts ? result : redactNativeThreadResponse(result));
859
+ return threadResult(result);
767
860
  };
768
861
  if (action === "archive") {
769
862
  const threadId = readThreadId(params);
@@ -824,7 +917,7 @@ function createCodexNodeExecServerCommand() {
824
917
  signal: AbortSignal.any([io.signal, context.signal])
825
918
  } : io;
826
919
  const assertExecAuthorized = context.prepareExecAuthorization(request.authorization);
827
- const { runCodexNodeExecServer } = await import("./.setup/node-exec-server.runtime-BgBfWQqo.mjs");
920
+ const { runCodexNodeExecServer } = await import("./.setup/node-exec-server.runtime-0xSEjKYt.mjs");
828
921
  runtimeIo.signal.throwIfAborted();
829
922
  const workspace = await context.acquireManagedWorkspaceAsync({
830
923
  workspaceDir: placement.cwd,
@@ -927,188 +1020,2711 @@ function createCodexNodeExecServerInvokePolicy() {
927
1020
  };
928
1021
  }
929
1022
  //#endregion
930
- //#region extensions/codex/src/supervision-tool-policy.ts
931
- var CodexSupervisionPolicyError = class extends Error {};
932
- function requireSupervisionEnabled(pluginConfig) {
933
- if (readCodexPluginConfig(pluginConfig).supervision?.enabled !== true) throw new CodexSupervisionPolicyError("Codex supervision is disabled in the codex plugin config.");
934
- }
935
- function requireOwnerAccess(options) {
936
- options.assertInvocationCurrent?.();
937
- if (!options.senderIsOwner) throw new CodexSupervisionPolicyError("Codex supervision compatibility tools require an owner-authorized sender.");
938
- }
939
- function resolveToolPolicy(pluginConfig) {
940
- const config = readCodexPluginConfig(pluginConfig).supervision;
941
- return {
942
- allowRawTranscripts: config?.allowRawTranscripts === true,
943
- allowWriteControls: config?.allowWriteControls === true
1023
+ //#region extensions/codex/src/session-catalog-create.ts
1024
+ const CODEX_AGENT_RUNTIME_ID = "codex";
1025
+ const CODEX_CATALOG_DEFAULT_MODEL_REF = "openai/gpt-6-astra";
1026
+ function resolveCodexCatalogCreateSession(modelConfig, config, requestedAgentId) {
1027
+ if (!config) return;
1028
+ const agentId = requestedAgentId ?? resolveDefaultAgentId(config);
1029
+ const defaultModel = modelConfig.resolveDefaultModelForAgent({
1030
+ cfg: config,
1031
+ agentId
1032
+ });
1033
+ const modelRef = defaultModel.provider === "openai" ? `${defaultModel.provider}/${defaultModel.model}` : CODEX_CATALOG_DEFAULT_MODEL_REF;
1034
+ const allowed = modelConfig.resolveAllowedModelRef({
1035
+ cfg: config,
1036
+ catalog: [],
1037
+ raw: modelRef,
1038
+ defaultProvider: defaultModel.provider,
1039
+ defaultModel: defaultModel.model,
1040
+ agentId
1041
+ });
1042
+ return "error" in allowed ? void 0 : {
1043
+ model: allowed.key,
1044
+ agentRuntime: CODEX_AGENT_RUNTIME_ID
944
1045
  };
945
1046
  }
946
- function requireRawTranscriptAccess(pluginConfig) {
947
- if (!resolveToolPolicy(pluginConfig).allowRawTranscripts) throw new CodexSupervisionPolicyError("Codex session reads are disabled for this codex plugin supervision config.");
948
- }
949
- function requireWriteAccess(pluginConfig) {
950
- if (!resolveToolPolicy(pluginConfig).allowWriteControls) throw new CodexSupervisionPolicyError("Codex write controls are disabled for this codex plugin supervision config.");
951
- }
952
1047
  //#endregion
953
- //#region extensions/codex/src/supervision-tools.ts
954
- /**
955
- * Compatibility tools for the retired Codex Supervisor plugin.
956
- *
957
- * Read operations and active-turn controls use the Codex plugin's canonical
958
- * shared app-server client. Idle threads are never resumed or started here:
959
- * continuation belongs to the Codex harness, which installs approval and tool
960
- * handlers before it starts or resumes the harness-owned Codex thread.
961
- */
962
- /** Legacy endpoint env retained for the shipped Supervisor tool contract. */
963
- const LEGACY_CODEX_SUPERVISOR_ENDPOINTS_ENV = "OPENCLAW_CODEX_SUPERVISOR_ENDPOINTS";
964
- const CODEX_SUPERVISION_COMPAT_TOOL_NAMES = [
965
- "codex_endpoint_probe",
966
- "codex_sessions_list",
967
- "codex_session_read",
968
- "codex_session_send",
969
- "codex_session_interrupt"
1048
+ //#region extensions/codex/src/app-server/request-observation.ts
1049
+ const CODEX_REQUEST_WAITER_OUTCOMES = [
1050
+ "resolved",
1051
+ "native-error",
1052
+ "timed-out",
1053
+ "aborted",
1054
+ "authority-rejected",
1055
+ "local-failed",
1056
+ "client-closed"
970
1057
  ];
971
- const EmptyParamsSchema = Type.Object({}, { additionalProperties: false });
972
- const SessionsListParamsSchema = Type.Object({
973
- include_stored: Type.Optional(Type.Boolean()),
974
- max_stored_sessions: Type.Optional(Type.Integer({
975
- minimum: 1,
976
- maximum: 1e3
977
- }))
978
- }, { additionalProperties: false });
979
- const SessionReadParamsSchema = Type.Object({
980
- endpoint_id: Type.Optional(Type.String()),
981
- thread_id: Type.String(),
982
- include_turns: Type.Optional(Type.Boolean())
983
- }, { additionalProperties: false });
984
- const SessionSendParamsSchema = Type.Object({
985
- endpoint_id: Type.Optional(Type.String()),
986
- thread_id: Type.String(),
987
- text: Type.String(),
988
- mode: Type.Optional(Type.Union([
989
- Type.Literal("auto"),
990
- Type.Literal("start"),
991
- Type.Literal("steer")
992
- ]))
993
- }, { additionalProperties: false });
994
- const SessionInterruptParamsSchema = Type.Object({
995
- endpoint_id: Type.Optional(Type.String()),
996
- thread_id: Type.String(),
997
- turn_id: Type.Optional(Type.String())
998
- }, { additionalProperties: false });
999
- const ALL_CODEX_THREAD_SOURCE_KINDS = [
1000
- "cli",
1001
- "vscode",
1002
- "exec",
1003
- "appServer",
1004
- "subAgent",
1005
- "subAgentReview",
1006
- "subAgentCompact",
1007
- "subAgentThreadSpawn",
1008
- "subAgentOther",
1009
- "unknown"
1058
+ const CODEX_REQUEST_WIRE_OUTCOMES = [
1059
+ "retained-pending",
1060
+ "native-ok",
1061
+ "native-error",
1062
+ "ingress-rejected",
1063
+ "correlation-closed",
1064
+ "not-written"
1010
1065
  ];
1011
- const DEFAULT_MAX_STORED_SESSIONS = 200;
1012
- const PAGE_LIMIT = 100;
1013
- const MAX_COMPAT_PAGINATION_PAGES = 100;
1014
- const MAX_COMPAT_CURSOR_LENGTH = 4096;
1015
- const MAX_COMPAT_THREAD_ID_LENGTH = 4096;
1016
- function asRecordArray(value) {
1017
- return Array.isArray(value) ? value.filter(isRecord) : [];
1018
- }
1019
- function readCompatNextCursor(value, method) {
1020
- if (value === null || value === void 0) return;
1021
- if (typeof value !== "string" || value.trim().length === 0 || value.length > MAX_COMPAT_CURSOR_LENGTH) throw new Error(`Codex ${method} returned an invalid nextCursor`);
1022
- return value;
1066
+ //#endregion
1067
+ //#region extensions/codex/src/session-catalog-diagnostics.ts
1068
+ const log = createSubsystemLogger("gateway/session-catalog");
1069
+ const listScope = new AsyncLocalStorage();
1070
+ let epoch;
1071
+ let sequence = 0;
1072
+ let active = 0;
1073
+ let windowStart = 0;
1074
+ let emitted = 0;
1075
+ let omitted = 0;
1076
+ const WAITER_OUTCOMES = new Set(CODEX_REQUEST_WAITER_OUTCOMES);
1077
+ const WIRE_OUTCOMES = new Set(CODEX_REQUEST_WIRE_OUTCOMES);
1078
+ function controlWaiterTuple(controlCallOrdinal, summary) {
1079
+ const ordinals = [
1080
+ controlCallOrdinal,
1081
+ summary.overloadAttemptOrdinal,
1082
+ summary.rpcId,
1083
+ summary.waiterOrdinal
1084
+ ];
1085
+ const times = [
1086
+ summary.attemptCreatedAtMs,
1087
+ summary.waiterAttachedAtMs,
1088
+ summary.waiterSettledAtMs
1089
+ ];
1090
+ const optionalTimes = [summary.firstPossibleWriteAtMs, summary.wireObservedAtMs];
1091
+ const validTime = (value) => Number.isFinite(value) && value >= 0 && Number.isSafeInteger(Math.round(value));
1092
+ if (!/^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/i.test(summary.clientInstanceId) || !ordinals.every((value) => Number.isSafeInteger(value) && value > 0) || !times.every(validTime) || !optionalTimes.every((value) => value === null || validTime(value)) || summary.disposition !== "new" && summary.disposition !== "joined" || !WAITER_OUTCOMES.has(summary.waiterOutcome) || !WIRE_OUTCOMES.has(summary.wireOutcomeAtWaiterSettlement)) return;
1093
+ return [
1094
+ controlCallOrdinal,
1095
+ summary.overloadAttemptOrdinal,
1096
+ summary.clientInstanceId,
1097
+ summary.rpcId,
1098
+ summary.waiterOrdinal,
1099
+ summary.disposition,
1100
+ Math.round(summary.attemptCreatedAtMs),
1101
+ summary.firstPossibleWriteAtMs === null ? null : Math.round(summary.firstPossibleWriteAtMs),
1102
+ Math.round(summary.waiterAttachedAtMs),
1103
+ Math.round(summary.waiterSettledAtMs),
1104
+ summary.waiterOutcome,
1105
+ summary.wireOutcomeAtWaiterSettlement,
1106
+ summary.wireObservedAtMs === null ? null : Math.round(summary.wireObservedAtMs)
1107
+ ];
1023
1108
  }
1024
- function readCompatThreadId(value, method, index) {
1025
- if (typeof value !== "string" || value.trim().length === 0 || value.length > MAX_COMPAT_THREAD_ID_LENGTH) throw new Error(`Codex ${method} returned an invalid thread id at data[${index}]`);
1026
- return value;
1109
+ function fitsMetadata(metadata) {
1110
+ return Object.keys(metadata).length <= 28 && Buffer.byteLength(JSON.stringify(metadata)) <= 2048;
1027
1111
  }
1028
- function readLoadedThreadIds(data) {
1029
- if (data.length > PAGE_LIMIT) throw new Error(`Codex thread/loaded/list returned more than ${PAGE_LIMIT} entries`);
1030
- return data.map((entry, index) => readCompatThreadId(entry, "thread/loaded/list", index));
1112
+ function withControlWaiters(metadata, fields) {
1113
+ if (!("origin" in fields) || !fields.controlWaitersV1) return metadata;
1114
+ const kept = fields.controlWaitersV1.slice();
1115
+ let count = fields.controlWaitersOmitted ?? 0;
1116
+ while (true) {
1117
+ const complete = {
1118
+ ...metadata,
1119
+ controlWaitersV1: JSON.stringify(kept),
1120
+ controlWaitersOmitted: count
1121
+ };
1122
+ if (fitsMetadata(complete)) return complete;
1123
+ if (kept.length === 0) {
1124
+ const countOnly = {
1125
+ ...metadata,
1126
+ controlWaitersOmitted: count
1127
+ };
1128
+ return fitsMetadata(countOnly) ? countOnly : metadata;
1129
+ }
1130
+ kept.splice(kept.length > 2 ? kept.length - 2 : 0, 1);
1131
+ count = Math.min(Number.MAX_SAFE_INTEGER, count + 1);
1132
+ }
1031
1133
  }
1032
- function readStoredThreads(data, maxEntries) {
1033
- if (data.length > maxEntries) throw new Error(`Codex thread/list returned more than ${maxEntries} entries`);
1034
- return data.map((entry, index) => {
1035
- if (!isRecord(entry)) throw new Error(`Codex thread/list returned an invalid entry at data[${index}]`);
1036
- readCompatThreadId(entry.id, "thread/list", index);
1037
- return entry;
1038
- });
1134
+ const CONTROL_PHASE_FIELDS = {
1135
+ "load-control": "controlLoadMs",
1136
+ prepare: "controlPrepareMs",
1137
+ "acquire-client": "controlAcquireClientMs",
1138
+ "client-request": "controlClientRequestMs",
1139
+ "release-client": "controlReleaseClientMs"
1140
+ };
1141
+ function enabled() {
1142
+ return areDiagnosticsEnabledForProcess() && log.isEnabled("warn");
1039
1143
  }
1040
- function readIntegerParam(params, key) {
1041
- const value = params[key];
1042
- if (value === void 0) return;
1043
- if (typeof value !== "number" || !Number.isInteger(value)) throw new Error(`${key} must be an integer`);
1044
- if (value < 1 || value > 1e3) throw new Error(`${key} must be between 1 and 1000`);
1045
- return value;
1144
+ function start(kind, fields) {
1145
+ if (!enabled()) return;
1146
+ if (active >= 64) {
1147
+ omitted = Math.min(Number.MAX_SAFE_INTEGER, omitted + 1);
1148
+ return;
1149
+ }
1150
+ active++;
1151
+ epoch ??= randomUUID();
1152
+ const started = performance.now();
1153
+ const observation = {
1154
+ operationId: String(++sequence),
1155
+ fields,
1156
+ closed: false,
1157
+ finish(outcome) {
1158
+ if (observation.closed) return;
1159
+ observation.closed = true;
1160
+ active--;
1161
+ const elapsedMs = performance.now() - started;
1162
+ try {
1163
+ if (elapsedMs < 1e3 || !enabled()) return;
1164
+ if (performance.now() - windowStart >= 6e4) {
1165
+ windowStart = performance.now();
1166
+ emitted = 0;
1167
+ }
1168
+ if (emitted >= 60) {
1169
+ omitted = Math.min(Number.MAX_SAFE_INTEGER, omitted + 1);
1170
+ return;
1171
+ }
1172
+ const metadata = {
1173
+ diagnosticEpoch: epoch,
1174
+ operationId: observation.operationId,
1175
+ pid: process.pid,
1176
+ threadId,
1177
+ isMainThread,
1178
+ elapsedMs: Math.round(elapsedMs),
1179
+ outcome,
1180
+ omittedObservations: omitted,
1181
+ ...Object.fromEntries(Object.entries(fields).filter(([key, value]) => value !== void 0 && key !== "controlWaitersV1" && key !== "controlWaitersOmitted").map(([key, value]) => [key, typeof value === "number" ? Math.round(value) : value]))
1182
+ };
1183
+ if (!fitsMetadata(metadata)) {
1184
+ omitted = Math.min(Number.MAX_SAFE_INTEGER, omitted + 1);
1185
+ return;
1186
+ }
1187
+ emitted++;
1188
+ log.warn(`slow Codex catalog ${kind}`, withControlWaiters(metadata, fields));
1189
+ omitted = 0;
1190
+ } catch {}
1191
+ }
1192
+ };
1193
+ return observation;
1046
1194
  }
1047
- function readModeParam(params) {
1048
- const mode = readStringParam(params, "mode");
1049
- if (!mode) return;
1050
- if (mode === "auto" || mode === "start" || mode === "steer") return mode;
1051
- throw new Error("mode must be auto, start, or steer");
1195
+ function currentCodexCatalogListDiagnostics() {
1196
+ const observation = listScope.getStore();
1197
+ return observation?.closed ? void 0 : observation;
1052
1198
  }
1053
- function normalizeEndpointId(value, index) {
1054
- const trimmed = value.trim();
1055
- return trimmed ? trimmed.replace(/[^a-zA-Z0-9_.:-]/g, "-") : `endpoint-${index + 1}`;
1199
+ function startCodexCatalogListTiming(field, counter) {
1200
+ const observation = currentCodexCatalogListDiagnostics();
1201
+ const started = observation ? performance.now() : 0;
1202
+ if (observation && counter) observation.fields[counter]++;
1203
+ return () => {
1204
+ if (observation && !observation.closed) observation.fields[field] = (observation.fields[field] ?? 0) + performance.now() - started;
1205
+ };
1056
1206
  }
1057
- function normalizeConfiguredEndpoint(endpoint, index) {
1207
+ /** One logical list scope survives admission pauses; finishing drops its captured context. */
1208
+ function createCodexCatalogListScope() {
1209
+ const observation = start("list phases", {
1210
+ controlPageCalls: 0,
1211
+ exclusionMarkCalls: 0,
1212
+ adoptionCalls: 0
1213
+ });
1214
+ let captured = listScope.run(observation, () => AsyncLocalStorage.snapshot());
1058
1215
  return {
1059
- id: normalizeEndpointId(endpoint.id ?? endpoint.label ?? "", index),
1060
- ...endpoint.label?.trim() ? { label: endpoint.label.trim() } : {},
1061
- configured: endpoint
1216
+ run(run) {
1217
+ if (!captured) throw new Error("Codex catalog diagnostic scope is closed");
1218
+ return captured(run);
1219
+ },
1220
+ finish(outcome) {
1221
+ const finishInScope = captured;
1222
+ captured = void 0;
1223
+ finishInScope?.(() => observation?.finish(outcome));
1224
+ }
1062
1225
  };
1063
1226
  }
1064
- function parseEndpointRecord(value) {
1065
- if (!isRecord(value)) return;
1066
- const transport = typeof value.transport === "string" ? value.transport : void 0;
1067
- const common = {
1068
- ...typeof value.id === "string" ? { id: value.id } : {},
1069
- ...typeof value.label === "string" ? { label: value.label } : {}
1227
+ function startCodexCatalogPageDiagnostics(origin) {
1228
+ return start("page producer", {
1229
+ origin,
1230
+ listOperationId: currentCodexCatalogListDiagnostics()?.operationId,
1231
+ controlRequestCalls: 0,
1232
+ provenanceChecks: 0,
1233
+ provenanceCacheHits: 0,
1234
+ provenanceReadCalls: 0
1235
+ });
1236
+ }
1237
+ function startCodexCatalogControlRequestDiagnostics(page) {
1238
+ if (!page) return;
1239
+ let state = "active";
1240
+ const controlCallOrdinal = page.fields.controlRequestCalls;
1241
+ let phase = "load-control";
1242
+ let phaseStarted = performance.now();
1243
+ const finishPhase = () => {
1244
+ const now = performance.now();
1245
+ const field = CONTROL_PHASE_FIELDS[phase];
1246
+ page.fields[field] = (page.fields[field] ?? 0) + (now - phaseStarted);
1247
+ phaseStarted = now;
1070
1248
  };
1071
- if (transport === "websocket" && typeof value.url === "string") return {
1072
- ...common,
1073
- transport,
1074
- url: value.url,
1075
- ...typeof value.authTokenEnv === "string" ? { authTokenEnv: value.authTokenEnv } : {}
1249
+ const observation = {
1250
+ attemptWaiterFinished(summary) {
1251
+ if (state === "closed" || page.closed) return;
1252
+ const kept = page.fields.controlWaitersV1 ??= [];
1253
+ page.fields.controlWaitersOmitted ??= 0;
1254
+ const tuple = controlWaiterTuple(controlCallOrdinal, summary);
1255
+ if (!tuple) {
1256
+ page.fields.controlWaitersOmitted = Math.min(Number.MAX_SAFE_INTEGER, page.fields.controlWaitersOmitted + 1);
1257
+ return;
1258
+ }
1259
+ if (kept.length === 4) {
1260
+ kept.splice(2, 1);
1261
+ page.fields.controlWaitersOmitted = Math.min(Number.MAX_SAFE_INTEGER, page.fields.controlWaitersOmitted + 1);
1262
+ }
1263
+ kept.push(tuple);
1264
+ },
1265
+ phase(next) {
1266
+ if (state === "active" && !page.closed) {
1267
+ finishPhase();
1268
+ phase = next;
1269
+ }
1270
+ },
1271
+ failed(failure) {
1272
+ if (state === "active" && !page.closed) {
1273
+ finishPhase();
1274
+ state = "failed";
1275
+ page.fields.controlFailurePhase = failure.phase;
1276
+ page.fields.controlFailureCategory = failure.category;
1277
+ }
1278
+ },
1279
+ rejected() {
1280
+ observation.failed({
1281
+ phase,
1282
+ category: "other"
1283
+ });
1284
+ },
1285
+ close() {
1286
+ if (state === "active" && !page.closed) finishPhase();
1287
+ state = "closed";
1288
+ }
1076
1289
  };
1077
- if (transport === "stdio-proxy" || transport === void 0) {
1078
- const args = Array.isArray(value.args) ? value.args.filter((entry) => typeof entry === "string") : void 0;
1290
+ return observation;
1291
+ }
1292
+ //#endregion
1293
+ //#region extensions/codex/src/session-catalog-node-snapshot.ts
1294
+ /** One query-compatible native page per node, owned by the registered catalog provider. */
1295
+ var CodexCatalogNodeSnapshots = class {
1296
+ constructor() {
1297
+ this.generation = 0;
1298
+ this.inventoryGeneration = 0;
1299
+ this.configGeneration = 0;
1300
+ this.nodes = /* @__PURE__ */ new Map();
1301
+ }
1302
+ start(config) {
1303
+ if (this.config !== config) {
1304
+ this.nodes.clear();
1305
+ this.config = config;
1306
+ this.configGeneration = this.generation + 1;
1307
+ this.inventoryGeneration = this.configGeneration;
1308
+ }
1309
+ return ++this.generation;
1310
+ }
1311
+ observe(generation, nodes) {
1312
+ if (generation < this.inventoryGeneration) return;
1313
+ this.inventoryGeneration = generation;
1314
+ const connected = new Map(nodes.filter((node) => node.connected).map((node) => [node.nodeId, node]));
1315
+ for (const [nodeId, publication] of this.nodes) {
1316
+ const node = connected.get(nodeId);
1317
+ if (!node || node.connectedAtMs !== publication.connection) this.nodes.delete(nodeId);
1318
+ }
1319
+ for (const node of connected.values()) if (!this.nodes.has(node.nodeId)) this.nodes.set(node.nodeId, {
1320
+ connection: node.connectedAtMs,
1321
+ generation: 0
1322
+ });
1323
+ }
1324
+ forNode(node, generation, key) {
1325
+ let publication = this.nodes.get(node.nodeId);
1326
+ if (!publication) {
1327
+ publication = {
1328
+ connection: node.connectedAtMs,
1329
+ generation: 0
1330
+ };
1331
+ if (generation >= this.inventoryGeneration) this.nodes.set(node.nodeId, publication);
1332
+ }
1333
+ const valid = () => generation >= this.configGeneration && this.nodes.get(node.nodeId) === publication && publication.connection === node.connectedAtMs;
1079
1334
  return {
1080
- ...common,
1081
- transport: "stdio-proxy",
1082
- ...typeof value.command === "string" ? { command: value.command } : {},
1083
- ...args && args.length > 0 ? { args } : {},
1084
- ...typeof value.cwd === "string" ? { cwd: value.cwd } : {}
1335
+ read: () => valid() && publication.snapshot?.key === key ? publication.snapshot : void 0,
1336
+ publish: (host) => {
1337
+ if (!valid() || generation < publication.generation) return false;
1338
+ publication.generation = generation;
1339
+ publication.snapshot = node.connected && host.connected ? {
1340
+ key,
1341
+ host
1342
+ } : void 0;
1343
+ return true;
1344
+ },
1345
+ isCurrent: (snapshot) => valid() && publication.snapshot === snapshot,
1346
+ valid
1085
1347
  };
1086
1348
  }
1087
- }
1088
- function endpointFromToken(token, index) {
1089
- const trimmed = token.trim();
1090
- if (!trimmed) return;
1091
- if (trimmed.startsWith("ws://") || trimmed.startsWith("wss://") || trimmed.startsWith("unix://")) return {
1092
- id: normalizeEndpointId("", index),
1093
- transport: "websocket",
1094
- url: trimmed
1349
+ };
1350
+ function createNodeHostPublication(publication, adopted, sourceKey, onHost, signal, partial, waitUntil) {
1351
+ let publishedSnapshot;
1352
+ let publishedHost;
1353
+ const project = (host) => ({
1354
+ ...host,
1355
+ sessions: host.sessions.map((session) => {
1356
+ const entry = session.sourceHomeId ? adopted.get(sourceKey(host.hostId, session.threadId, session.sourceHomeId)) : void 0;
1357
+ return entry ? {
1358
+ ...session,
1359
+ sessionKey: entry.key
1360
+ } : session;
1361
+ })
1362
+ });
1363
+ const emit = (host) => {
1364
+ publishedHost = project(host);
1365
+ return onHost?.(publishedHost);
1095
1366
  };
1096
- if (trimmed === "local" || trimmed === "proxy" || trimmed === "stdio") return {
1097
- id: "local",
1098
- label: "local Codex app-server",
1099
- transport: "stdio-proxy"
1367
+ return {
1368
+ project,
1369
+ readPublished: () => publishedHost,
1370
+ publish: (host) => {
1371
+ if (signal?.aborted) return partial ? void 0 : onHost?.(project(host));
1372
+ if (!publication.valid()) return;
1373
+ if (publication.publish(host)) {
1374
+ publishedSnapshot = publication.read();
1375
+ return emit(host);
1376
+ }
1377
+ const latest = publication.read();
1378
+ return emit(latest?.host ?? host);
1379
+ },
1380
+ publishCached: (snapshot) => {
1381
+ if (signal?.aborted || snapshot === publishedSnapshot || !publication.isCurrent(snapshot)) return;
1382
+ const completion = createDeferred();
1383
+ completion.promise.catch(() => void 0);
1384
+ try {
1385
+ waitUntil?.(completion.promise);
1386
+ completion.resolve(emit(snapshot.host));
1387
+ publishedSnapshot = snapshot;
1388
+ } catch (error) {
1389
+ completion.reject(error);
1390
+ throw error;
1391
+ }
1392
+ }
1100
1393
  };
1101
- const separatorIndex = trimmed.indexOf("=");
1102
- const id = separatorIndex >= 0 ? trimmed.slice(0, separatorIndex) : trimmed;
1103
- const url = separatorIndex >= 0 ? trimmed.slice(separatorIndex + 1) : void 0;
1104
- if (url?.startsWith("ws://") || url?.startsWith("wss://") || url?.startsWith("unix://")) return {
1105
- id: normalizeEndpointId(id, index),
1106
- transport: "websocket",
1107
- url
1394
+ }
1395
+ //#endregion
1396
+ //#region extensions/codex/src/session-catalog-terminal.ts
1397
+ const CODEX_TERMINAL_RESUME_COMMAND = "codex.terminal.resume.v1";
1398
+ const CODEX_TERMINAL_START_COMMAND = "codex.terminal.start.v1";
1399
+ function createCodexTerminalStartNodeHostCommand() {
1400
+ return {
1401
+ command: CODEX_TERMINAL_START_COMMAND,
1402
+ cap: CODEX_APP_SERVER_THREADS_CAPABILITY,
1403
+ dangerous: false,
1404
+ duplex: true,
1405
+ hasActiveWork: () => false,
1406
+ isAvailable: ({ env }) => Boolean(resolveNodeHostExecutable("codex", {
1407
+ env,
1408
+ strategy: "direct"
1409
+ })),
1410
+ handle: async (paramsJSON, io) => {
1411
+ if (!io) throw new Error("Codex terminal command requires duplex transport");
1412
+ const params = decodeNodePtyStartParams(paramsJSON);
1413
+ const resolution = resolveNodeHostExecutable("codex", { strategy: "direct" });
1414
+ if (!resolution) throw new Error("Codex CLI is unavailable; install codex on this node and reconnect");
1415
+ return JSON.stringify(await runNodePtyCommand({
1416
+ file: resolution.executable,
1417
+ args: params.initialMessage !== void 0 ? ["--", params.initialMessage] : [],
1418
+ cwd: params.cwd,
1419
+ requiredCwd: true,
1420
+ cols: params.cols,
1421
+ rows: params.rows
1422
+ }, io));
1423
+ }
1108
1424
  };
1109
1425
  }
1110
- function requireUniqueEndpointIds(endpoints) {
1111
- const seen = /* @__PURE__ */ new Set();
1426
+ function resolveCodexCatalogTerminalHome(sources) {
1427
+ sources.source?.assertCurrent();
1428
+ const runtimeConfig = sources.getRuntimeConfig();
1429
+ if (!runtimeConfig) throw new Error("OpenClaw runtime config is unavailable");
1430
+ const agentDir = sources.source?.agentDir ?? (sources.agentId ? resolveAgentDir(runtimeConfig, sources.agentId) : resolveDefaultAgentDir(runtimeConfig));
1431
+ const startOptions = sources.source?.appServer.start ?? sources.resolveRuntimeOptions({ pluginConfig: sources.getPluginConfig() }).start;
1432
+ if (startOptions.transport !== "stdio") throw new CatalogParamsError("Native terminal requires a local Codex source");
1433
+ return resolveCodexAppServerLocalHomeDir(startOptions, agentDir);
1434
+ }
1435
+ function resolveLocalCodexTerminalExecutable(env = process.env) {
1436
+ return resolveLocalCodexTerminalResolution(env)?.executable;
1437
+ }
1438
+ function resolveLocalCodexTerminalResolution(env = process.env) {
1439
+ return resolveNodeHostExecutable("codex", {
1440
+ env,
1441
+ pathEnv: env.PATH ?? env.Path ?? "",
1442
+ strategy: "fallback"
1443
+ });
1444
+ }
1445
+ function codexNodeTerminalCapability(node) {
1446
+ const commands = node.invocableCommands ?? node.commands;
1447
+ return {
1448
+ canOpenTerminalCodex: node.connected === true && commands?.includes("codex.terminal.resume.v1") === true,
1449
+ canStartTerminal: node.connected === true && node.invocableCommands?.includes("codex.terminal.start.v1") === true
1450
+ };
1451
+ }
1452
+ function createCodexTerminalNodeHostCommand(bindRequest) {
1453
+ return {
1454
+ command: CODEX_TERMINAL_RESUME_COMMAND,
1455
+ cap: CODEX_APP_SERVER_THREADS_CAPABILITY,
1456
+ dangerous: false,
1457
+ duplex: true,
1458
+ hasActiveWork: () => false,
1459
+ isAvailable: ({ config, env }) => (readCodexPluginConfig(config.plugins?.entries?.codex?.config).appServer?.transport ?? "stdio") === "stdio" && Boolean(resolveNodeHostExecutable("codex", {
1460
+ env,
1461
+ pathEnv: env.PATH ?? env.Path ?? "",
1462
+ strategy: "direct"
1463
+ })),
1464
+ handle: async (paramsJSON, io) => {
1465
+ if (!io) throw new Error("Codex terminal command requires duplex transport");
1466
+ const request = await bindRequest(paramsJSON);
1467
+ if (request.transport !== "stdio") throw new CatalogParamsError("Native terminal requires a local Codex source");
1468
+ const resume = decodeNodePtyResumeParams(request.paramsJSON, (value) => {
1469
+ 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");
1470
+ return value;
1471
+ });
1472
+ const record = await request.control.requireEligibleThread(resume.threadId);
1473
+ const resolution = resolveNodeHostExecutable("codex", {
1474
+ env: process.env,
1475
+ pathEnv: process.env.PATH ?? process.env.Path ?? "",
1476
+ strategy: "direct"
1477
+ });
1478
+ if (!resolution) throw new Error("Codex CLI is unavailable");
1479
+ request.assertCurrent();
1480
+ return JSON.stringify(await runNodePtyCommand({
1481
+ file: resolution.executable,
1482
+ args: ["resume", resume.threadId],
1483
+ assertCurrent: () => request.assertCurrent(),
1484
+ ...record.cwd ? { cwd: record.cwd } : {},
1485
+ env: { CODEX_HOME: request.codexHome },
1486
+ cols: resume.cols,
1487
+ rows: resume.rows
1488
+ }, io));
1489
+ }
1490
+ };
1491
+ }
1492
+ async function openCodexCatalogTerminal(params) {
1493
+ const title = `codex resume ${params.threadId.slice(0, 8)}…`;
1494
+ if (params.hostId === "gateway:local" || params.hostId.startsWith(`gateway:local:`)) {
1495
+ const record = await params.control.requireEligibleThread(params.threadId);
1496
+ const resolution = resolveLocalCodexTerminalResolution();
1497
+ if (!resolution) throw new CatalogParamsError("Codex CLI is unavailable");
1498
+ return {
1499
+ kind: "local",
1500
+ argv: [
1501
+ resolution.executable,
1502
+ "resume",
1503
+ params.threadId
1504
+ ],
1505
+ ...record.cwd ? { cwd: record.cwd } : {},
1506
+ env: { CODEX_HOME: resolveCodexCatalogTerminalHome(params) },
1507
+ ...resolution.pathEnv ? { pathEnv: resolution.pathEnv } : {},
1508
+ title
1509
+ };
1510
+ }
1511
+ if (!params.hostId.startsWith("node:")) throw new CatalogParamsError("hostId is invalid");
1512
+ const nodeId = params.hostId.slice(5);
1513
+ if (!(await params.api.runtime.nodes.list()).nodes.find((candidate) => {
1514
+ const commands = candidate.invocableCommands ?? candidate.commands;
1515
+ return candidate.nodeId === nodeId && candidate.connected === true && commands?.includes("codex.appServer.threads.list.v1") === true && commands.includes("codex.terminal.resume.v1");
1516
+ })) throw new CatalogParamsError("paired-node Codex terminal is unavailable");
1517
+ const lookup = await lookupNodeCodexCatalogRecord({
1518
+ agentId: params.agentId,
1519
+ runtime: params.api.runtime,
1520
+ nodeId,
1521
+ threadId: params.threadId,
1522
+ sourceHomeId: params.sourceHomeId
1523
+ });
1524
+ if (lookup.kind !== "found" || !isInteractiveThreadSource(lookup.record.source)) throw new CatalogParamsError("Codex session is not a non-archived interactive Codex session");
1525
+ const record = lookup.record;
1526
+ return {
1527
+ kind: "node",
1528
+ nodeId,
1529
+ command: CODEX_TERMINAL_RESUME_COMMAND,
1530
+ uploadPathStyle: "native",
1531
+ paramsJSON: JSON.stringify({
1532
+ agentId: params.agentId,
1533
+ threadId: params.threadId,
1534
+ ...lookup.sourceHomeId ? { sourceHomeId: lookup.sourceHomeId } : {}
1535
+ }),
1536
+ ...record.cwd ? { cwd: record.cwd } : {},
1537
+ title
1538
+ };
1539
+ }
1540
+ async function startCodexCatalogTerminal(params) {
1541
+ if (params.nodeId) return {
1542
+ kind: "node",
1543
+ nodeId: params.nodeId,
1544
+ command: CODEX_TERMINAL_START_COMMAND,
1545
+ uploadPathStyle: "native",
1546
+ paramsJSON: JSON.stringify({
1547
+ cwd: params.cwd,
1548
+ initialMessage: params.initialMessage
1549
+ }),
1550
+ cwd: params.cwd,
1551
+ title: "codex"
1552
+ };
1553
+ const resolution = resolveLocalCodexTerminalResolution();
1554
+ if (!resolution) throw new CatalogParamsError("Codex CLI is unavailable; install Codex or add codex to PATH, then try again");
1555
+ return {
1556
+ kind: "local",
1557
+ argv: [resolution.executable, ...params.initialMessage !== void 0 ? ["--", params.initialMessage] : []],
1558
+ cwd: params.cwd,
1559
+ env: { CODEX_HOME: resolveCodexCatalogTerminalHome(params) },
1560
+ ...resolution.pathEnv ? { pathEnv: resolution.pathEnv } : {},
1561
+ title: "codex"
1562
+ };
1563
+ }
1564
+ //#endregion
1565
+ //#region extensions/codex/src/session-catalog-visible-page.ts
1566
+ /** Fill exclusions from bounded resident pages. */
1567
+ var CodexCatalogVisiblePage = class {
1568
+ constructor(params) {
1569
+ this.params = params;
1570
+ this.sessions = [];
1571
+ this.seenCursors = /* @__PURE__ */ new Set();
1572
+ this.pages = 0;
1573
+ this.complete = false;
1574
+ this.request = new CodexCatalogListRequest();
1575
+ this.cursor = params.cursor;
1576
+ }
1577
+ async next() {
1578
+ try {
1579
+ const step = await this.request.run(() => this.nextPage());
1580
+ if (step.done) this.request.resolved();
1581
+ return step;
1582
+ } catch (error) {
1583
+ if (this.params.signal?.aborted) this.request.close();
1584
+ else this.request.rejected(error);
1585
+ throw error;
1586
+ }
1587
+ }
1588
+ close() {
1589
+ this.complete = true;
1590
+ this.request.close();
1591
+ }
1592
+ async nextPage() {
1593
+ if (this.complete) throw new Error("Codex catalog page is already complete");
1594
+ const params = this.params;
1595
+ params.signal?.throwIfAborted();
1596
+ const finishTiming = startCodexCatalogListTiming("controlWaitSumMs", "controlPageCalls");
1597
+ let rawPage;
1598
+ try {
1599
+ rawPage = await params.control.listPage({
1600
+ limit: params.limit - this.sessions.length,
1601
+ ...this.cursor ? { cursor: this.cursor } : {},
1602
+ ...params.searchTerm ? { searchTerm: params.searchTerm } : {},
1603
+ ...params.cwd ? { cwd: params.cwd } : {}
1604
+ });
1605
+ } finally {
1606
+ finishTiming();
1607
+ }
1608
+ this.request.assertActive();
1609
+ params.signal?.throwIfAborted();
1610
+ const page = filterCatalogPageByTitle(parseCatalogPage(rawPage), params.searchTerm);
1611
+ if (this.pages++ === 0) this.backwardsCursor = page.backwardsCursor;
1612
+ let excludedFromPage = false;
1613
+ for (const managed of rawPage.managedThreads ?? []) {
1614
+ excludedFromPage = true;
1615
+ params.signal?.throwIfAborted();
1616
+ await params.onExcludedThread?.(managed);
1617
+ }
1618
+ for (const session of page.sessions) {
1619
+ if (!params.excludedThreadIds?.has(session.threadId)) {
1620
+ this.sessions.push(session);
1621
+ continue;
1622
+ }
1623
+ excludedFromPage = true;
1624
+ params.signal?.throwIfAborted();
1625
+ await params.onExcludedThread?.({ threadId: session.threadId });
1626
+ }
1627
+ const nextCursor = page.nextCursor;
1628
+ if (!nextCursor || this.sessions.length >= params.limit || !excludedFromPage) this.complete = true;
1629
+ else {
1630
+ if (this.seenCursors.has(nextCursor)) throw new Error("Codex session catalog returned a repeated exclusion cursor");
1631
+ this.seenCursors.add(nextCursor);
1632
+ this.cursor = nextCursor;
1633
+ this.complete = this.pages >= 20 || !this.request.hasPages;
1634
+ }
1635
+ return this.complete ? {
1636
+ done: true,
1637
+ page: {
1638
+ sessions: this.sessions.slice(0, params.limit),
1639
+ ...nextCursor ? { nextCursor } : {},
1640
+ ...this.backwardsCursor ? { backwardsCursor: this.backwardsCursor } : {}
1641
+ }
1642
+ } : { done: false };
1643
+ }
1644
+ };
1645
+ /** Node and direct callers finish the same bounded outer algorithm inline. */
1646
+ async function listVisiblePage(params) {
1647
+ const operation = new CodexCatalogVisiblePage(params);
1648
+ try {
1649
+ for (;;) {
1650
+ const step = await operation.next();
1651
+ if (step.done) return step.page;
1652
+ }
1653
+ } finally {
1654
+ operation.close();
1655
+ }
1656
+ }
1657
+ //#endregion
1658
+ //#region extensions/codex/src/session-catalog-list-operation.ts
1659
+ async function boundedHost(pending) {
1660
+ return await raceWithTimeout(pending, 250, () => void 0);
1661
+ }
1662
+ function measureNodeHost(host, diagnostics, started) {
1663
+ return diagnostics ? host.finally(() => {
1664
+ if (!diagnostics.closed) {
1665
+ diagnostics.fields.pairedNodeSettled = (diagnostics.fields.pairedNodeSettled ?? 0) + 1;
1666
+ diagnostics.fields.nodeWaitSumMs = (diagnostics.fields.nodeWaitSumMs ?? 0) + performance.now() - started;
1667
+ }
1668
+ }) : host;
1669
+ }
1670
+ function hostFailure(source, error) {
1671
+ return {
1672
+ hostId: source?.hostId ?? "gateway:local",
1673
+ label: source?.label ?? "Local Codex",
1674
+ kind: "gateway",
1675
+ connected: false,
1676
+ sessions: [],
1677
+ error: error instanceof CodexCatalogLoadingError ? {
1678
+ code: error.code,
1679
+ message: error.message
1680
+ } : catalogError("APP_SERVER_UNAVAILABLE", error)
1681
+ };
1682
+ }
1683
+ async function projectLocalHost(params, agentId, source, page) {
1684
+ params.signal?.throwIfAborted();
1685
+ const { listAdoptedSessionEntries } = await import("./.setup/session-catalog-adoption-CPIP4S_y.mjs");
1686
+ const { sessionCatalogAdoptedSourceKey } = await import("openclaw/plugin-sdk/session-catalog");
1687
+ params.signal?.throwIfAborted();
1688
+ const finishTiming = startCodexCatalogListTiming("adoptionSumMs", "adoptionCalls");
1689
+ let adopted;
1690
+ try {
1691
+ adopted = await listAdoptedSessionEntries({
1692
+ agentId,
1693
+ bindingStore: params.bindingStore,
1694
+ config: params.config,
1695
+ runtime: params.runtime,
1696
+ sessionEntries: params.sessionEntries
1697
+ });
1698
+ } finally {
1699
+ finishTiming();
1700
+ }
1701
+ const hostId = source?.hostId ?? "gateway:local";
1702
+ const sourceHomeId = source?.sourceHomeId ?? "gateway:local";
1703
+ return {
1704
+ hostId,
1705
+ label: source?.label ?? "Local Codex",
1706
+ kind: "gateway",
1707
+ connected: true,
1708
+ ...page,
1709
+ sessions: page.sessions.map((session) => {
1710
+ const entry = adopted.get(sessionCatalogAdoptedSourceKey(sourceHomeId, session.threadId)) ?? (hostId === "gateway:local" ? adopted.get(sessionCatalogAdoptedSourceKey("gateway:local", session.threadId)) : void 0);
1711
+ const sourced = source ? {
1712
+ ...session,
1713
+ sourceHomeId: source.sourceHomeId
1714
+ } : session;
1715
+ return entry ? {
1716
+ ...sourced,
1717
+ sessionKey: entry.key
1718
+ } : sourced;
1719
+ })
1720
+ };
1721
+ }
1722
+ function managedMarker(store, sourceHomeId, managed) {
1723
+ return async ({ threadId, rolloutPath }) => {
1724
+ if (managed?.has(threadId)) return;
1725
+ const finishTiming = startCodexCatalogListTiming("exclusionMarkSumMs", "exclusionMarkCalls");
1726
+ try {
1727
+ await store.mark({
1728
+ sourceHomeId,
1729
+ threadId,
1730
+ ...rolloutPath ? { rolloutPath } : {}
1731
+ });
1732
+ } finally {
1733
+ finishTiming();
1734
+ }
1735
+ };
1736
+ }
1737
+ async function finishLocalHost(params, agentId, host) {
1738
+ try {
1739
+ for (;;) {
1740
+ const step = await host.page.next();
1741
+ params.signal?.throwIfAborted();
1742
+ if (step.done) return await projectLocalHost(params, agentId, host.source, step.page);
1743
+ }
1744
+ } catch (error) {
1745
+ return hostFailure(host.source, error);
1746
+ } finally {
1747
+ host.page.close();
1748
+ }
1749
+ }
1750
+ function createNodePublicationTracker(publications, waitUntil) {
1751
+ const settled = () => {
1752
+ publications.pending--;
1753
+ };
1754
+ return (completion) => {
1755
+ publications.pending++;
1756
+ completion.then(settled, settled);
1757
+ waitUntil?.(completion);
1758
+ };
1759
+ }
1760
+ /** Holds only one logical filled list; no native producer is suspended between next calls. */
1761
+ var CodexCatalogListDriver = class {
1762
+ constructor(params) {
1763
+ this.locals = [];
1764
+ this.nodeActive = false;
1765
+ this.nodeResults = [];
1766
+ this.nodeDiscoveryFailed = false;
1767
+ this.nodePublications = { pending: 0 };
1768
+ this.nodesStarted = false;
1769
+ this.localFailed = false;
1770
+ this.active = 0;
1771
+ this.running = false;
1772
+ this.complete = false;
1773
+ this.params = params;
1774
+ this.nodeSnapshots = params.nodeSnapshots ?? new CodexCatalogNodeSnapshots();
1775
+ this.nodeGeneration = this.nodeSnapshots.start(params.config);
1776
+ }
1777
+ request() {
1778
+ if (!this.params) throw new Error("Codex catalog list operation is closed");
1779
+ return this.params;
1780
+ }
1781
+ selection() {
1782
+ if (!this.prepared) throw new Error("Codex catalog list operation is not initialized");
1783
+ return this.prepared;
1784
+ }
1785
+ async initialize() {
1786
+ const params = this.request();
1787
+ const agentId = resolveSessionAgentIdsStrict({
1788
+ config: params.config ?? {},
1789
+ agentId: params.agentId
1790
+ }).sessionAgentId;
1791
+ const query = readGatewayParams(params.query);
1792
+ const requestedHostIds = query.hostIds ? new Set(query.hostIds) : void 0;
1793
+ const localSources = params.localHomes?.filter((source) => !requestedHostIds || requestedHostIds.has(source.hostId)) ?? (params.includeLocal !== false && (!requestedHostIds || requestedHostIds.has("gateway:local")) ? [void 0] : []);
1794
+ const diagnostics = currentCodexCatalogListDiagnostics();
1795
+ if (diagnostics) diagnostics.fields.localHostCount = localSources.length;
1796
+ const store = params.bindingStore.managedThreads;
1797
+ const started = diagnostics && store ? performance.now() : 0;
1798
+ let managed;
1799
+ try {
1800
+ managed = await store?.snapshot();
1801
+ } finally {
1802
+ if (diagnostics && !diagnostics.closed && store) diagnostics.fields.managedSnapshotMs = performance.now() - started;
1803
+ }
1804
+ params.signal?.throwIfAborted();
1805
+ const fallback = localSources.some((source) => source === void 0) ? (await params.control.homesForAgent(agentId))[0] : void 0;
1806
+ params.signal?.throwIfAborted();
1807
+ this.prepared = {
1808
+ agentId,
1809
+ query,
1810
+ requestedHostIds
1811
+ };
1812
+ if (requestedHostIds && !query.hostIds?.some((host) => host.startsWith("node:"))) this.nodeHosts = [];
1813
+ for (const source of localSources) {
1814
+ const selected = source ?? fallback;
1815
+ const excluded = selected ? managed?.get(selected.sourceHomeId) : void 0;
1816
+ const host = {
1817
+ source,
1818
+ page: new CodexCatalogVisiblePage({
1819
+ control: params.control.forRequest(agentId, selected),
1820
+ cursor: query.cursors?.[source?.hostId ?? "gateway:local"],
1821
+ limit: query.limitPerHost,
1822
+ excludedThreadIds: excluded,
1823
+ searchTerm: query.search,
1824
+ signal: params.signal,
1825
+ ...selected && store ? { onExcludedThread: managedMarker(store, selected.sourceHomeId, excluded) } : {}
1826
+ }),
1827
+ completion: createDeferred()
1828
+ };
1829
+ this.locals.push(host);
1830
+ publishSessionCatalogHost(params, host.completion.promise);
1831
+ }
1832
+ }
1833
+ canPause() {
1834
+ return !this.localFailed && this.nodeHosts !== void 0 && !this.nodeDiscoveryFailed && !this.nodeActive && this.nodePublications.pending === 0;
1835
+ }
1836
+ async readHost(host) {
1837
+ const params = this.request();
1838
+ if (params.allowPartialResults === true && params.onHost && params.waitUntil) {
1839
+ host.background = true;
1840
+ const completion = finishLocalHost(params, this.selection().agentId, host);
1841
+ completion.then(host.completion.resolve, host.completion.reject);
1842
+ host.value = await boundedHost(completion) ?? {
1843
+ hostId: host.source?.hostId ?? "gateway:local",
1844
+ label: host.source?.label ?? "Local Codex",
1845
+ kind: "gateway",
1846
+ connected: true,
1847
+ pending: true,
1848
+ sessions: []
1849
+ };
1850
+ return;
1851
+ }
1852
+ try {
1853
+ const page = await host.page.next();
1854
+ params.signal?.throwIfAborted();
1855
+ if (page.done) host.value = await projectLocalHost(params, this.selection().agentId, host.source, page.page);
1856
+ } catch (error) {
1857
+ this.localFailed = true;
1858
+ host.value = hostFailure(host.source, error);
1859
+ }
1860
+ if (host.value) host.completion.resolve(host.value);
1861
+ }
1862
+ startHost(host) {
1863
+ if (host.value || host.active || this.failure) return;
1864
+ this.active++;
1865
+ host.active = this.readHost(host).then(() => {
1866
+ host.active = void 0;
1867
+ this.active--;
1868
+ if (!host.value && (!this.canPause() || this.active > 0)) this.startHost(host);
1869
+ this.checkpoint();
1870
+ }, (error) => {
1871
+ host.active = void 0;
1872
+ this.active--;
1873
+ this.failure ??= { error };
1874
+ this.checkpoint();
1875
+ });
1876
+ }
1877
+ async readNodes() {
1878
+ const params = this.request();
1879
+ const { agentId, query, requestedHostIds } = this.selection();
1880
+ const diagnostics = currentCodexCatalogListDiagnostics();
1881
+ const started = diagnostics ? performance.now() : 0;
1882
+ if (diagnostics) diagnostics.fields.nodeRegistryCalls = 1;
1883
+ let nodes;
1884
+ let inventory;
1885
+ try {
1886
+ try {
1887
+ inventory = (await (params.listNodes?.() ?? params.runtime.nodes.list())).nodes;
1888
+ nodes = inventory.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 - this.locals.length);
1889
+ } finally {
1890
+ if (diagnostics && !diagnostics.closed) diagnostics.fields.nodeRegistryMs = performance.now() - started;
1891
+ }
1892
+ } catch (error) {
1893
+ this.nodeDiscoveryFailed = true;
1894
+ const host = {
1895
+ hostId: "node:registry",
1896
+ label: "Paired nodes",
1897
+ kind: "node",
1898
+ connected: false,
1899
+ canStartTerminal: false,
1900
+ sessions: [],
1901
+ error: catalogError("NODE_LIST_FAILED", error)
1902
+ };
1903
+ params.onHost?.(host);
1904
+ return [host];
1905
+ }
1906
+ params.signal?.throwIfAborted();
1907
+ this.nodeSnapshots.observe(this.nodeGeneration, inventory);
1908
+ const { listNodeAdoptedSessionEntries, nodeAdoptedSourceKey } = await import("./.setup/session-catalog-node-adoption-7-WEQTB1.mjs");
1909
+ const { compareNodeLabels, listPairedNode, nodeLabel } = await import("./.setup/session-catalog-node-continue-DLWBwAAO.mjs");
1910
+ params.signal?.throwIfAborted();
1911
+ const adopted = listNodeAdoptedSessionEntries({
1912
+ agentId,
1913
+ config: params.config,
1914
+ runtime: params.runtime,
1915
+ sessionEntries: params.sessionEntries
1916
+ });
1917
+ if (diagnostics && !diagnostics.closed) {
1918
+ diagnostics.fields.pairedNodeCalls = 0;
1919
+ diagnostics.fields.pairedNodeSettled = 0;
1920
+ }
1921
+ const trackPublication = createNodePublicationTracker(this.nodePublications, params.waitUntil);
1922
+ const partial = params.allowPartialResults === true && Boolean(params.onHost && params.waitUntil);
1923
+ const pendingHosts = nodes.toSorted(compareNodeLabels).map((node) => {
1924
+ const key = JSON.stringify([
1925
+ agentId,
1926
+ query.limitPerHost,
1927
+ query.search,
1928
+ query.cursors?.[`node:${node.nodeId}`],
1929
+ node.displayName,
1930
+ node.remoteIp,
1931
+ node.caps,
1932
+ node.commands,
1933
+ node.invocableCommands
1934
+ ]);
1935
+ const publication = this.nodeSnapshots.forNode(node, this.nodeGeneration, key);
1936
+ const { project, publish, publishCached, readPublished } = createNodeHostPublication(publication, adopted, nodeAdoptedSourceKey, params.onHost, params.signal, partial, trackPublication);
1937
+ const cached = partial ? publication.read() : void 0;
1938
+ let result;
1939
+ this.nodeResults.push(() => {
1940
+ const latest = partial ? publication.read() : void 0;
1941
+ if (latest) {
1942
+ publishCached(latest);
1943
+ return project(latest.host);
1944
+ }
1945
+ return !partial ? result : publication.valid() ? readPublished() ?? result : void 0;
1946
+ });
1947
+ if (cached) publishCached(cached);
1948
+ const nodeStarted = diagnostics ? performance.now() : 0;
1949
+ if (diagnostics && !diagnostics.closed) diagnostics.fields.pairedNodeCalls = (diagnostics.fields.pairedNodeCalls ?? 0) + 1;
1950
+ const completion = measureNodeHost(listPairedNode({
1951
+ agentId,
1952
+ runtime: params.runtime,
1953
+ node,
1954
+ query,
1955
+ terminalCapabilities: codexNodeTerminalCapability(node),
1956
+ waitUntil: trackPublication,
1957
+ signal: params.signal,
1958
+ onHost: publish
1959
+ }), diagnostics, nodeStarted);
1960
+ if (cached) {
1961
+ completion.catch(() => void 0);
1962
+ return Promise.resolve(project(cached.host));
1963
+ }
1964
+ return (partial ? boundedHost(completion) : completion).then((value) => {
1965
+ result = value ? project(value) : {
1966
+ hostId: `node:${node.nodeId}`,
1967
+ label: nodeLabel(node),
1968
+ kind: "node",
1969
+ nodeId: node.nodeId,
1970
+ connected: true,
1971
+ pending: true,
1972
+ ...codexNodeTerminalCapability(node),
1973
+ sessions: []
1974
+ };
1975
+ return result;
1976
+ });
1977
+ });
1978
+ try {
1979
+ return await Promise.all(pendingHosts);
1980
+ } catch (error) {
1981
+ await Promise.allSettled(pendingHosts);
1982
+ throw error;
1983
+ }
1984
+ }
1985
+ startNodes() {
1986
+ if (this.nodeHosts !== void 0 || this.nodesStarted) return;
1987
+ this.nodesStarted = true;
1988
+ this.nodeActive = true;
1989
+ this.readNodes().then((hosts) => {
1990
+ this.nodeHosts = hosts;
1991
+ this.nodeActive = false;
1992
+ this.checkpoint();
1993
+ }, (error) => {
1994
+ this.nodeActive = false;
1995
+ this.failure ??= { error };
1996
+ this.checkpoint();
1997
+ });
1998
+ }
1999
+ checkpoint() {
2000
+ if (this.active > 0 || !this.step) return;
2001
+ if (this.failure) {
2002
+ if (!this.nodeActive) this.step.reject(this.failure.error);
2003
+ } else if (this.nodeHosts && this.locals.every((host) => host.value !== void 0)) try {
2004
+ this.complete = true;
2005
+ this.step.resolve({
2006
+ done: true,
2007
+ hosts: [...this.locals.flatMap((host) => host.value ? [host.value] : []), ...this.nodeResults.length ? this.nodeResults.flatMap((read) => {
2008
+ const host = read();
2009
+ return host ? [host] : [];
2010
+ }) : this.nodeHosts]
2011
+ });
2012
+ } catch (error) {
2013
+ this.failure ??= { error };
2014
+ this.step.reject(error);
2015
+ }
2016
+ else if (this.canPause()) this.step.resolve({ done: false });
2017
+ }
2018
+ async next() {
2019
+ const params = this.request();
2020
+ if (this.running || this.complete) throw new Error("Codex catalog list operation cannot advance");
2021
+ params.signal?.throwIfAborted();
2022
+ this.running = true;
2023
+ try {
2024
+ if (!this.prepared) await this.initialize();
2025
+ this.step = createDeferred();
2026
+ for (const host of this.locals) this.startHost(host);
2027
+ this.startNodes();
2028
+ this.checkpoint();
2029
+ return await this.step.promise;
2030
+ } finally {
2031
+ this.running = false;
2032
+ this.step = void 0;
2033
+ }
2034
+ }
2035
+ close() {
2036
+ if (!this.params) return;
2037
+ if (this.running) throw new Error("Cannot close an active Codex catalog list step");
2038
+ const reason = this.failure?.error ?? this.params.signal?.reason ?? /* @__PURE__ */ new Error("Codex catalog list operation closed");
2039
+ this.params = void 0;
2040
+ for (const host of this.locals) {
2041
+ if (!host.background) host.page.close();
2042
+ if (!host.value) host.completion.reject(reason);
2043
+ }
2044
+ this.locals = [];
2045
+ this.prepared = void 0;
2046
+ this.nodeHosts = void 0;
2047
+ this.nodeResults = [];
2048
+ this.failure = void 0;
2049
+ }
2050
+ };
2051
+ function createCodexSessionCatalogListOperation(params) {
2052
+ const driver = new CodexCatalogListDriver(params);
2053
+ return {
2054
+ next: () => driver.next(),
2055
+ close: () => driver.close()
2056
+ };
2057
+ }
2058
+ async function runCatalogListInline(operation) {
2059
+ try {
2060
+ for (;;) {
2061
+ const step = await operation.next();
2062
+ if (step.done) return step.hosts;
2063
+ }
2064
+ } finally {
2065
+ operation.close();
2066
+ }
2067
+ }
2068
+ //#endregion
2069
+ //#region extensions/codex/src/app-server/thread-history-page.ts
2070
+ const TURN_ITEM_CURSOR_PREFIX = "turn-item:";
2071
+ function encodeTurnItemCursor(turnCursor, itemId) {
2072
+ return TURN_ITEM_CURSOR_PREFIX + Buffer.from(JSON.stringify([turnCursor, itemId])).toString("base64url");
2073
+ }
2074
+ function decodeTurnItemCursor(cursor) {
2075
+ if (!cursor?.startsWith(TURN_ITEM_CURSOR_PREFIX)) return { turnCursor: cursor };
2076
+ let value;
2077
+ try {
2078
+ value = JSON.parse(Buffer.from(cursor.slice(10), "base64url").toString());
2079
+ } catch {
2080
+ throw new CatalogParamsError("invalid Codex transcript item cursor");
2081
+ }
2082
+ 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");
2083
+ return {
2084
+ turnCursor: value[0],
2085
+ itemId: value[1]
2086
+ };
2087
+ }
2088
+ /** Legacy stores expose only turn cursors; an item identity preserves paging across appends. */
2089
+ async function readLegacyCodexHistoryPage(readTurns, request, projection) {
2090
+ const { turnCursor, itemId } = decodeTurnItemCursor(request.cursor);
2091
+ const page = parseTranscriptPage(await readTurns({
2092
+ threadId: request.threadId,
2093
+ limit: 1,
2094
+ sortDirection: "desc",
2095
+ itemsView: "full",
2096
+ ...turnCursor ? { cursor: turnCursor } : {}
2097
+ }));
2098
+ const source = page.data.flatMap(({ items, ...turn }) => items.toReversed().map((item) => ({
2099
+ turnId: turn.id,
2100
+ item,
2101
+ turn
2102
+ })));
2103
+ const anchorIndex = itemId ? source.findIndex(({ item }) => item.id === itemId) : -1;
2104
+ if (itemId && anchorIndex < 0) throw new CatalogParamsError("Codex transcript changed; refresh the session before loading older items");
2105
+ const remaining = source.slice(anchorIndex + 1);
2106
+ const items = projection.project(remaining.slice(0, request.limit), request.limit);
2107
+ const result = () => {
2108
+ const lastSource = remaining[items.length - 1];
2109
+ const partial = lastSource !== void 0 && items.length < remaining.length;
2110
+ const nativeCursor = partial ? page.backwardsCursor : page.nextCursor;
2111
+ const cursor = nativeCursor ? partial ? encodeTurnItemCursor(nativeCursor, lastSource.item.id) : nativeCursor : void 0;
2112
+ if (partial && !cursor) throw new Error("Codex app-server did not provide a transcript continuation anchor");
2113
+ return {
2114
+ items,
2115
+ ...cursor ? { nextCursor: cursor } : {}
2116
+ };
2117
+ };
2118
+ let bounded = result();
2119
+ while (!projection.fits(bounded)) {
2120
+ if (items.length <= 1) throw new Error("Codex transcript item exceeds the safe response size");
2121
+ items.pop();
2122
+ bounded = result();
2123
+ }
2124
+ return bounded;
2125
+ }
2126
+ /** Callers authorize the thread; this reader owns native cursor and response-size semantics. */
2127
+ async function readCodexThreadHistoryPage(control, thread, request, projection) {
2128
+ if (thread.historyMode !== "paginated") return readLegacyCodexHistoryPage((params) => control.listTurnPage(params), request, projection);
2129
+ let limit = request.limit;
2130
+ for (;;) {
2131
+ const page = await control.listItemPage({
2132
+ threadId: request.threadId,
2133
+ limit,
2134
+ sortDirection: "desc",
2135
+ ...request.cursor ? { cursor: request.cursor } : {}
2136
+ });
2137
+ const nextCursor = readControlCursor(page.nextCursor, "transcript next response");
2138
+ const items = projection.project(page.data, limit);
2139
+ const result = {
2140
+ items,
2141
+ ...nextCursor ? { nextCursor } : {}
2142
+ };
2143
+ const fittingCount = items.length - (projection.fits(result) ? 0 : 1);
2144
+ if (fittingCount === page.data.length) return result;
2145
+ if (fittingCount < 1) throw new Error("Codex transcript item exceeds the safe response size");
2146
+ limit = fittingCount;
2147
+ }
2148
+ }
2149
+ //#endregion
2150
+ //#region extensions/codex/src/session-catalog-transcript-item.ts
2151
+ const CODEX_MESSAGE_TYPES = /* @__PURE__ */ new Map([
2152
+ ["userMessage", "userMessage"],
2153
+ ["agentMessage", "agentMessage"],
2154
+ ["reasoning", "reasoning"]
2155
+ ]);
2156
+ const CODEX_TOOL_TYPES = /* @__PURE__ */ new Set([
2157
+ "commandExecution",
2158
+ "fileChange",
2159
+ "mcpToolCall",
2160
+ "dynamicToolCall",
2161
+ "collabAgentToolCall",
2162
+ "webSearch",
2163
+ "imageView",
2164
+ "imageGeneration"
2165
+ ]);
2166
+ function toGenericTranscriptItem(item) {
2167
+ let type = CODEX_MESSAGE_TYPES.get(item.type);
2168
+ if (!type && CODEX_TOOL_TYPES.has(item.type)) type = item.result !== void 0 || Boolean(item.aggregatedOutput) ? "toolResult" : "toolCall";
2169
+ type ??= "other";
2170
+ const fallback = item.title ?? item.name ?? item.tool ?? item.command ?? item.query ?? void 0;
2171
+ const resultText = item.aggregatedOutput || (item.result === void 0 ? void 0 : JSON.stringify(item.result, null, 2));
2172
+ const changesText = Array.isArray(item.changes) ? item.changes.map((change) => `${change.kind}: ${change.path}`).join("\n") || void 0 : void 0;
2173
+ const text = item.type === "userMessage" ? projectCodexUserItemText(item) : item.text || resultText || changesText || fallback;
2174
+ return {
2175
+ id: item.id,
2176
+ type,
2177
+ ...text ? { text } : {},
2178
+ raw: item
2179
+ };
2180
+ }
2181
+ //#endregion
2182
+ //#region extensions/codex/src/session-catalog-transcript.ts
2183
+ const transcriptPageSchema = z.strictObject({
2184
+ items: z.array(z.strictObject({
2185
+ id: z.string(),
2186
+ type: z.enum([
2187
+ "userMessage",
2188
+ "agentMessage",
2189
+ "reasoning",
2190
+ "toolCall",
2191
+ "toolResult",
2192
+ "other"
2193
+ ]),
2194
+ text: z.string().optional(),
2195
+ raw: z.record(z.string(), z.json()).optional(),
2196
+ truncated: z.boolean().optional()
2197
+ })),
2198
+ nextCursor: z.string().optional()
2199
+ });
2200
+ function parseCodexCatalogTranscriptPage(value) {
2201
+ return transcriptPageSchema.parse(value);
2202
+ }
2203
+ function projectTranscriptPage(entries, limit) {
2204
+ const projected = entries.map(({ item }) => toGenericTranscriptItem(item));
2205
+ const page = sessionCatalogPaging.boundTranscriptPage(projected.toReversed(), limit, 0).items;
2206
+ for (const [index, item] of page.entries()) if (item.text !== projected[index]?.text && projected[index]?.text) item.truncated = true;
2207
+ return page;
2208
+ }
2209
+ function pageFitsNodeTransport(page) {
2210
+ return Buffer.byteLength(JSON.stringify({ payloadJSON: JSON.stringify(page) }), "utf8") <= MAX_TRANSCRIPT_PAGE_BYTES;
2211
+ }
2212
+ /** The legacy API can anchor a turn, but cannot continue within that turn. */
2213
+ async function readLegacyCodexTranscriptPage(readTurns, request) {
2214
+ return readLegacyCodexHistoryPage(readTurns, request, {
2215
+ project: projectTranscriptPage,
2216
+ fits: pageFitsNodeTransport
2217
+ });
2218
+ }
2219
+ /** Uses the native store's item cursor whenever that store supports item history. */
2220
+ async function readCodexCatalogTranscriptPage(control, request) {
2221
+ return readCodexThreadHistoryPage(control, await control.requireEligibleThread(request.threadId), request, {
2222
+ project: projectTranscriptPage,
2223
+ fits: pageFitsNodeTransport
2224
+ });
2225
+ }
2226
+ //#endregion
2227
+ //#region extensions/codex/src/session-catalog-listing.ts
2228
+ /** Builds the node-local read-only Codex app-server catalog command. */
2229
+ function createCodexSessionCatalogNodeHostCommands(controlFactory, bindingStore) {
2230
+ const bindRequest = async (paramsJSON) => {
2231
+ const parsed = parseJsonParams(paramsJSON);
2232
+ if (!isRecord(parsed)) throw new CatalogParamsError("Codex session catalog parameters must be an object");
2233
+ const agentId = readBoundedOptionalString(parsed, "agentId", 256);
2234
+ const sourceHomeId = readBoundedOptionalString(parsed, "sourceHomeId", 256);
2235
+ const source = await controlFactory.forNode(agentId);
2236
+ if (sourceHomeId && sourceHomeId !== source.sourceHomeId) throw new CatalogParamsError("Codex catalog source home changed. Reopen the session from the catalog.");
2237
+ const request = { ...parsed };
2238
+ delete request.agentId;
2239
+ delete request.sourceHomeId;
2240
+ return {
2241
+ ...source,
2242
+ params: request,
2243
+ paramsJSON: JSON.stringify(request)
2244
+ };
2245
+ };
2246
+ const transcriptCommand = (command, read) => ({
2247
+ command,
2248
+ cap: CODEX_APP_SERVER_THREADS_CAPABILITY,
2249
+ dangerous: false,
2250
+ hasActiveWork: controlFactory.hasActiveWork,
2251
+ onDisconnect: controlFactory.disconnect,
2252
+ handle: async (paramsJSON) => {
2253
+ const request = await bindRequest(paramsJSON);
2254
+ const action = readNodeTranscriptParams(request.params);
2255
+ try {
2256
+ return JSON.stringify(await read(request.control, action));
2257
+ } catch (error) {
2258
+ if (error instanceof CatalogParamsError) throw error;
2259
+ throw new Error("Codex app-server transcript is unavailable", { cause: error });
2260
+ }
2261
+ }
2262
+ });
2263
+ const commands = [
2264
+ {
2265
+ command: CODEX_APP_SERVER_THREADS_LIST_COMMAND,
2266
+ cap: CODEX_APP_SERVER_THREADS_CAPABILITY,
2267
+ dangerous: false,
2268
+ hasActiveWork: controlFactory.hasActiveWork,
2269
+ onDisconnect: controlFactory.disconnect,
2270
+ handle: async (paramsJSON) => {
2271
+ const request = await bindRequest(paramsJSON);
2272
+ const pageParams = readPageParams(request.params);
2273
+ try {
2274
+ const managedThreads = await bindingStore?.managedThreads?.snapshot();
2275
+ const sourceHomeId = request.sourceHomeId;
2276
+ const managedThreadIds = sourceHomeId ? managedThreads?.get(sourceHomeId) : void 0;
2277
+ const page = await listVisiblePage({
2278
+ control: request.control,
2279
+ cursor: pageParams.cursor,
2280
+ cwd: pageParams.cwd,
2281
+ excludedThreadIds: managedThreadIds,
2282
+ limit: pageParams.limit,
2283
+ ...sourceHomeId && bindingStore?.managedThreads ? { onExcludedThread: async ({ threadId, rolloutPath }) => {
2284
+ if (!managedThreadIds?.has(threadId)) await bindingStore.managedThreads?.mark({
2285
+ sourceHomeId,
2286
+ threadId,
2287
+ ...rolloutPath ? { rolloutPath } : {}
2288
+ });
2289
+ } } : {},
2290
+ searchTerm: pageParams.searchTerm
2291
+ });
2292
+ return JSON.stringify({
2293
+ ...page,
2294
+ sourceHomeId: request.sourceHomeId,
2295
+ canContinueCodex: request.transport === "stdio"
2296
+ });
2297
+ } catch {
2298
+ throw new Error("Codex app-server catalog is unavailable");
2299
+ }
2300
+ }
2301
+ },
2302
+ transcriptCommand(CODEX_APP_SERVER_THREAD_TURNS_LIST_COMMAND, async (control, action) => {
2303
+ await control.requireEligibleThread(action.threadId);
2304
+ return parseTranscriptPage(await control.listTurnPage({
2305
+ threadId: action.threadId,
2306
+ limit: action.limit,
2307
+ sortDirection: "desc",
2308
+ itemsView: "full",
2309
+ ...action.cursor ? { cursor: action.cursor } : {}
2310
+ }));
2311
+ }),
2312
+ transcriptCommand(CODEX_CATALOG_TRANSCRIPT_READ_COMMAND, readCodexCatalogTranscriptPage),
2313
+ createCodexTerminalNodeHostCommand(bindRequest),
2314
+ createCodexTerminalStartNodeHostCommand()
2315
+ ];
2316
+ return process.env.OPENCLAW_NODE_EXEC_HOST?.trim().toLowerCase() === "app" ? commands.filter(({ command }) => command !== CODEX_CATALOG_TRANSCRIPT_READ_COMMAND) : commands;
2317
+ }
2318
+ function readNodeTranscriptParams(value) {
2319
+ requireOnlyKeys(value, /* @__PURE__ */ new Set([
2320
+ "threadId",
2321
+ "cursor",
2322
+ "limit"
2323
+ ]));
2324
+ const threadId = readBoundedOptionalString(value, "threadId", 256);
2325
+ if (!threadId) throw new CatalogParamsError("threadId is required");
2326
+ const cursor = readBoundedOptionalString(value, "cursor", MAX_CURSOR_LENGTH);
2327
+ return {
2328
+ threadId,
2329
+ limit: normalizeLimit(value.limit, "limit", 20, 50),
2330
+ ...cursor ? { cursor } : {}
2331
+ };
2332
+ }
2333
+ /** Reads the persisted transcript for a Gateway-local or paired-node Codex session. */
2334
+ async function readCodexSessionTranscript(params) {
2335
+ const cursor = readControlCursor(params.cursor, "transcript request");
2336
+ const limit = normalizeLimit(params.limit, "limit", 20, 50);
2337
+ if (params.source || params.hostId === "gateway:local") {
2338
+ const page = await readCodexCatalogTranscriptPage(params.control, {
2339
+ threadId: params.threadId,
2340
+ limit,
2341
+ cursor
2342
+ });
2343
+ return {
2344
+ hostId: params.hostId,
2345
+ label: params.source?.label ?? "Local Codex",
2346
+ threadId: params.threadId,
2347
+ ...page
2348
+ };
2349
+ }
2350
+ const nodeId = params.hostId.slice(5);
2351
+ 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"));
2352
+ if (!node) throw new CatalogParamsError("paired-node Codex session host is offline or unavailable");
2353
+ const invoke = async (command, request) => unwrapNodeInvokePayload(await params.runtime.nodes.invoke({
2354
+ nodeId,
2355
+ command,
2356
+ params: {
2357
+ agentId: params.agentId,
2358
+ threadId: params.threadId,
2359
+ ...params.sourceHomeId ? { sourceHomeId: params.sourceHomeId } : {},
2360
+ ...request
2361
+ },
2362
+ timeoutMs: NODE_INVOKE_TIMEOUT_MS,
2363
+ scopes: ["operator.write"]
2364
+ }));
2365
+ const page = node.commands?.includes("codex.sessionCatalog.transcript.read.v1") ? parseCodexCatalogTranscriptPage(await invoke(CODEX_CATALOG_TRANSCRIPT_READ_COMMAND, {
2366
+ cursor,
2367
+ limit
2368
+ })) : await readLegacyCodexTranscriptPage(async ({ cursor: turnCursor, limit: turnLimit }) => parseTranscriptPage(await invoke(CODEX_APP_SERVER_THREAD_TURNS_LIST_COMMAND, {
2369
+ cursor: turnCursor,
2370
+ limit: turnLimit
2371
+ })), {
2372
+ threadId: params.threadId,
2373
+ cursor,
2374
+ limit
2375
+ });
2376
+ const { nodeLabel } = await import("./.setup/session-catalog-node-continue-DLWBwAAO.mjs");
2377
+ return {
2378
+ hostId: params.hostId,
2379
+ label: nodeLabel(node),
2380
+ threadId: params.threadId,
2381
+ ...page
2382
+ };
2383
+ }
2384
+ //#endregion
2385
+ //#region extensions/codex/src/session-upstream-activity.ts
2386
+ const CODEX_UPSTREAM_TURN_LIMIT = 100;
2387
+ function readMarker(probe) {
2388
+ if (!isRecord(probe.marker)) return;
2389
+ const turnId = probe.marker.turnId;
2390
+ if (turnId !== null && typeof turnId !== "string") return;
2391
+ const count = probe.marker.userMessageCount;
2392
+ if (count !== void 0 && (typeof count !== "number" || !Number.isSafeInteger(count) || count < 0)) return;
2393
+ return {
2394
+ turnId,
2395
+ ...count === void 0 ? {} : { userMessageCount: count }
2396
+ };
2397
+ }
2398
+ function upstreamConnectionFingerprint(probe) {
2399
+ return isRecord(probe.upstreamRef) && typeof probe.upstreamRef.connectionFingerprint === "string" ? probe.upstreamRef.connectionFingerprint : void 0;
2400
+ }
2401
+ function classifyCodexUpstreamTurns(params) {
2402
+ const marker = readMarker(params.probe);
2403
+ if (!marker) return;
2404
+ const newest = params.turns[0];
2405
+ if (!newest?.id) return;
2406
+ const markerIndex = marker.turnId === null ? -1 : params.turns.findIndex((turn) => turn.id === marker.turnId);
2407
+ const candidateTurns = markerIndex < 0 ? params.turns : params.turns.slice(0, markerIndex + 1);
2408
+ const newestUserMessageCount = newest.items.filter((item) => item.type === "userMessage").length;
2409
+ if (!(marker.turnId !== newest.id || marker.userMessageCount === void 0 || newestUserMessageCount > marker.userMessageCount)) return;
2410
+ const ownTexts = new Set(params.probe.ownRecentUserTexts);
2411
+ let humanTurns = 0;
2412
+ let occurredAt;
2413
+ for (const turn of candidateTurns) {
2414
+ const userMessages = turn.items.filter((item) => item.type === "userMessage");
2415
+ const alreadySeen = turn.id === marker.turnId ? marker.userMessageCount ?? userMessages.length : 0;
2416
+ for (const item of userMessages.slice(alreadySeen)) {
2417
+ const texts = normalizeUserMessageTexts(item);
2418
+ if (ownTexts.has(texts.join(" ")) || texts.length > 1 && texts.every((text) => ownTexts.has(text))) continue;
2419
+ humanTurns += 1;
2420
+ if (occurredAt === void 0) {
2421
+ const timestampSeconds = turn.completedAt ?? turn.startedAt;
2422
+ occurredAt = typeof timestampSeconds === "number" && Number.isFinite(timestampSeconds) ? timestampSeconds * 1e3 : params.now ?? Date.now();
2423
+ }
2424
+ }
2425
+ }
2426
+ const activityId = `${newest.id}:${newestUserMessageCount}`;
2427
+ return {
2428
+ kind: "activity",
2429
+ sessionKey: params.probe.sessionKey,
2430
+ humanTurns,
2431
+ nextMarker: {
2432
+ turnId: newest.id,
2433
+ userMessageCount: newestUserMessageCount
2434
+ },
2435
+ ...humanTurns > 0 ? {
2436
+ occurredAt: occurredAt ?? params.now ?? Date.now(),
2437
+ dedupeId: activityId
2438
+ } : {}
2439
+ };
2440
+ }
2441
+ function normalizeUserMessageTexts(item) {
2442
+ const typed = item;
2443
+ const contentTexts = typed.content?.filter((input) => input.type === "text").map((input) => input.text.trim().replace(/\s+/g, " ")).filter(Boolean);
2444
+ return contentTexts?.length ? contentTexts : [(typed.text ?? "").trim().replace(/\s+/g, " ")];
2445
+ }
2446
+ async function checkCodexUpstreamActivity(probes, control, resolveThreadId = (probe) => probe.threadId) {
2447
+ return await control.withPinnedConnection(async (pinned) => {
2448
+ const activities = [];
2449
+ for (const probe of probes) {
2450
+ const fingerprint = upstreamConnectionFingerprint(probe);
2451
+ if (probe.upstreamKind !== "codex-app-server" || !fingerprint || fingerprint !== pinned.connectionFingerprint) continue;
2452
+ try {
2453
+ const threadId = resolveThreadId(probe);
2454
+ const page = await pinned.listTurnPage({
2455
+ threadId,
2456
+ limit: CODEX_UPSTREAM_TURN_LIMIT,
2457
+ sortDirection: "desc",
2458
+ itemsView: "full"
2459
+ }).catch((error) => {
2460
+ if (error instanceof CodexAppServerRpcError && error.code === -32600) return;
2461
+ throw error;
2462
+ });
2463
+ if (!page?.data.length && readMarker(probe)) {
2464
+ try {
2465
+ await pinned.readThread(threadId, false);
2466
+ } catch (error) {
2467
+ if (isCodexThreadReadMissingError(error, threadId)) activities.push({
2468
+ kind: "missing",
2469
+ sessionKey: probe.sessionKey
2470
+ });
2471
+ }
2472
+ continue;
2473
+ }
2474
+ const activity = page && classifyCodexUpstreamTurns({
2475
+ probe,
2476
+ turns: page.data
2477
+ });
2478
+ if (activity) activities.push(activity);
2479
+ } catch {}
2480
+ }
2481
+ return activities;
2482
+ });
2483
+ }
2484
+ function createChecker(params) {
2485
+ const resolveThreadId = (probe) => {
2486
+ const config = params.getRuntimeConfig();
2487
+ const sessionId = params.api.runtime.agent.session.getSessionEntry({
2488
+ agentId: probe.agentId,
2489
+ sessionKey: probe.sessionKey,
2490
+ readConsistency: "latest"
2491
+ })?.sessionId?.trim();
2492
+ if (!sessionId) return probe.threadId;
2493
+ const binding = params.bindingStore.read(sessionBindingIdentity({
2494
+ sessionId,
2495
+ sessionKey: probe.sessionKey,
2496
+ config
2497
+ }));
2498
+ return binding?.connectionScope === "supervision" && binding.supervisionSourceThreadId === probe.threadId ? binding.threadId : probe.threadId;
2499
+ };
2500
+ return async (probes) => {
2501
+ const groups = /* @__PURE__ */ new Map();
2502
+ for (const probe of probes) {
2503
+ const fingerprint = upstreamConnectionFingerprint(probe);
2504
+ if (!fingerprint) continue;
2505
+ const control = await params.control.forUpstream(probe.agentId, fingerprint);
2506
+ if (!control) continue;
2507
+ const key = `${probe.agentId}\0${fingerprint}`;
2508
+ const group = groups.get(key) ?? {
2509
+ control,
2510
+ probes: []
2511
+ };
2512
+ group.probes.push(probe);
2513
+ groups.set(key, group);
2514
+ }
2515
+ return (await Promise.all([...groups.values()].map((group) => checkCodexUpstreamActivity(group.probes, group.control, resolveThreadId)))).flat();
2516
+ };
2517
+ }
2518
+ //#endregion
2519
+ //#region extensions/codex/src/session-catalog-eligibility.ts
2520
+ /** Exact identity and native membership are independent of resident retention. */
2521
+ async function requireEligibleCodexThread(params) {
2522
+ const { requests, threadId } = params;
2523
+ const deadline = params.now() + requests.requestTimeoutMs;
2524
+ 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.");
2525
+ const remaining = () => {
2526
+ const timeoutMs = Math.ceil(deadline - params.now());
2527
+ if (timeoutMs <= 0) throw unverified();
2528
+ return timeoutMs;
2529
+ };
2530
+ const verify = async () => {
2531
+ if (params.sourceHomeId && await params.managedThreads?.has(params.sourceHomeId, threadId)) throw unverified();
2532
+ remaining();
2533
+ const index = await requests.index();
2534
+ const root = params.localSessionsRoot;
2535
+ if (root && index.get(threadId)?.archived) throw unverified();
2536
+ const thread = await requests.readThread(threadId, false, remaining());
2537
+ remaining();
2538
+ if (thread.id !== threadId || thread.ephemeral === true || !isInteractiveThreadSource(thread.source)) throw unverified();
2539
+ if (!root) {
2540
+ const { CODEX_CATALOG_NATIVE_PAGE_LIMIT } = await import("./.setup/session-catalog-native-projection-CTBd4EUm.mjs").then((n) => n.a);
2541
+ const { CODEX_CATALOG_MAX_ROWS } = await import("./.setup/session-catalog-limits-DEU36Qlo.mjs").then((n) => n.r);
2542
+ let cursor;
2543
+ const seenCursors = /* @__PURE__ */ new Set();
2544
+ for (;;) {
2545
+ const page = await requests.listThreads({
2546
+ archived: false,
2547
+ limit: CODEX_CATALOG_NATIVE_PAGE_LIMIT,
2548
+ modelProviders: [],
2549
+ sortKey: "recency_at",
2550
+ sortDirection: "desc",
2551
+ ...thread.cwd ? { cwd: thread.cwd } : {},
2552
+ ...cursor ? { cursor } : {}
2553
+ }, remaining());
2554
+ remaining();
2555
+ const listed = page.data.find((entry) => entry.id === threadId);
2556
+ if (listed) {
2557
+ if (listed.ephemeral === true || !isInteractiveThreadSource(listed.source)) throw unverified();
2558
+ break;
2559
+ }
2560
+ const nextCursor = readControlCursor(page.nextCursor, "next response");
2561
+ if (!nextCursor || seenCursors.has(nextCursor)) throw unverified();
2562
+ seenCursors.add(nextCursor);
2563
+ if (seenCursors.size > CODEX_CATALOG_MAX_ROWS) {
2564
+ const oldest = seenCursors.values().next().value;
2565
+ if (oldest !== void 0) seenCursors.delete(oldest);
2566
+ }
2567
+ cursor = nextCursor;
2568
+ }
2569
+ }
2570
+ if (root) {
2571
+ if (!thread.path) throw unverified();
2572
+ const metadata = await readCodexSessionMeta(root, thread.path, threadId);
2573
+ remaining();
2574
+ if (!metadata || !isInteractiveThreadSource(metadata.source) || metadata.originator === "openclaw") throw unverified();
2575
+ await index.upsertThread(thread);
2576
+ remaining();
2577
+ }
2578
+ return thread;
2579
+ };
2580
+ return await withTimeout$1(verify(), requests.requestTimeoutMs, "Codex session eligibility could not be verified", unverified);
2581
+ }
2582
+ //#endregion
2583
+ //#region extensions/codex/src/session-catalog-control-requests.ts
2584
+ function createCodexCatalogRequestSnapshot(requestTimeoutMs, request, index, beginList, catalogRead = false) {
2585
+ const read = (method, params, timeoutMs, observation) => {
2586
+ const scope = catalogRead ? void 0 : currentCodexCatalogListRequest();
2587
+ if (!scope) return request(method, params, timeoutMs, void 0, observation);
2588
+ return scope.read(timeoutMs ?? requestTimeoutMs, async (remaining) => {
2589
+ const attempt = beginList(scope);
2590
+ if (!attempt.allowed) throw attempt.error;
2591
+ return await request(method, params, remaining, void 0, observation);
2592
+ });
2593
+ };
2594
+ return {
2595
+ index,
2596
+ beginList,
2597
+ get requestTimeoutMs() {
2598
+ return catalogRead ? requestTimeoutMs : currentCodexCatalogListRequest()?.remaining(requestTimeoutMs) ?? requestTimeoutMs;
2599
+ },
2600
+ listThreads: (params, timeoutMs, observation) => read(CODEX_CONTROL_METHODS.listThreads, params, timeoutMs, observation),
2601
+ listThreadTurns: (params) => read(CODEX_CONTROL_METHODS.listThreadTurns, params),
2602
+ listThreadItems: (params) => read(CODEX_CONTROL_METHODS.listThreadItems, params),
2603
+ forkThread: (params, assertCurrent) => request(CODEX_CONTROL_METHODS.forkThread, assertCodexThreadForkParams(params), void 0, assertCurrent),
2604
+ readThread: async (threadId, includeTurns, timeoutMs) => (await read(CODEX_CONTROL_METHODS.readThread, {
2605
+ threadId,
2606
+ includeTurns
2607
+ }, timeoutMs)).thread,
2608
+ archiveThread: async (threadId, assertCurrent) => {
2609
+ await request(CODEX_CONTROL_METHODS.archiveThread, { threadId }, void 0, assertCurrent);
2610
+ }
2611
+ };
2612
+ }
2613
+ function createCodexSessionCatalogControlFromRequests(params) {
2614
+ return {
2615
+ forkContext: params.forkContext,
2616
+ ...params.clientId ? { clientId: params.clientId } : {},
2617
+ ...params.connectionFingerprint ? { connectionFingerprint: params.connectionFingerprint } : {},
2618
+ withPinnedConnection: params.withPinnedConnection,
2619
+ async initialize() {
2620
+ await (await params.createRequestSnapshot().index()).initialize();
2621
+ },
2622
+ requireEligibleThread: (threadId) => requireEligibleCodexThread({
2623
+ threadId,
2624
+ requests: params.createRequestSnapshot(),
2625
+ localSessionsRoot: params.localSessionsRoot,
2626
+ sourceHomeId: params.sourceHomeId,
2627
+ managedThreads: params.managedThreads,
2628
+ now: params.now
2629
+ }),
2630
+ retireConnection: params.retireConnection,
2631
+ async listPage(pageParams) {
2632
+ readControlCursor(pageParams.cursor, "request");
2633
+ const query = readPageParams(pageParams);
2634
+ return await withCodexCatalogListRequest(async (request) => {
2635
+ const requests = params.createRequestSnapshot();
2636
+ const timeoutMs = Math.min(requests.requestTimeoutMs, 5e3);
2637
+ const deadline = request.constrainDeadline(performance.now() + timeoutMs);
2638
+ return await (await withTimeout$1(requests.index(), request.remaining(timeoutMs), "Codex session catalog is still loading", () => new CodexCatalogLoadingError())).list(query, deadline);
2639
+ });
2640
+ },
2641
+ async listDescendantPage(listParams) {
2642
+ const requests = params.createRequestSnapshot();
2643
+ return await requests.listThreads(listParams, requests.requestTimeoutMs);
2644
+ },
2645
+ async readThread(threadId, includeTurns = false) {
2646
+ return await params.createRequestSnapshot().readThread(threadId, includeTurns);
2647
+ },
2648
+ async listTurnPage(listParams) {
2649
+ return await params.createRequestSnapshot().listThreadTurns(listParams);
2650
+ },
2651
+ listItemPage: (listParams) => params.createRequestSnapshot().listThreadItems(listParams),
2652
+ async forkThread(forkParams, assertCurrent) {
2653
+ const requests = params.createRequestSnapshot();
2654
+ const index = forkParams.ephemeral === true ? void 0 : await requests.index();
2655
+ const response = await requests.forkThread(forkParams, assertCurrent);
2656
+ if (index && !index.get(response.thread.id)) await index.upsertThread(response.thread);
2657
+ return response;
2658
+ },
2659
+ async archiveThread(threadId, assertCurrent) {
2660
+ const requests = params.createRequestSnapshot();
2661
+ const index = await requests.index();
2662
+ await requests.archiveThread(threadId, assertCurrent);
2663
+ index.archive(threadId);
2664
+ }
2665
+ };
2666
+ }
2667
+ //#endregion
2668
+ //#region extensions/codex/src/session-catalog-homes.ts
2669
+ /** Discovers path facts on demand; runtime projections belong only to their requesting owner. */
2670
+ function createCodexCatalogHomeResolver(params) {
2671
+ const env = params.env ?? process.env;
2672
+ const generations = /* @__PURE__ */ new WeakMap();
2673
+ let lastConfig = params.config;
2674
+ const currentConfig = () => lastConfig = params.getRuntimeConfig() ?? lastConfig;
2675
+ const generation = () => {
2676
+ const config = currentConfig();
2677
+ let current = generations.get(config);
2678
+ if (!current) {
2679
+ current = {
2680
+ config,
2681
+ assertCurrent: () => {
2682
+ if (currentConfig() !== config) throw new CatalogParamsError("Codex session catalog configuration changed; retry the request");
2683
+ },
2684
+ pluginConfig: params.getPluginConfig(),
2685
+ agentDirs: /* @__PURE__ */ new Map(),
2686
+ paths: /* @__PURE__ */ new Map(),
2687
+ directories: /* @__PURE__ */ new Set()
2688
+ };
2689
+ generations.set(config, current);
2690
+ }
2691
+ return current;
2692
+ };
2693
+ const agentIds = (snapshot) => snapshot.agentIds ??= listAgentIds(snapshot.config).toSorted((a, b) => a.localeCompare(b));
2694
+ const agentDir = (snapshot, agentId) => {
2695
+ let directory = snapshot.agentDirs.get(agentId);
2696
+ if (!directory) {
2697
+ directory = resolveAgentDir(snapshot.config, agentId, env);
2698
+ snapshot.agentDirs.set(agentId, directory);
2699
+ }
2700
+ return directory;
2701
+ };
2702
+ const homePath = async (snapshot, value) => {
2703
+ const cached = snapshot.paths.get(value);
2704
+ if (cached !== void 0) return cached;
2705
+ const resolved = path.resolve(value);
2706
+ const discovery = canonicalPathFromExistingAncestor(resolved).catch(() => resolved).then(async (canonical) => {
2707
+ if (await fs.stat(canonical).then((stat) => stat.isDirectory(), () => false)) snapshot.directories.add(value);
2708
+ snapshot.paths.set(value, canonical);
2709
+ return canonical;
2710
+ });
2711
+ snapshot.paths.set(value, discovery);
2712
+ return discovery;
2713
+ };
2714
+ const sharedCandidates = (snapshot) => snapshot.candidates ??= (async () => {
2715
+ const candidates = [];
2716
+ const seen = /* @__PURE__ */ new Set();
2717
+ const append = async (value, label) => {
2718
+ const codexHome = await homePath(snapshot, value);
2719
+ if (!snapshot.directories.has(value) || seen.has(codexHome)) return;
2720
+ seen.add(codexHome);
2721
+ candidates.push({
2722
+ codexHome,
2723
+ label: `Local Codex · ${label ?? path.basename(codexHome)}`
2724
+ });
2725
+ };
2726
+ for (const id of agentIds(snapshot)) {
2727
+ await scheduler.yield();
2728
+ const directory = await homePath(snapshot, agentDir(snapshot, id));
2729
+ await append(resolveCodexAppServerHomeDir(directory), id);
2730
+ if (candidates.length === 100) return candidates;
2731
+ }
2732
+ for (const entry of readCodexPluginConfig(snapshot.pluginConfig).sessionCatalog?.homes ?? []) {
2733
+ await scheduler.yield();
2734
+ const { path: home, label } = typeof entry === "string" ? { path: entry } : entry;
2735
+ await append(home, label);
2736
+ if (candidates.length === 100) break;
2737
+ }
2738
+ return candidates;
2739
+ })().then((candidates) => snapshot.candidates = candidates, (error) => {
2740
+ snapshot.candidates = void 0;
2741
+ throw error;
2742
+ });
2743
+ const prepareAgentHomes = async (snapshot, agentId, fleet) => {
2744
+ await scheduler.yield();
2745
+ snapshot.assertCurrent();
2746
+ if (!agentIds(snapshot).includes(agentId)) return [];
2747
+ const ownerAgentDir = await homePath(snapshot, agentDir(snapshot, agentId));
2748
+ const base = params.resolveRuntimeOptions({
2749
+ config: snapshot.config,
2750
+ pluginConfig: snapshot.pluginConfig,
2751
+ agentDir: ownerAgentDir,
2752
+ env
2753
+ });
2754
+ const processHomeConfigured = Boolean(env.CODEX_HOME?.trim());
2755
+ const candidates = [{
2756
+ codexHome: await homePath(snapshot, resolveCodexAppServerLocalHomeDir(base.start, ownerAgentDir, env)),
2757
+ label: "Local Codex",
2758
+ usesProcessHomeFallback: base.start.transport === "stdio" && base.start.homeScope === "user" && !processHomeConfigured
2759
+ }];
2760
+ if (fleet && base.start.transport === "stdio") {
2761
+ candidates.push({
2762
+ codexHome: await homePath(snapshot, resolveCodexAppServerUserHomeDir(env)),
2763
+ label: "Local Codex · user",
2764
+ usesProcessHomeFallback: !processHomeConfigured
2765
+ });
2766
+ const ownerHome = resolveCodexAppServerHomeDir(ownerAgentDir);
2767
+ const codexHome = await homePath(snapshot, ownerHome);
2768
+ if (snapshot.directories.has(ownerHome)) candidates.push({
2769
+ codexHome,
2770
+ label: `Local Codex · ${agentId}`
2771
+ });
2772
+ candidates.push(...await sharedCandidates(snapshot));
2773
+ }
2774
+ snapshot.assertCurrent();
2775
+ const homes = [];
2776
+ const seen = /* @__PURE__ */ new Set();
2777
+ for (const candidate of candidates) {
2778
+ if (seen.has(candidate.codexHome)) continue;
2779
+ seen.add(candidate.codexHome);
2780
+ const sourceHomeId = codexCatalogHomeIdFromCanonicalPath(candidate.codexHome);
2781
+ const primary = homes.length === 0;
2782
+ homes.push({
2783
+ assertCurrent: snapshot.assertCurrent,
2784
+ sourceHomeId,
2785
+ hostId: primary ? CODEX_LOCAL_SESSION_HOST_ID : `${CODEX_LOCAL_SESSION_HOST_ID}:${sourceHomeId}`,
2786
+ label: candidate.label,
2787
+ agentDir: ownerAgentDir,
2788
+ appServer: base.start.transport !== "stdio" ? base : {
2789
+ ...base,
2790
+ start: {
2791
+ ...base.start,
2792
+ codexHome: candidate.codexHome,
2793
+ ...!primary ? {
2794
+ homeScope: "user",
2795
+ env: {
2796
+ ...base.start.env,
2797
+ CODEX_HOME: candidate.codexHome
2798
+ }
2799
+ } : {}
2800
+ }
2801
+ },
2802
+ ...base.connectionClass === "remote" ? {} : { localSessionsRoot: path.join(candidate.codexHome, "sessions") },
2803
+ usesProcessHomeFallback: candidate.usesProcessHomeFallback ?? false
2804
+ });
2805
+ if (homes.length === 100) break;
2806
+ }
2807
+ return homes;
2808
+ };
2809
+ setCodexCatalogConnectionHomeResolver(async (directory) => {
2810
+ const snapshot = generation();
2811
+ for (const id of agentIds(snapshot)) {
2812
+ await scheduler.yield();
2813
+ if (agentDir(snapshot, id) === directory) return prepareAgentHomes(snapshot, id, true);
2814
+ }
2815
+ snapshot.assertCurrent();
2816
+ return [];
2817
+ });
2818
+ return {
2819
+ forAgent: (agentId) => prepareAgentHomes(generation(), agentId, true),
2820
+ async forNode(requestedAgentId) {
2821
+ const snapshot = generation();
2822
+ const configured = readCodexPluginConfig(snapshot.pluginConfig).appServer;
2823
+ if (configured?.homeScope === "agent" || configured?.transport && configured.transport !== "stdio") {
2824
+ const agentId = resolveSessionAgentIdsStrict({
2825
+ config: snapshot.config,
2826
+ agentId: requestedAgentId
2827
+ }).sessionAgentId;
2828
+ const source = (await prepareAgentHomes(snapshot, agentId, false))[0];
2829
+ if (!source) throw new CatalogParamsError(`unknown Codex session catalog agent: ${agentId}`);
2830
+ return {
2831
+ ...source,
2832
+ agentId,
2833
+ codexHome: resolveCodexAppServerLocalHomeDir(source.appServer.start, source.agentDir, env)
2834
+ };
2835
+ }
2836
+ const codexHome = await homePath(snapshot, resolveCodexAppServerUserHomeDir(env));
2837
+ snapshot.assertCurrent();
2838
+ const appServer = params.resolveRuntimeOptions({
2839
+ pluginConfig: snapshot.pluginConfig,
2840
+ config: snapshot.config,
2841
+ env
2842
+ });
2843
+ return {
2844
+ assertCurrent: snapshot.assertCurrent,
2845
+ sourceHomeId: codexCatalogHomeIdFromCanonicalPath(codexHome),
2846
+ codexHome,
2847
+ localSessionsRoot: path.join(codexHome, "sessions"),
2848
+ appServer: {
2849
+ ...appServer,
2850
+ start: {
2851
+ ...appServer.start,
2852
+ env: {
2853
+ ...appServer.start.env,
2854
+ CODEX_HOME: codexHome
2855
+ }
2856
+ }
2857
+ }
2858
+ };
2859
+ }
2860
+ };
2861
+ }
2862
+ //#endregion
2863
+ //#region extensions/codex/src/session-catalog-source-backoff.ts
2864
+ const INITIAL_BACKOFF_MS = 5e3;
2865
+ const MAX_BACKOFF_MS = 6e4;
2866
+ /** Source health is separate from query-keyed page sharing and cached page delivery. */
2867
+ var CodexCatalogSourceBackoff = class {
2868
+ constructor(now) {
2869
+ this.now = now;
2870
+ this.sourcesByConfig = /* @__PURE__ */ new WeakMap();
2871
+ }
2872
+ begin(config, agentId, sourceHomeId, scope) {
2873
+ let sources = this.sourcesByConfig.get(config);
2874
+ if (!sources) {
2875
+ sources = /* @__PURE__ */ new Map();
2876
+ this.sourcesByConfig.set(config, sources);
2877
+ }
2878
+ const key = JSON.stringify([agentId, sourceHomeId ?? null]);
2879
+ if (scope) return scope.attempt(sources, key, () => this.begin(config, agentId, sourceHomeId));
2880
+ let state = sources.get(key);
2881
+ if (!state) {
2882
+ state = {};
2883
+ sources.set(key, state);
2884
+ }
2885
+ const failure = state.failure;
2886
+ if (failure && (failure.probing || failure.retryAt > this.now())) return {
2887
+ allowed: false,
2888
+ error: failure.error
2889
+ };
2890
+ if (failure) failure.probing = true;
2891
+ return {
2892
+ allowed: true,
2893
+ resolved: () => {
2894
+ if (sources.get(key) === state) sources.set(key, {});
2895
+ },
2896
+ rejected: (error) => {
2897
+ if (sources.get(key) !== state) return;
2898
+ if (error instanceof CatalogParamsError || error instanceof Error && error.name === "AbortError" || error instanceof CodexAppServerRpcError && (error.code === -32600 || error.code === -32602)) {
2899
+ if (failure) failure.probing = false;
2900
+ return;
2901
+ }
2902
+ const delayMs = findCodexAppServerSpawnError(error) ? Infinity : failure ? Math.min(failure.delayMs * 2 || INITIAL_BACKOFF_MS, MAX_BACKOFF_MS) : 0;
2903
+ sources.set(key, { failure: {
2904
+ error,
2905
+ delayMs,
2906
+ retryAt: this.now() + delayMs,
2907
+ probing: false
2908
+ } });
2909
+ },
2910
+ abandoned: () => {
2911
+ if (sources.get(key) === state && failure) failure.probing = false;
2912
+ }
2913
+ };
2914
+ }
2915
+ };
2916
+ //#endregion
2917
+ //#region extensions/codex/src/session-catalog-control.ts
2918
+ /** Builds the passive catalog over the Codex plugin's canonical shared client. */
2919
+ function createCodexSessionCatalogControl(params) {
2920
+ const now = params.now ?? Date.now;
2921
+ const sourceBackoff = new CodexCatalogSourceBackoff(now);
2922
+ const noConfig = {};
2923
+ const resolveRuntimeOptions = (options) => {
2924
+ const runtime = params.resolveRuntimeOptions(options);
2925
+ return runtime.start.transport === "stdio" && runtime.start.commandSource === "managed" ? {
2926
+ ...runtime,
2927
+ start: {
2928
+ ...runtime.start,
2929
+ managedCommandOrder: "package-only"
2930
+ }
2931
+ } : runtime;
2932
+ };
2933
+ const homeResolver = createCodexCatalogHomeResolver({
2934
+ config: params.config ?? {},
2935
+ getRuntimeConfig: params.getRuntimeConfig,
2936
+ getPluginConfig: params.getPluginConfig,
2937
+ resolveRuntimeOptions,
2938
+ ...params.env ? { env: params.env } : {}
2939
+ });
2940
+ const requestOptionsByConfig = /* @__PURE__ */ new WeakMap();
2941
+ const indexes = /* @__PURE__ */ new Map();
2942
+ const retiringState = /* @__PURE__ */ new Map();
2943
+ const directHomes = /* @__PURE__ */ new Map();
2944
+ const residentRequests = /* @__PURE__ */ new Set();
2945
+ let generation = params.getRuntimeConfig();
2946
+ let residentEpoch = 0;
2947
+ let closed = false;
2948
+ let runBackground = (run) => run();
2949
+ let retiring;
2950
+ const retireIndexes = () => {
2951
+ residentEpoch++;
2952
+ const closing = [];
2953
+ for (const [homeId, index] of indexes) {
2954
+ const writes = index.retire().finally(() => {
2955
+ if (retiringState.get(homeId) === writes) retiringState.delete(homeId);
2956
+ });
2957
+ retiringState.set(homeId, writes);
2958
+ closing.push(writes, index.close());
2959
+ }
2960
+ indexes.clear();
2961
+ directHomes.clear();
2962
+ const drain = Promise.allSettled([retiring, ...closing]).then(() => {
2963
+ if (retiring === drain) retiring = void 0;
2964
+ });
2965
+ retiring = drain;
2966
+ return drain;
2967
+ };
2968
+ const resolveResident = async (agentId, source) => {
2969
+ if (closed) throw new Error("Codex resident catalog is closed");
2970
+ const config = params.getRuntimeConfig();
2971
+ if (generation !== config) {
2972
+ generation = config;
2973
+ retireIndexes();
2974
+ }
2975
+ const epoch = residentEpoch;
2976
+ const runtime = source?.appServer ?? resolveRuntimeOptions({ pluginConfig: params.getPluginConfig() });
2977
+ const requestOptions = resolveRequestOptions(runtime.start, agentId, source);
2978
+ const key = source?.sourceHomeId ?? agentId ?? "";
2979
+ let home = directHomes.get(key);
2980
+ if (!home) {
2981
+ home = codexCatalogResidentHomeKey({
2982
+ startOptions: requestOptions.startOptions,
2983
+ agentDir: requestOptions.agentDir,
2984
+ sourceHomeId: source?.sourceHomeId
2985
+ });
2986
+ directHomes.set(key, home);
2987
+ }
2988
+ const homeId = await home;
2989
+ await retiringState.get(homeId);
2990
+ if (closed || generation !== config || residentEpoch !== epoch) throw new Error("Codex catalog configuration changed");
2991
+ let index = indexes.get(homeId);
2992
+ if (!index) {
2993
+ const [{ CodexCatalogIndex }, { canReuseCodexCatalogPreview, projectCodexCatalogDeltaPage, projectCodexCatalogPage }] = await Promise.all([import("./.setup/session-catalog-index-DPICGlxr.mjs"), import("./.setup/session-catalog-projection-CE0_Hffi.mjs")]);
2994
+ source?.assertCurrent();
2995
+ if (closed || generation !== config || residentEpoch !== epoch) throw new Error("Codex catalog configuration changed");
2996
+ index = indexes.get(homeId);
2997
+ if (index) return index;
2998
+ const root = source?.localSessionsRoot ?? (runtime.connectionClass !== "remote" ? path.join(resolveCodexAppServerLocalHomeDir(requestOptions.startOptions, requestOptions.agentDir, params.env), "sessions") : void 0);
2999
+ let nativeAttempt;
3000
+ index = new CodexCatalogIndex({
3001
+ homeId,
3002
+ requestTimeoutMs: runtime.requestTimeoutMs,
3003
+ runBackground: (run) => runBackground(run),
3004
+ localSessionsRoot: root,
3005
+ state: params.openResidentState?.(homeId),
3006
+ runNativeWalk: async (run) => {
3007
+ try {
3008
+ const result = await run();
3009
+ if (nativeAttempt?.allowed) nativeAttempt.resolved();
3010
+ return result;
3011
+ } catch (error) {
3012
+ if (nativeAttempt?.allowed) nativeAttempt.rejected(error);
3013
+ throw error;
3014
+ } finally {
3015
+ nativeAttempt = void 0;
3016
+ }
3017
+ },
3018
+ assertCurrent: () => {
3019
+ source?.assertCurrent();
3020
+ if (closed || params.getRuntimeConfig() !== config || residentEpoch !== epoch) throw new Error("Codex catalog configuration changed");
3021
+ },
3022
+ readNative: async (query, remainingRows, foreground) => {
3023
+ const requests = createRequestSnapshot(agentId, source, true, query.useStateDbOnly ? (thread) => {
3024
+ const row = index?.get(thread.id);
3025
+ return canReuseCodexCatalogPreview(row, thread) ? row?.preview : void 0;
3026
+ } : void 0, Math.min(64, remainingRows));
3027
+ const attempt = foreground ? requests.beginList(foreground) : query.cursor && nativeAttempt ? nativeAttempt : requests.beginList();
3028
+ if (!foreground) nativeAttempt = attempt;
3029
+ if (!attempt.allowed) throw attempt.error;
3030
+ const diagnostics = startCodexCatalogPageDiagnostics("cold");
3031
+ if (diagnostics) diagnostics.fields.controlRequestCalls = 1;
3032
+ const observation = startCodexCatalogControlRequestDiagnostics(diagnostics);
3033
+ let outcome = "rejected";
3034
+ try {
3035
+ const started = performance.now();
3036
+ let response;
3037
+ try {
3038
+ response = await requests.listThreads(query, foreground?.remaining(requests.requestTimeoutMs) ?? requests.requestTimeoutMs, observation);
3039
+ } finally {
3040
+ if (diagnostics) {
3041
+ const elapsed = performance.now() - started;
3042
+ diagnostics.fields.inclusiveControlRequestWaitMs = elapsed;
3043
+ diagnostics.fields.inclusiveControlRequestWaitMaxMs = elapsed;
3044
+ }
3045
+ }
3046
+ foreground?.assertActive();
3047
+ const { sanitizeTerminalText } = await import("openclaw/plugin-sdk/text-chunking");
3048
+ const bounded = {
3049
+ ...response,
3050
+ data: response.data.slice(0, remainingRows)
3051
+ };
3052
+ const projection = {
3053
+ localSessionsRoot: root,
3054
+ sanitize: sanitizeTerminalText,
3055
+ diagnostics
3056
+ };
3057
+ const page = query.useStateDbOnly ? await projectCodexCatalogDeltaPage(bounded, {
3058
+ ...projection,
3059
+ getRow: (threadId) => index?.get(threadId)
3060
+ }) : await projectCodexCatalogPage(bounded, projection);
3061
+ foreground?.assertActive();
3062
+ outcome = "resolved";
3063
+ return page;
3064
+ } catch (error) {
3065
+ observation?.rejected();
3066
+ throw error;
3067
+ } finally {
3068
+ observation?.close();
3069
+ diagnostics?.finish(outcome);
3070
+ }
3071
+ }
3072
+ });
3073
+ indexes.set(homeId, index);
3074
+ }
3075
+ return index;
3076
+ };
3077
+ const residentFor = (agentId, source) => {
3078
+ const request = resolveResident(agentId, source);
3079
+ residentRequests.add(request);
3080
+ const release = () => residentRequests.delete(request);
3081
+ request.then(release, release);
3082
+ return request;
3083
+ };
3084
+ const resolveRequestOptions = (startOptions, agentId, source) => {
3085
+ source?.assertCurrent();
3086
+ const runtimeConfig = params.getRuntimeConfig();
3087
+ const agentDir = source?.agentDir ?? (agentId ? resolveAgentDir(runtimeConfig ?? {}, agentId) : void 0);
3088
+ const resolvedStartOptions = source?.appServer.start ?? startOptions;
3089
+ if (!runtimeConfig) return {
3090
+ agentDir,
3091
+ config: void 0,
3092
+ startOptions: structuredClone(resolvedStartOptions)
3093
+ };
3094
+ let snapshot = requestOptionsByConfig.get(runtimeConfig);
3095
+ const cacheKey = `${agentId ?? ""}\0${source?.sourceHomeId ?? ""}`;
3096
+ const cached = snapshot?.byAgent.get(cacheKey);
3097
+ if (cached) return cached;
3098
+ if (!snapshot) {
3099
+ snapshot = {
3100
+ config: structuredClone(runtimeConfig),
3101
+ byAgent: /* @__PURE__ */ new Map()
3102
+ };
3103
+ requestOptionsByConfig.set(runtimeConfig, snapshot);
3104
+ }
3105
+ const resolved = {
3106
+ agentDir,
3107
+ config: snapshot.config,
3108
+ startOptions: structuredClone(resolvedStartOptions)
3109
+ };
3110
+ snapshot.byAgent.set(cacheKey, resolved);
3111
+ return resolved;
3112
+ };
3113
+ const createRequestSnapshot = (agentId, source, catalogPreview, catalogPreviewCache, catalogRows) => {
3114
+ const pluginConfig = params.getPluginConfig();
3115
+ const runtime = source?.appServer ?? resolveRuntimeOptions({ pluginConfig });
3116
+ const requestOptions = resolveRequestOptions(runtime.start, agentId, source);
3117
+ return createCodexCatalogRequestSnapshot(runtime.requestTimeoutMs, async (method, requestParams, timeoutMs, assertCurrent, observation) => {
3118
+ const { codexControlRequest } = await import("./.setup/command-rpc-B6xsq2dB.mjs").then((n) => n.n);
3119
+ return await codexControlRequest(pluginConfig, method, requestParams, {
3120
+ ...requestOptions,
3121
+ authProfileId: null,
3122
+ assertCurrent,
3123
+ ...catalogPreview && method === CODEX_CONTROL_METHODS.listThreads ? {
3124
+ catalogPreview,
3125
+ catalogRows,
3126
+ ...catalogPreviewCache ? { catalogPreviewCache } : {}
3127
+ } : {},
3128
+ ...observation ? { controlObservation: observation } : {},
3129
+ ...timeoutMs === void 0 ? {} : { timeoutMs }
3130
+ });
3131
+ }, () => residentFor(agentId, source), (request) => sourceBackoff.begin(requestOptions.config ?? noConfig, agentId, source?.sourceHomeId, request), catalogPreview === true);
3132
+ };
3133
+ const forRequest = (agentId, source) => {
3134
+ source?.assertCurrent();
3135
+ const withPinnedConnection = async (run) => {
3136
+ const pluginConfig = params.getPluginConfig();
3137
+ const runtime = source?.appServer ?? resolveRuntimeOptions({ pluginConfig });
3138
+ const { agentDir, config: runtimeConfig, startOptions } = resolveRequestOptions(runtime.start, agentId, source);
3139
+ let catalogIndex;
3140
+ const { getLeasedSharedCodexAppServerClient, releaseLeasedSharedCodexAppServerClient, retireSharedCodexAppServerClientIfCurrent } = await import("./.setup/shared-client-DJJ3ljH2.mjs").then((n) => n.v);
3141
+ const { resolveCodexAppServerClientInstanceId } = await import("./.setup/client-CBzEVDyb.mjs").then((n) => n.n);
3142
+ const { requestCodexAppServerClientJson } = await import("./.setup/request-BH3FvYUE.mjs").then((n) => n.i);
3143
+ const client = await getLeasedSharedCodexAppServerClient({
3144
+ agentDir,
3145
+ config: runtimeConfig,
3146
+ startOptions,
3147
+ authProfileId: null,
3148
+ timeoutMs: currentCodexCatalogListRequest()?.remaining(runtime.requestTimeoutMs) ?? runtime.requestTimeoutMs
3149
+ });
3150
+ try {
3151
+ const requests = createCodexCatalogRequestSnapshot(runtime.requestTimeoutMs, async (method, requestParams, timeoutMs, assertCurrent, observation) => await requestCodexAppServerClientJson({
3152
+ client,
3153
+ method,
3154
+ requestParams,
3155
+ config: runtimeConfig,
3156
+ timeoutMs: timeoutMs ?? runtime.requestTimeoutMs,
3157
+ assertCurrent,
3158
+ ...observation ? { controlObservation: observation } : {}
3159
+ }), () => catalogIndex ??= residentFor(agentId, source), (request) => sourceBackoff.begin(runtimeConfig ?? noConfig, agentId, source?.sourceHomeId, request));
3160
+ const pinnedControl = createCodexSessionCatalogControlFromRequests({
3161
+ forkContext: agentDir ? {
3162
+ client,
3163
+ appServer: runtime,
3164
+ pluginConfig,
3165
+ agentDir,
3166
+ localSessionsRoot: source?.localSessionsRoot
3167
+ } : void 0,
3168
+ clientId: resolveCodexAppServerClientInstanceId(client),
3169
+ retireConnection: () => {
3170
+ retireSharedCodexAppServerClientIfCurrent(client);
3171
+ },
3172
+ connectionFingerprint: buildCodexAppServerConnectionFingerprint(runtime, agentDir),
3173
+ createRequestSnapshot: () => requests,
3174
+ ...source?.localSessionsRoot ? { localSessionsRoot: source.localSessionsRoot } : {},
3175
+ sourceHomeId: source?.sourceHomeId,
3176
+ managedThreads: params.managedThreads,
3177
+ now,
3178
+ withPinnedConnection: async (nestedRun) => await nestedRun(pinnedControl)
3179
+ });
3180
+ return await run(pinnedControl);
3181
+ } finally {
3182
+ releaseLeasedSharedCodexAppServerClient(client);
3183
+ }
3184
+ };
3185
+ const control = createCodexSessionCatalogControlFromRequests({
3186
+ createRequestSnapshot: () => createRequestSnapshot(agentId, source),
3187
+ ...source?.localSessionsRoot ? { localSessionsRoot: source.localSessionsRoot } : {},
3188
+ now,
3189
+ withPinnedConnection
3190
+ });
3191
+ return {
3192
+ ...control,
3193
+ requireEligibleThread: (threadId) => withPinnedConnection((pinned) => pinned.requireEligibleThread(threadId)),
3194
+ async listPage(pageParams) {
3195
+ source?.assertCurrent();
3196
+ return await control.listPage(pageParams);
3197
+ }
3198
+ };
3199
+ };
3200
+ const forUpstream = async (agentId, connectionFingerprint) => {
3201
+ const source = (await homeResolver.forAgent(agentId)).find((home) => buildCodexAppServerConnectionFingerprint(home.appServer, home.agentDir) === connectionFingerprint);
3202
+ return source ? forRequest(agentId, source) : void 0;
3203
+ };
3204
+ return {
3205
+ hasActiveWork: () => residentRequests.size > 0 || retiring !== void 0 || hasActiveSharedCodexAppServerWork() || [...indexes.values()].some((index) => index.hasActiveWork()),
3206
+ async disconnect() {
3207
+ await retireIndexes();
3208
+ await Promise.allSettled(residentRequests);
3209
+ const clients = getSharedCodexAppServerClientState();
3210
+ if (clients.liveClients.size > 0 || clients.startup.pending.size > 0) {
3211
+ const { clearSharedCodexAppServerClientAndWait } = await import("./.setup/shared-client-DJJ3ljH2.mjs").then((n) => n.v);
3212
+ await clearSharedCodexAppServerClientAndWait();
3213
+ }
3214
+ },
3215
+ async start() {
3216
+ const serviceScope = AsyncLocalStorage.snapshot();
3217
+ runBackground = (run) => serviceScope(run);
3218
+ },
3219
+ async stop() {
3220
+ closed = true;
3221
+ await retireIndexes();
3222
+ await Promise.allSettled(residentRequests);
3223
+ },
3224
+ forRequest,
3225
+ forUpstream,
3226
+ homesForAgent: homeResolver.forAgent,
3227
+ async forNode(agentId) {
3228
+ const source = await homeResolver.forNode(agentId);
3229
+ return {
3230
+ assertCurrent: () => source.assertCurrent(),
3231
+ control: forRequest(source.agentId, source),
3232
+ sourceHomeId: source.sourceHomeId,
3233
+ codexHome: source.codexHome,
3234
+ transport: source.appServer.start.transport
3235
+ };
3236
+ }
3237
+ };
3238
+ }
3239
+ //#endregion
3240
+ //#region extensions/codex/src/session-catalog.ts
3241
+ /** Allows read-only catalog and transcript commands on supported paired-node platforms. */
3242
+ function createCodexSessionCatalogNodeInvokePolicies() {
3243
+ return [{
3244
+ commands: [
3245
+ CODEX_APP_SERVER_THREADS_LIST_COMMAND,
3246
+ CODEX_APP_SERVER_THREAD_TURNS_LIST_COMMAND,
3247
+ CODEX_CATALOG_TRANSCRIPT_READ_COMMAND,
3248
+ CODEX_TERMINAL_RESUME_COMMAND,
3249
+ CODEX_TERMINAL_START_COMMAND
3250
+ ],
3251
+ defaultPlatforms: [
3252
+ "macos",
3253
+ "linux",
3254
+ "windows"
3255
+ ],
3256
+ handle: (context) => {
3257
+ 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 } : {
3258
+ ok: false,
3259
+ message: "Native terminal start requires operator.admin and enabled CLI agents and terminals"
3260
+ };
3261
+ return context.command === "codex.terminal.resume.v1" ? { ok: true } : context.invokeNode();
3262
+ }
3263
+ }];
3264
+ }
3265
+ function isLocalCodexCatalogHost(hostId) {
3266
+ return hostId === "gateway:local" || hostId.startsWith(`gateway:local:`);
3267
+ }
3268
+ function resolveLocalCatalogHomeForThread(params) {
3269
+ if (params.homes.length === 0) throw new CatalogParamsError("local Codex sessions are unavailable in isolated state");
3270
+ const exact = params.sourceHomeId ? params.homes.find((home) => home.sourceHomeId === params.sourceHomeId) : params.homes.find((home) => home.hostId === params.hostId);
3271
+ if (!exact || params.sourceHomeId && exact.hostId !== params.hostId) throw new CatalogParamsError("Codex session source home is unavailable");
3272
+ return exact;
3273
+ }
3274
+ function withCatalogListScope(initialize) {
3275
+ let create = initialize;
3276
+ let operation;
3277
+ let scope;
3278
+ let running = false;
3279
+ let closed = false;
3280
+ let completed = false;
3281
+ return {
3282
+ async next() {
3283
+ if (closed || running) throw new Error("Codex catalog list operation cannot advance");
3284
+ running = true;
3285
+ try {
3286
+ scope ??= createCodexCatalogListScope();
3287
+ return await scope.run(async () => {
3288
+ if (create) {
3289
+ const initializeOnce = create;
3290
+ create = void 0;
3291
+ operation = await initializeOnce();
3292
+ }
3293
+ if (!operation) throw new Error("Codex catalog list operation did not initialize");
3294
+ const step = await operation.next();
3295
+ completed ||= step.done;
3296
+ return step;
3297
+ });
3298
+ } finally {
3299
+ running = false;
3300
+ }
3301
+ },
3302
+ close() {
3303
+ if (closed) return;
3304
+ if (running) throw new Error("Cannot close an active Codex catalog list step");
3305
+ closed = true;
3306
+ create = void 0;
3307
+ const current = operation;
3308
+ operation = void 0;
3309
+ const currentScope = scope;
3310
+ scope = void 0;
3311
+ try {
3312
+ if (currentScope) currentScope.run(() => current?.close());
3313
+ } finally {
3314
+ currentScope?.finish(completed ? "resolved" : "rejected");
3315
+ }
3316
+ }
3317
+ };
3318
+ }
3319
+ function catalogHostMapper(localTerminalAvailable, localHomes) {
3320
+ return (host) => {
3321
+ const finishTiming = startCodexCatalogListTiming("mappingMs");
3322
+ try {
3323
+ const localSourceAvailable = localTerminalAvailable && localHomes.some((home) => home.hostId === host.hostId && home.appServer.start.transport === "stdio");
3324
+ const local = isLocalCodexCatalogHost(host.hostId);
3325
+ return {
3326
+ hostId: host.hostId,
3327
+ label: host.label,
3328
+ kind: host.kind,
3329
+ connected: host.connected,
3330
+ ...host.pending ? { pending: true } : {},
3331
+ ...host.nodeId ? { nodeId: host.nodeId } : {},
3332
+ sessions: host.sessions.map((session) => {
3333
+ const interactive = isInteractiveThreadSource(session.source);
3334
+ const continuable = interactive && !session.archived && (session.status === "idle" || session.status === "notLoaded");
3335
+ const name = session.name ?? session.fallbackName;
3336
+ return {
3337
+ threadId: session.threadId,
3338
+ ...session.sourceHomeId ? { sourceHomeId: session.sourceHomeId } : {},
3339
+ ...name ? { name } : {},
3340
+ ...session.cwd ? { cwd: session.cwd } : {},
3341
+ status: session.status,
3342
+ ...session.createdAt != null ? { createdAt: session.createdAt } : {},
3343
+ ...session.updatedAt != null ? { updatedAt: session.updatedAt } : {},
3344
+ ...session.recencyAt != null ? { recencyAt: session.recencyAt } : {},
3345
+ ...session.source ? { source: session.source } : {},
3346
+ ...session.modelProvider ? { modelProvider: session.modelProvider } : {},
3347
+ ...session.cliVersion ? { cliVersion: session.cliVersion } : {},
3348
+ ...session.gitBranch ? { gitBranch: session.gitBranch } : {},
3349
+ archived: session.archived,
3350
+ ...session.sessionKey ? { sessionKey: session.sessionKey } : {},
3351
+ canContinue: (local || host.canContinueCodex === true) && continuable,
3352
+ canArchive: local && continuable,
3353
+ canOpenTerminal: interactive && (local ? localSourceAvailable : host.canOpenTerminalCodex === true)
3354
+ };
3355
+ }),
3356
+ ...host.nextCursor ? { nextCursor: host.nextCursor } : {},
3357
+ ...host.error ? { error: host.error } : {},
3358
+ canStartTerminal: host.kind === "gateway" ? localSourceAvailable && host.hostId === "gateway:local" : host.canStartTerminal === true
3359
+ };
3360
+ } finally {
3361
+ finishTiming();
3362
+ }
3363
+ };
3364
+ }
3365
+ function registerCodexSessionCatalog(params) {
3366
+ const catalogHomes = async (agentId, allowProcessHomeFallback) => {
3367
+ const homes = await params.control.homesForAgent(agentId);
3368
+ return allowProcessHomeFallback === false ? homes.filter((home) => !home.usesProcessHomeFallback) : homes;
3369
+ };
3370
+ const resolveRequestAgentId = (agentId) => resolveSessionAgentIdsStrict({
3371
+ config: params.getRuntimeConfig() ?? params.api.config,
3372
+ agentId
3373
+ }).sessionAgentId;
3374
+ const bindRequest = async (request) => {
3375
+ const agentId = resolveRequestAgentId(request.agentId);
3376
+ const source = isLocalCodexCatalogHost(request.hostId) ? resolveLocalCatalogHomeForThread({
3377
+ homes: [...await catalogHomes(agentId, request.allowProcessHomeFallback)],
3378
+ hostId: request.hostId,
3379
+ ...request.sourceHomeId ? { sourceHomeId: request.sourceHomeId } : {}
3380
+ }) : void 0;
3381
+ return {
3382
+ agentId,
3383
+ source,
3384
+ control: params.control.forRequest(agentId, source)
3385
+ };
3386
+ };
3387
+ const bindLocalRequest = async (request) => {
3388
+ const bound = await bindRequest(request);
3389
+ if (!bound.source) throw new CatalogParamsError("Codex session catalog hostId is invalid");
3390
+ return {
3391
+ ...bound,
3392
+ source: bound.source
3393
+ };
3394
+ };
3395
+ const checkUpstreamActivity = createChecker(params);
3396
+ const nodeSnapshots = new CodexCatalogNodeSnapshots();
3397
+ const createListOperation = (query) => withCatalogListScope(async () => {
3398
+ const { agentId: requestedAgentId, allowProcessHomeFallback, allowPartialResults, listNodes, onHost, waitUntil, signal, sessionEntries, ...gatewayQuery } = query;
3399
+ const agentId = resolveRequestAgentId(requestedAgentId);
3400
+ const selectedQuery = readGatewayParams(gatewayQuery);
3401
+ const localHomes = selectedQuery.hostIds && !selectedQuery.hostIds.some(isLocalCodexCatalogHost) ? [] : [...await catalogHomes(agentId, allowProcessHomeFallback)];
3402
+ const mapHost = catalogHostMapper(resolveLocalCodexTerminalExecutable() !== void 0, localHomes);
3403
+ const operation = createCodexSessionCatalogListOperation({
3404
+ agentId,
3405
+ bindingStore: params.bindingStore,
3406
+ config: params.getRuntimeConfig(),
3407
+ runtime: params.api.runtime,
3408
+ control: params.control,
3409
+ query: selectedQuery,
3410
+ listNodes,
3411
+ waitUntil,
3412
+ signal,
3413
+ sessionEntries,
3414
+ localHomes,
3415
+ allowPartialResults,
3416
+ nodeSnapshots,
3417
+ ...onHost ? { onHost: (host) => onHost(mapHost(host)) } : {}
3418
+ });
3419
+ return {
3420
+ async next() {
3421
+ const step = await operation.next();
3422
+ return step.done ? {
3423
+ done: true,
3424
+ hosts: step.hosts.map(mapHost)
3425
+ } : step;
3426
+ },
3427
+ close: () => operation.close()
3428
+ };
3429
+ });
3430
+ const provider = {
3431
+ id: "codex",
3432
+ label: "Codex",
3433
+ supportsProcessHomeIsolation: true,
3434
+ resolveCreateSession: ({ agentId }) => resolveCodexCatalogCreateSession(params.api.runtime.modelConfig, params.getRuntimeConfig() ?? params.api.config, agentId),
3435
+ list: (query) => runCatalogListInline(createListOperation(query)),
3436
+ createListOperation,
3437
+ read: async (request) => {
3438
+ const { agentId, source, control } = await bindRequest(request);
3439
+ return await readCodexSessionTranscript({
3440
+ agentId,
3441
+ runtime: params.api.runtime,
3442
+ control,
3443
+ hostId: request.hostId,
3444
+ threadId: request.threadId,
3445
+ sourceHomeId: request.sourceHomeId,
3446
+ cursor: request.cursor,
3447
+ limit: request.limit ?? 20,
3448
+ ...source ? { source } : {}
3449
+ });
3450
+ },
3451
+ continueSession: async (request) => {
3452
+ const config = params.getRuntimeConfig();
3453
+ if (!config) throw new Error("OpenClaw runtime config is unavailable");
3454
+ if (request.hostId.startsWith("node:")) {
3455
+ const agentId = resolveRequestAgentId(request.agentId);
3456
+ const { continueNodeCodexSession } = await import("./.setup/session-catalog-node-continue-DLWBwAAO.mjs");
3457
+ return await continueNodeCodexSession({
3458
+ agentId,
3459
+ api: params.api,
3460
+ config,
3461
+ hostId: request.hostId,
3462
+ threadId: request.threadId,
3463
+ sourceHomeId: request.sourceHomeId,
3464
+ clientScopes: request.clientScopes
3465
+ });
3466
+ }
3467
+ if (!isLocalCodexCatalogHost(request.hostId)) throw new CatalogParamsError("Codex session catalog hostId is invalid");
3468
+ const { agentId, source, control } = await bindLocalRequest(request);
3469
+ source.assertCurrent();
3470
+ let upstreamBaseline;
3471
+ const { continueLocalCodexSession } = await import("./.setup/session-catalog-adoption-CPIP4S_y.mjs");
3472
+ const continued = await continueLocalCodexSession({
3473
+ agentId,
3474
+ api: params.api,
3475
+ bindingStore: params.bindingStore,
3476
+ config,
3477
+ control,
3478
+ threadId: request.threadId,
3479
+ hostId: source.hostId,
3480
+ sourceHomeId: source.sourceHomeId,
3481
+ ...source.hostId === "gateway:local" ? { allowLegacy: true } : {},
3482
+ onContinued: (baseline) => {
3483
+ upstreamBaseline = baseline;
3484
+ }
3485
+ });
3486
+ return codexUpstreamContinueResult(continued.sessionKey, request.threadId, upstreamBaseline);
3487
+ },
3488
+ checkUpstreamActivity: async (probes, policy) => {
3489
+ const filtered = [];
3490
+ for (const probe of probes) if (!isLocalCodexCatalogHost(probe.hostId) || policy?.allowProcessHomeFallback !== false || (await catalogHomes(probe.agentId, false)).some((home) => home.hostId === probe.hostId)) filtered.push(probe);
3491
+ return checkUpstreamActivity(filtered);
3492
+ },
3493
+ archive: async (request) => {
3494
+ if (request.confirmNoOtherRunner !== true) throw new CatalogParamsError("archive requires confirmation that no other runner is active");
3495
+ if (!isLocalCodexCatalogHost(request.hostId)) throw new CatalogParamsError("paired-node Codex sessions are view-only");
3496
+ const config = params.getRuntimeConfig();
3497
+ if (!config) throw new Error("OpenClaw runtime config is unavailable");
3498
+ const { agentId, source, control } = await bindLocalRequest(request);
3499
+ source.assertCurrent();
3500
+ const { archiveLocalCodexSession } = await import("./.setup/session-catalog-archive-DcgwvSbF.mjs");
3501
+ await archiveLocalCodexSession({
3502
+ agentId,
3503
+ bindingStore: params.bindingStore,
3504
+ config,
3505
+ control,
3506
+ runtime: params.api.runtime,
3507
+ threadId: request.threadId,
3508
+ hostId: source.hostId,
3509
+ sourceHomeId: source.sourceHomeId,
3510
+ ...source.hostId === "gateway:local" ? { allowLegacy: true } : {}
3511
+ });
3512
+ return { ok: true };
3513
+ },
3514
+ openTerminal: async (request) => {
3515
+ const { agentId, source, control } = await bindRequest(request);
3516
+ return await openCodexCatalogTerminal({
3517
+ api: params.api,
3518
+ control,
3519
+ getPluginConfig: params.getPluginConfig,
3520
+ getRuntimeConfig: params.getRuntimeConfig,
3521
+ resolveRuntimeOptions: params.resolveRuntimeOptions,
3522
+ ...source ? { source } : {},
3523
+ ...request,
3524
+ agentId
3525
+ });
3526
+ },
3527
+ startTerminalSession: async (request) => {
3528
+ 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");
3529
+ const source = request.nodeId ? void 0 : resolveLocalCatalogHomeForThread({
3530
+ homes: [...await catalogHomes(request.agentId, request.allowProcessHomeFallback)],
3531
+ hostId: request.hostId ?? "gateway:local"
3532
+ });
3533
+ if (source && source.appServer.start.transport !== "stdio") throw new CatalogParamsError("Native terminal start requires a local Codex source");
3534
+ return await startCodexCatalogTerminal({
3535
+ getPluginConfig: params.getPluginConfig,
3536
+ getRuntimeConfig: params.getRuntimeConfig,
3537
+ resolveRuntimeOptions: params.resolveRuntimeOptions,
3538
+ ...request,
3539
+ source
3540
+ });
3541
+ }
3542
+ };
3543
+ params.api.registerSessionCatalog(provider);
3544
+ }
3545
+ //#endregion
3546
+ //#region extensions/codex/src/supervision-tool-policy.ts
3547
+ var CodexSupervisionPolicyError = class extends Error {};
3548
+ function requireSupervisionEnabled(pluginConfig) {
3549
+ if (readCodexPluginConfig(pluginConfig).supervision?.enabled !== true) throw new CodexSupervisionPolicyError("Codex supervision is disabled in the codex plugin config.");
3550
+ }
3551
+ function requireOwnerAccess(options) {
3552
+ options.assertInvocationCurrent?.();
3553
+ if (!options.senderIsOwner) throw new CodexSupervisionPolicyError("Codex supervision compatibility tools require an owner-authorized sender.");
3554
+ }
3555
+ function resolveToolPolicy(pluginConfig) {
3556
+ const config = readCodexPluginConfig(pluginConfig).supervision;
3557
+ return {
3558
+ allowRawTranscripts: config?.allowRawTranscripts === true,
3559
+ allowWriteControls: config?.allowWriteControls === true
3560
+ };
3561
+ }
3562
+ function requireRawTranscriptAccess(pluginConfig) {
3563
+ if (!resolveToolPolicy(pluginConfig).allowRawTranscripts) throw new CodexSupervisionPolicyError("Codex session reads are disabled for this codex plugin supervision config.");
3564
+ }
3565
+ function requireWriteAccess(pluginConfig) {
3566
+ if (!resolveToolPolicy(pluginConfig).allowWriteControls) throw new CodexSupervisionPolicyError("Codex write controls are disabled for this codex plugin supervision config.");
3567
+ }
3568
+ //#endregion
3569
+ //#region extensions/codex/src/supervision-tools.ts
3570
+ /**
3571
+ * Compatibility tools for the retired Codex Supervisor plugin.
3572
+ *
3573
+ * Read operations and active-turn controls use the Codex plugin's canonical
3574
+ * shared app-server client. Idle threads are never resumed or started here:
3575
+ * continuation belongs to the Codex harness, which installs approval and tool
3576
+ * handlers before it starts or resumes the harness-owned Codex thread.
3577
+ */
3578
+ /** Legacy endpoint env retained for the shipped Supervisor tool contract. */
3579
+ const LEGACY_CODEX_SUPERVISOR_ENDPOINTS_ENV = "OPENCLAW_CODEX_SUPERVISOR_ENDPOINTS";
3580
+ const CODEX_SUPERVISION_COMPAT_TOOL_NAMES = [
3581
+ "codex_endpoint_probe",
3582
+ "codex_sessions_list",
3583
+ "codex_session_read",
3584
+ "codex_session_send",
3585
+ "codex_session_interrupt"
3586
+ ];
3587
+ const EmptyParamsSchema = Type.Object({}, { additionalProperties: false });
3588
+ const SessionsListParamsSchema = Type.Object({
3589
+ include_stored: Type.Optional(Type.Boolean()),
3590
+ max_stored_sessions: Type.Optional(Type.Integer({
3591
+ minimum: 1,
3592
+ maximum: 1e3
3593
+ }))
3594
+ }, { additionalProperties: false });
3595
+ const SessionReadParamsSchema = Type.Object({
3596
+ endpoint_id: Type.Optional(Type.String()),
3597
+ thread_id: Type.String(),
3598
+ include_turns: Type.Optional(Type.Boolean())
3599
+ }, { additionalProperties: false });
3600
+ const SessionSendParamsSchema = Type.Object({
3601
+ endpoint_id: Type.Optional(Type.String()),
3602
+ thread_id: Type.String(),
3603
+ text: Type.String(),
3604
+ mode: Type.Optional(Type.Union([
3605
+ Type.Literal("auto"),
3606
+ Type.Literal("start"),
3607
+ Type.Literal("steer")
3608
+ ]))
3609
+ }, { additionalProperties: false });
3610
+ const SessionInterruptParamsSchema = Type.Object({
3611
+ endpoint_id: Type.Optional(Type.String()),
3612
+ thread_id: Type.String(),
3613
+ turn_id: Type.Optional(Type.String())
3614
+ }, { additionalProperties: false });
3615
+ const ALL_CODEX_THREAD_SOURCE_KINDS = [
3616
+ "cli",
3617
+ "vscode",
3618
+ "exec",
3619
+ "appServer",
3620
+ "subAgent",
3621
+ "subAgentReview",
3622
+ "subAgentCompact",
3623
+ "subAgentThreadSpawn",
3624
+ "subAgentOther",
3625
+ "unknown"
3626
+ ];
3627
+ const DEFAULT_MAX_STORED_SESSIONS = 200;
3628
+ const PAGE_LIMIT = 100;
3629
+ const MAX_COMPAT_PAGINATION_PAGES = 100;
3630
+ const MAX_COMPAT_CURSOR_LENGTH = 4096;
3631
+ const MAX_COMPAT_THREAD_ID_LENGTH = 4096;
3632
+ function asRecordArray(value) {
3633
+ return Array.isArray(value) ? value.filter(isRecord) : [];
3634
+ }
3635
+ function readCompatNextCursor(value, method) {
3636
+ if (value === null || value === void 0) return;
3637
+ if (typeof value !== "string" || value.trim().length === 0 || value.length > MAX_COMPAT_CURSOR_LENGTH) throw new Error(`Codex ${method} returned an invalid nextCursor`);
3638
+ return value;
3639
+ }
3640
+ function readCompatThreadId(value, method, index) {
3641
+ if (typeof value !== "string" || value.trim().length === 0 || value.length > MAX_COMPAT_THREAD_ID_LENGTH) throw new Error(`Codex ${method} returned an invalid thread id at data[${index}]`);
3642
+ return value;
3643
+ }
3644
+ function readLoadedThreadIds(data) {
3645
+ if (data.length > PAGE_LIMIT) throw new Error(`Codex thread/loaded/list returned more than ${PAGE_LIMIT} entries`);
3646
+ return data.map((entry, index) => readCompatThreadId(entry, "thread/loaded/list", index));
3647
+ }
3648
+ function readStoredThreads(data, maxEntries) {
3649
+ if (data.length > maxEntries) throw new Error(`Codex thread/list returned more than ${maxEntries} entries`);
3650
+ return data.map((entry, index) => {
3651
+ if (!isRecord(entry)) throw new Error(`Codex thread/list returned an invalid entry at data[${index}]`);
3652
+ readCompatThreadId(entry.id, "thread/list", index);
3653
+ return entry;
3654
+ });
3655
+ }
3656
+ function readIntegerParam(params, key) {
3657
+ const value = params[key];
3658
+ if (value === void 0) return;
3659
+ if (typeof value !== "number" || !Number.isInteger(value)) throw new Error(`${key} must be an integer`);
3660
+ if (value < 1 || value > 1e3) throw new Error(`${key} must be between 1 and 1000`);
3661
+ return value;
3662
+ }
3663
+ function readModeParam(params) {
3664
+ const mode = readStringParam(params, "mode");
3665
+ if (!mode) return;
3666
+ if (mode === "auto" || mode === "start" || mode === "steer") return mode;
3667
+ throw new Error("mode must be auto, start, or steer");
3668
+ }
3669
+ function normalizeEndpointId(value, index) {
3670
+ const trimmed = value.trim();
3671
+ return trimmed ? trimmed.replace(/[^a-zA-Z0-9_.:-]/g, "-") : `endpoint-${index + 1}`;
3672
+ }
3673
+ function normalizeConfiguredEndpoint(endpoint, index) {
3674
+ return {
3675
+ id: normalizeEndpointId(endpoint.id ?? endpoint.label ?? "", index),
3676
+ ...endpoint.label?.trim() ? { label: endpoint.label.trim() } : {},
3677
+ configured: endpoint
3678
+ };
3679
+ }
3680
+ function parseEndpointRecord(value) {
3681
+ if (!isRecord(value)) return;
3682
+ const transport = typeof value.transport === "string" ? value.transport : void 0;
3683
+ const common = {
3684
+ ...typeof value.id === "string" ? { id: value.id } : {},
3685
+ ...typeof value.label === "string" ? { label: value.label } : {}
3686
+ };
3687
+ if (transport === "websocket" && typeof value.url === "string") return {
3688
+ ...common,
3689
+ transport,
3690
+ url: value.url,
3691
+ ...typeof value.authTokenEnv === "string" ? { authTokenEnv: value.authTokenEnv } : {}
3692
+ };
3693
+ if (transport === "stdio-proxy" || transport === void 0) {
3694
+ const args = Array.isArray(value.args) ? value.args.filter((entry) => typeof entry === "string") : void 0;
3695
+ return {
3696
+ ...common,
3697
+ transport: "stdio-proxy",
3698
+ ...typeof value.command === "string" ? { command: value.command } : {},
3699
+ ...args && args.length > 0 ? { args } : {},
3700
+ ...typeof value.cwd === "string" ? { cwd: value.cwd } : {}
3701
+ };
3702
+ }
3703
+ }
3704
+ function endpointFromToken(token, index) {
3705
+ const trimmed = token.trim();
3706
+ if (!trimmed) return;
3707
+ if (trimmed.startsWith("ws://") || trimmed.startsWith("wss://") || trimmed.startsWith("unix://")) return {
3708
+ id: normalizeEndpointId("", index),
3709
+ transport: "websocket",
3710
+ url: trimmed
3711
+ };
3712
+ if (trimmed === "local" || trimmed === "proxy" || trimmed === "stdio") return {
3713
+ id: "local",
3714
+ label: "local Codex app-server",
3715
+ transport: "stdio-proxy"
3716
+ };
3717
+ const separatorIndex = trimmed.indexOf("=");
3718
+ const id = separatorIndex >= 0 ? trimmed.slice(0, separatorIndex) : trimmed;
3719
+ const url = separatorIndex >= 0 ? trimmed.slice(separatorIndex + 1) : void 0;
3720
+ if (url?.startsWith("ws://") || url?.startsWith("wss://") || url?.startsWith("unix://")) return {
3721
+ id: normalizeEndpointId(id, index),
3722
+ transport: "websocket",
3723
+ url
3724
+ };
3725
+ }
3726
+ function requireUniqueEndpointIds(endpoints) {
3727
+ const seen = /* @__PURE__ */ new Set();
1112
3728
  for (const endpoint of endpoints) {
1113
3729
  if (seen.has(endpoint.id)) throw new Error(`duplicate Codex supervisor endpoint id: ${endpoint.id}`);
1114
3730
  seen.add(endpoint.id);
@@ -1128,23 +3744,17 @@ function readLegacyEnvEndpoints(env) {
1128
3744
  function resolveEndpoints(pluginConfig, env, runtimeConfig, resolveAuthProfileId, resolveRuntimeOptions) {
1129
3745
  const configured = readCodexPluginConfig(pluginConfig).supervision?.endpoints;
1130
3746
  const endpoints = configured?.length ? configured : readLegacyEnvEndpoints(env);
1131
- const normalized = endpoints ? requireUniqueEndpointIds(endpoints.map(normalizeConfiguredEndpoint)) : [{
3747
+ return (endpoints ? requireUniqueEndpointIds(endpoints.map(normalizeConfiguredEndpoint)) : [{
1132
3748
  id: "local",
1133
3749
  label: "local Codex app-server"
1134
- }];
1135
- const resolved = [];
1136
- for (const endpoint of normalized) resolved.push({
1137
- ...endpoint,
1138
- connectionKey: supervisionEndpointConnectionKey({
1139
- endpoint,
1140
- pluginConfig,
1141
- env,
1142
- runtimeConfig,
1143
- resolveAuthProfileId,
1144
- resolveRuntimeOptions
1145
- })
1146
- });
1147
- return resolved;
3750
+ }]).map((endpoint) => Object.assign({}, endpoint, { connectionKey: supervisionEndpointConnectionKey({
3751
+ endpoint,
3752
+ pluginConfig,
3753
+ env,
3754
+ runtimeConfig,
3755
+ resolveAuthProfileId,
3756
+ resolveRuntimeOptions
3757
+ }) }));
1148
3758
  }
1149
3759
  function resolveEndpointStartOptions(params) {
1150
3760
  const base = params.resolveRuntimeOptions({
@@ -1259,29 +3869,24 @@ function toSession(endpointId, thread, humanAttached) {
1259
3869
  ...humanAttached !== void 0 ? { humanAttached } : {}
1260
3870
  };
1261
3871
  }
1262
- function threadFromRead(value) {
1263
- return isRecord(value) && isRecord(value.thread) ? value.thread : void 0;
1264
- }
1265
3872
  function isLoadedThreadReadMiss(error) {
1266
3873
  const message = coerceErrorMessage(error);
1267
3874
  return message.includes("thread not found") || message.includes("thread not loaded");
1268
3875
  }
1269
3876
  async function readThread(params) {
1270
- try {
1271
- const thread = threadFromRead(await params.request(params.endpoint, "thread/read", {
3877
+ const read = async (includeTurns, errorOptions) => {
3878
+ const response = await params.request(params.endpoint, "thread/read", {
1272
3879
  threadId: params.threadId,
1273
- includeTurns: params.includeTurns
1274
- }));
1275
- if (!thread) throw new Error("Codex thread/read returned an invalid response");
1276
- return thread;
3880
+ includeTurns
3881
+ });
3882
+ if (!isRecord(response) || !isRecord(response.thread)) throw new Error("Codex thread/read returned an invalid response", errorOptions);
3883
+ return response.thread;
3884
+ };
3885
+ try {
3886
+ return await read(params.includeTurns);
1277
3887
  } catch (error) {
1278
3888
  if (!params.includeTurns || !String(error).includes("not materialized yet")) throw error;
1279
- const thread = threadFromRead(await params.request(params.endpoint, "thread/read", {
1280
- threadId: params.threadId,
1281
- includeTurns: false
1282
- }));
1283
- if (!thread) throw new Error("Codex thread/read returned an invalid response", { cause: error });
1284
- return thread;
3889
+ return await read(false, { cause: error });
1285
3890
  }
1286
3891
  }
1287
3892
  async function listSessions(request, endpoint, storedLimit) {
@@ -1409,15 +4014,12 @@ function redactCodexSupervisionValue(value, key = "") {
1409
4014
  }
1410
4015
  function redactEndpointUrl(value) {
1411
4016
  if (value.startsWith("unix://")) return "unix://";
1412
- try {
1413
- const url = new URL(value);
1414
- url.username = "";
1415
- url.password = "";
1416
- if (url.search) url.search = "?[redacted]";
1417
- return url.toString();
1418
- } catch {
1419
- return "[redacted]";
1420
- }
4017
+ const url = URL.parse(value);
4018
+ if (!url) return "[redacted]";
4019
+ url.username = "";
4020
+ url.password = "";
4021
+ if (url.search) url.search = "?[redacted]";
4022
+ return url.toString();
1421
4023
  }
1422
4024
  function endpointResult(endpoint, pluginConfig, env, resolveRuntimeOptions) {
1423
4025
  const start = endpoint.configured ?? resolveRuntimeOptions({
@@ -1660,7 +4262,7 @@ function createCodexSupervisionTools(options) {
1660
4262
  }
1661
4263
  //#endregion
1662
4264
  //#region extensions/codex/src/web-search-provider.ts
1663
- const loadCodexWebSearchRuntime = createLazyRuntimeModule(() => import("./.setup/web-search-provider.runtime-UKgeiBUG.mjs"));
4265
+ const loadCodexWebSearchRuntime = createLazyRuntimeModule(() => import("./.setup/web-search-provider.runtime-CsVmqbFm.mjs"));
1664
4266
  const CodexWebSearchSchema = {
1665
4267
  type: "object",
1666
4268
  properties: { query: {
@@ -1744,9 +4346,12 @@ var codex_default = definePluginEntry({
1744
4346
  deleteIf: (key, predicate) => openBindingStateStore().deleteIf(key, predicate),
1745
4347
  entries: () => openBindingStateStore().entries(),
1746
4348
  lookup: (key) => openBindingStateStore().lookup(key),
1747
- get lookupMany() {
1748
- const store = openBindingStateStore();
1749
- return store.lookupMany?.bind(store);
4349
+ asyncReads: {
4350
+ lookup: (key) => openBindingMutationStore().lookup(key),
4351
+ get lookupMany() {
4352
+ const store = openBindingMutationStore();
4353
+ return store.lookupMany?.bind(store);
4354
+ }
1750
4355
  },
1751
4356
  registerIfAbsent: (key, value, options) => openBindingStateStore().registerIfAbsent(key, value, options),
1752
4357
  withCurrent: (authority) => {
@@ -1762,7 +4367,6 @@ var codex_default = definePluginEntry({
1762
4367
  });
1763
4368
  const bindingStore = createLazyCodexAppServerBindingStore(lazyBindingStateStore, {
1764
4369
  entries: () => openManagedThreadStateStore().entries(),
1765
- lookup: (key) => openManagedThreadStateStore().lookup(key),
1766
4370
  registerIfAbsent: (key, value) => openManagedThreadStateStore().registerIfAbsent(key, value)
1767
4371
  });
1768
4372
  registerCodexCliMetadata(api);
@@ -1786,7 +4390,7 @@ var codex_default = definePluginEntry({
1786
4390
  stop: () => sessionCatalogControlFactory.stop()
1787
4391
  });
1788
4392
  if (sessionCatalogEnabled) {
1789
- codexSessionCatalogRuntime.register({
4393
+ registerCodexSessionCatalog({
1790
4394
  api,
1791
4395
  resolveRuntimeOptions: resolveCodexSupervisionAppServerRuntimeOptions,
1792
4396
  bindingStore,
@@ -1925,7 +4529,7 @@ var codex_default = definePluginEntry({
1925
4529
  if (endedSessionKey && nextSessionKey && nextSessionKey !== endedSessionKey) return;
1926
4530
  if (event.nextSessionId?.trim() === event.sessionId.trim()) return;
1927
4531
  const config = resolveCurrentConfig();
1928
- const [{ sessionBindingIdentity }, { retireCodexAppServerSessionGeneration }] = await Promise.all([import("./.setup/session-binding-DGCYAfvD.mjs").then((n) => n.s), import("./.setup/session-retirement-LlYWBKTJ.mjs")]);
4532
+ const [{ sessionBindingIdentity }, { retireCodexAppServerSessionGeneration }] = await Promise.all([import("./.setup/session-binding-Ce7BqiPN.mjs").then((n) => n.i), import("./.setup/session-retirement-aC60o6P3.mjs")]);
1929
4533
  await retireCodexAppServerSessionGeneration({
1930
4534
  bindingStore,
1931
4535
  identity: sessionBindingIdentity({