Repository navigation
feat(statusline): configure how the quota row shows usage and resets - #537
Merged
Merged
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
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
force-pushed
the
feat/statusline-usage
branch
from
October 20, 2026 08:08
18e00a5 to
0185cc9
Compare
…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.
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.
Brings the quota row in line with claude-hud's usage line. A new
usagegroup 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 whetherresets inintroduces it.usage.thresholdhides the row until a window has used that much, andusage.sevenDayThresholdhides the weekly window beside a five-hour one until it has. These only decide what is drawn; the colour bands stay withbands.*, 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
clockgroup rather than part ofusage, 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, soStatuslinePortsgains aclockport (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_scopedand 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 theirperiodMsthrough 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
--statuslineassignments gain a boolean kind. The parity map and table,docs/configuration-model.mdand the generated schemas follow.