From ad5af93f20a28b80061d2516a5be50498ff81e3a Mon Sep 17 00:00:00 2001 From: hellno Date: Fri, 3 Jul 2026 11:20:13 +0200 Subject: [PATCH] docs(dev): app-driving + window-scoped screenshot recipe (E0) Commit a reusable, documented way to drive the running GPUI wallet and capture per-window screenshots, so every v4 GUI issue can produce before/after evidence. - scripts/deckard-drive.sh: window finder (Swift CGWindowListCopyWindowInfo -> largest layer-0 "deckard" window), screencapture -l (occlusion-proof window capture), cliclick/osascript input, and an unlock helper. Self- diagnoses focus via NSRunningApplication.activate -> isActive. - docs/dev/driving-the-app.md: the full macOS recipe (just demo funded Sepolia fork, passphrase deckard-demo) + honest caveats -- synthetic input only lands when the app is the active/key app; the Cmd-Return confirm, the Cmd-K query, and Activity j/k/x/Esc are hand-rolled and don't fire synthetically; drive real broadcasts via the headless agent and verify logic with tests. Cross- links the Linux/CI recipe. - docs/screenshots/driving-the-app-unlock.png: recipe-produced capture of the demo Unlock screen (launch + Swift finder + window-scoped capture). Docs/scripts only -- no crate touched. Refs #179, #180. --- docs/dev/driving-the-app.md | 197 ++++++++++++++++ docs/screenshots/driving-the-app-unlock.png | Bin 0 -> 84974 bytes scripts/deckard-drive.sh | 242 ++++++++++++++++++++ 3 files changed, 439 insertions(+) create mode 100644 docs/dev/driving-the-app.md create mode 100644 docs/screenshots/driving-the-app-unlock.png create mode 100755 scripts/deckard-drive.sh diff --git a/docs/dev/driving-the-app.md b/docs/dev/driving-the-app.md new file mode 100644 index 0000000..19bedf5 --- /dev/null +++ b/docs/dev/driving-the-app.md @@ -0,0 +1,197 @@ +# Driving the app + capturing screenshots (macOS) + +Deckard is a native GPUI app dogfooded on macOS — there is no headless browser to point a +test runner at. When you touch a `crates/deckard-app` view you owe the PR a **before/after +screenshot** (`CLAUDE.md` → Visual verification; the v4 epic #179 DoD). This is the committed, +reusable recipe for driving the running app and capturing per-window screenshots, so every GUI +issue can produce that evidence. + +The helper is [`scripts/deckard-drive.sh`](../../scripts/deckard-drive.sh). For a headless +Linux / CI session (no display, no GPU) use the sibling recipe instead: +[`docs/dev/headless-gui-screenshots.md`](./headless-gui-screenshots.md). + +## Read the caveats first + +Synthetic input on this GPUI app is **partial**, and — this is the one that costs hours — +**capture works even when input doesn't.** `screencapture -l` reads the window's own bitmap +regardless of focus or z-order, so a clean screenshot does **not** prove your clicks/keys landed. +Always confirm state from the *next* screenshot, never from the fact that a command exited 0. + +- **Synthetic input only reaches the app while it is the ACTIVE (key) app.** Mouse events route + by screen location, but a click on an *inactive* app is swallowed as an activation click, and + keystrokes always go to whatever app is active. `deckard-drive.sh raise` calls + `NSRunningApplication.activate` and prints `isActive=` — **if it prints `isActive=false`, + stop: nothing you type or click will land.** On macOS 14+ an app cannot steal focus from another + active app, and a GPUI app launched in the **background** (e.g. `just demo` under an agent/CI + shell, as opposed to a Terminal you're sitting in front of) may refuse activation entirely — it + renders and captures fine but never becomes key. In that situation you must physically click the + app once (or launch it from a foreground Terminal), or drive the headless paths below and verify + logic with tests. See [Honest caveats](#honest-caveats-read-before-you-script-a-flow). +- **Unlock is a CLICK, never Return.** Once the app IS active, the passphrase field auto-focuses, + but a synthetic `Return` does not submit — GPUI's `InputState` eats it. Type the passphrase, + then click the button. +- **You can reliably capture SCREENS** (unlock, compose, review, activity) by clicking to + navigate and screenshotting — provided the app is active per the point above. +- **You cannot reliably fire the hand-rolled key handlers** — the `⌘↵` / click *confirm*, the + ⌘K query field, Activity `j`/`k`/`x`/`Esc`. Synthetic key events don't land the way the app's + `on_key_down` expects. Do **not** try to drive a real broadcast from the keyboard. +- **Registered-action shortcuts DO work** — `⌘,` (Settings), `⌘⇧D` (dev toggle) — because they + dispatch through GPUI's action system, not a per-view key listener. +- To drive a **real value move** end-to-end, use the headless agent (`just demo-deposit` + + `just demo-agent`), not synthetic clicks. Verify **logic** with `cargo test`, not screenshots. + +## One-time setup (macOS permissions) + +The controlling terminal app (Conductor, Terminal, iTerm, …) needs two grants. System Settings › +Privacy & Security › + +- **Accessibility** → enable your terminal app — required for `cliclick` clicks and `osascript` + keystrokes to reach the app. +- **Screen Recording** → enable the same app — required for `screencapture`. + +Confirm the tools are installed: + +```bash +scripts/deckard-drive.sh deps # swift, cliclick, screencapture, osascript +# cliclick missing? -> brew install cliclick (swift ships with the Xcode Command Line Tools) +``` + +## 1. Launch the app + +**Option A — the funded demo (preferred for evidence).** `just demo` boots a local anvil fork of +Sepolia (pinned block) plus the app + daemon, seals a throwaway vault for anvil account 0, and +lands straight on the **Unlock** screen. It needs an upstream Sepolia **archive** RPC to fork +from (this is anvil's `--fork-url`; no Deckard binary reads it). A free archive endpoint works: + +```bash +export RPC_URL_SEPOLIA=https://sepolia.drpc.org # or Alchemy/Infura Sepolia +just demo # unlock passphrase: deckard-demo +``` + +`just demo` runs in the foreground and tears the anvil fork down on exit, so start it in its own +terminal (or background it and kill it when done). The demo world is fixed: + +| | | +|---|---| +| config dir | `~/.deckard/demo` | +| socket | `~/.deckard/demo/signerd.sock` | +| chain | `11155111` (Sepolia fork on anvil `:8545`) | +| wallet | anvil account 0 — `0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266` | +| **passphrase** | **`deckard-demo`** | + +Then, from another terminal (the app must be **unlocked** first): + +```bash +just demo-deposit # send a real 0.02 ETH inbound transfer (a positive delta) +just demo-deposit 0.15 # over the per-tx cap → drives the human-approval beat +just demo-agent # run the headless watch-and-shield agent loop +just demo-fund # (optional) top the wallet up with 10 ETH +``` + +**Option B — `just run`** launches the everyday app against your real config (no fork). **Option +C — `just qa`** seals a throwaway anvil vault under `/tmp/deckard-qa` (chain `31337`, passphrase +`deckard-qa`) and boots straight to Unlock — the lightest way to reach an unlocked wallet when +you don't need the funded fork; start `anvil --chain-id 31337` first for live balances. + +## 2. Unlock and capture (the quick path) + +Once the app is on the Unlock screen: + +```bash +scripts/deckard-drive.sh unlock # types `deckard-demo`, CLICKS Unlock, shots +scripts/deckard-drive.sh shot home # -> .context/shots/home.png +``` + +`unlock` takes the passphrase as an optional arg (`unlock deckard-qa` for the QA vault). Screenshots +land in `.context/shots/` (the gitignored scratch dir) by default — override with +`DECKARD_SHOT_DIR`. Attach the labelled PNG to the PR. + +## 3. Navigate and capture other screens + +```bash +scripts/deckard-drive.sh win # " " of the Deckard window +scripts/deckard-drive.sh click 0.5 0.7 # click at window-relative FRACTIONs (0..1) +scripts/deckard-drive.sh clickpt 120 400 # ...or window-relative POINTs from top-left +scripts/deckard-drive.sh type "0.02" # type into the focused field +scripts/deckard-drive.sh key , cmd # ⌘, (Settings — a registered action, works) +scripts/deckard-drive.sh shot review # capture the current screen +``` + +Clicks use **window-relative** coordinates, so they survive the window moving between calls (the +finder re-reads the live bounds each time). Compute a fraction from a screenshot: the button at +pixel `(x, y)` in an `W×H` capture is fraction `(x/W, y/H)`. To place a button precisely, `shot` +first, read the fraction off the image, then `click`. + +## How it works (rebuild it without the script) + +Three macOS primitives, which is all the helper wraps: + +**Find the window** with a Swift `CGWindowListCopyWindowInfo` snippet — the largest on-screen +layer-0 window whose owner name contains `deckard`. It prints the window id + top-left-origin +bounds in logical points (the same space `cliclick` and `screencapture` use, so no conversion): + +```swift +import CoreGraphics; import Foundation +let list = CGWindowListCopyWindowInfo([.optionOnScreenOnly, .excludeDesktopElements], + kCGNullWindowID) as? [[String: Any]] ?? [] +for w in list where (w[kCGWindowOwnerName as String] as? String ?? "").lowercased().contains("deckard") { + guard (w[kCGWindowLayer as String] as? Int ?? -1) == 0 else { continue } // 0 == a real window + let b = w[kCGWindowBounds as String] as? [String: Any] ?? [:] + print(w[kCGWindowNumber as String] as? Int ?? -1, + Int(b["X"] as? Double ?? 0), Int(b["Y"] as? Double ?? 0), + Int(b["Width"] as? Double ?? 0), Int(b["Height"] as? Double ?? 0)) +} +``` + +**Capture that window** by id — this dodges occlusion. Region capture (`screencapture -R x,y,w,h`) +reads back whatever is *composited* at those screen coordinates, so Conductor/Zed/Claude sitting +on top give you the wrong app's pixels. `-l` grabs the Deckard window's own bitmap regardless +of z-order: + +```bash +screencapture -x -o -l out.png # -x no sound, -o no shadow +``` + +**Send input** with `cliclick` (clicks/typing at screen points) and `osascript` (keystrokes for +registered actions). Screen point for a window-relative fraction `(fx, fy)` is +`(win_x + fx·win_w, win_y + fy·win_h)`. + +## Honest caveats (read before you script a flow) + +Two things make synthetic input uneven here: the app must be the **active/key** app for *any* +input to land (macOS activation), and GPUI **hand-rolls per-view key handling** with focus quirks +(so even when active, some keys don't behave). What actually happens: + +| Interaction | Synthetic input? | Do this instead | +|---|---|---| +| **App is active/key** (prerequisite for ALL input) | ⚠️ only if `raise` reports `isActive=true`; a background/agent-launched app on macOS 14+ may never activate | run from a foreground Terminal, or physically click the app once; capture still works regardless | +| **Unlock submit** | ❌ `Return` doesn't submit (`InputState` eats it) | **Click** the Unlock button (`unlock` does this — once the app is active) | +| **Compose / review SCREENS** | ✅ reachable by clicking to navigate | click through, then `shot` | +| **`⌘↵` / click confirm** (arm-delay send) | ❌ doesn't reliably fire the confirm | never drive a real send from the keyboard | +| **⌘K palette query** | ❌ the query field is flaky under synthetic keys | screenshot the palette open; don't script typed search | +| **Activity `j`/`k`/`x`/`Esc`** | ❌ hand-rolled `on_key_down`, doesn't land | verify selection/stop **logic** with `cargo test` | +| **`⌘,` Settings, `⌘⇧D` dev toggle** | ✅ registered actions dispatch fine | `key , cmd` / `key d cmd shift` | +| **Real value move** (deposit → shield) | n/a — don't fake it | `just demo-deposit` + `just demo-agent` (headless agent) | + +The rule of thumb: **capture SCREENS via clicks; drive real BROADCASTS through the headless +agent; verify LOGIC via tests, not screenshots.** A screenshot proves a screen renders; it does +not prove the confirm/keyboard path works — that's what the workspace test suite is for. + +Other gotchas: + +- **`raise` before a click batch, and heed its `isActive`.** A stray `cargo run` / terminal / + chat app grabbing focus makes input vanish. The helper calls `raise` (→ + `NSRunningApplication.activate`) before every click/type; if input isn't landing, run `raise` + on its own and read the `isActive=` line — `false` means you're driving a window that can't take + focus, so fix that first (foreground Terminal / physical click) instead of retrying blindly. +- **Never `pkill -f 'target/debug/deckard'`.** The pattern matches your own shell's command line + and can kill the session. Kill the app by explicit PID, or `pkill -x deckard` (note: process + names truncate at 15 chars, so `deckard-signerd` won't match `-x` — kill it by PID). +- Clicks are in **logical points** (Retina-safe): `CGWindowBounds` and `cliclick` agree, so a + fraction of the window maps correctly on any display scale. + +## Linux / CI + +For a headless Linux or Claude-on-the-web session, the mechanics are different (virtual X display ++ software Vulkan, `xdotool` for input, `import -window` for capture). That reproducible recipe +lives in [`docs/dev/headless-gui-screenshots.md`](./headless-gui-screenshots.md). diff --git a/docs/screenshots/driving-the-app-unlock.png b/docs/screenshots/driving-the-app-unlock.png new file mode 100644 index 0000000000000000000000000000000000000000..55da7b236048631530305faac8590a708dcba678 GIT binary patch literal 84974 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 grabs THAT window's bitmap +# regardless of z-order, so Conductor/Zed/Claude sitting on top +# never occlude the shot (region capture reads back the wrong app). +# • input — `cliclick` for clicks/typing at window-relative coords; +# `osascript keystroke` for registered-action shortcuts (⌘, / ⌘⇧D). +# +# One-time grants (System Settings › Privacy & Security): +# • Accessibility → the controlling terminal app (e.g. Conductor / Terminal / iTerm) +# — required for cliclick + osascript synthetic input. +# • Screen Recording → the same app — required for screencapture. +# +# Full recipe, honest caveats, and the demo launch story: docs/dev/driving-the-app.md +# Linux / CI (headless Xvfb + software Vulkan) path: docs/dev/headless-gui-screenshots.md +# +# Usage: +# scripts/deckard-drive.sh [args] +# +# win print " " for the Deckard window +# raise bring the Deckard app to the front +# shot capture the window to $DECKARD_SHOT_DIR/.png +# click click at window-relative FRACTIONs (0..1), e.g. 0.5 0.7 +# clickpt click at window-relative POINTs from the top-left +# type "" type text into the focused field +# key [mods...] registered-action shortcut, mods ∈ {cmd shift opt ctrl} +# e.g. key , cmd (Settings) key d cmd shift (⌘⇧D) +# unlock [passphrase] type the passphrase + CLICK Unlock (default: deckard-demo), +# then screenshot to $DECKARD_SHOT_DIR/unlocked.png +# deps verify swift + cliclick + screencapture are present +# +# Env: +# DECKARD_WINDOW_OWNER owner-name substring to match (default: deckard) +# DECKARD_SHOT_DIR screenshot output dir (default: .context/shots) +# DECKARD_UNLOCK_FRAC "fx,fy" of the Unlock button (default: 0.5,0.65) +# +# IMPORTANT — synthetic input needs the app to be the ACTIVE (key) app. `raise` +# uses NSRunningApplication.activate, but on macOS 14+ an app cannot steal focus +# from another *active* app, and a GPUI app launched in the background (e.g. this +# repo's `just demo` under an agent/CI shell) may refuse activation entirely +# (`isActive` stays false; it exposes no AXWindow). Capture (`screencapture -l`) +# works regardless of focus; clicks/keys do NOT. See docs/dev/driving-the-app.md +# → "Honest caveats" for when this bites and what to do (physically click; or +# verify logic via `cargo test`, not screenshots). +# +set -euo pipefail + +OWNER="${DECKARD_WINDOW_OWNER:-deckard}" +SHOT_DIR="${DECKARD_SHOT_DIR:-.context/shots}" +UNLOCK_FRAC="${DECKARD_UNLOCK_FRAC:-0.5,0.65}" + +die() { printf 'deckard-drive: %s\n' "$*" >&2; exit 1; } + +# ── window finder ───────────────────────────────────────────────────────────── +# Print " " for the largest on-screen layer-0 window whose +# owner name contains $OWNER. Coordinates are top-left-origin logical points — +# the same space cliclick and screencapture use, so no conversion is needed. +find_window() { + swift - "$OWNER" <<'SWIFT' +import CoreGraphics +import Foundation + +let needle = (CommandLine.arguments.dropFirst().first ?? "deckard").lowercased() +guard let list = CGWindowListCopyWindowInfo( + [.optionOnScreenOnly, .excludeDesktopElements], kCGNullWindowID + ) as? [[String: Any]] else { exit(1) } + +var best: (id: Int, x: Int, y: Int, w: Int, h: Int, area: Double)? +for win in list { + let owner = (win[kCGWindowOwnerName as String] as? String ?? "").lowercased() + guard owner.contains(needle) else { continue } + // Layer 0 == a normal app window; title-bar/shadow helpers live on other layers. + guard (win[kCGWindowLayer as String] as? Int ?? -1) == 0 else { continue } + let b = win[kCGWindowBounds as String] as? [String: Any] ?? [:] + let x = Int(b["X"] as? Double ?? 0), y = Int(b["Y"] as? Double ?? 0) + let w = Int(b["Width"] as? Double ?? 0), h = Int(b["Height"] as? Double ?? 0) + let area = Double(w * h) + let id = win[kCGWindowNumber as String] as? Int ?? -1 + if best == nil || area > best!.area { best = (id, x, y, w, h, area) } +} +guard let b = best else { + FileHandle.standardError.write( + "no on-screen layer-0 window owned by '\(needle)' — is the app running?\n".data(using: .utf8)!) + exit(2) +} +print("\(b.id) \(b.x) \(b.y) \(b.w) \(b.h)") +SWIFT +} + +# Raise the app so synthetic input reaches it. Uses the modern activation API +# (NSRunningApplication.activate) — the right primitive when the app CAN be +# activated. Best-effort: on macOS 14+ this cannot steal focus from another +# active app, and a background-launched GPUI app may not activate at all (see the +# header note + docs/dev/driving-the-app.md). Prints "isActive=" so a caller +# can tell whether input will actually land. +raise_app() { + local pid + pid="$(pgrep -x "$OWNER" | head -1)" + [ -n "$pid" ] || { echo "isActive=false (no '$OWNER' process)"; return 0; } + swift - "$pid" <<'SWIFT' 2>/dev/null || true +import AppKit +let pid = Int32(CommandLine.arguments.dropFirst().first ?? "0") ?? 0 +guard let app = NSRunningApplication(processIdentifier: pid) else { print("isActive=false"); exit(0) } +app.activate() +usleep(400_000) +print("isActive=\(app.isActive)") +SWIFT +} + +# ── commands ────────────────────────────────────────────────────────────────── +cmd_win() { find_window; } + +cmd_raise() { raise_app; echo "raised $OWNER"; } + +cmd_shot() { + local name="${1:-shot}" + mkdir -p "$SHOT_DIR" + read -r id _ _ _ _ < <(find_window) + local out="$SHOT_DIR/${name}.png" + screencapture -x -o -l"$id" "$out" + echo "$out" +} + +# Click at window-relative fractions (0..1 of width/height). +cmd_click() { + [ $# -eq 2 ] || die "click needs (fractions 0..1)" + raise_app + read -r _ x y w h < <(find_window) + local sx sy + sx=$(awk -v x="$x" -v w="$w" -v f="$1" 'BEGIN{printf "%d", x + f*w}') + sy=$(awk -v y="$y" -v h="$h" -v f="$2" 'BEGIN{printf "%d", y + f*h}') + cliclick "c:${sx},${sy}" + echo "clicked frac($1,$2) -> screen($sx,$sy)" +} + +# Click at window-relative points (from the top-left corner of the window). +cmd_clickpt() { + [ $# -eq 2 ] || die "clickpt needs (points from window top-left)" + raise_app + read -r _ x y _ _ < <(find_window) + cliclick "c:$((x + $1)),$((y + $2))" + echo "clicked pt($1,$2) -> screen($((x + $1)),$((y + $2)))" +} + +cmd_type() { + [ $# -ge 1 ] || die "type needs \"\"" + raise_app + osascript -e "tell application \"System Events\" to keystroke \"$1\"" + echo "typed: $1" +} + +# Registered-action shortcut, e.g. `key , cmd` or `key d cmd shift`. +cmd_key() { + [ $# -ge 1 ] || die "key needs [mods...]" + local char="$1"; shift + raise_app + if [ $# -eq 0 ]; then + osascript -e "tell application \"System Events\" to keystroke \"$char\"" + else + local clause="" m + for m in "$@"; do + case "$m" in + cmd) clause+="command down, " ;; + shift) clause+="shift down, " ;; + opt) clause+="option down, " ;; + ctrl) clause+="control down, " ;; + *) die "unknown modifier '$m' (use cmd|shift|opt|ctrl)" ;; + esac + done + clause="${clause%, }" + osascript -e "tell application \"System Events\" to keystroke \"$char\" using {$clause}" + fi + echo "key: $char ${*:-}" +} + +# Unlock the demo/QA vault: the passphrase field auto-focuses, so type it and then +# CLICK the Unlock button — a synthetic Return does NOT submit (GPUI InputState eats +# it). Argon2 + the daemon round-trip take ~1s (PRODUCTION KDF) before the app lands. +cmd_unlock() { + local pass="${1:-deckard-demo}" + mkdir -p "$SHOT_DIR" + local active; active="$(raise_app)"; echo "$active" + case "$active" in + *isActive=false*) + echo "deckard-drive: WARNING — Deckard is not the active app, so the passphrase and" >&2 + echo " Unlock click will NOT land (you'll get an empty field). Give the window focus" >&2 + echo " first — run it from a foreground Terminal, or physically click the app once —" >&2 + echo " then re-run. See docs/dev/driving-the-app.md → Honest caveats." >&2 ;; + esac + osascript -e "tell application \"System Events\" to keystroke \"$pass\"" >/dev/null + local fx="${UNLOCK_FRAC%,*}" fy="${UNLOCK_FRAC#*,}" + read -r _ x y w h < <(find_window) + local sx sy + sx=$(awk -v x="$x" -v w="$w" -v f="$fx" 'BEGIN{printf "%d", x + f*w}') + sy=$(awk -v y="$y" -v h="$h" -v f="$fy" 'BEGIN{printf "%d", y + f*h}') + cliclick "c:${sx},${sy}" + # Give the KDF + daemon unlock a moment before capturing the unlocked screen. + osascript -e 'delay 2' >/dev/null 2>&1 || true + local out="$SHOT_DIR/unlocked.png" + read -r id _ _ _ _ < <(find_window) + screencapture -x -o -l"$id" "$out" + echo "typed passphrase, clicked Unlock at frac($fx,$fy) -> screen($sx,$sy); shot: $out" +} + +cmd_deps() { + local ok=1 + for bin in swift cliclick screencapture osascript; do + if command -v "$bin" >/dev/null 2>&1; then + echo "ok $bin -> $(command -v "$bin")" + else + echo "MISS $bin"; ok=0 + fi + done + [ $ok -eq 1 ] || die "install missing tools (cliclick: brew install cliclick; swift ships with Xcode CLT)" +} + +main() { + [ $# -ge 1 ] || { grep -E '^#( |$)' "$0" | sed -E 's/^# ?//'; exit 0; } + local cmd="$1"; shift + case "$cmd" in + win|find) cmd_win "$@" ;; + raise) cmd_raise "$@" ;; + shot) cmd_shot "$@" ;; + click) cmd_click "$@" ;; + clickpt) cmd_clickpt "$@" ;; + type) cmd_type "$@" ;; + key) cmd_key "$@" ;; + unlock) cmd_unlock "$@" ;; + deps) cmd_deps "$@" ;; + -h|--help|help) grep -E '^#( |$)' "$0" | sed -E 's/^# ?//' ;; + *) die "unknown command '$cmd' (try: help)" ;; + esac +} + +main "$@"