#!/usr/bin/env bash # restore-ocaml.sh — print recovery state for the OCaml-on-SX loop. # # The loop runs as a Claude Code instance inside a tmux session named `ocaml`, # operating in a git worktree at /root/rose-ash-loops/ocaml on branch # loops/ocaml. This script shows you where things stand. To respawn, see the # bottom of the output. # # Usage: # bash plans/restore-ocaml.sh # status snapshot # bash plans/restore-ocaml.sh --print # also cat the briefing # set -uo pipefail cd "$(dirname "$0")/.." WT="/root/rose-ash-loops/ocaml" echo "=== ocaml loop state ===" echo if [ -d "$WT" ]; then echo "Worktree: $WT" echo "Branch: $(git -C "$WT" rev-parse --abbrev-ref HEAD 2>/dev/null || echo '?')" echo "HEAD: $(git -C "$WT" log -1 --oneline 2>/dev/null || echo '?')" else echo "Worktree: MISSING ($WT)" echo " Recreate with:" echo " git worktree add /root/rose-ash-loops/ocaml -b loops/ocaml architecture" fi echo echo "=== Recent commits on lib/ocaml/ + plan ===" if [ -d "$WT" ]; then git -C "$WT" log -15 --oneline -- lib/ocaml/ plans/ocaml-on-sx.md plans/agent-briefings/ocaml-loop.md 2>/dev/null \ || echo " (none yet)" else echo " (worktree missing)" fi echo echo "=== lib/ocaml/ contents ===" if [ -d "$WT/lib/ocaml" ]; then ls -1 "$WT/lib/ocaml/" 2>/dev/null | sed 's/^/ /' else echo " (lib/ocaml/ does not exist yet — Phase 1 not started)" fi echo echo "=== lib/guest/ prerequisites ===" for f in lib/guest/lex.sx lib/guest/pratt.sx lib/guest/match.sx lib/guest/layout.sx lib/guest/hm.sx; do if [ -f "$f" ]; then printf " ✓ %s (%d lines)\n" "$f" "$(wc -l < "$f")" else printf " ✗ %s MISSING\n" "$f" fi done echo echo "=== Plan progress (phase checkboxes) ===" if [ -f plans/ocaml-on-sx.md ]; then awk '/^### Phase / {phase=$0; print " " phase; phase_seen=1; next} /^- \[/ && phase_seen { print " " $0 } /^## [^#]/ {phase_seen=0}' plans/ocaml-on-sx.md \ | head -80 else echo " plans/ocaml-on-sx.md NOT found" fi echo echo "=== Tests + scoreboard (Phase 5.1+) ===" if [ -d "$WT/lib/ocaml/tests" ]; then ls -1 "$WT/lib/ocaml/tests/" 2>/dev/null | sed 's/^/ /' else echo " (no tests yet)" fi if [ -f "$WT/lib/ocaml/scoreboard.json" ]; then echo " ✓ scoreboard.json present" python3 -c "import json try: d=json.load(open('$WT/lib/ocaml/scoreboard.json')) t=d.get('totals',d.get('overall',{})) print(f\" totals: pass={t.get('pass','?')} fail={t.get('fail','?')}\") except Exception as e: print(f' (read error: {e})')" 2>/dev/null else echo " (no scoreboard yet — Phase 5.1 not landed)" fi echo echo "=== sx_server.exe ===" if [ -x hosts/ocaml/_build/default/bin/sx_server.exe ]; then echo " ✓ built" else echo " ✗ NOT built — loop conformance runs need it. Run: sx_build target=ocaml" fi echo echo "=== tmux session 'ocaml' ===" if command -v tmux >/dev/null && tmux has-session -t ocaml 2>/dev/null; then echo " ✓ session live" echo " Attach: tmux attach -t ocaml" echo " Last 8 visible lines:" tmux capture-pane -t ocaml -p 2>/dev/null \ | grep -v '^[[:space:]]*$' \ | tail -8 \ | sed 's/^/ /' else echo " ✗ session not running" fi echo echo "=== Remote loops/ocaml ===" if git ls-remote --exit-code origin loops/ocaml >/dev/null 2>&1; then echo " ✓ origin/loops/ocaml exists" if [ -d "$WT" ]; then AHEAD=$(git -C "$WT" rev-list --count origin/loops/ocaml..HEAD 2>/dev/null || echo "?") BEHIND=$(git -C "$WT" rev-list --count HEAD..origin/loops/ocaml 2>/dev/null || echo "?") echo " local ahead: $AHEAD, local behind: $BEHIND" fi else echo " (origin/loops/ocaml not yet pushed)" fi echo echo "=== Briefing ===" [ -f plans/agent-briefings/ocaml-loop.md ] \ && echo " plans/agent-briefings/ocaml-loop.md" \ || echo " briefing NOT found" echo echo "=== To respawn ===" cat <<'EOF' If the worktree is missing: git worktree add /root/rose-ash-loops/ocaml -b loops/ocaml architecture # ALWAYS patch .mcp.json immediately — fresh worktrees have no _build/, # so the relative-path mcp_tree.exe will fail and won't reconnect from # inside a running claude. Use the main repo's binary via absolute path: sed -i 's|"./hosts/ocaml/_build/default/bin/mcp_tree.exe"|"/root/rose-ash/hosts/ocaml/_build/default/bin/mcp_tree.exe"|' \ /root/rose-ash-loops/ocaml/.mcp.json If the tmux session died: tmux new-session -d -s ocaml -c /root/rose-ash-loops/ocaml tmux send-keys -t ocaml 'claude' Enter # wait until the Claude UI box appears, then: tmux send-keys -t ocaml 'You are the OCaml-on-SX loop runner. Read /root/rose-ash/plans/agent-briefings/ocaml-loop.md in full and follow the iteration protocol indefinitely. Run the pre-flight check first; partial-kit-shipped status on lib-guest Steps 5-8 is expected and fine. Worktree: /root/rose-ash-loops/ocaml on branch loops/ocaml. Push to origin/loops/ocaml after every commit. Never push to main or architecture. Resume from the first unchecked [ ] in plans/ocaml-on-sx.md.' Enter Enter Note: on first run the loop will hit a permission prompt to read the briefing outside the worktree. Press "2" to allow agent-briefings/ for the session. If the session is alive but stuck, attach with `tmux attach -t ocaml` and unstick manually. The plan file is the source of truth — the loop reads it fresh every iteration and picks up wherever the queue left off. EOF if [ "${1:-}" = "--print" ]; then echo echo "=== Briefing contents ===" [ -f plans/agent-briefings/ocaml-loop.md ] && cat plans/agent-briefings/ocaml-loop.md fi