← Commit history

v0.16.49 (insiders): nb-bridge#55: wait for the export control to appear (a freshly opened window has only browser chrome in the accessibility tree at first, which made the verb report 'renamed again' when the page had simply not rendered), and reuse its rect for the real-click fallback

John Lauer ·4760a72180 ·13d ago ·parent f32cb32
6 files changed +22−12
bin/nb-dashboard+1−1
@@ -20,7 +20,7 @@ const { execFile, spawn } = require('child_process'); const fs = require('fs'); const crypto = require('crypto'); -const VERSION = '0.16.48';           // keep in lockstep with package.json (pkg version)+const VERSION = '0.16.49';           // keep in lockstep with package.json (pkg version) // SEND TO AI IS UN-PARKED (John: "yeah, we are re-enabling the send to ai. it seems to be good now"). // The ah build thread certified the crash family dead on the gate-fixed build and the delivery leg is // proven end to end. The park const is DELETED rather than flipped, so no dead branch can resurrect it.
bridge/BRIDGE_VERSION+1−1
@@ -1 +1 @@-0.16.48\ No newline at end of file+0.16.49\ No newline at end of file
bridge/bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "native-browser",   "displayName": "Adom Native Browser",-  "version": "0.16.48",+  "version": "0.16.49",   "expectedExtensionVersion": "0.2.22",   "description": "Drives the user's REAL signed-in Chrome/Edge, in two layers. Layer 1 (nb) needs NOTHING installed and works on any machine: nbrowser_open_os_window (open a URL in the user's real profile, background+flashing, the OAuth/consent path), nbrowser_os_windows, nbrowser_profiles, nbrowser_wake_profile, nbrowser_force_close. Layer 2 (nbe, the Adom Native Browser Extension) unlocks the rest: CDP driving (navigate/click/read/screenshot) inside their logged-in profile. The bridge binds an ephemeral loopback port and the native-messaging host pumps stdio <-> bridge.",   "homepage": "https://wiki.adom.inc/adom/nb-bridge",
bridge/package.json+1−1
@@ -1,6 +1,6 @@ {   "name": "adom-native-browser-bridge",-  "version": "0.16.48",+  "version": "0.16.49",   "private": true,   "description": "Native-browser bridge for Bridge (ab): layer 1 (nb) plus layer 2 via nbe, the Adom Native Browser Extension (Chrome + Edge).",   "main": "server.js",
bridge/server.js+17−7
@@ -3176,12 +3176,23 @@ async function exportSavedLogins(opts) {   // Chrome 156 renamed this: the ROW is titled "Export passwords" but the clickable control is   // "Download file" (first real run on AdomLapper, nb-bridge#55). Try the button labels first, then the   // older row-as-button wording, so this survives either.-  let invoked = null;-  for (const name of ['Download file', 'Download File', 'Export passwords', 'Export passwords…', 'Export']) {-    const r = await abCommand(null, 'desktop_ui_click', { hwnd, contains: name,+  // WAIT for the control, do not guess a delay: a freshly opened window has only browser chrome in the+  // accessibility tree for the first seconds, and a fixed sleep made this fail as "renamed again" when+  // the page simply had not rendered yet (measured 2026-10-29).+  const names = ['Download file', 'Download File', 'Export passwords', 'Export passwords…', 'Export'];+  let invoked = null, btnRect = null;+  const findDeadline = Date.now() + 25000;+  while (Date.now() < findDeadline && !invoked) {+    for (const name of names) {+      const f = await abCommand(null, 'desktop_find_control', { hwnd, contains: name }).catch(() => null);+      const rect = (() => { try { const b = f.body.data || f.body; return (b.best || b.match || {}).rect || null; } catch { return null; } })();+      if (rect) { invoked = name; btnRect = rect; break; }+    }+    if (!invoked) await _sleep(1500);+  }+  if (invoked) {+    await abCommand(null, 'desktop_ui_click', { hwnd, contains: invoked,       reason: 'nb-bridge#55: start the browser\'s own consented password export' }).catch(() => null);-    const okr = r && r.body && (r.body.success !== false);-    if (okr) { invoked = name; break; }   }   // UIA Invoke on a Chrome PAGE button reports success and does nothing (measured here 2026-10-29: the   // click "succeeded", no Hello, no dialog, 200s of waiting). Same trap as the Load-unpacked picker. So@@ -3193,8 +3204,7 @@ async function exportSavedLogins(opts) {     const rows = (() => { try { return (after.body.data || after.body).windows || []; } catch { return []; } })();     const dialogUp = rows.some((w) => w.className === '#32770' || /windows security|windows hello|verify your identity/i.test(String(w.title || '')));     if (!dialogUp) {-      const f = await abCommand(null, 'desktop_find_control', { hwnd, contains: 'Download file' }).catch(() => null);-      const rect = (() => { try { const b = f.body.data || f.body; return (b.best || b.match || {}).rect || null; } catch { return null; } })();+      const rect = btnRect;       if (rect) {         await abCommand(null, 'desktop_bring_to_front', { hwnd, reason: 'nb-bridge#55: the page button needs a real click; the user is about to be asked to authenticate' }).catch(() => {});         await _sleep(400);
package.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "nb-bridge",-  "version": "0.16.48",+  "version": "0.16.49",   "type": "app",   "title": "NB - Native Browser Bridge",   "description": "This package installs the SKILLS into your container so your AI knows how to drive your real signed-in Chrome and Edge; Bridge loads the bridge runtime itself from the release zip.",