# Changelog All notable changes to **ai-usagebar** are recorded here. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Each release is also published at . ## [Unreleased] ### Added - **Omarchy panel and settings speak English, Russian, and Brazilian Portuguese.** A Language dropdown (`uiLocale`: Auto / English / Português (Brasil) / Русский) remaps chrome, formatters, known report footnotes, and credential hints through a local catalog; Auto follows the system locale. Long settings copy wraps under the hero instead of overflowing the detail pill, and API-key notes wrap on their own line under the env var name. - **Korean (한국어) in the tray popover.** Settings → Appearance → Language gains 한국어 on Windows and macOS, with a full `messages/ko.json` catalog; metric labels and usage strings from the report are translated as they are for Português. - **OpenRouter: recent models activity and real-dollar credit balance.** `GET /api/v1/activity` queries the 2 most recently used models, showing their per-model cost and request counts alongside the existing spend breakdown in both the TUI and the popover. When no quota reset date is published, the meter row displays the account's available credit balance in USD ($) directly below the gauge. Full Portuguese (pt-BR) localization support in the popover. The activity endpoint requires an OpenRouter *management* key (`management_api_key_env`, default `OPENROUTER_MANAGEMENT_API_KEY`, also per `[[openrouter.accounts]]`); without one the activity request is skipped and the block simply stays hidden. ### Fixed - **Ollama Cloud monthly-only accounts no longer paint a fake 0% 5h/7d pair.** Some Pro accounts report `limits.monthly` instead of `session`/`weekly`. The TUI, tooltip and `usage --json` already showed that month; the widget default format and the `{session_pct}`/`{weekly_pct}` aliases still emitted `0` for the omitted windows, so Waybar and the macOS menu bar read as two exhausted rate-limit windows. Absent windows are now empty placeholders (a present month at 0% used still renders `0`), the default bar shows `{oll_monthly_pct}%`, and the macOS selector draws that pool on the primary bar as Monthly. - **Omarchy bar chips keep their icon next to their own value.** 1.30.0 put a 6 px spacer between a chip's brand mark and its value inside a row that already spaces its children 4 px apart, so the gap became 14 px — wider than the gap to the previous chip, and each icon read as part of the chip before it. The spacer is gone; the row's spacing is the gap again, and an icon-only chip still collapses to the mark alone. - **macOS menu bar parses DeepInfra named accounts.** PR #291 added named account support to DeepInfra in Rust, but `API_KEY_ACCOUNT_VENDORS` in the macOS menu bar was not updated. It now includes `deepinfra` so `[[deepinfra.accounts]]` entries appear as menu choices and in Preferences. - **Provider catalog and detection recognize named accounts and path overrides.** `ai-usagebar vendors --json` and the TUI/macOS provider views reported providers as unconfigured ("needs credential") when authentication was configured via named accounts (`[[.accounts]]`) without setting the ambient key, or when `show_default_account = false` was set. The catalog now checks named API-key accounts as well as Anthropic and OpenAI named accounts and path overrides (`credentials_path`, `codex_auth_path`), matching the credential resolution of the fetch and `detect` (see #307). ## [1.30.0] — 2026-10-01 ### Added - **Meta Muse (Muse Spark) evaluation and `[[custom]]` local-spend recipe.** `docs/vendor-endpoints.md` records why Muse is not implementable as a native vendor (Meta publishes no quota or billing endpoint; the dashboard's private GraphQL route needs a browser session), and `config.example.toml` gains a commented recipe that tallies Muse Code's local session logs through a loopback `[[custom]]` provider. - **The Omarchy bar dims the chips the open panel is not showing.** While the panel is open, the chip for the entry it displays keeps its colour and the others step back to 45% over 140 ms, so the bar says which entry the panel belongs to, next to the shell's own underline under the widget. An alarming chip that is not the selected one dims as well, so its red reads softer for as long as the panel is open; the lone, vertical and loading placeholders never dim, and the chip under the pointer, its click target and the tooltip are untouched. - **Omarchy can color-code usage by level.** The Quattro bar chips, panel meters, and hover tooltip can paint green → yellow → orange → red as usage climbs, reading those colours from the active Omarchy theme (`colors.toml`) with Quattro's urgent colour for the critical rung. A new **Color-code usage by level** display toggle (`colorCodeUsage`, off by default) turns the palette on or off immediately; when it is off, everything stays on the normal foreground colour and the classic alarm chrome (#278) still fires for a critical quota. Theme key precedence matches Waybar/`theme.rs` after #289 (named `red`/`green`/`yellow` win over `color1`–`color3`). ### Fixed - **GNOME: the top bar no longer goes blank when every window is hidden.** With both the 5h and weekly bars switched off, the indicator drew an empty label and left an invisible click target in the panel. It now shows the top-bar vendor's symbolic icon instead, and the click menu works as before. - **`vendors --json` no longer reports Command Code as configured just because pi's shared keystore exists.** The catalog treated any file on Command Code's auth search list as a login, but the second path is pi's keystore for every provider the user signed pi into — so a machine with pi and no Command Code login still showed the provider as having the credential it needs (and the macOS preferences as "credential available"). Command Code is configured only when one of those files holds its live credential, the same answer detection and the fetch already give, and the check now honors a configured `auth_paths` override. - **Cached quotas stay marked stale during HTTP 429 backoff.** An expired payload served while requests are paused no longer appears fresh in the report and desktop frontends. - **Linux Mint tray polls quota endpoints every five minutes.** The previous one-minute interval could trigger Claude and Codex rate limits. - **AUR `ai-usagebar-bin` installs again: the release signing key is now on a keyserver.** The v1.29.0 key (`AE42EF5D73DD92E248815C95B65CCCAF64A99438`) was only shipped as a release asset, so `makepkg`/`yay` could not fetch it for `validpgpkeys` and the install aborted. The public key is now published to keys.openpgp.org (served by fingerprint; a confirmation email makes it searchable by address). The v1.29.0 release notes' `AA`→`CA` fingerprint typo is fixed in the release body; the changelog's released [1.29.0] section keeps the original text because released sections are immutable (#301). - **Omarchy's open-panel underline spans the full chip width.** Quattro's bar paints the active-plugin mark at ~55% of the slot unless the widget hints otherwise; the AI Usage chip now reports its full width so the underline tracks Cursor's multi-percentage label as indicators come and go. ## [1.29.0] — 2026-09-30 ### Added - **AUR `ai-usagebar-bin` package verifies detached PGP signatures against `validpgpkeys`.** Following upstream release signing introduced in v1.28.0 (#257), `packaging/aur/PKGBUILD-bin` and `.SRCINFO-bin` now declare maintainer key `AE42EF5D73DD92E248815C95B65CCAAF64A99438` in `validpgpkeys` and fetch detached `.sig` signatures alongside each architecture's binary archive (`source_x86_64` and `source_aarch64`), allowing `makepkg` to automatically verify release integrity and authenticity (#282). - **Native DeepInfra billing support.** The widget, TUI, aggregate report, and named API-key accounts now read `DEEPINFRA_API_KEY`, combine the documented billing checklist and current-month usage endpoints, convert usage cents to dollars, and show prepaid balance, monthly spend, optional limit, and period. - **The Omarchy bar's per-provider chips open that provider.** With **Show all providers** on, a left-click on a chip selects the entry that chip stands for and opens the panel there, the way the panel's own provider buttons do, instead of toggling the panel on whatever was selected last. Clicking the chip the panel already shows closes it; right-click and middle-click keep their panel-wide meaning, and hovering a chip still shows the button tooltip. - **Multiple Antigravity CLI accounts on macOS.** The optional `agy` status-line integration adds one live usage entry per distinct active Google account, deduplicates repeated sessions, and displays only a masked email with an opaque stable account ID. Active sessions are marked stale after 15 minutes without a new status-line payload. It does not read or store OAuth tokens and falls back to the existing Antigravity collector when no valid status-line session is active. ### Changed - **The meter colour and the flame follow the pace line, with a tolerance.** Any row the least bit over the pace tick was red with a "Limit in …" flame, so a weekly Claude row at 4% used seven hours into its week warned of a run-out 7 hours before the reset, and a row at 98% left read like one that needed attention. The verdict now allows for noise: up to 110% of the pace line is blue with no flame ("~N% spare" or "~N% left at reset"); 110–130% is yellow with "~N% over pace" and still no flame; over 130%, or over the line with under 10% left, is red with the flame and "Limit in …". Each band also needs the bar to sit past the tick by 3 points (yellow) or 5 points (red), because early in a long window one whole percent of use swings the projection by twenty points or more. Before a window has a projection the colour reads what is left (blue, yellow under 50%, red under 20%). The same in Left and Used mode, in the tray popover and in the Linux Mint tray. ### Fixed - **The macOS Z.AI row says “MCP tools” without the monthly suffix.** The suffix made the row wider than the other usage rows, while the reset countdown already shows the length of the quota window. - **Account CLI commands sanitize filesystem paths and account labels in terminal output.** Terminal output from `account add`, `account switch`, and `account merge-history` previously interpolated raw `.display()` paths and unsanitized labels directly into `println!` and `eprintln!`, violating the project invariant that untrusted text is sanitized at the sink and risking ANSI escape sequence injection into the terminal. Paths now route through `sanitize_untrusted_path`; errors, capture notes and config parse messages through one `printable` helper. A guard test fails on any `account` print that interpolates `.display()`, `{error}` or `{note}` bare. - **`account merge-history` synchronizes under `account_switch_lock`.** Running history merges now acquires the profile switch lock before staging and merging, preventing race conditions and potential profile corruption when concurrent switches or refreshes target the same profile. - **Antigravity keeps reporting with only the `agy` CLI installed.** The saved Google session lasts about an hour and only a running Antigravity renews it; with the desktop app closed nothing did, so the widget fell to "session expired and ai-usagebar has no OAuth client" until the user ran `agy` themselves. When the session is expired and no OAuth client is configured, the fetch now runs `agy models` (no TTY, no prompt, read-only; it rewrites the saved credential as a side effect) and reads the credential again. `agy` is found on `PATH`, then in `~/.local/bin`. The run is bounded to 25 seconds and attempted at most once every ten minutes, failures included, so a dead refresh token never turns into a spawn per poll, and the spawn never inherits this process's provider key env vars. `agy`'s own background updater is switched off for that run (`AGY_CLI_DISABLE_AUTO_UPDATE=true`): on Windows it opens a console window of its own that no flag on our spawn can hide. Configuring `oauth_client_id` and `oauth_client_secret` still refreshes directly and never spawns anything. - **Cursor is detected from `cursor-agent` alone on macOS.** The CLI keeps its login in the login Keychain (`cursor-access-token`, account `cursor-user`) rather than in an `auth.json`, so a Mac with the CLI and no desktop IDE had neither credential source and Cursor read as signed out. The Keychain is now the third source, after the IDE's `state.vscdb` and the agent's `auth.json`, and is only read when the IDE database does not exist and the agent path is the default one. The agent file's default location on macOS was also wrong: `cursor-agent` writes `~/.cursor/auth.json`, not `~/Library/Application Support/cursor/`, so the file fallback could never be found there. The default now follows the CLI's own per-OS path (Linux and Windows are unchanged). - **Popover error messages keep their path.** The card removed absolute paths from a diagnostic, but only up to the next space, so on macOS "Cursor database not found at ~/Library/Application Support/…" became "not found at Support/Cursor/…", and on Windows the path vanished and the sentence read "not found at Open the Cursor IDE". The path now stays whole, with only the home prefix (`/Users/`, `/home/`, `/root`, `C:\Users\`) folded to `~`, so the account name still stays off the card. A diagnosis that is nothing but a path still falls back to "Open TUI for details". - **The update banner says "Updating…" once.** Clicking Install put the same "Updating…" on the button and in the sentence above it, and the download and install that followed repeated each step in both places too. Progress now shows on the button only; the sentence keeps naming the release ("AI Usage vX.Y.Z is ready to install.") until it is done, and a failure still explains itself there. - **The Omarchy palette is read from where Omarchy applies it.** `omarchy-theme-set` writes the active theme to `~/.local/state/omarchy/current/theme`, while the TUI and the widget looked in `~/.config/omarchy/current/theme`, a layout Omarchy no longer populates. The lookup came up empty, the One Dark fallback was silent, and every themed surface stayed One Dark — the older path is now the fallback rather than the only candidate. Theme files that name their colors (`red`, `green`, `yellow`) are also read: only the pre-Omarchy-4 `color1`-`color3` aliases were parsed, so a current theme file would have overridden the foreground and background but left every severity color at One Dark. - **The Omarchy bar's chips answer a click anywhere in their column.** The bar presses a slot's widget by geometry, so a chip only won a press inside its own rect: the glyph sat 12 px tall in a 26 px slot, and a press on the padding above or below it fell through to the button, which toggled whichever entry was already selected instead. Each chip now registers its whole column of the slot — the full height, half of every gap beside it, split at the midpoint with its neighbour, and the button's padding at either end of the widget — so the row is a partition of the slot rather than glyphs floating in a button. The row's width and each chip's place in it are unchanged. - **A quota notification no longer repeats while nothing changes.** The dedupe recorded each window's reset instant and re-armed the key whenever a later fetch reported a later one. Vendors report that instant with sub-second precision that drifts between fetches — Anthropic's five-hour window came back 0.70s apart on two fetches four minutes apart — so a window sitting above the threshold re-notified on a good share of refreshes. A move now has to clear an hour and a half: longer than any refresh interval this ships with, and far shorter than the shortest window, so a window that really rolled over still notifies. ## [1.28.0] — 2026-09-29 ### Changed - **Cursor on-demand in `usage --json` is numeric.** The On-Demand text row carries `used_cents`, `limit_cents`, and `percent` (USD cents and the consumed percent) when Cursor reports a prepaid cap. The Omarchy chip and panel meter read those fields. The formatted `$spent / $cap` value is unchanged for every other surface. A report from an older binary, which has only that formatted value, still works. - **The Omarchy bar no longer turns red for a cached or failed refresh.** That alert state now follows the highest-percent window alone, like the Waybar `class` and every other frontend; stale and error text stays in the panel. A refresh that yields no report at all still marks the bar. Thresholds are unchanged. ### Fixed - **Omarchy panel scrolls long settings forms faster.** Touchpad gestures, mouse wheels, and keyboard steps now cover more of the popup per movement, so the Save button remains reachable without dozens of gestures. - **Grok Bot reads its session on Linux when the app used Chromium's `"peanuts"` key.** The Grok Bot desktop app picks its OSCrypt key at runtime from whichever Secret Service backend Electron selected, and encrypts with `"peanuts"` whenever that backend is `basic_text`. A machine can therefore hold an `application="Grok Bot"` keyring item while the blobs in `sand-secrets.json` were keyed with `"peanuts"` — and the reader preferred the item's key, so every token failed to decrypt and the bar reported "a stored token could not be decrypted; sign in to the Grok Bot desktop app again" for a session that was perfectly valid. Both keys are now tried, most specific first; a wrong AES key almost always fails PKCS#7 unpadding, so the right candidate is effectively ruled in. No configuration, re-login or keyring change is needed, and a genuinely unreadable file still reports the same error it always did. ## [1.27.0] — 2026-09-28 ### Added - **`account merge-history` for relocated Claude Desktop profiles (macOS).** Merges every account's sessions and schedules into whichever account a given profile is signed into, without swapping a credential or touching the app: `ai-usagebar account merge-history --data-dir [--from ]...`. Intended for side-by-side Desktop copies launched with `--user-data-dir`, where `account switch` cannot be used because it installs a stored token over the profile's live login and quits the app by application name. The merge is additive — no deletion sweep runs, so an unattended run cannot lose history — sources are opened read-only, and a second run is a no-op. Note that it deliberately crosses accounts: afterwards one account's window lists conversations started under the others. - **GNOME menu supports all enabled providers.** Native submenus display the shared usage report, including Cursor, named accounts and custom providers, with metric labels, balances, errors and reset details supplied by the binary. Collapsed rows preview the first two metrics in report order, retaining their labels and groups, with optional mini bars and symbolic provider icons. Menu preferences offer values only, hidden icons and compact spacing. The top bar continues to follow its vendor preference. - **Omarchy bar shows both Cursor pools and prepaid on-demand.** The Quattro chip lists Cursor Models, Other Models, and on-demand used percent in that order (`35% · 7% · 0%`), the same consumed-percent reading OpenRouter uses for a credit balance. The tooltip is one short line per pool. Three switches on the Cursor page turn those figures on and off in the top bar and tooltip only; the open panel still lists every pool, and the last remaining figure cannot be turned off. A pool the report does not contain, such as on-demand with no prepaid row, does not count as that last figure. The bar's urgent color follows the pools still on the chip. - The TUI vendor menu is now navigated with the Up/Down arrow keys (wrapping), with `Tab`/`Shift+Tab`/`←`/`→`/`h`/`l` kept as secondary shortcuts. Mouse clicks work in the TUI: click a vendor menu entry to select it, click a footer action to refresh, refresh all, open Settings, or quit, click a Settings field to focus it, or click **Save** to save. In Settings the on/off cells toggle their provider (or the quota-alerts switch) and the focused Primary vendor's ◀/▶ arrows step the radio; the hint line is clickable too: save, close, toggle, reveal and change-vendor segments send their key through the same handler. ### Changed - **Right-clicking the tray icon opens the Options menu.** On macOS a right-click on the menu bar item no longer opens the popover like a left-click: it shows the footer's Options menu as a native menu — Customize (Classic only), Settings, Refresh, Detect Providers, Open TUI, Start at Login, Check for Updates…, About, Quit — in the popover's language, and the items that name a screen open the popover on that screen. The Windows right-click menu, which had only Refresh, Detect Providers, Open TUI, Start with Windows and Quit, is now the same menu. - **Refresh lives in the Options menu only.** The ↺ button in each provider card's header was Reset, not Refresh: one click threw away that provider's row order and visibility. It is gone from the dashboard (Reset stays in the provider's Customize screen, behind a second click), and the row menu's per-provider Refresh went with it; Options → Refresh updates every provider. - **Quit in the Options menu is no longer red.** It uses the same color as the other items. ### Fixed - **GNOME Shell 45–46 compatibility.** Vertical menu rows now use the layout property available in the running Shell, avoiding the unsupported `orientation` property on older versions. The extension had failed to enable on Shell 45 and 46 since it first shipped (#272). - **GNOME preferences display literal labels correctly.** The pool description and colour labels no longer treat `&` and `<` as markup. ## [1.26.0] — 2026-09-27 ### Added - **Named accounts for every API-key provider.** The `[[openrouter.accounts]]` array (#221) now works for `[zai]`, `[deepseek]`, `[kilo]`, `[novita]`, `[moonshot]`, `[grok]`, `[minimax]`, and `[orcarouter]`: one entry per extra key, each with its own TUI tab, `usage` report entry (`deepseek@work`), macOS menu choice, and `/