繁體中文

新功能

面板系統大翻新,多款酷炫主題隨你換

現在你可以隨心情自由切換各種風格的用量面板了。原本只有單一款式的預設面板,現在底層改用現代網頁技術(HTML/CSS)重新打造,不僅讓按鈕有了按壓的微縮回饋、減少了開啟時的白畫面閃爍,還一口氣推出了多款新選擇:深色簡約風(Minimal)、像醫療儀器的波形圖(ECG,波形振幅隨用量比例變化,消耗越快節奏越強)、字元如雨落下的駭客任務風(Matrix),以及帶有台灣國旗的在地化面板。就像是把只能看時間的傳統電子錶,換成了能隨時下載酷炫動畫錶面的智慧型手錶,而且運作起來比以前更順暢。

新功能

支援 Antigravity,第三個 AI 錢包也幫你管牢

你現在能同時掌控 Antigravity 的用量了,不用擔心第三個 AI 工具花超支。面板上多出了一張專屬卡片,把你的目前用量(Session,短時間窗)與每週上限(Weekly,長時間窗)分得清清楚楚。更聰明的是,如果你的額度完全沒動過,它會貼心地把重置時間藏起來,不會一直顯示無意義的「大約 24 小時後重置」。就像是你的財務管家,不只幫你管好原有的兩個錢包,現在連第三個新錢包也一併照顧好,而且在裡面沒錢流動時絕對不來煩你。

新功能

進度條顏色隨用量變換,油表見底一眼即知

現在你一瞥就能掌握用量到底多緊繃,不用停下來細讀數字。各項工具的進度條不再永遠是同一個顏色,現在會根據你燒掉的額度自動改變警告色:50% 以下是原本的品牌色(Claude 的橘色或 Codex 的青色),超過一半會變成琥珀黃提醒你,要是達到 80% 以上就會直接轉成警告紅。這就像開車時的油表,平常是綠的,快沒油時會亮黃燈,見底時直接亮紅燈警告,讓你用眼角餘光也能立刻警覺。

新功能

重新整理不再卡頓,底層除蟲與效能大升級

你點開選單列時,畫面不再會有惱人的瞬間凍結了。以前每次重新整理用量,介面都會稍微卡一下,現在這些讀取工作全被移到背景執行,確保隨點隨開。另外,系統也修好了一大堆可能嚇到你的小問題:像是網路不穩時估算成本不再永遠卡在舊數字、介面也不會再莫名報錯,而各種抓取用量的邏輯(包含過濾舊紀錄、排查壞掉的紀錄檔)也變得更精準,甚至連價格快取(cache,先把查好的定價存起來,下次直接用不用重查)都會在七天後自動過期,以免模型降價你還在看舊的貴數字。就像是請管家從原本在客廳當面整理帳單,改成在後台默默把帳算好再遞給你,完全不打斷你做正事。

新功能

正名與打包,免敲指令即可雙擊啟動並自動清理

你再也不用打開終端機敲一堆指令才能安裝和執行它了。這項工具正式更名為「usage」,並且被妥善打包成了完整的 macOS 應用程式(.app),現在可以雙擊直接啟動;而且不論你把它放在哪個資料夾,內建的 hook(用來在背景抓取用量的腳本)都能自動辨識並找到對的路徑來安裝。如果你以前裝過舊版(當時叫 usag),它還會很乖巧地清理掉 v0.1.x 遺留的特定殘留路徑與啟動項目,同時明確保留既有的設定路徑與執行檔名稱不動,以免破壞現有安裝。就像是原本要自己看說明書動手鎖螺絲的家具,現在變成了開箱即用的成品,不僅把上一代留下來的特定垃圾順手帶走、保留了你已經習慣的擺設,連名字也印得更漂亮了。

English

FEATURE

Panel system completely revamped with multiple cool themes to choose from

