Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
985 changes: 474 additions & 511 deletions ai-catalog.json

Large diffs are not rendered by default.

11 changes: 1 addition & 10 deletions catalog-icons.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,7 @@
}
},
{
"identifier": "urn:air:github.com:mattpocock:skills:grill-me",
"url": "https://raw.githubusercontent.com/github/agentfinder-catalog/70e8c6e2f8eba283b453846a1c0ad65266d46511/icons/mattpocock/skills.png",
"provenance": {
"sourceUrl": "https://www.aihero.dev/favicon.svg",
"approval": "sourceUrl identifies the project's published SVG logo mark. Public redistribution of this logo as the project's catalog icon was explicitly approved by the contributing maintainer. Rasterizing the mark in white, centered without cropping on a solid dark background, was approved; no third-party license is asserted.",
"sha256": "917a0d8ca7be693df146172a881d0a99f36cea6a1da0acb76cf82e7651e17f6a"
}
},
{
"identifier": "urn:air:github.com:mattpocock:skills:grilling",
"identifier": "urn:air:github.com:mattpocock:skills:mattpocock-skills",
"url": "https://raw.githubusercontent.com/github/agentfinder-catalog/70e8c6e2f8eba283b453846a1c0ad65266d46511/icons/mattpocock/skills.png",
"provenance": {
"sourceUrl": "https://www.aihero.dev/favicon.svg",
Expand Down
11 changes: 0 additions & 11 deletions catalog/mattpocock/grill-me.json

This file was deleted.

11 changes: 0 additions & 11 deletions catalog/mattpocock/grilling.json

This file was deleted.

11 changes: 11 additions & 0 deletions catalog/mattpocock/mattpocock-skills.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"identifier": "urn:ai:github.com:mattpocock:skills:mattpocock-skills",
"displayName": "Matt Pocock Skills",
"mediaType": "application/vnd.anthropic.claude-plugin+json",
"url": "https://github.com/mattpocock/skills/blob/main/.claude-plugin/plugin.json",
"description": "Engineering and productivity skills for planning, test-driven development, implementation, code review, and structured questioning.",
"metadata": {
"sourceSet": "mattpocock/skills",
"repoPath": ".claude-plugin/plugin.json"
}
}
11 changes: 0 additions & 11 deletions catalog/mattpocock/to-questionnaire.json

This file was deleted.

11 changes: 0 additions & 11 deletions catalog/mattpocock/wizard.json

This file was deleted.

85 changes: 85 additions & 0 deletions tests/test_mattpocock_plugin_refs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import json
import unittest
from pathlib import Path

ROOT = Path(__file__).resolve().parent.parent
IDENTIFIER_PREFIX = "urn:ai:github.com:mattpocock:skills:"
PLUGIN_IDENTIFIER = IDENTIFIER_PREFIX + "mattpocock-skills"
PLUGIN_MEDIA_TYPE = "application/vnd.anthropic.claude-plugin+json"
RETIRED_SKILL_NAMES = ("grill-me", "grilling", "to-questionnaire", "wizard")


class MattPocockPluginRefsTest(unittest.TestCase):
def setUp(self):
self.entries = {}
for path in sorted((ROOT / "catalog/mattpocock").glob("*.json")):
entry = json.loads(path.read_text(encoding="utf-8"))
self.entries[entry["identifier"]] = entry
self.icons = json.loads(
(ROOT / "catalog-icons.json").read_text(encoding="utf-8")
)["icons"]

def test_parent_plugin_targets_root_manifest(self):
entry = self.entries[PLUGIN_IDENTIFIER]
self.assertEqual(entry["displayName"], "Matt Pocock Skills")
self.assertEqual(entry["mediaType"], PLUGIN_MEDIA_TYPE)
self.assertEqual(
entry["url"],
"https://github.com/mattpocock/skills/blob/main/.claude-plugin/plugin.json",
)
self.assertEqual(
entry["metadata"],
{
"sourceSet": "mattpocock/skills",
"repoPath": ".claude-plugin/plugin.json",
},
)

def test_bundled_skills_are_not_separate_entries(self):
for name in RETIRED_SKILL_NAMES:
with self.subTest(name=name):
self.assertNotIn(IDENTIFIER_PREFIX + name, self.entries)

def test_nonbundled_skills_remain_cataloged(self):
for name, repo_path in (
("claude-handoff", "skills/in-progress/claude-handoff/SKILL.md"),
("git-guardrails-claude-code", "skills/misc/git-guardrails-claude-code/SKILL.md"),
):
with self.subTest(name=name):
entry = self.entries[IDENTIFIER_PREFIX + name]
self.assertEqual(entry["mediaType"], "application/ai-skill")
self.assertEqual(entry["metadata"]["sourceSet"], "mattpocock/skills")
self.assertEqual(entry["metadata"]["repoPath"], repo_path)
self.assertEqual(
entry["url"], f"https://github.com/mattpocock/skills/blob/main/{repo_path}"
)

def test_reviewed_icon_targets_only_parent_plugin(self):
prefix = IDENTIFIER_PREFIX.replace("urn:ai:", "urn:air:", 1)
icons = [icon for icon in self.icons if icon["identifier"].startswith(prefix)]
self.assertEqual(
[icon["identifier"] for icon in icons],
[PLUGIN_IDENTIFIER.replace("urn:ai:", "urn:air:", 1)],
)
self.assertTrue(icons[0]["url"].endswith("/icons/mattpocock/skills.png"))

def test_generated_catalog_publishes_plugin_instead_of_bundled_skills(self):
catalog = json.loads((ROOT / "ai-catalog.json").read_text(encoding="utf-8"))
entries = {entry["identifier"]: entry for entry in catalog["entries"]}
identifier = PLUGIN_IDENTIFIER.replace("urn:ai:", "urn:air:", 1)
entry = entries[identifier]
self.assertEqual(entry["type"], PLUGIN_MEDIA_TYPE)
self.assertEqual(entry["url"], self.entries[PLUGIN_IDENTIFIER]["url"])
for key in ("sourceSet", "repoPath"):
self.assertEqual(entry["metadata"][key], self.entries[PLUGIN_IDENTIFIER]["metadata"][key])
icon = next(icon for icon in self.icons if icon["identifier"] == identifier)
self.assertEqual(entry["metadata"]["com.github.agentfinder.icon.url"], icon["url"])
for name in RETIRED_SKILL_NAMES:
with self.subTest(name=name):
self.assertNotIn(
(IDENTIFIER_PREFIX + name).replace("urn:ai:", "urn:air:", 1), entries
)


if __name__ == "__main__":
unittest.main()
Loading