#!/bin/bash # Upgrade script for Claude Code configuration # Usage: ./upgrade.sh [--check|--backup|--apply] set -euo pipefail CLAUDE_DIR="${HOME}/.claude" VERSION_FILE="${CLAUDE_DIR}/VERSION" BACKUP_DIR="${CLAUDE_DIR}/backups" # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' info() { echo -e "${BLUE}ℹ${NC} $1"; } ok() { echo -e "${GREEN}✓${NC} $1"; } warn() { echo -e "${YELLOW}⚠${NC} $1"; } error() { echo -e "${RED}✗${NC} $1"; } get_current_version() { if [[ -f "$VERSION_FILE" ]]; then cat "$VERSION_FILE" | tr -d '\n' else echo "0.0.0" fi } compare_versions() { local v1="$1" local v2="$2" # Returns: -1 if v1 < v2, 0 if equal, 1 if v1 > v2 if [[ "$v1" == "$v2" ]]; then echo "0" return fi local IFS='.' local i v1_parts=($v1) v2_parts=($v2) for ((i=0; i<3; i++)); do local v1_part="${v1_parts[i]:-0}" local v2_part="${v2_parts[i]:-0}" if ((v1_part > v2_part)); then echo "1" return elif ((v1_part < v2_part)); then echo "-1" return fi done echo "0" } check_upgrade() { local current=$(get_current_version) echo "" echo "🔍 Checking for upgrades..." echo "" echo " Current version: $current" echo "" # Check git status if in a repo if [[ -d "${CLAUDE_DIR}/.git" ]]; then cd "$CLAUDE_DIR" # Fetch latest if git fetch origin 2>/dev/null; then local local_hash=$(git rev-parse HEAD 2>/dev/null || echo "unknown") local remote_hash=$(git rev-parse origin/main 2>/dev/null || echo "unknown") if [[ "$local_hash" != "$remote_hash" ]] && [[ "$remote_hash" != "unknown" ]]; then local ahead=$(git rev-list --count origin/main..HEAD 2>/dev/null || echo "0") local behind=$(git rev-list --count HEAD..origin/main 2>/dev/null || echo "0") if [[ "$behind" -gt 0 ]]; then warn "Behind origin/main by $behind commit(s)" echo "" echo " Run: cd ~/.claude && git pull" fi if [[ "$ahead" -gt 0 ]]; then info "Ahead of origin/main by $ahead commit(s)" fi else ok "Up to date with origin/main" fi else warn "Could not fetch from remote" fi else info "Not a git repository - manual upgrade required" fi echo "" } pre_upgrade_backup() { echo "" echo "📦 Creating pre-upgrade backup..." mkdir -p "$BACKUP_DIR" local timestamp=$(date +%Y%m%d-%H%M%S) local backup_file="${BACKUP_DIR}/pre-upgrade-${timestamp}.tar.gz" # Backup essential files only tar -czf "$backup_file" \ -C "$CLAUDE_DIR" \ --exclude='backups' \ --exclude='logs' \ --exclude='*.pyc' \ --exclude='__pycache__' \ --exclude='.git' \ --exclude='venv' \ . 2>/dev/null || true ok "Backup created: $backup_file" echo "" } apply_migrations() { local current="$1" local target="$2" echo "" echo "🔄 Applying migrations from $current to $target..." echo "" # Migration: 0.x.x -> 1.0.0 if [[ $(compare_versions "$current" "1.0.0") -lt 0 ]] && \ [[ $(compare_versions "$target" "1.0.0") -ge 0 ]]; then info "Migration: Initializing plugin structure..." # Create directories if missing mkdir -p "${CLAUDE_DIR}/.claude-plugin" mkdir -p "${CLAUDE_DIR}/hooks/scripts" mkdir -p "${CLAUDE_DIR}/state/personal-assistant/memory" mkdir -p "${CLAUDE_DIR}/state/personal-assistant/history" ok "Plugin structure initialized" fi # Migration: 1.0.x -> 1.1.0 if [[ $(compare_versions "$current" "1.1.0") -lt 0 ]] && \ [[ $(compare_versions "$target" "1.1.0") -ge 0 ]]; then info "Migration: Adding automation scripts..." # Ensure automation directory exists mkdir -p "${CLAUDE_DIR}/automation/systemd" mkdir -p "${CLAUDE_DIR}/logs" ok "Automation structure initialized" fi echo "" ok "Migrations complete" } run_post_upgrade() { echo "" echo "🔧 Running post-upgrade tasks..." # Make scripts executable find "${CLAUDE_DIR}/automation" -name "*.sh" -type f -exec chmod +x {} \; 2>/dev/null || true find "${CLAUDE_DIR}/automation" -name "*.py" -type f -exec chmod +x {} \; 2>/dev/null || true find "${CLAUDE_DIR}/hooks/scripts" -name "*.sh" -type f -exec chmod +x {} \; 2>/dev/null || true ok "Scripts made executable" # Validate if "${CLAUDE_DIR}/automation/validate-setup.sh" > /dev/null 2>&1; then ok "Validation passed" else warn "Validation had warnings (run claude-validate to see details)" fi echo "" } show_usage() { echo "Usage: $0 [--check|--backup|--apply TARGET_VERSION]" echo "" echo "Options:" echo " --check Check for available upgrades" echo " --backup Create pre-upgrade backup" echo " --apply Apply migrations (requires TARGET_VERSION)" echo "" echo "Examples:" echo " $0 --check" echo " $0 --backup && git pull && $0 --apply 1.2.0" } # Main case "${1:-}" in --check) check_upgrade ;; --backup) pre_upgrade_backup ;; --apply) if [[ -z "${2:-}" ]]; then error "TARGET_VERSION required for --apply" show_usage exit 1 fi pre_upgrade_backup apply_migrations "$(get_current_version)" "$2" echo "$2" > "$VERSION_FILE" run_post_upgrade ok "Upgrade to $2 complete!" ;; --help|-h) show_usage ;; *) check_upgrade ;; esac