Compare commits

..

6 Commits

Author SHA1 Message Date
salt aeeb4042eb Dull the brightness of "critical" codex statuses 2026-06-20 01:26:30 -05:00
salt 8e974f01bb Use reset time instead of label for RL periods 2026-06-20 00:24:57 -05:00
salt 42d9758ecc Make scrape fails on the AI rate limit dash non-critical 2026-06-19 17:12:59 -05:00
salt b34d5b1d97 Trim script 2026-06-15 00:08:47 -05:00
salt ff86eeff4b Ignore pycache 2026-06-15 00:08:41 -05:00
salt ff30800337 Tweaks 2026-06-15 00:05:29 -05:00
4 changed files with 18 additions and 81 deletions
+3 -1
View File
@@ -61,7 +61,7 @@
"margin-bottom": 16, "margin-bottom": 16,
"margin-left": 16, "margin-left": 16,
"margin-right": 16, "margin-right": 16,
"modules-left": ["gamemode", "battery", "temperature", "cpu", "memory", "network", "custom/codex-primary", "custom/codex-secondary"], "modules-left": ["gamemode", "battery", "temperature", "cpu", "memory", "custom/codex-primary", "custom/codex-secondary", "network"],
"modules-center": [], "modules-center": [],
"modules-right": ["mpris", "pulseaudio", "custom/output-device", "backlight", "idle_inhibitor", "clock"], "modules-right": ["mpris", "pulseaudio", "custom/output-device", "backlight", "idle_inhibitor", "clock"],
"clock": { "clock": {
@@ -160,6 +160,7 @@
"return-type": "json", "return-type": "json",
"exec": "$HOME/.config/waybar/scripts/openai-rate.py --window primary", "exec": "$HOME/.config/waybar/scripts/openai-rate.py --window primary",
"exec-if": "test -r ~/.codex/auth.json", "exec-if": "test -r ~/.codex/auth.json",
"escape": false,
"format": " {}" "format": " {}"
}, },
"custom/codex-secondary": { "custom/codex-secondary": {
@@ -167,6 +168,7 @@
"return-type": "json", "return-type": "json",
"exec": "$HOME/.config/waybar/scripts/openai-rate.py --window secondary", "exec": "$HOME/.config/waybar/scripts/openai-rate.py --window secondary",
"exec-if": "test -r ~/.codex/auth.json", "exec-if": "test -r ~/.codex/auth.json",
"escape": false,
"format": " {}" "format": " {}"
}, },
"custom/backup": { "custom/backup": {
@@ -0,0 +1 @@
__pycache__
+13 -77
View File
@@ -17,6 +17,10 @@ def waybar(text, klass="good", tooltip=None):
sys.exit(0) sys.exit(0)
def unknown(tooltip):
waybar('unk <span font-size="7pt">--</span>', "good", tooltip)
def load_auth(): def load_auth():
auth_path = Path(os.environ.get("OPENAI_AUTH_FILE", "~/.codex/auth.json")).expanduser() auth_path = Path(os.environ.get("OPENAI_AUTH_FILE", "~/.codex/auth.json")).expanduser()
auth = {} auth = {}
@@ -69,11 +73,11 @@ def fetch_usage(token, account_id):
return json.load(res) return json.load(res)
except urllib.error.HTTPError as exc: except urllib.error.HTTPError as exc:
detail = exc.read().decode("utf-8", "replace")[:240] detail = exc.read().decode("utf-8", "replace")[:240]
waybar("AI rate failed", "critical", f"Usage endpoint returned HTTP {exc.code}\n{detail}") unknown(f"Usage endpoint returned HTTP {exc.code}\n{detail}")
except (OSError, TimeoutError) as exc: except (OSError, TimeoutError) as exc:
waybar("AI rate failed", "critical", f"Could not reach Codex usage endpoint\n{exc}") unknown(f"Could not reach Codex usage endpoint\n{exc}")
except json.JSONDecodeError as exc: except json.JSONDecodeError as exc:
waybar("AI rate unreadable", "critical", f"Usage endpoint returned invalid JSON\n{exc}") unknown(f"Usage endpoint returned invalid JSON\n{exc}")
def window_label(seconds): def window_label(seconds):
@@ -135,48 +139,14 @@ def format_window(name, window):
tooltip += f", resets in {reset}" tooltip += f", resets in {reset}"
return { return {
"label": label, "label": label,
"reset": reset or "--",
"left": left, "left": left,
"text": f"{left}% {label}",
"used": used, "used": used,
"tooltip": tooltip, "tooltip": tooltip,
} }
def credit_text(credits): def output_window(data, source, selector):
if not isinstance(credits, dict) or not credits.get("has_credits"):
return None
if credits.get("unlimited"):
return "credits unlimited"
balance = credits.get("balance")
if balance is None:
return "credits enabled"
try:
return f"credits {round(float(balance))}"
except (TypeError, ValueError):
return f"credits {balance}"
def spend_control_text(spend_control):
limit = (spend_control or {}).get("individual_limit")
if not isinstance(limit, dict):
return None
remaining = limit.get("remaining_percent")
used = limit.get("used")
cap = limit.get("limit")
reset = reset_text(limit.get("reset_after_seconds"))
if not isinstance(remaining, int):
return None
text = f"monthly credits: {100 - remaining}% used"
if used and cap:
text += f" ({used}/{cap})"
if reset:
text += f", resets in {reset}"
return text
def selected_window_output(data, source, selector):
rate_limit = data.get("rate_limit") or {} rate_limit = data.get("rate_limit") or {}
window = format_window(selector, rate_limit.get(f"{selector}_window")) window = format_window(selector, rate_limit.get(f"{selector}_window"))
if not window: if not window:
@@ -184,45 +154,15 @@ def selected_window_output(data, source, selector):
klass = usage_class(window["used"], rate_limit.get("limit_reached")) klass = usage_class(window["used"], rate_limit.get("limit_reached"))
tooltip = [window["tooltip"], f"{window['left']}% remaining", f"source: {source}"] tooltip = [window["tooltip"], f"{window['left']}% remaining", f"source: {source}"]
waybar(f"{window['left']}% {window['label']}", klass, "\n".join(tooltip)) waybar(f"{window['left']}% <span font-size=\"7pt\">{window['reset']}</span>", klass, "\n".join(tooltip))
def combined_output(data, source):
rate_limit = data.get("rate_limit") or {}
windows = [
format_window("primary", rate_limit.get("primary_window")),
format_window("secondary", rate_limit.get("secondary_window")),
]
windows = [window for window in windows if window]
parts = [window["text"] for window in windows]
credits = credit_text(data.get("credits"))
if credits:
parts.append(credits)
if not parts:
waybar("AI n/a", "warning", f"No displayable usage data\nsource: {source}")
worst_used = max(window["used"] for window in windows) if windows else 0
klass = usage_class(worst_used, rate_limit.get("limit_reached"))
tooltip = [window["tooltip"] for window in windows]
spend = spend_control_text(data.get("spend_control"))
if credits:
tooltip.append(credits)
if spend:
tooltip.append(spend)
tooltip.append(f"source: {source}")
waybar(f"AI {' '.join(parts)}", klass, "\n".join(tooltip))
def parse_args(): def parse_args():
parser = ArgumentParser(description="Waybar Codex rate-limit widget") parser = ArgumentParser(description="Waybar Codex rate-limit widget")
parser.add_argument( parser.add_argument(
"--window", "--window",
choices=("primary", "secondary", "all"), choices=("primary", "secondary"),
default="all", required=True,
help="usage window to display", help="usage window to display",
) )
return parser.parse_args() return parser.parse_args()
@@ -232,11 +172,7 @@ def main():
args = parse_args() args = parse_args()
token, account_id, source = load_auth() token, account_id, source = load_auth()
data = fetch_usage(token, account_id) data = fetch_usage(token, account_id)
output_window(data, source, args.window)
if args.window == "all":
combined_output(data, source)
else:
selected_window_output(data, source, args.window)
if __name__ == "__main__": if __name__ == "__main__":
+1 -3
View File
@@ -253,7 +253,5 @@ window#waybar.fullscreen #window {
} }
#custom-codex-primary.critical, #custom-codex-primary.critical,
#custom-codex-secondary.critical { #custom-codex-secondary.critical {
color: #282828; color: #fb4934;
background: #fb4934;
border-radius: 8px;
} }