@verirun/cli 0.2.4 → 0.3.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.
- package/README.md +302 -17
- package/dist/cli.js +61 -28
- package/dist/gate.mjs +1 -1
- package/dist/graph.mjs +39 -39
- package/man/verirun.1 +294 -28
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@ Record a browser workflow, replay it, and capture the Supabase, Vercel + Railway
|
|
|
4
4
|
your backend produced during the replay. Plus `verirun map`: a static
|
|
5
5
|
interaction graph of your React/TypeScript app — every page, what you can click
|
|
6
6
|
on it, and which backend calls those clicks make — without running anything.
|
|
7
|
+
And `verirun scan <url>`: a read-only scan of any live site for JS errors,
|
|
8
|
+
failed requests, dead links and missing anchors, with no source or logs needed.
|
|
7
9
|
|
|
8
10
|
## Install
|
|
9
11
|
|
|
@@ -30,17 +32,34 @@ your `MANPATH` (`man verirun`) on macOS, Linux, and WSL / Git Bash. Native
|
|
|
30
32
|
Windows (cmd, PowerShell) has no `man` — use `--help`, or `man -l` the file
|
|
31
33
|
under a POSIX shell. From a `npm link` checkout: `man -l man/verirun.1`.
|
|
32
34
|
|
|
35
|
+
### Output and exit codes
|
|
36
|
+
|
|
37
|
+
Output is compact by default: a verdict on the first line (`PASS` / `FAIL`),
|
|
38
|
+
then only the evidence for it. Commands that report something take `--json`
|
|
39
|
+
(one object on one line, with a `schemaVersion`) and `--verbose` for the full
|
|
40
|
+
detail. With `--json`, progress and warnings go to stderr, so stdout is the
|
|
41
|
+
result and nothing else.
|
|
42
|
+
|
|
43
|
+
| Exit code | Meaning |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| `0` | The command did what it was asked and the check, if any, passed. |
|
|
46
|
+
| `1` | It ran, and what it checks failed: a replay step (`run`), findings (`scan`), errors in a workflow file (`workflow check`), no usable license (`whoami`), a recording with no actions (`record`). |
|
|
47
|
+
| `2` | It could not run: bad usage, missing setup, no license, an unreachable target. With `--json` the message is also printed on stdout as `{"status":"error","error":{"message":"…"}}`. |
|
|
48
|
+
|
|
49
|
+
Before 0.3.0 every failure exited `1`. A script that only tests for non-zero is
|
|
50
|
+
unaffected.
|
|
51
|
+
|
|
33
52
|
---
|
|
34
53
|
|
|
35
54
|
## Account
|
|
36
55
|
|
|
37
|
-
`record` and `
|
|
56
|
+
`record`, `run`, `map` and `scan` need a connected Verirun account. First run on a machine:
|
|
38
57
|
|
|
39
58
|
```bash
|
|
40
59
|
verirun login
|
|
41
60
|
```
|
|
42
61
|
|
|
43
|
-
This prints a short code and a link. Open the link, sign in (a
|
|
62
|
+
This prints a short code and a link. Open the link, sign in (a 3-day free trial
|
|
44
63
|
starts automatically if you are new), and enter the code. The CLI then holds a
|
|
45
64
|
device token for that machine.
|
|
46
65
|
|
|
@@ -49,6 +68,11 @@ verirun whoami # account, plan, subscription status
|
|
|
49
68
|
verirun logout # disconnect this machine
|
|
50
69
|
```
|
|
51
70
|
|
|
71
|
+
`verirun whoami` exits `0` when the gated commands would run and `1` when they
|
|
72
|
+
would not, and `verirun whoami --json` prints the same status as JSON
|
|
73
|
+
(`schemaVersion` 1, with a `licensed` boolean), so a script can check the
|
|
74
|
+
license without parsing text.
|
|
75
|
+
|
|
52
76
|
| | |
|
|
53
77
|
| --- | --- |
|
|
54
78
|
| `~/.verirun/config.json` | Holds the device token. Per user, not per project. Restricted to your account (0600, or an `icacls` ACL on Windows). |
|
|
@@ -114,6 +138,8 @@ Opens a headed browser. Perform the workflow by hand — click, type, navigate.
|
|
|
114
138
|
| `--user-data-dir <dir>` | Record in a persistent profile directory, so the session is already logged in and stays logged in for later runs. The real browser using that profile must be closed first. |
|
|
115
139
|
| `--test-id-attribute <attr>` | Attribute preferred for test-id selectors. Defaults to `data-testid`; also settable as `testIdAttribute` in config. |
|
|
116
140
|
| `-f, --force` | Overwrite an existing workflow of the same name. Without it, recording onto an existing name errors. |
|
|
141
|
+
| `--json` | Print the result as JSON (`schemaVersion` 1: `name`, `saved`, `steps`, `path`). Everything else goes to stderr. |
|
|
142
|
+
| `--verbose` | List every recorded step after saving. By default `record` prints one line: how many steps it saved and where. |
|
|
117
143
|
|
|
118
144
|
**Name rules.** `<name>` becomes a filename: letters, digits, dot, dash,
|
|
119
145
|
underscore; must start with a letter or digit; 64 chars max. Two Windows rules
|
|
@@ -147,6 +173,20 @@ what you recorded is what runs.
|
|
|
147
173
|
into a field and close the browser without clicking or tabbing away, that last
|
|
148
174
|
value is not recorded. Tab out before closing.
|
|
149
175
|
|
|
176
|
+
**Dialogs.** Answer `alert` / `confirm` / `prompt` boxes in the recording
|
|
177
|
+
browser as you normally would. Codegen notes *that* a step opened one but not
|
|
178
|
+
which button you pressed, so after you close the browser `record` asks, per such
|
|
179
|
+
step, `[O]K / [c]ancel` (Enter = OK; without a terminal every answer is OK). The
|
|
180
|
+
answer is saved on the step and `run` replays it:
|
|
181
|
+
|
|
182
|
+
```json
|
|
183
|
+
{ "index": 4, "action": "click", "selector": "…", "dialog": { "action": "dismiss" } }
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
`action` is `accept` (OK) or `dismiss` (Cancel). For a `prompt()`, add
|
|
187
|
+
`"promptText": "…"` — without it, accepting submits the prompt's default value.
|
|
188
|
+
Every dialog the step opens gets the same answer.
|
|
189
|
+
|
|
150
190
|
**Nothing recorded.** If you close the browser without doing anything, nothing
|
|
151
191
|
is saved and the command says so.
|
|
152
192
|
|
|
@@ -208,6 +248,26 @@ Replays the recorded steps — headless, in the same browser kind the workflow w
|
|
|
208
248
|
recorded in — then captures logs for the wall-clock window the replay occupied
|
|
209
249
|
and writes `.verirun/runs/<name>-<timestamp>/logs.json`.
|
|
210
250
|
|
|
251
|
+
What it prints is a summary, verdict first:
|
|
252
|
+
|
|
253
|
+
```text
|
|
254
|
+
FAIL checkout step 2 failed: click button "Pay now" (2/4 steps replayed, 2.3s)
|
|
255
|
+
locator.click: Timeout 2000ms exceeded.
|
|
256
|
+
waiting for locator('role=button[name="Pay now"i]')
|
|
257
|
+
selector: role=button[name="Pay now"i]
|
|
258
|
+
logs 90 entries, 34 errors, 6 warnings (Vercel 90)
|
|
259
|
+
x30 vercel/lambda error 500 Error: connect ECONNREFUSED 10.0.3.7:5432
|
|
260
|
+
x3 vercel/lambda error 500 TypeError: Cannot read properties of undefined (reading 'total')
|
|
261
|
+
x1 vercel/lambda error 500 Unhandled rejection: payment provider returned 402 for order ord_99812
|
|
262
|
+
full log: .verirun/runs/checkout-2026-11-13T13-10-02-468Z/logs.json
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
The `logs` lines are the error-level entries (and any carrying an HTTP 5xx
|
|
266
|
+
status) from the run window. Lines that differ only by ids or numbers are
|
|
267
|
+
folded into one with a count, most frequent first, 8 groups at most. A `PASS`
|
|
268
|
+
with error lines under `logs` is the case this tool exists for: the screen said
|
|
269
|
+
done and the backend threw. Everything else is in `logs.json`.
|
|
270
|
+
|
|
211
271
|
| Flag | Meaning |
|
|
212
272
|
| --- | --- |
|
|
213
273
|
| `--slow-mo <ms>` | Pause before each action. Defaults to **500 ms when `--headed`** so you can follow the run by eye, and to 0 otherwise. `--slow-mo 0` watches at full speed; a bigger number follows a fast form more easily. |
|
|
@@ -217,6 +277,25 @@ and writes `.verirun/runs/<name>-<timestamp>/logs.json`.
|
|
|
217
277
|
| `--user-data-dir <dir>` | Replay in a persistent profile directory, so it runs already logged in. The profile must not be open in another browser. |
|
|
218
278
|
| `--cdp <url>` | Attach to a browser already running with remote debugging and drive it. See below. |
|
|
219
279
|
| `--user <id>` | Keep only log entries whose message or raw payload contains this string, case-insensitive — e.g. a user's email. Overrides `config.userFilter`. Recorded in `logs.json` as `"filter": { "user": … }`; `entries` and the per-source counts are post-filter. If everything is filtered out, `run` warns. |
|
|
280
|
+
| `--dialog <answer>` | How to answer a browser dialog opened by a step with no saved `dialog` answer: `accept` (OK, the default) or `dismiss` (Cancel). A step's own `dialog` always wins. |
|
|
281
|
+
| `--json` | Print the summary as one JSON object instead of text (below). `logs.json` is written either way. |
|
|
282
|
+
| `--verbose` | Also print each step as it replays, every distinct error line, and the full error text. |
|
|
283
|
+
|
|
284
|
+
`run --json` (`schemaVersion` 1) is the summary, not the entries:
|
|
285
|
+
|
|
286
|
+
```jsonc
|
|
287
|
+
{ "schemaVersion": 1, "tool": "verirun-run", "workflow": "checkout", "status": "ok" | "failed",
|
|
288
|
+
"durationMs": 2300, "window": { "startedAt": "<ISO>", "endedAt": "<ISO>" },
|
|
289
|
+
"steps": { "total": 4, "replayed": 2, "failedAt": 2 },
|
|
290
|
+
"failedStep": { "index": 2, "action": "click", "selector": "…", "description": "…" }, // on failure
|
|
291
|
+
"error": "<full message>", // on failure
|
|
292
|
+
"dialogs": 0,
|
|
293
|
+
"sources": [ { "id": "vercel", "name": "Vercel", "entries": 90 } ],
|
|
294
|
+
"logs": { "entries": 90, "problems": 34, "warnings": 6, "groupsOmitted": 0,
|
|
295
|
+
"groups": [ { "source": "vercel", "stream": "lambda", "level": "error", "status": 500,
|
|
296
|
+
"message": "<first line>", "count": 30, "firstAt": "<ISO>", "lastAt": "<ISO>" } ] },
|
|
297
|
+
"logsPath": ".verirun/runs/checkout-<timestamp>/logs.json" }
|
|
298
|
+
```
|
|
220
299
|
|
|
221
300
|
**Where the user filter runs.** For **Supabase** it goes into the log query's
|
|
222
301
|
`WHERE` (matched against the rendered message and the JSON of `metadata`), so
|
|
@@ -263,6 +342,11 @@ frontmost.
|
|
|
263
342
|
whatever logs already landed are still written, and the exit code is non-zero.
|
|
264
343
|
- Popups and newly opened tabs become the active target as they open. A workflow
|
|
265
344
|
that drives several tabs at once is not supported yet.
|
|
345
|
+
- Browser dialogs (`alert`, `confirm`, `prompt`, `beforeunload`) are answered
|
|
346
|
+
automatically: with the step's saved `dialog` if it has one, otherwise with
|
|
347
|
+
`--dialog` (default `accept`). Each one is printed under its step and listed
|
|
348
|
+
in `logs.json` `dialogs`. With `--cdp`, only tabs the run itself drives or
|
|
349
|
+
opens are touched.
|
|
266
350
|
|
|
267
351
|
### Sequencing
|
|
268
352
|
|
|
@@ -282,6 +366,9 @@ warned about and contributes no entries.
|
|
|
282
366
|
"window": { "startedAt": "2026-08-31T13:01:50.998Z", "endedAt": "2026-08-31T13:01:51.499Z" },
|
|
283
367
|
"steps": { "total": 12, "replayed": 12 },
|
|
284
368
|
"filter": { "user": "ada@example.com" },
|
|
369
|
+
"dialogs": [
|
|
370
|
+
{ "step": 7, "type": "confirm", "message": "Delete this item?", "action": "accept", "at": "2026-08-31T13:01:51.102Z" }
|
|
371
|
+
],
|
|
285
372
|
"sources": [{ "id": "vercel", "name": "Vercel", "entries": 8 }],
|
|
286
373
|
"entries": [
|
|
287
374
|
{
|
|
@@ -300,12 +387,100 @@ warned about and contributes no entries.
|
|
|
300
387
|
(the step index) and the file carries a top-level `error` string.
|
|
301
388
|
- `filter` is present only when `--user` / `config.userFilter` was in effect;
|
|
302
389
|
`entries` and every `sources[].entries` count are then post-filter.
|
|
390
|
+
- `dialogs` lists every browser dialog the replay answered, in order: the
|
|
391
|
+
`step` running when it opened, its `type` and `message`, the prompt's
|
|
392
|
+
`defaultValue` (prompts only), the `action` taken, and the `promptText`
|
|
393
|
+
submitted to an accepted prompt. Empty when none opened.
|
|
303
394
|
- `entries` merges every source, sorted by `timestamp`. `stream` is the
|
|
304
395
|
sub-stream within a source (`lambda`, `edge`, `postgres_logs`, …). `raw` is
|
|
305
396
|
the provider's untouched payload (for Supabase that now includes the row's
|
|
306
397
|
`metadata`, so a `--user` filter can match a nested email field).
|
|
307
|
-
- With no log sources configured, `run` still replays and
|
|
308
|
-
empty.
|
|
398
|
+
- With no log sources configured, `run` still replays and says so in its
|
|
399
|
+
summary; `entries` is empty.
|
|
400
|
+
- The file's schema is unchanged by the compact summary: `run` prints less, it
|
|
401
|
+
does not store less.
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## `verirun scan <url>`
|
|
406
|
+
|
|
407
|
+
```bash
|
|
408
|
+
verirun scan https://example.com
|
|
409
|
+
verirun scan https://example.com --md # paste-ready Markdown
|
|
410
|
+
verirun scan https://example.com --json # the full report
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
An outside-in scan of a live site. It needs no source code, no recording and
|
|
414
|
+
no log source: point it at a public URL. It crawls same-origin links breadth
|
|
415
|
+
first (20 pages, 2 hops from the start URL by default) in headless Chromium,
|
|
416
|
+
loading up to 4 pages at a time with a 500 ms pause before each request on
|
|
417
|
+
each connection. Pages listed in the site's sitemap (the `Sitemap:` lines in
|
|
418
|
+
`robots.txt`, else `/sitemap.xml`) join the crawl after the start page's own
|
|
419
|
+
links, so a site whose navigation is JavaScript rather than `<a href>` is still
|
|
420
|
+
covered. A request that gets no response at all (a reset connection, not a
|
|
421
|
+
timeout) is asked once more before it is reported. A `429` means the site is
|
|
422
|
+
rate-limiting the scanner, not that the URL is broken, so it is counted rather
|
|
423
|
+
than reported; a link served as a download is treated as a file. It reports,
|
|
424
|
+
per page:
|
|
425
|
+
|
|
426
|
+
- JavaScript exceptions and console errors
|
|
427
|
+
- failed requests and HTTP 4xx / 5xx responses
|
|
428
|
+
- dead internal links
|
|
429
|
+
- in-page `#anchor` and skip-link targets that do not exist
|
|
430
|
+
- a missing main landmark
|
|
431
|
+
|
|
432
|
+
Only the site's own problems are kept: its own origin, or an API it calls.
|
|
433
|
+
Analytics, ad, chat-widget and other third-party noise is dropped. The same
|
|
434
|
+
finding on several pages is reported once, with the pages and a count.
|
|
435
|
+
|
|
436
|
+
```text
|
|
437
|
+
FAIL https://example.com/ 5 findings on 6 pages (browser, 9.4s)
|
|
438
|
+
JS exception TypeError: Cannot read properties of undefined (reading 'call')
|
|
439
|
+
on /
|
|
440
|
+
HTTP error 500 GET /api/data
|
|
441
|
+
on /
|
|
442
|
+
dead link /broken-page returned 404
|
|
443
|
+
on /
|
|
444
|
+
…
|
|
445
|
+
14 internal links checked
|
|
446
|
+
never requested: 2 destructive-looking links, 1 URL disallowed by robots.txt
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
**It is strictly read-only.**
|
|
450
|
+
|
|
451
|
+
- It only navigates. It sends `GET` and `HEAD`, never clicks a button, never
|
|
452
|
+
submits a form.
|
|
453
|
+
- It never requests a link that looks destructive: `logout`, `signout`,
|
|
454
|
+
`delete`, `remove`, `unsubscribe`, `cancel`, `deactivate`, `revoke` and
|
|
455
|
+
similar, in the URL or the link text.
|
|
456
|
+
- It identifies itself honestly:
|
|
457
|
+
`Mozilla/5.0 (compatible; VerirunScan/1.0; +https://get-verirun.duely.in/scanner)`.
|
|
458
|
+
That page explains the scanner and how to block it.
|
|
459
|
+
- It obeys `robots.txt` (the `VerirunScan` group, else `*`), including
|
|
460
|
+
`Crawl-delay`; a site that sets one gets one request at a time. If the start
|
|
461
|
+
URL is disallowed, the scan does not run.
|
|
462
|
+
|
|
463
|
+
Scan sites you own or have permission to scan.
|
|
464
|
+
|
|
465
|
+
| Flag | Meaning |
|
|
466
|
+
| --- | --- |
|
|
467
|
+
| `--max-pages <n>` | Stop after this many pages. Default 20. |
|
|
468
|
+
| `--depth <n>` | Follow same-origin links this many hops from the start URL. Default 2. |
|
|
469
|
+
| `--delay <ms>` | Pause before each page load, on each of the 4 parallel connections. Default 500; a larger `Crawl-delay` in robots.txt wins and also drops the scan to one connection. |
|
|
470
|
+
| `--timeout <ms>` | Per-page load timeout. Default 20000. |
|
|
471
|
+
| `--no-browser` | Plain HTTP instead of headless Chromium. Nothing is executed, so JS exceptions and console errors are not checked, and a page that renders entirely client-side shows little. The report says so. |
|
|
472
|
+
| `--json` | The report as one JSON object, `schemaVersion` 1: `status` (`clean` / `findings` / `error`), `summary`, `pages`, and `findings` (`kind`, `message`, `evidence`, `pages`, `count`). |
|
|
473
|
+
| `--md` | The report as Markdown, ready to paste into a reply or an issue. |
|
|
474
|
+
| `--verbose` | Every finding with its evidence, and every page scanned. |
|
|
475
|
+
|
|
476
|
+
Exit code `0` when nothing was found, `1` when there are findings, `2` when the
|
|
477
|
+
scan could not run (unreachable, disallowed by robots.txt, not HTML).
|
|
478
|
+
|
|
479
|
+
**What an outside scan cannot see.** It sees what a visitor's browser sees. It
|
|
480
|
+
does not know which backend call a button makes (`verirun map` reads that from
|
|
481
|
+
your source) and it cannot see your backend logs (`verirun run` captures those
|
|
482
|
+
for a recorded flow). It does not log in, so anything behind a login is out of
|
|
483
|
+
reach.
|
|
309
484
|
|
|
310
485
|
---
|
|
311
486
|
|
|
@@ -392,7 +567,7 @@ browser, no server, no recording.
|
|
|
392
567
|
|
|
393
568
|
```bash
|
|
394
569
|
verirun map # per-page summary
|
|
395
|
-
verirun map --json # the whole graph
|
|
570
|
+
verirun map --json # the whole graph, on one line (--verbose indents it)
|
|
396
571
|
verirun map --report # graph + coverage.md into .verirun/map
|
|
397
572
|
verirun map --bfs /account --depth 2 # what is reachable from one page
|
|
398
573
|
verirun map --reach # how much of each page was captured
|
|
@@ -422,17 +597,34 @@ element that gets you there:
|
|
|
422
597
|
$ verirun map --bfs /account --depth 2
|
|
423
598
|
page:/account
|
|
424
599
|
└─ nav "verirun" → page:/
|
|
425
|
-
└─ effect "revoke" [if
|
|
600
|
+
└─ effect "revoke" [if window.confirm("Revoke this terminal's access? …")] → effect:POST ?
|
|
601
|
+
opens confirm "Revoke this terminal's access? …" — the answer decides what the click does
|
|
426
602
|
└─ nav "Log in" → page:/login
|
|
427
603
|
# frontier at depth 2: page:/login, page:/signup
|
|
428
604
|
```
|
|
429
605
|
|
|
606
|
+
**Browser dialogs.** An element whose handler calls the native `alert()`,
|
|
607
|
+
`confirm()` or `prompt()` (bare, or on `window` / `globalThis`; a locally
|
|
608
|
+
imported `confirm` is a custom modal, not a dialog) carries
|
|
609
|
+
`dialogs: [{ type, message, messageStatic, gates, … }]` in `--json`. `gates` is
|
|
610
|
+
true when the handler reads the answer, so OK and Cancel lead to different
|
|
611
|
+
outcomes. An early `if (!window.confirm(…)) return;` also shows up as the
|
|
612
|
+
`guardSource` of every backend call after it, which is how you see that Cancel
|
|
613
|
+
skips the `POST`. The per-page summary counts the elements that open a dialog,
|
|
614
|
+
`--bfs` prints each one under its edge, and `coverage.md` lists them all. A
|
|
615
|
+
workflow step that clicks one answers it with its `dialog` field (see
|
|
616
|
+
[`verirun run`](#verirun-run-name)); `workflow check` warns when that field is
|
|
617
|
+
missing (see below).
|
|
618
|
+
|
|
430
619
|
**Limits, honestly.** It is static analysis: a target computed at runtime shows
|
|
431
620
|
as `unresolved`, an endpoint passed through a variable as `?`, and Supabase
|
|
432
621
|
`.auth.*` / `.storage.*` calls are not yet classified as effects. `--reach`
|
|
433
622
|
tells you what fraction of each page it actually attached, so you can see when
|
|
434
623
|
it is missing something rather than guessing.
|
|
435
624
|
|
|
625
|
+
`--bfs` and `--reach` also take `--json`, for the same result as one JSON
|
|
626
|
+
object (`schemaVersion` 1).
|
|
627
|
+
|
|
436
628
|
---
|
|
437
629
|
|
|
438
630
|
## `verirun workflow check <name>`
|
|
@@ -451,6 +643,15 @@ verirun workflow check login --json # machine-readable findings
|
|
|
451
643
|
verirun workflow check ./some/file.json
|
|
452
644
|
```
|
|
453
645
|
|
|
646
|
+
If `verirun map --report` has saved `.verirun/map/interaction-tree.json`,
|
|
647
|
+
`check` also warns about a step that clicks an element the graph says opens a
|
|
648
|
+
browser dialog but has no `dialog` answer. Replay would press OK, which is
|
|
649
|
+
usually what you want, but when the handler reads the answer, Cancel is a
|
|
650
|
+
different path and should be chosen on purpose. Matching is by exact selector, so it catches
|
|
651
|
+
workflows written from `map --json`. A selector that elements *without* a dialog
|
|
652
|
+
also match (a bare `role=button`) is skipped rather than guessed at. Re-run
|
|
653
|
+
`map --report` when the app changes; the saved graph goes stale.
|
|
654
|
+
|
|
454
655
|
Static only: it never opens a browser, so it cannot tell you whether a selector
|
|
455
656
|
matches the live page. Only `verirun run` can. Non-zero exit if anything is an
|
|
456
657
|
error.
|
|
@@ -477,7 +678,9 @@ an agent — to write `.verirun/workflows/<name>.json` directly:
|
|
|
477
678
|
Actions and required `params`: `navigate` (`url`, absolute), `click` /
|
|
478
679
|
`dblclick`, `fill` (`text`), `press` (`key`), `check` / `uncheck`, `select`
|
|
479
680
|
(`values`), `setInputFiles` (`files`). Everything but `navigate` needs a
|
|
480
|
-
`selector`, which is handed to `page.locator()` verbatim.
|
|
681
|
+
`selector`, which is handed to `page.locator()` verbatim. A step that opens a
|
|
682
|
+
browser dialog can carry `"dialog": { "action": "accept" | "dismiss",
|
|
683
|
+
"promptText"?: "…" }`; without it `run` accepts.
|
|
481
684
|
|
|
482
685
|
A recorded workflow is ground truth; a written one is a guess until `run`
|
|
483
686
|
confirms it. Don't overwrite a recording with a generated file — use a new name.
|
|
@@ -486,18 +689,30 @@ confirms it. Don't overwrite a recording with a generated file — use a new nam
|
|
|
486
689
|
|
|
487
690
|
## `verirun agent`
|
|
488
691
|
|
|
489
|
-
Prints a
|
|
490
|
-
|
|
491
|
-
the
|
|
492
|
-
**this** checkout — resolved repo root, configured log sources,
|
|
493
|
-
workflows, recent runs.
|
|
692
|
+
Prints a compact reference for an AI coding agent: what the tool does, the loop
|
|
693
|
+
to follow, how to read a result, the exit codes, the commands an agent drives
|
|
694
|
+
with their flags (read from the CLI itself, so they can't drift), and a
|
|
695
|
+
snapshot of **this** checkout — resolved repo root, configured log sources,
|
|
696
|
+
recorded workflows, recent runs.
|
|
697
|
+
|
|
698
|
+
The default is deliberately short, because an agent reads it on every task.
|
|
699
|
+
Three longer sections are printed only when asked for:
|
|
700
|
+
|
|
701
|
+
| `--topic` | What it covers |
|
|
702
|
+
| --- | --- |
|
|
703
|
+
| `authoring` | Writing a workflow file yourself from `map --json`: format, actions, selectors, dialogs. |
|
|
704
|
+
| `signed-in` | Testing a flow behind a login: the browser profile, Windows paths. |
|
|
705
|
+
| `schemas` | The full shapes of `run --json`, `logs.json` and the scan report. |
|
|
494
706
|
|
|
495
707
|
```bash
|
|
496
|
-
verirun agent
|
|
708
|
+
verirun agent # the short reference
|
|
709
|
+
verirun agent --topic authoring # one section
|
|
710
|
+
verirun agent --full > .verirun/AGENT.md # everything, saved as context for your agent
|
|
497
711
|
verirun agent --json # machine-readable form
|
|
498
712
|
verirun agent --skill --install # .claude/skills/verirun/SKILL.md
|
|
499
713
|
verirun agent --skill --install cursor # .cursor/rules/verirun.mdc
|
|
500
|
-
verirun agent --skill --install
|
|
714
|
+
verirun agent --skill --install codex # .agents/skills/verirun/SKILL.md + an AGENTS.md section
|
|
715
|
+
verirun agent --skill --install all # all three
|
|
501
716
|
```
|
|
502
717
|
|
|
503
718
|
`--skill` emits the same knowledge as an agent skill — frontmatter with a
|
|
@@ -509,14 +724,23 @@ looks:
|
|
|
509
724
|
|---|---|---|
|
|
510
725
|
| `claude` (default) | `.claude/skills/verirun/SKILL.md` | automatically, when a task looks like app testing |
|
|
511
726
|
| `cursor` | `.cursor/rules/verirun.mdc` | when the task matches its description (an agent-requested rule, not always-on) |
|
|
512
|
-
| `
|
|
727
|
+
| `codex` | `.agents/skills/verirun/SKILL.md`, plus a short section in `AGENTS.md` | the skill when the task matches its description; the `AGENTS.md` section (a pointer to the skill) on every request |
|
|
728
|
+
| `all` | all three | |
|
|
729
|
+
|
|
730
|
+
Codex reads skills from `.agents/skills/` between the working directory and the
|
|
731
|
+
repo root. `AGENTS.md` is shared with other tools and with people, so verirun only
|
|
732
|
+
writes between `<!-- verirun:start -->` and `<!-- verirun:end -->`: it creates the
|
|
733
|
+
file if there is none, appends the section if there is no marked one, and
|
|
734
|
+
replaces just that section on a re-run. Everything outside the markers is left as
|
|
735
|
+
it was.
|
|
513
736
|
|
|
514
737
|
Re-run it after upgrading verirun; the file is generated, not hand-maintained.
|
|
515
738
|
|
|
516
739
|
For any other agent, paste the output into `CLAUDE.md`, an `AGENTS.md`, or pipe it
|
|
517
740
|
straight into a prompt. No account needed. The agent then knows to run
|
|
518
|
-
`verirun run <name>`,
|
|
519
|
-
|
|
741
|
+
`verirun run <name>`, branch on the exit code, and act on the `PASS` / `FAIL`
|
|
742
|
+
summary without you explaining the tool, opening `logs.json` only when it needs
|
|
743
|
+
an entry the summary does not show.
|
|
520
744
|
|
|
521
745
|
---
|
|
522
746
|
|
|
@@ -663,6 +887,67 @@ run this often.
|
|
|
663
887
|
|
|
664
888
|
## Changelog
|
|
665
889
|
|
|
890
|
+
### 0.3.0
|
|
891
|
+
|
|
892
|
+
- **`verirun scan <url>`.** A read-only, outside-in scan of any live site: JS
|
|
893
|
+
exceptions, console errors, failed requests, HTTP 4xx / 5xx, dead internal
|
|
894
|
+
links, missing `#anchor` and skip-link targets, a missing main landmark. No
|
|
895
|
+
source and no logs needed. `--json`, `--md`, `--no-browser`. It never clicks
|
|
896
|
+
or submits, skips logout / delete style links, sends an honest user agent and
|
|
897
|
+
obeys `robots.txt`. Needs a connected account, like `record` and `run`.
|
|
898
|
+
It also crawls the pages a site's sitemap lists, so JavaScript-only
|
|
899
|
+
navigation is covered, and asks once more before reporting a request that
|
|
900
|
+
got no response, so one dropped connection does not fail the scan.
|
|
901
|
+
A rendered page bloated with inline base64 images no longer produces
|
|
902
|
+
missing-anchor findings past the read limit (data URIs are compacted, and a
|
|
903
|
+
page still too large skips its absence checks); `429`s and download links
|
|
904
|
+
are no longer reported as failures.
|
|
905
|
+
- **Compact output.** `run` now prints a verdict first, then the failed step
|
|
906
|
+
and the error-level log lines from the run window with repeats folded into a
|
|
907
|
+
count, instead of a step list and a pointer to a file. On the same run, what
|
|
908
|
+
an agent has to read to learn why it failed drops from the whole `logs.json`
|
|
909
|
+
to a few lines. `workflow check`, `whoami` and `record` lead with their
|
|
910
|
+
result too. `--verbose` brings the detail back.
|
|
911
|
+
- **`--json` everywhere it was missing**: `run`, `record`, `whoami`, `map --bfs`
|
|
912
|
+
and `map --reach`. Each is one object on one line with a `schemaVersion`.
|
|
913
|
+
`map --json` and `workflow check --json` are now one line too (`map
|
|
914
|
+
--verbose` indents); `workflow check --json` gained `schemaVersion`.
|
|
915
|
+
- **Exit codes mean something.** `0` ok, `1` the check failed, `2` could not
|
|
916
|
+
run (usage, setup, license, unreachable). Before, every failure was `1`.
|
|
917
|
+
`whoami` now exits `1` when the gated commands would not run.
|
|
918
|
+
- **`verirun agent --skill --install codex`.** Writes the skill to
|
|
919
|
+
`.agents/skills/verirun/SKILL.md`, where Codex looks for skills, and a short
|
|
920
|
+
marked section in `AGENTS.md` pointing at it, without touching the rest of
|
|
921
|
+
that file. `--install all` now covers Claude Code, Cursor and Codex.
|
|
922
|
+
- **`verirun agent` is shorter.** The default reference carries what an agent
|
|
923
|
+
needs on every task; the workflow-authoring, signed-in and schema sections
|
|
924
|
+
moved behind `--topic`, and `--full` prints everything.
|
|
925
|
+
- `logs.json` and workflow files are unchanged (both still `schemaVersion` 1).
|
|
926
|
+
|
|
927
|
+
### 0.2.5
|
|
928
|
+
|
|
929
|
+
- **`verirun run` answers browser dialogs instead of cancelling them.** With no
|
|
930
|
+
handler, Playwright dismissed every `alert` / `confirm` / `prompt`, so each
|
|
931
|
+
`confirm()` in a workflow came back as Cancel and the action it guarded
|
|
932
|
+
quietly never happened. Replay now answers each one: with the step's saved
|
|
933
|
+
`dialog` (`accept` / `dismiss`, plus `promptText` for a prompt), otherwise
|
|
934
|
+
with the new `--dialog accept|dismiss` (default `accept`). Each dialog is
|
|
935
|
+
printed under its step and listed in `logs.json` under `dialogs`. With
|
|
936
|
+
`--cdp`, only the tabs the run drives are touched.
|
|
937
|
+
- **`verirun record` asks which button you pressed.** Playwright's recorder notes
|
|
938
|
+
that a step opened a dialog but not the answer, so after you close the
|
|
939
|
+
browser `record` asks `[O]K / [c]ancel` for each such step and saves it on the
|
|
940
|
+
step.
|
|
941
|
+
- **`verirun map` shows the dialogs an element opens.** `--json` carries a
|
|
942
|
+
`dialogs` list per element (`type`, `message`, and `gates` when the handler
|
|
943
|
+
reads the answer). An early `if (!window.confirm(…)) return;` now shows up as
|
|
944
|
+
the `guardSource` of the backend calls after it, so you can see that Cancel
|
|
945
|
+
skips them. The summary counts them, `--bfs` prints them under their edge,
|
|
946
|
+
and `coverage.md` lists them.
|
|
947
|
+
- **`verirun workflow check` validates the `dialog` field.** After `map
|
|
948
|
+
--report`, it also warns about a step that clicks a dialog-opening element
|
|
949
|
+
without saying OK or Cancel.
|
|
950
|
+
|
|
666
951
|
### 0.2.4
|
|
667
952
|
|
|
668
953
|
- **`verirun map` reads the import aliases your project actually declares.**
|