token-tracker 0.3.2__tar.gz → 0.3.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {token_tracker-0.3.2 → token_tracker-0.3.4}/PKG-INFO +1 -1
- {token_tracker-0.3.2 → token_tracker-0.3.4}/pyproject.toml +1 -1
- {token_tracker-0.3.2 → token_tracker-0.3.4}/src/cli.py +42 -4
- {token_tracker-0.3.2 → token_tracker-0.3.4}/src/hooks.py +24 -11
- {token_tracker-0.3.2 → token_tracker-0.3.4}/token_tracker.egg-info/PKG-INFO +1 -1
- {token_tracker-0.3.2 → token_tracker-0.3.4}/README.md +0 -0
- {token_tracker-0.3.2 → token_tracker-0.3.4}/setup.cfg +0 -0
- {token_tracker-0.3.2 → token_tracker-0.3.4}/src/__init__.py +0 -0
- {token_tracker-0.3.2 → token_tracker-0.3.4}/src/adapters/__init__.py +0 -0
- {token_tracker-0.3.2 → token_tracker-0.3.4}/src/adapters/claude.py +0 -0
- {token_tracker-0.3.2 → token_tracker-0.3.4}/src/adapters/codex.py +0 -0
- {token_tracker-0.3.2 → token_tracker-0.3.4}/src/adapters/rate_limits.py +0 -0
- {token_tracker-0.3.2 → token_tracker-0.3.4}/src/adapters/registry.py +0 -0
- {token_tracker-0.3.2 → token_tracker-0.3.4}/src/adapters/types.py +0 -0
- {token_tracker-0.3.2 → token_tracker-0.3.4}/src/analyzer/__init__.py +0 -0
- {token_tracker-0.3.2 → token_tracker-0.3.4}/src/analyzer/aggregator.py +0 -0
- {token_tracker-0.3.2 → token_tracker-0.3.4}/src/analyzer/blocks.py +0 -0
- {token_tracker-0.3.2 → token_tracker-0.3.4}/src/analyzer/cost.py +0 -0
- {token_tracker-0.3.2 → token_tracker-0.3.4}/src/ui/__init__.py +0 -0
- {token_tracker-0.3.2 → token_tracker-0.3.4}/src/ui/tables.py +0 -0
- {token_tracker-0.3.2 → token_tracker-0.3.4}/token_tracker.egg-info/SOURCES.txt +0 -0
- {token_tracker-0.3.2 → token_tracker-0.3.4}/token_tracker.egg-info/dependency_links.txt +0 -0
- {token_tracker-0.3.2 → token_tracker-0.3.4}/token_tracker.egg-info/entry_points.txt +0 -0
- {token_tracker-0.3.2 → token_tracker-0.3.4}/token_tracker.egg-info/requires.txt +0 -0
- {token_tracker-0.3.2 → token_tracker-0.3.4}/token_tracker.egg-info/top_level.txt +0 -0
|
@@ -92,8 +92,6 @@ def _fit_screen(text: str, height: int, scroll_offset: int) -> tuple[str, int]:
|
|
|
92
92
|
|
|
93
93
|
|
|
94
94
|
def _show_interactive_dashboard(agents):
|
|
95
|
-
import tty
|
|
96
|
-
import termios
|
|
97
95
|
import shutil
|
|
98
96
|
from io import StringIO
|
|
99
97
|
from rich.console import Console as RichConsole
|
|
@@ -135,7 +133,7 @@ def _show_interactive_dashboard(agents):
|
|
|
135
133
|
sys.stdout.write("\033[2J\033[3J\033[H" + screen)
|
|
136
134
|
sys.stdout.flush()
|
|
137
135
|
|
|
138
|
-
key = _read_key(
|
|
136
|
+
key = _read_key()
|
|
139
137
|
if key == "left":
|
|
140
138
|
current = (current - 1) % len(agents)
|
|
141
139
|
scroll_offset = 0
|
|
@@ -158,9 +156,11 @@ def _show_interactive_dashboard(agents):
|
|
|
158
156
|
_tables.console = orig
|
|
159
157
|
|
|
160
158
|
|
|
161
|
-
def
|
|
159
|
+
def _read_key_unix():
|
|
162
160
|
import os as _os
|
|
163
161
|
import select
|
|
162
|
+
import tty
|
|
163
|
+
import termios
|
|
164
164
|
fd = sys.stdin.fileno()
|
|
165
165
|
old = termios.tcgetattr(fd)
|
|
166
166
|
try:
|
|
@@ -204,6 +204,44 @@ def _read_key(tty, termios):
|
|
|
204
204
|
termios.tcsetattr(fd, termios.TCSADRAIN, old)
|
|
205
205
|
|
|
206
206
|
|
|
207
|
+
def _read_key_win():
|
|
208
|
+
import msvcrt
|
|
209
|
+
ch = msvcrt.getch()
|
|
210
|
+
if ch in (b"\xe0", b"\x00"):
|
|
211
|
+
ch2 = msvcrt.getch()
|
|
212
|
+
if ch2 == b"K":
|
|
213
|
+
return "left"
|
|
214
|
+
if ch2 == b"M":
|
|
215
|
+
return "right"
|
|
216
|
+
if ch2 == b"H":
|
|
217
|
+
return "up"
|
|
218
|
+
if ch2 == b"P":
|
|
219
|
+
return "down"
|
|
220
|
+
if ch2 == b"I":
|
|
221
|
+
return "page_up"
|
|
222
|
+
if ch2 == b"Q":
|
|
223
|
+
return "page_down"
|
|
224
|
+
return "other"
|
|
225
|
+
if ch == b"h":
|
|
226
|
+
return "left"
|
|
227
|
+
if ch == b"l":
|
|
228
|
+
return "right"
|
|
229
|
+
if ch == b"k":
|
|
230
|
+
return "up"
|
|
231
|
+
if ch == b"j":
|
|
232
|
+
return "down"
|
|
233
|
+
if ch == b"b":
|
|
234
|
+
return "page_up"
|
|
235
|
+
if ch == b"f":
|
|
236
|
+
return "page_down"
|
|
237
|
+
if ch in (b"q", b"Q", b"\x03", b"\x1b"):
|
|
238
|
+
return "quit"
|
|
239
|
+
return "other"
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
_read_key = _read_key_win if sys.platform == "win32" else _read_key_unix
|
|
243
|
+
|
|
244
|
+
|
|
207
245
|
def _get_version() -> str:
|
|
208
246
|
from importlib.metadata import version
|
|
209
247
|
return version("token-tracker")
|
|
@@ -2,6 +2,7 @@ import json
|
|
|
2
2
|
import os
|
|
3
3
|
import re
|
|
4
4
|
import stat
|
|
5
|
+
import sys
|
|
5
6
|
import tomllib
|
|
6
7
|
|
|
7
8
|
from .ui.tables import console
|
|
@@ -10,7 +11,7 @@ CLAUDE_SETTINGS = os.path.expanduser("~/.claude/settings.json")
|
|
|
10
11
|
HOOK_SCRIPT_PATH = os.path.expanduser("~/.claude/tt-statusline.py")
|
|
11
12
|
CODEX_CONFIG = os.path.expanduser("~/.codex/config.toml")
|
|
12
13
|
CODEX_BACKUP = os.path.expanduser("~/.codex/tt-backup.json")
|
|
13
|
-
HOOK_VERSION = "1.
|
|
14
|
+
HOOK_VERSION = "1.5"
|
|
14
15
|
_BACKUP_KEY = "tokenTracker"
|
|
15
16
|
_PREV_SL_KEY = "previousStatusLine"
|
|
16
17
|
_SL_REGEX = re.compile(r'status_line\s*=\s*\[.*?\]', re.DOTALL)
|
|
@@ -25,7 +26,7 @@ CODEX_STATUS_LINE = [
|
|
|
25
26
|
|
|
26
27
|
HOOK_SCRIPT = r'''#!/usr/bin/env python3
|
|
27
28
|
"""Claude Code statusLine — 状态栏显示 + 数据持久化到 tt-status.json"""
|
|
28
|
-
__version__ = "1.
|
|
29
|
+
__version__ = "1.5"
|
|
29
30
|
import json, os, re, subprocess, sys, tempfile
|
|
30
31
|
from datetime import datetime, timezone
|
|
31
32
|
|
|
@@ -37,6 +38,9 @@ C = {
|
|
|
37
38
|
"peach": "\033[38;5;216m", "dim": "\033[2m", "reset": "\033[0m",
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
if sys.platform == "win32":
|
|
42
|
+
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
|
43
|
+
|
|
40
44
|
|
|
41
45
|
def vlen(s):
|
|
42
46
|
return len(ANSI_RE.sub("", s))
|
|
@@ -47,13 +51,15 @@ def get_width():
|
|
|
47
51
|
return max(1, os.get_terminal_size(2).columns - 4)
|
|
48
52
|
except Exception:
|
|
49
53
|
pass
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
if os.name != "nt":
|
|
55
|
+
try:
|
|
56
|
+
import fcntl, struct, termios
|
|
57
|
+
with open('/dev/tty', 'r') as tty:
|
|
58
|
+
res = fcntl.ioctl(tty, termios.TIOCGWINSZ, b'\x00' * 8)
|
|
59
|
+
return max(1, struct.unpack('hh', res[:4])[1] - 4)
|
|
60
|
+
except Exception:
|
|
61
|
+
pass
|
|
62
|
+
return 116
|
|
57
63
|
|
|
58
64
|
|
|
59
65
|
def color_by_pct(pct):
|
|
@@ -237,6 +243,7 @@ def render(data, now):
|
|
|
237
243
|
output = [" | ".join(line) for line in (line1, line2, line3) if line]
|
|
238
244
|
if output:
|
|
239
245
|
print("\n".join(output))
|
|
246
|
+
sys.stdout.flush()
|
|
240
247
|
|
|
241
248
|
|
|
242
249
|
def main():
|
|
@@ -310,13 +317,18 @@ def _installed_hook_version() -> str | None:
|
|
|
310
317
|
|
|
311
318
|
|
|
312
319
|
def needs_update() -> bool:
|
|
320
|
+
if not os.path.isdir(os.path.dirname(HOOK_SCRIPT_PATH)):
|
|
321
|
+
return False
|
|
313
322
|
return _installed_hook_version() != HOOK_VERSION
|
|
314
323
|
|
|
315
324
|
|
|
316
325
|
def update_hook() -> None:
|
|
326
|
+
if not os.path.isdir(os.path.dirname(HOOK_SCRIPT_PATH)):
|
|
327
|
+
return
|
|
317
328
|
with open(HOOK_SCRIPT_PATH, "w", encoding="utf-8") as f:
|
|
318
329
|
f.write(HOOK_SCRIPT)
|
|
319
|
-
|
|
330
|
+
if os.name != "nt":
|
|
331
|
+
os.chmod(HOOK_SCRIPT_PATH, os.stat(HOOK_SCRIPT_PATH).st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
|
320
332
|
|
|
321
333
|
|
|
322
334
|
# --- setup ---
|
|
@@ -358,7 +370,8 @@ def _setup_claude() -> None:
|
|
|
358
370
|
console.print(f"[yellow]检测到已有 statusLine,备份后替换[/yellow]")
|
|
359
371
|
settings.setdefault(_BACKUP_KEY, {})[_PREV_SL_KEY] = existing
|
|
360
372
|
|
|
361
|
-
|
|
373
|
+
python = sys.executable or "python3"
|
|
374
|
+
settings["statusLine"] = {"type": "command", "command": f"{python} {HOOK_SCRIPT_PATH}"}
|
|
362
375
|
|
|
363
376
|
with open(CLAUDE_SETTINGS, "w", encoding="utf-8") as f:
|
|
364
377
|
json.dump(settings, f, indent=2, ensure_ascii=False)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|