← Commit history

ACTUALLY FIX the root cause I kept describing instead of doing (John: 'and yet its still not fixed?'). Everything — taskbar paint, park, session resolution — located windows by their '(session: <id>)' TITLE TAG, and Chrome's PDF viewer cannot carry that tag. So on a PDF window every lookup failed: no badge was ever painted no matter what the compositor produced, park returned park-failed (which is also why those PDFs jumped to the foreground unasked), and the reclaim janitor kept re-adopting the same unresolvable window as a NEW session every 90s — five of them by the end, all fighting over one taskbar button, each seeing only its own slice of the window's tabs (which is why one painter reported 'no favicon anywhere' while a sibling session held the real hanover.com favicon). Four changes: (1) park STORES the resolved window handle on the session (title-independent identity); (2) the taskbar overlay is addressed BY HWND when known, falling back to the title tag only when it is not; (3) sessionHwnd prefers the stored handle over a title lookup; (4) reclaim REFUSES to adopt a window whose OS window id already belongs to a live session, so duplicates stop being minted. Nine badge revisions could not fix this because the compositor was never the problem — the paint had no target.

John Lauer ·a441bd10ca ·3mo ago ·parent 4a97b89
4 files changed +37−7
adom-bridge-puppeteer-manifest.json+4−4
@@ -1,10 +1,10 @@ {   "manifest_version": 1,   "name": "puppeteer",-  "version": "1.9.211",-  "url": "https://wiki.adom.inc/download/adom/adom-desktop-puppeteer-bridge/1.9.211/adom-bridge-puppeteer-v1.9.211.zip",-  "sha256": "427591d318dc9ebe8816dec1bfff1ae77362b6443efa466d96faadd949cb002d",-  "size": 438798,+  "version": "1.9.212",+  "url": "https://wiki.adom.inc/download/adom/adom-desktop-puppeteer-bridge/1.9.212/adom-bridge-puppeteer-v1.9.212.zip",+  "sha256": "c7d75658b21febf9bf9cfb8596c66fa669b879e25be88d89d9bfb233cf2d6139",+  "size": 440347,   "verbPrefixes": [     "browser_",     "desktop_recorder_",
src/BRIDGE_VERSION+1−1
@@ -1 +1 @@-1.9.211+1.9.212
src/bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "puppeteer",   "displayName": "Puppeteer (Chrome for Testing + Native)",-  "version": "1.9.211",+  "version": "1.9.212",   "description": "Drives a browser ALREADY on the machine \u2014 installed Chrome, else Microsoft Edge (every Windows PC ships with Edge) \u2014 launched with a FRESH isolated profile, so the common case has NO ~150 MB Chrome-for-Testing download and it never touches the user's real tabs/logins. Binds its local server to LOOPBACK (127.0.0.1) only, so no Windows Firewall 'allow Node through the firewall' prompt ever pops. Chrome for Testing is fetched only as a LAST RESORT if the machine has no Chromium browser at all. SPAWN-VERIFIED fallback: pup tries each detected browser (Chrome \u2192 Edge \u2192 CfT) and actually launches it, falling through to the next if one won't start (and handling browsers like Edge that relaunch onto another PID), so a corrupt/partial install never hard-fails an open. The browser that launches is cached as the default (persisted across restarts) so it isn't re-probed each time. On spawn the bridge SELF-WARMS: detects browsers + disk, and only if the box has no Chrome/Edge and no cached CfT does it background-fetch CfT so the first open is instant. browser_use pins a specific browser (chrome | edge | cft | auto); {browser:'chrome',install:true} downloads & installs REAL Google Chrome (user-scoped, no admin) on an Edge-only box. browser_readiness (READ-ONLY) reports which browser will be used + the full candidate list + the default + free disk. Every failure returns a specific errorCode + _hint (chrome_install_no_disk, chrome_download_network, chrome_install_permission, chrome_stable_not_detected, \u2026). Launches with FULL browser permissions by default for full debug (strictPermissions:true opts out). Headful automation: open/close windows+tabs, navigate, screenshot, eval JS, record. pup is a GENERIC, non-profile browser only \u2014 every session is a fresh isolated Chrome/Edge process, never the user's real signed-in browser; profile defaults to sessionId. To drive the user's REAL Chrome/Edge (their profile, cookies, SSO), use the Adom browser EXTENSION's nbrowser_* verbs \u2014 a separate bridge, not pup's job. macOS (v1.9.74+): full parity with mac-native mechanics \u2014 background-by-default is the app-level hide (windows stay drivable/screenshottable while hidden), raise/lower map to unhide+activate/hide, browser_alert_window posts a native toast whose click focuses the window, browser_use {browser:'chrome',install:true} installs Chrome from the official dmg, and taskbar identity/badging remains Windows-only.",   "homepage": "https://wiki.adom.inc/adom/adom-desktop",   "author": "Adom Inc.",
src/server.js+31−1
@@ -1894,6 +1894,8 @@ async function pupCaption(text, expiresInMs = 8000, id = 'pup-assist') {   try { await chrome.adCommand('desktop_caption', { text, expiresInMs, id, position: 'bottom', size: 'medium' }, { timeoutMs: 4000 }); } catch (e) {} } async function sessionHwnd(sessionId) {+  // v1.9.212: prefer the STORED handle — a title lookup cannot find a PDF-viewer window at all.+  try { const _s = sessions.get(sessionId); if (_s && _s._hwnd) return Number(_s._hwnd); } catch (e) {}   try {     const fw = adPayload(await chrome.adCommand('desktop_find_window', { titleContains: `(session: ${sessionId}` }, { timeoutMs: 5000, caller: sessionCaller(sessions.get(sessionId)) }));     const b = fw && (fw.best || (fw.data && fw.data.best));@@ -4090,8 +4092,11 @@ async function applyAppOverlay(session, sessionId) {     }     const tabs = (session.tabs || []).length;     const nm = session._appName ? `${session._appName} — ` : '';+    // v1.9.212: address the button BY HWND when known — the title tag is unavailable on PDF windows,+    // which is why those buttons never got painted no matter what the compositor produced.+    const _tgt = (session._hwnd ? { hwnd: session._hwnd } : { titleContains: `(session: ${sessionId}` });     await chrome.adCommand('desktop_taskbar', {-      titleContains: `(session: ${sessionId}`,+      ..._tgt,       overlay: { icon: overlay, tooltip: `Adom Pup — ${nm}${plateAuthed ? 'Adom wiki: SIGNED IN · ' : ''}${tabs} tab${tabs === 1 ? '' : 's'}${tabs > 1 ? ' (icon = active tab)' : ''}` },     }, { timeoutMs: 5000 });     session._appOverlay = true;@@ -4495,6 +4500,23 @@ async function reclaimUnmanagedWindows() {         // Adopting on first sight turns any such blink into a duplicate session that can never be         // reconciled. Require the SAME window to look unowned on two consecutive sweeps; anything         // transient resolves itself in between and is never touched.+        // v1.9.212: refuse to adopt a window that a LIVE session already owns by hwnd. Without this+        // the janitor minted a new session every 90s for the same unresolvable PDF window, splitting+        // its tabs across sessions (which is why one painter saw only PDFs and reported no favicon).+        try {+          let _wh = null;+          try { _wh = await pageWindowId(group[0]); } catch (e) {}+          if (_wh != null) {+            let owned = false;+            for (const [, s2] of sessions) {+              for (const t2 of (s2.tabs || [])) {+                try { if ((await pageWindowId(t2.page)) === _wh) { owned = true; break; } } catch (e) {}+              }+              if (owned) break;+            }+            if (owned) { console.log(`[reclaim] skipping window ${key} — a live session already owns this OS window (no duplicate session)`); continue; }+          }+        } catch (e) {}         const strikeKey = `${profileName}:${key}`;         const strikes = (_reclaimStrikes.get(strikeKey) || 0) + 1;         if (strikes < 2) {@@ -5346,6 +5368,14 @@ async function parkSessionWindowDirect(page, sessionId) {       } catch (e) {}     }     if (!parkHwnd) { console.log(`[park] "${sessionId}": no hwnd for placement — leaving off-screen, self-heal will retry`); return 'park-failed'; }+    // v1.9.212 — STORE THE HWND ON THE SESSION. This is the fix John has been waiting for me to+    // actually make instead of describing. Everything downstream (taskbar paint, park, resolution)+    // has been finding windows by their "(session: <id>)" TITLE TAG, and Chrome's PDF viewer cannot+    // carry that tag — so on a PDF window every one of those lookups failed: no badge painted,+    // park-failed, and the reclaim janitor kept re-adopting the window as yet another session+    // (five of them by now, all fighting over one taskbar button). A window handle is stable and+    // title-independent, so hold onto it here where we have already resolved it.+    try { const _s = sessions.get(sessionId); if (_s) { _s._hwnd = Number(parkHwnd); } } catch (e) {}     // Place on-screen full-size (CDP plain bounds — the only move that doesn't raise), then     // RE-BOTTOM (trust nothing) and CONFIRM the z-order. Unconfirmable → back off-screen.     const placed = await placeOnScreen();