mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-09-05 04:00:31 +00:00
Claude Code's plugin schema rejects "agents": "./agents" (a bare
directory string) with:
Validation errors: agents: Invalid input
so the bundled plugin has never been installable. Unlike "skills",
which accepts a directory string, "agents" must be an array of .md
file paths.
Replaced the string with the explicit list of the three agent files.
Verified with `claude plugin validate plugins` (2.1.231): fails on the
old manifest with the error above, passes after this change.
Added tests/test_plugin_manifest.py to guard the manifest shape: agents
is a non-empty array of existing .md paths that stays in sync with
plugins/agents/, and the skills directory exists.
Fixes #1350
51 lines
1.9 KiB
Python
51 lines
1.9 KiB
Python
"""
|
|
Test for the Claude Code plugin manifest (Issue #1350).
|
|
|
|
Claude Code's plugin schema requires "agents" to be an array of .md file
|
|
paths (a bare directory string is rejected with "agents: Invalid input"),
|
|
while "skills" may be a directory string. This guards the manifest shape
|
|
so the bundled plugin stays installable.
|
|
"""
|
|
import json
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
MANIFEST = REPO_ROOT / "plugins" / ".claude-plugin" / "plugin.json"
|
|
|
|
|
|
class TestPluginManifest(unittest.TestCase):
|
|
"""Validate plugins/.claude-plugin/plugin.json against Claude Code's schema shape."""
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
cls.manifest = json.loads(MANIFEST.read_text(encoding="utf-8"))
|
|
cls.plugin_root = MANIFEST.parent.parent
|
|
|
|
def test_agents_is_list_of_md_file_paths(self):
|
|
agents = self.manifest["agents"]
|
|
self.assertIsInstance(
|
|
agents, list,
|
|
'Claude Code rejects "agents" unless it is an array of .md file paths',
|
|
)
|
|
self.assertTrue(agents, "agents list should not be empty")
|
|
for entry in agents:
|
|
self.assertIsInstance(entry, str)
|
|
self.assertTrue(entry.endswith(".md"), f"{entry} is not a .md file path")
|
|
path = self.plugin_root / entry
|
|
self.assertTrue(path.is_file(), f"{entry} does not exist under plugins/")
|
|
|
|
def test_agents_list_covers_all_agent_files(self):
|
|
declared = {Path(entry).name for entry in self.manifest["agents"]}
|
|
on_disk = {p.name for p in (self.plugin_root / "agents").glob("*.md")}
|
|
self.assertEqual(declared, on_disk)
|
|
|
|
def test_skills_directory_exists(self):
|
|
skills = self.manifest["skills"]
|
|
self.assertIsInstance(skills, str)
|
|
self.assertTrue((self.plugin_root / skills).is_dir())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|