Skip to content
Closed
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": "\"${CLAUDE_PLUGIN_ROOT}/hooks/session-start.cmd\""
}
]
}
Expand Down
63 changes: 63 additions & 0 deletions hooks/session-start.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
:<<"::CMDLITERAL"
@ECHO OFF
GOTO :CMDSCRIPT
::CMDLITERAL

# ==============================================================================
# Bash/sh section - runs on Unix/Linux/macOS
# ==============================================================================

set -euo pipefail

# Determine plugin root directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
PLUGIN_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"

# Check if legacy skills directory exists and build warning
warning_message=""
legacy_skills_dir="${HOME}/.config/superpowers/skills"
if [ -d "$legacy_skills_dir" ]; then
warning_message="\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>"
fi

# Read using-superpowers content
using_superpowers_content=$(cat "${PLUGIN_ROOT}/skills/using-superpowers/SKILL.md" 2>&1 || echo "Error reading using-superpowers skill")
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

Fix error output handling.

The 2>&1 redirect sends error messages into $using_superpowers_content, polluting it with error text like "cat: file: No such file or directory" before the fallback message. This would appear in the JSON output.

-using_superpowers_content=$(cat "${PLUGIN_ROOT}/skills/using-superpowers/SKILL.md" 2>&1 || echo "Error reading using-superpowers skill")
+using_superpowers_content=$(cat "${PLUGIN_ROOT}/skills/using-superpowers/SKILL.md" 2>/dev/null || echo "Error reading using-superpowers skill")
📝 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
using_superpowers_content=$(cat "${PLUGIN_ROOT}/skills/using-superpowers/SKILL.md" 2>&1 || echo "Error reading using-superpowers skill")
using_superpowers_content=$(cat "${PLUGIN_ROOT}/skills/using-superpowers/SKILL.md" 2>/dev/null || echo "Error reading using-superpowers skill")
🤖 Prompt for AI Agents
In hooks/session-start.cmd around line 24, the command captures stderr into the
using_superpowers_content variable (via 2>&1), which pollutes the content with
cat error messages; change the logic to avoid redirecting stderr into the
variable by either checking the file exists/readable before reading and falling
back, or redirect only stderr to /dev/null during the cat and capture a shell
conditional result so the fallback string is used on failure; ensure any errors
are logged separately (to stderr or a log) rather than being mixed into
using_superpowers_content.


# Escape outputs for JSON
using_superpowers_escaped=$(echo "$using_superpowers_content" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | awk '{printf "%s\\n", $0}')
warning_escaped=$(echo "$warning_message" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | awk '{printf "%s\\n", $0}')
Comment on lines +27 to +28
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

JSON escaping is insufficient and risks invalid output.

The manual escaping only handles backslashes and quotes, missing critical JSON special characters:

  • Control characters: tabs (\t), carriage returns (\r), form feeds, etc.
  • The SKILL.md may contain any of these, especially if it has Windows line endings

This creates a critical cross-platform inconsistency: the Windows path uses ConvertTo-Json (line 61) which properly escapes all special characters, while bash uses incomplete manual escaping.

Consider using jq for robust JSON generation:

-# Escape outputs for JSON
-using_superpowers_escaped=$(echo "$using_superpowers_content" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | awk '{printf "%s\\n", $0}')
-warning_escaped=$(echo "$warning_message" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | awk '{printf "%s\\n", $0}')
-
-# Output context injection as JSON
-cat <<EOF
-{
-  "hookSpecificOutput": {
-    "hookEventName": "SessionStart",
-    "additionalContext": "<EXTREMELY_IMPORTANT>\nYou have superpowers.\n\n**The content below is from skills/using-superpowers/SKILL.md - your introduction to using skills:**\n\n${using_superpowers_escaped}\n\n${warning_escaped}\n</EXTREMELY_IMPORTANT>"
-  }
-}
-EOF
+# Build additionalContext with proper newline handling
+additional_context="<EXTREMELY_IMPORTANT>\nYou have superpowers.\n\n**The content below is from skills/using-superpowers/SKILL.md - your introduction to using skills:**\n\n${using_superpowers_content}\n\n${warning_message}\n</EXTREMELY_IMPORTANT>"
+
+# Output context injection as JSON using jq for proper escaping
+jq -n --arg ctx "$additional_context" '{
+  hookSpecificOutput: {
+    hookEventName: "SessionStart",
+    additionalContext: $ctx
+  }
+}'

If jq is not available in the execution environment, verify this and document the risk of invalid JSON.


🏁 Script executed:

#!/bin/bash
# Check if jq is mentioned elsewhere in the codebase or if it's an available dependency
rg -i '\bjq\b' --type sh --type json --type md

Length of output: 0


