init: llm-wiki-haness 하네스 설계
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Atomically convert checker-confirmed bare branch decision/owner refs to wikilinks."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import importlib.util
|
||||
import json
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
from fs_transaction import replace_many
|
||||
|
||||
|
||||
DEFAULT_ROOT = Path(__file__).resolve().parents[2]
|
||||
|
||||
|
||||
def _load_checker(root: Path):
|
||||
path = root / ".claude/hooks/wiki_consistency_check.py"
|
||||
hooks = str(path.parent)
|
||||
if hooks not in sys.path:
|
||||
sys.path.insert(0, hooks)
|
||||
spec = importlib.util.spec_from_file_location("wiki_consistency_fix_source", path)
|
||||
if spec is None or spec.loader is None:
|
||||
raise OSError(f"cannot load checker: {path}")
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
def _replace_slug(line: str, slug: str, branch_dir: str) -> tuple[str, bool]:
|
||||
pattern = re.compile(
|
||||
rf"(?<![\/\w-])`?{re.escape(slug)}`?(?![\w-])"
|
||||
)
|
||||
rendered, count = pattern.subn(f"[[{branch_dir}/{slug}]]", line, count=1)
|
||||
return rendered, bool(count)
|
||||
|
||||
|
||||
def build_updates(root: Path) -> tuple[dict[Path, str], dict[str, Any]]:
|
||||
checker = _load_checker(root)
|
||||
updates: dict[Path, str] = {}
|
||||
decision_fixes = 0
|
||||
owner_fixes = 0
|
||||
for branch_path in sorted((root / checker.BRANCH_DIR).glob("*.md")):
|
||||
text = branch_path.read_text(encoding="utf-8")
|
||||
lines = text.splitlines(keepends=True)
|
||||
for line_number, slug, _ref_id, kind in checker.extract_refs(text, branch_path.stem):
|
||||
if kind != "bare":
|
||||
continue
|
||||
original = lines[line_number - 1]
|
||||
lines[line_number - 1], changed = _replace_slug(original, slug, checker.BRANCH_DIR)
|
||||
if changed:
|
||||
decision_fixes += 1
|
||||
current = "".join(lines)
|
||||
coverage = checker.coverage_rows(current)
|
||||
for line_number, _concern, status, owner in coverage:
|
||||
if "delegated" not in status or not owner:
|
||||
continue
|
||||
slugs = [match.group(1) for match in checker.BARE_SLUG_RE.finditer(owner)]
|
||||
for slug in slugs:
|
||||
original = lines[line_number - 1]
|
||||
lines[line_number - 1], changed = _replace_slug(original, slug, checker.BRANCH_DIR)
|
||||
if changed:
|
||||
owner_fixes += 1
|
||||
rendered = "".join(lines)
|
||||
if rendered != text:
|
||||
updates[branch_path] = rendered
|
||||
return updates, {
|
||||
"decision_ref_fixes": decision_fixes,
|
||||
"owner_ref_fixes": owner_fixes,
|
||||
"changed_files": [path.relative_to(root).as_posix() for path in sorted(updates)],
|
||||
}
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
mode = parser.add_mutually_exclusive_group(required=True)
|
||||
mode.add_argument("--check", action="store_true")
|
||||
mode.add_argument("--write", action="store_true")
|
||||
parser.add_argument("--root", type=Path, default=DEFAULT_ROOT)
|
||||
args = parser.parse_args(argv)
|
||||
try:
|
||||
root = args.root.resolve(strict=True)
|
||||
updates, counts = build_updates(root)
|
||||
if args.write and updates:
|
||||
replace_many({path: text.encode("utf-8") for path, text in updates.items()})
|
||||
result = {
|
||||
"schema_version": "bare-ref-migration-result/v1",
|
||||
"status": "DRIFT" if args.check and updates else "UPDATED" if updates else "CURRENT",
|
||||
**counts,
|
||||
}
|
||||
json.dump(result, sys.stdout, ensure_ascii=False, indent=2, sort_keys=True)
|
||||
sys.stdout.write("\n")
|
||||
return 1 if args.check and updates else 0
|
||||
except (OSError, UnicodeError, ValueError) as exc:
|
||||
json.dump({"schema_version": "bare-ref-migration-result/v1", "status": "FAIL", "error": str(exc)}, sys.stdout, ensure_ascii=False, indent=2)
|
||||
sys.stdout.write("\n")
|
||||
return 2
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user