chore: sync tower-watchdog and tower-session updates
This commit is contained in:
@@ -1,8 +1,13 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# ── Tower Watchdog ─────────────────────────────────────────────────────
|
# ── Tower Watchdog ─────────────────────────────────────────────────────
|
||||||
# Ensures the tower session stays alive. Restarts dead panes.
|
# Ensures the tower session stays alive. Restarts dead panes/windows.
|
||||||
# Run via cron: */5 * * * * ~/hermes-config/bin/tower-watchdog.sh
|
# Run via cron: */5 * * * * ~/hermes-config/bin/tower-watchdog.sh
|
||||||
#
|
#
|
||||||
|
# Layout:
|
||||||
|
# Window 1, Pane 1: tower-hermes.sh (conversation driver)
|
||||||
|
# Window 1, Pane 2: tower-status.sh (status dashboard)
|
||||||
|
# Window 2: tower-timmy.sh (Timmy loop, hidden)
|
||||||
|
#
|
||||||
# Source-controlled: gitea/rockachopa/hermes-config
|
# Source-controlled: gitea/rockachopa/hermes-config
|
||||||
# ───────────────────────────────────────────────────────────────────────
|
# ───────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -17,49 +22,67 @@ log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG"; }
|
|||||||
# If session doesn't exist at all, recreate it
|
# If session doesn't exist at all, recreate it
|
||||||
if ! tmux has-session -t "$SESSION" 2>/dev/null; then
|
if ! tmux has-session -t "$SESSION" 2>/dev/null; then
|
||||||
log "Session '$SESSION' missing. Recreating."
|
log "Session '$SESSION' missing. Recreating."
|
||||||
# Start detached — don't attach (we're in cron)
|
|
||||||
tmux new-session -d -s "$SESSION" -n "tower" -x 200 -y 50
|
tmux new-session -d -s "$SESSION" -n "tower" -x 200 -y 50
|
||||||
tmux split-window -h -t "$SESSION:1.1"
|
tmux split-window -h -p 35 -t "$SESSION:1.1"
|
||||||
tmux select-pane -t "$SESSION:1.1" -T "⚡ Hermes"
|
tmux select-pane -t "$SESSION:1.1" -T "⚡ Tower"
|
||||||
tmux select-pane -t "$SESSION:1.2" -T "🕐 Timmy"
|
tmux select-pane -t "$SESSION:1.2" -T "📊 Status"
|
||||||
tmux select-layout -t "$SESSION:1" even-horizontal
|
|
||||||
tmux send-keys -t "$SESSION:1.1" "$TOWER_BIN/tower-hermes.sh" Enter
|
tmux send-keys -t "$SESSION:1.1" "$TOWER_BIN/tower-hermes.sh" Enter
|
||||||
tmux send-keys -t "$SESSION:1.2" "$TOWER_BIN/tower-timmy.sh" Enter
|
tmux send-keys -t "$SESSION:1.2" "$TOWER_BIN/tower-status.sh" Enter
|
||||||
log "Session recreated with both panes."
|
# Hidden window for Timmy
|
||||||
|
tmux new-window -t "$SESSION" -n "timmy-bg"
|
||||||
|
tmux send-keys -t "$SESSION:2" "$TOWER_BIN/tower-timmy.sh" Enter
|
||||||
|
tmux select-window -t "$SESSION:1"
|
||||||
|
log "Session recreated (conversation + status + timmy-bg)."
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Session exists — check each pane
|
# Session exists — check window 1 panes
|
||||||
PANE_COUNT=$(tmux list-panes -t "$SESSION:1" 2>/dev/null | wc -l | tr -d ' ')
|
PANE_COUNT=$(tmux list-panes -t "$SESSION:1" 2>/dev/null | wc -l | tr -d ' ')
|
||||||
|
|
||||||
if [ "$PANE_COUNT" -lt 2 ]; then
|
if [ "$PANE_COUNT" -lt 2 ]; then
|
||||||
log "Only $PANE_COUNT pane(s). Killing and recreating session."
|
log "Window 1 has only $PANE_COUNT pane(s). Killing and recreating session."
|
||||||
tmux kill-session -t "$SESSION" 2>/dev/null
|
tmux kill-session -t "$SESSION" 2>/dev/null
|
||||||
exec "$0" # re-run to recreate
|
exec "$0" # re-run to recreate
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if the loops are actually running in each pane
|
# Check Hermes loop (window 1, pane 1)
|
||||||
for PANE in 1 2; do
|
HERMES_PID=$(tmux display-message -p -t "$SESSION:1.1" '#{pane_pid}' 2>/dev/null)
|
||||||
PANE_PID=$(tmux display-message -p -t "$SESSION:1.$PANE" '#{pane_pid}' 2>/dev/null)
|
if [ -n "$HERMES_PID" ]; then
|
||||||
if [ -z "$PANE_PID" ]; then
|
CHILDREN=$(pgrep -P "$HERMES_PID" 2>/dev/null | wc -l | tr -d ' ')
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if there's a running process (not just a shell prompt)
|
|
||||||
CHILDREN=$(pgrep -P "$PANE_PID" 2>/dev/null | wc -l | tr -d ' ')
|
|
||||||
if [ "$CHILDREN" -eq 0 ]; then
|
if [ "$CHILDREN" -eq 0 ]; then
|
||||||
if [ "$PANE" -eq 1 ]; then
|
|
||||||
log "Hermes pane idle. Restarting tower-hermes.sh"
|
log "Hermes pane idle. Restarting tower-hermes.sh"
|
||||||
# Clean stale lock
|
|
||||||
rm -f "$HOME/.tower/hermes.lock"
|
rm -f "$HOME/.tower/hermes.lock"
|
||||||
tmux send-keys -t "$SESSION:1.1" "$TOWER_BIN/tower-hermes.sh" Enter
|
tmux send-keys -t "$SESSION:1.1" "$TOWER_BIN/tower-hermes.sh" Enter
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check status pane (window 1, pane 2) — restart if dead
|
||||||
|
STATUS_PID=$(tmux display-message -p -t "$SESSION:1.2" '#{pane_pid}' 2>/dev/null)
|
||||||
|
if [ -n "$STATUS_PID" ]; then
|
||||||
|
CHILDREN=$(pgrep -P "$STATUS_PID" 2>/dev/null | wc -l | tr -d ' ')
|
||||||
|
if [ "$CHILDREN" -eq 0 ]; then
|
||||||
|
log "Status pane idle. Restarting tower-status.sh"
|
||||||
|
tmux send-keys -t "$SESSION:1.2" "$TOWER_BIN/tower-status.sh" Enter
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check Timmy loop (window 2)
|
||||||
|
if ! tmux has-window -t "$SESSION:2" 2>/dev/null; then
|
||||||
|
log "Timmy window missing. Recreating."
|
||||||
|
tmux new-window -t "$SESSION" -n "timmy-bg"
|
||||||
|
tmux send-keys -t "$SESSION:2" "$TOWER_BIN/tower-timmy.sh" Enter
|
||||||
|
tmux select-window -t "$SESSION:1"
|
||||||
else
|
else
|
||||||
|
TIMMY_PID=$(tmux display-message -p -t "$SESSION:2" '#{pane_pid}' 2>/dev/null)
|
||||||
|
if [ -n "$TIMMY_PID" ]; then
|
||||||
|
CHILDREN=$(pgrep -P "$TIMMY_PID" 2>/dev/null | wc -l | tr -d ' ')
|
||||||
|
if [ "$CHILDREN" -eq 0 ]; then
|
||||||
log "Timmy pane idle. Restarting tower-timmy.sh"
|
log "Timmy pane idle. Restarting tower-timmy.sh"
|
||||||
rm -f "$HOME/.tower/timmy.lock"
|
rm -f "$HOME/.tower/timmy.lock"
|
||||||
tmux send-keys -t "$SESSION:1.2" "$TOWER_BIN/tower-timmy.sh" Enter
|
tmux send-keys -t "$SESSION:2" "$TOWER_BIN/tower-timmy.sh" Enter
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
|
||||||
|
|
||||||
# Trim log if > 1000 lines
|
# Trim log if > 1000 lines
|
||||||
if [ -f "$LOG" ] && [ "$(wc -l < "$LOG")" -gt 1000 ]; then
|
if [ -f "$LOG" ] && [ "$(wc -l < "$LOG")" -gt 1000 ]; then
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# ── Tower Session ──────────────────────────────────────────────────────
|
# ── Tower Session ──────────────────────────────────────────────────────
|
||||||
# Two-pane tmux session: Hermes ↔ Timmy conversation loop
|
# Two-pane tmux session: Hermes ↔ Timmy conversation + status dashboard
|
||||||
#
|
#
|
||||||
# Left pane: Hermes (cloud, Claude) talking TO Timmy
|
# Left pane (65%): Hermes loop — drives the conversation, shows both sides
|
||||||
# Right pane: Timmy (local/Anthropic) talking TO Hermes
|
# Right pane (35%): Status dashboard — loop health, message stats, infra
|
||||||
#
|
#
|
||||||
# Communication: file-based message passing via ~/.tower/
|
# Communication: file-based message passing via ~/.tower/
|
||||||
# Self-healing: watchdog checks both panes, restarts if dead
|
# Self-healing: watchdog checks both panes, restarts if dead
|
||||||
@@ -27,26 +27,32 @@ if tmux has-session -t "$SESSION" 2>/dev/null; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Create session with two panes ─────────────────────────────────────
|
# ── Create session with two panes ─────────────────────────────────────
|
||||||
# Left pane: Hermes side of the conversation
|
# Left pane: Hermes conversation loop (drives the conversation, shows both sides)
|
||||||
tmux new-session -d -s "$SESSION" -n "tower" -x 200 -y 50
|
tmux new-session -d -s "$SESSION" -n "tower" -x 200 -y 50
|
||||||
|
|
||||||
# Right pane: Timmy side
|
# Right pane: Status dashboard (35% width)
|
||||||
tmux split-window -h -t "$SESSION:1.1"
|
tmux split-window -h -p 35 -t "$SESSION:1.1"
|
||||||
|
|
||||||
# Set pane titles
|
# Set pane titles
|
||||||
tmux select-pane -t "$SESSION:1.1" -T "⚡ Hermes"
|
tmux select-pane -t "$SESSION:1.1" -T "⚡ Tower"
|
||||||
tmux select-pane -t "$SESSION:1.2" -T "🕐 Timmy"
|
tmux select-pane -t "$SESSION:1.2" -T "📊 Status"
|
||||||
|
|
||||||
# Equal width
|
# ── Start the loops ──────────────────────────────────────────────────
|
||||||
tmux select-layout -t "$SESSION:1" even-horizontal
|
# Pane 1: Hermes loop (conversation driver — shows Hermes & Timmy messages)
|
||||||
|
|
||||||
# ── Start the conversation loops ──────────────────────────────────────
|
|
||||||
tmux send-keys -t "$SESSION:1.1" \
|
tmux send-keys -t "$SESSION:1.1" \
|
||||||
"$TOWER_BIN/tower-hermes.sh" Enter
|
"$TOWER_BIN/tower-hermes.sh" Enter
|
||||||
|
|
||||||
|
# Pane 2: Status dashboard
|
||||||
tmux send-keys -t "$SESSION:1.2" \
|
tmux send-keys -t "$SESSION:1.2" \
|
||||||
|
"$TOWER_BIN/tower-status.sh" Enter
|
||||||
|
|
||||||
|
# Hidden window 2: Timmy loop (no need to watch — status pane monitors health)
|
||||||
|
tmux new-window -t "$SESSION" -n "timmy-bg"
|
||||||
|
tmux send-keys -t "$SESSION:2" \
|
||||||
"$TOWER_BIN/tower-timmy.sh" Enter
|
"$TOWER_BIN/tower-timmy.sh" Enter
|
||||||
|
|
||||||
# Focus left pane (Hermes)
|
# Back to window 1, focus conversation pane
|
||||||
|
tmux select-window -t "$SESSION:1"
|
||||||
tmux select-pane -t "$SESSION:1.1"
|
tmux select-pane -t "$SESSION:1.1"
|
||||||
|
|
||||||
# ── Attach ────────────────────────────────────────────────────────────
|
# ── Attach ────────────────────────────────────────────────────────────
|
||||||
|
|||||||
Reference in New Issue
Block a user