Repository navigation
fix(usage): read Cursor Unified Ultra current-period quotas - #31978
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Priority: ➖ Normal Severity of issue fixed: Medium Merge Risk: ⚪ Minimal · up to
|
acb3d97 to
b19211f
Compare
…HTML Cursor answers unknown /api/dashboard routes with a 200 HTML app shell, so a retired current-period endpoint would surface as a permanent parse error for every Unified Ultra account instead of the summary fallback. Co-Authored-By: Claude <noreply@anthropic.com>
Unified Ultra now reports a weekly period, so the Accounts heading and search copy no longer promise a monthly window. Co-Authored-By: Claude <noreply@anthropic.com>
…plans Cursor's weekly X Subscription plans (Plus/Premium/Super/Ultra, incl. enterprise seats moved to Premium) all keep stale monthly zeros in usage-summary. Gate on unified_* membership, or on idle summary pools with a sub-monthly current period; non-unified plans ignore current-period failures so their behavior is unchanged. Co-Authored-By: Claude <noreply@anthropic.com>
…unified plans Co-Authored-By: Claude <noreply@anthropic.com>
b19211f to
4ebe2d7
Compare
ELI5
People on Cursor's new weekly plans saw Orca's Cursor usage stuck at 0%, with a reset date about a month away. Cursor moved these accounts to a weekly allowance. The old endpoint Orca reads still sends stale monthly zeros. The real numbers come from a newer endpoint.
With this PR, Orca reads that newer endpoint for those accounts, so it shows the actual usage (for example 1% Cursor Models) and the real weekly reset. Accounts that already show real usage make no extra request and behave exactly as before. The Accounts settings heading now reads "Plan usage" instead of "Monthly plan usage", because the period can be weekly.
What Changed
GET /api/usage-summary, Orca sendsPOST /api/dashboard/get-current-period-usagewith body{}when either:membershipTypestarts withunified_(Cursor's weekly "X Subscription" family;unified_ultrais the confirmed case). These accounts trust the current period strictly.isUnlimited(unlimited non-unified plans keep main's no-bar result and make no extra request). That is the stale-zero symptom on weekly plans that don't use aunified_*membership, such as an enterprise seat moved to weekly Premium. These accounts only switch over when the current period is shorter than 27 days (a weekly window). If the period is monthly, or the request fails in any way, the summary is used unchanged. (added in de-risk pass)planUsagegoes through the existing pool mapper, which already handles clamping, numeric strings, epoch-millisecond date strings and named pools, using the window dates from the current-period response. On-demand keeps the summary's own billing period./api/dashboard/*routes with a 200 HTML page, not a 404 (re-checked live).applyStalePolicyinservice-result-policy.ts) keeps showing the last good snapshot through these errors: up to 30 minutes, or 24 hours for 429.Linked Issue
Fixes #31803. Fixes #31804 (duplicate report, same account and same endpoint responses).
Evidence for the endpoint contract (upstream source, read-only clones)
I read six independent open-source Cursor usage trackers that call this endpoint:
docs/API_REFERENCE.md), Pulse (CursorUsageService.swift) and maxx-meter all usePOSTwith{}, the Cookie header andOrigin: https://cursor.com. That is the same request Orca sends.billingCycleStart/billingCycleEndandplanUsage.{autoPercentUsed, apiPercentUsed, totalPercentUsed}, the same fields Orca maps. Pulse's captured Premium fixture sends the dates as epoch-millisecond strings;parseCursorTimestampMsalready handles those, and a new test uses that format.unified_ultraalone was too narrow. It is also why the second trigger (idle pools plus a weekly-length period) exists.planUsagefrom this endpoint (headroom). The mapper returns null, so these accounts keep the summary.Verification
cursor-current-period-usage.test.tsfails onmain's fetcher. The 4 new de-risk cases (enterprise seat on weekly Premium, plus idle-pool fallbacks for a monthly period, 429 and network failure) fail against the PR's previous fetcher and pass now.pnpm teston the 6 Cursor rate-limit files (cursor-auth,cursor-current-period-usage,cursor-fetcher,cursor-session-token,cursor-usage-mapping,service-cursor-usage): 6 files / 99 tests pass after rebasing onto currentorigin/main(head 4ebe2d7). The new unlimited-plan case fails without theisUnlimitedgate and passes with it.isUnlimitedinteraction: agi-cli (cli/src/lib/accounting/usage.ts) prefers the current-period reply for every account and ignoresisUnlimited. So forunified_*accounts Orca still trusts the current period, and only the idle-pool trigger is gated.cursor.com(no real account credentials):GETon the endpoint returns 405 (the route exists and needs POST).POSTto an unknown/api/dashboard/does-not-exist-xyzreturns 200text/html(the reason for the HTML fallback). An earlier run with Electronnet.fetchand a rejected session got 401, which maps to "Cursor sign-in expired".src/main/rate-limits,src/main/runtime/session-tabs,src/renderer/src/components/settingsandsrc/shared/cursor-usage-buckets.ts; oxfmt--checkis clean on all 14 changed files; fullpnpm tcpasses (node, cli, web, all configs).static analysis and typecheckrun checked a merge ref from before fix(runtime): main lints and typechecks again after #32018 #32168 landed (oxlintmax-linesonheadless-terminal-tab-close.ts, a file this PR does not touch). This PR is now rebased onto amainthat includes fix(runtime): main lints and typechecks again after #32018 #32168, which gives a fresh CI run that includes the gated unit-test job.ProviderRateLimitsshape.Visual Proof
Controlled responses in the real hidden Electron app on macOS (from the original author's run). The "before" data comes from the existing summary mapper. The "after" data comes through the production fetcher with synthetic HTTP responses copied from the issue. These are not live-account checks.
Remaining Tradeoffs
isUnlimited: a successful current-period reply is shown, not the barless unlimited result. This matches upstream trackers, which treat the current period as authoritative.unified_*accounts and for accounts whose summary pools are all 0%. Accounts with any real usage make no extra request.Related
Earlier Cursor usage work: #22633, #24575, #25243, #28406. Thanks to @huangsky-stabo for the detailed issue with redacted endpoint captures.
Agent skill upstream boundary