mirror of
https://github.com/anthropics/claude-code.git
synced 2025-11-28 16:50:27 +08:00
Adds the plugin-dev plugin to public marketplace. A comprehensive toolkit for
developing Claude Code plugins with 7 expert skills, 3 AI-assisted agents, and
extensive documentation covering the complete plugin development lifecycle.
Key features:
- 7 skills: hook-development, mcp-integration, plugin-structure, plugin-settings,
command-development, agent-development, skill-development
- 3 agents: agent-creator (AI-assisted generation), plugin-validator (structure
validation), skill-reviewer (quality review)
- 1 command: /plugin-dev:create-plugin (guided 8-phase workflow)
- 10 utility scripts for validation and testing
- 21 reference docs with deep-dive guidance (~11k words)
- 9 working examples demonstrating best practices
Changes for public release:
- Replaced all references to internal repositories with "Claude Code"
- Updated MCP examples: internal.company.com → api.example.com
- Updated token variables: ${INTERNAL_TOKEN} → ${API_TOKEN}
- Reframed agent-creation-system-prompt as "proven in production"
- Preserved all ${CLAUDE_PLUGIN_ROOT} references (186 total)
- Preserved valuable test blocks in core modules
Validation:
- All 3 agents validated successfully with validate-agent.sh
- All JSON files validated with jq
- Zero internal references remaining
- 59 files migrated, 21,971 lines added
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
252 lines
5.2 KiB
Bash
Executable file
252 lines
5.2 KiB
Bash
Executable file
#!/bin/bash
|
|
# Hook Testing Helper
|
|
# Tests a hook with sample input and shows output
|
|
|
|
set -euo pipefail
|
|
|
|
# Usage
|
|
show_usage() {
|
|
echo "Usage: $0 [options] <hook-script> <test-input.json>"
|
|
echo ""
|
|
echo "Options:"
|
|
echo " -h, --help Show this help message"
|
|
echo " -v, --verbose Show detailed execution information"
|
|
echo " -t, --timeout N Set timeout in seconds (default: 60)"
|
|
echo ""
|
|
echo "Examples:"
|
|
echo " $0 validate-bash.sh test-input.json"
|
|
echo " $0 -v -t 30 validate-write.sh write-input.json"
|
|
echo ""
|
|
echo "Creates sample test input with:"
|
|
echo " $0 --create-sample <event-type>"
|
|
exit 0
|
|
}
|
|
|
|
# Create sample input
|
|
create_sample() {
|
|
event_type="$1"
|
|
|
|
case "$event_type" in
|
|
PreToolUse)
|
|
cat <<'EOF'
|
|
{
|
|
"session_id": "test-session",
|
|
"transcript_path": "/tmp/transcript.txt",
|
|
"cwd": "/tmp/test-project",
|
|
"permission_mode": "ask",
|
|
"hook_event_name": "PreToolUse",
|
|
"tool_name": "Write",
|
|
"tool_input": {
|
|
"file_path": "/tmp/test.txt",
|
|
"content": "Test content"
|
|
}
|
|
}
|
|
EOF
|
|
;;
|
|
PostToolUse)
|
|
cat <<'EOF'
|
|
{
|
|
"session_id": "test-session",
|
|
"transcript_path": "/tmp/transcript.txt",
|
|
"cwd": "/tmp/test-project",
|
|
"permission_mode": "ask",
|
|
"hook_event_name": "PostToolUse",
|
|
"tool_name": "Bash",
|
|
"tool_result": "Command executed successfully"
|
|
}
|
|
EOF
|
|
;;
|
|
Stop|SubagentStop)
|
|
cat <<'EOF'
|
|
{
|
|
"session_id": "test-session",
|
|
"transcript_path": "/tmp/transcript.txt",
|
|
"cwd": "/tmp/test-project",
|
|
"permission_mode": "ask",
|
|
"hook_event_name": "Stop",
|
|
"reason": "Task appears complete"
|
|
}
|
|
EOF
|
|
;;
|
|
UserPromptSubmit)
|
|
cat <<'EOF'
|
|
{
|
|
"session_id": "test-session",
|
|
"transcript_path": "/tmp/transcript.txt",
|
|
"cwd": "/tmp/test-project",
|
|
"permission_mode": "ask",
|
|
"hook_event_name": "UserPromptSubmit",
|
|
"user_prompt": "Test user prompt"
|
|
}
|
|
EOF
|
|
;;
|
|
SessionStart|SessionEnd)
|
|
cat <<'EOF'
|
|
{
|
|
"session_id": "test-session",
|
|
"transcript_path": "/tmp/transcript.txt",
|
|
"cwd": "/tmp/test-project",
|
|
"permission_mode": "ask",
|
|
"hook_event_name": "SessionStart"
|
|
}
|
|
EOF
|
|
;;
|
|
*)
|
|
echo "Unknown event type: $event_type"
|
|
echo "Valid types: PreToolUse, PostToolUse, Stop, SubagentStop, UserPromptSubmit, SessionStart, SessionEnd"
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Parse arguments
|
|
VERBOSE=false
|
|
TIMEOUT=60
|
|
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
-h|--help)
|
|
show_usage
|
|
;;
|
|
-v|--verbose)
|
|
VERBOSE=true
|
|
shift
|
|
;;
|
|
-t|--timeout)
|
|
TIMEOUT="$2"
|
|
shift 2
|
|
;;
|
|
--create-sample)
|
|
create_sample "$2"
|
|
exit 0
|
|
;;
|
|
*)
|
|
break
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [ $# -ne 2 ]; then
|
|
echo "Error: Missing required arguments"
|
|
echo ""
|
|
show_usage
|
|
fi
|
|
|
|
HOOK_SCRIPT="$1"
|
|
TEST_INPUT="$2"
|
|
|
|
# Validate inputs
|
|
if [ ! -f "$HOOK_SCRIPT" ]; then
|
|
echo "❌ Error: Hook script not found: $HOOK_SCRIPT"
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -x "$HOOK_SCRIPT" ]; then
|
|
echo "⚠️ Warning: Hook script is not executable. Attempting to run with bash..."
|
|
HOOK_SCRIPT="bash $HOOK_SCRIPT"
|
|
fi
|
|
|
|
if [ ! -f "$TEST_INPUT" ]; then
|
|
echo "❌ Error: Test input not found: $TEST_INPUT"
|
|
exit 1
|
|
fi
|
|
|
|
# Validate test input JSON
|
|
if ! jq empty "$TEST_INPUT" 2>/dev/null; then
|
|
echo "❌ Error: Test input is not valid JSON"
|
|
exit 1
|
|
fi
|
|
|
|
echo "🧪 Testing hook: $HOOK_SCRIPT"
|
|
echo "📥 Input: $TEST_INPUT"
|
|
echo ""
|
|
|
|
if [ "$VERBOSE" = true ]; then
|
|
echo "Input JSON:"
|
|
jq . "$TEST_INPUT"
|
|
echo ""
|
|
fi
|
|
|
|
# Set up environment
|
|
export CLAUDE_PROJECT_DIR="${CLAUDE_PROJECT_DIR:-/tmp/test-project}"
|
|
export CLAUDE_PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(pwd)}"
|
|
export CLAUDE_ENV_FILE="${CLAUDE_ENV_FILE:-/tmp/test-env-$$}"
|
|
|
|
if [ "$VERBOSE" = true ]; then
|
|
echo "Environment:"
|
|
echo " CLAUDE_PROJECT_DIR=$CLAUDE_PROJECT_DIR"
|
|
echo " CLAUDE_PLUGIN_ROOT=$CLAUDE_PLUGIN_ROOT"
|
|
echo " CLAUDE_ENV_FILE=$CLAUDE_ENV_FILE"
|
|
echo ""
|
|
fi
|
|
|
|
# Run the hook
|
|
echo "▶️ Running hook (timeout: ${TIMEOUT}s)..."
|
|
echo ""
|
|
|
|
start_time=$(date +%s)
|
|
|
|
set +e
|
|
output=$(timeout "$TIMEOUT" bash -c "cat '$TEST_INPUT' | $HOOK_SCRIPT" 2>&1)
|
|
exit_code=$?
|
|
set -e
|
|
|
|
end_time=$(date +%s)
|
|
duration=$((end_time - start_time))
|
|
|
|
# Analyze results
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "Results:"
|
|
echo ""
|
|
echo "Exit Code: $exit_code"
|
|
echo "Duration: ${duration}s"
|
|
echo ""
|
|
|
|
case $exit_code in
|
|
0)
|
|
echo "✅ Hook approved/succeeded"
|
|
;;
|
|
2)
|
|
echo "🚫 Hook blocked/denied"
|
|
;;
|
|
124)
|
|
echo "⏱️ Hook timed out after ${TIMEOUT}s"
|
|
;;
|
|
*)
|
|
echo "⚠️ Hook returned unexpected exit code: $exit_code"
|
|
;;
|
|
esac
|
|
|
|
echo ""
|
|
echo "Output:"
|
|
if [ -n "$output" ]; then
|
|
echo "$output"
|
|
echo ""
|
|
|
|
# Try to parse as JSON
|
|
if echo "$output" | jq empty 2>/dev/null; then
|
|
echo "Parsed JSON output:"
|
|
echo "$output" | jq .
|
|
fi
|
|
else
|
|
echo "(no output)"
|
|
fi
|
|
|
|
# Check for environment file
|
|
if [ -f "$CLAUDE_ENV_FILE" ]; then
|
|
echo ""
|
|
echo "Environment file created:"
|
|
cat "$CLAUDE_ENV_FILE"
|
|
rm -f "$CLAUDE_ENV_FILE"
|
|
fi
|
|
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
|
|
if [ $exit_code -eq 0 ] || [ $exit_code -eq 2 ]; then
|
|
echo "✅ Test completed successfully"
|
|
exit 0
|
|
else
|
|
echo "❌ Test failed"
|
|
exit 1
|
|
fi
|