sync: Auto-sync from ACG-M-L5090 at 2026-03-10 19:11:00
Synced files: - Quote wizard frontend (all components, hooks, types, config) - API updates (config, models, routers, schemas, services) - Client work (bg-builders, gurushow) - Scripts (BGB Lesley termination, CIPP, Datto, migration) - Temp files (Bardach contacts, VWP investigation, misc) - Credentials and session logs - Email service, PHP API, session logs Machine: ACG-M-L5090 Timestamp: 2026-03-10 19:11:00 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
296
scripts/migration-restore.sh
Normal file
296
scripts/migration-restore.sh
Normal file
@@ -0,0 +1,296 @@
|
||||
#!/bin/bash
|
||||
###############################################################################
|
||||
# migration-restore.sh
|
||||
#
|
||||
# Restores a ClaudeTools environment from an encrypted migration archive.
|
||||
# Works in Git Bash on Windows AND native Linux bash.
|
||||
#
|
||||
# Usage: ./migration-restore.sh <archive.tar.gpg> [target_dir]
|
||||
# archive.tar.gpg Path to the encrypted migration archive
|
||||
# target_dir Where to clone/restore (default: $HOME/ClaudeTools)
|
||||
###############################################################################
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Globals
|
||||
# ---------------------------------------------------------------------------
|
||||
ARCHIVE_PATH="${1:-}"
|
||||
TARGET_DIR="${2:-"${HOME}/ClaudeTools"}"
|
||||
GITEA_REPO="ssh://git@172.16.3.20:2222/azcomputerguru/claudetools.git"
|
||||
TEMP_EXTRACT=""
|
||||
WARN_COUNT=0
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
log_info() { echo "[INFO] $*"; }
|
||||
log_ok() { echo "[OK] $*"; }
|
||||
log_warn() { echo "[WARNING] $*"; WARN_COUNT=$((WARN_COUNT + 1)); }
|
||||
log_error() { echo "[ERROR] $*"; }
|
||||
|
||||
cleanup() {
|
||||
if [[ -n "$TEMP_EXTRACT" && -d "$TEMP_EXTRACT" ]]; then
|
||||
log_info "Cleaning up temporary extraction directory..."
|
||||
rm -rf "$TEMP_EXTRACT"
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
check_tool() {
|
||||
local tool="$1"
|
||||
if ! command -v "$tool" &>/dev/null; then
|
||||
log_error "Required tool not found: ${tool}"
|
||||
log_error "Please install ${tool} before running this script."
|
||||
exit 1
|
||||
fi
|
||||
log_ok "Found: ${tool}"
|
||||
}
|
||||
|
||||
# Derive the Claude projects directory name from the target path.
|
||||
# On Windows (Git Bash): /d/ClaudeTools -> D--ClaudeTools
|
||||
# On Linux: /home/user/ClaudeTools -> -home-user-ClaudeTools
|
||||
derive_claude_project_name() {
|
||||
local abs_target
|
||||
abs_target="$(cd "$TARGET_DIR" && pwd)"
|
||||
|
||||
# Check if we are on Windows (Git Bash) by looking at path format
|
||||
if [[ "$abs_target" =~ ^/([a-zA-Z])/(.*) ]]; then
|
||||
# Git Bash path: /d/ClaudeTools -> D--ClaudeTools
|
||||
local drive="${BASH_REMATCH[1]^^}"
|
||||
local rest="${BASH_REMATCH[2]}"
|
||||
echo "${drive}--${rest//\//-}"
|
||||
elif [[ "$abs_target" =~ ^([a-zA-Z]):(.*) ]]; then
|
||||
# Raw Windows path: D:\ClaudeTools -> D--ClaudeTools
|
||||
local drive="${BASH_REMATCH[1]^^}"
|
||||
local rest="${BASH_REMATCH[2]}"
|
||||
rest="${rest//\\/-}"
|
||||
rest="${rest//\//-}"
|
||||
rest="${rest#-}"
|
||||
echo "${drive}--${rest}"
|
||||
else
|
||||
# Linux/macOS: /home/user/ClaudeTools -> -home-user-ClaudeTools
|
||||
local name="${abs_target//\//-}"
|
||||
name="${name#-}"
|
||||
echo "${name}"
|
||||
fi
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Main
|
||||
# ---------------------------------------------------------------------------
|
||||
main() {
|
||||
echo "============================================================"
|
||||
echo " ClaudeTools Migration Restore"
|
||||
echo " $(date '+%Y-%m-%d %H:%M:%S')"
|
||||
echo "============================================================"
|
||||
echo ""
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Validate arguments
|
||||
# ------------------------------------------------------------------
|
||||
if [[ -z "$ARCHIVE_PATH" ]]; then
|
||||
log_error "Usage: $0 <archive.tar.gpg> [target_dir]"
|
||||
log_error " archive.tar.gpg Encrypted migration archive"
|
||||
log_error " target_dir Restore location (default: \$HOME/ClaudeTools)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$ARCHIVE_PATH" ]]; then
|
||||
log_error "Archive not found: ${ARCHIVE_PATH}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Archive: ${ARCHIVE_PATH}"
|
||||
log_info "Target dir: ${TARGET_DIR}"
|
||||
echo ""
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Check required tools
|
||||
# ------------------------------------------------------------------
|
||||
log_info "--- Checking required tools ---"
|
||||
check_tool git
|
||||
check_tool gpg
|
||||
check_tool tar
|
||||
echo ""
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Decrypt archive
|
||||
# ------------------------------------------------------------------
|
||||
log_info "--- Decrypting archive ---"
|
||||
log_info "You will be prompted for the passphrase."
|
||||
echo ""
|
||||
|
||||
TEMP_EXTRACT="$(mktemp -d 2>/dev/null || mktemp -d -t 'migration-restore')"
|
||||
local tar_tmp="${TEMP_EXTRACT}/archive.tar"
|
||||
|
||||
if [[ -n "${GPG_PASSPHRASE:-}" ]]; then
|
||||
echo "$GPG_PASSPHRASE" | gpg --batch --yes --passphrase-fd 0 \
|
||||
--decrypt --output "$tar_tmp" "$ARCHIVE_PATH"
|
||||
else
|
||||
gpg --decrypt --output "$tar_tmp" "$ARCHIVE_PATH"
|
||||
fi
|
||||
|
||||
if [[ ! -f "$tar_tmp" ]]; then
|
||||
log_error "Decryption failed. Check your passphrase and try again."
|
||||
exit 1
|
||||
fi
|
||||
log_ok "Archive decrypted."
|
||||
echo ""
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Extract archive to temp location
|
||||
# ------------------------------------------------------------------
|
||||
log_info "--- Extracting archive ---"
|
||||
local extract_dir="${TEMP_EXTRACT}/contents"
|
||||
mkdir -p "$extract_dir"
|
||||
tar -xf "$tar_tmp" -C "$extract_dir"
|
||||
rm -f "$tar_tmp"
|
||||
log_ok "Archive extracted."
|
||||
|
||||
# Show manifest if present
|
||||
if [[ -f "${extract_dir}/MIGRATION_MANIFEST.txt" ]]; then
|
||||
echo ""
|
||||
log_info "--- Migration Manifest ---"
|
||||
cat "${extract_dir}/MIGRATION_MANIFEST.txt"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Clone repository
|
||||
# ------------------------------------------------------------------
|
||||
log_info "--- Cloning repository ---"
|
||||
|
||||
if [[ -d "$TARGET_DIR/.git" ]]; then
|
||||
log_warn "Target directory already contains a git repo: ${TARGET_DIR}"
|
||||
log_info "Skipping clone; will overlay migration files into existing repo."
|
||||
elif [[ -d "$TARGET_DIR" ]]; then
|
||||
# Directory exists but is not a git repo
|
||||
log_warn "Target directory exists but is not a git repo: ${TARGET_DIR}"
|
||||
log_info "Attempting clone into existing directory..."
|
||||
git clone "$GITEA_REPO" "${TARGET_DIR}.tmp"
|
||||
# Move .git and tracked files into existing directory
|
||||
mv "${TARGET_DIR}.tmp/.git" "${TARGET_DIR}/"
|
||||
# Checkout working tree into existing directory
|
||||
(cd "$TARGET_DIR" && git checkout -- .)
|
||||
rm -rf "${TARGET_DIR}.tmp"
|
||||
log_ok "Cloned repository into existing directory."
|
||||
else
|
||||
git clone "$GITEA_REPO" "$TARGET_DIR"
|
||||
log_ok "Cloned repository to: ${TARGET_DIR}"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Overlay non-git files from migration archive
|
||||
# ------------------------------------------------------------------
|
||||
log_info "--- Restoring non-git files ---"
|
||||
|
||||
# Copy everything except claude-context (handled separately) and manifest
|
||||
local item
|
||||
for item in "$extract_dir"/*; do
|
||||
local basename
|
||||
basename="$(basename "$item")"
|
||||
|
||||
# Skip claude-context dir and manifest
|
||||
if [[ "$basename" == "claude-context" || "$basename" == "MIGRATION_MANIFEST.txt" ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ -d "$item" ]]; then
|
||||
cp -a "$item" "$TARGET_DIR/"
|
||||
log_ok "Restored directory: ${basename}"
|
||||
elif [[ -f "$item" ]]; then
|
||||
cp -a "$item" "$TARGET_DIR/"
|
||||
log_ok "Restored file: ${basename}"
|
||||
fi
|
||||
done
|
||||
|
||||
# Handle dotfiles (hidden files/dirs from archive root)
|
||||
for item in "$extract_dir"/.*; do
|
||||
local basename
|
||||
basename="$(basename "$item")"
|
||||
[[ "$basename" == "." || "$basename" == ".." ]] && continue
|
||||
|
||||
if [[ -d "$item" ]]; then
|
||||
# Merge directory contents (e.g., .claude/)
|
||||
cp -a "$item"/. "$TARGET_DIR/${basename}/" 2>/dev/null || cp -a "$item" "$TARGET_DIR/"
|
||||
log_ok "Restored directory: ${basename}"
|
||||
elif [[ -f "$item" ]]; then
|
||||
cp -a "$item" "$TARGET_DIR/"
|
||||
log_ok "Restored file: ${basename}"
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Restore Claude AI context
|
||||
# ------------------------------------------------------------------
|
||||
log_info "--- Restoring Claude AI context ---"
|
||||
|
||||
local claude_ctx_src="${extract_dir}/claude-context"
|
||||
if [[ -d "$claude_ctx_src" ]]; then
|
||||
local project_name
|
||||
project_name="$(derive_claude_project_name)"
|
||||
local claude_ctx_dst="${HOME}/.claude/projects/${project_name}"
|
||||
|
||||
mkdir -p "$claude_ctx_dst"
|
||||
cp -a "$claude_ctx_src"/. "$claude_ctx_dst/"
|
||||
log_ok "Restored Claude context to: ${claude_ctx_dst}"
|
||||
else
|
||||
log_warn "No claude-context directory found in archive. Skipping."
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Initialize submodules
|
||||
# ------------------------------------------------------------------
|
||||
log_info "--- Initializing git submodules ---"
|
||||
(cd "$TARGET_DIR" && git submodule update --init --recursive) && \
|
||||
log_ok "Submodules initialized." || \
|
||||
log_warn "Submodule initialization had issues. You may need to run it manually."
|
||||
echo ""
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Summary and post-restore checklist
|
||||
# ------------------------------------------------------------------
|
||||
echo "============================================================"
|
||||
echo " Restore Complete"
|
||||
echo "============================================================"
|
||||
echo ""
|
||||
echo " Target: ${TARGET_DIR}"
|
||||
echo " Warnings: ${WARN_COUNT}"
|
||||
echo ""
|
||||
echo "============================================================"
|
||||
echo " Post-Restore Checklist"
|
||||
echo "============================================================"
|
||||
echo ""
|
||||
echo " [ ] Verify credentials.md contains correct, unredacted values"
|
||||
echo " File: ${TARGET_DIR}/credentials.md"
|
||||
echo ""
|
||||
echo " [ ] Set up Python virtual environment for MCP servers"
|
||||
echo " cd ${TARGET_DIR} && python -m venv .venv"
|
||||
echo " source .venv/bin/activate (or .venv\\Scripts\\activate on Windows)"
|
||||
echo " pip install -r requirements.txt"
|
||||
echo ""
|
||||
echo " [ ] Configure Claude Code CLI"
|
||||
echo " Run: claude (first launch will prompt for authentication)"
|
||||
echo " Verify .claude/ context was restored correctly"
|
||||
echo ""
|
||||
echo " [ ] Test Gitea SSH access"
|
||||
echo " Run: ssh -p 2222 git@172.16.3.20"
|
||||
echo " If it fails, copy your SSH keys and update ~/.ssh/config"
|
||||
echo ""
|
||||
echo " [ ] Rebuild grepai index"
|
||||
echo " The semantic search index is machine-specific."
|
||||
echo " Run grepai indexing from within Claude Code."
|
||||
echo ""
|
||||
echo " [ ] Verify .env and .mcp.json values are correct for new machine"
|
||||
echo ""
|
||||
echo " [ ] Test database connectivity"
|
||||
echo " Ensure 172.16.3.30:3306 is reachable from this machine"
|
||||
echo ""
|
||||
log_ok "Done."
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user