import re import unittest from pathlib import Path ROOT = Path(__file__).resolve().parents[1] SKILLS_ROOT = ROOT / "skills" FIRST_PARTY_SKILLS = { "commit-message": SKILLS_ROOT / "commit-message" / "SKILL.md", "gitea-fix-ci": SKILLS_ROOT / "gitea-fix-ci" / "SKILL.md", "style-cleanup": SKILLS_ROOT / "style-cleanup" / "SKILL.md", } def read_text(path: Path) -> str: return path.read_text(encoding="utf-8") def normalize_space(text: str) -> str: return " ".join(text.split()) def parse_frontmatter(text: str) -> dict[str, str]: match = re.match(r"^---\n(.*?)\n---\n", text, re.DOTALL) if match is None: raise AssertionError("missing YAML frontmatter") block = match.group(1) data: dict[str, str] = {} current_key: str | None = None current_value: list[str] = [] for raw_line in block.splitlines(): if raw_line.startswith(" ") and current_key is not None: current_value.append(raw_line.strip()) continue if current_key is not None: data[current_key] = " ".join(current_value).strip().strip('"') current_key = None current_value = [] key, value = raw_line.split(":", 1) current_key = key.strip() current_value = [value.strip()] if current_key is not None: data[current_key] = " ".join(current_value).strip().strip('"') return data class FirstPartySkillsQualityTests(unittest.TestCase): def test_first_party_skill_frontmatter_is_minimal_and_named_consistently(self): for name, path in FIRST_PARTY_SKILLS.items(): with self.subTest(skill=name): frontmatter = parse_frontmatter(read_text(path)) self.assertEqual(set(frontmatter), {"name", "description"}) self.assertEqual(frontmatter["name"], name) self.assertRegex(frontmatter["name"], r"^[a-z0-9-]+$") def test_first_party_skill_descriptions_are_trigger_focused(self): for name, path in FIRST_PARTY_SKILLS.items(): with self.subTest(skill=name): description = parse_frontmatter(read_text(path))["description"] self.assertTrue(description.startswith("Use when")) self.assertLessEqual(len(description), 500) self.assertNotIn("Triggers:", description) def test_first_party_skills_have_required_sections(self): required_sections = ( "## Overview", "## When to Use", "## When Not to Use", "## Inputs", "## Procedure", "## Output Contract", "## Success Criteria", "## Failure Handling", ) for name, path in FIRST_PARTY_SKILLS.items(): text = read_text(path) with self.subTest(skill=name): for section in required_sections: self.assertIn(section, text) def test_commit_message_skill_handles_missing_or_mixed_staging_states(self): text = normalize_space(read_text(FIRST_PARTY_SKILLS["commit-message"])) self.assertIn("If nothing is staged", text) self.assertIn("If only unstaged changes exist", text) self.assertIn("strongly recommend splitting the commit", text) self.assertIn("Do not run `git commit`", text) def test_style_cleanup_skill_has_clear_non_goals_and_verification_loop(self): text = normalize_space(read_text(FIRST_PARTY_SKILLS["style-cleanup"])) self.assertIn("not for semantic refactors", text) self.assertIn("not for introducing a new formatter or lint configuration", text) self.assertIn("formatter -> lint/check -> lint --fix -> final check", text) self.assertIn("second formatter run produces no additional diff", text) def test_gitea_fix_ci_skill_is_gitea_specific_and_plan_gated(self): text = normalize_space(read_text(FIRST_PARTY_SKILLS["gitea-fix-ci"])) self.assertIn("Gitea Actions", text) self.assertIn("tea", text) self.assertIn("tea actions runs", text) self.assertIn("Gitea API", text) self.assertIn("Gitea 1.21", text) self.assertIn("workflow runs", text) self.assertIn("job logs", text) self.assertIn("/actions/runs//jobs//logs", text) self.assertIn("Do not implement before the user approves the fix plan", text) self.assertIn("not a standalone executor", text) self.assertNotIn("gh pr checks", text) self.assertNotIn("GitHub Actions", text) if __name__ == "__main__": unittest.main()