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.260: reveal falls back to a win32 filter set (library name only, no Enter) since eeschema's embedded Python binds minutes after a cold start
4 files changed
+41−21
BRIDGE_VERSION+1−1@@ -1 +1 @@-0.9.259+0.9.260
adom-bridge-kicad-manifest.json+5−5@@ -1,15 +1,15 @@ { "manifest_version": 1, "name": "kicad",- "version": "0.9.259",- "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.259/adom-bridge-kicad-v0.9.259.zip",- "sha256": "a32aa98f06a11fb4cfa211d49cd8eaa87024a2c16fe0c2c60e4c36efd7506451",- "size": 454884,+ "version": "0.9.260",+ "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.260/adom-bridge-kicad-v0.9.260.zip",+ "sha256": "bcce76a321d8a006d041235bc909855ab5e00dd4123142766581fed176368f23",+ "size": 455286, "verbPrefixes": [ "kicad_" ], "healthEndpoint": "/status",- "released_at": "2026-08-27T21:26:22Z",+ "released_at": "2026-08-27T21:29:41Z", "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.259",+ "version": "0.9.260", "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/install_library_bundle.py+34−14@@ -112,32 +112,52 @@ def _capture_proof(kicad_info: dict, args: dict, lib_name: str, first_symbol: st # Show the FULL list: clear the tree filter and select/expand the # library node by name (plugin 0.9.2 reveal_library; a text filter # made generic names like 'UI' lose a fuzzy match to other libs).+ _revealed = False try: import time as _rt from handlers.bridge_client import _resolve_plugin, call as _plugin_call- # A cold-started eeschema takes a few seconds to bind its- # reverse-bridge plugin; wait like the open path does instead- # of racing it (the capture itself may have used the win32- # fallback and proves nothing about plugin liveness).- _deadline = _rt.monotonic() + 15+ # Plugin path first when it happens to be alive (node select,+ # generic-name-proof) -- but eeschema's embedded Python+ # initializes LAZILY (minutes after launch, issue #21), so on a+ # cold start this almost never binds in time. Short wait only.+ _deadline = _rt.monotonic() + 4 info = err = None while _rt.monotonic() < _deadline: info, err = _resolve_plugin("eeschema") if info and err is None: break- _rt.sleep(1.5)+ _rt.sleep(1.0) if info and err is None: rev = _plugin_call(info["port"], "reveal_library", {"libraryName": lib_name}, timeout=20.0)- result["libraryRevealed"] = bool((rev or {}).get("found"))- if not result["libraryRevealed"]:- result["revealDetail"] = str((rev or {}).get("error") or rev)[:200]- else:+ _revealed = bool((rev or {}).get("found"))+ if _revealed:+ result["libraryRevealed"] = "tree"+ except Exception:+ pass+ if not _revealed:+ # Plugin-free fallback (the normal cold-start path): WM_SETTEXT+ # the LIB_TREE filter to JUST the library name -- no Enter, so+ # the loaded symbol stays put and the tree shows the library's+ # full list. (A generic name like 'UI' can still fuzzy-match+ # other libraries above ours; only the plugin path fixes that.)+ try:+ import ctypes+ from handlers.kicad_ui import _find_all_kicad_windows+ from handlers.open_symbol_editor import _find_child_by_class_and_parent+ user32 = ctypes.windll.user32+ hwnd = next((w.get("hwnd") for w in (_find_all_kicad_windows() or [])+ if "symbol editor" in (w.get("title") or "").lower()), None)+ edit = _find_child_by_class_and_parent(hwnd, "Edit", "searchCtrl") if hwnd else None+ if edit:+ user32.SendMessageW(edit, 0x000C, 0, ctypes.create_unicode_buffer(lib_name))+ result["libraryRevealed"] = "filter"+ else:+ result["libraryRevealed"] = False+ result["revealDetail"] = "no symbol editor filter control found"+ except Exception as e: result["libraryRevealed"] = False- result["revealDetail"] = f"plugin resolve failed: {err or 'no eeschema plugin'}"- except Exception as e:- result["libraryRevealed"] = False- result["revealDetail"] = f"{type(e).__name__}: {e}"+ result["revealDetail"] = f"{type(e).__name__}: {e}" except Exception as e: result["proofSkipped"] = str(e)