← Commit history

v1.6.76: hard-disable crashing in-app cloud search, APS readiness guard + rich hints, ABE sign-in skill

John Lauer ·865bd9295a ·3mo ago ·parent afed8e1
7 files changed +170−20
BRIDGE_VERSION+1−1
@@ -1 +1 @@-1.6.75\ No newline at end of file+1.6.76
adom-bridge-fusion-manifest.json+5−5
@@ -1,13 +1,13 @@ {   "manifest_version": 1,   "name": "fusion360",-  "version": "1.6.75",-  "url": "https://wiki.adom.inc/download/adom/adom-desktop-fusion-bridge/1.6.75/adom-bridge-fusion-v1.6.75.zip",-  "sha256": "20beea4addf440e2892d30f35bdc9b15072b0e27c617ca5d5bd3b337e2d70bbc",-  "size": 379941,+  "version": "1.6.76",+  "url": "https://wiki.adom.inc/download/adom/adom-desktop-fusion-bridge/1.6.76/adom-bridge-fusion-v1.6.76.zip",+  "sha256": "85728d1dd5098d66a6b60e9b03787bd4bfc1063174922695ce2c85b8e44ab173",+  "size": 15238076,   "verbPrefixes": [     "fusion_"   ],   "healthEndpoint": "/status",-  "released_at": "2026-07-07T16:20:00Z"+  "released_at": "2026-07-16T12:05:26Z" }\ No newline at end of file
bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "fusion360",   "displayName": "Autodesk Fusion 360",-  "version": "1.6.75",+  "version": "1.6.76",   "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.",
describe.py+4−4
@@ -76,10 +76,10 @@ _T = [      {"projectId": "required str", "parentFolderId": "required str", "name": "required str"}, {"folderId": "str"}, 50, None, False, {"projectId": "a.YnVz...", "parentFolderId": "urn:...", "name": "Adom AI Workspace"}),     ("fusion_aps_get", "Raw authenticated GET against a free APS path (dev/verify helper).",      {"path": "required str"}, {"status": "int", "body": "obj"}, 40, None, False, {"path": "/project/v1/hubs"}),-    ("fusion_walk_cloud_tree", "DO NOT USE: slow in-app add-in walk (30+ min) that CAN CRASH Fusion (WinError 10054). Use fusion_aps_search instead; see the 'fusion-aps-search' skill.",-     {}, {"tree": "obj"}, 600, _STATUS, True, {}),-    ("fusion_search_cloud_files", "DO NOT USE: slow in-app add-in search (30+ min) that CAN CRASH Fusion (WinError 10054). Use fusion_aps_search instead; see the 'fusion-aps-search' skill.",-     {"query": "required str"}, {"results": "[...]"}, 180, _STATUS, True, {"query": "Molecule"}),+    ("fusion_walk_cloud_tree", "⛔ DISABLED (returns an error): the in-app add-in walk took 30+ min and CRASHED Fusion (WinError 10054). It is hard-blocked in the bridge. Use fusion_aps_search / fusion_aps_open. See the 'fusion-aps-search' skill.",+     {}, {"disabled": "bool"}, 15, None, False, {}),+    ("fusion_search_cloud_files", "⛔ DISABLED (returns an error): the in-app add-in search took 30+ min and CRASHED Fusion (WinError 10054). It is hard-blocked in the bridge. Use fusion_aps_search {query} — server-indexed, seconds, no Fusion. See the 'fusion-aps-search' skill.",+     {"query": "required str"}, {"disabled": "bool"}, 15, None, False, {"query": "Molecule"}),      # ── Electronics ────────────────────────────────────────────────────────     ("fusion_show_schematic", "Switch the OPEN electronics design to its SCHEMATIC view (the symmetric partner of fusion_show_2d_board / fusion_show_3d_board, via Fusion's SwitchSchDocCmd). A VIEW of the project, not a standalone file. Drive it for demos with fusion_electron_zoom / _pan / _select.",
server.py+103−9
@@ -1560,6 +1560,94 @@ def _handle_get_preferences(fusion_info: dict, args: dict) -> dict:     return _shape_pref_result(res, wrote=False)  +# ── APS state + AI hint builder ───────────────────────────────────────────────+# Every cloud-file path routes through APS now (the old in-app search is disabled —+# see _handle_deprecated_cloud_search). This helper reads live APS state and returns+# a rich, self-teaching hint bundle so the AI ALWAYS knows: is APS installed/configured?+# signed in? token live/expired? what the verbs are, that it must sign in, and that the+# best sign-in path is the user's NATIVE Chrome/Edge via ABE (adom-browser-extension).+_APS_VERB_MAP = (+    "fusion_aps_status (state) · fusion_aps_signin (sign in) · fusion_aps_search {query} · "+    "fusion_aps_open {name} · fusion_aps_browse · fusion_aps_recent · fusion_aps_file_info · "+    "fusion_aps_versions · fusion_aps_download · fusion_aps_upload · fusion_aps_create_folder · "+    "fusion_aps_set_browser/get_browser/forget_browser (remember the native browser+profile)"+)+_APS_WHY = (+    "WHY APS: Autodesk offers NO fast file-search API for Fusion. The only in-app option "+    "(walk/search the folder tree from the add-in) takes 30+ min and CAN CRASH Fusion "+    "(WinError 10054). We searched far and wide; APS (Autodesk Platform Services, server-indexed) "+    "is the ONLY thing that works — seconds, no Fusion needed, no crash. It needs a one-time "+    "OAuth sign-in; once set up it is fast and amazing. The old crashing search is now DISABLED."+)+_APS_ABE = (+    "BEST sign-in path: drive the user's OWN Chrome/Edge (already logged into Autodesk) via ABE "+    "(adom-browser-extension). If ABE is not installed, tell the user to install it first "+    "(wiki.adom.inc/adom/adom-browser-extension), then walk them through it. With ABE the bridge "+    "opens the Autodesk auth URL in their real signed-in profile and captures the token — no "+    "password typing. Fallback: fusion_aps_signin {allowDefaultBrowser:true}."+)+++def _aps_state_hint(extra: str = "") -> dict:+    """Live APS readiness + a self-teaching hint bundle for the AI. Never raises."""+    try:+        st = aps.handle_status({})+        d = st.get("data", {}) if isinstance(st, dict) else {}+    except Exception as e:  # pragma: no cover - defensive+        d = {"error": str(e)}+    configured = bool(d.get("configured"))+    signed_in = bool(d.get("signedIn"))+    live = bool(d.get("tokenLive"))+    if not configured:+        stage, todo = "not_configured", ("Register a PKCE app at https://aps.autodesk.com (Data "+                                         "Management API on), then fusion_aps_set_client_id + fusion_aps_signin.")+    elif not signed_in:+        stage, todo = "not_signed_in", "Sign in: fusion_aps_signin (prefer ABE / native browser)."+    elif not live:+        stage, todo = "token_expired", "Token expired/refresh failed — fusion_aps_signin again."+    else:+        stage, todo = "ready", "Ready — fusion_aps_search {\"query\":\"...\"} or fusion_aps_open {\"name\":\"...\"}."+    parts = [f"APS {stage}.", todo, "VERBS: " + _APS_VERB_MAP, _APS_ABE, _APS_WHY]+    if extra:+        parts.insert(0, extra)+    return {+        "apsStage": stage, "apsConfigured": configured, "apsSignedIn": signed_in,+        "apsTokenLive": live, "_hint": "  ".join(parts),+    }+++def _aps_guarded(fn, args: dict):+    """Run an APS cloud handler, but FIRST ensure APS is signed-in + token-live. If not,+    short-circuit with the rich self-teaching hint bundle (state + verbs + sign-in + ABE)+    so the AI knows exactly what to do instead of getting an opaque auth failure. This is+    the 'check every time, in code' guard the user asked for."""+    state = _aps_state_hint()+    if state["apsStage"] != "ready":+        return {+            "success": False,+            "error": f"APS is {state['apsStage']} — sign in before cloud file operations.",+            "output": state["apsStage"],+            "data": {"apsNotReady": True, **state},+            "_hint": state["_hint"],+        }+    return fn(args)+++def _handle_deprecated_cloud_search(command: str, args: dict) -> dict:+    """HARD-BLOCK the old in-app cloud search/walk (crashes Fusion). Redirect to APS,+    surfacing live APS state so the AI can immediately continue via the good path."""+    aps_state = _aps_state_hint()+    return {+        "success": False,+        "error": (f"fusion_{command} is DISABLED: the in-app Fusion cloud "+                  "search/walk takes 30+ min and CAN CRASH Fusion (WinError 10054). "+                  "Use fusion_aps_search {\"query\":\"...\"} (or fusion_aps_open to open by name) instead."),+        "output": "deprecated_cloud_search_disabled",+        "data": {"disabled": True, "use": "fusion_aps_search", **aps_state},+        "_hint": aps_state["_hint"],+    }++ COMMAND_HANDLERS = {     "describe": lambda fi, args: describe.handle_describe(args),     "readiness": _handle_fusion_readiness,@@ -1610,16 +1698,22 @@ COMMAND_HANDLERS = {     "aps_set_browser": lambda fi, args: aps.handle_set_browser(args),     "aps_get_browser": lambda fi, args: aps.handle_get_browser(args),     "aps_forget_browser": lambda fi, args: aps.handle_forget_browser(args),-    "aps_search": lambda fi, args: aps.handle_search(args),-    "aps_browse": lambda fi, args: aps.handle_browse(args),-    "aps_recent": lambda fi, args: aps.handle_recent(args),-    "aps_file_info": lambda fi, args: aps.handle_file_info(args),-    "aps_versions": lambda fi, args: aps.handle_versions(args),-    "aps_download": lambda fi, args: aps.handle_download(args),-    "aps_create_folder": lambda fi, args: aps.handle_create_folder(args),-    "aps_upload": lambda fi, args: aps.handle_upload(args),-    "aps_open": lambda fi, args: _handle_aps_open(fi, args),+    # Cloud-data verbs go through _aps_guarded: it checks signed-in + token-live EVERY call+    # and returns the rich APS hint bundle (state/verbs/sign-in/ABE) if not ready.+    "aps_search": lambda fi, args: _aps_guarded(aps.handle_search, args),+    "aps_browse": lambda fi, args: _aps_guarded(aps.handle_browse, args),+    "aps_recent": lambda fi, args: _aps_guarded(aps.handle_recent, args),+    "aps_file_info": lambda fi, args: _aps_guarded(aps.handle_file_info, args),+    "aps_versions": lambda fi, args: _aps_guarded(aps.handle_versions, args),+    "aps_download": lambda fi, args: _aps_guarded(aps.handle_download, args),+    "aps_create_folder": lambda fi, args: _aps_guarded(aps.handle_create_folder, args),+    "aps_upload": lambda fi, args: _aps_guarded(aps.handle_upload, args),+    "aps_open": lambda fi, args: _aps_guarded(lambda a: _handle_aps_open(fi, a), args),     "aps_get": lambda fi, args: aps.handle_get(args),+    # DEPRECATED cloud search — HARD-BLOCKED here (in COMMAND_HANDLERS) so they return+    # BEFORE ever reaching the crashing add-in path. Redirect to APS + surface APS state.+    "search_cloud_files": lambda fi, args: _handle_deprecated_cloud_search("search_cloud_files", args),+    "walk_cloud_tree": lambda fi, args: _handle_deprecated_cloud_search("walk_cloud_tree", args), }  
skills/fusion-aps-search/SKILL.md+25
@@ -116,3 +116,28 @@ for cloud search, ever — no matter how blocked you feel. 3. **AUTH-001 "client_id does not have access to the api product":** the APS app at    aps.autodesk.com/myapps lost its **Data Management API** product. Open the app → API Access → ensure    Data Management API is checked → **Save changes** → wait a few minutes to propagate → retry.++## UPDATE (John, 2026-07-16): the old in-app search is now HARD-DISABLED in code++`fusion_search_cloud_files` and `fusion_walk_cloud_tree` no longer run. The bridge intercepts+them in `COMMAND_HANDLERS` (`_handle_deprecated_cloud_search`) and returns an error that+redirects to `fusion_aps_search`, together with live APS state. They can NO LONGER crash Fusion,+because they never reach the add-in. Do not try to "fall back" to them: there is nothing to fall+back to. APS is the only cloud-search path.++## Auto-guard: APS readiness is checked in CODE on every cloud call++Every cloud-data verb (`aps_search/open/browse/recent/file_info/versions/download/upload/+create_folder`) is wrapped by `_aps_guarded` in server.py. It checks signed-in + token-live+BEFORE the call and, if not ready, returns the rich hint bundle from `_aps_state_hint`+(stage + verb map + sign-in instruction + the ABE native-browser suggestion + WHY-APS). So the+AI never gets an opaque auth failure — it always gets the next step. Surface that `_hint` to the+user verbatim.++## Apologize, then reassure (the honest framing for the user)++If a user hits the one-time APS setup, be honest: "Autodesk offers NO fast file-search API for+Fusion. The only in-app option walks the folder tree and takes 30+ minutes and can crash Fusion.+We searched far and wide; APS (server-indexed) is the only thing Autodesk offers that actually+works. Sorry it needs a one-time sign-in, but once it's set up it's fast and genuinely great."+Then get them set up (prefer ABE native-browser sign-in, see fusion-aps-signin).
skills/fusion-aps-signin/SKILL.md+31
@@ -271,3 +271,34 @@ portal is fragile and Edge crashes):**    and the bridge's listener captures the token. 5. Poll `fusion_aps_status` until `signedIn:true`. Done — APS search is fast and never touches Fusion's    main thread.++## The BEST sign-in path: the user's NATIVE Chrome/Edge via ABE (adom-browser-extension)++Autodesk's OTP/2FA and its "which profile is signed in" problem vanish if we drive the user's+OWN browser that is ALREADY logged into Autodesk. That is what ABE (adom-browser-extension) is+for: it exposes `nbrowser_*` verbs that open a URL in the user's real Chrome/Edge profile.++**Recommend ABE first, and hand-hold the install if it's missing:**+1. Check: does `adom-desktop --target <laptop> nbrowser_readiness '{}'` succeed? If not, ABE isn't+   installed.+2. Tell the user (honestly): "The smoothest Autodesk sign-in drives your own Chrome/Edge that's+   already logged in, no password typing, no OTP races. That needs the Adom Browser Extension+   (ABE). Let me walk you through installing it, one time."+3. Point them to the install: https://wiki.adom.inc/adom/adom-browser-extension and follow the+   `installing-the-extension` steps (load the MV3 extension, approve the native-host). Do as much+   as you can drive for them; only ask for the clicks Chrome forces a human to make.+4. Once ABE is live: `fusion_aps_signin` returns `needsExtensionOpen` with an `authUrl`; open it+   via `nbrowser_open_window` in their signed-in profile; the bridge's localhost listener captures+   the token; poll `fusion_aps_status` until `signedIn:true`. Then `fusion_aps_set_browser {how:+   "extension"}` so every future sign-in reuses that exact profile.++Fallback only if ABE truly can't be installed: `fusion_aps_signin {allowDefaultBrowser:true}`+(OS default browser) and drive the OTP per this skill.++## Say the honest WHY (apologize, then reassure)++Autodesk gives no fast Fusion file-search API; the only in-app option takes 30+ minutes and can+crash Fusion, so it's now disabled. APS (server-indexed) is the one thing that works. The cost is+a one-time OAuth sign-in. Tell the user that plainly, apologize for the friction, and reassure+them: once it's set up, cloud search is instant and it stays signed in (auto-refresh). It is+worth it.