Skip to content

Conversation

@sgeraldes
Copy link

@sgeraldes sgeraldes commented Jan 25, 2026

Summary

Fixes #354

The SessionStart hook was failing on Windows due to two distinct issues:

Issue 1: Path Mangling

When CLAUDE_PLUGIN_ROOT (containing Windows backslash paths like C:\Users\...) is passed through bash command execution, backslashes are interpreted as escape characters and stripped:

# What Claude Code does internally:
$ PLUGIN_ROOT='C:\Users\Sebastian\.claude\...'
$ bash -c "$PLUGIN_ROOT/hooks/session-start.sh"
bash: C:UsersSebastian.claude.../hooks/session-start.sh: No such file or directory

Issue 2: Shebang stdout suppression

Git Bash on Windows suppresses stdout when running scripts with shebang lines via bash script.sh:

$ bash session-start.sh        # → No output (shebang bug)
$ source session-start.sh      # → Works correctly

Solution

Replace the bash script with a Node.js equivalent that:

  • Uses __dirname for reliable cross-platform path resolution
  • Works identically on Windows, macOS, and Linux
  • Produces proper JSON output for the Claude Code hook system

The original session-start.sh is retained for reference and potential Unix-only use cases.

Test Plan

  • Tested on Windows 11 with Git Bash
  • Node.js script produces correct JSON output
  • Verified the hook loads the using-superpowers skill content correctly

Related Issues

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Users will now see helpful guidance if they have legacy custom skills configured, with clear instructions on migrating their settings to the new standardized location.
  • Chores

    • Enhanced the session initialization process with improved cross-platform compatibility and reliability across different operating systems.

✏️ Tip: You can customize this high-level summary in your review settings.

Fixes obra#354

The SessionStart hook was failing on Windows due to two issues:

1. Path mangling: When CLAUDE_PLUGIN_ROOT (containing Windows backslash
   paths) is passed through bash command execution, backslashes are
   interpreted as escape characters and stripped, resulting in invalid
   paths like "C:UsersSebastian.claude..." instead of
   "C:\Users\Sebastian\.claude..."

2. Shebang stdout suppression: Git Bash on Windows suppresses stdout
   when running scripts with shebang lines via `bash script.sh`,
   causing the hook to produce no output even when it executes
   successfully.

Solution: Replace the bash script with a Node.js equivalent that:
- Uses __dirname for reliable cross-platform path resolution
- Works identically on Windows, macOS, and Linux
- Produces proper JSON output for the Claude Code hook system

The original session-start.sh is retained for reference and potential
Unix-only use cases.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Jan 25, 2026

📝 Walkthrough

Walkthrough

The SessionStart hook execution method is converted from a shell script to a Node.js script. The hooks configuration is updated to invoke the JavaScript file instead of the bash script, providing cross-platform execution without shebang-related issues.

Changes

Cohort / File(s) Summary
Hook Configuration
hooks/hooks.json
Updated the session-start hook command from bash execution of .sh file to node execution of .js file, altering the runtime environment
Hook Implementation
hooks/session-start.js
New Node.js script that determines plugin root, checks for legacy skills directory, injects migration warnings if needed, reads the using-superpowers skill content, and outputs a structured JSON object with hook metadata and additional context to stdout

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related issues

Possibly related PRs

Poem

