⭐5 — Cursor PKCE login com Bearer quota, auto router e empty-turn errors. Feature completa e testada (11 arquivos de teste, 133 testes focados, todos verdes).
**Validação (worktree combinado `.claude/worktrees/fix-9909`, board sobre `origin/release/v3.8.50`):**
- 3 conflitos reais resolvidos: `config/quality/eslint-suppressions.json` (aditivo), `open-sse/config/providers/registry/cursor/index.ts` (dedup de 208 entradas de catálogo, 0 IDs duplicados verificado), `open-sse/executors/cursor.ts` (imports aditivos).
- `npm run typecheck:core`: limpo.
- `check-changelog-integrity`, `check-file-size`, `check-complexity` (2615/2774), `check-cognitive-complexity` (1175/1223), `check-dead-code` (410/416): todos OK.
- `check-public-creds`: 1 entrada obsoleta pré-existente na allowlist (`copilot-m365-web.ts:330`), já presente no tip da release — não é desta PR.
- `npm run lint`: 0 errors (5 warnings pré-existentes).
- Testes focados (`cursor-agent-cli-version`, `cursor-available-models`, `cursor-catalog-combo-compat`, `cursor-errors-classify`, `cursor-login-pkce`, `cursor-model-effort-suffix-7289`, `cursor-streaming`, `cursor-token-extractor`, `cursor-token-refresh-wiring`, `cursor-usage-fetcher`, `empty-stream-no-content-8649`): 133/133 verdes.
- Corrigido durante a validação: 1 teste novo da própria PR (`cursor-model-effort-suffix-7289.test.ts`, "splits effort off legacy grok- ids") colidia com `CURSOR_MODEL_ALIASES` já mesclado na release (mapeia `grok-4.5-high` → `cursor-grok-4.5-high` antes do fallback legado rodar); ajustado para usar um id não-aliasado (`grok-3-high`) que de fato exercita o fallback — commit `68b58ed`.
Obrigado pela contribuição, @yansigit — feature robusta com boa cobertura de testes.
5.6 KiB
title, version, lastUpdated
| title | version | lastUpdated |
|---|---|---|
| Cursor Provider in Docker Environments | 3.8.50 | 2026-08-17 |
Cursor Provider in Docker Environments
When OmniRoute runs inside Docker, the legacy Import from Cursor IDE /
cursor-agent flows fail because the container cannot see the host Cursor
install. Use Login with Cursor (deep-control PKCE) instead.
Why IDE / CLI Import Fails in Docker
- Filesystem isolation — Auto-import looks for Linux paths such as
~/.config/Cursor/User/globalStorage/state.vscdbinside the container. On Docker Desktop for macOS the host IDE DB is not mounted by default, and the container OS is Linux even when the host is Darwin. - No
cursor-agentbinary — Official OmniRoute images do not shipcursor-agent. Available Models previously shelled out tocursor-agent --list-modelsand fell back to a static catalog. - Wrong binary — Do not bind-mount a macOS
cursor-agentinto a Linux container. It will not execute.
Recommended: Login with Cursor
- Open Dashboard → Providers → Cursor.
- Choose the Login with Cursor tab.
- Click Login with Cursor — OmniRoute opens
https://cursor.com/loginDeepControl?…in your host browser. - Approve the login in the browser, then return to the dashboard. OmniRoute
polls
api2.cursor.sh/auth/polluntil tokens arrive. - OmniRoute stores access + refresh tokens and refreshes them via
https://api2.cursor.sh/auth/exchange_user_api_key.
This path does not require Cursor IDE or cursor-agent inside the container.
Model discovery
With a logged-in connection, Available Models / Auto-Sync prefers Cursor’s
HTTP AiService/AvailableModels catalog using the connection bearer token.
If that fails, OmniRoute still tries host cursor-agent (when present), then
the static registry seed.
OmniRoute always exposes auto in the catalog (display “Auto”), plus
OpenCodex-style router modes auto-cost, auto-balance, and
auto-intelligence. On the wire these map to Cursor’s default model
(with an optimization ModelParameter for the three variants). Prefer
cu/auto when premium models are out of usage — Auto often still has budget.
Live catalog is exclusive when synced
After a successful Cursor model sync (cursor-agent --list-models → persisted
synced catalog, or the bearer-authenticated AvailableModels fetch above), the
dashboard, /v1/models, and Test All list:
- Models returned by the live sync
- Injected auto-router ids:
auto,auto-cost,auto-balance,auto-intelligence - Operator custom models (Import / manual) — never pruned by sync
The large static registry under
open-sse/config/providers/registry/cursor/ is offline fallback only. When
synced is empty (or discovery fails), listing falls back to that registry.
Effort-suffixed ids (for example claude-4.6-sonnet-high) may still be
requested at runtime: resolveRequestedModel strips the suffix into a wire
ModelParameter. Exclusive listing intentionally hides those static variants
from Test All so probes match what Cursor actually returns as available.
Helpers
providerUsesExclusiveSyncedListing("cursor"|"cu")—src/lib/providers/modelListingCapability.tsmergeProviderModelListing— dashboard mergeensureCursorAutoCatalogEntry— auto* inject on discovery + listingshouldSuppressStaticModelForExclusiveListing—/v1/modelsstatic loop
Provider Limits (quota)
Usage → Provider Limits for Cursor uses Bearer APIs on api2.cursor.sh
(GetCurrentPeriodUsage → usage summary → auth/usage) after PKCE or token
import. The legacy cookie/cursor.com dashboard path remains a last fallback
for older IDE-imported sessions.
Windows typically include Total, Auto + Composer, and API. If limits look empty, re-run Login with Cursor or re-import tokens (IDE import alone is no longer required).
Empty turns / out of usage
When Cursor accepts a Run but returns no assistant text (common when premium
usage is exhausted), OmniRoute surfaces an actionable 429 (quota cues) or
502 with guidance — not a bare “Provider returned empty content”. Streaming
failures such as not_found: AI Model Not Found (usage window exhausted) are
classified as Cursor rate limit / usage exceeded and keep that message
through the SSE pipeline (the shared empty-stream guard does not overwrite an
already-emitted error). Check Provider Limits, try model auto, or raise
Cursor plan limits.
Client version (headless)
Without a local cursor-agent install, OmniRoute resolves
x-cursor-client-version via env CURSOR_AGENT_CLI_VERSION, then a disk-cached
scrape of the Cursor installer script, then a pinned build id. Override with
CURSOR_AGENT_CLI_VERSION when needed.
Fallback: Manual Token Import
If you cannot complete browser login:
-
On the host, extract tokens from Cursor’s
state.vscdb:sqlite3 "$HOME/Library/Application Support/Cursor/User/globalStorage/state.vscdb" \ "SELECT key, value FROM ItemTable WHERE key IN ('cursorAuth/accessToken','cursorAuth/refreshToken','storage.serviceMachineId');" -
Open Import token in the Cursor auth modal.
-
Paste Access Token and, when available, Refresh Token (required for automatic refresh). Machine ID is optional.
Access-token-only imports still work but will expire without a refresh token — re-import when chat returns authentication errors.
Related
- Zed Docker guidance:
docs/providers/ZED-DOCKER.md - OpenCodex Cursor login reference (external): https://github.com/lidge-jun/opencodex/blob/main/src/oauth/cursor.ts