0
Fork 0
mirror of https://github.com/obra/superpowers.git synced 2026-09-25 22:09:05 +00:00

SessionStart hook fails on Windows — bash cannot resolve ${CLAUDE_PLUGIN_ROOT} path #389

Closed
opened 2026-01-30 22:32:05 +00:00 by Turum · 1 comment
Turum commented 2026-01-30 22:32:05 +00:00 (Migrated from github.com)

Bug

The SessionStart hook fails on Windows with:

/bin/bash: C:UsersAlexanderMelnikov.claudepluginscacheclaude-plugins-officialsuperpowers4.1.1/hooks/session-start.sh: No such file or directory

Environment

  • OS: Windows 11
  • Claude Code: v2.1.27
  • Shell: Git Bash (C:\Program Files\Git\bin\bash.exe)
  • Superpowers: v4.1.1

Root cause

In hooks/hooks.json, the command is:

"command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh"                                                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                                                                                
On Windows, CLAUDE_PLUGIN_ROOT expands to a path with backslashes (e.g. C:\Users\...). When Claude Code passes this to Git Bash, the backslashes are stripped, producing an invalid path: C:Users... instead of C:\Users\....                                                                                                                   
                                                                                                                                                                                                                                                                                                                                                
Suggested fix                                                                                                                                                                                                                                                                                                                                   
                                                                                                                                                                                                                                                                                                                                                
Replace the bash script with a Node.js equivalent (same approach used by everything-claude-code plugin, which works fine on Windows). Change hooks.json to:                                                                                                                                                                                     
                                                                                                                                                                                                                                                                                                                                                
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/session-start.js\""                                                                                                                                                                                                                                                                              
                                                                                                                                                                                                                                                                                                                                                
And add a session-start.js that replicates the logic of session-start.sh — Node's path module handles Windows paths correctly:                                                                                                                                                                                                                  
                                                                                                                                                                                                                                                                                                                                                
const fs = require("fs");                                                                                                                                                                                                                                                                                                                       
const path = require("path");                                                                                                                                                                                                                                                                                                                   
const os = require("os");                                                                                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                                                                                
const PLUGIN_ROOT = path.resolve(__dirname, "..");                                                                                                                                                                                                                                                                                              
                                                                                                                                                                                                                                                                                                                                                
let warningMessage = "";                                                                                                                                                                                                                                                                                                                        
const legacySkillsDir = path.join(os.homedir(), ".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>";                                                                                                                                                                                                                                                   
}                                                                                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                                                                                
let skillContent;                                                                                                                                                                                                                                                                                                                               
try {                                                                                                                                                                                                                                                                                                                                           
  skillContent = fs.readFileSync(                                                                                                                                                                                                                                                                                                               
    path.join(PLUGIN_ROOT, "skills", "using-superpowers", "SKILL.md"),                                                                                                                                                                                                                                                                          
    "utf8"                                                                                                                                                                                                                                                                                                                                      
  );                                                                                                                                                                                                                                                                                                                                            
} catch (e) {                                                                                                                                                                                                                                                                                                                                   
  skillContent = "Error reading using-superpowers skill: " + e.message;                                                                                                                                                                                                                                                                         
}                                                                                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                                                                                
const output = {                                                                                                                                                                                                                                                                                                                                
  hookSpecificOutput: {                                                                                                                                                                                                                                                                                                                         
    hookEventName: "SessionStart",                                                                                                                                                                                                                                                                                                              
    additionalContext:                                                                                                                                                                                                                                                                                                                          
      "<EXTREMELY_IMPORTANT>\nYou have superpowers.\n\n" +                                                                                                                                                                                                                                                                                      
      "**Below is the full content of your 'superpowers:using-superpowers' skill - " +                                                                                                                                                                                                                                                          
      "your introduction to using skills. For all other skills, use the 'Skill' tool:**\n\n" +                                                                                                                                                                                                                                                  
      skillContent +                                                                                                                                                                                                                                                                                                                            
      "\n\n" +                                                                                                                                                                                                                                                                                                                                  
      warningMessage +                                                                                                                                                                                                                                                                                                                          
      "\n</EXTREMELY_IMPORTANT>",                                                                                                                                                                                                                                                                                                               
  },                                                                                                                                                                                                                                                                                                                                            
};                                                                                                                                                                                                                                                                                                                                              
                                                                                                                                                                                                                                                                                                                                                
