fix(hooks): Node.js SessionStart hook for Windows compatibility#475
fix(hooks): Node.js SessionStart hook for Windows compatibility#475wombatfish wants to merge 2 commits intoobra:mainfrom
Conversation
…ompatibility
Claude Code strips backslashes from ${CLAUDE_PLUGIN_ROOT} during template
substitution, producing forward-slash paths like C:/Users/dave/.claude/...
This is valid for Node.js but breaks bash (interprets as escape sequences).
By switching from session-start.sh to session-start.js, the hook works on
all platforms without requiring an upstream Claude Code fix. The script uses
path.resolve(__dirname, '..') as fallback if CLAUDE_PLUGIN_ROOT is missing
or mangled.
Fixes obra#420, obra#414, obra#417, obra#354, obra#440, obra#466
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
📝 WalkthroughWalkthroughReplaces the SessionStart hook shell invocation with a Node.js script that reads SKILL.md, checks for a legacy skills directory, builds an HTML-wrapped additionalContext (including warnings), and writes a JSON hook payload to stdout. Changes
Sequence Diagram(s)sequenceDiagram
participant Claude as Claude Host
participant Node as node (session-start.js)
participant FS as Filesystem
Claude->>Node: spawn node session-start.js (hook)
Node->>FS: stat(...) check legacy skills dir
FS-->>Node: exists / not found
Node->>FS: read SKILL.md
FS-->>Node: file contents / error
Node->>Claude: stdout JSON {hookEventName, additionalContext, ...}
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 6✅ Passed checks (6 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
No actionable comments were generated in the recent review. 🎉 Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@hooks/hooks.json`:
- Line 9: The command string "node ${CLAUDE_PLUGIN_ROOT}/hooks/session-start.js"
can break when CLAUDE_PLUGIN_ROOT expands to a path with spaces; update the
command to quote the expanded path so the shell treats it as a single argument,
e.g. change the JSON value to use quotes around the variable like "node
'${CLAUDE_PLUGIN_ROOT}/hooks/session-start.js'"; ensure you update the same
command entry in hooks.json so all similar hook commands use quoted
${CLAUDE_PLUGIN_ROOT}.
In `@hooks/session-start.js`:
- Line 12: The current construction of legacyDir using
path.join(process.env.HOME || process.env.USERPROFILE || '', ...) can produce a
relative path when both env vars are missing; change to first read a home
variable (e.g. const home = process.env.HOME || process.env.USERPROFILE) and
only compute legacyDir (const legacyDir = path.join(home, '.config',
'superpowers', 'skills')) when home is truthy, otherwise leave legacyDir
undefined or skip the legacy stat/lookup; update any subsequent checks (the
statSync/exists check that references legacyDir) to guard for legacyDir being
defined before calling fs.statSync so you never accidentally match a relative
path.
…ames Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
session-start.shwithsession-start.js— eliminates bash dependency on Windowshooks.jsonto invokenodeinstead of relying on Claude Code's.shauto-detectionWhy this works
Claude Code strips backslashes from
${CLAUDE_PLUGIN_ROOT}during template substitution, producing forward-slash paths likeC:/Users/dave/.claude/....This is the root cause behind #420, #414, #417, #354, #440, and #466 — but it's only a problem for bash, which interprets forward-slash paths and unescaped characters differently. Node.js handles forward-slash paths natively on Windows. No upstream Claude Code fix required.
The previous attempt (#421) was closed because it still relied on bash with path normalization. This PR eliminates bash entirely.
Fallback
The script uses
path.resolve(__dirname, '..')as fallback whenCLAUDE_PLUGIN_ROOTis missing or mangled, so it works even if template substitution is completely broken.What changed
hooks/session-start.jssession-start.sh— reads SKILL.md, checks legacy dir, outputs JSONhooks/hooks.json.shpath tonode ... .jssession-start.shis preserved for Linux/macOS users who may reference it directly.Testing
Tested on Windows 11 (MSYS2/Git Bash environment) with Claude Code 2.1.x. The hook produces valid JSON and the SessionStart context injection works correctly — confirmed by 4 consecutive "startup hook success" messages across session restarts.
Fixes
Closes #420, #414, #417, #354, #440, #466
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Chores