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 6 file(s)
6 files changed
+52−17
BRIDGE_VERSION+1−1@@ -1 +1 @@-1.9.120+1.9.121
adom-bridge-fusion-manifest.json+4−4@@ -1,10 +1,10 @@ { "manifest_version": 1, "name": "fusion360",- "version": "1.9.120",- "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.135/adom-bridge-fusion-v1.9.120.zip",- "sha256": "f5afdcbab0498fc627f1cbb47a2838230822a52dadd1ce66ffa866cd4e012830",- "size": 455871,+ "version": "1.9.121",+ "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.136/adom-bridge-fusion-v1.9.121.zip",+ "sha256": "eec4f3ba279d3dd1a6aa349b3df8c8d459541fbe4d7e3a8f7081b19ea819fd3b",+ "size": 456629, "verbPrefixes": [ "fusion_" ],
bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "fusion360", "displayName": "Autodesk Fusion 360",- "version": "1.9.120",+ "version": "1.9.121", "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.",
package.json+1−1@@ -1,6 +1,6 @@ { "slug": "fusion-bridge",- "version": "1.9.135",+ "version": "1.9.136", "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+10−7@@ -1,6 +1,6 @@ { "slug": "fusion-bridge",- "version": "1.9.135",+ "version": "1.9.136", "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",@@ -70,7 +74,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.",@@ -99,9 +106,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+35−3@@ -7036,8 +7036,26 @@ def _show_library_view(name, suffix, lbr_path=None): _pending = [d for d in (classify_blocking_dialogs() or []) if d.get("category") == "create_confirm"] if _pending:+ # A create_confirm on screen is not automatically OURS (run 7d4427d443f5: a+ # footprint EDIT whose name WAS in the library got failed because a stale+ # Create-new prompt from an earlier interaction was still standing). Read the+ # dialog's own text: only a prompt that names THIS artifact fails THIS call.+ # Foreign/stale prompts are still declined (never left blocking the main+ # thread), but the EDIT's own outcome decides the result.+ _about_this = False for _d in _pending:+ try:+ from handlers.dialog_classify import _dialog_text as _dtxt+ _body = "%s %s" % (_dtxt(_d.get("hwnd")) or "", _d.get("title") or "")+ except Exception:+ _body = _d.get("title") or ""+ if str(name).lower() in _body.lower():+ _about_this = True _unwrap(_ad_call("desktop_ui_click", {"hwnd": _d.get("hwnd"), "name": "No"}, timeout=12))+ if not _about_this:+ print("[Fusion Bridge] declined a STALE Create-new prompt that does not mention "+ "%r - clearing it and trusting the EDIT's own result" % name)+ if _pending and _about_this: print("[Fusion Bridge] declined a Create-new prompt for %r - the name is not in the " "library (answering Yes would fabricate an empty artifact)" % name) return {@@ -9270,13 +9288,19 @@ def _handle_prove_library(fusion_info: dict, args: dict) -> dict: # Create3DPackage opens the empty Package3D GENERATOR for an already-bound library - # bodies=0, a frame of nothing). The evidence is the f3d the package3d urn points # at: open THAT document, which loads the real geometry the Library Manager shows.+ # THE URN LIVES IN wip_urn, NOT urn (run 7d4427d443f5): this bridge's own bind+ # writes `<package3d urn="" wip_urn="urn:adsk.wipprod:fs.file:vf...">` - urn stays+ # empty by the EAGLE-XML convention used everywhere else in this file. Reading only+ # `urn` made a bound library look unopenable ("no urn"). A caller (the create_library+ # chain) can also hand the bind result's urn straight in as f3dUrn. _p3d_urn = "" try: import xml.etree.ElementTree as _ET3 for _p3 in _ET3.parse(lbr).getroot().iter("package3d"):- _p3d_urn = (_p3.get("urn") or "").strip() or _p3d_urn+ _p3d_urn = (_p3.get("urn") or _p3.get("wip_urn") or "").strip() or _p3d_urn except Exception: pass+ _p3d_urn = _p3d_urn or (args.get("f3dUrn") or "").strip() opened3d = None if _p3d_urn: opened3d = dispatch_command("open_by_urn", {"urn": _p3d_urn})@@ -9339,6 +9363,11 @@ def _handle_prove_library(fusion_info: dict, args: dict) -> dict: except Exception as _e: missing.append("thumbnail(check-failed)") captured = [e for e in evidence if e.get("ok") and e.get("screenshot")]+ # A failed FRAME belongs in `missing` too (run 7d4427d443f5 read "missing=[]" while+ # 2 of 4 frames had failed - the reader should never have to diff the evidence list+ # to learn what is absent).+ missing += ["frame:%s(%s)" % (e.get("step"), str(e.get("error"))[:60])+ for e in evidence if not (e.get("ok") and e.get("screenshot"))] proven = (not missing) and len(captured) == 4 out = {"success": proven, "proven": proven, "libraryPath": lbr, "deviceset": want, "artifacts": artifacts, "missing": missing,@@ -9750,8 +9779,11 @@ def _handle_create_library(fusion_info: dict, args: dict) -> dict: state.update(stage="failed", success=False); _save(); return _leave("bind") _enter("proving (four evidence frames)")- prove = _handle_prove_library(fusion_info, {"libraryPath": target_lbr,- "name": args.get("name")})+ prove = _handle_prove_library(fusion_info, {+ "libraryPath": target_lbr, "name": args.get("name"),+ # the bind just told us exactly which f3d holds the geometry - hand it on so+ # the 3D frame never depends on re-parsing the lbr for it+ "f3dUrn": ((state.get("bind") or {}).get("wip_urn") or "")}) _leave("prove") state.update(stage="done", success=bool(prove.get("proven")), prove=prove) _save()