@vosjs/cli 0.71.0 → 0.73.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,7 +15,7 @@ npx vos render animation.json out.webm
15
15
 
16
16
  Deterministic: the preview is the render, and every edit is a data patch to `doc.json`, never a re-record. Rendering is local and free at every resolution up to 4K, no watermark. The workflow skills for agents install with `npx skills add vosjs/skills` (`product-video` records and cuts one video, `vos-cut` cuts an existing recording, `launch-kit` ships the media with a release); `vos setup` runs that for you, and falls back to the copy of the catalog this package ships when skills.sh cannot be reached. A coding agent gets the whole procedure from one line: `Read https://vos.so/agent.md and do what it says.`
17
17
 
18
- Until 0.9 the take pipeline and the vos.so verbs shipped separately as `@vosso/vos-plugin`, and before that as `@vosso/cli` and `@vosso/voila-cli`; those names are deprecated on npm and forward here.
18
+ Until 0.9 the take pipeline and the vos.so verbs shipped separately as `@vosso/vos-plugin`, and before that as `@vosso/cli`; those names are deprecated on npm and forward here.
19
19
 
20
20
  ## Contents
21
21
 
@@ -335,7 +335,7 @@ vos assets ls [--kind <kind>] [--q <text>] [--sort size] | usage | why <id> #
335
335
  vos recipe push <FILE.md> --folder <slug> | --asset <id> # the one recipe write: create, or replace in place
