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
Dashboard Settings: 'Import logins from Chrome/Edge' picker (adom-you seed). Reads browser_import_scan, lists every discovered profile with source-account identity tags + saved-login count + ABE lock, checkbox each (default all). Import button reports honest-pending until the AD-core elevated decrypt helper (adom/adom-desktop #51) lands.
4 files changed
+68−8
adom-bridge-puppeteer-manifest.json+4−4@@ -1,10 +1,10 @@ { "manifest_version": 1, "name": "puppeteer",- "version": "1.9.322",- "url": "https://wiki.adom.inc/download/adom/adom-desktop-puppeteer-bridge/1.9.322/adom-bridge-puppeteer-v1.9.322.zip",- "sha256": "490fcd9d57963f569aeb498f3d8003674207824e981cd62519417401b652296a",- "size": 616629,+ "version": "1.9.323",+ "url": "https://wiki.adom.inc/download/adom/adom-desktop-puppeteer-bridge/1.9.323/adom-bridge-puppeteer-v1.9.323.zip",+ "sha256": "db1c74ae4f95237e1e40d1b629d947de5acf709e75d6ccdf077e721e00d31a17",+ "size": 618569, "verbPrefixes": [ "browser_", "desktop_recorder_",
src/BRIDGE_VERSION+1−1@@ -1 +1 @@-1.9.322+1.9.323
src/bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "puppeteer", "displayName": "Puppeteer (Chrome for Testing + Native)",- "version": "1.9.322",+ "version": "1.9.323", "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+62−2@@ -9258,7 +9258,7 @@ function toast(msg,type){ _q('#toasts').appendChild(t); setTimeout(()=>{t.classList.add('out');setTimeout(()=>t.remove(),350)},type==='error'?8000:4000); }-const ACTMSG={'flash':'flashed the taskbar button of','unflash':'taskbar flash cleared on','flash-all':'flashed every pup taskbar button','unflash-all':'cleared every taskbar flash','close-all':'closed all pup windows','close-window':'closed','close-tab':'closed tab in','fg':'bringing to front:','bg':'sent to background:','set-setting':'setting saved','test-caption':'sample caption shown on your screen','regen-overlays':'regenerated all overlay icons'};+const ACTMSG={'flash':'flashed the taskbar button of','unflash':'taskbar flash cleared on','flash-all':'flashed every pup taskbar button','unflash-all':'cleared every taskbar flash','close-all':'closed all pup windows','close-window':'closed','close-tab':'closed tab in','fg':'bringing to front:','bg':'sent to background:','set-setting':'setting saved','test-caption':'sample caption shown on your screen','regen-overlays':'regenerated all overlay icons','import-scan':'scanned your browsers for logins','import-run':'import'}; async function act(p){ try{ const r=await fetch('/dashboard/action',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(p)});@@ -9322,6 +9322,43 @@ const SETTINGS_DEF=[ {k:'notMineCaption',l:'"Not foregrounded by Adom" caption',d:'Low importance. When a window comes to the front on its own (JavaScript, a focus change, Chrome), briefly caption that Adom did NOT do it. It stays SILENT when YOU raised the window (detected via recent taskbar/keyboard input), so your own clicks never trigger it. Default on.'}, {k:'minimalTouch',l:'Minimal-touch mode',d:'The safety mode from the Chrome crash hunt. ON means pup keeps its hands off your windows: it only opens them and drives the pages inside, and skips the extra Windows machinery (identity stamps, window sweeps, shell churn) that was suspected of freezing Chrome. The toggles above are the real per-feature controls now and they win over this switch. Rule of thumb: leave this ON; if pup ever gets crashy, make sure it is ON and turn features back on one at a time to find the culprit.'}, ];+// Import-logins picker (the adom-you seed). Discovery runs today via browser_import_scan; the+// actual decrypt is AD-core (adom/adom-desktop #51) so the Import button reports honest-pending.+let _importScan=null; let _importSel={};+function _idTag(a){return '<span style="display:inline-block;background:rgba(120,150,205,.22);border-radius:4px;padding:1px 6px;margin:0 4px 2px 0;font-size:11px;white-space:nowrap">'+esc(a)+'</span>';}+function _idBadges(accts){return (accts&&accts.length)?accts.map(_idTag).join(''):'<span style="opacity:.55;font-size:11px">no linked account</span>';}+function importSectionHtml(){+ const s=_importScan; let rows='';+ if(s&&s.profiles){+ rows=s.profiles.length?s.profiles.map(p=>{+ const key=p.browser+'/'+p.profileDir, on=_importSel[key]!==false;+ const cnt=(p.passwordCount==null?'?':p.passwordCount)+' logins';+ const lock=p.abe?'<span style="opacity:.6;font-size:11px" title="App-Bound Encrypted - needs admin approval to decrypt">🔒 encrypted</span>':'';+ return '<div class="srow" style="padding:8px 0"><label class="stxt" style="cursor:pointer;display:flex;gap:10px;align-items:flex-start;width:100%">'+ +'<input type="checkbox" data-imchk="'+esc(key)+'"'+(on?' checked':'')+' style="margin-top:3px;flex:0 0 auto">'+ +'<span style="flex:1 1 auto;min-width:0"><div class="slbl">'+esc(p.browserName||p.browser)+' — '+esc(p.profileName||p.profileDir)+'</div>'+ +'<div class="sdesc">'+cnt+' '+_idBadges(p.accounts)+' '+lock+'</div></span></label></div>';+ }).join(''):'<div class="sdesc">No Chrome / Edge / Brave profiles found on this machine.</div>';+ }+ const has=s&&s.profiles&&s.profiles.length;+ const summary=s?'<div class="sdesc" style="margin:8px 0">Found <b>'+(s.profiles?s.profiles.length:0)+'</b> profile(s), ~<b>'+(s.totalPasswords||0)+'</b> saved logins across '+((s.accounts&&s.accounts.length)?s.accounts.map(esc).join(', '):'no linked accounts')+'.'+(s.pythonAvailable?'':' <span style="opacity:.6">(login counts unavailable - python not found)</span>')+'</div>':'';+ return '<div class="srow" style="flex-direction:column;align-items:stretch;border-top:2px solid rgba(255,255,255,.16);margin-top:16px;padding-top:14px">'+ +'<div class="slbl" style="font-size:15px">Import logins from Chrome / Edge <span class="ibadge" data-tip="Seeds the shared adom-you profile with the logins you already have, tagged by which account they came from ([email protected] vs [email protected] vs [email protected]) so the agent acts as the right you on each site. Discovery runs now; the actual decrypt needs one Windows admin approval, being built in Adom Desktop core (issue #51).">i</span></div>'+ +'<div class="sdesc">Build a comprehensive adom-you profile from every browser profile on this machine. Each login stays tagged by its source account so the agent picks the right identity per site.</div>'+ +'<div style="display:flex;gap:8px;margin:12px 0;flex-wrap:wrap"><button class="btn sm" id="importScanBtn">'+(s?'Rescan browsers':'Scan my browsers')+'</button>'+ +(has?'<button class="btn sm" id="importRunBtn">Import selected logins</button>':'')+'</div>'+ +summary+rows+ +(has?'<div id="importStatus" class="sdesc" style="opacity:.6;margin-top:10px">Decrypting these needs a one-time Windows admin approval, handled by Adom Desktop core (issue #51). Discovery works today; one-click import lights up when that lands.</div>':'')+ +'</div>';+}+async function runImportScan(){const b=_q('#importScanBtn');if(b){b.disabled=true;b.textContent='Scanning…';}const j=await act({action:'import-scan'});_importScan=(j&&j.ok)?j:{profiles:[],accounts:[]};renderDlg();}+async function runImport(){+ const sel=((_importScan&&_importScan.profiles)||[]).filter(p=>_importSel[p.browser+'/'+p.profileDir]!==false);+ if(!sel.length){toast('Select at least one profile','error');return;}+ const r=await fetch('/dashboard/action',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'import-run',profiles:sel.map(p=>({browser:p.browser,profileDir:p.profileDir}))})});+ const j=await r.json().catch(()=>({}));const el=_q('#importStatus');if(el)el.textContent=j.message||j.error||'Requested.';+ toast(j.pending?'Import pending the Windows admin-approval helper (AD #51)':'Import requested','info');+} function renderDlg(){ const st=(SNAP&&SNAP.bridge&&SNAP.bridge.settings)||{}; _q('#dlgBody').innerHTML=SETTINGS_DEF.map(def=>{@@ -9352,7 +9389,7 @@ function renderDlg(){ +'<button class="btn sm" data-act="unflash-all" title="clear every taskbar flash">clear flash</button></div>':''; return '<div class="srow"><div class="stxt"><div class="slbl">'+esc(def.l)+(def.info?' <span class="ibadge" data-tip="'+esc(def.info)+'">i</span>':'')+'</div><div class="sdesc">'+esc(def.d)+'</div>'+exImg+testRow+'</div>' +'<div class="tgl'+(on?' is-on':'')+'" role="switch" tabindex="0" aria-checked="'+on+'" aria-label="'+esc(def.l)+'" data-tgl="'+def.k+'"></div></div>';- }).join('');+ }).join('')+importSectionHtml(); } async function setSetting(key,value){ const j=await act({action:'set-setting',key,value});@@ -9364,6 +9401,12 @@ document.addEventListener('click',ev=>{ const t=ev.target.closest('[data-tgl]'); if(t){setSetting(t.dataset.tgl,t.classList.contains('is-on')?'off':'on');return;} if(ev.target.closest('[data-testcap]')){act({action:'test-caption'});return;}+ if(ev.target.closest('#importScanBtn')){runImportScan();return;}+ if(ev.target.closest('#importRunBtn')){runImport();return;}+});+document.addEventListener('change',ev=>{+ const c=ev.target.closest('[data-imchk]');+ if(c){_importSel[c.dataset.imchk]=c.checked;} }); document.addEventListener('input',ev=>{ const r=ev.target.closest('[data-slider]');@@ -9512,6 +9555,23 @@ const server = http.createServer(async (req, res) => { pupCaption(`This is what an AI-foreground caption looks like. Reason: "you clicked Test in pup settings" (${(ms / 1000).toFixed(1)}s)`, ms, 'pup-fg-reason', ms).catch(() => {}); return done({ ok: true, ms }); }+ if (act === 'import-scan') {+ // Dashboard "Import logins" picker → self-call the read-only discovery verb.+ try {+ const r = await fetch(`http://127.0.0.1:${PORT}/command`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ command: 'browser_import_scan', args: {} }) });+ const j = await r.json().catch(() => ({}));+ return done({ ok: !!j.success, profiles: j.profiles || [], totalPasswords: j.totalPasswords || 0, accounts: j.accounts || [], pythonAvailable: !!j.pythonAvailable });+ } catch (e) { return done({ ok: false, error: e.message }); }+ }+ if (act === 'import-run') {+ // The elevated SYSTEM decrypt of ABE (v20) passwords is AD-core (adom/adom-desktop #51).+ // A user process (this bridge) CANNOT decrypt them, so never fake a success — report the+ // honest pending state. When the AD helper lands, this becomes: one UAC → decrypt the+ // selected profiles → merge identity-tagged rows into the adom-you vault.+ const sel = Array.isArray(a.profiles) ? a.profiles : [];+ console.log(`[import] run requested for ${sel.length} profile(s) — awaiting AD-core decrypt helper (#51)`);+ return done({ ok: true, pending: true, selected: sel.length, message: `Discovery is done. Decrypting ${sel.length} profile(s) needs a one-time Windows admin approval, handled by the Adom Desktop core helper being built now (issue #51). One-click import completes the moment that lands — nothing was decrypted or stored yet.` });+ } if (act === 'set-setting') { // v1.9.259: the dashboard settings dialog. Whitelisted keys only; values validated. const ALLOWED = {