Repository navigation
feat: weekly usage limit including Weekly (All) and model-specific quota (e.g., Fable) - #86
Merged
Carl723000 merged 7 commits intoAug 7, 2026
Conversation
* normalize the usage API's limits[] array instead of retired per-model fields * rename showOpusWeekly to showScopedWeekly, migrating the stored value * show usage credits and their monthly reset in the quota tooltip * merge weekly caps that reset together into one tooltip row * make the tooltip follow resetCountdownFormat and show a wall clock per row * round reset times to the minute and drop implied .1f percent precision * fill five missing pt-BR / id settings translations
* print the shared weekly countdown once instead of per cap * give each tooltip cap its own row and bar * label the all-models row, localised across eight locales * put the credit spend after its reset date
* read "Weekly (All)" to keep the window column narrow * abbreviate the label in all eight locales
* a fixed epoch put the 4.8h fixture on the next UTC day, so CI saw a weekday the assertions did not expect * local-noon anchor keeps same-day and next-day true in every timezone
* replace the credit percentage with the spend, keeping the bar on the cap * keep reporting spend after credits are toggled off * handle an absent or unlimited cap instead of hiding the row * pad the monthly reset date away from the amount
* print no decimal for the integer limits[] field, one for the legacy float * correct the showScopedWeekly help text in all eight locales * pin that an idle per-model cap leaves no trace in the status bar
* gap the right-aligned share and reset cells * drop the credits row's one-off pad
8 tasks done
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
showOpusWeeklyhad stopped working entirely, not merely gone stale. Anthropic's OAuth usage endpoint no longer populates the per-model quota fields the extension read, so the figure that setting exists to show was silently blank.The real data moved into a generic
limitsarray, where a scoped cap names its own model:This reads that array instead, so no model name is hardcoded anywhere and the next rename costs no code change. It also closes a risk gap rather than only a display one: the status bar's warning colour considered just the all-models figure, so an account could sit green at
wk 9%while its binding per-model cap ran near full.Before

After

What changed
Reading the API.
src/quotaWindows.ts, normalizes either payload generation into one ordered window list. The legacy flat fields stay as a fallback for accounts still served the old shape.hasExpiredWindowand the dashboard's quota banner read those fields directly too, so they route through the normalizer as well.Status bar.
wk 9% (fable 17%), so the shared countdown prints once instead of per cap. A cap on its own schedule keeps its own segment and countdown.5handwksegments.Tooltip.
Weekly (All)andWeekly (Fable), localized across all eight locales.time left (wall clock), and the countdown followsresetCountdownFormat, which it previously ignored.5h 0%is the signal that tracking works at all.Setting.
showOpusWeeklybecomesshowScopedWeekly, with a one-shot migration carrying the stored value over. It stays opt-in and off by default.Fixes found along the way
Not in the original scope, but in the code this touches:
resetCountdownFormat. On the defaultdecimalthe same window read4.5hin the status bar and4h 29min the tooltip.16:59:59displayed as16:59while the cap it resets alongside displayed17:00.8%rendered as8.0%. Precision now follows the field the API used.pt-BR, oneid) were silently falling back to English.Notes for review
Row merging is tolerance-based, not equality-based.
The two weekly caps are stamped microseconds apart and straddle a minute boundary (
23:59:59.227Zagainst00:00:00.227Z), so an equality test would refuse to merge them. Caps merge when their resets agree within five minutes; anything genuinely separate differs by hours or days.Share precision follows the API's field, not the value.
limits[].percentis serialized as an integer (3) while the legacyutilizationis a float (3.0), andJSON.parsecollapses both to3. The normalizer records which shape a window came from, so the modern path prints3%and the legacy path3.0%. Keying on the field rather than sniffing the raw response text avoids threading raw JSON through the HTTP layer, at the cost of missing a future9.0insidelimits[].The credits reset is derived, not reported.
The payload carries no reset for credits (
dailyandweeklyare bothnull).Sep 1comes from the calendar, which is why it renders as a bare date rather than a countdown: the day is trustworthy, the exact instant and its billing timezone are not.Credits show an amount, not a share.
The cap is user-adjustable and may be unlimited, so a percentage of it says little. The percentage survives only as the bar's fill, and is null (empty bar) when there is no finite cap.
extra_usage.used_creditsscale is assumed.The
spendblock is preferred because its minor units and exponent are unambiguous. The olderextra_usagefallback assumesused_creditsfollowsdecimal_placeslikemonthly_limitdoes, which could not be confirmed against live data since it has only ever been observed at 0.Credit currency follows the account, not the viewer.
It comes from the API (
spend.used.currency), so a non-USD account renders as42.00 EURrather than a localized symbol. Consistent with how the rest of the extension formats monetary cost.Testing
npm run compileclean;npm testat 244 tests, 243 passing with 1 pre-existing skip.src/test/quotaWindows.test.ts, 34 new tests: both payload generations,nullper-model fields, unknown scoped kinds, rollover per window period, row merging, zero-usage hiding, per-source precision, credits parsing across toggle-off and uncapped cases.src/test/quotaFormat.test.ts, 11 to 35 tests.src/test/quotaI18n.test.ts, 4 new tests: quota strings across all eight locales, plus a repo-wide invariant that every settings key is translated. That invariant is what surfaced the five untranslated entries.Normalizer and formatter output verified end-to-end against a live
/api/oauth/usageresponse in all three reset formats and all eight locales. UI verified in the Extension Development Host.Reset-formatting tests are anchored to local wall time rather than a fixed epoch, after a first CI run failed on it:
1_700_000_000_000is 22:13 UTC, so the+4.8hfixture crossed into the next UTC day and CI saw a weekday the assertions did not expect. Verified in 14 timezones including+05:45and+12:45offsets.