TradingAgents/.claude/hooks/validate_hooks_documented.py

111 lines
2.9 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Validate All Hooks Documented - Pre-commit Hook
Ensures every hook in hooks/ directory is documented in docs/HOOKS.md.
Blocks commits if new hooks are added without documentation.
Usage:
python3 validate_hooks_documented.py
Exit Codes:
0 - All hooks documented
1 - Some hooks missing from docs
"""
import re
import sys
from pathlib import Path
def get_project_root() -> Path:
"""Find project root by looking for .git directory."""
current = Path.cwd()
while current != current.parent:
if (current / ".git").exists():
return current
current = current.parent
return Path.cwd()
def get_documented_hooks(hooks_md: Path) -> set[str]:
"""Extract hook names documented in HOOKS.md.
Returns:
Set of hook names (without .py extension)
"""
if not hooks_md.exists():
return set()
content = hooks_md.read_text()
# Match "### hook_name.py" or "### hook_name"
pattern = r'^###\s+([a-z_]+)(?:\.py)?'
matches = re.findall(pattern, content, re.MULTILINE)
return set(matches)
def get_source_hooks(hooks_dir: Path) -> set[str]:
"""Get all hook names from source directory.
Returns:
Set of hook names (without .py extension)
"""
if not hooks_dir.exists():
return set()
hooks = set()
for f in hooks_dir.glob("*.py"):
if f.name.startswith("test_") or f.name == "__init__.py":
continue
hooks.add(f.stem)
return hooks
def validate_hooks_documented() -> tuple[bool, list[str]]:
"""Validate all hooks are documented in HOOKS.md.
Returns:
Tuple of (success, list of undocumented hooks)
"""
project_root = get_project_root()
plugin_dir = project_root / "plugins" / "autonomous-dev"
hooks_dir = plugin_dir / "hooks"
hooks_md = project_root / "docs" / "HOOKS.md"
if not hooks_md.exists():
return True, [] # No docs file, skip validation
source_hooks = get_source_hooks(hooks_dir)
documented_hooks = get_documented_hooks(hooks_md)
# Find undocumented hooks
undocumented = source_hooks - documented_hooks
return len(undocumented) == 0, sorted(undocumented)
def main() -> int:
"""Main entry point."""
success, undocumented = validate_hooks_documented()
if success:
print("✅ All hooks documented in HOOKS.md")
return 0
else:
print("❌ Undocumented hooks detected!")
print("")
print(f"Missing from docs/HOOKS.md ({len(undocumented)}):")
for hook in undocumented:
print(f" - {hook}.py")
print("")
print("Fix: Add documentation for each hook to docs/HOOKS.md")
print("Format:")
print(" ### hook_name.py")
print(" **Purpose**: What it does")
print(" **Lifecycle**: PreCommit/SubagentStop/etc")
return 1
if __name__ == "__main__":
sys.exit(main())