mirror of
https://github.com/obra/superpowers.git
synced 2026-07-17 23:44:04 +08:00
Compare commits
2 Commits
dev
...
fix/window
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd12428a5c | ||
|
|
390bc07abb |
@@ -6,9 +6,18 @@ Claude Code plugins need hooks that work on Windows, macOS, and Linux. This docu
|
|||||||
|
|
||||||
## The Problem
|
## The Problem
|
||||||
|
|
||||||
Claude Code runs hook commands through the system's default shell:
|
Claude Code runs hook commands through a shell:
|
||||||
- **Windows**: CMD.exe
|
|
||||||
- **macOS/Linux**: bash or sh
|
- **macOS/Linux**: bash or sh
|
||||||
|
- **Windows with Git Bash installed**: Git Bash
|
||||||
|
- **Windows without Git Bash**: PowerShell (older versions used CMD.exe)
|
||||||
|
|
||||||
|
Neither Windows fallback shell can parse our command string: PowerShell treats
|
||||||
|
a leading quoted path as a string expression and errors on the next bareword,
|
||||||
|
and CMD.exe's `/c` quoting rules strip the outer quotes when the path contains
|
||||||
|
a metacharacter such as `(`. Our hooks therefore declare `"shell": "bash"`
|
||||||
|
(supported since Claude Code 2.1.81; older versions ignore the key), which
|
||||||
|
forces the Git Bash route and, when Git Bash is absent, produces an actionable
|
||||||
|
"install Git for Windows" error instead of a shell parser failure.
|
||||||
|
|
||||||
This creates several challenges:
|
This creates several challenges:
|
||||||
|
|
||||||
@@ -42,6 +51,7 @@ hooks/
|
|||||||
{
|
{
|
||||||
"type": "command",
|
"type": "command",
|
||||||
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cmd\" session-start",
|
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cmd\" session-start",
|
||||||
|
"shell": "bash",
|
||||||
"async": false
|
"async": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
{
|
{
|
||||||
"type": "command",
|
"type": "command",
|
||||||
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cmd\" session-start",
|
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cmd\" session-start",
|
||||||
|
"shell": "bash",
|
||||||
"async": false
|
"async": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -143,6 +143,27 @@ for (const forbiddenText of forbiddenTexts) {
|
|||||||
|
|
||||||
echo "SessionStart hook output tests"
|
echo "SessionStart hook output tests"
|
||||||
|
|
||||||
|
# Registration shape: the hook must declare shell:"bash" so Claude Code on
|
||||||
|
# Windows dispatches via Git Bash (or fails with an actionable error) instead
|
||||||
|
# of PowerShell/cmd.exe, whose parsers break on the quoted command string
|
||||||
|
# (PowerShell ParserError; cmd.exe quote-stripping on paths with metacharacters).
|
||||||
|
if node -e '
|
||||||
|
const hooks = JSON.parse(require("fs").readFileSync(process.argv[1], "utf8"));
|
||||||
|
const entry = hooks.hooks.SessionStart[0].hooks[0];
|
||||||
|
if (entry.shell !== "bash") {
|
||||||
|
console.error(`SessionStart hook shell is ${JSON.stringify(entry.shell)}, expected "bash"`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
if (!/run-hook\.cmd" session-start$/.test(entry.command)) {
|
||||||
|
console.error(`unexpected SessionStart command shape: ${entry.command}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
' "$REPO_ROOT/hooks/hooks.json"; then
|
||||||
|
pass "hooks.json registers SessionStart with shell:bash dispatch"
|
||||||
|
else
|
||||||
|
fail "hooks.json registers SessionStart with shell:bash dispatch"
|
||||||
|
fi
|
||||||
|
|
||||||
claude_home="$(make_home claude-code)"
|
claude_home="$(make_home claude-code)"
|
||||||
assert_command_output \
|
assert_command_output \
|
||||||
"Claude Code emits nested SessionStart additionalContext" \
|
"Claude Code emits nested SessionStart additionalContext" \
|
||||||
|
|||||||
Reference in New Issue
Block a user