You can now freely switch between various usage panel styles to suit your mood. The default panel, which previously only had one look, has been rebuilt from the ground up using modern web technologies (HTML/CSS). This not only adds subtle press-shrink feedback to buttons and reduces the white flash on opening, but also introduces several new choices: a dark Minimal style, a medical monitor waveform (ECG, where the waveform amplitude scales with usage percentage and higher burn rates produce more intense rhythms), a digital-rain Matrix style, and a localized Taiwan panel featuring its flag. It's like upgrading a basic digital watch that only tells time into a smartwatch where you can download cool animated faces anytime, and it runs smoother than ever.

FEATURE

Antigravity support added to keep a tight grip on your third AI wallet

You can now keep track of your Antigravity usage simultaneously, so you don't have to worry about overspending on a third AI tool. The panel now features a dedicated card for it, clearly splitting your current usage (Session) and weekly cap (Weekly). Even smarter, if you haven't touched your quota at all, it politely hides the reset time instead of endlessly displaying a meaningless "reset in ~24h". It's like your financial manager not only keeping an eye on your original two wallets but now taking care of a third new one as well, and never bothering you when there's no money moving inside it.

FEATURE

Progress bar colors shift with usage so you can spot an empty tank instantly

You can now gauge how tight your usage is at a mere glance, without pausing to read the exact numbers. The progress bars for each tool are no longer stuck on a single color; they now dynamically shift warning colors based on how much quota you've burned: below 50% stays the original brand color (Claude's orange or Codex's cyan), over half turns an amber yellow to remind you, and reaching 80% or above flashes straight to a warning red. It's just like a car's gas gauge—green normally, yellow when running low, and blaring red when it's hitting empty—allowing you to catch the danger in your peripheral vision instantly.

FEATURE

Refreshing no longer freezes, with massive under-the-hood bug fixes and performance boosts

Your screen will no longer suffer annoying momentary freezes when you click the menu bar. Previously, every usage refresh would cause the interface to stutter slightly; these read operations have now been shoved to the background to ensure it opens instantly. In addition, the system has fixed a mountain of minor bugs that might have startled you: cost estimates no longer get permanently stuck on stale numbers when your network is flaky, the interface stops throwing random errors, and the logic for grabbing usage data (including filtering out old logs and isolating corrupted record files) is now far more precise. The pricing cache (saving fetched prices locally to avoid looking them up again) even expires automatically after seven days so you aren't staring at outdated, expensive numbers after a model price drop. It's like asking your butler to stop sorting the bills in front of you in the living room, and instead quietly balance the books in the back office before handing you the final tally — never interrupting your actual work.

FEATURE

Renamed and bundled: double-click to launch with zero terminal commands and automatic cleanup

You no longer have to crack open a terminal and type a bunch of commands just to install and run it. The tool has been officially renamed to "usage" and neatly bundled into a standalone macOS application (.app) that you can simply double-click to launch. No matter which folder you drop it in, the built-in hook (a script that grabs usage in the background) automatically recognizes its surroundings and finds the correct paths to install itself. If you've used the older version before (back when it was called "usag"), it politely sweeps away specific v0.1.x leftover paths and startup items, while explicitly leaving your existing configuration paths and binary names untouched so it won't break your current setup. It's like taking a piece of furniture that previously required you to read a manual and screw it together yourself, and turning it into a fully assembled product straight out of the box — it even takes out specific previous-generation trash for you while preserving the layout you're used to, and comes with a much prettier name printed on it.

原始 CHANGELOG

