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 7 file(s)
7 files changed
+56−65
BRIDGE_VERSION+1−1@@ -1 +1 @@-1.9.122+1.9.123
adom-bridge-fusion-manifest.json+4−4@@ -1,10 +1,10 @@ { "manifest_version": 1, "name": "fusion360",- "version": "1.9.122",- "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.137/adom-bridge-fusion-v1.9.122.zip",- "sha256": "6c654c30b623b07ed26a5b388d969eebba4180f66bac205c30e467bc7c3a3847",- "size": 458429,+ "version": "1.9.123",+ "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.139/adom-bridge-fusion-v1.9.123.zip",+ "sha256": "32f28501be653cb137b4388718b9bd64bd6da24e8fe979673d124fef6830c61b",+ "size": 458698, "verbPrefixes": [ "fusion_" ],
bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "fusion360", "displayName": "Autodesk Fusion 360",- "version": "1.9.122",+ "version": "1.9.123", "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.",
describe.py+1−1@@ -14,7 +14,7 @@ _STATUS = "fusion_get_app_state" # Compact source table: name -> (summary, input, output, timeout, statusVerb, longRunning, example) _T = [ # ── Lifecycle ──────────────────────────────────────────────────────────- ("fusion_create_library", "ONE-CALL library creation for web-control (one call = one consent). TWO entry shapes: A) {libraryPath, stepPath} - a ready .lbr plus the 3D; B) {kicadSymbolPath, kicadFootprintPath, stepPath, pinMap?} - KiCad sources, converted via adom-lbr (the canonical converter), pinMap = explicit {pinName: padName} for when pin numbers do not match pad names (BGA-style). Chains convert -> bind 3D -> prove (four evidence frames + verdict) in the BACKGROUND and returns immediately; poll fusion_prove_result (stage narrates, prove carries the verdict). stepPath is required for a PROVEN library - no real 3D body without it.", {"libraryPath": "optional str (shape A, or output path for B)", "kicadSymbolPath": "optional str", "kicadFootprintPath": "optional str", "stepPath": "optional str (required for proven)", "pinMap": "optional {pinName: padName}", "name": "optional str"}, {"started": "bool", "statusVerb": "str"}, 30, "fusion_prove_result", True, {"libraryPath": "C:/Temp/PART.lbr", "stepPath": "C:/Temp/PART.step"}),+ ("fusion_create_library", "ONE-CALL library creation for web-control (one call = one consent). TWO entry shapes: A) {libraryPath, stepPath} - a ready .lbr plus the 3D; B) {kicadSymbolPath, kicadFootprintPath, stepPath, pinMap?} - KiCad sources; needs adom-lbr, which is Linux-container-only by platform rule, so on Windows/Mac boxes shape B refuses IMMEDIATELY (adom_lbr_unavailable, before any staging or Fusion launch - fusion_readiness reports kicadIngest up front). Convert at AUTHORING time in a container and use shape A. pinMap = explicit {pinName: padName} for when pin numbers do not match pad names (BGA-style). Chains convert -> bind 3D -> prove (four evidence frames + verdict) in the BACKGROUND and returns immediately; poll fusion_prove_result (stage narrates, prove carries the verdict). stepPath is required for a PROVEN library - no real 3D body without it.", {"libraryPath": "optional str (shape A, or output path for B)", "kicadSymbolPath": "optional str", "kicadFootprintPath": "optional str", "stepPath": "optional str (required for proven)", "pinMap": "optional {pinName: padName}", "name": "optional str"}, {"started": "bool", "statusVerb": "str"}, 30, "fusion_prove_result", True, {"libraryPath": "C:/Temp/PART.lbr", "stepPath": "C:/Temp/PART.step"}), ("fusion_start", "Launch Fusion 360 (if needed) and wait for the AdomBridge add-in to be ready.", {}, {"success": "bool", "addinReady": "bool", "status": "str"}, 150, None, True, {}), ("fusion_stop", "Gracefully STOP Fusion 360: close docs cleanly + WM_CLOSE, then wait. NO force-kill - the clean opposite of fusion_start. If a window will not close it returns failure; use fusion_kill then.",
package.json+1−1@@ -1,6 +1,6 @@ { "slug": "fusion-bridge",- "version": "1.9.138",+ "version": "1.9.139", "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.138",+ "version": "1.9.139", "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+38−50@@ -1749,6 +1749,11 @@ def _handle_fusion_readiness(fusion_info: dict, args: dict) -> dict: "installing": installing, "running": running, "ready": ready,+ # CAPABILITY, knowable before staging a single file (#43 follow-up): shape B of+ # fusion_create_library needs adom-lbr, which is Linux-container-only by platform+ # rule - so on Windows/Mac this is False and the caller should convert at+ # authoring time and send shape A (.lbr + .step).+ "kicadIngest": bool(_find_adom_lbr()), "bridgeVersion": BRIDGE_VERSION, **stale_info, "_hint": (hint + " NOTE: " + result_note) if result_note else hint,@@ -9493,6 +9498,26 @@ COMMAND_HANDLERS["prove_library"] = _handle_prove_library +def _kicad_ingest_unavailable_error() -> dict:+ """The shape-B refusal, shared by import_kicad and the create_library fast-fail.++ Platform rule (John, 2026-08-21): a bridge runs on Windows or Mac; ALL Adom binaries+ are Linux-container-only. So KiCad conversion can never happen on this box, and the+ contract is authoring-time: convert in a container, publish the validated .lbr on the+ part page, hand the bridge shape A (.lbr + .step)."""+ return {"success": False, "errorCode": "adom_lbr_unavailable",+ "kicadIngest": False,+ "error": "adom-lbr (the canonical KiCad->EAGLE converter) does not run on this "+ "platform - Adom binaries are Linux-container-only by design - and this "+ "bridge deliberately does NOT convert KiCad formats itself.",+ "_hint": ("Convert at AUTHORING time, where adom-lbr genuinely runs: in a "+ "container, `adom-lbr generate --sym <.kicad_sym> --fp <.kicad_mod> "+ "-o <out.lbr>` (auto-linted), publish the .lbr on the part page, then "+ "call fusion_create_library shape A {libraryPath, stepPath}. "+ "fusion_readiness reports kicadIngest so this is knowable before "+ "staging files or launching Fusion.")}++ def _find_adom_lbr() -> str: """Locate adom-lbr on THIS box (the canonical KiCad->EAGLE converter, adom/adom-lbr).""" import shutil as _sh@@ -9508,44 +9533,12 @@ def _find_adom_lbr() -> str: -def _install_adom_lbr_windows() -> str:- """SELF-INSTALL adom-lbr on this box (doctrine: never hand the user an install step).-- Probes the wiki for a windows release asset (requested in adom-lbr#6) and caches it- under %LOCALAPPDATA%\\Programs\\adom-lbr. Returns the exe path, or "" while no- windows asset exists yet - at which point the caller's error says conversion is- container-side for now. The moment Ray ships the asset, this verb starts working on- fresh boxes with no code change.- """- import urllib.request as _u- la = os.environ.get("LOCALAPPDATA", "")- if not la:- return ""- dest_dir = os.path.join(la, "Programs", "adom-lbr")- dest = os.path.join(dest_dir, "adom-lbr.exe")- if os.path.exists(dest):- return dest- try:- req = _u.Request("https://wiki.adom.inc/api/v1/pages/adom-lbr/releases")- rels = json.loads(_u.urlopen(req, timeout=15).read()).get("releases") or []- ver = rels[0].get("version") if rels else None- if not ver:- return ""- url = "https://wiki.adom.inc/download/adom/adom-lbr/%s/adom-lbr.exe" % ver- os.makedirs(dest_dir, exist_ok=True)- tmp = dest + ".tmp"- with _u.urlopen(url, timeout=60) as r, open(tmp, "wb") as f:- f.write(r.read())- os.replace(tmp, dest)- print("[Fusion Bridge] self-installed adom-lbr %s -> %s" % (ver, dest))- return dest- except Exception:- try:- os.remove(dest + ".tmp")- except Exception:- pass- return ""-+# _install_adom_lbr_windows was DELETED (2026-08-21). The platform rule it violated:+# a bridge runs on Windows or Mac, and ALL Adom binaries are Linux-container-only by+# deliberate decision - there will never be a windows adom-lbr asset for it to fetch+# (adom-lbr#6 withdrawn, adom-lbr#8 retracted by its own filer). Conversion happens at+# AUTHORING time in a container; the published .lbr is the runtime contract (page+# issue #43, adom-bridge#92). def _apply_pin_map(lbr_path: str, pin_map: dict) -> dict:@@ -9610,18 +9603,7 @@ def _handle_import_kicad(fusion_info: dict, args: dict) -> dict: "error": "Pass kicadSymbolPath and/or kicadFootprintPath."} tool = _find_adom_lbr() if not tool:- tool = _install_adom_lbr_windows()- if not tool:- return {"success": False, "errorCode": "adom_lbr_unavailable",- "error": "adom-lbr (the canonical KiCad->EAGLE converter) is not installed "- "on this box, and this bridge deliberately does NOT convert KiCad "- "formats itself.",- "_hint": ("Conversion is owned by adom/adom-lbr - one converter for the whole "- "ecosystem. From a CONTAINER: `adom-lbr generate --sym <.kicad_sym> "- "--fp <.kicad_mod> -o <out.lbr>` (auto-linted), then stage the .lbr "- "to this box (send_files, dest under %TEMP%) and use the fusion_show_* "- "verbs. A windows release asset of adom-lbr has been requested so this "- "verb can run it on-box.")}+ return _kicad_ingest_unavailable_error() if not lbr_p: base = (sym_p or mod_p).rsplit("/", 1) stem = base[-1].rsplit(".", 1)[0]@@ -9777,6 +9759,12 @@ def _handle_create_library(fusion_info: dict, args: dict) -> dict: "_hint": "Shape A: {libraryPath, stepPath}. Shape B: {kicadSymbolPath, " "kicadFootprintPath, stepPath, pinMap?}. stepPath is required for " "a PROVEN library - without it there is no real 3D body."}+ # SHAPE B FAILS AT THE FRONT DOOR, never three stages in (#43 follow-up, 2026-08-21):+ # the old flow staged files, launched Fusion (a minute of the user's time), and THEN+ # discovered adom-lbr is absent - which on Windows/Mac it always is, by platform rule.+ # Knowable up front, so refused up front; fusion_readiness carries the same flag.+ if (sym_p or mod_p) and not _find_adom_lbr():+ return _kicad_ingest_unavailable_error() import uuid as _uuid run_id = _uuid.uuid4().hex[:12]