- Rename skill/ to skills/ for consistency with naming conventions - Rename agent/ to agents/ and command/ to commands/ - Update AGENTS.md with all directory references - Update scripts/test-skill.sh paths - Update prompts/athena.txt documentation This aligns with best practices of using plural directory names and updates all documentation to reflect the new structure.
104 lines
3.2 KiB
Python
Executable File
104 lines
3.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Quick validation script for Opencode skills - minimal version
|
|
"""
|
|
|
|
import sys
|
|
import os
|
|
import re
|
|
import yaml
|
|
from pathlib import Path
|
|
|
|
|
|
def validate_skill(skill_path):
|
|
"""Basic validation of a skill"""
|
|
skill_path = Path(skill_path)
|
|
skill_md = skill_path / "SKILL.md"
|
|
|
|
if not skill_md.exists():
|
|
return False, "SKILL.md not found"
|
|
|
|
content = skill_md.read_text()
|
|
if not content.startswith("---"):
|
|
return False, "No YAML frontmatter found"
|
|
|
|
match = re.match(r"^---\n(.*?)\n---", content, re.DOTALL)
|
|
if not match:
|
|
return False, "Invalid frontmatter format"
|
|
|
|
frontmatter_text = match.group(1)
|
|
|
|
try:
|
|
frontmatter = yaml.safe_load(frontmatter_text)
|
|
if not isinstance(frontmatter, dict):
|
|
return False, "Frontmatter must be a YAML dictionary"
|
|
except yaml.YAMLError as e:
|
|
return False, f"Invalid YAML in frontmatter: {e}"
|
|
|
|
ALLOWED_PROPERTIES = {
|
|
"name",
|
|
"description",
|
|
"license",
|
|
"allowed-tools",
|
|
"metadata",
|
|
"compatibility",
|
|
}
|
|
|
|
unexpected_keys = set(frontmatter.keys()) - ALLOWED_PROPERTIES
|
|
if unexpected_keys:
|
|
return False, (
|
|
f"Unexpected key(s) in SKILL.md frontmatter: {', '.join(sorted(unexpected_keys))}. "
|
|
f"Allowed properties are: {', '.join(sorted(ALLOWED_PROPERTIES))}"
|
|
)
|
|
|
|
if "name" not in frontmatter:
|
|
return False, "Missing 'name' in frontmatter"
|
|
if "description" not in frontmatter:
|
|
return False, "Missing 'description' in frontmatter"
|
|
|
|
name = frontmatter.get("name", "")
|
|
if not isinstance(name, str):
|
|
return False, f"Name must be a string, got {type(name).__name__}"
|
|
name = name.strip()
|
|
if name:
|
|
if not re.match(r"^[a-z0-9-]+$", name):
|
|
return (
|
|
False,
|
|
f"Name '{name}' should be hyphen-case (lowercase letters, digits, and hyphens only)",
|
|
)
|
|
if name.startswith("-") or name.endswith("-") or "--" in name:
|
|
return (
|
|
False,
|
|
f"Name '{name}' cannot start/end with hyphen or contain consecutive hyphens",
|
|
)
|
|
if len(name) > 64:
|
|
return (
|
|
False,
|
|
f"Name is too long ({len(name)} characters). Maximum is 64 characters.",
|
|
)
|
|
|
|
description = frontmatter.get("description", "")
|
|
if not isinstance(description, str):
|
|
return False, f"Description must be a string, got {type(description).__name__}"
|
|
description = description.strip()
|
|
if description:
|
|
if "<" in description or ">" in description:
|
|
return False, "Description cannot contain angle brackets (< or >)"
|
|
if len(description) > 1024:
|
|
return (
|
|
False,
|
|
f"Description is too long ({len(description)} characters). Maximum is 1024 characters.",
|
|
)
|
|
|
|
return True, "Skill is valid!"
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) != 2:
|
|
print("Usage: python quick_validate.py <skill_directory>")
|
|
sys.exit(1)
|
|
|
|
valid, message = validate_skill(sys.argv[1])
|
|
print(message)
|
|
sys.exit(0 if valid else 1)
|