Repository navigation
Conversation
Bun's Windows shell parser rejects `(cmd) > file` with:
error: Failed to run script build due to error
Subshells with redirections are currently not supported.
Please open a GitHub issue.
This makes `./setup` fail on every Windows install — the binaries
don't rebuild and the user is left with whatever stale browse.exe
was last committed (or no binary at all on a fresh clone).
Fix: wrap each `(git rev-parse HEAD ...) > path` and the trailing
`(rm -f ...)` cleanup in `bash -c '...'`. The version-stamp behavior
is identical (empty file when not in a git checkout vs SHA when we
are); the build now runs end-to-end on Windows via git-bash + bun
1.3.13.
Verified on Windows 11 + bun 1.3.13 + git-bash:
- Pre-patch: `./setup` aborts during `bun run build`.
- Post-patch: full build completes (~7s on a warm cache), all 5
compiled exes land in their dist dirs, server-node.mjs bundles.
POSIX behaviour is unchanged — bash on macOS / Linux handles either
syntax. No risk to existing platforms.
Bun's compiled-binary `fs.mkdirSync(path, {recursive:true})` throws
EEXIST when the directory already exists. Node does NOT — `recursive:
true` is documented as suppressing EEXIST. The divergence makes every
`browse` invocation on Windows exit 1 with:
[browse] EEXIST: file already exists, mkdir 'C:\...\.gstack'
because ensureStateDir() runs unconditionally at startup and the
project's `.gstack/` exists by then (gitignore'd state dir).
Reproduced on:
- Windows 11 Home (10.0.26200)
- bun 1.3.13
- OneDrive home directory (path contains a space)
- git-bash + plain cmd.exe — both surface the same EEXIST
A plain `node -e "require('fs').mkdirSync('.gstack', {recursive:true})"`
on the same machine + same path succeeds. So the bug is in bun's fs
shim, not in our code or the filesystem. But mkdirSecure can defend
defensively without waiting for an upstream bun fix.
Fix: catch EEXIST in mkdirSecure(), verify the existing path is in
fact a directory (statSync), then fall through to re-apply the ACL.
Throws on any other error code. The behavior on Node is unchanged
(EEXIST is never raised, so the catch never fires).
Verified end-to-end: rebuilt the browse binary with the patch,
re-ran `browse status` and `browse goto https://example.com` — both
return cleanly. Prior to the patch, both exited 1 with the EEXIST.
Without this fix, gstack browse is 100% unusable on Windows.
|
Thanks for splitting this into two commits. One collision to call out: the |
|
Thanks for this, @w-khai. The fix is now on main: the build moved to scripts/build.sh and the EEXIST on an existing .gstack dir under Bun on Windows is handled (fixed in v1.91.16.0, #3014). Closing as superseded; if you still see the problem on the latest gstack, please open an issue with ./setup --status output. |
What
Two independent fixes that together unblock gstack browse on Windows. Each commit is self-contained and can be cherry-picked individually.
e0daa44package.json(1 line)./setupfails before binaries rebuild because bun's Windows shell doesn't support(cmd) > filesubshell-with-redirect.376c5cdbrowse/src/file-permissions.ts(+16/-1)browseinvocation on Windows exits 1 withEEXISTbecause bun'sfs.mkdirSync(p, {recursive:true})throws when the dir exists (Node doesn't).Without these two fixes, gstack browse is 100% unusable on Windows. With them, both
./setupandbrowse <cmd>work end-to-end on Windows 11 + bun 1.3.13 + git-bash + OneDrive home directory.Reproduction (pre-patch)
Verification (post-patch)
I drove a full real-app QA walkthrough end-to-end against an in-house SvelteKit + Go project on Windows after the fix landed — 12 browser-side commands across login, form fill, screenshot, JS eval, navigation — zero EEXIST recurrences.
Risk
Both fixes are POSIX no-ops:
package.jsonchange wraps subshell-with-redirect lines inbash -c '...'. Bash on macOS / Linux handles the wrapped form identically to the unwrapped one (it's just one extra fork). I ranbun run buildafter the patch on Windows; can't trivially exercise on macOS from this box but the syntax change is mechanical.mkdirSecureonly ADDS a catch arm forEEXIST(and re-throws everything else). Node'smkdirSync({recursive:true})is documented to never throw EEXIST, so on Linux/macOS this catch arm never fires. ThestatSync+restrictDirectoryPermissionsfollow-through is idempotent.Test plan
For maintainers wanting to reproduce:
./setup.cd <some-project>(any dir is fine; the bug fires on the.gstack/mkdir at browse startup).master(pre-patch):./setupfails on the build script. After commenting out the redirects locally, the resulting binary then fails with EEXIST on everybrowseinvocation../setupandbrowse statuscomplete cleanly.Notes
212912583+w-khai@users.noreply.github.com) because my real email is private.🤖 Generated with Claude Code