From cd8095c9a0bf92dd8bbf3ae8227e52ef659ace49 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Mon, 18 May 2026 17:31:29 +0200 Subject: [PATCH 1/6] feat(windows): scaffolding pass for Windows support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First-pass changes to let pkgm at least start on Windows so CI can surface real gaps instead of failing at "/usr/local doesn't exist": - standardPath(): add Windows case returning the baseline System32 / System32\Wbem dirs joined with `;`. Introduces PATH_SEP module constant used wherever we tokenise $PATH (a literal `:` split would shred `C:\` drive prefixes on Windows). - install_prefix(): on Windows, skip the /usr/local probe and return Path.home()/.local. System-wide installs under %ProgramFiles% need UAC modelling — out of scope here. - get_pkgx(): use PATH_SEP and look for `pkgx.exe` on Windows. - install() PATH-contains check: use PATH_SEP. - Stub writing: skip the Deno.chmod(0o755) on Windows (it throws). The stub content is still POSIX shell — proper `.cmd`/`.ps1` stub emission is a follow-up. - CI: add windows-latest to the `test` matrix with `strategy.fail-fast: false`. The existing `continue-on-error: true` keeps the matrix overall green; the Windows leg surfaces what's still broken so we can iterate. Open design questions deliberately left for the draft-PR description: - System-wide install prefix on Windows (%ProgramFiles%? user-only?) - Elevation model (UAC? refuse?) - Stub format (.cmd, .ps1, or compiled wrapper?) - libpkgx + pkgxdev/setup Windows-readiness verification Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/ci.yml | 6 ++++++ pkgm.ts | 38 ++++++++++++++++++++++++++++++++++---- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1bbb50b..cf6e338 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,10 +27,16 @@ jobs: test: continue-on-error: true strategy: + fail-fast: false matrix: os: - macos-latest - ubuntu-latest + # Windows: scaffolding pass — steps below rely on shebang + # interpretation and POSIX paths, so most will fail until + # pkgm grows native Windows install/stub support. See the + # draft PR description for the open design questions. + - windows-latest runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 diff --git a/pkgm.ts b/pkgm.ts index f3f08c3..749fd5b 100755 --- a/pkgm.ts +++ b/pkgm.ts @@ -13,7 +13,23 @@ import { ensureDir, existsSync, walk } from "jsr:@std/fs@^1"; import { parseArgs } from "jsr:@std/cli@^1"; const { hydrate } = plumbing; +// Path-separator: `;` on Windows, `:` on POSIX. Used everywhere we +// split or join $PATH, since C:\ on Windows would tokenise wrong with `:`. +const PATH_SEP = Deno.build.os == "windows" ? ";" : ":"; + function standardPath() { + if (Deno.build.os == "windows") { + // Windows: no /usr/local hierarchy and no homebrew. Return the + // baseline system dirs so subprocesses can still locate built-in + // commands (cmd, find, etc.) when we feed them an explicit PATH. + const systemRoot = Deno.env.get("SystemRoot") ?? "C:\\Windows"; + return [ + `${systemRoot}\\System32`, + systemRoot, + `${systemRoot}\\System32\\Wbem`, + ].join(PATH_SEP); + } + let path = "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"; // for pkgx installed via homebrew @@ -194,7 +210,12 @@ async function install(args: string[], basePath: string) { await Deno.remove(to_stub); //FIXME inefficient to symlink for no reason await Deno.writeTextFile(to_stub, sh.trim() + "\n"); - await Deno.chmod(to_stub, 0o755); + // Windows has no POSIX exec bit; Deno.chmod throws there. Stub + // content is still POSIX shell at this point — proper `.cmd`/`.ps1` + // stub emission is a separate TODO (see draft PR description). + if (Deno.build.os != "windows") { + await Deno.chmod(to_stub, 0o755); + } rv.push(to_stub); } @@ -204,7 +225,7 @@ async function install(args: string[], basePath: string) { if ( !Deno.env .get("PATH") - ?.split(":") + ?.split(PATH_SEP) ?.includes(new Path(basePath).join("bin").string) ) { console.error( @@ -518,8 +539,9 @@ function symlink_with_overwrite(src: string, dst: string) { } function get_pkgx() { - for (const path of Deno.env.get("PATH")!.split(":")) { - const pkgx = join(path, "pkgx"); + const exe = Deno.build.os == "windows" ? "pkgx.exe" : "pkgx"; + for (const path of Deno.env.get("PATH")!.split(PATH_SEP)) { + const pkgx = join(path, exe); if (existsSync(pkgx)) { const out = new Deno.Command(pkgx, { args: ["--version"] }).outputSync(); const stdout = new TextDecoder().decode(out.stdout); @@ -758,6 +780,14 @@ async function update() { } function install_prefix() { + // Windows has no /usr/local analogue; the per-user prefix is the + // only sensible default for now. System-wide installs on Windows + // (e.g. under %ProgramFiles%) require UAC elevation modelling and + // are out of scope for the initial port — see the draft PR + // description for the design questions. + if (Deno.build.os == "windows") { + return Path.home().join(".local"); + } // if /usr/local is writable, use that if (writable("/usr/local")) { return new Path("/usr/local"); From 5f5d7a0ecc2b8bf21017d1cde1fdd1a96de16a15 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Mon, 18 May 2026 17:45:40 +0200 Subject: [PATCH 2/6] feat(windows): iterate after surveying pkgx's Windows patterns Surveyed pkgxdev/pkgx + pkgxdev/setup for prior art and applied: - install_prefix() on Windows now resolves to %LOCALAPPDATA%\pkgm (was Path.home()/.local). Mirrors pkgxdev/setup/installer.ps1 which installs pkgx to $env:LOCALAPPDATA\pkgx, and matches libpkgx config.rs falling back to dirs_next::data_local_dir() on Windows. Keeps the per-user, no-UAC posture pkgx already adopts. - ls()/outdated() walk install_prefix().join("pkgs") on Windows instead of the hard-coded POSIX pair, so installed pkgs are actually found there. Co-Authored-By: Claude Opus 4.7 (1M context) --- pkgm.ts | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/pkgm.ts b/pkgm.ts index 749fd5b..7525166 100755 --- a/pkgm.ts +++ b/pkgm.ts @@ -556,12 +556,13 @@ function get_pkgx() { } async function* ls() { - for ( - const path of [ - new Path("/usr/local/pkgs"), - Path.home().join(".local/pkgs"), - ] - ) { + // On POSIX a host can have both a system-wide /usr/local/pkgs and + // a per-user ~/.local/pkgs install — we list both. Windows has only + // the per-user prefix from install_prefix() (no /usr/local concept). + const candidates = Deno.build.os == "windows" + ? [install_prefix().join("pkgs")] + : [new Path("/usr/local/pkgs"), Path.home().join(".local/pkgs")]; + for (const path of candidates) { if (!path.isDirectory()) continue; const dirs = [path]; let dir: Path | undefined; @@ -680,11 +681,14 @@ function writable(path: string) { async function outdated() { const pkgs: Installation[] = []; - for await (const pkg of walk_pkgs(new Path("/usr/local/pkgs"))) { - pkgs.push(pkg); - } - for await (const pkg of walk_pkgs(Path.home().join(".local/pkgs"))) { - pkgs.push(pkg); + // See ls(): POSIX scans both prefixes, Windows only the user one. + const candidates = Deno.build.os == "windows" + ? [install_prefix().join("pkgs")] + : [new Path("/usr/local/pkgs"), Path.home().join(".local/pkgs")]; + for (const candidate of candidates) { + for await (const pkg of walk_pkgs(candidate)) { + pkgs.push(pkg); + } } const { pkgs: raw_graph } = await hydrate( @@ -780,13 +784,17 @@ async function update() { } function install_prefix() { - // Windows has no /usr/local analogue; the per-user prefix is the - // only sensible default for now. System-wide installs on Windows - // (e.g. under %ProgramFiles%) require UAC elevation modelling and - // are out of scope for the initial port — see the draft PR - // description for the design questions. + // Windows: per-user only, under %LOCALAPPDATA%\pkgm. Mirrors pkgx's + // own pattern (installer.ps1 in pkgxdev/setup uses + // $env:LOCALAPPDATA\pkgx, and libpkgx's config.rs falls back to + // dirs_next::data_local_dir() which resolves to %LOCALAPPDATA% on + // Windows). pkgx itself doesn't model UAC elevation; we follow. + // Fallback path-join is a defensive equivalent for the rare runner + // missing the LOCALAPPDATA env var. if (Deno.build.os == "windows") { - return Path.home().join(".local"); + const localAppData = Deno.env.get("LOCALAPPDATA") ?? + join(Deno.env.get("USERPROFILE") ?? "", "AppData", "Local"); + return new Path(join(localAppData, "pkgm")); } // if /usr/local is writable, use that if (writable("/usr/local")) { From ce6da9b7dc875134300196a5e811a03840aefc38 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Mon, 18 May 2026 18:09:27 +0200 Subject: [PATCH 3/6] feat(windows): hardlink fallback for symlinks + .cmd wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three more pieces of the Windows port, all aligned with how pkgx itself handles the same primitives: - symlink_with_overwrite(): on Windows, files fall back to Deno.linkSync (hardlinks need no elevation as long as src/dst live on the same volume — true with the new install_prefix). Plain copy is the last resort for cross-volume. Directories still go through Deno.symlinkSync({ type: "dir" }), which uses developer-mode-style dir symlinks (enabled on GHA Windows runners; non-elevated machines without dev-mode skip create_v_symlinks anyway, below). - create_v_symlinks(): early-return on Windows. The v1/v2/... major-version aliases are a navigation convenience — installed pkgs are still accessible via the canonical v path, which is what mirror_directory + the stub wrappers actually reference. Adding junctions (mklink /J via subprocess) is a follow-up if someone needs them. - install() stub loop: when runtime_env is set on Windows, emit a .cmd wrapper at .cmd that `set`s the env vars then execs the real binary from the pkg cache. We delete the original .exe hardlink first so PATHEXT doesn't shadow the .cmd. `%` is the only in-quotes special char inside `set "K=V"`, escaped as `%%` (batch- file convention). Matches pkgx's find_program() looking up .exe → .bat → .cmd. POSIX legs verified locally: deno fmt/lint/check clean, `./pkgm.ts i hyperfine` + `./pkgm.ts ls` still produce the expected output. Co-Authored-By: Claude Opus 4.7 (1M context) --- pkgm.ts | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/pkgm.ts b/pkgm.ts index 7525166..a894185 100755 --- a/pkgm.ts +++ b/pkgm.ts @@ -199,6 +199,29 @@ async function install(args: string[], basePath: string) { const to_stub = join(dst, bin, entry.name); + if (Deno.build.os == "windows") { + // Emit a .cmd wrapper next to (and replacing) the hardlinked + // binary. PATHEXT lookup picks `.cmd` only if there's no + // `.exe` at the same stem, so we must remove the hardlink + // first or it would shadow the wrapper. + const stem = entry.name.replace(/\.(exe|bat|cmd)$/i, ""); + const cmd_path = join(dst, bin, stem + ".cmd"); + const target = join(bin_prefix, entry.name); + let cmd = "@echo off\r\n"; + for (const [key, value] of Object.entries(env)) { + // Inside `set "K=V"` quotes the value is literal except for + // `%`, which cmd's parser still treats as variable-expand + // even when quoted. Escape as `%%` (batch-file convention). + const escaped = value.replace(/%/g, "%%"); + cmd += `set "${key}=${escaped}"\r\n`; + } + cmd += `"${target}" %*\r\n`; + await Deno.remove(to_stub); + await Deno.writeTextFile(cmd_path, cmd); + rv.push(cmd_path); + continue; + } + let sh = `#!/bin/sh\n`; for (const [key, value] of Object.entries(env)) { sh += `export ${key}="${value}"\n`; @@ -210,12 +233,7 @@ async function install(args: string[], basePath: string) { await Deno.remove(to_stub); //FIXME inefficient to symlink for no reason await Deno.writeTextFile(to_stub, sh.trim() + "\n"); - // Windows has no POSIX exec bit; Deno.chmod throws there. Stub - // content is still POSIX shell at this point — proper `.cmd`/`.ps1` - // stub emission is a separate TODO (see draft PR description). - if (Deno.build.os != "windows") { - await Deno.chmod(to_stub, 0o755); - } + await Deno.chmod(to_stub, 0o755); rv.push(to_stub); } @@ -459,6 +477,15 @@ async function symlink(src: string, dst: string) { //FIXME we only do major as that's typically all pkgs need, but like we should do better async function create_v_symlinks(prefix: string) { + if (Deno.build.os == "windows") { + // Skipped on Windows for v1: directory aliases would need either a + // junction (mklink /J via subprocess — Deno has no native API) or a + // dir symlink (admin/dev-mode). Installed pkgs are still accessible + // via their canonical v path, which is what the stubs and + // mirror_directory steps reference anyway. v1/v2/... aliases are a + // user-navigation convenience, not a runtime requirement. + return; + } const shelf = dirname(prefix); const versions = []; @@ -535,6 +562,26 @@ function symlink_with_overwrite(src: string, dst: string) { if (existsSync(dst) && Deno.lstatSync(dst).isSymlink) { Deno.removeSync(dst); } + if (Deno.build.os == "windows") { + // Windows: file symlinks need admin or developer mode. Hardlinks + // work without elevation as long as src and dst are on the same + // volume — true for our install (everything under + // %LOCALAPPDATA%\pkgm) once the pkg cache itself lives there. Fall + // back to a plain copy if even hardlink fails (cross-volume etc). + // Directory symlinks are handled by the caller skipping + // create_v_symlinks() on Windows. + const isDir = existsSync(src) && Deno.statSync(src).isDirectory; + if (isDir) { + Deno.symlinkSync(src, dst, { type: "dir" }); + } else { + try { + Deno.linkSync(src, dst); + } catch { + Deno.copyFileSync(src, dst); + } + } + return; + } Deno.symlinkSync(src, dst); } From fcbba47c1804f1810c562c93728ea6cf5c2dad7e Mon Sep 17 00:00:00 2001 From: tannevaled Date: Mon, 18 May 2026 18:13:10 +0200 Subject: [PATCH 4/6] ci(windows): split into dedicated test-windows job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous "windows-latest in test matrix" approach fails at step 1 (\`./pkgm.ts i git\`) because Windows doesn't interpret shebangs. Guarding ~25 POSIX-style steps with \`if: runner.os != 'Windows'\` would be noise; the existing job stays POSIX-only. Add a focused \`test-windows\` job that invokes pkgm via the explicit form a user without the (not-yet-existing) \`pkgm.cmd\` wrapper would use: pkgx deno^2.1 run --ext=ts --allow-... ./pkgm.ts Two smoke steps: 1. \`pkgm --version\` — floor test that pkgx is on PATH, deno can run the script, libpkgx imports resolve on Windows, parseArgs reaches the version arm. 2. \`pkgm i hyperfine\` — exercises the install end-to-end. Expected to surface either pantry-resolution / hardlink-fallback / .cmd- emission gaps. continue-on-error: true while iterating. Verifies the expected cache landing site is %LOCALAPPDATA%\pkgm\pkgs. --- .github/workflows/ci.yml | 58 +++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cf6e338..a895aea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,16 +27,10 @@ jobs: test: continue-on-error: true strategy: - fail-fast: false matrix: os: - macos-latest - ubuntu-latest - # Windows: scaffolding pass — steps below rely on shebang - # interpretation and POSIX paths, so most will fail until - # pkgm grows native Windows install/stub support. See the - # draft PR description for the open design questions. - - windows-latest runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -115,6 +109,58 @@ jobs: ./pkgm.ts i spotify_player spotify_player --version + # Scaffolding-pass smoke test for the Windows port. Uses an explicit + # `pkgx deno^2.1 run` invocation because the kernel doesn't interpret + # `#!/usr/bin/env -S pkgx …` shebangs on Windows; a `pkgm.cmd` wrapper + # that papers over this belongs in pkgxdev/setup's installer.ps1, not + # here. continue-on-error: true while the port is in progress. + test-windows: + continue-on-error: true + runs-on: windows-latest + defaults: + run: + shell: pwsh + steps: + - uses: actions/checkout@v4 + - uses: pkgxdev/setup@v4 + + - name: smoke - pkgm --version + # Verifies the absolute floor: pkgx is on PATH, deno can run + # the script, libpkgx imports resolve on Windows, parseArgs + + # the `version` arm exit 0. No filesystem touching yet. + run: | + $denoArgs = @( + 'deno^2.1', 'run', '--ext=ts', + '--allow-sys=uid', '--allow-run', '--allow-env', + '--allow-read', '--allow-write', '--allow-ffi', + '--allow-net=dist.pkgx.dev', + './pkgm.ts', '--version' + ) + pkgx @denoArgs + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + + - name: smoke - install hyperfine + # Exercises the install path end-to-end on Windows. Expected to + # fail at one of: pantry resolution (if no Windows build), the + # hardlink-fallback path in symlink_with_overwrite, or the .cmd + # emission step. Failure mode is the discovery signal for the + # next iteration. + run: | + $denoArgs = @( + 'deno^2.1', 'run', '--ext=ts', + '--allow-sys=uid', '--allow-run', '--allow-env', + '--allow-read', '--allow-write', '--allow-ffi', + '--allow-net=dist.pkgx.dev', + './pkgm.ts', 'i', 'hyperfine' + ) + pkgx @denoArgs + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + $expected = Join-Path $env:LOCALAPPDATA "pkgm\pkgs\crates.io\hyperfine" + if (!(Test-Path $expected)) { + Write-Error "expected hyperfine cache at $expected" + exit 1 + } + # Validates `sudo pkgm install` behaviour fixed in 2b33f20: # - privilege drop so pkgx cache stays owned by $SUDO_USER, not root # - HOME override so the cache lands under the invoking user's tree From ba62fe2d678760e52cb2d790fc67b3d81d980b12 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Mon, 18 May 2026 18:19:47 +0200 Subject: [PATCH 5/6] =?UTF-8?q?ci(windows):=20swap=20install=20smoke=20for?= =?UTF-8?q?=20ls=20smoke=20=E2=80=94=20dist=20gap=20upstream?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "install hyperfine" smoke step on \`test-windows\` failed with \`Error: CmdNotFound("hyperfine")\`. Investigation: hyperfine has no Windows build in \`dist.pkgx.dev\`. Exhaustive probe of all 842 top- level prefixes in the bucket found zero packages with a \`windows/\` subdir — pkgx-on-Windows can pull \`pkgx.exe\` itself but no other package. \`pkgm install\` on Windows is blocked on upstream shipping Windows artifacts, independent of pkgm's port. Drop the install step (it can't pass), keep the \`--version\` floor, and add a \`pkgm ls\` smoke that exercises install_prefix() (now %LOCALAPPDATA%\pkgm) and the new Windows candidate-paths branch in ls() without depending on a real install. Job no longer needs \`continue-on-error: true\` — both remaining steps are deterministically achievable on Windows today. --- .github/workflows/ci.yml | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a895aea..7047271 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -109,13 +109,18 @@ jobs: ./pkgm.ts i spotify_player spotify_player --version - # Scaffolding-pass smoke test for the Windows port. Uses an explicit + # Scaffolding-pass smoke for the Windows port. Uses an explicit # `pkgx deno^2.1 run` invocation because the kernel doesn't interpret # `#!/usr/bin/env -S pkgx …` shebangs on Windows; a `pkgm.cmd` wrapper # that papers over this belongs in pkgxdev/setup's installer.ps1, not - # here. continue-on-error: true while the port is in progress. + # here. + # + # End-to-end install can't be exercised yet: a probe of all 842 + # top-level prefixes in dist.pkgx.dev (the bucket pkgx pulls from) + # finds zero packages with a `windows/` subdir. pkgm install is + # blocked on upstream shipping Windows artifacts; we test what we + # can — that pkgm runs at all on Windows. test-windows: - continue-on-error: true runs-on: windows-latest defaults: run: @@ -125,9 +130,9 @@ jobs: - uses: pkgxdev/setup@v4 - name: smoke - pkgm --version - # Verifies the absolute floor: pkgx is on PATH, deno can run - # the script, libpkgx imports resolve on Windows, parseArgs + - # the `version` arm exit 0. No filesystem touching yet. + # Verifies the floor: pkgx.exe is on PATH, deno can run the + # script, libpkgx imports resolve on Windows, parseArgs + the + # version arm exit 0. No filesystem touching yet. run: | $denoArgs = @( 'deno^2.1', 'run', '--ext=ts', @@ -139,27 +144,22 @@ jobs: pkgx @denoArgs if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - - name: smoke - install hyperfine - # Exercises the install path end-to-end on Windows. Expected to - # fail at one of: pantry resolution (if no Windows build), the - # hardlink-fallback path in symlink_with_overwrite, or the .cmd - # emission step. Failure mode is the discovery signal for the - # next iteration. + - name: smoke - pkgm ls on a fresh runner + # Exercises install_prefix() (now %LOCALAPPDATA%\pkgm on + # Windows) and the ls() candidate-paths branch. Fresh runner + # → no installed pkgs → empty output, exit 0. Catches regressions + # in the path-resolution layer without depending on + # dist.pkgx.dev having Windows builds. run: | $denoArgs = @( 'deno^2.1', 'run', '--ext=ts', '--allow-sys=uid', '--allow-run', '--allow-env', '--allow-read', '--allow-write', '--allow-ffi', '--allow-net=dist.pkgx.dev', - './pkgm.ts', 'i', 'hyperfine' + './pkgm.ts', 'ls' ) pkgx @denoArgs if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - $expected = Join-Path $env:LOCALAPPDATA "pkgm\pkgs\crates.io\hyperfine" - if (!(Test-Path $expected)) { - Write-Error "expected hyperfine cache at $expected" - exit 1 - } # Validates `sudo pkgm install` behaviour fixed in 2b33f20: # - privilege drop so pkgx cache stays owned by $SUDO_USER, not root From 9d8616b1dc68ac5a5249ca7c21118df951b64228 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Mon, 18 May 2026 19:14:02 +0200 Subject: [PATCH 6/6] ci(windows): correct comment block re: dist Windows state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous comment claimed "a probe of all 842 top-level prefixes in dist.pkgx.dev finds zero packages with a windows/ subdir". That probe was on the v1 root layout and missed the v2/ hierarchy, where 15 toolchain-layer packages do have Windows builds today (bun, cmake, curl, deno, git, go, libarchive, nasm, ninja, openssl, perl, python, rust, sqlite, zlib). jhheider clarified on pkgxdev/pkgx#607 that the manifest pipeline producing those was rolled back about a year ago, so no new Windows builds are shipping — but it's not a "zero artifacts" situation, and the path forward is reviving the build pipeline rather than starting from scratch. No functional change; only the explanatory comment is updated. --- .github/workflows/ci.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7047271..506882f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -115,11 +115,15 @@ jobs: # that papers over this belongs in pkgxdev/setup's installer.ps1, not # here. # - # End-to-end install can't be exercised yet: a probe of all 842 - # top-level prefixes in dist.pkgx.dev (the bucket pkgx pulls from) - # finds zero packages with a `windows/` subdir. pkgm install is - # blocked on upstream shipping Windows artifacts; we test what we - # can — that pkgm runs at all on Windows. + # End-to-end install can't be exercised yet: the v2 dist layout + # (`v2//windows/x86-64/`) has 15 toolchain-layer packages built + # for Windows (bun, cmake, curl, deno, git, go, libarchive, nasm, + # ninja, openssl, perl, python, rust, sqlite, zlib) — no application + # packages. Per pkgxdev/pkgx#607 the manifest pipeline that + # produced them was rolled back about a year ago, so no new Windows + # builds are being shipped. We test what we can — that pkgm runs at + # all on Windows — and the install path will start passing once the + # upstream build pipeline comes back online. test-windows: runs-on: windows-latest defaults: