#!/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())