@openclaw/codex 2026.9.6 → 2026.9.8
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.
- package/README.md +2 -0
- package/assets/icon.png +0 -0
- package/dist/.setup/{account-usage-runtime-Eem_WGqY.mjs → account-usage-runtime-G348lY1q.mjs} +5 -5
- package/dist/.setup/{apply-DDOi8uNx.mjs → apply-Cqb-YoCS.mjs} +22 -36
- package/dist/.setup/{attempt-client-cleanup-CEv1cKwF.mjs → attempt-client-cleanup-B-S7ngS_.mjs} +128 -37
- package/dist/.setup/attempt-workspace-context-BJ5Z_olH.mjs +164 -0
- package/dist/.setup/{auth-binding-DhLWa_7K.mjs → auth-binding-BLWz7stm.mjs} +14 -1
- package/dist/.setup/{auth-cache-key-B2mpaI9D.mjs → auth-cache-key-Dnps4W4_.mjs} +36 -34
- package/dist/.setup/{auth-profile-WqZtZfXN.mjs → auth-profile-B0okYl2D.mjs} +1 -2
- package/dist/.setup/auth-start-options-BPIPeEX8.mjs +44 -0
- package/dist/.setup/{binding-connection-ThoatDcb.mjs → binding-connection-DTtN1KrX.mjs} +2 -2
- package/dist/.setup/{binding-connection.runtime-yoHrABt-.mjs → binding-connection.runtime-6TpgD1M6.mjs} +4 -4
- package/dist/.setup/{bounded-turn-B2HScEgT.mjs → bounded-turn-BNunZPtz.mjs} +15 -18
- package/dist/.setup/bounded-turn-isolation-B8K_ylqk.mjs +14 -0
- package/dist/.setup/{build-state-C7EnDVgr.mjs → build-state-DIQ5O_-S.mjs} +1 -1
- package/dist/.setup/{capabilities-CDXOOFdZ.mjs → capabilities-B3WEZl4e.mjs} +2 -10
- package/dist/.setup/{client-catalog-response-BMgt_4q4.mjs → client-catalog-response-DRvx_wCC.mjs} +1 -1
- package/dist/.setup/{client-Cs08OXVQ.mjs → client-qyUBJlGZ.mjs} +138 -399
- package/dist/.setup/{command-dispatch-B4JuOsOk.mjs → command-dispatch-Btrs1D6f.mjs} +5 -8
- package/dist/.setup/{command-formatters-Bmqvr9tO.mjs → command-formatters-R3ckE3Co.mjs} +29 -61
- package/dist/.setup/{command-handlers-DW7Lx9oH.mjs → command-handlers-DvlCHJch.mjs} +222 -343
- package/dist/.setup/{command-rpc-DixIj3HW.mjs → command-rpc-skzRq4wD.mjs} +15 -18
- package/dist/.setup/compact-8ttks5U5.mjs +776 -0
- package/dist/.setup/{config-BoTP_mrL.mjs → config-DKhXquav.mjs} +26 -28
- package/dist/.setup/{config-options-BvaRs51b.mjs → config-options-CzyWLTJt.mjs} +24 -37
- package/dist/.setup/{config-parsing-CcB9iPoq.mjs → config-parsing-b088LyhT.mjs} +57 -60
- package/dist/.setup/{config-runtime-C8Rw1m1m.mjs → config-runtime-C0NbLms1.mjs} +2 -2
- package/dist/.setup/{config-security-BEReZ6go.mjs → config-security-CE-FcGw9.mjs} +32 -111
- package/dist/.setup/{config-utils-DujwEnhg.mjs → config-utils-D0CXecki.mjs} +3 -13
- package/dist/.setup/context-engine-projection-PezSESth.mjs +387 -0
- package/dist/.setup/{conversation-binding-DP-gMrBP.mjs → conversation-binding-74LaGGH-.mjs} +67 -90
- package/dist/.setup/{conversation-binding-data-CrcyZk6O.mjs → conversation-binding-data-C746z5Pn.mjs} +8 -12
- package/dist/.setup/{conversation-control-uK9Jomlc.mjs → conversation-control-OrN6zuaY.mjs} +8 -8
- package/dist/.setup/{cyber-failover-DYwbmf1o.mjs → cyber-failover-XV0nNRZu.mjs} +1 -1
- package/dist/.setup/{cyber-failover-notice-e9G3J9-e.mjs → cyber-failover-notice-RNpGpTyP.mjs} +1 -1
- package/dist/.setup/{dynamic-tools-BDXl-8Cw.mjs → dynamic-tools-Db2sY5cZ.mjs} +2305 -2606
- package/dist/.setup/{effective-mcp-catalog-CvnvnGIe.mjs → effective-mcp-catalog-Bi6-SQ7i.mjs} +8 -17
- package/dist/.setup/{ephemeral-turn-poidXgek.mjs → ephemeral-turn-DiCS1ijR.mjs} +3 -3
- package/dist/.setup/event-projector-assistant-message-MV_1dj-3.mjs +69 -0
- package/dist/.setup/{event-projector-usage-CnBS8Wa3.mjs → event-projector-usage-03R0I2dM.mjs} +3 -25
- package/dist/.setup/event-projector-values-DJSz8BTk.mjs +106 -0
- package/dist/.setup/incognito-session-DWYapfwf.mjs +2 -0
- package/dist/.setup/{inference-context-D96l9-ew.mjs → inference-context-D-9gWlTR.mjs} +16 -18
- package/dist/.setup/inference-dispatch-CMZtjQyz.mjs +359 -0
- package/dist/.setup/inference-metadata-CgIf7sOx.mjs +81 -0
- package/dist/.setup/{inference-proxy-b-aJMSxm.mjs → inference-proxy-DhcXOgUE.mjs} +174 -214
- package/dist/.setup/{isolated-completion-BIZFhTNG.mjs → isolated-completion-D80IXfQF.mjs} +9 -12
- package/dist/.setup/{managed-binary-BnshlFag.mjs → managed-binary-kiWRhNRE.mjs} +8 -12
- package/dist/.setup/{model-catalog-CfXJf9Ay.mjs → model-catalog-DiC0Tkha.mjs} +11 -10
- package/dist/.setup/model-runtime-BdqzOMkU.mjs +11 -0
- package/dist/.setup/{models-KnqBv0hE.mjs → models-DfLmPV0k.mjs} +9 -18
- package/dist/.setup/{native-auth-rWbGbMn3.mjs → native-auth-CuG53tu4.mjs} +4 -4
- package/dist/.setup/{native-execution-policy-umd0tgh4.mjs → native-execution-policy-BxZJy5mP.mjs} +5 -30
- package/dist/.setup/{native-subagent-monitor-D3filLY2.mjs → native-subagent-monitor-BwkQXf9e.mjs} +4395 -3609
- package/dist/.setup/native-subagent-pending-assignments-DwkCzLvD.mjs +203 -0
- package/dist/.setup/native-task-assignments-DMQ0g3hu.mjs +194 -0
- package/dist/.setup/{node-cli-sessions-r3avj02l.mjs → node-cli-sessions-HC4W6FLI.mjs} +19 -49
- package/dist/.setup/{node-exec-server.runtime-BDwWXVpK.mjs → node-exec-server.runtime-BgBfWQqo.mjs} +3 -6
- package/dist/.setup/{plan-CN3VwfNU.mjs → plan-DPdMk1Oy.mjs} +49 -92
- package/dist/.setup/{plugin-activation-DT3MNtqj.mjs → plugin-activation-cNHRfaxU.mjs} +8 -36
- package/dist/.setup/{plugin-app-cache-key-B2CsSdnV.mjs → plugin-app-cache-key-BL9B5H0L.mjs} +6 -23
- package/dist/.setup/{plugin-inventory-BoRei8Z4.mjs → plugin-inventory-Cky2XJUw.mjs} +21 -21
- package/dist/.setup/{plugin-marketplace-discovery-CDOi8IFs.mjs → plugin-marketplace-discovery-D_dV9FXa.mjs} +18 -24
- package/dist/.setup/{plugin-metadata-cache-Ctmo83k_.mjs → plugin-metadata-cache-BRwtRct9.mjs} +116 -176
- package/dist/.setup/{provider-BOsxQHOM.mjs → provider-D6F_7p1I.mjs} +11 -14
- package/dist/.setup/{provider-capabilities-BfE88FZ5.mjs → provider-capabilities-DG5qbsUZ.mjs} +13 -18
- package/dist/.setup/{rate-limits-CMU3DUD0.mjs → rate-limits-B7-X2TgG.mjs} +9 -31
- package/dist/.setup/{request-D2L0zMrq.mjs → request-BZOfsSXW.mjs} +7 -6
- package/dist/.setup/responses-oauth-twnuTaAa.mjs +93 -0
- package/dist/.setup/rpc-error-BlD2vuzn.mjs +31 -0
- package/dist/.setup/{run-attempt-BHu11r7h.mjs → run-attempt-dYJhjZrp.mjs} +1035 -1023
- package/dist/.setup/{run-attempt-lifecycle-B7JbY4-F.mjs → run-attempt-lifecycle-C-6O3Exn.mjs} +10 -24
- package/dist/.setup/{runtime-artifact-CLZ8udh-.mjs → runtime-artifact-DDQ-HGXf.mjs} +16 -4
- package/dist/.setup/runtime-artifact-connection-D68qQn1m.mjs +78 -0
- package/dist/.setup/sandbox-guard-DjCz2eOw.mjs +126 -0
- package/dist/.setup/scope-DOC1Xjc8.mjs +6 -0
- package/dist/.setup/session-binding-DGCYAfvD.mjs +443 -0
- package/dist/.setup/{session-binding-record-BGoz8wOK.mjs → session-binding-record-Oe9L-CNY.mjs} +52 -130
- package/dist/.setup/{session-binding-sidecars-BlB5EvIS.mjs → session-binding-sidecars-jo6H8dFr.mjs} +196 -17
- package/dist/.setup/{session-catalog-Pno1xGcl.mjs → session-catalog-BFafIiF6.mjs} +185 -350
- package/dist/.setup/{session-catalog-adoption-BI6UTDZT.mjs → session-catalog-adoption-BU_pHWG7.mjs} +7 -6
- package/dist/.setup/{session-catalog-archive-lHBqzhaO.mjs → session-catalog-archive-spHfihri.mjs} +6 -6
- package/dist/.setup/session-catalog-events-BMCFMZw-.mjs +139 -0
- package/dist/.setup/session-catalog-home-id-vlih0B_g.mjs +22 -0
- package/dist/.setup/{session-catalog-index-B9_VQIUz.mjs → session-catalog-index-DwJjnF5k.mjs} +126 -122
- package/dist/.setup/{session-catalog-index-order-hcdz07yN.mjs → session-catalog-index-order-BcQpHks3.mjs} +1 -1
- package/dist/.setup/{session-catalog-index-state-Dgh8ORJm.mjs → session-catalog-index-state-TeO7EyO-.mjs} +3 -2
- package/dist/.setup/session-catalog-limits-DDxOsQeC.mjs +14 -0
- package/dist/.setup/session-catalog-list-request-CvtxrYSe.mjs +170 -0
- package/dist/.setup/session-catalog-native-projection-CuaFZuQE.mjs +178 -0
- package/dist/.setup/{session-catalog-node-adoption-ITddWx_X.mjs → session-catalog-node-adoption-DgXvSGu0.mjs} +10 -27
- package/dist/.setup/{session-catalog-node-continue-6g6qi4A9.mjs → session-catalog-node-continue-DjKXHBbi.mjs} +8 -10
- package/dist/.setup/session-catalog-node-lookup-CtAXI5W5.mjs +56 -0
- package/dist/.setup/{session-catalog-native-projection-DowriLid.mjs → session-catalog-parsing-CPGaPYr-.mjs} +11 -194
- package/dist/.setup/{session-catalog-projection-zK_PUsiE.mjs → session-catalog-projection-CGfzfP93.mjs} +6 -4
- package/dist/.setup/session-catalog-provenance-DoAvktcj.mjs +95 -0
- package/dist/.setup/{session-cli-irrD-uo7.mjs → session-cli-DlmBHYIe.mjs} +9 -22
- package/dist/.setup/{session-history-BrqhSCf9.mjs → session-history-D83lJWHG.mjs} +4 -6
- package/dist/.setup/{session-history-import-D-3wAgOP.mjs → session-history-import-WhX-X33a.mjs} +7 -10
- package/dist/.setup/session-history-read-Ov3StuL4.mjs +133 -0
- package/dist/.setup/{session-history.worker-CaCh0xF_.mjs → session-history.worker-MnPKncqP.mjs} +9 -5
- package/dist/.setup/session-initialization-6aveB9qb.mjs +22 -0
- package/dist/.setup/{session-permission-policy-BI1QK_98.mjs → session-permission-policy-Ci_fVX6y.mjs} +4 -8
- package/dist/.setup/{session-retirement-BH-S6qkJ.mjs → session-retirement-LlYWBKTJ.mjs} +17 -17
- package/dist/.setup/{settled-turn-context-fmwouT5I.mjs → settled-turn-context-D4yj4rxf.mjs} +1 -1
- package/dist/.setup/{settled-turn-finalizer-DiAi6Kx6.mjs → settled-turn-finalizer-DW9W3gza.mjs} +14 -10
- package/dist/.setup/{shared-client-DA4VR4Eb.mjs → shared-client-CJCTeFpQ.mjs} +783 -412
- package/dist/.setup/shared-client-lifecycle-7xgtlo15.mjs +153 -0
- package/dist/.setup/{side-question-BJ1wSDcB.mjs → side-question-BLeGj7TQ.mjs} +79 -143
- package/dist/.setup/{source-CUzJq5WN.mjs → source-CJis_1EF.mjs} +80 -137
- package/dist/.setup/{thread-lifecycle-B3mfz1TG.mjs → thread-lifecycle-_bAbjedG.mjs} +294 -737
- package/dist/.setup/{thread-ownership-DcTtAcXj.mjs → thread-ownership-B6pPt21M.mjs} +45 -10
- package/dist/.setup/{incognito-session-uhrBF6wJ.mjs → thread-ownership-queue-Dp24d7-F.mjs} +1 -2
- package/dist/.setup/{thread-policy-DGuQsuFC.mjs → thread-policy-gNPzzpVp.mjs} +46 -7
- package/dist/.setup/{thread-requests-BLvGkP2R.mjs → thread-requests-OWGOiDaV.mjs} +199 -302
- package/dist/.setup/{thread-resume-DIBXwOpE.mjs → thread-resume-GOry0AYh.mjs} +6 -6
- package/dist/.setup/{timeout-C910MdAB.mjs → timeout-CXOfNoaX.mjs} +1 -35
- package/dist/.setup/{transcript-history-projection-ZZpkFkJ_.mjs → transcript-history-projection-DRSifI-1.mjs} +17 -89
- package/dist/.setup/{transcript-mirror-attestation-CzM-94NC.mjs → transcript-mirror-attestation-YSegaktH.mjs} +3 -4
- package/dist/.setup/{transcript-mirror-BtHDBp1G.mjs → transcript-mirror-kxmCYsuF.mjs} +7 -9
- package/dist/.setup/{transport-stdio-h2VHOskC.mjs → transport-stdio-Bdegpn2V.mjs} +5 -22
- package/dist/.setup/transport-websocket-BTBE-LD9.mjs +211 -0
- package/dist/.setup/{upstream-prompt-provenance-LphB8slG.mjs → upstream-prompt-provenance-fXkKbPVC.mjs} +3 -9
- package/dist/.setup/{upstream-session-fork-BUr4OUbC.mjs → upstream-session-fork-gkdRj2yH.mjs} +23 -23
- package/dist/.setup/{usage-BML0r-ua.mjs → usage-CApUvLOV.mjs} +4 -4
- package/dist/.setup/{usage-limit-error-DUMbefVY.mjs → usage-limit-error-wSMQkbpV.mjs} +4 -19
- package/dist/.setup/{web-search-provider.runtime-CDKlN-Rv.mjs → web-search-provider.runtime-UKgeiBUG.mjs} +8 -19
- package/dist/api.js +9 -11
- package/dist/catalog-page.worker.js +1 -1
- package/dist/cli-metadata.js +1 -1
- package/dist/doctor-contract-api.js +50 -8
- package/dist/harness.js +344 -1
- package/dist/index.js +193 -245
- package/dist/media-understanding-provider.js +9 -22
- package/dist/migration-provider-api.js +1 -1
- package/dist/provider-discovery.js +1 -1
- package/dist/session-history-worker-runtime.js +3 -3
- package/dist/session-history.worker.js +1 -1
- package/openclaw.plugin.json +14 -2
- package/package.json +7 -6
- package/dist/.setup/attempt-workspace-context-DUVEn_CS.mjs +0 -331
- package/dist/.setup/compact-Du5UvtxA.mjs +0 -680
- package/dist/.setup/event-projector-assistant-message-BsruvNrH.mjs +0 -103
- package/dist/.setup/event-projector-items-C6L_5ZiT.mjs +0 -234
- package/dist/.setup/harness-a_MsE4-_.mjs +0 -355
- package/dist/.setup/history-rejection-B4nOXNXF.mjs +0 -13
- package/dist/.setup/image-payload-sanitizer-tupAr-2o.mjs +0 -79
- package/dist/.setup/local-runtime-attribution-B_2mnqhb.mjs +0 -19
- package/dist/.setup/native-subagent-history-0nYYgo0k.mjs +0 -148
- package/dist/.setup/native-subagent-task-ids-wb8CKZGN.mjs +0 -441
- package/dist/.setup/plugin-approval-roundtrip-C0MZzCuP.mjs +0 -122
- package/dist/.setup/rolldown-runtime-8H4AJuhK.mjs +0 -14
- package/dist/.setup/sandbox-guard-C2sRMOEY.mjs +0 -166
- package/dist/.setup/session-binding-Cm0apEbd.mjs +0 -692
- package/dist/.setup/session-catalog-events-Bj6j94E_.mjs +0 -347
- package/dist/.setup/session-history-read-B3ZfSUbF.mjs +0 -50
- package/dist/.setup/session-initialization-rcgbZiid.mjs +0 -75
- package/dist/.setup/thread-history-page-DoVpnHim.mjs +0 -83
|
@@ -1,40 +1,43 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as defineCodexBuildState, t as codexBuildSymbol } from "./build-state-
|
|
1
|
+
import { i as isJsonObject } from "./protocol-CANUwXJ3.mjs";
|
|
2
|
+
import { n as defineCodexBuildState, t as codexBuildSymbol } from "./build-state-DIQ5O_-S.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
|
|
7
|
-
import { a as resolveCodexAppServerStartOptionsForAgent, d as readCodexEffectiveConfig, o as resolveCodexComputerUseConfig, t as codexAppServerStartOptionsKey, u as CODEX_SESSION_OVERRIDABLE_LAYER_TYPES } from "./config-options-
|
|
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-
|
|
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-
|
|
10
|
-
import {
|
|
11
|
-
import { n as resolveCodexAppServerSpawnEnv } from "./transport-stdio-
|
|
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-Dnps4W4_.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-7xgtlo15.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-
|
|
14
|
-
import { n as
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
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-BMCFMZw-.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-qyUBJlGZ.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
|
|
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 {
|
|
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
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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
|
-
|
|
195
|
-
|
|
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 (
|
|
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
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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
|
|
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
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
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)
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
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 =
|
|
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
|
|
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 (
|
|
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
|
|
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
|
-
|
|
489
|
-
|
|
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
|
|
615
|
+
for (const candidate of candidates) if (await wrapperOwnedBySource(targetPath, candidate.bundledMarketplacePath)) return true;
|
|
496
616
|
return false;
|
|
497
617
|
}
|
|
498
|
-
function
|
|
499
|
-
|
|
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
|
|
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
|
|
618
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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 || !
|
|
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
|
|
1004
|
-
|
|
1005
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1154
|
-
|
|
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
|
|
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
|
|
1319
|
+
} : await resolveCodexAppServerAuthProfileLoginParamsInternal({
|
|
1198
1320
|
agentDir,
|
|
1199
1321
|
authProfileId: params.authProfileId ?? void 0,
|
|
1200
|
-
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 (!
|
|
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
|
-
|
|
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
|
|
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
|
|
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(
|
|
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
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
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 (
|
|
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
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
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
|
|
2202
|
-
if (
|
|
2203
|
-
if (
|
|
2204
|
-
owner.authRoute
|
|
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
|
|
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)
|
|
2210
|
-
|
|
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-BwkQXf9e.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.
|
|
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
|
-
|
|
2230
|
-
|
|
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
|
-
|
|
2244
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
2709
|
+
const state = resolveGlobalMap(CODEX_NATIVE_CONFIG_FENCE_STATE);
|
|
2287
2710
|
const previous = state.get(key) ?? Promise.resolve();
|
|
2288
|
-
|
|
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
|
-
|
|
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
|
|
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 {
|
|
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 {
|
|
3233
|
+
const { usesNativeAuth, ...startContext } = context;
|
|
2837
3234
|
return await ownCodexStartup(lifetime, startInitializedCodexAppServerClient({
|
|
3235
|
+
...startContext,
|
|
2838
3236
|
lifetime,
|
|
2839
|
-
|
|
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
|
-
|
|
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
|
|
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-
|
|
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(() =>
|
|
2929
|
-
|
|
2930
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 {
|
|
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 };
|