← Commit history
BRIDGE_VERSION+1−1
@@ -1 +1 @@-0.9.16+0.9.17
Cargo.lock+1−1
@@ -107,7 +107,7 @@ dependencies = [  [[package]] name = "swx-bridge"-version = "0.9.16"+version = "0.9.17" dependencies = [  "serde",  "serde_json",
Cargo.toml+1−1
@@ -1,6 +1,6 @@ [package] name = "swx-bridge"-version = "0.9.16"+version = "0.9.17" edition = "2021" rust-version = "1.80" description = "Adom SOLIDWORKS bridge — swx_* verbs over the SOLIDWORKS COM API, as a single native binary"
README.md+6−1
@@ -461,7 +461,12 @@ not.  ## Roadmap -- v0.9.16 (this): **any login window, typed where it really is.** Measured on+- v0.9.17 (this): **the resize is the measured one.** The window-tall-enough step+  that clears the cookie banner now calls `desktop_set_window_bounds+  {hwnd, x:300, y:30, w:1100, h:1450}` — the call that was measured to work on+  2026-10-02 (email box at y=787, banner at y=1020) — instead of a resize verb+  that had never been observed on ab. No other behaviour changed.+- v0.9.16: **any login window, typed where it really is.** Measured on   the Visualize login window: page 2 (its "Remember me" checkbox is off-screen,   so its visible label is what gets clicked), the page re-lays when the window   moves (clicks now land at the field's own fresh centre, and a banner over the
bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "solidworks",   "displayName": "SOLIDWORKS",-  "version": "0.9.16",+  "version": "0.9.17",   "description": "Bridge for SOLIDWORKS desktop CAD \u2014 create and open documents, a modeling DSL, file management (find/open/save/export/Pack and Go), custom properties, BOM generation, design analysis (mass properties, bodies, parameters, interference, rebuild health) and background window/dialog etiquette, over the SOLIDWORKS COM API. Single native binary: no interpreter, no PowerShell, ~10ms cold start.",   "author": "Adom Inc.",   "license": "MIT",
docs/LAUNCH-RESILIENCE.md+1−1
@@ -1352,7 +1352,7 @@ unmeasured, and NO credentials — only where they come from in general terms. | | Measured | 0.9.16 | |---|---|---| | P1 — page 2 | Edit "Email or username" (prefilled), Edit "Password " (automationId `password`), CheckBox "Remember me " (toggleState off, rect OFF-SCREEN: centerX -14493 — the native input is hidden; the visible control is the Text "Remember me…"), Button "Log in", Button "Back", the cookie banner still present | Page 2 is now a measured fixture. "Remember me": already on → nothing; an on-screen invokable box → a background Invoke; an off-screen one → a real click on its visible LABEL (only while the user is idle, with the window raised and in front), then the toggle state read again; a tick that cannot be made safely is skipped and said, never failing the sign-in |-| P2 — geometry moves | moving the window re-laid the page; the cookie banner then COVERED the email box; a click at the earlier point hit the banner, select-all selected page text, the typing went nowhere | Before every real click the tree is RE-READ and the click lands at the field's own `rect.centerX/centerY` in screen px (`desktop_click {x, y}`). A field a cookie-banner element overlaps → the window is made 1100x1450 (`desktop_ui_window {action:"resize"}` — arguments UNMEASURED) and re-read; still covered → `sign_in_needs_user` (the banner is the user's) |+| P2 — geometry moves | moving the window re-laid the page; the cookie banner then COVERED the email box; a click at the earlier point hit the banner, select-all selected page text, the typing went nowhere | Before every real click the tree is RE-READ and the click lands at the field's own `rect.centerX/centerY` in screen px (`desktop_click {x, y}`). A field a cookie-banner element overlaps → the window is made 1100x1450 (`desktop_set_window_bounds {hwnd, x:300, y:30, w:1100, h:1450}` — MEASURED 2026-10-02: replied ok, email box at y=787 above the banner at y=1020) and re-read; still covered → `sign_in_needs_user` (the banner is the user's) | | P3 — focus | a plain click does not take focus while the user's app is active (the login thread's focus was 0); `desktop_raise_window {hwnd, reason}` brings it forward and then the click lands; `desktop_type {text, hwnd:<Chrome_RenderWidgetHostHWND child>}` types; reading the user name back works | Raise, confirm the login window is the foreground window, click, then select-all and type to the render widget when the tree names its handle (else the window) | | P4 — the vault | now holds the login (host iam.3ds.com, stored with `credential_set`) | The reveal asks the host the vault lists on the 3ds.com domain (`iam.*` first) | | P5 — policy | typing the password through ab FROM THE CLOUD is refused by the auto-mode classifier ("Credential Leakage") — rightly | The only path is the bridge reading the vault LOCALLY and typing locally. So `swx_sign_in {userAuthorized:true}` (the user's say-so) answers ANY 3DEXPERIENCE ID login window on the machine — our launch chain's, SOLIDWORKS Visualize's (`SLDWORKSVisualize.exe` is now in the census), any Dassault process's — and reports which process owns it; `window:"visualize"\|"solidworks"\|<hwnd>` picks one when several are up (`sign_in_window_ambiguous` otherwise). Without the authorization, only the bridge's own launch's window. This wires the unwired half of T4 |
install.sh

  
package.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "solidworks-bridge",-  "version": "0.9.16",+  "version": "0.9.17",   "type": "app",   "description": "Skills for your container so your AI knows how to drive the SOLIDWORKS bridge (swx_* verbs). The bridge runtime itself is the release zip — a single native swx-bridge.exe; Adom Bridge loads that.",   "tags": [
skills/solidworks-sign-in/SKILL.md+2−1
@@ -65,7 +65,8 @@ Every line below is marked **[measured]** (seen on a real machine, 2026-10-02) o   the email box, a click at the old point hit the banner, select-all selected   page text, and the typing went nowhere. After any move or resize, re-read the   tree and click at the control's OWN `rect.centerX/centerY` (screen pixels).-  A window of about 1100x1450 kept the box clear of the banner.+  `desktop_set_window_bounds {hwnd, x:300, y:30, w:1100, h:1450, reason}` kept+  the box clear of the banner (email box at y=787, banner at y=1020). - [measured] A plain click does not take focus while the user's own app is   active. `desktop_raise_window {hwnd, reason}` brings the login window   forward; confirm it IS the foreground window before typing.
src/signin.rs+6−4
@@ -1218,11 +1218,13 @@ fn fill_field(hwnd: i64, el: &Element, text: &[u8], read_back: bool, steps: &mut     let mut spot = locate(hwnd, el);     if let Some(sp) = &spot {         if sp.covered {-            // Make the window tall enough that the field clears the banner-            // (MEASURED: 1100x1450 worked). The resize arguments are UNMEASURED.+            // Make the window tall enough that the field clears the banner.+            // MEASURED 2026-10-02 on ab 2.1.163: desktop_set_window_bounds+            // {hwnd, x:300, y:30, w:1100, h:1450, reason} replied "ok" and the+            // email box then sat at y=787, the banner at y=1020 (keys are w/h).             let _ = crate::caller::ad_callback(-                "desktop_ui_window",-                json!({"action": "resize", "hwnd": hwnd, "width": 1100, "height": 1450, "reason": FILL_REASON}),+                "desktop_set_window_bounds",+                json!({"hwnd": hwnd, "x": 300, "y": 30, "w": 1100, "h": 1450, "reason": FILL_REASON}),                 AB_TIMEOUT,             );             std::thread::sleep(Duration::from_millis(wake_ms()));
tests/signin.rs+2−1
@@ -1077,7 +1077,8 @@ fn a_cookie_banner_over_the_field_is_never_clicked_through() {         b,         "covered: the window was made taller, the field still covered -> sign_in_needs_user (the banner is the user's); no click, no typing",         r["errorCode"] == "sign_in_needs_user" && r["cookieBanner"] == true-            && ab.calls_to("desktop_ui_window").iter().any(|c| c["args"]["action"] == "resize" && c["args"]["height"] == 1450)+            && ab.calls_to("desktop_set_window_bounds").iter().any(|c| c["args"]["w"] == 1100 && c["args"]["h"] == 1450 && c["args"]["hwnd"].is_number())+            && ab.calls_to("desktop_ui_window").is_empty()             && ab.calls_to("desktop_click").is_empty() && ab.calls_to("desktop_type").is_empty(),         s(&r)     );
uninstall.sh