hook-script.sh 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. #!/bin/bash
  2. #
  3. # Claude Code Hook: [Description]
  4. #
  5. # Event: [PreToolUse|PostToolUse|SessionStart|etc]
  6. # Matcher: [Tool name or * for all]
  7. #
  8. # Security: Validates input, quotes variables, prevents path traversal
  9. #
  10. set -euo pipefail
  11. # Error handling
  12. trap 'echo "Error at line $LINENO" >&2; exit 1' ERR
  13. # Check dependencies
  14. command -v jq >/dev/null 2>&1 || {
  15. echo "jq is required but not installed" >&2
  16. exit 1
  17. }
  18. # Read input from stdin
  19. INPUT=$(cat)
  20. # Validate JSON
  21. if ! echo "$INPUT" | jq -e '.' > /dev/null 2>&1; then
  22. echo "Invalid JSON input" >&2
  23. exit 2
  24. fi
  25. # Parse common fields
  26. TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty')
  27. SESSION=$(echo "$INPUT" | jq -r '.session_id // empty')
  28. # -------------------------------------------------------------------
  29. # Your hook logic here
  30. # -------------------------------------------------------------------
  31. # Example: Log tool usage
  32. LOG_FILE="${CLAUDE_PROJECT_DIR:-.}/.claude/hook.log"
  33. mkdir -p "$(dirname "$LOG_FILE")"
  34. echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") | $TOOL | $SESSION" >> "$LOG_FILE"
  35. # Example: Block dangerous operations
  36. # if [[ "$TOOL" == "Bash" ]]; then
  37. # CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
  38. # if [[ "$CMD" == *"rm -rf /"* ]]; then
  39. # echo "Blocked dangerous command" >&2
  40. # exit 2 # Exit 2 = blocking error
  41. # fi
  42. # fi
  43. # Example: Validate file paths
  44. # if [[ "$TOOL" == "Write" ]]; then
  45. # FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
  46. # if [[ "$FILE" == *".."* ]]; then
  47. # echo "Path traversal blocked" >&2
  48. # exit 2
  49. # fi
  50. # fi
  51. # -------------------------------------------------------------------
  52. # Exit codes:
  53. # 0 = Success (continue execution)
  54. # 2 = Blocking error (stderr shown to Claude)
  55. # Other = Non-blocking error (logged, continues)
  56. # -------------------------------------------------------------------
  57. exit 0
  58. # CONFIGURATION EXAMPLE:
  59. # Add to ~/.claude/settings.json or .claude/settings.local.json:
  60. #
  61. # {
  62. # "hooks": {
  63. # "PreToolUse": [{
  64. # "matcher": "*",
  65. # "hooks": [{
  66. # "type": "command",
  67. # "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/this-script.sh",
  68. # "timeout": 5000
  69. # }]
  70. # }]
  71. # }
  72. # }