install_claude_hooks_windows.ps1•13.9 kB
# Claude Code Memory Awareness Hooks - Windows Installation Script v2.2.0
# Installs hooks into Claude Code hooks directory for automatic memory awareness
# Enhanced Output Control and Session Management
param(
    [switch]$Uninstall,
    [switch]$Test,
    [switch]$Help
)
$ErrorActionPreference = "Stop"
# Configuration - Detect proper Claude Code hooks directory
function Get-ClaudeHooksDirectory {
    # Primary location: User profile (updated to match actual Claude Code directory structure)
    $primaryPath = "$env:USERPROFILE\.claude\hooks"
    
    # Alternative locations to check
    $alternativePaths = @(
        "$env:APPDATA\.claude\hooks",
        "$env:LOCALAPPDATA\.claude\hooks"
    )
    
    # If primary path already exists, use it
    if (Test-Path $primaryPath) {
        return $primaryPath
    }
    
    # Check if Claude Code is installed and can tell us the hooks directory
    try {
        $claudeHelp = claude --help 2>$null
        if ($claudeHelp -match "hooks.*directory.*(\S+)") {
            $detectedPath = $matches[1]
            if ($detectedPath -and (Test-Path (Split-Path -Parent $detectedPath) -ErrorAction SilentlyContinue)) {
                return $detectedPath
            }
        }
    } catch {
        # Claude CLI not available or failed
    }
    
    # Check alternative locations
    foreach ($altPath in $alternativePaths) {
        if (Test-Path $altPath) {
            return $altPath
        }
    }
    
    # Default to primary path (will be created if needed)
    return $primaryPath
}
$CLAUDE_HOOKS_DIR = Get-ClaudeHooksDirectory
# Script is now in the claude-hooks directory itself
$SCRIPT_DIR = $PSScriptRoot
$SOURCE_DIR = $SCRIPT_DIR
$dateStr = Get-Date -Format "yyyyMMdd-HHmmss"
$BACKUP_DIR = "$env:USERPROFILE\.claude\hooks-backup-$dateStr"
# Debug: Display resolved paths
function Write-Info { Write-Host "[INFO]" -ForegroundColor Green -NoNewline; Write-Host " $args" }
function Write-Warn { Write-Host "[WARN]" -ForegroundColor Yellow -NoNewline; Write-Host " $args" }
function Write-Error { Write-Host "[ERROR]" -ForegroundColor Red -NoNewline; Write-Host " $args" }
Write-Info "Script location: $SCRIPT_DIR"
Write-Info "Repository root: $REPO_ROOT" 
Write-Info "Source hooks directory: $SOURCE_DIR"
Write-Info "Target hooks directory: $CLAUDE_HOOKS_DIR"
# Show help
if ($Help) {
    Write-Host @"
Claude Code Memory Awareness Hooks - Windows Installation
Usage: .\install_claude_hooks_windows.ps1 [options]
Options:
  -Help       Show this help message
  -Uninstall  Remove installed hooks
  -Test       Run tests only
Examples:
  .\install_claude_hooks_windows.ps1              # Install hooks
  .\install_claude_hooks_windows.ps1 -Uninstall   # Remove hooks
  .\install_claude_hooks_windows.ps1 -Test        # Test installation
"@
    exit 0
}
# Header
Write-Host ""
Write-Host "Claude Code Memory Awareness Hooks Installation v2.2.0 (Windows)" -ForegroundColor Cyan
Write-Host "================================================================" -ForegroundColor Cyan
Write-Host ""
# Check if Claude Code is installed
function Test-ClaudeCode {
    $claudePath = Get-Command claude -ErrorAction SilentlyContinue
    if (-not $claudePath) {
        Write-Warn "Claude Code CLI not found in PATH"
        Write-Warn "Please ensure Claude Code is installed and accessible"
        $response = Read-Host "Continue anyway? (Y/N)"
        if ($response -ne "Y" -and $response -ne "y") {
            exit 1
        }
    } else {
        Write-Info "Claude Code CLI found: $($claudePath.Source)"
    }
}
# Validate source directory exists
function Test-SourceDirectory {
    Write-Info "Validating source directory..."
    
    if (-not (Test-Path $SOURCE_DIR)) {
        Write-Error "Source hooks directory not found: $SOURCE_DIR"
        Write-Error "Please ensure you are running this script from the mcp-memory-service repository"
        Write-Error "Expected repository structure:"
        Write-Error "  mcp-memory-service/"
        Write-Error "    scripts/"
        Write-Error "      install_claude_hooks_windows.ps1  (This script)"
        Write-Error "    claude-hooks/"
        Write-Error "      core/"
        Write-Error "      utilities/"
        Write-Error "      config.json"
        exit 1
    }
    
    # Check for required subdirectories
    $requiredDirs = @("core", "utilities", "tests")
    foreach ($dir in $requiredDirs) {
        $dirPath = Join-Path $SOURCE_DIR $dir
        if (-not (Test-Path $dirPath)) {
            Write-Error "Missing required directory: $dirPath"
            Write-Error "The claude-hooks directory appears to be incomplete"
            exit 1
        }
    }
    
    Write-Info "Source directory validation passed"
}
# Create Claude Code hooks directory if it does not exist
function New-HooksDirectory {
    if (-not (Test-Path $CLAUDE_HOOKS_DIR)) {
        Write-Info "Creating Claude Code hooks directory: $CLAUDE_HOOKS_DIR"
        try {
            New-Item -ItemType Directory -Path $CLAUDE_HOOKS_DIR -Force | Out-Null
            Write-Info "Successfully created hooks directory"
        } catch {
            Write-Error "Failed to create hooks directory: $CLAUDE_HOOKS_DIR"
            Write-Error "Error: $($_.Exception.Message)"
            Write-Error ""
            Write-Error "Possible solutions:"
            Write-Error "  1. Run PowerShell as Administrator"
            Write-Error "  2. Check if the parent directory exists and is writable"
            Write-Error "  3. Manually create the directory: $CLAUDE_HOOKS_DIR"
            exit 1
        }
    } else {
        Write-Info "Claude Code hooks directory exists: $CLAUDE_HOOKS_DIR"
    }
    
    # Test write access
    $testFile = Join-Path $CLAUDE_HOOKS_DIR "write-test.tmp"
    try {
        "test" | Out-File -FilePath $testFile -Force
        Remove-Item -Path $testFile -Force
        Write-Info "Write access confirmed for hooks directory"
    } catch {
        Write-Error "No write access to hooks directory: $CLAUDE_HOOKS_DIR"
        Write-Error "Please check permissions or run as Administrator"
        exit 1
    }
}
# Backup existing hooks if they exist
function Backup-ExistingHooks {
    $hasExisting = $false
    
    if ((Test-Path "$CLAUDE_HOOKS_DIR\core") -or 
        (Test-Path "$CLAUDE_HOOKS_DIR\utilities") -or
        (Test-Path "$CLAUDE_HOOKS_DIR\config.json")) {
        $hasExisting = $true
    }
    
    if ($hasExisting) {
        Write-Info "Backing up existing hooks to: $BACKUP_DIR"
        New-Item -ItemType Directory -Path $BACKUP_DIR -Force | Out-Null
        Copy-Item -Path "$CLAUDE_HOOKS_DIR\*" -Destination $BACKUP_DIR -Recurse -Force -ErrorAction SilentlyContinue
        Write-Info "Backup created successfully"
    }
}
# Install hook files
function Install-Hooks {
    Write-Info "Installing memory awareness hooks..."
    
    # Create necessary directories
    New-Item -ItemType Directory -Path "$CLAUDE_HOOKS_DIR\core" -Force | Out-Null
    New-Item -ItemType Directory -Path "$CLAUDE_HOOKS_DIR\utilities" -Force | Out-Null
    New-Item -ItemType Directory -Path "$CLAUDE_HOOKS_DIR\tests" -Force | Out-Null
    
    # Copy core hooks
    Copy-Item -Path "$SOURCE_DIR\core\*" -Destination "$CLAUDE_HOOKS_DIR\core\" -Recurse -Force
    Write-Info "Installed core hooks (session-start, session-end, topic-change)"
    
    # Copy utilities
    Copy-Item -Path "$SOURCE_DIR\utilities\*" -Destination "$CLAUDE_HOOKS_DIR\utilities\" -Recurse -Force
    Write-Info "Installed utility modules"
    
    # Copy tests
    Copy-Item -Path "$SOURCE_DIR\tests\*" -Destination "$CLAUDE_HOOKS_DIR\tests\" -Recurse -Force
    Write-Info "Installed test suite"
    
    # Copy documentation and configuration
    Copy-Item -Path "$SOURCE_DIR\README.md" -Destination "$CLAUDE_HOOKS_DIR\" -Force
    Copy-Item -Path "$SOURCE_DIR\config.template.json" -Destination "$CLAUDE_HOOKS_DIR\" -Force
    Write-Info "Installed documentation and templates"
}
# Install or update configuration
function Install-Config {
    $configFile = "$CLAUDE_HOOKS_DIR\config.json"
    
    if (-not (Test-Path $configFile)) {
        # First installation - use default config
        Copy-Item -Path "$SOURCE_DIR\config.json" -Destination $configFile -Force
        Write-Info "Installed default configuration"
        Write-Warn "Please update config.json with your memory service endpoint and API key"
    } else {
        Write-Info "Configuration file already exists - not overwriting"
        Write-Info "   Compare with config.template.json for new options"
    }
}
# Test installation
function Test-Installation {
    Write-Info "Testing installation..."
    
    # Check if required files exist
    $requiredFiles = @(
        "core\session-start.js",
        "core\session-end.js",
        "utilities\project-detector.js",
        "utilities\memory-scorer.js",
        "utilities\context-formatter.js",
        "config.json",
        "README.md"
    )
    
    $missingFiles = @()
    foreach ($file in $requiredFiles) {
        if (-not (Test-Path "$CLAUDE_HOOKS_DIR\$file")) {
            $missingFiles += $file
        }
    }
    
    if ($missingFiles.Count -gt 0) {
        Write-Error "Installation incomplete - missing files:"
        foreach ($file in $missingFiles) {
            Write-Host "  - $file"
        }
        return $false
    }
    
    # Test Node.js availability
    $nodeVersion = node --version 2>$null
    if (-not $nodeVersion) {
        Write-Warn "Node.js not found - hooks require Node.js to function"
        Write-Warn "Please install Node.js version 14 or higher"
    } else {
        Write-Info "Node.js available: $nodeVersion"
    }
    
    # Run integration test
    if (Test-Path "$CLAUDE_HOOKS_DIR\tests\integration-test.js") {
        Write-Info "Running integration tests..."
        Push-Location $CLAUDE_HOOKS_DIR
        try {
            $testResult = node tests\integration-test.js 2>&1
            if ($LASTEXITCODE -eq 0) {
                Write-Info "Integration tests passed"
            } else {
                Write-Warn "Some integration tests failed - check configuration"
                Write-Host $testResult
            }
        } finally {
            Pop-Location
        }
    }
    
    return $true
}
# Display post-installation instructions
function Show-PostInstallInstructions {
    Write-Host ""
    Write-Host "Installation Complete!" -ForegroundColor Green
    Write-Host "=====================" -ForegroundColor Green
    Write-Host ""
    Write-Host "Next Steps:" -ForegroundColor Yellow
    Write-Host ""
    Write-Host "1. Configure your memory service endpoint:"
    Write-Host "   Edit: $CLAUDE_HOOKS_DIR\config.json"
    Write-Host "   Update endpoint and apiKey values"
    Write-Host ""
    Write-Host "2. Test the hooks:"
    Write-Host "   cd $CLAUDE_HOOKS_DIR"
    Write-Host "   node tests\integration-test.js"
    Write-Host ""
    Write-Host "3. Start using Claude Code:"
    Write-Host "   The hooks will automatically activate on session start/end"
    Write-Host ""
    Write-Host "Installation Details:" -ForegroundColor Cyan
    Write-Host "   Hooks Directory: $CLAUDE_HOOKS_DIR"
    if (Test-Path $BACKUP_DIR) {
        Write-Host "   Backup Directory: $BACKUP_DIR"
    }
    Write-Host ""
    
    # Try to read and display current configuration
    $configPath = Join-Path $CLAUDE_HOOKS_DIR "config.json"
    if (Test-Path $configPath) {
        try {
            $config = Get-Content $configPath | ConvertFrom-Json
            Write-Host "Configuration:" -ForegroundColor Cyan
            Write-Host "   Memory Service: $($config.memoryService.endpoint)"
            Write-Host "   Max Memories: $($config.memoryService.maxMemoriesPerSession)"
        } catch {
            Write-Warn "Could not read configuration file"
        }
    }
    Write-Host ""
    $readmePath = Join-Path $CLAUDE_HOOKS_DIR "README.md"
    Write-Host "For troubleshooting, see: $readmePath"
}
# Uninstall function
function Uninstall-Hooks {
    if (Test-Path $CLAUDE_HOOKS_DIR) {
        $response = Read-Host "Remove all Claude Code memory awareness hooks? (Y/N)"
        if ($response -eq "Y" -or $response -eq "y") {
            Remove-Item -Path "$CLAUDE_HOOKS_DIR\core" -Recurse -Force -ErrorAction SilentlyContinue
            Remove-Item -Path "$CLAUDE_HOOKS_DIR\utilities" -Recurse -Force -ErrorAction SilentlyContinue
            Remove-Item -Path "$CLAUDE_HOOKS_DIR\tests" -Recurse -Force -ErrorAction SilentlyContinue
            Remove-Item -Path "$CLAUDE_HOOKS_DIR\config.json" -Force -ErrorAction SilentlyContinue
            Remove-Item -Path "$CLAUDE_HOOKS_DIR\config.template.json" -Force -ErrorAction SilentlyContinue
            Remove-Item -Path "$CLAUDE_HOOKS_DIR\README.md" -Force -ErrorAction SilentlyContinue
            Write-Info "Hooks uninstalled successfully"
        }
    } else {
        Write-Info "No hooks found to uninstall"
    }
}
# Test only function
function Test-Only {
    if (Test-Path "$CLAUDE_HOOKS_DIR\tests\integration-test.js") {
        Push-Location $CLAUDE_HOOKS_DIR
        try {
            node tests\integration-test.js
        } finally {
            Pop-Location
        }
    } else {
        Write-Error "Tests not found - please install first"
        exit 1
    }
}
# Main execution
try {
    if ($Uninstall) {
        Uninstall-Hooks
    } elseif ($Test) {
        Test-Only
    } else {
        # Main installation process
        Test-SourceDirectory
        Test-ClaudeCode
        New-HooksDirectory
        Backup-ExistingHooks
        Install-Hooks
        Install-Config
        if (Test-Installation) {
            Show-PostInstallInstructions
        }
    }
} catch {
    Write-Host "ERROR: Installation failed" -ForegroundColor Red
    Write-Host $_.Exception.Message
    exit 1
}