basic BMAD setup
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
"""Tests for registry.py: records, members, single-skill modules, unregistered skills, symlink dedupe."""
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
SCRIPT = Path(__file__).resolve().parents[1] / "registry.py"
|
||||
|
||||
|
||||
def write(path: Path, text: str) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(text, encoding="utf-8")
|
||||
|
||||
|
||||
def make_project(root: Path) -> Path:
|
||||
project = root / "project"
|
||||
agents = project / ".agents" / "skills"
|
||||
(project / "_bmad").mkdir(parents=True)
|
||||
# core record
|
||||
write(agents / "bmod-core-tools" / "SKILL.md", "---\nname: bmod-core-tools\ndescription: x\n---\n")
|
||||
write(
|
||||
agents / "bmod-core-tools" / "bmod.toml",
|
||||
'[bmod]\ncode = "core-tools"\nversion = "6.13.0"\nupdate_source = "github:bmad-code-org/BMAD-METHOD/skills"\nskills = ["bmad"]\n',
|
||||
)
|
||||
write(agents / "bmad" / "SKILL.md", "---\nname: bmad\ndescription: x\n---\n")
|
||||
write(
|
||||
agents / "bmad" / "bmod.toml",
|
||||
'[skill]\nbmod = "bmod-core-tools"\nsource = "github:bmad-code-org/BMAD-METHOD/skills"\n',
|
||||
)
|
||||
# an org module with an agent member and help
|
||||
write(agents / "bmod-acme" / "SKILL.md", "---\nname: bmod-acme\ndescription: x\n---\n")
|
||||
write(
|
||||
agents / "bmod-acme" / "bmod.toml",
|
||||
'[bmod]\ncode = "acme"\nversion = "1.0.0"\nupdate_source = "github:acme/skills"\nskills = ["acme-release-notes"]\n',
|
||||
)
|
||||
write(agents / "bmod-acme" / "help" / "help.md", "# Acme\n")
|
||||
write(agents / "bmod-acme" / "roster.toml", "[[members]]\ncode = 'acme-agent-scout'\n")
|
||||
write(agents / "acme-release-notes" / "SKILL.md", "---\nname: acme-release-notes\ndescription: x\n---\n")
|
||||
write(agents / "acme-release-notes" / "bmod.toml", '[skill]\nbmod = "bmod-acme"\nsource = "github:acme/skills"\n')
|
||||
write(agents / "acme-agent-scout" / "SKILL.md", "---\nname: acme-agent-scout\ndescription: x\n---\n")
|
||||
write(agents / "acme-agent-scout" / "bmod.toml", '[skill]\nbmod = "bmod-acme"\nsource = "github:acme/skills"\n')
|
||||
# a single-skill module
|
||||
write(agents / "doc-standards" / "SKILL.md", "---\nname: doc-standards\ndescription: x\n---\n")
|
||||
write(
|
||||
agents / "doc-standards" / "bmod.toml",
|
||||
'[bmod]\ncode = "docstd"\nversion = "0.1.0"\nupdate_source = "github:me/doc-standards"\n\n[skill]\n',
|
||||
)
|
||||
write(agents / "doc-standards" / "help" / "help.md", "# Doc standards\n")
|
||||
# wired to BMad, registered nowhere
|
||||
write(agents / "random-generator" / "SKILL.md", "---\nname: random-generator\ndescription: x\n---\n")
|
||||
write(agents / "random-generator" / "customize.toml", "[workflow]\n")
|
||||
write(
|
||||
agents / "joke" / "SKILL.md",
|
||||
"---\nname: joke\ndescription: x\n---\nRun `uv run {project-root}/_bmad/scripts/resolve_config.py`.\n",
|
||||
)
|
||||
# plain, outside BMad
|
||||
write(agents / "plain" / "SKILL.md", "---\nname: plain\ndescription: x\n---\nJust do it.\n")
|
||||
# .claude/skills mirrors .agents/skills through symlinks
|
||||
claude = project / ".claude" / "skills"
|
||||
claude.mkdir(parents=True)
|
||||
for folder in agents.iterdir():
|
||||
os.symlink(Path("..") / ".." / ".agents" / "skills" / folder.name, claude / folder.name)
|
||||
return project
|
||||
|
||||
|
||||
def run(project: Path, *extra: str) -> dict:
|
||||
res = subprocess.run(
|
||||
[sys.executable, str(SCRIPT), "--project-root", str(project), *extra], capture_output=True, text=True
|
||||
)
|
||||
assert res.returncode == 0, res.stderr
|
||||
return json.loads(res.stdout)
|
||||
|
||||
|
||||
class RegistryTest(unittest.TestCase):
|
||||
def test_records_members_and_unregistered(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
project = make_project(Path(tmp))
|
||||
roots = [str(project / ".agents" / "skills"), str(project / ".claude" / "skills")]
|
||||
data = run(project, "--root", roots[0], "--root", roots[1])
|
||||
self.assertEqual(data["bmad"], {"present": True, "version": "6.13.0"})
|
||||
self.assertFalse(data["skills_repo"])
|
||||
by_code = {r["code"]: r for r in data["records"]}
|
||||
self.assertEqual(sorted(by_code), ["acme", "core-tools", "docstd"])
|
||||
acme = by_code["acme"]
|
||||
self.assertEqual(acme["skills"], ["acme-agent-scout", "acme-release-notes"])
|
||||
self.assertEqual(acme["prefix"], "acme-")
|
||||
self.assertTrue(acme["has_help"])
|
||||
self.assertTrue(acme["has_roster"])
|
||||
self.assertFalse(acme["single_skill"])
|
||||
self.assertEqual(acme["scope"], "project")
|
||||
doc = by_code["docstd"]
|
||||
self.assertTrue(doc["single_skill"])
|
||||
self.assertEqual(doc["skills"], [])
|
||||
self.assertEqual(doc["prefix"], "docstd-")
|
||||
self.assertEqual(by_code["core-tools"]["prefix"], "bmad-")
|
||||
self.assertEqual(sorted(u["skill"] for u in data["unregistered"]), ["joke", "random-generator"])
|
||||
# the symlinked copies did not double anything
|
||||
self.assertEqual(len(data["records"]), 3)
|
||||
self.assertEqual(len(data["unregistered"]), 2)
|
||||
|
||||
def test_empty_project(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
project = Path(tmp) / "empty"
|
||||
project.mkdir()
|
||||
data = run(project, "--root", str(project / "nowhere"))
|
||||
self.assertEqual(data["bmad"], {"present": False, "version": None})
|
||||
self.assertEqual(data["records"], [])
|
||||
self.assertEqual(data["unregistered"], [])
|
||||
|
||||
def test_skills_repo_detected(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
project = Path(tmp) / "repo"
|
||||
write(project / "skills" / "bmod-x" / "SKILL.md", "---\nname: bmod-x\ndescription: x\n---\n")
|
||||
write(
|
||||
project / "skills" / "bmod-x" / "bmod.toml",
|
||||
'[bmod]\ncode = "x"\nversion = "1"\nupdate_source = "github:a/b"\n',
|
||||
)
|
||||
data = run(project, "--root", str(project / "skills"))
|
||||
self.assertTrue(data["skills_repo"])
|
||||
self.assertEqual(data["records"][0]["code"], "x")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user