報表標題早就寫著這段期間的高峰日,你卻沒有任何圖可以對照——daily_trend 裡放著 30 天的資料,沒有任何圖表用到它。現在週彙總上方多了一條逐日的面積線,標出最高的那一天,並且只標期間的第一天與最後一天。樣式表也加了一段 @media print:各區塊避免在內部斷頁、互動控制項隱藏、陰影與位移移除,顏色反轉成白底深字,這樣讀者開著深色模式時列印的 PDF 仍然讀得下去。
新功能
報表的表格、圖表與區塊層次都補上了
最重的五個工作階段本來是報表裡唯一純文字的表格,現在權杖那一欄多了一條細長條,比例以這五個裡最大的為基準,顏色沿用模型表格那套供應商配色。作息時段圖以前只有小時標籤,現在會在右下角用低調的字標出尖峰值,沒有另外加格線或 Y 軸。十個區塊本來長得一模一樣,現在洞察與熱圖採用較重的陰影,近期工作與工具兩區則較輕、用 --faint 邊框——只動陰影與邊框,因為人物誌那區放了兩張卡,改背景會讓它們的高度差變得刺眼。
帶著 message.id 卻沒有 message.model 的訊息,會被編成一個空字串,但後面的檢查只測 model is None。所以這些事件既沒有被歸給任何模型,也沒有被算進未歸屬那一桶,上一張卡講的那個一次過關率因此把打斷數算少了。這次修好了。
新功能
完全沒有用量時,報表會顯示乾淨的空狀態
用量為零時,敘述句會把零和佔位符號一起填進去,變成 ---- -- -- was the peak (0/day), main LLM 未知,下方七個區塊全都只寫著「nothing here yet」——新使用者第一次打開看到的正是這個。現在 total_tokens 與 messages 都是零時,敘述改成 report_empty_state_hint,這個鍵五種語言都加了,並且只渲染標題、統計卡與贊助區塊。有資料時的輸出逐位元組相同,沒被動過的 full_zh_tw 與 full_en 快照就是證明。
English
FEATURE
Grok CLI gets its own usage status line
Grok CLI supports the same command-style status line mechanism as Claude Code, so usage_statusline_grok.py joins the existing install / remove / self-heal flow behind the switch already shared with Claude Code and Antigravity. Grok's stdin payload carries no rate-limit summary — its documentation says so explicitly — so the script tails ~/.grok/logs/unified.jsonl for creditUsagePercent and currentPeriod.end; when neither can be read the segment is omitted rather than printed as placeholder characters. Only the weekly axis is shown, since Grok has no 5-hour window and reports no cache hit ratio, and neither is estimated.
FEATURE
The status line's second row shows cache hit rate and a countdown
Claude Code 2.1.251 added a prompt_cache object to the status line hook's stdin JSON, and usage was already storing the whole payload in usage-status.json without reading it. The second row now shows the prompt cache hit rate and a countdown to expiry. A new color_by_pct_inverted() mirrors the thresholds, so a 91% hit rate reads as good instead of borrowing the quota palette's red, and progress_bar() takes an optional color_func, leaving existing callers unchanged. The segment is skipped entirely when caching_observed is not True or the ratio is unavailable, so older Claude Code versions silently omit it; an expired expires_at drops only the countdown and keeps the bar. Narrow terminals degrade in two further steps: the countdown goes first, then the whole segment.
FEATURE
The status line lights up the numbers and dims everything else
Empty progress cells, the context window total, and the | separators were pure white and brighter than the figures themselves; they are now grey 240 / dim, leaving usage as the only lit element. The second row is secondary information, so a cache hit rate of 80% or better takes that row's muted purple and only turns orange below 80% and red below 50% — good news does not need to glow. The same batch reworded the cache countdown. The previous wording was a literal rendering of warm/cold that read as nothing in particular; it now reuses the existing remaining_prefix, giving (59min left) in English alongside the two segments before it. cache_cold_suffix, used in exactly one place, was removed, so five languages no longer need a separate word for it.
BUGFIX
A third-party status line with a similar name is no longer taken over
Hook ownership was decided by the substring test "usage-statusline" in cmd, so someone else's usage-statusline-pro.py was treated as a usage installation: taken over without a backup, and its configuration deleted on uninstall. The comparison now matches the complete filename, derived from HOOK_TARGET.name and its siblings instead of a hardcoded string, requiring a path separator, quote, whitespace, or string boundary on each side. It deliberately does not compare full paths: the command string shifts with interpreter location, quoting, and Windows backslashes, and a path comparison would stop usage recognizing itself.
BUGFIX
The status line's file lock times out instead of hanging
Every message you sent left the status line stalled, because another process was holding the same lock. _exclusive_lock()'s POSIX branch used a plainly blocking flock(LOCK_EX), while the Windows branch already had a 10-second _LOCK_TIMEOUT_S guard. The POSIX branch now polls with LOCK_EX | LOCK_NB and, on timeout, follows the msvcrt path: the atomic write proceeds without the lock.
FEATURE
Installed status line copies actually update now
needs_update() compares __version__ in ~/.claude/usage-statusline.py against HOOK_VERSION and skips the copy when they match, so rendering changes that shipped without a version bump never reached an installed copy, silently and with no error. Both constants were bumped, and a drift test was added: the Token Saver hook had that guard already; the status line was missing it.
FEATURE
The report adds a first-pass rate, compared across models
The report's usage habits section gained a card measuring what share of your turns this period ran without an interruption and without a blocked tool call, split by model — a quality axis rather than another quota count. Both signals are structural, read from ~/.claude/projects: interruptedMessageId on user lines, and permission-denial strings inside tool_result content; nothing is inferred semantically. The denominator is user turns rather than assistant messages, because a single exchange emits a dozen assistant messages and would compress every model above 99.5%. Multiple interruptions inside one turn count once. Angle-bracketed internal markers such as <synthetic> are excluded. Interrupted assistant messages are frequently aborted before reaching disk, so unresolvable signals go to an unattributed bucket and are not shown rather than being assigned to a model. The insight line is written only when the spread between the highest and lowest model exceeds 15 points.
FEATURE
The report draws a day-by-day curve and prints properly
The report's header already named the period's peak day, but you had no chart to check it against: daily_trend held 30 days of data that no chart used. A daily area line now sits above the weekly rollup, marking the highest day and labelling only the period's first and last dates. The stylesheet also gained a @media print block: sections avoid internal page breaks, interactive controls are hidden, shadows and offsets are removed, and colors invert to dark-on-white so a PDF stays readable when the reader is in dark mode.
FEATURE
The report's tables, charts, and section rhythm were filled in
The five heaviest sessions were the report's only all-text table; the tokens column now carries a thin bar scaled against the largest of the five, colored by the same provider palette the model table uses. The active-hours chart, previously hour labels alone, now marks its peak value in muted type in the lower right, with no gridlines or Y axis added. The ten sections shared one identical treatment; insights and the heatmap now carry heavier shadows while the recent-work and tools sections are lighter with --faint borders — shadows and borders only, since the persona section holds two cards and a background change would make their height difference conspicuous.
FEATURE
Project and model rows in the report carry share bars
Comparing ten stacked rows previously meant reading the numbers. Each name now has a 4px solid proportion bar beneath it — solid rather than gradient, so the color is not misread as carrying meaning. The donut's "Other" slice, which used to draw the palette's seventh color and read as nearly the same green as the first, is now a neutral #8b8577, selected inside _donut_svg by a synthetic flag rather than guessed from its index.
BUGFIX
A week still in progress is no longer compared against a complete one
The weekly trend measured the current partial week against the previous full one, which on Monday 2026-08-31 produced "W36 ↘ −97%" and the conclusion that this week was 97% lighter. The final week is now marked in progress when its Sunday falls after date_to (new trend_week_in_progress key, added in all five languages) and shows no percentage, and _trend_summary() compares the last two completed weeks instead.
BUGFIX
The Antigravity model name stops mixing two languages, and the menu bar title tightens
Antigravity's display_name already ends in an English effort suffix such as (High), and usage appended a localized one after it, naming the same level twice in two languages. The English suffix is now stripped and only the localized label is kept; when display_name carries no effort field, the stripped suffix becomes the source. The menu bar title tightened up too: the interpunct separator was removed, since the provider icons already separate the figures, and icon spacing was reduced to two spaces. Separately, prompt cache health was documented in all five READMEs under real-time visibility, noting it needs Claude Code 2.1.251 or newer, and the website's description of the AI Tool Update Digest was removed, a report section that no longer exists.
FEATURE
Uninstalling restores Grok's original status line
unsetup() handled Claude Code and Codex but skipped Grok, so after --unsetup the user's ~/.grok/config.toml still pointed at a usage script with no supported way back to their own [ui.status_line]. Uninstalling now restores Grok's original status line. The old test exercised only the private _unsetup_grok(), which is why this slipped through; the new one enters through the public unsetup().
FEATURE
Weekly burn trend bars are now CSS gradients
The donut, heatmap, and active-hours chart on the same page were all drawn graphics, while the weekly trend drew its bars with █ characters, looking pasted in from another document. Those bars are now CSS gradients. The four-column layout and terminal styling are unchanged; the rendering moved into a new ui/report_charts.py.
BUGFIX
The heatmap stops skipping months, and the donut agrees with the table
A heatmap column's month was taken from its Monday, so a week spanning a month boundary was credited to the old month it barely touched, and a label suppressed by the spacing rule was lost permanently — real output dropped September entirely. The month is now read from the column's Thursday and compared against the last month actually labelled, so a suppressed month reappears at the next column that satisfies the spacing. Separately, the project donut divided by the sum of by_project[:10] while the table's percentage used total tokens, so one project showed 42.5% in the chart and 36.1% in the table, and the center figure read as a total it was not. The denominator is now summary.total_tokens, with everything not shown (including projects outside the top ten) combined into an "Other" slice reusing the existing report_chart_other string.
BUGFIX
Interruptions and denied tools on messages with no model name are no longer dropped
A message carrying message.id but no message.model was indexed as an empty string, while the later check tested only model is None. Those events were therefore neither attributed to a model nor counted as unattributed, undercounting interruptions in the first-pass rate described on the previous card. That is now fixed.
FEATURE
A report with no usage renders a clean empty state
At zero usage the narrative sentence interpolated zeros and placeholders — "---- -- -- was the peak (0/day), main LLM 未知" — above seven sections each saying only "nothing here yet", which is what a new user saw on first open. When both total_tokens and messages are zero the narrative is now replaced by report_empty_state_hint, a key added in all five languages, and only the header, stat cards, and sponsor section render. Output with data is byte-identical; the untouched full_zh_tw and full_en snapshots are the proof.
原始 CHANGELOG
Original changelogGrok CLI 也有自己的用量狀態列了
**Grok CLI now gets its own `usage` status line.** Grok CLI supports the same command-style status line mechanism as Claude Code, so `usage_statusline_grok.py` joins the existing install / remove / self-heal flow behind the switch already shared with Claude Code and Antigravity. Grok's stdin payload carries no rate-limit summary (its documentation says so explicitly), so the script tails `~/.grok/logs/unified.jsonl` for `creditUsagePercent` and `currentPeriod.end`; when neither can be read the segment is omitted rather than printed as placeholder characters. Only the weekly axis is shown — Grok has no 5-hour window and reports no cache hit ratio, and neither is estimated.
Original changelog狀態列第二行看得到快取命中率與到期倒數
**The status line's second row now shows prompt cache hit rate and a countdown to expiry.** Claude Code 2.1.251 added a `prompt_cache` object to the status line hook's stdin JSON; `usage` was already storing the whole payload in `usage-status.json` without reading it. A new `color_by_pct_inverted()` mirrors the thresholds, so a 91% hit rate reads as good instead of borrowing the quota palette's red, and `progress_bar()` takes an optional `color_func` leaving existing callers unchanged. The segment is skipped entirely when `caching_observed` is not `True` or the ratio is unavailable, so older Claude Code versions silently omit it; an expired `expires_at` drops only the countdown and keeps the bar. Narrow terminals degrade in two further steps: the countdown goes first, then the whole segment.
Original changelog狀態列只把數字點亮,其餘壓暗
**The status line dims what isn't the number.** Empty progress cells, the context window total, and the `|` separators were pure white and brighter than the figures themselves; they are now grey 240 / dim, leaving usage as the only lit element. The second row is secondary information, so a cache hit rate of 80% or better takes that row's muted purple and only turns orange below 80% and red below 50% — good news does not need to glow.
**The cache countdown now says "left", matching the 5-hour and 7-day segments.** The previous wording was a literal rendering of warm/cold that read as nothing in particular; it now reuses the existing `remaining_prefix`, giving `(59min left)` in English alongside the two segments before it. `cache_cold_suffix`, used in exactly one place, was removed, so five languages no longer need a separate word for it.
Original changelog別人的同名狀態列腳本不再被當成自己的接管
**A third-party status line with a similar name is no longer mistaken for our own.** Hook ownership was decided by the substring test `"usage-statusline" in cmd`, so someone else's `usage-statusline-pro.py` was treated as a `usage` installation: taken over without a backup, and its configuration deleted on uninstall. The comparison now matches the complete filename, derived from `HOOK_TARGET.name` and its siblings instead of a hardcoded string, requiring a path separator, quote, whitespace, or string boundary on each side. It deliberately does not compare full paths — the command string shifts with interpreter location, quoting, and Windows backslashes, and a path comparison would stop `usage` recognizing itself.
Original changelog狀態列的檔案鎖改成等一段時間就放行
**The status line's file lock now times out instead of hanging a message.** `_exclusive_lock()`'s POSIX branch used a plainly blocking `flock(LOCK_EX)` while the Windows branch already had a 10-second `_LOCK_TIMEOUT_S` guard, so a process holding the lock stalled the status line on every message. The POSIX branch now polls with `LOCK_EX | LOCK_NB` and, on timeout, follows the `msvcrt` path: the atomic write proceeds without the lock.
Original changelog已安裝的狀態列副本真的會跟著更新了
**Installed status line copies now actually update.** `needs_update()` compares `__version__` in `~/.claude/usage-statusline.py` against `HOOK_VERSION` and skips the copy when they match, so rendering changes that shipped without a version bump never reached an installed copy, silently and with no error. Both constants were bumped, and a drift test was added — the Token Saver hook had that guard already; the status line was missing it.
Original changelog報表多了一項「一次過關率」,各模型分開比
**The HTML report's usage habits section now has a first-pass rate, compared across models.** The card measures what share of your turns this period ran without an interruption and without a blocked tool call, split by model — a quality axis rather than another quota count. Both signals are structural, read from `~/.claude/projects`: `interruptedMessageId` on user lines, and permission-denial strings inside `tool_result` content; nothing is inferred semantically. The denominator is user turns rather than assistant messages, because a single exchange emits a dozen assistant messages and would compress every model above 99.5%. Multiple interruptions inside one turn count once. Angle-bracketed internal markers such as `<synthetic>` are excluded. Interrupted assistant messages are frequently aborted before reaching disk, so unresolvable signals go to an unattributed bucket and are not shown rather than being assigned to a model. The insight line is written only when the spread between the highest and lowest model exceeds 15 points.
Original changelog報表加了逐日曲線,列印出來也讀得下去
**The report's trend section now draws a day-by-day curve for the period, and prints properly.** `daily_trend` already held 30 days of data that no chart used, leaving the peak day named in the header with nothing to check it against. A daily area line now sits above the weekly rollup, marking the highest day and labelling only the period's first and last dates. The stylesheet also gained a `@media print` block: sections avoid internal page breaks, interactive controls are hidden, shadows and offsets are removed, and colors invert to dark-on-white so a PDF stays readable when the reader is in dark mode.
Original changelog報表的表格、圖表與區塊層次都補上了
**The report's heaviest-sessions table, active-hours chart, and section rhythm were filled in.** The five heaviest sessions were the report's only all-text table; the tokens column now carries a thin bar scaled against the largest of the five, colored by the same provider palette the model table uses. The active-hours chart, previously hour labels alone, now marks its peak value in muted type in the lower right, with no gridlines or Y axis added. The ten sections shared one identical treatment; insights and the heatmap now carry heavier shadows while the recent-work and tools sections are lighter with `--faint` borders — shadows and borders only, since the persona section holds two cards and a background change would make their height difference conspicuous.
Original changelog報表的專案與模型列多了佔比條
**Project and model rows in the report now carry share bars.** Comparing ten stacked rows previously meant reading the numbers; each name now has a 4px solid proportion bar beneath it — solid rather than gradient, so the color is not misread as carrying meaning. The donut's "Other" slice, which used to draw the palette's seventh color and read as nearly the same green as the first, is now a neutral `#8b8577`, selected inside `_donut_svg` by a synthetic flag rather than guessed from its index.
Original changelog還沒過完的一週不再拿去跟完整的一週比
**A week still in progress is no longer compared against a complete one.** The weekly trend measured the current partial week against the previous full one, which on Monday 2026-08-31 produced "W36 ↘ −97%" and the conclusion that this week was 97% lighter. The final week is now marked in progress when its Sunday falls after `date_to` (new `trend_week_in_progress` key, added in all five languages) and shows no percentage, and `_trend_summary()` compares the last two completed weeks instead.
Original changelogAntigravity 的模型名不再兩種語言混寫,選單列標題也縮短
**The Antigravity model name no longer mixes two languages.** Antigravity's `display_name` already ends in an English effort suffix such as `(High)`, and `usage` appended a localized one after it, naming the same level twice in two languages. The English suffix is now stripped and only the localized label is kept; when `display_name` carries no effort field, the stripped suffix becomes the source.
**The menu bar title tightened up.** The interpunct separator was removed, since the provider icons already separate the figures, and icon spacing was reduced to two spaces.
Documented prompt cache health in all five READMEs under real-time visibility, noting it needs Claude Code 2.1.251 or newer, and removed the website's description of the AI Tool Update Digest, a report section that no longer exists.
Original changelog移除時會把 Grok 原本的狀態列放回去
**Uninstalling now restores Grok's original status line.** `unsetup()` handled Claude Code and Codex but skipped Grok, so after `--unsetup` the user's `~/.grok/config.toml` still pointed at a `usage` script with no supported way back to their own `[ui.status_line]`. The old test exercised only the private `_unsetup_grok()`, which is why this slipped through; the new one enters through the public `unsetup()`.
Original changelog週燃燒趨勢的長條改用 CSS 漸層畫
**Weekly burn trend bars are now CSS gradients.** The weekly trend drew its bars with `█` characters while the donut, heatmap, and active-hours chart on the same page were graphical. The four-column layout and terminal styling are unchanged; the rendering moved into a new `ui/report_charts.py`.
Original changelog熱圖不再漏標月份,甜甜圈的百分比跟表格對得上
**The heatmap's month labels no longer skip or mislabel a month.** A column's month was taken from its Monday, so a week spanning a month boundary was credited to the old month it barely touched, and a label suppressed by the spacing rule was lost permanently — real output dropped September entirely. The month is now read from the column's Thursday and compared against the last month actually labelled, so a suppressed month reappears at the next column that satisfies the spacing.
**The project donut's percentages now agree with the table beneath it.** The donut divided by the sum of `by_project[:10]` while the table's percentage used total tokens, so one project showed 42.5% in the chart and 36.1% in the table, and the center figure read as a total it was not. The denominator is now `summary.total_tokens`, with everything not shown — including projects outside the top ten — combined into an "Other" slice reusing the existing `report_chart_other` string.
Original changelog沒有模型名稱的打斷與被擋工具不再被丟掉
**Interruptions and denied tools on messages with no model name are no longer dropped.** A message carrying `message.id` but no `message.model` was indexed as an empty string, while the later check tested only `model is None` — so those events were neither attributed to a model nor counted as unattributed, undercounting interruptions in the first-pass rate.
Original changelog完全沒有用量時,報表會顯示乾淨的空狀態
**A report with no usage now renders a clean empty state.** At zero usage the narrative sentence interpolated zeros and placeholders — "---- -- -- was the peak (0/day), main LLM 未知" — above seven sections each saying only "nothing here yet", which is what a new user saw on first open. When both `total_tokens` and `messages` are zero the narrative is replaced by `report_empty_state_hint` (added in all five languages) and only the header, stat cards, and sponsor section render. Output with data is byte-identical; the untouched `full_zh_tw` and `full_en` snapshots are the proof.