#!/usr/bin/env python3 """Validate dsh-skills catalog: each skills//SKILL.md frontmatter must carry required name and description, with kebab-case names (the contract enforced by @deepseek-ai/dsh-skill-filesystem). Exits non-zero on any issue.""" import re import sys from pathlib import Path def main(root: str) -> int: base = Path(root) / "skills" if not base.is_dir(): print(f"no skills dir at {base}", file=sys.stderr) return 1 errors = 0 examined = 0 for d in sorted(p for p in base.iterdir() if p.is_dir()): md = d / "SKILL.md" if not md.is_file(): print(f"[warn] {d.name}: missing SKILL.md", file=sys.stderr) errors += 1 continue examined += 1 text = md.read_text(encoding="utf-8") m = re.match(r"^---\n([\s\S]*?)\n---", text) if not m: print(f"[error] {d.name}: no frontmatter", file=sys.stderr) errors += 1 continue fm = m.group(1) name = re.search(r"^name:\s*(\S.*)$", fm, re.M) desc = re.search(r"^description:\s*(\S.*)$", fm, re.M) if not name: print(f"[error] {d.name}: missing 'name'", file=sys.stderr) errors += 1 else: n = name.group(1).strip() if n != d.name: print(f"[error] {d.name}: frontmatter name '{n}' != dir name", file=sys.stderr) errors += 1 if not re.fullmatch(r"[a-z0-9]+(-[a-z0-9]+)*", n): print(f"[error] {d.name}: name not kebab-case: '{n}'", file=sys.stderr) errors += 1 if not desc: print(f"[error] {d.name}: missing 'description'", file=sys.stderr) errors += 1 print(f"checked {examined} skills, {errors} problems") return 1 if errors else 0 if __name__ == "__main__": root = sys.argv[1] if len(sys.argv) > 1 else "." sys.exit(main(root))