session-start 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  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 "$0")" && pwd)"
  6. PLUGIN_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
  7. # Read using-superpowers content
  8. using_superpowers_content=$(cat "${PLUGIN_ROOT}/skills/using-superpowers/SKILL.md" 2>&1 || echo "Error reading using-superpowers skill")
  9. # Escape string for JSON embedding using bash parameter substitution.
  10. # Each ${s//old/new} is a single C-level pass - orders of magnitude
  11. # faster than the character-by-character loop this replaces.
  12. escape_for_json() {
  13. local s="$1"
  14. s="${s//\\/\\\\}"
  15. s="${s//\"/\\\"}"
  16. s="${s//$'\n'/\\n}"
  17. s="${s//$'\r'/\\r}"
  18. s="${s//$'\t'/\\t}"
  19. printf '%s' "$s"
  20. }
  21. using_superpowers_escaped=$(escape_for_json "$using_superpowers_content")
  22. 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</EXTREMELY_IMPORTANT>"
  23. # Output context injection as JSON.
  24. # Cursor hooks expect additional_context (snake_case).
  25. # Claude Code hooks expect hookSpecificOutput.additionalContext (nested).
  26. # Copilot CLI (v1.0.11+) and others expect additionalContext (top-level, SDK standard).
  27. # Claude Code reads BOTH additional_context and hookSpecificOutput without
  28. # deduplication, so we must emit only the field the current platform consumes.
  29. #
  30. # Uses printf instead of heredoc to work around bash 5.3+ heredoc hang.
  31. # See: https://github.com/obra/superpowers/issues/571
  32. if [ -n "${CURSOR_PLUGIN_ROOT:-}" ]; then
  33. # Cursor sets CURSOR_PLUGIN_ROOT (may also set CLAUDE_PLUGIN_ROOT)
  34. printf '{\n "additional_context": "%s"\n}\n' "$session_context"
  35. elif [ -n "${CLAUDE_PLUGIN_ROOT:-}" ] && [ -z "${COPILOT_CLI:-}" ]; then
  36. # Claude Code sets CLAUDE_PLUGIN_ROOT without COPILOT_CLI
  37. printf '{\n "hookSpecificOutput": {\n "hookEventName": "SessionStart",\n "additionalContext": "%s"\n }\n}\n' "$session_context"
  38. else
  39. # Copilot CLI (sets COPILOT_CLI=1) or unknown platform — SDK standard format
  40. printf '{\n "additionalContext": "%s"\n}\n' "$session_context"
  41. fi
  42. exit 0