152 lines
4.7 KiB
Bash
Executable File
152 lines
4.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# ── Timmy Status Sidebar ───────────────────────────────────────────────
|
|
# Compact current-state view for the local Hermes + Timmy workflow.
|
|
# ───────────────────────────────────────────────────────────────────────
|
|
|
|
set -euo pipefail
|
|
|
|
GITEA_URL="${GITEA_URL:-http://143.198.27.163:3000}"
|
|
CORE_REPOS="${CORE_REPOS:-Timmy_Foundation/the-nexus Timmy_Foundation/timmy-home Timmy_Foundation/timmy-config Timmy_Foundation/hermes-agent}"
|
|
|
|
for token_file in "$HOME/.hermes/gitea_token_vps" "$HOME/.config/gitea/token" "$HOME/.config/gitea/codex-token"; do
|
|
if [ -f "$token_file" ]; then
|
|
TOKEN=$(cat "$token_file")
|
|
break
|
|
fi
|
|
done
|
|
TOKEN="${TOKEN:-}"
|
|
|
|
B='\033[1m'
|
|
D='\033[2m'
|
|
R='\033[0m'
|
|
G='\033[32m'
|
|
Y='\033[33m'
|
|
RD='\033[31m'
|
|
C='\033[36m'
|
|
|
|
COLS=$(tput cols 2>/dev/null || echo 48)
|
|
hr() { printf "${D}"; printf '─%.0s' $(seq 1 "$COLS"); printf "${R}\n"; }
|
|
|
|
while true; do
|
|
clear
|
|
echo -e "${B}${C} TIMMY STATUS${R} ${D}$(date '+%H:%M:%S')${R}"
|
|
hr
|
|
|
|
python3 - "$HOME/.timmy" "$HOME/.hermes" <<'PY'
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
timmy = Path(sys.argv[1])
|
|
hermes = Path(sys.argv[2])
|
|
|
|
last_tick = timmy / "heartbeat" / "last_tick.json"
|
|
model_health = hermes / "model_health.json"
|
|
checkpoint = timmy / "twitter-archive" / "checkpoint.json"
|
|
|
|
if last_tick.exists():
|
|
try:
|
|
tick = json.loads(last_tick.read_text())
|
|
sev = tick.get("decision", {}).get("severity", "?")
|
|
tick_id = tick.get("tick_id", "?")
|
|
print(f" heartbeat {tick_id} severity={sev}")
|
|
except Exception:
|
|
print(" heartbeat unreadable")
|
|
else:
|
|
print(" heartbeat missing")
|
|
|
|
if model_health.exists():
|
|
try:
|
|
health = json.loads(model_health.read_text())
|
|
provider_ok = health.get("api_responding")
|
|
inference_ok = health.get("inference_ok")
|
|
models = len(health.get("models_loaded", []) or [])
|
|
print(f" model api={provider_ok} inference={inference_ok} models={models}")
|
|
except Exception:
|
|
print(" model unreadable")
|
|
else:
|
|
print(" model missing")
|
|
|
|
if checkpoint.exists():
|
|
try:
|
|
cp = json.loads(checkpoint.read_text())
|
|
print(f" archive batches={cp.get('batches_completed', '?')} next={cp.get('next_offset', '?')} phase={cp.get('phase', '?')}")
|
|
except Exception:
|
|
print(" archive unreadable")
|
|
else:
|
|
print(" archive missing")
|
|
PY
|
|
|
|
hr
|
|
echo -e " ${B}freshness${R}"
|
|
~/.hermes/bin/pipeline-freshness.sh 2>/dev/null | sed 's/^/ /' || echo -e " ${Y}unknown${R}"
|
|
|
|
hr
|
|
echo -e " ${B}review queue${R}"
|
|
python3 - "$GITEA_URL" "$TOKEN" "$CORE_REPOS" <<'PY'
|
|
import json
|
|
import sys
|
|
import urllib.request
|
|
|
|
base = sys.argv[1].rstrip("/")
|
|
token = sys.argv[2]
|
|
repos = sys.argv[3].split()
|
|
headers = {"Authorization": f"token {token}"} if token else {}
|
|
|
|
count = 0
|
|
for repo in repos:
|
|
try:
|
|
req = urllib.request.Request(f"{base}/api/v1/repos/{repo}/issues?state=open&limit=50&type=pulls", headers=headers)
|
|
with urllib.request.urlopen(req, timeout=5) as resp:
|
|
items = json.loads(resp.read().decode())
|
|
for item in items:
|
|
assignees = [a.get("login", "") for a in (item.get("assignees") or [])]
|
|
if any(name in assignees for name in ("Timmy", "allegro")):
|
|
print(f" {repo.split('/',1)[1]:12s} #{item['number']:<4d} {item['title'][:28]}")
|
|
count += 1
|
|
if count >= 6:
|
|
raise SystemExit
|
|
except SystemExit:
|
|
break
|
|
except Exception:
|
|
continue
|
|
if count == 0:
|
|
print(" (clear)")
|
|
PY
|
|
|
|
hr
|
|
echo -e " ${B}unassigned${R}"
|
|
python3 - "$GITEA_URL" "$TOKEN" "$CORE_REPOS" <<'PY'
|
|
import json
|
|
import sys
|
|
import urllib.request
|
|
|
|
base = sys.argv[1].rstrip("/")
|
|
token = sys.argv[2]
|
|
repos = sys.argv[3].split()
|
|
headers = {"Authorization": f"token {token}"} if token else {}
|
|
|
|
count = 0
|
|
for repo in repos:
|
|
try:
|
|
req = urllib.request.Request(f"{base}/api/v1/repos/{repo}/issues?state=open&limit=50&type=issues", headers=headers)
|
|
with urllib.request.urlopen(req, timeout=5) as resp:
|
|
items = json.loads(resp.read().decode())
|
|
for item in items:
|
|
if not item.get("assignees"):
|
|
print(f" {repo.split('/',1)[1]:12s} #{item['number']:<4d} {item['title'][:28]}")
|
|
count += 1
|
|
if count >= 6:
|
|
raise SystemExit
|
|
except SystemExit:
|
|
break
|
|
except Exception:
|
|
continue
|
|
if count == 0:
|
|
print(" (none)")
|
|
PY
|
|
|
|
hr
|
|
sleep 10
|
|
done
|