Files
mini-openclaw/backend/tools/skills_scanner.py
T

68 lines
2.5 KiB
Python

"""Skills Scanner — Scan skills/ directory and generate SKILLS_SNAPSHOT.md."""
from pathlib import Path
from hashlib import sha256
import yaml
def discover_skills(base_dir: Path) -> list[dict]:
"""Read the native Skills catalog without changing its generated snapshot."""
root = (base_dir / "skills").resolve()
entries = []
for file in sorted(root.rglob("SKILL.md")):
resolved = file.resolve()
if not resolved.is_relative_to(root):
continue
try:
content = file.read_text(encoding="utf-8")
if not content.startswith("---"):
continue
parts = content.split("---", 2)
meta = yaml.safe_load(parts[1]) if len(parts) == 3 else None
if not isinstance(meta, dict):
continue
legacy_id = file.relative_to(root).as_posix()
entries.append({
"id": legacy_id,
"component_id": str(meta.get("id", legacy_id)),
"legacy_id": legacy_id,
"kind": str(meta.get("kind", "skill")),
"version": str(meta.get("version", "legacy")),
"schema_version": int(meta.get("schema_version", 1)),
"status": str(meta.get("status", "published")),
"name": str(meta.get("name", file.parent.name)),
"description": str(meta.get("description", "")),
"content_hash": sha256(content.encode("utf-8")).hexdigest(),
"content": content,
})
except (OSError, ValueError, TypeError, yaml.YAMLError):
continue
return entries
def scan_skills(base_dir: Path) -> str:
"""Scan all SKILL.md files and generate SKILLS_SNAPSHOT.md."""
skills_dir = base_dir / "skills"
snapshot_path = base_dir / "SKILLS_SNAPSHOT.md"
if not skills_dir.exists():
skills_dir.mkdir(parents=True)
skills = [{**s, "location":f"./backend/skills/{s['legacy_id']}"} for s in discover_skills(base_dir)]
# Build XML-style snapshot
lines = ["<available_skills>"]
for s in skills:
lines.append(" <skill>")
lines.append(f" <name>{s['name']}</name>")
lines.append(f" <description>{s['description']}</description>")
lines.append(f" <location>{s['location']}</location>")
lines.append(" </skill>")
lines.append("</available_skills>")
snapshot = "\n".join(lines)
snapshot_path.write_text(snapshot, encoding="utf-8")
print(f"📋 Skills snapshot: {len(skills)} skills found")
return snapshot