← Commit history

v1.6.63: FIX launch regression - run the FusionLauncher.exe that HAS its .ini beside it (the stub), not the app-dir launcher (no .ini) which throws 'Error Launching Streamed Application'. Separate 'installed?'(Fusion360.exe) from 'which launcher'(the .ini-bearing one). Stop mis-blaming a healthy install as incomplete.

John Lauer ·9dc5138263 ·3mo ago ·parent 7a0299c
4 files changed +67−41
BRIDGE_VERSION+1−1
@@ -1 +1 @@-1.6.62\ No newline at end of file+1.6.63\ No newline at end of file
adom-bridge-fusion-manifest.json+4−4
@@ -1,10 +1,10 @@ {   "manifest_version": 1,   "name": "fusion360",-  "version": "1.6.62",-  "url": "https://wiki.adom.inc/download/adom/adom-desktop-fusion-bridge/1.6.62/adom-bridge-fusion-v1.6.62.zip",-  "sha256": "71007d08f29036151f947769a7cab289a20a2a9a5f71b6d6044ccf9b9356d4c7",-  "size": 357246,+  "version": "1.6.63",+  "url": "https://wiki.adom.inc/download/adom/adom-desktop-fusion-bridge/1.6.63/adom-bridge-fusion-v1.6.63.zip",+  "sha256": "8db07d4fb1be353eb055cc37681e14700b4c4da3e47cd2eecbb46c14cad91a17",+  "size": 357907,   "verbPrefixes": [     "fusion_"   ],
bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "fusion360",   "displayName": "Autodesk Fusion 360",-  "version": "1.6.62",+  "version": "1.6.63",   "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/adom-desktop-fusion-bridge",   "author": "Adom Inc.",
fusion_detect.py+61−35
@@ -129,11 +129,25 @@ def _any_app_complete() -> bool:   def _find_fusion_launcher() -> Path | None:-    """Return the FusionLauncher.exe to launch, but ONLY when a COMPLETE install exists (a hash dir-    with Fusion360.exe). Otherwise None -> detect_fusion() reports NOT installed, and readiness-    surfaces the streamer as installing. Prefers the launcher living beside the newest complete app;-    falls back to any FusionLauncher.exe on disk, then to Fusion360.exe itself."""-    complete_dirs = []   # (mtime, subdir)+    """Return the FusionLauncher.exe to RUN, but only when Fusion is actually INSTALLED.++    TWO SEPARATE QUESTIONS (conflating them is what broke the launch, John 2026-07-14):+      1. Is Fusion installed?  ->  a hash dir contains the real app binary Fusion360.exe.+      2. Which launcher do I run?  ->  a FusionLauncher.exe that HAS its FusionLauncher.exe.ini+         BESIDE IT. Running a FusionLauncher.exe WITHOUT its .ini throws Fusion's own+         "Error Launching Streamed Application ... FusionLauncher.exe.ini is missing or incomplete".+         The complete APP dir (615 files, Fusion360.exe) frequently has the launcher but NO .ini; a+         separate tiny STUB dir carries FusionLauncher.exe + its ~412-byte .ini and knows how to load+         the app. So we must return the launcher-WITH-.ini, NOT the app dir's bare launcher.++    Because we gate on Fusion360.exe first, the stub's .ini is guaranteed complete by then (mid-stream+    there is no Fusion360.exe, so we return None and nothing launches into a half-written install)."""+    if not _any_app_complete():+        return None                                   # not installed (or still streaming) -> None++    runnable = []      # (mtime, launcher) - FusionLauncher.exe that has its .ini beside it+    bare = []          # (mtime, launcher) - FusionLauncher.exe with NO .ini (fallback only)+    app_exes = []      # (mtime, Fusion360.exe) - last-ditch fallback     for base in _WEBDEPLOY_BASES:         if not base.exists():             continue@@ -142,26 +156,24 @@ def _find_fusion_launcher() -> Path | None:         except OSError:             continue         for subdir in subdirs:+            try:+                mtime = subdir.stat().st_mtime+            except OSError:+                mtime = 0.0+            launcher = subdir / "FusionLauncher.exe"+            if launcher.exists():+                if (subdir / "FusionLauncher.exe.ini").exists():+                    runnable.append((mtime, launcher))+                else:+                    bare.append((mtime, launcher))             if _app_dir_complete(subdir):-                try:-                    mtime = subdir.stat().st_mtime-                except OSError:-                    mtime = 0.0-                complete_dirs.append((mtime, subdir))--    if not complete_dirs:-        return None                                   # nothing complete -> NOT installed-    complete_dirs.sort(key=lambda c: c[0], reverse=True)   # newest complete install wins-    newest = complete_dirs[0][1]-    launcher = newest / "FusionLauncher.exe"-    if launcher.exists():-        return launcher-    # complete app dir lacks its own launcher (unusual) - use any FusionLauncher.exe, else the app exe-    for _mt, subdir in complete_dirs:-        cand = subdir / "FusionLauncher.exe"-        if cand.exists():-            return cand-    return newest / _FUSION_APP_EXE+                app_exes.append((mtime, subdir / _FUSION_APP_EXE))++    for pool in (runnable, bare, app_exes):            # prefer launcher+ini, then bare launcher, then app exe+        if pool:+            pool.sort(key=lambda c: c[0], reverse=True)+            return pool[0][1]+    return None   def _incomplete_webdeploy_present() -> bool:@@ -800,23 +812,37 @@ def ensure_fusion_running(fusion_info: dict, wait_addin: bool = False) -> dict |                     close_dialog_bg(d.get("hwnd"))         except Exception:             pass-        removed = _clean_incomplete_webdeploy()-        if launch_err or removed:++        # DISTINGUISH the two causes (John 2026-07-14 - conflating them mis-blamed a healthy install):+        #  (a) app is COMPLETE (Fusion360.exe present) but launch failed -> almost always we launched a+        #      FusionLauncher.exe WITHOUT its .ini, or a stale lock from a just-killed instance. The+        #      install is FINE; do NOT tell the user to re-stream. _find_fusion_launcher now prefers the+        #      launcher-with-.ini, so a retry usually succeeds.+        #  (b) app is NOT complete -> a genuinely half-streamed install; clean the partial dirs so the+        #      next fusion_install_fusion re-streams clean.+        if _any_app_complete():             return {                 "success": False,-                "error": "Fusion launch failed: INCOMPLETE streamed install (FusionLauncher.exe.ini "-                         "missing or truncated).",-                "errorCode": "fusion_incomplete_install",-                "cleanedWebdeployDirs": removed,+                "error": "Fusion is INSTALLED (Fusion360.exe present) but did not start within 30s"+                         + (" - a launch-error dialog was dismissed" if launch_err else "") + ".",+                "errorCode": "fusion_launch_failed",+                "installed": True,                 "dialog": (launch_err or {}).get("title"),-                "_hint": "AUTO-RECOVERED: dismissed the launch-error dialog and removed the corrupt "-                         "webdeploy dir(s). Re-run fusion_install_fusion, then WAIT for fusion_readiness "-                         "to report installing:false (the streamer has exited) BEFORE fusion_start - "-                         "starting mid-stream is what corrupts the install.",+                "_hint": "The install is COMPLETE - do NOT re-stream. Retry fusion_start (it now picks the "+                         "FusionLauncher.exe that has its .ini beside it; a stale lock from a just-killed "+                         "instance also clears on a retry). If it keeps failing, fusion_kill then wait a "+                         "few seconds before fusion_start.",             }+        removed = _clean_incomplete_webdeploy()         return {             "success": False,-            "error": "Fusion 360 launched but process not found after 30s",+            "error": "Fusion launch failed: the streamed install is INCOMPLETE (no Fusion360.exe yet).",+            "errorCode": "fusion_incomplete_install",+            "cleanedWebdeployDirs": removed,+            "dialog": (launch_err or {}).get("title"),+            "_hint": "AUTO-RECOVERED: dismissed the launch-error dialog and removed the partial webdeploy "+                     "dir(s). Re-run fusion_install_fusion, then WAIT for fusion_readiness to report "+                     "installed:true BEFORE fusion_start - starting mid-stream is what corrupts the install.",         }      # Give it time to finish initializing UI