app
Pup - the AI's own browser
Public Made by Adomby adom
pup gives your AI a real browser on your desktop that it drives completely, in the background, signed in as you: windows that never jump in front of your work, one shared profile that learns your logins, and every window labeled on the taskbar with its AI thread's name.
← Commit history
FG-STEAL GUARD (John: 'why did that pup window that just opened to the adom-theme disrupt me in the foreground?'). Diagnosis from the log: the ats-publish window (hd-theme thread) was born off-screen, backgrounded, and bottomed post-nav as designed - but Chrome SELF-RAISES parked windows on late paints / in-page focus(), the sibling adom-vscode-wiki window needed SIX re-bottoms in a row, and once the scripted re-asserts end a late raise STICKS. The v1.9.180 user-activity watcher that would have caught it is minimal-touch-gated, i.e. dead in the normal mode (the same dead-under-the-gate disease as the overlay enforcer). Fix: an ungated fg-steal guard - for 20s after any background open/navigation (armed inside reassertBottomAfterNav so every open/nav/new-tab path arms it), pup polls the OS foreground at 2.5s ONLY while a guard is armed (zero steady-state cost) and immediately bottoms a background pup window found holding the foreground without a granted foregroundReason, returning the screen to the user. Three knockbacks inside one guard window means a human is insisting, so the human wins: guard backs off and marks the window user-foreground. Deliberately NOT gated by minimal-touch: user protection, same doctrine as the foreground-reason caption. Rule + history recorded in dev-skills/pup-bridge-dev.
4 files changed
+54−6
adom-bridge-puppeteer-manifest.json+4−4@@ -1,10 +1,10 @@ { "manifest_version": 1, "name": "puppeteer",- "version": "1.9.251",- "url": "https://wiki.adom.inc/download/adom/adom-desktop-puppeteer-bridge/1.9.251/adom-bridge-puppeteer-v1.9.251.zip",- "sha256": "0246f4e9fb866b3fc7699fd589c7c0c1ded677b63d509413a1250a1336135d15",- "size": 470281,+ "version": "1.9.252",+ "url": "https://wiki.adom.inc/download/adom/adom-desktop-puppeteer-bridge/1.9.252/adom-bridge-puppeteer-v1.9.252.zip",+ "sha256": "14dac85ae41fc539350c2d058b04e426c7a776b716530b06132ac0d940781937",+ "size": 471245, "verbPrefixes": [ "browser_", "desktop_recorder_",
src/BRIDGE_VERSION+1−1@@ -1 +1 @@-1.9.251+1.9.252
src/bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "puppeteer", "displayName": "Puppeteer (Chrome for Testing + Native)",- "version": "1.9.251",+ "version": "1.9.252", "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+48@@ -5781,6 +5781,19 @@ async function parkSessionWindowDirect(page, sessionId) { // batch sat on top with honest 'backgrounded' verdicts; a later same-window navigate does NOT // raise — tested). force:false so AD skips a window the user is actively holding foreground. async function reassertBottomAfterNav(sessionId) {+ // v1.9.252 (John: "why did that pup window that just opened to the adom-theme disrupt me in the+ // foreground?"): arm the FG-STEAL GUARD. Chrome can self-raise a parked background window on late+ // paints or an in-page focus() AFTER these scripted re-asserts finish, and under minimal-touch the+ // old watcher that would notice was disabled - so the steal stuck and the user got disrupted. For+ // 20s after any background open/navigation, the guard interval below knocks back any un-granted+ // foreground takeover the moment it is seen.+ try {+ const _gs = sessions.get(sessionId);+ if (_gs && !_gs._foreground) {+ if (!_gs._fgGuardUntil || _gs._fgGuardUntil < Date.now()) _gs._fgStealCount = 0; // fresh arm resets the strike count+ _gs._fgGuardUntil = Date.now() + 20000;+ }+ } catch (e) {} if (process.platform !== 'win32' || !sessionId) return; // v1.9.201 (John's PDF window came to the front with NO ai requesting it): this used ONLY AD's // desktop_set_window_state — a verb that is NOT present on every desktop (the Bills thread hit@@ -12415,6 +12428,41 @@ server.listen(PORT, BIND_HOST, async () => { const _healingIds = new Set(); // sessionIds with a relaunch in flight (guards the 15s re-tick) const MAX_HEAL_ATTEMPTS = 2; const HEAL_COOLDOWN_MS = 5 * 60 * 1000;+ // v1.9.252 FG-STEAL GUARD (ungated: user protection, not cosmetic machinery - the same doctrine+ // as the foreground caption). A background pup window must NEVER sit in the OS foreground without+ // a granted foregroundReason. Chrome self-raises parked windows (late first paint, in-page+ // focus()), and the fixed post-nav re-asserts can end before the last raise. While any session's+ // guard is armed (20s after each background open/nav), one cheap foreground read per 2.5s tick+ // catches the steal and bottoms the window immediately, giving the user their screen back.+ // Steady-state (no guards armed) costs nothing. A user's own deliberate raise outside the guard+ // window, or any granted raise (_foreground), is never touched.+ setInterval(async () => {+ if (process.platform !== 'win32') return;+ try {+ const now = Date.now();+ const guarded = [...sessions].filter(([, s2]) => s2._fgGuardUntil && s2._fgGuardUntil > now && !s2._foreground && !s2._lostBrowser);+ if (!guarded.length) return;+ const fg = osGetForegroundWindow();+ if (!fg) return;+ for (const [sid2, s2] of guarded) {+ try {+ if (!s2._hwnd) { try { await resolveSessionHwndByBounds(s2, sid2); } catch (e) {} }+ if (!s2._hwnd || String(fg) !== String(s2._hwnd)) continue;+ if ((s2._fgStealCount || 0) >= 3) {+ // three knockbacks in one guard window = a human is insisting; the human wins.+ s2._fgGuardUntil = 0; s2._foreground = true;+ console.log(`[fg-guard] "${sid2}" raised 3x inside one guard window — assuming the USER wants it up; backing off and marking foreground`);+ continue;+ }+ console.log(`[fg-guard] "${sid2}" STOLE the OS foreground with no granted reason (Chrome self-raise) — bottoming it and returning the screen to the user`);+ s2._fgStealCount = (s2._fgStealCount || 0) + 1;+ await reassertBottomAfterNav(sid2);+ break;+ } catch (e) {}+ }+ } catch (e) {}+ }, 2500);+ // v1.9.243 (John: "you have red led's galore in your dashboard. why?"). The overlay ENFORCER was // dead on arrival: it sat inside the health interval ABOVE, whose first line is `if (minimalTouch()) // return;` — and minimal-touch is the normal mode, so it never ran once. Overlays are explicitly