Added (all now linked from their live locations): - home_root/.claude/settings.json. The statusLine command now uses $HOME instead of a Linux-only absolute path. - home_root/.claude/bin/ratecheck and home_root/.claude/skills/australis-design. - home_config/zsh/claude-config-dir.zsh and home_root/.local/bin/claude-config-dir-init, the per-repo Claude Code login helper and its seeding script. - home_root/.gitconfig and home_config/git/ignore. - home_root/.zshenv, with the cargo env line guarded so boxes without rust start clean. link-dotfiles --check reports drift without changing anything: tracked files whose live copy is no longer a link (stow dry-run conflicts) and links into this repo that dangle. Exits 1 on drift. Verified against a clean baseline and two planted drifts, a detached .nanorc and a dangling link. .mailmap maps every earlier identity to Vuong Hoang: the repo-local 'Your Name' placeholder config (now removed), host-generated emails, and aider suffixes. CLAUDE.md: the symlink warning now lists every linked file and points at --check. README: documents what is and isn't tracked under .claude, the edit rule, and --check.
65 lines
2.5 KiB
Python
Executable File
65 lines
2.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Read the rate-limit window and say whether a consult may be dispatched.
|
|
|
|
The percentages exist only in the JSON the harness pipes to the statusline; no CLI
|
|
subcommand exposes them and nothing else on disk carries them. `~/.claude/statusline-command.sh`
|
|
tees them to ~/.claude/rate-limits.json on every render (added 2026-09-05, operator directive);
|
|
this reads that file.
|
|
|
|
Exit codes: 0 GO 1 PAUSE 2 UNKNOWN
|
|
|
|
⚠ UNKNOWN is NOT a pause. A stale or missing file means the instrument is broken, and a
|
|
broken instrument that halts every consult is a self-inflicted outage worse than the
|
|
overspend it guards. UNKNOWN proceeds and says so loudly, so the gap is visible rather
|
|
than silently protective.
|
|
"""
|
|
import json, os, sys, time
|
|
|
|
THRESHOLD = 93.0 # advisory default; a project may set its own and say so
|
|
STALE_SECONDS = 900 # the statusline renders constantly in an interactive session
|
|
|
|
PATH = os.path.join(os.environ.get("CLAUDE_CONFIG_DIR") or os.path.expanduser("~/.claude"), "rate-limits.json")
|
|
|
|
|
|
def main() -> int:
|
|
try:
|
|
with open(PATH, encoding="utf-8") as fh:
|
|
d = json.load(fh)
|
|
except FileNotFoundError:
|
|
print(f"UNKNOWN no {PATH} — statusline tee missing or never rendered")
|
|
return 2
|
|
except (OSError, ValueError) as exc:
|
|
print(f"UNKNOWN {PATH} unreadable: {exc}")
|
|
return 2
|
|
|
|
five, seven = d.get("five_hour_pct"), d.get("seven_day_pct")
|
|
age = time.time() - (d.get("written_at") or 0)
|
|
stamp = d.get("written_at_iso", "?")
|
|
|
|
if five is None and seven is None:
|
|
print(f"UNKNOWN both windows null (written {stamp}) — session reported no rate_limits")
|
|
return 2
|
|
if age > STALE_SECONDS:
|
|
print(f"UNKNOWN stale by {age/60:.0f} min (written {stamp}) — "
|
|
f"last seen 5h={five} 7d={seven}; the statusline is not rendering")
|
|
return 2
|
|
|
|
worst = max(v for v in (five, seven) if v is not None)
|
|
which = "5h" if five == worst else "7d"
|
|
line = (f"5h={five if five is not None else '?'}% "
|
|
f"7d={seven if seven is not None else '?'}% "
|
|
f"(age {age/60:.1f} min, threshold {THRESHOLD}%)")
|
|
|
|
if worst >= THRESHOLD:
|
|
reset = d.get(f"{'five_hour' if which == '5h' else 'seven_day'}_resets_at")
|
|
when = (time.strftime("%H:%MZ", time.gmtime(reset)) if reset else "unknown")
|
|
print(f"PAUSE {line} — {which} at {worst}% >= {THRESHOLD}%; resets {when}")
|
|
return 1
|
|
|
|
print(f"GO {line}")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|