"""Extract Claude Code's rate-limit windows from a status-line payload. Invoked by `claude-statusline-bridge.sh` with the feed path as argv[1] and the status-line JSON on stdin. Appends only the rate-limit fields to the feed and prints a status line. Must never fail: a status-line command that errors degrades the user's Claude Code session, so every step is guarded and this always exits 0 having printed. """ import json import os import sys # Keep the feed bounded. The probe only needs the newest line; older ones are # superseded snapshots, not history worth keeping. MAX_FEED_BYTES = 256 * 1024 WINDOW_NAMES = ("five_hour", "seven_day") PERCENT_KEYS = ("used_percentage", "utilization", "resets_at") def extract(payload): """Return the record to append: rate-limit fields and nothing else. The payload also carries the session's cost, transcript path, working directory, and model. None of that is Lumbridge's business, and none of it is copied — this builds a fresh dict rather than filtering the original. """ record = {"rate_limits_available": payload.get("rate_limits_available")} limits = payload.get("rate_limits") if not isinstance(limits, dict): return record windows = {} for name in WINDOW_NAMES: window = limits.get(name) if not isinstance(window, dict): continue kept = { key: window[key] for key in PERCENT_KEYS if isinstance(window.get(key), (int, float)) and not isinstance(window.get(key), bool) } if kept: windows[name] = kept if windows: record["rate_limits"] = windows return record def status_line(record): if record.get("rate_limits_available") is False: return "lumbridge · no plan limits on this account" windows = record.get("rate_limits") if not windows: return "lumbridge · no window reported yet" parts = [] for name, label in (("five_hour", "5h"), ("seven_day", "7d")): window = windows.get(name) if not window: continue percent = window.get("used_percentage", window.get("utilization")) if percent is None: continue parts.append(f"{label} {max(0.0, 100.0 - float(percent)):.0f}% left") if not parts: return "lumbridge · no window reported yet" return "lumbridge · " + " · ".join(parts) def append(feed, record): if not feed: return try: # Rotate rather than grow without bound. The probe resets its read # offset when the file shrinks, so a rotation costs one reading. if os.path.exists(feed) and os.path.getsize(feed) > MAX_FEED_BYTES: open(feed, "w").close() # Append so concurrent Claude Code sessions do not clobber each other; # a short line written in append mode lands intact. with open(feed, "a") as handle: handle.write(json.dumps(record, separators=(",", ":")) + "\n") except Exception: pass # A feed we cannot write is not worth breaking a session over. def main(): feed = sys.argv[1] if len(sys.argv) > 1 else "" try: payload = json.load(sys.stdin) except Exception: print("lumbridge · unreadable status payload") return 0 if not isinstance(payload, dict): print("lumbridge · unreadable status payload") return 0 record = extract(payload) append(feed, record) print(status_line(record)) return 0 try: sys.exit(main()) except Exception: # Last resort: never let a status line take a session down. print("lumbridge") sys.exit(0)