Ctrl K
ComunidadGuías…

scripts/docs-update-plan-links.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env python3
"""Update docs/plans/ paths after subdirectory restructure."""
from __future__ import annotations

import re
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]

MOVES: dict[str, str] = {
    "roadmap-backlog-and-boundaries-2026-05.md": "decisions",
    "four-reports-out-of-scope-2026-05.md": "decisions",
    "five-reports-not-done-2026-05.md": "decisions",
    "four-reports-improvement-roadmap-2026-05.md": "roadmaps",
    "five-reports-improvement-roadmap-2026-05.md": "roadmaps",
    "external-agent-reports-improvement-roadmap-2026-05.md": "roadmaps",
    "post-consolidation-roadmap-2026-05.md": "active",
    "cc-butler-gap-analysis-2026-05.md": "active",
    "consolidation-2026-05.md": "archive",
    "consolidation-p3-implementation-2026-05.md": "archive",
    "memory-unification-implementation-2026-05.md": "archive",
    "health-report-refactor-2026-05.md": "archive",
    "wechat-steer-implementation-2026-05.md": "archive",
    "p3-deferred-deep-dive-2026-05.md": "archive",
    "reference-learning-plan-2026-05.md": "archive",
}

CORPUS_PREFIXES = ("corpus-", "dev-assistant-corpus-", "wechat-corpus-ops", "wechat-dev-conversation", "wechat-real-")


def subdir_for(name: str) -> str:
    if name in MOVES:
        return MOVES[name]
    if any(name.startswith(p) for p in CORPUS_PREFIXES):
        return "corpus"
    return "comparisons"


def repl_path(match: re.Match[str]) -> str:
    prefix, name = match.group(1), match.group(2)
    sub = subdir_for(name)
    return f"{prefix}plans/{sub}/{name}"


# docs/plans/foo.md or ](plans/foo.md — not already plans/sub/
PAT = re.compile(
    r"((?:\.\./)*docs/|\]\()(?:plans/)(?!(?:active|decisions|roadmaps|comparisons|corpus|archive)/)"
    r"([a-z0-9._-]+\.md)"
)


def fix_file(path: Path) -> bool:
    text = path.read_text(encoding="utf-8")
    new = PAT.sub(repl_path, text)
    if new != text:
        path.write_text(new, encoding="utf-8")
        return True
    return False


def fix_plans_subdir_relatives(path: Path) -> bool:
    subdirs = {"active", "decisions", "roadmaps", "comparisons", "corpus", "archive"}
    rel = path.relative_to(ROOT)
    if len(rel.parts) != 4 or rel.parts[0] != "docs" or rel.parts[1] != "plans":
        return False
    if rel.parts[2] not in subdirs:
        return False

    text = path.read_text(encoding="utf-8")
    new = text
    for d in ("architecture", "guides", "config", "ops", "design", "history", "reviews"):
        new = new.replace(f"](../{d}/", f"](../../{d}/")
        new = new.replace(f"](../{d}.md)", f"](../../{d}.md)")
    new = new.replace("](../DOCUMENTATION.md)", "](../../DOCUMENTATION.md)")
    for d in ("CONTRIBUTING.md", "tests/", "projects/", "scripts/", "STRUCTURE.md", "AGENTS.md"):
        new = new.replace(f"](../../{d}", f"](../../../{d}")
    new = new.replace("](../../README.md)", "](../../../README.md)")
    for name, sub in MOVES.items():
        new = re.sub(rf"\]\(({re.escape(name)})\)", rf"](../{sub}/\1)", new)
        new = re.sub(rf"\]\(({re.escape(name)}#)", rf"](../{sub}/\1#", new)
    if new != text:
        path.write_text(new, encoding="utf-8")
        return True
    return False


REL_PLANS = re.compile(r"\]\(\.\./plans/([a-z0-9._-]+\.md)")


def fix_relative_plans_links(path: Path) -> bool:
    text = path.read_text(encoding="utf-8")

    def sub_rel(m: re.Match[str]) -> str:
        name = m.group(1)
        return f"](../plans/{subdir_for(name)}/{name}"

    new = REL_PLANS.sub(sub_rel, text)
    new = re.sub(
        r"\]\(plans/([a-z0-9._-]+\.md)",
        lambda m: f"](plans/{subdir_for(m.group(1))}/{m.group(1)}",
        new,
    )
    if new != text:
        path.write_text(new, encoding="utf-8")
        return True
    return False


def main() -> None:
    changed = 0
    skip_dirs = {".git", "node_modules", "reference", "projects"}
    for ext in ("*.md", "*.mdc", "*.yml", "*.yaml", "*.sh"):
        for path in ROOT.rglob(ext):
            if any(p in skip_dirs for p in path.parts):
                continue
            c1 = fix_file(path)
            c2 = fix_plans_subdir_relatives(path)
            c3 = fix_relative_plans_links(path)
            if c1 or c2 or c3:
                changed += 1
                print(path.relative_to(ROOT))
    print(f"updated {changed} files")


if __name__ == "__main__":
    main()