#!/usr/bin/env bash # ── tmux-resume.sh — Cold-start Session Resume ─────────────────────────── # Reads ~/.timmy/tmux-state.json and resumes hermes sessions. # Run at startup to restore pane state after supervisor restart. # ────────────────────────────────────────────────────────────────────────── set -euo pipefail MANIFEST="${HOME}/.timmy/tmux-state.json" if [ ! -f "$MANIFEST" ]; then echo "[tmux-resume] No manifest found at $MANIFEST — starting fresh." exit 0 fi python3 << 'PYEOF' import json, subprocess, os, sys from datetime import datetime, timezone MANIFEST = os.path.expanduser("~/.timmy/tmux-state.json") def run(cmd): try: r = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=30) return r.stdout.strip(), r.returncode except Exception as e: return str(e), 1 def session_exists(name): out, _ = run(f"tmux has-session -t '{name}' 2>&1") return "can't find" not in out.lower() with open(MANIFEST) as f: state = json.load(f) ts = state.get("timestamp", "unknown") age = "unknown" try: t = datetime.fromisoformat(ts.replace("Z", "+00:00")) delta = datetime.now(timezone.utc) - t mins = int(delta.total_seconds() / 60) if mins < 60: age = f"{mins}m ago" else: age = f"{mins//60}h {mins%60}m ago" except: pass print(f"[tmux-resume] Manifest from {age}: {state['summary']['total_sessions']} sessions, " f"{state['summary']['hermes_panes']} hermes panes") restored = 0 skipped = 0 for pane in state.get("panes", []): if not pane.get("is_hermes"): continue addr = pane["address"] # e.g. "BURN:2.3" session = addr.split(":")[0] session_id = pane.get("session_id") profile = pane.get("profile", "default") model = pane.get("model", "") task = pane.get("task", "") # Skip if session already exists (already running) if session_exists(session): print(f" [skip] {addr} — session '{session}' already exists") skipped += 1 continue # Respawn hermes with session resume if we have a session ID if session_id: print(f" [resume] {addr} — profile={profile} model={model} session={session_id}") cmd = f"hermes chat --resume {session_id}" else: print(f" [start] {addr} — profile={profile} model={model} (no session ID)") cmd = f"hermes chat --profile {profile}" # Create tmux session and run hermes run(f"tmux new-session -d -s '{session}' -n '{session}:0'") run(f"tmux send-keys -t '{session}' '{cmd}' Enter") restored += 1 # Write resume log log = { "resumed_at": datetime.now(timezone.utc).isoformat(), "manifest_age": age, "restored": restored, "skipped": skipped, } log_path = os.path.expanduser("~/.timmy/tmux-resume.log") with open(log_path, "w") as f: json.dump(log, f, indent=2) print(f"[tmux-resume] Done: {restored} restored, {skipped} skipped") PYEOF