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.
Files changed (229) hide show
  1. {usage_cli-0.32.0 → usage_cli-0.32.1}/PKG-INFO +31 -3
  2. {usage_cli-0.32.0 → usage_cli-0.32.1}/README.md +30 -2
  3. {usage_cli-0.32.0 → usage_cli-0.32.1}/i18n.json +5 -0
  4. {usage_cli-0.32.0 → usage_cli-0.32.1}/installer/claude_pane.py +28 -0
  5. {usage_cli-0.32.0 → usage_cli-0.32.1}/main.py +5 -0
  6. {usage_cli-0.32.0 → usage_cli-0.32.1}/pyproject.toml +1 -1
  7. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_claude_pane.py +53 -0
  8. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_main.py +13 -0
  9. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_wintray.py +88 -1
  10. {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_cli.egg-info/PKG-INFO +31 -3
  11. {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_cli.py +3 -1
  12. {usage_cli-0.32.0 → usage_cli-0.32.1}/wintray/app.py +61 -0
  13. {usage_cli-0.32.0 → usage_cli-0.32.1}/wintray/menu.py +2 -0
  14. {usage_cli-0.32.0 → usage_cli-0.32.1}/LICENSE +0 -0
  15. {usage_cli-0.32.0 → usage_cli-0.32.1}/adapters/__init__.py +0 -0
  16. {usage_cli-0.32.0 → usage_cli-0.32.1}/adapters/agy.py +0 -0
  17. {usage_cli-0.32.0 → usage_cli-0.32.1}/adapters/claude.py +0 -0
  18. {usage_cli-0.32.0 → usage_cli-0.32.1}/adapters/codex.py +0 -0
  19. {usage_cli-0.32.0 → usage_cli-0.32.1}/adapters/grok.py +0 -0
  20. {usage_cli-0.32.0 → usage_cli-0.32.1}/adapters/muse.py +0 -0
  21. {usage_cli-0.32.0 → usage_cli-0.32.1}/adapters/rate_limits.py +0 -0
  22. {usage_cli-0.32.0 → usage_cli-0.32.1}/adapters/registry.py +0 -0
  23. {usage_cli-0.32.0 → usage_cli-0.32.1}/adapters/types.py +0 -0
  24. {usage_cli-0.32.0 → usage_cli-0.32.1}/analyzer/__init__.py +0 -0
  25. {usage_cli-0.32.0 → usage_cli-0.32.1}/analyzer/aggregator.py +0 -0
  26. {usage_cli-0.32.0 → usage_cli-0.32.1}/analyzer/blocks.py +0 -0
  27. {usage_cli-0.32.0 → usage_cli-0.32.1}/analyzer/diagnoser.py +0 -0
  28. {usage_cli-0.32.0 → usage_cli-0.32.1}/analyzer/dispatch_ledger.py +0 -0
  29. {usage_cli-0.32.0 → usage_cli-0.32.1}/analyzer/insights.py +0 -0
  30. {usage_cli-0.32.0 → usage_cli-0.32.1}/analyzer/persona_loader.py +0 -0
  31. {usage_cli-0.32.0 → usage_cli-0.32.1}/analyzer/reporter.py +0 -0
  32. {usage_cli-0.32.0 → usage_cli-0.32.1}/analyzer/subscription.py +0 -0
  33. {usage_cli-0.32.0 → usage_cli-0.32.1}/analyzer/usage_snapshot.py +0 -0
  34. {usage_cli-0.32.0 → usage_cli-0.32.1}/doctor.py +0 -0
  35. {usage_cli-0.32.0 → usage_cli-0.32.1}/fsevents_watch.py +0 -0
  36. {usage_cli-0.32.0 → usage_cli-0.32.1}/i18n.py +0 -0
  37. {usage_cli-0.32.0 → usage_cli-0.32.1}/installer/__init__.py +0 -0
  38. {usage_cli-0.32.0 → usage_cli-0.32.1}/installer/login_item.py +0 -0
  39. {usage_cli-0.32.0 → usage_cli-0.32.1}/installer/session_hooks.py +0 -0
  40. {usage_cli-0.32.0 → usage_cli-0.32.1}/installer/setup_hook.py +0 -0
  41. {usage_cli-0.32.0 → usage_cli-0.32.1}/installer/statusline_settings.py +0 -0
  42. {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/__init__.py +0 -0
  43. {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/agy_disk_cache.py +0 -0
  44. {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/agy_loader.py +0 -0
  45. {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/agy_quota_probe.py +0 -0
  46. {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/cache_quarantine.py +0 -0
  47. {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/claude_paths.py +0 -0
  48. {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/codex_disk_cache.py +0 -0
  49. {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/codex_events.py +0 -0
  50. {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/codex_fork_replay.py +0 -0
  51. {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/codex_loader.py +0 -0
  52. {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/codex_paths.py +0 -0
  53. {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/disk_cache_common.py +0 -0
  54. {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/disk_cache_lifecycle.py +0 -0
  55. {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/grok_loader.py +0 -0
  56. {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/grok_quota_probe.py +0 -0
  57. {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/history_disk_cache.py +0 -0
  58. {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/history_loader.py +0 -0
  59. {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/jsonl_limits.py +0 -0
  60. {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/jsonl_utils.py +0 -0
  61. {usage_cli-0.32.0 → usage_cli-0.32.1}/loaders/muse_loader.py +0 -0
  62. {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/__init__.py +0 -0
  63. {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/actions.py +0 -0
  64. {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/agy.py +0 -0
  65. {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/app.py +0 -0
  66. {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/chrome.py +0 -0
  67. {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/grok.py +0 -0
  68. {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/menu.py +0 -0
  69. {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/new_badge.py +0 -0
  70. {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/notify.py +0 -0
  71. {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/popover.py +0 -0
  72. {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/prefs.py +0 -0
  73. {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/refresh.py +0 -0
  74. {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/state.py +0 -0
  75. {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/title.py +0 -0
  76. {usage_cli-0.32.0 → usage_cli-0.32.1}/menubar/update.py +0 -0
  77. {usage_cli-0.32.0 → usage_cli-0.32.1}/panels/__init__.py +0 -0
  78. {usage_cli-0.32.0 → usage_cli-0.32.1}/panels/base.py +0 -0
  79. {usage_cli-0.32.0 → usage_cli-0.32.1}/panels/dynamic_height.py +0 -0
  80. {usage_cli-0.32.0 → usage_cli-0.32.1}/panels/panel_scale.py +0 -0
  81. {usage_cli-0.32.0 → usage_cli-0.32.1}/panels/panel_window.py +0 -0
  82. {usage_cli-0.32.0 → usage_cli-0.32.1}/panels/panel_window_state.py +0 -0
  83. {usage_cli-0.32.0 → usage_cli-0.32.1}/panels/payload.py +0 -0
  84. {usage_cli-0.32.0 → usage_cli-0.32.1}/panels/web_panel.py +0 -0
  85. {usage_cli-0.32.0 → usage_cli-0.32.1}/panels/window_drag.py +0 -0
  86. {usage_cli-0.32.0 → usage_cli-0.32.1}/prefs.py +0 -0
  87. {usage_cli-0.32.0 → usage_cli-0.32.1}/pricing.py +0 -0
  88. {usage_cli-0.32.0 → usage_cli-0.32.1}/project_resolver.py +0 -0
  89. {usage_cli-0.32.0 → usage_cli-0.32.1}/quota/__init__.py +0 -0
  90. {usage_cli-0.32.0 → usage_cli-0.32.1}/quota/agy_window_keeper.py +0 -0
  91. {usage_cli-0.32.0 → usage_cli-0.32.1}/quota/burn_rate.py +0 -0
  92. {usage_cli-0.32.0 → usage_cli-0.32.1}/quota/codex_window_keeper.py +0 -0
  93. {usage_cli-0.32.0 → usage_cli-0.32.1}/quota/usage_rate.py +0 -0
  94. {usage_cli-0.32.0 → usage_cli-0.32.1}/quota/window_keeper.py +0 -0
  95. {usage_cli-0.32.0 → usage_cli-0.32.1}/service_status.py +0 -0
  96. {usage_cli-0.32.0 → usage_cli-0.32.1}/setup.cfg +0 -0
  97. {usage_cli-0.32.0 → usage_cli-0.32.1}/setup_app.py +0 -0
  98. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_adapters_claude.py +0 -0
  99. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_adapters_codex.py +0 -0
  100. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_adapters_rate_limits.py +0 -0
  101. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_aggregator.py +0 -0
  102. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_agy_adapter.py +0 -0
  103. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_agy_disk_cache.py +0 -0
  104. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_agy_loader.py +0 -0
  105. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_agy_quota_probe.py +0 -0
  106. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_agy_window_keeper.py +0 -0
  107. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_analyzer_blocks.py +0 -0
  108. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_analyzer_pipeline.py +0 -0
  109. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_burn_rate.py +0 -0
  110. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_cache_quarantine.py +0 -0
  111. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_claude_paths.py +0 -0
  112. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_codex_consistency.py +0 -0
  113. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_codex_loader.py +0 -0
  114. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_codex_window_keeper.py +0 -0
  115. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_diagnoser.py +0 -0
  116. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_disk_cache_shards.py +0 -0
  117. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_dispatch_ledger.py +0 -0
  118. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_doctor.py +0 -0
  119. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_dynamic_height.py +0 -0
  120. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_fsevents_watch.py +0 -0
  121. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_grok_loader.py +0 -0
  122. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_grok_quota_probe.py +0 -0
  123. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_history_loader.py +0 -0
  124. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_hook_scripts_are_standalone.py +0 -0
  125. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_html_report_snapshot.py +0 -0
  126. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_i18n_format_fallback.py +0 -0
  127. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_i18n_key_parity.py +0 -0
  128. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_i18n_packaged_path.py +0 -0
  129. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_insights.py +0 -0
  130. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_jsonl_utils.py +0 -0
  131. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_login_item.py +0 -0
  132. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_menubar.py +0 -0
  133. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_menubar_agy.py +0 -0
  134. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_menubar_grok.py +0 -0
  135. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_menubar_notify.py +0 -0
  136. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_menubar_prefs.py +0 -0
  137. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_menubar_state.py +0 -0
  138. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_muse_loader.py +0 -0
  139. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_new_badge.py +0 -0
  140. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_packaged_resources.py +0 -0
  141. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_packaging.py +0 -0
  142. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_panel_footer_layout.py +0 -0
  143. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_panel_scale.py +0 -0
  144. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_panel_window_state.py +0 -0
  145. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_panels.py +0 -0
  146. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_panels_lazy_import.py +0 -0
  147. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_persona_loader.py +0 -0
  148. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_pricing.py +0 -0
  149. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_project_resolver.py +0 -0
  150. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_report_daily_chart.py +0 -0
  151. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_report_filter_js.py +0 -0
  152. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_reporter_build_data.py +0 -0
  153. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_service_status.py +0 -0
  154. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_session_resume.py +0 -0
  155. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_setup_app.py +0 -0
  156. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_setup_hook.py +0 -0
  157. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_setup_hook_coexistence.py +0 -0
  158. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_setup_hook_resume.py +0 -0
  159. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_setup_hook_terse.py +0 -0
  160. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_subprocess_utils.py +0 -0
  161. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_subscription.py +0 -0
  162. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_time_utils.py +0 -0
  163. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_tui.py +0 -0
  164. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_tui_sprite.py +0 -0
  165. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_ui_tables.py +0 -0
  166. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_update_checker.py +0 -0
  167. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_update_gate.py +0 -0
  168. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_update_release_notes.py +0 -0
  169. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_cli.py +0 -0
  170. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_client.py +0 -0
  171. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_diagnosis_snapshot.py +0 -0
  172. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_dir_sweeper.py +0 -0
  173. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_lang.py +0 -0
  174. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_logging.py +0 -0
  175. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_notifications.py +0 -0
  176. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_rate.py +0 -0
  177. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_snapshot.py +0 -0
  178. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_snapshot_replay.py +0 -0
  179. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_statusline.py +0 -0
  180. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_statusline_agy.py +0 -0
  181. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_statusline_forwarder.py +0 -0
  182. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_statusline_grok.py +0 -0
  183. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_terse_mode.py +0 -0
  184. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_usage_terse_reminder.py +0 -0
  185. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_web_panel_payload.py +0 -0
  186. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_wheel_packaging.py +0 -0
  187. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_win_login_item.py +0 -0
  188. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_window_keeper.py +0 -0
  189. {usage_cli-0.32.0 → usage_cli-0.32.1}/tests/test_windows_manifest.py +0 -0
  190. {usage_cli-0.32.0 → usage_cli-0.32.1}/tui/__init__.py +0 -0
  191. {usage_cli-0.32.0 → usage_cli-0.32.1}/tui/app.py +0 -0
  192. {usage_cli-0.32.0 → usage_cli-0.32.1}/tui/sprite.py +0 -0
  193. {usage_cli-0.32.0 → usage_cli-0.32.1}/ui/__init__.py +0 -0
  194. {usage_cli-0.32.0 → usage_cli-0.32.1}/ui/html_report.py +0 -0
  195. {usage_cli-0.32.0 → usage_cli-0.32.1}/ui/report_charts.py +0 -0
  196. {usage_cli-0.32.0 → usage_cli-0.32.1}/ui/report_daily_chart.py +0 -0
  197. {usage_cli-0.32.0 → usage_cli-0.32.1}/ui/report_filter.py +0 -0
  198. {usage_cli-0.32.0 → usage_cli-0.32.1}/ui/report_ledger.py +0 -0
  199. {usage_cli-0.32.0 → usage_cli-0.32.1}/ui/report_scripts.py +0 -0
  200. {usage_cli-0.32.0 → usage_cli-0.32.1}/ui/report_styles.py +0 -0
  201. {usage_cli-0.32.0 → usage_cli-0.32.1}/ui/tables.py +0 -0
  202. {usage_cli-0.32.0 → usage_cli-0.32.1}/updates/__init__.py +0 -0
  203. {usage_cli-0.32.0 → usage_cli-0.32.1}/updates/checker.py +0 -0
  204. {usage_cli-0.32.0 → usage_cli-0.32.1}/updates/gate.py +0 -0
  205. {usage_cli-0.32.0 → usage_cli-0.32.1}/updates/release_notes.py +0 -0
  206. {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_cli.egg-info/SOURCES.txt +0 -0
  207. {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_cli.egg-info/dependency_links.txt +0 -0
  208. {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_cli.egg-info/entry_points.txt +0 -0
  209. {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_cli.egg-info/requires.txt +0 -0
  210. {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_cli.egg-info/top_level.txt +0 -0
  211. {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_client.py +0 -0
  212. {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_common/__init__.py +0 -0
  213. {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_common/subprocess_utils.py +0 -0
  214. {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_common/time_utils.py +0 -0
  215. {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_common/usage_dir_sweeper.py +0 -0
  216. {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_common/usage_lang.py +0 -0
  217. {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_common/usage_logging.py +0 -0
  218. {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_diagnosis_snapshot.py +0 -0
  219. {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_notifications.py +0 -0
  220. {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_session_resume.py +0 -0
  221. {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_statusline.py +0 -0
  222. {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_statusline_agy.py +0 -0
  223. {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_statusline_forwarder.py +0 -0
  224. {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_statusline_grok.py +0 -0
  225. {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_terse_mode.py +0 -0
  226. {usage_cli-0.32.0 → usage_cli-0.32.1}/usage_terse_reminder.py +0 -0
  227. {usage_cli-0.32.0 → usage_cli-0.32.1}/wintray/__init__.py +0 -0
  228. {usage_cli-0.32.0 → usage_cli-0.32.1}/wintray/login_item.py +0 -0
  229. {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.0
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):** Toggle quotas, Claude sessions and background jobs inside Claude Code. Requires a recent Claude Code with mod support (tested with 2.1.289). Open a new conversation or run `/reload-plugins` after enabling. The pane opens on the right automatically at terminal widths ≥144 columns; use `/usage-dash` in narrower terminals. macOS Terminal supports only 256 colors and may show a gray background; select an ANSI dark theme in `/config`. Conversations waiting for your permission or MCP input are marked in yellow across panes, and background jobs also list subagents started by Claude with the Agent tool and their status. When the usage app starts, it automatically updates an enabled pane to the bundled version.
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):** Toggle quotas, Claude sessions and background jobs inside Claude Code. Requires a recent Claude Code with mod support (tested with 2.1.289). Open a new conversation or run `/reload-plugins` after enabling. The pane opens on the right automatically at terminal widths ≥144 columns; use `/usage-dash` in narrower terminals. macOS Terminal supports only 256 colors and may show a gray background; select an ANSI dark theme in `/config`. Conversations waiting for your permission or MCP input are marked in yellow across panes, and background jobs also list subagents started by Claude with the Agent tool and their status. When the usage app starts, it automatically updates an enabled pane to the bundled version.
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:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "usage-cli"
3
- version = "0.32.0"
3
+ version = "0.32.1"
4
4
  description = "usage — 在 macOS menu bar 與 Windows 系統匣顯示 Claude Code、Codex、Antigravity 用量的小工具(也提供終端機 TUI)"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.13"
@@ -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[-3:] == [
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.0
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):** Toggle quotas, Claude sessions and background jobs inside Claude Code. Requires a recent Claude Code with mod support (tested with 2.1.289). Open a new conversation or run `/reload-plugins` after enabling. The pane opens on the right automatically at terminal widths ≥144 columns; use `/usage-dash` in narrower terminals. macOS Terminal supports only 256 colors and may show a gray background; select an ANSI dark theme in `/config`. Conversations waiting for your permission or MCP input are marked in yellow across panes, and background jobs also list subagents started by Claude with the Agent tool and their status. When the usage app starts, it automatically updates an enabled pane to the bundled version.
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