| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657 |
- #!/usr/bin/env bash
- # SessionStart hook for superpowers plugin
- set -euo pipefail
- # Determine plugin root directory
- SCRIPT_DIR="$(cd "$(dirname "$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")
- # Escape string for JSON embedding using bash parameter substitution.
- # Each ${s//old/new} is a single C-level pass - orders of magnitude
- # faster than the character-by-character loop this replaces.
- escape_for_json() {
- local s="$1"
- s="${s//\\/\\\\}"
- s="${s//\"/\\\"}"
- s="${s//$'\n'/\\n}"
- s="${s//$'\r'/\\r}"
- s="${s//$'\t'/\\t}"
- printf '%s' "$s"
- }
- using_superpowers_escaped=$(escape_for_json "$using_superpowers_content")
- warning_escaped=$(escape_for_json "$warning_message")
- session_context="<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${using_superpowers_escaped}\n\n${warning_escaped}\n</EXTREMELY_IMPORTANT>"
- # Output context injection as JSON.
- # Cursor hooks expect additional_context.
- # Claude Code hooks expect hookSpecificOutput.additionalContext.
- # Claude Code reads BOTH fields without deduplication, so we must only
- # emit the field consumed by the current platform to avoid double injection.
- #
- # Uses printf instead of heredoc (cat <<EOF) to work around a bash 5.3+
- # bug where heredoc variable expansion hangs when content exceeds ~512 bytes.
- # See: https://github.com/obra/superpowers/issues/571
- if [ -n "${CURSOR_PLUGIN_ROOT:-}" ]; then
- # Cursor sets CURSOR_PLUGIN_ROOT (may also set CLAUDE_PLUGIN_ROOT) — emit additional_context
- printf '{\n "additional_context": "%s"\n}\n' "$session_context"
- elif [ -n "${CLAUDE_PLUGIN_ROOT:-}" ]; then
- # Claude Code sets CLAUDE_PLUGIN_ROOT — emit only hookSpecificOutput
- printf '{\n "hookSpecificOutput": {\n "hookEventName": "SessionStart",\n "additionalContext": "%s"\n }\n}\n' "$session_context"
- else
- # Other platforms — emit additional_context as fallback
- printf '{\n "additional_context": "%s"\n}\n' "$session_context"
- fi
- exit 0
|