session-start 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. #!/usr/bin/env bash
  2. # SessionStart hook for superpowers plugin
  3. set -euo pipefail
  4. # Determine plugin root directory
  5. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
  6. PLUGIN_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
  7. # Check if legacy skills directory exists and build warning
  8. warning_message=""
  9. legacy_skills_dir="${HOME}/.config/superpowers/skills"
  10. if [ -d "$legacy_skills_dir" ]; then
  11. 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>"
  12. fi
  13. # Read using-superpowers content
  14. using_superpowers_content=$(cat "${PLUGIN_ROOT}/skills/using-superpowers/SKILL.md" 2>&1 || echo "Error reading using-superpowers skill")
  15. # Escape string for JSON embedding using bash parameter substitution.
  16. # Each ${s//old/new} is a single C-level pass - orders of magnitude
  17. # faster than the character-by-character loop this replaces.
  18. escape_for_json() {
  19. local s="$1"
  20. s="${s//\\/\\\\}"
  21. s="${s//\"/\\\"}"
  22. s="${s//$'\n'/\\n}"
  23. s="${s//$'\r'/\\r}"
  24. s="${s//$'\t'/\\t}"
  25. printf '%s' "$s"
  26. }
  27. using_superpowers_escaped=$(escape_for_json "$using_superpowers_content")
  28. warning_escaped=$(escape_for_json "$warning_message")
  29. 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>"
  30. # Output context injection as JSON.
  31. # Cursor hooks expect additional_context.
  32. # Claude Code hooks expect hookSpecificOutput.additionalContext.
  33. # Claude Code reads BOTH fields without deduplication, so we must only
  34. # emit the field consumed by the current platform to avoid double injection.
  35. if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ]; then
  36. # Claude Code sets CLAUDE_PLUGIN_ROOT — emit only hookSpecificOutput
  37. cat <<EOF
  38. {
  39. "hookSpecificOutput": {
  40. "hookEventName": "SessionStart",
  41. "additionalContext": "${session_context}"
  42. }
  43. }
  44. EOF
  45. else
  46. # Other platforms (Cursor, etc.) — emit only additional_context
  47. cat <<EOF
  48. {
  49. "additional_context": "${session_context}"
  50. }
  51. EOF
  52. fi
  53. exit 0