Files
Nexus/scripts/consolidate_docs.py
2026-07-08 22:31:31 +08:00

274 lines
8.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""Consolidate Nexus docs: move batches to docs/archive/ and generate merged volumes."""
from __future__ import annotations
import shutil
from datetime import date
from pathlib import Path
REPO = Path(__file__).resolve().parents[1]
DOCS = REPO / "docs"
ARCHIVE = DOCS / "archive"
TODAY = date.today().isoformat()
def ensure_dirs() -> None:
for sub in (
"audits/2026-06-04-line-walk",
"audits/2026-06-04-delta",
"audits/2026-06-04-phase2",
"audits/2026-06-04-frontend-14p",
"memory/raw",
"handoff",
"project",
"reports/2026-05-reviews",
"reports/2026-05-steps",
):
(ARCHIVE / sub).mkdir(parents=True, exist_ok=True)
def extract_summary(text: str, max_lines: int = 12) -> str:
lines: list[str] = []
for line in text.splitlines():
s = line.strip()
if not s:
continue
if s.startswith("#"):
lines.append(s)
elif any(k in s for k in ("Closure", "DoD", "P0", "P1", "FINDING", "结论", "摘要")):
lines.append(s[:200])
if len(lines) >= max_lines:
break
return "\n".join(lines) if lines else (text.splitlines()[0][:200] if text.splitlines() else "(empty)")
def extract_closure_rows(text: str) -> list[str]:
rows: list[str] = []
in_table = False
for line in text.splitlines():
if "|" in line and ("Closure" in line or "H " in line or "FINDING" in line):
in_table = True
if in_table and line.strip().startswith("|") and "---" not in line:
rows.append(line.strip())
if in_table and not line.strip() and rows:
break
return rows[:80]
def merge_glob(
pattern: str,
out_name: str,
title: str,
archive_subdir: str,
) -> None:
base = DOCS / "reports"
files = sorted(base.glob(pattern))
if not files:
print(f" skip merge (no files): {pattern}")
return
out_path = ARCHIVE / "audits" / out_name
parts = [
f"# {title}",
"",
f"> 生成日期: {TODAY} · 源文件 {len(files)} 篇 · 原文 `docs/archive/{archive_subdir}/`",
"",
"## 批次索引",
"",
]
archive_dir = ARCHIVE / archive_subdir
archive_dir.mkdir(parents=True, exist_ok=True)
all_closure: list[str] = []
for f in files:
dest = archive_dir / f.name
if f.resolve() != dest.resolve():
if dest.exists():
dest.unlink()
shutil.move(str(f), str(dest))
text = dest.read_text(encoding="utf-8", errors="replace")
parts.append(f"### `{f.name}`")
parts.append("")
parts.append(extract_summary(text))
parts.append("")
all_closure.extend(extract_closure_rows(text))
if all_closure:
parts.extend(["## Closure 摘录(合并)", ""])
seen: set[str] = set()
for row in all_closure:
if row not in seen:
seen.add(row)
parts.append(row)
parts.append("")
out_path.write_text("\n".join(parts), encoding="utf-8")
print(f" merged {len(files)}{out_path.relative_to(REPO)}")
def merge_memory() -> None:
mem_dir = DOCS / "memory"
if not mem_dir.is_dir():
return
files = sorted(p for p in mem_dir.glob("*.md") if p.name != "MEMORY.md")
if not files:
return
raw_dir = ARCHIVE / "memory/raw"
raw_dir.mkdir(parents=True, exist_ok=True)
parts = [
"# Agent Memory 合并卷(2026-05 迁移)",
"",
f"> 生成: {TODAY} · 原 docs/memory/ {len(files)} 篇",
"",
"请以 [nexus-functional-development-guide.md](../project/nexus-functional-development-guide.md) 为准。",
"",
]
for f in files:
text = f.read_text(encoding="utf-8", errors="replace")
dest = raw_dir / f.name
if f.resolve() != dest.resolve():
shutil.move(str(f), str(dest))
parts.extend([f"## {f.stem}", "", extract_summary(text, 8), ""])
out = ARCHIVE / "memory/agentmemory-2026-05-merged.md"
out.write_text("\n".join(parts), encoding="utf-8")
(mem_dir / "MEMORY.md").write_text(
"# 项目记忆(已归档)\n\n"
"见 [agentmemory-2026-05-merged.md](../archive/memory/agentmemory-2026-05-merged.md)\n"
"与 [功能开发指南](../project/nexus-functional-development-guide.md)。\n",
encoding="utf-8",
)
print(f" memory merged → {out.relative_to(REPO)}")
def archive_handoffs() -> None:
for name in ("handoff-2026-05-31.md", "handoff-2026-06-01.md"):
src = DOCS / name
if src.is_file():
shutil.move(str(src), str(ARCHIVE / "handoff" / name))
for f in sorted((DOCS / "project").glob("AI-HANDOFF-2026-05*.md")):
shutil.move(str(f), str(ARCHIVE / "handoff" / f.name))
old = DOCS / "project" / "AI-HANDOFF-2026-06-01-files.md"
if old.is_file():
shutil.move(str(old), str(ARCHIVE / "handoff" / old.name))
print(" handoffs archived")
def archive_nexus_full_site_features() -> None:
src = DOCS / "project" / "nexus-full-site-features.md"
if not src.is_file():
return
shutil.move(str(src), str(ARCHIVE / "project" / src.name))
(DOCS / "project" / "nexus-full-site-features.md").write_text(
"# 全站功能清单(已 supersede\n\n"
"请以 **[nexus-functional-development-guide.md](nexus-functional-development-guide.md)** 为准。\n\n"
"历史 HTML 版: [archive](../archive/project/nexus-full-site-features.md)\n",
encoding="utf-8",
)
print(" nexus-full-site-features → archive + stub")
def archive_old_line_walk_standard() -> None:
v1 = DOCS / "project" / "line-walk-audit-standard.md"
if v1.is_file():
shutil.move(str(v1), str(ARCHIVE / "project" / v1.name))
print(" line-walk v1 archived")
def archive_phase2_reviews() -> None:
dest = ARCHIVE / "reports/2026-05-reviews"
patterns = (
"review-*-2026-05-21.md",
"signoff-2026-05-21.md",
"session-log-2026-05-21.md",
"2026-05-23-full-audit-report.md",
"audit-full-vs-phase2-reconciliation.md",
"audit-phase-2*.md",
"audit-phase-3*.md",
"implementation-progress-2026-05-21.md",
)
n = 0
reports = DOCS / "reports"
for pat in patterns:
for g in reports.glob(pat):
if g.is_file():
t = dest / g.name
if t.exists():
t.unlink()
shutil.move(str(g), str(t))
n += 1
step_dir = ARCHIVE / "reports/2026-05-steps"
for f in reports.glob("step-*"):
if f.is_dir():
target = step_dir / f.name
if target.exists():
shutil.rmtree(target)
shutil.move(str(f), str(target))
n += 1
if n:
print(f" archived {n} legacy review/step items")
def write_archive_readme() -> None:
(ARCHIVE / "README.md").write_text(
f"""# Nexus 文档归档区
> 更新: {TODAY}
历史审计、旧 handoff、agentmemory。**日常请先读** [docs/README.md](../README.md)。
## 合并卷
| 文件 | 内容 |
|------|------|
| [audits/2026-06-04-line-walk-merged.md](audits/2026-06-04-line-walk-merged.md) | Line-walk batch |
| [audits/2026-06-04-delta-merged.md](audits/2026-06-04-delta-merged.md) | Delta D1D8 |
| [audits/2026-06-04-phase2-merged.md](audits/2026-06-04-phase2-merged.md) | Phase2 P2 |
| [audits/2026-06-04-frontend-14p-merged.md](audits/2026-06-04-frontend-14p-merged.md) | 前端 14p |
| [memory/agentmemory-2026-05-merged.md](memory/agentmemory-2026-05-merged.md) | 旧 memory |
原文在对应子目录;changelog 不归档。
""",
encoding="utf-8",
)
def main() -> None:
print("=== Nexus docs consolidation ===")
ensure_dirs()
merge_glob(
"audit-bug-line-walk-2026-06-04-batch*.md",
"2026-06-04-line-walk-merged.md",
"Bug Scan Line-Walk 合并卷",
"audits/2026-06-04-line-walk",
)
merge_glob(
"audit-delta-2026-06-04-waveD*.md",
"2026-06-04-delta-merged.md",
"Delta D1D8 合并卷",
"audits/2026-06-04-delta",
)
merge_glob(
"audit-phase2-2026-06-04-waveP2-*.md",
"2026-06-04-phase2-merged.md",
"Phase2 P2 合并卷",
"audits/2026-06-04-phase2",
)
merge_glob(
"audit-frontend-14p-2026-06-04-batch*.md",
"2026-06-04-frontend-14p-merged.md",
"前端 14p batch 合并卷",
"audits/2026-06-04-frontend-14p",
)
merge_memory()
archive_handoffs()
archive_nexus_full_site_features()
archive_old_line_walk_standard()
archive_phase2_reviews()
write_archive_readme()
print("=== done ===")
if __name__ == "__main__":
main()