import unittest from pathlib import Path ROOT = Path(__file__).resolve().parents[1] class TemplateContractsTests(unittest.TestCase): def test_project_templates_drop_legacy_language_placeholders(self): templates_readme = (ROOT / "templates" / "README.md").read_text( encoding="utf-8" ) self.assertNotIn("{{MAIN_LANGUAGE}}", templates_readme) self.assertNotIn("{{LANGUAGE_1}}", templates_readme) self.assertNotIn("docs/workflows/", templates_readme) self.assertNotIn("templates/workflows/", templates_readme) self.assertIn("docs/superpowers/", templates_readme) self.assertIn("docs/prompts/README.md", templates_readme) self.assertIn("完整主链只在 `AGENT_RULES.template.md` 定义", templates_readme) agents_template = (ROOT / "templates" / "AGENTS.template.md").read_text( encoding="utf-8" ) self.assertNotIn("{{MAIN_LANGUAGE}}", agents_template) self.assertIn("AGENT_RULES.md", agents_template) self.assertIn("docs/prompts/README.md", agents_template) tech_context_template = ( ROOT / "templates" / "memory-bank" / "tech-context.template.md" ).read_text(encoding="utf-8") self.assertNotIn("{{MAIN_LANGUAGE}}", tech_context_template) self.assertNotIn("{{LANGUAGE_1}}", tech_context_template) self.assertNotIn("**主要语言**", tech_context_template) self.assertIn("## 不可假设项", tech_context_template) project_brief_template = ( ROOT / "templates" / "memory-bank" / "project-brief.template.md" ).read_text(encoding="utf-8") self.assertIn("## 成功定义", project_brief_template) def test_memory_bank_templates_capture_short_lived_context_contracts(self): progress_template = ( ROOT / "templates" / "memory-bank" / "progress.template.md" ).read_text(encoding="utf-8") self.assertIn("短期状态快照,不是 changelog", progress_template) self.assertIn("`Recent Changes` 只保留最近 3-5 条", progress_template) self.assertIn("整理/替换旧摘要,不做无限追加", progress_template) active_context_template = ( ROOT / "templates" / "memory-bank" / "active-context.template.md" ).read_text(encoding="utf-8") self.assertIn("短期上下文快照,不是长期日志", active_context_template) self.assertIn("`Recent Changes` 只保留最近 3-5 条", active_context_template) self.assertIn( "`Touched Files` 只保留当前 Plan / 下一轮仍相关的文件", active_context_template, ) self.assertIn("整理/替换旧上下文,不做无限追加", active_context_template) def test_prompt_templates_point_to_current_superpowers_flow(self): update_memory_template = ( ROOT / "templates" / "prompts" / "coding" / "update-memory.template.md" ).read_text(encoding="utf-8") self.assertNotIn("workflow-state", update_memory_template) self.assertIn("plan-status", update_memory_template) self.assertIn("## Updated Files", update_memory_template) self.assertIn("## New Context", update_memory_template) self.assertIn("## Outstanding Risks", update_memory_template) self.assertIn("AGENT_RULES.local.md", update_memory_template) self.assertIn("短期状态快照", update_memory_template) self.assertIn( "不要把 `Recent Changes` 当作无限追加日志", update_memory_template ) self.assertIn("短期上下文快照", update_memory_template) self.assertIn( "`Touched Files` 只保留当前 Plan / 下一轮仍相关的文件", update_memory_template, ) close_task_template = ( ROOT / "templates" / "prompts" / "coding" / "close-task.template.md" ).read_text(encoding="utf-8") self.assertIn("main_loop.py finish", close_task_template) self.assertIn("如本轮来自 `main_loop.py claim`", close_task_template) self.assertNotIn("workflow-state", close_task_template) self.assertIn("未归档不得声明 Plan 完成", close_task_template) self.assertIn("按项目归档机制只归档", close_task_template) self.assertIn("状态已写回,交付未完成", close_task_template) self.assertIn("## Completed", close_task_template) self.assertIn("## Not Completed", close_task_template) self.assertIn("## Verification", close_task_template) self.assertIn("## Risks", close_task_template) self.assertIn("## Next Steps", close_task_template) verify_change_template = ( ROOT / "templates" / "prompts" / "coding" / "verify-change.template.md" ).read_text(encoding="utf-8") self.assertIn("如本轮来自 `main_loop.py claim`", verify_change_template) self.assertNotIn("workflow-state", verify_change_template) self.assertIn("plan-status", verify_change_template) self.assertIn("验证通过不等于 Plan 完成", verify_change_template) self.assertIn( "当前 Plan 相关差异未归档/提交时,不得声明 Plan 完成", verify_change_template, ) self.assertIn("## Validated", verify_change_template) self.assertIn("## Evidence", verify_change_template) self.assertIn("## Not Validated", verify_change_template) self.assertIn("## Risks", verify_change_template) clarify_template = ( ROOT / "templates" / "prompts" / "coding" / "clarify.template.md" ).read_text(encoding="utf-8") self.assertNotIn("Vibe-coding", clarify_template) self.assertIn("## Current Understanding", clarify_template) self.assertIn("## Open Question", clarify_template) self.assertIn("## Recommended Default", clarify_template) code_review_template = ( ROOT / "templates" / "prompts" / "coding" / "code-review.template.md" ).read_text(encoding="utf-8") self.assertIn("## Findings", code_review_template) self.assertIn("## Open Questions", code_review_template) self.assertIn("## Residual Risk", code_review_template) prompts_readme = (ROOT / "templates" / "prompts" / "README.md").read_text( encoding="utf-8" ) self.assertIn("AGENT_RULES.md", prompts_readme) self.assertIn("docs/superpowers/", prompts_readme) self.assertIn("不是流程权威", prompts_readme) self.assertNotIn("playbook.py -record-spec", prompts_readme) self.assertNotIn("playbook.py -record-plan", prompts_readme) self.assertNotIn("using-superpowers", prompts_readme) self.assertNotIn("main_loop.py claim", prompts_readme) self.assertNotIn("docs/workflows/", prompts_readme) self.assertIn("设计与计划产物", prompts_readme) agent_behavior_template = ( ROOT / "templates" / "prompts" / "system" / "agent-behavior.template.md" ).read_text(encoding="utf-8") self.assertIn("AGENT_RULES.md", agent_behavior_template) self.assertIn("AGENT_RULES.local.md", agent_behavior_template) self.assertIn("docs/superpowers/specs/", agent_behavior_template) self.assertIn("docs/superpowers/plans/", agent_behavior_template) self.assertNotIn("using-superpowers", agent_behavior_template) self.assertNotIn("main_loop.py claim", agent_behavior_template) self.assertNotIn("playbook.py -record-spec", agent_behavior_template) self.assertNotIn("playbook.py -record-plan", agent_behavior_template) self.assertIn( "项目上下文与执行状态写入 `memory-bank/`", agent_behavior_template ) def test_agent_rules_template_defines_plan_and_archival_contracts(self): rules_template = (ROOT / "templates" / "AGENT_RULES.template.md").read_text( encoding="utf-8" ) self.assertIn("框架流程约束基线", rules_template) self.assertIn("{{PLAYBOOK_ROOT}}", rules_template) self.assertIn("Playbook 模板/供应商目录", rules_template) self.assertIn("唯一设计与计划产物中心", rules_template) self.assertIn("memory-bank/progress.md", rules_template) self.assertIn("优先恢复 `in-progress`", rules_template) self.assertIn("选择第一个可执行 Plan", rules_template) self.assertIn( "`main_loop.py finish -status done` 只负责写回机器状态", rules_template, ) self.assertIn( "Plan `done` 后必须完成当前 Plan 变更的归档/提交", rules_template ) self.assertIn( "spec/plan 产出阶段不单独提交或归档", rules_template ) self.assertIn( "如外部 skill", rules_template ) self.assertIn("Plan 范围是归档/提交边界", rules_template) self.assertIn( "不自动提交或归档", rules_template, ) self.assertIn("当前 Plan 文件", rules_template) self.assertIn("`memory-bank/progress.md`", rules_template) self.assertIn("必要 memory 更新", rules_template) self.assertIn("允许其未归档共存", rules_template) self.assertIn("当前 Plan 无遗留差异", rules_template) self.assertIn("状态已写回,交付未完成", rules_template) self.assertNotIn("如项目使用 Git", rules_template) self.assertNotIn("Git 提交", rules_template) self.assertNotIn("git status", rules_template) self.assertNotIn("git commit", rules_template) self.assertNotIn("git worktree", rules_template) self.assertNotIn(".gitattributes", rules_template) self.assertIn("`progress.md` 上半部分是短期状态快照", rules_template) self.assertIn("`active-context.md` 是短期上下文快照", rules_template) if __name__ == "__main__": unittest.main()