Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ This app is for Windows users who already have **Claude Code (CLI or App) instal

Codex support is optional. To show Codex usage, install and sign in to the Codex CLI, then enable Codex from the right-click **Models** menu.

Antigravity support is optional too. To show Antigravity usage, install and sign in to Google Antigravity, then enable the **Antigravity** model from the right-click **Models** menu.
Antigravity support is optional too. To show Antigravity usage, install Google Antigravity, run `agy` in a terminal and sign in there, then enable the **Antigravity** model from the right-click **Models** menu.

It works best if you want a simple "how close am I to the limit?" display that is always visible.

Expand All @@ -37,7 +37,7 @@ It works best if you want a simple "how close am I to the limit?" display that i
- Windows 10 or Windows 11
- Claude Code (CLI or App) installed and authenticated
- Optional: Codex CLI installed and authenticated, if you want Codex usage
- Optional: Google Antigravity installed and authenticated, if you want Antigravity usage
- Optional: Google Antigravity installed with its `agy` CLI authenticated, if you want Antigravity usage

If you use Claude Code through WSL, that is supported too. The monitor can read your Claude Code credentials from Windows or from your WSL environment.

Expand All @@ -62,8 +62,9 @@ claude-code-usage-monitor
Once running, it will appear in your taskbar and as one or more tray icons in the notification area.

- Drag the left divider to move the taskbar widget
- On multi-monitor setups, drag the widget onto another Windows taskbar to move it to that screen
- Right-click the taskbar widget or tray icon for refresh, displayed models, update frequency, Start with Windows, reset position, language, updates, and exit
- On multi-monitor setups, drag the widget onto another Windows taskbar to move it to that screen, or pick the screen directly via **Settings → Monitor**
- Right-click the taskbar widget or tray icon for refresh, displayed models, update frequency, Start with Windows, reset position, taskbar side, language, updates, and exit
- Use **Settings → Taskbar Side** to anchor the widget to the left or right side of the taskbar (right by default); dragging still fine-tunes the position from the chosen side
- Left-click the tray icon to toggle the taskbar widget on or off
- Enable `Start with Windows` from the right-click menu if you want it to launch automatically when you sign in

Expand Down Expand Up @@ -139,7 +140,7 @@ What the app sends over the network:

What the app stores locally:

- Widget position
- Widget position and taskbar side
- Selected taskbar / screen
- Widget visibility
- Polling frequency
Expand All @@ -159,7 +160,7 @@ Notes:

- If your Claude Code token is expired, the app may ask the local Claude CLI to refresh it in the background
- If your Codex token is expired, the app may ask the local Codex CLI to refresh it in the background. The monitor does not write `auth.json` itself; any credential update is handled by the Codex CLI.
- If your Antigravity token is expired, open Antigravity and sign in again. The monitor does not write Windows Credential Manager entries itself.
- If your Antigravity token is expired, run `agy` in a terminal and sign in again. The monitor does not write Windows Credential Manager entries itself.
- Portable installs can update themselves by downloading the latest release from this repository
- Proxies should be trusted because proxied usage requests include your OAuth bearer token inside the TLS connection

