#!/usr/bin/env bash # Restore the heavy-duty org watcher after reboot / session loss. # Usage: # ./scripts/restore.sh # create/attach tmux + resume Grok # ./scripts/restore.sh --attach # attach only # ./scripts/restore.sh --status # health snapshot set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" # shellcheck source=lib/common.sh source "${SCRIPT_DIR}/lib/common.sh" mkdir -p "${LOG_DIR}" session_id() { if [[ -f "${STATE_FILE}" ]] && command -v jq >/dev/null 2>&1; then local id id="$(jq -r '.session_id // empty' "${STATE_FILE}" 2>/dev/null || true)" if [[ -n "${id}" && "${id}" != "null" ]]; then echo "${id}" return fi fi echo "" } status() { echo "=== heavy-duty-watcher status ===" echo "dir: ${WATCHER_DIR}" echo "backend: ${FORGE_BACKEND} org: ${ORG} bot: ${BOT_LOGIN}" if [[ -f "${STATE_FILE}" ]]; then jq '{scope, org, bot_login, session_id, last_poll_at, last_poll_summary, health, items: (.items|keys)}' \ "${STATE_FILE}" 2>/dev/null || cat "${STATE_FILE}" else echo "(missing state.json)" fi echo tmux ls 2>/dev/null || echo "(no tmux sessions)" echo case "${FORGE_BACKEND}" in github) echo "gh user: $(gh api user --jq .login 2>/dev/null || echo 'not authenticated')" ;; forgejo) echo "stoke: $(stoke auth status 2>/dev/null | head -n 4 | tr '\n' ' ' || echo 'not authenticated')" ;; esac echo "session_id: $(session_id || true)" [[ -f "${LOG_DIR}/poll.log" ]] && { echo; echo "last poll log:"; tail -n 5 "${LOG_DIR}/poll.log"; } [[ -f "${LOG_DIR}/health.log" ]] && { echo; echo "last health log:"; tail -n 5 "${LOG_DIR}/health.log"; } bash "${WATCHER_DIR}/scripts/health-check.sh" || true } attach_only() { if tmux has-session -t "${TMUX_SESSION}" 2>/dev/null; then exec tmux attach -t "${TMUX_SESSION}" fi echo "tmux session '${TMUX_SESSION}' not running. Run without --attach to start." exit 1 } start_or_attach() { local sid resume_prompt sid="$(session_id)" resume_prompt="$(cat </dev/null; then if ! tmux list-windows -t "${TMUX_SESSION}" -F '#{window_name}' 2>/dev/null | grep -qx 'poll-loop'; then tmux new-window -t "${TMUX_SESSION}" -n poll-loop -c "${WATCHER_DIR}" \ "bash ${WATCHER_DIR}/scripts/poll-loop.sh" fi if ! tmux list-windows -t "${TMUX_SESSION}" -F '#{window_name}' 2>/dev/null | grep -qx 'health-loop'; then tmux new-window -t "${TMUX_SESSION}" -n health-loop -c "${WATCHER_DIR}" \ "bash ${WATCHER_DIR}/scripts/health-loop.sh" fi echo "tmux session '${TMUX_SESSION}' exists — attaching." exec tmux attach -t "${TMUX_SESSION}" fi echo "Creating tmux session '${TMUX_SESSION}'..." local grok_cmd if [[ -n "${sid}" ]]; then grok_cmd="grok -r ${sid} --cwd ${HOME} $(printf %q "${resume_prompt}") || grok -c --cwd ${HOME} $(printf %q "${resume_prompt}") || grok --cwd ${HOME} $(printf %q "${resume_prompt}")" else grok_cmd="grok --cwd ${HOME} $(printf %q "${resume_prompt}")" fi tmux new-session -d -s "${TMUX_SESSION}" -n grok -c "${HOME}" \ "${grok_cmd}; echo; echo '[heavy-duty-watcher] Grok exited.'; exec bash" tmux new-window -t "${TMUX_SESSION}" -n poll-loop -c "${WATCHER_DIR}" \ "bash ${WATCHER_DIR}/scripts/poll-loop.sh" tmux new-window -t "${TMUX_SESSION}" -n health-loop -c "${WATCHER_DIR}" \ "bash ${WATCHER_DIR}/scripts/health-loop.sh" tmux new-window -t "${TMUX_SESSION}" -n tools -c "${WATCHER_DIR}" \ "echo 'tools: ./scripts/discover.sh | ./scripts/health-check.sh | tail -f logs/poll.log'; exec bash" tmux select-window -t "${TMUX_SESSION}:grok" watcher_log "${LOG_DIR}/poll.log" "restore.sh started ${TMUX_SESSION}" exec tmux attach -t "${TMUX_SESSION}" } case "${1:-}" in --status|-s) status ;; --attach|-a) attach_only ;; --help|-h) sed -n '2,7p' "$0" ;; *) start_or_attach ;; esac