@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
package/src/claude/outbound.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { anthropicProgressEnvelope, isAnthropicProgressMirror } from "../responses/anthropic-progress";
|
|
1
2
|
/**
|
|
2
3
|
* Claude Code outbound: internal /v1/responses output -> Anthropic Messages API shapes.
|
|
3
4
|
*
|
|
@@ -11,7 +12,7 @@
|
|
|
11
12
|
* - errors: {type:"error", error:{type,message}}; may arrive mid-stream after HTTP 200.
|
|
12
13
|
*/
|
|
13
14
|
import { createHash } from "node:crypto";
|
|
14
|
-
import { httpStatusFromTerminalError } from "../lib/errors";
|
|
15
|
+
import { httpStatusFromTerminalError, UNDECLARED_TOOL_CALL_ERROR_CODE } from "../lib/errors";
|
|
15
16
|
import { isTransientUpstreamStatus } from "../lib/upstream-retry";
|
|
16
17
|
import {
|
|
17
18
|
isTranslatorBudgetExceededError,
|
|
@@ -81,12 +82,16 @@ export function anthropicErrorType(status: number): string {
|
|
|
81
82
|
* (devlog/_plan/261009_claude_1m_default/010).
|
|
82
83
|
*/
|
|
83
84
|
const CLAUDE_PROMPT_TOO_LONG_RE = /prompt is too long|input is too long for requested model/i;
|
|
84
|
-
const
|
|
85
|
+
const MAX_OVERFLOW_MESSAGE_CHARS = 64 * 1024;
|
|
86
|
+
const STATED_CONTEXT_LIMIT_RE = /maximum context length is (\d+) tokens/i;
|
|
87
|
+
const STATED_REQUEST_COUNT_RE = /(?:resulted in|you requested) (\d+) tokens/i;
|
|
85
88
|
|
|
86
89
|
export function claudePromptTooLongMessage(message: string): string {
|
|
90
|
+
message = message.slice(0, MAX_OVERFLOW_MESSAGE_CHARS);
|
|
87
91
|
if (CLAUDE_PROMPT_TOO_LONG_RE.test(message)) return message;
|
|
88
|
-
const
|
|
89
|
-
|
|
92
|
+
const limit = STATED_CONTEXT_LIMIT_RE.exec(message);
|
|
93
|
+
const requested = limit && STATED_REQUEST_COUNT_RE.exec(message.slice(limit.index + limit[0].length));
|
|
94
|
+
if (limit && requested) return `prompt is too long: ${requested[1]} tokens > ${limit[1]} maximum`;
|
|
90
95
|
return `prompt is too long: ${message}`;
|
|
91
96
|
}
|
|
92
97
|
|
|
@@ -218,10 +223,20 @@ export function sanitizeWebSearchInput(input: unknown): Rec {
|
|
|
218
223
|
/**
|
|
219
224
|
* Map a Responses `web_search_call` item to its Anthropic pair: the server_tool_use
|
|
220
225
|
* input (query/queries) and the web_search_tool_result content (hits, or the error
|
|
221
|
-
* object when the search failed).
|
|
226
|
+
* object when the search failed). An item carrying `fetch_result` is Anthropic's
|
|
227
|
+
* server-side web_fetch and maps to web_fetch + its web_fetch_tool_result, verbatim.
|
|
228
|
+
* Shared by the SSE and JSON translation paths.
|
|
222
229
|
*/
|
|
223
|
-
export function webSearchPairFromItem(item: Rec): {
|
|
230
|
+
export function webSearchPairFromItem(item: Rec): {
|
|
231
|
+
id: string; name: "web_search" | "web_fetch"; resultType: string; input: Rec; resultContent: unknown; completed: boolean;
|
|
232
|
+
} {
|
|
224
233
|
const action = isRec(item.action) ? item.action : {};
|
|
234
|
+
const id = typeof item.id === "string" && item.id.length > 0 ? item.id : `srvtoolu_${uuid()}`;
|
|
235
|
+
const completed = item.status !== "failed";
|
|
236
|
+
if (item.fetch_result !== undefined) {
|
|
237
|
+
const input = { url: typeof action.url === "string" ? action.url : "" };
|
|
238
|
+
return { id, name: "web_fetch", resultType: "web_fetch_tool_result", input, resultContent: item.fetch_result, completed };
|
|
239
|
+
}
|
|
225
240
|
const queries = Array.isArray(action.queries)
|
|
226
241
|
? action.queries.filter((q): q is string => typeof q === "string" && q.length > 0)
|
|
227
242
|
: [];
|
|
@@ -229,7 +244,6 @@ export function webSearchPairFromItem(item: Rec): { id: string; input: Rec; resu
|
|
|
229
244
|
const input = sanitizeWebSearchInput(
|
|
230
245
|
queries.length > 1 ? { queries } : { query: queries[0] ?? query },
|
|
231
246
|
);
|
|
232
|
-
const completed = item.status !== "failed";
|
|
233
247
|
let resultContent: unknown;
|
|
234
248
|
if (completed) {
|
|
235
249
|
const hits: Rec[] = [];
|
|
@@ -244,8 +258,7 @@ export function webSearchPairFromItem(item: Rec): { id: string; input: Rec; resu
|
|
|
244
258
|
} else {
|
|
245
259
|
resultContent = { type: "web_search_tool_result_error", error_code: "unavailable" };
|
|
246
260
|
}
|
|
247
|
-
|
|
248
|
-
return { id, input, resultContent, completed };
|
|
261
|
+
return { id, name: "web_search", resultType: "web_search_tool_result", input, resultContent, completed };
|
|
249
262
|
}
|
|
250
263
|
|
|
251
264
|
/**
|
|
@@ -549,7 +562,13 @@ export function responsesSseToAnthropicSse(
|
|
|
549
562
|
terminalDelivered = true;
|
|
550
563
|
};
|
|
551
564
|
|
|
565
|
+
let progressMirrorId: string | undefined;
|
|
552
566
|
const handleFrame = (eventName: string, data: Rec) => {
|
|
567
|
+
const frameItem = isRec(data.item) ? data.item : null;
|
|
568
|
+
if (progressMirrorId && (data.item_id === progressMirrorId || frameItem?.id === progressMirrorId)) {
|
|
569
|
+
if (eventName === "response.output_item.done") progressMirrorId = undefined;
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
553
572
|
switch (eventName) {
|
|
554
573
|
case "response.created":
|
|
555
574
|
case "response.in_progress": {
|
|
@@ -701,7 +720,7 @@ export function responsesSseToAnthropicSse(
|
|
|
701
720
|
const toolIndex = blockIndex++;
|
|
702
721
|
emit("content_block_start", {
|
|
703
722
|
type: "content_block_start", index: toolIndex,
|
|
704
|
-
content_block: { type: "server_tool_use", id: pair.id, name:
|
|
723
|
+
content_block: { type: "server_tool_use", id: pair.id, name: pair.name },
|
|
705
724
|
});
|
|
706
725
|
emit("content_block_delta", {
|
|
707
726
|
type: "content_block_delta", index: toolIndex,
|
|
@@ -711,10 +730,10 @@ export function responsesSseToAnthropicSse(
|
|
|
711
730
|
const resultIndex = blockIndex++;
|
|
712
731
|
emit("content_block_start", {
|
|
713
732
|
type: "content_block_start", index: resultIndex,
|
|
714
|
-
content_block: { type:
|
|
733
|
+
content_block: { type: pair.resultType, tool_use_id: pair.id, content: pair.resultContent },
|
|
715
734
|
});
|
|
716
735
|
emit("content_block_stop", { type: "content_block_stop", index: resultIndex });
|
|
717
|
-
if (pair.completed) webSearchRequests++;
|
|
736
|
+
if (pair.completed && pair.name === "web_search") webSearchRequests++;
|
|
718
737
|
break;
|
|
719
738
|
}
|
|
720
739
|
// Close the matching open block (message/reasoning items close implicitly on
|
|
@@ -768,6 +787,15 @@ export function responsesSseToAnthropicSse(
|
|
|
768
787
|
ensureBlock("thinking");
|
|
769
788
|
}
|
|
770
789
|
if (open?.kind === "thinking") {
|
|
790
|
+
if (env?.upd && typeof env.txt === "string") {
|
|
791
|
+
// This plaintext was deliberately surfaced as commentary, unlike hidden reasoning.
|
|
792
|
+
progressMirrorId = env.upd;
|
|
793
|
+
const bytes = Buffer.byteLength(env.txt);
|
|
794
|
+
translatorBudget.chargeRetained(bytes, { kind: "reasoning" });
|
|
795
|
+
translatorBudget.releaseRetained(open.thinkingBufBytes ?? 0, { kind: "reasoning" });
|
|
796
|
+
open.thinkingBuf = env.txt;
|
|
797
|
+
open.thinkingBufBytes = bytes;
|
|
798
|
+
}
|
|
771
799
|
if (env?.sig) open.reasoningSig = env.sig;
|
|
772
800
|
if (native) open.reasoningNative = typeof item.id === "string" && item.id.length > 0 ? { enc: native, id: item.id } : { enc: native };
|
|
773
801
|
closeOpenBlock();
|
|
@@ -804,11 +832,14 @@ export function responsesSseToAnthropicSse(
|
|
|
804
832
|
// Unclassified status-absent response.failed (relaySseWithFailedTail synthetic
|
|
805
833
|
// tail) still lands on a transient 5xx here — the mid-stream reset shape maps to
|
|
806
834
|
// overloaded_error by design.
|
|
835
|
+
// The undeclared-tool refusal is deterministic and proxy-owned, not an upstream
|
|
836
|
+
// condition: keep its api_error type and code instead of a retryable overload.
|
|
837
|
+
const deterministic = code === UNDECLARED_TOOL_CALL_ERROR_CODE;
|
|
807
838
|
fail(
|
|
808
839
|
status,
|
|
809
840
|
message,
|
|
810
|
-
|
|
811
|
-
code === "context_length_exceeded" ? code : undefined,
|
|
841
|
+
!deterministic,
|
|
842
|
+
deterministic || code === "context_length_exceeded" ? code : undefined,
|
|
812
843
|
);
|
|
813
844
|
break;
|
|
814
845
|
}
|
|
@@ -969,7 +1000,8 @@ export function responsesJsonToAnthropicMessage(json: unknown, model: string, tr
|
|
|
969
1000
|
let sawToolUse = false;
|
|
970
1001
|
let webSearchRequests = 0;
|
|
971
1002
|
|
|
972
|
-
for (const raw of output) {
|
|
1003
|
+
for (const [index, raw] of output.entries()) {
|
|
1004
|
+
if (index > 0 && isAnthropicProgressMirror(raw, anthropicProgressEnvelope(output[index - 1], translatorBudget))) continue;
|
|
973
1005
|
if (!isRec(raw)) continue;
|
|
974
1006
|
switch (raw.type) {
|
|
975
1007
|
case "message": {
|
|
@@ -1003,7 +1035,7 @@ export function responsesJsonToAnthropicMessage(json: unknown, model: string, tr
|
|
|
1003
1035
|
const native = nativeEncryptedReasoning(encrypted);
|
|
1004
1036
|
const tag = native && nativeReasoningTagFor?.(native);
|
|
1005
1037
|
if (parts.length > 0 || env?.sig || tag) {
|
|
1006
|
-
const text = parts.join("\n\n");
|
|
1038
|
+
const text = env?.upd ? env.txt! : parts.join("\n\n");
|
|
1007
1039
|
const nat = tag ? { enc: native, model, tag, ...(typeof raw.id === "string" && raw.id.length > 0 ? { id: raw.id } : {}) } : undefined;
|
|
1008
1040
|
content.push({ type: "thinking", thinking: text, signature: env?.sig ?? encodeReasoningEnvelope({ txt: text, ...(nat ? { nat } : {}) }, translatorBudget) });
|
|
1009
1041
|
}
|
|
@@ -1027,9 +1059,9 @@ export function responsesJsonToAnthropicMessage(json: unknown, model: string, tr
|
|
|
1027
1059
|
case "web_search_call": {
|
|
1028
1060
|
// Server-side search: emit the Anthropic pair. Does NOT set sawToolUse.
|
|
1029
1061
|
const pair = webSearchPairFromItem(raw);
|
|
1030
|
-
content.push({ type: "server_tool_use", id: pair.id, name:
|
|
1031
|
-
content.push({ type:
|
|
1032
|
-
if (pair.completed) webSearchRequests++;
|
|
1062
|
+
content.push({ type: "server_tool_use", id: pair.id, name: pair.name, input: pair.input });
|
|
1063
|
+
content.push({ type: pair.resultType, tool_use_id: pair.id, content: pair.resultContent });
|
|
1064
|
+
if (pair.completed && pair.name === "web_search") webSearchRequests++;
|
|
1033
1065
|
break;
|
|
1034
1066
|
}
|
|
1035
1067
|
default:
|
package/src/cli/account-api.ts
CHANGED
|
@@ -8,6 +8,7 @@ export const threshold = z.number().int().min(0).max(100);
|
|
|
8
8
|
const nullableThreshold = threshold.nullable();
|
|
9
9
|
const row = z.object({
|
|
10
10
|
id: accountId, alias: text.optional(), autoSwitchThresholdOverride: nullableThreshold.optional(),
|
|
11
|
+
useRemainingQuota: z.boolean().optional(),
|
|
11
12
|
quota: z.object({ shortWindowSeconds: z.number().finite().optional(), shortResetAt: z.number().finite().optional(),
|
|
12
13
|
weeklyResetAt: z.number().finite().optional() }).nullable().optional(),
|
|
13
14
|
quotaAutoRefresh: z.object({ fiveHourAvailable: z.boolean(), weeklyAvailable: z.boolean(),
|
|
@@ -39,6 +40,11 @@ export const poolSchema = z.object({
|
|
|
39
40
|
export const thresholdReceipt = z.object({ ok: z.literal(true), id: accountId,
|
|
40
41
|
autoSwitchThresholdOverride: nullableThreshold, autoSwitchThreshold: threshold });
|
|
41
42
|
export const creditReceipt = z.object({ ok: z.literal(true), id: accountId, creditsAfterLimit: z.boolean() });
|
|
43
|
+
export const remainingQuotaReceipt = z.object({ ok: z.literal(true), id: accountId,
|
|
44
|
+
useRemainingQuota: z.boolean(), autoSwitchThreshold: threshold,
|
|
45
|
+
mainAccountHardLock: z.object({ enabled: z.boolean(), state: z.enum(["off", "unknown", "ready", "blocked"]),
|
|
46
|
+
thresholds: z.object({ short: threshold, long: threshold }) }).optional(),
|
|
47
|
+
});
|
|
42
48
|
export const creditAllReceipt = z.object({ ok: z.literal(true), all: z.boolean(),
|
|
43
49
|
ids: z.array(accountId).refine(ids => new Set(ids).size === ids.length) });
|
|
44
50
|
const window = z.enum(["five_hour", "seven_day", "seven_day_overage_included"]);
|
|
@@ -5,14 +5,15 @@ import { resolveCodexAccountTargetFromRows } from "./account-target";
|
|
|
5
5
|
import { runCatalogAction } from "./catalog-command-result";
|
|
6
6
|
import { serializeManagementJson } from "./json-input";
|
|
7
7
|
import { creditAllReceipt, creditReceipt, grantsSchema, parseDto, poolSchema, record,
|
|
8
|
-
rosterSchema, threshold, thresholdReceipt } from "./account-policy-dto";
|
|
8
|
+
rosterSchema, threshold, thresholdReceipt, remainingQuotaReceipt } from "./account-policy-dto";
|
|
9
9
|
import { CliUsageError, RuntimeApiError, printData, runtimeBaseUrl, runtimeRequest, summaryLines,
|
|
10
10
|
takeFlag, takeOptionWithSyntax, type RuntimeApiDeps } from "./runtime-api";
|
|
11
11
|
|
|
12
|
-
type Subcommand = "pool" | "auto-switch" | "credits" | "quota-activation" | "anthropic-reset-grants";
|
|
12
|
+
type Subcommand = "pool" | "auto-switch" | "credits" | "quota-activation" | "anthropic-reset-grants" | "use-remaining";
|
|
13
13
|
const USAGE = "Usage: ocx account pool <provider> [--enabled on|off] [--threshold 0-100] [--strategy NAME] [--sticky 1-100] [--quota-window NAME] [--json]\n"
|
|
14
14
|
+ " ocx account auto-switch openai <status|on|off|inherit|threshold N> --account ID [--json]\n"
|
|
15
15
|
+ " ocx account credits openai <ID on|off|--all on|off> [--json]\n"
|
|
16
|
+
+ " ocx account use-remaining openai ID <on|off|status> [--json]\n"
|
|
16
17
|
+ " ocx account quota-activation openai ID --window <fiveHour|weekly> <on|off> [--json]\n"
|
|
17
18
|
+ " ocx account anthropic-reset-grants [ID] [--provider anthropic|anthropic2] [--json]";
|
|
18
19
|
const READ_ERRORS = { no_account: "No matching Anthropic OAuth account.", auth_failed: "Sign in to this Anthropic account again.",
|
|
@@ -53,6 +54,32 @@ function output(data: Record<string, unknown>, json: boolean, note?: string): nu
|
|
|
53
54
|
}
|
|
54
55
|
function requireEqual(actual: unknown, expected: unknown): void { if (actual !== expected) throw new Error("Unverified account policy result"); }
|
|
55
56
|
|
|
57
|
+
async function useRemaining(args: string[], json: boolean, deps: RuntimeApiDeps): Promise<number> {
|
|
58
|
+
if (args.shift() !== "openai") usage();
|
|
59
|
+
const requested = selector(args.shift()), action = args.shift();
|
|
60
|
+
if (!["on", "off", "status"].includes(action ?? "")) usage();
|
|
61
|
+
done(args);
|
|
62
|
+
const pinned = { ...deps, baseUrl: await runtimeBaseUrl(deps) };
|
|
63
|
+
const { id } = await target(pinned, requested);
|
|
64
|
+
const path = "/api/codex-auth/accounts/use-remaining";
|
|
65
|
+
const result = parseDto(remainingQuotaReceipt, await request(
|
|
66
|
+
action === "status" ? path + "?id=" + encodeURIComponent(id) : path,
|
|
67
|
+
pinned, action === "status" ? undefined : { id, useRemainingQuota: action === "on" },
|
|
68
|
+
));
|
|
69
|
+
requireEqual(result.id, id);
|
|
70
|
+
if (action !== "status") requireEqual(result.useRemainingQuota, action === "on");
|
|
71
|
+
if (result.useRemainingQuota) {
|
|
72
|
+
requireEqual(result.autoSwitchThreshold, 0);
|
|
73
|
+
if (id === MAIN_CODEX_ACCOUNT_ID) {
|
|
74
|
+
requireEqual(result.mainAccountHardLock?.thresholds.short, 100);
|
|
75
|
+
requireEqual(result.mainAccountHardLock?.thresholds.long, 100);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return output(result, json, result.useRemainingQuota
|
|
79
|
+
? "Use remaining included quota: on. Paid-credit permission is unchanged."
|
|
80
|
+
: "Use remaining included quota: off. Configured usage thresholds apply.");
|
|
81
|
+
}
|
|
82
|
+
|
|
56
83
|
async function pool(args: string[], json: boolean, deps: RuntimeApiDeps): Promise<number> {
|
|
57
84
|
const provider = selector(args.shift()).toLowerCase();
|
|
58
85
|
if (!isValidProviderName(provider)) usage();
|
|
@@ -63,7 +90,8 @@ async function pool(args: string[], json: boolean, deps: RuntimeApiDeps): Promis
|
|
|
63
90
|
if (limit !== undefined) patch.autoSwitchThreshold = integer(limit, 0);
|
|
64
91
|
if (sticky !== undefined) patch.stickyLimit = integer(sticky, 1);
|
|
65
92
|
if (strategy !== undefined) {
|
|
66
|
-
|
|
93
|
+
// reset-first is a Codex and generic-pool strategy; the Anthropic pool does not run it.
|
|
94
|
+
if (!["quota", "round-robin", "fill-first", ...(isAnthropicInstanceId(provider) ? [] : ["reset-first"]),
|
|
67
95
|
...(provider === "kiro" ? ["least-loaded"] : [])].includes(strategy)) usage();
|
|
68
96
|
patch.strategy = strategy;
|
|
69
97
|
}
|
|
@@ -122,12 +150,12 @@ async function codex(sub: "auto-switch" | "credits" | "quota-activation", args:
|
|
|
122
150
|
const override = selected?.autoSwitchThresholdOverride;
|
|
123
151
|
if (override === undefined) throw new Error("Missing account threshold evidence");
|
|
124
152
|
const active = record(await request("/api/codex-auth/active", pinned));
|
|
125
|
-
const effective = override ?? parseDto(threshold, active.autoSwitchThreshold);
|
|
153
|
+
const effective = selected?.useRemainingQuota ? 0 : override ?? parseDto(threshold, active.autoSwitchThreshold);
|
|
126
154
|
return output({ ok: true, id, autoSwitchThresholdOverride: override, autoSwitchThreshold: effective }, json);
|
|
127
155
|
}
|
|
128
156
|
const result = parseDto(thresholdReceipt, await request("/api/codex-auth/auto-switch", pinned, { id, threshold: value }));
|
|
129
157
|
requireEqual(result.id, id); requireEqual(result.autoSwitchThresholdOverride, value);
|
|
130
|
-
if (value !== null) requireEqual(result.autoSwitchThreshold, value);
|
|
158
|
+
if (value !== null && !rows.find(row => row.id === id)?.useRemainingQuota) requireEqual(result.autoSwitchThreshold, value);
|
|
131
159
|
return output(result, json, "Account threshold saved.");
|
|
132
160
|
}
|
|
133
161
|
if (sub === "credits") {
|
|
@@ -157,6 +185,7 @@ export async function handleAccountPolicyCommand(sub: Subcommand, args: string[]
|
|
|
157
185
|
const rest = [...args], json = takeFlag(rest, "--json");
|
|
158
186
|
if (rest.includes("--json")) usage();
|
|
159
187
|
if (sub === "pool") return pool(rest, json, deps);
|
|
188
|
+
if (sub === "use-remaining") return useRemaining(rest, json, deps);
|
|
160
189
|
if (sub !== "anthropic-reset-grants") return codex(sub, rest, json, deps);
|
|
161
190
|
const selectedProvider = option(rest, "--provider");
|
|
162
191
|
const provider = selectedProvider ?? "anthropic";
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { apiError, apiJson, proxyUnreachable, resolveBaseUrl, type AccountDeps } from "./account-api";
|
|
2
|
+
|
|
3
|
+
/** This operation follows the selected runtime; never read a local account/config roster. */
|
|
4
|
+
export async function cmdPreserveSignedIn(args: string[], deps: AccountDeps): Promise<number> {
|
|
5
|
+
const provider = args.shift();
|
|
6
|
+
let mode = "status";
|
|
7
|
+
let hasMode = false;
|
|
8
|
+
let json = false;
|
|
9
|
+
let applyToBound = false;
|
|
10
|
+
for (const arg of args) {
|
|
11
|
+
if (arg === "--json" && !json) json = true;
|
|
12
|
+
else if (arg === "--apply-to-bound" && !applyToBound) applyToBound = true;
|
|
13
|
+
else if (["on", "off", "status"].includes(arg) && !hasMode) { mode = arg; hasMode = true; }
|
|
14
|
+
else return usage();
|
|
15
|
+
}
|
|
16
|
+
if (provider !== "openai" || (applyToBound && mode !== "on")) return usage();
|
|
17
|
+
const baseUrl = await resolveBaseUrl(deps);
|
|
18
|
+
if (!baseUrl) return proxyUnreachable();
|
|
19
|
+
const result = await apiJson(deps, baseUrl, mode === "status" ? "GET" : "PUT", "/api/codex-auth/preserve-signed-in",
|
|
20
|
+
mode === "status" ? undefined : { enabled: mode === "on", applyToBound });
|
|
21
|
+
if (result.status === 0) return proxyUnreachable(result.transportError);
|
|
22
|
+
if (result.status !== 200) return apiError(result.json, "Signed-in quota policy unavailable", result.status);
|
|
23
|
+
if (typeof result.json.enabled !== "boolean" || !Array.isArray(result.json.affectedAccountIds)
|
|
24
|
+
|| !result.json.affectedAccountIds.every(id => typeof id === "string")
|
|
25
|
+
|| (result.json.nextAccountId !== null && typeof result.json.nextAccountId !== "string")) {
|
|
26
|
+
return apiError({}, "Invalid signed-in quota policy response", 502);
|
|
27
|
+
}
|
|
28
|
+
if (json) console.log(JSON.stringify(result.json, null, 2));
|
|
29
|
+
else {
|
|
30
|
+
console.log(`Preserve signed-in quota: ${result.json.enabled ? "on" : "off"}`);
|
|
31
|
+
console.log(`Affected pool entries: ${result.json.affectedAccountIds.join(", ")}`);
|
|
32
|
+
console.log(`Next unbound choice: ${result.json.nextAccountId ?? "none"}`);
|
|
33
|
+
console.log(`Bindings: ${result.json.bindings}; manual pin: ${result.json.pinnedAccountId ?? "none"}`);
|
|
34
|
+
if (result.json.priorityFailbackEnabled === true) console.log("Existing priority failback can move bound work when its quota and freshness conditions hold.");
|
|
35
|
+
console.log("Fallback can consume signed-in quota. Exact-account models override this preference.");
|
|
36
|
+
console.log("Use on --apply-to-bound to release affected bindings and pins for the next request.");
|
|
37
|
+
}
|
|
38
|
+
return 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function usage(): number {
|
|
42
|
+
console.error("Usage: ocx account preserve-signed-in openai [on|off|status] [--apply-to-bound] [--json]");
|
|
43
|
+
return 1;
|
|
44
|
+
}
|
package/src/cli/account.ts
CHANGED
|
@@ -54,6 +54,7 @@ const ACCOUNT_USAGE = `Usage:
|
|
|
54
54
|
ocx account auto-switch <provider> <on|off|status|threshold <0-100>> [--json]
|
|
55
55
|
ocx account auto-switch <anthropic|anthropic2> <on|off|status|inherit|threshold <0-100>> --account <id> [--json]
|
|
56
56
|
ocx account alias <provider> <account-or-key-id|alias> <display-name|-> [--json]
|
|
57
|
+
ocx account preserve-signed-in openai [on|off|status] [--apply-to-bound] [--json]
|
|
57
58
|
ocx account priority <provider> <account-id|alias|main> [<-100..100|first|earlier|normal|later|last|reset>] [--json]
|
|
58
59
|
ocx account pause <provider> <account-id|alias|main> [--json]
|
|
59
60
|
ocx account resume <provider> <account-id|alias|main> [--json]
|
|
@@ -69,6 +70,7 @@ const ACCOUNT_USAGE = `Usage:
|
|
|
69
70
|
ocx account login <provider> [--id <account-id>] [--reauth] [--open-browser on|off] [--add-account on|off] [--code -] [--no-wait] [--json]
|
|
70
71
|
ocx account pool <provider> [--enabled on|off] [--threshold N] [--strategy NAME] [--sticky N] [--quota-window W] [--json]
|
|
71
72
|
ocx account credits openai <ID on|off|--all on|off> [--json]
|
|
73
|
+
ocx account use-remaining openai <ID|main> <on|off|status> [--json]
|
|
72
74
|
ocx account quota-activation openai ID --window fiveHour|weekly <on|off> [--json]
|
|
73
75
|
ocx account anthropic-reset-grants [ID] [--provider anthropic|anthropic2] [--json]
|
|
74
76
|
ocx account code <provider> [--flow <flow-id>] [--json] (reads the code from stdin)
|
|
@@ -459,11 +461,11 @@ async function cmdClear(rest: string[], deps: AccountDeps): Promise<number> {
|
|
|
459
461
|
export async function cmdAccount(args: string[], deps: AccountDeps = {}): Promise<number> {
|
|
460
462
|
const [sub, ...rest] = args;
|
|
461
463
|
try {
|
|
462
|
-
if (["pool", "credits", "quota-activation", "anthropic-reset-grants"].includes(sub ?? "")
|
|
464
|
+
if (["pool", "credits", "quota-activation", "anthropic-reset-grants", "use-remaining"].includes(sub ?? "")
|
|
463
465
|
|| (sub === "auto-switch" && rest[0]?.trim().toLowerCase() === "openai"
|
|
464
466
|
&& rest.some(arg => arg === "--account" || arg.startsWith("--account=")))) {
|
|
465
467
|
const { handleAccountPolicyCommand } = await import("./account-policy");
|
|
466
|
-
return handleAccountPolicyCommand(sub as "pool" | "auto-switch" | "credits" | "quota-activation" | "anthropic-reset-grants", rest, deps);
|
|
468
|
+
return handleAccountPolicyCommand(sub as "pool" | "auto-switch" | "credits" | "quota-activation" | "anthropic-reset-grants" | "use-remaining", rest, deps);
|
|
467
469
|
}
|
|
468
470
|
if (sub === "list") return await cmdList(rest, deps);
|
|
469
471
|
if (sub === "history") {
|
|
@@ -476,6 +478,10 @@ export async function cmdAccount(args: string[], deps: AccountDeps = {}): Promis
|
|
|
476
478
|
if (sub === "refresh") return await cmdRefresh(rest, deps);
|
|
477
479
|
if (sub === "auto-switch") return await cmdAutoSwitch(rest, deps);
|
|
478
480
|
if (sub === "alias" || sub === "rename") return await cmdAlias(rest, deps);
|
|
481
|
+
if (sub === "preserve-signed-in") {
|
|
482
|
+
const { cmdPreserveSignedIn } = await import("./account-preservation");
|
|
483
|
+
return cmdPreserveSignedIn(rest, deps);
|
|
484
|
+
}
|
|
479
485
|
if (sub === "priority") return await cmdPriority(rest, deps);
|
|
480
486
|
// #2702: the server routes existed and only the CLI caller was missing, so these were
|
|
481
487
|
// dashboard-only capabilities.
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { ADVISOR_CONTEXT_SHARING_CONSENT_VERSION, ADVISOR_CONTEXT_SHARING_DISCLOSURE } from "../advisor/disclosure";
|
|
2
|
+
import { CliUsageError, printData, rejectArgs, runCliAction, runtimeRequest, takeFlag, type RuntimeApiDeps } from "./runtime-api";
|
|
3
|
+
|
|
4
|
+
const USAGE = `Usage:
|
|
5
|
+
ocx advisor status [--json]
|
|
6
|
+
ocx advisor activity [--json]
|
|
7
|
+
ocx advisor on [--ack-context-sharing] [--json]
|
|
8
|
+
ocx advisor off [--json]
|
|
9
|
+
ocx advisor consent [--revoke] [--json]
|
|
10
|
+
ocx advisor set [--model <model>] [--effort <effort>] [--policy <manual|preflight|adaptive>] [--max-consultations <1-3>] [--timeout-ms <ms>] [--json]`;
|
|
11
|
+
|
|
12
|
+
const VALUED_FLAGS = new Set(["--model", "--effort", "--policy", "--timeout-ms", "--max-consultations"]);
|
|
13
|
+
|
|
14
|
+
interface SetOptions {
|
|
15
|
+
model?: string;
|
|
16
|
+
effort?: string;
|
|
17
|
+
policy?: string;
|
|
18
|
+
timeoutMs?: string;
|
|
19
|
+
maxConsultations?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function parseSetArgs(args: string[]): SetOptions {
|
|
23
|
+
const options: SetOptions = {};
|
|
24
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
25
|
+
const arg = args[index]!;
|
|
26
|
+
if (!VALUED_FLAGS.has(arg)) throw new CliUsageError(`unknown advisor set option ${arg}`, USAGE);
|
|
27
|
+
const value = args[++index];
|
|
28
|
+
if (value === undefined || value.startsWith("--")) throw new CliUsageError(`${arg} requires a value`, USAGE);
|
|
29
|
+
// An explicitly supplied empty value is meaningful for --model alone: the settings route
|
|
30
|
+
// treats "" as the supported "clear the model" state. Every other valued flag still needs one.
|
|
31
|
+
if (value === "" && arg !== "--model") throw new CliUsageError(`${arg} requires a value`, USAGE);
|
|
32
|
+
if (arg === "--model") options.model = value;
|
|
33
|
+
else if (arg === "--effort") options.effort = value;
|
|
34
|
+
else if (arg === "--policy") options.policy = value;
|
|
35
|
+
else if (arg === "--max-consultations") options.maxConsultations = value;
|
|
36
|
+
else options.timeoutMs = value;
|
|
37
|
+
}
|
|
38
|
+
if (Object.keys(options).length === 0) {
|
|
39
|
+
throw new CliUsageError("advisor set requires a model, effort, policy, task limit, or timeout option", USAGE);
|
|
40
|
+
}
|
|
41
|
+
return options;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function status(argv: string[], deps: RuntimeApiDeps): Promise<void> {
|
|
45
|
+
const args = [...argv];
|
|
46
|
+
const wantsJson = takeFlag(args, "--json");
|
|
47
|
+
rejectArgs(args, USAGE);
|
|
48
|
+
printData(await runtimeRequest("/api/advisor/settings", {}, deps), wantsJson);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function printDisclosure(): void {
|
|
52
|
+
console.error(ADVISOR_CONTEXT_SHARING_DISCLOSURE);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function readConsent(deps: RuntimeApiDeps): Promise<unknown> {
|
|
56
|
+
const current = await runtimeRequest("/api/advisor/settings", {}, deps) as {
|
|
57
|
+
settings?: { contextSharingConsent?: unknown };
|
|
58
|
+
};
|
|
59
|
+
return current.settings?.contextSharingConsent;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function setEnabled(enabled: boolean, argv: string[], deps: RuntimeApiDeps): Promise<void> {
|
|
63
|
+
const args = [...argv];
|
|
64
|
+
const wantsJson = takeFlag(args, "--json");
|
|
65
|
+
const acknowledge = takeFlag(args, "--ack-context-sharing");
|
|
66
|
+
rejectArgs(args, USAGE);
|
|
67
|
+
if (!enabled) {
|
|
68
|
+
if (acknowledge) {
|
|
69
|
+
throw new CliUsageError(
|
|
70
|
+
"--ack-context-sharing has no effect with `ocx advisor off`; it never records consent.",
|
|
71
|
+
USAGE,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
printData(await runtimeRequest("/api/advisor/settings", {
|
|
75
|
+
method: "PUT",
|
|
76
|
+
body: JSON.stringify({ enabled: false }),
|
|
77
|
+
}, deps), wantsJson, ["Advisor disabled."]);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const consent = await readConsent(deps);
|
|
81
|
+
if (acknowledge) {
|
|
82
|
+
printDisclosure();
|
|
83
|
+
printData(await runtimeRequest("/api/advisor/settings", {
|
|
84
|
+
method: "PUT",
|
|
85
|
+
body: JSON.stringify({
|
|
86
|
+
enabled: true,
|
|
87
|
+
contextSharingConsent: ADVISOR_CONTEXT_SHARING_CONSENT_VERSION,
|
|
88
|
+
}),
|
|
89
|
+
}, deps), wantsJson, ["Advisor enabled with context-sharing consent v1."]);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (consent !== ADVISOR_CONTEXT_SHARING_CONSENT_VERSION) {
|
|
93
|
+
printDisclosure();
|
|
94
|
+
throw new CliUsageError(
|
|
95
|
+
"Advisor context-sharing consent is required before consultations can send task content. "
|
|
96
|
+
+ "Re-run `ocx advisor on --ack-context-sharing` after reading the disclosure, or run `ocx advisor consent`.",
|
|
97
|
+
USAGE,
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
printData(await runtimeRequest("/api/advisor/settings", {
|
|
101
|
+
method: "PUT",
|
|
102
|
+
body: JSON.stringify({ enabled: true }),
|
|
103
|
+
}, deps), wantsJson, ["Advisor enabled."]);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function consent(argv: string[], deps: RuntimeApiDeps): Promise<void> {
|
|
107
|
+
const args = [...argv];
|
|
108
|
+
const wantsJson = takeFlag(args, "--json");
|
|
109
|
+
const revoke = takeFlag(args, "--revoke");
|
|
110
|
+
rejectArgs(args, USAGE);
|
|
111
|
+
if (!revoke) printDisclosure();
|
|
112
|
+
printData(await runtimeRequest("/api/advisor/settings", {
|
|
113
|
+
method: "PUT",
|
|
114
|
+
body: JSON.stringify({
|
|
115
|
+
contextSharingConsent: revoke ? null : ADVISOR_CONTEXT_SHARING_CONSENT_VERSION,
|
|
116
|
+
}),
|
|
117
|
+
}, deps), wantsJson, [revoke
|
|
118
|
+
? "Advisor context-sharing consent removed. Consultations will not send task content."
|
|
119
|
+
: "Advisor context-sharing consent v1 recorded.",
|
|
120
|
+
]);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function set(argv: string[], deps: RuntimeApiDeps): Promise<void> {
|
|
124
|
+
const args = [...argv];
|
|
125
|
+
const wantsJson = takeFlag(args, "--json");
|
|
126
|
+
const options = parseSetArgs(args);
|
|
127
|
+
const patch: Record<string, unknown> = {};
|
|
128
|
+
if (options.model !== undefined) patch.model = options.model;
|
|
129
|
+
if (options.effort !== undefined) patch.effort = options.effort;
|
|
130
|
+
if (options.policy !== undefined) patch.policy = options.policy;
|
|
131
|
+
if (options.maxConsultations !== undefined) {
|
|
132
|
+
const limit = Number(options.maxConsultations);
|
|
133
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 3) throw new CliUsageError("--max-consultations must be an integer between 1 and 3", USAGE);
|
|
134
|
+
patch.maxConsultationsPerTask = limit;
|
|
135
|
+
}
|
|
136
|
+
if (options.timeoutMs !== undefined) {
|
|
137
|
+
const parsed = Number(options.timeoutMs);
|
|
138
|
+
if (!Number.isFinite(parsed)) throw new CliUsageError("--timeout-ms must be a number", USAGE);
|
|
139
|
+
patch.timeoutMs = parsed;
|
|
140
|
+
}
|
|
141
|
+
printData(await runtimeRequest("/api/advisor/settings", {
|
|
142
|
+
method: "PUT",
|
|
143
|
+
body: JSON.stringify(patch),
|
|
144
|
+
}, deps), wantsJson, ["Advisor settings saved."]);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export async function handleAdvisorCommand(argv: string[], deps: RuntimeApiDeps = {}): Promise<number> {
|
|
148
|
+
return runCliAction(async () => {
|
|
149
|
+
const [sub = "status", ...rest] = argv;
|
|
150
|
+
if (sub === "status") await status(rest, deps);
|
|
151
|
+
else if (sub === "activity") {
|
|
152
|
+
const args = [...rest];
|
|
153
|
+
const wantsJson = takeFlag(args, "--json");
|
|
154
|
+
rejectArgs(args, USAGE);
|
|
155
|
+
printData(await runtimeRequest("/api/advisor/activity", {}, deps), wantsJson);
|
|
156
|
+
}
|
|
157
|
+
else if (sub === "on") await setEnabled(true, rest, deps);
|
|
158
|
+
else if (sub === "off") await setEnabled(false, rest, deps);
|
|
159
|
+
else if (sub === "consent") await consent(rest, deps);
|
|
160
|
+
else if (sub === "set") await set(rest, deps);
|
|
161
|
+
else throw new CliUsageError(`unknown advisor command ${sub}`, USAGE);
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export const ADVISOR_USAGE = USAGE;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { OcxConfig } from "../types";
|
|
2
|
+
import { AuxiliaryListenerBindError } from "../server/ports";
|
|
3
|
+
import { createServer } from "node:net";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Reject impossible auxiliary binds before startup creates private state. On Windows
|
|
7
|
+
* that publication requires several synchronous ACL subprocesses. This is only an
|
|
8
|
+
* early rejection: startServer still owns the actual bind and transactional rollback
|
|
9
|
+
* if another process takes the port between this probe and startup.
|
|
10
|
+
*/
|
|
11
|
+
export async function assertAuxiliaryListenerPortsAvailable(config: OcxConfig): Promise<void> {
|
|
12
|
+
const loopback = config.unauthenticatedLoopbackListener;
|
|
13
|
+
const management = config.runtimeRole === "hub" ? config.hub?.managementIngress : undefined;
|
|
14
|
+
const targets = [
|
|
15
|
+
{ listener: "unauthenticatedLoopbackListener", port: loopback?.enabled ? loopback.port : undefined },
|
|
16
|
+
{ listener: "hub.managementIngress", port: management?.enabled ? management.port : undefined },
|
|
17
|
+
] as const;
|
|
18
|
+
// Each probe releases its socket, so two listeners configured for one port would both
|
|
19
|
+
// pass and startup would still fail on the second bind. Reject the collision directly.
|
|
20
|
+
if (targets[0].port !== undefined && targets[0].port === targets[1].port) {
|
|
21
|
+
throw new AuxiliaryListenerBindError(
|
|
22
|
+
"hub.managementIngress", targets[1].port, "127.0.0.1",
|
|
23
|
+
new Error("port is also configured for unauthenticatedLoopbackListener"),
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
for (const { listener, port } of targets) {
|
|
27
|
+
// The port-less companion shares the public bind; it has no independent target.
|
|
28
|
+
if (port === undefined) continue;
|
|
29
|
+
await new Promise<void>((resolve, reject) => {
|
|
30
|
+
const probe = createServer(socket => socket.destroy());
|
|
31
|
+
const fail = (cause: unknown) => reject(new AuxiliaryListenerBindError(listener, port, "127.0.0.1", cause));
|
|
32
|
+
probe.once("error", fail);
|
|
33
|
+
probe.once("listening", () => probe.close(error => error ? fail(error) : resolve()));
|
|
34
|
+
try { probe.listen({ port, host: "127.0.0.1" }); } catch (error) { fail(error); }
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -2,6 +2,14 @@ import type { Capability } from "./capability-types";
|
|
|
2
2
|
|
|
3
3
|
/** Account pool operations and physical native-login profiles have separate owners. */
|
|
4
4
|
export const ACCOUNT_CAPABILITIES: readonly Capability[] = [
|
|
5
|
+
{
|
|
6
|
+
command: ["account", "preserve-signed-in"], summary: "Prefer other Codex identities and reserve the native sign-in as fallback.",
|
|
7
|
+
usage: "ocx account preserve-signed-in openai [on|off|status] [--apply-to-bound] [--json]",
|
|
8
|
+
routes: [{ method: "GET", path: "/api/codex-auth/preserve-signed-in" }, { method: "PUT", path: "/api/codex-auth/preserve-signed-in" }],
|
|
9
|
+
flags: [{ name: "--apply-to-bound", value: "boolean", summary: "With on, release protected bindings and pins for the next request." }, { name: "--json", value: "boolean", summary: "Emit affected entries, next unbound choice and pin/binding semantics." }],
|
|
10
|
+
mutates: true, json: "payload",
|
|
11
|
+
details: ["Default/status reads. Custom priorities are preserved. Bound threads and manual pins remain unless explicitly released. Exact-account models override the preference. Fallback can spend signed-in quota; linked pause excludes it instead."],
|
|
12
|
+
},
|
|
5
13
|
{
|
|
6
14
|
command: ["logout"],
|
|
7
15
|
summary: "Remove the active stored OAuth credential for a provider locally.",
|
|
@@ -157,11 +165,22 @@ export const ACCOUNT_CAPABILITIES: readonly Capability[] = [
|
|
|
157
165
|
usage: "ocx account pool <provider> [--enabled <on|off>] [--threshold <0-100>] [--strategy <name>] [--sticky <1-100>] [--quota-window <five-hour|weekly|max-utilization>] [--json]",
|
|
158
166
|
summary: "Read or edit the selected runtime's supported pool policy fields.",
|
|
159
167
|
routes: [{"method":"GET","path":"/api/pool/settings"},{"method":"PUT","path":"/api/pool/settings"}],
|
|
160
|
-
flags: [{"name":"--enabled","value":"string","summary":"Stored pool preference; unsupported for Codex. Not equivalent to threshold0."},{"name":"--threshold","value":"number","summary":"Auto-switch threshold0–100."},{"name":"--strategy","value":"string","summary":"Use a strategy supported by this provider kind; reset-first is Codex, least-loaded is Kiro."},{"name":"--sticky","value":"number","summary":"Sticky limit1–100."},{"name":"--quota-window","value":"string","summary":"Anthropic only: five-hour, weekly or max-utilization."},{"name":"--json","value":"boolean","summary":"Emit the validated task result as one JSON document."}],
|
|
168
|
+
flags: [{"name":"--enabled","value":"string","summary":"Stored pool preference; unsupported for Codex. Not equivalent to threshold0."},{"name":"--threshold","value":"number","summary":"Auto-switch threshold0–100."},{"name":"--strategy","value":"string","summary":"Use a strategy supported by this provider kind; reset-first is Codex or generic OAuth, least-loaded is Kiro."},{"name":"--sticky","value":"number","summary":"Sticky limit1–100."},{"name":"--quota-window","value":"string","summary":"Anthropic only: five-hour, weekly or max-utilization."},{"name":"--json","value":"boolean","summary":"Emit the validated task result as one JSON document."}],
|
|
161
169
|
mutates: true,
|
|
162
170
|
json: "envelope",
|
|
163
171
|
details: ["Reads the target supported-field list before a narrow PUT. Null/unsupported, stored/effective and generic inert policy stay distinct; disabling does not promise that reactive429 rotation stops.","No local classification/defaults are round-tripped into the live target; supported-field reads are not CAS."],
|
|
164
172
|
},
|
|
173
|
+
{
|
|
174
|
+
command: ["account", "use-remaining"],
|
|
175
|
+
usage: "ocx account use-remaining openai <id|alias|main> <on|off|status> [--json]",
|
|
176
|
+
summary: "Choose whether one Codex account keeps using its remaining included quota.",
|
|
177
|
+
routes: [{ method: "GET", path: "/api/codex-auth/accounts" },
|
|
178
|
+
{ method: "GET", path: "/api/codex-auth/accounts/use-remaining" }, { method: "PUT", path: "/api/codex-auth/accounts/use-remaining" }],
|
|
179
|
+
flags: [{ name: "--json", value: "boolean", summary: "Emit the validated account policy." }],
|
|
180
|
+
mutates: true, json: "envelope",
|
|
181
|
+
details: ["On disables proactive usage switching for the selected account and raises main-account protection to 100%. Off restores the configured thresholds.",
|
|
182
|
+
"This is a persistent preference, not account selection. Pause, reauthentication, cooldown, entitlement and paid-credit policy still apply."],
|
|
183
|
+
},
|
|
165
184
|
{
|
|
166
185
|
command: ["account","credits"],
|
|
167
186
|
usage: "ocx account credits openai <id|alias|main> <on|off> [--json]; ocx account credits openai --all <on|off> [--json]",
|