Releases: aweussom/claude-code-quota
Release list
v2.0.0 — PowerShell 7 required, UTF-8 BOMs on all .ps1
Breaking: Windows PowerShell 5.1 is no longer supported
pwsh 7+ only on Windows. Every entry point now carries #Requires -Version 7.0
and refuses to run under 5.1 instead of degrading.
If your statusline currently runs under powershell.exe, it will stop working
after this upgrade. Fix it by pointing ~/.claude/settings.json at pwsh:
{
"statusLine": {
"type": "command",
"command": "pwsh -NoProfile -NonInteractive -ExecutionPolicy Bypass -File C:/Users/<you>/.claude/statusline.ps1"
}
}install.ps1 now writes that automatically, and warns if it finds a
powershell-launched command already in place.
Linux/WSL2 is unaffected.
The bug this started from
install.ps1 failed to parse under 5.1 with four bogus Missing closing '}'
errors, none of them near the real cause:
At install.ps1:168 char:46
+ if (Test-Path $statuslineDst -PathType Leaf) {
Missing closing '}' in statement block or type definition.
The files were UTF-8 without a BOM. 5.1 cannot detect UTF-8 without one, so
it decoded them as ANSI — and an em-dash (E2 80 94) became †plus
U+201D, which PowerShell accepts as a string delimiter. The string closed
early, the parser desynced, and it reported the last good construct before each
desync rather than the actual line.
statusline.ps1.template had the quieter form of the same bug: its ⚠ markers
are in emitted strings, so 5.1 printed mojibake instead of erroring.
Changes
- UTF-8 BOM on all PowerShell files. This had to come first — the whole file is
parsed before#Requiresis evaluated, so without a BOM no version gate could
ever fire. #Requires -Version 7.0oninstall.ps1,statusline.ps1.template, and
_quota-fetch-helper.ps1.install.ps1exits 1 if not on 7+, and separately ifpwshis missing from
PATH — Claude Code launches the statusline aspwsh ..., so resolving in
the installing shell is not enough.- Both
powershell.exefallbacks removed.quota-lib.ps1relaunches its
background worker via[Environment]::ProcessPath— the pwsh already running
it — rather than searching PATH. A 5.1 worker would write a mis-encoded cache
that every other session then reads. - New
tests/test-quota-lib.ps1: BOMs,#Requireson entry points, absence of
anypowershell.exefallback, that every file parses, and strict UTF-8
validity. No network, no fixtures, cannot consume quota.
quota-lib.ps1 deliberately has no #Requires — it is dot-sourced, and the
directive would throw in the caller.
Compatibility
Cache schema_version is unchanged at 3; only lib_version moves. No cache
migration, and older libraries can still read the file.
Full changelog: v1.2.0...v2.0.0
v1.2.0 — scoped limits, honest staleness, concurrency safety
Everything since v1.0.0. Version 1.1.0 was bumped in the manifests but never tagged or released, so its changes ship here too.
Plugin users:
marketplace.jsonwas stuck at 1.0.0 through both bumps, so/plugin marketplace addwas offering 1.0.0 regardless of what was onmain. Fixed in this release.
Scoped limits
If your plan includes a model- or surface-scoped limit — a separate allowance from the 5h and weekly buckets — it now gets its own status line segment:
Opus 5 | main | ctx:36% | 5h:70% ~1h54m | 7d:9% ~6d14h | Fable:15%
Read generically from the API's limits[] array, labelled from scope.model.display_name with fallbacks to model.id → surface → kind. No model name is hardcoded, so a bucket arriving or leaving with your plan needs no code change. A successful fetch is authoritative including by omission: a bucket you no longer have simply stops being reported.
New result keys: scoped_summary, scoped_alert, scoped_worst, scoped_worst_pct, scoped_worst_resets_in. All empty for accounts with no scoped limits, so nothing changes if you don't have one.
Honest staleness — ? instead of a spent figure
A cached percentage is trustworthy only until the window it describes resets. If fetches are failing when a window rolls over, the library can prove its figure is obsolete, so it drops the value and sets percent_unknown; the bundled status line renders 5h:?⚠.
Previously a rolled-over window displayed its last percentage indefinitely, next to a ~0 min countdown. Buckets are judged independently — a rolled-over 5h window leaves the weekly and scoped figures alone.
Fixes
- Field-shift bug in the bash cache parser.
_ql_parse_cachesplit jq output on\t, but tab is IFS whitespace, so bash strips leading tabs and collapses runs of them. Any empty field shifted every value after it — concretely, a null 5h percentage put the weekly figure intoQUOTA_RESULT[pct], silently. Both parsers now use0x1F, which is non-whitespace and preserves empty fields. This affected Linux/WSL2 users of 1.0.0. - Cache writes are now atomic (write-to-temp then rename). Several Claude Code sessions share one cache file, and a torn read parsed as "no cache", which sent that session down the blocking fetch path.
- Fetch lock uses
O_EXCL/FileMode::CreateNewinstead of check-then-write, which let simultaneous sessions all launch a fetch at once. Locks are abandoned after 120s, since a recycled PID would otherwise look like a fetch in flight forever. - Retries taper after failures — 60s → 120s → 240s → 480s, capped at 15 min, keyed on the
consecutive_failurescounter that already existed and was unused. A rate-limited endpoint was previously retried on every refresh, turning a brief outage into a long one. -NoProfileadded to the documented status line command. Without it your PowerShell profile loads on every refresh and any output it produces lands on stdout ahead of the status line.
Also in this release (from 1.1.0)
- An
errorresult key, so status lines can say why quota is missing instead of showing nothing or a bare stale marker - HTTP 200 without usage fields, and an unreadable
quota-data.json, are reported as explicit parse errors instead of failing silently /quotaskill always surfaces the error when stale or invalid- Execution-policy docs covering managed vs unmanaged machines
Cache schema 2 → 3
Adds scoped_limits[] and percent_unknown. Additive only — an older library reads a v3 cache without complaint.
Tests
New tests/test-quota-lib.sh — 38 checks over synthetic fixtures shaped like real API responses. No network calls, so it can't consume quota or trip rate limits. Requires jq.
bash tests/test-quota-lib.shUpgrading
Windows: re-run install.ps1. Linux/WSL2: re-run install.sh. Plugin users: reinstall from the marketplace to pick up 1.2.0. No cache reset needed — the schema change is additive.
v1.0.0 — plugin packaging, /quota skill, versioning
First tagged release.
Highlights
- Claude Code plugin: the repo is now its own plugin marketplace. Install with:
/plugin marketplace add aweussom/claude-code-quota /plugin install claude-code-quota@aweussom - /quota skill: the legacy
commands/quota.mdslash command is now a proper skill (skills/quota/SKILL.md), cross-platform and able to guide statusline setup. Installers migrate pre-1.0 command files automatically. - Fixed: the stale marker
⚠was silently mangled to?on Windows — captured stdout defaults to the OEM code page. The statusline template now sets UTF-8 output encoding. - Versioning: both libraries stamp
lib_versioninto the quota cache, so/quotacan report the installed version.
What it is
Claude OAuth quota (5-hour session % and weekly %) live in your Claude Code status line — no daemon, non-blocking cached fetches, and a cache format shared between native Windows (PowerShell, zero dependencies) and Linux/WSL2 (bash + jq).