← Commit history
bridge/BRIDGE_VERSION+1−1
@@ -1 +1 @@-0.1.45\ No newline at end of file+0.1.46\ 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.45",+  "version": "0.1.46",   "expectedExtensionVersion": "0.1.3",   "description": "Drives the user's REAL signed-in Chrome/Edge. MOST verbs require the Adom extension installed in that browser profile (CDP driving: navigate/click/read/screenshot). TWO verbs need NO extension at all and work on any machine: nbrowser_open_os_window (open a URL in the user's real profile, background+flashing - the OAuth/consent path) and nbrowser_os_windows (enumerate browser windows). Also extension-free: nbrowser_profiles, nbrowser_wake_profile, nbrowser_force_close. The bridge binds an ephemeral loopback port and the native-messaging host pumps stdio <-> bridge.",   "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.45",+  "version": "0.1.46",   "private": true,   "description": "adom-desktop bridge for the Adom native-browser extension (Chrome + Edge)",   "main": "server.js",
bridge/server.js+29−1
@@ -1689,11 +1689,20 @@ function dispatch(verb, args) {           }         }         if (a.foreground === true) announceForeground(a.foregroundReason, a.sessionId);+        else if (!hwnd) {+          // BACKGROUND WAS REQUESTED BUT COULD NOT BE HONORED: no new window was created (the browser+          // grouped the page into an existing one), so there is nothing to minimize and the page lands+          // in front of the user. Tell them what appeared and why - John, 2026-07-22: a sign-in page+          // showing up unannounced is the failure, whether or not the AI asked for foreground.+          announceForeground(`opened ${(() => { try { return new URL(url).hostname; } catch { return 'a page'; } })()} in your browser${a.purpose ? ' - ' + String(a.purpose).slice(0, 90) : ''}`, a.sessionId);+        }         // LAYER-1 BADGE (hollow): mark the window Adom OPENED even though it cannot drive it - provenance         // matters most on an OAuth consent page. Uses applyBadge so the normal 3-min idle expiry restores         // the native avatar; nothing lingers.         if (hwnd) applyBadge(a.sessionId, hwnd, kp.key, 'hollow');-        logActivity({ verb: 'nbrowser_open_os_window', sessionId: a.sessionId, thread: a.thread, profile: kp.key, ok: !!hwnd, errorCode: hwnd ? null : 'hwnd_not_found' });+        logActivity({ verb: 'nbrowser_open_os_window', sessionId: a.sessionId, thread: a.thread, profile: kp.key, ok: true,+          ops: `fg=${a.foreground === true}·hwndResolved=${!!hwnd}·minimized=${minimized}`, hwnd: hwnd || undefined,+          errorCode: hwnd ? null : 'grouped_into_existing_window' });         sessionThread.set(a.sessionId, a.thread); sessionPurpose.set(a.sessionId, a.purpose); sessionProfile.set(a.sessionId, kp.key); if (hwnd) sessionHwnd.set(a.sessionId, hwnd); osOpened.add(a.sessionId); persistSessions();         const upsell = extSt && extSt.installed           ? `NOTE: the Adom extension IS installed in this profile${extSt.enabled ? '' : ' (but DISABLED)'} - you could have FULL control instead: nbrowser_wake_profile then nbrowser_open_window gives you navigation, reading, clicking, screenshots, and ownership guards. Prefer that path.`@@ -2352,4 +2361,23 @@ async function resetStaleBadgesOnStartup(attempt = 0) {     if (hit && !seen.has(w.hwnd)) { seen.add(w.hwnd); nativeOverlay(w.hwnd, hit.key); }   } }+// ── REAP USER-CLOSED WINDOWS (John, 2026-07-22): "if a user closes the ai created nb window, you should+// detect that and remove your overlay icon." A closed window's taskbar button disappears with it, but the+// BRIDGE would still think it owns that hwnd - it would keep arming idle timers, re-painting a dead+// window, and reporting it in nbrowser_owned. Poll the live browser-window set and forget what is gone.+async function reapClosedWindows() {+  if (!sessionHwnd.size && !spawnHwnd.size) return;+  let live;+  try { live = new Set((await chromeWindowsDetailed()).map((w) => w.hwnd)); } catch { return; }+  if (!live.size) return; // AD blind - never reap on no data+  let reaped = 0;+  for (const [sid, h] of [...sessionHwnd]) {+    if (live.has(h)) continue;+    sessionHwnd.delete(sid); clearBadge(sid); osOpened.delete(sid); reaped++;+    logActivity({ verb: '_window_reaped', sessionId: sid, thread: sessionThread.get(sid) || null, profile: sessionProfile.get(sid) || null, hwnd: h, ops: 'closed_by_user', ok: true, internal: true });+  }+  for (const [wid, h] of [...spawnHwnd]) { if (!live.has(h)) { spawnHwnd.delete(wid); reaped++; } }+  if (reaped) persistSessions();+}+setInterval(() => { reapClosedWindows().catch(() => {}); }, 30000).unref(); setTimeout(() => resetStaleBadgesOnStartup(), 4000);
native-browser-bridge-manifest.json+4−4
@@ -1,8 +1,8 @@ {   "manifest_version": 1,-  "version": "0.1.45",-  "url": "https://wiki.adom.inc/download/adom/adom-browser-extension/0.1.45/native-browser-bridge-v0.1.45.zip",-  "sha256": "123bfbecf98722eb394ae84a03fc5a2d8d2112bcb999cff19fe35a6cb8150fbe",-  "size": 94856,+  "version": "0.1.46",+  "url": "https://wiki.adom.inc/download/adom/adom-browser-extension/0.1.46/native-browser-bridge-v0.1.46.zip",+  "sha256": "bd12662cad4b58d66d70e61fa78d1448203b6230ba8179043df05edce4b0d730",+  "size": 95531,   "released_at": "2026-07-22T00:00:00Z" }