# Build .skill archives from skills// into dist/.skill # Usage: build.ps1 [-Names ,] (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" }