← Commit history
Update 5 file(s)
5 files changed
+27−19
bridge/BRIDGE_VERSION+1−1@@ -1 +1 @@-0.1.41+0.1.42
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" }