Update all code and documentation to use deacon/ instead of daemon/ for lifecycle mail targets: - internal/cmd/handoff.go: getManager() returns deacon/ for Mayor/Witness - internal/daemon/lifecycle.go: ProcessLifecycleRequests uses deacon/ inbox - docs/architecture.md: update all references in lifecycle docs - scripts/mayor-respawn-daemon.sh: use BD_IDENTITY=deacon for mail commands 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
165 lines
3.9 KiB
Bash
Executable File
165 lines
3.9 KiB
Bash
Executable File
#!/bin/bash
|
|
# Mayor Respawn Daemon
|
|
# Watches for restart requests and respawns the mayor session
|
|
#
|
|
# Usage: mayor-respawn-daemon.sh [start|stop|status]
|
|
#
|
|
# The daemon monitors for mail to "deacon/" with subject containing "RESTART".
|
|
# When found, it:
|
|
# 1. Acknowledges the mail
|
|
# 2. Waits 5 seconds (for handoff mail to be sent)
|
|
# 3. Runs `gt mayor restart`
|
|
|
|
DAEMON_NAME="gt-mayor-respawn"
|
|
PID_FILE="/tmp/${DAEMON_NAME}.pid"
|
|
LOG_FILE="/tmp/${DAEMON_NAME}.log"
|
|
CHECK_INTERVAL=10 # seconds between mail checks
|
|
TOWN_ROOT="${GT_TOWN_ROOT:-/Users/stevey/gt}"
|
|
|
|
log() {
|
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG_FILE"
|
|
}
|
|
|
|
check_for_restart() {
|
|
cd "$TOWN_ROOT" || return 1
|
|
|
|
# Check inbox for deacon identity - look for RESTART subject
|
|
# Set BD_IDENTITY=deacon so bd mail knows which inbox to check
|
|
local inbox
|
|
inbox=$(BD_IDENTITY=deacon bd mail inbox --json 2>/dev/null)
|
|
|
|
if [ -z "$inbox" ] || [ "$inbox" = "null" ] || [ "$inbox" = "[]" ]; then
|
|
return 1
|
|
fi
|
|
|
|
# Parse JSON to find RESTART messages
|
|
# Note: bd mail returns "title" not "subject" (beads uses title for message subjects)
|
|
local msg_id
|
|
msg_id=$(echo "$inbox" | jq -r '.[] | select(.title | test("RESTART"; "i")) | .id' 2>/dev/null | head -1)
|
|
|
|
if [ -n "$msg_id" ] && [ "$msg_id" != "null" ]; then
|
|
log "Found restart request: $msg_id"
|
|
|
|
# Acknowledge the message
|
|
BD_IDENTITY=deacon bd mail ack "$msg_id" 2>/dev/null
|
|
log "Acknowledged restart request"
|
|
|
|
# Wait for handoff to complete
|
|
sleep 5
|
|
|
|
# Restart mayor (just sends Ctrl-C, loop handles respawn)
|
|
log "Triggering mayor respawn..."
|
|
gt mayor restart 2>&1 | while read -r line; do log "$line"; done
|
|
log "Mayor respawn triggered"
|
|
|
|
return 0
|
|
fi
|
|
|
|
return 1
|
|
}
|
|
|
|
daemon_loop() {
|
|
log "Daemon starting, watching for restart requests..."
|
|
|
|
while true; do
|
|
if check_for_restart; then
|
|
log "Restart handled, continuing watch..."
|
|
fi
|
|
sleep "$CHECK_INTERVAL"
|
|
done
|
|
}
|
|
|
|
start_daemon() {
|
|
if [ -f "$PID_FILE" ]; then
|
|
local pid
|
|
pid=$(cat "$PID_FILE")
|
|
if kill -0 "$pid" 2>/dev/null; then
|
|
echo "Daemon already running (PID $pid)"
|
|
return 1
|
|
fi
|
|
rm -f "$PID_FILE"
|
|
fi
|
|
|
|
# Start daemon in background using the script itself
|
|
nohup "$0" run > /dev/null 2>&1 &
|
|
|
|
local pid=$!
|
|
echo "$pid" > "$PID_FILE"
|
|
echo "Started mayor respawn daemon (PID $pid)"
|
|
echo "Log: $LOG_FILE"
|
|
}
|
|
|
|
run_daemon() {
|
|
# Called when script is invoked with "run"
|
|
echo $$ > "$PID_FILE"
|
|
daemon_loop
|
|
}
|
|
|
|
stop_daemon() {
|
|
if [ ! -f "$PID_FILE" ]; then
|
|
echo "Daemon not running (no PID file)"
|
|
return 1
|
|
fi
|
|
|
|
local pid
|
|
pid=$(cat "$PID_FILE")
|
|
|
|
if kill -0 "$pid" 2>/dev/null; then
|
|
kill "$pid"
|
|
rm -f "$PID_FILE"
|
|
echo "Stopped daemon (PID $pid)"
|
|
else
|
|
rm -f "$PID_FILE"
|
|
echo "Daemon was not running (stale PID file removed)"
|
|
fi
|
|
}
|
|
|
|
daemon_status() {
|
|
if [ ! -f "$PID_FILE" ]; then
|
|
echo "Daemon not running"
|
|
return 1
|
|
fi
|
|
|
|
local pid
|
|
pid=$(cat "$PID_FILE")
|
|
|
|
if kill -0 "$pid" 2>/dev/null; then
|
|
echo "Daemon running (PID $pid)"
|
|
echo "Log: $LOG_FILE"
|
|
if [ -f "$LOG_FILE" ]; then
|
|
echo ""
|
|
echo "Recent log entries:"
|
|
tail -5 "$LOG_FILE"
|
|
fi
|
|
return 0
|
|
else
|
|
rm -f "$PID_FILE"
|
|
echo "Daemon not running (stale PID file removed)"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
case "${1:-}" in
|
|
start)
|
|
start_daemon
|
|
;;
|
|
stop)
|
|
stop_daemon
|
|
;;
|
|
status)
|
|
daemon_status
|
|
;;
|
|
restart)
|
|
stop_daemon 2>/dev/null
|
|
start_daemon
|
|
;;
|
|
run)
|
|
# Internal: called when daemon starts itself in background
|
|
run_daemon
|
|
;;
|
|
*)
|
|
echo "Usage: $0 {start|stop|status|restart}"
|
|
exit 1
|
|
;;
|
|
esac
|