🔧 chore(playbook): split sync_templates into sections
This commit is contained in:
parent
278750e3c9
commit
73d5c261b1
19
README.md
19
README.md
|
|
@ -64,17 +64,20 @@ python scripts/playbook.py -config playbook.toml
|
||||||
[playbook]
|
[playbook]
|
||||||
project_root = "/path/to/project"
|
project_root = "/path/to/project"
|
||||||
|
|
||||||
[sync_templates]
|
[sync_rules]
|
||||||
|
# force = true # 可选
|
||||||
|
|
||||||
|
[sync_memory_bank]
|
||||||
project_name = "MyProject"
|
project_name = "MyProject"
|
||||||
full = false
|
|
||||||
|
[sync_prompts]
|
||||||
```
|
```
|
||||||
|
|
||||||
**部署行为**:
|
**部署行为**:
|
||||||
|
|
||||||
- **新项目**:创建完整的 `AGENTS.md`、`AGENT_RULES.md`、`memory-bank/`、`docs/prompts/`
|
- **配置节存在即启用**:只写需要同步的配置节
|
||||||
- **已有 AGENTS.md**:追加路由链接(使用 `<!-- playbook:templates:start/end -->` 标记)
|
- **AGENTS.md**:始终按区块更新(`<!-- playbook:xxx:start/end -->`)
|
||||||
- **full = true**:追加完整框架(规则优先级 + 新会话开始时)到已有 AGENTS.md
|
- **force**:默认 false,已存在则跳过;设为 true 时强制覆盖(会先备份)
|
||||||
- **其他文件**:如果已存在则跳过(使用 `force = true` 覆盖)
|
|
||||||
|
|
||||||
详见:`templates/README.md`
|
详见:`templates/README.md`
|
||||||
|
|
||||||
|
|
@ -226,7 +229,9 @@ git commit -m ":package: deps(playbook): add tsl standards"
|
||||||
[sync_standards]
|
[sync_standards]
|
||||||
langs = ["tsl", "cpp"]
|
langs = ["tsl", "cpp"]
|
||||||
|
|
||||||
[sync_templates]
|
[sync_rules]
|
||||||
|
|
||||||
|
[sync_memory_bank]
|
||||||
project_name = "MyProject"
|
project_name = "MyProject"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,20 @@
|
||||||
# langs = ["tsl"] # 可选:默认仅 tsl
|
# langs = ["tsl"] # 可选:默认仅 tsl
|
||||||
# target_dir = "docs/standards/playbook"
|
# target_dir = "docs/standards/playbook"
|
||||||
|
|
||||||
[sync_templates]
|
[sync_rules]
|
||||||
|
# 同步 AGENT_RULES.md(配置节存在即启用)
|
||||||
|
# force = false # 可选:覆盖已有文件
|
||||||
|
|
||||||
|
[sync_memory_bank]
|
||||||
|
# 同步 memory-bank/(配置节存在即启用)
|
||||||
# project_name = "MyProject" # 可选:替换 {{PROJECT_NAME}}
|
# project_name = "MyProject" # 可选:替换 {{PROJECT_NAME}}
|
||||||
# main_language = "tsl" # 可选:替换 {{MAIN_LANGUAGE}}(未配置时取 sync_standards.langs[0],否则 tsl)
|
# force = false # 可选:覆盖已有目录(会先备份)
|
||||||
# date = "2026-01-23" # 可选:替换 {{DATE}},默认今天
|
# no_backup = false # 可选:跳过备份
|
||||||
# force = false # 可选:覆盖已有目录
|
|
||||||
|
[sync_prompts]
|
||||||
|
# 同步 docs/prompts/(配置节存在即启用)
|
||||||
|
# force = false # 可选:覆盖已有目录(会先备份)
|
||||||
# no_backup = false # 可选:跳过备份
|
# no_backup = false # 可选:跳过备份
|
||||||
# full = false # 可选:写入 framework 区块
|
|
||||||
|
|
||||||
[sync_standards]
|
[sync_standards]
|
||||||
# langs = ["tsl", "cpp"] # 必填:要同步的语言
|
# langs = ["tsl", "cpp"] # 必填:要同步的语言
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,15 @@ try:
|
||||||
except ModuleNotFoundError: # Python < 3.11
|
except ModuleNotFoundError: # Python < 3.11
|
||||||
tomllib = None
|
tomllib = None
|
||||||
|
|
||||||
ORDER = ["vendor", "sync_templates", "sync_standards", "install_skills", "format_md"]
|
ORDER = [
|
||||||
|
"vendor",
|
||||||
|
"sync_rules",
|
||||||
|
"sync_memory_bank",
|
||||||
|
"sync_prompts",
|
||||||
|
"sync_standards",
|
||||||
|
"install_skills",
|
||||||
|
"format_md",
|
||||||
|
]
|
||||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||||
PLAYBOOK_ROOT = SCRIPT_DIR.parent
|
PLAYBOOK_ROOT = SCRIPT_DIR.parent
|
||||||
|
|
||||||
|
|
@ -503,15 +511,125 @@ def update_agents_section(
|
||||||
log("Appended: AGENTS.md (section)")
|
log("Appended: AGENTS.md (section)")
|
||||||
|
|
||||||
|
|
||||||
def sync_templates_action(config: dict, context: dict) -> int:
|
def resolve_project_name(context: dict) -> str | None:
|
||||||
|
config = context.get("config", {})
|
||||||
|
if not isinstance(config, dict):
|
||||||
|
return None
|
||||||
|
memory_conf = config.get("sync_memory_bank")
|
||||||
|
if isinstance(memory_conf, dict):
|
||||||
|
raw = memory_conf.get("project_name")
|
||||||
|
if raw is not None and str(raw).strip():
|
||||||
|
return str(raw).strip()
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_template_date(context: dict) -> str:
|
||||||
|
config = context.get("config", {})
|
||||||
|
if isinstance(config, dict):
|
||||||
|
for key in ("sync_rules", "sync_memory_bank", "sync_prompts"):
|
||||||
|
section = config.get(key)
|
||||||
|
if isinstance(section, dict):
|
||||||
|
value = section.get("date")
|
||||||
|
if value:
|
||||||
|
return str(value)
|
||||||
|
return datetime.now().strftime("%Y-%m-%d")
|
||||||
|
|
||||||
|
|
||||||
|
def sync_agents_template(context: dict) -> int:
|
||||||
project_root: Path = context["project_root"]
|
project_root: Path = context["project_root"]
|
||||||
if project_root.resolve() == PLAYBOOK_ROOT.resolve():
|
if project_root.resolve() == PLAYBOOK_ROOT.resolve():
|
||||||
log("Skip: playbook root equals project root.")
|
log("Skip: playbook root equals project root.")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
templates_dir = PLAYBOOK_ROOT / "templates"
|
templates_dir = PLAYBOOK_ROOT / "templates"
|
||||||
if not templates_dir.is_dir():
|
agents_src = templates_dir / "AGENTS.template.md"
|
||||||
print(f"ERROR: templates not found: {templates_dir}", file=sys.stderr)
|
if not agents_src.is_file():
|
||||||
|
return 0
|
||||||
|
|
||||||
|
project_name = resolve_project_name(context)
|
||||||
|
main_language = resolve_main_language({}, context)
|
||||||
|
playbook_scripts = resolve_playbook_scripts(project_root, context)
|
||||||
|
date_value = resolve_template_date(context)
|
||||||
|
|
||||||
|
agents_dst = project_root / "AGENTS.md"
|
||||||
|
if agents_dst.exists():
|
||||||
|
agents_text = agents_dst.read_text(encoding="utf-8")
|
||||||
|
if "<!-- playbook:framework:start -->" in agents_text:
|
||||||
|
start_marker = "<!-- playbook:framework:start -->"
|
||||||
|
end_marker = "<!-- playbook:framework:end -->"
|
||||||
|
elif "<!-- playbook:templates:start -->" in agents_text:
|
||||||
|
start_marker = "<!-- playbook:templates:start -->"
|
||||||
|
end_marker = "<!-- playbook:templates:end -->"
|
||||||
|
else:
|
||||||
|
start_marker = "<!-- playbook:templates:start -->"
|
||||||
|
end_marker = "<!-- playbook:templates:end -->"
|
||||||
|
else:
|
||||||
|
start_marker = "<!-- playbook:framework:start -->"
|
||||||
|
end_marker = "<!-- playbook:framework:end -->"
|
||||||
|
|
||||||
|
update_agents_section(
|
||||||
|
agents_dst,
|
||||||
|
agents_src,
|
||||||
|
start_marker,
|
||||||
|
end_marker,
|
||||||
|
project_name,
|
||||||
|
date_value,
|
||||||
|
main_language,
|
||||||
|
playbook_scripts,
|
||||||
|
)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def should_sync_agents(config: dict) -> bool:
|
||||||
|
for key in ("sync_rules", "sync_memory_bank", "sync_prompts", "sync_standards"):
|
||||||
|
if key in config:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def sync_rules_action(config: dict, context: dict) -> int:
|
||||||
|
project_root: Path = context["project_root"]
|
||||||
|
if project_root.resolve() == PLAYBOOK_ROOT.resolve():
|
||||||
|
log("Skip: playbook root equals project root.")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
templates_dir = PLAYBOOK_ROOT / "templates"
|
||||||
|
rules_src = templates_dir / "AGENT_RULES.template.md"
|
||||||
|
if not rules_src.is_file():
|
||||||
|
print(f"ERROR: template not found: {rules_src}", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
|
||||||
|
rules_dst = project_root / "AGENT_RULES.md"
|
||||||
|
force = bool(config.get("force", False))
|
||||||
|
if rules_dst.exists() and not force:
|
||||||
|
log("AGENT_RULES.md already exists. Use force to overwrite.")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
project_name = resolve_project_name(context)
|
||||||
|
main_language = resolve_main_language(config, context)
|
||||||
|
playbook_scripts = resolve_playbook_scripts(project_root, context)
|
||||||
|
date_value = config.get("date") or datetime.now().strftime("%Y-%m-%d")
|
||||||
|
|
||||||
|
backup_path(rules_dst, False)
|
||||||
|
text = rules_src.read_text(encoding="utf-8")
|
||||||
|
text = replace_placeholders(
|
||||||
|
text, project_name, date_value, main_language, playbook_scripts
|
||||||
|
)
|
||||||
|
rules_dst.write_text(text + "\n", encoding="utf-8")
|
||||||
|
log("Synced: AGENT_RULES.md")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def sync_memory_bank_action(config: dict, context: dict) -> int:
|
||||||
|
project_root: Path = context["project_root"]
|
||||||
|
if project_root.resolve() == PLAYBOOK_ROOT.resolve():
|
||||||
|
log("Skip: playbook root equals project root.")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
templates_dir = PLAYBOOK_ROOT / "templates"
|
||||||
|
memory_src = templates_dir / "memory-bank"
|
||||||
|
if not memory_src.is_dir():
|
||||||
|
print(f"ERROR: templates not found: {memory_src}", file=sys.stderr)
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
project_name = config.get("project_name")
|
project_name = config.get("project_name")
|
||||||
|
|
@ -520,18 +638,12 @@ def sync_templates_action(config: dict, context: dict) -> int:
|
||||||
date_value = config.get("date") or datetime.now().strftime("%Y-%m-%d")
|
date_value = config.get("date") or datetime.now().strftime("%Y-%m-%d")
|
||||||
force = bool(config.get("force", False))
|
force = bool(config.get("force", False))
|
||||||
no_backup = bool(config.get("no_backup", False))
|
no_backup = bool(config.get("no_backup", False))
|
||||||
full = bool(config.get("full", False))
|
|
||||||
|
|
||||||
memory_src = templates_dir / "memory-bank"
|
|
||||||
prompts_src = templates_dir / "prompts"
|
|
||||||
agents_src = templates_dir / "AGENTS.template.md"
|
|
||||||
rules_src = templates_dir / "AGENT_RULES.template.md"
|
|
||||||
|
|
||||||
if memory_src.is_dir():
|
|
||||||
memory_dst = project_root / "memory-bank"
|
memory_dst = project_root / "memory-bank"
|
||||||
if memory_dst.exists() and not force:
|
if memory_dst.exists() and not force:
|
||||||
log("memory-bank/ already exists. Use force to overwrite.")
|
log("memory-bank/ already exists. Use force to overwrite.")
|
||||||
else:
|
return 0
|
||||||
|
|
||||||
backup_path(memory_dst, no_backup)
|
backup_path(memory_dst, no_backup)
|
||||||
copytree(memory_src, memory_dst)
|
copytree(memory_src, memory_dst)
|
||||||
rename_template_files(memory_dst)
|
rename_template_files(memory_dst)
|
||||||
|
|
@ -543,12 +655,33 @@ def sync_templates_action(config: dict, context: dict) -> int:
|
||||||
playbook_scripts,
|
playbook_scripts,
|
||||||
)
|
)
|
||||||
log("Synced: memory-bank/")
|
log("Synced: memory-bank/")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def sync_prompts_action(config: dict, context: dict) -> int:
|
||||||
|
project_root: Path = context["project_root"]
|
||||||
|
if project_root.resolve() == PLAYBOOK_ROOT.resolve():
|
||||||
|
log("Skip: playbook root equals project root.")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
templates_dir = PLAYBOOK_ROOT / "templates"
|
||||||
|
prompts_src = templates_dir / "prompts"
|
||||||
|
if not prompts_src.is_dir():
|
||||||
|
print(f"ERROR: templates not found: {prompts_src}", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
|
||||||
|
project_name = resolve_project_name(context)
|
||||||
|
main_language = resolve_main_language(config, context)
|
||||||
|
playbook_scripts = resolve_playbook_scripts(project_root, context)
|
||||||
|
date_value = config.get("date") or datetime.now().strftime("%Y-%m-%d")
|
||||||
|
force = bool(config.get("force", False))
|
||||||
|
no_backup = bool(config.get("no_backup", False))
|
||||||
|
|
||||||
if prompts_src.is_dir():
|
|
||||||
prompts_dst = project_root / "docs/prompts"
|
prompts_dst = project_root / "docs/prompts"
|
||||||
if prompts_dst.exists() and not force:
|
if prompts_dst.exists() and not force:
|
||||||
log("docs/prompts/ already exists. Use force to overwrite.")
|
log("docs/prompts/ already exists. Use force to overwrite.")
|
||||||
else:
|
return 0
|
||||||
|
|
||||||
backup_path(prompts_dst, no_backup)
|
backup_path(prompts_dst, no_backup)
|
||||||
ensure_dir(prompts_dst.parent)
|
ensure_dir(prompts_dst.parent)
|
||||||
copytree(prompts_src, prompts_dst)
|
copytree(prompts_src, prompts_dst)
|
||||||
|
|
@ -561,39 +694,6 @@ def sync_templates_action(config: dict, context: dict) -> int:
|
||||||
playbook_scripts,
|
playbook_scripts,
|
||||||
)
|
)
|
||||||
log("Synced: docs/prompts/")
|
log("Synced: docs/prompts/")
|
||||||
|
|
||||||
if agents_src.is_file():
|
|
||||||
agents_dst = project_root / "AGENTS.md"
|
|
||||||
if full:
|
|
||||||
start_marker = "<!-- playbook:framework:start -->"
|
|
||||||
end_marker = "<!-- playbook:framework:end -->"
|
|
||||||
else:
|
|
||||||
start_marker = "<!-- playbook:templates:start -->"
|
|
||||||
end_marker = "<!-- playbook:templates:end -->"
|
|
||||||
update_agents_section(
|
|
||||||
agents_dst,
|
|
||||||
agents_src,
|
|
||||||
start_marker,
|
|
||||||
end_marker,
|
|
||||||
project_name,
|
|
||||||
date_value,
|
|
||||||
main_language,
|
|
||||||
playbook_scripts,
|
|
||||||
)
|
|
||||||
|
|
||||||
if rules_src.is_file():
|
|
||||||
rules_dst = project_root / "AGENT_RULES.md"
|
|
||||||
if rules_dst.exists() and not force:
|
|
||||||
log("AGENT_RULES.md already exists. Use force to overwrite.")
|
|
||||||
else:
|
|
||||||
backup_path(rules_dst, no_backup)
|
|
||||||
text = rules_src.read_text(encoding="utf-8")
|
|
||||||
text = replace_placeholders(
|
|
||||||
text, project_name, date_value, main_language, playbook_scripts
|
|
||||||
)
|
|
||||||
rules_dst.write_text(text + "\n", encoding="utf-8")
|
|
||||||
log("Synced: AGENT_RULES.md")
|
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -959,8 +1059,12 @@ def run_action(name: str, config: dict, context: dict) -> int:
|
||||||
print(f"[action] {name}")
|
print(f"[action] {name}")
|
||||||
if name == "vendor":
|
if name == "vendor":
|
||||||
return vendor_action(config, context)
|
return vendor_action(config, context)
|
||||||
if name == "sync_templates":
|
if name == "sync_rules":
|
||||||
return sync_templates_action(config, context)
|
return sync_rules_action(config, context)
|
||||||
|
if name == "sync_memory_bank":
|
||||||
|
return sync_memory_bank_action(config, context)
|
||||||
|
if name == "sync_prompts":
|
||||||
|
return sync_prompts_action(config, context)
|
||||||
if name == "sync_standards":
|
if name == "sync_standards":
|
||||||
return sync_standards_action(config, context)
|
return sync_standards_action(config, context)
|
||||||
if name == "install_skills":
|
if name == "install_skills":
|
||||||
|
|
@ -1002,6 +1106,11 @@ def main(argv: list[str]) -> int:
|
||||||
"config": config,
|
"config": config,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if should_sync_agents(config):
|
||||||
|
result = sync_agents_template(context)
|
||||||
|
if result != 0:
|
||||||
|
return result
|
||||||
|
|
||||||
for name in ORDER:
|
for name in ORDER:
|
||||||
if name in config:
|
if name in config:
|
||||||
result = run_action(name, config[name], context)
|
result = run_action(name, config[name], context)
|
||||||
|
|
|
||||||
|
|
@ -37,16 +37,25 @@ templates/
|
||||||
|
|
||||||
## 快速部署
|
## 快速部署
|
||||||
|
|
||||||
使用统一入口 `playbook.py`:
|
使用统一入口 `playbook.py`,配置节存在即启用:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
# playbook.toml
|
# playbook.toml
|
||||||
[playbook]
|
[playbook]
|
||||||
project_root = "/path/to/project"
|
project_root = "/path/to/project"
|
||||||
|
|
||||||
[sync_templates]
|
# 同步 AGENT_RULES.md(配置节存在即启用)
|
||||||
|
[sync_rules]
|
||||||
|
# force = true # 可选,强制覆盖已存在的文件
|
||||||
|
|
||||||
|
# 同步 memory-bank/(配置节存在即启用)
|
||||||
|
[sync_memory_bank]
|
||||||
project_name = "MyProject"
|
project_name = "MyProject"
|
||||||
full = false
|
# force = true # 可选,强制覆盖(会先备份)
|
||||||
|
|
||||||
|
# 同步 docs/prompts/(配置节存在即启用)
|
||||||
|
[sync_prompts]
|
||||||
|
# force = true # 可选,强制覆盖(会先备份)
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
@ -55,14 +64,37 @@ python docs/standards/playbook/scripts/playbook.py -config playbook.toml
|
||||||
|
|
||||||
参数说明见 `playbook.toml.example`(仓库根目录)或 vendoring 后的 `docs/standards/playbook/playbook.toml.example`。
|
参数说明见 `playbook.toml.example`(仓库根目录)或 vendoring 后的 `docs/standards/playbook/playbook.toml.example`。
|
||||||
|
|
||||||
### 部署行为
|
### 配置节说明
|
||||||
|
|
||||||
- **新项目**:创建完整的 AGENTS.md、AGENT_RULES.md、memory-bank/、docs/prompts/
|
| 配置节 | 部署内容 | 选项 |
|
||||||
- **已有 AGENTS.md**:
|
| -------------------- | -------------- | ----------------------- |
|
||||||
- 默认:追加路由链接(`<!-- playbook:templates:start/end -->`)
|
| `[sync_rules]` | AGENT_RULES.md | `force` |
|
||||||
- `full = true`:追加完整框架(规则优先级 + 路由 + 新会话开始时)
|
| `[sync_memory_bank]` | memory-bank/ | `project_name`, `force` |
|
||||||
- **其他文件**:如果已存在则跳过(使用 `force = true` 覆盖)
|
| `[sync_prompts]` | docs/prompts/ | `force` |
|
||||||
- **占位符替换**:自动替换 `{{DATE}}` 为当前日期
|
|
||||||
|
- **配置节存在即启用**:只写需要同步的配置节
|
||||||
|
- **AGENTS.md**:始终按区块更新(`<!-- playbook:xxx:start/end -->`),不受配置节控制
|
||||||
|
- **force**:默认 false,已存在则跳过;设为 true 时强制覆盖(memory-bank/ 和 prompts/ 会先备份)
|
||||||
|
- **占位符替换**:自动替换 `{{DATE}}`、`{{PLAYBOOK_SCRIPTS}}` 等
|
||||||
|
|
||||||
|
### 典型场景
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# 场景 1:初次部署(全部)
|
||||||
|
[sync_rules]
|
||||||
|
[sync_memory_bank]
|
||||||
|
project_name = "MyProject"
|
||||||
|
[sync_prompts]
|
||||||
|
|
||||||
|
# 场景 2:框架升级(只更新规则)
|
||||||
|
[sync_rules]
|
||||||
|
force = true
|
||||||
|
|
||||||
|
# 场景 3:重置项目上下文
|
||||||
|
[sync_memory_bank]
|
||||||
|
project_name = "MyProject"
|
||||||
|
force = true
|
||||||
|
```
|
||||||
|
|
||||||
### 部署后的目录结构
|
### 部署后的目录结构
|
||||||
|
|
||||||
|
|
@ -99,9 +131,8 @@ project/
|
||||||
| `{{PLAYBOOK_SCRIPTS}}` | 脚本路径 | ✅ 是 |
|
| `{{PLAYBOOK_SCRIPTS}}` | 脚本路径 | ✅ 是 |
|
||||||
| 其他 `{{...}}` | 项目特定内容 | ❌ 手动 |
|
| 其他 `{{...}}` | 项目特定内容 | ❌ 手动 |
|
||||||
|
|
||||||
`{{PROJECT_NAME}}` 可通过 `sync_templates.project_name` 自动替换;未配置时保持原样。
|
`{{PROJECT_NAME}}` 可通过 `sync_memory_bank.project_name` 自动替换;未配置时保持原样。
|
||||||
`{{MAIN_LANGUAGE}}` 可通过 `sync_templates.main_language` 或 `sync_standards.langs[0]` 自动替换;
|
`{{MAIN_LANGUAGE}}` 可通过 `sync_standards.langs[0]` 自动替换;未配置时默认 `tsl`。
|
||||||
未配置时默认 `tsl`。
|
|
||||||
`{{PLAYBOOK_SCRIPTS}}` 自动替换为 Playbook 脚本路径(默认 `docs/standards/playbook/scripts`)。
|
`{{PLAYBOOK_SCRIPTS}}` 自动替换为 Playbook 脚本路径(默认 `docs/standards/playbook/scripts`)。
|
||||||
|
|
||||||
## 模板说明
|
## 模板说明
|
||||||
|
|
@ -170,11 +201,11 @@ project/
|
||||||
|
|
||||||
**playbook 标记**(用于自动更新):
|
**playbook 标记**(用于自动更新):
|
||||||
|
|
||||||
| 标记 | 用途 | 管理入口 |
|
| 标记 | 用途 | 说明 |
|
||||||
| --------------------------------------- | --------------------- | ------------------------------ |
|
| --------------------------------------- | ------------ | -------------------------- |
|
||||||
| `<!-- playbook:agents:start/end -->` | 语言规则链接 | playbook.py `[sync_standards]` |
|
| `<!-- playbook:agents:start/end -->` | 语言规则链接 | 由 `[sync_standards]` 管理 |
|
||||||
| `<!-- playbook:templates:start/end -->` | 路由链接(默认追加) | playbook.py `[sync_templates]` |
|
| `<!-- playbook:templates:start/end -->` | 路由链接 | AGENTS.md 始终按区块更新 |
|
||||||
| `<!-- playbook:framework:start/end -->` | 完整框架(full 追加) | playbook.py `[sync_templates]` |
|
| `<!-- playbook:framework:start/end -->` | 完整框架 | AGENTS.md 始终按区块更新 |
|
||||||
|
|
||||||
### ci/、cpp/、python/
|
### ci/、cpp/、python/
|
||||||
|
|
||||||
|
|
@ -213,7 +244,7 @@ playbook/
|
||||||
├── docs/ # 权威静态文档
|
├── docs/ # 权威静态文档
|
||||||
├── templates/ # 本目录:项目架构模板 → 部署到 memory-bank/ 等
|
├── templates/ # 本目录:项目架构模板 → 部署到 memory-bank/ 等
|
||||||
└── scripts/
|
└── scripts/
|
||||||
├── playbook.py # 统一入口:vendor/sync_templates/sync_standards/...
|
├── playbook.py # 统一入口:vendor/sync_rules/sync_memory_bank/sync_prompts/sync_standards/...
|
||||||
└── plan_progress.py # Plan 选择与进度记录
|
└── plan_progress.py # Plan 选择与进度记录
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ tests/
|
||||||
├── test_gitattributes_modes.py # gitattr_mode 行为测试
|
├── test_gitattributes_modes.py # gitattr_mode 行为测试
|
||||||
├── test_plan_progress_cli.py # plan_progress CLI 测试
|
├── test_plan_progress_cli.py # plan_progress CLI 测试
|
||||||
├── test_superpowers_list_sync.py # superpowers 列表一致性测试
|
├── test_superpowers_list_sync.py # superpowers 列表一致性测试
|
||||||
├── test_sync_templates_placeholders.py # 占位符替换测试
|
├── test_sync_templates_placeholders.py # 占位符替换测试(sync_rules/sync_standards)
|
||||||
├── test_toml_edge_cases.py # TOML 解析边界测试
|
├── test_toml_edge_cases.py # TOML 解析边界测试
|
||||||
├── templates/ # 模板验证测试
|
├── templates/ # 模板验证测试
|
||||||
│ ├── validate_python_templates.sh # Python 模板验证
|
│ ├── validate_python_templates.sh # Python 模板验证
|
||||||
|
|
@ -64,7 +64,7 @@ sh tests/integration/check_doc_links.sh
|
||||||
|
|
||||||
- CLI 参数解析与帮助信息
|
- CLI 参数解析与帮助信息
|
||||||
- TOML 配置解析与动作顺序
|
- TOML 配置解析与动作顺序
|
||||||
- vendor/sync/install 等基础动作落地
|
- vendor/sync_rules/sync_memory_bank/sync_prompts/sync_standards 等基础动作落地
|
||||||
|
|
||||||
### 2. 模板验证测试 (templates/)
|
### 2. 模板验证测试 (templates/)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,13 +65,13 @@ langs = ["tsl"]
|
||||||
self.assertEqual(result.returncode, 0)
|
self.assertEqual(result.returncode, 0)
|
||||||
self.assertTrue(snapshot.is_file())
|
self.assertTrue(snapshot.is_file())
|
||||||
|
|
||||||
def test_sync_templates_creates_memory_bank(self):
|
def test_sync_memory_bank_creates_memory_bank(self):
|
||||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||||
config_body = f"""
|
config_body = f"""
|
||||||
[playbook]
|
[playbook]
|
||||||
project_root = "{tmp_dir}"
|
project_root = "{tmp_dir}"
|
||||||
|
|
||||||
[sync_templates]
|
[sync_memory_bank]
|
||||||
project_name = "Demo"
|
project_name = "Demo"
|
||||||
"""
|
"""
|
||||||
config_path = Path(tmp_dir) / "playbook.toml"
|
config_path = Path(tmp_dir) / "playbook.toml"
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,7 @@ class SyncTemplatesPlaceholdersTests(unittest.TestCase):
|
||||||
[playbook]
|
[playbook]
|
||||||
project_root = \"{tmp_dir}\"
|
project_root = \"{tmp_dir}\"
|
||||||
|
|
||||||
[sync_templates]
|
[sync_rules]
|
||||||
project_name = \"Demo\"
|
|
||||||
full = true
|
|
||||||
|
|
||||||
[sync_standards]
|
[sync_standards]
|
||||||
langs = [\"cpp\", \"tsl\"]
|
langs = [\"cpp\", \"tsl\"]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue