← Commit history

v1.6.11: detect globalinstall Fusion + notify-on-active-step

John Lauer ·5fcd63fa22 ·3mo ago ·parent 477475c
8 files changed +78−31
BRIDGE_VERSION+1−1
@@ -1 +1 @@-1.6.10\ No newline at end of file+1.6.11\ No newline at end of file
CHANGELOG.md+15
@@ -3,6 +3,21 @@ All notable changes to the Adom Desktop Fusion 360 bridge, newest first. Canonical: https://wiki.adom.inc/adom/adom-desktop-fusion-bridge · GitHub backup: `adom-inc/adom-desktop-fusion-bridge` +## 1.6.11 - 2026-07-03++- **Detect a system-wide (`--globalinstall`) Fusion, not just per-user (fixes a broken onboarding+  loop, found on the ADOMBASELINE fresh-VM test).** The fusion-onboarding skill installs Fusion with+  `--globalinstall`, which lands the launcher under `%ProgramFiles%\Autodesk\webdeploy\production\`,+  but detection (both `fusion_detect.py` and the `bridge.json` `detect` block) only checked+  `%LOCALAPPDATA%`. So an AI-installed Fusion was INVISIBLE - onboarding "succeeded" yet the bridge ++  AD `bridge_readiness` still reported `no-app`. Detection now scans `%LOCALAPPDATA%`, `%ProgramFiles%`,+  `%ProgramFiles(x86)%` (and `%ProgramW6432%`), preferring a complete install (has `.ini`) + newest.+- **Notify the user on EVERY active step.** Per the "the AI does everything, but pull the user in when+  only they can act" rule: the USER skill's convention 4 and fusion-onboarding now mandate an AD+  `notify_user` toast the instant the user must do something (Autodesk sign-in, 2FA, a UAC/elevation+  prompt, license acceptance), and a progress toast for long installs - never silently wait on a+  screen they aren't watching.+ ## 1.6.10 - 2026-07-03  - **"Fusion not installed" hints now honor the SDK Tier-2 cardinal rule (found on a fresh-AD test).**
SKILL.md+1−1
@@ -35,7 +35,7 @@ Branch on the stable `errorCode`, never the prose: 1. **Poll readiness, don't launch blindly.** `fusion_readiness` (or AD's `bridge_readiness`) is read-only — it reports `installed`/`running`/`ready`/`addinStale` WITHOUT launching anything. Loop: readiness → act on the row above → drive. 2. **`fusion_readiness` is the standardized cold-start probe.** (Fusion is a detected HOST APP with no heavy download, so there's no `prewarm` step — readiness is the whole gate.) 3. **Core verbs live in the table below; `fusion_describe '{}'` is the full machine-readable catalog.** Read the table to act fast; hit `describe` for completeness — don't guess a verb.-4. **Background by default — don't disrupt the user.** This bridge drives the AI's workspace, not the user's screen. Dismiss dialogs in the BACKGROUND (`fusion_close_window`, never `fusion_send_key`/Escape, which steals focus); only foreground to SHOW the user something. See [fusion-driving](skills/fusion-driving/SKILL.md).+4. **Background by default — but NOTIFY on every active step.** This bridge drives the AI's workspace, not the user's screen: dismiss dialogs in the BACKGROUND (`fusion_close_window`, never `fusion_send_key`/Escape, which steals focus). **The instant the user must DO something you can't (Autodesk sign-in, 2FA, a UAC/elevation prompt, accepting a license, a manual choice), fire an AD `notify_user` (a toast, and a progress toast for long installs) so they're pulled in — never silently wait on a screen they aren't looking at.** Only foreground Fusion to SHOW the user something. See [fusion-driving](skills/fusion-driving/SKILL.md) and [fusion-onboarding](skills/fusion-onboarding/SKILL.md). 5. **`ok:true` is not enough — verify.** A long op that "times out" at ~60s is usually STILL RUNNING server-side (the relay caps the request, not the work). Verify by artifacts (the saved file / a screenshot / `fusion_get_app_state`), don't blindly retry. 6. **Reuse the running Fusion, don't relaunch.** Fusion is a singleton — `fusion_readiness` before `fusion_start` (especially after a compaction); if it's already `ready`, just drive. Relaunching churns state. 7. **Surface `_hint` verbatim + branch on `errorCode`.** Every verb returns an actionable `_hint`; relay it to the user unchanged and key your logic off the stable `errorCode`, not the prose.
adom-bridge-fusion-manifest.json+5−5
@@ -1,13 +1,13 @@ {   "manifest_version": 1,   "name": "fusion360",-  "version": "1.6.10",-  "url": "https://wiki.adom.inc/download/adom/adom-desktop-fusion-bridge/1.6.10/adom-bridge-fusion-v1.6.10.zip",-  "sha256": "a70072e14337eeffd759f33dd83cc93ef37a797136ede1145633cb51013fa461",-  "size": 298417,+  "version": "1.6.11",+  "url": "https://wiki.adom.inc/download/adom/adom-desktop-fusion-bridge/1.6.11/adom-bridge-fusion-v1.6.11.zip",+  "sha256": "c9d494cbf710ac86be6bb9bd851fc2cba38ba088d8adf8a910995d50a350aa40",+  "size": 299827,   "verbPrefixes": [     "fusion_"   ],   "healthEndpoint": "/status",-  "released_at": "2026-07-03T15:30:00Z"+  "released_at": "2026-07-03T16:15:00Z" }\ No newline at end of file
bridge.json+4−2
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "fusion360",   "displayName": "Autodesk Fusion 360",-  "version": "1.6.10",+  "version": "1.6.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/adom-desktop-fusion-bridge",   "author": "Adom Inc.",@@ -112,7 +112,9 @@     "hostApp": "Fusion 360",     "paths": {       "windows": [-        "%LOCALAPPDATA%\\Autodesk\\webdeploy\\production\\*\\FusionLauncher.exe"+        "%LOCALAPPDATA%\\Autodesk\\webdeploy\\production\\*\\FusionLauncher.exe",+        "%ProgramFiles%\\Autodesk\\webdeploy\\production\\*\\FusionLauncher.exe",+        "%ProgramFiles(x86)%\\Autodesk\\webdeploy\\production\\*\\FusionLauncher.exe"       ],       "macos": [         "/Applications/Autodesk Fusion.app",
fusion_detect.py+43−21
@@ -13,8 +13,23 @@ from pathlib import Path ADDIN_PORT = 8774  # Fusion 360 uses a web-deploy model — the launcher lives under-# %LOCALAPPDATA%\Autodesk\webdeploy\production\<hash>\FusionLauncher.exe-WEBDEPLOY_BASE = Path(os.environ.get("LOCALAPPDATA", "")) / "Autodesk" / "webdeploy" / "production"+#   <base>\Autodesk\webdeploy\production\<hash>\FusionLauncher.exe+# where <base> is %LOCALAPPDATA% for a per-user install OR %ProgramFiles%+# (/%ProgramFiles(x86)%/%ProgramW6432%) for a SYSTEM-WIDE `--globalinstall` -+# which is exactly what the fusion-onboarding skill runs. We MUST check both, or+# an AI-installed (globalinstall) Fusion is invisible and onboarding "succeeds"+# yet the bridge still reports not-installed. (Found on the ADOMBASELINE test.)+_WEBDEPLOY_BASES = []+for _var in ("LOCALAPPDATA", "ProgramFiles", "ProgramFiles(x86)", "ProgramW6432"):+    _root = os.environ.get(_var)+    if _root:+        _base = Path(_root) / "Autodesk" / "webdeploy" / "production"+        if _base not in _WEBDEPLOY_BASES:+            _WEBDEPLOY_BASES.append(_base)+# Back-compat alias (some callers import WEBDEPLOY_BASE directly).+WEBDEPLOY_BASE = _WEBDEPLOY_BASES[0] if _WEBDEPLOY_BASES else (+    Path(os.environ.get("LOCALAPPDATA", "")) / "Autodesk" / "webdeploy" / "production"+)  # Add-ins can live in either of these directories (varies by Fusion version) ADDINS_DIR_CANDIDATES = [@@ -59,29 +74,36 @@ def detect_fusion() -> dict:   def _find_fusion_launcher() -> Path | None:-    """Find FusionLauncher.exe under the webdeploy production directory.+    """Find the newest FusionLauncher.exe across ALL webdeploy bases. -    Scans subdirectories sorted by modification time (newest first).+    Checks the per-user (%LOCALAPPDATA%) AND the system-wide (%ProgramFiles%,+    from `--globalinstall`) locations. Prefers a COMPLETE install (one that also+    has FusionLauncher.exe.ini) and, among those, the newest by mtime.     """-    if not WEBDEPLOY_BASE.exists():-        return None+    candidates = []  # (has_ini, mtime, launcher_path)+    for base in _WEBDEPLOY_BASES:+        if not base.exists():+            continue+        try:+            subdirs = [d for d in base.iterdir() if d.is_dir()]+        except OSError:+            continue+        for subdir in subdirs:+            launcher = subdir / "FusionLauncher.exe"+            if not launcher.exists():+                continue+            has_ini = (subdir / "FusionLauncher.exe.ini").exists()+            try:+                mtime = subdir.stat().st_mtime+            except OSError:+                mtime = 0.0+            candidates.append((has_ini, mtime, launcher)) -    try:-        subdirs = sorted(-            [d for d in WEBDEPLOY_BASE.iterdir() if d.is_dir()],-            key=lambda d: d.stat().st_mtime,-            reverse=True,-        )-    except OSError:+    if not candidates:         return None--    for subdir in subdirs:-        launcher = subdir / "FusionLauncher.exe"-        ini_file = subdir / "FusionLauncher.exe.ini"-        if launcher.exists() and ini_file.exists():-            return launcher--    return None+    # Complete installs (has_ini) win; newest mtime breaks ties.+    candidates.sort(key=lambda c: (c[0], c[1]), reverse=True)+    return candidates[0][2]   def _find_addins_dir() -> Path | None:
page.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "adom-desktop-fusion-bridge",-  "version": "1.6.11",+  "version": "1.6.12",   "type": "app",   "description": "Drive Autodesk Fusion 360 from the cloud via Adom Desktop: 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 with browse/recent/versions, cloud download/upload and folder creation, and in-app parametric modeling. Never-charge: APS calls are capped to the free tier.",   "dependencies": {},
skills/fusion-onboarding/SKILL.md+8
@@ -57,6 +57,14 @@ shell_execute {"command":"curl -L -o C:\\tmp\\FusionDL.exe \"https://dl.appstrea account** (free) — and Fusion offers a **free trial / personal-use** tier that's enough for viewing and a lot of work. Don't auto-enter their password; do drive the OTP/forms. +> **NOTIFY the user the moment login is needed.** The sign-in (and any 2FA/password step you must+> not auto-fill) is an ACTIVE step only they can do. Fire an AD **`notify_user`** toast ("Fusion is+> installed and open - it needs your Autodesk sign-in to continue") the instant the login screen is+> up, so they act instead of you silently waiting on a screen they aren't watching. Same for the+> `--globalinstall` UAC/elevation prompt (Step 2) and license acceptance. Long installs: use a+> **progress** toast. This is the general rule (see the USER skill's convention 4): notify on EVERY+> step that needs the user.+ ## Step 4 — Complete the circuit: auto-install the AdomBridge add-in This is what lets the bridge inject commands into Fusion after launch. - **The bridge does this for you:** on first dispatch, `server.py` auto-runs `install_addin` if