feat(limits): show Copilot premium-request counts, not just a percentage - #98
Merged
Conversation
added 3 commits
July 25, 2026 10:15
A user asked whether TokenTracker can track GitHub Copilot credits. It already reads them — and then throws the answer away. `fetchCopilotLimits` pulls `quota_snapshots.premium_interactions` from api.github.com, which carries `entitlement` and `remaining`. buildCopilotWindow divided them into a percentage and dropped both numbers, so the card showed "Premium 53%" when GitHub had said "158 of 300 used". 53% needs arithmetic before it means anything; 142 left is the decision itself. buildWindow now takes optional `used`/`limit` and emits them only when a provider reports countable units. Everyone else passes neither, so the keys are omitted rather than set to null — other providers' payloads stay byte-identical and no consumer learns a field it will never see. A test asserts that shape for Cursor. On the surface, the count replaces the percentage where one exists: - Card chip: the 4-tier coloured dot and tint already carry severity, so dropping the percent sign loses nothing, and the tooltip keeps both. - Limits page bar: the bar *is* a proportional drawing of the percentage, so printing "53%" beside a 53%-wide bar repeats itself. "158/300" does not. - Both follow the Used/Remaining toggle: 158/300 used, 142/300 left. The count is clamped to the allowance. Copilot keeps billing past the quota so `remaining` can go negative, and "312/300 used" reads as a bug even when it is true — the percentage has always been clamped for the same reason. There was no test anywhere for fetchCopilotLimits before this. The new file also covers the pre-existing all-zero-snapshot guard and the no-token path, and the mock data now ships a configured Copilot so the chip is visible under `dashboard:dev` on a machine that has never signed in to Copilot. README's quota bullet said the chips show "used %", which this makes untrue, so it says what they show now. Closes#97
Independent QA at xhigh returned SHIP: NO on the first cut. All three were real and all three were mine; each is reproduced below and now has a regression test. 1. Percentage and count could describe different realities. `buildCopilotWindow` preferred `percent_remaining` for the bar while the caption came from `entitlement`/`remaining`. With `percent_remaining: 30, entitlement: 300, remaining: 72` that drew a 70%-wide bar captioned "228/300" — which is 76%. The caption is the number the user reads, so the percentage is now derived from the counts whenever both arrive; `percent_remaining` stays the fallback for the case it exists to cover, a percentage with no denominator. 2. A null count read as zero remaining. `Number(null)` is 0, so `remaining: null` reported the entire allowance consumed — "300/300" beside a percentage saying 10% used. That tells someone their quota is gone when they have barely touched it. Counts now require an actual finite number, and an absent one falls back to the percentage with no counts emitted at all. 3. Clamping the wrong half in the dashboard. `getWindowCounts` clamped only the low end, so an unclamped payload rendered "312/300" in Used mode from `used: 312` AND in Remaining mode from `used: -12`. Clamping into [0, limit] now happens before the mode flip. The current server clamps, but a newer dashboard talks to whatever server is installed — which is exactly what the discarded comment claimed to handle. Also: README:99 still said the quota chips show a used percentage. I fixed that claim at README:83 in the previous commit and assumed it was the only one. It was not. Refs #97
Non-blocking findings from the QA re-check. Both described the card chip as showing label + %, which stopped being true when the count replaced it.
Uh oh!
There was an error while loading. Please reload this page.
pitimon added a commit
that referenced
this pull request
Jul 25, 2026
Ships #98 (issue #97): GitHub Copilot quota now reports the premium-request count — "158/300", or "142/300" in Remaining mode — instead of a percentage the reader has to convert. The numbers were already being fetched from api.github.com and discarded after one division. The independent Codex QA gate returned SHIP: NO on the first cut and all three findings were real: the bar and its caption could be drawn from different fields and disagree (70% beside 228/300, which is 76%); a null `remaining` coerced to zero and reported the whole allowance consumed; and the dashboard clamped only one end, so an unclamped payload could render "312/300" in either mode. Fixed, each with a regression test built from the exact reproduction. First release where the `version` lifecycle hook from #96 did its job: the bump synced TokenTrackerBar/project.yml and TokenTrackerWin.csproj, which is what made 0.39.39–0.39.42 unable to cut a desktop build. prepublishOnly re-vendored the LiteLLM seed: 2,522 models, no rate changes, only _meta.generated_at moved. Co-authored-by: itarun.p <itarun.p@somapait.com>
4 tasks
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 freeto 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.
Closes#97. From a user question: "can TokenTracker track GitHub Copilot credits?"
It already reads them. It was throwing the answer away.
The defect
fetchCopilotLimitspullsquota_snapshots.premium_interactionsfromapi.github.com, which carriesentitlementandremaining.buildCopilotWindowdid this:So the card read
Premium 53%when GitHub had said158 of 300 used. "53%" needs arithmetic before it means anything. "142 left" is the decision.Change
buildWindowtakes optionalused/limitand emits them only when a provider reports countable units. Everyone else passes neither, so the keys are omitted rather than set tonull— other providers' payloads stay byte-identical and no consumer has to learn a field it will never see. A test pins that shape for Cursor.Where a count exists, it replaces the percentage:
53%beside a 53%-wide bar repeats itself.158/300beside it does not.Both follow the existing Used/Remaining toggle:
158/300used,142/300left.The count is clamped to the allowance. Copilot keeps billing past quota so
remainingcan go negative, and312/300 usedreads as a bug even when it's true — the percentage has always been clamped for the same reason.Deliberately not in scope
parseCopilotIncrementalreading Copilot's OTEL export (COPILOT_OTEL_ENABLED=true) — a completely separate mechanism from quota, already explained by the in-applimits.copilot.otelHintpanel. Users conflate the two; that's a docs problem, not this one.Test plan
npm run ci:local— exit 0, 839/839 root (+6), 255 dashboard (+7)fetchCopilotLimitsbefore this —grep -rl 'fetchCopilotLimits\|copilot_internal' test/was empty. New file covers counts flowing through,percent_remaining-only (no denominator → no counts), over-quota clamping, the pre-existing all-zero-snapshot guard, and the no-token pathHEADand re-ran: 2 server + 5 dashboard tests fail, confirming they exercise the changeUsageLimitsPanel.test.jsx, not just pure functions — the counts reach the screen through acopy()key, and a mistyped key renders as the raw key string while everygetWindowCountsunit test still passes. That test also caught my own wrong prop guess (modevsdisplayMode)mock-data.tsships a configured Copilot, so the chip is visible underdashboard:devwithout a real Copilot installconfigured: false(no token on disk), so the API-shape assumptions come from the existing parser, not from a live responseNote
README's quota bullet claimed the chips show "used %", which this change makes untrue — updated in the same commit rather than left to drift.