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
Update 5 file(s)
5 files changed
+45−7
BRIDGE_VERSION+1−1@@ -1 +1 @@-0.9.196+0.9.197
adom-bridge-kicad-manifest.json+5−5@@ -1,15 +1,15 @@ { "manifest_version": 1, "name": "kicad",- "version": "0.9.196",- "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.196/adom-bridge-kicad-v0.9.196.zip",- "sha256": "cbc24354afed887b790049e44c1406b3ef311fcd83e60365941457ce372ca812",- "size": 466875,+ "version": "0.9.197",+ "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.197/adom-bridge-kicad-v0.9.197.zip",+ "sha256": "fc2b6091f00d477824d025f61cc072367fc8ea95ec396bc806ae2fb9dcbc79d5",+ "size": 467545, "verbPrefixes": [ "kicad_" ], "healthEndpoint": "/status",- "released_at": "2026-08-20T00:20:00Z",+ "released_at": "2026-08-20T00:55:00Z", "hero": "https://wiki.adom.inc/blob/app/kicad-bridge/kicad-hero.png", "languages": [ "Python",
bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "kicad", "displayName": "KiCad EDA",- "version": "0.9.196",+ "version": "0.9.197", "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/open_footprint_editor.py+18@@ -97,6 +97,20 @@ def _find_kicad_manager() -> int | None: return None ++def _step(label: str, percent=None, blocked_by: str = None) -> None:+ """Report a SUB-STEP of the running footprint phase (wiki issues #35, #39).++ Without these the ab status line reads "show_footprint starting" for the+ whole 20-30s cold open - a bar that moves but never says anything. Best+ effort: progress reporting must never be able to fail a real verb."""+ try:+ from handlers import progress as _pg+ for ph in ("show_footprint", "show_3d_chip", "cold_start", "warm_start"):+ _pg.step(ph, label, percent, blocked_by=blocked_by)+ except Exception:+ pass+ def _find_footprint_editor() -> int | None: """Find an open Footprint Editor window.""" windows = _find_windows_by_title("Footprint Editor")@@ -482,6 +496,8 @@ def handle_open_footprint_editor(kicad_info: dict, args: dict) -> dict: fp_hwnd = _find_footprint_editor() pathways_tried: list[str] = []+ _step("Footprint Editor already open" if fp_hwnd+ else "opening the Footprint Editor (KiCad indexes every footprint library here)", 10) # Tier 0: open Footprint Editor from a RUNNING pcbnew (menu id 20572 — # "Footprint Editor", discovered via get_menu_ids on KiCad 10). The Footprint@@ -766,6 +782,7 @@ def handle_open_footprint_editor(kicad_info: dict, args: dict) -> dict: # v0.9.89: plugin-free background load first (the 0.9.86 symbol-editor tier). _filter = f"{library_name} {footprint_name}".strip() if library_name else search_text+ _step(f"navigating the library tree to '{search_text}'", 80) if _background_navigate_win32_fp(fp_hwnd, _filter, _verify): return { "success": True,@@ -779,6 +796,7 @@ def handle_open_footprint_editor(kicad_info: dict, args: dict) -> dict: # 0.9.192: retry here instead of telling the caller to. The first attempt is # what warms the library tree, so a second one is a genuinely different shot, # not a repeat of a hopeless call. Same change as open_symbol_editor.+ _step("first pass did not confirm; retrying now the tree is warm", 90) if _background_navigate_win32_fp(fp_hwnd, _filter, _verify): return { "success": True,
server.py+20@@ -554,6 +554,26 @@ def _handle_progress(kicad_info: dict, args: dict) -> dict: frames = _pg.live() except Exception as e: return {"success": False, "error": f"progress unavailable: {e}"[:140]}++ # blockedBy, resolved at POLL time (issue #39, John: "the one that buys the+ # most trust"). A bar that keeps sliding while KiCad is sitting on a modal+ # the USER has to dismiss is worse than no bar. Doing the scan here rather+ # than inside the slow verb costs nothing when idle, and is more accurate:+ # it reports whether a dialog is up NOW, not whether one was up when the+ # verb last thought to look.+ if frames:+ try:+ from handlers.close_windows import _win_scan_kicad_dialogs+ for d in (_win_scan_kicad_dialogs(kicad_info) or []):+ if not d.get("isDialog"):+ continue+ what = (d.get("title") or "").strip() or "a KiCad dialog"+ for f in frames:+ f["blockedBy"] = what+ f["stepLabel"] = f"waiting for you: {what}"+ break+ except Exception:+ pass return { "success": True, "busy": bool(frames),