tools/harness.sh resume seeds IndexedDB with a station and one rendered track, resumes it with no user gesture and expects the TAP TO PLAY wait. IndexedDB needs http, so the page is served from a temp folder; headless Chrome's virtual time doesn't wait for IndexedDB, so this mode is driven in real time over the DevTools protocol (tools/harness-cdp.py, stdlib only). The loop harness now prints state.phase too. ARCHITECTURE.md describes the machine as implemented; HANDOFF.md lists what was found and left alone; STORAGE.md gains db.get and the tapes store (the code already had both); README points at the new files. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K6897PWcUEwHiqZMcVnNF6
64 lines
3.1 KiB
Bash
64 lines
3.1 KiB
Bash
#!/bin/sh
|
|
# tools/harness.sh: the playback regression run. Appends a harness fragment's script to index.html, runs it in headless
|
|
# Chrome, prints one state line per step. Needs Chrome/Chromium and python3.
|
|
#
|
|
# sh tools/harness.sh # tools/harness.html: the station loop with autoplay allowed, from file://
|
|
# sh tools/harness.sh resume # tools/harness-resume.html: resume a stored station with autoplay BLOCKED, served
|
|
# # over http (IndexedDB needs it) and driven in real time over the DevTools protocol
|
|
# # (tools/harness-cdp.py); expects the TAP TO PLAY wait
|
|
#
|
|
# CHROME=/path/to/chrome and CHROME_FLAGS="--no-sandbox --disable-dev-shm-usage" when it isn't found or runs as root.
|
|
set -eu
|
|
cd "$(dirname "$0")/.."
|
|
MODE=${1:-loop}
|
|
case "$MODE" in
|
|
loop) FRAG=tools/harness.html; AUTOPLAY=--autoplay-policy=no-user-gesture-required ;;
|
|
resume) FRAG=tools/harness-resume.html; AUTOPLAY= ;;
|
|
*) echo "usage: sh tools/harness.sh [resume]" >&2; exit 2 ;;
|
|
esac
|
|
CHROME=${CHROME:-}
|
|
for c in "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" "$(command -v chromium || true)" "$(command -v google-chrome || true)"; do
|
|
if [ -z "$CHROME" ] && [ -n "$c" ] && [ -x "$c" ]; then CHROME=$c; fi
|
|
done
|
|
[ -n "$CHROME" ] || { echo "no Chrome found; set CHROME" >&2; exit 1; }
|
|
out=$(mktemp -d)
|
|
prof=$(mktemp -d)
|
|
python3 - "$out" "$FRAG" <<'EOF'
|
|
import sys, pathlib
|
|
out = pathlib.Path(sys.argv[1])
|
|
page = pathlib.Path("index.html").read_text()
|
|
h = pathlib.Path(sys.argv[2]).read_text()
|
|
script = h[h.index("<!-- harness -->"):]
|
|
(out / "run.html").write_text(page.replace("</body>", script + "</body>"))
|
|
EOF
|
|
cp brain.js "$out/brain.js"
|
|
if [ "$MODE" = resume ]; then
|
|
# a fresh profile and a port picked by the OS, so no run inherits another's IndexedDB
|
|
PORT=$(python3 -c 'import socket; s=socket.socket(); s.bind(("127.0.0.1",0)); print(s.getsockname()[1])')
|
|
python3 -m http.server "$PORT" --bind 127.0.0.1 --directory "$out" >/dev/null 2>&1 </dev/null &
|
|
SRV=$!
|
|
trap 'kill $SRV 2>/dev/null || true; rm -rf "$out" "$prof"' EXIT INT TERM
|
|
n=0
|
|
until curl -fs -o /dev/null --max-time 2 "http://127.0.0.1:$PORT/run.html"; do
|
|
n=$((n + 1)); [ "$n" -lt 40 ] || { echo "the local server on port $PORT never answered" >&2; exit 1; }; sleep 0.5
|
|
done
|
|
URL="http://127.0.0.1:$PORT/run.html"
|
|
else
|
|
trap 'rm -rf "$out" "$prof"' EXIT INT TERM
|
|
URL="file://$out/run.html"
|
|
fi
|
|
if [ "$MODE" = resume ]; then
|
|
# real time, over the DevTools protocol: --dump-dom's virtual time doesn't wait for IndexedDB (see harness-cdp.py)
|
|
# shellcheck disable=SC2086
|
|
python3 tools/harness-cdp.py "$CHROME" "$URL" 30 ${CHROME_FLAGS:-}
|
|
else
|
|
# shellcheck disable=SC2086
|
|
"$CHROME" --headless=new --disable-gpu --user-data-dir="$prof" $AUTOPLAY --virtual-time-budget=25000 ${CHROME_FLAGS:-} --dump-dom "$URL" 2>/dev/null > "$out/dom.html" || true
|
|
python3 - "$out/dom.html" <<'EOF'
|
|
import sys, re, html
|
|
s = open(sys.argv[1]).read()
|
|
m = re.search(r'<pre id="diag">(.*?)</pre>', s, re.S)
|
|
print(html.unescape(m.group(1)) if m else "no diag: the harness did not run")
|
|
EOF
|
|
fi
|