← Commit history

v0.1.3/ext0.1.2: TITLE-based hwnd correlation (chrome.windows bounds are logical px, OS rects physical - broke badge on 150% scaled displays); title match is DPI-independent

John Lauer ·b68ed457f3 ·4mo ago ·parent ae9151a
7 files changed +20−15
bridge/BRIDGE_VERSION+1−1
@@ -1 +1 @@-0.1.2+0.1.3
bridge/bridge.json+2−2
@@ -2,8 +2,8 @@   "manifest_version": 1,   "name": "native-browser",   "displayName": "Adom Native Browser (Chrome + Edge)",-  "version": "0.1.2",-  "expectedExtensionVersion": "0.1.1",+  "version": "0.1.3",+  "expectedExtensionVersion": "0.1.2",   "description": "Drives the user's REAL signed-in Chrome/Edge via an installed extension (native-messaging transport). Mirrors the puppeteer bridge's verb surface as nbrowser_* but runs inside the actual logged-in profile, so cookies/SSO/saved-logins/captcha human-trust all work. The bridge binds an ephemeral loopback port (PORTS.md compliant) and writes a discovery file; the native-messaging host pumps stdio <-> this bridge; the extension never touches a TCP port.",   "homepage": "https://wiki.adom.inc/adom/adom-browser-extension",   "author": "Adom Inc.",
bridge/package.json+1−1
@@ -1,6 +1,6 @@ {   "name": "adom-native-browser-bridge",-  "version": "0.1.2",+  "version": "0.1.3",   "private": true,   "description": "adom-desktop bridge for the Adom native-browser extension (Chrome + Edge)",   "main": "server.js",
bridge/server.js+9−5
@@ -444,8 +444,12 @@ async function chromeWindowsDetailed() {   return ws.filter((w) => /Chrome_WidgetWin/.test(w.className || '') && !/for Testing/.test(w.title || '')); } function matchHwnd(list, bounds, title) {+  // TITLE first — DPI-INDEPENDENT. chrome.windows bounds are LOGICAL px, but the OS window rects are+  // PHYSICAL px, so on a scaled display (e.g. 150%) bounds won't match. The OS Chrome window title+  // contains the page title (and the profile email), so a title substring is a reliable correlation.+  if (title && String(title).trim().length >= 6) { const t = String(title).slice(0, 30); const m = list.find((w) => (w.title || '').includes(t)); if (m) return m.hwnd; }+  // Fallback: bounds (only reliable at 100% scaling).   if (bounds) for (const w of list) { const r = w.rect || {}; if (r.left != null && r.top != null && Math.abs(r.left - bounds.left) <= 24 && Math.abs(r.top - bounds.top) <= 24) return w.hwnd; }-  if (title) { const t = String(title).slice(0, 24); const m = list.find((w) => (w.title || '').includes(t)); if (m) return m.hwnd; }   return null; } // (Re)paint the "Adom is driving" badge from a nbrowser_owned / nbrowser_list_windows payload, correlating@@ -458,8 +462,8 @@ async function badgeSpawnsIn(payload) {   if (payload && Array.isArray(payload.spawned)) for (const s of payload.spawned) if (s.kind === 'window' && s.windowId != null) spawns.push({ windowId: s.windowId, bounds: s.bounds, title: s.title });   if (payload && Array.isArray(payload.sessions)) for (const s of payload.sessions) {     if (s.windowId == null) continue;-    if (s.owner === 'agent-spawned') spawns.push({ windowId: s.windowId, bounds: s.bounds, title: s.url });-    else if (s.owner === 'agent-opened' && s.id) owned.push({ sid: s.id, bounds: s.bounds, title: s.url });+    if (s.owner === 'agent-spawned') spawns.push({ windowId: s.windowId, bounds: s.bounds, title: s.title || s.url });+    else if (s.owner === 'agent-opened' && s.id) owned.push({ sid: s.id, bounds: s.bounds, title: s.title || s.url });   }   const fresh = spawns.filter((s) => !spawnHwnd.has(s.windowId));   if (!fresh.length && !owned.length) return;@@ -1291,8 +1295,8 @@ async function onHostFrame(frame) {             const list = await chromeWindowsDetailed();             // Correlate by BOUNDS first (profile-independent + precise — the new-window DIFF can't tell             // profiles apart and badged the WRONG profile's taskbar button). Diff only as a fallback.-            if (payload.bounds) neu = matchHwnd(list, payload.bounds, null);-            if (!neu) neu = list.map((w) => w.hwnd).find((h) => !preOpenHwnds.has(h)) || null;+            neu = matchHwnd(list, payload.bounds, payload.title); // title-first (DPI-safe), then bounds+            if (!neu) neu = list.map((w) => w.hwnd).find((h) => !preOpenHwnds.has(h)) || null; // diff fallback (title empty while loading)           } catch {}           if (neu) { lastHwnd = neu; if (sid) sessionHwnd.set(sid, neu); taskbar(neu, { overlay: { badge: 'adom', tooltip: 'Adom is driving this browser' } }); break; }           await new Promise((r) => setTimeout(r, 250));
extension/manifest.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 3,   "name": "Adom for Chrome & Edge",   "short_name": "Adom",-  "version": "0.1.1",+  "version": "0.1.2",   "description": "Drive your real, logged-in Chrome/Edge from the Adom ecosystem \u2014 the native-browser counterpart to pup.",   "minimum_chrome_version": "116",   "background": {
extension/src/native.js+2−1
@@ -501,7 +501,7 @@ export async function openWindow(args = {}) {   // the taskbar badge — the old "new Chrome window" diff can't tell profiles apart and badged the wrong one.   let bounds; try { const w2 = await chrome.windows.get(win.id); bounds = { left: w2.left, top: w2.top, width: w2.width, height: w2.height }; } catch { bounds = { left: win.left, top: win.top, width: win.width, height: win.height }; }   const res = {-    ok: true, sessionId: sid, tabId: String(tab.id), windowId: win.id, url: tab.url || args.url, bounds,+    ok: true, sessionId: sid, tabId: String(tab.id), windowId: win.id, url: tab.url || args.url, title: tab.title, bounds,     _hint: 'New window opened in the BACKGROUND — the user\'s focus is deliberately NOT stolen. ' + POLITE_HINT +       ' Screenshot it where it sits with nbrowser_screenshot (CDP) or AD desktop_screenshot_window (WGC); both capture a background/occluded window, so NEVER foreground it to grab a shot. To raise it you must justify it (userRequestedForeground:true + foregroundReason) AND warn the user first. Remember to nbrowser_close_window {sessionId:"' + sid + '"} when done so you don\'t leave abandoned windows.',   };@@ -602,6 +602,7 @@ export async function listWindows(args = {}) {       state: w.state,       bounds: { left: w.left, top: w.top, width: w.width, height: w.height },       url: (w.tabs || []).find((t) => t.active)?.url,+      title: (w.tabs || []).find((t) => t.active)?.title, // for DPI-independent hwnd correlation (OS title match)     };   });   if (args.mine) sessions = sessions.filter((s) => s.owner !== 'user'); // only windows an agent opened/spawned
native-browser-bridge-manifest.json+4−4
@@ -1,8 +1,8 @@ {   "manifest_version": 1,-  "version": "0.1.2",-  "url": "https://wiki.adom.inc/download/adom/adom-browser-extension/0.1.2/native-browser-bridge-v0.1.2.bin",-  "sha256": "0742cfbb954e12600a8bc453401d88881dc636fc9da5aa95636151c06671e84c",-  "size": 53867,+  "version": "0.1.3",+  "url": "https://wiki.adom.inc/download/adom/adom-browser-extension/0.1.3/native-browser-bridge-v0.1.3.bin",+  "sha256": "10124cf825d36e6c734c607b238d89705ddf4446b6d1b72f8f6886ae3cd3b4ec",+  "size": 54092,   "released_at": "2026-07-14T00:00:00Z" }\ No newline at end of file