@vosjs/cli 0.41.1 → 0.43.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 CHANGED
@@ -80,7 +80,7 @@ vos plan take --reuse # re-time that cut onto
80
80
 
81
81
  | Verb | Flags |
82
82
  | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
83
- | `record` | `--actions <file>` (or positional) `--url` `--out take` `--strict` `--dry-run` `--allow-wall` `--keep-frames` `--storage-state <file>` `--browser-arg=<switch>`... `--max-duration <s>` `--background <slug\|url\|none>` |
83
+ | `record` | `--actions <file>` (or positional) `--url` `--out take` `--strict` `--dry-run` `--allow-wall` `--keep-frames` `--storage-state <file>` `--header name=value`... `--browser-arg=<switch>`... `--max-duration <s>` `--background <slug\|url\|none>` |
84
84
  | `create` | The `record` flags plus the render flags (`--width` `--height` `--fps` `--format` `--parallel` `--draft` `--frame` `--set`), no `--range`. With `--strict` an incomplete recording exits 2 before anything is rendered |
85
85
  | `plan` | `--fresh` (discard the current plan) `--reuse` `--from <doc.json>` (defaults to `<take>/doc.prev.json`) `--style <doc.json\|take\|vosId>` `--with <doc.json\|take\|vosId>[@end\|@start\|@step:<id>\|@<seconds>]` (a template, repeatable) `--background` `--motion` (re-propose the motion) `--headline` `--kicker` `--launch` `--brand` `--music` `--entrance` `--transitions slide\|fade\|scale\|none` `--end-card on\|none\|<ref>` `--captions` `--clicks` `--release` |
