feat(skills): add per-task skill spec auto-detection and injection

Replace external inject-spec.py hook with built-in zero-config skill
detection in codeagent-wrapper. The system auto-detects project type
from fingerprint files (go.mod, package.json, etc.), maps to installed
skills, and injects SKILL.md content directly into sub-agent prompts.

Key changes:
- Add DetectProjectSkills/ResolveSkillContent in executor/prompt.go
- Add Skills field to TaskSpec with parallel config parsing
- Add --skills CLI flag for explicit override
- Update /do SKILL.md Phase 4 with per-task skill examples
- Remove on-stop.py global hook (not needed)
- Replace inject-spec.py with no-op (detection now internal)
- Add 20 unit tests covering detection, resolution, budget, security

Security: path traversal protection via validSkillName regex,
16K char budget with tag overhead accounting, CRLF normalization.

Generated with SWE-Agent.ai

Co-Authored-By: SWE-Agent.ai <noreply@swe-agent.ai>
This commit is contained in:
cexll
2026-02-09 11:06:36 +08:00
parent 5853539cab
commit 97dfa907d9
24 changed files with 1699 additions and 419 deletions

30
hooks/hooks.json Normal file
View File

@@ -0,0 +1,30 @@
{
"description": "ClaudeKit global hooks: dangerous command blocker, spec injection, prompt logging, session review",
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/pre-bash.py \"$CLAUDE_TOOL_INPUT\""
},
{
"type": "command",
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/inject-spec.py"
}
]
}
],
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/log-prompt.py"
}
]
}
]
}
}

13
hooks/inject-spec.py Normal file
View File

@@ -0,0 +1,13 @@
#!/usr/bin/env python3
"""
Global Spec Injection Hook (DEPRECATED).
Spec injection is now handled internally by codeagent-wrapper via the
per-task `skills:` field in parallel config and the `--skills` CLI flag.
This hook is kept as a no-op for backward compatibility.
"""
import sys
sys.exit(0)

55
hooks/log-prompt.py Normal file
View File

@@ -0,0 +1,55 @@
#!/usr/bin/env python3
"""
Log Prompt Hook - Record user prompts to session-specific log files.
Used for review on Stop.
Uses session-isolated logs to handle concurrency.
"""
import json
import os
import sys
from datetime import datetime
from pathlib import Path
def get_session_id() -> str:
"""Get unique session identifier."""
return os.environ.get("CLAUDE_CODE_SSE_PORT", "default")
def write_log(prompt: str) -> None:
"""Write prompt to session log file."""
log_dir = Path(".claude/state")
session_id = get_session_id()
log_file = log_dir / f"session-{session_id}.log"
log_dir.mkdir(parents=True, exist_ok=True)
timestamp = datetime.now().isoformat()
entry = f"[{timestamp}] {prompt[:500]}\n"
with open(log_file, "a", encoding="utf-8") as f:
f.write(entry)
def main():
input_data = ""
if not sys.stdin.isatty():
try:
input_data = sys.stdin.read()
except Exception:
pass
prompt = ""
try:
data = json.loads(input_data)
prompt = data.get("prompt", "")
except json.JSONDecodeError:
prompt = input_data.strip()
if prompt:
write_log(prompt)
if __name__ == "__main__":
main()

30
hooks/pre-bash.py Normal file
View File

@@ -0,0 +1,30 @@
#!/usr/bin/env python3
"""
Pre-Bash Hook - Block dangerous commands before execution.
"""
import sys
DANGEROUS_PATTERNS = [
'rm -rf /',
'rm -rf ~',
'dd if=',
':(){:|:&};:',
'mkfs.',
'> /dev/sd',
]
def main():
command = sys.argv[1] if len(sys.argv) > 1 else ''
for pattern in DANGEROUS_PATTERNS:
if pattern in command:
print(f"[CWF] BLOCKED: Dangerous command detected: {pattern}", file=sys.stderr)
sys.exit(1)
sys.exit(0)
if __name__ == "__main__":
main()