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 40 file(s)
4 files changed
+27−11
BRIDGE_VERSION+1−1@@ -1 +1 @@-0.9.267+0.9.268
adom-bridge-kicad-manifest.json+5−5@@ -1,15 +1,15 @@ { "manifest_version": 1, "name": "kicad",- "version": "0.9.267",- "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.267/adom-bridge-kicad-v0.9.267.zip",- "sha256": "97384b29d0c8789dd3c0dbf7bf6a5cfde124066fece969a67b6108a696692c96",- "size": 1039132,+ "version": "0.9.268",+ "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.268/adom-bridge-kicad-v0.9.268.zip",+ "sha256": "18fc8eef06c10d653465a18f7a5e65d3138385b91364cf45c3ee62cabd617c68",+ "size": 1039529, "verbPrefixes": [ "kicad_" ], "healthEndpoint": "/status",- "released_at": "2026-09-01T02:31:50Z",+ "released_at": "2026-09-01T02:33:56Z", "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.267",+ "version": "0.9.268", "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/kicad_log.py+20−4@@ -183,7 +183,14 @@ def _enum_dialog_text(hwnd: int) -> list[str]: txt = (buf.value or "").strip() cls = ctypes.create_unicode_buffer(256) user32.GetClassNameW(child, cls, 256)- if txt and cls.value.lower() in ("static", "wxwindownr", "wxstatictext"):+ # Accept ANY child that carries text. The original filter listed+ # ("static","wxwindownr","wxstatictext") and returned nothing for a+ # KiCad 10 error, because that dialog is a Windows TASKDIALOG: its text+ # is drawn by DirectUI, in a DirectUIHWND with no per-string child+ # controls, so GetWindowText has nothing to find. UIA can read it,+ # win32 cannot. Keeping the broad filter still captures classic wx+ # dialogs; TaskDialogs fall through to the UIA hand-off below.+ if txt and cls.value.lower() not in ("button",): out.append(txt) return True @@ -221,9 +228,18 @@ def handle_errors(kicad_info: dict, args: dict) -> dict: texts = _enum_dialog_text(hwnd) # the message is the longest static; buttons are short ("OK", "Cancel") msg = max(texts, key=len) if texts else ""- wins.append({"hwnd": hwnd, "title": title, "message": msg,- "allText": texts[:12],- "level": "error" if _ERR_TITLE.search(title) else "info"})+ entry = {"hwnd": hwnd, "title": title, "message": msg,+ "allText": texts[:12],+ "level": "error" if _ERR_TITLE.search(title) else "info"}+ if not msg:+ # A TaskDialog. Say so, and hand the caller the exact call that DOES+ # read it, rather than reporting an error with no text and leaving+ # them to screenshot it.+ entry["messageUnavailable"] = "taskdialog_directui"+ entry["readTextWith"] = (f'desktop_ui_tree {{"hwnd":{hwnd},"maxDepth":8}} '+ "— the message is the Text node; win32 cannot read "+ "DirectUI, UIA can (read-only, no foreground)")+ wins.append(entry) return True try: