diff --git a/Install-Claude.ps1 b/Install-Claude.ps1 index 36723662..8c332257 100644 --- a/Install-Claude.ps1 +++ b/Install-Claude.ps1 @@ -646,6 +646,37 @@ function Backup-AndReplaceDirectory { return $true } +function Backup-CriticalConfigFiles { + param( + [string]$TargetDirectory, + [string]$BackupFolder, + [string[]]$FileNames + ) + + if (-not $BackupFolder -or $NoBackup) { + return + } + + if (-not (Test-Path $TargetDirectory)) { + return + } + + $backedUpCount = 0 + foreach ($fileName in $FileNames) { + $filePath = Join-Path $TargetDirectory $fileName + if (Test-Path $filePath) { + if (Backup-FileToFolder -FilePath $filePath -BackupFolder $BackupFolder) { + Write-ColorOutput "Critical config backed up: $fileName" $ColorSuccess + $backedUpCount++ + } + } + } + + if ($backedUpCount -gt 0) { + Write-ColorOutput "Backed up $backedUpCount critical configuration file(s)" $ColorInfo + } +} + function Merge-DirectoryContents { param( [string]$Source, @@ -1227,9 +1258,9 @@ function Install-Global { } } - # Replace .claude directory (backup → clear → copy entire folder) - Write-ColorOutput "Installing .claude directory..." $ColorInfo - $claudeInstalled = Backup-AndReplaceDirectory -Source $sourceClaudeDir -Destination $globalClaudeDir -Description ".claude directory" -BackupFolder $backupFolder + # Merge .claude directory (incremental overlay - preserves user files) + Write-ColorOutput "Installing .claude directory (incremental merge)..." $ColorInfo + $claudeInstalled = Merge-DirectoryContents -Source $sourceClaudeDir -Destination $globalClaudeDir -Description ".claude directory" -BackupFolder $backupFolder # Track .claude directory in manifest if ($claudeInstalled) { @@ -1253,9 +1284,12 @@ function Install-Global { Add-ManifestEntry -Manifest $manifest -Path $globalClaudeMd -Type "File" } - # Replace .codex directory (backup → clear → copy entire folder) - Write-ColorOutput "Installing .codex directory..." $ColorInfo - $codexInstalled = Backup-AndReplaceDirectory -Source $sourceCodexDir -Destination $globalCodexDir -Description ".codex directory" -BackupFolder $backupFolder + # Backup critical config files in .codex directory before installation + Backup-CriticalConfigFiles -TargetDirectory $globalCodexDir -BackupFolder $backupFolder -FileNames @("AGENTS.md") + + # Merge .codex directory (incremental overlay - preserves user files) + Write-ColorOutput "Installing .codex directory (incremental merge)..." $ColorInfo + $codexInstalled = Merge-DirectoryContents -Source $sourceCodexDir -Destination $globalCodexDir -Description ".codex directory" -BackupFolder $backupFolder # Track .codex directory in manifest if ($codexInstalled) { @@ -1268,9 +1302,12 @@ function Install-Global { } } - # Replace .gemini directory (backup → clear → copy entire folder) - Write-ColorOutput "Installing .gemini directory..." $ColorInfo - $geminiInstalled = Backup-AndReplaceDirectory -Source $sourceGeminiDir -Destination $globalGeminiDir -Description ".gemini directory" -BackupFolder $backupFolder + # Backup critical config files in .gemini directory before installation + Backup-CriticalConfigFiles -TargetDirectory $globalGeminiDir -BackupFolder $backupFolder -FileNames @("GEMINI.md", "CLAUDE.md") + + # Merge .gemini directory (incremental overlay - preserves user files) + Write-ColorOutput "Installing .gemini directory (incremental merge)..." $ColorInfo + $geminiInstalled = Merge-DirectoryContents -Source $sourceGeminiDir -Destination $globalGeminiDir -Description ".gemini directory" -BackupFolder $backupFolder # Track .gemini directory in manifest if ($geminiInstalled) { @@ -1283,9 +1320,12 @@ function Install-Global { } } - # Replace .qwen directory (backup → clear → copy entire folder) - Write-ColorOutput "Installing .qwen directory..." $ColorInfo - $qwenInstalled = Backup-AndReplaceDirectory -Source $sourceQwenDir -Destination $globalQwenDir -Description ".qwen directory" -BackupFolder $backupFolder + # Backup critical config files in .qwen directory before installation + Backup-CriticalConfigFiles -TargetDirectory $globalQwenDir -BackupFolder $backupFolder -FileNames @("QWEN.md") + + # Merge .qwen directory (incremental overlay - preserves user files) + Write-ColorOutput "Installing .qwen directory (incremental merge)..." $ColorInfo + $qwenInstalled = Merge-DirectoryContents -Source $sourceQwenDir -Destination $globalQwenDir -Description ".qwen directory" -BackupFolder $backupFolder # Track .qwen directory in manifest if ($qwenInstalled) { @@ -1372,9 +1412,9 @@ function Install-Path { $destFolderPath = Join-Path $localClaudeDir $folder if (Test-Path $sourceFolderPath) { - # Use new backup and replace logic for local folders - Write-ColorOutput "Installing local folder: $folder..." $ColorInfo - $folderInstalled = Backup-AndReplaceDirectory -Source $sourceFolderPath -Destination $destFolderPath -Description "$folder folder" -BackupFolder $backupFolder + # Use incremental merge for local folders (preserves user customizations) + Write-ColorOutput "Installing local folder: $folder (incremental merge)..." $ColorInfo + $folderInstalled = Merge-DirectoryContents -Source $sourceFolderPath -Destination $destFolderPath -Description "$folder folder" -BackupFolder $backupFolder Write-ColorOutput "Installed local folder: $folder" $ColorSuccess # Track local folder in manifest @@ -1461,9 +1501,12 @@ function Install-Path { Add-ManifestEntry -Manifest $manifest -Path $globalClaudeMd -Type "File" } - # Replace .codex directory to local location (backup → clear → copy entire folder) - Write-ColorOutput "Installing .codex directory to local location..." $ColorInfo - $codexInstalled = Backup-AndReplaceDirectory -Source $sourceCodexDir -Destination $localCodexDir -Description ".codex directory" -BackupFolder $backupFolder + # Backup critical config files in .codex directory before installation + Backup-CriticalConfigFiles -TargetDirectory $localCodexDir -BackupFolder $backupFolder -FileNames @("AGENTS.md") + + # Merge .codex directory to local location (incremental overlay - preserves user files) + Write-ColorOutput "Installing .codex directory to local location (incremental merge)..." $ColorInfo + $codexInstalled = Merge-DirectoryContents -Source $sourceCodexDir -Destination $localCodexDir -Description ".codex directory" -BackupFolder $backupFolder # Track .codex directory in manifest if ($codexInstalled) { @@ -1476,9 +1519,12 @@ function Install-Path { } } - # Replace .gemini directory to local location (backup → clear → copy entire folder) - Write-ColorOutput "Installing .gemini directory to local location..." $ColorInfo - $geminiInstalled = Backup-AndReplaceDirectory -Source $sourceGeminiDir -Destination $localGeminiDir -Description ".gemini directory" -BackupFolder $backupFolder + # Backup critical config files in .gemini directory before installation + Backup-CriticalConfigFiles -TargetDirectory $localGeminiDir -BackupFolder $backupFolder -FileNames @("GEMINI.md", "CLAUDE.md") + + # Merge .gemini directory to local location (incremental overlay - preserves user files) + Write-ColorOutput "Installing .gemini directory to local location (incremental merge)..." $ColorInfo + $geminiInstalled = Merge-DirectoryContents -Source $sourceGeminiDir -Destination $localGeminiDir -Description ".gemini directory" -BackupFolder $backupFolder # Track .gemini directory in manifest if ($geminiInstalled) { @@ -1491,9 +1537,12 @@ function Install-Path { } } - # Replace .qwen directory to local location (backup → clear → copy entire folder) - Write-ColorOutput "Installing .qwen directory to local location..." $ColorInfo - $qwenInstalled = Backup-AndReplaceDirectory -Source $sourceQwenDir -Destination $localQwenDir -Description ".qwen directory" -BackupFolder $backupFolder + # Backup critical config files in .qwen directory before installation + Backup-CriticalConfigFiles -TargetDirectory $localQwenDir -BackupFolder $backupFolder -FileNames @("QWEN.md") + + # Merge .qwen directory to local location (incremental overlay - preserves user files) + Write-ColorOutput "Installing .qwen directory to local location (incremental merge)..." $ColorInfo + $qwenInstalled = Merge-DirectoryContents -Source $sourceQwenDir -Destination $localQwenDir -Description ".qwen directory" -BackupFolder $backupFolder # Track .qwen directory in manifest if ($qwenInstalled) { diff --git a/Install-Claude.sh b/Install-Claude.sh index 37558570..5201cdc0 100644 --- a/Install-Claude.sh +++ b/Install-Claude.sh @@ -344,6 +344,36 @@ function copy_file_to_destination() { fi } +function backup_critical_config_files() { + local target_directory="$1" + local backup_folder="$2" + shift 2 + local file_names=("$@") + + if [ "$NO_BACKUP" = true ] || [ -z "$backup_folder" ]; then + return 0 + fi + + if [ ! -d "$target_directory" ]; then + return 0 + fi + + local backed_up_count=0 + for file_name in "${file_names[@]}"; do + local file_path="${target_directory}/${file_name}" + if [ -f "$file_path" ]; then + if backup_file_to_folder "$file_path" "$backup_folder"; then + write_color "Critical config backed up: $file_name" "$COLOR_SUCCESS" + ((backed_up_count++)) + fi + fi + done + + if [ "$backed_up_count" -gt 0 ]; then + write_color "Backed up $backed_up_count critical configuration file(s)" "$COLOR_INFO" + fi +} + function backup_and_replace_directory() { local source="$1" local destination="$2" @@ -512,9 +542,9 @@ function install_global() { fi fi - # Replace .claude directory (backup → clear conflicting → copy) - write_color "Installing .claude directory..." "$COLOR_INFO" - if backup_and_replace_directory "$source_claude_dir" "$global_claude_dir" ".claude directory" "$backup_folder"; then + # Merge .claude directory (incremental overlay - preserves user files) + write_color "Installing .claude directory (incremental merge)..." "$COLOR_INFO" + if merge_directory_contents "$source_claude_dir" "$global_claude_dir" ".claude directory" "$backup_folder"; then # Track .claude directory in manifest add_manifest_entry "$manifest_file" "$global_claude_dir" "Directory" @@ -533,9 +563,12 @@ function install_global() { add_manifest_entry "$manifest_file" "$global_claude_md" "File" fi - # Replace .codex directory (backup → clear conflicting → copy) - write_color "Installing .codex directory..." "$COLOR_INFO" - if backup_and_replace_directory "$source_codex_dir" "$global_codex_dir" ".codex directory" "$backup_folder"; then + # Backup critical config files in .codex directory before installation + backup_critical_config_files "$global_codex_dir" "$backup_folder" "AGENTS.md" + + # Merge .codex directory (incremental overlay - preserves user files) + write_color "Installing .codex directory (incremental merge)..." "$COLOR_INFO" + if merge_directory_contents "$source_codex_dir" "$global_codex_dir" ".codex directory" "$backup_folder"; then # Track .codex directory in manifest add_manifest_entry "$manifest_file" "$global_codex_dir" "Directory" @@ -547,9 +580,12 @@ function install_global() { done < <(find "$source_codex_dir" -type f -print0) fi - # Replace .gemini directory (backup → clear conflicting → copy) - write_color "Installing .gemini directory..." "$COLOR_INFO" - if backup_and_replace_directory "$source_gemini_dir" "$global_gemini_dir" ".gemini directory" "$backup_folder"; then + # Backup critical config files in .gemini directory before installation + backup_critical_config_files "$global_gemini_dir" "$backup_folder" "GEMINI.md" "CLAUDE.md" + + # Merge .gemini directory (incremental overlay - preserves user files) + write_color "Installing .gemini directory (incremental merge)..." "$COLOR_INFO" + if merge_directory_contents "$source_gemini_dir" "$global_gemini_dir" ".gemini directory" "$backup_folder"; then # Track .gemini directory in manifest add_manifest_entry "$manifest_file" "$global_gemini_dir" "Directory" @@ -561,9 +597,12 @@ function install_global() { done < <(find "$source_gemini_dir" -type f -print0) fi - # Replace .qwen directory (backup → clear conflicting → copy) - write_color "Installing .qwen directory..." "$COLOR_INFO" - if backup_and_replace_directory "$source_qwen_dir" "$global_qwen_dir" ".qwen directory" "$backup_folder"; then + # Backup critical config files in .qwen directory before installation + backup_critical_config_files "$global_qwen_dir" "$backup_folder" "QWEN.md" + + # Merge .qwen directory (incremental overlay - preserves user files) + write_color "Installing .qwen directory (incremental merge)..." "$COLOR_INFO" + if merge_directory_contents "$source_qwen_dir" "$global_qwen_dir" ".qwen directory" "$backup_folder"; then # Track .qwen directory in manifest add_manifest_entry "$manifest_file" "$global_qwen_dir" "Directory" @@ -642,9 +681,9 @@ function install_path() { local dest_folder="${local_claude_dir}/${folder}" if [ -d "$source_folder" ]; then - # Use new backup and replace logic for local folders - write_color "Installing local folder: $folder..." "$COLOR_INFO" - if backup_and_replace_directory "$source_folder" "$dest_folder" "$folder folder" "$backup_folder"; then + # Use incremental merge for local folders (preserves user customizations) + write_color "Installing local folder: $folder (incremental merge)..." "$COLOR_INFO" + if merge_directory_contents "$source_folder" "$dest_folder" "$folder folder" "$backup_folder"; then # Track local folder in manifest add_manifest_entry "$manifest_file" "$dest_folder" "Directory" @@ -715,9 +754,12 @@ function install_path() { add_manifest_entry "$manifest_file" "$global_claude_md" "File" fi - # Replace .codex directory to local location (backup → clear conflicting → copy) - write_color "Installing .codex directory to local location..." "$COLOR_INFO" - if backup_and_replace_directory "$source_codex_dir" "$local_codex_dir" ".codex directory" "$backup_folder"; then + # Backup critical config files in .codex directory before installation + backup_critical_config_files "$local_codex_dir" "$backup_folder" "AGENTS.md" + + # Merge .codex directory to local location (incremental overlay - preserves user files) + write_color "Installing .codex directory to local location (incremental merge)..." "$COLOR_INFO" + if merge_directory_contents "$source_codex_dir" "$local_codex_dir" ".codex directory" "$backup_folder"; then # Track .codex directory in manifest add_manifest_entry "$manifest_file" "$local_codex_dir" "Directory" @@ -729,9 +771,12 @@ function install_path() { done < <(find "$source_codex_dir" -type f -print0) fi - # Replace .gemini directory to local location (backup → clear conflicting → copy) - write_color "Installing .gemini directory to local location..." "$COLOR_INFO" - if backup_and_replace_directory "$source_gemini_dir" "$local_gemini_dir" ".gemini directory" "$backup_folder"; then + # Backup critical config files in .gemini directory before installation + backup_critical_config_files "$local_gemini_dir" "$backup_folder" "GEMINI.md" "CLAUDE.md" + + # Merge .gemini directory to local location (incremental overlay - preserves user files) + write_color "Installing .gemini directory to local location (incremental merge)..." "$COLOR_INFO" + if merge_directory_contents "$source_gemini_dir" "$local_gemini_dir" ".gemini directory" "$backup_folder"; then # Track .gemini directory in manifest add_manifest_entry "$manifest_file" "$local_gemini_dir" "Directory" @@ -743,9 +788,12 @@ function install_path() { done < <(find "$source_gemini_dir" -type f -print0) fi - # Replace .qwen directory to local location (backup → clear conflicting → copy) - write_color "Installing .qwen directory to local location..." "$COLOR_INFO" - if backup_and_replace_directory "$source_qwen_dir" "$local_qwen_dir" ".qwen directory" "$backup_folder"; then + # Backup critical config files in .qwen directory before installation + backup_critical_config_files "$local_qwen_dir" "$backup_folder" "QWEN.md" + + # Merge .qwen directory to local location (incremental overlay - preserves user files) + write_color "Installing .qwen directory to local location (incremental merge)..." "$COLOR_INFO" + if merge_directory_contents "$source_qwen_dir" "$local_qwen_dir" ".qwen directory" "$backup_folder"; then # Track .qwen directory in manifest add_manifest_entry "$manifest_file" "$local_qwen_dir" "Directory"