🐰 A bash script once struggled on Windows so fair,
But a Node.js hop through the hooks fills the air!
No shebangs to confuse, just clean output flow,
Cross-platform at last—watch the context now grow! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: replacing a bash hook with Node.js for cross-platform (Windows) support, which is the primary objective of the PR.
Linked Issues check ✅ Passed The PR directly addresses issue #354 by replacing the problematic bash SessionStart hook with a Node.js implementation that produces JSON output on Windows, resolving the stdout suppression and path mangling issues.
Out of Scope Changes check ✅ Passed All changes are in-scope: updating hooks.json to point to the new Node.js script and adding session-start.js as the cross-platform hook implementation, both directly related to fixing the Windows hook issue.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@hooks/hooks.json`:
- Around line 8-10: The command string in the hooks.json entry uses double
quotes around ${CLAUDE_PLUGIN_ROOT} which can allow word-splitting for paths
with spaces; update the "command" value so the expanded ${CLAUDE_PLUGIN_ROOT} is
wrapped in single quotes (preserving the existing escaped inner path to
hooks/session-start.js) so the shell treats the full path as a single
literal—look for the "command" key that references
"${CLAUDE_PLUGIN_ROOT}/hooks/session-start.js" and replace the surrounding
double quotes for the variable portion with single quotes.
🧹 Nitpick comments (1)
hooks/session-start.js (1)

20-22: Use os.homedir() to avoid empty/relative legacy path resolution.

If HOME/USERPROFILE is unset, the current code resolves to a relative .config/... path, which can cause false warnings or filesystem probes in the working directory. os.homedir() is the reliable cross‑platform source.

♻️ Suggested tweak
-const legacySkillsDir = path.join(process.env.HOME || process.env.USERPROFILE || '', '.config', 'superpowers', 'skills');
-if (fs.existsSync(legacySkillsDir)) {
+const homeDir = require('os').homedir();
+const legacySkillsDir = homeDir ? path.join(homeDir, '.config', 'superpowers', 'skills') : '';
+if (legacySkillsDir && fs.existsSync(legacySkillsDir)) {
     warningMessage = '\n\n<important-reminder>IN YOUR FIRST REPLY AFTER SEEING THIS MESSAGE YOU MUST TELL THE USER:⚠️ **WARNING:** Superpowers now uses Claude Code\'s skills system. Custom skills in ~/.config/superpowers/skills will not be read. Move custom skills to ~/.claude/skills instead. To make this message go away, remove ~/.config/superpowers/skills</important-reminder>';
 }

Comment on lines 8 to 10
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh"
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/session-start.js\""
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Check the repository structure and hooks.json file
git ls-files hooks/ 2>/dev/null | head -20

Repository: obra/superpowers

Length of output: 141


🏁 Script executed:

# Read the hooks.json file to see the current state
if [ -f "hooks/hooks.json" ]; then
  cat -n hooks/hooks.json
fi

Repository: obra/superpowers

Length of output: 443


🏁 Script executed:

# Check if this is a superpowers plugin repo
git ls-files | grep -E "(package\.json|README|superpowers)" | head -20

Repository: obra/superpowers

Length of output: 266


Use single quotes around ${CLAUDE_PLUGIN_ROOT} to prevent word splitting in paths with spaces.

Claude Code expands variables before passing the command to the shell, so single quotes preserve the expanded path as a literal string and prevent breaking on spaces. Double-quoted escaping does not provide the same protection.

✅ Suggested change
-            "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/session-start.js\""
+            "command": "node '${CLAUDE_PLUGIN_ROOT}/hooks/session-start.js'"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh"
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/session-start.js\""
}
"type": "command",
"command": "node '${CLAUDE_PLUGIN_ROOT}/hooks/session-start.js'"
}
🤖 Prompt for AI Agents
In `@hooks/hooks.json` around lines 8 - 10, The command string in the hooks.json
entry uses double quotes around ${CLAUDE_PLUGIN_ROOT} which can allow
word-splitting for paths with spaces; update the "command" value so the expanded
${CLAUDE_PLUGIN_ROOT} is wrapped in single quotes (preserving the existing
escaped inner path to hooks/session-start.js) so the shell treats the full path
as a single literal—look for the "command" key that references
"${CLAUDE_PLUGIN_ROOT}/hooks/session-start.js" and replace the surrounding
double quotes for the variable portion with single quotes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SessionStart hook produces no output on Windows (Git Bash shebang issue)

2 participants