Files
claude-code/automation/validate-registry.py
OpenCode Test 3132948246 Implement component registry for PA session awareness
Components:
- state/component-registry.json: Registry with all skills, commands, agents, workflows
- automation/generate-registry.py: Auto-generate from directory scan
- automation/validate-registry.py: Check for drift and TODO placeholders
- system-instructions.json: Added component-lifecycle process

Registry includes:
- 6 skills with routing triggers
- 10 commands with aliases
- 12 agents with model info
- 10 workflows with triggers
- 2 delegation helpers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 00:08:11 -08:00

156 lines
4.6 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Validate Component Registry
Checks that the registry is in sync with actual component files.
Usage:
python3 validate-registry.py
Exit codes:
0 - All valid
1 - Warnings (stale entries)
2 - Errors (missing entries or TODO placeholders)
"""
import json
import sys
from pathlib import Path
CLAUDE_DIR = Path.home() / ".claude"
REGISTRY_PATH = CLAUDE_DIR / "state" / "component-registry.json"
# Scan paths
SCAN_PATHS = {
"skills": (CLAUDE_DIR / "skills", "*/SKILL.md"),
"commands": (CLAUDE_DIR / "commands", "**/*.md"),
"agents": (CLAUDE_DIR / "agents", "*.md"),
"workflows": (CLAUDE_DIR / "workflows", "**/*.yaml"),
}
def get_actual_components() -> dict:
"""Get actual components from filesystem."""
actual = {
"skills": set(),
"commands": set(),
"agents": set(),
"workflows": set(),
}
# Skills
skills_dir = SCAN_PATHS["skills"][0]
if skills_dir.exists():
for skill_dir in skills_dir.iterdir():
if skill_dir.is_dir() and (skill_dir / "SKILL.md").exists():
actual["skills"].add(skill_dir.name)
# Commands
commands_dir = SCAN_PATHS["commands"][0]
if commands_dir.exists():
for cmd_file in commands_dir.rglob("*.md"):
rel_path = cmd_file.relative_to(commands_dir)
cmd_name = "/" + str(rel_path).replace(".md", "").replace("/", ":")
actual["commands"].add(cmd_name)
# Agents
agents_dir = SCAN_PATHS["agents"][0]
if agents_dir.exists():
for agent_file in agents_dir.glob("*.md"):
actual["agents"].add(agent_file.stem)
# Workflows
workflows_dir = SCAN_PATHS["workflows"][0]
if workflows_dir.exists():
for wf_file in workflows_dir.rglob("*.yaml"):
rel_path = wf_file.relative_to(workflows_dir)
actual["workflows"].add(str(rel_path).replace(".yaml", ""))
for wf_file in workflows_dir.rglob("*.yml"):
rel_path = wf_file.relative_to(workflows_dir)
actual["workflows"].add(str(rel_path).replace(".yml", ""))
return actual
def validate_registry() -> int:
"""Validate the registry against actual components."""
print("Registry Validation")
print("=" * 40)
if not REGISTRY_PATH.exists():
print("✗ Registry file not found!")
print(f" Run: python3 generate-registry.py")
return 2
# Load registry
with open(REGISTRY_PATH) as f:
registry = json.load(f)
# Get actual components
actual = get_actual_components()
errors = 0
warnings = 0
for component_type in ["skills", "commands", "agents", "workflows"]:
registered = set(registry.get(component_type, {}).keys())
registered_active = {
k for k, v in registry.get(component_type, {}).items()
if v.get("status") != "removed"
}
actual_set = actual[component_type]
# Check for missing in registry
missing = actual_set - registered
if missing:
print(f"{component_type}: {len(missing)} missing from registry")
for name in sorted(missing):
print(f" + {name}")
errors += len(missing)
# Check for stale entries
stale = registered_active - actual_set
if stale:
print(f"{component_type}: {len(stale)} stale entries")
for name in sorted(stale):
print(f" - {name}")
warnings += len(stale)
# Check for TODO placeholders
for name, data in registry.get(component_type, {}).items():
if data.get("status") == "removed":
continue
if data.get("description") == "TODO":
print(f"{component_type}/{name}: description is TODO")
warnings += 1
if "triggers" in data and data["triggers"] == ["TODO"]:
print(f"{component_type}/{name}: triggers is TODO")
warnings += 1
# Success message if all good
if not missing and not stale:
count = len(actual_set)
print(f"{component_type}: {count} components, all present")
print("=" * 40)
if errors > 0:
print(f"\n{errors} error(s), {warnings} warning(s)")
print(" Run: python3 generate-registry.py")
return 2
elif warnings > 0:
print(f"\n{warnings} warning(s)")
print(" Consider updating registry with manual hints")
return 1
else:
print("\n✓ Registry is valid")
return 0
def main():
sys.exit(validate_registry())
if __name__ == "__main__":
main()