import subprocess import sys import tempfile import unittest from pathlib import Path ROOT = Path(__file__).resolve().parents[2] SCRIPT = ROOT / "scripts" / "playbook.py" CUSTOM_DEPLOY_ROOT = "custom/playbook" def run_cli(*args): return subprocess.run( [sys.executable, str(SCRIPT), *args], capture_output=True, text=True, ) class ClaudeMdSyncTests(unittest.TestCase): def test_sync_claude_md_creates_when_no_claude_md(self): with tempfile.TemporaryDirectory() as tmp_dir: config_body = f""" [playbook] project_root = "{tmp_dir}" playbook_root = "{CUSTOM_DEPLOY_ROOT}" install_mode = "snapshot" [sync_memory_bank] project_name = "Demo" """ config_path = Path(tmp_dir) / "playbook.toml" config_path.write_text(config_body, encoding="utf-8") result = run_cli("-config", str(config_path)) self.assertEqual(result.returncode, 0) claude_md = Path(tmp_dir) / "CLAUDE.md" self.assertTrue(claude_md.exists()) text = claude_md.read_text(encoding="utf-8") self.assertTrue(text.startswith("# CLAUDE.md\n\n")) self.assertIn("@AGENTS.md", text) self.assertIn("", text) def test_sync_claude_md_appends_block_to_existing_claude_md(self): with tempfile.TemporaryDirectory() as tmp_dir: claude_md = Path(tmp_dir) / "CLAUDE.md" claude_md.write_text( "# My project\n\nSome existing content.\n", encoding="utf-8" ) config_body = f""" [playbook] project_root = "{tmp_dir}" playbook_root = "{CUSTOM_DEPLOY_ROOT}" install_mode = "snapshot" [sync_memory_bank] project_name = "Demo" """ config_path = Path(tmp_dir) / "playbook.toml" config_path.write_text(config_body, encoding="utf-8") result = run_cli("-config", str(config_path)) self.assertEqual(result.returncode, 0) text = claude_md.read_text(encoding="utf-8") self.assertIn("@AGENTS.md", text) self.assertIn("@AGENT_RULES.md", text) self.assertIn("", text) self.assertIn("Some existing content.", text) def test_sync_claude_md_updates_existing_block(self): with tempfile.TemporaryDirectory() as tmp_dir: claude_md = Path(tmp_dir) / "CLAUDE.md" claude_md.write_text( "# My project\n\n" "\n" "@AGENTS.md\n" "\n", encoding="utf-8", ) config_body = f""" [playbook] project_root = "{tmp_dir}" playbook_root = "{CUSTOM_DEPLOY_ROOT}" install_mode = "snapshot" [sync_memory_bank] project_name = "Demo" """ config_path = Path(tmp_dir) / "playbook.toml" config_path.write_text(config_body, encoding="utf-8") result = run_cli("-config", str(config_path)) self.assertEqual(result.returncode, 0) text = claude_md.read_text(encoding="utf-8") self.assertIn("@AGENTS.md", text) self.assertIn("@AGENT_RULES.md", text) self.assertEqual(text.count(""), 1) def test_sync_claude_md_adds_heading_to_generated_block(self): with tempfile.TemporaryDirectory() as tmp_dir: claude_md = Path(tmp_dir) / "CLAUDE.md" claude_md.write_text( "\n" "\n" "@AGENTS.md\n" "@AGENT_RULES.md\n" "\n" "\n", encoding="utf-8", ) config_body = f""" [playbook] project_root = "{tmp_dir}" playbook_root = "{CUSTOM_DEPLOY_ROOT}" install_mode = "snapshot" [sync_memory_bank] project_name = "Demo" """ config_path = Path(tmp_dir) / "playbook.toml" config_path.write_text(config_body, encoding="utf-8") result = run_cli("-config", str(config_path)) self.assertEqual(result.returncode, 0) text = claude_md.read_text(encoding="utf-8") self.assertTrue(text.startswith("# CLAUDE.md\n\n")) self.assertIn("@AGENTS.md", text) self.assertIn("@AGENT_RULES.md", text) self.assertEqual(text.count(""), 1) def test_sync_claude_md_skips_when_already_references_agents(self): with tempfile.TemporaryDirectory() as tmp_dir: claude_md = Path(tmp_dir) / "CLAUDE.md" original = "# My project\n\n@AGENTS.md\n" claude_md.write_text(original, encoding="utf-8") config_body = f""" [playbook] project_root = "{tmp_dir}" playbook_root = "{CUSTOM_DEPLOY_ROOT}" install_mode = "snapshot" [sync_memory_bank] project_name = "Demo" """ config_path = Path(tmp_dir) / "playbook.toml" config_path.write_text(config_body, encoding="utf-8") result = run_cli("-config", str(config_path)) self.assertEqual(result.returncode, 0) self.assertEqual(claude_md.read_text(encoding="utf-8"), original) if __name__ == "__main__": unittest.main()