← Commit history
bridge/BRIDGE_VERSION+1−1
@@ -1 +1 @@-0.1.41\ No newline at end of file+0.1.42\ No newline at end of file
bridge/bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "native-browser",   "displayName": "Adom Browser Extension",-  "version": "0.1.41",+  "version": "0.1.42",   "expectedExtensionVersion": "0.1.3",   "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",
bridge/package.json+1−1
@@ -1,6 +1,6 @@ {   "name": "adom-native-browser-bridge",-  "version": "0.1.41",+  "version": "0.1.42",   "private": true,   "description": "adom-desktop bridge for the Adom native-browser extension (Chrome + Edge)",   "main": "server.js",
bridge/server.js+19−11
@@ -802,9 +802,19 @@ async function chromeWindowsDetailed() { } 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; }+  // PHYSICAL px, so on a scaled display (e.g. 150%) bounds won't match. The OS window title is+  // "<page title> - <Browser>", so the session's page title is a PREFIX of it. Prefer that exact prefix+  // (disambiguates two windows whose titles share a substring, e.g. two Gusto pages); fall back to a+  // substring match. Exclude PWA/app windows (they can carry the profile email in-title but are NOT the+  // browser window the user is watching) by requiring the "- Google Chrome"/"- Microsoft Edge" suffix.+  const t = title && String(title).trim();+  if (t && t.length >= 6) {+    const isBrowserWin = (w) => / - (Google Chrome|Microsoft.?\s*Edge)\s*$/i.test(String(w.title || ''));+    const pre = list.find((w) => isBrowserWin(w) && String(w.title || '').startsWith(t));            // exact page-title prefix+    if (pre) return pre.hwnd;+    const sub = list.find((w) => isBrowserWin(w) && String(w.title || '').includes(t.slice(0, 40)));  // substring, still a real browser window+    if (sub) return sub.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; }   return null;@@ -815,7 +825,6 @@ function matchHwnd(list, bounds, title) { // diff bug), a list call re-correlates by bounds, clears the STALE badge, and paints the correct one. function emailOf(key) { const s = String(key || ''); const i = s.indexOf(':'); return i >= 0 ? s.slice(i + 1) : s; } async function badgeSpawnsIn(payload, profileKey) {-  const email = emailOf(profileKey);   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 });@@ -828,14 +837,13 @@ async function badgeSpawnsIn(payload, profileKey) {   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); paintBadge(h, profileKey); } }-  // PROFILE-LEVEL badge: the OS window title for Google pages contains the profile email, and Windows-  // taskbar buttons group by profile — so badging ANY window of the driven profile lights the right-  // button. This is STABLE while pages navigate (unlike a per-window title), which is why per-window-  // correlation was flaky on the actively-driven work profile. Prefer it; fall back to per-window match.-  let profileHwnd = null;-  if (email.includes('@')) { const m = list.find((w) => (w.title || '').includes(email)); if (m) profileHwnd = m.hwnd; }+  // Correlate each owned session to its OWN browser window by its page title (matchHwnd, which prefers+  // an exact title prefix and only matches real browser windows). The old "profileHwnd = first window+  // whose title contains the profile email" shortcut is REMOVED: it matched the [email protected] "Adom+  // Mail"/Gmail PWA window and badged THAT instead of the Chrome window the user was watching — a real+  // regression (badge invisible on the driven work-Chrome button; the whole trust signal broke).   for (const o of owned) {-    const h = profileHwnd || matchHwnd(list, o.bounds, o.title);+    const h = matchHwnd(list, o.bounds, o.title);     if (!h) continue;     const old = sessionHwnd.get(o.sid);     if (old !== h) { if (old && old !== h) nativeOverlay(old, profileKey); sessionHwnd.set(o.sid, h); persistSessions(); lastHwnd = h; clearBadge(o.sid); applyBadge(o.sid, h); }
native-browser-bridge-manifest.json+5−5
@@ -1,8 +1,8 @@ {   "manifest_version": 1,-  "version": "0.1.41",-  "url": "https://wiki.adom.inc/download/adom/adom-browser-extension/0.1.41/native-browser-bridge-v0.1.41.zip",-  "sha256": "349921157abf29e1d42944e59c7a6a86616e997db881ec0d5bfdfb213e3807fc",-  "size": 86212,-  "released_at": "2026-07-19T00:00:00Z"+  "version": "0.1.42",+  "url": "https://wiki.adom.inc/download/adom/adom-browser-extension/0.1.42/native-browser-bridge-v0.1.42.zip",+  "sha256": "07a0f05540f622a3364705ff8efe50e24f865df37534e9d82a2d1d6483ae9d8d",+  "size": 86469,+  "released_at": "2026-07-21T00:00:00Z" }