Co-authored-by: alvinfei <alvinfei@tencent.com> Co-authored-by: Cursor <cursoragent@cursor.com>
83 lines
2.8 KiB
Python
83 lines
2.8 KiB
Python
#!/usr/bin/env python3
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
REQUIRED_PATHS = (
|
|
"NOTICE",
|
|
"docs/ARCHITECTURE.md",
|
|
"docs/DEVELOPMENT_LOOP.md",
|
|
"apps/core/pyproject.toml",
|
|
"apps/cli/package.json",
|
|
"apps/web/package.json",
|
|
"apps/desktop/package.json",
|
|
"packages/contracts/package.json",
|
|
"scripts/audit_core_test_design.py",
|
|
"scripts/generate_core_test_index.py",
|
|
"scripts/summarize_core_test_report.py",
|
|
"pnpm-workspace.yaml",
|
|
"SECURITY.md",
|
|
"PRIVACY.md",
|
|
"CONTRIBUTING.md",
|
|
)
|
|
|
|
#: Paths that must stay gone, with the reason they were removed.
|
|
#:
|
|
#: A required-paths list cannot express "this was deleted on purpose", so a
|
|
#: deleted entry point reads as an oversight and comes back. `deploy/docker`
|
|
#: could not build for three independent reasons — pip does not read
|
|
#: `[tool.uv.sources]` so the private HY dependency never installed, the web
|
|
#: UI was never copied into the image, and the compose port bound loopback
|
|
#: only, so a remote deploy was unreachable even if it had built.
|
|
FORBIDDEN_PATHS = {
|
|
"deploy/docker": "无法构建的部署入口,2026-09-09 RL-31 移除;桌面壳走 pyinstaller + extraResources",
|
|
"AGENTS.md": "内部 Agent 协作说明不属于公开源码",
|
|
"HANDSOFF.md": "内部交接和验收状态不属于公开源码",
|
|
"docs/mvp/PREREQUISITES.md": "内部发布前置与审批跟踪不属于公开源码",
|
|
"docs/mvp/SCOPE.md": "历史开源规划快照不属于公开源码",
|
|
"docs/mvp/packaging-smoke-checklist.md": "内部实包验收记录不属于公开源码",
|
|
}
|
|
|
|
FORBIDDEN_ROOT_GLOBS = {
|
|
"_tmp_*": "临时文件不得进入仓库根目录",
|
|
}
|
|
|
|
|
|
def main() -> None:
|
|
root = Path(__file__).resolve().parents[1]
|
|
missing = [relative for relative in REQUIRED_PATHS if not (root / relative).exists()]
|
|
if missing:
|
|
for relative in missing:
|
|
print(f"missing: {relative}")
|
|
raise SystemExit(1)
|
|
|
|
returned = [
|
|
(relative, reason)
|
|
for relative, reason in FORBIDDEN_PATHS.items()
|
|
if (root / relative).exists()
|
|
]
|
|
if returned:
|
|
for relative, reason in returned:
|
|
print(f"should not exist: {relative} — {reason}")
|
|
raise SystemExit(1)
|
|
|
|
matched_globs = [
|
|
(path.relative_to(root), reason)
|
|
for pattern, reason in FORBIDDEN_ROOT_GLOBS.items()
|
|
for path in root.glob(pattern)
|
|
]
|
|
if matched_globs:
|
|
for relative, reason in matched_globs:
|
|
print(f"should not exist: {relative} — {reason}")
|
|
raise SystemExit(1)
|
|
|
|
print(
|
|
f"structure gate passed: {len(REQUIRED_PATHS)} required paths exist, "
|
|
f"{len(FORBIDDEN_PATHS)} removed paths stayed removed, "
|
|
f"{len(FORBIDDEN_ROOT_GLOBS)} forbidden root patterns stayed empty"
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|