from __future__ import annotations from pathlib import Path from textwrap import dedent import pytest from personal_mcp.skills import document_loader def _write_skill( root: Path, *, skill_id: str, references_block: str = "", ) -> Path: skill_dir = root / "docs" / "skills" / skill_id skill_dir.mkdir(parents=True, exist_ok=True) frontmatter_lines = [ "---", f"name: {skill_id}", "description: Example skill", "x-personal-mcp:", f" id: {skill_id}", " version: 1.0.0", " tags: [example]", " capabilities:", f" - resource://skills/{skill_id}/document", ] if references_block: frontmatter_lines.extend(f" {line}" for line in references_block.splitlines()) frontmatter_lines.append("---") skill_doc = "\n".join(frontmatter_lines) + f"\n\n# {skill_id}\n" (skill_dir / "SKILL.md").write_text(skill_doc, encoding="utf-8") return skill_dir def _load_registry(monkeypatch: pytest.MonkeyPatch, root: Path): monkeypatch.setattr(document_loader, "files", lambda _: root) return document_loader.load_docs_registry(package_anchor="unused") def test_auto_discovers_top_level_references(monkeypatch, tmp_path: Path) -> None: skill_dir = _write_skill(tmp_path, skill_id="demo-skill") refs = skill_dir / "references" refs.mkdir() (refs / "index.md").write_text("# Source Map\n", encoding="utf-8") (refs / "feature-catalog.md").write_text("# Feature Catalog\n", encoding="utf-8") registry = _load_registry(monkeypatch, tmp_path) skill = registry.skills_by_id["demo-skill"] assert set(skill.references) == {"index", "feature-catalog"} assert skill.references["index"].title == "Index" assert skill.references["feature-catalog"].title == "Feature Catalog" def test_explicit_reference_overrides_discovered(monkeypatch, tmp_path: Path) -> None: references_block = dedent( """\ references: index: path: references/index.md mime_type: text/plain title: Explicit Title """ ).rstrip() skill_dir = _write_skill( tmp_path, skill_id="override-skill", references_block=references_block, ) refs = skill_dir / "references" refs.mkdir() (refs / "index.md").write_text("# Source Map\n", encoding="utf-8") registry = _load_registry(monkeypatch, tmp_path) record = registry.skills_by_id["override-skill"].references["index"] assert record.mime_type == "text/plain" assert record.title == "Explicit Title" def test_nested_references_are_not_auto_discovered(monkeypatch, tmp_path: Path) -> None: references_block = dedent( """\ references: architecture-overview: path: references/nested/architecture-overview.md title: Architecture Overview """ ).rstrip() skill_dir = _write_skill( tmp_path, skill_id="nested-skill", references_block=references_block, ) refs = skill_dir / "references" (refs / "nested").mkdir(parents=True) (refs / "nested" / "architecture-overview.md").write_text( "# Architecture\n", encoding="utf-8", ) registry = _load_registry(monkeypatch, tmp_path) skill = registry.skills_by_id["nested-skill"] assert set(skill.references) == {"architecture-overview"} @pytest.mark.parametrize( ("skill_id", "files", "expected_refs"), [ ( "non-markdown-skill", {"guide.txt": "plain text", "guide.md": "# Guide\n"}, {"guide"}, ), ( "normalized-id-skill", {"implicit_io.md": "# Implicit IO\n"}, {"implicit-io"}, ), ], ) def test_auto_discovery_file_filtering_and_ref_id_normalization( monkeypatch, tmp_path: Path, skill_id: str, files: dict[str, str], expected_refs: set[str], ) -> None: skill_dir = _write_skill(tmp_path, skill_id=skill_id) refs = skill_dir / "references" refs.mkdir() for filename, content in files.items(): (refs / filename).write_text(content, encoding="utf-8") registry = _load_registry(monkeypatch, tmp_path) skill = registry.skills_by_id[skill_id] assert set(skill.references) == expected_refs