mirror of
https://github.com/anthropics/claude-code.git
synced 2026-04-19 01:52:42 +00:00
Compare commits
1 Commits
claude/sla
...
claude/sla
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ffa4f07ff |
@@ -3,7 +3,6 @@
|
||||
"hooks": {
|
||||
"SessionStart": [
|
||||
{
|
||||
"matcher": "*",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"hooks": {
|
||||
"PreToolUse": [
|
||||
{
|
||||
"matcher": "*",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
@@ -15,7 +14,6 @@
|
||||
],
|
||||
"PostToolUse": [
|
||||
{
|
||||
"matcher": "*",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
@@ -27,7 +25,6 @@
|
||||
],
|
||||
"Stop": [
|
||||
{
|
||||
"matcher": "*",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
@@ -39,7 +36,6 @@
|
||||
],
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"matcher": "*",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"hooks": {
|
||||
"SessionStart": [
|
||||
{
|
||||
"matcher": "*",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
|
||||
45
plugins/plan-auto-show/README.md
Normal file
45
plugins/plan-auto-show/README.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# Plan Auto-Show Plugin
|
||||
|
||||
Automatically displays the plan content when it's updated in plan mode, eliminating the need to type `/plan` to preview changes.
|
||||
|
||||
## Problem
|
||||
|
||||
When in plan mode, Claude updates the plan file and may ask follow-up questions. Users can't see the plan without typing `/plan`, but they also can't type `/plan` while being asked questions - they need to respond to the questions first.
|
||||
|
||||
## Solution
|
||||
|
||||
This plugin instructs Claude to automatically display the plan content in its response whenever it updates the plan file. The plan is shown before any follow-up questions, giving users the context they need to answer.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Enable the plugin in your Claude Code settings
|
||||
2. The SessionStart hook will automatically add instructions for plan auto-display
|
||||
|
||||
## How It Works
|
||||
|
||||
The plugin adds a SessionStart hook that provides additional context to Claude:
|
||||
- After updating the plan file, Claude will display the full plan content
|
||||
- The plan is shown in a markdown code block
|
||||
- The plan appears before any follow-up questions
|
||||
|
||||
## Example
|
||||
|
||||
Before this plugin:
|
||||
```
|
||||
Claude: I've updated the plan file. Would you prefer approach A or B?
|
||||
User: (Can't see the plan without typing /plan, but needs to answer the question)
|
||||
```
|
||||
|
||||
After this plugin:
|
||||
```
|
||||
Claude: I've updated the plan file:
|
||||
|
||||
## Current Plan
|
||||
1. Implement feature X
|
||||
2. Add tests
|
||||
3. Deploy
|
||||
|
||||
Would you prefer approach A or B?
|
||||
|
||||
User: (Can see the plan and answer the question)
|
||||
```
|
||||
15
plugins/plan-auto-show/hooks/session-start.sh
Executable file
15
plugins/plan-auto-show/hooks/session-start.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Auto-show plan content after updates in plan mode
|
||||
# This hook adds instructions to automatically display the plan when updated
|
||||
|
||||
cat << 'EOF'
|
||||
{
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "SessionStart",
|
||||
"additionalContext": "## Plan Mode Auto-Display\n\nWhen you are in plan mode and you update the plan file:\n\n1. After writing or editing the plan file, ALWAYS display the full plan content in a markdown code block in your response\n2. Use the format:\n ```markdown\n ## Current Plan\n [full plan content here]\n ```\n3. This ensures the user can see the plan without needing to run `/plan`, which is especially important when you're asking follow-up questions\n4. Show the plan BEFORE asking any clarifying questions, so the user has context for their answers\n\nThis improves the user experience by making the plan visible immediately after updates, without requiring separate commands."
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
exit 0
|
||||
15
plugins/plan-auto-show/settings.json
Normal file
15
plugins/plan-auto-show/settings.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"hooks": {
|
||||
"SessionStart": [
|
||||
{
|
||||
"matcher": "*",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -40,27 +40,7 @@ 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
|
||||
for event in $(jq -r 'keys[]' "$HOOKS_FILE"); do
|
||||
found=false
|
||||
for valid_event in "${VALID_EVENTS[@]}"; do
|
||||
if [ "$event" = "$valid_event" ]; then
|
||||
@@ -82,12 +62,12 @@ 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 event in $(jq -r 'keys[]' "$HOOKS_FILE"); do
|
||||
hook_count=$(jq -r ".\"$event\" | length" "$HOOKS_FILE")
|
||||
|
||||
for ((i=0; i<hook_count; i++)); do
|
||||
# Check matcher exists
|
||||
matcher=$(jq -r "$HOOKS_PATH.\"$event\"[$i].matcher // empty" "$HOOKS_FILE")
|
||||
matcher=$(jq -r ".\"$event\"[$i].matcher // empty" "$HOOKS_FILE")
|
||||
if [ -z "$matcher" ]; then
|
||||
echo "❌ $event[$i]: Missing 'matcher' field"
|
||||
((error_count++))
|
||||
@@ -95,7 +75,7 @@ for event in $(jq -r "$HOOKS_PATH | keys[]" "$HOOKS_FILE"); do
|
||||
fi
|
||||
|
||||
# Check hooks array exists
|
||||
hooks=$(jq -r "$HOOKS_PATH.\"$event\"[$i].hooks // empty" "$HOOKS_FILE")
|
||||
hooks=$(jq -r ".\"$event\"[$i].hooks // empty" "$HOOKS_FILE")
|
||||
if [ -z "$hooks" ] || [ "$hooks" = "null" ]; then
|
||||
echo "❌ $event[$i]: Missing 'hooks' array"
|
||||
((error_count++))
|
||||
@@ -103,10 +83,10 @@ for event in $(jq -r "$HOOKS_PATH | keys[]" "$HOOKS_FILE"); do
|
||||
fi
|
||||
|
||||
# Validate each hook in the array
|
||||
hook_array_count=$(jq -r "$HOOKS_PATH.\"$event\"[$i].hooks | length" "$HOOKS_FILE")
|
||||
hook_array_count=$(jq -r ".\"$event\"[$i].hooks | length" "$HOOKS_FILE")
|
||||
|
||||
for ((j=0; j<hook_array_count; j++)); do
|
||||
hook_type=$(jq -r "$HOOKS_PATH.\"$event\"[$i].hooks[$j].type // empty" "$HOOKS_FILE")
|
||||
hook_type=$(jq -r ".\"$event\"[$i].hooks[$j].type // empty" "$HOOKS_FILE")
|
||||
|
||||
if [ -z "$hook_type" ]; then
|
||||
echo "❌ $event[$i].hooks[$j]: Missing 'type' field"
|
||||
@@ -122,7 +102,7 @@ for event in $(jq -r "$HOOKS_PATH | keys[]" "$HOOKS_FILE"); do
|
||||
|
||||
# Check type-specific fields
|
||||
if [ "$hook_type" = "command" ]; then
|
||||
command=$(jq -r "$HOOKS_PATH.\"$event\"[$i].hooks[$j].command // empty" "$HOOKS_FILE")
|
||||
command=$(jq -r ".\"$event\"[$i].hooks[$j].command // empty" "$HOOKS_FILE")
|
||||
if [ -z "$command" ]; then
|
||||
echo "❌ $event[$i].hooks[$j]: Command hooks must have 'command' field"
|
||||
((error_count++))
|
||||
@@ -134,7 +114,7 @@ for event in $(jq -r "$HOOKS_PATH | keys[]" "$HOOKS_FILE"); do
|
||||
fi
|
||||
fi
|
||||
elif [ "$hook_type" = "prompt" ]; then
|
||||
prompt=$(jq -r "$HOOKS_PATH.\"$event\"[$i].hooks[$j].prompt // empty" "$HOOKS_FILE")
|
||||
prompt=$(jq -r ".\"$event\"[$i].hooks[$j].prompt // empty" "$HOOKS_FILE")
|
||||
if [ -z "$prompt" ]; then
|
||||
echo "❌ $event[$i].hooks[$j]: Prompt hooks must have 'prompt' field"
|
||||
((error_count++))
|
||||
@@ -148,7 +128,7 @@ for event in $(jq -r "$HOOKS_PATH | keys[]" "$HOOKS_FILE"); do
|
||||
fi
|
||||
|
||||
# Check timeout
|
||||
timeout=$(jq -r "$HOOKS_PATH.\"$event\"[$i].hooks[$j].timeout // empty" "$HOOKS_FILE")
|
||||
timeout=$(jq -r ".\"$event\"[$i].hooks[$j].timeout // empty" "$HOOKS_FILE")
|
||||
if [ -n "$timeout" ] && [ "$timeout" != "null" ]; then
|
||||
if ! [[ "$timeout" =~ ^[0-9]+$ ]]; then
|
||||
echo "❌ $event[$i].hooks[$j]: Timeout must be a number"
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"hooks": {
|
||||
"Stop": [
|
||||
{
|
||||
"matcher": "*",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Validate all hooks.json files in the repository
|
||||
# This script can be run in CI to ensure all plugins have valid hook configurations
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
VALIDATOR="$REPO_ROOT/plugins/plugin-dev/skills/hook-development/scripts/validate-hook-schema.sh"
|
||||
|
||||
echo "🔍 Validating all hooks.json files in the repository..."
|
||||
echo ""
|
||||
|
||||
# Find all hooks.json files
|
||||
mapfile -t HOOKS_FILES < <(find "$REPO_ROOT/plugins" -name "hooks.json" -type f 2>/dev/null)
|
||||
|
||||
if [ ${#HOOKS_FILES[@]} -eq 0 ]; then
|
||||
echo "No hooks.json files found"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Found ${#HOOKS_FILES[@]} hooks.json file(s)"
|
||||
echo ""
|
||||
|
||||
errors=0
|
||||
for hooks_file in "${HOOKS_FILES[@]}"; do
|
||||
relative_path="${hooks_file#$REPO_ROOT/}"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "📄 $relative_path"
|
||||
echo ""
|
||||
|
||||
if bash "$VALIDATOR" "$hooks_file"; then
|
||||
echo ""
|
||||
else
|
||||
echo ""
|
||||
((errors++))
|
||||
fi
|
||||
done
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
if [ $errors -eq 0 ]; then
|
||||
echo "✅ All ${#HOOKS_FILES[@]} hooks.json file(s) are valid!"
|
||||
exit 0
|
||||
else
|
||||
echo "❌ $errors hooks.json file(s) have validation errors"
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user