@iislee/opencodex 2.11.0 → 2.35.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 +117 -22
- package/bin/ocx.mjs +245 -88
- package/bin/package-main.mjs +1 -1
- package/gui/dist/assets/index-Be1sDpWw.css +1 -0
- package/gui/dist/assets/index-D4OKgUV4.js +114 -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 +21 -10
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +475 -62
- package/src/adapters/base.ts +82 -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 +637 -0
- package/src/adapters/cursor/call-id.ts +44 -0
- package/src/adapters/cursor/catalog.ts +541 -0
- package/src/adapters/cursor/checkpoint-store.ts +308 -0
- package/src/adapters/cursor/cursor-errors.ts +144 -6
- package/src/adapters/cursor/discovery.ts +122 -14
- package/src/adapters/cursor/effort-map.ts +106 -4
- package/src/adapters/cursor/envelope-echo.ts +290 -0
- 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 +180 -59
- package/src/adapters/cursor/live-transport.ts +623 -170
- package/src/adapters/cursor/message-mapper.ts +4 -1
- package/src/adapters/cursor/native-exec-common.ts +23 -2
- package/src/adapters/cursor/native-exec-desktop.ts +23 -0
- 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 +5 -3
- package/src/adapters/cursor/native-exec.ts +121 -14
- package/src/adapters/cursor/protobuf-events.ts +829 -11
- package/src/adapters/cursor/protobuf-request.ts +447 -75
- package/src/adapters/cursor/request-builder.ts +271 -35
- package/src/adapters/cursor/tool-definitions.ts +252 -12
- package/src/adapters/cursor/tool-result-normalize.ts +115 -0
- package/src/adapters/cursor/transport.ts +22 -0
- package/src/adapters/cursor/types.ts +48 -1
- package/src/adapters/cursor.ts +336 -39
- package/src/adapters/exec-tool-result-normalize.ts +99 -0
- package/src/adapters/google-antigravity-replay.ts +713 -41
- package/src/adapters/google-antigravity-wire.ts +48 -10
- package/src/adapters/google-errors.ts +44 -12
- 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 +742 -86
- package/src/adapters/identity.ts +39 -6
- package/src/adapters/image.ts +1 -1
- package/src/adapters/kiro-constants.ts +27 -0
- 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 +65 -17
- package/src/adapters/kiro.ts +270 -73
- package/src/adapters/mimo-free.ts +17 -0
- package/src/adapters/openai-chat-url.ts +11 -0
- package/src/adapters/openai-chat.ts +1377 -344
- package/src/adapters/openai-responses-url.ts +16 -0
- package/src/adapters/openai-responses.ts +1164 -64
- package/src/adapters/registry.ts +175 -0
- package/src/adapters/responses-tool-schema.ts +67 -0
- package/src/adapters/run-turn-queue.ts +36 -1
- package/src/adapters/tool-call-id.ts +119 -0
- package/src/adapters/tool-catalog-nudge.ts +105 -21
- package/src/adapters/xai-tool-schema.ts +436 -0
- package/src/adapters/xai-web-search.ts +186 -0
- package/src/bridge.ts +512 -92
- package/src/chat/inbound.ts +57 -20
- package/src/chat/outbound.ts +97 -33
- package/src/claude/agents-inject.ts +40 -10
- package/src/claude/context-windows.ts +37 -14
- 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 +88 -21
- package/src/cli/access.ts +46 -3
- package/src/cli/account-api.ts +150 -19
- package/src/cli/account-auth.ts +33 -6
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +648 -28
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +97 -19
- package/src/cli/agent.ts +53 -2
- package/src/cli/alias.ts +66 -0
- package/src/cli/capabilities-command.ts +94 -0
- package/src/cli/capabilities.ts +496 -0
- package/src/cli/claude-agent-startup-sync.ts +73 -0
- package/src/cli/claude-desktop.ts +60 -15
- package/src/cli/claude.ts +129 -35
- 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 +821 -0
- package/src/cli/doctor.ts +440 -56
- package/src/cli/ensure-desired-integrations.ts +152 -0
- package/src/cli/export-command.ts +46 -20
- package/src/cli/help.ts +34 -274
- package/src/cli/index.ts +417 -528
- package/src/cli/init.ts +5 -17
- package/src/cli/inspect.ts +230 -0
- 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 +130 -2
- package/src/cli/models.ts +118 -16
- package/src/cli/observe.ts +123 -11
- package/src/cli/opencode.ts +4 -2
- package/src/cli/provider-runtime.ts +34 -3
- package/src/cli/provider.ts +25 -3
- package/src/cli/ready.ts +301 -0
- package/src/cli/registry.ts +476 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +57 -10
- package/src/cli/star-prompt.ts +71 -15
- package/src/cli/status.ts +51 -4
- package/src/cli/storage.ts +234 -0
- package/src/cli/system-command.ts +16 -0
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +153 -6
- package/src/cli/usage-report.ts +184 -0
- package/src/cli/v2.ts +137 -18
- package/src/cli/version-skew.ts +46 -0
- package/src/cli.ts +1 -1
- package/src/clients/config-export.ts +1442 -23
- package/src/clients/effective-status.ts +30 -2
- package/src/clients/probes/cline.ts +81 -0
- package/src/codex/account-label.ts +35 -1
- package/src/codex/account-lifecycle.ts +130 -13
- package/src/codex/account-namespaces.ts +49 -3
- package/src/codex/account-pause.ts +2 -1
- package/src/codex/account-priority.ts +84 -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 +570 -107
- package/src/codex/app-server-restart-service.ts +232 -0
- package/src/codex/auth-api.ts +893 -246
- package/src/codex/auth-collision.ts +5 -3
- package/src/codex/auth-context.ts +348 -32
- package/src/codex/autostart-health.ts +24 -1
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +86 -10
- package/src/codex/catalog/bundled.ts +331 -33
- package/src/codex/catalog/effort.ts +138 -32
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +555 -45
- package/src/codex/catalog/native-models.ts +75 -0
- package/src/codex/catalog/parsing.ts +269 -30
- package/src/codex/catalog/provider-fetch.ts +1626 -144
- package/src/codex/catalog/sync.ts +1576 -187
- 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 +386 -0
- package/src/codex/convergence-types.ts +614 -0
- package/src/codex/convergence.ts +676 -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/desktop-app-restart.ts +355 -0
- package/src/codex/features.ts +636 -39
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +436 -0
- package/src/codex/history-lock.ts +242 -0
- package/src/codex/history-manifest.ts +112 -0
- package/src/codex/history-migration-guardian.ts +30 -24
- package/src/codex/history-provider.ts +1016 -235
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +223 -0
- package/src/codex/inject-coordination.ts +373 -0
- package/src/codex/inject.ts +1114 -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 +81 -0
- package/src/codex/journal.ts +66 -4
- package/src/codex/log-guard/inspect.ts +524 -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 +360 -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 +622 -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 +675 -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 +1313 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/prompt-text-probe.ts +238 -0
- package/src/codex/quota-rejection.ts +298 -0
- package/src/codex/quota.ts +264 -21
- package/src/codex/refresh.ts +11 -2
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/routing.ts +514 -94
- package/src/codex/runtime.ts +159 -38
- package/src/codex/shim.ts +1065 -31
- package/src/codex/subagent-model-fallback.ts +437 -43
- package/src/codex/sync.ts +191 -2
- package/src/codex/transition-state.ts +720 -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 +47 -0
- package/src/combos/index.ts +4 -0
- package/src/combos/request.ts +32 -0
- package/src/combos/types.ts +91 -9
- package/src/compatibility/index.ts +26 -0
- package/src/compatibility/manifest.ts +253 -0
- package/src/compatibility/openai-responses.ts +121 -0
- package/src/config/atomic-write.ts +219 -0
- package/src/config/paths.ts +40 -0
- package/src/config/process-state.ts +309 -0
- package/src/config/provider-name.ts +24 -0
- package/src/config/provider-validation.ts +177 -0
- package/src/config/rebase-provenance.ts +68 -0
- package/src/config.ts +1713 -709
- package/src/generated/compatibility-version.json +3324 -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 +157 -33
- package/src/images/plan.ts +24 -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-policy.ts +160 -0
- package/src/integrations/ownership.ts +155 -0
- package/src/integrations/registry.ts +166 -0
- package/src/integrations/serialize.ts +314 -0
- package/src/integrations/state.ts +433 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer-lock.ts +98 -0
- package/src/integrations/writer.ts +715 -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/admin-secrets.ts +24 -0
- package/src/lib/app-owned-memory-stores.ts +22 -0
- package/src/lib/bounded-body.ts +167 -11
- 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 +26 -2
- package/src/lib/destination-policy.ts +65 -1
- package/src/lib/errors.ts +80 -5
- 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/package-tree-integrity.ts +101 -0
- package/src/lib/pinned-http.ts +145 -26
- package/src/lib/process-control.ts +6 -2
- 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/service-secrets.ts +15 -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 +253 -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 +30 -4
- package/src/oauth/chatgpt.ts +12 -1
- package/src/oauth/cline.ts +203 -0
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +46 -5
- package/src/oauth/generic-account-failover.ts +231 -0
- package/src/oauth/google-antigravity.ts +35 -3
- package/src/oauth/health.ts +20 -12
- package/src/oauth/index.ts +462 -71
- package/src/oauth/key-providers.ts +25 -0
- package/src/oauth/kimi.ts +25 -3
- package/src/oauth/kiro.ts +95 -6
- package/src/oauth/local-token-detect.ts +13 -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/open-browser-choice.ts +26 -0
- package/src/oauth/store.ts +133 -26
- package/src/oauth/token-guardian.ts +9 -3
- package/src/oauth/types.ts +15 -0
- 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/auto-compact-budget.ts +65 -0
- package/src/providers/base-url-choices.ts +10 -0
- package/src/providers/codex-capacity.ts +292 -0
- package/src/providers/command-code-efforts.ts +176 -0
- package/src/providers/context-cap.ts +26 -8
- package/src/providers/cursor-pool.ts +72 -0
- package/src/providers/default-aliases.ts +65 -0
- package/src/providers/derive.ts +281 -6
- package/src/providers/fastwire.ts +507 -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 +35 -2
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +115 -22
- package/src/providers/model-presets.ts +119 -0
- package/src/providers/model-rename-migration.ts +255 -0
- package/src/providers/model-rename-startup.ts +28 -0
- package/src/providers/new-model-policy.ts +146 -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 +30 -0
- package/src/providers/quota.ts +1379 -40
- package/src/providers/registry.ts +1545 -112
- package/src/providers/request-pacing.ts +310 -0
- package/src/providers/service-tier.ts +277 -0
- package/src/providers/slug-codec.ts +94 -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 +32 -4
- package/src/reasoning-effort.ts +68 -3
- package/src/responses/apply-patch-envelope.ts +63 -0
- package/src/responses/code-mode-helper-compat.ts +50 -0
- package/src/responses/compaction.ts +26 -1
- package/src/responses/custom-tool-compat.ts +384 -0
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/namespace-tool-compat.ts +435 -0
- package/src/responses/parser.ts +225 -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 +504 -0
- package/src/responses/schema.ts +12 -2
- package/src/responses/spill-store.ts +75 -10
- package/src/responses/state.ts +659 -31
- package/src/responses/thought-signature-replay.ts +364 -0
- package/src/responses/tool-search-compat.ts +301 -0
- package/src/responses/truncated-stop-reason.ts +60 -0
- package/src/responses/turn-termination.ts +107 -0
- package/src/router.ts +405 -31
- package/src/routing/analytics.ts +379 -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 +155 -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 +289 -48
- package/src/server/background-lifecycle.ts +182 -0
- package/src/server/chat-completions.ts +154 -72
- package/src/server/chat-native-sse.ts +331 -0
- package/src/server/chat-native.ts +445 -0
- package/src/server/claude-messages.ts +160 -44
- 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 +1021 -190
- package/src/server/lifecycle.ts +336 -14
- 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 +433 -116
- package/src/server/management/api-key-usage.ts +31 -5
- package/src/server/management/body.ts +6 -0
- package/src/server/management/codex-prompt-routes.ts +570 -0
- package/src/server/management/combo-routes.ts +64 -25
- package/src/server/management/config-routes.ts +511 -51
- package/src/server/management/context.ts +89 -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 +127 -52
- package/src/server/management/model-routes.ts +461 -133
- package/src/server/management/model-rows.ts +167 -0
- package/src/server/management/native-integration-routes.ts +770 -0
- package/src/server/management/oauth-account-routes.ts +90 -8
- package/src/server/management/provider-capability-config.ts +48 -0
- package/src/server/management/provider-routes.ts +836 -159
- package/src/server/management/request-history-routes.ts +191 -0
- package/src/server/management/route-registry.ts +332 -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 +289 -33
- 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 +126 -23
- package/src/server/management-auth.ts +220 -5
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/port-reclaim.ts +1 -1
- package/src/server/ports.ts +41 -1
- package/src/server/proxy-liveness.ts +161 -10
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +221 -54
- package/src/server/relay.ts +479 -87
- package/src/server/request-decompress.ts +113 -6
- package/src/server/request-log-conversation.ts +51 -0
- package/src/server/request-log.ts +298 -31
- 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/codex-auth-error.ts +55 -0
- package/src/server/responses/collaboration.ts +239 -36
- package/src/server/responses/combo-stream-preflight.ts +178 -0
- package/src/server/responses/compact.ts +444 -72
- package/src/server/responses/core.ts +3579 -436
- package/src/server/responses/empty-completion-guard.ts +333 -0
- package/src/server/responses/encrypted-payload.ts +62 -39
- package/src/server/responses/fetch-helpers.ts +89 -99
- package/src/server/responses/input-admission.ts +187 -0
- package/src/server/responses/pacing-overload.ts +13 -0
- package/src/server/responses/passthrough-error.ts +33 -9
- package/src/server/responses/policy-fallback.ts +178 -0
- package/src/server/responses/responses-field-backfill.ts +343 -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 +381 -0
- package/src/server/responses-custom-tool-repair.ts +363 -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 +363 -0
- package/src/server/responses-tool-search-repair.ts +267 -0
- package/src/server/responses-undeclared-tool-guard.ts +376 -0
- package/src/server/responses.ts +18 -2
- package/src/server/search.ts +78 -13
- package/src/server/sse-frame-buffer.ts +319 -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 +53 -40
- package/src/service-manager-probe.ts +892 -0
- package/src/service.ts +1153 -94
- package/src/sidecar/auth.ts +92 -0
- package/src/sidecar/candidates.ts +83 -0
- package/src/storage/cleanup.ts +2 -2
- package/src/storage/policy-job.ts +14 -4
- package/src/storage/policy.ts +88 -23
- 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 +911 -0
- package/src/types/provider.ts +614 -0
- package/src/types/request.ts +397 -0
- package/src/types/tools.ts +236 -0
- package/src/types/wire.ts +80 -0
- package/src/types.ts +107 -1237
- package/src/update/index.ts +37 -23
- package/src/update/job.ts +445 -68
- 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 +266 -0
- package/src/usage/cost.ts +0 -0
- package/src/usage/expected-prices.ts +287 -16
- package/src/usage/log.ts +666 -50
- package/src/usage/summary.ts +388 -17
- 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 +27 -16
- 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 +119 -0
- package/src/web-search/executor.ts +21 -6
- package/src/web-search/gemini-executor.ts +141 -0
- package/src/web-search/index.ts +150 -15
- package/src/web-search/loop.ts +284 -54
- 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
package/src/claude/outbound.ts
CHANGED
|
@@ -2,13 +2,16 @@
|
|
|
2
2
|
* Claude Code outbound: internal /v1/responses output -> Anthropic Messages API shapes.
|
|
3
3
|
*
|
|
4
4
|
* Wire contract pinned in devlog/260711_claude_inbound/003_evidence.md (all Tier 2):
|
|
5
|
-
* -
|
|
6
|
-
*
|
|
5
|
+
* - Transport-only `ping` events may appear at any point, including before
|
|
6
|
+
* message_start. Semantic framing stays message_start ->
|
|
7
|
+
* (content_block_start -> deltas -> content_block_stop)* -> message_delta -> message_stop.
|
|
7
8
|
* - thinking blocks get thinking_delta(s) then ONE synthetic signature_delta just
|
|
8
9
|
* before content_block_stop (CCR precedent: Claude Code does not verify signatures).
|
|
9
10
|
* - message_delta.usage is cumulative; message_start embeds a full message snapshot.
|
|
10
11
|
* - errors: {type:"error", error:{type,message}}; may arrive mid-stream after HTTP 200.
|
|
11
12
|
*/
|
|
13
|
+
import { createHash } from "node:crypto";
|
|
14
|
+
import { httpStatusFromTerminalError } from "../lib/errors";
|
|
12
15
|
import { isTransientUpstreamStatus } from "../lib/upstream-retry";
|
|
13
16
|
import {
|
|
14
17
|
isTranslatorBudgetExceededError,
|
|
@@ -16,6 +19,7 @@ import {
|
|
|
16
19
|
TranslatorBudgetExceededError,
|
|
17
20
|
type TranslatorBudget,
|
|
18
21
|
} from "../lib/translator-budget";
|
|
22
|
+
import { sseFieldOffset, sseFieldValue } from "../lib/sse-decoder";
|
|
19
23
|
|
|
20
24
|
type Rec = Record<string, unknown>;
|
|
21
25
|
|
|
@@ -23,6 +27,27 @@ function isRec(v: unknown): v is Rec {
|
|
|
23
27
|
return !!v && typeof v === "object" && !Array.isArray(v);
|
|
24
28
|
}
|
|
25
29
|
|
|
30
|
+
function reasoningIdentityDigest(value: string): string {
|
|
31
|
+
return createHash("sha256").update(value).digest("base64url");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Fixed-size identity that preserves protocol boundaries without retaining upstream strings. */
|
|
35
|
+
function boundedReasoningIdentity(value: unknown): string {
|
|
36
|
+
if (typeof value === "number") {
|
|
37
|
+
if (Number.isSafeInteger(value) && value >= 0) return `n${value}`;
|
|
38
|
+
if (Number.isFinite(value)) return `d${value}`;
|
|
39
|
+
return Number.isNaN(value) ? "dnan" : value > 0 ? "dinf" : "d-inf";
|
|
40
|
+
}
|
|
41
|
+
if (typeof value === "string") {
|
|
42
|
+
return `s${reasoningIdentityDigest(value)}`;
|
|
43
|
+
}
|
|
44
|
+
if (value === null) return "z";
|
|
45
|
+
if (typeof value === "boolean") return value ? "b1" : "b0";
|
|
46
|
+
if (Array.isArray(value)) return `a${reasoningIdentityDigest(JSON.stringify(value) ?? "[]")}`;
|
|
47
|
+
// Preserve the prior String(record) category semantics without serializing untrusted trees.
|
|
48
|
+
return typeof value === "object" ? "o" : "u";
|
|
49
|
+
}
|
|
50
|
+
|
|
26
51
|
function uuid(): string {
|
|
27
52
|
return crypto.randomUUID().replace(/-/g, "");
|
|
28
53
|
}
|
|
@@ -187,6 +212,8 @@ interface OpenBlock {
|
|
|
187
212
|
argsBufBytes?: number;
|
|
188
213
|
webSearchArgsEmitted?: boolean;
|
|
189
214
|
callId?: string;
|
|
215
|
+
/** Last fixed-size reasoning identity (item + summary/content index) seen by this block. */
|
|
216
|
+
reasoningPartKey?: string;
|
|
190
217
|
}
|
|
191
218
|
|
|
192
219
|
/** Streaming: Responses SSE bytes -> Anthropic Messages SSE bytes. */
|
|
@@ -242,14 +269,13 @@ export function responsesSseToAnthropicSse(
|
|
|
242
269
|
emit("message_start", { type: "message_start", message: messageSnapshot(model) });
|
|
243
270
|
emit("ping", { type: "ping" });
|
|
244
271
|
};
|
|
245
|
-
//
|
|
246
|
-
//
|
|
247
|
-
//
|
|
272
|
+
// Keepalive pings protect remote deployments behind LB/NAT idle timeouts even
|
|
273
|
+
// before semantic output. They are transport-only and must not manufacture a
|
|
274
|
+
// message before a possible initial error.
|
|
248
275
|
if (pingIntervalMs > 0) {
|
|
249
276
|
pingTimer = setInterval(() => {
|
|
250
|
-
if (terminated) return;
|
|
277
|
+
if (terminated || (controller.desiredSize ?? 0) <= 0) return;
|
|
251
278
|
try {
|
|
252
|
-
ensureStarted();
|
|
253
279
|
emit("ping", { type: "ping" });
|
|
254
280
|
} catch { /* controller torn down; the read loop is ending anyway */ }
|
|
255
281
|
}, pingIntervalMs);
|
|
@@ -325,20 +351,25 @@ export function responsesSseToAnthropicSse(
|
|
|
325
351
|
))));
|
|
326
352
|
return;
|
|
327
353
|
}
|
|
328
|
-
ensureStarted();
|
|
329
|
-
closeOpenBlock();
|
|
330
354
|
const type = upstreamDerived && isTransientUpstreamStatus(status) ? "overloaded_error" : undefined;
|
|
355
|
+
if (!started) {
|
|
356
|
+
// An initial upstream failure is an Anthropic error stream, not a partial message.
|
|
357
|
+
// Do not manufacture message_start before the terminal error. Earlier transport-only
|
|
358
|
+
// pings remain valid and do not turn the failure into a partial message.
|
|
359
|
+
emit("error", anthropicErrorBody(status, message, type, code));
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
closeOpenBlock();
|
|
331
363
|
emit("error", anthropicErrorBody(status, message, type, code));
|
|
332
364
|
};
|
|
333
365
|
|
|
334
366
|
const handleFrame = (eventName: string, data: Rec) => {
|
|
335
367
|
switch (eventName) {
|
|
336
368
|
case "response.created":
|
|
337
|
-
|
|
369
|
+
// Transport prelude only. Start Anthropic framing on semantic output or completion.
|
|
338
370
|
break;
|
|
339
371
|
case "response.heartbeat":
|
|
340
|
-
|
|
341
|
-
emit("ping", { type: "ping" });
|
|
372
|
+
if ((controller.desiredSize ?? 0) > 0) emit("ping", { type: "ping" });
|
|
342
373
|
break;
|
|
343
374
|
case "response.output_text.delta": {
|
|
344
375
|
if (typeof data.delta !== "string" || data.delta.length === 0) break;
|
|
@@ -353,6 +384,24 @@ export function responsesSseToAnthropicSse(
|
|
|
353
384
|
case "response.reasoning_text.delta": {
|
|
354
385
|
if (typeof data.delta !== "string" || data.delta.length === 0) break;
|
|
355
386
|
ensureBlock("thinking");
|
|
387
|
+
// The JSON path joins reasoning summary/content parts with "\n\n"
|
|
388
|
+
// (responsesJsonToAnthropicMessage); mirror that at part and item boundaries
|
|
389
|
+
// so multi-part summaries do not glue into one run-on paragraph. Frames
|
|
390
|
+
// without part indices produce a constant key and never get a separator.
|
|
391
|
+
const slot = eventName === "response.reasoning_summary_text.delta"
|
|
392
|
+
? `s${boundedReasoningIdentity(data.summary_index)}`
|
|
393
|
+
: `c${boundedReasoningIdentity(data.content_index)}`;
|
|
394
|
+
// Upstream string metadata can be arbitrarily large. Hash strings into fixed-size
|
|
395
|
+
// components while retaining item and part equality, rather than dropping item_id and
|
|
396
|
+
// accidentally joining distinct malformed reasoning items.
|
|
397
|
+
const partKey = `${boundedReasoningIdentity(data.item_id)}:${slot}`;
|
|
398
|
+
if (open!.reasoningPartKey !== undefined && open!.reasoningPartKey !== partKey) {
|
|
399
|
+
emit("content_block_delta", {
|
|
400
|
+
type: "content_block_delta", index: open!.index,
|
|
401
|
+
delta: { type: "thinking_delta", thinking: "\n\n" },
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
open!.reasoningPartKey = partKey;
|
|
356
405
|
emit("content_block_delta", {
|
|
357
406
|
type: "content_block_delta", index: open!.index,
|
|
358
407
|
delta: { type: "thinking_delta", thinking: data.delta },
|
|
@@ -507,9 +556,19 @@ export function responsesSseToAnthropicSse(
|
|
|
507
556
|
}
|
|
508
557
|
const status = code === "translation_buffer_limit"
|
|
509
558
|
? 413
|
|
510
|
-
: typeof error.status === "number"
|
|
511
|
-
|
|
512
|
-
|
|
559
|
+
: typeof error.status === "number"
|
|
560
|
+
? error.status
|
|
561
|
+
// Internal response.failed envelopes carry the classified {type, code, message}
|
|
562
|
+
// but no numeric status. Derive it with the same mapping /api/logs uses so a
|
|
563
|
+
// classified 429/401/400 reaches Claude Code as its real Anthropic error type
|
|
564
|
+
// instead of being masked as retryable overload.
|
|
565
|
+
: httpStatusFromTerminalError({
|
|
566
|
+
type: typeof error.type === "string" ? error.type : undefined,
|
|
567
|
+
code: typeof error.code === "string" ? error.code : null,
|
|
568
|
+
message,
|
|
569
|
+
});
|
|
570
|
+
// Unclassified status-absent response.failed (relaySseWithFailedTail synthetic
|
|
571
|
+
// tail) still lands on a transient 5xx here — the mid-stream reset shape maps to
|
|
513
572
|
// overloaded_error by design.
|
|
514
573
|
fail(
|
|
515
574
|
status,
|
|
@@ -571,10 +630,16 @@ export function responsesSseToAnthropicSse(
|
|
|
571
630
|
while (lineStart <= rawFrame.length) {
|
|
572
631
|
const newline = rawFrame.indexOf("\n", lineStart);
|
|
573
632
|
const lineEnd = newline === -1 ? rawFrame.length : newline;
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
633
|
+
// The space after the colon is optional in text/event-stream (#1170);
|
|
634
|
+
// compute the value offset the same way sseFieldValue does, without
|
|
635
|
+
// slicing the line first — the byte accounting below is keyed to
|
|
636
|
+
// offsets into rawFrame.
|
|
637
|
+
const eventOffset = sseFieldOffset(rawFrame, lineStart, lineEnd, "event");
|
|
638
|
+
const dataOffset = sseFieldOffset(rawFrame, lineStart, lineEnd, "data");
|
|
639
|
+
if (eventOffset !== -1) {
|
|
640
|
+
eventName = rawFrame.slice(eventOffset, lineEnd).trim();
|
|
641
|
+
} else if (dataOffset !== -1) {
|
|
642
|
+
const fragmentStart = dataOffset;
|
|
578
643
|
const fragmentBytes = utf8SliceBytes(rawFrame, fragmentStart, lineEnd);
|
|
579
644
|
const fragmentReservation = translatorBudget.reserveTransient(fragmentBytes, { kind: "live_transient" });
|
|
580
645
|
let fragmentCommitted = false;
|
|
@@ -844,8 +909,10 @@ export async function collectAnthropicMessage(
|
|
|
844
909
|
let eventName = "";
|
|
845
910
|
let dataLine = "";
|
|
846
911
|
for (const line of rawFrame.split("\n")) {
|
|
847
|
-
|
|
848
|
-
|
|
912
|
+
const eventValue = sseFieldValue(line, "event");
|
|
913
|
+
if (eventValue !== null) { eventName = eventValue.trim(); continue; }
|
|
914
|
+
const dataValue = sseFieldValue(line, "data");
|
|
915
|
+
if (dataValue !== null) dataLine += dataValue;
|
|
849
916
|
}
|
|
850
917
|
if (!eventName || !dataLine) continue;
|
|
851
918
|
let data: unknown;
|
package/src/cli/access.ts
CHANGED
|
@@ -17,6 +17,51 @@ const USAGE = `Usage:
|
|
|
17
17
|
ocx access models [--json]
|
|
18
18
|
ocx access test <model> [--protocol <chat|responses|messages>] [--json]`;
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Render the key table with the usage fields the API already returns (#2705).
|
|
22
|
+
*
|
|
23
|
+
* `usage` is a DISCRIMINATED UNION server-side (`api-key-usage.ts`): the `{ambiguous:true}`
|
|
24
|
+
* variant carries no numbers at all, because when two config entries share an id there IS no
|
|
25
|
+
* per-key total. The union exists specifically so a consumer cannot print a number beside an
|
|
26
|
+
* ambiguity marker, so this renders the word `ambiguous` across the numeric columns rather
|
|
27
|
+
* than a fabricated 0 -- reporting 0 requests for a key that may be in heavy use is the
|
|
28
|
+
* dangerous answer to hand someone deciding what to delete.
|
|
29
|
+
*
|
|
30
|
+
* `attributionSince` and `historyTruncated` describe the DATA SET, not a key, so they print
|
|
31
|
+
* once as a footer. Without `attributionSince`, an absent `lastUsedAt` is unreadable: it
|
|
32
|
+
* could mean "never used" or "nothing is attributable yet".
|
|
33
|
+
*/
|
|
34
|
+
function formatKeyRows(payload: Record<string, unknown>, keys: Array<Record<string, unknown>>): string[] {
|
|
35
|
+
const cells: string[][] = [["ID", "NAME", "PREFIX", "REQ 7D", "TOTAL", "LAST USED"]];
|
|
36
|
+
for (const entry of keys) {
|
|
37
|
+
const usage = (entry.usage ?? {}) as Record<string, unknown>;
|
|
38
|
+
const ambiguous = usage.ambiguous === true;
|
|
39
|
+
const num = (value: unknown): string => (typeof value === "number" ? value.toLocaleString("en-US") : "-");
|
|
40
|
+
cells.push([
|
|
41
|
+
String(entry.id ?? ""),
|
|
42
|
+
String(entry.name ?? ""),
|
|
43
|
+
String(entry.prefix ?? ""),
|
|
44
|
+
// One marker spanning both numeric columns: the union guarantees neither exists.
|
|
45
|
+
ambiguous ? "ambiguous" : num(usage.requests7d),
|
|
46
|
+
ambiguous ? "" : num(usage.totalRequests),
|
|
47
|
+
ambiguous ? "" : (typeof usage.lastUsedAt === "string" ? usage.lastUsedAt : "never"),
|
|
48
|
+
]);
|
|
49
|
+
}
|
|
50
|
+
const widths = cells[0]!.map((_, column) => Math.max(...cells.map(row => (row[column] ?? "").length)));
|
|
51
|
+
const lines = cells.map(row => row.map((cell, i) => (cell ?? "").padEnd(widths[i]!)).join(" ").trimEnd());
|
|
52
|
+
const footer: string[] = [];
|
|
53
|
+
if (typeof payload.attributionSince === "string") {
|
|
54
|
+
footer.push(`attribution since ${payload.attributionSince}`);
|
|
55
|
+
}
|
|
56
|
+
if (payload.historyTruncated === true) {
|
|
57
|
+
footer.push("older history truncated");
|
|
58
|
+
}
|
|
59
|
+
if (keys.some(entry => (entry.usage as Record<string, unknown> | undefined)?.ambiguous === true)) {
|
|
60
|
+
footer.push("ambiguous: two configured keys share an id, so per-key totals do not exist");
|
|
61
|
+
}
|
|
62
|
+
return footer.length > 0 ? [...lines, "", ...footer] : lines;
|
|
63
|
+
}
|
|
64
|
+
|
|
20
65
|
async function key(argv: string[], deps: RuntimeApiDeps): Promise<void> {
|
|
21
66
|
const args = [...argv];
|
|
22
67
|
const action = (args.shift() ?? "list").toLowerCase();
|
|
@@ -25,9 +70,7 @@ async function key(argv: string[], deps: RuntimeApiDeps): Promise<void> {
|
|
|
25
70
|
rejectArgs(args, USAGE);
|
|
26
71
|
const result = await runtimeRequest<Record<string, unknown>>("/api/keys", {}, deps);
|
|
27
72
|
const keys = Array.isArray(result.keys) ? result.keys as Array<Record<string, unknown>> : [];
|
|
28
|
-
printData(result, wantsJson, keys.length
|
|
29
|
-
? keys.map(entry => `${String(entry.id)} ${String(entry.name)} ${String(entry.prefix ?? "")}`)
|
|
30
|
-
: ["No API access keys configured."]);
|
|
73
|
+
printData(result, wantsJson, keys.length ? formatKeyRows(result, keys) : ["No API access keys configured."]);
|
|
31
74
|
return;
|
|
32
75
|
}
|
|
33
76
|
if (action === "create") {
|
package/src/cli/account-api.ts
CHANGED
|
@@ -21,13 +21,34 @@ export interface AccountRow {
|
|
|
21
21
|
masked?: string;
|
|
22
22
|
active: boolean;
|
|
23
23
|
needsReauth?: boolean;
|
|
24
|
+
/** Codex pool selection order, higher used earlier. Absent where ordering does not apply. */
|
|
25
|
+
priority?: number;
|
|
24
26
|
quota?: CodexQuotaDto | null;
|
|
27
|
+
/**
|
|
28
|
+
* Whether the pool is holding this account out of rotation.
|
|
29
|
+
*
|
|
30
|
+
* The server has always sent it (auth-api.ts:286 for pool accounts, :1315 for main) and the
|
|
31
|
+
* CLI dropped it, so a paused account was indistinguishable from an available one in every
|
|
32
|
+
* human listing (#2703).
|
|
33
|
+
*/
|
|
34
|
+
paused?: boolean;
|
|
25
35
|
}
|
|
26
36
|
|
|
27
37
|
export type ClassifyResult = { type: AccountType } | { error: string };
|
|
28
38
|
|
|
29
39
|
export type AccountStdin = NodeJS.ReadableStream & { isTTY?: boolean };
|
|
30
40
|
|
|
41
|
+
export interface NativeMainLoginChild {
|
|
42
|
+
exited: Promise<number>;
|
|
43
|
+
kill(signal?: number | NodeJS.Signals): void;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface StageLeaseClock {
|
|
47
|
+
now(): number;
|
|
48
|
+
setTimeout(callback: () => void, ms: number): ReturnType<typeof setTimeout>;
|
|
49
|
+
clearTimeout(timer: ReturnType<typeof setTimeout>): void;
|
|
50
|
+
}
|
|
51
|
+
|
|
31
52
|
export interface AccountDeps {
|
|
32
53
|
/** Test injection: skip findLiveProxy and call the API at this base URL. */
|
|
33
54
|
baseUrl?: string;
|
|
@@ -35,6 +56,16 @@ export interface AccountDeps {
|
|
|
35
56
|
loadConfigImpl?: () => OcxConfig;
|
|
36
57
|
stdinImpl?: AccountStdin;
|
|
37
58
|
stdinTimeoutMs?: number;
|
|
59
|
+
/** Internal test seam for the account-import POST; production is capped at ten minutes. */
|
|
60
|
+
importTimeoutMs?: number;
|
|
61
|
+
/** Test/platform injection for the official Codex login in a restricted staging home. */
|
|
62
|
+
spawnCodexLoginImpl?: (codexHome: string) => NativeMainLoginChild;
|
|
63
|
+
/** Legacy test seam. Production always uses the spawned child handle above. */
|
|
64
|
+
runCodexLoginImpl?: (codexHome: string) => Promise<number>;
|
|
65
|
+
/** Test-only heartbeat cadence floor. Production keeps the five-second floor. */
|
|
66
|
+
stageHeartbeatIntervalMinMs?: number;
|
|
67
|
+
/** Test-only clock for deterministic native-profile lease deadline coverage. */
|
|
68
|
+
stageLeaseClock?: StageLeaseClock;
|
|
38
69
|
}
|
|
39
70
|
|
|
40
71
|
export function classifyAccount(config: OcxConfig, name: string): ClassifyResult {
|
|
@@ -60,6 +91,12 @@ export interface ApiResult {
|
|
|
60
91
|
/** 0 = network-level failure (proxy unreachable). */
|
|
61
92
|
status: number;
|
|
62
93
|
json: Record<string, unknown>;
|
|
94
|
+
/**
|
|
95
|
+
* Message from the thrown transport error when `status` is 0. Previously the
|
|
96
|
+
* error was swallowed by a catch block with an empty body, so an unreachable proxy, a DNS
|
|
97
|
+
* failure and a TLS error were indistinguishable (#2698).
|
|
98
|
+
*/
|
|
99
|
+
transportError?: string;
|
|
63
100
|
}
|
|
64
101
|
|
|
65
102
|
export async function apiJson(
|
|
@@ -68,6 +105,7 @@ export async function apiJson(
|
|
|
68
105
|
method: "GET" | "PUT" | "POST" | "DELETE",
|
|
69
106
|
path: string,
|
|
70
107
|
body?: unknown,
|
|
108
|
+
options: { signal?: AbortSignal } = {},
|
|
71
109
|
): Promise<ApiResult> {
|
|
72
110
|
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
73
111
|
try {
|
|
@@ -75,11 +113,18 @@ export async function apiJson(
|
|
|
75
113
|
method,
|
|
76
114
|
headers: runningProxyUpdateHeaders(),
|
|
77
115
|
body: body === undefined ? undefined : JSON.stringify(body),
|
|
116
|
+
signal: options.signal,
|
|
78
117
|
});
|
|
79
118
|
const json = (await res.json().catch(() => ({}))) as Record<string, unknown>;
|
|
80
119
|
return { status: res.status, json };
|
|
81
|
-
} catch {
|
|
82
|
-
|
|
120
|
+
} catch (error) {
|
|
121
|
+
// status 0 stays the transport sentinel, but keep the cause: callers can now
|
|
122
|
+
// tell the operator why the request never reached the proxy (#2698).
|
|
123
|
+
return {
|
|
124
|
+
status: 0,
|
|
125
|
+
json: {},
|
|
126
|
+
transportError: error instanceof Error ? error.message : String(error),
|
|
127
|
+
};
|
|
83
128
|
}
|
|
84
129
|
}
|
|
85
130
|
|
|
@@ -90,15 +135,43 @@ export async function resolveBaseUrl(deps: AccountDeps): Promise<string | null>
|
|
|
90
135
|
return `http://${probeHostname(live.hostname)}:${live.port}`;
|
|
91
136
|
}
|
|
92
137
|
|
|
93
|
-
export function proxyUnreachable(): number {
|
|
138
|
+
export function proxyUnreachable(transportError?: string): number {
|
|
94
139
|
console.error("Proxy not reachable. Start it with 'ocx start' or 'ocx ensure'.");
|
|
140
|
+
// Naming the transport cause distinguishes "nothing is listening" from a refused
|
|
141
|
+
// or reset connection, which is what made #2696-class breakage undiagnosable.
|
|
142
|
+
if (transportError) console.error(`reason: ${transportError}`);
|
|
95
143
|
return 1;
|
|
96
144
|
}
|
|
97
145
|
|
|
98
|
-
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
146
|
+
function accountStringField(json: Record<string, unknown>, key: string): string | undefined {
|
|
147
|
+
const value = json[key];
|
|
148
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Report a failed management call from the account family.
|
|
153
|
+
*
|
|
154
|
+
* `reason` and `hint` are the actionable fields on a refusal — the management plane
|
|
155
|
+
* sets both on a 503, and several routes return `reason` with no `error` key at all,
|
|
156
|
+
* which used to print only the generic fallback (#2698).
|
|
157
|
+
*
|
|
158
|
+
* `status` selects the exit code so the account client speaks the same vocabulary as
|
|
159
|
+
* runtime-api.ts: 4 for not-found, 5 for conflict, 1 otherwise. Previously every
|
|
160
|
+
* failure exited 1, so a script could not distinguish a missing account from a
|
|
161
|
+
* concurrent mutation.
|
|
162
|
+
*/
|
|
163
|
+
export function apiError(json: Record<string, unknown>, fallback: string, status: number): number {
|
|
164
|
+
const primary = accountStringField(json, "error") ?? fallback;
|
|
165
|
+
const lines = [`Error: ${primary}`];
|
|
166
|
+
const reason = accountStringField(json, "reason");
|
|
167
|
+
if (reason && reason !== primary) lines.push(`reason: ${reason}`);
|
|
168
|
+
const hint = accountStringField(json, "hint");
|
|
169
|
+
if (hint && hint !== primary) lines.push(`hint: ${hint}`);
|
|
170
|
+
for (const line of lines) console.error(line);
|
|
171
|
+
if (json.cleanupRequired === true) {
|
|
172
|
+
console.error("Warning: native-login staging cleanup is still required; run 'ocx account main doctor'.");
|
|
173
|
+
}
|
|
174
|
+
return status === 404 ? 4 : status === 409 ? 5 : 1;
|
|
102
175
|
}
|
|
103
176
|
|
|
104
177
|
export interface FamilyRows {
|
|
@@ -106,10 +179,12 @@ export interface FamilyRows {
|
|
|
106
179
|
activeId: string | null;
|
|
107
180
|
autoSwitchThreshold?: number;
|
|
108
181
|
/** HTTP status for a completed family read, including failures. */
|
|
109
|
-
status
|
|
182
|
+
status: number;
|
|
110
183
|
/** Set when the family endpoint returned an error. */
|
|
111
184
|
errorJson?: Record<string, unknown>;
|
|
112
185
|
networkDown?: boolean;
|
|
186
|
+
/** Transport cause when `networkDown` is set. Callers must forward this to `proxyUnreachable`. */
|
|
187
|
+
transportError?: string;
|
|
113
188
|
}
|
|
114
189
|
|
|
115
190
|
export interface CodexQuotaDto {
|
|
@@ -117,6 +192,18 @@ export interface CodexQuotaDto {
|
|
|
117
192
|
monthlyPercent?: number;
|
|
118
193
|
weeklyResetAt?: number;
|
|
119
194
|
monthlyResetAt?: number;
|
|
195
|
+
/**
|
|
196
|
+
* Five-hour window, as the per-account provider probe reports it
|
|
197
|
+
* (`/api/oauth/accounts?quota=1`). Distinct from `shortPercent`, which is the Codex pool's
|
|
198
|
+
* self-declared burst window; the two surfaces name the same idea differently and both reach
|
|
199
|
+
* this DTO.
|
|
200
|
+
*/
|
|
201
|
+
fiveHourPercent?: number;
|
|
202
|
+
fiveHourResetAt?: number;
|
|
203
|
+
/** Sub-day burst window, when upstream declares one (#1791). */
|
|
204
|
+
shortPercent?: number;
|
|
205
|
+
shortResetAt?: number;
|
|
206
|
+
shortWindowSeconds?: number;
|
|
120
207
|
}
|
|
121
208
|
|
|
122
209
|
export interface ProviderQuotaWindowDto {
|
|
@@ -148,13 +235,21 @@ interface CodexAccountDto {
|
|
|
148
235
|
plan?: string;
|
|
149
236
|
isMain?: boolean;
|
|
150
237
|
needsReauth?: boolean;
|
|
238
|
+
priority?: number;
|
|
151
239
|
quota?: CodexQuotaDto | null;
|
|
240
|
+
paused?: boolean;
|
|
152
241
|
}
|
|
153
242
|
|
|
154
243
|
function projectQuota(quota: CodexQuotaDto | null | undefined): CodexQuotaDto | null {
|
|
155
244
|
if (!quota) return null;
|
|
156
245
|
const projected: CodexQuotaDto = {};
|
|
157
|
-
|
|
246
|
+
// `fiveHourPercent`/`fiveHourResetAt` were declared on the DTO and read by two renderers
|
|
247
|
+
// -- `quotaText`'s `quota.fiveHourPercent ?? quota.shortPercent` (account.ts:89) and
|
|
248
|
+
// `quotaParts` (account-extended.ts:275) -- but omitted from this whitelist, so the first
|
|
249
|
+
// operand was unreachable and a 5h-only account rendered as unknown (#2703). A projection
|
|
250
|
+
// that silently drops a field its own type declares is worse than one that never had it:
|
|
251
|
+
// the type checks, the renderer looks correct, and only the output is wrong.
|
|
252
|
+
for (const key of ["fiveHourPercent", "fiveHourResetAt", "weeklyPercent", "monthlyPercent", "weeklyResetAt", "monthlyResetAt", "shortPercent", "shortResetAt", "shortWindowSeconds"] as const) {
|
|
158
253
|
if (typeof quota[key] === "number" && Number.isFinite(quota[key])) projected[key] = quota[key];
|
|
159
254
|
}
|
|
160
255
|
return projected;
|
|
@@ -164,6 +259,7 @@ export async function fetchCodexRows(
|
|
|
164
259
|
deps: AccountDeps,
|
|
165
260
|
baseUrl: string,
|
|
166
261
|
forceRefresh = false,
|
|
262
|
+
includeQuota = forceRefresh,
|
|
167
263
|
): Promise<FamilyRows> {
|
|
168
264
|
const accountsPath = `/api/codex-auth/accounts${forceRefresh ? "?refresh=1" : ""}`;
|
|
169
265
|
const [accountsRes, activeRes] = await Promise.all([
|
|
@@ -177,7 +273,13 @@ export async function fetchCodexRows(
|
|
|
177
273
|
return { rows: [], activeId: null, status: activeRes.status, errorJson: activeRes.json };
|
|
178
274
|
}
|
|
179
275
|
if (accountsRes.status === 0 || activeRes.status === 0) {
|
|
180
|
-
return {
|
|
276
|
+
return {
|
|
277
|
+
rows: [],
|
|
278
|
+
activeId: null,
|
|
279
|
+
status: 0,
|
|
280
|
+
networkDown: true,
|
|
281
|
+
transportError: accountsRes.transportError ?? activeRes.transportError,
|
|
282
|
+
};
|
|
181
283
|
}
|
|
182
284
|
const activeId = typeof activeRes.json.activeCodexAccountId === "string"
|
|
183
285
|
? activeRes.json.activeCodexAccountId
|
|
@@ -195,7 +297,9 @@ export async function fetchCodexRows(
|
|
|
195
297
|
plan: a.plan,
|
|
196
298
|
active: a.id === activeId,
|
|
197
299
|
needsReauth: a.needsReauth,
|
|
198
|
-
|
|
300
|
+
priority: typeof a.priority === "number" ? a.priority : 0,
|
|
301
|
+
paused: a.paused === true,
|
|
302
|
+
...(includeQuota ? { quota: projectQuota(a.quota) } : {}),
|
|
199
303
|
}));
|
|
200
304
|
return { rows, activeId, autoSwitchThreshold, status: 200 };
|
|
201
305
|
}
|
|
@@ -206,11 +310,25 @@ interface OAuthAccountDto {
|
|
|
206
310
|
email?: string;
|
|
207
311
|
active?: boolean;
|
|
208
312
|
needsReauth?: boolean;
|
|
313
|
+
quota?: CodexQuotaDto | null;
|
|
314
|
+
quotaUnavailable?: boolean;
|
|
209
315
|
}
|
|
210
316
|
|
|
211
|
-
async function fetchOAuthRows(
|
|
212
|
-
|
|
213
|
-
|
|
317
|
+
async function fetchOAuthRows(
|
|
318
|
+
deps: AccountDeps,
|
|
319
|
+
baseUrl: string,
|
|
320
|
+
name: string,
|
|
321
|
+
quota?: { refresh?: boolean },
|
|
322
|
+
): Promise<FamilyRows> {
|
|
323
|
+
// Quota is opt-in: the server probes the upstream once per stored credential when `quota=1`
|
|
324
|
+
// is present, so the default listing must stay a cheap local read (#2566).
|
|
325
|
+
const query = quota
|
|
326
|
+
? `?provider=${encodeURIComponent(name)}"a=1${quota.refresh ? "&refresh=1" : ""}`
|
|
327
|
+
: `?provider=${encodeURIComponent(name)}`;
|
|
328
|
+
const res = await apiJson(deps, baseUrl, "GET", `/api/oauth/accounts${query}`);
|
|
329
|
+
if (res.status === 0) {
|
|
330
|
+
return { rows: [], activeId: null, status: 0, networkDown: true, transportError: res.transportError };
|
|
331
|
+
}
|
|
214
332
|
if (res.status !== 200) return { rows: [], activeId: null, status: res.status, errorJson: res.json };
|
|
215
333
|
const activeId = typeof res.json.activeAccountId === "string" ? res.json.activeAccountId : null;
|
|
216
334
|
const accounts = Array.isArray(res.json.accounts) ? res.json.accounts as OAuthAccountDto[] : [];
|
|
@@ -222,6 +340,8 @@ async function fetchOAuthRows(deps: AccountDeps, baseUrl: string, name: string):
|
|
|
222
340
|
email: a.email,
|
|
223
341
|
active: a.active ?? a.id === activeId,
|
|
224
342
|
needsReauth: a.needsReauth,
|
|
343
|
+
...(a.quota !== undefined ? { quota: a.quota } : {}),
|
|
344
|
+
...(a.quotaUnavailable !== undefined ? { quotaUnavailable: a.quotaUnavailable } : {}),
|
|
225
345
|
}));
|
|
226
346
|
return { rows, activeId, status: 200 };
|
|
227
347
|
}
|
|
@@ -235,7 +355,9 @@ interface ApiKeyDto {
|
|
|
235
355
|
|
|
236
356
|
async function fetchKeyRows(deps: AccountDeps, baseUrl: string, name: string): Promise<FamilyRows> {
|
|
237
357
|
const res = await apiJson(deps, baseUrl, "GET", `/api/providers/keys?name=${encodeURIComponent(name)}`);
|
|
238
|
-
if (res.status === 0)
|
|
358
|
+
if (res.status === 0) {
|
|
359
|
+
return { rows: [], activeId: null, status: 0, networkDown: true, transportError: res.transportError };
|
|
360
|
+
}
|
|
239
361
|
if (res.status !== 200) return { rows: [], activeId: null, status: res.status, errorJson: res.json };
|
|
240
362
|
const activeId = typeof res.json.activeId === "string" ? res.json.activeId : null;
|
|
241
363
|
const keys = Array.isArray(res.json.keys) ? res.json.keys as ApiKeyDto[] : [];
|
|
@@ -250,9 +372,15 @@ async function fetchKeyRows(deps: AccountDeps, baseUrl: string, name: string): P
|
|
|
250
372
|
return { rows, activeId, status: 200 };
|
|
251
373
|
}
|
|
252
374
|
|
|
253
|
-
export function fetchRows(
|
|
254
|
-
|
|
255
|
-
|
|
375
|
+
export function fetchRows(
|
|
376
|
+
deps: AccountDeps,
|
|
377
|
+
baseUrl: string,
|
|
378
|
+
name: string,
|
|
379
|
+
type: AccountType,
|
|
380
|
+
quota?: { refresh?: boolean },
|
|
381
|
+
): Promise<FamilyRows> {
|
|
382
|
+
if (type === "codex") return fetchCodexRows(deps, baseUrl, Boolean(quota?.refresh), quota !== undefined);
|
|
383
|
+
if (type === "oauth") return fetchOAuthRows(deps, baseUrl, name, quota);
|
|
256
384
|
return fetchKeyRows(deps, baseUrl, name);
|
|
257
385
|
}
|
|
258
386
|
|
|
@@ -260,8 +388,11 @@ export async function fetchProviderQuotaReport(
|
|
|
260
388
|
deps: AccountDeps,
|
|
261
389
|
baseUrl: string,
|
|
262
390
|
name: string,
|
|
263
|
-
): Promise<{ status: number; report: ProviderQuotaReportDto | null; errorJson?: Record<string, unknown
|
|
391
|
+
): Promise<{ status: number; report: ProviderQuotaReportDto | null; errorJson?: Record<string, unknown>; transportError?: string }> {
|
|
264
392
|
const res = await apiJson(deps, baseUrl, "GET", "/api/provider-quotas?refresh=1");
|
|
393
|
+
if (res.status === 0) {
|
|
394
|
+
return { status: 0, report: null, errorJson: res.json, transportError: res.transportError };
|
|
395
|
+
}
|
|
265
396
|
if (res.status !== 200) return { status: res.status, report: null, errorJson: res.json };
|
|
266
397
|
const reports = Array.isArray(res.json.reports) ? res.json.reports as ProviderQuotaReportDto[] : [];
|
|
267
398
|
return { status: 200, report: reports.find(report => report?.provider === name) ?? null };
|
package/src/cli/account-auth.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { writeSync } from "node:fs";
|
|
2
|
+
import { warnIfCodexCatalogRefreshPending } from "./account-catalog-refresh";
|
|
1
3
|
import {
|
|
2
4
|
CliUsageError,
|
|
3
5
|
printData,
|
|
@@ -12,6 +14,22 @@ import {
|
|
|
12
14
|
type RuntimeApiDeps,
|
|
13
15
|
} from "./runtime-api";
|
|
14
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Write the whole block to fd 1 synchronously (#1007). `console.log` can
|
|
19
|
+
* buffer behind a pipe, which hid the authorization URL for the entire
|
|
20
|
+
* polling window under non-TTY stdout. A partial write loops; a zero-byte
|
|
21
|
+
* write is a hard failure, never silent progress.
|
|
22
|
+
*/
|
|
23
|
+
function writeStdoutFully(text: string): void {
|
|
24
|
+
const bytes = Buffer.from(text, "utf8");
|
|
25
|
+
let offset = 0;
|
|
26
|
+
while (offset < bytes.length) {
|
|
27
|
+
const written = writeSync(1, bytes, offset, bytes.length - offset);
|
|
28
|
+
if (written <= 0) throw new CliUsageError("failed to write login instructions to stdout");
|
|
29
|
+
offset += written;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
15
33
|
const USAGE = `Usage:
|
|
16
34
|
ocx account login <provider> [--id <account-id>] [--reauth] [--code -] [--no-wait] [--json]
|
|
17
35
|
ocx account code <provider> [--flow <flow-id>] [--json] (reads the code from stdin)
|
|
@@ -82,9 +100,14 @@ async function login(argv: string[], deps: RuntimeApiDeps): Promise<void> {
|
|
|
82
100
|
body: JSON.stringify({ ...(id ? { id } : {}), ...(reauth ? { reauth: true } : {}) }),
|
|
83
101
|
}, deps);
|
|
84
102
|
if (!wantsJson) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
103
|
+
// One atomic pre-poll block, flushed synchronously so a piped parent
|
|
104
|
+
// reads the URL before the polling window starts (#1007).
|
|
105
|
+
const block = [
|
|
106
|
+
start.url ? `Open this URL to sign in:\n${start.url}` : "",
|
|
107
|
+
start.instructions ?? "",
|
|
108
|
+
start.flowId ? `Flow: ${start.flowId}` : "",
|
|
109
|
+
].filter(line => line !== "").join("\n");
|
|
110
|
+
if (block) writeStdoutFully(`${block}\n`);
|
|
88
111
|
}
|
|
89
112
|
if (code && start.flowId) {
|
|
90
113
|
await runtimeRequest("/api/codex-auth/login/code", {
|
|
@@ -105,6 +128,7 @@ async function login(argv: string[], deps: RuntimeApiDeps): Promise<void> {
|
|
|
105
128
|
);
|
|
106
129
|
if (state.status === "done") {
|
|
107
130
|
printData(state, wantsJson, [`Logged in${state.email ? ` as ${String(state.email)}` : ""}.`]);
|
|
131
|
+
if (!wantsJson) warnIfCodexCatalogRefreshPending(state);
|
|
108
132
|
return;
|
|
109
133
|
}
|
|
110
134
|
if (state.status === "error" || state.status === "expired") {
|
|
@@ -120,9 +144,12 @@ async function login(argv: string[], deps: RuntimeApiDeps): Promise<void> {
|
|
|
120
144
|
body: JSON.stringify({ provider, addAccount: !reauth, ...(reauth && id ? { accountId: id, reauth: true } : {}) }),
|
|
121
145
|
}, deps);
|
|
122
146
|
if (!wantsJson) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
147
|
+
const block = [
|
|
148
|
+
start.url ? `Open this URL to sign in:\n${start.url}` : "",
|
|
149
|
+
start.instructions ?? "",
|
|
150
|
+
start.deviceCode ? `Device code: ${start.deviceCode}` : "",
|
|
151
|
+
].filter(line => line !== "").join("\n");
|
|
152
|
+
if (block) writeStdoutFully(`${block}\n`);
|
|
126
153
|
}
|
|
127
154
|
if (code) {
|
|
128
155
|
await runtimeRequest("/api/oauth/login/code", {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const CODEX_CATALOG_REFRESH_PENDING_WARNING =
|
|
2
|
+
"Warning: the account change was saved, but the Codex model catalog refresh is pending. Run 'ocx sync' to retry.";
|
|
3
|
+
|
|
4
|
+
/** Read only the public completion flag from an account mutation response. */
|
|
5
|
+
export function codexCatalogRefreshPending(value: unknown): boolean {
|
|
6
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
7
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, "catalogRefreshPending");
|
|
8
|
+
return descriptor !== undefined && "value" in descriptor && descriptor.value === true;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Print fixed recovery guidance without reflecting server or account details. */
|
|
12
|
+
export function warnIfCodexCatalogRefreshPending(value: unknown): void {
|
|
13
|
+
if (codexCatalogRefreshPending(value)) console.error(CODEX_CATALOG_REFRESH_PENDING_WARNING);
|
|
14
|
+
}
|