from __future__ import annotations import json from pathlib import PurePosixPath import pytest from personal_mcp.catalog.server import build_skill_detail_payload from personal_mcp.registry.models.prompt import PromptArgumentEntry from personal_mcp.registry.models.registry import DocsRegistry from personal_mcp.registry.models.registry import PromptRecord from personal_mcp.registry.models.registry import PromptSummaryPayload from personal_mcp.registry.models.registry import ReferenceRecord from personal_mcp.registry.models.registry import SkillPatternPayload from personal_mcp.registry.models.registry import SkillRecord from personal_mcp.registry.models.registry import SkillSummaryPayload from personal_mcp.registry.models.registry import SkillSummaryRecord pytestmark = pytest.mark.unit def _make_skill_record() -> SkillRecord: return SkillRecord( skill_id="demo-skill", name="demo-skill", description="demo skill", version="1.2.3", tags=("testing", "catalog"), capabilities=("resource://skills/demo-skill/document", "resource://catalog/skills_index"), document_uri="resource://skills/demo-skill/document", document_relpath=PurePosixPath("skills/demo-skill/SKILL.md"), document_content="# demo", references={ "zeta": ReferenceRecord( ref_id="zeta", uri="resource://skills/demo-skill/references/zeta", relpath=PurePosixPath("skills/demo-skill/references/zeta.md"), mime_type="text/markdown", title="Zeta", content="# zeta", ), "alpha": ReferenceRecord( ref_id="alpha", uri="resource://skills/demo-skill/references/alpha", relpath=PurePosixPath("skills/demo-skill/references/alpha.md"), mime_type="text/markdown", title="Alpha", content="# alpha", ), }, ) def _make_prompt_record() -> PromptRecord: return PromptRecord( prompt_id="demo-prompt", name="demo-prompt", description="demo prompt", version="0.9.0", tags=("testing",), capabilities=("resource://prompts/demo-prompt/document",), arguments={ "topic": PromptArgumentEntry( title="Topic", required=True, description="topic to discuss", ) }, document_uri="resource://prompts/demo-prompt/document", document_relpath=PurePosixPath("prompts/demo-prompt/PROMPT.md"), document_content="# demo", ) def test_skill_pattern_payload_from_record_shape() -> None: record = _make_skill_record() payload = SkillPatternPayload.from_record(record).model_dump() assert payload == { "id": "demo-skill", "name": "demo-skill", "version": "1.2.3", "description": "demo skill", "tags": ["testing", "catalog"], "capabilities": ["resource://skills/demo-skill/document", "resource://catalog/skills_index"], "resources": ["resource://skills/demo-skill/document", "resource://catalog/skills_index"], } def test_skill_summary_payload_from_record_shape() -> None: record = _make_skill_record() payload = SkillSummaryPayload.from_record(record).model_dump() assert payload == { "id": "demo-skill", "name": "demo-skill", "description": "demo skill", "tags": ["testing", "catalog"], "capabilities": ["resource://skills/demo-skill/document", "resource://catalog/skills_index"], "version": "1.2.3", "document_uri": "resource://skills/demo-skill/document", "detail_uri": "resource://catalog/skills/demo-skill", "resources": { "document": "resource://skills/demo-skill/document", "references": [ "resource://skills/demo-skill/references/alpha", "resource://skills/demo-skill/references/zeta", ], }, } def test_prompt_summary_payload_from_record_shape() -> None: record = _make_prompt_record() payload = PromptSummaryPayload.from_record(record).model_dump() assert payload == { "id": "demo-prompt", "name": "demo-prompt", "description": "demo prompt", "tags": ["testing"], "capabilities": ["resource://prompts/demo-prompt/document"], "version": "0.9.0", "document_uri": "resource://prompts/demo-prompt/document", "detail_uri": "resource://catalog/prompts/demo-prompt", } def test_skill_detail_serializes_reference_paths() -> None: record = _make_skill_record() registry = DocsRegistry( skills_by_id={record.skill_id: record}, skills_in_load_order=(record.skill_id,), skills_summary_in_load_order=(SkillSummaryRecord.from_record(record),), docs_markdown_by_path={}, docs_markdown_path_index=(), tag_to_skill_ids={}, capability_to_skill_ids={}, prompts_by_id={}, prompts_in_load_order=(), prompts_summary_in_load_order=(), tag_to_prompt_ids={}, ) payload = build_skill_detail_payload(registry, record.skill_id) assert payload["resources"]["references"]["alpha"]["path"] == ("skills/demo-skill/references/alpha.md") json.dumps(payload)