cdx-manager 0.10.0 → 0.11.0
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.
- package/README.md +6 -8
- package/bin/cdx +2 -11
- package/changelogs/CHANGELOGS_0_11_0.md +51 -0
- package/checksums/release-archives.json +4 -0
- package/install.ps1 +12 -19
- package/install.sh +6 -29
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/claude_refresh.py +17 -33
- package/src/cli.py +5 -36
- package/src/cli_args.py +14 -12
- package/src/cli_commands.py +30 -17
- package/src/cli_helpers.py +26 -38
- package/src/cli_view.py +5 -27
- package/src/codex_usage.py +14 -8
- package/src/notify.py +6 -10
- package/src/provider_runtime.py +58 -14
- package/src/session_service.py +131 -57
- package/src/session_store.py +2 -2
- package/src/status_source.py +47 -25
package/src/session_store.py
CHANGED
|
@@ -294,8 +294,8 @@ def create_session_store(base_dir):
|
|
|
294
294
|
continue
|
|
295
295
|
try:
|
|
296
296
|
entry = json.loads(line)
|
|
297
|
-
except json.JSONDecodeError
|
|
298
|
-
|
|
297
|
+
except json.JSONDecodeError:
|
|
298
|
+
continue
|
|
299
299
|
if session_name and entry.get("session_name") != session_name:
|
|
300
300
|
continue
|
|
301
301
|
entries.append(entry)
|
package/src/status_source.py
CHANGED
|
@@ -20,10 +20,6 @@ _KEY_VALUE_PATTERNS = [
|
|
|
20
20
|
("remaining_5h_pct", re.compile(r"remaining_?5h_pct\s*[:=]\s*(\d{1,3})%?", re.I)),
|
|
21
21
|
("remaining_week_pct", re.compile(r"remaining_?week_pct\s*[:=]\s*(\d{1,3})%?", re.I)),
|
|
22
22
|
("credits", re.compile(r"credits?\s*[:=]\s*(\d[\d, ]*(?:\.\d+)?)\s*(?:credits?)?", re.I)),
|
|
23
|
-
("remaining_5h_pct", re.compile(r"5h\s+limit\s*:\s*\[[^\]]*\]\s*(\d{1,3})%\s*left", re.I)),
|
|
24
|
-
("remaining_week_pct", re.compile(r"weekly\s+limit\s*:\s*\[[^\]]*\]\s*(\d{1,3})%\s*left", re.I)),
|
|
25
|
-
("remaining_5h_pct", re.compile(r"5h\s+limit\s*:\s*\[[^\]]*\]\s*(\d{1,3})(?:%|\b)", re.I)),
|
|
26
|
-
("remaining_week_pct", re.compile(r"weekly\s+limit\s*:\s*\[[^\]]*\]\s*(\d{1,3})(?:%|\b)", re.I)),
|
|
27
23
|
("usage_pct", re.compile(r"usage\s*[:=]\s*(\d{1,3})%", re.I)),
|
|
28
24
|
("usage_pct", re.compile(r"current\s*[:=]\s*(\d{1,3})%", re.I)),
|
|
29
25
|
("remaining_5h_pct", re.compile(r"5h(?:\s+remaining)?\s*[:=]\s*(\d{1,3})%", re.I)),
|
|
@@ -32,6 +28,14 @@ _KEY_VALUE_PATTERNS = [
|
|
|
32
28
|
("remaining_week_pct", re.compile(r"remaining\s+week\s*[:=]\s*(\d{1,3})%", re.I)),
|
|
33
29
|
]
|
|
34
30
|
|
|
31
|
+
_CODEX_LIMIT_PERCENT_PATTERNS = [
|
|
32
|
+
("remaining_5h_pct", re.compile(r"5h\s+limit\s*:\s*\[[^\]]*\]\s*(\d{1,3})%\s*left", re.I)),
|
|
33
|
+
("remaining_5h_pct", re.compile(r"5h\s+limit\s*:\s*\[[^\]]*\]\s*(\d{1,3})(?:%|\b)", re.I)),
|
|
34
|
+
("remaining_week_pct", re.compile(r"weekly\s+limit\s*:\s*\[[^\]]*\]\s*(\d{1,3})%\s*left", re.I)),
|
|
35
|
+
("remaining_week_pct", re.compile(r"weekly\s+limit\s*:\s*\[[^\]]*\]\s*(\d{1,3})(?:%|\b)", re.I)),
|
|
36
|
+
]
|
|
37
|
+
_KEY_VALUE_PATTERNS.extend(_CODEX_LIMIT_PERCENT_PATTERNS)
|
|
38
|
+
|
|
35
39
|
|
|
36
40
|
def _strip_ansi(text):
|
|
37
41
|
return _ANSI_ESCAPE.sub("", str(text or ""))
|
|
@@ -103,6 +107,27 @@ def _is_zero_credit_balance(value):
|
|
|
103
107
|
return False
|
|
104
108
|
|
|
105
109
|
|
|
110
|
+
def _get_structured_rate_limit_window(rate_limits, duration_mins, fallback_key):
|
|
111
|
+
for key in ("primary", "secondary"):
|
|
112
|
+
window = rate_limits.get(key) or {}
|
|
113
|
+
if window.get("windowDurationMins") == duration_mins:
|
|
114
|
+
return window
|
|
115
|
+
if window.get("window_minutes") == duration_mins:
|
|
116
|
+
return window
|
|
117
|
+
fallback = rate_limits.get(fallback_key) or {}
|
|
118
|
+
if "windowDurationMins" in fallback or "window_minutes" in fallback:
|
|
119
|
+
return {}
|
|
120
|
+
return fallback
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _get_rate_limit_used_percent(window):
|
|
124
|
+
return window.get("used_percent", window.get("usedPercent"))
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _get_rate_limit_reset_at(window):
|
|
128
|
+
return window.get("resets_at", window.get("resetsAt"))
|
|
129
|
+
|
|
130
|
+
|
|
106
131
|
def _extract_structured_rate_limits(record):
|
|
107
132
|
if not isinstance(record, dict):
|
|
108
133
|
return None
|
|
@@ -111,25 +136,27 @@ def _extract_structured_rate_limits(record):
|
|
|
111
136
|
if not isinstance(rate_limits, dict):
|
|
112
137
|
return None
|
|
113
138
|
|
|
114
|
-
|
|
115
|
-
|
|
139
|
+
five_hour = _get_structured_rate_limit_window(rate_limits, 300, "primary")
|
|
140
|
+
weekly = _get_structured_rate_limit_window(rate_limits, 10080, "secondary")
|
|
116
141
|
credits = rate_limits.get("credits") or {}
|
|
117
142
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
remaining_5h_pct = None if
|
|
121
|
-
remaining_week_pct = None if
|
|
143
|
+
five_hour_used = _coerce_percentage(_get_rate_limit_used_percent(five_hour))
|
|
144
|
+
weekly_used = _coerce_percentage(_get_rate_limit_used_percent(weekly))
|
|
145
|
+
remaining_5h_pct = None if five_hour_used is None else max(0, 100 - five_hour_used)
|
|
146
|
+
remaining_week_pct = None if weekly_used is None else max(0, 100 - weekly_used)
|
|
122
147
|
|
|
123
148
|
result = {
|
|
124
|
-
"usage_pct":
|
|
149
|
+
"usage_pct": five_hour_used if five_hour_used is not None else weekly_used,
|
|
125
150
|
"remaining_5h_pct": remaining_5h_pct,
|
|
126
151
|
"remaining_week_pct": remaining_week_pct,
|
|
127
152
|
"credits": None,
|
|
128
|
-
"reset_5h_at": _normalize_timestamp_value(
|
|
129
|
-
"reset_week_at": _normalize_timestamp_value(
|
|
153
|
+
"reset_5h_at": _normalize_timestamp_value(_get_rate_limit_reset_at(five_hour)),
|
|
154
|
+
"reset_week_at": _normalize_timestamp_value(_get_rate_limit_reset_at(weekly)),
|
|
130
155
|
"reset_at": None,
|
|
131
156
|
"raw_status_text": json.dumps(rate_limits, sort_keys=True),
|
|
132
157
|
}
|
|
158
|
+
if not five_hour and weekly:
|
|
159
|
+
result["_skip_5h_backfill"] = True
|
|
133
160
|
|
|
134
161
|
balance = credits.get("balance")
|
|
135
162
|
if balance not in (None, "") and not (
|
|
@@ -496,18 +523,10 @@ def extract_named_statuses_from_text(text):
|
|
|
496
523
|
break
|
|
497
524
|
|
|
498
525
|
for line in lines:
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
if m and "remaining_5h_pct" not in result:
|
|
504
|
-
result["remaining_5h_pct"] = int(m[1])
|
|
505
|
-
m = re.search(r"weekly\s+limit\s*:\s*\[[^\]]*\]\s*(\d{1,3})%\s*left", line, re.I)
|
|
506
|
-
if m and "remaining_week_pct" not in result:
|
|
507
|
-
result["remaining_week_pct"] = int(m[1])
|
|
508
|
-
m = re.search(r"weekly\s+limit\s*:\s*\[[^\]]*\]\s*(\d{1,3})(?:%|\b)", line, re.I)
|
|
509
|
-
if m and "remaining_week_pct" not in result:
|
|
510
|
-
result["remaining_week_pct"] = int(m[1])
|
|
526
|
+
for field, pattern in _CODEX_LIMIT_PERCENT_PATTERNS:
|
|
527
|
+
m = pattern.search(line)
|
|
528
|
+
if m and field not in result:
|
|
529
|
+
result[field] = int(m[1])
|
|
511
530
|
|
|
512
531
|
if "remaining_5h_pct" in result and "usage_pct" not in result:
|
|
513
532
|
result["usage_pct"] = max(0, 100 - result["remaining_5h_pct"])
|
|
@@ -640,6 +659,8 @@ _STATUS_VALUE_FIELDS = (
|
|
|
640
659
|
|
|
641
660
|
def _backfill_missing_fields(target, source):
|
|
642
661
|
for field in _STATUS_VALUE_FIELDS:
|
|
662
|
+
if target.get("_skip_5h_backfill") and field in ("remaining_5h_pct", "reset_5h_at"):
|
|
663
|
+
continue
|
|
643
664
|
if target.get(field) is None and source.get(field) is not None:
|
|
644
665
|
target[field] = source[field]
|
|
645
666
|
|
|
@@ -694,6 +715,7 @@ def find_latest_status_artifact(
|
|
|
694
715
|
"reset_week_at": candidate["structured"].get("reset_week_at"),
|
|
695
716
|
"reset_at": candidate["structured"].get("reset_at"),
|
|
696
717
|
"raw_status_text": candidate["structured"].get("raw_status_text"),
|
|
718
|
+
"_skip_5h_backfill": candidate["structured"].get("_skip_5h_backfill"),
|
|
697
719
|
}
|
|
698
720
|
if not parsed:
|
|
699
721
|
continue
|