← Commit history

v1.9.11: focus etiquette drain sweep

John Lauer ·1604a08bcd ·1mo ago ·parent 4c42ce3
5 files changed +29−7
BRIDGE_VERSION+1−1
@@ -1 +1 @@-1.9.10\ No newline at end of file+1.9.11\ No newline at end of file
adom-bridge-fusion-manifest.json+4−4
@@ -1,10 +1,10 @@ {     "manifest_version": 1,     "name": "fusion360",-    "version": "1.9.10",-    "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.10/adom-bridge-fusion-v1.9.10.zip",-    "sha256": "b3bebb34d99940a281d317253dec76ce6e4891123e10a490624093f90d0a787e",-    "size": 358515,+    "version": "1.9.11",+    "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.11/adom-bridge-fusion-v1.9.11.zip",+    "sha256": "7b3896d37966565029b928caff13189f43fa57037c3adc8612e73990bb861690",+    "size": 358860,     "verbPrefixes": [         "fusion_"     ],
bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "fusion360",   "displayName": "Autodesk Fusion 360",-  "version": "1.9.10",+  "version": "1.9.11",   "description": "Drive Autodesk Fusion 360 from the cloud: launch Fusion, electronics board layout, design rules, exports (STEP/IGES/STL/3MF/USDZ/OBJ/DXF/DWG/Gerbers/BOM/CPL), fast APS server-indexed cloud search plus browse/recent/file-info/versions, cloud file download/upload and folder creation, and in-app parametric modeling (fusion_run_modeling_script). Never-charge: APS calls are capped to the free tier.",   "homepage": "https://wiki.adom.inc/adom/fusion-bridge",   "author": "Adom Inc.",
fusion_detect.py+19−1
@@ -782,7 +782,25 @@ def _envelope_watch(seconds: float, minimize: bool):                             user32.SetWindowPos(fg, HWND_BOTTOM, 0, 0, 0, 0, SWP_FLAGS)             except Exception:                 pass-            time.sleep(0.1)+            time.sleep(0.05)+        # Drain sweep (2026-08-15, caught live by focus_invariance + John watching): a modal+        # (Package3D Save dialog) can pop AT the deadline and keep the foreground it grabbed+        # after the watcher dies. If a family window holds the foreground at drain time, keep+        # demoting for a grace period instead of walking away mid-steal.+        grace_end = time.time() + 20+        while time.time() < grace_end:+            try:+                fg = user32.GetForegroundWindow()+                if not (fg and pids):+                    break+                wpid = ctypes.wintypes.DWORD(0)+                user32.GetWindowThreadProcessId(fg, ctypes.byref(wpid))+                if wpid.value not in pids:+                    break+                user32.SetWindowPos(fg, HWND_BOTTOM, 0, 0, 0, 0, SWP_FLAGS)+            except Exception:+                break+            time.sleep(0.2)     except Exception:         pass  # non-Windows / ctypes unavailable: envelope is a no-op, refcount still drains     finally:
server.py+4
@@ -2596,6 +2596,10 @@ def _orchestrate_attach_3d_package(args: dict) -> dict:                 "error": "filePath (.lbr) and modelPath (.step) are required (Windows paths, e.g. C:/...).",                 "_hint": "Stage both onto Windows first (no container->Windows push verb). See the fusion-libraries skill."}     steps = []+    # The attach flow raises documents AND modal dialogs over several minutes - arm its own+    # long envelope so the Save dialog at the end is still covered (2026-08-15: the dispatch+    # envelope had expired by dialog time and the dialog kept the user's foreground).+    begin_background_envelope(600.0)     open_res = _orchestrate_open_lbr({"filePath": file_path})     if not open_res.get("success"):         return {"success": False, "error": "open_lbr failed: " + str(open_res.get("error")), "data": {"steps": steps}}