mirror of
https://github.com/cexll/myclaude.git
synced 2026-02-13 03:31:49 +08:00
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:
30
hooks/hooks.json
Normal file
30
hooks/hooks.json
Normal 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
13
hooks/inject-spec.py
Normal 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
55
hooks/log-prompt.py
Normal 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
30
hooks/pre-bash.py
Normal 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()
|
||||
Reference in New Issue
Block a user