@iislee/opencodex 2.11.0 → 2.35.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/AGENTS_INSTALL.md +109 -0
- package/README.md +117 -22
- package/bin/ocx.mjs +245 -88
- package/bin/package-main.mjs +1 -1
- package/gui/dist/assets/index-Be1sDpWw.css +1 -0
- package/gui/dist/assets/index-D4OKgUV4.js +114 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/alibaba-color.svg +1 -1
- package/gui/dist/provider-icons/antigravity-color.svg +1 -1
- package/gui/dist/provider-icons/claude-color.svg +1 -1
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/commandcode-color.svg +1 -0
- package/gui/dist/provider-icons/copilot-color.svg +1 -1
- package/gui/dist/provider-icons/cursor-color.svg +1 -1
- package/gui/dist/provider-icons/deepseek-color.svg +1 -1
- package/gui/dist/provider-icons/firepass-color.svg +1 -1
- package/gui/dist/provider-icons/fireworks-color.svg +1 -1
- package/gui/dist/provider-icons/gemini-color.svg +1 -1
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
- package/gui/dist/provider-icons/grok.svg +1 -1
- package/gui/dist/provider-icons/groq-color.svg +1 -1
- package/gui/dist/provider-icons/huggingface-color.svg +1 -1
- package/gui/dist/provider-icons/kimi-color.svg +1 -1
- package/gui/dist/provider-icons/kiro-color.svg +2 -2
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
- package/gui/dist/provider-icons/mistral-color.svg +1 -1
- package/gui/dist/provider-icons/moonshot-color.svg +1 -1
- package/gui/dist/provider-icons/nvidia-color.svg +1 -1
- package/gui/dist/provider-icons/ollama-color.svg +1 -1
- package/gui/dist/provider-icons/openai.svg +1 -1
- package/gui/dist/provider-icons/opencode.svg +2 -1
- package/gui/dist/provider-icons/openrouter-color.svg +1 -1
- package/gui/dist/provider-icons/pi.svg +2 -2
- package/gui/dist/provider-icons/qianfan-color.svg +1 -1
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/vllm-color.svg +1 -1
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
- package/package.json +21 -10
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +475 -62
- package/src/adapters/base.ts +82 -7
- package/src/adapters/client-fingerprint.ts +18 -12
- package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
- package/src/adapters/command-code.ts +637 -0
- package/src/adapters/cursor/call-id.ts +44 -0
- package/src/adapters/cursor/catalog.ts +541 -0
- package/src/adapters/cursor/checkpoint-store.ts +308 -0
- package/src/adapters/cursor/cursor-errors.ts +144 -6
- package/src/adapters/cursor/discovery.ts +122 -14
- package/src/adapters/cursor/effort-map.ts +106 -4
- package/src/adapters/cursor/envelope-echo.ts +290 -0
- package/src/adapters/cursor/framing.ts +39 -0
- package/src/adapters/cursor/h2-pool.ts +123 -0
- package/src/adapters/cursor/http1-bidi.ts +361 -0
- package/src/adapters/cursor/images.ts +704 -0
- package/src/adapters/cursor/live-models.ts +180 -59
- package/src/adapters/cursor/live-transport.ts +623 -170
- package/src/adapters/cursor/message-mapper.ts +4 -1
- package/src/adapters/cursor/native-exec-common.ts +23 -2
- package/src/adapters/cursor/native-exec-desktop.ts +23 -0
- package/src/adapters/cursor/native-exec-fs.ts +10 -7
- package/src/adapters/cursor/native-exec-network.ts +1 -1
- package/src/adapters/cursor/native-exec-shell.ts +5 -3
- package/src/adapters/cursor/native-exec.ts +121 -14
- package/src/adapters/cursor/protobuf-events.ts +829 -11
- package/src/adapters/cursor/protobuf-request.ts +447 -75
- package/src/adapters/cursor/request-builder.ts +271 -35
- package/src/adapters/cursor/tool-definitions.ts +252 -12
- package/src/adapters/cursor/tool-result-normalize.ts +115 -0
- package/src/adapters/cursor/transport.ts +22 -0
- package/src/adapters/cursor/types.ts +48 -1
- package/src/adapters/cursor.ts +336 -39
- package/src/adapters/exec-tool-result-normalize.ts +99 -0
- package/src/adapters/google-antigravity-replay.ts +713 -41
- package/src/adapters/google-antigravity-wire.ts +48 -10
- package/src/adapters/google-errors.ts +44 -12
- package/src/adapters/google-http.ts +38 -10
- package/src/adapters/google-tool-schema.ts +80 -15
- package/src/adapters/google-truncation.ts +11 -0
- package/src/adapters/google.ts +742 -86
- package/src/adapters/identity.ts +39 -6
- package/src/adapters/image.ts +1 -1
- package/src/adapters/kiro-constants.ts +27 -0
- package/src/adapters/kiro-errors.ts +11 -0
- package/src/adapters/kiro-events.ts +19 -1
- package/src/adapters/kiro-thinking.ts +18 -2
- package/src/adapters/kiro-tools.ts +65 -17
- package/src/adapters/kiro.ts +270 -73
- package/src/adapters/mimo-free.ts +17 -0
- package/src/adapters/openai-chat-url.ts +11 -0
- package/src/adapters/openai-chat.ts +1377 -344
- package/src/adapters/openai-responses-url.ts +16 -0
- package/src/adapters/openai-responses.ts +1164 -64
- package/src/adapters/registry.ts +175 -0
- package/src/adapters/responses-tool-schema.ts +67 -0
- package/src/adapters/run-turn-queue.ts +36 -1
- package/src/adapters/tool-call-id.ts +119 -0
- package/src/adapters/tool-catalog-nudge.ts +105 -21
- package/src/adapters/xai-tool-schema.ts +436 -0
- package/src/adapters/xai-web-search.ts +186 -0
- package/src/bridge.ts +512 -92
- package/src/chat/inbound.ts +57 -20
- package/src/chat/outbound.ts +97 -33
- package/src/claude/agents-inject.ts +40 -10
- package/src/claude/context-windows.ts +37 -14
- package/src/claude/desktop-3p.ts +243 -9
- package/src/claude/gateway-cache.ts +41 -4
- package/src/claude/inbound.ts +72 -3
- package/src/claude/model-info.ts +38 -15
- package/src/claude/outbound.ts +88 -21
- package/src/cli/access.ts +46 -3
- package/src/cli/account-api.ts +150 -19
- package/src/cli/account-auth.ts +33 -6
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +648 -28
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +97 -19
- package/src/cli/agent.ts +53 -2
- package/src/cli/alias.ts +66 -0
- package/src/cli/capabilities-command.ts +94 -0
- package/src/cli/capabilities.ts +496 -0
- package/src/cli/claude-agent-startup-sync.ts +73 -0
- package/src/cli/claude-desktop.ts +60 -15
- package/src/cli/claude.ts +129 -35
- package/src/cli/codex-log-guard-doctor.ts +103 -0
- package/src/cli/codex-shim-autorestore.ts +2 -0
- package/src/cli/codex-shim-readiness.ts +76 -0
- package/src/cli/combo.ts +8 -0
- package/src/cli/config-command.ts +74 -10
- package/src/cli/dispatch.ts +821 -0
- package/src/cli/doctor.ts +440 -56
- package/src/cli/ensure-desired-integrations.ts +152 -0
- package/src/cli/export-command.ts +46 -20
- package/src/cli/help.ts +34 -274
- package/src/cli/index.ts +417 -528
- package/src/cli/init.ts +5 -17
- package/src/cli/inspect.ts +230 -0
- package/src/cli/integrations.ts +120 -2
- package/src/cli/lab.ts +607 -0
- package/src/cli/launcher-context.ts +77 -0
- package/src/cli/minimax.ts +497 -0
- package/src/cli/models-runtime.ts +130 -2
- package/src/cli/models.ts +118 -16
- package/src/cli/observe.ts +123 -11
- package/src/cli/opencode.ts +4 -2
- package/src/cli/provider-runtime.ts +34 -3
- package/src/cli/provider.ts +25 -3
- package/src/cli/ready.ts +301 -0
- package/src/cli/registry.ts +476 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +57 -10
- package/src/cli/star-prompt.ts +71 -15
- package/src/cli/status.ts +51 -4
- package/src/cli/storage.ts +234 -0
- package/src/cli/system-command.ts +16 -0
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +153 -6
- package/src/cli/usage-report.ts +184 -0
- package/src/cli/v2.ts +137 -18
- package/src/cli/version-skew.ts +46 -0
- package/src/cli.ts +1 -1
- package/src/clients/config-export.ts +1442 -23
- package/src/clients/effective-status.ts +30 -2
- package/src/clients/probes/cline.ts +81 -0
- package/src/codex/account-label.ts +35 -1
- package/src/codex/account-lifecycle.ts +130 -13
- package/src/codex/account-namespaces.ts +49 -3
- package/src/codex/account-pause.ts +2 -1
- package/src/codex/account-priority.ts +84 -0
- package/src/codex/account-store.ts +29 -2
- package/src/codex/account-usability.ts +25 -2
- package/src/codex/admission.ts +256 -0
- package/src/codex/affinity-debug.ts +162 -0
- package/src/codex/app-server-processes.ts +570 -107
- package/src/codex/app-server-restart-service.ts +232 -0
- package/src/codex/auth-api.ts +893 -246
- package/src/codex/auth-collision.ts +5 -3
- package/src/codex/auth-context.ts +348 -32
- package/src/codex/autostart-health.ts +24 -1
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +86 -10
- package/src/codex/catalog/bundled.ts +331 -33
- package/src/codex/catalog/effort.ts +138 -32
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +555 -45
- package/src/codex/catalog/native-models.ts +75 -0
- package/src/codex/catalog/parsing.ts +269 -30
- package/src/codex/catalog/provider-fetch.ts +1626 -144
- package/src/codex/catalog/sync.ts +1576 -187
- package/src/codex/catalog-admission.ts +199 -0
- package/src/codex/catalog-refresh-status.ts +105 -0
- package/src/codex/catalog-write-serialization.ts +242 -0
- package/src/codex/catalog.ts +6 -3
- package/src/codex/codex-write-lock.ts +386 -0
- package/src/codex/convergence-types.ts +614 -0
- package/src/codex/convergence.ts +676 -0
- package/src/codex/coordinator-doctor.ts +332 -0
- package/src/codex/custom-model-catalog-migration.ts +176 -0
- package/src/codex/desired-state.ts +230 -0
- package/src/codex/desktop-app-restart.ts +355 -0
- package/src/codex/features.ts +636 -39
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +436 -0
- package/src/codex/history-lock.ts +242 -0
- package/src/codex/history-manifest.ts +112 -0
- package/src/codex/history-migration-guardian.ts +30 -24
- package/src/codex/history-provider.ts +1016 -235
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +223 -0
- package/src/codex/inject-coordination.ts +373 -0
- package/src/codex/inject.ts +1114 -152
- package/src/codex/injected-marker.ts +37 -3
- package/src/codex/integration-record.ts +266 -0
- package/src/codex/internal/catalog-writer.ts +203 -0
- package/src/codex/internal/history-writer.ts +81 -0
- package/src/codex/journal.ts +66 -4
- package/src/codex/log-guard/inspect.ts +524 -0
- package/src/codex/log-guard/lock.ts +150 -0
- package/src/codex/log-guard/maintenance.ts +403 -0
- package/src/codex/log-guard/path-safety.ts +88 -0
- package/src/codex/log-guard/policy.ts +44 -0
- package/src/codex/log-guard/processes.ts +205 -0
- package/src/codex/log-guard/protection.ts +489 -0
- package/src/codex/log-guard/sqlite-errors.ts +9 -0
- package/src/codex/main-account-cache.ts +24 -0
- package/src/codex/main-account.ts +29 -1
- package/src/codex/management-convergence.ts +167 -0
- package/src/codex/model-cache.ts +56 -10
- package/src/codex/model-entitlements.ts +360 -0
- package/src/codex/native-main-admission.ts +47 -0
- package/src/codex/native-main-auth-temp.ts +187 -0
- package/src/codex/native-main-claim.ts +178 -0
- package/src/codex/native-main-lock-file.ts +162 -0
- package/src/codex/native-main-owner.ts +329 -0
- package/src/codex/native-profile-api.ts +247 -0
- package/src/codex/native-profile-manager.ts +1531 -0
- package/src/codex/native-profile-processes.ts +121 -0
- package/src/codex/native-profile-recovery.ts +99 -0
- package/src/codex/native-profile-stage-store.ts +387 -0
- package/src/codex/native-profile-startup.ts +622 -0
- package/src/codex/native-profile-store.ts +855 -0
- package/src/codex/native-profile-types.ts +120 -0
- package/src/codex/native-residue.ts +675 -0
- package/src/codex/paths.ts +80 -1
- package/src/codex/plan-from-token.ts +140 -0
- package/src/codex/plan.ts +40 -0
- package/src/codex/plugins-doctor.ts +1 -1
- package/src/codex/pool-rotation.ts +74 -4
- package/src/codex/project-config-warnings.ts +20 -6
- package/src/codex/prompt-journal.ts +352 -0
- package/src/codex/prompt-layers.ts +1313 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/prompt-text-probe.ts +238 -0
- package/src/codex/quota-rejection.ts +298 -0
- package/src/codex/quota.ts +264 -21
- package/src/codex/refresh.ts +11 -2
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/routing.ts +514 -94
- package/src/codex/runtime.ts +159 -38
- package/src/codex/shim.ts +1065 -31
- package/src/codex/subagent-model-fallback.ts +437 -43
- package/src/codex/sync.ts +191 -2
- package/src/codex/transition-state.ts +720 -0
- package/src/codex/upstream-host-health.ts +368 -0
- package/src/codex/user-identity.ts +557 -0
- package/src/codex/warmup.ts +187 -81
- package/src/codex/write-coordination.ts +114 -0
- package/src/combos/failover.ts +47 -0
- package/src/combos/index.ts +4 -0
- package/src/combos/request.ts +32 -0
- package/src/combos/types.ts +91 -9
- package/src/compatibility/index.ts +26 -0
- package/src/compatibility/manifest.ts +253 -0
- package/src/compatibility/openai-responses.ts +121 -0
- package/src/config/atomic-write.ts +219 -0
- package/src/config/paths.ts +40 -0
- package/src/config/process-state.ts +309 -0
- package/src/config/provider-name.ts +24 -0
- package/src/config/provider-validation.ts +177 -0
- package/src/config/rebase-provenance.ts +68 -0
- package/src/config.ts +1713 -709
- package/src/generated/compatibility-version.json +3324 -0
- package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
- package/src/grok/inject.ts +16 -5
- package/src/grok/inspect.ts +45 -0
- package/src/grok/sync.ts +2 -2
- package/src/images/loop.ts +157 -33
- package/src/images/plan.ts +24 -13
- package/src/integrations/config-io.ts +269 -0
- package/src/integrations/journal.ts +315 -0
- package/src/integrations/merge.ts +135 -0
- package/src/integrations/mutation-flight.ts +71 -0
- package/src/integrations/native/ownership-preflight.ts +202 -0
- package/src/integrations/omp-yaml-source.ts +358 -0
- package/src/integrations/owned-refresh.ts +74 -0
- package/src/integrations/ownership-policy.ts +160 -0
- package/src/integrations/ownership.ts +155 -0
- package/src/integrations/registry.ts +166 -0
- package/src/integrations/serialize.ts +314 -0
- package/src/integrations/state.ts +433 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer-lock.ts +98 -0
- package/src/integrations/writer.ts +715 -0
- package/src/lab/artifacts/sanitize.ts +586 -0
- package/src/lab/artifacts/secure-fs.ts +475 -0
- package/src/lab/artifacts/store.ts +310 -0
- package/src/lab/automation/budgets.ts +78 -0
- package/src/lab/automation/config-persistence.ts +256 -0
- package/src/lab/automation/constants.ts +39 -0
- package/src/lab/automation/cooldown.ts +103 -0
- package/src/lab/automation/dispatch.ts +211 -0
- package/src/lab/automation/index.ts +13 -0
- package/src/lab/automation/orchestrator.ts +499 -0
- package/src/lab/automation/persistence.ts +512 -0
- package/src/lab/automation/planner.ts +371 -0
- package/src/lab/automation/policy.ts +136 -0
- package/src/lab/automation/queue.ts +191 -0
- package/src/lab/automation/recovery.ts +24 -0
- package/src/lab/automation/route-context.ts +21 -0
- package/src/lab/automation/run-key.ts +44 -0
- package/src/lab/automation/runs-query.ts +34 -0
- package/src/lab/automation/types.ts +160 -0
- package/src/lab/conformance/assertion.ts +325 -0
- package/src/lab/conformance/digest.ts +22 -0
- package/src/lab/conformance/executor.ts +741 -0
- package/src/lab/conformance/fixture-provider.ts +27 -0
- package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
- package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
- package/src/lab/conformance/harness-budget.ts +47 -0
- package/src/lab/conformance/index.ts +5 -0
- package/src/lab/conformance/jcs.ts +64 -0
- package/src/lab/conformance/json-pointer.ts +39 -0
- package/src/lab/conformance/manifest.ts +180 -0
- package/src/lab/conformance/mcp-stub.ts +179 -0
- package/src/lab/conformance/negative-controls.ts +164 -0
- package/src/lab/conformance/observation.ts +355 -0
- package/src/lab/conformance/runner.ts +68 -0
- package/src/lab/conformance/sse-normalize.ts +59 -0
- package/src/lab/conformance/suite-manifest.ts +78 -0
- package/src/lab/conformance/types.ts +214 -0
- package/src/lab/constants.ts +126 -0
- package/src/lab/digest.ts +64 -0
- package/src/lab/events/errors.ts +9 -0
- package/src/lab/events/limits.ts +117 -0
- package/src/lab/events/types.ts +229 -0
- package/src/lab/events/validate.ts +781 -0
- package/src/lab/fabric/constants.ts +40 -0
- package/src/lab/fabric/executor.ts +492 -0
- package/src/lab/fabric/index.ts +80 -0
- package/src/lab/fabric/manifest.ts +222 -0
- package/src/lab/fabric/observe.ts +489 -0
- package/src/lab/fabric/patch.ts +79 -0
- package/src/lab/fabric/producer-child.ts +139 -0
- package/src/lab/fabric/producer-isolate.ts +276 -0
- package/src/lab/fabric/producer-protocol.ts +61 -0
- package/src/lab/fabric/scratch.ts +439 -0
- package/src/lab/fabric/subject.ts +106 -0
- package/src/lab/fabric/types.ts +134 -0
- package/src/lab/fabric/verifier.ts +98 -0
- package/src/lab/index.ts +54 -0
- package/src/lab/ledger/artifact-refs.ts +127 -0
- package/src/lab/ledger/invalidation.ts +136 -0
- package/src/lab/ledger/purge.ts +310 -0
- package/src/lab/ledger/store.ts +532 -0
- package/src/lab/live/credential-lease.ts +53 -0
- package/src/lab/live/destination.ts +155 -0
- package/src/lab/live/executor.ts +336 -0
- package/src/lab/live/inert-tools.ts +56 -0
- package/src/lab/live/manifest.ts +85 -0
- package/src/lab/live/mcp-loopback.ts +57 -0
- package/src/lab/live/runner.ts +19 -0
- package/src/lab/live/sandbox.ts +61 -0
- package/src/lab/live/suite-manifest.ts +41 -0
- package/src/lab/live/transport.ts +118 -0
- package/src/lab/live/types.ts +197 -0
- package/src/lab/observe/from-conformance.ts +301 -0
- package/src/lab/observe/from-live.ts +117 -0
- package/src/lab/paths.ts +153 -0
- package/src/lab/projection/rebuild.ts +495 -0
- package/src/lab/projection/schema.ts +135 -0
- package/src/lab/projection/verdicts.ts +474 -0
- package/src/lab/projection/verification.ts +412 -0
- package/src/lab/public/bundle.ts +217 -0
- package/src/lab/public/community-authority.ts +175 -0
- package/src/lab/public/community-files.ts +29 -0
- package/src/lab/public/community.ts +479 -0
- package/src/lab/public/file-safety.ts +155 -0
- package/src/lab/public/ids.ts +26 -0
- package/src/lab/public/index.ts +16 -0
- package/src/lab/public/mutation-lock.ts +424 -0
- package/src/lab/public/operator.ts +353 -0
- package/src/lab/public/origin-purge.ts +79 -0
- package/src/lab/public/origin.ts +203 -0
- package/src/lab/public/privacy.ts +143 -0
- package/src/lab/public/private-file.ts +261 -0
- package/src/lab/public/project.ts +124 -0
- package/src/lab/public/purge-test-fault.ts +21 -0
- package/src/lab/public/purge.ts +223 -0
- package/src/lab/public/registry.ts +44 -0
- package/src/lab/public/revocation.ts +252 -0
- package/src/lab/public/signature.ts +243 -0
- package/src/lab/public/storage.ts +105 -0
- package/src/lab/public/strict-json.ts +206 -0
- package/src/lab/public/time.ts +26 -0
- package/src/lab/public/types.ts +172 -0
- package/src/lab/public/validate.ts +391 -0
- package/src/lab/query/catalog.ts +101 -0
- package/src/lab/query/connection.ts +107 -0
- package/src/lab/query/constants.ts +4 -0
- package/src/lab/query/cursor.ts +132 -0
- package/src/lab/query/dto-map.ts +277 -0
- package/src/lab/query/errors.ts +22 -0
- package/src/lab/query/freshness.ts +53 -0
- package/src/lab/query/index.ts +45 -0
- package/src/lab/query/latest-observation.ts +59 -0
- package/src/lab/query/passive-production.ts +159 -0
- package/src/lab/query/queries.ts +444 -0
- package/src/lab/query/types.ts +266 -0
- package/src/lab/subject/behavior-fingerprint.ts +77 -0
- package/src/lab/subject/installation-salt.ts +112 -0
- package/src/lab/subject/protocol-subject.ts +80 -0
- package/src/lab/subject/route-subject.ts +74 -0
- package/src/lib/admin-secrets.ts +24 -0
- package/src/lib/app-owned-memory-stores.ts +22 -0
- package/src/lib/bounded-body.ts +167 -11
- package/src/lib/bun-runtime.ts +125 -12
- package/src/lib/bun-stream-caps.ts +13 -9
- package/src/lib/codex-restart-contract.ts +120 -0
- package/src/lib/config-ownership.ts +26 -2
- package/src/lib/destination-policy.ts +65 -1
- package/src/lib/errors.ts +80 -5
- package/src/lib/fabric-task-execution-authority.ts +7 -0
- package/src/lib/fabric-task-host.ts +29 -0
- package/src/lib/lab-activation.ts +223 -0
- package/src/lib/lab-live-execution-authority.ts +13 -0
- package/src/lib/lab-live-host.ts +30 -0
- package/src/lib/lab-live-pinned-sender.ts +56 -0
- package/src/lib/lab-live-route-production.ts +130 -0
- package/src/lib/lab-passive-linker-registration.ts +26 -0
- package/src/lib/local-management-attestation.ts +51 -0
- package/src/lib/local-management-capability.ts +100 -0
- package/src/lib/local-provider-reload-contract.ts +100 -0
- package/src/lib/optional-shutdown-hooks.ts +57 -0
- package/src/lib/package-tree-integrity.ts +101 -0
- package/src/lib/pinned-http.ts +145 -26
- package/src/lib/process-control.ts +6 -2
- package/src/lib/provider-outbound.ts +49 -9
- package/src/lib/redact.ts +419 -3
- package/src/lib/self-launch-argv.ts +15 -0
- package/src/lib/server-resource-ownership.ts +71 -0
- package/src/lib/service-secrets.ts +15 -0
- package/src/lib/shadow-call.ts +35 -4
- package/src/lib/sse-decoder.ts +41 -0
- package/src/lib/state-store-registrations.ts +10 -2
- package/src/lib/system-restart-contract.ts +73 -0
- package/src/lib/token-estimate.ts +19 -2
- package/src/lib/tool-argument-integers.ts +253 -0
- package/src/lib/translator-budget.ts +44 -0
- package/src/lib/upstream-http-version.ts +57 -0
- package/src/lib/upstream-reachability.ts +95 -0
- package/src/lib/upstream-retry.ts +156 -3
- package/src/lib/windows-atomic-replace.ts +155 -0
- package/src/lib/windows-elevation.ts +70 -2
- package/src/lib/windows-secret-acl.ts +409 -69
- package/src/lib/windows-service-wrappers.ts +72 -0
- package/src/lib/windows-text.ts +106 -0
- package/src/lib/windows-user-principal.ts +341 -0
- package/src/lib/winsw.ts +33 -5
- package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
- package/src/oauth/account-import/index.ts +15 -0
- package/src/oauth/account-import/parser.ts +83 -0
- package/src/oauth/account-import/registry.ts +18 -0
- package/src/oauth/account-import/service.ts +75 -0
- package/src/oauth/account-import/types.ts +91 -0
- package/src/oauth/anthropic.ts +12 -1
- package/src/oauth/callback-server.ts +30 -4
- package/src/oauth/chatgpt.ts +12 -1
- package/src/oauth/cline.ts +203 -0
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +46 -5
- package/src/oauth/generic-account-failover.ts +231 -0
- package/src/oauth/google-antigravity.ts +35 -3
- package/src/oauth/health.ts +20 -12
- package/src/oauth/index.ts +462 -71
- package/src/oauth/key-providers.ts +25 -0
- package/src/oauth/kimi.ts +25 -3
- package/src/oauth/kiro.ts +95 -6
- package/src/oauth/local-token-detect.ts +13 -2
- package/src/oauth/log.ts +3 -1
- package/src/oauth/login-cli.ts +88 -28
- package/src/oauth/nous.ts +798 -0
- package/src/oauth/open-browser-choice.ts +26 -0
- package/src/oauth/store.ts +133 -26
- package/src/oauth/token-guardian.ts +9 -3
- package/src/oauth/types.ts +15 -0
- package/src/pi/models.ts +2 -2
- package/src/providers/alibaba-region-migration.ts +1 -1
- package/src/providers/antigravity-models.ts +521 -31
- package/src/providers/auto-compact-budget.ts +65 -0
- package/src/providers/base-url-choices.ts +10 -0
- package/src/providers/codex-capacity.ts +292 -0
- package/src/providers/command-code-efforts.ts +176 -0
- package/src/providers/context-cap.ts +26 -8
- package/src/providers/cursor-pool.ts +72 -0
- package/src/providers/default-aliases.ts +65 -0
- package/src/providers/derive.ts +281 -6
- package/src/providers/fastwire.ts +507 -0
- package/src/providers/free-directory.ts +10 -7
- package/src/providers/google-vertex-location.ts +14 -0
- package/src/providers/key-failover.ts +71 -3
- package/src/providers/label.ts +35 -2
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +115 -22
- package/src/providers/model-presets.ts +119 -0
- package/src/providers/model-rename-migration.ts +255 -0
- package/src/providers/model-rename-startup.ts +28 -0
- package/src/providers/new-model-policy.ts +146 -0
- package/src/providers/openai-sidecar.ts +72 -4
- package/src/providers/openai-tier-startup.ts +31 -2
- package/src/providers/openai-tiers.ts +119 -4
- package/src/providers/openai-virtual-models.ts +1 -0
- package/src/providers/opencode-zen-rate-limit.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +30 -0
- package/src/providers/quota.ts +1379 -40
- package/src/providers/registry.ts +1545 -112
- package/src/providers/request-pacing.ts +310 -0
- package/src/providers/service-tier.ts +277 -0
- package/src/providers/slug-codec.ts +94 -6
- package/src/providers/static-model-discovery.ts +86 -0
- package/src/providers/xai-responses-opt-in.ts +15 -0
- package/src/providers/xai-transport.ts +32 -4
- package/src/reasoning-effort.ts +68 -3
- package/src/responses/apply-patch-envelope.ts +63 -0
- package/src/responses/code-mode-helper-compat.ts +50 -0
- package/src/responses/compaction.ts +26 -1
- package/src/responses/custom-tool-compat.ts +384 -0
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/namespace-tool-compat.ts +435 -0
- package/src/responses/parser.ts +225 -38
- package/src/responses/provider-continuation.ts +98 -0
- package/src/responses/provider-opaque-metadata.ts +73 -0
- package/src/responses/reasoning-envelope.ts +9 -1
- package/src/responses/reasoning-replay-cache.ts +504 -0
- package/src/responses/schema.ts +12 -2
- package/src/responses/spill-store.ts +75 -10
- package/src/responses/state.ts +659 -31
- package/src/responses/thought-signature-replay.ts +364 -0
- package/src/responses/tool-search-compat.ts +301 -0
- package/src/responses/truncated-stop-reason.ts +60 -0
- package/src/responses/turn-termination.ts +107 -0
- package/src/router.ts +405 -31
- package/src/routing/analytics.ts +379 -0
- package/src/routing/capability.ts +244 -0
- package/src/routing/compatibility/assemble.ts +73 -0
- package/src/routing/compatibility/behavior.ts +278 -0
- package/src/routing/compatibility/catalog.ts +99 -0
- package/src/routing/compatibility/endpoint.ts +52 -0
- package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
- package/src/routing/compatibility/policy.ts +181 -0
- package/src/routing/compatibility/provider-slot.ts +56 -0
- package/src/routing/compatibility/reader.ts +110 -0
- package/src/routing/compatibility/subject.ts +191 -0
- package/src/routing/compatibility/types.ts +64 -0
- package/src/routing/compatibility/version.ts +104 -0
- package/src/routing/cost.ts +77 -0
- package/src/routing/evaluator.ts +495 -0
- package/src/routing/health.ts +412 -0
- package/src/routing/history/cursor.ts +43 -0
- package/src/routing/history/indexer.ts +605 -0
- package/src/routing/history/schema.ts +72 -0
- package/src/routing/profile-namespace.ts +15 -0
- package/src/routing/profile.ts +547 -0
- package/src/routing/quota.ts +155 -0
- package/src/routing/request-evidence.ts +45 -0
- package/src/routing/trace.ts +776 -0
- package/src/server/adapter-resolve.ts +2 -29
- package/src/server/auth-cors.ts +289 -48
- package/src/server/background-lifecycle.ts +182 -0
- package/src/server/chat-completions.ts +154 -72
- package/src/server/chat-native-sse.ts +331 -0
- package/src/server/chat-native.ts +445 -0
- package/src/server/claude-messages.ts +160 -44
- package/src/server/direct-local-http.ts +347 -0
- package/src/server/effort-policy.ts +18 -0
- package/src/server/github-copilot-responses-repair.ts +338 -0
- package/src/server/gui-static.ts +39 -10
- package/src/server/images.ts +94 -12
- package/src/server/index.ts +1021 -190
- package/src/server/lifecycle.ts +336 -14
- package/src/server/live.ts +136 -17
- package/src/server/local-management-read-client.ts +90 -0
- package/src/server/local-provider-reload-client.ts +137 -0
- package/src/server/management/agent-settings-routes.ts +433 -116
- package/src/server/management/api-key-usage.ts +31 -5
- package/src/server/management/body.ts +6 -0
- package/src/server/management/codex-prompt-routes.ts +570 -0
- package/src/server/management/combo-routes.ts +64 -25
- package/src/server/management/config-routes.ts +511 -51
- package/src/server/management/context.ts +89 -2
- package/src/server/management/integration-routes.ts +498 -0
- package/src/server/management/lab-automation-routes.ts +206 -0
- package/src/server/management/lab-routes.ts +563 -0
- package/src/server/management/logs-usage-routes.ts +127 -52
- package/src/server/management/model-routes.ts +461 -133
- package/src/server/management/model-rows.ts +167 -0
- package/src/server/management/native-integration-routes.ts +770 -0
- package/src/server/management/oauth-account-routes.ts +90 -8
- package/src/server/management/provider-capability-config.ts +48 -0
- package/src/server/management/provider-routes.ts +836 -159
- package/src/server/management/request-history-routes.ts +191 -0
- package/src/server/management/route-registry.ts +332 -0
- package/src/server/management/routing-analytics-routes.ts +74 -0
- package/src/server/management/routing-profile-routes.ts +380 -0
- package/src/server/management/shared.ts +27 -11
- package/src/server/management/sidebar-routes.ts +47 -31
- package/src/server/management/storage-log-guard-routes.ts +186 -0
- package/src/server/management/sync-response.ts +69 -0
- package/src/server/management/system-restart.ts +289 -33
- package/src/server/management/system-routes.ts +77 -0
- package/src/server/management/usage-summary-cache.ts +9 -1
- package/src/server/management/vision-sidecar-options.ts +167 -0
- package/src/server/management/web-search-sidecar-options.ts +120 -0
- package/src/server/management-api.ts +126 -23
- package/src/server/management-auth.ts +220 -5
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/port-reclaim.ts +1 -1
- package/src/server/ports.ts +41 -1
- package/src/server/proxy-liveness.ts +161 -10
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +221 -54
- package/src/server/relay.ts +479 -87
- package/src/server/request-decompress.ts +113 -6
- package/src/server/request-log-conversation.ts +51 -0
- package/src/server/request-log.ts +298 -31
- package/src/server/responses/agent-task-recovery-cache.ts +143 -0
- package/src/server/responses/agent-task-recovery.ts +465 -0
- package/src/server/responses/codex-auth-error.ts +55 -0
- package/src/server/responses/collaboration.ts +239 -36
- package/src/server/responses/combo-stream-preflight.ts +178 -0
- package/src/server/responses/compact.ts +444 -72
- package/src/server/responses/core.ts +3579 -436
- package/src/server/responses/empty-completion-guard.ts +333 -0
- package/src/server/responses/encrypted-payload.ts +62 -39
- package/src/server/responses/fetch-helpers.ts +89 -99
- package/src/server/responses/input-admission.ts +187 -0
- package/src/server/responses/pacing-overload.ts +13 -0
- package/src/server/responses/passthrough-error.ts +33 -9
- package/src/server/responses/policy-fallback.ts +178 -0
- package/src/server/responses/responses-field-backfill.ts +343 -0
- package/src/server/responses/terminal-guard.ts +26 -5
- package/src/server/responses/upstream-error.ts +5 -0
- package/src/server/responses/ws-upstream.ts +381 -0
- package/src/server/responses-custom-tool-repair.ts +363 -0
- package/src/server/responses-item-id-repair.ts +54 -6
- package/src/server/responses-json-events.ts +90 -0
- package/src/server/responses-model-rewrite.ts +29 -0
- package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
- package/src/server/responses-snapshot-repair.ts +621 -0
- package/src/server/responses-terminal-repair.ts +363 -0
- package/src/server/responses-tool-search-repair.ts +267 -0
- package/src/server/responses-undeclared-tool-guard.ts +376 -0
- package/src/server/responses.ts +18 -2
- package/src/server/search.ts +78 -13
- package/src/server/sse-frame-buffer.ts +319 -0
- package/src/server/sse-payload-rewrite.ts +110 -22
- package/src/server/startup-action-control.ts +8 -1
- package/src/server/startup-health-cache.ts +19 -1
- package/src/server/system-env.ts +80 -9
- package/src/server/ws-bridge.ts +53 -40
- package/src/service-manager-probe.ts +892 -0
- package/src/service.ts +1153 -94
- package/src/sidecar/auth.ts +92 -0
- package/src/sidecar/candidates.ts +83 -0
- package/src/storage/cleanup.ts +2 -2
- package/src/storage/policy-job.ts +14 -4
- package/src/storage/policy.ts +88 -23
- package/src/storage/scanner.ts +1 -1
- package/src/storage/worker-lifecycle.ts +14 -14
- package/src/tray/windows-tray.ps1 +83 -9
- package/src/tray/windows.ts +43 -16
- package/src/types/accounts.ts +37 -0
- package/src/types/config.ts +911 -0
- package/src/types/provider.ts +614 -0
- package/src/types/request.ts +397 -0
- package/src/types/tools.ts +236 -0
- package/src/types/wire.ts +80 -0
- package/src/types.ts +107 -1237
- package/src/update/index.ts +37 -23
- package/src/update/job.ts +445 -68
- package/src/update/notify.ts +12 -6
- package/src/update/npm-cache-preflight.d.mts +47 -0
- package/src/update/npm-cache-preflight.mjs +201 -0
- package/src/update/transactional-install.d.mts +22 -0
- package/src/update/transactional-install.mjs +266 -0
- package/src/usage/cost.ts +0 -0
- package/src/usage/expected-prices.ts +287 -16
- package/src/usage/log.ts +666 -50
- package/src/usage/summary.ts +388 -17
- package/src/usage/user-cost-overlay-reconciler.ts +313 -0
- package/src/usage/user-cost-overlays.ts +314 -0
- package/src/vision/anthropic-describe.ts +10 -6
- package/src/vision/backends.ts +97 -0
- package/src/vision/describe.ts +27 -16
- package/src/vision/eligibility.ts +250 -0
- package/src/vision/index.ts +238 -24
- package/src/vision/reasoning.ts +55 -0
- package/src/vision/routed-describe.ts +175 -0
- package/src/vision/timeout-bounds.ts +9 -0
- package/src/web-search/anthropic-executor.ts +13 -7
- package/src/web-search/backends.ts +108 -0
- package/src/web-search/exa-executor.ts +119 -0
- package/src/web-search/executor.ts +21 -6
- package/src/web-search/gemini-executor.ts +141 -0
- package/src/web-search/index.ts +150 -15
- package/src/web-search/loop.ts +284 -54
- package/src/web-search/parse.ts +125 -30
- package/src/web-search/sources.ts +60 -0
- package/src/web-search/xai-executor.ts +219 -0
- package/gui/dist/assets/index-DTpMHS4F.js +0 -67
- package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
- package/gui/dist/provider-icons/antigravity.svg +0 -1
- package/gui/dist/provider-icons/claude.svg +0 -1
- package/gui/dist/provider-icons/copilot.svg +0 -1
- package/gui/dist/provider-icons/cursor.svg +0 -2
- package/gui/dist/provider-icons/gemini.svg +0 -1
- package/gui/dist/provider-icons/grok-color.svg +0 -1
- package/gui/dist/provider-icons/kiro.svg +0 -14
- package/src/cli/internal-dispatch.ts +0 -20
|
@@ -0,0 +1,821 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry-driven command dispatch (Phase 3 of the CLI deepening).
|
|
3
|
+
*
|
|
4
|
+
* The command switch moved out of src/cli/index.ts into a runner table keyed
|
|
5
|
+
* by command name. Aliases resolve through the registry's alias pairs
|
|
6
|
+
* (init/setup, restore/eject, uninstall/remove, models/model); the registry
|
|
7
|
+
* remains the single source of command metadata. index.ts passes its local
|
|
8
|
+
* helpers (start/stop/ensure/status/...) through CliDispatchDeps so dispatch
|
|
9
|
+
* never needs to import the entry module back (no cycle).
|
|
10
|
+
*/
|
|
11
|
+
import { CLI_COMMANDS } from "./registry";
|
|
12
|
+
import { isValidProviderName } from "../config/provider-name";
|
|
13
|
+
import type { CliHead } from "./root";
|
|
14
|
+
import type { ReadyArgs } from "./ready";
|
|
15
|
+
import type { LiveProxy } from "../server/proxy-liveness";
|
|
16
|
+
import type { OcxConfig } from "../types";
|
|
17
|
+
import { hasHelpFlag, printSubcommandUsage, printUsage } from "./help";
|
|
18
|
+
import { setIntegrationEnabled, shouldSyncCodexOnStart } from "../codex/desired-state";
|
|
19
|
+
import { syncModelsToCodex } from "../codex/sync";
|
|
20
|
+
import { collectOrcaCodexHomeDiagnostic } from "../codex/home";
|
|
21
|
+
import { restoreNativeCodexAsync } from "../codex/inject";
|
|
22
|
+
import { stripGrokConfig } from "../grok/inject";
|
|
23
|
+
import { afterCatalogWriteHandleAppServers } from "../codex/app-server-processes";
|
|
24
|
+
import { normalizeUpdateChannel, runGuiUpdateWorker } from "../update/job";
|
|
25
|
+
import { isJsonOption, takeFlag } from "./runtime-api";
|
|
26
|
+
|
|
27
|
+
export interface CliDispatchDeps {
|
|
28
|
+
args: string[];
|
|
29
|
+
command: string | undefined;
|
|
30
|
+
head: CliHead;
|
|
31
|
+
loadConfig: () => OcxConfig;
|
|
32
|
+
findLiveProxy: () => Promise<LiveProxy | null>;
|
|
33
|
+
probeHostname: (hostname: string | undefined) => string;
|
|
34
|
+
waitForProxy: (timeoutMs?: number) => Promise<LiveProxy | null>;
|
|
35
|
+
startArgv: (port?: number) => string[];
|
|
36
|
+
/** Spawn a detached proxy child (stdio ignore, unref'd, provenance env). */
|
|
37
|
+
spawnDetached: (argv: readonly string[]) => void;
|
|
38
|
+
handleStart: () => Promise<void>;
|
|
39
|
+
handleStop: () => Promise<boolean>;
|
|
40
|
+
handleEnsure: (options?: { existingIsSuccess?: boolean }) => Promise<boolean>;
|
|
41
|
+
handleTrayProxyStart: (existingIsSuccess?: boolean) => Promise<boolean>;
|
|
42
|
+
handleTrayProxyRestart: () => Promise<void>;
|
|
43
|
+
handleRestartStartWhenStopped: () => Promise<boolean | "skipped">;
|
|
44
|
+
handleProxyRestart: (startWhenStopped: () => Promise<boolean | "skipped">) => Promise<boolean>;
|
|
45
|
+
handleUninstall: () => Promise<void>;
|
|
46
|
+
handleStatus: () => Promise<void>;
|
|
47
|
+
handleRecoverHistory: () => Promise<void>;
|
|
48
|
+
handleReady: (args: ReadyArgs) => Promise<number>;
|
|
49
|
+
serviceCommand: (...args: string[]) => Promise<void>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type CommandRunner = (deps: CliDispatchDeps) => Promise<number>;
|
|
53
|
+
|
|
54
|
+
const commandRunners: Record<string, CommandRunner> = {
|
|
55
|
+
init: async () => {
|
|
56
|
+
const { runInit } = await import("./init");
|
|
57
|
+
await runInit();
|
|
58
|
+
// runInit sets process.exitCode = 1 on stdin EOF/closed; preserve it.
|
|
59
|
+
return Number(process.exitCode ?? 0);
|
|
60
|
+
},
|
|
61
|
+
start: async deps => {
|
|
62
|
+
await deps.handleStart();
|
|
63
|
+
return Number(process.exitCode ?? 0);
|
|
64
|
+
},
|
|
65
|
+
stop: async deps => {
|
|
66
|
+
// Downtime warning lives HERE, not in handleStop: `restart`/tray-restart callers
|
|
67
|
+
// re-start the proxy immediately, so warning there would contradict the next line.
|
|
68
|
+
if (await deps.handleStop()) {
|
|
69
|
+
console.log("⚠️ Codex/Claude requests through the proxy will fail until it is restarted ('ocx start' or 'ocx service start').");
|
|
70
|
+
}
|
|
71
|
+
return Number(process.exitCode ?? 0);
|
|
72
|
+
},
|
|
73
|
+
restore: async deps => {
|
|
74
|
+
const restoreArgs = deps.args.slice(1);
|
|
75
|
+
const restoreJson = takeFlag(restoreArgs, "--json");
|
|
76
|
+
if (restoreArgs[0] === "back") {
|
|
77
|
+
// Reverse switch: re-point plain `codex` at the RUNNING proxy without touching its
|
|
78
|
+
// lifecycle — the counterpart of `ocx restore`. Start/stop triggers are unchanged;
|
|
79
|
+
// this only re-runs the same inject (config + catalog + history) `ocx start` does.
|
|
80
|
+
// takeFlag above makes `ocx restore --json back` restore-back, not eject.
|
|
81
|
+
const { skippedRestoreEnvelope } = await import("../codex/inject");
|
|
82
|
+
const emitBack = (success: boolean, message: string, code: number): number => {
|
|
83
|
+
if (restoreJson) console.log(JSON.stringify(skippedRestoreEnvelope(success, message)));
|
|
84
|
+
else if (code === 0) console.log(message);
|
|
85
|
+
else console.error(message);
|
|
86
|
+
return code;
|
|
87
|
+
};
|
|
88
|
+
const live = await deps.findLiveProxy();
|
|
89
|
+
if (!live) {
|
|
90
|
+
return emitBack(false, "No running proxy found. Run 'ocx start' — it injects opencodex automatically.", 1);
|
|
91
|
+
}
|
|
92
|
+
const desired = setIntegrationEnabled("codex", true);
|
|
93
|
+
if (!desired.ok) {
|
|
94
|
+
return emitBack(false, `Codex desired state was not saved (${desired.reason}).`, desired.reason === "conflict" ? 2 : 1);
|
|
95
|
+
}
|
|
96
|
+
const synced = await syncModelsToCodex(live.port);
|
|
97
|
+
if (synced.status === "skipped") {
|
|
98
|
+
return emitBack(false, "Codex integration is OFF; restore back did not change Codex. Retry after the competing integration change finishes.", 2);
|
|
99
|
+
}
|
|
100
|
+
if (!synced.ok) {
|
|
101
|
+
return emitBack(false, "Plain `codex` was not switched back to opencodex. Fix the reported Codex config issue and retry.", 1);
|
|
102
|
+
}
|
|
103
|
+
const target = collectOrcaCodexHomeDiagnostic();
|
|
104
|
+
return emitBack(true, `Plain \`codex\` now routes through opencodex in ${target.effectiveCodexHome} (undo with: ocx restore).`, 0);
|
|
105
|
+
}
|
|
106
|
+
const desired = setIntegrationEnabled("codex", false);
|
|
107
|
+
if (!desired.ok) {
|
|
108
|
+
if (restoreJson) {
|
|
109
|
+
// Machine-readable contract: every restore --json outcome emits one
|
|
110
|
+
// schema-complete envelope on stdout, including pre-machinery failures.
|
|
111
|
+
const { skippedRestoreEnvelope } = await import("../codex/inject");
|
|
112
|
+
console.log(JSON.stringify(skippedRestoreEnvelope(false, `Codex desired state was not saved (${desired.reason}).`)));
|
|
113
|
+
} else {
|
|
114
|
+
console.error(`Codex desired state was not saved (${desired.reason}).`);
|
|
115
|
+
}
|
|
116
|
+
return desired.reason === "conflict" ? 2 : 1;
|
|
117
|
+
}
|
|
118
|
+
// A repeated OFF on an already-clean home is a policy no-op. Do not enter
|
|
119
|
+
// restore's native-profile machinery merely to prove there is nothing to
|
|
120
|
+
// restore: those locks live in CODEX_HOME and a skip must create nothing.
|
|
121
|
+
if (desired.status === "unchanged") {
|
|
122
|
+
const { classifyNativeRoutedResidue } = await import("../codex/native-residue");
|
|
123
|
+
if (classifyNativeRoutedResidue().kind === "clean") {
|
|
124
|
+
const alreadyOff = "Codex integration is already OFF and native; no Codex files changed.";
|
|
125
|
+
if (restoreJson) {
|
|
126
|
+
const { skippedRestoreEnvelope } = await import("../codex/inject");
|
|
127
|
+
console.log(JSON.stringify(skippedRestoreEnvelope(true, alreadyOff)));
|
|
128
|
+
} else {
|
|
129
|
+
console.log(alreadyOff);
|
|
130
|
+
}
|
|
131
|
+
return 0;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
let r: { success: boolean; message: string };
|
|
135
|
+
try {
|
|
136
|
+
r = await restoreNativeCodexAsync({ revalidateDesiredState: true });
|
|
137
|
+
} catch (err) {
|
|
138
|
+
r = { success: false, message: err instanceof Error ? err.message : String(err) };
|
|
139
|
+
}
|
|
140
|
+
if (restoreJson) {
|
|
141
|
+
// Spawned callers need the artifact-level result to distinguish a busy
|
|
142
|
+
// history worker from a successful native restore. Keep stdout machine
|
|
143
|
+
// readable; human framing remains the default command contract.
|
|
144
|
+
console.log(JSON.stringify(r));
|
|
145
|
+
return r.success ? 0 : 1;
|
|
146
|
+
}
|
|
147
|
+
if (r.success) console.log(`✅ ${r.message}`);
|
|
148
|
+
else {
|
|
149
|
+
console.error(`⚠️ ${r.message}`);
|
|
150
|
+
}
|
|
151
|
+
let code = r.success ? 0 : 1;
|
|
152
|
+
try {
|
|
153
|
+
const g = stripGrokConfig();
|
|
154
|
+
if (g.changed) console.log(`✅ ${g.message}`);
|
|
155
|
+
else if (!g.ok) {
|
|
156
|
+
console.error(`⚠️ ${g.message}`);
|
|
157
|
+
code = 1;
|
|
158
|
+
}
|
|
159
|
+
} catch { /* best-effort */ }
|
|
160
|
+
if (r.success) {
|
|
161
|
+
console.log("Codex integration is OFF and plain `codex` now runs natively. Switch back with: ocx restore back");
|
|
162
|
+
} else {
|
|
163
|
+
console.error("Plain `codex` was not fully restored. Inspect $CODEX_HOME/config.toml before using native Codex.");
|
|
164
|
+
}
|
|
165
|
+
return code;
|
|
166
|
+
},
|
|
167
|
+
"recover-history": async deps => {
|
|
168
|
+
await deps.handleRecoverHistory();
|
|
169
|
+
return Number(process.exitCode ?? 0);
|
|
170
|
+
},
|
|
171
|
+
uninstall: async deps => {
|
|
172
|
+
await deps.handleUninstall();
|
|
173
|
+
return Number(process.exitCode ?? 0);
|
|
174
|
+
},
|
|
175
|
+
status: async deps => {
|
|
176
|
+
await deps.handleStatus();
|
|
177
|
+
return Number(process.exitCode ?? 0);
|
|
178
|
+
},
|
|
179
|
+
doctor: async deps => {
|
|
180
|
+
const doctorArgs = deps.args.slice(1);
|
|
181
|
+
// `--json` was silently ignored here: runDoctor scans for its own flags and prints human
|
|
182
|
+
// output regardless, so a caller that asked for JSON got prose and exit 0 -- and the skill
|
|
183
|
+
// recipes recommended exactly that invocation. Refusing it is worse than supporting it and
|
|
184
|
+
// better than lying about it.
|
|
185
|
+
//
|
|
186
|
+
// Not implemented rather than deferred silently: runDoctor has no report collection at all
|
|
187
|
+
// (a module-level failure bit plus ~90 direct console emissions), and this runner appends
|
|
188
|
+
// the Codex Log Guard's human output after it returns, so emitting a JSON document here
|
|
189
|
+
// would interleave prose with JSON on one stdout -- unparseable, which is worse than the
|
|
190
|
+
// ignored flag. The structured-report refactor is tracked as its own work-phase.
|
|
191
|
+
if (doctorArgs.some(isJsonOption)) {
|
|
192
|
+
console.error("ocx doctor does not support --json yet. Run `ocx doctor` for the human report, or use `ocx status --json` and `ocx ready --json` for machine-readable health.");
|
|
193
|
+
return 2;
|
|
194
|
+
}
|
|
195
|
+
const { RECOVER_ZERO_BYTE_COORDINATOR_FLAG, runDoctor, doctorFailed } = await import("./doctor");
|
|
196
|
+
await runDoctor(doctorArgs);
|
|
197
|
+
if (!doctorArgs.includes("--fix-codex-runtime") && !doctorArgs.includes(RECOVER_ZERO_BYTE_COORDINATOR_FLAG)) {
|
|
198
|
+
console.log("");
|
|
199
|
+
const { printCodexLogGuardDoctor } = await import("./codex-log-guard-doctor");
|
|
200
|
+
printCodexLogGuardDoctor();
|
|
201
|
+
}
|
|
202
|
+
// A diagnostic that always exits 0 cannot gate a script. `runDoctor` reports by direct
|
|
203
|
+
// console.log with no checks collection, and signals its own special-flag failures
|
|
204
|
+
// through process.exitCode, so honour both: an explicit exitCode wins, otherwise a
|
|
205
|
+
// FAIL-level check fails the command. This is a BREAKING change for pipelines that ran
|
|
206
|
+
// `ocx doctor` and ignored the result; a diagnostic that cannot fail is worse.
|
|
207
|
+
const explicit = Number(process.exitCode ?? 0);
|
|
208
|
+
if (explicit !== 0) return explicit;
|
|
209
|
+
return doctorFailed() ? 1 : 0;
|
|
210
|
+
},
|
|
211
|
+
debug: async deps => {
|
|
212
|
+
const { handleDebugCommand } = await import("./debug");
|
|
213
|
+
await handleDebugCommand(deps.args.slice(1));
|
|
214
|
+
return 0;
|
|
215
|
+
},
|
|
216
|
+
ensure: async deps => {
|
|
217
|
+
await deps.handleEnsure();
|
|
218
|
+
return Number(process.exitCode ?? 0);
|
|
219
|
+
},
|
|
220
|
+
login: async deps => {
|
|
221
|
+
const { handleLogin } = await import("../oauth/login-cli");
|
|
222
|
+
await handleLogin(deps.args[1]);
|
|
223
|
+
return 0;
|
|
224
|
+
},
|
|
225
|
+
logout: async deps => {
|
|
226
|
+
// Argv is parsed BEFORE any store access, which is the whole point of this shape.
|
|
227
|
+
// Previously `args[1]` was taken as the provider name with no parsing, so
|
|
228
|
+
// `ocx logout --json` called removeCredential("--json"), printed "Logged out of
|
|
229
|
+
// --json." and exited 0 -- a silent false success, the worst outcome for a caller
|
|
230
|
+
// that can only see the exit code.
|
|
231
|
+
//
|
|
232
|
+
// That is not merely a wasted call. `normalizeAuthStore` copies every top-level key
|
|
233
|
+
// it finds, so a hand-edited, legacy, or corrupted auth.json containing a `--json`
|
|
234
|
+
// key would have its active account deleted -- and the key dropped entirely if that
|
|
235
|
+
// was its last account. A flag must never reach the store as a provider name.
|
|
236
|
+
const logoutArgs = deps.args.slice(1);
|
|
237
|
+
const wantsJson = logoutArgs.includes("--json");
|
|
238
|
+
// Any leading dash is an option, not a provider. Matching only `--` left the same defect
|
|
239
|
+
// one dash shorter: `ocx logout -j` treated `-j` as the provider name and, with a `-j` key
|
|
240
|
+
// present in the store, deleted it and exited 0.
|
|
241
|
+
const isOption = (arg: string): boolean => arg.startsWith("-");
|
|
242
|
+
const positionals = logoutArgs.filter(arg => !isOption(arg));
|
|
243
|
+
const unknownFlags = logoutArgs.filter(arg => isOption(arg) && arg !== "--json");
|
|
244
|
+
const name = (positionals[0] ?? "").trim().toLowerCase();
|
|
245
|
+
|
|
246
|
+
// Usage failures exit 2 and touch nothing. A missing provider is a usage error; a
|
|
247
|
+
// provider that simply has no credential is a not-found (4) further down, because the
|
|
248
|
+
// vocabulary distinguishes "you called this wrong" from "the thing is not there".
|
|
249
|
+
//
|
|
250
|
+
// The shape check is `isValidProviderName`, not another dash test. Rejecting a leading
|
|
251
|
+
// ASCII `-` fixed `-j` and still let `logout —json` through with a Unicode dash, which is
|
|
252
|
+
// the same defect a third time: each patch named one spelling instead of the class. The
|
|
253
|
+
// canonical validator states the rule positively -- start and end alphanumeric, internal
|
|
254
|
+
// `._-` allowed -- so `github-copilot` and `google-antigravity` pass while every dash
|
|
255
|
+
// variant, empty string, and reserved name fails. Anything that is not a possible
|
|
256
|
+
// provider id cannot reach the store at all.
|
|
257
|
+
const malformedName = Boolean(name) && !isValidProviderName(name);
|
|
258
|
+
if (unknownFlags.length > 0 || positionals.length > 1 || !name || malformedName) {
|
|
259
|
+
const problem = unknownFlags.length > 0
|
|
260
|
+
? `unknown option ${unknownFlags[0]}`
|
|
261
|
+
: positionals.length > 1 ? "too many arguments"
|
|
262
|
+
: malformedName ? `not a valid provider name: ${name}`
|
|
263
|
+
: "missing provider";
|
|
264
|
+
console.error(`Usage: ocx logout <provider> [--json] (${problem})`);
|
|
265
|
+
return 2;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// The disposition comes from inside the store mutation, not from a read-then-remove
|
|
269
|
+
// preflight. `mutateStore` serializes writes, so a preflight leaves a window where a
|
|
270
|
+
// concurrent logout removes the same account and BOTH callers exit 0 claiming a removal --
|
|
271
|
+
// a false success again, just a narrower one than the flag bug above.
|
|
272
|
+
const { removeCredential } = await import("../oauth/store");
|
|
273
|
+
const outcome = await removeCredential(name);
|
|
274
|
+
if (outcome === "not-found") {
|
|
275
|
+
if (wantsJson) console.log(JSON.stringify({ schemaVersion: 1, ok: false, provider: name, removed: false, reason: "not_found" }, null, 2));
|
|
276
|
+
else console.error(`No stored credential for '${name}'.`);
|
|
277
|
+
return 4;
|
|
278
|
+
}
|
|
279
|
+
if (wantsJson) console.log(JSON.stringify({ schemaVersion: 1, ok: true, provider: name, removed: true }, null, 2));
|
|
280
|
+
else console.log(`Logged out of ${name}.`);
|
|
281
|
+
return 0;
|
|
282
|
+
},
|
|
283
|
+
sync: async deps => {
|
|
284
|
+
const syncArgs = deps.args.slice(1);
|
|
285
|
+
const restartCodex = syncArgs.includes("--restart-codex");
|
|
286
|
+
// Separate flag on purpose: --restart-codex promises app-server-only scope,
|
|
287
|
+
// and quitting the desktop app ends live conversations.
|
|
288
|
+
const restartDesktopApp = syncArgs.includes("--restart-desktop-app");
|
|
289
|
+
const live = await deps.findLiveProxy();
|
|
290
|
+
const synced = await syncModelsToCodex(
|
|
291
|
+
live?.port,
|
|
292
|
+
undefined,
|
|
293
|
+
undefined,
|
|
294
|
+
undefined,
|
|
295
|
+
{ catalogEvenWhenNotInjected: true },
|
|
296
|
+
);
|
|
297
|
+
let code = 0;
|
|
298
|
+
if (synced.status === "skipped") {
|
|
299
|
+
console.log("Codex integration is OFF; sync skipped and no Codex files changed.");
|
|
300
|
+
} else if (synced.status === "catalog-only") {
|
|
301
|
+
// Explicit sync with the integration OFF still refreshes the catalog/cache
|
|
302
|
+
// for side profiles that consume the proxy without injection.
|
|
303
|
+
console.log(synced.message ?? "Codex integration is OFF; catalog refreshed, Codex config untouched.");
|
|
304
|
+
} else if (!synced.ok) {
|
|
305
|
+
code = 1;
|
|
306
|
+
console.error("Codex sync did not complete. Fix the reported Codex config issue and retry.");
|
|
307
|
+
}
|
|
308
|
+
// Only warn/restart when a catalog or models_cache write actually happened. This is
|
|
309
|
+
// deliberately not an `else`: refreshCodexModelCatalog runs before injectCodexConfig,
|
|
310
|
+
// so a sync can fail (`ok: false`) after the catalog was already rewritten — which is
|
|
311
|
+
// exactly when a long-lived app-server is holding the stale list.
|
|
312
|
+
if (synced.catalogWritten || synced.cacheSynced) {
|
|
313
|
+
afterCatalogWriteHandleAppServers({ restart: restartCodex, log: console });
|
|
314
|
+
if (restartDesktopApp) await handleDesktopAppRestart(console);
|
|
315
|
+
}
|
|
316
|
+
// `ocx sync` is a direct CLI path; it does not call the management
|
|
317
|
+
// `/api/sync` route. Refresh the already-connected MCode block here too,
|
|
318
|
+
// after Codex has published the catalog that supplies its capabilities.
|
|
319
|
+
if (synced.status !== "refused" && live) {
|
|
320
|
+
try {
|
|
321
|
+
const config = deps.loadConfig();
|
|
322
|
+
const { refreshOwnedIntegration } = await import("../integrations/owned-refresh");
|
|
323
|
+
const result = await refreshOwnedIntegration({
|
|
324
|
+
clientId: "mcode",
|
|
325
|
+
models: async () => {
|
|
326
|
+
const { loadExportModels } = await import("../server/management/model-rows");
|
|
327
|
+
return loadExportModels(config);
|
|
328
|
+
},
|
|
329
|
+
config,
|
|
330
|
+
port: live.port,
|
|
331
|
+
});
|
|
332
|
+
if (result?.changed) console.log("MCode integration refreshed from the current catalog.");
|
|
333
|
+
else if (result?.reason) console.warn(`MCode integration was not refreshed: ${result.reason}`);
|
|
334
|
+
} catch (error) {
|
|
335
|
+
console.warn(`MCode integration was not refreshed: ${error instanceof Error ? error.message : String(error)}`);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return code;
|
|
339
|
+
},
|
|
340
|
+
v2: async deps => {
|
|
341
|
+
const { cmdV2 } = await import("./v2");
|
|
342
|
+
return await cmdV2(deps.args.slice(1), {}, async () => (await deps.findLiveProxy())?.port);
|
|
343
|
+
},
|
|
344
|
+
"sync-cache": async deps => {
|
|
345
|
+
const cacheArgs = deps.args.slice(1);
|
|
346
|
+
const restartCodex = cacheArgs.includes("--restart-codex");
|
|
347
|
+
const restartDesktopApp = cacheArgs.includes("--restart-desktop-app");
|
|
348
|
+
const { withCatalogWriteSerialization } = await import("../codex/catalog-write-serialization");
|
|
349
|
+
const { invalidateCodexModelsCacheWithPermit } = await import("../codex/catalog/sync");
|
|
350
|
+
const { getCodexHome } = await import("../codex/paths");
|
|
351
|
+
const { readCodexCatalogPathForHome } = await import("../codex/catalog/parsing");
|
|
352
|
+
const { existsSync } = await import("node:fs");
|
|
353
|
+
const owningCodexHome = getCodexHome();
|
|
354
|
+
const desiredDisabled = !shouldSyncCodexOnStart(deps.loadConfig());
|
|
355
|
+
const invalidated = withCatalogWriteSerialization(owningCodexHome, permit =>
|
|
356
|
+
invalidateCodexModelsCacheWithPermit(permit, owningCodexHome, { allowWhenDesiredDisabled: true }));
|
|
357
|
+
const cacheJson = cacheArgs.includes("--json");
|
|
358
|
+
const jsonSafeLog = cacheJson
|
|
359
|
+
? { log: (...values: unknown[]) => console.error(...values), error: (...values: unknown[]) => console.error(...values) }
|
|
360
|
+
: console;
|
|
361
|
+
// Only warn/restart when models_cache was actually rewritten from a readable catalog.
|
|
362
|
+
if (invalidated.kind === "completed" && invalidated.value) {
|
|
363
|
+
afterCatalogWriteHandleAppServers({ restart: restartCodex, log: jsonSafeLog });
|
|
364
|
+
if (restartDesktopApp) await handleDesktopAppRestart(jsonSafeLog);
|
|
365
|
+
} else if (desiredDisabled && !cacheJson) {
|
|
366
|
+
// Worth saying in the human path, because it explains why nothing was written.
|
|
367
|
+
// Under --json this belongs on the envelope, not as a second stdout line.
|
|
368
|
+
console.log("Codex integration is OFF; no catalog or cache write resulted.");
|
|
369
|
+
}
|
|
370
|
+
// `completed` with a falsy value means the cache was NOT rewritten. Previously every
|
|
371
|
+
// outcome exited 0, so a script could not tell a refreshed cache from a skipped one.
|
|
372
|
+
//
|
|
373
|
+
// Losing the catalog write lock to another process is a skip, not a failure:
|
|
374
|
+
// serialization working as designed is the expected outcome under concurrency, and a
|
|
375
|
+
// proxy startup holding the permit would otherwise make a perfectly healthy
|
|
376
|
+
// `ocx sync-cache` exit 1 and fail the pipeline that called it -- intermittently, so it
|
|
377
|
+
// would read as a flake rather than a bug. `codex-retained-root-serialization.test.ts`
|
|
378
|
+
// pins exactly that: contended lock, no cache write, exit 0.
|
|
379
|
+
//
|
|
380
|
+
// `desiredDisabled` is deliberately NOT part of the success test, which is the subtle
|
|
381
|
+
// part. This call passes `allowWhenDesiredDisabled: true`, so the OFF gate inside the
|
|
382
|
+
// refresh never fires and the work is genuinely attempted -- an explicit `ocx sync-cache`
|
|
383
|
+
// means the user asked for it regardless of the toggle. Treating OFF as automatic success
|
|
384
|
+
// would report exit 0 and `skipped: true` for a refresh that actually failed.
|
|
385
|
+
//
|
|
386
|
+
// But `invalidateCodexModelsCacheWithPermit` returns a bare boolean for four different
|
|
387
|
+
// situations -- wrote it, no catalog file exists, the OFF gate fired, or it threw -- so
|
|
388
|
+
// `false` alone cannot be read as failure either. `!existsSync(catalogPath)` is a
|
|
389
|
+
// legitimate nothing-to-do: with no catalog there is no cache to derive, which is the
|
|
390
|
+
// normal state of a fully native home and the case
|
|
391
|
+
// `codex-composed-acceptance.test.ts` pins at exit 0. It is checked here rather than by
|
|
392
|
+
// widening that function's return type, because its boolean is consumed by a dozen
|
|
393
|
+
// management routes that have no use for the distinction.
|
|
394
|
+
const wrote = invalidated.kind === "completed" && Boolean(invalidated.value);
|
|
395
|
+
const contended = invalidated.kind === "unavailable" && invalidated.reason === "busy";
|
|
396
|
+
const noCatalog = !wrote && !existsSync(readCodexCatalogPathForHome(owningCodexHome));
|
|
397
|
+
const ok = wrote || contended || noCatalog;
|
|
398
|
+
if (cacheJson) {
|
|
399
|
+
console.log(JSON.stringify({
|
|
400
|
+
schemaVersion: 1,
|
|
401
|
+
ok,
|
|
402
|
+
wrote,
|
|
403
|
+
skipped: contended || noCatalog,
|
|
404
|
+
outcome: invalidated.kind,
|
|
405
|
+
// `outcome` alone cannot separate a contended lock from a hard serialization
|
|
406
|
+
// failure -- both are `unavailable`. Carry the reason so a caller can.
|
|
407
|
+
reason: invalidated.kind === "unavailable" ? invalidated.reason : undefined,
|
|
408
|
+
// Which of the two benign skips this was, so `skipped: true` is never opaque.
|
|
409
|
+
skippedReason: contended ? "contended" : noCatalog ? "no_catalog" : undefined,
|
|
410
|
+
desiredDisabled,
|
|
411
|
+
codexHome: owningCodexHome,
|
|
412
|
+
}, null, 2));
|
|
413
|
+
} else if (contended) {
|
|
414
|
+
console.log("Another process owns the catalog write; cache sync skipped.");
|
|
415
|
+
} else if (noCatalog) {
|
|
416
|
+
console.log("No Codex catalog to derive a cache from; nothing to sync.");
|
|
417
|
+
} else if (!ok) {
|
|
418
|
+
console.error(`Cache refresh did not complete (${invalidated.kind}). The Codex model cache was not rewritten.`);
|
|
419
|
+
}
|
|
420
|
+
return ok ? 0 : 1;
|
|
421
|
+
},
|
|
422
|
+
gui: async deps => {
|
|
423
|
+
const config = deps.loadConfig();
|
|
424
|
+
// Identity-checked liveness (not the pid file + a fixed sleep): finds a fallback-port
|
|
425
|
+
// proxy and waits until the spawned one actually answers before opening the browser.
|
|
426
|
+
let live = await deps.findLiveProxy();
|
|
427
|
+
if (!live) {
|
|
428
|
+
console.log("Proxy not running. Starting...");
|
|
429
|
+
deps.spawnDetached(deps.startArgv((config.port ?? 10100) > 0 ? (config.port ?? 10100) : undefined));
|
|
430
|
+
live = await deps.waitForProxy();
|
|
431
|
+
if (!live) {
|
|
432
|
+
console.error("❌ Proxy did not become healthy after starting. Not opening the GUI.");
|
|
433
|
+
return 1;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
// Open the host the proxy actually binds — `localhost` only answers for
|
|
437
|
+
// loopback/wildcard binds, not a concrete LAN/IPv6 hostname.
|
|
438
|
+
const guiHost = deps.probeHostname(live?.hostname ?? config.hostname);
|
|
439
|
+
const guiUrl = `http://${guiHost === "127.0.0.1" ? "localhost" : guiHost}:${live?.port ?? config.port}`;
|
|
440
|
+
console.log(`Opening ${guiUrl}`);
|
|
441
|
+
const { openUrl } = await import("../lib/open-url");
|
|
442
|
+
openUrl(guiUrl);
|
|
443
|
+
return 0;
|
|
444
|
+
},
|
|
445
|
+
service: async deps => {
|
|
446
|
+
process.exitCode = 0;
|
|
447
|
+
await deps.serviceCommand(...deps.args.slice(1));
|
|
448
|
+
// serviceCommand uses process.exitCode for recoverable install/stop failures
|
|
449
|
+
// that must finish cleanup before the single top-level process.exit runs.
|
|
450
|
+
return Number(process.exitCode ?? 0);
|
|
451
|
+
},
|
|
452
|
+
tray: async deps => {
|
|
453
|
+
const { windowsTrayCommand } = await import("../tray/windows");
|
|
454
|
+
// windowsTrayCommand reports failure through process.exitCode (tray/windows.ts sets
|
|
455
|
+
// it for bad usage and for a failed install/start/stop/uninstall) and returns void,
|
|
456
|
+
// so a literal 0 here made `ocx tray install` print an error and exit 0 (#2697).
|
|
457
|
+
process.exitCode = 0;
|
|
458
|
+
await windowsTrayCommand(deps.args.slice(1));
|
|
459
|
+
return Number(process.exitCode ?? 0);
|
|
460
|
+
},
|
|
461
|
+
"codex-shim": async deps => {
|
|
462
|
+
const { codexShimStatus, diagnoseCodexShim, installCodexShim, uninstallCodexShim } = await import("../codex/shim");
|
|
463
|
+
switch (deps.args[1]) {
|
|
464
|
+
case "install": {
|
|
465
|
+
const r = installCodexShim();
|
|
466
|
+
const { collectCodexShimReadinessWarnings } = await import("./codex-shim-readiness");
|
|
467
|
+
const warnings = diagnoseCodexShim().healthy
|
|
468
|
+
? collectCodexShimReadinessWarnings()
|
|
469
|
+
: [];
|
|
470
|
+
console.log(`${r.installed && warnings.length === 0 ? "✅ " : "⚠️ "}${r.message}`);
|
|
471
|
+
for (const warning of warnings) console.warn(` ${warning}`);
|
|
472
|
+
break;
|
|
473
|
+
}
|
|
474
|
+
case "status":
|
|
475
|
+
console.log(codexShimStatus());
|
|
476
|
+
break;
|
|
477
|
+
case "uninstall":
|
|
478
|
+
case "remove": {
|
|
479
|
+
const r = uninstallCodexShim();
|
|
480
|
+
console.log(r.removed ? `✅ ${r.message}` : `⚠️ ${r.message}`);
|
|
481
|
+
break;
|
|
482
|
+
}
|
|
483
|
+
default:
|
|
484
|
+
console.error("Usage: ocx codex-shim <install|status|uninstall|remove>");
|
|
485
|
+
return 1;
|
|
486
|
+
}
|
|
487
|
+
return 0;
|
|
488
|
+
},
|
|
489
|
+
update: async deps => {
|
|
490
|
+
// `ocx update --help` must print usage and exit WITHOUT side effects — running the
|
|
491
|
+
// real self-update stops the proxy and drops in-flight routed streams (issue #168).
|
|
492
|
+
if (hasHelpFlag(deps.args.slice(1))) {
|
|
493
|
+
printSubcommandUsage("update");
|
|
494
|
+
return 0;
|
|
495
|
+
}
|
|
496
|
+
const { runUpdate } = await import("../update");
|
|
497
|
+
await runUpdate();
|
|
498
|
+
return 0;
|
|
499
|
+
},
|
|
500
|
+
"__refresh-version": async deps => {
|
|
501
|
+
// Hidden, detached helper spawned by the update prompt to refresh the
|
|
502
|
+
// cached latest version without blocking the foreground start. Not in help.
|
|
503
|
+
const { refreshVersionCache } = await import("../update/notify");
|
|
504
|
+
const channel = deps.args[1] === "preview" ? "preview" : "latest";
|
|
505
|
+
await refreshVersionCache(channel);
|
|
506
|
+
return 0;
|
|
507
|
+
},
|
|
508
|
+
"__tray-start": async deps => {
|
|
509
|
+
return (await deps.handleTrayProxyStart()) ? 0 : 1;
|
|
510
|
+
},
|
|
511
|
+
"__tray-restart": async deps => {
|
|
512
|
+
await deps.handleTrayProxyRestart();
|
|
513
|
+
return Number(process.exitCode ?? 0);
|
|
514
|
+
},
|
|
515
|
+
"__startup-health": async deps => {
|
|
516
|
+
const { collectStartupHealth } = await import("../codex/autostart-health");
|
|
517
|
+
console.log(JSON.stringify(collectStartupHealth(deps.loadConfig())));
|
|
518
|
+
return 0;
|
|
519
|
+
},
|
|
520
|
+
"__tray-host": async () => {
|
|
521
|
+
const { runWindowsTrayHost } = await import("../tray/windows");
|
|
522
|
+
await runWindowsTrayHost();
|
|
523
|
+
return 0;
|
|
524
|
+
},
|
|
525
|
+
"__gui-update-worker": async deps => {
|
|
526
|
+
const jobId = deps.args[1];
|
|
527
|
+
if (!jobId) return 1;
|
|
528
|
+
const channel = normalizeUpdateChannel(deps.args[2]);
|
|
529
|
+
await runGuiUpdateWorker(jobId, channel, deps.args[3] === "restart");
|
|
530
|
+
return 0;
|
|
531
|
+
},
|
|
532
|
+
restart: async deps => {
|
|
533
|
+
// The running proxy owns its drain and replacement through /api/system/restart.
|
|
534
|
+
// If nothing is live, restart degrades to the documented `ensure` start behavior.
|
|
535
|
+
await deps.handleProxyRestart(deps.handleRestartStartWhenStopped);
|
|
536
|
+
return Number(process.exitCode ?? 0);
|
|
537
|
+
},
|
|
538
|
+
capabilities: async deps => {
|
|
539
|
+
const { runCapabilities } = await import("./capabilities-command");
|
|
540
|
+
return await runCapabilities(deps.args.slice(1));
|
|
541
|
+
},
|
|
542
|
+
health: async deps => {
|
|
543
|
+
const healthArgs = deps.args.slice(1);
|
|
544
|
+
const wantsHealthJson = healthArgs.includes("--json");
|
|
545
|
+
const live = await deps.findLiveProxy();
|
|
546
|
+
if (wantsHealthJson) {
|
|
547
|
+
console.log(JSON.stringify({ ok: !!live, pid: live?.pid ?? null, port: live?.port ?? null }));
|
|
548
|
+
} else {
|
|
549
|
+
console.log(live ? `Proxy healthy (PID ${live.pid}, port ${live.port})` : "Proxy not healthy");
|
|
550
|
+
}
|
|
551
|
+
return live ? 0 : 1;
|
|
552
|
+
},
|
|
553
|
+
ready: async deps => {
|
|
554
|
+
// Fail-closed impossible-state guard: readyArgs is populated by the
|
|
555
|
+
// preparse block in src/cli/root.ts before maybeAutoRestoreCodexShim, so
|
|
556
|
+
// reaching here without it means dispatch diverged. Refuse with code 64
|
|
557
|
+
// and perform NO I/O (no discovery/probe). process.exit is `never`,
|
|
558
|
+
// narrowing below.
|
|
559
|
+
const readyArgs = deps.head.readyArgs;
|
|
560
|
+
if (!readyArgs) return 64;
|
|
561
|
+
return await deps.handleReady(readyArgs);
|
|
562
|
+
},
|
|
563
|
+
provider: async deps => {
|
|
564
|
+
const { handleProviderCommand } = await import("./provider");
|
|
565
|
+
// Reset first, like the service runner below: reading process.exitCode only
|
|
566
|
+
// reports THIS command's outcome if nothing earlier in the process set it.
|
|
567
|
+
process.exitCode = 0;
|
|
568
|
+
await handleProviderCommand(deps.args.slice(1));
|
|
569
|
+
// handleProviderCommand reports failure through process.exitCode, which it sets
|
|
570
|
+
// from handleProviderRuntimeCommand. Returning a literal 0 here made index.ts
|
|
571
|
+
// call process.exit(0) and erase it, so `ocx provider quota` against a stopped
|
|
572
|
+
// proxy printed an error and still exited 0 (#2697).
|
|
573
|
+
return Number(process.exitCode ?? 0);
|
|
574
|
+
},
|
|
575
|
+
account: async deps => {
|
|
576
|
+
const { cmdAccount } = await import("./account");
|
|
577
|
+
return await cmdAccount(deps.args.slice(1));
|
|
578
|
+
},
|
|
579
|
+
models: async deps => {
|
|
580
|
+
const { handleModels } = await import("./models");
|
|
581
|
+
process.exitCode = 0;
|
|
582
|
+
await handleModels(deps.args.slice(1));
|
|
583
|
+
// Same as the provider runner above: handleModels sets process.exitCode from
|
|
584
|
+
// handleModelsRuntimeCommand, and a literal 0 discarded it (#2697).
|
|
585
|
+
return Number(process.exitCode ?? 0);
|
|
586
|
+
},
|
|
587
|
+
alias: async deps => {
|
|
588
|
+
const { handleAliasCommand } = await import("./alias");
|
|
589
|
+
return await handleAliasCommand(deps.args.slice(1));
|
|
590
|
+
},
|
|
591
|
+
combo: async deps => {
|
|
592
|
+
const { handleComboCommand } = await import("./combo");
|
|
593
|
+
return await handleComboCommand(deps.args.slice(1));
|
|
594
|
+
},
|
|
595
|
+
route: async deps => {
|
|
596
|
+
if (deps.args[1] !== "combo" && deps.args[1] !== "policy") {
|
|
597
|
+
console.error("Usage: ocx route <combo|policy> <subcommand>");
|
|
598
|
+
return 2;
|
|
599
|
+
}
|
|
600
|
+
if (deps.args[1] === "combo") {
|
|
601
|
+
const { handleComboCommand } = await import("./combo");
|
|
602
|
+
return await handleComboCommand(deps.args.slice(2));
|
|
603
|
+
} else {
|
|
604
|
+
const { handleRoutePolicyCommand } = await import("./route-policy");
|
|
605
|
+
return await handleRoutePolicyCommand(deps.args.slice(2));
|
|
606
|
+
}
|
|
607
|
+
},
|
|
608
|
+
agent: async deps => {
|
|
609
|
+
const { handleAgentCommand } = await import("./agent");
|
|
610
|
+
return await handleAgentCommand(deps.args.slice(1));
|
|
611
|
+
},
|
|
612
|
+
observe: async deps => {
|
|
613
|
+
const { handleObserveCommand } = await import("./observe");
|
|
614
|
+
return await handleObserveCommand(deps.args.slice(1));
|
|
615
|
+
},
|
|
616
|
+
inspect: async deps => {
|
|
617
|
+
const { handleInspectCommand } = await import("./inspect");
|
|
618
|
+
return await handleInspectCommand(deps.args.slice(1));
|
|
619
|
+
},
|
|
620
|
+
logs: async deps => {
|
|
621
|
+
const { handleObserveCommand } = await import("./observe");
|
|
622
|
+
return await handleObserveCommand([deps.command!, ...deps.args.slice(1)]);
|
|
623
|
+
},
|
|
624
|
+
usage: async deps => {
|
|
625
|
+
const { handleObserveCommand } = await import("./observe");
|
|
626
|
+
return await handleObserveCommand([deps.command!, ...deps.args.slice(1)]);
|
|
627
|
+
},
|
|
628
|
+
storage: async deps => {
|
|
629
|
+
// `ocx storage` used to be a pure alias of `observe storage`, which reached only the report
|
|
630
|
+
// route. wp7 gave it cleanup, trash, and policy subcommands, so it dispatches to its own
|
|
631
|
+
// module -- with `report` as the default subcommand, so a bare `ocx storage` still prints
|
|
632
|
+
// the same thing it printed before.
|
|
633
|
+
const { handleStorageCommand } = await import("./storage");
|
|
634
|
+
return await handleStorageCommand(deps.args.slice(1));
|
|
635
|
+
},
|
|
636
|
+
memory: async deps => {
|
|
637
|
+
const { handleObserveCommand } = await import("./observe");
|
|
638
|
+
return await handleObserveCommand([deps.command!, ...deps.args.slice(1)]);
|
|
639
|
+
},
|
|
640
|
+
access: async deps => {
|
|
641
|
+
const { handleAccessCommand } = await import("./access");
|
|
642
|
+
return await handleAccessCommand(deps.args.slice(1));
|
|
643
|
+
},
|
|
644
|
+
"api-key": async deps => {
|
|
645
|
+
const { handleAccessCommand } = await import("./access");
|
|
646
|
+
return await handleAccessCommand(["key", ...deps.args.slice(1)]);
|
|
647
|
+
},
|
|
648
|
+
export: async deps => {
|
|
649
|
+
const { handleExportCommand } = await import("./export-command");
|
|
650
|
+
return await handleExportCommand(deps.args.slice(1));
|
|
651
|
+
},
|
|
652
|
+
grok: async deps => {
|
|
653
|
+
const { handleGrokCommand } = await import("./integrations");
|
|
654
|
+
return await handleGrokCommand(deps.args.slice(1));
|
|
655
|
+
},
|
|
656
|
+
integration: async deps => {
|
|
657
|
+
const integration = deps.args[1];
|
|
658
|
+
if (integration === "grok") {
|
|
659
|
+
const { handleGrokCommand } = await import("./integrations");
|
|
660
|
+
return await handleGrokCommand(deps.args.slice(2));
|
|
661
|
+
} else if (integration === "native") {
|
|
662
|
+
// The native client toggles are a separate server surface from the reversible file
|
|
663
|
+
// integrations `client` manages, so they get their own subcommand rather than being
|
|
664
|
+
// folded into one that means something else.
|
|
665
|
+
const { handleIntegrationCommand } = await import("./inspect");
|
|
666
|
+
return await handleIntegrationCommand(deps.args.slice(1));
|
|
667
|
+
} else if (integration === "claude") {
|
|
668
|
+
const { handleClaudeConfigCommand } = await import("./integrations");
|
|
669
|
+
return await handleClaudeConfigCommand(deps.args.slice(2));
|
|
670
|
+
} else if (integration === "client") {
|
|
671
|
+
const { handleClientIntegrationCommand } = await import("./integrations");
|
|
672
|
+
return await handleClientIntegrationCommand(deps.args.slice(2));
|
|
673
|
+
} else {
|
|
674
|
+
console.error("Usage: ocx integration <claude|grok|client> <subcommand>");
|
|
675
|
+
return 2;
|
|
676
|
+
}
|
|
677
|
+
},
|
|
678
|
+
system: async deps => {
|
|
679
|
+
const { handleSystemCommand } = await import("./system-command");
|
|
680
|
+
return await handleSystemCommand(deps.args.slice(1));
|
|
681
|
+
},
|
|
682
|
+
config: async deps => {
|
|
683
|
+
const { handleConfigCommand } = await import("./config-command");
|
|
684
|
+
return await handleConfigCommand(deps.args.slice(1));
|
|
685
|
+
},
|
|
686
|
+
lab: async deps => {
|
|
687
|
+
const { handleLabCommand } = await import("./lab");
|
|
688
|
+
return await handleLabCommand(deps.args.slice(1));
|
|
689
|
+
},
|
|
690
|
+
claude: async deps => {
|
|
691
|
+
const { cmdClaude } = await import("./claude");
|
|
692
|
+
// "ocx claude desktop" → write Desktop 3P config
|
|
693
|
+
if (deps.args[1] === "desktop") {
|
|
694
|
+
const { handleClaudeDesktopCommand } = await import("./claude-desktop");
|
|
695
|
+
const exitCode = await handleClaudeDesktopCommand(deps.args.slice(2));
|
|
696
|
+
if (exitCode !== 0) return exitCode;
|
|
697
|
+
return 0;
|
|
698
|
+
}
|
|
699
|
+
if (deps.args[1] === "config") {
|
|
700
|
+
const { handleClaudeConfigCommand } = await import("./integrations");
|
|
701
|
+
return await handleClaudeConfigCommand(deps.args.slice(2));
|
|
702
|
+
}
|
|
703
|
+
return await cmdClaude(deps.args.slice(1));
|
|
704
|
+
},
|
|
705
|
+
opencode: async deps => {
|
|
706
|
+
const { cmdOpencode } = await import("./opencode");
|
|
707
|
+
return await cmdOpencode(deps.args.slice(1));
|
|
708
|
+
},
|
|
709
|
+
pi: async deps => {
|
|
710
|
+
const { handlePiCommand } = await import("./pi");
|
|
711
|
+
return await handlePiCommand(deps.args.slice(1));
|
|
712
|
+
},
|
|
713
|
+
"sync-cloud": async deps => {
|
|
714
|
+
const { handleSyncCloudCommand } = await import("./sync-cloud");
|
|
715
|
+
return await handleSyncCloudCommand(deps.args.slice(1));
|
|
716
|
+
},
|
|
717
|
+
mcode: async deps => {
|
|
718
|
+
const { cmdMcode } = await import("./minimax");
|
|
719
|
+
return await cmdMcode(deps.args.slice(1));
|
|
720
|
+
},
|
|
721
|
+
mmx: async deps => {
|
|
722
|
+
const { cmdMmx } = await import("./minimax");
|
|
723
|
+
return await cmdMmx(deps.args.slice(1));
|
|
724
|
+
},
|
|
725
|
+
zcode: async deps => {
|
|
726
|
+
const { handleZcodeCommand } = await import("./integrations");
|
|
727
|
+
return await handleZcodeCommand(deps.args.slice(1));
|
|
728
|
+
},
|
|
729
|
+
help: async () => {
|
|
730
|
+
printUsage();
|
|
731
|
+
return 0;
|
|
732
|
+
},
|
|
733
|
+
"--help": async () => {
|
|
734
|
+
printUsage();
|
|
735
|
+
return 0;
|
|
736
|
+
},
|
|
737
|
+
"-h": async () => {
|
|
738
|
+
printUsage();
|
|
739
|
+
return 0;
|
|
740
|
+
},
|
|
741
|
+
};
|
|
742
|
+
|
|
743
|
+
/** Registry alias pairs → canonical dispatch name (init/setup, restore/eject, …). */
|
|
744
|
+
const aliasTargets = new Map<string, string>();
|
|
745
|
+
for (const entry of CLI_COMMANDS) {
|
|
746
|
+
for (const alias of entry.aliases ?? []) aliasTargets.set(alias, entry.name);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
export const DISPATCH_COMMANDS: ReadonlySet<string> = new Set(Object.keys(commandRunners));
|
|
750
|
+
export const DISPATCH_ALIASES: ReadonlyMap<string, string> = aliasTargets;
|
|
751
|
+
|
|
752
|
+
/** Resolve the runner key for a command, following registry aliases to the
|
|
753
|
+
* canonical runner. Returns undefined when the command is unknown. */
|
|
754
|
+
export function resolveDispatchCommand(command: string | undefined): string | undefined {
|
|
755
|
+
if (command === undefined) return undefined;
|
|
756
|
+
if (Object.prototype.hasOwnProperty.call(commandRunners, command)) return command;
|
|
757
|
+
return aliasTargets.get(command);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
export async function dispatchCommand(head: CliHead, deps: CliDispatchDeps): Promise<number> {
|
|
761
|
+
const command = head.command;
|
|
762
|
+
if (command === undefined || command === "help" || command === "--help" || command === "-h") {
|
|
763
|
+
printUsage();
|
|
764
|
+
return 0;
|
|
765
|
+
}
|
|
766
|
+
const runner = commandRunners[resolveDispatchCommand(command) ?? ""];
|
|
767
|
+
if (!runner) {
|
|
768
|
+
console.error(`Unknown command: ${command}`);
|
|
769
|
+
printUsage();
|
|
770
|
+
return 1;
|
|
771
|
+
}
|
|
772
|
+
return await runner(deps);
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
/**
|
|
776
|
+
* Report the outcome of an opt-in desktop-app restart. Kept next to the two
|
|
777
|
+
* callers so `sync` and `sync-cache` cannot drift in what they tell the user.
|
|
778
|
+
*/
|
|
779
|
+
async function handleDesktopAppRestart(log: Pick<Console, "log" | "error">): Promise<void> {
|
|
780
|
+
const { restartCodexDesktopApp } = await import("../codex/desktop-app-restart");
|
|
781
|
+
const result = restartCodexDesktopApp();
|
|
782
|
+
switch (result.reason) {
|
|
783
|
+
case "windows_only":
|
|
784
|
+
log.error("--restart-desktop-app is supported on Windows only; nothing was stopped.");
|
|
785
|
+
return;
|
|
786
|
+
case "package_discovery_failed":
|
|
787
|
+
log.error(
|
|
788
|
+
"Could not identify the installed Codex desktop package. Quit and relaunch the desktop app "
|
|
789
|
+
+ "manually to refresh the model picker.",
|
|
790
|
+
);
|
|
791
|
+
return;
|
|
792
|
+
case "self_ancestry":
|
|
793
|
+
log.error(
|
|
794
|
+
"Refusing to restart the desktop app because this command is running inside it. "
|
|
795
|
+
+ "Run 'ocx sync --restart-desktop-app' from an external terminal instead.",
|
|
796
|
+
);
|
|
797
|
+
return;
|
|
798
|
+
case "process_probe_failed":
|
|
799
|
+
// Distinct from `no_targets`: we could not look, which is not the same as looking and
|
|
800
|
+
// finding nothing. Saying "not running" here sent users away believing there was nothing
|
|
801
|
+
// to restart (#2557).
|
|
802
|
+
log.error(
|
|
803
|
+
"Could not enumerate Codex desktop processes, so the app was not restarted. "
|
|
804
|
+
+ "Quit and relaunch the desktop app manually to refresh the model picker.",
|
|
805
|
+
);
|
|
806
|
+
return;
|
|
807
|
+
case "no_targets":
|
|
808
|
+
log.log("Codex desktop app is not running; nothing to restart.");
|
|
809
|
+
return;
|
|
810
|
+
case "targets_survived":
|
|
811
|
+
log.error(
|
|
812
|
+
`Codex desktop app PID(s) ${result.surviving.join(", ")} did not exit, so it was not relaunched. `
|
|
813
|
+
+ "Quit the desktop app manually to refresh the model picker.",
|
|
814
|
+
);
|
|
815
|
+
return;
|
|
816
|
+
default:
|
|
817
|
+
if (result.relaunch === "started") {
|
|
818
|
+
log.log("Codex desktop app restarted; its model picker will re-read the catalog.");
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
}
|