Skip to content

feat(statusline): configure how the quota row shows usage and resets - #537

Merged
Mearman merged 14 commits into
mainfrom
feat/statusline-usage
Oct 20, 2026
Merged

Mearman merged 14 commits into
mainfrom
feat/statusline-usage

Conversation

@Mearman

@Mearman Mearman commented Oct 19, 2026

Copy link
Copy Markdown
Member

Brings the quota row in line with claude-hud's usage line. A new usage group sets whether a window's figure is the share used or left, whether windows are bars, plain text or one compact line, how a reset is told (time left, wall-clock time, both, share of the window elapsed, or elapsed plus wall-clock) and whether resets in introduces it. usage.threshold hides the row until a window has used that much, and usage.sevenDayThreshold hides the weekly window beside a five-hour one until it has. These only decide what is drawn; the colour bands stay with bands.*, where claude-hud's usage colours are fixed. Every default reproduces the previous output, so claude-hud's own defaults (reset label on, per-model windows on, weekly threshold of 80) are recorded in the parity table rather than adopted.

Hour cycle and clock seconds are a clock group rather than part of usage, because claude-hud applies them to every wall-clock time it draws and later elements will share them. Wall-clock times need the machine's locale and time zone, so StatuslinePorts gains a clock port (the fake is en-GB in UTC) and the formatting stays a pure function of the context.

Model-scoped weekly windows come from the payload's rate_limits.model_scoped and are drawn after the account's own windows only for a session that selected no provider, since they describe the signed-in account and the enriched snapshot windows already cover provider sessions. Provider quota windows now carry their periodMs through the summary so the elapsed forms work for them; a model family's window has no known length and shows no elapsed share. claude-hud's "limit reached" notice is not drawn, as a window at its limit is already a full bar in the critical colour.

The key listing and --statusline assignments gain a boolean kind. The parity map and table, docs/configuration-model.md and the generated schemas follow.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
🔒 Security Review ⚠️ Failed 2026-10-19T21:37:31.862933Z a303d7b PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

This security review couldn’t start because the paying account has exhausted its Codex allowance and has insufficient available credits. The payer can check their balance and add credits in the Codex usage dashboard, then try again. If you do not manage the paying account, contact this repository's admins.

Add a `usage` group (value, bar, compact, resetLabel, modelScoped,
timeFormat, threshold, sevenDayThreshold) and a shared `clock` group
(hourCycle, seconds) to the statusline settings, and make the quota row
follow them. The figure can be the share used or left, drawn as bars,
as text, or as one compact line. A reset can be told as time left, a
wall-clock time, both, or the share of the window already gone, with
`at`, `resets` and `resets in` wording on request.

The per-model weekly windows in the client's payload join the account's
own windows for a session that selected no provider. Wall-clock times
come from a new `clock` port (locale and time zone), so the row stays
a function of its context. The key listing and `--statusline` assignments
gain a boolean kind. Every default reproduces the previous output, so
the new options only apply when a layer names them.
…ol ranking

The expiring-quota publisher restated the five-hour and seven-day window lengths that the pool
ranking already exports. One definition now serves both.
…times as the locale does

The quota row drawn as text or as a compact line was one unbroken line, so several windows
overflowed a narrow terminal. Elements now receive the usable width, and the windows are packed
onto lines with the header's packing (extracted as `packLines`), separated by the usual pipe.

A reset under half a second away rounds to no time left but was still counted as pending, which
produced "resets in available". Whether a reset is pending now follows the rounded time left.

Wall-clock hours are written the way the locale writes them in the cycle in use: padded in a
24-hour cycle, unpadded in a 12-hour one. Formatters are built once per locale, zone and options.

Model names from the client are cleaned with the statusline's display-text sanitiser, which leaves
emoji sequences whole, and cut on grapheme boundaries through the config module's own segmenter.
…e form

