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.
master
John Lauer
v2.0.727 (insiders): A pup window waiting on a slow page now explains itself instead of showing a blank PUPBIRTH tab: w…
b75d102
22d ago
// pup birth page script (2.0.632). Lives in its own file because an extension page's default content
// security policy refuses inline scripts: an inline version left every title at plain "PUPBIRTH", so pup's
// token lookup timed out on every open and the window showed for the 3 s it waited (measured, 2.0.631).
// 2.0.726: fills in who opened the window, why and where it is going, and counts the wait (John, 2026-10-19).
const q = new URLSearchParams(location.search);
const t = q.get('token') || '';
if (t) document.title = 'PUPBIRTH-' + t;
const thread = (q.get('t') || '').trim();
const reason = (q.get('r') || '').trim();
const target = (q.get('u') || '').trim();
const born = Number(q.get('at')) || Date.now();
const real = /^https?:\/\//i.test(target);
let host = '';
try { if (real) host = new URL(target).host; } catch (e) { host = ''; }
function fill() {
const $ = (id) => document.getElementById(id);
$('head').textContent = host ? 'Opening ' + host : 'Opening a page';
$('thread').textContent = thread ? 'the AI thread "' + thread + '"' : 'an AI thread that did not give its name';
$('reason').textContent = reason || 'The thread did not say why when it opened this window.';
const tv = $('target');
if (real) {
const a = document.createElement('a');
a.href = target; a.textContent = target; // clicking it goes there now, in this same tab
tv.appendChild(a);
} else {
tv.textContent = 'pup has not been told the address yet; the thread will send it next.';
}
const st = $('status');
const tick = () => {
const s = Math.max(0, Math.round((Date.now() - born) / 1000));
const slow = s >= 20;
st.className = 'status' + (slow ? ' slow' : '');
st.textContent = real
? (slow ? 'Still waiting for ' + host + ' to answer (' + s + ' s). The site is slow right now; pup keeps waiting and tries again on its own.'
: 'Waiting for ' + host + ' to answer (' + s + ' s).')
: 'Waiting for the thread to say where to go (' + s + ' s).';
};
tick(); setInterval(tick, 1000);
$('card').classList.remove('hidden');
// The PUPBIRTH-<token> title is how pup finds this window, and it binds within 3 s of the create. Once that is
// long done, give the tab and the taskbar a title a person can read.
setTimeout(() => { document.title = (host ? 'Opening ' + host : 'Opening a page') + (thread ? ' for ' + thread : '') + ' (pup)'; }, 10000);
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', fill); else fill();