fix(skills): frontmatter lint — using-interns v0.3.1 (YAML+≤1024), using-wiki-graph v0.1.1 (≤1024), ralph-loop-execution frontmatter, remove using-yt-tools stub, add scripts/lint-skills.py + wire into update.{sh,ps1}
This commit is contained in:
85
scripts/lint-skills.py
Normal file
85
scripts/lint-skills.py
Normal file
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env python3
|
||||
"""lint-skills.py — Agent Skills spec lint over a skills catalog.
|
||||
|
||||
Checks every SKILL.md:
|
||||
1. frontmatter parses as YAML
|
||||
2. `description` present and <= 1024 chars (spec cap)
|
||||
3. required fields present: name, description (version optional-but-encouraged)
|
||||
|
||||
Exit code 0 = clean, 1 = violations found (prints them).
|
||||
Usage: python lint-skills.py [skills-dir] (default: ./skills)
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
try:
|
||||
import yaml
|
||||
except ImportError:
|
||||
print("error: PyYAML required (pip install pyyaml)", file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
MAX_DESC = 1024
|
||||
REQUIRED = ("name", "description")
|
||||
|
||||
|
||||
def lint_one(path):
|
||||
"""Return list of violation strings for one SKILL.md."""
|
||||
problems = []
|
||||
txt = open(path, encoding="utf-8").read()
|
||||
if not txt.startswith("---"):
|
||||
return [f"{path}: missing frontmatter (must start with ---)"]
|
||||
try:
|
||||
fm = txt.split("---", 2)[1]
|
||||
d = yaml.safe_load(fm)
|
||||
except Exception as e:
|
||||
return [f"{path}: frontmatter YAML parse error: {str(e)[:80]}"]
|
||||
if not isinstance(d, dict):
|
||||
return [f"{path}: frontmatter is not a mapping"]
|
||||
for f in REQUIRED:
|
||||
if not d.get(f):
|
||||
problems.append(f"{path}: missing required field '{f}'")
|
||||
desc = d.get("description") or ""
|
||||
if len(desc) > MAX_DESC:
|
||||
problems.append(f"{path}: description exceeds {MAX_DESC} chars ({len(desc)})")
|
||||
return problems
|
||||
|
||||
|
||||
def warn_one(path):
|
||||
"""Soft findings (not spec violations)."""
|
||||
warnings = []
|
||||
txt = open(path, encoding="utf-8").read()
|
||||
if not txt.startswith("---"):
|
||||
return warnings
|
||||
d = yaml.safe_load(txt.split("---", 2)[1])
|
||||
if isinstance(d, dict) and not d.get("version"):
|
||||
warnings.append(f"{path}: missing version (encouraged)")
|
||||
return warnings
|
||||
|
||||
|
||||
def main():
|
||||
root = sys.argv[1] if len(sys.argv) > 1 else "skills"
|
||||
if not os.path.isdir(root):
|
||||
print(f"error: not a directory: {root}", file=sys.stderr)
|
||||
return 2
|
||||
all_problems = []
|
||||
all_warnings = []
|
||||
count = 0
|
||||
for dirpath, dirnames, filenames in os.walk(root):
|
||||
if "SKILL.md" in filenames:
|
||||
count += 1
|
||||
p = os.path.join(dirpath, "SKILL.md")
|
||||
all_problems.extend(lint_one(p))
|
||||
all_warnings.extend(warn_one(p))
|
||||
for w in all_warnings:
|
||||
print(" W: " + w)
|
||||
if all_problems:
|
||||
print(f"lint: {count} skills, {len(all_problems)} violations:")
|
||||
for p in all_problems:
|
||||
print(" " + p)
|
||||
return 1
|
||||
print(f"lint: {count} skills, 0 violations ({len(all_warnings)} warnings)")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -133,6 +133,10 @@ if (Test-Path (Join-Path $internsMcp '.git')) {
|
||||
|
||||
Pop-Location
|
||||
Write-Host "[update] Installing skills..." -ForegroundColor Cyan
|
||||
# 0. Lint skills against Agent Skills spec (fail on violations)
|
||||
& python "$root\scripts\lint-skills.py" "$root\skills" 2>$null
|
||||
if ($LASTEXITCODE -ne 0) { Write-Host "[update] SKILL.md lint failed - fix before install" -ForegroundColor Red; exit 1 }
|
||||
# 1. Install all skills via install.ps1
|
||||
& "$root\scripts\install.ps1"
|
||||
Write-Host "[ok] Skills installed." -ForegroundColor Green
|
||||
|
||||
|
||||
@@ -123,7 +123,10 @@ fi
|
||||
|
||||
cd "$ROOT"
|
||||
info "Installing skills..."
|
||||
bash "$ROOT/scripts/install.sh"
|
||||
# 0. Lint skills against Agent Skills spec (fail on violations)
|
||||
python "$ROOT/scripts/lint-skills.py" "$ROOT/skills" || { error "SKILL.md lint failed - fix before install"; exit 1; }
|
||||
# 1. Install all skills via install.sh
|
||||
bash "$ROOT/scripts/install.sh"
|
||||
ok "Skills installed."
|
||||
|
||||
# ── Step 5: Version diff ───────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user