@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
|
@@ -71,6 +71,107 @@ export async function sleepWithAbort(ms: number, signal?: AbortSignal): Promise<
|
|
|
71
71
|
});
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Best-effort, bounded cancellation of a response body before a retry backoff.
|
|
76
|
+
*
|
|
77
|
+
* The 429 paths release the unread body before waiting so sockets do not accumulate under a
|
|
78
|
+
* rate-limit storm, but a never-settling `cancel()` promise must not be able to block the
|
|
79
|
+
* abort-aware backoff (client cancel, `maxIntervalMs`, or the cumulative header deadline).
|
|
80
|
+
* Cancellation is started and its rejection observed; the await is bounded by `timeoutMs`
|
|
81
|
+
* and the abort signal. This mirrors the rotation-path guarantee (release is initiated, not
|
|
82
|
+
* awaited forever) while preserving the resource-release intent of the same-target paths.
|
|
83
|
+
*/
|
|
84
|
+
export async function releaseResponseBodyBestEffort(
|
|
85
|
+
body: ReadableStream<Uint8Array> | null,
|
|
86
|
+
signal: AbortSignal | undefined,
|
|
87
|
+
timeoutMs = 1_000,
|
|
88
|
+
): Promise<void> {
|
|
89
|
+
if (!body) return;
|
|
90
|
+
if (signal?.aborted) {
|
|
91
|
+
void body.cancel().catch(() => {});
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const cancel = body.cancel().catch(() => {});
|
|
95
|
+
if (!signal) {
|
|
96
|
+
await Promise.race([cancel, new Promise<void>(resolve => setTimeout(resolve, timeoutMs))]);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
await new Promise<void>(resolve => {
|
|
100
|
+
let timer: ReturnType<typeof setTimeout>;
|
|
101
|
+
/**
|
|
102
|
+
* Abort hook: clear the bounded-body release timer and settle the promise so a
|
|
103
|
+
* never-settling cancel() can never block the abort-aware backoff.
|
|
104
|
+
*/
|
|
105
|
+
const onAbort = () => {
|
|
106
|
+
clearTimeout(timer);
|
|
107
|
+
resolve();
|
|
108
|
+
};
|
|
109
|
+
timer = setTimeout(() => {
|
|
110
|
+
signal.removeEventListener("abort", onAbort);
|
|
111
|
+
resolve();
|
|
112
|
+
}, timeoutMs);
|
|
113
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
114
|
+
void cancel.then(() => {
|
|
115
|
+
clearTimeout(timer);
|
|
116
|
+
signal.removeEventListener("abort", onAbort);
|
|
117
|
+
resolve();
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Abort-aware sleep that yields an adapter `heartbeat` at least every `heartbeatIntervalMs`.
|
|
124
|
+
* The Responses bridge treats a returned iterator event as upstream liveness and aborts turns
|
|
125
|
+
* that stay silent past the stall budget (default 300s), while a retryOn429 wait may legally
|
|
126
|
+
* reach 600s — so deliberate waits must keep the watchdog fed or a long backoff is killed
|
|
127
|
+
* mid-turn. The final chunk always yields once, which doubles as the post-wait liveness beat.
|
|
128
|
+
*/
|
|
129
|
+
export async function* sleepWithHeartbeats(
|
|
130
|
+
ms: number,
|
|
131
|
+
signal?: AbortSignal,
|
|
132
|
+
heartbeatIntervalMs = 10_000,
|
|
133
|
+
): AsyncGenerator<{ type: "heartbeat" }> {
|
|
134
|
+
if (ms <= 0) return;
|
|
135
|
+
// Guard against a non-positive interval: a zero/negative step would spin the loop forever
|
|
136
|
+
// while sleepWithAbort early-returns without ever observing the abort signal. NaN must be
|
|
137
|
+
// normalized too: Math.max(1, NaN) is NaN, which would abort the wait after one beat.
|
|
138
|
+
const stepMs = Number.isNaN(heartbeatIntervalMs) ? 1 : Math.max(1, heartbeatIntervalMs);
|
|
139
|
+
let remaining = ms;
|
|
140
|
+
while (remaining > 0) {
|
|
141
|
+
const chunk = Math.min(remaining, stepMs);
|
|
142
|
+
await sleepWithAbort(chunk, signal);
|
|
143
|
+
remaining -= chunk;
|
|
144
|
+
yield { type: "heartbeat" };
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export interface SameTarget429WaitOptions {
|
|
149
|
+
body: ReadableStream<Uint8Array> | null;
|
|
150
|
+
signal?: AbortSignal;
|
|
151
|
+
delayMs: number;
|
|
152
|
+
/**
|
|
153
|
+
* When set, the wait yields adapter heartbeats so bridge stall watchdogs stay fed.
|
|
154
|
+
* Omit for pre-stream recovery paths that have no stall watchdog.
|
|
155
|
+
*/
|
|
156
|
+
heartbeatIntervalMs?: number;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Shared pre-replay prep for opt-in same-target 429 waits:
|
|
161
|
+
* release the unread 429 body, then sleep (optionally with heartbeats).
|
|
162
|
+
* Callers still own attempt budgeting, abort re-checks, and the replay itself.
|
|
163
|
+
*/
|
|
164
|
+
export async function* prepareSameTarget429Wait(
|
|
165
|
+
options: SameTarget429WaitOptions,
|
|
166
|
+
): AsyncGenerator<{ type: "heartbeat" }> {
|
|
167
|
+
await releaseResponseBodyBestEffort(options.body, options.signal);
|
|
168
|
+
if (options.heartbeatIntervalMs === undefined) {
|
|
169
|
+
await sleepWithAbort(options.delayMs, options.signal);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
yield* sleepWithHeartbeats(options.delayMs, options.signal, options.heartbeatIntervalMs);
|
|
173
|
+
}
|
|
174
|
+
|
|
74
175
|
export function isConnectionResetError(err: unknown): boolean {
|
|
75
176
|
if (!(err instanceof Error)) return false;
|
|
76
177
|
// Aborts and timeouts are caller decisions / honest failures — never retryable.
|
|
@@ -114,6 +215,7 @@ export async function fetchWithAttemptDeadline(
|
|
|
114
215
|
timeoutMs: number,
|
|
115
216
|
abortSignal?: AbortSignal,
|
|
116
217
|
preferIdentityEncoding = false,
|
|
218
|
+
executor: typeof globalThis.fetch = globalThis.fetch,
|
|
117
219
|
): Promise<Response> {
|
|
118
220
|
const attemptTimeout = clearableDeadline(timeoutMs, abortSignal);
|
|
119
221
|
const headers = new Headers(init.headers);
|
|
@@ -121,7 +223,7 @@ export async function fetchWithAttemptDeadline(
|
|
|
121
223
|
headers.set("accept-encoding", "identity");
|
|
122
224
|
}
|
|
123
225
|
try {
|
|
124
|
-
return await
|
|
226
|
+
return await executor(url, {
|
|
125
227
|
...init,
|
|
126
228
|
headers,
|
|
127
229
|
signal: attemptTimeout.signal,
|
|
@@ -148,6 +250,39 @@ export interface TransientRetryOptions extends ResetRetryOptions {
|
|
|
148
250
|
export type UpstreamSendRecovery = "connection-reset" | "transient-5xx";
|
|
149
251
|
type ReplayableFetch = (recovery?: UpstreamSendRecovery) => Promise<Response>;
|
|
150
252
|
|
|
253
|
+
/**
|
|
254
|
+
* Rejection thrown by the upstream retry helpers when the terminal attempt
|
|
255
|
+
* rejects after earlier attempts already produced credential-visible evidence:
|
|
256
|
+
* transient 5xx responses, or a connection reset after the request was read.
|
|
257
|
+
*
|
|
258
|
+
* That evidence proves the host and credential path were reached, so the
|
|
259
|
+
* failure must stay account-attributed even though the terminal promise looks
|
|
260
|
+
* like a transport rejection (issue #914 review: mixed 5xx/reset -> rejection
|
|
261
|
+
* must not be downgraded to the account-neutral pre-connection class). The
|
|
262
|
+
* original rejection is preserved as `cause` so its code and message stay
|
|
263
|
+
* inspectable. Extracted from PR #966 (Yuxin-Qiao) with attribution.
|
|
264
|
+
*/
|
|
265
|
+
export class UpstreamRetryEvidenceError extends Error {
|
|
266
|
+
constructor(
|
|
267
|
+
public readonly transientStatuses: readonly number[],
|
|
268
|
+
cause: unknown,
|
|
269
|
+
/** True when a connection-reset retry already reached the origin. */
|
|
270
|
+
public readonly resetSeen = false,
|
|
271
|
+
) {
|
|
272
|
+
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
273
|
+
const kinds: string[] = [];
|
|
274
|
+
if (transientStatuses.length > 0) kinds.push("transient 5xx response(s)");
|
|
275
|
+
if (resetSeen) kinds.push("a credential-visible connection reset");
|
|
276
|
+
super(
|
|
277
|
+
kinds.length > 0
|
|
278
|
+
? `upstream fetch failed after ${kinds.join(" and ")}: ${detail}`
|
|
279
|
+
: `upstream fetch failed: ${detail}`,
|
|
280
|
+
{ cause },
|
|
281
|
+
);
|
|
282
|
+
this.name = "UpstreamRetryEvidenceError";
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
151
286
|
/**
|
|
152
287
|
* Opt out of Bun's keep-alive pool after a connection-reset retry.
|
|
153
288
|
*
|
|
@@ -181,12 +316,22 @@ export async function fetchWithResetRetry(
|
|
|
181
316
|
): Promise<Response> {
|
|
182
317
|
const attempts = Math.max(1, opts.attempts ?? RESET_RETRY_MAX_ATTEMPTS);
|
|
183
318
|
let lastError: unknown;
|
|
319
|
+
let sawReset = false;
|
|
184
320
|
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
185
321
|
if (opts.abortSignal?.aborted) throw abortError(opts.abortSignal);
|
|
186
322
|
try {
|
|
187
323
|
return await doFetch(attempt === 0 ? firstRecovery : "connection-reset");
|
|
188
324
|
} catch (err) {
|
|
189
|
-
if (opts.abortSignal?.aborted
|
|
325
|
+
if (opts.abortSignal?.aborted) throw err;
|
|
326
|
+
if (!isConnectionResetError(err)) {
|
|
327
|
+
// A reset that already reached the origin is credential-visible
|
|
328
|
+
// evidence: keep it attached so the terminal rejection cannot be
|
|
329
|
+
// downgraded to the pre-connection neutral class (#914 review).
|
|
330
|
+
if (sawReset) throw new UpstreamRetryEvidenceError([], err, true);
|
|
331
|
+
throw err;
|
|
332
|
+
}
|
|
333
|
+
if (attempt === attempts - 1) throw err;
|
|
334
|
+
sawReset = true;
|
|
190
335
|
lastError = err;
|
|
191
336
|
console.warn(
|
|
192
337
|
`[upstream-retry] connection reset${opts.label ? ` (${opts.label})` : ""} — retrying (${attempt + 2}/${attempts})`,
|
|
@@ -216,6 +361,7 @@ export async function fetchWithTransientRetry(
|
|
|
216
361
|
): Promise<Response> {
|
|
217
362
|
const attempts = Math.max(1, opts.attempts ?? TRANSIENT_RETRY_MAX_ATTEMPTS);
|
|
218
363
|
const slowAttemptMs = opts.slowAttemptMs ?? TRANSIENT_RETRY_SLOW_ATTEMPT_MS;
|
|
364
|
+
const transientStatuses: number[] = [];
|
|
219
365
|
let attemptStart = Date.now();
|
|
220
366
|
let res = await fetchWithResetRetry(doFetch, opts);
|
|
221
367
|
for (let attempt = 0; attempt < attempts - 1; attempt++) {
|
|
@@ -233,7 +379,14 @@ export async function fetchWithTransientRetry(
|
|
|
233
379
|
cancelResponseBodyBestEffort(res);
|
|
234
380
|
await sleepWithAbort(delay, opts.abortSignal);
|
|
235
381
|
attemptStart = Date.now();
|
|
236
|
-
res
|
|
382
|
+
transientStatuses.push(res.status);
|
|
383
|
+
try {
|
|
384
|
+
res = await fetchWithResetRetry(doFetch, opts, "transient-5xx");
|
|
385
|
+
} catch (err) {
|
|
386
|
+
// Keep the prior 5xx evidence attached: the origin already responded, so
|
|
387
|
+
// this rejection is not pre-connection and must not classify as neutral.
|
|
388
|
+
throw new UpstreamRetryEvidenceError(transientStatuses, err);
|
|
389
|
+
}
|
|
237
390
|
}
|
|
238
391
|
return res;
|
|
239
392
|
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Windows-tolerant atomic replace.
|
|
3
|
+
*
|
|
4
|
+
* POSIX `rename()` replaces the destination entry unconditionally. Windows can
|
|
5
|
+
* refuse the same call with EBUSY, EPERM or EACCES while another process holds
|
|
6
|
+
* the target open — a real-time scanner that just indexed the file, a sync
|
|
7
|
+
* client, a backup agent. The hold is usually momentary, so a bounded retry
|
|
8
|
+
* turns an operational failure back into a successful publish.
|
|
9
|
+
*
|
|
10
|
+
* The envelope is deliberately small: two retries, 25ms then 50ms, about 75ms
|
|
11
|
+
* total. It is sized for a scanner blinking, not for a file someone actually
|
|
12
|
+
* has open. Widening it without evidence would trade a rare failure for a
|
|
13
|
+
* routine stall.
|
|
14
|
+
*
|
|
15
|
+
* This lives in its own module rather than in config.ts because
|
|
16
|
+
* config-ownership.ts is one of its callers and config.ts already imports
|
|
17
|
+
* config-ownership.ts — exporting it from there would close an import cycle.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { renameSync } from "node:fs";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Which durable publisher retried. A closed union on purpose: the value is a
|
|
24
|
+
* label in a diagnostic surface, and a path-derived string could carry a
|
|
25
|
+
* username. The type is the enforcement — a path cannot be passed here without
|
|
26
|
+
* failing typecheck. (`privacy:scan` reads file text and cannot see a runtime
|
|
27
|
+
* value, so it is a backstop for the response body, not the guard.)
|
|
28
|
+
*/
|
|
29
|
+
export type ReplacePublisher =
|
|
30
|
+
| "config"
|
|
31
|
+
| "prompt-journal"
|
|
32
|
+
| "config-ownership"
|
|
33
|
+
| "claude-agents"
|
|
34
|
+
| "lab-automation"
|
|
35
|
+
| "lab-ledger"
|
|
36
|
+
| "storage-cleanup"
|
|
37
|
+
| "tray";
|
|
38
|
+
|
|
39
|
+
/** The Windows error codes this module treats as a momentary hold. */
|
|
40
|
+
export type ReplaceRetryCode = "EBUSY" | "EPERM" | "EACCES";
|
|
41
|
+
|
|
42
|
+
export interface ReplaceRetryCounts {
|
|
43
|
+
/** Replaces that hit this code and were retried. */
|
|
44
|
+
retried: number;
|
|
45
|
+
/** Replaces that exhausted every retry and threw. */
|
|
46
|
+
exhausted: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Keyed by publisher AND code. The code is the diagnostic half: EBUSY from a
|
|
51
|
+
* scanner, EACCES from a permissions problem and EPERM from a lock are three
|
|
52
|
+
* different stories, and collapsing them would leave the counters unable to
|
|
53
|
+
* answer the question they exist for.
|
|
54
|
+
*/
|
|
55
|
+
const counters = new Map<string, ReplaceRetryCounts>();
|
|
56
|
+
|
|
57
|
+
function counterKey(publisher: ReplacePublisher, code: ReplaceRetryCode): string {
|
|
58
|
+
return `${publisher}:${code}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function bump(
|
|
62
|
+
publisher: ReplacePublisher,
|
|
63
|
+
code: ReplaceRetryCode,
|
|
64
|
+
field: keyof ReplaceRetryCounts,
|
|
65
|
+
): void {
|
|
66
|
+
const key = counterKey(publisher, code);
|
|
67
|
+
const current = counters.get(key) ?? { retried: 0, exhausted: 0 };
|
|
68
|
+
current[field] += 1;
|
|
69
|
+
counters.set(key, current);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Process-lifetime snapshot, keyed `publisher:CODE`. These reset on restart,
|
|
74
|
+
* which is fine: the question they answer is "does this ever fire at all", not
|
|
75
|
+
* "how often per hour".
|
|
76
|
+
*/
|
|
77
|
+
export function readWindowsReplaceRetryCounters(): Record<string, ReplaceRetryCounts> {
|
|
78
|
+
const out: Record<string, ReplaceRetryCounts> = {};
|
|
79
|
+
for (const [key, counts] of counters) out[key] = { ...counts };
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Test-only: the counters are module state and cases must not leak into each other. */
|
|
84
|
+
export function resetWindowsReplaceRetryCountersForTests(): void {
|
|
85
|
+
counters.clear();
|
|
86
|
+
}
|
|
87
|
+
export interface AtomicRenameIO {
|
|
88
|
+
platform: NodeJS.Platform;
|
|
89
|
+
rename: (source: string, destination: string) => void;
|
|
90
|
+
sleep: (milliseconds: number) => void;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const MAX_RETRIES = 2;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Windows sharing violations only, returning the code so the caller can record
|
|
97
|
+
* which one. Any other error is the caller's to see, immediately.
|
|
98
|
+
*/
|
|
99
|
+
function transientWindowsReplaceCode(
|
|
100
|
+
platform: NodeJS.Platform,
|
|
101
|
+
error: unknown,
|
|
102
|
+
): ReplaceRetryCode | null {
|
|
103
|
+
if (platform !== "win32") return null;
|
|
104
|
+
const code = (error as NodeJS.ErrnoException).code;
|
|
105
|
+
return code === "EBUSY" || code === "EPERM" || code === "EACCES" ? code : null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function renameAtomicFile(
|
|
109
|
+
source: string,
|
|
110
|
+
destination: string,
|
|
111
|
+
io: AtomicRenameIO = {
|
|
112
|
+
platform: process.platform,
|
|
113
|
+
rename: renameSync,
|
|
114
|
+
sleep: Bun.sleepSync,
|
|
115
|
+
},
|
|
116
|
+
publisher: ReplacePublisher = "config",
|
|
117
|
+
): void {
|
|
118
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
119
|
+
try {
|
|
120
|
+
io.rename(source, destination);
|
|
121
|
+
return;
|
|
122
|
+
} catch (error) {
|
|
123
|
+
const code = transientWindowsReplaceCode(io.platform, error);
|
|
124
|
+
if (!code) throw error;
|
|
125
|
+
if (attempt >= MAX_RETRIES) {
|
|
126
|
+
bump(publisher, code, "exhausted");
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
bump(publisher, code, "retried");
|
|
130
|
+
io.sleep(25 * (attempt + 1));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export async function renameAtomicFileAsync(
|
|
136
|
+
source: string,
|
|
137
|
+
destination: string,
|
|
138
|
+
publisher: ReplacePublisher = "config",
|
|
139
|
+
): Promise<void> {
|
|
140
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
141
|
+
try {
|
|
142
|
+
renameSync(source, destination);
|
|
143
|
+
return;
|
|
144
|
+
} catch (error) {
|
|
145
|
+
const code = transientWindowsReplaceCode(process.platform, error);
|
|
146
|
+
if (!code) throw error;
|
|
147
|
+
if (attempt >= MAX_RETRIES) {
|
|
148
|
+
bump(publisher, code, "exhausted");
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
bump(publisher, code, "retried");
|
|
152
|
+
await Bun.sleep(25 * (attempt + 1));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -21,6 +21,13 @@ type TrustedSystemDirectoryResolver = () => string;
|
|
|
21
21
|
type IsUserAnAdmin = () => number;
|
|
22
22
|
type WindowsElevationProbe = () => boolean | null;
|
|
23
23
|
|
|
24
|
+
export class WindowsSystemDirectoryFfiUnavailableError extends Error {
|
|
25
|
+
constructor() {
|
|
26
|
+
super("Failed to load GetSystemDirectoryW from kernel32.dll.");
|
|
27
|
+
this.name = "WindowsSystemDirectoryFfiUnavailableError";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
24
31
|
let getSystemDirectoryWFn: GetSystemDirectoryW | null | undefined;
|
|
25
32
|
let trustedSystemDirectoryResolverForTests: TrustedSystemDirectoryResolver | null = null;
|
|
26
33
|
let isUserAnAdminFn: (() => boolean) | null | undefined;
|
|
@@ -114,7 +121,7 @@ export function resolveTrustedWindowsSystemDirectory(): string {
|
|
|
114
121
|
}
|
|
115
122
|
const getSystemDirectoryW = loadGetSystemDirectoryW();
|
|
116
123
|
if (!getSystemDirectoryW) {
|
|
117
|
-
throw new
|
|
124
|
+
throw new WindowsSystemDirectoryFfiUnavailableError();
|
|
118
125
|
}
|
|
119
126
|
|
|
120
127
|
let size = 260;
|
|
@@ -168,7 +175,7 @@ export function assertTrustedSystemExecutableForTests(candidate: string, label:
|
|
|
168
175
|
return assertTrustedSystemExecutable(candidate, label);
|
|
169
176
|
}
|
|
170
177
|
|
|
171
|
-
type ElevationExeOverrides = { powershell?: string; schtasks?: string };
|
|
178
|
+
type ElevationExeOverrides = { powershell?: string; schtasks?: string; taskkill?: string; icacls?: string };
|
|
172
179
|
let elevationExeOverridesForTests: ElevationExeOverrides | null = null;
|
|
173
180
|
|
|
174
181
|
/**
|
|
@@ -204,6 +211,24 @@ export function resolveTrustedWindowsSchtasksExe(): string {
|
|
|
204
211
|
return assertTrustedSystemExecutable(candidate, "schtasks.exe");
|
|
205
212
|
}
|
|
206
213
|
|
|
214
|
+
/** Absolute path to System32\\taskkill.exe from a trusted system directory. */
|
|
215
|
+
export function resolveTrustedWindowsTaskkillExe(): string {
|
|
216
|
+
if (elevationExeOverridesForTests?.taskkill) {
|
|
217
|
+
return elevationExeOverridesForTests.taskkill;
|
|
218
|
+
}
|
|
219
|
+
const candidate = join(resolveTrustedWindowsSystemDirectory(), "taskkill.exe");
|
|
220
|
+
return assertTrustedSystemExecutable(candidate, "taskkill.exe");
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** Absolute path to System32\\icacls.exe from a trusted system directory. */
|
|
224
|
+
export function resolveTrustedWindowsIcaclsExe(): string {
|
|
225
|
+
if (elevationExeOverridesForTests?.icacls) {
|
|
226
|
+
return elevationExeOverridesForTests.icacls;
|
|
227
|
+
}
|
|
228
|
+
const candidate = join(resolveTrustedWindowsSystemDirectory(), "icacls.exe");
|
|
229
|
+
return assertTrustedSystemExecutable(candidate, "icacls.exe");
|
|
230
|
+
}
|
|
231
|
+
|
|
207
232
|
/** Stable machine-readable marker for a denied `schtasks /create`. Crosses the CLI→proxy boundary. */
|
|
208
233
|
export const WINDOWS_SCHTASKS_CREATE_ACCESS_DENIED_MARKER =
|
|
209
234
|
"OCX_ERROR_CODE=WINDOWS_SCHTASKS_CREATE_ACCESS_DENIED";
|
|
@@ -605,6 +630,49 @@ export function runWindowsElevated(file: string, args: string[]): Promise<number
|
|
|
605
630
|
return startPowerShellCommand(script).completion.then(result => result.exitCode);
|
|
606
631
|
}
|
|
607
632
|
|
|
633
|
+
/**
|
|
634
|
+
* Register one scheduled-task definition without exposing a mutable XML pathname to
|
|
635
|
+
* the elevated process. The XML bytes are fixed in the encoded PowerShell command
|
|
636
|
+
* before UAC; Register-ScheduledTask receives that string directly after elevation.
|
|
637
|
+
*/
|
|
638
|
+
export function runWindowsElevatedScheduledTaskRegistration(
|
|
639
|
+
taskName: string,
|
|
640
|
+
xml: string,
|
|
641
|
+
): Promise<number> {
|
|
642
|
+
const xmlBase64 = Buffer.from(xml, "utf16le").toString("base64");
|
|
643
|
+
const powerShellPath = windowsPowerShell();
|
|
644
|
+
const powerShellDirectory = powerShellPath.replace(/[\\/][^\\/]+$/, "");
|
|
645
|
+
const scheduledTasksModule = `${powerShellDirectory}\\Modules\\ScheduledTasks\\ScheduledTasks.psd1`;
|
|
646
|
+
const inner = [
|
|
647
|
+
`$taskName = ${psSingleQuote(taskName)}`,
|
|
648
|
+
`$xmlBase64 = ${psSingleQuote(xmlBase64)}`,
|
|
649
|
+
"$xml = [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($xmlBase64))",
|
|
650
|
+
`$module = Microsoft.PowerShell.Core\\Import-Module -Name ${psSingleQuote(scheduledTasksModule)} -PassThru -Force -ErrorAction Stop`,
|
|
651
|
+
"$registerTask = $module.ExportedCommands['Register-ScheduledTask']",
|
|
652
|
+
"if ($null -eq $registerTask) { throw 'Trusted ScheduledTasks module does not export Register-ScheduledTask.' }",
|
|
653
|
+
"& $registerTask -TaskName $taskName -Xml $xml -Force -ErrorAction Stop | Out-Null",
|
|
654
|
+
].join("; ");
|
|
655
|
+
const encodedCommand = Buffer.from(inner, "utf16le").toString("base64");
|
|
656
|
+
const script = [
|
|
657
|
+
`$p = Start-Process -FilePath ${psSingleQuote(powerShellPath)}`,
|
|
658
|
+
` -ArgumentList ${psSingleQuote(buildWindowsElevatedArgumentList([
|
|
659
|
+
"-NoProfile",
|
|
660
|
+
"-NonInteractive",
|
|
661
|
+
"-ExecutionPolicy",
|
|
662
|
+
"Bypass",
|
|
663
|
+
"-EncodedCommand",
|
|
664
|
+
encodedCommand,
|
|
665
|
+
]))}`,
|
|
666
|
+
" -Verb RunAs -WindowStyle Hidden -PassThru -Wait;",
|
|
667
|
+
`if ($null -eq $p) { exit ${OCX_ELEVATED_UAC_CANCELLED} }`,
|
|
668
|
+
"$null = $p.Handle;",
|
|
669
|
+
`if ($null -eq $p.ExitCode) { exit ${OCX_ELEVATED_PROTOCOL_FAILED} }`,
|
|
670
|
+
"exit $p.ExitCode",
|
|
671
|
+
].join("");
|
|
672
|
+
|
|
673
|
+
return startPowerShellCommand(script).completion.then(result => result.exitCode);
|
|
674
|
+
}
|
|
675
|
+
|
|
608
676
|
/**
|
|
609
677
|
* Build the elevated (post-UAC) script: create → run → optional delete rollback.
|
|
610
678
|
* Returns only OpenCodex protocol exit codes (never raw schtasks codes, never 1223).
|