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
v0.9.173: a click is a GOAL - the footprint/3D-chip surfaces now bind the plugin themselves (open a board in the background, since 10.0.5 only scans its plugin dir when a board editor comes up) instead of reporting 'no plugin' at the user
5 files changed
+56−7
BRIDGE_VERSION+1−1@@ -1 +1 @@-0.9.172+0.9.173
adom-bridge-kicad-manifest.json+5−5@@ -1,15 +1,15 @@ { "manifest_version": 1, "name": "kicad",- "version": "0.9.172",- "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.172/adom-bridge-kicad-v0.9.172.zip",- "sha256": "7674966eb1ef6ee04671a1cf9f8f277ea0a25b6edb7c311e27d040131b690afb",- "size": 446638,+ "version": "0.9.173",+ "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.173/adom-bridge-kicad-v0.9.173.zip",+ "sha256": "e91db7bcd39cc72cd1ee6cc6790d6dbab1c40ba4c56858600018ea3d32e70b3a",+ "size": 447228, "verbPrefixes": [ "kicad_" ], "healthEndpoint": "/status",- "released_at": "2026-08-19T08:46:04Z",+ "released_at": "2026-08-19T08:48:03Z", "hero": "https://wiki.adom.inc/blob/app/kicad-bridge/kicad-hero.png", "languages": [ "Python",
adom-bridge-kicad-v0.9.173.zipadded⋯ 1 unchanged line ⋯
bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "kicad", "displayName": "KiCad EDA",- "version": "0.9.172",+ "version": "0.9.173", "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.",
handlers/show.py+49@@ -23,6 +23,7 @@ symbolName/footprintName (+ optional libraryName), or filePath for the docs. from handlers.launch import handle_launch from handlers.open_files import handle_open_board, handle_open_schematic from handlers.open_symbol_editor import handle_open_symbol_editor+import sys import time from handlers.open_footprint_editor import (handle_open_footprint_editor, handle_open_3d_viewer, _find_pcb_editor, _find_footprint_editor)@@ -93,9 +94,56 @@ def _verify_window(result: dict, finder, label: str, waits: int = 12) -> dict: "LED: the background path needs the reverse-bridge plugin bound.")} +def _plugin_alive() -> bool:+ try:+ from handlers.bridge_client import _files_for_exe, _resolve_plugin+ for exe in ("pcbnew", "kicad"):+ meta, err = _resolve_plugin(exe)+ if meta and not err:+ return True+ except Exception:+ pass+ return False+++def ensure_plugin_ready(kicad_info: dict, waits: int = 14) -> bool:+ """A click is a GOAL, not an audit (the Adom automation doctrine).++ The background footprint path needs the reverse-bridge plugin, and on KiCad+ 10.0.5 the plugin only loads when KiCad SCANS its plugin directory - which+ happens when a board editor comes up, not when the project manager alone is+ running. So rather than telling the user "no plugin, open a board yourself"+ (0.9.172 did exactly that, correctly but uselessly), open one ourselves, in+ the background, and wait for the bind."""+ if _plugin_alive():+ return True+ from pathlib import Path as _P+ import os as _os+ board = None+ docs = _P(_os.environ.get("USERPROFILE") or _P.home()) / "Documents"+ for cand in sorted(docs.glob("adom-*/*.kicad_pcb")) + sorted(docs.glob("*/*.kicad_pcb")):+ board = str(cand)+ break+ if not board:+ return False+ print(f"[show] no plugin bound - opening {board} in the background to bind it",+ file=sys.stderr, flush=True)+ try:+ handle_open_board(kicad_info, {"filePath": board,+ "reason": "bind the reverse-bridge plugin"})+ except Exception:+ return False+ for _ in range(waits):+ time.sleep(3)+ if _plugin_alive():+ return True+ return False++ def handle_show_footprint(kicad_info: dict, args: dict) -> dict: """Show a FOOTPRINT in the Footprint Editor. Args: footprintName (+ library), or library alone to browse."""+ ensure_plugin_ready(kicad_info) r = handle_open_footprint_editor(kicad_info, args or {}) r = _verify_window(r, _find_footprint_editor, "Footprint Editor") r.setdefault("surface", "footprint")@@ -107,6 +155,7 @@ def handle_show_3d_chip(kicad_info: dict, args: dict) -> dict: analogue). Loads the footprint first if footprintName is given, then its 3D viewer.""" a = dict(args or {}) if a.get("footprintName") or a.get("footprint") or a.get("library"):+ ensure_plugin_ready(kicad_info) loaded = handle_open_footprint_editor(kicad_info, a) if not loaded.get("success") and not loaded.get("editorOpened"): loaded["surface"] = "3d_chip"