← Commit history
BRIDGE_VERSION+1−1
@@ -1 +1 @@-1.10.34\ No newline at end of file+1.10.35\ No newline at end of file
bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "fusion360",   "displayName": "Autodesk Fusion 360",-  "version": "1.10.34",+  "version": "1.10.35",   "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.",
contracts/describe.json+6−6
@@ -1,6 +1,6 @@ {   "contract": "fusion-bridge verb catalog",-  "frozen": "2026-09-20",+  "frozen": "2026-09-21",   "note": "The Python bridge and the Rust bridge must both serve this catalog byte-for-byte in meaning: same names, same args, same result shapes, same timeouts. Regenerate ONLY from describe.py and diff in CI.",   "source": "describe.py",   "verbs": [@@ -34,7 +34,7 @@         "success": "bool"       },       "statusVerb": null,-      "summary": "Make a named open document the ACTIVE one before driving it. EDIT and most modelling verbs act on whatever is active, so in a batch with several documents open this is how you stop a verb landing in the wrong file (page issue #47). Prefer passing expectDocument on the verb itself, which fails closed instead of merely re-targeting.",+      "summary": "Make a named open document the ACTIVE one before driving it. EDIT and most modelling verbs act on whatever is active, so in a batch with several documents open this is how you stop a verb landing in the wrong file (page issue #47). Prefer passing expectDocument on the verb itself, which fails closed instead of merely re-targeting. An electronics design's schematic, board and 3D view are separate tabs with ONE name (type unknown): the reply says so in sameNameDocuments, and fusion_show_schematic / fusion_show_2d_board / fusion_show_3d_board {documentName} reach a specific view.",       "timeoutSeconds": 60     },     {@@ -288,7 +288,7 @@         "success": "bool"       },       "statusVerb": null,-      "summary": "Set the org's APS (PKCE) client id used for cloud search. Get it from your org's members-only wiki page: adom-wiki api /api/v1/pages/<org>/org-settings/files/integrations/autodesk-aps.json (never from another machine's config file). The reply carries orgSettingsFile, the exact JSON to publish there when your org has none yet, so every other box adopts it in two calls (fusion-aps-org-setup skill). Public identifier, no secret.",+      "summary": "Set the org's APS (PKCE) client id used for cloud search. Get it from your org's members-only wiki settings: adom-wiki settings get <org> autodesk-aps (never from another machine's config file). When the org has none yet, the reply's hint gives the adom-wiki settings set command that shares it, so every other box adopts it in two calls (fusion-aps-org-setup skill). Public identifier, no secret.",       "timeoutSeconds": 20     },     {@@ -322,7 +322,7 @@         "signedIn": "bool"       },       "statusVerb": null,-      "summary": "APS state: configured, signed in, token live, never-charge meter. When configured:false the hint sends you to your org's shared app ID on the wiki (<org>/org-settings, integrations/autodesk-aps.json) before anything else; the fusion-aps-org-setup skill covers new boxes and first-time orgs.",+      "summary": "APS state: configured, signed in, token live, never-charge meter. When configured:false the hint sends you to your org's shared app ID on the wiki (adom-wiki settings get <org> autodesk-aps) before anything else; the fusion-aps-org-setup skill covers new boxes and first-time orgs.",       "timeoutSeconds": 20     },     {@@ -1140,7 +1140,7 @@         "success": "bool"       },       "statusVerb": null,-      "summary": "Export the ACTIVE electronics document as plain EAGLE XML (.sch or .brd; the outputPath extension picks the format). Fusion's .fsch/.fbrd are ZIP containers with the EAGLE XML inside; this exports the container via Document.CopyToDesktop, extracts the inner XML, writes it to outputPath and deletes the intermediate file. The result opens in standalone EAGLE, imports into KiCad, and parses with any XML tool. The matching editor MUST be active: fusion_show_2d_board before a .brd, the Schematic Editor (fusion_show_schematic or EDIT .s1) before a .sch.",+      "summary": "Export the ACTIVE electronics document as plain EAGLE XML (.sch or .brd; the outputPath extension picks the format). Fusion's .fsch/.fbrd are ZIP containers with the EAGLE XML inside; this exports the container via Document.CopyToDesktop, extracts the inner XML, writes it to outputPath and deletes the intermediate file. The result opens in standalone EAGLE, imports into KiCad, and parses with any XML tool. The container holds whichever editor is ACTIVE, so since 1.10.35 the bridge switches to it first (Schematic Editor for .sch, PCB Editor for .brd; reply carries switchedView) instead of answering 'No .sch file found inside .fsch ZIP container' (page issue #95).",       "timeoutSeconds": 60     },     {@@ -1320,7 +1320,7 @@         "success": "bool"       },       "statusVerb": null,-      "summary": "Export the ACTIVE electronics document in Fusion's native source format via Document.CopyToDesktop: .fbrd (board), .fsch (schematic) or .flbr (library); the outputPath extension picks the format. The matching editor MUST be active or no file is written: fusion_show_2d_board before a .fbrd (the 3D view does not work), fusion_electron_run {command:\"EDIT .s1\"} or fusion_show_schematic before a .fsch, fusion_open_lbr before a .flbr. For plain EAGLE XML use fusion_export_eagle_source.",+      "summary": "Export the ACTIVE electronics document in Fusion's native source format via Document.CopyToDesktop: .fbrd (board), .fsch (schematic) or .flbr (library); the outputPath extension picks the format. The container holds whichever editor is ACTIVE, so since 1.10.35 the bridge switches to it first: the Schematic Editor for a .fsch, the PCB Editor for a .fbrd (reply carries switchedView). A .flbr still needs the library open (fusion_open_lbr). For plain EAGLE XML use fusion_export_eagle_source.",       "timeoutSeconds": 60     },     {
dashboard/Cargo.lock+1−1
@@ -4,7 +4,7 @@ version = 4  [[package]] name = "fusion-dashboard"-version = "1.10.34"+version = "1.10.35" dependencies = [  "serde_json", ]
dashboard/Cargo.toml+1−1
@@ -1,6 +1,6 @@ [package] name = "fusion-dashboard"-version = "1.10.34"+version = "1.10.35" edition = "2021"  [dependencies]
describe.py+5−5
@@ -92,9 +92,9 @@ _T = [      240, "fusion_demo", True, {}),      # ── Cloud search & files (APS) ─────────────────────────────────────────-    ("fusion_aps_status", "APS state: configured, signed in, token live, never-charge meter. When configured:false the hint sends you to your org's shared app ID on the wiki (<org>/org-settings, integrations/autodesk-aps.json) before anything else; the fusion-aps-org-setup skill covers new boxes and first-time orgs.",+    ("fusion_aps_status", "APS state: configured, signed in, token live, never-charge meter. When configured:false the hint sends you to your org's shared app ID on the wiki (adom-wiki settings get <org> autodesk-aps) before anything else; the fusion-aps-org-setup skill covers new boxes and first-time orgs.",      {}, {"configured": "bool", "signedIn": "bool", "neverCharge": "bool"}, 20, None, False, {}),-    ("fusion_aps_set_client_id", "Set the org's APS (PKCE) client id used for cloud search. Get it from your org's members-only wiki page: adom-wiki api /api/v1/pages/<org>/org-settings/files/integrations/autodesk-aps.json (never from another machine's config file). The reply carries orgSettingsFile, the exact JSON to publish there when your org has none yet, so every other box adopts it in two calls (fusion-aps-org-setup skill). Public identifier, no secret.",+    ("fusion_aps_set_client_id", "Set the org's APS (PKCE) client id used for cloud search. Get it from your org's members-only wiki settings: adom-wiki settings get <org> autodesk-aps (never from another machine's config file). When the org has none yet, the reply's hint gives the adom-wiki settings set command that shares it, so every other box adopts it in two calls (fusion-aps-org-setup skill). Public identifier, no secret.",      {"clientId": "required str"}, {"success": "bool"}, 20, None, False, {"clientId": "D5nn...EPAq"}),     ("fusion_aps_signin", "Open the Autodesk sign-in in the REMEMBERED browser+profile (not the OS default); a background listener captures the token. Pass {exe,profileDir,name} to use+remember a specific browser, or {allowDefaultBrowser:true} to fall back to the OS default. If nothing is remembered, returns needsExtensionOpen so the caller opens authUrl in the user's real browser via nbrowser_open_window.",      {"exe": "optional str (browser binary to launch+remember)", "profileDir": "optional str (e.g. 'Default','Profile 2')", "name": "optional str", "allowDefaultBrowser": "optional bool"},@@ -317,7 +317,7 @@ _T = [      10, "fusion_prove_result", True, {"runId": "a3f1c2d4e5b6"}),     ("fusion_addin_status", "Is the AdomBridge add-in loaded and answering inside Fusion? Reports addinReady, port and version, plus busy when a long command holds the main thread. If Fusion is running but this says not ready, the add-in was installed while Fusion was open - Fusion loads add-ins only at launch - so call fusion_restart_for_addin (ask the user first when one is present).",      {}, {"addinReady": "bool", "port": "int", "version": "str", "busy": "bool"}, 15, None, True, {}),-    ("fusion_activate_document", "Make a named open document the ACTIVE one before driving it. EDIT and most modelling verbs act on whatever is active, so in a batch with several documents open this is how you stop a verb landing in the wrong file (page issue #47). Prefer passing expectDocument on the verb itself, which fails closed instead of merely re-targeting.",+    ("fusion_activate_document", "Make a named open document the ACTIVE one before driving it. EDIT and most modelling verbs act on whatever is active, so in a batch with several documents open this is how you stop a verb landing in the wrong file (page issue #47). Prefer passing expectDocument on the verb itself, which fails closed instead of merely re-targeting. An electronics design's schematic, board and 3D view are separate tabs with ONE name (type unknown): the reply says so in sameNameDocuments, and fusion_show_schematic / fusion_show_2d_board / fusion_show_3d_board {documentName} reach a specific view.",      {"name": "required str (document name as reported by fusion_get_app_state)"},      {"success": "bool", "activeDocument": "str"}, 60, None, False, {"name": "TJA1050"}),     ("fusion_action_ledger", "Read the append-only record of what the bridge did in the BACKGROUND on this machine - dialogs it answered, Untitled scratch docs it swept, Fusion auto-starts, add-in restarts. Survives bridge respawns (~/.adom/fusion-bridge/actions.jsonl). This is the audit trail for why something changed on the user screen.",@@ -381,11 +381,11 @@ _T = [      {"filePath": "required str (WINDOWS path to a .fsch, .fbrd or .flbr; must exist on the Fusion machine)"},      {"success": "bool", "filePath": "str", "fileType": "str", "extension": "str", "activeWorkspace": "str", "activeDocument": "str", "nextSteps": "[str]", "postOpenCheck": "{required, steps}", "screenshots": "[{type,savedTo,sizeKB}] (sidecar shell) or postOpenScreenshot (exe shell)"},      60, None, True, {"filePath": "C:/Temp/TJA1050.fbrd"}),-    ("fusion_export_source", "Export the ACTIVE electronics document in Fusion's native source format via Document.CopyToDesktop: .fbrd (board), .fsch (schematic) or .flbr (library); the outputPath extension picks the format. The matching editor MUST be active or no file is written: fusion_show_2d_board before a .fbrd (the 3D view does not work), fusion_electron_run {command:\"EDIT .s1\"} or fusion_show_schematic before a .fsch, fusion_open_lbr before a .flbr. For plain EAGLE XML use fusion_export_eagle_source.",+    ("fusion_export_source", "Export the ACTIVE electronics document in Fusion's native source format via Document.CopyToDesktop: .fbrd (board), .fsch (schematic) or .flbr (library); the outputPath extension picks the format. The container holds whichever editor is ACTIVE, so since 1.10.35 the bridge switches to it first: the Schematic Editor for a .fsch, the PCB Editor for a .fbrd (reply carries switchedView). A .flbr still needs the library open (fusion_open_lbr). For plain EAGLE XML use fusion_export_eagle_source.",      {"outputPath": "required str (WINDOWS path ending in .fsch, .fbrd or .flbr)"},      {"success": "bool", "savedTo": "str", "sizeBytes": "int", "format": "str (fsch|fbrd|flbr)", "activeDocument": "str", "activeWorkspace": "str"},      60, None, False, {"outputPath": "C:/Temp/TJA1050.fbrd"}),-    ("fusion_export_eagle_source", "Export the ACTIVE electronics document as plain EAGLE XML (.sch or .brd; the outputPath extension picks the format). Fusion's .fsch/.fbrd are ZIP containers with the EAGLE XML inside; this exports the container via Document.CopyToDesktop, extracts the inner XML, writes it to outputPath and deletes the intermediate file. The result opens in standalone EAGLE, imports into KiCad, and parses with any XML tool. The matching editor MUST be active: fusion_show_2d_board before a .brd, the Schematic Editor (fusion_show_schematic or EDIT .s1) before a .sch.",+    ("fusion_export_eagle_source", "Export the ACTIVE electronics document as plain EAGLE XML (.sch or .brd; the outputPath extension picks the format). Fusion's .fsch/.fbrd are ZIP containers with the EAGLE XML inside; this exports the container via Document.CopyToDesktop, extracts the inner XML, writes it to outputPath and deletes the intermediate file. The result opens in standalone EAGLE, imports into KiCad, and parses with any XML tool. The container holds whichever editor is ACTIVE, so since 1.10.35 the bridge switches to it first (Schematic Editor for .sch, PCB Editor for .brd; reply carries switchedView) instead of answering 'No .sch file found inside .fsch ZIP container' (page issue #95).",      {"outputPath": "required str (WINDOWS path ending in .sch or .brd)"},      {"success": "bool", "savedTo": "str", "sizeBytes": "int", "format": "str (sch|brd)", "innerZipEntry": "str", "activeDocument": "str", "activeWorkspace": "str"},      60, None, False, {"outputPath": "C:/Temp/TJA1050.brd"}),
docs/aps-cloud-search.md+1−1
@@ -49,7 +49,7 @@ adom-bridge fusion_aps_signin '{"profile":"chrome:[email protected]"}'   # once per u The Client ID is per org and lives on the wiki, on the members-only `<org>/org-settings` page:  ```bash-adom-wiki api /api/v1/pages/<org>/org-settings/files/integrations/autodesk-aps.json   # -> { "clientId": ... }+adom-wiki settings get <org> autodesk-aps   # -> { "clientId": ... } ```  A new box adopts it from there, and the person then signs in with their own Autodesk login. A 404 means
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.10.34"+DASH_VERSION="1.10.35" 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.10.34",+  "version": "1.10.35",   "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.10.34",+  "version": "1.10.35",   "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]"-  }-}\ No newline at end of file+  ]+}
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.10.34"+version = "1.10.35" edition = "2021" license = "MIT" 
rust/bridge/src/aps_signin.rs+3−3
@@ -177,8 +177,8 @@ pub fn signin(ctx: &Ctx, args: &Value) -> Value {     let store = ApsStore::default_location();     let client_id = store.client_id();     if client_id.is_empty() {-        return json!({"success": false, "error": "No APS Client ID configured.", "errorCode": "aps_not_configured", "orgSettingsPath": "/api/v1/pages/<org>/org-settings/files/integrations/autodesk-aps.json",-            "_hint": format!("No APS app ID on this box. FIRST check your org's shared settings on the wiki (members-only, no secret involved): `adom-wiki whoami` names your org, then `adom-wiki api /api/v1/pages/<org>/org-settings/files/integrations/autodesk-aps.json` returns {{clientId}}. Got one: fusion_aps_set_client_id {{\"clientId\":\"<it>\"}} then fusion_aps_signin, and the person signs in with THEIR OWN Autodesk login. 404 (your org has none yet, or you work solo): one admin registers a Desktop/PKCE app ONCE at https://aps.autodesk.com (Data Management API, the callbacks below), sets it here, and publishes it to <org>/org-settings so nobody in the org ever does this again (the fusion-aps-org-setup skill has the exact file and commands). Do NOT read another machine's config files for it. Callbacks: {}.", all_registered_callbacks().join(", "))});+        return json!({"success": false, "error": "No APS Client ID configured.", "errorCode": "aps_not_configured", "orgSettingsCommand": "adom-wiki settings get <org> autodesk-aps",+            "_hint": format!("No APS app ID on this box. FIRST get your org's shared one from the wiki (members-only, nothing secret): `adom-wiki whoami` lists your orgs (belong to several? ask the user which), then `adom-wiki settings get <org> autodesk-aps` prints {{clientId}}. Got one: fusion_aps_set_client_id {{\"clientId\":\"<it>\"}} then fusion_aps_signin, and the person signs in with THEIR OWN Autodesk login. SETTINGS_NOT_FOUND (the org has none yet, or you work solo): one admin registers a Desktop/PKCE app ONCE at https://aps.autodesk.com (Data Management API, the callbacks below), sets it here, then shares it with `adom-wiki settings set <org> autodesk-aps clientId=<id> kind=public-pkce-client-id` so nobody in the org does this again (the fusion-aps-org-setup skill has every step). Never read another machine's config files for it. Callbacks: {}.", all_registered_callbacks().join(", "))});     }     let (verifier, challenge) = pkce_pair();     let mut sb = [0u8; 12]; let _ = getrandom::getrandom(&mut sb); let state = b64url(&sb);@@ -233,7 +233,7 @@ pub fn set_client_id(args: &Value) -> Value {     cfg["client_id"] = json!(cid); store.write("config.json", &cfg);     json!({"success": true, "output": format!("Saved APS Client ID ({}...). Now call fusion_aps_signin.", cid.chars().take(6).collect::<String>()), "data": {"configured": true},         "orgSettingsFile": {"path": "integrations/autodesk-aps.json", "content": {"schema": "adom.org-integration/1", "integration": "autodesk-aps", "owner": "<org>", "clientId": cid, "kind": "public-pkce-client-id", "secret": false}},-        "_hint": "Saved. NEXT: fusion_aps_signin. THEN share it so no other box in your org needs this step: if `adom-wiki api /api/v1/pages/<org>/org-settings/files/integrations/autodesk-aps.json` is a 404, save orgSettingsFile.content (with your org slug as owner) to integrations/autodesk-aps.json and `adom-wiki repo push <org>/org-settings --files integrations/autodesk-aps.json` (create the page first, private, with `adom-wiki page create org-settings --org <org> --private --type skill ...`). It is a public PKCE identifier, never a secret. The fusion-aps-org-setup skill walks through it."})+        "_hint": format!("Saved. NEXT: fusion_aps_signin. THEN share it so no other box in your org needs this step: if `adom-wiki settings get <org> autodesk-aps` answers SETTINGS_NOT_FOUND, run `adom-wiki settings set <org> autodesk-aps clientId={cid} kind=public-pkce-client-id` (it refuses anything secret-shaped, and when <org>/org-settings does not exist yet it prints the one `page create` command to run first). It is a public PKCE identifier, never a secret. The fusion-aps-org-setup skill walks through it.")}) } pub fn set_browser(args: &Value) -> Value {     let store = ApsStore::default_location();
rust/bridge/src/main.rs+8−2
@@ -419,7 +419,13 @@ fn main() {                         let side = |verb: &str, a: Value, t: u64| proxy_with_timeout(&sc, &json!({"command": verb, "args": a}).to_string(), &ca, t);                         let dlg = |res: Value| small_verbs::merge_dialog_array(res, &ca, &pids);                         let ctx = addin::Ctx { host: &**h, fusion_exe: h.fusion_executable(), short_path: |p| host().short_path(p), state_dir: sd.clone(), caller: caller.clone(), pids: pids.clone(), sidecar: &side, dialogs: &dlg };-                        let mut r = if matches!(cmd.as_str(), "show_schematic" | "show_2d_board" | "show_3d_board") { orchestrations::show_with_document(&cmd, &parsed["args"], &|v, a| addin::pass_through(v, &a, &ctx)) } else { addin::pass_through(&cmd, &parsed["args"], &ctx) };+                        let pt = |v: &str, a: Value| addin::pass_through(v, &a, &ctx);+                        let mut r = match cmd.as_str() {+                            "show_schematic" | "show_2d_board" | "show_3d_board" => orchestrations::show_with_document(&cmd, &parsed["args"], &pt),+                            "export_source" | "export_eagle_source" => orchestrations::export_in_right_view(&cmd, &parsed["args"], &pt),+                            "activate_document" => orchestrations::activate_with_same_name_note(&parsed["args"], &pt),+                            _ => addin::pass_through(&cmd, &parsed["args"], &ctx),+                        };                         ind.stop(r["success"].as_bool() == Some(false));                         timings::log_run(&sd, &cmd, t0.elapsed().as_secs_f64(), r["success"].as_bool() != Some(false));                         r["shell"] = json!("rust"); r },@@ -1181,7 +1187,7 @@ fn native_aps_status(sidecar: &Arc<Mutex<Option<Sidecar>>>, caller: &Caller) ->         "freeEndpointsOnly": FREE_PATH_PREFIXES, "neverCharge": true,     });     let (hint, summary) = if client_id.is_empty() {-        (format!("Not configured: this box has no APS app ID. FIRST look in your org's shared settings on the wiki (members-only, nothing secret): `adom-wiki whoami` names your org, then `adom-wiki api /api/v1/pages/<org>/org-settings/files/integrations/autodesk-aps.json` returns {{clientId}}. Got one: fusion_aps_set_client_id {{\"clientId\":\"<it>\"}} then fusion_aps_signin (the person signs in with their OWN Autodesk login). 404: one admin registers a Desktop/PKCE app ONCE at https://aps.autodesk.com (enable Data Management API, set callbacks {}), sets it here, and publishes it to <org>/org-settings so the rest of the org never repeats this (fusion-aps-org-setup skill). Do NOT read another machine's config files for it.", all_registered_callbacks().join(", ")), "APS not configured")+        (format!("Not configured: this box has no APS app ID. FIRST get your org's shared one from the wiki (members-only, nothing secret): `adom-wiki whoami` lists your orgs (several? ask the user which), then `adom-wiki settings get <org> autodesk-aps` prints {{clientId}}. Got one: fusion_aps_set_client_id {{\"clientId\":\"<it>\"}} then fusion_aps_signin (the person signs in with their OWN Autodesk login). SETTINGS_NOT_FOUND: one admin registers a Desktop/PKCE app ONCE at https://aps.autodesk.com (enable Data Management API, set callbacks {}), sets it here, and shares it with `adom-wiki settings set <org> autodesk-aps clientId=<id> kind=public-pkce-client-id` so the rest of the org never repeats this (fusion-aps-org-setup skill). Never read another machine's config files for it.", all_registered_callbacks().join(", ")), "APS not configured")     } else if !has_at { ("Configured but not signed in. Call fusion_aps_signin (opens browser).".into(), "configured, not signed in") }     else if !live { ("Token expired and refresh failed. Call fusion_aps_signin again.".into(), "signed in, token expired") }     else { ("Ready. Use fusion_aps_search {\"query\":\"...\"}.".into(), "ready") };
rust/bridge/src/orchestrations.rs+61
@@ -518,6 +518,67 @@ pub fn show_project(ctx: &Ctx, args: &Value, pass: &dyn Fn(&str, Value) -> Value     Some(out) } +/// `fusion_export_source` / `fusion_export_eagle_source` write whatever editor is ACTIVE, and an+/// electronics design's schematic, board and 3D view are separate tabs with ONE name. From the+/// board editor a .sch export answered "No .sch file found inside .fsch ZIP container" (reads as a+/// corrupt file) and a .fsch export silently wrote a container holding only the .brd (page issue+/// #95, adonis/nametag-blank-large-led). The extension says which editor the caller wants, so the+/// bridge switches to it first (the same SwitchSchDocCmd / SwitchPcbDocCmd the show verbs run)+/// and says so. A .flbr needs a library, which is not a view of a design: left alone.+pub fn export_in_right_view(cmd: &str, args: &Value, pass: &dyn Fn(&str, Value) -> Value) -> Value {+    let out = args["outputPath"].as_str().unwrap_or("").to_ascii_lowercase();+    let (want_ws, switch_verb, label) = if out.ends_with(".sch") || out.ends_with(".fsch") { ("Schematic Editor", "show_schematic", "schematic") }+        else if out.ends_with(".brd") || out.ends_with(".fbrd") { ("PCB Editor", "show_2d_board", "2D board") }+        else { return pass(cmd, args.clone()) };+    let ws_now = |r: &Value| r["data"]["activeWorkspace"].as_str().or(r["activeWorkspace"].as_str()).unwrap_or("").to_string();+    let before = ws_now(&pass("get_app_state", json!({})));+    let mut switched = Value::Null;+    if !before.is_empty() && before != want_ws {+        let sw = pass(switch_verb, json!({}));+        if sw["success"].as_bool() == Some(true) { switched = json!({"from": before, "to": want_ws, "via": format!("fusion_{switch_verb}")}); }+        else {+            return json!({"success": false, "errorCode": "wrong_editor_active",+                "error": format!("{} needs the {label} editor active, and the {before} is. Switching with fusion_{switch_verb} failed: {}", out.rsplit(['/', '\\']).next().unwrap_or(&out), sw["error"].as_str().unwrap_or("unknown")),+                "_hint": format!("Open the electronics DESIGN first (fusion_open_cloud_file / fusion_open_by_urn), then fusion_{switch_verb} {{documentName}} and retry. fusion_document_info lists the open tabs.")});+        }+    }+    let mut r = pass(cmd, args.clone());+    if r["success"].as_bool() == Some(false) && r["error"].as_str().map(|e| e.contains("found inside")).unwrap_or(false) {+        r["errorCode"] = json!("wrong_editor_active");+        r["_hint"] = json!(format!("The file is not corrupt: the container Fusion wrote holds the view that was ACTIVE, not the {label}. Run fusion_{switch_verb} {{documentName}} and retry (the bridge normally does this itself; it could not confirm the switch this time)."));+    }+    if !switched.is_null() && r.is_object() {+        r["switchedView"] = switched;+        let h = r["_hint"].as_str().unwrap_or("").to_string();+        r["_hint"] = json!(format!("The bridge switched to the {label} editor first, because a {} export writes the ACTIVE editor. {h}", out.rsplit('.').next().unwrap_or("")).trim().to_string());+    }+    r+}++/// `fusion_activate_document`: an electronics design opens as several tabs that all carry the+/// design's name, and Fusion reports their type as unknown, so "activate by name" picks one of+/// them. Say so, and name the verbs that reach a specific view (page issue #95).+pub fn activate_with_same_name_note(args: &Value, pass: &dyn Fn(&str, Value) -> Value) -> Value {+    let mut r = pass("activate_document", args.clone());+    let want = args["name"].as_str().unwrap_or("").trim().to_lowercase();+    if want.is_empty() { return r; }+    let info = pass("document_info", json!({}));+    let docs: Vec<String> = info["data"]["openDocuments"].as_array().or(info["openDocuments"].as_array()).map(|a| a.iter().filter_map(|d| d["name"].as_str().map(str::to_string)).collect()).unwrap_or_default();+    let exact = docs.iter().filter(|n| n.to_lowercase() == want).count();+    let loose = docs.iter().filter(|n| n.to_lowercase().contains(&want)).count();+    let views = "To reach a specific view of an electronics design use fusion_show_schematic, fusion_show_2d_board or fusion_show_3d_board with {documentName}: each activates the design and switches to that editor.";+    if exact > 1 || (exact == 0 && loose > 1) {+        let n = if exact > 1 { exact } else { loose };+        r["sameNameDocuments"] = json!(n);+        let h = r["_hint"].as_str().unwrap_or("").to_string();+        r["_hint"] = json!(format!("{n} open tabs match '{}': an electronics design's schematic, board and 3D views are separate tabs with ONE name, and Fusion reports their type as unknown, so this activated one of them. {views} {h}", args["name"].as_str().unwrap_or("")).trim().to_string());+    } else if r["success"].as_bool() == Some(false) && docs.is_empty() == false {+        let h = r["_hint"].as_str().unwrap_or("").to_string();+        r["_hint"] = json!(format!("{h} {views}").trim().to_string());+    }+    r+}+ /// The three view-switch verbs act on the ACTIVE document; this names the one the caller means /// and explains the wrong-document failure. Called from the dispatcher's add-in arm (which is /// where show_* really run) and from `open_with_screenshot`.
skills/fusion-aps-org-setup/SKILL.md+12−19
@@ -1,6 +1,6 @@ --- name: fusion-aps-org-setup-description: How an ORG (or a solo user) gets Fusion cloud search (APS) working on every box with one admin setup - where the org's APS app ID lives (the members-only <org>/org-settings wiki page), how a new box adopts it in two calls, how the first admin registers the Autodesk app and publishes the ID for everyone else, and what each person still does themselves (one Autodesk sign-in). Read this whenever fusion_aps_status says configured:false, before telling anyone to register an APS app, and before copying an ID between machines. Trigger words - aps not configured, aps_not_configured, fusion_aps_set_client_id, APS client id, share aps id, org settings, org-settings, autodesk-aps.json, set up aps for my company, aps first time setup, new box aps, cloud search not set up, consent window not visible.+description: How an ORG (or a solo user) gets Fusion cloud search (APS) working on every box with one admin setup - where the org's APS app ID lives (the members-only <org>/org-settings wiki page), how a new box adopts it in two calls, how the first admin registers the Autodesk app and publishes the ID for everyone else, and what each person still does themselves (one Autodesk sign-in). Read this whenever fusion_aps_status says configured:false, before telling anyone to register an APS app, and before copying an ID between machines. Trigger words - aps not configured, adom-wiki settings, settings get autodesk-aps, aps_not_configured, fusion_aps_set_client_id, APS client id, share aps id, org settings, org-settings, autodesk-aps.json, set up aps for my company, aps first time setup, new box aps, cloud search not set up, consent window not visible. ---  # APS for a whole org: one admin setup, then everyone just signs in@@ -14,20 +14,22 @@ Fusion cloud search uses Autodesk Platform Services (APS) with PKCE, so there is ## A. New box, org already set up (the common case, about a minute)  ```bash-adom-wiki whoami                                   # "orgs": your org slug, e.g. adom-adom-wiki api /api/v1/pages/<org>/org-settings/files/integrations/autodesk-aps.json-#   -> { "clientId": "...", "secret": false, ... }      404 = go to section B+adom-wiki whoami                                   # "orgs": your org slug(s)+adom-wiki settings get <org> autodesk-aps          # -> { "clientId": "...", "secret": false, ... } adom-bridge --target <box> fusion_aps_set_client_id '{"clientId":"<clientId>"}' adom-bridge --target <box> fusion_aps_signin '{}' adom-bridge --target <box> fusion_aps_status '{}'  # poll until signedIn:true ``` +- **Which org.** Use the one `whoami` lists. If you belong to several, ask the user which org this box works for: never guess.+- **SETTINGS_NOT_FOUND** means the org has not published one, or you are not a member. Go to section B. - The wiki read uses YOUR wiki token inside the container. The desktop box never needs a wiki token.+- `adom-wiki settings show <org>` lists every integration the org has published. - Sign-in opens a browser window on the box. With a warm Autodesk session it completes by itself. Otherwise the person signs in there: never type their password or 2FA code for them.-- Since 1.10.33 the bridge finds a sign-in window that needs a human and puts it on the primary monitor, in front. On older bridges it could be parked off-screen at -32000: `desktop_list_windows`, find "Sign in - Autodesk", then `desktop_set_window_bounds {hwnd,x,y,w,h}` and `desktop_bring_to_front {hwnd, reason}`.+- Since 1.10.33 the bridge finds a sign-in window that needs a human and puts it on the primary monitor, in front. If one is still missing: `desktop_list_windows`, find "Sign in - Autodesk" (a window at -32000 is parked off-screen), then `desktop_set_window_bounds {hwnd,x,y,w,h}` and `desktop_bring_to_front {hwnd, reason}`. - Whose Autodesk login? The same account Fusion uses on that box is the natural choice: search then sees exactly what that person sees in Fusion. -**Never** read another machine's `~/.adom/fusion-aps/config.json` to find the ID. It looks like credential hunting, permission systems block it, and the wiki page exists so you do not have to.+**Never** read another machine's `~/.adom/fusion-aps/config.json` to find the ID. It looks like credential hunting, permission systems block it, and the wiki settings exist so you do not have to.  ## B. First time for this org (one admin, once) @@ -35,22 +37,13 @@ adom-bridge --target <box> fusion_aps_status '{}'  # poll until signedIn:true 2. Enable the **Data Management API** on the app. Without it sign-in fails with AUTH-001 before any login. 3. Add every callback `fusion_aps_status` lists (six localhost URLs on ports 8917, 8918, 8920). 4. Copy the Client ID. `fusion_aps_set_client_id {clientId}`, then `fusion_aps_signin`.-5. **Publish it for the org** so nobody repeats steps 1 to 4. `fusion_aps_set_client_id` returns `orgSettingsFile.content` ready to save:+5. **Share it with the org** so nobody repeats steps 1 to 4:  ```bash-adom-wiki page create org-settings --org <org> --private --type skill \-  --title "<Org> Org Settings" \-  --brief "Shared, non-secret integration IDs for <org>, read by every member's AI." \-  --because "No page holds org-wide integration IDs; brand is a visual guide with its own confirm gate." \-  --headline "One sign-in, every box" \-  --subhead "Your org's shared integration IDs, read by your AI so nobody copies config between machines"-adom-wiki repo clone <org>/org-settings && cd org-settings-mkdir -p integrations    # save orgSettingsFile.content here, owner = your org slug:-#   integrations/autodesk-aps.json-adom-wiki repo push <org>/org-settings --files integrations/autodesk-aps.json -m "APS app id for the org"+adom-wiki settings set <org> autodesk-aps clientId=<id> kind=public-pkce-client-id ``` -A solo user does the same under their own username instead of `--org`.+`settings set` refuses anything secret-shaped and writes nothing in that case. If `<org>/org-settings` does not exist yet, it prints the one `adom-wiki page create org-settings ...` command to run first; run it, then repeat the `set`. A solo user does the same with their own username as the owner.  ## The file @@ -73,4 +66,4 @@ One Autodesk sign-in per box, in the browser window the bridge opens. Tokens are  ## Status of the standard -`<org>/org-settings` is a convention the Fusion bridge uses today. A first-class org-default settings repo (auto-created beside `<org>/brand`, with CLI sugar) is proposed in [adom/adom-wiki-cli issue 59](https://wiki.adom.inc/adom/adom-wiki-cli/issues/59). If that lands with a different name or path, the bridge hints and this skill move with it.+`<org>/org-settings` and the `adom-wiki settings show|get|set` commands (adom-wiki 1.7.55+) came out of [adom/adom-wiki-cli issue 59](https://wiki.adom.inc/adom/adom-wiki-cli/issues/59). The page is created on first write, never automatically, so SETTINGS_NOT_FOUND always means "this org has not set one up". Open on the wiki side: a dedicated page type for settings (today the page is typed `skill`).
skills/fusion-aps-search/SKILL.md+1−1
@@ -106,7 +106,7 @@ for cloud search, ever — no matter how blocked you feel.  **Auto-recover APS (do this instead of giving up):** 1. **Not configured?** The org Client ID is a **public PKCE identifier** (no secret) and lives on the-   wiki: `adom-wiki api /api/v1/pages/<org>/org-settings/files/integrations/autodesk-aps.json` (your org+   wiki: `adom-wiki settings get <org> autodesk-aps` (your org    from `adom-wiki whoami`), then `fusion_aps_set_client_id {clientId}`. A 404 means the org has not    published one: the **fusion-aps-org-setup** skill covers the one-time admin setup and publishing it.    Do NOT read another machine's config file for it.
skills/fusion-electronics/SKILL.md+4
@@ -47,6 +47,10 @@ The design is open; switch the LIVE editor between its three views with the symm - All three show verbs take `documentName`: with more than one tab open (a board plus its library is the   usual pair) pass it and the bridge activates that document first. Without it they act on the ACTIVE   document and answer `not_an_electronics_design` plus `openDocuments` when a library or 3D design is in front.+- An open electronics design is several tabs with ONE name (3D design, board, schematic), all typed+  unknown, so `fusion_activate_document {name}` lands on one of them. Reach a view with the show verbs.+  The export verbs switch for you: a `.sch`/`.fsch` export moves to the Schematic Editor first and a+  `.brd`/`.fbrd` export to the PCB Editor (reply `switchedView`), since 1.10.35. - `fusion_show_3d_board` - the populated 3D PCB. `Switch3dPcbDocCmd`.  All three move the VISIBLE editor (not just the API's active doc), so they're what you use to set up a
skills/fusion-molecule-export/SKILL.md+1−1
@@ -32,7 +32,7 @@ It can. The verbs exist today:  Notes learned the hard way: - `fusion_export_eagle_source` picks board vs schematic from the **active editor**, so switch first-  (`fusion_show_2d_board` -> export `.brd`; `fusion_show_schematic` -> export `.sch`). Tested: 840 KB+  (`fusion_show_2d_board` -> export `.brd`; `fusion_show_schematic` -> export `.sch`). Since 1.10.35 the export verbs switch to the matching editor themselves, so from the board editor a `.sch` export just works. Tested: 840 KB   `.brd` + 623 KB `.sch` off a ~110-part board. - Do NOT try raw EAGLE `WRITE 'path'` via `fusion_electron_run`: the bridge BLOCKS it because on cloud   documents `WRITE` opens a blocking "Version Description" save dialog and hangs. `fusion_export_eagle_source`
tools/check-naming.sh

  
tools/check-portable.sh

  
tools/promote.sh

  
tools/release.sh