← Commit history

v2.0.227: A taskbar button nudge skipped because its window happened to be focused is no longer a dead end: the skip becomes a pending state with bounded backoff retries, so a window stamped while the user was looking at it stops keeping its previous button name and art indefinitely, and the dashboard now turns that button red with an explanation instead of reporting a green match while the taskbar visibly disagrees.

John Lauer ·3c58836432 ·2mo ago ·parent 16df3d5
4 files changed +53−11
adom-bridge-puppeteer-manifest.json+6−6
@@ -1,10 +1,10 @@ {   "manifest_version": 1,   "name": "puppeteer",-  "version": "2.0.226",-  "url": "https://wiki.adom.inc/download/adom/pup-bridge/2.0.226/adom-bridge-puppeteer-v2.0.226.zip",-  "sha256": "c777357bc8cc71c0a21c8f1f7d42ed5ac4d4b79cb7e2202f64bcd3099938fb28",-  "size": 942767,+  "version": "2.0.227",+  "url": "https://wiki.adom.inc/download/adom/pup-bridge/2.0.227/adom-bridge-puppeteer-v2.0.227.zip",+  "sha256": "8b5611b3be56a59a22b1a58d169bde7ed2128766ad5888251b51a4fa61774bab",+  "size": 943878,   "verbPrefixes": [     "browser_",     "desktop_recorder_",@@ -12,5 +12,5 @@   ],   "healthEndpoint": "/status",   "statusVerb": "browser_readiness",-  "released_at": "2026-07-20T15:30:00Z"-}\ No newline at end of file+  "released_at": "2026-08-18T10:18:59.867486Z"+}
src/BRIDGE_VERSION+1−1
@@ -1 +1 @@-2.0.226+2.0.227\ No newline at end of file
src/bridge.json+2−2
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "puppeteer",   "displayName": "Puppeteer (Chrome for Testing + Native)",-  "version": "2.0.226",+  "version": "2.0.227",   "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. pup_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. pup_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, pup_alert_window posts a native toast whose click focuses the window, pup_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-bridge",   "author": "Adom Inc.",@@ -127,4 +127,4 @@     ]   },   "uninstall": "pup_uninstall"-}\ No newline at end of file+}
src/server.js+44−2
@@ -4718,6 +4718,10 @@ Write-Output ("CONVERGED {0} of {1}" -f $n, $script:wins.Count)`;   } } let _nudgeUntil = 0;   // v2.0.172: while set, ignore window-opened events caused by our own nudge+// v2.0.227: backoff for a nudge skipped because the window was foreground. Short first (the user+// usually clicks away within seconds), then patient — a window focused for 10 straight minutes is+// being actively used, and blinking it the moment they look away is the whole point of the skip.+const NUDGE_RETRY_DELAYS = [6000, 15000, 45000, 120000, 300000]; function nudgeTaskbarButton(hwnd, sessionId) {   if (process.platform !== 'win32' || !hwnd) return;   _nudgeUntil = Date.now() + 6000;@@ -4733,6 +4737,35 @@ public static class SW {     execFile('powershell', ['-NoProfile', '-Command', ps], { windowsHide: true, timeout: 20000 }, (err, stdout) => {       const r = String(stdout || '').trim();       console.log(`[thread-tile] "${sessionId}" button nudge: ${err ? 'ERR ' + err.message.slice(0, 80) : r}`);+      // v2.0.227 (John's icon audit found fusion-dashboard grouped under the stock "Google Chrome for+      // Testing" button while wearing stale teal art): a SKIP-FG was a DEAD END. Windows never rebuilds+      // a taskbar button on an in-place AUMID change without this hide/show, so a window that merely+      // happened to be FOCUSED at stamp time kept its previous button identity FOREVER. The skill+      // called this a self-healing tradeoff ("heals on the next focus change") but nothing watched for+      // that change. Now the skip is a PENDING state with a bounded backoff retry; the PS itself+      // re-checks foreground, so a retry while still focused simply skips again and re-queues.+      const _sk = sessions.get(sessionId);+      if (!err && r === 'SKIP-FG' && _sk) {+        const at = (_sk._nudgePending && _sk._nudgePending.attempts || 0) + 1;+        if (at <= NUDGE_RETRY_DELAYS.length) {+          _sk._nudgePending = { since: (_sk._nudgePending && _sk._nudgePending.since) || Date.now(), attempts: at, hwnd };+          const delay = NUDGE_RETRY_DELAYS[at - 1];+          console.log(`[thread-tile] "${sessionId}" nudge SKIPPED (window was focused) — button still wears its OLD identity; retry ${at}/${NUDGE_RETRY_DELAYS.length} in ${Math.round(delay / 1000)}s`);+          if (_sk._nudgeTimer) clearTimeout(_sk._nudgeTimer);+          _sk._nudgeTimer = setTimeout(() => {+            const s2 = sessions.get(sessionId);+            if (!s2 || !s2._nudgePending) return;+            nudgeTaskbarButton(s2._nudgePending.hwnd || hwnd, sessionId);+          }, delay);+        } else {+          console.log(`[thread-tile] "${sessionId}" nudge still skipped after ${NUDGE_RETRY_DELAYS.length} retries — the window has been focused throughout; leaving it pending for the next stamp`);+        }+      }+      if (!err && r === 'NUDGED' && _sk && _sk._nudgePending) {+        console.log(`[thread-tile] "${sessionId}" deferred nudge LANDED after ${_sk._nudgePending.attempts} retr(ies) — button rebuilt with its real identity`);+        _sk._nudgePending = null;+        if (_sk._nudgeTimer) { clearTimeout(_sk._nudgeTimer); _sk._nudgeTimer = null; }+      }       // v2.0.171: the nudge DESTROYS and recreates the button, so any overlay badge already painted       // is gone from glass while pup's model still says painted — mark bare so the enforcer repaints       // the favicon badge onto the recreated thread-tile button (John wants tile + overlay together).@@ -11458,6 +11491,10 @@ async function dashboardSnapshot() {         } catch (e) {}         return null;       })(),+      // v2.0.227: pup KNEW this window's button was never rebuilt (SKIP-FG) yet the chip still read+      // green MATCH while the taskbar showed the stock Chrome name + stale art. Surface it.+      identityPending: !!(sess._nudgePending),+      identityPendingMs: sess._nudgePending ? Date.now() - sess._nudgePending.since : 0,       overlayLed: (() => {         const painted = !!sess._appOverlay;         const hasBytes = (() => { try { return fs.existsSync(path.join(require('os').tmpdir(), 'pup-badge-debug', sid + '.png')); } catch (e) { return false; } })();@@ -11530,8 +11567,13 @@ async function dashboardSnapshot() {   // check John asked to see as a green/red light.   for (const btn of buttons.values()) {     const leds = btn.windows.map(sid => { const w = wins.find(x => x.sessionId === sid); return w ? w.overlayLed : 'red'; });-    btn.led = leds.includes('red') ? 'red' : leds.includes('amber') ? 'amber' : 'green';-    btn.ledWhy = leds.includes('red') ? 'a window under this button has NO overlay painted (taskbar would be bare/stale)'+    // v2.0.227: an identity pup stamped but never got onto the SHELL (skipped nudge) means this+    // button is displaying the WRONG name/art right now — that is a red, not a green.+    const _pend = btn.windows.filter(sid => { const w = wins.find(x => x.sessionId === sid); return w && w.identityPending; });+    btn.identityPending = _pend.length;+    btn.led = _pend.length ? 'red' : leds.includes('red') ? 'red' : leds.includes('amber') ? 'amber' : 'green';+    btn.ledWhy = _pend.length ? `identity stamped but the shell button was never rebuilt on ${_pend.length} window(s) (the nudge is skipped while a window is focused) — this button still shows its PREVIOUS name/art; a retry is queued`+      : leds.includes('red') ? 'a window under this button has NO overlay painted (taskbar would be bare/stale)'       : leds.includes('amber') ? 'all painted, but a window fell back to the generic icon (page had no favicon)'       : 'every window wears its real page-favicon overlay — dashboard matches the taskbar';   }