@petukhovart/agent-view 0.13.1 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +21 -21
  3. package/LICENSE +21 -21
  4. package/README.md +82 -3
  5. package/dist/cdp/transport.d.ts.map +1 -1
  6. package/dist/cdp/transport.js +154 -15
  7. package/dist/cdp/transport.js.map +1 -1
  8. package/dist/cdp/types.d.ts +56 -0
  9. package/dist/cdp/types.d.ts.map +1 -1
  10. package/dist/cdp/types.js.map +1 -1
  11. package/dist/cli/commands/click.d.ts +1 -0
  12. package/dist/cli/commands/click.d.ts.map +1 -1
  13. package/dist/cli/commands/click.js +2 -0
  14. package/dist/cli/commands/click.js.map +1 -1
  15. package/dist/cli/commands/coverage.d.ts +14 -0
  16. package/dist/cli/commands/coverage.d.ts.map +1 -0
  17. package/dist/cli/commands/coverage.js +34 -0
  18. package/dist/cli/commands/coverage.js.map +1 -0
  19. package/dist/cli/commands/heap.d.ts +14 -0
  20. package/dist/cli/commands/heap.d.ts.map +1 -0
  21. package/dist/cli/commands/heap.js +25 -0
  22. package/dist/cli/commands/heap.js.map +1 -0
  23. package/dist/cli/commands/listeners.d.ts +11 -0
  24. package/dist/cli/commands/listeners.d.ts.map +1 -0
  25. package/dist/cli/commands/listeners.js +34 -0
  26. package/dist/cli/commands/listeners.js.map +1 -0
  27. package/dist/cli/index.js +92 -0
  28. package/dist/cli/index.js.map +1 -1
  29. package/dist/inspectors/coverage/index.d.ts +17 -0
  30. package/dist/inspectors/coverage/index.d.ts.map +1 -0
  31. package/dist/inspectors/coverage/index.js +62 -0
  32. package/dist/inspectors/coverage/index.js.map +1 -0
  33. package/dist/inspectors/format.d.ts +6 -0
  34. package/dist/inspectors/format.d.ts.map +1 -0
  35. package/dist/inspectors/format.js +17 -0
  36. package/dist/inspectors/format.js.map +1 -0
  37. package/dist/inspectors/heap/index.d.ts +65 -0
  38. package/dist/inspectors/heap/index.d.ts.map +1 -0
  39. package/dist/inspectors/heap/index.js +269 -0
  40. package/dist/inspectors/heap/index.js.map +1 -0
  41. package/dist/inspectors/listeners/index.d.ts +4 -0
  42. package/dist/inspectors/listeners/index.d.ts.map +1 -0
  43. package/dist/inspectors/listeners/index.js +30 -0
  44. package/dist/inspectors/listeners/index.js.map +1 -0
  45. package/dist/server/server.d.ts +21 -0
  46. package/dist/server/server.d.ts.map +1 -1
  47. package/dist/server/server.js +150 -9
  48. package/dist/server/server.js.map +1 -1
  49. package/package.json +2 -1
  50. package/skills/verify/SKILL.md +163 -427
  51. package/skills/verify/references/commands.md +384 -0
  52. package/skills/verify/references/design-conformance.md +23 -0
  53. package/skills/verify/references/memory-leaks.md +94 -0
  54. package/dist/cdp/console-stream.d.ts +0 -35
  55. package/dist/cdp/console-stream.d.ts.map +0 -1
  56. package/dist/cdp/console-stream.js +0 -103
  57. package/dist/cdp/console-stream.js.map +0 -1
  58. package/dist/inspectors/dom.d.ts +0 -17
  59. package/dist/inspectors/dom.d.ts.map +0 -1
  60. package/dist/inspectors/dom.js +0 -131
  61. package/dist/inspectors/dom.js.map +0 -1
  62. package/dist/inspectors/scene/pixi.d.ts +0 -3
  63. package/dist/inspectors/scene/pixi.d.ts.map +0 -1
  64. package/dist/inspectors/scene/pixi.js +0 -52
  65. package/dist/inspectors/scene/pixi.js.map +0 -1
