refactor(plugin): remove restrictive hooks, clean up orphaned scripts
Removed: - prefer-core.sh: blocked raw go/php commands unnecessarily - post-commit-check.sh: noisy warnings after every commit - block-docs.sh: blocked writing specs and RFCs - capture-context.sh, extract-actionables.sh, pr-created.sh, suggest-compact.sh: orphaned scripts not referenced by any hook Kept: - go-format.sh, php-format.sh: auto-format after edits (helpful) - check-debug.sh: warns about dd()/fmt.Print* (lightweight) - session-start.sh, pre-compact.sh, session-save.sh: essential Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
cce41faa39
commit
88e5fc6f49
8 changed files with 0 additions and 327 deletions
|
|
@ -1,18 +1,6 @@
|
|||
{
|
||||
"$schema": "https://claude.ai/schemas/hooks.json",
|
||||
"hooks": {
|
||||
"PreToolUse": [
|
||||
{
|
||||
"matcher": "Bash",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/prefer-core.sh"
|
||||
}
|
||||
],
|
||||
"description": "Block destructive commands (rm -rf, sed -i, xargs rm) and enforce core CLI"
|
||||
},
|
||||
],
|
||||
"PostToolUse": [
|
||||
{
|
||||
"matcher": "tool == \"Edit\" && tool_input.file_path matches \"\\.go$\"",
|
||||
|
|
@ -43,16 +31,6 @@
|
|||
}
|
||||
],
|
||||
"description": "Warn about debug statements (dd, dump, fmt.Println)"
|
||||
},
|
||||
{
|
||||
"matcher": "tool == \"Bash\" && tool_input.command matches \"^git commit\"",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/post-commit-check.sh"
|
||||
}
|
||||
],
|
||||
"description": "Warn about uncommitted work after git commit"
|
||||
}
|
||||
],
|
||||
"Stop": [
|
||||
|
|
|
|||
|
|
@ -1,18 +1,6 @@
|
|||
{
|
||||
"$schema": "https://claude.ai/schemas/hooks.json",
|
||||
"hooks": {
|
||||
"PreToolUse": [
|
||||
{
|
||||
"matcher": "Bash",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/prefer-core.sh"
|
||||
}
|
||||
],
|
||||
"description": "Block destructive commands (rm -rf, sed -i, xargs rm) and enforce core CLI"
|
||||
},
|
||||
],
|
||||
"PostToolUse": [
|
||||
{
|
||||
"matcher": "tool == \"Edit\" && tool_input.file_path matches \"\\.go$\"",
|
||||
|
|
@ -43,16 +31,6 @@
|
|||
}
|
||||
],
|
||||
"description": "Warn about debug statements (dd, dump, fmt.Println)"
|
||||
},
|
||||
{
|
||||
"matcher": "tool == \"Bash\" && tool_input.command matches \"^git commit\"",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/post-commit-check.sh"
|
||||
}
|
||||
],
|
||||
"description": "Warn about uncommitted work after git commit"
|
||||
}
|
||||
],
|
||||
"PreCompact": [
|
||||
|
|
|
|||
|
|
@ -1,108 +0,0 @@
|
|||
#!/bin/bash
|
||||
# PreToolUse hook: Block dangerous commands, enforce core CLI
|
||||
#
|
||||
# BLOCKS:
|
||||
# - Raw go commands (use core go *)
|
||||
# - Destructive patterns (sed -i, xargs rm, etc.)
|
||||
# - Mass file operations (rm -rf, mv/cp with wildcards)
|
||||
#
|
||||
# This prevents "efficient shortcuts" that nuke codebases
|
||||
|
||||
read -r input
|
||||
full_command=$(echo "$input" | jq -r '.tool_input.command // empty')
|
||||
|
||||
# Strip heredoc content — only check the actual command, not embedded text
|
||||
# This prevents false positives from code/docs inside heredocs
|
||||
command=$(echo "$full_command" | sed -n '1p')
|
||||
if echo "$command" | grep -qE "<<\s*['\"]?[A-Z_]+"; then
|
||||
# First line has heredoc marker — only check the command portion before <<
|
||||
command=$(echo "$command" | sed -E 's/\s*<<.*$//')
|
||||
fi
|
||||
|
||||
# For multi-line commands joined with && or ;, check each segment
|
||||
# But still only the first line (not heredoc body)
|
||||
|
||||
# === HARD BLOCKS - Never allow these ===
|
||||
|
||||
# Block rm -rf, rm -r (except for known safe paths like node_modules, vendor, .cache)
|
||||
# Allow git rm -r (safe — git tracks everything, easily reversible)
|
||||
if echo "$command" | grep -qE 'rm\s+(-[a-zA-Z]*r[a-zA-Z]*|-[a-zA-Z]*f[a-zA-Z]*r|--recursive)'; then
|
||||
# git rm -r is safe — everything is tracked and recoverable
|
||||
if echo "$command" | grep -qE 'git\s+rm\s'; then
|
||||
: # allow git rm through
|
||||
# Allow only specific safe directories for raw rm
|
||||
elif ! echo "$command" | grep -qE 'rm\s+(-rf|-r)\s+(node_modules|vendor|\.cache|dist|build|__pycache__|\.pytest_cache|/tmp/)'; then
|
||||
echo '{"decision": "block", "message": "BLOCKED: Recursive delete is not allowed. Delete files individually or ask the user to run this command."}'
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Block mv/cp with dangerous wildcards (e.g. `cp * /tmp`, `mv ./* /dest`)
|
||||
# Allow specific file copies that happen to use glob in a for loop or path
|
||||
if echo "$command" | grep -qE '(mv|cp)\s+(\.\/)?\*\s'; then
|
||||
echo '{"decision": "block", "message": "BLOCKED: Mass file move/copy with bare wildcards is not allowed. Copy files individually."}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Block xargs with rm, mv, cp (mass operations)
|
||||
if echo "$command" | grep -qE 'xargs\s+.*(rm|mv|cp)'; then
|
||||
echo '{"decision": "block", "message": "BLOCKED: xargs with file operations is not allowed. Too risky for mass changes."}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Block find -exec with rm, mv, cp
|
||||
if echo "$command" | grep -qE 'find\s+.*-exec\s+.*(rm|mv|cp)'; then
|
||||
echo '{"decision": "block", "message": "BLOCKED: find -exec with file operations is not allowed. Too risky for mass changes."}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Block sed -i on LOCAL files only (allow on remote via ssh/docker exec)
|
||||
if echo "$command" | grep -qE '^sed\s+(-[a-zA-Z]*i|--in-place)'; then
|
||||
echo '{"decision": "block", "message": "BLOCKED: sed -i (in-place edit) on local files. Use the Edit tool."}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Block grep -l piped to destructive commands only (not head, wc, etc.)
|
||||
if echo "$command" | grep -qE 'grep\s+.*-l.*\|\s*(xargs|sed|rm|mv)'; then
|
||||
echo '{"decision": "block", "message": "BLOCKED: grep -l piped to destructive commands. Too risky."}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Block perl -i on local files
|
||||
if echo "$command" | grep -qE '^perl\s+-[a-zA-Z]*i'; then
|
||||
echo '{"decision": "block", "message": "BLOCKED: In-place file editing with perl. Use the Edit tool."}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# === REQUIRE CORE CLI ===
|
||||
|
||||
# Suggest core CLI for common go commands, but don't block
|
||||
# go work sync, go mod edit, go get, go install, go list etc. have no core wrapper
|
||||
case "$command" in
|
||||
"go test"*|"go build"*|"go fmt"*|"go vet"*)
|
||||
echo '{"decision": "block", "message": "Use `core go test`, `core build`, `core go fmt --fix`, `core go vet`. Raw go commands bypass quality checks."}'
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
# Allow all other go commands (go mod tidy, go work sync, go get, go run, etc.)
|
||||
|
||||
# Block raw php commands
|
||||
case "$command" in
|
||||
"php artisan serve"*|"./vendor/bin/pest"*|"./vendor/bin/pint"*|"./vendor/bin/phpstan"*)
|
||||
echo '{"decision": "block", "message": "Use `core php dev`, `core php test`, `core php fmt`, `core php analyse`. Raw php commands are not allowed."}'
|
||||
exit 0
|
||||
;;
|
||||
"composer test"*|"composer lint"*)
|
||||
echo '{"decision": "block", "message": "Use `core php test` or `core php fmt`. Raw composer commands are not allowed."}'
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
# Block golangci-lint directly
|
||||
if echo "$command" | grep -qE '^golangci-lint'; then
|
||||
echo '{"decision": "block", "message": "Use `core go lint` instead of golangci-lint directly."}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# === APPROVED ===
|
||||
echo '{"decision": "approve"}'
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Capture context facts from tool output or conversation
|
||||
# Called by PostToolUse hooks to extract actionable items
|
||||
#
|
||||
# Stores in ~/.claude/sessions/context.json as:
|
||||
# [{"fact": "...", "source": "core go qa", "ts": 1234567890}, ...]
|
||||
|
||||
CONTEXT_FILE="${HOME}/.claude/sessions/context.json"
|
||||
TIMESTAMP=$(date '+%s')
|
||||
THREE_HOURS=10800
|
||||
|
||||
mkdir -p "${HOME}/.claude/sessions"
|
||||
|
||||
# Initialize if missing or stale
|
||||
if [[ -f "$CONTEXT_FILE" ]]; then
|
||||
FIRST_TS=$(jq -r '.[0].ts // 0' "$CONTEXT_FILE" 2>/dev/null)
|
||||
NOW=$(date '+%s')
|
||||
AGE=$((NOW - FIRST_TS))
|
||||
if [[ $AGE -gt $THREE_HOURS ]]; then
|
||||
echo "[]" > "$CONTEXT_FILE"
|
||||
fi
|
||||
else
|
||||
echo "[]" > "$CONTEXT_FILE"
|
||||
fi
|
||||
|
||||
# Read input (fact and source passed as args or stdin)
|
||||
FACT="${1:-}"
|
||||
SOURCE="${2:-manual}"
|
||||
|
||||
if [[ -z "$FACT" ]]; then
|
||||
# Try reading from stdin
|
||||
read -r FACT
|
||||
fi
|
||||
|
||||
if [[ -n "$FACT" ]]; then
|
||||
# Append to context (keep last 20 items)
|
||||
jq --arg fact "$FACT" --arg source "$SOURCE" --argjson ts "$TIMESTAMP" \
|
||||
'. + [{"fact": $fact, "source": $source, "ts": $ts}] | .[-20:]' \
|
||||
"$CONTEXT_FILE" > "${CONTEXT_FILE}.tmp" && mv "${CONTEXT_FILE}.tmp" "$CONTEXT_FILE"
|
||||
|
||||
echo "[Context] Saved: $FACT" >&2
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Extract actionable items from core CLI output
|
||||
# Called PostToolUse on Bash commands that run core
|
||||
|
||||
read -r input
|
||||
COMMAND=$(echo "$input" | jq -r '.tool_input.command // empty')
|
||||
OUTPUT=$(echo "$input" | jq -r '.tool_output.output // empty')
|
||||
|
||||
CONTEXT_SCRIPT="$(dirname "$0")/capture-context.sh"
|
||||
|
||||
# Extract actionables from specific core commands
|
||||
case "$COMMAND" in
|
||||
"core go qa"*|"core go test"*|"core go lint"*)
|
||||
# Extract error/warning lines
|
||||
echo "$OUTPUT" | grep -E "^(ERROR|WARN|FAIL|---)" | head -5 | while read -r line; do
|
||||
"$CONTEXT_SCRIPT" "$line" "core go"
|
||||
done
|
||||
;;
|
||||
"core php test"*|"core php analyse"*)
|
||||
# Extract PHP errors
|
||||
echo "$OUTPUT" | grep -E "^(FAIL|Error|×)" | head -5 | while read -r line; do
|
||||
"$CONTEXT_SCRIPT" "$line" "core php"
|
||||
done
|
||||
;;
|
||||
"core build"*)
|
||||
# Extract build errors
|
||||
echo "$OUTPUT" | grep -E "^(error|cannot|undefined)" | head -5 | while read -r line; do
|
||||
"$CONTEXT_SCRIPT" "$line" "core build"
|
||||
done
|
||||
;;
|
||||
esac
|
||||
|
||||
# Pass through
|
||||
echo "$input"
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Post-commit hook: Check for uncommitted work that might get lost
|
||||
#
|
||||
# After committing task-specific files, check if there's other work
|
||||
# in the repo that should be committed or stashed
|
||||
|
||||
read -r input
|
||||
COMMAND=$(echo "$input" | jq -r '.tool_input.command // empty')
|
||||
|
||||
# Only run after git commit
|
||||
if ! echo "$COMMAND" | grep -qE '^git commit'; then
|
||||
echo "$input"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check for remaining uncommitted changes
|
||||
UNSTAGED=$(git diff --name-only 2>/dev/null | wc -l | tr -d ' ')
|
||||
STAGED=$(git diff --cached --name-only 2>/dev/null | wc -l | tr -d ' ')
|
||||
UNTRACKED=$(git ls-files --others --exclude-standard 2>/dev/null | wc -l | tr -d ' ')
|
||||
|
||||
TOTAL=$((UNSTAGED + STAGED + UNTRACKED))
|
||||
|
||||
if [[ $TOTAL -gt 0 ]]; then
|
||||
echo "" >&2
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" >&2
|
||||
echo "[PostCommit] WARNING: Uncommitted work remains" >&2
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" >&2
|
||||
|
||||
if [[ $UNSTAGED -gt 0 ]]; then
|
||||
echo " Modified (unstaged): $UNSTAGED files" >&2
|
||||
git diff --name-only 2>/dev/null | head -5 | sed 's/^/ /' >&2
|
||||
[[ $UNSTAGED -gt 5 ]] && echo " ... and $((UNSTAGED - 5)) more" >&2
|
||||
fi
|
||||
|
||||
if [[ $STAGED -gt 0 ]]; then
|
||||
echo " Staged (not committed): $STAGED files" >&2
|
||||
git diff --cached --name-only 2>/dev/null | head -5 | sed 's/^/ /' >&2
|
||||
fi
|
||||
|
||||
if [[ $UNTRACKED -gt 0 ]]; then
|
||||
echo " Untracked: $UNTRACKED files" >&2
|
||||
git ls-files --others --exclude-standard 2>/dev/null | head -5 | sed 's/^/ /' >&2
|
||||
[[ $UNTRACKED -gt 5 ]] && echo " ... and $((UNTRACKED - 5)) more" >&2
|
||||
fi
|
||||
|
||||
echo "" >&2
|
||||
echo "Consider: commit these, stash them, or confirm they're intentionally left" >&2
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" >&2
|
||||
fi
|
||||
|
||||
echo "$input"
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Log PR URL and provide review command after PR creation
|
||||
|
||||
read -r input
|
||||
COMMAND=$(echo "$input" | jq -r '.tool_input.command // empty')
|
||||
OUTPUT=$(echo "$input" | jq -r '.tool_output.output // empty')
|
||||
|
||||
if [[ "$COMMAND" == *"gh pr create"* ]]; then
|
||||
PR_URL=$(echo "$OUTPUT" | grep -oE 'https://github.com/[^/]+/[^/]+/pull/[0-9]+' | head -1)
|
||||
if [[ -n "$PR_URL" ]]; then
|
||||
REPO=$(echo "$PR_URL" | sed -E 's|https://github.com/([^/]+/[^/]+)/pull/[0-9]+|\1|')
|
||||
PR_NUM=$(echo "$PR_URL" | sed -E 's|.*/pull/([0-9]+)|\1|')
|
||||
echo "[Hook] PR created: $PR_URL" >&2
|
||||
echo "[Hook] To review: gh pr review $PR_NUM --repo $REPO" >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "$input"
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Suggest /compact at logical intervals to manage context window
|
||||
# Tracks tool calls per session, suggests compaction every 50 calls
|
||||
|
||||
SESSION_ID="${CLAUDE_SESSION_ID:-$$}"
|
||||
COUNTER_FILE="/tmp/claude-tool-count-${SESSION_ID}"
|
||||
THRESHOLD="${COMPACT_THRESHOLD:-50}"
|
||||
|
||||
# Read or initialize counter
|
||||
if [[ -f "$COUNTER_FILE" ]]; then
|
||||
COUNT=$(($(cat "$COUNTER_FILE") + 1))
|
||||
else
|
||||
COUNT=1
|
||||
fi
|
||||
|
||||
echo "$COUNT" > "$COUNTER_FILE"
|
||||
|
||||
# Suggest compact at threshold
|
||||
if [[ $COUNT -eq $THRESHOLD ]]; then
|
||||
echo "[Compact] ${THRESHOLD} tool calls - consider /compact if transitioning phases" >&2
|
||||
fi
|
||||
|
||||
# Suggest at intervals after threshold
|
||||
if [[ $COUNT -gt $THRESHOLD ]] && [[ $((COUNT % 25)) -eq 0 ]]; then
|
||||
echo "[Compact] ${COUNT} tool calls - good checkpoint for /compact" >&2
|
||||
fi
|
||||
|
||||
exit 0
|
||||
Loading…
Add table
Reference in a new issue