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 4 file(s)
4 files changed
+87−8
BRIDGE_VERSION+1−1@@ -1 +1 @@-0.9.202+0.9.203
adom-bridge-kicad-manifest.json+5−5@@ -1,15 +1,15 @@ { "manifest_version": 1, "name": "kicad",- "version": "0.9.202",- "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.202/adom-bridge-kicad-v0.9.202.zip",- "sha256": "da428b6cb0ecff185fa43e6918487362371f8b0039d3abaac2af3783755f13fe",- "size": 471755,+ "version": "0.9.203",+ "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.203/adom-bridge-kicad-v0.9.203.zip",+ "sha256": "6a11d4fb41c136ac77a2b31c9bc9be77a7c8517f57c57544855671a0084b5275",+ "size": 472907, "verbPrefixes": [ "kicad_" ], "healthEndpoint": "/status",- "released_at": "2026-08-20T11:05:00Z",+ "released_at": "2026-08-20T11:30: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.202",+ "version": "0.9.203", "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_ui.py+80−1@@ -73,7 +73,85 @@ VK_MAP = { "f9": 0x78, "f10": 0x79, "f11": 0x7A, "f12": 0x7B, } -SCREENSHOT_DIR = "C:/tmp/adom-desktop-screenshots"+def _screenshot_dir() -> str:+ """Where this bridge writes its captures.++ Wiki issue #40 (John, 2026-08-20). This used to be a hardcoded+ C:/tmp/adom-desktop-screenshots. Two problems: `adom-desktop` is a RETIRED+ product name (renamed to Adom Bridge in 2.0.0), so a fresh directory under+ the old name was the last place it was still propagating - a user auditing+ their disk found a folder for an app that no longer exists; and C:/tmp is+ not a Windows convention at all. Now it lives beside the other bridge caches+ under the current name, matching what pup does."""+ base = os.environ.get("LOCALAPPDATA")+ if base:+ return os.path.join(base, "Adom Bridge", "bridges-cache", "kicad", "screenshots")+ return os.path.join(os.environ.get("TEMP") or "/tmp", "adom-kicad-shots")+++SCREENSHOT_DIR = _screenshot_dir()++# Retained so the janitor can drain what earlier versions already wrote.+_LEGACY_SCREENSHOT_DIRS = ("C:/tmp/adom-desktop-screenshots", "C:/tmp/ad-shots")++_SHOT_MAX_AGE_SEC = 48 * 3600 # two days of history is plenty to debug with+_SHOT_MAX_FILES = 300 # and a hard ceiling for a heavy test day+_last_prune = 0.0+++def prune_screenshots(force: bool = False) -> dict:+ """Keep the capture directory bounded. Nothing else prunes it - ab's janitor+ covers ab's OWN dirs and should not be expected to know about ours.++ Deletes by age first, then oldest-first if still over the file ceiling, and+ drains the retired directories on the way. Runs at most once every 10+ minutes so it never adds latency to a burst of captures."""+ global _last_prune+ now = time.time()+ if not force and (now - _last_prune) < 600:+ return {"skipped": "ran recently"}+ _last_prune = now+ removed = 0+ freed = 0+ for d in (SCREENSHOT_DIR,) + _LEGACY_SCREENSHOT_DIRS:+ try:+ if not os.path.isdir(d):+ continue+ legacy = d != SCREENSHOT_DIR+ entries = []+ for name in os.listdir(d):+ fp = os.path.join(d, name)+ try:+ st = os.stat(fp)+ except Exception:+ continue+ if not os.path.isfile(fp):+ continue+ entries.append((st.st_mtime, st.st_size, fp))+ entries.sort()+ # A retired directory is drained entirely; the live one keeps a window.+ doomed = list(entries) if legacy else [+ e for e in entries if (now - e[0]) > _SHOT_MAX_AGE_SEC]+ if not legacy:+ keep = [e for e in entries if e not in doomed]+ if len(keep) > _SHOT_MAX_FILES:+ doomed += keep[: len(keep) - _SHOT_MAX_FILES]+ for _mt, size, fp in doomed:+ try:+ os.remove(fp)+ removed += 1+ freed += size+ except Exception:+ pass+ if legacy:+ try:+ os.rmdir(d)+ except Exception:+ pass+ except Exception:+ pass+ return {"removed": removed, "freedMB": round(freed / 1048576.0, 1),+ "dir": SCREENSHOT_DIR} # KiCad window title keywords (wxWidgets windows use class wxWindowNR) KICAD_TITLE_KEYWORDS = [@@ -423,6 +501,7 @@ def _screenshot_hwnd(hwnd: int, label: str = "", max_dim: int = 1568) -> dict: user32.ReleaseDC(hwnd, hdc_screen) os.makedirs(SCREENSHOT_DIR, exist_ok=True)+ prune_screenshots() timestamp = int(time.time() * 1000) # Slugify the label so filenames have NO spaces/punctuation (clean for a # cloud caller to pull). v0.8.8: "pcb_editor pic_programmer Read Only" -> "pcb-editor-pic-programmer-read-only".