← Commit history

0.9.342: First-run wizard deadlock: time-boxed dialog clicks and bounded sweeps (#83)

John Lauer ·1b513ddca3 ·1mo ago ·parent 680ee7e
3 files changed +19−3
BRIDGE_VERSION+1−1
@@ -1 +1 @@-0.9.341\ No newline at end of file+0.9.342\ No newline at end of file
bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "kicad",   "displayName": "KiCad EDA",-  "version": "0.9.341",+  "version": "0.9.342",   "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/close_windows.py+17−1
@@ -436,7 +436,17 @@ if IS_WINDOWS:         for tier in _DISMISS_BUTTON_TIERS:             btn = _find_button(tier)             if btn:-                user32.SendMessageW(btn, BM_CLICK, 0, 0)+                # NEVER a plain SendMessage here (#83, winvm 2026-09-07): clicking the+                # first-run wizard's Cancel opens its "Are you sure?" Confirmation+                # MODALLY inside the button handler, so a synchronous BM_CLICK does+                # not return until that box is answered, and the only thing that+                # would answer it is this sweep, which is blocked. That deadlock held+                # kicad_open_schematic past ab's 130 s budget. Time-boxed send: the+                # click is delivered, we get control back, the next pass answers the+                # follow-up dialog.+                SMTO_ABORTIFHUNG = 0x0002+                res = ctypes.wintypes.DWORD(0)+                user32.SendMessageTimeoutW(btn, BM_CLICK, 0, 0, SMTO_ABORTIFHUNG, 1500, ctypes.byref(res))                 return "clicked-button"         # No recognized button — Escape closes most wizards/dialogs cleanly.         user32.PostMessageW(hwnd, WM_KEYDOWN, VK_ESCAPE, 0)@@ -517,7 +527,10 @@ if IS_WINDOWS:         # only the first time we see a given hwnd so we don't shoot the same box         # repeatedly. Stop as soon as a pass dismisses nothing new.         shot_hwnds: set = set()+        _deadline = time.time() + 25.0   # a sweep is never allowed to eat the verb's budget         for _pass in range(5):+            if time.time() > _deadline:+                break             remaining = []             acted = False             for w in _win_scan_kicad_dialogs(kicad_info):@@ -912,7 +925,10 @@ def auto_sweep_dialogs(kicad_info: dict, screenshot: bool = True,     dialogs = []     had_error = False     seen = set()+    _deadline = time.time() + 25.0   # bounded: ab's budget is 130 s and the verb already spent some     for _pass in range(4):+        if time.time() > _deadline:+            break         acted = False         for w in _win_scan_kicad_dialogs(kicad_info):             if not w.get("isDialog"):