codex-cli-usage 0.1.0__tar.gz → 0.1.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.
- codex_cli_usage-0.1.4/.gitignore +2 -0
- {codex_cli_usage-0.1.0 → codex_cli_usage-0.1.4}/PKG-INFO +1 -1
- {codex_cli_usage-0.1.0 → codex_cli_usage-0.1.4}/pyproject.toml +1 -1
- {codex_cli_usage-0.1.0 → codex_cli_usage-0.1.4}/src/codex_cli_usage/__init__.py +54 -13
- codex_cli_usage-0.1.4/src/codex_cli_usage/__main__.py +2 -0
- {codex_cli_usage-0.1.0 → codex_cli_usage-0.1.4}/uv.lock +3 -3
- {codex_cli_usage-0.1.0 → codex_cli_usage-0.1.4}/.github/workflows/publish.yml +0 -0
- {codex_cli_usage-0.1.0 → codex_cli_usage-0.1.4}/README.md +0 -0
|
@@ -23,9 +23,49 @@ import urllib.request
|
|
|
23
23
|
from datetime import datetime, timezone
|
|
24
24
|
from pathlib import Path
|
|
25
25
|
|
|
26
|
+
_TTY = sys.stdout.isatty()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _find_codex_path(filename: str) -> Path:
|
|
30
|
+
"""Return the first existing path for a .codex file.
|
|
31
|
+
|
|
32
|
+
Checks the native path first (~/.codex/<filename>). On Windows, if the
|
|
33
|
+
native path doesn't exist, also checks WSL distros via //wsl$/.
|
|
34
|
+
"""
|
|
35
|
+
native = Path.home() / ".codex" / filename
|
|
36
|
+
if native.exists():
|
|
37
|
+
return native
|
|
38
|
+
|
|
39
|
+
if sys.platform == "win32":
|
|
40
|
+
import subprocess
|
|
41
|
+
try:
|
|
42
|
+
result = subprocess.run(
|
|
43
|
+
["wsl", "-l", "-q"],
|
|
44
|
+
capture_output=True, timeout=5,
|
|
45
|
+
)
|
|
46
|
+
decoded = result.stdout.decode("utf-16-le", errors="ignore")
|
|
47
|
+
distros = [d.strip() for d in decoded.splitlines() if d.strip()]
|
|
48
|
+
except Exception:
|
|
49
|
+
distros = []
|
|
50
|
+
|
|
51
|
+
for distro in distros:
|
|
52
|
+
wsl_home = Path(f"//wsl$/{distro}/home")
|
|
53
|
+
try:
|
|
54
|
+
users = [u for u in wsl_home.iterdir() if u.is_dir()]
|
|
55
|
+
except OSError:
|
|
56
|
+
continue
|
|
57
|
+
for user_dir in users:
|
|
58
|
+
candidate = user_dir / ".codex" / filename
|
|
59
|
+
if candidate.exists():
|
|
60
|
+
return candidate
|
|
61
|
+
|
|
62
|
+
# Fall back to native path even if it doesn't exist yet
|
|
63
|
+
return native
|
|
64
|
+
|
|
65
|
+
|
|
26
66
|
CODEX_DIR = Path.home() / ".codex"
|
|
27
|
-
AUTH_FILE =
|
|
28
|
-
USAGE_FILE =
|
|
67
|
+
AUTH_FILE = _find_codex_path("auth.json")
|
|
68
|
+
USAGE_FILE = _find_codex_path("usage-limits.json")
|
|
29
69
|
DAEMON_INTERVAL = 300 # 5 minutes
|
|
30
70
|
CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann"
|
|
31
71
|
USAGE_URL = "https://chatgpt.com/backend-api/codex/usage"
|
|
@@ -205,11 +245,11 @@ def cmd_status(raw_json=False):
|
|
|
205
245
|
print(json.dumps(data, indent=2))
|
|
206
246
|
return
|
|
207
247
|
|
|
208
|
-
R = "\033[0;31m"
|
|
209
|
-
Y = "\033[0;33m"
|
|
210
|
-
G = "\033[0;32m"
|
|
211
|
-
D = "\033[0;90m"
|
|
212
|
-
RST = "\033[0m"
|
|
248
|
+
R = "\033[0;31m" if _TTY else ""
|
|
249
|
+
Y = "\033[0;33m" if _TTY else ""
|
|
250
|
+
G = "\033[0;32m" if _TTY else ""
|
|
251
|
+
D = "\033[0;90m" if _TTY else ""
|
|
252
|
+
RST = "\033[0m" if _TTY else ""
|
|
213
253
|
|
|
214
254
|
def color_pct(pct):
|
|
215
255
|
p = int(pct)
|
|
@@ -260,7 +300,8 @@ def cmd_status(raw_json=False):
|
|
|
260
300
|
def cmd_daemon(interval: int = DAEMON_INTERVAL):
|
|
261
301
|
"""Run in foreground, refresh every `interval` seconds."""
|
|
262
302
|
signal.signal(signal.SIGINT, lambda *_: sys.exit(0))
|
|
263
|
-
|
|
303
|
+
if hasattr(signal, "SIGTERM"):
|
|
304
|
+
signal.signal(signal.SIGTERM, lambda *_: sys.exit(0))
|
|
264
305
|
|
|
265
306
|
print(f"codex-cli-usage daemon started (refreshing every {interval}s)")
|
|
266
307
|
print(f"Writing to {USAGE_FILE}")
|
|
@@ -306,11 +347,11 @@ def _get_cached_usage(max_age: int = DAEMON_INTERVAL) -> dict:
|
|
|
306
347
|
|
|
307
348
|
def cmd_statusline():
|
|
308
349
|
"""Statusline command. Reads cached usage and prints compact summary."""
|
|
309
|
-
R = "\033[0;31m"
|
|
310
|
-
Y = "\033[0;33m"
|
|
311
|
-
G = "\033[0;32m"
|
|
312
|
-
D = "\033[0;90m"
|
|
313
|
-
RST = "\033[0m"
|
|
350
|
+
R = "\033[0;31m" if _TTY else ""
|
|
351
|
+
Y = "\033[0;33m" if _TTY else ""
|
|
352
|
+
G = "\033[0;32m" if _TTY else ""
|
|
353
|
+
D = "\033[0;90m" if _TTY else ""
|
|
354
|
+
RST = "\033[0m" if _TTY else ""
|
|
314
355
|
|
|
315
356
|
def color_pct(pct: int) -> str:
|
|
316
357
|
c = R if pct >= 70 else Y if pct >= 50 else G
|
|
File without changes
|
|
File without changes
|