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
Fix 1.9.147's dead-on-arrival thread-default window: a legacy 'sessionId is required' gate at the top of browser_open_window rejected every no-id call before the new thread-keyed block could run — caught because the ship-then-prove harness ran the exact three-thread scenario and all opens failed with the legacy error text. The gate now only refuses the fully anonymous case (no sessionId AND no caller identity) with the teaching caller_identity_required error; thread-identified no-id opens flow through to the thread-window logic. VERB_META's 'sessionId is required' pitfall rewritten to recommend omitting it.
4 files changed
+13−9
adom-bridge-puppeteer-manifest.json+4−4@@ -1,10 +1,10 @@ { "manifest_version": 1, "name": "puppeteer",- "version": "1.9.147",- "url": "https://wiki.adom.inc/download/adom/adom-desktop-puppeteer-bridge/1.9.147/adom-bridge-puppeteer-v1.9.147.zip",- "sha256": "aff60037876049f5c6b02a542ca099ee98ce7b55528b0981af6502f7576022db",- "size": 399314,+ "version": "1.9.148",+ "url": "https://wiki.adom.inc/download/adom/adom-desktop-puppeteer-bridge/1.9.148/adom-bridge-puppeteer-v1.9.148.zip",+ "sha256": "b90700626eb0a07b4d0a23b0a698c1cdc701cf159094869219946dd729d9f8fe",+ "size": 399459, "verbPrefixes": [ "browser_", "desktop_recorder_",
src/BRIDGE_VERSION+1−1@@ -1 +1 @@-1.9.147+1.9.148
src/bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "puppeteer", "displayName": "Puppeteer (Chrome for Testing + Native)",- "version": "1.9.147",+ "version": "1.9.148", "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+7−3@@ -5984,7 +5984,7 @@ setInterval(async () => { // asked to adopt: a calling AI should never have to guess and never have to // read docs first. { verb: { hint, related[], pitfalls[] } }. const VERB_META = {- browser_open_window: { hint: 'Opens a generic, fully-controllable pup window (a fresh isolated Chrome/Edge process — never your real signed-in browser) that you then drive by sessionId. To drive the user\'s REAL Chrome/Edge, use the Adom browser extension\'s nbrowser_* verbs instead.', related: ['browser_navigate', 'browser_list_windows', 'browser_close_window'], pitfalls: ['sessionId is required and is your handle for every later call', 'profile defaults to the durable shared \'adom-you\' profile (logins/localStorage persist + are shared across all pup windows); isolated:true for a private throwaway — omit it for a plain "open in pup"', 'sessionIds are SHARED across all AI threads on this desktop — a generic id ("wiki", "test") may collide with another thread\'s window and navigating it away steals their work. Use a task-prefixed sessionId + pass owner:"<your-task>" so pup can protect it', 'reusing an existing sessionId with a new url NAVIGATES that window — check browser_status (shows owner per window) first if unsure'] },+ browser_open_window: { hint: 'Opens a generic, fully-controllable pup window (a fresh isolated Chrome/Edge process — never your real signed-in browser) that you then drive by sessionId. To drive the user\'s REAL Chrome/Edge, use the Adom browser extension\'s nbrowser_* verbs instead.', related: ['browser_navigate', 'browser_list_windows', 'browser_close_window'], pitfalls: ['sessionId is OPTIONAL: omit it and your thread gets its OWN window (keyed on your --ai-thread name; later opens become tabs in it). Pass one only for a deliberate separate window — it is then your handle for every later call', 'profile defaults to the durable shared \'adom-you\' profile (logins/localStorage persist + are shared across all pup windows); isolated:true for a private throwaway — omit it for a plain "open in pup"', 'sessionIds are SHARED across all AI threads on this desktop — a generic id ("wiki", "test") may collide with another thread\'s window and navigating it away steals their work. Use a task-prefixed sessionId + pass owner:"<your-task>" so pup can protect it', 'reusing an existing sessionId with a new url NAVIGATES that window — check browser_status (shows owner per window) first if unsure'] }, browser_open_tab: { hint: 'Adds a tab to an existing session; returns the new tabId.', related: ['browser_switch_tab', 'browser_list_tabs', 'browser_close_tab'], pitfalls: ['the session must already exist (browser_open_window first)'] }, browser_close_tab: { hint: 'Closes one tab; the session stays open.', related: ['browser_close_window', 'browser_list_tabs'], pitfalls: ['omit tabId to close the active tab — closing the last tab may close the window'] }, browser_close_window: { hint: 'Closes the whole session and all its tabs. Destructive.', related: ['browser_list_windows'], pitfalls: ['this ends the session — its sessionId is no longer valid afterward'] },@@ -6613,8 +6613,12 @@ const server = http.createServer(async (req, res) => { } // --- Session management commands --- case 'browser_open_window': {- if (!args.sessionId) {- sendJSON(res, { success: false, error: 'sessionId is required. Example: browser_open_window { "sessionId": "dart2", "profile": "dart2", "url": "https://..." }' });+ // v1.9.147: sessionId is OPTIONAL when the caller identifies its thread — the thread gets+ // its own keyed window (see the thread-default block below). Only the fully anonymous+ // no-id no-thread case is refused, down there, with a teaching error.+ if (!args.sessionId && !_callerThread) {+ sendJSON(res, { success: false, errorCode: 'caller_identity_required',+ error: 'No sessionId AND no caller identity. Either pass a sessionId, or (better) identify your thread — adom-desktop --ai-thread "<your thread>" ... — and pup gives your thread its OWN window automatically: first open creates it, later opens become tabs in it, and no other thread can touch it.' }); return; } // ── Cold-start gate (v1.9.90: NATIVE-FIRST) — READ-ONLY detect; never blocks when drivable ──