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
mode-ralph: taskbar-state switching ralph with UIA glass verification + rapid-click race rounds; selftest skill: run it after any identity change
2 files changed
+109
dev-skills/pup-selftest/SKILL.md+4@@ -26,6 +26,10 @@ roundtrip · T9 **no test windows left open** (John's hard rule) + cleanup. Also run before/after risky work: `tools/churn-ralph.sh` (the #46 destructive-kill invariant) and `tests/check_dashboard_script.js` alone for any dashboard edit.+After ANY identity/stamp/strip/mode change: `tools/mode-ralph.sh` — walks all three taskbar+modes plus RAPID double-click rounds (the in-flight-stamp race that shipped branded buttons in+plain mode, caught by John 2026-08-16), UIA-verifying the GLASS each round. Bookkeeping said the+strip worked while nine buttons stayed branded; only button names + pixels count. ## The pixel gates (manual, non-negotiable before claiming anything to John)
tools/mode-ralph.shadded+105@@ -0,0 +1,105 @@+#!/usr/bin/env bash+# mode-ralph.sh — the taskbar-state switching ralph (John, 2026-08-16: "loop forever until you have+# it fixed. figure out how to take screenshots to fix yourself and analyze").+#+# Drives taskbarMode/overlayBadges through the SAME /dashboard/action endpoint the Settings dialog+# uses (via pup_eval on the cn-dash window), waits for the apply-progress tracker to report done,+# then verifies the GLASS with UIA button names and captures the tray. Includes RAPID double-click+# rounds that reproduce the in-flight-stamp race (the 2.0.216 generation-token fix's regression+# test). Exit code = number of failed rounds.+#+# Usage: tools/mode-ralph.sh [TARGET] [FINAL_MODE] [FINAL_OV]+set -u+TARGET="${1:-AdomLapper}"+FINAL_MODE="${2:-plain}"+FINAL_OV="${3:-on}"+export ADOM_AI_THREAD="${ADOM_AI_THREAD:-pup bridge maintenance}"+export ADOM_CONTAINER_NAME="${ADOM_CONTAINER_NAME:-galliaApril}"+CLI="adom-bridge --target $TARGET"+PASS=0; FAIL=0+SHOTDIR="${SHOTDIR:-/tmp/mode-ralph-shots}"; mkdir -p "$SHOTDIR"++evaljs() { # evaljs <expression> -> prints result+ timeout 60 $CLI pup_eval "{\"sessionId\":\"cn-dash\",\"expression\":$(python3 -c 'import json,sys;print(json.dumps(sys.argv[1]))' "$1")}" 2>&1 \+ | python3 -c "import sys,json;raw=sys.stdin.read();i=raw.find('{');print(json.loads(raw[i:]).get('result',''))" 2>/dev/null+}++switch_state() { # switch_state <mode> <ov on|off>+ evaljs "(fetch('/dashboard/action',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'set-setting',key:'taskbarMode',value:'$1'})}).then(()=>fetch('/dashboard/action',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'set-setting',key:'overlayBadges',value:'$2'})})), 'sent')" >/dev/null+}++wait_done() { # poll apply-progress until done (max ~40s)+ for i in $(seq 1 40); do+ D=$(evaljs "fetch('/dashboard/apply-progress').then(r=>r.json()).then(j=>String(j&&j.apply&&j.apply.done))")+ [ "$D" = "true" ] && return 0+ sleep 1+ done+ return 1+}++uia_buttons() {+ local PS='Add-Type -AssemblyName UIAutomationClient; $tray=[System.Windows.Automation.AutomationElement]::RootElement.FindFirst([System.Windows.Automation.TreeScope]::Children,(New-Object System.Windows.Automation.PropertyCondition([System.Windows.Automation.AutomationElement]::ClassNameProperty,"Shell_TrayWnd"))); $btns=$tray.FindAll([System.Windows.Automation.TreeScope]::Descendants,(New-Object System.Windows.Automation.PropertyCondition([System.Windows.Automation.AutomationElement]::ControlTypeProperty,[System.Windows.Automation.ControlType]::Button))); foreach($b in $btns){Write-Output $b.Current.Name}'+ local B64; B64=$(python3 -c "import base64,sys;print(base64.b64encode(sys.stdin.read().encode('utf-16-le')).decode())" <<< "$PS")+ timeout 90 $CLI shell_execute "{\"command\":\"powershell -NoProfile -EncodedCommand $B64\",\"reason\":\"mode-ralph: UIA taskbar button names\"}" 2>&1 \+ | python3 -c "import sys,json;raw=sys.stdin.read();i=raw.find('{');d=json.loads(raw[i:]) if i>=0 else {};print(d.get('stdout') or '')"+}++shot_tray() { # shot_tray <label>+ local HW; HW=$(cat /tmp/tray_hwnd 2>/dev/null || echo 65952)+ timeout 60 $CLI desktop_screenshot_window "{\"hwnd\":$HW}" >/dev/null 2>&1+ local P; P=$(ls -t ~/project/screenshots/adom-bridge/window/*-${HW}*.full.png 2>/dev/null | head -1)+ [ -n "$P" ] && cp "$P" "$SHOTDIR/$1.png"+}++verify_state() { # verify_state <mode> <label>+ local mode="$1" label="$2"+ local B; B=$(uia_buttons)+ local N_PUP N_THREAD N_CFT+ N_PUP=$(echo "$B" | grep -c "Adom Pup" || true)+ N_THREAD=$(echo "$B" | grep -Ec "^(ti-crawl|mouser-run|digikey-run|wiki-in|wiki-out|dash-app|reclaimed|pup bridge maintenance|pup-dashboard)" || true)+ N_CFT=$(echo "$B" | grep -c "Chrome for Testing" || true)+ shot_tray "$label"+ case "$mode" in+ plain)+ if [ "$N_PUP" -eq 0 ] && [ "$N_THREAD" -eq 0 ]; then PASS=$((PASS+1)); echo " PASS [$label] plain: 0 branded buttons (CfT groups: $N_CFT)"; return 0+ else FAIL=$((FAIL+1)); echo " FAIL [$label] plain: $N_PUP 'Adom Pup' + $N_THREAD thread buttons still on the bar"; echo "$B" | grep -E "Adom Pup|^(ti-crawl|mouser-run|digikey-run|wiki-in|wiki-out|dash-app|reclaimed|pup bridge)" | sed 's/^/ /'; return 1; fi ;;+ aumid)+ if [ "$N_PUP" -ge 5 ]; then PASS=$((PASS+1)); echo " PASS [$label] aumid: $N_PUP 'Adom Pup' per-window buttons"; return 0+ else FAIL=$((FAIL+1)); echo " FAIL [$label] aumid: only $N_PUP 'Adom Pup' buttons"; return 1; fi ;;+ tiles)+ if [ "$N_THREAD" -ge 4 ]; then PASS=$((PASS+1)); echo " PASS [$label] tiles: $N_THREAD thread-name buttons"; return 0+ else FAIL=$((FAIL+1)); echo " FAIL [$label] tiles: only $N_THREAD thread-name buttons"; return 1; fi ;;+ esac+}++round() { # round <mode> <ov> <label> — clean switch, wait, verify+ echo "== ROUND $3: switch to $1 + overlay $2 =="+ switch_state "$1" "$2"+ wait_done || echo " (apply-progress never reported done — verifying anyway)"+ sleep 3+ verify_state "$1" "$3"+}++rapid_round() { # rapid_round <modeA> <modeB> <label> — the race: click A, then B ~1.2s later; B must win+ echo "== RAPID $3: $1 then $2 after 1.2s (the in-flight-stamp race) =="+ switch_state "$1" "on"+ sleep 1.2+ switch_state "$2" "on"+ wait_done || echo " (apply-progress never reported done — verifying anyway)"+ sleep 5+ verify_state "$2" "$3"+}++round tiles on r1-tiles+round aumid on r2-aumid+round plain on r3-plain+rapid_round aumid plain r4-rapid-aumid-then-plain+round tiles on r5-tiles+rapid_round tiles plain r6-rapid-tiles-then-plain+round aumid on r7-aumid+round "$FINAL_MODE" "$FINAL_OV" r8-final-$FINAL_MODE++echo+echo "== MODE-RALPH RESULT: $PASS passed, $FAIL failed (shots in $SHOTDIR) =="+[ "$FAIL" -eq 0 ] && echo "GREEN" || echo "RED"+exit $FAIL