Browse Source

punk-getzig: spaced-path + Windows PowerShell 5 fixes (launcher and payload); punkshell 0.30.5

User-reported: './punk-getzig.cmd' from a spaced checkout failed with
'C:\repo\jn\program: The term ... is not recognized' while punk-runtime
worked. Root cause: punk-getzig_wrap.toml still used the pwsh '-c'
command-string launcher, which tokenizes a spaced script path - punk-runtime
received the 'cmd.exe /c powershell ... -File' fix during G-119 (its wrap
toml carries the comment) and punk-getzig never did. Adopting the same
launcher surfaced three latent payload issues, all fixed in
src/scriptapps/bin/punk-getzig.ps1:
- Resolve-Path -RelativeBasePath is pwsh 7.4+ - replaced with the
  Push-Location + -Relative spelling (PS5-compatible)
- Invoke-WebRequest without -UseBasicParsing NullReferences on PS5 (IE
  parsing engine); all three call sites fixed, with progress suppressed
  around the large distribution download (PS5 -OutFile slowdown)
- Invoke-Expression "$zigexe version" splits spaced paths under ANY
  powershell (latent even on pwsh) - both sites now use the call operator
Payload growth pushed :exit_multishell across a 512-byte boundary; the
punk-runtime-style '(512B spacer)' comment added to punk-getzig.bash and the
polyglot regenerated (checkfile ERROR-free). Verified in the
'C:/repo/jn/program files/punkshell' checkout: full fetch (community-mirror
latency ordering, local punkbin mirror, minisign verify, extract, ZIG
VERSION: 0.16.0) and the already-installed branch; main-repo argless run
clean. Sources and regenerated bin/punk-getzig.cmd committed together per
the wrap workflow (no roundtrip pin exists for punk-getzig - candidate noted
in the completion report).

Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 2 days ago
parent
commit
c0263ff934
  1. 15
      CHANGELOG.md
  2. 36
      bin/punk-getzig.cmd
  3. 2
      punkproject.toml
  4. 4
      src/scriptapps/bin/punk-getzig.bash
  5. 28
      src/scriptapps/bin/punk-getzig.ps1
  6. 10
      src/scriptapps/bin/punk-getzig_wrap.toml

15
CHANGELOG.md

