116 lines
3.6 KiB
Python
116 lines
3.6 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
OpenJarvis Skills Compatibility Checker
|
|
Verifies that all frontmatter fields are properly mapped in FIELD_MAPPING.
|
|
Usage: python3 check_skill_compatibility.py
|
|
"""
|
|
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
def extract_field_mapping(parser_path):
|
|
"""Extract FIELD_MAPPING from parser.py"""
|
|
content = parser_path.read_text()
|
|
# Find FIELD_MAPPING dictionary
|
|
match = re.search(r'FIELD_MAPPING: Dict\[str, tuple\[str, str\]\] = \{(.*?)\}',
|
|
content, re.DOTALL)
|
|
if not match:
|
|
print("ERROR: Could not find FIELD_MAPPING in parser.py")
|
|
return {}
|
|
|
|
mapping_text = match.group(1)
|
|
# Extract key-value pairs
|
|
fields = {}
|
|
for line in mapping_text.split('\n'):
|
|
m = re.search(r'"(\w+)":\s*\("(\w+)",\s*"(\w+)"\)', line)
|
|
if m:
|
|
fields[m.group(1)] = (m.group(2), m.group(3))
|
|
return fields
|
|
|
|
def check_skill_frontmatter(skill_md_path, mapped_fields):
|
|
"""Check a skill's frontmatter for unmapped fields"""
|
|
content = skill_md_path.read_text()
|
|
if not content.startswith('---'):
|
|
return []
|
|
|
|
# Extract frontmatter
|
|
parts = content.split('---', 2)
|
|
if len(parts) < 3:
|
|
return []
|
|
|
|
frontmatter = parts[1]
|
|
|
|
# Find all field names
|
|
field_pattern = r'^(\w+):'
|
|
found_fields = re.findall(field_pattern, frontmatter, re.MULTILINE)
|
|
|
|
# Standard SPEC_FIELDS from parser.py
|
|
spec_fields = {"name", "description", "license", "compatibility",
|
|
"metadata", "allowed-tools"}
|
|
|
|
unmapped = []
|
|
for field in found_fields:
|
|
if field not in spec_fields and field not in mapped_fields:
|
|
unmapped.append(field)
|
|
|
|
return unmapped
|
|
|
|
def main():
|
|
# Default paths (adjust based on your setup)
|
|
parser_path = Path("src/openjarvis/skills/parser.py")
|
|
skills_dir = Path("~/.openjarvis/skill-cache/hermes/skills").expanduser()
|
|
|
|
if not parser_path.exists():
|
|
print(f"ERROR: {parser_path} not found")
|
|
print("Please run from OpenJarvis source directory")
|
|
sys.exit(1)
|
|
|
|
print("OpenJarvis Skills Compatibility Checker")
|
|
print("=" * 50)
|
|
|
|
# Extract current FIELD_MAPPING
|
|
mapped_fields = extract_field_mapping(parser_path)
|
|
print(f"\nFound {len(mapped_fields)} mapped fields in FIELD_MAPPING:")
|
|
for field, (target, attr) in sorted(mapped_fields.items()):
|
|
print(f" {field} -> {target}.{attr}")
|
|
|
|
if not skills_dir.exists():
|
|
print(f"\nNote: Skills cache not found at {skills_dir}")
|
|
print("Run 'jarvis skill sync hermes' first")
|
|
sys.exit(0)
|
|
|
|
# Check all skills
|
|
print(f"\nChecking skills in {skills_dir}...")
|
|
skill_dirs = [d for d in skills_dir.iterdir() if d.is_dir()]
|
|
|
|
total_skills = 0
|
|
total_unmapped = 0
|
|
|
|
for skill_dir in skill_dirs:
|
|
skill_md = skill_dir / "SKILL.md"
|
|
if not skill_md.exists():
|
|
continue
|
|
|
|
total_skills += 1
|
|
unmapped = check_skill_frontmatter(skill_md, mapped_fields)
|
|
|
|
if unmapped:
|
|
total_unmapped += len(unmapped)
|
|
print(f" \033[93m⚠ {skill_dir.name}: {', '.join(unmapped)}\033[0m")
|
|
|
|
print(f"\n{'='*50}")
|
|
print(f"Total skills checked: {total_skills}")
|
|
print(f"Total unmapped fields: {total_unmapped}")
|
|
|
|
if total_unmapped == 0:
|
|
print("\n✅ All frontmatter fields properly mapped!")
|
|
else:
|
|
print(f"\n\033[91m⚠ Found {total_unmapped} unmapped field(s)\033[0m")
|
|
print("Add them to FIELD_MAPPING in parser.py")
|
|
|
|
return 0 if total_unmapped == 0 else 1
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|