Files
llm_wiki/tools/scripts/promote-knowledge.py
hehaiguang1123 a6f05ab2d5 Phase 0-2: Schema cleanup, typed relations, event-driven automation
- Phase 0: AGENTS.md cleanup (dedup quotes, renumber sections, merge qmd)
- Phase 1: typed relations (manage-relations.py, graph-search.py, check-staleness.py, detect-conflicts.py)
- Phase 2: frontmatter validator, weekly lint, knowledge promotion, git hooks
- Fix .gitignore to track tools/ and .githooks/
- Fix git remote URL (remove plaintext token)
- New wiki pages: 504 pages, 34 raw sources
2026-07-01 08:05:43 +08:00

142 lines
4.2 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 python
# -*- coding: utf-8 -*-
"""
promote-knowledge.py — Consolidation tiers: 检查 wiki/working/ 中的页面
是否可以提升到 wiki/semantic/(即主 wiki 目录)。
条件:
- 有完整的 frontmattercategories, tags, type, source
- 正文 > 100 字
- 创建时间 > 7 天(通过 created 字段判断)
用法:
python tools/scripts/promote-knowledge.py # 检查可提升页面
python tools/scripts/promote-knowledge.py --apply # 执行提升
python tools/scripts/promote-knowledge.py --dry-run # 预览
"""
import argparse
import re
import shutil
import sys
from datetime import date, timedelta
from pathlib import Path
try:
import yaml
except ImportError:
yaml = None
WIKI = Path(r"D:\Applications\app\kepano-obsidian-main\wiki")
WORKING = WIKI / "working"
SEMANTIC = WIKI # semantic 层就是当前 wiki/
ARCHIVE = WIKI / "archive"
PROCEDURAL = WIKI / "procedural"
def ensure_dirs():
"""确保层目录存在"""
for d in [WORKING, ARCHIVE, PROCEDURAL]:
d.mkdir(exist_ok=True)
def check_promotable(fp: Path) -> tuple[bool, list[str]]:
"""检查文件是否可提升"""
content = fp.read_text(encoding="utf-8")
m = re.match(r"^---\n(.*?)\n---", content, re.DOTALL)
if not m:
return False, ["No frontmatter"]
if not yaml:
return False, ["PyYAML not installed"]
try:
front = yaml.safe_load(m.group(1)) or {}
except:
return False, ["YAML parse error"]
body = content[m.end():].strip()
reasons = []
if not front.get("categories"):
reasons.append("Missing categories")
tags = front.get("tags", [])
if isinstance(tags, str): tags = [tags]
if "wiki" not in tags:
reasons.append("Missing 'wiki' in tags")
if not front.get("type"):
reasons.append("Missing type")
if not front.get("source"):
reasons.append("Missing source")
if len(body) < 100:
reasons.append(f"Body too short ({len(body)} chars, need 100+)")
created = front.get("created")
if created:
try:
cdate = date.fromisoformat(str(created))
if (date.today() - cdate).days < 7:
reasons.append(f"Created < 7 days ago ({created})")
except:
pass # ignore invalid dates
return len(reasons) == 0, reasons
def main():
parser = argparse.ArgumentParser(description="Knowledge consolidation tiers")
parser.add_argument("--apply", action="store_true", help="Execute promotion")
parser.add_argument("--dry-run", action="store_true", help="Preview only")
args = parser.parse_args()
ensure_dirs()
if not WORKING.exists():
print("No working/ directory found. Nothing to promote.")
return
working_files = sorted(WORKING.glob("*.md"))
if not working_files:
print("No files in working/")
return
promotable = []
not_ready = []
for fp in working_files:
ready, reasons = check_promotable(fp)
if ready:
promotable.append(fp)
else:
not_ready.append((fp, reasons))
print(f"=== Knowledge Promotion Check ===")
print(f" Working files: {len(working_files)}")
print(f" Promotable: {len(promotable)}")
print(f" Not ready: {len(not_ready)}")
if promotable:
print(f"\n Promotable to semantic/:")
for fp in promotable:
dest = SEMANTIC / fp.name
if dest.exists():
print(f" [[{fp.stem}]] → WARNING: target exists")
else:
print(f" [[{fp.stem}]]")
if args.apply and not args.dry_run:
for fp in promotable:
dest = SEMANTIC / fp.name
if not dest.exists():
shutil.move(str(fp), str(dest))
print(f" Moved: working/{fp.name}{fp.name}")
print(f"\n Promoted: {len(promotable)}")
elif args.dry_run:
print(f"\n (--dry-run: no files moved)")
if not_ready:
print(f"\n Not ready for promotion:")
for fp, reasons in not_ready:
for r in reasons:
print(f" [[{fp.stem}]] — {r}")
if __name__ == "__main__":
main()