@crouton-kit/capture 1.4.1 → 1.4.10
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.
- package/README.md +178 -0
- package/bin/capture +31299 -7322
- package/package.json +3 -1
- package/src/capture.ts +21 -18
- package/src/cdp/args.ts +269 -49
- package/src/cdp/bridge/server.ts +6 -5
- package/src/cdp/bridge/spawn.ts +41 -97
- package/src/cdp/commands/bridge-serve.ts +11 -21
- package/src/cdp/commands/cdp.ts +44 -22
- package/src/cdp/commands/heap/census.ts +61 -0
- package/src/cdp/commands/heap/common.ts +77 -0
- package/src/cdp/commands/heap/diff.ts +92 -0
- package/src/cdp/commands/heap/index.ts +38 -0
- package/src/cdp/commands/heap/objects.ts +42 -0
- package/src/cdp/commands/heap/retainers.ts +52 -0
- package/src/cdp/commands/heap/snapshot.ts +94 -0
- package/src/cdp/commands/lib.ts +9 -17
- package/src/cdp/commands/lighthouse.ts +414 -0
- package/src/cdp/commands/measure/census.ts +2 -1
- package/src/cdp/commands/measure/check.ts +70 -16
- package/src/cdp/commands/measure/diff.ts +1 -2
- package/src/cdp/commands/measure/explain.ts +44 -7
- package/src/cdp/commands/measure/index.ts +24 -32
- package/src/cdp/commands/measure/map-ax.ts +2 -1
- package/src/cdp/commands/measure/map-focus.ts +2 -1
- package/src/cdp/commands/measure/map-layers.ts +5 -3
- package/src/cdp/commands/measure/map-scroll.ts +2 -1
- package/src/cdp/commands/measure/snap.ts +5 -4
- package/src/cdp/commands/measure/sweep.ts +16 -11
- package/src/cdp/commands/measure/text.ts +147 -0
- package/src/cdp/commands/motion/index.ts +10 -18
- package/src/cdp/commands/motion/jank.ts +13 -22
- package/src/cdp/commands/motion/mask.ts +10 -9
- package/src/cdp/commands/motion/rec.ts +230 -28
- package/src/cdp/commands/motion/timeline.ts +1 -1
- package/src/cdp/commands/page/click.ts +18 -8
- package/src/cdp/commands/page/elements.ts +43 -11
- package/src/cdp/commands/page/exec.ts +53 -18
- package/src/cdp/commands/page/index.ts +20 -20
- package/src/cdp/commands/page/inspect.ts +338 -0
- package/src/cdp/commands/page/navigate.ts +83 -38
- package/src/cdp/commands/page/repeat.ts +176 -0
- package/src/cdp/commands/page/scroll.ts +11 -6
- package/src/cdp/commands/page/shot.ts +68 -33
- package/src/cdp/commands/page/type.ts +7 -3
- package/src/cdp/commands/perf/index.ts +32 -0
- package/src/cdp/commands/perf/insights.ts +214 -0
- package/src/cdp/commands/perf/trace.ts +235 -0
- package/src/cdp/commands/perf/vitals.ts +76 -0
- package/src/cdp/commands/session/collectors.ts +54 -0
- package/src/cdp/commands/stub.ts +10 -0
- package/src/cdp/commands/tab/close.ts +2 -2
- package/src/cdp/commands/tab/index.ts +16 -23
- package/src/cdp/commands/tab/launch.ts +1 -1
- package/src/cdp/commands/tab/mock/index.ts +24 -0
- package/src/cdp/commands/tab/mock/lifecycle.ts +88 -0
- package/src/cdp/commands/tab/mock/start.ts +65 -0
- package/src/cdp/commands/tab/mock/stop.ts +39 -0
- package/src/cdp/commands/tab/network.ts +22 -13
- package/src/cdp/commands/tab/reset.ts +11 -12
- package/src/cdp/connection.ts +19 -39
- package/src/cdp/detect.ts +27 -7
- package/src/cdp/dispatch.ts +25 -4
- package/src/cdp/domains.ts +2 -2
- package/src/cdp/har-recorder.ts +0 -1
- package/src/cdp/heap-snapshot.ts +647 -0
- package/src/cdp/host/client.ts +22 -0
- package/src/cdp/host/collector.ts +74 -0
- package/src/cdp/host/collectors/heap.ts +79 -0
- package/src/cdp/host/collectors/intercept.ts +247 -0
- package/src/cdp/{recorder-bridge.ts → host/collectors/motion.ts} +388 -473
- package/src/cdp/host/collectors/trace.ts +108 -0
- package/src/cdp/host/core.ts +217 -0
- package/src/cdp/host/handle.ts +47 -0
- package/src/cdp/host/held-client.ts +91 -0
- package/src/cdp/host/kinds.ts +97 -0
- package/src/cdp/host/lifecycle.ts +123 -0
- package/src/cdp/host/server.ts +88 -0
- package/src/cdp/leaf-grammar.ts +2 -2
- package/src/cdp/measure/check.ts +181 -16
- package/src/cdp/measure/collectors/hittest.ts +16 -10
- package/src/cdp/measure/collectors/scroll.ts +15 -7
- package/src/cdp/measure/collectors/style-provenance.ts +11 -0
- package/src/cdp/measure/collectors/styles.ts +4 -4
- package/src/cdp/measure/explain.ts +14 -2
- package/src/cdp/measure/map-layers.ts +52 -8
- package/src/cdp/measure/snapshot.ts +5 -3
- package/src/cdp/measure/sweep.ts +29 -6
- package/src/cdp/measure/text.ts +227 -0
- package/src/cdp/motion/jank.ts +29 -83
- package/src/cdp/motion/mask.ts +18 -9
- package/src/cdp/motion/recorder.ts +86 -731
- package/src/cdp/scope-lock.ts +9 -9
- package/src/cdp/screenshot.ts +51 -21
- package/src/cdp/timing.ts +5 -5
- package/src/cdp/trace-analysis.ts +320 -0
- package/src/cdp/types.ts +31 -1
- package/src/cdp.ts +4 -6
- package/src/har-manager.ts +2 -4
- package/src/interact.ts +78 -25
- package/src/output/artifact.ts +49 -5
- package/src/output/render.ts +60 -9
- package/src/output/selection.ts +6 -0
- package/src/session/artifacts.ts +122 -12
- package/src/session/commands.ts +348 -113
- package/src/session/coordinator.ts +0 -93
- package/src/session/har-redact.ts +29 -23
- package/src/session-context.ts +13 -9
- package/src/cdp/bridge/protocol.ts +0 -224
- package/src/cdp/recorder-client.ts +0 -326
- package/src/cdp/tab-lock.ts +0 -132
package/README.md
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# capture
|
|
2
|
+
|
|
3
|
+
**Browser automation that measures instead of guessing.** A CDP command line built for agents.
|
|
4
|
+
|
|
5
|
+
A screenshot shows you what a page looks like. It does not show you why the button doesn't work.
|
|
6
|
+
|
|
7
|
+
`capture` answers questions about a live page with numbers and coordinates: what is covering this button, which CSS rule moved it, how long the page took to answer a click, what changed between two states, and which pixels moved and when. Every finding comes back with the element, the geometry, and the evidence it was read from.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g @crouton-kit/capture
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Against the alternatives
|
|
14
|
+
|
|
15
|
+
Compared against `@playwright/mcp` 0.0.79 and `chrome-devtools-mcp` 1.8.0 — the Chrome DevTools MCP surface Claude Code drives — read at those published versions.
|
|
16
|
+
|
|
17
|
+
Both ship a JavaScript escape hatch, so much of this is *reachable* in either one — by writing the code yourself. ❌ below means the answer is not returned to you as a fact; it means you write and maintain the measurement.
|
|
18
|
+
|
|
19
|
+
| | capture | Playwright MCP | Chrome DevTools MCP |
|
|
20
|
+
|---|:---:|---|---|
|
|
21
|
+
| Bounding box of every element | ✅ | ✅ `browser_snapshot boxes:true` | ❌ Must use raw JS |
|
|
22
|
+
| Names the element covering a target | ✅ | ❌ Must use raw JS | ❌ Must use raw JS |
|
|
23
|
+
| Percentage of the target's box it covers | ✅ | ❌ Must use raw JS | ❌ Must use raw JS |
|
|
24
|
+
| Full receiver stack at a point | ✅ | ❌ Must use raw JS | ❌ Must use raw JS |
|
|
25
|
+
| Winning CSS declaration for a property | ✅ | ❌ Must use raw CDP | ❌ Not reachable — no CSS tool, no CDP passthrough |
|
|
26
|
+
| Its specificity and source location | ✅ | ❌ Must use raw CDP | ❌ Not reachable |
|
|
27
|
+
| Tap-target and contrast findings | ✅ | ❌ Must use raw JS | ✅ `lighthouse_audit`, written to a report file |
|
|
28
|
+
| A rect on every finding | ✅ | ❌ Must use raw JS | ❌ Inside the report file |
|
|
29
|
+
| A PNG crop of every finding | ✅ | ❌ One screenshot call per element | ❌ No crops |
|
|
30
|
+
| Per-element style and geometry delta between two states | ✅ | ❌ Must use raw JS | ❌ Must use raw JS |
|
|
31
|
+
| Cascade provenance on the property that changed | ✅ | ❌ Must use raw CDP | ❌ Not reachable |
|
|
32
|
+
| Raster diff of two states | ✅ | ❌ Diff two screenshots yourself | ❌ Diff two screenshots yourself |
|
|
33
|
+
| Steps a width range in one command | ✅ | ❌ Your own resize loop | ❌ Your own resize loop |
|
|
34
|
+
| Brackets the exact pixel where layout state changes | ✅ | ❌ Your own resize loop | ❌ Your own resize loop |
|
|
35
|
+
| Input → mutation → paint → settle for one interaction | ✅ | ❌ Video file only | ❌ Trace insights are page-level |
|
|
36
|
+
| Per-frame geometry of one element through an animation | ✅ | ❌ Video file only | ❌ Must use raw JS |
|
|
37
|
+
| Changed pixel regions attributed to elements | ✅ | ❌ Must use raw JS | ❌ Must use raw JS |
|
|
38
|
+
| A whole interaction as one image | ✅ | ❌ | ❌ |
|
|
39
|
+
|
|
40
|
+
Both do things capture does not. Playwright MCP is cross-browser and can mock network responses; Chrome DevTools MCP has Core Web Vitals, real Lighthouse, DevTools performance tracing and heap profiling. capture is Chromium-only and points at one question — what is this page actually doing, in numbers.
|
|
41
|
+
|
|
42
|
+
## See it
|
|
43
|
+
|
|
44
|
+
Eight short clips. Every overlay is real: the text is extracted from the command's actual stdout, the boxes are drawn at the coordinates the command printed, and the inset images are files a command actually wrote.
|
|
45
|
+
|
|
46
|
+
Each player below contains the full clip. Use its controls to play, pause, scrub, or fullscreen.
|
|
47
|
+
|
|
48
|
+
### 1. Every command succeeded. The page is still broken.
|
|
49
|
+
|
|
50
|
+
<video src="https://github.com/user-attachments/assets/eb82b71b-a981-49b7-a0cc-c823dcda43c9" controls muted playsinline></video>
|
|
51
|
+
|
|
52
|
+
An agent checks out. The promo code applies and the total drops $691.20 → $518.40, so the page is clearly working. Then it clicks **Complete purchase** — reported clicked, nothing happens. Rather than guess, it measures. The hit test resolves the click to something that is not the button, and `measure map paint` names it: `#consent`, z-index 99, **covering 100.00%** of the button's ink box.
|
|
53
|
+
|
|
54
|
+
Playwright throws "element intercepts pointer events" and names nothing. A screenshot shows a perfect page.
|
|
55
|
+
|
|
56
|
+
`capture measure map paint <snap> --selector "#pay"` · [full clip, 22s](demo/1-ghost-overlay.mp4)
|
|
57
|
+
|
|
58
|
+
### 2. The page looks finished. The measurements disagree.
|
|
59
|
+
|
|
60
|
+
<video src="https://github.com/user-attachments/assets/37cd9cc9-0ac8-4f53-938b-799065657261" controls muted playsinline></video>
|
|
61
|
+
|
|
62
|
+
One command measures a team-access page against thresholds and draws every failure onto it at real coordinates: a row control at 28×28 under the 44×44 floor, a helper line at 2.16:1 contrast, an identity column clipping the address it is showing you. Each finding carries a cropped PNG of its own evidence, and the gate exits nonzero.
|
|
63
|
+
|
|
64
|
+
`capture measure check <snap> --for tap-targets,contrast,truncation --gate` · [full clip, 22s](demo/2-check-gate.mp4)
|
|
65
|
+
|
|
66
|
+
### 3. Two changes shipped. Which one moved the button?
|
|
67
|
+
|
|
68
|
+
<video src="https://github.com/user-attachments/assets/e33641f0-61d1-4e0a-a80a-232782a0d35a" controls muted playsinline></video>
|
|
69
|
+
|
|
70
|
+
A report switches to Weekly, then a design-system stylesheet lands live. The Publish button is somewhere new. A pixel diff can only say "3% of pixels differ" — this names the element, both of its boxes, how far it moved, and the declaration that now wins, down to `tokens-v2.css` line 6.
|
|
71
|
+
|
|
72
|
+
`capture measure diff --before <snap> --after <snap>` · [full clip, 27s](demo/3-measure-diff.mp4)
|
|
73
|
+
|
|
74
|
+
### 4. The layout flips between two pixel widths. Which two?
|
|
75
|
+
|
|
76
|
+
<video src="https://github.com/user-attachments/assets/b07923e9-9e10-4af3-a3f4-b5cdebc24309" controls muted playsinline></video>
|
|
77
|
+
|
|
78
|
+
Instead of dragging a window edge until something snaps, sweep the axis. The viewport steps 619 → 620 → 621 → 622, the grid goes one column to two, and the command brackets the exact pair it happened between.
|
|
79
|
+
|
|
80
|
+
`capture measure sweep --axis width --from 619 --to 622` · [full clip, 21s](demo/4-sweep-breakpoint.mp4)
|
|
81
|
+
|
|
82
|
+
### 5. Name a component. Get the component.
|
|
83
|
+
|
|
84
|
+
<video src="https://github.com/user-attachments/assets/584c2a67-c684-4019-be84-e6ae2145567c" controls muted playsinline></video>
|
|
85
|
+
|
|
86
|
+
The agent asks for a card and gets a cropped, padded, zoomed image of exactly that card — no coordinates, no full-viewport screenshot to squint at. It can ask by CSS selector or by the visible label a screen reader would read. Ask for `button` when six match, and it refuses to guess and lists all six.
|
|
87
|
+
|
|
88
|
+
`capture page shot --crop-selector "#revenue-card" --pad 8 --zoom 1.5` · [full clip, 24s](demo/5-component-shot.mp4)
|
|
89
|
+
|
|
90
|
+
### 6. How fast did that click actually answer?
|
|
91
|
+
|
|
92
|
+
<video src="https://github.com/user-attachments/assets/a88cb918-cd42-4681-8bd2-9f725dbf8a57" controls muted playsinline></video>
|
|
93
|
+
|
|
94
|
+
Record a real interaction, then read its timeline off the recording rather than eyeballing a screenshot: input dispatch, DOM mutation at +7.20ms, first paint at +18.76ms across 6276 changed pixels, settled at +325.06ms. Every row names the evidence it came from.
|
|
95
|
+
|
|
96
|
+
`capture motion response <rec> --action "click:Run sweep"` · [full clip, 23s](demo/6-motion-response.mp4)
|
|
97
|
+
|
|
98
|
+
### 7. Seven seconds of motion, in one still.
|
|
99
|
+
|
|
100
|
+
<video src="https://github.com/user-attachments/assets/001e21ff-bfed-4cd9-9b2e-350562c751f6" controls muted playsinline></video>
|
|
101
|
+
|
|
102
|
+
A model cannot watch a video. Hand it a screen recording and you are really handing it dozens of separate frames to reason across one at a time — expensive, and still hopeless, because the thing you care about is the motion *between* frames and no single frame contains it.
|
|
103
|
+
|
|
104
|
+
`motion mask` collapses the whole interaction into one image, which is the format a model reads well. Colour encodes *when* each pixel changed — blue is early, red is late — so the entire route of the payload is legible at a glance. Underneath it, the changed regions ranked largest first with the window each one moved in. The agent gets to see the animation.
|
|
105
|
+
|
|
106
|
+
`capture motion mask <rec> --limit 4` · [full clip, 22s](demo/7-motion-mask.mp4)
|
|
107
|
+
|
|
108
|
+
### 8. Drive the browser you are already signed into.
|
|
109
|
+
|
|
110
|
+
<video src="https://github.com/user-attachments/assets/5924757d-96e0-456e-94ce-0575d50a7faa" controls muted playsinline></video>
|
|
111
|
+
|
|
112
|
+
No storage-state dance and no separate automation profile. Attach over `--port`, adopt the tab already in front of you, drive it, and finish with one bundle: the recording, the HAR, the shots and the measurements together. The network panel is drawn from the captured HAR — every field read from that entry, nothing inferred, and credential headers withheld with their length marked in place.
|
|
113
|
+
|
|
114
|
+
`capture session start --target <tab-id> --port 9860` · [full clip, 30s](demo/8-live-session.mp4)
|
|
115
|
+
|
|
116
|
+
## Quick start
|
|
117
|
+
|
|
118
|
+
Needs Node and a Chrome. `capture tab launch` starts a headless browser that capture owns and reaps — it looks for `$CAPTURE_BROWSER`, then a `~/.cache/puppeteer` Chrome, then a system Chrome. If a CDP-enabled browser is already running, capture can attach to that instead.
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
capture tab launch # start a browser capture owns
|
|
122
|
+
capture session start --url https://example.com # open a tab, begin recording traffic
|
|
123
|
+
capture measure snap # → snap-mtdpfnkr-08fbabdd
|
|
124
|
+
capture measure check snap-mtdpfnkr-08fbabdd --for contrast,tap-targets
|
|
125
|
+
capture session stop <session-id> # write the bundle manifest
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
`measure check` reports real measurements, not opinions:
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
1. tap-targets — html > body > div > p:nth-of-type(2) > a measures 82×18px; threshold is 44×44px
|
|
132
|
+
Rect: x=160 y=186.078125 w=82 h=18
|
|
133
|
+
crop: snap-mtdpfnkr-08fbabdd/findings/1-tap-targets.png
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Add `--gate` to `check` or `diff` and it exits nonzero on findings, so the same command works in CI.
|
|
137
|
+
|
|
138
|
+
## The command surface
|
|
139
|
+
|
|
140
|
+
Seven roots. Every leaf renders prose by default and mirrors the same result under `--json`.
|
|
141
|
+
|
|
142
|
+
| root | what it owns |
|
|
143
|
+
|---|---|
|
|
144
|
+
| `session` | the artifact container — records HAR, bundles artifacts, sets the active context |
|
|
145
|
+
| `page` | verbs against the live tab — `click`, `type`, `scroll`, `navigate`, `exec`, `shot`, `elements` |
|
|
146
|
+
| `tab` | browser and tab plumbing — `launch`, `list`, `open`, `close`, `reset`, `network` |
|
|
147
|
+
| `measure` | settled-snapshot substrate plus read-only queries — `snap`, `check`, `diff`, `explain`, `sweep`, `census`, `map` |
|
|
148
|
+
| `motion` | recorder lifecycle plus queries over a recording — `rec`, `mask`, `timeline`, `response`, `jank` |
|
|
149
|
+
| `cdp` | raw Chrome DevTools Protocol escape hatch |
|
|
150
|
+
| `lib` | vault-lib introspection, for running forked libs in the tab |
|
|
151
|
+
|
|
152
|
+
Run any of them bare for the subcommand list, or `capture <root> <leaf> -h` for a leaf's usage.
|
|
153
|
+
|
|
154
|
+
## How it fits together
|
|
155
|
+
|
|
156
|
+
Three artifact kinds, and the split matters because it is what keeps queries cheap.
|
|
157
|
+
|
|
158
|
+
- **A session** is the container. It opens or adopts a tab, records HAR while it is active, and writes a bundle manifest when it stops. Everything produced while it runs lands in one directory.
|
|
159
|
+
- **A snapshot** (`measure snap`) drives the page once and writes a settled substrate — geometry, styles, accessibility, layers, hit testing, text, forms, screenshot. Every other `measure` leaf is a cheap read over that artifact and never re-drives the browser.
|
|
160
|
+
- **A recording** (`motion rec`) captures an interaction, one-shot or composed across several commands. Every other `motion` leaf reads the finalized recording.
|
|
161
|
+
|
|
162
|
+
Findings exit 0 — they are a report, not a crash. Only `check` and `diff` accept `--gate`, which turns findings into exit 2.
|
|
163
|
+
|
|
164
|
+
## Targeting elements
|
|
165
|
+
|
|
166
|
+
The driving verbs resolve exactly one element through a single grammar, and reject an ambiguous target with the list of candidates rather than picking one:
|
|
167
|
+
|
|
168
|
+
- a bare CSS selector (takes precedence)
|
|
169
|
+
- an exact accessible name, when CSS finds nothing
|
|
170
|
+
- `ax:<name>`, `axid:<id>`, or `backend:<id>`
|
|
171
|
+
|
|
172
|
+
## For agents
|
|
173
|
+
|
|
174
|
+
The CLI is designed to be read by a model: errors are structured, every error carries a `follow_up` naming the command that would fix it, and help is available at every level.
|
|
175
|
+
|
|
176
|
+
## License
|
|
177
|
+
|
|
178
|
+
MIT
|