86
86
  | `digest` | `--out <take>/digest` `--full 960` `--crop 640` (image long edges, the token budget) `--no-frames` `--transcript <file>` (Whisper-shaped segments merged as `said`) `--style <ref>` (report a reference document's style fields) |
@@ -90,6 +90,32 @@ vos plan take --reuse # re-time that cut onto
90
90
 
91
91
  **The wall check.** Once the first navigation settles, and before a frame is captured, `record`, `create` and `--dry-run` ask whether the recorder landed where it was sent. A take that met a sign-in instead is refused with exit 4 and a sentence (`asked for /dashboard, landed on /login: no session for app.acme.com`): the asked URL answered 401 or 403, the recorder was sent to an identity provider or a sign-in path, or the page is a sign-in form (one password field, or a one-time-code field) rendered in place. A redirect somewhere else with no sign-in in sight, which is what a site that shows strangers a public page looks like, is refused under `--strict` and in a rehearsal, and said as a warning otherwise. The check runs before a re-record clears anything, so a session that expired since the last take never costs the footage it failed to replace. The way past a wall is a session: `--storage-state <file>`, minted from the test auth the project already has wherever that exists. `--allow-wall` records the page anyway (a video OF a sign-in page is a legitimate take), and the take's `meta.wall` and its digest then say so.
92
92
 
93
+ **`setup`: the steps that run before the camera rolls.** A sign-in form, a cookie banner, the "choose your editor" modal, an onboarding tour: things a take must get past and must not show. `actions.json` takes `setup: [...]` beside `steps`, with the verbs `goto`, `click`, `type`, `press`, `wait`. They run after the first navigation and before a frame is captured, as plain actions with no cursor, no frames, no pace and nothing in `meta.steps`; then the recorder opens `url` again and the take begins where the setup left it. A `type` step's `text` may be `{ "env": "DEMO_PASSWORD" }`, read from the shell at run time and never logged or stored (the log names the field, never the value; a literal typed into a password field is refused by `validate`, because `actions.json` is committed and pushed with the take). A selector that never appears fails the take before anything is recorded (exit 2), because a take that begins at a half-finished sign-in is the wall by another name; rehearse the setup with `--dry-run` like everything else. This is rung 2 of the session ladder made scriptable: a local or self-hosted instance with a seeded user, no state file needed.
94
+
95
+ ```json
96
+ "setup": [
97
+ { "do": "goto", "url": "http://localhost:3000/login" },
98
+ { "do": "type", "selector": "#email", "text": "demo@acme.test" },
99
+ { "do": "type", "selector": "#password", "text": { "env": "DEMO_PASSWORD" } },
100
+ { "do": "press", "key": "Enter", "ms": 800 }
101
+ ]
102
+ ```
103
+
104
+ **`--header name=value`**, repeatable: a request header on every request the recording browser makes, the way past a preview deployment protected by a bypass header alone (`--header x-vercel-protection-bypass=$TOKEN`). The rehearsal's `Next:` line carries it.
105
+
106
+ **What the frame shows.** Getting past a login puts the account's own data in the picture, and asking for a demo account does not hold that line: a person asked to sign in signs in as themselves. So the recorder looks. After the page opens and after every step it reads the text visible in the viewport and reports the KIND of thing it saw and where, never the string: an email address (one on `example.com` or a `.test`, `.example`, `.invalid` or `.localhost` domain is demo data and is not reported), something shaped like an API key or a JWT, a card number that passes the Luhn check, a masked card's visible tail. They land in `meta.exposures[]` (`step`, `kind`, `selector`, `rect`, `seen`), in the `record` and `create` done events, at the end of a rehearsal (before anything is recorded), as warnings in `vos validate <take>`, and in the digest's `take.exposures`. They warn; they do not fail a take, because a product may legitimately show addresses. The `selector` reaches that element and no other, so it can be pasted into a mask.
107
+
108
+ **`mask`** in `actions.json` hides a selector BEFORE the first frame is captured and keeps it hidden across navigations and re-renders, so the real value is never in a frame, never in the recording, never pushed:
109
+
110
+ ```json
111
+ "mask": [
112
+ { "selector": "nav > span", "as": "text", "text": "jane@acme.test" },
113
+ { "selector": ".card-number" }
114
+ ]
115
+ ```
116
+
117
+ `as: "blur"` (the default) blurs the element; `as: "text"` swaps its words, which reads as a product where a blur reads as a redaction. Use `text` for IDENTIFIERS (an email, a name, an account id), never for product copy or numbers: the video stays true to the product. A form control is always blurred, since writing into an input would change what the app submits. A mask whose selector reached no element hid nothing, so it fails `--strict` and a rehearsal (exit 2) and is named; `meta.masks[]` records each mask's `hits`.
118
+
93
119
  **Rehearse before you record.** `vos record … --dry-run` runs every step against the real page, in order, because a later selector usually exists only after an earlier click. Nothing is captured and nothing is written: the pointer lands instead of travelling, every pause is cut to a beat, and the take directory beside it keeps its footage, its cut and its script exactly as they were (a real re-record moves `doc.json` aside; a rehearsal does not). Selector lookups keep their whole timeout, so a miss here is a miss in the take. It prints each step with the rect it resolved, in capture px, which are the rects a pin or `vos callout --step` reads, and exits 2 on any miss or a first load that never settled. Add `--dry-run` to the exact command you were about to run; `--storage-state` and `--browser-arg=` apply to it too, and the `Next:` line it prints carries them, so the command it hands you records what it rehearsed.
94
120
 
95
121
  **Digest first.** `vos digest <take>` is how an agent sees a recording without reading the video. It writes `digest/digest.json`: one moment per thing the cursor track says mattered (click clusters, typing sessions, scroll runs, dwells, idle gaps, head, tail, and frame-diff scene changes), each with source and output extents, a normalized `focus` and `rect` you can copy into a zoom span, per-second `activity`, and the planners' `proposed` span ids; plus one footage frame and a crop around the target per moment, and `sheet.png`, the contact sheet. Read the JSON, then the sheet, then a crop only where you must decide. `vos validate` then warns when a zoom does not contain what was clicked under it, and `vos frames --at-moments` renders the composed output at every moment so a still and its footage crop share an id.