# Install skills// into ~\.claude\skills\\ (or $env:CLAUDE_SKILLS_DIR) # Usage: install.ps1 [-Names ,] [-Prune] # no args = install all skills/* into target # -Prune = after install, remove target// dirs that are NOT in skills/* # (prune always scans full target, ignores -Names filter — it's a global cleanup) # # PowerShell port of install.sh — same behavior, native cmdlets, no bash dependency. [CmdletBinding()] param( [string[]]$Names = @(), [switch]$Prune ) $ErrorActionPreference = 'Stop' $root = Split-Path -Parent $PSScriptRoot $src = Join-Path $root 'skills' if ($env:CLAUDE_SKILLS_DIR) { $target = $env:CLAUDE_SKILLS_DIR } else { $target = Join-Path $env:USERPROFILE '.claude\skills' } if (-not (Test-Path $target)) { New-Item -ItemType Directory -Force -Path $target | Out-Null } if ($Names.Count -eq 0) { $Names = Get-ChildItem -Path $src -Directory | Sort-Object Name | Select-Object -ExpandProperty Name } foreach ($name in $Names) { $srcDir = Join-Path $src $name $dstDir = Join-Path $target $name if (-not (Test-Path $srcDir -PathType Container)) { Write-Warning "skip: $name (not found in skills/)" continue } if (-not (Test-Path (Join-Path $srcDir 'SKILL.md'))) { Write-Warning "skip: $name (missing SKILL.md)" continue } if (Test-Path $dstDir) { Remove-Item -Recurse -Force $dstDir } Copy-Item -Recurse $srcDir $dstDir Write-Host "installed: $name -> $dstDir" } if ($Prune) { $sourceNames = @(Get-ChildItem -Path $src -Directory | Select-Object -ExpandProperty Name) $installedDirs = Get-ChildItem -Path $target -Directory -ErrorAction SilentlyContinue foreach ($dir in $installedDirs) { if ($sourceNames -notcontains $dir.Name) { Write-Host "pruning: $($dir.Name) (not in skills/) -> $($dir.FullName)" Remove-Item -Recurse -Force $dir.FullName } } }