336
336
  ```
337
337
 
338
- `push` is polymorphic by a deterministic sniff, never a flag: a take directory (a `doc.json` carrying `source`) pushes recording and document through the take pipeline; a `config.json` (or a directory holding one) pushes the program, and a `doc.json` beside it that carries `program` (a program document: overlays, objects, audio, speed, tween edits, its own length; `program.config` omitted on disk) rides along, lint-gated. `fetch` and `pull` write a program document back the same way. `pull` takes `--since <versionId>` (walk the changelog from that base instead of the tracked one) and `--check` (print what changed and stop: nothing on disk moves) on both paths. A program push LANDS where `vos.json` says: a directory that tracks a vos iterates it, so the fetch, edit, check, push, pull loop needs no flags, and making something separate from the same config is the explicit `--remix-of` door. Program pushes take `--vos`, `--title`, `--slug`, `--desc`, `--tags`, `--folder`, `--remix-of`, `--base`, `--label`, `--note`, `--override <id>` (repeatable) and `--claimable`; take pushes take `--title`, `--label`, `--note`, `--folder`, `--override`, `--yes` and `--claimable`. Both take `--wait`. A new vos pushed without `--folder` lands unfiled, at the root of the shelf, and the done line says so.
338
+ `push` is polymorphic by a deterministic sniff, never a flag: a take directory (a `doc.json` carrying `source`) pushes recording and document through the take pipeline; a `config.json` (or a directory holding one) pushes the program, and a `doc.json` beside it that carries `program` (a program document: overlays, objects, audio, speed, tween edits, its own length; `program.config` omitted on disk) rides along, lint-gated. `fetch` and `pull` write a program document back the same way. `pull` takes `--since <versionId>` (walk the changelog from that base instead of the tracked one) and `--check` (print what changed and stop: nothing on disk moves) on both paths. A program push LANDS where `vos.json` says: a directory that tracks a vos iterates it, so the fetch, edit, check, push, pull loop needs no flags, and making something separate from the same config is the explicit `--remix-of` door. Program pushes take `--vos`, `--title`, `--slug`, `--desc`, `--tags`, `--folder`, `--remix-of`, `--base`, `--label`, `--note`, `--override <id>` (repeatable) and `--claimable`; take pushes take `--title`, `--label`, `--note`, `--folder`, `--override`, `--yes` and `--claimable`. Both take `--wait`. A new vos pushed without `--folder` lands unfiled, at the root of the shelf, and the done line says so. `--folder` takes a project on your own shelf (its slug or id) or anyone's project by its address, `<handle>/<slug>` as its page on vos.so names it: the server answers where the push lands, CONTINUING that project when the key is its owner's and otherwise STARTING the person's own from it (a private project made once, named after it, with the recipes they may read copied in, never its videos). The push says which.
339
339
 
340
340
  **A program's files are declared, never typed into a function.** `config.json` names each file it uses in `assets` (`"assets": { "logo": { "ref": "./logo.png", "kind": "image" }, "shots": { "ref": ["./shots/1.png", "./shots/2.png"] } }`) and reads `ctx.assets.logo`, or `"$assets.logo"` in an element, object or font. On disk a `ref` is a path in the config's own directory or below, so `vos render`, `vos still` and `vos preview` serve the file to the page from disk. A path that climbs out of that directory (`../`, an absolute path, a link that points away) is not served and not uploaded, and a config loaded from a URL reads no local file: a program's code runs in a page, and what the page is served the program can send anywhere. `vos push` uploads each local file (content-addressed, so a re-push sends nothing: pictures, SVG, video, sound, `.glb` models, fonts and HDR environments) and what it stores names the hosted file as `asset:<id>`, the one spelling the platform resolves for every render; the config on disk keeps its paths. A file an element names as `src` or a font names as `url` is lifted into the manifest on the way (the element then names `"$assets.<name>"`), and a path in `data` that is a file beside the config is uploaded and rewritten to the hosted file's path, so every place a program can name a file crosses. A file typed inside a function cannot be rewritten: `vos push` says so, with the manifest line to write. `vos fetch --media` brings a program's hosted files home under `assets/` and re-points the manifest at them (`assets/.hosted.json` remembers which hosted file each one is, so a later fetch replaces one that changed); without `--media` the manifest keeps `asset:<id>` and a local render reads each file with your key. `vos check` says when a `"$assets.<name>"` names nothing, when a declared path is not a file, and when a function names a hosted file in code instead of the manifest: a file named only in code does not load on a render of a private program and does not follow a remix. A `--claimable` push carries them too, through the claim's own upload session (below).
341
341
 
@@ -369,7 +369,7 @@ vos push /tmp/take --label "$TAG launch" --yes --json # VOS_API_KEY as a r
369
369
  - **`--max-duration <s>`** on `record` and `create` defaults to the hosted recording cap, read live from `GET /api/limits` (2 s, fail-open to 30 min when the origin is unreachable): the capture stops there and the done event says so. Cut the flow rather than raising the cap; the platform refuses a longer take.
370
370
  - **`create`** is the one-shot verb: record, auto-plan and render in one command and one browser session. The take directory still lands on disk, so the full loop (frames, edit `doc.json`, re-render) stays open afterwards.
371
371
  - **`vos validate <thing>`** takes an `actions.json`, a take directory, a program directory (`config.json`, plus its program document when present), or a `kit.json`; exit 1 on any problem.
372
- - **Environment.** `VOS_ORIGIN` (the platform, and the studio `vos open` opens), `VOS_API_KEY`, `VOS_BROWSER_PATH`, `VOS_CLIENT` (the client string a push self-reports; unset, a push names the coding agent that spawned the CLI, read from its environment the way `@vercel/detect-agent` reads it, e.g. `claude-code vos-cli`, else `vos-cli`). `vos voila <verb>` is still accepted as an alias of `vos <verb>` and says so.
372
+ - **Environment.** `VOS_ORIGIN` (the platform, and the studio `vos open` opens), `VOS_API_KEY`, `VOS_BROWSER_PATH`, `VOS_CLIENT` (the client string a push self-reports; unset, a push names the coding agent that spawned the CLI, read from its environment the way `@vercel/detect-agent` reads it, e.g. `claude-code vos-cli`, else `vos-cli`).
373
373
 
374
374
  ## Programmatic use
375
375
 
@@ -2400,7 +2400,7 @@ async function renderChunk(context2, serverBase, chunk, opts, onChunkProgress) {
2400
2400
  bitrate: opts.bitrate ?? 1e7,
2401
2401
  mediabunnyUrl: MEDIABUNNY_URL,
2402
2402
  outName,
2403
- debug: process.env.VOILA_DEBUG_CHUNKS === "1",
2403
+ debug: process.env.VOS_DEBUG_CHUNKS === "1",
2404
2404
  audioProducerCode: audio?.producerCode,
2405
2405
  audioDataJson: audio ? JSON.stringify(audio.data) : void 0,
2406
2406
  audioDuration: audio?.duration
@@ -3226,7 +3226,7 @@ function parseTranscript(raw) {
3226
3226
  }
3227
3227
 
3228
3228
  // src/plugin/framesTake.ts
3229
- var VIDEO_TOKEN = "__VOILA_CLI_VIDEO__";
3229
+ var VIDEO_TOKEN = "__VOS_CLI_VIDEO__";
3230
3230
  function stillSupersample(w, h) {
3231
3231
  return Math.min(3, Math.max(1, Math.ceil(1800 / Math.max(1, w, h))));
3232
3232
  }
@@ -3512,7 +3512,7 @@ import {
3512
3512
  resolveExportSize as resolveExportSize2,
3513
3513
  studioAudioPlan
3514
3514
  } from "@vosjs/studio-core";
3515
- var VIDEO_TOKEN2 = "__VOILA_CLI_VIDEO__";
3515
+ var VIDEO_TOKEN2 = "__VOS_CLI_VIDEO__";
3516
3516
  async function renderTake(browser, dir, outFile, opts) {
3517
3517
  const take = await loadTake(dir);
3518
3518
  if (!take.doc) throw new Error(`${dir} has no doc.json \u2014 run plan first`);
@@ -6022,6 +6022,38 @@ function resolveFolder(rows, ref) {
6022
6022
  }
6023
6023
  return hit;
6024
6024
  }
6025
+ function projectAddress(ref) {
6026
+ const m = /^@?([A-Za-z0-9_]{1,30})\/([A-Za-z0-9][\w-]{0,99})$/.exec(
6027
+ ref.trim()
6028
+ );
6029
+ return m ? { handle: m[1], slug: m[2].toLowerCase() } : null;
6030
+ }
6031
+ async function resolvePushFolder(origin, key, ref) {
6032
+ const at2 = projectAddress(ref);
6033
+ if (!at2) {
6034
+ return {
6035
+ id: resolveFolder(await listFolders(origin, key), ref).id,
6036
+ note: null
6037
+ };
6038
+ }
6039
+ const r = await apiJson(
6040
+ origin,
6041
+ `/api/folders/public/${encodeURIComponent(at2.handle)}/${encodeURIComponent(at2.slug)}/push-target`,
6042
+ { method: "POST", key }
6043
+ );
6044
+ if (r.status !== 200 && r.status !== 201) {
6045
+ throw new Error(apiError(`find the project ${at2.handle}/${at2.slug}`, r));
6046
+ }
6047
+ const body = r.body;
6048
+ if (!body.folder) {
6049
+ throw new Error(
6050
+ `find the project ${at2.handle}/${at2.slug}: no project in the answer`
6051
+ );
6052
+ }
6053
+ const source = body.source?.name ?? `${at2.handle}/${at2.slug}`;
6054
+ const note = body.target === "continue" ? `continuing ${source}` : body.created ? `starting your own ${source} (${body.folder.slug}), its ${body.recipes ?? 0} recipe${body.recipes === 1 ? "" : "s"} copied in` : `adding to your own ${source} (${body.folder.slug})`;
6055
+ return { id: body.folder.id, note };
6056
+ }
6025
6057
  function printTree(rows) {
6026
6058
  const children = /* @__PURE__ */ new Map();
6027
6059
  for (const f of rows) {
@@ -6404,10 +6436,9 @@ async function pushTake(dir, flags, r) {
6404
6436
  "--folder applies when CREATING a vos \u2014 this take is already pushed; file it with: vos folder move <vosId> --to <folder>"
6405
6437
  );
6406
6438
  }
6407
- folderId = resolveFolder(
6408
- await listFolders(ctx.origin, ctx.key),
6409
- flags.folder
6410
- ).id;
6439
+ const target = await resolvePushFolder(ctx.origin, ctx.key, flags.folder);
6440
+ folderId = target.id;
6441
+ if (target.note) r.log(target.note);
6411
6442
  }
6412
6443
  if (firstPush && !flags.yes) {
6413
6444
  if (!process.stdin.isTTY) {
@@ -7265,7 +7296,7 @@ async function cmdPushProgram(argv) {
7265
7296
  const target = positionals[0];
7266
7297
  if (!target) {
7267
7298
  throw new UsageError(
7268
- 'vos push <config.json|take> [--vos id] [--title t] [--slug s] [--desc d] [--tags a,b] [--folder <id|slug>] [--remix-of id] [--note n] [--label l] [--base versionId] [--override id]... [--prompt "<the prompt that made it>"] [--claimable [--share]]'
7299
+ 'vos push <config.json|take> [--vos id] [--title t] [--slug s] [--desc d] [--tags a,b] [--folder <id|slug|handle/slug>] [--remix-of id] [--note n] [--label l] [--base versionId] [--override id]... [--prompt "<the prompt that made it>"] [--claimable [--share]]'
7269
7300
  );
7270
7301
  }
7271
7302
  const source = resolveConfigPath(target);
@@ -7487,7 +7518,9 @@ ${landedLines(landed2)}` : "")
7487
7518
  const remixOfId = pushTarget.kind === "create" ? pushTarget.remixOfId : void 0;
