@iislee/opencodex 2.11.0 → 2.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS_INSTALL.md +109 -0
- package/README.md +114 -19
- package/bin/ocx.mjs +164 -36
- package/bin/package-main.mjs +1 -1
- package/gui/dist/assets/index-BF38heuV.js +104 -0
- package/gui/dist/assets/index-DMiI18Kv.css +1 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/alibaba-color.svg +1 -1
- package/gui/dist/provider-icons/antigravity-color.svg +1 -1
- package/gui/dist/provider-icons/claude-color.svg +1 -1
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/commandcode-color.svg +1 -0
- package/gui/dist/provider-icons/copilot-color.svg +1 -1
- package/gui/dist/provider-icons/cursor-color.svg +1 -1
- package/gui/dist/provider-icons/deepseek-color.svg +1 -1
- package/gui/dist/provider-icons/firepass-color.svg +1 -1
- package/gui/dist/provider-icons/fireworks-color.svg +1 -1
- package/gui/dist/provider-icons/gemini-color.svg +1 -1
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
- package/gui/dist/provider-icons/grok.svg +1 -1
- package/gui/dist/provider-icons/groq-color.svg +1 -1
- package/gui/dist/provider-icons/huggingface-color.svg +1 -1
- package/gui/dist/provider-icons/kimi-color.svg +1 -1
- package/gui/dist/provider-icons/kiro-color.svg +2 -2
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
- package/gui/dist/provider-icons/mistral-color.svg +1 -1
- package/gui/dist/provider-icons/moonshot-color.svg +1 -1
- package/gui/dist/provider-icons/nvidia-color.svg +1 -1
- package/gui/dist/provider-icons/ollama-color.svg +1 -1
- package/gui/dist/provider-icons/openai.svg +1 -1
- package/gui/dist/provider-icons/opencode.svg +2 -1
- package/gui/dist/provider-icons/openrouter-color.svg +1 -1
- package/gui/dist/provider-icons/pi.svg +2 -2
- package/gui/dist/provider-icons/qianfan-color.svg +1 -1
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/vllm-color.svg +1 -1
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
- package/package.json +19 -10
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +376 -52
- package/src/adapters/base.ts +54 -7
- package/src/adapters/client-fingerprint.ts +18 -12
- package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
- package/src/adapters/command-code.ts +601 -0
- package/src/adapters/cursor/checkpoint-store.ts +303 -0
- package/src/adapters/cursor/cursor-errors.ts +129 -6
- package/src/adapters/cursor/discovery.ts +61 -4
- package/src/adapters/cursor/effort-map.ts +27 -3
- package/src/adapters/cursor/framing.ts +39 -0
- package/src/adapters/cursor/h2-pool.ts +123 -0
- package/src/adapters/cursor/http1-bidi.ts +361 -0
- package/src/adapters/cursor/images.ts +704 -0
- package/src/adapters/cursor/live-models.ts +174 -58
- package/src/adapters/cursor/live-transport.ts +609 -170
- package/src/adapters/cursor/native-exec-common.ts +23 -2
- package/src/adapters/cursor/native-exec-fs.ts +10 -7
- package/src/adapters/cursor/native-exec-network.ts +1 -1
- package/src/adapters/cursor/native-exec-shell.ts +0 -1
- package/src/adapters/cursor/native-exec.ts +101 -14
- package/src/adapters/cursor/protobuf-events.ts +829 -11
- package/src/adapters/cursor/protobuf-request.ts +383 -65
- package/src/adapters/cursor/request-builder.ts +237 -31
- package/src/adapters/cursor/tool-definitions.ts +242 -12
- package/src/adapters/cursor/tool-result-normalize.ts +92 -0
- package/src/adapters/cursor/transport.ts +22 -0
- package/src/adapters/cursor/types.ts +28 -1
- package/src/adapters/cursor.ts +133 -7
- package/src/adapters/google-antigravity-replay.ts +558 -34
- package/src/adapters/google-antigravity-wire.ts +43 -10
- package/src/adapters/google-http.ts +38 -10
- package/src/adapters/google-tool-schema.ts +80 -15
- package/src/adapters/google-truncation.ts +11 -0
- package/src/adapters/google.ts +618 -74
- package/src/adapters/identity.ts +39 -6
- package/src/adapters/kiro-errors.ts +11 -0
- package/src/adapters/kiro-events.ts +19 -1
- package/src/adapters/kiro-thinking.ts +18 -2
- package/src/adapters/kiro-tools.ts +10 -1
- package/src/adapters/kiro.ts +92 -54
- package/src/adapters/mimo-free.ts +17 -0
- package/src/adapters/openai-chat-url.ts +11 -0
- package/src/adapters/openai-chat.ts +1311 -336
- package/src/adapters/openai-responses-url.ts +16 -0
- package/src/adapters/openai-responses.ts +830 -56
- package/src/adapters/registry.ts +175 -0
- package/src/adapters/responses-tool-schema.ts +67 -0
- package/src/adapters/tool-call-id.ts +119 -0
- package/src/adapters/tool-catalog-nudge.ts +104 -21
- package/src/adapters/xai-web-search.ts +185 -0
- package/src/bridge.ts +428 -61
- package/src/chat/inbound.ts +43 -19
- package/src/chat/outbound.ts +82 -26
- package/src/claude/agents-inject.ts +32 -9
- package/src/claude/context-windows.ts +21 -5
- package/src/claude/desktop-3p.ts +243 -9
- package/src/claude/gateway-cache.ts +41 -4
- package/src/claude/inbound.ts +72 -3
- package/src/claude/model-info.ts +38 -15
- package/src/claude/outbound.ts +70 -16
- package/src/cli/account-api.ts +35 -1
- package/src/cli/account-auth.ts +33 -6
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +389 -2
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +30 -6
- package/src/cli/agent.ts +45 -1
- package/src/cli/claude-agent-startup-sync.ts +73 -0
- package/src/cli/claude-desktop.ts +29 -4
- package/src/cli/claude.ts +103 -34
- package/src/cli/codex-log-guard-doctor.ts +103 -0
- package/src/cli/codex-shim-autorestore.ts +2 -0
- package/src/cli/codex-shim-readiness.ts +76 -0
- package/src/cli/combo.ts +8 -0
- package/src/cli/config-command.ts +74 -10
- package/src/cli/dispatch.ts +593 -0
- package/src/cli/doctor.ts +315 -43
- package/src/cli/ensure-desired-integrations.ts +152 -0
- package/src/cli/export-command.ts +46 -20
- package/src/cli/help.ts +20 -271
- package/src/cli/index.ts +378 -519
- package/src/cli/init.ts +4 -17
- package/src/cli/integrations.ts +120 -2
- package/src/cli/lab.ts +607 -0
- package/src/cli/launcher-context.ts +77 -0
- package/src/cli/minimax.ts +497 -0
- package/src/cli/models-runtime.ts +35 -2
- package/src/cli/models.ts +100 -14
- package/src/cli/observe.ts +92 -3
- package/src/cli/opencode.ts +4 -2
- package/src/cli/provider-runtime.ts +18 -1
- package/src/cli/provider.ts +24 -3
- package/src/cli/ready.ts +301 -0
- package/src/cli/registry.ts +437 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +6 -3
- package/src/cli/star-prompt.ts +71 -15
- package/src/cli/status.ts +10 -3
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +153 -6
- package/src/cli/v2.ts +105 -10
- package/src/cli.ts +1 -1
- package/src/clients/config-export.ts +1358 -21
- package/src/codex/account-label.ts +14 -1
- package/src/codex/account-lifecycle.ts +130 -13
- package/src/codex/account-namespaces.ts +49 -3
- package/src/codex/account-priority.ts +83 -0
- package/src/codex/account-store.ts +29 -2
- package/src/codex/account-usability.ts +25 -2
- package/src/codex/admission.ts +256 -0
- package/src/codex/affinity-debug.ts +162 -0
- package/src/codex/app-server-processes.ts +493 -106
- package/src/codex/app-server-restart-service.ts +232 -0
- package/src/codex/auth-api.ts +849 -242
- package/src/codex/auth-collision.ts +5 -3
- package/src/codex/auth-context.ts +345 -32
- package/src/codex/autostart-health.ts +8 -1
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +68 -10
- package/src/codex/catalog/bundled.ts +331 -33
- package/src/codex/catalog/effort.ts +121 -30
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +529 -45
- package/src/codex/catalog/native-models.ts +72 -0
- package/src/codex/catalog/parsing.ts +224 -30
- package/src/codex/catalog/provider-fetch.ts +1460 -134
- package/src/codex/catalog/sync.ts +1449 -186
- package/src/codex/catalog-admission.ts +199 -0
- package/src/codex/catalog-refresh-status.ts +105 -0
- package/src/codex/catalog-write-serialization.ts +242 -0
- package/src/codex/catalog.ts +6 -3
- package/src/codex/codex-write-lock.ts +384 -0
- package/src/codex/convergence-types.ts +614 -0
- package/src/codex/convergence.ts +651 -0
- package/src/codex/coordinator-doctor.ts +332 -0
- package/src/codex/custom-model-catalog-migration.ts +176 -0
- package/src/codex/desired-state.ts +230 -0
- package/src/codex/features.ts +636 -39
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +407 -0
- package/src/codex/history-lock.ts +242 -0
- package/src/codex/history-migration-guardian.ts +26 -20
- package/src/codex/history-provider.ts +231 -28
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +220 -0
- package/src/codex/inject-coordination.ts +290 -0
- package/src/codex/inject.ts +1073 -152
- package/src/codex/injected-marker.ts +37 -3
- package/src/codex/integration-record.ts +266 -0
- package/src/codex/internal/catalog-writer.ts +203 -0
- package/src/codex/internal/history-writer.ts +80 -0
- package/src/codex/journal.ts +66 -4
- package/src/codex/log-guard/inspect.ts +506 -0
- package/src/codex/log-guard/lock.ts +150 -0
- package/src/codex/log-guard/maintenance.ts +403 -0
- package/src/codex/log-guard/path-safety.ts +88 -0
- package/src/codex/log-guard/policy.ts +44 -0
- package/src/codex/log-guard/processes.ts +205 -0
- package/src/codex/log-guard/protection.ts +489 -0
- package/src/codex/log-guard/sqlite-errors.ts +9 -0
- package/src/codex/main-account-cache.ts +24 -0
- package/src/codex/main-account.ts +29 -1
- package/src/codex/management-convergence.ts +167 -0
- package/src/codex/model-cache.ts +56 -10
- package/src/codex/model-entitlements.ts +353 -0
- package/src/codex/native-main-admission.ts +47 -0
- package/src/codex/native-main-auth-temp.ts +187 -0
- package/src/codex/native-main-claim.ts +178 -0
- package/src/codex/native-main-lock-file.ts +162 -0
- package/src/codex/native-main-owner.ts +329 -0
- package/src/codex/native-profile-api.ts +247 -0
- package/src/codex/native-profile-manager.ts +1531 -0
- package/src/codex/native-profile-processes.ts +121 -0
- package/src/codex/native-profile-recovery.ts +99 -0
- package/src/codex/native-profile-stage-store.ts +387 -0
- package/src/codex/native-profile-startup.ts +492 -0
- package/src/codex/native-profile-store.ts +855 -0
- package/src/codex/native-profile-types.ts +120 -0
- package/src/codex/native-residue.ts +682 -0
- package/src/codex/paths.ts +80 -1
- package/src/codex/plan-from-token.ts +140 -0
- package/src/codex/plan.ts +40 -0
- package/src/codex/plugins-doctor.ts +1 -1
- package/src/codex/pool-rotation.ts +74 -4
- package/src/codex/project-config-warnings.ts +20 -6
- package/src/codex/prompt-journal.ts +352 -0
- package/src/codex/prompt-layers.ts +967 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/quota-rejection.ts +298 -0
- package/src/codex/quota.ts +175 -13
- package/src/codex/refresh.ts +11 -2
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/routing.ts +505 -94
- package/src/codex/runtime.ts +159 -38
- package/src/codex/shim.ts +1009 -28
- package/src/codex/subagent-model-fallback.ts +350 -35
- package/src/codex/sync.ts +191 -2
- package/src/codex/transition-state.ts +612 -0
- package/src/codex/upstream-host-health.ts +368 -0
- package/src/codex/user-identity.ts +557 -0
- package/src/codex/warmup.ts +187 -81
- package/src/codex/write-coordination.ts +114 -0
- package/src/combos/failover.ts +20 -0
- package/src/combos/index.ts +4 -0
- package/src/combos/request.ts +32 -0
- package/src/combos/types.ts +81 -9
- package/src/config/provider-name.ts +24 -0
- package/src/config.ts +1762 -140
- package/src/generated/compatibility-version.json +3164 -0
- package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
- package/src/grok/inject.ts +16 -5
- package/src/grok/inspect.ts +45 -0
- package/src/grok/sync.ts +2 -2
- package/src/images/loop.ts +152 -29
- package/src/images/plan.ts +23 -13
- package/src/integrations/config-io.ts +269 -0
- package/src/integrations/journal.ts +315 -0
- package/src/integrations/merge.ts +135 -0
- package/src/integrations/mutation-flight.ts +71 -0
- package/src/integrations/native/ownership-preflight.ts +202 -0
- package/src/integrations/omp-yaml-source.ts +358 -0
- package/src/integrations/owned-refresh.ts +74 -0
- package/src/integrations/ownership.ts +111 -0
- package/src/integrations/registry.ts +159 -0
- package/src/integrations/serialize.ts +314 -0
- package/src/integrations/state.ts +361 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer-lock.ts +98 -0
- package/src/integrations/writer.ts +691 -0
- package/src/lab/artifacts/sanitize.ts +586 -0
- package/src/lab/artifacts/secure-fs.ts +475 -0
- package/src/lab/artifacts/store.ts +310 -0
- package/src/lab/automation/budgets.ts +78 -0
- package/src/lab/automation/config-persistence.ts +256 -0
- package/src/lab/automation/constants.ts +39 -0
- package/src/lab/automation/cooldown.ts +103 -0
- package/src/lab/automation/dispatch.ts +211 -0
- package/src/lab/automation/index.ts +13 -0
- package/src/lab/automation/orchestrator.ts +499 -0
- package/src/lab/automation/persistence.ts +512 -0
- package/src/lab/automation/planner.ts +371 -0
- package/src/lab/automation/policy.ts +136 -0
- package/src/lab/automation/queue.ts +191 -0
- package/src/lab/automation/recovery.ts +24 -0
- package/src/lab/automation/route-context.ts +21 -0
- package/src/lab/automation/run-key.ts +44 -0
- package/src/lab/automation/runs-query.ts +34 -0
- package/src/lab/automation/types.ts +160 -0
- package/src/lab/conformance/assertion.ts +325 -0
- package/src/lab/conformance/digest.ts +22 -0
- package/src/lab/conformance/executor.ts +741 -0
- package/src/lab/conformance/fixture-provider.ts +27 -0
- package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
- package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
- package/src/lab/conformance/harness-budget.ts +47 -0
- package/src/lab/conformance/index.ts +5 -0
- package/src/lab/conformance/jcs.ts +64 -0
- package/src/lab/conformance/json-pointer.ts +39 -0
- package/src/lab/conformance/manifest.ts +180 -0
- package/src/lab/conformance/mcp-stub.ts +179 -0
- package/src/lab/conformance/negative-controls.ts +164 -0
- package/src/lab/conformance/observation.ts +355 -0
- package/src/lab/conformance/runner.ts +68 -0
- package/src/lab/conformance/sse-normalize.ts +59 -0
- package/src/lab/conformance/suite-manifest.ts +78 -0
- package/src/lab/conformance/types.ts +214 -0
- package/src/lab/constants.ts +126 -0
- package/src/lab/digest.ts +64 -0
- package/src/lab/events/errors.ts +9 -0
- package/src/lab/events/limits.ts +117 -0
- package/src/lab/events/types.ts +229 -0
- package/src/lab/events/validate.ts +781 -0
- package/src/lab/fabric/constants.ts +40 -0
- package/src/lab/fabric/executor.ts +492 -0
- package/src/lab/fabric/index.ts +80 -0
- package/src/lab/fabric/manifest.ts +222 -0
- package/src/lab/fabric/observe.ts +489 -0
- package/src/lab/fabric/patch.ts +79 -0
- package/src/lab/fabric/producer-child.ts +139 -0
- package/src/lab/fabric/producer-isolate.ts +276 -0
- package/src/lab/fabric/producer-protocol.ts +61 -0
- package/src/lab/fabric/scratch.ts +439 -0
- package/src/lab/fabric/subject.ts +106 -0
- package/src/lab/fabric/types.ts +134 -0
- package/src/lab/fabric/verifier.ts +98 -0
- package/src/lab/index.ts +54 -0
- package/src/lab/ledger/artifact-refs.ts +127 -0
- package/src/lab/ledger/invalidation.ts +136 -0
- package/src/lab/ledger/purge.ts +310 -0
- package/src/lab/ledger/store.ts +532 -0
- package/src/lab/live/credential-lease.ts +53 -0
- package/src/lab/live/destination.ts +155 -0
- package/src/lab/live/executor.ts +336 -0
- package/src/lab/live/inert-tools.ts +56 -0
- package/src/lab/live/manifest.ts +85 -0
- package/src/lab/live/mcp-loopback.ts +57 -0
- package/src/lab/live/runner.ts +19 -0
- package/src/lab/live/sandbox.ts +61 -0
- package/src/lab/live/suite-manifest.ts +41 -0
- package/src/lab/live/transport.ts +118 -0
- package/src/lab/live/types.ts +197 -0
- package/src/lab/observe/from-conformance.ts +301 -0
- package/src/lab/observe/from-live.ts +117 -0
- package/src/lab/paths.ts +153 -0
- package/src/lab/projection/rebuild.ts +495 -0
- package/src/lab/projection/schema.ts +135 -0
- package/src/lab/projection/verdicts.ts +474 -0
- package/src/lab/projection/verification.ts +412 -0
- package/src/lab/public/bundle.ts +217 -0
- package/src/lab/public/community-authority.ts +175 -0
- package/src/lab/public/community-files.ts +29 -0
- package/src/lab/public/community.ts +479 -0
- package/src/lab/public/file-safety.ts +155 -0
- package/src/lab/public/ids.ts +26 -0
- package/src/lab/public/index.ts +16 -0
- package/src/lab/public/mutation-lock.ts +424 -0
- package/src/lab/public/operator.ts +353 -0
- package/src/lab/public/origin-purge.ts +79 -0
- package/src/lab/public/origin.ts +203 -0
- package/src/lab/public/privacy.ts +143 -0
- package/src/lab/public/private-file.ts +261 -0
- package/src/lab/public/project.ts +124 -0
- package/src/lab/public/purge-test-fault.ts +21 -0
- package/src/lab/public/purge.ts +223 -0
- package/src/lab/public/registry.ts +44 -0
- package/src/lab/public/revocation.ts +252 -0
- package/src/lab/public/signature.ts +243 -0
- package/src/lab/public/storage.ts +105 -0
- package/src/lab/public/strict-json.ts +206 -0
- package/src/lab/public/time.ts +26 -0
- package/src/lab/public/types.ts +172 -0
- package/src/lab/public/validate.ts +391 -0
- package/src/lab/query/catalog.ts +101 -0
- package/src/lab/query/connection.ts +107 -0
- package/src/lab/query/constants.ts +4 -0
- package/src/lab/query/cursor.ts +132 -0
- package/src/lab/query/dto-map.ts +277 -0
- package/src/lab/query/errors.ts +22 -0
- package/src/lab/query/freshness.ts +53 -0
- package/src/lab/query/index.ts +45 -0
- package/src/lab/query/latest-observation.ts +59 -0
- package/src/lab/query/passive-production.ts +159 -0
- package/src/lab/query/queries.ts +444 -0
- package/src/lab/query/types.ts +266 -0
- package/src/lab/subject/behavior-fingerprint.ts +77 -0
- package/src/lab/subject/installation-salt.ts +112 -0
- package/src/lab/subject/protocol-subject.ts +80 -0
- package/src/lab/subject/route-subject.ts +74 -0
- package/src/lib/app-owned-memory-stores.ts +22 -0
- package/src/lib/bounded-body.ts +153 -9
- package/src/lib/bun-runtime.ts +125 -12
- package/src/lib/bun-stream-caps.ts +13 -9
- package/src/lib/codex-restart-contract.ts +120 -0
- package/src/lib/config-ownership.ts +6 -2
- package/src/lib/destination-policy.ts +65 -1
- package/src/lib/errors.ts +44 -2
- package/src/lib/fabric-task-execution-authority.ts +7 -0
- package/src/lib/fabric-task-host.ts +29 -0
- package/src/lib/lab-activation.ts +223 -0
- package/src/lib/lab-live-execution-authority.ts +13 -0
- package/src/lib/lab-live-host.ts +30 -0
- package/src/lib/lab-live-pinned-sender.ts +56 -0
- package/src/lib/lab-live-route-production.ts +130 -0
- package/src/lib/lab-passive-linker-registration.ts +26 -0
- package/src/lib/local-management-attestation.ts +51 -0
- package/src/lib/local-management-capability.ts +100 -0
- package/src/lib/local-provider-reload-contract.ts +100 -0
- package/src/lib/optional-shutdown-hooks.ts +57 -0
- package/src/lib/pinned-http.ts +145 -26
- package/src/lib/process-control.ts +4 -1
- package/src/lib/provider-outbound.ts +49 -9
- package/src/lib/redact.ts +419 -3
- package/src/lib/self-launch-argv.ts +15 -0
- package/src/lib/server-resource-ownership.ts +71 -0
- package/src/lib/shadow-call.ts +35 -4
- package/src/lib/sse-decoder.ts +41 -0
- package/src/lib/state-store-registrations.ts +10 -2
- package/src/lib/system-restart-contract.ts +73 -0
- package/src/lib/token-estimate.ts +19 -2
- package/src/lib/tool-argument-integers.ts +202 -0
- package/src/lib/translator-budget.ts +44 -0
- package/src/lib/upstream-http-version.ts +57 -0
- package/src/lib/upstream-reachability.ts +95 -0
- package/src/lib/upstream-retry.ts +156 -3
- package/src/lib/windows-atomic-replace.ts +155 -0
- package/src/lib/windows-elevation.ts +70 -2
- package/src/lib/windows-secret-acl.ts +409 -69
- package/src/lib/windows-service-wrappers.ts +72 -0
- package/src/lib/windows-text.ts +106 -0
- package/src/lib/windows-user-principal.ts +341 -0
- package/src/lib/winsw.ts +33 -5
- package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
- package/src/oauth/account-import/index.ts +15 -0
- package/src/oauth/account-import/parser.ts +83 -0
- package/src/oauth/account-import/registry.ts +18 -0
- package/src/oauth/account-import/service.ts +75 -0
- package/src/oauth/account-import/types.ts +91 -0
- package/src/oauth/anthropic.ts +12 -1
- package/src/oauth/callback-server.ts +8 -2
- package/src/oauth/chatgpt.ts +12 -1
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +46 -5
- package/src/oauth/google-antigravity.ts +35 -3
- package/src/oauth/health.ts +20 -12
- package/src/oauth/index.ts +398 -66
- package/src/oauth/key-providers.ts +16 -0
- package/src/oauth/kimi.ts +16 -2
- package/src/oauth/kiro.ts +50 -6
- package/src/oauth/local-token-detect.ts +11 -2
- package/src/oauth/log.ts +3 -1
- package/src/oauth/login-cli.ts +88 -28
- package/src/oauth/nous.ts +798 -0
- package/src/oauth/store.ts +119 -21
- package/src/oauth/token-guardian.ts +9 -3
- package/src/pi/models.ts +2 -2
- package/src/providers/alibaba-region-migration.ts +1 -1
- package/src/providers/antigravity-models.ts +521 -31
- package/src/providers/base-url-choices.ts +10 -0
- package/src/providers/codex-capacity.ts +292 -0
- package/src/providers/command-code-efforts.ts +144 -0
- package/src/providers/context-cap.ts +22 -5
- package/src/providers/cursor-pool.ts +72 -0
- package/src/providers/derive.ts +253 -6
- package/src/providers/fastwire.ts +501 -0
- package/src/providers/free-directory.ts +10 -7
- package/src/providers/google-vertex-location.ts +14 -0
- package/src/providers/key-failover.ts +71 -3
- package/src/providers/label.ts +1 -1
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +115 -22
- package/src/providers/model-rename-migration.ts +255 -0
- package/src/providers/model-rename-startup.ts +28 -0
- package/src/providers/openai-sidecar.ts +72 -4
- package/src/providers/openai-tier-startup.ts +31 -2
- package/src/providers/openai-tiers.ts +119 -4
- package/src/providers/openai-virtual-models.ts +1 -0
- package/src/providers/opencode-zen-rate-limit.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +29 -0
- package/src/providers/quota.ts +1319 -38
- package/src/providers/registry.ts +1429 -111
- package/src/providers/request-pacing.ts +310 -0
- package/src/providers/service-tier.ts +277 -0
- package/src/providers/slug-codec.ts +42 -6
- package/src/providers/static-model-discovery.ts +86 -0
- package/src/providers/xai-responses-opt-in.ts +15 -0
- package/src/providers/xai-transport.ts +11 -4
- package/src/reasoning-effort.ts +49 -1
- package/src/responses/compaction.ts +26 -1
- package/src/responses/custom-tool-compat.ts +266 -0
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/namespace-tool-compat.ts +355 -0
- package/src/responses/parser.ts +220 -38
- package/src/responses/provider-continuation.ts +98 -0
- package/src/responses/provider-opaque-metadata.ts +73 -0
- package/src/responses/reasoning-envelope.ts +9 -1
- package/src/responses/reasoning-replay-cache.ts +426 -0
- package/src/responses/schema.ts +7 -1
- package/src/responses/spill-store.ts +75 -10
- package/src/responses/state.ts +565 -27
- package/src/responses/thought-signature-replay.ts +347 -0
- package/src/responses/tool-search-compat.ts +301 -0
- package/src/responses/truncated-stop-reason.ts +60 -0
- package/src/router.ts +366 -30
- package/src/routing/analytics.ts +378 -0
- package/src/routing/capability.ts +244 -0
- package/src/routing/compatibility/assemble.ts +73 -0
- package/src/routing/compatibility/behavior.ts +278 -0
- package/src/routing/compatibility/catalog.ts +99 -0
- package/src/routing/compatibility/endpoint.ts +52 -0
- package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
- package/src/routing/compatibility/policy.ts +181 -0
- package/src/routing/compatibility/provider-slot.ts +56 -0
- package/src/routing/compatibility/reader.ts +110 -0
- package/src/routing/compatibility/subject.ts +191 -0
- package/src/routing/compatibility/types.ts +64 -0
- package/src/routing/compatibility/version.ts +104 -0
- package/src/routing/cost.ts +77 -0
- package/src/routing/evaluator.ts +495 -0
- package/src/routing/health.ts +412 -0
- package/src/routing/history/cursor.ts +43 -0
- package/src/routing/history/indexer.ts +605 -0
- package/src/routing/history/schema.ts +72 -0
- package/src/routing/profile-namespace.ts +15 -0
- package/src/routing/profile.ts +547 -0
- package/src/routing/quota.ts +145 -0
- package/src/routing/request-evidence.ts +45 -0
- package/src/routing/trace.ts +776 -0
- package/src/server/adapter-resolve.ts +2 -29
- package/src/server/auth-cors.ts +267 -46
- package/src/server/background-lifecycle.ts +182 -0
- package/src/server/chat-completions.ts +130 -56
- package/src/server/chat-native-sse.ts +331 -0
- package/src/server/chat-native.ts +426 -0
- package/src/server/claude-messages.ts +159 -43
- package/src/server/direct-local-http.ts +347 -0
- package/src/server/effort-policy.ts +18 -0
- package/src/server/github-copilot-responses-repair.ts +338 -0
- package/src/server/gui-static.ts +39 -10
- package/src/server/images.ts +94 -12
- package/src/server/index.ts +865 -181
- package/src/server/lifecycle.ts +284 -13
- package/src/server/live.ts +136 -17
- package/src/server/local-management-read-client.ts +90 -0
- package/src/server/local-provider-reload-client.ts +137 -0
- package/src/server/management/agent-settings-routes.ts +398 -103
- package/src/server/management/api-key-usage.ts +31 -5
- package/src/server/management/body.ts +6 -0
- package/src/server/management/combo-routes.ts +62 -24
- package/src/server/management/config-routes.ts +464 -51
- package/src/server/management/context.ts +80 -2
- package/src/server/management/integration-routes.ts +498 -0
- package/src/server/management/lab-automation-routes.ts +206 -0
- package/src/server/management/lab-routes.ts +563 -0
- package/src/server/management/logs-usage-routes.ts +101 -32
- package/src/server/management/model-routes.ts +189 -131
- package/src/server/management/model-rows.ts +163 -0
- package/src/server/management/native-integration-routes.ts +769 -0
- package/src/server/management/oauth-account-routes.ts +80 -4
- package/src/server/management/provider-capability-config.ts +48 -0
- package/src/server/management/provider-routes.ts +764 -157
- package/src/server/management/request-history-routes.ts +191 -0
- package/src/server/management/routing-analytics-routes.ts +74 -0
- package/src/server/management/routing-profile-routes.ts +380 -0
- package/src/server/management/shared.ts +27 -11
- package/src/server/management/sidebar-routes.ts +47 -31
- package/src/server/management/storage-log-guard-routes.ts +186 -0
- package/src/server/management/sync-response.ts +69 -0
- package/src/server/management/system-restart.ts +288 -32
- package/src/server/management/system-routes.ts +77 -0
- package/src/server/management/usage-summary-cache.ts +9 -1
- package/src/server/management/vision-sidecar-options.ts +167 -0
- package/src/server/management/web-search-sidecar-options.ts +120 -0
- package/src/server/management-api.ts +115 -14
- package/src/server/management-auth.ts +220 -5
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/ports.ts +41 -1
- package/src/server/proxy-liveness.ts +132 -5
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +82 -42
- package/src/server/relay.ts +236 -76
- package/src/server/request-decompress.ts +113 -6
- package/src/server/request-log.ts +235 -22
- package/src/server/responses/agent-task-recovery-cache.ts +143 -0
- package/src/server/responses/agent-task-recovery.ts +465 -0
- package/src/server/responses/collaboration.ts +204 -35
- package/src/server/responses/compact.ts +442 -55
- package/src/server/responses/core.ts +2872 -331
- package/src/server/responses/empty-completion-guard.ts +276 -0
- package/src/server/responses/encrypted-payload.ts +62 -39
- package/src/server/responses/fetch-helpers.ts +79 -4
- package/src/server/responses/input-admission.ts +185 -0
- package/src/server/responses/pacing-overload.ts +13 -0
- package/src/server/responses/policy-fallback.ts +178 -0
- package/src/server/responses/responses-field-backfill.ts +251 -0
- package/src/server/responses/terminal-guard.ts +26 -5
- package/src/server/responses/upstream-error.ts +5 -0
- package/src/server/responses/ws-upstream.ts +308 -0
- package/src/server/responses-custom-tool-repair.ts +282 -0
- package/src/server/responses-item-id-repair.ts +54 -6
- package/src/server/responses-json-events.ts +90 -0
- package/src/server/responses-model-rewrite.ts +29 -0
- package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
- package/src/server/responses-snapshot-repair.ts +621 -0
- package/src/server/responses-terminal-repair.ts +342 -0
- package/src/server/responses-tool-search-repair.ts +267 -0
- package/src/server/responses-undeclared-tool-guard.ts +153 -0
- package/src/server/responses.ts +18 -2
- package/src/server/search.ts +78 -13
- package/src/server/sse-frame-buffer.ts +292 -0
- package/src/server/sse-payload-rewrite.ts +110 -22
- package/src/server/startup-action-control.ts +8 -1
- package/src/server/startup-health-cache.ts +19 -1
- package/src/server/system-env.ts +80 -9
- package/src/server/ws-bridge.ts +39 -38
- package/src/service-manager-probe.ts +892 -0
- package/src/service.ts +1111 -90
- package/src/sidecar/auth.ts +92 -0
- package/src/sidecar/candidates.ts +83 -0
- package/src/storage/cleanup.ts +2 -2
- package/src/storage/scanner.ts +1 -1
- package/src/storage/worker-lifecycle.ts +14 -14
- package/src/tray/windows-tray.ps1 +83 -9
- package/src/tray/windows.ts +43 -16
- package/src/types/accounts.ts +37 -0
- package/src/types/config.ts +845 -0
- package/src/types/provider.ts +545 -0
- package/src/types/request.ts +384 -0
- package/src/types/tools.ts +131 -0
- package/src/types/wire.ts +80 -0
- package/src/types.ts +104 -1236
- package/src/update/index.ts +32 -19
- package/src/update/job.ts +442 -67
- package/src/update/notify.ts +12 -6
- package/src/update/npm-cache-preflight.d.mts +47 -0
- package/src/update/npm-cache-preflight.mjs +201 -0
- package/src/update/transactional-install.d.mts +22 -0
- package/src/update/transactional-install.mjs +259 -0
- package/src/usage/cost.ts +0 -0
- package/src/usage/expected-prices.ts +268 -16
- package/src/usage/log.ts +606 -41
- package/src/usage/summary.ts +177 -9
- package/src/usage/user-cost-overlay-reconciler.ts +313 -0
- package/src/usage/user-cost-overlays.ts +314 -0
- package/src/vision/anthropic-describe.ts +10 -6
- package/src/vision/backends.ts +97 -0
- package/src/vision/describe.ts +9 -3
- package/src/vision/eligibility.ts +250 -0
- package/src/vision/index.ts +238 -24
- package/src/vision/reasoning.ts +55 -0
- package/src/vision/routed-describe.ts +175 -0
- package/src/vision/timeout-bounds.ts +9 -0
- package/src/web-search/anthropic-executor.ts +13 -7
- package/src/web-search/backends.ts +108 -0
- package/src/web-search/exa-executor.ts +88 -0
- package/src/web-search/executor.ts +11 -3
- package/src/web-search/gemini-executor.ts +141 -0
- package/src/web-search/index.ts +150 -15
- package/src/web-search/loop.ts +279 -50
- package/src/web-search/parse.ts +125 -30
- package/src/web-search/sources.ts +60 -0
- package/src/web-search/xai-executor.ts +219 -0
- package/gui/dist/assets/index-DTpMHS4F.js +0 -67
- package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
- package/gui/dist/provider-icons/antigravity.svg +0 -1
- package/gui/dist/provider-icons/claude.svg +0 -1
- package/gui/dist/provider-icons/copilot.svg +0 -1
- package/gui/dist/provider-icons/cursor.svg +0 -2
- package/gui/dist/provider-icons/gemini.svg +0 -1
- package/gui/dist/provider-icons/grok-color.svg +0 -1
- package/gui/dist/provider-icons/kiro.svg +0 -14
- package/src/cli/internal-dispatch.ts +0 -20
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { importAccounts } from "./service";
|
|
2
|
+
export {
|
|
3
|
+
ACCOUNT_IMPORT_DEADLINE_MS,
|
|
4
|
+
ACCOUNT_IMPORT_FORMAT,
|
|
5
|
+
ACCOUNT_IMPORT_MAX_BYTES,
|
|
6
|
+
ACCOUNT_IMPORT_MAX_REQUEST_BYTES,
|
|
7
|
+
ACCOUNT_IMPORT_PROVIDER,
|
|
8
|
+
} from "./types";
|
|
9
|
+
export type {
|
|
10
|
+
AccountImportCode,
|
|
11
|
+
AccountImportRecordResult,
|
|
12
|
+
AccountImportRequest,
|
|
13
|
+
AccountImportResult,
|
|
14
|
+
AccountImportStatus,
|
|
15
|
+
} from "./types";
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ACCOUNT_IMPORT_MAX_BYTES,
|
|
3
|
+
ACCOUNT_IMPORT_MAX_EMAIL_LENGTH,
|
|
4
|
+
ACCOUNT_IMPORT_MAX_RECORDS,
|
|
5
|
+
ACCOUNT_IMPORT_MAX_REFRESH_TOKEN_BYTES,
|
|
6
|
+
type ParsedCockpitRecord,
|
|
7
|
+
} from "./types";
|
|
8
|
+
|
|
9
|
+
const encoder = new TextEncoder();
|
|
10
|
+
const ALLOWED_RECORD_KEYS = new Set(["email", "refresh_token", "tags", "notes"]);
|
|
11
|
+
|
|
12
|
+
export type CockpitDocumentParseResult =
|
|
13
|
+
| { ok: true; records: ParsedCockpitRecord[] }
|
|
14
|
+
| { ok: false; code: "invalid_document" };
|
|
15
|
+
|
|
16
|
+
function isPlainRecord(value: unknown): value is Record<string, unknown> {
|
|
17
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
18
|
+
const prototype = Object.getPrototypeOf(value);
|
|
19
|
+
return prototype === Object.prototype || prototype === null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function serializedDocumentSize(document: unknown): number | null {
|
|
23
|
+
try {
|
|
24
|
+
const serialized = JSON.stringify(document);
|
|
25
|
+
return serialized === undefined ? null : encoder.encode(serialized).byteLength;
|
|
26
|
+
} catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function validEmail(value: unknown): value is string {
|
|
32
|
+
if (typeof value !== "string" || value.length === 0 || value.length > ACCOUNT_IMPORT_MAX_EMAIL_LENGTH) return false;
|
|
33
|
+
if (value !== value.trim() || /[\x00-\x20\x7f]/.test(value)) return false;
|
|
34
|
+
const at = value.indexOf("@");
|
|
35
|
+
return at > 0 && at === value.lastIndexOf("@") && at < value.length - 1;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function validRefreshToken(value: unknown): value is string {
|
|
39
|
+
return typeof value === "string"
|
|
40
|
+
&& value.length > 0
|
|
41
|
+
&& encoder.encode(value).byteLength <= ACCOUNT_IMPORT_MAX_REFRESH_TOKEN_BYTES
|
|
42
|
+
&& !/[\s\x7f]/.test(value);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function validMetadata(record: Record<string, unknown>): boolean {
|
|
46
|
+
if (record.tags !== undefined && (
|
|
47
|
+
!Array.isArray(record.tags)
|
|
48
|
+
|| record.tags.some(tag => typeof tag !== "string")
|
|
49
|
+
)) return false;
|
|
50
|
+
return record.notes === undefined || typeof record.notes === "string";
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function parseRecord(value: unknown, index: number): ParsedCockpitRecord {
|
|
54
|
+
if (!isPlainRecord(value)) return { index, code: "invalid_record" };
|
|
55
|
+
if (Object.keys(value).some(key => !ALLOWED_RECORD_KEYS.has(key))) return { index, code: "invalid_record" };
|
|
56
|
+
if (!validEmail(value.email) || !validRefreshToken(value.refresh_token) || !validMetadata(value)) {
|
|
57
|
+
return { index, code: "invalid_record" };
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
index,
|
|
61
|
+
record: {
|
|
62
|
+
email: value.email.toLowerCase(),
|
|
63
|
+
refreshToken: value.refresh_token,
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function parseCockpitAccountDocument(document: unknown): CockpitDocumentParseResult {
|
|
69
|
+
const size = serializedDocumentSize(document);
|
|
70
|
+
if (size === null || size > ACCOUNT_IMPORT_MAX_BYTES) return { ok: false, code: "invalid_document" };
|
|
71
|
+
if (!Array.isArray(document) || document.length === 0 || document.length > ACCOUNT_IMPORT_MAX_RECORDS) {
|
|
72
|
+
return { ok: false, code: "invalid_document" };
|
|
73
|
+
}
|
|
74
|
+
const seen = new Set<string>();
|
|
75
|
+
const records = document.map((value, index): ParsedCockpitRecord => {
|
|
76
|
+
const parsed = parseRecord(value, index);
|
|
77
|
+
if ("code" in parsed) return parsed;
|
|
78
|
+
if (seen.has(parsed.record.email)) return { index, code: "invalid_record" };
|
|
79
|
+
seen.add(parsed.record.email);
|
|
80
|
+
return parsed;
|
|
81
|
+
});
|
|
82
|
+
return { ok: true, records };
|
|
83
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createAntigravityAccountImportAdapter } from "./google-antigravity-adapter";
|
|
2
|
+
import {
|
|
3
|
+
ACCOUNT_IMPORT_FORMAT,
|
|
4
|
+
ACCOUNT_IMPORT_PROVIDER,
|
|
5
|
+
type AccountImportAdapter,
|
|
6
|
+
} from "./types";
|
|
7
|
+
|
|
8
|
+
export type AccountImportRegistryResult =
|
|
9
|
+
| { ok: true; adapter: AccountImportAdapter }
|
|
10
|
+
| { ok: false; code: "unsupported_provider" | "unsupported_format" };
|
|
11
|
+
|
|
12
|
+
const antigravityAdapter = createAntigravityAccountImportAdapter();
|
|
13
|
+
|
|
14
|
+
export function resolveAccountImportAdapter(provider: string, format: string): AccountImportRegistryResult {
|
|
15
|
+
if (provider !== ACCOUNT_IMPORT_PROVIDER) return { ok: false, code: "unsupported_provider" };
|
|
16
|
+
if (format !== ACCOUNT_IMPORT_FORMAT) return { ok: false, code: "unsupported_format" };
|
|
17
|
+
return { ok: true, adapter: antigravityAdapter };
|
|
18
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { parseCockpitAccountDocument } from "./parser";
|
|
2
|
+
import { resolveAccountImportAdapter, type AccountImportRegistryResult } from "./registry";
|
|
3
|
+
import {
|
|
4
|
+
AccountImportAbortError,
|
|
5
|
+
throwIfAccountImportAborted,
|
|
6
|
+
} from "./types";
|
|
7
|
+
import type {
|
|
8
|
+
AccountImportRequest,
|
|
9
|
+
AccountImportResult,
|
|
10
|
+
AccountImportRecordResult,
|
|
11
|
+
} from "./types";
|
|
12
|
+
|
|
13
|
+
export type AccountImportServiceResult =
|
|
14
|
+
| { ok: true; result: AccountImportResult }
|
|
15
|
+
| {
|
|
16
|
+
ok: false;
|
|
17
|
+
status: 400 | 408;
|
|
18
|
+
code: "unsupported_provider" | "unsupported_format" | "invalid_document" | "import_cancelled";
|
|
19
|
+
/** True when at least one credential was committed before the terminal failure. */
|
|
20
|
+
changed?: boolean;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export interface AccountImportServiceDeps {
|
|
24
|
+
resolveAdapter(provider: string, format: string): AccountImportRegistryResult;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function importAccounts(
|
|
28
|
+
request: AccountImportRequest,
|
|
29
|
+
deps: AccountImportServiceDeps = { resolveAdapter: resolveAccountImportAdapter },
|
|
30
|
+
): Promise<AccountImportServiceResult> {
|
|
31
|
+
// Provider/format admission intentionally precedes any traversal or serialization of the
|
|
32
|
+
// credential-bearing document.
|
|
33
|
+
const resolved = deps.resolveAdapter(request.provider, request.format);
|
|
34
|
+
if (!resolved.ok) return { ok: false, status: 400, code: resolved.code };
|
|
35
|
+
|
|
36
|
+
const parsed = parseCockpitAccountDocument(request.document);
|
|
37
|
+
if (!parsed.ok) return { ok: false, status: 400, code: parsed.code };
|
|
38
|
+
|
|
39
|
+
const results: AccountImportRecordResult[] = [];
|
|
40
|
+
try {
|
|
41
|
+
for (const item of parsed.records) {
|
|
42
|
+
throwIfAccountImportAborted(request.signal);
|
|
43
|
+
if ("code" in item) {
|
|
44
|
+
results.push({ index: item.index, status: "failed", code: item.code });
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const outcome = await resolved.adapter.importRecord(item.record, request.signal);
|
|
48
|
+
results.push({ index: item.index, ...outcome });
|
|
49
|
+
// Record the committed outcome before observing cancellation. The route uses this
|
|
50
|
+
// internal signal to reconcile live stores and caches even when the public response
|
|
51
|
+
// is the terminal 408 DTO.
|
|
52
|
+
throwIfAccountImportAborted(request.signal);
|
|
53
|
+
}
|
|
54
|
+
} catch (error) {
|
|
55
|
+
if (error instanceof AccountImportAbortError) {
|
|
56
|
+
const changed = results.some(result => result.status === "imported" || result.status === "updated");
|
|
57
|
+
return { ok: false, status: 408, code: "import_cancelled", ...(changed ? { changed: true } : {}) };
|
|
58
|
+
}
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const count = (status: AccountImportRecordResult["status"]) =>
|
|
63
|
+
results.filter(result => result.status === status).length;
|
|
64
|
+
return {
|
|
65
|
+
ok: true,
|
|
66
|
+
result: {
|
|
67
|
+
totalCount: results.length,
|
|
68
|
+
importedCount: count("imported"),
|
|
69
|
+
updatedCount: count("updated"),
|
|
70
|
+
failedCount: count("failed"),
|
|
71
|
+
unsupportedCount: count("unsupported"),
|
|
72
|
+
results,
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { OAuthCredentials } from "../types";
|
|
2
|
+
|
|
3
|
+
export const ACCOUNT_IMPORT_PROVIDER = "google-antigravity" as const;
|
|
4
|
+
export const ACCOUNT_IMPORT_FORMAT = "cockpit-tools" as const;
|
|
5
|
+
export const ACCOUNT_IMPORT_MAX_BYTES = 256 * 1024;
|
|
6
|
+
// The HTTP request also carries the fixed provider/format envelope. Keep that envelope bounded
|
|
7
|
+
// without making a valid document at the 256 KiB contract boundary fail at the API layer.
|
|
8
|
+
export const ACCOUNT_IMPORT_MAX_REQUEST_BYTES = ACCOUNT_IMPORT_MAX_BYTES + 1024;
|
|
9
|
+
// Shared CLI POST timeout and management-route deadline. Individual provider requests keep
|
|
10
|
+
// shorter timeouts; this bounds the full admitted batch (up to ACCOUNT_IMPORT_MAX_RECORDS).
|
|
11
|
+
export const ACCOUNT_IMPORT_DEADLINE_MS = 600_000;
|
|
12
|
+
export const ACCOUNT_IMPORT_MAX_RECORDS = 25;
|
|
13
|
+
export const ACCOUNT_IMPORT_MAX_EMAIL_LENGTH = 254;
|
|
14
|
+
export const ACCOUNT_IMPORT_MAX_REFRESH_TOKEN_BYTES = 16 * 1024;
|
|
15
|
+
|
|
16
|
+
export type AccountImportStatus = "imported" | "updated" | "failed" | "unsupported";
|
|
17
|
+
|
|
18
|
+
export type AccountImportCode =
|
|
19
|
+
| "imported"
|
|
20
|
+
| "updated"
|
|
21
|
+
| "import_cancelled"
|
|
22
|
+
| "unsupported_provider"
|
|
23
|
+
| "unsupported_format"
|
|
24
|
+
| "invalid_document"
|
|
25
|
+
| "invalid_record"
|
|
26
|
+
| "credential_rejected"
|
|
27
|
+
| "identity_mismatch"
|
|
28
|
+
| "missing_project"
|
|
29
|
+
| "persist_failed";
|
|
30
|
+
|
|
31
|
+
export interface AccountImportRecordResult {
|
|
32
|
+
index: number;
|
|
33
|
+
status: AccountImportStatus;
|
|
34
|
+
code: AccountImportCode;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface AccountImportResult {
|
|
38
|
+
totalCount: number;
|
|
39
|
+
importedCount: number;
|
|
40
|
+
updatedCount: number;
|
|
41
|
+
failedCount: number;
|
|
42
|
+
unsupportedCount: number;
|
|
43
|
+
results: AccountImportRecordResult[];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface AccountImportRequest {
|
|
47
|
+
provider: string;
|
|
48
|
+
format: string;
|
|
49
|
+
document: unknown;
|
|
50
|
+
signal?: AbortSignal;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** A secret-free terminal signal for a cancelled import request. */
|
|
54
|
+
export class AccountImportAbortError extends Error {
|
|
55
|
+
constructor() {
|
|
56
|
+
super("Account import cancelled");
|
|
57
|
+
this.name = "AccountImportAbortError";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function throwIfAccountImportAborted(signal?: AbortSignal): void {
|
|
62
|
+
if (signal?.aborted) throw new AccountImportAbortError();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface CockpitAccountRecord {
|
|
66
|
+
email: string;
|
|
67
|
+
refreshToken: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export type ParsedCockpitRecord =
|
|
71
|
+
| { index: number; record: CockpitAccountRecord }
|
|
72
|
+
| { index: number; code: "invalid_record" };
|
|
73
|
+
|
|
74
|
+
export type AccountImportRecordOutcome =
|
|
75
|
+
| { status: "imported"; code: "imported" }
|
|
76
|
+
| { status: "updated"; code: "updated" }
|
|
77
|
+
| {
|
|
78
|
+
status: "failed";
|
|
79
|
+
code: "credential_rejected" | "identity_mismatch" | "missing_project" | "persist_failed";
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export interface AccountImportAdapter {
|
|
83
|
+
readonly provider: typeof ACCOUNT_IMPORT_PROVIDER;
|
|
84
|
+
readonly format: typeof ACCOUNT_IMPORT_FORMAT;
|
|
85
|
+
importRecord(record: CockpitAccountRecord, signal?: AbortSignal): Promise<AccountImportRecordOutcome>;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface ValidatedAntigravityCredential extends OAuthCredentials {
|
|
89
|
+
email?: string;
|
|
90
|
+
projectId?: string;
|
|
91
|
+
}
|
package/src/oauth/anthropic.ts
CHANGED
|
@@ -81,10 +81,21 @@ function parseTokenResponse(responseBody: string): AnthropicTokenResponse {
|
|
|
81
81
|
function credsFrom(data: AnthropicTokenResponse, refreshFallback?: string): OAuthCredentials {
|
|
82
82
|
const accountUuid = data.account?.uuid;
|
|
83
83
|
const email = data.account?.email_address;
|
|
84
|
+
// Guard against a missing/non-finite/negative expires_in (malformed upstream
|
|
85
|
+
// response): a NaN expiry would never compare as expired, and a negative
|
|
86
|
+
// duration would stamp an already-past expiry — both block refresh semantics.
|
|
87
|
+
const expiresIn =
|
|
88
|
+
typeof data.expires_in === "number" && Number.isFinite(data.expires_in) && data.expires_in >= 0
|
|
89
|
+
? data.expires_in
|
|
90
|
+
: 3600;
|
|
91
|
+
// The computed timestamp itself must stay finite: Number.MAX_VALUE passes
|
|
92
|
+
// Number.isFinite but overflows to Infinity once multiplied by 1000.
|
|
93
|
+
const computedExpires = Date.now() + expiresIn * 1000 - 5 * 60 * 1000;
|
|
94
|
+
const expires = Number.isFinite(computedExpires) ? computedExpires : Date.now() + 3600 * 1000 - 5 * 60 * 1000;
|
|
84
95
|
return {
|
|
85
96
|
refresh: data.refresh_token || refreshFallback || "",
|
|
86
97
|
access: data.access_token,
|
|
87
|
-
expires
|
|
98
|
+
expires,
|
|
88
99
|
accountId: typeof accountUuid === "string" && accountUuid.length > 0 ? accountUuid : undefined,
|
|
89
100
|
email: typeof email === "string" && email.length > 0 ? email : undefined,
|
|
90
101
|
};
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Change vs source: the success/error page is an inline HTML constant. opencodex's GUI polls
|
|
6
6
|
* GET /api/oauth/status, so it does not need OAuth state injected into the callback page.
|
|
7
7
|
*
|
|
8
|
-
* Handles: port allocation (preferred → random fallback), callback server, CSRF state,
|
|
8
|
+
* Handles: port allocation (preferred → random/manual-only fallback), callback server, CSRF state,
|
|
9
9
|
* manual-input race, 300s timeout. Providers implement generateAuthUrl() + exchangeToken().
|
|
10
10
|
*/
|
|
11
11
|
import { isAddrInUse } from "../server/ports";
|
|
@@ -131,8 +131,14 @@ export abstract class OAuthCallbackFlow {
|
|
|
131
131
|
}
|
|
132
132
|
const redirectUri = `http://${this.callbackHostname}:${this.preferredPort}${this.callbackPath}`;
|
|
133
133
|
return { servers, redirectUri };
|
|
134
|
-
} catch {
|
|
134
|
+
} catch (error) {
|
|
135
135
|
if (this.redirectUri) {
|
|
136
|
+
// Fixed OAuth redirect URIs cannot move to a random port. Remote dashboards can
|
|
137
|
+
// still complete the same state/PKCE flow by pasting the final redirect URL or
|
|
138
|
+
// authorization code, so do not make a local listener a prerequisite for that path.
|
|
139
|
+
if (this.ctrl.onManualCodeInput && isAddrInUse(error)) {
|
|
140
|
+
return { servers: [], redirectUri: this.redirectUri };
|
|
141
|
+
}
|
|
136
142
|
throw new Error(
|
|
137
143
|
`OAuth callback port ${this.preferredPort} unavailable; cannot fall back to a random port when redirectUri is set`,
|
|
138
144
|
);
|
package/src/oauth/chatgpt.ts
CHANGED
|
@@ -49,10 +49,21 @@ export function extractEmail(idToken?: string, accessToken?: string): string | u
|
|
|
49
49
|
function credsFromToken(data: Record<string, unknown>): OAuthCredentials {
|
|
50
50
|
const idToken = typeof data.id_token === "string" ? data.id_token : undefined;
|
|
51
51
|
const accessToken = data.access_token as string;
|
|
52
|
+
// ?? only guards null/undefined; NaN or a string expires_in would otherwise
|
|
53
|
+
// produce a NaN expiry that never compares as expired, and a negative duration
|
|
54
|
+
// would stamp an already-past expiry — both block refresh semantics.
|
|
55
|
+
const expiresIn =
|
|
56
|
+
typeof data.expires_in === "number" && Number.isFinite(data.expires_in) && data.expires_in >= 0
|
|
57
|
+
? data.expires_in
|
|
58
|
+
: 3600;
|
|
59
|
+
// The computed timestamp itself must stay finite: Number.MAX_VALUE passes
|
|
60
|
+
// Number.isFinite but overflows to Infinity once multiplied by 1000.
|
|
61
|
+
const computedExpires = Date.now() + expiresIn * 1000;
|
|
62
|
+
const expires = Number.isFinite(computedExpires) ? computedExpires : Date.now() + 3600 * 1000;
|
|
52
63
|
return {
|
|
53
64
|
access: accessToken,
|
|
54
65
|
refresh: (data.refresh_token as string) ?? "",
|
|
55
|
-
expires
|
|
66
|
+
expires,
|
|
56
67
|
accountId: extractAccountId(idToken, accessToken),
|
|
57
68
|
email: extractEmail(idToken, accessToken),
|
|
58
69
|
};
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import type { OAuthController, OAuthCredentials } from "./types";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { isAddrInUse } from "../server/ports";
|
|
5
|
+
import { parseCallbackInput } from "./callback-server";
|
|
6
|
+
|
|
7
|
+
const COMMAND_CODE_STUDIO_URL = "https://commandcode.ai";
|
|
8
|
+
const COMMAND_CODE_CALLBACK_PORT = 5959;
|
|
9
|
+
const LOGIN_TIMEOUT_MS = 120_000;
|
|
10
|
+
const CALLBACK_PATH = "/callback";
|
|
11
|
+
|
|
12
|
+
interface CommandCodeCallback {
|
|
13
|
+
apiKey: string;
|
|
14
|
+
state: string;
|
|
15
|
+
userId: string;
|
|
16
|
+
userName: string;
|
|
17
|
+
keyName: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface CommandCodeLocalAuth {
|
|
21
|
+
apiKey?: unknown;
|
|
22
|
+
userId?: unknown;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface CommandCodeLoginOptions {
|
|
26
|
+
/** Add-account and reauthentication flows must select a fresh browser identity. */
|
|
27
|
+
importLocal?: "fallback" | "off";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function shouldImportLocalCommandCodeAuth(options: CommandCodeLoginOptions = {}): boolean {
|
|
31
|
+
return options.importLocal !== "off";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function importLocalCommandCodeAuth(signal?: AbortSignal): Promise<OAuthCredentials | undefined> {
|
|
35
|
+
if (signal?.aborted) {
|
|
36
|
+
throw signal.reason ?? new DOMException("Command Code login aborted", "AbortError");
|
|
37
|
+
}
|
|
38
|
+
let parsed: CommandCodeLocalAuth;
|
|
39
|
+
try {
|
|
40
|
+
parsed = JSON.parse(await Bun.file(join(homedir(), ".commandcode", "auth.json")).text()) as CommandCodeLocalAuth;
|
|
41
|
+
} catch {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
if (typeof parsed.apiKey !== "string" || parsed.apiKey.length === 0) return undefined;
|
|
45
|
+
let accountId: string | undefined;
|
|
46
|
+
try {
|
|
47
|
+
const response = await fetch("https://api.commandcode.ai/alpha/whoami", {
|
|
48
|
+
headers: { Authorization: `Bearer ${parsed.apiKey}`, Accept: "application/json" },
|
|
49
|
+
signal: signal ? AbortSignal.any([signal, AbortSignal.timeout(10_000)]) : AbortSignal.timeout(10_000),
|
|
50
|
+
});
|
|
51
|
+
if (!response.ok) return undefined;
|
|
52
|
+
// Carry the validated whoami identity so an imported credential keeps multi-account
|
|
53
|
+
// semantics even when the local auth.json omits userId.
|
|
54
|
+
const body = (await response.json()) as { user?: { id?: unknown } };
|
|
55
|
+
if (typeof body.user?.id === "string" && body.user.id.length > 0) accountId = body.user.id;
|
|
56
|
+
} catch (error) {
|
|
57
|
+
if (signal?.aborted) throw signal.reason ?? new DOMException("Command Code login aborted", "AbortError");
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
if (!accountId && typeof parsed.userId === "string" && parsed.userId.length > 0) accountId = parsed.userId;
|
|
61
|
+
return {
|
|
62
|
+
access: parsed.apiKey,
|
|
63
|
+
refresh: parsed.apiKey,
|
|
64
|
+
expires: Number.MAX_SAFE_INTEGER,
|
|
65
|
+
...(accountId ? { accountId } : {}),
|
|
66
|
+
source: "local-cli",
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function randomState(): string {
|
|
71
|
+
const bytes = new Uint8Array(32);
|
|
72
|
+
crypto.getRandomValues(bytes);
|
|
73
|
+
return Buffer.from(bytes).toString("base64url");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function parseCommandCodeCallback(value: unknown, expectedState: string): CommandCodeCallback {
|
|
77
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
78
|
+
throw new Error("Command Code callback must be an object");
|
|
79
|
+
}
|
|
80
|
+
const body = value as Record<string, unknown>;
|
|
81
|
+
if (body.state !== expectedState) throw new Error("Command Code OAuth state mismatch");
|
|
82
|
+
for (const field of ["apiKey", "userId", "userName", "keyName"] as const) {
|
|
83
|
+
if (typeof body[field] !== "string" || body[field].length === 0) {
|
|
84
|
+
throw new Error(`Command Code callback missing ${field}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return body as unknown as CommandCodeCallback;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function createCallbackServer(state: string): {
|
|
91
|
+
servers: Array<ReturnType<typeof Bun.serve>>;
|
|
92
|
+
callback: Promise<CommandCodeCallback>;
|
|
93
|
+
} {
|
|
94
|
+
let resolve!: (value: CommandCodeCallback) => void;
|
|
95
|
+
const callback = new Promise<CommandCodeCallback>((res) => { resolve = res; });
|
|
96
|
+
const fetch = async (request: Request): Promise<Response> => {
|
|
97
|
+
const url = new URL(request.url);
|
|
98
|
+
const origin = request.headers.get("origin");
|
|
99
|
+
const headers = new Headers({
|
|
100
|
+
"Content-Type": "application/json",
|
|
101
|
+
"Access-Control-Allow-Origin": origin === COMMAND_CODE_STUDIO_URL ? origin : COMMAND_CODE_STUDIO_URL,
|
|
102
|
+
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
103
|
+
"Access-Control-Allow-Headers": "Content-Type",
|
|
104
|
+
});
|
|
105
|
+
if (request.method === "OPTIONS") return new Response(null, { status: 204, headers });
|
|
106
|
+
if (url.pathname !== CALLBACK_PATH) return Response.json({ success: false, error: "Not found" }, { status: 404, headers });
|
|
107
|
+
if (request.method !== "POST") return Response.json({ success: false, error: "Method not allowed" }, { status: 405, headers });
|
|
108
|
+
try {
|
|
109
|
+
const body = await request.json();
|
|
110
|
+
const parsed = parseCommandCodeCallback(body, state);
|
|
111
|
+
queueMicrotask(() => resolve(parsed));
|
|
112
|
+
return Response.json({ success: true }, { headers });
|
|
113
|
+
} catch (error) {
|
|
114
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
115
|
+
return Response.json({ success: false, error: message }, { status: 400, headers });
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
const create = (port: number): Array<ReturnType<typeof Bun.serve>> => {
|
|
119
|
+
// The advertised callback host is `127.0.0.1`; on Windows `localhost` commonly resolves to `::1`
|
|
120
|
+
// first, so also bind the IPv6 loopback best-effort (mirrors the shared OAuthCallbackFlow).
|
|
121
|
+
const servers = [Bun.serve({ hostname: "127.0.0.1", port, fetch })];
|
|
122
|
+
try {
|
|
123
|
+
servers.push(Bun.serve({ hostname: "::1", port: servers[0].port, fetch }));
|
|
124
|
+
} catch (error) {
|
|
125
|
+
if (isAddrInUse(error)) {
|
|
126
|
+
for (const server of servers) server.stop(true);
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
// IPv6 unsupported (EAFNOSUPPORT etc.) degrades to the IPv4-only listener.
|
|
130
|
+
}
|
|
131
|
+
return servers;
|
|
132
|
+
};
|
|
133
|
+
try {
|
|
134
|
+
return { servers: create(COMMAND_CODE_CALLBACK_PORT), callback };
|
|
135
|
+
} catch {
|
|
136
|
+
return { servers: create(0), callback };
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Validate a raw pasted Command Code API key and return the validated identity. */
|
|
141
|
+
async function validatePastedApiKey(apiKey: string): Promise<{ userId: string; userName: string } | undefined> {
|
|
142
|
+
try {
|
|
143
|
+
const response = await fetch("https://api.commandcode.ai/alpha/whoami", {
|
|
144
|
+
headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json" },
|
|
145
|
+
signal: AbortSignal.timeout(10_000),
|
|
146
|
+
});
|
|
147
|
+
if (!response.ok) return undefined;
|
|
148
|
+
const body = (await response.json()) as { user?: { id?: unknown; userName?: unknown } };
|
|
149
|
+
const userId = body.user?.id;
|
|
150
|
+
const userName = body.user?.userName;
|
|
151
|
+
if (typeof userId !== "string" || typeof userName !== "string") return undefined;
|
|
152
|
+
if (!userId.trim() || !userName.trim()) return undefined;
|
|
153
|
+
return { userId, userName };
|
|
154
|
+
} catch {
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** Manual-paste fallback: a raw API key, or a pasted callback JSON/URL that carries `apiKey`. */
|
|
160
|
+
function parsePastedCommandCodeInput(input: string, expectedState: string): CommandCodeCallback | undefined {
|
|
161
|
+
const trimmed = input.trim();
|
|
162
|
+
if (!trimmed) return undefined;
|
|
163
|
+
if (trimmed.startsWith("{")) {
|
|
164
|
+
try {
|
|
165
|
+
return parseCommandCodeCallback(JSON.parse(trimmed) as unknown, expectedState);
|
|
166
|
+
} catch {
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const parsed = parseCallbackInput(trimmed);
|
|
171
|
+
const apiKey = parsed.code?.trim();
|
|
172
|
+
if (!apiKey) return undefined;
|
|
173
|
+
// A URL/query-shaped paste is an authorization response and must carry a matching state,
|
|
174
|
+
// mirroring the shared OAuth callback flow; a stale or attacker-supplied URL from another
|
|
175
|
+
// session must not be accepted. Raw in-session keys are exempt (no state to compare).
|
|
176
|
+
if (parsed.kind !== "raw" && parsed.state !== expectedState) return undefined;
|
|
177
|
+
return { apiKey, state: expectedState, userId: "", userName: "", keyName: "manual" };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export async function loginCommandCode(ctrl: OAuthController, options: CommandCodeLoginOptions = {}): Promise<OAuthCredentials> {
|
|
181
|
+
if (ctrl.signal?.aborted) {
|
|
182
|
+
throw ctrl.signal.reason ?? new DOMException("Command Code login aborted", "AbortError");
|
|
183
|
+
}
|
|
184
|
+
if (shouldImportLocalCommandCodeAuth(options)) {
|
|
185
|
+
const local = await importLocalCommandCodeAuth(ctrl.signal);
|
|
186
|
+
if (local) {
|
|
187
|
+
ctrl.onProgress?.("Imported existing Command Code CLI authentication.");
|
|
188
|
+
return local;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
const state = randomState();
|
|
192
|
+
let servers: Array<ReturnType<typeof Bun.serve>> = [];
|
|
193
|
+
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
|
194
|
+
try {
|
|
195
|
+
const created = createCallbackServer(state);
|
|
196
|
+
servers = created.servers;
|
|
197
|
+
const callbackUrl = `http://127.0.0.1:${servers[0].port}${CALLBACK_PATH}`;
|
|
198
|
+
const authUrl = `${COMMAND_CODE_STUDIO_URL}/studio/auth/cli?callback=${encodeURIComponent(callbackUrl)}&state=${encodeURIComponent(state)}`;
|
|
199
|
+
ctrl.onAuth?.({ url: authUrl, instructions: "Sign in with Command Code in the browser." });
|
|
200
|
+
ctrl.onProgress?.("Waiting for Command Code authentication...");
|
|
201
|
+
const timeout = new Promise<never>((_, reject) => {
|
|
202
|
+
timeoutId = setTimeout(() => reject(new Error("Command Code OAuth callback timed out")), LOGIN_TIMEOUT_MS);
|
|
203
|
+
ctrl.signal?.addEventListener("abort", () => { if (timeoutId) clearTimeout(timeoutId); reject(ctrl.signal?.reason); }, { once: true });
|
|
204
|
+
});
|
|
205
|
+
const manual = ctrl.onManualCodeInput
|
|
206
|
+
? (async (): Promise<CommandCodeCallback> => {
|
|
207
|
+
while (true) {
|
|
208
|
+
// The loop keeps waiting until a valid paste arrives; invalid pastes re-prompt.
|
|
209
|
+
// Yield between iterations so an abort signal can interrupt a fast re-prompt loop.
|
|
210
|
+
if (ctrl.signal?.aborted) throw ctrl.signal.reason ?? new DOMException("Command Code login aborted", "AbortError");
|
|
211
|
+
const input = await ctrl.onManualCodeInput?.(state);
|
|
212
|
+
if (input === undefined) continue;
|
|
213
|
+
const pasted = parsePastedCommandCodeInput(input, state);
|
|
214
|
+
if (!pasted) continue;
|
|
215
|
+
const identity = await validatePastedApiKey(pasted.apiKey);
|
|
216
|
+
if (identity) return { ...pasted, ...identity };
|
|
217
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
218
|
+
}
|
|
219
|
+
})()
|
|
220
|
+
: undefined;
|
|
221
|
+
const result = await Promise.race([created.callback, timeout, ...(manual ? [manual] : [])]);
|
|
222
|
+
if (result === undefined) throw new Error("Command Code OAuth callback cancelled");
|
|
223
|
+
return {
|
|
224
|
+
access: result.apiKey,
|
|
225
|
+
refresh: result.apiKey,
|
|
226
|
+
expires: Number.MAX_SAFE_INTEGER,
|
|
227
|
+
accountId: result.userId,
|
|
228
|
+
source: "oauth",
|
|
229
|
+
};
|
|
230
|
+
} finally {
|
|
231
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
232
|
+
for (const server of servers) server.stop(true);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export async function refreshCommandCodeToken(apiKey: string): Promise<OAuthCredentials> {
|
|
237
|
+
if (!apiKey) throw new Error("Command Code API key missing; run ocx login command-code");
|
|
238
|
+
return { access: apiKey, refresh: apiKey, expires: Number.MAX_SAFE_INTEGER, source: "oauth" };
|
|
239
|
+
}
|