@openclaw/codex 2026.9.6 → 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 (158) hide show
  1. package/README.md +2 -0
  2. package/assets/icon.png +0 -0
  3. package/dist/.setup/{account-usage-runtime-Eem_WGqY.mjs → account-usage-runtime-DFhbh1zz.mjs} +5 -5
  4. package/dist/.setup/{apply-DDOi8uNx.mjs → apply-D3GcSoSa.mjs} +22 -36
  5. package/dist/.setup/{attempt-client-cleanup-CEv1cKwF.mjs → attempt-client-cleanup-DOP-cW5j.mjs} +128 -37
  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-B2mpaI9D.mjs → auth-cache-key-Dbvq-QgB.mjs} +36 -34
  9. package/dist/.setup/{auth-profile-WqZtZfXN.mjs → auth-profile-B0okYl2D.mjs} +1 -2
  10. package/dist/.setup/auth-start-options-BPIPeEX8.mjs +44 -0
  11. package/dist/.setup/{binding-connection-ThoatDcb.mjs → binding-connection-DTtN1KrX.mjs} +2 -2
  12. package/dist/.setup/{binding-connection.runtime-yoHrABt-.mjs → binding-connection.runtime-6TpgD1M6.mjs} +4 -4
  13. package/dist/.setup/{bounded-turn-B2HScEgT.mjs → bounded-turn-CbjoN2OW.mjs} +15 -18
  14. package/dist/.setup/bounded-turn-isolation-B8K_ylqk.mjs +14 -0
  15. package/dist/.setup/{build-state-C7EnDVgr.mjs → build-state-Da1_z0kd.mjs} +1 -1
  16. package/dist/.setup/{capabilities-CDXOOFdZ.mjs → capabilities-B3WEZl4e.mjs} +2 -10
  17. package/dist/.setup/{client-Cs08OXVQ.mjs → client-N0JpgSzF.mjs} +138 -399
  18. package/dist/.setup/{client-catalog-response-BMgt_4q4.mjs → client-catalog-response-5HHLdcde.mjs} +1 -1
  19. package/dist/.setup/{command-dispatch-B4JuOsOk.mjs → command-dispatch-BeAoaovI.mjs} +5 -8
  20. package/dist/.setup/{command-formatters-Bmqvr9tO.mjs → command-formatters-R3ckE3Co.mjs} +29 -61
  21. package/dist/.setup/{command-handlers-DW7Lx9oH.mjs → command-handlers-ylTMS00z.mjs} +222 -343
  22. package/dist/.setup/{command-rpc-DixIj3HW.mjs → command-rpc-CGJGUQ6Y.mjs} +15 -18
  23. package/dist/.setup/compact-C2WamavS.mjs +776 -0
  24. package/dist/.setup/{config-BoTP_mrL.mjs → config-DKhXquav.mjs} +26 -28
  25. package/dist/.setup/{config-options-BvaRs51b.mjs → config-options-CzyWLTJt.mjs} +24 -37
  26. package/dist/.setup/{config-parsing-CcB9iPoq.mjs → config-parsing-b088LyhT.mjs} +57 -60
  27. package/dist/.setup/{config-runtime-C8Rw1m1m.mjs → config-runtime-C0NbLms1.mjs} +2 -2
  28. package/dist/.setup/{config-security-BEReZ6go.mjs → config-security-CE-FcGw9.mjs} +32 -111
  29. package/dist/.setup/{config-utils-DujwEnhg.mjs → config-utils-D0CXecki.mjs} +3 -13
  30. package/dist/.setup/context-engine-projection-PezSESth.mjs +387 -0
  31. package/dist/.setup/{conversation-binding-DP-gMrBP.mjs → conversation-binding-3Min8qvP.mjs} +67 -90
  32. package/dist/.setup/{conversation-binding-data-CrcyZk6O.mjs → conversation-binding-data-C746z5Pn.mjs} +8 -12
  33. package/dist/.setup/{conversation-control-uK9Jomlc.mjs → conversation-control-CEP8X5JC.mjs} +8 -8
  34. package/dist/.setup/{cyber-failover-DYwbmf1o.mjs → cyber-failover-XV0nNRZu.mjs} +1 -1
  35. package/dist/.setup/{cyber-failover-notice-e9G3J9-e.mjs → cyber-failover-notice-RNpGpTyP.mjs} +1 -1
  36. package/dist/.setup/{dynamic-tools-BDXl-8Cw.mjs → dynamic-tools-DzlsLUuS.mjs} +2305 -2606
  37. package/dist/.setup/{effective-mcp-catalog-CvnvnGIe.mjs → effective-mcp-catalog-CxUtC-xG.mjs} +8 -17
  38. package/dist/.setup/{ephemeral-turn-poidXgek.mjs → ephemeral-turn-CDsPJOa2.mjs} +3 -3
  39. package/dist/.setup/event-projector-assistant-message-CigreO4K.mjs +69 -0
  40. package/dist/.setup/{event-projector-usage-CnBS8Wa3.mjs → event-projector-usage-03R0I2dM.mjs} +3 -25
  41. package/dist/.setup/event-projector-values-DJSz8BTk.mjs +106 -0
  42. package/dist/.setup/incognito-session-DWYapfwf.mjs +2 -0
  43. package/dist/.setup/{inference-context-D96l9-ew.mjs → inference-context-D-9gWlTR.mjs} +16 -18
  44. package/dist/.setup/inference-dispatch-CMZtjQyz.mjs +359 -0
  45. package/dist/.setup/inference-metadata-CgIf7sOx.mjs +81 -0
  46. package/dist/.setup/{inference-proxy-b-aJMSxm.mjs → inference-proxy-DhcXOgUE.mjs} +174 -214
  47. package/dist/.setup/{isolated-completion-BIZFhTNG.mjs → isolated-completion-Dm3PzxJk.mjs} +9 -12
  48. package/dist/.setup/{managed-binary-BnshlFag.mjs → managed-binary-kiWRhNRE.mjs} +8 -12
  49. package/dist/.setup/{model-catalog-CfXJf9Ay.mjs → model-catalog-PAuZgJC6.mjs} +11 -10
  50. package/dist/.setup/model-runtime-BdqzOMkU.mjs +11 -0
  51. package/dist/.setup/{models-KnqBv0hE.mjs → models-DHXZtVVk.mjs} +9 -18
  52. package/dist/.setup/{native-auth-rWbGbMn3.mjs → native-auth-CuG53tu4.mjs} +4 -4
  53. package/dist/.setup/{native-execution-policy-umd0tgh4.mjs → native-execution-policy-BxZJy5mP.mjs} +5 -30
  54. package/dist/.setup/{native-subagent-monitor-D3filLY2.mjs → native-subagent-monitor-Dpsmf2wz.mjs} +4395 -3609
  55. package/dist/.setup/native-subagent-pending-assignments-DwkCzLvD.mjs +203 -0
  56. package/dist/.setup/native-task-assignments-DMQ0g3hu.mjs +194 -0
  57. package/dist/.setup/{node-cli-sessions-r3avj02l.mjs → node-cli-sessions-HC4W6FLI.mjs} +19 -49
  58. package/dist/.setup/{node-exec-server.runtime-BDwWXVpK.mjs → node-exec-server.runtime-BgBfWQqo.mjs} +3 -6
  59. package/dist/.setup/{plan-CN3VwfNU.mjs → plan-Y-QIvrKB.mjs} +49 -92
  60. package/dist/.setup/{plugin-activation-DT3MNtqj.mjs → plugin-activation-cNHRfaxU.mjs} +8 -36
  61. package/dist/.setup/{plugin-app-cache-key-B2CsSdnV.mjs → plugin-app-cache-key-BL9B5H0L.mjs} +6 -23
  62. package/dist/.setup/{plugin-inventory-BoRei8Z4.mjs → plugin-inventory-Cky2XJUw.mjs} +21 -21
  63. package/dist/.setup/{plugin-marketplace-discovery-CDOi8IFs.mjs → plugin-marketplace-discovery-D_dV9FXa.mjs} +18 -24
  64. package/dist/.setup/{plugin-metadata-cache-Ctmo83k_.mjs → plugin-metadata-cache-DsjsL1dr.mjs} +115 -175
  65. package/dist/.setup/{provider-BOsxQHOM.mjs → provider-DH8NSzGt.mjs} +11 -14
  66. package/dist/.setup/{provider-capabilities-BfE88FZ5.mjs → provider-capabilities-CAxoF-X1.mjs} +13 -18
  67. package/dist/.setup/{rate-limits-CMU3DUD0.mjs → rate-limits-B7-X2TgG.mjs} +9 -31
  68. package/dist/.setup/{request-D2L0zMrq.mjs → request-BHZ1nz8d.mjs} +7 -6
  69. package/dist/.setup/responses-oauth-twnuTaAa.mjs +93 -0
  70. package/dist/.setup/rpc-error-BlD2vuzn.mjs +31 -0
  71. package/dist/.setup/{run-attempt-BHu11r7h.mjs → run-attempt-D8RZUOzY.mjs} +1035 -1023
  72. package/dist/.setup/{run-attempt-lifecycle-B7JbY4-F.mjs → run-attempt-lifecycle-C-6O3Exn.mjs} +10 -24
  73. package/dist/.setup/{runtime-artifact-CLZ8udh-.mjs → runtime-artifact-DDQ-HGXf.mjs} +16 -4
  74. package/dist/.setup/runtime-artifact-connection-D68qQn1m.mjs +78 -0
  75. package/dist/.setup/sandbox-guard-DjCz2eOw.mjs +126 -0
  76. package/dist/.setup/scope-DOC1Xjc8.mjs +6 -0
  77. package/dist/.setup/session-binding-DGCYAfvD.mjs +443 -0
  78. package/dist/.setup/{session-binding-record-BGoz8wOK.mjs → session-binding-record-Oe9L-CNY.mjs} +52 -130
  79. package/dist/.setup/{session-binding-sidecars-BlB5EvIS.mjs → session-binding-sidecars-jo6H8dFr.mjs} +196 -17
  80. package/dist/.setup/{session-catalog-Pno1xGcl.mjs → session-catalog-4sCdv5qx.mjs} +170 -324
  81. package/dist/.setup/{session-catalog-adoption-BI6UTDZT.mjs → session-catalog-adoption-BU_pHWG7.mjs} +7 -6
  82. package/dist/.setup/{session-catalog-archive-lHBqzhaO.mjs → session-catalog-archive-spHfihri.mjs} +6 -6
  83. package/dist/.setup/session-catalog-events-DePDzzjc.mjs +139 -0
  84. package/dist/.setup/session-catalog-home-id-vlih0B_g.mjs +22 -0
  85. package/dist/.setup/{session-catalog-index-B9_VQIUz.mjs → session-catalog-index-CZvDzC6z.mjs} +126 -122
  86. package/dist/.setup/{session-catalog-index-order-hcdz07yN.mjs → session-catalog-index-order-BcQpHks3.mjs} +1 -1
  87. package/dist/.setup/{session-catalog-index-state-Dgh8ORJm.mjs → session-catalog-index-state-TeO7EyO-.mjs} +3 -2
  88. package/dist/.setup/session-catalog-limits-DDxOsQeC.mjs +14 -0
  89. package/dist/.setup/session-catalog-list-request-CvtxrYSe.mjs +170 -0
  90. package/dist/.setup/session-catalog-native-projection-DjhwGL6x.mjs +178 -0
  91. package/dist/.setup/{session-catalog-node-adoption-ITddWx_X.mjs → session-catalog-node-adoption-DgXvSGu0.mjs} +10 -27
  92. package/dist/.setup/{session-catalog-node-continue-6g6qi4A9.mjs → session-catalog-node-continue-DjKXHBbi.mjs} +8 -10
  93. package/dist/.setup/session-catalog-node-lookup-CtAXI5W5.mjs +56 -0
  94. package/dist/.setup/{session-catalog-native-projection-DowriLid.mjs → session-catalog-parsing-CPGaPYr-.mjs} +11 -194
  95. package/dist/.setup/{session-catalog-projection-zK_PUsiE.mjs → session-catalog-projection-Cr5qP5Dj.mjs} +6 -4
  96. package/dist/.setup/session-catalog-provenance-DoAvktcj.mjs +95 -0
  97. package/dist/.setup/{session-cli-irrD-uo7.mjs → session-cli-Cn_nCqfq.mjs} +9 -22
  98. package/dist/.setup/{session-history-BrqhSCf9.mjs → session-history-D83lJWHG.mjs} +4 -6
  99. package/dist/.setup/{session-history-import-D-3wAgOP.mjs → session-history-import-WhX-X33a.mjs} +7 -10
  100. package/dist/.setup/session-history-read-Ov3StuL4.mjs +133 -0
  101. package/dist/.setup/{session-history.worker-CaCh0xF_.mjs → session-history.worker-MnPKncqP.mjs} +9 -5
  102. package/dist/.setup/session-initialization-6aveB9qb.mjs +22 -0
  103. package/dist/.setup/{session-permission-policy-BI1QK_98.mjs → session-permission-policy-Ci_fVX6y.mjs} +4 -8
  104. package/dist/.setup/{session-retirement-BH-S6qkJ.mjs → session-retirement-qMTxkNx2.mjs} +17 -17
  105. package/dist/.setup/{settled-turn-context-fmwouT5I.mjs → settled-turn-context-D4yj4rxf.mjs} +1 -1
  106. package/dist/.setup/{settled-turn-finalizer-DiAi6Kx6.mjs → settled-turn-finalizer-BsvEabkw.mjs} +14 -10
  107. package/dist/.setup/{shared-client-DA4VR4Eb.mjs → shared-client-DqyTMYug.mjs} +783 -412
  108. package/dist/.setup/shared-client-lifecycle-DJIgqgMw.mjs +153 -0
  109. package/dist/.setup/{side-question-BJ1wSDcB.mjs → side-question-C4kCmQy1.mjs} +79 -143
  110. package/dist/.setup/{source-CUzJq5WN.mjs → source-CS_7GFJZ.mjs} +80 -137
  111. package/dist/.setup/{thread-lifecycle-B3mfz1TG.mjs → thread-lifecycle-DPflntEJ.mjs} +294 -737
  112. package/dist/.setup/{incognito-session-uhrBF6wJ.mjs → thread-ownership-queue-Dp24d7-F.mjs} +1 -2
  113. package/dist/.setup/{thread-ownership-DcTtAcXj.mjs → thread-ownership-roNP0l1c.mjs} +45 -10
  114. package/dist/.setup/{thread-policy-DGuQsuFC.mjs → thread-policy-DTd-DtkX.mjs} +46 -7
  115. package/dist/.setup/{thread-requests-BLvGkP2R.mjs → thread-requests-B_bRnMGN.mjs} +199 -302
  116. package/dist/.setup/{thread-resume-DIBXwOpE.mjs → thread-resume-CdDaoc7T.mjs} +6 -6
  117. package/dist/.setup/{timeout-C910MdAB.mjs → timeout-CXOfNoaX.mjs} +1 -35
  118. package/dist/.setup/{transcript-history-projection-ZZpkFkJ_.mjs → transcript-history-projection-DRSifI-1.mjs} +17 -89
  119. package/dist/.setup/{transcript-mirror-attestation-CzM-94NC.mjs → transcript-mirror-attestation-YSegaktH.mjs} +3 -4
  120. package/dist/.setup/{transcript-mirror-BtHDBp1G.mjs → transcript-mirror-kxmCYsuF.mjs} +7 -9
  121. package/dist/.setup/{transport-stdio-h2VHOskC.mjs → transport-stdio-Bdegpn2V.mjs} +5 -22
  122. package/dist/.setup/transport-websocket-BTBE-LD9.mjs +211 -0
  123. package/dist/.setup/{upstream-prompt-provenance-LphB8slG.mjs → upstream-prompt-provenance-fXkKbPVC.mjs} +3 -9
  124. package/dist/.setup/{upstream-session-fork-BUr4OUbC.mjs → upstream-session-fork-CBeVjBpT.mjs} +23 -23
  125. package/dist/.setup/{usage-BML0r-ua.mjs → usage-BMzNxeR_.mjs} +4 -4
  126. package/dist/.setup/{usage-limit-error-DUMbefVY.mjs → usage-limit-error-QXerDo3i.mjs} +4 -19
  127. package/dist/.setup/{web-search-provider.runtime-CDKlN-Rv.mjs → web-search-provider.runtime-P77OUeoo.mjs} +8 -19
  128. package/dist/api.js +9 -11
  129. package/dist/catalog-page.worker.js +1 -1
  130. package/dist/cli-metadata.js +1 -1
  131. package/dist/doctor-contract-api.js +50 -8
  132. package/dist/harness.js +344 -1
  133. package/dist/index.js +193 -245
  134. package/dist/media-understanding-provider.js +9 -22
  135. package/dist/migration-provider-api.js +1 -1
  136. package/dist/provider-discovery.js +1 -1
  137. package/dist/session-history-worker-runtime.js +3 -3
  138. package/dist/session-history.worker.js +1 -1
  139. package/openclaw.plugin.json +14 -2
  140. package/package.json +7 -6
  141. package/dist/.setup/attempt-workspace-context-DUVEn_CS.mjs +0 -331
  142. package/dist/.setup/compact-Du5UvtxA.mjs +0 -680
  143. package/dist/.setup/event-projector-assistant-message-BsruvNrH.mjs +0 -103
  144. package/dist/.setup/event-projector-items-C6L_5ZiT.mjs +0 -234
  145. package/dist/.setup/harness-a_MsE4-_.mjs +0 -355
  146. package/dist/.setup/history-rejection-B4nOXNXF.mjs +0 -13
  147. package/dist/.setup/image-payload-sanitizer-tupAr-2o.mjs +0 -79
  148. package/dist/.setup/local-runtime-attribution-B_2mnqhb.mjs +0 -19
  149. package/dist/.setup/native-subagent-history-0nYYgo0k.mjs +0 -148
  150. package/dist/.setup/native-subagent-task-ids-wb8CKZGN.mjs +0 -441
  151. package/dist/.setup/plugin-approval-roundtrip-C0MZzCuP.mjs +0 -122
  152. package/dist/.setup/rolldown-runtime-8H4AJuhK.mjs +0 -14
  153. package/dist/.setup/sandbox-guard-C2sRMOEY.mjs +0 -166
  154. package/dist/.setup/session-binding-Cm0apEbd.mjs +0 -692
  155. package/dist/.setup/session-catalog-events-Bj6j94E_.mjs +0 -347
  156. package/dist/.setup/session-history-read-B3ZfSUbF.mjs +0 -50
  157. package/dist/.setup/session-initialization-rcgbZiid.mjs +0 -75
  158. package/dist/.setup/thread-history-page-DoVpnHim.mjs +0 -83
@@ -1,40 +1,43 @@
1
- import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
2
- import { n as defineCodexBuildState, t as codexBuildSymbol } from "./build-state-C7EnDVgr.mjs";
1
+ import { i as isJsonObject } from "./protocol-CANUwXJ3.mjs";
2
+ import { n as defineCodexBuildState, t as codexBuildSymbol } from "./build-state-Da1_z0kd.mjs";
3
3
  import { t as CODEX_APP_SERVER_AUTH_PROVIDER } from "./auth-profile-selection-DFu9e167.mjs";
4
- import { d as resolveCodexAppServerHomeDir, f as resolveCodexAppServerLocalHomeDir, h as withEphemeralCodexAuthStore, m as withClearedEnvironmentVariables, p as resolveCodexAppServerUserHomeDir } from "./config-security-BEReZ6go.mjs";
5
4
  import { n as isCodexAppServerProxyLaunch } from "./launch-args-DbFCehO7.mjs";
