Files
Claude-Code-Workflow/Install-Claude.ps1
catlog22 445ac823ba Initial release: Claude Code Workflow (CCW) v2.0
🚀 Revolutionary AI-powered development workflow orchestration system

## 🔥 Core Innovations
- **Document-State Separation**: Markdown for planning, JSON for execution state
- **Progressive Complexity Management**: Level 0-2 adaptive workflow depth
- **5-Agent Orchestration**: Specialized AI agents with context preservation
- **Session-First Architecture**: Auto-discovery and state inheritance

## 🏗️ Key Features
- Intelligent workflow orchestration (Simple/Medium/Complex patterns)
- Real-time document-state synchronization with conflict resolution
- Hierarchical task management with 3-level JSON structure
- Gemini CLI integration with 12+ specialized templates
- Comprehensive file output generation for all workflow commands

## 📦 Installation
Remote one-liner installation:
```
iex (iwr -useb https://raw.githubusercontent.com/catlog22/Claude-CCW/main/install-remote.ps1)
```

## 🎯 System Architecture
4-layer intelligent development architecture:
1. Command Layer - Smart routing and version management
2. Agent Layer - 5 specialized development agents
3. Workflow Layer - Gemini templates and task orchestration
4. Memory Layer - Distributed documentation and auto-sync

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-07 17:39:54 +08:00

603 lines
20 KiB
PowerShell

