← Commit history

v0.9.185: background the project manager too (a spawned window that appears after the verb returned is still ours, for 60s) + wiki #35 warm-editor reuse: if the editor already shows the part, return in about a second instead of a ~56s cold path

John Lauer ·388d6962ca ·1mo ago ·parent 7969a4f
6 files changed +81−9
BRIDGE_VERSION+1−1
@@ -1 +1 @@-0.9.184+0.9.185
adom-bridge-kicad-manifest.json+5−5
@@ -1,15 +1,15 @@ {   "manifest_version": 1,   "name": "kicad",-  "version": "0.9.184",-  "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.184/adom-bridge-kicad-v0.9.184.zip",-  "sha256": "7778eb8b5ce1f04aa2bff108d478b2d41f7fd1fff6f1dfb28b8685639df987d5",-  "size": 453470,+  "version": "0.9.185",+  "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.185/adom-bridge-kicad-v0.9.185.zip",+  "sha256": "289572d55a9f54487fff3cecba20ad9920f3d72f0b32ba77a15f93b1022a2a54",+  "size": 454450,   "verbPrefixes": [     "kicad_"   ],   "healthEndpoint": "/status",-  "released_at": "2026-08-19T18:39:05Z",+  "released_at": "2026-08-19T19:00:04Z",   "hero": "https://wiki.adom.inc/blob/app/kicad-bridge/kicad-hero.png",   "languages": [     "Python",
adom-bridge-kicad-v0.9.185.zipadded
⋯ 1 unchanged line ⋯
bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "kicad",   "displayName": "KiCad EDA",-  "version": "0.9.184",+  "version": "0.9.185",   "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/show.py+47−2
@@ -42,10 +42,45 @@ def handle_show_project(kicad_info: dict, args: dict) -> dict:     return r  +def _open_editor_showing(kind: str, name: str, lib: str):+    """Is an editor of `kind` ALREADY open on exactly this part?++    Wiki issue #35 (Colby Knox): kicad_show_symbol cost ~56s on EVERY call, even+    when the Symbol Editor was already open on that exact symbol, because the+    verb always ran the cold path - and KiCad re-indexes every symbol library+    when that editor opens, which is where the time goes. The desired end state+    was already on screen; we just were not looking."""+    try:+        from handlers.kicad_ui import _find_all_kicad_windows+        want_editor = kind.lower()+        for w in _find_all_kicad_windows() or []:+            title = (w.get("title") or "")+            low = title.lower()+            if want_editor not in low:+                continue+            if name and name.lower() in low and (not lib or lib.lower() in low):+                return w+    except Exception:+        pass+    return None++ def handle_show_symbol(kicad_info: dict, args: dict) -> dict:     """Show a schematic SYMBOL in the Symbol Editor. Args: symbolName (+ libraryName),     or libraryName alone to browse a library."""-    r = handle_open_symbol_editor(kicad_info, args or {})+    a = args or {}+    already = _open_editor_showing("symbol editor", a.get("symbolName") or "",+                                   a.get("libraryName") or a.get("library") or "")+    if already:+        return {"success": True, "surface": "symbol", "reused": True,+                "window": already.get("title"),+                "output": f"Symbol Editor is already showing {already.get('title')} - "+                          f"reused it (no relaunch, no library rescan).",+                "_hint": "Returned the existing editor instead of running the cold path. "+                         "KiCad re-indexes every symbol library when the Symbol Editor "+                         "opens, so reuse is the difference between about a second and "+                         "about a minute (wiki issue #35)."}+    r = handle_open_symbol_editor(kicad_info, a)     r = _verify_window(r, _find_symbol_editor, "Symbol Editor")     r.setdefault("surface", "symbol")     return r@@ -143,8 +178,18 @@ def ensure_plugin_ready(kicad_info: dict, waits: int = 14) -> bool: def handle_show_footprint(kicad_info: dict, args: dict) -> dict:     """Show a FOOTPRINT in the Footprint Editor. Args: footprintName (+ library),     or library alone to browse."""+    a2 = args or {}+    already_fp = _open_editor_showing("footprint editor", a2.get("footprintName") or "",+                                      a2.get("library") or a2.get("libraryName") or "")+    if already_fp:+        return {"success": True, "surface": "footprint", "reused": True,+                "window": already_fp.get("title"),+                "output": f"Footprint Editor is already showing {already_fp.get('title')} - "+                          f"reused it (no relaunch, no library rescan).",+                "_hint": "Returned the existing editor instead of running the cold path "+                         "(wiki issue #35)."}     ensure_plugin_ready(kicad_info)-    r = handle_open_footprint_editor(kicad_info, args or {})+    r = handle_open_footprint_editor(kicad_info, a2)     r = _verify_window(r, _find_footprint_editor, "Footprint Editor")     r.setdefault("surface", "footprint")     return r
handlers/win_focus.py+27
@@ -579,12 +579,33 @@ def load_owned_ledger() -> None:             pass  +_spawn_watch_until = 0.0   # we are responsible for windows appearing before this+++def spawn_watch_active() -> bool:+    try:+        import time as _t+        return _t.monotonic() < _spawn_watch_until+    except Exception:+        return False++ def register_owned_pid(pid) -> None:     """Spawn sites call this for every kicad-family process the bridge starts."""+    global _spawn_watch_until     try:         if pid:             _owned_pids.add(int(pid))             _save_ledger()+            # 0.9.185 (John, live: "you opened the kicad main menu and it came to+            # the foreground - you did nothing to even attempt once to put it in+            # the background"). A spawned app can take many seconds to show its+            # first window, by which time the verb has returned and the idle rule+            # correctly says "hands off". That rule is for windows the USER+            # opened; for 60s after WE spawn something, a window that appears in+            # front is ours to put behind - exactly once, as always.+            import time as _t+            _spawn_watch_until = _t.monotonic() + 60.0     except Exception:         pass @@ -1317,6 +1338,12 @@ def start_focus_sentinel() -> None:                             _log("user-owned window (left alone)", fg, ago)                         elif _guard_count > 0:                             _log("steal-during-guard (guardian handles)", fg, ago)+                        elif (_verb_inflight <= 0 and _guard_count <= 0+                              and spawn_watch_active() and _is_owned_window(fg)):+                            # We spawned this within the last minute: it is ours+                            # to background, once, even though the verb returned.+                            _log("our freshly spawned window took the foreground", fg, ago)+                            _push_kicad_to_background(fg)                         elif _verb_inflight <= 0 and _guard_count <= 0:                             # 0.9.172 - THE IDLE RULE (John, 2026-08-19: "when I                             # click the taskbar icon to bring the app to the fg,