I need to gather more information about the codebase environment and the actual implementation. Let me search for dependency files and examine the actual file structure.




---

🏁 Script executed:

```shell
#!/bin/bash
# Search for dependency/configuration files that might list jq as a dependency
fd -e 'package.json' -e 'Gemfile' -e 'requirements.txt' -e 'Dockerfile' -e 'docker-compose.yml' -e '.tool-versions' -e 'brew' | head -20

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check the actual hooks/session-start.cmd file to understand context
cat hooks/session-start.cmd 2>/dev/null || echo "File not found at that location"

Length of output: 3617


🏁 Script executed:

#!/bin/bash
# Search more broadly for jq in all configuration and script types
rg 'jq' --type sh --type json --type md --type yaml --type toml --type xml -i

Length of output: 0


Rewritten review comment:

JSON escaping is insufficient and creates invalid output with multi-line content.

The bash implementation (lines 27-28) only escapes backslashes and quotes, missing critical issues:

  • Actual newlines in SKILL.md content will appear as literal newlines in the JSON string value, rendering it invalid
  • Control characters (tabs, carriage returns, etc.) are unescaped
  • The Windows path uses ConvertTo-Json which properly handles all escaping—cross-platform inconsistency

The proposed jq solution cannot be verified as viable: jq is not listed anywhere in the codebase or its dependencies. Before implementing this approach, confirm jq is available in all target execution environments, or use an alternative approach:

Alternative 1: Use printf with proper escaping before JSON:

additional_context=$(printf '%s' "$using_superpowers_content" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | sed 's/$/\\n/' | tr -d '\n')

Alternative 2: Build the JSON structure using only variables and avoid heredoc substitution entirely.

Verify that the chosen solution produces valid JSON when SKILL.md contains newlines or special characters.

🤖 Prompt for AI Agents
In hooks/session-start.cmd around lines 27-28, the current sed/awk escaping only
handles backslashes and double quotes and fails to escape actual newlines and
control characters, producing invalid JSON for multi-line SKILL.md; replace this
with a robust escaping approach: either (A) use a portable printf-based pipeline
that escapes backslashes, quotes, control characters and converts newlines to \n
before embedding into JSON (as suggested in the review), or (B) avoid heredoc
substitution entirely and construct the JSON payload by assembling
properly-escaped variables; do NOT rely on jq unless you first verify it is
present in all target environments—if you choose jq, add a runtime check and
fallback—and add a unit/manual test that builds the JSON when SKILL.md contains
newlines, tabs, carriage returns, and Windows paths to ensure the output is
valid JSON.


# Output context injection as JSON
cat <<EOF
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "<EXTREMELY_IMPORTANT>\nYou have superpowers.\n\n**The content below is from skills/using-superpowers/SKILL.md - your introduction to using skills:**\n\n${using_superpowers_escaped}\n\n${warning_escaped}\n</EXTREMELY_IMPORTANT>"
}
}
EOF

exit 0

:CMDSCRIPT
REM ==============================================================================
REM Windows cmd.exe section - runs on Windows
REM ==============================================================================

SETLOCAL EnableDelayedExpansion

REM Determine plugin root directory
SET "SCRIPT_DIR=%~dp0"
SET "PLUGIN_ROOT=%SCRIPT_DIR%.."

REM Check if legacy skills directory exists and build warning
SET "warning_message="
SET "legacy_skills_dir=%USERPROFILE%\.config\superpowers\skills"
IF EXIST "%legacy_skills_dir%" (
SET "warning_message=\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>"
)

REM Call PowerShell to handle the JSON generation (it's much better at this)
powershell -NoProfile -ExecutionPolicy Bypass -Command "$scriptDir = '%SCRIPT_DIR%'; $pluginRoot = '%PLUGIN_ROOT%'; $warningMessage = '%warning_message%'; $skillFile = Join-Path $pluginRoot 'skills\using-superpowers\SKILL.md'; if (Test-Path $skillFile) { $skillContent = Get-Content -Path $skillFile -Raw -Encoding UTF8 } else { $skillContent = 'Error: using-superpowers skill file not found' }; $contextContent = '<EXTREMELY_IMPORTANT>\nYou have superpowers.\n\n**The content below is from skills/using-superpowers/SKILL.md - your introduction to using skills:**\n\n' + $skillContent + '\n\n' + $warningMessage + '\n</EXTREMELY_IMPORTANT>'; $output = @{ hookSpecificOutput = @{ hookEventName = 'SessionStart'; additionalContext = $contextContent } }; $output | ConvertTo-Json -Depth 10 -Compress:$false"

EXIT /B 0
34 changes: 0 additions & 34 deletions hooks/session-start.sh

This file was deleted.