usage-cli 0.32.2__tar.gz → 0.32.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {usage_cli-0.32.2 → usage_cli-0.32.4}/PKG-INFO +5 -2
- {usage_cli-0.32.2 → usage_cli-0.32.4}/README.md +3 -1
- usage_cli-0.32.4/THIRD_PARTY_NOTICES.md +28 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/doctor.py +8 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/i18n.json +110 -5
- usage_cli-0.32.4/installer/codex_hook_trust.py +66 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/loaders/agy_quota_probe.py +34 -1
- {usage_cli-0.32.2 → usage_cli-0.32.4}/menubar/agy.py +22 -7
- {usage_cli-0.32.2 → usage_cli-0.32.4}/menubar/app.py +10 -41
- {usage_cli-0.32.2 → usage_cli-0.32.4}/menubar/grok.py +8 -17
- usage_cli-0.32.4/menubar/manual_refresh.py +51 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/menubar/menu.py +14 -0
- usage_cli-0.32.4/menubar/notify.py +219 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/menubar/prefs.py +0 -5
- {usage_cli-0.32.2 → usage_cli-0.32.4}/menubar/refresh.py +7 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/menubar/state.py +20 -4
- {usage_cli-0.32.2 → usage_cli-0.32.4}/menubar/title.py +19 -13
- {usage_cli-0.32.2 → usage_cli-0.32.4}/menubar/update.py +33 -50
- {usage_cli-0.32.2 → usage_cli-0.32.4}/panels/payload.py +1 -1
- {usage_cli-0.32.2 → usage_cli-0.32.4}/pyproject.toml +2 -2
- {usage_cli-0.32.2 → usage_cli-0.32.4}/quota/agy_window_keeper.py +37 -54
- {usage_cli-0.32.2 → usage_cli-0.32.4}/quota/codex_window_keeper.py +38 -64
- usage_cli-0.32.4/quota/keeper_outcome.py +195 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/quota/window_keeper.py +34 -62
- {usage_cli-0.32.2 → usage_cli-0.32.4}/setup_app.py +1 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_agy_quota_probe.py +88 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_agy_window_keeper.py +1 -1
- usage_cli-0.32.4/tests/test_codex_hook_trust.py +89 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_doctor.py +2 -1
- usage_cli-0.32.4/tests/test_keeper_menu.py +83 -0
- usage_cli-0.32.4/tests/test_keeper_outcome.py +483 -0
- usage_cli-0.32.4/tests/test_manual_refresh.py +62 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_menubar.py +92 -79
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_menubar_agy.py +31 -2
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_menubar_grok.py +14 -0
- usage_cli-0.32.4/tests/test_menubar_notify.py +91 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_menubar_prefs.py +0 -5
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_menubar_state.py +50 -0
- usage_cli-0.32.4/tests/test_menubar_update.py +35 -0
- usage_cli-0.32.4/tests/test_quota_label.py +425 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_update_checker.py +30 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_update_gate.py +21 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_usage_cli.py +13 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_web_panel_payload.py +10 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_wintray.py +363 -10
- {usage_cli-0.32.2 → usage_cli-0.32.4}/updates/checker.py +9 -9
- {usage_cli-0.32.2 → usage_cli-0.32.4}/updates/gate.py +28 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/usage_cli.egg-info/PKG-INFO +5 -2
- {usage_cli-0.32.2 → usage_cli-0.32.4}/usage_cli.egg-info/SOURCES.txt +14 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/usage_cli.py +2 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/wintray/app.py +196 -33
- {usage_cli-0.32.2 → usage_cli-0.32.4}/wintray/menu.py +19 -0
- usage_cli-0.32.4/wintray/prefs.py +25 -0
- usage_cli-0.32.4/wintray/quota_label.py +184 -0
- usage_cli-0.32.4/wintray/taskbar_obstacles.py +71 -0
- usage_cli-0.32.4/wintray/taskbar_overlay.py +296 -0
- usage_cli-0.32.2/menubar/notify.py +0 -119
- usage_cli-0.32.2/tests/test_menubar_notify.py +0 -37
- {usage_cli-0.32.2 → usage_cli-0.32.4}/LICENSE +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/adapters/__init__.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/adapters/agy.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/adapters/claude.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/adapters/codex.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/adapters/grok.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/adapters/muse.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/adapters/rate_limits.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/adapters/registry.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/adapters/types.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/analyzer/__init__.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/analyzer/aggregator.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/analyzer/blocks.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/analyzer/diagnoser.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/analyzer/dispatch_ledger.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/analyzer/insights.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/analyzer/persona_loader.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/analyzer/reporter.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/analyzer/subscription.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/analyzer/usage_snapshot.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/fsevents_watch.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/i18n.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/installer/__init__.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/installer/claude_pane.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/installer/login_item.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/installer/session_hooks.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/installer/setup_hook.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/installer/statusline_settings.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/loaders/__init__.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/loaders/agy_disk_cache.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/loaders/agy_loader.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/loaders/cache_quarantine.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/loaders/claude_paths.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/loaders/codex_disk_cache.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/loaders/codex_events.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/loaders/codex_fork_replay.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/loaders/codex_loader.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/loaders/codex_paths.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/loaders/disk_cache_common.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/loaders/disk_cache_lifecycle.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/loaders/grok_loader.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/loaders/grok_quota_probe.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/loaders/history_disk_cache.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/loaders/history_loader.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/loaders/jsonl_limits.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/loaders/jsonl_utils.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/loaders/muse_loader.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/main.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/menubar/__init__.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/menubar/actions.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/menubar/chrome.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/menubar/new_badge.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/menubar/popover.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/panels/__init__.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/panels/base.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/panels/dynamic_height.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/panels/panel_scale.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/panels/panel_window.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/panels/panel_window_state.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/panels/web_panel.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/panels/window_drag.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/prefs.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/pricing.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/project_resolver.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/quota/__init__.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/quota/burn_rate.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/quota/usage_rate.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/service_status.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/setup.cfg +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_adapters_claude.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_adapters_codex.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_adapters_rate_limits.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_aggregator.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_agy_adapter.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_agy_disk_cache.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_agy_loader.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_analyzer_blocks.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_analyzer_pipeline.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_burn_rate.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_cache_quarantine.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_claude_pane.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_claude_paths.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_codex_consistency.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_codex_loader.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_codex_window_keeper.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_diagnoser.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_disk_cache_shards.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_dispatch_ledger.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_dynamic_height.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_fsevents_watch.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_grok_loader.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_grok_quota_probe.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_history_loader.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_hook_scripts_are_standalone.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_html_report_snapshot.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_i18n_format_fallback.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_i18n_key_parity.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_i18n_packaged_path.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_insights.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_jsonl_utils.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_login_item.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_main.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_muse_loader.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_new_badge.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_packaged_resources.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_packaging.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_panel_footer_layout.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_panel_scale.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_panel_window_state.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_panels.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_panels_lazy_import.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_persona_loader.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_pricing.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_project_resolver.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_report_daily_chart.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_report_filter_js.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_reporter_build_data.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_service_status.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_session_resume.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_setup_app.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_setup_hook.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_setup_hook_coexistence.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_setup_hook_resume.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_setup_hook_terse.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_subprocess_utils.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_subscription.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_time_utils.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_tui.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_tui_sprite.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_ui_tables.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_update_release_notes.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_usage_client.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_usage_diagnosis_snapshot.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_usage_dir_sweeper.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_usage_lang.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_usage_logging.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_usage_notifications.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_usage_rate.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_usage_snapshot.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_usage_snapshot_replay.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_usage_statusline.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_usage_statusline_agy.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_usage_statusline_forwarder.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_usage_statusline_grok.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_usage_terse_mode.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_usage_terse_reminder.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_wheel_packaging.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_win_login_item.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_window_keeper.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tests/test_windows_manifest.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tui/__init__.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tui/app.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/tui/sprite.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/ui/__init__.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/ui/html_report.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/ui/report_charts.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/ui/report_daily_chart.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/ui/report_filter.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/ui/report_ledger.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/ui/report_scripts.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/ui/report_styles.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/ui/tables.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/updates/__init__.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/updates/release_notes.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/usage_cli.egg-info/dependency_links.txt +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/usage_cli.egg-info/entry_points.txt +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/usage_cli.egg-info/requires.txt +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/usage_cli.egg-info/top_level.txt +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/usage_client.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/usage_common/__init__.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/usage_common/subprocess_utils.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/usage_common/time_utils.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/usage_common/usage_dir_sweeper.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/usage_common/usage_lang.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/usage_common/usage_logging.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/usage_diagnosis_snapshot.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/usage_notifications.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/usage_session_resume.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/usage_statusline.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/usage_statusline_agy.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/usage_statusline_forwarder.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/usage_statusline_grok.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/usage_terse_mode.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/usage_terse_reminder.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/wintray/__init__.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/wintray/login_item.py +0 -0
- {usage_cli-0.32.2 → usage_cli-0.32.4}/wintray/watch.py +0 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: usage-cli
|
|
3
|
-
Version: 0.32.
|
|
3
|
+
Version: 0.32.4
|
|
4
4
|
Summary: usage — 在 macOS menu bar 與 Windows 系統匣顯示 Claude Code、Codex、Antigravity 用量的小工具(也提供終端機 TUI)
|
|
5
5
|
License-Expression: AGPL-3.0-only
|
|
6
6
|
Requires-Python: >=3.13
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
8
|
License-File: LICENSE
|
|
9
|
+
License-File: THIRD_PARTY_NOTICES.md
|
|
9
10
|
Requires-Dist: pyobjc-framework-Cocoa>=11.0; sys_platform == "darwin"
|
|
10
11
|
Requires-Dist: pyobjc-framework-Quartz>=11.0; sys_platform == "darwin"
|
|
11
12
|
Requires-Dist: pyobjc-framework-UserNotifications>=11.0; sys_platform == "darwin"
|
|
@@ -179,7 +180,9 @@ See your quota, other conversations, and background jobs without leaving Claude
|
|
|
179
180
|
|
|
180
181
|
Windows has the full core experience: the system-tray UI, Claude Code status-line hook, and Codex history parsing all work natively. Download `usage-windows.zip` from the [latest GitHub Release](https://github.com/aqua5230/usage/releases/latest), unzip it, then run `usage.exe`—no installer is needed. If SmartScreen shows **Windows protected your PC** on first launch, click **More info** → **Run anyway**. The tray UI requires Microsoft Edge WebView2 Runtime, which is normally included with Windows 10 and 11.
|
|
181
182
|
|
|
182
|
-
The system-tray icon
|
|
183
|
+
The system-tray icon shows the remaining session quota percentage for Claude or Codex. Choose **Tray Display Source → Claude Code / Codex** in the right-click menu or panel menu; the change applies immediately and survives restarts (default: Claude). If Codex has no session window, the icon uses its weekly quota instead and the tooltip identifies that window. Missing quota data shows `--`. The tooltip summarizes both tools, with the selected source first. Left-click opens the same 16 quota themes available on macOS (Default plus the other fifteen) in WebView2. Right-click also provides Reset Panel Position and Quit; panel switching, refresh, launch at login, and update checks are in the panel menu.
|
|
184
|
+
|
|
185
|
+
Enable **Show Taskbar Quota** in either menu for a transparent `Codex: 92%` label inside the taskbar, immediately left of the notification area. It follows taskbar position, scaling, and light/dark theme, and hides during fullscreen use or taskbar auto-hide. Click the label to open the panel. If buttons leave insufficient space, it moves just outside the taskbar. The normal app icon remains as a menu entry point; the label follows the selected source and quota window.
|
|
183
186
|
|
|
184
187
|
Windows differences: the panel opens at the bottom-right of the working area rather than next to the tray icon; update prompts use a system Yes/No dialog.
|
|
185
188
|
|
|
@@ -159,7 +159,9 @@ See your quota, other conversations, and background jobs without leaving Claude
|
|
|
159
159
|
|
|
160
160
|
Windows has the full core experience: the system-tray UI, Claude Code status-line hook, and Codex history parsing all work natively. Download `usage-windows.zip` from the [latest GitHub Release](https://github.com/aqua5230/usage/releases/latest), unzip it, then run `usage.exe`—no installer is needed. If SmartScreen shows **Windows protected your PC** on first launch, click **More info** → **Run anyway**. The tray UI requires Microsoft Edge WebView2 Runtime, which is normally included with Windows 10 and 11.
|
|
161
161
|
|
|
162
|
-
The system-tray icon
|
|
162
|
+
The system-tray icon shows the remaining session quota percentage for Claude or Codex. Choose **Tray Display Source → Claude Code / Codex** in the right-click menu or panel menu; the change applies immediately and survives restarts (default: Claude). If Codex has no session window, the icon uses its weekly quota instead and the tooltip identifies that window. Missing quota data shows `--`. The tooltip summarizes both tools, with the selected source first. Left-click opens the same 16 quota themes available on macOS (Default plus the other fifteen) in WebView2. Right-click also provides Reset Panel Position and Quit; panel switching, refresh, launch at login, and update checks are in the panel menu.
|
|
163
|
+
|
|
164
|
+
Enable **Show Taskbar Quota** in either menu for a transparent `Codex: 92%` label inside the taskbar, immediately left of the notification area. It follows taskbar position, scaling, and light/dark theme, and hides during fullscreen use or taskbar auto-hide. Click the label to open the panel. If buttons leave insufficient space, it moves just outside the taskbar. The normal app icon remains as a menu entry point; the label follows the selected source and quota window.
|
|
163
165
|
|
|
164
166
|
Windows differences: the panel opens at the bottom-right of the working area rather than next to the tray icon; update prompts use a system Yes/No dialog.
|
|
165
167
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
The Windows taskbar label anchoring in `wintray/taskbar_overlay.py` is adapted
|
|
4
|
+
from [Codex Usage Widget](https://github.com/ognjeeen/codex-usage-widget),
|
|
5
|
+
commit `940d722d4044242bbe73f8056014449c2ef827a7`, particularly
|
|
6
|
+
`Infrastructure/Windows/TaskbarWindowInterop.cs`.
|
|
7
|
+
|
|
8
|
+
MIT License
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2026 Ognjen Marinković
|
|
11
|
+
|
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
+
in the Software without restriction, including without limitation the rights
|
|
15
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
+
furnished to do so, subject to the following conditions:
|
|
18
|
+
|
|
19
|
+
The above copyright notice and this permission notice shall be included in all
|
|
20
|
+
copies or substantial portions of the Software.
|
|
21
|
+
|
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
+
SOFTWARE.
|
|
@@ -20,6 +20,7 @@ from typing import Final
|
|
|
20
20
|
|
|
21
21
|
from i18n import packaged_resource_path
|
|
22
22
|
from installer import setup_hook
|
|
23
|
+
from installer.codex_hook_trust import codex_terse_hook_trust
|
|
23
24
|
|
|
24
25
|
SEPARATOR = "-" * 29
|
|
25
26
|
RATE_LIMIT_FRESH_SECONDS: Final = 15 * 60
|
|
@@ -54,6 +55,7 @@ CHECK_LABELS: Final = {
|
|
|
54
55
|
CODEX_RATE_LIMITS: "codex rate limits",
|
|
55
56
|
CODEX_HISTORY: "codex history",
|
|
56
57
|
CLAUDE_COST: "claude cost",
|
|
58
|
+
"codex_terse_hook_trust": "codex terse hook trust",
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
|
|
@@ -87,6 +89,7 @@ def collect() -> DoctorReport:
|
|
|
87
89
|
("optional", _field(CODEX_LOGS, _codex_logs)),
|
|
88
90
|
("optional", _field(CODEX_RATE_LIMITS, _codex_rate_limits)),
|
|
89
91
|
("optional", _field(CLAUDE_COST, _claude_cost)),
|
|
92
|
+
("optional", _field("codex_terse_hook_trust", _codex_terse_trust)),
|
|
90
93
|
]
|
|
91
94
|
return DoctorReport(
|
|
92
95
|
version=_text_field(_current_version),
|
|
@@ -514,3 +517,8 @@ def _ago(mtime: float) -> str:
|
|
|
514
517
|
return f"{hours}h"
|
|
515
518
|
days = hours // 24
|
|
516
519
|
return f"{days}d"
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
def _codex_terse_trust() -> CheckResult:
|
|
523
|
+
trust = codex_terse_hook_trust()
|
|
524
|
+
return CheckResult("codex_terse_hook_trust", "ok" if trust == "trusted" else "warn", trust)
|
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
"launch_at_login": "開機自動啟動",
|
|
23
23
|
"reset_panel_position": "重設面板位置",
|
|
24
24
|
"hide_sections_menu": "隱藏區塊",
|
|
25
|
+
"tray_provider_menu": "系統匣顯示來源",
|
|
26
|
+
"quota_label_menu": "顯示工作列額度",
|
|
27
|
+
"quota_label_format": "{provider}: {value}%",
|
|
28
|
+
"quota_label_unknown": "{provider}: --",
|
|
25
29
|
"quota_notifications_menu": "用量提醒通知",
|
|
26
30
|
"window_keeper_menu": "自動啟動 5 小時計時",
|
|
27
31
|
"window_keeper_tooltip": "5 小時額度重置後,自動各送一則極小訊息(Claude 用 Haiku、agy 用 Gemini 3.5 Flash Low、Codex 用最省成本模型),讓下一輪 5 小時立刻開始計時(會消耗極少量額度)",
|
|
@@ -56,6 +60,7 @@
|
|
|
56
60
|
"data_stale_hint": "資料來自備援來源,建議檢查設定",
|
|
57
61
|
"status_loading": "載入中",
|
|
58
62
|
"status_synced": "✓ 已同步",
|
|
63
|
+
"status_refreshing": "↻ 更新中…",
|
|
59
64
|
"status_no_data": "無資料",
|
|
60
65
|
"awaiting_rate_limits": "請對 Claude Code 發送一句訊息以同步配額",
|
|
61
66
|
"hook_broken_not_installed": "⚠ 狀態列沒在更新,請按「設定狀態列」重新安裝",
|
|
@@ -75,6 +80,7 @@
|
|
|
75
80
|
"percent_used": "{value}% 已用",
|
|
76
81
|
"reset_in": "重置 {time}",
|
|
77
82
|
"reset_imminent": "即將重置",
|
|
83
|
+
"reset_done": "已重置",
|
|
78
84
|
"burn_warning": "⚠ 照目前速度 {empty}後用完 · 重置 {reset}",
|
|
79
85
|
"burn_warning_compact": "⚠ {empty}後用完",
|
|
80
86
|
"reset_placeholder": "重置 --",
|
|
@@ -490,7 +496,22 @@
|
|
|
490
496
|
"claude_pane_invalid_sidecar": "usage-pane.json 格式錯誤",
|
|
491
497
|
"claude_pane_elapsed": "{minutes}分{seconds}秒",
|
|
492
498
|
"claude_pane_remaining": "剩",
|
|
493
|
-
"
|
|
499
|
+
"claude_pane_reset_done": "已重置",
|
|
500
|
+
"claude_pane_hours_ago": "{count}時前",
|
|
501
|
+
"update_check_failed_offline": "連不上 GitHub,請確認網路後再試。",
|
|
502
|
+
"update_check_failed_rate_limited": "GitHub 暫時拒絕請求,可能太頻繁了,稍後再試。",
|
|
503
|
+
"update_check_failed_server": "GitHub 回應錯誤,稍後再試。",
|
|
504
|
+
"update_check_failed_bad_response": "GitHub 回傳的資料看不懂,稍後再試。",
|
|
505
|
+
"agy_signin_expired": "登入過期",
|
|
506
|
+
"agy_signin_expired_tooltip": "Antigravity 登入已過期,usage 拿不到新額度。在終端機執行一次 agy 重新登入,成功後會自動恢復。",
|
|
507
|
+
"keeper_failed_title": "自動開窗失敗",
|
|
508
|
+
"keeper_failed_body": "{tool}:{reason}。下一輪 5 小時沒有開始計時。",
|
|
509
|
+
"keeper_reason_not_found": "找不到指令",
|
|
510
|
+
"keeper_reason_timeout": "逾時",
|
|
511
|
+
"keeper_failed_line": "上次失敗 {time}:{tool}({reason})",
|
|
512
|
+
"terse_codex_hook_untrusted": "Codex 還沒批准 usage 的精簡模式 hook,Codex 那邊不會生效。在 Codex 裡打 /hooks 批准它。",
|
|
513
|
+
"terse_codex_hook_disabled": "你在 Codex 停用了 usage 的精簡模式 hook。在 Codex 裡打 /hooks 重新啟用。",
|
|
514
|
+
"claude_pane_stopped": "已停止"
|
|
494
515
|
},
|
|
495
516
|
"en": {
|
|
496
517
|
"panel_default_name": "Default",
|
|
@@ -515,6 +536,10 @@
|
|
|
515
536
|
"launch_at_login": "Launch at Login",
|
|
516
537
|
"reset_panel_position": "Reset panel position",
|
|
517
538
|
"hide_sections_menu": "Hide Sections",
|
|
539
|
+
"tray_provider_menu": "Tray Display Source",
|
|
540
|
+
"quota_label_menu": "Show Taskbar Quota",
|
|
541
|
+
"quota_label_format": "{provider}: {value}%",
|
|
542
|
+
"quota_label_unknown": "{provider}: --",
|
|
518
543
|
"quota_notifications_menu": "Usage Alert Notifications",
|
|
519
544
|
"window_keeper_menu": "Auto-start 5-hour Session",
|
|
520
545
|
"window_keeper_tooltip": "After your 5-hour quotas reset, automatically send one tiny message to each tool (Claude with Haiku, agy with Gemini 3.5 Flash Low, Codex with its cheapest model) so the next 5-hour sessions start counting right away (uses a tiny bit of quota).",
|
|
@@ -549,6 +574,7 @@
|
|
|
549
574
|
"data_stale_hint": "Data is from a fallback source. Check settings.",
|
|
550
575
|
"status_loading": "Loading",
|
|
551
576
|
"status_synced": "✓ Synced",
|
|
577
|
+
"status_refreshing": "↻ Refreshing…",
|
|
552
578
|
"status_no_data": "No data",
|
|
553
579
|
"awaiting_rate_limits": "Send a message in Claude Code to sync your quota",
|
|
554
580
|
"hook_broken_not_installed": "⚠ Status line is not updating. Click \"Set Up Status Line\" to reinstall it.",
|
|
@@ -568,6 +594,7 @@
|
|
|
568
594
|
"percent_used": "{value}% used",
|
|
569
595
|
"reset_in": "Resets in {time}",
|
|
570
596
|
"reset_imminent": "Reset imminent",
|
|
597
|
+
"reset_done": "Reset",
|
|
571
598
|
"burn_warning": "⚠ At this pace, empty in {empty} · resets in {reset}",
|
|
572
599
|
"burn_warning_compact": "⚠ Empty in {empty}",
|
|
573
600
|
"reset_placeholder": "Resets in --",
|
|
@@ -983,7 +1010,22 @@
|
|
|
983
1010
|
"claude_pane_invalid_sidecar": "Invalid usage-pane.json",
|
|
984
1011
|
"claude_pane_elapsed": "{minutes}m{seconds}s",
|
|
985
1012
|
"claude_pane_remaining": "left",
|
|
986
|
-
"
|
|
1013
|
+
"claude_pane_reset_done": "Reset",
|
|
1014
|
+
"claude_pane_hours_ago": "{count}h ago",
|
|
1015
|
+
"update_check_failed_offline": "Cannot reach GitHub. Check your connection and try again.",
|
|
1016
|
+
"update_check_failed_rate_limited": "GitHub is limiting requests. Try again later.",
|
|
1017
|
+
"update_check_failed_server": "GitHub returned an error. Try again later.",
|
|
1018
|
+
"update_check_failed_bad_response": "Could not read GitHub’s response. Try again later.",
|
|
1019
|
+
"agy_signin_expired": "Sign-in expired",
|
|
1020
|
+
"agy_signin_expired_tooltip": "Your Antigravity sign-in expired, so usage cannot fetch fresh quota. Run agy in a terminal to sign in again. Quota will recover automatically.",
|
|
1021
|
+
"keeper_failed_title": "Auto-start failed",
|
|
1022
|
+
"keeper_failed_body": "{tool}: {reason}. The next 5-hour window has not started.",
|
|
1023
|
+
"keeper_reason_not_found": "Command not found",
|
|
1024
|
+
"keeper_reason_timeout": "Timed out",
|
|
1025
|
+
"keeper_failed_line": "Last failure {time}: {tool} ({reason})",
|
|
1026
|
+
"terse_codex_hook_untrusted": "Codex has not approved usage’s terse mode hook, so terse mode will not work in Codex. Run /hooks in Codex to approve it.",
|
|
1027
|
+
"terse_codex_hook_disabled": "You disabled usage’s terse mode hook in Codex. Run /hooks in Codex to enable it again.",
|
|
1028
|
+
"claude_pane_stopped": "stopped"
|
|
987
1029
|
},
|
|
988
1030
|
"zh-CN": {
|
|
989
1031
|
"panel_default_name": "默认",
|
|
@@ -1008,6 +1050,10 @@
|
|
|
1008
1050
|
"launch_at_login": "开机自动启动",
|
|
1009
1051
|
"reset_panel_position": "重设面板位置",
|
|
1010
1052
|
"hide_sections_menu": "隐藏区块",
|
|
1053
|
+
"tray_provider_menu": "托盘显示来源",
|
|
1054
|
+
"quota_label_menu": "显示任务栏额度",
|
|
1055
|
+
"quota_label_format": "{provider}: {value}%",
|
|
1056
|
+
"quota_label_unknown": "{provider}: --",
|
|
1011
1057
|
"quota_notifications_menu": "用量提醒通知",
|
|
1012
1058
|
"window_keeper_menu": "自动启动 5 小时计时",
|
|
1013
1059
|
"window_keeper_tooltip": "5 小时额度重置后,自动各发送一则极小消息(Claude 用 Haiku、agy 用 Gemini 3.5 Flash Low、Codex 用最省成本模型),让下一轮 5 小时立刻开始计时(会消耗极少量额度)",
|
|
@@ -1042,6 +1088,7 @@
|
|
|
1042
1088
|
"data_stale_hint": "数据来自备用来源,建议检查设置",
|
|
1043
1089
|
"status_loading": "加载中",
|
|
1044
1090
|
"status_synced": "✓ 已同步",
|
|
1091
|
+
"status_refreshing": "↻ 更新中…",
|
|
1045
1092
|
"status_no_data": "无数据",
|
|
1046
1093
|
"awaiting_rate_limits": "请对 Claude Code 发送一句消息以同步配额",
|
|
1047
1094
|
"hook_broken_not_installed": "⚠ 状态栏没有更新,请点「设置状态栏」重新安装",
|
|
@@ -1061,6 +1108,7 @@
|
|
|
1061
1108
|
"percent_used": "{value}% 已用",
|
|
1062
1109
|
"reset_in": "重置 {time}",
|
|
1063
1110
|
"reset_imminent": "即将重置",
|
|
1111
|
+
"reset_done": "已重置",
|
|
1064
1112
|
"burn_warning": "⚠ 按当前速度 {empty}后用完 · 重置 {reset}",
|
|
1065
1113
|
"burn_warning_compact": "⚠ {empty}后用完",
|
|
1066
1114
|
"reset_placeholder": "重置 --",
|
|
@@ -1476,7 +1524,22 @@
|
|
|
1476
1524
|
"claude_pane_invalid_sidecar": "usage-pane.json 格式错误",
|
|
1477
1525
|
"claude_pane_elapsed": "{minutes}分{seconds}秒",
|
|
1478
1526
|
"claude_pane_remaining": "剩",
|
|
1479
|
-
"
|
|
1527
|
+
"claude_pane_reset_done": "已重置",
|
|
1528
|
+
"claude_pane_hours_ago": "{count}时前",
|
|
1529
|
+
"update_check_failed_offline": "连不上 GitHub,请确认网络后再试。",
|
|
1530
|
+
"update_check_failed_rate_limited": "GitHub 暂时拒绝请求,可能太频繁了,稍后再试。",
|
|
1531
|
+
"update_check_failed_server": "GitHub 响应错误,稍后再试。",
|
|
1532
|
+
"update_check_failed_bad_response": "GitHub 返回的数据看不懂,稍后再试。",
|
|
1533
|
+
"agy_signin_expired": "登录过期",
|
|
1534
|
+
"agy_signin_expired_tooltip": "Antigravity 登录已过期,usage 无法获取新额度。在终端运行一次 agy 重新登录,成功后会自动恢复。",
|
|
1535
|
+
"keeper_failed_title": "自动开窗失败",
|
|
1536
|
+
"keeper_failed_body": "{tool}:{reason}。下一轮 5 小时没有开始计时。",
|
|
1537
|
+
"keeper_reason_not_found": "找不到命令",
|
|
1538
|
+
"keeper_reason_timeout": "超时",
|
|
1539
|
+
"keeper_failed_line": "上次失败 {time}:{tool}({reason})",
|
|
1540
|
+
"terse_codex_hook_untrusted": "Codex 还没批准 usage 的精简模式 hook,Codex 那边不会生效。在 Codex 里输入 /hooks 批准它。",
|
|
1541
|
+
"terse_codex_hook_disabled": "你在 Codex 停用了 usage 的精简模式 hook。在 Codex 里输入 /hooks 重新启用。",
|
|
1542
|
+
"claude_pane_stopped": "已停止"
|
|
1480
1543
|
},
|
|
1481
1544
|
"ja": {
|
|
1482
1545
|
"panel_default_name": "デフォルト",
|
|
@@ -1501,6 +1564,10 @@
|
|
|
1501
1564
|
"launch_at_login": "ログイン時に起動",
|
|
1502
1565
|
"reset_panel_position": "パネルの位置をリセット",
|
|
1503
1566
|
"hide_sections_menu": "セクションを非表示",
|
|
1567
|
+
"tray_provider_menu": "トレイの表示元",
|
|
1568
|
+
"quota_label_menu": "タスクバーにクォータを表示",
|
|
1569
|
+
"quota_label_format": "{provider}: {value}%",
|
|
1570
|
+
"quota_label_unknown": "{provider}: --",
|
|
1504
1571
|
"quota_notifications_menu": "使用量アラート通知",
|
|
1505
1572
|
"window_keeper_menu": "5 時間セッションを自動開始",
|
|
1506
1573
|
"window_keeper_tooltip": "5 時間枠のリセット後、各ツールにごく小さなメッセージを自動送信します(Claude は Haiku、agy は Gemini 3.5 Flash Low、Codex は最も低コストなモデル)。次の 5 時間のカウントをすぐに開始します(ごくわずかな枠を消費します)。",
|
|
@@ -1535,6 +1602,7 @@
|
|
|
1535
1602
|
"data_stale_hint": "データはフォールバック元から取得しています。設定を確認してください。",
|
|
1536
1603
|
"status_loading": "読み込み中",
|
|
1537
1604
|
"status_synced": "✓ 同期済み",
|
|
1605
|
+
"status_refreshing": "↻ 更新中…",
|
|
1538
1606
|
"status_no_data": "データなし",
|
|
1539
1607
|
"awaiting_rate_limits": "Claude Code にメッセージを送信してクォータを同期してください",
|
|
1540
1608
|
"hook_broken_not_installed": "⚠ ステータスラインが更新されていません。「ステータスラインを設定」を押して再インストールしてください。",
|
|
@@ -1554,6 +1622,7 @@
|
|
|
1554
1622
|
"percent_used": "{value}% 使用済み",
|
|
1555
1623
|
"reset_in": "{time}後にリセット",
|
|
1556
1624
|
"reset_imminent": "まもなくリセット",
|
|
1625
|
+
"reset_done": "リセット済み",
|
|
1557
1626
|
"burn_warning": "⚠ このペースで{empty}で使い切り·リセット{reset}",
|
|
1558
1627
|
"burn_warning_compact": "⚠ {empty}で使い切り",
|
|
1559
1628
|
"reset_placeholder": "リセット --",
|
|
@@ -1969,7 +2038,22 @@
|
|
|
1969
2038
|
"claude_pane_invalid_sidecar": "usage-pane.json の形式が不正です",
|
|
1970
2039
|
"claude_pane_elapsed": "{minutes}分{seconds}秒",
|
|
1971
2040
|
"claude_pane_remaining": "残り",
|
|
1972
|
-
"
|
|
2041
|
+
"claude_pane_reset_done": "リセット済み",
|
|
2042
|
+
"claude_pane_hours_ago": "{count}時間前",
|
|
2043
|
+
"update_check_failed_offline": "GitHub に接続できません。ネット接続を確認して再試行してください。",
|
|
2044
|
+
"update_check_failed_rate_limited": "GitHub がリクエストを制限しています。後でもう一度お試しください。",
|
|
2045
|
+
"update_check_failed_server": "GitHub でエラーが発生しました。後でもう一度お試しください。",
|
|
2046
|
+
"update_check_failed_bad_response": "GitHub の応答を読み取れませんでした。後でもう一度お試しください。",
|
|
2047
|
+
"agy_signin_expired": "ログイン期限切れ",
|
|
2048
|
+
"agy_signin_expired_tooltip": "Antigravity のログイン期限が切れたため、usage は新しい利用枠を取得できません。ターミナルで agy を実行して再ログインすると、自動で復旧します。",
|
|
2049
|
+
"keeper_failed_title": "自動開始に失敗",
|
|
2050
|
+
"keeper_failed_body": "{tool}:{reason}。次の 5 時間枠は開始されていません。",
|
|
2051
|
+
"keeper_reason_not_found": "コマンドが見つかりません",
|
|
2052
|
+
"keeper_reason_timeout": "タイムアウト",
|
|
2053
|
+
"keeper_failed_line": "前回の失敗 {time}:{tool}({reason})",
|
|
2054
|
+
"terse_codex_hook_untrusted": "Codex が usage の簡潔モード hook をまだ承認していないため、Codex では機能しません。Codex で /hooks を入力して承認してください。",
|
|
2055
|
+
"terse_codex_hook_disabled": "Codex で usage の簡潔モード hook が無効になっています。Codex で /hooks を入力して再び有効にしてください。",
|
|
2056
|
+
"claude_pane_stopped": "停止済み"
|
|
1973
2057
|
},
|
|
1974
2058
|
"ko": {
|
|
1975
2059
|
"panel_default_name": "기본",
|
|
@@ -1994,6 +2078,10 @@
|
|
|
1994
2078
|
"launch_at_login": "로그인 시 시작",
|
|
1995
2079
|
"reset_panel_position": "패널 위치 재설정",
|
|
1996
2080
|
"hide_sections_menu": "섹션 숨기기",
|
|
2081
|
+
"tray_provider_menu": "트레이 표시 소스",
|
|
2082
|
+
"quota_label_menu": "작업 표시줄 할당량 표시",
|
|
2083
|
+
"quota_label_format": "{provider}: {value}%",
|
|
2084
|
+
"quota_label_unknown": "{provider}: --",
|
|
1997
2085
|
"quota_notifications_menu": "사용량 알림",
|
|
1998
2086
|
"window_keeper_menu": "5시간 세션 자동 시작",
|
|
1999
2087
|
"window_keeper_tooltip": "5시간 할당량이 리셋되면 각 도구에 아주 작은 메시지를 자동 전송합니다 (Claude는 Haiku, agy는 Gemini 3.5 Flash Low, Codex는 가장 저렴한 모델). 다음 5시간 카운트를 바로 시작합니다 (극소량의 할당량을 소모합니다).",
|
|
@@ -2028,6 +2116,7 @@
|
|
|
2028
2116
|
"data_stale_hint": "데이터가 대체 소스에서 왔습니다. 설정을 확인하세요.",
|
|
2029
2117
|
"status_loading": "불러오는 중",
|
|
2030
2118
|
"status_synced": "✓ 동기화됨",
|
|
2119
|
+
"status_refreshing": "↻ 새로 고치는 중…",
|
|
2031
2120
|
"status_no_data": "데이터 없음",
|
|
2032
2121
|
"awaiting_rate_limits": "Claude Code에 메시지를 보내 할당량을 동기화하세요",
|
|
2033
2122
|
"hook_broken_not_installed": "⚠ 상태 표시줄이 업데이트되지 않습니다. \"상태 표시줄 설정\"을 눌러 다시 설치하세요.",
|
|
@@ -2047,6 +2136,7 @@
|
|
|
2047
2136
|
"percent_used": "{value}% 사용됨",
|
|
2048
2137
|
"reset_in": "{time} 후 초기화",
|
|
2049
2138
|
"reset_imminent": "곧 초기화",
|
|
2139
|
+
"reset_done": "리셋됨",
|
|
2050
2140
|
"burn_warning": "⚠ 현재 속도면 {empty} 후 소진 · 초기화까지 {reset}",
|
|
2051
2141
|
"burn_warning_compact": "⚠ {empty} 후 소진",
|
|
2052
2142
|
"reset_placeholder": "초기화까지 --",
|
|
@@ -2462,6 +2552,21 @@
|
|
|
2462
2552
|
"claude_pane_invalid_sidecar": "usage-pane.json 형식이 잘못되었습니다",
|
|
2463
2553
|
"claude_pane_elapsed": "{minutes}분{seconds}초",
|
|
2464
2554
|
"claude_pane_remaining": "남음",
|
|
2465
|
-
"
|
|
2555
|
+
"claude_pane_reset_done": "리셋됨",
|
|
2556
|
+
"claude_pane_hours_ago": "{count}시간 전",
|
|
2557
|
+
"update_check_failed_offline": "GitHub에 연결할 수 없어요. 인터넷 연결을 확인하고 다시 시도하세요.",
|
|
2558
|
+
"update_check_failed_rate_limited": "GitHub가 요청을 제한하고 있어요. 잠시 후 다시 시도하세요.",
|
|
2559
|
+
"update_check_failed_server": "GitHub에서 오류가 발생했어요. 잠시 후 다시 시도하세요.",
|
|
2560
|
+
"update_check_failed_bad_response": "GitHub 응답을 읽을 수 없어요. 잠시 후 다시 시도하세요.",
|
|
2561
|
+
"agy_signin_expired": "로그인 만료",
|
|
2562
|
+
"agy_signin_expired_tooltip": "Antigravity 로그인이 만료되어 usage가 새 한도를 가져올 수 없어요. 터미널에서 agy를 실행해 다시 로그인하면 자동으로 복구돼요.",
|
|
2563
|
+
"keeper_failed_title": "자동 시작 실패",
|
|
2564
|
+
"keeper_failed_body": "{tool}: {reason}. 다음 5시간 구간이 시작되지 않았습니다.",
|
|
2565
|
+
"keeper_reason_not_found": "명령을 찾을 수 없음",
|
|
2566
|
+
"keeper_reason_timeout": "시간 초과",
|
|
2567
|
+
"keeper_failed_line": "마지막 실패 {time}: {tool} ({reason})",
|
|
2568
|
+
"terse_codex_hook_untrusted": "Codex가 usage의 간결 모드 hook을 아직 승인하지 않아 Codex에서 작동하지 않습니다. Codex에서 /hooks를 입력해 승인하세요.",
|
|
2569
|
+
"terse_codex_hook_disabled": "Codex에서 usage의 간결 모드 hook을 비활성화했습니다. Codex에서 /hooks를 입력해 다시 활성화하세요.",
|
|
2570
|
+
"claude_pane_stopped": "중지됨"
|
|
2466
2571
|
}
|
|
2467
2572
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""Read Codex's approval record without granting hook trust."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
import tomllib
|
|
8
|
+
|
|
9
|
+
from installer import session_hooks
|
|
10
|
+
from loaders.codex_paths import codex_home
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def codex_terse_hook_trust() -> str:
|
|
14
|
+
"""Return the usage SessionStart hook's trust state.
|
|
15
|
+
|
|
16
|
+
A trusted_hash alone cannot detect Modified (a hook edited after approval).
|
|
17
|
+
Codex remains responsible for verifying the hash and asking for approval.
|
|
18
|
+
"""
|
|
19
|
+
path = session_hooks.CODEX_HOOKS_JSON
|
|
20
|
+
try:
|
|
21
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
22
|
+
if not isinstance(data, dict):
|
|
23
|
+
return "unknown"
|
|
24
|
+
groups = session_hooks._codex_session_start_list(data)
|
|
25
|
+
if groups is None:
|
|
26
|
+
return "not_installed"
|
|
27
|
+
index = None
|
|
28
|
+
for group_index, group in enumerate(groups):
|
|
29
|
+
handlers = group.get("hooks") if isinstance(group, dict) else None
|
|
30
|
+
if not isinstance(handlers, list):
|
|
31
|
+
continue
|
|
32
|
+
for handler_index, handler in enumerate(handlers):
|
|
33
|
+
command = handler.get("command") if isinstance(handler, dict) else None
|
|
34
|
+
if isinstance(command, str) and session_hooks._TERSE_MARKER in command:
|
|
35
|
+
index = (group_index, handler_index)
|
|
36
|
+
break
|
|
37
|
+
if index is not None:
|
|
38
|
+
break
|
|
39
|
+
if index is None:
|
|
40
|
+
return "not_installed"
|
|
41
|
+
with (codex_home() / "config.toml").open("rb") as handle:
|
|
42
|
+
config = tomllib.load(handle)
|
|
43
|
+
hooks = config.get("hooks", {})
|
|
44
|
+
states = hooks.get("state", {}) if isinstance(hooks, dict) else {}
|
|
45
|
+
if not isinstance(states, dict):
|
|
46
|
+
return "unknown"
|
|
47
|
+
suffix = f":session_start:{index[0]}:{index[1]}"
|
|
48
|
+
entry = states.get(f"{path}{suffix}")
|
|
49
|
+
if entry is None:
|
|
50
|
+
entry = next(
|
|
51
|
+
(
|
|
52
|
+
value
|
|
53
|
+
for key, value in states.items()
|
|
54
|
+
if key.endswith(suffix)
|
|
55
|
+
and os.path.realpath(key[: -len(suffix)]) == os.path.realpath(path)
|
|
56
|
+
),
|
|
57
|
+
{},
|
|
58
|
+
)
|
|
59
|
+
if not isinstance(entry, dict):
|
|
60
|
+
return "untrusted"
|
|
61
|
+
if entry.get("enabled") is False:
|
|
62
|
+
return "disabled"
|
|
63
|
+
trusted_hash = entry.get("trusted_hash")
|
|
64
|
+
return "trusted" if isinstance(trusted_hash, str) and trusted_hash else "untrusted"
|
|
65
|
+
except (OSError, UnicodeError, ValueError):
|
|
66
|
+
return "unknown"
|
|
@@ -37,6 +37,19 @@ from urllib.request import Request, urlopen
|
|
|
37
37
|
from usage_common.subprocess_utils import hidden_console_kwargs
|
|
38
38
|
|
|
39
39
|
CACHE_PATH = Path(os.path.expanduser("~/.usage/agy_quota_cache.json"))
|
|
40
|
+
AUTH_EXPIRED_PATH = CACHE_PATH.parent / "agy_auth_expired"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def auth_expired() -> bool:
|
|
44
|
+
return AUTH_EXPIRED_PATH.exists()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _mark_auth_expired() -> None:
|
|
48
|
+
with suppress(OSError):
|
|
49
|
+
AUTH_EXPIRED_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
50
|
+
AUTH_EXPIRED_PATH.touch()
|
|
51
|
+
|
|
52
|
+
|
|
40
53
|
# Legacy OAuth token written by older Antigravity CLI versions. Read-only: we
|
|
41
54
|
# never write back here (that is the CLI's home and could corrupt its login).
|
|
42
55
|
_TOKEN_PATH = Path(os.path.expanduser("~/.gemini/antigravity-cli/antigravity-oauth-token"))
|
|
@@ -117,7 +130,11 @@ def probe_quota(timeout_seconds: float = 15) -> AgyQuotaResult | None:
|
|
|
117
130
|
groups_raw = _extract_groups(raw)
|
|
118
131
|
if not groups_raw:
|
|
119
132
|
return None
|
|
120
|
-
|
|
133
|
+
result = _build_result(groups_raw)
|
|
134
|
+
if result is not None:
|
|
135
|
+
with suppress(OSError):
|
|
136
|
+
AUTH_EXPIRED_PATH.unlink(missing_ok=True)
|
|
137
|
+
return result
|
|
121
138
|
|
|
122
139
|
|
|
123
140
|
def find_agy() -> str | None:
|
|
@@ -353,6 +370,20 @@ def _refresh_token(refresh_token: str, timeout: float) -> tuple[str, int] | None
|
|
|
353
370
|
payload = json.loads(raw)
|
|
354
371
|
except HTTPError as exc:
|
|
355
372
|
_handle_http_error(exc)
|
|
373
|
+
if exc.code == 401:
|
|
374
|
+
_mark_auth_expired()
|
|
375
|
+
elif exc.code == 400:
|
|
376
|
+
try:
|
|
377
|
+
raw_error = exc.read(_MAX_RESPONSE_BYTES + 1)
|
|
378
|
+
if len(raw_error) <= _MAX_RESPONSE_BYTES:
|
|
379
|
+
error_payload = json.loads(raw_error)
|
|
380
|
+
if (
|
|
381
|
+
isinstance(error_payload, dict)
|
|
382
|
+
and error_payload.get("error") == "invalid_grant"
|
|
383
|
+
):
|
|
384
|
+
_mark_auth_expired()
|
|
385
|
+
except (OSError, ValueError):
|
|
386
|
+
pass
|
|
356
387
|
return None
|
|
357
388
|
except (URLError, OSError, ValueError):
|
|
358
389
|
return None
|
|
@@ -387,6 +418,8 @@ def _post_json(url: str, access_token: str, body: dict[str, object], timeout: fl
|
|
|
387
418
|
return json.loads(raw)
|
|
388
419
|
except HTTPError as exc:
|
|
389
420
|
_handle_http_error(exc)
|
|
421
|
+
if exc.code == 401:
|
|
422
|
+
_mark_auth_expired()
|
|
390
423
|
return None
|
|
391
424
|
except (URLError, OSError, ValueError):
|
|
392
425
|
return None
|
|
@@ -18,6 +18,7 @@ from loaders.agy_quota_probe import (
|
|
|
18
18
|
AgyQuotaGroup,
|
|
19
19
|
AgyQuotaResult,
|
|
20
20
|
AgyQuotaWindow,
|
|
21
|
+
auth_expired,
|
|
21
22
|
load_quota,
|
|
22
23
|
)
|
|
23
24
|
from loaders.agy_quota_probe import (
|
|
@@ -213,20 +214,20 @@ def _remaining_percent(window: AgyQuotaWindow) -> float:
|
|
|
213
214
|
return max(0.0, min(100.0, float(window.remaining_percent)))
|
|
214
215
|
|
|
215
216
|
|
|
216
|
-
def _cache_age_minutes(fetched_at: str, now: float) ->
|
|
217
|
-
"""
|
|
217
|
+
def _cache_age_minutes(fetched_at: str, now: float) -> float:
|
|
218
|
+
"""Minutes since the cached snapshot was taken (never negative)."""
|
|
218
219
|
try:
|
|
219
220
|
age_seconds = now - parse_iso8601_utc_or_raise(fetched_at).timestamp()
|
|
220
221
|
except (TypeError, ValueError):
|
|
221
222
|
return 0
|
|
222
|
-
return max(0,
|
|
223
|
+
return max(0.0, age_seconds / 60)
|
|
223
224
|
|
|
224
225
|
|
|
225
226
|
def _window_row(
|
|
226
227
|
title: str,
|
|
227
228
|
window: AgyQuotaWindow,
|
|
228
229
|
language: str,
|
|
229
|
-
age_minutes:
|
|
230
|
+
age_minutes: float = 0,
|
|
230
231
|
forecast_seconds: float | None = None,
|
|
231
232
|
warning_max_seconds: float | None = None,
|
|
232
233
|
*,
|
|
@@ -236,12 +237,20 @@ def _window_row(
|
|
|
236
237
|
used = 100.0 - remaining
|
|
237
238
|
warning = False
|
|
238
239
|
warning_seconds: float | None = None
|
|
239
|
-
|
|
240
|
+
reset_done = window.resets_in_minutes is not None and window.resets_in_minutes <= max(
|
|
241
|
+
0, age_minutes
|
|
242
|
+
)
|
|
243
|
+
if reset_done:
|
|
244
|
+
used = 0.0
|
|
245
|
+
reset_text = _t(language, "reset_done")
|
|
246
|
+
elif remaining == 100.0:
|
|
240
247
|
reset_text = _t(language, "agy_quota_full")
|
|
241
248
|
elif window.resets_in_minutes is None:
|
|
242
249
|
reset_text = _t(language, "reset_placeholder")
|
|
250
|
+
elif window.resets_in_minutes - max(0, age_minutes) < 1:
|
|
251
|
+
reset_text = _t(language, "reset_imminent")
|
|
243
252
|
else:
|
|
244
|
-
minutes_left =
|
|
253
|
+
minutes_left = window.resets_in_minutes - int(max(0, age_minutes))
|
|
245
254
|
time_to_reset = minutes_left * 60
|
|
246
255
|
if window_seconds is None:
|
|
247
256
|
if (
|
|
@@ -275,16 +284,22 @@ def _window_row(
|
|
|
275
284
|
)
|
|
276
285
|
return QuotaRowState(
|
|
277
286
|
title=title,
|
|
278
|
-
percent=
|
|
287
|
+
percent=100.0 - remaining,
|
|
279
288
|
percent_text=_t(language, "percent_used", value=_format_percent(used)),
|
|
280
289
|
reset_text=reset_text,
|
|
281
290
|
color=_bar_color(used, AGY_COLOR),
|
|
282
291
|
warning=warning,
|
|
283
292
|
available=True,
|
|
293
|
+
reset_done=reset_done,
|
|
284
294
|
)
|
|
285
295
|
|
|
286
296
|
|
|
287
297
|
def _stale_state(fetched_at: str, now: float, language: str) -> AgyStaleState | None:
|
|
298
|
+
if auth_expired():
|
|
299
|
+
return {
|
|
300
|
+
"ageText": _t(language, "agy_signin_expired"),
|
|
301
|
+
"tooltip": _t(language, "agy_signin_expired_tooltip"),
|
|
302
|
+
}
|
|
288
303
|
try:
|
|
289
304
|
age_seconds = now - parse_iso8601_utc_or_raise(fetched_at).timestamp()
|
|
290
305
|
except (TypeError, ValueError):
|