app
KiCad - the KiCad Bridge
Public Made by Adomby adom
Reference implementation of the KiCad bridge: multi-instance Python server, forward path via kicad-cli, reverse path via in-process plugin. Most complex of the three bundled bridges.
← Commit history
0.9.275: kicad_adom_library_heal (wiki #71 follow-up, John's call: merge): reconcile a split Adom library by merging every symbol from the orphaned bridge-default file into the registered file KiCad reads, one quote-aware add behind the balance gate with a .bak; dryRun previews; repoint mode kept as the other answer. Never runs on its own. Idempotent, refuses an unbalanced source, never edits or deletes the orphan.
3 files changed
+65−2
BRIDGE_VERSION+1−1@@ -1 +1 @@-0.9.274+0.9.275
adom_library.py+63@@ -422,3 +422,66 @@ def add_symbol(kicad_info: dict, symbol_text: str) -> dict: "added": added_names, "lib_path": str(lib_path), }+++def heal_split(kicad_info: dict, mode: str = "merge", dry_run: bool = False) -> dict:+ """Reconcile a split Adom library (wiki #71). John's call, 2026-09-03: MERGE.++ merge: copy every top-level symbol that exists in the orphaned (bridge+ default) file but not in the registered file INTO the registered+ file, one quote-aware add_symbol at a time, each behind the+ refuse-to-write balance gate with a .bak. The registered file stays+ the one KiCad reads; nothing is deleted; the orphan is left as-is.+ repoint: rewrite the sym-lib-table row's uri to the orphan. Not chosen; kept+ so the other answer is one argument away and not a code change.++ Never runs on its own: the bridge cannot know which of two libraries is the+ user's real one. This exists because a human said which."""+ rep = library_split_report(kicad_info)+ if not rep.get("split"):+ return {"success": True, "healed": False, "reason": "no split", **rep}+ registered = Path(rep["registeredPath"])+ orphan = Path(rep["bridgeDefaultPath"])+ if mode == "repoint":+ paths = _get_paths(kicad_info)+ table_path = paths[0]+ table = LibTable.parse_file(str(table_path))+ row = next((e for e in table.entries if e.name == ADOM_LIB_NAME), None)+ if row is None:+ return {"success": False, "error": "no Adom row to repoint"}+ if not dry_run:+ row.uri = str(orphan).replace("\\", "/")+ table.write_file(str(table_path))+ return {"success": True, "healed": not dry_run, "mode": "repoint", "dryRun": dry_run,+ "rowNowPointsAt": str(orphan).replace("\\", "/"),+ "_hint": "KiCad reads the repointed file after its next library load (restart)."}+ if mode != "merge":+ return {"success": False, "error": f"unknown mode {mode!r}", "allowed": ["merge", "repoint"]}+ try:+ orphan_text = orphan.read_text(encoding="utf-8")+ _parse_library_nodes(orphan_text) # balance gate on the SOURCE too+ except Exception as e: # pylint: disable=broad-except+ return {"success": False, "error": f"orphan library does not parse cleanly, refusing to merge from it: {e}"}+ have = {n.lower() for n in list_symbols(registered)}+ to_add = [(name, text) for name, text in _extract_top_level_symbols(orphan_text)+ if name.lower() not in have]+ skipped = [name for name, _ in _extract_top_level_symbols(orphan_text) if name.lower() in have]+ if dry_run:+ return {"success": True, "healed": False, "mode": "merge", "dryRun": True,+ "wouldAdd": [n for n, _ in to_add], "alreadyPresent": skipped,+ "registeredPath": str(registered), "orphanPath": str(orphan)}+ added, failed = [], []+ for name, text in to_add:+ # add_symbol takes a WHOLE .kicad_sym file (it re-parses it with the+ # quote-aware walker), so wrap the single top-level block in a minimal+ # library. Row-first _get_paths means it lands in the registered file.+ wrapped = "(kicad_symbol_lib (version 20231120) (generator \"adom-heal\")\n" + text + "\n)\n"+ r = add_symbol(kicad_info, wrapped)+ (added if r.get("success") else failed).append(name if r.get("success") else {"symbol": name, "error": r.get("error")})+ after = library_split_report(kicad_info)+ return {"success": not failed, "healed": True, "mode": "merge", "dryRun": False,+ "added": added, "alreadyPresent": skipped, "failed": failed,+ "registeredSymbolsAfter": after.get("registeredSymbols"),+ "_hint": ("Merged into the file KiCad reads. A running KiCad sees them after its next "+ "library load (kicad_rescan_libraries force:true, or restart). The orphan file "+ "was not modified or deleted.")}
bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "kicad", "displayName": "KiCad EDA",- "version": "0.9.274",+ "version": "0.9.275", "description": "Reverse bridge for KiCad \u2014 board/schematic introspection, lint via kicad-cli, plugin install, multi-instance probe, in-process DRC.", "homepage": "https://wiki.adom.inc/adom/adom-bridge", "author": "Adom Inc.",