@vosjs/cli 0.84.0 → 0.86.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.
Files changed (30) hide show
  1. package/README.md +15 -5
  2. package/dist/{assetManifest-32VI7OK7.js → assetManifest-QFJ7X6TT.js} +3 -3
  3. package/dist/{chunk-Q47FUCYN.js → chunk-2LAXJZCG.js} +2 -2
  4. package/dist/{chunk-OWYOJB7K.js → chunk-7A3PZARL.js} +14 -3
  5. package/dist/chunk-7A3PZARL.js.map +1 -0
  6. package/dist/{chunk-EPSYIF2S.js → chunk-PZP76YJI.js} +298 -58
  7. package/dist/chunk-PZP76YJI.js.map +1 -0
  8. package/dist/{chunk-M5ZBQFPG.js → chunk-V3RUNUNP.js} +2 -2
  9. package/dist/{chunk-DM7ADA77.js → chunk-ZXFO32KW.js} +722 -203
  10. package/dist/chunk-ZXFO32KW.js.map +1 -0
  11. package/dist/cli.js +7 -7
  12. package/dist/index.d.ts +37 -13
  13. package/dist/index.js +5 -5
  14. package/dist/manifest-OLVFUZTW.js +8 -0
  15. package/dist/{run-J5Z32LEB.js → run-KB36L2ZI.js} +5 -5
  16. package/package.json +7 -7
  17. package/skills/VERSION +1 -1
  18. package/skills/launch-kit/SKILL.md +6 -2
  19. package/skills/product-video/SKILL.md +13 -3
  20. package/skills/vos-cut/SKILL.md +6 -2
  21. package/skills/vos-score/SKILL.md +15 -5
  22. package/dist/chunk-DM7ADA77.js.map +0 -1
  23. package/dist/chunk-EPSYIF2S.js.map +0 -1
  24. package/dist/chunk-OWYOJB7K.js.map +0 -1
  25. package/dist/manifest-VTOIEUHJ.js +0 -8
  26. /package/dist/{assetManifest-32VI7OK7.js.map → assetManifest-QFJ7X6TT.js.map} +0 -0
  27. /package/dist/{chunk-Q47FUCYN.js.map → chunk-2LAXJZCG.js.map} +0 -0
  28. /package/dist/{chunk-M5ZBQFPG.js.map → chunk-V3RUNUNP.js.map} +0 -0
  29. /package/dist/{manifest-VTOIEUHJ.js.map → manifest-OLVFUZTW.js.map} +0 -0
  30. /package/dist/{run-J5Z32LEB.js.map → run-KB36L2ZI.js.map} +0 -0
package/dist/cli.js CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  stillOutFor,
20
20
  stillWarnings,
21
21
  videoFormat
22
- } from "./chunk-Q47FUCYN.js";
22
+ } from "./chunk-2LAXJZCG.js";
23
23
  import {
24
24
  ASSET_ROUTE,
25
25
  MEDIA_HEAD_BYTES,
@@ -38,7 +38,7 @@ import {
38
38
  serveFile,
39
39
  unusedFlagsMessage,
40
40
  writeOutput
41
- } from "./chunk-EPSYIF2S.js";
41
+ } from "./chunk-PZP76YJI.js";
42
42
 
43
43
  // src/cli.ts
44
44
  import { existsSync, readFileSync, statSync } from "fs";
