feat: add Cursor quota provider#132
Conversation
✅ AI Code Review CompletedReview finished. Check the PR for inline comments. 📋 View Logs | 🤖 Model: |
There was a problem hiding this comment.
honestly this is a clean addition — the JSON model with snake/camel fallback decoders, the flexible Double parser, and the team-pool resolution logic are all thoughtful. tests cover the interesting edges (used/limit fallback, team pool selection, JWT/CLI userId extraction, percent clamping). reading the diff felt like reading the existing providers, which is the highest compliment a new provider can earn here.
few things hold this back from a clean approve though:
Blockers
- SwiftLint is failing on this PR because of a duplicate
import Foundationat the top ofCursorProvider.swift. that's also why CI is red. one-line fix.
Worth fixing in this PR
- Force-unwrapped
URL(string:)!on line 326 — the codebase already has a precedent (seeAGENTS.md→ "TimeZone Force Unwrap Safety") for avoiding force-unwraps even on hardcoded literals. swap to astatic letorguard let. - Dead branch in
ModernStatusBarIconView.swift:127— thecase .cursor: return "cursorarrow"is unreachable because the caller always short-circuits onidentifier == .cursorto render the asset image. remove it so future devs don't get confused about which icon wins.
Minor / non-blocking observations
cursorAutoResetandcursorApiResetare always set to the samebillingCycleEndvalue. fine for now, but if Cursor ever exposes per-window resets the model is already shaped for it — nice forward thinking.headlinePlanPercentreturns 0.0 whentotalPercentUsedis exactly 0, which then triggers the(percent ?? 0) == 0fallback to on-demand. that means a real "0% used" plan can silently hop to the on-demand bucket. probably what you want for the headline metric, but worth a// MARK:comment so the next reader doesn't have to puzzle it out.- No
minimumFetchIntervalset, so this hits cursor.com on every refresh tick. consistent with most providers; onlyClaudeProviderthrottles. low priority. - the SQLite read uses the default mode — if Cursor itself is writing while we read, you can hit "database is locked". the error path surfaces it as
providerError, so it'll show up as an error row instead of a crash. acceptable, butPRAGMA busy_timeout=2000or-readonlymode would harden it later.
Validation
the test suite + manual launch evidence in the PR body is exactly the kind of signal that makes review fast. thanks for that.
once the duplicate import is gone CI should go green and this is good to merge. nice work overall.
This bot will re-review automatically on new pushes. You can also re-trigger it by mentioning @op-gg-ai-devops in a comment with optional directions, e.g.:
@op-gg-ai-devops review typos@op-gg-ai-devops focus on security in CursorProvider.swift@op-gg-ai-devops re-check after fixing duplicate import
✅ AI Code Review CompletedReview finished. Check the PR for inline comments. 📋 View Logs | 🤖 Model: |
There was a problem hiding this comment.
all three blockers from the previous round are gone:
- duplicate
import Foundation→ dropped, SwiftLint is green now - force-unwrapped URL literal → swapped for a proper
guard let - dead
case .cursor: return "cursorarrow"→ killed,systemIconName(for:)now returnsString?and the asset image branch handles.cursorcleanly
the inline comment you added on the 0%-headline → on-demand fallback is exactly what i was hoping for. future-me reading that switch will know it's intentional.
also the small things that didn't get touched are fine — cursorAutoReset == cursorApiReset == billingCycleEnd is forward-shaped for when Cursor exposes per-window resets, no minimumFetchInterval keeps you consistent with most providers, and the SQLite default-mode read still degrades gracefully via providerError.
CI signal: SwiftLint ✅, GitHub Actions Lint ✅. Build is still running but with the SwiftLint fix in there's no reason to expect red.
One small thing for later (non-blocking)
Cursor's actual paid tier list is wider than what's in ProviderSubscriptionPresets.cursor:
| Plan | Price |
|---|---|
| Pro | $20/mo ✅ already in presets |
| Pro+ | $60/mo ❌ missing |
| Ultra | $200/mo ❌ missing |
| Teams | $40/user/mo ✅ already in presets |
users on Pro+ or Ultra won't have a matching preset. fine to leave for a follow-up — not a blocker for this PR.
Validation
tests cover the interesting bits (used/limit fallback, team pool selection, JWT/CLI userId extraction, percent clamping). manual launch evidence in the PR body is appreciated.
ship it. nice work — turning around three review fixes plus a clarifying comment that fast is solid.
This bot will re-review automatically on new pushes. You can also re-trigger it by mentioning @op-gg-ai-devops in a comment with optional directions, e.g.:
@op-gg-ai-devops review typos@op-gg-ai-devops focus on security in CursorProvider.swift@op-gg-ai-devops re-check after merging main
Adds Cursor as a quota-based provider using the local SQLite/API extraction approach from mm7894215/TokenTracker.
Summary:
~/Library/Application Support/Cursor/User/globalStorage/state.vscdband~/.cursor/cli-config.jsonwithout logging tokens.https://cursor.com/api/usage-summarywith the Cursor session cookie and normalizes Cursor quota windows.Validation:
Cursor: 1%, 54%with Auto/API windows andUsing in: Cursor.Related fork PR: Daltonganger#3