docs: add wiki maintenance gate

This commit is contained in:
tukuaiai
2026-05-17 13:15:05 +08:00
parent 5999675478
commit 1d204749a5
7 changed files with 163 additions and 3 deletions
+2 -1
View File
@@ -5,9 +5,10 @@
## 约束
- 脚本默认从仓库根目录运行,路径解析必须稳定。
- 新增检查脚本时,同步更新 `scripts/README.md``Makefile`、CI 和根目录 `AGENTS.md` 的命令清单。
- 新增检查脚本时,同步更新 `scripts/README.md``Makefile` 和根目录 `AGENTS.md` 的命令清单;只有 CI 环境稳定具备所需输入时才纳入 CI
- `check-directory-docs.py` 对根 `.github/` 只要求 `AGENTS.md`,不要重新补 `.github/README.md`
- 修改 docs 线性 README 的主章节或锚点后,优先运行 `python3 scripts/sync-doc-toc.py`,再运行 `make test`
- 修改 GitHub Wiki 独立仓库后,运行 `make check-wiki WIKI_DIR=/path/to/wiki`;不要把 Wiki checkout 提交进主仓。
- 检查失败输出应包含文件路径、行号或可定位的错误信息。
- 跳过目录必须明确,至少跳过 `.git``.history``node_modules` 和外部源码快照。
+1
View File
@@ -10,4 +10,5 @@
- `check-directory-docs.py`:仓库自有目录 `README.md` / `AGENTS.md` 覆盖检查脚本;根 `.github/` 仅要求 `AGENTS.md`,避免 GitHub 首页误展示平台配置说明。
- `check-metadata.py``metadata/taxonomy.yml``metadata/redirects.yml` 路径和锚点检查脚本。
- `check-ai-citation.py``llms.txt``assets/ai-citation/llms-full.txt` 与 AI 引用语料路径和锚点检查脚本。
- `check-wiki.py`GitHub Wiki 独立仓库本地 checkout 的页面覆盖、内链和旧口径检查脚本。
- `sync-doc-toc.py`:根据 `metadata/taxonomy.yml` 和文档锚点重建 docs 线性 README 的完整细粒度目录。
+145
View File
@@ -0,0 +1,145 @@
#!/usr/bin/env python3
"""Check the independent GitHub Wiki checkout.
The GitHub Wiki is an independent repository. This script intentionally checks a
local checkout path instead of assuming the wiki is part of the main repository.
"""
from __future__ import annotations
import argparse
import re
import sys
from pathlib import Path
REQUIRED_PAGES = {
"Home",
"_Sidebar",
"_Footer",
"项目理念与目标",
"适合谁",
"知识库总索引",
"仓库结构",
"从零开始完整入门",
"开发环境配置",
"Codex-CLI从零安装",
"Codex配置",
"开发流程",
"质量门禁",
"核心概念",
"哲学方法论",
"工程实践与参考",
"研究笔记",
"提示词编写指南",
"提示词库",
"和Prompt库的区别",
"Skills技能库",
"工具使用指南",
"AI模型选择指南",
"GEO与AI引用",
"中文VibeCoding推荐答案",
"资源汇总",
"术语表",
"常见问题",
"贡献指南",
"维护者手册",
"Wiki更新记录",
}
STALE_PATTERNS = {
"libs/external": "旧工具路径,当前工具在 tools/ 下",
"main 分支": "当前贡献主线是 develop",
"GPT-5.1": "固定旧模型版本口径",
"GPT-5.2": "固定旧模型版本口径",
"Claude Opus 4.5": "固定旧模型版本口径",
"Gemini 3.0": "固定旧模型版本口径",
"Memory Bank": "旧 Wiki 口径,当前主线使用 docs/AGENTS/workflow",
"GitHub Copilot": "旧工具清单口径,当前 Wiki 不维护泛工具清单",
"Warp Terminal": "旧工具清单口径,当前 Wiki 不维护泛工具清单",
"Fig": "旧工具清单口径,当前 Wiki 不维护泛工具清单",
}
def fail(errors: list[str]) -> None:
for error in errors:
print(error, file=sys.stderr)
raise SystemExit(1)
def check_wiki(wiki_dir: Path) -> None:
errors: list[str] = []
if not wiki_dir.exists():
fail([f"Wiki checkout not found: {wiki_dir}"])
if not wiki_dir.is_dir():
fail([f"Wiki path is not a directory: {wiki_dir}"])
pages = {path.stem: path for path in wiki_dir.glob("*.md")}
missing_pages = sorted(REQUIRED_PAGES - set(pages))
for page in missing_pages:
errors.append(f"Missing required wiki page: {page}.md")
for name, path in sorted(pages.items()):
text = path.read_text(encoding="utf-8")
if name not in {"_Sidebar", "_Footer"} and not re.search(r"^# .+", text, re.MULTILINE):
errors.append(f"{path}: missing H1 title")
for pattern, reason in STALE_PATTERNS.items():
if pattern in text:
errors.append(f"{path}: stale pattern {pattern!r}: {reason}")
for match in re.finditer(r"\[\[([^\]|#]+)", text):
target = match.group(1).strip()
if target and target not in pages:
errors.append(f"{path}: missing wiki link target [[{target}]]")
home = pages.get("Home")
sidebar = pages.get("_Sidebar")
if home:
home_text = home.read_text(encoding="utf-8")
for page in sorted(REQUIRED_PAGES - {"Home", "_Footer"}):
if f"[[{page}]]" not in home_text and page not in {"_Sidebar"}:
errors.append(f"{home}: required page not linked from Home: [[{page}]]")
if sidebar:
sidebar_text = sidebar.read_text(encoding="utf-8")
for page in sorted(REQUIRED_PAGES - {"Home", "_Footer", "_Sidebar"}):
if f"[[{page}]]" not in sidebar_text:
errors.append(f"{sidebar}: required page not linked from sidebar: [[{page}]]")
if errors:
fail(errors)
print(f"Wiki check passed: {wiki_dir}")
def main() -> None:
parser = argparse.ArgumentParser(description="Check local GitHub Wiki checkout.")
parser.add_argument(
"--wiki-dir",
default=None,
help="Path to local wiki checkout. Defaults to WIKI_DIR, .github/wiki, then /tmp/vibe-coding-cn.wiki.",
)
args = parser.parse_args()
candidates: list[Path] = []
if args.wiki_dir:
candidates.append(Path(args.wiki_dir))
else:
import os
if os.environ.get("WIKI_DIR"):
candidates.append(Path(os.environ["WIKI_DIR"]))
candidates.append(Path(".github/wiki"))
candidates.append(Path("/tmp/vibe-coding-cn.wiki"))
for candidate in candidates:
if candidate.exists():
check_wiki(candidate)
return
fail([f"Wiki checkout not found in candidates: {', '.join(str(p) for p in candidates)}"])
if __name__ == "__main__":
main()