Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
a49c0d8
feat(compact): pace tick on usage gauges with a menu toggle
fix2it Oct 18, 2026
2a097c1
fix(compact): keep the pace tick when a reset is reported slightly late
fix2it Oct 19, 2026
4e01052
style: cargo fmt
fix2it Oct 25, 2026
714941f
fix(compact): guard session pace ticks with claude.session.available
fix2it Nov 3, 2026
e6714ad
feat(antigravity): reimagined pool alternating as on-demand hover cro…
fix2it Oct 21, 2026
5cdf02d
style: cargo fmt
fix2it Oct 25, 2026
65b2ff3
feat(codex): dual mode with 300ms hover crossfade, dynamic width, and…
fix2it Oct 27, 2026
c7ed1cd
feat: dual mode for Claude Code and Antigravity with 300ms hover cros…
fix2it Oct 28, 2026
52a0de0
feat: asymmetric hover crossfade animation with fast fade-out and lea…
fix2it Oct 29, 2026
2598321
refactor(animation): unify crossfade loop, state checks, and context …
fix2it Oct 29, 2026
bd903f4
refactor(hit-test): consolidate tile hover, profile checks, and bound…
fix2it Oct 29, 2026
b1eca8f
fix(opencode): add Authorization: Bearer header to Go status requests
fix2it Nov 7, 2026
c589f45
test(opencode): assert Authorization: Bearer value in mock-request test
fix2it Nov 7, 2026
010996f
fix(opencode): skip empty auth= value in Bearer token extraction
fix2it Nov 7, 2026
72127ce
fix(opencode): only send Authorization: Bearer when clean token is av…
fix2it Nov 7, 2026
656fe08
fix(opencode): robust Bearer token extraction and independent test as…
fix2it Nov 7, 2026
6edc4f6
fix(i18n): translate missing UI strings and refresh advisory review date
fix2it Nov 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ Notable changes to Claude Code Usage Monitor are documented here, newest first.
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), with
changes grouped into Added, Changed, Fixed, and Removed where applicable.

## [Unreleased]

### Changed

- Show Antigravity's Gemini usage labels at rest and reveal the Claude/GPT labels while the cursor is over the Antigravity tile, replacing the timed 8 s / 2 s alternation.
- With only one Antigravity pool enabled, hovering the Antigravity tile crossfades to the other pool's labels and gauges, the same way as with both pools enabled.

## [2.23.0] - 2026-11-03

### Added
Expand Down
4 changes: 2 additions & 2 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ yanked = "deny"
unmaintained = "all"
unsound = "all"
unused-ignored-advisory = "deny"
# Owner: repository maintainers. Review by 2026-10-23, or on an oxifont update.
# Owner: repository maintainers. Review by 2026-12-08, or on an oxifont update.
# Build-time only: oxifont processes font bytes bundled by locked dependencies.
# No patched release exists; migrate/update the subsetter to remove this crate.
# Keep cargo-audit's warning visible. This does not ignore future vulnerabilities.
ignore = [
{ id = "RUSTSEC-2026-0192", reason = "ttf-parser 0.25.1 is unmaintained; required by oxifont-subset/oxifont-parser 0.2.2 for build-time bundled font subsetting. Owner: repository maintainers; review by 2026-10-23. See docs/dependency-security.md." },
{ id = "RUSTSEC-2026-0192", reason = "ttf-parser 0.25.1 is unmaintained; required by oxifont-subset/oxifont-parser 0.2.2 for build-time bundled font subsetting. Owner: repository maintainers; review by 2026-12-08. See docs/dependency-security.md." },
]

[licenses]
Expand Down
2 changes: 1 addition & 1 deletion docs/dependency-security.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ it does not parse user-provided fonts at runtime through this dependency.

`deny.toml` temporarily excepts only this advisory. `cargo audit` still displays
its warning, and future vulnerability advisories remain blocking. The repository
maintainers own reviewing this exception by **2026-10-23**, or sooner when
maintainers own reviewing this exception by **2026-12-08**, or sooner when
oxifont updates. Update or replace the subsetter to remove `ttf-parser`, then
remove the exception; cargo-deny rejects unused advisory exceptions. The review
date is a maintenance reminder, not an automatically enforced expiration.
Expand Down
8 changes: 8 additions & 0 deletions src/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,14 @@ impl Default for ProviderAccounts {
}

