feat: cursor usage meter#68
Open
Rtas-17 wants to merge 2 commits into
Open
Conversation
Adds a Cursor usage meter alongside Claude Code, Codex, and Antigravity. Cursor stores the signed-in JWT in its local state.vscdb and exposes a JSON usage summary at cursor.com/api/usage-summary - no HTML scraping needed. - src/models.rs: new optional 'cursor' field on AppUsageData - src/poller.rs: read cursorAuth/accessToken from state.vscdb via rusqlite (bundled), with CURSOR_SESSION_TOKEN env fallback, build the WorkosCursorSessionToken cookie (user id decoded from the JWT sub claim joined with the token via ::), and map autoPercentUsed / apiPercentUsed onto the two bars. billingCycleEnd is the shared reset for both. Includes a unit test for the mapping (cursor_usage_maps_auto_and_api_percentages). - src/window.rs: new bar in the widget, Models -> Cursor toggle, tray tooltip uses "Auto: ... | API: ..." wording. When Cursor is the only model shown, the row labels switch from 5h/7d to Auto/API since Cursor has no rolling 5-hour window. Accent is near-black, inverted for dark taskbars. - src/localization/*: new cursor_model, cursor_window_title, cursor_auto_window, cursor_api_window strings across all locales - Cargo.toml: rusqlite (bundled) to read the Cursor IDE state DB Verified locally: cargo test --bin claude-code-usage-monitor passes 6/6 (including the new Cursor mapping test), release build unaffected. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Pull request overview
Adds a new “Cursor” provider to the usage monitor, including polling Cursor’s usage-summary API using a session token sourced from the Cursor IDE’s local state DB (or an env var override), plus UI/toggle/localization updates to render the new meter.
Changes:
- Extend the core usage model to include optional Cursor usage data.
- Implement Cursor polling: read session token (env var or
state.vscdb), callhttps://cursor.com/api/usage-summary, and map Auto/API percentages into the existing session/weekly bars. - Update the Windows UI/tray + settings + localization to add a Cursor toggle and display Auto/API labeling when Cursor is the only active model.
Reviewed changes
Copilot reviewed 16 out of 17 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/window.rs | Adds Cursor state fields, toggle plumbing, tray tooltip/icon entries, and bar rendering (including Cursor-only Auto/API labels). |
| src/poller.rs | Adds Cursor poller: token resolution from env/SQLite, usage-summary HTTP fetch, and response mapping + unit test. |
| src/models.rs | Adds AppUsageData.cursor: Option<UsageData> for Cursor usage. |
| src/localization/mod.rs | Extends Strings with Cursor labels/titles (model name + Auto/API window labels + window title). |
| src/localization/english.rs | Adds Cursor strings in English. |
| src/localization/dutch.rs | Adds Cursor strings in Dutch. |
| src/localization/spanish.rs | Adds Cursor strings in Spanish. |
| src/localization/french.rs | Adds Cursor strings in French. |
| src/localization/german.rs | Adds Cursor strings in German. |
| src/localization/japanese.rs | Adds Cursor strings in Japanese. |
| src/localization/korean.rs | Adds Cursor strings in Korean. |
| src/localization/traditional_chinese.rs | Adds Cursor strings in Traditional Chinese. |
| src/localization/simplified_chinese.rs | Adds Cursor strings in Simplified Chinese. |
| src/localization/russian.rs | Adds Cursor strings in Russian. |
| src/localization/portuguese_brazil.rs | Adds Cursor strings in Portuguese (Brazil). |
| Cargo.toml | Adds rusqlite (bundled) dependency for reading Cursor’s local state DB. |
| Cargo.lock | Locks new dependency graph for rusqlite/sqlite. |
Comments suppressed due to low confidence (1)
src/window.rs:500
- In the loading/error tray-icon state, Cursor is also assigned
TrayIconKind::Codex, so hovering is the only way to distinguish it from Codex. If Cursor is meant to have its own tray indicator, it should use a dedicated icon kind.
if s.show_cursor {
icons.push(tray_icon::TrayIconData {
kind: tray_icon::TrayIconKind::Codex,
percent: None,
tooltip: s.language.strings().cursor_window_title.to_string(),
});
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Give Cursor its own TrayIconKind so it no longer shares Codex's tray slot/styling when both are enabled. - Use localized cursor_auto_window / cursor_api_window strings in the Cursor tray tooltip instead of hard-coded English. - Also wire Cursor-only auth balloon copy to the Cursor tray icon (same class of bug as the Ollama review). Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a Cursor usage meter next to Claude Code, Codex, and Antigravity.
Cursor already keeps the signed-in JWT in its local
state.vscdb, andcursor.com/api/usage-summaryreturns JSON with Auto / API percentages for the current billing cycle. So this is a straight SQLite read + HTTP call — no HTML scraping, no separate login helper.How auth works
cursorAuth/accessTokenfrom%APPDATA%\Cursor\User\globalStorage\state.vscdb(read-only; copies to a temp file if Cursor has the DB locked).sub, take the id after the last|, and buildWorkosCursorSessionToken=<id>%3A%3A<jwt>.CURSOR_SESSION_TOKENto the raw cookie value or JWT if the IDE DB isn't available.If there's no token the Cursor bar shows
!until you sign in to Cursor (or set the env var).What this PR adds
src/models.rs: optionalcursorfield onAppUsageDatasrc/poller.rs:poll_cursor()/ cookie helpers /fetch_cursor_usage()mappingautoPercentUsed→ session bar andapiPercentUsed→ weekly bar, withbillingCycleEndas the shared reset. Unit test for the mapping included.src/window.rs: widget bar, Models → Cursor toggle, tray tooltip uses Auto/API wording. When Cursor is the only model enabled, row labels switch from5h/7dtoAuto/API— Cursor has a monthly pool, not a rolling 5-hour window.src/localization/*:cursor_model,cursor_window_title,cursor_auto_window,cursor_api_windowCargo.toml:rusqlitewith thebundledfeature so we can read the state DB without a system SQLite installTest plan
cargo testpasses (verified locally, includingcursor_usage_maps_auto_and_api_percentages)cargo build --releasecleanI checked this on Windows 11 against a Pro account — usage-summary returned Auto ~1%, API 0%, reset at billingCycleEnd.
Design notes
billingCycleEnd.cursor.comover HTTPS.rusqlite(bundled). No webview / wry / tao.What's not in this PR
Risks
!rather than fake zeros.Happy to tweak the Auto/API labeling or split anything out if you'd rather review differently.