| | @@ -40,7 +40,27 @@ |
| 40 | 40 | echo "Checking root structure..." |
| 41 | 41 | VALID_EVENTS=("PreToolUse" "PostToolUse" "UserPromptSubmit" "Stop" "SubagentStop" "SessionStart" "SessionEnd" "PreCompact" "Notification") |
| 42 | 42 | |
| 43 | | -for event in $(jq -r 'keys[]' "$HOOKS_FILE"); do |
| 43 | +# Detect format: plugin format has { description?, hooks: {...} } wrapper |
| 44 | +# Settings format has events directly at root level |
| 45 | +is_plugin_format=false |
| 46 | +if jq -e '.hooks' "$HOOKS_FILE" >/dev/null 2>&1; then |
| 47 | + is_plugin_format=true |
| 48 | + HOOKS_PATH=".hooks" |
| 49 | + echo "Detected plugin format (with 'hooks' wrapper)" |
| 50 | + |
| 51 | + # Validate allowed root keys for plugin format |
| 52 | + for key in $(jq -r 'keys[]' "$HOOKS_FILE"); do |
| 53 | + if [ "$key" != "hooks" ] && [ "$key" != "description" ]; then |
| 54 | + echo "⚠️ Unknown root key in plugin format: $key (expected: 'hooks', 'description')" |
| 55 | + fi |
| 56 | + done |
| 57 | +else |
| 58 | + HOOKS_PATH="." |
| 59 | + echo "Detected settings format (events at root)" |
| 60 | +fi |
| 61 | + |
| 62 | +# Validate event types |
| 63 | +for event in $(jq -r "$HOOKS_PATH | keys[]" "$HOOKS_FILE"); do |
| 44 | 64 | found=false |
| 45 | 65 | for valid_event in "${VALID_EVENTS[@]}"; do |
| 46 | 66 | if [ "$event" = "$valid_event" ]; then |
| | @@ -62,12 +82,12 @@ |
| 62 | 82 | error_count=0 |
| 63 | 83 | warning_count=0 |
| 64 | 84 | |
| 65 | | -for event in $(jq -r 'keys[]' "$HOOKS_FILE"); do |
| 66 | | - hook_count=$(jq -r ".\"$event\" | length" "$HOOKS_FILE") |
| 85 | +for event in $(jq -r "$HOOKS_PATH | keys[]" "$HOOKS_FILE"); do |
| 86 | + hook_count=$(jq -r "$HOOKS_PATH.\"$event\" | length" "$HOOKS_FILE") |
| 67 | 87 | |
| 68 | 88 | for ((i=0; i<hook_count; i++)); do |
| 69 | 89 | # Check matcher exists |
| 70 | | - matcher=$(jq -r ".\"$event\"[$i].matcher // empty" "$HOOKS_FILE") |
| 90 | + matcher=$(jq -r "$HOOKS_PATH.\"$event\"[$i].matcher // empty" "$HOOKS_FILE") |
| 71 | 91 | if [ -z "$matcher" ]; then |
| 72 | 92 | echo "❌ $event[$i]: Missing 'matcher' field" |
| 73 | 93 | ((error_count++)) |
| | @@ -75,7 +95,7 @@ |
| 75 | 95 | fi |
| 76 | 96 | |
| 77 | 97 | # Check hooks array exists |
| 78 | | - hooks=$(jq -r ".\"$event\"[$i].hooks // empty" "$HOOKS_FILE") |
| 98 | + hooks=$(jq -r "$HOOKS_PATH.\"$event\"[$i].hooks // empty" "$HOOKS_FILE") |
| 79 | 99 | if [ -z "$hooks" ] || [ "$hooks" = "null" ]; then |
| 80 | 100 | echo "❌ $event[$i]: Missing 'hooks' array" |
| 81 | 101 | ((error_count++)) |
| | @@ -83,10 +103,10 @@ |
| 83 | 103 | fi |
| 84 | 104 | |
| 85 | 105 | # Validate each hook in the array |
| 86 | | - hook_array_count=$(jq -r ".\"$event\"[$i].hooks | length" "$HOOKS_FILE") |
| 106 | + hook_array_count=$(jq -r "$HOOKS_PATH.\"$event\"[$i].hooks | length" "$HOOKS_FILE") |
| 87 | 107 | |
| 88 | 108 | for ((j=0; j<hook_array_count; j++)); do |
| 89 | | - hook_type=$(jq -r ".\"$event\"[$i].hooks[$j].type // empty" "$HOOKS_FILE") |
| 109 | + hook_type=$(jq -r "$HOOKS_PATH.\"$event\"[$i].hooks[$j].type // empty" "$HOOKS_FILE") |
| 90 | 110 | |
| 91 | 111 | if [ -z "$hook_type" ]; then |
| 92 | 112 | echo "❌ $event[$i].hooks[$j]: Missing 'type' field" |
| | @@ -102,7 +122,7 @@ |
| 102 | 122 | |
| 103 | 123 | # Check type-specific fields |
| 104 | 124 | if [ "$hook_type" = "command" ]; then |
| 105 | | - command=$(jq -r ".\"$event\"[$i].hooks[$j].command // empty" "$HOOKS_FILE") |
| 125 | + command=$(jq -r "$HOOKS_PATH.\"$event\"[$i].hooks[$j].command // empty" "$HOOKS_FILE") |
| 106 | 126 | if [ -z "$command" ]; then |
| 107 | 127 | echo "❌ $event[$i].hooks[$j]: Command hooks must have 'command' field" |
| 108 | 128 | ((error_count++)) |
| | @@ -114,7 +134,7 @@ |
| 114 | 134 | fi |
| 115 | 135 | fi |
| 116 | 136 | elif [ "$hook_type" = "prompt" ]; then |
| 117 | | - prompt=$(jq -r ".\"$event\"[$i].hooks[$j].prompt // empty" "$HOOKS_FILE") |
| 137 | + prompt=$(jq -r "$HOOKS_PATH.\"$event\"[$i].hooks[$j].prompt // empty" "$HOOKS_FILE") |
| 118 | 138 | if [ -z "$prompt" ]; then |
| 119 | 139 | echo "❌ $event[$i].hooks[$j]: Prompt hooks must have 'prompt' field" |
| 120 | 140 | ((error_count++)) |
| | @@ -128,7 +148,7 @@ |
| 128 | 148 | fi |
| 129 | 149 | |
| 130 | 150 | # Check timeout |
| 131 | | - timeout=$(jq -r ".\"$event\"[$i].hooks[$j].timeout // empty" "$HOOKS_FILE") |
| 151 | + timeout=$(jq -r "$HOOKS_PATH.\"$event\"[$i].hooks[$j].timeout // empty" "$HOOKS_FILE") |
| 132 | 152 | if [ -n "$timeout" ] && [ "$timeout" != "null" ]; then |
| 133 | 153 | if ! [[ "$timeout" =~ ^[0-9]+$ ]]; then |
| 134 | 154 | echo "❌ $event[$i].hooks[$j]: Timeout must be a number" |