← Commit history

v0.1.9: pass profileDir/userDataDir to desktop_taskbar so AD composites the Adom mark onto the Chrome/Edge profile avatar (no longer evicts the profile face)

John Lauer ·288dcece03 ·3mo ago ·parent 3d2b81d
5 files changed +43−11
bridge/BRIDGE_VERSION+1−1
@@ -1 +1 @@-0.1.8+0.1.9
bridge/bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "native-browser",   "displayName": "Adom Native Browser (Chrome + Edge)",-  "version": "0.1.8",+  "version": "0.1.9",   "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",
bridge/package.json+1−1
@@ -1,6 +1,6 @@ {   "name": "adom-native-browser-bridge",-  "version": "0.1.8",+  "version": "0.1.9",   "private": true,   "description": "adom-desktop bridge for the Adom native-browser extension (Chrome + Edge)",   "main": "server.js",
bridge/server.js+35−3
@@ -450,7 +450,39 @@ function armBadgeIdle(sid) {   const prev = badgeIdle.get(sid); if (prev) clearTimeout(prev);   badgeIdle.set(sid, setTimeout(() => { const h = sessionHwnd.get(sid); if (h) taskbar(h, { overlay: { badge: 'none' } }).catch(() => {}); badgeOn.delete(sid); badgeIdle.delete(sid); }, BADGE_IDLE_MS)); }-function applyBadge(sid, hwnd) { if (!sid || !hwnd) return; taskbar(hwnd, { overlay: { badge: 'adom', tooltip: 'Adom is driving this browser' } }); badgeOn.add(sid); armBadgeIdle(sid); }+// Map a driven profile → its Chrome/Edge profile DIRECTORY, so AD (>=1.9.110) can composite the Adom mark+// onto that profile's AVATAR instead of evicting it (the taskbar overlay has one slot = the avatar's slot).+// AD can't derive this itself: Chrome/Edge run ONE browser process for all profiles, so hwnd→PID→cmdline+// has no --profile-directory. We read the browser's Local State (profile.info_cache: dir → {user_name}).+const _avatarCache = new Map(); // profileKey -> {userDataDir, profileDir} | null+function avatarForProfile(profileKey) {+  if (!profileKey) return null;+  if (_avatarCache.has(profileKey)) return _avatarCache.get(profileKey);+  let result = null;+  try {+    const i = String(profileKey).indexOf(':');+    const browser = i >= 0 ? profileKey.slice(0, i) : 'chrome';+    const email = i >= 0 ? profileKey.slice(i + 1) : profileKey;+    const local = process.env.LOCALAPPDATA;+    if (local && email.includes('@')) {+      const root = browser === 'edge' ? path.join(local, 'Microsoft', 'Edge', 'User Data') : path.join(local, 'Google', 'Chrome', 'User Data');+      const j = JSON.parse(fs.readFileSync(path.join(root, 'Local State'), 'utf8'));+      const cache = (j.profile && j.profile.info_cache) || {};+      for (const [dir, info] of Object.entries(cache)) {+        if (String((info && info.user_name) || '').toLowerCase() === email.toLowerCase()) { result = { userDataDir: root, profileDir: dir }; break; }+      }+    }+  } catch {}+  _avatarCache.set(profileKey, result);+  return result;+}+function applyBadge(sid, hwnd, profileKey) {+  if (!sid || !hwnd) return;+  const overlay = { badge: 'adom', tooltip: 'Adom is driving this browser' };+  const av = avatarForProfile(profileKey || sessionProfile.get(sid)); // composite onto the profile avatar if we can find it+  if (av) { overlay.profileDir = av.profileDir; overlay.userDataDir = av.userDataDir; }+  taskbar(hwnd, { overlay }); badgeOn.add(sid); armBadgeIdle(sid);+} // Called on every DRIVE verb: the badge tracks ACTIVE driving, not mere ownership. On the first activity // (or after a bridge restart) it lazily correlates the driven profile's taskbar window; then it just // re-arms the idle timer. An IDLE owned window (a thread opened it then went quiet) is NEVER badged here,@@ -468,7 +500,7 @@ async function touchBadge(sid, profileKey) {     try { const list = await chromeWindowsDetailed(); const m = list.find((w) => (w.title || '').includes(email)); if (m) { h = m.hwnd; sessionHwnd.set(sid, h); } } catch {}     if (!h) return;   }-  if (!badgeOn.has(sid)) applyBadge(sid, h); else armBadgeIdle(sid);+  if (!badgeOn.has(sid)) applyBadge(sid, h, profileKey); else armBadgeIdle(sid); } function clearBadge(sid) { const t = badgeIdle.get(sid); if (t) clearTimeout(t); badgeIdle.delete(sid); badgeOn.delete(sid); badgeTry.delete(sid); } // Capture the driven window's hwnd by DIFFING the real-Chrome window list across the open (the new@@ -1373,7 +1405,7 @@ async function onHostFrame(frame) {             if (!neu) neu = list.map((w) => w.hwnd).find((h) => !preOpenHwnds.has(h)) || null; // diff fallback (title empty while loading)             if (!neu) { const email = emailOf(p.profileKey); if (email.includes('@')) { const m = list.find((w) => (w.title || '').includes(email)); if (m) neu = m.hwnd; } } // profile-level fallback           } catch {}-          if (neu) { lastHwnd = neu; if (sid) sessionHwnd.set(sid, neu); applyBadge(sid, neu); break; } // applyBadge = badge + arm idle-expiry+          if (neu) { lastHwnd = neu; if (sid) sessionHwnd.set(sid, neu); applyBadge(sid, neu, p.profileKey); break; } // applyBadge = badge (composited onto the profile avatar) + arm idle-expiry           await new Promise((r) => setTimeout(r, 250));         }         payload = { ...payload, ...(neu ? { hwnd: neu } : {}), _taskbarHint: flashHint(),
native-browser-bridge-manifest.json+5−5
@@ -1,8 +1,8 @@ {   "manifest_version": 1,-  "version": "0.1.8",-  "url": "https://wiki.adom.inc/download/adom/adom-browser-extension/0.1.8/native-browser-bridge-v0.1.8.bin",-  "sha256": "1ed081a1136b767e6136ec478fdcc0df5a4bc1c1916e46af631cd0d68b6f3350",-  "size": 57125,-  "released_at": "2026-07-14T00:00:00Z"+  "version": "0.1.9",+  "url": "https://wiki.adom.inc/download/adom/adom-browser-extension/0.1.9/native-browser-bridge-v0.1.9.bin",+  "sha256": "c2753b101d02ea99a3d819a47e1967cb8088026b833746bf3a1d8e8bd48687c4",+  "size": 57677,+  "released_at": "2026-07-15T00:00:00Z" }\ No newline at end of file