@bitkyc08/opencodex 2.84.0 → 2.87.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 +0 -4
- package/bin/ocx.mjs +61 -3
- package/gui/dist/assets/App-ZfYbLHkB.js +58 -0
- package/gui/dist/assets/App-wT3mXqFz.css +1 -0
- package/gui/dist/assets/{Tray-C9TGtwad.js → Tray-DCd-A1az.js} +1 -1
- package/gui/dist/assets/index-CfYDMj34.js +94 -0
- package/gui/dist/assets/index-DPeB9HpV.css +1 -0
- package/gui/dist/assets/quota-summary-ChvmKGOk.js +1 -0
- package/gui/dist/index.html +2 -2
- package/package.json +1 -2
- package/src/adapters/anthropic/beta-allowlist.ts +91 -11
- package/src/adapters/anthropic/beta-body-pairs.ts +93 -0
- package/src/adapters/anthropic/client-identity.ts +1 -1
- package/src/adapters/anthropic/passthrough.ts +16 -3
- package/src/adapters/anthropic-progress.ts +84 -0
- package/src/adapters/anthropic.ts +108 -21
- package/src/adapters/azure.ts +19 -1
- package/src/adapters/base.ts +2 -0
- package/src/adapters/claude-cli/adapter.ts +111 -23
- package/src/adapters/claude-cli/profiles.ts +2 -1
- package/src/adapters/claude-cli/stable-replay.ts +108 -0
- package/src/adapters/claude-cli/usage-admission.ts +230 -0
- package/src/adapters/client-fingerprint.ts +24 -0
- package/src/adapters/coding-agent/protocol.ts +1 -1
- package/src/adapters/coding-agent/turn.ts +40 -11
- package/src/adapters/cursor/arg-codec.ts +17 -5
- package/src/adapters/cursor/catalog.ts +8 -0
- package/src/adapters/cursor/effort-map.ts +3 -0
- package/src/adapters/cursor/freeform-args.ts +75 -0
- package/src/adapters/cursor/protobuf-events.ts +36 -23
- package/src/adapters/dsh-account.ts +97 -0
- package/src/adapters/google-antigravity-wire.ts +22 -1
- package/src/adapters/google.ts +37 -10
- package/src/adapters/openai-chat/messages.ts +4 -3
- package/src/adapters/openai-chat/passthrough.ts +8 -2
- package/src/adapters/openai-chat/reasoning-replay.ts +52 -0
- package/src/adapters/openai-chat/response-events.ts +59 -1
- package/src/adapters/openai-chat.ts +8 -5
- package/src/adapters/openai-responses/compaction-search-history.ts +14 -7
- package/src/adapters/openai-responses/passthrough.ts +57 -125
- package/src/adapters/openai-responses/request-strips.ts +25 -3
- package/src/adapters/openai-responses/transport.ts +81 -0
- package/src/adapters/qoder/adapter.ts +44 -3
- package/src/adapters/registry.ts +5 -0
- package/src/adapters/zed.ts +26 -1
- package/src/advisor/activity.ts +55 -0
- package/src/advisor/budget.ts +62 -0
- package/src/advisor/consult.ts +223 -0
- package/src/advisor/context.ts +238 -0
- package/src/advisor/disclosure.ts +20 -0
- package/src/advisor/evidence-tool.ts +21 -0
- package/src/advisor/evidence.ts +117 -0
- package/src/advisor/runtime.ts +353 -0
- package/src/advisor/settings.ts +144 -0
- package/src/advisor/state.ts +369 -0
- package/src/advisor/synthetic-tool.ts +33 -0
- package/src/bridge/errors.ts +24 -1
- package/src/bridge/internal.ts +3 -1
- package/src/bridge/response-json.ts +18 -3
- package/src/bridge/sse.ts +58 -8
- package/src/bridge/terminal-refusal.ts +59 -0
- package/src/chat/inbound.ts +30 -6
- package/src/chat/outbound.ts +5 -0
- package/src/claude/desktop-3p-library.ts +72 -7
- package/src/claude/desktop-3p.ts +75 -19
- package/src/claude/desktop-first-party.ts +1 -1
- package/src/claude/desktop-picker-platform.ts +4 -0
- package/src/claude/desktop-picker-profile.ts +11 -4
- package/src/claude/desktop-picker.ts +15 -8
- package/src/claude/desktop-profile.ts +10 -1
- package/src/claude/desktop-remote-store-io.ts +5 -3
- package/src/claude/desktop-system-proxy.ts +50 -4
- package/src/claude/inbound-content-options.ts +11 -0
- package/src/claude/inbound.ts +154 -50
- package/src/claude/intercept/local-ca.ts +8 -1
- package/src/claude/intercept/picker-ca-startup.ts +2 -1
- package/src/claude/intercept/picker-runtime.ts +6 -5
- package/src/claude/intercept/picker-trust-windows.ts +338 -0
- package/src/claude/intercept/picker-trust.ts +19 -0
- package/src/claude/intercept/port-policy.ts +30 -0
- package/src/claude/intercept/runtime.ts +97 -94
- package/src/claude/model-default-settings.ts +154 -0
- package/src/claude/model-info.ts +7 -7
- package/src/claude/outbound.ts +51 -19
- package/src/cli/account-api.ts +1 -0
- package/src/cli/account-policy-dto.ts +6 -0
- package/src/cli/account-policy.ts +34 -5
- package/src/cli/account-preservation.ts +44 -0
- package/src/cli/account.ts +8 -2
- package/src/cli/advisor.ts +165 -0
- package/src/cli/auxiliary-listener-preflight.ts +37 -0
- package/src/cli/capabilities-accounts.ts +20 -1
- package/src/cli/capabilities-agents-routing.ts +23 -2
- package/src/cli/capabilities-base.ts +39 -11
- package/src/cli/capabilities-observe-system.ts +63 -3
- package/src/cli/capabilities-provider-models.ts +11 -0
- package/src/cli/chatgpt-command.ts +35 -14
- package/src/cli/claude.ts +46 -6
- package/src/cli/codex-cli-update.ts +151 -41
- package/src/cli/codex-provider.ts +44 -0
- package/src/cli/combo-input.ts +10 -1
- package/src/cli/combo-result.ts +1 -1
- package/src/cli/combo.ts +2 -1
- package/src/cli/cross-home-owner.ts +17 -14
- package/src/cli/dispatch.ts +30 -5
- package/src/cli/doctor.ts +15 -1
- package/src/cli/ensure-desktop-cold-start.ts +382 -0
- package/src/cli/export-command.ts +1 -1
- package/src/cli/help.ts +4 -2
- package/src/cli/index.ts +14 -5
- package/src/cli/integration-plan-dto.ts +3 -0
- package/src/cli/log-history.ts +172 -0
- package/src/cli/models-runtime-subcommands.ts +1 -0
- package/src/cli/models-runtime.ts +72 -8
- package/src/cli/observe-stream.ts +2 -0
- package/src/cli/observe.ts +16 -4
- package/src/cli/provider.ts +27 -5
- package/src/cli/registry.ts +41 -9
- package/src/cli/restart-scope.ts +3 -1
- package/src/cli/runtime-api.ts +5 -3
- package/src/cli/system-command.ts +40 -8
- package/src/cli/uninstall-client-state.ts +32 -0
- package/src/cli/usage-compare.ts +309 -0
- package/src/cli/usage-model-search.ts +4 -4
- package/src/cli/usage-report.ts +2 -2
- package/src/cli/v2.ts +1 -1
- package/src/client/machine-listener.ts +1 -3
- package/src/client/runtime.ts +1 -0
- package/src/clients/client-path.ts +51 -0
- package/src/clients/config-export/contracts.ts +3 -1
- package/src/clients/config-export/model-metadata.ts +3 -2
- package/src/clients/config-export/qoder.ts +93 -0
- package/src/clients/config-export.ts +35 -48
- package/src/clients/gentle-shell-path.ts +87 -0
- package/src/codex/account-auto-switch.ts +2 -0
- package/src/codex/account-identity.ts +29 -0
- package/src/codex/account-label.ts +1 -1
- package/src/codex/account-lifecycle.ts +21 -5
- package/src/codex/account-preservation.ts +28 -0
- package/src/codex/account-use-remaining.ts +23 -0
- package/src/codex/app-server-processes.ts +97 -7
- package/src/codex/app-server-restart-service.ts +55 -4
- package/src/codex/auth-api/account-list.ts +4 -0
- package/src/codex/auth-api/account-pause-group.ts +6 -50
- package/src/codex/auth-api/account-preservation.ts +57 -0
- package/src/codex/auth-api/pool-mode-gate.ts +5 -2
- package/src/codex/auth-api/routes.ts +8 -0
- package/src/codex/auth-api/use-remaining-route.ts +36 -0
- package/src/codex/auth-api.ts +0 -1
- package/src/codex/auth-context.ts +81 -7
- package/src/codex/autostart-health.ts +4 -0
- package/src/codex/catalog/auto-review.ts +20 -3
- package/src/codex/catalog/build-entries.ts +19 -2
- package/src/codex/catalog/combo-member.ts +14 -5
- package/src/codex/catalog/configured-tiers.ts +50 -0
- package/src/codex/catalog/effort.ts +4 -1
- package/src/codex/catalog/gather-capture.ts +2 -0
- package/src/codex/catalog/metadata.ts +11 -9
- package/src/codex/catalog/model-hints.ts +42 -19
- package/src/codex/catalog/model-visibility.ts +3 -1
- package/src/codex/catalog/native-ultrafast.ts +106 -0
- package/src/codex/catalog/parsing.ts +35 -86
- package/src/codex/catalog/provider-models.ts +40 -34
- package/src/codex/catalog/retained-sync.ts +2 -0
- package/src/codex/catalog/routed-gather.ts +33 -16
- package/src/codex/catalog/vendor-context.ts +82 -0
- package/src/codex/cli-install-provenance.ts +105 -17
- package/src/codex/cli-update-plan.ts +545 -0
- package/src/codex/config-write-lock.ts +63 -4
- package/src/codex/convergence.ts +2 -0
- package/src/codex/desktop-app/picker-freshness.ts +96 -0
- package/src/codex/desktop-app/types.ts +2 -0
- package/src/codex/desktop-app/windows.ts +29 -16
- package/src/codex/desktop-app-restart.ts +25 -2
- package/src/codex/desktop-compatibility/certificate-service.ts +99 -0
- package/src/codex/desktop-compatibility/certificate-store.ts +193 -0
- package/src/codex/desktop-compatibility/connection-store.ts +87 -0
- package/src/codex/desktop-compatibility/installed-build.ts +73 -0
- package/src/codex/desktop-compatibility/json-body.ts +29 -0
- package/src/codex/desktop-compatibility/native-identity.ts +62 -0
- package/src/codex/desktop-compatibility/relay-listener.ts +93 -0
- package/src/codex/desktop-compatibility/routing-binding.ts +10 -0
- package/src/codex/desktop-compatibility/routing-preflight.ts +69 -0
- package/src/codex/desktop-compatibility/runtime-ownership.ts +28 -0
- package/src/codex/desktop-compatibility/runtime.ts +182 -0
- package/src/codex/desktop-compatibility/service.ts +30 -0
- package/src/codex/desktop-compatibility/startup-settings.ts +50 -0
- package/src/codex/desktop-compatibility/usage-activation.ts +86 -0
- package/src/codex/desktop-compatibility/usage-controlled-fetch.ts +59 -0
- package/src/codex/desktop-compatibility/usage-controller.ts +107 -0
- package/src/codex/desktop-compatibility/usage-policy.ts +59 -0
- package/src/codex/desktop-compatibility/usage-refresh.ts +33 -0
- package/src/codex/desktop-compatibility/usage-sse-controller.ts +86 -0
- package/src/codex/desktop-compatibility/windows-activation-source.ts +44 -0
- package/src/codex/desktop-compatibility/windows-certificate-trust.ts +81 -0
- package/src/codex/desktop-compatibility/windows-key-protection.ts +165 -0
- package/src/codex/desktop-compatibility/windows-package-command.ts +86 -0
- package/src/codex/desktop-compatibility/windows-package-launch.ts +28 -0
- package/src/codex/features.ts +85 -45
- package/src/codex/history-provider.ts +1 -1
- package/src/codex/inject/config-write-section.ts +4 -1
- package/src/codex/inject/history-failure.ts +27 -0
- package/src/codex/inject/remove.ts +18 -6
- package/src/codex/inject/restore.ts +24 -2
- package/src/codex/inject/routing-classify.ts +4 -3
- package/src/codex/inject.ts +18 -27
- package/src/codex/journal.ts +16 -1
- package/src/codex/main-account-hard-lock.ts +30 -1
- package/src/codex/main-account.ts +99 -15
- package/src/codex/native-main-refresh-mode.ts +217 -0
- package/src/codex/native-profile-startup.ts +1 -1
- package/src/codex/ocx-compaction-history.ts +12 -10
- package/src/codex/paths.ts +86 -1
- package/src/codex/provider-routing.ts +174 -0
- package/src/codex/refresh.ts +2 -2
- package/src/codex/routing/health-store.ts +2 -2
- package/src/codex/routing/pool-recovery.ts +79 -0
- package/src/codex/routing/selection.ts +4 -3
- package/src/codex/routing/thread-affinity.ts +1 -1
- package/src/codex/shim-diagnostics.ts +6 -0
- package/src/codex/shim-overlay.ts +7 -2
- package/src/codex/signed-in-identity.ts +43 -0
- package/src/codex/subagent-model-fallback.ts +1 -1
- package/src/codex/sync.ts +6 -1
- package/src/codex/user-identity.ts +16 -5
- package/src/codex/windows-local-appdata.ts +84 -0
- package/src/combos/failover.ts +6 -1
- package/src/combos/index.ts +1 -0
- package/src/combos/resolve.ts +46 -10
- package/src/combos/types.ts +15 -0
- package/src/config/diagnostics.ts +35 -7
- package/src/config/live-reconcile.ts +51 -2
- package/src/config/load-degrade.ts +23 -1
- package/src/config/opencode-wire-upgrade.ts +54 -0
- package/src/config/opencode-zen-upgrade.ts +52 -0
- package/src/config/owner-registry.ts +22 -17
- package/src/config/paths.ts +10 -3
- package/src/config/provider-validation.ts +45 -2
- package/src/config/schema/config-schema.ts +39 -0
- package/src/config/schema/desktop-compatibility.ts +9 -0
- package/src/config/schema/leaf-validators.ts +39 -9
- package/src/config/schema/main-account-hard-lock-fallback.ts +26 -0
- package/src/config/schema/native-reasoning-retention.ts +26 -0
- package/src/config.ts +2 -0
- package/src/generated/compatibility-version.json +962 -350
- package/src/generated/model-metadata.ts +1 -1
- package/src/grok/sync.ts +1 -1
- package/src/images/loop.ts +46 -8
- package/src/integrations/catalog-refresh.ts +1 -1
- package/src/integrations/config-io.ts +20 -2
- package/src/integrations/journal.ts +15 -1
- package/src/integrations/mutation-plan.ts +2 -0
- package/src/integrations/registry.ts +15 -0
- package/src/integrations/store.ts +3 -0
- package/src/integrations/writer.ts +10 -1
- package/src/lib/advisor-activation.ts +16 -0
- package/src/lib/background-work.ts +65 -0
- package/src/lib/bounded-file-read.ts +58 -0
- package/src/lib/bun-path-runtime.d.mts +10 -1
- package/src/lib/bun-path-runtime.mjs +62 -3
- package/src/lib/codex-restart-contract.ts +15 -0
- package/src/lib/desktop-proxy-route.ts +30 -0
- package/src/lib/desktop-upstream-tunnel.ts +72 -0
- package/src/lib/empty-tool-catalog.ts +62 -0
- package/src/lib/errors.ts +26 -3
- package/src/lib/gcp-adc.ts +96 -9
- package/src/lib/gcp-credential-input.ts +12 -0
- package/src/lib/lab-live-route-production.ts +5 -0
- package/src/lib/local-internal-call-capability.ts +55 -0
- package/src/lib/opaque-proxy-tunnel.ts +217 -0
- package/src/lib/package-tree-integrity.ts +2 -2
- package/src/lib/redact.ts +2 -2
- package/src/lib/socks5-fetch.ts +48 -71
- package/src/lib/socks5-handshake.ts +112 -0
- package/src/lib/translator-budget.ts +7 -1
- package/src/oauth/account-quota-rank.ts +69 -2
- package/src/oauth/anthropic-account-refusal.ts +20 -2
- package/src/oauth/anthropic-oauth-definitions.ts +3 -1
- package/src/oauth/anthropic-routing.ts +1 -21
- package/src/oauth/anthropic.ts +38 -7
- package/src/oauth/callback-server.ts +27 -1
- package/src/oauth/chatgpt-device.ts +1 -1
- package/src/oauth/chatgpt-shared.ts +83 -0
- package/src/oauth/chatgpt.ts +8 -72
- package/src/oauth/dsh.ts +203 -0
- package/src/oauth/generic-account-failover.ts +62 -12
- package/src/oauth/generic-session-affinity.ts +125 -0
- package/src/oauth/index.ts +188 -111
- package/src/oauth/kiro-device-login.ts +2 -1
- package/src/oauth/kiro.ts +7 -1
- package/src/oauth/local-token-detect.ts +21 -1
- package/src/oauth/login-cli-errors.ts +44 -0
- package/src/oauth/login-cli.ts +69 -7
- package/src/oauth/login-flow-state.ts +371 -23
- package/src/oauth/meta-muse-errors.ts +41 -0
- package/src/oauth/meta-muse-keychain.ts +52 -0
- package/src/oauth/meta-muse.ts +51 -84
- package/src/oauth/model-discovery-auth.ts +3 -0
- package/src/oauth/pool-settings-capability.ts +4 -2
- package/src/oauth/refresh-flight-retirement.ts +48 -0
- package/src/oauth/session-affinity-key.ts +23 -0
- package/src/oauth/store-anthropic-instance.ts +9 -2
- package/src/oauth/store.ts +12 -5
- package/src/protocols/codecs/chat-ir.ts +467 -0
- package/src/protocols/codecs/chat.ts +10 -1
- package/src/protocols/codecs/messages-ir.ts +500 -0
- package/src/protocols/encoders/adapter-events.ts +5 -4
- package/src/protocols/encoders/messages.ts +9 -6
- package/src/protocols/features.ts +10 -2
- package/src/protocols/path.ts +11 -1
- package/src/protocols/plan-snapshot.ts +39 -16
- package/src/protocols/plan.ts +9 -1
- package/src/protocols/provider-summary.ts +2 -1
- package/src/protocols/settings.ts +8 -0
- package/src/providers/antigravity-account-roster.ts +102 -0
- package/src/providers/antigravity-models.ts +85 -7
- package/src/providers/api-key-cooldowns.ts +49 -0
- package/src/providers/api-key-resolve.ts +11 -6
- package/src/providers/api-key-response-ownership.ts +57 -0
- package/src/providers/api-key-selection.ts +31 -6
- package/src/providers/api-keys.ts +214 -3
- package/src/providers/claude-cli-usage.ts +96 -0
- package/src/providers/dsh-account-destination.ts +31 -0
- package/src/providers/dsh-account-models.ts +41 -0
- package/src/providers/gcp-credential-cleanup.ts +59 -0
- package/src/providers/key-failover.ts +54 -50
- package/src/providers/key-store.ts +7 -2
- package/src/providers/model-rename-fields.ts +5 -0
- package/src/providers/model-rename-migration.ts +7 -5
- package/src/providers/openai-tiers-destination.ts +11 -2
- package/src/providers/openai-tiers.ts +5 -12
- package/src/providers/opencode-go-transport.ts +3 -1
- package/src/providers/quota/account-cache.ts +6 -5
- package/src/providers/quota/account-row.ts +34 -0
- package/src/providers/quota/antigravity.ts +28 -7
- package/src/providers/quota/dsh-account.ts +70 -0
- package/src/providers/quota/vendor-probes-oauth.ts +1 -93
- package/src/providers/quota-types.ts +2 -0
- package/src/providers/quota.ts +14 -20
- package/src/providers/registry/entries-core.ts +44 -14
- package/src/providers/registry/entries-extended.ts +19 -0
- package/src/providers/registry/types.ts +1 -1
- package/src/providers/request-pacing.ts +77 -19
- package/src/providers/routed-config.ts +339 -0
- package/src/providers/service-tier.ts +2 -1
- package/src/quota/window-mapping.ts +5 -2
- package/src/responses/anthropic-progress.ts +34 -0
- package/src/responses/assistant-replay.ts +35 -0
- package/src/responses/compaction-history-framing.ts +65 -0
- package/src/responses/compaction.ts +6 -1
- package/src/responses/incomplete-reason.ts +31 -0
- package/src/responses/parser.ts +78 -22
- package/src/responses/reasoning-envelope.ts +4 -0
- package/src/responses/reasoning-replay-cache.ts +24 -2
- package/src/responses/reasoning-retention.ts +173 -0
- package/src/responses/retained-compaction.ts +46 -0
- package/src/responses/schema.ts +23 -0
- package/src/responses/state.ts +32 -29
- package/src/router.ts +8 -321
- package/src/routing/health.ts +37 -22
- package/src/routing/history/build-file.ts +92 -0
- package/src/routing/history/indexer.ts +254 -221
- package/src/routing/history/ingest.ts +242 -0
- package/src/routing/history/rebuild-job.ts +111 -0
- package/src/routing/history/rebuild-protocol.ts +15 -0
- package/src/routing/history/rebuild-worker.ts +34 -0
- package/src/routing/profile.ts +1 -1
- package/src/server/admission-model-scope.ts +21 -1
- package/src/server/antigravity-direct-eligibility.ts +208 -0
- package/src/server/auth-cors.ts +15 -0
- package/src/server/chat-completions.ts +82 -10
- package/src/server/chat-native-reasoning.ts +123 -0
- package/src/server/chat-native-sse.ts +110 -7
- package/src/server/chat-native.ts +76 -17
- package/src/server/claude-messages.ts +164 -433
- package/src/server/effort-policy.ts +1 -1
- package/src/server/images.ts +15 -2
- package/src/server/index/desktop-compatibility-startup.ts +56 -0
- package/src/server/index/model-alias-id.ts +36 -0
- package/src/server/index/optional-listeners.ts +2 -0
- package/src/server/index/serve-options.ts +11 -3
- package/src/server/index/startup-warnings.ts +11 -0
- package/src/server/index/websocket-handler.ts +9 -0
- package/src/server/index.ts +14 -11
- package/src/server/inference/advisor-diagnostics.ts +31 -0
- package/src/server/inference/client-encoder-delivery.ts +6 -5
- package/src/server/login-shell-path.ts +146 -0
- package/src/server/management/advisor-routes.ts +202 -0
- package/src/server/management/agent-settings-routes.ts +22 -4
- package/src/server/management/claude-desktop-picker-routes.ts +1 -1
- package/src/server/management/combo-routes.ts +176 -50
- package/src/server/management/companion-routes.ts +4 -0
- package/src/server/management/config-routes.ts +77 -6
- package/src/server/management/context.ts +4 -0
- package/src/server/management/cursor-integration-routes.ts +1 -1
- package/src/server/management/desktop-compatibility-routes.ts +46 -0
- package/src/server/management/desktop-compatibility-runtime-routes.ts +46 -0
- package/src/server/management/desktop-compatibility-settings-routes.ts +27 -0
- package/src/server/management/model-routes.ts +13 -8
- package/src/server/management/model-rows.ts +14 -0
- package/src/server/management/native-integration-routes.ts +2 -7
- package/src/server/management/native-reasoning-retention-routes.ts +41 -0
- package/src/server/management/oauth-account-routes.ts +87 -14
- package/src/server/management/protocol-settings-patch.ts +1 -0
- package/src/server/management/provider-gcp-credential-routes.ts +29 -0
- package/src/server/management/provider-key-pacing-routes.ts +31 -0
- package/src/server/management/provider-overwrite-carry.ts +7 -0
- package/src/server/management/provider-routes.ts +25 -30
- package/src/server/management/route-registry.ts +21 -1
- package/src/server/management/sibling-guard.ts +1 -0
- package/src/server/management-api.ts +9 -1
- package/src/server/messages-antigravity-direct.ts +195 -0
- package/src/server/messages-native-tool-guard.ts +185 -0
- package/src/server/messages-native.ts +106 -22
- package/src/server/messages-shared.ts +431 -0
- package/src/server/relay.ts +1 -1
- package/src/server/request-log-terminal-status.ts +1 -1
- package/src/server/request-log.ts +13 -1
- package/src/server/responses/account-change-state.ts +8 -2
- package/src/server/responses/adapter-continuation.ts +48 -19
- package/src/server/responses/adapter-delivery.ts +43 -8
- package/src/server/responses/adapter-dispatch.ts +48 -4
- package/src/server/responses/advisor-plan-slot.ts +27 -0
- package/src/server/responses/advisor-retention.ts +117 -0
- package/src/server/responses/advisor-slot.ts +368 -0
- package/src/server/responses/code-mode-collab-surface.ts +116 -8
- package/src/server/responses/codex-ws-wire.ts +15 -8
- package/src/server/responses/compact.ts +303 -125
- package/src/server/responses/compaction-recovery.ts +18 -10
- package/src/server/responses/compaction-retention.ts +61 -0
- package/src/server/responses/context-overflow.ts +11 -6
- package/src/server/responses/core-auth.ts +6 -0
- package/src/server/responses/core-codex-account.ts +11 -1
- package/src/server/responses/core-combo-failure.ts +12 -1
- package/src/server/responses/core-combo.ts +141 -36
- package/src/server/responses/core-errors.ts +3 -3
- package/src/server/responses/core-lifetime.ts +7 -2
- package/src/server/responses/core-normalize.ts +11 -0
- package/src/server/responses/core-opaque-recovery.ts +35 -0
- package/src/server/responses/core-options.ts +51 -0
- package/src/server/responses/core-pipeline.ts +141 -0
- package/src/server/responses/core-replay.ts +25 -6
- package/src/server/responses/core.ts +3 -116
- package/src/server/responses/fetch-helpers.ts +73 -19
- package/src/server/responses/main-hard-lock-routing.ts +109 -0
- package/src/server/responses/native-response-control.ts +4 -2
- package/src/server/responses/passthrough-delivery.ts +19 -11
- package/src/server/responses/passthrough-dispatch.ts +29 -16
- package/src/server/responses/request-prepare.ts +144 -17
- package/src/server/responses/request-sidecar-auth.ts +2 -2
- package/src/server/responses/request-transport.ts +120 -27
- package/src/server/responses/response-effects.ts +1 -0
- package/src/server/responses/run-turn-execution.ts +166 -38
- package/src/server/responses/sidecar-execution.ts +98 -5
- package/src/server/responses/terminal-guard.ts +4 -17
- package/src/server/responses-undeclared-tool-guard.ts +30 -9
- package/src/server/startup-action-control.ts +16 -2
- package/src/server/startup-health-cache.ts +1 -0
- package/src/service/auth-preflight.ts +71 -0
- package/src/service/cli.ts +4 -2
- package/src/service/definition.ts +97 -0
- package/src/service/desktop-startup.ts +14 -0
- package/src/service/guards.ts +1 -61
- package/src/service/health-sentinel-linux.ts +112 -0
- package/src/service/health-sentinel-main.ts +99 -61
- package/src/service/health-sentinel-probe.ts +24 -7
- package/src/service/health.ts +5 -89
- package/src/service/launchd.ts +27 -7
- package/src/service/logging.ts +135 -0
- package/src/service/repair.ts +2 -1
- package/src/service/state.ts +7 -8
- package/src/service/systemd.ts +1 -1
- package/src/service/windows-guarded-manager.ts +2 -1
- package/src/service/windows-ops.ts +1 -1
- package/src/service/windows-scheduler.ts +2 -7
- package/src/service/windows-taskxml.ts +2 -2
- package/src/service/windows-wscript.ts +14 -0
- package/src/service.ts +4 -2
- package/src/sidecar/auth.ts +2 -0
- package/src/tray/windows-tray.ps1 +43 -24
- package/src/types/config.ts +124 -6
- package/src/types/opencode-go.ts +61 -0
- package/src/types/opencode-zen.ts +29 -0
- package/src/types/provider.ts +39 -6
- package/src/types/request.ts +38 -2
- package/src/types/tools.ts +2 -0
- package/src/types/wire.ts +29 -37
- package/src/types.ts +1 -0
- package/src/update/async-check.ts +1 -1
- package/src/update/badge.ts +2 -2
- package/src/update/index.ts +88 -15
- package/src/update/job-supervised-restart.ts +107 -0
- package/src/update/job.ts +32 -32
- package/src/update/notify.ts +1 -1
- package/src/update/npm-invocation.mjs +12 -2
- package/src/update/refresh-scheduler.ts +2 -2
- package/src/update/supervised-recovery.d.mts +27 -0
- package/src/update/supervised-recovery.mjs +157 -0
- package/src/usage/cache-diagnostic.ts +2 -0
- package/src/usage/cost.ts +48 -12
- package/src/usage/expected-prices.ts +15 -0
- package/src/usage/ledger-retention.ts +2 -1
- package/src/usage/ledger-scanner.ts +6 -5
- package/src/usage/log.ts +17 -8
- package/src/usage/summary.ts +22 -9
- package/src/usage/user-cost-overlays.ts +14 -19
- package/src/usage/user-cost-validation.ts +38 -0
- package/src/vision/eligibility.ts +13 -0
- package/src/web-search/gemini-executor.ts +2 -2
- package/src/web-search/loop.ts +55 -5
- package/src/web-search/progress-stream.ts +4 -1
- package/src/web-search/run-turn-loop.ts +9 -1
- package/assets/sponsors/packycode.png +0 -0
- package/gui/dist/assets/App-CSJvmjNs.css +0 -1
- package/gui/dist/assets/App-CZtqiGcw.js +0 -56
- package/gui/dist/assets/index-BB6uK6tU.css +0 -1
- package/gui/dist/assets/index-CTm4l-HQ.js +0 -94
- package/gui/dist/assets/quota-summary-BbEeRfPY.js +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
inspectCodexCliInstall,
|
|
3
|
+
observeCodexCliSelectedCommand,
|
|
3
4
|
type CodexCliInstallProvenanceDeps,
|
|
4
5
|
type CodexCliInstallReport,
|
|
5
6
|
} from "../codex/cli-install-provenance";
|
|
@@ -11,20 +12,29 @@ import type {
|
|
|
11
12
|
CodexCliInstallationSnapshot,
|
|
12
13
|
CodexCliInstallationTargetDerivation,
|
|
13
14
|
} from "../codex/cli-installation-targets";
|
|
15
|
+
import {
|
|
16
|
+
createCodexCliUpdatePlan,
|
|
17
|
+
type CodexCliUpdateChannel,
|
|
18
|
+
type CodexCliUpdatePlan,
|
|
19
|
+
type CodexCliUpdatePlanDeps,
|
|
20
|
+
} from "../codex/cli-update-plan";
|
|
21
|
+
import {
|
|
22
|
+
type ResolveCodexRuntimeDeps,
|
|
23
|
+
type ResolveCodexRuntimeResult,
|
|
24
|
+
} from "../codex/runtime";
|
|
14
25
|
import { CliUsageError, isJsonOption, printData, runCliAction } from "./runtime-api";
|
|
15
26
|
import { trustedNodeLauncherContext } from "./launcher-context";
|
|
16
27
|
|
|
17
28
|
export const CODEX_CLI_UPDATE_USAGE = `Usage:
|
|
18
29
|
ocx system codex-cli-update check [--json]
|
|
19
30
|
ocx system codex-cli-update attest [--json]
|
|
20
|
-
ocx system codex-cli-update attest --candidate <absolute-path> --npm-prefix <absolute-path> --npm-cli <absolute-path> --node <absolute-path> [--json]
|
|
31
|
+
ocx system codex-cli-update attest --candidate <absolute-path> --npm-prefix <absolute-path> --npm-cli <absolute-path> --node <absolute-path> [--json]
|
|
32
|
+
ocx system codex-cli-update plan [--channel latest] [--json]`;
|
|
21
33
|
|
|
22
|
-
export type ParsedCodexCliUpdateArgs =
|
|
23
|
-
json: boolean
|
|
24
|
-
|
|
25
|
-
json: boolean;
|
|
26
|
-
attest: CodexCliInstallationIdentityInput | "selected";
|
|
27
|
-
}>;
|
|
34
|
+
export type ParsedCodexCliUpdateArgs =
|
|
35
|
+
| Readonly<{ action: "check"; json: boolean }>
|
|
36
|
+
| Readonly<{ action: "plan"; json: boolean; channel: CodexCliUpdateChannel }>
|
|
37
|
+
| Readonly<{ json: boolean; attest: CodexCliInstallationIdentityInput | "selected" }>;
|
|
28
38
|
|
|
29
39
|
export interface CodexCliUpdateCommandDeps {
|
|
30
40
|
readonly inspectInstall?: (deps: CodexCliInstallProvenanceDeps) => Promise<CodexCliInstallReport>;
|
|
@@ -32,6 +42,8 @@ export interface CodexCliUpdateCommandDeps {
|
|
|
32
42
|
readonly deriveInstallationInput?: (
|
|
33
43
|
snapshot: CodexCliInstallationSnapshot,
|
|
34
44
|
) => Promise<CodexCliInstallationTargetDerivation>;
|
|
45
|
+
readonly createPlan?: (deps: CodexCliUpdatePlanDeps) => Promise<CodexCliUpdatePlan>;
|
|
46
|
+
readonly resolveSelectedRuntime?: (deps: ResolveCodexRuntimeDeps) => ResolveCodexRuntimeResult;
|
|
35
47
|
}
|
|
36
48
|
|
|
37
49
|
function identitySummary(report: CodexCliInstallationIdentityReport): string[] {
|
|
@@ -68,24 +80,60 @@ function installSummary(report: CodexCliInstallReport): string[] {
|
|
|
68
80
|
];
|
|
69
81
|
}
|
|
70
82
|
|
|
83
|
+
function planSummary(plan: CodexCliUpdatePlan): string[] {
|
|
84
|
+
const lines = [
|
|
85
|
+
`applicable: ${plan.applicable ? "yes" : "no"}`,
|
|
86
|
+
`reason: ${plan.refusal ?? "none"}`,
|
|
87
|
+
`provenance: ${plan.provenance}`,
|
|
88
|
+
`installed-version: ${plan.installedVersion ?? "unavailable"}`,
|
|
89
|
+
`version-evidence: ${plan.versionEvidence}`,
|
|
90
|
+
`channel: ${plan.channel}`,
|
|
91
|
+
`target-version: ${plan.targetVersion ?? "unresolved"}`,
|
|
92
|
+
`target-integrity: ${plan.targetIntegrity ?? "unresolved"}`,
|
|
93
|
+
`session: ${plan.session.state}${plan.session.matches === null ? "" : ` (${plan.session.matches})`}`,
|
|
94
|
+
];
|
|
95
|
+
if (plan.planId) lines.push(`plan: ${plan.planId}`);
|
|
96
|
+
if (plan.command) lines.push(`command: ${plan.command.join(" ")} (indicative — a future apply phase verifies the packed tarball and installs the verified file)`);
|
|
97
|
+
return lines;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Read ``--name value`` and ``--name=value`` alike; both spellings reach this CLI. */
|
|
102
|
+
function optionValue(tokens: readonly string[], index: number, name: string): { value: string; next: number } {
|
|
103
|
+
const token = tokens[index]!;
|
|
104
|
+
const inline = `--${name}=`;
|
|
105
|
+
if (token.startsWith(inline)) {
|
|
106
|
+
const value = token.slice(inline.length);
|
|
107
|
+
if (!value) throw new CliUsageError(`--${name} requires a value`, CODEX_CLI_UPDATE_USAGE);
|
|
108
|
+
return { value, next: index + 1 };
|
|
109
|
+
}
|
|
110
|
+
const value = tokens[index + 1];
|
|
111
|
+
if (value === undefined) throw new CliUsageError(`--${name} requires a value`, CODEX_CLI_UPDATE_USAGE);
|
|
112
|
+
return { value, next: index + 2 };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function isOption(token: string, name: string): boolean {
|
|
116
|
+
return token === `--${name}` || token.startsWith(`--${name}=`);
|
|
117
|
+
}
|
|
118
|
+
|
|
71
119
|
export function parseCodexCliUpdateArgs(argv: readonly string[]): ParsedCodexCliUpdateArgs {
|
|
72
120
|
// `--json` is accepted in any argv position CLI-wide, so remove it before positional
|
|
73
|
-
// validation. Requiring
|
|
121
|
+
// validation. Requiring the action at index 0 first would reject `--json check`, which
|
|
74
122
|
// automation that puts output flags ahead of the subcommand legitimately produces.
|
|
75
123
|
let json = false;
|
|
76
|
-
const
|
|
124
|
+
const rest: string[] = [];
|
|
77
125
|
for (const token of argv) {
|
|
78
126
|
if (isJsonOption(token)) {
|
|
79
127
|
if (json) throw new CliUsageError("--json may be specified only once", CODEX_CLI_UPDATE_USAGE);
|
|
80
128
|
json = true;
|
|
81
129
|
continue;
|
|
82
130
|
}
|
|
83
|
-
|
|
131
|
+
rest.push(token);
|
|
84
132
|
}
|
|
85
|
-
if (
|
|
133
|
+
if (rest[0] === "attest") {
|
|
86
134
|
// No options: attest the selected candidate identified from the proof-bound
|
|
87
135
|
// launcher snapshot. The four explicit paths remain all-or-none.
|
|
88
|
-
if (
|
|
136
|
+
if (rest.length === 1) {
|
|
89
137
|
return Object.freeze({ json, attest: "selected" as const });
|
|
90
138
|
}
|
|
91
139
|
const options = new Map<string, keyof CodexCliInstallationIdentityInput>([
|
|
@@ -93,12 +141,12 @@ export function parseCodexCliUpdateArgs(argv: readonly string[]): ParsedCodexCli
|
|
|
93
141
|
["--npm-cli", "npmCli"], ["--node", "node"],
|
|
94
142
|
]);
|
|
95
143
|
const input: Partial<Record<keyof CodexCliInstallationIdentityInput, string>> = {};
|
|
96
|
-
for (let index = 1; index <
|
|
97
|
-
const key = options.get(
|
|
144
|
+
for (let index = 1; index < rest.length; index += 2) {
|
|
145
|
+
const key = options.get(rest[index]!);
|
|
98
146
|
if (!key || input[key] !== undefined) {
|
|
99
147
|
throw new CliUsageError("unsupported or duplicate attest option", CODEX_CLI_UPDATE_USAGE);
|
|
100
148
|
}
|
|
101
|
-
const value =
|
|
149
|
+
const value = rest[index + 1];
|
|
102
150
|
if (!value || !value.trim() || /[\0\r\n]/.test(value)
|
|
103
151
|
|| !(value.startsWith("/") || /^[a-z]:[\\/]/i.test(value))) {
|
|
104
152
|
throw new CliUsageError("attest options require explicit absolute paths", CODEX_CLI_UPDATE_USAGE);
|
|
@@ -112,13 +160,78 @@ export function parseCodexCliUpdateArgs(argv: readonly string[]): ParsedCodexCli
|
|
|
112
160
|
candidate: input.candidate, npmPrefix: input.npmPrefix, npmCli: input.npmCli, node: input.node,
|
|
113
161
|
}) });
|
|
114
162
|
}
|
|
115
|
-
|
|
116
|
-
|
|
163
|
+
const action = rest[0];
|
|
164
|
+
if (action !== "check" && action !== "plan") {
|
|
165
|
+
throw new CliUsageError("codex-cli-update action must be check, attest or plan", CODEX_CLI_UPDATE_USAGE);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (action === "check") {
|
|
169
|
+
if (rest.length > 1) throw new CliUsageError("unsupported codex-cli-update argument", CODEX_CLI_UPDATE_USAGE);
|
|
170
|
+
return Object.freeze({ action, json });
|
|
117
171
|
}
|
|
118
|
-
|
|
119
|
-
|
|
172
|
+
|
|
173
|
+
if (action === "plan") {
|
|
174
|
+
let channel: CodexCliUpdateChannel = "latest";
|
|
175
|
+
let seen = false;
|
|
176
|
+
let index = 1;
|
|
177
|
+
while (index < rest.length) {
|
|
178
|
+
const token = rest[index]!;
|
|
179
|
+
if (!isOption(token, "channel")) {
|
|
180
|
+
throw new CliUsageError("unsupported codex-cli-update argument", CODEX_CLI_UPDATE_USAGE);
|
|
181
|
+
}
|
|
182
|
+
if (seen) throw new CliUsageError("--channel may be specified only once", CODEX_CLI_UPDATE_USAGE);
|
|
183
|
+
const read = optionValue(rest, index, "channel");
|
|
184
|
+
// Only the stable channel is offered. A preview channel would need its own
|
|
185
|
+
// provenance story before it may install anything on the operator's behalf.
|
|
186
|
+
if (read.value !== "latest") throw new CliUsageError("--channel must be latest", CODEX_CLI_UPDATE_USAGE);
|
|
187
|
+
channel = read.value;
|
|
188
|
+
seen = true;
|
|
189
|
+
index = read.next;
|
|
190
|
+
}
|
|
191
|
+
return Object.freeze({ action, json, channel });
|
|
120
192
|
}
|
|
121
|
-
|
|
193
|
+
|
|
194
|
+
// Unreachable: the action check above already rejected every other verb, but the
|
|
195
|
+
// fallthrough keeps the parser total for the type checker.
|
|
196
|
+
throw new CliUsageError("unsupported codex-cli-update action", CODEX_CLI_UPDATE_USAGE);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Inspection inputs for this one-shot CLI process.
|
|
201
|
+
*
|
|
202
|
+
* The published Node launcher supplies a proof-bound snapshot of configured candidate
|
|
203
|
+
* evidence, not selected-runtime admission. A direct Bun or source launch has no such
|
|
204
|
+
* proof, so nothing ambient or persisted is inspected at all.
|
|
205
|
+
*/
|
|
206
|
+
function inspectionDeps(commandDeps: CodexCliUpdateCommandDeps): CodexCliInstallProvenanceDeps {
|
|
207
|
+
const trusted = trustedNodeLauncherContext()?.codexCliInspectionEnv;
|
|
208
|
+
if (!trusted || trusted.managerRoots === null) return { env: { PATH: "" }, configDir: "." };
|
|
209
|
+
// Attestation also requires the runtime resolver to pick the snapshot's
|
|
210
|
+
// candidate. probeVersion: false keeps this read-only — no codex --version
|
|
211
|
+
// executes on a check/plan path — while still refusing attestation when the
|
|
212
|
+
// resolver would settle on a different executable.
|
|
213
|
+
const selectedCommand = observeCodexCliSelectedCommand({
|
|
214
|
+
env: {
|
|
215
|
+
CODEX_CLI_PATH: trusted.codexCliPath ?? undefined,
|
|
216
|
+
PATH: trusted.path ?? undefined,
|
|
217
|
+
PATHEXT: trusted.pathExt ?? undefined,
|
|
218
|
+
},
|
|
219
|
+
configDir: trusted.configDir,
|
|
220
|
+
}, commandDeps.resolveSelectedRuntime);
|
|
221
|
+
return {
|
|
222
|
+
env: {
|
|
223
|
+
...trusted.managerRoots,
|
|
224
|
+
CODEX_CLI_PATH: trusted.codexCliPath ?? undefined,
|
|
225
|
+
PATH: trusted.path ?? undefined,
|
|
226
|
+
PATHEXT: trusted.pathExt ?? undefined,
|
|
227
|
+
},
|
|
228
|
+
configDir: trusted.configDir,
|
|
229
|
+
// The snapshot is proof-bound to the launcher, but the report may only attest
|
|
230
|
+
// the environment candidate when the resolver picks the same canonical path —
|
|
231
|
+
// managed requires both.
|
|
232
|
+
selectionAttested: true,
|
|
233
|
+
selectedCommand,
|
|
234
|
+
};
|
|
122
235
|
}
|
|
123
236
|
|
|
124
237
|
export async function handleCodexCliUpdateCommand(
|
|
@@ -136,7 +249,9 @@ export async function handleCodexCliUpdateCommand(
|
|
|
136
249
|
}
|
|
137
250
|
throw error;
|
|
138
251
|
}
|
|
139
|
-
|
|
252
|
+
// A refusal or an unapplied update is a legitimate answer rather than a crash, so the
|
|
253
|
+
// outcome exit code is decided here and only a thrown error is left to runCliAction.
|
|
254
|
+
const code = await runCliAction(async () => {
|
|
140
255
|
if ("attest" in parsed) {
|
|
141
256
|
let report: CodexCliInstallationIdentityReport;
|
|
142
257
|
try {
|
|
@@ -167,25 +282,20 @@ export async function handleCodexCliUpdateCommand(
|
|
|
167
282
|
printData(report, parsed.json, identitySummary(report));
|
|
168
283
|
return;
|
|
169
284
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
// ambient or persisted candidate state at all.
|
|
185
|
-
env: { PATH: "" },
|
|
186
|
-
configDir: ".",
|
|
187
|
-
};
|
|
188
|
-
const report = await (deps.inspectInstall ?? inspectCodexCliInstall)(inspectionDeps);
|
|
189
|
-
printData(report, parsed.json, installSummary(report));
|
|
285
|
+
if (parsed.action === "check") {
|
|
286
|
+
const report = await (deps.inspectInstall ?? inspectCodexCliInstall)(inspectionDeps(deps));
|
|
287
|
+
printData(report, parsed.json, installSummary(report));
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
if (parsed.action === "plan") {
|
|
291
|
+
const plan = await (deps.createPlan ?? createCodexCliUpdatePlan)({
|
|
292
|
+
channel: parsed.channel,
|
|
293
|
+
inspectionDeps: inspectionDeps(deps),
|
|
294
|
+
inspect: deps.inspectInstall,
|
|
295
|
+
});
|
|
296
|
+
printData(plan, parsed.json, planSummary(plan));
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
190
299
|
});
|
|
300
|
+
return code;
|
|
191
301
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { allowCodexProviderRouting, approvedCodexProviders, previewCodexProviderConsent, restoreApprovedCodexProviders } from "../codex/provider-routing";
|
|
2
|
+
import { interactiveConfirm } from "./interactive-confirm";
|
|
3
|
+
import { terminalSafeError, terminalSafeText } from "./runtime-api";
|
|
4
|
+
|
|
5
|
+
export const CODEX_PROVIDER_USAGE = "Usage: ocx codex-provider <status|allow <id> [--yes]|revoke <id>>";
|
|
6
|
+
|
|
7
|
+
export async function handleCodexProviderCommand(args: string[]): Promise<number> {
|
|
8
|
+
const [verb, id, flag] = args;
|
|
9
|
+
if (verb === "status" && args.length === 1) {
|
|
10
|
+
console.log(JSON.stringify({ approvedProviders: approvedCodexProviders() }));
|
|
11
|
+
return 0;
|
|
12
|
+
}
|
|
13
|
+
if ((verb !== "allow" && verb !== "revoke") || !id || args.length > 3
|
|
14
|
+
|| (flag !== undefined && (verb !== "allow" || flag !== "--yes"))) {
|
|
15
|
+
console.error(CODEX_PROVIDER_USAGE);
|
|
16
|
+
return 1;
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
if (verb === "revoke") {
|
|
20
|
+
restoreApprovedCodexProviders(id);
|
|
21
|
+
console.log(`Routing consent revoked for ${terminalSafeText(id)}; any unchanged managed URL was restored.`);
|
|
22
|
+
return 0;
|
|
23
|
+
}
|
|
24
|
+
const expected = previewCodexProviderConsent(id);
|
|
25
|
+
console.log(`OpenCodex will manage only base_url for Codex provider ${terminalSafeText(id)} in the selected CODEX_HOME.`);
|
|
26
|
+
console.log("Start/sync will route it to the local proxy; stop/restore will restore its original URL. Provider identity, transport settings and history stay unchanged.");
|
|
27
|
+
if (flag !== "--yes") {
|
|
28
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
29
|
+
console.error("Explicit consent required: use an interactive terminal or pass --yes with the exact provider ID.");
|
|
30
|
+
return 1;
|
|
31
|
+
}
|
|
32
|
+
if (!await interactiveConfirm({ question: "Allow this provider's routing to be managed?", defaultYes: false })) {
|
|
33
|
+
console.log("Cancelled; no consent or routing changes were saved.");
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
allowCodexProviderRouting(id, expected);
|
|
38
|
+
console.log("Consent saved. Run ocx start or ocx sync to apply routing; use ocx codex-provider revoke <id> to undo consent.");
|
|
39
|
+
return 0;
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error(terminalSafeError(error));
|
|
42
|
+
return 1;
|
|
43
|
+
}
|
|
44
|
+
}
|
package/src/cli/combo-input.ts
CHANGED
|
@@ -8,8 +8,9 @@ type ComboInput = {
|
|
|
8
8
|
imageInput?: "auto" | "disabled";
|
|
9
9
|
reasoningEffortMode?: "strict" | "adaptive";
|
|
10
10
|
nativeAlias?: boolean;
|
|
11
|
+
allowMeteredTargets?: boolean;
|
|
11
12
|
};
|
|
12
|
-
const TARGET_KEYS = new Set(["provider", "model", "weight", "reasoningEfforts", "modelProfile", "lastResort"]);
|
|
13
|
+
const TARGET_KEYS = new Set(["provider", "model", "weight", "reasoningEfforts", "modelProfile", "lastResort", "metered"]);
|
|
13
14
|
|
|
14
15
|
export function parseComboTargets(value: unknown): Array<Record<string, unknown>> {
|
|
15
16
|
if (!Array.isArray(value) || value.length === 0) throw new CliUsageError("Targets input must be a nonempty array");
|
|
@@ -41,6 +42,9 @@ export function parseComboTargets(value: unknown): Array<Record<string, unknown>
|
|
|
41
42
|
if (Object.hasOwn(target, "lastResort") && typeof target.lastResort !== "boolean") {
|
|
42
43
|
throw new CliUsageError("Target lastResort must be a boolean");
|
|
43
44
|
}
|
|
45
|
+
if (Object.hasOwn(target, "metered") && typeof target.metered !== "boolean") {
|
|
46
|
+
throw new CliUsageError("Target metered must be a boolean");
|
|
47
|
+
}
|
|
44
48
|
// Preserve raw slashes, target order, explicit false and omitted metadata.
|
|
45
49
|
return { ...target };
|
|
46
50
|
});
|
|
@@ -70,6 +74,10 @@ export async function prepareComboInput(args: string[], deps: RuntimeApiDeps = {
|
|
|
70
74
|
const image = takeOptionWithSyntax(args, "--image-input")?.value;
|
|
71
75
|
const reasoning = takeOptionWithSyntax(args, "--reasoning-effort-mode")?.value;
|
|
72
76
|
const nativeAlias = takeNativeAlias(args);
|
|
77
|
+
const metered = takeOptionWithSyntax(args, "--allow-metered-targets")?.value;
|
|
78
|
+
if (metered !== undefined && metered !== "on" && metered !== "off") {
|
|
79
|
+
throw new CliUsageError("--allow-metered-targets must be on or off");
|
|
80
|
+
}
|
|
73
81
|
if (file !== undefined && args.some(arg => arg === "--targets" || arg.startsWith("--targets="))) {
|
|
74
82
|
throw new CliUsageError("--targets-file cannot be combined with --targets");
|
|
75
83
|
}
|
|
@@ -84,5 +92,6 @@ export async function prepareComboInput(args: string[], deps: RuntimeApiDeps = {
|
|
|
84
92
|
...(image === undefined ? {} : { imageInput: image }),
|
|
85
93
|
...(reasoning === undefined ? {} : { reasoningEffortMode: reasoning }),
|
|
86
94
|
...(nativeAlias === undefined ? {} : { nativeAlias }),
|
|
95
|
+
...(metered === undefined ? {} : { allowMeteredTargets: metered === "on" }),
|
|
87
96
|
};
|
|
88
97
|
}
|
package/src/cli/combo-result.ts
CHANGED
|
@@ -33,7 +33,7 @@ function publicCombo(value: unknown): Record<string, unknown> {
|
|
|
33
33
|
} else if (Object.hasOwn(RANGES, key)) {
|
|
34
34
|
const [min, max] = RANGES[key]!;
|
|
35
35
|
if (typeof child !== "number" || !Number.isSafeInteger(child) || child < min || child > max) invalid();
|
|
36
|
-
} else if (key === "nativeAlias") {
|
|
36
|
+
} else if (key === "nativeAlias" || key === "allowMeteredTargets") {
|
|
37
37
|
if (typeof child !== "boolean") invalid();
|
|
38
38
|
} else invalid();
|
|
39
39
|
result[key] = child;
|
package/src/cli/combo.ts
CHANGED
|
@@ -23,7 +23,7 @@ const USAGE = `Usage:
|
|
|
23
23
|
[--strategy <failover|round-robin|random|least-used|reset-window|jev>] [--sticky <1-100|->]
|
|
24
24
|
[--effort <low|medium|high|xhigh|max|ultra|->] [--effort-mode <fallback|force|->]
|
|
25
25
|
(force overrides valid client effort and can increase cost/latency) [--alias <name|->]
|
|
26
|
-
[--native-alias [on|off]] [--display-name <label|->]
|
|
26
|
+
[--native-alias [on|off]] [--allow-metered-targets <on|off>] [--display-name <label|->]
|
|
27
27
|
[--image-input <auto|disabled>] [--reasoning-effort-mode <strict|adaptive>]
|
|
28
28
|
[--decision-provider <provider|-> | --decision-model <route|->] [--decision-timeout <ms|->]
|
|
29
29
|
(jev only; the provider must be a configured jev-decision row)
|
|
@@ -160,6 +160,7 @@ async function set(argv: string[], deps: RuntimeApiDeps): Promise<number> {
|
|
|
160
160
|
if (effortMode !== undefined) combo.defaultEffortMode = effortMode === "-" ? "fallback" : effortMode;
|
|
161
161
|
if (alias !== undefined) combo.alias = alias === "-" ? "" : alias;
|
|
162
162
|
if (additional.nativeAlias !== undefined) combo.nativeAlias = additional.nativeAlias;
|
|
163
|
+
if (additional.allowMeteredTargets !== undefined) combo.allowMeteredTargets = additional.allowMeteredTargets;
|
|
163
164
|
if (additional.imageInput !== undefined) combo.imageInput = additional.imageInput;
|
|
164
165
|
if (additional.reasoningEffortMode !== undefined) combo.reasoningEffortMode = additional.reasoningEffortMode;
|
|
165
166
|
if (displayName !== undefined) combo.displayName = displayName === "-" ? "" : displayName;
|
|
@@ -14,6 +14,7 @@ import { readClientConnectionState } from "../client/state";
|
|
|
14
14
|
import { findManagedRegion, resolveGrokHome } from "../grok/inject";
|
|
15
15
|
import { providerTableString } from "../codex/injected-marker";
|
|
16
16
|
import { isLocalAttestationSecret } from "../lib/local-management-attestation";
|
|
17
|
+
import { isProtectedHomeUnderTest } from "../lib/test-home-guard";
|
|
17
18
|
import { readOwnerRegistry } from "../config/owner-registry";
|
|
18
19
|
import {
|
|
19
20
|
classifyHealthz,
|
|
@@ -160,7 +161,7 @@ export async function findCrossHomeOwnerDetailed(options: { homeDir?: string; io
|
|
|
160
161
|
};
|
|
161
162
|
|
|
162
163
|
const defaultHome = join(options.homeDir ?? homedir(), ".opencodex");
|
|
163
|
-
recordHome(defaultHome);
|
|
164
|
+
if (options.homeDir !== undefined || !isProtectedHomeUnderTest(defaultHome)) recordHome(defaultHome);
|
|
164
165
|
// The shared registry is what lets one custom home find another: every runtime
|
|
165
166
|
// that published a runtime record registered its home beside the shared clients.
|
|
166
167
|
const registry = readOwnerRegistry();
|
|
@@ -291,33 +292,35 @@ export async function findCrossHomeOwnerDetailed(options: { homeDir?: string; io
|
|
|
291
292
|
}
|
|
292
293
|
|
|
293
294
|
/** Mark this process before any shared-client write when another home owns the clients. */
|
|
294
|
-
export async function markCrossHomeSibling(
|
|
295
|
-
|
|
295
|
+
export async function markCrossHomeSibling(
|
|
296
|
+
options: Parameters<typeof findCrossHomeOwnerDetailed>[0] = {},
|
|
297
|
+
): Promise<boolean> {
|
|
298
|
+
const verdict = await findCrossHomeOwnerDetailed(options);
|
|
296
299
|
if (verdict.kind === "none") return false;
|
|
297
|
-
if (verdict.port === null) throw new Error("Shared-client owner could not be located; refusing startup before any shared-client write.");
|
|
298
300
|
if (verdict.kind === "indeterminate") {
|
|
299
|
-
//
|
|
300
|
-
//
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
"
|
|
304
|
-
+ "treating this instance as a sibling so Codex, Grok and Claude configs are left alone.",
|
|
301
|
+
// A missed probe is not proof of a sibling topology. Refuse before publication
|
|
302
|
+
// so the service can retry discovery without freezing uncertainty for its lifetime.
|
|
303
|
+
throw new Error(
|
|
304
|
+
`Shared-client owner could not be verified (${verdict.reason}); `
|
|
305
|
+
+ "refusing startup before any shared-client write. Retry startup after discovery recovers.",
|
|
305
306
|
);
|
|
306
307
|
}
|
|
307
|
-
|
|
308
|
-
markSiblingStart(port);
|
|
308
|
+
markSiblingStart(verdict.port);
|
|
309
309
|
return true;
|
|
310
310
|
}
|
|
311
311
|
|
|
312
312
|
/** A live proxy in this home can publish its sibling owner even while that owner is down. */
|
|
313
|
-
export async function markLiveHomeSibling(
|
|
313
|
+
export async function markLiveHomeSibling(
|
|
314
|
+
live: { pid: number | null; port: number },
|
|
315
|
+
options: Parameters<typeof findCrossHomeOwnerDetailed>[0] = {},
|
|
316
|
+
): Promise<boolean> {
|
|
314
317
|
const runtime = readRuntimePort();
|
|
315
318
|
if (live.pid !== null && runtime?.pid === live.pid && runtime.port === live.port
|
|
316
319
|
&& runtime.siblingOfPort !== undefined && runtime.siblingOfPort !== live.port) {
|
|
317
320
|
markSiblingStart(runtime.siblingOfPort);
|
|
318
321
|
return true;
|
|
319
322
|
}
|
|
320
|
-
const verdict = await findCrossHomeOwnerDetailed();
|
|
323
|
+
const verdict = await findCrossHomeOwnerDetailed(options);
|
|
321
324
|
if (verdict.kind === "none" || verdict.port === live.port) return false;
|
|
322
325
|
if (verdict.port === null) throw new Error("Shared-client owner could not be located; refusing startup before any shared-client write.");
|
|
323
326
|
markSiblingStart(verdict.port);
|
package/src/cli/dispatch.ts
CHANGED
|
@@ -370,19 +370,32 @@ const commandRunners: Record<string, CommandRunner> = {
|
|
|
370
370
|
},
|
|
371
371
|
login: async deps => {
|
|
372
372
|
const loginArgs = deps.args.slice(1);
|
|
373
|
+
// `--headless` is the only flag this command takes; the provider is the first bare word, so
|
|
374
|
+
// `ocx login --headless anthropic` and `ocx login anthropic --headless` mean the same thing.
|
|
375
|
+
// It is deliberately not `--code`: that name carries a secret value everywhere else in the
|
|
376
|
+
// CLI (`ocx account login <provider> --code <value>`) and its operand is scrubbed from stderr.
|
|
377
|
+
const codeMode = loginArgs.includes("--headless");
|
|
378
|
+
const positional = loginArgs.filter(arg => !arg.startsWith("--"));
|
|
373
379
|
// 'ocx login codex' is the command people type first, and until now it answered with
|
|
374
380
|
// the full provider wall because the Codex pool lives behind 'ocx account login'.
|
|
375
381
|
// Route the three Codex spellings to that flow instead of making the user discover
|
|
376
382
|
// a second noun. Everything else stays on the local OAuth/API-key path.
|
|
377
383
|
const { isCodexAccountLoginName, handleAccountAuthCommand } = await import("./account-auth");
|
|
378
|
-
if (isCodexAccountLoginName(
|
|
384
|
+
if (isCodexAccountLoginName(positional[0] ?? "")) {
|
|
385
|
+
// `--headless` is the OAuth code-display mode, which Codex does not have; account-auth
|
|
386
|
+
// would reject the flag as an unexpected argument. Codex's headless path is the device-code
|
|
387
|
+
// login, so point there instead.
|
|
388
|
+
if (codeMode) {
|
|
389
|
+
console.error("Codex has no code-display login. For a headless host use: ocx account login codex --device");
|
|
390
|
+
return 1;
|
|
391
|
+
}
|
|
379
392
|
// null means "unknown subcommand", which "login" never is; the coalesce exists because
|
|
380
393
|
// the shared signature serves callers that do pass an unknown one.
|
|
381
394
|
const code = await handleAccountAuthCommand("login", loginArgs, { findLiveProxy: deps.findLiveProxy });
|
|
382
395
|
return code ?? 1;
|
|
383
396
|
}
|
|
384
397
|
const { handleLogin } = await import("../oauth/login-cli");
|
|
385
|
-
await handleLogin(
|
|
398
|
+
await handleLogin(positional[0], {}, { codeMode });
|
|
386
399
|
return 0;
|
|
387
400
|
},
|
|
388
401
|
logout: async deps => {
|
|
@@ -461,11 +474,15 @@ const commandRunners: Record<string, CommandRunner> = {
|
|
|
461
474
|
code = 1;
|
|
462
475
|
console.error("Codex sync did not complete. Fix the reported Codex config issue and retry.");
|
|
463
476
|
}
|
|
464
|
-
//
|
|
477
|
+
// Catalog/model-cache writes retain their warning/restart handling. This is
|
|
465
478
|
// deliberately not an `else`: refreshCodexModelCatalog runs before injectCodexConfig,
|
|
466
479
|
// so a sync can fail (`ok: false`) after the catalog was already rewritten — which is
|
|
467
480
|
// exactly when a long-lived app-server is holding the stale list.
|
|
468
|
-
|
|
481
|
+
// A configuration-only change also needs a reload, but only when explicitly
|
|
482
|
+
// requested. A successful no-op or refused write is never restart authority.
|
|
483
|
+
const requestedConfigRestart = (restartScope.appServers || restartScope.desktopApp)
|
|
484
|
+
&& synced.ok && synced.configChanged === true;
|
|
485
|
+
if (synced.catalogWritten || synced.cacheSynced || requestedConfigRestart) {
|
|
469
486
|
await handleRestartScopeAfterWrite(restartScope, console);
|
|
470
487
|
}
|
|
471
488
|
// `ocx sync` is a direct CLI path; it does not call the management
|
|
@@ -484,7 +501,7 @@ const commandRunners: Record<string, CommandRunner> = {
|
|
|
484
501
|
},
|
|
485
502
|
config,
|
|
486
503
|
port: live.port,
|
|
487
|
-
}, ["mcode", "pi", "raycast", "omo", "cline", "commandcode", "droid", "opencode", "kilo"]));
|
|
504
|
+
}, ["mcode", "pi", "raycast", "omo", "cline", "commandcode", "droid", "opencode", "kilo", "qoder"]));
|
|
488
505
|
} catch (error) {
|
|
489
506
|
console.warn(`Client integrations were not refreshed: ${error instanceof Error ? error.message : String(error)}`);
|
|
490
507
|
}
|
|
@@ -834,6 +851,10 @@ const commandRunners: Record<string, CommandRunner> = {
|
|
|
834
851
|
const { handleComboCommand } = await import("./combo");
|
|
835
852
|
return await handleComboCommand(deps.args.slice(1));
|
|
836
853
|
},
|
|
854
|
+
advisor: async deps => {
|
|
855
|
+
const { handleAdvisorCommand } = await import("./advisor");
|
|
856
|
+
return await handleAdvisorCommand(deps.args.slice(1));
|
|
857
|
+
},
|
|
837
858
|
companion: async deps => {
|
|
838
859
|
const { handleCompanionCommand } = await import("./companion");
|
|
839
860
|
return await handleCompanionCommand(deps.args.slice(1), { findLiveProxy: deps.findLiveProxy });
|
|
@@ -941,6 +962,10 @@ const commandRunners: Record<string, CommandRunner> = {
|
|
|
941
962
|
const { handleLabCommand } = await import("./lab");
|
|
942
963
|
return await handleLabCommand(deps.args.slice(1));
|
|
943
964
|
},
|
|
965
|
+
"codex-provider": async deps => {
|
|
966
|
+
const { handleCodexProviderCommand } = await import("./codex-provider");
|
|
967
|
+
return await handleCodexProviderCommand(deps.args.slice(1));
|
|
968
|
+
},
|
|
944
969
|
chatgpt: async deps => {
|
|
945
970
|
const { handleChatgptCommand } = await import("./chatgpt-command");
|
|
946
971
|
return await handleChatgptCommand(deps.args.slice(1));
|
package/src/cli/doctor.ts
CHANGED
|
@@ -1160,6 +1160,11 @@ async function fetchExposedModelIds(live: LiveProxy, fetchFn: ExposedModelsFetch
|
|
|
1160
1160
|
if (id.length === 0) continue;
|
|
1161
1161
|
if (id.length > EXPOSED_MODEL_ID_MAX_LENGTH) return null;
|
|
1162
1162
|
ids.add(id);
|
|
1163
|
+
const nativeId = (row as { native_id?: unknown }).native_id;
|
|
1164
|
+
if (nativeId !== undefined) {
|
|
1165
|
+
if (typeof nativeId !== "string" || nativeId.length > EXPOSED_MODEL_ID_MAX_LENGTH) return null;
|
|
1166
|
+
if (nativeId.length > 0) ids.add(nativeId);
|
|
1167
|
+
}
|
|
1163
1168
|
}
|
|
1164
1169
|
return ids;
|
|
1165
1170
|
} catch {
|
|
@@ -1428,6 +1433,15 @@ export async function runDoctor(args: string[] = []): Promise<void> {
|
|
|
1428
1433
|
}
|
|
1429
1434
|
}
|
|
1430
1435
|
|
|
1436
|
+
// #2999: which process refreshes the native main login in CODEX_HOME.
|
|
1437
|
+
console.log("\nNative main refresh");
|
|
1438
|
+
{
|
|
1439
|
+
const { loadConfig } = await import("../config");
|
|
1440
|
+
const { formatNativeMainRefreshDoctorLines, resolveNativeMainRefreshMode } = await import("../codex/native-main-refresh-mode");
|
|
1441
|
+
const resolution = await resolveNativeMainRefreshMode(loadConfig());
|
|
1442
|
+
for (const line of formatNativeMainRefreshDoctorLines(resolution)) console.log(line);
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1431
1445
|
// Mirrors `ocx status` through the same comparison rather than a second implementation:
|
|
1432
1446
|
// two diagnostics disagreeing about whether an install is stale is worse than one (#2701).
|
|
1433
1447
|
// No extra probe -- findLiveProxy already carried the version back.
|
|
@@ -1458,7 +1472,7 @@ export async function runDoctor(args: string[] = []): Promise<void> {
|
|
|
1458
1472
|
|
|
1459
1473
|
// Observe-only and warning-level: a bypassed Desktop first-party install still serves the
|
|
1460
1474
|
// CLI and every non-Desktop client, so this never records a doctor failure.
|
|
1461
|
-
const desktopSystemProxyLines = formatDesktopSystemProxyLines(collectDesktopSystemProxy(doctorConfig));
|
|
1475
|
+
const desktopSystemProxyLines = formatDesktopSystemProxyLines(await collectDesktopSystemProxy(doctorConfig));
|
|
1462
1476
|
if (desktopSystemProxyLines.length > 0) {
|
|
1463
1477
|
console.log("\nClaude Desktop first-party vs Windows system proxy");
|
|
1464
1478
|
for (const line of desktopSystemProxyLines) console.log(line);
|