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
v2.0.711 (insiders): Alt+Shift+A starts Annotate in pup windows, including while focus is inside an embedded frame (a video player, an embedded document): the key is caught in every frame of the page. Chrome keeps Alt+Shift+A for itself, so the address bar and Chrome's own pages stay out of reach (John, 2026-10-11). Includes 2.0.709: closed isolated windows no longer leave Chrome for Testing icons in the system tray. Gates on arav-rog: smoke all pass (2 of 3 runs; one run's demo-site login landed late), foreground pass, parity 55/56, jump list 12/15.
4 files changed
+17−15
rust/Cargo.lock+12−12@@ -10,7 +10,7 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "adom-pup-bridge"-version = "2.0.709"+version = "2.0.711" dependencies = [ "pup-browser", "pup-cdp",@@ -655,7 +655,7 @@ dependencies = [ [[package]] name = "pup-browser"-version = "2.0.709"+version = "2.0.711" dependencies = [ "pup-core", "pup-host",@@ -667,7 +667,7 @@ dependencies = [ [[package]] name = "pup-cdp"-version = "2.0.709"+version = "2.0.711" dependencies = [ "serde_json", "thiserror",@@ -677,7 +677,7 @@ dependencies = [ [[package]] name = "pup-core"-version = "2.0.709"+version = "2.0.711" dependencies = [ "serde", "serde_json",@@ -687,7 +687,7 @@ dependencies = [ [[package]] name = "pup-dashboard"-version = "2.0.709"+version = "2.0.711" dependencies = [ "pup-cdp", "pup-core",@@ -700,7 +700,7 @@ dependencies = [ [[package]] name = "pup-host"-version = "2.0.709"+version = "2.0.711" dependencies = [ "serde", "serde_json",@@ -709,14 +709,14 @@ dependencies = [ [[package]] name = "pup-host-mac"-version = "2.0.709"+version = "2.0.711" dependencies = [ "pup-host", ] [[package]] name = "pup-host-win"-version = "2.0.709"+version = "2.0.711" dependencies = [ "pup-core", "pup-host",@@ -726,7 +726,7 @@ dependencies = [ [[package]] name = "pup-identity"-version = "2.0.709"+version = "2.0.711" dependencies = [ "fontdue", "image",@@ -736,7 +736,7 @@ dependencies = [ [[package]] name = "pup-session"-version = "2.0.709"+version = "2.0.711" dependencies = [ "pup-core", "serde",@@ -746,7 +746,7 @@ dependencies = [ [[package]] name = "pup-vault"-version = "2.0.709"+version = "2.0.711" dependencies = [ "pup-core", "pup-host",@@ -757,7 +757,7 @@ dependencies = [ [[package]] name = "pup-verbs"-version = "2.0.709"+version = "2.0.711" dependencies = [ "base64", "png 0.17.16",
rust/Cargo.toml+1−1@@ -4,7 +4,7 @@ members = ["core", "host", "host-win", "host-mac", "cdp", "browser", "session", # One version for the whole bridge, in lockstep with src/BRIDGE_VERSION (tools/ship.sh bumps both). [workspace.package]-version = "2.0.709"+version = "2.0.711" edition = "2021" license = "MIT"
src/extension/content.js+3−1@@ -3,7 +3,8 @@ // Rendered by the extension (not pup injection) so the click can route through the worker to // pup's loopback. Gated by pup's tbFloatyPencil setting (checked once per page load). (async () => {- if (window !== window.top) return;+ // 2.0.711: this script now runs in EVERY frame, so Alt+Shift+A works while focus is inside an embedded frame (a+ // YouTube player, an embedded document). Only the hotkey runs in subframes; the pencil stays top-frame only. if (window.__pupFloatyInstalled) return; window.__pupFloatyInstalled = true; try {@@ -20,6 +21,7 @@ chrome.runtime.sendMessage({ t: 'pup-annotate', tool: 'pen' }).catch(() => {}); }, true); }+ if (window !== window.top) return; if (!cfg || !cfg.enabled) return; const host = document.createElement('div');
src/extension/worker.js+1−1@@ -144,7 +144,7 @@ chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { // and action all work), so the worker injects the floaty itself when a tab finishes loading. chrome.tabs.onUpdated.addListener((tabId, info, tab) => { if (info.status !== 'complete' || !tab || !tab.url || !/^https?:/.test(tab.url)) return;- chrome.scripting.executeScript({ target: { tabId }, files: ['content.js'] }).catch(() => {});+ chrome.scripting.executeScript({ target: { tabId, allFrames: true }, files: ['content.js'] }).catch(() => {}); // 2.0.711: every frame, for the hotkey // 2.0.602: the login-capture rail. It lived only on the CDP lane, so a password typed in a normal // (extension-lane) pup window was never stored: pup's whole "sign in once and I remember" promise was // off on the DEFAULT lane. Injected the same way as content.js because declarative content_scripts do