#!/usr/bin/env bash set -euo pipefail DATA_ROOT="${DATA_ROOT:-/data/root}" SYNC_INTERVAL="${SYNC_INTERVAL:-300}" CONFIG_PATH=".openclaw/openclaw.json" EXCLUDES=( "--exclude=.cache" "--exclude=.npm/_cacache" "--exclude=.npm/_update-notifier-last-checked*" "--exclude=.pnpm-store" "--exclude=node_modules" "--exclude=.next" "--exclude=dist" "--exclude=build" "--exclude=coverage" "--exclude=tmp" ) data_available() { [ -d /data ] || mkdir -p /data 2>/dev/null || return 1 mkdir -p "$DATA_ROOT" 2>/dev/null || return 1 } # /root → /data (--update: hanya file lebih baru di root yg masuk data) persist_root() { if data_available; then echo "Syncing /root → $DATA_ROOT (update: root wins if newer)..." rsync -rlptD --no-specials --no-devices --update --delete "${EXCLUDES[@]}" /root/ "$DATA_ROOT/" || true else echo "Persistent /data is not available; skipping persist." fi } # /data → /root (FORCE: data selalu menang, tanpa --update) restore_root() { if data_available; then echo "Restoring $DATA_ROOT → /root (force: data always wins)..." rsync -rlptD --no-specials --no-devices "${EXCLUDES[@]}" "$DATA_ROOT/" /root/ || true else echo "Persistent /data is not available; skipping restore." fi } sync_config_newer() { local root_config="/root/$CONFIG_PATH" local data_config="$DATA_ROOT/$CONFIG_PATH" if [ -f "$data_config" ] && { [ ! -f "$root_config" ] || [ "$data_config" -nt "$root_config" ]; }; then mkdir -p "$(dirname "$root_config")" cp -p "$data_config" "$root_config" || true echo "Pulled newer OpenClaw config: $data_config → $root_config" elif [ -f "$root_config" ] && { [ ! -f "$data_config" ] || [ "$root_config" -nt "$data_config" ]; }; then mkdir -p "$(dirname "$data_config")" cp -p "$root_config" "$data_config" || true echo "Persisted newer OpenClaw config: $root_config → $data_config" fi } # Urutan penting: # 1. persist → /root → /data (--update, perubahan root masuk data dulu) # 2. config → two-way reconcile openclaw.json # 3. restore → /data → /root (force, data selalu menang sebagai sumber kebenaran) # # Efeknya: # - Root berubah → masuk data di step 1, restore step 3 no-op (sudah sama) ✓ # - Data berubah → step 1 tidak tumpuk data (--update), step 3 force ke root ✓ reconcile_root_data() { if data_available; then persist_root sync_config_newer restore_root else echo "Persistent /data is not available; skipping two-way sync." fi } case "${1:-loop}" in restore) restore_root ;; persist) persist_root ;; reconcile) reconcile_root_data ;; loop) while true; do reconcile_root_data sleep "$SYNC_INTERVAL" done ;; *) echo "Usage: $0 {restore|persist|reconcile|loop}" exit 2 ;; esac