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
Update 102 file(s)
9 files changed
+53−39
BRIDGE_VERSION+1−1@@ -1 +1 @@-1.9.290+1.9.291
adom-bridge-fusion-manifest.json+4−4@@ -1,10 +1,10 @@ { "manifest_version": 1, "name": "fusion360",- "version": "1.9.290",- "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.290/adom-bridge-fusion-v1.9.290.zip",- "sha256": "6e1c5a0467c57780f126fdd7c5922f0977bf01ee53d5a13143a3c934b9cd4ae3",- "size": 582215,+ "version": "1.9.291",+ "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.291/adom-bridge-fusion-v1.9.291.zip",+ "sha256": "bb993d6eda42ee5503ad78ab154877ca6f75af8ca364264c57267c43bb4d3a24",+ "size": 582406, "verbPrefixes": [ "fusion_" ],
bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "fusion360", "displayName": "Autodesk Fusion 360",- "version": "1.9.290",+ "version": "1.9.291", "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/fusion-bridge", "author": "Adom Inc.",
dashboard/Cargo.lock+1−1@@ -4,7 +4,7 @@ version = 4 [[package]] name = "fusion-dashboard"-version = "1.9.290"+version = "1.9.291" dependencies = [ "serde_json", ]
dashboard/Cargo.toml+1−1@@ -1,6 +1,6 @@ [package] name = "fusion-dashboard"-version = "1.9.290"+version = "1.9.291" edition = "2021" [dependencies]
install.sh+1−1@@ -21,7 +21,7 @@ echo "Installed fusion-bridge skills: $(ls "$PKG_DIR/skills" 2>/dev/null | tr '\ # binary (the three-artifact pattern: bridge zip -> ab, THIS pkg -> container skills + # this download, page media -> wiki). Per the wiki's PKG_VS_RELEASE policy, binaries are # platform-tagged RELEASE assets, never tarball content - the installer fetches them.-DASH_VERSION="1.9.290"+DASH_VERSION="1.9.291" DASH_URL="https://wiki.adom.inc/download/adom/fusion-bridge/${DASH_VERSION}/fusion-dashboard" DEST="" if [ -w /usr/local/bin ]; then DEST=/usr/local/bin
package.json+1−1@@ -1,6 +1,6 @@ { "slug": "fusion-bridge",- "version": "1.9.290",+ "version": "1.9.291", "type": "app", "description": "This package installs the bridge's SKILLS into your container so your AI knows how to drive it; Adom Bridge loads the bridge runtime itself from the release zip.", "dependencies": {
page.json+11−8@@ -1,6 +1,6 @@ { "slug": "fusion-bridge",- "version": "1.9.290",+ "version": "1.9.291", "type": "app", "description": "This package installs the bridge's SKILLS into your container so your AI knows how to drive it; Adom Bridge loads the bridge runtime itself from the release zip.", "dependencies": {@@ -11,6 +11,10 @@ "uninstall": "./uninstall.sh" }, "tags": [+ "ab",+ "bridge",+ "fusion",+ "desktop-app", "fusion360", "autodesk", "cad",@@ -75,7 +79,10 @@ "build a basic parts library", "add a 3d model to a component", "make a fusion 360 library with 3d",- "set up the fusion bridge"+ "set up the fusion bridge",+ "fusion dashboard",+ "fusion status page",+ "open the fusion launch page" ], "discovery_pitch": "Use the Adom Bridge Fusion 360 bridge when the user wants to DRIVE Autodesk Fusion 360 from the cloud: open/search their team's Fusion cloud designs, lay out a PCB or do electronics, export STEP/IGES/STL/Gerbers/BOM, or build a component library with real rendering 3D. It runs Fusion on the user's own machine via Adom Bridge. NOT for web/browser/login/form-filling (that's the native-browser extension) and NOT for KiCad (that's the kicad bridge).", "brief": "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.",@@ -104,9 +111,5 @@ "label": "Part volume", "prompt": "How much material does each printed part in this assembly use?" }- ],- "author": {- "name": "John Lauer",- "email": "[email protected]"- }-}+ ]+}
server.py+32−21@@ -3841,23 +3841,24 @@ def _orchestrate_attach_3d_package(args: dict) -> dict: "def _layer(n):\n" " n=(n or '').split(':')[0]\n" " return n.startswith('Adom.') and n in LAYERS_OFF\n"- "def _walk(comp, under):\n"+ "def _walk(comp, group, hide):\n" " for i in range(comp.bRepBodies.count):\n"- " b=comp.bRepBodies.item(i); names.append((under or '')+'/'+b.name)\n"- " if under or _layer(b.name):\n"+ " b=comp.bRepBodies.item(i); names.append((group or '')+'/'+b.name)\n"+ " if hide or _layer(b.name):\n" " try:\n"- " b.isLightBulbOn=False; hidden.append((under or '')+'/'+b.name)\n"+ " b.isLightBulbOn=False; hidden.append((group or '')+'/'+b.name)\n" " except Exception: pass\n" " for j in range(comp.occurrences.count):\n"- " o=comp.occurrences.item(j); on=(o.component.name or o.name)\n"- " lay=under or (on if _layer(on) else '')\n"- " if lay and not under:\n"+ " o=comp.occurrences.item(j); on=(o.component.name or o.name).split(':')[0]\n"+ " g=group or (on if on.startswith('Adom.') else '')\n"+ " h=hide or _layer(on)\n"+ " if h and not hide:\n" " try: o.isLightBulbOn=False\n" " except Exception: pass\n"- " _walk(o.component, lay)\n"+ " _walk(o.component, g, h)\n" f"LAYERS_OFF=set({sorted(set(str(x) for x in (args.get('layersOff') or [])))!r})\n" "try:\n"- " _walk(oc.component, '')\n"+ " _walk(oc.component, '', False)\n" "except Exception as _e:\n" " res['layersError']=str(_e)[:120]\n" "res['bodies']=names; res['layersHidden']=hidden\n"@@ -4233,10 +4234,19 @@ def _orchestrate_make_3d_package(args: dict) -> dict: # activeProject is None on a fresh box until the user touches the data panel, so fall # back to the default upload project by id, then by name 'Main' (mirrors the add-in's # _resolve_project; hub->project listing only, never a recursive file walk).+ # The folder listing can be stale right after a failed run created the folder: add()+ # then fails CB_NAE ("another object with the same name already exists") even though+ # the scan missed it (LAN7800 variant runs, 2026-08-30). Re-scan before giving up. "def _sub(p,nm):\n"- " for i in range(p.dataFolders.count):\n"- " if p.dataFolders.item(i).name==nm: return p.dataFolders.item(i)\n"- " return p.dataFolders.add(nm)\n"+ " import time as _ts\n"+ " for _try in range(4):\n"+ " for i in range(p.dataFolders.count):\n"+ " if p.dataFolders.item(i).name==nm: return p.dataFolders.item(i)\n"+ " try: return p.dataFolders.add(nm)\n"+ " except Exception as _fe:\n"+ " if 'CB_NAE' not in str(_fe) and 'same name' not in str(_fe): raise\n"+ " adsk.doEvents(); _ts.sleep(2.0)\n"+ " raise RuntimeError('cloud folder %s exists but cannot be resolved' % nm)\n" "res={}\n" # Optional layer bodies (Adom.HeatsinkVias, Adom.SolderBalls, Adom.LaserEtch) arrive # visible; switch them off so the user opts in from Fusion's Browser (John, 2026-08-30).@@ -4251,23 +4261,24 @@ def _orchestrate_make_3d_package(args: dict) -> dict: "def _layer(n):\n" " n=(n or '').split(':')[0]\n" " return n.startswith('Adom.') and n in LAYERS_OFF\n"- "def _walk(comp, under):\n"+ "def _walk(comp, group, hide):\n" " for i in range(comp.bRepBodies.count):\n"- " b=comp.bRepBodies.item(i); names.append((under or '')+'/'+b.name)\n"- " if under or _layer(b.name):\n"+ " b=comp.bRepBodies.item(i); names.append((group or '')+'/'+b.name)\n"+ " if hide or _layer(b.name):\n" " try:\n"- " b.isLightBulbOn=False; hidden.append((under or '')+'/'+b.name)\n"+ " b.isLightBulbOn=False; hidden.append((group or '')+'/'+b.name)\n" " except Exception: pass\n" " for j in range(comp.occurrences.count):\n"- " o=comp.occurrences.item(j); on=(o.component.name or o.name)\n"- " lay=under or (on if _layer(on) else '')\n"- " if lay and not under:\n"+ " o=comp.occurrences.item(j); on=(o.component.name or o.name).split(':')[0]\n"+ " g=group or (on if on.startswith('Adom.') else '')\n"+ " h=hide or _layer(on)\n"+ " if h and not hide:\n" " try: o.isLightBulbOn=False\n" " except Exception: pass\n"- " _walk(o.component, lay)\n"+ " _walk(o.component, g, h)\n" f"LAYERS_OFF=set({sorted(set(str(x) for x in (args.get('layersOff') or [])))!r})\n" "try:\n"- " _walk(oc.component, '')\n"+ " _walk(oc.component, '', False)\n" "except Exception as _e:\n" " res['layersError']=str(_e)[:120]\n" "res['bodies']=names; res['layersHidden']=hidden\n"