From 7da1c3cf682a9e4dde90573566fa6ae2a050f4e1 Mon Sep 17 00:00:00 2001 From: garrytan Date: Sat, 3 Oct 2026 21:35:23 +0000 Subject: [PATCH] E1: cmd.exe-safe investigate freeze hook On Windows Claude Code runs hook commands through cmd.exe, which cannot parse the single-quoted bash -c argument, so /investigate's scope-lock hook never ran. Use one double-quoted bash -c script that names the hook path directly (no S= variable: POSIX sh would expand $S to empty and skip the hook). --- investigate/SKILL.md.tmpl | 4 ++-- test/investigate-freeze-path.test.ts | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/investigate/SKILL.md.tmpl b/investigate/SKILL.md.tmpl index 7ddded7d3..f29a1ed9e 100644 --- a/investigate/SKILL.md.tmpl +++ b/investigate/SKILL.md.tmpl @@ -30,12 +30,12 @@ hooks: - matcher: "Edit" hooks: - type: command - command: 'bash -c ''S="$HOME/.claude/skills/gstack/freeze/bin/check-freeze.sh"; [ -x "$S" ] && exec bash "$S"; exit 0''' + command: 'bash -c "test -x \"$HOME/.claude/skills/gstack/freeze/bin/check-freeze.sh\" && exec bash \"$HOME/.claude/skills/gstack/freeze/bin/check-freeze.sh\"; exit 0"' statusMessage: "Checking debug scope boundary..." - matcher: "Write" hooks: - type: command - command: 'bash -c ''S="$HOME/.claude/skills/gstack/freeze/bin/check-freeze.sh"; [ -x "$S" ] && exec bash "$S"; exit 0''' + command: 'bash -c "test -x \"$HOME/.claude/skills/gstack/freeze/bin/check-freeze.sh\" && exec bash \"$HOME/.claude/skills/gstack/freeze/bin/check-freeze.sh\"; exit 0"' statusMessage: "Checking debug scope boundary..." gbrain: schema: 1 diff --git a/test/investigate-freeze-path.test.ts b/test/investigate-freeze-path.test.ts index 7b9ef0cae..ab7379b02 100644 --- a/test/investigate-freeze-path.test.ts +++ b/test/investigate-freeze-path.test.ts @@ -17,8 +17,9 @@ describe('investigate freeze path resolution', () => { const content = fs.readFileSync(path.join(ROOT, rel), 'utf-8'); test(`${rel} hook resolves check-freeze via the $HOME anchor`, () => { - expect(content).toContain('S="$HOME/.claude/skills/gstack/freeze/bin/check-freeze.sh"'); - expect(content).toContain('[ -x "$S" ] && exec bash "$S"; exit 0'); + // E1: cmd.exe-safe — no single-quoted words, no variable POSIX sh would expand to empty. + expect(content).toContain(`command: 'bash -c "test -x \\"$HOME/.claude/skills/gstack/freeze/bin/check-freeze.sh\\" && exec bash \\"$HOME/.claude/skills/gstack/freeze/bin/check-freeze.sh\\"; exit 0"'`); + expect(content).not.toContain('S="$HOME/.claude/skills/gstack/freeze/bin/check-freeze.sh"'); const commandLines = content.split('\n').filter((l) => l.trim().startsWith('command:')); expect(commandLines.length).toBeGreaterThan(0); for (const line of commandLines) {