@openclaw/codex 2026.9.3 → 2026.9.5
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/assets/activity.svg +30 -0
- package/assets/icon.png +0 -0
- package/dist/.setup/account-usage-runtime-C2MOIvfq.mjs +75 -0
- package/dist/{apply-B6el6hdO.js → .setup/apply-CJ0ZfmBG.mjs} +12 -13
- package/dist/.setup/async-questions-DdhOCwGi.mjs +27 -0
- package/dist/{attempt-client-cleanup-D6cR54TV.js → .setup/attempt-client-cleanup-BpYKdTA0.mjs} +30 -211
- package/dist/{attempt-context-AO4DSjE0.js → .setup/attempt-context-VXVwTCfS.mjs} +6 -6
- package/dist/.setup/attempt-terminal-gZrxQ35N.mjs +5 -0
- package/dist/{auth-binding-Co2Vfcf_.js → .setup/auth-binding-DhLWa_7K.mjs} +2 -2
- package/dist/{auth-cache-key-Kq6oerr6.js → .setup/auth-cache-key-QirmgiCo.mjs} +3 -3
- package/dist/{auth-profile-CwzO4_RG.js → .setup/auth-profile-WqZtZfXN.mjs} +1 -1
- package/dist/.setup/binding-connection-Bm38niE8.mjs +50 -0
- package/dist/.setup/binding-connection.runtime-CnRMC0ta.mjs +48 -0
- package/dist/{bounded-turn-lRpmZHFv.js → .setup/bounded-turn-BtlZcivC.mjs} +19 -14
- package/dist/{build-state-6RL6qohz.js → .setup/build-state-Xx9ybZqa.mjs} +1 -1
- package/dist/{capabilities-BeqLPbtM.js → .setup/capabilities-_vXcZGSx.mjs} +1 -1
- package/dist/{client-BEKu4yDx.js → .setup/client-vXs2929Q.mjs} +355 -164
- package/dist/{command-dispatch-CisT9Jqq.js → .setup/command-dispatch-naHIZwwF.mjs} +3 -3
- package/dist/{command-formatters-DeTfrapr.js → .setup/command-formatters-CGEkdawF.mjs} +4 -3
- package/dist/{command-handlers-BfIsJEuA.js → .setup/command-handlers-BtAJEW1X.mjs} +812 -152
- package/dist/{command-rpc-BMqRQOFX.js → .setup/command-rpc-DHFpn4le.mjs} +37 -21
- package/dist/{compact-CGJZ2rlb.js → .setup/compact-C3i3qlzj.mjs} +28 -43
- package/dist/{config-JDfTI4VI.js → .setup/config-CedDWjM-.mjs} +5 -4
- package/dist/{config-options-jnIFvwxD.js → .setup/config-options-BsanJ8QG.mjs} +9 -421
- package/dist/{protocol-CAAcVIKF.js → .setup/config-parsing-CcB9iPoq.mjs} +9 -51
- package/dist/{config-runtime-BWf6JLWG.js → .setup/config-runtime-CeAhl_h4.mjs} +2 -2
- package/dist/.setup/config-security-BRQ2mgW9.mjs +465 -0
- package/dist/{config-utils-C57JiJrU.js → .setup/config-utils-DujwEnhg.mjs} +2 -4
- package/dist/{conversation-binding-CxOlHiix.js → .setup/conversation-binding-DhzrpTM6.mjs} +60 -47
- package/dist/{conversation-binding-data-BiodpIzq.js → .setup/conversation-binding-data-CrcyZk6O.mjs} +1 -1
- package/dist/{conversation-control-CUCrSIQI.js → .setup/conversation-control-DN53ns41.mjs} +17 -13
- package/dist/.setup/cyber-failover-DYwbmf1o.mjs +123 -0
- package/dist/.setup/cyber-failover-notice-e9G3J9-e.mjs +17 -0
- package/dist/{dynamic-tools-D-JBoaLt.js → .setup/dynamic-tools-D16lOp67.mjs} +168 -61
- package/dist/{effective-mcp-catalog-J_5Ep5Um.js → .setup/effective-mcp-catalog-K6kLCN8X.mjs} +3 -3
- package/dist/{ephemeral-turn-DSwzP8YY.js → .setup/ephemeral-turn-R1gA8Sn6.mjs} +4 -5
- package/dist/{event-projector-assistant-message-BmBM4qBV.js → .setup/event-projector-assistant-message-DNUR1s0A.mjs} +6 -3
- package/dist/.setup/event-projector-items-DyTQ_XqL.mjs +200 -0
- package/dist/{attempt-notifications--H8zXR5-.js → .setup/event-projector-usage-C7Ntzs-f.mjs} +102 -9
- package/dist/{harness-FR6eQgyO.js → .setup/harness-rxaaoN-o.mjs} +90 -19
- package/dist/.setup/inference-context-fulhZuz8.mjs +94 -0
- package/dist/.setup/inference-proxy-CC15HuSi.mjs +311 -0
- package/dist/{isolated-completion-DHBefrzg.js → .setup/isolated-completion-B6srt48J.mjs} +7 -7
- package/dist/{launch-args-RXQwn8zV.js → .setup/launch-args-DnMak49W.mjs} +22 -1
- package/dist/{managed-binary-DrjjRRUD.js → .setup/managed-binary-DP6Rib3P.mjs} +11 -2
- package/dist/{managed-thread-store-D1t5jh3G.js → .setup/managed-thread-store-BMqgThVL.mjs} +48 -14
- package/dist/{model-catalog-B_6M04Wo.js → .setup/model-catalog-DkvUuBey.mjs} +35 -10
- package/dist/{models-P9k2qAof.js → .setup/models-BDFgm_G-.mjs} +3 -3
- package/dist/.setup/native-auth-BLZGqFjw.mjs +57 -0
- package/dist/.setup/native-subagent-history-YXaL6dMd.mjs +135 -0
- package/dist/.setup/native-subagent-monitor-B1hxzIOy.mjs +5031 -0
- package/dist/.setup/native-subagent-task-ids-DsuOonKv.mjs +411 -0
- package/dist/{node-cli-sessions-rj0ysJwM.js → .setup/node-cli-sessions-Cl8b2ZF3.mjs} +1 -1
- package/dist/{node-exec-server.runtime-BY_ctYnT.js → .setup/node-exec-server.runtime-BaViBKNz.mjs} +5 -5
- package/dist/{plan-BMJdMOEF.js → .setup/plan-xD7WKYTM.mjs} +331 -79
- package/dist/{plugin-activation-BQK-f5sV.js → .setup/plugin-activation-r8nq5Jzp.mjs} +24 -19
- package/dist/{plugin-app-cache-key-CdSQzWyX.js → .setup/plugin-app-cache-key-BOxKP7db.mjs} +29 -25
- package/dist/{plugin-approval-roundtrip-DeW95wB5.js → .setup/plugin-approval-roundtrip-CjfzafAZ.mjs} +1 -1
- package/dist/{plugin-inventory-CoRCzWW4.js → .setup/plugin-inventory-DUle8DLz.mjs} +12 -8
- package/dist/{plugin-marketplace-discovery-3akBizzF.js → .setup/plugin-marketplace-discovery-P-Vndfqq.mjs} +18 -15
- package/dist/{plugin-metadata-cache-DgNfRAGA.js → .setup/plugin-metadata-cache-DsS5buNa.mjs} +33 -14
- package/dist/{provider-capabilities-W4tfK5Y5.js → .setup/provider-capabilities-B8J4Dy-O.mjs} +2 -2
- package/dist/.setup/provider-fFh_-VR3.mjs +50 -0
- package/dist/{rate-limits-Bqnx1N4z.js → .setup/rate-limits-DOEGYRNs.mjs} +90 -46
- package/dist/.setup/request-BioXJLYa.mjs +292 -0
- package/dist/.setup/run-attempt-lifecycle-B7JbY4-F.mjs +71 -0
- package/dist/{run-attempt-DwKds3DN.js → .setup/run-attempt-rlA07pUv.mjs} +644 -491
- package/dist/{runtime-artifact-T-NwqeSH.js → .setup/runtime-artifact-Dy38Z5iU.mjs} +2 -2
- package/dist/{sandbox-guard-BcT66fWy.js → .setup/sandbox-guard-BBP-RbTf.mjs} +4 -3
- package/dist/{session-binding-CKSepwIC.js → .setup/session-binding-_0W_fHRr.mjs} +45 -63
- package/dist/{session-binding-record-CaZjYwNS.js → .setup/session-binding-record-TH3xA0zj.mjs} +181 -3
- package/dist/.setup/session-binding-sidecars-CKYEcfNn.mjs +543 -0
- package/dist/{session-catalog-adoption-BKLtSrwi.js → .setup/session-catalog-adoption-CR_whkEW.mjs} +6 -6
- package/dist/{session-catalog-archive-D0i2pGj2.js → .setup/session-catalog-archive-CwZaPacf.mjs} +6 -6
- package/dist/.setup/session-catalog-events-jMcYfQyd.mjs +250 -0
- package/dist/.setup/session-catalog-fUdWDx-U.mjs +2464 -0
- package/dist/.setup/session-catalog-index-B141u15s.mjs +1070 -0
- package/dist/.setup/session-catalog-index-order-Cc5BzlQr.mjs +48 -0
- package/dist/.setup/session-catalog-index-state-BAuDztHN.mjs +180 -0
- package/dist/{session-catalog-parsing-CdD3JhdM.js → .setup/session-catalog-native-projection-ChV3cCtm.mjs} +213 -21
- package/dist/{session-catalog-node-adoption-BUuDYY8R.js → .setup/session-catalog-node-adoption-BVRsYOSh.mjs} +3 -3
- package/dist/{session-catalog-node-continue-CBtc4wkI.js → .setup/session-catalog-node-continue-Dowv8osw.mjs} +7 -7
- package/dist/.setup/session-catalog-projection-C1Bj9Jl-.mjs +414 -0
- package/dist/{session-cli-CbgaHh0f.js → .setup/session-cli-DIj-IE-E.mjs} +4 -4
- package/dist/{session-history-Cz-tOOYj.js → .setup/session-history-C--SrLI8.mjs} +10 -5
- package/dist/{session-history-import-DFN7sWRU.js → .setup/session-history-import-JHXT5Xfi.mjs} +4 -4
- package/dist/{session-history-read-cxPUxyVV.js → .setup/session-history-read-B3ZfSUbF.mjs} +2 -2
- package/dist/{session-history.worker-CNEvGaU5.js → .setup/session-history.worker-CpNj7H_P.mjs} +192 -89
- package/dist/{session-initialization-Jo86C60I.js → .setup/session-initialization-DH1z6fXn.mjs} +2 -2
- package/dist/{session-permission-policy-B22InTp_.js → .setup/session-permission-policy-DhurXY0l.mjs} +2 -2
- package/dist/{session-retirement-BSNG_mhf.js → .setup/session-retirement-CU87AOg9.mjs} +6 -6
- package/dist/{settled-turn-context-Du6gdUDd.js → .setup/settled-turn-context-fmwouT5I.mjs} +2 -2
- package/dist/{settled-turn-finalizer-BuLUrZl2.js → .setup/settled-turn-finalizer-CiY2bLFK.mjs} +10 -10
- package/dist/{shared-client-CVhez2Uo.js → .setup/shared-client-BpTtuLQ5.mjs} +495 -156
- package/dist/{side-question-DLbr2vUU.js → .setup/side-question-DSCZyoBD.mjs} +64 -47
- package/dist/{source-Da-h6f7e.js → .setup/source-Bjp4UQij.mjs} +15 -14
- package/dist/{thread-archive-guard-D1bP04Tf.js → .setup/thread-archive-guard-jmecf6OJ.mjs} +1 -1
- package/dist/.setup/thread-history-page-BTx-4xsg.mjs +83 -0
- package/dist/{thread-lifecycle-D1pzRwHB.js → .setup/thread-lifecycle-Cik28qWn.mjs} +330 -150
- package/dist/{thread-ownership-D6oASVRu.js → .setup/thread-ownership-skomxnIt.mjs} +4 -4
- package/dist/{thread-policy-D8kI7yAO.js → .setup/thread-policy-Cjs4B8xf.mjs} +3 -3
- package/dist/{thread-resume-T5cveyxA.js → .setup/thread-resume-BkNpj9Pz.mjs} +8 -5
- package/dist/.setup/timeout-DZF05XrR.mjs +63 -0
- package/dist/{session-catalog-home-id-D7-aLiNt.js → .setup/transcript-history-projection-DHNBDhCU.mjs} +73 -20
- package/dist/{transcript-mirror-t5TOccct.js → .setup/transcript-mirror-D4qp_leP.mjs} +15 -6
- package/dist/{transcript-mirror-attestation-DibE0krH.js → .setup/transcript-mirror-attestation-CzM-94NC.mjs} +4 -1
- package/dist/{transport-stdio-BGjHoYLr.js → .setup/transport-stdio-Cmx94Oiy.mjs} +149 -44
- package/dist/{upstream-session-fork-De-sLJ2r.js → .setup/upstream-session-fork-D3UKxgVD.mjs} +27 -26
- package/dist/{usage-CPPTmBvZ.js → .setup/usage-BOgBEKso.mjs} +4 -4
- package/dist/.setup/usage-limit-error-C0ow7DOc.mjs +166 -0
- package/dist/{version-omm6IPI3.js → .setup/version-CoqzXPgK.mjs} +1 -1
- package/dist/{web-search-provider.runtime-CSVgQL0w.js → .setup/web-search-provider.runtime-CTGuJt6i.mjs} +3 -3
- package/dist/api.js +28 -20
- package/dist/cli-metadata.js +1 -1
- package/dist/doctor-contract-api.js +8 -528
- package/dist/harness.js +1 -1
- package/dist/index.js +130 -135
- package/dist/media-understanding-provider.js +3 -3
- package/dist/migration-provider-api.js +2 -0
- package/dist/native-tool-policy.js +12 -0
- package/dist/provider-discovery.js +18 -0
- package/dist/session-history-worker-runtime.js +23 -5
- package/dist/session-history.worker.js +2 -2
- package/dist/web-search-contract-api.js +1 -1
- package/openclaw.plugin.json +354 -68
- package/package.json +11 -8
- package/dist/binding-connection-QqgcPCgk.js +0 -60
- package/dist/event-projector-usage-CIyrYYid.js +0 -102
- package/dist/native-subagent-monitor-BbCUKRwC.js +0 -3350
- package/dist/request-CGvGOpeR.js +0 -198
- package/dist/session-catalog-HaDcp7Sv.js +0 -1533
- package/dist/session-catalog-provenance-DkJHo735.js +0 -124
- package/dist/timeout-BVw8aaM1.js +0 -33
- package/dist/{auth-profile-selection-DFu9e167.js → .setup/auth-profile-selection-DFu9e167.mjs} +0 -0
- package/dist/{context-compaction-activity-CMla5FPJ.js → .setup/context-compaction-activity-CMla5FPJ.mjs} +0 -0
- package/dist/{elicitation-input-DPoK8F7w.js → .setup/elicitation-input-DPoK8F7w.mjs} +0 -0
- package/dist/{history-rejection-B4nOXNXF.js → .setup/history-rejection-B4nOXNXF.mjs} +0 -0
- package/dist/{image-payload-sanitizer-tupAr-2o.js → .setup/image-payload-sanitizer-tupAr-2o.mjs} +0 -0
- package/dist/{incognito-session-uhrBF6wJ.js → .setup/incognito-session-uhrBF6wJ.mjs} +0 -0
- package/dist/{local-runtime-attribution-B_2mnqhb.js → .setup/local-runtime-attribution-B_2mnqhb.mjs} +0 -0
- package/dist/{native-execution-policy-umd0tgh4.js → .setup/native-execution-policy-YBMHSzC4.mjs} +1 -1
- /package/dist/{rolldown-runtime-8H4AJuhK.js → .setup/rolldown-runtime-8H4AJuhK.mjs} +0 -0
- /package/dist/{session-binding-meta-B7aEMU7g.js → .setup/session-binding-meta-B7aEMU7g.mjs} +0 -0
- /package/dist/{session-upstream-marker-D15C9NHp.js → .setup/session-upstream-marker-D15C9NHp.mjs} +0 -0
- /package/dist/{upstream-prompt-provenance-LphB8slG.js → .setup/upstream-prompt-provenance-LphB8slG.mjs} +0 -0
- /package/dist/{web-search-provider.shared-BrZmlqyR.js → .setup/web-search-provider.shared-BrZmlqyR.mjs} +0 -0
|
@@ -1,43 +1,47 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { s as
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { s as
|
|
9
|
-
import {
|
|
10
|
-
import { i as
|
|
11
|
-
import {
|
|
12
|
-
import { i as
|
|
13
|
-
import {
|
|
14
|
-
import "./
|
|
15
|
-
import {
|
|
16
|
-
import { i as resolveCodexBindingAppServerConnection } from "./binding-connection-
|
|
17
|
-
import {
|
|
18
|
-
import
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import { n as
|
|
27
|
-
import {
|
|
28
|
-
import { a as
|
|
29
|
-
import {
|
|
1
|
+
import { n as isCodexFastServiceTier } from "./config-utils-DujwEnhg.mjs";
|
|
2
|
+
import { c as CODEX_PLUGINS_MARKETPLACE_NAME, i as pluginReadParams, r as isOpenAiCuratedMarketplaceName, t as findCodexMarketplacePluginSummary } from "./plugin-inventory-DUle8DLz.mjs";
|
|
3
|
+
import { n as assertCodexBindingMayBeReplaced, p as sessionBindingIdentity, r as bindingStoreKey } from "./session-binding-record-TH3xA0zj.mjs";
|
|
4
|
+
import { m as isJsonObject } from "./config-security-BRQ2mgW9.mjs";
|
|
5
|
+
import { _ as assertCodexThreadAcceptsDirectInput, s as isCodexAppServerIndeterminateRequestCancellationError, u as isCodexAppServerPrewriteRequestCancellationError, y as assertCodexThreadResumeResponse } from "./client-vXs2929Q.mjs";
|
|
6
|
+
import { c as resolveCodexAppServerPreparedApiKeyCacheKey, s as resolveCodexAppServerFallbackApiKeyCacheKey } from "./auth-cache-key-QirmgiCo.mjs";
|
|
7
|
+
import { r as withCodexConversationThreadActivity, t as isIncognitoSessionKey } from "./incognito-session-uhrBF6wJ.mjs";
|
|
8
|
+
import { a as CODEX_HOST_INSPECTION_AUTH_ERROR, c as hasCodexAdminScope, i as CODEX_FULL_PERMISSIONS_AUTH_ERROR, n as filterCodexMarketplacePlugins, o as CODEX_NATIVE_EXECUTION_AUTH_ERROR, r as parseCodexPluginMarketplaceId, s as canMutateCodexHost, t as discoverCodexMarketplacePlugins } from "./plugin-marketplace-discovery-P-Vndfqq.mjs";
|
|
9
|
+
import { s as summarizeCodexAccountUsage } from "./rate-limits-DOEGYRNs.mjs";
|
|
10
|
+
import { a as formatCodexAccountLine, c as formatCodexTextForDisplay, d as formatModels, f as formatSkills, i as formatAccount, l as formatComputerUseStatus, n as buildHelp, o as formatCodexDisplayText, p as formatThreads, r as escapeCodexChatText, s as formatCodexStatus, t as CODEX_RESUME_SAFE_THREAD_ID_PATTERN, u as formatList } from "./command-formatters-CGEkdawF.mjs";
|
|
11
|
+
import { i as readCodexConversationBindingData, n as createCodexCliNodeConversationBindingData, o as resolveCodexDefaultWorkspaceDir, r as createCodexConversationBindingData } from "./conversation-binding-data-CrcyZk6O.mjs";
|
|
12
|
+
import { i as CodexAppServerRpcError } from "./timeout-DZF05XrR.mjs";
|
|
13
|
+
import { t as CODEX_CONTROL_METHODS } from "./capabilities-_vXcZGSx.mjs";
|
|
14
|
+
import { i as formatCodexCliSessions } from "./node-cli-sessions-Cl8b2ZF3.mjs";
|
|
15
|
+
import { a as defaultCodexAppInventoryCache, r as buildCodexPluginAppCacheKey } from "./plugin-app-cache-key-BOxKP7db.mjs";
|
|
16
|
+
import { i as resolveCodexBindingAppServerConnection } from "./binding-connection-Bm38niE8.mjs";
|
|
17
|
+
import { o as withCodexAppServerJsonClient } from "./request-BioXJLYa.mjs";
|
|
18
|
+
import "./config-CedDWjM-.mjs";
|
|
19
|
+
import { n as resolveCodexAppServerRuntimeOptions } from "./config-runtime-CeAhl_h4.mjs";
|
|
20
|
+
import { a as resolveCodexAppServerAuthProfileStore, i as resolveCodexAppServerAuthProfileIdForAgent, n as normalizeCodexAppServerBindingModelProvider } from "./auth-profile-WqZtZfXN.mjs";
|
|
21
|
+
import { n as fingerprintCodexAppServerAuthBinding } from "./auth-binding-DhLWa_7K.mjs";
|
|
22
|
+
import { I as hasCodexAppServerLiveThread, N as consumeCodexAppServerLiveThread, X as resolveCodexAppServerAuthAccountCacheKey, c as getLeasedSharedCodexAppServerClient, h as releaseLeasedSharedCodexAppServerClient } from "./shared-client-BpTtuLQ5.mjs";
|
|
23
|
+
import { a as closeCodexStartupClientBestEffort } from "./attempt-client-cleanup-BpYKdTA0.mjs";
|
|
24
|
+
import { t as listAllCodexAppServerModels } from "./models-BDFgm_G-.mjs";
|
|
25
|
+
import { n as refreshCodexAppRuntimeState, r as refreshCodexPluginRuntimeState } from "./plugin-activation-r8nq5Jzp.mjs";
|
|
26
|
+
import { n as createCodexSessionGenerationSupersededError, o as resolveCodexSessionBinding } from "./session-binding-_0W_fHRr.mjs";
|
|
27
|
+
import { r as assertCodexSupervisionThreadLineage } from "./thread-policy-Cjs4B8xf.mjs";
|
|
28
|
+
import { a as rollbackCodexAppServerBindingSubscription, i as retireCodexConversationThreadBinding, n as releaseCodexAppServerBindingSubscription, r as retainCodexAppServerBindingSubscription, s as withExclusiveCodexAppServerThread, t as isSameCodexAppServerThreadOwner } from "./thread-ownership-skomxnIt.mjs";
|
|
29
|
+
import { n as resolveCodexNativeSandboxBlock, t as resolveCodexNativeExecutionBlock } from "./sandbox-guard-BBP-RbTf.mjs";
|
|
30
|
+
import { i as readCodexComputerUseStatus, r as installCodexComputerUse, t as defaultCodexPluginMetadataCache } from "./plugin-metadata-cache-DsS5buNa.mjs";
|
|
31
|
+
import { a as requestOptions, i as readCodexStatusProbes, o as safeCodexControlRequest, r as prepareCodexControlSessionAuth, t as codexControlRequest } from "./command-rpc-DHFpn4le.mjs";
|
|
32
|
+
import { a as setCodexConversationFastMode, c as steerCodexConversationTurn, i as readCodexConversationActiveTurn, l as stopCodexConversationTurn, n as parseCodexFastModeArg, o as setCodexConversationModel, r as parseCodexPermissionsModeArg, s as setCodexConversationPermissions, t as formatPermissionsMode } from "./conversation-control-DN53ns41.mjs";
|
|
30
33
|
import { normalizeOptionalString, normalizeUniqueStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
31
34
|
import crypto from "node:crypto";
|
|
35
|
+
import { isDeepStrictEqual } from "node:util";
|
|
32
36
|
import { resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
|
|
33
37
|
import { parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
|
|
34
38
|
import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
|
35
39
|
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
36
|
-
import {
|
|
37
|
-
import { ensureAuthProfileStore, resolveAgentDir as resolveAgentDir$1, resolveAuthProfileEligibility, resolveProfileUnusableUntilForDisplay } from "openclaw/plugin-sdk/agent-runtime";
|
|
38
|
-
import { parseAgentSessionKey } from "openclaw/plugin-sdk/routing";
|
|
40
|
+
import { ensureAuthProfileStore, resolveAgentDir as resolveAgentDir$1, resolveAgentWorkspaceDir, resolveAuthProfileEligibility, resolveProfileUnusableUntilForDisplay } from "openclaw/plugin-sdk/agent-runtime";
|
|
39
41
|
import { getSessionEntry, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
|
|
40
42
|
import { findNormalizedProviderValue, resolveAuthProfileOrder } from "openclaw/plugin-sdk/provider-auth";
|
|
43
|
+
import { parseAgentSessionKey } from "openclaw/plugin-sdk/routing";
|
|
44
|
+
import { renderMessagePresentationFallbackText } from "openclaw/plugin-sdk/interactive-runtime";
|
|
41
45
|
import { MODEL_SELECTION_LOCKED_MESSAGE, isModelSelectionLocked, resolvePersistedSessionRuntimeId } from "openclaw/plugin-sdk/model-session-runtime";
|
|
42
46
|
//#region extensions/codex/src/command-account.ts
|
|
43
47
|
const OPENAI_PROVIDER_ID = "openai";
|
|
@@ -336,6 +340,453 @@ function formatRelativeReset(untilMs, nowMs) {
|
|
|
336
340
|
const days = Math.ceil(durationMs / dayMs);
|
|
337
341
|
return `in ${days} ${days === 1 ? "day" : "days"}`;
|
|
338
342
|
}
|
|
343
|
+
function buildCodexPluginAppLinks(apps, options = {}) {
|
|
344
|
+
const blocks = apps.slice(0, 5).map((app) => {
|
|
345
|
+
const name = formatCodexDisplayText((app.name.trim() || app.id).slice(0, 80));
|
|
346
|
+
const url = safeCodexAppLink(app.installUrl);
|
|
347
|
+
return url ? {
|
|
348
|
+
type: "buttons",
|
|
349
|
+
buttons: [{
|
|
350
|
+
label: `Open ${name} in ChatGPT`,
|
|
351
|
+
action: {
|
|
352
|
+
type: "url",
|
|
353
|
+
url
|
|
354
|
+
}
|
|
355
|
+
}]
|
|
356
|
+
} : {
|
|
357
|
+
type: "text",
|
|
358
|
+
text: `${name}: ChatGPT setup/manage link unavailable. In Codex CLI, run /apps and select this app to continue.`
|
|
359
|
+
};
|
|
360
|
+
});
|
|
361
|
+
const remaining = apps.length - 5;
|
|
362
|
+
if (remaining > 0) blocks.push({
|
|
363
|
+
type: "text",
|
|
364
|
+
text: `${remaining} more apps are not shown. ${options.continuationCommand ? "Choose More apps to continue." : "In Codex CLI, run /apps to review the remaining apps."}`
|
|
365
|
+
});
|
|
366
|
+
if (options.continuationCommand) blocks.push({
|
|
367
|
+
type: "buttons",
|
|
368
|
+
buttons: [{
|
|
369
|
+
label: "More apps",
|
|
370
|
+
action: {
|
|
371
|
+
type: "command",
|
|
372
|
+
command: options.continuationCommand
|
|
373
|
+
}
|
|
374
|
+
}]
|
|
375
|
+
});
|
|
376
|
+
if (apps.length > 0) blocks.push({
|
|
377
|
+
type: "context",
|
|
378
|
+
text: "Use the same ChatGPT account and workspace as Codex in your browser. Opening an app page does not confirm that it is connected or callable in this conversation. If the app is not shown, in Codex CLI run /apps and select it."
|
|
379
|
+
});
|
|
380
|
+
return blocks;
|
|
381
|
+
}
|
|
382
|
+
function safeCodexAppLink(value) {
|
|
383
|
+
if (!value || value.length > 2048 || /[\s\p{Cc}\p{Cf}<>]/u.test(value)) return;
|
|
384
|
+
try {
|
|
385
|
+
const url = new URL(value);
|
|
386
|
+
const host = url.hostname;
|
|
387
|
+
const hosted = host === "chatgpt.com" || host === "chatgpt-staging.com" || host.endsWith(".chatgpt.com") || host.endsWith(".chatgpt-staging.com");
|
|
388
|
+
return url.protocol === "https:" && !url.username && !url.password && hosted ? value : void 0;
|
|
389
|
+
} catch {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
//#endregion
|
|
394
|
+
//#region extensions/codex/src/command-plugin-config.ts
|
|
395
|
+
/** Merge historical curated wire aliases only when they identify the same install source. */
|
|
396
|
+
function resolveCuratedMarketplaceAliases(plugins, requestedMarketplaceName) {
|
|
397
|
+
if (!isOpenAiCuratedMarketplaceName(requestedMarketplaceName)) return;
|
|
398
|
+
const sourceIdentities = new Set(plugins.map((plugin) => plugin.marketplacePath ? `local:${plugin.marketplacePath}` : plugin.remotePluginId ? `remote:${plugin.remotePluginId}` : void 0));
|
|
399
|
+
if (sourceIdentities.size !== 1 || sourceIdentities.has(void 0)) return;
|
|
400
|
+
const selected = plugins.find((plugin) => plugin.marketplaceName === requestedMarketplaceName) ?? plugins[0];
|
|
401
|
+
if (!selected) return;
|
|
402
|
+
return {
|
|
403
|
+
...selected,
|
|
404
|
+
installed: plugins.some((plugin) => plugin.installed),
|
|
405
|
+
enabled: plugins.some((plugin) => plugin.installed && plugin.enabled),
|
|
406
|
+
available: plugins.every((plugin) => plugin.available),
|
|
407
|
+
...selected.remotePluginId ? { mustShowInstallationInterstitial: plugins.some((plugin) => plugin.mustShowInstallationInterstitial === true) ? true : plugins.every((plugin) => plugin.mustShowInstallationInterstitial === false) ? false : null } : {},
|
|
408
|
+
...plugins.some((plugin) => plugin.installPolicy === "NOT_AVAILABLE") ? { installPolicy: "NOT_AVAILABLE" } : {}
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
function persistedPluginName(plugin) {
|
|
412
|
+
return !plugin.marketplacePath && plugin.summaryId.endsWith(`@${plugin.marketplaceName}`) ? plugin.summaryId : plugin.pluginName;
|
|
413
|
+
}
|
|
414
|
+
function resolveConfiguredPluginKey(plugins, target) {
|
|
415
|
+
const requested = parseCodexPluginMarketplaceId(target);
|
|
416
|
+
const direct = plugins[target];
|
|
417
|
+
if (!requested) {
|
|
418
|
+
if (!direct) return { status: "missing" };
|
|
419
|
+
const qualifiedName = direct.pluginName ? parseCodexPluginMarketplaceId(direct.pluginName) : void 0;
|
|
420
|
+
if (qualifiedName && direct.marketplaceName && !marketplaceNamesRepresentSameCatalog(qualifiedName.marketplaceName, direct.marketplaceName)) return { status: "mismatched" };
|
|
421
|
+
const identity = resolveConfiguredPluginIdentity(direct);
|
|
422
|
+
if (!identity) return {
|
|
423
|
+
status: "matched",
|
|
424
|
+
configKey: target
|
|
425
|
+
};
|
|
426
|
+
const marketplaceName = isOpenAiCuratedMarketplaceName(identity.marketplaceName) ? CODEX_PLUGINS_MARKETPLACE_NAME : identity.marketplaceName;
|
|
427
|
+
const canonicalId = `${identity.pluginName}@${marketplaceName}`;
|
|
428
|
+
const canonical = plugins[canonicalId];
|
|
429
|
+
if (canonical && !matchesConfiguredPluginIdentity(canonical, identity, canonicalId)) return { status: "mismatched" };
|
|
430
|
+
return Object.values(plugins).filter((entry) => matchesConfiguredPluginIdentity(entry, identity, canonicalId)).length > 1 ? { status: "ambiguous" } : {
|
|
431
|
+
status: "matched",
|
|
432
|
+
configKey: target
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
if (direct && !matchesConfiguredPluginIdentity(direct, requested, target)) return { status: "mismatched" };
|
|
436
|
+
const matching = Object.entries(plugins).filter(([, entry]) => matchesConfiguredPluginIdentity(entry, requested, target));
|
|
437
|
+
if (matching.length > 1) return { status: "ambiguous" };
|
|
438
|
+
const configKey = matching[0]?.[0];
|
|
439
|
+
return configKey ? {
|
|
440
|
+
status: "matched",
|
|
441
|
+
configKey
|
|
442
|
+
} : { status: "missing" };
|
|
443
|
+
}
|
|
444
|
+
function resolveInstalledPluginKey(plugins, plugin) {
|
|
445
|
+
const discovered = resolveConfiguredPluginKey(plugins, plugin.id);
|
|
446
|
+
if (discovered.status === "ambiguous" || discovered.status === "mismatched") return discovered;
|
|
447
|
+
if (!isOpenAiCuratedMarketplaceName(plugin.marketplaceName)) return discovered;
|
|
448
|
+
const canonical = resolveConfiguredPluginKey(plugins, `${plugin.pluginName}@${CODEX_PLUGINS_MARKETPLACE_NAME}`);
|
|
449
|
+
if (canonical.status === "ambiguous" || canonical.status === "mismatched") return canonical;
|
|
450
|
+
if (discovered.status === "matched" && canonical.status === "matched" && discovered.configKey !== canonical.configKey) return { status: "ambiguous" };
|
|
451
|
+
return canonical.status === "matched" ? canonical : discovered;
|
|
452
|
+
}
|
|
453
|
+
function resolveConfiguredPluginIdentity(entry) {
|
|
454
|
+
if (!entry.pluginName || !entry.marketplaceName) return;
|
|
455
|
+
const qualified = parseCodexPluginMarketplaceId(entry.pluginName);
|
|
456
|
+
if (qualified) return marketplaceNamesRepresentSameCatalog(qualified.marketplaceName, entry.marketplaceName) ? {
|
|
457
|
+
pluginName: qualified.pluginName,
|
|
458
|
+
marketplaceName: entry.marketplaceName
|
|
459
|
+
} : void 0;
|
|
460
|
+
return parseCodexPluginMarketplaceId(`${entry.pluginName}@${entry.marketplaceName}`);
|
|
461
|
+
}
|
|
462
|
+
function matchesConfiguredPluginIdentity(entry, requested, target) {
|
|
463
|
+
const configuredName = entry.pluginName ? parseCodexPluginMarketplaceId(entry.pluginName) : void 0;
|
|
464
|
+
return typeof entry.marketplaceName === "string" && marketplaceNamesRepresentSameCatalog(entry.marketplaceName, requested.marketplaceName) && (entry.pluginName === requested.pluginName || entry.pluginName === target || configuredName?.pluginName === requested.pluginName && marketplaceNamesRepresentSameCatalog(configuredName.marketplaceName, requested.marketplaceName));
|
|
465
|
+
}
|
|
466
|
+
function marketplaceNamesRepresentSameCatalog(left, right) {
|
|
467
|
+
return left === right || isOpenAiCuratedMarketplaceName(left) && isOpenAiCuratedMarketplaceName(right);
|
|
468
|
+
}
|
|
469
|
+
function describeConfiguredPluginIdentityConflict(target, status) {
|
|
470
|
+
const identity = formatCodexDisplayText(target);
|
|
471
|
+
return status === "ambiguous" ? `Multiple configured Codex plugins match '${identity}'; resolve duplicate plugin policies first.` : `Configured Codex plugin key '${identity}' points to a different plugin identity; resolve the configuration conflict first.`;
|
|
472
|
+
}
|
|
473
|
+
//#endregion
|
|
474
|
+
//#region extensions/codex/src/command-plugins-readiness.ts
|
|
475
|
+
/** Runtime support is not account-wide permission to browse, connect or invoke apps. */
|
|
476
|
+
async function readCodexHostedAppsSupport(context, account) {
|
|
477
|
+
if (account.status !== "known") return "unknown";
|
|
478
|
+
if (!isJsonObject(account.value.account) || account.value.account.type !== "chatgpt") return "sign_in_required";
|
|
479
|
+
const features = await readEvidence(async () => {
|
|
480
|
+
let cursor;
|
|
481
|
+
const visited = /* @__PURE__ */ new Set();
|
|
482
|
+
do {
|
|
483
|
+
const response = await context.request("experimentalFeature/list", {
|
|
484
|
+
...context.threadId ? { threadId: context.threadId } : {},
|
|
485
|
+
...cursor ? { cursor } : {},
|
|
486
|
+
limit: 100
|
|
487
|
+
});
|
|
488
|
+
const apps = response.data.find((feature) => feature.name === "apps");
|
|
489
|
+
if (apps) return apps.enabled;
|
|
490
|
+
cursor = response.nextCursor ?? void 0;
|
|
491
|
+
if (cursor && visited.has(cursor)) return;
|
|
492
|
+
if (cursor) visited.add(cursor);
|
|
493
|
+
} while (cursor);
|
|
494
|
+
});
|
|
495
|
+
if (features.status !== "known") return features.reason === "unsupported" ? "unsupported" : "unknown";
|
|
496
|
+
return features.value === void 0 ? "unknown" : features.value ? "supported" : "disabled";
|
|
497
|
+
}
|
|
498
|
+
function describeCodexHostedAppsSupport(support) {
|
|
499
|
+
switch (support) {
|
|
500
|
+
case "supported": return "Hosted apps: supported by this runtime; account connections and action permissions are checked separately.";
|
|
501
|
+
case "sign_in_required": return "Hosted apps require ChatGPT sign-in. Check /codex account; local Codex plugins remain available.";
|
|
502
|
+
case "disabled": return "Hosted apps are disabled in this Codex runtime. Check its effective apps feature configuration.";
|
|
503
|
+
case "unsupported": return "Hosted app support is unknown: this Codex version cannot report the required feature state. Update to OpenClaw's supported Codex version.";
|
|
504
|
+
default: return "Hosted app support is unknown. Check /codex account and retry this command.";
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
function pluginCatalogState(summary) {
|
|
508
|
+
if (!summary) return "unknown";
|
|
509
|
+
if (summary.availability === "DISABLED_BY_ADMIN" || summary.installPolicy === "NOT_AVAILABLE") return "blocked";
|
|
510
|
+
return summary.availability === "AVAILABLE" && (summary.installPolicy === "AVAILABLE" || summary.installPolicy === "INSTALLED_BY_DEFAULT") ? "available" : "unknown";
|
|
511
|
+
}
|
|
512
|
+
function codexPluginAppPageLinks(readiness) {
|
|
513
|
+
if (readiness.hostedSupport !== "supported" || pluginCatalogState(readiness.summary) !== "available" || readiness.metadata.status !== "known") return [];
|
|
514
|
+
const metadata = new Map(readiness.metadata.value.apps.map((app) => [app.id, app]));
|
|
515
|
+
return (readiness.detail?.apps ?? []).flatMap((app) => {
|
|
516
|
+
const authorized = metadata.get(app.id);
|
|
517
|
+
return authorized ? [{
|
|
518
|
+
...app,
|
|
519
|
+
name: authorized.name,
|
|
520
|
+
installUrl: authorized.installUrl
|
|
521
|
+
}] : [];
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
/** Reads existing snapshots only. Neither metadata nor installation proves a live connection. */
|
|
525
|
+
async function readCodexPluginReadiness(params) {
|
|
526
|
+
const { context, current, configKey } = params;
|
|
527
|
+
const entry = current.plugins?.[configKey];
|
|
528
|
+
const identity = entry ? resolveConfiguredPluginIdentity(entry) : void 0;
|
|
529
|
+
if (!entry?.marketplaceName || !entry.pluginName || !identity) throw new Error("This configured plugin has no marketplace identity. Check /codex plugins list.");
|
|
530
|
+
const result = {
|
|
531
|
+
configKey,
|
|
532
|
+
commandId: `${identity.pluginName}@${identity.marketplaceName}`,
|
|
533
|
+
openClawEnabled: current.enabled === true && entry.enabled !== false,
|
|
534
|
+
agentId: context.agentId,
|
|
535
|
+
profileId: context.profileId,
|
|
536
|
+
workspaceDir: context.workspaceDir,
|
|
537
|
+
threadId: context.threadId,
|
|
538
|
+
runtime: {
|
|
539
|
+
status: "unavailable",
|
|
540
|
+
reason: "request_failed"
|
|
541
|
+
},
|
|
542
|
+
metadata: {
|
|
543
|
+
status: "unavailable",
|
|
544
|
+
reason: "request_failed"
|
|
545
|
+
},
|
|
546
|
+
account: await readEvidence(() => context.request("account/read", { refreshToken: false })),
|
|
547
|
+
hostedSupport: "unknown"
|
|
548
|
+
};
|
|
549
|
+
const installed = await readEvidence(() => context.request("plugin/installed", { cwds: [context.workspaceDir] }));
|
|
550
|
+
let selected = installed.status === "known" ? findCodexMarketplacePluginSummary(installed.value, entry.marketplaceName, entry.pluginName) : void 0;
|
|
551
|
+
if (!selected) {
|
|
552
|
+
const responses = [];
|
|
553
|
+
const catalog = await readEvidence(() => discoverCodexMarketplacePlugins({
|
|
554
|
+
workspaceDir: context.workspaceDir,
|
|
555
|
+
request: async (requestParams) => {
|
|
556
|
+
const response = await context.request("plugin/list", requestParams);
|
|
557
|
+
responses.push(response);
|
|
558
|
+
return response;
|
|
559
|
+
}
|
|
560
|
+
}));
|
|
561
|
+
if (catalog.status === "known") {
|
|
562
|
+
const matches = catalog.value.plugins.filter((plugin) => {
|
|
563
|
+
const configured = resolveInstalledPluginKey(current.plugins ?? {}, plugin);
|
|
564
|
+
return configured.status === "matched" && configured.configKey === configKey;
|
|
565
|
+
});
|
|
566
|
+
const candidate = matches.length === 1 ? matches[0] : resolveCuratedMarketplaceAliases(matches, entry.marketplaceName);
|
|
567
|
+
if (candidate) for (const response of responses) {
|
|
568
|
+
selected = findCodexMarketplacePluginSummary(response, candidate.marketplaceName, candidate.summaryId);
|
|
569
|
+
if (selected) {
|
|
570
|
+
selected.summary = {
|
|
571
|
+
...selected.summary,
|
|
572
|
+
installed: candidate.installed,
|
|
573
|
+
enabled: candidate.enabled,
|
|
574
|
+
...candidate.available ? {} : { availability: "DISABLED_BY_ADMIN" }
|
|
575
|
+
};
|
|
576
|
+
break;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
} else result.diagnostic = describeUnavailableEvidence(catalog.reason);
|
|
580
|
+
}
|
|
581
|
+
if (!selected) {
|
|
582
|
+
await context.validateCurrent();
|
|
583
|
+
return result;
|
|
584
|
+
}
|
|
585
|
+
result.summary = selected.summary;
|
|
586
|
+
const selectedPlugin = selected;
|
|
587
|
+
const pluginName = selected.marketplace.remoteMarketplaceName ? selected.summary.remotePluginId : entry.pluginName;
|
|
588
|
+
if (!pluginName) return result;
|
|
589
|
+
const detail = await readEvidence(() => context.request("plugin/read", pluginReadParams(selectedPlugin.marketplace, pluginName)));
|
|
590
|
+
if (detail.status !== "known" || detail.value.plugin.summary.id !== selected.summary.id) {
|
|
591
|
+
if (detail.status === "unavailable") result.diagnostic = describeUnavailableEvidence(detail.reason);
|
|
592
|
+
await context.validateCurrent();
|
|
593
|
+
return result;
|
|
594
|
+
}
|
|
595
|
+
result.detail = detail.value.plugin;
|
|
596
|
+
result.summary = detail.value.plugin.summary;
|
|
597
|
+
const appIds = Array.from(new Set(result.detail.apps.map((app) => app.id))).toSorted();
|
|
598
|
+
if (appIds.length > 0) {
|
|
599
|
+
result.hostedSupport = await readCodexHostedAppsSupport(context, result.account);
|
|
600
|
+
const [runtime, metadata] = await Promise.all([readEvidence(() => context.request("app/installed", {
|
|
601
|
+
...context.threadId ? { threadId: context.threadId } : {},
|
|
602
|
+
forceRefresh: false
|
|
603
|
+
})), readEvidence(async () => {
|
|
604
|
+
const responses = [];
|
|
605
|
+
for (let offset = 0; offset < appIds.length; offset += 100) responses.push(await context.request("app/read", {
|
|
606
|
+
appIds: appIds.slice(offset, offset + 100),
|
|
607
|
+
...context.threadId ? { threadId: context.threadId } : {}
|
|
608
|
+
}));
|
|
609
|
+
return {
|
|
610
|
+
apps: responses.flatMap((response) => response.apps),
|
|
611
|
+
missingAppIds: responses.flatMap((response) => response.missingAppIds)
|
|
612
|
+
};
|
|
613
|
+
})]);
|
|
614
|
+
result.runtime = runtime;
|
|
615
|
+
result.metadata = metadata;
|
|
616
|
+
}
|
|
617
|
+
await context.validateCurrent();
|
|
618
|
+
return result;
|
|
619
|
+
}
|
|
620
|
+
function formatCodexPluginReadiness(readiness, page = 1) {
|
|
621
|
+
const summary = readiness.summary;
|
|
622
|
+
const catalog = pluginCatalogState(summary);
|
|
623
|
+
const hasApps = Boolean(readiness.detail?.apps.length);
|
|
624
|
+
const canRefreshHostedApps = readiness.hostedSupport === "supported";
|
|
625
|
+
const lines = [
|
|
626
|
+
`Plugin: ${display(readiness.commandId)}`,
|
|
627
|
+
`Agent: ${display(readiness.agentId)} · Profile: ${display(readiness.profileId ?? "native Codex account (profile unknown)")}`,
|
|
628
|
+
`Conversation workspace: ${display(readiness.workspaceDir)}`,
|
|
629
|
+
formatBoundAccount(readiness.account),
|
|
630
|
+
`Catalog: ${catalog === "blocked" ? "blocked by marketplace policy" : catalog}`,
|
|
631
|
+
`Bundle: ${summary ? summary.installed ? "installed" : "not installed" : "unknown"}`,
|
|
632
|
+
`Codex plugin: ${summary ? summary.enabled ? "enabled" : "disabled" : "unknown"}`,
|
|
633
|
+
`OpenClaw app access: ${readiness.openClawEnabled ? "enabled" : "disabled"} (shared Codex plugin configuration; takes effect on your next message).`,
|
|
634
|
+
...hasApps ? [describeCodexHostedAppsSupport(readiness.hostedSupport)] : []
|
|
635
|
+
];
|
|
636
|
+
if (catalog === "blocked") lines.push(summary?.disabledReason === "plan_not_eligible" ? "Next: this ChatGPT plan is not eligible for the plugin. Check its plan requirements." : summary?.disabledReason === "required_app_unavailable" ? "Next: a required hosted app is unavailable. Check access with the app or workspace owner." : summary?.disabledReason === "disabled_by_admin" || summary?.availability === "DISABLED_BY_ADMIN" ? "Next: ask the marketplace administrator to restore access." : "Next: check the plugin's marketplace requirements; its policy does not permit installation.");
|
|
637
|
+
else if (!readiness.openClawEnabled) lines.push(`Next: /codex plugins enable ${readiness.commandId}. Takes effect on your next message.`);
|
|
638
|
+
else if (summary && (!summary.installed || !summary.enabled)) lines.push(`Next: /codex plugins install ${readiness.commandId}. Takes effect on your next message.`);
|
|
639
|
+
const blocks = [{
|
|
640
|
+
type: "text",
|
|
641
|
+
text: lines.join("\n")
|
|
642
|
+
}];
|
|
643
|
+
if (readiness.diagnostic) blocks.push({
|
|
644
|
+
type: "text",
|
|
645
|
+
text: readiness.diagnostic
|
|
646
|
+
});
|
|
647
|
+
if (!readiness.detail) blocks.push({
|
|
648
|
+
type: "text",
|
|
649
|
+
text: "App details unavailable. Check the plugin in Codex, then run this status command again."
|
|
650
|
+
});
|
|
651
|
+
else {
|
|
652
|
+
const apps = readiness.detail.apps.toSorted((left, right) => left.id.localeCompare(right.id));
|
|
653
|
+
const pageCount = Math.max(1, Math.ceil(apps.length / 5));
|
|
654
|
+
if (page > pageCount) return { text: `No app page ${page}. Use /codex plugins status ${readiness.commandId} ${pageCount}.` };
|
|
655
|
+
const start = (page - 1) * 5;
|
|
656
|
+
const visible = apps.slice(start, start + 5);
|
|
657
|
+
const runtimeById = new Map(readiness.runtime.status === "known" ? readiness.runtime.value.apps.map((app) => [app.id, app]) : []);
|
|
658
|
+
if (visible.length > 0 && readiness.runtime.status === "unavailable") blocks.push({
|
|
659
|
+
type: "text",
|
|
660
|
+
text: describeUnavailableEvidence(readiness.runtime.reason)
|
|
661
|
+
});
|
|
662
|
+
blocks.push({
|
|
663
|
+
type: "text",
|
|
664
|
+
text: visible.length === 0 ? "No hosted apps declared. Skills and other plugin capabilities are not assessed here." : [
|
|
665
|
+
`Apps (page ${page}/${pageCount}):`,
|
|
666
|
+
`Runtime scope: ${readiness.threadId ? "current Codex thread" : "account (no bound Codex thread)"}.`,
|
|
667
|
+
...visible.map((app) => {
|
|
668
|
+
const runtime = runtimeById.get(app.id);
|
|
669
|
+
const state = runtime ? `enabled: ${runtime.enabled}; callable: ${runtime.callable}` : readiness.runtime.status === "known" ? "not reported by app/installed" : "runtime flags unavailable";
|
|
670
|
+
return `- ${display(app.name)}: ${state}.`;
|
|
671
|
+
})
|
|
672
|
+
].join("\n")
|
|
673
|
+
});
|
|
674
|
+
if (visible.length > 0) {
|
|
675
|
+
const authorized = new Map(codexPluginAppPageLinks(readiness).map((app) => [app.id, app]));
|
|
676
|
+
const links = visible.flatMap((app) => {
|
|
677
|
+
const link = authorized.get(app.id);
|
|
678
|
+
return link ? [link] : [];
|
|
679
|
+
});
|
|
680
|
+
blocks.push(...buildCodexPluginAppLinks(links, page < pageCount ? { continuationCommand: `/codex plugins status ${readiness.commandId} ${page + 1}` } : {}));
|
|
681
|
+
if (links.length < visible.length) blocks.push({
|
|
682
|
+
type: "text",
|
|
683
|
+
text: "Some app-page permissions are unknown or unavailable. A declared app or setup URL does not establish access. Retry this status command after checking the reported restriction."
|
|
684
|
+
});
|
|
685
|
+
blocks.push({
|
|
686
|
+
type: "text",
|
|
687
|
+
text: "Flags reflect Codex's runtime snapshot; status does not refresh hosted tools. After connecting, /codex plugins refresh refreshes hosted inventory for the current Codex account/runtime, across all apps. Use Check status separately to inspect this plugin without refreshing. OpenClaw app-access changes take effect on your next message; use /new or /reset after connecting."
|
|
688
|
+
});
|
|
689
|
+
blocks.push({
|
|
690
|
+
type: "buttons",
|
|
691
|
+
buttons: [...canRefreshHostedApps ? [{
|
|
692
|
+
label: "Refresh hosted apps",
|
|
693
|
+
action: {
|
|
694
|
+
type: "command",
|
|
695
|
+
command: "/codex plugins refresh"
|
|
696
|
+
}
|
|
697
|
+
}] : [], {
|
|
698
|
+
label: "Check status",
|
|
699
|
+
action: {
|
|
700
|
+
type: "command",
|
|
701
|
+
command: `/codex plugins status ${readiness.commandId}`
|
|
702
|
+
}
|
|
703
|
+
}]
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
const presentation = {
|
|
708
|
+
title: "Codex plugin status",
|
|
709
|
+
blocks
|
|
710
|
+
};
|
|
711
|
+
return {
|
|
712
|
+
text: renderMessagePresentationFallbackText({ presentation }),
|
|
713
|
+
presentation,
|
|
714
|
+
presentationTextMode: "fallback"
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
async function readEvidence(read) {
|
|
718
|
+
try {
|
|
719
|
+
return {
|
|
720
|
+
status: "known",
|
|
721
|
+
value: await read()
|
|
722
|
+
};
|
|
723
|
+
} catch (error) {
|
|
724
|
+
return {
|
|
725
|
+
status: "unavailable",
|
|
726
|
+
reason: error instanceof CodexAppServerRpcError && error.code === -32601 ? "unsupported" : "request_failed"
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
function describeUnavailableEvidence(reason) {
|
|
731
|
+
return reason === "unsupported" ? "This Codex app-server does not support the required status method. Update to OpenClaw's supported Codex version." : "Codex status could not be read. Check Codex sign-in and connectivity, then run this command again.";
|
|
732
|
+
}
|
|
733
|
+
function display(value) {
|
|
734
|
+
return formatCodexDisplayText(value.slice(0, 120));
|
|
735
|
+
}
|
|
736
|
+
function formatBoundAccount(evidence) {
|
|
737
|
+
const account = evidence.status === "known" ? evidence.value.account : void 0;
|
|
738
|
+
if (isJsonObject(account) && account.type === "chatgpt") {
|
|
739
|
+
const email = typeof account.email === "string" ? account.email : "email unknown";
|
|
740
|
+
const plan = typeof account.planType === "string" ? account.planType : "plan unknown";
|
|
741
|
+
return `ChatGPT account: ${formatCodexAccountLine(email.slice(0, 120))} (${display(plan)}).`;
|
|
742
|
+
}
|
|
743
|
+
if (isJsonObject(account) && typeof account.type === "string") return `Account type: ${display(account.type)}; ChatGPT account identity is not available.`;
|
|
744
|
+
return "Codex account: unknown. Check /codex account.";
|
|
745
|
+
}
|
|
746
|
+
//#endregion
|
|
747
|
+
//#region extensions/codex/src/command-apps-refresh.ts
|
|
748
|
+
/** Refreshes hosted app inventory for the current account/runtime. */
|
|
749
|
+
async function refreshCodexHostedApps(context) {
|
|
750
|
+
let account;
|
|
751
|
+
try {
|
|
752
|
+
account = await context.request("account/read", { refreshToken: false });
|
|
753
|
+
const support = await readCodexHostedAppsSupport({ request: context.request }, {
|
|
754
|
+
status: "known",
|
|
755
|
+
value: account
|
|
756
|
+
});
|
|
757
|
+
if (support !== "supported") return { text: `Hosted app inventory was not refreshed. ${describeCodexHostedAppsSupport(support)}` };
|
|
758
|
+
await refreshCodexAppRuntimeState({
|
|
759
|
+
request: context.request,
|
|
760
|
+
appCache: defaultCodexAppInventoryCache,
|
|
761
|
+
appCacheKey: context.appCacheKey
|
|
762
|
+
});
|
|
763
|
+
} catch (error) {
|
|
764
|
+
await context.validateCurrent();
|
|
765
|
+
return { text: `${error instanceof CodexAppServerRpcError && error.code === -32601 ? "This Codex app-server does not support the required app inventory methods. Update the Codex plugin and retry." : (isCodexAppServerIndeterminateRequestCancellationError(error) || isCodexAppServerPrewriteRequestCancellationError(error)) && "reason" in error && error.reason === "aborted" ? "The hosted app refresh was cancelled." : "Hosted app tools could not be refreshed. Check the Codex connection and try again."} Run /codex plugins refresh to retry for the current Codex account/runtime. Previous inventory was not confirmed; no conversation policy was changed.` };
|
|
766
|
+
}
|
|
767
|
+
const presentation = {
|
|
768
|
+
title: "Hosted app refresh",
|
|
769
|
+
blocks: [{
|
|
770
|
+
type: "text",
|
|
771
|
+
text: [
|
|
772
|
+
`Agent: ${formatCodexDisplayText(context.agentId.slice(0, 120))} · Profile: ${formatCodexDisplayText((context.profileId ?? "native Codex account (profile unknown)").slice(0, 120))}`,
|
|
773
|
+
formatBoundAccount({
|
|
774
|
+
status: "known",
|
|
775
|
+
value: account
|
|
776
|
+
}),
|
|
777
|
+
"Hosted app refresh request completed for the current Codex account/runtime, across all hosted apps. Codex does not report whether it replaced its snapshot; this does not verify a live connection. No plugin enablement or conversation policy was changed. Use /new or /reset after connecting."
|
|
778
|
+
].join("\n")
|
|
779
|
+
}, {
|
|
780
|
+
type: "text",
|
|
781
|
+
text: "Use /codex plugins list to find configured plugins, then /codex plugins status <name>@<marketplace> to inspect one."
|
|
782
|
+
}]
|
|
783
|
+
};
|
|
784
|
+
return {
|
|
785
|
+
text: renderMessagePresentationFallbackText({ presentation }),
|
|
786
|
+
presentation,
|
|
787
|
+
presentationTextMode: "fallback"
|
|
788
|
+
};
|
|
789
|
+
}
|
|
339
790
|
//#endregion
|
|
340
791
|
//#region extensions/codex/src/command-diagnostics-state.ts
|
|
341
792
|
/** Runtime state for diagnostics upload throttling and confirmation handshakes. */
|
|
@@ -396,6 +847,10 @@ function buildCodexSubcommandPickerReply() {
|
|
|
396
847
|
label: "account",
|
|
397
848
|
command: "/codex account"
|
|
398
849
|
},
|
|
850
|
+
{
|
|
851
|
+
label: "refresh hosted apps",
|
|
852
|
+
command: "/codex plugins refresh"
|
|
853
|
+
},
|
|
399
854
|
{
|
|
400
855
|
label: "help",
|
|
401
856
|
command: "/codex help"
|
|
@@ -1121,7 +1576,7 @@ async function resolvePreparedCodexCommandAuthority(deps, ctx) {
|
|
|
1121
1576
|
assertCurrent
|
|
1122
1577
|
};
|
|
1123
1578
|
}
|
|
1124
|
-
async function
|
|
1579
|
+
async function resolveCommandAppServerContext(deps, ctx, pluginConfig) {
|
|
1125
1580
|
const authority = await resolvePreparedCodexCommandAuthority(deps, ctx);
|
|
1126
1581
|
const { target, binding } = authority;
|
|
1127
1582
|
const fallback = resolveCodexConversationControlScope(ctx);
|
|
@@ -1131,22 +1586,32 @@ async function resolveCommandAppServerScope(deps, ctx, pluginConfig) {
|
|
|
1131
1586
|
agentDir,
|
|
1132
1587
|
config: ctx.config
|
|
1133
1588
|
});
|
|
1134
|
-
const connection = resolveCodexBindingAppServerConnection({
|
|
1589
|
+
const connection = await resolveCodexBindingAppServerConnection({
|
|
1135
1590
|
binding,
|
|
1136
1591
|
authProfileId,
|
|
1137
|
-
pluginConfig
|
|
1138
|
-
});
|
|
1139
|
-
return {
|
|
1140
|
-
agentId: target?.agentId ?? fallback.agentId,
|
|
1592
|
+
pluginConfig,
|
|
1141
1593
|
agentDir,
|
|
1142
|
-
|
|
1143
|
-
...connection.usesSupervisionConnection ? { startOptions: connection.appServer.start } : {},
|
|
1144
|
-
...authority.sessionKey ? { sessionKey: authority.sessionKey } : {},
|
|
1145
|
-
...authority.sessionId ? { sessionId: authority.sessionId } : {},
|
|
1146
|
-
...authority.storePath ? { storePath: authority.storePath } : {},
|
|
1594
|
+
config: ctx.config,
|
|
1147
1595
|
assertCurrent: authority.assertCurrent
|
|
1596
|
+
});
|
|
1597
|
+
return {
|
|
1598
|
+
scope: {
|
|
1599
|
+
agentId: target?.agentId ?? fallback.agentId,
|
|
1600
|
+
agentDir,
|
|
1601
|
+
...connection.clientAuthProfileId !== void 0 ? { authProfileId: connection.clientAuthProfileId } : {},
|
|
1602
|
+
...connection.usesSupervisionConnection ? { startOptions: connection.appServer.start } : {},
|
|
1603
|
+
...authority.sessionKey ? { sessionKey: authority.sessionKey } : {},
|
|
1604
|
+
...authority.sessionId ? { sessionId: authority.sessionId } : {},
|
|
1605
|
+
...authority.storePath ? { storePath: authority.storePath } : {},
|
|
1606
|
+
assertCurrent: authority.assertCurrent
|
|
1607
|
+
},
|
|
1608
|
+
target,
|
|
1609
|
+
binding
|
|
1148
1610
|
};
|
|
1149
1611
|
}
|
|
1612
|
+
async function resolveCommandAppServerScope(deps, ctx, pluginConfig) {
|
|
1613
|
+
return (await resolveCommandAppServerContext(deps, ctx, pluginConfig)).scope;
|
|
1614
|
+
}
|
|
1150
1615
|
function conversationBindingIdentity(bindingId) {
|
|
1151
1616
|
return {
|
|
1152
1617
|
kind: "conversation",
|
|
@@ -1292,12 +1757,19 @@ async function sendCodexDiagnosticsFeedbackForTargets(deps, ctx, pluginConfig, n
|
|
|
1292
1757
|
const sent = [];
|
|
1293
1758
|
const failed = [];
|
|
1294
1759
|
for (const target of targets) {
|
|
1760
|
+
const assertCurrent = () => {
|
|
1761
|
+
const current = resolvePendingCodexDiagnosticsTargets(deps, [target], ctx.config);
|
|
1762
|
+
if (!codexDiagnosticsTargetsMatch([target], current)) throw new Error("The Codex diagnostics session changed before upload; request it again.");
|
|
1763
|
+
};
|
|
1295
1764
|
let connection;
|
|
1296
1765
|
try {
|
|
1297
|
-
connection = resolveCodexBindingAppServerConnection({
|
|
1766
|
+
connection = await resolveCodexBindingAppServerConnection({
|
|
1298
1767
|
binding: target,
|
|
1299
1768
|
authProfileId: target.authProfileId,
|
|
1300
|
-
pluginConfig
|
|
1769
|
+
pluginConfig,
|
|
1770
|
+
agentDir: target.agentDir,
|
|
1771
|
+
config: ctx.config,
|
|
1772
|
+
assertCurrent
|
|
1301
1773
|
});
|
|
1302
1774
|
} catch (error) {
|
|
1303
1775
|
failed.push({
|
|
@@ -1315,6 +1787,7 @@ async function sendCodexDiagnosticsFeedbackForTargets(deps, ctx, pluginConfig, n
|
|
|
1315
1787
|
}, {
|
|
1316
1788
|
config: ctx.config,
|
|
1317
1789
|
agentDir: target.agentDir,
|
|
1790
|
+
assertCurrent,
|
|
1318
1791
|
...connection.clientAuthProfileId !== void 0 ? { authProfileId: connection.clientAuthProfileId } : {},
|
|
1319
1792
|
...connection.usesSupervisionConnection ? { startOptions: connection.appServer.start } : {},
|
|
1320
1793
|
...target.sessionId ? { sessionId: target.sessionId } : {},
|
|
@@ -1828,10 +2301,13 @@ async function handleNativeGoal(deps, ctx, pluginConfig, args) {
|
|
|
1828
2301
|
const { target, binding } = authority;
|
|
1829
2302
|
if (!target) return "Cannot manage the Codex goal because this command has no stable binding identity.";
|
|
1830
2303
|
if (!binding?.threadId) return "No Codex thread is attached to this OpenClaw session yet.";
|
|
1831
|
-
const connection = resolveCodexBindingAppServerConnection({
|
|
2304
|
+
const connection = await resolveCodexBindingAppServerConnection({
|
|
1832
2305
|
binding,
|
|
1833
2306
|
authProfileId: binding.authProfileId,
|
|
1834
|
-
pluginConfig
|
|
2307
|
+
pluginConfig,
|
|
2308
|
+
agentDir: target.agentDir,
|
|
2309
|
+
config: ctx.config,
|
|
2310
|
+
assertCurrent: authority.assertCurrent
|
|
1835
2311
|
});
|
|
1836
2312
|
const goalRequestOptions = {
|
|
1837
2313
|
agentDir: target.agentDir,
|
|
@@ -1999,10 +2475,13 @@ async function startThreadAction(deps, ctx, pluginConfig, kind, args) {
|
|
|
1999
2475
|
const result = await compactCurrent();
|
|
2000
2476
|
return result.compacted ? `Compacted Codex session (${result.tokensAfter ?? "unknown"} tokens after).` : `Codex compaction did not complete: ${formatCodexDisplayText(result.reason ?? "no reason returned")}.`;
|
|
2001
2477
|
}
|
|
2002
|
-
const connection = resolveCodexBindingAppServerConnection({
|
|
2478
|
+
const connection = await resolveCodexBindingAppServerConnection({
|
|
2003
2479
|
binding,
|
|
2004
2480
|
authProfileId: binding.authProfileId,
|
|
2005
|
-
pluginConfig
|
|
2481
|
+
pluginConfig,
|
|
2482
|
+
agentDir: target.agentDir,
|
|
2483
|
+
config: ctx.config,
|
|
2484
|
+
assertCurrent: authority.assertCurrent
|
|
2006
2485
|
});
|
|
2007
2486
|
await deps.bindingStore.withLease(target.identity, () => deps.codexControlRequest(pluginConfig, CODEX_CONTROL_METHODS.review, {
|
|
2008
2487
|
threadId: binding.threadId,
|
|
@@ -2035,8 +2514,61 @@ function supervisedCommandGuard(deps, identity, binding) {
|
|
|
2035
2514
|
};
|
|
2036
2515
|
}
|
|
2037
2516
|
//#endregion
|
|
2517
|
+
//#region extensions/codex/src/command-plugins-available.ts
|
|
2518
|
+
const AVAILABLE_PAGE_SIZE = 10;
|
|
2519
|
+
function formatCodexAvailablePlugins(plugins, warnings, query, page) {
|
|
2520
|
+
const filtered = filterCodexMarketplacePlugins(plugins, query);
|
|
2521
|
+
const pageCount = Math.max(1, Math.ceil(filtered.length / AVAILABLE_PAGE_SIZE));
|
|
2522
|
+
const start = (page - 1) * AVAILABLE_PAGE_SIZE;
|
|
2523
|
+
const visible = filtered.slice(start, start + AVAILABLE_PAGE_SIZE);
|
|
2524
|
+
const pageCommand = (target) => `/codex plugins available --page ${target}${query ? ` -- '${query.replaceAll("'", "'\\''")}'` : ""}`;
|
|
2525
|
+
const buttons = [];
|
|
2526
|
+
const lines = [];
|
|
2527
|
+
if (filtered.length === 0) lines.push(query ? `No Codex plugins match "${formatCodexDisplayText(query)}" in the returned catalogs. Try a shorter search or browse all plugins.` : "No Codex plugins were discovered for the current workspace.");
|
|
2528
|
+
else if (page > pageCount) {
|
|
2529
|
+
lines.push(`No plugin page ${page}. There are ${filtered.length} results across ${pageCount} pages.`);
|
|
2530
|
+
buttons.push({
|
|
2531
|
+
label: "First page",
|
|
2532
|
+
command: pageCommand(1)
|
|
2533
|
+
});
|
|
2534
|
+
} else {
|
|
2535
|
+
lines.push(`Showing ${start + 1}–${start + visible.length} of ${filtered.length}${query ? ` matches for "${formatCodexDisplayText(query)}"` : " plugins"} (page ${page}/${pageCount}).`);
|
|
2536
|
+
if (page > 1) buttons.push({
|
|
2537
|
+
label: "Previous page",
|
|
2538
|
+
command: pageCommand(page - 1)
|
|
2539
|
+
});
|
|
2540
|
+
if (page < pageCount) buttons.push({
|
|
2541
|
+
label: "Next page",
|
|
2542
|
+
command: pageCommand(page + 1)
|
|
2543
|
+
});
|
|
2544
|
+
lines.push(...visible.map((plugin) => {
|
|
2545
|
+
const state = plugin.installed ? plugin.enabled ? "installed" : "installed, disabled" : plugin.available ? "available" : "unavailable";
|
|
2546
|
+
const title = plugin.displayName ? `${formatCodexDisplayText(plugin.displayName)} — ` : "";
|
|
2547
|
+
const publisher = plugin.developerName ? formatCodexDisplayText(plugin.developerName) : "Not provided";
|
|
2548
|
+
const description = plugin.description ? formatCodexDisplayText(plugin.description) : "No description provided.";
|
|
2549
|
+
return `- ${title}${plugin.id} (${state})\n Publisher: ${publisher}. ${description}`;
|
|
2550
|
+
}));
|
|
2551
|
+
}
|
|
2552
|
+
lines.push(...warnings.map((warning) => `Warning: ${formatCodexDisplayText(warning)}`), "Search names, titles, publishers, marketplaces, or descriptions: /codex plugins available <query>", "To authorize one plugin, an owner or operator.admin must send:", "/codex plugins install <plugin>@<marketplace>");
|
|
2553
|
+
if (query) buttons.push({
|
|
2554
|
+
label: "Browse all plugins",
|
|
2555
|
+
command: "/codex plugins available"
|
|
2556
|
+
});
|
|
2557
|
+
buttons.push({
|
|
2558
|
+
label: "Plugin controls",
|
|
2559
|
+
command: "/codex plugins menu"
|
|
2560
|
+
});
|
|
2561
|
+
const presentation = buildCodexCommandPickerPresentation("Discoverable Codex plugins", lines.join("\n"), buttons);
|
|
2562
|
+
return {
|
|
2563
|
+
text: renderMessagePresentationFallbackText({ presentation }),
|
|
2564
|
+
presentation,
|
|
2565
|
+
presentationTextMode: "fallback"
|
|
2566
|
+
};
|
|
2567
|
+
}
|
|
2568
|
+
//#endregion
|
|
2038
2569
|
//#region extensions/codex/src/command-plugins-management.ts
|
|
2039
2570
|
const POLICY_REFRESH_HINT = "Takes effect on your next message.";
|
|
2571
|
+
const AVAILABLE_USAGE = "Usage: /codex plugins available [query] [--page <positive integer>]. Search text must be at most 100 characters; use -- before literal query text that contains options.";
|
|
2040
2572
|
async function handleCodexPluginsSubcommand(ctx, rest, io, runtime) {
|
|
2041
2573
|
const [verb = "list", ...args] = rest;
|
|
2042
2574
|
const normalized = verb.toLowerCase();
|
|
@@ -2054,19 +2586,51 @@ async function handleCodexPluginsSubcommand(ctx, rest, io, runtime) {
|
|
|
2054
2586
|
return { text: formatPluginList(current.plugins ?? {}, { globalEnabled: current.enabled === true }) };
|
|
2055
2587
|
}
|
|
2056
2588
|
if (normalized === "available") {
|
|
2057
|
-
if (args.length > 0) return { text: "Usage: /codex plugins available" };
|
|
2058
2589
|
if (!canMutateCodexHost(ctx)) return { text: "Only an owner or operator.admin gateway client can list available Codex plugins." };
|
|
2590
|
+
let page = 1;
|
|
2591
|
+
const queryParts = [];
|
|
2592
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
2593
|
+
const arg = expectDefined(args[index], "current Codex plugin search argument");
|
|
2594
|
+
if (arg === "--") {
|
|
2595
|
+
queryParts.push(...args.slice(index + 1));
|
|
2596
|
+
break;
|
|
2597
|
+
}
|
|
2598
|
+
if (arg === "--page") {
|
|
2599
|
+
const parsedPage = parseStrictPositiveInteger(args[++index]);
|
|
2600
|
+
if (parsedPage === void 0) return { text: AVAILABLE_USAGE };
|
|
2601
|
+
page = parsedPage;
|
|
2602
|
+
} else queryParts.push(arg);
|
|
2603
|
+
}
|
|
2604
|
+
const query = queryParts.join(" ").trim();
|
|
2605
|
+
if (query.length > 100) return { text: AVAILABLE_USAGE };
|
|
2059
2606
|
if (!runtime) return { text: "Codex plugin discovery is unavailable for this command." };
|
|
2060
2607
|
try {
|
|
2061
2608
|
const discovered = await discoverCodexMarketplacePlugins({
|
|
2062
2609
|
request: runtime.list,
|
|
2063
2610
|
workspaceDir: await runtime.workspaceDir()
|
|
2064
2611
|
});
|
|
2065
|
-
return
|
|
2612
|
+
return formatCodexAvailablePlugins(discovered.plugins, discovered.warnings, query, page);
|
|
2066
2613
|
} catch (error) {
|
|
2067
2614
|
return { text: `Could not list Codex plugins: ${formatCodexDisplayText(errorMessage(error))}` };
|
|
2068
2615
|
}
|
|
2069
2616
|
}
|
|
2617
|
+
if (normalized === "status") {
|
|
2618
|
+
const requestedPlugin = args[0];
|
|
2619
|
+
const page = args[1] === void 0 ? 1 : Number(args[1]);
|
|
2620
|
+
if (!requestedPlugin || !parseCodexPluginMarketplaceId(requestedPlugin) || args.length > 2 || !Number.isSafeInteger(page) || page < 1) return { text: "Usage: /codex plugins status <name>@<marketplace> [page]. Use /codex plugins list to find a configured plugin." };
|
|
2621
|
+
if (!canMutateCodexHost(ctx)) return { text: "Only an owner or operator.admin gateway client can run /codex plugins status." };
|
|
2622
|
+
if (!runtime?.withContext) return { text: "Codex plugin status is unavailable. Check the configured Codex app-server, then run this command again." };
|
|
2623
|
+
return await runtime.withContext(async (context) => {
|
|
2624
|
+
const configured = resolveConfiguredPluginKey(context.current.plugins ?? {}, requestedPlugin);
|
|
2625
|
+
if (configured.status === "ambiguous" || configured.status === "mismatched") return { text: describeConfiguredPluginIdentityConflict(requestedPlugin, configured.status) };
|
|
2626
|
+
if (configured.status === "missing") return { text: "This plugin is not explicitly configured. Use /codex plugins list, or /codex plugins available to find an install command." };
|
|
2627
|
+
return formatCodexPluginReadiness(await readCodexPluginReadiness({
|
|
2628
|
+
context,
|
|
2629
|
+
current: context.current,
|
|
2630
|
+
configKey: configured.configKey
|
|
2631
|
+
}), page);
|
|
2632
|
+
});
|
|
2633
|
+
}
|
|
2070
2634
|
if (normalized === "install") {
|
|
2071
2635
|
if (args.length !== 1 || !args[0]) return { text: "Usage: /codex plugins install <plugin>@<marketplace>" };
|
|
2072
2636
|
if (!canMutateCodexHost(ctx)) return { text: "Only an owner or operator.admin gateway client can run /codex plugins install." };
|
|
@@ -2108,9 +2672,11 @@ function buildPluginsMenuReply() {
|
|
|
2108
2672
|
"",
|
|
2109
2673
|
" 1. /codex plugins list",
|
|
2110
2674
|
" 2. /codex plugins available",
|
|
2111
|
-
" 3. /codex plugins
|
|
2112
|
-
" 4. /codex plugins
|
|
2113
|
-
" 5. /codex plugins
|
|
2675
|
+
" 3. /codex plugins status <name>@<marketplace>",
|
|
2676
|
+
" 4. /codex plugins refresh — refresh hosted apps",
|
|
2677
|
+
" 5. /codex plugins enable",
|
|
2678
|
+
" 6. /codex plugins disable",
|
|
2679
|
+
" 7. /codex plugins help",
|
|
2114
2680
|
"",
|
|
2115
2681
|
"Type '/codex' to go back to the main menu."
|
|
2116
2682
|
].join("\n"),
|
|
@@ -2123,6 +2689,10 @@ function buildPluginsMenuReply() {
|
|
|
2123
2689
|
label: "available",
|
|
2124
2690
|
command: "/codex plugins available"
|
|
2125
2691
|
},
|
|
2692
|
+
{
|
|
2693
|
+
label: "Refresh hosted apps",
|
|
2694
|
+
command: "/codex plugins refresh"
|
|
2695
|
+
},
|
|
2126
2696
|
{
|
|
2127
2697
|
label: "enable",
|
|
2128
2698
|
command: "/codex plugins enable"
|
|
@@ -2187,16 +2757,18 @@ function buildPluginsHelp() {
|
|
|
2187
2757
|
"Codex plugin discovery and owner-approved installation:",
|
|
2188
2758
|
"- /codex plugins (alias for list)",
|
|
2189
2759
|
"- /codex plugins list show explicitly configured plugins",
|
|
2190
|
-
"- /codex plugins available
|
|
2760
|
+
"- /codex plugins available [query] [--page <n>] search or browse Codex plugins",
|
|
2761
|
+
"- /codex plugins status <name>@<marketplace> [page] inspect app readiness without refreshing",
|
|
2762
|
+
"- /codex plugins refresh refresh all hosted apps for the current Codex account/runtime",
|
|
2191
2763
|
"- /codex plugins install <name>@<marketplace> install and authorize one plugin",
|
|
2192
2764
|
"- /codex plugins enable <name> enable a configured plugin",
|
|
2193
2765
|
"- /codex plugins disable <name> disable a configured plugin",
|
|
2194
|
-
"Only an owner or operator.admin can discover, install, enable, or disable plugins."
|
|
2766
|
+
"Only an owner or operator.admin can discover, inspect, refresh hosted apps, install, enable, or disable plugins."
|
|
2195
2767
|
].join("\n");
|
|
2196
2768
|
}
|
|
2197
2769
|
async function installCodexPlugin(requestedId, io, runtime) {
|
|
2198
2770
|
const requested = parseCodexPluginMarketplaceId(requestedId);
|
|
2199
|
-
if (!requested) return { text: "Invalid plugin identifier. Use /codex plugins install <plugin>@<marketplace
|
|
2771
|
+
if (!requested) return { text: "Invalid plugin identifier. Use /codex plugins install <plugin>@<marketplace>. Both names allow ASCII letters, digits, underscores, and hyphens. Plugin names may also contain dots between nonempty segments." };
|
|
2200
2772
|
let plugin;
|
|
2201
2773
|
let workspaceDir;
|
|
2202
2774
|
try {
|
|
@@ -2271,104 +2843,64 @@ async function installCodexPlugin(requestedId, io, runtime) {
|
|
|
2271
2843
|
}
|
|
2272
2844
|
const appsNeedingAuth = result?.appsNeedingAuth ?? [];
|
|
2273
2845
|
if (appsNeedingAuth.length > 0) {
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
}
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2846
|
+
let appLinks = [];
|
|
2847
|
+
if (runtime.withContext) try {
|
|
2848
|
+
appLinks = await runtime.withContext(async (context) => {
|
|
2849
|
+
const configured = resolveConfiguredPluginKey(context.current.plugins ?? {}, requestedId);
|
|
2850
|
+
if (configured.status !== "matched") return [];
|
|
2851
|
+
const readiness = await readCodexPluginReadiness({
|
|
2852
|
+
context,
|
|
2853
|
+
current: context.current,
|
|
2854
|
+
configKey: configured.configKey
|
|
2855
|
+
});
|
|
2856
|
+
const pendingIds = new Set(appsNeedingAuth.map((app) => app.id));
|
|
2857
|
+
return codexPluginAppPageLinks(readiness).filter((app) => pendingIds.has(app.id));
|
|
2858
|
+
});
|
|
2859
|
+
} catch {}
|
|
2860
|
+
const authRequirement = appsNeedingAuth.length === 1 ? "1 app still requires" : `${appsNeedingAuth.length} apps still require`;
|
|
2861
|
+
const presentation = {
|
|
2862
|
+
title: "Codex plugin app setup",
|
|
2863
|
+
tone: "warning",
|
|
2864
|
+
blocks: [
|
|
2865
|
+
{
|
|
2866
|
+
type: "text",
|
|
2867
|
+
text: `${formatCodexDisplayText(requestedId)} bundle was installed in Codex. OpenClaw app access is configured. ${authRequirement} connector authentication in ChatGPT. Installation does not confirm app connections or current-conversation readiness.`
|
|
2868
|
+
},
|
|
2869
|
+
...buildCodexPluginAppLinks(appLinks),
|
|
2870
|
+
...appLinks.length < appsNeedingAuth.length ? [{
|
|
2871
|
+
type: "text",
|
|
2872
|
+
text: `Some app setup permissions could not be confirmed. Run /codex plugins status ${requestedId} to check the current account and restrictions.`
|
|
2873
|
+
}] : [],
|
|
2874
|
+
{
|
|
2875
|
+
type: "buttons",
|
|
2876
|
+
buttons: [...appLinks.length > 0 ? [{
|
|
2877
|
+
label: "Refresh hosted apps",
|
|
2878
|
+
action: {
|
|
2879
|
+
type: "command",
|
|
2880
|
+
command: "/codex plugins refresh"
|
|
2881
|
+
}
|
|
2882
|
+
}] : [], {
|
|
2883
|
+
label: "Check status",
|
|
2884
|
+
action: {
|
|
2885
|
+
type: "command",
|
|
2886
|
+
command: `/codex plugins status ${requestedId}`
|
|
2887
|
+
}
|
|
2888
|
+
}]
|
|
2889
|
+
},
|
|
2890
|
+
{
|
|
2891
|
+
type: "context",
|
|
2892
|
+
text: `${refreshWarning.trim()} ${POLICY_REFRESH_HINT}`.trim()
|
|
2893
|
+
}
|
|
2894
|
+
]
|
|
2310
2895
|
};
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
return Object.values(plugins).filter((entry) => matchesConfiguredPluginIdentity(entry, identity, canonicalId)).length > 1 ? { status: "ambiguous" } : {
|
|
2316
|
-
status: "matched",
|
|
2317
|
-
configKey: target
|
|
2896
|
+
return {
|
|
2897
|
+
text: renderMessagePresentationFallbackText({ presentation }),
|
|
2898
|
+
presentation,
|
|
2899
|
+
presentationTextMode: "fallback"
|
|
2318
2900
|
};
|
|
2319
2901
|
}
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
if (matching.length > 1) return { status: "ambiguous" };
|
|
2323
|
-
const configKey = matching[0]?.[0];
|
|
2324
|
-
return configKey ? {
|
|
2325
|
-
status: "matched",
|
|
2326
|
-
configKey
|
|
2327
|
-
} : { status: "missing" };
|
|
2328
|
-
}
|
|
2329
|
-
function resolveInstalledPluginKey(plugins, plugin) {
|
|
2330
|
-
const discovered = resolveConfiguredPluginKey(plugins, plugin.id);
|
|
2331
|
-
if (discovered.status === "ambiguous" || discovered.status === "mismatched") return discovered;
|
|
2332
|
-
if (!isOpenAiCuratedMarketplaceName(plugin.marketplaceName)) return discovered;
|
|
2333
|
-
const canonical = resolveConfiguredPluginKey(plugins, `${plugin.pluginName}@${CODEX_PLUGINS_MARKETPLACE_NAME}`);
|
|
2334
|
-
if (canonical.status === "ambiguous" || canonical.status === "mismatched") return canonical;
|
|
2335
|
-
if (discovered.status === "matched" && canonical.status === "matched" && discovered.configKey !== canonical.configKey) return { status: "ambiguous" };
|
|
2336
|
-
return canonical.status === "matched" ? canonical : discovered;
|
|
2337
|
-
}
|
|
2338
|
-
function resolveConfiguredPluginIdentity(entry) {
|
|
2339
|
-
if (!entry.pluginName || !entry.marketplaceName) return;
|
|
2340
|
-
const qualified = parseCodexPluginMarketplaceId(entry.pluginName);
|
|
2341
|
-
if (qualified) return marketplaceNamesRepresentSameCatalog(qualified.marketplaceName, entry.marketplaceName) ? {
|
|
2342
|
-
pluginName: qualified.pluginName,
|
|
2343
|
-
marketplaceName: entry.marketplaceName
|
|
2344
|
-
} : void 0;
|
|
2345
|
-
return parseCodexPluginMarketplaceId(`${entry.pluginName}@${entry.marketplaceName}`);
|
|
2346
|
-
}
|
|
2347
|
-
function matchesConfiguredPluginIdentity(entry, requested, target) {
|
|
2348
|
-
const configuredName = entry.pluginName ? parseCodexPluginMarketplaceId(entry.pluginName) : void 0;
|
|
2349
|
-
return typeof entry.marketplaceName === "string" && marketplaceNamesRepresentSameCatalog(entry.marketplaceName, requested.marketplaceName) && (entry.pluginName === requested.pluginName || entry.pluginName === target || configuredName?.pluginName === requested.pluginName && marketplaceNamesRepresentSameCatalog(configuredName.marketplaceName, requested.marketplaceName));
|
|
2350
|
-
}
|
|
2351
|
-
function marketplaceNamesRepresentSameCatalog(left, right) {
|
|
2352
|
-
return left === right || isOpenAiCuratedMarketplaceName(left) && isOpenAiCuratedMarketplaceName(right);
|
|
2353
|
-
}
|
|
2354
|
-
function describeConfiguredPluginIdentityConflict(target, status) {
|
|
2355
|
-
const identity = formatCodexDisplayText(target);
|
|
2356
|
-
return status === "ambiguous" ? `Multiple configured Codex plugins match '${identity}'; resolve duplicate plugin policies first.` : `Configured Codex plugin key '${identity}' points to a different plugin identity; resolve the configuration conflict first.`;
|
|
2357
|
-
}
|
|
2358
|
-
function formatAvailablePlugins(plugins, warnings) {
|
|
2359
|
-
if (plugins.length === 0) return ["No Codex plugins were discovered for the current workspace.", ...warnings.map((warning) => `Warning: ${formatCodexDisplayText(warning)}`)].join("\n");
|
|
2360
|
-
return [
|
|
2361
|
-
"Discoverable Codex plugins:",
|
|
2362
|
-
...plugins.slice(0, 30).map((plugin) => {
|
|
2363
|
-
const state = plugin.installed ? plugin.enabled ? "installed" : "installed, disabled" : plugin.available ? "available" : "unavailable";
|
|
2364
|
-
const description = plugin.description ? ` - ${formatCodexDisplayText(plugin.description)}` : "";
|
|
2365
|
-
return `- ${plugin.id} (${state})${description}`;
|
|
2366
|
-
}),
|
|
2367
|
-
...plugins.length > 30 ? ["- Additional plugins omitted."] : [],
|
|
2368
|
-
...warnings.map((warning) => `Warning: ${formatCodexDisplayText(warning)}`),
|
|
2369
|
-
"To authorize one plugin, an owner or operator.admin must send:",
|
|
2370
|
-
"/codex plugins install <plugin>@<marketplace>"
|
|
2371
|
-
].join("\n");
|
|
2902
|
+
const status = alreadyInstalled ? "bundle was already installed in Codex" : "bundle was installed in Codex";
|
|
2903
|
+
return { text: `${formatCodexDisplayText(requestedId)} ${status}. OpenClaw app access is configured.${refreshWarning} ${POLICY_REFRESH_HINT}` };
|
|
2372
2904
|
}
|
|
2373
2905
|
function errorMessage(error) {
|
|
2374
2906
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -2395,10 +2927,124 @@ function formatPluginList(plugins, options = {}) {
|
|
|
2395
2927
|
...rows.map((r) => ` ${r.state} ${r.displayKey.padEnd(keyW)} ${r.pluginName.padEnd(pluginW)} [${r.marketplace}]`),
|
|
2396
2928
|
"",
|
|
2397
2929
|
...globalEnabled ? [] : ["Global codexPlugins.enabled is off; configured sub-plugins are inactive.", ""],
|
|
2930
|
+
"Inspect one configured plugin: /codex plugins status <name>@<marketplace> [page].",
|
|
2398
2931
|
POLICY_REFRESH_HINT
|
|
2399
2932
|
].join("\n");
|
|
2400
2933
|
}
|
|
2401
2934
|
//#endregion
|
|
2935
|
+
//#region extensions/codex/src/command-plugins-runtime.ts
|
|
2936
|
+
const SCOPE_CHANGED_MESSAGE = "Codex account, conversation, or plugin policy changed. Run the command again.";
|
|
2937
|
+
async function withCodexPluginCommandContext(params, run) {
|
|
2938
|
+
const { deps, ctx, pluginConfig } = params;
|
|
2939
|
+
const current = await deps.codexPluginsManagementIo?.readConfig() ?? {};
|
|
2940
|
+
const initialPolicy = JSON.stringify(current);
|
|
2941
|
+
const { scope, target, binding } = await resolveCommandAppServerContext(deps, ctx, pluginConfig);
|
|
2942
|
+
const conversation = readCodexConversationBindingData(await ctx.getCurrentConversationBinding());
|
|
2943
|
+
const workspaceDir = binding?.cwd || (conversation?.kind === "codex-app-server-session" ? conversation.workspaceDir : void 0) || resolveAgentWorkspaceDir(ctx.config, scope.agentId);
|
|
2944
|
+
const configuredRuntime = resolveCodexAppServerRuntimeOptions({ pluginConfig });
|
|
2945
|
+
const appServer = scope.startOptions ? {
|
|
2946
|
+
...configuredRuntime,
|
|
2947
|
+
start: scope.startOptions
|
|
2948
|
+
} : configuredRuntime;
|
|
2949
|
+
const auth = await prepareCodexControlSessionAuth({
|
|
2950
|
+
...scope,
|
|
2951
|
+
config: ctx.config
|
|
2952
|
+
}, appServer.start);
|
|
2953
|
+
const preparedAuth = "preparedAuth" in auth.clientOptions ? auth.clientOptions.preparedAuth : void 0;
|
|
2954
|
+
const usesNativeAuth = scope.authProfileId === null || appServer.start.homeScope === "user";
|
|
2955
|
+
const profileId = usesNativeAuth ? void 0 : auth.authProfileId;
|
|
2956
|
+
const readAuthBinding = () => profileId ? fingerprintCodexAppServerAuthBinding({
|
|
2957
|
+
authProfileId: profileId,
|
|
2958
|
+
authProfileStore: resolveCodexAppServerAuthProfileStore({
|
|
2959
|
+
authProfileId: profileId,
|
|
2960
|
+
agentDir: scope.agentDir,
|
|
2961
|
+
config: ctx.config
|
|
2962
|
+
}),
|
|
2963
|
+
agentDir: scope.agentDir,
|
|
2964
|
+
config: ctx.config
|
|
2965
|
+
}) : Promise.resolve(void 0);
|
|
2966
|
+
const authBinding = "authBindingFingerprint" in auth.clientOptions ? auth.clientOptions.authBindingFingerprint : await readAuthBinding();
|
|
2967
|
+
const accountId = usesNativeAuth ? void 0 : preparedAuth?.kind === "api-key" ? resolveCodexAppServerPreparedApiKeyCacheKey(preparedAuth.apiKey) : preparedAuth?.kind === "profile" ? preparedAuth.snapshot.secretFreeCacheKey : await resolveCodexAppServerAuthAccountCacheKey({
|
|
2968
|
+
authProfileId: profileId,
|
|
2969
|
+
agentDir: scope.agentDir,
|
|
2970
|
+
config: ctx.config
|
|
2971
|
+
});
|
|
2972
|
+
if (await readAuthBinding() !== authBinding) throw new Error(SCOPE_CHANGED_MESSAGE);
|
|
2973
|
+
return await withCodexAppServerJsonClient({
|
|
2974
|
+
startOptions: appServer.start,
|
|
2975
|
+
pluginConfig,
|
|
2976
|
+
agentDir: scope.agentDir,
|
|
2977
|
+
config: ctx.config,
|
|
2978
|
+
sessionId: ctx.sessionId,
|
|
2979
|
+
sessionKey: ctx.sessionKey,
|
|
2980
|
+
timeoutMs: appServer.requestTimeoutMs,
|
|
2981
|
+
timeoutMessage: "Codex plugin request timed out. Check the Codex connection and retry.",
|
|
2982
|
+
assertCurrent: scope.assertCurrent,
|
|
2983
|
+
...auth.clientOptions
|
|
2984
|
+
}, async (request, client, requestScope) => {
|
|
2985
|
+
const assertCurrent = () => {
|
|
2986
|
+
requestScope.assertCurrent();
|
|
2987
|
+
if (client.getCloseError()) throw new Error(SCOPE_CHANGED_MESSAGE);
|
|
2988
|
+
};
|
|
2989
|
+
const validateCurrent = async () => {
|
|
2990
|
+
assertCurrent();
|
|
2991
|
+
const currentTarget = await resolveControlTarget(ctx);
|
|
2992
|
+
const currentConversation = readCodexConversationBindingData(await ctx.getCurrentConversationBinding());
|
|
2993
|
+
const currentPolicy = JSON.stringify(await deps.codexPluginsManagementIo?.readConfig() ?? {});
|
|
2994
|
+
const currentAuthBinding = await readAuthBinding();
|
|
2995
|
+
assertCurrent();
|
|
2996
|
+
if (!isDeepStrictEqual(currentTarget, target) || !isDeepStrictEqual(currentConversation, conversation) || currentPolicy !== initialPolicy || currentAuthBinding !== authBinding) throw new Error(SCOPE_CHANGED_MESSAGE);
|
|
2997
|
+
};
|
|
2998
|
+
try {
|
|
2999
|
+
await request({
|
|
3000
|
+
method: "account/read",
|
|
3001
|
+
requestParams: { refreshToken: false },
|
|
3002
|
+
assertCurrent
|
|
3003
|
+
});
|
|
3004
|
+
} catch {
|
|
3005
|
+
requestScope.assertCurrent();
|
|
3006
|
+
throw new Error("Codex account startup could not be confirmed. Check /codex account and retry.");
|
|
3007
|
+
}
|
|
3008
|
+
const unsubscribe = client.addNotificationHandler((notification) => {
|
|
3009
|
+
if (notification.method === "account/updated") requestScope.abort(/* @__PURE__ */ new Error(SCOPE_CHANGED_MESSAGE));
|
|
3010
|
+
});
|
|
3011
|
+
try {
|
|
3012
|
+
await validateCurrent();
|
|
3013
|
+
const result = await run({
|
|
3014
|
+
request: async (method, requestParams) => {
|
|
3015
|
+
await validateCurrent();
|
|
3016
|
+
const response = await request({
|
|
3017
|
+
method,
|
|
3018
|
+
requestParams,
|
|
3019
|
+
assertCurrent
|
|
3020
|
+
});
|
|
3021
|
+
await validateCurrent();
|
|
3022
|
+
return response;
|
|
3023
|
+
},
|
|
3024
|
+
workspaceDir,
|
|
3025
|
+
agentId: scope.agentId,
|
|
3026
|
+
current,
|
|
3027
|
+
...profileId ? { profileId } : {},
|
|
3028
|
+
...binding?.clientId === client.getInstanceId() ? { threadId: binding.threadId } : {},
|
|
3029
|
+
appCacheKey: buildCodexPluginAppCacheKey({
|
|
3030
|
+
appServer,
|
|
3031
|
+
agentDir: scope.agentDir,
|
|
3032
|
+
authProfileId: profileId,
|
|
3033
|
+
accountId,
|
|
3034
|
+
envApiKeyFingerprint: usesNativeAuth || preparedAuth || profileId ? void 0 : resolveCodexAppServerFallbackApiKeyCacheKey({ startOptions: appServer.start }),
|
|
3035
|
+
appServerVersion: client.getServerVersion(),
|
|
3036
|
+
runtimeIdentity: client.getRuntimeIdentity()
|
|
3037
|
+
}),
|
|
3038
|
+
validateCurrent
|
|
3039
|
+
});
|
|
3040
|
+
await validateCurrent();
|
|
3041
|
+
return result;
|
|
3042
|
+
} finally {
|
|
3043
|
+
unsubscribe();
|
|
3044
|
+
}
|
|
3045
|
+
});
|
|
3046
|
+
}
|
|
3047
|
+
//#endregion
|
|
2402
3048
|
//#region extensions/codex/src/command-handlers.ts
|
|
2403
3049
|
const CODEX_HOST_INSPECTION_SUBCOMMANDS = /* @__PURE__ */ new Set([
|
|
2404
3050
|
"account",
|
|
@@ -2420,10 +3066,24 @@ async function handleCodexSubcommand(ctx, options) {
|
|
|
2420
3066
|
const sandboxBlock = resolveCodexNativeCommandSandboxBlock(ctx, normalized, rest);
|
|
2421
3067
|
if (sandboxBlock) return { text: sandboxBlock };
|
|
2422
3068
|
if (normalized === "plugins") {
|
|
3069
|
+
if (rest[0]?.toLowerCase() === "refresh") {
|
|
3070
|
+
if (rest.length !== 1) return { text: "Usage: /codex plugins refresh — refresh hosted app inventory for the current Codex account/runtime." };
|
|
3071
|
+
if (!canMutateCodexHost(ctx)) return { text: "Only an owner or operator.admin gateway client can refresh hosted app inventory." };
|
|
3072
|
+
return await withCodexPluginCommandContext({
|
|
3073
|
+
deps,
|
|
3074
|
+
ctx,
|
|
3075
|
+
pluginConfig: options.pluginConfig
|
|
3076
|
+
}, (context) => refreshCodexHostedApps(context));
|
|
3077
|
+
}
|
|
2423
3078
|
if (!deps.codexPluginsManagementIo) return { text: "Codex sub-plugin management is not wired up (codexPluginsManagementIo dep is undefined). Edit ~/.openclaw/openclaw.json or use `openclaw config patch` until the runtime exposes the IO." };
|
|
2424
3079
|
let appServerScope;
|
|
2425
3080
|
const getAppServerScope = () => appServerScope ??= resolveCommandAppServerScope(deps, ctx, options.pluginConfig);
|
|
2426
3081
|
return await handleCodexPluginsSubcommand(ctx, rest, deps.codexPluginsManagementIo, {
|
|
3082
|
+
withContext: (run) => withCodexPluginCommandContext({
|
|
3083
|
+
deps,
|
|
3084
|
+
ctx,
|
|
3085
|
+
pluginConfig: options.pluginConfig
|
|
3086
|
+
}, run),
|
|
2427
3087
|
workspaceDir: async () => {
|
|
2428
3088
|
const data = readCodexConversationBindingData(await ctx.getCurrentConversationBinding());
|
|
2429
3089
|
return (data?.kind === "codex-app-server-session" ? data.workspaceDir : void 0)?.trim() || deps.resolveCodexDefaultWorkspaceDir(options.pluginConfig);
|