@vosjs/cli 0.58.1 → 0.59.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.
@@ -36,7 +36,7 @@ import {
36
36
  videoFormat,
37
37
  writeCredential,
38
38
  writeSyncState
39
- } from "./chunk-IH5JJBIB.js";
39
+ } from "./chunk-YC3LY4LW.js";
40
40
  import {
41
41
  deadLine,
42
42
  deadWarns
@@ -1659,7 +1659,7 @@ function framingWarnings(docIn, doc, zoom, overlays, warnings) {
1659
1659
  if (!tf || !isNum(tf.x) || !isNum(tf.y)) return;
1660
1660
  const pinned = pins.get(String(o.id));
1661
1661
  if (!pinned && o.pin === void 0 && (o.kind === "html" || o.kind === "image" || o.kind === "video")) {
1662
- const words = layerWords(o);
1662
+ const words2 = layerWords(o);
1663
1663
  let layerBox = null;
1664
1664
  try {
1665
1665
  const b = pinBox(o, layout);
@@ -1677,7 +1677,7 @@ function framingWarnings(docIn, doc, zoom, overlays, warnings) {
1677
1677
  start: o.start,
1678
1678
  duration: o.duration
1679
1679
  })) {
1680
- const named = c.selector ? selectorLabelWords(c.selector).filter((x) => words.has(x)) : [];
1680
+ const named = c.selector ? selectorLabelWords(c.selector).filter((x) => words2.has(x)) : [];
1681
1681
  if (named.length) {
1682
1682
  about.push({
1683
1683
  step: String(c.step),
@@ -2042,6 +2042,60 @@ function isTakeRelativeKey(key) {
2042
2042
  return !!key && !/^(https?:|blob:|data:|media:|\/\/)/.test(key) && !key.startsWith("/api/");
2043
2043
  }
2044
2044
  var takeRelativeFile = (key) => key.replace(/^\/+/, "");
2045
+ function sourceSidecarRefs(doc, keep = isTakeRelativeKey) {
2046
+ const out = [];
2047
+ for (const [field, where] of [
2048
+ ["micKey", "mic track"],
2049
+ ["camKey", "cam track"]
2050
+ ]) {
2051
+ const key = doc.source[field];
2052
+ if (!key || !keep(key)) continue;
2053
+ out.push({
2054
+ where,
2055
+ key,
2056
+ set: (next) => {
2057
+ doc.source[field] = next;
2058
+ }
2059
+ });
2060
+ }
2061
+ return out;
2062
+ }
2063
+ function docObjectRefs(doc, keep = isTakeRelativeKey) {
2064
+ const out = [];
2065
+ for (const clip of doc.objects ?? []) {
2066
+ const asset = clip.asset;
2067
+ if (asset.kind !== "gltf" || !keep(asset.key)) continue;
2068
+ out.push({
2069
+ where: `object ${clip.id}`,
2070
+ key: asset.key,
2071
+ set: (next) => {
2072
+ asset.key = next;
2073
+ }
2074
+ });
2075
+ }
2076
+ return out;
2077
+ }
2078
+ function docOverlayRefs(doc, keep = isTakeRelativeKey) {
2079
+ const out = [];
2080
+ for (const clip of doc.overlays ?? []) {
2081
+ if (!isKeyedOverlay(clip) || !keep(clip.key)) continue;
2082
+ out.push({
2083
+ where: `overlay ${clip.id}`,
2084
+ key: clip.key,
2085
+ set: (next) => {
2086
+ clip.key = next;
2087
+ }
2088
+ });
2089
+ }
2090
+ return out;
2091
+ }
2092
+ function docLayerRefs(doc, keep = isTakeRelativeKey) {
2093
+ return [
2094
+ ...docOverlayRefs(doc, keep),
2095
+ ...docObjectRefs(doc, keep),
2096
+ ...docAudioRefs(doc, keep)
2097
+ ];
2098
+ }
2045
2099
  function docMediaRefs(doc, keep = isTakeRelativeKey) {
2046
2100
  const out = [];
2047
2101
  for (const m of doc.media ?? []) {
@@ -2072,16 +2126,8 @@ function docMediaRefs(doc, keep = isTakeRelativeKey) {
2072
2126
  }
2073
2127
  });
2074
2128
  }
2075
- for (const clip of doc.overlays ?? []) {
2076
- if (!isKeyedOverlay(clip) || !keep(clip.key)) continue;
2077
- out.push({
2078
- where: `overlay ${clip.id}`,
2079
- key: clip.key,
2080
- set: (next) => {
2081
- clip.key = next;
2082
- }
2083
- });
2084
- }
2129
+ out.push(...docOverlayRefs(doc, keep));
2130
+ out.push(...docObjectRefs(doc, keep));
2085
2131
  const mark = doc.endCard?.mark;
2086
2132
  if (mark && keep(mark.key))
2087
2133
  out.push({
@@ -2688,9 +2734,9 @@ async function renderInPage(opts) {
2688
2734
  w.__error = String(e instanceof Error && e.stack || e);
2689
2735
  }
2690
2736
  }
2691
- async function renderChunk(context, serverBase, chunk2, opts, onChunkProgress) {
2737
+ async function renderChunk(context2, serverBase, chunk2, opts, onChunkProgress) {
2692
2738
  const outName = `render-chunk-${chunk2.index}.tmp`;
2693
- const page = await context.newPage();
2739
+ const page = await context2.newPage();
2694
2740
  try {
2695
2741
  page.on("console", (m) => {
2696
2742
  if (m.type() === "error" || process.env.VOS_RENDER_DEBUG)
@@ -2755,7 +2801,7 @@ async function renderAnimation(browser, opts) {
2755
2801
  const server = await startTakeServer(opts.workDir, {
2756
2802
  "/render.html": renderPageHtml()
2757
2803
  });
2758
- const context = await browser.newContext({
2804
+ const context2 = await browser.newContext({
2759
2805
  viewport: { width: opts.width, height: opts.height }
2760
2806
  });
2761
2807
  try {
@@ -2769,7 +2815,7 @@ async function renderAnimation(browser, opts) {
2769
2815
  };
2770
2816
  const outNames = await Promise.all(
2771
2817
  chunks.map(
2772
- (chunk2) => renderChunk(context, server.base, chunk2, effOpts, (fraction) => {
2818
+ (chunk2) => renderChunk(context2, server.base, chunk2, effOpts, (fraction) => {
2773
2819
  progress[chunk2.index] = fraction;
2774
2820
  reportProgress();
2775
2821
  })
@@ -2793,7 +2839,7 @@ async function renderAnimation(browser, opts) {
2793
2839
  );
2794
2840
  return { bytes, totalFrames, chunks: chunks.length };
2795
2841
  } finally {
2796
- await context.close();
2842
+ await context2.close();
2797
2843
  server.close();
2798
2844
  }
2799
2845
  }
@@ -3297,11 +3343,11 @@ async function digestTake(browser, dir, opts = {}) {
3297
3343
  const server = await startTakeServer(dir, {
3298
3344
  "/digest.html": digestPageHtml()
3299
3345
  });
3300
- const context = await browser.newContext({
3346
+ const context2 = await browser.newContext({
3301
3347
  viewport: { width: 640, height: 360 }
3302
3348
  });
3303
3349
  try {
3304
- const page = await context.newPage();
3350
+ const page = await context2.newPage();
3305
3351
  page.on("console", (m) => {
3306
3352
  if (m.type() === "error")
3307
3353
  process.stderr.write(` [digest page] ${m.text()}
@@ -3369,7 +3415,7 @@ async function digestTake(browser, dir, opts = {}) {
3369
3415
  }
3370
3416
  if (sizes["sheet.png"]) sheet = "sheet.png";
3371
3417
  } finally {
3372
- await context.close();
3418
+ await context2.close();
3373
3419
  server.close();
3374
3420
  }
3375
3421
  } else {
@@ -3636,11 +3682,11 @@ async function framesTake(browser, dir, opts) {
3636
3682
  "/render.html": renderPageHtml()
3637
3683
  });
3638
3684
  const ss = stillSupersample(width, height);
3639
- const context = await browser.newContext({
3685
+ const context2 = await browser.newContext({
3640
3686
  viewport: { width: width * ss, height: height * ss }
3641
3687
  });
3642
3688
  try {
3643
- const page = await context.newPage();
3689
+ const page = await context2.newPage();
3644
3690
  page.on("console", (m) => {
3645
3691
  if (m.type() === "error")
3646
3692
  process.stderr.write(` [stills page] ${m.text()}
@@ -3683,7 +3729,7 @@ async function framesTake(browser, dir, opts) {
3683
3729
  }
3684
3730
  return { frames, width, height, duration, outDir };
3685
3731
  } finally {
3686
- await context.close();
3732
+ await context2.close();
3687
3733
  server.close();
3688
3734
  }
3689
3735
  }
@@ -4442,11 +4488,11 @@ var outputLength = (doc) => ratedSegments4(doc).reduce((acc, s) => {
4442
4488
  const rate = s.rate && s.rate > 0 ? s.rate : 1;
4443
4489
  return acc + (s.out - s.in) / rate;
4444
4490
  }, 0);
4445
- function templateWords(words) {
4446
- const headline = (words.headline ?? "").trim();
4447
- const kicker = (words.kicker ?? "").trim();
4448
- const brand = (words.brand ?? "").trim();
4449
- const sub = [brand, (words.release ?? "").trim()].filter(Boolean).join(" ");
4491
+ function templateWords(words2) {
4492
+ const headline = (words2.headline ?? "").trim();
4493
+ const kicker = (words2.kicker ?? "").trim();
4494
+ const brand = (words2.brand ?? "").trim();
4495
+ const sub = [brand, (words2.release ?? "").trim()].filter(Boolean).join(" ");
4450
4496
  const out = {};
4451
4497
  if (headline) {
4452
4498
  out["stage-title"] = headline;
@@ -4472,7 +4518,7 @@ var anchorWord = (at2) => typeof at2 === "object" ? `step ${at2.step}` : typeof
4472
4518
  var onWord = (v) => v === void 0 || /^(on|yes|true)$/i.test(v.trim());
4473
4519
  function proposeMotion(input, opts) {
4474
4520
  let doc = migrateMotion(structuredClone(input));
4475
- const { words, launch, catalog } = opts;
4521
+ const { words: words2, launch, catalog } = opts;
4476
4522
  const notes = [];
4477
4523
  const skipped = [];
4478
4524
  const footage = outputLength(doc);
@@ -4502,7 +4548,7 @@ function proposeMotion(input, opts) {
4502
4548
  (t) => !(t.from === END_CARD_FROM && off(endCardRole))
4503
4549
  );
4504
4550
  const namedEndCard = templates.some((t) => t.from === END_CARD_FROM);
4505
- const tWords = templateWords(words);
4551
+ const tWords = templateWords(words2);
4506
4552
  const keys = opts.mark ? { "stage-mark": opts.mark.key, "endcard-markimg": opts.mark.key } : void 0;
4507
4553
  for (const t of templates) {
4508
4554
  const at2 = resolveAnchor(doc, t.at);
@@ -4527,9 +4573,9 @@ function proposeMotion(input, opts) {
4527
4573
  else delete doc.frame.anim;
4528
4574
  }
4529
4575
  } else if (onWord(endCardRole) && !namedEndCard) {
4530
- const headline = (words.headline ?? "").trim();
4531
- const brand = (words.brand ?? "").trim();
4532
- const sub = [brand, (words.release ?? "").trim()].filter(Boolean).join(" ");
4576
+ const headline = (words2.headline ?? "").trim();
4577
+ const brand = (words2.brand ?? "").trim();
4578
+ const sub = [brand, (words2.release ?? "").trim()].filter(Boolean).join(" ");
4533
4579
  if (headline || brand) {
4534
4580
  const card = { seconds: END_CARD_SECONDS };
4535
4581
  if (opts.ink) card.ink = opts.ink;
@@ -6996,11 +7042,11 @@ async function readDigestActivity(dir) {
6996
7042
  return null;
6997
7043
  }
6998
7044
  }
6999
- function patchStageWords(doc, words) {
7045
+ function patchStageWords(doc, words2) {
7000
7046
  const map = {
7001
- "stage-title": words.headline,
7002
- "stage-kicker": words.kicker,
7003
- "stage-brand": words.brand
7047
+ "stage-title": words2.headline,
7048
+ "stage-kicker": words2.kicker,
7049
+ "stage-brand": words2.brand
7004
7050
  };
7005
7051
  for (const clip of doc.overlays ?? []) {
7006
7052
  if (clip.kind !== "text" || !isStageClip(clip)) continue;
@@ -7675,13 +7721,15 @@ async function pushTake(dir, flags, r) {
7675
7721
  if (upload.reused) r.log(" recording already hosted \u2014 reused");
7676
7722
  const docForPush = structuredClone(take.doc);
7677
7723
  docForPush.source.videoKey = assetUrl;
7678
- if (docForPush.source.camKey && !/^(https?:)?\//.test(docForPush.source.camKey)) {
7679
- r.log(" cam track is local-only \u2014 dropped from the push");
7680
- delete docForPush.source.camKey;
7681
- }
7682
- if (docForPush.source.micKey && !/^(https?:)?\//.test(docForPush.source.micKey)) {
7683
- r.log(" mic track is local-only \u2014 dropped from the push");
7684
- delete docForPush.source.micKey;
7724
+ await uploadDocRefs(sourceSidecarRefs(docForPush), dir, ctx, (l) => r.log(l));
7725
+ for (const field of ["micKey", "camKey"]) {
7726
+ const key = docForPush.source[field];
7727
+ if (key && isTakeRelativeKey(key)) {
7728
+ r.log(
7729
+ ` ${field === "micKey" ? "mic" : "cam"} track ${key} is not beside the take \u2014 left out of the push`
7730
+ );
7731
+ delete docForPush.source[field];
7732
+ }
7685
7733
  }
7686
7734
  await uploadDocRefs(docMediaRefs(docForPush), dir, ctx, (l) => r.log(l));
7687
7735
  const lowered = lowerToComposition3(docForPush);
@@ -8345,7 +8393,7 @@ with their key: vos push ${source} --vos ${String(created2.id ?? "<id>")}`
8345
8393
  void flags.yes;
8346
8394
  if (programDoc) {
8347
8395
  await uploadDocRefs(
8348
- docAudioRefs(soundOf(programDoc)),
8396
+ docLayerRefs(layersOf(programDoc)),
8349
8397
  dir,
8350
8398
  { origin, key },
8351
8399
  (l) => r.log(l)
@@ -8692,6 +8740,13 @@ function isTakeDir(target) {
8692
8740
  function soundOf(doc) {
8693
8741
  return { audio: Array.isArray(doc.audio) ? doc.audio : [] };
8694
8742
  }
8743
+ function layersOf(doc) {
8744
+ return {
8745
+ ...soundOf(doc),
8746
+ overlays: Array.isArray(doc.overlays) ? doc.overlays : [],
8747
+ objects: Array.isArray(doc.objects) ? doc.objects : []
8748
+ };
8749
+ }
8695
8750
  function storedProgramConfig(config, programDoc) {
8696
8751
  if (!programDoc) return config;
8697
8752
  const doc = { audio: [], ...programDoc };
@@ -8872,12 +8927,177 @@ async function cmdAsset(argv) {
8872
8927
  import { existsSync as existsSync16, rmSync as rmSync2, statSync as statSync4 } from "fs";
8873
8928
  import { join as join18 } from "path";
8874
8929
  import { createInterface as createInterface3 } from "readline/promises";
8875
- var BOOLEAN_FLAGS4 = /* @__PURE__ */ new Set(["json", "help", "yes"]);
8876
- async function cmdDelete(argv) {
8930
+
8931
+ // src/plugin/trash.ts
8932
+ var BOOLEAN_FLAGS4 = /* @__PURE__ */ new Set(["json", "help"]);
8933
+ var MONTHS = [
8934
+ "Jan",
8935
+ "Feb",
8936
+ "Mar",
8937
+ "Apr",
8938
+ "May",
8939
+ "Jun",
8940
+ "Jul",
8941
+ "Aug",
8942
+ "Sep",
8943
+ "Oct",
8944
+ "Nov",
8945
+ "Dec"
8946
+ ];
8947
+ function restoreDate(iso, now = /* @__PURE__ */ new Date()) {
8948
+ const d = new Date(iso);
8949
+ if (Number.isNaN(d.getTime())) return iso;
8950
+ const day = `${d.getUTCDate()} ${MONTHS[d.getUTCMonth()]}`;
8951
+ return d.getUTCFullYear() === now.getUTCFullYear() ? day : `${day} ${d.getUTCFullYear()}`;
8952
+ }
8953
+ function trashedBy(entry) {
8954
+ if (entry.deletedVia === "key") {
8955
+ return entry.deletedClient ?? entry.deletedKeyName ?? "a key";
8956
+ }
8957
+ if (entry.deletedVia === "admin") return "an admin";
8958
+ if (entry.deletedVia === "service") return "vos.so";
8959
+ return "you";
8960
+ }
8961
+ function sinceMoment(value, now = /* @__PURE__ */ new Date()) {
8962
+ const rel = /^(\d+(?:\.\d+)?)(s|m|h|d)$/.exec(value.trim());
8963
+ if (rel) {
8964
+ const unit = { s: 1e3, m: 6e4, h: 36e5, d: 864e5 }[rel[2]];
8965
+ return new Date(now.getTime() - Number(rel[1]) * unit);
8966
+ }
8967
+ const at2 = new Date(value);
8968
+ return Number.isNaN(at2.getTime()) ? null : at2;
8969
+ }
8970
+ function words(kind) {
8971
+ return kind === "vos" ? "vos" : kind === "folder" ? "project" : "file";
8972
+ }
8973
+ function context(flags) {
8974
+ const origin = platformOrigin({
8975
+ origin: strFlag(flags, "origin"),
8976
+ api: strFlag(flags, "api")
8977
+ }).replace(/\/+$/, "");
8978
+ return { origin, key: requireCredential(strFlag(flags, "key")) };
8979
+ }
8980
+ async function readTrash(ctx) {
8981
+ const res = await apiJson(ctx.origin, "/api/trash", { key: ctx.key });
8982
+ if (res.status !== 200) throw new Error(apiError("read Trash", res));
8983
+ return res.body.entries ?? [];
8984
+ }
8985
+ async function restore(ctx, body) {
8986
+ let restored = [];
8987
+ let missing = [];
8988
+ for (let pass = 0; pass < 100; pass++) {
8989
+ const res = await apiJson(ctx.origin, "/api/trash/restore", {
8990
+ method: "POST",
8991
+ key: ctx.key,
8992
+ body
8993
+ });
8994
+ if (res.status !== 200) throw new Error(apiError("restore", res));
8995
+ if (pass === 0) {
8996
+ restored = res.body.restored ?? [];
8997
+ missing = res.body.missing ?? [];
8998
+ }
8999
+ if (res.body.done !== false) break;
9000
+ }
9001
+ return { restored, missing };
9002
+ }
9003
+ async function cmdTrash(argv) {
8877
9004
  const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS4);
9005
+ const r = createReporter(flags.json === true);
9006
+ const ctx = context(flags);
9007
+ if (positionals[0] === "restore") {
9008
+ const raw = strFlag(flags, "since");
9009
+ const since = raw ? sinceMoment(raw) : null;
9010
+ if (!since)
9011
+ throw new UsageError(
9012
+ "vos trash restore --since <30m|1h|2d|ISO time> [--by <key name>] [--json]"
9013
+ );
9014
+ const by = strFlag(flags, "by");
9015
+ let keyId = null;
9016
+ if (by) {
9017
+ const match = (await readTrash(ctx)).find(
9018
+ (e) => e.deletedKeyName === by || e.deletedKeyId?.startsWith(by)
9019
+ );
9020
+ keyId = match?.deletedKeyId ?? null;
9021
+ if (!keyId)
9022
+ throw new Error(`nothing in Trash was moved there by a key named ${by}`);
9023
+ } else {
9024
+ const me = await apiJson(ctx.origin, "/api/user/whoami", {
9025
+ key: ctx.key
9026
+ });
9027
+ keyId = (me.body.key ?? null)?.id ?? null;
9028
+ if (me.status !== 200 || !keyId)
9029
+ throw new Error(
9030
+ "could not tell which key this is: pass --by <key name> (vos trash lists them)"
9031
+ );
9032
+ }
9033
+ const done = await restore(ctx, { keyId, since: since.toISOString() });
9034
+ r.done(
9035
+ { restored: done.restored, count: done.restored.length },
9036
+ done.restored.length ? `restored ${done.restored.length} item${done.restored.length === 1 ? "" : "s"} moved to Trash since ${since.toISOString()}` : `nothing was moved to Trash by that key since ${since.toISOString()}`
9037
+ );
9038
+ return EXIT_OK;
9039
+ }
9040
+ if (positionals[0])
9041
+ throw new UsageError(
9042
+ `vos trash has no "${positionals[0]}": vos trash, or vos trash restore --since <time>. Trash is emptied by a person, at vos.so/app/trash`
9043
+ );
9044
+ const entries2 = await readTrash(ctx);
9045
+ if (flags.json === true) {
9046
+ r.done({ entries: entries2, count: entries2.length }, "");
9047
+ return EXIT_OK;
9048
+ }
9049
+ if (entries2.length === 0) {
9050
+ r.done({ entries: entries2, count: 0 }, "Trash is empty");
9051
+ return EXIT_OK;
9052
+ }
9053
+ const lines = entries2.map((e) => {
9054
+ const inside = e.members ? ` (${e.members.voses} vos, ${e.members.assets} files)` : "";
9055
+ return ` ${words(e.kind).padEnd(7)} ${e.id} "${e.title}"${inside}: moved by ${trashedBy(e)}, restorable until ${restoreDate(e.restoreUntil)}`;
9056
+ });
9057
+ r.done(
9058
+ { entries: entries2, count: entries2.length },
9059
+ `${entries2.length} in Trash
9060
+ ${lines.join("\n")}
9061
+ restore one: vos restore <id> (emptying Trash is the person's act, at vos.so/app/trash)`
9062
+ );
9063
+ return EXIT_OK;
9064
+ }
9065
+ async function cmdRestore(argv) {
9066
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS4);
9067
+ if (positionals.length === 0)
9068
+ throw new UsageError("vos restore <id|watch-url> [...] [--json]");
9069
+ const r = createReporter(flags.json === true);
9070
+ const ctx = context(flags);
9071
+ const entries2 = await readTrash(ctx);
9072
+ const wanted = positionals.map((p) => parseVosId(p) ?? p);
9073
+ const units = wanted.map((id) => {
9074
+ const entry = entries2.find((e) => e.id === id);
9075
+ if (!entry)
9076
+ throw new Error(
9077
+ `${id} is not in Trash (vos trash lists what is; something inside a trashed project comes back with the project)`
9078
+ );
9079
+ return { kind: entry.kind, id: entry.id, title: entry.title };
9080
+ });
9081
+ const done = await restore(ctx, {
9082
+ ids: units.map(({ kind, id }) => ({ kind, id }))
9083
+ });
9084
+ const names = units.map((u) => `"${u.title}"`).join(", ");
9085
+ r.done(
9086
+ { restored: done.restored, count: done.restored.length },
9087
+ `restored ${names}`
9088
+ );
9089
+ return EXIT_OK;
9090
+ }
9091
+
9092
+ // src/plugin/remove.ts
9093
+ var BOOLEAN_FLAGS5 = /* @__PURE__ */ new Set(["json", "help", "yes", "dry-run"]);
9094
+ async function cmdDelete(argv) {
9095
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS5);
8878
9096
  const target = positionals[0];
8879
9097
  if (!target)
8880
- throw new UsageError("vos delete <vosId|watch-url|dir> [--yes] [--json]");
9098
+ throw new UsageError(
9099
+ "vos delete <vosId|watch-url|dir> [--yes] [--dry-run] [--json]"
9100
+ );
8881
9101
  const r = createReporter(flags.json === true);
8882
9102
  const origin = platformOrigin({
8883
9103
  origin: strFlag(flags, "origin"),
@@ -8894,24 +9114,33 @@ async function cmdDelete(argv) {
8894
9114
  if (meta.status !== 200) throw new Error(apiError(`read ${vosId}`, meta));
8895
9115
  const vos = meta.body.vos ?? {};
8896
9116
  const title = typeof vos.title === "string" ? vos.title : vosId;
9117
+ if (flags["dry-run"] === true) {
9118
+ r.done(
9119
+ { id: vosId, title, deleted: false, dryRun: true },
9120
+ `would move "${title}" (${vosId}) to Trash; nothing was changed`
9121
+ );
9122
+ return EXIT_OK;
9123
+ }
8897
9124
  if (flags.yes !== true) {
8898
9125
  if (!process.stdin.isTTY)
8899
9126
  throw new UsageError(
8900
- `deleting "${title}" (${vosId}) cannot be undone: re-run with --yes to confirm`
9127
+ `"${title}" (${vosId}) would move to Trash: re-run with --yes to confirm, or --dry-run to only look`
8901
9128
  );
8902
9129
  const rl = createInterface3({ input: process.stdin, output: process.stderr });
8903
9130
  const answer = await rl.question(
8904
- `Delete "${title}" (${vosId}) and every version of it? This cannot be undone. [y/N] `
9131
+ `Move "${title}" (${vosId}) to Trash? It stays restorable there for a while (vos restore ${vosId}). [y/N] `
8905
9132
  );
8906
9133
  rl.close();
8907
9134
  if (!/^y(es)?$/i.test(answer.trim())) {
8908
- r.done({ id: vosId, deleted: false }, "kept \u2014 nothing was deleted");
9135
+ r.done({ id: vosId, deleted: false }, "kept: nothing was deleted");
8909
9136
  return EXIT_OK;
8910
9137
  }
8911
9138
  }
8912
9139
  const res = await apiJson(origin, `/api/vos/${vosId}`, {
8913
9140
  method: "DELETE",
8914
- key
9141
+ key,
9142
+ // Who did it, for the person reading Trash later (display only).
9143
+ headers: { "x-vos-client": clientId() }
8915
9144
  });
8916
9145
  if (res.status !== 200 && res.status !== 204)
8917
9146
  throw new Error(apiError(`delete ${vosId}`, res));
@@ -8920,9 +9149,23 @@ async function cmdDelete(argv) {
8920
9149
  rmSync2(join18(dir, SYNC_STATE_NAME), { force: true });
8921
9150
  unlinked = true;
8922
9151
  }
9152
+ const trashed = res.body.trashed === true;
9153
+ const restoreUntil = typeof res.body.restoreUntil === "string" ? res.body.restoreUntil : null;
9154
+ const tail = unlinked ? `; ${dir} no longer tracks it` : "";
8923
9155
  r.done(
8924
- { id: vosId, title, deleted: true, unlinked },
8925
- `deleted "${title}" (${vosId})${unlinked ? `; ${dir} no longer tracks it` : ""}`
9156
+ {
9157
+ id: vosId,
9158
+ title,
9159
+ deleted: true,
9160
+ trashed,
9161
+ ...restoreUntil ? { restoreUntil } : {},
9162
+ unlinked
9163
+ },
9164
+ trashed ? `moved "${title}" (${vosId}) to Trash${restoreUntil ? `, restorable until ${restoreDate(restoreUntil)}` : ""}: vos restore ${vosId}${tail}` : (
9165
+ // A vos with no version (a refused hosted take's empty shell) has
9166
+ // nothing to restore, so the platform erases it.
9167
+ `deleted "${title}" (${vosId})${tail}`
9168
+ )
8926
9169
  );
8927
9170
  return EXIT_OK;
8928
9171
  }
@@ -9122,9 +9365,9 @@ function nonJson(value, path) {
9122
9365
  }
9123
9366
  return null;
9124
9367
  }
9125
- var BOOLEAN_FLAGS5 = /* @__PURE__ */ new Set(["json", "help"]);
9368
+ var BOOLEAN_FLAGS6 = /* @__PURE__ */ new Set(["json", "help"]);
9126
9369
  async function cmdBuild(argv) {
9127
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS5);
9370
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS6);
9128
9371
  const source = positionals[0];
9129
9372
  if (!source)
9130
9373
  throw new UsageError("vos build <program.mjs> [--out config.json] [--json]");
@@ -9166,7 +9409,7 @@ async function cmdBuild(argv) {
9166
9409
  import { spawnSync } from "child_process";
9167
9410
  import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
9168
9411
  import { join as join20, resolve as resolve8 } from "path";
9169
- var BOOLEAN_FLAGS6 = /* @__PURE__ */ new Set(["json", "help"]);
9412
+ var BOOLEAN_FLAGS7 = /* @__PURE__ */ new Set(["json", "help"]);
9170
9413
  function sampleTimes(duration, every) {
9171
9414
  const step = every > 0 ? every : 1;
9172
9415
  const out = [];
@@ -9217,7 +9460,7 @@ function probeSize(video) {
9217
9460
  return m ? { width: Number(m[1]), height: Number(m[2]) } : null;
9218
9461
  }
9219
9462
  async function cmdCompare(argv) {
9220
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS6);
9463
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS7);
9221
9464
  const source = positionals[0];
9222
9465
  const against = strFlag(flags, "against");
9223
9466
  if (!source || !against)
@@ -10362,8 +10605,8 @@ function toHex(css) {
10362
10605
  return `#${hex2(+m[1])}${hex2(+m[2])}${hex2(+m[3])}${a < 1 ? hex2(a * 255) : ""}`;
10363
10606
  }
10364
10607
  function keyFor(label, taken, prefix = "t") {
10365
- const words = label.replace(/[^A-Za-z0-9]+/g, " ").trim().split(" ").filter(Boolean).slice(0, 4);
10366
- let base = words.map(
10608
+ const words2 = label.replace(/[^A-Za-z0-9]+/g, " ").trim().split(" ").filter(Boolean).slice(0, 4);
10609
+ let base = words2.map(
10367
10610
  (w, i) => i === 0 ? w.toLowerCase() : w[0].toUpperCase() + w.slice(1).toLowerCase()
10368
10611
  ).join("");
10369
10612
  if (!base || /^[0-9]/.test(base)) base = prefix + (base || "");
@@ -10424,8 +10667,8 @@ function planScaffold(inv, opts) {
10424
10667
  for (const t of inv.texts) {
10425
10668
  const generic = /^(div|span|p|h[1-6]|li|a|b|i|em|strong)-\d+$/.test(t.id);
10426
10669
  const key = keyFor(generic ? t.text : t.id, taken);
10427
- const words = t.font.transform === "uppercase" ? t.text.toUpperCase() : t.font.transform === "lowercase" ? t.text.toLowerCase() : t.text;
10428
- data[key] = words;
10670
+ const words2 = t.font.transform === "uppercase" ? t.text.toUpperCase() : t.font.transform === "lowercase" ? t.text.toLowerCase() : t.text;
10671
+ data[key] = words2;
10429
10672
  const family = faceFor(t);
10430
10673
  elements.push({
10431
10674
  id: key,
@@ -10444,7 +10687,7 @@ function planScaffold(inv, opts) {
10444
10687
  } : {}
10445
10688
  }
10446
10689
  });
10447
- textKeys.push({ key, size: t.font.size, label: words.slice(0, 40) });
10690
+ textKeys.push({ key, size: t.font.size, label: words2.slice(0, 40) });
10448
10691
  if (t.scene && sceneNames.has(t.scene))
10449
10692
  (sceneElements[t.scene] ??= []).push(key);
10450
10693
  }
@@ -10742,7 +10985,7 @@ function reportText(inv, r) {
10742
10985
  "",
10743
10986
  "## Images and video",
10744
10987
  "",
10745
- "Not placed: upload each with `vos asset upload` and add an image or video element over its hosted URL.",
10988
+ "Not placed: upload each with `vos asset push` and add an image or video element over its hosted URL.",
10746
10989
  "",
10747
10990
  ...inv.media.filter((m) => m.kind === "image" || m.kind === "video").map((m) => `- ${m.kind} ${m.src ?? "(inline)"}`)
10748
10991
  ] : [],
@@ -10776,7 +11019,7 @@ function probeAudioDuration(file) {
10776
11019
  }
10777
11020
 
10778
11021
  // src/plugin/port.ts
10779
- var BOOLEAN_FLAGS7 = /* @__PURE__ */ new Set(["json", "help"]);
11022
+ var BOOLEAN_FLAGS8 = /* @__PURE__ */ new Set(["json", "help"]);
10780
11023
  async function cmdPort(argv) {
10781
11024
  const [sub, ...rest] = argv;
10782
11025
  if (sub === "inventory") return await inventory(rest);
@@ -10786,7 +11029,7 @@ async function cmdPort(argv) {
10786
11029
  );
10787
11030
  }
10788
11031
  async function inventory(argv) {
10789
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS7);
11032
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS8);
10790
11033
  const source = positionals[0] ?? ".";
10791
11034
  const r = createReporter(flags.json === true);
10792
11035
  const outDir = resolve11(strFlag(flags, "out") ?? "port");
@@ -10827,7 +11070,7 @@ function summary(inv) {
10827
11070
  };
10828
11071
  }
10829
11072
  async function scaffold(argv) {
10830
- const { flags } = parseArgs(argv, BOOLEAN_FLAGS7);
11073
+ const { flags } = parseArgs(argv, BOOLEAN_FLAGS8);
10831
11074
  const r = createReporter(flags.json === true);
10832
11075
  const from = resolve11(strFlag(flags, "from") ?? join24("port", "inventory.json"));
10833
11076
  if (!existsSync20(from))
@@ -10866,7 +11109,7 @@ function scaffoldSourceDir(inv) {
10866
11109
  // src/plugin/recipe.ts
10867
11110
  import { readFileSync as readFileSync8 } from "fs";
10868
11111
  import { basename as basename9 } from "path";
10869
- var BOOLEAN_FLAGS8 = /* @__PURE__ */ new Set(["json", "help"]);
11112
+ var BOOLEAN_FLAGS9 = /* @__PURE__ */ new Set(["json", "help"]);
10870
11113
  var USAGE = "vos recipe push <file.md> (--folder <folderId|slug> | --asset <assetId>)";
10871
11114
  function recipeFilename(file) {
10872
11115
  const name = basename9(file);
@@ -10876,7 +11119,7 @@ function recipeFilename(file) {
10876
11119
  return name;
10877
11120
  }
10878
11121
  async function cmdPush2(argv) {
10879
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS8);
11122
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS9);
10880
11123
  const [file] = positionals;
10881
11124
  const folderRef = strFlag(flags, "folder");
10882
11125
  const assetId = strFlag(flags, "asset");
@@ -11977,7 +12220,7 @@ import {
11977
12220
  Output,
11978
12221
  WebMOutputFormat
11979
12222
  } from "mediabunny";
11980
- var BOOLEAN_FLAGS9 = /* @__PURE__ */ new Set(["json", "help"]);
12223
+ var BOOLEAN_FLAGS10 = /* @__PURE__ */ new Set(["json", "help"]);
11981
12224
  async function probeVideoFile(path) {
11982
12225
  const input = new Input({
11983
12226
  source: new FilePathSource(path),
@@ -12068,7 +12311,7 @@ function parseViewport(v) {
12068
12311
  return { width: Number(m[1]), height: Number(m[2]) };
12069
12312
  }
12070
12313
  async function cmdIngest(argv) {
12071
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS9, MULTI_FLAGS2);
12314
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS10, MULTI_FLAGS2);
12072
12315
  const source = positionals[0];
12073
12316
  if (!source)
12074
12317
  throw new UsageError(
@@ -12274,6 +12517,7 @@ var RULES_BODY = `## Product videos (vosso)
12274
12517
  - Look before you cut: vos frames take --at-zooms; edit take/doc.json and re-render, never re-record
12275
12518
  - Hand back: vos open take serves the take into the studio at vos.so, doc.json intact
12276
12519
  - Local by default: vos push only when asked for a link, the shelf or a cloud render
12520
+ - Deleting: vos delete moves a vos to Trash and vos restore brings it back; if you deleted by mistake, restore it and say so. Only the person can delete forever, at vos.so/app/trash
12277
12521
  - Credentials: VOS_API_KEY, then ~/.config/vos/credentials, then vos login; never print one
12278
12522
  - Reference: https://vos.so/llms-full.txt`;
12279
12523
  var RULES_BLOCK = `${RULES_BEGIN}
@@ -12422,7 +12666,7 @@ function bundledSkillsDir(from) {
12422
12666
  }
12423
12667
 
12424
12668
  // src/plugin/machineCmd.ts
12425
- var BOOLEAN_FLAGS10 = /* @__PURE__ */ new Set([
12669
+ var BOOLEAN_FLAGS11 = /* @__PURE__ */ new Set([
12426
12670
  "json",
12427
12671
  "help",
12428
12672
  "global",
@@ -12500,7 +12744,7 @@ async function doctorFacts(opts) {
12500
12744
  };
12501
12745
  }
12502
12746
  async function cmdSetup(argv) {
12503
- const { flags } = parseArgs(argv, BOOLEAN_FLAGS10);
12747
+ const { flags } = parseArgs(argv, BOOLEAN_FLAGS11);
12504
12748
  const r = reporterFor(flags);
12505
12749
  const root = process.cwd();
12506
12750
  const global = flags.global === true;
@@ -12619,7 +12863,7 @@ Next: ${report.next_step}`
12619
12863
  return report.ok ? EXIT_OK : EXIT_NO_BROWSER;
12620
12864
  }
12621
12865
  async function cmdDoctor(argv) {
12622
- const { flags } = parseArgs(argv, BOOLEAN_FLAGS10);
12866
+ const { flags } = parseArgs(argv, BOOLEAN_FLAGS11);
12623
12867
  const r = reporterFor(flags);
12624
12868
  const root = process.cwd();
12625
12869
  const homes = detectAgents(root, { home: homedir2(), global: true });
@@ -12638,7 +12882,7 @@ Next: ${report.next_step}`
12638
12882
  return report.ok ? EXIT_OK : EXIT_NO_BROWSER;
12639
12883
  }
12640
12884
  async function cmdWhoami(argv) {
12641
- const { flags } = parseArgs(argv, BOOLEAN_FLAGS10);
12885
+ const { flags } = parseArgs(argv, BOOLEAN_FLAGS11);
12642
12886
  const r = reporterFor(flags);
12643
12887
  const origin = platformOrigin({
12644
12888
  origin: strFlag(flags, "origin"),
@@ -12700,7 +12944,7 @@ async function cmdWhoami(argv) {
12700
12944
  return EXIT_OK;
12701
12945
  }
12702
12946
  function cmdLogout(argv) {
12703
- const { flags } = parseArgs(argv, BOOLEAN_FLAGS10);
12947
+ const { flags } = parseArgs(argv, BOOLEAN_FLAGS11);
12704
12948
  const r = reporterFor(flags);
12705
12949
  const had = existsSync23(CREDENTIALS_PATH);
12706
12950
  rmSync3(CREDENTIALS_PATH, { force: true });
@@ -12718,7 +12962,7 @@ function cmdLogout(argv) {
12718
12962
  }
12719
12963
 
12720
12964
  // src/plugin/run.ts
12721
- var BOOLEAN_FLAGS11 = /* @__PURE__ */ new Set([
12965
+ var BOOLEAN_FLAGS12 = /* @__PURE__ */ new Set([
12722
12966
  "json",
12723
12967
  "help",
12724
12968
  "wait",
@@ -12820,16 +13064,29 @@ Platform (vos.so) \u2014 fetch, edit, push, pull, repeat
12820
13064
  --override consents to touching
12821
13065
  protected (human-edited) nodes, ONLY when the user asked.
12822
13066
  Without --folder a new vos lands unfiled, at the root of your
12823
- shelf. A document's local sound (doc.json audio keys) uploads
12824
- with the push. --wait stays until the version's still has
13067
+ shelf. A document's local files (doc.json: picture and video
13068
+ overlays, 3D props, sound; a take's mic and cam too) upload
13069
+ with the push, each once. --wait stays until the version's still has
12825
13070
  rendered and prints absolute still and preview links.
12826
13071
  --still <seconds> sets a PROGRAM's cover (doc.json "still", kept
12827
13072
  by every later push); without it the platform picks an early
12828
13073
  frame. A take's cover is its doc.json "still".
12829
- vos delete <vosId|watch-url|dir> [--yes] [--json]
12830
- take a vos off vos.so, every version of it, for good. Asks on a
12831
- terminal; headless it needs --yes. A dir that tracked it is
12832
- unlinked (its vos.json removed)
13074
+ vos delete <vosId|watch-url|dir> [--yes] [--dry-run] [--json]
13075
+ move a vos to Trash on vos.so. Nothing is erased: it stays
13076
+ restorable until the date the delete prints (vos restore <id>).
13077
+ Asks on a terminal; headless it needs --yes. --dry-run names
13078
+ what would move and changes nothing. A dir that tracked it is
13079
+ unlinked (its vos.json removed). Needs a key with the delete
13080
+ scope; no key can delete forever, only the person can, on the
13081
+ web
13082
+ vos trash [--json]
13083
+ what is in Trash on vos.so: what, moved by whom, restorable
13084
+ until when
13085
+ vos restore <id|watch-url> [...] [--json]
13086
+ bring those back from Trash, as they were
13087
+ vos trash restore --since <30m|1h|2d|ISO> [--by <key name>] [--json]
13088
+ undo everything this key (or the named one) moved to Trash
13089
+ since then
12833
13090
  vos pull [dir|take] [--vos <id>] [--since versionId] [--check] [--media] [--json]
12834
13091
  what changed on vos.so since your base; syncs config.json (backup
12835
13092
  kept) or the take's doc.json. ALWAYS pull before editing pushed work.
@@ -13175,7 +13432,7 @@ function wallGate(flags, r, opts) {
13175
13432
  async function cmdRecord(argv) {
13176
13433
  const { positionals, flags, multi } = parseArgs(
13177
13434
  argv,
13178
- BOOLEAN_FLAGS11,
13435
+ BOOLEAN_FLAGS12,
13179
13436
  MULTI_FLAGS2
13180
13437
  );
13181
13438
  const actionsPath = strFlag(flags, "actions") ?? positionals[0];
@@ -13296,10 +13553,10 @@ async function cmdRecord(argv) {
13296
13553
  const rec = await inSession(
13297
13554
  sessionName,
13298
13555
  actions,
13299
- (context) => recordTake(browser2, url, actions, takePaths(outDir), r.log, {
13556
+ (context2) => recordTake(browser2, url, actions, takePaths(outDir), r.log, {
13300
13557
  storageState,
13301
13558
  headers,
13302
- context,
13559
+ context: context2,
13303
13560
  dryRun: true,
13304
13561
  // A rehearsal is always strict, and it touches no directory.
13305
13562
  onArrival: wallGate(flags, r, { strict: true })
@@ -13358,11 +13615,11 @@ ${lines.join("\n")}
13358
13615
  const rec = await inSession(
13359
13616
  sessionName,
13360
13617
  actions,
13361
- (context) => recordTake(browser, url, actions, paths, r.log, {
13618
+ (context2) => recordTake(browser, url, actions, paths, r.log, {
13362
13619
  maxDurationSeconds,
13363
13620
  storageState,
13364
13621
  headers,
13365
- context,
13622
+ context: context2,
13366
13623
  onArrival: wallGate(flags, r, {
13367
13624
  strict: flags.strict === true,
13368
13625
  prepare
@@ -13417,7 +13674,7 @@ ${lines.join("\n")}
13417
13674
  async function cmdCreate2(argv) {
13418
13675
  const { positionals, flags, multi } = parseArgs(
13419
13676
  argv,
13420
- BOOLEAN_FLAGS11,
13677
+ BOOLEAN_FLAGS12,
13421
13678
  MULTI_FLAGS2
13422
13679
  );
13423
13680
  const actionsPath = strFlag(flags, "actions");
@@ -13462,11 +13719,11 @@ async function cmdCreate2(argv) {
13462
13719
  const rec = await inSession(
13463
13720
  sessionName,
13464
13721
  actions,
13465
- (context) => recordTake(browser, url, actions, paths, r.log, {
13722
+ (context2) => recordTake(browser, url, actions, paths, r.log, {
13466
13723
  maxDurationSeconds,
13467
13724
  storageState,
13468
13725
  headers,
13469
- context,
13726
+ context: context2,
13470
13727
  onArrival: wallGate(flags, r, {
13471
13728
  strict: flags.strict === true,
13472
13729
  prepare
@@ -13543,7 +13800,7 @@ async function cmdCreate2(argv) {
13543
13800
  async function cmdPlan(argv) {
13544
13801
  const { positionals, flags, multi } = parseArgs(
13545
13802
  argv,
13546
- BOOLEAN_FLAGS11,
13803
+ BOOLEAN_FLAGS12,
13547
13804
  /* @__PURE__ */ new Set(["with"])
13548
13805
  );
13549
13806
  const dir = positionals[0];
@@ -13644,7 +13901,7 @@ async function releaseInputs(dir, flags, r, withRefs = []) {
13644
13901
  }
13645
13902
  const launch = await readLaunchBesideTake(dir, strFlag(flags, "launch"));
13646
13903
  const lines = (v) => v === null || v === void 0 ? null : v.replace(/\\n/g, "\n");
13647
- const words = {
13904
+ const words2 = {
13648
13905
  headline: lines(strFlag(flags, "headline") ?? launch?.roles.headline),
13649
13906
  kicker: lines(strFlag(flags, "kicker") ?? launch?.roles.kicker),
13650
13907
  brand: strFlag(flags, "brand-name") ?? lookPick.roles?.wordmark ?? null,
@@ -13729,7 +13986,7 @@ async function releaseInputs(dir, flags, r, withRefs = []) {
13729
13986
  }
13730
13987
  }
13731
13988
  return {
13732
- words,
13989
+ words: words2,
13733
13990
  launchRoles,
13734
13991
  ink: endCardInk(lookPick.look, lookPick.roles),
13735
13992
  mark,
@@ -13741,7 +13998,7 @@ async function releaseInputs(dir, flags, r, withRefs = []) {
13741
13998
  async function cmdRender(argv) {
13742
13999
  const { positionals, flags, multi } = parseArgs(
13743
14000
  argv,
13744
- BOOLEAN_FLAGS11,
14001
+ BOOLEAN_FLAGS12,
13745
14002
  MULTI_FLAGS2
13746
14003
  );
13747
14004
  const dir = positionals[0];
@@ -13809,7 +14066,7 @@ async function cmdRender(argv) {
13809
14066
  async function cmdFrames(argv) {
13810
14067
  const { positionals, flags, multi } = parseArgs(
13811
14068
  argv,
13812
- BOOLEAN_FLAGS11,
14069
+ BOOLEAN_FLAGS12,
13813
14070
  MULTI_FLAGS2
13814
14071
  );
13815
14072
  const dir = positionals[0];
@@ -13882,7 +14139,7 @@ async function cmdFrames(argv) {
13882
14139
  async function cmdDeliver(argv) {
13883
14140
  const { positionals, flags, multi } = parseArgs(
13884
14141
  argv,
13885
- BOOLEAN_FLAGS11,
14142
+ BOOLEAN_FLAGS12,
13886
14143
  MULTI_FLAGS2
13887
14144
  );
13888
14145
  const dir = positionals[0];
@@ -14048,7 +14305,7 @@ async function officialTemplate(origin, ref) {
14048
14305
  }
14049
14306
  }
14050
14307
  async function cmdDigest(argv) {
14051
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS11);
14308
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS12);
14052
14309
  const dir = positionals[0];
14053
14310
  if (!dir)
14054
14311
  throw new UsageError(
@@ -14112,7 +14369,7 @@ async function cmdDigest(argv) {
14112
14369
  }
14113
14370
  }
14114
14371
  async function cmdOpen(argv) {
14115
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS11);
14372
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS12);
14116
14373
  const dir = positionals[0];
14117
14374
  if (!dir) throw new UsageError("vos open <take> [--studio <url>]");
14118
14375
  const r = createReporter(flags.json === true);
@@ -14150,7 +14407,7 @@ async function cmdOpen(argv) {
14150
14407
  return EXIT_OK;
14151
14408
  }
14152
14409
  async function cmdJudge(argv) {
14153
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS11);
14410
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS12);
14154
14411
  const target = positionals[0];
14155
14412
  const against = strFlag(flags, "against");
14156
14413
  if (!target || !against)
@@ -14179,7 +14436,7 @@ Win rate so far: ${rate.wins} win(s), ${rate.ties} tie(s) of ${rate.judged} judg
14179
14436
  return EXIT_OK;
14180
14437
  }
14181
14438
  async function cmdCallout(argv) {
14182
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS11);
14439
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS12);
14183
14440
  const dir = positionals[0];
14184
14441
  const shape = positionals[1];
14185
14442
  if (!dir || !shape || !isCalloutShape(shape))
@@ -14204,19 +14461,19 @@ async function cmdCallout(argv) {
14204
14461
  );
14205
14462
  const codeFile = strFlag(flags, "code-file");
14206
14463
  const code = codeFile ? await readFile17(codeFile, "utf8") : strFlag(flags, "code");
14207
- const words = {
14464
+ const words2 = {
14208
14465
  kicker: strFlag(flags, "kicker"),
14209
14466
  title: strFlag(flags, "title"),
14210
14467
  body: strFlag(flags, "body"),
14211
14468
  code: code?.replace(/\\n/g, "\n")
14212
14469
  };
14213
- if (shape === "code" && !words.code)
14470
+ if (shape === "code" && !words2.code)
14214
14471
  throw new UsageError(
14215
14472
  'a code callout needs --code "\u2026" or --code-file <file>'
14216
14473
  );
14217
- if (shape === "note" && !words.title)
14474
+ if (shape === "note" && !words2.title)
14218
14475
  throw new UsageError('a note needs --title "\u2026"');
14219
- if (shape === "tag" && !words.kicker && !words.title)
14476
+ if (shape === "tag" && !words2.kicker && !words2.title)
14220
14477
  throw new UsageError('a tag needs --kicker "\u2026"');
14221
14478
  const stepRaw = strFlag(flags, "step");
14222
14479
  const atRaw = strFlag(flags, "at");
@@ -14227,7 +14484,7 @@ async function cmdCallout(argv) {
14227
14484
  try {
14228
14485
  composed = composeCallout(take.doc, register, {
14229
14486
  shape,
14230
- words,
14487
+ words: words2,
14231
14488
  id: strFlag(flags, "id"),
14232
14489
  step: stepRaw !== void 0 ? /^\d+$/.test(stepRaw) ? Number(stepRaw) : stepRaw : void 0,
14233
14490
  at: atRaw !== void 0 ? Number(atRaw) : void 0,
@@ -14278,7 +14535,7 @@ async function cmdCallout(argv) {
14278
14535
  return EXIT_OK;
14279
14536
  }
14280
14537
  async function cmdValidate(argv) {
14281
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS11);
14538
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS12);
14282
14539
  const target = positionals[0];
14283
14540
  if (!target) throw new UsageError("vos validate <actions.json|take>");
14284
14541
  const r = createReporter(flags.json === true);
@@ -14440,7 +14697,7 @@ async function cmdValidate(argv) {
14440
14697
  async function cmdPush3(argv) {
14441
14698
  const { positionals, flags, multi } = parseArgs(
14442
14699
  argv,
14443
- BOOLEAN_FLAGS11,
14700
+ BOOLEAN_FLAGS12,
14444
14701
  MULTI_FLAGS2
14445
14702
  );
14446
14703
  const dir = positionals[0];
@@ -14504,7 +14761,7 @@ ${landedLines(landed)}` : "")
14504
14761
  return EXIT_OK;
14505
14762
  }
14506
14763
  async function cmdPull2(argv) {
14507
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS11, MULTI_FLAGS2);
14764
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS12, MULTI_FLAGS2);
14508
14765
  const dir = positionals[0] ?? ".";
14509
14766
  const r = createReporter(flags.json === true);
14510
14767
  const result = await pullTake(
@@ -14617,6 +14874,10 @@ async function run(argv) {
14617
14874
  }
14618
14875
  case "delete":
14619
14876
  return await cmdDelete(rest);
14877
+ case "trash":
14878
+ return await cmdTrash(rest);
14879
+ case "restore":
14880
+ return await cmdRestore(rest);
14620
14881
  case "build":
14621
14882
  return await cmdBuild(rest);
14622
14883
  case "compare":
@@ -14669,7 +14930,7 @@ async function run(argv) {
14669
14930
  }
14670
14931
  }
14671
14932
  async function cmdSession(argv) {
14672
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS11);
14933
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS12);
14673
14934
  const [sub, arg] = positionals;
14674
14935
  const r = createReporter(flags.json === true);
14675
14936
  const usage = "vos session open <url> --name <app> | check <name> [--url <url>] | list | rm <name>";
@@ -14809,4 +15070,4 @@ export {
14809
15070
  verbHelp,
14810
15071
  run
14811
15072
  };
14812
- //# sourceMappingURL=chunk-RZZUR2IF.js.map
15073
+ //# sourceMappingURL=chunk-67L7FPJR.js.map