Skip to content

fix(sync): run gstack-brain-sync through bash, not cmd.exe, on Windows - #2510

Open
ShahriarLak wants to merge 1 commit into
garrytan:mainfrom
ShahriarLak:fix/windows-brain-sync-bash-interpreter
Open

fix(sync): run gstack-brain-sync through bash, not cmd.exe, on Windows#2510
ShahriarLak wants to merge 1 commit into
garrytan:mainfrom
ShahriarLak:fix/windows-brain-sync-bash-interpreter

Conversation

@ShahriarLak

Copy link
Copy Markdown

The bug

On Windows the brain-sync stage of /sync-gbrain fails on every run:

'C:\Users\...\.claude\skills\gstack\bin\gstack-brain-sync' is not recognized as an internal or external command,
operable program or batch file.

  ERR   brain-sync   gstack-brain-sync exited 1 (0.0s)

Why the #1731 fix didn't cover it

#1731 added shell: NEEDS_SHELL_ON_WINDOWS to these spawns. That is correct for the gbrain.cmd shim and does nothing here: shell: true routes through cmd.exe, which resolves .cmd/.bat via PATHEXT but has no concept of a shebang, so an extension-less bash script is rejected outright.

A .cmd shim needs a shell. A shebang script needs an interpreter. The two cases look identical and are not, which is why one fix appeared to cover both.

Why it matters more than one red line

artifacts_sync_mode defaults to pushing curated artifacts to git. With this stage dead, a Windows user's learnings accumulate in ~/.gstack and are never committed, while the sync report shows one red line among otherwise green stages. It reads as a minor stage failure and is actually silent data stagnation.

The change

New bashScriptInvocation() in lib/gbrain-exec.ts:

  • Resolves Git for Windows' bash.exe and passes the script as argv[0].
  • Prefers Git bash over a bare bash on PATH: WindowsApps ships a bash.exe that is the WSL launcher, and if it wins PATH order it reads C:\... as a Linux path and the script never sees the repo.
  • Forward-slashes the script path, since bash treats backslashes as escapes.
  • GSTACK_BASH overrides for unusual installs.
  • Returns null when no bash exists, so the stage reports skipped (no bash found; set GSTACK_BASH to your Git bash.exe) rather than an unactionable spawn error.

POSIX is unchanged: the script is exec'd directly, no interpreter, no shell.

Tests

The #1731 tripwire asserted the shape that does not work (spawnSync(brainSyncPath, ...) + shell: NEEDS_SHELL_ON_WINDOWS), so it now asserts the opposite and fails if a raw spawn returns. Six unit tests cover the resolver: POSIX passthrough, Git-bash resolution, path slashing, shell: false, GSTACK_BASH override, and the no-bash null.

The gbrain.cmd assertions in that file are untouched — that part of #1731 is right and still enforced.

Verification (Windows 11, gstack 1.61.0.0, bun 1.3.11)

Before: ERR brain-sync gstack-brain-sync exited 1 (0.0s)
After: OK brain-sync curated artifacts pushed (4.2s) — and the artifacts repo committed and pushed on its own.

The suite is nondeterministic on Windows (the same tree gave 743 and 741 failures on back-to-back runs), so I compared the affected files rather than the whole run: 14 failures before, 14 after, with 6 new passing tests. No behaviour change on POSIX, where the invocation is byte-identical to today's.

🤖 Generated with Claude Code

The brain-sync stage failed on EVERY Windows run with "is not
recognized as an internal or external command", so /sync-gbrain always
reported ERR brain-sync among otherwise green stages.

garrytan#1731 gave these spawns shell: NEEDS_SHELL_ON_WINDOWS. That is correct
for the gbrain.cmd shim and does nothing here: shell:true routes through
cmd.exe, which resolves .cmd/.bat via PATHEXT but has no concept of a
shebang, so an extension-less bash script is rejected outright. A .cmd
shim needs a shell; a shebang script needs an interpreter. The two cases
look identical and are not.

The failure was quiet rather than loud. artifacts_sync_mode defaults to
pushing curated artifacts to git, so a Windows user's learnings piled up
uncommitted in ~/.gstack indefinitely while the sync report showed one
red line out of four.

New bashScriptInvocation() resolves Git for Windows' bash explicitly and
passes the script as argv[0]. It prefers Git bash over a bare `bash` on
PATH because WindowsApps ships a bash.exe that is the WSL launcher, which
would read C:\... as a Linux path; GSTACK_BASH overrides for unusual
installs; forward slashes because bash treats backslashes as escapes; and
it returns null when no bash exists so the stage says so plainly instead
of surfacing an unactionable spawn error.

The garrytan#1731 tripwire asserted the shape that does not work, so it now
asserts the opposite (never a raw spawnSync(brainSyncPath, ...)) and six
unit tests cover the resolver.

Verified on Windows: the stage now reports "OK brain-sync curated
artifacts pushed (4.2s)" and the artifacts repo committed + pushed on its
own. Affected-test set unchanged at 14 pre-existing failures before and
after, with 6 new passing tests.
@trunk-io

trunk-io Bot commented Aug 10, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

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