@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
|
@@ -31,6 +31,22 @@ export function bindAnthropicRefusalCredentialForSend(response: Response, owner:
|
|
|
31
31
|
responseCredentials.set(response, Object.freeze({ ...owner, providerAccountUuid, checkProviderUuid: arguments.length >= 3 }));
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
/** Preserve the original send proof across internal error normalization, without renewing it. */
|
|
35
|
+
export function carryAnthropicRefusalCredential(source: Response, target: Response): void {
|
|
36
|
+
const sent = responseCredentials.get(source);
|
|
37
|
+
if (sent) responseCredentials.set(target, sent);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Recheck after body consumption: a late refusal cannot acquire a replacement login's authority. */
|
|
41
|
+
export function anthropicRefusalCredentialIsCurrent(response: Response, instance: AnthropicInstanceId, accountId: string): boolean {
|
|
42
|
+
const sent = responseCredentials.get(response);
|
|
43
|
+
if (!sent || sent.provider !== instance || sent.accountId !== accountId
|
|
44
|
+
|| !anthropicPhysicalSendOwnershipIsCurrent(sent)) return false;
|
|
45
|
+
const row = getAccountCredentialWithStatus(instance, accountId);
|
|
46
|
+
return !!row && !row.paused && !row.needsReauth
|
|
47
|
+
&& (!sent.checkProviderUuid || row.credential.accountId === sent.providerAccountUuid);
|
|
48
|
+
}
|
|
49
|
+
|
|
34
50
|
async function isRevokedOAuthToken(response: Response, signal?: AbortSignal): Promise<boolean> {
|
|
35
51
|
if (response.status !== 401) return false;
|
|
36
52
|
try {
|
|
@@ -59,9 +75,11 @@ async function isAccountRefusal(response: Response, signal?: AbortSignal): Promi
|
|
|
59
75
|
// Whole-message patterns: request-policy/model/resource refusals and quoted diagnostics
|
|
60
76
|
// must not acquire account authority merely by containing entitlement keywords.
|
|
61
77
|
if ("code" in error && error.code != null
|
|
62
|
-
&& (typeof error.code !== "string" || !["subscription_required", "insufficient_quota", "permission_denied"].includes(error.code))) return false;
|
|
78
|
+
&& (typeof error.code !== "string" || !["subscription_required", "insufficient_quota", "permission_denied", "oauth_org_not_allowed"].includes(error.code))) return false;
|
|
79
|
+
// The organization disabled subscription access: an account-scoped verdict, cooled like its siblings.
|
|
80
|
+
if (error.type === "oauth_org_not_allowed" || ("code" in error && error.code === "oauth_org_not_allowed")) return true;
|
|
63
81
|
const message = error.message.trim();
|
|
64
|
-
if (error.type === "permission_error" && /^(?:Your account does not have access to Claude Code|Your (?:Claude )?subscription (?:has expired|is (?:expired|inactive))|Your account does not have an active subscription)[.!]?$/i.test(message)) return true;
|
|
82
|
+
if (error.type === "permission_error" && /^(?:Your account does not have access to Claude Code|Your (?:Claude )?subscription (?:has expired|is (?:expired|inactive))|Your account does not have an active subscription|(?:Your|This) organization has disabled Claude subscription access for Claude Code(?:\. Use an Anthropic API key instead, or ask your admin to enable access)?)[.!]?$/i.test(message)) return true;
|
|
65
83
|
return (error.type === "billing_error" || error.type === "permission_error")
|
|
66
84
|
&& /^Your credit balance is too low to access the Anthropic API\.(?: Please go to Plans & Billing to upgrade or purchase credits\.)?$/i.test(message);
|
|
67
85
|
} catch {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ConfigMutationLockError } from "../config";
|
|
2
2
|
import { deriveOAuthDefaultModel, deriveOAuthProviderConfig } from "../providers/derive";
|
|
3
3
|
import type { AnthropicInstanceId } from "../providers/anthropic-instance-id";
|
|
4
|
-
import { loginAnthropic, refreshAnthropicToken } from "./anthropic";
|
|
4
|
+
import { ANTHROPIC_CODE_REDIRECT_URI, loginAnthropic, refreshAnthropicToken } from "./anthropic";
|
|
5
5
|
import type { OAuthProviderDef } from "./index";
|
|
6
6
|
import {
|
|
7
7
|
clearOAuthRefreshIntent, clearOAuthRefreshIntentIfMatch, markOAuthRefreshIntentCleanupPending,
|
|
@@ -16,8 +16,10 @@ export function anthropicOAuthDefinition(instance: AnthropicInstanceId): OAuthPr
|
|
|
16
16
|
return {
|
|
17
17
|
login: (ctrl, opts) => loginAnthropic(ctrl, {
|
|
18
18
|
instance, importLocal: instance === "anthropic2" || opts?.forceLogin ? "off" : "fallback",
|
|
19
|
+
codeMode: opts?.codeMode === true,
|
|
19
20
|
}),
|
|
20
21
|
refresh: refreshAnthropicToken,
|
|
22
|
+
codeRedirectUri: ANTHROPIC_CODE_REDIRECT_URI,
|
|
21
23
|
providerConfig,
|
|
22
24
|
defaultModel,
|
|
23
25
|
// Subscription OAuth must never generate unattended traffic by default.
|
|
@@ -19,7 +19,6 @@ import { clearAllAnthropicFamilyQuota, anthropicModelQuotaFor, anthropicModelPer
|
|
|
19
19
|
*/
|
|
20
20
|
import { clearAllAnthropicRatePauses, anthropicRatePolicyFor, classifyAnthropic429, anthropicRetryAfterMs } from "./anthropic-rate-limit-policy";
|
|
21
21
|
import { REFRESH_SKEW_MS } from "./refresh-policy";
|
|
22
|
-
import { createHash } from "node:crypto";
|
|
23
22
|
import { captureOAuthAccountSelection, commitOAuthAccountSelection, credentialGeneration, getAccountSet, getAccountCredential, getAccountCredentialWithStatus } from "./store";
|
|
24
23
|
import type { OAuthAccessSnapshot } from "./index";
|
|
25
24
|
import { getCachedProviderAccountQuota } from "../providers/quota";
|
|
@@ -273,26 +272,7 @@ export function formatAnthropicProviderForLog(
|
|
|
273
272
|
return `${providerName}-${formatAnthropicAccountOrdinal(accountId)}`;
|
|
274
273
|
}
|
|
275
274
|
|
|
276
|
-
export
|
|
277
|
-
sessionIdHeader?: string | null;
|
|
278
|
-
threadIdHeader?: string | null;
|
|
279
|
-
promptCacheKey?: string | null;
|
|
280
|
-
clientThreadId?: string | null;
|
|
281
|
-
/** When true, prompt_cache_key is a shared Desktop cohort — ignore it for affinity. */
|
|
282
|
-
promptCacheKeyIsSharedCohort?: boolean;
|
|
283
|
-
}): string | null {
|
|
284
|
-
const preferred = input.clientThreadId?.trim()
|
|
285
|
-
|| input.sessionIdHeader?.trim()
|
|
286
|
-
|| input.threadIdHeader?.trim()
|
|
287
|
-
|| "";
|
|
288
|
-
if (preferred) {
|
|
289
|
-
return preferred.length <= 128 ? preferred : createHash("sha256").update(preferred).digest("hex");
|
|
290
|
-
}
|
|
291
|
-
if (input.promptCacheKeyIsSharedCohort) return null;
|
|
292
|
-
const cacheKey = input.promptCacheKey?.trim() ?? "";
|
|
293
|
-
if (!cacheKey) return null;
|
|
294
|
-
return cacheKey.length <= 128 ? cacheKey : createHash("sha256").update(cacheKey).digest("hex");
|
|
295
|
-
}
|
|
275
|
+
export { oauthSessionKeyFromParts as anthropicSessionKeyFromParts } from "./session-affinity-key";
|
|
296
276
|
|
|
297
277
|
|
|
298
278
|
export type AnthropicCooldownRecoveryClaim = Readonly<{
|
package/src/oauth/anthropic.ts
CHANGED
|
@@ -15,6 +15,16 @@ const CALLBACK_PATH = "/callback";
|
|
|
15
15
|
/** Profile enrichment budget on token refresh; login paths keep the resolver's own deadline. */
|
|
16
16
|
const REFRESH_PROFILE_TIMEOUT_MS = 2_000;
|
|
17
17
|
const SCOPES = "org:create_api_key user:profile user:inference";
|
|
18
|
+
/**
|
|
19
|
+
* Provider-hosted code-display redirect: Anthropic renders `code#state` for the user to copy
|
|
20
|
+
* instead of redirecting to a local port. This is what makes login possible from a container or
|
|
21
|
+
* a hosted gateway, where no browser can reach this process. Same OAuth client as the callback
|
|
22
|
+
* flow — only the redirect differs, so it must be the redirect_uri used for BOTH the authorize
|
|
23
|
+
* request and the token exchange.
|
|
24
|
+
*/
|
|
25
|
+
export const ANTHROPIC_CODE_REDIRECT_URI = "https://platform.claude.com/oauth/code/callback";
|
|
26
|
+
/** A displayed code is copied by hand across devices; the 300s callback wait is too short. */
|
|
27
|
+
const CODE_MODE_TIMEOUT_MS = 10 * 60_000;
|
|
18
28
|
|
|
19
29
|
// ── OAuth-request requirements applied by the anthropic adapter when authMode==="oauth" ──
|
|
20
30
|
export const ANTHROPIC_OAUTH_BETA = "claude-code-20250219,oauth-2025-04-20";
|
|
@@ -142,10 +152,27 @@ async function withAccountProfile(credential: OAuthCredentials, signal?: AbortSi
|
|
|
142
152
|
}
|
|
143
153
|
|
|
144
154
|
export class AnthropicOAuthFlow extends OAuthCallbackFlow {
|
|
155
|
+
/**
|
|
156
|
+
* PKCE verifier for THIS flow. One `AnthropicOAuthFlow` is constructed per login and
|
|
157
|
+
* `generateAuthUrl` runs once on it, so the verifier is already flow-scoped: a second
|
|
158
|
+
* concurrent login builds a second instance and cannot reach this field.
|
|
159
|
+
*/
|
|
145
160
|
#verifier = "";
|
|
161
|
+
#codeMode: boolean;
|
|
146
162
|
|
|
147
|
-
constructor(ctrl: OAuthController) {
|
|
148
|
-
|
|
163
|
+
constructor(ctrl: OAuthController, opts?: { codeMode?: boolean }) {
|
|
164
|
+
if (opts?.codeMode) {
|
|
165
|
+
super(ctrl, {
|
|
166
|
+
preferredPort: CALLBACK_PORT,
|
|
167
|
+
callbackPath: CALLBACK_PATH,
|
|
168
|
+
redirectUri: ANTHROPIC_CODE_REDIRECT_URI,
|
|
169
|
+
skipCallbackServer: true,
|
|
170
|
+
timeoutMs: CODE_MODE_TIMEOUT_MS,
|
|
171
|
+
});
|
|
172
|
+
} else {
|
|
173
|
+
super(ctrl, CALLBACK_PORT, CALLBACK_PATH);
|
|
174
|
+
}
|
|
175
|
+
this.#codeMode = opts?.codeMode === true;
|
|
149
176
|
}
|
|
150
177
|
|
|
151
178
|
async generateAuthUrl(state: string, redirectUri: string): Promise<{ url: string; instructions?: string }> {
|
|
@@ -163,8 +190,9 @@ export class AnthropicOAuthFlow extends OAuthCallbackFlow {
|
|
|
163
190
|
});
|
|
164
191
|
return {
|
|
165
192
|
url: `${AUTHORIZE_URL}?${authParams.toString()}`,
|
|
166
|
-
instructions:
|
|
167
|
-
"
|
|
193
|
+
instructions: this.#codeMode
|
|
194
|
+
? "Open this URL in any browser, approve access, then paste the code Anthropic displays (it looks like code#state)."
|
|
195
|
+
: "Complete Claude login in your browser. If the browser cannot reach this machine, paste the final redirect URL or authorization code when prompted.",
|
|
168
196
|
};
|
|
169
197
|
}
|
|
170
198
|
|
|
@@ -191,9 +219,12 @@ export class AnthropicOAuthFlow extends OAuthCallbackFlow {
|
|
|
191
219
|
|
|
192
220
|
export async function loginAnthropic(
|
|
193
221
|
ctrl: OAuthController,
|
|
194
|
-
opts?: { importLocal?: LocalTokenImportMode; instance?: AnthropicInstanceId },
|
|
222
|
+
opts?: { importLocal?: LocalTokenImportMode; instance?: AnthropicInstanceId; codeMode?: boolean },
|
|
195
223
|
): Promise<OAuthCredentials> {
|
|
196
|
-
|
|
224
|
+
// A code-mode caller asked for a URL to show and a box to paste into. Importing a local
|
|
225
|
+
// Claude Code token instead would complete WITHOUT ever firing onAuth, so the caller would
|
|
226
|
+
// get no URL at all — a different outcome than the one its contract promises.
|
|
227
|
+
const importLocal = opts?.codeMode ? "off" : opts?.importLocal ?? "off";
|
|
197
228
|
if (opts?.instance === "anthropic2" && importLocal !== "off") throw new AnthropicLocalCliImportError();
|
|
198
229
|
if (importLocal !== "off") {
|
|
199
230
|
const { detectClaudeCodeToken } = await import("./local-token-detect");
|
|
@@ -221,7 +252,7 @@ export async function loginAnthropic(
|
|
|
221
252
|
);
|
|
222
253
|
}
|
|
223
254
|
}
|
|
224
|
-
return new AnthropicOAuthFlow(ctrl).login();
|
|
255
|
+
return new AnthropicOAuthFlow(ctrl, { codeMode: opts?.codeMode === true }).login();
|
|
225
256
|
}
|
|
226
257
|
|
|
227
258
|
export async function refreshAnthropicToken(refreshToken: string): Promise<OAuthCredentials> {
|
|
@@ -66,6 +66,15 @@ export interface OAuthCallbackFlowOptions {
|
|
|
66
66
|
callbackBindHostname?: string;
|
|
67
67
|
/** Exact redirect URI advertised to the provider; disables port fallback. */
|
|
68
68
|
redirectUri?: string;
|
|
69
|
+
/**
|
|
70
|
+
* Code-display mode: the provider renders the authorization code for the user to paste, so
|
|
71
|
+
* this process never receives a redirect and must NOT open a listener. Requires `redirectUri`
|
|
72
|
+
* (the provider-hosted code page) and an `onManualCodeInput` channel — without one the flow
|
|
73
|
+
* would wait for a callback that can never arrive.
|
|
74
|
+
*/
|
|
75
|
+
skipCallbackServer?: boolean;
|
|
76
|
+
/** Overrides the 300s wait for the code; code-display pastes are hand-typed and slower. */
|
|
77
|
+
timeoutMs?: number;
|
|
69
78
|
}
|
|
70
79
|
|
|
71
80
|
type BunServer = ReturnType<typeof Bun.serve>;
|
|
@@ -77,6 +86,8 @@ export abstract class OAuthCallbackFlow {
|
|
|
77
86
|
callbackHostname: string;
|
|
78
87
|
callbackBindHostname: string;
|
|
79
88
|
redirectUri?: string;
|
|
89
|
+
skipCallbackServer: boolean;
|
|
90
|
+
timeoutMs: number;
|
|
80
91
|
#callbackResolve?: (result: CallbackResult) => void;
|
|
81
92
|
#callbackReject?: (error: string) => void;
|
|
82
93
|
|
|
@@ -86,6 +97,8 @@ export abstract class OAuthCallbackFlow {
|
|
|
86
97
|
callbackPath: string = CALLBACK_PATH,
|
|
87
98
|
) {
|
|
88
99
|
this.ctrl = ctrl;
|
|
100
|
+
this.skipCallbackServer = false;
|
|
101
|
+
this.timeoutMs = DEFAULT_TIMEOUT;
|
|
89
102
|
if (typeof preferredPortOrOptions === "number") {
|
|
90
103
|
this.preferredPort = preferredPortOrOptions;
|
|
91
104
|
this.callbackPath = callbackPath;
|
|
@@ -98,6 +111,11 @@ export abstract class OAuthCallbackFlow {
|
|
|
98
111
|
this.callbackHostname = preferredPortOrOptions.callbackHostname ?? DEFAULT_HOSTNAME;
|
|
99
112
|
this.callbackBindHostname = preferredPortOrOptions.callbackBindHostname ?? DEFAULT_BIND_HOSTNAME;
|
|
100
113
|
this.redirectUri = preferredPortOrOptions.redirectUri;
|
|
114
|
+
this.skipCallbackServer = preferredPortOrOptions.skipCallbackServer === true;
|
|
115
|
+
this.timeoutMs = preferredPortOrOptions.timeoutMs ?? DEFAULT_TIMEOUT;
|
|
116
|
+
if (this.skipCallbackServer && !this.redirectUri) {
|
|
117
|
+
throw new Error("skipCallbackServer requires an explicit redirectUri");
|
|
118
|
+
}
|
|
101
119
|
}
|
|
102
120
|
|
|
103
121
|
/** Build provider-specific authorization URL. */
|
|
@@ -132,6 +150,14 @@ export abstract class OAuthCallbackFlow {
|
|
|
132
150
|
}
|
|
133
151
|
|
|
134
152
|
async #startCallbackServer(expectedState: string): Promise<{ servers: BunServer[]; redirectUri: string }> {
|
|
153
|
+
if (this.skipCallbackServer) {
|
|
154
|
+
// The paste channel is the ONLY way this flow can complete. Fail loudly here rather than
|
|
155
|
+
// hanging until the timeout on a controller that can never deliver a code.
|
|
156
|
+
if (!this.ctrl.onManualCodeInput) {
|
|
157
|
+
throw new Error("Code-display login requires a manual code input channel");
|
|
158
|
+
}
|
|
159
|
+
return { servers: [], redirectUri: this.redirectUri! };
|
|
160
|
+
}
|
|
135
161
|
try {
|
|
136
162
|
const servers = this.#createServers(this.preferredPort, expectedState);
|
|
137
163
|
if (this.redirectUri) {
|
|
@@ -226,7 +252,7 @@ export abstract class OAuthCallbackFlow {
|
|
|
226
252
|
}
|
|
227
253
|
|
|
228
254
|
#waitForCallback(expectedState: string): Promise<CallbackResult> {
|
|
229
|
-
const timeoutSignal = AbortSignal.timeout(
|
|
255
|
+
const timeoutSignal = AbortSignal.timeout(this.timeoutMs);
|
|
230
256
|
const signal = this.ctrl.signal ? AbortSignal.any([this.ctrl.signal, timeoutSignal]) : timeoutSignal;
|
|
231
257
|
|
|
232
258
|
const callbackPromise = new Promise<CallbackResult>((resolve, reject) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { OAuthController, OAuthCredentials } from "./types";
|
|
2
|
-
import { CHATGPT_CLIENT_ID, CHATGPT_TOKEN_URL, credsFromToken } from "./chatgpt";
|
|
2
|
+
import { CHATGPT_CLIENT_ID, CHATGPT_TOKEN_URL, credsFromToken } from "./chatgpt-shared";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* OpenAI deviceauth (device-code) grant for the ChatGPT/Codex provider.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { OAuthCredentials } from "./types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* What the browser callback grant and the deviceauth grant share: the public PKCE client and the
|
|
5
|
+
* way a token response becomes credentials.
|
|
6
|
+
*
|
|
7
|
+
* This is a leaf on purpose. `./chatgpt-device` needs these, and `./chatgpt` needs the device
|
|
8
|
+
* grant for `flow: "device"`; importing them straight from `./chatgpt` made the pair a cycle.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
12
|
+
const TOKEN_URL = "https://auth.openai.com/oauth/token";
|
|
13
|
+
|
|
14
|
+
/** Shared with the deviceauth grant in `./chatgpt-device`: same public PKCE client. */
|
|
15
|
+
export const CHATGPT_CLIENT_ID = CLIENT_ID;
|
|
16
|
+
export const CHATGPT_TOKEN_URL = TOKEN_URL;
|
|
17
|
+
|
|
18
|
+
export function decodeJwtPayload(token: string): Record<string, unknown> | undefined {
|
|
19
|
+
const parts = token.split(".");
|
|
20
|
+
if (parts.length !== 3 || !parts[1]) return undefined;
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8")) as Record<string, unknown>;
|
|
23
|
+
} catch {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function extractAccountId(idToken?: string, accessToken?: string): string | undefined {
|
|
29
|
+
for (const token of [idToken, accessToken]) {
|
|
30
|
+
if (!token) continue;
|
|
31
|
+
const payload = decodeJwtPayload(token);
|
|
32
|
+
if (!payload) continue;
|
|
33
|
+
if (typeof payload.chatgpt_account_id === "string") return payload.chatgpt_account_id;
|
|
34
|
+
const ns = payload["https://api.openai.com/auth"];
|
|
35
|
+
if (ns && typeof ns === "object" && typeof (ns as Record<string, unknown>).chatgpt_account_id === "string") {
|
|
36
|
+
return (ns as Record<string, unknown>).chatgpt_account_id as string;
|
|
37
|
+
}
|
|
38
|
+
const orgs = payload.organizations;
|
|
39
|
+
if (Array.isArray(orgs) && orgs[0] && typeof orgs[0].id === "string") return orgs[0].id as string;
|
|
40
|
+
}
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function extractEmail(idToken?: string, accessToken?: string): string | undefined {
|
|
45
|
+
for (const token of [idToken, accessToken]) {
|
|
46
|
+
if (!token) continue;
|
|
47
|
+
const payload = decodeJwtPayload(token);
|
|
48
|
+
if (!payload) continue;
|
|
49
|
+
if (typeof payload.email === "string") return payload.email.toLowerCase();
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function credsFromToken(data: Record<string, unknown>): OAuthCredentials {
|
|
55
|
+
const idToken = typeof data.id_token === "string" ? data.id_token : undefined;
|
|
56
|
+
// This parses a response from an external boundary, so the access token is
|
|
57
|
+
// validated rather than cast. A 200 carrying no access_token would otherwise
|
|
58
|
+
// resolve a login as successful with an undefined credential, which then gets
|
|
59
|
+
// silently declined at persistence — a success message and no account.
|
|
60
|
+
const accessToken = typeof data.access_token === "string" && data.access_token.length > 0
|
|
61
|
+
? data.access_token
|
|
62
|
+
: undefined;
|
|
63
|
+
if (!accessToken) throw new Error("ChatGPT token response missing access token");
|
|
64
|
+
const refreshToken = typeof data.refresh_token === "string" ? data.refresh_token : "";
|
|
65
|
+
// ?? only guards null/undefined; NaN or a string expires_in would otherwise
|
|
66
|
+
// produce a NaN expiry that never compares as expired, and a negative duration
|
|
67
|
+
// would stamp an already-past expiry — both block refresh semantics.
|
|
68
|
+
const expiresIn =
|
|
69
|
+
typeof data.expires_in === "number" && Number.isFinite(data.expires_in) && data.expires_in >= 0
|
|
70
|
+
? data.expires_in
|
|
71
|
+
: 3600;
|
|
72
|
+
// The computed timestamp itself must stay finite: Number.MAX_VALUE passes
|
|
73
|
+
// Number.isFinite but overflows to Infinity once multiplied by 1000.
|
|
74
|
+
const computedExpires = Date.now() + expiresIn * 1000;
|
|
75
|
+
const expires = Number.isFinite(computedExpires) ? computedExpires : Date.now() + 3600 * 1000;
|
|
76
|
+
return {
|
|
77
|
+
access: accessToken,
|
|
78
|
+
refresh: refreshToken,
|
|
79
|
+
expires,
|
|
80
|
+
accountId: extractAccountId(idToken, accessToken),
|
|
81
|
+
email: extractEmail(idToken, accessToken),
|
|
82
|
+
};
|
|
83
|
+
}
|
package/src/oauth/chatgpt.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { OAuthCallbackFlow } from "./callback-server";
|
|
2
|
+
import { CHATGPT_CLIENT_ID, CHATGPT_TOKEN_URL, credsFromToken, decodeJwtPayload, extractAccountId, extractEmail } from "./chatgpt-shared";
|
|
2
3
|
import type { OAuthController, OAuthCredentials } from "./types";
|
|
3
4
|
import { generatePKCE } from "./pkce";
|
|
4
5
|
import { classifyChatgptRefreshFailure } from "../codex/chatgpt-refresh-failure";
|
|
@@ -102,44 +103,20 @@ function chatGptTokenError(status: number, body: string, label: string): ChatGpt
|
|
|
102
103
|
);
|
|
103
104
|
}
|
|
104
105
|
|
|
105
|
-
|
|
106
|
+
/**
|
|
107
|
+
* The client and token decoding live in a leaf shared with the device grant.
|
|
108
|
+
* Re-exported so existing import sites keep their public helper surface.
|
|
109
|
+
*/
|
|
110
|
+
export { CHATGPT_CLIENT_ID, CHATGPT_TOKEN_URL, credsFromToken, decodeJwtPayload, extractAccountId, extractEmail };
|
|
111
|
+
const CLIENT_ID = CHATGPT_CLIENT_ID;
|
|
106
112
|
const AUTH_URL = "https://auth.openai.com/oauth/authorize";
|
|
107
|
-
const TOKEN_URL =
|
|
113
|
+
const TOKEN_URL = CHATGPT_TOKEN_URL;
|
|
108
114
|
|
|
109
|
-
/** Shared with the deviceauth grant in `./chatgpt-device`: same public PKCE client. */
|
|
110
|
-
export const CHATGPT_CLIENT_ID = CLIENT_ID;
|
|
111
|
-
export const CHATGPT_TOKEN_URL = TOKEN_URL;
|
|
112
115
|
const SCOPE = "openid profile email offline_access api.connectors.read api.connectors.invoke";
|
|
113
116
|
const CALLBACK_PORT = 1455;
|
|
114
117
|
const CALLBACK_PATH = "/auth/callback";
|
|
115
118
|
const ORIGINATOR = "opencodex";
|
|
116
119
|
|
|
117
|
-
export function decodeJwtPayload(token: string): Record<string, unknown> | undefined {
|
|
118
|
-
const parts = token.split(".");
|
|
119
|
-
if (parts.length !== 3 || !parts[1]) return undefined;
|
|
120
|
-
try {
|
|
121
|
-
return JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8")) as Record<string, unknown>;
|
|
122
|
-
} catch {
|
|
123
|
-
return undefined;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
export function extractAccountId(idToken?: string, accessToken?: string): string | undefined {
|
|
128
|
-
for (const token of [idToken, accessToken]) {
|
|
129
|
-
if (!token) continue;
|
|
130
|
-
const payload = decodeJwtPayload(token);
|
|
131
|
-
if (!payload) continue;
|
|
132
|
-
if (typeof payload.chatgpt_account_id === "string") return payload.chatgpt_account_id;
|
|
133
|
-
const ns = payload["https://api.openai.com/auth"];
|
|
134
|
-
if (ns && typeof ns === "object" && typeof (ns as Record<string, unknown>).chatgpt_account_id === "string") {
|
|
135
|
-
return (ns as Record<string, unknown>).chatgpt_account_id as string;
|
|
136
|
-
}
|
|
137
|
-
const orgs = payload.organizations;
|
|
138
|
-
if (Array.isArray(orgs) && orgs[0] && typeof orgs[0].id === "string") return orgs[0].id as string;
|
|
139
|
-
}
|
|
140
|
-
return undefined;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
120
|
/**
|
|
144
121
|
* Three-way answer to "is this token marked as belonging to the ChatGPT account domain".
|
|
145
122
|
* Only ChatGPT-specific claims count as markers: a top-level chatgpt_account_id or the
|
|
@@ -196,16 +173,6 @@ export function inspectChatGptDomainClaim(token: string): ChatGptDomainClaim {
|
|
|
196
173
|
return accountId ? { kind: "valid", accountId } : { kind: "invalid" };
|
|
197
174
|
}
|
|
198
175
|
|
|
199
|
-
export function extractEmail(idToken?: string, accessToken?: string): string | undefined {
|
|
200
|
-
for (const token of [idToken, accessToken]) {
|
|
201
|
-
if (!token) continue;
|
|
202
|
-
const payload = decodeJwtPayload(token);
|
|
203
|
-
if (!payload) continue;
|
|
204
|
-
if (typeof payload.email === "string") return payload.email.toLowerCase();
|
|
205
|
-
}
|
|
206
|
-
return undefined;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
176
|
/**
|
|
210
177
|
* Identity-agreement view of one token for security-sensitive bindings. `accountId` follows the
|
|
211
178
|
* existing extractAccountId precedence (top-level, then namespaced, then organizations[0]).
|
|
@@ -233,37 +200,6 @@ export function extractAccountIdClaims(token?: string): { accountId: string | un
|
|
|
233
200
|
};
|
|
234
201
|
}
|
|
235
202
|
|
|
236
|
-
export function credsFromToken(data: Record<string, unknown>): OAuthCredentials {
|
|
237
|
-
const idToken = typeof data.id_token === "string" ? data.id_token : undefined;
|
|
238
|
-
// This parses a response from an external boundary, so the access token is
|
|
239
|
-
// validated rather than cast. A 200 carrying no access_token would otherwise
|
|
240
|
-
// resolve a login as successful with an undefined credential, which then gets
|
|
241
|
-
// silently declined at persistence — a success message and no account.
|
|
242
|
-
const accessToken = typeof data.access_token === "string" && data.access_token.length > 0
|
|
243
|
-
? data.access_token
|
|
244
|
-
: undefined;
|
|
245
|
-
if (!accessToken) throw new Error("ChatGPT token response missing access token");
|
|
246
|
-
const refreshToken = typeof data.refresh_token === "string" ? data.refresh_token : "";
|
|
247
|
-
// ?? only guards null/undefined; NaN or a string expires_in would otherwise
|
|
248
|
-
// produce a NaN expiry that never compares as expired, and a negative duration
|
|
249
|
-
// would stamp an already-past expiry — both block refresh semantics.
|
|
250
|
-
const expiresIn =
|
|
251
|
-
typeof data.expires_in === "number" && Number.isFinite(data.expires_in) && data.expires_in >= 0
|
|
252
|
-
? data.expires_in
|
|
253
|
-
: 3600;
|
|
254
|
-
// The computed timestamp itself must stay finite: Number.MAX_VALUE passes
|
|
255
|
-
// Number.isFinite but overflows to Infinity once multiplied by 1000.
|
|
256
|
-
const computedExpires = Date.now() + expiresIn * 1000;
|
|
257
|
-
const expires = Number.isFinite(computedExpires) ? computedExpires : Date.now() + 3600 * 1000;
|
|
258
|
-
return {
|
|
259
|
-
access: accessToken,
|
|
260
|
-
refresh: refreshToken,
|
|
261
|
-
expires,
|
|
262
|
-
accountId: extractAccountId(idToken, accessToken),
|
|
263
|
-
email: extractEmail(idToken, accessToken),
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
|
|
267
203
|
export class ChatGPTOAuthFlow extends OAuthCallbackFlow {
|
|
268
204
|
#verifier = "";
|
|
269
205
|
forceLogin = false;
|
package/src/oauth/dsh.ts
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeepSeek Harness Account OAuth implementation (Import-first).
|
|
3
|
+
*
|
|
4
|
+
* Imports existing authenticated account from DeepSeek Harness Desktop
|
|
5
|
+
* (`$DSH_HOME/.credentials.yaml`, default `~/.dsh/.credentials.yaml`).
|
|
6
|
+
*
|
|
7
|
+
* Invariant: The DSH credential store is strictly READ-ONLY to OpenCodeX.
|
|
8
|
+
* OpenCodeX NEVER mutates, overwrites, deletes, or changes permissions of `~/.dsh/.credentials.yaml`.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { OAuthController, OAuthCredentials } from "./types";
|
|
12
|
+
import { homedir } from "node:os";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
15
|
+
|
|
16
|
+
export const DSH_PLATFORM_ORIGIN = "https://platform.deepseek.com";
|
|
17
|
+
export const DSH_INFERENCE_ORIGIN = "https://api.deepseek.com/anthropic";
|
|
18
|
+
|
|
19
|
+
export interface DshAccountDetectionResult {
|
|
20
|
+
detected: boolean;
|
|
21
|
+
token?: string;
|
|
22
|
+
issuer?: string;
|
|
23
|
+
error?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface DshValidatedAccountIdentity {
|
|
27
|
+
valid: boolean;
|
|
28
|
+
accountId?: string;
|
|
29
|
+
email?: string;
|
|
30
|
+
name?: string;
|
|
31
|
+
error?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function resolveDshCredentialsPath(): string {
|
|
35
|
+
const dshHome = process.env.DSH_HOME?.trim() || join(homedir(), ".dsh");
|
|
36
|
+
return join(dshHome, ".credentials.yaml");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Pure read-only probe to detect whether DeepSeek Harness Desktop is installed
|
|
41
|
+
* and signed in on this machine.
|
|
42
|
+
* NEVER writes, creates, mutates, or deletes any file.
|
|
43
|
+
*/
|
|
44
|
+
export function detectDshAccount(): DshAccountDetectionResult {
|
|
45
|
+
const filePath = resolveDshCredentialsPath();
|
|
46
|
+
if (!existsSync(filePath)) {
|
|
47
|
+
return { detected: false };
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
const content = readFileSync(filePath, "utf8");
|
|
51
|
+
const data = Bun.YAML.parse(content) as Record<string, unknown> | null;
|
|
52
|
+
if (!data || typeof data !== "object") {
|
|
53
|
+
return { detected: false };
|
|
54
|
+
}
|
|
55
|
+
const records = data.records as Record<string, unknown> | undefined;
|
|
56
|
+
const accountRecord = records?.["deepseek-account-platform/default"] as {
|
|
57
|
+
kind?: string;
|
|
58
|
+
payload?: { version?: number; token?: string; issuer?: string };
|
|
59
|
+
} | undefined;
|
|
60
|
+
|
|
61
|
+
if (accountRecord?.kind === "grant" && typeof accountRecord.payload?.token === "string" && accountRecord.payload.token.length > 0) {
|
|
62
|
+
return {
|
|
63
|
+
detected: true,
|
|
64
|
+
token: accountRecord.payload.token,
|
|
65
|
+
issuer: accountRecord.payload.issuer ?? DSH_PLATFORM_ORIGIN,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return { detected: false };
|
|
69
|
+
} catch {
|
|
70
|
+
return { detected: false, error: "CREDENTIAL_FILE_READ_FAILED" };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Validate token against DeepSeek's authoritative profile endpoint:
|
|
76
|
+
* GET https://platform.deepseek.com/auth-api/v0/users/current
|
|
77
|
+
*/
|
|
78
|
+
export async function validateDshAccountToken(
|
|
79
|
+
token: string,
|
|
80
|
+
signal?: AbortSignal,
|
|
81
|
+
): Promise<DshValidatedAccountIdentity> {
|
|
82
|
+
try {
|
|
83
|
+
const timeoutSignal = AbortSignal.timeout(10_000);
|
|
84
|
+
const combinedSignal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
|
|
85
|
+
const response = await fetch(`${DSH_PLATFORM_ORIGIN}/auth-api/v0/users/current`, {
|
|
86
|
+
method: "GET",
|
|
87
|
+
headers: {
|
|
88
|
+
"x-dsh-auth-token": token,
|
|
89
|
+
"accept": "application/json",
|
|
90
|
+
},
|
|
91
|
+
redirect: "manual",
|
|
92
|
+
signal: combinedSignal,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
if (response.status === 401) {
|
|
96
|
+
return { valid: false, error: "ACCOUNT_TOKEN_INVALID" };
|
|
97
|
+
}
|
|
98
|
+
if (!response.ok) {
|
|
99
|
+
return { valid: false, error: `Platform returned HTTP ${response.status}` };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const body = (await response.json()) as {
|
|
103
|
+
code?: number;
|
|
104
|
+
data?: {
|
|
105
|
+
biz_code?: number;
|
|
106
|
+
biz_data?: {
|
|
107
|
+
id?: string | null;
|
|
108
|
+
email?: string;
|
|
109
|
+
id_profile?: { name?: string | null; picture?: string | null };
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
if (body.code !== 0 || body.data?.biz_code !== 0 || !body.data.biz_data) {
|
|
115
|
+
return { valid: false, error: `Platform error code: ${body.code ?? "unknown"}` };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const biz = body.data.biz_data;
|
|
119
|
+
// Account-store slot matching and reauthentication require the same stable upstream ID.
|
|
120
|
+
// Email/phone/display names and a shared fallback must never identify an imported account.
|
|
121
|
+
const accountId = typeof biz.id === "string" ? biz.id.trim() : "";
|
|
122
|
+
if (!accountId) return { valid: false, error: "ACCOUNT_IDENTITY_UNVERIFIED" };
|
|
123
|
+
const email = typeof biz.email === "string" ? biz.email.trim() || undefined : undefined;
|
|
124
|
+
const name = typeof biz.id_profile?.name === "string" ? biz.id_profile.name.trim() || undefined : undefined;
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
valid: true,
|
|
128
|
+
accountId,
|
|
129
|
+
email,
|
|
130
|
+
name,
|
|
131
|
+
};
|
|
132
|
+
} catch {
|
|
133
|
+
if (signal?.aborted) throw signal.reason ?? new DOMException("DSH login aborted", "AbortError");
|
|
134
|
+
// Parser and transport errors may contain profile data or credential-file contents.
|
|
135
|
+
return { valid: false, error: "PROFILE_VALIDATION_FAILED" };
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export interface DshLoginOptions {
|
|
140
|
+
forceLogin?: boolean;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Explicit user login action for DSH Account.
|
|
145
|
+
* Reuses the existing DSH local credential after live authoritative validation.
|
|
146
|
+
*/
|
|
147
|
+
export async function loginDshAccount(
|
|
148
|
+
ctrl: OAuthController,
|
|
149
|
+
_opts: DshLoginOptions = {},
|
|
150
|
+
): Promise<OAuthCredentials> {
|
|
151
|
+
if (ctrl.signal?.aborted) {
|
|
152
|
+
throw ctrl.signal.reason ?? new DOMException("DSH login aborted", "AbortError");
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const detection = detectDshAccount();
|
|
156
|
+
if (!detection.detected || !detection.token) {
|
|
157
|
+
throw new Error(
|
|
158
|
+
"DeepSeek Harness account not found in ~/.dsh/.credentials.yaml. " +
|
|
159
|
+
"Please sign in to DeepSeek Harness Desktop first, then import your account.",
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const validation = await validateDshAccountToken(detection.token, ctrl.signal);
|
|
164
|
+
if (!validation.valid || !validation.accountId) {
|
|
165
|
+
throw new Error(
|
|
166
|
+
`DeepSeek Harness account token in ~/.dsh/.credentials.yaml is invalid or expired (${validation.error ?? "unknown"}). ` +
|
|
167
|
+
"Please re-login in DeepSeek Harness Desktop, then try again.",
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
access: detection.token,
|
|
173
|
+
refresh: detection.token,
|
|
174
|
+
expires: Number.MAX_SAFE_INTEGER,
|
|
175
|
+
accountId: validation.accountId,
|
|
176
|
+
email: validation.email,
|
|
177
|
+
source: "credential-file",
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Token refresh for DSH Account.
|
|
183
|
+
* DSH accounts use long-lived session grant tokens without an automatic rotation endpoint.
|
|
184
|
+
* In accordance with the explicit-import contract, background or automatic refresh MUST NOT
|
|
185
|
+
* automatically re-read or adopt new credentials from ~/.dsh/.credentials.yaml.
|
|
186
|
+
* If the grant is rejected or expires, this throws a terminal error so the account transitions
|
|
187
|
+
* to needsReauth, requiring explicit user re-import.
|
|
188
|
+
*/
|
|
189
|
+
export async function refreshDshAccountToken(
|
|
190
|
+
_refreshToken: string,
|
|
191
|
+
_signal?: AbortSignal,
|
|
192
|
+
_credential?: OAuthCredentials,
|
|
193
|
+
_accountId?: string,
|
|
194
|
+
): Promise<OAuthCredentials> {
|
|
195
|
+
throw new Error("DeepSeek Harness account session expired or revoked. Please sign in to DeepSeek Harness Desktop and re-import.");
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Provider-owned auth hooks keep the shared OAuth registry within its line budget. */
|
|
199
|
+
export const DSH_ACCOUNT_AUTH = {
|
|
200
|
+
login: loginDshAccount,
|
|
201
|
+
refresh: refreshDshAccountToken,
|
|
202
|
+
defaultRefreshPolicy: "disabled" as const,
|
|
203
|
+
};
|