Pipeline/scripts/claude-statusline-to-pipeli...

100 lines
3.3 KiB
Python
Raw Normal View History

2026-05-21 04:25:31 -05:00
#!/usr/bin/env python3
"""Forward Claude Code status-line usage windows to Pipeline.
Claude Code passes a JSON snapshot on stdin to status-line commands. This helper
extracts only the documented rate_limits fields and posts them to Pipeline so the
dashboard can show provider-native Current session and All models reset windows.
Required environment:
PIPELINE_API_URL e.g. http://localhost:8001
PIPELINE_AUTH_TOKEN local bearer token or user token
PIPELINE_GATEWAY_ID gateway UUID to attach this local Claude Code session to
Optional environment:
PIPELINE_STATUSLINE_TIMEOUT_SECONDS default: 2
PIPELINE_STATUSLINE_PRINT set to 0 to suppress compact status output
"""
from __future__ import annotations
import json
import os
import sys
import urllib.error
import urllib.request
def _compact_status(payload: dict[str, object]) -> str:
model = payload.get("model")
model_name = "Claude"
if isinstance(model, dict):
display = model.get("display_name")
if isinstance(display, str) and display.strip():
model_name = display.strip()
rate_limits = payload.get("rate_limits")
if not isinstance(rate_limits, dict):
return f"[{model_name}]"
parts: list[str] = []
five = rate_limits.get("five_hour")
if isinstance(five, dict) and isinstance(five.get("used_percentage"), int | float):
parts.append(f"5h {five['used_percentage']:.0f}%")
week = rate_limits.get("seven_day")
if isinstance(week, dict) and isinstance(week.get("used_percentage"), int | float):
parts.append(f"7d {week['used_percentage']:.0f}%")
return f"[{model_name}] {' · '.join(parts)}" if parts else f"[{model_name}]"
def _sanitize(raw: dict[str, object]) -> dict[str, object]:
payload: dict[str, object] = {}
for key in ("session_id", "model", "workspace", "rate_limits"):
value = raw.get(key)
if value is not None:
payload[key] = value
return payload
def main() -> int:
try:
raw = json.load(sys.stdin)
except json.JSONDecodeError:
return 0
if not isinstance(raw, dict):
return 0
payload = _sanitize(raw)
if os.environ.get("PIPELINE_STATUSLINE_PRINT") != "0":
print(_compact_status(payload))
api_url = os.environ.get("PIPELINE_API_URL", "").strip().rstrip("/")
token = os.environ.get("PIPELINE_AUTH_TOKEN", "").strip()
gateway_id = os.environ.get("PIPELINE_GATEWAY_ID", "").strip()
if not api_url or not token or not gateway_id:
return 0
url = f"{api_url}/api/v1/gateways/{gateway_id}/provider-usage/claude/statusline"
body = json.dumps(payload).encode("utf-8")
timeout = float(os.environ.get("PIPELINE_STATUSLINE_TIMEOUT_SECONDS", "2"))
request = urllib.request.Request(
url,
data=body,
method="POST",
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
"User-Agent": "PipelineClaudeStatusline/1.0",
},
)
try:
with urllib.request.urlopen(request, timeout=timeout):
pass
except (OSError, urllib.error.URLError, urllib.error.HTTPError):
# Status-line hooks must never disrupt Claude Code if Pipeline is down.
return 0
return 0
if __name__ == "__main__":
raise SystemExit(main())