7488
7519
  const fallbackTitle = state?.title ? `${state.title} remix` : basename3(source).replace(/\.json$/i, "") || "vos remix";
7489
7520
  const title = (strFlag(flags, "title") ?? fallbackTitle).slice(0, 100);
7490
- const folderId = folderRef ? resolveFolder(await listFolders(origin, key), folderRef).id : void 0;
7521
+ const pushFolder = folderRef ? await resolvePushFolder(origin, key, folderRef) : void 0;
7522
+ const folderId = pushFolder?.id;
7523
+ if (pushFolder?.note) r.log(pushFolder.note);
7491
7524
  const created = await createProgramVos({
7492
7525
  origin,
7493
7526
  key,
@@ -7531,6 +7564,7 @@ ${landedLines(landed2)}` : "")
7531
7564
  title,
7532
7565
  visibility: "private",
7533
7566
  folder: folderRef ?? null,
7567
+ ...pushFolder?.note ? { folderNote: pushFolder.note } : {},
7534
7568
  remixOfId: remixOfId ?? null,
7535
7569
  currentVersionId: created.currentVersionId,
7536
7570
  watchUrl,
@@ -7547,7 +7581,7 @@ ${landedLines(landed2)}` : "")
7547
7581
  watch: ${watchUrl}
7548
7582
  studio: ${studioUrl}
7549
7583
  ` + (landed ? `${landedLines(landed)}
7550
- ` : "") + ` shelf: ${folderRef ? `in ${folderRef}` : `unfiled, at the root of your shelf (file it: vos folder move ${created.id} --to <slug>)`}
7584
+ ` : "") + ` shelf: ${folderRef ? `in ${folderRef}${pushFolder?.note ? ` (${pushFolder.note})` : ""}` : `unfiled, at the root of your shelf (file it: vos folder move ${created.id} --to <slug>)`}
7551
7585
  cover: ${typeof programDoc?.still === "number" ? `${String(programDoc.still)}s` : "the platform picks an early frame; choose one with --still <seconds>"}
7552
7586
  ` + (prompt ? ` prompt: shown on the watch page
7553
7587
  ` : ` prompt: none shown; show the one that made it: ${promptHint(source, created.id)}
@@ -14328,4 +14362,4 @@ export {
14328
14362
  verbHelp,
14329
14363
  run
14330
14364
  };
14331
- //# sourceMappingURL=chunk-XB5XRE4Q.js.map
14365
+ //# sourceMappingURL=chunk-EYF3WJIC.js.map