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 171 file(s)
13 files changed
+89−39
BRIDGE_VERSION+1−1@@ -1 +1 @@-1.11.41+1.11.42
addin/AdomBridge/commands/activity_palette.py+37−6@@ -106,6 +106,9 @@ def _shell_html(initial_payload=None, event_stream_url=None): .detail{color:#8b949e;font-size:12px;min-height:1.4em} .track{height:6px;background:#21262d;border-radius:3px;margin:10px 0 6px;overflow:hidden} .fill{height:100%%;width:0%%;background:#00b8b1;transition:width .4s ease}+ .track.sweep .fill{width:30%%;transition:none;animation:sweep 1.4s ease-in-out infinite}+ @keyframes sweep{0%%{transform:translateX(-100%%)}100%%{transform:translateX(340%%)}}+ @media (prefers-reduced-motion:reduce){.track.sweep .fill{animation:none;width:100%%;opacity:.35}} .meta{display:flex;justify-content:space-between;font-size:11px;color:#8b949e;font-variant-numeric:tabular-nums} .warn{margin-top:10px;padding:8px 10px;border-left:3px solid #00b8b1;background:#161b22;border-radius:6px;font-size:12px} .warn[hidden]{display:none}@@ -118,7 +121,7 @@ def _shell_html(initial_payload=None, event_stream_url=None): <div class="brand"><span class="mark">%(logo)s</span><span class="dot" id="dot"></span><span class="brandtxt">is driving Fusion</span></div> <h1 id="title">Working</h1> <div class="detail" id="detail"></div>- <div class="track"><div class="fill" id="fill"></div></div>+ <div class="track" id="track"><div class="fill" id="fill"></div></div> <div class="meta"><span id="pct">0%%</span><span id="eta"></span></div> <div class="routing" id="routing" hidden><h2>Selected connection</h2><p id="routeConnection"></p><h2>Calculated route</h2><p id="routePlan"></p><h2>Measured checks</h2><p id="routeChecks"></p><h2>Recent operations</h2><p id="routeEvents"></p><div class="connection" id="streamStatus"></div></div> <div class="warn" id="warn">Please do not click, type or close documents in Fusion until this finishes. Your other apps are unaffected.</div>@@ -132,13 +135,36 @@ def _shell_html(initial_payload=None, event_stream_url=None): var route=d.routing||{}; document.getElementById('routing').hidden=!d.routing; ['Connection','Plan','Checks','Events'].forEach(function(k){document.getElementById('route'+k).textContent=route[k.toLowerCase()]||'';});- var pct=Math.max(0,Math.min(100,parseInt(d.percent||0,10)||0));- var fill=document.getElementById('fill'); fill.style.width=pct+'%%'; fill.style.background=c;+ document.getElementById('fill').style.background=c; document.getElementById('dot').style.background=c;- document.getElementById('pct').textContent=pct+'%%';- document.getElementById('eta').textContent=d.eta||'';+ // a new step (new title) restarts the clock the time-based bar runs on+ if(d.title!==cur.title){ cur.t0=Date.now(); }+ cur.title=d.title; cur.tone=d.tone||'working';+ cur.pct=(d.percent===null||d.percent===undefined)?null:Math.max(0,Math.min(100,parseInt(d.percent,10)||0));+ cur.eta=(d.etaSec===null||d.etaSec===undefined)?null:Math.max(0,+d.etaSec);+ cur.etaText=d.eta||'';+ paint(); var w=document.getElementById('warn'); w.hidden=(d.tone&&d.tone!=='working'); w.style.borderLeftColor=c; }+ var cur={title:null,t0:Date.now(),pct:null,eta:null,etaText:'',tone:'working'};+ function paint(){+ var fill=document.getElementById('fill'), track=document.getElementById('track');+ var pctEl=document.getElementById('pct'), etaEl=document.getElementById('eta');+ if(cur.tone!=='working'){ track.classList.remove('sweep'); fill.style.width='100%%'; pctEl.textContent=cur.tone==='done'?'Done':'Stopped'; etaEl.textContent=''; return; }+ if(cur.pct!==null){ track.classList.remove('sweep'); fill.style.width=cur.pct+'%%'; pctEl.textContent=cur.pct+'%%'; etaEl.textContent=cur.etaText; return; }+ var el=(Date.now()-cur.t0)/1000;+ if(cur.eta){+ // elapsed against the usual time for this step, never past 95%% until it really ends+ track.classList.remove('sweep');+ var p=Math.min(95,Math.round(100*el/cur.eta)); fill.style.width=p+'%%'; pctEl.textContent=p+'%%';+ var left=Math.round(cur.eta-el);+ etaEl.textContent=left>0?(left>=60?('about '+Math.floor(left/60)+'m '+('0'+left%%60).slice(-2)+'s left'):('about '+left+'s left')):'taking longer than usual';+ } else {+ track.classList.add('sweep'); fill.style.width=''; pctEl.textContent='Working';+ etaEl.textContent=Math.round(el)+'s';+ }+ }+ setInterval(paint,1000); window.fusionJavaScriptHandler={handle:function(action,data){ try{ if(action==='update'){ apply(JSON.parse(data||'{}')); } }catch(e){ return 'ERR '+e; } return 'OK';@@ -159,8 +185,13 @@ def _payload(title, detail, percent, eta_sec, tone): if eta_sec is not None: m, s = divmod(max(0, int(eta_sec)), 60) eta = ("about %dm %02ds left" % (m, s)) if m else ("about %ds left" % s)+ # percent None means the caller does not know it (most verbs: a document opening, a view+ # switching). The page then fills the bar by elapsed time against etaSec, or sweeps it when+ # there is no ETA either. Sending 0 painted "0%" for the whole step (issue #121).+ pct = None if percent is None else max(0, min(100, int(percent))) return _json.dumps({"title": str(title or "Working"), "detail": str(detail or ""),- "percent": max(0, min(100, int(percent or 0))), "eta": eta,+ "percent": pct, "eta": eta,+ "etaSec": None if eta_sec is None else max(0, int(eta_sec)), "tone": tone or "working"})
bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "fusion360", "displayName": "Autodesk Fusion 360",- "version": "1.11.41",+ "version": "1.11.42", "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.11.41"+version = "1.11.42" dependencies = [ "serde_json", ]
dashboard/Cargo.toml+1−1@@ -1,6 +1,6 @@ [package] name = "fusion-dashboard"-version = "1.11.41"+version = "1.11.42" edition = "2021" [dependencies]
install.sh+36−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.11.41"+DASH_VERSION="1.11.42" 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@@ -45,3 +45,38 @@ else rm -f "$DEST/fusion-dashboard.tmp" echo "WARN: fusion-dashboard download failed ($DASH_URL) - the Dashboard is unavailable until 'adom-wiki pkg update' retries it" fi++# KEEP THE DASHBOARD SERVING ACROSS RESTARTS (page issue #121, Muzzer 2026-10-17): after a+# container restart the Dashboard tab read "Its server is not running", because only the dock+# button starts `serve` and nothing brings it back. Where systemd runs and sudo needs no+# password, install a unit like adom-shotlog's (Restart=always). The dock's own launch step+# finds this instance on its port and reuses it. A reinstall restarts it onto the new binary.+if [ -x "$DEST/fusion-dashboard" ] && [ -d /run/systemd/system ] && sudo -n true 2>/dev/null; then+ UNIT=/etc/systemd/system/adom-fusion-dashboard.service+ sudo -n tee "$UNIT" >/dev/null <<UNIT_EOF+[Unit]+Description=Adom Fusion Dashboard (the fusion-bridge Launch Page server)+After=network-online.target++[Service]+Type=simple+User=$(id -un)+Environment=HOME=$HOME+ExecStart=/bin/bash -lc 'exec $DEST/fusion-dashboard serve --port 8930 --ai-thread fusion-dashboard'+Restart=always+RestartSec=3++[Install]+WantedBy=multi-user.target+UNIT_EOF+ # a dock-launched server (setsid, outside the unit) holds port 8930 and would push the service+ # onto 8931 as a second copy: stop THIS binary's serve processes only, then let the unit own it+ pkill -f "^$DEST/fusion-dashboard serve" 2>/dev/null || true+ sudo -n systemctl daemon-reload \+ && sudo -n systemctl enable adom-fusion-dashboard.service >/dev/null 2>&1 \+ && sudo -n systemctl restart adom-fusion-dashboard.service \+ && echo "fusion-dashboard runs as a service (adom-fusion-dashboard.service): it comes back after a restart" \+ || echo "WARN: could not enable adom-fusion-dashboard.service; the dock button still starts the Dashboard"+else+ echo "NOTE: no systemd here (or sudo needs a password), so the Dashboard starts from the dock button and does not come back on its own after a restart"+fi
package.json+1−1@@ -1,6 +1,6 @@ { "slug": "fusion-bridge",- "version": "1.11.41",+ "version": "1.11.42", "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−26@@ -1,6 +1,6 @@ { "slug": "fusion-bridge",- "version": "1.11.41",+ "version": "1.11.42", "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",@@ -76,6 +80,9 @@ "add a 3d model to a component", "make a fusion 360 library with 3d", "set up the fusion bridge",+ "fusion dashboard",+ "fusion status page",+ "open the fusion launch page", "aps not configured", "share aps client id across my org", "set up fusion cloud search for my company",@@ -108,28 +115,5 @@ "label": "Part volume", "prompt": "How much material does each printed part in this assembly use?" }- ],- "agent_permissions": {- "allow_bash": [],- "allow": [- "adom-desktop-fusion-bridge read-only verbs (via the adom-bridge CLI): fusion_readiness, fusion_get_app_state, fusion_addin_status, fusion_check_dialogs - state queries; they change nothing.",- "adom-desktop-fusion-bridge read-only verbs: fusion_alerts (reads Fusion's own log for toasts), fusion_document_info, fusion_window_info, fusion_board_info, fusion_library_parts - inspect only.",- "adom-desktop-fusion-bridge read-only verbs: fusion_prove_result (a persisted run report), fusion_plan_library_import (report-only preflight), fusion_list_cloud_projects, fusion_describe.",- "adom-desktop-fusion-bridge evidence captures fusion_screenshot_fusion and fusion_capture_library_views read pixels and write local image files only."- ],- "soft_deny": [- "adom-desktop-fusion-bridge lifecycle verbs fusion_stop, fusion_kill, fusion_restart_for_addin close or kill the Fusion application - keep the human prompt.",- "adom-desktop-fusion-bridge fusion_install_fusion silently installs Autodesk Fusion on the user's machine.",- "adom-desktop-fusion-bridge fusion_cleanup_cloud_files deletes files from the user's Autodesk cloud hub.",- "adom-desktop-fusion-bridge managed-library verbs (fusion_managed_library_push/pull/create/link/unlink) publish to or overwrite the user's library.io libraries."- ],- "environment": [- "adom-desktop-fusion-bridge is the Fusion 360 bridge for Adom Bridge; its fusion_* verbs are invoked through the adom-bridge CLI and drive Autodesk Fusion on the user's own desktop.",- "adom-desktop-fusion-bridge desktop actions also pass Adom Bridge's own human-approval gate (caller identity, per-call reason, Activity Log) - a container approval is the first of two gates."- ]- },- "author": {- "name": "John Lauer",- "email": "[email protected]"- }-}+ ]+}
rust/Cargo.toml+1−1@@ -4,7 +4,7 @@ members = ["core", "lbr", "os-win", "os-mac", "bridge"] # One version for the whole bridge, in lockstep with BRIDGE_VERSION (tools/release.sh bumps both). [workspace.package]-version = "1.11.41"+version = "1.11.42" edition = "2021" license = "MIT"
tools/check-naming.shtools/check-portable.shtools/promote.shtools/release.sh