← Commit history

v0.1.2/ext0.1.1: badge the correct-profile window via BOUNDS correlation (fixes badge landing on the wrong Chrome profile taskbar) + self-heal on list_windows/owned

John Lauer ·ae9151a5aa ·4mo ago ·parent 7c6089f
7 files changed +38−16
bridge/BRIDGE_VERSION+1−1
@@ -1 +1 @@-0.1.1+0.1.2
bridge/bridge.json+2−2
@@ -2,8 +2,8 @@   "manifest_version": 1,   "name": "native-browser",   "displayName": "Adom Native Browser (Chrome + Edge)",-  "version": "0.1.1",-  "expectedExtensionVersion": "0.1.0",+  "version": "0.1.2",+  "expectedExtensionVersion": "0.1.1",   "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.1",+  "version": "0.1.2",   "private": true,   "description": "adom-desktop bridge for the Adom native-browser extension (Chrome + Edge)",   "main": "server.js",
bridge/server.js+25−6
@@ -448,16 +448,29 @@ function matchHwnd(list, bounds, title) {   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; }-// Paint the "Adom is driving" badge on any adopted SPAWNED window in a nbrowser_owned / nbrowser_list_windows-// payload we haven't badged yet — so child/popup windows get the trust tell too, not just open_window.+// (Re)paint the "Adom is driving" badge from a nbrowser_owned / nbrowser_list_windows payload, correlating+// each window's OS hwnd by BOUNDS (profile-independent). This badges adopted SPAWNED windows AND+// SELF-HEALS agent-OPENED windows: if the open-time badge landed on the wrong profile's window (the old+// diff bug), a list call re-correlates by bounds, clears the STALE badge, and paints the correct one. async function badgeSpawnsIn(payload) {-  const spawns = [];+  const spawns = []; // { windowId, bounds, title }+  const owned = [];  // { sid, bounds, title }   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.owner === 'agent-spawned' && s.windowId != null) spawns.push({ windowId: s.windowId, bounds: s.bounds, title: s.url });+  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 });+  }   const fresh = spawns.filter((s) => !spawnHwnd.has(s.windowId));-  if (!fresh.length) return;+  if (!fresh.length && !owned.length) return;   let list; try { list = await chromeWindowsDetailed(); } catch { return; }   for (const s of fresh) { const h = matchHwnd(list, s.bounds, s.title); if (h) { spawnHwnd.set(s.windowId, h); taskbar(h, { overlay: { badge: 'adom', tooltip: 'Adom is driving this browser' } }); } }+  for (const o of owned) {+    const h = matchHwnd(list, o.bounds, o.title);+    if (!h) continue;+    const old = sessionHwnd.get(o.sid);+    if (old !== h) { if (old) taskbar(old, { overlay: { badge: 'none' } }).catch(() => {}); sessionHwnd.set(o.sid, h); lastHwnd = h; taskbar(h, { overlay: { badge: 'adom', tooltip: 'Adom is driving this browser' } }); }+  } } // A "come look" moment = a verb in COMELOOK, OR a semantic signal in the payload that the user should // glance over: an error/refusal, an idle-timeout risk, a human gate (captcha/2FA/login), or fresh spawned@@ -1274,7 +1287,13 @@ async function onHostFrame(frame) {         // desktop_screenshot_window (the window+chrome+child-popup capture technique).         let neu = null;         for (let i = 0; i < 4; i++) {-          try { const after = await chromeHwnds(); neu = [...after].find((h) => !preOpenHwnds.has(h)) || null; } catch {}+          try {+            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;+          } 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.0",+  "version": "0.1.1",   "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+4−1
@@ -497,8 +497,11 @@ export async function openWindow(args = {}) {   await persist();   const warn = await enforceBackground(win.id, args, 'nbrowser_open_window', prev); // backstop: never leaves it topmost   const tab = (win.tabs && win.tabs[0]) || {};+  // Return the window's BOUNDS so the bridge can correlate its OS hwnd by rect (profile-independent) for+  // 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,+    ok: true, sessionId: sid, tabId: String(tab.id), windowId: win.id, url: tab.url || args.url, 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.',   };
native-browser-bridge-manifest.json+4−4
@@ -1,8 +1,8 @@ {   "manifest_version": 1,-  "version": "0.1.1",-  "url": "https://wiki.adom.inc/download/adom/adom-browser-extension/0.1.1/native-browser-bridge-v0.1.1.bin",-  "sha256": "5412f87a9f81ee457f4c2315dba5ad464446b33f600adeb260b1df64013b39e9",-  "size": 53513,+  "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,   "released_at": "2026-07-14T00:00:00Z" }\ No newline at end of file