usage-cli 0.34.4__tar.gz → 0.34.6__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.34.4/usage_cli.egg-info → usage_cli-0.34.6}/PKG-INFO +1 -1
- {usage_cli-0.34.4 → usage_cli-0.34.6}/analyzer/dispatch_ledger.py +113 -27
- {usage_cli-0.34.4 → usage_cli-0.34.6}/analyzer/reporter.py +13 -2
- {usage_cli-0.34.4 → usage_cli-0.34.6}/i18n.json +55 -75
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/muse_quota_probe.py +38 -1
- {usage_cli-0.34.4 → usage_cli-0.34.6}/pyproject.toml +1 -1
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_dispatch_ledger.py +244 -80
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_muse_quota_probe.py +56 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_report_cold_read.py +10 -19
- usage_cli-0.34.6/ui/report_ledger.py +102 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/ui/report_styles.py +4 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6/usage_cli.egg-info}/PKG-INFO +1 -1
- usage_cli-0.34.4/ui/report_ledger.py +0 -88
- {usage_cli-0.34.4 → usage_cli-0.34.6}/LICENSE +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/README.md +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/THIRD_PARTY_NOTICES.md +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/adapters/__init__.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/adapters/agy.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/adapters/claude.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/adapters/codex.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/adapters/grok.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/adapters/muse.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/adapters/rate_limits.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/adapters/registry.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/adapters/types.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/analyzer/__init__.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/analyzer/aggregator.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/analyzer/blocks.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/analyzer/diagnoser.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/analyzer/diagnosis_snapshot.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/analyzer/history_persist.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/analyzer/insights.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/analyzer/ledger_backfill.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/analyzer/persona_loader.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/analyzer/subscription.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/analyzer/usage_snapshot.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/installer/__init__.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/installer/claude_pane.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/installer/codex_hook_trust.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/installer/login_item.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/installer/session_hooks.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/installer/setup_hook.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/installer/statusline_settings.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/__init__.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/_shared_cache_file.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/agy_disk_cache.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/agy_loader.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/agy_quota_probe.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/cache_quarantine.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/chromium_cache.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/claude_desktop.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/claude_paths.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/claude_usage.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/codex_disk_cache.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/codex_events.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/codex_fork_replay.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/codex_loader.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/codex_paths.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/disk_cache_common.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/disk_cache_lifecycle.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/grok_loader.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/grok_quota_probe.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/history_disk_cache.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/history_loader.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/jsonl_limits.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/jsonl_utils.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/loaders/muse_loader.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/main.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/menubar/__init__.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/menubar/actions.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/menubar/agy.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/menubar/app.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/menubar/chrome.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/menubar/fsevents_watch.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/menubar/grok.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/menubar/manual_refresh.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/menubar/menu.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/menubar/muse.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/menubar/new_badge.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/menubar/notify.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/menubar/popover.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/menubar/prefs.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/menubar/refresh.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/menubar/state.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/menubar/title.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/menubar/update.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/menubar/whats_new.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/panels/__init__.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/panels/base.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/panels/catalog.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/panels/dynamic_height.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/panels/panel_scale.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/panels/panel_window.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/panels/panel_window_state.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/panels/payload.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/panels/web_panel.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/panels/window_drag.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/quota/__init__.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/quota/agy_window_keeper.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/quota/burn_rate.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/quota/codex_window_keeper.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/quota/keeper_outcome.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/quota/notifications.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/quota/quota_snapshot.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/quota/status_payload.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/quota/usage_rate.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/quota/window_keeper.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/setup.cfg +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/setup_app.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_adapters_claude.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_adapters_codex.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_adapters_rate_limits.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_aggregator.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_agy_adapter.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_agy_disk_cache.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_agy_loader.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_agy_quota_probe.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_agy_window_keeper.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_analyzer_blocks.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_analyzer_pipeline.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_app_version.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_burn_rate.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_cache_quarantine.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_check_upstream.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_chromium_cache.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_claude_desktop.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_claude_pane.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_claude_paths.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_codex_consistency.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_codex_hook_trust.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_codex_loader.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_codex_window_keeper.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_compact_cards.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_desktop_fresh_cache.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_desktop_quota_display.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_desktop_quota_review.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_diagnoser.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_disk_cache_shards.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_doctor.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_dynamic_height.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_fsevents_watch.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_grok_loader.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_grok_quota_probe.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_history_loader.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_history_persist.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_hook_scripts_are_standalone.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_html_report_snapshot.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_i18n_format_fallback.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_i18n_key_parity.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_i18n_packaged_path.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_insights.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_jsonl_utils.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_keeper_menu.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_keeper_outcome.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_ledger_backfill.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_login_item.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_main.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_manual_refresh.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_menubar.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_menubar_agy.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_menubar_grok.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_menubar_muse.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_menubar_notify.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_menubar_prefs.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_menubar_state.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_menubar_update.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_muse_coverage.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_muse_loader.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_muse_review_regressions.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_new_badge.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_packaged_resources.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_packaging.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_panel_footer_layout.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_panel_scale.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_panel_window_state.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_panels.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_panels_lazy_import.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_persona_loader.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_pricing.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_project_resolver.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_quota_aware.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_quota_label.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_report_daily_chart.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_report_filter_js.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_report_share_mask.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_reporter_build_data.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_service_status.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_session_resume.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_setup_app.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_setup_hook.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_setup_hook_coexistence.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_setup_hook_resume.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_setup_hook_terse.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_subprocess_utils.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_subscription.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_taskbar_menu.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_taskbar_obstacles.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_time_utils.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_tui.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_tui_sprite.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_ui_tables.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_update_checker.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_update_gate.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_update_release_notes.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_usage_cli.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_usage_client.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_usage_diagnosis_snapshot.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_usage_dir_sweeper.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_usage_lang.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_usage_logging.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_usage_notifications.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_usage_rate.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_usage_snapshot.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_usage_snapshot_replay.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_usage_statusline.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_usage_statusline_agy.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_usage_statusline_forwarder.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_usage_statusline_grok.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_usage_terse_mode.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_usage_terse_reminder.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_web_panel_payload.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_whats_new.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_wheel_packaging.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_win_login_item.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_window_keeper.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_windows_manifest.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tests/test_wintray.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tui/__init__.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tui/app.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/tui/sprite.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/ui/__init__.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/ui/html_report.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/ui/report_charts.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/ui/report_daily_chart.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/ui/report_filter.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/ui/report_scripts.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/ui/tables.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/updates/__init__.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/updates/checker.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/updates/gate.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/updates/release_notes.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/updates/whats_new.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_app/__init__.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_app/cli.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_app/doctor.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_cli.egg-info/SOURCES.txt +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_cli.egg-info/dependency_links.txt +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_cli.egg-info/entry_points.txt +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_cli.egg-info/requires.txt +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_cli.egg-info/top_level.txt +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_common/__init__.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_common/app_version.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_common/i18n.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_common/prefs.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_common/pricing.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_common/project_resolver.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_common/service_status.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_common/subprocess_utils.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_common/time_utils.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_common/usage_dir_sweeper.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_common/usage_lang.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_common/usage_logging.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_hooks/__init__.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_hooks/usage_quota_aware.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_hooks/usage_session_resume.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_hooks/usage_statusline.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_hooks/usage_statusline_agy.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_hooks/usage_statusline_forwarder.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_hooks/usage_statusline_grok.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_hooks/usage_terse_mode.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/usage_hooks/usage_terse_reminder.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/wintray/__init__.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/wintray/app.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/wintray/login_item.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/wintray/menu.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/wintray/prefs.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/wintray/quota_label.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/wintray/taskbar_menu.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/wintray/taskbar_obstacles.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/wintray/taskbar_overlay.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/wintray/watch.py +0 -0
- {usage_cli-0.34.4 → usage_cli-0.34.6}/wintray/whats_new.py +0 -0
|
@@ -18,6 +18,7 @@ from adapters import rate_limits
|
|
|
18
18
|
from adapters.types import UsageEntry
|
|
19
19
|
from loaders import agy_loader, agy_quota_probe, codex_loader, muse_quota_probe
|
|
20
20
|
from loaders.claude_paths import claude_config_dirs
|
|
21
|
+
from usage_common.project_resolver import resolve_project_name
|
|
21
22
|
|
|
22
23
|
_DISPATCH = {
|
|
23
24
|
"codex": re.compile(r"(^|[;&|(\s])codex exec"),
|
|
@@ -61,7 +62,10 @@ class LedgerRow(TypedDict):
|
|
|
61
62
|
dispatch_count: int
|
|
62
63
|
claude_pct: float | None
|
|
63
64
|
codex_pct: float | None
|
|
64
|
-
|
|
65
|
+
agy_groups: dict[str, float]
|
|
66
|
+
claude_reset: bool
|
|
67
|
+
codex_reset: bool
|
|
68
|
+
agy_reset: bool
|
|
65
69
|
total_pct: float
|
|
66
70
|
|
|
67
71
|
|
|
@@ -69,6 +73,52 @@ class LedgerData(TypedDict):
|
|
|
69
73
|
rows: list[LedgerRow]
|
|
70
74
|
unowned_codex: int
|
|
71
75
|
unowned_agy: int
|
|
76
|
+
used_pct: dict[str, float]
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class LedgerBlock(TypedDict):
|
|
80
|
+
quota: str
|
|
81
|
+
used_pct: float | None
|
|
82
|
+
conversations: list[tuple[LedgerRow, float]]
|
|
83
|
+
more_count: int
|
|
84
|
+
more_pct: float
|
|
85
|
+
other_pct: float | None
|
|
86
|
+
all_reset: bool
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def ledger_blocks(rows: list[LedgerRow], used_pct: dict[str, float]) -> list[LedgerBlock]:
|
|
90
|
+
"""Select each quota's top five from every owned conversation."""
|
|
91
|
+
shares: dict[str, list[tuple[LedgerRow, float]]] = defaultdict(list)
|
|
92
|
+
for row in rows:
|
|
93
|
+
if row["codex_pct"] is not None and row["codex_pct"] > 0:
|
|
94
|
+
shares["codex"].append((row, row["codex_pct"]))
|
|
95
|
+
for group, value in row["agy_groups"].items():
|
|
96
|
+
if value > 0:
|
|
97
|
+
shares[f"antigravity:{group}"].append((row, value))
|
|
98
|
+
if any(row["codex_reset"] for row in rows):
|
|
99
|
+
shares.setdefault("codex", [])
|
|
100
|
+
blocks: list[LedgerBlock] = []
|
|
101
|
+
for quota, conversations in shares.items():
|
|
102
|
+
conversations.sort(key=lambda item: item[1], reverse=True)
|
|
103
|
+
total = sum(value for _, value in conversations)
|
|
104
|
+
used = used_pct.get(quota)
|
|
105
|
+
other = max(0.0, used - total) if used is not None else None
|
|
106
|
+
blocks.append(
|
|
107
|
+
{
|
|
108
|
+
"quota": quota,
|
|
109
|
+
"used_pct": used,
|
|
110
|
+
"conversations": conversations[:5],
|
|
111
|
+
"more_count": len(conversations[5:]),
|
|
112
|
+
"more_pct": sum(value for _, value in conversations[5:]),
|
|
113
|
+
"other_pct": other if other is not None and other >= 0.5 else None,
|
|
114
|
+
"all_reset": quota == "codex" and not conversations,
|
|
115
|
+
}
|
|
116
|
+
)
|
|
117
|
+
blocks.sort(
|
|
118
|
+
key=lambda block: sum(value for _, value in block["conversations"]) + block["more_pct"],
|
|
119
|
+
reverse=True,
|
|
120
|
+
)
|
|
121
|
+
return blocks
|
|
72
122
|
|
|
73
123
|
|
|
74
124
|
def _timestamp(value: object) -> datetime | None:
|
|
@@ -319,11 +369,15 @@ def estimate_pct(
|
|
|
319
369
|
return session_tokens / total_tokens * window.used_pct
|
|
320
370
|
|
|
321
371
|
|
|
372
|
+
SessionGroup = tuple[str, str, str]
|
|
373
|
+
|
|
374
|
+
|
|
322
375
|
def estimate_sessions(
|
|
323
376
|
entries: list[UsageEntry], windows: dict[str, QuotaWindow], now: datetime
|
|
324
|
-
) -> dict[
|
|
377
|
+
) -> tuple[dict[SessionGroup, float], set[SessionGroup]]:
|
|
325
378
|
totals: dict[str, int] = defaultdict(int)
|
|
326
379
|
sessions: dict[tuple[str, str, str], int] = defaultdict(int)
|
|
380
|
+
before_window: set[SessionGroup] = set()
|
|
327
381
|
for entry in entries:
|
|
328
382
|
group = entry.agent_id
|
|
329
383
|
if entry.agent_id == "antigravity":
|
|
@@ -351,18 +405,21 @@ def estimate_sessions(
|
|
|
351
405
|
"",
|
|
352
406
|
)
|
|
353
407
|
window = windows.get(group)
|
|
354
|
-
if window is None or not window.resets_at - window.length <= entry.timestamp <= now:
|
|
355
|
-
continue
|
|
356
408
|
tokens = entry.input_tokens + entry.output_tokens + entry.cache_creation_tokens
|
|
409
|
+
if window is None or entry.timestamp > now or tokens <= 0:
|
|
410
|
+
continue
|
|
411
|
+
key = (entry.agent_id, entry.session_id, group)
|
|
412
|
+
if entry.timestamp < window.resets_at - window.length:
|
|
413
|
+
before_window.add(key)
|
|
414
|
+
continue
|
|
357
415
|
totals[group] += tokens
|
|
358
|
-
sessions[
|
|
359
|
-
estimates: dict[
|
|
416
|
+
sessions[key] += tokens
|
|
417
|
+
estimates: dict[SessionGroup, float] = {}
|
|
360
418
|
for (agent_id, session_id, group), tokens in sessions.items():
|
|
361
419
|
value = estimate_pct(tokens, totals[group], windows.get(group), now)
|
|
362
420
|
if value is not None:
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
return estimates
|
|
421
|
+
estimates[(agent_id, session_id, group)] = value
|
|
422
|
+
return estimates, before_window - sessions.keys()
|
|
366
423
|
|
|
367
424
|
|
|
368
425
|
def _session_title(path: Path) -> str:
|
|
@@ -392,13 +449,23 @@ def _session_title(path: Path) -> str:
|
|
|
392
449
|
return title or first_text
|
|
393
450
|
|
|
394
451
|
|
|
395
|
-
def build_ledger(
|
|
452
|
+
def build_ledger(
|
|
453
|
+
estimates: dict[SessionGroup, float],
|
|
454
|
+
now: datetime,
|
|
455
|
+
reset_sessions: set[SessionGroup] | None = None,
|
|
456
|
+
used_pct: dict[str, float] | None = None,
|
|
457
|
+
) -> LedgerData:
|
|
396
458
|
cutoff = now - timedelta(days=7)
|
|
397
459
|
paths = _claude_paths(cutoff)
|
|
398
460
|
dispatches = [
|
|
399
461
|
item for path in paths for item in _read_dispatches(path) if cutoff <= item.timestamp <= now
|
|
400
462
|
]
|
|
401
|
-
empty: LedgerData = {
|
|
463
|
+
empty: LedgerData = {
|
|
464
|
+
"rows": [],
|
|
465
|
+
"unowned_codex": 0,
|
|
466
|
+
"unowned_agy": 0,
|
|
467
|
+
"used_pct": used_pct or {},
|
|
468
|
+
}
|
|
402
469
|
if not dispatches:
|
|
403
470
|
return empty
|
|
404
471
|
known_sessions = {path.stem for path in paths}
|
|
@@ -426,32 +493,51 @@ def build_ledger(estimates: dict[tuple[str, str], float | None], now: datetime)
|
|
|
426
493
|
origin = by_owner.get(owner)
|
|
427
494
|
if not origin:
|
|
428
495
|
continue
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
496
|
+
claude_pct = estimates.get(("claude-code", owner, "claude-code"))
|
|
497
|
+
codex_values = [
|
|
498
|
+
estimates[("codex", child, "codex")]
|
|
499
|
+
for child in children["codex"]
|
|
500
|
+
if ("codex", child, "codex") in estimates
|
|
501
|
+
]
|
|
502
|
+
codex_pct = sum(codex_values) if codex_values else None
|
|
503
|
+
agy_groups: dict[str, float] = {}
|
|
504
|
+
for (agent, child, group), value in estimates.items():
|
|
505
|
+
if agent == "antigravity" and child in children[agent]:
|
|
506
|
+
name = group.removeprefix("antigravity:")
|
|
507
|
+
agy_groups[name] = agy_groups.get(name, 0.0) + value
|
|
508
|
+
reset_agents = {
|
|
509
|
+
agent
|
|
510
|
+
for agent, session, _ in reset_sessions or set()
|
|
511
|
+
if (agent == "claude-code" and session == owner)
|
|
512
|
+
or session in children.get(agent, set())
|
|
513
|
+
}
|
|
437
514
|
first = min(origin, key=lambda item: item.timestamp)
|
|
438
515
|
rows.append(
|
|
439
516
|
(
|
|
440
517
|
owner,
|
|
441
518
|
{
|
|
442
519
|
"date": first.timestamp.astimezone().strftime("%Y-%m-%d"),
|
|
443
|
-
"project":
|
|
520
|
+
"project": resolve_project_name(first.cwd),
|
|
444
521
|
"title": "",
|
|
445
522
|
"dispatch_count": len(origin),
|
|
446
|
-
"claude_pct":
|
|
447
|
-
"codex_pct":
|
|
448
|
-
"
|
|
449
|
-
"
|
|
523
|
+
"claude_pct": claude_pct,
|
|
524
|
+
"codex_pct": codex_pct,
|
|
525
|
+
"agy_groups": agy_groups,
|
|
526
|
+
"claude_reset": claude_pct is None and "claude-code" in reset_agents,
|
|
527
|
+
"codex_reset": codex_pct is None and "codex" in reset_agents,
|
|
528
|
+
"agy_reset": not agy_groups and "antigravity" in reset_agents,
|
|
529
|
+
"total_pct": (claude_pct or 0) + (codex_pct or 0) + sum(agy_groups.values()),
|
|
450
530
|
},
|
|
451
531
|
)
|
|
452
532
|
)
|
|
453
533
|
rows.sort(key=lambda item: item[1]["total_pct"], reverse=True)
|
|
454
|
-
for
|
|
455
|
-
|
|
456
|
-
|
|
534
|
+
empty["rows"] = [row for _, row in rows]
|
|
535
|
+
displayed = {
|
|
536
|
+
id(row)
|
|
537
|
+
for block in ledger_blocks(empty["rows"], empty["used_pct"])
|
|
538
|
+
for row, _ in block["conversations"]
|
|
539
|
+
}
|
|
540
|
+
for owner, row in rows:
|
|
541
|
+
if id(row) in displayed:
|
|
542
|
+
row["title"] = _session_title(path_by_session[owner])
|
|
457
543
|
return empty
|
|
@@ -1258,7 +1258,13 @@ def build_report_data(agents: list[AgentInfo], period: str = "month") -> ReportD
|
|
|
1258
1258
|
entry for entry in weekly_entries if not ledger_backfill.is_ledger_entry(entry)
|
|
1259
1259
|
]
|
|
1260
1260
|
windows = dispatch_ledger.load_windows() if weekly_entries else {}
|
|
1261
|
-
|
|
1261
|
+
group_estimates, reset_sessions = dispatch_ledger.estimate_sessions(
|
|
1262
|
+
weekly_entries, windows, now
|
|
1263
|
+
)
|
|
1264
|
+
estimates: dict[tuple[str, str], float] = {}
|
|
1265
|
+
for (agent_id, session_id, _), value in group_estimates.items():
|
|
1266
|
+
key = (agent_id, session_id)
|
|
1267
|
+
estimates[key] = estimates.get(key, 0.0) + value
|
|
1262
1268
|
sessions_by_cost = sorted(
|
|
1263
1269
|
aggregate_sessions(real_entries), key=lambda session: session.cost_usd, reverse=True
|
|
1264
1270
|
)
|
|
@@ -1322,7 +1328,12 @@ def build_report_data(agents: list[AgentInfo], period: str = "month") -> ReportD
|
|
|
1322
1328
|
"sessions": session_rows,
|
|
1323
1329
|
"daily_trend": daily_trend,
|
|
1324
1330
|
"top_sessions": top_sessions,
|
|
1325
|
-
"dispatch_ledger": dispatch_ledger.build_ledger(
|
|
1331
|
+
"dispatch_ledger": dispatch_ledger.build_ledger(
|
|
1332
|
+
group_estimates,
|
|
1333
|
+
now,
|
|
1334
|
+
reset_sessions,
|
|
1335
|
+
{key: window.used_pct for key, window in windows.items()},
|
|
1336
|
+
),
|
|
1326
1337
|
"comparison": comparison,
|
|
1327
1338
|
"subscriptions": subscription.load_subscriptions(),
|
|
1328
1339
|
"persona": _load_persona_for_period(period),
|
|
@@ -223,16 +223,7 @@
|
|
|
223
223
|
"report_cost": "API 等值",
|
|
224
224
|
"report_quota_share": "約佔週額度",
|
|
225
225
|
"report_quota_approx": "約 {value}%",
|
|
226
|
-
"report_ledger_section": "
|
|
227
|
-
"report_ledger_date": "日期",
|
|
228
|
-
"report_ledger_title": "對話標題",
|
|
229
|
-
"report_ledger_count": "派工次數",
|
|
230
|
-
"report_ledger_claude": "Claude 週額度",
|
|
231
|
-
"report_ledger_codex": "Codex 週額度",
|
|
232
|
-
"report_ledger_agy": "Antigravity 週額度",
|
|
233
|
-
"report_ledger_unowned_part": "{count} 個 {agent}",
|
|
234
|
-
"report_ledger_unowned_sep": "、",
|
|
235
|
-
"report_ledger_unowned": "另有 {items} 對話找不到由 Claude 派工的紀錄,未列入上表",
|
|
226
|
+
"report_ledger_section": "派工額度花在哪(最近 7 天)",
|
|
236
227
|
"report_daily_chart_title": "每日用量",
|
|
237
228
|
"report_daily_chart_mode_tokens": "Tokens",
|
|
238
229
|
"report_daily_chart_mode_cost": "API 等值",
|
|
@@ -320,9 +311,9 @@
|
|
|
320
311
|
"report_wrapped_top_project": "最常用專案",
|
|
321
312
|
"report_wrapped_books_equivalent": "≈ {books} 本書的字量",
|
|
322
313
|
"report_wrapped_beast_phoenix_title": "鳳凰加冕",
|
|
323
|
-
"report_wrapped_beast_phoenix_caption": "
|
|
314
|
+
"report_wrapped_beast_phoenix_caption": "近一年 Claude 的火力略勝一籌,像把灰燼一口氣吹回天空。",
|
|
324
315
|
"report_wrapped_beast_dragon_title": "巨龍加冕",
|
|
325
|
-
"report_wrapped_beast_dragon_caption": "
|
|
316
|
+
"report_wrapped_beast_dragon_caption": "近一年 Codex 的火力更猛,像一條龍一路把工地燒到完工。",
|
|
326
317
|
"project_butler": "接著上次做",
|
|
327
318
|
"project_butler_tooltip": "開新對話時,自動把上次的進度交給 AI,不用再重講一次。",
|
|
328
319
|
"terse_mode_menu": "省 token 模式",
|
|
@@ -552,14 +543,19 @@
|
|
|
552
543
|
"claude_desktop_updated": "Claude 桌面版 · {minutes} 分鐘前更新",
|
|
553
544
|
"claude_desktop_stale": "Claude 桌面版 · 資料過期 · {minutes} 分鐘前更新",
|
|
554
545
|
"report_project_others": "其他專案",
|
|
555
|
-
"
|
|
546
|
+
"report_ledger_lead": "Claude 派給 Codex、Antigravity 的工作,各吃掉多少週額度。",
|
|
556
547
|
"report_trend_partial_week": "僅 {days} 天",
|
|
557
548
|
"report_history_scope": "分工具紀錄從 {date} 起;更早的每日總量只在下方熱力圖",
|
|
558
549
|
"report_composition_missing": "另有 {tokens} tokens 沒有輸入/輸出拆解",
|
|
559
550
|
"report_wrapped_cost_scope": "只含有價格紀錄的日子({date} 起)",
|
|
560
551
|
"report_wrapped_cost_no_records": "沒有價格紀錄",
|
|
561
|
-
"report_wrapped_beast_phoenix_caption_dominant": "
|
|
562
|
-
"report_wrapped_beast_dragon_caption_dominant": "
|
|
552
|
+
"report_wrapped_beast_phoenix_caption_dominant": "近一年 Claude 的用量遙遙領先。",
|
|
553
|
+
"report_wrapped_beast_dragon_caption_dominant": "近一年 Codex 的用量遙遙領先。",
|
|
554
|
+
"report_ledger_used": "本週已用 {pct}%",
|
|
555
|
+
"report_ledger_row_meta": "{project} · 派工 {count} 次",
|
|
556
|
+
"report_ledger_more": "另外 {count} 段派工對話",
|
|
557
|
+
"report_ledger_other": "其他(你直接用的,或沒對到派工紀錄)",
|
|
558
|
+
"report_ledger_all_reset": "最近 7 天的派工都在額度重置前,算在上週。"
|
|
563
559
|
},
|
|
564
560
|
"en": {
|
|
565
561
|
"panel_default_name": "Default",
|
|
@@ -785,16 +781,7 @@
|
|
|
785
781
|
"report_cost": "API equivalent",
|
|
786
782
|
"report_quota_share": "Approx. weekly quota",
|
|
787
783
|
"report_quota_approx": "about {value}%",
|
|
788
|
-
"report_ledger_section": "
|
|
789
|
-
"report_ledger_date": "Date",
|
|
790
|
-
"report_ledger_title": "Conversation title",
|
|
791
|
-
"report_ledger_count": "Dispatches",
|
|
792
|
-
"report_ledger_claude": "Claude weekly quota",
|
|
793
|
-
"report_ledger_codex": "Codex weekly quota",
|
|
794
|
-
"report_ledger_agy": "Antigravity weekly quota",
|
|
795
|
-
"report_ledger_unowned_part": "{count} {agent}",
|
|
796
|
-
"report_ledger_unowned_sep": ", ",
|
|
797
|
-
"report_ledger_unowned": "No record of dispatch by Claude was found for another {items} conversations; they are not included in the table above",
|
|
784
|
+
"report_ledger_section": "Where your dispatch quota went (last 7 days)",
|
|
798
785
|
"report_daily_chart_title": "Daily usage",
|
|
799
786
|
"report_daily_chart_mode_tokens": "Tokens",
|
|
800
787
|
"report_daily_chart_mode_cost": "API equivalent",
|
|
@@ -882,9 +869,9 @@
|
|
|
882
869
|
"report_wrapped_top_project": "Top project",
|
|
883
870
|
"report_wrapped_books_equivalent": "≈ {books} books worth of words",
|
|
884
871
|
"report_wrapped_beast_phoenix_title": "Phoenix Crowned",
|
|
885
|
-
"report_wrapped_beast_phoenix_caption": "Claude carried slightly more fire
|
|
872
|
+
"report_wrapped_beast_phoenix_caption": "Claude carried slightly more fire over the past year, like a bird kicking the whole workshop back into the sky.",
|
|
886
873
|
"report_wrapped_beast_dragon_title": "Dragon Crowned",
|
|
887
|
-
"report_wrapped_beast_dragon_caption": "Codex hit harder
|
|
874
|
+
"report_wrapped_beast_dragon_caption": "Codex hit harder over the past year, like a dragon torching a build all the way to done.",
|
|
888
875
|
"project_butler": "Resume Last Session",
|
|
889
876
|
"project_butler_tooltip": "When you open a new session, automatically hand your last progress to the AI — no need to re-explain.",
|
|
890
877
|
"terse_mode_menu": "Token Saver",
|
|
@@ -1114,14 +1101,19 @@
|
|
|
1114
1101
|
"claude_desktop_updated": "Claude Desktop · updated {minutes}m ago",
|
|
1115
1102
|
"claude_desktop_stale": "Claude Desktop · stale · updated {minutes}m ago",
|
|
1116
1103
|
"report_project_others": "Other projects",
|
|
1117
|
-
"
|
|
1104
|
+
"report_ledger_lead": "How much of each weekly quota went to work Claude handed to Codex and Antigravity.",
|
|
1118
1105
|
"report_trend_partial_week": "only {days} days",
|
|
1119
1106
|
"report_history_scope": "Per-tool records start on {date}; earlier daily totals appear only in the heatmap below.",
|
|
1120
1107
|
"report_composition_missing": "Another {tokens} tokens have no input/output breakdown.",
|
|
1121
1108
|
"report_wrapped_cost_scope": "Only days with price records (from {date})",
|
|
1122
1109
|
"report_wrapped_cost_no_records": "No price records",
|
|
1123
|
-
"report_wrapped_beast_phoenix_caption_dominant": "Claude led by a wide margin in tokens
|
|
1124
|
-
"report_wrapped_beast_dragon_caption_dominant": "Codex led by a wide margin in tokens
|
|
1110
|
+
"report_wrapped_beast_phoenix_caption_dominant": "Claude led by a wide margin in tokens over the past year.",
|
|
1111
|
+
"report_wrapped_beast_dragon_caption_dominant": "Codex led by a wide margin in tokens over the past year.",
|
|
1112
|
+
"report_ledger_used": "{pct}% used this week",
|
|
1113
|
+
"report_ledger_row_meta": "{project} · {count} dispatches",
|
|
1114
|
+
"report_ledger_more": "{count} more dispatching conversations",
|
|
1115
|
+
"report_ledger_other": "Other (your own use, or no dispatch record found)",
|
|
1116
|
+
"report_ledger_all_reset": "All dispatched work in the last 7 days came before the quota reset, so it counts toward last week."
|
|
1125
1117
|
},
|
|
1126
1118
|
"zh-CN": {
|
|
1127
1119
|
"panel_default_name": "默认",
|
|
@@ -1347,16 +1339,7 @@
|
|
|
1347
1339
|
"report_cost": "API 等值",
|
|
1348
1340
|
"report_quota_share": "约占周额度",
|
|
1349
1341
|
"report_quota_approx": "约 {value}%",
|
|
1350
|
-
"report_ledger_section": "
|
|
1351
|
-
"report_ledger_date": "日期",
|
|
1352
|
-
"report_ledger_title": "对话标题",
|
|
1353
|
-
"report_ledger_count": "派工次数",
|
|
1354
|
-
"report_ledger_claude": "Claude 周额度",
|
|
1355
|
-
"report_ledger_codex": "Codex 周额度",
|
|
1356
|
-
"report_ledger_agy": "Antigravity 周额度",
|
|
1357
|
-
"report_ledger_unowned_part": "{count} 个 {agent}",
|
|
1358
|
-
"report_ledger_unowned_sep": "、",
|
|
1359
|
-
"report_ledger_unowned": "另有 {items} 对话找不到由 Claude 派工的记录,未列入上表",
|
|
1342
|
+
"report_ledger_section": "派工额度花在哪(最近 7 天)",
|
|
1360
1343
|
"report_daily_chart_title": "每日用量",
|
|
1361
1344
|
"report_daily_chart_mode_tokens": "Tokens",
|
|
1362
1345
|
"report_daily_chart_mode_cost": "API 等值",
|
|
@@ -1444,9 +1427,9 @@
|
|
|
1444
1427
|
"report_wrapped_top_project": "最常用项目",
|
|
1445
1428
|
"report_wrapped_books_equivalent": "≈ {books} 本书的字量",
|
|
1446
1429
|
"report_wrapped_beast_phoenix_title": "凤凰加冕",
|
|
1447
|
-
"report_wrapped_beast_phoenix_caption": "
|
|
1430
|
+
"report_wrapped_beast_phoenix_caption": "近一年 Claude 的火力略胜一筹,像把灰烬一口气吹回天空。",
|
|
1448
1431
|
"report_wrapped_beast_dragon_title": "巨龙加冕",
|
|
1449
|
-
"report_wrapped_beast_dragon_caption": "
|
|
1432
|
+
"report_wrapped_beast_dragon_caption": "近一年 Codex 的火力更猛,像一条龙一路把工地烧到完工。",
|
|
1450
1433
|
"project_butler": "接着上次做",
|
|
1451
1434
|
"project_butler_tooltip": "开新对话时,自动把上次的进度交给 AI,不用再重讲一次。",
|
|
1452
1435
|
"terse_mode_menu": "省 token 模式",
|
|
@@ -1676,14 +1659,19 @@
|
|
|
1676
1659
|
"claude_desktop_updated": "Claude 桌面版 · {minutes} 分钟前更新",
|
|
1677
1660
|
"claude_desktop_stale": "Claude 桌面版 · 数据过期 · {minutes} 分钟前更新",
|
|
1678
1661
|
"report_project_others": "其他项目",
|
|
1679
|
-
"
|
|
1662
|
+
"report_ledger_lead": "Claude 派给 Codex、Antigravity 的工作,各吃掉多少周额度。",
|
|
1680
1663
|
"report_trend_partial_week": "仅 {days} 天",
|
|
1681
1664
|
"report_history_scope": "分工具记录从 {date} 起;更早的每日总量只在下方热力图",
|
|
1682
1665
|
"report_composition_missing": "另有 {tokens} tokens 没有输入/输出拆解",
|
|
1683
1666
|
"report_wrapped_cost_scope": "只含有价格记录的日子({date} 起)",
|
|
1684
1667
|
"report_wrapped_cost_no_records": "没有价格记录",
|
|
1685
|
-
"report_wrapped_beast_phoenix_caption_dominant": "
|
|
1686
|
-
"report_wrapped_beast_dragon_caption_dominant": "
|
|
1668
|
+
"report_wrapped_beast_phoenix_caption_dominant": "近一年 Claude 的用量遥遥领先。",
|
|
1669
|
+
"report_wrapped_beast_dragon_caption_dominant": "近一年 Codex 的用量遥遥领先。",
|
|
1670
|
+
"report_ledger_used": "本周已用 {pct}%",
|
|
1671
|
+
"report_ledger_row_meta": "{project} · 派工 {count} 次",
|
|
1672
|
+
"report_ledger_more": "另外 {count} 段派工对话",
|
|
1673
|
+
"report_ledger_other": "其他(你直接用的,或没对到派工记录)",
|
|
1674
|
+
"report_ledger_all_reset": "最近 7 天的派工都在额度重置前,算在上周。"
|
|
1687
1675
|
},
|
|
1688
1676
|
"ja": {
|
|
1689
1677
|
"panel_default_name": "デフォルト",
|
|
@@ -1909,16 +1897,7 @@
|
|
|
1909
1897
|
"report_cost": "API 換算",
|
|
1910
1898
|
"report_quota_share": "週間枠の推定割合",
|
|
1911
1899
|
"report_quota_approx": "約 {value}%",
|
|
1912
|
-
"report_ledger_section": "
|
|
1913
|
-
"report_ledger_date": "日付",
|
|
1914
|
-
"report_ledger_title": "会話タイトル",
|
|
1915
|
-
"report_ledger_count": "委任回数",
|
|
1916
|
-
"report_ledger_claude": "Claude 週間クォータ",
|
|
1917
|
-
"report_ledger_codex": "Codex 週間クォータ",
|
|
1918
|
-
"report_ledger_agy": "Antigravity 週間クォータ",
|
|
1919
|
-
"report_ledger_unowned_part": "{agent} {count} 件",
|
|
1920
|
-
"report_ledger_unowned_sep": "、",
|
|
1921
|
-
"report_ledger_unowned": "ほかに {items} 件の会話には Claude からのタスク割り当て記録が見つからず、上の表には含めていません",
|
|
1900
|
+
"report_ledger_section": "委任先で使ったクォータ(直近 7 日間)",
|
|
1922
1901
|
"report_daily_chart_title": "日別の使用量",
|
|
1923
1902
|
"report_daily_chart_mode_tokens": "Tokens",
|
|
1924
1903
|
"report_daily_chart_mode_cost": "API 換算",
|
|
@@ -2006,9 +1985,9 @@
|
|
|
2006
1985
|
"report_wrapped_top_project": "最も使ったプロジェクト",
|
|
2007
1986
|
"report_wrapped_books_equivalent": "≈ {books} 冊分の文字量",
|
|
2008
1987
|
"report_wrapped_beast_phoenix_title": "フェニックス戴冠",
|
|
2009
|
-
"report_wrapped_beast_phoenix_caption": "
|
|
1988
|
+
"report_wrapped_beast_phoenix_caption": "この1年は Claude の火力がわずかに上回り、灰を空へ吹き返すような一年でした。",
|
|
2010
1989
|
"report_wrapped_beast_dragon_title": "ドラゴン戴冠",
|
|
2011
|
-
"report_wrapped_beast_dragon_caption": "
|
|
1990
|
+
"report_wrapped_beast_dragon_caption": "この1年は Codex の火力がより強く、工事現場を完成まで焼き切るような一年でした。",
|
|
2012
1991
|
"project_butler": "前回の続きから",
|
|
2013
1992
|
"project_butler_tooltip": "新規セッションを開くと、前回の進捗を自動で AI に引き継ぎます。説明し直す必要はありません。",
|
|
2014
1993
|
"terse_mode_menu": "トークン節約モード",
|
|
@@ -2238,14 +2217,19 @@
|
|
|
2238
2217
|
"claude_desktop_updated": "Claude デスクトップ · {minutes}分前に更新",
|
|
2239
2218
|
"claude_desktop_stale": "Claude デスクトップ · 古いデータ · {minutes}分前に更新",
|
|
2240
2219
|
"report_project_others": "その他のプロジェクト",
|
|
2241
|
-
"
|
|
2220
|
+
"report_ledger_lead": "Claude が Codex・Antigravity に任せた作業が、それぞれの週間クォータをどれだけ使ったか。",
|
|
2242
2221
|
"report_trend_partial_week": "{days} 日分のみ",
|
|
2243
2222
|
"report_history_scope": "ツール別記録は {date} から。それ以前の日別合計は下のヒートマップにのみ表示します。",
|
|
2244
2223
|
"report_composition_missing": "ほかに {tokens} tokens は入力/出力の内訳がありません。",
|
|
2245
2224
|
"report_wrapped_cost_scope": "価格記録のある日のみ({date} 以降)",
|
|
2246
2225
|
"report_wrapped_cost_no_records": "価格記録なし",
|
|
2247
|
-
"report_wrapped_beast_phoenix_caption_dominant": "
|
|
2248
|
-
"report_wrapped_beast_dragon_caption_dominant": "
|
|
2226
|
+
"report_wrapped_beast_phoenix_caption_dominant": "この1年のトークン数は Claude が大きくリードしました。",
|
|
2227
|
+
"report_wrapped_beast_dragon_caption_dominant": "この1年のトークン数は Codex が大きくリードしました。",
|
|
2228
|
+
"report_ledger_used": "今週は {pct}% 使用済み",
|
|
2229
|
+
"report_ledger_row_meta": "{project} · 委任 {count} 回",
|
|
2230
|
+
"report_ledger_more": "ほか {count} 件の委任元の会話",
|
|
2231
|
+
"report_ledger_other": "その他(直接使った分、または委任記録が見つからない分)",
|
|
2232
|
+
"report_ledger_all_reset": "直近 7 日間に委任した作業はすべてクォータのリセット前のため、先週分に含まれます。"
|
|
2249
2233
|
},
|
|
2250
2234
|
"ko": {
|
|
2251
2235
|
"panel_default_name": "기본",
|
|
@@ -2471,16 +2455,7 @@
|
|
|
2471
2455
|
"report_cost": "API 환산",
|
|
2472
2456
|
"report_quota_share": "주간 한도 예상 비율",
|
|
2473
2457
|
"report_quota_approx": "약 {value}%",
|
|
2474
|
-
"report_ledger_section": "
|
|
2475
|
-
"report_ledger_date": "날짜",
|
|
2476
|
-
"report_ledger_title": "대화 제목",
|
|
2477
|
-
"report_ledger_count": "위임 횟수",
|
|
2478
|
-
"report_ledger_claude": "Claude 주간 한도",
|
|
2479
|
-
"report_ledger_codex": "Codex 주간 한도",
|
|
2480
|
-
"report_ledger_agy": "Antigravity 주간 한도",
|
|
2481
|
-
"report_ledger_unowned_part": "{agent} {count}개",
|
|
2482
|
-
"report_ledger_unowned_sep": ", ",
|
|
2483
|
-
"report_ledger_unowned": "추가로 {items}개 대화는 Claude의 작업 배정 기록을 찾을 수 없어 위 표에서 제외했습니다",
|
|
2458
|
+
"report_ledger_section": "위임 작업에 쓴 한도 (최근 7일)",
|
|
2484
2459
|
"report_daily_chart_title": "일별 사용량",
|
|
2485
2460
|
"report_daily_chart_mode_tokens": "Tokens",
|
|
2486
2461
|
"report_daily_chart_mode_cost": "API 환산",
|
|
@@ -2568,9 +2543,9 @@
|
|
|
2568
2543
|
"report_wrapped_top_project": "가장 많이 쓴 프로젝트",
|
|
2569
2544
|
"report_wrapped_books_equivalent": "≈ 책 {books}권 분량의 글자",
|
|
2570
2545
|
"report_wrapped_beast_phoenix_title": "불사조 즉위",
|
|
2571
|
-
"report_wrapped_beast_phoenix_caption": "
|
|
2546
|
+
"report_wrapped_beast_phoenix_caption": "최근 1년은 Claude 쪽 화력이 조금 더 컸고, 재를 한 번에 하늘로 날려 보내는 듯했습니다.",
|
|
2572
2547
|
"report_wrapped_beast_dragon_title": "드래곤 즉위",
|
|
2573
|
-
"report_wrapped_beast_dragon_caption": "
|
|
2548
|
+
"report_wrapped_beast_dragon_caption": "최근 1년은 Codex 쪽 화력이 더 강했고, 공사판을 완공까지 밀어붙이는 용 같았습니다.",
|
|
2574
2549
|
"project_butler": "이어하기",
|
|
2575
2550
|
"project_butler_tooltip": "새 세션을 열 때 지난 진행 상황을 AI에게 자동으로 전달합니다. 처음부터 다시 설명할 필요 없어요.",
|
|
2576
2551
|
"terse_mode_menu": "토큰 절약 모드",
|
|
@@ -2800,13 +2775,18 @@
|
|
|
2800
2775
|
"claude_desktop_updated": "Claude 데스크톱 · {minutes}분 전 업데이트",
|
|
2801
2776
|
"claude_desktop_stale": "Claude 데스크톱 · 오래된 데이터 · {minutes}분 전 업데이트",
|
|
2802
2777
|
"report_project_others": "기타 프로젝트",
|
|
2803
|
-
"
|
|
2778
|
+
"report_ledger_lead": "Claude가 Codex와 Antigravity에 맡긴 작업이 각 주간 한도를 얼마나 썼는지 보여 줍니다.",
|
|
2804
2779
|
"report_trend_partial_week": "{days}일만 포함",
|
|
2805
2780
|
"report_history_scope": "도구별 기록은 {date}부터입니다. 이전 일별 합계는 아래 히트맵에만 표시됩니다.",
|
|
2806
2781
|
"report_composition_missing": "추가 {tokens} tokens에는 입력/출력 내역이 없습니다.",
|
|
2807
2782
|
"report_wrapped_cost_scope": "가격 기록이 있는 날만 포함 ({date}부터)",
|
|
2808
2783
|
"report_wrapped_cost_no_records": "가격 기록 없음",
|
|
2809
|
-
"report_wrapped_beast_phoenix_caption_dominant": "
|
|
2810
|
-
"report_wrapped_beast_dragon_caption_dominant": "
|
|
2784
|
+
"report_wrapped_beast_phoenix_caption_dominant": "최근 1년 토큰 사용량은 Claude가 크게 앞섰습니다.",
|
|
2785
|
+
"report_wrapped_beast_dragon_caption_dominant": "최근 1년 토큰 사용량은 Codex가 크게 앞섰습니다.",
|
|
2786
|
+
"report_ledger_used": "이번 주 {pct}% 사용",
|
|
2787
|
+
"report_ledger_row_meta": "{project} · 작업 위임 {count}회",
|
|
2788
|
+
"report_ledger_more": "작업을 위임한 대화 {count}개 더",
|
|
2789
|
+
"report_ledger_other": "기타 (직접 사용했거나 위임 기록을 찾지 못한 사용량)",
|
|
2790
|
+
"report_ledger_all_reset": "최근 7일 동안 위임한 작업은 모두 한도 초기화 전이므로 지난주 사용량에 포함됩니다."
|
|
2811
2791
|
}
|
|
2812
2792
|
}
|
|
@@ -10,12 +10,14 @@ import json
|
|
|
10
10
|
import logging
|
|
11
11
|
import math
|
|
12
12
|
import os
|
|
13
|
+
import re
|
|
13
14
|
import shutil
|
|
14
15
|
import subprocess
|
|
15
16
|
import tempfile
|
|
16
17
|
import threading
|
|
17
18
|
import time
|
|
18
19
|
from contextlib import suppress
|
|
20
|
+
from datetime import datetime
|
|
19
21
|
from pathlib import Path
|
|
20
22
|
from typing import TypedDict, TypeGuard
|
|
21
23
|
|
|
@@ -27,6 +29,10 @@ CACHE_PATH = Path.home() / ".usage/muse_quota.json"
|
|
|
27
29
|
PROBE_DIR = Path.home() / ".usage/muse-probe"
|
|
28
30
|
MUSE_MODEL = "muse-spark-1.3"
|
|
29
31
|
STALE_SECONDS = 30 * 60
|
|
32
|
+
WINDOW_SECONDS = 5 * 3600
|
|
33
|
+
_EXHAUSTED = re.compile(
|
|
34
|
+
r"Subscription quota exhausted\. Your usage window resets at (\d{4}-\d\d-\d\dT[\d:.]+Z)"
|
|
35
|
+
)
|
|
30
36
|
_probe_lock = threading.Lock()
|
|
31
37
|
_probe_running = False
|
|
32
38
|
_retry_after = 0.0
|
|
@@ -109,6 +115,34 @@ def parse_muse_allowance(stdout: str, checked_at: float) -> MuseQuotaResult | No
|
|
|
109
115
|
return None
|
|
110
116
|
|
|
111
117
|
|
|
118
|
+
def parse_exhausted_window(
|
|
119
|
+
stdout: str, cached: MuseQuotaResult | None, now: float
|
|
120
|
+
) -> MuseQuotaResult | None:
|
|
121
|
+
"""Read the 429 Muse returns once a window is used up; it carries no allowance.
|
|
122
|
+
|
|
123
|
+
The reply names only a reset time. Within 5 hours it is the 5-hour window, so the weekly
|
|
124
|
+
reading and its age stay from ``cached``. Further out it can only be the weekly allowance.
|
|
125
|
+
"""
|
|
126
|
+
match = _EXHAUSTED.search(stdout)
|
|
127
|
+
if cached is None or match is None:
|
|
128
|
+
return None
|
|
129
|
+
try:
|
|
130
|
+
reset = datetime.fromisoformat(match[1]).timestamp()
|
|
131
|
+
except ValueError:
|
|
132
|
+
return None
|
|
133
|
+
used_up = MuseQuotaWindow(used_percent=100.0, resets_at=reset)
|
|
134
|
+
if reset - now <= WINDOW_SECONDS:
|
|
135
|
+
return MuseQuotaResult(
|
|
136
|
+
checked_at=cached["checked_at"], window=used_up, weekly=cached["weekly"]
|
|
137
|
+
)
|
|
138
|
+
window = cached["window"]
|
|
139
|
+
# Nothing runs without weekly allowance, so a lapsed window is empty. One resetting past
|
|
140
|
+
# 5 hours is a weekly 429 that v0.34.5 recorded as the 5-hour window.
|
|
141
|
+
if not now < window["resets_at"] <= now + WINDOW_SECONDS:
|
|
142
|
+
window = MuseQuotaWindow(used_percent=0.0, resets_at=now)
|
|
143
|
+
return MuseQuotaResult(checked_at=now, window=window, weekly=used_up)
|
|
144
|
+
|
|
145
|
+
|
|
112
146
|
def read_cache() -> MuseQuotaResult | None:
|
|
113
147
|
"""Ignore invalid shared snapshots without deleting or quarantining them."""
|
|
114
148
|
try:
|
|
@@ -214,7 +248,10 @@ def _probe_worker(executable: str) -> None:
|
|
|
214
248
|
process.kill()
|
|
215
249
|
process.communicate()
|
|
216
250
|
raise
|
|
217
|
-
|
|
251
|
+
if process.returncode == 0:
|
|
252
|
+
result = parse_muse_allowance(stdout, time.time())
|
|
253
|
+
else:
|
|
254
|
+
result = parse_exhausted_window(stdout, read_cache(), time.time())
|
|
218
255
|
if result is not None:
|
|
219
256
|
_write_cache(result)
|
|
220
257
|
succeeded = True
|