Files
superpowers/hooks/run-hook.cmd

60 lines
2.1 KiB
Batchfile
Raw Normal View History

Add Windows support for plugin hooks (#134) * feat: Add Windows support for session-start hook - Create polyglot session-start.cmd that works in both CMD and bash - Update hooks.json to use the .cmd polyglot launcher - Replace sed/awk with pure bash for JSON escaping (Windows compatibility) The polyglot script uses a heredoc trick: - CMD sees the @echo off block and runs bash.exe with cygpath conversion - Bash sees a heredoc and skips to the Unix section 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Add execute permission to session-start.cmd for Unix 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: Add comprehensive polyglot hooks documentation - Add docs/windows/polyglot-hooks.md explaining the cross-platform technique - Add reusable run-hook.cmd wrapper for parameterized hook execution - Document how the polyglot works in CMD vs bash - Include troubleshooting section and related GitHub issues 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * test: Add polyglot hook test script for macOS/Linux Run ./test-polyglot.sh from repo root to verify: - Required files exist with execute permissions - Simple wrapper (session-start.cmd) produces valid JSON - Parameterized wrapper (run-hook.cmd) works - Heredoc correctly skips CMD block on Unix 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Use direct pipe to jq in test to avoid variable escaping issues 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: Use single reusable run-hook.cmd for all hooks - Remove session-start.cmd in favor of run-hook.cmd - Update hooks.json to use: run-hook.cmd session-start.sh - Simplify test script to only test run-hook.cmd This makes it easy to add more hooks - just create the .sh file and add a line to hooks.json pointing to run-hook.cmd with the script name. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Simplify run-hook.cmd CMD block Pass path directly to bash instead of using cygpath in a subshell. The complex quoting was causing issues on Windows. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * chore: Remove test-polyglot.sh Testing complete - polyglot hooks work on Windows and macOS. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
2025-12-01 15:42:12 -08:00
: << 'CMDBLOCK'
@echo off
REM Cross-platform polyglot wrapper for hook scripts.
REM On Windows: cmd.exe runs the batch portion, which finds and calls bash.
REM On Unix: the shell interprets this as a script (: is a no-op in bash).
REM
REM Hook scripts use extensionless filenames (e.g. "session-start" not
REM "session-start.sh") so Claude Code's Windows auto-detection -- which
REM prepends "bash" to any command containing .sh -- doesn't interfere.
REM
Add Windows support for plugin hooks (#134) * feat: Add Windows support for session-start hook - Create polyglot session-start.cmd that works in both CMD and bash - Update hooks.json to use the .cmd polyglot launcher - Replace sed/awk with pure bash for JSON escaping (Windows compatibility) The polyglot script uses a heredoc trick: - CMD sees the @echo off block and runs bash.exe with cygpath conversion - Bash sees a heredoc and skips to the Unix section 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Add execute permission to session-start.cmd for Unix 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: Add comprehensive polyglot hooks documentation - Add docs/windows/polyglot-hooks.md explaining the cross-platform technique - Add reusable run-hook.cmd wrapper for parameterized hook execution - Document how the polyglot works in CMD vs bash - Include troubleshooting section and related GitHub issues 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * test: Add polyglot hook test script for macOS/Linux Run ./test-polyglot.sh from repo root to verify: - Required files exist with execute permissions - Simple wrapper (session-start.cmd) produces valid JSON - Parameterized wrapper (run-hook.cmd) works - Heredoc correctly skips CMD block on Unix 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Use direct pipe to jq in test to avoid variable escaping issues 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: Use single reusable run-hook.cmd for all hooks - Remove session-start.cmd in favor of run-hook.cmd - Update hooks.json to use: run-hook.cmd session-start.sh - Simplify test script to only test run-hook.cmd This makes it easy to add more hooks - just create the .sh file and add a line to hooks.json pointing to run-hook.cmd with the script name. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Simplify run-hook.cmd CMD block Pass path directly to bash instead of using cygpath in a subshell. The complex quoting was causing issues on Windows. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * chore: Remove test-polyglot.sh Testing complete - polyglot hooks work on Windows and macOS. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
2025-12-01 15:42:12 -08:00
REM Usage: run-hook.cmd <script-name> [args...]
if "%~1"=="" (
echo run-hook.cmd: missing script name >&2
exit /b 1
)
set "HOOK_DIR=%~dp0"
REM Try Git for Windows bash in standard locations
if exist "C:\Program Files\Git\bin\bash.exe" (
"C:\Program Files\Git\bin\bash.exe" "%HOOK_DIR%%~1" %2 %3 %4 %5 %6 %7 %8 %9
exit /b %ERRORLEVEL%
)
if exist "C:\Program Files (x86)\Git\bin\bash.exe" (
"C:\Program Files (x86)\Git\bin\bash.exe" "%HOOK_DIR%%~1" %2 %3 %4 %5 %6 %7 %8 %9
exit /b %ERRORLEVEL%
)
Probe per-user Git Bash and Scoop before falling back to PATH on Windows Stock Windows 10/11 ships C:\Windows\System32\bash.exe (the WSL launcher) as the first match for `where bash`. WSL's bash cannot execute Windows-style script paths, so when Git Bash is installed outside the two standard system locations -- specifically the per-user "Only for me" Git for Windows installer (%LOCALAPPDATA%\Programs\Git) or a Scoop install (%USERPROFILE%\scoop\apps\git\current\usr\bin) -- run-hook.cmd silently fails: WSL prints "Windows Subsystem for Linux must be updated", the script returns 0, and Superpowers' SessionStart bootstrap is never injected. From the user's perspective skills auto-trigger inconsistently or not at all, with no surfaced error. Add explicit probes for both locations between the existing system- wide Git for Windows checks and the `where bash` fallback. Also add a comment to the fallback documenting the WSL-launcher trap so future maintainers understand why the explicit probes must come first. Verified on a Windows 11 VM (dockur/windows 11, Git Bash 2.x, Node 22): - System Git present: existing probe still matches (no regression) - System Git absent, per-user Git present via junction: new probe matches, hook produces valid 6422-byte JSON, exit 0 - All Git probes absent: confirmed WSL trap fires ("Windows Subsystem for Linux must be updated") and the hook exits 0 silently, demonstrating the original bug Existing tests/hooks/test-session-start.sh still passes on macOS (7/7). Reported by @ytchenak in #1607. Co-authored-by: ytchenak <ytchenak@users.noreply.github.com> Closes #1607.
2026-05-23 16:58:56 -07:00
REM Per-user Git for Windows installer ("Only for me" / winget user scope)
if exist "%LOCALAPPDATA%\Programs\Git\bin\bash.exe" (
"%LOCALAPPDATA%\Programs\Git\bin\bash.exe" "%HOOK_DIR%%~1" %2 %3 %4 %5 %6 %7 %8 %9
exit /b %ERRORLEVEL%
)
REM Scoop user install (`scoop install git`)
if exist "%USERPROFILE%\scoop\apps\git\current\usr\bin\bash.exe" (
"%USERPROFILE%\scoop\apps\git\current\usr\bin\bash.exe" "%HOOK_DIR%%~1" %2 %3 %4 %5 %6 %7 %8 %9
exit /b %ERRORLEVEL%
)
Probe per-user Git Bash and Scoop before falling back to PATH on Windows Stock Windows 10/11 ships C:\Windows\System32\bash.exe (the WSL launcher) as the first match for `where bash`. WSL's bash cannot execute Windows-style script paths, so when Git Bash is installed outside the two standard system locations -- specifically the per-user "Only for me" Git for Windows installer (%LOCALAPPDATA%\Programs\Git) or a Scoop install (%USERPROFILE%\scoop\apps\git\current\usr\bin) -- run-hook.cmd silently fails: WSL prints "Windows Subsystem for Linux must be updated", the script returns 0, and Superpowers' SessionStart bootstrap is never injected. From the user's perspective skills auto-trigger inconsistently or not at all, with no surfaced error. Add explicit probes for both locations between the existing system- wide Git for Windows checks and the `where bash` fallback. Also add a comment to the fallback documenting the WSL-launcher trap so future maintainers understand why the explicit probes must come first. Verified on a Windows 11 VM (dockur/windows 11, Git Bash 2.x, Node 22): - System Git present: existing probe still matches (no regression) - System Git absent, per-user Git present via junction: new probe matches, hook produces valid 6422-byte JSON, exit 0 - All Git probes absent: confirmed WSL trap fires ("Windows Subsystem for Linux must be updated") and the hook exits 0 silently, demonstrating the original bug Existing tests/hooks/test-session-start.sh still passes on macOS (7/7). Reported by @ytchenak in #1607. Co-authored-by: ytchenak <ytchenak@users.noreply.github.com> Closes #1607.
2026-05-23 16:58:56 -07:00
REM Try bash on PATH (e.g. user-installed Git Bash, MSYS2, Cygwin). Note that
REM on stock Windows 10/11 `where bash` resolves to C:\Windows\System32\bash.exe
REM (the WSL launcher), which fails on Windows-style script paths. The explicit
REM probes above must therefore be exhausted first.
where bash >nul 2>nul
if %ERRORLEVEL% equ 0 (
bash "%HOOK_DIR%%~1" %2 %3 %4 %5 %6 %7 %8 %9
exit /b %ERRORLEVEL%
)
REM No bash found - exit silently rather than error
REM (plugin still works, just without SessionStart context injection)
exit /b 0
Add Windows support for plugin hooks (#134) * feat: Add Windows support for session-start hook - Create polyglot session-start.cmd that works in both CMD and bash - Update hooks.json to use the .cmd polyglot launcher - Replace sed/awk with pure bash for JSON escaping (Windows compatibility) The polyglot script uses a heredoc trick: - CMD sees the @echo off block and runs bash.exe with cygpath conversion - Bash sees a heredoc and skips to the Unix section 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Add execute permission to session-start.cmd for Unix 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: Add comprehensive polyglot hooks documentation - Add docs/windows/polyglot-hooks.md explaining the cross-platform technique - Add reusable run-hook.cmd wrapper for parameterized hook execution - Document how the polyglot works in CMD vs bash - Include troubleshooting section and related GitHub issues 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * test: Add polyglot hook test script for macOS/Linux Run ./test-polyglot.sh from repo root to verify: - Required files exist with execute permissions - Simple wrapper (session-start.cmd) produces valid JSON - Parameterized wrapper (run-hook.cmd) works - Heredoc correctly skips CMD block on Unix 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Use direct pipe to jq in test to avoid variable escaping issues 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: Use single reusable run-hook.cmd for all hooks - Remove session-start.cmd in favor of run-hook.cmd - Update hooks.json to use: run-hook.cmd session-start.sh - Simplify test script to only test run-hook.cmd This makes it easy to add more hooks - just create the .sh file and add a line to hooks.json pointing to run-hook.cmd with the script name. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Simplify run-hook.cmd CMD block Pass path directly to bash instead of using cygpath in a subshell. The complex quoting was causing issues on Windows. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * chore: Remove test-polyglot.sh Testing complete - polyglot hooks work on Windows and macOS. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
2025-12-01 15:42:12 -08:00
CMDBLOCK
# Unix: run the named script directly
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
Add Windows support for plugin hooks (#134) * feat: Add Windows support for session-start hook - Create polyglot session-start.cmd that works in both CMD and bash - Update hooks.json to use the .cmd polyglot launcher - Replace sed/awk with pure bash for JSON escaping (Windows compatibility) The polyglot script uses a heredoc trick: - CMD sees the @echo off block and runs bash.exe with cygpath conversion - Bash sees a heredoc and skips to the Unix section 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Add execute permission to session-start.cmd for Unix 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: Add comprehensive polyglot hooks documentation - Add docs/windows/polyglot-hooks.md explaining the cross-platform technique - Add reusable run-hook.cmd wrapper for parameterized hook execution - Document how the polyglot works in CMD vs bash - Include troubleshooting section and related GitHub issues 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * test: Add polyglot hook test script for macOS/Linux Run ./test-polyglot.sh from repo root to verify: - Required files exist with execute permissions - Simple wrapper (session-start.cmd) produces valid JSON - Parameterized wrapper (run-hook.cmd) works - Heredoc correctly skips CMD block on Unix 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Use direct pipe to jq in test to avoid variable escaping issues 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: Use single reusable run-hook.cmd for all hooks - Remove session-start.cmd in favor of run-hook.cmd - Update hooks.json to use: run-hook.cmd session-start.sh - Simplify test script to only test run-hook.cmd This makes it easy to add more hooks - just create the .sh file and add a line to hooks.json pointing to run-hook.cmd with the script name. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Simplify run-hook.cmd CMD block Pass path directly to bash instead of using cygpath in a subshell. The complex quoting was causing issues on Windows. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * chore: Remove test-polyglot.sh Testing complete - polyglot hooks work on Windows and macOS. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
2025-12-01 15:42:12 -08:00
SCRIPT_NAME="$1"
shift
exec bash "${SCRIPT_DIR}/${SCRIPT_NAME}" "$@"