#!/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