#!/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()