#Requires -Version 5.1
<#
.SYNOPSIS
Claude Code Workflow System Interactive Installer
.DESCRIPTION
Installation script for Claude Code Workflow System with Agent coordination and distributed memory system.
Installs globally to user profile directory (~/.claude) by default.
.PARAMETER InstallMode
Installation mode: "Global" (default and only supported mode)
.PARAMETER TargetPath
Target path for Custom installation mode
.PARAMETER Force
Skip confirmation prompts
.PARAMETER NonInteractive
Run in non-interactive mode with default options
.PARAMETER BackupAll
Automatically backup all existing files without confirmation prompts (enabled by default)
.PARAMETER NoBackup
Disable automatic backup functionality
.EXAMPLE
.\Install-Claude.ps1
Interactive installation with mode selection
.EXAMPLE
.\Install-Claude.ps1 -InstallMode Global -Force
Global installation without prompts
.EXAMPLE
.\Install-Claude.ps1 -Force -NonInteractive
Global installation without prompts
.EXAMPLE
.\Install-Claude.ps1 -BackupAll
Global installation with automatic backup of all existing files
.EXAMPLE
.\Install-Claude.ps1 -NoBackup
Installation without any backup (overwrite existing files)
#>
param(
[ValidateSet("Global")]
[string]$InstallMode = "Global",
[switch]$Force,
[switch]$NonInteractive,
[switch]$BackupAll,
[switch]$NoBackup
)
# Set encoding for proper Unicode support
if ($PSVersionTable.PSVersion.Major -ge 6) {
$OutputEncoding = [System.Text.Encoding]::UTF8
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
[Console]::InputEncoding = [System.Text.Encoding]::UTF8
} else {
# For Windows PowerShell 5.1
chcp 65001 | Out-Null
}
# Script metadata
$ScriptName = "Claude Code Workflow System Installer"
$Version = "2.1.0"
# Initialize backup behavior - backup is enabled by default unless NoBackup is specified
if (-not $BackupAll -and -not $NoBackup) {
$BackupAll = $true
Write-Verbose "Auto-backup enabled by default. Use -NoBackup to disable."
}
# Colors for output
$ColorSuccess = "Green"
$ColorInfo = "Cyan"
$ColorWarning = "Yellow"
$ColorError = "Red"
$ColorPrompt = "Magenta"
function Write-ColorOutput {
param(
[string]$Message,
[string]$Color = "White"
)
Write-Host $Message -ForegroundColor $Color
}
function Show-Header {
Write-ColorOutput "==== $ScriptName v$Version ====" $ColorInfo
Write-ColorOutput "========================================================" $ColorInfo
if ($NoBackup) {
Write-ColorOutput "WARNING: Backup disabled - existing files will be overwritten without backup!" $ColorWarning
} else {
Write-ColorOutput "Auto-backup enabled - existing files will be backed up before replacement" $ColorSuccess
}
Write-Host ""
}
function Test-Prerequisites {
# Test PowerShell version
if ($PSVersionTable.PSVersion.Major -lt 5) {
Write-ColorOutput "ERROR: PowerShell 5.1 or higher is required" $ColorError
Write-ColorOutput "Current version: $($PSVersionTable.PSVersion)" $ColorError
return $false
}
# Test source files exist
$sourceDir = $PSScriptRoot
$claudeDir = Join-Path $sourceDir ".claude"
$claudeMd = Join-Path $sourceDir "CLAUDE.md"
if (-not (Test-Path $claudeDir)) {
Write-ColorOutput "ERROR: .claude directory not found in $sourceDir" $ColorError
return $false
}
if (-not (Test-Path $claudeMd)) {
Write-ColorOutput "ERROR: CLAUDE.md file not found in $sourceDir" $ColorError
return $false
}
Write-ColorOutput "Prerequisites check passed" $ColorSuccess
return $true
}
function Get-UserChoice {
param(
[string]$Prompt,
[string[]]$Options,
[string]$Default = $null
)
if ($NonInteractive -and $Default) {
Write-ColorOutput "Non-interactive mode: Using default '$Default'" $ColorInfo
return $Default
}
Write-ColorOutput $Prompt $ColorPrompt
for ($i = 0; $i -lt $Options.Count; $i++) {
if ($Default -and $Options[$i] -eq $Default) {
$marker = " (default)"
} else {
$marker = ""
}
Write-Host " $($i + 1). $($Options[$i])$marker"
}
do {
$input = Read-Host "Please select (1-$($Options.Count))"
if ([string]::IsNullOrWhiteSpace($input) -and $Default) {
return $Default
}
$index = $null
if ([int]::TryParse($input, [ref]$index) -and $index -ge 1 -and $index -le $Options.Count) {
return $Options[$index - 1]
}
Write-ColorOutput "Invalid selection. Please enter a number between 1 and $($Options.Count)" $ColorWarning
} while ($true)
}
function Confirm-Action {
param(
[string]$Message,
[switch]$DefaultYes
)
if ($Force) {
Write-ColorOutput "Force mode: Proceeding with '$Message'" $ColorInfo
return $true
}
if ($NonInteractive) {
if ($DefaultYes) {
$result = $true
} else {
$result = $false
}
if ($result) {
$resultText = 'Yes'
} else {
$resultText = 'No'
}
Write-ColorOutput "Non-interactive mode: $Message - $resultText" $ColorInfo
return $result
}
if ($DefaultYes) {
$defaultChar = "Y"
$prompt = "(Y/n)"
} else {
$defaultChar = "N"
$prompt = "(y/N)"
}
do {
$response = Read-Host "$Message $prompt"
if ([string]::IsNullOrWhiteSpace($response)) {
return $DefaultYes
}
switch ($response.ToLower()) {
{ $_ -in @('y', 'yes') } { return $true }
{ $_ -in @('n', 'no') } { return $false }
default {
Write-ColorOutput "Please answer 'y' or 'n'" $ColorWarning
}
}
} while ($true)
}
function Get-BackupDirectory {
param(
[string]$TargetDirectory
)
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
$backupDirName = "claude-backup-$timestamp"
$backupPath = Join-Path $TargetDirectory $backupDirName
# Ensure backup directory exists
if (-not (Test-Path $backupPath)) {
New-Item -ItemType Directory -Path $backupPath -Force | Out-Null
}
return $backupPath
}
function Backup-FileToFolder {
param(
[string]$FilePath,
[string]$BackupFolder
)
if (-not (Test-Path $FilePath)) {
return $false
}
try {
$fileName = Split-Path $FilePath -Leaf
$relativePath = ""
# Try to determine relative path structure for better organization
$fileDir = Split-Path $FilePath -Parent
if ($fileDir -match '\.claude') {
# Extract path relative to .claude directory
$claudeIndex = $fileDir.LastIndexOf('.claude')
if ($claudeIndex -ge 0) {
$relativePath = $fileDir.Substring($claudeIndex + 7) # +7 for ".claude\"
if ($relativePath.StartsWith('\')) {
$relativePath = $relativePath.Substring(1)
}
}
}
# Create subdirectory structure in backup if needed
$backupSubDir = $BackupFolder
if (-not [string]::IsNullOrEmpty($relativePath)) {
$backupSubDir = Join-Path $BackupFolder $relativePath
if (-not (Test-Path $backupSubDir)) {
New-Item -ItemType Directory -Path $backupSubDir -Force | Out-Null
}
}
$backupFilePath = Join-Path $backupSubDir $fileName
Copy-Item -Path $FilePath -Destination $backupFilePath -Force
Write-ColorOutput "Backed up: $fileName" $ColorInfo
return $true
} catch {
Write-ColorOutput "WARNING: Failed to backup file $FilePath`: $($_.Exception.Message)" $ColorWarning
return $false
}
}
function Backup-DirectoryToFolder {
param(
[string]$DirectoryPath,
[string]$BackupFolder
)
if (-not (Test-Path $DirectoryPath)) {
return $false
}
try {
$dirName = Split-Path $DirectoryPath -Leaf
$backupDirPath = Join-Path $BackupFolder $dirName
Copy-Item -Path $DirectoryPath -Destination $backupDirPath -Recurse -Force
Write-ColorOutput "Backed up directory: $dirName" $ColorInfo
return $true
} catch {
Write-ColorOutput "WARNING: Failed to backup directory $DirectoryPath`: $($_.Exception.Message)" $ColorWarning
return $false
}
}
function Copy-DirectoryRecursive {
param(
[string]$Source,
[string]$Destination
)
if (-not (Test-Path $Source)) {
throw "Source directory does not exist: $Source"
}
# Create destination directory if it doesn't exist
if (-not (Test-Path $Destination)) {
New-Item -ItemType Directory -Path $Destination -Force | Out-Null
}
try {
# Copy all items recursively
Copy-Item -Path "$Source\*" -Destination $Destination -Recurse -Force
Write-ColorOutput "Directory copied: $Source -> $Destination" $ColorSuccess
} catch {
throw "Failed to copy directory: $($_.Exception.Message)"
}
}
function Copy-FileToDestination {
param(
[string]$Source,
[string]$Destination,
[string]$Description = "file",
[string]$BackupFolder = $null
)
if (Test-Path $Destination) {
# Use BackupAll mode for automatic backup without confirmation (default behavior)
if ($BackupAll -and -not $NoBackup) {
if ($BackupFolder -and (Backup-FileToFolder -FilePath $Destination -BackupFolder $BackupFolder)) {
Write-ColorOutput "Auto-backed up: $Description" $ColorSuccess
}
Copy-Item -Path $Source -Destination $Destination -Force
Write-ColorOutput "$Description updated (with backup)" $ColorSuccess
return $true
} elseif ($NoBackup) {
# No backup mode - ask for confirmation
if (Confirm-Action "$Description already exists. Replace it? (NO BACKUP)" -DefaultYes:$false) {
Copy-Item -Path $Source -Destination $Destination -Force
Write-ColorOutput "$Description updated (no backup)" $ColorWarning
return $true
} else {
Write-ColorOutput "Skipping $Description installation" $ColorWarning
return $false
}
} elseif (Confirm-Action "$Description already exists. Replace it?" -DefaultYes:$false) {
if ($BackupFolder -and (Backup-FileToFolder -FilePath $Destination -BackupFolder $BackupFolder)) {
Write-ColorOutput "Existing $Description backed up" $ColorSuccess
}
Copy-Item -Path $Source -Destination $Destination -Force
Write-ColorOutput "$Description updated" $ColorSuccess
return $true
} else {
Write-ColorOutput "Skipping $Description installation" $ColorWarning
return $false
}
} else {
# Ensure destination directory exists
$destinationDir = Split-Path $Destination -Parent
if (-not (Test-Path $destinationDir)) {
New-Item -ItemType Directory -Path $destinationDir -Force | Out-Null
}
Copy-Item -Path $Source -Destination $Destination -Force
Write-ColorOutput "$Description installed" $ColorSuccess
return $true
}
}
function Merge-DirectoryContents {
param(
[string]$Source,
[string]$Destination,
[string]$Description = "directory contents",
[string]$BackupFolder = $null
)
if (-not (Test-Path $Source)) {
Write-ColorOutput "WARNING: Source $Description not found: $Source" $ColorWarning
return $false
}
# Create destination directory if it doesn't exist
if (-not (Test-Path $Destination)) {
New-Item -ItemType Directory -Path $Destination -Force | Out-Null
Write-ColorOutput "Created destination directory: $Destination" $ColorInfo
}
# Get all items in source directory
$sourceItems = Get-ChildItem -Path $Source -Recurse -File
$mergedCount = 0
$skippedCount = 0
foreach ($item in $sourceItems) {
# Calculate relative path from source
$relativePath = $item.FullName.Substring($Source.Length + 1)
$destinationPath = Join-Path $Destination $relativePath
# Ensure destination directory exists
$destinationDir = Split-Path $destinationPath -Parent
if (-not (Test-Path $destinationDir)) {
New-Item -ItemType Directory -Path $destinationDir -Force | Out-Null
}
# Handle file merging
if (Test-Path $destinationPath) {
$fileName = Split-Path $relativePath -Leaf
# Use BackupAll mode for automatic backup without confirmation (default behavior)
if ($BackupAll -and -not $NoBackup) {
if ($BackupFolder -and (Backup-FileToFolder -FilePath $destinationPath -BackupFolder $BackupFolder)) {
Write-ColorOutput "Auto-backed up: $fileName" $ColorInfo
}
Copy-Item -Path $item.FullName -Destination $destinationPath -Force
$mergedCount++
} elseif ($NoBackup) {
# No backup mode - ask for confirmation
if (Confirm-Action "File '$relativePath' already exists. Replace it? (NO BACKUP)" -DefaultYes:$false) {
Copy-Item -Path $item.FullName -Destination $destinationPath -Force
$mergedCount++
} else {
Write-ColorOutput "Skipped $fileName (no backup)" $ColorWarning
$skippedCount++
}
} elseif (Confirm-Action "File '$relativePath' already exists. Replace it?" -DefaultYes:$false) {
if ($BackupFolder -and (Backup-FileToFolder -FilePath $destinationPath -BackupFolder $BackupFolder)) {
Write-ColorOutput "Backed up existing $fileName" $ColorInfo
}
Copy-Item -Path $item.FullName -Destination $destinationPath -Force
$mergedCount++
} else {
Write-ColorOutput "Skipped $fileName" $ColorWarning
$skippedCount++
}
} else {
Copy-Item -Path $item.FullName -Destination $destinationPath -Force
$mergedCount++
}
}
Write-ColorOutput "Merged $mergedCount files, skipped $skippedCount files" $ColorSuccess
return $true
}
function Install-Global {
Write-ColorOutput "Installing Claude Code Workflow System globally..." $ColorInfo
# Determine user profile directory
$userProfile = [Environment]::GetFolderPath("UserProfile")
$globalClaudeDir = Join-Path $userProfile ".claude"
$globalClaudeMd = Join-Path $globalClaudeDir "CLAUDE.md"
Write-ColorOutput "Global installation path: $userProfile" $ColorInfo
# Source paths
$sourceDir = $PSScriptRoot
$sourceClaudeDir = Join-Path $sourceDir ".claude"
$sourceClaudeMd = Join-Path $sourceDir "CLAUDE.md"
# Create backup folder if needed (default behavior unless NoBackup is specified)
$backupFolder = $null
if (-not $NoBackup) {
if (Test-Path $globalClaudeDir) {
$existingFiles = Get-ChildItem $globalClaudeDir -Recurse -File -ErrorAction SilentlyContinue
if (($existingFiles -and ($existingFiles | Measure-Object).Count -gt 0)) {
$backupFolder = Get-BackupDirectory -TargetDirectory $userProfile
Write-ColorOutput "Backup folder created: $backupFolder" $ColorInfo
}
} elseif (Test-Path $globalClaudeMd) {
# Create backup folder even if .claude directory doesn't exist but CLAUDE.md does
$backupFolder = Get-BackupDirectory -TargetDirectory $userProfile
Write-ColorOutput "Backup folder created: $backupFolder" $ColorInfo
}
}
# Merge .claude directory contents (don't replace entire directory)
Write-ColorOutput "Merging .claude directory contents..." $ColorInfo
$claudeMerged = Merge-DirectoryContents -Source $sourceClaudeDir -Destination $globalClaudeDir -Description ".claude directory contents" -BackupFolder $backupFolder
# Handle CLAUDE.md file in .claude directory
Write-ColorOutput "Installing CLAUDE.md to global .claude directory..." $ColorInfo
$claudeMdInstalled = Copy-FileToDestination -Source $sourceClaudeMd -Destination $globalClaudeMd -Description "CLAUDE.md" -BackupFolder $backupFolder
if ($backupFolder -and (Test-Path $backupFolder)) {
$backupFiles = Get-ChildItem $backupFolder -Recurse -File -ErrorAction SilentlyContinue
if (-not $backupFiles -or ($backupFiles | Measure-Object).Count -eq 0) {
# Remove empty backup folder
Remove-Item -Path $backupFolder -Force
Write-ColorOutput "Removed empty backup folder" $ColorInfo
}
}
return $true
}
function Get-InstallationMode {
Write-ColorOutput "Installation mode: Global (installing to user profile ~/.claude/)" $ColorInfo
return "Global"
}
function Show-Summary {
param(
[string]$Mode,
[string]$Path,
[bool]$Success
)
Write-Host ""
if ($Success) {
Write-ColorOutput "Installation completed successfully!" $ColorSuccess
} else {
Write-ColorOutput "Installation completed with warnings" $ColorWarning
}
Write-ColorOutput "Installation Details:" $ColorInfo
Write-Host " Mode: $Mode"
Write-Host " Path: $Path"
if ($NoBackup) {
Write-Host " Backup: Disabled (no backup created)"
} elseif ($BackupAll) {
Write-Host " Backup: Enabled (automatic backup of all existing files)"
} else {
Write-Host " Backup: Enabled (default behavior)"
}
Write-Host ""
Write-ColorOutput "Next steps:" $ColorInfo
Write-Host "1. Review CLAUDE.md - Customize guidelines for your project"
Write-Host "2. Configure settings - Edit .claude/settings.local.json as needed"
Write-Host "3. Start using Claude Code with Agent workflow coordination!"
Write-Host "4. Use /workflow commands for task execution"
Write-Host "5. Use /update_dms commands for memory system management"
Write-Host ""
Write-ColorOutput "Documentation: https://github.com/catlog22/Claude-CCW" $ColorInfo
Write-ColorOutput "Features: Unified workflow system with comprehensive file output generation" $ColorInfo
}
function Main {
Show-Header
# Test prerequisites
Write-ColorOutput "Checking system requirements..." $ColorInfo
if (-not (Test-Prerequisites)) {
Write-ColorOutput "Prerequisites check failed!" $ColorError
return 1
}
try {
# Get installation mode
$mode = Get-InstallationMode
$installPath = ""
$success = $false
$installPath = [Environment]::GetFolderPath("UserProfile")
$success = Install-Global
Show-Summary -Mode $mode -Path $installPath -Success $success
# Wait for user confirmation before exit in interactive mode
if (-not $NonInteractive) {
Write-Host ""
Write-ColorOutput "Installation completed. Press any key to exit..." $ColorPrompt
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}
if ($success) {
return 0
} else {
return 1
}
} catch {
Write-ColorOutput "CRITICAL ERROR: $($_.Exception.Message)" $ColorError
# Wait for user confirmation before exit in interactive mode
if (-not $NonInteractive) {
Write-Host ""
Write-ColorOutput "An error occurred. Press any key to exit..." $ColorPrompt
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}
return 1
}
}
# Run main function
exit (Main)