← Commit history

v1.8.27: remove redundant pup-side localhost probe (AD core already reprimands localhost on failure); keep the real background-by-default fix + foreground-gate + finite flash

John Lauer ·b9418c5eb7 · ·parent 682bca7
4 files changed +13−85
adom-bridge-puppeteer-manifest.json+5−5
@@ -1,10 +1,10 @@ {   "manifest_version": 1,   "name": "puppeteer",-  "version": "1.8.26",-  "url": "https://wiki.adom.inc/download/adom/adom-desktop-puppeteer-bridge/1.8.26/adom-bridge-puppeteer-v1.8.26.zip",-  "sha256": "e5f071c0e73444ca9b1ae28cbfefbaaf699cbc4cf5d8a12e64a1f395bb020142",-  "size": 156777,+  "version": "1.8.27",+  "url": "https://wiki.adom.inc/download/adom/adom-desktop-puppeteer-bridge/1.8.27/adom-bridge-puppeteer-v1.8.27.zip",+  "sha256": "4fb299c0a4bd85e4382d69ed1ea1ce2565f644b701122a750cf13b5655319cbd",+  "size": 155251,   "verbPrefixes": [     "browser_",     "desktop_recorder_",@@ -12,5 +12,5 @@   ],   "healthEndpoint": "/status",   "statusVerb": "browser_readiness",-  "released_at": "2026-07-14T18:41:59Z"+  "released_at": "2026-07-14T18:54:10Z" }\ No newline at end of file
src/BRIDGE_VERSION+1−1
@@ -1 +1 @@-1.8.26+1.8.27
src/bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "puppeteer",   "displayName": "Puppeteer (Chrome for Testing + Native)",-  "version": "1.8.26",+  "version": "1.8.27",   "description": "Drives a browser ALREADY on the machine — installed Chrome, else Microsoft Edge (every Windows PC ships with Edge) — 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 → Edge → 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, …). 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 — 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 — a separate bridge, not pup's job.",   "homepage": "https://wiki.adom.inc/adom/adom-desktop",   "author": "Adom Inc.",
src/server.js+6−78
@@ -1491,26 +1491,6 @@ function osSendWindowToBack(profileName) {   } catch (e) { console.error(`[bg] send-to-back failed for "${profileName}": ${e.message}`); return false; } } -// v1.8.24: capture the user's CURRENT foreground window BEFORE we launch a pup-// browser (which grabs foreground). We hand focus back to it right after, so-// opening a pup window NEVER steals focus. Returns a decimal HWND string or null.-function osGetForegroundWindow() {-  if (process.platform !== 'win32') return null;-  try {-    const scriptPath = path.join(require('os').tmpdir(), `_adom_fg_${process.pid}_${Date.now()}.ps1`);-    const ps = [-      'Add-Type @"',-      'using System; using System.Runtime.InteropServices;',-      'public class WinFgGet { [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow(); }',-      '"@',-      'Write-Output ([int64][WinFgGet]::GetForegroundWindow())',-    ].join('\r\n');-    fs.writeFileSync(scriptPath, ps);-    const out = execSync(`powershell.exe -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}"`, { encoding: 'utf8', timeout: 4000 }).trim();-    return out && out !== '0' ? out : null;-  } catch (e) { return null; }-}- // v1.8.26: THE real "background by default" enforcement, done RIGHT. A freshly-launched // --start-maximized browser grabs foreground; osSendWindowToBack only lowers z-order and // SetForegroundWindow(userWindow) is BLOCKED by Windows' foreground lock — so the earlier@@ -1572,49 +1552,11 @@ function osBackgroundWindowByPid(pid, cdpPort) {   } catch (e) { console.error(`[bg] pid ${pid} port ${cdpPort}: ${e.message}`); return 'error'; } } -// v1.8.26: is anything actually LISTENING on host:port (from the desktop, where pup-// runs)? A quick TCP connect. Used to sanity-check localhost URLs — see localhostReachability.-function isPortListening(host, port, timeoutMs = 1200) {-  return new Promise((resolve) => {-    const net = require('net');-    const sock = new net.Socket();-    let done = false;-    const finish = (ok) => { if (done) return; done = true; try { sock.destroy(); } catch (e) {} resolve(ok); };-    sock.setTimeout(timeoutMs);-    sock.once('connect', () => finish(true));-    sock.once('timeout', () => finish(false));-    sock.once('error', () => finish(false));-    try { sock.connect(port, host); } catch (e) { finish(false); }-  });-}--// v1.8.26: pup opens URLs on the USER'S DESKTOP, so a `localhost` URL points at the-// DESKTOP's localhost — NOT the caller's cloud container. A cloud-container AI that-// serves something on its OWN localhost and asks pup to open it hits a dead port on the-// user's machine. Since pup runs ON the desktop, it can just check whether anything is-// listening there. Returns { isLocalhost, host, port, reachable }. reachable is null when-// the URL isn't localhost (nothing to warn about — e.g. a normal https site or a public-// container URL). Hydrogen Desktop + genuine desktop servers ARE reachable, so they never-// trip the warning; this only flags the container-localhost mistake.-async function localhostReachability(urlStr) {-  let host, port;-  try {-    const u = new URL(urlStr);-    host = u.hostname.replace(/^\[|\]$/g, '');-    const LH = new Set(['localhost', '127.0.0.1', '0.0.0.0', '::1']);-    const isLocalhost = LH.has(host.toLowerCase()) || /\.localhost$/i.test(host);-    port = u.port ? Number(u.port) : (u.protocol === 'https:' ? 443 : 80);-    if (!isLocalhost) return { isLocalhost: false, host, port, reachable: null };-  } catch (e) { return { isLocalhost: false, reachable: null }; }-  const probeHost = (host === '0.0.0.0' || host === '::1') ? '127.0.0.1' : host;-  const reachable = await isPortListening(probeHost, port);-  return { isLocalhost: true, host, port, reachable };-}--// The reprimand text attached when a localhost URL is NOT reachable from the desktop.-function localhostReprimandHint(urlStr, host, port) {-  return `⚠ LOCALHOST ON THE WRONG MACHINE: you opened ${urlStr}, but pup opens the browser on the USER'S DESKTOP — so "localhost" is THEIR machine, and nothing is listening on ${host}:${port} there. If you're a cloud container, localhost:${port} is YOUR container (the desktop can't reach it), so this will just show a connection error. To actually surface this to the user: (1) if it's a FILE you generated, send it to the desktop (adom-desktop file transfer) and open it as file:///C:/path/... ; or (2) expose your server at your container's PUBLIC url and open THAT. If you genuinely started a server ON the desktop via AD and it's still booting, retry shortly. (Reachable localhost servers — e.g. Hydrogen Desktop — get NO warning; you're seeing this because the port is dead here.)`;-}+// NOTE: localhost-URL reprimand (container-vs-desktop) is handled by AD CORE, which+// appends a container-topology hint to a failed response whose URL is localhost. pup+// doesn't duplicate it — and because AD keys on the connection FAILURE, Hydrogen+// Desktop's working localhost URLs load fine and never trip it. (Enriching AD's hint+// with actionable alternatives is an adom/adom-desktop request.)  // v1.8.23: REAL taskbar flash (FlashWindowEx) for a session's window — the orange // nudge that tells the user "the agent touched this window" WITHOUT stealing focus.@@ -3075,24 +3017,10 @@ const server = http.createServer(async (req, res) => {           } else if (reuse && reuse.reused) {             ownHint = ' Reused the existing window (same/no url — benign refresh).';           }-          // v1.8.26: localhost sanity — pup opens on the DESKTOP, so a localhost URL the-          // desktop can't reach is almost always the CALLER'S container localhost. Warn-          // (don't block — it might be a desktop server that's still booting).-          let lhHint = '', lhInfo = {};-          try {-            if (args.url) {-              const lh = await localhostReachability(args.url);-              if (lh.isLocalhost && lh.reachable === false) {-                lhHint = ' ' + localhostReprimandHint(args.url, lh.host, lh.port);-                lhInfo = { localhostUnreachable: true, probedHost: lh.host, probedPort: lh.port };-              }-            }-          } catch (e) {}           sendJSON(res, {             success: true,             output: JSON.stringify({               ok: true,-              ...lhInfo,               defaultPermissionsApplied: !args.strictPermissions,               defaultPermissions: args.strictPermissions ? [] : PERMISSIVE_DEFAULT_PERMISSIONS.map(p => `${p.name}=${p.setting}`),               downloadsEnabled: !args.strictPermissions,@@ -3108,7 +3036,7 @@ const server = http.createServer(async (req, res) => {               // v1.8.16: reuse/ownership verdict (null = fresh window).               reused: reuse ? { navigatedAway: reuse.navigatedAway, previousUrl: reuse.previousUrl, previousOwner: reuse.previousOwner, takeover: reuse.takeover } : null,               owner: session.owner || null,-              _hint: `${bgHint}${ownHint} ${brep._hint}${lhHint}`,+              _hint: `${bgHint}${ownHint} ${brep._hint}`,               ...info,             }),           });