Release notes

BUGFIX

Usage estimates no longer count CJK text at one quarter of its size

If you use Chinese, Japanese, or Korean files to diagnose waste, the old figures were four times too small. The diagnostic treated every four characters as one token (the unit an AI uses to measure text). That works for ASCII text, but a CJK character is roughly one token. It now counts each CJK codepoint as one token and keeps the four-characters-per-token estimate for everything else, so reported waste and the cost based on it no longer shrink to a quarter of their real estimate. It was like weighing tomatoes but recording only one for every four on the scale. The tool remains offline; it does not add a model-specific tokenizer just to chase tiny rounding differences.

FEATURE

A damaged cache is quarantined instead of erased

When a usage number looks wrong, a damaged cache (stored results reused instead of recomputed) will no longer vanish immediately. Antigravity, Codex, and history caches still recover by recomputing an unreadable file, but first move the original into ~/.usage/quarantine/ so there is something to inspect later. Names include a millisecond timestamp, so a second failure cannot replace the first; the folder holds at most ten files, up to 5 MB each. It is like bagging a damaged lab sample before taking a new one instead of throwing away the only clue. An old schema_version is excluded because it is a normal upgrade. With 32 shards per cache, quarantining an entire version bump would crowd out the evidence from a real failure.

BUGFIX

`--doctor` separates a missing file from one you do not need

When you run --doctor to check an installation, forwarder script: [missing] no longer automatically means trouble. The report used to flatten fourteen checks into one list, so it showed a missing forwarder script even in a mode that never uses one. A forwarder script is simply a script that passes data along. Results are now separated into [core], [hook], and [optional]; a mode that does not need the script says [not needed in <state> mode]. It is like a health report separating required tests, elective tests, and tests that do not apply instead of marking every absent test red. The checking logic itself did not change; a file required by the current mode is still reported as missing.

FEATURE

Windows tray tests write to your real preferences

After a Windows developer ran tray tests, their own panel preference changed in silence. The tray is the corner of the Windows taskbar where background-app icons live. Two tests call switch_panel(), which then writes preferences through _save_active_panel_id(). But the tests did not redirect prefs.PREFERENCES_FILE to a temporary location, so they wrote to the real ~/.claude/usage-preferences.json. The tests were meant to rearrange furniture in a model home, yet walked into your living room instead.

FEATURE

Documentation checks now watch all four README translations

When the English README gains a section, the Simplified Chinese, Japanese, and Korean versions are now checked for keeping up too. check_doc_parity.py used to compare English only with Traditional Chinese, leaving the other three translations guarded only by a hand-written reminder in CLAUDE.md. Each translation is now compared with English on its own, and a failure names the file that drifted. The check counts ## headings rather than matching their wording, so translators can still write natural headings instead of copying English word for word. It is like checking that every language edition of an exhibition has the same number of gallery doors, without forcing all the signs to use identical words.

FEATURE

A local-install script keeps the menu bar from quietly running an old build

After you make a local build (a compiled, runnable version of the app), adding a release tag does not replace the copy already running from /Applications. That final step used to live only in a checklist, and the menu bar once kept running a build six versions old. For a local install, run scripts/install_local.sh. It confirms the build exists, prints both versions, waits for the running app to exit, swaps the files, and verifies that the installed version matches. Buying a new light bulb is not the same as putting it in the socket. The script links removing the old bulb, fitting the new one, and checking that the light turns on, so the local copy actually catches up.

Original changelog

Original changelogUsage estimates no longer count CJK text at one quarter of its size
**Token estimates no longer undercount CJK text by a factor of four.** Six places in the waste diagnosis converted characters to tokens with `chars // 4`, which is the ASCII ratio. A CJK character is roughly one token, not a quarter of one, so every figure the diagnosis reported for a Chinese, Japanese or Korean file — wasted tokens and the cost derived from them — came out at a quarter of the truth. This project reads its own `i18n.json`, `CLAUDE.md` and `README.zh-TW.md` often enough to hit this on itself. The estimate now counts CJK codepoints as one token each and everything else at four characters per token. No tokenizer dependency was added: this is an offline tool, and pulling in a model-specific tokenizer to chase rounding-level accuracy is not a trade worth making.
Original changelogA damaged cache is quarantined instead of erased
**A corrupt disk cache is preserved instead of being deleted outright.** All three caches — Antigravity, Codex and history — dealt with an unreadable file by removing it and recomputing. That is the right recovery, but it also destroys the only evidence of what went wrong, so a later report of "my numbers look off" has nothing left to inspect. A damaged file is now moved to `~/.usage/quarantine/` first, named with a millisecond timestamp so a second failure cannot overwrite the first, capped at ten files and 5 MB each. A stale `schema_version` is *not* quarantined: that is an ordinary upgrade, and with 32 shards per cache one version bump would flush the whole budget and push the real evidence out. The quarantine helper swallows every error it can hit — it is a side service and must never take the caller down with it.
Original changelog`--doctor` separates a missing file from one you do not need
**`--doctor` no longer reports a missing file that the current mode does not use.** The report listed fourteen checks as one flat list, so `forwarder script: [missing]` read as a fault even when the installed mode never needs that script. It is now grouped into `[core]`, `[hook]` and `[optional]`, and the forwarder line says `[not needed in <state> mode]` when that is the case. None of the check logic changed.
Original changelogWindows tray tests write to your real preferences
**Two Windows tray tests wrote into the real `~/.claude/usage-preferences.json`.** Both call `switch_panel()`, which persists through `_save_active_panel_id()`, and neither patched `prefs.PREFERENCES_FILE` — so running the suite silently changed the developer's own active panel.
Original changelogDocumentation checks now watch all four README translations
**The documentation parity check covers Simplified Chinese, Japanese and Korean.** `check_doc_parity.py` only compared English against Traditional Chinese, leaving the other three README translations unwatched; `CLAUDE.md` had to carry a note to sync them by hand. Each translation is now compared on its own and the failure message names the file that drifted. The comparison is still a count of `##` headings rather than their text — matching text would force translators to mirror English headings word for word, which is what makes translated docs read badly.
Original changelogA local-install script keeps the menu bar from quietly running an old build
**`scripts/install_local.sh` replaces the hand-typed steps for installing a build locally.** Releasing does not touch `/Applications`: the tag drives CI, and the local copy keeps running whatever was already there. That last step lived only in a checklist, and the menu bar once ran a stale build for six versions before anyone noticed. The script checks the build exists, prints both versions, waits for the running app to exit, swaps it, and verifies the installed version matches.