Summary
On Windows (Git Bash + Bun's built-in script runner), bun run build fails after compiling all binaries because package.json line 12's scripts.build contains three bash brace groups { cmd; } which Bun's Windows shell parser doesn't support. The compile steps succeed but the .version-write step throws three bun: command not found: { errors and exits with code 1.
Knock-on impact: when setup invokes bun run build and the build exits non-zero, the subshell-wrapped call masks the failure (outer setup exit code stays 0) but the script DOES bail out of the build subshell, so the downstream link_claude_skill_dirs step is never reached. Result: stale top-level skill registrations on Windows (filed separately).
Steps to Reproduce
Minimal isolation — no gstack needed:
mkdir -p /tmp/bun-brace-test && cd /tmp/bun-brace-test
cat > package.json <<'PKG'
{
"name": "brace-test",
"scripts": {
"test-parens": "( echo hello-parens )",
"test-braces": "{ echo hello-braces; }",
"test-version-pattern": "{ git rev-parse HEAD 2>/dev/null || true; } > /tmp/version-out.txt"
}
}
PKG
bun run test-parens
# $ ( echo hello-parens )
# hello-parens <-- works
bun run test-braces
# $ { echo hello-braces; }
# bun: command not found: {
# bun: command not found: }
# error: script "test-braces" exited with code 1
bun run test-version-pattern
# Same error pattern.
Full gstack repro:
cd ~/.claude/skills/gstack && bun run build 2>&1 | tail -10
# (after the compiles succeed:)
# bun: command not found: {
# bun: command not found: }
# bun: command not found: }
# error: script "build" exited with code 1
Expected Behavior
bun run build exits 0 on Windows after successfully writing all three .version files.
Actual Behavior
Bun's Windows shell parser interprets { and } as command names, not as brace-group syntax. The compile steps complete, then the three .version-write steps fail back-to-back, and the entire bun run build exits with code 1.
The existing safety net at setup lines 242-245 catches the missing browse/dist/.version after the failure, but the two sibling .version files (design/dist/.version, make-pdf/dist/.version) get no such fallback, and the non-zero exit code is what trips the silent setup bail-out.
Root Cause
package.json line 12, three occurrences of bash brace groups:
... && { git rev-parse HEAD 2>/dev/null || true; } > browse/dist/.version
&& { git rev-parse HEAD 2>/dev/null || true; } > design/dist/.version
&& { git rev-parse HEAD 2>/dev/null || true; } > make-pdf/dist/.version && ...
POSIX bash treats { cmd; } as a brace group (no subshell, same environment). Bun's Windows shell parser does NOT implement brace-group parsing. The runner falls through to treating { as a literal command-to-invoke.
Suggested Patch
Replace each brace group with a parenthesis subshell. Functionally equivalent for one-shot stdout redirection (no shared-variable semantics needed here):
- "build": "... && { git rev-parse HEAD 2>/dev/null || true; } > browse/dist/.version && { git rev-parse HEAD 2>/dev/null || true; } > design/dist/.version && { git rev-parse HEAD 2>/dev/null || true; } > make-pdf/dist/.version && ...",
+ "build": "... && ( git rev-parse HEAD 2>/dev/null || true ) > browse/dist/.version && ( git rev-parse HEAD 2>/dev/null || true ) > design/dist/.version && ( git rev-parse HEAD 2>/dev/null || true ) > make-pdf/dist/.version && ...",
Subshells ( ... ) are universally supported in POSIX bash, zsh, and Bun's Windows shell. The cost (spawning a subshell vs sharing env) is irrelevant for a one-line git rev-parse + redirect.
Workaround (for users on current setup)
Either:
- Local patch of
package.json line 12 (will conflict on next git pull).
- Skip the build step entirely if binaries are already current —
touch ~/.claude/skills/gstack/browse/dist/browse (and the other 4 binaries) to push their mtime past package.json and bun.lock. Setup's NEEDS_BUILD=0 check at line 224 then skips the build call.
Environment
- Windows 11 Home 10.0.26200
- Git Bash (MINGW64)
- bun 1.3.13
- gstack v1.33.2.0 (HEAD
dc6252d1)
Summary
On Windows (Git Bash + Bun's built-in script runner),
bun run buildfails after compiling all binaries becausepackage.jsonline 12'sscripts.buildcontains three bash brace groups{ cmd; }which Bun's Windows shell parser doesn't support. The compile steps succeed but the.version-write step throws threebun: command not found: {errors and exits with code 1.Knock-on impact: when
setupinvokesbun run buildand the build exits non-zero, the subshell-wrapped call masks the failure (outer setup exit code stays 0) but the script DOES bail out of the build subshell, so the downstreamlink_claude_skill_dirsstep is never reached. Result: stale top-level skill registrations on Windows (filed separately).Steps to Reproduce
Minimal isolation — no gstack needed:
Full gstack repro:
Expected Behavior
bun run buildexits 0 on Windows after successfully writing all three.versionfiles.Actual Behavior
Bun's Windows shell parser interprets
{and}as command names, not as brace-group syntax. The compile steps complete, then the three.version-write steps fail back-to-back, and the entirebun run buildexits with code 1.The existing safety net at
setuplines 242-245 catches the missingbrowse/dist/.versionafter the failure, but the two sibling.versionfiles (design/dist/.version,make-pdf/dist/.version) get no such fallback, and the non-zero exit code is what trips the silent setup bail-out.Root Cause
package.jsonline 12, three occurrences of bash brace groups:POSIX bash treats
{ cmd; }as a brace group (no subshell, same environment). Bun's Windows shell parser does NOT implement brace-group parsing. The runner falls through to treating{as a literal command-to-invoke.Suggested Patch
Replace each brace group with a parenthesis subshell. Functionally equivalent for one-shot stdout redirection (no shared-variable semantics needed here):
Subshells
( ... )are universally supported in POSIX bash, zsh, and Bun's Windows shell. The cost (spawning a subshell vs sharing env) is irrelevant for a one-linegit rev-parse+ redirect.Workaround (for users on current setup)
Either:
package.jsonline 12 (will conflict on nextgit pull).touch ~/.claude/skills/gstack/browse/dist/browse(and the other 4 binaries) to push their mtime pastpackage.jsonandbun.lock. Setup'sNEEDS_BUILD=0check at line 224 then skips the build call.Environment
dc6252d1)