← Commit history

v1.8.37: cleanup nudge — browser_status/open _hint reminds the agent to close stale/piled-up pup windows (never auto-closes); skill: 'clean up after yourself' section

John Lauer ·caee4bb0d9 · ·parent 951983a
6 files changed +51−10
adom-bridge-puppeteer-manifest.json+5−5
@@ -1,10 +1,10 @@ {   "manifest_version": 1,   "name": "puppeteer",-  "version": "1.8.36",-  "url": "https://wiki.adom.inc/download/adom/adom-desktop-puppeteer-bridge/1.8.36/adom-bridge-puppeteer-v1.8.36.zip",-  "sha256": "e335d2cfb7b68a005eb4a31988954c690871e64eb8e9c31e3e4cae6e7c74aea7",-  "size": 157535,+  "version": "1.8.37",+  "url": "https://wiki.adom.inc/download/adom/adom-desktop-puppeteer-bridge/1.8.37/adom-bridge-puppeteer-v1.8.37.zip",+  "sha256": "594ac30fcfbe258b570f1334f1d279f13391e7b32e3a06c19ac9dab2439f4278",+  "size": 158194,   "verbPrefixes": [     "browser_",     "desktop_recorder_",@@ -12,5 +12,5 @@   ],   "healthEndpoint": "/status",   "statusVerb": "browser_readiness",-  "released_at": "2026-07-14T20:52:41Z"+  "released_at": "2026-07-14T20:59:35Z" }\ No newline at end of file
package.json+2−2
@@ -1,8 +1,8 @@ {   "slug": "adom-desktop-puppeteer-bridge",-  "version": "1.8.30",+  "version": "1.8.38",   "type": "app",-  "description": "The pup SKILL PACK \u2014 the AI skills that teach a cloud/container AI how to drive the Adom Desktop Puppeteer (pup) bridge (browser_* verbs): the everyday `pup` skill plus focused sub-skills for windows/sessions/tabs, screenshots+recording, browsers+Chrome install, and driving the Adom wiki. Installs into ~/.claude/skills + ~/.codex/skills. DOCS ONLY \u2014 this is NOT the bridge runtime. The bridge itself (the Node program that drives the browser) runs on the DESKTOP: Adom Desktop bundles it and auto-installs/updates it, and it's published separately on the Releases tab as adom-bridge-puppeteer-v<ver>.zip. So the pkg version (skills, bumps often) and the Release version (runtime, bumps rarely) differ on purpose. TL;DR: pkg install = the skills for your AI; the bridge = the Release zip, which Adom Desktop manages for you.",+  "description": "The pup SKILL PACK — the AI skills that teach a cloud/container AI how to drive the Adom Desktop Puppeteer (pup) bridge (browser_* verbs): the everyday `pup` skill plus focused sub-skills for windows/sessions/tabs, screenshots+recording, browsers+Chrome install, and driving the Adom wiki. Installs into ~/.claude/skills + ~/.codex/skills. DOCS ONLY — this is NOT the bridge runtime. The bridge itself (the Node program that drives the browser) runs on the DESKTOP: Adom Desktop bundles it and auto-installs/updates it, and it's published separately on the Releases tab as adom-bridge-puppeteer-v<ver>.zip. So the pkg version (skills, bumps often) and the Release version (runtime, bumps rarely) differ on purpose. TL;DR: pkg install = the skills for your AI; the bridge = the Release zip, which Adom Desktop manages for you.",   "keywords": [     "pup",     "puppeteer",
skills/pup-windows-sessions-tabs/SKILL.md+16
@@ -119,6 +119,22 @@ adom-desktop browser_close_tab   '{"sessionId":"task-web","tabId":"tab-2"}' Opening the same content under a new `sessionId` leaves the user staring at two identical windows — so `browser_status` first and reuse when the URL is already open. +## Clean up after yourself — close windows when the task is done++pup **never auto-closes** a window (a "stale" one might belong to a thread that's just paused+between turns). So every window you open lingers on the **user's real desktop** until *you* close it.+Left alone, a day of tasks piles up a dozen dead pup windows the user has to find and close.++- **When you finish a task, `browser_close_window` the windows you opened for it.** Same for one-off+  windows (a quick screenshot/scrape) — close them right after.+- **Check what's yours:** `browser_status` lists every window with its `owner` and `ageMinutes`, and+  now nudges you (a `🧹 CLEANUP` hint) when windows are old (≥30 min) or piling up. Act on it — close+  the ones you're done with. Only close windows **you own**; never close another thread's.+- **Long-running work?** Reuse ONE window (`browser_navigate` / `browser_open_tab`) instead of opening+  a fresh window each step, so there's only one thing to clean up.+- If you truly need a window to persist across turns (a login you'll reuse for hours), that's fine —+  but it's a deliberate choice, and you still own closing it when done.+ ## Verify what you opened — `ok:true` is not enough  `browser_open_window` returns `ok:true` as soon as navigation *starts*, not when content rendered. Confirm
src/BRIDGE_VERSION+1−1
@@ -1 +1 @@-1.8.36+1.8.37
src/bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "puppeteer",   "displayName": "Puppeteer (Chrome for Testing + Native)",-  "version": "1.8.36",+  "version": "1.8.37",   "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+26−1
@@ -1679,6 +1679,27 @@ function recordAgentUpdate(session, verb, args, tabId) {   if (upd.tabId) { const t = (session.tabs || []).find(x => x.tabId === upd.tabId); if (t) t.lastAgentUpdate = upd; } } +// v1.8.37: CLEANUP NUDGE. pup never auto-closes windows (a "stale" one may belong to a+// paused thread), so windows an agent opened for a finished task otherwise pile up on the+// user's desktop forever. This returns a _hint (appended to open/status responses) reminding+// the caller to close what it's done with — but only when it's actually worth nagging: some+// window is old (≥ OLD_MIN) OR there are a lot of them (≥ MANY). Lists the oldest offenders.+function staleWindowsHint() {+  try {+    const OLD_MIN = 30, MANY = 5;+    const now = Date.now();+    const all = [];+    for (const [sid, s] of sessions) {+      all.push({ sid, ageMin: s.createdAt ? Math.round((now - s.createdAt) / 60000) : 0, owner: s.owner || null });+    }+    const old = all.filter(w => w.ageMin >= OLD_MIN);+    if (old.length === 0 && all.length < MANY) return '';+    const show = (old.length ? old : all).sort((a, b) => b.ageMin - a.ageMin).slice(0, 6)+      .map(w => `${w.sid}${w.owner ? `(owner:${w.owner})` : ''}=${w.ageMin}m`).join(', ');+    return ` 🧹 CLEANUP: ${all.length} pup window(s) open${old.length ? `, ${old.length} ≥${OLD_MIN}m old` : ''} — close the ones you're DONE with via browser_close_window so they don't pile up on the user's desktop (pup never auto-closes; that's your job when a task ends). Oldest: [${show}].`;+  } catch (e) { return ''; }+}+ // Resize/position a session's window via CDP (works for detached+connected). Setting // explicit bounds also un-maximizes the window (--start-maximized is otherwise the // default). x/y/width/height in screen pixels; any subset is honored.@@ -3112,7 +3133,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}`,+              _hint: `${bgHint}${ownHint} ${brep._hint}${staleWindowsHint()}`,               ...info,             }),           });@@ -4511,6 +4532,10 @@ const server = http.createServer(async (req, res) => {           // Add guidance when no sessions exist so the AI knows what to do next           if (sessions.size === 0) {             statusResult.hint = 'No browser sessions are open. Use browser_open_window with sessionId, profile, and url to launch a Chrome window on the desktop before using screenshot/eval/navigate.';+          } else {+            // v1.8.37: nudge to close stale/piled-up windows (each row already has ageMinutes+owner).+            const cln = staleWindowsHint();+            if (cln) statusResult.hint = cln.trim();           }           sendJSON(res, { success: true, output: JSON.stringify(statusResult) });           return;