161 lines
5.3 KiB
PowerShell
161 lines
5.3 KiB
PowerShell
# install.ps1 — Link claude-meta config into ~/.claude/
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
$repoRoot = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path)
|
|
$sourceDir = Join-Path $repoRoot "home-claude"
|
|
$claudeDir = Join-Path $env:USERPROFILE ".claude"
|
|
|
|
# Verify source exists
|
|
if (-not (Test-Path $sourceDir)) {
|
|
Write-Host "ERROR: home-claude/ not found at $sourceDir" -ForegroundColor Red
|
|
exit 1
|
|
}
|
|
|
|
# Ensure ~/.claude/ is a real directory (never a symlink!)
|
|
if (Test-Path $claudeDir) {
|
|
$item = Get-Item $claudeDir -Force
|
|
if ($item.Attributes -band [System.IO.FileAttributes]::ReparsePoint) {
|
|
Write-Host "ERROR: ~/.claude/ is a symlink/junction. It must be a real directory." -ForegroundColor Red
|
|
Write-Host "Claude Code Bug #764: symlinked ~/.claude/ breaks file detection." -ForegroundColor Red
|
|
exit 1
|
|
}
|
|
} else {
|
|
New-Item -ItemType Directory -Path $claudeDir -Force | Out-Null
|
|
Write-Host "Created ~/.claude/" -ForegroundColor Cyan
|
|
}
|
|
|
|
# Verify same volume for junctions
|
|
$sourceVolume = (Get-Item $sourceDir).PSDrive.Name
|
|
$targetVolume = (Get-Item $claudeDir).PSDrive.Name
|
|
if ($sourceVolume -ne $targetVolume) {
|
|
Write-Host "WARNING: Source ($sourceVolume`:) and target ($targetVolume`:) are on different volumes." -ForegroundColor Yellow
|
|
Write-Host "Junctions require same volume. Falling back to file copy for directories." -ForegroundColor Yellow
|
|
$useJunctions = $false
|
|
} else {
|
|
$useJunctions = $true
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "Installing claude-meta config..." -ForegroundColor Cyan
|
|
Write-Host " Source: $sourceDir" -ForegroundColor Gray
|
|
Write-Host " Target: $claudeDir" -ForegroundColor Gray
|
|
Write-Host ""
|
|
|
|
$success = $true
|
|
|
|
# --- File Symlinks ---
|
|
$files = @("CLAUDE.md", "settings.json")
|
|
foreach ($file in $files) {
|
|
$src = Join-Path $sourceDir $file
|
|
$dst = Join-Path $claudeDir $file
|
|
|
|
if (-not (Test-Path $src)) {
|
|
Write-Host " SKIP: $file (not in repo)" -ForegroundColor Yellow
|
|
continue
|
|
}
|
|
|
|
# Remove existing file/link
|
|
if (Test-Path $dst) {
|
|
Remove-Item $dst -Force
|
|
}
|
|
|
|
# Try symlink first
|
|
try {
|
|
New-Item -ItemType SymbolicLink -Path $dst -Target $src -ErrorAction Stop | Out-Null
|
|
Write-Host " SYMLINK: $file -> $src" -ForegroundColor Green
|
|
} catch {
|
|
# Fallback: copy
|
|
Write-Host " WARNING: Symlink failed for $file (need Developer Mode?). Using copy." -ForegroundColor Yellow
|
|
Copy-Item $src $dst -Force
|
|
Write-Host " COPY: $file (changes won't auto-sync!)" -ForegroundColor Yellow
|
|
$success = $false
|
|
}
|
|
}
|
|
|
|
# --- Directory Junctions ---
|
|
$dirs = @("skills", "rules")
|
|
foreach ($dir in $dirs) {
|
|
$src = Join-Path $sourceDir $dir
|
|
$dst = Join-Path $claudeDir $dir
|
|
|
|
if (-not (Test-Path $src)) {
|
|
Write-Host " SKIP: $dir/ (not in repo)" -ForegroundColor Yellow
|
|
continue
|
|
}
|
|
|
|
# Remove existing dir/junction
|
|
if (Test-Path $dst) {
|
|
$item = Get-Item $dst -Force
|
|
if ($item.Attributes -band [System.IO.FileAttributes]::ReparsePoint) {
|
|
# It's a junction/symlink — remove it
|
|
cmd /c "rmdir `"$dst`"" 2>$null
|
|
} else {
|
|
Remove-Item $dst -Recurse -Force
|
|
}
|
|
}
|
|
|
|
if ($useJunctions) {
|
|
# Junction (no admin needed, same volume only)
|
|
cmd /c "mklink /J `"$dst`" `"$src`"" | Out-Null
|
|
if ($LASTEXITCODE -eq 0) {
|
|
Write-Host " JUNCTION: $dir/ -> $src" -ForegroundColor Green
|
|
} else {
|
|
# Fallback: copy
|
|
Copy-Item $src $dst -Recurse -Force
|
|
Write-Host " COPY: $dir/ (changes won't auto-sync!)" -ForegroundColor Yellow
|
|
$success = $false
|
|
}
|
|
} else {
|
|
Copy-Item $src $dst -Recurse -Force
|
|
Write-Host " COPY: $dir/ (different volume)" -ForegroundColor Yellow
|
|
$success = $false
|
|
}
|
|
}
|
|
|
|
# --- Validation ---
|
|
Write-Host ""
|
|
Write-Host "Validating..." -ForegroundColor Cyan
|
|
|
|
$valid = $true
|
|
foreach ($file in $files) {
|
|
$dst = Join-Path $claudeDir $file
|
|
if (Test-Path $dst) {
|
|
$content = Get-Content $dst -Raw -ErrorAction SilentlyContinue
|
|
if ($content) {
|
|
Write-Host " OK: $file readable" -ForegroundColor Green
|
|
} else {
|
|
Write-Host " FAIL: $file exists but empty/unreadable" -ForegroundColor Red
|
|
$valid = $false
|
|
}
|
|
} else {
|
|
Write-Host " FAIL: $file not found" -ForegroundColor Red
|
|
$valid = $false
|
|
}
|
|
}
|
|
|
|
foreach ($dir in $dirs) {
|
|
$dst = Join-Path $claudeDir $dir
|
|
if (Test-Path $dst) {
|
|
$count = (Get-ChildItem $dst -Recurse -File).Count
|
|
Write-Host " OK: $dir/ ($count files)" -ForegroundColor Green
|
|
} else {
|
|
Write-Host " FAIL: $dir/ not found" -ForegroundColor Red
|
|
$valid = $false
|
|
}
|
|
}
|
|
|
|
# --- Summary ---
|
|
Write-Host ""
|
|
if ($valid) {
|
|
Write-Host "Installation complete!" -ForegroundColor Green
|
|
if (-not $success) {
|
|
Write-Host ""
|
|
Write-Host "NOTE: Some items were copied instead of linked." -ForegroundColor Yellow
|
|
Write-Host "Enable Developer Mode (Settings > Developer) for symlinks," -ForegroundColor Yellow
|
|
Write-Host "or re-run after changes with: .\scripts\install.ps1" -ForegroundColor Yellow
|
|
}
|
|
} else {
|
|
Write-Host "Installation had errors. Check output above." -ForegroundColor Red
|
|
exit 1
|
|
}
|