@ -5,6 +5,21 @@ The latest `## [X.Y.Z]` header must match the `version` field in `punkproject.to
Entries are newest-first; one bullet per notable change. See the root `AGENTS.md` Entries are newest-first; one bullet per notable change. See the root `AGENTS.md`
"Project Versioning" section for the bump policy. "Project Versioning" section for the bump policy.
## [0.30.5] - 2026-07-29
- `punk-getzig.cmd` fixed for spaced checkout paths and Windows PowerShell 5:
the launcher moves off the `pwsh -c` form (which tokenized a spaced script
path - same `cmd.exe /c powershell ... -File` fix punk-runtime received in
G-119) and the payload drops its pwsh-isms: `Resolve-Path
-RelativeBasePath` (7.4+) becomes the Push-Location `-Relative` form,
`Invoke-WebRequest` gains `-UseBasicParsing` (PS5 IE-engine
NullReferenceException) with progress suppressed for the large download,
and two `Invoke-Expression "$zigexe version"` sites (which split spaced
paths under ANY powershell) become call-operator invocations. Verified end
to end from a "program files" checkout: mirror-latency selection, fetch
from the local punkbin mirror, minisign verification, extraction and both
the fresh-install and already-installed branches.
## [0.30.4] - 2026-07-29 ## [0.30.4] - 2026-07-29
- `punk-runtime fetch` now prints a one-line materialization hint when the - `punk-runtime fetch` now prints a one-line materialization hint when the

36
bin/punk-getzig.cmd

@ -95,8 +95,8 @@ set ^"endlocal=for %%# in (1 2) do if %%#==2 (%\n%
@REM If more than 64 chars needed for a target, it can still be done but overall script padding may need checking/adjusting @REM If more than 64 chars needed for a target, it can still be done but overall script padding may need checking/adjusting
@REM Supporting more explicit oses than those listed may also require script padding adjustment @REM Supporting more explicit oses than those listed may also require script padding adjustment
: <<nextshell_start>> : <<nextshell_start>>
@SET "nextshellpath[win32___________]=pwsh -nop -nol -ExecutionPolicy bypass -c_______________________________________________________________________________________" @SET "nextshellpath[win32___________]=cmd.exe /c powershell -nop -nol -ExecutionPolicy bypass -File___________________________________________________________________"
@SET "nextshelltype[win32___________]=pwsh____________" @SET "nextshelltype[win32___________]=powershell______"
@SET "nextshellpath[dragonflybsd____]=/usr/bin/env bash_______________________________________________________________________________________________________________" @SET "nextshellpath[dragonflybsd____]=/usr/bin/env bash_______________________________________________________________________________________________________________"
@SET "nextshelltype[dragonflybsd____]=bash____________" @SET "nextshelltype[dragonflybsd____]=bash____________"
@SET "nextshellpath[freebsd_________]=/usr/bin/env bash_______________________________________________________________________________________________________________" @SET "nextshellpath[freebsd_________]=/usr/bin/env bash_______________________________________________________________________________________________________________"
@ -1301,6 +1301,10 @@ echo " and extract to ${targetdir} (the tarball's own root folder name) manuall
#tar -xf "./tools/${tarball}" -C ./tools #tar -xf "./tools/${tarball}" -C ./tools
#"${targetdir}/zig" version #"${targetdir}/zig" version
#(512B spacer) byte-alignment padding so template labels beyond the payloads clear cmd's
#512-byte label-scan boundaries - resize this comment if scriptwrap checkfile reports a
#boundary-spanning label after a payload edit (see bin/AGENTS.md polyglot workflow)
#</shell-payload> #</shell-payload>
@ -1634,7 +1638,12 @@ Write-Host "requested zig version: $releaseversion -> $zigfolder"
Write-Output "powershell version: $($PSVersionTable.PSVersion)" Write-Output "powershell version: $($PSVersionTable.PSVersion)"
if (Get-Command $zigexe -ErrorAction SilentlyContinue) { if (Get-Command $zigexe -ErrorAction SilentlyContinue) {
$relative_zigfolder = Resolve-Path -Path $zigfolder -RelativeBasePath $outbase -Relative #-RelativeBasePath is pwsh 7.4+; Push-Location + -Relative is the
#PS-5.1-compatible spelling of the same computation (the launcher runs
#Windows PowerShell - see punk-getzig_wrap.toml)
Push-Location $outbase
$relative_zigfolder = Resolve-Path -Path $zigfolder -Relative
Pop-Location
Write-Host "zig.exe is installed in $relative_zigfolder" Write-Host "zig.exe is installed in $relative_zigfolder"
$zigv = & $zigexe version 2>&1 $zigv = & $zigexe version 2>&1
$stdout = $zigv | Where-Object {$_ -is [string]} $stdout = $zigv | Where-Object {$_ -is [string]}
@ -1790,7 +1799,7 @@ if (-not $download_required) {
$null = extractZip $releasearchive $toolsfolder $null = extractZip $releasearchive $toolsfolder
$zigexe = Join-Path $zigfolder -ChildPath "zig.exe" $zigexe = Join-Path $zigfolder -ChildPath "zig.exe"
$v = Invoke-Expression "$zigexe version" $v = & $zigexe version
Write-Host "ZIG VERSION: ${v}" Write-Host "ZIG VERSION: ${v}"
exit 0 exit 0
} }
@ -1799,7 +1808,10 @@ if (-not $download_required) {
$mirrors_url = "https://ziglang.org/download/community-mirrors.txt" $mirrors_url = "https://ziglang.org/download/community-mirrors.txt"
#some mirrors have no index and the base url will produce a 404, some have an html index, some have a modified copy of the ziglang.org/download/index.json #some mirrors have no index and the base url will produce a 404, some have an html index, some have a modified copy of the ziglang.org/download/index.json
$mirrors_response = $(Invoke-WebRequest -Uri $mirrors_url) #-UseBasicParsing: required for reliability on powershell 5 (without it PS5's
#Invoke-WebRequest uses the IE parsing engine - NullReferenceException on
#machines without it); harmless no-op on pwsh. Same convention as punk-runtime.
$mirrors_response = $(Invoke-WebRequest -UseBasicParsing -Uri $mirrors_url)
if ($mirrors_response.StatusCode -eq 200) { if ($mirrors_response.StatusCode -eq 200) {
#https://www.gitea1.intx.com.au/jn/punkbin/raw/branch/master/win32-x86_64/tools/zig-x86_64-windows-0.15.1.zip #https://www.gitea1.intx.com.au/jn/punkbin/raw/branch/master/win32-x86_64/tools/zig-x86_64-windows-0.15.1.zip
$mirror_array = @("https://gitea1.intx.com.au/jn/punkbin/raw/branch/master/win32-x86_64/tools") $mirror_array = @("https://gitea1.intx.com.au/jn/punkbin/raw/branch/master/win32-x86_64/tools")
@ -1907,7 +1919,7 @@ if ($mirrors_response.StatusCode -eq 200) {
} }
#download the minisig first - because if that fails, we should move on without trying the larger download #download the minisig first - because if that fails, we should move on without trying the larger download
Write-Host "Downloading minisig signature from $sig_uristring" Write-Host "Downloading minisig signature from $sig_uristring"
Invoke-WebRequest -Uri $sig_uristring -Outfile "${outfile}.minisig" Invoke-WebRequest -UseBasicParsing -Uri $sig_uristring -Outfile "${outfile}.minisig"
if (-not(Test-Path -Path "${outfile}.minisig" -PathType Leaf)) { if (-not(Test-Path -Path "${outfile}.minisig" -PathType Leaf)) {
write-Host "Failed to download minisig signature from $sig_uristring to ${outfile}.minisig .. aborting download from $uristring" write-Host "Failed to download minisig signature from $sig_uristring to ${outfile}.minisig .. aborting download from $uristring"
continue continue
@ -1915,7 +1927,15 @@ if ($mirrors_response.StatusCode -eq 200) {
Write-Host "Downloading zig distribution from $full_uristring" Write-Host "Downloading zig distribution from $full_uristring"
Write-Host "Download to: $outfile" Write-Host "Download to: $outfile"
Invoke-WebRequest -Uri $full_uristring -OutFile $outfile #progress rendering makes PS5's Invoke-WebRequest -OutFile drastically
#slow on large files - suppress for the transfer, restore after
$OriginalProgressPreference = $Global:ProgressPreference
$Global:ProgressPreference = 'SilentlyContinue'
try {
Invoke-WebRequest -UseBasicParsing -Uri $full_uristring -OutFile $outfile
} finally {
$Global:ProgressPreference = $OriginalProgressPreference
}
if (-not(Test-Path -Path $outfile -PathType Leaf)) { if (-not(Test-Path -Path $outfile -PathType Leaf)) {
write-Host "Failed to download zig package from $full_uristring to ${outfile} .. aborting download from $uristring" write-Host "Failed to download zig package from $full_uristring to ${outfile} .. aborting download from $uristring"
@ -1953,7 +1973,7 @@ if ($mirrors_response.StatusCode -eq 200) {
$null = extractZip $releasearchive $toolsfolder $null = extractZip $releasearchive $toolsfolder
$zigexe = Join-Path $zigfolder -ChildPath "zig.exe" $zigexe = Join-Path $zigfolder -ChildPath "zig.exe"
$v = Invoke-Expression "$zigexe version" $v = & $zigexe version
Write-Host "ZIG VERSION: ${v}" Write-Host "ZIG VERSION: ${v}"
$test_ok = 1 ;#todo $test_ok = 1 ;#todo

2
punkproject.toml

@ -1,4 +1,4 @@
[project] [project]
name = "punkshell" name = "punkshell"
version = "0.30.4" version = "0.30.5"
license = "BSD-2-Clause" license = "BSD-2-Clause"

4
src/scriptapps/bin/punk-getzig.bash

@ -20,3 +20,7 @@ echo " and extract to ${targetdir} (the tarball's own root folder name) manuall
#minisign verification as per the powershell side (zig minisign pubkey), then: #minisign verification as per the powershell side (zig minisign pubkey), then:
#tar -xf "./tools/${tarball}" -C ./tools #tar -xf "./tools/${tarball}" -C ./tools
#"${targetdir}/zig" version #"${targetdir}/zig" version
#(512B spacer) byte-alignment padding so template labels beyond the payloads clear cmd's
#512-byte label-scan boundaries - resize this comment if scriptwrap checkfile reports a
#boundary-spanning label after a payload edit (see bin/AGENTS.md polyglot workflow)

28
src/scriptapps/bin/punk-getzig.ps1

@ -38,7 +38,12 @@ Write-Host "requested zig version: $releaseversion -> $zigfolder"
Write-Output "powershell version: $($PSVersionTable.PSVersion)" Write-Output "powershell version: $($PSVersionTable.PSVersion)"
if (Get-Command $zigexe -ErrorAction SilentlyContinue) { if (Get-Command $zigexe -ErrorAction SilentlyContinue) {
$relative_zigfolder = Resolve-Path -Path $zigfolder -RelativeBasePath $outbase -Relative #-RelativeBasePath is pwsh 7.4+; Push-Location + -Relative is the
#PS-5.1-compatible spelling of the same computation (the launcher runs
#Windows PowerShell - see punk-getzig_wrap.toml)
Push-Location $outbase
$relative_zigfolder = Resolve-Path -Path $zigfolder -Relative
Pop-Location
Write-Host "zig.exe is installed in $relative_zigfolder" Write-Host "zig.exe is installed in $relative_zigfolder"
$zigv = & $zigexe version 2>&1 $zigv = & $zigexe version 2>&1
$stdout = $zigv | Where-Object {$_ -is [string]} $stdout = $zigv | Where-Object {$_ -is [string]}
@ -194,7 +199,7 @@ if (-not $download_required) {
$null = extractZip $releasearchive $toolsfolder $null = extractZip $releasearchive $toolsfolder
$zigexe = Join-Path $zigfolder -ChildPath "zig.exe" $zigexe = Join-Path $zigfolder -ChildPath "zig.exe"
$v = Invoke-Expression "$zigexe version" $v = & $zigexe version
Write-Host "ZIG VERSION: ${v}" Write-Host "ZIG VERSION: ${v}"
exit 0 exit 0
} }
@ -203,7 +208,10 @@ if (-not $download_required) {
$mirrors_url = "https://ziglang.org/download/community-mirrors.txt" $mirrors_url = "https://ziglang.org/download/community-mirrors.txt"
#some mirrors have no index and the base url will produce a 404, some have an html index, some have a modified copy of the ziglang.org/download/index.json #some mirrors have no index and the base url will produce a 404, some have an html index, some have a modified copy of the ziglang.org/download/index.json
$mirrors_response = $(Invoke-WebRequest -Uri $mirrors_url) #-UseBasicParsing: required for reliability on powershell 5 (without it PS5's
#Invoke-WebRequest uses the IE parsing engine - NullReferenceException on
#machines without it); harmless no-op on pwsh. Same convention as punk-runtime.
$mirrors_response = $(Invoke-WebRequest -UseBasicParsing -Uri $mirrors_url)
if ($mirrors_response.StatusCode -eq 200) { if ($mirrors_response.StatusCode -eq 200) {
#https://www.gitea1.intx.com.au/jn/punkbin/raw/branch/master/win32-x86_64/tools/zig-x86_64-windows-0.15.1.zip #https://www.gitea1.intx.com.au/jn/punkbin/raw/branch/master/win32-x86_64/tools/zig-x86_64-windows-0.15.1.zip
$mirror_array = @("https://gitea1.intx.com.au/jn/punkbin/raw/branch/master/win32-x86_64/tools") $mirror_array = @("https://gitea1.intx.com.au/jn/punkbin/raw/branch/master/win32-x86_64/tools")
@ -311,7 +319,7 @@ if ($mirrors_response.StatusCode -eq 200) {
} }
#download the minisig first - because if that fails, we should move on without trying the larger download #download the minisig first - because if that fails, we should move on without trying the larger download
Write-Host "Downloading minisig signature from $sig_uristring" Write-Host "Downloading minisig signature from $sig_uristring"
Invoke-WebRequest -Uri $sig_uristring -Outfile "${outfile}.minisig" Invoke-WebRequest -UseBasicParsing -Uri $sig_uristring -Outfile "${outfile}.minisig"
if (-not(Test-Path -Path "${outfile}.minisig" -PathType Leaf)) { if (-not(Test-Path -Path "${outfile}.minisig" -PathType Leaf)) {
write-Host "Failed to download minisig signature from $sig_uristring to ${outfile}.minisig .. aborting download from $uristring" write-Host "Failed to download minisig signature from $sig_uristring to ${outfile}.minisig .. aborting download from $uristring"
continue continue
@ -319,7 +327,15 @@ if ($mirrors_response.StatusCode -eq 200) {
Write-Host "Downloading zig distribution from $full_uristring" Write-Host "Downloading zig distribution from $full_uristring"
Write-Host "Download to: $outfile" Write-Host "Download to: $outfile"
Invoke-WebRequest -Uri $full_uristring -OutFile $outfile #progress rendering makes PS5's Invoke-WebRequest -OutFile drastically
#slow on large files - suppress for the transfer, restore after
$OriginalProgressPreference = $Global:ProgressPreference
$Global:ProgressPreference = 'SilentlyContinue'
try {
Invoke-WebRequest -UseBasicParsing -Uri $full_uristring -OutFile $outfile
} finally {
$Global:ProgressPreference = $OriginalProgressPreference
}
if (-not(Test-Path -Path $outfile -PathType Leaf)) { if (-not(Test-Path -Path $outfile -PathType Leaf)) {
write-Host "Failed to download zig package from $full_uristring to ${outfile} .. aborting download from $uristring" write-Host "Failed to download zig package from $full_uristring to ${outfile} .. aborting download from $uristring"
@ -357,7 +373,7 @@ if ($mirrors_response.StatusCode -eq 200) {
$null = extractZip $releasearchive $toolsfolder $null = extractZip $releasearchive $toolsfolder
$zigexe = Join-Path $zigfolder -ChildPath "zig.exe" $zigexe = Join-Path $zigfolder -ChildPath "zig.exe"
$v = Invoke-Expression "$zigexe version" $v = & $zigexe version
Write-Host "ZIG VERSION: ${v}" Write-Host "ZIG VERSION: ${v}"
$test_ok = 1 ;#todo $test_ok = 1 ;#todo

10
src/scriptapps/bin/punk-getzig_wrap.toml

@ -16,6 +16,12 @@
#valid nextshelltype entries are: tcl perl pwsh powershell bash. #valid nextshelltype entries are: tcl perl pwsh powershell bash.
#nextshellpath entries must be 64 characters or less. #nextshellpath entries must be 64 characters or less.
win32.nextshellpath="pwsh -nop -nol -ExecutionPolicy bypass -c" #win32.nextshellpath="pwsh -nop -nol -ExecutionPolicy bypass -c"
win32.nextshelltype="pwsh" #win32.nextshelltype="pwsh"
#powershell needs cmd.exe to preserve spaced args - and the -c (command
#string) form breaks on a spaced script path outright (tokenizes at the
#space). Same fix as punk-runtime_wrap.toml, found there during G-119.
win32.nextshellpath="cmd.exe /c powershell -nop -nol -ExecutionPolicy bypass -File"
win32.nextshelltype="powershell"
win32.outputfile="punk-getzig.cmd" win32.outputfile="punk-getzig.cmd"

Loading…
Cancel
Save