impl ProviderAccounts {
pub fn is_profile_enabled(&self, id: &str, default_if_missing: bool) -> bool {
self.profiles
.iter()
.find(|profile| profile.id == id)
.map(|profile| profile.enabled)
.unwrap_or(default_if_missing)
}

pub fn selected(&self) -> Option<&AccountProfile> {
self.profiles
.iter()
Expand Down
24 changes: 24 additions & 0 deletions src/app_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ pub struct SettingsFile {
/// Preserve theme fonts and Windows substitution unless explicitly disabled.
#[serde(default = "default_true")]
pub use_windows_default_font: bool,
#[serde(default = "default_true")]
pub show_pace: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub active_theme_path: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -143,6 +145,7 @@ impl Default for SettingsFile {
custom_theme_enabled: true,
usage_countdown: false,
use_windows_default_font: true,
show_pace: true,
active_theme_path: None,
dashboard_width: None,
dashboard_height: None,
Expand Down Expand Up @@ -690,6 +693,27 @@ mod tests {
assert_eq!(settings_json(&counting_down)["usage_countdown"], true);
}

#[test]
fn show_pace_defaults_to_on_and_round_trips() {
let settings = SettingsFile::default();
assert!(settings.show_pace);
assert_eq!(settings_json(&settings)["show_pace"], true);

let legacy = decode_settings(r#"{"poll_interval_ms":900000}"#).unwrap();
assert!(legacy.show_pace);

for show_pace in [false, true] {
let settings = SettingsFile {
show_pace,
..Default::default()
};
let json = settings_json(&settings);
assert_eq!(json["show_pace"], show_pace);
let loaded = decode_settings(&json.to_string()).unwrap();
assert_eq!(loaded.show_pace, show_pace);
}
}

#[test]
fn settings_always_use_the_theme_widget() {
let mut settings = SettingsFile {
Expand Down
46 changes: 36 additions & 10 deletions src/context_menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,13 @@ pub enum ContextMenuAction {
},
ToggleAntigravityGemini,
ToggleAntigravityExternal,
ToggleClaudeMain,
ToggleClaudeX,
ToggleCodexMain,
ToggleCodexX,
ToggleStartup,
ToggleTaskbarLock,
ToggleShowPace,
ToggleWidget,
/// Accepted only so menus saved by older versions can be loaded and
/// cleaned up. New menus cannot create or execute this legacy action.
Expand Down Expand Up @@ -310,7 +315,11 @@ pub fn rendered_label(
"Refresh" => language.text("Refresh"),
"Exit" => language.text("Exit"),
"Claude Code" => language.text("Claude Code"),
"Claude Code (Main)" => language.text("Claude Code (Main)"),
"Claude Code X" => language.text("Claude Code X"),
"Codex" => language.text("Codex"),
"Codex (Main)" => language.text("Codex (Main)"),
"Codex X" => language.text("Codex X"),
"Antigravity" => language.text("Antigravity"),
"OpenCode" => language.text("OpenCode"),
"Cursor" => language.text("Cursor"),
Expand All @@ -325,6 +334,7 @@ pub fn rendered_label(
"Check for updates" => language.text("Check for updates"),
"Lock in taskbar" => language.text("Lock in taskbar"),
"Show widget" => language.text("Show widget"),
"Show pace" => language.text("Show pace"),
_ => label,
};
crate::theme_engine::format_template(translated, context)
Expand Down Expand Up @@ -373,19 +383,17 @@ pub fn classic_context_menu() -> ContextMenuDocument {
"Providers",
vec![
ContextMenuItem::action(
"provider-claude",
"Claude Code",
Action::ToggleProvider {
provider: Provider::Claude,
},
"provider-claude-main",
"Claude Code (Main)",
Action::ToggleClaudeMain,
),
ContextMenuItem::action("provider-claude-x", "Claude Code X", Action::ToggleClaudeX),
ContextMenuItem::action(
"provider-codex",
"Codex",
Action::ToggleProvider {
provider: Provider::Codex,
},
"provider-codex-main",
"Codex (Main)",
Action::ToggleCodexMain,
),
ContextMenuItem::action("provider-codex-x", "Codex X", Action::ToggleCodexX),
ContextMenuItem::action(
"provider-antigravity-gemini",
"Antigravity (Gemini)",
Expand Down Expand Up @@ -457,6 +465,7 @@ pub fn classic_context_menu() -> ContextMenuDocument {
Action::ToggleStartup,
),
ContextMenuItem::action("lock-taskbar", "Lock in taskbar", Action::ToggleTaskbarLock),
ContextMenuItem::action("show-pace", "Show pace", Action::ToggleShowPace),
ContextMenuItem::submenu("language", "Language", languages),
ContextMenuItem::separator("settings-separator"),
ContextMenuItem::action(
Expand Down Expand Up @@ -718,6 +727,23 @@ mod tests {
assert!(menu.validate().is_empty());
assert!(menu.items.iter().any(|item| item.id == "refresh"));
assert!(menu.items.iter().any(|item| item.id == "update-frequency"));
let settings = menu
.items
.iter()
.find(|item| item.id == "settings")
.unwrap();
let ContextMenuItemKind::Submenu { items } = &settings.kind else {
panic!("Settings must be a submenu");
};
assert!(items.iter().any(|item| {
item.label == "Show pace"
&& matches!(
&item.kind,
ContextMenuItemKind::Action {
action: ContextMenuAction::ToggleShowPace
}
)
}));
assert!(serde_json::to_string(&menu)
.unwrap()
.contains("provider-opencode"));
Expand Down
17 changes: 11 additions & 6 deletions src/localization/locales/de.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,13 @@ second_suffix = "s"
token_expired_title = "Authentifizierungsfehler"
token_expired_body = "Führen Sie 'claude' in einem Terminal aus, verwenden Sie dann '/login' und folgen Sie den Anweisungen. Aktualisieren oder starten Sie diese App anschließend neu."
codex_token_expired_title = "Codex-Authentifizierungsfehler"
codex_token_expired_body = "Fuhren Sie 'codex' in einem Terminal aus und folgen Sie den Anmeldeanweisungen. Aktualisieren oder starten Sie diese App anschliessend neu."
codex_token_expired_body = "Führen Sie 'codex' in einem Terminal aus und folgen Sie den Anmeldeanweisungen. Aktualisieren oder starten Sie diese App anschließend neu."
antigravity_token_expired_title = "Antigravity-Authentifizierungsfehler"
antigravity_token_expired_body = "Offnen Sie Antigravity und melden Sie sich erneut an. Aktualisieren oder starten Sie diese App anschliessend neu."
antigravity_token_expired_body = "Öffnen Sie Antigravity und melden Sie sich erneut an. Aktualisieren oder starten Sie diese App anschließend neu."
opencode_token_expired_title = "OpenCode nicht gefunden"
opencode_token_expired_body = "Legen Sie OPENCODE_GO_WORKSPACE_ID und OPENCODE_GO_AUTH_COOKIE für die OpenCode Go-Nutzungsüberwachung fest. Siehe README. Aktualisieren oder starten Sie diese App anschliessend neu."
cursor_token_expired_title = "Cursor Auth Error"
cursor_token_expired_body = "Sign in to Cursor (or set CURSOR_SESSION_TOKEN), then refresh or restart this app."
opencode_token_expired_body = "Legen Sie OPENCODE_GO_WORKSPACE_ID und OPENCODE_GO_AUTH_COOKIE für die OpenCode Go-Nutzungsüberwachung fest. Siehe README. Aktualisieren oder starten Sie diese App anschließend neu."
cursor_token_expired_title = "Cursor-Authentifizierungsfehler"
cursor_token_expired_body = "Melden Sie sich bei Cursor an (oder setzen Sie CURSOR_SESSION_TOKEN). Aktualisieren oder starten Sie diese App anschließend neu."
grok_token_expired_title = "Grok-Authentifizierungsfehler"
grok_token_expired_body = "Führen Sie 'grok login' in einem Terminal aus und folgen Sie den Anmeldeanweisungen. Aktualisieren oder starten Sie diese App anschließend neu."
copilot_token_expired_title = "Copilot-Authentifizierungsfehler"
Expand Down Expand Up @@ -125,10 +125,14 @@ copilot_window_title = "Copilot-Nutzungsmonitor"
"Choose asset..." = "Medium auswählen..."
"Choose one action for this context menu item." = "Wählen Sie eine Aktion für diesen Kontextmenüeintrag."
"Claude Code" = "Claude Code"
"Claude Code (Main)" = "Claude Code (Main)"
"Claude Code X" = "Claude Code X"
"Click" = "Click"
"Close asset library" = "Close asset library"
"Close Builder" = "Baukasten schließen"
"Codex" = "Codex"
"Codex (Main)" = "Codex (Main)"
"Codex X" = "Codex X"
"Collect usage from Anthropic" = "Nutzungsdaten von Anthropic abrufen"
"Collect usage from GitHub" = "Nutzungsdaten von GitHub abrufen"
"Collect usage from Google" = "Nutzungsdaten von Google abrufen"
Expand Down Expand Up @@ -362,6 +366,7 @@ copilot_window_title = "Copilot-Nutzungsmonitor"
"Short duration" = "Kurze Dauer"
"Show context menu" = "Kontextmenü anzeigen"
"Show dashboard" = "Dashboard anzeigen"
"Show pace" = "Show pace"
"Show widget" = "Widget anzeigen"
"Size" = "Größe"
"Smaller value" = "Kleinerer Wert"
Expand Down Expand Up @@ -456,6 +461,6 @@ copilot_window_title = "Copilot-Nutzungsmonitor"
"X" = "X"
"Y offset" = "Y-Versatz"
"Y" = "Y"
"Lock in taskbar" = "Lock in taskbar"
"Lock in taskbar" = "In Taskleiste fixieren"
"Keep the widget docked; never float automatically" = "Keep the widget docked; never float automatically"
"Locked" = "Locked"
5 changes: 5 additions & 0 deletions src/localization/locales/en.toml
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,14 @@ copilot_window_title = "Copilot Usage Monitor"
"Choose asset..." = "Choose asset..."
"Choose one action for this context menu item." = "Choose one action for this context menu item."
"Claude Code" = "Claude Code"
"Claude Code (Main)" = "Claude Code (Main)"
"Claude Code X" = "Claude Code X"
"Click" = "Click"
"Close asset library" = "Close asset library"
"Close Builder" = "Close Builder"
"Codex" = "Codex"
"Codex (Main)" = "Codex (Main)"
"Codex X" = "Codex X"
"Collect usage from Anthropic" = "Collect usage from Anthropic"
"Collect usage from GitHub" = "Collect usage from GitHub"
"Collect usage from Google" = "Collect usage from Google"
Expand Down Expand Up @@ -362,6 +366,7 @@ copilot_window_title = "Copilot Usage Monitor"
"Short duration" = "Short duration"
"Show context menu" = "Show context menu"
"Show dashboard" = "Show dashboard"
"Show pace" = "Show pace"
"Show widget" = "Show widget"
"Size" = "Size"
"Smaller value" = "Smaller value"
Expand Down
9 changes: 7 additions & 2 deletions src/localization/locales/es.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ antigravity_token_expired_title = "Error de autenticacion de Antigravity"
antigravity_token_expired_body = "Abre Antigravity e inicia sesion otra vez. Despues, actualiza o reinicia esta aplicacion."
opencode_token_expired_title = "OpenCode no encontrado"
opencode_token_expired_body = "Define OPENCODE_GO_WORKSPACE_ID y OPENCODE_GO_AUTH_COOKIE para supervisar el uso de OpenCode Go. Consulta el README. Despues, actualiza o reinicia esta aplicacion."
cursor_token_expired_title = "Cursor Auth Error"
cursor_token_expired_body = "Sign in to Cursor (or set CURSOR_SESSION_TOKEN), then refresh or restart this app."
cursor_token_expired_title = "Error de autenticación de Cursor"
cursor_token_expired_body = "Inicia sesión en Cursor (o define CURSOR_SESSION_TOKEN). Después, actualiza o reinicia esta aplicación."
grok_token_expired_title = "Error de autenticación de Grok"
grok_token_expired_body = "Ejecuta 'grok login' en una terminal y sigue las indicaciones de inicio de sesión. Después, actualiza o reinicia esta aplicación."
copilot_token_expired_title = "Error de autenticación de Copilot"
Expand Down Expand Up @@ -125,10 +125,14 @@ copilot_window_title = "Monitor de uso de Copilot"
"Choose asset..." = "Elegir recurso..."
"Choose one action for this context menu item." = "Elija una acción para este elemento del menú contextual."
"Claude Code" = "Claude Code"
"Claude Code (Main)" = "Claude Code (Main)"
"Claude Code X" = "Claude Code X"
"Click" = "Click"
"Close asset library" = "Close asset library"
"Close Builder" = "Cerrar Constructor"
"Codex" = "Codex"
"Codex (Main)" = "Codex (Main)"
"Codex X" = "Codex X"
"Collect usage from Anthropic" = "Recopilar uso de Anthropic"
"Collect usage from GitHub" = "Recopilar uso de GitHub"
"Collect usage from Google" = "Recopilar uso de Google"
Expand Down Expand Up @@ -362,6 +366,7 @@ copilot_window_title = "Monitor de uso de Copilot"
"Short duration" = "Duración corta"
"Show context menu" = "Mostrar menú contextual"
"Show dashboard" = "Mostrar panel"
"Show pace" = "Show pace"
"Show widget" = "Mostrar widget"
"Size" = "Tamaño"
"Smaller value" = "Valor menor"
Expand Down
11 changes: 8 additions & 3 deletions src/localization/locales/fr.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ antigravity_token_expired_title = "Erreur d'authentification Antigravity"
antigravity_token_expired_body = "Ouvrez Antigravity et reconnectez-vous. Ensuite, actualisez ou redemarrez cette application."
opencode_token_expired_title = "OpenCode introuvable"
opencode_token_expired_body = "Definissez OPENCODE_GO_WORKSPACE_ID et OPENCODE_GO_AUTH_COOKIE pour suivre l'utilisation d'OpenCode Go. Consultez le README. Ensuite, actualisez ou redemarrez cette application."
cursor_token_expired_title = "Cursor Auth Error"
cursor_token_expired_body = "Sign in to Cursor (or set CURSOR_SESSION_TOKEN), then refresh or restart this app."
cursor_token_expired_title = "Erreur d'authentification Cursor"
cursor_token_expired_body = "Connectez-vous à Cursor (ou définissez CURSOR_SESSION_TOKEN). Ensuite, actualisez ou redémarrez cette application."
grok_token_expired_title = "Erreur d'authentification Grok"
grok_token_expired_body = "Exécutez 'grok login' dans un terminal et suivez les instructions de connexion. Ensuite, actualisez ou redémarrez cette application."
copilot_token_expired_title = "Erreur d'authentification Copilot"
Expand Down Expand Up @@ -125,10 +125,14 @@ copilot_window_title = "Moniteur d'utilisation Copilot"
"Choose asset..." = "Choisir une ressource..."
"Choose one action for this context menu item." = "Choisissez une action pour cet élément du menu contextuel."
"Claude Code" = "Claude Code"
"Claude Code (Main)" = "Claude Code (Main)"
"Claude Code X" = "Claude Code X"
"Click" = "Click"
"Close asset library" = "Close asset library"
"Close Builder" = "Fermer le Constructeur"
"Codex" = "Codex"
"Codex (Main)" = "Codex (Main)"
"Codex X" = "Codex X"
"Collect usage from Anthropic" = "Collecter l'utilisation depuis Anthropic"
"Collect usage from GitHub" = "Collecter l'utilisation depuis GitHub"
"Collect usage from Google" = "Collecter l'utilisation depuis Google"
Expand Down Expand Up @@ -362,6 +366,7 @@ copilot_window_title = "Moniteur d'utilisation Copilot"
"Short duration" = "Durée courte"
"Show context menu" = "Afficher le menu contextuel"
"Show dashboard" = "Afficher le tableau de bord"
"Show pace" = "Show pace"
"Show widget" = "Afficher le widget"
"Size" = "Taille"
"Smaller value" = "Valeur la plus petite"
Expand Down Expand Up @@ -456,6 +461,6 @@ copilot_window_title = "Moniteur d'utilisation Copilot"
"X" = "X"
"Y offset" = "Décalage Y"
"Y" = "Y"
"Lock in taskbar" = "Lock in taskbar"
"Lock in taskbar" = "Verrouiller dans la barre des tâches"
"Keep the widget docked; never float automatically" = "Keep the widget docked; never float automatically"
"Locked" = "Locked"
Loading
Loading