#!/usr/bin/env bash # # sync-check.sh — verify canonical claude-templates/.ai/ matches the .ai/ mirror. # # Usage: # scripts/sync-check.sh # exit 0 if synced, 1 if drift # scripts/sync-check.sh --fix # rsync canonical → mirror, then re-check # # Runs as a pre-commit hook (githooks/pre-commit) to catch drift before # commit, and as a manual check via `make sync-check`. # # The three synced paths are: # claude-templates/.ai/protocols.org ↔ .ai/protocols.org # claude-templates/.ai/workflows/ ↔ .ai/workflows/ # claude-templates/.ai/scripts/ ↔ .ai/scripts/ # # Source of truth is the canonical (claude-templates/) side. The mirror # exists so rulesets-as-a-project has a working copy. Drift in either # direction is a defect — both have to land in the same commit. set -euo pipefail if ! repo_root="$(git rev-parse --show-toplevel 2>/dev/null)" || [ -z "$repo_root" ]; then echo "sync-check: not inside a git checkout" >&2 exit 2 fi canonical="$repo_root/claude-templates/.ai" mirror="$repo_root/.ai" if [ ! -d "$canonical" ] || [ ! -d "$mirror" ]; then echo "sync-check: not a rulesets-shaped repo (missing claude-templates/.ai or .ai)" >&2 exit 2 fi paths=(protocols.org workflows scripts) check_drift() { local drift=0 for relpath in "${paths[@]}"; do if ! diff -rq "$canonical/$relpath" "$mirror/$relpath" >/dev/null 2>&1; then echo "drift: claude-templates/.ai/$relpath ↔ .ai/$relpath" >&2 diff -rq "$canonical/$relpath" "$mirror/$relpath" 2>&1 | head -20 >&2 drift=1 fi done return "$drift" } if check_drift; then exit 0 fi if [ "${1:-}" = "--fix" ]; then echo "" >&2 echo "sync-check --fix: syncing canonical → mirror..." >&2 rsync -a "$canonical/protocols.org" "$mirror/protocols.org" rsync -a --delete "$canonical/workflows/" "$mirror/workflows/" rsync -a --delete "$canonical/scripts/" "$mirror/scripts/" if check_drift; then echo "sync-check --fix: resolved." >&2 echo "Re-stage the synced files and retry the commit." >&2 exit 0 else echo "sync-check --fix: drift persists after sync. Inspect manually." >&2 exit 1 fi fi echo "" >&2 echo "Run 'scripts/sync-check.sh --fix' (or 'make sync-check FIX=1') to resolve." >&2 exit 1