#!/bin/bash ############################################################################### # Sync a skill (or plugin) directory to a remote agent and restart the container. # Usage: ./sync_skill.sh # MODULE_DIR_NAME = directory under workspace/skills/ (e.g. tavily, mem0-integration) # Prefer rsync (exclude node_modules); fallback to scp if rsync not available. ############################################################################### set -e WORKSPACE="${WORKSPACE:-/root/.openclaw/workspace}" SKILLS_SRC="$WORKSPACE/skills" REMOTE_BASE="/opt/openclaw-remote" RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } log_ok() { echo -e "${GREEN}[OK]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_err() { echo -e "${RED}[ERROR]${NC} $1"; } # --- 1. Parameter check --- TARGET_IP="${1:?Usage: $0 }" AGENT_ID="${2:?Usage: $0 }" MODULE_NAME="${3:?Usage: $0 }" LOCAL_PATH="$SKILLS_SRC/$MODULE_NAME" REMOTE_PATH="$REMOTE_BASE/$AGENT_ID/skills" # --- 2. Local path exists --- if [ ! -d "$LOCAL_PATH" ]; then log_err "Local path not found: $LOCAL_PATH" exit 1 fi # --- 3. Optional: quick SSH connectivity check --- if ! ssh -o ConnectTimeout=5 -o BatchMode=yes "root@$TARGET_IP" "exit" 2>/dev/null; then log_warn "SSH to root@$TARGET_IP may require password or key. Continuing anyway." fi # --- 4. Sync: prefer rsync, fallback scp --- if command -v rsync >/dev/null 2>&1; then log_info "Syncing with rsync (excluding node_modules): $LOCAL_PATH -> root@$TARGET_IP:$REMOTE_PATH/" rsync -avz --exclude 'node_modules' "$LOCAL_PATH/" "root@${TARGET_IP}:${REMOTE_PATH}/${MODULE_NAME}/" log_ok "Rsync done." else log_warn "rsync not found; using scp (slower, includes node_modules)." log_info "Syncing: $LOCAL_PATH -> root@$TARGET_IP:$REMOTE_PATH/" ssh "root@$TARGET_IP" "mkdir -p $REMOTE_PATH" scp -r "$LOCAL_PATH" "root@${TARGET_IP}:${REMOTE_PATH}/" log_ok "Scp done." fi # --- 5. Restart remote container --- log_info "Restarting container: ssh root@$TARGET_IP 'cd $REMOTE_BASE/$AGENT_ID && docker compose restart'" ssh "root@$TARGET_IP" "cd $REMOTE_BASE/$AGENT_ID && docker compose restart" log_ok "Sync and restart completed."