* fix(hooks): resolve MCP health-check spawn ENOENT on Windows
On Windows, commands like 'npx' are batch files (npx.cmd) that require
shell expansion to resolve via PATH. Without shell: true, Node.js
spawn() fails with ENOENT.
However, absolute paths (e.g. C:\Program Files\nodejs\node.exe) must
NOT use shell mode because cmd.exe misparses paths containing spaces.
Fix: enable shell mode only for non-absolute commands on Windows, using
path.isAbsolute() to distinguish. This matches how attemptReconnect()
already handles the shell option.
Fixes#1455
* fix(hooks): harden Windows shell spawn — validate command for metacharacters
Addresses bot review feedback on PR #1456:
- Add UNSAFE_SHELL_CHARS regex to guard against shell injection when
needsShell=true: cmd.exe operators (&, |, <, >, ^, %, !, (), ;,
whitespace) are rejected before shell mode is enabled
- Add typeof command === 'string' check so path.isAbsolute() cannot
throw on malformed non-string command values
- Rename test to 'via PATH resolution' (not Windows-only; runs all platforms)
- Fix misleading test comment: 'node' resolves via PATH like npx.cmd but
does not itself use .cmd; comment now accurately reflects the intent
* fix(hooks): kill full process tree on Windows when shell mode is used
When needsShell=true, the spawned child is cmd.exe. Calling child.kill()
only terminates the shell, leaving the real server process orphaned.
Use taskkill /PID <pid> /T /F on Windows+shell to kill the entire
process tree rooted at cmd.exe. Fall back to SIGTERM+SIGKILL on all
other platforms or when shell mode is not active.
* fix(hooks): fall back to child.kill() when taskkill fails
Windows taskkill can fail if it's not on PATH, the process already
exited, or permissions are denied. Previously the failure was silently
ignored and no kill signal reached the child.
Now: capture the spawnSync result and fall back to child.kill('SIGKILL')
on any taskkill error or non-zero status. This still may leak a
detached server process but at least guarantees the cmd.exe shell is
signaled.
Extends the hook command path correction from PR #1682 (English source) to
the zh-CN, zh-TW, and ja-JP translated mirrors so the PreToolUse hook
example matches the actual script location at
~/.claude/scripts/hooks/suggest-compact.js.
Changes per locale:
- docs/zh-CN/skills/strategic-compact/SKILL.md: update both command strings
from ~/.claude/skills/strategic-compact/suggest-compact.js to
~/.claude/scripts/hooks/suggest-compact.js.
- docs/zh-TW/skills/strategic-compact/SKILL.md: replace the outdated
suggest-compact.sh reference (the .sh variant was removed in merged PR
#41) with the current node-invoked suggest-compact.js, and align the
matcher block structure with the English canonical SKILL.md post-#1682.
- docs/ja-JP/skills/strategic-compact/SKILL.md: same .sh -> .js migration
and matcher alignment as zh-TW.
The ko-KR mirror already uses the correct CLAUDE_PLUGIN_ROOT-based hook
path and needs no change.
Refs #1675
The Hook Setup example pointed to
`~/.claude/skills/strategic-compact/suggest-compact.js`, which does not
exist in the current repo layout. The cross-platform Node.js hook ships
at `scripts/hooks/suggest-compact.js` and is installed to
`~/.claude/scripts/hooks/suggest-compact.js`.
Anyone copy-pasting the documented config hit a broken hook command.
Closes#1675
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>