@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,7 @@
|
|
|
1
|
+
import { canInferVendorContext } from "./vendor-context";
|
|
1
2
|
import { effectiveProviderAlias, effectiveProviderAliasDecision } from "../../providers/default-aliases";
|
|
2
3
|
import { initialModelSelectionPending } from "../../providers/initial-model-selection";
|
|
4
|
+
import { supportsConfiguredUltraFast } from "./configured-tiers";
|
|
3
5
|
import { execFileSync } from "node:child_process";
|
|
4
6
|
import { createHash, createHmac, randomBytes } from "node:crypto";
|
|
5
7
|
import { copyFileSync, existsSync, mkdirSync, readFileSync, realpathSync } from "node:fs";
|
|
@@ -33,7 +35,6 @@ import {
|
|
|
33
35
|
import type { OcxConfig, OcxProviderConfig } from "../../types";
|
|
34
36
|
import { modelInList } from "../../types";
|
|
35
37
|
import { CODEX_REASONING_LEVELS, codexEffortRank, configuredReasoningEfforts, modelRecordValue, sanitizeCodexReasoningEfforts } from "../../reasoning-effort";
|
|
36
|
-
import { isModelVisionSidecarConsumer } from "../../vision/eligibility";
|
|
37
38
|
import { getModelMetadata, getModelMetadataCaseInsensitive, listModelMetadata, resolveMetadataProvider, type ModelMetadata } from "../../generated/model-metadata";
|
|
38
39
|
import { enrichProviderFromRegistry, shouldCaseFoldMetadataModelId } from "../../providers/derive";
|
|
39
40
|
import {
|
|
@@ -101,7 +102,7 @@ import type {
|
|
|
101
102
|
CatalogTrustedOpenAiApiPolicySnapshot,
|
|
102
103
|
} from "../convergence-types";
|
|
103
104
|
import type { CatalogGatherProviderAuthOutcome, CatalogGatherProviderModelOutcome, GatherFlightCapture, ModelsAuthResolverFactory } from "./gather-capture";
|
|
104
|
-
import { applyProviderConfigHints, configuredAutoCompactTokenLimit, configuredMaxInputTokens, configuredReasoningSummarySupport, modelInputModalities, routedMaxOutputTokens } from "./model-hints";
|
|
105
|
+
import { applyProviderConfigHints, configuredAutoCompactTokenLimit, configuredMaxInputTokens, configuredReasoningSummarySupport, modelInputModalities, routedMaxOutputTokens, withVisionSidecarInput } from "./model-hints";
|
|
105
106
|
import { resolveComboCatalogMember } from "./combo-member";
|
|
106
107
|
import { captureGatherFlight, captureTrustedOpenAiApiPolicy, gatherFlightKey, keyedGatherBytesIdentity, withCanonicalOpenAiForwardAuthDefault } from "./gather-capture";
|
|
107
108
|
import { fetchProviderModelsWithAuth, observedModelsAuthResolver, refreshingModelsAuthResolver } from "./provider-models";
|
|
@@ -318,6 +319,7 @@ function boundCustomNativeReasoning(
|
|
|
318
319
|
return bounded;
|
|
319
320
|
}
|
|
320
321
|
|
|
322
|
+
/** Gather discovered and custom rows under one captured provider policy, including speed capabilities. */
|
|
321
323
|
async function gatherRoutedModelsUncached(
|
|
322
324
|
config: OcxConfig,
|
|
323
325
|
capture: GatherFlightCapture,
|
|
@@ -327,6 +329,7 @@ async function gatherRoutedModelsUncached(
|
|
|
327
329
|
const localProviderAuthOutcomes = capture.providerAuthOutcomes;
|
|
328
330
|
const resolveAuth = capture.authResolver;
|
|
329
331
|
const ttlMs = config.modelCacheTtlMs ?? DEFAULT_MODEL_CACHE_TTL_MS;
|
|
332
|
+
const visionSidecarEnabled = config.visionSidecar?.enabled !== false;
|
|
330
333
|
// Persisted provider entries can predate newer registry fields (noVisionModels,
|
|
331
334
|
// modelInputModalities, ...). The ROUTER merges registry seeds at request time
|
|
332
335
|
// (routedProviderConfig), so the proxy behaves correctly — the catalog listing must see the
|
|
@@ -334,6 +337,8 @@ async function gatherRoutedModelsUncached(
|
|
|
334
337
|
// vision-sidecar model advertised text-only, blocking image attachments app-side).
|
|
335
338
|
// Enrich a CLONE: hydrated defaults must never leak into the persisted config.
|
|
336
339
|
const activeProviders = capture.providers;
|
|
340
|
+
// Use admission-time provider clones for sidecar advertisement, custom rows and combo members.
|
|
341
|
+
const enrichedByName = new Map(activeProviders.map(provider => [provider.name, provider.provider]));
|
|
337
342
|
const providerResults = await Promise.all(
|
|
338
343
|
activeProviders.map(provider => fetchProviderModelsWithAuth(
|
|
339
344
|
provider,
|
|
@@ -358,6 +363,7 @@ async function gatherRoutedModelsUncached(
|
|
|
358
363
|
const policy = fastPolicyForModel(apiProvider.provider, model.id, apiProvider.name);
|
|
359
364
|
const supported = serviceTierSupportFromPolicy(policy);
|
|
360
365
|
if (supported !== undefined) model.supportsServiceTier = supported;
|
|
366
|
+
model.supportsUltraFastTier = supportsConfiguredUltraFast(policy);
|
|
361
367
|
if (supported === true && policy.fastTierDescription !== undefined) model.fastTierDescription = policy.fastTierDescription;
|
|
362
368
|
}
|
|
363
369
|
}
|
|
@@ -374,7 +380,9 @@ async function gatherRoutedModelsUncached(
|
|
|
374
380
|
config,
|
|
375
381
|
metadataModelIdCaseFoldByProvider,
|
|
376
382
|
metadataConfigDirByProvider,
|
|
383
|
+
false,
|
|
377
384
|
)
|
|
385
|
+
.map(model => withVisionSidecarInput(model, enrichedByName.get(model.provider), visionSidecarEnabled))
|
|
378
386
|
// Drop image/video generation models (e.g. Grok image/video) by default. Cursor's static catalog
|
|
379
387
|
// intentionally mirrors Cursor's public model table, including Gemini image preview, so the
|
|
380
388
|
// exposure decision goes through shouldExposeRoutedModel (single choke point).
|
|
@@ -467,7 +475,7 @@ async function gatherRoutedModelsUncached(
|
|
|
467
475
|
...inherited,
|
|
468
476
|
catalogKind: CODEX_CUSTOM_MODEL_CATALOG_KIND,
|
|
469
477
|
...(typeof custom.contextWindow === "number" && custom.contextWindow > 0
|
|
470
|
-
? { contextWindow: custom.contextWindow }
|
|
478
|
+
? { contextWindow: custom.contextWindow, contextWindowInference: undefined }
|
|
471
479
|
: {}),
|
|
472
480
|
...(Array.isArray(custom.inputModalities)
|
|
473
481
|
? { inputModalities: [...custom.inputModalities] }
|
|
@@ -478,9 +486,6 @@ async function gatherRoutedModelsUncached(
|
|
|
478
486
|
...(custom.codexToolMode !== undefined ? { codexToolMode: custom.codexToolMode } : {}),
|
|
479
487
|
});
|
|
480
488
|
}
|
|
481
|
-
// Enriched (registry-hydrated) provider clones — shared by combo member synthesis and
|
|
482
|
-
// custom-model vision-sidecar inheritance so both see the same merged registry view.
|
|
483
|
-
const enrichedByName = new Map(activeProviders.map(provider => [provider.name, provider.provider]));
|
|
484
489
|
for (const id of listComboIds(config)) {
|
|
485
490
|
const combo = getCombo(config, id);
|
|
486
491
|
if (!combo) continue;
|
|
@@ -517,6 +522,7 @@ async function gatherRoutedModelsUncached(
|
|
|
517
522
|
nativeAliasFallback,
|
|
518
523
|
metadataModelIdCaseFoldByProvider.get(target.provider),
|
|
519
524
|
metadataConfigDirByProvider.get(target.provider),
|
|
525
|
+
visionSidecarEnabled,
|
|
520
526
|
))
|
|
521
527
|
.filter((member): member is CatalogModel => member !== undefined);
|
|
522
528
|
const derived = deriveComboCatalogModel(id, combo, members);
|
|
@@ -654,6 +660,7 @@ async function gatherRoutedModelsUncached(
|
|
|
654
660
|
...(Array.isArray(cm.reasoningEfforts) ? { reasoningEfforts: [...cm.reasoningEfforts] } : {}),
|
|
655
661
|
...(cm.defaultReasoningEffort ? { defaultReasoningEffort: cm.defaultReasoningEffort } : {}),
|
|
656
662
|
...(typeof supportsServiceTier === "boolean" ? { supportsServiceTier } : {}),
|
|
663
|
+
supportsUltraFastTier: supportsConfiguredUltraFast(fastPolicy),
|
|
657
664
|
...(supportsServiceTier === true && fastPolicy?.fastTierDescription !== undefined
|
|
658
665
|
? { fastTierDescription: fastPolicy.fastTierDescription }
|
|
659
666
|
: {}),
|
|
@@ -686,7 +693,8 @@ async function gatherRoutedModelsUncached(
|
|
|
686
693
|
: undefined;
|
|
687
694
|
const merged: CatalogModel = replaced ? {
|
|
688
695
|
...base,
|
|
689
|
-
...(base.contextWindow === undefined && replaced.contextWindow !== undefined
|
|
696
|
+
...(base.contextWindow === undefined && replaced.contextWindow !== undefined
|
|
697
|
+
? { contextWindow: replaced.contextWindow, ...(replaced.contextWindowInference ? { contextWindowInference: replaced.contextWindowInference, contextCap: replaced.contextCap, contextCapped: replaced.contextCapped } : {}) } : {}),
|
|
690
698
|
...(mergedMaxInput !== undefined ? { maxInputTokens: mergedMaxInput } : {}),
|
|
691
699
|
...(mergedMaxOutput !== undefined ? { maxOutputTokens: mergedMaxOutput } : {}),
|
|
692
700
|
...(base.autoCompactTokenLimit === undefined && replaced.autoCompactTokenLimit !== undefined
|
|
@@ -703,17 +711,29 @@ async function gatherRoutedModelsUncached(
|
|
|
703
711
|
...(base.codexToolMode === undefined && replaced.codexToolMode !== undefined ? { codexToolMode: replaced.codexToolMode } : {}),
|
|
704
712
|
...(base.capabilities === undefined && replaced.capabilities !== undefined ? { capabilities: replaced.capabilities } : {}),
|
|
705
713
|
} : base;
|
|
714
|
+
// A custom-only model may never appear in /models or the provider's configured roster.
|
|
715
|
+
// Fill only its absent context; a full hint overlay would overwrite custom capabilities.
|
|
716
|
+
const customContextHints = merged.contextWindow === undefined && effectiveProvider && canInferVendorContext(cm.provider, effectiveProvider)
|
|
717
|
+
? applyProviderConfigHints(cm.provider, effectiveProvider, { provider: cm.provider, id: cm.modelId },
|
|
718
|
+
providerContextCap(config, cm.provider), metadataModelIdCaseFoldByProvider.get(cm.provider),
|
|
719
|
+
undefined, metadataConfigDirByProvider.get(cm.provider), false)
|
|
720
|
+
: undefined;
|
|
721
|
+
const contextResolved: CatalogModel = customContextHints?.contextWindow !== undefined
|
|
722
|
+
? { ...merged, contextWindow: customContextHints.contextWindow,
|
|
723
|
+
...(customContextHints.contextWindowInference ? { contextWindowInference: customContextHints.contextWindowInference } : {}),
|
|
724
|
+
...(customContextHints.contextCap !== undefined ? { contextCap: customContextHints.contextCap, contextCapped: customContextHints.contextCapped } : {}) }
|
|
725
|
+
: merged;
|
|
706
726
|
// Catalog-advertised efforts are bounded whenever the model id is a pinned native
|
|
707
727
|
// slug. Desktop validates that id, so a gateway such as YYLJ/gpt-6-astra still cannot
|
|
708
728
|
// advertise none/minimal. Full native identity stays behind the alias predicate.
|
|
709
729
|
const nativeEffortSource = hasNativeOpenAiCapabilityMetadata(cm.modelId);
|
|
710
730
|
const reasoningBounded = nativeEffortSource
|
|
711
731
|
? boundCustomNativeReasoning(
|
|
712
|
-
|
|
732
|
+
contextResolved,
|
|
713
733
|
nativeReasoningEfforts(cm.modelId),
|
|
714
734
|
nativeAliasDefaultEffort ?? nativeDefaultReasoningEffort(cm.modelId),
|
|
715
735
|
)
|
|
716
|
-
:
|
|
736
|
+
: contextResolved;
|
|
717
737
|
// Vision-sidecar coverage only: when the enriched provider's shared predicate matches
|
|
718
738
|
// noVisionModels or text-without-image modelInputModalities, advertise image input so the
|
|
719
739
|
// Codex app lets images reach the sidecar (#349/#344). Deliberately NOT the full
|
|
@@ -744,13 +764,7 @@ async function gatherRoutedModelsUncached(
|
|
|
744
764
|
: mergedWithHardBounds;
|
|
745
765
|
const enrichedProvider = enrichedByName.get(cm.provider) ?? rawProvider;
|
|
746
766
|
// Reuse the request-time consumer predicate so custom rows cannot drift from catalog hints.
|
|
747
|
-
|
|
748
|
-
const current = mergedWithAutoCompact.inputModalities ?? ["text"];
|
|
749
|
-
if (!current.includes("image")) {
|
|
750
|
-
return { ...mergedWithAutoCompact, inputModalities: [...current, "image"] };
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
return mergedWithAutoCompact;
|
|
767
|
+
return withVisionSidecarInput(mergedWithAutoCompact, enrichedProvider, visionSidecarEnabled);
|
|
754
768
|
});
|
|
755
769
|
// Custom rows override discovered rows that encode to the same Codex-facing slug. A provider whose
|
|
756
770
|
// captured discovery declares an order (preferFirst) keeps each replacement in the discovered row's
|
|
@@ -930,6 +944,7 @@ export function augmentRoutedModelsWithMetadata(
|
|
|
930
944
|
caps?: Pick<OcxConfig, "providerContextCaps">,
|
|
931
945
|
metadataModelIdCaseFoldByProvider?: ReadonlyMap<string, boolean>,
|
|
932
946
|
metadataConfigDirByProvider?: ReadonlyMap<string, string>,
|
|
947
|
+
includeVisionSidecar = true,
|
|
933
948
|
): CatalogModel[] {
|
|
934
949
|
const out = [...models];
|
|
935
950
|
const indexByKey = new Map(out.map((model, index) => [`${model.provider}/${model.id}`, index]));
|
|
@@ -959,6 +974,7 @@ export function augmentRoutedModelsWithMetadata(
|
|
|
959
974
|
metadataModelIdCaseFoldByProvider?.get(provider),
|
|
960
975
|
undefined,
|
|
961
976
|
metadataConfigDirByProvider?.get(provider),
|
|
977
|
+
includeVisionSidecar,
|
|
962
978
|
)
|
|
963
979
|
: seeded;
|
|
964
980
|
continue;
|
|
@@ -983,6 +999,7 @@ export function augmentRoutedModelsWithMetadata(
|
|
|
983
999
|
metadataModelIdCaseFoldByProvider?.get(provider),
|
|
984
1000
|
undefined,
|
|
985
1001
|
metadataConfigDirByProvider?.get(provider),
|
|
1002
|
+
includeVisionSidecar,
|
|
986
1003
|
)
|
|
987
1004
|
: {}),
|
|
988
1005
|
});
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { listModelMetadata, resolveMetadataProvider, type ModelMetadata } from "../../generated/model-metadata";
|
|
2
|
+
import { PROVIDER_REGISTRY } from "../../providers/registry";
|
|
3
|
+
import type { OcxProviderConfig } from "../../types";
|
|
4
|
+
|
|
5
|
+
/** A bundled model-window estimate, not evidence of the serving gateway's capacity. */
|
|
6
|
+
export interface VendorContextInference {
|
|
7
|
+
source: "vendor" | "aggregator";
|
|
8
|
+
provider: string;
|
|
9
|
+
modelId: string;
|
|
10
|
+
contextWindow: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Capacity and price have different authorities: hosting vendors (Cerebras/Bedrock), Azure
|
|
14
|
+
// and the Codex subscription table must not replace the original vendor's API window.
|
|
15
|
+
const VENDORS = ["anthropic", "openai", "google", "moonshot", "minimax", "deepseek", "xai", "zai", "mistral", "xiaomi"];
|
|
16
|
+
const AGGREGATORS = ["openrouter", "opencode-go"];
|
|
17
|
+
// Snapshot names once, never consult the mutable registry after gather flight admission.
|
|
18
|
+
const BUILTIN_NAMES = new Set(PROVIDER_REGISTRY.map(entry => entry.id.toLowerCase()));
|
|
19
|
+
/**
|
|
20
|
+
* Opt-in only (#1073): an id-only custom row keeps the conservative fallback unless the
|
|
21
|
+
* operator sets `inferContextWindow: true`. Built-in names stay excluded even when set.
|
|
22
|
+
*/
|
|
23
|
+
export function canInferVendorContext(provider: string, config: Pick<OcxProviderConfig, "inferContextWindow"> | undefined): boolean {
|
|
24
|
+
return config?.inferContextWindow === true
|
|
25
|
+
&& !BUILTIN_NAMES.has(provider.toLowerCase()) && !resolveMetadataProvider(provider);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const normalize = (id: string): string => id.toLowerCase().replaceAll(".", "-");
|
|
29
|
+
type Candidate = VendorContextInference | null;
|
|
30
|
+
|
|
31
|
+
/** Build a pure lookup; conflicting windows within one authority tier fail closed. */
|
|
32
|
+
export function createVendorContextLookup(
|
|
33
|
+
vendors: readonly ModelMetadata[],
|
|
34
|
+
aggregators: readonly ModelMetadata[],
|
|
35
|
+
): (id: string) => VendorContextInference | undefined {
|
|
36
|
+
const build = (rows: readonly ModelMetadata[], source: VendorContextInference["source"]) => {
|
|
37
|
+
const exact = new Map<string, Candidate>();
|
|
38
|
+
const normalized = new Map<string, Candidate>();
|
|
39
|
+
const add = (map: Map<string, Candidate>, id: string, value: VendorContextInference) => {
|
|
40
|
+
if (!map.has(id)) map.set(id, value);
|
|
41
|
+
else if (map.get(id)?.contextWindow !== value.contextWindow) map.set(id, null);
|
|
42
|
+
};
|
|
43
|
+
for (const row of rows) {
|
|
44
|
+
const window = row.contextWindow;
|
|
45
|
+
if (!Number.isSafeInteger(window) || window! <= 0 || row.id.startsWith("~")) continue;
|
|
46
|
+
const value: VendorContextInference = { source, provider: row.provider, modelId: row.id, contextWindow: window! };
|
|
47
|
+
const ids = source === "aggregator" ? [row.id, row.id.slice(row.id.lastIndexOf("/") + 1)] : [row.id];
|
|
48
|
+
for (const id of ids) {
|
|
49
|
+
if (!id) continue;
|
|
50
|
+
add(exact, id, value);
|
|
51
|
+
add(normalized, normalize(id), value);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return { exact, normalized };
|
|
55
|
+
};
|
|
56
|
+
const tiers = [build(vendors, "vendor"), build(aggregators, "aggregator")];
|
|
57
|
+
return rawId => {
|
|
58
|
+
const id = rawId.trim();
|
|
59
|
+
if (!id || id.startsWith("~")) return undefined;
|
|
60
|
+
for (const tier of tiers) {
|
|
61
|
+
// An exact spelling wins over its normalized alias. A conflicting key does not
|
|
62
|
+
// fall through to a lower-authority source and accidentally regain a larger window.
|
|
63
|
+
const map = tier.exact.has(id) ? tier.exact : tier.normalized;
|
|
64
|
+
const key = map === tier.exact ? id : normalize(id);
|
|
65
|
+
if (map.has(key)) {
|
|
66
|
+
const value = map.get(key);
|
|
67
|
+
return value ? { ...value } : undefined;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let lookup: ReturnType<typeof createVendorContextLookup> | undefined;
|
|
75
|
+
export function vendorContextInference(modelId: string): VendorContextInference | undefined {
|
|
76
|
+
lookup ??= createVendorContextLookup(VENDORS.flatMap(listModelMetadata), AGGREGATORS.flatMap(listModelMetadata));
|
|
77
|
+
return lookup(modelId);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function vendorContextWindow(modelId: string): number | undefined {
|
|
81
|
+
return vendorContextInference(modelId)?.contextWindow;
|
|
82
|
+
}
|
|
@@ -18,6 +18,9 @@ import { isSpawnableCodexCandidate } from "./exec-invocation";
|
|
|
18
18
|
import {
|
|
19
19
|
codexRuntimeStatePath,
|
|
20
20
|
parsePersistedCodexRuntime,
|
|
21
|
+
resolveCodexRuntime,
|
|
22
|
+
type ResolveCodexRuntimeDeps,
|
|
23
|
+
type ResolveCodexRuntimeResult,
|
|
21
24
|
} from "./runtime";
|
|
22
25
|
import {
|
|
23
26
|
inspectCodexShimBackingForCommand,
|
|
@@ -46,12 +49,13 @@ export type CodexCliInstallReason =
|
|
|
46
49
|
| "shim_state_unknown"
|
|
47
50
|
| "shim_update_deferred"
|
|
48
51
|
| "app_bundle"
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
| "
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
| "version_manager_owned"
|
|
53
|
+
| "npm_global_unverified"
|
|
54
|
+
| "managed_npm_global"
|
|
55
|
+
| "selection_unattested"
|
|
56
|
+
| "version_mismatch"
|
|
57
|
+
| "unverified_standalone"
|
|
58
|
+
| "inspection_failed";
|
|
55
59
|
|
|
56
60
|
export type CodexCliCandidateSource = "environment" | "persisted";
|
|
57
61
|
export type CodexCliInstallEvidence =
|
|
@@ -82,6 +86,12 @@ export interface CodexCliInstallReport {
|
|
|
82
86
|
readonly managed: boolean;
|
|
83
87
|
readonly reason: CodexCliInstallReason;
|
|
84
88
|
readonly location: string | null;
|
|
89
|
+
/**
|
|
90
|
+
* sha256 digest of the canonical package manifest root when one was observed,
|
|
91
|
+
* otherwise null. Digest-only so the public report still carries no path; plan
|
|
92
|
+
* identity binds this value so two different install roots cannot share a plan.
|
|
93
|
+
*/
|
|
94
|
+
readonly installDigest: string | null;
|
|
85
95
|
readonly packageVersion: string | null;
|
|
86
96
|
readonly shim: Readonly<{
|
|
87
97
|
status: "not-tracked" | "matched" | "unknown";
|
|
@@ -105,6 +115,19 @@ export interface CodexCliInstallProvenanceDeps {
|
|
|
105
115
|
platform: NodeJS.Platform,
|
|
106
116
|
configDir: string,
|
|
107
117
|
) => CodexShimBackingForCommand;
|
|
118
|
+
/**
|
|
119
|
+
* Caller assertion that `env.CODEX_CLI_PATH` is the runtime the launcher actually
|
|
120
|
+
* selected, not merely a configured name. Only a proof-bound caller may set this;
|
|
121
|
+
* a persisted selection and an arbitrary environment stay unattested.
|
|
122
|
+
*/
|
|
123
|
+
readonly selectionAttested?: boolean;
|
|
124
|
+
/**
|
|
125
|
+
* The command the runtime resolver actually selected under the same evidence.
|
|
126
|
+
* Attestation additionally requires its canonical path to match the inspected
|
|
127
|
+
* candidate, so a snapshot candidate the resolver would have rejected cannot
|
|
128
|
+
* turn a different installation managed.
|
|
129
|
+
*/
|
|
130
|
+
readonly selectedCommand?: string | null;
|
|
108
131
|
}
|
|
109
132
|
|
|
110
133
|
interface PackageManifestEvidence {
|
|
@@ -159,6 +182,7 @@ function unknownReport(
|
|
|
159
182
|
managed: false,
|
|
160
183
|
reason,
|
|
161
184
|
location: extra.location ?? null,
|
|
185
|
+
installDigest: null,
|
|
162
186
|
packageVersion: null,
|
|
163
187
|
shim: Object.freeze({ status: "not-tracked", backingKind: null }),
|
|
164
188
|
evidence: Object.freeze([]),
|
|
@@ -287,6 +311,38 @@ function resolveCandidateCommandPath(
|
|
|
287
311
|
return null;
|
|
288
312
|
}
|
|
289
313
|
|
|
314
|
+
/** Resolve selection under inspection's bounded, local-only filesystem policy. */
|
|
315
|
+
export function observeCodexCliSelectedCommand(
|
|
316
|
+
deps: CodexCliInstallProvenanceDeps,
|
|
317
|
+
resolve: (deps: ResolveCodexRuntimeDeps) => ResolveCodexRuntimeResult = resolveCodexRuntime,
|
|
318
|
+
): string | null {
|
|
319
|
+
const platform = deps.platform ?? process.platform;
|
|
320
|
+
// Even the general resolver's existence checks can touch a remote Windows
|
|
321
|
+
// candidate. Deferred inspection must return before invoking it at all.
|
|
322
|
+
if (platform === "win32") return null;
|
|
323
|
+
const configDir = deps.configDir ?? getConfigDir();
|
|
324
|
+
if (!isSafeLocalInspectionPath(configDir, deps)) return null;
|
|
325
|
+
try {
|
|
326
|
+
return resolve({
|
|
327
|
+
platform,
|
|
328
|
+
env: deps.env,
|
|
329
|
+
configDir,
|
|
330
|
+
discoverAlternatives: false,
|
|
331
|
+
probeVersion: false,
|
|
332
|
+
// Runtime and shim state must use the same no-follow, nonblocking,
|
|
333
|
+
// size-bounded descriptor reads as provenance, including before selection.
|
|
334
|
+
readFileSync: path => {
|
|
335
|
+
const bytes = readBoundedFile(path, MAX_RUNTIME_STATE_BYTES, deps);
|
|
336
|
+
if (!bytes) throw new Error("inspection_state_unavailable");
|
|
337
|
+
return bytes.toString("utf8");
|
|
338
|
+
},
|
|
339
|
+
existsSync: path => resolveCandidateCommandPath(path, deps) !== null,
|
|
340
|
+
}).runtime.command ?? null;
|
|
341
|
+
} catch {
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
290
346
|
function canonicalize(path: string, deps: CodexCliInstallProvenanceDeps): string | null {
|
|
291
347
|
if (!isSafeLocalInspectionPath(path, deps)) return null;
|
|
292
348
|
try {
|
|
@@ -630,15 +686,16 @@ export async function inspectCodexCliInstall(
|
|
|
630
686
|
managed: false,
|
|
631
687
|
reason: appBundle ? "app_bundle" : "version_manager_owned",
|
|
632
688
|
location: publicExecutableLocation(lexicalCandidatePath, platform),
|
|
689
|
+
installDigest: null,
|
|
633
690
|
packageVersion: null,
|
|
634
691
|
shim: Object.freeze({ status: "unknown", backingKind: null }),
|
|
635
692
|
evidence: Object.freeze([appBundle ? "app_bundle_path" : "version_manager_path"]),
|
|
636
693
|
});
|
|
637
694
|
}
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
695
|
+
return unknownWindowsReport("windows_inspection_deferred", candidate, {
|
|
696
|
+
location: publicExecutableLocation(lexicalCandidatePath, platform),
|
|
697
|
+
});
|
|
698
|
+
}
|
|
642
699
|
const configDir = deps.configDir ?? getConfigDir();
|
|
643
700
|
if (!isSafeLocalInspectionPath(configDir, deps)) {
|
|
644
701
|
return unknownReport("shim_state_unknown", candidate);
|
|
@@ -651,6 +708,23 @@ export async function inspectCodexCliInstall(
|
|
|
651
708
|
if (!canonicalCandidatePath) {
|
|
652
709
|
return unknownReport("candidate_path_unsafe", candidate);
|
|
653
710
|
}
|
|
711
|
+
// Only a proof-bound caller may attest that the environment candidate is the
|
|
712
|
+
// runtime it actually selected, and only when the runtime resolver picked the
|
|
713
|
+
// same canonical path under the same evidence. A persisted selection records
|
|
714
|
+
// intent, not the resolved binary, and an arbitrary environment is ambient —
|
|
715
|
+
// neither can become managed here; a resolver that would choose a different
|
|
716
|
+
// executable cannot attest the snapshot's installation either.
|
|
717
|
+
const resolverPicked = deps.selectedCommand
|
|
718
|
+
? canonicalize(
|
|
719
|
+
resolveCandidateCommandPath(deps.selectedCommand, deps) ?? deps.selectedCommand,
|
|
720
|
+
deps,
|
|
721
|
+
)
|
|
722
|
+
: null;
|
|
723
|
+
const selectionAttested =
|
|
724
|
+
deps.selectionAttested === true
|
|
725
|
+
&& candidate.evidence === "environment"
|
|
726
|
+
&& resolverPicked !== null
|
|
727
|
+
&& samePath(resolverPicked, canonicalCandidatePath, platform);
|
|
654
728
|
const inspectShim = deps.inspectShim ?? inspectCodexShimBackingForCommand;
|
|
655
729
|
const shim = inspectShim(candidatePath, platform, configDir);
|
|
656
730
|
if (shim.status === "unknown") {
|
|
@@ -658,6 +732,7 @@ export async function inspectCodexCliInstall(
|
|
|
658
732
|
...unknownReport("shim_state_unknown", candidate, {
|
|
659
733
|
location: publicExecutableLocation(canonicalCandidatePath, platform),
|
|
660
734
|
}),
|
|
735
|
+
selectionAttested,
|
|
661
736
|
shim: shimReport(shim),
|
|
662
737
|
});
|
|
663
738
|
}
|
|
@@ -666,6 +741,7 @@ export async function inspectCodexCliInstall(
|
|
|
666
741
|
...unknownReport("shim_update_deferred", candidate, {
|
|
667
742
|
location: publicExecutableLocation(canonicalCandidatePath, platform),
|
|
668
743
|
}),
|
|
744
|
+
selectionAttested,
|
|
669
745
|
provenance: "standalone-unverified",
|
|
670
746
|
shim: shimReport(shim),
|
|
671
747
|
evidence: Object.freeze(["canonical_path", "shim_backing"] as const),
|
|
@@ -685,7 +761,7 @@ export async function inspectCodexCliInstall(
|
|
|
685
761
|
candidateAvailable: true,
|
|
686
762
|
candidateVersion: candidate.version,
|
|
687
763
|
candidateSource: candidate.evidence,
|
|
688
|
-
selectionAttested
|
|
764
|
+
selectionAttested,
|
|
689
765
|
versionEvidence: Object.freeze({
|
|
690
766
|
kind: candidate.version ? "advisory-runtime" as const : "unavailable" as const,
|
|
691
767
|
}),
|
|
@@ -693,6 +769,7 @@ export async function inspectCodexCliInstall(
|
|
|
693
769
|
managed: false,
|
|
694
770
|
reason: "app_bundle",
|
|
695
771
|
location,
|
|
772
|
+
installDigest: null,
|
|
696
773
|
packageVersion: null,
|
|
697
774
|
shim: shimReport(shim),
|
|
698
775
|
evidence: Object.freeze(["canonical_path", "app_bundle_path"]),
|
|
@@ -706,7 +783,7 @@ export async function inspectCodexCliInstall(
|
|
|
706
783
|
candidateAvailable: true,
|
|
707
784
|
candidateVersion: candidate.version,
|
|
708
785
|
candidateSource: candidate.evidence,
|
|
709
|
-
selectionAttested
|
|
786
|
+
selectionAttested,
|
|
710
787
|
versionEvidence: Object.freeze({
|
|
711
788
|
kind: candidate.version ? "advisory-runtime" as const : "unavailable" as const,
|
|
712
789
|
}),
|
|
@@ -714,6 +791,7 @@ export async function inspectCodexCliInstall(
|
|
|
714
791
|
managed: false,
|
|
715
792
|
reason: "version_manager_owned",
|
|
716
793
|
location,
|
|
794
|
+
installDigest: null,
|
|
717
795
|
packageVersion: null,
|
|
718
796
|
shim: shimReport(shim),
|
|
719
797
|
evidence: Object.freeze(["canonical_path", "version_manager_path"]),
|
|
@@ -722,6 +800,7 @@ export async function inspectCodexCliInstall(
|
|
|
722
800
|
if (/codex[.]opencodex-real(?:[.](?:cmd|bat|exe))?$/i.test(pathTools(platform).basename(candidatePath))) {
|
|
723
801
|
return freezeReport({
|
|
724
802
|
...unknownReport("shim_state_unknown", candidate, { location }),
|
|
803
|
+
selectionAttested,
|
|
725
804
|
shim: shimReport(shim),
|
|
726
805
|
});
|
|
727
806
|
}
|
|
@@ -745,22 +824,30 @@ export async function inspectCodexCliInstall(
|
|
|
745
824
|
const versionMatches = candidate.version === null || candidate.version === manifest.version;
|
|
746
825
|
const reason: CodexCliInstallReason = !global || !linked
|
|
747
826
|
? "npm_global_unverified"
|
|
748
|
-
: !versionMatches ? "version_mismatch"
|
|
827
|
+
: !versionMatches ? "version_mismatch"
|
|
828
|
+
: selectionAttested ? "managed_npm_global" : "selection_unattested";
|
|
749
829
|
return freezeReport({
|
|
750
830
|
schemaVersion: 1,
|
|
751
831
|
candidateAvailable: true,
|
|
752
832
|
candidateVersion: candidate.version,
|
|
753
833
|
candidateSource: candidate.evidence,
|
|
754
|
-
selectionAttested
|
|
834
|
+
selectionAttested,
|
|
755
835
|
versionEvidence: Object.freeze({
|
|
756
|
-
|
|
836
|
+
// The manifest is the on-disk record of what is installed. An absent advisory
|
|
837
|
+
// version (the launcher snapshot carries no version) cannot contradict it,
|
|
838
|
+
// while a reported one that disagrees already classified as version_mismatch.
|
|
839
|
+
kind: manifestOwned && versionMatches
|
|
757
840
|
? "package-manifest" as const
|
|
758
841
|
: candidate.version !== null ? "advisory-runtime" as const : "unavailable" as const,
|
|
759
842
|
}),
|
|
760
843
|
provenance: manifestOwned ? "npm-global" : "standalone-unverified",
|
|
761
|
-
managed:
|
|
844
|
+
managed: manifestOwned && versionMatches && selectionAttested,
|
|
762
845
|
reason,
|
|
763
846
|
location,
|
|
847
|
+
// Plan identity binds this digest, not the redacted display location: two
|
|
848
|
+
// package roots that resolve to the same "<path>/codex" string must still
|
|
849
|
+
// produce different plans.
|
|
850
|
+
installDigest: sha256("codex-cli-install-root-v1", normalizePath(manifest.root, platform)),
|
|
764
851
|
packageVersion: manifest.version,
|
|
765
852
|
shim: shimReport(shim),
|
|
766
853
|
evidence: Object.freeze<CodexCliInstallEvidence[]>([
|
|
@@ -786,7 +873,7 @@ export async function inspectCodexCliInstall(
|
|
|
786
873
|
candidateAvailable: true,
|
|
787
874
|
candidateVersion: candidate.version,
|
|
788
875
|
candidateSource: candidate.evidence,
|
|
789
|
-
selectionAttested
|
|
876
|
+
selectionAttested,
|
|
790
877
|
versionEvidence: Object.freeze({
|
|
791
878
|
kind: candidate.version ? "advisory-runtime" as const : "unavailable" as const,
|
|
792
879
|
}),
|
|
@@ -794,6 +881,7 @@ export async function inspectCodexCliInstall(
|
|
|
794
881
|
managed: false,
|
|
795
882
|
reason: "unverified_standalone",
|
|
796
883
|
location,
|
|
884
|
+
installDigest: null,
|
|
797
885
|
packageVersion: null,
|
|
798
886
|
shim: shimReport(shim),
|
|
799
887
|
evidence: Object.freeze(["canonical_path"]),
|