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.190: THE #34 ROOT CAUSE, and it was mine - a dedupe edit stripped 'import sys' from inside the GENERATED loader's source text, so every fresh deploy shipped a loader that died with NameError at import and logged it silently. Restored, plus the generated sources are now executed in a sandbox at import time so this class of break is loud
5 files changed
+42−7
BRIDGE_VERSION+1−1@@ -1 +1 @@-0.9.189+0.9.190
adom-bridge-kicad-manifest.json+5−5@@ -1,15 +1,15 @@ { "manifest_version": 1, "name": "kicad",- "version": "0.9.189",- "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.189/adom-bridge-kicad-v0.9.189.zip",- "sha256": "7f13596197384490e009ecea5f1a5cd8732d435a5f5b59e149be3a7ffbcaf451",- "size": 458771,+ "version": "0.9.190",+ "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.190/adom-bridge-kicad-v0.9.190.zip",+ "sha256": "236a0956ddb424a4137f079597f585193aabad886f56f0c1990601d9e471be00",+ "size": 459265, "verbPrefixes": [ "kicad_" ], "healthEndpoint": "/status",- "released_at": "2026-08-19T20:51:11Z",+ "released_at": "2026-08-19T20:53:17Z", "hero": "https://wiki.adom.inc/blob/app/kicad-bridge/kicad-hero.png", "languages": [ "Python",
adom-bridge-kicad-v0.9.190.zipadded⋯ 1 unchanged line ⋯
bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "kicad", "displayName": "KiCad EDA",- "version": "0.9.189",+ "version": "0.9.190", "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.",
plugin_install.py+35@@ -155,6 +155,7 @@ has finished setting Python up. Everything is logged to %TEMP%/adom-kicad-plugin-loader.log so a failure is one file away. \"\"\" import os+import sys import tempfile import threading import time@@ -212,6 +213,40 @@ except Exception: """ +def _selftest_generated_sources() -> None:+ """Run the generated loaders in a sandbox at import time.++ They are shipped as TEXT, so nothing type-checks or imports them here, and+ they deliberately swallow their own exceptions into a log file - which means+ a broken one fails SILENTLY on the user's machine. Executing them in a throw+ away namespace turns that into an immediate, loud failure for us instead.+ """+ import tempfile as _tf+ for name, src in (("adom_bridge_plugin.py", _PLUGIN_DIR_LOADER),+ ("adom_bridge_boot.py", _BOOT_PY)):+ ns = {"__name__": "__selftest__"}+ log = os.path.join(_tf.gettempdir(), "adom-kicad-plugin-loader.log")+ before = os.path.getsize(log) if os.path.exists(log) else 0+ try:+ exec(compile(src, name, "exec"), ns) # noqa: S102 - our own text+ except SystemExit:+ pass+ except Exception as e: # pragma: no cover+ raise RuntimeError(f"generated {name} is broken: {type(e).__name__}: {e}")+ try:+ if os.path.exists(log) and os.path.getsize(log) > before:+ with open(log, encoding="utf-8", errors="replace") as fh:+ fh.seek(before)+ tail = fh.read()+ if "Traceback" in tail or "Error" in tail:+ raise RuntimeError(f"generated {name} logged a failure: {tail[:200]}")+ except OSError:+ pass+++_selftest_generated_sources()++ def _kicad_plugin_dirs(version: str): """KiCad's own scripting-plugin directories (it imports every .py here at startup). %APPDATA%/kicad/<version>/scripting/plugins on Windows."""