Skip to content

fix(hooks): use SCRIPT_NAME variable in run-hook.cmd to avoid arg-par…#1175

Open
ZakAnun wants to merge 1 commit into
obra:mainfrom
ZakAnun:fix/1142-sessionstart-space-path
Open

fix(hooks): use SCRIPT_NAME variable in run-hook.cmd to avoid arg-par…#1175
ZakAnun wants to merge 1 commit into
obra:mainfrom
ZakAnun:fix/1142-sessionstart-space-path

Conversation

@ZakAnun
Copy link
Copy Markdown

@ZakAnun ZakAnun commented Apr 15, 2026

Fixes #1142.

What problem are you trying to solve?

On Windows systems where the user profile path contains spaces (e.g. C:\Users\Artur Sebesta\...), the SessionStart hook silently fails to execute. Inside run-hook.cmd, the bash invocation is constructed as "%HOOK_DIR%%~1" where %HOOK_DIR% (set from %~dp0) already contains the spaced path. The inline %~1 expansion adjacent to %HOOK_DIR% inside the quoted string causes the Windows CMD parser to misinterpret the boundary, resulting in bash receiving a truncated path such as /c/Users/Artur and failing to find the script. Superpowers bootstrap context is never injected at session start. This is a real startup failure experienced by users with spaces in their Windows username — not a theoretical concern.

What does this PR change?

In the Windows CMD branch of hooks/run-hook.cmd:

  • Adds setlocal to isolate HOOK_DIR and SCRIPT_NAME from the calling environment
  • Captures %~1 into SCRIPT_NAME before constructing the bash invocation, so "%HOOK_DIR%%SCRIPT_NAME%" is assembled from two stable, separately-expanded variables rather than mixing %HOOK_DIR% with an inline %~1 inside the same quoted string
  • Keeps %2..%9 without shift to correctly forward extra arguments — using %* after shift was considered and rejected because %* does not update after shift in Windows CMD, which would re-inject the script name as a spurious $1 into every target script

Adds regression tests under tests/hooks/:

  • tests/hooks/test-run-hook-wrapper.sh — verifies hooks.json routing, absence of %* in the CMD branch, and the Unix polyglot branch end-to-end with a spaced directory path and spaced arguments
  • tests/hooks/fixtures/check-args — fixture asserting exactly two specific argument values are received
  • tests/hooks/fixtures/check-no-args — fixture asserting no extra arguments are injected when run-hook.cmd is called with only a script name (simulates the real session-start invocation)

Is this change appropriate for the core library?

Yes. run-hook.cmd is the core hook entry point for all Superpowers users on Windows (cmd.exe, PowerShell, WSL). Spaces in a Windows username is a common real-world configuration. This fix improves baseline plugin startup reliability for all affected users without touching any skill content or adding any dependency.

What alternatives did you consider?

  1. Call bash directly in hooks/hooks.json — this was the approach taken in PR fix(hooks): avoid SessionStart path split on Windows with spaced user… #1158. The maintainer closed it with the explicit comment that run-hook.cmd must remain in the call chain because it does essential heavy lifting for Windows cmd.exe, PowerShell, and WSL. This approach is a non-starter.

  2. Use %* after shift — capture the script name first, shift, then use %* for remaining args. Discarded because in Windows CMD, %* always expands to the original full argument list and does not update after shift. This would re-inject the script name as a spurious $1 into every target script.

  3. Current approach (chosen) — keep run-hook.cmd fully intact, fix only the variable expansion in the bash invocation. Minimal and targeted, retains all existing wrapper functionality.

Does this PR contain multiple unrelated changes?

No. One bug, one fix, plus regression tests for that fix. All changes are directly related to the Windows spaced-path hook failure.

Existing PRs

PR #1158 addressed the same issue (#1142) but by bypassing run-hook.cmd entirely — calling bash directly from hooks.json. The maintainer closed it because run-hook.cmd must stay in the call chain. This PR takes the opposite approach: keep run-hook.cmd as the entry point and fix the argument expansion inside it. The two approaches are mutually exclusive; this one respects the maintainer's stated constraint.

Environment tested

Harness Harness version Model Model version/ID
Claude Code

CI run (windows-latest + ubuntu-latest, both green):
https://github.com/ZakAnun/superpowers/actions/runs/24438382711

Evaluation

  • Initial prompt: reproduce and fix issue SessionStart hook fails on Windows when username contains spaces #1142 — SessionStart hook fails on Windows when username contains spaces
  • Eval sessions after change: 3 CI runs on GitHub Actions windows-latest with a hooks directory path containing spaces, testing spaced argument forwarding and the no-extra-args invariant
  • Before: run-hook.cmd invoked bash with a truncated path, hook silently failed. After: bash receives the fully quoted path and executes correctly; check-no-args fixture confirms the script name is not re-injected as a spurious argument

Rigor

  • If this is a skills change: N/A — this is a hook infrastructure fix, not a skills change
  • This change was tested adversarially: spaced directory path, spaced arguments, no-argument call (real SessionStart pattern), and static check that %* is absent from the CMD branch
  • I did not modify any behavior-shaping skill content

Human review

  • A human has reviewed the COMPLETE proposed diff before submission

…sing edge cases

Fixes obra#1142.

On Windows with a user profile path containing spaces (e.g.
C:\Users\Artur Sebesta\...), the SessionStart hook can fail to invoke
the target script correctly because of how the Windows CMD argument
parser expands %~1 when HOOK_DIR also contains spaces.

Changes:
- Add `setlocal` to isolate HOOK_DIR/SCRIPT_NAME from the calling
  environment
- Capture %~1 into SCRIPT_NAME before constructing the bash invocation,
  so the quoted path "%HOOK_DIR%%SCRIPT_NAME%" is assembled from two
  stable, separately-expanded variables rather than an inline %~1
  substitution that can interact with surrounding quotes unexpectedly
- Keep %2..%9 (no shift) to forward extra arguments without injecting
  the script name as a spurious extra positional argument — a regression
  that was introduced by an earlier attempted fix using %* after shift

Add tests:
- tests/hooks/test-run-hook-wrapper.sh: verifies hooks.json routing,
  absence of %* in the CMD branch, and the Unix polyglot branch
  end-to-end with a spaced directory path and spaced arguments
- tests/hooks/fixtures/check-args: fixture that asserts exactly two
  specific argument values are received
- tests/hooks/fixtures/check-no-args: fixture that asserts no extra
  arguments are injected when run-hook.cmd is called with only a
  script name (simulates the real SessionStart invocation)

CI evidence (windows-latest + ubuntu-latest, all green):
https://github.com/ZakAnun/superpowers/actions/runs/24438382711

Made-with: Cursor
@obra
Copy link
Copy Markdown
Owner

obra commented Apr 15, 2026

Ooh! Thank you so much. As a not-windows person, I'm not always up on the right way to do things. We'll run this through a bit of local testing, but assuming it checks out, I'm +1 to merge.

@ZakAnun
Copy link
Copy Markdown
Author

ZakAnun commented Apr 16, 2026

Ooh! Thank you so much. As a not-windows person, I'm not always up on the right way to do things. We'll run this through a bit of local testing, but assuming it checks out, I'm +1 to merge.

Thank you for your affirmation. I would be honored if I could help with this project.

@obra obra added hooks Hook system (SessionStart, Stop, etc.) windows labels Apr 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

hooks Hook system (SessionStart, Stop, etc.) windows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SessionStart hook fails on Windows when username contains spaces

2 participants