Files
claude/claude-code-installer.ps1

1039 lines
37 KiB
PowerShell
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#Requires -Version 5.1
<#
.SYNOPSIS
Claude Code Installer for Windows
A colorized, interactive installer with full system detection
.DESCRIPTION
This script automates the installation of Claude Code on Windows systems.
Features:
- Detects Windows version and architecture
- Checks/removes existing Node.js and npm installations
- Installs Node.js 20 LTS
- Installs Claude Code
- Configures permissions interactively
.NOTES
Author: BitMaster
Repository: https://git.bitmaster.cc/BitMaster/claude
License: MIT
.EXAMPLE
.\claude-code-installer.ps1
.EXAMPLE
# Run directly from web
irm https://git.bitmaster.cc/BitMaster/claude/raw/branch/main/claude-code-installer.ps1 | iex
#>
# Ensure we're running with proper execution
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"
#-------------------------------------------------------------------------------
# Configuration
#-------------------------------------------------------------------------------
$script:BoxWidth = 65 # Inner width of boxes
#-------------------------------------------------------------------------------
# Color and Display Functions
#-------------------------------------------------------------------------------
function Write-ColorText {
param(
[string]$Text,
[ConsoleColor]$Color = "White",
[switch]$NoNewline
)
if ($NoNewline) {
Write-Host $Text -ForegroundColor $Color -NoNewline
} else {
Write-Host $Text -ForegroundColor $Color
}
}
function Write-BoxTop {
param([int]$Width = $script:BoxWidth)
$line = "" * $Width
Write-ColorText "$line" -Color White
}
function Write-BoxMiddle {
param([int]$Width = $script:BoxWidth)
$line = "" * $Width
Write-ColorText "$line" -Color White
}
function Write-BoxBottom {
param([int]$Width = $script:BoxWidth)
$line = "" * $Width
Write-ColorText "$line" -Color White
}
function Write-BoxTitle {
param(
[string]$Title,
[int]$Width = $script:BoxWidth
)
$padding = $Width - $Title.Length - 2
$leftPad = [math]::Floor($padding / 2)
$rightPad = $padding - $leftPad
Write-ColorText "" -Color White -NoNewline
Write-ColorText (" " * ($leftPad + 1)) -Color White -NoNewline
Write-ColorText $Title -Color White -NoNewline
Write-ColorText (" " * ($rightPad + 1)) -Color White -NoNewline
Write-ColorText "" -Color White
}
function Write-BoxEmpty {
param([int]$Width = $script:BoxWidth)
Write-ColorText "" -Color White -NoNewline
Write-ColorText (" " * $Width) -Color White -NoNewline
Write-ColorText "" -Color White
}
function Write-BoxContent {
param(
[string]$Label,
[ConsoleColor]$LabelColor = "Cyan",
[string]$Value,
[ConsoleColor]$ValueColor = "Green",
[int]$LabelWidth = 16,
[int]$Width = $script:BoxWidth
)
$paddedLabel = $Label.PadRight($LabelWidth)
$remainingWidth = $Width - $LabelWidth - 4 # 4 for prefix spacing
$paddedValue = $Value
if ($Value.Length -gt $remainingWidth) {
$paddedValue = $Value.Substring(0, $remainingWidth - 3) + "..."
}
$totalPadding = $Width - $paddedLabel.Length - $paddedValue.Length - 2
if ($totalPadding -lt 0) { $totalPadding = 0 }
Write-ColorText "" -Color White -NoNewline
Write-ColorText $paddedLabel -Color $LabelColor -NoNewline
Write-ColorText $paddedValue -Color $ValueColor -NoNewline
Write-ColorText (" " * $totalPadding) -Color White -NoNewline
Write-ColorText "" -Color White
}
function Write-BoxLine {
param(
[string]$Text,
[ConsoleColor]$Color = "White",
[int]$Width = $script:BoxWidth,
[int]$Indent = 1
)
$indentStr = " " * $Indent
$maxTextWidth = $Width - $Indent - 1
$displayText = $Text
if ($Text.Length -gt $maxTextWidth) {
$displayText = $Text.Substring(0, $maxTextWidth - 3) + "..."
}
$padding = $Width - $Indent - $displayText.Length - 1
if ($padding -lt 0) { $padding = 0 }
Write-ColorText "" -Color White -NoNewline
Write-ColorText $indentStr -Color White -NoNewline
Write-ColorText $displayText -Color $Color -NoNewline
Write-ColorText (" " * $padding) -Color White -NoNewline
Write-ColorText "" -Color White
}
function Write-BoxLineMultiColor {
param(
[array]$Parts, # Array of @{Text=""; Color="White"}
[int]$Width = $script:BoxWidth,
[int]$Indent = 1
)
$indentStr = " " * $Indent
$totalLength = $Indent
foreach ($part in $Parts) {
$totalLength += $part.Text.Length
}
$padding = $Width - $totalLength - 1
if ($padding -lt 0) { $padding = 0 }
Write-ColorText "" -Color White -NoNewline
Write-ColorText $indentStr -Color White -NoNewline
foreach ($part in $Parts) {
Write-ColorText $part.Text -Color $part.Color -NoNewline
}
Write-ColorText (" " * $padding) -Color White -NoNewline
Write-ColorText "" -Color White
}
function Write-Banner {
Clear-Host
Write-Host ""
Write-ColorText " ╔═══════════════════════════════════════════════════════════════════╗" -Color Cyan
Write-ColorText " ║ ║" -Color Cyan
Write-ColorText "" -Color Cyan -NoNewline
Write-ColorText "██████╗██╗ █████╗ ██╗ ██╗██████╗ ███████╗" -Color Cyan -NoNewline
Write-ColorText "" -Color Cyan
Write-ColorText "" -Color Cyan -NoNewline
Write-ColorText "██╔════╝██║ ██╔══██╗██║ ██║██╔══██╗██╔════╝" -Color Cyan -NoNewline
Write-ColorText "" -Color Cyan
Write-ColorText "" -Color Cyan -NoNewline
Write-ColorText "██║ ██║ ███████║██║ ██║██║ ██║█████╗" -Color Cyan -NoNewline
Write-ColorText "" -Color Cyan
Write-ColorText "" -Color Cyan -NoNewline
Write-ColorText "██║ ██║ ██╔══██║██║ ██║██║ ██║██╔══╝" -Color Cyan -NoNewline
Write-ColorText "" -Color Cyan
Write-ColorText "" -Color Cyan -NoNewline
Write-ColorText "╚██████╗███████╗██║ ██║╚██████╔╝██████╔╝███████╗" -Color Cyan -NoNewline
Write-ColorText "" -Color Cyan
Write-ColorText "" -Color Cyan -NoNewline
Write-ColorText "╚═════╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝" -Color Cyan -NoNewline
Write-ColorText "" -Color Cyan
Write-ColorText " ║ ║" -Color Cyan
Write-ColorText "" -Color Cyan -NoNewline
Write-ColorText "C O D E I N S T A L L E R" -Color White -NoNewline
Write-ColorText "" -Color Cyan
Write-ColorText " ║ ║" -Color Cyan
Write-ColorText "" -Color Cyan -NoNewline
Write-ColorText "[ Windows Edition ]" -Color Yellow -NoNewline
Write-ColorText "" -Color Cyan
Write-ColorText " ║ ║" -Color Cyan
Write-ColorText " ╚═══════════════════════════════════════════════════════════════════╝" -Color Cyan
Write-Host ""
}
function Write-Section {
param([string]$Title)
Write-Host ""
Write-ColorText " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -Color Blue
Write-ColorText " $Title" -Color White
Write-ColorText " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -Color Blue
Write-Host ""
}
function Write-Step {
param([string]$Message)
Write-ColorText "" -Color Cyan -NoNewline
Write-ColorText $Message -Color White
}
function Write-Success {
param([string]$Message)
Write-ColorText "" -Color Green -NoNewline
Write-ColorText $Message -Color Green
}
function Write-Error2 {
param([string]$Message)
Write-ColorText "" -Color Red -NoNewline
Write-ColorText $Message -Color Red
}
function Write-Warning2 {
param([string]$Message)
Write-ColorText "" -Color Yellow -NoNewline
Write-ColorText $Message -Color Yellow
}
function Write-Info {
param([string]$Message)
Write-ColorText " " -Color Blue -NoNewline
Write-ColorText $Message -Color DarkGray
}
function Confirm-Action {
param(
[string]$Prompt,
[bool]$DefaultYes = $true
)
if ($DefaultYes) {
$options = "[Y/n]"
} else {
$options = "[y/N]"
}
Write-ColorText " ? " -Color Yellow -NoNewline
Write-ColorText "$Prompt " -Color White -NoNewline
Write-ColorText $options -Color DarkGray -NoNewline
Write-ColorText ": " -Color White -NoNewline
$response = Read-Host
if ([string]::IsNullOrWhiteSpace($response)) {
return $DefaultYes
}
return $response -match "^[Yy]"
}
function Wait-ForKey {
Write-Host ""
Write-ColorText " Press any key to continue..." -Color DarkGray
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
Write-Host ""
}
#-------------------------------------------------------------------------------
# System Detection Functions
#-------------------------------------------------------------------------------
function Get-SystemInfo {
Write-Section "⚙ System Detection"
Write-Step "Identifying your Windows system..."
Start-Sleep -Milliseconds 500
# Get Windows version info
$os = Get-CimInstance -ClassName Win32_OperatingSystem
$cs = Get-CimInstance -ClassName Win32_ComputerSystem
$script:WindowsVersion = $os.Caption
$script:WindowsBuild = $os.BuildNumber
$script:WindowsArch = $cs.SystemType
$script:ComputerName = $cs.Name
$script:TotalRAM = [math]::Round($cs.TotalPhysicalMemory / 1GB, 2)
# Determine architecture for Node.js download
if ($env:PROCESSOR_ARCHITECTURE -eq "AMD64" -or $env:PROCESSOR_ARCHITEW6432 -eq "AMD64") {
$script:Arch = "x64"
$script:ArchDisplay = "64-bit (x64)"
} elseif ($env:PROCESSOR_ARCHITECTURE -eq "ARM64") {
$script:Arch = "arm64"
$script:ArchDisplay = "ARM64"
} else {
$script:Arch = "x86"
$script:ArchDisplay = "32-bit (x86)"
}
# Check if running as Administrator
$script:IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
# Check PowerShell version
$script:PSVersion = $PSVersionTable.PSVersion.ToString()
# Display detected information
Write-Host ""
Write-BoxTop
Write-BoxTitle -Title "System Information"
Write-BoxMiddle
Write-BoxContent -Label "Windows:" -Value $WindowsVersion
Write-BoxContent -Label "Build:" -Value $WindowsBuild
Write-BoxContent -Label "Architecture:" -Value $ArchDisplay
Write-BoxContent -Label "Computer:" -Value $ComputerName
Write-BoxContent -Label "RAM:" -Value "$TotalRAM GB"
Write-BoxContent -Label "PowerShell:" -Value "v$PSVersion"
if ($IsAdmin) {
Write-BoxContent -Label "Admin Rights:" -Value "Yes" -ValueColor Green
} else {
Write-BoxContent -Label "Admin Rights:" -Value "No" -ValueColor Yellow
}
Write-BoxBottom
Write-Host ""
Write-Success "System detected successfully!"
Start-Sleep -Seconds 1
}
#-------------------------------------------------------------------------------
# Node.js Detection and Installation
#-------------------------------------------------------------------------------
function Test-NodeInstallation {
Write-Section "📦 Node.js & npm Detection"
Write-Step "Checking for existing Node.js installation..."
Start-Sleep -Milliseconds 500
$script:NodeInstalled = $false
$script:NpmInstalled = $false
$script:NodeVersion = ""
$script:NpmVersion = ""
$script:NeedsUpgrade = $false
# Check Node.js
try {
$nodeOutput = & node --version 2>$null
if ($nodeOutput) {
$script:NodeInstalled = $true
$script:NodeVersion = $nodeOutput
}
} catch {
$script:NodeInstalled = $false
}
# Check npm
try {
$npmOutput = & npm --version 2>$null
if ($npmOutput) {
$script:NpmInstalled = $true
$script:NpmVersion = $npmOutput
}
} catch {
$script:NpmInstalled = $false
}
# Display current status
Write-Host ""
Write-BoxTop
Write-BoxTitle -Title "Current Installation Status"
Write-BoxMiddle
if ($NodeInstalled) {
# Check if version is sufficient (need v18+)
$versionNum = $NodeVersion -replace "v", ""
$majorVersion = [int]($versionNum.Split('.')[0])
if ($majorVersion -ge 18) {
Write-BoxLineMultiColor -Parts @(
@{Text=""; Color="Green"},
@{Text="Node.js: "; Color="White"},
@{Text="$NodeVersion"; Color="Green"},
@{Text=" (Compatible)"; Color="Green"}
)
} else {
Write-BoxLineMultiColor -Parts @(
@{Text=""; Color="Yellow"},
@{Text="Node.js: "; Color="White"},
@{Text="$NodeVersion"; Color="Yellow"},
@{Text=" (Needs upgrade to v18+)"; Color="Yellow"}
)
$script:NeedsUpgrade = $true
}
} else {
Write-BoxLineMultiColor -Parts @(
@{Text=""; Color="Red"},
@{Text="Node.js: "; Color="White"},
@{Text="Not installed"; Color="Red"}
)
$script:NeedsUpgrade = $true
}
if ($NpmInstalled) {
Write-BoxLineMultiColor -Parts @(
@{Text=""; Color="Green"},
@{Text="npm: "; Color="White"},
@{Text="v$NpmVersion"; Color="Green"}
)
} else {
Write-BoxLineMultiColor -Parts @(
@{Text=""; Color="Red"},
@{Text="npm: "; Color="White"},
@{Text="Not installed"; Color="Red"}
)
}
Write-BoxBottom
Write-Host ""
# Determine action needed
if ($NodeInstalled -and $NeedsUpgrade) {
Write-Warning2 "Your Node.js version is incompatible with Claude Code."
Write-Info "Claude Code requires Node.js version 18.0.0 or higher."
Write-Host ""
if (Confirm-Action "Would you like to uninstall the existing version and install Node.js 20 LTS?") {
Uninstall-Node
Install-Node
} else {
Write-Error2 "Cannot proceed without Node.js 18+. Exiting."
exit 1
}
} elseif (-not $NodeInstalled) {
Write-Info "Node.js is not installed on your system."
Write-Host ""
if (Confirm-Action "Would you like to install Node.js 20 LTS?") {
Install-Node
} else {
Write-Error2 "Cannot proceed without Node.js. Exiting."
exit 1
}
} else {
Write-Success "Node.js installation is compatible!"
Write-Host ""
if (Confirm-Action "Would you like to reinstall Node.js anyway (fresh installation)?" -DefaultYes $false) {
Uninstall-Node
Install-Node
}
}
}
function Uninstall-Node {
Write-Section "⚙ Removing Existing Node.js Installation"
Write-Step "Searching for Node.js installations..."
Write-Host ""
# Check for Node.js in common locations
$nodePaths = @(
"$env:ProgramFiles\nodejs",
"${env:ProgramFiles(x86)}\nodejs",
"$env:LOCALAPPDATA\Programs\nodejs"
)
# Try to uninstall via Windows installer
Write-ColorText "" -Color Yellow -NoNewline
Write-ColorText "Checking for installed Node.js package..." -Color White
$uninstallKeys = @(
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*",
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*",
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*"
)
$nodePackage = $null
foreach ($key in $uninstallKeys) {
$nodePackage = Get-ItemProperty $key -ErrorAction SilentlyContinue |
Where-Object { $_.DisplayName -like "*Node.js*" -or $_.DisplayName -like "*Node*" } |
Select-Object -First 1
if ($nodePackage) { break }
}
if ($nodePackage -and $nodePackage.UninstallString) {
Write-ColorText "" -Color Yellow -NoNewline
Write-ColorText "Found Node.js installation. Uninstalling..." -Color White
try {
$uninstallCmd = $nodePackage.UninstallString
if ($uninstallCmd -match "msiexec") {
# MSI uninstall
$productCode = $uninstallCmd -replace ".*(\{[A-F0-9-]+\}).*", '$1'
if ($productCode -match "^\{") {
Start-Process "msiexec.exe" -ArgumentList "/x $productCode /qn" -Wait -NoNewWindow
}
} else {
Start-Process $uninstallCmd -ArgumentList "/S" -Wait -NoNewWindow -ErrorAction SilentlyContinue
}
Write-ColorText " done" -Color Green
} catch {
Write-ColorText " manual removal required" -Color Yellow
}
}
# Remove Node.js directories
foreach ($path in $nodePaths) {
if (Test-Path $path) {
Write-ColorText "" -Color Yellow -NoNewline
Write-ColorText "Removing $path..." -Color White -NoNewline
try {
Remove-Item -Path $path -Recurse -Force -ErrorAction Stop
Write-ColorText " done" -Color Green
} catch {
Write-ColorText " failed (may need admin rights)" -Color Red
}
}
}
# Remove npm cache and global packages
$npmPaths = @(
"$env:APPDATA\npm",
"$env:APPDATA\npm-cache",
"$env:LOCALAPPDATA\npm-cache"
)
foreach ($path in $npmPaths) {
if (Test-Path $path) {
Write-ColorText "" -Color Yellow -NoNewline
Write-ColorText "Removing $path..." -Color White -NoNewline
try {
Remove-Item -Path $path -Recurse -Force -ErrorAction Stop
Write-ColorText " done" -Color Green
} catch {
Write-ColorText " skipped" -Color Yellow
}
}
}
# Remove from PATH (current session)
$env:Path = ($env:Path.Split(';') | Where-Object { $_ -notlike "*nodejs*" -and $_ -notlike "*npm*" }) -join ';'
Write-Host ""
Write-Success "Node.js removal completed!"
Start-Sleep -Seconds 1
}
function Install-Node {
Write-Section "📦 Installing Node.js 20 LTS"
Write-Step "Preparing to install Node.js 20 LTS..."
Write-Host ""
# Determine download URL based on architecture
$nodeVersion = "20.19.0" # LTS version
switch ($Arch) {
"x64" { $installerFile = "node-v$nodeVersion-x64.msi" }
"x86" { $installerFile = "node-v$nodeVersion-x86.msi" }
"arm64" { $installerFile = "node-v$nodeVersion-arm64.msi" }
default { $installerFile = "node-v$nodeVersion-x64.msi" }
}
$downloadUrl = "https://nodejs.org/dist/v$nodeVersion/$installerFile"
$installerPath = "$env:TEMP\$installerFile"
Write-ColorText "" -Color Yellow -NoNewline
Write-ColorText "Downloading Node.js v$nodeVersion ($Arch)..." -Color White
Write-Info " URL: $downloadUrl"
try {
# Download with progress
$webClient = New-Object System.Net.WebClient
$webClient.DownloadFile($downloadUrl, $installerPath)
Write-ColorText "" -Color Yellow -NoNewline
Write-ColorText "Download complete!" -Color Green
} catch {
Write-Error2 "Failed to download Node.js installer."
Write-Info "Please check your internet connection and try again."
Write-Info "Or download manually from: https://nodejs.org/"
exit 1
}
# Install Node.js
Write-Host ""
Write-ColorText "" -Color Yellow -NoNewline
Write-ColorText "Installing Node.js (this may take a minute)..." -Color White
try {
$installArgs = "/i `"$installerPath`" /qn /norestart"
$process = Start-Process "msiexec.exe" -ArgumentList $installArgs -Wait -PassThru -NoNewWindow
if ($process.ExitCode -eq 0) {
Write-ColorText "" -Color Yellow -NoNewline
Write-ColorText "Installation successful!" -Color Green
} elseif ($process.ExitCode -eq 3010) {
Write-ColorText "" -Color Yellow -NoNewline
Write-ColorText "Installation successful (restart may be required)" -Color Yellow
} else {
throw "MSI installer returned code: $($process.ExitCode)"
}
} catch {
Write-Error2 "Installation failed: $_"
Write-Info "Try running the installer manually: $installerPath"
exit 1
}
# Refresh environment variables
Write-ColorText "" -Color Yellow -NoNewline
Write-ColorText "Refreshing environment variables..." -Color White
# Add Node.js to PATH for current session
$nodePath = "$env:ProgramFiles\nodejs"
if (Test-Path $nodePath) {
$env:Path = "$nodePath;$env:APPDATA\npm;$env:Path"
}
# Also try to refresh from registry
$machinePath = [Environment]::GetEnvironmentVariable("Path", "Machine")
$userPath = [Environment]::GetEnvironmentVariable("Path", "User")
$env:Path = "$machinePath;$userPath"
Write-ColorText " done" -Color Green
# Cleanup
Write-ColorText "" -Color Yellow -NoNewline
Write-ColorText "Cleaning up installer..." -Color White -NoNewline
Remove-Item -Path $installerPath -Force -ErrorAction SilentlyContinue
Write-ColorText " done" -Color Green
Write-Host ""
Write-Success "Node.js installation completed!"
Start-Sleep -Seconds 1
}
function Test-NodeVerification {
Write-Section "✓ Verifying Installation"
Write-Step "Checking Node.js and npm versions..."
Write-Host ""
Start-Sleep -Milliseconds 500
# Refresh PATH
$nodePath = "$env:ProgramFiles\nodejs"
if (Test-Path $nodePath) {
$env:Path = "$nodePath;$env:APPDATA\npm;$env:Path"
}
$nodeOk = $false
$npmOk = $false
# Verify Node.js
try {
$newNodeVersion = & "$nodePath\node.exe" --version 2>$null
if (-not $newNodeVersion) {
$newNodeVersion = & node --version 2>$null
}
if ($newNodeVersion) {
$versionNum = $newNodeVersion -replace "v", ""
$majorVersion = [int]($versionNum.Split('.')[0])
if ($majorVersion -ge 18) {
Write-ColorText "" -Color Green -NoNewline
Write-ColorText "Node.js: " -Color White -NoNewline
Write-ColorText "$newNodeVersion" -Color Green -NoNewline
Write-ColorText " (Compatible!)" -Color Green
$nodeOk = $true
} else {
Write-ColorText "" -Color Red -NoNewline
Write-ColorText "Node.js: " -Color White -NoNewline
Write-ColorText "$newNodeVersion (Too old - need v18+)" -Color Red
}
} else {
throw "No version output"
}
} catch {
Write-ColorText "" -Color Red -NoNewline
Write-ColorText "Node.js: " -Color White -NoNewline
Write-ColorText "Not found!" -Color Red
}
# Verify npm
try {
$newNpmVersion = & "$nodePath\npm.cmd" --version 2>$null
if (-not $newNpmVersion) {
$newNpmVersion = & npm --version 2>$null
}
if ($newNpmVersion) {
Write-ColorText "" -Color Green -NoNewline
Write-ColorText "npm: " -Color White -NoNewline
Write-ColorText "v$newNpmVersion" -Color Green
$npmOk = $true
} else {
throw "No version output"
}
} catch {
Write-ColorText "" -Color Red -NoNewline
Write-ColorText "npm: " -Color White -NoNewline
Write-ColorText "Not found!" -Color Red
}
# Show paths
Write-Host ""
Write-Info "Node path: $nodePath\node.exe"
Write-Info "npm path: $nodePath\npm.cmd"
Write-Host ""
if ($nodeOk -and $npmOk) {
Write-Success "All requirements verified successfully!"
return $true
} else {
Write-Error2 "Verification failed! Please check the installation."
return $false
}
}
#-------------------------------------------------------------------------------
# Claude Code Installation
#-------------------------------------------------------------------------------
function Install-ClaudeCode {
Write-Section "🚀 Installing Claude Code"
Write-Step "Installing Claude Code via npm..."
Write-Host ""
# Ensure npm is in PATH
$nodePath = "$env:ProgramFiles\nodejs"
$npmPath = "$env:APPDATA\npm"
$env:Path = "$nodePath;$npmPath;$env:Path"
Write-ColorText "" -Color Yellow -NoNewline
Write-ColorText "Running npm install..." -Color White
Write-Host ""
try {
# Install Claude Code globally
$npmCmd = if (Test-Path "$nodePath\npm.cmd") { "$nodePath\npm.cmd" } else { "npm" }
$process = Start-Process -FilePath $npmCmd -ArgumentList "install", "-g", "@anthropic-ai/claude-code" -Wait -PassThru -NoNewWindow -RedirectStandardOutput "$env:TEMP\npm-out.txt" -RedirectStandardError "$env:TEMP\npm-err.txt"
# Display output
if (Test-Path "$env:TEMP\npm-out.txt") {
$output = Get-Content "$env:TEMP\npm-out.txt" -Raw
if ($output) {
$output.Split("`n") | ForEach-Object {
if ($_ -match "added|packages") {
Write-ColorText " $_" -Color Green
} elseif ($_ -match "WARN") {
Write-ColorText " $_" -Color Yellow
} elseif ($_.Trim()) {
Write-ColorText " $_" -Color DarkGray
}
}
}
Remove-Item "$env:TEMP\npm-out.txt" -Force -ErrorAction SilentlyContinue
}
if (Test-Path "$env:TEMP\npm-err.txt") {
$errOutput = Get-Content "$env:TEMP\npm-err.txt" -Raw
if ($errOutput -and $errOutput.Trim()) {
$errOutput.Split("`n") | ForEach-Object {
if ($_ -match "ERR|error") {
Write-ColorText " $_" -Color Red
} elseif ($_ -match "WARN") {
Write-ColorText " $_" -Color Yellow
}
}
}
Remove-Item "$env:TEMP\npm-err.txt" -Force -ErrorAction SilentlyContinue
}
if ($process.ExitCode -ne 0) {
throw "npm install failed with exit code: $($process.ExitCode)"
}
} catch {
Write-Error2 "Failed to install Claude Code: $_"
Write-Info "Try running manually: npm install -g @anthropic-ai/claude-code"
return $false
}
Write-Host ""
# Verify installation
$claudePath = "$env:APPDATA\npm\claude.cmd"
if (Test-Path $claudePath) {
Write-Success "Claude Code installed successfully!"
Write-Info "Location: $claudePath"
return $true
} else {
# Check if claude is in PATH
$claudeInPath = Get-Command claude -ErrorAction SilentlyContinue
if ($claudeInPath) {
Write-Success "Claude Code installed successfully!"
Write-Info "Location: $($claudeInPath.Source)"
return $true
} else {
Write-Warning2 "Claude Code may have been installed but is not in PATH."
Write-Info "Try restarting your terminal or running: refreshenv"
return $true
}
}
}
#-------------------------------------------------------------------------------
# Permission Configuration
#-------------------------------------------------------------------------------
function Set-ClaudePermissions {
Write-Section "🛡 Permission Configuration"
Write-Host " Claude Code can run with different permission levels:"
Write-Host ""
Write-BoxTop
Write-BoxEmpty
# Option 1 - Normal Mode
Write-BoxLineMultiColor -Parts @(
@{Text="1."; Color="Cyan"},
@{Text=" Normal Mode"; Color="White"},
@{Text=" (Recommended for most users)"; Color="DarkGray"}
)
Write-BoxLine -Text "Claude will ask permission before file edits and commands" -Color DarkGray -Indent 4
Write-BoxLineMultiColor -Parts @(
@{Text="✓ Safe ✓ Interactive ✓ Full control"; Color="Green"}
) -Indent 4
Write-BoxEmpty
# Option 2 - Auto-Accept Edits
Write-BoxLineMultiColor -Parts @(
@{Text="2."; Color="Cyan"},
@{Text=" Auto-Accept Edits"; Color="White"}
)
Write-BoxLine -Text "Automatically accept file edits, ask for commands" -Color DarkGray -Indent 4
Write-BoxLineMultiColor -Parts @(
@{Text="⚡ Faster editing ✓ Command safety"; Color="Yellow"}
) -Indent 4
Write-BoxEmpty
# Option 3 - Full Auto Mode
Write-BoxLineMultiColor -Parts @(
@{Text="3."; Color="Cyan"},
@{Text=" Full Auto Mode"; Color="White"},
@{Text=" (--dangerously-skip-permissions)"; Color="DarkGray"}
)
Write-BoxLine -Text "Skip all permission prompts (use with caution!)" -Color DarkGray -Indent 4
Write-BoxLineMultiColor -Parts @(
@{Text="⚠ No confirmations ⚠ Full system access"; Color="Red"}
) -Indent 4
Write-BoxEmpty
# Option 4 - Don't start
Write-BoxLineMultiColor -Parts @(
@{Text="4."; Color="Cyan"},
@{Text=" Don't start Claude"; Color="White"}
)
Write-BoxLine -Text "Exit installer without starting Claude" -Color DarkGray -Indent 4
Write-BoxEmpty
Write-BoxBottom
Write-Host ""
while ($true) {
Write-ColorText " ? " -Color Yellow -NoNewline
Write-ColorText "Select permission mode [" -Color White -NoNewline
Write-ColorText "1" -Color Green -NoNewline
Write-ColorText "/" -Color White -NoNewline
Write-ColorText "2" -Color Cyan -NoNewline
Write-ColorText "/" -Color White -NoNewline
Write-ColorText "3" -Color Red -NoNewline
Write-ColorText "/" -Color White -NoNewline
Write-ColorText "4" -Color White -NoNewline
Write-ColorText "]: " -Color White -NoNewline
$choice = Read-Host
switch ($choice) {
"1" {
$script:PermissionMode = "normal"
$script:ClaudeCmd = "claude"
Write-Success "Selected: Normal Mode"
return
}
"2" {
$script:PermissionMode = "auto-edit"
$script:ClaudeCmd = "claude --auto-accept-edits"
Write-Success "Selected: Auto-Accept Edits"
return
}
"3" {
$script:PermissionMode = "full-auto"
Write-Host ""
Write-Warning2 "⚠️ WARNING: Full Auto Mode gives Claude unrestricted access!"
Write-ColorText " This mode will:" -Color Red
Write-ColorText " • Execute commands without confirmation" -Color Red
Write-ColorText " • Modify files without asking" -Color Red
Write-ColorText " • Have full access to your system" -Color Red
Write-Host ""
if (Confirm-Action "Are you sure you want to use Full Auto Mode?" -DefaultYes $false) {
$script:ClaudeCmd = "claude --dangerously-skip-permissions"
Write-Success "Selected: Full Auto Mode"
return
} else {
Write-Host ""
Write-Info "Please select a different mode."
Write-Host ""
}
}
"4" {
$script:PermissionMode = "exit"
$script:ClaudeCmd = ""
Write-Info "Installation complete. You can start Claude anytime with: claude"
return
}
default {
Write-Error2 "Invalid choice. Please enter 1, 2, 3, or 4."
}
}
}
}
#-------------------------------------------------------------------------------
# Launch Claude Code
#-------------------------------------------------------------------------------
function Start-Claude {
if ($PermissionMode -eq "exit") {
Write-Section "✓ Installation Complete!"
Write-ColorText " Claude Code has been successfully installed!" -Color Green
Write-Host ""
Write-ColorText " To start Claude Code, open a new terminal and run:" -Color White
Write-Host ""
Write-ColorText " claude" -Color Cyan -NoNewline
Write-ColorText " # Normal mode" -Color DarkGray
Write-ColorText " claude --auto-accept-edits" -Color Cyan -NoNewline
Write-ColorText " # Auto-accept file edits" -Color DarkGray
Write-ColorText " claude --dangerously-skip-permissions" -Color Cyan -NoNewline
Write-ColorText " # Full auto mode" -Color DarkGray
Write-Host ""
Write-Info "If 'claude' is not recognized, restart your terminal to refresh PATH."
Write-Host ""
Write-Success "Thank you for installing Claude Code!"
return
}
Write-Section "🚀 Launching Claude Code"
Write-ColorText " Starting Claude Code with: " -Color White -NoNewline
Write-ColorText $ClaudeCmd -Color Cyan
Write-Host ""
Write-ColorText " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -Color DarkGray
Write-Host ""
Start-Sleep -Seconds 1
# Ensure PATH is set
$npmPath = "$env:APPDATA\npm"
$env:Path = "$npmPath;$env:Path"
# Launch Claude
try {
if ($PermissionMode -eq "normal") {
& claude
} elseif ($PermissionMode -eq "auto-edit") {
& claude --auto-accept-edits
} else {
& claude --dangerously-skip-permissions
}
} catch {
Write-Error2 "Failed to start Claude Code."
Write-Info "Try opening a new terminal and running: $ClaudeCmd"
}
}
#-------------------------------------------------------------------------------
# Main Script Execution
#-------------------------------------------------------------------------------
function Main {
# Check Windows version
if ([Environment]::OSVersion.Platform -ne "Win32NT") {
Write-Error2 "This script is designed for Windows only."
exit 1
}
# Display banner
Write-Banner
Write-ColorText " Welcome to the Claude Code Installer!" -Color White
Write-Host ""
Write-ColorText " This script will:" -Color DarkGray
Write-ColorText " 1. Detect your Windows system" -Color DarkGray
Write-ColorText " 2. Check/install Node.js 20 LTS" -Color DarkGray
Write-ColorText " 3. Install Claude Code" -Color DarkGray
Write-ColorText " 4. Configure permissions" -Color DarkGray
Write-Host ""
if (-not (Confirm-Action "Ready to begin installation?")) {
Write-Host ""
Write-Info "Installation cancelled. Goodbye!"
exit 0
}
# Run installation steps
Get-SystemInfo
Test-NodeInstallation
if (-not (Test-NodeVerification)) {
exit 1
}
if (-not (Install-ClaudeCode)) {
exit 1
}
Set-ClaudePermissions
Start-Claude
}
# Run main function
Main