process.stdout.write(JSON.stringify(output, null, 2));                                                                                                                                                                                                                                                                                          
                                                                                                                                                                                                                                                                                                                                                
Workaround                                                                                                                                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                                                                                                
Manually create hooks/session-start.js in the cached plugin directory and update hooks.json to call node instead of .sh. This works until the next plugin update overwrites the cache. 
## Bug The `SessionStart` hook fails on Windows with: /bin/bash: C:UsersAlexanderMelnikov.claudepluginscacheclaude-plugins-officialsuperpowers4.1.1/hooks/session-start.sh: No such file or directory ## Environment - OS: Windows 11 - Claude Code: v2.1.27 - Shell: Git Bash (`C:\Program Files\Git\bin\bash.exe`) - Superpowers: v4.1.1 ## Root cause In `hooks/hooks.json`, the command is: ```json "command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh" On Windows, CLAUDE_PLUGIN_ROOT expands to a path with backslashes (e.g. C:\Users\...). When Claude Code passes this to Git Bash, the backslashes are stripped, producing an invalid path: C:Users... instead of C:\Users\.... Suggested fix Replace the bash script with a Node.js equivalent (same approach used by everything-claude-code plugin, which works fine on Windows). Change hooks.json to: "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/session-start.js\"" And add a session-start.js that replicates the logic of session-start.sh — Node's path module handles Windows paths correctly: const fs = require("fs"); const path = require("path"); const os = require("os"); const PLUGIN_ROOT = path.resolve(__dirname, ".."); let warningMessage = ""; const legacySkillsDir = path.join(os.homedir(), ".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>"; } let skillContent; try { skillContent = fs.readFileSync( path.join(PLUGIN_ROOT, "skills", "using-superpowers", "SKILL.md"), "utf8" ); } catch (e) { skillContent = "Error reading using-superpowers skill: " + e.message; } const output = { hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: "<EXTREMELY_IMPORTANT>\nYou have superpowers.\n\n" + "**Below is the full content of your 'superpowers:using-superpowers' skill - " + "your introduction to using skills. For all other skills, use the 'Skill' tool:**\n\n" + skillContent + "\n\n" + warningMessage + "\n</EXTREMELY_IMPORTANT>", }, }; process.stdout.write(JSON.stringify(output, null, 2)); Workaround Manually create hooks/session-start.js in the cached plugin directory and update hooks.json to call node instead of .sh. This works until the next plugin update overwrites the cache.
Boysiee commented 2026-02-04 10:15:12 +00:00 (Migrated from github.com)

Found a fix that works for me.

The issue is Windows using WSL bash instead of Git Bash. WSL can't handle the Windows paths that Claude Code passes.

Fix:

  1. Create hooks/session-start.cmd:
    @echo off
    "C:\Program Files\Git\bin\bash.exe" "%~dp0session-start.sh"

  2. Change hooks/hooks.json to point to the .cmd instead:
    "command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.cmd"

The .cmd runs natively on Windows and calls Git Bash directly, bypassing the WSL issue.

Found a fix that works for me. The issue is Windows using WSL bash instead of Git Bash. WSL can't handle the Windows paths that Claude Code passes. Fix: 1. Create hooks/session-start.cmd: @echo off "C:\Program Files\Git\bin\bash.exe" "%~dp0session-start.sh" 2. Change hooks/hooks.json to point to the .cmd instead: "command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.cmd" The .cmd runs natively on Windows and calls Git Bash directly, bypassing the WSL issue.
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
skills/obra-superpowers#389
No description provided.