6
- import { i as isJsonObject } from "./protocol-CANUwXJ3.mjs";
7
- import { a as resolveCodexAppServerStartOptionsForAgent, d as readCodexEffectiveConfig, o as resolveCodexComputerUseConfig, t as codexAppServerStartOptionsKey, u as CODEX_SESSION_OVERRIDABLE_LAYER_TYPES } from "./config-options-BvaRs51b.mjs";
8
- import { d as resolveMacOSDesktopCodexBundledMarketplaceCandidates, f as resolveMacOSDesktopCodexComputerUseServiceAppCandidates, i as resolveManagedCodexNativeCommand, l as resolveFirstExistingMacOSDesktopCodexBundledMarketplacePath, r as resolveManagedCodexAppServerStartOptions, t as isManagedCodexDesktopCommand, u as resolveMacOSDesktopCodexAppPathCandidates } from "./managed-binary-BnshlFag.mjs";
9
- import { a as readCodexCliAuthFileApiKey, c as resolveCodexAppServerPreparedApiKeyCacheKey, d as waitForCodexDesktopGeneration, i as fingerprintTokenAuthProfileCacheKey, n as CODEX_AUTH_JSON_FILENAME, o as readFirstNonEmptyEnv, r as fingerprintApiKeyAuthProfileCacheKey, s as resolveCodexAppServerFallbackApiKeyCacheKey, t as CODEX_APP_SERVER_API_KEY_ENV_VARS, u as isCodexDesktopGenerationCurrent } from "./auth-cache-key-B2mpaI9D.mjs";
10
- import { d as createCodexAppServerStartupLifetime, f as getCurrentSharedClientEntry, h as retireSharedCodexAppServerClientIfCurrent, l as closeRetiredSharedClientEntry, n as observeCodexCatalogClient, o as readCodexSessionMeta, p as getSharedCodexAppServerClientState, u as closeRetiredSharedClientEntryIfIdle } from "./session-catalog-events-Bj6j94E_.mjs";
11
- import { n as resolveCodexAppServerSpawnEnv } from "./transport-stdio-h2VHOskC.mjs";
5
+ import { a as withEphemeralCodexAuthStore, i as withClearedEnvironmentVariables, n as resolveCodexAppServerLocalHomeDir, r as resolveCodexAppServerUserHomeDir, t as resolveCodexAppServerHomeDir } from "./auth-start-options-BPIPeEX8.mjs";
6
+ import { a as resolveCodexAppServerStartOptionsForAgent, d as readCodexEffectiveConfig, o as resolveCodexComputerUseConfig, t as codexAppServerStartOptionsKey, u as CODEX_SESSION_OVERRIDABLE_LAYER_TYPES } from "./config-options-CzyWLTJt.mjs";
7
+ import { d as resolveMacOSDesktopCodexBundledMarketplaceCandidates, f as resolveMacOSDesktopCodexComputerUseServiceAppCandidates, i as resolveManagedCodexNativeCommand, l as resolveFirstExistingMacOSDesktopCodexBundledMarketplacePath, r as resolveManagedCodexAppServerStartOptions, t as isManagedCodexDesktopCommand, u as resolveMacOSDesktopCodexAppPathCandidates } from "./managed-binary-kiWRhNRE.mjs";
8
+ import { a as readCodexCliAuthFileApiKey, c as resolveCodexAppServerPreparedApiKeyCacheKey, d as waitForCodexDesktopGeneration, f as readCodexDesktopArtifactTreeFingerprint, i as fingerprintTokenAuthProfileCacheKey, n as CODEX_AUTH_JSON_FILENAME, o as readFirstNonEmptyEnv, r as fingerprintApiKeyAuthProfileCacheKey, s as resolveCodexAppServerFallbackApiKeyCacheKey, t as CODEX_APP_SERVER_API_KEY_ENV_VARS, u as isCodexDesktopGenerationCurrent } from "./auth-cache-key-Dbvq-QgB.mjs";
9
+ import { a as notifyDesktopGenerationDrainChecks, c as retainSharedClientEntry, d as retireSharedCodexAppServerClientIfCurrent, m as waitForUnclaimedSharedClientStartup, n as getCurrentSharedClientEntry, o as ownCodexStartup, r as getSharedCodexAppServerClientState, s as releaseSharedClientEntry, t as createCodexAppServerStartupLifetime, u as retirePendingSharedClientEntryIfUnclaimed } from "./shared-client-lifecycle-DJIgqgMw.mjs";
10
+ import { n as resolveCodexAppServerSpawnEnv } from "./transport-stdio-Bdegpn2V.mjs";
12
11
  import { n as CodexAppServerAuthProfileUnavailableError, r as formatCodexAuthProfileUnavailableMessage } from "./auth-profile-recovery-BREezV0L.mjs";
13
- import { i as withTimeout } from "./timeout-C910MdAB.mjs";
14
- import { n as resolveCodexAppServerRuntimeOptions } from "./config-runtime-C8Rw1m1m.mjs";
15
- import { a as resolveCodexAppServerAuthProfileStore, i as resolveCodexAppServerAuthProfileIdForAgent, r as resolveCodexAppServerAuthProfileId, t as isCodexAppServerNativeAuthProfile } from "./auth-profile-WqZtZfXN.mjs";
16
- import { f as isUnsupportedCodexAppServerVersionError, t as CodexAppServerClient } from "./client-Cs08OXVQ.mjs";
12
+ import { i as withTimeout } from "./timeout-CXOfNoaX.mjs";
13
+ import { n as readCodexSessionMeta } from "./session-catalog-provenance-DoAvktcj.mjs";
14
+ import { n as observeCodexCatalogClient } from "./session-catalog-events-DePDzzjc.mjs";
15
+ import { n as resolveCodexAppServerRuntimeOptions } from "./config-runtime-C0NbLms1.mjs";
16
+ import { a as resolveCodexAppServerAuthProfileStore, i as resolveCodexAppServerAuthProfileIdForAgent, r as resolveCodexAppServerAuthProfileId, t as isCodexAppServerNativeAuthProfile } from "./auth-profile-B0okYl2D.mjs";
17
+ import { i as isCodexResponsesOAuthCredential, n as createCodexResponsesOAuth, o as resolveCodexResponsesOAuthProfileFingerprint, r as isCodexResponsesOAuth, t as CODEX_RESPONSES_OAUTH_PROVIDER } from "./responses-oauth-twnuTaAa.mjs";
18
+ import { f as isUnsupportedCodexAppServerVersionError, t as CodexAppServerClient } from "./client-N0JpgSzF.mjs";
19
+ import { n as isCodexWebSocketOpenFailure } from "./transport-websocket-BTBE-LD9.mjs";
20
+ import { t as __exportAll } from "./session-binding-sidecars-jo6H8dFr.mjs";
17
21
  import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
18
- import { createHash } from "node:crypto";
22
+ import { createHash, randomUUID } from "node:crypto";
19
23
  import { isDeepStrictEqual } from "node:util";
20
24
  import { AgentHarnessPreflightError, resolveDefaultAgentDir } from "openclaw/plugin-sdk/agent-harness-registration";