Original changelog面板系統大翻新,多款酷炫主題隨你換
**Default panel now renders via WKWebView + HTML/CSS**: the classic default panel moved to a shared HTML/CSS layer, paving the way for a future Windows version; macOS still embeds it in `NSPopover` via `WKWebView`.
WKWebView integration adds a JS bridge (refresh / quit / switch), preload support, and a dark backing layer to remove launch-time white flash; panel switching tears down the web view to break retain cycles.
Panel buttons now have pressed-depth and subtle scale feedback on click.
Removed the CoreGraphics `panels/classic.py` implementation in favor of `HTMLPanel`.
**ECG panel**: medical-monitor style panel. `ECGView` drives a dual-channel ECG waveform animation via `NSTimer` at 80 ms — LEAD A for Claude Code, LEAD B for Codex. Waveform amplitude scales with quota usage percent; higher burn rate produces more intense rhythms. Text labels and waveform zones are separated into fixed vertical sections so they never overlap.
**Matrix panel (駭客任務)**: animated digital-rain panel — black background, cascading katakana + digit characters in Matrix green. `MatrixRainView` is driven by an `NSTimer` at 80 ms; each tick draws one bright head glyph and a 10-character fading trail per column. Card areas use a translucent dark-green fill with green borders; all buttons and headers use terminal bracket style (`[ SWITCH ]`, `[ REFRESH ]`, `[ EXIT ]`); rate/status/today labels use uppercase English prefixes.
**Panel switching system**: a `⇄ Switch panel` button in the popover top-right opens an `NSMenu` of all registered panels; the selected panel applies immediately and is persisted via `NSUserDefaults` (key `usage.activePanelId`), so the last choice survives restarts.
**Classic panel**: the original two-card + footer layout, with the switch button embedded in the Claude card's top-right and a new `ClassicSwitchButton` that stays legible in both light and dark mode.
**Taiwan panel**: red-on-white themed panel (a 20-line `ThemeConfig`), with a top header bar containing the TAIWAN flag icon, the "台灣用量監控" title, and the switch button. Popover height grows from 574 → 672 when this panel is active.
New `panels/` module: `base.py` provides the `Panel` Protocol, `ThemeConfig` dataclass, generic `ThemedPanel`, and `NSUserDefaults` helpers; `classic.py` / `taiwan.py` are concrete panels; `__init__.py` provides the panel registry (`get_panel(id)`, `all_panels()`, with classic fallback for unknown ids).
New `assets/taiwan.png`, registered in `setup_app.py`'s `resources` list so it ships inside the `.app` bundle.
`menubar.py` shrunk significantly (1041 → 524 lines): all popover drawing and layout moved into `panels/`; `PopoverViewController` is now a lightweight container that rebuilds its content view from the active `Panel`; `AppDelegate` gains `switchPanel:` / `selectPanel:` and `_set_active_panel_id` to drive panel transitions.
Added `tests/test_panels.py` (11 cases) covering: panel registry contents, each panel's `preferred_size`, `NSUserDefaults` round-trip, unknown-id fallback, `ThemeConfig` application, and `ThemedPanel` height difference with/without a header.
README: replaced mainland Chinese phrasing ("打API", "打網路") with standard Taiwanese usage ("呼叫 API", "連網路").
Popover redesign:
- Claude Code / Codex cards now show a branded icon in the header (`claude.webp` / `codex.webp`).
- Card surfaces and progress fills switched to gradient (`NSGradient`); accent colours brightened (Claude leans warm orange, Codex leans cyan).
- "Refresh now" and "Quit" buttons replaced with a custom `ActionButton` that draws primary / secondary styles (primary uses the accent gradient, secondary uses a translucent bordered fill).
- Rate / status / today-cost line wrapped in its own card so the three sections share one visual language.
- Spacing, weights, tracking, and muted colours re-tuned for stronger contrast in both Light and Dark Mode.
Popover redesigned: Claude / Codex sections now sit in subtle inset cards, with refined spacing, font weights, and muted footer text. Card fill adapts to Dark / Light appearance.
Original changelog支援 Antigravity,第三個 AI 錢包也幫你管牢
**Antigravity quota tracking**: the popover now shows three cards for Claude Code, Codex, and Antigravity; the Antigravity card has two rows for current usage (Session) and weekly cap (Weekly).
Antigravity buckets with `remainingFraction == 1.0` (unused) now hide reset times, avoiding the API's rolling placeholder from appearing as an endless "reset in ~24h".
`antigravity_loader` now splits quota buckets by reset window: shorter windows become Session and longer windows become Weekly. When Google's API exposes a weekly bucket, Weekly fills automatically.
Original changelog進度條顏色隨用量變換,油表見底一眼即知
**Minimal panel**: dark minimal panel inspired by Linear / Raycast. Near-black background (`#0A0A0C`), rounded cards, accent-coloured progress bars (Claude warm-orange / Codex cyan). Each card has a Session row (26pt number) and a Weekly row (24pt), each with a label, percentage text, 2px progress bar, and reset countdown. Footer card presents rate, status, and today's cost as a two-column label-left / value-right layout with horizontal dividers between rows. Three-button bar (Refresh / Quit / Switch panel) uses accent gradient for primary and translucent bordered fill for secondary.
Progress bars now change colour based on usage level: below 50% keeps the brand colour, 50–80% shifts to amber, ≥ 80% turns red.
Progress bars now change colour based on usage level: below 50% keeps the brand colour (Claude orange / Codex cyan), 50–80% shifts to amber, ≥ 80% turns red.
Original changelog重新整理不再卡頓,底層除蟲與效能大升級
New dependencies: `pyobjc-framework-WebKit`, `pyobjc-framework-Quartz`.
Tightened `codex_loader` / `history_loader._as_int` typing with `max(0, int(value))`.
Use Quartz `CGColorCreateGenericRGB` to create the `CGColorRef`, eliminating the launch-time `ObjCPointerWarning`.
`pricing.py`: `_pricing_cache` now records its source (cache / fetched / fallback) and timestamp. Fallback results use a short 10-minute TTL so cost estimates no longer stay stuck on stale fallback values after offline startup when the network recovers.
`README.md` / `README.en.md`: added a sentence to the pricing table section noting that first launch without a cache does a synchronous fetch and may take ~10 seconds on slow networks, so new users don't think the app is hung.
New `tests/test_main.py` (9 cases) covering `parse_args` and `_apply_outcome` behaviour.
New `tests/test_menubar.py` (14 cases) covering pure helpers: `format_human_time`, `_format_percent`, `_bar_color`, `_quota_row`, `_missing_row`, `_today_title(mock=True)`, `_empty_state`, `_error_state`, `_popover_size`.
Added 4 new cases in `tests/test_pricing.py` covering fallback TTL, retry-then-fetched, and no-refetch for fetched / cache sources.
Test suite grew from 63 → 90 passed.
`codex_loader.py`: use last token-event timestamp for `hours_back` filtering; per-file fault-tolerant sort.
`history_loader.py`: composite dedup key when id fields are absent; reject bool and negative token values.
README: corrected three factual inaccuracies (network claim, Codex data source, cost is an estimate).
README: added Quick start table, Download the app section, and Troubleshooting table.
`codex_loader.py`: use the last token-event timestamp for `hours_back` filtering so long sessions no longer drop recent tokens; per-file fault-tolerant sort so a single bad file doesn't break the entire session scan.
`history_loader.py`: fall back to a composite dedup key when `message_id` / `request_id` is absent; reject bool and negative token values.
README now ships 5 badges (CI status, latest release, Python version, platform, license).
Added bilingual `CONTRIBUTING.md` / `CONTRIBUTING.en.md`: spells out what issues / PRs should include, the three checks required before merge, off-limits technical identifiers and UI constants, the bilingual CHANGELOG rule, and commit message style.
All tests use `monkeypatch` to redirect path constants; **real `~/.claude` and `~/.codex` are never touched** (verified by before/after mtime comparison).
Test count: 44 → 60. Runtime: 0.04s → 0.08s.
Bumped `actions/setup-python` from v5 to v6 (v6 runs on Node.js 24). GitHub had been warning that v5 runs on Node.js 20 and the runner will force Node 24 after 2026-09-16; pre-empting the breakage.
Tightened `menubar.py` mypy config from a blanket `# mypy: ignore-errors` to `disable-error-code="import-untyped,misc"`, which only suppresses PyObjC's missing stubs and dynamic base-class errors. Real type errors (the class of bug behind `tracker.sample`'s `AttributeError`) will now be caught.
`docs/popover.png` updated to the new look.
Live data no longer collapses to `--` with `狀態:錯誤 (AttributeError)`. The stale `self.tracker.sample(...)` call in `menubar.py` (left over from 0.1.2's `sample()` removal) raised `AttributeError` on every successful refresh; dropped the call. `tracker.group()` already reads history entries directly.
Applied `ruff format` across the project (formatting only; no logic changes).
`.gitignore` now excludes `*.egg-info/` and `.pytest_cache/`.
English README (`README.en.md`) and a language switcher at the top of both READMEs.
CI runs `pytest -v` after ruff and mypy.
GitHub Actions CI runs `ruff check` and `mypy` on push to main and pull requests (macos-latest runner, uv-managed deps).
Issue templates (bug report, feature request) and pull request template under `.github/`.
`menubar.py`: I/O moved off the AppKit main thread (background `threading.Thread` + `performSelectorOnMainThread_withObject_waitUntilDone_`), eliminating the periodic UI freeze on each refresh tick. A `_refresh_in_flight` flag prevents re-entry.
`menubar.py`: divider lines re-centered between provider blocks (first_y=178, second_y=352). "今日" status line returned to 12pt to match the rest of the footer.
`pricing_cache.json` expires after 7 days based on mtime, so stale prices don't linger after a model price drop.
Seven previously silent `except OSError` sites in `pricing.py`, `codex_loader.py`, and `history_loader.py` now log a warning before swallowing the error.
`blocks.py` — unused dead code.
Original changelog正名與打包,免敲指令即可雙擊啟動並自動清理
`scripts/install-hook.sh`: wrap paths with `shlex.quote()` when generating the statusLine command, matching `setup_hook.py`. Prevents broken hook installs when the user's Python or hook path contains spaces.
`menubar.py` / `codex_loader.py`: silent `except` blocks now emit `logger.warning(exc_info=True)` when `USAGE_DEBUG=1`, otherwise stay quiet. Debug sessions no longer mistake parse failures for "Codex not installed".
Internal app identifiers changed from `usag` to `usage`: bundle id, filenames, launchctl label, and `~/.claude/` paths were renamed.
`setup_hook.py` now detects and clears old v0.1.x `usag` leftovers: hook script, settings statusLine, backup key, and status file.
`install-launchagent.sh` / `uninstall-launchagent.sh` now clean the old LaunchAgent plist and label automatically.
`usage_client.py` now falls back to the old `usag-status.json` path for upgrade compatibility.
Public app naming and internal bundle identifiers are now consistently `usage`.
`setup_app.py` now packages `usag_statusline.py` so the `.app` bundle ships the hook source.
`setup_hook.py` now resolves the hook source in both source-tree mode and `.app` bundle mode.
The popover now shows a one-click "立即安裝 hook" recovery button when the status file is missing.
`usage_client.py`: guard `rate_limits` sub-fields against non-dict values.
`setup_hook.py`: validate settings before writing; safely rebuild backup field if not a dict.
Sync status label changed from `usag-status` to `usage` to match the public-facing project name.
`setup_hook.py`: wrap interpreter and hook paths with `shlex.quote()` so hooks work when the project directory contains spaces (PR #1, thanks @DennisWei9898).
`usag_statusline.py`: replace `datetime.UTC` (Python 3.11+) with `timezone.utc` for compatibility with macOS system Python 3.9 (PR #1, thanks @DennisWei9898).
`usage_client.py`: guard `rate_limits` and its sub-fields against non-dict values.
`setup_hook.py`: validate `settings.json` structure before writing; safely rebuild the backup field if it is not a dict.
`setup_app.py` declares `claude.webp` / `codex.webp` as py2app `resources` so the `.app` bundle ships the icons.
`menubar.py` resolves icon paths via `NSBundle.mainBundle().pathForResource_ofType_`, so both the dev deployment (LaunchAgent runs `main.py` directly) and the `.app` bundle find the assets.
README's "How it gets the data" section now includes a mermaid diagram visualizing the `Claude Code → hook → JSON file → usage` chain, with `Anthropic API` explicitly drawn as **never called** (dashed broken line).
Added three new test files covering the three highest-risk "I/O / parse boundary" modules (previously zero coverage, the same class of code that produced the 0.1.2 → 0.1.3 "change one place, miss another" bug):
- `tests/test_usage_client.py`: `_read_status_file` with both paths missing / `USAG_STATUS` bad JSON / fallback to TT_STATUS; `_build_snapshot` missing fields / percent out-of-range clamp; `ClaudeUsageClient` outcomes in mock and real mode.
- `tests/test_codex_loader.py`: `load_entries` with missing sessions dir / valid JSONL / `hours_back` cutoff filter / bad JSON line / missing fields / `_parse_timestamp` across three ISO 8601 variants; `load_rate_limits` returns None when file missing / parses primary + secondary windows.
- `tests/test_setup_hook.py`: `setup` in a clean env / existing custom statusLine gets backed up / idempotent on repeat; `unsetup` restores backup / behaves cleanly when never installed; `_is_usag_hook` discriminator.
Public-facing name unified from `usag` to `usage`, matching the GitHub repo:
- `pyproject.toml`'s `name` changed from `"usag"` to `"usage"` (so PyPI / `pip list` now show `usage`).
- `README.md` / `README.en.md` headers and prose now say `usage`.
- `.github/ISSUE_TEMPLATE/bug_report.md` updated likewise.
**Intentionally unchanged** (to avoid breaking existing installs): all file paths, settings keys, and binary names keep the `usag` prefix — `~/.claude/usag-status.json`, `~/.claude/usag-statusline.py`, `~/Library/Logs/usag/`, `com.lollapalooza.usag` (LaunchAgent label), `usag.app` (bundle), `USAG_DEBUG` (env var), `settings.usag.previousStatusLine` (JSON key) are all untouched. The technical short name is `usag`; the public name is `usage`.
`pyproject.toml`'s `description` was rewritten from "在 macOS 終端機顯示 Claude Code 用量的繁中小工具" (terminal-only) to "usage — 在 macOS menu bar 顯示 Claude Code 用量的繁中小工具(也提供終端機 TUI)". The old description misrepresented the project as terminal-only; the new one reflects the menu-bar-first reality and aligns the displayed project name with the repo.
Release workflow (`.github/workflows/release.yml`) is now self-healing: after a tag is pushed, if the matching GitHub release does not exist yet, the workflow first creates it via `gh release create` (empty notes, target set to the tag's ref) and then uploads `usag.app.zip`. The "workflow assumes release already exists, upload fails" trap hit during 0.1.3 won't recur.
`pricing.py`: pricing cache moved from the package directory to `~/.claude/pricing_cache.json` so the read-only `.app` bundle can refresh the cache.
`UsageRateTracker.sample()` dead code (was a no-op called from `main._apply_outcome`).
py2app `.app` bundle build config (`setup_app.py`, `build_app.sh`) so users can run usag without a terminal.
GitHub Actions release workflow (`release.yml`) automatically builds `usag.app.zip` and attaches it to each tagged release.
pytest test suite under `tests/` covering `pricing`, `history_loader`, and `usage_rate` (44 tests, 89% line coverage).
`USAG_DEBUG=1` environment variable enables warning-level logger output for the previously silent OSError sites.
`usage_rate.py`: 30-second TTL cache for `group()`; stops re-scanning the last hour of JSONL on every TUI tick.
README: use `python3` instead of `python` (the uv venv only ships the `python3` symlink); documented `USAG_DEBUG`.
`setup_hook.py` and `pricing.py` use atomic writes (`tempfile.mkstemp` + `os.replace`); a crash mid-write no longer corrupts `~/.claude/settings.json` or `pricing_cache.json`.
`install-launchagent.sh` uses `BASH_SOURCE` to resolve the project directory; previously broke when run from anywhere other than the project root.
`uninstall-launchagent.sh` removes logs from `~/Library/Logs/usag/` (the actual location), not from the project directory.