Header Usage popup + Cursor Admin API + ADE CLI usage commands#276
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
|
@cursor review |
📝 WalkthroughWalkthroughAdds Cursor provider usage polling and monthly windows, refactors pacing into a window-based per-provider engine, moves usage UI from Settings into a header gauge and modal UsageQuotaPanel with budget editing, updates Cursor credential detection, and adds an ChangesCursor Usage Tracking and Header UI Migration
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Capy auto-review is paused for this organization because the monthly auto-review limit has been reached. Increase the limit or turn it off in billing settings to resume automatic reviews. |
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
apps/desktop/src/renderer/components/app/SettingsPage.tsx (1)
31-45:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winPreserve old
?tab=usagedeep links.Removing the section without an alias means existing
/settings?tab=usagelinks now fall back togeneral, which is a confusing regression for bookmarks and stale in-app links. Add ausagealias to the closest surviving destination or a dedicated “moved to header usage popup” landing state.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/desktop/src/renderer/components/app/SettingsPage.tsx` around lines 31 - 45, The TAB_ALIASES mapping no longer preserves old ?tab=usage deep links; update the TAB_ALIASES constant (used to map legacy query tabs to SectionId) to include a "usage" key mapped to the closest surviving section (e.g., add "usage": "general") so legacy /settings?tab=usage URLs continue to route correctly; modify the TAB_ALIASES object to include this alias and ensure any code that reads TAB_ALIASES (referencing TAB_ALIASES and SectionId) will pick up the new mapping.apps/desktop/src/main/services/ai/providerConnectionStatus.ts (2)
176-192:⚠️ Potential issue | 🟠 Major | ⚡ Quick winUse the same Cursor key validation here as the usage poller.
cursorEnvAuthandcursorStoredAuthcurrently accept any non-empty value, butpollCursorUsage()only treats SDK/store keys as usable when they match thekey_format. That lets this status surface reportauthAvailable/usageAvailable=truewhile the usage poller silently skips Cursor. Reuse one shared helper so status and polling agree.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/desktop/src/main/services/ai/providerConnectionStatus.ts` around lines 176 - 192, Replace the loose non-empty checks for Cursor keys in providerConnectionStatus (cursorEnvAuth, cursorStoredAuth and the derived cursorSdkAuth/cursorUsageAuth logic) with the same key-format validation used by pollCursorUsage; import or extract the poller’s helper (e.g., isCursorKeyValid or whatever validation function exists in pollCursorUsage) and use it to validate process.env.CURSOR_API_KEY, getAllApiKeys().cursor, and process.env.CURSOR_ADMIN_API_KEY before setting cursorEnvAuth/cursorStoredAuth/cursorAdminEnvAuth and cursorCredsSource so the status reporter and poller agree on which keys are actually usable.
215-238:⚠️ Potential issue | 🟠 Major | ⚡ Quick winDon't let runtime health disable admin-key usage polling.
usageAvailableis correctly derived fromcursorUsageAuth, but the unconditionalapplyRuntimeHealth(cursor, cursorRuntimeHealth)call can still zero it out when the Cursor runtime is broken or missing an SDK key. That regresses the admin-key-only path this PR adds: usage polling works, but the UI will still say Cursor usage is unavailable.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/desktop/src/main/services/ai/providerConnectionStatus.ts` around lines 215 - 238, The runtime-health decorator applyRuntimeHealth currently runs after building cursor and can overwrite usageAvailable (breaking the admin-key-only path); move or reassign usageAvailable so the final cursor.usageAvailable reflects cursorUsageAuth regardless of runtime health — e.g., call applyRuntimeHealth(cursor, cursorRuntimeHealth) first (or leave it as is) but then set cursor.usageAvailable = cursorUsageAuth afterwards (or patch applyRuntimeHealth to never modify usageAvailable). Update the code that constructs cursor (symbols: cursor, usageAvailable, cursorUsageAuth, applyRuntimeHealth, cursorRuntimeHealth, createUnavailableStatus) so usageAvailable is preserved for the admin-key path.
🧹 Nitpick comments (3)
apps/ade-cli/README.md (1)
90-91: 💤 Low valueConsider documenting command aliases for discoverability.
The test file verifies that
quota/quotasare aliases forusage snapshotandpollis an alias forusage refresh, but these aliases aren't mentioned in the README examples. Documenting them would improve discoverability for users.📝 Example documentation enhancement
ade usage snapshot --text +ade quota snapshot --text # alias ade usage refresh --text +ade usage poll --text # alias🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/ade-cli/README.md` around lines 90 - 91, Add documentation for the CLI command aliases missing from the README: mention that the commands "quota" and "quotas" are aliases for "ade usage snapshot" and that "poll" is an alias for "ade usage refresh". Update the usage examples section (where "ade usage snapshot --text" and "ade usage refresh --text" are shown) to include the equivalent alias forms and a short note explaining these aliases for discoverability, referencing the exact command names "usage snapshot", "usage refresh", "quota"/"quotas", and "poll" so readers can find them easily.apps/desktop/src/renderer/components/settings/UsageMeter.tsx (2)
102-102: Consider refactoringMODEL_COLORSto avoid redundancy withtoneColor.The first entry in
MODEL_COLORS("#A78BFA") duplicates the defaulttoneColor. When breakdown rendering usesi === 0 ? toneColor : MODEL_COLORS[i % MODEL_COLORS.length],MODEL_COLORS[0]is only accessed wheni = 4, 8, 12...due to modulo wrapping, creating subtle redundancy that can confuse maintainers.♻️ Proposed refactor for clarity
Option 1: Remove the first color and start the palette from index 1:
-const MODEL_COLORS = ["#A78BFA", "#7C3AED", "#C4B5FD", "#6D28D9"]; +const MODEL_COLORS = ["#7C3AED", "#C4B5FD", "#6D28D9"];Then adjust the cycling logic to use
MODEL_COLORS[(i - 1) % MODEL_COLORS.length]fori > 0.Option 2: Document the intentional duplication with a comment explaining that
MODEL_COLORS[0]is used for the 5th+ model whiletoneColoris used for the 1st.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/desktop/src/renderer/components/settings/UsageMeter.tsx` at line 102, MODEL_COLORS currently duplicates toneColor which is confusing; remove the first entry ("#A78BFA") from MODEL_COLORS and update the color selection logic (the ternary that currently reads i === 0 ? toneColor : MODEL_COLORS[i % MODEL_COLORS.length]) to use MODEL_COLORS[(i - 1) % MODEL_COLORS.length] for i > 0 so the first color is always toneColor and subsequent models cycle the compact palette; alternatively, if you prefer to keep the array as-is, add a clear comment next to MODEL_COLORS explaining that MODEL_COLORS[0] intentionally duplicates toneColor and is only used for the 5th+ model.
52-56: ⚡ Quick winConsider using
transform: scaleX()instead of animatingwidth.Animating the
widthproperty triggers layout reflow. Usingtransform: scaleX()withtransform-origin: leftwould provide smoother animation performance, especially on lower-end devices.⚡ Proposed performance optimization
<div - className="absolute inset-y-0 left-0 transition-all duration-500 ease-out" + className="absolute inset-y-0 left-0 w-full origin-left transition-transform duration-500 ease-out" style={{ - width: `${clamped}%`, + transform: `scaleX(${clamped / 100})`, background: fillColor, }} />🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/desktop/src/renderer/components/settings/UsageMeter.tsx` around lines 52 - 56, The progress bar currently animates width (the element with className "absolute inset-y-0 left-0 ..." in UsageMeter.tsx); change it to keep a fixed width (e.g., width: "100%") and animate using CSS transform: set style.transform = `scaleX(${clamped / 100})` and style.transformOrigin = "left"; update the transition to animate transform (e.g., transition: "transform 500ms ease-out") and consider adding willChange: "transform" to improve performance on low-end devices.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/ade-cli/README.md`:
- Line 95: Add a positive test in cli.test.ts that runs the CLI command string
"ade usage budget cumulative --scope global --text" (same form as in README) and
asserts it routes to the cumulative backend action; mock the CLI runner/backend
client used in existing usage tests (reuse the same test scaffolding as other
"ade usage" tests) and verify the mocked backend method for the cumulative
budget action is invoked with expected parameters and output formatting, rather
than only checking the error message path currently referenced in the test
suite.
In `@apps/ade-cli/src/cli.test.ts`:
- Around line 2726-2727: Add a positive unit test in
apps/ade-cli/src/cli.test.ts that mirrors the existing "get" and "check" tests
to verify the "usage budget cumulative" routing works: call buildCliPlan with
["usage","budget","cumulative"] and assert the returned plan matches the
expected handler/shape (the same kind of assertion used for the "get" and
"check" tests) so the CLI recognizes "cumulative" as a valid subcommand; locate
tests around other usage budget assertions near buildCliPlan to copy the
pattern.
In `@apps/ade-cli/src/cli.ts`:
- Line 4294: Add the "quota" and "quotas" aliases to the CLI help alias
resolution so "ade quota --help" / "ade help quota" resolve to the same handler
as "usage": update the help alias map (the structure where other aliases are
defined, e.g., HELP_ALIASES or helpAliases) to map "quota" and "quotas" to
"usage", and ensure the existing runtime check that uses the primary variable
and calls buildUsagePlan(...) already covers those values (or add them there if
missing).
- Around line 3675-3688: The current logic treats an empty/whitespace text
payload as absent and falls back to collectGenericObjectArgs, allowing an
implicit {} to be sent to budget.updateConfig; change the hasInlineBody handling
in the read/parse block so that if readFileTextInput(args) returns a non-null
value but text.trim().length === 0 you throw a CliUsageError (e.g., "Empty
budget config provided") instead of falling back, otherwise proceed to
JSON.parse(text) as before; update the branch around
readFileTextInput/hasInlineBody/JSON.parse and ensure budget.updateConfig
(actionStep("result","budget","updateConfig", ...)) only receives a parsed
non-empty JSON object.
In `@apps/desktop/src/main/services/cto/ctoStateService.ts`:
- Around line 194-195: The two-line help text is inconsistent: the first line
says usage/guardrails moved to the header usage popup but the second line still
instructs configuring automations in /settings; update the second string (the
automation guidance entry in the same array or constant in ctoStateService.ts)
to remove the `/settings` reference and instead direct users to the header usage
popup or to return a navigation suggestion when an action should open in ADE
(match the existing phrasing "When an action should be opened in ADE, return a
navigation suggestion. Never silently switch tabs."); ensure both strings
consistently mention the header usage popup and the navigation-suggestion
behavior.
In `@apps/desktop/src/main/services/usage/usageTrackingService.ts`:
- Around line 314-324: The comment incorrectly calls monthlyLimitDollars
"team-wide" while it's actually a per-member field on CursorSpendMember; update
the comment above memberLimitCents to describe monthlyLimitDollars as a
per-member default monthly limit (a per-member fallback used when
hardLimitOverrideDollars is not set) so it's clear each member's
monthlyLimitDollars is summed into totalLimitCents; reference memberLimitCents
and CursorSpendMember when updating the comment.
In `@apps/desktop/src/renderer/components/settings/UsageMeter.tsx`:
- Line 69: The background color selection causes collisions because the first
slice uses toneColor while others use MODEL_COLORS[i % MODEL_COLORS.length], so
when i >= MODEL_COLORS.length the colors repeat; update the logic in UsageMeter
(the background assignments that reference toneColor and MODEL_COLORS) to avoid
collisions by either using MODEL_COLORS[(i + 1) % MODEL_COLORS.length] for
non-zero i (skip the first MODEL_COLORS entry) or by always using MODEL_COLORS[i
% MODEL_COLORS.length] and synchronizing MODEL_COLORS[0] with toneColor, and
apply the same change to both places where background is set (the occurrences
around the current toneColor and the second usage at the other background
assignment).
- Around line 47-57: Wrap the visual meter with proper ARIA attributes so screen
readers can interpret it: in the UsageMeter component add a semantic progress
role and values to the element representing the filled bar (the div that uses
clamped and fillColor) — set role="progressbar", aria-valuemin={0},
aria-valuemax={100}, aria-valuenow={clamped} and include either
aria-label="Usage" or aria-valuetext={`${clamped}% used`} (ensure clamped is a
numeric value) so assistive tech reads the percent; keep the visual styling
(fillColor, width: `${clamped}%`) unchanged.
---
Outside diff comments:
In `@apps/desktop/src/main/services/ai/providerConnectionStatus.ts`:
- Around line 176-192: Replace the loose non-empty checks for Cursor keys in
providerConnectionStatus (cursorEnvAuth, cursorStoredAuth and the derived
cursorSdkAuth/cursorUsageAuth logic) with the same key-format validation used by
pollCursorUsage; import or extract the poller’s helper (e.g., isCursorKeyValid
or whatever validation function exists in pollCursorUsage) and use it to
validate process.env.CURSOR_API_KEY, getAllApiKeys().cursor, and
process.env.CURSOR_ADMIN_API_KEY before setting
cursorEnvAuth/cursorStoredAuth/cursorAdminEnvAuth and cursorCredsSource so the
status reporter and poller agree on which keys are actually usable.
- Around line 215-238: The runtime-health decorator applyRuntimeHealth currently
runs after building cursor and can overwrite usageAvailable (breaking the
admin-key-only path); move or reassign usageAvailable so the final
cursor.usageAvailable reflects cursorUsageAuth regardless of runtime health —
e.g., call applyRuntimeHealth(cursor, cursorRuntimeHealth) first (or leave it as
is) but then set cursor.usageAvailable = cursorUsageAuth afterwards (or patch
applyRuntimeHealth to never modify usageAvailable). Update the code that
constructs cursor (symbols: cursor, usageAvailable, cursorUsageAuth,
applyRuntimeHealth, cursorRuntimeHealth, createUnavailableStatus) so
usageAvailable is preserved for the admin-key path.
In `@apps/desktop/src/renderer/components/app/SettingsPage.tsx`:
- Around line 31-45: The TAB_ALIASES mapping no longer preserves old ?tab=usage
deep links; update the TAB_ALIASES constant (used to map legacy query tabs to
SectionId) to include a "usage" key mapped to the closest surviving section
(e.g., add "usage": "general") so legacy /settings?tab=usage URLs continue to
route correctly; modify the TAB_ALIASES object to include this alias and ensure
any code that reads TAB_ALIASES (referencing TAB_ALIASES and SectionId) will
pick up the new mapping.
---
Nitpick comments:
In `@apps/ade-cli/README.md`:
- Around line 90-91: Add documentation for the CLI command aliases missing from
the README: mention that the commands "quota" and "quotas" are aliases for "ade
usage snapshot" and that "poll" is an alias for "ade usage refresh". Update the
usage examples section (where "ade usage snapshot --text" and "ade usage refresh
--text" are shown) to include the equivalent alias forms and a short note
explaining these aliases for discoverability, referencing the exact command
names "usage snapshot", "usage refresh", "quota"/"quotas", and "poll" so readers
can find them easily.
In `@apps/desktop/src/renderer/components/settings/UsageMeter.tsx`:
- Line 102: MODEL_COLORS currently duplicates toneColor which is confusing;
remove the first entry ("#A78BFA") from MODEL_COLORS and update the color
selection logic (the ternary that currently reads i === 0 ? toneColor :
MODEL_COLORS[i % MODEL_COLORS.length]) to use MODEL_COLORS[(i - 1) %
MODEL_COLORS.length] for i > 0 so the first color is always toneColor and
subsequent models cycle the compact palette; alternatively, if you prefer to
keep the array as-is, add a clear comment next to MODEL_COLORS explaining that
MODEL_COLORS[0] intentionally duplicates toneColor and is only used for the 5th+
model.
- Around line 52-56: The progress bar currently animates width (the element with
className "absolute inset-y-0 left-0 ..." in UsageMeter.tsx); change it to keep
a fixed width (e.g., width: "100%") and animate using CSS transform: set
style.transform = `scaleX(${clamped / 100})` and style.transformOrigin = "left";
update the transition to animate transform (e.g., transition: "transform 500ms
ease-out") and consider adding willChange: "transform" to improve performance on
low-end devices.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: db773104-1aef-4750-9d93-a1b29b65fef4
⛔ Files ignored due to path filters (4)
docs/ARCHITECTURE.mdis excluded by!docs/**docs/features/automations/README.mdis excluded by!docs/**docs/features/automations/guardrails.mdis excluded by!docs/**docs/features/onboarding-and-settings/README.mdis excluded by!docs/**
📒 Files selected for processing (20)
apps/ade-cli/README.mdapps/ade-cli/src/cli.test.tsapps/ade-cli/src/cli.tsapps/desktop/src/main/services/ai/providerConnectionStatus.tsapps/desktop/src/main/services/cto/ctoStateService.tsapps/desktop/src/main/services/usage/usageTrackingService.test.tsapps/desktop/src/main/services/usage/usageTrackingService.tsapps/desktop/src/renderer/components/app/CommandPalette.tsxapps/desktop/src/renderer/components/app/SettingsPage.tsxapps/desktop/src/renderer/components/app/TopBar.tsxapps/desktop/src/renderer/components/automations/components/RuleEditorPanel.tsxapps/desktop/src/renderer/components/missions/MissionHeader.tsxapps/desktop/src/renderer/components/settings/SettingsUsageSection.tsxapps/desktop/src/renderer/components/settings/UsageGuardrailsSection.tsxapps/desktop/src/renderer/components/settings/UsageMeter.tsxapps/desktop/src/renderer/components/usage/HeaderUsageControl.tsxapps/desktop/src/renderer/components/usage/UsageQuotaPanel.test.tsxapps/desktop/src/renderer/components/usage/UsageQuotaPanel.tsxapps/desktop/src/shared/types/config.tsapps/desktop/src/shared/types/usage.ts
💤 Files with no reviewable changes (3)
- apps/desktop/src/renderer/components/app/CommandPalette.tsx
- apps/desktop/src/renderer/components/settings/SettingsUsageSection.tsx
- apps/desktop/src/renderer/components/settings/UsageGuardrailsSection.tsx
- Cursor: prefer overallSpendCents (total) over spendCents (on-demand only) and fall back to monthlyLimitDollars when no per-user override is set. - HeaderUsageControl: per-provider tooltip, glow + pulse on critical/error states, accurate aria-label, runtime tone reflects warnings only when no active percentage takes priority. - UsageMeter: replace the stacked sub-quota bar (sub-quotas were independent percentages, not contributions) with a single fill plus per-model ticks. - Move automation guardrails into the header Usage popup as a collapsible section; remove Settings → Usage tab, SettingsUsageSection, UsageGuardrailsSection, and stale references in CommandPalette, RuleEditorPanel, ctoStateService, and the feature docs. - ade-cli: add `ade usage snapshot|refresh|budget` plan plus help entry. - Tests cover the new Cursor parsing fallbacks; typecheck and affected vitest suites pass.
- automate: extend ade-cli/cli.test.ts with 5 cases for the new `ade usage snapshot|refresh|budget` plan (123 → 123 incl. usage paths). - automate: refresh docs/ARCHITECTURE.md telemetry pointer to the header Usage popup (HeaderUsageControl + UsageQuotaPanel). - finalize/simplify: extract `finiteOrZero` for the Cursor spend reducers, flatten the cursorBlocker ternary into an if/else cascade, collapse the inline budget-set try block, drop unnecessary useMemo + try/catch on the ipc unsubscribe callbacks, replace nested ternaries in ExtraUsageCard / AuthChip / fillColor with explicit branches. - finalize/cli-parity: add `ade usage` examples to apps/ade-cli/README CLI surface inventory. Local gate: typecheck (desktop/ade-cli/web), eslint, vitest shards 1-8, and ade-cli tests all green.
b7bd3eb to
6766502
Compare
|
@cursor review |
| { id: "integrations", label: "Integrations", icon: Plugs }, | ||
| { id: "memory", label: "Memory", icon: Database }, | ||
| { id: "lane-templates", label: "Lane Templates", icon: Stack }, | ||
| { id: "usage", label: "Usage", icon: Lightning }, |
There was a problem hiding this comment.
Missing alias for removed "usage" settings tab
Medium Severity
The usage section was removed from SECTIONS and the command palette entry navigating to /settings?tab=usage was deleted, but no entry was added to TAB_ALIASES to redirect stale deep links. Any existing bookmark, external link, or automation that navigates to /settings?tab=usage will land on the Settings page with no active tab and an empty content area, since "usage" is no longer a valid SectionId and has no alias mapping.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit b7bd3eb. Configure here.
|
@cursor review |
|
@cursor review |
|
@cursor review |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/desktop/src/renderer/components/usage/UsageQuotaPanel.test.tsx`:
- Around line 61-79: The tests currently cast incomplete IPC mock objects to any
(e.g., the globalThis.window.ade mock and its ai.getStatus) which bypasses
TypeScript checks; create a properly typed fixture for the preload contract (or
replace the cast with an object declared to satisfy AiSettingsStatus) and use it
for globalThis.window.ade.ai.getStatus and other mocks referenced in
UsageQuotaPanel.test.tsx so all required fields (mode, availableProviders,
models, features, etc.) are present; alternatively declare the mock with
"satisfies AiSettingsStatus" to enforce the full contract and update the other
mocks (usage.getSnapshot, refresh, getBudgetConfig, saveBudgetConfig, onUpdate)
to match their respective interfaces instead of using "as any".
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: dc73f463-331f-4d2d-a19a-0d3721a4e9da
⛔ Files ignored due to path filters (4)
docs/ARCHITECTURE.mdis excluded by!docs/**docs/features/automations/README.mdis excluded by!docs/**docs/features/automations/guardrails.mdis excluded by!docs/**docs/features/onboarding-and-settings/README.mdis excluded by!docs/**
📒 Files selected for processing (23)
apps/ade-cli/README.mdapps/ade-cli/src/cli.test.tsapps/ade-cli/src/cli.tsapps/desktop/src/main/services/ai/providerConnectionStatus.test.tsapps/desktop/src/main/services/ai/providerConnectionStatus.tsapps/desktop/src/main/services/ai/utils.tsapps/desktop/src/main/services/cto/ctoStateService.tsapps/desktop/src/main/services/usage/usageTrackingService.test.tsapps/desktop/src/main/services/usage/usageTrackingService.tsapps/desktop/src/renderer/components/app/CommandPalette.tsxapps/desktop/src/renderer/components/app/SettingsPage.tsxapps/desktop/src/renderer/components/app/TopBar.tsxapps/desktop/src/renderer/components/automations/components/RuleEditorPanel.tsxapps/desktop/src/renderer/components/missions/MissionHeader.tsxapps/desktop/src/renderer/components/settings/SettingsUsageSection.tsxapps/desktop/src/renderer/components/settings/UsageGuardrailsSection.test.tsxapps/desktop/src/renderer/components/settings/UsageGuardrailsSection.tsxapps/desktop/src/renderer/components/settings/UsageMeter.tsxapps/desktop/src/renderer/components/usage/HeaderUsageControl.tsxapps/desktop/src/renderer/components/usage/UsageQuotaPanel.test.tsxapps/desktop/src/renderer/components/usage/UsageQuotaPanel.tsxapps/desktop/src/shared/types/config.tsapps/desktop/src/shared/types/usage.ts
💤 Files with no reviewable changes (4)
- apps/desktop/src/renderer/components/settings/SettingsUsageSection.tsx
- apps/desktop/src/renderer/components/settings/UsageGuardrailsSection.test.tsx
- apps/desktop/src/renderer/components/settings/UsageGuardrailsSection.tsx
- apps/desktop/src/renderer/components/app/CommandPalette.tsx
✅ Files skipped from review due to trivial changes (3)
- apps/desktop/src/main/services/ai/utils.ts
- apps/desktop/src/main/services/cto/ctoStateService.ts
- apps/desktop/src/renderer/components/automations/components/RuleEditorPanel.tsx
🚧 Files skipped from review as they are similar to previous changes (13)
- apps/desktop/src/shared/types/config.ts
- apps/ade-cli/README.md
- apps/desktop/src/renderer/components/app/SettingsPage.tsx
- apps/desktop/src/main/services/usage/usageTrackingService.test.ts
- apps/desktop/src/renderer/components/settings/UsageMeter.tsx
- apps/desktop/src/main/services/ai/providerConnectionStatus.ts
- apps/desktop/src/renderer/components/usage/HeaderUsageControl.tsx
- apps/desktop/src/main/services/usage/usageTrackingService.ts
- apps/desktop/src/renderer/components/missions/MissionHeader.tsx
- apps/ade-cli/src/cli.ts
- apps/desktop/src/shared/types/usage.ts
- apps/desktop/src/renderer/components/app/TopBar.tsx
- apps/desktop/src/renderer/components/usage/UsageQuotaPanel.tsx
|
@cursor review |
|
@cursor review |
|
@cursor review |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
apps/desktop/src/main/services/ai/providerConnectionStatus.test.ts (1)
232-260: ⚡ Quick winDeduplicate env var setup/restore across Cursor tests.
The repeated
CURSOR_API_KEY/CURSOR_ADMIN_API_KEYsave+restore blocks are easy to drift. A tiny helper would reduce maintenance risk.♻️ Suggested refactor
+async function withCursorEnv( + env: { cursorApiKey?: string; cursorAdminApiKey?: string }, + run: () => Promise<void>, +): Promise<void> { + const prevKey = process.env.CURSOR_API_KEY; + const prevAdminKey = process.env.CURSOR_ADMIN_API_KEY; + if (env.cursorApiKey === undefined) delete process.env.CURSOR_API_KEY; + else process.env.CURSOR_API_KEY = env.cursorApiKey; + if (env.cursorAdminApiKey === undefined) delete process.env.CURSOR_ADMIN_API_KEY; + else process.env.CURSOR_ADMIN_API_KEY = env.cursorAdminApiKey; + try { + await run(); + } finally { + if (prevKey === undefined) delete process.env.CURSOR_API_KEY; + else process.env.CURSOR_API_KEY = prevKey; + if (prevAdminKey === undefined) delete process.env.CURSOR_ADMIN_API_KEY; + else process.env.CURSOR_ADMIN_API_KEY = prevAdminKey; + } +}Then each test becomes a concise wrapper around
withCursorEnv(...).Also applies to: 263-278, 281-308, 311-338
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/desktop/src/main/services/ai/providerConnectionStatus.test.ts` around lines 232 - 260, Multiple Cursor tests repeat the same save/restore logic for CURSOR_API_KEY and CURSOR_ADMIN_API_KEY; create a small helper (e.g., withCursorEnv) that accepts the desired env values and a callback, saves previous values, sets process.env.CURSOR_API_KEY and process.env.CURSOR_ADMIN_API_KEY, runs the callback (which will call buildProviderConnections / mergeCliStatuses in the tests), and finally restores the originals; then refactor tests like the "marks Cursor runtime available through the SDK when an env API key is set" test to call withCursorEnv({CURSOR_API_KEY: 'test-key', CURSOR_ADMIN_API_KEY: undefined}, async () => { ...expect(...)... }); reference functions buildProviderConnections and mergeCliStatuses to ensure the helper is used around the exact test logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@apps/desktop/src/main/services/ai/providerConnectionStatus.test.ts`:
- Around line 232-260: Multiple Cursor tests repeat the same save/restore logic
for CURSOR_API_KEY and CURSOR_ADMIN_API_KEY; create a small helper (e.g.,
withCursorEnv) that accepts the desired env values and a callback, saves
previous values, sets process.env.CURSOR_API_KEY and
process.env.CURSOR_ADMIN_API_KEY, runs the callback (which will call
buildProviderConnections / mergeCliStatuses in the tests), and finally restores
the originals; then refactor tests like the "marks Cursor runtime available
through the SDK when an env API key is set" test to call
withCursorEnv({CURSOR_API_KEY: 'test-key', CURSOR_ADMIN_API_KEY: undefined},
async () => { ...expect(...)... }); reference functions buildProviderConnections
and mergeCliStatuses to ensure the helper is used around the exact test logic.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 424fcb89-e4f9-4d8b-84cc-e95b1c2db595
📒 Files selected for processing (8)
apps/ade-cli/src/cli.test.tsapps/ade-cli/src/cli.tsapps/desktop/src/main/services/ai/providerConnectionStatus.test.tsapps/desktop/src/main/services/ai/providerConnectionStatus.tsapps/desktop/src/main/services/usage/usageTrackingService.tsapps/desktop/src/renderer/components/usage/HeaderUsageControl.tsxapps/desktop/src/renderer/components/usage/UsageQuotaPanel.test.tsxapps/desktop/src/renderer/components/usage/UsageQuotaPanel.tsx
🚧 Files skipped from review as they are similar to previous changes (7)
- apps/desktop/src/renderer/components/usage/HeaderUsageControl.tsx
- apps/desktop/src/main/services/ai/providerConnectionStatus.ts
- apps/ade-cli/src/cli.test.ts
- apps/ade-cli/src/cli.ts
- apps/desktop/src/main/services/usage/usageTrackingService.ts
- apps/desktop/src/renderer/components/usage/UsageQuotaPanel.tsx
- apps/desktop/src/renderer/components/usage/UsageQuotaPanel.test.tsx
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
There are 3 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 5248237. Configure here.
| if (absDelta <= 6) return deltaPercent >= 0 ? "slightly-ahead" : "slightly-behind"; | ||
| if (absDelta <= 12) return deltaPercent >= 0 ? "ahead" : "behind"; | ||
| return deltaPercent >= 0 ? "far-ahead" : "far-behind"; | ||
| } |
There was a problem hiding this comment.
Pacing thresholds silently narrowed, breaking existing consumers
Medium Severity
stageForDelta narrows pacing thresholds from ±4/±10/±20 to ±2/±6/±12 compared to the old inline logic in calculatePacing. The legacy calculatePacing function now delegates to calculatePacingForWindow → stageForDelta, so the same delta values produce more aggressive statuses — e.g., a delta of 5% was "on-track" and is now "slightly-ahead", a delta of 13% was "ahead" and is now "far-ahead". Existing calculatePacing tests (lines ~112–161, not shown in the diff and therefore not updated) likely assert the old status labels and will break.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 5248237. Configure here.
|
|
||
| function extractError(err: unknown): string { | ||
| return err instanceof Error ? err.message : String(err); | ||
| } |
There was a problem hiding this comment.
Duplicated extractError utility across new components
Low Severity
The identical extractError helper is copy-pasted into both HeaderUsageControl.tsx and UsageQuotaPanel.tsx. A shared getErrorMessage already exists in the main-process utils (../shared/utils). Consolidating into a single renderer-accessible utility avoids drift and reduces maintenance burden.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 5248237. Configure here.


Summary
Describe the change.
What Changed
Key files and behaviors.
Validation
How you tested.
Risks
Anything to watch.
Note
Medium Risk
Medium risk because it introduces new network polling/auth-key handling (Cursor Admin API) and changes the main UX entrypoint for usage/guardrails; incorrect key detection or spend polling (including single-page results) could misreport usage/budgets.
Overview
Moves usage + guardrails UI out of Settings into the header. Adds a new top-bar popup (
HeaderUsageControl→UsageQuotaPanel) that shows live provider quota windows, refresh, warnings, and a collapsible Automation guardrails editor (BudgetCapEditor); removes the Settings Usage tab and related command-palette/navigation copy.Extends live usage tracking to Cursor and makes pacing provider-aware.
usageTrackingServicenow polls Cursor team spend via the Admin API (Basic auth fromCURSOR_ADMIN_API_KEYor admin-shaped keys), normalizes it into amonthlywindow +ExtraUsage, and computes both legacy aggregate pacing pluspacingByProvider; sharedusagetypes addcursor,monthly,windowDurationMs, andpacingByProvider.Adds a typed
ade usageCLI surface. Newusage snapshot|refresh|budget get|set|check|cumulativecommands (withquota/quotasaliases) route to service actions and validate budget JSON inputs; docs and tests updated accordingly, and Cursor connection status now distinguishes runtime vs usage availability based on Admin API key shape.Reviewed by Cursor Bugbot for commit 5248237. Configure here.
Summary by CodeRabbit
New Features
Improvements
Greptile Summary
This PR adds a top-bar
HeaderUsageControl/UsageQuotaPanelcomponent that consolidates live provider quotas and automation guardrails, removes the dedicated Settings "Usage" tab, and extendsusageTrackingServiceto poll Cursor team spend via the Admin API. It also addsade usageCLI routes forsnapshot,refresh, andbudget get/set/check/cumulative.parseCursorSpendUsageaggregates team-member spend/limit cents into a monthlyUsageWindowand optionalExtraUsage, with pacing computed in a newcalculatePacingByProviderhelper that produces per-providerUsagePacingalongside the existing aggregate.usageAvailablefor Cursor is now driven byisCursorAdminApiKeydetection rather than runtime readiness, allowing usage-only admin keys to coexist with absent SDK keys.buildUsagePlancorrectly sequencesfirstPositionalcalls for thebudgetsub-command;UsageMeternow renders cumulative tick marks, fixing the prior non-cumulative position bug.Confidence Score: 4/5
Safe to merge for most teams; Cursor spend data will be silently under-counted for teams exceeding 100 members, and the admin key detection relies on a prefix heuristic that could misfire.
The core polling, pacing, and UI wiring are well-tested and logically sound. The single-page Cursor Admin API fetch means displayed spend and pacing status are under-reported for large Cursor teams with no error surfaced. The "key_" admin-key heuristic is wide open and could misclassify keys. Both issues are contained to the new Cursor usage path and do not affect Claude or Codex behavior.
apps/desktop/src/main/services/usage/usageTrackingService.ts — Cursor spend fetch lacks pagination; apps/desktop/src/main/services/ai/utils.ts — admin key heuristic.
Important Files Changed
Sequence Diagram
sequenceDiagram participant R as Renderer (UsageQuotaPanel) participant B as IPC Bridge participant S as usageTrackingService (main) participant CA as Claude API participant CO as Codex API participant CU as Cursor Admin API R->>B: getSnapshot() B->>S: getSnapshot() S-->>B: UsageSnapshot (cached) B-->>R: UsageSnapshot R->>B: refresh() B->>S: forceRefresh() S->>CA: GET /api/oauth/usage (OAuth token) S->>CO: GET /wham/usage (JWT) S->>CU: "POST /teams/spend (Basic key_*)" CA-->>S: windows[] CO-->>S: windows[] CU-->>S: teamMemberSpend[] S->>S: parseCursorSpendUsage() / calculatePacingByProvider() S-->>B: updated UsageSnapshot B-->>R: UsageSnapshot B->>R: onUpdate(snapshot) [push]Comments Outside Diff (1)
apps/desktop/src/main/services/usage/usageTrackingService.ts, line 784-822 (link)pollCursorUsagesends a single POST with{ pageSize: 100 }and stops there. If the Cursor team has more than 100 members, the response contains only the first page, sototalSpendCentsandtotalLimitCentsare each under-counted by all remaining members. The resultingpercentUsed, pacing status, andExtraUsagedollar figures will be systematically lower than the real values, and the UI will silently show the wrong numbers with no error or warning.A pagination loop is needed: keep fetching additional pages (passing the returned cursor/offset token) until all members have been included, or at minimum expose a hard upper bound and emit an error/warning when it's hit.
Prompt To Fix With AI
Prompt To Fix All With AI
Reviews (7): Last reviewed commit: "ship: iteration 6 preserve cursor usage ..." | Re-trigger Greptile