Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion hooks/hooks.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh"
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/session-start.js\""
}
Comment on lines 8 to 10
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.

]
}
Expand Down
50 changes: 50 additions & 0 deletions hooks/session-start.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/usr/bin/env node
/**
* SessionStart hook for superpowers plugin
*
* Cross-platform wrapper (Windows, macOS, Linux) that handles:
* - Windows path backslash issues when CLAUDE_PLUGIN_ROOT is passed to bash
* - Git Bash shebang stdout suppression issue on Windows
*
* See: https://github.com/obra/superpowers/issues/354
*/

const fs = require('fs');
const path = require('path');

// Determine plugin root from this script's location
const SCRIPT_DIR = __dirname;
const PLUGIN_ROOT = path.dirname(SCRIPT_DIR);

// Check if legacy skills directory exists
let warningMessage = '';
const legacySkillsDir = path.join(process.env.HOME || process.env.USERPROFILE || '', '.config', 'superpowers', 'skills');
if (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>';
}

// Read using-superpowers skill content
const skillPath = path.join(PLUGIN_ROOT, 'skills', 'using-superpowers', 'SKILL.md');
let usingSuperpowersContent = '';
try {
usingSuperpowersContent = fs.readFileSync(skillPath, 'utf8');
} catch (err) {
usingSuperpowersContent = 'Error reading using-superpowers skill: ' + err.message;
}

// Output JSON for Claude Code hook system
const output = {
hookSpecificOutput: {
hookEventName: 'SessionStart',
additionalContext: `<EXTREMELY_IMPORTANT>
You have superpowers.

**Below is the full content of your 'superpowers:using-superpowers' skill - your introduction to using skills. For all other skills, use the 'Skill' tool:**

${usingSuperpowersContent}
${warningMessage}
</EXTREMELY_IMPORTANT>`
}
};

console.log(JSON.stringify(output, null, 2));