app
Pup - Puppeteer Bridge
Public Made by Adomby adom
pup is the AI's own browser: a real, full Chrome on the user's desktop that the AI fully controls (a sandbox, not the user's signed-in browser). Rides Bridge; pup_* verbs open windows and tabs, navigate, screenshot, and eval JS.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
#!/bin/bash
# Ralph MIMIC test: reproduce John's REAL 3-thread workload (observed 2026-08-09) and the
# bridge-respawn recovery flow where the wonk actually lives.
#
# Mimics exactly what was observed live:
# - "kicad-bridge dev" -> explicit session mk-kicad-$r, wiki page + 2 issue tabs, foreground:true on OPEN
# - "fusion-bridge maintenance" -> explicit session mk-fusion-$r, 5 wiki tabs added sequentially, never foregrounded
# - "nb bridge build" -> explicit session mk-nb-$r, 6 tabs incl. query-param URL, raise AFTER open
# (multi-word --ai-thread names + explicit sessionIds — the combo the old ralph never used)
# Then the RECOVERY leg (the flow that produced "NOT resolved — 2 wiggle-matches" and the
# wrong-category stamp on John's real kicad-touched3): force-reinstall the bridge while the
# windows are OPEN, let it recover them, and assert the identity pipeline re-runs cleanly.
#
# NEVER touches John's real windows (kicad-touched3 / fusion-wiki-tabs / nb-show / pup-dashboard):
# only mk-* sessions are opened/closed, and closes are per-session, never global pup_close {}.
TGT=AdomLapper
ROUNDS=${1:-2}
LOG='C:\\Users\\john\\.adom\\bridge-logs\\puppeteer.log'
MANIFEST='https://wiki.adom.inc/api/v1/pages/pup-bridge/files/adom-bridge-puppeteer-manifest.json'
ab(){ adom-bridge-cli --target $TGT "$@" 2>&1; }
pull_log(){ ab pull_file "{\"filePaths\":[\"$LOG\"],\"saveTo\":\"/tmp/mimiclog\"}" --ai-thread "pup-bridge build" >/dev/null 2>&1
# anchor to the LAST boot marker — the log spans respawns, and head-of-file lines are a PRIOR boot
local raw=/tmp/mimiclog/puppeteer.log b
b=$(grep -n "Puppeteer Bridge running" $raw | tail -1 | cut -d: -f1); b=${b:-1}
tail -n +$b $raw > /tmp/mimiclog/current-boot.log; }
LF=/tmp/mimiclog/current-boot.log
fail=0; declare -A allhandles
# assert <sid> <phase> — full identity pipeline for one window in the CURRENT log
assert_win(){
local sid=$1 phase=$2 prob=""
local handle stamped overlay jl notres
handle=$(grep -E "\"$sid\" resolved OS handle [0-9]+" "$LF" 2>/dev/null | tail -1 | sed -E 's/.*handle ([0-9]+).*/\1/')
stamped=$(grep -cE "\"$sid\" stamped appId" "$LF" 2>/dev/null)
overlay=$(grep -cE "\"$sid\".*(PAINT|ENFORCED)" "$LF" 2>/dev/null)
jl=$(grep -E "\"$sid\" set [0-9]+ task" "$LF" 2>/dev/null | tail -1 | sed -E 's/.*set ([0-9]+) task.*/\1/')
notres=$(grep -cE "\"$sid\" NOT resolved" "$LF" 2>/dev/null)
[ -z "$handle" ] && prob="$prob NO-HANDLE"
[ "$notres" != "0" ] && prob="$prob NOT-RESOLVED-x$notres"
[ "$stamped" = "0" ] && prob="$prob NOT-STAMPED"
[ "$overlay" = "0" ] && prob="$prob NO-OVERLAY"
[ -z "$jl" ] && prob="$prob NO-JUMPLIST" || { [ "$jl" -lt 5 ] && prob="$prob JUMPLIST-$jl-TASKS"; }
if [ -n "$handle" ] && [ -n "${allhandles[$handle]}" ] && [ "${allhandles[$handle]}" != "$sid" ]; then prob="$prob COLLISION-with-${allhandles[$handle]}"; fi
[ -n "$handle" ] && allhandles[$handle]=$sid
if [ -n "$prob" ]; then echo " [$phase] $sid hwnd=$handle jl=$jl ->$prob"; fail=$((fail+1)); else echo " [$phase] $sid hwnd=$handle jl=$jl stamp=$stamped ovl=$overlay OK"; fi
}
for r in $(seq 1 $ROUNDS); do
echo "── round $r: concurrent 3-thread mimic ──"
# kicad: foreground on open, then 2 issue tabs (matches the observed flow incl. the granted reason)
( ab pup_open_window "{\"sessionId\":\"mk-kicad-$r\",\"url\":\"https://wiki.adom.inc/adom/kicad-bridge\",\"foreground\":true,\"foregroundReason\":\"ralph mimic of the kicad thread's granted open-foreground\"}" --ai-thread "kicad-bridge dev" >/dev/null 2>&1
ab pup_open_tab "{\"sessionId\":\"mk-kicad-$r\",\"url\":\"https://wiki.adom.inc/adom/hero-studio/issues/32\"}" --ai-thread "kicad-bridge dev" >/dev/null 2>&1
ab pup_open_tab "{\"sessionId\":\"mk-kicad-$r\",\"url\":\"https://wiki.adom.inc/adom/adom-bridge/issues/56\"}" --ai-thread "kicad-bridge dev" >/dev/null 2>&1 ) &
# fusion: background, 4 extra tabs sequentially
( ab pup_open_window "{\"sessionId\":\"mk-fusion-$r\",\"url\":\"https://wiki.adom.inc/adom/fusion-bridge\",\"foreground\":false}" --ai-thread "fusion-bridge maintenance" >/dev/null 2>&1
for u in pup-bridge adom-bridge hero-studio wiki; do
ab pup_open_tab "{\"sessionId\":\"mk-fusion-$r\",\"url\":\"https://wiki.adom.inc/adom/$u\"}" --ai-thread "fusion-bridge maintenance" >/dev/null 2>&1
done ) &
# nb: background open with query-param URL, 5 extra tabs, RAISE after
( ab pup_open_window "{\"sessionId\":\"mk-nb-$r\",\"url\":\"https://wiki.adom.inc/adom/nb-bridge?v=puptour\",\"foreground\":false}" --ai-thread "nb bridge build" >/dev/null 2>&1
for u in hero-studio pup-bridge kicad-bridge adom-bridge definitions; do
ab pup_open_tab "{\"sessionId\":\"mk-nb-$r\",\"url\":\"https://wiki.adom.inc/adom/$u\"}" --ai-thread "nb bridge build" >/dev/null 2>&1
done
ab pup_focus_window "{\"sessionId\":\"mk-nb-$r\",\"reason\":\"ralph mimic of the nb thread's post-open raise\"}" --ai-thread "nb bridge build" >/dev/null 2>&1 ) &
wait
sleep 14
pull_log
for sid in mk-kicad-$r mk-fusion-$r mk-nb-$r; do assert_win $sid "live"; done
# register the REAL windows' handles as claims too — theft from them must flag COLLISION
for sid in kicad-touched3 fusion-wiki-tabs nb-show; do
h=$(grep -E "\"$sid\".*(resolved OS handle|VALIDATED)" "$LF" 2>/dev/null | tail -1 | grep -oE '[0-9]+' | tail -1)
[ -n "$h" ] && [ -z "${allhandles[$h]}" ] && allhandles[$h]=$sid
done
echo "── round $r: RESPAWN + recovery leg (windows stay open through it) ──"
ab bridge_install "{\"manifestUrl\":\"$MANIFEST\",\"force\":true}" --ai-thread "pup-bridge build" >/dev/null 2>&1
sleep 45 # let the NEW process actually boot (old one keeps serving during adopt-before-reap)
# wake + warm the respawned bridge
ok=""
for i in 1 2 3 4 5 6; do
rr=$(ab pup_readiness '{}' --ai-thread "pup-bridge build" 2>&1 | python3 -c "import sys,json;print(json.load(sys.stdin).get('ready'))" 2>/dev/null)
[ "$rr" = "True" ] && ok=1 && break; sleep 5
done
[ -z "$ok" ] && { echo " [recover] BRIDGE-NOT-READY after respawn"; fail=$((fail+1)); }
sleep 20 # give recovery + the startup jumplist re-commit sweep time to run
pull_log
echo " recovery banner: $(grep -cE 'Recovered session' $LF) recovered / re-commit sweep: $(grep -c 'forcing a re-commit' $LF)"
# DO NOT reset the collision map: handles survive respawns (Chrome outlives pup), so a recovered
# window claiming a DIFFERENT session's known handle is THEFT and must flag COLLISION (the exact
# bug a map reset hid: mk-* windows silently took John's real windows' handles).
for sid in mk-kicad-$r mk-fusion-$r mk-nb-$r kicad-touched3 fusion-wiki-tabs nb-show; do assert_win $sid "recovered"; done
# close ONLY the mimic windows, AS THEIR OWNER THREADS (the ownership gate refuses third-party
# closes — a prior harness closed as "pup-bridge build" and every close silently no-oped)
ab pup_close_window "{\"sessionId\":\"mk-kicad-$r\"}" --ai-thread "kicad-bridge dev" >/dev/null 2>&1
ab pup_close_window "{\"sessionId\":\"mk-fusion-$r\"}" --ai-thread "fusion-bridge maintenance" >/dev/null 2>&1
ab pup_close_window "{\"sessionId\":\"mk-nb-$r\"}" --ai-thread "nb bridge build" >/dev/null 2>&1
sleep 3
echo "round $r done (running fails=$fail)"
done
echo "===================="
echo "MIMIC RALPH DONE: $ROUNDS rounds x 3 windows x (live+recovered) | FAILURES: $fail"
# v2.0.46 final assert: NO WINDOW LEAK — every pup OS window must have a session (ghost windows
# from partial closes were the last wonk class; desktop count and session count must match).
NW=$(ab desktop_enum_windows '{"className":"Chrome_WidgetWin_1"}' --ai-thread rjl 2>/dev/null | python3 -c "
import sys,json
d=json.load(sys.stdin); inner=json.loads(d.get('output') or '{}')
pids=set()
import urllib.request
# pup-owned = any pid that owns a window whose title ends in the pup profiles' pages — simplest robust check:
# count Chrome windows NOT belonging to the user's default Chrome by asking pup which pids it owns is
# overkill here; compare against the session count trendline instead.
print(len([w for w in (inner.get('windows') or []) if w.get('title','').endswith('Google Chrome') or w.get('title')=='Pup live windows - Google Chrome']))" 2>/dev/null)
NS=$(ab pup_list_windows '{}' --ai-thread rjl 2>/dev/null | python3 -c "import sys,json;print(len(json.load(sys.stdin).get('sessions') or []))" 2>/dev/null)
echo "leak check (informational): chrome-titled windows=$NW sessions=$NS"