#!/bin/bash # Hook Schema Validator # Validates hooks.json structure and checks for common issues set -euo pipefail # Usage if [ $# -eq 0 ]; then echo "Usage: $0 " echo "" echo "Validates hook configuration file for:" echo " - Valid JSON syntax" echo " - Required fields" echo " - Hook type validity" echo " - Matcher patterns" echo " - Timeout ranges" exit 1 fi HOOKS_FILE="$1" if [ ! -f "$HOOKS_FILE" ]; then echo "❌ Error: File not found: $HOOKS_FILE" exit 1 fi echo "🔍 Validating hooks configuration: $HOOKS_FILE" echo "" # Check 1: Valid JSON echo "Checking JSON syntax..." if ! jq empty "$HOOKS_FILE" 2>/dev/null; then echo "❌ Invalid JSON syntax" exit 1 fi echo "✅ Valid JSON" # Check 2: Root structure echo "" echo "Checking root structure..." VALID_EVENTS=("PreToolUse" "PostToolUse" "UserPromptSubmit" "Stop" "SubagentStop" "SessionStart" "SessionEnd" "PreCompact" "Notification") # Detect format: plugin format has { description?, hooks: {...} } wrapper # Settings format has events directly at root level is_plugin_format=false if jq -e '.hooks' "$HOOKS_FILE" >/dev/null 2>&1; then is_plugin_format=true HOOKS_PATH=".hooks" echo "Detected plugin format (with 'hooks' wrapper)" # Validate allowed root keys for plugin format for key in $(jq -r 'keys[]' "$HOOKS_FILE"); do if [ "$key" != "hooks" ] && [ "$key" != "description" ]; then echo "⚠️ Unknown root key in plugin format: $key (expected: 'hooks', 'description')" fi done else HOOKS_PATH="." echo "Detected settings format (events at root)" fi # Validate event types for event in $(jq -r "$HOOKS_PATH | keys[]" "$HOOKS_FILE"); do found=false for valid_event in "${VALID_EVENTS[@]}"; do if [ "$event" = "$valid_event" ]; then found=true break fi done if [ "$found" = false ]; then echo "⚠️ Unknown event type: $event" fi done echo "✅ Root structure valid" # Check 3: Validate each hook echo "" echo "Validating individual hooks..." error_count=0 warning_count=0 for event in $(jq -r "$HOOKS_PATH | keys[]" "$HOOKS_FILE"); do hook_count=$(jq -r "$HOOKS_PATH.\"$event\" | length" "$HOOKS_FILE") for ((i=0; i