@verirun/cli 0.1.0 → 0.2.1
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 +296 -34
- package/dist/cli.js +25 -16
- package/dist/gate.mjs +1 -1
- package/dist/graph.mjs +58 -0
- package/man/verirun.1 +194 -6
- package/package.json +9 -2
package/README.md
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# verirun
|
|
2
2
|
|
|
3
3
|
Record a browser workflow, replay it, and capture the Supabase, Vercel + Railway logs
|
|
4
|
-
your backend produced during the replay.
|
|
4
|
+
your backend produced during the replay. Plus `verirun map`: a static
|
|
5
|
+
interaction graph of your React/TypeScript app — every page, what you can click
|
|
6
|
+
on it, and which backend calls those clicks make — without running anything.
|
|
5
7
|
|
|
6
8
|
## Install
|
|
7
9
|
|
|
@@ -49,7 +51,7 @@ verirun logout # disconnect this machine
|
|
|
49
51
|
|
|
50
52
|
| | |
|
|
51
53
|
| --- | --- |
|
|
52
|
-
| `~/.verirun/config.json` | Holds the device token. Per user, not per project. |
|
|
54
|
+
| `~/.verirun/config.json` | Holds the device token. Per user, not per project. Restricted to your account (0600, or an `icacls` ACL on Windows). |
|
|
53
55
|
| `~/.verirun/state.json` | The last **server-signed lease** (Ed25519) plus a local tamper check. Editing it, or a lease not signed by Verirun's key, is ignored and forces a fresh online check. |
|
|
54
56
|
| `$VERIRUN_LICENSE_KEY` | A raw key for CI, used instead of `verirun login`. |
|
|
55
57
|
| `$VERIRUN_LICENSE_SERVER` | Point the CLI at a different server. |
|
|
@@ -72,6 +74,7 @@ machine past that is blocked until you release one from
|
|
|
72
74
|
fingerprint and use a seat; release the stale one to fix it.
|
|
73
75
|
|
|
74
76
|
`verirun --help`, `verirun --version`, `verirun log` and `verirun agent` do not require an account.
|
|
77
|
+
`verirun map` does.
|
|
75
78
|
|
|
76
79
|
---
|
|
77
80
|
|
|
@@ -96,8 +99,12 @@ Opens a headed browser. Perform the workflow by hand — click, type, navigate.
|
|
|
96
99
|
| `-f, --force` | Overwrite an existing workflow of the same name. Without it, recording onto an existing name errors. |
|
|
97
100
|
|
|
98
101
|
**Name rules.** `<name>` becomes a filename: letters, digits, dot, dash,
|
|
99
|
-
underscore; must start with a letter or digit; 64 chars max.
|
|
100
|
-
|
|
102
|
+
underscore; must start with a letter or digit; 64 chars max. Two Windows rules
|
|
103
|
+
are enforced on every platform, so a workflow you record stays usable for a
|
|
104
|
+
teammate who checks the repo out on Windows: no trailing dot (Windows drops it,
|
|
105
|
+
colliding with the bare name), and no reserved device stem — `con`, `prn`, `aux`,
|
|
106
|
+
`nul`, `com1`–`com9`, `lpt1`–`lpt9`, at any extension. Names are not sanitised —
|
|
107
|
+
an invalid name errors rather than being rewritten.
|
|
101
108
|
|
|
102
109
|
**Selectors.** Recording goes through Playwright's codegen engine, so each step
|
|
103
110
|
gets its stable selector — `getByTestId`, then `getByRole` with an accessible
|
|
@@ -128,6 +135,52 @@ is saved and the command says so.
|
|
|
128
135
|
|
|
129
136
|
---
|
|
130
137
|
|
|
138
|
+
### Recording or replaying as a signed-in user
|
|
139
|
+
|
|
140
|
+
Point both commands at a Chrome profile that is already logged in:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
verirun record checkout --channel chrome --user-data-dir "$HOME/.verirun-profile"
|
|
144
|
+
verirun run checkout --channel chrome --user-data-dir "$HOME/.verirun-profile"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
On Windows pass an absolute path instead — cmd and PowerShell don't expand `~`
|
|
148
|
+
inside an argument like this, and verirun never expands it either, so a literal
|
|
149
|
+
`~` just creates a directory called `~` and the run starts logged out:
|
|
150
|
+
|
|
151
|
+
```powershell
|
|
152
|
+
verirun run checkout --channel chrome --user-data-dir "$env:USERPROFILE\.verirun-profile"
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Create that profile once, by hand, and sign in there — identity providers block
|
|
156
|
+
sign-in in an automation-launched browser:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# macOS / Linux
|
|
160
|
+
google-chrome --user-data-dir="$HOME/.verirun-profile" --password-store=basic
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
```powershell
|
|
164
|
+
# Windows (PowerShell)
|
|
165
|
+
& "$env:ProgramFiles\Google\Chrome\Application\chrome.exe" `
|
|
166
|
+
--user-data-dir="$env:USERPROFILE\.verirun-profile"
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
`--password-store=basic` (plus `--use-mock-keychain` on macOS) is not optional:
|
|
170
|
+
Playwright always launches Chrome with those flags, and cookies written under
|
|
171
|
+
your OS keyring can't be decrypted without them — the run starts logged out with
|
|
172
|
+
no error. Both switches are Unix-only, so on Windows they're ignored — there just
|
|
173
|
+
create the profile as the same Windows user that runs verirun. **The Windows path
|
|
174
|
+
is untested:** if a run starts logged out despite a signed-in profile, that's the
|
|
175
|
+
first thing to suspect. On every platform, don't reuse your everyday Chrome
|
|
176
|
+
profile; use a dedicated one. Close the profile before recording or running, since
|
|
177
|
+
Chrome locks it.
|
|
178
|
+
|
|
179
|
+
To check it took, reopen the profile on its own — if that window is signed in,
|
|
180
|
+
verirun will be too.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
131
184
|
## `verirun run <name>`
|
|
132
185
|
|
|
133
186
|
```bash
|
|
@@ -140,6 +193,7 @@ and writes `.verirun/runs/<name>-<timestamp>/logs.json`.
|
|
|
140
193
|
|
|
141
194
|
| Flag | Meaning |
|
|
142
195
|
| --- | --- |
|
|
196
|
+
| `--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. |
|
|
143
197
|
| `--headed` | Show the browser window instead of running headless. |
|
|
144
198
|
| `--timeout <ms>` | Per-action timeout, milliseconds. Non-negative. Defaults to Playwright's 30000. |
|
|
145
199
|
| `--channel <name>` | Replay in an installed browser: `chrome`, `msedge`, … Overrides the channel saved in the workflow. Chromium family only. |
|
|
@@ -265,28 +319,151 @@ with `railway.deploymentId` in config.) Logs are already scoped to that service
|
|
|
265
319
|
+ environment, so there's no separate project filter. Already connected →
|
|
266
320
|
one-line status.
|
|
267
321
|
|
|
268
|
-
**`verirun log vercel`** —
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
322
|
+
**`verirun log vercel`** — same shape as the other two: it opens
|
|
323
|
+
`https://vercel.com/account/settings/tokens`, you paste a token, and it picks
|
|
324
|
+
the project. If the repo has a `.vercel/project.json` (i.e. you have run
|
|
325
|
+
`vercel link`), the project and team are read from it and **you are asked
|
|
326
|
+
nothing else**; otherwise it lists your teams and projects and you choose. It
|
|
327
|
+
then resolves the newest ready production deployment and reads its runtime logs
|
|
328
|
+
to confirm the token works. No tunnel, no drain, no second terminal.
|
|
329
|
+
|
|
330
|
+
On each run it re-resolves the newest ready deployment, so a redeploy doesn't
|
|
331
|
+
break the config. Pin one with `vercel.deploymentId`, or read preview
|
|
332
|
+
deployments instead with `vercel.environment: "preview"`.
|
|
333
|
+
|
|
334
|
+
<details>
|
|
335
|
+
<summary><b>Drain mode</b> (<code>--drain</code>) — the old push-based setup</summary>
|
|
336
|
+
|
|
337
|
+
Vercel's runtime-log API is the easy path, but if it isn't available to you, the
|
|
338
|
+
original Log Drain flow is still there under `verirun log vercel --drain`: a
|
|
339
|
+
tunnel, a local listener, and a drain pointed at it (4-step checklist → tunnel →
|
|
340
|
+
`--listen` → add the drain with **Sources: Edge + Serverless, Format: JSON,
|
|
341
|
+
Endpoint: `<tunnel>/drain`** → paste the signing secret). Config keys
|
|
342
|
+
`listenerPort`, `listenerPath`, `drainSecret`, `drainGraceMs`, `project` belong
|
|
343
|
+
to this mode only. verirun uses drain mode whenever `vercel.token` is absent,
|
|
344
|
+
so the two never collide.
|
|
345
|
+
|
|
346
|
+
</details>
|
|
276
347
|
|
|
277
348
|
Non-interactive shells get the env/config values to set instead of a prompt.
|
|
278
349
|
|
|
279
350
|
| Flag | Meaning |
|
|
280
351
|
| --- | --- |
|
|
281
352
|
| `--reconnect` | Run the connect flow again and replace what was saved. Any source. |
|
|
282
|
-
| `--test` |
|
|
283
|
-
| `--
|
|
353
|
+
| `--test` | Query the last 5 minutes and print what came back, or the error. Needs a connected source. Non-zero exit if it errored. |
|
|
354
|
+
| `--drain` | **`vercel` only.** Set up the old push-based Log Drain instead of the API. |
|
|
355
|
+
| `--listen` | **`vercel` drain mode only.** Start the Log Drain listener now and keep it running until Ctrl+C, printing each delivery as `timestamp level stream message`. Binds `listenerPort` + `listenerPath` from config (defaults `4319` / `/drain`). |
|
|
284
356
|
|
|
285
357
|
An unknown `<source>` errors. A flag meant for another source is ignored.
|
|
286
358
|
Each `verirun log <source>` connect flow *writes* its own block of
|
|
287
|
-
`.verirun/config.json
|
|
288
|
-
|
|
289
|
-
|
|
359
|
+
`.verirun/config.json`, restricted to your user account — mode 0600 on macOS and
|
|
360
|
+
Linux, and an `icacls` ACL granting only you on Windows, since mode bits mean
|
|
361
|
+
nothing there. If that cannot be applied the flow warns rather than leaving you
|
|
362
|
+
to assume the token is protected. The overview is read-only. A secret supplied via
|
|
363
|
+
`$VERIRUN_SUPABASE_ACCESS_TOKEN` / `$VERIRUN_VERCEL_TOKEN` /
|
|
364
|
+
`$VERIRUN_VERCEL_DRAIN_SECRET` / `$VERIRUN_RAILWAY_TOKEN` is never written to
|
|
365
|
+
the file.
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## `verirun map`
|
|
370
|
+
|
|
371
|
+
Reads this repository's React/TypeScript source and builds an **interaction
|
|
372
|
+
graph**: one node per page, the interactive elements on it, the pages each one
|
|
373
|
+
navigates to, and the backend calls each one makes. Nothing is executed — no
|
|
374
|
+
browser, no server, no recording.
|
|
375
|
+
|
|
376
|
+
```bash
|
|
377
|
+
verirun map # per-page summary
|
|
378
|
+
verirun map --json # the whole graph
|
|
379
|
+
verirun map --report # graph + coverage.md into .verirun/map
|
|
380
|
+
verirun map --bfs /account --depth 2 # what is reachable from one page
|
|
381
|
+
verirun map --reach # how much of each page was captured
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
Routes come from a react-router `<Routes>` declaration **or** a Next.js App
|
|
385
|
+
Router `app/**/page.tsx` tree (`[id]` → `:id`, route groups dropped, `layout.tsx`
|
|
386
|
+
applied to its subtree). Components a page renders from another file are
|
|
387
|
+
followed, so a page whose real UI lives in a client component is not reported
|
|
388
|
+
empty. Import aliases are read from `tsconfig.json`; add more with
|
|
389
|
+
`--alias @/=src`.
|
|
390
|
+
|
|
391
|
+
```
|
|
392
|
+
$ verirun map
|
|
393
|
+
6 pages · 6 backend effects · 31 edges (40 files)
|
|
394
|
+
|
|
395
|
+
/ — Page, 0 element(s), 10 nav, 0 effect
|
|
396
|
+
/account — AccountPage, 5 element(s), 1 nav, 4 effect
|
|
397
|
+
/login — LoginPage, 2 element(s), 2 nav, 3 effect
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
`--bfs` takes a route path (`/account`), a page id (`page:/account`) or a page
|
|
401
|
+
component name, and reports each node once at its shortest distance, with the
|
|
402
|
+
element that gets you there:
|
|
403
|
+
|
|
404
|
+
```
|
|
405
|
+
$ verirun map --bfs /account --depth 2
|
|
406
|
+
page:/account
|
|
407
|
+
└─ nav "verirun" → page:/
|
|
408
|
+
└─ effect "revoke" [if !(tokens.length === 0)] → effect:POST ?
|
|
409
|
+
└─ nav "Log in" → page:/login
|
|
410
|
+
# frontier at depth 2: page:/login, page:/signup
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
**Limits, honestly.** It is static analysis: a target computed at runtime shows
|
|
414
|
+
as `unresolved`, an endpoint passed through a variable as `?`, and Supabase
|
|
415
|
+
`.auth.*` / `.storage.*` calls are not yet classified as effects. `--reach`
|
|
416
|
+
tells you what fraction of each page it actually attached, so you can see when
|
|
417
|
+
it is missing something rather than guessing.
|
|
418
|
+
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
## `verirun workflow check <name>`
|
|
422
|
+
|
|
423
|
+
Validates a workflow file without running it — JSON shape, schema version, known
|
|
424
|
+
actions, a `selector` where one is needed, the required `params` per action, and
|
|
425
|
+
warnings for the things that replay tolerates but you probably didn't mean
|
|
426
|
+
(a bare `role=button` that matches five elements, an `assert*` step that replay
|
|
427
|
+
skips, a first step that isn't `navigate`, and a `navigate` *after* the first
|
|
428
|
+
step — walking the app by URL skips the UI, so a dead link or a button that
|
|
429
|
+
stopped submitting still passes).
|
|
430
|
+
|
|
431
|
+
```bash
|
|
432
|
+
verirun workflow check login
|
|
433
|
+
verirun workflow check login --json # machine-readable findings
|
|
434
|
+
verirun workflow check ./some/file.json
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
Static only: it never opens a browser, so it cannot tell you whether a selector
|
|
438
|
+
matches the live page. Only `verirun run` can. Non-zero exit if anything is an
|
|
439
|
+
error.
|
|
440
|
+
|
|
441
|
+
This exists because a workflow doesn't have to come from `record`. `verirun map
|
|
442
|
+
--json` gives every element a `selector`, a `selectorConfidence`
|
|
443
|
+
(`high`/`medium`/`low`) and a suggested `action`, which is enough for you — or
|
|
444
|
+
an agent — to write `.verirun/workflows/<name>.json` directly:
|
|
445
|
+
|
|
446
|
+
```jsonc
|
|
447
|
+
{
|
|
448
|
+
"schemaVersion": 1,
|
|
449
|
+
"name": "login",
|
|
450
|
+
"createdAt": "2026-09-20T00:00:00.000Z",
|
|
451
|
+
"browser": "chromium",
|
|
452
|
+
"steps": [
|
|
453
|
+
{ "index": 0, "action": "navigate", "params": { "url": "https://app.example.com/login" }, "signals": [] },
|
|
454
|
+
{ "index": 1, "action": "fill", "selector": "role=textbox[name=\"Email\"i]", "params": { "text": "ada@example.com" }, "signals": [] },
|
|
455
|
+
{ "index": 2, "action": "click", "selector": "role=button[name=\"Log in\"i]", "params": {}, "signals": [] }
|
|
456
|
+
]
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
Actions and required `params`: `navigate` (`url`, absolute), `click` /
|
|
461
|
+
`dblclick`, `fill` (`text`), `press` (`key`), `check` / `uncheck`, `select`
|
|
462
|
+
(`values`), `setInputFiles` (`files`). Everything but `navigate` needs a
|
|
463
|
+
`selector`, which is handed to `page.locator()` verbatim.
|
|
464
|
+
|
|
465
|
+
A recorded workflow is ground truth; a written one is a guess until `run`
|
|
466
|
+
confirms it. Don't overwrite a recording with a generated file — use a new name.
|
|
290
467
|
|
|
291
468
|
---
|
|
292
469
|
|
|
@@ -301,8 +478,16 @@ workflows, recent runs.
|
|
|
301
478
|
```bash
|
|
302
479
|
verirun agent > .verirun/AGENT.md # save it as context for your agent
|
|
303
480
|
verirun agent --json # machine-readable form
|
|
481
|
+
verirun agent --skill --install # .claude/skills/verirun/SKILL.md
|
|
304
482
|
```
|
|
305
483
|
|
|
484
|
+
`--skill` emits the same knowledge as a **Claude Code skill** — YAML frontmatter
|
|
485
|
+
with a `description` that tells Claude when to load it, then a shorter body
|
|
486
|
+
aimed at deciding *which* command to reach for. With `--install` it writes
|
|
487
|
+
`.claude/skills/verirun/SKILL.md` in the repo, and Claude Code loads it on its
|
|
488
|
+
own whenever a task looks like app testing. Re-run it after upgrading verirun;
|
|
489
|
+
the file is generated, not hand-maintained.
|
|
490
|
+
|
|
306
491
|
Paste the output into `CLAUDE.md`, `.cursorrules`, an `AGENTS.md`, or pipe it
|
|
307
492
|
straight into a prompt. No account needed. The agent then knows to run
|
|
308
493
|
`verirun run <name>`, read exit code + `.verirun/runs/<name>-<newest>/logs.json`,
|
|
@@ -364,11 +549,18 @@ it are sent only to the respective provider's own API.
|
|
|
364
549
|
| `supabase.projectRef` | — | Supabase project ref. Required for Supabase capture. |
|
|
365
550
|
| `supabase.accessToken` | — | Personal access token. Required for Supabase capture. |
|
|
366
551
|
| `supabase.sources` | `postgres_logs`, `edge_logs`, `auth_logs` | Log sources to query, one request each. |
|
|
367
|
-
| `vercel.
|
|
368
|
-
| `vercel.
|
|
369
|
-
| `vercel.
|
|
370
|
-
| `vercel.
|
|
371
|
-
| `vercel.
|
|
552
|
+
| `vercel.token` | — | Vercel API token (vercel.com/account/settings/tokens). Its presence is what selects API mode over drain mode. |
|
|
553
|
+
| `vercel.projectId` | — | `prj_…` id of the project to read logs from. Required in API mode. |
|
|
554
|
+
| `vercel.teamId` | — | `team_…` id, when the project belongs to a team. |
|
|
555
|
+
| `vercel.deploymentId` | — | Pin log capture to one deployment instead of the newest ready one. |
|
|
556
|
+
| `vercel.environment` | `production` | Which target to resolve the newest deployment from: `production` or `preview`. |
|
|
557
|
+
| `vercel.readMs` | `8000` | How long to read the runtime-log stream before giving up. |
|
|
558
|
+
| `vercel.tailGraceMs` | `3000` | Extra window past the run's end to keep, for lines Vercel flushes late. |
|
|
559
|
+
| `vercel.listenerPort` | `4319` | *Drain mode.* Port the local Log Drain listener binds during a run. |
|
|
560
|
+
| `vercel.listenerPath` | `/drain` | *Drain mode.* Path the listener accepts POSTs on. |
|
|
561
|
+
| `vercel.drainSecret` | — | *Drain mode.* If set, deliveries with a missing or wrong `x-vercel-signature` (HMAC-SHA1 of the body) are rejected. |
|
|
562
|
+
| `vercel.drainGraceMs` | `3000` | *Drain mode.* How long collection waits after replay for trailing drain batches. |
|
|
563
|
+
| `vercel.project` | — | *Drain mode.* Keep only deliveries whose `projectName` or `projectId` equals this (a drain carries the whole team's logs). Unset = keep all. If every delivery is filtered out, `run` warns. |
|
|
372
564
|
| `railway.token` | — | Railway API token (Account/Workspace, from railway.com/account/tokens). Required for Railway capture. |
|
|
373
565
|
| `railway.deploymentId` | — | Pin log capture to one deployment. Overrides the project/environment/service trio. |
|
|
374
566
|
| `railway.projectId` / `railway.environmentId` / `railway.serviceId` | — | Together, the target for which the newest deployment is resolved each run (so a redeploy doesn't need a config change). |
|
|
@@ -379,7 +571,8 @@ it are sent only to the respective provider's own API.
|
|
|
379
571
|
| Variable | Replaces |
|
|
380
572
|
| --- | --- |
|
|
381
573
|
| `VERIRUN_SUPABASE_ACCESS_TOKEN` | `supabase.accessToken` |
|
|
382
|
-
| `
|
|
574
|
+
| `VERIRUN_VERCEL_TOKEN` | `vercel.token` |
|
|
575
|
+
| `VERIRUN_VERCEL_DRAIN_SECRET` | `vercel.drainSecret` (drain mode) |
|
|
383
576
|
| `VERIRUN_RAILWAY_TOKEN` | `railway.token` |
|
|
384
577
|
|
|
385
578
|
---
|
|
@@ -387,8 +580,8 @@ it are sent only to the respective provider's own API.
|
|
|
387
580
|
## Log capture
|
|
388
581
|
|
|
389
582
|
A source appears only when its config block is present. Run `verirun log
|
|
390
|
-
<source>` for guided setup
|
|
391
|
-
|
|
583
|
+
<source>` for guided setup and `verirun log <source> --test` to check a
|
|
584
|
+
connected one against the last 5 minutes.
|
|
392
585
|
|
|
393
586
|
**Supabase (pull).** After replay, one query per configured source goes to the
|
|
394
587
|
Management API's `analytics/endpoints/logs.all` endpoint, scoped to the run
|
|
@@ -402,17 +595,27 @@ either `deploymentId` or `projectId` + `environmentId` + `serviceId` (the newest
|
|
|
402
595
|
deployment of that trio is resolved first). Errors are warned about; the run
|
|
403
596
|
continues. Logs are already scoped to one service + environment.
|
|
404
597
|
|
|
405
|
-
**Vercel (
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
598
|
+
**Vercel (pull).** After replay, verirun resolves the project's newest ready
|
|
599
|
+
deployment (or `vercel.deploymentId`) and reads
|
|
600
|
+
`/v1/projects/<projectId>/deployments/<deploymentId>/runtime-logs`, keeping the
|
|
601
|
+
lines whose timestamp falls in the run window plus `tailGraceMs`. Needs `token`
|
|
602
|
+
and `projectId`. The endpoint streams and stays open to tail live lines, so the
|
|
603
|
+
read stops once the stream has been quiet for a moment, or after `readMs`.
|
|
604
|
+
Errors are warned about; the run continues. Retention is Vercel's, not ours —
|
|
605
|
+
on Hobby, runtime logs are short-lived, which is fine because collection happens
|
|
606
|
+
seconds after the run.
|
|
412
607
|
|
|
413
|
-
|
|
608
|
+
<details>
|
|
609
|
+
<summary><b>Vercel drain mode</b> (only when <code>vercel.token</code> is unset)</summary>
|
|
414
610
|
|
|
415
|
-
|
|
611
|
+
During a run, verirun runs a local HTTP listener on `listenerPort` +
|
|
612
|
+
`listenerPath`; whatever the Log Drain POSTs while it is up is kept. It accepts
|
|
613
|
+
both JSON-array and NDJSON bodies, echoes the `x-vercel-verify` challenge (so
|
|
614
|
+
Vercel can confirm the endpoint), and — if `drainSecret` is set — rejects
|
|
615
|
+
unsigned or wrongly signed deliveries. After replay, collection waits
|
|
616
|
+
`drainGraceMs` for late batches, then stops the listener.
|
|
617
|
+
|
|
618
|
+
One-time setup (`verirun log vercel --drain` walks you through it):
|
|
416
619
|
|
|
417
620
|
1. Expose the listener port to the internet — `ngrok http 4319`, a Cloudflare
|
|
418
621
|
Tunnel, etc. Note the public URL.
|
|
@@ -428,3 +631,62 @@ Vercel must be able to reach your listener, so this is manual:
|
|
|
428
631
|
|
|
429
632
|
A free ngrok URL changes each session; a reserved hostname is worth it if you
|
|
430
633
|
run this often.
|
|
634
|
+
|
|
635
|
+
</details>
|
|
636
|
+
|
|
637
|
+
---
|
|
638
|
+
|
|
639
|
+
## Changelog
|
|
640
|
+
|
|
641
|
+
### 0.2.1
|
|
642
|
+
|
|
643
|
+
Windows support pass. Nothing in the CLI was Unix-only by design, but several
|
|
644
|
+
paths had never been exercised on Windows.
|
|
645
|
+
|
|
646
|
+
- **Workflow names** reject the two spellings Windows cannot store: a trailing
|
|
647
|
+
dot (Windows drops it, colliding with the bare name) and a reserved device
|
|
648
|
+
stem — `con`, `prn`, `aux`, `nul`, `com1`–`com9`, `lpt1`–`lpt9`, at any
|
|
649
|
+
extension. Enforced on every platform, so a workflow recorded on macOS or
|
|
650
|
+
Linux stays usable for a teammate on Windows.
|
|
651
|
+
- **Config permissions on Windows** — `.verirun/config.json`, `~/.verirun/` and
|
|
652
|
+
the files in it are now restricted with an `icacls` ACL granting only the
|
|
653
|
+
current user. Mode bits are not an access control on Windows, so these held
|
|
654
|
+
provider tokens and the device token on whatever ACL they inherited. A
|
|
655
|
+
connect flow that cannot lock the file down now warns instead of implying
|
|
656
|
+
protection it did not get.
|
|
657
|
+
- **`verirun log supabase`** can find the `supabase` CLI on Windows, where it
|
|
658
|
+
is a `.cmd` shim that needs a shell to launch. It previously always fell
|
|
659
|
+
through to the manual project-ref prompt.
|
|
660
|
+
- **Hardware fingerprint** filters Windows virtual adapters (Hyper-V, WSL,
|
|
661
|
+
VMware, VirtualBox, VPN and loopback), which were being counted as physical
|
|
662
|
+
and could shift the machine id — consuming an extra seat against the license.
|
|
663
|
+
- Docs: `--user-data-dir` needs an absolute path on Windows, since neither cmd,
|
|
664
|
+
PowerShell nor verirun expands `~`.
|
|
665
|
+
|
|
666
|
+
**Not verified on Windows.** These fixes are from reading the code and the
|
|
667
|
+
platform rules, not from a Windows test run. The signed-in Chrome profile path
|
|
668
|
+
in particular is untested there.
|
|
669
|
+
|
|
670
|
+
### 0.2.0
|
|
671
|
+
|
|
672
|
+
- **`verirun map`** — static interaction graph of a React/TypeScript app:
|
|
673
|
+
every page, the interactive elements on it, where they navigate, and the
|
|
674
|
+
backend calls they make. No browser, no recording. `--json`, `--report`,
|
|
675
|
+
`--reach`, `--bfs <node> --depth N`. Routes come from react-router
|
|
676
|
+
`<Routes>` or a Next.js `app/**/page.tsx` tree.
|
|
677
|
+
- **`verirun workflow check`** — validate a workflow file without running it.
|
|
678
|
+
Together with the selectors `map` emits, a workflow can now be written by
|
|
679
|
+
hand (or by an agent) instead of recorded.
|
|
680
|
+
- **Vercel logs without a tunnel** — `verirun log vercel` is now a token and a
|
|
681
|
+
project, pulled from Vercel's runtime-log API. The old Log Drain flow
|
|
682
|
+
remains under `--drain` and is still used automatically for existing configs.
|
|
683
|
+
- **`verirun agent --skill --install`** — writes `.claude/skills/verirun/SKILL.md`
|
|
684
|
+
so Claude Code picks the tool up on its own.
|
|
685
|
+
- **Watchable replays** — `--headed` now paces actions (500ms), tunable with
|
|
686
|
+
`--slow-mo <ms>`.
|
|
687
|
+
- `verirun record`/`run` document how to use a signed-in Chrome profile.
|
|
688
|
+
|
|
689
|
+
### 0.1.0
|
|
690
|
+
|
|
691
|
+
- `record`, `run`, `log` (Supabase / Vercel drain / Railway), `agent`, and the
|
|
692
|
+
account commands `login` / `logout` / `whoami`.
|