← Commit history
BRIDGE_VERSION+1−1
@@ -1 +1 @@-1.9.208\ No newline at end of file+1.9.209\ 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.208",-  "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.208/adom-bridge-fusion-v1.9.208.zip",-  "sha256": "94a8322042721d9bdf84afa77ee3818a13b5a1ba1b6c0cb5129a87eaf201b1f2",-  "size": 495990,+  "version": "1.9.209",+  "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.209/adom-bridge-fusion-v1.9.209.zip",+  "sha256": "ca5e84bea81f7b19ab79383ace76d1cde8f43d4bf067dabb9f42e270e3972b12",+  "size": 497196,   "verbPrefixes": [     "fusion_"   ],
bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "fusion360",   "displayName": "Autodesk Fusion 360",-  "version": "1.9.208",+  "version": "1.9.209",   "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.208"+version = "1.9.209" dependencies = [  "serde_json", ]
dashboard/Cargo.toml+1−1
@@ -1,6 +1,6 @@ [package] name = "fusion-dashboard"-version = "1.9.208"+version = "1.9.209" 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.208"+DASH_VERSION="1.9.209" 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.208",+  "version": "1.9.209",   "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.208",+  "version": "1.9.209",   "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+66−1
@@ -9194,6 +9194,17 @@ def _orchestrate_bind_library_3d(args: dict) -> dict:                       "fresh mint) - EDIT %s.dev then screenshot to verify the render." % deviceset)}  +def _lbr_has_package3d(lbr_path: str):+    """Does this .lbr carry a bound package3d? Returns True/False, or None when the file+    cannot be read (unknown is NOT False - a caller must be able to tell them apart)."""+    try:+        txt = open(lbr_path, encoding="utf-8", errors="replace").read()+    except Exception:+        return None+    m = re.search(r'<package3d[^>]*(?:\burn|\bwip_urn)="([^"]+)"', txt)+    return bool(m and m.group(1).strip())++ def _orchestrate_show_library(args: dict) -> dict:     """Eight-surfaces contract (ab SDK, issue #30): the LIBRARY surface by its smallest     name. libraryPath opens it (open_lbr); name alone handles the already-open case."""@@ -9214,7 +9225,61 @@ def _orchestrate_show_library(args: dict) -> dict:                     "_hint": "Pass libraryPath (WINDOWS .lbr path) to open it; name alone only handles the already-open case."}     else:         return {"success": False, "error": "libraryPath or name required."}-    out = {"success": True, "view": "library"}+    # ── FINDING 2 (#58): ASSERT THE LIBRARY IS ACTUALLY THE ACTIVE DOCUMENT ────────────+    # One call returned success:true with Fusion sitting on an empty Untitled(1) DESIGN+    # tab, no Electronics panels at all, and nothing in the response distinguished it from+    # the nine that worked. Worse, the reporter's blank-frame smoke alarm RATED IT BEST:+    # 99.5% ink coverage vs 94.5-94.7% for the real ones, because a uniform dark canvas is+    # "inked" everywhere. A screenshot cannot be the proof here; the document name can.+    want = (name or (lbr.rsplit("/", 1)[-1].rsplit(".", 1)[0] if lbr else "")).strip()+    active = ""+    try:+        st = _proxy_to_addin("get_app_state", {}, timeout=12)+        active = str((st.get("data") or {}).get("activeDocument", "") or "")+    except Exception:+        pass+    if want and active and want.lower() not in active.lower():+        return {"success": False, "errorCode": "library_not_active",+                "error": "opened %r but the ACTIVE document is %r - the view you would "+                         "screenshot is not the library." % (want, active),+                "activeDocument": active, "expected": want,+                "_hint": ("Fusion switched or left another tab in front. Re-call "+                          "fusion_show_library {libraryPath} once; if it repeats, close the "+                          "stray document (fusion_close_document) and retry.")}++    out = {"success": True, "view": "library", "activeDocument": active or None}++    # ── THE HINT REQUEST (#58): say when there is no 3D to show ────────────────────────+    # The reporter called this verb alone, got a grey Placeholder in the 3D pane on 10/10+    # parts, and filed it as a bridge bug before finding their own documentation saying+    # fusion_bind_library_3d must run first. They are right that the bridge KNOWS this and+    # said nothing. threeDBound is null when unknowable (name-only call), never False.+    bound = _lbr_has_package3d(lbr) if lbr else None+    out["threeDBound"] = bound+    if bound is False:+        out["_hint"] = ("This library has NO package3d, so Fusion renders a grey Placeholder "+                        "slab in the 3D pane - that is not a captured 3D artifact. Run "+                        "fusion_bind_library_3d {libraryPath, stepPath} FIRST, then re-open. "+                        "(fusion_create_library does the whole chain for you.)")+    elif bound is None and lbr:+        out["_hint"] = ("Could not read the .lbr to tell whether a package3d is bound; if the "+                        "3D pane shows a grey Placeholder, run fusion_bind_library_3d first.")++    # ── FINDING 3 (#58): ten calls left ten tabs open ──────────────────────────────────+    # Not closed automatically: showing a library is a "leave it on screen" verb, so+    # closing it would defeat the call. Reported instead, so a batch caller can see the+    # accumulation it is causing rather than discovering it ten tabs later.+    try:+        _docs = _open_doc_names()+        if len(_docs) > 3:+            out["openDocuments"] = len(_docs)+            out["_hintDocs"] = ("%d documents are open in Fusion. show_library deliberately "+                                "leaves the library on screen, so a batch of calls accumulates "+                                "tabs - close them with fusion_close_all_documents between "+                                "runs." % len(_docs))+    except Exception:+        pass+     try:         shot = _handle_screenshot_fusion({}, {})         p = shot.get("savedTo") or shot.get("localSafePath")