@openclaw/codex 2026.9.5 → 2026.9.7

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 (174) hide show
  1. package/README.md +2 -0
  2. package/assets/icon.png +0 -0
  3. package/dist/.setup/{account-usage-runtime-C2MOIvfq.mjs → account-usage-runtime-DFhbh1zz.mjs} +6 -6
  4. package/dist/.setup/{apply-CJ0ZfmBG.mjs → apply-D3GcSoSa.mjs} +35 -55
  5. package/dist/.setup/{attempt-client-cleanup-BpYKdTA0.mjs → attempt-client-cleanup-DOP-cW5j.mjs} +179 -73
  6. package/dist/.setup/attempt-workspace-context-C5HigshI.mjs +164 -0
  7. package/dist/.setup/{auth-binding-DhLWa_7K.mjs → auth-binding-BLWz7stm.mjs} +14 -1
  8. package/dist/.setup/{auth-cache-key-QirmgiCo.mjs → auth-cache-key-Dbvq-QgB.mjs} +41 -111
  9. package/dist/.setup/{auth-profile-WqZtZfXN.mjs → auth-profile-B0okYl2D.mjs} +1 -2
  10. package/dist/.setup/auth-profile-health-oHizqgye.mjs +53 -0
  11. package/dist/.setup/auth-profile-recovery-BREezV0L.mjs +14 -0
  12. package/dist/.setup/auth-start-options-BPIPeEX8.mjs +44 -0
  13. package/dist/.setup/{binding-connection-Bm38niE8.mjs → binding-connection-DTtN1KrX.mjs} +2 -2
  14. package/dist/.setup/{binding-connection.runtime-CnRMC0ta.mjs → binding-connection.runtime-6TpgD1M6.mjs} +5 -5
  15. package/dist/.setup/{bounded-turn-BtlZcivC.mjs → bounded-turn-CbjoN2OW.mjs} +140 -37
  16. package/dist/.setup/bounded-turn-isolation-B8K_ylqk.mjs +14 -0
  17. package/dist/.setup/{build-state-Xx9ybZqa.mjs → build-state-Da1_z0kd.mjs} +1 -1
  18. package/dist/.setup/{capabilities-_vXcZGSx.mjs → capabilities-B3WEZl4e.mjs} +2 -10
  19. package/dist/.setup/{client-vXs2929Q.mjs → client-N0JpgSzF.mjs} +635 -872
  20. package/dist/.setup/client-catalog-response-5HHLdcde.mjs +285 -0
  21. package/dist/.setup/{command-dispatch-naHIZwwF.mjs → command-dispatch-BeAoaovI.mjs} +9 -8
  22. package/dist/.setup/{command-formatters-CGEkdawF.mjs → command-formatters-R3ckE3Co.mjs} +36 -64
  23. package/dist/.setup/{command-handlers-BtAJEW1X.mjs → command-handlers-ylTMS00z.mjs} +301 -488
  24. package/dist/.setup/{command-rpc-DHFpn4le.mjs → command-rpc-CGJGUQ6Y.mjs} +40 -28
  25. package/dist/.setup/compact-C2WamavS.mjs +776 -0
  26. package/dist/.setup/{config-CedDWjM-.mjs → config-DKhXquav.mjs} +26 -28
  27. package/dist/.setup/{config-options-BsanJ8QG.mjs → config-options-CzyWLTJt.mjs} +68 -65
  28. package/dist/.setup/{config-parsing-CcB9iPoq.mjs → config-parsing-b088LyhT.mjs} +57 -60
  29. package/dist/.setup/{config-runtime-CeAhl_h4.mjs → config-runtime-C0NbLms1.mjs} +2 -2
  30. package/dist/.setup/{config-security-BRQ2mgW9.mjs → config-security-CE-FcGw9.mjs} +51 -215
  31. package/dist/.setup/{config-utils-DujwEnhg.mjs → config-utils-D0CXecki.mjs} +3 -13
  32. package/dist/.setup/context-engine-projection-PezSESth.mjs +387 -0
  33. package/dist/.setup/{conversation-binding-DhzrpTM6.mjs → conversation-binding-3Min8qvP.mjs} +71 -105
  34. package/dist/.setup/{conversation-binding-data-CrcyZk6O.mjs → conversation-binding-data-C746z5Pn.mjs} +8 -12
  35. package/dist/.setup/{conversation-control-DN53ns41.mjs → conversation-control-CEP8X5JC.mjs} +30 -69
  36. package/dist/.setup/{cyber-failover-DYwbmf1o.mjs → cyber-failover-XV0nNRZu.mjs} +1 -1
  37. package/dist/.setup/{cyber-failover-notice-e9G3J9-e.mjs → cyber-failover-notice-RNpGpTyP.mjs} +1 -1
  38. package/dist/.setup/{dynamic-tools-D16lOp67.mjs → dynamic-tools-DzlsLUuS.mjs} +3136 -3167
  39. package/dist/.setup/{effective-mcp-catalog-K6kLCN8X.mjs → effective-mcp-catalog-CxUtC-xG.mjs} +8 -17
  40. package/dist/.setup/{ephemeral-turn-R1gA8Sn6.mjs → ephemeral-turn-CDsPJOa2.mjs} +9 -6
  41. package/dist/.setup/event-projector-assistant-message-CigreO4K.mjs +69 -0
  42. package/dist/.setup/{event-projector-usage-C7Ntzs-f.mjs → event-projector-usage-03R0I2dM.mjs} +4 -26
  43. package/dist/.setup/event-projector-values-DJSz8BTk.mjs +106 -0
  44. package/dist/.setup/incognito-session-DWYapfwf.mjs +2 -0
  45. package/dist/.setup/{inference-context-fulhZuz8.mjs → inference-context-D-9gWlTR.mjs} +16 -18
  46. package/dist/.setup/inference-dispatch-CMZtjQyz.mjs +359 -0
  47. package/dist/.setup/inference-metadata-CgIf7sOx.mjs +81 -0
  48. package/dist/.setup/inference-proxy-DhcXOgUE.mjs +561 -0
  49. package/dist/.setup/{isolated-completion-B6srt48J.mjs → isolated-completion-Dm3PzxJk.mjs} +15 -11
  50. package/dist/.setup/launch-args-DbFCehO7.mjs +196 -0
  51. package/dist/.setup/{managed-binary-DP6Rib3P.mjs → managed-binary-kiWRhNRE.mjs} +16 -9
  52. package/dist/.setup/{model-catalog-DkvUuBey.mjs → model-catalog-PAuZgJC6.mjs} +14 -14
  53. package/dist/.setup/model-runtime-BdqzOMkU.mjs +11 -0
  54. package/dist/.setup/{models-BDFgm_G-.mjs → models-DHXZtVVk.mjs} +9 -18
  55. package/dist/.setup/{native-auth-BLZGqFjw.mjs → native-auth-CuG53tu4.mjs} +5 -5
  56. package/dist/.setup/{native-execution-policy-YBMHSzC4.mjs → native-execution-policy-BxZJy5mP.mjs} +6 -31
  57. package/dist/.setup/{native-subagent-monitor-B1hxzIOy.mjs → native-subagent-monitor-Dpsmf2wz.mjs} +4422 -3808
  58. package/dist/.setup/native-subagent-pending-assignments-DwkCzLvD.mjs +203 -0
  59. package/dist/.setup/native-task-assignments-DMQ0g3hu.mjs +194 -0
  60. package/dist/.setup/{node-cli-sessions-Cl8b2ZF3.mjs → node-cli-sessions-HC4W6FLI.mjs} +99 -111
  61. package/dist/.setup/node-exec-server.runtime-BgBfWQqo.mjs +244 -0
  62. package/dist/.setup/{plan-xD7WKYTM.mjs → plan-Y-QIvrKB.mjs} +118 -163
  63. package/dist/.setup/{plugin-activation-r8nq5Jzp.mjs → plugin-activation-cNHRfaxU.mjs} +10 -47
  64. package/dist/.setup/{plugin-app-cache-key-BOxKP7db.mjs → plugin-app-cache-key-BL9B5H0L.mjs} +9 -42
  65. package/dist/.setup/{plugin-inventory-DUle8DLz.mjs → plugin-inventory-Cky2XJUw.mjs} +32 -23
  66. package/dist/.setup/{plugin-marketplace-discovery-P-Vndfqq.mjs → plugin-marketplace-discovery-D_dV9FXa.mjs} +22 -25
  67. package/dist/.setup/{plugin-metadata-cache-DsS5buNa.mjs → plugin-metadata-cache-DsjsL1dr.mjs} +328 -318
  68. package/dist/.setup/protocol-CANUwXJ3.mjs +17 -0
  69. package/dist/.setup/provider-DH8NSzGt.mjs +51 -0
  70. package/dist/.setup/{provider-capabilities-B8J4Dy-O.mjs → provider-capabilities-CAxoF-X1.mjs} +35 -12
  71. package/dist/.setup/{rate-limits-DOEGYRNs.mjs → rate-limits-B7-X2TgG.mjs} +123 -166
  72. package/dist/.setup/{request-BioXJLYa.mjs → request-BHZ1nz8d.mjs} +25 -16
  73. package/dist/.setup/responses-oauth-twnuTaAa.mjs +93 -0
  74. package/dist/.setup/rpc-error-BlD2vuzn.mjs +31 -0
  75. package/dist/.setup/{run-attempt-rlA07pUv.mjs → run-attempt-D8RZUOzY.mjs} +2046 -1454
  76. package/dist/.setup/{run-attempt-lifecycle-B7JbY4-F.mjs → run-attempt-lifecycle-C-6O3Exn.mjs} +10 -24
  77. package/dist/.setup/{runtime-artifact-Dy38Z5iU.mjs → runtime-artifact-DDQ-HGXf.mjs} +43 -47
  78. package/dist/.setup/runtime-artifact-connection-D68qQn1m.mjs +78 -0
  79. package/dist/.setup/sandbox-guard-DjCz2eOw.mjs +126 -0
  80. package/dist/.setup/scope-DOC1Xjc8.mjs +6 -0
  81. package/dist/.setup/session-binding-DGCYAfvD.mjs +443 -0
  82. package/dist/.setup/{session-binding-record-TH3xA0zj.mjs → session-binding-record-Oe9L-CNY.mjs} +73 -132
  83. package/dist/.setup/{session-binding-sidecars-CKYEcfNn.mjs → session-binding-sidecars-jo6H8dFr.mjs} +242 -60
  84. package/dist/.setup/{session-catalog-fUdWDx-U.mjs → session-catalog-4sCdv5qx.mjs} +598 -452
  85. package/dist/.setup/{session-catalog-adoption-CR_whkEW.mjs → session-catalog-adoption-BU_pHWG7.mjs} +59 -26
  86. package/dist/.setup/{session-catalog-archive-CwZaPacf.mjs → session-catalog-archive-spHfihri.mjs} +7 -7
  87. package/dist/.setup/session-catalog-events-DePDzzjc.mjs +139 -0
  88. package/dist/.setup/session-catalog-home-id-vlih0B_g.mjs +22 -0
  89. package/dist/.setup/{session-catalog-index-B141u15s.mjs → session-catalog-index-CZvDzC6z.mjs} +286 -182
  90. package/dist/.setup/{session-catalog-index-order-Cc5BzlQr.mjs → session-catalog-index-order-BcQpHks3.mjs} +2 -2
  91. package/dist/.setup/{session-catalog-index-state-BAuDztHN.mjs → session-catalog-index-state-TeO7EyO-.mjs} +6 -2
  92. package/dist/.setup/session-catalog-limits-DDxOsQeC.mjs +14 -0
  93. package/dist/.setup/session-catalog-list-request-CvtxrYSe.mjs +170 -0
  94. package/dist/.setup/session-catalog-native-projection-DjhwGL6x.mjs +178 -0
  95. package/dist/.setup/{session-catalog-node-adoption-BVRsYOSh.mjs → session-catalog-node-adoption-DgXvSGu0.mjs} +30 -35
  96. package/dist/.setup/{session-catalog-node-continue-Dowv8osw.mjs → session-catalog-node-continue-DjKXHBbi.mjs} +25 -18
  97. package/dist/.setup/session-catalog-node-lookup-CtAXI5W5.mjs +56 -0
  98. package/dist/.setup/{session-catalog-native-projection-ChV3cCtm.mjs → session-catalog-parsing-CPGaPYr-.mjs} +14 -180
  99. package/dist/.setup/{session-catalog-projection-C1Bj9Jl-.mjs → session-catalog-projection-Cr5qP5Dj.mjs} +15 -5
  100. package/dist/.setup/session-catalog-provenance-DoAvktcj.mjs +95 -0
  101. package/dist/.setup/{session-cli-DIj-IE-E.mjs → session-cli-Cn_nCqfq.mjs} +11 -24
  102. package/dist/.setup/{session-history-C--SrLI8.mjs → session-history-D83lJWHG.mjs} +16 -23
  103. package/dist/.setup/{session-history-import-JHXT5Xfi.mjs → session-history-import-WhX-X33a.mjs} +7 -10
  104. package/dist/.setup/session-history-read-Ov3StuL4.mjs +133 -0
  105. package/dist/.setup/{session-history.worker-CpNj7H_P.mjs → session-history.worker-MnPKncqP.mjs} +14 -23
  106. package/dist/.setup/session-initialization-6aveB9qb.mjs +22 -0
  107. package/dist/.setup/{session-permission-policy-DhurXY0l.mjs → session-permission-policy-Ci_fVX6y.mjs} +4 -8
  108. package/dist/.setup/{session-retirement-CU87AOg9.mjs → session-retirement-qMTxkNx2.mjs} +31 -12
  109. package/dist/.setup/{settled-turn-context-fmwouT5I.mjs → settled-turn-context-D4yj4rxf.mjs} +1 -1
  110. package/dist/.setup/{settled-turn-finalizer-CiY2bLFK.mjs → settled-turn-finalizer-BsvEabkw.mjs} +17 -13
  111. package/dist/.setup/{shared-client-BpTtuLQ5.mjs → shared-client-DqyTMYug.mjs} +826 -485
  112. package/dist/.setup/shared-client-lifecycle-DJIgqgMw.mjs +153 -0
  113. package/dist/.setup/{side-question-DSCZyoBD.mjs → side-question-C4kCmQy1.mjs} +206 -334
  114. package/dist/.setup/{source-Bjp4UQij.mjs → source-CS_7GFJZ.mjs} +82 -139
  115. package/dist/.setup/spawn-error-CL3n6MAa.mjs +57 -0
  116. package/dist/.setup/{thread-archive-guard-jmecf6OJ.mjs → thread-archive-guard-C9frICzX.mjs} +10 -3
  117. package/dist/.setup/thread-lifecycle-DPflntEJ.mjs +2362 -0
  118. package/dist/.setup/{incognito-session-uhrBF6wJ.mjs → thread-ownership-queue-Dp24d7-F.mjs} +1 -2
  119. package/dist/.setup/{thread-ownership-skomxnIt.mjs → thread-ownership-roNP0l1c.mjs} +47 -10
  120. package/dist/.setup/thread-policy-DTd-DtkX.mjs +109 -0
  121. package/dist/.setup/thread-requests-B_bRnMGN.mjs +2102 -0
  122. package/dist/.setup/{thread-resume-BkNpj9Pz.mjs → thread-resume-CdDaoc7T.mjs} +6 -6
  123. package/dist/.setup/timeout-CXOfNoaX.mjs +46 -0
  124. package/dist/.setup/transcript-history-projection-DRSifI-1.mjs +201 -0
  125. package/dist/.setup/{transcript-mirror-attestation-CzM-94NC.mjs → transcript-mirror-attestation-YSegaktH.mjs} +3 -4
  126. package/dist/.setup/{transcript-mirror-D4qp_leP.mjs → transcript-mirror-kxmCYsuF.mjs} +224 -206
  127. package/dist/.setup/{transport-stdio-Cmx94Oiy.mjs → transport-stdio-Bdegpn2V.mjs} +138 -75
  128. package/dist/.setup/transport-websocket-BTBE-LD9.mjs +211 -0
  129. package/dist/.setup/{upstream-prompt-provenance-LphB8slG.mjs → upstream-prompt-provenance-fXkKbPVC.mjs} +3 -9
  130. package/dist/.setup/{upstream-session-fork-D3UKxgVD.mjs → upstream-session-fork-CBeVjBpT.mjs} +48 -40
  131. package/dist/.setup/{usage-BOgBEKso.mjs → usage-BMzNxeR_.mjs} +5 -4
  132. package/dist/.setup/{usage-limit-error-C0ow7DOc.mjs → usage-limit-error-QXerDo3i.mjs} +5 -20
  133. package/dist/.setup/{web-search-provider.runtime-CTGuJt6i.mjs → web-search-provider.runtime-P77OUeoo.mjs} +10 -20
  134. package/dist/api.js +25 -16
  135. package/dist/catalog-page-worker-entrypoint.js +12 -0
  136. package/dist/catalog-page.worker.js +9 -0
  137. package/dist/cli-metadata.js +1 -1
  138. package/dist/doctor-contract-api.js +50 -8
  139. package/dist/harness.js +344 -1
  140. package/dist/index.js +345 -346
  141. package/dist/media-understanding-provider.js +9 -22
  142. package/dist/migration-provider-api.js +1 -1
  143. package/dist/provider-discovery.js +1 -1
  144. package/dist/session-history-worker-runtime.js +16 -33
  145. package/dist/session-history.worker.js +1 -1
  146. package/openclaw.plugin.json +14 -2
  147. package/package.json +11 -7
  148. package/dist/.setup/attempt-context-VXVwTCfS.mjs +0 -636
  149. package/dist/.setup/compact-C3i3qlzj.mjs +0 -687
  150. package/dist/.setup/event-projector-assistant-message-DNUR1s0A.mjs +0 -105
  151. package/dist/.setup/event-projector-items-DyTQ_XqL.mjs +0 -200
  152. package/dist/.setup/harness-rxaaoN-o.mjs +0 -349
  153. package/dist/.setup/history-rejection-B4nOXNXF.mjs +0 -13
  154. package/dist/.setup/image-payload-sanitizer-tupAr-2o.mjs +0 -79
  155. package/dist/.setup/inference-proxy-CC15HuSi.mjs +0 -311
  156. package/dist/.setup/launch-args-DnMak49W.mjs +0 -111
  157. package/dist/.setup/local-runtime-attribution-B_2mnqhb.mjs +0 -19
  158. package/dist/.setup/native-subagent-history-YXaL6dMd.mjs +0 -135
  159. package/dist/.setup/native-subagent-task-ids-DsuOonKv.mjs +0 -411
  160. package/dist/.setup/node-exec-server.runtime-BaViBKNz.mjs +0 -226
  161. package/dist/.setup/plugin-approval-roundtrip-CjfzafAZ.mjs +0 -122
  162. package/dist/.setup/provider-fFh_-VR3.mjs +0 -50
  163. package/dist/.setup/rolldown-runtime-8H4AJuhK.mjs +0 -14
  164. package/dist/.setup/sandbox-guard-BBP-RbTf.mjs +0 -166
  165. package/dist/.setup/session-binding-_0W_fHRr.mjs +0 -721
  166. package/dist/.setup/session-catalog-events-jMcYfQyd.mjs +0 -250
  167. package/dist/.setup/session-history-read-B3ZfSUbF.mjs +0 -50
  168. package/dist/.setup/session-initialization-DH1z6fXn.mjs +0 -75
  169. package/dist/.setup/thread-history-page-BTx-4xsg.mjs +0 -83
  170. package/dist/.setup/thread-lifecycle-Cik28qWn.mjs +0 -4904
  171. package/dist/.setup/thread-policy-Cjs4B8xf.mjs +0 -54
  172. package/dist/.setup/timeout-DZF05XrR.mjs +0 -63
  173. package/dist/.setup/transcript-history-projection-DHNBDhCU.mjs +0 -243
  174. package/dist/.setup/version-CoqzXPgK.mjs +0 -12