21
- import { addTimerTimeoutGraceMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
22
25
  import { runExec } from "openclaw/plugin-sdk/process-runtime";
23
- import fs, { constants } from "node:fs";
26
+ import { addTimerTimeoutGraceMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
27
+ import fs, { constants, existsSync } from "node:fs";
24
28
  import path from "node:path";
25
29
  import fs$1 from "node:fs/promises";
30
+ import { extractErrorCode } from "openclaw/plugin-sdk/error-runtime";
31
+ import { resolveGlobalMap } from "openclaw/plugin-sdk/global-singleton";
26
32
  import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
27
33
  import { ensureAuthProfileStore, findPersistedAuthProfileCredential, refreshOAuthCredentialForRuntime, resolveApiKeyForProfile, resolvePersistedAuthProfileOwnerAgentDir } from "openclaw/plugin-sdk/agent-runtime";
28
- import { AgentHarnessPreflightError as AgentHarnessPreflightError$1, embeddedAgentLog as embeddedAgentLog$1, formatErrorMessage } from "openclaw/plugin-sdk/agent-harness-runtime";
34
+ import { AgentHarnessPreflightError as AgentHarnessPreflightError$1, embeddedAgentLog as embeddedAgentLog$1, formatErrorMessage as formatErrorMessage$1 } from "openclaw/plugin-sdk/agent-harness-runtime";
29
35
  import { hasUsableOAuthCredential, resolveOpenAICodexAuthIdentity } from "openclaw/plugin-sdk/provider-auth";
30
36
  import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
31
- import { assertNoSymlinkParents } from "openclaw/plugin-sdk/security-runtime";
37
+ import { assertDirectoryIdentitySync, readDirectoryIdentity } from "@openclaw/fs-safe/advanced";
38
+ import { assertNoSymlinkParents, pathScope } from "openclaw/plugin-sdk/security-runtime";
39
+ import { sleepWithAbort } from "openclaw/plugin-sdk/runtime-env";
32
40
  //#region extensions/codex/src/app-server/attempt-timeouts.ts
33
- /**
34
- * Timeout defaults and normalizers for Codex app-server startup and turn
35
- * liveness watches.
36
- */
37
- /** Minimum startup timeout accepted by the Codex app-server harness. */
38
41
  const CODEX_APP_SERVER_STARTUP_TIMEOUT_FLOOR_MS = 100;
39
42
  const TURN_TERMINAL_SETTLEMENT_TIMEOUT_MS = 12e4;
40
43
  const TURN_FINALIZE_DRAIN_ABORT_GRACE_MS = 5e3;
@@ -53,7 +56,6 @@ function resolvePositiveIntegerTimeoutMs(value, fallbackMs) {
53
56
  const fallback = resolveTimerTimeoutMs(fallbackMs, 1);
54
57
  return resolveTimerTimeoutMs(value, fallback);
55
58
  }
56
- /** Runs startup work with abort and timeout handling plus optional cleanup. */
57
59
  async function withCodexStartupTimeout(params) {
58
60
  if (params.signal.aborted) throw new CodexAppServerStartupError("aborted");
59
61
  let timeout;
@@ -91,13 +93,11 @@ async function withCodexStartupTimeout(params) {
91
93
  abortCleanup?.();
92
94
  }
93
95
  }
94
- /** Resolves startup timeout while honoring the configured floor. */
95
96
  function resolveCodexStartupTimeoutMs(params) {
96
97
  const timeoutFloorMs = resolvePositiveIntegerTimeoutMs(params.timeoutFloorMs, CODEX_APP_SERVER_STARTUP_TIMEOUT_FLOOR_MS);
97
98
  const timeoutMs = resolvePositiveIntegerTimeoutMs(params.timeoutMs, timeoutFloorMs);
98
99
  return Math.max(timeoutFloorMs, timeoutMs);
99
100
  }
100
- /** Adds gateway grace time to a caller timeout without overflowing invalid values. */
101
101
  function resolveCodexGatewayTimeoutWithGraceMs(timeoutMs, graceMs = 1e4) {
102
102
  const timeout = resolvePositiveIntegerTimeoutMs(timeoutMs, 1);
103
103
  const grace = resolveTimerTimeoutMs(graceMs, 0, 0);
@@ -168,17 +168,16 @@ async function assertOwnedCodexHomePath(params) {
168
168
  }
169
169
  async function readRealDirectoryIdentity(directoryPath, label) {
170
170
  const logicalPath = path.resolve(directoryPath);
171
- const before = await fs$1.lstat(logicalPath);
172
- if (before.isSymbolicLink() || !before.isDirectory()) throw new Error(`${label} must be a real directory: ${logicalPath}`);
173
- const realPath = await fs$1.realpath(logicalPath);
174
- const [after, resolved] = await Promise.all([fs$1.lstat(logicalPath), fs$1.lstat(realPath)]);
175
- if (after.isSymbolicLink() || !after.isDirectory() || !resolved.isDirectory() || before.dev !== after.dev || before.ino !== after.ino || after.dev !== resolved.dev || after.ino !== resolved.ino) throw new Error(`${label} changed while its ownership boundary was being established.`);
176
- return {
177
- logicalPath,
178
- realPath,
179
- dev: after.dev,
180
- ino: after.ino
181
- };
171
+ try {
172
+ const identity = await readDirectoryIdentity(logicalPath);
173
+ assertDirectoryIdentitySync(logicalPath, identity);
174
+ return {
175
+ logicalPath,
176
+ ...identity
177
+ };
178
+ } catch (cause) {
179
+ throw new Error(`${label} must remain a real directory: ${logicalPath}`, { cause });
180
+ }
182
181
  }
183
182
  async function assertOwnedServiceParentStable(parent) {
184
183
  await assertDirectoryIdentityStable(parent, "Computer Use service parent");
@@ -186,14 +185,10 @@ async function assertOwnedServiceParentStable(parent) {
186
185
  async function assertDirectoryIdentityStable(expected, label) {
187
186
  if (!await directoryIdentityIsStable(expected)) throw new Error(`${label} changed during refresh; refusing to mutate the replacement path.`);
188
187
  }
189
- async function ownedServiceParentIsStable(parent) {
190
- return await directoryIdentityIsStable(parent);
191
- }
192
188
  async function directoryIdentityIsStable(expected) {
193
189
  try {
194
- const current = await fs$1.lstat(expected.logicalPath);
195
- if (current.isSymbolicLink() || !current.isDirectory() || current.dev !== expected.dev || current.ino !== expected.ino) return false;
196
- return await fs$1.realpath(expected.logicalPath) === expected.realPath;
190
+ assertDirectoryIdentitySync(expected.logicalPath, expected);
191
+ return true;
197
192
  } catch {
198
193
  return false;
199
194
  }
@@ -202,7 +197,7 @@ async function assertNotSymlink(filePath, label) {
202
197
  try {
203
198
  if ((await fs$1.lstat(filePath)).isSymbolicLink()) throw new Error(`${label} must not be a symbolic link: ${filePath}`);
204
199
  } catch (error) {
205
- if (hasNodeErrorCode$1(error, "ENOENT")) return;
200
+ if (extractErrorCode(error) === "ENOENT") return;
206
201
  throw error;
207
202
  }
208
203
  }
@@ -210,84 +205,43 @@ async function ensureRealDirectoryTree(ownershipRoot, directoryPath, label) {
210
205
  const root = path.resolve(ownershipRoot);
211
206
  const target = path.resolve(directoryPath);
212
207
  assertPathAtOrInside(root, target, label);
213
- const relative = path.relative(root, target);
214
- let current = root;
215
- for (const segment of relative.split(path.sep).filter(Boolean)) {
216
- current = path.join(current, segment);
217
- const existing = await fs$1.lstat(current).catch((error) => {
218
- if (hasNodeErrorCode$1(error, "ENOENT")) return;
219
- throw error;
220
- });
221
- if (!existing) {
222
- try {
223
- await fs$1.mkdir(current, { mode: 448 });
224
- } catch (error) {
225
- if (!hasNodeErrorCode$1(error, "EEXIST")) throw error;
226
- }
227
- const created = await fs$1.lstat(current);
228
- if (created.isSymbolicLink() || !created.isDirectory()) throw new Error(`${label} changed while its directory tree was being created: ${current}`);
229
- } else if (existing.isSymbolicLink() || !existing.isDirectory()) throw new Error(`${label} must traverse real directories: ${current}`);
208
+ if (root !== target) {
209
+ const prepared = await pathScope(root, { label }).ensureDir(`${target}${path.sep}`, { mode: 448 });
210
+ if (!prepared.ok) throw new Error(`${label} must traverse real directories: ${prepared.error}`, { cause: prepared.diagnostic });
230
211
  }
231
- await assertNoSymlinkParents({
232
- rootDir: root,
233
- targetPath: target,
234
- allowMissing: false,
235
- requireDirectories: true,
236
- messagePrefix: "Computer Use service path"
237
- });
238
212
  await readRealDirectoryIdentity(target, label);
239
213
  }
240
214
  function assertPathAtOrInside(rootPath, candidatePath, label) {
241
215
  const relative = path.relative(path.resolve(rootPath), path.resolve(candidatePath));
242
216
  if (relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) throw new Error(`${label} must remain inside ${path.resolve(rootPath)}.`);
243
217
  }
244
- function hasNodeErrorCode$1(error, code) {
245
- return Boolean(error && typeof error === "object" && "code" in error && error.code === code);
246
- }
247
218
  //#endregion
248
219
  //#region extensions/codex/src/app-server/computer-use-cache.ts
249
220
  /** Shared Computer Use plugin cache reconciliation for isolated Codex homes. */
250
221
  const DEFAULT_CODEX_COMPUTER_USE_BUNDLED_MARKETPLACE_PATH = resolveMacOSDesktopCodexBundledMarketplaceCandidates("darwin")[0] ?? "";
251
222
  const DEFAULT_BUNDLED_MARKETPLACE_NAME = "openai-bundled";
252
223
  async function ensureCodexComputerUseSharedPluginCache(params) {
253
- if (!params.config.enabled) return skippedCacheResult("disabled", "Computer Use cache sharing skipped because it is disabled.");
254
- if (params.config.pluginCacheMode === "independent") return skippedCacheResult("independent", "Computer Use cache sharing skipped because pluginCacheMode is independent.");
255
- if (params.config.marketplaceName || params.config.marketplacePath) return skippedCacheResult("explicit_marketplace", "Computer Use cache sharing skipped because an explicit marketplace is configured.");
224
+ if (!params.config.enabled || params.config.pluginCacheMode === "independent" || params.config.marketplaceName || params.config.marketplacePath) return false;
256
225
  const bundledMarketplacePath = resolveComputerUseBundledMarketplacePath(params);
257
226
  const sourcePluginRoot = path.join(bundledMarketplacePath, "plugins", params.config.pluginName);
258
227
  const version = await readBundledPluginVersion(sourcePluginRoot);
259
- if (!version) return skippedCacheResult("source_missing", `Computer Use bundled plugin source was not found at ${sourcePluginRoot}.`);
260
- const marketplaceName = params.config.marketplaceName ?? DEFAULT_BUNDLED_MARKETPLACE_NAME;
261
- const cacheRoot = path.join(params.codexHome, "plugins", "cache", marketplaceName, params.config.pluginName);
262
- const cachePath = path.join(cacheRoot, version);
263
- return {
264
- status: "shared",
265
- changed: await ensureRealDirectoryCopy(cachePath, sourcePluginRoot, version, {
266
- codexHome: params.codexHome,
267
- ownershipRoot: params.ownershipRoot,
268
- assertCurrent: params.assertCurrent,
269
- forceRefresh: params.forceRefresh
270
- }),
271
- cachePath,
272
- targetPath: sourcePluginRoot,
273
- version,
274
- removedStaleVersions: [],
275
- warnings: [],
276
- message: `Computer Use plugin cache ${cachePath} contains bundled plugin ${sourcePluginRoot}.`
277
- };
228
+ if (!version) return false;
229
+ const cacheRoot = path.join(params.codexHome, "plugins", "cache", params.config.marketplaceName ?? DEFAULT_BUNDLED_MARKETPLACE_NAME, params.config.pluginName);
230
+ await ensureRealDirectoryCopy(path.join(cacheRoot, version), sourcePluginRoot, version, {
231
+ codexHome: params.codexHome,
232
+ ownershipRoot: params.ownershipRoot,
233
+ assertCurrent: params.assertCurrent,
234
+ forceRefresh: params.forceRefresh
235
+ });
236
+ return true;
278
237
  }
279
238
  function resolveComputerUseBundledMarketplacePath(params) {
280
239
  return params.bundledMarketplacePath ?? resolveFirstExistingMacOSDesktopCodexBundledMarketplacePath({ candidates: params.bundledMarketplacePathCandidates }) ?? params.bundledMarketplacePathCandidates?.[0] ?? DEFAULT_CODEX_COMPUTER_USE_BUNDLED_MARKETPLACE_PATH;
281
240
  }
282
241
  async function readBundledPluginVersion(sourcePluginRoot) {
283
242
  const pluginJsonPath = path.join(sourcePluginRoot, ".codex-plugin", "plugin.json");
284
- let raw;
285
- try {
286
- raw = await fs$1.readFile(pluginJsonPath, "utf8");
287
- } catch {
288
- return;
289
- }
290
243
  try {
244
+ const raw = await fs$1.readFile(pluginJsonPath, "utf8");
291
245
  const parsed = JSON.parse(raw);
292
246
  return typeof parsed.version === "string" && parsed.version.trim() ? parsed.version.trim() : void 0;
293
247
  } catch {
@@ -305,7 +259,13 @@ async function ensureRealDirectoryCopy(cachePath, sourcePluginRoot, version, bou
305
259
  const physicalCachePath = ownedParent ? path.join(ownedParent.realPath, path.basename(cachePath)) : cachePath;
306
260
  const stat = await fs$1.lstat(physicalCachePath).catch(() => void 0);
307
261
  if (stat?.isDirectory() && !stat.isSymbolicLink()) {
308
- if (await readBundledPluginVersion(physicalCachePath) === version && !boundary.forceRefresh) return false;
262
+ if (await readBundledPluginVersion(physicalCachePath) === version && !boundary.forceRefresh) {
263
+ const [cachedMcp, sourceMcp] = await Promise.all([physicalCachePath, sourcePluginRoot].map(async (root) => fs$1.readFile(path.join(root, ".mcp.json"), "utf8").catch((error) => {
264
+ if (extractErrorCode(error) === "ENOENT") return;
265
+ throw error;
266
+ })));
267
+ if (cachedMcp === sourceMcp) return;
268
+ }
309
269
  }
310
270
  const cacheName = path.basename(cachePath);
311
271
  const physicalCacheRoot = path.dirname(physicalCachePath);
@@ -314,7 +274,8 @@ async function ensureRealDirectoryCopy(cachePath, sourcePluginRoot, version, bou
314
274
  const backupPath = path.join(physicalCacheRoot, `.${cacheName}.backup-${process.pid}-${Date.now()}`);
315
275
  let backupCreated = false;
316
276
  try {
317
- await fs$1.cp(sourcePluginRoot, stagedPath, { recursive: true });
277
+ const physicalSourceRoot = await fs$1.realpath(sourcePluginRoot);
278
+ await fs$1.cp(physicalSourceRoot, stagedPath, { recursive: true });
318
279
  await waitForCodexDesktopGeneration();
319
280
  if (ownedParent) await assertDirectoryIdentityStable(ownedParent, "Computer Use plugin cache parent");
320
281
  if (stat) {
@@ -343,7 +304,6 @@ async function ensureRealDirectoryCopy(cachePath, sourcePluginRoot, version, bou
343
304
  force: true
344
305
  });
345
306
  }
346
- return true;
347
307
  } finally {
348
308
  if (!ownedParent || await directoryIdentityIsStable(ownedParent)) await fs$1.rm(stagingRoot, {
349
309
  recursive: true,
@@ -351,19 +311,148 @@ async function ensureRealDirectoryCopy(cachePath, sourcePluginRoot, version, bou
351
311
  });
352
312
  }
353
313
  }
354
- function skippedCacheResult(status, message) {
314
+ //#endregion
315
+ //#region extensions/codex/src/app-server/computer-use-unified.ts
316
+ /** Materializes the desktop-owned unified MCP template for an isolated Computer Use home. */
317
+ const UNIFIED_COMPUTER_USE_PLUGIN = "unified-computer-use";
318
+ const UNIFIED_SERVER = "cua_repl";
319
+ const CUA_REPL_ENTRY = "@oai/cua/tinyskyAlt";
320
+ /** The selected desktop distribution owns both the plugin and its executable dependencies. */
321
+ async function resolveCodexUnifiedComputerUseRuntime(candidate, codexHome, requestedPluginName, requestedServerName) {
322
+ const pluginName = requestedPluginName ?? "computer-use";
323
+ const serverName = requestedServerName ?? pluginName;
324
+ if (!(pluginName === "computer-use" && serverName === "computer-use") && !(pluginName === "unified-computer-use" && serverName === UNIFIED_SERVER)) return;
325
+ if ((await readObject(path.join(candidate.bundledMarketplacePath, "plugins", "computer-use", ".codex-plugin", "plugin.json")))?.mcpServers && requestedPluginName !== "unified-computer-use") return;
326
+ const pluginRoot = path.join(candidate.bundledMarketplacePath, "plugins", UNIFIED_COMPUTER_USE_PLUGIN);
327
+ const manifest = await readObject(path.join(pluginRoot, ".codex-plugin", "plugin.json"));
328
+ if (!manifest || manifest.name !== "unified-computer-use" || manifest.mcpServers !== "./.mcp.json") return;
329
+ const template = await readObject(path.join(pluginRoot, ".mcp.json"));
330
+ const servers = template?.mcpServers;
331
+ const server = isRecord(servers) ? servers[UNIFIED_SERVER] : void 0;
332
+ if (!template || !isRecord(servers) || !isRecord(server)) throw new Error("The selected desktop's unified Computer Use MCP template is invalid.");
333
+ const runtimeRoot = path.join(candidate.appBundlePath, "Contents", "Resources", "cua_node");
334
+ const modules = path.join(runtimeRoot, "lib", "node_modules");
335
+ const node = path.join(runtimeRoot, "bin", "node");
336
+ const nodeRepl = path.join(runtimeRoot, "bin", "node_repl");
337
+ const launcher = path.join(modules, "@oai", "cua-repl", "bin", "cua-repl.mjs");
338
+ const cuaRoot = path.join(modules, "@oai", "cua");
339
+ const cuaPackage = await readObject(path.join(cuaRoot, "package.json"));
340
+ const cuaEntry = isRecord(cuaPackage?.exports) ? cuaPackage.exports["./tinyskyAlt"] : void 0;
341
+ try {
342
+ if (typeof cuaEntry !== "string" || !cuaEntry.startsWith("./") || path.relative(cuaRoot, path.resolve(cuaRoot, cuaEntry)).startsWith("..")) throw new Error("The desktop CUA package does not expose its unified entry point.");
343
+ await Promise.all([
344
+ fs$1.access(node, constants.X_OK),
345
+ fs$1.access(nodeRepl, constants.X_OK),
346
+ fs$1.access(launcher, constants.R_OK),
347
+ fs$1.access(path.join(modules, "@oai", "sky", "package.json"), constants.R_OK),
348
+ fs$1.access(path.resolve(cuaRoot, cuaEntry), constants.R_OK)
349
+ ]);
350
+ } catch (cause) {
351
+ throw new Error("The selected desktop's unified Computer Use runtime is incomplete.", { cause });
352
+ }
355
353
  return {
356
- status,
357
- changed: false,
358
- message,
359
- removedStaleVersions: [],
360
- warnings: status === "source_missing" ? [message] : []
354
+ pluginRoot,
355
+ sourceFingerprint: await readCodexDesktopArtifactTreeFingerprint(pluginRoot),
356
+ manifest,
357
+ mcp: {
358
+ ...template,
359
+ mcpServers: {
360
+ ...servers,
361
+ [UNIFIED_SERVER]: {
362
+ ...server,
363
+ command: node,
364
+ args: [launcher],
365
+ enabled: true,
366
+ env_vars: [],
367
+ env: {
368
+ CODEX_HOME: codexHome,
369
+ CUA_REPL_NODE_REPL_PATH: nodeRepl,
370
+ CUA_REPL_ENABLED_SURFACES: "computer",
371
+ NODE_REPL_NODE_PATH: node,
372
+ NODE_REPL_NODE_MODULE_DIRS: modules,
373
+ NODE_REPL_TRUSTED_CODE_PATHS: [codexHome, modules].join(path.delimiter),
374
+ NODE_REPL_TRUSTED_SERVICES: JSON.stringify({ sky: "@oai/sky/service" }),
375
+ NODE_REPL_JS_BANNER: `await import(${JSON.stringify(CUA_REPL_ENTRY)});`,
376
+ SKY_CUA_SERVICE_PATH: path.join(codexHome, "computer-use", "Codex Computer Use.app")
377
+ }
378
+ }
379
+ }
380
+ }
361
381
  };
362
382
  }
383
+ async function publishCodexUnifiedComputerUsePlugin(target, runtime) {
384
+ const templatePath = path.join(runtime.pluginRoot, ".mcp.json");
385
+ await fs$1.cp(runtime.pluginRoot, target, {
386
+ recursive: true,
387
+ filter: (source) => source !== templatePath
388
+ });
389
+ await fs$1.writeFile(path.join(target, ".mcp.json"), `${JSON.stringify(runtime.mcp, null, 2)}\n`, { mode: 384 });
390
+ }
391
+ async function codexUnifiedComputerUsePluginMatches(target, runtime) {
392
+ return isDeepStrictEqual(await readObject(path.join(target, ".codex-plugin", "plugin.json")), runtime.manifest) && isDeepStrictEqual(await readObject(path.join(target, ".mcp.json")), runtime.mcp);
393
+ }
394
+ /** Preserve custom identities and legacy desktops; the legacy default follows its replacement. */
395
+ async function resolveManagedCodexComputerUseConfig(config, marketplacePath) {
396
+ if (!marketplacePath || config.marketplaceSource || config.marketplaceName || config.marketplacePath || config.pluginName !== "computer-use" || config.mcpServerName !== "computer-use") return config;
397
+ const plugins = path.join(marketplacePath, "plugins");
398
+ const legacy = await readObject(path.join(plugins, "computer-use", ".codex-plugin", "plugin.json"));
399
+ if (!legacy || legacy.mcpServers) return config;
400
+ const unified = await readObject(path.join(plugins, UNIFIED_COMPUTER_USE_PLUGIN, ".codex-plugin", "plugin.json"));
401
+ const mcp = await readObject(path.join(plugins, UNIFIED_COMPUTER_USE_PLUGIN, ".mcp.json"));
402
+ const server = isRecord(mcp?.mcpServers) ? mcp.mcpServers[UNIFIED_SERVER] : void 0;
403
+ if (unified?.name !== "unified-computer-use" || !isRecord(server) || server.enabled !== true) return config;
404
+ return {
405
+ ...config,
406
+ pluginName: UNIFIED_COMPUTER_USE_PLUGIN,
407
+ mcpServerName: UNIFIED_SERVER
408
+ };
409
+ }
410
+ /** A native plugin disable veto must survive an automatic identity replacement. */
411
+ function isLegacyCodexComputerUsePluginDisabled(config) {
412
+ const plugin = isRecord(config) && isRecord(config.plugins) ? config.plugins["computer-use@openai-bundled"] : void 0;
413
+ return isRecord(plugin) && plugin.enabled === false;
414
+ }
415
+ /** Renaming a server must not discard an operator's legacy server or tool restrictions. */
416
+ function hasLegacyCodexComputerUseMcpPolicy(config) {
417
+ if (!isRecord(config)) return false;
418
+ if (isRecord(config.mcp_servers) && Object.hasOwn(config.mcp_servers, "computer-use")) return true;
419
+ const plugin = isRecord(config.plugins) ? config.plugins["computer-use@openai-bundled"] : void 0;
420
+ return isRecord(plugin) && isRecord(plugin.mcp_servers) && Object.keys(plugin.mcp_servers).length > 0;
421
+ }
422
+ async function readObject(file) {
423
+ try {
424
+ const value = JSON.parse(await fs$1.readFile(file, "utf8"));
425
+ return isRecord(value) ? value : void 0;
426
+ } catch {
427
+ return;
428
+ }
429
+ }
430
+ /** Publish the cache from the same prepared source that native plugin/install consumes. */
431
+ async function reconcileManagedCodexComputerUseCache(params) {
432
+ const config = params.config;
433
+ params.assertCurrent();
434
+ const bundledMarketplacePath = params.managedMarketplacePath ?? params.bundledMarketplacePath;
435
+ const cacheBinding = [
436
+ params.epoch ?? "manual",
437
+ bundledMarketplacePath ?? "default",
438
+ config.pluginName
439
+ ].join("\0");
440
+ const shared = await ensureCodexComputerUseSharedPluginCache({
441
+ codexHome: params.codexHome,
442
+ config,
443
+ ...params.ownershipRoot ? { ownershipRoot: params.ownershipRoot } : {},
444
+ ...bundledMarketplacePath ? { bundledMarketplacePath } : {},
445
+ assertCurrent: params.assertCurrent,
446
+ forceRefresh: params.forceRefresh === true || params.previousCacheBinding !== cacheBinding
447
+ });
448
+ params.assertCurrent();
449
+ return shared ? cacheBinding : void 0;
450
+ }
363
451
  //#endregion
364
452
  //#region extensions/codex/src/app-server/computer-use-marketplace.ts
365
453
  /** Managed local wrapper for Codex's reserved bundled marketplace. */
366
454
  const MARKETPLACE_NAME = "openai-bundled";
455
+ const UNIFIED_SOURCE_FINGERPRINT = ".openclaw-unified-source-fingerprint";
367
456
  const activeInstalls$1 = /* @__PURE__ */ new Map();
368
457
  function resolveCodexManagedBundledMarketplacePath(codexHome) {
369
458
  return path.join(codexHome, ".tmp", "bundled-marketplaces", MARKETPLACE_NAME);
@@ -375,6 +464,7 @@ async function ensureCodexManagedBundledMarketplace(params) {
375
464
  candidates
376
465
  });
377
466
  if (!source) return;
467
+ const unifiedRuntime = await resolveCodexUnifiedComputerUseRuntime(source, params.codexHome, params.computerUsePluginName, params.computerUseMcpServerName);
378
468
  const parentPath = path.dirname(resolveCodexManagedBundledMarketplacePath(params.codexHome));
379
469
  const targetPath = path.join(parentPath, MARKETPLACE_NAME);
380
470
  const parent = await prepareOwnedServiceParent({
@@ -390,11 +480,12 @@ async function ensureCodexManagedBundledMarketplace(params) {
390
480
  await active.promise.catch(() => void 0);
391
481
  return await ensureCodexManagedBundledMarketplace(params);
392
482
  }
393
- const install = reconcileManagedWrapper({
483
+ const install = publishManagedWrapper({
394
484
  parent,
395
485
  physicalTargetPath,
396
486
  targetPath,
397
487
  source,
488
+ unifiedRuntime,
398
489
  ownershipCandidates: params.ownershipCandidates ?? candidates,
399
490
  assertCurrent: params.assertCurrent
400
491
  });
@@ -409,12 +500,9 @@ async function ensureCodexManagedBundledMarketplace(params) {
409
500
  install.then(clearActive, clearActive);
410
501
  return await install;
411
502
  }
412
- async function reconcileManagedWrapper(params) {
413
- if (await wrapperMatches(params.physicalTargetPath, params.source.bundledMarketplacePath)) return params.targetPath;
414
- return await publishManagedWrapper(params);
415
- }
416
503
  async function publishManagedWrapper(params) {
417
504
  const { parent, physicalTargetPath, targetPath, source, ownershipCandidates, assertCurrent } = params;
505
+ if (await wrapperMatches(physicalTargetPath, source.bundledMarketplacePath, params.unifiedRuntime)) return targetPath;
418
506
  const stagingPath = await fs$1.mkdtemp(path.join(parent.realPath, `.${MARKETPLACE_NAME}.staging-`));
419
507
  const backupPath = path.join(parent.realPath, `.${MARKETPLACE_NAME}.backup-${process.pid}-${Date.now()}`);
420
508
  let backupCreated = false;
@@ -424,10 +512,22 @@ async function publishManagedWrapper(params) {
424
512
  recursive: true,
425
513
  mode: 448
426
514
  });
427
- await Promise.all([fs$1.symlink(path.join(source.bundledMarketplacePath, ".agents", "plugins", "marketplace.json"), path.join(manifestParent, "marketplace.json")), fs$1.symlink(path.join(source.bundledMarketplacePath, "plugins"), path.join(stagingPath, "plugins"))]);
515
+ await fs$1.symlink(path.join(source.bundledMarketplacePath, ".agents", "plugins", "marketplace.json"), path.join(manifestParent, "marketplace.json"));
516
+ if (params.unifiedRuntime) {
517
+ const pluginsPath = path.join(stagingPath, "plugins");
518
+ await fs$1.mkdir(pluginsPath);
519
+ for (const entry of await fs$1.readdir(path.join(source.bundledMarketplacePath, "plugins"))) {
520
+ const target = path.join(pluginsPath, entry);
521
+ if (entry === "unified-computer-use") await publishCodexUnifiedComputerUsePlugin(target, params.unifiedRuntime);
522
+ else await fs$1.symlink(path.join(source.bundledMarketplacePath, "plugins", entry), target);
523
+ }
524
+ await fs$1.writeFile(path.join(stagingPath, UNIFIED_SOURCE_FINGERPRINT), params.unifiedRuntime.sourceFingerprint, { mode: 384 });
525
+ } else await fs$1.symlink(path.join(source.bundledMarketplacePath, "plugins"), path.join(stagingPath, "plugins"));
526
+ await waitForCodexDesktopGeneration();
527
+ assertCurrent?.();
428
528
  await assertDirectoryIdentityStable(parent, "managed bundled marketplace parent");
429
529
  const existing = await fs$1.lstat(physicalTargetPath).catch((error) => {
430
- if (hasNodeErrorCode(error, "ENOENT")) return;
530
+ if (extractErrorCode(error) === "ENOENT") return;
431
531
  throw error;
432
532
  });
433
533
  if (existing && !existing.isDirectory()) throw new Error(`Managed bundled marketplace must be a real directory: ${targetPath}`);
@@ -450,7 +550,7 @@ async function publishManagedWrapper(params) {
450
550
  if (backupCreated) try {
451
551
  await assertDirectoryIdentityStable(parent, "managed bundled marketplace parent");
452
552
  if (await fs$1.lstat(physicalTargetPath).catch(() => void 0)) {
453
- if (!await wrapperMatches(physicalTargetPath, source.bundledMarketplacePath)) throw new Error("managed bundled marketplace replacement is no longer owned", { cause: error });
553
+ if (!await wrapperOwnedBySource(physicalTargetPath, source.bundledMarketplacePath)) throw new Error("managed bundled marketplace replacement is no longer owned", { cause: error });
454
554
  await fs$1.rm(physicalTargetPath, { recursive: true });
455
555
  }
456
556
  await fs$1.rename(backupPath, physicalTargetPath);
@@ -481,22 +581,51 @@ async function isExpectedMarketplace(root) {
481
581
  return false;
482
582
  }
483
583
  }
484
- async function wrapperMatches(targetPath, sourcePath) {
584
+ async function wrapperMatches(targetPath, sourcePath, unifiedRuntime) {
585
+ if (!await wrapperOwnedBySource(targetPath, sourcePath)) return false;
586
+ const plugins = await fs$1.lstat(path.join(targetPath, "plugins"));
587
+ if (unifiedRuntime && plugins.isDirectory()) {
588
+ const [sourceEntries, targetEntries] = await Promise.all([fs$1.readdir(path.join(sourcePath, "plugins")), fs$1.readdir(path.join(targetPath, "plugins"))]);
589
+ const sourceNames = new Set(sourceEntries);
590
+ if (sourceNames.size !== targetEntries.length || targetEntries.some((name) => !sourceNames.has(name))) return false;
591
+ }
592
+ return unifiedRuntime ? plugins.isDirectory() && await fs$1.readFile(path.join(targetPath, UNIFIED_SOURCE_FINGERPRINT), "utf8").catch(() => void 0) === unifiedRuntime.sourceFingerprint && await codexUnifiedComputerUsePluginMatches(path.join(targetPath, "plugins", "unified-computer-use"), unifiedRuntime) : plugins.isSymbolicLink();
593
+ }
594
+ async function wrapperOwnedBySource(targetPath, sourcePath) {
485
595
  try {
486
596
  const target = await fs$1.lstat(targetPath);
487
597
  if (!target.isDirectory() || target.isSymbolicLink()) return false;
488
- const [manifest, plugins] = await Promise.all([fs$1.readlink(path.join(targetPath, ".agents", "plugins", "marketplace.json")), fs$1.readlink(path.join(targetPath, "plugins"))]);
489
- return manifest === path.join(sourcePath, ".agents", "plugins", "marketplace.json") && plugins === path.join(sourcePath, "plugins");
598
+ if (await fs$1.readlink(path.join(targetPath, ".agents", "plugins", "marketplace.json")) !== path.join(sourcePath, ".agents", "plugins", "marketplace.json")) return false;
599
+ const pluginsPath = path.join(targetPath, "plugins");
600
+ const plugins = await fs$1.lstat(pluginsPath);
601
+ if (plugins.isSymbolicLink()) return await fs$1.readlink(pluginsPath) === path.join(sourcePath, "plugins");
602
+ if (!plugins.isDirectory()) return false;
603
+ let hasUnifiedPlugin = false;
604
+ for (const entry of await fs$1.readdir(pluginsPath, { withFileTypes: true })) if (entry.name === "unified-computer-use" && entry.isDirectory()) {
605
+ const plugin = JSON.parse(await fs$1.readFile(path.join(pluginsPath, entry.name, ".codex-plugin", "plugin.json"), "utf8"));
606
+ if (!isRecord(plugin) || plugin.name !== "unified-computer-use") return false;
607
+ hasUnifiedPlugin = true;
608
+ } else if (!entry.isSymbolicLink() || await fs$1.readlink(path.join(pluginsPath, entry.name)) !== path.join(sourcePath, "plugins", entry.name)) return false;
609
+ return hasUnifiedPlugin;
490
610
  } catch {
491
611
  return false;
492
612
  }
493
613
  }
494
614
  async function wrapperMatchesAnySource(targetPath, candidates) {
495
- for (const candidate of candidates) if (await wrapperMatches(targetPath, candidate.bundledMarketplacePath)) return true;
615
+ for (const candidate of candidates) if (await wrapperOwnedBySource(targetPath, candidate.bundledMarketplacePath)) return true;
496
616
  return false;
497
617
  }
498
- function hasNodeErrorCode(error, code) {
499
- return Boolean(error && typeof error === "object" && "code" in error && error.code === code);
618
+ async function resolveClientManagedBundledMarketplacePath(codexHome, agentDir) {
619
+ if (!codexHome || !agentDir) return;
620
+ const [actualRealHome, expectedRealHome] = await Promise.all([fs$1.realpath(codexHome).catch(() => void 0), fs$1.realpath(resolveCodexAppServerHomeDir(agentDir)).catch(() => void 0)]);
621
+ if (!actualRealHome || actualRealHome !== expectedRealHome) return;
622
+ const managedPath = resolveCodexManagedBundledMarketplacePath(codexHome);
623
+ return existsSync(managedPath) ? managedPath : void 0;
624
+ }
625
+ function resolveBundledComputerUseMarketplacePath(params) {
626
+ if (params.defaultBundledMarketplacePath) return existsSync(params.defaultBundledMarketplacePath) ? params.defaultBundledMarketplacePath : void 0;
627
+ if (!params.defaultBundledMarketplacePathCandidates) return;
628
+ return resolveFirstExistingMacOSDesktopCodexBundledMarketplacePath({ candidates: params.defaultBundledMarketplacePathCandidates });
500
629
  }
501
630
  //#endregion
502
631
  //#region extensions/codex/src/app-server/computer-use-service.ts
@@ -548,7 +677,6 @@ async function ensureCodexComputerUseServiceApp(params) {
548
677
  ownershipRoot,
549
678
  targetParent,
550
679
  targetPath,
551
- platform,
552
680
  sourceAppCandidates: candidates
553
681
  });
554
682
  const activeEntry = {
@@ -564,13 +692,20 @@ async function ensureCodexComputerUseServiceApp(params) {
564
692
  }
565
693
  async function ensureCodexComputerUseServiceAppOnce(params) {
566
694
  const inspectServiceApp = params.inspectServiceApp ?? inspectTrustedServiceApp;
567
- const source = await findUsableServiceApp(params.sourceAppCandidates ?? [], inspectServiceApp);
695
+ const source = await findUsableServiceApp(params.sourceAppCandidates, inspectServiceApp);
568
696
  if (!source) return {
569
697
  status: "source_missing",
570
698
  changed: false,
571
699
  targetPath: params.targetPath
572
700
  };
573
701
  const { path: sourcePath, identity: sourceIdentity } = source;
702
+ const alreadyCurrent = {
703
+ status: "already_current",
704
+ changed: false,
705
+ targetPath: params.targetPath,
706
+ sourcePath,
707
+ sourceBuild: sourceIdentity.build
708
+ };
574
709
  const ownedParent = await prepareOwnedServiceParent({
575
710
  ownershipRoot: params.ownershipRoot,
576
711
  codexHome: params.codexHome,
@@ -579,19 +714,29 @@ async function ensureCodexComputerUseServiceAppOnce(params) {
579
714
  const operationTargetPath = path.join(ownedParent.realPath, SERVICE_APP_NAME);
580
715
  await assertNotSymlink(operationTargetPath, "Computer Use service target");
581
716
  const initialTarget = await readServiceAppSnapshot(operationTargetPath, inspectServiceApp);
582
- if (initialTarget.identity && identitiesMatch(initialTarget.identity, sourceIdentity)) return {
583
- status: "already_current",
584
- changed: false,
585
- targetPath: params.targetPath,
586
- sourcePath,
587
- sourceBuild: sourceIdentity.build
588
- };
717
+ if (initialTarget.identity && identitiesMatch(initialTarget.identity, sourceIdentity)) return alreadyCurrent;
589
718
  await assertOwnedServiceParentStable(ownedParent);
590
719
  const stagingRoot = await fs$1.mkdtemp(path.join(ownedParent.realPath, ".service-app.staging-"));
591
720
  const stagingRootIdentity = await readRealDirectoryIdentity(stagingRoot, "Computer Use service staging directory");
592
721
  const stagedPath = path.join(stagingRoot, SERVICE_APP_NAME);
593
722
  const backupPath = path.join(ownedParent.realPath, `.service-app.backup-${process.pid}-${Date.now()}`);
594
723
  let backupCreated = false;
724
+ const restoreBackup = async () => {
725
+ await assertOwnedServiceParentStable(ownedParent);
726
+ await fs$1.rename(backupPath, operationTargetPath);
727
+ await assertOwnedServiceParentStable(ownedParent);
728
+ backupCreated = false;
729
+ };
730
+ const removeBackup = async () => {
731
+ await assertOwnedServiceParentStable(ownedParent);
732
+ await assertNotSymlink(backupPath, "Computer Use service backup");
733
+ await fs$1.rm(backupPath, {
734
+ recursive: true,
735
+ force: true
736
+ });
737
+ await assertOwnedServiceParentStable(ownedParent);
738
+ backupCreated = false;
739
+ };
595
740
  try {
596
741
  await (params.copyServiceApp ?? copyServiceAppWithDitto)(sourcePath, stagedPath);
597
742
  await assertOwnedServiceParentStable(ownedParent);
@@ -614,23 +759,11 @@ async function ensureCodexComputerUseServiceAppOnce(params) {
614
759
  backupCreated = true;
615
760
  const movedTarget = await readServiceAppSnapshot(backupPath, inspectServiceApp);
616
761
  if (movedTarget.identity && identitiesMatch(movedTarget.identity, sourceIdentity)) {
617
- await assertOwnedServiceParentStable(ownedParent);
618
- await fs$1.rename(backupPath, operationTargetPath);
619
- await assertOwnedServiceParentStable(ownedParent);
620
- backupCreated = false;
621
- return {
622
- status: "already_current",
623
- changed: false,
624
- targetPath: params.targetPath,
625
- sourcePath,
626
- sourceBuild: sourceIdentity.build
627
- };
762
+ await restoreBackup();
763
+ return alreadyCurrent;
628
764
  }
629
765
  if (!snapshotsMatch(initialTarget, movedTarget)) {
630
- await assertOwnedServiceParentStable(ownedParent);
631
- await fs$1.rename(backupPath, operationTargetPath);
632
- await assertOwnedServiceParentStable(ownedParent);
633
- backupCreated = false;
766
+ await restoreBackup();
634
767
  throw new Error("Computer Use service target changed to an unexpected generation during refresh.");
635
768
  }
636
769
  }
@@ -644,33 +777,11 @@ async function ensureCodexComputerUseServiceAppOnce(params) {
644
777
  await assertNotSymlink(operationTargetPath, "Computer Use service target");
645
778
  const winnerIdentity = await inspectServiceApp(operationTargetPath);
646
779
  if (!winnerIdentity || !identitiesMatch(winnerIdentity, sourceIdentity)) {
647
- if (backupCreated) {
648
- if (!await pathExists$1(operationTargetPath)) {
649
- await assertOwnedServiceParentStable(ownedParent);
650
- await fs$1.rename(backupPath, operationTargetPath);
651
- await assertOwnedServiceParentStable(ownedParent);
652
- backupCreated = false;
653
- }
654
- }
780
+ if (backupCreated && !await pathExists$1(operationTargetPath)) await restoreBackup();
655
781
  throw error;
656
782
  }
657
- if (backupCreated) {
658
- await assertOwnedServiceParentStable(ownedParent);
659
- await assertNotSymlink(backupPath, "Computer Use service backup");
660
- await fs$1.rm(backupPath, {
661
- recursive: true,
662
- force: true
663
- });
664
- await assertOwnedServiceParentStable(ownedParent);
665
- backupCreated = false;
666
- }
667
- return {
668
- status: "already_current",
669
- changed: false,
670
- targetPath: params.targetPath,
671
- sourcePath,
672
- sourceBuild: sourceIdentity.build
673
- };
783
+ if (backupCreated) await removeBackup();
784
+ return alreadyCurrent;
674
785
  }
675
786
  await assertNotSymlink(operationTargetPath, "Installed Computer Use service app");
676
787
  const installedSnapshot = await readServiceAppSnapshot(operationTargetPath, inspectServiceApp);
@@ -690,16 +801,7 @@ async function ensureCodexComputerUseServiceAppOnce(params) {
690
801
  }
691
802
  throw new Error("Installed Computer Use service app failed post-install identity verification.");
692
803
  }
693
- if (backupCreated) {
694
- await assertOwnedServiceParentStable(ownedParent);
695
- await assertNotSymlink(backupPath, "Computer Use service backup");
696
- await fs$1.rm(backupPath, {
697
- recursive: true,
698
- force: true
699
- });
700
- await assertOwnedServiceParentStable(ownedParent);
701
- backupCreated = false;
702
- }
804
+ if (backupCreated) await removeBackup();
703
805
  return {
704
806
  status: initialTarget.exists ? "refreshed" : "installed",
705
807
  changed: true,
@@ -709,14 +811,14 @@ async function ensureCodexComputerUseServiceAppOnce(params) {
709
811
  ...initialTarget.identity ? { previousBuild: initialTarget.identity.build } : {}
710
812
  };
711
813
  } catch (error) {
712
- if (backupCreated && await ownedServiceParentIsStable(ownedParent) && !await pathExists$1(operationTargetPath)) {
814
+ if (backupCreated && await directoryIdentityIsStable(ownedParent) && !await pathExists$1(operationTargetPath)) {
713
815
  await assertOwnedServiceParentStable(ownedParent);
714
816
  await fs$1.rename(backupPath, operationTargetPath);
715
817
  backupCreated = false;
716
818
  }
717
819
  throw error;
718
820
  } finally {
719
- if (await ownedServiceParentIsStable(ownedParent) && await directoryIdentityIsStable(stagingRootIdentity)) await fs$1.rm(stagingRoot, {
821
+ if (await directoryIdentityIsStable(ownedParent) && await directoryIdentityIsStable(stagingRootIdentity)) await fs$1.rm(stagingRoot, {
720
822
  recursive: true,
721
823
  force: true
722
824
  });
@@ -763,18 +865,10 @@ function filesystemSnapshotsMatch(left, right) {
763
865
  function identitiesMatch(left, right) {
764
866
  return left.bundleId === right.bundleId && left.version === right.version && left.build === right.build && left.cdHash === right.cdHash && left.teamId === right.teamId && left.clientBundleId === right.clientBundleId && left.clientCdHash === right.clientCdHash && left.clientTeamId === right.clientTeamId;
765
867
  }
766
- async function hasExecutableClient(appPath) {
767
- try {
768
- await fs$1.access(path.join(appPath, CLIENT_RELATIVE_PATH), constants.X_OK);
769
- return true;
770
- } catch {
771
- return false;
772
- }
773
- }
774
868
  async function inspectTrustedServiceApp(appPath) {
775
- if (!await hasExecutableClient(appPath)) return;
776
869
  const clientAppPath = path.join(appPath, CLIENT_APP_RELATIVE_PATH);
777
870
  try {
871
+ await fs$1.access(path.join(appPath, CLIENT_RELATIVE_PATH), constants.X_OK);
778
872
  await verifyTrustedBundle(appPath, SERVICE_BUNDLE_ID, true);
779
873
  await verifyTrustedBundle(clientAppPath, CLIENT_BUNDLE_ID, false);
780
874
  const [info, serviceSignature, clientSignature] = await Promise.all([
@@ -918,8 +1012,7 @@ function resolveUnimportedAgentCodexAuthMessage(params) {
918
1012
  const targetAgentId = params.agentId?.trim() || "<agent-id>";
919
1013
  return `A Codex auth file exists at ${authPath}, but agent-scoped Codex runs use OpenClaw's auth store and do not read that file. Preview only that credential import with \`openclaw migrate plan codex --from <codex-home> --agent ${targetAgentId} --include-secrets --item auth:openai\`, then run \`openclaw migrate apply codex --from <codex-home> --agent ${targetAgentId} --include-secrets --item auth:openai --yes\`. If the plan finds no credentials, remove the stale auth file.`;
920
1014
  }
921
- /** Resolves prepared profile login material once so cache identity and RPC login cannot drift. */
922
- async function resolveCodexAppServerPreparedAuthProfileSnapshot(params) {
1015
+ function resolveCodexAppServerAuthProfile(params) {
923
1016
  const agentDir = params.agentDir?.trim() || resolveDefaultAgentDir(params.config ?? {});
924
1017
  const store = resolveCodexAppServerAuthProfileStore({
925
1018
  agentDir,
@@ -934,7 +1027,33 @@ async function resolveCodexAppServerPreparedAuthProfileSnapshot(params) {
934
1027
  });
935
1028
  if (!profileId) return;
936
1029
  const credential = store.profiles[profileId];
937
- if (!credential || !isCodexAppServerAuthProfileCredential(credential)) return;
1030
+ if (!credential || !isCodexAppServerAuthProvider(credential.provider)) return;
1031
+ return {
1032
+ agentDir,
1033
+ store,
1034
+ profileId,
1035
+ credential
1036
+ };
1037
+ }
1038
+ /** Resolves prepared profile login material once so cache identity and RPC login cannot drift. */
1039
+ async function resolveCodexAppServerPreparedAuthProfileSnapshot(params) {
1040
+ const profile = resolveCodexAppServerAuthProfile(params);
1041
+ if (!profile) return;
1042
+ const { agentDir, store, profileId, credential } = profile;
1043
+ if (isCodexResponsesOAuthCredential(credential)) return {
1044
+ inferenceAuth: "host-oauth",
1045
+ loginParams: {
1046
+ type: "apiKey",
1047
+ apiKey: `openclaw-local-${randomUUID()}`
1048
+ },
1049
+ secretFreeCacheKey: await resolveCodexResponsesOAuthProfileFingerprint({
1050
+ profileId,
1051
+ store,
1052
+ agentDir,
1053
+ config: params.config
1054
+ })
1055
+ };
1056
+ if (credential.type === "oauth" && credential.authFlow === "chatgpt-identity") throw new Error("ChatGPT subscription sharing was not granted; sign in again and enable sharing.");
938
1057
  const loginParams = await resolveCodexAppServerAuthProfileLoginParamsInternal({
939
1058
  agentDir,
940
1059
  authProfileId: profileId,
@@ -955,6 +1074,22 @@ async function resolveCodexAppServerPreparedAuthProfileSnapshot(params) {
955
1074
  /** Maps one prepared route to one mutually exclusive app-server auth handoff. */
956
1075
  async function resolveCodexAppServerPreparedAuthHandoff(params) {
957
1076
  const usesNativeHome = params.homeScope === "user";
1077
+ const selectedCredential = params.authProfileId ? params.authProfileStore.profiles[params.authProfileId] : void 0;
1078
+ if (isCodexResponsesOAuthCredential(selectedCredential)) {
1079
+ if (usesNativeHome || params.requirePreparedAuth || params.authRequirement !== "api-key") throw new Error("ChatGPT subscription sharing requires the managed local Codex API route and an isolated home.");
1080
+ const snapshot = await resolveCodexAppServerPreparedAuthProfileSnapshot(params);
1081
+ if (!snapshot || !params.authProfileId) throw new Error("ChatGPT subscription sharing could not prepare the selected profile.");
1082
+ return {
1083
+ authProfileId: params.authProfileId,
1084
+ nativeAuthProfile: false,
1085
+ preparedAuth: {
1086
+ kind: "profile",
1087
+ profileId: params.authProfileId,
1088
+ store: params.authProfileStore,
1089
+ snapshot
1090
+ }
1091
+ };
1092
+ }
958
1093
  if (params.requirePreparedAuth && usesNativeHome) throw createCodexAppServerAuthError("Codex remote-exec cloud placement requires prepared OpenAI auth. Configure an OpenAI API-key, OAuth, or token profile and use appServer.homeScope=\"agent\"; ambient credentials and native Codex auth are not allowed.");
959
1094
  if (usesNativeHome) return { nativeAuthProfile: true };
960
1095
  if (params.authRequirement === "api-key") {
@@ -1000,21 +1135,9 @@ async function resolveCodexAppServerPreparedAuthHandoff(params) {
1000
1135
  };
1001
1136
  }
1002
1137
  async function resolveCodexAppServerAuthAccountCacheKey(params) {
1003
- const agentDir = params.agentDir?.trim() || resolveDefaultAgentDir(params.config ?? {});
1004
- const store = resolveCodexAppServerAuthProfileStore({
1005
- agentDir,
1006
- authProfileId: params.authProfileId,
1007
- authProfileStore: params.authProfileStore,
1008
- config: params.config
1009
- });
1010
- const profileId = resolveCodexAppServerAuthProfileId({
1011
- authProfileId: params.authProfileId,
1012
- store,
1013
- config: params.config
1014
- });
1015
- if (!profileId) return;
1016
- const credential = store.profiles[profileId];
1017
- if (!credential || !isCodexAppServerAuthProfileCredential(credential)) return;
1138
+ const profile = resolveCodexAppServerAuthProfile(params);
1139
+ if (!profile) return;
1140
+ const { agentDir, store, profileId, credential } = profile;
1018
1141
  const accountId = resolveChatgptAccountId(profileId, credential);
1019
1142
  if (credential.type === "oauth") return accountId;
1020
1143
  const value = (await resolveApiKeyForProfile({
@@ -1106,12 +1229,15 @@ async function reconcileCodexComputerUseStartArtifactsOnce(params) {
1106
1229
  needsBundledMarketplace
1107
1230
  }) : exactDesktopCandidate;
1108
1231
  params.assertCurrent();
1232
+ let marketplacePath;
1109
1233
  if (provisioningAgentDir) {
1110
1234
  if (desktopCandidates.length > 0 && !artifactCandidate) throw new CodexComputerUseCandidateArtifactsUnavailableError();
1111
1235
  try {
1112
- const marketplacePath = usesManagedBundledMarketplace ? await ensureCodexManagedBundledMarketplace({
1236
+ marketplacePath = usesManagedBundledMarketplace ? await ensureCodexManagedBundledMarketplace({
1113
1237
  codexHome,
1114
1238
  ownershipRoot: provisioningAgentDir,
1239
+ computerUsePluginName: computerUseConfig.pluginName,
1240
+ computerUseMcpServerName: computerUseConfig.mcpServerName,
1115
1241
  ...artifactCandidate ? {
1116
1242
  appServerCommand: artifactCandidate.appServerCommandPath,
1117
1243
  candidates: [artifactCandidate],
@@ -1142,21 +1268,17 @@ async function reconcileCodexComputerUseStartArtifactsOnce(params) {
1142
1268
  }
1143
1269
  }
1144
1270
  params.assertCurrent();
1145
- const cacheBinding = [
1146
- params.desktopGeneration?.epoch ?? "manual",
1147
- artifactCandidate?.bundledMarketplacePath ?? "default",
1148
- computerUseConfig.pluginName
1149
- ].join("\0");
1150
- const cache = await ensureCodexComputerUseSharedPluginCache({
1271
+ return await reconcileManagedCodexComputerUseCache({
1151
1272
  codexHome,
1152
1273
  config: computerUseConfig,
1153
- ...ownsIsolatedCodexHome ? { ownershipRoot: params.agentDir } : {},
1154
- ...artifactCandidate ? { bundledMarketplacePath: artifactCandidate.bundledMarketplacePath } : {},
1274
+ ownershipRoot: ownsIsolatedCodexHome ? params.agentDir : void 0,
1275
+ managedMarketplacePath: marketplacePath,
1276
+ bundledMarketplacePath: artifactCandidate?.bundledMarketplacePath,
1277
+ epoch: params.desktopGeneration?.epoch,
1155
1278
  assertCurrent: params.assertCurrent,
1156
- forceRefresh: params.forceCacheRefresh === true || params.previousCacheBinding !== cacheBinding
1279
+ forceRefresh: params.forceCacheRefresh,
1280
+ previousCacheBinding: params.previousCacheBinding
1157
1281
  });
1158
- params.assertCurrent();
1159
- return cache.status === "shared" ? cacheBinding : void 0;
1160
1282
  }
1161
1283
  async function resolveCompleteComputerUseArtifactCandidate(params) {
1162
1284
  for (const candidate of params.candidates) {
@@ -1194,10 +1316,14 @@ async function applyCodexAppServerAuthProfile(params) {
1194
1316
  let loginParams = params.preparedAuth?.kind === "profile" ? params.preparedAuth.snapshot.loginParams : params.preparedAuth?.kind === "api-key" ? {
1195
1317
  type: "apiKey",
1196
1318
  apiKey: params.preparedAuth.apiKey
1197
- } : await resolveCodexAppServerAuthProfileLoginParams({
1319
+ } : await resolveCodexAppServerAuthProfileLoginParamsInternal({
1198
1320
  agentDir,
1199
1321
  authProfileId: params.authProfileId ?? void 0,
1200
- authProfileStore: params.authProfileStore,
1322
+ authProfileStore: resolveCodexAppServerAuthProfileStore({
1323
+ ...params,
1324
+ agentDir,
1325
+ authProfileId: params.authProfileId ?? void 0
1326
+ }),
1201
1327
  config: params.config
1202
1328
  });
1203
1329
  if (params.authRequirement === "subscription" && loginParams?.type !== "chatgptAuthTokens") throw createCodexAppServerAuthError("Codex subscription auth profile could not produce login credentials. Sign in with `openclaw models auth login --provider openai`, select that profile, then retry.");
@@ -1241,13 +1367,6 @@ function createCodexAppServerAuthError(message, cause) {
1241
1367
  const error = cause === void 0 ? new Error(message) : new Error(message, { cause });
1242
1368
  return Object.assign(error, { status: 401 });
1243
1369
  }
1244
- async function resolveCodexAppServerAuthProfileLoginParams(params) {
1245
- const store = resolveCodexAppServerAuthProfileStore(params);
1246
- return await resolveCodexAppServerAuthProfileLoginParamsInternal({
1247
- ...params,
1248
- authProfileStore: store
1249
- });
1250
- }
1251
1370
  async function refreshCodexAppServerAuthTokens(params) {
1252
1371
  const previousAccountId = params.previousAccountId?.trim();
1253
1372
  const handoffAccountId = params.authHandoff?.chatgptAccountId.trim();
@@ -1268,8 +1387,7 @@ async function refreshCodexAppServerAuthTokens(params) {
1268
1387
  forceOAuthRefresh: true
1269
1388
  });
1270
1389
  if (!loginParams || loginParams.type !== "chatgptAuthTokens") throw new Error("Codex app-server ChatGPT token refresh requires an OAuth auth profile. Sign in with `openclaw models auth login --provider openai`, select that profile, then retry.");
1271
- if (previousAccountId && loginParams.chatgptAccountId !== previousAccountId) throw new Error("ChatGPT workspace changed during Codex token refresh. Retry to start a client for the selected workspace.");
1272
- if (params.authHandoff && loginParams.chatgptAccountId !== params.authHandoff.chatgptAccountId) throw new Error("ChatGPT workspace changed during Codex token refresh. Retry to start a client for the selected workspace.");
1390
+ if (previousAccountId && loginParams.chatgptAccountId !== previousAccountId || params.authHandoff && loginParams.chatgptAccountId !== params.authHandoff.chatgptAccountId) throw new Error("ChatGPT workspace changed during Codex token refresh. Retry to start a client for the selected workspace.");
1273
1391
  return {
1274
1392
  accessToken: loginParams.accessToken,
1275
1393
  chatgptAccountId: loginParams.chatgptAccountId,
@@ -1291,7 +1409,7 @@ async function resolveCodexAppServerAuthProfileLoginParamsInternal(params) {
1291
1409
  if (!profileId) return;
1292
1410
  const credential = store.profiles[profileId];
1293
1411
  if (!credential) throw new CodexAppServerAuthProfileUnavailableError(formatCodexAuthProfileUnavailableMessage(profileId));
1294
- if (!isCodexAppServerAuthProfileCredential(credential)) throw new CodexAppServerAuthProfileUnavailableError(`Codex app-server auth profile "${profileId}" must use the canonical OpenAI auth provider; run "openclaw doctor --fix" to migrate legacy provider IDs.`);
1412
+ if (!isCodexAppServerAuthProvider(credential.provider)) throw new CodexAppServerAuthProfileUnavailableError(`Codex app-server auth profile "${profileId}" must use the canonical OpenAI auth provider; run "openclaw doctor --fix" to migrate legacy provider IDs.`);
1295
1413
  const loginParams = await resolveLoginParamsForCredential(profileId, credential, {
1296
1414
  agentDir: params.agentDir,
1297
1415
  store,
@@ -1469,15 +1587,11 @@ async function resolveScopedOAuthCredential(params) {
1469
1587
  }
1470
1588
  function assertCodexOAuthRefreshWorkspace(profileId, credential, expectedAccountId) {
1471
1589
  if (!expectedAccountId) return;
1472
- const loginParams = buildChatgptAuthTokensParams(profileId, credential, credential.access.trim());
1473
- if (loginParams.type !== "chatgptAuthTokens" || loginParams.chatgptAccountId !== expectedAccountId) throw new Error("ChatGPT workspace changed during Codex token refresh. Retry to start a client for the selected workspace.");
1590
+ if (buildChatgptAuthTokensParams(profileId, credential, credential.access.trim()).chatgptAccountId !== expectedAccountId) throw new Error("ChatGPT workspace changed during Codex token refresh. Retry to start a client for the selected workspace.");
1474
1591
  }
1475
1592
  function isCodexAppServerAuthProvider(provider) {
1476
1593
  return provider.trim().toLowerCase() === CODEX_APP_SERVER_AUTH_PROVIDER;
1477
1594
  }
1478
- function isCodexAppServerAuthProfileCredential(credential) {
1479
- return isCodexAppServerAuthProvider(credential.provider);
1480
- }
1481
1595
  function shouldClearOpenAiApiKeyForCodexAuthProfile(params) {
1482
1596
  const profileId = params.authProfileId?.trim();
1483
1597
  return isCodexSubscriptionCredential(profileId ? params.store.profiles[profileId] : params.store.profiles[OPENAI_CODEX_DEFAULT_PROFILE_ID]);
@@ -1529,7 +1643,7 @@ function createThreadOwnerToken(threadId, onInvalidated) {
1529
1643
  } catch (error) {
1530
1644
  embeddedAgentLog$1.warn("codex thread ownership invalidation failed", {
1531
1645
  threadId,
1532
- reason: formatErrorMessage(error)
1646
+ reason: formatErrorMessage$1(error)
1533
1647
  });
1534
1648
  }
1535
1649
  }
@@ -1575,6 +1689,21 @@ function forgetThreadOwnership(runtime, threadId, owner) {
1575
1689
  if (forgotten) owner.invalidate();
1576
1690
  return forgotten;
1577
1691
  }
1692
+ /** Compaction discards client-authored catalog refreshes, not creation policy. */
1693
+ function revertRetainedThreadSkillsCatalog(runtime, threadId) {
1694
+ const retained = runtime.retainedThreads.get(threadId);
1695
+ if (retained?.ephemeralPolicy) retained.ephemeralPolicy = {
1696
+ ...retained.ephemeralPolicy,
1697
+ skillsInstructions: retained.ephemeralPolicy.nativeSkillsInstructions
1698
+ };
1699
+ }
1700
+ function createCodexEphemeralThreadPolicy({ developerInstructions, skillsInstructions }) {
1701
+ return {
1702
+ developerInstructions,
1703
+ skillsInstructions,
1704
+ nativeSkillsInstructions: skillsInstructions
1705
+ };
1706
+ }
1578
1707
  //#endregion
1579
1708
  //#region extensions/codex/src/app-server/rate-limit-cache.ts
1580
1709
  const DEFAULT_CODEX_RATE_LIMIT_CACHE_MAX_AGE_MS = 6e5;
@@ -1841,7 +1970,7 @@ function scheduleRetainedThreadEviction(client, runtime) {
1841
1970
  runtime.evictionTimer = setTimeout(() => {
1842
1971
  runtime.evictionTimer = void 0;
1843
1972
  evictExpiredRetainedThreads(client, runtime).catch((error) => {
1844
- embeddedAgentLog$1.warn("codex retained thread expiry failed", { reason: formatErrorMessage(error) });
1973
+ embeddedAgentLog$1.warn("codex retained thread expiry failed", { reason: formatErrorMessage$1(error) });
1845
1974
  });
1846
1975
  }, Math.max(0, expiresAt - Date.now()));
1847
1976
  runtime.evictionTimer.unref?.();
@@ -1935,7 +2064,7 @@ async function retainCodexAppServerLiveThread(client, threadId, releaseThread, c
1935
2064
  scheduleRetainedThreadEviction(client, runtime);
1936
2065
  embeddedAgentLog$1.warn("codex retained thread capacity eviction failed", {
1937
2066
  threadId,
1938
- reason: formatErrorMessage(error)
2067
+ reason: formatErrorMessage$1(error)
1939
2068
  });
1940
2069
  return false;
1941
2070
  }
@@ -2039,6 +2168,11 @@ function claimCodexAppServerThreadOwnership(client, runtime, threadId, retained,
2039
2168
  }
2040
2169
  };
2041
2170
  }
2171
+ /** Standalone incognito compaction retains its separately owned subscription. */
2172
+ function revertCodexAppServerLiveThreadSkillsCatalog(client, threadId) {
2173
+ const runtime = configuredClients.get(client);
2174
+ if (runtime && !runtime.closed) revertRetainedThreadSkillsCatalog(runtime, threadId);
2175
+ }
2042
2176
  /** Distinguish active claimed ownership from an already-evicted idle subscription. */
2043
2177
  function hasCodexAppServerLiveThread(client, threadId) {
2044
2178
  return hasThreadOwnership(configuredClients.get(client), threadId);
@@ -2128,25 +2262,156 @@ function protectCodexAppServerLiveThread(client, threadId) {
2128
2262
  evictExcessIdleThreads(client, runtime).catch((error) => {
2129
2263
  embeddedAgentLog$1.warn("codex retained thread unpin eviction failed", {
2130
2264
  threadId,
2131
- reason: formatErrorMessage(error)
2265
+ reason: formatErrorMessage$1(error)
2132
2266
  });
2133
2267
  });
2134
2268
  };
2135
2269
  }
2136
2270
  //#endregion
2271
+ //#region extensions/codex/src/app-server/client-startup-retry.ts
2272
+ /** Recovers physical startup, including acquisitions before thread preparation. */
2273
+ async function withCodexWebSocketOpenRetry(params) {
2274
+ const startedAt = performance.now();
2275
+ for (let attempt = 1;; attempt += 1) try {
2276
+ return await params.start(resolveRemainingAcquireTimeout(params.timeoutMs, startedAt));
2277
+ } catch (error) {
2278
+ if (params.signal.aborted || attempt >= 3 || !isCodexWebSocketOpenFailure(error)) throw error;
2279
+ const remaining = resolveRemainingAcquireTimeout(params.timeoutMs, startedAt);
2280
+ const delay = 1e3 * 2 ** (attempt - 1);
2281
+ await sleepWithAbort(remaining > 0 ? Math.min(delay, remaining) : delay, params.signal);
2282
+ }
2283
+ }
2284
+ function resolveRemainingAcquireTimeout(timeoutMs, startedAt) {
2285
+ if (!(timeoutMs > 0)) return timeoutMs;
2286
+ const remaining = timeoutMs - (performance.now() - startedAt);
2287
+ if (remaining <= 0) throw new CodexAppServerStartupError("timed_out", "codex app-server initialize timed out");
2288
+ return remaining;
2289
+ }
2290
+ async function withCodexAppServerAcquireDeadline(timeoutMs, promise, signal, timeoutMessage = "codex app-server initialize timed out", timeoutErrorFactory) {
2291
+ if (signal?.aborted) throw new CodexAppServerStartupError("aborted", "codex app-server initialize aborted");
2292
+ const timed = withTimeout(promise, timeoutMs, timeoutMessage, () => timeoutErrorFactory?.() ?? new CodexAppServerStartupError("timed_out", timeoutMessage));
2293
+ if (!signal) return await timed;
2294
+ return await new Promise((resolve, reject) => {
2295
+ const onAbort = () => reject(new CodexAppServerStartupError("aborted", "codex app-server initialize aborted"));
2296
+ signal.addEventListener("abort", onAbort, { once: true });
2297
+ timed.then(resolve, reject).finally(() => signal.removeEventListener("abort", onAbort));
2298
+ });
2299
+ }
2300
+ //#endregion
2301
+ //#region extensions/codex/src/app-server/inference-environment.ts
2302
+ function supportsInferenceEnvironment(native) {
2303
+ if (native.CODEX_CA_CERTIFICATE?.trim() || native.SSL_CERT_FILE?.trim()) return false;
2304
+ const names = [
2305
+ "HTTP_PROXY",
2306
+ "HTTPS_PROXY",
2307
+ "ALL_PROXY",
2308
+ "NO_PROXY"
2309
+ ];
2310
+ for (const upper of names) {
2311
+ const lower = upper.toLowerCase();
2312
+ if (native[upper] !== process.env[upper] || native[lower] !== process.env[lower] || native[upper] !== void 0 && native[lower] !== void 0 && native[upper] !== native[lower]) return false;
2313
+ }
2314
+ const value = (name) => (native[name] ?? native[name.toLowerCase()])?.trim() || void 0;
2315
+ const http = value("HTTP_PROXY");
2316
+ const https = value("HTTPS_PROXY");
2317
+ const all = value("ALL_PROXY");
2318
+ if (!http && !https && !all) return true;
2319
+ const noProxy = native.NO_PROXY ?? native.no_proxy ?? "";
2320
+ if (noProxy === "*") return true;
2321
+ if (native.REQUEST_METHOD !== void 0 || names.slice(0, 3).some((name) => {
2322
+ const raw = native[name] ?? native[name.toLowerCase()];
2323
+ return raw !== void 0 && raw !== raw.trim();
2324
+ })) return false;
2325
+ if ((https ?? all) !== (https ?? http ?? all)) return false;
2326
+ const bypasses = noProxy.split(",").map((entry) => entry.trim()).filter(Boolean);
2327
+ if (bypasses.some((entry) => ![
2328
+ "127.0.0.1",
2329
+ "localhost",
2330
+ "::1",
2331
+ "[::1]"
2332
+ ].includes(entry))) return false;
2333
+ if ((http || all) && !bypasses.includes("127.0.0.1")) return false;
2334
+ return /^https?:\/\//.test(https ?? all ?? "");
2335
+ }
2336
+ //#endregion
2337
+ //#region extensions/codex/src/app-server/inference-provider-config.ts
2338
+ function providerKind(name) {
2339
+ if (name === "Amazon Bedrock" || name === "Amazon Bedrock Runtime") return;
2340
+ return name === "OpenAI" ? "openai" : typeof name === "string" && name.toLowerCase() === "azure" ? "azure" : "other";
2341
+ }
2342
+ function hasProviderAws(config, provider) {
2343
+ return readProviderField(config, provider, "aws") != null || Object.keys(config ?? {}).some((key) => key.startsWith(`model_providers.${provider}.aws.`));
2344
+ }
2345
+ function configuredProviders(...configs) {
2346
+ const providers = /* @__PURE__ */ new Set(["openai"]);
2347
+ for (const config of configs) {
2348
+ for (const provider of Object.keys(isJsonObject(config?.model_providers) ? config.model_providers : {})) providers.add(provider);
2349
+ for (const key of Object.keys(config ?? {})) {
2350
+ const provider = /^model_providers\.([^.]+)(?:\.|$)/.exec(key)?.[1];
2351
+ if (provider) providers.add(provider);
2352
+ }
2353
+ }
2354
+ return providers;
2355
+ }
2356
+ function projectProviderRoutes(config, providers) {
2357
+ let projected = config ?? {};
2358
+ for (const [provider, route] of providers) projected = withProviderBaseUrl(projected, provider, route.baseUrl);
2359
+ return projected;
2360
+ }
2361
+ function readProviderBaseUrl(config, provider) {
2362
+ if (provider === "openai") return config?.openai_base_url;
2363
+ return readProviderField(config, provider, "base_url");
2364
+ }
2365
+ function readProviderField(config, provider, field) {
2366
+ const selected = (isJsonObject(config?.model_providers) ? config.model_providers : void 0)?.[provider];
2367
+ const flat = config?.[`model_providers.${provider}`];
2368
+ return config?.[`model_providers.${provider}.${field}`] ?? (isJsonObject(flat) ? flat[field] : void 0) ?? (isJsonObject(selected) ? selected[field] : void 0);
2369
+ }
2370
+ function withProviderBaseUrl(config, provider, baseUrl) {
2371
+ if (provider === "openai") return {
2372
+ ...config,
2373
+ openai_base_url: baseUrl
2374
+ };
2375
+ const providers = isJsonObject(config?.model_providers) ? config.model_providers : {};
2376
+ const selected = providers[provider];
2377
+ const providerKey = `model_providers.${provider}`;
2378
+ const baseUrlKey = `${providerKey}.base_url`;
2379
+ const flat = config?.[providerKey];
2380
+ return {
2381
+ ...config,
2382
+ model_providers: {
2383
+ ...providers,
2384
+ [provider]: {
2385
+ ...isJsonObject(selected) ? selected : {},
2386
+ base_url: baseUrl
2387
+ }
2388
+ },
2389
+ ...isJsonObject(flat) ? { [providerKey]: {
2390
+ ...flat,
2391
+ base_url: baseUrl
2392
+ } } : {},
2393
+ ...config?.[baseUrlKey] !== void 0 ? { [baseUrlKey]: baseUrl } : {}
2394
+ };
2395
+ }
2396
+ //#endregion
2137
2397
  //#region extensions/codex/src/app-server/inference-routing.ts
2138
2398
  const owners = defineCodexBuildState("openclaw.codexAppServerInferenceOwners", () => /* @__PURE__ */ new WeakMap())();
2139
2399
  const MAX_ROUTES = 8;
2140
2400
  const MAX_THREADS = 256;
2141
- const NATIVE_OPENAI_UPSTREAMS = /* @__PURE__ */ new Set(["https://api.openai.com/v1", "https://chatgpt.com/backend-api/codex"]);
2142
2401
  /** Only managed native stdio startup calls this; locality or metadata cannot opt a client in. */
2143
- function ownCodexInferenceClient(client) {
2402
+ function ownCodexInferenceClient(client, startOptions = {}, oauth) {
2144
2403
  if (owners.has(client)) return;
2404
+ if (!supportsInferenceEnvironment(resolveCodexAppServerSpawnEnv(startOptions))) {
2405
+ if (oauth) throw new Error("ChatGPT subscription sharing requires the managed public Responses inference route with a compatible proxy and trust configuration.");
2406
+ return;
2407
+ }
2145
2408
  const owner = {
2146
2409
  closed: false,
2410
+ memoryConfigured: false,
2147
2411
  routes: /* @__PURE__ */ new Map(),
2148
2412
  threads: /* @__PURE__ */ new Map(),
2149
- handles: /* @__PURE__ */ new Set()
2413
+ handles: /* @__PURE__ */ new Map(),
2414
+ oauth
2150
2415
  };
2151
2416
  owners.set(client, owner);
2152
2417
  const close = () => {
@@ -2165,10 +2430,11 @@ function ownCodexInferenceClient(client) {
2165
2430
  });
2166
2431
  }
2167
2432
  async function prepareCodexInferenceRoute(params) {
2168
- const owner = owners.get(params.client);
2433
+ const client = params.client;
2434
+ const owner = owners.get(client);
2169
2435
  if (!owner) return;
2170
2436
  const assertClient = () => {
2171
- if (owner.closed || owners.get(params.client) !== owner) throw new Error("Codex inference route ownership changed; reconnect before retrying");
2437
+ if (owner.closed || owners.get(client) !== owner) throw new Error("Codex inference route ownership changed; reconnect before retrying");
2172
2438
  };
2173
2439
  const assertCurrent = () => {
2174
2440
  assertClient();
@@ -2178,40 +2444,102 @@ async function prepareCodexInferenceRoute(params) {
2178
2444
  assertCurrent();
2179
2445
  const snapshot = params.effectiveConfig ?? await readCodexEffectiveConfig(params.client, params.cwd, { signal: params.signal });
2180
2446
  assertCurrent();
2181
- if (snapshot.config.model_provider != null && snapshot.config.model_provider !== "openai") return;
2182
- if (isJsonObject(snapshot.config.features) && snapshot.config.features.respect_system_proxy === true) return;
2183
- const configured = snapshot.config.openai_base_url;
2447
+ const unsupported = () => {
2448
+ if (owner.oauth) throw new Error("ChatGPT subscription sharing requires the managed public Responses inference route.");
2449
+ };
2450
+ const selectedProvider = params.modelProvider ?? params.config?.model_provider ?? snapshot.config.model_provider ?? "openai";
2451
+ if (owner.oauth && (snapshot.config.model_provider != null && snapshot.config.model_provider !== "openai" || selectedProvider !== "openai" && selectedProvider !== "openclaw_token_sharing")) return unsupported();
2452
+ const provider = owner.oauth ? CODEX_RESPONSES_OAUTH_PROVIDER : selectedProvider;
2453
+ if (typeof provider !== "string" || !provider.trim()) return unsupported();
2454
+ const customProvider = !owner.oauth && provider !== "openai";
2455
+ const providerField = (field) => readProviderField(params.config, provider, field) ?? readProviderField(snapshot.config, provider, field);
2456
+ const nativeProviderName = owner.oauth ? "OpenClaw subscription sharing" : customProvider ? providerField("name") : "OpenAI";
2457
+ const kind = providerKind(nativeProviderName);
2458
+ const wireApi = customProvider ? providerField("wire_api") : "responses";
2459
+ if (!kind || customProvider && ([
2460
+ "amazon-bedrock",
2461
+ "amazon-bedrock-runtime",
2462
+ "ollama",
2463
+ "lmstudio"
2464
+ ].includes(provider) || hasProviderAws(params.config, provider) || hasProviderAws(snapshot.config, provider) || wireApi != null && wireApi !== "responses")) return unsupported();
2465
+ if ((params.config?.["features.respect_system_proxy"] ?? (isJsonObject(params.config?.features) ? params.config.features.respect_system_proxy : void 0) ?? (isJsonObject(snapshot.config.features) ? snapshot.config.features.respect_system_proxy : void 0)) === true) return unsupported();
2466
+ const configured = customProvider ? providerField("base_url") : params.config?.openai_base_url ?? snapshot.config.openai_base_url;
2184
2467
  if (configured != null && typeof configured !== "string") throw new Error("Codex inference upstream configuration is invalid");
2468
+ if (typeof configured === "string" && (!configured.trim() || configured.includes("?") || configured.includes("#"))) return unsupported();
2185
2469
  if (configured) {
2186
2470
  let target;
2187
2471
  try {
2188
2472
  target = new URL(configured);
2189
2473
  } catch {
2190
- return;
2474
+ return unsupported();
2191
2475
  }
2192
- if (!NATIVE_OPENAI_UPSTREAMS.has(target.href.replace(/\/$/, ""))) return;
2476
+ if (target.protocol !== "https:" || target.username || target.password || target.hash || target.search || owner.oauth && target.href.replace(/\/$/, "") !== "https://api.openai.com/v1") return unsupported();
2193
2477
  }
2194
- const origin = snapshot.origins?.openai_base_url;
2195
- if (origin && !CODEX_SESSION_OVERRIDABLE_LAYER_TYPES.has(origin.name.type)) return;
2196
- const account = await params.client.request("account/read", { refreshToken: false }, {
2478
+ if (customProvider && !configured) return unsupported();
2479
+ const configKey = customProvider ? `model_providers.${provider}.base_url` : "openai_base_url";
2480
+ if (Object.entries(snapshot.origins ?? {}).filter(([key]) => customProvider ? key === "model_providers" || key === `model_providers.${provider}` || key === configKey : key === configKey).some(([, origin]) => !origin || !CODEX_SESSION_OVERRIDABLE_LAYER_TYPES.has(origin.name.type))) return unsupported();
2481
+ const account = customProvider ? void 0 : await params.client.request("account/read", { refreshToken: false }, {
2197
2482
  signal: params.signal,
2198
2483
  assertCurrent
2199
2484
  });
2200
2485
  assertCurrent();
2201
- const type = account.account?.type;
2202
- if (type !== "apiKey" && type !== "chatgpt") return;
2203
- if (owner.authRoute && owner.authRoute !== type) throw new Error("Codex native account route changed; reconnect before retrying");
2204
- owner.authRoute = type;
2486
+ const type = account?.account?.type;
2487
+ if (owner.oauth && type !== "apiKey") return unsupported();
2488
+ if (!customProvider && type !== "apiKey" && type !== "chatgpt") return unsupported();
2489
+ if (!customProvider && owner.authRoute && owner.authRoute !== type) throw new Error("Codex native account route changed; reconnect before retrying");
2490
+ if (type === "apiKey" || type === "chatgpt") owner.authRoute = type;
2205
2491
  const target = new URL(configured || (type === "apiKey" ? "https://api.openai.com/v1" : "https://chatgpt.com/backend-api/codex"));
2206
- const key = target.toString();
2492
+ const { isBlockedHostnameOrIp } = await import("openclaw/plugin-sdk/ssrf-runtime");
2493
+ assertCurrent();
2494
+ if (isBlockedHostnameOrIp(target.hostname)) return unsupported();
2495
+ const nativeBaseUrl = typeof configured === "string" ? configured.toLowerCase() : target.href;
2496
+ const preserveAzureUrlFeatures = typeof nativeProviderName === "string" && nativeProviderName.toLowerCase() === "azure" || [
2497
+ "openai.azure.",
2498
+ "cognitiveservices.azure.",
2499
+ "aoai.azure.",
2500
+ "azure-api.",
2501
+ "azurefd.",
2502
+ "windows.net/openai"
2503
+ ].some((marker) => nativeBaseUrl.includes(marker));
2504
+ const preserveCodexBackendRoutes = nativeProviderName === "OpenAI" && (configured == null || configured.replace(/\/+$/, "").endsWith("/backend-api/codex"));
2505
+ const memoryFeature = params.config?.["features.memories"] ?? (isJsonObject(params.config?.features) ? params.config.features.memories : void 0) ?? (isJsonObject(snapshot.config.features) ? snapshot.config.features.memories : void 0);
2506
+ owner.memoryConfigured ||= memoryFeature === true;
2507
+ const modelPolicyEnforced = params.modelPolicyEnforced !== false;
2508
+ const key = JSON.stringify([
2509
+ provider,
2510
+ target.toString(),
2511
+ kind,
2512
+ preserveAzureUrlFeatures,
2513
+ preserveCodexBackendRoutes,
2514
+ modelPolicyEnforced
2515
+ ]);
2207
2516
  let pending = owner.routes.get(key);
2208
2517
  if (!pending) {
2209
- if (owner.routes.size >= MAX_ROUTES) throw new Error("Codex inference route limit reached");
2210
- pending = import("./inference-proxy-b-aJMSxm.mjs").then(({ createCodexInferenceProxy }) => {
2518
+ if (owner.routes.size >= MAX_ROUTES) {
2519
+ if (params.optionalProjection) return unsupported();
2520
+ throw new Error("Codex inference route limit reached; start a fresh managed native connection before retrying.");
2521
+ }
2522
+ pending = Promise.all([
2523
+ import("./inference-proxy-DhcXOgUE.mjs"),
2524
+ import("./native-subagent-monitor-Dpsmf2wz.mjs").then((n) => n.n),
2525
+ import("./inference-dispatch-CMZtjQyz.mjs")
2526
+ ]).then(([{ createCodexInferenceProxy }, native, { createCodexInferenceModelBinding }]) => {
2211
2527
  assertClient();
2212
2528
  return createCodexInferenceProxy({
2213
2529
  upstream: target,
2214
- assertCurrent: assertClient
2530
+ assertCurrent: assertClient,
2531
+ oauth: owner.oauth,
2532
+ preserveAzureUrlFeatures,
2533
+ preserveCodexBackendRoutes,
2534
+ bindModelExecution: createCodexInferenceModelBinding({
2535
+ client,
2536
+ provider,
2537
+ modelPolicyEnforced,
2538
+ assertCurrent: assertClient,
2539
+ memoryConfigured: () => owner.memoryConfigured,
2540
+ captureModelSource: native.codexNativeSubagentMonitorRuntime.captureModelSource,
2541
+ resolveModelThreadId: native.codexNativeSubagentMonitorRuntime.resolveModelThreadId
2542
+ })
2215
2543
  });
2216
2544
  });
2217
2545
  owner.routes.set(key, pending);
@@ -2220,14 +2548,41 @@ async function prepareCodexInferenceRoute(params) {
2220
2548
  assertCurrent();
2221
2549
  route.assertCurrent();
2222
2550
  params.client.protectPrivateTransportSecret(new URL(route.baseUrl).pathname.split("/")[1] ?? "");
2223
- owner.handles.add(route);
2551
+ owner.handles.set(route, {
2552
+ provider,
2553
+ kind,
2554
+ modelPolicyEnforced
2555
+ });
2224
2556
  return route;
2225
2557
  }
2226
2558
  /** Prepare a managed thread without changing an attached or unsupported native profile. */
2227
2559
  async function prepareCodexInferenceThreadConfig(params) {
2228
2560
  const { binding } = params;
2229
- if (binding?.connectionScope === "supervision" || binding?.preserveNativeModel === true) return;
2230
- const route = await prepareCodexInferenceRoute(params);
2561
+ const owner = owners.get(params.client);
2562
+ if (!owner) return;
2563
+ if (owner.closed) throw new Error("Codex inference route ownership changed; reconnect before retrying");
2564
+ const preserved = binding?.connectionScope === "supervision" || binding?.preserveNativeModel === true;
2565
+ let retained = preserved && binding?.clientId === params.clientId ? owner.threads.get(binding.threadId) : void 0;
2566
+ if (preserved) {
2567
+ if (owner.oauth) throw new Error("ChatGPT subscription sharing cannot attach to a native Codex thread.");
2568
+ if (!retained) return;
2569
+ retained.route.assertCurrent();
2570
+ if (owner.handles.get(retained.route)?.modelPolicyEnforced !== (params.modelPolicyEnforced !== false)) retained = void 0;
2571
+ else if (!params.operatorBacked) return {
2572
+ route: retained.route,
2573
+ providers: retained.providers,
2574
+ config: projectProviderRoutes(params.config, retained.providers)
2575
+ };
2576
+ }
2577
+ params.signal?.throwIfAborted();
2578
+ params.assertCurrent();
2579
+ const effectiveConfig = params.effectiveConfig ?? await readCodexEffectiveConfig(params.client, params.cwd, { signal: params.signal });
2580
+ params.signal?.throwIfAborted();
2581
+ params.assertCurrent();
2582
+ const route = retained?.route ?? await prepareCodexInferenceRoute({
2583
+ ...params,
2584
+ effectiveConfig
2585
+ });
2231
2586
  if (!route) return;
2232
2587
  if (binding?.clientId === params.clientId && !getCodexInferenceThread(params.client, binding.threadId)) {
2233
2588
  const { thread } = await params.client.request("thread/read", {
@@ -2240,23 +2595,65 @@ async function prepareCodexInferenceThreadConfig(params) {
2240
2595
  params.assertCurrent();
2241
2596
  if (thread.id !== binding.threadId || thread.status?.type !== "notLoaded") throw new Error("Codex loaded thread has no owned inference route; reconnect before retrying");
2242
2597
  }
2243
- if (params.config?.openai_base_url !== void 0 && params.config.openai_base_url !== route.upstream) throw new Error("Codex thread configuration conflicts with its trusted inference upstream");
2244
- return {
2598
+ const provider = owner.handles.get(route)?.provider;
2599
+ if (!provider) throw new Error("Codex inference provider ownership changed");
2600
+ if (owner.oauth) return {
2245
2601
  route,
2246
2602
  config: {
2247
2603
  ...params.config,
2248
- openai_base_url: route.baseUrl
2604
+ model_provider: CODEX_RESPONSES_OAUTH_PROVIDER,
2605
+ model_providers: { [CODEX_RESPONSES_OAUTH_PROVIDER]: responsesOAuthProvider(route) }
2249
2606
  }
2250
2607
  };
2608
+ if (!params.operatorBacked) return {
2609
+ route,
2610
+ config: withProviderBaseUrl(params.config, provider, route.baseUrl)
2611
+ };
2612
+ const providers = new Map(retained?.providers ?? [[provider, route]]);
2613
+ for (const candidate of configuredProviders(effectiveConfig.config, params.config)) {
2614
+ if (providers.has(candidate)) continue;
2615
+ const sibling = await prepareCodexInferenceRoute({
2616
+ ...params,
2617
+ effectiveConfig,
2618
+ modelProvider: candidate,
2619
+ optionalProjection: true
2620
+ });
2621
+ if (sibling) providers.set(candidate, sibling);
2622
+ }
2623
+ return {
2624
+ route,
2625
+ config: projectProviderRoutes(params.config, providers),
2626
+ providers
2627
+ };
2628
+ }
2629
+ function responsesOAuthProvider(route) {
2630
+ return {
2631
+ name: "OpenClaw subscription sharing",
2632
+ base_url: route.baseUrl,
2633
+ wire_api: "responses",
2634
+ requires_openai_auth: true,
2635
+ supports_websockets: false
2636
+ };
2251
2637
  }
2252
2638
  /** Validate the exact private handle and unchanged upstream, not a localhost string exception. */
2253
- function assertCodexInferenceRouteConfig(client, route, config) {
2639
+ function assertCodexInferenceRouteConfig(client, route, config, modelProvider, providers) {
2254
2640
  if (!route) return;
2255
2641
  const owner = owners.get(client);
2256
- if (!owner || owner.closed || !owner.handles.has(route) || config?.openai_base_url !== route.baseUrl) throw new Error("Codex parent-local inference route was overridden; no turn was sent");
2642
+ const provider = (owner?.handles.get(route))?.provider;
2643
+ const selectedProvider = modelProvider ?? config?.model_provider ?? provider;
2644
+ const systemProxy = config?.["features.respect_system_proxy"] ?? (isJsonObject(config?.features) ? config.features.respect_system_proxy : void 0);
2645
+ if (!owner || owner.closed || !provider || selectedProvider !== provider || systemProxy === true || readProviderBaseUrl(config, provider) !== route.baseUrl) throw new Error("Codex parent-local inference route was overridden; no turn was sent");
2646
+ if (owner.oauth && (config?.model_provider !== "openclaw_token_sharing" || !isJsonObject(config?.model_providers) || !isDeepStrictEqual(config.model_providers["openclaw_token_sharing"], responsesOAuthProvider(route)) || Object.keys(config).some((key) => key.startsWith(`model_providers.openclaw_token_sharing`)))) throw new Error("Codex parent-local inference route was overridden; no turn was sent");
2257
2647
  route.assertCurrent();
2648
+ for (const [candidate, sibling] of providers ?? [[provider, route]]) {
2649
+ const siblingDefinition = owner.handles.get(sibling);
2650
+ const name = readProviderField(config, candidate, "name");
2651
+ const wireApi = readProviderField(config, candidate, "wire_api");
2652
+ if (siblingDefinition?.provider !== candidate || readProviderBaseUrl(config, candidate) !== sibling.baseUrl || candidate !== "openai" && (name !== void 0 && providerKind(name) !== siblingDefinition.kind || wireApi !== void 0 && wireApi !== "responses" || hasProviderAws(config, candidate))) throw new Error("Codex native provider inference route was overridden; no turn was sent");
2653
+ sibling.assertCurrent();
2654
+ }
2258
2655
  }
2259
- function bindCodexInferenceThread(client, threadId, route) {
2656
+ function bindCodexInferenceThread(client, threadId, route, providers) {
2260
2657
  const owner = owners.get(client);
2261
2658
  if (!owner && !route) return;
2262
2659
  if (!owner || owner.closed) throw new Error("Codex inference client is closed");
@@ -2265,30 +2662,53 @@ function bindCodexInferenceThread(client, threadId, route) {
2265
2662
  return;
2266
2663
  }
2267
2664
  route.assertCurrent();
2665
+ const provider = owner.handles.get(route)?.provider;
2666
+ if (!provider) throw new Error("Codex inference provider ownership changed");
2268
2667
  if (!owner.threads.has(threadId) && owner.threads.size >= MAX_THREADS) throw new Error("Codex inference thread limit reached; reconnect before retrying");
2269
- owner.threads.set(threadId, route);
2668
+ const projected = new Map(providers ?? [[provider, route]]);
2669
+ if (projected.get(provider) !== route) throw new Error("Codex inference provider ownership changed");
2670
+ const assertCurrent = () => {
2671
+ if (owner.closed || owners.get(client) !== owner) throw new Error("Codex inference client is closed");
2672
+ for (const [candidate, routed] of projected) {
2673
+ if (owner.handles.get(routed)?.provider !== candidate) throw new Error("Codex inference provider ownership changed");
2674
+ routed.assertCurrent();
2675
+ }
2676
+ };
2677
+ assertCurrent();
2678
+ const qualification = owner.handles.get(route)?.modelPolicyEnforced ? Object.freeze({
2679
+ assertCurrent,
2680
+ hasProvider: (candidate) => {
2681
+ assertCurrent();
2682
+ const projectedRoute = projected.get(candidate);
2683
+ return projectedRoute !== void 0 && owner.handles.get(projectedRoute)?.modelPolicyEnforced === true;
2684
+ }
2685
+ }) : void 0;
2686
+ owner.threads.set(threadId, {
2687
+ route,
2688
+ providers: projected,
2689
+ qualification
2690
+ });
2270
2691
  }
2271
2692
  function getCodexInferenceThread(client, threadId) {
2272
2693
  const owner = owners.get(client);
2273
2694
  if (owner?.closed) throw new Error("Codex inference client is closed");
2274
- return owner?.threads.get(threadId);
2695
+ return owner?.threads.get(threadId)?.route;
2696
+ }
2697
+ /** Configuration provenance for native restore admission, independent of the input's source. */
2698
+ function getCodexInferenceThreadQualification(client, threadId) {
2699
+ const owner = owners.get(client);
2700
+ if (owner?.closed) throw new Error("Codex inference client is closed");
2701
+ return owner?.threads.get(threadId)?.qualification;
2275
2702
  }
2276
2703
  //#endregion
2277
2704
  //#region extensions/codex/src/app-server/native-config-fence.ts
2705
+ /** Serializes this Gateway's native config writes with its config-loading requests. */
2278
2706
  const CODEX_NATIVE_CONFIG_FENCE_STATE = Symbol.for("openclaw.codexNativeConfigFenceState");
2279
- function getFenceState() {
2280
- const globalState = globalThis;
2281
- globalState[CODEX_NATIVE_CONFIG_FENCE_STATE] ??= /* @__PURE__ */ new Map();
2282
- return globalState[CODEX_NATIVE_CONFIG_FENCE_STATE];
2283
- }
2284
2707
  /** Acquires the per-CODEX_HOME fence and returns an idempotent release. */
2285
2708
  async function acquireCodexNativeConfigFence(key, options = {}) {
2286
- const state = getFenceState();
2709
+ const state = resolveGlobalMap(CODEX_NATIVE_CONFIG_FENCE_STATE);
2287
2710
  const previous = state.get(key) ?? Promise.resolve();
2288
- let resolveCurrent = () => void 0;
2289
- const current = new Promise((resolve) => {
2290
- resolveCurrent = resolve;
2291
- });
2711
+ const { promise: current, resolve: resolveCurrent } = createDeferred();
2292
2712
  state.set(key, current);
2293
2713
  try {
2294
2714
  await waitForPreviousFence(previous, options);
@@ -2381,9 +2801,14 @@ function resolveCodexAppServerSpawnIdentity(startOptions, resolvedNativeCommand)
2381
2801
  }
2382
2802
  //#endregion
2383
2803
  //#region extensions/codex/src/app-server/thread-lifecycle-errors.ts
2804
+ const CODEX_APP_SERVER_CONTEXT_RESTART_SELECTION_CHANGED = "CODEX_APP_SERVER_CONTEXT_RESTART_SELECTION_CHANGED";
2805
+ /** True when a pre-write context restart must replay on the newly selected owner. */
2806
+ function isCodexContextRestartSelectionChangedError(error) {
2807
+ return error instanceof Error && "code" in error && error.code === "CODEX_APP_SERVER_CONTEXT_RESTART_SELECTION_CHANGED";
2808
+ }
2384
2809
  var CodexThreadStartRequestError = class extends Error {
2385
2810
  constructor(cause) {
2386
- super(`thread/start: ${formatErrorMessage(cause)}`, { cause });
2811
+ super(`thread/start: ${formatErrorMessage$1(cause)}`, { cause });
2387
2812
  this.name = "CodexThreadStartRequestError";
2388
2813
  }
2389
2814
  };
@@ -2407,10 +2832,6 @@ var CodexAdoptedThreadActiveError = class extends AgentHarnessPreflightError$1 {
2407
2832
  };
2408
2833
  //#endregion
2409
2834
  //#region extensions/codex/src/app-server/shared-client.ts
2410
- /**
2411
- * Owns shared and isolated Codex app-server client startup, auth application,
2412
- * lease tracking, and teardown.
2413
- */
2414
2835
  var shared_client_exports = /* @__PURE__ */ __exportAll({
2415
2836
  assertCodexAppServerClientStartSelectionCurrent: () => assertCodexAppServerClientStartSelectionCurrent,
2416
2837
  captureCodexAppServerClientLifetime: () => captureCodexAppServerClientLifetime,
@@ -2429,7 +2850,6 @@ var shared_client_exports = /* @__PURE__ */ __exportAll({
2429
2850
  releaseCodexAppServerClientLease: () => releaseCodexAppServerClientLease,
2430
2851
  releaseLeasedSharedCodexAppServerClient: () => releaseLeasedSharedCodexAppServerClient,
2431
2852
  resolveCodexNativeConfigFenceKey: () => resolveCodexNativeConfigFenceKey,
2432
- retainSharedCodexAppServerClientByInstanceId: () => retainSharedCodexAppServerClientByInstanceId,
2433
2853
  retainSharedCodexAppServerClientIfCurrent: () => retainSharedCodexAppServerClientIfCurrent,
2434
2854
  retireSharedCodexAppServerClientIfCurrent: () => retireSharedCodexAppServerClientIfCurrent,
2435
2855
  waitForCodexAppServerClientDesktopGenerationDrain: () => waitForCodexAppServerClientDesktopGenerationDrain,
@@ -2437,12 +2857,6 @@ var shared_client_exports = /* @__PURE__ */ __exportAll({
2437
2857
  });
2438
2858
  const SHARED_CODEX_APP_SERVER_CLIENT_DISPOSER = codexBuildSymbol("openclaw.codexAppServerClientDisposer");
2439
2859
  const CODEX_APP_SERVER_INITIALIZE_TIMEOUT_MESSAGE = "codex app-server initialize timed out";
2440
- function ownCodexStartup(lifetime, operation) {
2441
- lifetime.pending.add(operation);
2442
- const release = () => lifetime.pending.delete(operation);
2443
- operation.then(release, release);
2444
- return operation;
2445
- }
2446
2860
  async function prepareCodexAppServerClient(options) {
2447
2861
  const lifetime = getSharedCodexAppServerClientState().startup;
2448
2862
  const abandonSignal = options?.abandonSignal ? AbortSignal.any([lifetime.controller.signal, options.abandonSignal]) : lifetime.controller.signal;
@@ -2471,11 +2885,9 @@ function readCodexAppServerClientProcessIdentity(client) {
2471
2885
  ...runtimeIdentity?.userAgent ? { userAgent: runtimeIdentity.userAgent } : {}
2472
2886
  };
2473
2887
  }
2474
- /** Returns the lifecycle fingerprint that owns a managed desktop client. */
2475
2888
  function readCodexAppServerClientDesktopGenerationFingerprint(client) {
2476
2889
  return readCodexAppServerClientDesktopGeneration(client)?.fingerprint;
2477
2890
  }
2478
- /** Returns the lifecycle generation that owns a managed desktop client. */
2479
2891
  function readCodexAppServerClientDesktopGeneration(client) {
2480
2892
  return getSharedCodexAppServerClientState().startMetadata.get(client)?.desktopGeneration;
2481
2893
  }
@@ -2522,7 +2934,6 @@ function assertCodexAppServerClientStartSelectionCurrent(params) {
2522
2934
  });
2523
2935
  if ((metadata.startOptions.managedCommandOrder ?? "package-first") !== (current.managedCommandOrder ?? "package-first")) throw new CodexAppServerStartSelectionChangedError();
2524
2936
  }
2525
- /** Resolves the per-CODEX_HOME key used to serialize native config loading. */
2526
2937
  function resolveCodexNativeConfigFenceKey(params) {
2527
2938
  const metadata = params.client ? getSharedCodexAppServerClientState().startMetadata.get(params.client) : void 0;
2528
2939
  const startOptions = metadata?.startOptions ?? params.startOptions;
@@ -2541,9 +2952,9 @@ async function resolveCodexAppServerClientStartContext(options) {
2541
2952
  if (preparedAuth?.kind === "profile" && !preparedAuth.store.profiles[preparedAuth.profileId]) throw new CodexAppServerAuthProfileUnavailableError(formatCodexAuthProfileUnavailableMessage(preparedAuth.profileId));
2542
2953
  if (preparedAuth?.kind === "api-key" && !preparedApiKey) throw new Error("Prepared Codex API-key auth is missing its resolved key.");
2543
2954
  if (preparedAuth && requestedStartOptions.homeScope === "user") throw new Error("Prepared Codex auth requires an isolated app-server home.");
2544
- const preparedAuthRequirement = preparedAuth && (preparedAuth.kind === "api-key" ? "api-key" : "subscription");
2955
+ const preparedAuthRequirement = preparedAuth && (preparedAuth.kind === "api-key" || isCodexResponsesOAuth(preparedAuth) ? "api-key" : "subscription");
2545
2956
  if (options?.authRequirement && preparedAuthRequirement && options.authRequirement !== preparedAuthRequirement) throw new Error("Prepared Codex auth does not satisfy the requested auth requirement.");
2546
- const authRequirement = options?.authRequirement ?? preparedAuthRequirement;
2957
+ let authRequirement = options?.authRequirement ?? preparedAuthRequirement;
2547
2958
  const usesNativeAuth = !preparedAuth && (options?.authProfileId === null || requestedStartOptions.homeScope === "user");
2548
2959
  const requestedAuthProfileId = preparedAuth?.kind === "profile" ? preparedAuth.profileId : options?.authProfileId ?? void 0;
2549
2960
  const authProfileStore = preparedAuth?.kind === "profile" ? preparedAuth.store : !usesNativeAuth && preparedAuth?.kind !== "api-key" ? resolveCodexAppServerAuthProfileStore({
@@ -2574,10 +2985,25 @@ async function resolveCodexAppServerClientStartContext(options) {
2574
2985
  store: authProfileStore,
2575
2986
  snapshot: preparedAuthProfileSnapshot
2576
2987
  } : void 0;
2988
+ if (isCodexResponsesOAuth(resolvedPreparedAuth)) {
2989
+ if (authRequirement && authRequirement !== "api-key") throw new Error("ChatGPT subscription sharing requires the public OpenAI API route.");
2990
+ authRequirement = "api-key";
2991
+ }
2577
2992
  const agentStartOptions = resolveCodexAppServerStartOptionsForAgent({
2578
2993
  startOptions: requestedStartOptions,
2579
2994
  agentDir
2580
2995
  });
2996
+ const startOptions = await bridgeCodexAppServerStartOptions({
2997
+ startOptions: await resolveManagedCodexAppServerStartOptions(agentStartOptions),
2998
+ agentId: options?.agentId,
2999
+ agentDir,
3000
+ authProfileId: usesNativeAuth || preparedAuth?.kind === "api-key" ? null : authProfileId,
3001
+ ...(preparedAuth || isCodexResponsesOAuth(resolvedPreparedAuth)) && resolvedPreparedAuth ? { preparedAuth: resolvedPreparedAuth } : {},
3002
+ authRequirement,
3003
+ config: options?.config,
3004
+ pluginConfig: options?.pluginConfig,
3005
+ ...authProfileStore ? { authProfileStore } : {}
3006
+ });
2581
3007
  return {
2582
3008
  agentDir,
2583
3009
  usesNativeAuth,
@@ -2586,17 +3012,7 @@ async function resolveCodexAppServerClientStartContext(options) {
2586
3012
  requestedStartOptions,
2587
3013
  preparedAuth: resolvedPreparedAuth,
2588
3014
  authRequirement,
2589
- startOptions: await bridgeCodexAppServerStartOptions({
2590
- startOptions: await resolveManagedCodexAppServerStartOptions(agentStartOptions),
2591
- agentId: options?.agentId,
2592
- agentDir,
2593
- authProfileId: usesNativeAuth || preparedAuth?.kind === "api-key" ? null : authProfileId,
2594
- ...preparedAuth && resolvedPreparedAuth ? { preparedAuth: resolvedPreparedAuth } : {},
2595
- authRequirement,
2596
- config: options?.config,
2597
- pluginConfig: options?.pluginConfig,
2598
- ...authProfileStore ? { authProfileStore } : {}
2599
- }),
3015
+ startOptions,
2600
3016
  ...options?.pluginConfig !== void 0 ? { pluginConfig: options.pluginConfig } : {},
2601
3017
  ...desktopGeneration ? { desktopGeneration } : {}
2602
3018
  };
@@ -2614,7 +3030,6 @@ function getSharedCodexAppServerClient(options) {
2614
3030
  function getLeasedSharedCodexAppServerClient(options) {
2615
3031
  return acquireSharedCodexAppServerClient(options, true);
2616
3032
  }
2617
- /** Releases one outstanding lease for a shared Codex app-server client. */
2618
3033
  function releaseLeasedSharedCodexAppServerClient(client) {
2619
3034
  const entry = getSharedCodexAppServerClientState().entriesByClient.get(client);
2620
3035
  if (!entry || entry.anonymousLeases === 0) return false;
@@ -2686,7 +3101,8 @@ async function acquireSharedCodexAppServerClient(options, leased = false) {
2686
3101
  const state = getSharedCodexAppServerClientState();
2687
3102
  const { context, lifetime, abandonSignal, startedAt, assertCurrent } = await prepareCodexAppServerClient(options);
2688
3103
  assertCurrent();
2689
- const { agentDir, usesNativeAuth, authProfileId, authProfileStore, preparedAuth, authRequirement, requestedStartOptions, startOptions, desktopGeneration, pluginConfig } = context;
3104
+ const { usesNativeAuth, ...startContext } = context;
3105
+ const { agentDir, authProfileId, authProfileStore, preparedAuth, authRequirement, startOptions, desktopGeneration } = startContext;
2690
3106
  const remainingTimeoutMs = resolveRemainingAcquireTimeout(timeoutMs, startedAt);
2691
3107
  const authIdentityCacheKey = preparedAuth?.kind === "api-key" ? resolveCodexAppServerPreparedApiKeyCacheKey(preparedAuth.apiKey) : preparedAuth?.snapshot.secretFreeCacheKey ?? (authRequirement === "api-key" && !authProfileId ? resolveCodexAppServerFallbackApiKeyCacheKey({ startOptions }) : void 0);
2692
3108
  const baseKey = `${codexAppServerStartOptionsKey(startOptions, {
@@ -2728,17 +3144,10 @@ async function acquireSharedCodexAppServerClient(options, leased = false) {
2728
3144
  if (options.abandonSignal.aborted) abandon();
2729
3145
  }
2730
3146
  const startup = entry.startup ?? (entry.startup = createSharedCodexAppServerClientStartup({
3147
+ ...startContext,
2731
3148
  lifetime,
2732
3149
  entry,
2733
- requestedStartOptions,
2734
- startOptions,
2735
- desktopGeneration,
2736
- ...pluginConfig !== void 0 ? { pluginConfig } : {},
2737
- agentDir,
2738
3150
  authProfileId: usesNativeAuth || preparedAuth?.kind === "api-key" ? null : authProfileId,
2739
- authProfileStore,
2740
- preparedAuth,
2741
- authRequirement,
2742
3151
  runtimeArtifactMode,
2743
3152
  ...options?.expectedRuntimeArtifact ? { expectedRuntimeArtifact: options.expectedRuntimeArtifact } : {},
2744
3153
  abandonSignal: entry.startupAbort.signal,
@@ -2752,7 +3161,7 @@ async function acquireSharedCodexAppServerClient(options, leased = false) {
2752
3161
  agentDir,
2753
3162
  authProfileId: usesNativeAuth ? void 0 : authProfileId,
2754
3163
  ...authProfileStore ? { authProfileStore } : {},
2755
- authMode: preparedAuth?.kind === "api-key" ? "prepared-api-key" : "profile",
3164
+ authMode: preparedAuth?.kind === "api-key" || isCodexResponsesOAuth(preparedAuth) ? "prepared-api-key" : "profile",
2756
3165
  config: options?.config
2757
3166
  });
2758
3167
  if (leased) {
@@ -2763,6 +3172,7 @@ async function acquireSharedCodexAppServerClient(options, leased = false) {
2763
3172
  } catch (error) {
2764
3173
  releasePendingAcquire();
2765
3174
  retirePendingSharedClientEntryIfUnclaimed(entry);
3175
+ await waitForUnclaimedSharedClientStartup(entry);
2766
3176
  throw error;
2767
3177
  } finally {
2768
3178
  cleanupAbandonSignal?.();
@@ -2770,30 +3180,17 @@ async function acquireSharedCodexAppServerClient(options, leased = false) {
2770
3180
  releasePendingAcquire();
2771
3181
  }
2772
3182
  }
2773
- async function withCodexAppServerAcquireDeadline(timeoutMs, promise, signal, timeoutMessage = CODEX_APP_SERVER_INITIALIZE_TIMEOUT_MESSAGE, timeoutErrorFactory) {
2774
- if (signal?.aborted) throw new CodexAppServerStartupError("aborted", "codex app-server initialize aborted");
2775
- const timed = withTimeout(promise, timeoutMs, timeoutMessage, () => timeoutErrorFactory?.() ?? new CodexAppServerStartupError("timed_out", timeoutMessage));
2776
- if (!signal) return await timed;
2777
- return await new Promise((resolve, reject) => {
2778
- const onAbort = () => reject(new CodexAppServerStartupError("aborted", "codex app-server initialize aborted"));
2779
- signal.addEventListener("abort", onAbort, { once: true });
2780
- timed.then(resolve, reject).finally(() => signal.removeEventListener("abort", onAbort));
2781
- });
2782
- }
2783
3183
  function buildCodexAppServerInitializeTimeoutError(client) {
2784
3184
  const stderr = client?.getStderrDiagnostic();
2785
3185
  return new CodexAppServerStartupError("timed_out", stderr ? `${CODEX_APP_SERVER_INITIALIZE_TIMEOUT_MESSAGE}; stderr=${JSON.stringify(stderr)}` : CODEX_APP_SERVER_INITIALIZE_TIMEOUT_MESSAGE);
2786
3186
  }
2787
- function resolveRemainingAcquireTimeout(timeoutMs, startedAt) {
2788
- if (!(timeoutMs > 0)) return timeoutMs;
2789
- const remaining = timeoutMs - (performance.now() - startedAt);
2790
- if (remaining <= 0) throw new CodexAppServerStartupError("timed_out", "codex app-server initialize timed out");
2791
- return remaining;
2792
- }
2793
3187
  function createSharedCodexAppServerClientStartup(params) {
2794
3188
  const initialized = createDeferred();
2795
3189
  const ready = ownCodexStartup(params.lifetime, startInitializedCodexAppServerClient({
2796
3190
  ...params,
3191
+ onStartingClient: (starting) => {
3192
+ params.entry.startupTransport = starting;
3193
+ },
2797
3194
  onStartedClient: (startedClient) => {
2798
3195
  const state = getSharedCodexAppServerClientState();
2799
3196
  if (params.entry.client) state.entriesByClient.delete(params.entry.client);
@@ -2833,18 +3230,11 @@ async function createIsolatedCodexAppServerClient(options) {
2833
3230
  const { context, lifetime, abandonSignal, startedAt, assertCurrent } = await prepareCodexAppServerClient(options);
2834
3231
  assertCurrent();
2835
3232
  const timeoutMs = options?.timeoutMs ?? 0;
2836
- const { agentDir, usesNativeAuth, authProfileId, authProfileStore, preparedAuth, authRequirement, requestedStartOptions, startOptions, desktopGeneration, pluginConfig } = context;
3233
+ const { usesNativeAuth, ...startContext } = context;
2837
3234
  return await ownCodexStartup(lifetime, startInitializedCodexAppServerClient({
3235
+ ...startContext,
2838
3236
  lifetime,
2839
- requestedStartOptions,
2840
- startOptions,
2841
- ...desktopGeneration ? { desktopGeneration } : {},
2842
- ...pluginConfig !== void 0 ? { pluginConfig } : {},
2843
- agentDir,
2844
- authProfileId: usesNativeAuth || preparedAuth?.kind === "api-key" ? null : authProfileId,
2845
- authProfileStore,
2846
- preparedAuth,
2847
- authRequirement,
3237
+ authProfileId: usesNativeAuth || context.preparedAuth?.kind === "api-key" ? null : context.authProfileId,
2848
3238
  runtimeArtifactMode: options?.runtimeArtifactMode ?? (options?.expectedRuntimeArtifact ? "capture" : void 0),
2849
3239
  ...options?.expectedRuntimeArtifact ? { expectedRuntimeArtifact: options.expectedRuntimeArtifact } : {},
2850
3240
  config: options?.config,
@@ -2865,7 +3255,17 @@ function trackIsolatedCodexAppServerClient(client) {
2865
3255
  notifyDesktopGenerationDrainChecks(state);
2866
3256
  });
2867
3257
  }
2868
- async function startInitializedCodexAppServerClient(params) {
3258
+ function startInitializedCodexAppServerClient(params) {
3259
+ return withCodexWebSocketOpenRetry({
3260
+ timeoutMs: params.timeoutMs ?? 0,
3261
+ signal: params.abandonSignal ? AbortSignal.any([params.lifetime.controller.signal, params.abandonSignal]) : params.lifetime.controller.signal,
3262
+ start: (timeoutMs) => startInitializedCodexAppServerClientOnce({
3263
+ ...params,
3264
+ timeoutMs
3265
+ })
3266
+ });
3267
+ }
3268
+ async function startInitializedCodexAppServerClientOnce(params) {
2869
3269
  const acquireStartedAt = performance.now();
2870
3270
  const timeoutMs = params.timeoutMs ?? 0;
2871
3271
  const abandonSignal = params.abandonSignal ? AbortSignal.any([params.lifetime.controller.signal, params.abandonSignal]) : params.lifetime.controller.signal;
@@ -2876,7 +3276,8 @@ async function startInitializedCodexAppServerClient(params) {
2876
3276
  const startOptionsCandidates = resolveManagedFallbackStartOptions(params.startOptions);
2877
3277
  for (const [index, startOptions] of startOptionsCandidates.entries()) {
2878
3278
  params.assertCurrent?.();
2879
- const desktopGeneration = params.desktopGeneration ?? (isManagedCodexDesktopCommand(startOptions.command) ? await waitForStartup(waitForCodexDesktopGeneration) : void 0);
3279
+ const desktopCommand = isManagedCodexDesktopCommand(startOptions.command);
3280
+ const desktopGeneration = params.desktopGeneration ?? (desktopCommand ? await waitForStartup(waitForCodexDesktopGeneration) : void 0);
2880
3281
  const assertStartupCurrent = () => {
2881
3282
  params.assertCurrent?.();
2882
3283
  if (abandonSignal.aborted) throw new CodexAppServerStartupError("aborted", "codex app-server initialize aborted");
@@ -2911,7 +3312,7 @@ async function startInitializedCodexAppServerClient(params) {
2911
3312
  } finally {
2912
3313
  artifactDrain?.cancel();
2913
3314
  }
2914
- const runtimeArtifactModule = params.runtimeArtifactMode ? await import("./runtime-artifact-CLZ8udh-.mjs") : void 0;
3315
+ const runtimeArtifactModule = params.runtimeArtifactMode ? await import("./runtime-artifact-DDQ-HGXf.mjs") : void 0;
2915
3316
  const runtimeArtifactBeforeStart = runtimeArtifactModule ? await runtimeArtifactModule.captureCodexAppServerRuntimeArtifactBeforeStart({
2916
3317
  startOptions,
2917
3318
  spawnIdentity: resolveCodexAppServerSpawnIdentity(startOptions),
@@ -2925,14 +3326,21 @@ async function startInitializedCodexAppServerClient(params) {
2925
3326
  let starting;
2926
3327
  let client;
2927
3328
  try {
2928
- client = await waitForStartup(() => starting = CodexAppServerClient.start(startOptions, () => {
2929
- assertStartupCurrent();
2930
- resolveRemainingAcquireTimeout(timeoutMs, acquireStartedAt);
2931
- }));
3329
+ client = await waitForStartup(() => {
3330
+ starting = CodexAppServerClient.start(startOptions, () => {
3331
+ assertStartupCurrent();
3332
+ resolveRemainingAcquireTimeout(timeoutMs, acquireStartedAt);
3333
+ });
3334
+ params.onStartingClient?.(starting);
3335
+ return starting;
3336
+ });
2932
3337
  } catch (error) {
2933
- if (starting) ownCodexStartup(params.lifetime, starting.then((lateClient) => lateClient.closeAndWait(), () => {}));
3338
+ if (starting) await ownCodexStartup(params.lifetime, starting.then((lateClient) => lateClient.closeAndWait(), () => {}));
2934
3339
  throw error;
2935
3340
  }
3341
+ client.addCloseHandler((closedClient) => {
3342
+ ownCodexStartup(params.lifetime, closedClient.waitForCloseWork());
3343
+ });
2936
3344
  let ready = false;
2937
3345
  try {
2938
3346
  const nativeCommandAtStart = startOptions.commandSource === "resolved-managed" ? resolveManagedCodexNativeCommand(startOptions.command) : void 0;
@@ -2971,7 +3379,7 @@ async function startInitializedCodexAppServerClient(params) {
2971
3379
  ensureCodexAppServerClientRuntime(client, {
2972
3380
  agentDir: params.agentDir,
2973
3381
  authProfileId: params.authProfileId ?? void 0,
2974
- authMode: params.preparedAuth?.kind === "api-key" ? "prepared-api-key" : "profile",
3382
+ authMode: params.preparedAuth?.kind === "api-key" || isCodexResponsesOAuth(params.preparedAuth) ? "prepared-api-key" : "profile",
2975
3383
  ...params.authProfileStore ? { authProfileStore: params.authProfileStore } : {},
2976
3384
  config: params.config,
2977
3385
  onAuthRefreshFailure: () => retireSharedCodexAppServerClientIfCurrent(client)
@@ -2988,7 +3396,18 @@ async function startInitializedCodexAppServerClient(params) {
2988
3396
  assertCurrent: assertStartupCurrent,
2989
3397
  ...params.authProfileStore ? { authProfileStore: params.authProfileStore } : {}
2990
3398
  }));
2991
- if (startOptions.transport === "stdio" && nativeCommandAtStart && !desktopGeneration && !isManagedCodexDesktopCommand(startOptions.command) && !isCodexAppServerProxyLaunch(startOptions.args)) ownCodexInferenceClient(client);
3399
+ const ownsInference = startOptions.transport === "stdio" && nativeCommandAtStart && !isCodexAppServerProxyLaunch(startOptions.args);
3400
+ if (isCodexResponsesOAuth(params.preparedAuth) && (!ownsInference || desktopGeneration || desktopCommand)) throw new Error("ChatGPT subscription sharing requires a managed local Codex process.");
3401
+ if (ownsInference) {
3402
+ const prepared = params.preparedAuth;
3403
+ ownCodexInferenceClient(client, startOptions, isCodexResponsesOAuth(prepared) && prepared?.kind === "profile" ? createCodexResponsesOAuth({
3404
+ profileId: prepared.profileId,
3405
+ store: prepared.store,
3406
+ fingerprint: prepared.snapshot.secretFreeCacheKey,
3407
+ agentDir: params.agentDir,
3408
+ config: params.config
3409
+ }) : void 0);
3410
+ }
2992
3411
  recordCodexAppServerAuthHandoff(client, authHandoff);
2993
3412
  if (runtimeArtifactModule && runtimeArtifact) runtimeArtifactModule.bindCodexAppServerRuntimeArtifact(client, runtimeArtifact);
2994
3413
  assertStartupCurrent();
@@ -3006,7 +3425,7 @@ async function startInitializedCodexAppServerClient(params) {
3006
3425
  ready = true;
3007
3426
  return client;
3008
3427
  } finally {
3009
- if (!ready) ownCodexStartup(params.lifetime, client.closeAndWait());
3428
+ if (!ready) await ownCodexStartup(params.lifetime, client.closeAndWait());
3010
3429
  }
3011
3430
  }
3012
3431
  throw new Error("Managed Codex app-server fallback candidates were exhausted.");
@@ -3032,7 +3451,6 @@ function resolveManagedFallbackStartOptions(startOptions) {
3032
3451
  function shouldTryManagedFallbackStartOption(error, startOptions, index, startOptionsCandidates) {
3033
3452
  return startOptions.commandSource === "resolved-managed" && index < startOptionsCandidates.length - 1 && isUnsupportedCodexAppServerVersionError(error);
3034
3453
  }
3035
- /** Clears and closes the shared entry only if it still owns the supplied client. */
3036
3454
  function clearSharedCodexAppServerClientIfCurrent(client) {
3037
3455
  if (!client) return false;
3038
3456
  const state = getSharedCodexAppServerClientState();
@@ -3055,24 +3473,10 @@ function captureSharedClientRegistration(client) {
3055
3473
  const generation = readCodexAppServerClientDesktopGeneration(client);
3056
3474
  return () => entry !== void 0 && state.clients.get(entry.key) === entry && entry.client === client && !entry.closeWhenIdle && !entry.closeError && !client.getCloseError() && (!generation || isCodexDesktopGenerationCurrent(generation));
3057
3475
  }
3058
- /** Retains the matching shared client and returns a release callback. */
3059
3476
  function retainSharedCodexAppServerClientIfCurrent(client) {
3060
3477
  const entry = getCurrentSharedClientEntry(client);
3061
3478
  return entry ? retainSharedClientEntry(entry) : void 0;
3062
3479
  }
3063
- /** Retains the live shared client whose initialized instance id matches a thread binding. */
3064
- function retainSharedCodexAppServerClientByInstanceId(clientId) {
3065
- const normalizedClientId = clientId?.trim();
3066
- if (!normalizedClientId) return;
3067
- for (const entry of getSharedCodexAppServerClientState().clients.values()) {
3068
- const client = entry.client;
3069
- if (client?.getInstanceId() !== normalizedClientId || entry.closeWhenIdle || entry.closeError) continue;
3070
- return {
3071
- client,
3072
- release: retainSharedClientEntry(entry)
3073
- };
3074
- }
3075
- }
3076
3480
  /** Captures physical ownership, independently of unrelated thread and reader leases. */
3077
3481
  function captureCodexAppServerClientLifetime(client, requiredOwnership) {
3078
3482
  const state = getSharedCodexAppServerClientState();
@@ -3097,10 +3501,7 @@ function createOlderDesktopGenerationDrainWait(params) {
3097
3501
  };
3098
3502
  const state = getSharedCodexAppServerClientState();
3099
3503
  let settled = false;
3100
- let resolveWait;
3101
- const promise = new Promise((resolve) => {
3102
- resolveWait = resolve;
3103
- });
3504
+ const { promise, resolve: resolveWait } = createDeferred();
3104
3505
  const cancel = () => {
3105
3506
  if (settled) return;
3106
3507
  settled = true;
@@ -3122,18 +3523,13 @@ function createOlderDesktopGenerationDrainWait(params) {
3122
3523
  };
3123
3524
  }
3124
3525
  function hasLiveOlderDesktopGenerationClient(params) {
3125
- for (const client of params.state.liveClients) if (isOlderDesktopGenerationClientForHome(client, params.generation, params.targetHome)) return true;
3126
- for (const client of params.state.isolatedClients) if (isOlderDesktopGenerationClientForHome(client, params.generation, params.targetHome)) return true;
3526
+ for (const clients of [params.state.liveClients, params.state.isolatedClients]) for (const client of clients) if (isOlderDesktopGenerationClientForHome(client, params.generation, params.targetHome)) return true;
3127
3527
  return false;
3128
3528
  }
3129
3529
  function isOlderDesktopGenerationClientForHome(client, generation, targetHome) {
3130
3530
  const metadata = getSharedCodexAppServerClientState().startMetadata.get(client);
3131
3531
  return Boolean(metadata?.desktopGeneration && metadata.desktopGeneration.epoch < generation.epoch && resolveCodexNativeConfigFenceKey({ client }) === targetHome);
3132
3532
  }
3133
- function notifyDesktopGenerationDrainChecks(state) {
3134
- for (const check of state.desktopGenerationDrainChecks) check();
3135
- }
3136
- /** Clears a matching shared client and waits for its process to exit. */
3137
3533
  async function clearSharedCodexAppServerClientIfCurrentAndWait(client, options) {
3138
3534
  if (!client) return false;
3139
3535
  const state = getSharedCodexAppServerClientState();
@@ -3143,7 +3539,6 @@ async function clearSharedCodexAppServerClientIfCurrentAndWait(client, options)
3143
3539
  await client.closeAndWait(options);
3144
3540
  return true;
3145
3541
  }
3146
- /** Clears all shared clients and waits for their processes to exit. */
3147
3542
  async function clearSharedCodexAppServerClientAndWait(options) {
3148
3543
  const state = getSharedCodexAppServerClientState();
3149
3544
  const lifetime = state.startup;
@@ -3175,7 +3570,6 @@ function getOrCreateSharedClientEntry(state, key) {
3175
3570
  }
3176
3571
  return entry;
3177
3572
  }
3178
- /** Clears a matching shared client only when no lease or acquire currently claims it. */
3179
3573
  function clearSharedCodexAppServerClientIfCurrentAndUnclaimed(client) {
3180
3574
  const entry = getCurrentSharedClientEntry(client);
3181
3575
  return {
@@ -3185,20 +3579,6 @@ function clearSharedCodexAppServerClientIfCurrentAndUnclaimed(client) {
3185
3579
  pendingAcquires: entry?.pendingAcquires ?? 0
3186
3580
  };
3187
3581
  }
3188
- function retainSharedClientEntry(entry, counter = "activeLeases") {
3189
- let released = false;
3190
- entry[counter] += 1;
3191
- return () => {
3192
- if (released) return;
3193
- released = true;
3194
- releaseSharedClientEntry(entry, counter);
3195
- };
3196
- }
3197
- function releaseSharedClientEntry(entry, counter) {
3198
- entry[counter] -= 1;
3199
- closeRetiredSharedClientEntryIfIdle(entry);
3200
- notifyDesktopGenerationDrainChecks(getSharedCodexAppServerClientState());
3201
- }
3202
3582
  function closeSharedClientEntryIfUnclaimed(entry) {
3203
3583
  if (entry.activeLeases > 0 || entry.pendingAcquires > 0) return false;
3204
3584
  const state = getSharedCodexAppServerClientState();
@@ -3207,14 +3587,5 @@ function closeSharedClientEntryIfUnclaimed(entry) {
3207
3587
  entry.client?.close();
3208
3588
  return Boolean(entry.client);
3209
3589
  }
3210
- function retirePendingSharedClientEntryIfUnclaimed(entry) {
3211
- if (entry.activeLeases > 0 || entry.pendingAcquires > 0) return;
3212
- entry.startupAbort?.abort(/* @__PURE__ */ new Error("Codex app-server startup was abandoned"));
3213
- entry.closeWhenIdle = true;
3214
- const state = getSharedCodexAppServerClientState();
3215
- if (state.clients.get(entry.key) === entry) state.clients.delete(entry.key);
3216
- if (!entry.client) return;
3217
- closeRetiredSharedClientEntry(entry);
3218
- }
3219
3590
  //#endregion
3220
- export { assertNotSymlink as $, getCodexInferenceThread as A, prepareCodexWorkspaceReferences as B, CodexThreadBindingConflictError as C, acquireCodexNativeConfigFence as D, nativeHookRelayUnregisterQueue as E, forgetCodexWorkspaceReferences as F, unsubscribeCodexAppServerLiveThread as G, readCodexClientSessionMeta as H, hasCodexAppServerLiveThread as I, rememberCodexRateLimitsRead as J, readCodexRateLimitsRevision as K, hasCodexAppServerSiblingThreadWork as L, claimCodexAppServerLiveThread as M, consumeCodexAppServerLiveThread as N, assertCodexInferenceRouteConfig as O, ensureCodexAppServerClientRuntime as P, resolveCodexManagedBundledMarketplacePath as Q, isCodexAppServerClientRuntimeLive as R, CodexAdoptedThreadActiveError as S, CodexThreadStartRequestError as T, releaseCodexAppServerLiveThread as U, protectCodexAppServerLiveThread as V, retainCodexAppServerLiveThread as W, resolveCodexAppServerAuthAccountCacheKey as X, reconcileCodexComputerUseStartArtifacts as Y, resolveCodexAppServerPreparedAuthHandoff as Z, retainSharedCodexAppServerClientByInstanceId as _, clearSharedCodexAppServerClientIfCurrentAndUnclaimed as a, resolveCodexStartupTimeoutMs as at, waitForCodexAppServerClientDesktopGenerationDrain as b, getLeasedSharedCodexAppServerClient as c, readCodexAppServerClientDesktopGeneration as d, CodexAppServerStartupError as et, readCodexAppServerClientDesktopGenerationFingerprint as f, resolveCodexNativeConfigFenceKey as g, releaseLeasedSharedCodexAppServerClient as h, clearSharedCodexAppServerClientIfCurrent as i, resolveCodexGatewayTimeoutWithGraceMs as it, prepareCodexInferenceThreadConfig as j, bindCodexInferenceThread as k, getSharedCodexAppServerClient as l, releaseCodexAppServerClientLease as m, captureCodexAppServerClientLifetime as n, TURN_TERMINAL_SETTLEMENT_TIMEOUT_MS as nt, clearSharedCodexAppServerClientIfCurrentAndWait as o, withCodexStartupTimeout as ot, readCodexAppServerClientProcessIdentity as p, readRecentCodexRateLimits as q, captureSharedCodexAppServerCatalogLifetime as r, isCodexAppServerStartupError as rt, createIsolatedCodexAppServerClient as s, assertCodexAppServerClientStartSelectionCurrent as t, TURN_FINALIZE_DRAIN_ABORT_GRACE_MS as tt, isCodexAppServerStartSelectionChangedError as u, retainSharedCodexAppServerClientIfCurrent as v, CodexThreadClientReplacementError as w, withLeasedCodexAppServerClientStartSelectionRetry as x, shared_client_exports as y, isCodexAppServerLiveThreadClaimed as z };
3591
+ export { reconcileCodexComputerUseStartArtifacts as $, bindCodexInferenceThread as A, isCodexAppServerClientRuntimeLive as B, CodexThreadBindingConflictError as C, nativeHookRelayUnregisterQueue as D, isCodexContextRestartSelectionChangedError as E, consumeCodexAppServerLiveThread as F, releaseCodexAppServerLiveThread as G, prepareCodexWorkspaceReferences as H, ensureCodexAppServerClientRuntime as I, unsubscribeCodexAppServerLiveThread as J, retainCodexAppServerLiveThread as K, forgetCodexWorkspaceReferences as L, getCodexInferenceThreadQualification as M, prepareCodexInferenceThreadConfig as N, acquireCodexNativeConfigFence as O, claimCodexAppServerLiveThread as P, createCodexEphemeralThreadPolicy as Q, hasCodexAppServerLiveThread as R, CodexAdoptedThreadActiveError as S, CodexThreadStartRequestError as T, protectCodexAppServerLiveThread as U, isCodexAppServerLiveThreadClaimed as V, readCodexClientSessionMeta as W, readRecentCodexRateLimits as X, readCodexRateLimitsRevision as Y, rememberCodexRateLimitsRead as Z, retainSharedCodexAppServerClientIfCurrent as _, clearSharedCodexAppServerClientIfCurrentAndUnclaimed as a, isLegacyCodexComputerUsePluginDisabled as at, withLeasedCodexAppServerClientStartSelectionRetry as b, getLeasedSharedCodexAppServerClient as c, assertNotSymlink as ct, readCodexAppServerClientDesktopGeneration as d, TURN_TERMINAL_SETTLEMENT_TIMEOUT_MS as dt, resolveCodexAppServerAuthAccountCacheKey as et, readCodexAppServerClientDesktopGenerationFingerprint as f, isCodexAppServerStartupError as ft, resolveCodexNativeConfigFenceKey as g, releaseLeasedSharedCodexAppServerClient as h, withCodexStartupTimeout as ht, clearSharedCodexAppServerClientIfCurrent as i, hasLegacyCodexComputerUseMcpPolicy as it, getCodexInferenceThread as j, assertCodexInferenceRouteConfig as k, getSharedCodexAppServerClient as l, CodexAppServerStartupError as lt, releaseCodexAppServerClientLease as m, resolveCodexStartupTimeoutMs as mt, captureCodexAppServerClientLifetime as n, resolveBundledComputerUseMarketplacePath as nt, clearSharedCodexAppServerClientIfCurrentAndWait as o, resolveManagedCodexComputerUseConfig as ot, readCodexAppServerClientProcessIdentity as p, resolveCodexGatewayTimeoutWithGraceMs as pt, revertCodexAppServerLiveThreadSkillsCatalog as q, captureSharedCodexAppServerCatalogLifetime as r, resolveClientManagedBundledMarketplacePath as rt, createIsolatedCodexAppServerClient as s, ensureCodexComputerUseSharedPluginCache as st, assertCodexAppServerClientStartSelectionCurrent as t, resolveCodexAppServerPreparedAuthHandoff as tt, isCodexAppServerStartSelectionChangedError as u, TURN_FINALIZE_DRAIN_ABORT_GRACE_MS as ut, shared_client_exports as v, CodexThreadClientReplacementError as w, CODEX_APP_SERVER_CONTEXT_RESTART_SELECTION_CHANGED as x, waitForCodexAppServerClientDesktopGenerationDrain as y, hasCodexAppServerSiblingThreadWork as z };