@vosjs/cli 0.53.6 → 0.54.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 +14 -0
- package/dist/{chunk-WLUWDQQO.js → chunk-JX2YEL3M.js} +251 -1
- package/dist/chunk-JX2YEL3M.js.map +1 -0
- package/dist/{chunk-MJYXP4AA.js → chunk-M7FLXLBN.js} +1534 -181
- package/dist/chunk-M7FLXLBN.js.map +1 -0
- package/dist/{chunk-2EHIFIYC.js → chunk-WZGCEAXB.js} +13 -1
- package/dist/chunk-WZGCEAXB.js.map +1 -0
- package/dist/cli.js +15 -15
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +6 -8
- package/dist/manifest-Q4QMVIYR.js +8 -0
- package/dist/{run-DYNCGXWO.js → run-SYDEWMK2.js} +3 -3
- package/package.json +7 -5
- package/skills/VERSION +1 -1
- package/skills/vos-port/SKILL.md +25 -22
- package/dist/chunk-2EHIFIYC.js.map +0 -1
- package/dist/chunk-MJYXP4AA.js.map +0 -1
- package/dist/chunk-WLUWDQQO.js.map +0 -1
- package/dist/chunk-ZCLGXETO.js +0 -249
- package/dist/chunk-ZCLGXETO.js.map +0 -1
- package/dist/manifest-IG2WSARS.js +0 -8
- /package/dist/{manifest-IG2WSARS.js.map → manifest-Q4QMVIYR.js.map} +0 -0
- /package/dist/{run-DYNCGXWO.js.map → run-SYDEWMK2.js.map} +0 -0
|
@@ -46,6 +46,18 @@ var manifest = {
|
|
|
46
46
|
name: "ingest",
|
|
47
47
|
summary: "a take from a recording someone else made, with its cursor track from a trace beside it (Playwright trace.zip, stamped records, CSV); without one nothing is planned"
|
|
48
48
|
},
|
|
49
|
+
{
|
|
50
|
+
name: "port",
|
|
51
|
+
summary: "bring a page, a HyperFrames or a Remotion piece: inventory (its words, colours, faces, media, scenes) then scaffold (a data-first program.mjs to translate the motion into)"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: "build",
|
|
55
|
+
summary: "program.mjs (real functions) \u2192 config.json, refusing what cannot run on its own (module-scope reads, syntax the page cannot parse, non-JSON data)"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: "compare",
|
|
59
|
+
summary: "a program against the source's own render: per-frame SSIM and source | vos | difference sheets; exits 1 when any frame is under the threshold"
|
|
60
|
+
},
|
|
49
61
|
{
|
|
50
62
|
name: "brand",
|
|
51
63
|
summary: "write a product's BRAND.md, witnessed: /design.md, /llms.txt, then the page (palette, faces, marks, the avoid list)"
|
|
@@ -101,4 +113,4 @@ var manifest = {
|
|
|
101
113
|
export {
|
|
102
114
|
manifest
|
|
103
115
|
};
|
|
104
|
-
//# sourceMappingURL=chunk-
|
|
116
|
+
//# sourceMappingURL=chunk-WZGCEAXB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugin/manifest.ts"],"sourcesContent":["/**\n * The verb manifest of the take pipeline and the vos.so verbs — what\n * `vos help` lists under the engine verbs. It kept the shape a separately\n * installed plugin once handed the host (name + host range), so a script\n * reading it keeps working.\n */\nexport interface PluginVerb {\n name: string\n summary: string\n}\n\nexport interface PluginManifest {\n name: string\n /** Host versions this plugin speaks the run(argv) contract with. */\n hostRange: string\n verbs: PluginVerb[]\n}\n\nexport const manifest: PluginManifest = {\n name: '@vosjs/cli',\n hostRange: '>=0.9.0',\n verbs: [\n {\n name: 'create',\n summary: 'record + auto-plan + render, one command (--strict)',\n },\n {\n name: 'record',\n summary: 'drive actions.json into a take (screencast + cursor track)',\n },\n {\n name: 'plan',\n summary:\n 'plan zoom/cursor effects into doc.json (wand contract); --reuse re-times a previous cut onto a re-recording',\n },\n {\n name: 'render',\n summary: 'render a take directory (engine configs render in the host)',\n },\n {\n name: 'frames',\n summary:\n 'PNG stills at output times / zoom apexes / moments / exact sizes',\n },\n {\n name: 'deliver',\n summary:\n 'render a take to release destinations (CWS, Product Hunt, X, LinkedIn, OG…) + verified kit.json',\n },\n {\n name: 'digest',\n summary:\n 'see a recording before cutting it: moments (clicks, typing, scrolls, idle, scenes) + footage frames + crops, in doc units',\n },\n { name: 'open', summary: 'serve the take into the vos.so studio' },\n {\n name: 'validate',\n summary:\n 'lint actions.json, a take dir (doc.json semantics), or re-measure a kit.json against the channel specs',\n },\n {\n name: 'actions',\n summary:\n 'from-agent-browser: turn an agent-browser walk (steps.jsonl) into actions.json; what cannot follow is named',\n },\n {\n name: 'ingest',\n summary:\n 'a take from a recording someone else made, with its cursor track from a trace beside it (Playwright trace.zip, stamped records, CSV); without one nothing is planned',\n },\n {\n name: 'port',\n summary:\n 'bring a page, a HyperFrames or a Remotion piece: inventory (its words, colours, faces, media, scenes) then scaffold (a data-first program.mjs to translate the motion into)',\n },\n {\n name: 'build',\n summary:\n 'program.mjs (real functions) → config.json, refusing what cannot run on its own (module-scope reads, syntax the page cannot parse, non-JSON data)',\n },\n {\n name: 'compare',\n summary:\n \"a program against the source's own render: per-frame SSIM and source | vos | difference sheets; exits 1 when any frame is under the threshold\",\n },\n {\n name: 'brand',\n summary:\n \"write a product's BRAND.md, witnessed: /design.md, /llms.txt, then the page (palette, faces, marks, the avoid list)\",\n },\n {\n name: 'fetch',\n summary: 'download a hosted program: config.json + vos.json tracking',\n },\n {\n name: 'push',\n summary: 'push a config.json or take to vos.so (private; versioned)',\n },\n {\n name: 'duplicate',\n summary:\n 'a private sibling of your OWN vos (someone else\\u2019s is remixed: fetch + push --remix-of)',\n },\n {\n name: 'pull',\n summary:\n 'sync what changed on vos.so since your base (--media brings a take’s footage home)',\n },\n {\n name: 'folder',\n summary:\n 'list/create/pull folders, move voses and assets into them (pull = the context package on disk)',\n },\n {\n name: 'asset',\n summary: 'rename one of your assets in place (recipes included)',\n },\n {\n name: 'recipe',\n summary:\n 'push a recipe .md into a folder, or replace one in place (prior body kept)',\n },\n {\n name: 'login',\n summary: 'sign in via the browser (or --key); stores a content key',\n },\n {\n name: 'setup',\n summary:\n 'ready this machine: the vos skills into your agent, a browser, one rules block, then doctor',\n },\n {\n name: 'doctor',\n summary:\n 'what is ready, in words: node, browser, ffmpeg, skills, a credential (never printed), the dev server',\n },\n {\n name: 'whoami',\n summary: 'the key’s name and the account it belongs to, never the key',\n },\n { name: 'logout', summary: 'remove ~/.config/vos/credentials' },\n ],\n}\n"],"mappings":";;;AAkBO,IAAM,WAA2B;AAAA,EACtC,MAAM;AAAA,EACN,WAAW;AAAA,EACX,OAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA,EAAE,MAAM,QAAQ,SAAS,wCAAwC;AAAA,IACjE;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA,EAAE,MAAM,UAAU,SAAS,mCAAmC;AAAA,EAChE;AACF;","names":[]}
|
package/dist/cli.js
CHANGED
|
@@ -1,12 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
inspectStill,
|
|
4
|
-
previewPages,
|
|
5
|
-
reencodeStill,
|
|
6
|
-
renderStill,
|
|
7
|
-
renderVideo,
|
|
8
|
-
stillWarnings
|
|
9
|
-
} from "./chunk-ZCLGXETO.js";
|
|
10
2
|
import {
|
|
11
3
|
BrowserUnavailableError,
|
|
12
4
|
MEDIA_HEAD_BYTES,
|
|
@@ -15,6 +7,7 @@ import {
|
|
|
15
7
|
configDuration,
|
|
16
8
|
directoryKind,
|
|
17
9
|
helpFlagsFor,
|
|
10
|
+
inspectStill,
|
|
18
11
|
launchBrowser,
|
|
19
12
|
loadProgramDirectory,
|
|
20
13
|
loadVosConfig,
|
|
@@ -22,15 +15,20 @@ import {
|
|
|
22
15
|
parseArgs,
|
|
23
16
|
parseTimes,
|
|
24
17
|
platformOrigin,
|
|
18
|
+
previewPages,
|
|
25
19
|
readSourceText,
|
|
20
|
+
reencodeStill,
|
|
21
|
+
renderStill,
|
|
22
|
+
renderVideo,
|
|
26
23
|
resolveCredential,
|
|
27
24
|
resolveMediaType,
|
|
28
25
|
setFlags,
|
|
29
26
|
stillFormat,
|
|
30
27
|
stillOutFor,
|
|
28
|
+
stillWarnings,
|
|
31
29
|
unusedFlagsMessage,
|
|
32
30
|
videoFormat
|
|
33
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-JX2YEL3M.js";
|
|
34
32
|
|
|
35
33
|
// src/cli.ts
|
|
36
34
|
import { writeFile } from "fs/promises";
|
|
@@ -445,7 +443,8 @@ async function cmdRender(argv) {
|
|
|
445
443
|
await writeFile(out, result.bytes);
|
|
446
444
|
const warnings = stillWarnings(
|
|
447
445
|
{ transparent: false, flat: false },
|
|
448
|
-
result.pageErrors
|
|
446
|
+
result.pageErrors,
|
|
447
|
+
result.engineNotes
|
|
449
448
|
);
|
|
450
449
|
for (const w of warnings) r.log(`warn: ${w}`);
|
|
451
450
|
r.done(
|
|
@@ -509,7 +508,8 @@ async function cmdStill(argv) {
|
|
|
509
508
|
await writeFile(target, bytes);
|
|
510
509
|
const warnings = stillWarnings(
|
|
511
510
|
await inspectStill(browser, result.bytes),
|
|
512
|
-
result.pageErrors
|
|
511
|
+
result.pageErrors,
|
|
512
|
+
result.engineNotes
|
|
513
513
|
);
|
|
514
514
|
written.push({
|
|
515
515
|
out: target,
|
|
@@ -728,7 +728,7 @@ async function cmdCheck(argv) {
|
|
|
728
728
|
return result.ok ? EXIT_OK : EXIT_ERROR;
|
|
729
729
|
}
|
|
730
730
|
async function delegate(argv, viaAlias = false) {
|
|
731
|
-
const { run } = await import("./run-
|
|
731
|
+
const { run } = await import("./run-SYDEWMK2.js");
|
|
732
732
|
if (viaAlias && argv[0]) {
|
|
733
733
|
process.stderr.write(
|
|
734
734
|
`note: "vos voila ${argv[0]}" is now "vos ${argv[0]}".
|
|
@@ -739,7 +739,7 @@ async function delegate(argv, viaAlias = false) {
|
|
|
739
739
|
}
|
|
740
740
|
async function printHelp() {
|
|
741
741
|
process.stdout.write(HELP_ENGINE);
|
|
742
|
-
const { manifest } = await import("./manifest-
|
|
742
|
+
const { manifest } = await import("./manifest-Q4QMVIYR.js");
|
|
743
743
|
process.stdout.write("\nTake pipeline + vos.so verbs\n");
|
|
744
744
|
for (const v of manifest.verbs) {
|
|
745
745
|
if (v.name === "render") continue;
|
|
@@ -768,7 +768,7 @@ async function main() {
|
|
|
768
768
|
const engine = HELP_ENGINE.split("\n").filter(
|
|
769
769
|
(l) => l.startsWith(` vos ${cmd} `)
|
|
770
770
|
);
|
|
771
|
-
const { verbHelp } = await import("./run-
|
|
771
|
+
const { verbHelp } = await import("./run-SYDEWMK2.js");
|
|
772
772
|
const take = verbHelp(cmd);
|
|
773
773
|
process.stdout.write(
|
|
774
774
|
`${engine.join("\n")}
|
|
@@ -800,7 +800,7 @@ ${take.includes("no such verb") ? "" : take}`
|
|
|
800
800
|
main().then(async (code) => {
|
|
801
801
|
if (code === EXIT_OK) {
|
|
802
802
|
const verb = process.argv[2] ?? "";
|
|
803
|
-
const { HELP } = await import("./run-
|
|
803
|
+
const { HELP } = await import("./run-SYDEWMK2.js");
|
|
804
804
|
const documented = [
|
|
805
805
|
...helpFlagsFor(HELP_ENGINE, verb),
|
|
806
806
|
...helpFlagsFor(HELP, verb)
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/output.ts","../src/check.ts","../src/plugin/knobs.ts","../src/programAudio.ts"],"sourcesContent":["import { writeFile } from 'node:fs/promises'\nimport { existsSync, readFileSync, statSync } from 'node:fs'\nimport { basename, dirname, join } from 'node:path'\nimport { createServer } from 'node:http'\nimport { createRequire } from 'node:module'\nimport { fileURLToPath } from 'node:url'\nimport { parseArgs, numFlag, UsageError } from './args'\nimport { helpFlagsFor, unusedFlagsMessage } from './flagUse'\nimport {\n createReporter,\n EXIT_ERROR,\n EXIT_NO_BROWSER,\n EXIT_OK,\n EXIT_USAGE,\n} from './output'\nimport {\n loadVosConfig,\n configDuration,\n directoryKind,\n loadProgramDirectory,\n readSourceText,\n} from './loadConfig'\nimport { launchBrowser, BrowserUnavailableError } from './browser'\nimport {\n inspectStill,\n previewPages,\n reencodeStill,\n renderStill,\n renderVideo,\n stillWarnings,\n} from './render'\nimport { runCheck } from './check'\nimport { programAudio } from './programAudio'\nimport {\n applyDataSets,\n parseTimes,\n setFlags,\n stillFormat,\n stillOutFor,\n videoFormat,\n} from './outputs'\nimport { platformOrigin, resolveCredential } from './plugin/platform'\n\nconst BOOLEAN_FLAGS = new Set(['json', 'help', 'version'])\n\nconst HELP_ENGINE = `vos — command line for the vos programmatic video engine (https://vos.so/engine)\n\nEngine verbs (local, no account, no network beyond the render page's CDN deps)\n vos render <config.json|url|take> [out.mp4|out.webm] [--width 1920] [--height 1080] [--fps 30]\n [--duration <s>] [--format webm|mp4] [--set data.<key>=<value>]... [--json]\n the output's name picks the container; a program document's sound is mixed in\n vos still <config.json|url> [out.webp|out.png|out.jpg] [--time 0 | --times 0,1.5,50%]\n [--width] [--height] [--set data.<key>=<value>]... [--json]\n vos info <config.json|url> [--json]\n vos check <config.json|url> [--json]\n migrate → schema → syntax → compile → determinism/dialect lints, all local\n vos preview <config.json|url> [--port 0]\n vos versions [--json]\n`\n\nconst HELP_CONVENTIONS = `\nConventions\n Results go to stdout; logs go to stderr. --json switches stdout to NDJSON\n events ending with {\"event\":\"done\",…}. Exit codes: 0 ok, 1 error, 2 usage,\n 3 no browser available, 4 the recorder met a sign-in instead of the page\n it was asked for (nothing was recorded; it needs a session, not a new\n script). vos <verb> --help prints that verb's flags.\n`\n\n/** An `audio` element in the config: something a render never mixes. */\nfunction hasAudioElements(config: unknown): boolean {\n const elements = (config as { elements?: unknown }).elements\n return (\n Array.isArray(elements) &&\n elements.some(\n (e) =>\n !!e &&\n typeof e === 'object' &&\n (e as { type?: unknown }).type === 'audio',\n )\n )\n}\n\nfunction outName(source: string, ext: string): string {\n const base = basename(source).replace(/\\.[a-z0-9]+$/i, '') || 'vos'\n return `${base}.${ext}`\n}\n\nasync function cmdRender(argv: string[]): Promise<number> {\n // Polymorphic render: a take DIRECTORY (its doc.json is a recording\n // document) renders through the plugin; a program directory (config.json,\n // composed with a program document when one sits beside it) and every\n // other source are engine config renders. A deterministic sniff, never a\n // flag — and the sniff reads the document, because a program directory\n // carries a doc.json too.\n const first = argv.find((a) => !a.startsWith('-'))\n if (first && directoryKind(first) === 'take') {\n return delegate(['render', ...argv])\n }\n const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS)\n const source = positionals[0]\n if (!source) throw new UsageError('vos render <config.json|url|take> [out]')\n const r = createReporter(flags.json === true)\n const format = videoFormat(\n flags.format === undefined ? undefined : String(flags.format),\n positionals[1],\n )\n\n const loaded = await loadVosConfig(source)\n for (const w of loaded.warnings) r.log(`note: ${w}`)\n void flags.set\n const config = applyDataSets(\n loaded.config as Record<string, unknown>,\n setFlags(argv),\n )\n const duration = numFlag(flags, 'duration', configDuration(config) ?? 5)\n const width = numFlag(flags, 'width', 1920)\n const height = numFlag(flags, 'height', 1080)\n const fps = numFlag(flags, 'fps', 30)\n const out = positionals[1] ?? outName(source, format)\n\n // A program document's sound rides its studio entry; mix it like a take's.\n const audio = await programAudio(config as Record<string, unknown>, {\n baseDir:\n existsSync(source) && statSync(source).isDirectory()\n ? source\n : dirname(source),\n duration,\n origin: platformOrigin({}),\n key: resolveCredential(),\n log: (line) => r.log(line),\n })\n if (audio) r.log(`mixing ${audio.clips} sound${audio.clips === 1 ? '' : 's'}`)\n if (hasAudioElements(config)) {\n r.log(\n 'note: an audio ELEMENT is not mixed by a render; put the sound on the program document instead (doc.json audio: [{ key, start, in, out, duration, gain }])',\n )\n }\n\n const browser = await launchBrowser()\n try {\n const result = await renderVideo(browser, {\n config,\n width,\n height,\n fps,\n duration,\n format,\n audioProducerCode: audio?.producerCode,\n onPhase: (phase) => {\n r.log(`${phase}…`)\n r.event({ event: 'phase', phase })\n },\n })\n await writeFile(out, result.bytes)\n const warnings = stillWarnings(\n { transparent: false, flat: false },\n result.pageErrors,\n )\n for (const w of warnings) r.log(`warn: ${w}`)\n r.done(\n {\n out,\n bytes: result.bytes.length,\n width,\n height,\n fps,\n duration,\n format,\n audio: audio?.clips ?? 0,\n ...(warnings.length ? { warnings } : {}),\n },\n `Wrote ${out} (${(result.bytes.length / 1024).toFixed(0)} KB, ${width}x${height}@${fps}, ${duration}s)`,\n )\n return EXIT_OK\n } finally {\n await browser.close()\n }\n}\n\nasync function cmdStill(argv: string[]): Promise<number> {\n const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS)\n const source = positionals[0]\n if (!source)\n throw new UsageError(\n 'vos still <config.json|url> [out.webp|out.png|out.jpg] [--time t | --times a,b,50%]',\n )\n const r = createReporter(flags.json === true)\n\n const loaded = await loadVosConfig(source)\n for (const w of loaded.warnings) r.log(`note: ${w}`)\n void flags.set\n const config = applyDataSets(\n loaded.config as Record<string, unknown>,\n setFlags(argv),\n )\n const width = numFlag(flags, 'width', 1280)\n const height = numFlag(flags, 'height', 720)\n const out = positionals[1] ?? outName(source, 'webp')\n const encoding = stillFormat(out)\n const timesRaw = flags.times === undefined ? undefined : String(flags.times)\n if (timesRaw !== undefined && flags.time !== undefined)\n throw new UsageError('--time and --times: pass one')\n const times =\n timesRaw !== undefined\n ? parseTimes(timesRaw, configDuration(config) ?? 5)\n : [numFlag(flags, 'time', 0)]\n const many = times.length > 1\n\n // One browser for every time: each still is its own capture page.\n const browser = await launchBrowser()\n try {\n const written: {\n out: string\n bytes: number\n time: number\n warnings?: string[]\n }[] = []\n for (const time of times) {\n const target = stillOutFor(out, time, many)\n const result = await renderStill(browser, {\n config,\n width,\n height,\n time,\n onPhase: (phase) => {\n r.event({ event: 'phase', phase, time })\n },\n })\n // The engine captures WebP; a .png or .jpg name is re-encoded in the\n // page, so the bytes always match the name.\n const bytes =\n encoding === 'webp'\n ? result.bytes\n : await reencodeStill(browser, result.bytes, encoding)\n await writeFile(target, bytes)\n // A still is checked before anyone looks at it: a fully transparent\n // or flat frame is written, and said, never passed off as a picture.\n const warnings = stillWarnings(\n await inspectStill(browser, result.bytes),\n result.pageErrors,\n )\n written.push({\n out: target,\n bytes: bytes.length,\n time,\n ...(warnings.length ? { warnings } : {}),\n })\n r.log(\n `Wrote ${target} (${(bytes.length / 1024).toFixed(0)} KB @ t=${Number(time.toFixed(2))}s)`,\n )\n for (const w of warnings)\n r.log(`warn: t=${Number(time.toFixed(2))}s ${w}`)\n }\n const first = written[0]\n r.done(\n many\n ? { stills: written, width, height, format: encoding }\n : { ...first, width, height, format: encoding },\n many\n ? `Wrote ${written.length} stills (${width}x${height})`\n : `Wrote ${first.out} (${(first.bytes / 1024).toFixed(0)} KB, ${width}x${height} @ t=${first.time}s)`,\n )\n return EXIT_OK\n } finally {\n await browser.close()\n }\n}\n\nasync function cmdInfo(argv: string[]): Promise<number> {\n const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS)\n const source = positionals[0]\n if (!source) throw new UsageError('vos info <config.json|url>')\n const r = createReporter(flags.json === true)\n\n const { config, warnings } = await loadVosConfig(source)\n const elements = Array.isArray(config.elements) ? config.elements.length : 0\n const data =\n typeof config.data === 'object' && config.data !== null\n ? Object.keys(config.data)\n : []\n const fns = ['setup', 'createContent', 'createTimeline', 'onFrame'].filter(\n (k) => typeof config[k] === 'string',\n )\n const info = {\n version: config.version,\n duration: configDuration(config) ?? null,\n camera:\n (config.camera as Record<string, unknown> | undefined)?.preset ?? null,\n elements,\n dataKeys: data,\n functions: fns,\n warnings,\n }\n if (r.json) r.done(info, '')\n else {\n for (const w of warnings) r.log(`note: ${w}`)\n process.stdout.write(\n `version: v${String(info.version)}\\n` +\n `duration: ${info.duration === null ? '(none)' : `${info.duration}s`}\\n` +\n `camera: ${String(info.camera ?? '(default)')}\\n` +\n `elements: ${elements}\\n` +\n `data keys: ${data.length ? data.join(', ') : '(none)'}\\n` +\n `functions: ${fns.join(', ')}\\n`,\n )\n }\n return EXIT_OK\n}\n\nfunction packageVersion(name: string): string | null {\n const require = createRequire(import.meta.url)\n // Fast path — packages that export ./package.json (e.g. playwright).\n try {\n return (require(`${name}/package.json`) as { version: string }).version\n } catch {\n // Strict `exports` maps (the @vosjs packages) hide package.json — resolve\n // the entry module instead and walk up to the owning package.json.\n }\n let entry: string | null = null\n try {\n entry = fileURLToPath(import.meta.resolve(name))\n } catch {\n try {\n entry = require.resolve(name)\n } catch {\n return null\n }\n }\n let dir = dirname(entry)\n for (let i = 0; i < 6; i++) {\n try {\n const pkg = JSON.parse(\n readFileSync(join(dir, 'package.json'), 'utf8'),\n ) as {\n name?: string\n version?: string\n }\n if (pkg.name === name && pkg.version) return pkg.version\n } catch {\n // keep walking\n }\n const parent = dirname(dir)\n if (parent === dir) return null\n dir = parent\n }\n return null\n}\n\nfunction ownVersion(): string {\n try {\n const own = JSON.parse(\n readFileSync(\n fileURLToPath(new URL('../package.json', import.meta.url)),\n 'utf8',\n ),\n ) as { version: string }\n return own.version\n } catch {\n return '(unknown)'\n }\n}\n\nasync function cmdVersions(argv: string[]): Promise<number> {\n const { flags } = parseArgs(argv, BOOLEAN_FLAGS)\n const r = createReporter(flags.json === true)\n const versions: Record<string, string> = {}\n versions['@vosjs/cli'] = ownVersion()\n for (const name of [\n '@vosjs/core',\n '@vosjs/elements',\n '@vosjs/tween',\n '@vosjs/editor',\n '@vosjs/timeline',\n '@vosjs/studio-core',\n '@vosjs/render-core',\n '@vosjs/shared',\n 'mediabunny',\n 'playwright',\n ]) {\n versions[name] = packageVersion(name) ?? '(not found)'\n }\n if (r.json) r.done({ versions }, '')\n else\n for (const [k, v] of Object.entries(versions))\n process.stdout.write(`${k} ${v}\\n`)\n return EXIT_OK\n}\n\nasync function cmdPreview(argv: string[]): Promise<number> {\n const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS)\n const source = positionals[0]\n if (!source) throw new UsageError('vos preview <config.json|url> [--port 0]')\n const r = createReporter(false)\n const { config, warnings } = await loadVosConfig(source)\n for (const w of warnings) r.log(`note: ${w}`)\n const { hostHtml, playerHtml } = previewPages(config)\n const server = createServer((req, res) => {\n const path = new URL(req.url ?? '/', 'http://x').pathname\n res.writeHead(200, { 'content-type': 'text/html' })\n res.end(path === '/player' ? playerHtml : hostHtml)\n })\n const port = numFlag(flags, 'port', 0)\n await new Promise<void>((resolve) => server.listen(port, resolve))\n const addr = server.address()\n const url = `http://localhost:${typeof addr === 'object' && addr ? addr.port : port}/`\n process.stdout.write(`${url}\\n`)\n r.log('Serving playback preview — Ctrl-C to stop.')\n await new Promise(() => {}) // keep alive until interrupted\n return EXIT_OK\n}\n\nasync function cmdCheck(argv: string[]): Promise<number> {\n const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS)\n const source = positionals[0]\n if (!source) throw new UsageError('vos check <config.json>')\n const r = createReporter(flags.json === true)\n\n // A directory is a take (refused here: its document is `vos validate`'s\n // job) or a program directory (config.json, composed with the program\n // document beside it so the ladder reads the layers' strings too).\n const kind = /^https?:\\/\\//.test(source) ? 'none' : directoryKind(source)\n if (kind === 'take') {\n throw new UsageError(\n `${source} is a take (its doc.json is a recording document). vos validate ${source} lints it; vos render ${source} renders it.`,\n )\n }\n let raw: string\n let parsed: unknown\n try {\n if (kind === 'program') {\n const notes: string[] = []\n parsed = await loadProgramDirectory(source, notes)\n for (const n of notes) r.log(`note: ${n}`)\n raw = ''\n } else {\n raw = await readSourceText(source)\n parsed = JSON.parse(raw)\n }\n } catch (e) {\n if (!(e instanceof SyntaxError)) throw e\n parsed = undefined\n if (!r.json) process.stdout.write(`error [json] ${(e as Error).message}\\n`)\n r.done(\n {\n ok: false,\n errors: 1,\n warnings: 0,\n issues: [\n { level: 'error', source: 'json', message: (e as Error).message },\n ],\n },\n `${source}: 1 error`,\n )\n return EXIT_ERROR\n }\n\n const result = runCheck(parsed)\n if (r.json) {\n r.done(\n {\n ok: result.ok,\n errors: result.errors,\n warnings: result.warnings,\n issues: result.issues,\n },\n '',\n )\n } else {\n for (const i of result.issues) {\n process.stdout.write(`${i.level} [${i.source}] ${i.message}\\n`)\n }\n process.stdout.write(\n result.ok\n ? `${source}: ok (${result.warnings} warning${result.warnings === 1 ? '' : 's'})\\n`\n : `${source}: ${result.errors} error${result.errors === 1 ? '' : 's'}, ${result.warnings} warning${result.warnings === 1 ? '' : 's'}\\n`,\n )\n }\n return result.ok ? EXIT_OK : EXIT_ERROR\n}\n\n// ---------------------------------------------------------------------------\n// Every verb this file does not own is a take-pipeline or vos.so verb from\n// `./plugin` (what used to ship separately as @vosso/vos-plugin). It loads on\n// demand, so the engine verbs never pay for the recorder's imports, and the\n// old names (`@vosso/cli`, `@vosso/voila-cli`, the `vos voila` alias) keep\n// resolving here for scripts that still use them.\n// ---------------------------------------------------------------------------\n\nasync function delegate(argv: string[], viaAlias = false): Promise<number> {\n const { run } = await import('./plugin/run')\n if (viaAlias && argv[0]) {\n process.stderr.write(\n `note: \"vos voila ${argv[0]}\" is now \"vos ${argv[0]}\".\\n`,\n )\n }\n return await run(argv)\n}\n\nasync function printHelp(): Promise<void> {\n process.stdout.write(HELP_ENGINE)\n const { manifest } = await import('./plugin/manifest')\n process.stdout.write('\\nTake pipeline + vos.so verbs\\n')\n for (const v of manifest.verbs) {\n if (v.name === 'render') continue // polymorphic — already listed above\n process.stdout.write(` vos ${v.name.padEnd(8)} ${v.summary}\\n`)\n }\n process.stdout.write(HELP_CONVENTIONS)\n}\n\nconst ENGINE_VERBS = new Set([\n 'render',\n 'still',\n 'info',\n 'versions',\n 'preview',\n 'check',\n])\n\nasync function main(): Promise<number> {\n const [cmd, ...rest] = process.argv.slice(2)\n if (!cmd || cmd === 'help' || cmd === '--help' || cmd === '-h') {\n await printHelp()\n return cmd ? EXIT_OK : EXIT_USAGE\n }\n if (cmd === '--version') return cmdVersions(['--json'])\n if (!ENGINE_VERBS.has(cmd) && cmd !== 'voila') return delegate([cmd, ...rest])\n // An engine verb asked for its flags: the engine's usage lines, plus the\n // take pipeline's where the verb is shared (render takes a config OR a take).\n if (rest.includes('--help') || rest.includes('-h')) {\n const engine = HELP_ENGINE.split('\\n').filter((l) =>\n l.startsWith(` vos ${cmd} `),\n )\n const { verbHelp } = await import('./plugin/run')\n const take = verbHelp(cmd)\n process.stdout.write(\n `${engine.join('\\n')}\\n${take.includes('no such verb') ? '' : take}`,\n )\n return EXIT_OK\n }\n switch (cmd) {\n case 'render':\n return cmdRender(rest)\n case 'still':\n return cmdStill(rest)\n case 'info':\n return cmdInfo(rest)\n case 'versions':\n return cmdVersions(rest)\n case 'preview':\n return cmdPreview(rest)\n case 'check':\n return cmdCheck(rest)\n // Hidden alias for existing scripts; not in HELP. Same code path as the\n // promoted verbs, plus a one-line pointer at the new spelling.\n case 'voila':\n return delegate(rest, true)\n default:\n throw new UsageError(`unknown command \"${cmd}\" — run vos help`)\n }\n}\n\nmain()\n .then(async (code) => {\n // A run that succeeded while ignoring a flag it was given did not do\n // what was asked (flagUse.ts): say so, and do not exit 0.\n if (code === EXIT_OK) {\n const verb = process.argv[2] ?? ''\n const { HELP } = await import('./plugin/run')\n const documented = [\n ...helpFlagsFor(HELP_ENGINE, verb),\n ...helpFlagsFor(HELP, verb),\n ]\n const message = unusedFlagsMessage(verb, [...new Set(documented)])\n if (message) {\n process.stderr.write(`usage error: ${message}\\n`)\n process.exit(EXIT_USAGE)\n }\n }\n process.exit(code)\n })\n .catch((e) => {\n if (e instanceof UsageError) {\n process.stderr.write(`usage error: ${e.message}\\n`)\n process.exit(EXIT_USAGE)\n }\n if (e instanceof BrowserUnavailableError) {\n process.stderr.write(`${e.message}\\n`)\n process.exit(EXIT_NO_BROWSER)\n }\n process.stderr.write(\n `error: ${e instanceof Error ? e.message : String(e)}\\n`,\n )\n process.exit(EXIT_ERROR)\n })\n","/**\n * Output conventions (agent-safe by construction):\n * - logs/progress → stderr (human readable)\n * - results → stdout; with --json, NDJSON events (`{\"event\":\"phase\"...}` then\n * `{\"event\":\"done\"...}`) so scripts and agents never parse prose\n * - exit codes: 0 ok · 1 failure · 2 usage · 3 browser unavailable ·\n * 4 the recorder met a sign-in (the take pipeline's wall check)\n */\nexport const EXIT_OK = 0\nexport const EXIT_ERROR = 1\nexport const EXIT_USAGE = 2\nexport const EXIT_NO_BROWSER = 3\n\nexport interface Reporter {\n json: boolean\n /** Human log line (stderr; suppressed in --json mode). */\n log: (msg: string) => void\n /** Machine event (stdout NDJSON in --json mode; no-op otherwise). */\n event: (obj: Record<string, unknown>) => void\n /** Final result: NDJSON `done` event in --json mode, plain line otherwise. */\n done: (obj: Record<string, unknown>, humanLine: string) => void\n}\n\nexport function createReporter(json: boolean): Reporter {\n return {\n json,\n log: (msg) => {\n if (!json) process.stderr.write(`${msg}\\n`)\n },\n event: (obj) => {\n if (json) process.stdout.write(`${JSON.stringify(obj)}\\n`)\n },\n done: (obj, humanLine) => {\n if (json)\n process.stdout.write(`${JSON.stringify({ event: 'done', ...obj })}\\n`)\n else process.stdout.write(`${humanLine}\\n`)\n },\n }\n}\n","/**\n * `vos check` — the local validation pipeline, pure so it can be unit-tested:\n * envelope unwrap → migrate → schema → compile → determinism + dialect lints.\n * Everything runs locally (no network, no browser). The platform runs the\n * same compiler server-side, so a clean check is a push that will compile.\n */\nimport {\n CURRENT_CONFIG_VERSION,\n compileVosConfig,\n migrateConfig,\n vosConfigJsonSchema,\n} from '@vosjs/core'\nimport {\n lintVosConfig,\n lintVosDialect,\n lintVosFonts,\n lintVosPostprocessing,\n} from '@vosjs/core/lint'\nimport { knobWarnings } from './plugin/knobs'\n\nexport interface CheckIssue {\n level: 'error' | 'warn'\n source:\n | 'schema'\n | 'syntax'\n | 'compile'\n | 'determinism'\n | 'dialect'\n | 'shape'\n | 'fonts'\n | 'postprocessing'\n message: string\n}\n\nexport interface CheckResult {\n ok: boolean\n errors: number\n warnings: number\n issues: CheckIssue[]\n /** The migrated config (params/presets untouched) — what a push should send. */\n config: Record<string, unknown> | null\n}\n\n// Top-level keys the schema does not know but the platform preserves on push.\nconst PLATFORM_EXTRA_KEYS = new Set(['params', 'presets'])\n\nexport function runCheck(parsed: unknown): CheckResult {\n const issues: CheckIssue[] = []\n const finish = (config: Record<string, unknown> | null): CheckResult => {\n const errors = issues.filter((i) => i.level === 'error').length\n return {\n ok: errors === 0,\n errors,\n warnings: issues.length - errors,\n issues,\n config,\n }\n }\n\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n issues.push({\n level: 'error',\n source: 'shape',\n message: 'not a JSON object',\n })\n return finish(null)\n }\n\n // API endpoints wrap the config: { config: {...} } — accept both shapes.\n let obj = parsed as Record<string, unknown>\n if (\n typeof obj.config === 'object' &&\n obj.config !== null &&\n !('createTimeline' in obj)\n ) {\n obj = obj.config as Record<string, unknown>\n }\n\n const version = obj.version\n let migrated: Record<string, unknown>\n try {\n migrated = migrateConfig(obj) as Record<string, unknown>\n } catch (e) {\n issues.push({\n level: 'error',\n source: 'shape',\n message: `migration failed: ${e instanceof Error ? e.message : String(e)}`,\n })\n return finish(null)\n }\n if (version === undefined) {\n // It compiles (the engine reads an absent version as the current one),\n // but a push is refused: a stored config must say which schema era it was\n // written against, and nobody can tell that from the file later.\n issues.push({\n level: 'warn',\n source: 'shape',\n message: `config declares no \"version\". It plays here, but a push is refused without one. Add \"version\": ${CURRENT_CONFIG_VERSION}.`,\n })\n } else if (version !== CURRENT_CONFIG_VERSION) {\n issues.push({\n level: 'warn',\n source: 'shape',\n message: `config is v${String(version)}, migrated to v${CURRENT_CONFIG_VERSION}. Save the migrated form.`,\n })\n }\n\n const schema = vosConfigJsonSchema.safeParse(migrated)\n if (!schema.success) {\n for (const i of schema.error.issues.slice(0, 10)) {\n issues.push({\n level: 'error',\n source: 'schema',\n message: `${i.path.join('.') || '(root)'}: ${i.message}`,\n })\n }\n return finish(null)\n }\n\n // Keys the platform's schema will silently drop on push (params/presets\n // excepted — those are re-attached by contract).\n const known = new Set([\n ...Object.keys(vosConfigJsonSchema.shape),\n ...PLATFORM_EXTRA_KEYS,\n ])\n for (const key of Object.keys(migrated)) {\n if (!known.has(key)) {\n issues.push({\n level: 'warn',\n source: 'shape',\n message: `unknown top-level key \"${key}\" — the platform drops it on push`,\n })\n }\n }\n\n // Knobs and Looks vos.so would drop (the push still saves, without them).\n for (const message of knobWarnings(migrated as Record<string, unknown>)) {\n issues.push({ level: 'warn', source: 'shape', message })\n }\n\n // Sound as an ELEMENT is not a track: no timeline row, no gain or fades,\n // nothing a render mixes, and a `data:` source inflates the config past\n // what a claimable push can carry. The document is where sound goes.\n const elements = Array.isArray(migrated.elements) ? migrated.elements : []\n for (const el of elements) {\n if (!el || typeof el !== 'object') continue\n const e = el as { type?: unknown; id?: unknown; src?: unknown }\n if (e.type !== 'audio') continue\n const inline =\n typeof e.src === 'string' && e.src.startsWith('data:')\n ? ` (embedded, ${Math.round(e.src.length / 1024)} KB of config)`\n : ''\n issues.push({\n level: 'warn',\n source: 'shape',\n message: `audio element \"${String(e.id ?? '?')}\"${inline} is not a track: renders do not mix it and the studio cannot edit it. Put the file beside the config and name it in doc.json (audio: [{ key: \"score.ogg\", start, in, out, duration, gain }]); vos push uploads it`,\n })\n }\n\n // Function strings are pasted into the template as text, so the compiler\n // cannot see a syntax error — parse each one here (construction only,\n // nothing executes).\n let syntaxErrors = 0\n for (const key of [\n 'setup',\n 'createContent',\n 'createTimeline',\n 'onFrame',\n ] as const) {\n const src = migrated[key]\n if (typeof src !== 'string' || !src.length) continue\n try {\n new Function(`\"use strict\"; return (${src}\\n)`)\n } catch (e) {\n syntaxErrors++\n issues.push({\n level: 'error',\n source: 'syntax',\n message: `${key}: ${e instanceof Error ? e.message : String(e)}`,\n })\n }\n }\n if (syntaxErrors) return finish(migrated)\n\n try {\n // Same options as `vos render` — a clean check is a config the CLI's own\n // render path will accept.\n compileVosConfig(migrated as never, { tweenEngine: 'vos' })\n } catch (e) {\n issues.push({\n level: 'error',\n source: 'compile',\n message: e instanceof Error ? e.message : String(e),\n })\n return finish(migrated)\n }\n\n for (const i of lintVosConfig(migrated as never)) {\n issues.push({\n level: i.severity === 'error' ? 'error' : 'warn',\n source: 'determinism',\n message: `${i.fn}:${i.line} [${i.rule}] ${i.message}`,\n })\n }\n for (const i of lintVosDialect(migrated as never)) {\n issues.push({\n level: i.severity === 'error' ? 'error' : 'warn',\n source: 'dialect',\n message: `${i.fn}:${i.line} [${i.rule}] ${i.message}`,\n })\n }\n for (const i of lintVosFonts(migrated as never)) {\n issues.push({\n level: 'warn',\n source: 'fonts',\n message: `[${i.rule}] ${i.message}`,\n })\n }\n for (const i of lintVosPostprocessing(migrated as never)) {\n issues.push({\n level: 'warn',\n source: 'postprocessing',\n message: `[${i.rule}] ${i.message}`,\n })\n }\n\n return finish(migrated)\n}\n","/**\n * What vos.so keeps of a config's knobs (`params`) and Looks (`presets`).\n *\n * A vos.so fact, so it lives in the platform client: the platform keeps at\n * most 12 knobs and 8 Looks, each within its field limits, and drops the\n * rest ONE BY ONE with a warning (it used to drop them all, silently). This\n * mirrors that rule so `vos check` says the same thing before a push does.\n */\nexport const MAX_PARAMS = 12\nexport const MAX_LOOKS = 8\n\nconst KINDS = new Set(['number', 'color', 'select', 'toggle', 'text', 'font'])\n\nconst str = (v: unknown, max: number, min = 0) =>\n typeof v === 'string' && v.length >= min && v.length <= max\n\n/** Why one knob would be dropped, or null when vos.so keeps it. */\nexport function knobProblem(p: unknown): string | null {\n if (!p || typeof p !== 'object') return 'not an object'\n const k = p as Record<string, unknown>\n if (!str(k.key, 40, 1)) return 'key must be 1 to 40 characters'\n if (typeof k.kind !== 'string' || !KINDS.has(k.kind))\n return `kind must be one of ${[...KINDS].join(', ')}`\n if (k.label !== undefined && !str(k.label, 60))\n return 'label: at most 60 characters'\n if (k.hint !== undefined && !str(k.hint, 140))\n return 'hint: at most 140 characters'\n if (k.unit !== undefined && !str(k.unit, 8))\n return 'unit: at most 8 characters'\n if (k.group !== undefined && !str(k.group, 24))\n return 'group: at most 24 characters'\n if (k.options !== undefined) {\n if (!Array.isArray(k.options) || k.options.length > 12)\n return 'options: at most 12'\n if (k.options.some((o) => !str(o, 40, 1)))\n return 'options: each 1 to 40 characters'\n }\n const d = k.default\n if (\n !(\n typeof d === 'number' ||\n typeof d === 'boolean' ||\n (typeof d === 'string' && d.length <= 280)\n )\n )\n return 'default must be a number, a boolean or at most 280 characters'\n return null\n}\n\n/** Why one Look would be dropped, or null when vos.so keeps it. */\nexport function lookProblem(l: unknown): string | null {\n if (!l || typeof l !== 'object') return 'not an object'\n const look = l as Record<string, unknown>\n if (!str(look.name, 24, 1)) return 'name must be 1 to 24 characters'\n if (!look.values || typeof look.values !== 'object') return 'values missing'\n return null\n}\n\n/** Every knob and Look vos.so would drop, in words, in order. */\nexport function knobWarnings(config: Record<string, unknown>): string[] {\n const out: string[] = []\n const sort = (\n raw: unknown,\n noun: 'knob' | 'look',\n field: string,\n max: number,\n problem: (e: unknown) => string | null,\n ) => {\n if (raw === undefined) return\n if (!Array.isArray(raw)) {\n out.push(`${noun === 'knob' ? 'params' : 'presets'} is not a list`)\n return\n }\n let kept = 0\n raw.forEach((entry, i) => {\n const id =\n entry && typeof (entry as Record<string, unknown>)[field] === 'string'\n ? `${noun} \"${String((entry as Record<string, unknown>)[field])}\"`\n : `${noun} #${i + 1}`\n const why = problem(entry)\n if (why) out.push(`${id} would be dropped on vos.so (${why})`)\n else if (kept >= max)\n out.push(\n `${id} would be dropped on vos.so: a vos keeps at most ${max} ${noun}s${noun === 'knob' ? ' (the rest can stay bound data)' : ''}`,\n )\n else kept += 1\n })\n }\n sort(config.params, 'knob', 'key', MAX_PARAMS, knobProblem)\n sort(config.presets, 'look', 'name', MAX_LOOKS, lookProblem)\n return out\n}\n","/**\n * The sound a program document adds, for a LOCAL render of the program.\n *\n * A composed program carries its `doc.audio` clips on the studio stack entry,\n * exactly as a take does, and the capture page mixes them through the same\n * producer a take render uses. The one difference is WHERE the bytes are: a\n * capture page has no origin of its own, so a clip keyed by a file beside the\n * document (`score.ogg`) or by a hosted asset path (`/api/assets/…`) cannot be\n * fetched from inside it. Each is inlined as a `data:` URI here: a local file\n * read from disk, a hosted asset downloaded with the caller's credential.\n * A clip that cannot be reached is left out and said, never a silent track.\n */\nimport { existsSync } from 'node:fs'\nimport { readFile } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { audioProducerCode, studioEntryData } from '@vosjs/render-core'\nimport { studioAudioPlan } from '@vosjs/studio-core'\nimport { MEDIA_HEAD_BYTES, resolveMediaType } from './plugin/container'\nimport type { EnvelopePoint, LoweredAudioClip } from '@vosjs/studio-core'\n\nexport interface ProgramAudioOptions {\n /** The directory the document's relative keys are read against. */\n baseDir: string\n /** The output length the mix is cut to, seconds. */\n duration: number\n /** For a clip keyed by a hosted asset: where it lives and who may read it. */\n origin?: string\n key?: string | null\n log: (line: string) => void\n}\n\nexport interface ProgramAudio {\n producerCode: string\n clips: number\n}\n\nfunction dataUri(bytes: Uint8Array, filename: string): string {\n const { type } = resolveMediaType({\n head: bytes.subarray(0, MEDIA_HEAD_BYTES),\n filename,\n })\n return `data:${type};base64,${Buffer.from(bytes).toString('base64')}`\n}\n\nasync function reach(\n clipKey: string,\n opts: ProgramAudioOptions,\n): Promise<string | null> {\n if (/^(data:|https?:)/.test(clipKey)) return clipKey\n if (clipKey.startsWith('/api/')) {\n if (!opts.origin || !opts.key) {\n opts.log(\n `note: sound ${clipKey} is a hosted asset and no credential is set, so the render leaves it out (vos login, or keep the file beside the document)`,\n )\n return null\n }\n const res = await fetch(`${opts.origin}${clipKey}`, {\n headers: { authorization: `Bearer ${opts.key}` },\n })\n if (!res.ok) {\n opts.log(\n `note: sound ${clipKey} could not be read (${res.status}), so the render leaves it out`,\n )\n return null\n }\n return dataUri(new Uint8Array(await res.arrayBuffer()), clipKey)\n }\n const file = join(opts.baseDir, clipKey.replace(/^\\/+/, ''))\n if (!existsSync(file)) {\n opts.log(\n `note: sound ${clipKey} is not beside the document, so the render leaves it out`,\n )\n return null\n }\n return dataUri(new Uint8Array(await readFile(file)), file)\n}\n\n/** The producer for a composed program's sound, or null when it adds none. */\nexport async function programAudio(\n config: Record<string, unknown>,\n opts: ProgramAudioOptions,\n): Promise<ProgramAudio | null> {\n const entry = studioEntryData(config.stack)\n const clips = Array.isArray(entry?.audio)\n ? (entry.audio as LoweredAudioClip[])\n : []\n if (!clips.length) return null\n const reached: LoweredAudioClip[] = []\n for (const clip of clips) {\n const key = await reach(clip.key, opts)\n if (key) reached.push({ ...clip, key })\n }\n if (!reached.length) return null\n const duckEnv = Array.isArray(entry?.duckEnv)\n ? (entry.duckEnv as EnvelopePoint[])\n : []\n const plan = studioAudioPlan(reached, duckEnv, opts.duration)\n return {\n producerCode: audioProducerCode({ plan }),\n clips: reached.length,\n }\n}\n"],"mappings":"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","names":["existsSync","join","existsSync","require","join"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/output.ts","../src/check.ts","../src/plugin/knobs.ts","../src/programAudio.ts"],"sourcesContent":["import { writeFile } from 'node:fs/promises'\nimport { existsSync, readFileSync, statSync } from 'node:fs'\nimport { basename, dirname, join } from 'node:path'\nimport { createServer } from 'node:http'\nimport { createRequire } from 'node:module'\nimport { fileURLToPath } from 'node:url'\nimport { parseArgs, numFlag, UsageError } from './args'\nimport { helpFlagsFor, unusedFlagsMessage } from './flagUse'\nimport {\n createReporter,\n EXIT_ERROR,\n EXIT_NO_BROWSER,\n EXIT_OK,\n EXIT_USAGE,\n} from './output'\nimport {\n loadVosConfig,\n configDuration,\n directoryKind,\n loadProgramDirectory,\n readSourceText,\n} from './loadConfig'\nimport { launchBrowser, BrowserUnavailableError } from './browser'\nimport {\n inspectStill,\n previewPages,\n reencodeStill,\n renderStill,\n renderVideo,\n stillWarnings,\n} from './render'\nimport { runCheck } from './check'\nimport { programAudio } from './programAudio'\nimport {\n applyDataSets,\n parseTimes,\n setFlags,\n stillFormat,\n stillOutFor,\n videoFormat,\n} from './outputs'\nimport { platformOrigin, resolveCredential } from './plugin/platform'\n\nconst BOOLEAN_FLAGS = new Set(['json', 'help', 'version'])\n\nconst HELP_ENGINE = `vos — command line for the vos programmatic video engine (https://vos.so/engine)\n\nEngine verbs (local, no account, no network beyond the render page's CDN deps)\n vos render <config.json|url|take> [out.mp4|out.webm] [--width 1920] [--height 1080] [--fps 30]\n [--duration <s>] [--format webm|mp4] [--set data.<key>=<value>]... [--json]\n the output's name picks the container; a program document's sound is mixed in\n vos still <config.json|url> [out.webp|out.png|out.jpg] [--time 0 | --times 0,1.5,50%]\n [--width] [--height] [--set data.<key>=<value>]... [--json]\n vos info <config.json|url> [--json]\n vos check <config.json|url> [--json]\n migrate → schema → syntax → compile → determinism/dialect lints, all local\n vos preview <config.json|url> [--port 0]\n vos versions [--json]\n`\n\nconst HELP_CONVENTIONS = `\nConventions\n Results go to stdout; logs go to stderr. --json switches stdout to NDJSON\n events ending with {\"event\":\"done\",…}. Exit codes: 0 ok, 1 error, 2 usage,\n 3 no browser available, 4 the recorder met a sign-in instead of the page\n it was asked for (nothing was recorded; it needs a session, not a new\n script). vos <verb> --help prints that verb's flags.\n`\n\n/** An `audio` element in the config: something a render never mixes. */\nfunction hasAudioElements(config: unknown): boolean {\n const elements = (config as { elements?: unknown }).elements\n return (\n Array.isArray(elements) &&\n elements.some(\n (e) =>\n !!e &&\n typeof e === 'object' &&\n (e as { type?: unknown }).type === 'audio',\n )\n )\n}\n\nfunction outName(source: string, ext: string): string {\n const base = basename(source).replace(/\\.[a-z0-9]+$/i, '') || 'vos'\n return `${base}.${ext}`\n}\n\nasync function cmdRender(argv: string[]): Promise<number> {\n // Polymorphic render: a take DIRECTORY (its doc.json is a recording\n // document) renders through the plugin; a program directory (config.json,\n // composed with a program document when one sits beside it) and every\n // other source are engine config renders. A deterministic sniff, never a\n // flag — and the sniff reads the document, because a program directory\n // carries a doc.json too.\n const first = argv.find((a) => !a.startsWith('-'))\n if (first && directoryKind(first) === 'take') {\n return delegate(['render', ...argv])\n }\n const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS)\n const source = positionals[0]\n if (!source) throw new UsageError('vos render <config.json|url|take> [out]')\n const r = createReporter(flags.json === true)\n const format = videoFormat(\n flags.format === undefined ? undefined : String(flags.format),\n positionals[1],\n )\n\n const loaded = await loadVosConfig(source)\n for (const w of loaded.warnings) r.log(`note: ${w}`)\n void flags.set\n const config = applyDataSets(\n loaded.config as Record<string, unknown>,\n setFlags(argv),\n )\n const duration = numFlag(flags, 'duration', configDuration(config) ?? 5)\n const width = numFlag(flags, 'width', 1920)\n const height = numFlag(flags, 'height', 1080)\n const fps = numFlag(flags, 'fps', 30)\n const out = positionals[1] ?? outName(source, format)\n\n // A program document's sound rides its studio entry; mix it like a take's.\n const audio = await programAudio(config as Record<string, unknown>, {\n baseDir:\n existsSync(source) && statSync(source).isDirectory()\n ? source\n : dirname(source),\n duration,\n origin: platformOrigin({}),\n key: resolveCredential(),\n log: (line) => r.log(line),\n })\n if (audio) r.log(`mixing ${audio.clips} sound${audio.clips === 1 ? '' : 's'}`)\n if (hasAudioElements(config)) {\n r.log(\n 'note: an audio ELEMENT is not mixed by a render; put the sound on the program document instead (doc.json audio: [{ key, start, in, out, duration, gain }])',\n )\n }\n\n const browser = await launchBrowser()\n try {\n const result = await renderVideo(browser, {\n config,\n width,\n height,\n fps,\n duration,\n format,\n audioProducerCode: audio?.producerCode,\n onPhase: (phase) => {\n r.log(`${phase}…`)\n r.event({ event: 'phase', phase })\n },\n })\n await writeFile(out, result.bytes)\n const warnings = stillWarnings(\n { transparent: false, flat: false },\n result.pageErrors,\n result.engineNotes,\n )\n for (const w of warnings) r.log(`warn: ${w}`)\n r.done(\n {\n out,\n bytes: result.bytes.length,\n width,\n height,\n fps,\n duration,\n format,\n audio: audio?.clips ?? 0,\n ...(warnings.length ? { warnings } : {}),\n },\n `Wrote ${out} (${(result.bytes.length / 1024).toFixed(0)} KB, ${width}x${height}@${fps}, ${duration}s)`,\n )\n return EXIT_OK\n } finally {\n await browser.close()\n }\n}\n\nasync function cmdStill(argv: string[]): Promise<number> {\n const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS)\n const source = positionals[0]\n if (!source)\n throw new UsageError(\n 'vos still <config.json|url> [out.webp|out.png|out.jpg] [--time t | --times a,b,50%]',\n )\n const r = createReporter(flags.json === true)\n\n const loaded = await loadVosConfig(source)\n for (const w of loaded.warnings) r.log(`note: ${w}`)\n void flags.set\n const config = applyDataSets(\n loaded.config as Record<string, unknown>,\n setFlags(argv),\n )\n const width = numFlag(flags, 'width', 1280)\n const height = numFlag(flags, 'height', 720)\n const out = positionals[1] ?? outName(source, 'webp')\n const encoding = stillFormat(out)\n const timesRaw = flags.times === undefined ? undefined : String(flags.times)\n if (timesRaw !== undefined && flags.time !== undefined)\n throw new UsageError('--time and --times: pass one')\n const times =\n timesRaw !== undefined\n ? parseTimes(timesRaw, configDuration(config) ?? 5)\n : [numFlag(flags, 'time', 0)]\n const many = times.length > 1\n\n // One browser for every time: each still is its own capture page.\n const browser = await launchBrowser()\n try {\n const written: {\n out: string\n bytes: number\n time: number\n warnings?: string[]\n }[] = []\n for (const time of times) {\n const target = stillOutFor(out, time, many)\n const result = await renderStill(browser, {\n config,\n width,\n height,\n time,\n onPhase: (phase) => {\n r.event({ event: 'phase', phase, time })\n },\n })\n // The engine captures WebP; a .png or .jpg name is re-encoded in the\n // page, so the bytes always match the name.\n const bytes =\n encoding === 'webp'\n ? result.bytes\n : await reencodeStill(browser, result.bytes, encoding)\n await writeFile(target, bytes)\n // A still is checked before anyone looks at it: a fully transparent\n // or flat frame is written, and said, never passed off as a picture.\n const warnings = stillWarnings(\n await inspectStill(browser, result.bytes),\n result.pageErrors,\n result.engineNotes,\n )\n written.push({\n out: target,\n bytes: bytes.length,\n time,\n ...(warnings.length ? { warnings } : {}),\n })\n r.log(\n `Wrote ${target} (${(bytes.length / 1024).toFixed(0)} KB @ t=${Number(time.toFixed(2))}s)`,\n )\n for (const w of warnings)\n r.log(`warn: t=${Number(time.toFixed(2))}s ${w}`)\n }\n const first = written[0]\n r.done(\n many\n ? { stills: written, width, height, format: encoding }\n : { ...first, width, height, format: encoding },\n many\n ? `Wrote ${written.length} stills (${width}x${height})`\n : `Wrote ${first.out} (${(first.bytes / 1024).toFixed(0)} KB, ${width}x${height} @ t=${first.time}s)`,\n )\n return EXIT_OK\n } finally {\n await browser.close()\n }\n}\n\nasync function cmdInfo(argv: string[]): Promise<number> {\n const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS)\n const source = positionals[0]\n if (!source) throw new UsageError('vos info <config.json|url>')\n const r = createReporter(flags.json === true)\n\n const { config, warnings } = await loadVosConfig(source)\n const elements = Array.isArray(config.elements) ? config.elements.length : 0\n const data =\n typeof config.data === 'object' && config.data !== null\n ? Object.keys(config.data)\n : []\n const fns = ['setup', 'createContent', 'createTimeline', 'onFrame'].filter(\n (k) => typeof config[k] === 'string',\n )\n const info = {\n version: config.version,\n duration: configDuration(config) ?? null,\n camera:\n (config.camera as Record<string, unknown> | undefined)?.preset ?? null,\n elements,\n dataKeys: data,\n functions: fns,\n warnings,\n }\n if (r.json) r.done(info, '')\n else {\n for (const w of warnings) r.log(`note: ${w}`)\n process.stdout.write(\n `version: v${String(info.version)}\\n` +\n `duration: ${info.duration === null ? '(none)' : `${info.duration}s`}\\n` +\n `camera: ${String(info.camera ?? '(default)')}\\n` +\n `elements: ${elements}\\n` +\n `data keys: ${data.length ? data.join(', ') : '(none)'}\\n` +\n `functions: ${fns.join(', ')}\\n`,\n )\n }\n return EXIT_OK\n}\n\nfunction packageVersion(name: string): string | null {\n const require = createRequire(import.meta.url)\n // Fast path — packages that export ./package.json (e.g. playwright).\n try {\n return (require(`${name}/package.json`) as { version: string }).version\n } catch {\n // Strict `exports` maps (the @vosjs packages) hide package.json — resolve\n // the entry module instead and walk up to the owning package.json.\n }\n let entry: string | null = null\n try {\n entry = fileURLToPath(import.meta.resolve(name))\n } catch {\n try {\n entry = require.resolve(name)\n } catch {\n return null\n }\n }\n let dir = dirname(entry)\n for (let i = 0; i < 6; i++) {\n try {\n const pkg = JSON.parse(\n readFileSync(join(dir, 'package.json'), 'utf8'),\n ) as {\n name?: string\n version?: string\n }\n if (pkg.name === name && pkg.version) return pkg.version\n } catch {\n // keep walking\n }\n const parent = dirname(dir)\n if (parent === dir) return null\n dir = parent\n }\n return null\n}\n\nfunction ownVersion(): string {\n try {\n const own = JSON.parse(\n readFileSync(\n fileURLToPath(new URL('../package.json', import.meta.url)),\n 'utf8',\n ),\n ) as { version: string }\n return own.version\n } catch {\n return '(unknown)'\n }\n}\n\nasync function cmdVersions(argv: string[]): Promise<number> {\n const { flags } = parseArgs(argv, BOOLEAN_FLAGS)\n const r = createReporter(flags.json === true)\n const versions: Record<string, string> = {}\n versions['@vosjs/cli'] = ownVersion()\n for (const name of [\n '@vosjs/core',\n '@vosjs/elements',\n '@vosjs/tween',\n '@vosjs/editor',\n '@vosjs/timeline',\n '@vosjs/studio-core',\n '@vosjs/render-core',\n '@vosjs/shared',\n 'mediabunny',\n 'playwright',\n ]) {\n versions[name] = packageVersion(name) ?? '(not found)'\n }\n if (r.json) r.done({ versions }, '')\n else\n for (const [k, v] of Object.entries(versions))\n process.stdout.write(`${k} ${v}\\n`)\n return EXIT_OK\n}\n\nasync function cmdPreview(argv: string[]): Promise<number> {\n const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS)\n const source = positionals[0]\n if (!source) throw new UsageError('vos preview <config.json|url> [--port 0]')\n const r = createReporter(false)\n const { config, warnings } = await loadVosConfig(source)\n for (const w of warnings) r.log(`note: ${w}`)\n const { hostHtml, playerHtml } = previewPages(config)\n const server = createServer((req, res) => {\n const path = new URL(req.url ?? '/', 'http://x').pathname\n res.writeHead(200, { 'content-type': 'text/html' })\n res.end(path === '/player' ? playerHtml : hostHtml)\n })\n const port = numFlag(flags, 'port', 0)\n await new Promise<void>((resolve) => server.listen(port, resolve))\n const addr = server.address()\n const url = `http://localhost:${typeof addr === 'object' && addr ? addr.port : port}/`\n process.stdout.write(`${url}\\n`)\n r.log('Serving playback preview — Ctrl-C to stop.')\n await new Promise(() => {}) // keep alive until interrupted\n return EXIT_OK\n}\n\nasync function cmdCheck(argv: string[]): Promise<number> {\n const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS)\n const source = positionals[0]\n if (!source) throw new UsageError('vos check <config.json>')\n const r = createReporter(flags.json === true)\n\n // A directory is a take (refused here: its document is `vos validate`'s\n // job) or a program directory (config.json, composed with the program\n // document beside it so the ladder reads the layers' strings too).\n const kind = /^https?:\\/\\//.test(source) ? 'none' : directoryKind(source)\n if (kind === 'take') {\n throw new UsageError(\n `${source} is a take (its doc.json is a recording document). vos validate ${source} lints it; vos render ${source} renders it.`,\n )\n }\n let raw: string\n let parsed: unknown\n try {\n if (kind === 'program') {\n const notes: string[] = []\n parsed = await loadProgramDirectory(source, notes)\n for (const n of notes) r.log(`note: ${n}`)\n raw = ''\n } else {\n raw = await readSourceText(source)\n parsed = JSON.parse(raw)\n }\n } catch (e) {\n if (!(e instanceof SyntaxError)) throw e\n parsed = undefined\n if (!r.json) process.stdout.write(`error [json] ${(e as Error).message}\\n`)\n r.done(\n {\n ok: false,\n errors: 1,\n warnings: 0,\n issues: [\n { level: 'error', source: 'json', message: (e as Error).message },\n ],\n },\n `${source}: 1 error`,\n )\n return EXIT_ERROR\n }\n\n const result = runCheck(parsed)\n if (r.json) {\n r.done(\n {\n ok: result.ok,\n errors: result.errors,\n warnings: result.warnings,\n issues: result.issues,\n },\n '',\n )\n } else {\n for (const i of result.issues) {\n process.stdout.write(`${i.level} [${i.source}] ${i.message}\\n`)\n }\n process.stdout.write(\n result.ok\n ? `${source}: ok (${result.warnings} warning${result.warnings === 1 ? '' : 's'})\\n`\n : `${source}: ${result.errors} error${result.errors === 1 ? '' : 's'}, ${result.warnings} warning${result.warnings === 1 ? '' : 's'}\\n`,\n )\n }\n return result.ok ? EXIT_OK : EXIT_ERROR\n}\n\n// ---------------------------------------------------------------------------\n// Every verb this file does not own is a take-pipeline or vos.so verb from\n// `./plugin` (what used to ship separately as @vosso/vos-plugin). It loads on\n// demand, so the engine verbs never pay for the recorder's imports, and the\n// old names (`@vosso/cli`, `@vosso/voila-cli`, the `vos voila` alias) keep\n// resolving here for scripts that still use them.\n// ---------------------------------------------------------------------------\n\nasync function delegate(argv: string[], viaAlias = false): Promise<number> {\n const { run } = await import('./plugin/run')\n if (viaAlias && argv[0]) {\n process.stderr.write(\n `note: \"vos voila ${argv[0]}\" is now \"vos ${argv[0]}\".\\n`,\n )\n }\n return await run(argv)\n}\n\nasync function printHelp(): Promise<void> {\n process.stdout.write(HELP_ENGINE)\n const { manifest } = await import('./plugin/manifest')\n process.stdout.write('\\nTake pipeline + vos.so verbs\\n')\n for (const v of manifest.verbs) {\n if (v.name === 'render') continue // polymorphic — already listed above\n process.stdout.write(` vos ${v.name.padEnd(8)} ${v.summary}\\n`)\n }\n process.stdout.write(HELP_CONVENTIONS)\n}\n\nconst ENGINE_VERBS = new Set([\n 'render',\n 'still',\n 'info',\n 'versions',\n 'preview',\n 'check',\n])\n\nasync function main(): Promise<number> {\n const [cmd, ...rest] = process.argv.slice(2)\n if (!cmd || cmd === 'help' || cmd === '--help' || cmd === '-h') {\n await printHelp()\n return cmd ? EXIT_OK : EXIT_USAGE\n }\n if (cmd === '--version') return cmdVersions(['--json'])\n if (!ENGINE_VERBS.has(cmd) && cmd !== 'voila') return delegate([cmd, ...rest])\n // An engine verb asked for its flags: the engine's usage lines, plus the\n // take pipeline's where the verb is shared (render takes a config OR a take).\n if (rest.includes('--help') || rest.includes('-h')) {\n const engine = HELP_ENGINE.split('\\n').filter((l) =>\n l.startsWith(` vos ${cmd} `),\n )\n const { verbHelp } = await import('./plugin/run')\n const take = verbHelp(cmd)\n process.stdout.write(\n `${engine.join('\\n')}\\n${take.includes('no such verb') ? '' : take}`,\n )\n return EXIT_OK\n }\n switch (cmd) {\n case 'render':\n return cmdRender(rest)\n case 'still':\n return cmdStill(rest)\n case 'info':\n return cmdInfo(rest)\n case 'versions':\n return cmdVersions(rest)\n case 'preview':\n return cmdPreview(rest)\n case 'check':\n return cmdCheck(rest)\n // Hidden alias for existing scripts; not in HELP. Same code path as the\n // promoted verbs, plus a one-line pointer at the new spelling.\n case 'voila':\n return delegate(rest, true)\n default:\n throw new UsageError(`unknown command \"${cmd}\" — run vos help`)\n }\n}\n\nmain()\n .then(async (code) => {\n // A run that succeeded while ignoring a flag it was given did not do\n // what was asked (flagUse.ts): say so, and do not exit 0.\n if (code === EXIT_OK) {\n const verb = process.argv[2] ?? ''\n const { HELP } = await import('./plugin/run')\n const documented = [\n ...helpFlagsFor(HELP_ENGINE, verb),\n ...helpFlagsFor(HELP, verb),\n ]\n const message = unusedFlagsMessage(verb, [...new Set(documented)])\n if (message) {\n process.stderr.write(`usage error: ${message}\\n`)\n process.exit(EXIT_USAGE)\n }\n }\n process.exit(code)\n })\n .catch((e) => {\n if (e instanceof UsageError) {\n process.stderr.write(`usage error: ${e.message}\\n`)\n process.exit(EXIT_USAGE)\n }\n if (e instanceof BrowserUnavailableError) {\n process.stderr.write(`${e.message}\\n`)\n process.exit(EXIT_NO_BROWSER)\n }\n process.stderr.write(\n `error: ${e instanceof Error ? e.message : String(e)}\\n`,\n )\n process.exit(EXIT_ERROR)\n })\n","/**\n * Output conventions (agent-safe by construction):\n * - logs/progress → stderr (human readable)\n * - results → stdout; with --json, NDJSON events (`{\"event\":\"phase\"...}` then\n * `{\"event\":\"done\"...}`) so scripts and agents never parse prose\n * - exit codes: 0 ok · 1 failure · 2 usage · 3 browser unavailable ·\n * 4 the recorder met a sign-in (the take pipeline's wall check)\n */\nexport const EXIT_OK = 0\nexport const EXIT_ERROR = 1\nexport const EXIT_USAGE = 2\nexport const EXIT_NO_BROWSER = 3\n\nexport interface Reporter {\n json: boolean\n /** Human log line (stderr; suppressed in --json mode). */\n log: (msg: string) => void\n /** Machine event (stdout NDJSON in --json mode; no-op otherwise). */\n event: (obj: Record<string, unknown>) => void\n /** Final result: NDJSON `done` event in --json mode, plain line otherwise. */\n done: (obj: Record<string, unknown>, humanLine: string) => void\n}\n\nexport function createReporter(json: boolean): Reporter {\n return {\n json,\n log: (msg) => {\n if (!json) process.stderr.write(`${msg}\\n`)\n },\n event: (obj) => {\n if (json) process.stdout.write(`${JSON.stringify(obj)}\\n`)\n },\n done: (obj, humanLine) => {\n if (json)\n process.stdout.write(`${JSON.stringify({ event: 'done', ...obj })}\\n`)\n else process.stdout.write(`${humanLine}\\n`)\n },\n }\n}\n","/**\n * `vos check` — the local validation pipeline, pure so it can be unit-tested:\n * envelope unwrap → migrate → schema → compile → determinism + dialect lints.\n * Everything runs locally (no network, no browser). The platform runs the\n * same compiler server-side, so a clean check is a push that will compile.\n */\nimport {\n CURRENT_CONFIG_VERSION,\n compileVosConfig,\n migrateConfig,\n vosConfigJsonSchema,\n} from '@vosjs/core'\nimport {\n lintVosConfig,\n lintVosDialect,\n lintVosFonts,\n lintVosPostprocessing,\n} from '@vosjs/core/lint'\nimport { knobWarnings } from './plugin/knobs'\n\nexport interface CheckIssue {\n level: 'error' | 'warn'\n source:\n | 'schema'\n | 'syntax'\n | 'compile'\n | 'determinism'\n | 'dialect'\n | 'shape'\n | 'fonts'\n | 'postprocessing'\n message: string\n}\n\nexport interface CheckResult {\n ok: boolean\n errors: number\n warnings: number\n issues: CheckIssue[]\n /** The migrated config (params/presets untouched) — what a push should send. */\n config: Record<string, unknown> | null\n}\n\n// Top-level keys the schema does not know but the platform preserves on push.\nconst PLATFORM_EXTRA_KEYS = new Set(['params', 'presets'])\n\nexport function runCheck(parsed: unknown): CheckResult {\n const issues: CheckIssue[] = []\n const finish = (config: Record<string, unknown> | null): CheckResult => {\n const errors = issues.filter((i) => i.level === 'error').length\n return {\n ok: errors === 0,\n errors,\n warnings: issues.length - errors,\n issues,\n config,\n }\n }\n\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n issues.push({\n level: 'error',\n source: 'shape',\n message: 'not a JSON object',\n })\n return finish(null)\n }\n\n // API endpoints wrap the config: { config: {...} } — accept both shapes.\n let obj = parsed as Record<string, unknown>\n if (\n typeof obj.config === 'object' &&\n obj.config !== null &&\n !('createTimeline' in obj)\n ) {\n obj = obj.config as Record<string, unknown>\n }\n\n const version = obj.version\n let migrated: Record<string, unknown>\n try {\n migrated = migrateConfig(obj) as Record<string, unknown>\n } catch (e) {\n issues.push({\n level: 'error',\n source: 'shape',\n message: `migration failed: ${e instanceof Error ? e.message : String(e)}`,\n })\n return finish(null)\n }\n if (version === undefined) {\n // It compiles (the engine reads an absent version as the current one),\n // but a push is refused: a stored config must say which schema era it was\n // written against, and nobody can tell that from the file later.\n issues.push({\n level: 'warn',\n source: 'shape',\n message: `config declares no \"version\". It plays here, but a push is refused without one. Add \"version\": ${CURRENT_CONFIG_VERSION}.`,\n })\n } else if (version !== CURRENT_CONFIG_VERSION) {\n issues.push({\n level: 'warn',\n source: 'shape',\n message: `config is v${String(version)}, migrated to v${CURRENT_CONFIG_VERSION}. Save the migrated form.`,\n })\n }\n\n const schema = vosConfigJsonSchema.safeParse(migrated)\n if (!schema.success) {\n for (const i of schema.error.issues.slice(0, 10)) {\n issues.push({\n level: 'error',\n source: 'schema',\n message: `${i.path.join('.') || '(root)'}: ${i.message}`,\n })\n }\n return finish(null)\n }\n\n // Keys the platform's schema will silently drop on push (params/presets\n // excepted — those are re-attached by contract).\n const known = new Set([\n ...Object.keys(vosConfigJsonSchema.shape),\n ...PLATFORM_EXTRA_KEYS,\n ])\n for (const key of Object.keys(migrated)) {\n if (!known.has(key)) {\n issues.push({\n level: 'warn',\n source: 'shape',\n message: `unknown top-level key \"${key}\" — the platform drops it on push`,\n })\n }\n }\n\n // Knobs and Looks vos.so would drop (the push still saves, without them).\n for (const message of knobWarnings(migrated as Record<string, unknown>)) {\n issues.push({ level: 'warn', source: 'shape', message })\n }\n\n // Sound as an ELEMENT is not a track: no timeline row, no gain or fades,\n // nothing a render mixes, and a `data:` source inflates the config past\n // what a claimable push can carry. The document is where sound goes.\n const elements = Array.isArray(migrated.elements) ? migrated.elements : []\n for (const el of elements) {\n if (!el || typeof el !== 'object') continue\n const e = el as { type?: unknown; id?: unknown; src?: unknown }\n if (e.type !== 'audio') continue\n const inline =\n typeof e.src === 'string' && e.src.startsWith('data:')\n ? ` (embedded, ${Math.round(e.src.length / 1024)} KB of config)`\n : ''\n issues.push({\n level: 'warn',\n source: 'shape',\n message: `audio element \"${String(e.id ?? '?')}\"${inline} is not a track: renders do not mix it and the studio cannot edit it. Put the file beside the config and name it in doc.json (audio: [{ key: \"score.ogg\", start, in, out, duration, gain }]); vos push uploads it`,\n })\n }\n\n // Function strings are pasted into the template as text, so the compiler\n // cannot see a syntax error — parse each one here (construction only,\n // nothing executes).\n let syntaxErrors = 0\n for (const key of [\n 'setup',\n 'createContent',\n 'createTimeline',\n 'onFrame',\n ] as const) {\n const src = migrated[key]\n if (typeof src !== 'string' || !src.length) continue\n try {\n new Function(`\"use strict\"; return (${src}\\n)`)\n } catch (e) {\n syntaxErrors++\n issues.push({\n level: 'error',\n source: 'syntax',\n message: `${key}: ${e instanceof Error ? e.message : String(e)}`,\n })\n }\n }\n if (syntaxErrors) return finish(migrated)\n\n try {\n // Same options as `vos render` — a clean check is a config the CLI's own\n // render path will accept.\n compileVosConfig(migrated as never, { tweenEngine: 'vos' })\n } catch (e) {\n issues.push({\n level: 'error',\n source: 'compile',\n message: e instanceof Error ? e.message : String(e),\n })\n return finish(migrated)\n }\n\n for (const i of lintVosConfig(migrated as never)) {\n issues.push({\n level: i.severity === 'error' ? 'error' : 'warn',\n source: 'determinism',\n message: `${i.fn}:${i.line} [${i.rule}] ${i.message}`,\n })\n }\n for (const i of lintVosDialect(migrated as never)) {\n issues.push({\n level: i.severity === 'error' ? 'error' : 'warn',\n source: 'dialect',\n message: `${i.fn}:${i.line} [${i.rule}] ${i.message}`,\n })\n }\n for (const i of lintVosFonts(migrated as never)) {\n issues.push({\n level: 'warn',\n source: 'fonts',\n message: `[${i.rule}] ${i.message}`,\n })\n }\n for (const i of lintVosPostprocessing(migrated as never)) {\n issues.push({\n level: 'warn',\n source: 'postprocessing',\n message: `[${i.rule}] ${i.message}`,\n })\n }\n\n return finish(migrated)\n}\n","/**\n * What vos.so keeps of a config's knobs (`params`) and Looks (`presets`).\n *\n * A vos.so fact, so it lives in the platform client: the platform keeps at\n * most 12 knobs and 8 Looks, each within its field limits, and drops the\n * rest ONE BY ONE with a warning (it used to drop them all, silently). This\n * mirrors that rule so `vos check` says the same thing before a push does.\n */\nexport const MAX_PARAMS = 12\nexport const MAX_LOOKS = 8\n\nconst KINDS = new Set(['number', 'color', 'select', 'toggle', 'text', 'font'])\n\nconst str = (v: unknown, max: number, min = 0) =>\n typeof v === 'string' && v.length >= min && v.length <= max\n\n/** Why one knob would be dropped, or null when vos.so keeps it. */\nexport function knobProblem(p: unknown): string | null {\n if (!p || typeof p !== 'object') return 'not an object'\n const k = p as Record<string, unknown>\n if (!str(k.key, 40, 1)) return 'key must be 1 to 40 characters'\n if (typeof k.kind !== 'string' || !KINDS.has(k.kind))\n return `kind must be one of ${[...KINDS].join(', ')}`\n if (k.label !== undefined && !str(k.label, 60))\n return 'label: at most 60 characters'\n if (k.hint !== undefined && !str(k.hint, 140))\n return 'hint: at most 140 characters'\n if (k.unit !== undefined && !str(k.unit, 8))\n return 'unit: at most 8 characters'\n if (k.group !== undefined && !str(k.group, 24))\n return 'group: at most 24 characters'\n if (k.options !== undefined) {\n if (!Array.isArray(k.options) || k.options.length > 12)\n return 'options: at most 12'\n if (k.options.some((o) => !str(o, 40, 1)))\n return 'options: each 1 to 40 characters'\n }\n const d = k.default\n if (\n !(\n typeof d === 'number' ||\n typeof d === 'boolean' ||\n (typeof d === 'string' && d.length <= 280)\n )\n )\n return 'default must be a number, a boolean or at most 280 characters'\n return null\n}\n\n/** Why one Look would be dropped, or null when vos.so keeps it. */\nexport function lookProblem(l: unknown): string | null {\n if (!l || typeof l !== 'object') return 'not an object'\n const look = l as Record<string, unknown>\n if (!str(look.name, 24, 1)) return 'name must be 1 to 24 characters'\n if (!look.values || typeof look.values !== 'object') return 'values missing'\n return null\n}\n\n/** Every knob and Look vos.so would drop, in words, in order. */\nexport function knobWarnings(config: Record<string, unknown>): string[] {\n const out: string[] = []\n const sort = (\n raw: unknown,\n noun: 'knob' | 'look',\n field: string,\n max: number,\n problem: (e: unknown) => string | null,\n ) => {\n if (raw === undefined) return\n if (!Array.isArray(raw)) {\n out.push(`${noun === 'knob' ? 'params' : 'presets'} is not a list`)\n return\n }\n let kept = 0\n raw.forEach((entry, i) => {\n const id =\n entry && typeof (entry as Record<string, unknown>)[field] === 'string'\n ? `${noun} \"${String((entry as Record<string, unknown>)[field])}\"`\n : `${noun} #${i + 1}`\n const why = problem(entry)\n if (why) out.push(`${id} would be dropped on vos.so (${why})`)\n else if (kept >= max)\n out.push(\n `${id} would be dropped on vos.so: a vos keeps at most ${max} ${noun}s${noun === 'knob' ? ' (the rest can stay bound data)' : ''}`,\n )\n else kept += 1\n })\n }\n sort(config.params, 'knob', 'key', MAX_PARAMS, knobProblem)\n sort(config.presets, 'look', 'name', MAX_LOOKS, lookProblem)\n return out\n}\n","/**\n * The sound a program document adds, for a LOCAL render of the program.\n *\n * A composed program carries its `doc.audio` clips on the studio stack entry,\n * exactly as a take does, and the capture page mixes them through the same\n * producer a take render uses. The one difference is WHERE the bytes are: a\n * capture page has no origin of its own, so a clip keyed by a file beside the\n * document (`score.ogg`) or by a hosted asset path (`/api/assets/…`) cannot be\n * fetched from inside it. Each is inlined as a `data:` URI here: a local file\n * read from disk, a hosted asset downloaded with the caller's credential.\n * A clip that cannot be reached is left out and said, never a silent track.\n */\nimport { existsSync } from 'node:fs'\nimport { readFile } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { audioProducerCode, studioEntryData } from '@vosjs/render-core'\nimport { studioAudioPlan } from '@vosjs/studio-core'\nimport { MEDIA_HEAD_BYTES, resolveMediaType } from './plugin/container'\nimport type { EnvelopePoint, LoweredAudioClip } from '@vosjs/studio-core'\n\nexport interface ProgramAudioOptions {\n /** The directory the document's relative keys are read against. */\n baseDir: string\n /** The output length the mix is cut to, seconds. */\n duration: number\n /** For a clip keyed by a hosted asset: where it lives and who may read it. */\n origin?: string\n key?: string | null\n log: (line: string) => void\n}\n\nexport interface ProgramAudio {\n producerCode: string\n clips: number\n}\n\nfunction dataUri(bytes: Uint8Array, filename: string): string {\n const { type } = resolveMediaType({\n head: bytes.subarray(0, MEDIA_HEAD_BYTES),\n filename,\n })\n return `data:${type};base64,${Buffer.from(bytes).toString('base64')}`\n}\n\nasync function reach(\n clipKey: string,\n opts: ProgramAudioOptions,\n): Promise<string | null> {\n if (/^(data:|https?:)/.test(clipKey)) return clipKey\n if (clipKey.startsWith('/api/')) {\n if (!opts.origin || !opts.key) {\n opts.log(\n `note: sound ${clipKey} is a hosted asset and no credential is set, so the render leaves it out (vos login, or keep the file beside the document)`,\n )\n return null\n }\n const res = await fetch(`${opts.origin}${clipKey}`, {\n headers: { authorization: `Bearer ${opts.key}` },\n })\n if (!res.ok) {\n opts.log(\n `note: sound ${clipKey} could not be read (${res.status}), so the render leaves it out`,\n )\n return null\n }\n return dataUri(new Uint8Array(await res.arrayBuffer()), clipKey)\n }\n const file = join(opts.baseDir, clipKey.replace(/^\\/+/, ''))\n if (!existsSync(file)) {\n opts.log(\n `note: sound ${clipKey} is not beside the document, so the render leaves it out`,\n )\n return null\n }\n return dataUri(new Uint8Array(await readFile(file)), file)\n}\n\n/** The producer for a composed program's sound, or null when it adds none. */\nexport async function programAudio(\n config: Record<string, unknown>,\n opts: ProgramAudioOptions,\n): Promise<ProgramAudio | null> {\n const entry = studioEntryData(config.stack)\n const clips = Array.isArray(entry?.audio)\n ? (entry.audio as LoweredAudioClip[])\n : []\n if (!clips.length) return null\n const reached: LoweredAudioClip[] = []\n for (const clip of clips) {\n const key = await reach(clip.key, opts)\n if (key) reached.push({ ...clip, key })\n }\n if (!reached.length) return null\n const duckEnv = Array.isArray(entry?.duckEnv)\n ? (entry.duckEnv as EnvelopePoint[])\n : []\n const plan = studioAudioPlan(reached, duckEnv, opts.duration)\n return {\n producerCode: audioProducerCode({ plan }),\n clips: reached.length,\n }\n}\n"],"mappings":"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","names":["existsSync","join","existsSync","require","join"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -30,6 +30,8 @@ interface RenderResult {
|
|
|
30
30
|
/** Uncaught exceptions the page threw while it rendered (it may still have
|
|
31
31
|
* written a frame, so a caller says them instead of hiding them). */
|
|
32
32
|
pageErrors: string[];
|
|
33
|
+
/** The engine's own '[vos] …' warnings: causes a picture cannot show. */
|
|
34
|
+
engineNotes: string[];
|
|
33
35
|
}
|
|
34
36
|
/** Render a vos config to a video (WebM/MP4) in a headless browser. */
|
|
35
37
|
declare function renderVideo(browser: Browser, opts: RenderVideoOptions): Promise<RenderResult>;
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
previewPages,
|
|
4
|
-
renderStill,
|
|
5
|
-
renderVideo
|
|
6
|
-
} from "./chunk-ZCLGXETO.js";
|
|
7
2
|
import {
|
|
8
3
|
RECORDING_NAME,
|
|
9
4
|
convertAgentBrowser,
|
|
@@ -23,7 +18,7 @@ import {
|
|
|
23
18
|
takePaths,
|
|
24
19
|
validateActions,
|
|
25
20
|
waitForPageDone
|
|
26
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-M7FLXLBN.js";
|
|
27
22
|
import {
|
|
28
23
|
BrowserUnavailableError,
|
|
29
24
|
apiError,
|
|
@@ -33,14 +28,17 @@ import {
|
|
|
33
28
|
loadVosConfig,
|
|
34
29
|
parseVosId,
|
|
35
30
|
platformOrigin,
|
|
31
|
+
previewPages,
|
|
36
32
|
readSyncState,
|
|
33
|
+
renderStill,
|
|
34
|
+
renderVideo,
|
|
37
35
|
resolveCredential,
|
|
38
36
|
writeSyncState
|
|
39
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-JX2YEL3M.js";
|
|
40
38
|
import "./chunk-6XPFWQKP.js";
|
|
41
39
|
import {
|
|
42
40
|
manifest
|
|
43
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-WZGCEAXB.js";
|
|
44
42
|
export {
|
|
45
43
|
BrowserUnavailableError,
|
|
46
44
|
RECORDING_NAME,
|
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
takeBackdrop,
|
|
7
7
|
takeBrowserArgs,
|
|
8
8
|
verbHelp
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-M7FLXLBN.js";
|
|
10
|
+
import "./chunk-JX2YEL3M.js";
|
|
11
11
|
import "./chunk-6XPFWQKP.js";
|
|
12
12
|
export {
|
|
13
13
|
HELP,
|
|
@@ -17,4 +17,4 @@ export {
|
|
|
17
17
|
takeBrowserArgs,
|
|
18
18
|
verbHelp
|
|
19
19
|
};
|
|
20
|
-
//# sourceMappingURL=run-
|
|
20
|
+
//# sourceMappingURL=run-SYDEWMK2.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vosjs/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.54.1",
|
|
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 and stills, deliver a release's media per destination spec, and sync with vos.so. One binary, every verb, MIT.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,16 +47,18 @@
|
|
|
47
47
|
],
|
|
48
48
|
"sideEffects": false,
|
|
49
49
|
"dependencies": {
|
|
50
|
+
"acorn": "^8.18.0",
|
|
51
|
+
"acorn-walk": "^8.3.5",
|
|
50
52
|
"mediabunny": "^1.55.7",
|
|
51
53
|
"playwright": "^1.49.0",
|
|
54
|
+
"@vosjs/core": "^0.25.4",
|
|
52
55
|
"@vosjs/editor": "^1.4.0",
|
|
53
56
|
"@vosjs/elements": "^0.9.0",
|
|
54
|
-
"@vosjs/core": "^0.25.3",
|
|
55
57
|
"@vosjs/render-core": "^0.3.9",
|
|
56
|
-
"@vosjs/studio-core": "^0.33.2",
|
|
57
58
|
"@vosjs/shared": "^0.6.0",
|
|
58
|
-
"@vosjs/
|
|
59
|
-
"@vosjs/timeline": "^0.4.1"
|
|
59
|
+
"@vosjs/studio-core": "^0.33.2",
|
|
60
|
+
"@vosjs/timeline": "^0.4.1",
|
|
61
|
+
"@vosjs/tween": "^0.8.2"
|
|
60
62
|
},
|
|
61
63
|
"devDependencies": {
|
|
62
64
|
"@types/node": "^22",
|
package/skills/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.13.0
|
package/skills/vos-port/SKILL.md
CHANGED
|
@@ -151,33 +151,36 @@ approximation.
|
|
|
151
151
|
|
|
152
152
|
## The procedure
|
|
153
153
|
|
|
154
|
-
1. **
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
154
|
+
1. **Get the source's own render.** Remotion: `npx remotion render <id>
|
|
155
|
+
out/source.mp4`. HyperFrames: `npx hyperframes render` (or the one in
|
|
156
|
+
`renders/`). It is the reference every check compares against.
|
|
157
|
+
2. **Inventory before writing** (cli 0.54+): `npx vos port inventory
|
|
158
|
+
<page.html|project dir>` reads the piece as a browser renders it (words,
|
|
159
|
+
the palette from its custom properties, faces with their catalog match,
|
|
160
|
+
media, scenes, the CSS no element can say) into `port/inventory.json`,
|
|
161
|
+
with stills from its render. A HyperFrames word is laid out where it
|
|
162
|
+
SETTLES in its scene. A Remotion project's words live in `src/`: read
|
|
163
|
+
them there. This IS the port's contract.
|
|
164
|
+
3. **Scaffold**: `npx vos port scaffold` writes `port/program/program.mjs`
|
|
165
|
+
(every word a bound element, every colour a key, the knobs, a label and a
|
|
166
|
+
TODO per scene, each scene's words shown in its window, a painter only
|
|
167
|
+
when the inventory needs one), `doc.json` with the score as a track, and
|
|
168
|
+
`port/REPORT.md` (substituted faces, gaps). Read the report first. On an
|
|
169
|
+
older CLI, scaffold from `references/intro-port.mjs` by hand.
|
|
170
|
+
4. **Translate scene by scene** with the tables, replacing each TODO. One
|
|
171
|
+
scene, then check it, then the next.
|
|
167
172
|
5. **Check** after every scene:
|
|
168
173
|
|
|
169
174
|
```bash
|
|
170
|
-
|
|
171
|
-
vos
|
|
172
|
-
|
|
173
|
-
ffmpeg -i r-1.png -i v-1.00s.png -filter_complex "[0:v][1:v]ssim" -f null - # SSIM
|
|
174
|
-
ffmpeg -i r-1.png -i v-1.00s.png -filter_complex hstack side.png # LOOK at it
|
|
175
|
-
vos render config.json small.mp4 --width 960 --height 540 # the scale check
|
|
175
|
+
npx vos build program.mjs && npx vos check . # real functions → config.json; refuses module-scope reads
|
|
176
|
+
npx vos compare . --against ../../renders/source.mp4 # per-frame SSIM + source | vos | difference sheets
|
|
177
|
+
npx vos render . small.mp4 --width 960 --height 540 # the scale check (and the score, from doc.json)
|
|
176
178
|
```
|
|
177
179
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
180
|
+
`vos compare` exits 1 when ANY frame is under 0.95 and writes a sheet
|
|
181
|
+
per frame: LOOK at them, because a number does not catch a missing
|
|
182
|
+
element. Without the 0.54 CLI, the same loop is `ffmpeg -ss <t>` for the
|
|
183
|
+
source frame, `vos still` for yours, and ffmpeg's `ssim` and `hstack`.
|
|
181
184
|
6. **Knob honesty**: one `--set data.<key>=<value>` still per param.
|
|
182
185
|
7. **Push** with the score: `vos push config.json --folder <slug> --label
|
|
183
186
|
"port of <source>" --note "<what was substituted, what is a painter>"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/plugin/manifest.ts"],"sourcesContent":["/**\n * The verb manifest of the take pipeline and the vos.so verbs — what\n * `vos help` lists under the engine verbs. It kept the shape a separately\n * installed plugin once handed the host (name + host range), so a script\n * reading it keeps working.\n */\nexport interface PluginVerb {\n name: string\n summary: string\n}\n\nexport interface PluginManifest {\n name: string\n /** Host versions this plugin speaks the run(argv) contract with. */\n hostRange: string\n verbs: PluginVerb[]\n}\n\nexport const manifest: PluginManifest = {\n name: '@vosjs/cli',\n hostRange: '>=0.9.0',\n verbs: [\n {\n name: 'create',\n summary: 'record + auto-plan + render, one command (--strict)',\n },\n {\n name: 'record',\n summary: 'drive actions.json into a take (screencast + cursor track)',\n },\n {\n name: 'plan',\n summary:\n 'plan zoom/cursor effects into doc.json (wand contract); --reuse re-times a previous cut onto a re-recording',\n },\n {\n name: 'render',\n summary: 'render a take directory (engine configs render in the host)',\n },\n {\n name: 'frames',\n summary:\n 'PNG stills at output times / zoom apexes / moments / exact sizes',\n },\n {\n name: 'deliver',\n summary:\n 'render a take to release destinations (CWS, Product Hunt, X, LinkedIn, OG…) + verified kit.json',\n },\n {\n name: 'digest',\n summary:\n 'see a recording before cutting it: moments (clicks, typing, scrolls, idle, scenes) + footage frames + crops, in doc units',\n },\n { name: 'open', summary: 'serve the take into the vos.so studio' },\n {\n name: 'validate',\n summary:\n 'lint actions.json, a take dir (doc.json semantics), or re-measure a kit.json against the channel specs',\n },\n {\n name: 'actions',\n summary:\n 'from-agent-browser: turn an agent-browser walk (steps.jsonl) into actions.json; what cannot follow is named',\n },\n {\n name: 'ingest',\n summary:\n 'a take from a recording someone else made, with its cursor track from a trace beside it (Playwright trace.zip, stamped records, CSV); without one nothing is planned',\n },\n {\n name: 'brand',\n summary:\n \"write a product's BRAND.md, witnessed: /design.md, /llms.txt, then the page (palette, faces, marks, the avoid list)\",\n },\n {\n name: 'fetch',\n summary: 'download a hosted program: config.json + vos.json tracking',\n },\n {\n name: 'push',\n summary: 'push a config.json or take to vos.so (private; versioned)',\n },\n {\n name: 'duplicate',\n summary:\n 'a private sibling of your OWN vos (someone else\\u2019s is remixed: fetch + push --remix-of)',\n },\n {\n name: 'pull',\n summary:\n 'sync what changed on vos.so since your base (--media brings a take’s footage home)',\n },\n {\n name: 'folder',\n summary:\n 'list/create/pull folders, move voses and assets into them (pull = the context package on disk)',\n },\n {\n name: 'asset',\n summary: 'rename one of your assets in place (recipes included)',\n },\n {\n name: 'recipe',\n summary:\n 'push a recipe .md into a folder, or replace one in place (prior body kept)',\n },\n {\n name: 'login',\n summary: 'sign in via the browser (or --key); stores a content key',\n },\n {\n name: 'setup',\n summary:\n 'ready this machine: the vos skills into your agent, a browser, one rules block, then doctor',\n },\n {\n name: 'doctor',\n summary:\n 'what is ready, in words: node, browser, ffmpeg, skills, a credential (never printed), the dev server',\n },\n {\n name: 'whoami',\n summary: 'the key’s name and the account it belongs to, never the key',\n },\n { name: 'logout', summary: 'remove ~/.config/vos/credentials' },\n ],\n}\n"],"mappings":";;;AAkBO,IAAM,WAA2B;AAAA,EACtC,MAAM;AAAA,EACN,WAAW;AAAA,EACX,OAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA,EAAE,MAAM,QAAQ,SAAS,wCAAwC;AAAA,IACjE;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA,EAAE,MAAM,UAAU,SAAS,mCAAmC;AAAA,EAChE;AACF;","names":[]}
|