@bitkyc08/opencodex 2.80.0 → 2.82.0
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 +3 -3
- package/bin/ocx.mjs +166 -73
- package/gui/dist/assets/App-Ds_qL7o8.js +54 -0
- package/gui/dist/assets/Tray-BqHF5Trd.js +1 -0
- package/gui/dist/assets/{index-Brk6F3fn.css → index-BAbcj51J.css} +1 -1
- package/gui/dist/assets/index-D3FBCNiP.js +94 -0
- package/gui/dist/assets/quota-summary-DTBC8n7-.js +1 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/claude-green.svg +1 -0
- package/package.json +3 -2
- package/src/adapters/anthropic-model-contract.ts +8 -2
- package/src/adapters/anthropic.ts +8 -3
- package/src/adapters/codebuddy/mcp-server.ts +2 -25
- package/src/adapters/codebuddy/tool-bridge.ts +1 -7
- package/src/adapters/coding-agent/mcp-server.ts +33 -0
- package/src/adapters/coding-agent/protocol.ts +122 -17
- package/src/adapters/coding-agent/tool-catalog.ts +75 -0
- package/src/adapters/coding-agent/turn.ts +101 -44
- package/src/adapters/cursor/catalog.ts +8 -0
- package/src/adapters/cursor/effort-map.ts +2 -0
- package/src/adapters/devin/live-models.ts +2 -0
- package/src/adapters/kiro-retry.ts +9 -4
- package/src/adapters/openai-chat/messages.ts +7 -6
- package/src/adapters/openai-responses/compaction-search-history.ts +109 -0
- package/src/adapters/openai-responses/passthrough.ts +9 -4
- package/src/adapters/openai-responses/tool-output-recovery.ts +20 -0
- package/src/adapters/physical-send.ts +8 -5
- package/src/adapters/qoder/adapter.ts +41 -6
- package/src/adapters/qoder/scaffold-guard.ts +2 -3
- package/src/adapters/zed.ts +16 -1
- package/src/claude/agents-inject.ts +14 -3
- package/src/claude/context-windows.ts +19 -17
- package/src/claude/desktop-3p.ts +88 -12
- package/src/claude/desktop-profile.ts +2 -1
- package/src/claude/gateway-cache.ts +18 -1
- package/src/claude/inbound-cache-stabilize.ts +4 -9
- package/src/claude/inbound.ts +78 -3
- package/src/claude/intercept/cli-catalog.ts +3 -0
- package/src/claude/intercept/model-bindings.ts +1 -0
- package/src/claude/intercept/picker-ca-persistence.ts +7 -6
- package/src/claude/intercept/picker-listener.ts +71 -4
- package/src/claude/intercept/picker-models.ts +14 -6
- package/src/claude/intercept/settings.ts +3 -0
- package/src/claude/long-context.ts +66 -0
- package/src/claude/model-info.ts +19 -16
- package/src/claude/outbound.ts +94 -9
- package/src/claude/subagent-model.ts +40 -11
- package/src/cli/account-anthropic-threshold.ts +14 -5
- package/src/cli/account-api.ts +3 -1
- package/src/cli/account-extended.ts +13 -9
- package/src/cli/account-policy-dto.ts +1 -1
- package/src/cli/account-policy.ts +13 -4
- package/src/cli/account.ts +3 -3
- package/src/cli/agent.ts +9 -5
- package/src/cli/aside-profile-recovery.ts +33 -0
- package/src/cli/capabilities-accounts.ts +2 -2
- package/src/cli/capabilities-agents-routing.ts +24 -0
- package/src/cli/capabilities-base.ts +5 -5
- package/src/cli/capabilities-integrations.ts +18 -2
- package/src/cli/cli-path-diagnostics.ts +132 -0
- package/src/cli/codex-shim-autorestore.ts +3 -0
- package/src/cli/desktop-runtime-guidance.ts +65 -0
- package/src/cli/dispatch.ts +15 -1
- package/src/cli/doctor.ts +16 -3
- package/src/cli/help.ts +4 -1
- package/src/cli/index.ts +25 -14
- package/src/cli/integration-aside-sync.ts +2 -1
- package/src/cli/integration-plan-dto.ts +1 -0
- package/src/cli/integration-preview.ts +8 -1
- package/src/cli/integrations.ts +48 -6
- package/src/cli/message-args.ts +34 -0
- package/src/cli/message-command.ts +43 -0
- package/src/cli/message-runtime.ts +6 -0
- package/src/cli/observe.ts +3 -1
- package/src/cli/provider.ts +29 -6
- package/src/cli/registry.ts +24 -2
- package/src/cli/resolve.ts +25 -2
- package/src/cli/root.ts +4 -2
- package/src/cli/status.ts +64 -12
- package/src/cli/update-restart-child.ts +4 -2
- package/src/cli/update-restart-home.ts +28 -10
- package/src/cli/update-restart-service-record.ts +116 -0
- package/src/cli/update-restart-supervision.ts +96 -0
- package/src/cli/update-restart.ts +59 -13
- package/src/cli/v2.ts +27 -20
- package/src/cli/version-skew-notice.ts +77 -0
- package/src/clients/config-export/commandcode.ts +131 -0
- package/src/clients/config-export/contracts.ts +12 -0
- package/src/clients/config-export.ts +64 -1
- package/src/clients/lazycodex.ts +1 -1
- package/src/clients/omo-role-models.ts +32 -7
- package/src/codex/auth-api/account-list.ts +11 -3
- package/src/codex/auth-api/account-selection.ts +107 -0
- package/src/codex/auth-api/main-account-probe.ts +25 -8
- package/src/codex/auth-api/pool-mode-gate.ts +33 -9
- package/src/codex/auth-api/pool-quota-probe.ts +15 -1
- package/src/codex/auth-api/routes.ts +11 -49
- package/src/codex/auth-context.ts +20 -1
- package/src/codex/autostart-health.ts +12 -3
- package/src/codex/catalog/auto-review.ts +13 -6
- package/src/codex/catalog/build-entries.ts +33 -7
- package/src/codex/catalog/bundled.ts +155 -26
- package/src/codex/catalog/combo-member.ts +3 -2
- package/src/codex/catalog/control-plane.ts +45 -0
- package/src/codex/catalog/effort.ts +37 -6
- package/src/codex/catalog/gather-capture.ts +10 -3
- package/src/codex/catalog/model-hints.ts +15 -8
- package/src/codex/catalog/model-visibility.ts +3 -1
- package/src/codex/catalog/operator-tiers.ts +38 -0
- package/src/codex/catalog/parsing.ts +2 -1
- package/src/codex/catalog/provider-models.ts +58 -44
- package/src/codex/catalog/retained-sync.ts +7 -5
- package/src/codex/catalog/routed-gather.ts +15 -1
- package/src/codex/catalog-auto-refresh-sources.ts +3 -4
- package/src/codex/catalog-auto-refresh.ts +19 -0
- package/src/codex/catalog.ts +1 -1
- package/src/codex/codex-home-owner.ts +3 -0
- package/src/codex/config-write-lock.ts +333 -0
- package/src/codex/control-plane-models.ts +6 -0
- package/src/codex/convergence.ts +2 -1
- package/src/codex/features.ts +257 -200
- package/src/codex/inject/config-write-section.ts +34 -0
- package/src/codex/inject/multi-agent-v2.ts +14 -6
- package/src/codex/inject/remove.ts +36 -11
- package/src/codex/inject/restore.ts +85 -20
- package/src/codex/inject-coordination.ts +15 -6
- package/src/codex/inject.ts +62 -20
- package/src/codex/journal.ts +62 -17
- package/src/codex/main-account-cache.ts +43 -0
- package/src/codex/paths.ts +2 -0
- package/src/codex/prepared-home.ts +18 -0
- package/src/codex/prompt-journal.ts +25 -12
- package/src/codex/prompt-layers.ts +49 -26
- package/src/codex/prompt-lock-claim.ts +134 -0
- package/src/codex/prompt-lock-evidence.ts +26 -0
- package/src/codex/prompt-lock-io.ts +16 -0
- package/src/codex/prompt-lock-owner.ts +130 -0
- package/src/codex/prompt-lock.ts +84 -53
- package/src/codex/routing/failure-window.ts +146 -0
- package/src/codex/routing/selection.ts +4 -1
- package/src/codex/routing.ts +13 -17
- package/src/codex/runtime.ts +106 -18
- package/src/codex/shim.ts +45 -19
- package/src/combos/jev-decision-contract.ts +25 -2
- package/src/combos/jev-service-exchange.ts +281 -0
- package/src/combos/jev.ts +34 -219
- package/src/combos/types.ts +1 -1
- package/src/config/atomic-write.ts +1 -1
- package/src/config/codex-ws-reuse-setting.ts +10 -0
- package/src/config/diagnostics.ts +27 -16
- package/src/config/live-reconcile.ts +17 -0
- package/src/config/load-degrade.ts +42 -0
- package/src/config/rebase-provenance.ts +11 -0
- package/src/config/schema/anthropic-account-pool.ts +143 -0
- package/src/config/schema/config-schema.ts +11 -1
- package/src/config/schema/leaf-validators.ts +4 -0
- package/src/config.ts +2 -0
- package/src/generated/compatibility-version.json +566 -298
- package/src/generated/model-metadata.ts +7 -6
- package/src/grok/inject.ts +50 -4
- package/src/grok/sync.ts +2 -1
- package/src/images/loop.ts +30 -11
- package/src/integrations/aside-profiles.ts +10 -3
- package/src/integrations/catalog-refresh.ts +19 -3
- package/src/integrations/mutation-plan.ts +7 -0
- package/src/integrations/registry.ts +8 -0
- package/src/integrations/state.ts +9 -2
- package/src/integrations/writer.ts +17 -5
- package/src/lib/bun-path-runtime.d.mts +32 -0
- package/src/lib/bun-path-runtime.mjs +95 -0
- package/src/lib/bun-runtime-preflight.ts +140 -0
- package/src/lib/desktop-cli-handoff.d.mts +20 -0
- package/src/lib/desktop-cli-handoff.mjs +92 -0
- package/src/lib/desktop-cli-record.d.mts +29 -0
- package/src/lib/desktop-cli-record.mjs +102 -0
- package/src/lib/lab-live-route-production.ts +9 -1
- package/src/lib/request-execution-budget.ts +244 -58
- package/src/lib/spend-pool-alias-validation.ts +79 -0
- package/src/lib/spend-pool-continuity.ts +34 -0
- package/src/lib/spend-reservation-ledger.ts +412 -50
- package/src/lib/state-store-registrations.ts +20 -3
- package/src/lib/synced-state-location.ts +46 -6
- package/src/lib/test-home-guard.ts +87 -1
- package/src/lib/translator-budget.ts +17 -4
- package/src/lib/upstream-retry.ts +17 -5
- package/src/lib/windows-atomic-replace.ts +38 -16
- package/src/lib/windows-elevation.ts +6 -0
- package/src/lib/windows-secret-acl.ts +92 -25
- package/src/lib/winsw.ts +2 -3
- package/src/lib/workflow-budget.ts +53 -11
- package/src/messaging/budget.ts +45 -0
- package/src/messaging/discovery.ts +57 -0
- package/src/messaging/envelope.ts +49 -0
- package/src/messaging/input.ts +37 -0
- package/src/messaging/rpc.ts +196 -0
- package/src/messaging/send.ts +58 -0
- package/src/messaging/socket.ts +72 -0
- package/src/messaging/types.ts +29 -0
- package/src/oauth/anthropic-account-refusal.ts +90 -18
- package/src/oauth/anthropic-account-threshold.ts +8 -2
- package/src/oauth/anthropic-continuity.ts +15 -1
- package/src/oauth/anthropic-model-quota.ts +120 -48
- package/src/oauth/anthropic-model-routes.ts +11 -3
- package/src/oauth/anthropic-oauth-definitions.ts +98 -0
- package/src/oauth/anthropic-pool-config.ts +30 -0
- package/src/oauth/anthropic-rate-limit-policy.ts +64 -9
- package/src/oauth/anthropic-routing.ts +1202 -866
- package/src/oauth/anthropic-send-ownership.ts +41 -0
- package/src/oauth/anthropic.ts +4 -1
- package/src/oauth/chatgpt.ts +113 -41
- package/src/oauth/generic-account-failover.ts +3 -1
- package/src/oauth/health.ts +8 -6
- package/src/oauth/index.ts +96 -175
- package/src/oauth/kiro.ts +22 -9
- package/src/oauth/login-cli.ts +2 -0
- package/src/oauth/model-discovery-auth.ts +43 -0
- package/src/oauth/pool-kernel.ts +11 -5
- package/src/oauth/pool-settings-capability.ts +5 -3
- package/src/oauth/store-anthropic-instance.ts +87 -0
- package/src/oauth/store.ts +68 -10
- package/src/oauth/token-guardian.ts +2 -0
- package/src/oauth/types.ts +2 -0
- package/src/protocols/plan-snapshot.ts +5 -0
- package/src/protocols/settings.ts +20 -5
- package/src/providers/anthropic-instance-id.ts +47 -0
- package/src/providers/anthropic-instance.ts +48 -0
- package/src/providers/anthropic-reset-grant-ledger.ts +11 -1
- package/src/providers/azure-model-metadata.ts +115 -0
- package/src/providers/derive.ts +23 -0
- package/src/providers/kiro-models.ts +3 -0
- package/src/providers/label.ts +1 -1
- package/src/providers/model-rename-fields.ts +2 -0
- package/src/providers/quota/account-cache.ts +37 -11
- package/src/providers/quota/anthropic-account-quota.ts +93 -0
- package/src/providers/quota/anthropic-cooldown-recovery.ts +222 -111
- package/src/providers/quota/report-cache.ts +24 -1
- package/src/providers/quota/vendor-probes-key.ts +127 -17
- package/src/providers/quota/vendor-probes-oauth.ts +46 -14
- package/src/providers/quota.ts +23 -33
- package/src/providers/registry/entries-core.ts +35 -30
- package/src/providers/registry/model-ids.ts +1 -0
- package/src/providers/registry/model-seeds.ts +7 -4
- package/src/providers/registry/types.ts +3 -0
- package/src/providers/registry.ts +3 -3
- package/src/responses/reasoning-envelope.ts +29 -1
- package/src/responses/reasoning-replay-cache.ts +17 -1
- package/src/responses/spill-store.ts +20 -3
- package/src/responses/state/metrics.ts +95 -0
- package/src/responses/state/snapshot-codec.ts +6 -0
- package/src/responses/state/spill-failure.ts +12 -0
- package/src/responses/state/spill-queue.ts +13 -5
- package/src/responses/state/unforced-store-false.ts +55 -0
- package/src/responses/state.ts +68 -76
- package/src/responses/task-input.ts +17 -0
- package/src/router.ts +28 -4
- package/src/routing/compatibility/assemble.ts +1 -1
- package/src/routing/quota.ts +7 -3
- package/src/server/auth-cors.ts +5 -0
- package/src/server/background-lifecycle.ts +27 -0
- package/src/server/chat-completions.ts +7 -1
- package/src/server/chat-native.ts +64 -28
- package/src/server/claude-messages.ts +59 -8
- package/src/server/gui-static.ts +38 -4
- package/src/server/inbound-body-admission.ts +1 -0
- package/src/server/index/claude-intercept-lifecycle.ts +3 -1
- package/src/server/index/serve-options.ts +10 -2
- package/src/server/index/spend-ledger-lifecycle.ts +12 -5
- package/src/server/index/startup-warnings.ts +19 -0
- package/src/server/index.ts +5 -2
- package/src/server/inference/context.ts +1 -1
- package/src/server/lifecycle.ts +1 -1
- package/src/server/management/agent-settings-routes.ts +123 -38
- package/src/server/management/anthropic-account-threshold.ts +12 -9
- package/src/server/management/anthropic-pool-settings.ts +72 -0
- package/src/server/management/anthropic-reset-grant-routes.ts +98 -39
- package/src/server/management/codex-agent-role-routes.ts +4 -2
- package/src/server/management/codex-prompt-routes.ts +1 -0
- package/src/server/management/codex-role-auto-assign.ts +13 -2
- package/src/server/management/config-routes.ts +85 -14
- package/src/server/management/context.ts +2 -2
- package/src/server/management/decision-routes.ts +2 -1
- package/src/server/management/integration-routes.ts +25 -2
- package/src/server/management/oauth-account-routes.ts +79 -98
- package/src/server/management/provider-instance-ownership.ts +44 -0
- package/src/server/management/provider-routes.ts +21 -28
- package/src/server/management/route-registry.ts +3 -1
- package/src/server/management/routing-profile-routes.ts +4 -4
- package/src/server/management/shared.ts +3 -3
- package/src/server/management/system-restart.ts +44 -14
- package/src/server/management/system-routes.ts +24 -2
- package/src/server/management/vision-sidecar-options.ts +9 -6
- package/src/server/management/web-search-sidecar-options.ts +51 -2
- package/src/server/management-auth.ts +6 -0
- package/src/server/messages-native-eligibility.ts +3 -2
- package/src/server/messages-native-oauth.ts +91 -45
- package/src/server/messages-native-selector.ts +39 -0
- package/src/server/messages-native.ts +133 -38
- package/src/server/messages-response-headers.ts +14 -0
- package/src/server/request-log-conversation.ts +48 -5
- package/src/server/request-log.ts +36 -2
- package/src/server/responses/adapter-continuation.ts +31 -19
- package/src/server/responses/adapter-dispatch.ts +75 -24
- package/src/server/responses/antigravity-validation-refusal.ts +20 -6
- package/src/server/responses/codex-ws-exchange.ts +17 -2
- package/src/server/responses/codex-ws-pool.ts +100 -13
- package/src/server/responses/codex-ws-wire.ts +9 -0
- package/src/server/responses/combo-requested-effort.ts +3 -1
- package/src/server/responses/compact.ts +25 -8
- package/src/server/responses/compaction-recovery.ts +1 -1
- package/src/server/responses/core-codex-account.ts +22 -1
- package/src/server/responses/core-combo-native.ts +24 -4
- package/src/server/responses/core-combo.ts +38 -25
- package/src/server/responses/core-lifetime.ts +3 -36
- package/src/server/responses/core-normalize.ts +1 -0
- package/src/server/responses/core-options.ts +8 -1
- package/src/server/responses/core-replay.ts +78 -0
- package/src/server/responses/core.ts +3 -3
- package/src/server/responses/fetch-helpers.ts +26 -3
- package/src/server/responses/passthrough-delivery.ts +30 -4
- package/src/server/responses/passthrough-dispatch.ts +39 -9
- package/src/server/responses/request-prepare.ts +41 -5
- package/src/server/responses/request-send-budget.ts +150 -50
- package/src/server/responses/request-spend.ts +325 -33
- package/src/server/responses/request-transport.ts +132 -52
- package/src/server/responses/response-effects.ts +1 -0
- package/src/server/responses/run-turn-execution.ts +13 -3
- package/src/server/responses/sidecar-execution.ts +113 -22
- package/src/server/responses/sidecar-send-budget.ts +58 -0
- package/src/server/responses/ws-upstream.ts +19 -6
- package/src/server/responses-undeclared-tool-guard.ts +5 -1
- package/src/server/startup-health-cache.ts +2 -1
- package/src/server/workflow-refusal.ts +33 -0
- package/src/service/cli.ts +20 -4
- package/src/service/desktop-command-guard.ts +32 -0
- package/src/service/desktop-startup.ts +66 -40
- package/src/service/desktop-supervision.d.mts +26 -0
- package/src/service/desktop-supervision.mjs +140 -0
- package/src/service/managing-cli.ts +1 -0
- package/src/service/orchestration.ts +46 -20
- package/src/service/ownership-mutation-lease.d.mts +1 -1
- package/src/service/ownership-mutation-lease.mjs +5 -7
- package/src/service/repair.ts +25 -9
- package/src/service/state.ts +4 -3
- package/src/service/systemd.ts +17 -8
- package/src/service/windows-ops.ts +61 -22
- package/src/sidecar/anthropic-binding.ts +79 -0
- package/src/sidecar/auth.ts +76 -2
- package/src/storage/policy-job.ts +5 -1
- package/src/storage/policy-worker.ts +3 -1
- package/src/storage/policy.ts +9 -0
- package/src/types/anthropic-account-pool.ts +33 -0
- package/src/types/config.ts +33 -28
- package/src/types/provider.ts +5 -0
- package/src/types/request.ts +5 -0
- package/src/types/tools.ts +7 -0
- package/src/types/wire.ts +1 -0
- package/src/types.ts +4 -0
- package/src/update/index.ts +57 -9
- package/src/update/restart-ownership.ts +10 -3
- package/src/update/runtime-ownership.d.mts +6 -0
- package/src/update/runtime-ownership.mjs +23 -7
- package/src/usage/cost.ts +3 -2
- package/src/usage/expected-prices.ts +66 -14
- package/src/vision/anthropic-describe.ts +16 -3
- package/src/vision/index.ts +3 -0
- package/src/vision/plan.ts +19 -6
- package/src/web-search/alpha-search.ts +7 -1
- package/src/web-search/anthropic-executor.ts +16 -4
- package/src/web-search/index.ts +7 -3
- package/src/web-search/loop.ts +32 -7
- package/src/web-search/passthrough-bridge.ts +4 -1
- package/src/web-search/sidecar-providers.ts +4 -3
- package/gui/dist/assets/App-MbDVfUeC.js +0 -54
- package/gui/dist/assets/Tray-CzkxK82A.js +0 -1
- package/gui/dist/assets/index-UJt6npXk.js +0 -94
- package/gui/dist/assets/quota-summary-DU3sD6Z-.js +0 -1
|
@@ -571,11 +571,11 @@ export const CAPABILITIES: readonly Capability[] = [
|
|
|
571
571
|
command: ["claude","config"],
|
|
572
572
|
summary: "Read or update Claude Code settings, including independent CLI first-party routing.",
|
|
573
573
|
routes: [{"method":"GET","path":"/api/claude-code"},{"method":"PUT","path":"/api/claude-code"}],
|
|
574
|
-
flags: [{"name":"--enabled","value":"string","summary":"on or off."},{"name":"--auth-mode","value":"string","summary":"auto, proxy or subscription."},{"name":"--system-env","value":"string","summary":"on or off."},{"name":"--fast-mode","value":"string","summary":"on or off."},{"name":"--auto-context","value":"string","summary":"on or off."},{"name":"--compact-window","value":"string","summary":"Positive token count or default to clear."},{"name":"--inject-agents","value":"string","summary":"on or off."},{"name":"--small-fast-model","value":"string","summary":"Model ID; - clears."},{"name":"--model-map","value":"string","summary":"Comma-separated from=to mappings; - clears."},{"name":"--blocked-skills","value":"string","summary":"Comma-separated names; - clears."},{"name":"--web-model","value":"string","summary":"Model ID; - clears."},{"name":"--web-backend","value":"string","summary":"openai, anthropic, xai, gemini, exa or -."},{"name":"--vision-model","value":"string","summary":"Model ID; - clears."},{"name":"--vision-backend","value":"string","summary":"openai, anthropic or -."},{"name":"--first-party","value":"string","summary":"on or off; must be the only setting."},{"name":"--json","value":"boolean","summary":"Emit the result as JSON."}],
|
|
574
|
+
flags: [{"name":"--enabled","value":"string","summary":"on or off."},{"name":"--auth-mode","value":"string","summary":"auto, proxy or subscription."},{"name":"--system-env","value":"string","summary":"on or off."},{"name":"--fast-mode","value":"string","summary":"on or off."},{"name":"--auto-context","value":"string","summary":"on or off."},{"name":"--compact-window","value":"string","summary":"Positive token count or default to clear."},{"name":"--context-accounting","value":"string","summary":"1m (default) or 200k."},{"name":"--inject-agents","value":"string","summary":"on or off."},{"name":"--small-fast-model","value":"string","summary":"Model ID; - clears."},{"name":"--model-map","value":"string","summary":"Comma-separated from=to mappings; - clears."},{"name":"--blocked-skills","value":"string","summary":"Comma-separated names; - clears."},{"name":"--web-model","value":"string","summary":"Model ID; - clears."},{"name":"--web-backend","value":"string","summary":"openai, anthropic, xai, gemini, exa or -."},{"name":"--vision-model","value":"string","summary":"Model ID; - clears."},{"name":"--vision-backend","value":"string","summary":"openai, anthropic or -."},{"name":"--first-party","value":"string","summary":"on or off; must be the only setting."},{"name":"--json","value":"boolean","summary":"Emit the result as JSON."}],
|
|
575
575
|
mutates: true,
|
|
576
576
|
json: "payload",
|
|
577
577
|
details: ["At least one setting is required. --first-party must be set alone and writes Claude settings immediately.","Clear both helper model and backend with - to restore inheritance. Preserve shared_proxy_retained warnings."],
|
|
578
|
-
usage: "ocx claude config status [--json]; ocx claude config set [--enabled <on|off>] [--auth-mode <auto|proxy|subscription>] [--system-env <on|off>] [--fast-mode <on|off>] [--auto-context <on|off>] [--compact-window <tokens|default>] [--inject-agents <on|off>] [--small-fast-model <id|->] [--model-map <from=to,...|->] [--blocked-skills <name,name|->] [--web-model <id|->] [--web-backend <openai|anthropic|xai|gemini|exa|->] [--vision-model <id|->] [--vision-backend <openai|anthropic|->] [--json]; or ocx claude config set --first-party <on|off> [--json]",
|
|
578
|
+
usage: "ocx claude config status [--json]; ocx claude config set [--enabled <on|off>] [--auth-mode <auto|proxy|subscription>] [--system-env <on|off>] [--fast-mode <on|off>] [--auto-context <on|off>] [--compact-window <tokens|default>] [--context-accounting <1m|200k>] [--inject-agents <on|off>] [--small-fast-model <id|->] [--model-map <from=to,...|->] [--blocked-skills <name,name|->] [--web-model <id|->] [--web-backend <openai|anthropic|xai|gemini|exa|->] [--vision-model <id|->] [--vision-backend <openai|anthropic|->] [--json]; or ocx claude config set --first-party <on|off> [--json]",
|
|
579
579
|
},
|
|
580
580
|
{
|
|
581
581
|
command: ["claude","intercept","start"],
|
|
@@ -714,11 +714,11 @@ export const CAPABILITIES: readonly Capability[] = [
|
|
|
714
714
|
command: ["agent","roles"],
|
|
715
715
|
summary: "omo (Codex / LazyCodex): show each Codex agent role's model pin, set one role's model in its TOML and in omo.jsonc, or suggest a model for every role.",
|
|
716
716
|
routes: [{"method":"GET","path":"/api/codex-agent-roles"},{"method":"PUT","path":"/api/codex-agent-roles/{role}"},{"method":"POST","path":"/api/codex-agent-roles/auto-assign"}],
|
|
717
|
-
flags: [{"name":"--json","value":"boolean","summary":"Emit the role list, the write result or the proposals as JSON."},{"name":"--model","value":"string","summary":"suggest: size the roles with this model instead of the Codex default model."},{"name":"--apply","value":"boolean","summary":"suggest: write every proposal through the role model write."}],
|
|
717
|
+
flags: [{"name":"--json","value":"boolean","summary":"Emit the role list, the write result or the proposals as JSON."},{"name":"--effort","value":"string","summary":"set: also write the role's reasoning effort."},{"name":"--model","value":"string","summary":"suggest: size the roles with this model instead of the Codex default model."},{"name":"--apply","value":"boolean","summary":"suggest: write every proposal through the role model write."}],
|
|
718
718
|
mutates: true,
|
|
719
719
|
json: "payload",
|
|
720
|
-
details: ["A bare invocation reads and never writes.","Requires Codex-based omo (LazyCodex): the omo@sisyphuslabs Codex plugin enabled in config.toml and installed; otherwise status lists no roles, and set and suggest are refused.","set rewrites only the root model value of $CODEX_HOME/agents/<role>.toml; omo.jsonc is skipped when absent or when it contains comments.","suggest sizes every role with one model call and prints proposals without writing; --apply writes each proposed model, and its effort when the role file already sets model_reasoning_effort."],
|
|
721
|
-
usage: "ocx agent roles [status] [--json]; ocx agent roles set <role> <model> [--json]; ocx agent roles suggest [--model <id>] [--apply] [--json]",
|
|
720
|
+
details: ["A bare invocation reads and never writes.","Requires Codex-based omo (LazyCodex): the omo@sisyphuslabs Codex plugin enabled in config.toml and installed; otherwise status lists no roles, and set and suggest are refused.","set rewrites only the root model value of $CODEX_HOME/agents/<role>.toml, plus model_reasoning_effort with --effort; omo.jsonc gets the same model and, when LazyCodex has that level, the effort as reasoning; it is skipped when absent or when it contains comments.","suggest sizes every role with one model call and prints proposals without writing; --apply writes each proposed model, and its effort when the role file already sets model_reasoning_effort."],
|
|
721
|
+
usage: "ocx agent roles [status] [--json]; ocx agent roles set <role> <model> [--effort <level>] [--json]; ocx agent roles suggest [--model <id>] [--apply] [--json]",
|
|
722
722
|
},
|
|
723
723
|
{
|
|
724
724
|
command: ["agent","injection"],
|
|
@@ -111,6 +111,22 @@ export const INTEGRATION_CAPABILITIES: readonly Capability[] = [
|
|
|
111
111
|
json: "payload",
|
|
112
112
|
details: ["With --client, restore requires --profile; only Aside profiles accept that selector. No automatic drift confirmation or retry.","Preview preserves exact opId/profile/confirm-drift intent. Generic restore derives the client on the server; the returned plan does not embed opId or complete command input.","A refused or no-op preview is completed inspection, not applied work. A stale bound mutation exits5 with a fixed re-preview hint; no replacement token is automatically adopted."],
|
|
113
113
|
},
|
|
114
|
+
{
|
|
115
|
+
command: ["commandcode", "restore"],
|
|
116
|
+
usage: "ocx commandcode restore --op <opId> [--confirm-drift] [--preview | --plan-fingerprint <token>] [--json]",
|
|
117
|
+
summary: "Restore a Command Code rollback operation, retaining client ownership and drift checks.",
|
|
118
|
+
routes: [{ method: "POST", path: "/api/client-integrations/commandcode/restore" }, { method: "POST", path: "/api/client-integrations/commandcode/restore/preview" }],
|
|
119
|
+
flags: [
|
|
120
|
+
{ name: "--op", value: "string", summary: "Command Code operation ID; --op-id is an alias.", required: true },
|
|
121
|
+
{ name: "--confirm-drift", value: "boolean", summary: "Explicitly allow replacing edits made after the snapshot." },
|
|
122
|
+
{ name: "--preview", value: "boolean", summary: "Inspect restoration without mutating; exclusive with a commit fingerprint." },
|
|
123
|
+
{ name: "--plan-fingerprint", value: "string", summary: "Optional versioned token from a matching preview; stale intent is refused without retry." },
|
|
124
|
+
{ name: "--json", value: "boolean", summary: "Emit the result as JSON." },
|
|
125
|
+
],
|
|
126
|
+
mutates: true,
|
|
127
|
+
json: "payload",
|
|
128
|
+
details: ["cmd restore is an alias. --client and --profile are rejected; the dedicated route binds the operation to Command Code.", "Older proxies without the dedicated route fail without a generic restore fallback. Redirects are refused.", "Preview preserves the operation and drift intent. A stale bound mutation requires a new explicit preview."],
|
|
129
|
+
},
|
|
114
130
|
{
|
|
115
131
|
command: ["claude", "config", "status"],
|
|
116
132
|
usage: "ocx claude config status [--json]",
|
|
@@ -123,10 +139,10 @@ export const INTEGRATION_CAPABILITIES: readonly Capability[] = [
|
|
|
123
139
|
},
|
|
124
140
|
{
|
|
125
141
|
command: ["claude", "config", "set"],
|
|
126
|
-
usage: "ocx claude config set [--enabled <on|off>] [--auth-mode <auto|proxy|subscription>] [--system-env <on|off>] [--fast-mode <on|off>] [--auto-context <on|off>] [--compact-window <tokens|default>] [--inject-agents <on|off>] [--small-fast-model <id|->] [--model-map <from=to,...|->] [--blocked-skills <name,name|->] [--web-model <id|->] [--web-backend <openai|anthropic|xai|gemini|exa|->] [--vision-model <id|->] [--vision-backend <openai|anthropic|->] [--json]; or ocx claude config set --first-party <on|off> [--json]",
|
|
142
|
+
usage: "ocx claude config set [--enabled <on|off>] [--auth-mode <auto|proxy|subscription>] [--system-env <on|off>] [--fast-mode <on|off>] [--auto-context <on|off>] [--compact-window <tokens|default>] [--context-accounting <1m|200k>] [--inject-agents <on|off>] [--small-fast-model <id|->] [--model-map <from=to,...|->] [--blocked-skills <name,name|->] [--web-model <id|->] [--web-backend <openai|anthropic|xai|gemini|exa|->] [--vision-model <id|->] [--vision-backend <openai|anthropic|->] [--json]; or ocx claude config set --first-party <on|off> [--json]",
|
|
127
143
|
summary: "Change Claude Code settings through the runtime owner.",
|
|
128
144
|
routes: [{"method": "PUT", "path": "/api/claude-code"}],
|
|
129
|
-
flags: [{"name": "--enabled", "value": "string", "summary": "on or off."}, {"name": "--auth-mode", "value": "string", "summary": "auto, proxy or subscription."}, {"name": "--system-env", "value": "string", "summary": "on or off."}, {"name": "--fast-mode", "value": "string", "summary": "on or off."}, {"name": "--auto-context", "value": "string", "summary": "on or off."}, {"name": "--compact-window", "value": "string", "summary": "Positive token count or default to clear."}, {"name": "--inject-agents", "value": "string", "summary": "on or off."}, {"name": "--small-fast-model", "value": "string", "summary": "Model ID; - clears."}, {"name": "--model-map", "value": "string", "summary": "Comma-separated from=to mappings; - clears."}, {"name": "--blocked-skills", "value": "string", "summary": "Comma-separated names; - clears."}, {"name": "--web-model", "value": "string", "summary": "Model ID; - clears."}, {"name": "--web-backend", "value": "string", "summary": "openai, anthropic, xai, gemini, exa or -."}, {"name": "--vision-model", "value": "string", "summary": "Model ID; - clears."}, {"name": "--vision-backend", "value": "string", "summary": "openai, anthropic or -."}, {"name": "--first-party", "value": "string", "summary": "on or off; must be the only setting."}, {"name": "--json", "value": "boolean", "summary": "Emit the result as JSON."}],
|
|
145
|
+
flags: [{"name": "--enabled", "value": "string", "summary": "on or off."}, {"name": "--auth-mode", "value": "string", "summary": "auto, proxy or subscription."}, {"name": "--system-env", "value": "string", "summary": "on or off."}, {"name": "--fast-mode", "value": "string", "summary": "on or off."}, {"name": "--auto-context", "value": "string", "summary": "on or off."}, {"name": "--compact-window", "value": "string", "summary": "Positive token count or default to clear."}, {"name": "--context-accounting", "value": "string", "summary": "1m (default) or 200k."}, {"name": "--inject-agents", "value": "string", "summary": "on or off."}, {"name": "--small-fast-model", "value": "string", "summary": "Model ID; - clears."}, {"name": "--model-map", "value": "string", "summary": "Comma-separated from=to mappings; - clears."}, {"name": "--blocked-skills", "value": "string", "summary": "Comma-separated names; - clears."}, {"name": "--web-model", "value": "string", "summary": "Model ID; - clears."}, {"name": "--web-backend", "value": "string", "summary": "openai, anthropic, xai, gemini, exa or -."}, {"name": "--vision-model", "value": "string", "summary": "Model ID; - clears."}, {"name": "--vision-backend", "value": "string", "summary": "openai, anthropic or -."}, {"name": "--first-party", "value": "string", "summary": "on or off; must be the only setting."}, {"name": "--json", "value": "boolean", "summary": "Emit the result as JSON."}],
|
|
130
146
|
mutates: true,
|
|
131
147
|
json: "payload",
|
|
132
148
|
details: ["At least one setting is required. --first-party must be set alone and writes Claude settings immediately.", "Clear both helper model and backend with - to restore inheritance. Preserve shared_proxy_retained warnings."],
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { accessSync, constants, realpathSync, statSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { posix, win32 } from "node:path";
|
|
4
|
+
import { readDesktopCliRecord, type DesktopCliRecordRead, desktopCliRecordPath, DESKTOP_CLI_RECORD_MAX_BYTES } from "../lib/desktop-cli-record.mjs";
|
|
5
|
+
import { redactUserPath } from "../lib/redact";
|
|
6
|
+
|
|
7
|
+
export type CliCommandIssue = Extract<DesktopCliRecordRead, { issue: string }>["issue"]
|
|
8
|
+
| "cleanup-pending"
|
|
9
|
+
| "desktop-target-missing" | "desktop-target-unusable"
|
|
10
|
+
| "expected-command-missing" | "expected-command-unusable"
|
|
11
|
+
| "path-missing" | "path-first-not-desktop" | "path-unreadable"
|
|
12
|
+
| "path-scan-truncated" | "windows-current-directory-shadow";
|
|
13
|
+
export type CliPathCandidate = {
|
|
14
|
+
path: string; realpath: string; pathIndex: number; extension: string;
|
|
15
|
+
};
|
|
16
|
+
export type CliPathDiagnostics = {
|
|
17
|
+
configured: boolean;
|
|
18
|
+
recordPath: string;
|
|
19
|
+
packageHandoff: "enabled" | "disabled-on-windows";
|
|
20
|
+
recordState: DesktopCliRecordRead["state"];
|
|
21
|
+
expectedExecutable: string | null;
|
|
22
|
+
handoffTarget: string | null;
|
|
23
|
+
candidates: CliPathCandidate[];
|
|
24
|
+
pathFirst: CliPathCandidate | null;
|
|
25
|
+
desktopFirstOnPath: boolean | null;
|
|
26
|
+
currentDirectoryCandidate: CliPathCandidate | null;
|
|
27
|
+
shellResolution: "unobserved";
|
|
28
|
+
issues: CliCommandIssue[];
|
|
29
|
+
};
|
|
30
|
+
export type CliPathObservation =
|
|
31
|
+
| { kind: "usable"; realpath: string }
|
|
32
|
+
| { kind: "missing" | "unusable" | "unreadable" };
|
|
33
|
+
export type CliPathDiagnosticOptions = {
|
|
34
|
+
platform?: NodeJS.Platform; env?: NodeJS.ProcessEnv; cwd?: string; home?: string;
|
|
35
|
+
recordRead?: DesktopCliRecordRead;
|
|
36
|
+
observe?: (path: string) => CliPathObservation;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export function collectCliPathDiagnostics(options: CliPathDiagnosticOptions = {}): CliPathDiagnostics {
|
|
40
|
+
const platform = options.platform ?? process.platform;
|
|
41
|
+
const env = options.env ?? process.env;
|
|
42
|
+
const api = platform === "win32" ? win32 : posix;
|
|
43
|
+
const cwd = options.cwd ?? process.cwd();
|
|
44
|
+
const home = options.home ?? (platform === "win32" ? env.USERPROFILE || homedir() : homedir());
|
|
45
|
+
const read = options.recordRead ?? readDesktopCliRecord({ platform, env, home, recordPath: desktopCliRecordPath({ platform, env, home }) });
|
|
46
|
+
const configured = read.state === "ready";
|
|
47
|
+
const target = configured && read.state === "ready" ? read.record.cliExecutable : null;
|
|
48
|
+
const expected = configured ? (platform === "win32" ? target : api.join(home, ".opencodex-desktop", "bin", "ocx")) : null;
|
|
49
|
+
const issues: CliCommandIssue[] = [];
|
|
50
|
+
const add = (issue: CliCommandIssue): void => { if (!issues.includes(issue)) issues.push(issue); };
|
|
51
|
+
if (read.state === "invalid" || read.state === "unreadable") add(read.issue);
|
|
52
|
+
if (read.state === "disabled" && read.cleanupPending) add("cleanup-pending");
|
|
53
|
+
const observe = options.observe ?? ((path: string): CliPathObservation => {
|
|
54
|
+
try {
|
|
55
|
+
if (!statSync(path).isFile()) return { kind: "unusable" };
|
|
56
|
+
accessSync(path, platform === "win32" ? constants.F_OK : constants.X_OK);
|
|
57
|
+
return { kind: "usable", realpath: realpathSync(path) };
|
|
58
|
+
} catch (error) {
|
|
59
|
+
const code = (error as NodeJS.ErrnoException).code;
|
|
60
|
+
return { kind: code === "ENOENT" || code === "ENOTDIR" ? "missing" : code === "EACCES" ? "unusable" : "unreadable" };
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
const key = (path: string): string => platform === "win32" ? path.toLowerCase() : path;
|
|
64
|
+
const same = (a: string, b: string): boolean => key(a) === key(b);
|
|
65
|
+
const envValue = (name: string): string | undefined => platform === "win32"
|
|
66
|
+
? env[Object.keys(env).find(key => key.toLowerCase() === name.toLowerCase()) ?? name] : env[name];
|
|
67
|
+
const path = envValue("PATH");
|
|
68
|
+
const rawExtensions = platform === "win32"
|
|
69
|
+
? (envValue("PATHEXT") ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(ext => /^\.[A-Za-z0-9]+$/.test(ext)) : [];
|
|
70
|
+
const uniqueExtensions = [...new Set(rawExtensions.map(ext => ext.toLowerCase()))];
|
|
71
|
+
const extensions = platform === "win32" ? [...uniqueExtensions.slice(0, 32), ""] : [""];
|
|
72
|
+
if (uniqueExtensions.length > 32) add("path-scan-truncated");
|
|
73
|
+
const directories = path === undefined ? [] : path.split(platform === "win32" ? ";" : ":");
|
|
74
|
+
if (directories.length > 256) add("path-scan-truncated");
|
|
75
|
+
const candidates: CliPathCandidate[] = [];
|
|
76
|
+
const scan = (directory: string, pathIndex: number): CliPathCandidate[] => {
|
|
77
|
+
const result: CliPathCandidate[] = [];
|
|
78
|
+
const unquoted = platform === "win32" && directory.startsWith('"') && directory.endsWith('"') ? directory.slice(1, -1) : directory;
|
|
79
|
+
for (const extension of extensions) {
|
|
80
|
+
const candidate = api.resolve(cwd, unquoted || ".", `ocx${extension}`);
|
|
81
|
+
const found = observe(candidate);
|
|
82
|
+
if (found.kind === "unreadable") add("path-unreadable");
|
|
83
|
+
if (found.kind === "usable") result.push({ path: candidate, realpath: found.realpath, pathIndex, extension });
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
};
|
|
87
|
+
for (const [index, directory] of directories.slice(0, 256).entries()) candidates.push(...scan(directory, index));
|
|
88
|
+
const pathFirst = candidates[0] ?? null;
|
|
89
|
+
const currentDirectoryCandidate = platform === "win32" ? scan(cwd, -1)[0] ?? null : null;
|
|
90
|
+
let expectedRealpath: string | null = null;
|
|
91
|
+
if (target) {
|
|
92
|
+
const found = observe(target);
|
|
93
|
+
if (found.kind === "missing") add("desktop-target-missing");
|
|
94
|
+
else if (found.kind !== "usable") add("desktop-target-unusable");
|
|
95
|
+
}
|
|
96
|
+
if (expected) {
|
|
97
|
+
const found = observe(expected);
|
|
98
|
+
if (found.kind === "missing") add("expected-command-missing");
|
|
99
|
+
else if (found.kind !== "usable") add("expected-command-unusable");
|
|
100
|
+
else expectedRealpath = found.realpath;
|
|
101
|
+
if (!pathFirst) add("path-missing");
|
|
102
|
+
else if (!same(pathFirst.path, expected) && (!expectedRealpath || !same(pathFirst.realpath, expectedRealpath))) add("path-first-not-desktop");
|
|
103
|
+
if (currentDirectoryCandidate && !same(currentDirectoryCandidate.path, expected)
|
|
104
|
+
&& (!expectedRealpath || !same(currentDirectoryCandidate.realpath, expectedRealpath))) add("windows-current-directory-shadow");
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
configured, recordPath: read.path, packageHandoff: platform === "win32" ? "disabled-on-windows" : "enabled",
|
|
108
|
+
recordState: read.state, expectedExecutable: expected, handoffTarget: platform === "win32" ? null : target,
|
|
109
|
+
candidates, pathFirst,
|
|
110
|
+
desktopFirstOnPath: configured && !issues.includes("path-unreadable") && !issues.includes("path-scan-truncated")
|
|
111
|
+
? Boolean(pathFirst && expected && expectedRealpath
|
|
112
|
+
&& (same(pathFirst.path, expected) || same(pathFirst.realpath, expectedRealpath))) : null,
|
|
113
|
+
currentDirectoryCandidate, shellResolution: "unobserved", issues,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function formatCliCommandLine(value: CliPathDiagnostics): string {
|
|
118
|
+
const first = value.pathFirst ? redactUserPath(value.pathFirst.path).replace(/[\x00-\x1f\x7f]/g, "?") : "none observed";
|
|
119
|
+
return `ocx command: PATH first=${first}; Desktop=${!value.configured ? "not configured" : value.desktopFirstOnPath === null ? "unobserved" : value.desktopFirstOnPath ? "first" : "not first"}; ${value.packageHandoff === "disabled-on-windows" ? "package handoff=disabled on Windows (user Path selects Desktop); " : ""}shell=unobserved${value.issues.length ? `; issues=${value.issues.join(",")}` : ""}`;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function formatCliStatusHealthLabel(health: string, value: CliPathDiagnostics, local: boolean): string {
|
|
123
|
+
return `${health}${local ? " (local)" : ""}\n ${formatCliCommandLine(value)}`;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function cliCommandDoctorChecks(value: CliPathDiagnostics): { level: "OK" | "WARN" | "FAIL"; message: string }[] {
|
|
127
|
+
const hard = value.issues.some(issue => issue.startsWith("record-") || issue.startsWith("desktop-target-") || issue.startsWith("expected-command-"));
|
|
128
|
+
const recovery = value.issues.some(issue => issue.startsWith("record-"))
|
|
129
|
+
? ` The terminal-command record at ${redactUserPath(value.recordPath).replace(/[\x00-\x1f\x7f]/g, "?")} could not be used. Open OpenCodex Desktop to repair the terminal command.${value.packageHandoff === "disabled-on-windows" ? "" : " Or run with OCX_NO_DESKTOP_HANDOFF=1."}${value.issues.includes("record-too-large") ? ` The record limit is ${DESKTOP_CLI_RECORD_MAX_BYTES} bytes.` : ""}`
|
|
130
|
+
: value.issues.includes("cleanup-pending") ? " Open OpenCodex Desktop to finish terminal-command cleanup." : "";
|
|
131
|
+
return [{ level: hard ? "FAIL" : value.issues.length ? "WARN" : "OK", message: formatCliCommandLine(value) + recovery }];
|
|
132
|
+
}
|
|
@@ -15,11 +15,14 @@ const DEFAULT_DEPS: CodexShimAutoRestoreCliDeps = {
|
|
|
15
15
|
readConfig: readConfigDiagnostics,
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
+
/** Identify command namespaces whose execution must not trigger automatic shim repair. */
|
|
18
19
|
export function skipsCodexShimAutoRestore(command: string | undefined, args: string[]): boolean {
|
|
19
20
|
if (command === "uninstall" || command === "remove") return true;
|
|
20
21
|
if (command === "status" || command === "doctor") return true;
|
|
21
22
|
// `lab` is read-only inspection; it must not trigger shim side effects.
|
|
22
23
|
if (command === "lab") return true;
|
|
24
|
+
// Local messaging owns its helpers; even malformed usage must not repair/start anything.
|
|
25
|
+
if (command === "message") return true;
|
|
23
26
|
// `resolve` is read-only inspection for embedding shells: a lookup made to populate
|
|
24
27
|
// a consent surface must not trigger a shim repair side effect first.
|
|
25
28
|
if (command === "resolve") return true;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { createSupervisionLatch, inspectDesktopSupervision } from "../service/desktop-supervision.mjs";
|
|
2
|
+
import type { DesktopSupervision, SupervisionInspector } from "../service/desktop-command-guard";
|
|
3
|
+
import { UpdateRestartRequired } from "./update-restart-candidate";
|
|
4
|
+
import { runProxyRestart, type ProxyRestartIo } from "./tray-proxy";
|
|
5
|
+
|
|
6
|
+
function evidenceForTarget(evidence: DesktopSupervision, pid: number | null | undefined): DesktopSupervision {
|
|
7
|
+
// Injected inspectors must obey the same target binding as the production inspector.
|
|
8
|
+
return evidence.kind === "desktop" && pid != null && evidence.runtimePid !== pid
|
|
9
|
+
? { kind: "unknown", reason: "unrelated-target", desktopSeen: false } : evidence;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function duplicateRuntimeMessage(
|
|
13
|
+
pid: number | null | undefined,
|
|
14
|
+
port: number,
|
|
15
|
+
inspect: SupervisionInspector = inspectDesktopSupervision,
|
|
16
|
+
): string {
|
|
17
|
+
const latch = createSupervisionLatch();
|
|
18
|
+
const evidence = evidenceForTarget(inspect({ targetPid: pid ?? undefined }), pid);
|
|
19
|
+
if (pid != null && latch.observe(evidence)) {
|
|
20
|
+
const supervisor = evidence.kind === "desktop" ? `, ${evidence.app}` : "";
|
|
21
|
+
return `OpenCodex Desktop supervises the running proxy (pid ${pid}${supervisor}, port ${port}). `
|
|
22
|
+
+ "Use the running proxy, or quit OpenCodex before starting it from this CLI.";
|
|
23
|
+
}
|
|
24
|
+
return `⚠️ Proxy already running (PID ${pid ?? "unknown"}, port ${port}). Use 'ocx stop' first.`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function desktopStopNotice(evidence: DesktopSupervision): string | null {
|
|
28
|
+
const latch = createSupervisionLatch();
|
|
29
|
+
return latch.observe(evidence)
|
|
30
|
+
? "OpenCodex Desktop may start this proxy again after a short backoff. Use Stop Proxy or Quit in the OpenCodex menu to keep it stopped."
|
|
31
|
+
: null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function runDesktopAwareProxyRestart(
|
|
35
|
+
io: ProxyRestartIo,
|
|
36
|
+
inspect: SupervisionInspector = inspectDesktopSupervision,
|
|
37
|
+
info: (line: string) => void = console.log,
|
|
38
|
+
) {
|
|
39
|
+
const latch = createSupervisionLatch();
|
|
40
|
+
let targetPid: number | undefined;
|
|
41
|
+
let supervisedRequest = false;
|
|
42
|
+
return runProxyRestart({
|
|
43
|
+
...io,
|
|
44
|
+
requestInPlaceRestart: async previous => {
|
|
45
|
+
targetPid = previous.pid ?? undefined;
|
|
46
|
+
const evidence = evidenceForTarget(inspect({ targetPid }), targetPid);
|
|
47
|
+
supervisedRequest = latch.observe(evidence);
|
|
48
|
+
const result = await io.requestInPlaceRestart(previous);
|
|
49
|
+
if (evidence.kind === "desktop" && result.accepted) {
|
|
50
|
+
info("Restart requested; OpenCodex Desktop starts the replacement.");
|
|
51
|
+
}
|
|
52
|
+
if (supervisedRequest && !result.accepted && !result.uncertain && result.error instanceof UpdateRestartRequired) {
|
|
53
|
+
info("OpenCodex Desktop supervises this proxy. Use the app's updater (tray → Check for Updates), or quit OpenCodex before updating and restarting from this CLI.");
|
|
54
|
+
return { accepted: false as const, uncertain: false, error: new Error("restart_desktop_update_required") };
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
},
|
|
58
|
+
startWhenStopped: async recovering => {
|
|
59
|
+
const blocked = latch.observe(evidenceForTarget(inspect({ targetPid }), targetPid));
|
|
60
|
+
// An accepted supervised handoff keeps its replacement intent through temporary absence.
|
|
61
|
+
if (supervisedRequest || blocked) return { status: "skipped" as const };
|
|
62
|
+
return io.startWhenStopped(recovering);
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
}
|
package/src/cli/dispatch.ts
CHANGED
|
@@ -37,6 +37,8 @@ import { parseStopApproval, type StopApproval } from "./stop-approval";
|
|
|
37
37
|
import type { ResolveArgs } from "./resolve";
|
|
38
38
|
import type { ClientConnectionState } from "../client/state";
|
|
39
39
|
import { OCX_NATIVE_REPLAY_RECOVERY_NOTE } from "../responses/compaction";
|
|
40
|
+
import { inspectDesktopSupervision } from "../service/desktop-supervision.mjs";
|
|
41
|
+
import { desktopStopNotice } from "./desktop-runtime-guidance";
|
|
40
42
|
|
|
41
43
|
export interface CliDispatchDeps {
|
|
42
44
|
args: string[];
|
|
@@ -51,6 +53,7 @@ export interface CliDispatchDeps {
|
|
|
51
53
|
spawnDetached: (argv: readonly string[]) => void;
|
|
52
54
|
handleStart: () => Promise<void>;
|
|
53
55
|
handleStop: (approval?: StopApproval) => Promise<StopOutcome>;
|
|
56
|
+
inspectDesktopSupervision?: typeof inspectDesktopSupervision;
|
|
54
57
|
handleEnsure: (options?: { existingIsSuccess?: boolean }) => Promise<boolean>;
|
|
55
58
|
handleResolve: (args: ResolveArgs) => Promise<number>;
|
|
56
59
|
handleTrayProxyStart: (existingIsSuccess?: boolean) => Promise<boolean>;
|
|
@@ -112,6 +115,8 @@ const commandRunners: Record<string, CommandRunner> = {
|
|
|
112
115
|
// re-start the proxy immediately, so warning there would contradict the next line.
|
|
113
116
|
const warning = "⚠️ Codex/Claude requests through the proxy will fail until it is restarted ('ocx start' or 'ocx service start').";
|
|
114
117
|
if (!parsed.json) {
|
|
118
|
+
const notice = desktopStopNotice((deps.inspectDesktopSupervision ?? inspectDesktopSupervision)());
|
|
119
|
+
if (notice) console.error(notice);
|
|
115
120
|
// handleStop returns the structured outcome now; an object is always truthy, so
|
|
116
121
|
// the warning must key on .ok — otherwise a failed stop would still claim downtime.
|
|
117
122
|
if ((await deps.handleStop()).ok) console.log(warning);
|
|
@@ -145,6 +150,7 @@ const commandRunners: Record<string, CommandRunner> = {
|
|
|
145
150
|
if (!deps.head.resolveArgs) return 64;
|
|
146
151
|
return await deps.handleResolve(deps.head.resolveArgs);
|
|
147
152
|
},
|
|
153
|
+
message: async deps => (await import("./message-command")).runMessageCommand(deps.args.slice(1)),
|
|
148
154
|
restore: async deps => {
|
|
149
155
|
const restoreArgs = deps.args.slice(1);
|
|
150
156
|
const restoreJson = takeFlag(restoreArgs, "--json");
|
|
@@ -465,7 +471,7 @@ const commandRunners: Record<string, CommandRunner> = {
|
|
|
465
471
|
},
|
|
466
472
|
config,
|
|
467
473
|
port: live.port,
|
|
468
|
-
}, ["mcode", "pi", "raycast", "omo", "cline", "droid", "opencode", "kilo"]));
|
|
474
|
+
}, ["mcode", "pi", "raycast", "omo", "cline", "commandcode", "droid", "opencode", "kilo"]));
|
|
469
475
|
} catch (error) {
|
|
470
476
|
console.warn(`Client integrations were not refreshed: ${error instanceof Error ? error.message : String(error)}`);
|
|
471
477
|
}
|
|
@@ -961,6 +967,14 @@ const commandRunners: Record<string, CommandRunner> = {
|
|
|
961
967
|
const { handleZcodeCommand } = await import("./integrations");
|
|
962
968
|
return await handleZcodeCommand(deps.args.slice(1));
|
|
963
969
|
},
|
|
970
|
+
commandcode: async deps => {
|
|
971
|
+
const { handleCommandcodeCommand } = await import("./integrations");
|
|
972
|
+
return await handleCommandcodeCommand(deps.args.slice(1));
|
|
973
|
+
},
|
|
974
|
+
cmd: async deps => {
|
|
975
|
+
const { handleCommandcodeCommand } = await import("./integrations");
|
|
976
|
+
return await handleCommandcodeCommand(deps.args.slice(1));
|
|
977
|
+
},
|
|
964
978
|
help: async () => {
|
|
965
979
|
printUsage();
|
|
966
980
|
return 0;
|
package/src/cli/doctor.ts
CHANGED
|
@@ -7,11 +7,13 @@
|
|
|
7
7
|
* it never sets proxy env, relocates state dirs, mutates quota, or changes
|
|
8
8
|
* networking. See devlog/_plan/260630_wsl-account-autoswitch/30_*.
|
|
9
9
|
*/
|
|
10
|
+
import { cliCommandDoctorChecks, collectCliPathDiagnostics } from "./cli-path-diagnostics";
|
|
10
11
|
import { accessSync, constants, existsSync, readFileSync } from "node:fs";
|
|
11
12
|
import { homedir } from "node:os";
|
|
12
13
|
import { dirname, join } from "node:path";
|
|
13
14
|
import { getConfigDir, getConfigPath, readConfigDiagnostics } from "../config";
|
|
14
15
|
import { readPid } from "../config/process-state";
|
|
16
|
+
import { inspectDesktopSupervision } from "../service/desktop-supervision.mjs";
|
|
15
17
|
import { fetchLiveStartupHealth, probeUncleanExitState, selectStatusStartupHealth } from "./status";
|
|
16
18
|
import { findLiveProxy, probeHostname, type LiveProxy } from "../server/proxy-liveness";
|
|
17
19
|
import { directLocalHttpFetch } from "../server/direct-local-http";
|
|
@@ -1324,6 +1326,12 @@ export async function runDoctor(args: string[] = []): Promise<void> {
|
|
|
1324
1326
|
console.log(` ${row.exists ? "ok " : "-- "} ${row.label}: ${row.path}${flags ? ` (${flags})` : ""}`);
|
|
1325
1327
|
}
|
|
1326
1328
|
|
|
1329
|
+
console.log("\nocx command selection");
|
|
1330
|
+
for (const check of cliCommandDoctorChecks(collectCliPathDiagnostics())) {
|
|
1331
|
+
console.log(` ${check.level === "OK" ? "ok " : "!! "} ${check.message}`);
|
|
1332
|
+
if (check.level === "FAIL") recordDoctorFailure();
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1327
1335
|
// Runs without the proxy on purpose: the worst accumulation happens when the proxy will
|
|
1328
1336
|
// not start, which is exactly when the in-process periodic reclaim never ticks.
|
|
1329
1337
|
const reclaimTemps = args.includes(RECLAIM_RESPONSE_TEMPS_FLAG);
|
|
@@ -1379,7 +1387,8 @@ export async function runDoctor(args: string[] = []): Promise<void> {
|
|
|
1379
1387
|
configFn: () => ({ port: doctorConfig.port, hostname: doctorConfig.hostname }),
|
|
1380
1388
|
});
|
|
1381
1389
|
const liveStartup = live ? await fetchLiveStartupHealth(live) : null;
|
|
1382
|
-
const startup = selectStatusStartupHealth(liveStartup, () => collectStartupHealth(doctorConfig)
|
|
1390
|
+
const { startup } = selectStatusStartupHealth(liveStartup, () => collectStartupHealth(doctorConfig),
|
|
1391
|
+
live?.pid != null ? () => inspectDesktopSupervision({ targetPid: live.pid! }) : undefined, live?.pid);
|
|
1383
1392
|
console.log("\nCodex restart safety");
|
|
1384
1393
|
console.log(` ${startup.rebootSafe ? "ok " : "!! "} ${startupHealthSummary(startup)}`);
|
|
1385
1394
|
console.log(` ${formatStartupRoutingDetail(startup)}`);
|
|
@@ -1685,8 +1694,12 @@ export async function runDoctor(args: string[] = []): Promise<void> {
|
|
|
1685
1694
|
const anyDrvfs = paths.some(p => detectFsType(p.path, mounts).isDrvfs || detectFsType(p.path, mounts).isMntDrive);
|
|
1686
1695
|
const noProxy = currentProxyEnv.every(p => !p.present) && !configuredProxy.present;
|
|
1687
1696
|
if (!startup.rebootSafe) {
|
|
1688
|
-
|
|
1689
|
-
|
|
1697
|
+
if (startup.recommendedAction || startup.desktop?.supervisor) {
|
|
1698
|
+
hints.push(`Codex is pinned to the local proxy without persistent startup protection. ${startup.recommendedAction ?? "Reopen OpenCodex and check Start at Login."}`);
|
|
1699
|
+
} else {
|
|
1700
|
+
const command = startup.recommendedCommand ?? startup.commands.restoreNative;
|
|
1701
|
+
hints.push(`Codex is pinned to the local proxy without persistent startup protection. After restart, requests can reconnect indefinitely. Run '${command}'.`);
|
|
1702
|
+
}
|
|
1690
1703
|
}
|
|
1691
1704
|
if (anyDrvfs) {
|
|
1692
1705
|
hints.push("State dir is on a Windows-mounted (/mnt) drive. Prefer the Linux home (~) under WSL for token/lock reliability.");
|
package/src/cli/help.ts
CHANGED
|
@@ -79,6 +79,7 @@ Usage:
|
|
|
79
79
|
ocx alias <sub> Short names for providers and models (list, set, rm, defaults)
|
|
80
80
|
ocx combo <sub> Combo routing strategies and failover
|
|
81
81
|
ocx agent <sub> Subagents, injection, effort caps, and sidecars
|
|
82
|
+
ocx message <sub> Loaded local Codex sessions and queued peer messages (sessions|send)
|
|
82
83
|
ocx effort [sub] Inspect and configure reasoning effort caps and defaults
|
|
83
84
|
ocx observe <sub> Logs, usage, storage, memory, and debug data
|
|
84
85
|
ocx inspect <sub> Effective config, catalog, analytics, pacing, client-config
|
|
@@ -91,7 +92,7 @@ Usage:
|
|
|
91
92
|
ocx api-key <sub> Alias of ocx access key
|
|
92
93
|
ocx access <sub> External API keys and endpoint information
|
|
93
94
|
ocx api <sub> Protocol paths: vocabulary, request-path preview, and policy
|
|
94
|
-
ocx export --client <id> Print a client config wired to the running proxy (
|
|
95
|
+
ocx export --client <id> Print a client config wired to the running proxy (18 clients)
|
|
95
96
|
ocx integration client <sub> Enable, disable, inspect or roll back a client integration
|
|
96
97
|
ocx grok <sub> Grok Build model selection and apply
|
|
97
98
|
ocx system <sub> Runtime settings, startup, sync, OpenCodex updates, and Codex CLI inspection
|
|
@@ -105,6 +106,8 @@ Usage:
|
|
|
105
106
|
ocx mcode [args...] Launch MiniMax Code through its managed provider
|
|
106
107
|
ocx mmx text <sub> [args] Launch MiniMax CLI text through the proxy
|
|
107
108
|
ocx zcode [sub] Connect ZCode to the proxy (managed provider)
|
|
109
|
+
ocx commandcode [sub] Connect Command Code CLI to the proxy (managed provider)
|
|
110
|
+
ocx cmd [sub] Alias of ocx commandcode
|
|
108
111
|
ocx help [command] Show help
|
|
109
112
|
ocx --version | -v Print version
|
|
110
113
|
|
package/src/cli/index.ts
CHANGED
|
@@ -8,6 +8,8 @@ import { homedir } from "node:os";
|
|
|
8
8
|
import { join } from "node:path";
|
|
9
9
|
import { currentServingCommand, deferServiceChildToNewerRuntime, markDelegatedServiceReady, recordServingRuntime } from "../config/serving-runtimes";
|
|
10
10
|
import { packageVersion } from "../lib/package-version";
|
|
11
|
+
import { codexHomeIsAbsent } from "../codex/codex-home-owner";
|
|
12
|
+
import { getCodexHome } from "../codex/paths";
|
|
11
13
|
import { admitUpdateRestartChild } from "./update-restart-child";
|
|
12
14
|
import { UpdateRestartRequired } from "./update-restart-candidate";
|
|
13
15
|
import { describeUpdateRestartFailure, restartFromCurrentInstallation } from "./update-restart";
|
|
@@ -75,7 +77,7 @@ import {
|
|
|
75
77
|
pendingTeardownsAreExactly,
|
|
76
78
|
quarantinePendingTeardown,
|
|
77
79
|
} from "../config/pending-teardown";
|
|
78
|
-
import { collectStatus, deadProxyRoutingAdviceLines, detectMissingCodexCatalogPath, hubStatusLines, missingCodexCatalogLines, remoteHubBannerLine, remoteHubStatusLines, unusedProxyWarningLines } from "./status";
|
|
80
|
+
import { collectStatus, deadProxyRoutingAdviceLines, detectMissingCodexCatalogPath, hubStatusLines, missingCodexCatalogLines, remoteHubBannerLine, remoteHubStatusLines, runtimeSupervisorLine, unusedProxyWarningLines } from "./status";
|
|
79
81
|
import { endpointsToProve, everyEndpointProvenDownAsync, sharedTeardownAuthorized, type UninstallObservation } from "./uninstall-plan";
|
|
80
82
|
import { takeFlag } from "./runtime-api";
|
|
81
83
|
import { parseStartOptions, StartArgsError } from "./start-args";
|
|
@@ -85,11 +87,11 @@ import {
|
|
|
85
87
|
recheckRestartFailedStart, reobserveRestartReplacement,
|
|
86
88
|
restartStartOutcome,
|
|
87
89
|
waitForProxyReplacement,
|
|
88
|
-
runProxyRestart,
|
|
89
90
|
runTrayProxyStart,
|
|
90
91
|
type ProxyRestartLive,
|
|
91
92
|
type ProxyRestartStartOutcome,
|
|
92
93
|
} from "./tray-proxy";
|
|
94
|
+
import { duplicateRuntimeMessage, runDesktopAwareProxyRestart } from "./desktop-runtime-guidance";
|
|
93
95
|
import { reportRestartFailure } from "./restart-failure";
|
|
94
96
|
import { requestBoundSystemRestart } from "./system-restart-client";
|
|
95
97
|
import { installCrashGuards } from "../lib/crash-guard";
|
|
@@ -210,11 +212,17 @@ initializeNodeLauncherContext();
|
|
|
210
212
|
// The compiled executable is also the capture-only MCP server's launcher.
|
|
211
213
|
// Handle this private entrypoint before CLI preflight or command dispatch.
|
|
212
214
|
if (process.argv[2] === "__keyring-load-check") { console.log(JSON.stringify((await import("../lib/keyring-native")).inspectKeyringBinding())); process.exit(0); }
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
215
|
+
|
|
216
|
+
// The compiled executable also launches the isolated MCP servers.
|
|
217
|
+
// Handle these private entrypoints before CLI preflight or command dispatch.
|
|
218
|
+
if (process.argv[2] === "__codebuddy-mcp" || process.argv[2] === "__qoder-mcp") {
|
|
219
|
+
if (process.argv[2] === "__codebuddy-mcp") {
|
|
220
|
+
const { runCodeBuddyMcpServer } = await import("../adapters/codebuddy/mcp-server");
|
|
221
|
+
await runCodeBuddyMcpServer(process.argv[3] ?? "");
|
|
222
|
+
} else {
|
|
223
|
+
const { runCodingAgentMcpServer } = await import("../adapters/coding-agent/mcp-server");
|
|
224
|
+
await runCodingAgentMcpServer(process.argv[3] ?? "");
|
|
225
|
+
}
|
|
218
226
|
await new Promise<never>(() => {});
|
|
219
227
|
}
|
|
220
228
|
|
|
@@ -323,7 +331,7 @@ async function chooseListenPort(
|
|
|
323
331
|
throw new StartCommandExit(serviceStayOutExitCode());
|
|
324
332
|
}
|
|
325
333
|
if (decision === "refuse-live-proxy") {
|
|
326
|
-
console.error(
|
|
334
|
+
console.error(duplicateRuntimeMessage(holder?.pid, preferred));
|
|
327
335
|
throw new StartCommandExit(1);
|
|
328
336
|
}
|
|
329
337
|
if (decision === "refuse-unidentified-holder") {
|
|
@@ -438,7 +446,7 @@ async function handleStart(options: { block?: boolean } = {}) {
|
|
|
438
446
|
process.exit(serviceStayOutExitCode());
|
|
439
447
|
}
|
|
440
448
|
if (decision === "refuse" || decision === "await-parent") {
|
|
441
|
-
console.error(
|
|
449
|
+
console.error(duplicateRuntimeMessage(owner.live.pid ?? owner.pidSnapshot, owner.live.port));
|
|
442
450
|
process.exit(1);
|
|
443
451
|
}
|
|
444
452
|
// Sibling path. The new instance takes over this home's ocx.pid / runtime-port.json while
|
|
@@ -648,10 +656,12 @@ async function handleStart(options: { block?: boolean } = {}) {
|
|
|
648
656
|
removeRuntimePort(process.pid);
|
|
649
657
|
if (teardown.restoreNativeCodex && !currentExternalCodexModelProvider()) {
|
|
650
658
|
try {
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
659
|
+
if (!codexHomeIsAbsent(getCodexHome())) {
|
|
660
|
+
const restored = restoreNativeCodex();
|
|
661
|
+
if (!restored.success) {
|
|
662
|
+
cleanupSucceeded = false;
|
|
663
|
+
console.error(`⚠️ Native Codex restore failed during shutdown: ${restored.message}`);
|
|
664
|
+
}
|
|
655
665
|
}
|
|
656
666
|
} catch (error) {
|
|
657
667
|
cleanupSucceeded = false;
|
|
@@ -922,7 +932,7 @@ async function handleProxyRestart(
|
|
|
922
932
|
startWhenStopped: (recoveringLiveRestart: boolean) => Promise<ProxyRestartStartOutcome>,
|
|
923
933
|
): Promise<boolean> {
|
|
924
934
|
const deadlineAt = Date.now() + PROXY_RESTART_OBSERVE_MS;
|
|
925
|
-
const result = await
|
|
935
|
+
const result = await runDesktopAwareProxyRestart({
|
|
926
936
|
findLive: () => discoverStableProxyForRestart({
|
|
927
937
|
findLive: () => findLiveProxy({ deadlineAt, attempts: 2, acceptPackageTreeFenced: true }),
|
|
928
938
|
expired: () => Date.now() >= deadlineAt,
|
|
@@ -1779,6 +1789,7 @@ async function handleStatus() {
|
|
|
1779
1789
|
console.log(` Config: ${status.json.paths.config}${local}`);
|
|
1780
1790
|
console.log(` PID file: ${status.json.paths.pid}${local}`);
|
|
1781
1791
|
console.log(` Runtime: ${status.json.paths.runtime}${local}`);
|
|
1792
|
+
if (runtimeSupervisorLine(status.json.startup)) console.log(` ${runtimeSupervisorLine(status.json.startup)}`);
|
|
1782
1793
|
console.log(` Runtime source: ${status.json.runtime.source}${status.json.runtime.overrideEnv ? ` (${status.json.runtime.overrideEnv})` : ""}${local}`);
|
|
1783
1794
|
// On a client this is the local default, which routing does not use — the hub applies its own.
|
|
1784
1795
|
console.log(` Default provider: ${status.json.defaultProvider}${local}`);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { redactUserPath } from "../lib/redact";
|
|
3
3
|
import type { RefusalReason } from "../integrations/mutation-plan";
|
|
4
|
+
import { ASIDE_SYNC_EMPTY_LINES } from "./aside-profile-recovery";
|
|
4
5
|
import { refreshAsideProfilesThroughServer } from "./aside-profiles";
|
|
5
6
|
import { runCatalogAction } from "./catalog-command-result";
|
|
6
7
|
import { CliUsageError, RuntimeApiError, printData, takeFlag, takeOption, type RuntimeApiDeps } from "./runtime-api";
|
|
@@ -56,7 +57,7 @@ export function handleIntegrationAsideSync(argv: string[], deps: AsideSyncCliDep
|
|
|
56
57
|
const parsed = resultsSchema.safeParse(outcomes);
|
|
57
58
|
if (!parsed.success) throw new Error("Invalid Aside synchronization outcome");
|
|
58
59
|
const results = parsed.data;
|
|
59
|
-
const lines = results.length === 0 ? [
|
|
60
|
+
const lines = results.length === 0 ? [...ASIDE_SYNC_EMPTY_LINES]
|
|
60
61
|
: results.flatMap(row => [
|
|
61
62
|
`Aside profile ${row.profileId}: ${row.ok ? row.changed ? "updated" : "unchanged" : "failed"}.`,
|
|
62
63
|
...(row.reason ? [row.reason] : []),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** Preview and explicitly bound mutations use the existing management authority. */
|
|
2
2
|
import type { IntegrationMutationPlan, IntegrationPlanOperation } from "../integrations/mutation-plan";
|
|
3
|
+
import type { IntegrationClientId } from "../integrations/registry";
|
|
3
4
|
import { redactSecretString, redactUserPath } from "../lib/redact";
|
|
4
5
|
import {
|
|
5
6
|
CliUsageError, RuntimeApiError, printData, runtimeRequest, terminalSafeText,
|
|
@@ -186,9 +187,15 @@ function reportError(error: unknown): number {
|
|
|
186
187
|
return 1;
|
|
187
188
|
}
|
|
188
189
|
|
|
189
|
-
export async function handleIntegrationPreviewCommand(argv: string[], deps: RuntimeApiDeps = {}): Promise<number> {
|
|
190
|
+
export async function handleIntegrationPreviewCommand(argv: string[], deps: RuntimeApiDeps = {}, expectedClientId?: IntegrationClientId): Promise<number> {
|
|
190
191
|
try {
|
|
191
192
|
const intent = parseIntent(argv);
|
|
193
|
+
if (expectedClientId !== undefined && intent.operation === "restore") {
|
|
194
|
+
if (intent.client !== undefined || intent.profile !== undefined) throw new CliUsageError("client-specific restore does not accept --client or --profile", USAGE);
|
|
195
|
+
intent.client = expectedClientId;
|
|
196
|
+
intent.path = `${clientIntegrationPath(expectedClientId)}/restore${intent.preview ? "/preview" : ""}`;
|
|
197
|
+
intent.body.expectedClientId = expectedClientId;
|
|
198
|
+
}
|
|
192
199
|
const result = await runtimeRequest(intent.path, {
|
|
193
200
|
method: intent.preview || intent.operation === "restore" ? "POST" : "PUT",
|
|
194
201
|
redirect: "error", body: JSON.stringify(intent.body),
|