← Commit history

Upload 1 file(s)

John Lauer ·66cffaaa47 ·2mo ago ·parent 01e3143
1 file changed +79−41
server.py+79−41
@@ -3731,46 +3731,74 @@ def _chrome_authorize_urls(max_age_min: int = 15):     return found  -def _fusion_window_hwnd():-    """Find the main Fusion window's hwnd by title (via desktop_list_windows). Returns int|None."""-    r = _ad_call("desktop_list_windows", {}, timeout=40)-    wins = (r.get("windows") if isinstance(r, dict) else None) or []-    if not wins and isinstance(r, dict):-        wins = ((r.get("data") or {}).get("windows")) or []-    cand = None+def _fusion_window():+    """Find the main Fusion window via desktop_list_windows. Returns the whole entry (it already+    carries `rect`, so we get geometry in the SAME call - there is no desktop_window_info verb).+    Returns {} when not found."""+    wins = _unwrap(_ad_call("desktop_list_windows", {}, timeout=40)).get("windows") or []+    cand = {}     for w in wins:         t = str(w.get("title", ""))         tl = t.lower()-        if "autodesk fusion" in tl or tl.startswith("signing in") or t.strip() == "Autodesk Fusion":-            # prefer the sign-in/welcome window-            if "signing in" in tl or "welcome" in tl:-                return w.get("hwnd")-            cand = cand or w.get("hwnd")+        if "autodesk fusion" in tl or tl.startswith("signing in"):+            if "signing in" in tl or "welcome" in tl:   # prefer the sign-in/welcome window+                return w+            cand = cand or w     return cand  -def _fusion_click_signin() -> bool:-    """Click Fusion's 'Welcome to Fusion' -> Sign In button SERVER-SIDE (it is a webview with-    no UIA node, so image-space click). Returns True if a click was dispatched. Runs on-box so-    it adds no remote round-trip to the ~2-min OAuth window."""-    hwnd = _fusion_window_hwnd()-    if not hwnd:-        rd = _handle_fusion_readiness({}, {})-        hwnd = rd.get("hwnd") or rd.get("windowHandle")+def _fusion_window_hwnd():+    """Just the hwnd of the main Fusion window (int|None)."""+    return (_fusion_window() or {}).get("hwnd")+++def _unwrap(r):+    """AD verb responses come back either flat or nested under `data` (the CLI puts the real+    payload in output.data). Always look through both - forgetting this silently broke the+    server-side Sign In click, because coordMap/shotId live one level down."""+    if not isinstance(r, dict):+        return {}+    inner = r.get("data")+    if isinstance(inner, dict) and inner:+        return inner+    return r+++def _fusion_click_signin() -> dict:+    """Click Fusion's 'Welcome to Fusion' -> Sign In button SERVER-SIDE, ALWAYS, on the user's+    behalf (John, 2026-07-22: "you should ALWAYS just click sign in on behalf of the adom+    users"). The button is a webview with no UIA node, so this is an image-space click.++    Runs on-box, so it costs no remote round-trip against Fusion's ~2-min OAuth expiry.+    Returns {clicked: bool, why: str} - never raises.+    """+    import time as _t+    win = _fusion_window()+    hwnd = win.get("hwnd") or _unwrap(_handle_fusion_readiness({}, {})).get("hwnd")     if not hwnd:-        return False-    shot = _ad_call("desktop_screenshot_window", {"hwnd": int(hwnd)}, timeout=45)-    sd = shot if isinstance(shot, dict) else {}-    cm = sd.get("coordMap") or {}-    sid = cm.get("shotId") or sd.get("shotId")-    w = sd.get("width") or (cm.get("imageWidth") if isinstance(cm, dict) else None) or 1400-    h = sd.get("height") or (cm.get("imageHeight") if isinstance(cm, dict) else None) or 860+        return {"clicked": False, "why": "could not find the Fusion window"}++    # A MINIMIZED Fusion captures as a ~237x39 title-bar sliver, so the click lands on nothing.+    # Restore it first (seen live: rect was at -32000,-32000, the Windows minimized position).+    rect = win.get("rect") or {}+    if (rect.get("left") is not None and rect["left"] <= -30000) or \+       (0 < (rect.get("width") or 0) < 600) or (0 < (rect.get("height") or 0) < 400):+        _ad_call("desktop_set_window_state", {"hwnd": int(hwnd), "state": "restore"}, timeout=30)+        _t.sleep(1.5)++    shot = _unwrap(_ad_call("desktop_screenshot_window", {"hwnd": int(hwnd)}, timeout=45))+    cm = shot.get("coordMap") or {}+    sid = cm.get("shotId") or shot.get("shotId")     if not sid:-        return False+        return {"clicked": False, "why": "screenshot returned no shotId"}+    img = cm.get("image") or {}+    w = shot.get("width") or img.get("width") or cm.get("imageWidth") or 1400+    h = shot.get("height") or img.get("height") or cm.get("imageHeight") or 860     # the Sign In button sits centered, ~57% down the welcome screen-    _ad_call("desktop_click", {"space": "image", "shotId": sid,-                               "x": int(w * 0.5), "y": int(h * 0.57)}, timeout=30)-    return True+    r = _unwrap(_ad_call("desktop_click", {"space": "image", "shotId": sid,+                                           "x": int(w * 0.5), "y": int(h * 0.57)}, timeout=30))+    return {"clicked": True, "why": "clicked Sign In at image (%d,%d) of %sx%s" % (+        int(w * 0.5), int(h * 0.57), w, h)}   def _capture_fresh_authorize(wait_sec: int = 30, max_age: int = 120):@@ -3804,7 +3832,10 @@ def _orchestrate_signin(args: dict) -> dict:     the remote relay is slow. This is the reliable path; the staged/manual path is the fallback.     """     steps = []-    auto = bool(args.get("auto"))+    # ALWAYS click Sign In for the user unless they explicitly opt out (auto:false). Adom users+    # should never be told "now go click Sign In yourself" - we do it for them and SAY so.+    auto = args.get("auto")+    auto = True if auto is None else bool(auto)     wait_sec = int(args.get("waitSec") or 32)     target = args.get("profile")           # explicit override, e.g. "chrome:[email protected]"     if target:@@ -3832,9 +3863,11 @@ def _orchestrate_signin(args: dict) -> dict:     urls = _chrome_authorize_urls()     fresh = urls[0] if (urls and urls[0]["ageSec"] <= 150) else None     if auto and not fresh:-        # ONE server-side pass: click Fusion's Sign In, then poll on-box for the fresh URL.-        clicked = _fusion_click_signin()-        steps.append("clicked Fusion 'Sign In'" if clicked else "could not click Fusion 'Sign In'")+        # ONE server-side pass: click Fusion's Sign In FOR THE USER, then poll on-box for the URL.+        ck = _fusion_click_signin()+        clicked = ck.get("clicked")+        steps.append("clicked Fusion 'Sign In' for the user" if clicked+                     else "could not click Fusion 'Sign In' (%s)" % ck.get("why"))         got = _capture_fresh_authorize(wait_sec=wait_sec, max_age=140)         if got and got["ageSec"] <= 150:             urls = [got]@@ -3844,12 +3877,17 @@ def _orchestrate_signin(args: dict) -> dict:             urls = []     if not urls:         return {"success": True, "stage": "click_signin", "done": False, "steps": steps,-                "_hint": ("No recent Fusion OAuth URL in any browser's history yet - Fusion has not "-                          "opened the sign-in browser. CLICK Fusion's 'Sign In' button (it is a "-                          "webview with no UIA node, so image-space desktop_click on the button - "-                          "screenshot the Fusion window for a shotId first), wait ~4s, then call "-                          "fusion_signin again. This verb then grabs the URL Fusion opened in the "-                          "WRONG default browser and re-opens it in the RIGHT profile."),+                "narrate": ("I clicked Fusion's Sign In for you, but Fusion has not written its "+                            "sign-in URL to a browser yet. Give it a few seconds."),+                "_hint": ("THIS VERB CLICKS FUSION'S 'Sign In' FOR THE USER - never tell them to go "+                          "click it themselves, and do not click it yourself. It just did (see "+                          "steps[]), but no Fusion OAuth URL has landed in any browser's history "+                          "yet. Simply CALL fusion_signin AGAIN in a few seconds; it will click if "+                          "needed, wait on-box for the URL, and re-open it in the right profile. "+                          "If steps[] says the click FAILED, that is a bridge bug worth reporting - "+                          "the usual causes are a minimized Fusion window (this verb restores it) "+                          "or the sign-in wall not being up yet (check fusion_readiness "+                          "needsSignin:true)."),                 "statusVerb": "fusion_signin"}     auth = urls[0]     steps.append("captured Fusion OAuth URL from %s profile '%s' (%ss old)"