文件预览

local.sh

查看 ClawSync 技能包中的文件内容。

文件内容

providers/local.sh

#!/usr/bin/env bash
# ClawSync Provider — Local directory (USB drive, NAS mount, shared folder)
set -euo pipefail
VAULT_DIR="$HOME/.clawsync"; CONFIG="$VAULT_DIR/config.yaml"; PROVIDER_CONFIG="$VAULT_DIR/.provider-local.json"
timestamp() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }; log() { echo "[clawsync:local $(timestamp)] $*"; }

EXCLUDE="--exclude local/ --exclude keys/ --exclude .provider-*.json --exclude .cloud-provider.json --exclude .sync-* --exclude .pull-* --exclude .heartbeat.pid --exclude .git-local/ --exclude .git/"

get_profile_name() {
  if [[ -n "${CLAWSYNC_PROFILE:-}" ]]; then echo "$CLAWSYNC_PROFILE"; return; fi
  local name
  name=$(grep 'profile_name:' "$CONFIG" 2>/dev/null | head -1 | awk '{print $2}' | tr -d '"')
  echo "${name:-$(hostname -s 2>/dev/null || echo default)}"
}

cmd_setup() {
  echo ""; echo "Local Storage Setup"; echo "==================="
  echo "Use a USB drive, NAS mount, or any local/network directory."
  echo ""
  read -rp "Directory path (e.g. /Volumes/USB/clawsync or /mnt/nas/clawsync): " target_dir
  if [[ -z "$target_dir" ]]; then log "Path required."; return 1; fi

  if [[ ! -d "$target_dir" ]]; then
    read -rp "Directory doesn't exist. Create it? [Y/n]: " yn
    if [[ "$yn" =~ ^[Nn] ]]; then return 1; fi
    mkdir -p "$target_dir" || { log "Cannot create directory."; return 1; }
  fi

  cat > "$PROVIDER_CONFIG" <<JSON
{"provider":"local","path":"$target_dir","configured":"$(timestamp)"}
JSON
  log "Local storage configured → $target_dir"
}

_get_path() {
  python3 -c "import json;print(json.load(open('$PROVIDER_CONFIG'))['path'])" 2>/dev/null
}

cmd_push() {
  if [[ ! -f "$PROVIDER_CONFIG" ]]; then log "Not configured."; return 1; fi
  local target; target=$(_get_path)
  if [[ ! -d "$target" ]]; then log "Target not found: $target"; return 1; fi
  local profile_name; profile_name=$(get_profile_name)
  local target_profile="$target/profiles/$profile_name"
  mkdir -p "$target_profile"
  log "Pushing to $target_profile..."
  rsync -a --delete $EXCLUDE "$VAULT_DIR/" "$target_profile/" 2>&1 | tail -3
  log "Push complete (profile: $profile_name)"
}

cmd_pull() {
  if [[ ! -f "$PROVIDER_CONFIG" ]]; then log "Not configured."; return 1; fi
  local target; target=$(_get_path)
  if [[ ! -d "$target" ]]; then log "Target not found: $target"; return 1; fi
  local profile_name; profile_name=$(get_profile_name)
  local source_dir="$target/profiles/$profile_name"
  [[ ! -d "$source_dir" ]] && source_dir="$target"
  log "Pulling from $source_dir..."
  for f in identity/USER.md knowledge/MEMORY.md requirements.yaml manifest.json identity/instances.yaml; do
    [[ -f "$source_dir/$f" ]] && mkdir -p "$(dirname "$VAULT_DIR/$f")" && cp "$source_dir/$f" "$VAULT_DIR/$f"
  done
  [[ -d "$source_dir/knowledge/projects" ]] && mkdir -p "$VAULT_DIR/knowledge/projects" && cp -r "$source_dir/knowledge/projects/"* "$VAULT_DIR/knowledge/projects/" 2>/dev/null || true
  log "Pull complete (profile: $profile_name)"
}

cmd_list_profiles() {
  if [[ ! -f "$PROVIDER_CONFIG" ]]; then log "Not configured."; return 1; fi
  local target; target=$(_get_path)
  local current; current=$(get_profile_name)
  echo ""; echo "Remote Profiles"; echo "==============="
  if [[ -d "$target/profiles" ]]; then
    ls -1 "$target/profiles/" 2>/dev/null | while read -r p; do
      local marker=""; [[ "$p" == "$current" ]] && marker=" ← current"
      echo "  $p$marker"
    done
  else
    echo "  (no profiles yet)"
  fi
  echo ""
}

cmd_test() {
  if [[ ! -f "$PROVIDER_CONFIG" ]]; then log "Not configured."; return 1; fi
  local target; target=$(_get_path)
  [[ -d "$target" ]] && log "Directory accessible: $target" || log "Directory NOT accessible: $target"
}

cmd_info() {
  if [[ -f "$PROVIDER_CONFIG" ]]; then
    echo "  Path: $(_get_path)"
    echo "  Profile: $(get_profile_name)"
  else echo "  Not configured"; fi
}

case "${1:-info}" in setup) cmd_setup;; push) cmd_push;; pull) cmd_pull;; test) cmd_test;; info) cmd_info;; list-profiles) cmd_list_profiles;; esac