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
v1.6.65: FIX ad_client capabilities() for current AD /commands shape (verbs in topLevel/bridges/cliRequired/desktop, no 'commands' key) - the REAL reason available() was always False and every bridge silently fell back to CLI relays. Plus discovery retries instead of caching a transient miss.
4 files changed
+55−24
BRIDGE_VERSION+1−1@@ -1 +1 @@-1.6.64+1.6.65
ad_client.py+49−18@@ -66,9 +66,8 @@ def _discover_direct_api(): ports adom-desktop.exe is LISTENING on and probe each `/commands`; the one that returns AD's verb catalog is the direct API. Cached for the process lifetime. Windows-only + best-effort; never raises.""" global _discovered_base- if _discovered_base is not None:- return _discovered_base or None- _discovered_base = "" # default: tried and failed (so we don't re-probe every call)+ if _discovered_base: # cache SUCCESS only; a transient miss must not stick forever+ return _discovered_base try: import subprocess as _sp, re as _re cnw = getattr(_sp, "CREATE_NO_WINDOW", 0)@@ -144,29 +143,61 @@ def available() -> bool: return capabilities() is not None -def capabilities():- """Set of AD command names from `GET /commands` (cached). None if unreachable.+def _names_from_list(items):+ """Collect verb names from a list of strings and/or {name|command|verb} dicts."""+ out = set()+ for it in items or []:+ if isinstance(it, str):+ out.add(it)+ elif isinstance(it, dict):+ n = it.get("name") or it.get("command") or it.get("verb")+ if n:+ out.add(n)+ return out - Shape-tolerant: accepts {"commands":[...]}, {"commands":[{"name":..}]}, or a- bare list of names/objects.- """++def _parse_command_names(data):+ """Extract the full verb-name set from a /commands response, tolerant of BOTH the legacy+ `{"commands":[...]}` shape AND the current AD (1.9.x) shape, where verbs are split across:+ topLevel: ["notify_user", "targets", ...] (flat name list)+ cliRequired: ["pull_file", "shell_execute", ...] (flat name list)+ bridges: [{name, verbs:[...]}, ...] (per-bridge verb lists)+ desktop: {commands:["screenshot_window", ...]} (SHORT names; real verb = "desktop_"+name)+ Without this, capabilities() returned None on every current AD, so available() was always False+ and the bridge silently fell back to slow CLI relays (root-caused live, John 2026-07-14)."""+ names = set()+ if isinstance(data, list):+ return _names_from_list(data)+ if not isinstance(data, dict):+ return names+ if isinstance(data.get("commands"), list): # legacy shape+ names |= _names_from_list(data["commands"])+ for k in ("topLevel", "cliRequired"): # current: flat name lists+ if isinstance(data.get(k), list):+ names |= _names_from_list(data[k])+ for b in (data.get("bridges") or []): # current: per-bridge verb lists+ if isinstance(b, dict):+ names |= _names_from_list(b.get("verbs"))+ dk = data.get("desktop") # current: desktop short names -> desktop_*+ if isinstance(dk, dict):+ for c in (dk.get("commands") or []):+ if isinstance(c, str):+ names.add(c)+ names.add("desktop_" + c)+ return names+++def capabilities():+ """Set of AD command names from `GET /commands` (cached). None if unreachable/unparseable.""" global _caps_cache if _caps_cache is not None: return _caps_cache data = _http("GET", "/commands") if data is None: return None- items = data.get("commands") if isinstance(data, dict) else data- if not isinstance(items, list):+ names = _parse_command_names(data)+ if not names: return None- names = set()- for it in items:- if isinstance(it, str):- names.add(it)- elif isinstance(it, dict):- n = it.get("name") or it.get("command") or it.get("verb")- if n:- names.add(n) _caps_cache = names return names
adom-bridge-fusion-manifest.json+4−4@@ -1,10 +1,10 @@ { "manifest_version": 1, "name": "fusion360",- "version": "1.6.64",- "url": "https://wiki.adom.inc/download/adom/adom-desktop-fusion-bridge/1.6.64/adom-bridge-fusion-v1.6.64.zip",- "sha256": "98761caabf5b6a40e68b9cfd11b61ab08ed741a22d148505b45c07f4a711c539",- "size": 359076,+ "version": "1.6.65",+ "url": "https://wiki.adom.inc/download/adom/adom-desktop-fusion-bridge/1.6.65/adom-bridge-fusion-v1.6.65.zip",+ "sha256": "c8b457a911913e54afa2679cddc4e321129fa3aec02bbaffb6aab1bc5876f445",+ "size": 359576, "verbPrefixes": [ "fusion_" ],
bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "fusion360", "displayName": "Autodesk Fusion 360",- "version": "1.6.64",+ "version": "1.6.65", "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.",