@vosjs/cli 0.58.1 → 0.59.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.
@@ -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
@@ -176,6 +176,7 @@ import {
176
176
  pinCandidates,
177
177
  pinRectOnScreen,
178
178
  pinReferent,
179
+ parseEmphasis,
179
180
  ratedSegments,
180
181
  recommendedExportResolution,
181
182
  resolvePins,
@@ -479,6 +480,23 @@ function lintDoc(docIn) {
479
480
  if (z.focusMode !== void 0 && z.focusMode !== "manual" && z.focusMode !== "auto") {
480
481
  problems.push(`${name}: focusMode must be 'manual' or 'auto'`);
481
482
  }
483
+ if (z.screen !== void 0) {
484
+ const sp = z.screen;
485
+ const ok = !!sp && typeof sp === "object" && isNum(sp.x) && isNum(sp.y) && sp.x >= 0 && sp.x <= 1 && sp.y >= 0 && sp.y <= 1;
486
+ if (!ok) {
487
+ problems.push(
488
+ `${name}: screen must be { x, y } in 0..1 \u2014 where the target lands as FRACTIONS of the frame (0.35, 0.5 = a third across, centred), not pixels`
489
+ );
490
+ } else if (z.focusMode === "auto") {
491
+ warnings.push(
492
+ `${name}: screen is ignored on a span that follows the cursor (focusMode 'auto'); drop one or the other`
493
+ );
494
+ } else if (cameraModel(doc.frame) !== "stage") {
495
+ warnings.push(
496
+ `${name}: screen places the target under the stage camera only (frame.camera: 'stage'); the magnifier keeps the target where it is`
497
+ );
498
+ }
499
+ }
482
500
  if (z.source !== void 0 && z.source !== "manual" && z.source !== "auto") {
483
501
  problems.push(`${name}: source must be 'manual' or 'auto'`);
484
502
  }
@@ -1000,6 +1018,23 @@ function lintDoc(docIn) {
1000
1018
  `${name}.preset "${String(o.preset)}" is not a known preset (${PRESETS.join("|")}) \u2014 falls back to "title"`
1001
1019
  );
1002
1020
  }
1021
+ if (o.emphasis !== void 0) {
1022
+ const em = o.emphasis;
1023
+ if (!em || typeof em !== "object" || Array.isArray(em)) {
1024
+ problems.push(
1025
+ `${name}.emphasis must be { weight?, color? } ({} turns *markers* on)`
1026
+ );
1027
+ } else {
1028
+ if (em.weight !== void 0 && (!isNum(em.weight) || em.weight < 100 || em.weight > 900))
1029
+ problems.push(`${name}.emphasis.weight must be 100..900`);
1030
+ if (em.color !== void 0 && typeof em.color !== "string")
1031
+ problems.push(`${name}.emphasis.color must be a CSS colour`);
1032
+ }
1033
+ } else if (typeof o.text === "string" && parseEmphasis(o.text) !== null) {
1034
+ warnings.push(
1035
+ `${name}.text has *marked* words but no emphasis, so the asterisks show as typed; add emphasis: {} to set them bold (\\* keeps one literal)`
1036
+ );
1037
+ }
1003
1038
  if (o.size !== void 0 && (!isNum(o.size) || o.size < 12 || o.size > 200)) {
1004
1039
  problems.push(`${name}.size must be design px in 12..200`);
1005
1040
  }
@@ -1632,7 +1667,13 @@ function framingWarnings(docIn, doc, zoom, overlays, warnings) {
1632
1667
  }
1633
1668
  const rect = { x: x0, y: y0, w: x1 - x0, h: y1 - y0 };
1634
1669
  if (!zoomCoversRect(
1635
- { level: z.level, cx: z.cx, cy: z.cy },
1670
+ {
1671
+ level: z.level,
1672
+ cx: z.cx,
1673
+ cy: z.cy,
1674
+ screen: z.screen,
1675
+ focusMode: z.focusMode
1676
+ },
1636
1677
  rect,
1637
1678
  layout,
1638
1679
  0.02,
@@ -1659,7 +1700,7 @@ function framingWarnings(docIn, doc, zoom, overlays, warnings) {
1659
1700
  if (!tf || !isNum(tf.x) || !isNum(tf.y)) return;
1660
1701
  const pinned = pins.get(String(o.id));
1661
1702
  if (!pinned && o.pin === void 0 && (o.kind === "html" || o.kind === "image" || o.kind === "video")) {
1662
- const words = layerWords(o);
1703
+ const words2 = layerWords(o);
1663
1704
  let layerBox = null;
1664
1705
  try {
1665
1706
  const b = pinBox(o, layout);
@@ -1677,7 +1718,7 @@ function framingWarnings(docIn, doc, zoom, overlays, warnings) {
1677
1718
  start: o.start,
1678
1719
  duration: o.duration
1679
1720
  })) {
1680
- const named = c.selector ? selectorLabelWords(c.selector).filter((x) => words.has(x)) : [];
1721
+ const named = c.selector ? selectorLabelWords(c.selector).filter((x) => words2.has(x)) : [];
1681
1722
  if (named.length) {
1682
1723
  about.push({
1683
1724
  step: String(c.step),
@@ -2042,6 +2083,60 @@ function isTakeRelativeKey(key) {
2042
2083
  return !!key && !/^(https?:|blob:|data:|media:|\/\/)/.test(key) && !key.startsWith("/api/");
2043
2084
  }
2044
2085
  var takeRelativeFile = (key) => key.replace(/^\/+/, "");
2086
+ function sourceSidecarRefs(doc, keep = isTakeRelativeKey) {
2087
+ const out = [];
2088
+ for (const [field, where] of [
2089
+ ["micKey", "mic track"],
2090
+ ["camKey", "cam track"]
2091
+ ]) {
2092
+ const key = doc.source[field];
2093
+ if (!key || !keep(key)) continue;
2094
+ out.push({
2095
+ where,
2096
+ key,
2097
+ set: (next) => {
2098
+ doc.source[field] = next;
2099
+ }
2100
+ });
2101
+ }
2102
+ return out;
2103
+ }
2104
+ function docObjectRefs(doc, keep = isTakeRelativeKey) {
2105
+ const out = [];
2106
+ for (const clip of doc.objects ?? []) {
2107
+ const asset = clip.asset;
2108
+ if (asset.kind !== "gltf" || !keep(asset.key)) continue;
2109
+ out.push({
2110
+ where: `object ${clip.id}`,
2111
+ key: asset.key,
2112
+ set: (next) => {
2113
+ asset.key = next;
2114
+ }
2115
+ });
2116
+ }
2117
+ return out;
2118
+ }
2119
+ function docOverlayRefs(doc, keep = isTakeRelativeKey) {
2120
+ const out = [];
2121
+ for (const clip of doc.overlays ?? []) {
2122
+ if (!isKeyedOverlay(clip) || !keep(clip.key)) continue;
2123
+ out.push({
2124
+ where: `overlay ${clip.id}`,
2125
+ key: clip.key,
2126
+ set: (next) => {
2127
+ clip.key = next;
2128
+ }
2129
+ });
2130
+ }
2131
+ return out;
2132
+ }
2133
+ function docLayerRefs(doc, keep = isTakeRelativeKey) {
2134
+ return [
2135
+ ...docOverlayRefs(doc, keep),
2136
+ ...docObjectRefs(doc, keep),
2137
+ ...docAudioRefs(doc, keep)
2138
+ ];
2139
+ }
2045
2140
  function docMediaRefs(doc, keep = isTakeRelativeKey) {
2046
2141
  const out = [];
2047
2142
  for (const m of doc.media ?? []) {
@@ -2072,16 +2167,8 @@ function docMediaRefs(doc, keep = isTakeRelativeKey) {
2072
2167
  }
2073
2168
  });
2074
2169
  }
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
- }
2170
+ out.push(...docOverlayRefs(doc, keep));
2171
+ out.push(...docObjectRefs(doc, keep));
2085
2172
  const mark = doc.endCard?.mark;
2086
2173
  if (mark && keep(mark.key))
2087
2174
  out.push({
@@ -2688,9 +2775,9 @@ async function renderInPage(opts) {
2688
2775
  w.__error = String(e instanceof Error && e.stack || e);
2689
2776
  }
2690
2777
  }
2691
- async function renderChunk(context, serverBase, chunk2, opts, onChunkProgress) {
2778
+ async function renderChunk(context2, serverBase, chunk2, opts, onChunkProgress) {
2692
2779
  const outName = `render-chunk-${chunk2.index}.tmp`;
2693
- const page = await context.newPage();
2780
+ const page = await context2.newPage();
2694
2781
  try {
2695
2782
  page.on("console", (m) => {
2696
2783
  if (m.type() === "error" || process.env.VOS_RENDER_DEBUG)
@@ -2755,7 +2842,7 @@ async function renderAnimation(browser, opts) {
2755
2842
  const server = await startTakeServer(opts.workDir, {
2756
2843
  "/render.html": renderPageHtml()
2757
2844
  });
2758
- const context = await browser.newContext({
2845
+ const context2 = await browser.newContext({
2759
2846
  viewport: { width: opts.width, height: opts.height }
2760
2847
  });
2761
2848
  try {
@@ -2769,7 +2856,7 @@ async function renderAnimation(browser, opts) {
2769
2856
  };
2770
2857
  const outNames = await Promise.all(
2771
2858
  chunks.map(
2772
- (chunk2) => renderChunk(context, server.base, chunk2, effOpts, (fraction) => {
2859
+ (chunk2) => renderChunk(context2, server.base, chunk2, effOpts, (fraction) => {
2773
2860
  progress[chunk2.index] = fraction;
2774
2861
  reportProgress();
2775
2862
  })
@@ -2793,7 +2880,7 @@ async function renderAnimation(browser, opts) {
2793
2880
  );
2794
2881
  return { bytes, totalFrames, chunks: chunks.length };
2795
2882
  } finally {
2796
- await context.close();
2883
+ await context2.close();
2797
2884
  server.close();
2798
2885
  }
2799
2886
  }
@@ -3297,11 +3384,11 @@ async function digestTake(browser, dir, opts = {}) {
3297
3384
  const server = await startTakeServer(dir, {
3298
3385
  "/digest.html": digestPageHtml()
3299
3386
  });
3300
- const context = await browser.newContext({
3387
+ const context2 = await browser.newContext({
3301
3388
  viewport: { width: 640, height: 360 }
3302
3389
  });
3303
3390
  try {
3304
- const page = await context.newPage();
3391
+ const page = await context2.newPage();
3305
3392
  page.on("console", (m) => {
3306
3393
  if (m.type() === "error")
3307
3394
  process.stderr.write(` [digest page] ${m.text()}
@@ -3369,7 +3456,7 @@ async function digestTake(browser, dir, opts = {}) {
3369
3456
  }
3370
3457
  if (sizes["sheet.png"]) sheet = "sheet.png";
3371
3458
  } finally {
3372
- await context.close();
3459
+ await context2.close();
3373
3460
  server.close();
3374
3461
  }
3375
3462
  } else {
@@ -3636,11 +3723,11 @@ async function framesTake(browser, dir, opts) {
3636
3723
  "/render.html": renderPageHtml()
3637
3724
  });
3638
3725
  const ss = stillSupersample(width, height);
3639
- const context = await browser.newContext({
3726
+ const context2 = await browser.newContext({
3640
3727
  viewport: { width: width * ss, height: height * ss }
3641
3728
  });
3642
3729
  try {
3643
- const page = await context.newPage();
3730
+ const page = await context2.newPage();
3644
3731
  page.on("console", (m) => {
3645
3732
  if (m.type() === "error")
3646
3733
  process.stderr.write(` [stills page] ${m.text()}
@@ -3683,7 +3770,7 @@ async function framesTake(browser, dir, opts) {
3683
3770
  }
3684
3771
  return { frames, width, height, duration, outDir };
3685
3772
  } finally {
3686
- await context.close();
3773
+ await context2.close();
3687
3774
  server.close();
3688
3775
  }
3689
3776
  }
@@ -4442,11 +4529,11 @@ var outputLength = (doc) => ratedSegments4(doc).reduce((acc, s) => {
4442
4529
  const rate = s.rate && s.rate > 0 ? s.rate : 1;
4443
4530
  return acc + (s.out - s.in) / rate;
4444
4531
  }, 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(" ");
4532
+ function templateWords(words2) {
4533
+ const headline = (words2.headline ?? "").trim();
4534
+ const kicker = (words2.kicker ?? "").trim();
4535
+ const brand = (words2.brand ?? "").trim();
4536
+ const sub = [brand, (words2.release ?? "").trim()].filter(Boolean).join(" ");
4450
4537
  const out = {};
4451
4538
  if (headline) {
4452
4539
  out["stage-title"] = headline;
@@ -4472,7 +4559,7 @@ var anchorWord = (at2) => typeof at2 === "object" ? `step ${at2.step}` : typeof
4472
4559
  var onWord = (v) => v === void 0 || /^(on|yes|true)$/i.test(v.trim());
4473
4560
  function proposeMotion(input, opts) {
4474
4561
  let doc = migrateMotion(structuredClone(input));
4475
- const { words, launch, catalog } = opts;
4562
+ const { words: words2, launch, catalog } = opts;
4476
4563
  const notes = [];
4477
4564
  const skipped = [];
4478
4565
  const footage = outputLength(doc);
@@ -4502,7 +4589,7 @@ function proposeMotion(input, opts) {
4502
4589
  (t) => !(t.from === END_CARD_FROM && off(endCardRole))
4503
4590
  );
4504
4591
  const namedEndCard = templates.some((t) => t.from === END_CARD_FROM);
4505
- const tWords = templateWords(words);
4592
+ const tWords = templateWords(words2);
4506
4593
  const keys = opts.mark ? { "stage-mark": opts.mark.key, "endcard-markimg": opts.mark.key } : void 0;
4507
4594
  for (const t of templates) {
4508
4595
  const at2 = resolveAnchor(doc, t.at);
@@ -4527,9 +4614,9 @@ function proposeMotion(input, opts) {
4527
4614
  else delete doc.frame.anim;
4528
4615
  }
4529
4616
  } 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(" ");
4617
+ const headline = (words2.headline ?? "").trim();
4618
+ const brand = (words2.brand ?? "").trim();
4619
+ const sub = [brand, (words2.release ?? "").trim()].filter(Boolean).join(" ");
4533
4620
  if (headline || brand) {
4534
4621
  const card = { seconds: END_CARD_SECONDS };
4535
4622
  if (opts.ink) card.ink = opts.ink;
@@ -6996,11 +7083,11 @@ async function readDigestActivity(dir) {
6996
7083
  return null;
6997
7084
  }
6998
7085
  }
6999
- function patchStageWords(doc, words) {
7086
+ function patchStageWords(doc, words2) {
7000
7087
  const map = {
7001
- "stage-title": words.headline,
7002
- "stage-kicker": words.kicker,
7003
- "stage-brand": words.brand
7088
+ "stage-title": words2.headline,
7089
+ "stage-kicker": words2.kicker,
7090
+ "stage-brand": words2.brand
7004
7091
  };
7005
7092
  for (const clip of doc.overlays ?? []) {
7006
7093
  if (clip.kind !== "text" || !isStageClip(clip)) continue;
@@ -7675,13 +7762,15 @@ async function pushTake(dir, flags, r) {
7675
7762
  if (upload.reused) r.log(" recording already hosted \u2014 reused");
7676
7763
  const docForPush = structuredClone(take.doc);
7677
7764
  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;
7765
+ await uploadDocRefs(sourceSidecarRefs(docForPush), dir, ctx, (l) => r.log(l));
7766
+ for (const field of ["micKey", "camKey"]) {
7767
+ const key = docForPush.source[field];
7768
+ if (key && isTakeRelativeKey(key)) {
7769
+ r.log(
7770
+ ` ${field === "micKey" ? "mic" : "cam"} track ${key} is not beside the take \u2014 left out of the push`
7771
+ );
7772
+ delete docForPush.source[field];
7773
+ }
7685
7774
  }
7686
7775
  await uploadDocRefs(docMediaRefs(docForPush), dir, ctx, (l) => r.log(l));
7687
7776
  const lowered = lowerToComposition3(docForPush);
@@ -8345,7 +8434,7 @@ with their key: vos push ${source} --vos ${String(created2.id ?? "<id>")}`
8345
8434
  void flags.yes;
8346
8435
  if (programDoc) {
8347
8436
  await uploadDocRefs(
8348
- docAudioRefs(soundOf(programDoc)),
8437
+ docLayerRefs(layersOf(programDoc)),
8349
8438
  dir,
8350
8439
  { origin, key },
8351
8440
  (l) => r.log(l)
@@ -8692,6 +8781,13 @@ function isTakeDir(target) {
8692
8781
  function soundOf(doc) {
8693
8782
  return { audio: Array.isArray(doc.audio) ? doc.audio : [] };
8694
8783
  }
8784
+ function layersOf(doc) {
8785
+ return {
8786
+ ...soundOf(doc),
8787
+ overlays: Array.isArray(doc.overlays) ? doc.overlays : [],
8788
+ objects: Array.isArray(doc.objects) ? doc.objects : []
8789
+ };
8790
+ }
8695
8791
  function storedProgramConfig(config, programDoc) {
8696
8792
  if (!programDoc) return config;
8697
8793
  const doc = { audio: [], ...programDoc };
@@ -8872,12 +8968,177 @@ async function cmdAsset(argv) {
8872
8968
  import { existsSync as existsSync16, rmSync as rmSync2, statSync as statSync4 } from "fs";
8873
8969
  import { join as join18 } from "path";
8874
8970
  import { createInterface as createInterface3 } from "readline/promises";
8875
- var BOOLEAN_FLAGS4 = /* @__PURE__ */ new Set(["json", "help", "yes"]);
8876
- async function cmdDelete(argv) {
8971
+
8972
+ // src/plugin/trash.ts
8973
+ var BOOLEAN_FLAGS4 = /* @__PURE__ */ new Set(["json", "help"]);
8974
+ var MONTHS = [
8975
+ "Jan",
8976
+ "Feb",
8977
+ "Mar",
8978
+ "Apr",
8979
+ "May",
8980
+ "Jun",
8981
+ "Jul",
8982
+ "Aug",
8983
+ "Sep",
8984
+ "Oct",
8985
+ "Nov",
8986
+ "Dec"
8987
+ ];
8988
+ function restoreDate(iso, now = /* @__PURE__ */ new Date()) {
8989
+ const d = new Date(iso);
8990
+ if (Number.isNaN(d.getTime())) return iso;
8991
+ const day = `${d.getUTCDate()} ${MONTHS[d.getUTCMonth()]}`;
8992
+ return d.getUTCFullYear() === now.getUTCFullYear() ? day : `${day} ${d.getUTCFullYear()}`;
8993
+ }
8994
+ function trashedBy(entry) {
8995
+ if (entry.deletedVia === "key") {
8996
+ return entry.deletedClient ?? entry.deletedKeyName ?? "a key";
8997
+ }
8998
+ if (entry.deletedVia === "admin") return "an admin";
8999
+ if (entry.deletedVia === "service") return "vos.so";
9000
+ return "you";
9001
+ }
9002
+ function sinceMoment(value, now = /* @__PURE__ */ new Date()) {
9003
+ const rel = /^(\d+(?:\.\d+)?)(s|m|h|d)$/.exec(value.trim());
9004
+ if (rel) {
9005
+ const unit = { s: 1e3, m: 6e4, h: 36e5, d: 864e5 }[rel[2]];
9006
+ return new Date(now.getTime() - Number(rel[1]) * unit);
9007
+ }
9008
+ const at2 = new Date(value);
9009
+ return Number.isNaN(at2.getTime()) ? null : at2;
9010
+ }
9011
+ function words(kind) {
9012
+ return kind === "vos" ? "vos" : kind === "folder" ? "project" : "file";
9013
+ }
9014
+ function context(flags) {
9015
+ const origin = platformOrigin({
9016
+ origin: strFlag(flags, "origin"),
9017
+ api: strFlag(flags, "api")
9018
+ }).replace(/\/+$/, "");
9019
+ return { origin, key: requireCredential(strFlag(flags, "key")) };
9020
+ }
9021
+ async function readTrash(ctx) {
9022
+ const res = await apiJson(ctx.origin, "/api/trash", { key: ctx.key });
9023
+ if (res.status !== 200) throw new Error(apiError("read Trash", res));
9024
+ return res.body.entries ?? [];
9025
+ }
9026
+ async function restore(ctx, body) {
9027
+ let restored = [];
9028
+ let missing = [];
9029
+ for (let pass = 0; pass < 100; pass++) {
9030
+ const res = await apiJson(ctx.origin, "/api/trash/restore", {
9031
+ method: "POST",
9032
+ key: ctx.key,
9033
+ body
9034
+ });
9035
+ if (res.status !== 200) throw new Error(apiError("restore", res));
9036
+ if (pass === 0) {
9037
+ restored = res.body.restored ?? [];
9038
+ missing = res.body.missing ?? [];
9039
+ }
9040
+ if (res.body.done !== false) break;
9041
+ }
9042
+ return { restored, missing };
9043
+ }
9044
+ async function cmdTrash(argv) {
8877
9045
  const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS4);
9046
+ const r = createReporter(flags.json === true);
9047
+ const ctx = context(flags);
9048
+ if (positionals[0] === "restore") {
9049
+ const raw = strFlag(flags, "since");
9050
+ const since = raw ? sinceMoment(raw) : null;
9051
+ if (!since)
9052
+ throw new UsageError(
9053
+ "vos trash restore --since <30m|1h|2d|ISO time> [--by <key name>] [--json]"
9054
+ );
9055
+ const by = strFlag(flags, "by");
9056
+ let keyId = null;
9057
+ if (by) {
9058
+ const match = (await readTrash(ctx)).find(
9059
+ (e) => e.deletedKeyName === by || e.deletedKeyId?.startsWith(by)
9060
+ );
9061
+ keyId = match?.deletedKeyId ?? null;
9062
+ if (!keyId)
9063
+ throw new Error(`nothing in Trash was moved there by a key named ${by}`);
9064
+ } else {
9065
+ const me = await apiJson(ctx.origin, "/api/user/whoami", {
9066
+ key: ctx.key
9067
+ });
9068
+ keyId = (me.body.key ?? null)?.id ?? null;
9069
+ if (me.status !== 200 || !keyId)
9070
+ throw new Error(
9071
+ "could not tell which key this is: pass --by <key name> (vos trash lists them)"
9072
+ );
9073
+ }
9074
+ const done = await restore(ctx, { keyId, since: since.toISOString() });
9075
+ r.done(
9076
+ { restored: done.restored, count: done.restored.length },
9077
+ 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()}`
9078
+ );
9079
+ return EXIT_OK;
9080
+ }
9081
+ if (positionals[0])
9082
+ throw new UsageError(
9083
+ `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`
9084
+ );
9085
+ const entries2 = await readTrash(ctx);
9086
+ if (flags.json === true) {
9087
+ r.done({ entries: entries2, count: entries2.length }, "");
9088
+ return EXIT_OK;
9089
+ }
9090
+ if (entries2.length === 0) {
9091
+ r.done({ entries: entries2, count: 0 }, "Trash is empty");
9092
+ return EXIT_OK;
9093
+ }
9094
+ const lines = entries2.map((e) => {
9095
+ const inside = e.members ? ` (${e.members.voses} vos, ${e.members.assets} files)` : "";
9096
+ return ` ${words(e.kind).padEnd(7)} ${e.id} "${e.title}"${inside}: moved by ${trashedBy(e)}, restorable until ${restoreDate(e.restoreUntil)}`;
9097
+ });
9098
+ r.done(
9099
+ { entries: entries2, count: entries2.length },
9100
+ `${entries2.length} in Trash
9101
+ ${lines.join("\n")}
9102
+ restore one: vos restore <id> (emptying Trash is the person's act, at vos.so/app/trash)`
9103
+ );
9104
+ return EXIT_OK;
9105
+ }
9106
+ async function cmdRestore(argv) {
9107
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS4);
9108
+ if (positionals.length === 0)
9109
+ throw new UsageError("vos restore <id|watch-url> [...] [--json]");
9110
+ const r = createReporter(flags.json === true);
9111
+ const ctx = context(flags);
9112
+ const entries2 = await readTrash(ctx);
9113
+ const wanted = positionals.map((p) => parseVosId(p) ?? p);
9114
+ const units = wanted.map((id) => {
9115
+ const entry = entries2.find((e) => e.id === id);
9116
+ if (!entry)
9117
+ throw new Error(
9118
+ `${id} is not in Trash (vos trash lists what is; something inside a trashed project comes back with the project)`
9119
+ );
9120
+ return { kind: entry.kind, id: entry.id, title: entry.title };
9121
+ });
9122
+ const done = await restore(ctx, {
9123
+ ids: units.map(({ kind, id }) => ({ kind, id }))
9124
+ });
9125
+ const names = units.map((u) => `"${u.title}"`).join(", ");
9126
+ r.done(
9127
+ { restored: done.restored, count: done.restored.length },
9128
+ `restored ${names}`
9129
+ );
9130
+ return EXIT_OK;
9131
+ }
9132
+
9133
+ // src/plugin/remove.ts
9134
+ var BOOLEAN_FLAGS5 = /* @__PURE__ */ new Set(["json", "help", "yes", "dry-run"]);
9135
+ async function cmdDelete(argv) {
9136
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS5);
8878
9137
  const target = positionals[0];
8879
9138
  if (!target)
8880
- throw new UsageError("vos delete <vosId|watch-url|dir> [--yes] [--json]");
9139
+ throw new UsageError(
9140
+ "vos delete <vosId|watch-url|dir> [--yes] [--dry-run] [--json]"
9141
+ );
8881
9142
  const r = createReporter(flags.json === true);
8882
9143
  const origin = platformOrigin({
8883
9144
  origin: strFlag(flags, "origin"),
@@ -8894,24 +9155,33 @@ async function cmdDelete(argv) {
8894
9155
  if (meta.status !== 200) throw new Error(apiError(`read ${vosId}`, meta));
8895
9156
  const vos = meta.body.vos ?? {};
8896
9157
  const title = typeof vos.title === "string" ? vos.title : vosId;
9158
+ if (flags["dry-run"] === true) {
9159
+ r.done(
9160
+ { id: vosId, title, deleted: false, dryRun: true },
9161
+ `would move "${title}" (${vosId}) to Trash; nothing was changed`
9162
+ );
9163
+ return EXIT_OK;
9164
+ }
8897
9165
  if (flags.yes !== true) {
8898
9166
  if (!process.stdin.isTTY)
8899
9167
  throw new UsageError(
8900
- `deleting "${title}" (${vosId}) cannot be undone: re-run with --yes to confirm`
9168
+ `"${title}" (${vosId}) would move to Trash: re-run with --yes to confirm, or --dry-run to only look`
8901
9169
  );
8902
9170
  const rl = createInterface3({ input: process.stdin, output: process.stderr });
8903
9171
  const answer = await rl.question(
8904
- `Delete "${title}" (${vosId}) and every version of it? This cannot be undone. [y/N] `
9172
+ `Move "${title}" (${vosId}) to Trash? It stays restorable there for a while (vos restore ${vosId}). [y/N] `
8905
9173
  );
8906
9174
  rl.close();
8907
9175
  if (!/^y(es)?$/i.test(answer.trim())) {
8908
- r.done({ id: vosId, deleted: false }, "kept \u2014 nothing was deleted");
9176
+ r.done({ id: vosId, deleted: false }, "kept: nothing was deleted");
8909
9177
  return EXIT_OK;
8910
9178
  }
8911
9179
  }
8912
9180
  const res = await apiJson(origin, `/api/vos/${vosId}`, {
8913
9181
  method: "DELETE",
8914
- key
9182
+ key,
9183
+ // Who did it, for the person reading Trash later (display only).
9184
+ headers: { "x-vos-client": clientId() }
8915
9185
  });
8916
9186
  if (res.status !== 200 && res.status !== 204)
8917
9187
  throw new Error(apiError(`delete ${vosId}`, res));
@@ -8920,9 +9190,23 @@ async function cmdDelete(argv) {
8920
9190
  rmSync2(join18(dir, SYNC_STATE_NAME), { force: true });
8921
9191
  unlinked = true;
8922
9192
  }
9193
+ const trashed = res.body.trashed === true;
9194
+ const restoreUntil = typeof res.body.restoreUntil === "string" ? res.body.restoreUntil : null;
9195
+ const tail = unlinked ? `; ${dir} no longer tracks it` : "";
8923
9196
  r.done(
8924
- { id: vosId, title, deleted: true, unlinked },
8925
- `deleted "${title}" (${vosId})${unlinked ? `; ${dir} no longer tracks it` : ""}`
9197
+ {
9198
+ id: vosId,
9199
+ title,
9200
+ deleted: true,
9201
+ trashed,
9202
+ ...restoreUntil ? { restoreUntil } : {},
9203
+ unlinked
9204
+ },
9205
+ trashed ? `moved "${title}" (${vosId}) to Trash${restoreUntil ? `, restorable until ${restoreDate(restoreUntil)}` : ""}: vos restore ${vosId}${tail}` : (
9206
+ // A vos with no version (a refused hosted take's empty shell) has
9207
+ // nothing to restore, so the platform erases it.
9208
+ `deleted "${title}" (${vosId})${tail}`
9209
+ )
8926
9210
  );
8927
9211
  return EXIT_OK;
8928
9212
  }
@@ -9122,9 +9406,9 @@ function nonJson(value, path) {
9122
9406
  }
9123
9407
  return null;
9124
9408
  }
9125
- var BOOLEAN_FLAGS5 = /* @__PURE__ */ new Set(["json", "help"]);
9409
+ var BOOLEAN_FLAGS6 = /* @__PURE__ */ new Set(["json", "help"]);
9126
9410
  async function cmdBuild(argv) {
9127
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS5);
9411
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS6);
9128
9412
  const source = positionals[0];
9129
9413
  if (!source)
9130
9414
  throw new UsageError("vos build <program.mjs> [--out config.json] [--json]");
@@ -9166,7 +9450,7 @@ async function cmdBuild(argv) {
9166
9450
  import { spawnSync } from "child_process";
9167
9451
  import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
9168
9452
  import { join as join20, resolve as resolve8 } from "path";
9169
- var BOOLEAN_FLAGS6 = /* @__PURE__ */ new Set(["json", "help"]);
9453
+ var BOOLEAN_FLAGS7 = /* @__PURE__ */ new Set(["json", "help"]);
9170
9454
  function sampleTimes(duration, every) {
9171
9455
  const step = every > 0 ? every : 1;
9172
9456
  const out = [];
@@ -9217,7 +9501,7 @@ function probeSize(video) {
9217
9501
  return m ? { width: Number(m[1]), height: Number(m[2]) } : null;
9218
9502
  }
9219
9503
  async function cmdCompare(argv) {
9220
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS6);
9504
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS7);
9221
9505
  const source = positionals[0];
9222
9506
  const against = strFlag(flags, "against");
9223
9507
  if (!source || !against)
@@ -10362,8 +10646,8 @@ function toHex(css) {
10362
10646
  return `#${hex2(+m[1])}${hex2(+m[2])}${hex2(+m[3])}${a < 1 ? hex2(a * 255) : ""}`;
10363
10647
  }
10364
10648
  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(
10649
+ const words2 = label.replace(/[^A-Za-z0-9]+/g, " ").trim().split(" ").filter(Boolean).slice(0, 4);
10650
+ let base = words2.map(
10367
10651
  (w, i) => i === 0 ? w.toLowerCase() : w[0].toUpperCase() + w.slice(1).toLowerCase()
10368
10652
  ).join("");
10369
10653
  if (!base || /^[0-9]/.test(base)) base = prefix + (base || "");
@@ -10424,8 +10708,8 @@ function planScaffold(inv, opts) {
10424
10708
  for (const t of inv.texts) {
10425
10709
  const generic = /^(div|span|p|h[1-6]|li|a|b|i|em|strong)-\d+$/.test(t.id);
10426
10710
  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;
10711
+ const words2 = t.font.transform === "uppercase" ? t.text.toUpperCase() : t.font.transform === "lowercase" ? t.text.toLowerCase() : t.text;
10712
+ data[key] = words2;
10429
10713
  const family = faceFor(t);
10430
10714
  elements.push({
10431
10715
  id: key,
@@ -10444,7 +10728,7 @@ function planScaffold(inv, opts) {
10444
10728
  } : {}
10445
10729
  }
10446
10730
  });
10447
- textKeys.push({ key, size: t.font.size, label: words.slice(0, 40) });
10731
+ textKeys.push({ key, size: t.font.size, label: words2.slice(0, 40) });
10448
10732
  if (t.scene && sceneNames.has(t.scene))
10449
10733
  (sceneElements[t.scene] ??= []).push(key);
10450
10734
  }
@@ -10742,7 +11026,7 @@ function reportText(inv, r) {
10742
11026
  "",
10743
11027
  "## Images and video",
10744
11028
  "",
10745
- "Not placed: upload each with `vos asset upload` and add an image or video element over its hosted URL.",
11029
+ "Not placed: upload each with `vos asset push` and add an image or video element over its hosted URL.",
10746
11030
  "",
10747
11031
  ...inv.media.filter((m) => m.kind === "image" || m.kind === "video").map((m) => `- ${m.kind} ${m.src ?? "(inline)"}`)
10748
11032
  ] : [],
@@ -10776,7 +11060,7 @@ function probeAudioDuration(file) {
10776
11060
  }
10777
11061
 
10778
11062
  // src/plugin/port.ts
10779
- var BOOLEAN_FLAGS7 = /* @__PURE__ */ new Set(["json", "help"]);
11063
+ var BOOLEAN_FLAGS8 = /* @__PURE__ */ new Set(["json", "help"]);
10780
11064
  async function cmdPort(argv) {
10781
11065
  const [sub, ...rest] = argv;
10782
11066
  if (sub === "inventory") return await inventory(rest);
@@ -10786,7 +11070,7 @@ async function cmdPort(argv) {
10786
11070
  );
10787
11071
  }
10788
11072
  async function inventory(argv) {
10789
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS7);
11073
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS8);
10790
11074
  const source = positionals[0] ?? ".";
10791
11075
  const r = createReporter(flags.json === true);
10792
11076
  const outDir = resolve11(strFlag(flags, "out") ?? "port");
@@ -10827,7 +11111,7 @@ function summary(inv) {
10827
11111
  };
10828
11112
  }
10829
11113
  async function scaffold(argv) {
10830
- const { flags } = parseArgs(argv, BOOLEAN_FLAGS7);
11114
+ const { flags } = parseArgs(argv, BOOLEAN_FLAGS8);
10831
11115
  const r = createReporter(flags.json === true);
10832
11116
  const from = resolve11(strFlag(flags, "from") ?? join24("port", "inventory.json"));
10833
11117
  if (!existsSync20(from))
@@ -10866,7 +11150,7 @@ function scaffoldSourceDir(inv) {
10866
11150
  // src/plugin/recipe.ts
10867
11151
  import { readFileSync as readFileSync8 } from "fs";
10868
11152
  import { basename as basename9 } from "path";
10869
- var BOOLEAN_FLAGS8 = /* @__PURE__ */ new Set(["json", "help"]);
11153
+ var BOOLEAN_FLAGS9 = /* @__PURE__ */ new Set(["json", "help"]);
10870
11154
  var USAGE = "vos recipe push <file.md> (--folder <folderId|slug> | --asset <assetId>)";
10871
11155
  function recipeFilename(file) {
10872
11156
  const name = basename9(file);
@@ -10876,7 +11160,7 @@ function recipeFilename(file) {
10876
11160
  return name;
10877
11161
  }
10878
11162
  async function cmdPush2(argv) {
10879
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS8);
11163
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS9);
10880
11164
  const [file] = positionals;
10881
11165
  const folderRef = strFlag(flags, "folder");
10882
11166
  const assetId = strFlag(flags, "asset");
@@ -11977,7 +12261,7 @@ import {
11977
12261
  Output,
11978
12262
  WebMOutputFormat
11979
12263
  } from "mediabunny";
11980
- var BOOLEAN_FLAGS9 = /* @__PURE__ */ new Set(["json", "help"]);
12264
+ var BOOLEAN_FLAGS10 = /* @__PURE__ */ new Set(["json", "help"]);
11981
12265
  async function probeVideoFile(path) {
11982
12266
  const input = new Input({
11983
12267
  source: new FilePathSource(path),
@@ -12068,7 +12352,7 @@ function parseViewport(v) {
12068
12352
  return { width: Number(m[1]), height: Number(m[2]) };
12069
12353
  }
12070
12354
  async function cmdIngest(argv) {
12071
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS9, MULTI_FLAGS2);
12355
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS10, MULTI_FLAGS2);
12072
12356
  const source = positionals[0];
12073
12357
  if (!source)
12074
12358
  throw new UsageError(
@@ -12274,6 +12558,7 @@ var RULES_BODY = `## Product videos (vosso)
12274
12558
  - Look before you cut: vos frames take --at-zooms; edit take/doc.json and re-render, never re-record
12275
12559
  - Hand back: vos open take serves the take into the studio at vos.so, doc.json intact
12276
12560
  - Local by default: vos push only when asked for a link, the shelf or a cloud render
12561
+ - 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
12562
  - Credentials: VOS_API_KEY, then ~/.config/vos/credentials, then vos login; never print one
12278
12563
  - Reference: https://vos.so/llms-full.txt`;
12279
12564
  var RULES_BLOCK = `${RULES_BEGIN}
@@ -12422,7 +12707,7 @@ function bundledSkillsDir(from) {
12422
12707
  }
12423
12708
 
12424
12709
  // src/plugin/machineCmd.ts
12425
- var BOOLEAN_FLAGS10 = /* @__PURE__ */ new Set([
12710
+ var BOOLEAN_FLAGS11 = /* @__PURE__ */ new Set([
12426
12711
  "json",
12427
12712
  "help",
12428
12713
  "global",
@@ -12500,7 +12785,7 @@ async function doctorFacts(opts) {
12500
12785
  };
12501
12786
  }
12502
12787
  async function cmdSetup(argv) {
12503
- const { flags } = parseArgs(argv, BOOLEAN_FLAGS10);
12788
+ const { flags } = parseArgs(argv, BOOLEAN_FLAGS11);
12504
12789
  const r = reporterFor(flags);
12505
12790
  const root = process.cwd();
12506
12791
  const global = flags.global === true;
@@ -12619,7 +12904,7 @@ Next: ${report.next_step}`
12619
12904
  return report.ok ? EXIT_OK : EXIT_NO_BROWSER;
12620
12905
  }
12621
12906
  async function cmdDoctor(argv) {
12622
- const { flags } = parseArgs(argv, BOOLEAN_FLAGS10);
12907
+ const { flags } = parseArgs(argv, BOOLEAN_FLAGS11);
12623
12908
  const r = reporterFor(flags);
12624
12909
  const root = process.cwd();
12625
12910
  const homes = detectAgents(root, { home: homedir2(), global: true });
@@ -12638,7 +12923,7 @@ Next: ${report.next_step}`
12638
12923
  return report.ok ? EXIT_OK : EXIT_NO_BROWSER;
12639
12924
  }
12640
12925
  async function cmdWhoami(argv) {
12641
- const { flags } = parseArgs(argv, BOOLEAN_FLAGS10);
12926
+ const { flags } = parseArgs(argv, BOOLEAN_FLAGS11);
12642
12927
  const r = reporterFor(flags);
12643
12928
  const origin = platformOrigin({
12644
12929
  origin: strFlag(flags, "origin"),
@@ -12700,7 +12985,7 @@ async function cmdWhoami(argv) {
12700
12985
  return EXIT_OK;
12701
12986
  }
12702
12987
  function cmdLogout(argv) {
12703
- const { flags } = parseArgs(argv, BOOLEAN_FLAGS10);
12988
+ const { flags } = parseArgs(argv, BOOLEAN_FLAGS11);
12704
12989
  const r = reporterFor(flags);
12705
12990
  const had = existsSync23(CREDENTIALS_PATH);
12706
12991
  rmSync3(CREDENTIALS_PATH, { force: true });
@@ -12718,7 +13003,7 @@ function cmdLogout(argv) {
12718
13003
  }
12719
13004
 
12720
13005
  // src/plugin/run.ts
12721
- var BOOLEAN_FLAGS11 = /* @__PURE__ */ new Set([
13006
+ var BOOLEAN_FLAGS12 = /* @__PURE__ */ new Set([
12722
13007
  "json",
12723
13008
  "help",
12724
13009
  "wait",
@@ -12820,16 +13105,29 @@ Platform (vos.so) \u2014 fetch, edit, push, pull, repeat
12820
13105
  --override consents to touching
12821
13106
  protected (human-edited) nodes, ONLY when the user asked.
12822
13107
  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
13108
+ shelf. A document's local files (doc.json: picture and video
13109
+ overlays, 3D props, sound; a take's mic and cam too) upload
13110
+ with the push, each once. --wait stays until the version's still has
12825
13111
  rendered and prints absolute still and preview links.
12826
13112
  --still <seconds> sets a PROGRAM's cover (doc.json "still", kept
12827
13113
  by every later push); without it the platform picks an early
12828
13114
  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)
13115
+ vos delete <vosId|watch-url|dir> [--yes] [--dry-run] [--json]
13116
+ move a vos to Trash on vos.so. Nothing is erased: it stays
13117
+ restorable until the date the delete prints (vos restore <id>).
13118
+ Asks on a terminal; headless it needs --yes. --dry-run names
13119
+ what would move and changes nothing. A dir that tracked it is
13120
+ unlinked (its vos.json removed). Needs a key with the delete
13121
+ scope; no key can delete forever, only the person can, on the
13122
+ web
13123
+ vos trash [--json]
13124
+ what is in Trash on vos.so: what, moved by whom, restorable
13125
+ until when
13126
+ vos restore <id|watch-url> [...] [--json]
13127
+ bring those back from Trash, as they were
13128
+ vos trash restore --since <30m|1h|2d|ISO> [--by <key name>] [--json]
13129
+ undo everything this key (or the named one) moved to Trash
13130
+ since then
12833
13131
  vos pull [dir|take] [--vos <id>] [--since versionId] [--check] [--media] [--json]
12834
13132
  what changed on vos.so since your base; syncs config.json (backup
12835
13133
  kept) or the take's doc.json. ALWAYS pull before editing pushed work.
@@ -13175,7 +13473,7 @@ function wallGate(flags, r, opts) {
13175
13473
  async function cmdRecord(argv) {
13176
13474
  const { positionals, flags, multi } = parseArgs(
13177
13475
  argv,
13178
- BOOLEAN_FLAGS11,
13476
+ BOOLEAN_FLAGS12,
13179
13477
  MULTI_FLAGS2
13180
13478
  );
13181
13479
  const actionsPath = strFlag(flags, "actions") ?? positionals[0];
@@ -13296,10 +13594,10 @@ async function cmdRecord(argv) {
13296
13594
  const rec = await inSession(
13297
13595
  sessionName,
13298
13596
  actions,
13299
- (context) => recordTake(browser2, url, actions, takePaths(outDir), r.log, {
13597
+ (context2) => recordTake(browser2, url, actions, takePaths(outDir), r.log, {
13300
13598
  storageState,
13301
13599
  headers,
13302
- context,
13600
+ context: context2,
13303
13601
  dryRun: true,
13304
13602
  // A rehearsal is always strict, and it touches no directory.
13305
13603
  onArrival: wallGate(flags, r, { strict: true })
@@ -13358,11 +13656,11 @@ ${lines.join("\n")}
13358
13656
  const rec = await inSession(
13359
13657
  sessionName,
13360
13658
  actions,
13361
- (context) => recordTake(browser, url, actions, paths, r.log, {
13659
+ (context2) => recordTake(browser, url, actions, paths, r.log, {
13362
13660
  maxDurationSeconds,
13363
13661
  storageState,
13364
13662
  headers,
13365
- context,
13663
+ context: context2,
13366
13664
  onArrival: wallGate(flags, r, {
13367
13665
  strict: flags.strict === true,
13368
13666
  prepare
@@ -13417,7 +13715,7 @@ ${lines.join("\n")}
13417
13715
  async function cmdCreate2(argv) {
13418
13716
  const { positionals, flags, multi } = parseArgs(
13419
13717
  argv,
13420
- BOOLEAN_FLAGS11,
13718
+ BOOLEAN_FLAGS12,
13421
13719
  MULTI_FLAGS2
13422
13720
  );
13423
13721
  const actionsPath = strFlag(flags, "actions");
@@ -13462,11 +13760,11 @@ async function cmdCreate2(argv) {
13462
13760
  const rec = await inSession(
13463
13761
  sessionName,
13464
13762
  actions,
13465
- (context) => recordTake(browser, url, actions, paths, r.log, {
13763
+ (context2) => recordTake(browser, url, actions, paths, r.log, {
13466
13764
  maxDurationSeconds,
13467
13765
  storageState,
13468
13766
  headers,
13469
- context,
13767
+ context: context2,
13470
13768
  onArrival: wallGate(flags, r, {
13471
13769
  strict: flags.strict === true,
13472
13770
  prepare
@@ -13543,7 +13841,7 @@ async function cmdCreate2(argv) {
13543
13841
  async function cmdPlan(argv) {
13544
13842
  const { positionals, flags, multi } = parseArgs(
13545
13843
  argv,
13546
- BOOLEAN_FLAGS11,
13844
+ BOOLEAN_FLAGS12,
13547
13845
  /* @__PURE__ */ new Set(["with"])
13548
13846
  );
13549
13847
  const dir = positionals[0];
@@ -13644,7 +13942,7 @@ async function releaseInputs(dir, flags, r, withRefs = []) {
13644
13942
  }
13645
13943
  const launch = await readLaunchBesideTake(dir, strFlag(flags, "launch"));
13646
13944
  const lines = (v) => v === null || v === void 0 ? null : v.replace(/\\n/g, "\n");
13647
- const words = {
13945
+ const words2 = {
13648
13946
  headline: lines(strFlag(flags, "headline") ?? launch?.roles.headline),
13649
13947
  kicker: lines(strFlag(flags, "kicker") ?? launch?.roles.kicker),
13650
13948
  brand: strFlag(flags, "brand-name") ?? lookPick.roles?.wordmark ?? null,
@@ -13729,7 +14027,7 @@ async function releaseInputs(dir, flags, r, withRefs = []) {
13729
14027
  }
13730
14028
  }
13731
14029
  return {
13732
- words,
14030
+ words: words2,
13733
14031
  launchRoles,
13734
14032
  ink: endCardInk(lookPick.look, lookPick.roles),
13735
14033
  mark,
@@ -13741,7 +14039,7 @@ async function releaseInputs(dir, flags, r, withRefs = []) {
13741
14039
  async function cmdRender(argv) {
13742
14040
  const { positionals, flags, multi } = parseArgs(
13743
14041
  argv,
13744
- BOOLEAN_FLAGS11,
14042
+ BOOLEAN_FLAGS12,
13745
14043
  MULTI_FLAGS2
13746
14044
  );
13747
14045
  const dir = positionals[0];
@@ -13809,7 +14107,7 @@ async function cmdRender(argv) {
13809
14107
  async function cmdFrames(argv) {
13810
14108
  const { positionals, flags, multi } = parseArgs(
13811
14109
  argv,
13812
- BOOLEAN_FLAGS11,
14110
+ BOOLEAN_FLAGS12,
13813
14111
  MULTI_FLAGS2
13814
14112
  );
13815
14113
  const dir = positionals[0];
@@ -13882,7 +14180,7 @@ async function cmdFrames(argv) {
13882
14180
  async function cmdDeliver(argv) {
13883
14181
  const { positionals, flags, multi } = parseArgs(
13884
14182
  argv,
13885
- BOOLEAN_FLAGS11,
14183
+ BOOLEAN_FLAGS12,
13886
14184
  MULTI_FLAGS2
13887
14185
  );
13888
14186
  const dir = positionals[0];
@@ -14048,7 +14346,7 @@ async function officialTemplate(origin, ref) {
14048
14346
  }
14049
14347
  }
14050
14348
  async function cmdDigest(argv) {
14051
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS11);
14349
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS12);
14052
14350
  const dir = positionals[0];
14053
14351
  if (!dir)
14054
14352
  throw new UsageError(
@@ -14112,7 +14410,7 @@ async function cmdDigest(argv) {
14112
14410
  }
14113
14411
  }
14114
14412
  async function cmdOpen(argv) {
14115
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS11);
14413
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS12);
14116
14414
  const dir = positionals[0];
14117
14415
  if (!dir) throw new UsageError("vos open <take> [--studio <url>]");
14118
14416
  const r = createReporter(flags.json === true);
@@ -14150,7 +14448,7 @@ async function cmdOpen(argv) {
14150
14448
  return EXIT_OK;
14151
14449
  }
14152
14450
  async function cmdJudge(argv) {
14153
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS11);
14451
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS12);
14154
14452
  const target = positionals[0];
14155
14453
  const against = strFlag(flags, "against");
14156
14454
  if (!target || !against)
@@ -14179,7 +14477,7 @@ Win rate so far: ${rate.wins} win(s), ${rate.ties} tie(s) of ${rate.judged} judg
14179
14477
  return EXIT_OK;
14180
14478
  }
14181
14479
  async function cmdCallout(argv) {
14182
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS11);
14480
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS12);
14183
14481
  const dir = positionals[0];
14184
14482
  const shape = positionals[1];
14185
14483
  if (!dir || !shape || !isCalloutShape(shape))
@@ -14204,19 +14502,19 @@ async function cmdCallout(argv) {
14204
14502
  );
14205
14503
  const codeFile = strFlag(flags, "code-file");
14206
14504
  const code = codeFile ? await readFile17(codeFile, "utf8") : strFlag(flags, "code");
14207
- const words = {
14505
+ const words2 = {
14208
14506
  kicker: strFlag(flags, "kicker"),
14209
14507
  title: strFlag(flags, "title"),
14210
14508
  body: strFlag(flags, "body"),
14211
14509
  code: code?.replace(/\\n/g, "\n")
14212
14510
  };
14213
- if (shape === "code" && !words.code)
14511
+ if (shape === "code" && !words2.code)
14214
14512
  throw new UsageError(
14215
14513
  'a code callout needs --code "\u2026" or --code-file <file>'
14216
14514
  );
14217
- if (shape === "note" && !words.title)
14515
+ if (shape === "note" && !words2.title)
14218
14516
  throw new UsageError('a note needs --title "\u2026"');
14219
- if (shape === "tag" && !words.kicker && !words.title)
14517
+ if (shape === "tag" && !words2.kicker && !words2.title)
14220
14518
  throw new UsageError('a tag needs --kicker "\u2026"');
14221
14519
  const stepRaw = strFlag(flags, "step");
14222
14520
  const atRaw = strFlag(flags, "at");
@@ -14227,7 +14525,7 @@ async function cmdCallout(argv) {
14227
14525
  try {
14228
14526
  composed = composeCallout(take.doc, register, {
14229
14527
  shape,
14230
- words,
14528
+ words: words2,
14231
14529
  id: strFlag(flags, "id"),
14232
14530
  step: stepRaw !== void 0 ? /^\d+$/.test(stepRaw) ? Number(stepRaw) : stepRaw : void 0,
14233
14531
  at: atRaw !== void 0 ? Number(atRaw) : void 0,
@@ -14278,7 +14576,7 @@ async function cmdCallout(argv) {
14278
14576
  return EXIT_OK;
14279
14577
  }
14280
14578
  async function cmdValidate(argv) {
14281
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS11);
14579
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS12);
14282
14580
  const target = positionals[0];
14283
14581
  if (!target) throw new UsageError("vos validate <actions.json|take>");
14284
14582
  const r = createReporter(flags.json === true);
@@ -14440,7 +14738,7 @@ async function cmdValidate(argv) {
14440
14738
  async function cmdPush3(argv) {
14441
14739
  const { positionals, flags, multi } = parseArgs(
14442
14740
  argv,
14443
- BOOLEAN_FLAGS11,
14741
+ BOOLEAN_FLAGS12,
14444
14742
  MULTI_FLAGS2
14445
14743
  );
14446
14744
  const dir = positionals[0];
@@ -14504,7 +14802,7 @@ ${landedLines(landed)}` : "")
14504
14802
  return EXIT_OK;
14505
14803
  }
14506
14804
  async function cmdPull2(argv) {
14507
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS11, MULTI_FLAGS2);
14805
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS12, MULTI_FLAGS2);
14508
14806
  const dir = positionals[0] ?? ".";
14509
14807
  const r = createReporter(flags.json === true);
14510
14808
  const result = await pullTake(
@@ -14617,6 +14915,10 @@ async function run(argv) {
14617
14915
  }
14618
14916
  case "delete":
14619
14917
  return await cmdDelete(rest);
14918
+ case "trash":
14919
+ return await cmdTrash(rest);
14920
+ case "restore":
14921
+ return await cmdRestore(rest);
14620
14922
  case "build":
14621
14923
  return await cmdBuild(rest);
14622
14924
  case "compare":
@@ -14669,7 +14971,7 @@ async function run(argv) {
14669
14971
  }
14670
14972
  }
14671
14973
  async function cmdSession(argv) {
14672
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS11);
14974
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS12);
14673
14975
  const [sub, arg] = positionals;
14674
14976
  const r = createReporter(flags.json === true);
14675
14977
  const usage = "vos session open <url> --name <app> | check <name> [--url <url>] | list | rm <name>";
@@ -14809,4 +15111,4 @@ export {
14809
15111
  verbHelp,
14810
15112
  run
14811
15113
  };
14812
- //# sourceMappingURL=chunk-RZZUR2IF.js.map
15114
+ //# sourceMappingURL=chunk-CYU7LVPB.js.map