Six independent windows-only failure clusters identified from the
windows-22 CI log on 1be0e4e2:
- scripts/command-contract-helpers.cjs: parseFrontmatter split on `\n`
→ on Windows checkout (autocrlf=true) every line carries trailing \r,
lines.indexOf('---', 1) returns -1, all fields read as missing. Drove
the bulk of three "67 subtests failed" suite-level errors covering
workstreams.md, workspace.md, verify-work.md, add-tests.md, etc.
Fix: split(/\r?\n/).
- tests/enh-3271-sdk-adr-structure.test.cjs: same CRLF pattern — H2
captures pulled '\r' into headings like "decision\r", breaking
equality checks on "## Decision" / "## Consequences". Fix: same.
- tests/runtime-bridge-sync-smoke.test.cjs: await import(BRIDGE_PATH)
passed a Windows absolute path to Node's ESM loader, which rejects
with "Only URLs with a scheme in: file, data, and node are
supported." Fix: wrap once at module scope with pathToFileURL.
pathToFileURL is a no-op for POSIX absolute paths.
- tests/bug-2957-claude-global-postinstall-message.test.cjs: hardcoded
'/tmp/gsd-test-settings.json' resolved to D:\tmp\... on Windows
where the parent dir doesn't exist → ENOENT on fs.writeFileSync
inside finishInstall. Fix: os.tmpdir() + pid suffix.
- tests/bug-2774-worktree-cleanup-workspace-safety.test.cjs: the
"while/read loop" subtest and the "end-to-end against real git
worktrees" describe both assert POSIX shell behavior (process
substitution `< <(...)`, RUNNER~1 8.3-shortname mismatch). Skip on
win32 with explicit reasons (satisfies the
no-unconditional-win32-skip guard).
- tests/bug-2838-summary-rescue-gitignored-planning.test.cjs: entire
describe extracts bash rescue blocks from workflow .md files and
runs them; the shell contract itself is the test's point. Skip on
win32 with reason.
- tests/helpers.cjs cleanup(): bumped rmSync retry budget from
10×100ms to 20×250ms — 1s wasn't enough for Windows Defender's
deferred handle release; bumping to 5s should absorb the residual
EBUSY failures observed in bug-1736 / bug-2248 / bug-2698 after the
first retry bump landed in 1be0e4e2.
Validated: holodeck (ubuntu docker) 11224/0 pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(#2957): claude+global post-install instructs restart and skill fallback
`npx get-shit-done-cc --claude --global` writes skills to
`~/.claude/skills/gsd-*/SKILL.md` (CC 2.1.88+ format) and removes the
legacy `~/.claude/commands/gsd/`. The post-install message still told
users to type `/gsd-new-project` without mentioning the required Claude
Code restart or the skill-name fallback. On configurations where CC
does not auto-surface skills in the slash menu, users hit "no commands
appear" and assumed the install failed.
Split the post-install message: the existing single-line instruction
stays for every non-Claude runtime and for `--claude --local`. For
`--claude --global` it now reads:
Restart Claude Code, then in any directory either type
/gsd-new-project or ask Claude to run the gsd-new-project skill.
This covers both invocation paths and surfaces the restart requirement.
Add tests/bug-2957-claude-global-postinstall-message.test.cjs as a
regression guard: captures the printed message for claude+global,
claude+local, and opencode+global; asserts content for each. Verified
the test fails on main (pre-fix) and passes after the fix.
Closes#2957
* test(#2957): assert legacy generic instruction is replaced not extended
CodeRabbit flagged that the test would still pass if the new restart/
fallback copy were printed *alongside* the old 'open a blank directory'
instruction. Adding a doesNotMatch assertion proves the claude+global
branch replaces the legacy line rather than appending to it.