Repository navigation
Conversation
…mini The Antigravity status-bar slot required `geminiCliOAuthEnabled`, and its sign-in CTA opened Gemini's Accounts section. Both were artifacts of the deleted Gemini mirror. Antigravity now earns its slot from Antigravity signals alone (checked item + CLI on PATH) and renders its own explicit unavailable state; it no longer offers a CTA that would configure a different provider. Refs #14515 Refs #9122
There was a problem hiding this comment.
ℹ️ No critical issues — a couple of stale comments worth cleaning up; otherwise a clean, well-scoped partial fix.
Reviewed changes
- Antigravity quota source — deletes
antigravity-usage-mirror.tsand addsantigravity-native-usage-source.ts, whosefetchAntigravityRateLimits()always reports Antigravity-nativeunavailableinstead of relabelling a Gemini snapshot. - Fetch-cycle integration —
fetchAntigravityRateLimits()joins thePromise.allSettledcycle as the 7th slot; the rejected branch also resolves tobuildAntigravityNativeUnavailable()so it never borrows another provider's failure. - Status-bar visibility —
hasUsageProviderSettingsForProvider('antigravity')now depends on the checked item alone (CLI on PATH), no longer ongeminiCliOAuthEnabled; the aggregatehasUsageProviderSettings()still omits Antigravity. - Sign-in routing —
getUsageProviderAccountsSectionId('antigravity')returnsnullinstead of routing toaccounts-gemini. - Tests — new source tests plus updated service/visibility/routing tests pin the unavailable state, the exact reason, that Gemini's own snapshot is untouched, and the stale-impersonation discard.
The core claims check out against the surrounding code: applyStalePolicy discards stale data on unavailable (service-result-policy.ts:28), trackActiveFailureStreak resets on unavailable (service-result-policy.ts:79), and the activation planner treats unavailable like ok (service-polling.ts:95), so the permanently-unavailable slot adds no retry churn. Mobile's ProviderRateLimitsSchema already accepts status: 'unavailable', and the wire shape is unchanged.
ℹ️ Nitpicks
src/renderer/src/components/status-bar/use-status-bar-controller.ts:106still claims Antigravity visibility "also requires geminiCliOAuthEnabled because its usage snapshot mirrors the Gemini fetch" — that gate is removed by this PR.src/renderer/src/components/status-bar/status-bar-provider-visibility.test.ts:126still says "antigravity durability requires the Gemini OAuth opt-in" — the new rationale is the "no readable source" reasoning already documented instatus-bar-provider-visibility.ts.
DeepSeek Pro (free via Pullfrog for OSS) | 𝕏
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (1)
Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review. 📝 WalkthroughWalkthroughAntigravity rate limits now use a dedicated native source that reports unavailability instead of mirroring Gemini data. The full fetch cycle retrieves Antigravity results independently and applies a native fallback when needed. Renderer visibility now depends only on Priority: ⬇️ Low Severity of issue fixed: Low Merge Risk: 🔵 Low · up to Antigravity usage now correctly reports unavailable, but its new error text may not be translated for localized users. This is a bounded follow-up rather than a merge-blocking functional failure. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
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 |
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Advanced
Run ID: afe1e644-df76-472b-9965-5bd3020162d6
📒 Files selected for processing (11)
src/main/rate-limits/antigravity-native-usage-source.test.tssrc/main/rate-limits/antigravity-native-usage-source.tssrc/main/rate-limits/antigravity-usage-mirror.test.tssrc/main/rate-limits/antigravity-usage-mirror.tssrc/main/rate-limits/service-antigravity-usage.test.tssrc/main/rate-limits/service/service-full-cycle-application.tssrc/main/rate-limits/service/service-full-cycle-preparation.tssrc/renderer/src/components/status-bar/status-bar-provider-visibility.test.tssrc/renderer/src/components/status-bar/status-bar-provider-visibility.tssrc/renderer/src/components/status-bar/usage-provider-settings-target.test.tssrc/renderer/src/components/status-bar/usage-provider-settings-target.ts
💤 Files with no reviewable changes (2)
- src/main/rate-limits/antigravity-usage-mirror.test.ts
- src/main/rate-limits/antigravity-usage-mirror.ts
Included review availability: Your plan provides up to 10 included reviews per hour; 4 remain after this review.
| export const ANTIGRAVITY_NO_NATIVE_SOURCE_REASON = | ||
| 'Antigravity usage is not available. Orca cannot read the Antigravity account quota pools yet.' |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Localize the Antigravity unavailability message.
buildAntigravityNativeUnavailable() stores raw English in ProviderRateLimits.error, and the unavailable-provider tooltip renders p.error directly. This bypasses translate() and shows English for non-English locales. Add an intent-named localization ID and resolve it at this display boundary.
…rebuild it The seven settled results were bound to names and immediately reassembled into an identical array, so adding a provider meant editing the same list in three places. Returning the awaited tuple directly drops that ceremony and leaves the fetch array as the single place a provider is added or removed. Checks run manually in place of the pre-commit hook: oxlint, oxlint --config config/oxlint-react-doctor.json, oxfmt --check.
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
Since the prior pullfrog review at 7e5f335, one commit landed:
- Provider cycle returns its settled tuple directly —
prepareFetchAllCyclenow returns thePromise.allSettledresult asresultsinstead of destructuring seven bindings and reassembling an identical array;service-full-cycle-application.tsdestructuresprepared.resultsby position. Behavior-preserving: same provider order, same rejected-branch handling, samesignal.abortedbail-outs.
The results field stays a hand-written seven-element PromiseSettledResult<ProviderRateLimits> tuple, so adding a fetcher without widening the type still fails typecheck. No references to the deleted antigravity-usage-mirror remain.
openrouter/deepseek/deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
|
Agreed that Gemini's numbers shouldn't be labelled as Antigravity. But one line in the description is out of date: "There is no way for Orca to read Antigravity's real usage today." There is now, and it's simple. The Antigravity CLI reports its own usage as JSON: agy -p /usage --output-format json
The shape of what it returns (trimmed, example values): {
"status": "SUCCESS",
"command": {
"name": "usage",
"data": {
"groups": [
{
"name": "Gemini Models",
"buckets": [
{ "id": "gemini-weekly", "window": "weekly", "remaining_fraction": 0.5, "reset_time": "<RFC 3339 time>" },
{ "id": "gemini-5h", "window": "5h", "remaining_fraction": 0.5, "reset_time": "<RFC 3339 time>" }
]
},
{
"name": "Claude and GPT models",
"buckets": [
{ "window": "weekly", "remaining_fraction": 0.5, "reset_time": "<RFC 3339 time>" },
{ "window": "5h", "remaining_fraction": 0.5, "reset_time": "<RFC 3339 time>" }
]
}
]
}
}
}These are the real Antigravity limits: two pools (Gemini, and Claude/GPT), each with a 5-hour and a weekly window, plus reset times. They match what Other tools already use it: CodexBar switched to this report in 0.60.2 (steipete/CodexBar#3607). With it, the Antigravity row shows all four limits. So instead of changing the row to "Usage unavailable", Orca could read this report. #20797 already does that. Could you take a look at it before merging this one? Otherwise the row goes blank for everyone even though the data is available. |
|
Current review verdict: do not merge this head as-is; superseded by #21654 → #21678. ELI5: this PR correctly stops labeling Gemini numbers as agy, but the maintained stack now reads agy’s supported |
|
Closing as superseded after checking current The quota behavior has been superseded by merged #24073 and #24593. Current main reads native Antigravity usage with CLI-version and preference gating. This older implementation reports usage as unavailable instead of retaining the real usage now supported on main. Closing this PR only; its branch is being retained. |

In plain language
Orca's usage bar was showing Google Gemini's quota numbers and labelling them "Antigravity". If you used Antigravity, the percentages you saw were a different product's usage, not your own — and they only showed up at all if you happened to have Google's Gemini command-line tool installed and signed in. There is no way for Orca to read Antigravity's real usage today, so instead of continuing to show you someone else's numbers, Antigravity now says plainly that its usage can't be read.
What you'll see differently: where Antigravity used to show a percentage bar, it now shows a dimmed dash, and the usage panel says "Usage unavailable" on the Antigravity row. Gemini's own numbers are unchanged. If you have Antigravity installed but never connected the Gemini tool, you'll now see that dimmed Antigravity row where previously you saw nothing at all.
User-visible downsides, stated up front
There are exactly two, and both are real:
--where they previously saw nothing. This is the honest state, but it is new visual clutter for that group — and it is likely the larger group of Antigravity users, since it no longer requires a Gemini install.Two further candidates were checked and ruled out rather than assumed:
getUsageRosterRowStatereturnskind: 'sign-in', which requires the error text to match a confirmed-signed-out pattern. None of the three Antigravity error strings — the two old ones or the new one — match, so the row always renderedkind: 'unavailable'andcanSignInwas never consulted. Verified against the real function, not by inspection. No user ever had that shortcut.isUsageEmptyStatepending check, which could in principle delay the "connect an account" prompt at startup. It does not: every provider is published in one state object, the others are equally unsettled on the first push and already gate the CTA, and Antigravity resolves synchronously — so it is never the last one outstanding.What this fixes — and what it does not
Read this first. This is a deliberate partial fix. Please do not merge it thinking it closes either linked issue.
Refs #14515/Refs #9122on purpose, notFixes.The bug
deriveAntigravityRateLimits()took a successful Gemini snapshot, relabelled itprovider: 'antigravity', and published it. Antigravity was never queried at all. Two consequences:Why there is no native replacement yet
A native Antigravity quota source is not implementable or verifiable from this repo today:
agy --helplists every subcommand —agent,agents,changelog,help,install,mcp,mic-serve,models,plugin,plugins,remote-control,update. There is nousage,quota,limits, orstatus.gemini, accountantigravity), not on disk. Orca has no keyring reader, and the Windows/Linux store layouts are undocumented here.So the substitution is removed rather than replaced.
fetchAntigravityRateLimits()is a real provider fetcher in thePromise.allSettledcycle (7th slot) that returnsstatus: 'unavailable'with an Antigravity-attributed reason.antigravity-usage-mirror.tsis deleted, so the Gemini→Antigravity derivation edge no longer exists in the type graph.Visual proof
Captured from the real Electron app (dev build on this branch, background launch, CDP screenshots of the hidden renderer). The renderer is byte-identical across the fix, so before/after differ only in the snapshot the main process publishes — each is the exact object the old and new code produce at runtime (see the runtime evidence below).
🔴 BEFORE — the bug
Gemini reports Pro 42% / Flash 11%, and Antigravity reports the same two numbers directly beneath it. This single image is #14515.
Usage panel. And in the status bar itself, the same pair of numbers appears twice — once under the Gemini icon, once under the Antigravity icon:
Status bar.
🟢 AFTER — the fix
Same app, same Gemini quota. Gemini keeps its own numbers; Antigravity states its own unavailability instead of borrowing them.
Usage panel. The status bar now shows Antigravity as a dimmed
--rather than a borrowed percentage:Status bar.
🟢 AFTER — with the Gemini sign-in turned off
What this one proves: Antigravity no longer needs Gemini to exist. Gemini drops out of the panel entirely, and Antigravity still has its own row with its own explanation — where previously it would have vanished along with Gemini. This is the #9122 half of the fix.
Is the chip hidden? No — and that's the recommendation
isProviderConfigured()returnsfalsefor'unavailable', which raised the question of whether the Antigravity chip silently disappears. It does not.getVisibleUsageProvider()falls through to the durable-settings check, so a configured Antigravity slot rendersProviderSegment's unavailable branch: a dimmed icon +--in the bar, and an explicit "Usage unavailable" row in the roster, with the full reason on drill-in.Recommendation: keep the visible unavailable state; do not hide the chip. It is the only place Orca can tell an Antigravity user why there is no usage — which is exactly the question #9122 was filed to ask. Hiding it would answer that question with silence.
Runtime proof (not just unit tests)
Driving the real
RateLimitService.refresh()cycle with a Gemini source returning a successful quota:With no Gemini CLI installed (real unmocked fetchers,
HOMEpointed at an empty directory, no network reached):Stale-policy path. A cached impersonated snapshot from before the upgrade (
{ ...gemini, provider: 'antigravity' },status: 'ok', Pro 42% / Flash 11%) was seeded into service state, then a refresh was run.applyStalePolicy()takes thefresh.status === 'unavailable'early return and discards it — the stale Gemini numbers do not survive the upgrade as an Antigravity snapshot.Two stale-coupling loose ends — resolved here, not deferred
Both were flagged as out of scope by the original implementation. Leaving Gemini coupling in a PR whose entire point is severing Gemini coupling would be the wrong call, and both fixes are one-liners in the same conceptual unit, so they are in this PR.
1.
status-bar-provider-visibility.ts— Antigravity visibility ANDed withgeminiCliOAuthEnabled.The original rationale ("the snapshot mirrors the Gemini fetch") is now false, but the gate was not inert — it was the only thing preventing a permanently dim chip. Now
hasUsageProviderSettingsForProvider('antigravity', …)depends only on Antigravity signals: the checked status-bar item plusagydetected on PATH.The tradeoff, stated plainly: the
antigravitystatus-bar item is default-on, so users who haveagyinstalled but never opted into Gemini CLI OAuth newly see a dimmedA --. That is intentional — it is an honest "Orca can't read this yet" for a provider they have installed, and it is the same treatment every other unavailable-but-configured provider gets. The alternative (returningfalseoutright and hiding the slot until a native source lands) is a one-word change if a reviewer prefers it; I recommend against it for the reason in the visual-proof section.hasUsageProviderSettings()deliberately still has no Antigravity term, so an Antigravity-only user still gets the setup CTA rather than a slot that can never fill.2.
usage-provider-settings-target.ts— Antigravity's sign-in CTA routed toaccounts-gemini.Now returns
null, like Kimi.accounts-geminiconfigures Gemini; sending an Antigravity user there configures the wrong provider.canSignInalready handlesnullby suppressing the CTA.Readiness review
ProviderRateLimitsshape and theantigravitykey are unchanged; only the value differs.mobile/src/components/accounts-snapshot.tsalready acceptsstatus: 'unavailable', so old paired clients and mobile decode it.fetchAntigravityRateLimits()cannot reject; a rejection is still handled.trackActiveFailureStreakresets onunavailable. The activation planner restampsupdatedAteach cycle, so the permanently-unavailable slot adds no fetch churn — same shape as Grok's unavailable path.Promise.allSettledentry resolving synchronously.antigravity-native-usage-source.tssits with the other provider sources insrc/main/rate-limits/, named for what it contains.No P0/P1/P2 findings.
Reviewing this diff
Use
?w=1.service-full-cycle-preparation.tsshows 83 changed lines, of which only 17 are substantive; the remaining ~66 are a two-space reindent of the provider array.The reindent is unavoidable. The original destructuring pattern was already 99 characters, right at the formatter's print width, and it only kept the array at its old indent because that length forced a
=/awaitline break. A seventh binding name pushes the pattern multi-line, which movesPromise.allSettled([up a level and shifts every element with it. I confirmed by experiment that oxfmt collapses a hand-written wrapped assignment back onto one line, so there is no formulation that preserves the old indent without a contrived, formatting-driven type annotation.What I did instead was delete the cause of the surrounding churn. The seven settled results were being bound to names and immediately reassembled into an identical array, so a provider had to be listed in three places. The third commit returns the awaited tuple directly, which drops 16 lines of ceremony, cuts the substantive change from 19 lines to 17, and leaves the fetch array as the single place a provider is added or removed — which should also reduce conflicts with any other PR touching this cycle.
The 17 substantive lines, in full:
Verification
npx vitest run src/main/rate-limits/ src/renderer/src/components/status-bar/ …— 97 files, 844 tests passingoxlint— cleanoxfmt --check— cleantsc --noEmitontsconfig.node.json,tsconfig.tc.web.json,tsconfig.tc.cli.json— all cleanRefs #14515
Refs #9122