@@ -842,7 +842,7 @@ async function cmdCheck(argv) {
842
842
  const result = runCheck(parsed);
843
843
  if (result.config) {
844
844
  const baseDir = baseDirOf(source);
845
- const { hostedLiteralWarnings } = await import("./assetManifest-32VI7OK7.js");
845
+ const { hostedLiteralWarnings } = await import("./assetManifest-QFJ7X6TT.js");
846
846
  const extra = [
847
847
  ...baseDir ? missingManifestFiles(result.config, baseDir) : [],
848
848
  ...hostedLiteralWarnings(result.config)
@@ -876,12 +876,12 @@ async function cmdCheck(argv) {
876
876
  return result.ok ? EXIT_OK : EXIT_ERROR;
877
877
  }
878
878
  async function delegate(argv) {
879
- const { run } = await import("./run-J5Z32LEB.js");
879
+ const { run } = await import("./run-KB36L2ZI.js");
880
880
  return await run(argv);
881
881
  }
882
882
  async function printHelp() {
883
883
  process.stdout.write(HELP_ENGINE);
884
- const { manifest } = await import("./manifest-VTOIEUHJ.js");
884
+ const { manifest } = await import("./manifest-OLVFUZTW.js");
885
885
  process.stdout.write("\nTake pipeline + vos.so verbs\n");
886
886
  for (const v of manifest.verbs) {
887
887
  if (v.name === "render") continue;
@@ -910,7 +910,7 @@ async function main() {
910
910
  const engine = HELP_ENGINE.split("\n").filter(
911
911
  (l) => l.startsWith(` vos ${cmd} `)
912
912
  );
913
- const { verbHelp } = await import("./run-J5Z32LEB.js");
913
+ const { verbHelp } = await import("./run-KB36L2ZI.js");
914
914
  const take = verbHelp(cmd);
915
915
  process.stdout.write(
916
916
  `${engine.join("\n")}
@@ -938,7 +938,7 @@ ${take.includes("no such verb") ? "" : take}`
938
938
  main().then(async (code) => {
939
939
  if (code === EXIT_OK) {
940
940
  const verb = process.argv[2] ?? "";
941
- const { HELP } = await import("./run-J5Z32LEB.js");
941
+ const { HELP } = await import("./run-KB36L2ZI.js");
942
942
  const documented = [
943
943
  ...helpFlagsFor(HELP_ENGINE, verb),
944
944
  ...helpFlagsFor(HELP, verb)
package/dist/index.d.ts CHANGED
@@ -4,6 +4,7 @@ import { ActionsFile, RecordOpts as RecordOpts$1 } from '@vosjs/render-core/reco
4
4
  export { ActionStep, ActionsFile, validateActions } from '@vosjs/render-core/record';
5
5
  import { CursorTrack, RecordingMeta, ProjectDoc, TemplateAnchor, Backdrop, LayoutParts, TranscriptSegment, Digest } from '@vosjs/studio-core';
6
6
  export { Digest } from '@vosjs/studio-core';
7
+ import { BedTrack, FilmSummary } from '@vosjs/shared/music';
7
8
 
8
9
  interface ProgramAssets {
9
10
  /** Name → the URL (or URLs) the page reads as `ctx.assets.<name>`. */
@@ -144,14 +145,13 @@ interface ReleaseWords {
144
145
  brand?: string | null;
145
146
  release?: string | null;
146
147
  }
148
+ /**
149
+ * The catalog as `GET /api/music` answers it: each track with what the
150
+ * library measured and a person wrote about it (`BedTrack`, the ranking's
151
+ * input), plus the built-in effects.
152
+ */
147
153
  interface MusicCatalog {
148
- tracks: {
149
- slug: string;
150
- title: string;
151
- mood?: string;
152
- duration: number;
153
- url: string;
154
- }[];
154
+ tracks: BedTrack[];
155
155
  sfx: {
156
156
  slug: string;
157
157
  title: string;
@@ -177,6 +177,12 @@ interface MotionProposalInput {
177
177
  caption: string;
178
178
  }[];
179
179
  catalog: MusicCatalog | null;
180
+ /**
181
+ * The film as the music ranking reads it (`filmSummaryOf`), so a mood
182
+ * or a few words in `music:` pick the bed that fits THIS cut; absent,
183
+ * a mood picks the first track of that mood.
184
+ */
185
+ film?: FilmSummary;
180
186
  /** The templates the recipe or the flags named, resolved, in order. */
181
187
  templates?: MotionTemplate[];
182
188
  }
@@ -512,6 +518,12 @@ declare function startTakeServer(rootDir: string, pages: Record<string, string>)
512
518
  /** Poll a capture/encode page for window.__done / __error / __progress. */
513
519
  declare function waitForPageDone(page: Page, label: string, onProgress: (fraction: number) => void, timeoutMs: number): Promise<Record<string, unknown>>;
514
520
 
521
+ /** Where the store lives; tests hand in a scratch pair. */
522
+ interface Store {
523
+ credentialsPath: string;
524
+ accountsDir: string;
525
+ }
526
+
515
527
  /**
516
528
  * Origin resolution: --origin (or legacy --api) → VOS_ORIGIN → legacy
517
529
  * VOS_API_BASE (which historically carried a trailing /api) → https://vos.so.
@@ -526,14 +538,26 @@ declare function platformOrigin(flags?: {
526
538
  * (/embed/vos/{id}), or a studio/stage URL (?vos={id}).
527
539
  */
528
540
  declare function parseVosId(input: string): string;
541
+ interface CredentialAsk {
542
+ /** `--key`: goes where the command goes. */
543
+ key?: string;
544
+ /** `--account <handle|id>`: a stored credential for the origin, by name. */
545
+ account?: string;
546
+ /** The origin in use; the store is read for it. Default: the platform origin. */
547
+ origin?: string;
548
+ /** Tests hand in a scratch store. */
549
+ store?: Store;
550
+ }
529
551
  /**
530
- * The full documented ladder: explicit --key → VOS_API_KEY → the
531
- * credential `vos login` stored. A vos_rg_ remix grant is just a key here.
532
- * Returns null when nothing resolves — callers decide whether auth is needed.
533
- * A stored key is remembered with its origin: it is only ever SENT there
534
- * (`bearerFor`).
552
+ * The full documented ladder: `--key` → `--account` → VOS_API_KEY →
553
+ * VOS_ACCOUNT → the active credential `vos login` stored. A vos_rg_ remix
554
+ * grant is just a key here. Returns null when nothing resolves — callers
555
+ * decide whether auth is needed. A stored key is remembered with its
556
+ * origin: it is only ever SENT there (`bearerFor`). A name that names no
557
+ * stored credential is an error in words, never a silent fall-through,
558
+ * because the person said which account and must not get another.
535
559
  */
536
- declare function resolveCredential(explicit?: string, path?: string): string | null;
560
+ declare function resolveCredential(explicit?: string | CredentialAsk, path?: string): string | null;
537
561
  interface ApiResult {
538
562
  status: number;
539
563
  body: Record<string, unknown>;
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  startTakeServer,
15
15
  validateActions,
16
16
  waitForPageDone
17
- } from "./chunk-DM7ADA77.js";
17
+ } from "./chunk-ZXFO32KW.js";
18
18
  import {
19
19
  BrowserUnavailableError,
20
20
  configDuration,
@@ -23,13 +23,13 @@ import {
23
23
  previewPages,
24
24
  renderStill,
25
25
  renderVideo
26
- } from "./chunk-Q47FUCYN.js";
26
+ } from "./chunk-2LAXJZCG.js";
27
27
  import {
28
28
  RECORDING_NAME,
29
29
  loadTake,
30
30
  pullMedia,
31
31
  takePaths
32
- } from "./chunk-M5ZBQFPG.js";
32
+ } from "./chunk-V3RUNUNP.js";
33
33
  import {
34
34
  apiError,
35
35
  apiJson,
@@ -38,11 +38,11 @@ import {
38
38
  readSyncState,
39
39
  resolveCredential,
40
40
  writeSyncState
41
- } from "./chunk-EPSYIF2S.js";
41
+ } from "./chunk-PZP76YJI.js";
42
42
  import "./chunk-6XPFWQKP.js";
43
43
  import {
44
44
  manifest
45
- } from "./chunk-OWYOJB7K.js";
45
+ } from "./chunk-7A3PZARL.js";
46
46
  export {
47
47
  BrowserUnavailableError,
48
48
  RECORDING_NAME,
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ manifest
4
+ } from "./chunk-7A3PZARL.js";
5
+ export {
6
+ manifest
7
+ };
8
+ //# sourceMappingURL=manifest-OLVFUZTW.js.map
@@ -9,10 +9,10 @@ import {
9
9
  takeBackdrop,
10
10
  takeBrowserArgs,
11
11
  verbHelp
12
- } from "./chunk-DM7ADA77.js";
13
- import "./chunk-Q47FUCYN.js";
14
- import "./chunk-M5ZBQFPG.js";
15
- import "./chunk-EPSYIF2S.js";
12
+ } from "./chunk-ZXFO32KW.js";
13
+ import "./chunk-2LAXJZCG.js";
14
+ import "./chunk-V3RUNUNP.js";
15
+ import "./chunk-PZP76YJI.js";
16
16
  import "./chunk-6XPFWQKP.js";
17
17
  export {
18
18
  HELP,
@@ -25,4 +25,4 @@ export {
25
25
  takeBrowserArgs,
26
26
  verbHelp
27
27
  };
28
- //# sourceMappingURL=run-J5Z32LEB.js.map
28
+ //# sourceMappingURL=run-KB36L2ZI.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vosjs/cli",
3
- "version": "0.84.0",
3
+ "version": "0.86.0",
4
4
  "description": "The vos CLI: record the real product from a scripted browser flow, auto-zoom from the cursor track, cut as data in doc.json, render deterministic video, deliver a release's video cuts per destination spec, and sync with vos.so. One binary, every verb, MIT.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -51,14 +51,14 @@
51
51
  "acorn-walk": "^8.3.5",
52
52
  "mediabunny": "^1.55.7",
53
53
  "playwright": "^1.49.0",
54
- "@vosjs/elements": "^0.12.1",
55
- "@vosjs/render-core": "^0.12.0",
56
- "@vosjs/shared": "^0.7.0",
57
- "@vosjs/studio-core": "^0.46.0",
54
+ "@vosjs/core": "^0.31.0",
55
+ "@vosjs/shared": "^0.8.0",
58
56
  "@vosjs/editor": "^1.6.0",
59
- "@vosjs/tween": "^0.8.3",
57
+ "@vosjs/elements": "^0.12.1",
58
+ "@vosjs/render-core": "^0.12.1",
60
59
  "@vosjs/timeline": "^0.5.0",
61
- "@vosjs/core": "^0.31.0"
60
+ "@vosjs/studio-core": "^0.47.0",
61
+ "@vosjs/tween": "^0.8.3"
62
62
  },
63
63
  "devDependencies": {
64
64
  "@types/node": "^22",
package/skills/VERSION CHANGED
@@ -1 +1 @@
1
- 0.28.0
1
+ 0.29.0
@@ -58,7 +58,7 @@ Five facts before any recording:
58
58
  ```yaml
59
59
  headline: "Two to six words\nover up to three lines" # the end card
60
60
  kicker: "PRODUCT V2.1" # absent = the wordmark plus --release
61
- music: upbeat # a catalog slug or mood; none = silent
61
+ music: upbeat # a catalog slug, a mood or a few words (ranked against the cut by vos plan); none = silent
62
62
  entrance: tilt-in # tilt-in | pull-out | rise | none
63
63
  endCard: on # the official End card template; none switches it off; a title, vos id or doc.json names another
64
64
  with: "<template>@start" # optional: any template laid at an anchor (@end | @start | @step:<id> | @<seconds>)
@@ -132,7 +132,11 @@ arriving word by word, the release line and the URL settle on the ground;
132
132
  its clips are stamped `from: endcard`), any template `with:` names at its
133
133
  anchor, a caption per step, a music bed and a click sound on every press
134
134
  when the take has no mic; every proposal carries a stable id (`bed`,
135
- `click-<n>`, `caption-<step>`). On an existing cut `--motion` re-proposes;
135
+ `click-<n>`, `caption-<step>`). The bed is RANKED against the cut, never
136
+ the first track of a mood: `music: upbeat` (or a few words) goes through
137
+ `vos music pick`'s ranking inside the plan, its report names the pick and
138
+ the runner-up, and a slug stays that track; name the runner-up in the
139
+ version note and ask the person to listen. On an existing cut `--motion` re-proposes;
136
140
  a refresh never does, so a deleted end card stays deleted. A template is a
137
141
  plain take on a shelf whose clips carry stable ids; a ref is a title on the
138
142
  official shelf (`"End card"`), a vos id, or a document on disk. Open the
@@ -133,7 +133,13 @@ person before recording**; an answer that does neither was not an answer.
133
133
  heard, and a downloaded output's own sound rides as a clip through
134
134
  `vos join`. When the sound IS the point (a voice preview, a generated
135
135
  clip) and the product synthesizes it, say so before recording and plan
136
- the download; when it is not, say the video is silent and score it.
136
+ the download; when it is not, say the video is silent and score it:
137
+ `vos music pick <take>` ranks the library against THIS cut (its length,
138
+ its captions and joins as the beats, its payoff, whether a voice plays)
139
+ and prints the `vos score` line that places each pick, so run
140
+ `vos score <take> --track best` (or the pick you prefer), name the
141
+ runner-up in the version note, and ask the person to listen, because
142
+ you cannot.
137
143
 
138
144
  ## The core loop (every destination)
139
145
 
@@ -309,8 +315,12 @@ person before recording**; an answer that does neither was not an answer.
309
315
  video needs `duration` (OUTPUT-anchored modulo loop); `dim` 0..1 scrim.
310
316
  Ambience, not a subject — dim it behind dense UI.
311
317
  - `audio`: OUTPUT-anchored clips; `key` may be a file dropped into the
312
- take dir (`"/music.mp3"`); gain/fades/loop. Muxed on full renders
313
- (Opus/AAC); `--range` stays silent; forces single-flight.
318
+ take dir (`"/music.mp3"`) or a library track; gain/fades/loop. Muxed
319
+ on full renders (Opus/AAC); `--range` stays silent; forces
320
+ single-flight. A library bed is picked by `vos music pick`, never by
321
+ a mood alone: the library knows each track's beat, intro, seam,
322
+ ending and vocals, and the ranking refuses what cannot cover the
323
+ cut, starts in a quiet intro, or sings under a voice.
314
324
  - export: `{"resolution": "720p|1080p|2k|4k", "fps": 30}` — never above
315
325
  the footage (validate warns).
316
326
  Then `vos validate take --json` — lints must pass.
@@ -192,8 +192,12 @@ Per beat, against `plan` and the recipe:
192
192
  the last frame, with `still` on it and the one `"zoom": true` mark;
193
193
  a recap card listing the path in the captions' words on the plate after
194
194
  the card fades; an off-camera wait said in measured time (`{elapsed}`
195
- in the caption after it); music scored `--at` the result's step. Never
196
- a caption the footage does not show, never a second door.
195
+ in the caption after it); music picked for the cut (`vos music pick
196
+ <take> --at <result step>`: the library's beats, intros and vocals
197
+ against this cut's length, captions, joins and voice) and scored `--at`
198
+ the result's step (`vos score <take> --track best` places the first
199
+ pick there), the runner-up named in the version note, the person asked
200
+ to listen. Never a caption the footage does not show, never a second door.
197
201
  - **Style.** In a series, `vos plan --style <seed>` BEFORE you cut: it copies
198
202
  the seed's `zoomStyle`/`zoomParams`/`speedParams`/`tiltStyle`/`frame`/
199
203
  `cursor`/`cam`/`export` and re-plans the auto spans under them. Never
@@ -6,11 +6,21 @@ license: MIT
6
6
 
7
7
  # Compose a score for a vos program
8
8
 
9
- A catalog track (`GET https://vos.so/api/music`: CC0, a slug, a mood, a
10
- length) carries no tempo and no downbeats, and you cannot listen to it. Under
11
- an ambient picture that is fine. Under a picture that moves on a beat, it is
12
- wrong in ways you will not hear: the kick lands between the poses, the drop
13
- arrives two bars early, the loud part sits under the quiet scene.
9
+ Try the library first: `vos music pick <take|config.json>` ranks every
10
+ catalog track (`GET https://vos.so/api/music`: CC0, each with its beat grid
11
+ and a confidence, its quiet intro, its loop seam, its ending, its sections,
12
+ its vocals and a sentence a person wrote) against THIS film's length, cuts
13
+ and payoff, and prints the `vos score` line that places each pick with its
14
+ swell on the payoff and its beats under the cuts. Under an ambient picture,
15
+ or a how-to that cuts on a few captions, the first pick is the answer:
16
+ `vos score <take> --track best`.
17
+
18
+ Compose when the picture is CHOREOGRAPHED: `pick` says no bed reaches the
19
+ beat fit the picture needs (every cut a tenth of a beat off, an uncertain
20
+ beat it would not score, every track refused), or the film dances, snaps
21
+ poses or animates on a grid of its own. A catalog track cannot be bent to
22
+ that grid, and you cannot listen to it: the kick lands between the poses,
23
+ the drop arrives two bars early, the loud part sits under the quiet scene.
14
24
 
15
25
  So write the music instead. The score is a spec (tempo, chords, a riff, a
16
26
  hook, sections by bar) that `scripts/compose.py` synthesizes into a WAV at