claude-skills/engineering-team/self-improving-agent/hooks/error-capture.sh
Claude 3349509db4
fix(scripts,plugins): exclude tool-sync dirs from convert.sh; rename si plugin's status/review skills
- convert.sh's SKILL.md finder now excludes .claude, .codex, .codex-plugin,
  .gemini, .hermes, .vibe, and docs — these are generated/symlinked mirrors
  for other tools, not source-of-truth skills. On platforms where git
  materializes symlinks as plain text (e.g. Git Bash on Windows), the
  mirrored files were being parsed as SKILL.md candidates and failing
  frontmatter extraction, flooding the run with "Skipping invalid
  frontmatter" warnings (#897).

- Renamed the self-improving-agent (si) plugin's `status` and `review`
  skills to `memory-status` and `memory-review` so their bare `name:`
  values no longer collide with Claude Code's built-in `/status` and
  `/review` commands (#885). Updated all in-plugin references
  (CLAUDE.md, README, agents, hooks, references, settings.json,
  plugin.json) to the new `/si:memory-status` / `/si:memory-review`
  invocations.

Fixes #897 (duplicate of #896), #885.
2026-07-08 05:37:03 +00:00

119 lines
3.1 KiB
Bash
Executable file

#!/bin/bash
# Self-Improving Agent — Error Capture Hook
# Fires on PostToolUse (Bash) to detect command failures.
# Zero output on success — only captures when errors are detected.
#
# When installed via `/plugin install self-improving-agent@claude-code-skills`
# this hook is registered automatically from the plugin's hooks.json. No
# manual wiring is required.
#
# If you need to wire it up manually, use ${CLAUDE_PLUGIN_ROOT} — a relative
# path like ./hooks/error-capture.sh resolves against your current working
# directory, not the plugin root, and will silently fail in every session
# started outside the plugin install dir.
#
# .claude/settings.json:
# {
# "hooks": {
# "PostToolUse": [{
# "matcher": "Bash",
# "hooks": [{
# "type": "command",
# "command": "${CLAUDE_PLUGIN_ROOT}/hooks/error-capture.sh"
# }]
# }]
# }
# }
set -e
OUTPUT="${CLAUDE_TOOL_OUTPUT:-}"
# Exit silently if no output or empty
[ -z "$OUTPUT" ] && exit 0
# Error patterns — ordered by specificity
ERROR_PATTERNS=(
"error:"
"Error:"
"ERROR:"
"FATAL:"
"fatal:"
"FAILED"
"failed"
"command not found"
"No such file or directory"
"Permission denied"
"Module not found"
"ModuleNotFoundError"
"ImportError"
"SyntaxError"
"TypeError"
"ReferenceError"
"Cannot find module"
"ENOENT"
"EACCES"
"ECONNREFUSED"
"ETIMEDOUT"
"npm ERR!"
"pnpm ERR!"
"Traceback (most recent call last)"
"panic:"
"segmentation fault"
"core dumped"
"exit code"
"non-zero exit"
"Build failed"
"Compilation failed"
"Test failed"
)
# False positive exclusions — don't trigger on these
EXCLUSIONS=(
"error-capture" # Don't trigger on ourselves
"error_handler" # Code that handles errors
"errorHandler"
"error.log" # Log file references
"console.error" # Code that logs errors
"catch (error" # Error handling code
"catch (err"
".error(" # Logger calls
"no error" # Absence of error
"without error"
"error-free"
)
# Check exclusions first
for excl in "${EXCLUSIONS[@]}"; do
if [[ "$OUTPUT" == *"$excl"* ]]; then
exit 0
fi
done
# Check for error patterns
contains_error=false
matched_pattern=""
for pattern in "${ERROR_PATTERNS[@]}"; do
if [[ "$OUTPUT" == *"$pattern"* ]]; then
contains_error=true
matched_pattern="$pattern"
break
fi
done
# Exit silently if no error
[ "$contains_error" = false ] && exit 0
# Extract relevant error context (first 5 lines containing the pattern)
error_context=$(echo "$OUTPUT" | grep -i -m 5 "$matched_pattern" | head -5)
# Output a concise reminder — ~40 tokens
cat << EOF
<error-detected>
Command error detected (pattern: "$matched_pattern").
If this was unexpected or required investigation to fix, save the solution:
/si:remember "explanation of what went wrong and the fix"
Or if this is a known pattern, check: /si:memory-review
Context: $(echo "$error_context" | head -2 | tr '\n' ' ' | cut -c1-200)
</error-detected>
EOF