versioncam 0.4.0 → 0.5.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/CHANGELOG.md CHANGED
@@ -6,6 +6,73 @@ 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.0 (2026-10-07)
10
+
11
+ A minor version: commands for version.cam, and the skill learns to use them.
12
+ Nothing records or renders differently, and the config and the clip DSL are
13
+ as they were.
14
+
15
+ ### Added
16
+
17
+ - **`versioncam cloud`** does from a terminal, or from an agent's shell, what
18
+ the dashboard at app.version.cam does. `cloud login` signs the command
19
+ line in with a code you approve in a browser, on any device, so it works
20
+ over SSH and in a sandbox. The token lasts seven days and is kept in
21
+ `~/.config/versioncam/credentials.json`, or under `$XDG_CONFIG_HOME`: a
22
+ file only you may read, with each API's sign-in apart, so staging and
23
+ production sit side by side. No command prints it, and `cloud logout`
24
+ revokes it. `VERSIONCAM_API` chooses the API from the shell alone: unlike
25
+ `publish`, the `cloud` commands never take it, or `XDG_CONFIG_HOME`, from
26
+ a `.env` file, and say so when one sets it, so a cloned repository cannot
27
+ send a sign-in to a server of its choosing.
28
+ - Reading needs nothing more. `cloud status` says of each clip whether it is
29
+ current or broken, since when, who acknowledged it, and what your pages
30
+ play meanwhile, then the plan and where to manage the project; outside a
31
+ clone it lists every project you can see. `cloud failure <clip>` says
32
+ which step stopped a broken clip and why, and saves the page as it was to
33
+ `.versioncam/failures/<clip>.png`. `cloud ack <clip>` is the dashboard's
34
+ "I know, keep the old one". `cloud embed <clip>` prints the snippets that
35
+ embed a clip, and its files, and `cloud plan` the plan and the pages to
36
+ upgrade and pay on. Each read takes `--json`, and `--project owner/repo`
37
+ names a project when the repository's `origin` on GitHub is not the one.
38
+ - **`cloud set`** changes a project's visibility, retention, "Tell viewers
39
+ when a clip is broken" or alerts, and only once you approve that one change
40
+ in the browser: it prints the change in a sentence, an address and a code,
41
+ and waits up to ten minutes. Paying, deleting a project and tokens for CI
42
+ outside GitHub stay on app.version.cam.
43
+ - **The skill's `platform.md`**, which `versioncam init` installs beside the
44
+ other briefs: `/versioncam status`, `/versioncam fix [clip]` (why a clip
45
+ broke, a repair, and a pull request for it) and `/versioncam embed <clip>`,
46
+ and any question about the project on version.cam. It changes nothing you
47
+ did not ask for, leaves every approval to you, and never touches the
48
+ token. A skill already installed gets it from `versioncam init --force`,
49
+ which also overwrites any brief you edited.
50
+ - The README's **`## version.cam`** section: connecting a repository, what
51
+ happens when a clip breaks on each plan, who can see the clips, the
52
+ `cloud` commands, and a repository whose CI runs elsewhere.
53
+
54
+ ### Changed
55
+
56
+ - `publish --report` writes version.cam's whole answer, not only its
57
+ `project` and `versions`, so a field the service adds reaches the
58
+ Action's job summary without a release of this package to carry it:
59
+ where to manage the project, who can see its clips, whether its plan tells
60
+ anyone when a clip breaks, and what a broken clip's pages play.
61
+ - `publish` calls a clip whose check failed on the default branch "broken",
62
+ not "stale", and says that a project token, `VERSIONCAM_TOKEN`, is for a
63
+ repository outside GitHub.
64
+
65
+ ## 0.4.1 (2026-10-06)
66
+
67
+ A patch version: nothing records or renders differently.
68
+
69
+ ### Changed
70
+
71
+ - The issue tracker lives in the versioncam organisation now, at
72
+ [github.com/versioncam/versioncam-home](https://github.com/versioncam/versioncam-home/issues).
73
+ The package's `bugs` link and the README's *Help* say so; the old address
74
+ redirects.
75
+
9
76
  ## 0.4.0 (2026-10-05)
10
77
 
11
78
  A minor version: clips whose app uses CSS transitions record differently.
package/README.md CHANGED
@@ -371,18 +371,18 @@ versioncam render [id…] composite and encode recordings and scenes
371
371
  Send what the last run recorded to [version.cam](https://version.cam), which
372
372
  renders it and keeps it at a living address. `publish` records nothing and
373
373
  renders nothing: for each clip the config defines, it sends the recording if
374
- the clip's last run passed, or the failure if it did not, so a clip that
375
- broke says so on every page that embeds it. Only the states the service has
376
- not seen are uploaded, so a version that changed one screen sends one
377
- screen.
374
+ the clip's last run passed, or the failure if it did not, so version.cam
375
+ knows when a clip broke (see *When a clip breaks*). Only the states the
376
+ service has not seen are uploaded, so a version that changed one screen
377
+ sends one screen.
378
378
 
379
379
  It needs a credential in the environment, never on the command line:
380
380
  `VERSIONCAM_OIDC_TOKEN`, which the versioncam GitHub Action requests from
381
381
  GitHub for the run (no secret to store), or `VERSIONCAM_TOKEN`, a project
382
- token from version.cam for any other CI. `VERSIONCAM_API` points it
383
- somewhere other than `https://api.version.cam`. Outside GitHub Actions it
384
- reads the commit and branch from git; `VERSIONCAM_COMMIT` and
385
- `VERSIONCAM_BRANCH` set them outright.
382
+ token from version.cam for a repository outside GitHub (see *Other CI*).
383
+ `VERSIONCAM_API` points it somewhere other than `https://api.version.cam`.
384
+ Outside GitHub Actions it reads the commit and branch from git;
385
+ `VERSIONCAM_COMMIT` and `VERSIONCAM_BRANCH` set them outright.
386
386
 
387
387
  ```
388
388
  versioncam publish [id…] send the recordings and their checks to version.cam
@@ -390,6 +390,31 @@ versioncam publish [id…] send the recordings and their checks to ver
390
390
  --report <file> and write the living URLs there, as JSON
391
391
  ```
392
392
 
393
+ ### Manage
394
+
395
+ What version.cam knows about a project, and its settings, from the command
396
+ line: what the dashboard shows and does, once you have signed in with a code
397
+ you approve in a browser. A setting changes only when you approve that one
398
+ change in the browser too. These need no `versioncam.config.ts`, and run
399
+ anywhere in a clone of the repository. See *From the command line*.
400
+
401
+ ```
402
+ versioncam cloud login sign in to version.cam, with a code you approve in a browser
403
+ --label <name> what the approval page calls this machine
404
+ versioncam cloud logout sign out: revoke the token, and delete it
405
+ versioncam cloud status [project] each clip, current or broken, and what plays meanwhile
406
+ versioncam cloud failure <clip> why a clip broke, and its picture, into .versioncam/failures/
407
+ versioncam cloud ack <clip> "I know, keep the old one": the reminders stop
408
+ versioncam cloud embed <clip> the snippets that embed a clip, and its files
409
+ versioncam cloud set <name> <val> change a setting, once you approve it in a browser:
410
+ visibility public|unlisted|private, retention <days>|off,
411
+ viewers on|off, alerts email|slack <address>|off,
412
+ alerts issues on|off
413
+ versioncam cloud plan [account] the plan, and the pages to upgrade and pay on
414
+ --project <owner/repo> which project, when not this repository's
415
+ --json machine-readable, for status, failure, embed and plan
416
+ ```
417
+
393
418
  ### From another directory
394
419
 
395
420
  In a monorepo the app is one directory among many. A command run from
@@ -409,6 +434,133 @@ versioncam <command> --cwd <dir> as if run in <dir>, which holds versioncam.co
409
434
  versioncam --version which versioncam this is
410
435
  ```
411
436
 
437
+ ## version.cam
438
+
439
+ [version.cam](https://version.cam) renders what `versioncam publish` sends
440
+ and keeps each clip at a living address,
441
+ `clips.version.cam/<owner>/<repo>/<clip>`. It plays the newest version from
442
+ your default branch that passed, so a page that embeds it never needs
443
+ editing. Projects are managed on [app.version.cam](https://app.version.cam).
444
+
445
+ ### Connect a repository
446
+
447
+ Sign in at [app.version.cam](https://app.version.cam) with GitHub, and
448
+ install the Versioncam GitHub App on the repositories you choose. Then
449
+ publish from GitHub Actions with the
450
+ [versioncam Action](https://github.com/versioncam/action), which signs in
451
+ with GitHub's own token, so there is no secret to store. A repository's
452
+ project appears the first time it publishes, or when the App is installed
453
+ on it.
454
+
455
+ The App is how version.cam learns from GitHub, each time someone signs in,
456
+ who may do what: whoever may read a repository sees its project, and
457
+ whoever administers the repository changes the project's settings. The App
458
+ also reports each publish on GitHub: a check on its commit, and on a pull
459
+ request a comment naming the clips that look different and the ones that
460
+ failed.
461
+
462
+ ### When a clip breaks
463
+
464
+ A clip breaks when its check fails on the default branch: a control it uses
465
+ was renamed or removed, a page moved, a step waited for something that never
466
+ came, or the app would not start. A change in how the app looks never breaks
467
+ a clip. It makes a new version.
468
+
469
+ Your pages keep playing the last version that passed, and say nothing about
470
+ the break. A project that wants its viewers told, open source docs perhaps,
471
+ turns on "Tell viewers when a clip is broken" in its settings.
472
+
473
+ On every plan, CI says so, and so does the dashboard: a pull request's check
474
+ fails and the Action comments on it, the App's check on the commit says the
475
+ clip is broken, and the summary of the job that publishes says what your
476
+ pages play meanwhile.
477
+
478
+ On Pro and Max, version.cam also tells your team, by email, in Slack or with
479
+ a GitHub issue, as the project's settings choose. It reminds them two days
480
+ after a clip broke and then every week, until the clip passes again or
481
+ someone acknowledges it on the dashboard ("I know, keep the old one"). An
482
+ acknowledged clip gets one more reminder a month later if it is still
483
+ broken. When the clip passes again, the team is told it is fixed.
484
+
485
+ ### Who can see the clips
486
+
487
+ | Visibility | Who can see the clips |
488
+ |---|---|
489
+ | public | Anyone, and search engines. |
490
+ | unlisted | Anyone with the address, kept out of search. The address is made of names, so unlisted means not listed, not secret. |
491
+ | private | Whoever GitHub lets read the repository, signed in at app.version.cam. |
492
+
493
+ A private repository's clips start private, and a public repository's start
494
+ public. A private clip plays only for the people who may see it, so never on
495
+ a public page: to show a private repository's clips in public docs or on a
496
+ landing page, make them public or unlisted in the project's settings.
497
+
498
+ ### From the command line
499
+
500
+ `versioncam cloud` does what the dashboard does, from a terminal, and so
501
+ from an agent working in one:
502
+
503
+ ```bash
504
+ npx versioncam cloud login # a code you approve in a browser, once a week
505
+ npx versioncam cloud status # this repository's clips: current or broken, and what plays
506
+ npx versioncam cloud failure checkout # where a broken clip stopped, and the page as it was
507
+ ```
508
+
509
+ **Signing in.** `cloud login` prints an address and a code. Open the address
510
+ on any device, sign in with GitHub, check that the page shows the same code,
511
+ and approve it. Nothing calls back to the machine that runs the command, so
512
+ it works over SSH and in a sandbox. The command line then holds a token that
513
+ lasts seven days, in `~/.config/versioncam/credentials.json`, or under
514
+ `$XDG_CONFIG_HOME` when that is set: a file only you may read, which no
515
+ command prints. `cloud logout` revokes it. `VERSIONCAM_API`, set in the
516
+ shell, points the commands at another version.cam, and each one's sign-in
517
+ is kept apart. Unlike `publish`, they never take it, or `XDG_CONFIG_HOME`,
518
+ from a `.env` file, so a repository you clone cannot send your sign-in to a
519
+ server of its choosing, or have the token written inside it.
520
+
521
+ **Reading** needs nothing more. `status` lists the clips: current or broken,
522
+ since when, who acknowledged a broken one, and the version your pages play
523
+ meanwhile; then the plan, and where to manage the project. `failure <clip>`
524
+ says which step stopped a broken clip and why, and saves the page as it was
525
+ then to `.versioncam/failures/<clip>.png`. `embed <clip>` prints the
526
+ snippets that embed it, and `plan` says which plan, why and until when, and
527
+ where to upgrade and pay. Each takes `--json`. They act on the repository
528
+ they run in, from its `origin` remote on GitHub, or on the one that
529
+ `--project owner/repo` names. `ack <clip>` is the dashboard's "I know, keep
530
+ the old one".
531
+
532
+ **A setting changes only once you approve it in the browser,** one change at
533
+ a time. `cloud set visibility public` prints the change in a sentence, an
534
+ address and a code, and waits up to ten minutes. The page shows exactly that
535
+ change, so an agent running the commands for you cannot change a project
536
+ without you seeing what it asked for. The settings are `visibility`,
537
+ `retention`, `viewers` ("Tell viewers when a clip is broken") and `alerts`,
538
+ by email, in Slack or with a GitHub issue.
539
+
540
+ Three things stay a click on app.version.cam: paying (`cloud plan` prints
541
+ the page), deleting a project, and making a project token for CI outside
542
+ GitHub.
543
+
544
+ The authoring skill runs these commands too: `/versioncam status`,
545
+ `/versioncam fix [clip]` and `/versioncam embed <clip>`.
546
+
547
+ ### Other CI
548
+
549
+ A repository on GitHub publishes from GitHub Actions, whatever builds it
550
+ otherwise. GitHub's token says which repository, commit and branch a run is
551
+ of, and version.cam takes them from it. A project token, `VERSIONCAM_TOKEN`,
552
+ would have to say all that itself, with nothing to check it against, so it
553
+ speaks only for a project with no GitHub repository.
554
+
555
+ So when your CI runs elsewhere, run just the clips in GitHub Actions: a
556
+ workflow beside the CI you have, with the versioncam Action checking the
557
+ clips on pull requests and publishing them from your default branch. The
558
+ [Action's README](https://github.com/versioncam/action) has one to copy.
559
+
560
+ A repository outside GitHub publishes with a project token, given to
561
+ `versioncam publish` as `VERSIONCAM_TOKEN` and made on the project's page at
562
+ app.version.cam. Its project is set up by hand: write to hello@version.cam.
563
+
412
564
  ## What a recording leaves behind
413
565
 
414
566
  `versioncam record` writes each clip to `.versioncam/recordings/<id>/`.
@@ -749,7 +901,7 @@ The words these pages use in a particular sense.
749
901
  ## Help
750
902
 
751
903
  Bugs, questions, and apps it cannot record go to the issue tracker at
752
- [github.com/petbul/versioncam-home](https://github.com/petbul/versioncam-home/issues).
904
+ [github.com/versioncam/versioncam-home](https://github.com/versioncam/versioncam-home/issues).
753
905
  A clip that will not reproduce is easiest to help with alongside the two
754
906
  pictures `versioncam stability` saves.
755
907
 
@@ -0,0 +1,59 @@
1
+ import type { ChangeRequest } from "../../cloud/protocol.js";
2
+ import { type Clock } from "../../cloud/wait.js";
3
+ /**
4
+ * `versioncam cloud`: what the dashboard at app.version.cam does, from a
5
+ * terminal, and so from an agent's shell.
6
+ *
7
+ * `versioncam login` was already taken, by the command that saves the app's
8
+ * own browser session for recording, so the platform's commands live under
9
+ * a name of their own.
10
+ *
11
+ * A person signs in once, with a code they approve in a browser, and the
12
+ * commands then read for them: a project's clips and whether each is
13
+ * broken, why one broke, how to embed one, the plan. Acknowledging a broken
14
+ * clip needs no more than that, as on the dashboard. Every setting change
15
+ * prints a code and waits for the person to approve that one change in the
16
+ * browser, because whoever runs these commands may be an agent, and what an
17
+ * agent reads here (clip titles, failure messages) was written by whoever
18
+ * published. Nothing it is told can change a project without a person seeing
19
+ * the change.
20
+ *
21
+ * The token never reaches the output, whatever the service says: every line
22
+ * written passes through a filter that knows it.
23
+ *
24
+ * And the commands run in the environment the shell gave, never with what
25
+ * the repository's `.env.recording` or `.env` added, which the CLI loads
26
+ * before every command. Those files come with whatever was cloned: one that
27
+ * set VERSIONCAM_API could send a sign-in, and every command holding a
28
+ * token, to a server of the repository's choosing, and one that set
29
+ * XDG_CONFIG_HOME could have the token written into the repository itself.
30
+ * `publish` still reads the files: CI sets its environment itself.
31
+ */
32
+ /** A variable a file set that these commands read only from the shell. */
33
+ export type Ignored = {
34
+ name: string;
35
+ file: string;
36
+ value: string;
37
+ };
38
+ /** What a cloud command needs from the world, so a test can hand it another one. */
39
+ export type CloudIo = {
40
+ /** The shell's environment, never a repository file's. */
41
+ env: NodeJS.ProcessEnv;
42
+ /** What a file tried to set, said once so that nobody wonders why it did nothing. */
43
+ ignored?: Ignored[];
44
+ /** The directory the command runs in: its repository, and its `.versioncam/`. */
45
+ cwd: string;
46
+ out(text: string): void;
47
+ err(text: string): void;
48
+ fetch: typeof fetch;
49
+ clock: Clock;
50
+ hostname(): string;
51
+ /** The zone dates are written in: the machine's own, unless a test pins one. */
52
+ timeZone?: string;
53
+ };
54
+ /** The environment a cloud command runs in, and what the files tried to add to it. */
55
+ export declare function shellEnvironment(): Pick<CloudIo, "env" | "ignored">;
56
+ export declare function cloud(argv: string[]): Promise<number>;
57
+ export declare function runCloud(argv: string[], io: CloudIo): Promise<number>;
58
+ /** The setting and value as the API takes them, or why not. */
59
+ export declare function changeRequest(args: string[]): ChangeRequest | string;