app
Fusion - the Fusion 360 Bridge
Public Made by Adomby adom
Drive Autodesk Fusion 360 from the cloud via Adom Bridge: component libraries, IPC package generation, board layout, exports (STEP/Gerbers/BOM/CPL), fast APS cloud search, and parametric modeling.
← Commit history
server.py+56−12@@ -3759,18 +3759,39 @@ def _fusion_window_hwnd(): # tree so page buttons/fields ARE reachable by accessible name. So: ALWAYS try background UIA # first and only fall back to a foreground click for things with no UIA node (Fusion's Sign In # button is a webview with none - that is the one documented exception).-def _click_background_first(hwnd, name=None, shot_id=None, x=None, y=None) -> dict:- """Click preferring the BACKGROUND UIA path. Returns {clicked, via, why}."""+def _announce_foreground(reason: str) -> bool:+ """ALWAYS tell the user WHY, right before we steal their foreground.++ John, 2026-07-22: "anytime you bring something to the foreground, you should show an ad notify+ for 2 seconds telling the user why... or an ad caption." A caption is the gentler of the two+ (no toast stack, auto-clears), so that is what we use. Best-effort; never blocks the action.+ """+ try:+ _ad_call("desktop_caption",+ {"text": "Adom: %s" % reason, "id": "fusion-bridge-foreground",+ "expiresInMs": 2500}, timeout=15)+ return True+ except Exception:+ return False+++def _click_background_first(hwnd, name=None, shot_id=None, x=None, y=None, reason=None) -> dict:+ """Click preferring the BACKGROUND UIA path (no focus steal, no cursor move). Only falls back+ to SendInput - which DOES foreground - when there is no UIA node, and in that case announces+ WHY to the user first. Returns {clicked, via, why, announced}.""" if name: r = _unwrap(_ad_call("desktop_ui_click", {"hwnd": int(hwnd), "name": name}, timeout=30)) if r.get("ok") or r.get("clicked") or r.get("invoked"):- return {"clicked": True, "via": "uia_background", "why": "UIA Invoke on %r" % name}+ return {"clicked": True, "via": "uia_background", "announced": False,+ "why": "UIA Invoke on %r (background, no focus steal)" % name} if shot_id is not None and x is not None and y is not None:+ announced = _announce_foreground(reason or "clicking %s for you" % (name or "a button")) _ad_call("desktop_click", {"space": "image", "shotId": shot_id, "x": int(x), "y": int(y), "hwnd": int(hwnd)}, timeout=30)- return {"clicked": True, "via": "foreground_click",- "why": "no UIA node; fell back to SendInput (this one DOES foreground)"}- return {"clicked": False, "via": None, "why": "no UIA node and no shot coords given"}+ return {"clicked": True, "via": "foreground_click", "announced": announced,+ "why": "no UIA node; used SendInput (DOES foreground - user was told why)"}+ return {"clicked": False, "via": None, "announced": False,+ "why": "no UIA node and no shot coords given"} # ── HUMAN WALLS: notify the user, and tell the AI it can drive it ────────────────────────────@@ -3778,19 +3799,38 @@ def _click_background_first(hwnd, name=None, shot_id=None, x=None, y=None) -> di # "suggest to the ai via hints that you can drive the thing on your own cuz the adom user wants # you to do everything automatically if you can". So on every wall we do BOTH: toast the human, # and hand the AI an exact, mechanical way to clear it without them.-def _detect_signin_wall() -> dict:+def _autodesk_window_hwnds() -> set:+ """hwnds of every Autodesk-ish BROWSER window right now (used to tell NEW from STALE)."""+ wins = _unwrap(_ad_call("desktop_list_windows", {}, timeout=40)).get("windows") or []+ out = set()+ for w in wins:+ tl = str(w.get("title", "")).lower()+ if "autodesk" in tl and "fusion" not in tl:+ out.add(w.get("hwnd"))+ return out+++def _detect_signin_wall(ignore_hwnds=None) -> dict: """Classify what the Autodesk sign-in is waiting on, from BROWSER WINDOW TITLES.- Title-based on purpose: cheap, needs no OCR, and never touches/foregrounds the window."""+ Title-based on purpose: cheap, needs no OCR, and never touches/foregrounds the window.++ ignore_hwnds = windows that already existed BEFORE we opened this sign-in. Without it a dead+ 'Sign-in request expired' / stale '2-step verification' tab from an earlier attempt gets+ reported as the live wall and we toast the user about nothing (seen live 2026-07-22).+ """+ ignore = set(ignore_hwnds or ()) wins = _unwrap(_ad_call("desktop_list_windows", {}, timeout=40)).get("windows") or [] best = {} for w in wins:+ if w.get("hwnd") in ignore:+ continue t = str(w.get("title", "")); tl = t.lower() if "2-step verification" in tl or "confirm sign-in" in tl: return {"wall": "twofactor_email_code", "hwnd": w.get("hwnd"), "title": t}- if "sign in - autodesk" in tl and not best:- best = {"wall": "credentials", "hwnd": w.get("hwnd"), "title": t} if "identity manager" in tl: best = {"wall": "protocol_handoff", "hwnd": w.get("hwnd"), "title": t}+ elif "sign in - autodesk" in tl and not best:+ best = {"wall": "credentials", "hwnd": w.get("hwnd"), "title": t} return best @@ -3886,7 +3926,8 @@ def _fusion_click_signin() -> dict: # node, so this almost always falls through to the image-space click - that is the documented # exception to the never-foreground rule, not a licence to foreground elsewhere. r = _click_background_first(hwnd, name="Sign In", shot_id=sid,- x=int(w * 0.5), y=int(h * 0.57))+ x=int(w * 0.5), y=int(h * 0.57),+ reason="signing Fusion in for you (clicking Sign In)") return {"clicked": r.get("clicked"), "why": "%s (image %dx%d)" % (r.get("why"), w, h), "via": r.get("via")}@@ -4109,6 +4150,9 @@ def _orchestrate_signin(args: dict) -> dict: tdesc = next((_describe_profile(c) for c in choices if c.get("profile") == target), target) import time as _tt sess = "fusion-signin-%d" % int(_tt.time()) # unique per attempt (a reused id can be refused)+ # snapshot the Autodesk windows that already exist, so a STALE expired tab from an earlier+ # attempt is never mistaken for this attempt's wall+ pre_hwnds = _autodesk_window_hwnds() _open_args = {"sessionId": sess, "url": auth["url"], "background": True, "profile": target, "thread": "fusion-signin", "purpose": "Fusion Autodesk sign-in (correct profile)"}@@ -4134,7 +4178,7 @@ def _orchestrate_signin(args: dict) -> dict: # Did the reopened sign-in immediately hit a HUMAN WALL (2FA, credentials, protocol dialog)? # If so, toast the user AND tell the AI how to clear it for them.- wall = _detect_signin_wall() if opened else {}+ wall = _detect_signin_wall(ignore_hwnds=pre_hwnds) if opened else {} wall_kind = wall.get("wall") notified = False if wall_kind: