check_doc_source_of_truth.py
1 #!/usr/bin/env python3 2 from __future__ import annotations 3 4 from pathlib import Path 5 import re 6 import sys 7 8 ROOT = Path(__file__).resolve().parents[2] 9 FILES = [ 10 ROOT / 'README.md', 11 ROOT / 'USAGE.md', 12 ROOT / 'PARITY.md', 13 ROOT / 'PHILOSOPHY.md', 14 ROOT / 'ROADMAP.md', 15 ROOT / '.github' / 'FUNDING.yml', 16 ] 17 FILES.extend(sorted((ROOT / 'docs').rglob('*.md')) if (ROOT / 'docs').exists() else []) 18 19 FORBIDDEN = { 20 r'github\.com/Yeachan-Heo/claw-code(?!-parity)': 'replace old claw-code GitHub links with ultraworkers/claw-code', 21 r'github\.com/code-yeongyu/claw-code': 'replace stale alternate claw-code GitHub links with ultraworkers/claw-code', 22 r'discord\.gg/6ztZB9jvWq': 'replace the stale UltraWorkers Discord invite with the current invite', 23 r'api\.star-history\.com/svg\?repos=Yeachan-Heo/claw-code': 'update star-history embeds to ultraworkers/claw-code', 24 r'star-history\.com/#Yeachan-Heo/claw-code': 'update star-history links to ultraworkers/claw-code', 25 r'assets/clawd-hero\.jpeg': 'rename stale hero asset references to assets/claw-hero.jpeg', 26 r'assets/instructkr\.png': 'remove stale instructkr image references', 27 } 28 29 errors: list[str] = [] 30 for path in FILES: 31 if not path.exists(): 32 continue 33 text = path.read_text(encoding='utf-8') 34 for pattern, message in FORBIDDEN.items(): 35 for match in re.finditer(pattern, text): 36 line = text.count('\n', 0, match.start()) + 1 37 errors.append(f'{path.relative_to(ROOT)}:{line}: {message}') 38 39 if errors: 40 print('doc source-of-truth check failed:', file=sys.stderr) 41 for error in errors: 42 print(f' - {error}', file=sys.stderr) 43 sys.exit(1) 44 45 print('doc source-of-truth check passed')