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.