You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(browse,design): resolve ~/.gstack via os.homedir() not $HOME || /tmp
31 sites across 6 files constructed paths for `~/.gstack/` state, chromium
profile, ngrok env, sidebar session dirs, worktrees, agent queue, openai
config, etc., using one of these patterns:
path.join(process.env.HOME || '/tmp', '.gstack', ...) (20 sites)
path.join(process.env.HOME || '', '.claude/skills/...', ...) (8 sites)
path.join(process.env.HOME!, '.gstack/openai.json') (1 site — non-null assertion)
path.join(process.env.HOME || "~", '.gstack', 'openai.json') (1 site — literal "~" never expands)
process.env.HOME || process.env.USERPROFILE || '/tmp' (1 site — already platform-aware)
On Windows, `process.env.HOME` is NOT set by default. Windows uses
`USERPROFILE` for the same purpose. Git Bash happens to set HOME, so
gstack state currently lands correctly when a user runs commands from a
Git Bash shell — which is the only supported dev path, since `./setup`
is a bash script. But:
- Compiled binaries (`browse.exe`, etc.) spawn detached subprocesses
(the server, the sidebar agent, chromium) with the environment of the
calling shell. When a user runs `browse.exe` from cmd.exe or PowerShell
(or from an IDE that doesn't inherit Git Bash's env), HOME is unset.
- `path.join('/tmp', '.gstack', 'x')` resolves to `\tmp\.gstack\x` on
Windows — literal directory that doesn't exist.
- `path.join('', '.claude/skills/...', 'x')` resolves to a relative path
from CWD — silent mislocation.
- `process.env.HOME!` crashes with a non-null assertion at load time.
- `path.join("~", ...)` creates a literal `~` dir under CWD; Node path
APIs never expand `~`.
Fix: replace all five variants with `os.homedir()`. Per Node docs, `os.homedir()`:
- on POSIX: returns `$HOME` if set, else consults `getpwuid(geteuid())`
- on Windows: returns `$USERPROFILE` if set, else calls the Win32 API
Strictly better than every variant above on every platform. Test-isolation
patterns that set `process.env.HOME = tmpDir` (e.g. the one in
`browse/test/security-review-flow.test.ts:30`) keep working on POSIX CI
because `os.homedir()` reads HOME there.
Added `import * as os from 'os'` / `import os from "os"` to the 6 files
that didn't already have it, matching each file's existing import style.
Empirical proof on Windows 11 (cmd.exe-equivalent env with HOME unset):
OLD (|| "/tmp"): \tmp\.gstack\sidebar-agent-queue.jsonl
NEW (os.homedir): C:\Users\Sam\.gstack\sidebar-agent-queue.jsonl
Test suite: 163 pass / 10 fail on this branch. Identical 163/10 on clean
upstream main with the same test selection (confirmed by stash + rerun).
The 10 failures are all pre-existing (batch.test.ts hook timeout,
bun-polyfill Bun.serve/spawn/sleep assertions, a few sidebar-integration
tests that hit a pre-existing beforeEach timeout) and don't touch the
paths this PR modifies. Zero regressions.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0 commit comments