← Commit history

v1.6.69: programmatic APS AUTH-001 self-heal - start_signin probes /authorize server-side, detects 'app lost Data Management API product' BEFORE opening a browser, returns errorCode aps_app_missing_product + the exact ABE-driven recovery recipe; full recovery playbook added to fusion-aps-signin skill

John Lauer ·7f5931ef2a ·3mo ago ·parent 137d8dc
6 files changed +112−6
BRIDGE_VERSION+1−1
@@ -1 +1 @@-1.6.68\ No newline at end of file+1.6.69\ No newline at end of file
adom-bridge-fusion-manifest.json+4−4
@@ -1,10 +1,10 @@ {   "manifest_version": 1,   "name": "fusion360",-  "version": "1.6.68",-  "url": "https://wiki.adom.inc/download/adom/adom-desktop-fusion-bridge/1.6.68/adom-bridge-fusion-v1.6.68.zip",-  "sha256": "0d16913c7b3f7bcd17c34d4419534ebc4ac008c43ec93eca56c7061ba90bae82",-  "size": 362037,+  "version": "1.6.69",+  "url": "https://wiki.adom.inc/download/adom/adom-desktop-fusion-bridge/1.6.69/adom-bridge-fusion-v1.6.69.zip",+  "sha256": "c2445f85d630be582aec04e859ab2d3b5aba6ff34a3666e2892d58f7967d03b5",+  "size": 364866,   "verbPrefixes": [     "fusion_"   ],
aps.py+68
@@ -95,6 +95,54 @@ APS_REQUIRED_HINT = (     "a few minutes to propagate, retry." ) ++def _aps_auth001_recovery_hint(client_id: str) -> str:+    """The programmatic self-heal for APS AUTH-001, returned by start_signin the moment it detects the+    app lost its Data Management API PRODUCT (John 2026-07-14: an AI figured this out live over an hour;+    no future AI should have to). The bridge can't drive aps.autodesk.com itself, so this is the exact+    ABE/nbrowser recipe the calling AI runs - deterministic, verified live."""+    return (+        "⚠ APS AUTH-001 - the APS app (Client ID " + (client_id[:8] + "...") + ") LOST its Data Management "+        "API product, so authorize fails BEFORE any login. This is fixable; here is the exact recovery "+        "(drive with ABE/nbrowser - if not installed, install adom-browser-extension first, it is the "+        "ONLY reliable way to drive the portal): "+        "(1) nbrowser_open_window {sessionId, thread, purpose, profile:<the warm Edge/Chrome profile>, "+        "url:'https://aps.autodesk.com/myapps/'} and open the app whose Client ID is this one. "+        "(2) On the app's App-settings page, API Access section: confirm 'Data Management API' is checked, "+        "then FORCE a re-commit - nbrowser_eval a click on the VISIBLE 'Save changes' button (filter "+        "buttons by /save changes/i AND offsetParent!==null; the bare text matches ~9 hidden duplicates so "+        "text-click is ambiguous). If Save is disabled, toggle any one unneeded API off first to dirty the "+        "form. (3) WAIT ~1-3 min for Autodesk to propagate. (4) Retry fusion_aps_signin; authorize now "+        "reaches the CONSENT screen ('<app> is requesting permission ... View/Manage/Write your data ... "+        "Allow') - nbrowser_navigate the session to the new authUrl, then nbrowser_click 'Allow'; the URL "+        "flips to localhost:<port>/fusion-aps/callback?code=... and the bridge captures the token. "+        "(5) Poll fusion_aps_status until signedIn:true. Verified live 2026-07-14."+    )+++def _probe_authorize_auth001(auth_url: str) -> bool:+    """Server-side probe: does this app's /authorize return AUTH-001 (no api-product access)? The check+    happens BEFORE any user login, so the bridge can detect a broken app WITHOUT a browser and hand back+    the recovery recipe immediately (instead of the AI opening a browser only to hit the JSON error).+    A healthy app 302-redirects to login/consent (no AUTH-001 body); a broken one returns the AUTH-001+    JSON. Never raises; returns False on any ambiguity (don't false-block a real sign-in)."""+    class _NoRedirect(urllib.request.HTTPRedirectHandler):+        def redirect_request(self, *a, **k):+            return None  # a redirect means the app is FINE - stop, don't chase the login page+    try:+        opener = urllib.request.build_opener(_NoRedirect)+        try:+            body = opener.open(urllib.request.Request(auth_url), timeout=8).read().decode("utf-8", "replace")+        except urllib.error.HTTPError as e:+            if e.code in (301, 302, 303, 307, 308):+                return False  # redirect to login = healthy app+            body = (e.read() or b"").decode("utf-8", "replace")+        except Exception:+            return False+        return ("AUTH-001" in body) or ("does not have access to the api product" in body.lower())+    except Exception:+        return False+ APS_DIR = Path(os.path.expanduser("~")) / ".adom" / "fusion-aps" CONFIG_FILE = APS_DIR / "config.json" TOKENS_FILE = APS_DIR / "tokens.json"@@ -449,6 +497,26 @@ def start_signin(args: dict | None = None) -> dict:     }     auth_url = AUTH_URL + "?" + urllib.parse.urlencode(params) +    # ── PROGRAMMATIC AUTH-001 SELF-HEAL (John 2026-07-14) ────────────────────────────────────────+    # Detect a broken APS app (lost its Data Management API PRODUCT) SERVER-SIDE, before opening any+    # browser, and hand back the exact ABE-driven recovery recipe. Without this, the AI opens a browser,+    # hits a raw AUTH-001 JSON error page, and has to reverse-engineer the fix (it once took an hour).+    if _probe_authorize_auth001(auth_url):+        try:+            server.server_close()+        except Exception:+            pass+        with _signin_lock:+            _signin_state = None+        return {"success": False,+                "error": "APS AUTH-001: the app's Client ID does not have access to the Data Management API product.",+                "errorCode": "aps_app_missing_product",+                "authUrl": auth_url,+                "appManagementUrl": "https://aps.autodesk.com/myapps/",+                "clientId": client_id,+                "recoverable": True,+                "_hint": _aps_auth001_recovery_hint(client_id)}+     # ── SMART BROWSER CHOICE (John, 2026-07-08: "power users have tons of browsers with tons     #    of profiles ... cache what browser you used when you successfully logged in ... don't     #    be lazy") ─────────────────────────────────────────────────────────────────────────
bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "fusion360",   "displayName": "Autodesk Fusion 360",-  "version": "1.6.68",+  "version": "1.6.69",   "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/adom-desktop-fusion-bridge",   "author": "Adom Inc.",
skills/fusion-aps-signin/SKILL.md+26
@@ -245,3 +245,29 @@ Windows reserved ranges (5357, 27339, 50000-50059). The box runs ~67 listeners    relevant when reading `fusion_aps_*` results (fields live under `data`). - Don't auto-enter the user's Autodesk **password** or drive their Google **consent** —   identity decisions are theirs; automate the OTP + form-filling, not the credentials.++## ⭐ APS AUTH-001 self-heal — the app lost its Data Management API product (verified live 2026-07-14)++**Symptom:** `fusion_aps_signin` now returns `errorCode: "aps_app_missing_product"` (the bridge probes+the /authorize endpoint server-side and detects it BEFORE opening a browser), or you see the raw+`{"errorCode":"AUTH-001","developerMessage":"The client_id specified does not have access to the api+product"}` on the authorize page. It means the org's APS app at aps.autodesk.com/myapps lost its **Data+Management API** product entitlement (it can work for months, then break). The app config often still+*looks* correct — the fix is a forced re-commit.++**Recovery (drive with ABE/nbrowser — install the extension FIRST if it isn't; coordinate-clicking the+portal is fragile and Edge crashes):**+1. `nbrowser_open_window {sessionId, thread, purpose, profile:<warm Edge/Chrome>, url:"https://aps.autodesk.com/myapps/"}` → open the app whose Client ID matches (in the org's "Adom APS" dev hub).+2. App-settings → **API Access**: confirm **Data Management API** is checked. Then force a re-commit —+   `nbrowser_eval` a click on the **visible** Save button:+   `(()=>{var b=[...document.querySelectorAll("button")].filter(x=>/save changes/i.test(x.textContent)&&x.offsetParent!==null);if(b.length)b[0].click();return JSON.stringify({n:b.length})})()`+   (the bare text "Save changes" matches ~9 hidden duplicates, so `nbrowser_click {text}` is ambiguous —+   use the offsetParent filter). If Save is disabled, open the API dropdown and toggle one unneeded API+   off first to dirty the form.+3. **Wait 1–3 min** for Autodesk to propagate the entitlement.+4. Retry `fusion_aps_signin` → it now reaches the **consent** screen ("… is requesting permission …+   View/Manage/Write your data … **Allow**"). `nbrowser_navigate` the session to the fresh `authUrl`,+   then `nbrowser_click {text:"Allow"}` → the URL flips to `localhost:<port>/fusion-aps/callback?code=…`+   and the bridge's listener captures the token.+5. Poll `fusion_aps_status` until `signedIn:true`. Done — APS search is fast and never touches Fusion's+   main thread.
skills/fusion-autodesk-signin/SKILL.md+12
@@ -98,3 +98,15 @@ drivable: `fusion_open_lbr`, `fusion_build_library_3d`, exports, GPU/graphics ch ## Related - `fusion-onboarding` — the install that precedes this (streams Fusion, then hands off here). - `fusion-bridge-dev` — how the bridge detects installed/installing/ready (Fusion360.exe completeness).++## ⭐ FIRST RULE FOR ANY BROWSER AUTOMATION: install + use ABE (nbrowser), don't coordinate-click (John, emphatic 2026-07-14)++The MOMENT a task needs you to DRIVE a browser (the Autodesk OAuth, the APS portal at+aps.autodesk.com/myapps, any web form), your FIRST move is to **recommend and install the+adom-browser-extension (ABE / nbrowser)** and drive via `nbrowser_*` (JS-level: read the DOM, click by+selector/text, reliably). Do NOT limp along with `desktop_click`/SendKeys coordinate-driving — on a VM+that Edge crashes, tabs multiply, buttons sit at the nav edge and clicks miss, and you waste enormous+time (learned the hard way here). Tell the user up front: "I need to install ABE to automate this+browser reliably." Install: `bridge_install {manifestUrl: .../adom-browser-extension/files/native-browser-bridge-manifest.json}`,+then the `installing-the-extension` flow, then `nbrowser_readiness` until `state:"ready"`. Coordinate-+driving is the fallback of last resort, never the default.