mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-05 01:50:27 +08:00
refactor(installer): implement incremental merge strategy with critical config backup
Changes: - Switch from full directory replacement to incremental merge for all directories (.claude, .codex, .gemini, .qwen) - Preserve user's custom files and folders during installation - Add priority backup for critical config files: - .codex/AGENTS.md - .gemini/GEMINI.md, CLAUDE.md - .qwen/QWEN.md - Only overwrite files present in installation package - Auto-cleanup empty backup folders - Update both PowerShell and Bash installers with consistent behavior Benefits: - Non-destructive updates that preserve user customizations - Safer upgrade path with automatic backup - Better user experience during reinstallation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user