@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
|
@@ -168,6 +168,45 @@ export function decodeAvailableConnectFrames(
|
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Cursor-based sibling of decodeAvailableConnectFrames for callers that keep
|
|
173
|
+
* their own raw backlog: consumes complete frames from the FRONT of `input`
|
|
174
|
+
* and reports how many bytes were consumed (headers included) instead of
|
|
175
|
+
* materializing a remainder copy, and hands payload VIEWS (not copies) back so
|
|
176
|
+
* the caller can transfer the already-charged bytes to the frame lifecycle
|
|
177
|
+
* instead of reserving a second copy. The caller advances its own cursor by
|
|
178
|
+
* `consumedBytes` and never pays an O(backlog) copy per drain.
|
|
179
|
+
*/
|
|
180
|
+
export function consumeConnectFrames(
|
|
181
|
+
input: Uint8Array,
|
|
182
|
+
maxPayloadBytes = MAX_CONNECT_FRAME_PAYLOAD_BYTES,
|
|
183
|
+
availableFrameSlots = Number.POSITIVE_INFINITY,
|
|
184
|
+
): { frames: ConnectFrame[]; consumedBytes: number } {
|
|
185
|
+
const planned: InspectedConnectFrame[] = [];
|
|
186
|
+
let offset = 0;
|
|
187
|
+
while (offset < input.length && planned.length < availableFrameSlots) {
|
|
188
|
+
const inspected = inspectConnectFrame(input, offset, maxPayloadBytes);
|
|
189
|
+
if (!inspected) break;
|
|
190
|
+
planned.push(inspected);
|
|
191
|
+
offset += inspected.readBytes;
|
|
192
|
+
}
|
|
193
|
+
// Zero-copy handoff for large payloads: VIEWS into the caller's backlog
|
|
194
|
+
// buffer (safe: append-only at its end, compaction/growth replace the
|
|
195
|
+
// buffer, a consumed region is never mutated in place). Small payloads are
|
|
196
|
+
// COPIED instead — a small view would pin the whole backlog buffer (up to
|
|
197
|
+
// 32 MiB) alive while the frame waits in the work queue.
|
|
198
|
+
const COPY_PIN_THRESHOLD_BYTES = 64 * 1024;
|
|
199
|
+
const frames = planned.map(({ flags, length, payloadStart }) => ({
|
|
200
|
+
flags,
|
|
201
|
+
payload: length <= COPY_PIN_THRESHOLD_BYTES
|
|
202
|
+
? input.slice(payloadStart, payloadStart + length)
|
|
203
|
+
: input.subarray(payloadStart, payloadStart + length),
|
|
204
|
+
compressed: isConnectFrameCompressed(flags),
|
|
205
|
+
endStream: isConnectFrameEndStream(flags),
|
|
206
|
+
}));
|
|
207
|
+
return { frames, consumedBytes: offset };
|
|
208
|
+
}
|
|
209
|
+
|
|
171
210
|
function inspectConnectFrame(
|
|
172
211
|
input: Uint8Array,
|
|
173
212
|
offset: number,
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import http2 from "node:http2";
|
|
2
|
+
import { registerOptionalShutdownHook } from "../../lib/optional-shutdown-hooks";
|
|
3
|
+
|
|
4
|
+
const DEFAULT_MAX_SESSIONS = 8;
|
|
5
|
+
const SESSION_CLOSE_TIMEOUT_MS = 2_000;
|
|
6
|
+
|
|
7
|
+
interface PoolEntry {
|
|
8
|
+
readonly session: http2.ClientHttp2Session;
|
|
9
|
+
readonly streams: Set<http2.ClientHttp2Stream>;
|
|
10
|
+
usable: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* HTTP/2 connection pool for Cursor Connect DISCOVERY calls (GetUsableModels).
|
|
15
|
+
* Sessions are keyed by origin (scheme+host+port) and reused to avoid fresh
|
|
16
|
+
* TCP+TLS per call. The Run path deliberately dials its own session: Run
|
|
17
|
+
* streams are long-lived bidi whose lifecycle/EOF semantics are owned by
|
|
18
|
+
* live-transport (see devlog 260822_senpi_cursor_transfer/190 — Run-path
|
|
19
|
+
* pooling is a separate, deliberate unit if ever taken).
|
|
20
|
+
*/
|
|
21
|
+
export class CursorH2SessionPool {
|
|
22
|
+
private readonly entries = new Map<string, PoolEntry>();
|
|
23
|
+
private closed = false;
|
|
24
|
+
|
|
25
|
+
constructor(private readonly maxSessions = DEFAULT_MAX_SESSIONS) {}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Lazily registered on first use so a process that never talks to Cursor registers
|
|
29
|
+
* nothing (optional-subsystem doctrine). The seam is synchronous and best-effort;
|
|
30
|
+
* shutdown() is fire-and-forget there because lifecycle's drainAndShutdown runs
|
|
31
|
+
* under its own absolute deadline.
|
|
32
|
+
*/
|
|
33
|
+
private armShutdownHook: (() => void) | undefined = () => {
|
|
34
|
+
this.armShutdownHook = undefined;
|
|
35
|
+
registerOptionalShutdownHook("cursor-h2-pool", () => { void this.shutdown(); });
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
request(
|
|
39
|
+
url: string,
|
|
40
|
+
headers: http2.OutgoingHttpHeaders,
|
|
41
|
+
): http2.ClientHttp2Stream {
|
|
42
|
+
if (this.closed) throw new Error("Cursor H2 session pool is closed");
|
|
43
|
+
this.armShutdownHook?.();
|
|
44
|
+
const origin = new URL(url).origin;
|
|
45
|
+
const entry = this.usableEntry(origin) ?? this.createEntry(origin);
|
|
46
|
+
try {
|
|
47
|
+
const stream = entry.session.request(headers);
|
|
48
|
+
entry.streams.add(stream);
|
|
49
|
+
stream.once("close", () => { entry.streams.delete(stream); });
|
|
50
|
+
return stream;
|
|
51
|
+
} catch (error) {
|
|
52
|
+
this.drain(entry, true);
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async shutdown(): Promise<void> {
|
|
58
|
+
if (this.closed) return;
|
|
59
|
+
this.closed = true;
|
|
60
|
+
const pending: Promise<void>[] = [];
|
|
61
|
+
for (const entry of [...this.entries.values()]) {
|
|
62
|
+
for (const stream of [...entry.streams]) stream.destroy();
|
|
63
|
+
entry.session.close();
|
|
64
|
+
if (entry.session.destroyed) continue;
|
|
65
|
+
pending.push(new Promise<void>(resolve => {
|
|
66
|
+
const timer = setTimeout(resolve, SESSION_CLOSE_TIMEOUT_MS);
|
|
67
|
+
timer.unref?.();
|
|
68
|
+
entry.session.once("close", () => { clearTimeout(timer); resolve(); });
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
this.entries.clear();
|
|
72
|
+
await Promise.all(pending);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
get size(): number { return this.entries.size; }
|
|
76
|
+
|
|
77
|
+
private usableEntry(origin: string): PoolEntry | undefined {
|
|
78
|
+
const entry = this.entries.get(origin);
|
|
79
|
+
if (!entry) return undefined;
|
|
80
|
+
if (entry.usable && !entry.session.closed && !entry.session.destroyed) return entry;
|
|
81
|
+
this.drain(entry, false);
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private createEntry(origin: string): PoolEntry {
|
|
86
|
+
const session = http2.connect(origin);
|
|
87
|
+
const entry: PoolEntry = {
|
|
88
|
+
session,
|
|
89
|
+
streams: new Set(),
|
|
90
|
+
usable: true,
|
|
91
|
+
};
|
|
92
|
+
this.entries.set(origin, entry);
|
|
93
|
+
session.once("goaway", () => { this.drain(entry, true); });
|
|
94
|
+
session.on("error", () => { this.drain(entry, false); });
|
|
95
|
+
session.once("close", () => {
|
|
96
|
+
// Identity check: a stale close event from an old session must not evict
|
|
97
|
+
// a healthy replacement entry that was created after drain() removed the old one.
|
|
98
|
+
if (this.entries.get(origin) === entry) this.entries.delete(origin);
|
|
99
|
+
});
|
|
100
|
+
// Enforce bound: evict oldest when over capacity.
|
|
101
|
+
while (this.entries.size > this.maxSessions) {
|
|
102
|
+
const oldest = this.entries.keys().next().value;
|
|
103
|
+
if (!oldest || oldest === origin) break;
|
|
104
|
+
const old = this.entries.get(oldest);
|
|
105
|
+
if (old) this.drain(old, true);
|
|
106
|
+
}
|
|
107
|
+
return entry;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private drain(entry: PoolEntry, closeSession: boolean): void {
|
|
111
|
+
entry.usable = false;
|
|
112
|
+
for (const stream of [...entry.streams]) stream.destroy();
|
|
113
|
+
entry.streams.clear();
|
|
114
|
+
if (closeSession) entry.session.close();
|
|
115
|
+
// Remove from map by finding the matching key.
|
|
116
|
+
for (const [key, value] of this.entries) {
|
|
117
|
+
if (value === entry) { this.entries.delete(key); break; }
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Shared singleton pool for all Cursor adapter H2 traffic. */
|
|
123
|
+
export const cursorH2Pool = new CursorH2SessionPool();
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
import { create, toBinary } from "@bufbuild/protobuf";
|
|
2
|
+
import type { TranslatorBudget } from "../../lib/translator-budget";
|
|
3
|
+
import { CURSOR_MAX_EFFECTIVE_CONNECT_PAYLOAD_BYTES } from "../../lib/translator-budget";
|
|
4
|
+
import { readBoundedResponseBytes } from "../../lib/bounded-body";
|
|
5
|
+
import { withUpstreamHttpVersionValue } from "../../lib/upstream-http-version";
|
|
6
|
+
import { isPreConnectReachabilityError } from "../../lib/upstream-reachability";
|
|
7
|
+
import { BidiRequestIdSchema } from "./gen/agent_pb";
|
|
8
|
+
import { consumeConnectFrames, encodeConnectFrame } from "./framing";
|
|
9
|
+
|
|
10
|
+
const CURSOR_RUN_SSE_PATH = "/agent.v1.AgentService/RunSSE";
|
|
11
|
+
const CURSOR_BIDI_APPEND_PATH = "/aiserver.v1.BidiService/BidiAppend";
|
|
12
|
+
const CURSOR_HTTP1_APPEND_TIMEOUT_MS = 30_000;
|
|
13
|
+
const CURSOR_HTTP1_APPEND_RESPONSE_MAX_BYTES = 64 * 1024;
|
|
14
|
+
const HEX = "0123456789abcdef";
|
|
15
|
+
|
|
16
|
+
export interface CursorHttp1BidiCallbacks {
|
|
17
|
+
onCommitted(): void;
|
|
18
|
+
onData(chunk: Uint8Array): void;
|
|
19
|
+
onEnd(): void;
|
|
20
|
+
onError(error: Error): void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface CursorHttp1BidiOptions {
|
|
24
|
+
baseUrl: string;
|
|
25
|
+
token: string;
|
|
26
|
+
clientVersion: string;
|
|
27
|
+
sessionId: string;
|
|
28
|
+
requestId: string;
|
|
29
|
+
translatorBudget: TranslatorBudget;
|
|
30
|
+
callbacks: CursorHttp1BidiCallbacks;
|
|
31
|
+
fetch?: typeof globalThis.fetch;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface PendingAppend {
|
|
35
|
+
payload: Uint8Array;
|
|
36
|
+
seqno: bigint;
|
|
37
|
+
rawBytesCharged: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function varintLength(value: bigint): number {
|
|
41
|
+
let length = 1;
|
|
42
|
+
for (let current = value; current >= 0x80n; current >>= 7n) length += 1;
|
|
43
|
+
return length;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function writeVarint(target: Uint8Array, offset: number, value: bigint): number {
|
|
47
|
+
let current = value;
|
|
48
|
+
while (current >= 0x80n) {
|
|
49
|
+
target[offset++] = Number(current & 0x7fn) | 0x80;
|
|
50
|
+
current >>= 7n;
|
|
51
|
+
}
|
|
52
|
+
target[offset++] = Number(current);
|
|
53
|
+
return offset;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function requestIdMessageBytes(requestId: string): Uint8Array {
|
|
57
|
+
const value = new TextEncoder().encode(requestId);
|
|
58
|
+
const message = new Uint8Array(1 + varintLength(BigInt(value.byteLength)) + value.byteLength);
|
|
59
|
+
let offset = 0;
|
|
60
|
+
message[offset++] = 0x0a; // field 1, string request_id
|
|
61
|
+
offset = writeVarint(message, offset, BigInt(value.byteLength));
|
|
62
|
+
message.set(value, offset);
|
|
63
|
+
return message;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Exact encoded size of Cursor's aiserver.v1.BidiAppendRequest hex fallback shape. */
|
|
67
|
+
export function cursorBidiAppendRequestSize(payloadBytes: number, requestId: string, seqno: bigint): number {
|
|
68
|
+
const hexBytes = payloadBytes * 2;
|
|
69
|
+
const requestIdBytes = requestIdMessageBytes(requestId).byteLength;
|
|
70
|
+
return (hexBytes > 0 ? 1 + varintLength(BigInt(hexBytes)) + hexBytes : 0)
|
|
71
|
+
+ 1 + varintLength(BigInt(requestIdBytes)) + requestIdBytes
|
|
72
|
+
+ (seqno > 0n ? 1 + varintLength(seqno) : 0);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Encode the compatibility request used by Cursor when HTTP/2 is disabled.
|
|
77
|
+
* The public client defaults to field 1's hexadecimal data when its binary-append
|
|
78
|
+
* feature gate is unavailable, so OpenCodex uses that backwards-compatible shape.
|
|
79
|
+
*/
|
|
80
|
+
export function encodeCursorBidiAppendRequest(
|
|
81
|
+
payload: Uint8Array,
|
|
82
|
+
requestId: string,
|
|
83
|
+
seqno: bigint,
|
|
84
|
+
): Uint8Array {
|
|
85
|
+
const requestIdBytes = requestIdMessageBytes(requestId);
|
|
86
|
+
const output = new Uint8Array(cursorBidiAppendRequestSize(payload.byteLength, requestId, seqno));
|
|
87
|
+
let offset = 0;
|
|
88
|
+
if (payload.byteLength > 0) {
|
|
89
|
+
const hexBytes = payload.byteLength * 2;
|
|
90
|
+
output[offset++] = 0x0a; // field 1, string data
|
|
91
|
+
offset = writeVarint(output, offset, BigInt(hexBytes));
|
|
92
|
+
for (const byte of payload) {
|
|
93
|
+
output[offset++] = HEX.charCodeAt(byte >>> 4);
|
|
94
|
+
output[offset++] = HEX.charCodeAt(byte & 0x0f);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
output[offset++] = 0x12; // field 2, BidiRequestId request_id
|
|
98
|
+
offset = writeVarint(output, offset, BigInt(requestIdBytes.byteLength));
|
|
99
|
+
output.set(requestIdBytes, offset);
|
|
100
|
+
offset += requestIdBytes.byteLength;
|
|
101
|
+
if (seqno > 0n) {
|
|
102
|
+
output[offset++] = 0x18; // field 3, int64 append_seqno
|
|
103
|
+
offset = writeVarint(output, offset, seqno);
|
|
104
|
+
}
|
|
105
|
+
return output;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function cursorHttp1Error(operation: "RunSSE" | "BidiAppend", status: number): Error {
|
|
109
|
+
return new Error(`Cursor HTTP/1.1 ${operation} failed with HTTP ${status || "unknown"}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function asError(error: unknown): Error {
|
|
113
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Bun accepts Uint8Array request bodies; TypeScript's DOM BodyInit omits that runtime shape. */
|
|
117
|
+
function bunFetchBody(bytes: Uint8Array): BodyInit {
|
|
118
|
+
return bytes as unknown as BodyInit;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Cursor's HTTP/1.1 compatibility bridge: a server-streaming RunSSE request carries
|
|
123
|
+
* output, while each client message is posted separately through BidiAppend.
|
|
124
|
+
*/
|
|
125
|
+
export class CursorHttp1BidiConnection {
|
|
126
|
+
private readonly abortController = new AbortController();
|
|
127
|
+
private readonly fetchImpl: typeof globalThis.fetch;
|
|
128
|
+
private readonly runSseReady: Promise<void>;
|
|
129
|
+
private resolveRunSseReady!: () => void;
|
|
130
|
+
private rejectRunSseReady!: (reason?: unknown) => void;
|
|
131
|
+
private appendChain: Promise<void> = Promise.resolve();
|
|
132
|
+
private nextAppendSeqno = 0n;
|
|
133
|
+
private committed = false;
|
|
134
|
+
private paused = false;
|
|
135
|
+
private resumeWaiters: Array<() => void> = [];
|
|
136
|
+
private terminal = false;
|
|
137
|
+
private closed = false;
|
|
138
|
+
destroyed = false;
|
|
139
|
+
|
|
140
|
+
constructor(private readonly options: CursorHttp1BidiOptions) {
|
|
141
|
+
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
142
|
+
this.runSseReady = new Promise<void>((resolve, reject) => {
|
|
143
|
+
this.resolveRunSseReady = resolve;
|
|
144
|
+
this.rejectRunSseReady = reject;
|
|
145
|
+
});
|
|
146
|
+
// A RunSSE failure can happen before the first append reaches its await; observe it here so
|
|
147
|
+
// the readiness promise never becomes an unhandled rejection.
|
|
148
|
+
void this.runSseReady.catch(() => undefined);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
start(): void {
|
|
152
|
+
void this.runSse().catch(error => {
|
|
153
|
+
this.rejectRunSseReady(error);
|
|
154
|
+
this.fail(asError(error));
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
write(frameBytes: Uint8Array): boolean {
|
|
159
|
+
if (this.closed || this.terminal) return false;
|
|
160
|
+
let frame;
|
|
161
|
+
try {
|
|
162
|
+
const decoded = consumeConnectFrames(frameBytes, CURSOR_MAX_EFFECTIVE_CONNECT_PAYLOAD_BYTES, 2);
|
|
163
|
+
if (decoded.frames.length !== 1 || decoded.consumedBytes !== frameBytes.byteLength) {
|
|
164
|
+
throw new Error("Cursor HTTP/1.1 append requires exactly one complete Connect frame");
|
|
165
|
+
}
|
|
166
|
+
frame = decoded.frames[0]!;
|
|
167
|
+
if (frame.flags !== 0) throw new Error(`Cursor HTTP/1.1 append does not support Connect flags ${frame.flags}`);
|
|
168
|
+
this.options.translatorBudget.chargeRetained(frame.payload.byteLength, { kind: "request_copies" });
|
|
169
|
+
} catch (error) {
|
|
170
|
+
this.fail(asError(error));
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const pending: PendingAppend = {
|
|
175
|
+
payload: frame.payload,
|
|
176
|
+
seqno: this.nextAppendSeqno++,
|
|
177
|
+
rawBytesCharged: true,
|
|
178
|
+
};
|
|
179
|
+
this.appendChain = this.appendChain
|
|
180
|
+
.then(() => this.postAppend(pending))
|
|
181
|
+
.catch(error => this.fail(asError(error)))
|
|
182
|
+
.finally(() => {
|
|
183
|
+
if (!pending.rawBytesCharged) return;
|
|
184
|
+
pending.rawBytesCharged = false;
|
|
185
|
+
this.options.translatorBudget.releaseRetained(pending.payload.byteLength, { kind: "request_copies" });
|
|
186
|
+
});
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
pause(): void {
|
|
191
|
+
this.paused = true;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
resume(): void {
|
|
195
|
+
if (!this.paused) return;
|
|
196
|
+
this.paused = false;
|
|
197
|
+
const waiters = this.resumeWaiters;
|
|
198
|
+
this.resumeWaiters = [];
|
|
199
|
+
for (const resume of waiters) resume();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
close(): void {
|
|
203
|
+
if (this.closed) return;
|
|
204
|
+
this.closed = true;
|
|
205
|
+
this.destroyed = true;
|
|
206
|
+
this.resume();
|
|
207
|
+
const reason = new DOMException("Cursor HTTP/1.1 connection closed", "AbortError");
|
|
208
|
+
this.rejectRunSseReady(reason);
|
|
209
|
+
this.abortController.abort(reason);
|
|
210
|
+
queueMicrotask(() => this.finish());
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
destroy(): void {
|
|
214
|
+
this.close();
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
private commonHeaders(contentType: string): Headers {
|
|
218
|
+
return new Headers({
|
|
219
|
+
"content-type": contentType,
|
|
220
|
+
"connect-protocol-version": "1",
|
|
221
|
+
authorization: `Bearer ${this.options.token}`,
|
|
222
|
+
"x-ghost-mode": "true",
|
|
223
|
+
"x-cursor-client-version": this.options.clientVersion,
|
|
224
|
+
"x-cursor-client-type": "cli",
|
|
225
|
+
"x-request-id": this.options.requestId,
|
|
226
|
+
"x-session-id": this.options.sessionId,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
private requestUrl(path: string): string {
|
|
231
|
+
const url = new URL(path, this.options.baseUrl);
|
|
232
|
+
if (url.protocol !== "https:") {
|
|
233
|
+
throw new Error("Cursor HTTP/1.1 transport requires an HTTPS base URL");
|
|
234
|
+
}
|
|
235
|
+
return url.toString();
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
private http1Init(url: string, init: RequestInit): RequestInit {
|
|
239
|
+
return withUpstreamHttpVersionValue(url, init, "http1.1") ?? init;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
private markCommitted(): void {
|
|
243
|
+
if (this.committed) return;
|
|
244
|
+
this.committed = true;
|
|
245
|
+
this.options.callbacks.onCommitted();
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
private async runSse(): Promise<void> {
|
|
249
|
+
const url = this.requestUrl(CURSOR_RUN_SSE_PATH);
|
|
250
|
+
const requestId = toBinary(BidiRequestIdSchema, create(BidiRequestIdSchema, {
|
|
251
|
+
requestId: this.options.requestId,
|
|
252
|
+
}));
|
|
253
|
+
const response = await this.fetchImpl(url, this.http1Init(url, {
|
|
254
|
+
method: "POST",
|
|
255
|
+
headers: this.commonHeaders("application/connect+proto"),
|
|
256
|
+
body: bunFetchBody(encodeConnectFrame(requestId)),
|
|
257
|
+
redirect: "manual",
|
|
258
|
+
signal: this.abortController.signal,
|
|
259
|
+
}));
|
|
260
|
+
if (response.status !== 200) {
|
|
261
|
+
void response.body?.cancel().catch(() => undefined);
|
|
262
|
+
throw cursorHttp1Error("RunSSE", response.status);
|
|
263
|
+
}
|
|
264
|
+
if (!response.body) throw new Error("Cursor HTTP/1.1 RunSSE returned no response body");
|
|
265
|
+
// Cursor has accepted the request id once RunSSE returns successful headers. Do not race the
|
|
266
|
+
// first BidiAppend ahead of that registration.
|
|
267
|
+
this.resolveRunSseReady();
|
|
268
|
+
const reader = response.body.getReader();
|
|
269
|
+
try {
|
|
270
|
+
while (!this.closed && !this.terminal) {
|
|
271
|
+
await this.waitWhilePaused();
|
|
272
|
+
if (this.closed || this.terminal) break;
|
|
273
|
+
const { value, done } = await reader.read();
|
|
274
|
+
if (done) break;
|
|
275
|
+
if (value && value.byteLength > 0) this.options.callbacks.onData(value);
|
|
276
|
+
}
|
|
277
|
+
this.finish();
|
|
278
|
+
} finally {
|
|
279
|
+
try { reader.releaseLock(); } catch { /* a pending abort may still own it */ }
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
private async postAppend(pending: PendingAppend): Promise<void> {
|
|
284
|
+
if (this.closed || this.terminal) return;
|
|
285
|
+
await this.runSseReady;
|
|
286
|
+
if (this.closed || this.terminal) return;
|
|
287
|
+
const encodedBytes = cursorBidiAppendRequestSize(
|
|
288
|
+
pending.payload.byteLength,
|
|
289
|
+
this.options.requestId,
|
|
290
|
+
pending.seqno,
|
|
291
|
+
);
|
|
292
|
+
const reservation = this.options.translatorBudget.reserveTransient(encodedBytes, { kind: "request_copies" });
|
|
293
|
+
let body: Uint8Array;
|
|
294
|
+
try {
|
|
295
|
+
body = encodeCursorBidiAppendRequest(pending.payload, this.options.requestId, pending.seqno);
|
|
296
|
+
} catch (error) {
|
|
297
|
+
reservation.release();
|
|
298
|
+
throw error;
|
|
299
|
+
}
|
|
300
|
+
if (pending.rawBytesCharged) {
|
|
301
|
+
pending.rawBytesCharged = false;
|
|
302
|
+
this.options.translatorBudget.releaseRetained(pending.payload.byteLength, { kind: "request_copies" });
|
|
303
|
+
}
|
|
304
|
+
try {
|
|
305
|
+
const url = this.requestUrl(CURSOR_BIDI_APPEND_PATH);
|
|
306
|
+
const timeout = AbortSignal.timeout(CURSOR_HTTP1_APPEND_TIMEOUT_MS);
|
|
307
|
+
const signal = AbortSignal.any([this.abortController.signal, timeout]);
|
|
308
|
+
let response: Response;
|
|
309
|
+
try {
|
|
310
|
+
response = await this.fetchImpl(url, this.http1Init(url, {
|
|
311
|
+
method: "POST",
|
|
312
|
+
headers: this.commonHeaders("application/proto"),
|
|
313
|
+
body: bunFetchBody(body),
|
|
314
|
+
redirect: "manual",
|
|
315
|
+
signal,
|
|
316
|
+
}));
|
|
317
|
+
} catch (error) {
|
|
318
|
+
// A proven DNS/TCP pre-connect failure means no append bytes reached Cursor and replay is
|
|
319
|
+
// safe. Every ambiguous rejection stays conservative: the server may have accepted the
|
|
320
|
+
// append before the response path failed, so suppress replay exactly as the h2 path does.
|
|
321
|
+
if (!isPreConnectReachabilityError(error)) this.markCommitted();
|
|
322
|
+
throw error;
|
|
323
|
+
}
|
|
324
|
+
this.markCommitted();
|
|
325
|
+
if (response.status !== 200) {
|
|
326
|
+
void response.body?.cancel().catch(() => undefined);
|
|
327
|
+
throw cursorHttp1Error("BidiAppend", response.status);
|
|
328
|
+
}
|
|
329
|
+
const result = await readBoundedResponseBytes(response, {
|
|
330
|
+
maxBytes: CURSOR_HTTP1_APPEND_RESPONSE_MAX_BYTES,
|
|
331
|
+
signal,
|
|
332
|
+
});
|
|
333
|
+
if (result.oversized) throw new Error("Cursor HTTP/1.1 BidiAppend response exceeds 64 KiB");
|
|
334
|
+
} finally {
|
|
335
|
+
reservation.release();
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
private waitWhilePaused(): Promise<void> {
|
|
340
|
+
if (!this.paused) return Promise.resolve();
|
|
341
|
+
return new Promise(resolve => this.resumeWaiters.push(resolve));
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
private fail(error: Error): void {
|
|
345
|
+
if (this.terminal) return;
|
|
346
|
+
this.terminal = true;
|
|
347
|
+
this.destroyed = true;
|
|
348
|
+
this.resume();
|
|
349
|
+
this.rejectRunSseReady(error);
|
|
350
|
+
if (!this.abortController.signal.aborted) this.abortController.abort(error);
|
|
351
|
+
this.options.callbacks.onError(error);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
private finish(): void {
|
|
355
|
+
if (this.terminal) return;
|
|
356
|
+
this.terminal = true;
|
|
357
|
+
this.destroyed = true;
|
|
358
|
+
this.resume();
|
|
359
|
+
this.options.callbacks.onEnd();
|
|
360
|
+
}
|
|
361
|
+
}
|