Skip to content

feat(windows): bundle full Git-for-Windows toolchain for the shell tool#1145

Draft
wpfleger96 wants to merge 3 commits into
mainfrom
duncan/windows-full-toolchain-bundle
Draft

feat(windows): bundle full Git-for-Windows toolchain for the shell tool#1145
wpfleger96 wants to merge 3 commits into
mainfrom
duncan/windows-full-toolchain-bundle

Conversation

@wpfleger96

@wpfleger96 wpfleger96 commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

The Windows bundle shipped a stripped MSYS2-bash-only tree — scripts/stage-windows-bash.sh dropped the mingw64/ subtree — so a bare host got bash + coreutils but no git, jq, or curl. The first Windows agent confirmed all three absent, which blocks the REPOS/ clone/commit/push workflow and any jq-piped CLI use. The nostr commit-identity plumbing (git-credential-nostr / git-sign-nostr / GIT_CONFIG_*) has always needed a git binary on PATH it never had on a bare box.

This keeps the single bash -c contract (no per-OS shell fork) and changes the bundle to a full real toolchain.

What changed

  • Stop dropping mingw64/ (scripts/stage-windows-bash.sh). The whole PortableGit tree is staged — git.exe plus curl and full sed/awk/grep/find live inside mingw64\bin. The tree is kept as the untouched closure git-for-windows ships; no hand-trimming (the same lazy-load hazard the script already documents for usr/ applies to mingw64/).
  • Vendor a pinned jq.exe (scripts/stage-windows-bash.sh). jq is not part of git-for-windows, so the standalone static jq.exe (1.8.1, a single binary with no DLL closure) is fetched into mingw64\bin alongside git/curl and verified against a pinned SHA-256 before it lands — a checksum mismatch fails the stage.
  • Flip the resolver entry to the launcher (crates/buzz-dev-mcp/src/shell.rs). BUNDLED_BASH_REL moves from git-bash\usr\bin\bash.exe to git-bash\bin\bash.exe. With mingw64/ present the tree matches a real Git-for-Windows install, so the launcher is the correct entry: it sets MSYSTEM=MINGW64 and prepends mingw64\bin to the in-shell PATH. That entry-point flip is the one change that makes git/jq/curl resolve inside the agent's shell — no Rust-side PATH injection needed. The bundled and installed-Git branches now share the same bin\bash.exe entry.
  • Version the staging marker to .stage-complete-v2 (scripts/stage-windows-bash.sh). An upgrade over the old mingw64-less layout would otherwise short-circuit the re-stage behind a stale .stage-complete and leave git silently absent. The integrity check asserts mingw64\bin\git.exe and mingw64\bin\jq.exe landed before the marker is written.
  • Extend the CI smoke-test (.github/workflows/ci.yml) to spawn the launcher under a deliberately bare PATH (stripped to the Windows system dir, stricter than a bare host) and assert git/jq/curl each resolve to a path anchored under the staged treecygpath -m translates the resolved tool back to its real Windows location and the check requires the $stage_dir prefix, not a bare mount shape. A git commit round-trips to prove git is functional.
  • Reconcile the lockstep comments in scripts/bundle-sidecars.sh and desktop/scripts/build-release-config.mjs.

Verification status

The CI smoke-test confirmed on the real Windows runner that the launcher prepends mingw64\bin to PATH under a non-login -c spawn and git resolves from the bundle. The CI job stages only empty sidecar placeholders, so it cannot exercise the end-to-end nostr-signed commit — that, plus confirming resolution on a real install with no host Git (the resolver prefers an installed Git, which would mask a broken bundle), is verified separately on a bare Windows host before this ships.

Language toolchains (Node / Python / Rust) stay host-assumed for v1; this bundles git, jq, and the Git-for-Windows shell tooling.

npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 and others added 3 commits June 19, 2026 13:14
The Windows bundle shipped a stripped MSYS2-bash-only tree (stage-windows-bash.sh
dropped mingw64/), so a bare host had bash + coreutils but no git/jq/curl — the
first Windows agent confirmed all three absent. Keep the whole PortableGit tree
instead and flip the resolver to the bin/bash.exe launcher, which sets MSYSTEM and
prepends mingw64/bin to the in-shell PATH; that single entry-point change makes
git/jq/curl resolve with no Rust-side PATH injection. Version the staging marker
(.stage-complete-v2) so an upgrade over the old mingw64-less layout re-stages
rather than short-circuiting behind a stale 'complete' marker, and assert git.exe
landed before writing it. Extend the CI smoke-test to spawn the launcher under a
bare PATH and prove git/jq/curl resolve from the bundle and git commits — the
launcher's non-login -c PATH behavior still needs a real bare-Windows host to
confirm end to end.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
The Windows smoke-test asserted resolved tools matched */git-bash/*, but under
the launcher's MSYS environment command -v reports POSIX mount paths
(/mingw64/bin/git, /usr/bin/jq) where /mingw64 and /usr are the staged tree's
own subdirs — so the check rejected a correctly-bundled git. The launcher flip
itself worked: CI proved git resolved to /mingw64/bin/git under a bare non-login
-c spawn, confirming the launcher prepends mingw64/bin to PATH as designed.
Accept the MSYS mounts (safe because PATH is stripped bare, so they can only be
the bundle) and reject host /c/... drive paths.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
…aged tree

Three changes from review of the full-toolchain bundle:

- jq is not shipped in PortableGit (verified at source against the 2.54.0 SFX:
  curl and cygpath present, jq absent), so vendor the pinned standalone jq.exe
  (1.8.1, SHA-256 verified) into mingw64/bin where it resolves alongside git/curl
  through the launcher. A checksum mismatch fails the stage.
- Anchor the CI git/jq/curl origin check to the actual staged tree: cygpath -m the
  resolved tool back to its real path and assert it sits under $stage_dir, instead
  of a bare /mingw64|/usr mount-shape match that any such-shaped path would satisfy.
- Note curl is the one tool with a System32 twin, and soften the bare-PATH comment
  to 'stricter than a bare host' since the test strips ambient PATH rather than
  mirroring it.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
@wpfleger96 wpfleger96 marked this pull request as draft June 19, 2026 18:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant