tokenmaxxing 0.2.1__tar.gz → 0.2.2__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.
- {tokenmaxxing-0.2.1 → tokenmaxxing-0.2.2}/PKG-INFO +1 -1
- {tokenmaxxing-0.2.1 → tokenmaxxing-0.2.2}/pyproject.toml +1 -1
- {tokenmaxxing-0.2.1 → tokenmaxxing-0.2.2}/src/tokenmaxxing/__init__.py +1 -1
- {tokenmaxxing-0.2.1 → tokenmaxxing-0.2.2}/src/tokenmaxxing/app.py +23 -8
- {tokenmaxxing-0.2.1 → tokenmaxxing-0.2.2}/.gitignore +0 -0
- {tokenmaxxing-0.2.1 → tokenmaxxing-0.2.2}/LICENSE +0 -0
- {tokenmaxxing-0.2.1 → tokenmaxxing-0.2.2}/README.md +0 -0
- {tokenmaxxing-0.2.1 → tokenmaxxing-0.2.2}/src/tokenmaxxing/__main__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tokenmaxxing
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Menu bar app showing your live Claude Code session and weekly usage as a colored progress bar.
|
|
5
5
|
Project-URL: Homepage, https://github.com/alvations/tokenmaxxing
|
|
6
6
|
Project-URL: Repository, https://github.com/alvations/tokenmaxxing
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tokenmaxxing"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.2"
|
|
8
8
|
description = "Menu bar app showing your live Claude Code session and weekly usage as a colored progress bar."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -78,8 +78,6 @@ REFRESH_SECONDS = 1800 # 30 min: /api/oauth/usage tolerates ~hourly polling but
|
|
|
78
78
|
# at ~5 min cadence with a sticky multi-hour cooldown. 30 min keeps
|
|
79
79
|
# us well below the throttle threshold; on-demand menu opens still
|
|
80
80
|
# refresh instantly.
|
|
81
|
-
SUSTAINED_429_THRESHOLD = 3 # after this many consecutive 429s, fall back to /v1/messages
|
|
82
|
-
# headers (which cost ~10 tokens/poll) until /usage recovers
|
|
83
81
|
STALE_AFTER_SECONDS = 600 # 10 min: only mark cached data "(stale)" past this age — one
|
|
84
82
|
# missed poll cycle (~5 min) shouldn't trigger the warning
|
|
85
83
|
REFRESH_MAX_BACKOFF = 1800 # Max backoff: 30 minutes
|
|
@@ -724,6 +722,7 @@ class ClaudeMonitorApp(rumps.App):
|
|
|
724
722
|
self._pending_lock = threading.Lock()
|
|
725
723
|
self._wake = threading.Event()
|
|
726
724
|
self._backoff_until = 0 # unix timestamp; worker won't poll until after this
|
|
725
|
+
self._force_fallback_next = False # set by "Force fresh" menu; consumed by next poll
|
|
727
726
|
self._history_lock = threading.Lock()
|
|
728
727
|
self._history = _load_history()
|
|
729
728
|
|
|
@@ -773,6 +772,8 @@ class ClaudeMonitorApp(rumps.App):
|
|
|
773
772
|
self.stats_item = rumps.MenuItem(HISTORY_COLLECTING)
|
|
774
773
|
self._dashboard_item = rumps.MenuItem("Open Claude dashboard…", callback=self._open_dashboard)
|
|
775
774
|
self._refresh_item = rumps.MenuItem("Refresh now", callback=self._manual_refresh)
|
|
775
|
+
self._refresh_paid_item = rumps.MenuItem(
|
|
776
|
+
"Force fresh (uses ~10 tokens)", callback=self._manual_refresh_paid)
|
|
776
777
|
|
|
777
778
|
self.menu = self._build_menu_items()
|
|
778
779
|
|
|
@@ -800,12 +801,14 @@ class ClaudeMonitorApp(rumps.App):
|
|
|
800
801
|
continue
|
|
801
802
|
|
|
802
803
|
oauth_data = _get_oauth_data()
|
|
803
|
-
#
|
|
804
|
-
#
|
|
805
|
-
#
|
|
806
|
-
#
|
|
807
|
-
#
|
|
808
|
-
|
|
804
|
+
# /v1/messages fallback is opt-in only — the user explicitly
|
|
805
|
+
# triggers it via the "Force fresh (uses ~10 tokens)" menu item,
|
|
806
|
+
# which sets _force_fallback_next for exactly one poll. The
|
|
807
|
+
# default path stays zero-token even when /api/oauth/usage is
|
|
808
|
+
# stuck — we'd rather show stale data than silently bill the
|
|
809
|
+
# user's quota.
|
|
810
|
+
allow_fallback = self._force_fallback_next
|
|
811
|
+
self._force_fallback_next = False
|
|
809
812
|
payload, err, is_rate_limited, retry_after = fetch_usage(
|
|
810
813
|
oauth_data, allow_messages_fallback=allow_fallback)
|
|
811
814
|
# Drop any Refresh-now clicks that arrived during the poll — the
|
|
@@ -882,6 +885,17 @@ class ClaudeMonitorApp(rumps.App):
|
|
|
882
885
|
# Without this, when the worker is in backoff (e.g. after sustained
|
|
883
886
|
# 429s), the wake event fires but the loop top-checks _backoff_until
|
|
884
887
|
# and goes right back to waiting — the click is swallowed.
|
|
888
|
+
# Zero token cost: hits /api/oauth/usage only.
|
|
889
|
+
self._backoff_until = 0
|
|
890
|
+
self._wake.set()
|
|
891
|
+
|
|
892
|
+
def _manual_refresh_paid(self, _sender):
|
|
893
|
+
# Opt-in escape hatch when /api/oauth/usage is stuck in a long
|
|
894
|
+
# cooldown. Costs ~10 tokens for one /v1/messages probe whose
|
|
895
|
+
# response headers carry the current rate-limit values. Consumed
|
|
896
|
+
# exactly once by the next poll; subsequent polls revert to the
|
|
897
|
+
# free path.
|
|
898
|
+
self._force_fallback_next = True
|
|
885
899
|
self._backoff_until = 0
|
|
886
900
|
self._wake.set()
|
|
887
901
|
|
|
@@ -962,6 +976,7 @@ class ClaudeMonitorApp(rumps.App):
|
|
|
962
976
|
None,
|
|
963
977
|
self.last_update_item,
|
|
964
978
|
self._refresh_item,
|
|
979
|
+
self._refresh_paid_item,
|
|
965
980
|
])
|
|
966
981
|
return items
|
|
967
982
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|