Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Guidance for developing lifecycle hooks for Claude Code plugins from the official Anthropic repository.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
scripts/test-hook.sh
1#!/bin/bash2# Hook Testing Helper3# Tests a hook with sample input and shows output45set -euo pipefail67# Usage8show_usage() {9echo "Usage: $0 [options] <hook-script> <test-input.json>"10echo ""11echo "Options:"12echo " -h, --help Show this help message"13echo " -v, --verbose Show detailed execution information"14echo " -t, --timeout N Set timeout in seconds (default: 60)"15echo ""16echo "Examples:"17echo " $0 validate-bash.sh test-input.json"18echo " $0 -v -t 30 validate-write.sh write-input.json"19echo ""20echo "Creates sample test input with:"21echo " $0 --create-sample <event-type>"22exit 023}2425# Create sample input26create_sample() {27event_type="$1"2829case "$event_type" in30PreToolUse)31cat <<'EOF'32{33"session_id": "test-session",34"transcript_path": "/tmp/transcript.txt",35"cwd": "/tmp/test-project",36"permission_mode": "ask",37"hook_event_name": "PreToolUse",38"tool_name": "Write",39"tool_input": {40"file_path": "/tmp/test.txt",41"content": "Test content"42}43}44EOF45;;46PostToolUse)47cat <<'EOF'48{49"session_id": "test-session",50"transcript_path": "/tmp/transcript.txt",51"cwd": "/tmp/test-project",52"permission_mode": "ask",53"hook_event_name": "PostToolUse",54"tool_name": "Bash",55"tool_result": "Command executed successfully"56}57EOF58;;59Stop|SubagentStop)60cat <<'EOF'61{62"session_id": "test-session",63"transcript_path": "/tmp/transcript.txt",64"cwd": "/tmp/test-project",65"permission_mode": "ask",66"hook_event_name": "Stop",67"reason": "Task appears complete"68}69EOF70;;71UserPromptSubmit)72cat <<'EOF'73{74"session_id": "test-session",75"transcript_path": "/tmp/transcript.txt",76"cwd": "/tmp/test-project",77"permission_mode": "ask",78"hook_event_name": "UserPromptSubmit",79"user_prompt": "Test user prompt"80}81EOF82;;83SessionStart|SessionEnd)84cat <<'EOF'85{86"session_id": "test-session",87"transcript_path": "/tmp/transcript.txt",88"cwd": "/tmp/test-project",89"permission_mode": "ask",90"hook_event_name": "SessionStart"91}92EOF93;;94*)95echo "Unknown event type: $event_type"96echo "Valid types: PreToolUse, PostToolUse, Stop, SubagentStop, UserPromptSubmit, SessionStart, SessionEnd"97exit 198;;99esac100}101102# Parse arguments103VERBOSE=false104TIMEOUT=60105106while [ $# -gt 0 ]; do107case "$1" in108-h|--help)109show_usage110;;111-v|--verbose)112VERBOSE=true113shift114;;115-t|--timeout)116TIMEOUT="$2"117shift 2118;;119--create-sample)120create_sample "$2"121exit 0122;;123*)124break125;;126esac127done128129if [ $# -ne 2 ]; then130echo "Error: Missing required arguments"131echo ""132show_usage133fi134135HOOK_SCRIPT="$1"136TEST_INPUT="$2"137138# Validate inputs139if [ ! -f "$HOOK_SCRIPT" ]; then140echo "❌ Error: Hook script not found: $HOOK_SCRIPT"141exit 1142fi143144if [ ! -x "$HOOK_SCRIPT" ]; then145echo "⚠️ Warning: Hook script is not executable. Attempting to run with bash..."146HOOK_SCRIPT="bash $HOOK_SCRIPT"147fi148149if [ ! -f "$TEST_INPUT" ]; then150echo "❌ Error: Test input not found: $TEST_INPUT"151exit 1152fi153154# Validate test input JSON155if ! jq empty "$TEST_INPUT" 2>/dev/null; then156echo "❌ Error: Test input is not valid JSON"157exit 1158fi159160echo "🧪 Testing hook: $HOOK_SCRIPT"161echo "📥 Input: $TEST_INPUT"162echo ""163164if [ "$VERBOSE" = true ]; then165echo "Input JSON:"166jq . "$TEST_INPUT"167echo ""168fi169170# Set up environment171export CLAUDE_PROJECT_DIR="${CLAUDE_PROJECT_DIR:-/tmp/test-project}"172export CLAUDE_PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(pwd)}"173export CLAUDE_ENV_FILE="${CLAUDE_ENV_FILE:-/tmp/test-env-$$}"174175if [ "$VERBOSE" = true ]; then176echo "Environment:"177echo " CLAUDE_PROJECT_DIR=$CLAUDE_PROJECT_DIR"178echo " CLAUDE_PLUGIN_ROOT=$CLAUDE_PLUGIN_ROOT"179echo " CLAUDE_ENV_FILE=$CLAUDE_ENV_FILE"180echo ""181fi182183# Run the hook184echo "▶️ Running hook (timeout: ${TIMEOUT}s)..."185echo ""186187start_time=$(date +%s)188189set +e190output=$(timeout "$TIMEOUT" bash -c "cat '$TEST_INPUT' | $HOOK_SCRIPT" 2>&1)191exit_code=$?192set -e193194end_time=$(date +%s)195duration=$((end_time - start_time))196197# Analyze results198echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"199echo "Results:"200echo ""201echo "Exit Code: $exit_code"202echo "Duration: ${duration}s"203echo ""204205case $exit_code in2060)207echo "✅ Hook approved/succeeded"208;;2092)210echo "🚫 Hook blocked/denied"211;;212124)213echo "⏱️ Hook timed out after ${TIMEOUT}s"214;;215*)216echo "⚠️ Hook returned unexpected exit code: $exit_code"217;;218esac219220echo ""221echo "Output:"222if [ -n "$output" ]; then223echo "$output"224echo ""225226# Try to parse as JSON227if echo "$output" | jq empty 2>/dev/null; then228echo "Parsed JSON output:"229echo "$output" | jq .230fi231else232echo "(no output)"233fi234235# Check for environment file236if [ -f "$CLAUDE_ENV_FILE" ]; then237echo ""238echo "Environment file created:"239cat "$CLAUDE_ENV_FILE"240rm -f "$CLAUDE_ENV_FILE"241fi242243echo ""244echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"245246if [ $exit_code -eq 0 ] || [ $exit_code -eq 2 ]; then247echo "✅ Test completed successfully"248exit 0249else250echo "❌ Test failed"251exit 1252fi253