← Commit history

Upload 1 file(s)

John Lauer ·1840ed0de4 ·4mo ago ·parent 51fa708
1 file changed +183−5
SKILL.md+183−5
@@ -1,7 +1,185 @@ ----name: adom-desktop-fusion-bridge-description: >-  Reference implementation of the Fusion 360 bridge — thin Python HTTP server that passes commands through to a Fusion add-in via local socket. The pattern for any host app that exposes a plugin API.+name: adom-desktop-fusion+public: true+description: "Launch and drive Fusion 360 on the user's laptop from this container via the adom-desktop CLI. Includes FAST cloud-file search via APS (Autodesk Platform Services) — search/browse/open the team's Fusion cloud designs in seconds (set up once per company, each user signs in once, never charged). Plus open .f3d/.f3z designs, open cloud files, close documents, dismiss recovery dialogs, capture Fusion window screenshots, send keys + click, run the add-in (STEP/GLB/.lbr import-export, BOM/parameters). Trigger words: fusion, Fusion 360, fast cloud search, fusion_aps_search, search fusion files, find a design, browse cloud files, fusion_aps_open, aps, open fusion, launch fusion, open design, f3d, f3z, import STEP, export STEP, export GLB, export lbr, Fusion electronics, Fusion PCB, BOM from Fusion, Fusion parameters, Fusion API, dismiss recovery, Fusion screenshot, fusion_click, fusion_send_key, fusion bridge, close fusion." ----# Reference bridge: Fusion 360-Reference implementation of the Fusion 360 bridge — thin Python HTTP server that passes commands through to a Fusion add-in via local socket. The pattern for any host app that exposes a plugin API.++# adom-desktop — Fusion 360 bridge++All commands dispatch to the Fusion Python bridge. From this container:++```bash+adom-desktop fusion_<action> '<json_args>'+```++The leading `fusion_` routes to the Fusion plugin; `<action>` is the plugin-side name.++## ⚡ Fast cloud search (APS) — READ THIS FIRST for any "find/search/open a cloud design" task++To search the team's Fusion cloud files, use **`fusion_aps_search`**, NOT the legacy+`fusion_search_cloud_files` (which walks folders one-by-one and takes 30+ MINUTES). APS hits+Autodesk's **server-side index** → results in **seconds**, and works with Fusion closed.++| Verb | Does |+|---|---|+| `fusion_aps_search {query, projectId?, limit?}` | Fast name search across the whole team hub; newest-first; shows each file's project. |+| `fusion_aps_browse {} / {projectId} / {projectId,folderId}` | Browse hubs→projects→folders→files (cloud explorer, no Fusion). |+| `fusion_aps_open {query}` | Search + open the best match in Fusion (opens by exact URN — works for nested files). |+| `fusion_aps_status {}` | configured? signedIn? token live? + never-charge usage meter. **Call this first** — its `_hint` tells you the next step. |+| `fusion_aps_signin {}` | One-time per user: opens Autodesk consent, captures the token. |+| `fusion_aps_set_client_id {clientId}` | Set the org's APS Client ID. |++**Auth model (important): set up ONCE per company, each user signs in once.** An admin registers a free APS app for the org one time (the AI drives the whole setup — see the `fusion-aps-signin` skill) → a **Client ID** (a public PKCE id, no secret, safe to share within the org). Then every teammate just runs `fusion_aps_signin` once with their own Autodesk login — **no plan, no card, no setup** for them. It's **per-organization** (each company runs its own setup; don't ship one global Client ID). **Nobody is ever charged** — the card is identity-verification only, and the bridge is free-endpoint-only + usage-capped.++If `fusion_aps_status` says not configured/signed in, follow its `_hint`. Full why + step-by-step setup: the bundled **`fusion-aps-search`** and **`fusion-aps-signin`** skills.++## Commands (core bridge)++| CLI form | Action | Purpose | Key args |+|---|---|---|---|+| `fusion_start` / `fusion_launch` | `start` / `launch` | Launch Fusion 360 (handles webdeploy glob, waits for bridge, dismisses startup picker) | — |+| `fusion_open_design` | `open_design` | Open a local `.f3d` / `.f3z` design file | `path` |+| `fusion_open_cloud_file` | `open_cloud_file` | Open a design from the user's Fusion cloud | `project`, `path` |+| `fusion_close_document` | `close_document` | Close the active document | — |+| `fusion_close_window` | `close_window` | Close a specific Fusion window by HWND | `hwnd` |+| `fusion_close` | `close` | Close Fusion 360 entirely | — |+| `fusion_dismiss_recovery` | `dismiss_recovery` | Dismiss the "recover unsaved work" dialog | — |+| `fusion_relocate_recovery` | `relocate_recovery` | Move recovery dialog offscreen (for recording) | — |+| `fusion_window_info` | `window_info` | Enumerate Fusion windows (HWND, title, bounds) | — |+| `fusion_screenshot_fusion` | `screenshot_fusion` | Screenshot the main Fusion window | — |+| `fusion_screenshot_all` | `screenshot_all` | Screenshot every Fusion window | — |+| `fusion_click_fusion` | `click_fusion` | Click at (x, y) in the Fusion main window | `x`, `y` |+| `fusion_send_key` | `send_key` | Send a keyboard shortcut to Fusion | `hwnd`, `key` |+| `fusion_addin_status` | `addin_status` | Report whether the in-process Adom add-in is loaded + healthy | — |++## Extended commands via the in-process add-in++If the Adom add-in is installed (`cd ~/project/adom-desktop/plugins/fusion360 && python install_addin.py` on the laptop), Fusion 360 exposes an additional API over its own ports. Typical extra commands proxied through the bridge:++- `fusion_import_step` — import a STEP file into the active document+- `fusion_export_step` — export active body/occurrence to STEP+- `fusion_export_glb` — export to GLB (used by the 3D viewer)+- `fusion_export_lbr` — export an Eagle library (used by the Eagle workflow)+- `fusion_open_lbr` / `fusion_open_symbol` — open symbol libraries+- `fusion_command` — generic `{"command": "<fusion_api_name>", "args": {...}}` pass-through for any Fusion API call+- `fusion_list_cloud_projects`, `fusion_list_cloud_files`, `fusion_walk_cloud_tree`, `fusion_search_cloud_files`, `fusion_open_cloud_file`, `fusion_export_cloud_file` — Autodesk cloud Data API operations++**Opening multi-design electronics files — pass `fileExtension`.** A Fusion electronics data file that links to multiple designs (common for boards with variants) makes `fusion_open_cloud_file` pop Fusion's native **"Select Electronics Design File" picker** — a CEF/Chromium modal whose list is **not keyboard- or Win32-navigable** (and screen-coord clicks are unreliable on multi-monitor/HiDPI), so it **can't be resolved headlessly**. Avoid it by opening the specific file directly: `fusion_open_cloud_file {"fileName":"<name>","fileExtension":"fbrd", ...}` (the `.fbrd` board lands straight in PCB Editor — live-confirmed). Opening the bare name or the `.fprj` project triggers the picker. If a picker still appears, `_diagnose_addin_timeout`/`blockingDialogs` will classify it (see below).++### Blocking-dialog awareness++Several Fusion modals (the multi-link "Select Electronics Design File" picker, "Fusion needs to update", Document Recovery, "Save changes?") block the add-in's main thread. The bridge now **classifies them by title** and, on a blocked command, returns `blockingDialogs: [{hwnd, title, category, resolution}]` with the precise cause + fix — instead of a misleading "add-in not responding / may have crashed". So a blocked open tells you *which* modal is up and how to clear it.++Resolution notes:+- **Multi-link picker** is a **CEF/web modal whose list is NOT keyboard- or Win32-navigable** (SendInput reaches only the native Cancel/OK; screen-coord clicks are unreliable on multi-monitor/HiDPI). It currently **must be resolved on the desktop**. *Headless fix tracked separately:* have the add-in open the specific linked design via the Fusion API, avoiding the picker entirely.+- **Update nag** is reported, not auto-dismissed (auto-confirming could start an update mid-run) — clear it on the desktop; doing so also commonly resolves recurring add-in crashes (host/add-in version drift).+- **Recovery** prompts: `fusion_dismiss_recovery` / `fusion_relocate_recovery`.++Check `fusion_addin_status` first — if the add-in isn't loaded, these will fail with a `_hint` pointing at the install script.++## Cloud search — defensive contract (add-in v1.0.2+)++`fusion_search_cloud_files` is the most-used long-running verb. Its v1.0.2 behavior is engineered specifically so the AI never misreports a failed search as "file not found":++| You read in the response | Mean |+|---|---|+| `searchComplete: true` + `totalFound: 0` | **Confirmed negative.** No match in the searched scope. |+| `searchComplete: true` + `totalFound: N` | All matches returned. |+| `searchComplete: false` (any reason) | **Search stopped early.** May or may not be more matches. Do NOT say "not found" to the user. Re-run with broader caps OR narrower `folderPath`. |++`searchComplete` is `true` ONLY when every one of these is clean: not `folderLimitReached`, not result-`truncated`, not `searchTimedOut`, `foldersSkipped == 0`, `filesSkipped == 0`. Five conditions, all five must pass.++### Performance + the slow-search etiquette++`fusion_search_cloud_files` runs at ~1 folder/sec because Autodesk's free Fusion 360 Python API has no indexed search endpoint — it walks the cloud Data API one folder at a time (30+ min on a real hub). **⚠️ Prefer `fusion_aps_search` instead** (see the APS section at the top) — it uses Autodesk Platform Services' server-side index and returns in **seconds**. This legacy walk verb remains only as a fallback for when APS isn't set up; if a user is hitting slow searches, set up APS (`fusion_aps_status` → its `_hint`) rather than tuning the walk.++**Before firing a broad search**, ask the user which subfolder is likely. Naming a folder like "Molecules" cuts 5-40 min searches down to ~10s. The verb's response includes a `costAnalysis` block (`foldersPerSecond`, `estimatedSecondsPer100Folders`) so the AI can budget realistically.++### Streaming progress++For interactive sessions, wrap long searches in `watch` so the AI gets one JSON-line progress event per `interval` seconds:++```bash+adom-desktop watch '{+  "command": "fusion_search_cloud_files",+  "args": {+    "query": "cosmiic",+    "projectName": "Main",+    "folderPath": "Molecules",+    "recursive": true,+    "maxFolders": 300,+    "maxDepth": 10,+    "searchTimeout": 340,+    "timeout": 400+  },+  "interval": 3+}'+```++Output:+```+{"event":"started", ...}+{"event":"progress", "foldersVisited": 12, "filesFound": 1, "elapsedSeconds": 15.1, "currentFolder": "Molecules/COSMIIC", ...}+{"event":"progress", "foldersVisited": 173, "filesFound": 3, "elapsedSeconds": 168.3, ...}+{"event":"complete", "result": {... full response with searchComplete:true ...}}+```++The `watch` wrapper composes with the `Monitor` tool — each stdout line becomes a notification.++### Args (no hard upper caps in v1.0.2+)++| Arg | Default | Notes |+|---|---|---|+| `query` | (required) | Substring of file name. **Case-insensitive both directions.** |+| `projectName` | active | Cloud project name. |+| `folderPath` | project root | Starting subfolder. **NARROW HERE — biggest perf lever.** |+| `recursive` | `false` | Descend into subfolders. |+| `maxDepth` | 2 | Recursion depth cap. |+| `maxFolders` | 10 | Folder-visit cap. |+| `maxResults` | 20 | Result cap. |+| `folderTimeout` | 30s | Per-folder cloud-API timeout. Bridge skips slow folders. |+| `searchTimeout` | 120s | Overall wall-clock timeout. Set 300+ for big walks. |+| `timeout` | 620s | HTTP envelope timeout (CLI+direct API). Bump if `searchTimeout` > 180. |++Real-world live test: `Main/Molecules` recursive depth-10 cosmiic search hit 173 folders in 168s with `searchComplete:true, totalFound:3, foldersSkipped:0, filesSkipped:0`. Fusion stayed `main_thread: responsive` throughout.++## Quick examples++```bash+# Launch Fusion+adom-desktop fusion_start '{}'++# Open a local design+adom-desktop fusion_open_design '{"path":"C:/designs/board.f3d"}'++# Screenshot all Fusion windows+adom-desktop fusion_screenshot_all '{}'++# Run a Fusion API command (add-in required)+adom-desktop fusion_command '{+  "command":"export_step",+  "args":{"occurrence":"body1","output":"C:/tmp/part.step"}+}'++# Check add-in health+adom-desktop fusion_addin_status '{}'+```++## Error shape++Every failing response includes a `_hint` field. Surface it verbatim when a Fusion command fails.++## Bridge architecture (v1.8.31+) — dynamic ports++Earlier versions used hardcoded port `8773` for the bridge and `8774` for the in-process add-in. **v1.8.31 made the bridge use OS-assigned ephemeral ports.** The add-in port is still 8774 (it's inside Fusion's process and the manifest pins it), but that's an internal detail.++- The CLI (`adom-desktop fusion_*`) routes through adom-desktop's direct API → the bridge's runtime port. No callers need port numbers.+- The add-in v1.0.2 ships a stale-lock watchdog in `http_server.py`: if a command holds the main-thread lock longer than `per_command_timeout + 30s` (e.g. Fusion's native cloud SDK wedges on a slow API call), the watchdog force-releases so subsequent commands work without restarting Fusion. The wedged command is orphaned but no longer blocks everything else.+- The `searchComplete` contract (see above) prevents false-negative reporting on capped/skipped searches. Always check `data.searchComplete` before telling the user "file not found".++## Related++- **`fusion-aps-search`** + **`fusion-aps-signin`** — APS fast-search reasoning + the AI-driven one-time setup (bundled in this repo's `skills/`).+- `adom-desktop-kicad` — sibling bridge for KiCad.+- `adom-desktop-direct-api` — the direct API contract that callers route through.+- **Canonical repo:** the wiki page `https://wiki.adom.inc/adom/adom-desktop-fusion-bridge` (+ GitHub backup `adom-inc/adom-desktop-fusion-bridge`). The old `adom-inc/adom-desktop/plugins/fusion360/` is a stale seed.