@@ -1,102 +1,93 @@
1
- import { n as isCodexFastServiceTier } from "./config-utils-DujwEnhg.mjs";
2
- import { c as CODEX_PLUGINS_MARKETPLACE_NAME, i as pluginReadParams, r as isOpenAiCuratedMarketplaceName, t as findCodexMarketplacePluginSummary } from "./plugin-inventory-DUle8DLz.mjs";
3
- import { n as assertCodexBindingMayBeReplaced, p as sessionBindingIdentity, r as bindingStoreKey } from "./session-binding-record-TH3xA0zj.mjs";
4
- import { m as isJsonObject } from "./config-security-BRQ2mgW9.mjs";
5
- import { _ as assertCodexThreadAcceptsDirectInput, s as isCodexAppServerIndeterminateRequestCancellationError, u as isCodexAppServerPrewriteRequestCancellationError, y as assertCodexThreadResumeResponse } from "./client-vXs2929Q.mjs";
6
- import { c as resolveCodexAppServerPreparedApiKeyCacheKey, s as resolveCodexAppServerFallbackApiKeyCacheKey } from "./auth-cache-key-QirmgiCo.mjs";
7
- import { r as withCodexConversationThreadActivity, t as isIncognitoSessionKey } from "./incognito-session-uhrBF6wJ.mjs";
8
- import { a as CODEX_HOST_INSPECTION_AUTH_ERROR, c as hasCodexAdminScope, i as CODEX_FULL_PERMISSIONS_AUTH_ERROR, n as filterCodexMarketplacePlugins, o as CODEX_NATIVE_EXECUTION_AUTH_ERROR, r as parseCodexPluginMarketplaceId, s as canMutateCodexHost, t as discoverCodexMarketplacePlugins } from "./plugin-marketplace-discovery-P-Vndfqq.mjs";
9
- import { s as summarizeCodexAccountUsage } from "./rate-limits-DOEGYRNs.mjs";
10
- import { a as formatCodexAccountLine, c as formatCodexTextForDisplay, d as formatModels, f as formatSkills, i as formatAccount, l as formatComputerUseStatus, n as buildHelp, o as formatCodexDisplayText, p as formatThreads, r as escapeCodexChatText, s as formatCodexStatus, t as CODEX_RESUME_SAFE_THREAD_ID_PATTERN, u as formatList } from "./command-formatters-CGEkdawF.mjs";
11
- import { i as readCodexConversationBindingData, n as createCodexCliNodeConversationBindingData, o as resolveCodexDefaultWorkspaceDir, r as createCodexConversationBindingData } from "./conversation-binding-data-CrcyZk6O.mjs";
12
- import { i as CodexAppServerRpcError } from "./timeout-DZF05XrR.mjs";
13
- import { t as CODEX_CONTROL_METHODS } from "./capabilities-_vXcZGSx.mjs";
14
- import { i as formatCodexCliSessions } from "./node-cli-sessions-Cl8b2ZF3.mjs";
15
- import { a as defaultCodexAppInventoryCache, r as buildCodexPluginAppCacheKey } from "./plugin-app-cache-key-BOxKP7db.mjs";
16
- import { i as resolveCodexBindingAppServerConnection } from "./binding-connection-Bm38niE8.mjs";
17
- import { o as withCodexAppServerJsonClient } from "./request-BioXJLYa.mjs";
18
- import "./config-CedDWjM-.mjs";
19
- import { n as resolveCodexAppServerRuntimeOptions } from "./config-runtime-CeAhl_h4.mjs";
20
- import { a as resolveCodexAppServerAuthProfileStore, i as resolveCodexAppServerAuthProfileIdForAgent, n as normalizeCodexAppServerBindingModelProvider } from "./auth-profile-WqZtZfXN.mjs";
21
- import { n as fingerprintCodexAppServerAuthBinding } from "./auth-binding-DhLWa_7K.mjs";
22
- import { I as hasCodexAppServerLiveThread, N as consumeCodexAppServerLiveThread, X as resolveCodexAppServerAuthAccountCacheKey, c as getLeasedSharedCodexAppServerClient, h as releaseLeasedSharedCodexAppServerClient } from "./shared-client-BpTtuLQ5.mjs";
23
- import { a as closeCodexStartupClientBestEffort } from "./attempt-client-cleanup-BpYKdTA0.mjs";
24
- import { t as listAllCodexAppServerModels } from "./models-BDFgm_G-.mjs";
25
- import { n as refreshCodexAppRuntimeState, r as refreshCodexPluginRuntimeState } from "./plugin-activation-r8nq5Jzp.mjs";
26
- import { n as createCodexSessionGenerationSupersededError, o as resolveCodexSessionBinding } from "./session-binding-_0W_fHRr.mjs";
27
- import { r as assertCodexSupervisionThreadLineage } from "./thread-policy-Cjs4B8xf.mjs";
28
- import { a as rollbackCodexAppServerBindingSubscription, i as retireCodexConversationThreadBinding, n as releaseCodexAppServerBindingSubscription, r as retainCodexAppServerBindingSubscription, s as withExclusiveCodexAppServerThread, t as isSameCodexAppServerThreadOwner } from "./thread-ownership-skomxnIt.mjs";
29
- import { n as resolveCodexNativeSandboxBlock, t as resolveCodexNativeExecutionBlock } from "./sandbox-guard-BBP-RbTf.mjs";
30
- import { i as readCodexComputerUseStatus, r as installCodexComputerUse, t as defaultCodexPluginMetadataCache } from "./plugin-metadata-cache-DsS5buNa.mjs";
31
- import { a as requestOptions, i as readCodexStatusProbes, o as safeCodexControlRequest, r as prepareCodexControlSessionAuth, t as codexControlRequest } from "./command-rpc-DHFpn4le.mjs";
32
- import { a as setCodexConversationFastMode, c as steerCodexConversationTurn, i as readCodexConversationActiveTurn, l as stopCodexConversationTurn, n as parseCodexFastModeArg, o as setCodexConversationModel, r as parseCodexPermissionsModeArg, s as setCodexConversationPermissions, t as formatPermissionsMode } from "./conversation-control-DN53ns41.mjs";
1
+ import { n as isCodexFastServiceTier } from "./config-utils-D0CXecki.mjs";
2
+ import { o as pluginReadParams, r as isOpenAiCuratedMarketplaceName, t as findCodexMarketplacePluginSummary, u as CODEX_PLUGINS_MARKETPLACE_NAME } from "./plugin-inventory-Cky2XJUw.mjs";
3
+ import { i as isJsonObject } from "./protocol-CANUwXJ3.mjs";
4
+ import { n as assertCodexBindingMayBeReplaced, r as bindingStoreKey, v as sessionBindingIdentity } from "./session-binding-record-Oe9L-CNY.mjs";
5
+ import { c as resolveCodexAppServerPreparedApiKeyCacheKey, s as resolveCodexAppServerFallbackApiKeyCacheKey } from "./auth-cache-key-Dbvq-QgB.mjs";
6
+ import { n as withCodexConversationThreadActivity } from "./thread-ownership-queue-Dp24d7-F.mjs";
7
+ import { a as CODEX_HOST_INSPECTION_AUTH_ERROR, c as canMutateCodexHost, i as CODEX_FULL_PERMISSIONS_AUTH_ERROR, l as hasCodexAdminScope, n as filterCodexMarketplacePlugins, o as CODEX_NATIVE_EXECUTION_AUTH_ERROR, r as parseCodexPluginMarketplaceId, s as assertCodexHostOwnerCurrent, t as discoverCodexMarketplacePlugins } from "./plugin-marketplace-discovery-D_dV9FXa.mjs";
8
+ import { l as formatRelativeDuration, s as summarizeCodexAccountUsage } from "./rate-limits-B7-X2TgG.mjs";
9
+ import { a as formatCodexAccountLine, c as formatCodexTextForDisplay, d as formatModels, f as formatSkills, i as formatAccount, l as formatComputerUseStatus, n as buildHelp, o as formatCodexDisplayText, p as formatThreads, r as escapeCodexChatText, s as formatCodexStatus, t as CODEX_RESUME_SAFE_THREAD_ID_PATTERN, u as formatList } from "./command-formatters-R3ckE3Co.mjs";
10
+ import { i as readCodexConversationBindingData, n as createCodexCliNodeConversationBindingData, o as resolveCodexDefaultWorkspaceDir, r as createCodexConversationBindingData } from "./conversation-binding-data-C746z5Pn.mjs";
11
+ import { t as isIncognitoSessionKey } from "./incognito-session-DWYapfwf.mjs";
12
+ import { n as CodexAppServerRpcError } from "./rpc-error-BlD2vuzn.mjs";
13
+ import { t as CODEX_CONTROL_METHODS } from "./capabilities-B3WEZl4e.mjs";
14
+ import { o as formatCodexCliSessions } from "./node-cli-sessions-HC4W6FLI.mjs";
15
+ import { a as defaultCodexAppInventoryCache, r as buildCodexPluginAppCacheKey } from "./plugin-app-cache-key-BL9B5H0L.mjs";
16
+ import { i as resolveCodexBindingAppServerConnection } from "./binding-connection-DTtN1KrX.mjs";
17
+ import { o as withCodexAppServerJsonClient } from "./request-BHZ1nz8d.mjs";
18
+ import "./config-DKhXquav.mjs";
19
+ import { n as resolveCodexAppServerRuntimeOptions } from "./config-runtime-C0NbLms1.mjs";
20
+ import { a as resolveCodexAppServerAuthProfileStore, i as resolveCodexAppServerAuthProfileIdForAgent, n as normalizeCodexAppServerBindingModelProvider } from "./auth-profile-B0okYl2D.mjs";
21
+ import { F as consumeCodexAppServerLiveThread, R as hasCodexAppServerLiveThread, c as getLeasedSharedCodexAppServerClient, et as resolveCodexAppServerAuthAccountCacheKey, h as releaseLeasedSharedCodexAppServerClient } from "./shared-client-DqyTMYug.mjs";
22
+ import { b as assertCodexThreadResumeResponse, s as isCodexAppServerIndeterminateRequestCancellationError, u as isCodexAppServerPrewriteRequestCancellationError, v as assertCodexThreadAcceptsDirectInput } from "./client-N0JpgSzF.mjs";
23
+ import { o as closeCodexStartupClientBestEffort } from "./attempt-client-cleanup-DOP-cW5j.mjs";
24
+ import { n as fingerprintCodexAppServerAuthBinding } from "./auth-binding-BLWz7stm.mjs";
25
+ import { n as listAllCodexAppServerModels } from "./models-DHXZtVVk.mjs";
26
+ import { n as refreshCodexAppRuntimeState, r as refreshCodexPluginRuntimeState } from "./plugin-activation-cNHRfaxU.mjs";
27
+ import { n as createCodexSessionGenerationSupersededError, o as resolveCodexSessionBinding } from "./session-binding-DGCYAfvD.mjs";
28
+ import { i as assertCodexSupervisionThreadLineage } from "./thread-policy-DTd-DtkX.mjs";
29
+ import { a as rollbackCodexAppServerBindingSubscription, c as withExclusiveCodexAppServerThread, i as retireCodexConversationThreadBinding, n as releaseCodexAppServerBindingSubscription, r as retainCodexAppServerBindingSubscription, t as isSameCodexAppServerThreadOwner } from "./thread-ownership-roNP0l1c.mjs";
30
+ import { n as resolveCodexNativeSandboxBlock, t as resolveCodexNativeExecutionBlock } from "./sandbox-guard-DjCz2eOw.mjs";
31
+ import { i as readCodexComputerUseStatus, r as installCodexComputerUse, t as defaultCodexPluginMetadataCache } from "./plugin-metadata-cache-DsjsL1dr.mjs";
32
+ import { a as requestOptions, i as readCodexStatusProbes, o as safeCodexControlRequest, r as prepareCodexControlSessionAuth, t as codexControlRequest } from "./command-rpc-CGJGUQ6Y.mjs";
33
+ import { a as setCodexConversationFastMode, c as steerCodexConversationTurn, i as readCodexConversationActiveTurn, l as stopCodexConversationTurn, n as parseCodexFastModeArg, o as setCodexConversationModel, r as parseCodexPermissionsModeArg, s as setCodexConversationPermissions, t as formatPermissionsMode } from "./conversation-control-CEP8X5JC.mjs";
33
34
  import { normalizeOptionalString, normalizeUniqueStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
34
35
  import crypto from "node:crypto";
35
36
  import { isDeepStrictEqual } from "node:util";
36
37
  import { resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
37
38
  import { parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
39
+ import { coerceErrorMessage } from "openclaw/plugin-sdk/error-runtime";
38
40
  import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
41
+ import { parseAgentSessionKey } from "openclaw/plugin-sdk/routing";
39
42
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
40
43
  import { ensureAuthProfileStore, resolveAgentDir as resolveAgentDir$1, resolveAgentWorkspaceDir, resolveAuthProfileEligibility, resolveProfileUnusableUntilForDisplay } from "openclaw/plugin-sdk/agent-runtime";
41
44
  import { getSessionEntry, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
42
45
  import { findNormalizedProviderValue, resolveAuthProfileOrder } from "openclaw/plugin-sdk/provider-auth";
43
- import { parseAgentSessionKey } from "openclaw/plugin-sdk/routing";
44
46
  import { renderMessagePresentationFallbackText } from "openclaw/plugin-sdk/interactive-runtime";
45
47
  import { MODEL_SELECTION_LOCKED_MESSAGE, isModelSelectionLocked, resolvePersistedSessionRuntimeId } from "openclaw/plugin-sdk/model-session-runtime";
46
48
  //#region extensions/codex/src/command-account.ts
47
49
  const OPENAI_PROVIDER_ID = "openai";
48
- const OPENAI_CODEX_PROVIDER_ID = OPENAI_PROVIDER_ID;
49
50
  async function readCodexAccountAuthOverview(params) {
51
+ if (!params.account.ok && !params.limits.ok) return;
50
52
  const config = params.ctx.config;
51
53
  const agentDir = params.agentDir;
52
54
  const store = ensureAuthProfileStore(agentDir, {
53
55
  allowKeychainPrompt: false,
54
56
  config
55
57
  });
56
- const { order, explicit: explicitOrder } = resolveDisplayAuthOrder({
58
+ const order = resolveDisplayAuthOrder({
57
59
  config,
58
60
  store
59
61
  });
62
+ const activeProfileId = params.authProfileId ?? void 0;
63
+ if (activeProfileId && !order.includes(activeProfileId)) order.unshift(activeProfileId);
60
64
  if (order.length === 0) return;
61
65
  const now = Date.now();
62
- const activeProfileId = resolveActiveProfileId({
63
- store,
64
- order,
65
- explicitOrder,
66
- config,
67
- account: params.account,
68
- limits: params.limits,
69
- now
70
- });
71
66
  const activeIsSubscription = activeProfileId !== void 0 && isChatGptSubscriptionProfile(store.profiles[activeProfileId]);
72
- const subscriptionProfileId = activeIsSubscription ? activeProfileId : order.find((profileId) => isChatGptSubscriptionProfile(store.profiles[profileId]));
67
+ const subscriptionProfileId = activeIsSubscription ? activeProfileId : activeProfileId ? order.find((profileId) => isChatGptSubscriptionProfile(store.profiles[profileId])) : void 0;
73
68
  const activeUsage = activeIsSubscription && params.limits.ok ? summarizeCodexAccountUsage(params.limits.value, now) : void 0;
74
- const subscriptionUsage = subscriptionProfileId && (!activeIsSubscription || subscriptionProfileId !== activeProfileId) ? await readSubscriptionUsage({
69
+ const subscriptionUsage = subscriptionProfileId && !activeIsSubscription ? await readSubscriptionUsage({
75
70
  ...params,
76
71
  agentDir,
77
72
  config,
78
73
  subscriptionProfileId,
79
74
  now
80
75
  }) : activeUsage;
81
- if (!params.account.ok && !params.limits.ok && !subscriptionUsage) return;
82
- const rows = order.map((profileId, index) => buildProfileRow({
76
+ const rows = order.map((profileId) => buildProfileRow({
83
77
  store,
84
78
  config,
85
79
  profileId,
86
80
  activeProfileId,
87
- activeIndex: activeProfileId ? order.indexOf(activeProfileId) : -1,
88
- index,
89
81
  now,
90
82
  usage: profileId === subscriptionProfileId ? subscriptionUsage : void 0
91
83
  }));
92
84
  const activeRow = rows.find((row) => row.active);
93
85
  if (!activeRow) return {
94
- currentLine: "OpenAI credentials: no working credential",
95
86
  orderTitle: "Auth order",
96
87
  rows
97
88
  };
98
89
  const activeIsApiKey = store.profiles[activeRow.profileId]?.type === "api_key";
99
- const subscriptionLabel = subscriptionProfileId ? formatProfileLabel(subscriptionProfileId, store.profiles[subscriptionProfileId]) : activeIsSubscription ? activeRow.label : void 0;
90
+ const subscriptionLabel = subscriptionProfileId ? formatProfileLabel(subscriptionProfileId, store.profiles[subscriptionProfileId]) : void 0;
100
91
  const subscriptionUsageLine = formatSubscriptionUsageLine(subscriptionUsage);
101
92
  return {
102
93
  ...activeIsApiKey ? { currentLine: buildApiKeyActiveLine(activeRow, subscriptionUsage) } : {},
@@ -107,92 +98,13 @@ async function readCodexAccountAuthOverview(params) {
107
98
  };
108
99
  }
109
100
  function resolveDisplayAuthOrder(params) {
110
- const codexOrder = resolveOrder(params.store.order, OPENAI_CODEX_PROVIDER_ID) ?? resolveOrder(params.config?.auth?.order, OPENAI_CODEX_PROVIDER_ID);
111
- if (codexOrder && codexOrder.length > 0) return {
112
- order: normalizeUniqueStringEntries(codexOrder),
113
- explicit: true
114
- };
115
- return {
116
- order: resolveAuthProfileOrder({
117
- cfg: params.config,
118
- store: params.store,
119
- provider: OPENAI_CODEX_PROVIDER_ID
120
- }),
121
- explicit: hasExplicitOpenAiAuthOrder(params)
122
- };
123
- }
124
- function hasExplicitOpenAiAuthOrder(params) {
125
- const sources = [params.store.order, params.config?.auth?.order];
126
- for (const source of sources) {
127
- const codex = resolveOrder(source, OPENAI_CODEX_PROVIDER_ID);
128
- if (codex && codex.length > 0) return true;
129
- const openai = resolveOrder(source, OPENAI_PROVIDER_ID);
130
- if (openai && openai.length > 0) return true;
131
- }
132
- return false;
133
- }
134
- function resolveOrder(order, provider) {
135
- return findNormalizedProviderValue(order, provider);
136
- }
137
- function resolveActiveProfileId(params) {
138
- const liveProfileId = resolveLiveAccountProfileId({
139
- account: params.account,
140
- store: params.store,
141
- order: params.order
142
- });
143
- if (liveProfileId) return liveProfileId;
144
- if (params.explicitOrder) return params.order.find((profileId) => isActiveProfileCandidate(params, profileId) && resolveAuthProfileEligibility({
145
- cfg: params.config,
146
- store: params.store,
147
- provider: OPENAI_CODEX_PROVIDER_ID,
148
- profileId,
149
- now: params.now
150
- }).eligible);
151
- const lastGood = [params.store.lastGood?.[OPENAI_PROVIDER_ID], params.store.lastGood?.[OPENAI_CODEX_PROVIDER_ID]].find((profileId) => typeof profileId === "string" && params.order.includes(profileId) && isActiveProfileCandidate(params, profileId));
152
- if (lastGood) return lastGood;
153
- const mostRecent = params.order.map((profileId) => ({
154
- profileId,
155
- lastUsed: params.store.usageStats?.[profileId]?.lastUsed ?? 0
156
- })).filter((entry) => entry.lastUsed > 0 && isActiveProfileCandidate(params, entry.profileId)).toSorted((left, right) => right.lastUsed - left.lastUsed)[0]?.profileId;
157
- if (mostRecent) return mostRecent;
158
- if (shouldInferApiKeyActiveFromRateLimitProbe(params.limits)) {
159
- const apiKeyProfile = params.order.find((profileId) => params.store.profiles[profileId]?.type === "api_key");
160
- if (apiKeyProfile) return apiKeyProfile;
161
- }
101
+ const explicitOrder = findNormalizedProviderValue(params.store.order, OPENAI_PROVIDER_ID) ?? findNormalizedProviderValue(params.config?.auth?.order, OPENAI_PROVIDER_ID);
102
+ if (explicitOrder && explicitOrder.length > 0) return normalizeUniqueStringEntries(explicitOrder);
162
103
  return resolveAuthProfileOrder({
163
104
  cfg: params.config,
164
105
  store: params.store,
165
- provider: OPENAI_CODEX_PROVIDER_ID
166
- })[0];
167
- }
168
- function isActiveProfileCandidate(params, profileId) {
169
- return !isActiveUntil(resolveProfileUnusableUntilForDisplay(params.store, profileId) ?? void 0, params.now);
170
- }
171
- function resolveLiveAccountProfileId(params) {
172
- if (!params.account.ok || !isJsonObject(params.account.value)) return;
173
- const account = isJsonObject(params.account.value.account) ? params.account.value.account : params.account.value;
174
- const type = normalizeOptionalString(account.type)?.toLowerCase();
175
- if (type === "chatgpt") {
176
- const email = normalizeOptionalString(account.email)?.toLowerCase();
177
- const accountId = normalizeOptionalString(account.accountId ?? account.chatgptAccountId);
178
- const subscriptionProfiles = params.order.filter((profileId) => isChatGptSubscriptionProfile(params.store.profiles[profileId]));
179
- if (accountId) {
180
- const exactWorkspace = subscriptionProfiles.find((profileId) => {
181
- const credential = params.store.profiles[profileId];
182
- return credential && "accountId" in credential && credential.accountId === accountId;
183
- });
184
- if (exactWorkspace) return exactWorkspace;
185
- }
186
- const matchingProfiles = email ? subscriptionProfiles.filter((profileId) => {
187
- return (params.store.profiles[profileId]?.email?.trim().toLowerCase() ?? extractEmailFromProfileId(profileId))?.toLowerCase() === email;
188
- }) : subscriptionProfiles;
189
- const lastGood = params.store.lastGood?.[OPENAI_PROVIDER_ID];
190
- return (lastGood && matchingProfiles.includes(lastGood) ? lastGood : void 0) ?? matchingProfiles[0] ?? subscriptionProfiles[0];
191
- }
192
- if (type === "apikey" || type === "api_key") return params.order.find((profileId) => params.store.profiles[profileId]?.type === "api_key");
193
- }
194
- function shouldInferApiKeyActiveFromRateLimitProbe(limits) {
195
- return !limits.ok && limits.error.toLowerCase().includes("chatgpt authentication required");
106
+ provider: OPENAI_PROVIDER_ID
107
+ });
196
108
  }
197
109
  async function readSubscriptionUsage(params) {
198
110
  const limits = await params.safeCodexControlRequest(params.pluginConfig, CODEX_CONTROL_METHODS.rateLimits, void 0, {
@@ -209,13 +121,12 @@ function buildProfileRow(params) {
209
121
  const label = formatProfileLabel(params.profileId, credential);
210
122
  const kind = formatProfileKind(credential);
211
123
  const active = params.profileId === params.activeProfileId;
212
- const status = active ? "active now" : params.usage?.blocked ? formatUsageBlockedStatus(params.usage) : describeInactiveProfileStatus({
124
+ const status = active ? "active now" : params.usage?.blocked ? "rate-limited" : describeInactiveProfileStatus({
213
125
  store: params.store,
214
126
  config: params.config,
215
127
  profileId: params.profileId,
216
128
  credential,
217
- now: params.now,
218
- afterActive: params.activeIndex >= 0 && params.index > params.activeIndex
129
+ now: params.now
219
130
  });
220
131
  return {
221
132
  profileId: params.profileId,
@@ -223,22 +134,18 @@ function buildProfileRow(params) {
223
134
  kind,
224
135
  status,
225
136
  active,
226
- ...credential?.type === "api_key" && active ? { billingNote: "billed per token" } : {},
227
- ...params.usage?.usageLine ? { usage: params.usage.usageLine } : {}
137
+ ...credential?.type === "api_key" && active ? { billingNote: "billed per token" } : {}
228
138
  };
229
139
  }
230
- function formatUsageBlockedStatus(usage) {
231
- return usage.blocked ? "rate-limited" : "available if needed";
232
- }
233
140
  function describeInactiveProfileStatus(params) {
234
141
  const stats = params.store.usageStats?.[params.profileId];
235
142
  const blockedUntil = stats?.blockedUntil;
236
- if (isActiveUntil(blockedUntil, params.now)) return `rate-limited - resets ${formatRelativeReset(blockedUntil, params.now)}`;
143
+ if (isActiveUntil(blockedUntil, params.now)) return `rate-limited - resets in ${formatRelativeDuration(Math.max(6e4, blockedUntil - params.now))}`;
237
144
  if (isActiveUntil(resolveProfileUnusableUntilForDisplay(params.store, params.profileId) ?? void 0, params.now)) return describeFailureStatus(stats?.disabledReason ?? stats?.cooldownReason, params.credential);
238
145
  const eligibility = resolveAuthProfileEligibility({
239
146
  cfg: params.config,
240
147
  store: params.store,
241
- provider: OPENAI_CODEX_PROVIDER_ID,
148
+ provider: OPENAI_PROVIDER_ID,
242
149
  profileId: params.profileId,
243
150
  now: params.now
244
151
  });
@@ -324,22 +231,6 @@ function describeEligibilityStatus(reason, credential) {
324
231
  function isActiveUntil(value, now) {
325
232
  return typeof value === "number" && Number.isFinite(value) && value > now;
326
233
  }
327
- function formatRelativeReset(untilMs, nowMs) {
328
- const durationMs = Math.max(1e3, untilMs - nowMs);
329
- const minuteMs = 6e4;
330
- const hourMs = 60 * minuteMs;
331
- const dayMs = 24 * hourMs;
332
- if (durationMs < hourMs) {
333
- const minutes = Math.ceil(durationMs / minuteMs);
334
- return `in ${minutes} ${minutes === 1 ? "minute" : "minutes"}`;
335
- }
336
- if (durationMs < dayMs) {
337
- const hours = Math.ceil(durationMs / hourMs);
338
- return `in ${hours} ${hours === 1 ? "hour" : "hours"}`;
339
- }
340
- const days = Math.ceil(durationMs / dayMs);
341
- return `in ${days} ${days === 1 ? "day" : "days"}`;
342
- }
343
234
  function buildCodexPluginAppLinks(apps, options = {}) {
344
235
  const blocks = apps.slice(0, 5).map((app) => {
345
236
  const name = formatCodexDisplayText((app.name.trim() || app.id).slice(0, 80));
@@ -379,6 +270,24 @@ function buildCodexPluginAppLinks(apps, options = {}) {
379
270
  });
380
271
  return blocks;
381
272
  }
273
+ function buildCodexPluginStatusButtons(pluginId, canRefreshHostedApps) {
274
+ return {
275
+ type: "buttons",
276
+ buttons: [...canRefreshHostedApps ? [{
277
+ label: "Refresh hosted apps",
278
+ action: {
279
+ type: "command",
280
+ command: "/codex plugins refresh"
281
+ }
282
+ }] : [], {
283
+ label: "Check status",
284
+ action: {
285
+ type: "command",
286
+ command: `/codex plugins status ${pluginId}`
287
+ }
288
+ }]
289
+ };
290
+ }
382
291
  function safeCodexAppLink(value) {
383
292
  if (!value || value.length > 2048 || /[\s\p{Cc}\p{Cf}<>]/u.test(value)) return;
384
293
  try {
@@ -686,22 +595,7 @@ function formatCodexPluginReadiness(readiness, page = 1) {
686
595
  type: "text",
687
596
  text: "Flags reflect Codex's runtime snapshot; status does not refresh hosted tools. After connecting, /codex plugins refresh refreshes hosted inventory for the current Codex account/runtime, across all apps. Use Check status separately to inspect this plugin without refreshing. OpenClaw app-access changes take effect on your next message; use /new or /reset after connecting."
688
597
  });
689
- blocks.push({
690
- type: "buttons",
691
- buttons: [...canRefreshHostedApps ? [{
692
- label: "Refresh hosted apps",
693
- action: {
694
- type: "command",
695
- command: "/codex plugins refresh"
696
- }
697
- }] : [], {
698
- label: "Check status",
699
- action: {
700
- type: "command",
701
- command: `/codex plugins status ${readiness.commandId}`
702
- }
703
- }]
704
- });
598
+ blocks.push(buildCodexPluginStatusButtons(readiness.commandId, canRefreshHostedApps));
705
599
  }
706
600
  }
707
601
  const presentation = {
@@ -872,73 +766,59 @@ function buildCodexSubcommandPickerReply() {
872
766
  };
873
767
  }
874
768
  function buildCodexFastMenuReply() {
875
- const modes = [
876
- "on",
877
- "off",
878
- "status"
879
- ];
880
- const buttons = [...modes.map((mode) => ({
881
- label: mode,
882
- command: `/codex fast ${mode}`
883
- })), {
884
- label: "back",
885
- command: "/codex"
886
- }];
887
- return {
888
- text: [
889
- "Codex fast mode. Pick one or type /codex fast <mode>:",
890
- "",
891
- ...modes.map((m, i) => ` ${i + 1}. /codex fast ${m}`),
892
- "",
893
- "Type '/codex' to go back to the main menu."
894
- ].join("\n"),
895
- presentation: buildCodexCommandPickerPresentation("Codex fast mode", "Pick a Codex fast mode:", buttons)
896
- };
769
+ return buildCodexChoiceMenuReply({
770
+ title: "Codex fast mode",
771
+ prompt: "Pick a Codex fast mode:",
772
+ introduction: "Codex fast mode. Pick one or type /codex fast <mode>:",
773
+ command: "/codex fast",
774
+ choices: [
775
+ "on",
776
+ "off",
777
+ "status"
778
+ ]
779
+ });
897
780
  }
898
781
  function buildCodexPermissionsMenuReply() {
899
- const modes = [
900
- "default",
901
- "yolo",
902
- "status"
903
- ];
904
- const buttons = [...modes.map((mode) => ({
905
- label: mode,
906
- command: `/codex permissions ${mode}`
907
- })), {
908
- label: "back",
909
- command: "/codex"
910
- }];
911
- return {
912
- text: [
913
- "Codex permissions. Pick one or type /codex permissions <mode>:",
914
- "",
915
- ...modes.map((m, i) => ` ${i + 1}. /codex permissions ${m}`),
916
- "",
917
- "Type '/codex' to go back to the main menu."
918
- ].join("\n"),
919
- presentation: buildCodexCommandPickerPresentation("Codex permissions", "Pick a Codex permissions mode:", buttons)
920
- };
782
+ return buildCodexChoiceMenuReply({
783
+ title: "Codex permissions",
784
+ prompt: "Pick a Codex permissions mode:",
785
+ introduction: "Codex permissions. Pick one or type /codex permissions <mode>:",
786
+ command: "/codex permissions",
787
+ choices: [
788
+ "default",
789
+ "yolo",
790
+ "status"
791
+ ]
792
+ });
921
793
  }
922
794
  function buildCodexComputerUseMenuReply() {
923
- const actions = ["status", "install"];
924
- const buttons = [...actions.map((action) => ({
925
- label: action,
926
- command: `/codex computer-use ${action}`
795
+ return buildCodexChoiceMenuReply({
796
+ title: "Codex computer-use",
797
+ prompt: "Pick a Codex computer-use action:",
798
+ introduction: "Codex computer-use. Pick one or type /codex computer-use <action>:",
799
+ command: "/codex computer-use",
800
+ choices: ["status", "install"],
801
+ hint: "Flag-driven invocations (--source, --marketplace-path, --marketplace) are not in the picker. Type '/codex computer-use' or read '/codex help' for the full surface."
802
+ });
803
+ }
804
+ function buildCodexChoiceMenuReply(params) {
805
+ const buttons = [...params.choices.map((choice) => ({
806
+ label: choice,
807
+ command: `${params.command} ${choice}`
927
808
  })), {
928
809
  label: "back",
929
810
  command: "/codex"
930
811
  }];
931
812
  return {
932
813
  text: [
933
- "Codex computer-use. Pick one or type /codex computer-use <action>:",
934
- "",
935
- ...actions.map((a, i) => ` ${i + 1}. /codex computer-use ${a}`),
814
+ params.introduction,
936
815
  "",
937
- "Flag-driven invocations (--source, --marketplace-path, --marketplace) are not in the picker. Type '/codex computer-use' or read '/codex help' for the full surface.",
816
+ ...params.choices.map((choice, index) => ` ${index + 1}. ${params.command} ${choice}`),
938
817
  "",
818
+ ...params.hint ? [params.hint, ""] : [],
939
819
  "Type '/codex' to go back to the main menu."
940
820
  ].join("\n"),
941
- presentation: buildCodexCommandPickerPresentation("Codex computer-use", "Pick a Codex computer-use action:", buttons)
821
+ presentation: buildCodexCommandPickerPresentation(params.title, params.prompt, buttons)
942
822
  };
943
823
  }
944
824
  function isMenuVerb(rest) {
@@ -990,54 +870,18 @@ function splitArgs(value) {
990
870
  return args;
991
871
  }
992
872
  function parseBindArgs(args) {
993
- const parsed = {};
994
- for (let index = 0; index < args.length; index += 1) {
995
- const arg = expectDefined(args[index], "current Codex bind argument");
996
- if (arg === "--help" || arg === "-h") {
997
- parsed.help = true;
998
- continue;
999
- }
1000
- if (arg === "--cwd") {
1001
- const value = readRequiredOptionValue(args, index);
1002
- if (!value || parsed.cwd !== void 0) {
1003
- parsed.help = true;
1004
- continue;
1005
- }
1006
- parsed.cwd = value;
1007
- index += 1;
1008
- continue;
1009
- }
1010
- if (arg === "--model") {
1011
- const value = readRequiredOptionValue(args, index);
1012
- if (!value || parsed.model !== void 0) {
1013
- parsed.help = true;
1014
- continue;
1015
- }
1016
- parsed.model = value;
1017
- index += 1;
1018
- continue;
1019
- }
1020
- if (arg === "--provider" || arg === "--model-provider") {
1021
- const value = readRequiredOptionValue(args, index);
1022
- if (!value || parsed.provider !== void 0) {
1023
- parsed.help = true;
1024
- continue;
1025
- }
1026
- parsed.provider = value;
1027
- index += 1;
1028
- continue;
1029
- }
1030
- if (!arg.startsWith("-") && !parsed.threadId) {
1031
- parsed.threadId = arg;
1032
- continue;
1033
- }
1034
- parsed.help = true;
1035
- }
1036
- parsed.threadId = normalizeOptionalString(parsed.threadId);
1037
- parsed.cwd = normalizeOptionalString(parsed.cwd);
1038
- parsed.model = normalizeOptionalString(parsed.model);
1039
- parsed.provider = normalizeOptionalString(parsed.provider);
1040
- return parsed;
873
+ const { parsed, values } = parseThreadArgs(args, /* @__PURE__ */ new Map([
874
+ ["--cwd", "cwd"],
875
+ ["--model", "model"],
876
+ ["--provider", "provider"],
877
+ ["--model-provider", "provider"]
878
+ ]));
879
+ return {
880
+ ...parsed,
881
+ cwd: normalizeOptionalString(values.get("cwd")),
882
+ model: normalizeOptionalString(values.get("model")),
883
+ provider: normalizeOptionalString(values.get("provider"))
884
+ };
1041
885
  }
1042
886
  function parseCodexCliSessionsArgs(args) {
1043
887
  const parsed = { filter: "" };
@@ -1080,29 +924,34 @@ function parseCodexCliSessionsArgs(args) {
1080
924
  return parsed;
1081
925
  }
1082
926
  function parseResumeArgs(args) {
927
+ const { parsed, values } = parseThreadArgs(args, /* @__PURE__ */ new Map([
928
+ ["--host", "host"],
929
+ ["--node", "host"],
930
+ ["--bind", "bind"]
931
+ ]));
932
+ return {
933
+ ...parsed,
934
+ ...values.has("bind") ? { bindHere: true } : {},
935
+ host: normalizeOptionalString(values.get("host"))
936
+ };
937
+ }
938
+ function parseThreadArgs(args, options) {
1083
939
  const parsed = {};
940
+ const values = /* @__PURE__ */ new Map();
1084
941
  for (let index = 0; index < args.length; index += 1) {
1085
- const arg = expectDefined(args[index], "current Codex resume argument");
942
+ const arg = expectDefined(args[index], "current Codex thread argument");
1086
943
  if (arg === "--help" || arg === "-h") {
1087
944
  parsed.help = true;
1088
945
  continue;
1089
946
  }
1090
- if (arg === "--host" || arg === "--node") {
947
+ const option = options.get(arg);
948
+ if (option) {
1091
949
  const value = readRequiredOptionValue(args, index);
1092
- if (!value || parsed.host !== void 0) {
1093
- parsed.help = true;
1094
- continue;
1095
- }
1096
- parsed.host = value;
1097
- index += 1;
1098
- continue;
1099
- }
1100
- if (arg === "--bind") {
1101
- if (readRequiredOptionValue(args, index) !== "here" || parsed.bindHere !== void 0) {
950
+ if (!value || values.has(option) || option === "bind" && value !== "here") {
1102
951
  parsed.help = true;
1103
952
  continue;
1104
953
  }
1105
- parsed.bindHere = true;
954
+ values.set(option, value);
1106
955
  index += 1;
1107
956
  continue;
1108
957
  }
@@ -1113,8 +962,10 @@ function parseResumeArgs(args) {
1113
962
  parsed.help = true;
1114
963
  }
1115
964
  parsed.threadId = normalizeOptionalString(parsed.threadId);
1116
- parsed.host = normalizeOptionalString(parsed.host);
1117
- return parsed;
965
+ return {
966
+ parsed,
967
+ values
968
+ };
1118
969
  }
1119
970
  function parseComputerUseArgs(args) {
1120
971
  const parsed = {
@@ -1139,33 +990,14 @@ function parseComputerUseArgs(args) {
1139
990
  parsed.action = arg;
1140
991
  continue;
1141
992
  }
1142
- if (arg === "--source" || arg === "--marketplace-source") {
1143
- const value = readRequiredOptionValue(args, index);
1144
- if (!value || parsed.overrides.marketplaceSource !== void 0) {
1145
- parsed.help = true;
1146
- continue;
1147
- }
1148
- parsed.overrides.marketplaceSource = value;
1149
- index += 1;
1150
- continue;
1151
- }
1152
- if (arg === "--marketplace-path" || arg === "--path") {
993
+ const option = arg === "--source" || arg === "--marketplace-source" ? "marketplaceSource" : arg === "--marketplace-path" || arg === "--path" ? "marketplacePath" : arg === "--marketplace" ? "marketplaceName" : void 0;
994
+ if (option) {
1153
995
  const value = readRequiredOptionValue(args, index);
1154
- if (!value || parsed.overrides.marketplacePath !== void 0) {
996
+ if (!value || parsed.overrides[option] !== void 0) {
1155
997
  parsed.help = true;
1156
998
  continue;
1157
999
  }
1158
- parsed.overrides.marketplacePath = value;
1159
- index += 1;
1160
- continue;
1161
- }
1162
- if (arg === "--marketplace") {
1163
- const value = readRequiredOptionValue(args, index);
1164
- if (!value || parsed.overrides.marketplaceName !== void 0) {
1165
- parsed.help = true;
1166
- continue;
1167
- }
1168
- parsed.overrides.marketplaceName = value;
1000
+ parsed.overrides[option] = value;
1169
1001
  index += 1;
1170
1002
  continue;
1171
1003
  }
@@ -1182,8 +1014,19 @@ function parseComputerUseArgs(args) {
1182
1014
  }
1183
1015
  parsed.help = true;
1184
1016
  }
1185
- parsed.overrides = normalizeComputerUseStringOverrides(parsed.overrides);
1186
- parsed.hasOverrides = Object.values(parsed.overrides).some(Boolean);
1017
+ const overrides = parsed.overrides;
1018
+ parsed.overrides = {};
1019
+ for (const key of [
1020
+ "marketplaceSource",
1021
+ "marketplacePath",
1022
+ "marketplaceName"
1023
+ ]) {
1024
+ const value = normalizeOptionalString(overrides[key]);
1025
+ if (value) {
1026
+ parsed.overrides[key] = value;
1027
+ parsed.hasOverrides = true;
1028
+ }
1029
+ }
1187
1030
  return parsed;
1188
1031
  }
1189
1032
  function formatComputerUsePersistentIdentityMigration(parsed) {
@@ -1203,16 +1046,6 @@ function readRequiredOptionValue(args, index) {
1203
1046
  if (!normalized || normalized.startsWith("-")) return;
1204
1047
  return value;
1205
1048
  }
1206
- function normalizeComputerUseStringOverrides(overrides) {
1207
- const normalized = {};
1208
- const marketplaceSource = normalizeOptionalString(overrides.marketplaceSource);
1209
- if (marketplaceSource) normalized.marketplaceSource = marketplaceSource;
1210
- const marketplacePath = normalizeOptionalString(overrides.marketplacePath);
1211
- if (marketplacePath) normalized.marketplacePath = marketplacePath;
1212
- const marketplaceName = normalizeOptionalString(overrides.marketplaceName);
1213
- if (marketplaceName) normalized.marketplaceName = marketplaceName;
1214
- return normalized;
1215
- }
1216
1049
  //#endregion
1217
1050
  //#region extensions/codex/src/command-diagnostics-support.ts
1218
1051
  const CODEX_DIAGNOSTICS_SOURCE = "openclaw-diagnostics";
@@ -1232,16 +1065,11 @@ function normalizeDiagnosticsReason(note) {
1232
1065
  }
1233
1066
  function parseDiagnosticsArgs(args) {
1234
1067
  const [action, token, ...extra] = splitArgs(args);
1235
- const normalizedAction = action?.toLowerCase();
1236
- if ((normalizedAction === "confirm" || normalizedAction === "--confirm") && token && extra.length === 0) return {
1237
- action: "confirm",
1068
+ const normalizedAction = action?.toLowerCase().replace(/^--/, "");
1069
+ if (normalizedAction === "confirm" || normalizedAction === "cancel") return token && extra.length === 0 ? {
1070
+ action: normalizedAction,
1238
1071
  token
1239
- };
1240
- if ((normalizedAction === "cancel" || normalizedAction === "--cancel") && token && extra.length === 0) return {
1241
- action: "cancel",
1242
- token
1243
- };
1244
- if (normalizedAction === "confirm" || normalizedAction === "--confirm" || normalizedAction === "cancel" || normalizedAction === "--cancel") return { action: "usage" };
1072
+ } : { action: "usage" };
1245
1073
  return {
1246
1074
  action: "request",
1247
1075
  note: args
@@ -1297,27 +1125,14 @@ function readCodexDiagnosticsConfirmationScope(ctx) {
1297
1125
  }
1298
1126
  function readCodexDiagnosticsScopeMismatch(pending, ctx) {
1299
1127
  const current = readCodexDiagnosticsConfirmationScope(ctx);
1300
- if (pending.accountId !== current.accountId) return {
1301
- confirmMessage: "This Codex diagnostics confirmation belongs to a different account.",
1302
- cancelMessage: "This Codex diagnostics confirmation belongs to a different account."
1303
- };
1128
+ if (pending.accountId !== current.accountId) return "This Codex diagnostics confirmation belongs to a different account.";
1304
1129
  if (pending.privateRouted) return;
1305
- if (pending.channelId !== current.channelId) return {
1306
- confirmMessage: "This Codex diagnostics confirmation belongs to a different channel instance.",
1307
- cancelMessage: "This Codex diagnostics confirmation belongs to a different channel instance."
1308
- };
1309
- if (pending.messageThreadId !== current.messageThreadId) return {
1310
- confirmMessage: "This Codex diagnostics confirmation belongs to a different thread.",
1311
- cancelMessage: "This Codex diagnostics confirmation belongs to a different thread."
1312
- };
1313
- if (pending.threadParentId !== current.threadParentId) return {
1314
- confirmMessage: "This Codex diagnostics confirmation belongs to a different parent thread.",
1315
- cancelMessage: "This Codex diagnostics confirmation belongs to a different parent thread."
1316
- };
1317
- if (pending.sessionKey !== current.sessionKey) return {
1318
- confirmMessage: "This Codex diagnostics confirmation belongs to a different session.",
1319
- cancelMessage: "This Codex diagnostics confirmation belongs to a different session."
1320
- };
1130
+ for (const [field, label] of [
1131
+ ["channelId", "channel instance"],
1132
+ ["messageThreadId", "thread"],
1133
+ ["threadParentId", "parent thread"],
1134
+ ["sessionKey", "session"]
1135
+ ]) if (pending[field] !== current[field]) return `This Codex diagnostics confirmation belongs to a different ${label}.`;
1321
1136
  }
1322
1137
  function readPendingCodexDiagnosticsConfirmation(token, now) {
1323
1138
  prunePendingCodexDiagnosticsConfirmations(now);
@@ -1394,13 +1209,13 @@ function formatCodexDiagnosticsTargetLine(target) {
1394
1209
  }
1395
1210
  function readCodexDiagnosticsTargetsCooldownMessage(targets, ctx, now, options = {}) {
1396
1211
  for (const target of targets) {
1397
- const cooldownMs = readCodexDiagnosticsCooldownMs(target.threadId, now);
1212
+ const cooldownMs = readCodexDiagnosticsCooldownMs(lastCodexDiagnosticsUploadByThread, target.threadId, now);
1398
1213
  if (cooldownMs > 0) {
1399
1214
  if (options.includeThreadId === false) return `Codex diagnostics were already sent for one of these Codex threads recently. Try again in ${Math.ceil(cooldownMs / 1e3)}s.`;
1400
1215
  return `Codex diagnostics were already sent for thread ${formatCodexDisplayText(target.threadId)} recently. Try again in ${Math.ceil(cooldownMs / 1e3)}s.`;
1401
1216
  }
1402
1217
  }
1403
- const scopeCooldownMs = readCodexDiagnosticsScopeCooldownMs(options.cooldownScope ?? readCodexDiagnosticsCooldownScope(ctx), now);
1218
+ const scopeCooldownMs = readCodexDiagnosticsCooldownMs(lastCodexDiagnosticsUploadByScope, options.cooldownScope ?? readCodexDiagnosticsCooldownScope(ctx), now);
1404
1219
  if (scopeCooldownMs > 0) return `Codex diagnostics were already sent for this account or channel recently. Try again in ${Math.ceil(scopeCooldownMs / 1e3)}s.`;
1405
1220
  }
1406
1221
  function recordCodexDiagnosticsUpload(threadId, ctx, now, cooldownScope) {
@@ -1422,30 +1237,22 @@ function readCodexDiagnosticsCooldownScope(ctx) {
1422
1237
  return crypto.createHash("sha256").update(payload).digest("hex");
1423
1238
  }
1424
1239
  function buildDiagnosticsTags(ctx) {
1425
- const tags = { source: CODEX_DIAGNOSTICS_SOURCE };
1426
- addTag(tags, "channel", ctx.channel);
1427
- return tags;
1428
- }
1429
- function addTag(tags, key, value) {
1430
- if (typeof value === "string" && value.trim()) tags[key] = value.trim();
1240
+ const channel = normalizeOptionalString(ctx.channel);
1241
+ return {
1242
+ source: CODEX_DIAGNOSTICS_SOURCE,
1243
+ ...channel ? { channel } : {}
1244
+ };
1431
1245
  }
1432
1246
  function formatCodexCopyableValueForDisplay(value) {
1433
1247
  const safe = formatCodexTextForDisplay(value);
1434
1248
  if (CODEX_RESUME_SAFE_THREAD_ID_PATTERN.test(safe)) return `\`${safe}\``;
1435
1249
  return escapeCodexChatText(safe);
1436
1250
  }
1437
- function readCodexDiagnosticsCooldownMs(threadId, now) {
1438
- const lastSentAt = lastCodexDiagnosticsUploadByThread.get(threadId);
1251
+ function readCodexDiagnosticsCooldownMs(map, key, now) {
1252
+ const lastSentAt = map.get(key);
1439
1253
  if (!lastSentAt) return 0;
1440
1254
  const remainingMs = Math.max(0, CODEX_DIAGNOSTICS_COOLDOWN_MS - (now - lastSentAt));
1441
- if (remainingMs === 0) lastCodexDiagnosticsUploadByThread.delete(threadId);
1442
- return remainingMs;
1443
- }
1444
- function readCodexDiagnosticsScopeCooldownMs(scope, now) {
1445
- const lastSentAt = lastCodexDiagnosticsUploadByScope.get(scope);
1446
- if (!lastSentAt) return 0;
1447
- const remainingMs = Math.max(0, CODEX_DIAGNOSTICS_COOLDOWN_MS - (now - lastSentAt));
1448
- if (remainingMs === 0) lastCodexDiagnosticsUploadByScope.delete(scope);
1255
+ if (remainingMs === 0) map.delete(key);
1449
1256
  return remainingMs;
1450
1257
  }
1451
1258
  function recordBoundedCodexDiagnosticsCooldown(map, key, maxSize, now) {
@@ -1573,7 +1380,15 @@ async function resolvePreparedCodexCommandAuthority(deps, ctx) {
1573
1380
  sessionKey,
1574
1381
  storePath,
1575
1382
  assertHostCurrent,
1576
- assertCurrent
1383
+ assertCurrent,
1384
+ assertMutationCurrent: () => {
1385
+ assertCodexHostOwnerCurrent(ctx);
1386
+ assertCurrent();
1387
+ },
1388
+ assertHostMutationCurrent: () => {
1389
+ assertCodexHostOwnerCurrent(ctx);
1390
+ assertHostCurrent();
1391
+ }
1577
1392
  };
1578
1393
  }
1579
1394
  async function resolveCommandAppServerContext(deps, ctx, pluginConfig) {
@@ -1631,7 +1446,9 @@ function resolveCodexConversationControlScope(ctx) {
1631
1446
  }
1632
1447
  //#endregion
1633
1448
  //#region extensions/codex/src/command-diagnostics.ts
1634
- async function handleCodexDiagnosticsFeedback(deps, ctx, pluginConfig, args, commandPrefix) {
1449
+ const NO_DIAGNOSTICS_THREAD = ["No Codex thread is attached to this OpenClaw session yet.", "Use /codex threads to find a thread, then /codex resume <thread-id> before sending diagnostics."].join("\n");
1450
+ async function handleCodexDiagnosticsFeedback(deps, context, pluginConfig, args, commandPrefix) {
1451
+ const ctx = { ...context };
1635
1452
  if (ctx.senderIsOwner !== true) return { text: "Only an owner can send Codex diagnostics." };
1636
1453
  const parsed = parseDiagnosticsArgs(args);
1637
1454
  if (parsed.action === "usage") return { text: formatDiagnosticsUsage(commandPrefix) };
@@ -1642,9 +1459,8 @@ async function handleCodexDiagnosticsFeedback(deps, ctx, pluginConfig, args, com
1642
1459
  return await requestCodexDiagnosticsFeedbackApproval(deps, ctx, parsed.note, commandPrefix);
1643
1460
  }
1644
1461
  async function requestCodexDiagnosticsFeedbackApproval(deps, ctx, note, commandPrefix) {
1645
- if (!await hasAnyCodexDiagnosticsIdentity(ctx)) return { text: "Cannot send Codex diagnostics because this command did not include a stable session identity." };
1646
- const targets = await resolveCodexDiagnosticsTargets(deps, ctx);
1647
- if (targets.length === 0) return { text: ["No Codex thread is attached to this OpenClaw session yet.", "Use /codex threads to find a thread, then /codex resume <thread-id> before sending diagnostics."].join("\n") };
1462
+ const targets = await requireCodexDiagnosticsTargets(deps, ctx);
1463
+ if (typeof targets === "string") return { text: targets };
1648
1464
  const now = Date.now();
1649
1465
  const cooldownMessage = readCodexDiagnosticsTargetsCooldownMessage(targets, ctx, now);
1650
1466
  if (cooldownMessage) return { text: cooldownMessage };
@@ -1698,9 +1514,8 @@ async function requestCodexDiagnosticsFeedbackApproval(deps, ctx, note, commandP
1698
1514
  };
1699
1515
  }
1700
1516
  async function previewCodexDiagnosticsFeedbackApproval(deps, ctx, note) {
1701
- if (!await hasAnyCodexDiagnosticsIdentity(ctx)) return "Cannot send Codex diagnostics because this command did not include a stable session identity.";
1702
- const targets = await resolveCodexDiagnosticsTargets(deps, ctx);
1703
- if (targets.length === 0) return ["No Codex thread is attached to this OpenClaw session yet.", "Use /codex threads to find a thread, then /codex resume <thread-id> before sending diagnostics."].join("\n");
1517
+ const targets = await requireCodexDiagnosticsTargets(deps, ctx);
1518
+ if (typeof targets === "string") return targets;
1704
1519
  const cooldownMessage = readCodexDiagnosticsTargetsCooldownMessage(targets, ctx, Date.now(), { includeThreadId: false });
1705
1520
  if (cooldownMessage) return cooldownMessage;
1706
1521
  const reason = normalizeDiagnosticsReason(note);
@@ -1714,28 +1529,16 @@ async function previewCodexDiagnosticsFeedbackApproval(deps, ctx, note) {
1714
1529
  ].join("\n");
1715
1530
  }
1716
1531
  async function confirmCodexDiagnosticsFeedback(deps, ctx, pluginConfig, token) {
1717
- const pending = readPendingCodexDiagnosticsConfirmation(token, Date.now());
1718
- if (!pending) return "No pending Codex diagnostics confirmation was found. Run /diagnostics again to create a fresh request.";
1719
- if (!pending.senderId || !ctx.senderId) return "Cannot confirm Codex diagnostics because this command did not include the original sender identity.";
1720
- if (pending.senderId !== ctx.senderId) return "Only the user who requested these Codex diagnostics can confirm the upload.";
1721
- if (pending.channel !== ctx.channel) return "This Codex diagnostics confirmation belongs to a different channel.";
1722
- const scopeMismatch = readCodexDiagnosticsScopeMismatch(pending, ctx);
1723
- if (scopeMismatch) return scopeMismatch.confirmMessage;
1724
- deletePendingCodexDiagnosticsConfirmation(token);
1532
+ const pending = consumeCodexDiagnosticsConfirmation(ctx, token, "confirm");
1533
+ if (typeof pending === "string") return pending;
1725
1534
  if (!pending.privateRouted && !await hasAnyCodexDiagnosticsIdentity(ctx)) return "Cannot send Codex diagnostics because this command did not include a stable session identity.";
1726
1535
  const currentTargets = pending.privateRouted ? resolvePendingCodexDiagnosticsTargets(deps, pending.targets, ctx.config) : await resolveCodexDiagnosticsTargets(deps, ctx);
1727
1536
  if (!codexDiagnosticsTargetsMatch(pending.targets, currentTargets)) return "The Codex diagnostics sessions changed before confirmation. Run /diagnostics again for the current threads.";
1728
1537
  return await sendCodexDiagnosticsFeedbackForTargets(deps, ctx, pluginConfig, pending.note ?? "", currentTargets, { cooldownScope: pending.scopeKey });
1729
1538
  }
1730
1539
  function cancelCodexDiagnosticsFeedback(ctx, token) {
1731
- const pending = readPendingCodexDiagnosticsConfirmation(token, Date.now());
1732
- if (!pending) return "No pending Codex diagnostics confirmation was found.";
1733
- if (!pending.senderId || !ctx.senderId) return "Cannot cancel Codex diagnostics because this command did not include the original sender identity.";
1734
- if (pending.senderId !== ctx.senderId) return "Only the user who requested these Codex diagnostics can cancel the upload.";
1735
- if (pending.channel !== ctx.channel) return "This Codex diagnostics confirmation belongs to a different channel.";
1736
- const scopeMismatch = readCodexDiagnosticsScopeMismatch(pending, ctx);
1737
- if (scopeMismatch) return scopeMismatch.cancelMessage;
1738
- deletePendingCodexDiagnosticsConfirmation(token);
1540
+ const pending = consumeCodexDiagnosticsConfirmation(ctx, token, "cancel");
1541
+ if (typeof pending === "string") return pending;
1739
1542
  return [
1740
1543
  "Codex diagnostics upload canceled.",
1741
1544
  "Codex sessions:",
@@ -1743,13 +1546,12 @@ function cancelCodexDiagnosticsFeedback(ctx, token) {
1743
1546
  ].join("\n");
1744
1547
  }
1745
1548
  async function sendCodexDiagnosticsFeedbackForContext(deps, ctx, pluginConfig, note) {
1746
- if (!await hasAnyCodexDiagnosticsIdentity(ctx)) return "Cannot send Codex diagnostics because this command did not include a stable session identity.";
1747
- const targets = await resolveCodexDiagnosticsTargets(deps, ctx);
1748
- if (targets.length === 0) return ["No Codex thread is attached to this OpenClaw session yet.", "Use /codex threads to find a thread, then /codex resume <thread-id> before sending diagnostics."].join("\n");
1549
+ const targets = await requireCodexDiagnosticsTargets(deps, ctx);
1550
+ if (typeof targets === "string") return targets;
1749
1551
  return await sendCodexDiagnosticsFeedbackForTargets(deps, ctx, pluginConfig, note, targets);
1750
1552
  }
1751
1553
  async function sendCodexDiagnosticsFeedbackForTargets(deps, ctx, pluginConfig, note, targets, options = {}) {
1752
- if (targets.length === 0) return ["No Codex thread is attached to this OpenClaw session yet.", "Use /codex threads to find a thread, then /codex resume <thread-id> before sending diagnostics."].join("\n");
1554
+ if (targets.length === 0) return NO_DIAGNOSTICS_THREAD;
1753
1555
  const now = Date.now();
1754
1556
  const cooldownMessage = readCodexDiagnosticsTargetsCooldownMessage(targets, ctx, now, { cooldownScope: options.cooldownScope });
1755
1557
  if (cooldownMessage) return cooldownMessage;
@@ -1758,6 +1560,7 @@ async function sendCodexDiagnosticsFeedbackForTargets(deps, ctx, pluginConfig, n
1758
1560
  const failed = [];
1759
1561
  for (const target of targets) {
1760
1562
  const assertCurrent = () => {
1563
+ ctx.assertOwnerCurrent?.();
1761
1564
  const current = resolvePendingCodexDiagnosticsTargets(deps, [target], ctx.config);
1762
1565
  if (!codexDiagnosticsTargetsMatch([target], current)) throw new Error("The Codex diagnostics session changed before upload; request it again.");
1763
1566
  };
@@ -1809,6 +1612,22 @@ async function sendCodexDiagnosticsFeedbackForTargets(deps, ctx, pluginConfig, n
1809
1612
  }
1810
1613
  return formatCodexDiagnosticsUploadResult(sent, failed);
1811
1614
  }
1615
+ function consumeCodexDiagnosticsConfirmation(ctx, token, action) {
1616
+ const pending = readPendingCodexDiagnosticsConfirmation(token, Date.now());
1617
+ if (!pending) return action === "confirm" ? "No pending Codex diagnostics confirmation was found. Run /diagnostics again to create a fresh request." : "No pending Codex diagnostics confirmation was found.";
1618
+ if (!pending.senderId || !ctx.senderId) return `Cannot ${action} Codex diagnostics because this command did not include the original sender identity.`;
1619
+ if (pending.senderId !== ctx.senderId) return `Only the user who requested these Codex diagnostics can ${action} the upload.`;
1620
+ if (pending.channel !== ctx.channel) return "This Codex diagnostics confirmation belongs to a different channel.";
1621
+ const scopeMismatch = readCodexDiagnosticsScopeMismatch(pending, ctx);
1622
+ if (scopeMismatch) return scopeMismatch;
1623
+ deletePendingCodexDiagnosticsConfirmation(token);
1624
+ return pending;
1625
+ }
1626
+ async function requireCodexDiagnosticsTargets(deps, ctx) {
1627
+ if (!await hasAnyCodexDiagnosticsIdentity(ctx)) return "Cannot send Codex diagnostics because this command did not include a stable session identity.";
1628
+ const targets = await resolveCodexDiagnosticsTargets(deps, ctx);
1629
+ return targets.length > 0 ? targets : NO_DIAGNOSTICS_THREAD;
1630
+ }
1812
1631
  async function hasAnyCodexDiagnosticsIdentity(ctx) {
1813
1632
  if (await resolveControlTarget(ctx)) return true;
1814
1633
  return (ctx.diagnosticsSessions ?? []).some((session) => Boolean(session.sessionId));
@@ -1955,6 +1774,7 @@ async function bindConversation(deps, ctx, pluginConfig, args) {
1955
1774
  }
1956
1775
  });
1957
1776
  const threadLabel = parsed.threadId ?? "a new thread";
1777
+ assertCodexHostOwnerCurrent(ctx);
1958
1778
  const request = await ctx.requestConversationBinding({
1959
1779
  summary: `Codex app-server thread ${formatCodexDisplayText(threadLabel)} in ${formatCodexDisplayText(workspaceDir)}`,
1960
1780
  detachHint: "/codex detach",
@@ -1988,6 +1808,7 @@ async function detachConversation(deps, ctx) {
1988
1808
  bindingStore: deps.bindingStore,
1989
1809
  identity,
1990
1810
  expectedThreadId,
1811
+ assertCurrent: () => assertCodexHostOwnerCurrent(ctx),
1991
1812
  ...expectedStartId ? { expectedStartId } : {},
1992
1813
  ...isIncognitoSessionKey(sourceSessionKey) ? { allowUntracked: true } : {},
1993
1814
  afterClear: async () => {
@@ -1996,6 +1817,7 @@ async function detachConversation(deps, ctx) {
1996
1817
  })) return "This Codex conversation binding changed while detaching; try again.";
1997
1818
  return detachedPublicConversation;
1998
1819
  });
1820
+ assertCodexHostOwnerCurrent(ctx);
1999
1821
  return await detachPublicConversation();
2000
1822
  }
2001
1823
  async function describeConversationBinding(deps, ctx) {
@@ -2119,7 +1941,10 @@ async function resumeThread(deps, ctx, pluginConfig, args) {
2119
1941
  retained = await retainCodexAppServerBindingSubscription(client, effectiveThreadId, knownOwnership);
2120
1942
  assertCurrent();
2121
1943
  if (!retained) throw new Error("Codex resumed thread lost its native subscription owner.");
2122
- if (bindingBeforeCommit && !sameOwner) await releaseCodexAppServerBindingSubscription(bindingBeforeCommit, { assertCurrent });
1944
+ if (bindingBeforeCommit && !sameOwner) await releaseCodexAppServerBindingSubscription(bindingBeforeCommit, {
1945
+ assertCurrent,
1946
+ retainedClientId: clientId
1947
+ });
2123
1948
  assertCurrent();
2124
1949
  if (!await deps.bindingStore.mutate(identity, {
2125
1950
  kind: "set",
@@ -2155,6 +1980,7 @@ async function resumeThread(deps, ctx, pluginConfig, args) {
2155
1980
  sessionId: ctx.sessionId,
2156
1981
  storePath: ctx.sessionTarget?.storePath,
2157
1982
  assertCurrent: assertHostGeneration,
1983
+ assertOwnerCurrent: () => assertCodexHostOwnerCurrent(ctx),
2158
1984
  beforeRequest: async (request) => {
2159
1985
  const { thread } = await request({
2160
1986
  method: "thread/read",
@@ -2199,6 +2025,7 @@ async function bindCodexCliNodeSession(deps, ctx, parsed) {
2199
2025
  cwd: resolved.session?.cwd
2200
2026
  });
2201
2027
  const summary = `Codex CLI session ${formatCodexDisplayText(parsed.threadId)} on ${formatCodexDisplayText(nodeId)}`;
2028
+ assertCodexHostOwnerCurrent(ctx);
2202
2029
  const request = await ctx.requestConversationBinding({
2203
2030
  summary,
2204
2031
  detachHint: "/codex detach",
@@ -2291,7 +2118,10 @@ async function handleComputerUseCommand(deps, ctx, pluginConfig, args) {
2291
2118
  forceEnable: parsed.action === "install" || parsed.hasOverrides,
2292
2119
  ...Object.keys(parsed.overrides).length > 0 ? { overrides: parsed.overrides } : {}
2293
2120
  };
2294
- if (parsed.action === "install") return formatComputerUseStatus(await deps.installCodexComputerUse(params));
2121
+ if (parsed.action === "install") return formatComputerUseStatus(await deps.installCodexComputerUse({
2122
+ ...params,
2123
+ assertCurrent: () => assertCodexHostOwnerCurrent(ctx)
2124
+ }));
2295
2125
  return formatComputerUseStatus(await deps.readCodexComputerUseStatus(params));
2296
2126
  }
2297
2127
  async function handleNativeGoal(deps, ctx, pluginConfig, args) {
@@ -2325,7 +2155,10 @@ async function handleNativeGoal(deps, ctx, pluginConfig, args) {
2325
2155
  }
2326
2156
  if (action === "clear") {
2327
2157
  if (args.length > 1) return "Usage: /codex goal clear";
2328
- const response = await deps.codexControlRequest(pluginConfig, CODEX_CONTROL_METHODS.clearThreadGoal, { threadId: binding.threadId }, goalRequestOptions);
2158
+ const response = await deps.codexControlRequest(pluginConfig, CODEX_CONTROL_METHODS.clearThreadGoal, { threadId: binding.threadId }, {
2159
+ ...goalRequestOptions,
2160
+ assertOwnerCurrent: () => assertCodexHostOwnerCurrent(ctx)
2161
+ });
2329
2162
  return isJsonObject(response) && response.cleared === true ? "Cleared the Codex goal." : "No Codex goal was active.";
2330
2163
  }
2331
2164
  const requestedStatus = action === "pause" ? "paused" : action === "resume" ? "active" : action === "block" ? "blocked" : action === "complete" ? "complete" : void 0;
@@ -2338,6 +2171,7 @@ async function handleNativeGoal(deps, ctx, pluginConfig, args) {
2338
2171
  ...requestedStatus ? { status: requestedStatus } : {}
2339
2172
  }, {
2340
2173
  ...goalRequestOptions,
2174
+ assertOwnerCurrent: () => assertCodexHostOwnerCurrent(ctx),
2341
2175
  ...(isObjectiveUpdate || requestedStatus === "active") && connection.usesSupervisionConnection ? { beforeRequest: supervisedCommandGuard(deps, target.identity, binding) } : {}
2342
2176
  })));
2343
2177
  }
@@ -2354,20 +2188,17 @@ function formatNativeGoal(response) {
2354
2188
  `- Tokens: ${tokensUsed}${tokenBudget === void 0 ? "" : ` / ${tokenBudget}`}`
2355
2189
  ].join("\n");
2356
2190
  }
2357
- async function stopConversationTurn(deps, ctx, pluginConfig) {
2191
+ async function stopConversationTurn(deps, ctx) {
2358
2192
  const authority = await resolvePreparedCodexCommandAuthority(deps, ctx);
2359
2193
  const { target, binding } = authority;
2360
2194
  if (!target) return "Cannot stop Codex because this command did not include a stable binding identity.";
2361
2195
  return (await deps.stopCodexConversationTurn({
2362
2196
  identity: target.identity,
2363
2197
  binding,
2364
- pluginConfig,
2365
- agentDir: target.agentDir,
2366
- config: ctx.config,
2367
- assertCurrent: authority.assertCurrent
2198
+ assertCurrent: authority.assertMutationCurrent
2368
2199
  })).message;
2369
2200
  }
2370
- async function steerConversationTurn(deps, ctx, pluginConfig, message) {
2201
+ async function steerConversationTurn(deps, ctx, message) {
2371
2202
  const authority = await resolvePreparedCodexCommandAuthority(deps, ctx);
2372
2203
  const { target, binding } = authority;
2373
2204
  if (!target) return "Cannot steer Codex because this command did not include a stable binding identity.";
@@ -2375,10 +2206,7 @@ async function steerConversationTurn(deps, ctx, pluginConfig, message) {
2375
2206
  identity: target.identity,
2376
2207
  binding,
2377
2208
  message,
2378
- pluginConfig,
2379
- agentDir: target.agentDir,
2380
- config: ctx.config,
2381
- assertCurrent: authority.assertCurrent
2209
+ assertCurrent: authority.assertMutationCurrent
2382
2210
  })).message;
2383
2211
  }
2384
2212
  async function setConversationModel(deps, ctx, pluginConfig, args) {
@@ -2410,7 +2238,8 @@ async function setConversationModel(deps, ctx, pluginConfig, args) {
2410
2238
  config: ctx.config,
2411
2239
  binding,
2412
2240
  storePath: authority.storePath,
2413
- assertCurrent: authority.assertCurrent
2241
+ assertCurrent: authority.assertCurrent,
2242
+ assertCommitAllowed: authority.assertMutationCurrent
2414
2243
  });
2415
2244
  }
2416
2245
  async function setConversationFastMode(deps, ctx, args) {
@@ -2426,7 +2255,7 @@ async function setConversationFastMode(deps, ctx, args) {
2426
2255
  bindingStore: deps.bindingStore,
2427
2256
  binding,
2428
2257
  enabled: parsed,
2429
- assertCurrent: authority.assertCurrent
2258
+ assertCurrent: parsed === void 0 ? authority.assertCurrent : authority.assertMutationCurrent
2430
2259
  });
2431
2260
  }
2432
2261
  async function setConversationPermissions(deps, ctx, args) {
@@ -2442,7 +2271,7 @@ async function setConversationPermissions(deps, ctx, args) {
2442
2271
  mode: parsed,
2443
2272
  config: ctx.config,
2444
2273
  storePath: authority.storePath,
2445
- assertCurrent: authority.assertHostCurrent,
2274
+ assertCurrent: parsed ? authority.assertHostMutationCurrent : authority.assertHostCurrent,
2446
2275
  session: {
2447
2276
  agentId: target.agentId,
2448
2277
  sessionId: ctx.sessionId,
@@ -2471,7 +2300,7 @@ async function startThreadAction(deps, ctx, pluginConfig, kind, args) {
2471
2300
  }
2472
2301
  const compactCurrent = ctx.runtimeContext?.compactCurrent;
2473
2302
  if (!compactCurrent) return "Codex compaction is unavailable because this command is not bound to a session.";
2474
- authority.assertCurrent();
2303
+ authority.assertMutationCurrent();
2475
2304
  const result = await compactCurrent();
2476
2305
  return result.compacted ? `Compacted Codex session (${result.tokensAfter ?? "unknown"} tokens after).` : `Codex compaction did not complete: ${formatCodexDisplayText(result.reason ?? "no reason returned")}.`;
2477
2306
  }
@@ -2494,6 +2323,7 @@ async function startThreadAction(deps, ctx, pluginConfig, kind, args) {
2494
2323
  sessionKey: authority.sessionKey,
2495
2324
  storePath: authority.storePath,
2496
2325
  assertCurrent: authority.assertCurrent,
2326
+ assertOwnerCurrent: () => assertCodexHostOwnerCurrent(ctx),
2497
2327
  ...connection.usesSupervisionConnection ? {
2498
2328
  startOptions: connection.appServer.start,
2499
2329
  beforeRequest: supervisedCommandGuard(deps, target.identity, binding)
@@ -2569,7 +2399,11 @@ function formatCodexAvailablePlugins(plugins, warnings, query, page) {
2569
2399
  //#region extensions/codex/src/command-plugins-management.ts
2570
2400
  const POLICY_REFRESH_HINT = "Takes effect on your next message.";
2571
2401
  const AVAILABLE_USAGE = "Usage: /codex plugins available [query] [--page <positive integer>]. Search text must be at most 100 characters; use -- before literal query text that contains options.";
2572
- async function handleCodexPluginsSubcommand(ctx, rest, io, runtime) {
2402
+ async function handleCodexPluginsSubcommand(input, rest, io, runtime) {
2403
+ const ctx = {
2404
+ ...input,
2405
+ gatewayClientScopes: input.gatewayClientScopes?.slice()
2406
+ };
2573
2407
  const [verb = "list", ...args] = rest;
2574
2408
  const normalized = verb.toLowerCase();
2575
2409
  if (normalized === "menu") {
@@ -2611,7 +2445,7 @@ async function handleCodexPluginsSubcommand(ctx, rest, io, runtime) {
2611
2445
  });
2612
2446
  return formatCodexAvailablePlugins(discovered.plugins, discovered.warnings, query, page);
2613
2447
  } catch (error) {
2614
- return { text: `Could not list Codex plugins: ${formatCodexDisplayText(errorMessage(error))}` };
2448
+ return { text: `Could not list Codex plugins: ${formatCodexDisplayText(coerceErrorMessage(error))}` };
2615
2449
  }
2616
2450
  }
2617
2451
  if (normalized === "status") {
@@ -2635,7 +2469,7 @@ async function handleCodexPluginsSubcommand(ctx, rest, io, runtime) {
2635
2469
  if (args.length !== 1 || !args[0]) return { text: "Usage: /codex plugins install <plugin>@<marketplace>" };
2636
2470
  if (!canMutateCodexHost(ctx)) return { text: "Only an owner or operator.admin gateway client can run /codex plugins install." };
2637
2471
  if (!runtime) return { text: "Codex plugin installation is unavailable for this command." };
2638
- return await installCodexPlugin(args[0], io, runtime);
2472
+ return await installCodexPlugin(args[0], io, runtime, ctx);
2639
2473
  }
2640
2474
  const target = args[0];
2641
2475
  if (normalized === "enable" || normalized === "disable") {
@@ -2653,6 +2487,7 @@ async function handleCodexPluginsSubcommand(ctx, rest, io, runtime) {
2653
2487
  if (configured.status === "ambiguous" || configured.status === "mismatched") return { text: describeConfiguredPluginIdentityConflict(target, configured.status) };
2654
2488
  if (configured.status === "missing") return { text: `Codex sub-plugin '${formatCodexDisplayText(target)}' is not configured. Run '/codex plugins list' to see configured plugins.` };
2655
2489
  const configKey = configured.configKey;
2490
+ assertCodexHostOwnerCurrent(ctx);
2656
2491
  await io.mutate((block) => {
2657
2492
  if (wantEnabled) block.enabled = true;
2658
2493
  block.plugins ??= {};
@@ -2660,7 +2495,7 @@ async function handleCodexPluginsSubcommand(ctx, rest, io, runtime) {
2660
2495
  ...block.plugins[configKey],
2661
2496
  enabled: wantEnabled
2662
2497
  };
2663
- });
2498
+ }, () => assertCodexHostOwnerCurrent(ctx));
2664
2499
  return { text: `${formatCodexDisplayText(configKey)}: ${wantEnabled ? "enabled" : "disabled"} in openclaw.json. ${POLICY_REFRESH_HINT}` };
2665
2500
  }
2666
2501
  return { text: `Unknown /codex plugins subcommand: ${formatCodexDisplayText(verb)}\n\n${buildPluginsHelp()}` };
@@ -2766,7 +2601,7 @@ function buildPluginsHelp() {
2766
2601
  "Only an owner or operator.admin can discover, inspect, refresh hosted apps, install, enable, or disable plugins."
2767
2602
  ].join("\n");
2768
2603
  }
2769
- async function installCodexPlugin(requestedId, io, runtime) {
2604
+ async function installCodexPlugin(requestedId, io, runtime, ctx) {
2770
2605
  const requested = parseCodexPluginMarketplaceId(requestedId);
2771
2606
  if (!requested) return { text: "Invalid plugin identifier. Use /codex plugins install <plugin>@<marketplace>. Both names allow ASCII letters, digits, underscores, and hyphens. Plugin names may also contain dots between nonempty segments." };
2772
2607
  let plugin;
@@ -2782,7 +2617,7 @@ async function installCodexPlugin(requestedId, io, runtime) {
2782
2617
  if (!plugin) return { text: `Multiple available Codex plugins match '${formatCodexDisplayText(requestedId)}'; the marketplace identity must be unique.` };
2783
2618
  } else plugin = matching[0];
2784
2619
  } catch (error) {
2785
- return { text: `Could not verify the requested Codex plugin: ${formatCodexDisplayText(errorMessage(error))}` };
2620
+ return { text: `Could not verify the requested Codex plugin: ${formatCodexDisplayText(coerceErrorMessage(error))}` };
2786
2621
  }
2787
2622
  if (!plugin) return { text: `${formatCodexDisplayText(requestedId)} was not found. Run /codex plugins available to inspect the current marketplaces.` };
2788
2623
  if (!plugin.available) return { text: `${formatCodexDisplayText(requestedId)} is unavailable or disabled by its marketplace administrator.` };
@@ -2795,7 +2630,7 @@ async function installCodexPlugin(requestedId, io, runtime) {
2795
2630
  const configured = resolveInstalledPluginKey((await io.readConfig()).plugins ?? {}, plugin);
2796
2631
  if (configured.status === "ambiguous" || configured.status === "mismatched") return { text: describeConfiguredPluginIdentityConflict(requestedId, configured.status) };
2797
2632
  } catch (error) {
2798
- return { text: `Could not verify existing Codex plugin authorization: ${formatCodexDisplayText(errorMessage(error))}` };
2633
+ return { text: `Could not verify existing Codex plugin authorization: ${formatCodexDisplayText(coerceErrorMessage(error))}` };
2799
2634
  }
2800
2635
  let result;
2801
2636
  if (!alreadyInstalled) {
@@ -2808,13 +2643,15 @@ async function installCodexPlugin(requestedId, io, runtime) {
2808
2643
  } : void 0;
2809
2644
  if (!requestParams) return { text: `${formatCodexDisplayText(requestedId)} cannot be installed because its marketplace did not provide a trusted local path or remote plugin identifier.` };
2810
2645
  try {
2646
+ assertCodexHostOwnerCurrent(ctx);
2811
2647
  result = await runtime.install(requestParams);
2812
2648
  } catch (error) {
2813
- return { text: `Could not install ${formatCodexDisplayText(requestedId)}: ${formatCodexDisplayText(errorMessage(error))}` };
2649
+ return { text: `Could not install ${formatCodexDisplayText(requestedId)}: ${formatCodexDisplayText(coerceErrorMessage(error))}` };
2814
2650
  }
2815
2651
  }
2816
2652
  const selectedPlugin = plugin;
2817
2653
  try {
2654
+ assertCodexHostOwnerCurrent(ctx);
2818
2655
  await io.mutate((block) => {
2819
2656
  block.plugins ??= {};
2820
2657
  const configured = resolveInstalledPluginKey(block.plugins, selectedPlugin);
@@ -2831,15 +2668,15 @@ async function installCodexPlugin(requestedId, io, runtime) {
2831
2668
  pluginName: existing?.pluginName ?? (curated ? selectedPlugin.pluginName : persistedPluginName(selectedPlugin))
2832
2669
  };
2833
2670
  block.plugins[configKey] = updated;
2834
- });
2671
+ }, () => assertCodexHostOwnerCurrent(ctx));
2835
2672
  } catch (error) {
2836
- return { text: `${formatCodexDisplayText(requestedId)} was installed in Codex but could not be authorized in OpenClaw and will not be exposed: ${formatCodexDisplayText(errorMessage(error))}` };
2673
+ return { text: `${formatCodexDisplayText(requestedId)} was installed in Codex but could not be authorized in OpenClaw and will not be exposed: ${formatCodexDisplayText(coerceErrorMessage(error))}` };
2837
2674
  }
2838
2675
  let refreshWarning = "";
2839
2676
  if (runtime.refresh) try {
2840
2677
  refreshWarning = (await runtime.refresh(workspaceDir)).diagnostics.map((diagnostic) => ` ${formatCodexDisplayText(diagnostic.message)}`).join("");
2841
2678
  } catch (error) {
2842
- refreshWarning = ` Runtime refresh requires a new conversation: ${formatCodexDisplayText(errorMessage(error))}`;
2679
+ refreshWarning = ` Runtime refresh requires a new conversation: ${formatCodexDisplayText(coerceErrorMessage(error))}`;
2843
2680
  }
2844
2681
  const appsNeedingAuth = result?.appsNeedingAuth ?? [];
2845
2682
  if (appsNeedingAuth.length > 0) {
@@ -2871,22 +2708,7 @@ async function installCodexPlugin(requestedId, io, runtime) {
2871
2708
  type: "text",
2872
2709
  text: `Some app setup permissions could not be confirmed. Run /codex plugins status ${requestedId} to check the current account and restrictions.`
2873
2710
  }] : [],
2874
- {
2875
- type: "buttons",
2876
- buttons: [...appLinks.length > 0 ? [{
2877
- label: "Refresh hosted apps",
2878
- action: {
2879
- type: "command",
2880
- command: "/codex plugins refresh"
2881
- }
2882
- }] : [], {
2883
- label: "Check status",
2884
- action: {
2885
- type: "command",
2886
- command: `/codex plugins status ${requestedId}`
2887
- }
2888
- }]
2889
- },
2711
+ buildCodexPluginStatusButtons(requestedId, appLinks.length > 0),
2890
2712
  {
2891
2713
  type: "context",
2892
2714
  text: `${refreshWarning.trim()} ${POLICY_REFRESH_HINT}`.trim()
@@ -2902,9 +2724,6 @@ async function installCodexPlugin(requestedId, io, runtime) {
2902
2724
  const status = alreadyInstalled ? "bundle was already installed in Codex" : "bundle was installed in Codex";
2903
2725
  return { text: `${formatCodexDisplayText(requestedId)} ${status}. OpenClaw app access is configured.${refreshWarning} ${POLICY_REFRESH_HINT}` };
2904
2726
  }
2905
- function errorMessage(error) {
2906
- return error instanceof Error ? error.message : String(error);
2907
- }
2908
2727
  function formatPluginList(plugins, options = {}) {
2909
2728
  const globalEnabled = options.globalEnabled === true;
2910
2729
  const keys = Object.keys(plugins).toSorted();
@@ -2935,7 +2754,11 @@ function formatPluginList(plugins, options = {}) {
2935
2754
  //#region extensions/codex/src/command-plugins-runtime.ts
2936
2755
  const SCOPE_CHANGED_MESSAGE = "Codex account, conversation, or plugin policy changed. Run the command again.";
2937
2756
  async function withCodexPluginCommandContext(params, run) {
2938
- const { deps, ctx, pluginConfig } = params;
2757
+ const { deps, pluginConfig } = params;
2758
+ const ctx = {
2759
+ ...params.ctx,
2760
+ gatewayClientScopes: params.ctx.gatewayClientScopes?.slice()
2761
+ };
2939
2762
  const current = await deps.codexPluginsManagementIo?.readConfig() ?? {};
2940
2763
  const initialPolicy = JSON.stringify(current);
2941
2764
  const { scope, target, binding } = await resolveCommandAppServerContext(deps, ctx, pluginConfig);
@@ -3016,7 +2839,10 @@ async function withCodexPluginCommandContext(params, run) {
3016
2839
  const response = await request({
3017
2840
  method,
3018
2841
  requestParams,
3019
- assertCurrent
2842
+ assertCurrent: () => {
2843
+ assertCurrent();
2844
+ assertCodexHostOwnerCurrent(ctx);
2845
+ }
3020
2846
  });
3021
2847
  await validateCurrent();
3022
2848
  return response;
@@ -3065,6 +2891,17 @@ async function handleCodexSubcommand(ctx, options) {
3065
2891
  if (CODEX_NATIVE_CONTROL_SUBCOMMANDS.has(normalized) && !returnsBeforeNativeCodexExecution(normalized, rest) && !isReadOnlyCodexGoalCommand(normalized, rest) && !canMutateCodexHost(ctx)) return { text: CODEX_NATIVE_EXECUTION_AUTH_ERROR };
3066
2892
  const sandboxBlock = resolveCodexNativeCommandSandboxBlock(ctx, normalized, rest);
3067
2893
  if (sandboxBlock) return { text: sandboxBlock };
2894
+ const usageCommand = normalized === "unbind" ? "detach" : normalized;
2895
+ if (rest.length > 0 && [
2896
+ "status",
2897
+ "models",
2898
+ "detach",
2899
+ "binding",
2900
+ "stop",
2901
+ "mcp",
2902
+ "skills",
2903
+ "account"
2904
+ ].includes(usageCommand)) return { text: `Usage: /codex ${usageCommand}` };
3068
2905
  if (normalized === "plugins") {
3069
2906
  if (rest[0]?.toLowerCase() === "refresh") {
3070
2907
  if (rest.length !== 1) return { text: "Usage: /codex plugins refresh — refresh hosted app inventory for the current Codex account/runtime." };
@@ -3099,7 +2936,8 @@ async function handleCodexSubcommand(ctx, options) {
3099
2936
  const scope = await getAppServerScope();
3100
2937
  return await deps.codexControlRequest(options.pluginConfig, CODEX_CONTROL_METHODS.installPlugin, requestParams, {
3101
2938
  ...scope,
3102
- config: ctx.config
2939
+ config: ctx.config,
2940
+ assertOwnerCurrent: () => assertCodexHostOwnerCurrent(ctx)
3103
2941
  });
3104
2942
  },
3105
2943
  refresh: async (workspaceDir) => {
@@ -3132,7 +2970,6 @@ async function handleCodexSubcommand(ctx, options) {
3132
2970
  appServerVersion: client.getServerVersion(),
3133
2971
  runtimeIdentity: client.getRuntimeIdentity()
3134
2972
  });
3135
- defaultCodexPluginMetadataCache.invalidate(appCacheKey);
3136
2973
  return await refreshCodexPluginRuntimeState({
3137
2974
  configCwd: workspaceDir,
3138
2975
  appCache: defaultCodexAppInventoryCache,
@@ -3153,12 +2990,10 @@ async function handleCodexSubcommand(ctx, options) {
3153
2990
  });
3154
2991
  }
3155
2992
  if (normalized === "status") {
3156
- if (rest.length > 0) return { text: "Usage: /codex status" };
3157
2993
  const { agentDir } = resolveCodexConversationControlScope(ctx);
3158
2994
  return { text: formatCodexStatus(await deps.readCodexStatusProbes(options.pluginConfig, ctx.config, agentDir)) };
3159
2995
  }
3160
2996
  if (normalized === "models") {
3161
- if (rest.length > 0) return { text: "Usage: /codex models" };
3162
2997
  const { agentDir } = resolveCodexConversationControlScope(ctx);
3163
2998
  return { text: formatModels(await deps.listCodexAppServerModels(deps.requestOptions(options.pluginConfig, 100, ctx.config, agentDir))) };
3164
2999
  }
@@ -3167,19 +3002,10 @@ async function handleCodexSubcommand(ctx, options) {
3167
3002
  if (normalized === "sessions") return { text: await buildCodexCliSessions(deps, rest) };
3168
3003
  if (normalized === "resume") return { text: await resumeThread(deps, ctx, options.pluginConfig, rest) };
3169
3004
  if (normalized === "bind") return await bindConversation(deps, ctx, options.pluginConfig, rest);
3170
- if (normalized === "detach" || normalized === "unbind") {
3171
- if (rest.length > 0) return { text: "Usage: /codex detach" };
3172
- return { text: await detachConversation(deps, ctx) };
3173
- }
3174
- if (normalized === "binding") {
3175
- if (rest.length > 0) return { text: "Usage: /codex binding" };
3176
- return { text: await describeConversationBinding(deps, ctx) };
3177
- }
3178
- if (normalized === "stop") {
3179
- if (rest.length > 0) return { text: "Usage: /codex stop" };
3180
- return { text: await stopConversationTurn(deps, ctx, options.pluginConfig) };
3181
- }
3182
- if (normalized === "steer") return { text: await steerConversationTurn(deps, ctx, options.pluginConfig, rest.join(" ")) };
3005
+ if (normalized === "detach" || normalized === "unbind") return { text: await detachConversation(deps, ctx) };
3006
+ if (normalized === "binding") return { text: await describeConversationBinding(deps, ctx) };
3007
+ if (normalized === "stop") return { text: await stopConversationTurn(deps, ctx) };
3008
+ if (normalized === "steer") return { text: await steerConversationTurn(deps, ctx, rest.join(" ")) };
3183
3009
  if (normalized === "model") return { text: await setConversationModel(deps, ctx, options.pluginConfig, rest) };
3184
3010
  if (normalized === "fast") {
3185
3011
  if (isMenuVerb(rest)) return buildCodexFastMenuReply();
@@ -3189,31 +3015,21 @@ async function handleCodexSubcommand(ctx, options) {
3189
3015
  if (isMenuVerb(rest)) return buildCodexPermissionsMenuReply();
3190
3016
  return { text: await setConversationPermissions(deps, ctx, rest) };
3191
3017
  }
3192
- if (normalized === "compact") return { text: await startThreadAction(deps, ctx, options.pluginConfig, "compact", rest) };
3193
- if (normalized === "review") return { text: await startThreadAction(deps, ctx, options.pluginConfig, "review", rest) };
3018
+ if (normalized === "compact" || normalized === "review") return { text: await startThreadAction(deps, ctx, options.pluginConfig, normalized, rest) };
3194
3019
  if (normalized === "diagnostics") return await handleCodexDiagnosticsFeedback(deps, ctx, options.pluginConfig, rest.join(" "), "/codex diagnostics");
3195
3020
  if (normalized === "computer-use" || normalized === "computeruse") {
3196
3021
  if (isMenuVerb(rest)) return buildCodexComputerUseMenuReply();
3197
3022
  return { text: await handleComputerUseCommand(deps, ctx, options.pluginConfig, rest) };
3198
3023
  }
3199
- if (normalized === "mcp") {
3200
- if (rest.length > 0) return { text: "Usage: /codex mcp" };
3024
+ if (normalized === "mcp" || normalized === "skills") {
3201
3025
  const scope = await resolveCommandAppServerScope(deps, ctx, options.pluginConfig);
3202
- return { text: formatList(await deps.codexControlRequest(options.pluginConfig, CODEX_CONTROL_METHODS.listMcpServers, { limit: 100 }, {
3026
+ const response = await deps.codexControlRequest(options.pluginConfig, normalized === "mcp" ? CODEX_CONTROL_METHODS.listMcpServers : CODEX_CONTROL_METHODS.listSkills, normalized === "mcp" ? { limit: 100 } : {}, {
3203
3027
  config: ctx.config,
3204
3028
  ...scope
3205
- }), "MCP servers") };
3206
- }
3207
- if (normalized === "skills") {
3208
- if (rest.length > 0) return { text: "Usage: /codex skills" };
3209
- const scope = await resolveCommandAppServerScope(deps, ctx, options.pluginConfig);
3210
- return { text: formatSkills(await deps.codexControlRequest(options.pluginConfig, CODEX_CONTROL_METHODS.listSkills, {}, {
3211
- config: ctx.config,
3212
- ...scope
3213
- })) };
3029
+ });
3030
+ return { text: normalized === "mcp" ? formatList(response, "MCP servers") : formatSkills(response) };
3214
3031
  }
3215
3032
  if (normalized === "account") {
3216
- if (rest.length > 0) return { text: "Usage: /codex account" };
3217
3033
  const scope = await resolveCommandAppServerScope(deps, ctx, options.pluginConfig);
3218
3034
  const requestScope = {
3219
3035
  config: ctx.config,
@@ -3223,6 +3039,7 @@ async function handleCodexSubcommand(ctx, options) {
3223
3039
  return { text: formatAccount(account, limits, await readCodexAccountAuthOverview({
3224
3040
  ctx,
3225
3041
  agentDir: scope.agentDir,
3042
+ authProfileId: scope.authProfileId,
3226
3043
  pluginConfig: options.pluginConfig,
3227
3044
  safeCodexControlRequest: deps.safeCodexControlRequest,
3228
3045
  account,
@@ -3234,11 +3051,7 @@ async function handleCodexSubcommand(ctx, options) {
3234
3051
  function resolvePluginRuntimeRefreshMethod(method) {
3235
3052
  const recognized = [
3236
3053
  CODEX_CONTROL_METHODS.listPlugins,
3237
- CODEX_CONTROL_METHODS.listSkills,
3238
- CODEX_CONTROL_METHODS.listHooks,
3239
- CODEX_CONTROL_METHODS.reloadMcpServers,
3240
3054
  CODEX_CONTROL_METHODS.installedApps,
3241
- CODEX_CONTROL_METHODS.listApps,
3242
3055
  CODEX_CONTROL_METHODS.readApps
3243
3056
  ].find((candidate) => candidate === method);
3244
3057
  if (!recognized) throw new Error(`Unexpected Codex plugin refresh method: ${method}`);