← Commit history
BRIDGE_VERSION+1−1
@@ -1 +1 @@-1.9.279\ No newline at end of file+1.9.280\ No newline at end of file
adom-bridge-fusion-manifest.json+4−4
@@ -1,10 +1,10 @@ {   "manifest_version": 1,   "name": "fusion360",-  "version": "1.9.279",-  "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.279/adom-bridge-fusion-v1.9.279.zip",-  "sha256": "78e37e369f5fc8cbf486b3b35d3b5d744582ffb7d4d8b80faa3f3c6914f8f9a7",-  "size": 570705,+  "version": "1.9.280",+  "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.280/adom-bridge-fusion-v1.9.280.zip",+  "sha256": "c199d0b73a122463454dd0402c605ac40fa95deb099e27b0fd093d9f6ad4a900",+  "size": 571489,   "verbPrefixes": [     "fusion_"   ],
bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "fusion360",   "displayName": "Autodesk Fusion 360",-  "version": "1.9.279",+  "version": "1.9.280",   "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.279"+version = "1.9.280" dependencies = [  "serde_json", ]
dashboard/Cargo.toml+1−1
@@ -1,6 +1,6 @@ [package] name = "fusion-dashboard"-version = "1.9.279"+version = "1.9.280" 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.279"+DASH_VERSION="1.9.280" 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.279",+  "version": "1.9.280",   "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.279",+  "version": "1.9.280",   "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]"-  }-}\ No newline at end of file+  ]+}
server.py+36−5
@@ -11426,9 +11426,19 @@ def _handle_prove_library(fusion_info: dict, args: dict) -> dict:     _LAST_LIBRARY[0] = lbr      evidence = []+    # SHARED PACKAGE, PROVE ONCE (John, 2026-08-30: "once you have a correctly defined+    # footprint with 3d attached, you don't need to re-bind each time ... this process+    # literally took you all night"). The bind was already once per package; the PROOF was+    # not: nine symbol variants on one SOIC-16 re-opened the same footprint and the same+    # cloud 3D design nine times. The chain now passes _skipSteps for a deviceset whose+    # package was proved earlier in the run; only its symbol and ganged frames are taken.+    _skip = set(args.get("_skipSteps") or [])+    _shared_with = args.get("_sharedWith")     # 1 + 2: the two editors, each full screen.     for label, suffix, view in (("symbol", "sym", "symbol-editor"),                                 ("footprint", "pac", "footprint-editor")):+        if label in _skip:+            continue         r = _show_library_view(want, suffix, lbr)         if not r.get("success"):             evidence.append(_emit({"step": label, "view": view, "ok": False,@@ -11437,7 +11447,7 @@ def _handle_prove_library(fusion_info: dict, args: dict) -> dict:         evidence.append(_emit(_prove_capture(label, view)))     # 3: the 3D editor. Only reachable when a real package3d is bound - with none, Fusion     #    shows its Placeholder, which is exactly the false pass this verb exists to prevent.-    if artifacts["package3d"]["present"]:+    if artifacts["package3d"]["present"] and "package3d" not in _skip:         # THE BOUND MODEL, NOT THE GENERATOR (caught by the bodies gate, run be27c38d034e:         # 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@@ -11574,7 +11584,7 @@ def _handle_prove_library(fusion_info: dict, args: dict) -> dict:                              "error": "Could not open the bound f3d (%s): %s" % (                                  _p3d_urn[-30:] if _p3d_urn else "no urn",                                  str((opened3d or {}).get("error"))[:100])}))-    else:+    elif "package3d" not in _skip:         evidence.append(_emit({"step": "package3d", "view": "3d-editor", "ok": False,                          "error": "No package3d bound - the 3D editor would only show Fusion's "                                   "grey Placeholder, which is not evidence."}))@@ -11624,9 +11634,11 @@ def _handle_prove_library(fusion_info: dict, args: dict) -> dict:     # of every message began - "Fusion offere[d ...]" - and cost the reporter a diagnosis)     missing += ["frame:%s(%s)" % (e.get("step"), str(e.get("error")))                 for e in evidence if not (e.get("ok") and e.get("screenshot"))]-    proven = (not missing) and len(captured) == 4+    _expected = 4 - len(_skip & {"symbol", "footprint", "package3d", "ganged"})+    proven = (not missing) and len(captured) == _expected     out = {"success": proven, "proven": proven, "libraryPath": lbr, "deviceset": want,            "artifacts": artifacts, "missing": missing,+           "stepsSkipped": sorted(_skip), "sharedPackageProof": _shared_with,            "evidence": evidence, "imagesCaptured": len(captured), "imagesRequired": 4}     if thumb_unverified:         out["thumbnailUnverified"] = thumb_unverified@@ -12993,7 +13005,7 @@ def _handle_create_library(fusion_info: dict, args: dict) -> dict:                 # Total is parts x 4, not a literal 4: on the first real 2-part run this                 # read "captured symbol (5 of 4)" - a narration line the front end renders                 # under the progress bar, reading nonsense from part two onward.-                _tot = 4 * max(1, int(state.get("partsToProve") or state.get("partsTotal") or 1))+                _tot = int(state.get("framesExpected") or 0) or 4 * max(1, int(state.get("partsToProve") or state.get("partsTotal") or 1))                 state["stageLabel"] = ("part %s of %s: captured %s (frame %d of %d)"                                        % (state.get("partIndex") or "?", state.get("partsToProve") or "?",                                           entry.get("step"), len(ev), _tot))@@ -13025,6 +13037,18 @@ def _handle_create_library(fusion_info: dict, args: dict) -> dict:             state["provedParts"] = []             _prove_results, _all_ok = [], True             _last_beat = [_tc.time()]+            # ONE FOOTPRINT + 3D PROOF PER PACKAGE (John, 2026-08-30). Devicesets that share a+            # package (symbol variants, value clones) get only their symbol and ganged frames;+            # the footprint and the cloud 3D design were proved with the first deviceset on+            # that package. Nine CH340G variants: 20 frames instead of 36, and the slow 3D+            # open happens once instead of nine times.+            try:+                _dev_pac = _library_artifact_names(target_lbr).get("dev_pac") or {}+            except Exception:+                _dev_pac = {}+            _pkg_proved_by = {}+            _uniq_pkgs = len({tuple(v) for v in _dev_pac.values()}) or len(_targets)+            state["framesExpected"] = 4 * min(_uniq_pkgs, len(_targets)) + 2 * max(0, len(_targets) - _uniq_pkgs)             for _pi, _dev in enumerate(_targets, 1):                 # A RUN MUST NOT OUTLIVE A SLEEP (John, 2026-08-30: "it seems odd to me that                 # its the next morning and you're still running this job"). The chain lives@@ -13067,14 +13091,21 @@ def _handle_create_library(fusion_info: dict, args: dict) -> dict:                     entry["kind"] = "proof"     # vs "main"/"popup" from fusion_live_feed                     return _publish_frame(entry) +                _pk_key = tuple(_dev_pac.get(_dev) or [])+                _shared = _pkg_proved_by.get(_pk_key) if _pk_key else None                 _r = _handle_prove_library(fusion_info, {                     "libraryPath": target_lbr, "name": _dev,                     # 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 ""),+                    "_skipSteps": (["footprint", "package3d"] if _shared else []),+                    "_sharedWith": _shared,                     "_onFrame": _frame_for})                 _prove_results.append({"part": _dev, "proven": bool(_r.get("proven")),-                                       "error": _r.get("error")})+                                       "error": _r.get("error"),+                                       "sharedPackageProof": _shared})+                if _r.get("proven") and _pk_key and not _shared:+                    _pkg_proved_by[_pk_key] = _dev                 state["provedParts"] = _prove_results                 _all_ok = _all_ok and bool(_r.get("proven"))                 # Close what THIS deviceset's frames opened (the 3D frame's design, any