versioncam 0.5.1 → 0.5.2
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/CHANGELOG.md +23 -0
- package/README.md +44 -2
- package/dist/cli/commands/doctor.js +14 -11
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/install.d.ts +45 -6
- package/dist/cli/commands/install.js +78 -18
- package/dist/cli/commands/install.js.map +1 -1
- package/dist/cli/commands/login.js +5 -0
- package/dist/cli/commands/login.js.map +1 -1
- package/dist/cli/commands/preview.js +6 -0
- package/dist/cli/commands/preview.js.map +1 -1
- package/dist/cli/usage.d.ts +1 -1
- package/dist/cli/usage.js +2 -1
- package/dist/cli/usage.js.map +1 -1
- package/package.json +4 -3
- package/plugin/.claude-plugin/plugin.json +7 -1
- package/plugin/README.md +11 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,29 @@ and versions follow [semantic versioning](https://semver.org/). While the
|
|
|
6
6
|
major version is 0, a minor version may change the config or the clip DSL,
|
|
7
7
|
and its entry here says how.
|
|
8
8
|
|
|
9
|
+
## 0.5.2 (2026-10-29)
|
|
10
|
+
|
|
11
|
+
A patch version: the config and the clip DSL are as they were. The README
|
|
12
|
+
now speaks to coding agents, the skill installs from the repository's own
|
|
13
|
+
marketplace, and the browser install is a third of what it was.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- The README has a section for coding agents: when versioncam fits, the exact
|
|
18
|
+
commands, and what to tell the person about the licence. Bugs and
|
|
19
|
+
questions go to github.com/versioncam/versioncam, where the source is
|
|
20
|
+
public since 2026-10-28.
|
|
21
|
+
- The skill installs as a Claude Code plugin from that repository's own
|
|
22
|
+
marketplace, `/plugin install versioncam --marketplace versioncam/versioncam`,
|
|
23
|
+
beside `versioncam init` and `--plugin-dir`; the plugin's manifest carries
|
|
24
|
+
the package's version.
|
|
25
|
+
- `versioncam install` fetches the headless shell alone, the Chromium that
|
|
26
|
+
records: 190 MB on a Mac, where both builds were 528. `login` and `preview`,
|
|
27
|
+
the two commands that open a window, fetch the full browser the first time
|
|
28
|
+
they run and say so first; `versioncam install --full` fetches both at once.
|
|
29
|
+
`doctor` reports the shell as `chromium`, and under `window` whether the
|
|
30
|
+
full browser is there, which is never a failure.
|
|
31
|
+
|
|
9
32
|
## 0.5.1 (2026-10-11)
|
|
10
33
|
|
|
11
34
|
A patch version: two clips that came out wrong now record and render as
|
package/README.md
CHANGED
|
@@ -43,6 +43,12 @@ Playwright exactly, because a new Chromium changes every captured pixel. Your
|
|
|
43
43
|
app may have a Playwright of its own at another version, and
|
|
44
44
|
`npx playwright install` fetches that one's Chromium.
|
|
45
45
|
|
|
46
|
+
`versioncam install` fetches the headless shell, the Chromium that records:
|
|
47
|
+
190 MB on a Mac. `login` and `preview` open a window, which needs the full
|
|
48
|
+
browser, 340 MB more; they fetch it the first time they run, or
|
|
49
|
+
`npx versioncam install --full` fetches both now, for a machine that will be
|
|
50
|
+
offline then.
|
|
51
|
+
|
|
46
52
|
### In CI
|
|
47
53
|
|
|
48
54
|
The same install, then `check`. It records every clip and fails the job on the
|
|
@@ -66,6 +72,40 @@ job in the Playwright image for the version versioncam pins,
|
|
|
66
72
|
`mcr.microsoft.com/playwright:v1.59.1-noble`. Chromium and its libraries are
|
|
67
73
|
already installed there.
|
|
68
74
|
|
|
75
|
+
## If you are a coding agent
|
|
76
|
+
|
|
77
|
+
You were probably asked for a product demo, a README or landing-page video, a
|
|
78
|
+
GIF, or docs screenshots that stay current. versioncam fits when the subject
|
|
79
|
+
is a web app that starts from a command and whose controls can be reached by
|
|
80
|
+
test id, role, label or placeholder, on Node 22 or later, on macOS or Linux.
|
|
81
|
+
It does not fit native mobile apps, terminal demos (VHS does those),
|
|
82
|
+
interactive HTML tours, narrated screencasts, or a UI that will never change
|
|
83
|
+
again.
|
|
84
|
+
|
|
85
|
+
Install it in the directory that holds the app's `package.json`, with exactly
|
|
86
|
+
these commands:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
npm i -D versioncam
|
|
90
|
+
npx versioncam install
|
|
91
|
+
npx versioncam init
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Use `versioncam install`, never `npx playwright install`: versioncam pins its
|
|
95
|
+
Playwright exactly, and the app's own Playwright, if it has one, fetches a
|
|
96
|
+
different Chromium. Then `npx versioncam doctor`, and read `npx versioncam dsl`
|
|
97
|
+
before writing a clip. If your host runs skills,
|
|
98
|
+
`/versioncam "<what the clip should show>"` does the rest, including setting
|
|
99
|
+
the repository up on its first run; otherwise `init --into <dir>` puts the
|
|
100
|
+
skill where your host reads it, and the clips are TypeScript you can write
|
|
101
|
+
from `inspect` and `measure`. Target by test id or role, never by coordinates.
|
|
102
|
+
Do not edit files while a clip records. Add `.versioncam/` to `.gitignore`
|
|
103
|
+
and commit the clip. In CI, `uses: versioncam/action@v1` after `npm ci`
|
|
104
|
+
records every clip and fails the job, with a comment on the pull request,
|
|
105
|
+
when one no longer matches the app. Tell the person what the licence is
|
|
106
|
+
(FSL-1.1-ALv2: free in their own CI, source-available, Apache 2.0 after two
|
|
107
|
+
years) and that the hosted layer at version.cam is optional and separate.
|
|
108
|
+
|
|
69
109
|
## Configure
|
|
70
110
|
|
|
71
111
|
`versioncam.config.ts` sits beside your clips. It is the one place your app
|
|
@@ -290,8 +330,9 @@ prints the same list.
|
|
|
290
330
|
Once per machine, and once per repository.
|
|
291
331
|
|
|
292
332
|
```
|
|
293
|
-
versioncam install the Chromium this version of versioncam records with
|
|
333
|
+
versioncam install the headless Chromium this version of versioncam records with
|
|
294
334
|
--with-deps and its system libraries (Linux CI)
|
|
335
|
+
--full and the full browser, which login and preview open
|
|
295
336
|
versioncam init install the authoring skill into .claude/
|
|
296
337
|
--into <dir> into <dir>/versioncam/ instead, for another host
|
|
297
338
|
--force overwrite files that are already there
|
|
@@ -904,7 +945,8 @@ The words these pages use in a particular sense.
|
|
|
904
945
|
## Help
|
|
905
946
|
|
|
906
947
|
Bugs, questions, and apps it cannot record go to the issue tracker at
|
|
907
|
-
[github.com/versioncam/versioncam
|
|
948
|
+
[github.com/versioncam/versioncam](https://github.com/versioncam/versioncam/issues),
|
|
949
|
+
where the source is.
|
|
908
950
|
A clip that will not reproduce is easiest to help with alongside the two
|
|
909
951
|
pictures `versioncam stability` saves.
|
|
910
952
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
1
|
+
import { browserPaths } from "./install.js";
|
|
3
2
|
import { ffmpegStatus } from "../../render/ffmpeg.js";
|
|
4
3
|
import { ensureApp, probe } from "../../app-server.js";
|
|
5
4
|
import { NO_CONFIG, findConfigFile, loadConfig, loadSceneIds, } from "../../loader.js";
|
|
@@ -112,19 +111,23 @@ export async function doctor() {
|
|
|
112
111
|
detail: `v${process.versions.node}`,
|
|
113
112
|
fix: "Install Node 22 or newer.",
|
|
114
113
|
});
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
catch {
|
|
120
|
-
chromiumPath = "";
|
|
121
|
-
}
|
|
114
|
+
// The headless shell is what records; `install` fetches it and nothing
|
|
115
|
+
// else. The full browser only `login` and `preview` need, and they fetch it
|
|
116
|
+
// themselves, so its absence is reported and is not a failure.
|
|
117
|
+
const browsers = browserPaths();
|
|
122
118
|
checks.push({
|
|
123
119
|
name: "chromium",
|
|
124
|
-
ok:
|
|
125
|
-
detail:
|
|
120
|
+
ok: browsers.shell !== null,
|
|
121
|
+
detail: browsers.shell ?? "not installed",
|
|
126
122
|
fix: "npx versioncam install",
|
|
127
123
|
});
|
|
124
|
+
checks.push({
|
|
125
|
+
name: "window",
|
|
126
|
+
ok: true,
|
|
127
|
+
detail: browsers.full
|
|
128
|
+
? `full Chromium at ${browsers.full}`
|
|
129
|
+
: "full Chromium not fetched yet; login and preview fetch it on first use, or `npx versioncam install --full`",
|
|
130
|
+
});
|
|
128
131
|
const { ffmpeg, ffprobe } = ffmpegStatus();
|
|
129
132
|
checks.push({
|
|
130
133
|
name: "ffmpeg",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAEvD,OAAO,EACL,SAAS,EACT,cAAc,EACd,UAAU,EACV,YAAY,GACb,MAAM,iBAAiB,CAAC;AAIzB,MAAM,WAAW,GACf,yFAAyF,CAAC;AAE5F;;;;;;;;;;;;;;GAcG;AACH,KAAK,UAAU,QAAQ,CAAC,GAAW;IACjC,IAAI,MAAsB,CAAC;IAC3B,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,IAAI,EAAE,KAAK;YACX,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,wBAAyB,KAAe,CAAC,OAAO,EAAE;YAC1D,GAAG,EAAE,6DAA6D;SACnE,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC3C,OAAO,MAAM,CAAC,EAAE;YACd,CAAC,CAAC;gBACE,IAAI,EAAE,KAAK;gBACX,EAAE,EAAE,IAAI;gBACR,MAAM,EAAE,sBAAsB,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,MAAM,GAAG;aACvE;YACH,CAAC,CAAC;gBACE,IAAI,EAAE,KAAK;gBACX,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,KAAK,MAAM,CAAC,MAAM,EAAE;gBAC7C,GAAG,EAAE,WAAW;aACjB,CAAC;IACR,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;QACpC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QACjB,OAAO;YACL,IAAI,EAAE,KAAK;YACX,EAAE,EAAE,IAAI;YACR,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM;SACnE,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,oEAAoE;QACpE,gDAAgD;QAChD,MAAM,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAI,KAAe,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC9D,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IACzE,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,KAAK,UAAU,WAAW,CAAC,GAAW;IACpC,IAAI,MAAsB,CAAC;IAC3B,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEhC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;QACvC,OAAO;YACL,IAAI,EAAE,QAAQ;YACd,EAAE,EAAE,IAAI;YACR,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,cAAc,EAAE;SAChE,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,uEAAuE;QACvE,MAAM,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAI,KAAe,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC9D,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IAC5E,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM;IAC1B,MAAM,MAAM,GAAY,EAAE,CAAC;IAE3B,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1D,MAAM,CAAC,IAAI,CAAC;QACV,IAAI,EAAE,MAAM;QACZ,EAAE,EAAE,KAAK,IAAI,EAAE;QACf,MAAM,EAAE,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE;QACnC,GAAG,EAAE,2BAA2B;KACjC,CAAC,CAAC;IAEH,uEAAuE;IACvE,4EAA4E;IAC5E,+DAA+D;IAC/D,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;IAChC,MAAM,CAAC,IAAI,CAAC;QACV,IAAI,EAAE,UAAU;QAChB,EAAE,EAAE,QAAQ,CAAC,KAAK,KAAK,IAAI;QAC3B,MAAM,EAAE,QAAQ,CAAC,KAAK,IAAI,eAAe;QACzC,GAAG,EAAE,wBAAwB;KAC9B,CAAC,CAAC;IACH,MAAM,CAAC,IAAI,CAAC;QACV,IAAI,EAAE,QAAQ;QACd,EAAE,EAAE,IAAI;QACR,MAAM,EAAE,QAAQ,CAAC,IAAI;YACnB,CAAC,CAAC,oBAAoB,QAAQ,CAAC,IAAI,EAAE;YACrC,CAAC,CAAC,4GAA4G;KACjH,CAAC,CAAC;IAEH,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,YAAY,EAAE,CAAC;IAC3C,MAAM,CAAC,IAAI,CAAC;QACV,IAAI,EAAE,QAAQ;QACd,EAAE,EAAE,MAAM,KAAK,IAAI;QACnB,MAAM,EAAE,MAAM,IAAI,WAAW;QAC7B,GAAG,EAAE,8CAA8C;KACpD,CAAC,CAAC;IACH,MAAM,CAAC,IAAI,CAAC;QACV,IAAI,EAAE,SAAS;QACf,EAAE,EAAE,OAAO,KAAK,IAAI;QACpB,MAAM,EAAE,OAAO,IAAI,WAAW;QAC9B,GAAG,EAAE,0DAA0D;KAChE,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7C,MAAM,CAAC,IAAI,CAAC;QACV,IAAI,EAAE,QAAQ;QACd,EAAE,EAAE,MAAM,KAAK,IAAI;QACnB,MAAM,EAAE,MAAM,IAAI,8BAA8B,OAAO,CAAC,GAAG,EAAE,EAAE;QAC/D,GAAG,EAAE,SAAS;KACf,CAAC,CAAC;IAEH,2EAA2E;IAC3E,2BAA2B;IAC3B,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QAChD,IAAI,MAAM;YAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAChC,MAAM,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,IAAI,CACpE,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC;YAC3B,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,IAAI,IAAI,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC3C,OAAO,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,CAAC"}
|
|
@@ -17,17 +17,56 @@ export declare function pinnedPlaywright(): {
|
|
|
17
17
|
/**
|
|
18
18
|
* The command `versioncam install` runs, as argv.
|
|
19
19
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
20
|
+
* The headless shell alone, unless asked for more. It is the Chromium that
|
|
21
|
+
* records: Playwright launches it for every headless run, and every recorder
|
|
22
|
+
* command but two is headless. It is also 190 MB where the full browser is
|
|
23
|
+
* 340 MB more, and a stranger's first ten minutes with the package were
|
|
24
|
+
* measured on 2026-10-28: on a slow line the two builds together took nine of
|
|
25
|
+
* them. `login` and `preview` open a window, which the shell cannot, so they
|
|
26
|
+
* fetch the full browser the first time they run; `--full` fetches both now,
|
|
27
|
+
* for a machine that will be offline then.
|
|
23
28
|
*/
|
|
24
|
-
export declare function installArgv(node: string, cli: string,
|
|
29
|
+
export declare function installArgv(node: string, cli: string, options?: {
|
|
30
|
+
withDeps?: boolean;
|
|
31
|
+
full?: boolean;
|
|
32
|
+
}): string[];
|
|
33
|
+
/** The command that fetches the full browser alone, the shell being there. */
|
|
34
|
+
export declare function fullBrowserArgv(node: string, cli: string): string[];
|
|
35
|
+
/**
|
|
36
|
+
* Where the two Chromium builds this version uses are, or null for one that
|
|
37
|
+
* is not there.
|
|
38
|
+
*
|
|
39
|
+
* Asked of Playwright's own registry, which knows the build numbers and
|
|
40
|
+
* honours PLAYWRIGHT_BROWSERS_PATH; the public API names only the full
|
|
41
|
+
* browser's path. `lib/server` is not public API, which the exact pin on
|
|
42
|
+
* Playwright makes bearable: an upgrade is an event, and the tests ask the
|
|
43
|
+
* registry this question too.
|
|
44
|
+
*/
|
|
45
|
+
export declare function browserPaths(): {
|
|
46
|
+
shell: string | null;
|
|
47
|
+
full: string | null;
|
|
48
|
+
};
|
|
49
|
+
/** Playwright's installer, with its output on this terminal; its exit code. */
|
|
50
|
+
export declare function runInstaller(command: string, args: string[]): Promise<number>;
|
|
51
|
+
/** What `ensureFullBrowser` touches, so a test can stand in for all of it. */
|
|
52
|
+
export type InstallerIO = {
|
|
53
|
+
has: () => boolean;
|
|
54
|
+
run: (command: string, args: string[]) => Promise<number>;
|
|
55
|
+
write: (text: string) => void;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Before a command opens a window: the full browser, fetched once if `install`
|
|
59
|
+
* left it out. It says what it is doing first, since a download of a third of
|
|
60
|
+
* a gigabyte with no word on the terminal looks like a hang.
|
|
61
|
+
*/
|
|
62
|
+
export declare function ensureFullBrowser(io?: InstallerIO): Promise<boolean>;
|
|
25
63
|
/**
|
|
26
64
|
* Install the Chromium this version of versioncam records with.
|
|
27
65
|
*
|
|
28
66
|
* `--with-deps` adds the system libraries Chromium needs on a bare Linux
|
|
29
67
|
* image, which is the usual state of a CI runner and asks for root there.
|
|
30
|
-
*
|
|
31
|
-
*
|
|
68
|
+
* `--full` adds the browser `login` and `preview` open. The command it runs
|
|
69
|
+
* is printed first: in a CI log, which Playwright installed which browser is
|
|
70
|
+
* the first question when something differs.
|
|
32
71
|
*/
|
|
33
72
|
export declare function install(argv: string[]): Promise<number>;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
2
3
|
import { createRequire } from "node:module";
|
|
3
4
|
import { dirname, join } from "node:path";
|
|
4
5
|
import { parseArgs } from "node:util";
|
|
6
|
+
import { registry } from "playwright-core/lib/server";
|
|
5
7
|
/**
|
|
6
8
|
* The Playwright this package drives: its version, and the CLI that ships
|
|
7
9
|
* with it.
|
|
@@ -23,44 +25,102 @@ export function pinnedPlaywright() {
|
|
|
23
25
|
/**
|
|
24
26
|
* The command `versioncam install` runs, as argv.
|
|
25
27
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
28
|
+
* The headless shell alone, unless asked for more. It is the Chromium that
|
|
29
|
+
* records: Playwright launches it for every headless run, and every recorder
|
|
30
|
+
* command but two is headless. It is also 190 MB where the full browser is
|
|
31
|
+
* 340 MB more, and a stranger's first ten minutes with the package were
|
|
32
|
+
* measured on 2026-10-28: on a slow line the two builds together took nine of
|
|
33
|
+
* them. `login` and `preview` open a window, which the shell cannot, so they
|
|
34
|
+
* fetch the full browser the first time they run; `--full` fetches both now,
|
|
35
|
+
* for a machine that will be offline then.
|
|
29
36
|
*/
|
|
30
|
-
export function installArgv(node, cli,
|
|
37
|
+
export function installArgv(node, cli, options = {}) {
|
|
31
38
|
return [
|
|
32
39
|
node,
|
|
33
40
|
cli,
|
|
34
41
|
"install",
|
|
35
|
-
...(withDeps ? ["--with-deps"] : []),
|
|
42
|
+
...(options.withDeps ? ["--with-deps"] : []),
|
|
43
|
+
...(options.full ? [] : ["--only-shell"]),
|
|
36
44
|
"chromium",
|
|
37
45
|
];
|
|
38
46
|
}
|
|
47
|
+
/** The command that fetches the full browser alone, the shell being there. */
|
|
48
|
+
export function fullBrowserArgv(node, cli) {
|
|
49
|
+
return [node, cli, "install", "--no-shell", "chromium"];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Where the two Chromium builds this version uses are, or null for one that
|
|
53
|
+
* is not there.
|
|
54
|
+
*
|
|
55
|
+
* Asked of Playwright's own registry, which knows the build numbers and
|
|
56
|
+
* honours PLAYWRIGHT_BROWSERS_PATH; the public API names only the full
|
|
57
|
+
* browser's path. `lib/server` is not public API, which the exact pin on
|
|
58
|
+
* Playwright makes bearable: an upgrade is an event, and the tests ask the
|
|
59
|
+
* registry this question too.
|
|
60
|
+
*/
|
|
61
|
+
export function browserPaths() {
|
|
62
|
+
const where = (name) => {
|
|
63
|
+
const found = registry.findExecutable(name)?.executablePath();
|
|
64
|
+
return found && existsSync(found) ? found : null;
|
|
65
|
+
};
|
|
66
|
+
return { shell: where("chromium-headless-shell"), full: where("chromium") };
|
|
67
|
+
}
|
|
68
|
+
/** Playwright's installer, with its output on this terminal; its exit code. */
|
|
69
|
+
export function runInstaller(command, args) {
|
|
70
|
+
return new Promise((resolve) => {
|
|
71
|
+
const child = spawn(command, args, { stdio: "inherit" });
|
|
72
|
+
child.on("error", (error) => {
|
|
73
|
+
process.stderr.write(`Could not run the installer: ${error.message}\n`);
|
|
74
|
+
resolve(1);
|
|
75
|
+
});
|
|
76
|
+
child.on("exit", (code) => resolve(code ?? 1));
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Before a command opens a window: the full browser, fetched once if `install`
|
|
81
|
+
* left it out. It says what it is doing first, since a download of a third of
|
|
82
|
+
* a gigabyte with no word on the terminal looks like a hang.
|
|
83
|
+
*/
|
|
84
|
+
export async function ensureFullBrowser(io = {
|
|
85
|
+
has: () => browserPaths().full !== null,
|
|
86
|
+
run: runInstaller,
|
|
87
|
+
write: (text) => process.stdout.write(text),
|
|
88
|
+
}) {
|
|
89
|
+
if (io.has())
|
|
90
|
+
return true;
|
|
91
|
+
const playwright = pinnedPlaywright();
|
|
92
|
+
const [command, ...args] = fullBrowserArgv(process.execPath, playwright.cli);
|
|
93
|
+
io.write("This opens a window, which needs the full Chromium; `versioncam install` " +
|
|
94
|
+
"fetched only the headless shell that records.\n" +
|
|
95
|
+
`Fetching it once, for Playwright ${playwright.version}:\n` +
|
|
96
|
+
` ${[command, ...args].join(" ")}\n`);
|
|
97
|
+
return (await io.run(command, args)) === 0;
|
|
98
|
+
}
|
|
39
99
|
/**
|
|
40
100
|
* Install the Chromium this version of versioncam records with.
|
|
41
101
|
*
|
|
42
102
|
* `--with-deps` adds the system libraries Chromium needs on a bare Linux
|
|
43
103
|
* image, which is the usual state of a CI runner and asks for root there.
|
|
44
|
-
*
|
|
45
|
-
*
|
|
104
|
+
* `--full` adds the browser `login` and `preview` open. The command it runs
|
|
105
|
+
* is printed first: in a CI log, which Playwright installed which browser is
|
|
106
|
+
* the first question when something differs.
|
|
46
107
|
*/
|
|
47
108
|
export async function install(argv) {
|
|
48
109
|
const { values } = parseArgs({
|
|
49
110
|
args: argv,
|
|
50
|
-
options: { "with-deps": { type: "boolean" } },
|
|
111
|
+
options: { "with-deps": { type: "boolean" }, full: { type: "boolean" } },
|
|
51
112
|
strict: false,
|
|
52
113
|
});
|
|
53
114
|
const playwright = pinnedPlaywright();
|
|
54
|
-
const
|
|
55
|
-
process.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const child = spawn(command, args, { stdio: "inherit" });
|
|
59
|
-
child.on("error", (error) => {
|
|
60
|
-
process.stderr.write(`Could not run the installer: ${error.message}\n`);
|
|
61
|
-
resolve(1);
|
|
62
|
-
});
|
|
63
|
-
child.on("exit", (code) => resolve(code ?? 1));
|
|
115
|
+
const full = values.full === true;
|
|
116
|
+
const [command, ...args] = installArgv(process.execPath, playwright.cli, {
|
|
117
|
+
withDeps: values["with-deps"] === true,
|
|
118
|
+
full,
|
|
64
119
|
});
|
|
120
|
+
process.stdout.write((full
|
|
121
|
+
? `Both Chromium builds for Playwright ${playwright.version}: the headless shell versioncam records with, and the browser login and preview open:\n`
|
|
122
|
+
: `The headless Chromium versioncam records with, for Playwright ${playwright.version}:\n`) +
|
|
123
|
+
` ${[command, ...args].join(" ")}\n`);
|
|
124
|
+
return runInstaller(command, args);
|
|
65
125
|
}
|
|
66
126
|
//# sourceMappingURL=install.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/cli/commands/install.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/cli/commands/install.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { launchBrowser } from "../../driver/launch.js";
|
|
2
|
+
import { ensureFullBrowser } from "./install.js";
|
|
2
3
|
import { mkdir } from "node:fs/promises";
|
|
3
4
|
import { dirname } from "node:path";
|
|
4
5
|
import { loadConfig } from "../../loader.js";
|
|
@@ -21,6 +22,10 @@ export async function login() {
|
|
|
21
22
|
return 1;
|
|
22
23
|
}
|
|
23
24
|
const storageState = auth.storageState;
|
|
25
|
+
// A window needs the full browser, which `install` leaves to the first
|
|
26
|
+
// command that opens one; fetched before the app is started, not under it.
|
|
27
|
+
if (!(await ensureFullBrowser()))
|
|
28
|
+
return 1;
|
|
24
29
|
return drivingApp(config, async () => {
|
|
25
30
|
const browser = await launchBrowser({ headless: false });
|
|
26
31
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../../src/cli/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK;IACzB,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IAEzB,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE,CAAC;QACxB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,2EAA2E;YACzE,wEAAwE,CAC3E,CAAC;QACF,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;IACvC,OAAO,UAAU,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE;QACnC,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QACzD,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;YACxE,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;YACrC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAEhC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,cAAc,MAAM,CAAC,OAAO,+BAA+B;gBACzD,sCAAsC,CACzC,CAAC;YACF,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;gBAClC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;gBACvB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE;oBAC9B,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;oBACtB,OAAO,EAAE,CAAC;gBACZ,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,MAAM,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACxD,MAAM,OAAO,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;QACrD,CAAC;gBAAS,CAAC;YACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACxB,CAAC;QAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,YAAY,IAAI,CAAC,CAAC;QACjE,OAAO,CAAC,CAAC;IACX,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../../src/cli/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK;IACzB,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IAEzB,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE,CAAC;QACxB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,2EAA2E;YACzE,wEAAwE,CAC3E,CAAC;QACF,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;IACvC,uEAAuE;IACvE,2EAA2E;IAC3E,IAAI,CAAC,CAAC,MAAM,iBAAiB,EAAE,CAAC;QAAE,OAAO,CAAC,CAAC;IAC3C,OAAO,UAAU,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE;QACnC,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QACzD,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;YACxE,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;YACrC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAEhC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,cAAc,MAAM,CAAC,OAAO,+BAA+B;gBACzD,sCAAsC,CACzC,CAAC;YACF,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;gBAClC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;gBACvB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE;oBAC9B,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;oBACtB,OAAO,EAAE,CAAC;gBACZ,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,MAAM,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACxD,MAAM,OAAO,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;QACrD,CAAC;gBAAS,CAAC;YACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACxB,CAAC;QAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,YAAY,IAAI,CAAC,CAAC;QACjE,OAAO,CAAC,CAAC;IACX,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -2,6 +2,7 @@ import { parseArgs } from "node:util";
|
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { launchBrowser } from "../../driver/launch.js";
|
|
5
|
+
import { ensureFullBrowser } from "./install.js";
|
|
5
6
|
import { loadConfig } from "../../loader.js";
|
|
6
7
|
import { renderConfigOf } from "../../config.js";
|
|
7
8
|
import { bundleScenes, loadSceneIds } from "../../loader.js";
|
|
@@ -41,6 +42,11 @@ export async function preview(argv) {
|
|
|
41
42
|
return 1;
|
|
42
43
|
}
|
|
43
44
|
}
|
|
45
|
+
// A window needs the full browser, which `install` leaves to the first
|
|
46
|
+
// command that opens one; after the checks above, so nothing is fetched
|
|
47
|
+
// for a recording that is not there.
|
|
48
|
+
if (!(await ensureFullBrowser()))
|
|
49
|
+
return 1;
|
|
44
50
|
const browser = await launchBrowser({ headless: false });
|
|
45
51
|
const context = await browser.newContext({
|
|
46
52
|
viewport: { width: 1400, height: 1000 },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preview.js","sourceRoot":"","sources":["../../../src/cli/commands/preview.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"preview.js","sourceRoot":"","sources":["../../../src/cli/commands/preview.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/usage.d.ts
CHANGED
|
@@ -13,4 +13,4 @@
|
|
|
13
13
|
* is what comes after publishing: `versioncam cloud`, whose own usage is that
|
|
14
14
|
* group. The last group is not a stage but a way to run any of them.
|
|
15
15
|
*/
|
|
16
|
-
export declare const USAGE = "versioncam: record and render demo clips of a real app\n\nSet up\n versioncam install the Chromium this version of versioncam records with\n --with-deps and its system libraries (Linux CI)\n versioncam init install the authoring skill into .claude/\n --into <dir> into <dir>/versioncam/ instead, for another host\n --force overwrite files that are already there\n versioncam doctor check this machine can record, and that the app starts\n versioncam login sign in once and save the browser session\n\nWrite\n versioncam inspect <path> what a clip can click, and where each name came from\n --json machine-readable\n versioncam measure <path> <sel> where a selector's matches are, and what they say\n versioncam dsl the clip DSL: every method, its options and defaults\n\nRecord\n versioncam record [id\u2026] drive the app and capture frames\n --draft 15fps at CSS scale: cheap, for writing clips\n versioncam check [id\u2026] record every clip; exit 1 if any breaks\n --report <file> and write each clip's result there, as JSON\n versioncam stability [id\u2026] record each clip twice the same way; stable or not\n --runs <n> how many times (default 2)\n --full at full quality rather than draft\n\nReview\n versioncam sheet <id> an eight-frame contact sheet\n --at-marks sample the beats instead of even spacing\n versioncam frame <id> <n> one frame at output size, to a png\n --t <seconds> pick the frame by time instead\n --at <label> or by the beat it shows\n versioncam review <id> the checks that need no eyes; PASS/FAIL, exit 0/1\n --beats <file> [{ label, expect }] the clip promised\n --min <s> --max <s> duration bounds (default 9 and 11)\n versioncam preview <id> open the scrubber in a real browser\n --scene <id> preview a scene instead\n --frame <n> start at this frame\n\nOutput\n versioncam render [id\u2026] composite and encode recordings and scenes\n no ids: every one, stale recordings included\n --scene <id> and this scene, whatever the ids say (repeatable)\n --sequence stitch the results into one piece\n --report <file> and write what it made there, as JSON\n\nPublish\n versioncam publish [id\u2026] send the recordings and their checks to version.cam\n --dry-run print what would be sent, and send nothing\n --report <file> and write the living URLs there, as JSON\n\nManage\n versioncam cloud login sign in to version.cam, with a code you approve in a browser\n --label <name> what the approval page calls this machine\n versioncam cloud logout sign out: revoke the token, and delete it\n versioncam cloud status [project] each clip, current or broken, and what plays meanwhile\n versioncam cloud failure <clip> why a clip broke, and its picture, into .versioncam/failures/\n versioncam cloud ack <clip> \"I know, keep the old one\": the reminders stop\n versioncam cloud embed <clip> the snippets that embed a clip, and its files\n versioncam cloud set <name> <val> change a setting, once you approve it in a browser:\n visibility public|unlisted|private, retention <days>|off,\n viewers on|off, alerts email|slack <address>|off,\n alerts issues on|off\n versioncam cloud plan [account] the plan, and the pages to upgrade and pay on\n --project <owner/repo> which project, when not this repository's\n --json machine-readable, for status, failure, embed and plan\n\nFrom another directory\n versioncam <command> --cwd <dir> as if run in <dir>, which holds versioncam.config.ts\n versioncam --version which versioncam this is\n\nRun from a directory containing versioncam.config.ts, or name it with --cwd.\n";
|
|
16
|
+
export declare const USAGE = "versioncam: record and render demo clips of a real app\n\nSet up\n versioncam install the headless Chromium this version of versioncam records with\n --with-deps and its system libraries (Linux CI)\n --full and the full browser, which login and preview open\n versioncam init install the authoring skill into .claude/\n --into <dir> into <dir>/versioncam/ instead, for another host\n --force overwrite files that are already there\n versioncam doctor check this machine can record, and that the app starts\n versioncam login sign in once and save the browser session\n\nWrite\n versioncam inspect <path> what a clip can click, and where each name came from\n --json machine-readable\n versioncam measure <path> <sel> where a selector's matches are, and what they say\n versioncam dsl the clip DSL: every method, its options and defaults\n\nRecord\n versioncam record [id\u2026] drive the app and capture frames\n --draft 15fps at CSS scale: cheap, for writing clips\n versioncam check [id\u2026] record every clip; exit 1 if any breaks\n --report <file> and write each clip's result there, as JSON\n versioncam stability [id\u2026] record each clip twice the same way; stable or not\n --runs <n> how many times (default 2)\n --full at full quality rather than draft\n\nReview\n versioncam sheet <id> an eight-frame contact sheet\n --at-marks sample the beats instead of even spacing\n versioncam frame <id> <n> one frame at output size, to a png\n --t <seconds> pick the frame by time instead\n --at <label> or by the beat it shows\n versioncam review <id> the checks that need no eyes; PASS/FAIL, exit 0/1\n --beats <file> [{ label, expect }] the clip promised\n --min <s> --max <s> duration bounds (default 9 and 11)\n versioncam preview <id> open the scrubber in a real browser\n --scene <id> preview a scene instead\n --frame <n> start at this frame\n\nOutput\n versioncam render [id\u2026] composite and encode recordings and scenes\n no ids: every one, stale recordings included\n --scene <id> and this scene, whatever the ids say (repeatable)\n --sequence stitch the results into one piece\n --report <file> and write what it made there, as JSON\n\nPublish\n versioncam publish [id\u2026] send the recordings and their checks to version.cam\n --dry-run print what would be sent, and send nothing\n --report <file> and write the living URLs there, as JSON\n\nManage\n versioncam cloud login sign in to version.cam, with a code you approve in a browser\n --label <name> what the approval page calls this machine\n versioncam cloud logout sign out: revoke the token, and delete it\n versioncam cloud status [project] each clip, current or broken, and what plays meanwhile\n versioncam cloud failure <clip> why a clip broke, and its picture, into .versioncam/failures/\n versioncam cloud ack <clip> \"I know, keep the old one\": the reminders stop\n versioncam cloud embed <clip> the snippets that embed a clip, and its files\n versioncam cloud set <name> <val> change a setting, once you approve it in a browser:\n visibility public|unlisted|private, retention <days>|off,\n viewers on|off, alerts email|slack <address>|off,\n alerts issues on|off\n versioncam cloud plan [account] the plan, and the pages to upgrade and pay on\n --project <owner/repo> which project, when not this repository's\n --json machine-readable, for status, failure, embed and plan\n\nFrom another directory\n versioncam <command> --cwd <dir> as if run in <dir>, which holds versioncam.config.ts\n versioncam --version which versioncam this is\n\nRun from a directory containing versioncam.config.ts, or name it with --cwd.\n";
|
package/dist/cli/usage.js
CHANGED
|
@@ -16,8 +16,9 @@
|
|
|
16
16
|
export const USAGE = `versioncam: record and render demo clips of a real app
|
|
17
17
|
|
|
18
18
|
Set up
|
|
19
|
-
versioncam install the Chromium this version of versioncam records with
|
|
19
|
+
versioncam install the headless Chromium this version of versioncam records with
|
|
20
20
|
--with-deps and its system libraries (Linux CI)
|
|
21
|
+
--full and the full browser, which login and preview open
|
|
21
22
|
versioncam init install the authoring skill into .claude/
|
|
22
23
|
--into <dir> into <dir>/versioncam/ instead, for another host
|
|
23
24
|
--force overwrite files that are already there
|
package/dist/cli/usage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/cli/usage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG
|
|
1
|
+
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/cli/usage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyEpB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "versioncam",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Record demo clips of a real web app: scripted, deterministic, re-recorded on every push.",
|
|
6
6
|
"license": "FSL-1.1-ALv2",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"url": "git+https://github.com/versioncam/versioncam.git",
|
|
12
12
|
"directory": "packages/recorder"
|
|
13
13
|
},
|
|
14
|
-
"bugs": "https://github.com/versioncam/versioncam
|
|
14
|
+
"bugs": "https://github.com/versioncam/versioncam/issues",
|
|
15
15
|
"keywords": [
|
|
16
16
|
"demo",
|
|
17
17
|
"video",
|
|
@@ -64,7 +64,8 @@
|
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
66
|
"esbuild": "^0.25.0",
|
|
67
|
-
"playwright": "1.59.1"
|
|
67
|
+
"playwright": "1.59.1",
|
|
68
|
+
"playwright-core": "1.59.1"
|
|
68
69
|
},
|
|
69
70
|
"optionalDependencies": {
|
|
70
71
|
"ffmpeg-static": "^5.2.0"
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "versioncam",
|
|
3
|
+
"version": "0.5.2",
|
|
3
4
|
"description": "Record a short, true demo clip of a web app from one sentence: a skill that sets the repository up on its first run, writes the clip, and has a reviewer pass it from a contact sheet.",
|
|
4
5
|
"author": {
|
|
5
6
|
"name": "Peter Bulovec"
|
|
6
7
|
},
|
|
7
8
|
"homepage": "https://version.cam",
|
|
8
|
-
"keywords": [
|
|
9
|
+
"keywords": [
|
|
10
|
+
"demo",
|
|
11
|
+
"recording",
|
|
12
|
+
"playwright",
|
|
13
|
+
"screencast"
|
|
14
|
+
]
|
|
9
15
|
}
|
package/plugin/README.md
CHANGED
|
@@ -30,6 +30,17 @@ Or, without copying anything, load the plugin directory as it is:
|
|
|
30
30
|
claude --plugin-dir node_modules/versioncam/plugin
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
+
Or install it as a plugin from the repository's own marketplace, in a Claude
|
|
34
|
+
Code session (2.1.275 or later):
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
/plugin install versioncam --marketplace versioncam/versioncam
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Loaded either of these two ways, the skill carries the plugin's name as a
|
|
41
|
+
prefix: `/versioncam:versioncam "<intent>"`. Installed by `init`, it is
|
|
42
|
+
`/versioncam`, as the examples below write it.
|
|
43
|
+
|
|
33
44
|
## Run it
|
|
34
45
|
|
|
35
46
|
```
|