feat(migration): 建立 Skill 迁移工作流与追踪工具

This commit is contained in:
zhiye.sun
2026-08-25 10:46:09 +08:00
parent 795c331706
commit 0e7eb1eb93
10 changed files with 1063 additions and 3 deletions
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env python3
"""根据扫描报告更新迁移台账;默认预览,显式 --apply 才写入。"""
from __future__ import annotations
import argparse
import hashlib
import json
from datetime import date
from pathlib import Path
VALID_STATUS = {
"pending", "specified", "rewriting", "review",
"migrated", "excluded", "superseded",
}
def merge(lock: dict, report: dict) -> dict:
"""保留人工维护字段,仅同步来源提交、数量和 Skill 指纹。"""
lock.setdefault("schemaVersion", 1)
lock["updatedAt"] = date.today().isoformat()
lock.setdefault("sources", {})
lock.setdefault("skills", {})
for source in report.get("sources", []):
source_id = source["id"]
lock["sources"][source_id] = {
"commit": source.get("commit"),
"skillCount": source["skillCount"],
}
for skill in source["skills"]:
# 发布台账不保存来源名称和路径;本地扫描报告负责提供可读映射。
path_hash = hashlib.sha256(skill["relativePath"].encode("utf-8")).hexdigest()
key = f"{source_id}:{path_hash[:16]}"
current = lock["skills"].get(key, {})
status = current.get("status", "pending")
if status not in VALID_STATUS:
raise ValueError(f"非法迁移状态:{key}={status}")
lock["skills"][key] = {
**current,
"sourcePathHash": path_hash,
"sourceSha256": skill["sha256"],
"status": status,
}
return lock
def main() -> None:
parser = argparse.ArgumentParser(description="更新 Skill 迁移台账")
parser.add_argument("--lock", required=True, type=Path)
parser.add_argument("--report", required=True, type=Path)
parser.add_argument("--apply", action="store_true", help="确认写入台账")
args = parser.parse_args()
lock = json.loads(args.lock.read_text(encoding="utf-8"))
report = json.loads(args.report.read_text(encoding="utf-8"))
content = json.dumps(merge(lock, report), ensure_ascii=False, indent=2) + "\n"
if args.apply:
temporary = args.lock.with_suffix(args.lock.suffix + ".tmp")
temporary.write_text(content, encoding="utf-8")
temporary.replace(args.lock)
else:
print(content, end="")
if __name__ == "__main__":
main()