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 9 file(s)
9 files changed
+84−84
BRIDGE_VERSION+1−1@@ -1 +1 @@-1.9.106+1.9.107
adom-bridge-fusion-manifest.json+4−4@@ -1,10 +1,10 @@ { "manifest_version": 1, "name": "fusion360",- "version": "1.9.106",- "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.121/adom-bridge-fusion-v1.9.106.zip",- "sha256": "3e0fe6e2fc817a76a2c2e62f02c0201fd98f1bba0ea9e3496b043e1865c90c64",- "size": 448670,+ "version": "1.9.107",+ "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.122/adom-bridge-fusion-v1.9.107.zip",+ "sha256": "452f2194983abdfc6fc1f0724c353d6c28e0e952c729f74cc66010eef3c2ea4d",+ "size": 442430, "verbPrefixes": [ "fusion_" ],
bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "fusion360", "displayName": "Autodesk Fusion 360",- "version": "1.9.106",+ "version": "1.9.107", "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.toml+1−1@@ -1,6 +1,6 @@ [package] name = "fusion-dashboard"-version = "1.9.121"+version = "1.9.122" 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.121"+DASH_VERSION="1.9.122" 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.121",+ "version": "1.9.122", "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.121",+ "version": "1.9.122", "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+65−67@@ -9029,86 +9029,84 @@ COMMAND_HANDLERS["prove_library"] = _handle_prove_library +def _find_adom_lbr() -> str:+ """Locate adom-lbr on THIS box (the canonical KiCad->EAGLE converter, adom/adom-lbr)."""+ import shutil as _sh+ hit = _sh.which("adom-lbr") or _sh.which("adom-lbr.exe")+ if hit:+ return hit+ la = os.environ.get("LOCALAPPDATA", "")+ for c in ([os.path.join(la, "Programs", "adom-lbr", "adom-lbr.exe"),+ os.path.join(la, "adom-lbr", "adom-lbr.exe")] if la else []):+ if os.path.exists(c):+ return c+ return ""++ def _handle_import_kicad(fusion_info: dict, args: dict) -> dict:- """Ingest KiCad symbol/footprint files and BUILD or PATCH a valid .lbr (issue #43).-- KiCad is the FUNDAMENTAL symbol/footprint representation at Adom; the .lbr is derived,- and a derived file can be missing, stale, or half-generated. This verb makes the .lbr an- optimization instead of a prerequisite - the same posture bind_library_3d already takes- for STEP.-- args:- kicadFootprintPath - Windows path to a .kicad_mod (optional)- kicadSymbolPath - Windows path to a .kicad_sym (optional)- libraryPath - .lbr to PATCH if it exists, else where to WRITE the new library- (optional; defaults next to the footprint/symbol file)- name, prefix - optional overrides for the created deviceset-- PATCH fills only what is EMPTY (<packages></packages>, <connects/>) and never overwrites- existing content. The concrete case: cr0603-fx-5601elf's .lbr had an empty <packages>- while a correct .kicad_mod sat beside it, so every downstream verb refused honestly and- uselessly. After this verb, that part just works.+ """Ingest KiCad symbol/footprint files and produce a valid .lbr (issue #43) - by+ DELEGATING to adom-lbr, the ecosystem's canonical converter.++ John, 2026-08-21: "just use adom-lbr as your converter" - instead of this bridge+ growing its own KiCad parser. adom-lbr owns the conversion, ships a linter whose+ checks name the exact failure this issue was filed about (empty-packages /+ empty-connects -> Fusion "No Components"), and round-trips KiCad, EAGLE and Altium.+ One converter, one set of bugs, one place to fix them.++ args: kicadSymbolPath, kicadFootprintPath (Windows paths), libraryPath (output,+ optional), name (optional override). """- import os as _os- import kicad_lbr as _kl- mod_p = (args.get("kicadFootprintPath") or "").replace("\\", "/")+ import subprocess as _sp sym_p = (args.get("kicadSymbolPath") or "").replace("\\", "/")+ mod_p = (args.get("kicadFootprintPath") or "").replace("\\", "/") lbr_p = (args.get("libraryPath") or "").replace("\\", "/")- if not mod_p and not sym_p:+ if not sym_p and not mod_p: return {"success": False, "errorCode": "kicad_source_required",- "error": "Pass kicadFootprintPath and/or kicadSymbolPath.",- "_hint": "Both are wiki first-class artifacts; stage them with send_files, "- "then call this with their Windows paths."}- def _read(p, what):- if not p:- return None, None- try:- return open(p, "r", encoding="utf-8", errors="replace").read(), None- except Exception as e:- return None, {"success": False, "errorCode": "kicad_source_unreadable",- "error": "Could not read %s: %s (%s)" % (what, p, str(e)[:80])}- mod_text, err = _read(mod_p, ".kicad_mod")- if err:- return err- sym_text, err = _read(sym_p, ".kicad_sym")- if err:- return err+ "error": "Pass kicadSymbolPath and/or kicadFootprintPath."}+ tool = _find_adom_lbr()+ 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.")} if not lbr_p:- base = (mod_p or sym_p).rsplit("/", 1)+ base = (sym_p or mod_p).rsplit("/", 1) stem = base[-1].rsplit(".", 1)[0] lbr_p = (base[0] + "/" if len(base) > 1 else "") + stem + ".lbr"- mode = "patched" if _os.path.exists(lbr_p) else "created"+ cmd = [tool, "generate"]+ if sym_p:+ cmd += ["--sym", sym_p]+ if mod_p:+ cmd += ["--fp", mod_p]+ if args.get("name"):+ cmd += ["--name", str(args["name"])]+ cmd += ["-o", lbr_p] try:- if mode == "patched":- original = open(lbr_p, "r", encoding="utf-8", errors="replace").read()- new_text, report = _kl.patch_lbr(original, kicad_mod_text=mod_text,- kicad_sym_text=sym_text, name=args.get("name"))- if new_text == original:- report["unchanged"] = True- else:- try:- open(lbr_p + ".bak", "w", encoding="utf-8").write(original)- except Exception:- pass- open(lbr_p, "w", encoding="utf-8").write(new_text)- else:- new_text, report = _kl.build_lbr(kicad_sym_text=sym_text, kicad_mod_text=mod_text,- name=args.get("name"),- prefix=args.get("prefix") or "U")- open(lbr_p, "w", encoding="utf-8").write(new_text)+ r = _sp.run(cmd, capture_output=True, text=True, timeout=120) except Exception as e:- return {"success": False, "errorCode": "kicad_conversion_failed",- "error": "Conversion failed: %s" % str(e)[:200]}+ return {"success": False, "errorCode": "adom_lbr_failed",+ "error": "adom-lbr did not run: %s" % str(e)[:150]}+ if r.returncode != 0:+ return {"success": False, "errorCode": "adom_lbr_failed",+ "error": "adom-lbr generate failed (exit %d): %s"+ % (r.returncode, (r.stderr or r.stdout)[-300:]),+ "_hint": "adom-lbr auto-lints its output and exits 2 on lint failure - the "+ "message above names the exact check that failed."} names = _library_artifact_names(lbr_p)- return {"success": True, "libraryPath": lbr_p, "mode": mode, "report": report,+ return {"success": True, "libraryPath": lbr_p, "converter": "adom-lbr", "symbols": names.get("sym", []), "packages": names.get("pac", []), "devicesets": names.get("dev", []), "has3d": bool(names.get("p3d")),- "sources": {"kicadFootprint": mod_p or None, "kicadSymbol": sym_p or None},- "_hint": ("%s %s from KiCad sources. fusion_show_symbol / show_footprint consume "- "it directly; bind the 3D with fusion_bind_library_3d {libraryPath, "- "stepPath} (has3d is %s), then fusion_prove_library captures the four "- "evidence frames. A .bak sits beside a patched file."- % (mode.capitalize(), lbr_p, bool(names.get("p3d"))))}+ "toolOutput": (r.stdout or "").strip()[-300:],+ "_hint": ("Generated by adom-lbr (lint-clean by construction). fusion_show_symbol / "+ "show_footprint consume it directly; bind the 3D with "+ "fusion_bind_library_3d {libraryPath, stepPath}, then "+ "fusion_prove_library captures the four evidence frames.")} COMMAND_HANDLERS["import_kicad"] = _handle_import_kicad
tools/release-files.txt−1@@ -56,4 +56,3 @@ start.bat uninstall.sh handlers/taskbar_overlay.py resources/adom-overlay-32.png-kicad_lbr.py