heavy-duty-watcher/scripts/restore.sh
grok-reviewer-andresmgsl 8d6f902209 Harden watcher: shared config, dual forge backends, safer discovery
- Add scripts/lib/common.sh (ORG/BOT/FORGE_BACKEND, logging, process_running)
- discover.sh: dedupe review-requested+assignee PRs; JSON+summary formats
- discover.sh: FORGE_BACKEND=forgejo via Forgejo API + stoke token
- Fix poll-loop process detection (basename, not install path)
- health-check: jq-safe JSON; backend-aware auth (gh or stoke)
- install-live: require rsync/jq/tmux; soft-warn missing gh/stoke
- self-test.sh offline smoke; restore/poll-once use shared config
- Docs: Forgejo table, watcher.env, OPERATIONS troubleshooting
2026-07-22 23:23:33 +00:00

123 lines
4.4 KiB
Bash
Executable file

#!/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 <<EOF
Resume the heavy-duty org watcher (ALL ${ORG}/* repos, backend=${FORGE_BACKEND}).
1. Read ${WATCHER_DIR}/POLL_INSTRUCTIONS.md and ${WATCHER_DIR}/state.json
2. Run one full org-wide poll cycle immediately (discover assigned/review-requested across org, read all comments, review until you agree)
3. Re-arm durable schedulers:
- 15m poll (org-wide, durable true)
- 1h health watchdog (durable true)
4. Confirm poll-loop + health-loop windows are running
5. Report status
Do not merge, close, or reassign unless explicitly asked.
EOF
)"
if tmux has-session -t "${TMUX_SESSION}" 2>/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