← Commit history
BRIDGE_VERSION+1−1
@@ -1 +1 @@-1.9.191\ No newline at end of file+1.9.192\ 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.191",-  "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.191/adom-bridge-fusion-v1.9.191.zip",-  "sha256": "179b2c54314dffd2351ed8b233a87f20d30bb1151f1ee3039f4fc78851887f68",-  "size": 494167,+  "version": "1.9.192",+  "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.192/adom-bridge-fusion-v1.9.192.zip",+  "sha256": "4c57175e91b1b4b03a782747b51a8aa2e71023a0ca4c689094041f3645b8b48e",+  "size": 494207,   "verbPrefixes": [     "fusion_"   ],
bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "fusion360",   "displayName": "Autodesk Fusion 360",-  "version": "1.9.191",+  "version": "1.9.192",   "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.191"+version = "1.9.192" dependencies = [  "serde_json", ]
dashboard/Cargo.toml+1−1
@@ -1,6 +1,6 @@ [package] name = "fusion-dashboard"-version = "1.9.191"+version = "1.9.192" edition = "2021"  [dependencies]
dashboard/src/main.rs+16−3
@@ -274,7 +274,14 @@ fn action(ai_thread: &str, target: &str, name: &str, args: &serde_json::Value) -             // view - transport buttons + the live caption, clickable while they watch             // Fusion. Best-effort: no pup, no problem, the dashboard page has the same             // controls. Opened FOREGROUND deliberately - the user just pressed Run.-            if let Some(id) = unwrap_data(&r)["demoId"].as_str() {+            let dug = {+                let d = unwrap_data(&r);+                if d["demoId"].is_string() { d }+                else if let Some(o) = d["output"].as_str() {+                    serde_json::from_str::<serde_json::Value>(o).unwrap_or(d)+                } else { d }+            };+            if let Some(id) = dug["demoId"].as_str() {                 let url = format!("{}?remote={}", url_for(current_port()), id);                 let args = serde_json::json!({"url": url, "sessionId": format!("fusion-tour-remote-{}", id),                     "width": 320, "height": 420, "left": 40, "top": 120,@@ -282,9 +289,15 @@ fn action(ai_thread: &str, target: &str, name: &str, args: &serde_json::Value) -                     "foregroundReason": "the user just started the Fusion tour; this is its stop/pause remote"}).to_string();                 let ai2 = ai_thread.to_string(); let t2 = target.to_string();                 std::thread::spawn(move || {-                    let _ = Command::new("adom-bridge")+                    match Command::new("adom-bridge")                         .args(["--ai-thread", &ai2, "--target", &t2, "pup_open_window", &args])-                        .output();+                        .output() {+                        Ok(o) if o.status.success() =>+                            eprintln!("[dash] tour remote floaty opened"),+                        Ok(o) => eprintln!("[dash] tour remote floaty FAILED: {}",+                            String::from_utf8_lossy(&o.stderr).chars().take(200).collect::<String>()),+                        Err(e) => eprintln!("[dash] tour remote floaty spawn error: {}", e),+                    }                 });             }             r
dashboard/ui/index.html+7−2
@@ -414,7 +414,9 @@ if(REMOTE_ID){       '<button class="btn" id="rExit" style="border-color:rgba(248,81,73,.5);color:var(--red)" data-tip="End the tour">&#9209; Exit tour</button>'+       '</div></div>';     let rp=false;-    const rctl=async(a)=>{try{await act('tour_control',{demoId:REMOTE_ID,action:a});+    const rctl=async(a)=>{try{+      let ok=await act('tour_control',{demoId:REMOTE_ID,action:a}).catch(()=>null);+      if(!ok)await act('tour_control',{demoId:REMOTE_ID,action:a});       if(a==='pause'){rp=true;$('#rPause').innerHTML='&#9654;';}       if(a==='resume'){rp=false;$('#rPause').innerHTML='&#9208;';}     }catch(e){}};@@ -558,7 +560,10 @@ $('#btnTour').onclick=async()=>{   if(tourAudioOn()&&caps.length){(async()=>{for(const c of caps){try{await fetch('api/tts?text='+encodeURIComponent(c));}catch(e){}}})();}   const tt=$('#tourTransport');tt.style.display='flex';   let ttPaused=false;-  const ctl=async(action)=>{try{const r=await act('tour_control',{demoId:id,action});const x=r.data||r;+  const ctl=async(action)=>{try{+    let r=await act('tour_control',{demoId:id,action}).catch(()=>null);+    if(!r)r=await act('tour_control',{demoId:id,action});   // one silent retry - a slow relay hop must not eat a pause click+    const x=r.data||r;     if(x.success===false){toast(x.error||'control refused','err');return;}     if(action==='pause'){ttPaused=true;$('#ttPause').innerHTML='&#9654;';toast('pausing at the next step boundary');}     if(action==='resume'){ttPaused=false;$('#ttPause').innerHTML='&#9208;';toast('resuming');}
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.191"+DASH_VERSION="1.9.192" 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.191",+  "version": "1.9.192",   "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.191",+  "version": "1.9.192",   "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+1
@@ -8395,6 +8395,7 @@ def _orchestrate_demo_tour(args: dict) -> dict:                             "open-design: %r never became the active document within 170s" % query)                         state["designOpenFailed"] = True                 elif key == "datahub":+                    _wait_idle()   # ralph run 649s: the 3D save was still grinding; busy != broken                     r = _proxy_to_addin("list_cloud_projects", {}, timeout=45)                     if r.get("success"):                         _d = r.get("data") or {}