refactor(hooks): use sessionStart.skill instead of command hooks
- Replace SessionStart command hook with plugin.json's native sessionStart.skill field (like Superpowers' using-superpowers pattern) - engineering-principles skill auto-loads at every session start - Remove hooks/session-start, hooks/run-hook.cmd scripts - Remove obsolete setup-hooks.sh (references deleted scripts) - Empty hooks.json — hooks not needed, skill auto-load handles it
This commit is contained in:
@@ -8,5 +8,7 @@
|
|||||||
},
|
},
|
||||||
"keywords": ["best-practice", "clean-code", "engineering-guide", "programming-standards", "architecture"],
|
"keywords": ["best-practice", "clean-code", "engineering-guide", "programming-standards", "architecture"],
|
||||||
"skills": "./skills/",
|
"skills": "./skills/",
|
||||||
"hooks": "./hooks/hooks.json"
|
"sessionStart": {
|
||||||
|
"skill": "engineering-principles"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-14
@@ -1,16 +1,3 @@
|
|||||||
{
|
{
|
||||||
"hooks": {
|
"hooks": {}
|
||||||
"SessionStart": [
|
|
||||||
{
|
|
||||||
"matcher": "startup|clear|compact",
|
|
||||||
"hooks": [
|
|
||||||
{
|
|
||||||
"type": "command",
|
|
||||||
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cmd\" session-start",
|
|
||||||
"async": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
: << 'CMDBLOCK'
|
|
||||||
@echo off
|
|
||||||
REM Cross-platform polyglot wrapper for hook scripts.
|
|
||||||
REM On Windows: cmd.exe runs the batch portion, which finds and calls bash.
|
|
||||||
REM On Unix: the shell interprets this as a script (: is a no-op in bash).
|
|
||||||
REM
|
|
||||||
REM Hook scripts use extensionless filenames so Claude Code's Windows
|
|
||||||
REM auto-detection doesn't interfere.
|
|
||||||
REM
|
|
||||||
REM Usage: run-hook.cmd <script-name> [args...]
|
|
||||||
|
|
||||||
if "%~1"=="" (
|
|
||||||
echo run-hook.cmd: missing script name >&2
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
|
|
||||||
set "HOOK_DIR=%~dp0"
|
|
||||||
|
|
||||||
REM Try Git for Windows bash in standard locations
|
|
||||||
if exist "C:\Program Files\Git\bin\bash.exe" (
|
|
||||||
"C:\Program Files\Git\bin\bash.exe" "%HOOK_DIR%%~1" %2 %3 %4 %5 %6 %7 %8 %9
|
|
||||||
exit /b %ERRORLEVEL%
|
|
||||||
)
|
|
||||||
if exist "C:\Program Files (x86)\Git\bin\bash.exe" (
|
|
||||||
"C:\Program Files (x86)\Git\bin\bash.exe" "%HOOK_DIR%%~1" %2 %3 %4 %5 %6 %7 %8 %9
|
|
||||||
exit /b %ERRORLEVEL%
|
|
||||||
)
|
|
||||||
|
|
||||||
REM Try bash on PATH
|
|
||||||
where bash >nul 2>nul
|
|
||||||
if %ERRORLEVEL% equ 0 (
|
|
||||||
bash "%HOOK_DIR%%~1" %2 %3 %4 %5 %6 %7 %8 %9
|
|
||||||
exit /b %ERRORLEVEL%
|
|
||||||
)
|
|
||||||
|
|
||||||
REM No bash found — exit silently
|
|
||||||
exit /b 0
|
|
||||||
CMDBLOCK
|
|
||||||
|
|
||||||
# Unix: run the named script directly
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
||||||
SCRIPT_NAME="$1"
|
|
||||||
shift
|
|
||||||
exec bash "${SCRIPT_DIR}/${SCRIPT_NAME}" "$@"
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# SessionStart hook for code-guide plugin
|
|
||||||
# Injects mandatory skill context at session start (like Superpowers pattern)
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# Determine plugin root directory
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
||||||
PLUGIN_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
||||||
|
|
||||||
SKILLS_DIR="${PLUGIN_ROOT}/skills"
|
|
||||||
|
|
||||||
# Build the context string by extracting descriptions from mandatory skill SKILL.md files
|
|
||||||
build_context() {
|
|
||||||
local ctx=""
|
|
||||||
|
|
||||||
ctx="${ctx}<EXTREMELY_IMPORTANT>\n"
|
|
||||||
ctx="${ctx}You have the code-guide plugin loaded. The following MANDATORY skills apply to EVERY coding task — load them via the Skill tool whenever relevant:\n\n"
|
|
||||||
|
|
||||||
# Read each mandatory skill's frontmatter
|
|
||||||
local mandatory="engineering-principles clean-code clean-architecture testing error-handling security git-workflow api-design"
|
|
||||||
|
|
||||||
for skill in $mandatory; do
|
|
||||||
local file="${SKILLS_DIR}/${skill}/SKILL.md"
|
|
||||||
if [ -f "$file" ]; then
|
|
||||||
# Extract description line — strip "description:" prefix and optional quotes
|
|
||||||
local desc
|
|
||||||
desc=$(grep "^description:" "$file" | head -1 | cut -d: -f2- | tr -d '\n')
|
|
||||||
desc="${desc#\"}" # strip leading quote if present
|
|
||||||
desc="${desc%\"}" # strip trailing quote if present
|
|
||||||
desc="$(echo "$desc" | awk '{$1=$1};1')" # trim whitespace
|
|
||||||
ctx="${ctx}• code-guide:${skill} — ${desc}\n"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
ctx="${ctx}\n"
|
|
||||||
|
|
||||||
# Add non-mandatory skills list (so Claude knows they exist)
|
|
||||||
ctx="${ctx}Other available skills (non-mandatory — trigger when relevant):\n"
|
|
||||||
ctx="${ctx}typescript, python, rust, go, react-frontend, nextjs, hono-backend, elysiajs, drizzle-database, docker, ci-cd, monitoring, logging-observability, performance, documentation, design-patterns, monorepo\n"
|
|
||||||
|
|
||||||
ctx="${ctx}\n"
|
|
||||||
ctx="${ctx}<EXTREMELY_IMPORTANT>Rules you MUST follow at all times:\n"
|
|
||||||
ctx="${ctx}1. NEVER suppress lints/type errors — fix the code instead.\n"
|
|
||||||
ctx="${ctx}2. NEVER assume — show evidence from codebase/docs for everything.\n"
|
|
||||||
ctx="${ctx}3. ASK when ambiguous — don't silently pick one interpretation.\n"
|
|
||||||
ctx="${ctx}4. Use the Workflow tool for complex multi-step tasks that need parallel execution or adversarial verification.\n"
|
|
||||||
ctx="${ctx}5. Fix root causes, not symptoms — patch the shared function, not every caller.\n"
|
|
||||||
ctx="${ctx}6. Tests come first — code without tests is legacy code.\n"
|
|
||||||
ctx="${ctx}7. The simplest solution that works is the correct one (YAGNI/KISS).\n"
|
|
||||||
ctx="${ctx}8. Leave every module cleaner than you found it (Boy Scout Rule).\n"
|
|
||||||
|
|
||||||
ctx="${ctx}\n"
|
|
||||||
ctx="${ctx}When you need the full content of any skill, use the Skill tool to load it.\n"
|
|
||||||
ctx="${ctx}</EXTREMELY_IMPORTANT>"
|
|
||||||
|
|
||||||
printf '%s' "$ctx"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Escape string for JSON embedding
|
|
||||||
escape_for_json() {
|
|
||||||
local s="$1"
|
|
||||||
s="${s//\\/\\\\}"
|
|
||||||
s="${s//\"/\\\"}"
|
|
||||||
s="${s//$'\n'/\\n}"
|
|
||||||
s="${s//$'\r'/\\r}"
|
|
||||||
s="${s//$'\t'/\\t}"
|
|
||||||
printf '%s' "$s"
|
|
||||||
}
|
|
||||||
|
|
||||||
context=$(build_context)
|
|
||||||
escaped_context=$(escape_for_json "$context")
|
|
||||||
|
|
||||||
# Output JSON for Claude Code (hookSpecificOutput.additionalContext format)
|
|
||||||
printf '{"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":"%s"}}\n' "$escaped_context"
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# setup-hooks.sh — Configure code-guide hooks in Claude Code
|
|
||||||
#
|
|
||||||
# Adds code-guide hooks to ~/.claude/settings.local.json
|
|
||||||
# This allows Claude to auto-detect your project and suggest relevant skills.
|
|
||||||
#
|
|
||||||
# Usage: ./setup-hooks.sh
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
SETTINGS_FILE="${HOME}/.claude/settings.local.json"
|
|
||||||
|
|
||||||
echo "code-guide hooks setup"
|
|
||||||
|
|
||||||
python3 << PYEOF
|
|
||||||
import json, os
|
|
||||||
|
|
||||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
settings_file = os.path.expanduser("~/.claude/settings.local.json")
|
|
||||||
|
|
||||||
# Read existing or create empty
|
|
||||||
if os.path.exists(settings_file):
|
|
||||||
with open(settings_file) as f:
|
|
||||||
cfg = json.load(f)
|
|
||||||
else:
|
|
||||||
cfg = {}
|
|
||||||
|
|
||||||
# Build hooks config
|
|
||||||
cfg["hooks"] = {
|
|
||||||
"SessionStart": [{
|
|
||||||
"hooks": [{
|
|
||||||
"type": "command",
|
|
||||||
"command": f"bash \"{script_dir}/hooks/scripts/detect-project.sh\"",
|
|
||||||
"timeout": 10
|
|
||||||
}]
|
|
||||||
}],
|
|
||||||
"PreToolUse": [{
|
|
||||||
"matcher": "Write|Edit",
|
|
||||||
"hooks": [{
|
|
||||||
"type": "command",
|
|
||||||
"command": f"bash \"{script_dir}/hooks/scripts/detect-file-type.sh\" \"\$TOOL_INPUT\"",
|
|
||||||
"timeout": 10
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
|
|
||||||
# Ensure parent dir exists
|
|
||||||
os.makedirs(os.path.dirname(settings_file), exist_ok=True)
|
|
||||||
|
|
||||||
with open(settings_file, 'w') as f:
|
|
||||||
json.dump(cfg, f, indent=2)
|
|
||||||
|
|
||||||
print(f"Hooks configured in {settings_file}")
|
|
||||||
PYEOF
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "Restart Claude Code or run /reload to activate hooks."
|
|
||||||
Reference in New Issue
Block a user