Expand Down
6 changes: 5 additions & 1 deletion src/localization/dutch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ pub(super) const STRINGS: Strings = Strings {
settings: "Instellingen",
start_with_windows: "Opstarten met Windows",
reset_position: "Positie herstellen",
taskbar_side: "Taakbalkzijde",
taskbar_side_left: "Links",
taskbar_side_right: "Rechts",
monitor: "Monitor",
language: "Taal",
system_default: "Systeemstandaard",
check_for_updates: "Controleren op updates",
Expand All @@ -43,7 +47,7 @@ pub(super) const STRINGS: Strings = Strings {
codex_token_expired_title: "Codex-authenticatiefout",
codex_token_expired_body: "Voer 'codex' uit in een terminal en volg de aanmeldstappen. Ververs of herstart de app daarna.",
antigravity_token_expired_title: "Antigravity-authenticatiefout",
antigravity_token_expired_body: "Open Antigravity en meld je opnieuw aan. Ververs of herstart de app daarna.",
antigravity_token_expired_body: "Voer 'agy' uit in een terminal en meld je opnieuw aan. Ververs of herstart de app daarna.",
codex_window_title: "Codex-gebruiksmonitor",
antigravity_window_title: "Antigravity-gebruiksmonitor",
second_suffix: "s",
Expand Down
6 changes: 5 additions & 1 deletion src/localization/english.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ pub(super) const STRINGS: Strings = Strings {
settings: "Settings",
start_with_windows: "Start with Windows",
reset_position: "Reset Position",
taskbar_side: "Taskbar Side",
taskbar_side_left: "Left",
taskbar_side_right: "Right",
monitor: "Monitor",
language: "Language",
system_default: "System Default",
check_for_updates: "Check for Updates",
Expand All @@ -43,7 +47,7 @@ pub(super) const STRINGS: Strings = Strings {
codex_token_expired_title: "Codex Auth Error",
codex_token_expired_body: "Run 'codex' in a terminal and follow the sign-in prompts. After that, refresh or restart this app.",
antigravity_token_expired_title: "Antigravity Auth Error",
antigravity_token_expired_body: "Open Antigravity and sign in again. After that, refresh or restart this app.",
antigravity_token_expired_body: "Run 'agy' in a terminal and sign in again. After that, refresh or restart this app.",
codex_window_title: "Codex Usage Monitor",
antigravity_window_title: "Antigravity Usage Monitor",
second_suffix: "s",
Expand Down
6 changes: 5 additions & 1 deletion src/localization/french.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ pub(super) const STRINGS: Strings = Strings {
settings: "Paramètres",
start_with_windows: "Démarrer avec Windows",
reset_position: "Réinitialiser la position",
taskbar_side: "Côté de la barre des tâches",
taskbar_side_left: "Gauche",
taskbar_side_right: "Droite",
monitor: "Écran",
language: "Langue",
system_default: "Par défaut du système",
check_for_updates: "Vérifier les mises à jour",
Expand All @@ -43,7 +47,7 @@ pub(super) const STRINGS: Strings = Strings {
codex_token_expired_title: "Erreur d'authentification Codex",
codex_token_expired_body: "Executez 'codex' dans un terminal et suivez les instructions de connexion. Ensuite, actualisez ou redemarrez cette application.",
antigravity_token_expired_title: "Erreur d'authentification Antigravity",
antigravity_token_expired_body: "Ouvrez Antigravity et reconnectez-vous. Ensuite, actualisez ou redemarrez cette application.",
antigravity_token_expired_body: "Executez 'agy' dans un terminal et reconnectez-vous. Ensuite, actualisez ou redemarrez cette application.",
codex_window_title: "Moniteur d'utilisation Codex",
antigravity_window_title: "Moniteur d'utilisation Antigravity",
second_suffix: "s",
Expand Down
6 changes: 5 additions & 1 deletion src/localization/german.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ pub(super) const STRINGS: Strings = Strings {
settings: "Einstellungen",
start_with_windows: "Mit Windows starten",
reset_position: "Position zurücksetzen",
taskbar_side: "Taskleistenseite",
taskbar_side_left: "Links",
taskbar_side_right: "Rechts",
monitor: "Monitor",
language: "Sprache",
system_default: "Systemstandard",
check_for_updates: "Nach Updates suchen",
Expand All @@ -43,7 +47,7 @@ pub(super) const STRINGS: Strings = Strings {
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.",
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: "Fuhren Sie 'agy' in einem Terminal aus und melden Sie sich erneut an. Aktualisieren oder starten Sie diese App anschliessend neu.",
codex_window_title: "Codex-Nutzungsmonitor",
antigravity_window_title: "Antigravity-Nutzungsmonitor",
second_suffix: "s",
Expand Down
6 changes: 5 additions & 1 deletion src/localization/japanese.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ pub(super) const STRINGS: Strings = Strings {
settings: "設定",
start_with_windows: "Windows と同時に開始",
reset_position: "位置をリセット",
taskbar_side: "タスクバーの配置",
taskbar_side_left: "左",
taskbar_side_right: "右",
monitor: "モニター",
language: "言語",
system_default: "システム既定",
check_for_updates: "更新を確認",
Expand All @@ -43,7 +47,7 @@ pub(super) const STRINGS: Strings = Strings {
codex_token_expired_title: "Codex 認証エラー",
codex_token_expired_body: "ターミナルで 'codex' を実行し、サインインの案内に従ってください。その後、このアプリを更新または再起動してください。",
antigravity_token_expired_title: "Antigravity 認証エラー",
antigravity_token_expired_body: "Antigravity を開いて再度サインインしてください。その後、このアプリを更新するか再起動してください。",
antigravity_token_expired_body: "ターミナルで 'agy' を実行し、再度サインインしてください。その後、このアプリを更新するか再起動してください。",
codex_window_title: "Codex 使用量モニター",
antigravity_window_title: "Antigravity 使用量モニター",
second_suffix: "秒",
Expand Down
6 changes: 5 additions & 1 deletion src/localization/korean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ pub(super) const STRINGS: Strings = Strings {
settings: "설정",
start_with_windows: "Windows 시작 시 자동 실행",
reset_position: "위치 초기화",
taskbar_side: "작업 표시줄 위치",
taskbar_side_left: "왼쪽",
taskbar_side_right: "오른쪽",
monitor: "모니터",
language: "언어",
system_default: "시스템 기본값",
check_for_updates: "업데이트 확인",
Expand All @@ -43,7 +47,7 @@ pub(super) const STRINGS: Strings = Strings {
codex_token_expired_title: "Codex 인증 오류",
codex_token_expired_body: "터미널에서 'codex'를 실행하고 로그인 안내를 따르세요. 그런 다음 이 앱을 새로 고치거나 다시 시작하세요.",
antigravity_token_expired_title: "Antigravity 인증 오류",
antigravity_token_expired_body: "Antigravity를 열고 다시 로그인하세요. 그런 다음 이 앱을 새로 고치거나 다시 시작하세요.",
antigravity_token_expired_body: "터미널에서 'agy'를 실행하고 다시 로그인하세요. 그런 다음 이 앱을 새로 고치거나 다시 시작하세요.",
codex_window_title: "Codex 사용량 모니터",
antigravity_window_title: "Antigravity 사용량 모니터",
second_suffix: "초",
Expand Down
4 changes: 4 additions & 0 deletions src/localization/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ pub struct Strings {
pub settings: &'static str,
pub start_with_windows: &'static str,
pub reset_position: &'static str,
pub taskbar_side: &'static str,
pub taskbar_side_left: &'static str,
pub taskbar_side_right: &'static str,
pub monitor: &'static str,
pub language: &'static str,
pub system_default: &'static str,
pub check_for_updates: &'static str,
Expand Down
6 changes: 5 additions & 1 deletion src/localization/portuguese_brazil.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ pub(super) const STRINGS: Strings = Strings {
settings: "Configurações",
start_with_windows: "Iniciar com o Windows",
reset_position: "Redefinir Posição",
taskbar_side: "Lado da barra de tarefas",
taskbar_side_left: "Esquerda",
taskbar_side_right: "Direita",
monitor: "Monitor",
language: "Idioma",
system_default: "Padrão do Sistema",
check_for_updates: "Busca atualizações",
Expand Down Expand Up @@ -44,7 +48,7 @@ pub(super) const STRINGS: Strings = Strings {
codex_token_expired_title: "Erro de Autenticação do Codex",
codex_token_expired_body: "Execute 'codex' em um terminal e siga as instruções de login. Depois disso, atualize ou reinicie este aplicativo.",
antigravity_token_expired_title: "Erro de Autenticação do Antigravity",
antigravity_token_expired_body: "Abra o Antigravity e entre novamente. Depois disso, atualize ou reinicie este aplicativo.",
antigravity_token_expired_body: "Execute 'agy' em um terminal e entre novamente. Depois disso, atualize ou reinicie este aplicativo.",
codex_window_title: "Monitor de uso do Codex",
antigravity_window_title: "Monitor de uso do Antigravity",
};
6 changes: 5 additions & 1 deletion src/localization/russian.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ pub(super) const STRINGS: Strings = Strings {
settings: "Настройки",
start_with_windows: "Запускать вместе с Windows",
reset_position: "Сбросить позицию",
taskbar_side: "Сторона панели задач",
taskbar_side_left: "Слева",
taskbar_side_right: "Справа",
monitor: "Монитор",
language: "Язык",
system_default: "Системный по умолчанию",
check_for_updates: "Проверить обновления",
Expand Down Expand Up @@ -44,7 +48,7 @@ pub(super) const STRINGS: Strings = Strings {
codex_token_expired_title: "Ошибка авторизации Codex",
codex_token_expired_body: "Запустите 'codex' в терминале и следуйте инструкциям для входа. После этого обновите или перезапустите приложение.",
antigravity_token_expired_title: "Ошибка авторизации Antigravity",
antigravity_token_expired_body: "Откройте Antigravity и войдите снова. После этого обновите или перезапустите приложение.",
antigravity_token_expired_body: "Запустите 'agy' в терминале и войдите снова. После этого обновите или перезапустите приложение.",
codex_window_title: "Монитор использования Codex",
antigravity_window_title: "Монитор использования Antigravity",
};
6 changes: 5 additions & 1 deletion src/localization/simplified_chinese.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ pub(super) const STRINGS: Strings = Strings {
settings: "设置",
start_with_windows: "开机时启动",
reset_position: "重置位置",
taskbar_side: "任务栏位置",
taskbar_side_left: "靠左",
taskbar_side_right: "靠右",
monitor: "显示器",
language: "语言",
system_default: "系统默认",
check_for_updates: "检查更新",
Expand All @@ -43,7 +47,7 @@ pub(super) const STRINGS: Strings = Strings {
codex_token_expired_title: "Codex 验证错误",
codex_token_expired_body: "请在终端中运行 'codex',并按照登录提示操作。完成后,请刷新或重新启动此应用程序。",
antigravity_token_expired_title: "Antigravity 验证错误",
antigravity_token_expired_body: "请打开 Antigravity 并重新登录。完成后,请刷新或重新启动此应用程序。",
antigravity_token_expired_body: "请在终端中运行 'agy' 并重新登录。完成后,请刷新或重新启动此应用程序。",
codex_window_title: "Codex 使用量监控",
antigravity_window_title: "Antigravity 使用量监控",
second_suffix: "秒",
Expand Down
6 changes: 5 additions & 1 deletion src/localization/spanish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ pub(super) const STRINGS: Strings = Strings {
settings: "Configuración",
start_with_windows: "Iniciar con Windows",
reset_position: "Restablecer posición",
taskbar_side: "Lado de la barra de tareas",
taskbar_side_left: "Izquierda",
taskbar_side_right: "Derecha",
monitor: "Monitor",
language: "Idioma",
system_default: "Predeterminado del sistema",
check_for_updates: "Buscar actualizaciones",
Expand All @@ -43,7 +47,7 @@ pub(super) const STRINGS: Strings = Strings {
codex_token_expired_title: "Error de autenticacion de Codex",
codex_token_expired_body: "Ejecuta 'codex' en una terminal y sigue las indicaciones de inicio de sesion. Despues, actualiza o reinicia esta aplicacion.",
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.",
antigravity_token_expired_body: "Ejecuta 'agy' en una terminal e inicia sesion otra vez. Despues, actualiza o reinicia esta aplicacion.",
codex_window_title: "Monitor de uso de Codex",
antigravity_window_title: "Monitor de uso de Antigravity",
second_suffix: "s",
Expand Down
6 changes: 5 additions & 1 deletion src/localization/traditional_chinese.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ pub(super) const STRINGS: Strings = Strings {
settings: "設定",
start_with_windows: "開機時啟動",
reset_position: "重置位置",
taskbar_side: "工作列位置",
taskbar_side_left: "靠左",
taskbar_side_right: "靠右",
monitor: "顯示器",
language: "語言",
system_default: "系統預設",
check_for_updates: "檢查更新",
Expand All @@ -43,7 +47,7 @@ pub(super) const STRINGS: Strings = Strings {
codex_token_expired_title: "Codex 驗證錯誤",
codex_token_expired_body: "請在終端機中執行 'codex',並依照登入提示操作。完成後,請重新整理或重新啟動此應用程式。",
antigravity_token_expired_title: "Antigravity 驗證錯誤",
antigravity_token_expired_body: "請開啟 Antigravity 並重新登入。完成後,請重新整理或重新啟動此應用程式。",
antigravity_token_expired_body: "請在終端機中執行 'agy' 並重新登入。完成後,請重新整理或重新啟動此應用程式。",
codex_window_title: "Codex 使用量監控",
antigravity_window_title: "Antigravity 使用量監控",
second_suffix: "秒",
Expand Down
38 changes: 37 additions & 1 deletion src/native_interop.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use windows::core::PCWSTR;
use windows::Win32::Foundation::{BOOL, HWND, LPARAM, RECT};
use windows::Win32::Foundation::{BOOL, HWND, LPARAM, POINT, RECT};
use windows::Win32::Graphics::Gdi::{
GetMonitorInfoW, MonitorFromPoint, MONITORINFO, MONITORINFOEXW, MONITOR_DEFAULTTONEAREST,
};
use windows::Win32::UI::Accessibility::{SetWinEventHook, UnhookWinEvent, HWINEVENTHOOK};
use windows::Win32::UI::Shell::{SHAppBarMessage, ABM_GETTASKBARPOS, APPBARDATA};
use windows::Win32::UI::WindowsAndMessaging::*;
Expand Down Expand Up @@ -61,6 +64,39 @@ pub fn find_taskbars() -> Vec<TaskbarWindow> {
taskbars
}

/// Windows display device number (the `n` in `\\.\DISPLAYn`, matching the
/// numbering shown in display settings for typical setups) of the monitor
/// containing the given rect.
pub fn monitor_number_for_rect(rect: RECT) -> Option<u32> {
unsafe {
let center = POINT {
x: rect.left + (rect.right - rect.left) / 2,
y: rect.top + (rect.bottom - rect.top) / 2,
};
let monitor = MonitorFromPoint(center, MONITOR_DEFAULTTONEAREST);
let mut info = MONITORINFOEXW::default();
info.monitorInfo.cbSize = std::mem::size_of::<MONITORINFOEXW>() as u32;
if !GetMonitorInfoW(
monitor,
&mut info as *mut MONITORINFOEXW as *mut MONITORINFO,
)
.as_bool()
{
return None;
}
let device_len = info
.szDevice
.iter()
.position(|unit| *unit == 0)
.unwrap_or(info.szDevice.len());
let device = String::from_utf16_lossy(&info.szDevice[..device_len]);
device
.rsplit(|c: char| !c.is_ascii_digit())
.next()
.and_then(|digits| digits.parse::<u32>().ok())
}
}

/// Find a child window by class name
pub fn find_child_window(parent: HWND, class_name: &str) -> Option<HWND> {
unsafe {
Expand Down
Loading