usage-cli 0.32.0__tar.gz → 0.32.1__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.0 → usage_cli-0.32.1}/PKG-INFO +31 -3
- {usage_cli-0.32.0 → usage_cli-0.32.1}/README.md +30 -2
- {usage_cli-0.32.0 → usage_cli-0.32.1}/i18n.json +5 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/installer/claude_pane.py +28 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/main.py +5 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/pyproject.toml +1 -1
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_claude_pane.py +53 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_main.py +13 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_wintray.py +88 -1
- {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_cli.egg-info/PKG-INFO +31 -3
- {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_cli.py +3 -1
- {usage_cli-0.32.0 → usage_cli-0.32.1}/wintray/app.py +61 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/wintray/menu.py +2 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/LICENSE +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/adapters/__init__.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/adapters/agy.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/adapters/claude.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/adapters/codex.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/adapters/grok.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/adapters/muse.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/adapters/rate_limits.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/adapters/registry.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/adapters/types.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/analyzer/__init__.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/analyzer/aggregator.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/analyzer/blocks.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/analyzer/diagnoser.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/analyzer/dispatch_ledger.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/analyzer/insights.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/analyzer/persona_loader.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/analyzer/reporter.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/analyzer/subscription.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/analyzer/usage_snapshot.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/doctor.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/fsevents_watch.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/i18n.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/installer/__init__.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/installer/login_item.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/installer/session_hooks.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/installer/setup_hook.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/installer/statusline_settings.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/__init__.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/agy_disk_cache.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/agy_loader.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/agy_quota_probe.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/cache_quarantine.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/claude_paths.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/codex_disk_cache.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/codex_events.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/codex_fork_replay.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/codex_loader.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/codex_paths.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/disk_cache_common.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/disk_cache_lifecycle.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/grok_loader.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/grok_quota_probe.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/history_disk_cache.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/history_loader.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/jsonl_limits.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/jsonl_utils.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/muse_loader.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/__init__.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/actions.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/agy.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/app.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/chrome.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/grok.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/menu.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/new_badge.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/notify.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/popover.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/prefs.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/refresh.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/state.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/title.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/update.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/panels/__init__.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/panels/base.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/panels/dynamic_height.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/panels/panel_scale.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/panels/panel_window.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/panels/panel_window_state.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/panels/payload.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/panels/web_panel.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/panels/window_drag.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/prefs.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/pricing.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/project_resolver.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/quota/__init__.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/quota/agy_window_keeper.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/quota/burn_rate.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/quota/codex_window_keeper.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/quota/usage_rate.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/quota/window_keeper.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/service_status.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/setup.cfg +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/setup_app.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_adapters_claude.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_adapters_codex.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_adapters_rate_limits.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_aggregator.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_agy_adapter.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_agy_disk_cache.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_agy_loader.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_agy_quota_probe.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_agy_window_keeper.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_analyzer_blocks.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_analyzer_pipeline.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_burn_rate.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_cache_quarantine.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_claude_paths.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_codex_consistency.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_codex_loader.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_codex_window_keeper.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_diagnoser.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_disk_cache_shards.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_dispatch_ledger.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_doctor.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_dynamic_height.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_fsevents_watch.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_grok_loader.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_grok_quota_probe.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_history_loader.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_hook_scripts_are_standalone.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_html_report_snapshot.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_i18n_format_fallback.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_i18n_key_parity.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_i18n_packaged_path.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_insights.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_jsonl_utils.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_login_item.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_menubar.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_menubar_agy.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_menubar_grok.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_menubar_notify.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_menubar_prefs.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_menubar_state.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_muse_loader.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_new_badge.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_packaged_resources.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_packaging.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_panel_footer_layout.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_panel_scale.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_panel_window_state.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_panels.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_panels_lazy_import.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_persona_loader.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_pricing.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_project_resolver.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_report_daily_chart.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_report_filter_js.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_reporter_build_data.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_service_status.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_session_resume.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_setup_app.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_setup_hook.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_setup_hook_coexistence.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_setup_hook_resume.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_setup_hook_terse.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_subprocess_utils.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_subscription.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_time_utils.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_tui.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_tui_sprite.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_ui_tables.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_update_checker.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_update_gate.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_update_release_notes.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_cli.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_client.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_diagnosis_snapshot.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_dir_sweeper.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_lang.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_logging.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_notifications.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_rate.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_snapshot.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_snapshot_replay.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_statusline.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_statusline_agy.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_statusline_forwarder.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_statusline_grok.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_terse_mode.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_terse_reminder.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_web_panel_payload.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_wheel_packaging.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_win_login_item.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_window_keeper.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_windows_manifest.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tui/__init__.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tui/app.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/tui/sprite.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/ui/__init__.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/ui/html_report.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/ui/report_charts.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/ui/report_daily_chart.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/ui/report_filter.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/ui/report_ledger.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/ui/report_scripts.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/ui/report_styles.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/ui/tables.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/updates/__init__.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/updates/checker.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/updates/gate.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/updates/release_notes.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_cli.egg-info/SOURCES.txt +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_cli.egg-info/dependency_links.txt +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_cli.egg-info/entry_points.txt +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_cli.egg-info/requires.txt +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_cli.egg-info/top_level.txt +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_client.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_common/__init__.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_common/subprocess_utils.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_common/time_utils.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_common/usage_dir_sweeper.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_common/usage_lang.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_common/usage_logging.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_diagnosis_snapshot.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_notifications.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_session_resume.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_statusline.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_statusline_agy.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_statusline_forwarder.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_statusline_grok.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_terse_mode.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_terse_reminder.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/wintray/__init__.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/wintray/login_item.py +0 -0
- {usage_cli-0.32.0 → usage_cli-0.32.1}/wintray/watch.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: usage-cli
|
|
3
|
-
Version: 0.32.
|
|
3
|
+
Version: 0.32.1
|
|
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
|
|
@@ -57,7 +57,7 @@ It lands in your Applications folder automatically. Open it once; if macOS 15 or
|
|
|
57
57
|
|
|
58
58
|
**Not on macOS?** `uvx usage-cli` runs the terminal interface anywhere, Linux included — no install, no menu bar.
|
|
59
59
|
|
|
60
|
-
**Jump to:** [What You Get](#what-you-get) · [Privacy](#privacy--data-sources) · [Requirements](#requirements) · [Install](#install) · [Status Line](#first-launch-set-up-the-status-line) · [Windows](#windows-support) · [Themes](#theme-gallery) · [Troubleshooting](#troubleshooting) · [Comparison](#comparison) · [Not a Fit?](#when-usage-isnt-the-right-fit) · [Development](#development)
|
|
60
|
+
**Jump to:** [What You Get](#what-you-get) · [Privacy](#privacy--data-sources) · [Requirements](#requirements) · [Install](#install) · [Status Line](#first-launch-set-up-the-status-line) · [Claude Code Side Pane](#claude-code-side-pane) · [Windows](#windows-support) · [Themes](#theme-gallery) · [Troubleshooting](#troubleshooting) · [Comparison](#comparison) · [Not a Fit?](#when-usage-isnt-the-right-fit) · [Development](#development)
|
|
61
61
|
|
|
62
62
|
## What You Get
|
|
63
63
|
|
|
@@ -76,7 +76,7 @@ It lands in your Applications folder automatically. Open it once; if macOS 15 or
|
|
|
76
76
|
|
|
77
77
|
- **Progress Concierge:** Open a new Claude Code session and `usage` hands your last progress straight to the AI, including your last request, uncommitted changes, and unfinished todos. No `/resume`, no recap. When you do `/resume` a conversation that sat long enough for its cache to expire, it warns you how many tokens the next message will re-send and suggests `/compact` first. Off by default.
|
|
78
78
|
- **Token Saver:** A menu-bar toggle asks Claude Code and Codex to answer more tersely and in plainer language, saving output tokens while keeping code and error messages byte-exact. A light reminder keeps long conversations from drifting back to verbose — in an A/B test on real sessions, late replies stayed ~40% shorter instead of drifting 84% longer.
|
|
79
|
-
- **Claude Code side pane (macOS):**
|
|
79
|
+
- **Claude Code side pane (macOS and Windows):** Quotas, conversations, and background jobs inside Claude Code. [See the side pane](#claude-code-side-pane).
|
|
80
80
|
- **Auto-start 5-hour Session:** Off by default. Turn it on and, right after a 5-hour quota resets, `usage` sends one tiny message to each tool (Claude with Haiku, Antigravity with Gemini 3.5 Flash Low, Codex with its cheapest model) so the next 5-hour window starts counting right away. Those messages do use a little quota, but the amount is negligible. Checking your quota never sends a message; only this switch does.
|
|
81
81
|
- **Terminal Integration:** `usage status --json` hands your Claude Code, Codex, Antigravity, and Grok quota to any tool that can run a command — Starship, tmux, or your own scripts. Reads the same local files as the menu bar. [Ready-made snippets](docs/DEVELOPMENT.md#quota-status-for-other-tools-usage-status).
|
|
82
82
|
- **Token-waste Health Check:** A daily background diagnosis scans your logs for waste, including repeated file reads, polluter directories, and noisy Bash output. If it finds issues, a one-line heads-up appears; say "show me" and the AI walks you through fixes.
|
|
@@ -147,6 +147,34 @@ Once set up, the bottom of the Claude Code window will show a status line like t
|
|
|
147
147
|
<img src="docs/statusline.en.gif" alt="Claude Code statusLine display (English)" width="900">
|
|
148
148
|
</p>
|
|
149
149
|
|
|
150
|
+
## Claude Code Side Pane
|
|
151
|
+
|
|
152
|
+
See your quota, other conversations, and background jobs without leaving Claude Code. Available on macOS and Windows.
|
|
153
|
+
|
|
154
|
+
<p align="center"><img src="docs/side-pane.png" alt="Claude Code side pane showing quotas, conversations, and background jobs" width="637"></p>
|
|
155
|
+
|
|
156
|
+
**What you’ll see**
|
|
157
|
+
|
|
158
|
+
- **Quotas:** Your 5-hour and weekly limits.
|
|
159
|
+
- **Claude conversations:** Conversations waiting for your permission or MCP input are marked in yellow.
|
|
160
|
+
- **Background jobs:** Includes subagents started by Claude with the Agent tool and their status.
|
|
161
|
+
|
|
162
|
+
**How to enable**
|
|
163
|
+
|
|
164
|
+
1. In the usage menu bar menu (macOS) or the system-tray panel menu (Windows), check **Claude Code side pane**.
|
|
165
|
+
2. Open a new conversation or run `/reload-plugins`.
|
|
166
|
+
3. At terminal widths ≥144 columns, the pane opens on the right automatically. In narrower terminals, enter `/usage-dash`.
|
|
167
|
+
|
|
168
|
+
<details>
|
|
169
|
+
<summary>Compatibility and updates</summary>
|
|
170
|
+
|
|
171
|
+
- Requires a recent Claude Code with mod support; tested with 2.1.289.
|
|
172
|
+
- The pane docks on the right only in Claude Code's fullscreen layout; otherwise it appears above the prompt. On Windows, enabling the pane turns the fullscreen layout on as well, and turning the pane off switches it back.
|
|
173
|
+
- The built-in macOS Terminal supports only 256 colors and may show a gray background. Select an ANSI dark theme in `/config`.
|
|
174
|
+
- When the usage app starts, it automatically updates an enabled pane to the bundled version.
|
|
175
|
+
|
|
176
|
+
</details>
|
|
177
|
+
|
|
150
178
|
## Windows Support
|
|
151
179
|
|
|
152
180
|
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.
|
|
@@ -37,7 +37,7 @@ It lands in your Applications folder automatically. Open it once; if macOS 15 or
|
|
|
37
37
|
|
|
38
38
|
**Not on macOS?** `uvx usage-cli` runs the terminal interface anywhere, Linux included — no install, no menu bar.
|
|
39
39
|
|
|
40
|
-
**Jump to:** [What You Get](#what-you-get) · [Privacy](#privacy--data-sources) · [Requirements](#requirements) · [Install](#install) · [Status Line](#first-launch-set-up-the-status-line) · [Windows](#windows-support) · [Themes](#theme-gallery) · [Troubleshooting](#troubleshooting) · [Comparison](#comparison) · [Not a Fit?](#when-usage-isnt-the-right-fit) · [Development](#development)
|
|
40
|
+
**Jump to:** [What You Get](#what-you-get) · [Privacy](#privacy--data-sources) · [Requirements](#requirements) · [Install](#install) · [Status Line](#first-launch-set-up-the-status-line) · [Claude Code Side Pane](#claude-code-side-pane) · [Windows](#windows-support) · [Themes](#theme-gallery) · [Troubleshooting](#troubleshooting) · [Comparison](#comparison) · [Not a Fit?](#when-usage-isnt-the-right-fit) · [Development](#development)
|
|
41
41
|
|
|
42
42
|
## What You Get
|
|
43
43
|
|
|
@@ -56,7 +56,7 @@ It lands in your Applications folder automatically. Open it once; if macOS 15 or
|
|
|
56
56
|
|
|
57
57
|
- **Progress Concierge:** Open a new Claude Code session and `usage` hands your last progress straight to the AI, including your last request, uncommitted changes, and unfinished todos. No `/resume`, no recap. When you do `/resume` a conversation that sat long enough for its cache to expire, it warns you how many tokens the next message will re-send and suggests `/compact` first. Off by default.
|
|
58
58
|
- **Token Saver:** A menu-bar toggle asks Claude Code and Codex to answer more tersely and in plainer language, saving output tokens while keeping code and error messages byte-exact. A light reminder keeps long conversations from drifting back to verbose — in an A/B test on real sessions, late replies stayed ~40% shorter instead of drifting 84% longer.
|
|
59
|
-
- **Claude Code side pane (macOS):**
|
|
59
|
+
- **Claude Code side pane (macOS and Windows):** Quotas, conversations, and background jobs inside Claude Code. [See the side pane](#claude-code-side-pane).
|
|
60
60
|
- **Auto-start 5-hour Session:** Off by default. Turn it on and, right after a 5-hour quota resets, `usage` sends one tiny message to each tool (Claude with Haiku, Antigravity with Gemini 3.5 Flash Low, Codex with its cheapest model) so the next 5-hour window starts counting right away. Those messages do use a little quota, but the amount is negligible. Checking your quota never sends a message; only this switch does.
|
|
61
61
|
- **Terminal Integration:** `usage status --json` hands your Claude Code, Codex, Antigravity, and Grok quota to any tool that can run a command — Starship, tmux, or your own scripts. Reads the same local files as the menu bar. [Ready-made snippets](docs/DEVELOPMENT.md#quota-status-for-other-tools-usage-status).
|
|
62
62
|
- **Token-waste Health Check:** A daily background diagnosis scans your logs for waste, including repeated file reads, polluter directories, and noisy Bash output. If it finds issues, a one-line heads-up appears; say "show me" and the AI walks you through fixes.
|
|
@@ -127,6 +127,34 @@ Once set up, the bottom of the Claude Code window will show a status line like t
|
|
|
127
127
|
<img src="docs/statusline.en.gif" alt="Claude Code statusLine display (English)" width="900">
|
|
128
128
|
</p>
|
|
129
129
|
|
|
130
|
+
## Claude Code Side Pane
|
|
131
|
+
|
|
132
|
+
See your quota, other conversations, and background jobs without leaving Claude Code. Available on macOS and Windows.
|
|
133
|
+
|
|
134
|
+
<p align="center"><img src="docs/side-pane.png" alt="Claude Code side pane showing quotas, conversations, and background jobs" width="637"></p>
|
|
135
|
+
|
|
136
|
+
**What you’ll see**
|
|
137
|
+
|
|
138
|
+
- **Quotas:** Your 5-hour and weekly limits.
|
|
139
|
+
- **Claude conversations:** Conversations waiting for your permission or MCP input are marked in yellow.
|
|
140
|
+
- **Background jobs:** Includes subagents started by Claude with the Agent tool and their status.
|
|
141
|
+
|
|
142
|
+
**How to enable**
|
|
143
|
+
|
|
144
|
+
1. In the usage menu bar menu (macOS) or the system-tray panel menu (Windows), check **Claude Code side pane**.
|
|
145
|
+
2. Open a new conversation or run `/reload-plugins`.
|
|
146
|
+
3. At terminal widths ≥144 columns, the pane opens on the right automatically. In narrower terminals, enter `/usage-dash`.
|
|
147
|
+
|
|
148
|
+
<details>
|
|
149
|
+
<summary>Compatibility and updates</summary>
|
|
150
|
+
|
|
151
|
+
- Requires a recent Claude Code with mod support; tested with 2.1.289.
|
|
152
|
+
- The pane docks on the right only in Claude Code's fullscreen layout; otherwise it appears above the prompt. On Windows, enabling the pane turns the fullscreen layout on as well, and turning the pane off switches it back.
|
|
153
|
+
- The built-in macOS Terminal supports only 256 colors and may show a gray background. Select an ANSI dark theme in `/config`.
|
|
154
|
+
- When the usage app starts, it automatically updates an enabled pane to the bundled version.
|
|
155
|
+
|
|
156
|
+
</details>
|
|
157
|
+
|
|
130
158
|
## Windows Support
|
|
131
159
|
|
|
132
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.
|
|
@@ -471,6 +471,7 @@
|
|
|
471
471
|
"claude_pane_menu": "Claude Code 側邊面板",
|
|
472
472
|
"claude_pane_tooltip": "在 Claude Code 顯示額度、對話與背景工作",
|
|
473
473
|
"claude_pane_enabled_msg": "已開啟側邊面板。開新的 Claude Code 對話(或在對話裡打 /reload-plugins)後生效;終端機寬度不夠時打 /usage-dash 叫出面板。",
|
|
474
|
+
"claude_pane_fullscreen_enabled_note": "已一併開啟 Claude Code 的全螢幕介面,讓面板顯示在右側。取消勾選側邊面板時會改回。",
|
|
474
475
|
"claude_pane_disabled_msg": "已移除 Claude Code 側邊面板。",
|
|
475
476
|
"claude_pane_action_failed": "Claude Code 側邊面板切換失敗。",
|
|
476
477
|
"claude_pane_source_missing": "找不到面板原始碼。已檢查:{tried}",
|
|
@@ -952,6 +953,7 @@
|
|
|
952
953
|
"claude_pane_menu": "Claude Code side pane",
|
|
953
954
|
"claude_pane_tooltip": "Show quotas, Claude sessions and background jobs in Claude Code",
|
|
954
955
|
"claude_pane_enabled_msg": "Pane enabled. Open a new Claude Code conversation (or run /reload-plugins in a conversation). If the terminal is too narrow, run /usage-dash to open the pane.",
|
|
956
|
+
"claude_pane_fullscreen_enabled_note": "Claude Code's fullscreen layout is now on so the pane can sit on the right. Turning the side pane off switches it back.",
|
|
955
957
|
"claude_pane_disabled_msg": "Claude Code side pane removed.",
|
|
956
958
|
"claude_pane_action_failed": "Could not change the Claude Code side pane.",
|
|
957
959
|
"claude_pane_source_missing": "Pane source not found. Tried: {tried}",
|
|
@@ -1433,6 +1435,7 @@
|
|
|
1433
1435
|
"claude_pane_menu": "Claude Code 侧边面板",
|
|
1434
1436
|
"claude_pane_tooltip": "在 Claude Code 显示额度、对话与后台任务",
|
|
1435
1437
|
"claude_pane_enabled_msg": "已开启侧边面板。打开新的 Claude Code 对话(或在对话里输入 /reload-plugins)后生效;终端宽度不够时输入 /usage-dash 打开面板。",
|
|
1438
|
+
"claude_pane_fullscreen_enabled_note": "已一并开启 Claude Code 的全屏界面,让面板显示在右侧。取消勾选侧边面板时会改回。",
|
|
1436
1439
|
"claude_pane_disabled_msg": "已移除 Claude Code 侧边面板。",
|
|
1437
1440
|
"claude_pane_action_failed": "Claude Code 侧边面板切换失败。",
|
|
1438
1441
|
"claude_pane_source_missing": "找不到面板源代码。已检查:{tried}",
|
|
@@ -1914,6 +1917,7 @@
|
|
|
1914
1917
|
"claude_pane_menu": "Claude Code サイドパネル",
|
|
1915
1918
|
"claude_pane_tooltip": "Claude Code に使用量、セッション、バックグラウンド作業を表示",
|
|
1916
1919
|
"claude_pane_enabled_msg": "サイドパネルを有効にしました。新しい Claude Code セッションを開くか、会話で /reload-plugins を実行してください。ターミナルの幅が足りない場合は /usage-dash で開けます。",
|
|
1920
|
+
"claude_pane_fullscreen_enabled_note": "Claude Code のフルスクリーンレイアウトを有効にし、パネルを右側に表示できるようにしました。サイドパネルをオフにすると元に戻ります。",
|
|
1917
1921
|
"claude_pane_disabled_msg": "Claude Code サイドパネルを削除しました。",
|
|
1918
1922
|
"claude_pane_action_failed": "Claude Code サイドパネルを切り替えられませんでした。",
|
|
1919
1923
|
"claude_pane_source_missing": "パネルのソースがありません。確認先: {tried}",
|
|
@@ -2395,6 +2399,7 @@
|
|
|
2395
2399
|
"claude_pane_menu": "Claude Code 사이드 패널",
|
|
2396
2400
|
"claude_pane_tooltip": "Claude Code에 사용량, 대화 및 백그라운드 작업 표시",
|
|
2397
2401
|
"claude_pane_enabled_msg": "사이드 패널을 켰습니다. 새 Claude Code 대화를 열거나 대화에서 /reload-plugins를 실행하세요. 터미널이 좁으면 /usage-dash로 패널을 여세요.",
|
|
2402
|
+
"claude_pane_fullscreen_enabled_note": "Claude Code의 전체 화면 레이아웃도 켜서 패널이 오른쪽에 표시됩니다. 사이드 패널을 끄면 원래대로 돌아갑니다.",
|
|
2398
2403
|
"claude_pane_disabled_msg": "Claude Code 사이드 패널을 제거했습니다.",
|
|
2399
2404
|
"claude_pane_action_failed": "Claude Code 사이드 패널을 전환하지 못했습니다.",
|
|
2400
2405
|
"claude_pane_source_missing": "패널 소스를 찾을 수 없습니다. 확인한 경로: {tried}",
|
|
@@ -45,6 +45,8 @@ def _resolve_source() -> Path:
|
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
def _status_argv() -> list[str]:
|
|
48
|
+
if getattr(sys, "frozen", False) and sys.platform == "win32":
|
|
49
|
+
return [sys.executable, "status", "--json"]
|
|
48
50
|
if getattr(sys, "frozen", False):
|
|
49
51
|
resources = str(Path(sys.executable).resolve().parent.parent / "Resources")
|
|
50
52
|
major, minor = sys.version_info[:2]
|
|
@@ -142,9 +144,25 @@ def enable_claude_pane() -> int:
|
|
|
142
144
|
return 0
|
|
143
145
|
|
|
144
146
|
|
|
147
|
+
def is_fullscreen_layout() -> bool:
|
|
148
|
+
return setup_hook._load_settings().get("tui") == "fullscreen"
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def enable_fullscreen_layout() -> None:
|
|
152
|
+
settings = setup_hook._load_settings()
|
|
153
|
+
settings["tui"] = "fullscreen"
|
|
154
|
+
usage = settings.get("usage")
|
|
155
|
+
if not isinstance(usage, dict):
|
|
156
|
+
usage = {}
|
|
157
|
+
settings["usage"] = usage
|
|
158
|
+
usage["claudePaneSetFullscreen"] = True
|
|
159
|
+
setup_hook._save_settings(settings)
|
|
160
|
+
|
|
161
|
+
|
|
145
162
|
def disable_claude_pane() -> int:
|
|
146
163
|
settings = setup_hook._load_settings()
|
|
147
164
|
env = _env(settings)
|
|
165
|
+
changed = False
|
|
148
166
|
if PLUGIN_DIRS_KEY in env:
|
|
149
167
|
value = _remove_path(env[PLUGIN_DIRS_KEY], str(INSTALL_DIR.absolute()))
|
|
150
168
|
if value:
|
|
@@ -153,6 +171,16 @@ def disable_claude_pane() -> int:
|
|
|
153
171
|
env.pop(PLUGIN_DIRS_KEY)
|
|
154
172
|
if not env:
|
|
155
173
|
settings.pop("env", None)
|
|
174
|
+
changed = True
|
|
175
|
+
usage = settings.get("usage")
|
|
176
|
+
if isinstance(usage, dict) and usage.get("claudePaneSetFullscreen") is True:
|
|
177
|
+
if settings.get("tui") == "fullscreen":
|
|
178
|
+
settings.pop("tui")
|
|
179
|
+
usage.pop("claudePaneSetFullscreen")
|
|
180
|
+
if not usage:
|
|
181
|
+
settings.pop("usage")
|
|
182
|
+
changed = True
|
|
183
|
+
if changed:
|
|
156
184
|
setup_hook._save_settings(settings)
|
|
157
185
|
if INSTALL_DIR.exists():
|
|
158
186
|
shutil.rmtree(INSTALL_DIR)
|
|
@@ -314,6 +314,11 @@ async def run_tui(mock: bool, interval: int, force_group: int | None = None) ->
|
|
|
314
314
|
|
|
315
315
|
|
|
316
316
|
def main() -> None:
|
|
317
|
+
if sys.argv[1:2] == ["status"]:
|
|
318
|
+
import usage_cli
|
|
319
|
+
|
|
320
|
+
usage_cli.main()
|
|
321
|
+
return
|
|
317
322
|
_setup_logging()
|
|
318
323
|
args = parse_args()
|
|
319
324
|
if args.doctor:
|
|
@@ -82,6 +82,50 @@ def test_disable_only_ours(isolated: Path, others: bool, keep_env: bool) -> None
|
|
|
82
82
|
assert not pane.is_claude_pane_enabled()
|
|
83
83
|
|
|
84
84
|
|
|
85
|
+
def test_enable_fullscreen_layout_records_usage_flag(isolated: Path) -> None:
|
|
86
|
+
setup_hook._save_settings({"usage": {"other": "keep"}, "other": "keep"})
|
|
87
|
+
|
|
88
|
+
pane.enable_fullscreen_layout()
|
|
89
|
+
|
|
90
|
+
assert setup_hook._load_settings() == {
|
|
91
|
+
"tui": "fullscreen",
|
|
92
|
+
"usage": {"other": "keep", "claudePaneSetFullscreen": True},
|
|
93
|
+
"other": "keep",
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def test_disable_restores_fullscreen_layout_set_by_pane(isolated: Path) -> None:
|
|
98
|
+
pane.INSTALL_DIR.mkdir(parents=True)
|
|
99
|
+
setup_hook._save_settings(
|
|
100
|
+
{
|
|
101
|
+
"tui": "fullscreen",
|
|
102
|
+
"usage": {"claudePaneSetFullscreen": True, "other": "keep"},
|
|
103
|
+
}
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
assert pane.disable_claude_pane() == 0
|
|
107
|
+
|
|
108
|
+
assert setup_hook._load_settings() == {"usage": {"other": "keep"}}
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def test_disable_keeps_user_fullscreen_layout(isolated: Path) -> None:
|
|
112
|
+
pane.INSTALL_DIR.mkdir(parents=True)
|
|
113
|
+
setup_hook._save_settings({"tui": "fullscreen"})
|
|
114
|
+
|
|
115
|
+
assert pane.disable_claude_pane() == 0
|
|
116
|
+
|
|
117
|
+
assert setup_hook._load_settings() == {"tui": "fullscreen"}
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def test_disable_keeps_changed_tui_when_pane_flagged(isolated: Path) -> None:
|
|
121
|
+
pane.INSTALL_DIR.mkdir(parents=True)
|
|
122
|
+
setup_hook._save_settings({"tui": "compact", "usage": {"claudePaneSetFullscreen": True}})
|
|
123
|
+
|
|
124
|
+
assert pane.disable_claude_pane() == 0
|
|
125
|
+
|
|
126
|
+
assert setup_hook._load_settings() == {"tui": "compact"}
|
|
127
|
+
|
|
128
|
+
|
|
85
129
|
def test_tilde_disable_and_reinstall(isolated: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
86
130
|
monkeypatch.setenv("HOME", str(pane.INSTALL_DIR.parent))
|
|
87
131
|
monkeypatch.setenv("USERPROFILE", str(pane.INSTALL_DIR.parent))
|
|
@@ -222,6 +266,15 @@ def test_uses_platform_separator(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
|
222
266
|
assert pane._remove_path("/other;/pane/", "/pane") == "/other"
|
|
223
267
|
|
|
224
268
|
|
|
269
|
+
def test_status_argv_uses_windows_frozen_executable(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
270
|
+
executable = r"C:\\Program Files\\usage\\usage.exe"
|
|
271
|
+
monkeypatch.setattr(sys, "frozen", True, raising=False)
|
|
272
|
+
monkeypatch.setattr(sys, "platform", "win32")
|
|
273
|
+
monkeypatch.setattr(sys, "executable", executable)
|
|
274
|
+
|
|
275
|
+
assert pane._status_argv() == [executable, "status", "--json"]
|
|
276
|
+
|
|
277
|
+
|
|
225
278
|
def test_missing_sidecar_language_falls_back(
|
|
226
279
|
isolated: Path, monkeypatch: pytest.MonkeyPatch
|
|
227
280
|
) -> None:
|
|
@@ -70,6 +70,19 @@ def test_parse_args_setup(monkeypatch: Any) -> None:
|
|
|
70
70
|
assert args.setup is True
|
|
71
71
|
|
|
72
72
|
|
|
73
|
+
def test_main_delegates_status_before_logging(monkeypatch: Any) -> None:
|
|
74
|
+
import usage_cli
|
|
75
|
+
|
|
76
|
+
calls: list[str] = []
|
|
77
|
+
monkeypatch.setattr(sys, "argv", ["usage", "status", "--json"])
|
|
78
|
+
monkeypatch.setattr(main, "_setup_logging", lambda: calls.append("logging"))
|
|
79
|
+
monkeypatch.setattr(usage_cli, "main", lambda: calls.append("status"))
|
|
80
|
+
|
|
81
|
+
main.main()
|
|
82
|
+
|
|
83
|
+
assert calls == ["status"]
|
|
84
|
+
|
|
85
|
+
|
|
73
86
|
def test_apply_outcome_success_updates_snapshot_and_clears_fatal_message() -> None:
|
|
74
87
|
state = AppViewState(fatal_message="boom")
|
|
75
88
|
snapshot = _snapshot()
|
|
@@ -22,6 +22,7 @@ import panels
|
|
|
22
22
|
import prefs
|
|
23
23
|
import service_status
|
|
24
24
|
from i18n import _t
|
|
25
|
+
from installer import claude_pane
|
|
25
26
|
from loaders import codex_loader
|
|
26
27
|
from loaders.agy_quota_probe import AgyQuotaGroup, AgyQuotaResult, AgyQuotaWindow
|
|
27
28
|
from menubar import agy as menubar_agy
|
|
@@ -1534,6 +1535,7 @@ def test_panel_menu_data_is_localized_and_reads_current_checks(
|
|
|
1534
1535
|
monkeypatch.setattr(wintray, "_window_keeper_enabled", lambda: True)
|
|
1535
1536
|
monkeypatch.setattr(wintray, "_session_resume_enabled", lambda: True)
|
|
1536
1537
|
monkeypatch.setattr(wintray, "_terse_mode_enabled", lambda: False)
|
|
1538
|
+
monkeypatch.setattr(wintray, "_claude_pane_enabled", lambda: True)
|
|
1537
1539
|
|
|
1538
1540
|
menu = controller._panel_menu_data()
|
|
1539
1541
|
|
|
@@ -1553,6 +1555,7 @@ def test_panel_menu_data_is_localized_and_reads_current_checks(
|
|
|
1553
1555
|
"window_keeper_menu",
|
|
1554
1556
|
"project_butler",
|
|
1555
1557
|
"terse_mode_menu",
|
|
1558
|
+
"claude_pane_menu",
|
|
1556
1559
|
"separator",
|
|
1557
1560
|
"check_update",
|
|
1558
1561
|
]
|
|
@@ -1566,6 +1569,7 @@ def test_panel_menu_data_is_localized_and_reads_current_checks(
|
|
|
1566
1569
|
assert menu[7]["checked"] is True
|
|
1567
1570
|
assert menu[8]["checked"] is True
|
|
1568
1571
|
assert menu[9]["checked"] is False
|
|
1572
|
+
assert menu[10]["checked"] is True
|
|
1569
1573
|
|
|
1570
1574
|
|
|
1571
1575
|
def test_panel_and_tray_menus_render_the_shared_model(
|
|
@@ -1683,6 +1687,7 @@ def test_tray_quit_label_removes_the_power_glyph() -> None:
|
|
|
1683
1687
|
({"action": "toggle_window_keeper"}, "toggle_window_keeper", ()),
|
|
1684
1688
|
({"action": "toggle_session_resume"}, "toggle_session_resume", ()),
|
|
1685
1689
|
({"action": "toggle_terse_mode"}, "toggle_terse_mode", ()),
|
|
1690
|
+
({"action": "toggle_claude_pane"}, "toggle_claude_pane", ()),
|
|
1686
1691
|
({"action": "check_update"}, "check_update", ()),
|
|
1687
1692
|
({"action": "quit"}, "quit", ()),
|
|
1688
1693
|
],
|
|
@@ -1930,6 +1935,7 @@ def test_attach_schedules_startup_maintenance_after_tray_is_visible(
|
|
|
1930
1935
|
"wintray.app.usage_diagnosis_snapshot.maybe_schedule_refresh",
|
|
1931
1936
|
lambda: events.append("diagnosis"),
|
|
1932
1937
|
)
|
|
1938
|
+
monkeypatch.setattr(claude_pane, "refresh_claude_pane", lambda: events.append("claude-pane"))
|
|
1933
1939
|
monkeypatch.setattr(
|
|
1934
1940
|
controller,
|
|
1935
1941
|
"_clear_stale_update_cache",
|
|
@@ -1951,7 +1957,8 @@ def test_attach_schedules_startup_maintenance_after_tray_is_visible(
|
|
|
1951
1957
|
]
|
|
1952
1958
|
startup = next(thread for thread in threads if thread.target == controller._startup_maintenance)
|
|
1953
1959
|
startup.target(**startup.kwargs)
|
|
1954
|
-
assert events[-
|
|
1960
|
+
assert events[-4:] == [
|
|
1961
|
+
"claude-pane",
|
|
1955
1962
|
"diagnosis",
|
|
1956
1963
|
"clear-update-cache",
|
|
1957
1964
|
(
|
|
@@ -1961,6 +1968,86 @@ def test_attach_schedules_startup_maintenance_after_tray_is_visible(
|
|
|
1961
1968
|
]
|
|
1962
1969
|
|
|
1963
1970
|
|
|
1971
|
+
def test_claude_pane_menu_check_and_toggle_results(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
1972
|
+
controller = wintray._WindowsTrayController(mock=True, interval=60)
|
|
1973
|
+
controller.language = "en"
|
|
1974
|
+
entry = wintray_menu.MenuCommand(
|
|
1975
|
+
"claude_pane_menu", "toggle_claude_pane", checked_by="claude_pane"
|
|
1976
|
+
)
|
|
1977
|
+
messages: list[str] = []
|
|
1978
|
+
monkeypatch.setattr(claude_pane, "is_claude_pane_enabled", lambda: False)
|
|
1979
|
+
monkeypatch.setattr(claude_pane, "enable_claude_pane", lambda: 0)
|
|
1980
|
+
monkeypatch.setattr(claude_pane, "is_fullscreen_layout", lambda: True)
|
|
1981
|
+
monkeypatch.setattr(controller, "_message_box", messages.append)
|
|
1982
|
+
|
|
1983
|
+
assert wintray._menu_checked(controller, entry) is False
|
|
1984
|
+
controller._toggle_claude_pane_in_background()
|
|
1985
|
+
|
|
1986
|
+
assert messages == [_t("en", "claude_pane_enabled_msg")]
|
|
1987
|
+
|
|
1988
|
+
|
|
1989
|
+
def test_claude_pane_toggle_enables_fullscreen_and_reports_note(
|
|
1990
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
1991
|
+
) -> None:
|
|
1992
|
+
controller = wintray._WindowsTrayController(mock=True, interval=60)
|
|
1993
|
+
controller.language = "en"
|
|
1994
|
+
messages: list[str] = []
|
|
1995
|
+
calls: list[str] = []
|
|
1996
|
+
monkeypatch.setattr(claude_pane, "is_claude_pane_enabled", lambda: False)
|
|
1997
|
+
monkeypatch.setattr(claude_pane, "enable_claude_pane", lambda: 0)
|
|
1998
|
+
monkeypatch.setattr(claude_pane, "is_fullscreen_layout", lambda: False)
|
|
1999
|
+
monkeypatch.setattr(claude_pane, "enable_fullscreen_layout", lambda: calls.append("fullscreen"))
|
|
2000
|
+
|
|
2001
|
+
monkeypatch.setattr(controller, "_message_box", messages.append)
|
|
2002
|
+
|
|
2003
|
+
controller._toggle_claude_pane_in_background()
|
|
2004
|
+
|
|
2005
|
+
assert calls == ["fullscreen"]
|
|
2006
|
+
assert messages == [
|
|
2007
|
+
f"{_t('en', 'claude_pane_enabled_msg')}\n\n"
|
|
2008
|
+
f"{_t('en', 'claude_pane_fullscreen_enabled_note')}"
|
|
2009
|
+
]
|
|
2010
|
+
|
|
2011
|
+
|
|
2012
|
+
def test_claude_pane_toggle_fullscreen_failure_reports_error(
|
|
2013
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
2014
|
+
) -> None:
|
|
2015
|
+
controller = wintray._WindowsTrayController(mock=True, interval=60)
|
|
2016
|
+
controller.language = "en"
|
|
2017
|
+
messages: list[str] = []
|
|
2018
|
+
monkeypatch.setattr(claude_pane, "is_claude_pane_enabled", lambda: False)
|
|
2019
|
+
monkeypatch.setattr(claude_pane, "enable_claude_pane", lambda: 0)
|
|
2020
|
+
monkeypatch.setattr(claude_pane, "is_fullscreen_layout", lambda: False)
|
|
2021
|
+
|
|
2022
|
+
def fail() -> None:
|
|
2023
|
+
raise OSError("fullscreen failure")
|
|
2024
|
+
|
|
2025
|
+
monkeypatch.setattr(claude_pane, "enable_fullscreen_layout", fail)
|
|
2026
|
+
monkeypatch.setattr(controller, "_message_box", messages.append)
|
|
2027
|
+
|
|
2028
|
+
controller._toggle_claude_pane_in_background()
|
|
2029
|
+
|
|
2030
|
+
assert messages == [f"{_t('en', 'claude_pane_action_failed')}\n\nfullscreen failure"]
|
|
2031
|
+
|
|
2032
|
+
|
|
2033
|
+
def test_claude_pane_toggle_failure_reports_output(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
2034
|
+
controller = wintray._WindowsTrayController(mock=True, interval=60)
|
|
2035
|
+
controller.language = "en"
|
|
2036
|
+
messages: list[str] = []
|
|
2037
|
+
monkeypatch.setattr(claude_pane, "is_claude_pane_enabled", lambda: False)
|
|
2038
|
+
|
|
2039
|
+
def fail() -> int:
|
|
2040
|
+
print("pane failure")
|
|
2041
|
+
return 1
|
|
2042
|
+
|
|
2043
|
+
monkeypatch.setattr(claude_pane, "enable_claude_pane", fail)
|
|
2044
|
+
monkeypatch.setattr(controller, "_message_box", messages.append)
|
|
2045
|
+
|
|
2046
|
+
controller._toggle_claude_pane_in_background()
|
|
2047
|
+
|
|
2048
|
+
assert messages == [f"{_t('en', 'claude_pane_action_failed')}\n\npane failure"]
|
|
2049
|
+
|
|
2050
|
+
|
|
1964
2051
|
def test_refresh_requested_while_busy_runs_once_after_current_refresh(
|
|
1965
2052
|
monkeypatch: pytest.MonkeyPatch,
|
|
1966
2053
|
) -> None:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: usage-cli
|
|
3
|
-
Version: 0.32.
|
|
3
|
+
Version: 0.32.1
|
|
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
|
|
@@ -57,7 +57,7 @@ It lands in your Applications folder automatically. Open it once; if macOS 15 or
|
|
|
57
57
|
|
|
58
58
|
**Not on macOS?** `uvx usage-cli` runs the terminal interface anywhere, Linux included — no install, no menu bar.
|
|
59
59
|
|
|
60
|
-
**Jump to:** [What You Get](#what-you-get) · [Privacy](#privacy--data-sources) · [Requirements](#requirements) · [Install](#install) · [Status Line](#first-launch-set-up-the-status-line) · [Windows](#windows-support) · [Themes](#theme-gallery) · [Troubleshooting](#troubleshooting) · [Comparison](#comparison) · [Not a Fit?](#when-usage-isnt-the-right-fit) · [Development](#development)
|
|
60
|
+
**Jump to:** [What You Get](#what-you-get) · [Privacy](#privacy--data-sources) · [Requirements](#requirements) · [Install](#install) · [Status Line](#first-launch-set-up-the-status-line) · [Claude Code Side Pane](#claude-code-side-pane) · [Windows](#windows-support) · [Themes](#theme-gallery) · [Troubleshooting](#troubleshooting) · [Comparison](#comparison) · [Not a Fit?](#when-usage-isnt-the-right-fit) · [Development](#development)
|
|
61
61
|
|
|
62
62
|
## What You Get
|
|
63
63
|
|
|
@@ -76,7 +76,7 @@ It lands in your Applications folder automatically. Open it once; if macOS 15 or
|
|
|
76
76
|
|
|
77
77
|
- **Progress Concierge:** Open a new Claude Code session and `usage` hands your last progress straight to the AI, including your last request, uncommitted changes, and unfinished todos. No `/resume`, no recap. When you do `/resume` a conversation that sat long enough for its cache to expire, it warns you how many tokens the next message will re-send and suggests `/compact` first. Off by default.
|
|
78
78
|
- **Token Saver:** A menu-bar toggle asks Claude Code and Codex to answer more tersely and in plainer language, saving output tokens while keeping code and error messages byte-exact. A light reminder keeps long conversations from drifting back to verbose — in an A/B test on real sessions, late replies stayed ~40% shorter instead of drifting 84% longer.
|
|
79
|
-
- **Claude Code side pane (macOS):**
|
|
79
|
+
- **Claude Code side pane (macOS and Windows):** Quotas, conversations, and background jobs inside Claude Code. [See the side pane](#claude-code-side-pane).
|
|
80
80
|
- **Auto-start 5-hour Session:** Off by default. Turn it on and, right after a 5-hour quota resets, `usage` sends one tiny message to each tool (Claude with Haiku, Antigravity with Gemini 3.5 Flash Low, Codex with its cheapest model) so the next 5-hour window starts counting right away. Those messages do use a little quota, but the amount is negligible. Checking your quota never sends a message; only this switch does.
|
|
81
81
|
- **Terminal Integration:** `usage status --json` hands your Claude Code, Codex, Antigravity, and Grok quota to any tool that can run a command — Starship, tmux, or your own scripts. Reads the same local files as the menu bar. [Ready-made snippets](docs/DEVELOPMENT.md#quota-status-for-other-tools-usage-status).
|
|
82
82
|
- **Token-waste Health Check:** A daily background diagnosis scans your logs for waste, including repeated file reads, polluter directories, and noisy Bash output. If it finds issues, a one-line heads-up appears; say "show me" and the AI walks you through fixes.
|
|
@@ -147,6 +147,34 @@ Once set up, the bottom of the Claude Code window will show a status line like t
|
|
|
147
147
|
<img src="docs/statusline.en.gif" alt="Claude Code statusLine display (English)" width="900">
|
|
148
148
|
</p>
|
|
149
149
|
|
|
150
|
+
## Claude Code Side Pane
|
|
151
|
+
|
|
152
|
+
See your quota, other conversations, and background jobs without leaving Claude Code. Available on macOS and Windows.
|
|
153
|
+
|
|
154
|
+
<p align="center"><img src="docs/side-pane.png" alt="Claude Code side pane showing quotas, conversations, and background jobs" width="637"></p>
|
|
155
|
+
|
|
156
|
+
**What you’ll see**
|
|
157
|
+
|
|
158
|
+
- **Quotas:** Your 5-hour and weekly limits.
|
|
159
|
+
- **Claude conversations:** Conversations waiting for your permission or MCP input are marked in yellow.
|
|
160
|
+
- **Background jobs:** Includes subagents started by Claude with the Agent tool and their status.
|
|
161
|
+
|
|
162
|
+
**How to enable**
|
|
163
|
+
|
|
164
|
+
1. In the usage menu bar menu (macOS) or the system-tray panel menu (Windows), check **Claude Code side pane**.
|
|
165
|
+
2. Open a new conversation or run `/reload-plugins`.
|
|
166
|
+
3. At terminal widths ≥144 columns, the pane opens on the right automatically. In narrower terminals, enter `/usage-dash`.
|
|
167
|
+
|
|
168
|
+
<details>
|
|
169
|
+
<summary>Compatibility and updates</summary>
|
|
170
|
+
|
|
171
|
+
- Requires a recent Claude Code with mod support; tested with 2.1.289.
|
|
172
|
+
- The pane docks on the right only in Claude Code's fullscreen layout; otherwise it appears above the prompt. On Windows, enabling the pane turns the fullscreen layout on as well, and turning the pane off switches it back.
|
|
173
|
+
- The built-in macOS Terminal supports only 256 colors and may show a gray background. Select an ANSI dark theme in `/config`.
|
|
174
|
+
- When the usage app starts, it automatically updates an enabled pane to the bundled version.
|
|
175
|
+
|
|
176
|
+
</details>
|
|
177
|
+
|
|
150
178
|
## Windows Support
|
|
151
179
|
|
|
152
180
|
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.
|
|
@@ -10,7 +10,7 @@ import sys
|
|
|
10
10
|
from collections.abc import Callable
|
|
11
11
|
from datetime import UTC, datetime
|
|
12
12
|
from pathlib import Path
|
|
13
|
-
from typing import Any
|
|
13
|
+
from typing import Any, cast
|
|
14
14
|
|
|
15
15
|
from loaders import agy_quota_probe, codex_loader, grok_quota_probe
|
|
16
16
|
from adapters import agy, claude, codex, grok, muse
|
|
@@ -483,6 +483,8 @@ def _run_status(args: list[str]) -> None:
|
|
|
483
483
|
|
|
484
484
|
payload = _status_payload(include_extra_agents="--json" in args)
|
|
485
485
|
if "--json" in args:
|
|
486
|
+
if sys.platform == "win32" and sys.stdout is not None:
|
|
487
|
+
cast(Any, sys.stdout).reconfigure(encoding="utf-8")
|
|
486
488
|
print(json.dumps(payload, ensure_ascii=False, separators=(",", ":")))
|
|
487
489
|
else:
|
|
488
490
|
print(_status_summary(payload))
|
|
@@ -864,6 +864,12 @@ class _WindowsTrayController:
|
|
|
864
864
|
self.refresh()
|
|
865
865
|
|
|
866
866
|
def _startup_maintenance(self) -> None:
|
|
867
|
+
from installer import claude_pane
|
|
868
|
+
|
|
869
|
+
try:
|
|
870
|
+
claude_pane.refresh_claude_pane()
|
|
871
|
+
except (OSError, SystemExit):
|
|
872
|
+
logger.warning("Claude Code pane refresh failed", exc_info=True)
|
|
867
873
|
usage_diagnosis_snapshot.maybe_schedule_refresh()
|
|
868
874
|
self._clear_stale_update_cache()
|
|
869
875
|
self._check_update_in_background(
|
|
@@ -1838,6 +1844,49 @@ class _WindowsTrayController:
|
|
|
1838
1844
|
if os.environ.get("USAGE_DEBUG") == "1":
|
|
1839
1845
|
logger.warning("toggle terse mode failed", exc_info=True)
|
|
1840
1846
|
|
|
1847
|
+
def toggle_claude_pane(self, _icon: Any = None, _item: Any = None) -> None:
|
|
1848
|
+
threading.Thread(target=self._toggle_claude_pane_in_background, daemon=True).start()
|
|
1849
|
+
|
|
1850
|
+
def _toggle_claude_pane_in_background(self) -> None:
|
|
1851
|
+
import contextlib
|
|
1852
|
+
import io
|
|
1853
|
+
|
|
1854
|
+
from installer import claude_pane
|
|
1855
|
+
|
|
1856
|
+
output = io.StringIO()
|
|
1857
|
+
ok = False
|
|
1858
|
+
enabled = False
|
|
1859
|
+
try:
|
|
1860
|
+
with contextlib.redirect_stdout(output), contextlib.redirect_stderr(output):
|
|
1861
|
+
enabled = not claude_pane.is_claude_pane_enabled()
|
|
1862
|
+
action = (
|
|
1863
|
+
claude_pane.enable_claude_pane if enabled else claude_pane.disable_claude_pane
|
|
1864
|
+
)
|
|
1865
|
+
ok = action() == 0
|
|
1866
|
+
except SystemExit as exc:
|
|
1867
|
+
print(exc.code, file=output)
|
|
1868
|
+
except Exception as exc:
|
|
1869
|
+
print(f"{type(exc).__name__}: {exc}", file=output)
|
|
1870
|
+
|
|
1871
|
+
if ok:
|
|
1872
|
+
if enabled and not claude_pane.is_fullscreen_layout():
|
|
1873
|
+
try:
|
|
1874
|
+
claude_pane.enable_fullscreen_layout()
|
|
1875
|
+
except (OSError, SystemExit) as exc:
|
|
1876
|
+
self._message_box(f"{_t(self.language, 'claude_pane_action_failed')}\n\n{exc}")
|
|
1877
|
+
else:
|
|
1878
|
+
self._message_box(
|
|
1879
|
+
f"{_t(self.language, 'claude_pane_enabled_msg')}\n\n"
|
|
1880
|
+
f"{_t(self.language, 'claude_pane_fullscreen_enabled_note')}"
|
|
1881
|
+
)
|
|
1882
|
+
else:
|
|
1883
|
+
key = "claude_pane_enabled_msg" if enabled else "claude_pane_disabled_msg"
|
|
1884
|
+
self._message_box(_t(self.language, key))
|
|
1885
|
+
else:
|
|
1886
|
+
self._message_box(
|
|
1887
|
+
f"{_t(self.language, 'claude_pane_action_failed')}\n\n{output.getvalue().strip()}"
|
|
1888
|
+
)
|
|
1889
|
+
|
|
1841
1890
|
def _process_quota_notifications(self, state: menubar_state.PopoverState) -> None:
|
|
1842
1891
|
try:
|
|
1843
1892
|
events = self._quota_notifier.update(
|
|
@@ -2120,6 +2169,8 @@ class _WindowsTrayController:
|
|
|
2120
2169
|
self.toggle_session_resume()
|
|
2121
2170
|
elif action == "toggle_terse_mode":
|
|
2122
2171
|
self.toggle_terse_mode()
|
|
2172
|
+
elif action == "toggle_claude_pane":
|
|
2173
|
+
self.toggle_claude_pane()
|
|
2123
2174
|
elif action == "check_update":
|
|
2124
2175
|
self.check_update()
|
|
2125
2176
|
elif action == "quit":
|
|
@@ -2221,6 +2272,7 @@ def _menu_checked(controller: _WindowsTrayController, entry: wintray_menu.MenuCo
|
|
|
2221
2272
|
"window_keeper": _window_keeper_enabled,
|
|
2222
2273
|
"session_resume": _session_resume_enabled,
|
|
2223
2274
|
"terse_mode": _terse_mode_enabled,
|
|
2275
|
+
"claude_pane": _claude_pane_enabled,
|
|
2224
2276
|
}
|
|
2225
2277
|
return checks[entry.checked_by]() if entry.checked_by is not None else False
|
|
2226
2278
|
|
|
@@ -2292,6 +2344,15 @@ def _terse_mode_enabled() -> bool:
|
|
|
2292
2344
|
return False
|
|
2293
2345
|
|
|
2294
2346
|
|
|
2347
|
+
def _claude_pane_enabled() -> bool:
|
|
2348
|
+
try:
|
|
2349
|
+
from installer import claude_pane
|
|
2350
|
+
|
|
2351
|
+
return claude_pane.is_claude_pane_enabled()
|
|
2352
|
+
except Exception:
|
|
2353
|
+
return False
|
|
2354
|
+
|
|
2355
|
+
|
|
2295
2356
|
_SINGLE_INSTANCE_MUTEX = "usage-windows-tray-single-instance"
|
|
2296
2357
|
_ERROR_ALREADY_EXISTS = 183
|
|
2297
2358
|
_single_instance_handle: int | None = None
|