@@ -0,0 +1,384 @@
1
+ # agent-view command reference
2
+
3
+ Every command accepts `--window <id|name>`. Output is plain text, except `discover` (JSON) and
4
+ `screenshot` (a file path). Refs (`[ref=N]`) and req handles (`[req=N]`) are reallocated on every
5
+ listing call — always expand from the most recent one.
6
+
7
+ ## Contents
8
+
9
+ - [Discovery & launch](#discovery--launch) — `launch`, `discover`, `stop`
10
+ - [DOM inspection](#dom-inspection) — `dom`
11
+ - [Interaction](#interaction) — `click`, `fill`, `drag`
12
+ - [Modals & file pickers](#modals--file-pickers-dialog-upload) — `dialog`, `upload`
13
+ - [Waiting](#waiting-wait) — `wait`
14
+ - [Screenshots](#screenshots) — `screenshot`
15
+ - [Runtime state](#runtime-state-eval) — `eval`
16
+ - [Reactive state](#reactive-state-watch) — `watch`
17
+ - [Console](#console-console) — `console`
18
+ - [Log feed](#log-feed-logs) — `logs`
19
+ - [Network](#network-network) — `network`
20
+ - [Reachability](#reachability-coverage-listeners) — `coverage`, `listeners`
21
+ - [Memory](#memory-heap) — `heap`
22
+ - [Targets](#targets-targets) — `targets`
23
+ - [Scene / canvas / WebGL](#scene--canvas--webgl-only-when-webgl-is-configured-in-agent-viewconfigjson) — `scene`, `snap`
24
+
25
+ ### Discovery & Launch
26
+ ```bash
27
+ agent-view launch # Start app from config, wait for CDP readiness (all runtimes incl. Tauri)
28
+ agent-view discover # List windows (JSON) — get window IDs
29
+ agent-view stop # Stop the lazy server
30
+ ```
31
+
32
+ **Port conflict**: if the configured port is held by a non-CDP process (e.g. a stray webpack-dev on the same port), `agent-view launch` exits non-zero with `code: PORT_CONFLICT` and reports the owning PID/process name.
33
+
34
+ **Tauri**: launch works the same as Electron, but the wait timeout is 10 min (cargo builds are slow). A port conflict on the Tauri devUrl port is almost always a parallel browser-dev.
35
+
36
+ ### DOM Inspection
37
+ ```bash
38
+ agent-view dom # DOM accessibility tree (default window)
39
+ agent-view dom --window <id|name> # Specific window
40
+ agent-view dom --filter "button" # Filter by text/role
41
+ agent-view dom --depth 3 # Limit tree depth
42
+ agent-view dom --compact # Merge single-child chains onto one line (~40-60% fewer tokens)
43
+ agent-view dom --count # Count of all visible nodes (single integer line)
44
+ agent-view dom --filter "row" --count # Count matching nodes — e.g. "does this table have 5 rows?"
45
+ agent-view dom --max-lines 200 # Hard line budget; refs for truncated nodes still stored
46
+ agent-view dom --diff # Lines changed since last dom call (+ added / - removed)
47
+ ```
48
+
49
+ `--count` skips tree output and ref mutations — cheapest way to assert "element exists N times" without loading the full tree into context.
50
+
51
+ ### Interaction
52
+ ```bash
53
+ agent-view click <ref> # Click element by ref from dom output
54
+ agent-view click --filter "Save" # Find element by text and click
55
+ agent-view click --pos 100,200 # Click by coordinates — CANVAS ONLY, see below
56
+ agent-view click <ref> --double # Double-click (fires dblclick handlers); works with --filter / --pos too
57
+ agent-view click <ref> --right # Right-click (fires contextmenu); works with --filter / --pos too
58
+ agent-view fill <ref> "text" # Type into input field
59
+ agent-view drag --from <ref> --to <ref> # Drag element to another element by ref
60
+ agent-view drag --from-pos 50,80 --to-pos 200,300 # Drag by coordinates (for canvas / Pixi)
61
+ agent-view drag --from <ref> --to <ref> --steps 25 --hold-ms 60 # Smoother movement, longer hold
62
+ ```
63
+
64
+ `drag` dispatches `mousePressed` → N × `mouseMoved` → `mouseReleased` via CDP. Endpoints can mix
65
+ ref and coordinate (e.g. `--from <ref> --to-pos 400,300`). For canvas/Pixi targets always use
66
+ `--from-pos`/`--to-pos` — derive the centroid via `agent-view eval` from the scene graph.
67
+ Refs are resolved fresh on each call, so window resizes between snapshots are tolerated.
68
+ Increase `--steps` for handlers using `globalpointermove` so intermediate frames are not skipped.
69
+
70
+ **Coordinates are a last resort.** `--pos` / `--from-pos` / `--to-pos` exist for canvas and WebGL,
71
+ where no ref exists. On DOM the correct order is `dom --filter "<text>"` → take the `[ref=N]` →
72
+ `click <ref>`, or `click --filter "<text>"` in one step. A coordinate pair breaks on any layout
73
+ shift, scroll, zoom, or window resize, and it clicks whatever now sits at that point — silently.
74
+ If you reach for `--pos` on a DOM element, first say why the ref was not usable.
75
+
76
+ ### Modals & file pickers (`dialog`, `upload`)
77
+
78
+ A modal that agent-view cannot answer stops a run dead: the window looks frozen, every
79
+ later command times out, and nothing says why. Two kinds, handled differently.
80
+
81
+ **JS modals — `alert` / `confirm` / `prompt` / `beforeunload` — are answered for you.**
82
+ Nothing to set up. While agent-view is attached these never block the page: the default
83
+ standing answer is *dismiss*, and each one is recorded. `agent-view dialog` is the
84
+ reliable place to read that record; the console feed carries the same line
85
+ (`[agent-view] confirm auto-dismissed: <message>`) but only from the moment console
86
+ attaches, so a modal answered before your first `console` call reaches `dialog` alone.
87
+
88
+ ```bash
89
+ agent-view dialog # standing answer + every modal this window has seen
90
+ agent-view dialog policy accept # confirm() → true from now on
91
+ agent-view dialog policy accept --text "name" # prompt() → "name"
92
+ agent-view dialog policy dismiss # back to the default
93
+ agent-view dialog dismiss # answer one that is open right now
94
+ agent-view dialog accept --text "x" # …ditto, accepting
95
+ ```
96
+
97
+ `dialog accept` / `dialog dismiss` exist for a modal that was already open **before**
98
+ agent-view attached — that one produced no event, so no policy applied to it.
99
+
100
+ **Native file pickers never open — you answer them in advance.** Which mechanism applies
101
+ depends on how the app opens the picker, and `dialog arm` sets up all of them at once,
102
+ so you do not have to know:
103
+
104
+ ```bash
105
+ # The input already exists in the DOM (even hidden) — no picker at all, cheapest path
106
+ agent-view upload --selector "#file-input" --file ./fixtures/a.png
107
+ agent-view upload --selector "#imgs" --file ./a.png --file ./b.png # multi-select
108
+ agent-view upload --ref 12 --file ./a.png # if the AX tree exposes it
109
+
110
+ # The input is created inside the click handler, or the app calls a native dialog API
111
+ agent-view dialog arm --file ./fixtures/a.png # then click the button that opens it
112
+ agent-view dialog arm --cancel # act as if the user pressed Cancel
113
+ agent-view dialog disarm # let real pickers open again
114
+ ```
115
+
116
+ Rules that actually bite:
117
+
118
+ - **Arm before the click.** A picker cannot be caught once it is open. `arm` is one-shot —
119
+ it is spent by the first picker and interception turns itself off, so a later click
120
+ opens a real OS dialog.
121
+ - **Click through `agent-view click`, never `eval "el.click()"`.** Chromium refuses to
122
+ open a file picker without user activation, and an eval-driven click carries none: the
123
+ picker is silently dropped and never intercepted.
124
+ - **Hidden inputs have no ref.** `display:none` / `v-show="false"` keeps them out of the
125
+ AX tree, so `dom` never prints one. Use `--selector`. `upload` has no `--filter` on
126
+ purpose: an accessible name lands on the label, not on the input behind it.
127
+ - **`beforeunload` is always dismissed**, whatever the policy — accepting it navigates
128
+ away and loses the state you are checking.
129
+ - Paths are resolved against your cwd and must exist — CDP accepts a bad path silently and
130
+ the app then reads an empty file.
131
+ - `agent-view dialog` after the fact shows what was intercepted and what was answered.
132
+
133
+ Known limits: `showOpenFilePicker()` (File System Access API) exposes no input to fill, so
134
+ it can only be cancelled. Electron does not implement `window.prompt` at all. Native
135
+ dialogs opened straight from an Electron **main** process (`dialog.showOpenDialog` behind
136
+ an IPC channel) are out of reach — CDP does not see the main process.
137
+
138
+ ### Waiting (`wait`)
139
+
140
+ ```bash
141
+ agent-view wait --filter "Saved" # until the text appears in the AX tree
142
+ agent-view wait --filter "Saved" --timeout 20 # max wait in seconds (default 10)
143
+ agent-view wait --filter "Row 5" --window "Main" # specific window
144
+ ```
145
+
146
+ Exits as soon as the element appears; exits non-zero on timeout — so `&&` after it is a real gate.
147
+
148
+ **Never sleep for a fixed time** — see the waiting-signal table in `SKILL.md`. If no condition-based
149
+ wait fits, poll `dom --filter X --count` with an explicit attempt cap and report the attempt count.
150
+
151
+
152
+ ### Screenshots
153
+ ```bash
154
+ agent-view screenshot --scale 0.5 # Recommended: JPEG at half-res (~3× fewer vision tokens)
155
+ agent-view screenshot --scale 0.5 --window <id> # Specific window
156
+ agent-view screenshot --crop "Sidebar" # Crop to element bounding box (~1.6k tokens — 12× win)
157
+ agent-view screenshot --crop "Chart" --scale 0.5 # Crop + scale (stacks)
158
+ agent-view screenshot --crop "Active bookings" --crop-up 1 # Crop the card, not just its heading
159
+ agent-view screenshot # Full-res PNG (expensive: ~19k tokens at 1920×1080)
160
+ ```
161
+
162
+ `--crop <filter>` resolves the element with the same filter syntax as `dom --filter`, then crops the screenshot to its bounding box. Prefer `--crop` over full-window screenshots whenever you only need to inspect a specific section. Falls back to full-window with a stderr warning if the filter matches nothing.
163
+
164
+ A text filter usually matches the text-bearing node, so cropping on a section title returns a thin strip of that title. `--crop-up <n>` climbs `n` element ancestors before cropping — use `1` (sometimes `2`) to get the surrounding card/section. When a crop comes back text-sized, the command says so on stderr.
165
+
166
+ ### Runtime State (`eval`)
167
+
168
+ Reads runtime values DOM/screenshot can't reveal — store contents, computed flags, worker internals.
169
+ **Requires `"allowEval": true` in `agent-view.config.json`** — if the call returns "eval is disabled", tell the user to add the flag rather than working around it.
170
+
171
+ ```bash
172
+ agent-view eval "store.state.user.role" # default page target
173
+ agent-view eval --window "Settings" "router.currentRoute.path"
174
+ agent-view eval --target sync-worker "self.queue.length" # SharedWorker / ServiceWorker by id or substring
175
+ agent-view eval --await "fetch('/api/health').then(r => r.status)"
176
+ agent-view eval --json "({ buttons: document.querySelectorAll('button').length })"
177
+ ```
178
+
179
+ When to reach for `eval` instead of `dom`:
180
+ - The truth lives in JS state, not the DOM (Pinia/Vuex/Redux/Zustand store, Vue refs, computed values, app singletons).
181
+ - The target is a worker (`shared_worker`, `service_worker`, `worker`) — DOM doesn't exist there.
182
+ - You need a precise number/string answer, not a tree to scan.
183
+ - Verifying a `window.*` API or globally-exposed object exists. `eval` runs in the page's **main world**, so anything set on `window` directly or exposed via `contextBridge.exposeInMainWorld` is reachable. APIs placed only in an isolated-world preload (without `contextBridge`) will NOT be visible — that is not an agent bug, that is the host app's wiring.
184
+
185
+ ### Reactive State (`watch`)
186
+
187
+ Streams JSON-patch diffs of an expression over time. Use when you need to see *what changed* between an action and a final state — `eval` shows the snapshot, `watch` shows the trajectory. **Requires `"allowEval": true`.**
188
+
189
+ ```bash
190
+ agent-view watch "store.cart.total" # 250ms poll, default 10 changes or 30s
191
+ agent-view watch "appState" --until "appState.status === 'ready'" # wait-for-condition with diff log
192
+ agent-view watch "store.user" --max-changes 1 # capture exactly one change after a click
193
+ agent-view watch "appState" --json # NDJSON, machine-readable
194
+ ```
195
+
196
+ When to reach for `watch` instead of `eval`:
197
+ - Debugging "the click did X but state shows Y — what happened in between?"
198
+ - Time-based assertions ("wait until store.status === 'ready'") — `--until` exits cleanly when truthy.
199
+ - Confirming an action triggered the *expected* sequence of mutations, not just the final state.
200
+
201
+ Output: `init` line (baseline), one line per RFC 6902 op (`replace /path old → new`, `add /items/0 ...`), final `stop` line with reason. Snapshot size cap 256 KB — narrow the expression (`store.x.y`, not `store`) for large objects.
202
+
203
+ ### Console (`console`)
204
+
205
+ Streams `Runtime.consoleAPICalled` + `Log.entryAdded`. Use to confirm a flow finished without errors, or to surface a specific warning after an interaction.
206
+
207
+ ```bash
208
+ agent-view console # buffered messages from auto-attached targets
209
+ agent-view console --level error,warn # filter
210
+ agent-view console --target sync-worker # one target (title/URL substring, same fuzzy semantics as eval --target)
211
+ agent-view console --target IJ56KL # one target (exact id)
212
+ agent-view console --follow --timeout 10 # stream window (use sparingly — 10s of waiting)
213
+ agent-view console --follow --until "ready" # exit as soon as a message contains "ready"
214
+ agent-view console --follow --until "/error/i" # exit on regex match (case-insensitive)
215
+ agent-view console --clear # baseline before an interaction
216
+ agent-view console --since "2026-04-26T10:00:00Z"
217
+ ```
218
+
219
+ `--until` requires `--follow`. Exits immediately when a message matches (substring or `/regex/flags`). On timeout without match exits non-zero.
220
+
221
+ Standard pattern for "did this action error?":
222
+ ```bash
223
+ agent-view console --clear
224
+ agent-view click --filter "Save"
225
+ agent-view wait --filter "Saved"
226
+ agent-view console --level error # expect "(no console messages)"
227
+ ```
228
+
229
+ Default attached target types: `page`, `shared_worker`, `service_worker` (override via `consoleTargets` in config).
230
+
231
+ ### Log feed (`logs`)
232
+
233
+ `console` reads a ring buffer that dies with the server; `logs` records the same messages — page *and* every worker — into one file you can grep later. Reach for it when a bug needs a timeline instead of a snapshot: intermittent failures, long scenarios, anything spanning reloads or worker restarts.
234
+
235
+ Feeds are scoped to the CDP port, so parallel worktrees each record their own app; give each one its own feed path (the default relative `.agent-view/console.log` already does, one per checkout).
236
+
237
+ ```bash
238
+ agent-view logs start --truncate # start clean; keeps recording across reloads
239
+ agent-view logs # tail last 200 records (alias of `logs tail`)
240
+ agent-view logs tail --grep "ws closed" # substring or /regex/
241
+ agent-view logs tail --since -2m # -30s | -5m | -2h | 09:31 | 09:31:02.500 | ISO
242
+ agent-view logs tail --level error,warn -n 50
243
+ agent-view logs clear # truncate feed + drop console buffer (baseline)
244
+ agent-view logs status # attached targets, feed size, tick count
245
+ agent-view logs stop
246
+ ```
247
+
248
+ Feed format — one record per line, always `HH:MM:SS.mmm [level] [type:id8] text`, local time, embedded newlines escaped as `\n`. That makes external `grep`/`awk` safe on it; a wrapped stack or JSON payload never breaks line-oriented filtering.
249
+
250
+ Default file `.agent-view/console.log` in the project root (override with `logFile` in config or `--file`). Caps at 8 MB, then rotates once to `<file>.prev` (`logMaxBytes` to change). Recording suspends the server's 5-min idle shutdown, so a long scenario keeps writing.
251
+
252
+ Standard pattern for "it fails once every N runs":
253
+ ```bash
254
+ agent-view logs start --truncate
255
+ # … drive the scenario, reload, retry as many times as needed …
256
+ agent-view logs tail --level error,warn
257
+ agent-view logs tail --grep "/socket|retry/" --since -5m
258
+ agent-view logs stop
259
+ ```
260
+
261
+ **Probes** (`--probe <file.js>[@target]`, requires `allowEval`) inject JS that logs into the same feed — use it when the evidence you need isn't logged by the app (wrap a method, count events, dump a scheduler). The probe is re-injected automatically whenever its context is gone: page reload, worker restart. Write it idempotent and let it report via plain `console.log`.
262
+
263
+ ```bash
264
+ agent-view logs start --probe ./probes/orchestrator.js@shared_worker --probe ./probes/audio.js@index.html
265
+ ```
266
+
267
+ ### Network (`network`)
268
+
269
+ Request/response timeline, headers, timing, bodies, and WebSocket/SSE frames. Use to confirm an expected API call fired, diagnose a silent 404 / CORS block / missing auth header, or verify "button disabled until the network completes".
270
+
271
+ ```bash
272
+ agent-view network # recent requests, newest at the bottom
273
+ agent-view network --req 3 # expand one: headers, timing, body / WS frame log
274
+ agent-view network --status 4xx,5xx # only failures (class or exact code, e.g. 404)
275
+ agent-view network --method POST # mutations among reads
276
+ agent-view network --type xhr,fetch # drop document/image/font noise
277
+ agent-view network --url "*/api/save*" # URL substring or * glob
278
+ agent-view network --follow --until "/api/save" # stream until a matching request fires
279
+ agent-view network --clear # baseline before an interaction
280
+ ```
281
+
282
+ **Eager, unlike `console`.** `network` captures from app launch, so page-load traffic (initial XHR/fetch, auth handshakes, boot 404s) is usually already buffered by the time you call it — in most cases you don't need to reload. `console` is the opposite (lazy: attaches on first call, loses earlier output). Call this asymmetry out so it isn't mistaken for a bug. Caveat: for very fast apps the earliest request can fire before capture attaches. If boot traffic looks missing, don't conclude "no request fired" — reload (`agent-view eval "location.reload()"`) and re-check before deciding.
283
+
284
+ `[req=N]` handles are reallocated on every list call (like `dom` refs) — expand from the most recent list. Sensitive headers are redacted by default (`--raw-headers` reveals them). Response/request **bodies** require `"captureBody": true` in config; WebSocket frame payloads are visible by default.
285
+
286
+ Standard pattern for "did the save call fire and succeed?":
287
+ ```bash
288
+ agent-view network --clear
289
+ agent-view click --filter "Save"
290
+ agent-view wait --filter "Saved"
291
+ agent-view network --url "*/api/save*" # expect one POST with status 200
292
+ ```
293
+
294
+ ### Reachability (`coverage`, `listeners`)
295
+
296
+ Use these before writing "no user action reaches this code" in a review. Reading a diff cannot prove reachability; running the app can.
297
+
298
+ **Only positive answers are cheap.** Proving a path exists costs one run of that path. Proving no path exists costs every path, so it is never bought. Both commands therefore treat an empty result as a valid answer with exit 0 — never as a failure — and neither ever proves unreachability.
299
+
300
+ `coverage` reports which functions ran since the last `--clear`, grouped by script URL:
301
+
302
+ ```bash
303
+ agent-view coverage --clear # open the window: counters reset
304
+ agent-view coverage # what ran since --clear (and reset again)
305
+ agent-view coverage --file "OrderForm" # scripts whose URL contains this
306
+ agent-view coverage --filter "onSubmit" # function name or script URL contains this
307
+ agent-view coverage --count # just the number of executed functions
308
+ agent-view coverage --all # include node_modules / runtime / url-less scripts
309
+ agent-view coverage --max-lines 40 # cap the output, tail `… N more lines`
310
+ agent-view coverage --target sync-worker # a worker's own window
311
+ ```
312
+
313
+ Standard pattern for "does clicking Save reach the code I changed?" — `clear → act → check`:
314
+ ```bash
315
+ agent-view coverage --clear \
316
+ && agent-view click --filter "Save" \
317
+ && agent-view coverage --file "OrderForm" # expect the handler by name
318
+ ```
319
+
320
+ **Every read is also a reset**, so two `coverage` calls in a row report different things — that is what makes one click attributable. Empty output is `(no code executed since --clear)`: it means *this* action did not reach the code, not that nothing can. Granularity is the function; unnamed functions print as `<anonymous>@<offset>`. Coverage lives in the V8 isolate, so a reload wipes it — `--clear` again after `location.reload()`. Reading before any `--clear` is an error telling you to run `--clear` first. `node_modules`, runtime bundles and url-less (`eval`'d) scripts are hidden unless `--all`.
321
+
322
+ `listeners` reports what is bound to one node and where each handler was declared:
323
+
324
+ ```bash
325
+ agent-view listeners --filter "Save" # node by accessible name, as in `click --filter`
326
+ agent-view listeners --ref 12 # node by ref from `dom`
327
+ agent-view listeners --selector "#save" # node by CSS — for nodes the AX tree never exposes
328
+ agent-view listeners --depth -1 # whole subtree (CDP depth; default 0)
329
+ ```
330
+
331
+ Positions are 1-based (`file.vue:88:14`) and paste straight into a review comment. `(no listeners on this node)` means the node itself has none — the handler may still be delegated from an ancestor, so try `--depth -1` from a parent before concluding anything. An unresolvable script falls back to `scriptId:7:88:14`. Reach for `--selector` only when the node has no `[ref=N]` — hidden and `aria-hidden` elements never enter the AX tree.
332
+
333
+ ### Memory (`heap`)
334
+
335
+ Named V8 heap snapshots, compared by class. The method (baseline → repeat the action ×10 → target → diff, then retainers) and how to read the output live in [`memory-leaks.md`](memory-leaks.md); this is the flag reference.
336
+
337
+ ```bash
338
+ agent-view heap take --name baseline # full GC, then snapshot; default names are s1, s2, …
339
+ agent-view heap take --name target -t worker # a worker's own heap
340
+ agent-view heap diff # the two most recent snapshots
341
+ agent-view heap diff baseline target # by name
342
+ agent-view heap diff --detached # detached DOM nodes only
343
+ agent-view heap diff --filter "OrderRow" # class name contains this
344
+ agent-view heap summary # classes of the latest snapshot by size
345
+ agent-view heap retainers "Detached <div class=\"row\">" # who holds the instances, one hop up
346
+ agent-view heap list # snapshots the server holds
347
+ agent-view heap clear # drop them
348
+ ```
349
+
350
+ `take` prints one line: `Snapshot "target" (page:Orders): 184,203 nodes, 41.2 MB, 240 detached DOM nodes (960 KB)`. The JSON never leaves the server; only the class table and the graph are kept, and they go away when the server idles out (5 min) or on `clear`.
351
+
352
+ `diff` prints a header with the node, byte and detached deltas, then one row per class whose count or size changed, largest size growth first: `class Δcount Δsize count`. Class names are V8's: JS objects by constructor (`OrderRowVM`), DOM nodes by tag and attributes (`<div class="row">`, `Detached <canvas>`), everything else by kind (`(string)`, `(closure)`, `(compiled code)`). Two snapshots with nothing changed print `(no class changed between "a" and "b")`, exit 0. `diff` before two snapshots exist is an error naming the recovery.
353
+
354
+ `retainers <class>` prints `retainer instances` rows: `Array []` means the instances are elements of an `Array`, `RowRegistry .el` means they are the `.el` property of a `RowRegistry`. Distinct instances are counted, not edges; weak edges and the class's own instances are excluded. A class with no instances prints `(no instances of "X" in "s")`, exit 0. Quote the class name: it contains spaces and angle brackets.
355
+
356
+ `--max-lines <n>` caps `summary`, `diff` and `retainers` with the usual `… N more lines` tail.
357
+
358
+ ### Targets (`targets`)
359
+
360
+ When `--window` doesn't show what you expected, or you need a worker target id for `eval`/`console`:
361
+
362
+ ```bash
363
+ agent-view targets # everything connectable
364
+ agent-view targets --type shared_worker,service_worker # filter
365
+ agent-view targets --json # machine-readable
366
+ ```
367
+
368
+ You usually don't need this — `eval --target <substring>` and `--window <name>` both do fuzzy matching. Reach for `targets` when the substring is ambiguous.
369
+
370
+ `targets` prints ids truncated to 8 chars, and `--target` / `--window` accept that printed handle (case-insensitive id prefix, ≥4 chars) as well as a full id or a title/URL substring. An ambiguous prefix is reported as ambiguous rather than resolved to an arbitrary target. Worker targets often share a blank title, so the printed id prefix is the reliable handle for them.
371
+
372
+ ### Scene / Canvas / WebGL (only when `webgl` is configured in agent-view.config.json)
373
+
374
+ These commands read the scene graph from canvas-based rendering engines. Skip this section if the project has no `webgl` field in config.
375
+
376
+ ```bash
377
+ agent-view scene # Scene graph from configured engine
378
+ agent-view scene --filter "player" # Filter by object name/type
379
+ agent-view scene --verbose # Extended props (scale, alpha, rotation)
380
+ agent-view scene --diff # Changes since last call
381
+ agent-view scene --compact # Merge single-child chains onto one line (reduces output)
382
+ agent-view snap # DOM + Scene combined
383
+ agent-view snap --scale 0.5 # DOM + Scene + Screenshot (path appended as === Screenshot === section)
384
+ ```
@@ -0,0 +1,23 @@
1
+ # Design conformance
2
+
3
+ Comparing captured screenshots against design references. Triggered when you are handed
4
+ `(label, screenshot command, expected reference path)` rows — from a plan, or from the developer
5
+ directly. Execute them yourself, inline, no subagent.
6
+
7
+ For each row:
8
+
9
+ 1. Run the screenshot command; capture the saved file path from stdout.
10
+ 2. Open both images for visual comparison — the capture and the `expected_path`. (Any harness
11
+ capability that loads an image into context; in Claude Code that is the file-read tool.) If
12
+ `expected_path` does not exist or cannot be read, mark the pair `skipped (expected_missing)`
13
+ and move on.
14
+ 3. Compare for: layout (relative position, alignment), sizing, color (dominant color family),
15
+ typography (weight/size broadly), content presence (anything missing or extra), decorations
16
+ (borders, shadows, dashed/solid lines, icons).
17
+ 4. Report each pair as `match` / `minor_mismatch` / `major_mismatch` with a one-sentence deviation.
18
+ - **Major** — missing or wrong component, broken layout, wrong color family, wrong text content.
19
+ - **Minor** — <10px spacing drift, slight color shade, small decoration difference.
20
+
21
+ Tolerance default is a designer's code-review level: flag what they would notice, ignore
22
+ anti-aliasing noise. Do not speculate about CSS causes — describe what looks different and let the
23
+ developer decide.
@@ -0,0 +1,94 @@
1
+ # Memory leak debugging with `heap`
2
+
3
+ Read this when the question is "does this action leak?", "why does memory grow?", or a screen gets
4
+ slower every time it is opened. The tool is `agent-view heap`; flags are in
5
+ [`commands.md`](commands.md#memory-heap).
6
+
7
+ ## The method: three snapshots, one repeated action
8
+
9
+ A single snapshot proves nothing: every app holds caches, pools and lazily built state that is
10
+ alive by design. A leak is what **grows with repetition and does not come back**. So:
11
+
12
+ 1. **Baseline.** Put the app in the state you will return to (the list closed, the dialog
13
+ dismissed). `agent-view heap take --name baseline`.
14
+ 2. **Repeat the action ~10 times.** Open the dialog and close it, navigate away and back, run the
15
+ search and clear it. Ten repetitions turn a per-action leak into a clear `+10 × N` in the diff
16
+ and drown out one-off allocations. Drive it with `click` / `fill` / `eval`, and finish in the
17
+ baseline state.
18
+ 3. **Target.** `agent-view heap take --name target`, then `agent-view heap diff baseline target`.
19
+ 4. **Final (optional).** Do whatever should release the memory (close the view, log out), take
20
+ `final`, and `heap diff target final`. Growth that goes away here is a cache, not a leak.
21
+
22
+ Every `take` runs a full GC first, so the numbers are live objects only.
23
+
24
+ ## Reading the diff
25
+
26
+ ```
27
+ baseline → target (page:Orders): +3,201 nodes, +2.4 MB, detached +240 (+960 KB)
28
+ class Δcount Δsize count
29
+ Detached <div class="row"> +240 +960 KB 252
30
+ OrderRowVM +10 +12 KB 10
31
+ (closure) +40 +8 KB 9,120
32
+ ```
33
+
34
+ - **The header line is the verdict.** `detached +240` after ten repetitions means 24 DOM nodes
35
+ per action are removed from the document but still referenced. `+0 nodes` and `+0 B` means
36
+ nothing leaked; stop.
37
+ - **Rows are classes sorted by size growth.** Look for a `Δcount` that is a multiple of your
38
+ repetition count: `+10`, `+20`, `+240` against 10 repetitions is the leak, `+3` is noise.
39
+ - **`Detached <tag …>`** rows are DOM nodes out of the document, named as V8 names them
40
+ (`<div class="row">`, `<canvas>`), so the class attribute usually names the component.
41
+ `--detached` shows only these.
42
+ - **A named class** (`OrderRowVM`, `Subscription`) growing in step with a detached DOM row is the
43
+ object that owns the node, and the better lead: it is your code.
44
+ - **`(closure)`, `(string)`, `(array)`** growing alone are usually the *content* of the leak, not
45
+ its cause; find the named class that grew with them.
46
+
47
+ `--filter <text>` narrows to a class name substring. Class names print as-is, so quote them:
48
+ `--filter "Detached <div"`.
49
+
50
+ ## Finding what holds it
51
+
52
+ ```bash
53
+ agent-view heap retainers "Detached <div class=\"row\">" --name target
54
+ ```
55
+
56
+ ```
57
+ Detached <div class="row"> ×252 in "target", retained by:
58
+ retainer instances
59
+ Array [] 240
60
+ RowRegistry .el 12
61
+ ```
62
+
63
+ One row per `<retainer class> <edge>`: which object holds the instances and through which property
64
+ or index. Read it as *"240 of them sit in an `Array`, 12 are the `.el` field of a `RowRegistry`"*.
65
+ The retainer that holds the same multiple as your repetition count is the one to fix; the next
66
+ question is who holds *that*: `heap retainers Array` is rarely useful (too many arrays), so go
67
+ back to the diff and pick the named class that grew alongside, or read the source for where a
68
+ `RowRegistry` keeps `.el`.
69
+
70
+ Only one hop is computed, and only strong edges: `WeakMap`, `WeakRef` and weak listeners never
71
+ appear, so if a retainer is missing, the object is held through something the GC ignores and is
72
+ not the leak. Instances holding each other (sibling links) are not listed.
73
+
74
+ ## Common causes, by what the diff shows
75
+
76
+ | Diff shows | Usual cause |
77
+ |----------------------------------------------------------|------------------------------------------------------------------------------|
78
+ | `Detached <…>` growing, retainer `Array []` / `Map` | A list of elements or rows kept for lookup and never pruned on unmount |
79
+ | `Detached <…>` growing, retainer `system / Context .<var>` | A closure (listener, observer, timer) captured the node in variable `<var>`, and was never removed |
80
+ | A named class growing, no detached DOM | A subscription / store watcher registered per mount, unregistered never |
81
+ | `(string)` growing alone, MBs at a time | A log buffer or a cache keyed by something unbounded (URL with a timestamp) |
82
+ | Everything grows a little, no multiples | Not a leak; warm caches and JIT. Compare `target → final` to confirm |
83
+
84
+ ## Scope and cost
85
+
86
+ - `take` is fast (a quarter second on the 30k-node bench app, linear in heap size) and holds the
87
+ parsed graph in the server, never in your context. The snapshot is parsed from one string, so a
88
+ heap above roughly 500 MB is out of reach; that is a DevTools job. Snapshots vanish when the
89
+ server idles out (5 min) or on `heap clear`; take all three in one sitting.
90
+ - `--target <worker>` snapshots a worker's own heap; a worker leak is invisible in the page's.
91
+ - Retained size, dominators, full retaining paths, duplicate-string scans and the other DevTools
92
+ filters (objects retained by event handlers, by console, by execution context) are not computed.
93
+ When the one hop and the detached filter are not enough, open the app's DevTools Memory panel on
94
+ the same CDP port: the class names printed here are the same ones it shows.
@@ -1,35 +0,0 @@
1
- import type { RuntimeSession, ConsoleMessage, ConsoleLevel, TargetType } from './types.js';
2
- export type ConsoleStreamOptions = {
3
- /** Per-target ring size. Default 500. */
4
- capacity?: number;
5
- };
6
- export type ConsoleFilter = {
7
- since?: number;
8
- level?: ReadonlySet<ConsoleLevel>;
9
- targetId?: string;
10
- };
11
- export type StampedConsoleMessage = ConsoleMessage & {
12
- targetId: string;
13
- targetType: TargetType;
14
- };
15
- /**
16
- * Multi-target console subscription with per-target ring buffer.
17
- * Server owns one instance for its lifetime; commands attach/drain.
18
- */
19
- export declare class ConsoleStream {
20
- private readonly capacity;
21
- private readonly targets;
22
- private readonly extraSubscribers;
23
- constructor(opts?: ConsoleStreamOptions);
24
- get attachedCount(): number;
25
- /** Idempotent per target id — second attach for same id is a no-op. */
26
- attach(session: RuntimeSession): void;
27
- detach(targetId?: string): void;
28
- clear(targetId?: string): void;
29
- /** Snapshot of buffered messages, sorted by timestamp (oldest first). */
30
- drain(filter?: ConsoleFilter): StampedConsoleMessage[];
31
- /** Subscribe to live messages. Returns disposer. Used by --follow streaming. */
32
- subscribe(handler: (msg: StampedConsoleMessage) => void): () => void;
33
- private snapshot;
34
- }
35
- //# sourceMappingURL=console-stream.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"console-stream.d.ts","sourceRoot":"","sources":["../../src/cdp/console-stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAI1F,MAAM,MAAM,oBAAoB,GAAG;IACjC,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,WAAW,CAAC,YAAY,CAAC,CAAA;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG,cAAc,GAAG;IACnD,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,UAAU,CAAA;CACvB,CAAA;AAUD;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoC;IAC5D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAkD;gBAEvE,IAAI,GAAE,oBAAyB;IAI3C,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED,uEAAuE;IACvE,MAAM,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IA6BrC,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;IAY/B,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;IAc9B,yEAAyE;IACzE,KAAK,CAAC,MAAM,GAAE,aAAkB,GAAG,qBAAqB,EAAE;IAe1D,gFAAgF;IAChF,SAAS,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,IAAI,GAAG,MAAM,IAAI;IAKpE,OAAO,CAAC,QAAQ;CAIjB"}
@@ -1,103 +0,0 @@
1
- const DEFAULT_CAPACITY = 500;
2
- /**
3
- * Multi-target console subscription with per-target ring buffer.
4
- * Server owns one instance for its lifetime; commands attach/drain.
5
- */
6
- export class ConsoleStream {
7
- capacity;
8
- targets = new Map();
9
- extraSubscribers = new Set();
10
- constructor(opts = {}) {
11
- this.capacity = opts.capacity ?? DEFAULT_CAPACITY;
12
- }
13
- get attachedCount() {
14
- return this.targets.size;
15
- }
16
- /** Idempotent per target id — second attach for same id is a no-op. */
17
- attach(session) {
18
- const id = session.target.id;
19
- if (this.targets.has(id))
20
- return;
21
- const entry = {
22
- session,
23
- ring: new Array(this.capacity),
24
- cursor: 0,
25
- full: false,
26
- dispose: () => { },
27
- };
28
- entry.dispose = session.onConsole((msg) => {
29
- const stamped = {
30
- ...msg,
31
- targetId: id,
32
- targetType: session.target.type,
33
- };
34
- entry.ring[entry.cursor] = stamped;
35
- entry.cursor = (entry.cursor + 1) % this.capacity;
36
- if (entry.cursor === 0)
37
- entry.full = true;
38
- for (const sub of this.extraSubscribers) {
39
- try {
40
- sub(stamped);
41
- }
42
- catch { /* ignore */ }
43
- }
44
- });
45
- this.targets.set(id, entry);
46
- }
47
- detach(targetId) {
48
- if (targetId === undefined) {
49
- for (const t of this.targets.values())
50
- t.dispose();
51
- this.targets.clear();
52
- return;
53
- }
54
- const t = this.targets.get(targetId);
55
- if (!t)
56
- return;
57
- t.dispose();
58
- this.targets.delete(targetId);
59
- }
60
- clear(targetId) {
61
- if (targetId === undefined) {
62
- for (const t of this.targets.values()) {
63
- t.cursor = 0;
64
- t.full = false;
65
- }
66
- return;
67
- }
68
- const t = this.targets.get(targetId);
69
- if (!t)
70
- return;
71
- t.cursor = 0;
72
- t.full = false;
73
- }
74
- /** Snapshot of buffered messages, sorted by timestamp (oldest first). */
75
- drain(filter = {}) {
76
- const result = [];
77
- for (const [id, entry] of this.targets) {
78
- if (filter.targetId && filter.targetId !== id)
79
- continue;
80
- const msgs = this.snapshot(entry);
81
- for (const m of msgs) {
82
- if (filter.since !== undefined && m.ts < filter.since)
83
- continue;
84
- if (filter.level && !filter.level.has(m.level))
85
- continue;
86
- result.push(m);
87
- }
88
- }
89
- result.sort((a, b) => a.ts - b.ts);
90
- return result;
91
- }
92
- /** Subscribe to live messages. Returns disposer. Used by --follow streaming. */
93
- subscribe(handler) {
94
- this.extraSubscribers.add(handler);
95
- return () => this.extraSubscribers.delete(handler);
96
- }
97
- snapshot(entry) {
98
- if (!entry.full)
99
- return entry.ring.slice(0, entry.cursor);
100
- return [...entry.ring.slice(entry.cursor), ...entry.ring.slice(0, entry.cursor)];
101
- }
102
- }
103
- //# sourceMappingURL=console-stream.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"console-stream.js","sourceRoot":"","sources":["../../src/cdp/console-stream.ts"],"names":[],"mappings":"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"}