✨ feat(playbook): add no_backup deploy controls
remove obsolete main_language placeholders and language summary template text limit generated .agents guidance to configured langs and normalize AGENT_RULES trailing newlines document install_skills no_backup behavior and refresh tests for deployment links and sync flows
This commit is contained in:
parent
8609d59d4a
commit
a2e3cb07de
|
|
@ -175,6 +175,8 @@ TSL 相关问题直接查阅 `rulesets/tsl/index.md` 与 `docs/tsl/`。
|
|||
|
||||
**安装与使用**:详见 `SKILLS.md`
|
||||
|
||||
如果你通过 `[install_skills]` 更新已经安装过的 skill,默认会先把旧目录备份为 `*.bak.<timestamp>`;如果你明确希望“删除旧版本后直接重装”,可在 `playbook.toml` 的 `[install_skills]` 下设置 `no_backup = true`。
|
||||
|
||||
## 在其他项目中使用本 Playbook
|
||||
|
||||
由于本仓库需要内部权限访问,其他项目**不能仅用外链引用**;推荐把 Playbook 规范部署到项目内,并用统一入口执行。
|
||||
|
|
|
|||
13
SKILLS.md
13
SKILLS.md
|
|
@ -75,10 +75,23 @@ skills = ["style-cleanup", "commit-message"]
|
|||
[install_skills]
|
||||
mode = "all"
|
||||
agents_home = "./.agents"
|
||||
# no_backup = true
|
||||
```
|
||||
|
||||
> 注意:Codex 默认从 `~/.agents/skills` 加载 skills;使用本地安装时,需要确保 Codex 能发现该路径。
|
||||
|
||||
`[install_skills]` 默认会先把已存在的 skill 目录重命名为 `*.bak.<timestamp>`,再复制新版本,便于手动回退。
|
||||
如果你希望安装过程不保留备份,而是“先删除旧目录,再复制新目录”,可显式设置:
|
||||
|
||||
```toml
|
||||
[install_skills]
|
||||
mode = "all"
|
||||
agents_home = "~/.agents"
|
||||
no_backup = true
|
||||
```
|
||||
|
||||
`no_backup = true` 适合 CI 或你已经用 Git 管理变更、只想要确定性覆盖安装的场景。
|
||||
|
||||
如果你的项目已经把本 Playbook 部署到项目内(无论来自 `git subtree`,还是外部 clone 后部署到自定义根目录),则在目标项目里执行:
|
||||
|
||||
```bash
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# TSL函数
|
||||
|
||||
> 本文档从 [docs/tsl/syntax_book/function/index.md](../../docs/tsl/syntax_book/function/index.md) 拆分而来
|
||||
> 本文档对应的正式检索入口见 [docs/tsl/reference/catalog/index.md](../../docs/tsl/reference/catalog/index.md)
|
||||
|
||||
TSL函数包含数学、系统、基础、图形等通用函数,适用于各种TSL脚本开发场景。
|
||||
|
||||
|
|
@ -80,4 +80,4 @@ TSL函数包含数学、系统、基础、图形等通用函数,适用于各
|
|||
|
||||
---
|
||||
|
||||
**返回**: [docs/tsl/syntax_book/function/index.md](../../docs/tsl/syntax_book/function/index.md)
|
||||
**返回**: [docs/tsl/reference/catalog/index.md](../../docs/tsl/reference/catalog/index.md)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
# force = false # 可选:覆盖已有文件
|
||||
# no_backup = false # 可选:跳过备份
|
||||
# date = "2026-04-22" # 可选:替换 {{DATE}}
|
||||
# main_language = "tsl" # 可选:覆盖 {{MAIN_LANGUAGE}}
|
||||
|
||||
[sync_memory_bank]
|
||||
# 同步 memory-bank/(配置节存在即启用)
|
||||
|
|
@ -25,7 +24,6 @@
|
|||
# force = false # 可选:覆盖已有文件(会先备份)
|
||||
# no_backup = false # 可选:跳过备份
|
||||
# date = "2026-04-22" # 可选:替换 {{DATE}}
|
||||
# main_language = "tsl" # 可选:覆盖 {{MAIN_LANGUAGE}}
|
||||
|
||||
[sync_prompts]
|
||||
# 同步 docs/prompts/(配置节存在即启用)
|
||||
|
|
@ -33,7 +31,6 @@
|
|||
# force = false # 可选:覆盖已有文件(会先备份)
|
||||
# no_backup = false # 可选:跳过备份
|
||||
# date = "2026-04-22" # 可选:替换 {{DATE}}
|
||||
# main_language = "tsl" # 可选:覆盖 {{MAIN_LANGUAGE}}
|
||||
|
||||
[sync_standards]
|
||||
# langs = ["tsl", "cpp", "typescript"] # 必填:要同步的语言
|
||||
|
|
@ -44,6 +41,7 @@
|
|||
# mode = "list" # list|all
|
||||
# skills = ["brainstorming"] # mode=list 时必填
|
||||
# agents_home = "~/.agents" # 可选:默认 ~/.agents
|
||||
# no_backup = false # 可选:跳过备份,直接删除旧 skill 后重装
|
||||
|
||||
[format_md]
|
||||
# tool = "prettier" # 仅支持 prettier
|
||||
|
|
|
|||
|
|
@ -320,29 +320,7 @@ def resolve_docs_prefix(context: dict) -> str:
|
|||
return join_deploy_subpath(resolve_deploy_root(context), "docs")
|
||||
|
||||
|
||||
def resolve_main_language(config: dict, context: dict) -> str:
|
||||
raw = config.get("main_language")
|
||||
if raw is not None and str(raw).strip():
|
||||
return str(raw).strip()
|
||||
|
||||
full_config = context.get("config", {})
|
||||
if isinstance(full_config, dict):
|
||||
sync_conf = full_config.get("sync_standards")
|
||||
if isinstance(sync_conf, dict):
|
||||
langs_raw = sync_conf.get("langs")
|
||||
if langs_raw is not None:
|
||||
try:
|
||||
langs = normalize_langs(langs_raw)
|
||||
except ValueError:
|
||||
langs = []
|
||||
if langs:
|
||||
return langs[0]
|
||||
|
||||
return "tsl"
|
||||
|
||||
|
||||
def resolve_playbook_scripts(project_root: Path, context: dict) -> str:
|
||||
_ = project_root
|
||||
def resolve_playbook_scripts(context: dict) -> str:
|
||||
return join_deploy_subpath(resolve_deploy_root(context), "scripts")
|
||||
|
||||
|
||||
|
|
@ -541,14 +519,11 @@ def replace_placeholders(
|
|||
text: str,
|
||||
project_name: str | None,
|
||||
date_value: str,
|
||||
main_language: str | None,
|
||||
playbook_scripts: str | None,
|
||||
) -> str:
|
||||
result = text.replace("{{DATE}}", date_value)
|
||||
if project_name:
|
||||
result = result.replace("{{PROJECT_NAME}}", project_name)
|
||||
if main_language:
|
||||
result = result.replace("{{MAIN_LANGUAGE}}", main_language)
|
||||
if playbook_scripts:
|
||||
result = result.replace("{{PLAYBOOK_SCRIPTS}}", playbook_scripts)
|
||||
return result
|
||||
|
|
@ -563,41 +538,16 @@ def backup_path(path: Path, no_backup: bool) -> None:
|
|||
log(f"Backed up: {path} -> {backup}")
|
||||
|
||||
|
||||
def rename_template_files(root: Path) -> None:
|
||||
for template in root.rglob("*.template.md"):
|
||||
target = template.with_name(template.name.replace(".template.md", ".md"))
|
||||
template.rename(target)
|
||||
|
||||
|
||||
def replace_placeholders_in_dir(
|
||||
root: Path,
|
||||
project_name: str | None,
|
||||
date_value: str,
|
||||
main_language: str | None,
|
||||
playbook_scripts: str | None,
|
||||
) -> None:
|
||||
for file_path in root.rglob("*.md"):
|
||||
text = file_path.read_text(encoding="utf-8")
|
||||
updated = replace_placeholders(
|
||||
text, project_name, date_value, main_language, playbook_scripts
|
||||
)
|
||||
if updated != text:
|
||||
file_path.write_text(updated, encoding="utf-8")
|
||||
|
||||
|
||||
def replace_placeholders_in_file(
|
||||
file_path: Path,
|
||||
project_name: str | None,
|
||||
date_value: str,
|
||||
main_language: str | None,
|
||||
playbook_scripts: str | None,
|
||||
) -> None:
|
||||
if file_path.suffix != ".md":
|
||||
return
|
||||
text = file_path.read_text(encoding="utf-8")
|
||||
updated = replace_placeholders(
|
||||
text, project_name, date_value, main_language, playbook_scripts
|
||||
)
|
||||
updated = replace_placeholders(text, project_name, date_value, playbook_scripts)
|
||||
if updated != text:
|
||||
file_path.write_text(updated, encoding="utf-8")
|
||||
|
||||
|
|
@ -616,7 +566,6 @@ def sync_directory(
|
|||
target_dir: Path,
|
||||
project_name: str | None,
|
||||
date_value: str,
|
||||
main_language: str | None,
|
||||
playbook_scripts: str | None,
|
||||
force: bool,
|
||||
no_backup: bool,
|
||||
|
|
@ -637,7 +586,6 @@ def sync_directory(
|
|||
target_file,
|
||||
project_name,
|
||||
date_value,
|
||||
main_language,
|
||||
playbook_scripts,
|
||||
)
|
||||
|
||||
|
|
@ -665,12 +613,11 @@ def update_agents_section(
|
|||
end_marker: str,
|
||||
project_name: str | None,
|
||||
date_value: str,
|
||||
main_language: str | None,
|
||||
playbook_scripts: str | None,
|
||||
) -> None:
|
||||
template_text = template_path.read_text(encoding="utf-8")
|
||||
template_text = replace_placeholders(
|
||||
template_text, project_name, date_value, main_language, playbook_scripts
|
||||
template_text, project_name, date_value, playbook_scripts
|
||||
)
|
||||
block = extract_block_lines(template_text, start_marker, end_marker)
|
||||
if not block:
|
||||
|
|
@ -746,8 +693,7 @@ def sync_agents_template(context: dict) -> int:
|
|||
return 0
|
||||
|
||||
project_name = resolve_project_name(context)
|
||||
main_language = resolve_main_language({}, context)
|
||||
playbook_scripts = resolve_playbook_scripts(project_root, context)
|
||||
playbook_scripts = resolve_playbook_scripts(context)
|
||||
date_value = resolve_template_date(context)
|
||||
|
||||
agents_dst = project_root / "AGENTS.md"
|
||||
|
|
@ -773,7 +719,6 @@ def sync_agents_template(context: dict) -> int:
|
|||
end_marker,
|
||||
project_name,
|
||||
date_value,
|
||||
main_language,
|
||||
playbook_scripts,
|
||||
)
|
||||
return 0
|
||||
|
|
@ -805,17 +750,14 @@ def sync_rules_action(config: dict, context: dict) -> int:
|
|||
return 0
|
||||
|
||||
project_name = resolve_project_name(context)
|
||||
main_language = resolve_main_language(config, context)
|
||||
playbook_scripts = resolve_playbook_scripts(project_root, context)
|
||||
playbook_scripts = resolve_playbook_scripts(context)
|
||||
date_value = config.get("date") or datetime.now().strftime("%Y-%m-%d")
|
||||
no_backup = bool(config.get("no_backup", False))
|
||||
|
||||
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")
|
||||
text = replace_placeholders(text, project_name, date_value, playbook_scripts)
|
||||
rules_dst.write_text(text.rstrip("\n") + "\n", encoding="utf-8")
|
||||
log("Synced: AGENT_RULES.md")
|
||||
return 0
|
||||
|
||||
|
|
@ -833,8 +775,7 @@ def sync_memory_bank_action(config: dict, context: dict) -> int:
|
|||
return 2
|
||||
|
||||
project_name = config.get("project_name")
|
||||
main_language = resolve_main_language(config, context)
|
||||
playbook_scripts = resolve_playbook_scripts(project_root, context)
|
||||
playbook_scripts = resolve_playbook_scripts(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))
|
||||
|
|
@ -846,7 +787,6 @@ def sync_memory_bank_action(config: dict, context: dict) -> int:
|
|||
memory_dst,
|
||||
project_name,
|
||||
date_value,
|
||||
main_language,
|
||||
playbook_scripts,
|
||||
force,
|
||||
no_backup,
|
||||
|
|
@ -868,8 +808,7 @@ def sync_prompts_action(config: dict, context: dict) -> int:
|
|||
return 2
|
||||
|
||||
project_name = resolve_project_name(context)
|
||||
main_language = resolve_main_language(config, context)
|
||||
playbook_scripts = resolve_playbook_scripts(project_root, context)
|
||||
playbook_scripts = resolve_playbook_scripts(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))
|
||||
|
|
@ -882,7 +821,6 @@ def sync_prompts_action(config: dict, context: dict) -> int:
|
|||
prompts_dst,
|
||||
project_name,
|
||||
date_value,
|
||||
main_language,
|
||||
playbook_scripts,
|
||||
force,
|
||||
no_backup,
|
||||
|
|
@ -945,6 +883,13 @@ def update_agents_block(agents_md: Path, block_lines: list[str]) -> None:
|
|||
|
||||
def create_agents_index(agents_root: Path, langs: list[str], docs_prefix: str | None) -> None:
|
||||
agents_index = agents_root / "index.md"
|
||||
lang_descriptions = {
|
||||
"tsl": "TSL 相关规则集(由 playbook 同步;适用于 `.tsl`/`.tsf`)",
|
||||
"cpp": "C++ 相关规则集(由 playbook 同步;适用于 C++23/Modules)",
|
||||
"python": "Python 相关规则集(由 playbook 同步)",
|
||||
"typescript": "TypeScript/JavaScript 相关规则集(由 playbook 同步)",
|
||||
"markdown": "Markdown 相关规则集(仅代码格式化)",
|
||||
}
|
||||
lines = [
|
||||
"# .agents(多语言)",
|
||||
"",
|
||||
|
|
@ -952,11 +897,11 @@ def create_agents_index(agents_root: Path, langs: list[str], docs_prefix: str |
|
|||
"",
|
||||
"建议约定:",
|
||||
"",
|
||||
"- `.agents/tsl/`:TSL 相关规则集(由 playbook 同步;适用于 `.tsl`/`.tsf`)",
|
||||
"- `.agents/cpp/`:C++ 相关规则集(由 playbook 同步;适用于 C++23/Modules)",
|
||||
"- `.agents/python/`:Python 相关规则集(由 playbook 同步)",
|
||||
"- `.agents/typescript/`:TypeScript/JavaScript 相关规则集(由 playbook 同步)",
|
||||
"- `.agents/markdown/`:Markdown 相关规则集(仅代码格式化)",
|
||||
]
|
||||
for lang in langs:
|
||||
description = lang_descriptions.get(lang, "相关规则集(由 playbook 同步)")
|
||||
lines.append(f"- `.agents/{lang}/`:{description}")
|
||||
lines += [
|
||||
"",
|
||||
"规则发生冲突时,建议以“更靠近代码的目录规则更具体”为准。",
|
||||
"",
|
||||
|
|
@ -1220,6 +1165,7 @@ def install_skills_action(config: dict, context: dict) -> int:
|
|||
return 2
|
||||
|
||||
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
|
||||
no_backup = bool(config.get("no_backup", False))
|
||||
for name in skills:
|
||||
src = skills_src_root / name
|
||||
if not src.is_dir():
|
||||
|
|
@ -1227,6 +1173,9 @@ def install_skills_action(config: dict, context: dict) -> int:
|
|||
return 2
|
||||
dst = skills_dst_root / name
|
||||
if dst.exists():
|
||||
if no_backup:
|
||||
rmtree(dst)
|
||||
else:
|
||||
backup = skills_dst_root / f"{name}.bak.{timestamp}"
|
||||
dst.rename(backup)
|
||||
log(f"Backed up existing skill: {name} -> {backup.name}")
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
请以 `.agents/` 下的规则为准:
|
||||
|
||||
- 入口:`.agents/index.md`
|
||||
- 语言规则:`.agents/{{MAIN_LANGUAGE}}/index.md`
|
||||
- 语言规则:见 `.agents/index.md` 与对应语言子目录
|
||||
<!-- playbook:agents:end -->
|
||||
|
||||
<!-- playbook:templates:start -->
|
||||
|
|
|
|||
|
|
@ -186,12 +186,10 @@ project/
|
|||
| `{{PROJECT_NAME}}` | 项目名称 | ✅ 可选 |
|
||||
| `{{PROJECT_GOAL}}` | 项目目标 | ❌ 手动 |
|
||||
| `{{PROJECT_DESCRIPTION}}` | 项目描述 | ❌ 手动 |
|
||||
| `{{MAIN_LANGUAGE}}` | 主语言 | ✅ 可选 |
|
||||
| `{{PLAYBOOK_SCRIPTS}}` | 脚本路径 | ✅ 是 |
|
||||
| 其他 `{{...}}` | 项目特定内容 | ❌ 手动 |
|
||||
|
||||
`{{PROJECT_NAME}}` 可通过 `sync_memory_bank.project_name` 自动替换;未配置时保持原样。
|
||||
`{{MAIN_LANGUAGE}}` 可通过 `sync_standards.langs[0]` 自动替换;未配置时默认 `tsl`。
|
||||
`{{PLAYBOOK_SCRIPTS}}` 自动替换为 Playbook 脚本路径(默认 `docs/standards/playbook/scripts`,也可按项目配置改成 `custom/playbook/scripts` 等)。
|
||||
|
||||
## 模板说明
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@
|
|||
|
||||
<!-- 【必填】 -->
|
||||
|
||||
**主语言**:{{MAIN_LANGUAGE}}
|
||||
|
||||
**文件类型**:{{FILE_TYPES}}
|
||||
|
||||
## 项目结构
|
||||
|
|
|
|||
|
|
@ -237,6 +237,29 @@ no_backup = true
|
|||
self.assertIn("`.agents/tsl/index.md`", agents_index)
|
||||
self.assertIn("`.agents/cpp/index.md`", agents_index)
|
||||
|
||||
def test_sync_standards_agents_index_only_lists_configured_langs(self):
|
||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||
root = Path(tmp_dir)
|
||||
config_body = f"""
|
||||
[playbook]
|
||||
project_root = "{tmp_dir}"
|
||||
deploy_root = "{CUSTOM_DEPLOY_ROOT}"
|
||||
|
||||
[sync_standards]
|
||||
langs = ["tsl", "markdown"]
|
||||
"""
|
||||
config_path = write_config(root, "playbook.toml", config_body)
|
||||
|
||||
result = run_cli("-config", str(config_path))
|
||||
self.assertEqual(result.returncode, 0, msg=result.stdout + result.stderr)
|
||||
|
||||
agents_index = (root / ".agents" / "index.md").read_text(encoding="utf-8")
|
||||
self.assertIn("`.agents/tsl/`:TSL 相关规则集", agents_index)
|
||||
self.assertIn("`.agents/markdown/`:Markdown 相关规则集", agents_index)
|
||||
self.assertNotIn("`.agents/cpp/`", agents_index)
|
||||
self.assertNotIn("`.agents/python/`", agents_index)
|
||||
self.assertNotIn("`.agents/typescript/`", agents_index)
|
||||
|
||||
def test_sync_standards_agents_block_has_blank_lines(self):
|
||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||
config_body = f"""
|
||||
|
|
|
|||
|
|
@ -74,6 +74,36 @@ no_backup = true
|
|||
git_backups = list(root.glob(".gitattributes.bak.*"))
|
||||
self.assertEqual(git_backups, [])
|
||||
|
||||
def test_install_skills_no_backup_replaces_existing_skill_without_backup(self):
|
||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||
root = Path(tmp_dir)
|
||||
skills_root = root / "agents" / "skills"
|
||||
existing = skills_root / "brainstorming"
|
||||
existing.mkdir(parents=True)
|
||||
(existing / "stale.txt").write_text("old", encoding="utf-8")
|
||||
|
||||
config_body = f"""
|
||||
[playbook]
|
||||
project_root = "{tmp_dir}"
|
||||
deploy_root = "{DEFAULT_DEPLOY_ROOT}"
|
||||
|
||||
[install_skills]
|
||||
agents_home = "{root / 'agents'}"
|
||||
mode = "list"
|
||||
skills = ["brainstorming"]
|
||||
no_backup = true
|
||||
"""
|
||||
config_path = root / "playbook.toml"
|
||||
config_path.write_text(config_body, encoding="utf-8")
|
||||
|
||||
result = run_cli("-config", str(config_path))
|
||||
self.assertEqual(result.returncode, 0, msg=result.stderr)
|
||||
|
||||
backups = list(skills_root.glob("brainstorming.bak.*"))
|
||||
self.assertEqual(backups, [])
|
||||
self.assertFalse((existing / "stale.txt").exists())
|
||||
self.assertTrue((existing / "SKILL.md").is_file())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
|
|
@ -27,7 +27,29 @@ def run_script(script_path: Path, *args, cwd: Path | None = None):
|
|||
|
||||
|
||||
class SyncTemplatesPlaceholdersTests(unittest.TestCase):
|
||||
def test_main_language_placeholder_replaced(self):
|
||||
def test_templates_no_longer_expose_main_language_placeholder(self):
|
||||
example_text = (ROOT / "playbook.toml.example").read_text(encoding="utf-8")
|
||||
self.assertNotIn("main_language", example_text)
|
||||
|
||||
templates_readme = (ROOT / "templates" / "README.md").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
self.assertNotIn("{{MAIN_LANGUAGE}}", templates_readme)
|
||||
self.assertNotIn("{{LANGUAGE_1}}", templates_readme)
|
||||
|
||||
agents_template = (ROOT / "templates" / "AGENTS.template.md").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
self.assertNotIn("{{MAIN_LANGUAGE}}", agents_template)
|
||||
|
||||
tech_stack_template = (
|
||||
ROOT / "templates" / "memory-bank" / "tech-stack.template.md"
|
||||
).read_text(encoding="utf-8")
|
||||
self.assertNotIn("{{MAIN_LANGUAGE}}", tech_stack_template)
|
||||
self.assertNotIn("{{LANGUAGE_1}}", tech_stack_template)
|
||||
self.assertNotIn("**主要语言**", tech_stack_template)
|
||||
|
||||
def test_sync_templates_replaces_playbook_scripts_without_main_language_support(self):
|
||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||
config_body = f"""
|
||||
[playbook]
|
||||
|
|
@ -36,6 +58,8 @@ deploy_root = "{DEFAULT_DEPLOY_ROOT}"
|
|||
|
||||
[sync_rules]
|
||||
|
||||
[sync_memory_bank]
|
||||
|
||||
[sync_standards]
|
||||
langs = [\"cpp\", \"tsl\"]
|
||||
"""
|
||||
|
|
@ -50,6 +74,12 @@ langs = [\"cpp\", \"tsl\"]
|
|||
self.assertIn(".agents/cpp/index.md", text)
|
||||
self.assertNotIn("{{MAIN_LANGUAGE}}", text)
|
||||
|
||||
tech_stack = Path(tmp_dir) / "memory-bank" / "tech-stack.md"
|
||||
tech_stack_text = tech_stack.read_text(encoding="utf-8")
|
||||
self.assertNotIn("{{LANGUAGE_1}}", tech_stack_text)
|
||||
self.assertNotIn("{{MAIN_LANGUAGE}}", tech_stack_text)
|
||||
self.assertNotIn("**主要语言**", tech_stack_text)
|
||||
|
||||
rules_md = Path(tmp_dir) / "AGENT_RULES.md"
|
||||
rules_text = rules_md.read_text(encoding="utf-8")
|
||||
self.assertIn("docs/standards/playbook/scripts/main_loop.py claim", rules_text)
|
||||
|
|
@ -57,6 +87,7 @@ langs = [\"cpp\", \"tsl\"]
|
|||
self.assertIn("不得直接使用 `$executing-plans`", rules_text)
|
||||
self.assertIn("不得直接使用 `$subagent-driven-development`", rules_text)
|
||||
self.assertNotIn("{{PLAYBOOK_SCRIPTS}}", rules_text)
|
||||
self.assertFalse(rules_text.endswith("\n\n"))
|
||||
|
||||
def test_sync_standards_rewrites_typescript_docs_prefix_for_vendored_playbook(self):
|
||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ PLAYBOOK_EXAMPLE = ROOT / "playbook.toml.example"
|
|||
SKILLS_DOC = ROOT / "SKILLS.md"
|
||||
TEMPLATES_CI_README = ROOT / "templates" / "ci" / "README.md"
|
||||
REMOVED_TSL_GUIDE = ROOT / "codex" / "skills" / "tsl-guide"
|
||||
REFERENCE_CATALOG_SOURCE_INDEX = ROOT / "data" / "tsl_reference_catalog_source" / "index.md"
|
||||
|
||||
|
||||
class TslEntrypointsConsistencyTests(unittest.TestCase):
|
||||
|
|
@ -51,6 +52,11 @@ class TslEntrypointsConsistencyTests(unittest.TestCase):
|
|||
self.assertNotIn("tsl-guide", SKILLS_DOC.read_text(encoding="utf-8"))
|
||||
self.assertNotIn("$tsl-guide", RULESET_TSL.read_text(encoding="utf-8"))
|
||||
|
||||
def test_reference_catalog_source_index_uses_canonical_reference_entrypoint(self):
|
||||
text = REFERENCE_CATALOG_SOURCE_INDEX.read_text(encoding="utf-8")
|
||||
self.assertIn("docs/tsl/reference/catalog/index.md", text)
|
||||
self.assertNotIn("docs/tsl/syntax_book/function/index.md", text)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
Loading…
Reference in New Issue