← Commit history

Probe on RELOAD and NAVIGATE too, and order the response by consequence. The hole John caught: only browser_open_window ran the render probe, so a thread that hit a 404, restarted its dev server, called browser_reload and got ok:true with the GENERIC 'do not assume it rendered' hint concluded 'Mockup is now live again' — reporting success on a page nobody checked. The verb used to CONFIRM a fix is exactly the verb that must verify it, so reload and navigate now capture their own HTTP status and run probeRender, and on any render verb a detected failure PREPENDS the hint ('THE PAGE IS STILL BROKEN: ...'). Also trimmed the boilerplate that the critical fields were competing with: the ~32 pre-granted permission strings collapse to a count plus a pointer to browser_describe, and the full browser inventory collapses to compact kind(source) labels since the chosen browser is already reported separately.

John Lauer ·e8376da2b0 ·3mo ago ·parent 139a069
4 files changed +49−9
adom-bridge-puppeteer-manifest.json+4−4
@@ -1,10 +1,10 @@ {   "manifest_version": 1,   "name": "puppeteer",-  "version": "1.9.108",-  "url": "https://wiki.adom.inc/download/adom/adom-desktop-puppeteer-bridge/1.9.108/adom-bridge-puppeteer-v1.9.108.zip",-  "sha256": "412f26fb25bf59140fa75c58a652a4fb832c71a8fbccd5934ea0179cd786fbee",-  "size": 378301,+  "version": "1.9.109",+  "url": "https://wiki.adom.inc/download/adom/adom-desktop-puppeteer-bridge/1.9.109/adom-bridge-puppeteer-v1.9.109.zip",+  "sha256": "4197608726b1a25359e8197d82787b75d8f15c121d2e7374a13ed18357ce9e47",+  "size": 379403,   "verbPrefixes": [     "browser_",     "desktop_recorder_",
src/BRIDGE_VERSION+1−1
@@ -1 +1 @@-1.9.108+1.9.109
src/bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "puppeteer",   "displayName": "Puppeteer (Chrome for Testing + Native)",-  "version": "1.9.108",+  "version": "1.9.109",   "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+43−3
@@ -5920,6 +5920,16 @@ function sendJSON(res, obj, status = 200) {             if (_v && RENDER_VERBS.has(_v) && _ok && inner._verifyRender === undefined) {               const _rc2 = (res && res._renderCheck) || null;               if (_rc2 && inner.renderCheck === undefined) inner.renderCheck = _rc2;+              // v1.9.109: on ANY render verb, a detected failure must lead the hint the caller reads,+              // not just browser_open_window's (which composes its own). reload/navigate get it here.+              if (_rc2 && _rc2.ok === false && (_rc2.signals || []).length) {+                const _st = (typeof _rc2.httpStatus === 'number') ? ' (HTTP ' + _rc2.httpStatus + ')' : '';+                const _lead = '\u26D4 THE PAGE IS STILL BROKEN: ' + _rc2.signals.join(', ') + _st+                  + (_rc2.excerpt ? ' \u2014 it says "' + String(_rc2.excerpt).replace(/\s+/g, ' ').slice(0, 120) + '"' : '')+                  + '. Do NOT report success. See _verifyRender. ';+                const _cur = (inner._hint !== undefined ? inner._hint : obj._hint) || '';+                if (String(_cur).indexOf('STILL BROKEN') === -1 && String(_cur).indexOf('IS BROKEN') === -1) inner._hint = _lead + _cur;+              }               inner._verifyRender = renderVerifyHint(inner.sessionId || (obj && obj.sessionId), inner.url || (obj && obj.url), _rc2);               touched = true;             }@@ -6526,12 +6536,23 @@ const server = http.createServer(async (req, res) => {               ok: true,               highFps: hf || false,               defaultPermissionsApplied: !args.strictPermissions,-              defaultPermissions: args.strictPermissions ? [] : PERMISSIVE_DEFAULT_PERMISSIONS.map(p => `${p.name}=${p.setting}`),+              // v1.9.109 (John: "you can trim the bloat if you think that just causes the ai to ignore+              // stuff") — this emitted all ~32 permission strings on EVERY open. The caller never acts on+              // them, and they were padding the response that a 404 verdict had to compete with. Ordering+              // by consequence means boilerplate collapses to a count + a pointer.+              defaultPermissionsCount: args.strictPermissions ? 0 : PERMISSIVE_DEFAULT_PERMISSIONS.length,+              defaultPermissionsNote: args.strictPermissions+                ? 'strictPermissions: nothing pre-granted'+                : 'full browser permissions pre-granted (clipboard, camera, geolocation, window-management, ...) — browser_describe has the exact list',               downloadsEnabled: !args.strictPermissions,               downloadPath,               // v1.4.0: which browser pup drove + the full fallback picture.               browser: brep.browser,-              availableBrowsers: brep.availableBrowsers,+              // Same treatment: the full browser inventory is a one-time discovery fact, not something a+              // caller re-reads on every open. The chosen browser is already reported in `browser`.+              availableBrowsers: (() => {+                try { return (brep.availableBrowsers || []).map(b => `${b.kind}(${b.source})`); } catch (e) { return brep.availableBrowsers; }+              })(),               defaultBrowser: brep.defaultBrowser,               // v1.8.0: window placement — background unless explicitly foregrounded.               placement: foreground ? 'foreground' : 'background',@@ -8335,14 +8356,27 @@ const server = http.createServer(async (req, res) => {           try { ({ tab, tabId } = resolveTabOrError(session, resolvedId, args, { allowCrashed: true })); }           catch (e) { sendTabResolveError(res, e); return; }           tab.errors.length = 0;-          await withTimeout(+          // v1.9.109: keep the reload's own HTTP status — page.reload() returns the response, and this+          // is the verb an AI uses right after "I fixed it", so a still-broken page must be caught here.+          const _rlResp = await withTimeout(             tab.page.reload({ waitUntil: 'domcontentloaded', timeout: 25000 }),             30_000, 'page.reload'           );+          try { tab.page.__pupHttpStatus = _rlResp && typeof _rlResp.status === 'function' ? _rlResp.status() : null; } catch (e) {}           if (tab._crashed) { tab._crashed = false; delete tab._crashedAt; delete tab._crashReason; console.log(`[crash] session "${resolvedId}" tab ${tabId} recovered via reload`); }           // v1.8.26: the user is signalled by the auto-flash, NOT by raising the window.           // Only raise if this session is one the user is actively watching.           if (session._foreground) { try { await tab.page.bringToFront(); } catch {} }+          // v1.9.109 — PROBE ON RELOAD TOO. This was the hole: only browser_open_window probed, so a+          // thread that hit a 404, fixed its dev server, called browser_reload and got ok:true with the+          // GENERIC "do not assume it rendered" hint concluded "Mockup is now live again" — reporting+          // success on a page nobody had checked. The verb used to confirm a fix is exactly the verb+          // that must verify it.+          try { res._renderCheck = await probeRender(tab.page, tab.page.__pupHttpStatus); } catch (e) {}+          try {+            const _rc = res._renderCheck;+            if (_rc && _rc.ok === false) console.log(`[render] "${resolvedId}" STILL BROKEN after reload: ${_rc.signals.join(', ')}`);+          } catch (e) {}           sendJSON(res, { success: true, output: JSON.stringify({ ok: true, sessionId: resolvedId, tabId }) });           return;         }@@ -8424,6 +8458,12 @@ const server = http.createServer(async (req, res) => {             setTimeout(() => { updateWikiJumplist(session, resolvedId).catch(() => {}); }, 1000);           }           if (tab._crashed) { tab._crashed = false; delete tab._crashedAt; delete tab._crashReason; console.log(`[crash] session "${resolvedId}" tab ${tabId} recovered via navigate`); }+          // v1.9.109: probe on navigate as well — same reasoning as reload.+          try { res._renderCheck = await probeRender(tab.page, tab.page.__pupHttpStatus); } catch (e) {}+          try {+            const _rc = res._renderCheck;+            if (_rc && _rc.ok === false) console.log(`[render] "${resolvedId}" BROKEN after navigate to ${args.url}: ${_rc.signals.join(', ')}`);+          } catch (e) {}           sendJSON(res, { success: true, output: JSON.stringify({ ok: true, url: args.url, sessionId: resolvedId, tabId, ...(authSteerHint(args.url) ? { _hint: authSteerHint(args.url).trim() } : {}) }) });           return;         }