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
Gates run beside other threads' windows (own profile, untouched); smoke expects no owner chip by default
3 files changed
+41−22
tools/ab-smoke.sh+2−1@@ -49,7 +49,8 @@ R=$($AB pup_eval '{"expr":"location.search"}'); chk "url carries view=public" "$ say annotate + chip R=$($AB pup_annotate '{"tool":"pen"}'); chk "annotate armed" "$(echo "$R" | j "d.get('ok')")" True sleep 2-R=$($AB pup_eval '{"expr":"JSON.stringify({ov: typeof window.__pupStartAnnotate, chip: !!document.querySelector(\"div[data-pup-owner]\")})"}'); chk "overlay + owner chip in DOM" "$(echo "$R" | j "d.get('result')")" '{"ov":"function","chip":true}'+# 2.0.713: the owner chip is OFF by default, so a page must carry NO chip unless a user turned it on+R=$($AB pup_eval '{"expr":"JSON.stringify({ov: typeof window.__pupStartAnnotate, chip: !!document.querySelector(\"div[data-pup-owner]\")})"}'); chk "overlay in DOM, no owner chip by default" "$(echo "$R" | j "d.get('result')")" '{"ov":"function","chip":false}' say screenshots R=$($AB pup_screenshot_element '{"selector":"h1"}'); chk "screenshot_element" "$(echo "$R" | j "bool(d.get('filePath')) and d.get('width',0)>0")" True
tools/foreground-proof.sh+11−7@@ -45,15 +45,19 @@ OTHERS=$(printf '%s' "$SESS" | python3 -c " import sys,json try: print(' '.join(s.get('sessionId')+'('+str(s.get('owner'))+')' for s in json.load(sys.stdin).get('sessions') or [] if s.get('owner')!='pup-foreground-proof')) except Exception: print('?unreadable')")-if [ -n "$OTHERS" ]; then echo "FOREGROUND PROOF: INVALID - other threads have pup windows on $BOX: $OTHERS. The gate restarts the browser and would close them; run it on a box with no other pup windows."; exit 2; fi+# 2.0.714: on a shared box run in the gate's OWN profile (fgproof): its own browser is the one forced cold, and other+# threads' windows are never touched. The judge is unchanged: ANY pup window on top fails.+PROF=""; KILLPAT="pup-profiles"; CLOSEALL='{"all":true,"takeover":true}'+if [ -n "$OTHERS" ]; then echo "SHARED MODE: other threads have pup windows on $BOX ($OTHERS); the gate uses its own profile and leaves them alone"; PROF=',"profile":"fgproof"'; KILLPAT='pup-profiles[\\/]fgproof'; CLOSEALL='{"all":true}'; fi for W in $(printf '%s' "$SESS" | python3 -c " import sys,json try: print(' '.join(s.get('sessionId') for s in json.load(sys.stdin).get('sessions') or [] if s.get('owner')=='pup-foreground-proof')) except Exception: pass"); do timeout 60 $AB pup_close_window "{\"window\":\"$W\",\"reason\":\"foreground proof: clear the gate's own leftover windows\"}" >/dev/null 2>&1; done cat > "$S/cold.ps1" <<'PS'-Get-CimInstance Win32_Process -Filter "Name='chrome.exe'" | Where-Object { $_.CommandLine -match 'pup-profiles' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }+Get-CimInstance Win32_Process -Filter "Name='chrome.exe'" | Where-Object { $_.CommandLine -match '__KILLPAT__' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue } Start-Sleep -Seconds 2; "cold" PS+KILLPAT="$KILLPAT" python3 -c 'import os,sys; p=sys.argv[1]; t=open(p).read(); open(p,"w").write(t.replace("__KILLPAT__", os.environ["KILLPAT"]))' "$S/cold.ps1" # byte-exact: sed and ${//} both eat the regex backslash ENC=$(iconv -f utf-8 -t utf-16le "$S/cold.ps1" | base64 -w0) timeout 120 $AB shell_execute "{\"command\":\"powershell -NoProfile -EncodedCommand $ENC\",\"timeoutMs\":60000,\"reason\":\"foreground proof: force a cold pup browser\"}" >/dev/null 2>&1 timeout 60 $AB desktop_bring_to_front "{\"hwnd\":$PIN,\"reason\":\"foreground proof: pin a non-pup window in front\"}" >/dev/null 2>&1; sleep 2@@ -68,11 +72,11 @@ import sys,json try: d=json.load(sys.stdin); print('ok' if d.get('ok') is True else 'FAIL '+str(d.get('errorCode') or d.get('error') or '?')[:90]) except Exception: print('FAIL unparsable')"); case "$ok" in ok) ;; *) FAILS=$((FAILS+1)); mark "$name FAILED: $ok";; esac; } sleep 1-step "cold open A" pup_open_window '{"window":"fgp-a","url":"https://example.com/"}'+step "cold open A" pup_open_window "{\"window\":\"fgp-a\",\"url\":\"https://example.com/\"$PROF}" step "navigate A" pup_navigate '{"window":"fgp-a","url":"https://example.org/"}' step "navigate A again" pup_navigate '{"window":"fgp-a","url":"https://example.com/"}'-step "warm open B" pup_open_window '{"window":"fgp-b","url":"https://example.org/"}'-step "warm open C" pup_open_window '{"window":"fgp-c","url":"https://example.com/"}'+step "warm open B" pup_open_window "{\"window\":\"fgp-b\",\"url\":\"https://example.org/\"$PROF}"+step "warm open C" pup_open_window "{\"window\":\"fgp-c\",\"url\":\"https://example.com/\"$PROF}" step "navigate C" pup_navigate '{"window":"fgp-c","url":"https://example.org/"}' mark "done"; sleep 3; kill $SP $PP 2>/dev/null; wait 2>/dev/null BAD=$(python3 - "$S/samples" "$S/puppids" <<'PYJ'@@ -95,6 +99,6 @@ except Exception: print(0)") echo; echo "== top of screen, start to finish =="; sort -m "$S/samples" "$S/marks" | uniq -f1 -c echo echo "steps failed: $FAILS | pup windows open at the end: $OPEN (want 3)"-if [ "$FAILS" -ne 0 ] || [ "$OPEN" -lt 3 ]; then echo "FOREGROUND PROOF: INVALID ($FAILS step(s) failed, $OPEN of 3 windows open): nothing to measure"; timeout 90 $AB pup_close '{"all":true,"takeover":true}' >/dev/null 2>&1; exit 2; fi-timeout 90 $AB pup_close '{"all":true,"takeover":true}' >/dev/null 2>&1+if [ "$FAILS" -ne 0 ] || [ "$OPEN" -lt 3 ]; then echo "FOREGROUND PROOF: INVALID ($FAILS step(s) failed, $OPEN of 3 windows open): nothing to measure"; timeout 90 $AB pup_close "$CLOSEALL" >/dev/null 2>&1; exit 2; fi+timeout 90 $AB pup_close "$CLOSEALL" >/dev/null 2>&1 if [ "$BAD" -eq 0 ]; then echo "FOREGROUND PROOF: PASS ($TOTAL samples, 3 windows opened and navigated, a pup window was never on top)"; exit 0; else echo "FOREGROUND PROOF: FAIL ($BAD of $TOTAL samples had a pup window on top)"; exit 1; fi
tools/jumplist-ralph.py+28−14@@ -31,9 +31,13 @@ def main(): # (pup_close everyone), which takes other threads' windows with it. A box where another thread has windows is # not a valid box: refuse (INVALID, exit 2) and name them, as tools/foreground-proof.sh does. others = [f"{s.get('sessionId')}({s.get('owner')})" for s in (ab(t, 'pup_status', {}).get('sessions') or []) if s.get('owner') not in (THREAD, 'user-taskbar-menu')]- if others:- print(f"JUMPLIST RALPH: INVALID - other threads have pup windows on {t}: {' '.join(others)}. This gate closes every pup window; run it on a box with no other pup windows.")- sys.exit(2)+ # 2.0.714 (John: "what if you use crr and arav-rog for your tests?"): on a box where other threads have windows,+ # run SHARED: the gate's windows live in their own profile (their own browser), closes touch only the gate's own+ # windows, and the one check that must close everyone's windows (the real Close ALL task) is skipped and said so.+ shared = bool(others)+ if shared: print(f"SHARED MODE: other threads have pup windows on {t} ({' '.join(others)}); the gate runs in its own profile and leaves them alone")+ prof = {'profile': 'jlralph'} if shared else {}+ close_mine = {'all': True} if shared else {'all': True, 'everyone': True} exe = ps(t, "Get-ChildItem (Join-Path $env:LOCALAPPDATA 'Adom Bridge\\bridges-cache\\puppeteer') -Filter *.exe | Select-Object -First 1 -ExpandProperty FullName", 'jump-list ralph: locate the pup exe') shim = ps(t, "Join-Path $env:LOCALAPPDATA 'Adom Bridge\\ab-taskrun.exe'", 'jump-list ralph: locate the taskrun shim') print(f'exe={exe}\nshim={shim}')@@ -45,8 +49,8 @@ def main(): def check(name, ok, detail=''): results.append((name, ok)); print(f' {"PASS" if ok else "FAIL"} {name} {detail}') - ab(t, 'pup_close', {'all': True, 'everyone': True}); time.sleep(1)- r = ab(t, 'pup_open_window', {'window': 'jl-ralph', 'url': WIKI, 'owner': THREAD}, timeout=150)+ ab(t, 'pup_close', close_mine); time.sleep(1)+ r = ab(t, 'pup_open_window', {'window': 'jl-ralph', 'url': WIKI, 'owner': THREAD, **prof}, timeout=150) sid = r.get('sessionId') or 'jl-ralph'; print(f'window {sid} hwnd={r.get("hwnd")}'); time.sleep(6) # identity + jump list committed # 1. Annotate this page@@ -98,8 +102,8 @@ def main(): emulated = [x.get('tabId') for x in rows if x.get('focusEmulated')] active = [x.get('tabId') for x in rows if x.get('active')] check('only the active tab is focus-emulated', len(rows) >= 2 and emulated == active, f'(tabs={len(rows)}, emulated={emulated}, active={active})')- ab(t, 'pup_close', {'all': True, 'everyone': True}); time.sleep(1)- r = ab(t, 'pup_open_window', {'window': 'jl-ralph', 'url': WIKI, 'owner': THREAD}, timeout=150); sid = r.get('sessionId') or 'jl-ralph'; time.sleep(6)+ ab(t, 'pup_close', close_mine); time.sleep(1)+ r = ab(t, 'pup_open_window', {'window': 'jl-ralph', 'url': WIKI, 'owner': THREAD, **prof}, timeout=150); sid = r.get('sessionId') or 'jl-ralph'; time.sleep(6) # 1b4. A press must never be left down (2.0.460, John: "i still can't scroll with my touchpad on ANY of your # pup windows... i also can't change tabs"). A release that failed mid-click left Chrome treating every later@@ -128,16 +132,21 @@ def main(): # across 8 processes?"). Set the grace to 1 min, close everything, and it must be gone within ~90 s. print('\n== An idle browser is released') ab(t, 'pup_configure', {'idleBrowserQuitMin': '1'})- ab(t, 'pup_close', {'all': True, 'everyone': True}); time.sleep(2)+ ab(t, 'pup_close', close_mine); time.sleep(2) gone = False for _ in range(10): time.sleep(15)+ if shared:+ # other threads keep the main browser busy: the gate's OWN browser (profile jlralph) must be the one that exits+ n = ps(t, "(Get-CimInstance Win32_Process -Filter \"Name='chrome.exe'\" | Where-Object { $_.CommandLine -match 'pup-profiles[\\\\/]jlralph' }).Count", 'jump-list ralph: is the gate browser gone')+ if n.strip() in ('', '0'): gone = True; break+ continue st = ab(t, 'pup_status', {}) m = st.get('memory') or {} if not m.get('browserMb'): gone = True; break check('the browser with no windows was closed', gone, '(pup_status no longer reports a browser for the profile)') ab(t, 'pup_configure', {'idleBrowserQuitMin': '10'})- r = ab(t, 'pup_open_window', {'window': 'jl-ralph', 'url': WIKI, 'owner': THREAD}, timeout=150); sid = r.get('sessionId') or 'jl-ralph'; time.sleep(6)+ r = ab(t, 'pup_open_window', {'window': 'jl-ralph', 'url': WIKI, 'owner': THREAD, **prof}, timeout=150); sid = r.get('sessionId') or 'jl-ralph'; time.sleep(6) # 1c. A tab the USER opens in a pup window (window.open from the page, outside pup) is adopted by that # window's session within a health tick (2.0.453).@@ -146,8 +155,8 @@ def main(): ab(t, 'pup_eval', {'window': sid, 'expr': "window.open('https://wiki.adom.inc/adom/pup-bridge/releases', '_blank'); true"}) time.sleep(3); after = ab(t, 'pup_list_tabs', {'window': sid}).get('tabs') or [] check('user-opened tab adopted into the window session', len(after) == before + 1 and any('releases' in (x.get('url') or '') for x in after), f'(tabs {before} -> {len(after)})')- ab(t, 'pup_close', {'all': True, 'everyone': True}); time.sleep(1)- r = ab(t, 'pup_open_window', {'window': 'jl-ralph', 'url': WIKI, 'owner': THREAD}, timeout=150); sid = r.get('sessionId') or 'jl-ralph'; time.sleep(6)+ ab(t, 'pup_close', close_mine); time.sleep(1)+ r = ab(t, 'pup_open_window', {'window': 'jl-ralph', 'url': WIKI, 'owner': THREAD, **prof}, timeout=150); sid = r.get('sessionId') or 'jl-ralph'; time.sleep(6) # 2. Switch to public view / logged-in view print('\n== Switch to public view'); out = fire('pup_wiki_set_view', {'sessionId': sid, 'view': 'public'}, 'jump-list ralph: public view task'); time.sleep(6)@@ -168,9 +177,14 @@ def main(): check('dashboard window exists', 'pup-dashboard' in sess, f'({out}; sessions={sess})') # 5. Close ALL Adom Pup windows- print('\n== Close ALL Adom Pup windows'); out = fire('pup_close', {'all': True, 'everyone': True}, 'jump-list ralph: close-all task'); time.sleep(4)- sess = [s.get('sessionId') for s in (ab(t, 'pup_list_windows', {}).get('sessions') or [])]- check('all windows closed', not sess, f'({out}; sessions={sess})')+ print('\n== Close ALL Adom Pup windows')+ if shared:+ print(' SKIP all windows closed: this task closes EVERY pup window, other threads included; it runs only on a box with no other windows')+ ab(t, 'pup_close', close_mine)+ else:+ out = fire('pup_close', {'all': True, 'everyone': True}, 'jump-list ralph: close-all task'); time.sleep(4)+ sess = [s.get('sessionId') for s in (ab(t, 'pup_list_windows', {}).get('sessions') or [])]+ check('all windows closed', not sess, f'({out}; sessions={sess})') fails = [n for n, ok in results if not ok] print(f'\nJUMPLIST RALPH: {"ALL PASS" if not fails else "FAIL " + ", ".join(fails)} ({len(results) - len(fails)}/{len(results)})')