🐛 fix(playbook): add heading to generated CLAUDE.md

This commit is contained in:
csh 2026-05-31 13:43:59 +08:00
parent 7656ee2907
commit c35cf841bc
2 changed files with 45 additions and 4 deletions

View File

@ -760,6 +760,10 @@ _CLAUDE_BLOCK_END = "<!-- playbook:claude:end -->"
_CLAUDE_MD_CANDIDATES = ["CLAUDE.md", ".claude/CLAUDE.md"]
def _claude_block_needs_heading(text: str) -> bool:
return text.lstrip().startswith(_CLAUDE_BLOCK_START)
def sync_claude_md(project_root: Path, config: dict) -> None:
claude_md_config = config.get("playbook", {}).get("claude_md")
@ -796,7 +800,9 @@ def sync_claude_md(project_root: Path, config: dict) -> None:
if not claude_md.exists():
ensure_dir(claude_md.parent)
claude_md.write_text(
"\n".join(block_lines) + "\n", encoding="utf-8", newline="\n"
"# CLAUDE.md\n\n" + "\n".join(block_lines) + "\n",
encoding="utf-8",
newline="\n",
)
log(f"Created {claude_md.relative_to(project_root)} with playbook block.")
return
@ -819,9 +825,10 @@ def sync_claude_md(project_root: Path, config: dict) -> None:
in_block = False
continue
updated.append(line)
claude_md.write_text(
"\n".join(updated) + "\n", encoding="utf-8", newline="\n"
)
updated_text = "\n".join(updated) + "\n"
if _claude_block_needs_heading(updated_text):
updated_text = "# CLAUDE.md\n\n" + updated_text.lstrip()
claude_md.write_text(updated_text, encoding="utf-8", newline="\n")
log("Updated CLAUDE.md (playbook block).")
elif "@AGENTS.md" in text:
log("Skip: CLAUDE.md already references AGENTS.md")

View File

@ -607,6 +607,7 @@ project_name = "Demo"
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("<!-- playbook:claude:start -->", text)
@ -665,6 +666,39 @@ project_name = "Demo"
self.assertIn("@AGENT_RULES.md", text)
self.assertEqual(text.count("<!-- playbook:claude:start -->"), 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(
"<!-- playbook:claude:start -->\n"
"\n"
"@AGENTS.md\n"
"@AGENT_RULES.md\n"
"\n"
"<!-- playbook:claude:end -->\n",
encoding="utf-8",
)
config_body = f"""
[playbook]
project_root = "{tmp_dir}"
deploy_root = "{CUSTOM_DEPLOY_ROOT}"
[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("<!-- playbook:claude:start -->"), 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"