Skip to content

Releases: aweussom/claude-code-quota

v2.0.0 — PowerShell 7 required, UTF-8 BOMs on all .ps1

Choose a tag to compare

@aweussom aweussom released this 18 Aug 11:20

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 #Requires is evaluated, so without a BOM no version gate could
    ever fire.
  • #Requires -Version 7.0 on install.ps1, statusline.ps1.template, and
    _quota-fetch-helper.ps1.
  • install.ps1 exits 1 if not on 7+, and separately if pwsh is missing from
    PATH — Claude Code launches the statusline as pwsh ..., so resolving in
    the installing shell is not enough.
  • Both powershell.exe fallbacks removed. quota-lib.ps1 relaunches 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, #Requires on entry points, absence of
    any powershell.exe fallback, 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

Choose a tag to compare

@aweussom aweussom released this 11 Aug 12:14

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.json was stuck at 1.0.0 through both bumps, so /plugin marketplace add was offering 1.0.0 regardless of what was on main. 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.idsurfacekind. 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_cache split 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 into QUOTA_RESULT[pct], silently. Both parsers now use 0x1F, 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::CreateNew instead 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_failures counter that already existed and was unused. A rate-limited endpoint was previously retried on every refresh, turning a brief outage into a long one.
  • -NoProfile added 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 error result 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
  • /quota skill 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.sh

Upgrading

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

Choose a tag to compare

@aweussom aweussom released this 28 Jul 20:33

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.md slash 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_version into the quota cache, so /quota can 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).