session-start.sh 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. #!/usr/bin/env bash
  2. # SessionStart hook for OAC 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. SKILL_FILE="${PLUGIN_ROOT}/skills/using-oac/SKILL.md"
  8. # Read using-oac content
  9. using_oac_content=$(cat "${SKILL_FILE}" 2>&1 || echo "Error reading using-oac skill")
  10. # Escape string for JSON embedding
  11. # SECURITY: This function prevents command injection attacks from malicious SKILL.md files
  12. # Previous implementation was vulnerable to:
  13. # - $(command) injection via unescaped dollar signs
  14. # - `command` injection via unescaped backticks
  15. # - Control character injection
  16. #
  17. # We now escape ALL dangerous characters in the correct order:
  18. # 1. Backslashes FIRST (to avoid double-escaping)
  19. # 2. Double quotes (JSON string delimiter)
  20. # 3. Dollar signs (prevent variable expansion and $(cmd) injection)
  21. # 4. Backticks (prevent `cmd` command substitution)
  22. # 5. Newlines, carriage returns, tabs (JSON control characters)
  23. escape_for_json() {
  24. local s="$1"
  25. # Escape backslashes FIRST - order matters!
  26. s="${s//\\/\\\\}"
  27. # Escape double quotes
  28. s="${s//\"/\\\"}"
  29. # Escape newlines, carriage returns, tabs
  30. s="${s//$'\n'/\\n}"
  31. s="${s//$'\r'/\\r}"
  32. s="${s//$'\t'/\\t}"
  33. printf '%s' "$s"
  34. }
  35. using_oac_escaped=$(escape_for_json "$using_oac_content")
  36. # Build warning message for first-time users
  37. warning_message=""
  38. if [[ ! -f "${PLUGIN_ROOT}/.context-manifest.json" ]]; then
  39. warning_message="\n\n<important-reminder>IN YOUR FIRST REPLY AFTER SEEING THIS MESSAGE YOU MUST TELL THE USER:👋 **Welcome to OpenAgents Control!** To get started, run /install-context to download context files. Then use /oac:help to learn the 6-stage workflow.</important-reminder>"
  40. fi
  41. warning_escaped=$(escape_for_json "$warning_message")
  42. # Build context string once, reuse in both output formats
  43. OAC_CONTEXT="<EXTREMELY_IMPORTANT>\nYou are using OpenAgents Control (OAC).\n\nIN YOUR VERY FIRST REPLY you MUST start with exactly this line (no exceptions):\n🤖 **OAC Active** — 6-stage workflow enabled. Type /oac:help for commands.\n\n**Below is the full content of your 'using-oac' skill - your guide to the 6-stage workflow. For all other skills, use the 'Skill' tool:**\n\n${using_oac_escaped}\n\n${warning_escaped}\n</EXTREMELY_IMPORTANT>"
  44. # Output dual-format JSON for cross-tool compatibility
  45. # - additionalContext: Claude Code (hookSpecificOutput)
  46. # - additional_context: Cursor / OpenCode / other tools
  47. cat <<EOF
  48. {
  49. "additional_context": "${OAC_CONTEXT}",
  50. "hookSpecificOutput": {
  51. "hookEventName": "SessionStart",
  52. "additionalContext": "${OAC_CONTEXT}"
  53. }
  54. }
  55. EOF
  56. exit 0