Hour padding was chosen from the hour cycle alone, so locales whose short time form is unpadded in
a 24-hour cycle (Japanese, Spanish, Czech) or pad in a 12-hour one (Gujarati) read differently from
how their users write the time, and Finnish got a colon where it uses a point. The time is now the
locale's own short form, or its medium form with seconds, in the chosen cycle.
visibleLength counted code units, so wide East Asian characters under-counted and joined emoji
sequences over-counted, and a line packed on that measure overflowed or wrapped early. It now
returns the columns a string draws, through string-width, which also ignores every escape sequence
and not only colours.
A reset under a minute away was drawn as 0m, which reads as nothing left rather than moments.
…ota row's wrapping by columns

An operating system command with no terminator left its payload behind in sanitised text, and a
model name made of zero-width or separator characters drew a window with an invisible label. The
sanitiser now removes an unterminated command up to the next escape, and the quota row strips
format and separator characters (keeping the joiners that hold emoji sequences together), then
skips a name with nothing left. The row's text wrapping is tested by columns, with colour, with
wide characters and joined emoji, with a part wider than the line, and at the width floor.
…ar glyphs in columns

The quota row's name cleaning joined "Claude Opus" into "ClaudeOpus", dropped the non-joiner that
Persian and Indic spelling needs, and cut a flag emoji down to a bare flag. The cleaning is now
`visibleDisplayText` in the sanitiser, shared by anything that draws a name from the client: spaces
of any width become a plain space, joiners and the tag characters of a flag stay, other invisible
format characters and line separators go, and the result is empty when nothing visible is left,
including a name of Braille blanks or Hangul fillers.

A window label's limit is now terminal columns rather than characters, in the setting and in the
cut applied to a client's model name, so a wide character counts for two. A bar character must
take exactly one column, because a bar repeats it once per column and a wide glyph doubled the
bar's width. The hour cycle setting's description names every value.
The comment on `formatDuration` credited another client's statusline and omitted the seconds form.
It now lists the forms, and the parity table does too. A reset under a minute is drawn in seconds,
where it was drawn as 0m before the seconds form.
@Mearman
Mearman force-pushed the feat/statusline-usage branch from 18e00a5 to 0185cc9 Compare October 20, 2026 08:08
…idth

`truncateToColumns` counted the bytes of an escape sequence as characters and could cut one in
half, leaving a stray escape byte on the line. It now treats a sequence as zero columns, never cuts
it, and keeps the ones after the cut so a colour that began is also ended. The sequence pattern is
exported from the ANSI module and shared with the sanitiser.
…shared definition

A name, a label or a bar character made of a lone combining mark, a variation selector, a joiner or
a Hangul filler drew nothing but was accepted or kept. `drawsNothing` now decides it: text takes no
terminal column once its blank cells (spaces of any width, the Braille blank, the Hangul fillers)
are set aside. `visibleDisplayText` returns an empty string for such input and is idempotent; a
label or bar character that draws nothing is refused by the schema.
… name

A space with a shaping character attached (a joiner, a variation selector, a combining mark) formed
one grapheme that measured as nothing, so the space was dropped with it and "Claude Opus" read
"ClaudeOpus". A leading space is now split off before the rest is measured, so the break stays.

The Hangul choseong and jungseong fillers were turned into spaces wherever they stood, which split
decomposed syllables. They are now blank only when they stand apart from a jamo cluster.

The control and bidirectional class is written with escapes, and a test runs every code point
against an independent list of the ranges it removes.
…glyphs as escapes

`truncateToColumns` kept a flag that could never change what it returned, because the running width
stays above the limit once it is crossed. The changed statusline sources and tests now write
non-ASCII glyphs as escapes so they survive copy and paste, with identical meaning.
…s cluster

The lookbehind half of the standalone-filler rule and the ends of each jamo range were untested, so
removing the lookbehind or moving any range end by one left every test green. The first and last
code point of each range, the code point just outside each, and both fillers on either side are
now checked. A doc comment in the quota tests that sat above the wrong constant moves to the
environment it describes.
@Mearman
Mearman merged commit 5576549 into main Oct 20, 2026
31 checks passed
@Mearman
Mearman deleted the feat/statusline-usage branch October 20, 2026 09:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant