# -*- coding: utf-8 -*- u"""把 `.claude/` 下所有脚本指向的**载板 PCB 文档 uuid** 一次性换掉。 /c/Python314/python .claude/pcb2_retarget.py # 只看哪些文件会被改 /c/Python314/python .claude/pcb2_retarget.py <新uuid> --write # 真的改 ## 为什么需要它 2026-09-07 的事故里 `PCB2-CARRIER`(`f126ffb2…`)这个**文档本身坏了**: 写得进去、同一次会话里读回来也对,但重开之后电气对象一律读回 0、渲染 API 挂死, 而且上一轮删掉并存过盘的图形重开后**又回来且翻倍**(1546 → 3091)—— 说明对它的写入根本没有真正落盘。判据是**换一块板对照**: 同一次会话里 PCB1 读回 301 件 / 2951 线 / 944 孔完全正常。 ⇒ 修不了,只能换一个干净的 PCB 文档重建。而载板的 uuid 硬编码在 20 多个脚本里, 手工改必漏,所以做成这个工具。 ## 换完之后的重建流程(每一步都回查,顺序不能乱) 1. pcb2_place.py --layers 切 4 层(新建的 PCB 默认 2 层) 2. pcb2_rules.py 设计规则 + 11 对差分 + 网络指派 3. pcb1_import.py --board2 --probe / --apply 216 个元件全部「增加元件」 4. pcb2_place.py --push 摆位 5. pcb2_place.py --outline 板框 + 10 个穿线槽 + 8 个 M3 孔 6. pcb2_place.py --mech 30 个手机定位孔 + 5 个手机位丝印 7. pcb2_restore.py --copper --push 2039 段铜 + 896 个过孔(快照 + cfgsel 账本) 8. pcb2_pour.py --push 7 块铺铜 9. 对账:焊盘 1000 个逐个比、铜层逐条比、inner1_verify.py、drc_read.py --pcb2 ⚠️ `pcb2_reload.py` 可以用,但有前提:**先存盘并回读验证,重载后必须过 `assert_alive()`**。 (2026-09-08 更正:把载板打进「Load Empty」的是**那个已损坏的文档**,不是 `location.reload()`; 在健康文档上重载完全正常,而且是清掉卡死后台任务、让铺铜能重建的唯一办法。) """ import io import os import re import sys HERE = os.path.dirname(os.path.abspath(__file__)) OLD = '942ed1560d81c1e7' # 只改脚本和缓存里的引用;`_*.json` 那些是数据快照,不含 uuid 也不该动。 SKIP_DIRS = {'obsolete', 'eda_src', 'skills', '__pycache__'} def targets(): out = [] for root, dirs, files in os.walk(HERE): dirs[:] = [d for d in dirs if d not in SKIP_DIRS] for fn in files: if not (fn.endswith('.py') or fn.endswith('.json')): continue p = os.path.join(root, fn) try: s = io.open(p, encoding='utf-8').read() except Exception: continue n = s.count(OLD) if n: out.append((p, n)) return sorted(out) def main(): args = [a for a in sys.argv[1:] if not a.startswith('--')] write = '--write' in sys.argv tg = targets() total = sum(n for _p, n in tg) print(u'旧 uuid %s 出现在 %d 个文件、共 %d 处:' % (OLD, len(tg), total)) for p, n in tg: print(u' %-52s ×%d' % (os.path.relpath(p, HERE), n)) if not args: print(u'\n用法: pcb2_retarget.py <新uuid> --write') return new = args[0] if not re.match(r'^[0-9a-f]{16}$', new): sys.exit(u'⛔ uuid 看着不对(应为 16 位十六进制):%r' % new) if new == OLD: sys.exit(u'⛔ 新旧 uuid 一样') if not write: print(u'\n将把它们全部换成 %s —— 加 --write 执行' % new) return changed = 0 for p, _n in tg: s = io.open(p, encoding='utf-8').read() io.open(p, 'w', encoding='utf-8').write(s.replace(OLD, new)) changed += 1 # 回查:旧 uuid 必须一处不剩 left = targets() if left: sys.exit(u'⛔ 还剩 %d 个文件有旧 uuid:%s' % (len(left), [os.path.basename(p) for p, _ in left])) print(u'\n✅ 已改 %d 个文件,旧 uuid 一处不剩;新目标 %s' % (changed, new)) print(u'⚠️ 本脚本自己的 OLD 常量也被换了 —— 下次再换目标时它就是新的起点,这是有意的。') main()