feat(ops): host_sync.sh — auto-sync host tree to origin/main (P-#160)
The writer, learning panels, and legal_mcp tools run from the HOST tree (Paperclip agents claude -p with cwd=~/legal-ai; pm2 services import from mcp-server/src) — not the container. A merge + Coolify deploy only refreshes the FastAPI container; host-side code stayed on the last manual `git pull`. On 2026-06-28 the host was 16 commits behind, so a day of learning-loop fixes sat dormant until pulled by hand. host_sync.sh (run every minute via cron, like the existing data/training pull) fast-forwards the host tree to origin/main when it falls behind. Fast-forward ONLY — never forces, so the perpetually-dirty .taskmaster/tasks/tasks.json is never clobbered (clean ff leaves it; an upstream conflict logs + bails for manual handling). Agent runs spawn fresh and pick up new code with no restart; only the long-running pm2 services that import app code (chat_service, court_fetch_service, reaper) are restarted, and only when their own files changed (precise, minimal churn). Logs to data/logs/host_sync.log. Cron entry (added on the host, flock-guarded): * * * * * flock -n /tmp/host_sync.lock bash ~/legal-ai/scripts/host_sync.sh SCRIPTS.md updated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
50
scripts/host_sync.sh
Executable file
50
scripts/host_sync.sh
Executable file
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env bash
|
||||
# host_sync.sh — keep the HOST working tree (~/legal-ai) in sync with origin/main.
|
||||
#
|
||||
# Why this exists: the writer (block_writer), the learning panels
|
||||
# (style_lesson_panel), and the legal_mcp MCP tools run from the host tree — the
|
||||
# Paperclip agents `claude -p` with cwd=/home/chaim/legal-ai, and the long-running
|
||||
# pm2 services import legal_mcp from mcp-server/src. A merge to main + Coolify
|
||||
# deploy only refreshes the CONTAINER (FastAPI endpoints); host-side code stays on
|
||||
# whatever was last `git pull`ed. On 2026-06-28 the host was 16 commits behind, so a
|
||||
# full day of learning-loop fixes sat dormant until a manual pull. This closes that
|
||||
# gap (TaskMaster #160).
|
||||
#
|
||||
# Safety: fast-forward ONLY (never force, never lose local work). The host tree
|
||||
# carries a perpetually-dirty .taskmaster/tasks/tasks.json (uncommitted by policy) —
|
||||
# a clean ff leaves it untouched; if upstream ever touches the same file the ff
|
||||
# fails and we log + bail rather than clobber it. Agent runs spawn fresh, so they
|
||||
# pick up new code on the next wakeup with no restart; only the long-running pm2
|
||||
# services that IMPORT app code are restarted, and only when their own files change.
|
||||
set -uo pipefail
|
||||
|
||||
REPO=/home/chaim/legal-ai
|
||||
LOG="$REPO/data/logs/host_sync.log"
|
||||
mkdir -p "$REPO/data/logs"
|
||||
log() { echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) $*" >> "$LOG"; }
|
||||
|
||||
cd "$REPO" || { log "ERROR cd $REPO failed"; exit 1; }
|
||||
|
||||
# Only sync when on main (don't disturb a manual branch checkout).
|
||||
branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
|
||||
[ "$branch" = "main" ] || { log "skip: on branch '$branch', not main"; exit 0; }
|
||||
|
||||
git fetch origin main --quiet 2>>"$LOG" || { log "ERROR git fetch failed"; exit 1; }
|
||||
local_head=$(git rev-parse HEAD)
|
||||
remote_head=$(git rev-parse origin/main)
|
||||
[ "$local_head" = "$remote_head" ] && exit 0 # up to date — quiet no-op
|
||||
|
||||
changed=$(git diff --name-only "$local_head" "$remote_head")
|
||||
if ! git pull --ff-only origin main --quiet 2>>"$LOG"; then
|
||||
log "ERROR ff-only pull failed ($local_head → $remote_head) — manual intervention needed (likely local tasks.json vs upstream); NOT forcing"
|
||||
exit 1
|
||||
fi
|
||||
log "synced $local_head → $(git rev-parse --short HEAD) ($(echo "$changed" | wc -l) files)"
|
||||
|
||||
# Restart only the long-running services whose OWN code changed (precise, minimal
|
||||
# churn). The agent path (writer/panels via fresh `claude -p`) needs no restart.
|
||||
restart() { pm2 restart "$1" --update-env >/dev/null 2>>"$LOG" && log "restarted $1"; }
|
||||
echo "$changed" | grep -q '^mcp-server/src/legal_mcp/chat_service/' && restart legal-chat-service
|
||||
echo "$changed" | grep -qE '^mcp-server/src/legal_mcp/court_fetch_service/' && restart legal-court-fetch-service
|
||||
echo "$changed" | grep -q '^scripts/reap_orphan_procs.py' && restart legal-reaper
|
||||
exit 0
|
||||
Reference in New Issue
Block a user