feat: migrate 12 personal skills + add build/install scripts
- skills/: editable sources for all 12 personal skills (caveman family, find-skills, project-bootstrap, task-status-wiki, using-context7, using-markitdown, wiki-maintainer, compress) - dist/: built .skill archives, committed (cross-machine deploy without needing zip on the target) - scripts/build.sh + build.ps1: zip skills/<name>/ into dist/<name>.skill; Windows fallback uses .NET ZipArchive (PS 5.1 Compress-Archive writes backslashes that break extraction on *nix) - scripts/install.sh: copy skills/<name>/ into ~/.claude/skills/<name>/ ($CLAUDE_SKILLS_DIR overrides target) - .wiki/source/repo-layout.md, build-notes.md: design + gotchas - .gitignore: keep dist/ tracked Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
71
scripts/build.ps1
Normal file
71
scripts/build.ps1
Normal file
@@ -0,0 +1,71 @@
|
||||
# Build .skill archives from skills/<name>/ into dist/<name>.skill
|
||||
# Usage: build.ps1 [-Names <name1>,<name2>] (no args = all)
|
||||
#
|
||||
# Uses .NET System.IO.Compression.ZipArchive directly to produce
|
||||
# spec-compliant ZIPs with forward-slash entry names (Windows PowerShell 5.1's
|
||||
# Compress-Archive writes backslashes, which break extraction on Linux/Mac).
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string[]]$Names = @()
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$root = Split-Path -Parent $PSScriptRoot
|
||||
$src = Join-Path $root 'skills'
|
||||
$dist = Join-Path $root 'dist'
|
||||
|
||||
if (-not (Test-Path $dist)) { New-Item -Type Directory -Path $dist | Out-Null }
|
||||
|
||||
if ($Names.Count -eq 0) {
|
||||
$Names = Get-ChildItem -Path $src -Directory | Sort-Object Name | Select-Object -ExpandProperty Name
|
||||
}
|
||||
|
||||
Add-Type -AssemblyName System.IO.Compression
|
||||
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||
|
||||
function New-SkillArchive {
|
||||
param(
|
||||
[string]$SkillName,
|
||||
[string]$SourceDir,
|
||||
[string]$OutPath
|
||||
)
|
||||
if (Test-Path $OutPath) { Remove-Item $OutPath -Force }
|
||||
|
||||
$sourceFull = (Resolve-Path $SourceDir).ProviderPath.TrimEnd('\','/')
|
||||
$archive = [System.IO.Compression.ZipFile]::Open(
|
||||
$OutPath,
|
||||
[System.IO.Compression.ZipArchiveMode]::Create
|
||||
)
|
||||
try {
|
||||
$files = Get-ChildItem -Path $sourceFull -Recurse -File
|
||||
foreach ($file in $files) {
|
||||
$rel = $file.FullName.Substring($sourceFull.Length + 1) -replace '\\','/'
|
||||
$entryName = "$SkillName/$rel"
|
||||
[System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile(
|
||||
$archive,
|
||||
$file.FullName,
|
||||
$entryName,
|
||||
[System.IO.Compression.CompressionLevel]::Optimal
|
||||
) | Out-Null
|
||||
}
|
||||
} finally {
|
||||
$archive.Dispose()
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($name in $Names) {
|
||||
$srcDir = Join-Path $src $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
|
||||
}
|
||||
$out = Join-Path $dist "$name.skill"
|
||||
New-SkillArchive -SkillName $name -SourceDir $srcDir -OutPath $out
|
||||
Write-Host "built: dist/$name.skill"
|
||||
}
|
||||
Reference in New Issue
Block a user