@vosjs/cli 0.87.1 → 0.88.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.
@@ -165,9 +165,9 @@ function landedLines(l) {
165
165
  }
166
166
 
167
167
  // src/plugin/run.ts
168
- import { mkdir as mkdir13, readFile as readFile19, rm as rm7 } from "fs/promises";
169
- import { existsSync as existsSync31 } from "fs";
170
- import { dirname as dirname12, join as join33, resolve as resolve22 } from "path";
168
+ import { mkdir as mkdir14, readFile as readFile20, rm as rm7 } from "fs/promises";
169
+ import { existsSync as existsSync32 } from "fs";
170
+ import { dirname as dirname12, join as join34, resolve as resolve23 } from "path";
171
171
  import {
172
172
  END_CARD_FROM as END_CARD_FROM2,
173
173
  docOutputDuration as docOutputDuration5,
@@ -6089,14 +6089,14 @@ function chromeTree(rows, pid) {
6089
6089
  }
6090
6090
  function readChromeTree(pid) {
6091
6091
  if (process.platform === "win32") return Promise.resolve(null);
6092
- return new Promise((resolve23) => {
6092
+ return new Promise((resolve24) => {
6093
6093
  execFile2(
6094
6094
  "ps",
6095
6095
  ["-A", "-o", "pid=", "-o", "ppid=", "-o", "command="],
6096
6096
  { maxBuffer: 16 * 1024 * 1024, timeout: 5e3 },
6097
6097
  (err, stdout) => {
6098
- if (err) resolve23(null);
6099
- else resolve23(chromeTree(parseProcessTable(stdout), pid));
6098
+ if (err) resolve24(null);
6099
+ else resolve24(chromeTree(parseProcessTable(stdout), pid));
6100
6100
  }
6101
6101
  );
6102
6102
  });
@@ -6198,7 +6198,7 @@ function enterPressed() {
6198
6198
  } };
6199
6199
  const rl = createInterface({ input: process.stdin });
6200
6200
  const pressed = new Promise(
6201
- (resolve23) => rl.once("line", () => resolve23())
6201
+ (resolve24) => rl.once("line", () => resolve24())
6202
6202
  );
6203
6203
  return { pressed, close: () => rl.close() };
6204
6204
  }
@@ -6371,14 +6371,14 @@ async function openSessionWindow(opts) {
6371
6371
  const child = spawn(exe, args, { stdio: "ignore" });
6372
6372
  let failed = null;
6373
6373
  let code = null;
6374
- const exited = new Promise((resolve23) => {
6374
+ const exited = new Promise((resolve24) => {
6375
6375
  child.once("exit", (c) => {
6376
6376
  code = c;
6377
- resolve23();
6377
+ resolve24();
6378
6378
  });
6379
6379
  child.once("error", (e) => {
6380
6380
  failed = e;
6381
- resolve23();
6381
+ resolve24();
6382
6382
  });
6383
6383
  });
6384
6384
  try {
@@ -13291,8 +13291,8 @@ async function cmdActions(argv) {
13291
13291
  if (!m) throw new UsageError("--viewport expects WxH, e.g. 1280x720");
13292
13292
  viewport = { width: Number(m[1]), height: Number(m[2]) };
13293
13293
  }
13294
- const { readFile: readFile20 } = await import("fs/promises");
13295
- const text = await readFile20(resolve14(input), "utf8");
13294
+ const { readFile: readFile21 } = await import("fs/promises");
13295
+ const text = await readFile21(resolve14(input), "utf8");
13296
13296
  const { records, problems } = parseAgentBrowserLog(text);
13297
13297
  for (const p of problems) r.log(` ${p}`);
13298
13298
  const result = convertAgentBrowser(records, {
@@ -13329,9 +13329,9 @@ function summary2(result) {
13329
13329
  }
13330
13330
  async function cmdActionsScript(input, flags) {
13331
13331
  const r = createReporter(flags.json === true);
13332
- const { readFile: readFile20 } = await import("fs/promises");
13332
+ const { readFile: readFile21 } = await import("fs/promises");
13333
13333
  const { shotList, formatShotList } = await import("./shotList-PL7XP6AC.js");
13334
- const raw = JSON.parse(await readFile20(resolve14(input), "utf8"));
13334
+ const raw = JSON.parse(await readFile21(resolve14(input), "utf8"));
13335
13335
  const errors = validateActions(raw);
13336
13336
  if (errors.length) throw new UsageError(`${input}:
13337
13337
  ${errors.join("\n ")}`);
@@ -13606,11 +13606,169 @@ async function cmdIngest(argv) {
13606
13606
  return EXIT_OK;
13607
13607
  }
13608
13608
 
13609
+ // src/plugin/recordApp.ts
13610
+ import { existsSync as existsSync23 } from "fs";
13611
+ import { mkdir as mkdir9, readFile as readFile14 } from "fs/promises";
13612
+ import { join as join24, resolve as resolve16 } from "path";
13613
+ var BOOLEAN_FLAGS11 = /* @__PURE__ */ new Set(["json", "help", "windows"]);
13614
+ var USAGE2 = "vos record --app <name|bundle id> [--out take] [--seconds <n>] [--max-duration <s>] [--background <slug|url|none>] [--json]\n vos record --window <id> \u2026 one window by its id\n vos record --windows list the windows that can be recorded";
13615
+ function isDesktopRecord(argv) {
13616
+ return argv.some(
13617
+ (a) => a === "--app" || a === "--window" || a === "--windows" || a.startsWith("--app=") || a.startsWith("--window=")
13618
+ );
13619
+ }
13620
+ async function loadDriver() {
13621
+ try {
13622
+ return await import("@vosjs/driver");
13623
+ } catch {
13624
+ throw new Error(
13625
+ "Recording a desktop app needs @vosjs/driver, which is not installed here. Install again without --omit=optional."
13626
+ );
13627
+ }
13628
+ }
13629
+ function driverFailure(error) {
13630
+ const e = error;
13631
+ if (e.code === "no-window")
13632
+ return new Error(
13633
+ "No window on screen matches. vos record --windows lists the windows that can be recorded."
13634
+ );
13635
+ return new Error(e.message ?? String(error));
13636
+ }
13637
+ var SCREEN_RECORDING = "Screen Recording is not granted to the app this was run from (the terminal, the editor or the agent host). Switch it on in System Settings, Privacy & Security, Screen & System Audio Recording, then start that app again.";
13638
+ function windowLine(w) {
13639
+ const size = `${Math.round(w.frame.w)}\xD7${Math.round(w.frame.h)}`;
13640
+ return `${String(w.id).padStart(7)} ${w.app || "(no name)"} ${size}${w.titled ? "" : " (untitled: an alert or a panel)"}`;
13641
+ }
13642
+ async function cmdRecordApp(argv, deps = {}) {
13643
+ const { flags } = parseArgs(argv, BOOLEAN_FLAGS11, MULTI_FLAGS2);
13644
+ const r = createReporter(flags.json === true);
13645
+ const driver = deps.driver ?? await loadDriver();
13646
+ let granted;
13647
+ try {
13648
+ granted = await driver.check();
13649
+ } catch (error) {
13650
+ throw driverFailure(error);
13651
+ }
13652
+ if (!granted.screenRecording) throw new Error(SCREEN_RECORDING);
13653
+ if (flags.windows === true) {
13654
+ const windows = await driver.windows().catch((error) => {
13655
+ throw driverFailure(error);
13656
+ });
13657
+ r.done(
13658
+ { windows },
13659
+ windows.length ? `${windows.map(windowLine).join("\n")}
13660
+
13661
+ Record one: vos record --app "<name>" --out take` : "No window that can be recorded is on screen."
13662
+ );
13663
+ return EXIT_OK;
13664
+ }
13665
+ const app = strFlag(flags, "app");
13666
+ const windowFlag = hasFlag(flags, "window") ? numFlag(flags, "window", NaN) : void 0;
13667
+ if (windowFlag !== void 0 && !Number.isInteger(windowFlag))
13668
+ throw new UsageError(
13669
+ "--window expects a window id from vos record --windows"
13670
+ );
13671
+ if (!app && windowFlag === void 0) throw new UsageError(USAGE2);
13672
+ const seconds = hasFlag(flags, "seconds") ? numFlag(flags, "seconds", NaN) : void 0;
13673
+ if (seconds !== void 0 && !(seconds > 0))
13674
+ throw new UsageError("--seconds expects a length above 0");
13675
+ const outDir = resolve16(strFlag(flags, "out") ?? "take");
13676
+ const backdrop = await takeBackdrop(flags, r);
13677
+ const cap = await maxDuration(flags, r);
13678
+ if (existsSync23(join24(outDir, "meta.json"))) {
13679
+ const { prevDoc, kept } = await prepareReRecord(outDir);
13680
+ r.log(
13681
+ `note: recording again into ${outDir}; kept ${kept.length ? kept.join(", ") : "nothing"}` + (prevDoc ? `; apply the previous cut with: vos plan ${outDir} --reuse` : "")
13682
+ );
13683
+ }
13684
+ await mkdir9(outDir, { recursive: true });
13685
+ const paths = takePaths(outDir);
13686
+ const notes = [];
13687
+ if (!granted.accessibility) {
13688
+ notes.push(
13689
+ "Accessibility is not granted to the app this was run from, so a press carries no bounds of what was pressed and its zoom cannot fit the control. Switch it on in System Settings, Privacy & Security, Accessibility, for zooms that fit."
13690
+ );
13691
+ r.log(`note: ${notes[0]}`);
13692
+ }
13693
+ const request = {
13694
+ ...windowFlag !== void 0 ? { window: windowFlag } : { app },
13695
+ out: outDir,
13696
+ maxSeconds: seconds !== void 0 ? Math.min(seconds, cap) : cap,
13697
+ pointer: true,
13698
+ frames: granted.accessibility
13699
+ };
13700
+ r.event({ event: "phase", phase: "record" });
13701
+ const take = driver.record(request);
13702
+ const end = () => void take.stop().catch(() => {
13703
+ });
13704
+ process.on("SIGINT", end);
13705
+ process.on("SIGTERM", end);
13706
+ let stopped;
13707
+ try {
13708
+ const ready = await take.ready;
13709
+ r.event({
13710
+ event: "recording",
13711
+ app: ready.app,
13712
+ window: ready.window,
13713
+ width: ready.captureWidth,
13714
+ height: ready.captureHeight
13715
+ });
13716
+ r.log(
13717
+ `recording ${ready.app || "the window"} (${ready.captureWidth}\xD7${ready.captureHeight})${seconds !== void 0 ? ` for ${seconds}s` : ". Use the app; Ctrl-C ends the take"}\u2026`
13718
+ );
13719
+ stopped = await take.done;
13720
+ } catch (error) {
13721
+ throw driverFailure(error);
13722
+ } finally {
13723
+ process.off("SIGINT", end);
13724
+ process.off("SIGTERM", end);
13725
+ }
13726
+ if (!existsSync23(paths.meta))
13727
+ throw new Error(`the recording ended without a take in ${outDir}`);
13728
+ const events = existsSync23(paths.cursor) ? JSON.parse(await readFile14(paths.cursor, "utf8")) : [];
13729
+ const clicks = events.filter((e) => e.type === "down").length;
13730
+ const typing = events.filter((e) => e.type === "key").length;
13731
+ const plan = await planTake(outDir, { backdrop });
13732
+ const said = notes.length;
13733
+ if (stopped.reason === "cap" && seconds === void 0)
13734
+ notes.push("stopped at --max-duration");
13735
+ if (stopped.resized)
13736
+ notes.push(
13737
+ "the window changed size during the take, so the picture is scaled to fit from there on"
13738
+ );
13739
+ const held = stopped.heldFrames;
13740
+ if (held > 0)
13741
+ notes.push(
13742
+ `another app's window was over this one for a moment: ${held} frame${held === 1 ? " was" : "s were"} held back so it is not in the take`
13743
+ );
13744
+ for (const n of notes.slice(said)) r.log(`note: ${n}`);
13745
+ const length = (stopped.durationMs / 1e3).toFixed(1);
13746
+ const cursorLine = events.length ? `${events.length} cursor events (${clicks} click${clicks === 1 ? "" : "s"}, ${typing} typing ping${typing === 1 ? "" : "s"}); ${plan.zoomAuto} zoom${plan.zoomAuto === 1 ? "" : "s"} planned` : "no pointer came over the window, so nothing was planned";
13747
+ r.done(
13748
+ {
13749
+ out: outDir,
13750
+ recording: "recording.mp4",
13751
+ durationMs: stopped.durationMs,
13752
+ frames: stopped.frames,
13753
+ bytes: stopped.bytes,
13754
+ reason: stopped.reason,
13755
+ cursor: { events: events.length, clicks, typing },
13756
+ zooms: plan.zoomAuto,
13757
+ backdrop: plan.backdrop ?? null,
13758
+ notes
13759
+ },
13760
+ `Recorded ${app ?? `window ${windowFlag}`} \u2192 ${outDir}/recording.mp4 (${length}s, ${stopped.frames} frames)
13761
+ ${cursorLine}
13762
+ Next: vos digest ${outDir} \u2014 look before you cut; edit doc.json; vos open ${outDir} or vos push ${outDir}`
13763
+ );
13764
+ return EXIT_OK;
13765
+ }
13766
+
13609
13767
  // src/plugin/checkVideo.ts
13610
13768
  import { createRequire as createRequire2 } from "module";
13611
- import { existsSync as existsSync23 } from "fs";
13612
- import { mkdir as mkdir9, readFile as readFile14, stat as stat3, writeFile as writeFile7 } from "fs/promises";
13613
- import { basename as basename12, dirname as dirname8, extname as extname4, join as join24, resolve as resolve16 } from "path";
13769
+ import { existsSync as existsSync24 } from "fs";
13770
+ import { mkdir as mkdir10, readFile as readFile15, stat as stat3, writeFile as writeFile7 } from "fs/promises";
13771
+ import { basename as basename12, dirname as dirname8, extname as extname4, join as join25, resolve as resolve17 } from "path";
13614
13772
  import { ALL_FORMATS as ALL_FORMATS2, FilePathSource as FilePathSource2, Input as Input2 } from "mediabunny";
13615
13773
 
13616
13774
  // src/plugin/videoChecks.ts
@@ -13850,7 +14008,7 @@ function posterWarning(which, deviation) {
13850
14008
  }
13851
14009
 
13852
14010
  // src/plugin/checkVideo.ts
13853
- var BOOLEAN_FLAGS11 = /* @__PURE__ */ new Set(["json", "help", "strict"]);
14011
+ var BOOLEAN_FLAGS12 = /* @__PURE__ */ new Set(["json", "help", "strict"]);
13854
14012
  var THUMB_LONG_SIDE = 160;
13855
14013
  var CELLS_LONG_SIDE = 16;
13856
14014
  async function probeVideoFacts(file) {
@@ -13893,10 +14051,10 @@ async function probeVideoFacts(file) {
13893
14051
  }
13894
14052
  async function mediabunnyBundle() {
13895
14053
  const entry = createRequire2(import.meta.url).resolve("mediabunny");
13896
- const bundle = join24(dirname8(entry), "mediabunny.min.mjs");
13897
- if (existsSync23(bundle)) return readFile14(bundle, "utf8");
13898
- return readFile14(
13899
- join24(entry.split("/dist/")[0], "dist/bundles/mediabunny.min.mjs"),
14054
+ const bundle = join25(dirname8(entry), "mediabunny.min.mjs");
14055
+ if (existsSync24(bundle)) return readFile15(bundle, "utf8");
14056
+ return readFile15(
14057
+ join25(entry.split("/dist/")[0], "dist/bundles/mediabunny.min.mjs"),
13900
14058
  "utf8"
13901
14059
  );
13902
14060
  }
@@ -14118,7 +14276,7 @@ async function checkVideo(browser, file, outDir) {
14118
14276
  );
14119
14277
  const long = Math.max(facts.width, facts.height, 1);
14120
14278
  const side = (n) => Math.max(1, Math.round(n / long * THUMB_LONG_SIDE));
14121
- const server = await startTakeServer(dirname8(resolve16(file)), {
14279
+ const server = await startTakeServer(dirname8(resolve17(file)), {
14122
14280
  "/check.html": '<!doctype html><html><head><meta charset="utf-8"><link rel="icon" href="data:,"></head><body></body></html>'
14123
14281
  });
14124
14282
  const page = await browser.newPage();
@@ -14153,9 +14311,9 @@ async function checkVideo(browser, file, outDir) {
14153
14311
  await page.close();
14154
14312
  server.close();
14155
14313
  }
14156
- await mkdir9(outDir, { recursive: true });
14157
- const firstFile = join24(outDir, "first.png");
14158
- const lastFile = join24(outDir, "last.png");
14314
+ await mkdir10(outDir, { recursive: true });
14315
+ const firstFile = join25(outDir, "first.png");
14316
+ const lastFile = join25(outDir, "last.png");
14159
14317
  await writeFile7(firstFile, Buffer.from(done.firstPng, "base64"));
14160
14318
  await writeFile7(lastFile, Buffer.from(done.lastPng, "base64"));
14161
14319
  const changes = sceneChanges2(
@@ -14204,7 +14362,7 @@ async function checkVideo(browser, file, outDir) {
14204
14362
  outDir
14205
14363
  };
14206
14364
  await writeFile7(
14207
- join24(outDir, "check.json"),
14365
+ join25(outDir, "check.json"),
14208
14366
  `${JSON.stringify(result, null, 2)}
14209
14367
  `
14210
14368
  );
@@ -14226,21 +14384,21 @@ function checkVideoLines(r) {
14226
14384
  ` scene changes: ${cuts.length}${cuts.length ? ` (${cuts.map((c) => `${c.time.toFixed(2)}s`).join(", ")})` : ""}; per ${r.scenes.window} s: ${r.scenes.perWindow.map((w) => w.count).join(", ")}`,
14227
14385
  r.audio ? ` loudness: ${l?.integrated ?? "silent"}${l?.integrated !== null ? " LUFS" : ""} integrated; short-term every 3 s: ${st?.join(", ")}; sample peak ${l?.samplePeakDb ?? "-inf"} dBFS` : " loudness: no audio track",
14228
14386
  ` posters: ${r.posters.first.file} (deviation ${r.posters.first.deviation}), ${r.posters.last.file} (deviation ${r.posters.last.deviation})`,
14229
- ` ${r.warnings.length ? `${r.warnings.length} warning${r.warnings.length === 1 ? "" : "s"}` : "no warnings"}; ${join24(r.outDir, "check.json")}`
14387
+ ` ${r.warnings.length ? `${r.warnings.length} warning${r.warnings.length === 1 ? "" : "s"}` : "no warnings"}; ${join25(r.outDir, "check.json")}`
14230
14388
  ].join("\n");
14231
14389
  }
14232
14390
  async function cmdCheckVideo(argv) {
14233
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS11);
14391
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS12);
14234
14392
  const file = positionals[0];
14235
14393
  if (!file)
14236
14394
  throw new UsageError(
14237
14395
  "vos check-video <file.mp4|webm> [--out dir] [--strict] [--json]"
14238
14396
  );
14239
- if (!existsSync23(file)) throw new UsageError(`${file} does not exist`);
14397
+ if (!existsSync24(file)) throw new UsageError(`${file} does not exist`);
14240
14398
  const r = createReporter(flags.json === true);
14241
14399
  const strict = flags.strict === true;
14242
- const outDir = resolve16(
14243
- strFlag(flags, "out") ?? join24(dirname8(file), `${basename12(file, extname4(file))}-check`)
14400
+ const outDir = resolve17(
14401
+ strFlag(flags, "out") ?? join25(dirname8(file), `${basename12(file, extname4(file))}-check`)
14244
14402
  );
14245
14403
  const browser = await launchBrowser();
14246
14404
  try {
@@ -14255,15 +14413,15 @@ async function cmdCheckVideo(argv) {
14255
14413
  }
14256
14414
 
14257
14415
  // src/plugin/join.ts
14258
- import { existsSync as existsSync26, readdirSync as readdirSync5, statSync as statSync7 } from "fs";
14259
- import { copyFile as copyFile3, mkdir as mkdir11, readFile as readFile17, rm as rm4 } from "fs/promises";
14416
+ import { existsSync as existsSync27, readdirSync as readdirSync5, statSync as statSync7 } from "fs";
14417
+ import { copyFile as copyFile3, mkdir as mkdir12, readFile as readFile18, rm as rm4 } from "fs/promises";
14260
14418
  import {
14261
14419
  basename as basename14,
14262
14420
  dirname as dirname9,
14263
14421
  isAbsolute as isAbsolute4,
14264
- join as join27,
14422
+ join as join28,
14265
14423
  relative as relative5,
14266
- resolve as resolve18,
14424
+ resolve as resolve19,
14267
14425
  sep as sep4
14268
14426
  } from "path";
14269
14427
  import {
@@ -14279,17 +14437,17 @@ import {
14279
14437
  import { totalDuration as totalDuration3 } from "@vosjs/timeline";
14280
14438
 
14281
14439
  // src/plugin/score.ts
14282
- import { existsSync as existsSync24 } from "fs";
14440
+ import { existsSync as existsSync25 } from "fs";
14283
14441
  import {
14284
14442
  copyFile as copyFile2,
14285
- mkdir as mkdir10,
14443
+ mkdir as mkdir11,
14286
14444
  mkdtemp,
14287
- readFile as readFile15,
14445
+ readFile as readFile16,
14288
14446
  rm as rm3,
14289
14447
  writeFile as writeFile8
14290
14448
  } from "fs/promises";
14291
14449
  import { tmpdir as tmpdir2 } from "os";
14292
- import { basename as basename13, isAbsolute as isAbsolute3, join as join25, relative as relative4, resolve as resolve17, sep as sep3 } from "path";
14450
+ import { basename as basename13, isAbsolute as isAbsolute3, join as join26, relative as relative4, resolve as resolve18, sep as sep3 } from "path";
14293
14451
  import { rankBeds as rankBeds2 } from "@vosjs/shared/music";
14294
14452
  import {
14295
14453
  NORMALIZE_MAX_LUFS as NORMALIZE_MAX_LUFS2,
@@ -14603,7 +14761,7 @@ async function measureInNode(path) {
14603
14761
  var PAGE_CHUNK_SECONDS = 10;
14604
14762
  var BROWSER_DECODE_MAX_BYTES = 200 * 1024 * 1024;
14605
14763
  async function measureInBrowser(path) {
14606
- const bytes = await readFile15(path);
14764
+ const bytes = await readFile16(path);
14607
14765
  if (bytes.length > BROWSER_DECODE_MAX_BYTES)
14608
14766
  throw new Error(
14609
14767
  `${basename13(path)} is ${Math.round(bytes.length / 1048576)} MB, past the ${BROWSER_DECODE_MAX_BYTES / 1048576} MB the browser decode takes whole`
@@ -14706,14 +14864,14 @@ function resolveAt(doc, raw) {
14706
14864
  return { at: r.start, via: `step ${v} (${r.start.toFixed(2)}s)` };
14707
14865
  }
14708
14866
  async function resolveTrack(dir, ref, flags, dryRun) {
14709
- const local = resolve17(ref);
14710
- if (existsSync24(local)) {
14711
- const rel = relative4(resolve17(dir), local);
14867
+ const local = resolve18(ref);
14868
+ if (existsSync25(local)) {
14869
+ const rel = relative4(resolve18(dir), local);
14712
14870
  const inside = !!rel && !rel.startsWith(`..${sep3}`) && rel !== ".." && !isAbsolute3(rel);
14713
14871
  const key = inside ? rel.split(sep3).join("/") : `music/${basename13(local)}`;
14714
14872
  if (!inside && !dryRun) {
14715
- await mkdir10(join25(dir, "music"), { recursive: true });
14716
- await copyFile2(local, join25(dir, key));
14873
+ await mkdir11(join26(dir, "music"), { recursive: true });
14874
+ await copyFile2(local, join26(dir, key));
14717
14875
  }
14718
14876
  return { path: local, key, name: basename13(local) };
14719
14877
  }
@@ -14729,8 +14887,8 @@ async function resolveTrack(dir, ref, flags, dryRun) {
14729
14887
  );
14730
14888
  const res = await fetch(track.url);
14731
14889
  if (!res.ok) throw new Error(`GET ${track.url} answered ${res.status}`);
14732
- const tmp = await mkdtemp(join25(tmpdir2(), "vos-score-"));
14733
- const path = join25(tmp, basename13(new URL(track.url).pathname) || "track");
14890
+ const tmp = await mkdtemp(join26(tmpdir2(), "vos-score-"));
14891
+ const path = join26(tmp, basename13(new URL(track.url).pathname) || "track");
14734
14892
  await writeFile8(path, new Uint8Array(await res.arrayBuffer()));
14735
14893
  return {
14736
14894
  path,
@@ -14739,13 +14897,13 @@ async function resolveTrack(dir, ref, flags, dryRun) {
14739
14897
  cleanup: () => rm3(tmp, { recursive: true, force: true })
14740
14898
  };
14741
14899
  }
14742
- var BOOLEAN_FLAGS12 = /* @__PURE__ */ new Set(["json", "help", "dry-run"]);
14743
- var USAGE2 = 'vos score <take> --track <slug|file|best> [--at <step id|output seconds>] [--mood <slug|tag>] [--words "\u2026"] [--gain 0..1] [--normalize <lufs|off>] [--fade-in <s>] [--fade-out <s>] [--dry-run] [--json]';
14900
+ var BOOLEAN_FLAGS13 = /* @__PURE__ */ new Set(["json", "help", "dry-run"]);
14901
+ var USAGE3 = 'vos score <take> --track <slug|file|best> [--at <step id|output seconds>] [--mood <slug|tag>] [--words "\u2026"] [--gain 0..1] [--normalize <lufs|off>] [--fade-in <s>] [--fade-out <s>] [--dry-run] [--json]';
14744
14902
  async function cmdScore(argv) {
14745
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS12);
14903
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS13);
14746
14904
  const dir = positionals[0];
14747
14905
  const trackRef = strFlag(flags, "track");
14748
- if (!dir || !trackRef) throw new UsageError(USAGE2);
14906
+ if (!dir || !trackRef) throw new UsageError(USAGE3);
14749
14907
  const r = createReporter(flags.json === true);
14750
14908
  const dryRun = flags["dry-run"] === true;
14751
14909
  const gain = numFlag(flags, "gain", 0.5);
@@ -14776,7 +14934,7 @@ async function cmdScore(argv) {
14776
14934
  });
14777
14935
  const catalog = await fetchMusicCatalog(origin);
14778
14936
  const film2 = filmSummaryOf2(doc, {
14779
- seed: readSyncState(dir)?.vosId ?? basename13(resolve17(dir)),
14937
+ seed: readSyncState(dir)?.vosId ?? basename13(resolve18(dir)),
14780
14938
  ...at2 ? { payoff: at2.at } : {},
14781
14939
  mood: strFlag(flags, "mood"),
14782
14940
  words: strFlag(flags, "words")
@@ -14878,7 +15036,7 @@ async function cmdScore(argv) {
14878
15036
  const placeLine = at2 && plan.swellAt !== null ? `the track starts at ${plan.in.toFixed(2)}s, so the swell lands at ${plan.swellAt.toFixed(2)}s of film (asked: ${at2.via})` : `the track starts at ${plan.in.toFixed(2)}s${at2 ? ` (asked: ${at2.via})` : ", its first rise above its median level"}`;
14879
15037
  r.done(
14880
15038
  {
14881
- take: resolve17(dir),
15039
+ take: resolve18(dir),
14882
15040
  dryRun,
14883
15041
  track: { key: track.key, name: track.name, duration: clip.duration },
14884
15042
  film: r3(film),
@@ -15405,9 +15563,9 @@ function perBeatLine(r, name = (m) => m ? `media ${m}` : "the primary") {
15405
15563
 
15406
15564
  // src/plugin/rejoin.ts
15407
15565
  import { createHash as createHash4 } from "crypto";
15408
- import { createReadStream, existsSync as existsSync25 } from "fs";
15409
- import { readFile as readFile16 } from "fs/promises";
15410
- import { join as join26 } from "path";
15566
+ import { createReadStream, existsSync as existsSync26 } from "fs";
15567
+ import { readFile as readFile17 } from "fs/promises";
15568
+ import { join as join27 } from "path";
15411
15569
  import {
15412
15570
  isRejected as isRejected2,
15413
15571
  layerStart as layerStart3,
@@ -15432,14 +15590,14 @@ async function partFootage(part) {
15432
15590
  const key = part.doc.source.videoKey;
15433
15591
  if (!isTakeRelativeKey(key))
15434
15592
  return `key:${createHash4("sha256").update(key).digest("hex")}`;
15435
- const file = join26(part.dir, takeRelativeFile(key));
15436
- return existsSync25(file) ? fileHash(file) : `key:${createHash4("sha256").update(key).digest("hex")}`;
15593
+ const file = join27(part.dir, takeRelativeFile(key));
15594
+ return existsSync26(file) ? fileHash(file) : `key:${createHash4("sha256").update(key).digest("hex")}`;
15437
15595
  }
15438
15596
  async function readJoinRecord(dir) {
15439
- const file = join26(dir, JOIN_RECORD_NAME);
15440
- if (!existsSync25(file)) return null;
15597
+ const file = join27(dir, JOIN_RECORD_NAME);
15598
+ if (!existsSync26(file)) return null;
15441
15599
  try {
15442
- const v = JSON.parse(await readFile16(file, "utf8"));
15600
+ const v = JSON.parse(await readFile17(file, "utf8"));
15443
15601
  return v && v.version === 1 && Array.isArray(v.inputs) ? v : null;
15444
15602
  } catch {
15445
15603
  return null;
@@ -15449,8 +15607,8 @@ async function recordFromFootage(dir, doc) {
15449
15607
  const hash = async (key) => {
15450
15608
  if (!isTakeRelativeKey(key))
15451
15609
  return `key:${createHash4("sha256").update(key).digest("hex")}`;
15452
- const file = join26(dir, takeRelativeFile(key));
15453
- return existsSync25(file) ? fileHash(file) : `missing:${key}`;
15610
+ const file = join27(dir, takeRelativeFile(key));
15611
+ return existsSync26(file) ? fileHash(file) : `missing:${key}`;
15454
15612
  };
15455
15613
  const inputs = [
15456
15614
  {
@@ -16212,7 +16370,7 @@ function joinDocs(parts, opts = {}) {
16212
16370
  ];
16213
16371
  for (const ref of refs)
16214
16372
  copy({
16215
- from: join27(first.dir, takeRelativeFile(ref.key)),
16373
+ from: join28(first.dir, takeRelativeFile(ref.key)),
16216
16374
  to: takeRelativeFile(ref.key),
16217
16375
  base: first.dir
16218
16376
  });
@@ -16295,7 +16453,7 @@ function joinDocs(parts, opts = {}) {
16295
16453
  for (const ref of refs) {
16296
16454
  const to = prefixed(pid, ref.key);
16297
16455
  copy({
16298
- from: join27(part.dir, takeRelativeFile(ref.key)),
16456
+ from: join28(part.dir, takeRelativeFile(ref.key)),
16299
16457
  to,
16300
16458
  base: part.dir
16301
16459
  });
@@ -16442,7 +16600,7 @@ function joinDocs(parts, opts = {}) {
16442
16600
  owners
16443
16601
  };
16444
16602
  }
16445
- var BOOLEAN_FLAGS13 = /* @__PURE__ */ new Set([
16603
+ var BOOLEAN_FLAGS14 = /* @__PURE__ */ new Set([
16446
16604
  "json",
16447
16605
  "help",
16448
16606
  "force",
@@ -16450,16 +16608,16 @@ var BOOLEAN_FLAGS13 = /* @__PURE__ */ new Set([
16450
16608
  "captions"
16451
16609
  ]);
16452
16610
  var MULTI = /* @__PURE__ */ new Set(["mute"]);
16453
- var USAGE3 = "vos join <take> <take|file.mp4>\u2026 --out <dir> [--keep-edits|--force] [--captions] [--zooms per-beat] [--mute <file>]... [--json]";
16611
+ var USAGE4 = "vos join <take> <take|file.mp4>\u2026 --out <dir> [--keep-edits|--force] [--captions] [--zooms per-beat] [--mute <file>]... [--json]";
16454
16612
  var within = (inner, outer) => {
16455
16613
  const rel = relative5(outer, inner);
16456
16614
  return rel === "" || !rel.startsWith(`..${sep4}`) && rel !== ".." && !isAbsolute4(rel);
16457
16615
  };
16458
16616
  async function readPart(arg) {
16459
- const path = resolve18(arg);
16460
- if (!existsSync26(path)) throw new UsageError(`${arg}: no such take or file`);
16617
+ const path = resolve19(arg);
16618
+ if (!existsSync27(path)) throw new UsageError(`${arg}: no such take or file`);
16461
16619
  if (statSync7(path).isDirectory()) {
16462
- if (!existsSync26(join27(path, "meta.json")))
16620
+ if (!existsSync27(join28(path, "meta.json")))
16463
16621
  throw new UsageError(
16464
16622
  `${arg}: not a take directory (no meta.json); a video file is joined by its path`
16465
16623
  );
@@ -16492,7 +16650,7 @@ async function readPart(arg) {
16492
16650
  };
16493
16651
  }
16494
16652
  async function cmdJoin(argv) {
16495
- const { positionals, flags, multi } = parseArgs(argv, BOOLEAN_FLAGS13, MULTI);
16653
+ const { positionals, flags, multi } = parseArgs(argv, BOOLEAN_FLAGS14, MULTI);
16496
16654
  const r = createReporter(flags.json === true);
16497
16655
  const outArg = strFlag(flags, "out");
16498
16656
  const force = flags.force === true;
@@ -16501,16 +16659,16 @@ async function cmdJoin(argv) {
16501
16659
  const zoomMode = zoomModeOf(strFlag(flags, "zooms"));
16502
16660
  if (zoomMode && typeof zoomMode === "object")
16503
16661
  throw new UsageError(zoomMode.error);
16504
- if (positionals.length < 2 || !outArg) throw new UsageError(USAGE3);
16662
+ if (positionals.length < 2 || !outArg) throw new UsageError(USAGE4);
16505
16663
  if (force && keepEdits)
16506
16664
  throw new UsageError(
16507
16665
  "--force replaces the joined take and --keep-edits keeps its edits; pass one"
16508
16666
  );
16509
- const out = resolve18(outArg);
16510
- const inputs = positionals.map((p) => resolve18(p));
16667
+ const out = resolve19(outArg);
16668
+ const inputs = positionals.map((p) => resolve19(p));
16511
16669
  const muted = /* @__PURE__ */ new Set();
16512
16670
  for (const m of multi.mute ?? []) {
16513
- const i = inputs.indexOf(resolve18(m));
16671
+ const i = inputs.indexOf(resolve19(m));
16514
16672
  if (i < 0)
16515
16673
  throw new UsageError(
16516
16674
  `--mute ${m}: not one of the inputs; name a file as it is given to vos join`
@@ -16524,19 +16682,19 @@ async function cmdJoin(argv) {
16524
16682
  );
16525
16683
  }
16526
16684
  let rejoin = false;
16527
- if (existsSync26(out)) {
16685
+ if (existsSync27(out)) {
16528
16686
  if (!force && !keepEdits)
16529
16687
  throw new UsageError(
16530
16688
  `--out ${outArg} exists; pass --keep-edits to join again and keep every edit made since (its trims, spans, layers, frame, sound), --force to replace it, or name a new directory`
16531
16689
  );
16532
16690
  if (keepEdits) {
16533
- if (!existsSync26(join27(out, "doc.json")))
16691
+ if (!existsSync27(join28(out, "doc.json")))
16534
16692
  throw new UsageError(
16535
16693
  `--keep-edits: ${outArg} holds no doc.json, so there are no edits to keep; name a new directory, or --force to replace it`
16536
16694
  );
16537
16695
  rejoin = true;
16538
16696
  } else {
16539
- const isTake = existsSync26(join27(out, "doc.json")) || existsSync26(join27(out, "meta.json"));
16697
+ const isTake = existsSync27(join28(out, "doc.json")) || existsSync27(join28(out, "meta.json"));
16540
16698
  if (!isTake && readdirSync5(out).length > 0)
16541
16699
  throw new UsageError(
16542
16700
  `--force replaces a take directory, and ${outArg} holds other files; name a new directory`
@@ -16572,7 +16730,7 @@ async function cmdJoin(argv) {
16572
16730
  let rejoined = null;
16573
16731
  if (rejoin) {
16574
16732
  const prev = JSON.parse(
16575
- await readFile17(join27(out, "doc.json"), "utf8")
16733
+ await readFile18(join28(out, "doc.json"), "utf8")
16576
16734
  );
16577
16735
  let record = await readJoinRecord(out);
16578
16736
  if (!record) {
@@ -16582,7 +16740,7 @@ async function cmdJoin(argv) {
16582
16740
  );
16583
16741
  }
16584
16742
  rejoined = rejoinDocs(migrateMotion3(prev), record, read, {
16585
- where: (p) => relative5(process.cwd(), resolve18(out, p)) || "."
16743
+ where: (p) => relative5(process.cwd(), resolve19(out, p)) || "."
16586
16744
  });
16587
16745
  plan = rejoined.plan;
16588
16746
  } else plan = joinDocs(parts);
@@ -16623,17 +16781,17 @@ async function cmdJoin(argv) {
16623
16781
  if (rejoined) {
16624
16782
  for (const k of rejoined.dropped) {
16625
16783
  if (!/^[A-Za-z0-9_-]+$/.test(k)) continue;
16626
- const dir = join27(out, k);
16627
- if (existsSync26(dir) && statSync7(dir).isDirectory())
16784
+ const dir = join28(out, k);
16785
+ if (existsSync27(dir) && statSync7(dir).isDirectory())
16628
16786
  await rm4(dir, { recursive: true, force: true });
16629
16787
  }
16630
16788
  } else {
16631
- if (existsSync26(out)) await rm4(out, { recursive: true, force: true });
16632
- await mkdir11(out, { recursive: true });
16789
+ if (existsSync27(out)) await rm4(out, { recursive: true, force: true });
16790
+ await mkdir12(out, { recursive: true });
16633
16791
  }
16634
16792
  for (const c of plan.copies) {
16635
- const to = join27(out, c.to);
16636
- await mkdir11(dirname9(to), { recursive: true });
16793
+ const to = join28(out, c.to);
16794
+ await mkdir12(dirname9(to), { recursive: true });
16637
16795
  if (c.remux) {
16638
16796
  const remuxed = await copyRecording(c.from, to, c.remux);
16639
16797
  if (!remuxed && c.remux !== "mov")
@@ -16649,7 +16807,7 @@ async function cmdJoin(argv) {
16649
16807
  for (const clip of doc.audio) {
16650
16808
  if (!added.has(clip.id) || !isTakeRelativeKey(clip.key)) continue;
16651
16809
  try {
16652
- const m = await measureTrack(join27(out, takeRelativeFile(clip.key)));
16810
+ const m = await measureTrack(join28(out, takeRelativeFile(clip.key)));
16653
16811
  if (m.lufs !== null)
16654
16812
  clip.loudness = loudnessFact(
16655
16813
  { lufs: m.lufs, peakDb: m.peakDb },
@@ -16661,14 +16819,14 @@ async function cmdJoin(argv) {
16661
16819
  );
16662
16820
  }
16663
16821
  }
16664
- await writeJson(join27(out, "meta.json"), doc.source.meta, true);
16822
+ await writeJson(join28(out, "meta.json"), doc.source.meta, true);
16665
16823
  if (doc.source.cursor.length)
16666
- await writeJson(join27(out, "cursor.json"), doc.source.cursor);
16824
+ await writeJson(join28(out, "cursor.json"), doc.source.cursor);
16667
16825
  if (parts[0].actions)
16668
- await writeJson(join27(out, "actions.json"), parts[0].actions, true);
16669
- await writeJson(join27(out, "doc.json"), doc, true);
16826
+ await writeJson(join28(out, "actions.json"), parts[0].actions, true);
16827
+ await writeJson(join28(out, "doc.json"), doc, true);
16670
16828
  await writeJson(
16671
- join27(out, JOIN_RECORD_NAME),
16829
+ join28(out, JOIN_RECORD_NAME),
16672
16830
  joinRecordOf(read, plan.ids),
16673
16831
  true
16674
16832
  );
@@ -16712,7 +16870,7 @@ async function cmdJoin(argv) {
16712
16870
  }
16713
16871
 
16714
16872
  // src/plugin/timeline.ts
16715
- import { join as join28, resolve as resolve19 } from "path";
16873
+ import { join as join29, resolve as resolve20 } from "path";
16716
16874
  import {
16717
16875
  docFreezes as docFreezes2,
16718
16876
  docMediaList as docMediaList4,
@@ -17003,7 +17161,7 @@ async function cmdTakeInfo(argv) {
17003
17161
  if (drift) r.warn(scriptDriftLine(drift));
17004
17162
  const timeline = takeTimeline(take.doc, /* @__PURE__ */ new Map([["", take.actions]]));
17005
17163
  r.done(
17006
- { take: resolve19(dir), doc: join28(resolve19(dir), "doc.json"), ...timeline },
17164
+ { take: resolve20(dir), doc: join29(resolve20(dir), "doc.json"), ...timeline },
17007
17165
  formatTimeline(timeline, dir)
17008
17166
  );
17009
17167
  return EXIT_OK;
@@ -17012,9 +17170,9 @@ async function cmdTakeInfo(argv) {
17012
17170
  // src/plugin/audio.ts
17013
17171
  import { mkdtemp as mkdtemp2, rm as rm5, writeFile as writeFile9 } from "fs/promises";
17014
17172
  import { tmpdir as tmpdir3 } from "os";
17015
- import { basename as basename15, join as join29 } from "path";
17173
+ import { basename as basename15, join as join30 } from "path";
17016
17174
  import { clipGain as clipGain3 } from "@vosjs/studio-core";
17017
- var USAGE4 = "vos audio measure <take> [--json]";
17175
+ var USAGE5 = "vos audio measure <take> [--json]";
17018
17176
  async function fileFor(dir, key, fetchImpl) {
17019
17177
  if (isTakeRelativeKey(key)) {
17020
17178
  const found = localFile(takeRelativeFile(key), dir);
@@ -17024,8 +17182,8 @@ async function fileFor(dir, key, fetchImpl) {
17024
17182
  if (/^https?:\/\//.test(key)) {
17025
17183
  const res = await fetchImpl(key);
17026
17184
  if (!res.ok) return { skipped: `GET ${key} answered ${res.status}` };
17027
- const tmp = await mkdtemp2(join29(tmpdir3(), "vos-audio-"));
17028
- const path = join29(tmp, basename15(new URL(key).pathname) || "audio");
17185
+ const tmp = await mkdtemp2(join30(tmpdir3(), "vos-audio-"));
17186
+ const path = join30(tmp, basename15(new URL(key).pathname) || "audio");
17029
17187
  await writeFile9(path, new Uint8Array(await res.arrayBuffer()));
17030
17188
  return { path, cleanup: () => rm5(tmp, { recursive: true, force: true }) };
17031
17189
  }
@@ -17081,7 +17239,7 @@ function clipLine(c) {
17081
17239
  async function cmdAudio(argv) {
17082
17240
  const { positionals, flags } = parseArgs(argv, /* @__PURE__ */ new Set(["json", "help"]));
17083
17241
  const [sub, dir] = positionals;
17084
- if (sub !== "measure" || !dir) throw new UsageError(USAGE4);
17242
+ if (sub !== "measure" || !dir) throw new UsageError(USAGE5);
17085
17243
  const r = createReporter(flags.json === true);
17086
17244
  const take = await loadTake(dir);
17087
17245
  if (!take.doc)
@@ -17106,11 +17264,11 @@ async function cmdAudio(argv) {
17106
17264
  }
17107
17265
 
17108
17266
  // src/plugin/musicCmd.ts
17109
- import { existsSync as existsSync27, readFileSync as readFileSync10, statSync as statSync8 } from "fs";
17110
- import { basename as basename16, resolve as resolve20 } from "path";
17267
+ import { existsSync as existsSync28, readFileSync as readFileSync10, statSync as statSync8 } from "fs";
17268
+ import { basename as basename16, resolve as resolve21 } from "path";
17111
17269
  import { rankBeds as rankBeds3, trackBySlug as trackBySlug2 } from "@vosjs/shared/music";
17112
17270
  import { filmSummaryOf as filmSummaryOf3, musicSlugsOfDoc } from "@vosjs/studio-core";
17113
- var BOOLEAN_FLAGS14 = /* @__PURE__ */ new Set([
17271
+ var BOOLEAN_FLAGS15 = /* @__PURE__ */ new Set([
17114
17272
  "json",
17115
17273
  "help",
17116
17274
  "loops",
@@ -17119,7 +17277,7 @@ var BOOLEAN_FLAGS14 = /* @__PURE__ */ new Set([
17119
17277
  "fade-in"
17120
17278
  ]);
17121
17279
  var MULTI_FLAGS3 = /* @__PURE__ */ new Set(["like"]);
17122
- var USAGE5 = 'vos music ls [--mood <slug>] [--vocals none|chops|lead] [--loops] [--bpm <lo>-<hi>] [--min-length <s>] [--q <words>] [--json]\nvos music pick <take|config.json> [--at <step id|seconds>] [--mood <slug|tag>] [--words "\u2026"] [--voice|--no-voice] [--like <vos id|slug>]... [--top <n>] [--json]';
17280
+ var USAGE6 = 'vos music ls [--mood <slug>] [--vocals none|chops|lead] [--loops] [--bpm <lo>-<hi>] [--min-length <s>] [--q <words>] [--json]\nvos music pick <take|config.json> [--at <step id|seconds>] [--mood <slug|tag>] [--words "\u2026"] [--voice|--no-voice] [--like <vos id|slug>]... [--top <n>] [--json]';
17123
17281
  var mmss = (s) => {
17124
17282
  const whole = Math.round(s);
17125
17283
  return `${Math.floor(whole / 60)}:${String(whole % 60).padStart(2, "0")}`;
@@ -17181,8 +17339,8 @@ function filterTracks(tracks, f) {
17181
17339
  });
17182
17340
  }
17183
17341
  async function loadFilm(ref) {
17184
- const path = resolve20(ref);
17185
- if (!existsSync27(path)) throw new UsageError(`${ref}: no such take or file`);
17342
+ const path = resolve21(ref);
17343
+ if (!existsSync28(path)) throw new UsageError(`${ref}: no such take or file`);
17186
17344
  if (statSync8(path).isDirectory()) {
17187
17345
  const take = await loadTake(path);
17188
17346
  if (!take.doc)
@@ -17261,12 +17419,12 @@ ${lines.join("\n")}${tail}`;
17261
17419
  async function cmdMusic(argv) {
17262
17420
  const { positionals, flags, multi } = parseArgs(
17263
17421
  argv,
17264
- BOOLEAN_FLAGS14,
17422
+ BOOLEAN_FLAGS15,
17265
17423
  MULTI_FLAGS3
17266
17424
  );
17267
17425
  const verb = positionals[0];
17268
17426
  if (flags.help === true || !verb || !["ls", "pick"].includes(verb))
17269
- throw new UsageError(USAGE5);
17427
+ throw new UsageError(USAGE6);
17270
17428
  const r = createReporter(flags.json === true);
17271
17429
  const origin = platformOrigin({
17272
17430
  origin: strFlag(flags, "origin"),
@@ -17292,7 +17450,7 @@ async function cmdMusic(argv) {
17292
17450
  return EXIT_OK;
17293
17451
  }
17294
17452
  const ref = positionals[1];
17295
- if (!ref) throw new UsageError(USAGE5);
17453
+ if (!ref) throw new UsageError(USAGE6);
17296
17454
  const { doc, seed, dir } = await loadFilm(ref);
17297
17455
  const atRaw = strFlag(flags, "at");
17298
17456
  const at2 = atRaw !== void 0 ? resolveAt(doc, atRaw) : null;
@@ -17333,10 +17491,10 @@ async function cmdMusic(argv) {
17333
17491
  }
17334
17492
 
17335
17493
  // src/plugin/look.ts
17336
- import { mkdir as mkdir12, mkdtemp as mkdtemp3, readFile as readFile18, rm as rm6 } from "fs/promises";
17337
- import { existsSync as existsSync28 } from "fs";
17494
+ import { mkdir as mkdir13, mkdtemp as mkdtemp3, readFile as readFile19, rm as rm6 } from "fs/promises";
17495
+ import { existsSync as existsSync29 } from "fs";
17338
17496
  import { tmpdir as tmpdir4 } from "os";
17339
- import { dirname as dirname10, join as join30, resolve as resolve21 } from "path";
17497
+ import { dirname as dirname10, join as join31, resolve as resolve22 } from "path";
17340
17498
  import { headersFor, urlSchemeProblem } from "@vosjs/render-core/record";
17341
17499
  function quote(value) {
17342
17500
  return `"${value.replace(/\s+/g, " ").replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
@@ -17799,8 +17957,8 @@ async function inspectPage(page, opts) {
17799
17957
  const { url, wall, settled } = opts;
17800
17958
  const ran = opts.steps;
17801
17959
  if (opts.waitMs && opts.waitMs > 0) await page.waitForTimeout(opts.waitMs);
17802
- await mkdir12(opts.outDir, { recursive: true });
17803
- const screenshot = join30(opts.outDir, "look.png");
17960
+ await mkdir13(opts.outDir, { recursive: true });
17961
+ const screenshot = join31(opts.outDir, "look.png");
17804
17962
  await page.screenshot({ path: screenshot });
17805
17963
  const scan = await page.evaluate(EXPOSURE_PROBE).catch(() => null);
17806
17964
  const step = ran.length ? ran.length - 1 : -1;
@@ -17855,7 +18013,7 @@ async function inspectPage(page, opts) {
17855
18013
  settled
17856
18014
  };
17857
18015
  }
17858
- var USAGE6 = "vos look <url> [--session <name> | --storage-state <file>] [--viewport WxH] [--headed] [--click <selector>]... [--type <selector>=<text>]... [--wait <ms>] [--out <dir>] [--json]\n vos look [url] --actions actions.json --until <step id> [--session <name> | --storage-state <file>] [--viewport WxH] [--headed] [--wait <ms>] [--out <dir>] [--json]";
18016
+ var USAGE7 = "vos look <url> [--session <name> | --storage-state <file>] [--viewport WxH] [--headed] [--click <selector>]... [--type <selector>=<text>]... [--wait <ms>] [--out <dir>] [--json]\n vos look [url] --actions actions.json --until <step id> [--session <name> | --storage-state <file>] [--viewport WxH] [--headed] [--wait <ms>] [--out <dir>] [--json]";
17859
18017
  function untilProblem(given, steps) {
17860
18018
  if (given.until !== void 0 && given.actions === void 0)
17861
18019
  return "--until names a step of a script: pass the script with --actions actions.json";
@@ -17914,7 +18072,7 @@ async function cmdLook(argv) {
17914
18072
  if (early) throw new UsageError(early);
17915
18073
  let actions;
17916
18074
  if (actionsArg) {
17917
- actions = await loadLookActions(resolve21(actionsArg));
18075
+ actions = await loadLookActions(resolve22(actionsArg));
17918
18076
  const bad = untilProblem(
17919
18077
  { actions: actionsArg, until: untilId, clicks: 0 },
17920
18078
  actions.steps
@@ -17922,21 +18080,21 @@ async function cmdLook(argv) {
17922
18080
  if (bad) throw new UsageError(bad);
17923
18081
  }
17924
18082
  const url = positionals[0] ?? actions?.url;
17925
- if (!url) throw new UsageError(USAGE6);
18083
+ if (!url) throw new UsageError(USAGE7);
17926
18084
  const scheme = urlSchemeProblem(url);
17927
18085
  if (scheme) throw new UsageError(scheme);
17928
18086
  const r = createReporter(flags.json === true);
17929
18087
  const viewportFlag = strFlag(flags, "viewport");
17930
18088
  const viewport = !viewportFlag && actions?.viewport ? actions.viewport : parseViewport2(viewportFlag);
17931
- const outDir = resolve21(strFlag(flags, "out") ?? "look");
18089
+ const outDir = resolve22(strFlag(flags, "out") ?? "look");
17932
18090
  const headed = flags.headed === true;
17933
18091
  const waitRaw = strFlag(flags, "wait");
17934
18092
  const waitMs = waitRaw === void 0 ? 0 : Number(waitRaw);
17935
18093
  if (!Number.isFinite(waitMs) || waitMs < 0 || waitMs > 6e4)
17936
18094
  throw new UsageError("--wait expects milliseconds, 0 to 60000");
17937
18095
  const storageRaw = strFlag(flags, "storage-state");
17938
- const storageState = storageRaw ? resolve21(storageRaw) : void 0;
17939
- if (storageState && !existsSync28(storageState))
18096
+ const storageState = storageRaw ? resolve22(storageRaw) : void 0;
18097
+ if (storageState && !existsSync29(storageState))
17940
18098
  throw new UsageError(`--storage-state: no such file: ${storageState}`);
17941
18099
  const sessionName = strFlag(flags, "session");
17942
18100
  if (sessionName) {
@@ -17946,7 +18104,7 @@ async function cmdLook(argv) {
17946
18104
  throw new UsageError(
17947
18105
  "--session and --storage-state are two doors to one page: a persistent profile cannot take a storage state. Pass one"
17948
18106
  );
17949
- if (!existsSync28(sessionDir(sessionName)))
18107
+ if (!existsSync29(sessionDir(sessionName)))
17950
18108
  throw new UsageError(
17951
18109
  `no session "${sessionName}". Make one: vos session open <url> --name ${sessionName} (a Chrome window opens; sign in and close it)`
17952
18110
  );
@@ -17963,7 +18121,7 @@ async function cmdLook(argv) {
17963
18121
  r,
17964
18122
  url,
17965
18123
  actions,
17966
- actionsPath: resolve21(actionsArg),
18124
+ actionsPath: resolve22(actionsArg),
17967
18125
  untilId,
17968
18126
  viewport,
17969
18127
  outDir,
@@ -18023,7 +18181,7 @@ async function cmdLook(argv) {
18023
18181
  async function loadLookActions(file) {
18024
18182
  let raw;
18025
18183
  try {
18026
- raw = JSON.parse(await readFile18(file, "utf8"));
18184
+ raw = JSON.parse(await readFile19(file, "utf8"));
18027
18185
  } catch (e) {
18028
18186
  throw new UsageError(
18029
18187
  `--actions ${file}: ${e instanceof Error ? e.message : String(e)}`
@@ -18041,7 +18199,7 @@ async function lookUntil(o) {
18041
18199
  const actions = { ...o.actions, viewport: o.viewport };
18042
18200
  let wall = null;
18043
18201
  let looked = null;
18044
- const scratch = await mkdtemp3(join30(tmpdir4(), "vos-look-"));
18202
+ const scratch = await mkdtemp3(join31(tmpdir4(), "vos-look-"));
18045
18203
  r.log(
18046
18204
  `walking ${o.actionsPath} to step ${o.untilId} (a rehearsal: guarded steps hovered, never pressed)\u2026`
18047
18205
  );
@@ -18127,18 +18285,18 @@ async function lookUntil(o) {
18127
18285
  import { spawnSync as spawnSync4 } from "child_process";
18128
18286
  import {
18129
18287
  cpSync,
18130
- existsSync as existsSync30,
18288
+ existsSync as existsSync31,
18131
18289
  mkdirSync as mkdirSync6,
18132
18290
  readFileSync as readFileSync12,
18133
18291
  writeFileSync as writeFileSync6
18134
18292
  } from "fs";
18135
18293
  import { homedir as homedir2 } from "os";
18136
- import { join as join32 } from "path";
18294
+ import { join as join33 } from "path";
18137
18295
  import { chromium as chromium2 } from "playwright";
18138
18296
 
18139
18297
  // src/plugin/machine.ts
18140
- import { existsSync as existsSync29, readFileSync as readFileSync11, readdirSync as readdirSync6, statSync as statSync9 } from "fs";
18141
- import { dirname as dirname11, join as join31 } from "path";
18298
+ import { existsSync as existsSync30, readFileSync as readFileSync11, readdirSync as readdirSync6, statSync as statSync9 } from "fs";
18299
+ import { dirname as dirname11, join as join32 } from "path";
18142
18300
  var AGENT_NAMES = [
18143
18301
  "claude",
18144
18302
  "cursor",
@@ -18158,17 +18316,17 @@ var HOME_DIRS = {
18158
18316
  copilot: [".copilot"]
18159
18317
  };
18160
18318
  function detectAgents(root, opts = {}) {
18161
- const exists = opts.exists ?? existsSync29;
18319
+ const exists = opts.exists ?? existsSync30;
18162
18320
  const out = [];
18163
18321
  for (const agent of AGENT_NAMES) {
18164
18322
  for (const rel of PROJECT_DIRS[agent]) {
18165
- const dir = join31(root, rel);
18323
+ const dir = join32(root, rel);
18166
18324
  if (exists(dir)) out.push({ agent, dir, scope: "project" });
18167
18325
  }
18168
- if (agent === "copilot" && !out.some((h) => h.agent === "copilot") && exists(join31(root, ".github", "copilot-instructions.md"))) {
18326
+ if (agent === "copilot" && !out.some((h) => h.agent === "copilot") && exists(join32(root, ".github", "copilot-instructions.md"))) {
18169
18327
  out.push({
18170
18328
  agent,
18171
- dir: join31(root, ".github", "copilot"),
18329
+ dir: join32(root, ".github", "copilot"),
18172
18330
  scope: "project"
18173
18331
  });
18174
18332
  }
@@ -18176,7 +18334,7 @@ function detectAgents(root, opts = {}) {
18176
18334
  if (opts.global && opts.home) {
18177
18335
  for (const agent of AGENT_NAMES) {
18178
18336
  for (const rel of HOME_DIRS[agent]) {
18179
- const dir = join31(opts.home, rel);
18337
+ const dir = join32(opts.home, rel);
18180
18338
  if (exists(dir)) out.push({ agent, dir, scope: "global" });
18181
18339
  }
18182
18340
  }
@@ -18194,18 +18352,18 @@ function agentsFromFlag(value, root) {
18194
18352
  return {
18195
18353
  homes: wanted.map((agent) => ({
18196
18354
  agent,
18197
- dir: join31(root, PROJECT_DIRS[agent][0]),
18355
+ dir: join32(root, PROJECT_DIRS[agent][0]),
18198
18356
  scope: "project"
18199
18357
  }))
18200
18358
  };
18201
18359
  }
18202
18360
  function skillsDirFor(home) {
18203
- return join31(home.dir, "skills");
18361
+ return join32(home.dir, "skills");
18204
18362
  }
18205
18363
  function fallbackSkillsHome(root) {
18206
- return { agent: "codex", dir: join31(root, ".agents"), scope: "project" };
18364
+ return { agent: "codex", dir: join32(root, ".agents"), scope: "project" };
18207
18365
  }
18208
- function installedSkills(dir, exists = existsSync29, list = (p) => {
18366
+ function installedSkills(dir, exists = existsSync30, list = (p) => {
18209
18367
  try {
18210
18368
  return readdirSync6(p);
18211
18369
  } catch {
@@ -18213,7 +18371,7 @@ function installedSkills(dir, exists = existsSync29, list = (p) => {
18213
18371
  }
18214
18372
  }) {
18215
18373
  if (!exists(dir)) return [];
18216
- return list(dir).filter((name) => exists(join31(dir, name, "SKILL.md"))).sort();
18374
+ return list(dir).filter((name) => exists(join32(dir, name, "SKILL.md"))).sort();
18217
18375
  }
18218
18376
  var RULES_BEGIN = "<!-- vos:begin (written by vos setup; the block is replaced on the next run) -->";
18219
18377
  var RULES_END = "<!-- vos:end -->";
@@ -18246,10 +18404,10 @@ ${RULES_BLOCK}
18246
18404
  }
18247
18405
  return { text, changed: text !== current };
18248
18406
  }
18249
- function rulesFileFor(root, exists = existsSync29) {
18250
- const agents = join31(root, "AGENTS.md");
18407
+ function rulesFileFor(root, exists = existsSync30) {
18408
+ const agents = join32(root, "AGENTS.md");
18251
18409
  if (exists(agents)) return agents;
18252
- const claude = join31(root, "CLAUDE.md");
18410
+ const claude = join32(root, "CLAUDE.md");
18253
18411
  if (exists(claude)) return claude;
18254
18412
  return agents;
18255
18413
  }
@@ -18258,14 +18416,14 @@ function chromeCandidates(platform, env) {
18258
18416
  return ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"];
18259
18417
  if (platform === "win32")
18260
18418
  return [
18261
- join31(
18419
+ join32(
18262
18420
  env["PROGRAMFILES"] ?? "C:\\Program Files",
18263
18421
  "Google",
18264
18422
  "Chrome",
18265
18423
  "Application",
18266
18424
  "chrome.exe"
18267
18425
  ),
18268
- join31(
18426
+ join32(
18269
18427
  env["LOCALAPPDATA"] ?? "",
18270
18428
  "Google",
18271
18429
  "Chrome",
@@ -18303,6 +18461,12 @@ var NODE_MIN_MAJOR = 18;
18303
18461
  function major(version) {
18304
18462
  return parseInt(version.split(".")[0] ?? "0", 10);
18305
18463
  }
18464
+ function desktopLine(d) {
18465
+ if (!d.available) return `not available (${d.reason})`;
18466
+ if (!d.screenRecording)
18467
+ return `vos-driver ${d.version}; Screen Recording not granted \u2717 switch it on for the app this runs from: System Settings, Privacy & Security, Screen & System Audio Recording`;
18468
+ return `vos-driver ${d.version}; Screen Recording \u2713; Accessibility ${d.accessibility ? "\u2713" : "not granted (a press then carries no bounds, so its zoom cannot fit the control)"}`;
18469
+ }
18306
18470
  function credentialLine(facts) {
18307
18471
  const accounts = facts.accounts ?? [];
18308
18472
  const active = accounts.find((a) => a.active);
@@ -18341,6 +18505,7 @@ function doctorReport(facts) {
18341
18505
  lines.push("skills none \u2717 run: npx vos setup");
18342
18506
  }
18343
18507
  lines.push(`credential ${credentialLine(facts)}`);
18508
+ if (facts.desktop) lines.push(`desktop ${desktopLine(facts.desktop)}`);
18344
18509
  if (facts.devServer) {
18345
18510
  const d = facts.devServer;
18346
18511
  lines.push(
@@ -18361,7 +18526,7 @@ function doctorReport(facts) {
18361
18526
  }
18362
18527
  function bundledSkillsVersion(dir) {
18363
18528
  try {
18364
- const v = readFileSync11(join31(dir, "VERSION"), "utf8").trim();
18529
+ const v = readFileSync11(join32(dir, "VERSION"), "utf8").trim();
18365
18530
  return /^\d+\.\d+\.\d+$/.test(v) ? v : null;
18366
18531
  } catch {
18367
18532
  return null;
@@ -18370,13 +18535,13 @@ function bundledSkillsVersion(dir) {
18370
18535
  function bundledSkillsDir(from) {
18371
18536
  let dir = dirname11(from);
18372
18537
  for (let i = 0; i < 6; i++) {
18373
- const pkg = join31(dir, "package.json");
18374
- if (existsSync29(pkg)) {
18538
+ const pkg = join32(dir, "package.json");
18539
+ if (existsSync30(pkg)) {
18375
18540
  try {
18376
18541
  const name = JSON.parse(readFileSync11(pkg, "utf8")).name;
18377
18542
  if (name === "@vosjs/cli") {
18378
- const skills = join31(dir, "skills");
18379
- return existsSync29(skills) && statSync9(skills).isDirectory() ? skills : null;
18543
+ const skills = join32(dir, "skills");
18544
+ return existsSync30(skills) && statSync9(skills).isDirectory() ? skills : null;
18380
18545
  }
18381
18546
  } catch {
18382
18547
  }
@@ -18389,7 +18554,7 @@ function bundledSkillsDir(from) {
18389
18554
  }
18390
18555
 
18391
18556
  // src/plugin/machineCmd.ts
18392
- var BOOLEAN_FLAGS15 = /* @__PURE__ */ new Set([
18557
+ var BOOLEAN_FLAGS16 = /* @__PURE__ */ new Set([
18393
18558
  "json",
18394
18559
  "help",
18395
18560
  "global",
@@ -18398,7 +18563,7 @@ var BOOLEAN_FLAGS15 = /* @__PURE__ */ new Set([
18398
18563
  "no-rules",
18399
18564
  "no-browser"
18400
18565
  ]);
18401
- var LOGOUT_FLAGS = /* @__PURE__ */ new Set([...BOOLEAN_FLAGS15, "all"]);
18566
+ var LOGOUT_FLAGS = /* @__PURE__ */ new Set([...BOOLEAN_FLAGS16, "all"]);
18402
18567
  var SKILLS_SOURCE = "vosjs/skills";
18403
18568
  var SKILLS_CLI_VERSION = "1.7.2";
18404
18569
  function skillsCatalogAt(version) {
@@ -18413,7 +18578,7 @@ function npx() {
18413
18578
  function bundledChromium() {
18414
18579
  try {
18415
18580
  const p = chromium2.executablePath();
18416
- return p && existsSync30(p) ? p : null;
18581
+ return p && existsSync31(p) ? p : null;
18417
18582
  } catch {
18418
18583
  return null;
18419
18584
  }
@@ -18422,7 +18587,7 @@ function probe2() {
18422
18587
  return probeBrowser({
18423
18588
  platform: process.platform,
18424
18589
  env: process.env,
18425
- exists: existsSync30,
18590
+ exists: existsSync31,
18426
18591
  bundled: bundledChromium
18427
18592
  });
18428
18593
  }
@@ -18470,9 +18635,28 @@ async function doctorFacts(opts) {
18470
18635
  skills: skillsFacts(opts.homes),
18471
18636
  credential: safeResolve() !== null,
18472
18637
  accounts: storedAccounts(platformOrigin()),
18473
- ...opts.url ? { devServer: await devServerFact(opts.url) } : {}
18638
+ ...opts.url ? { devServer: await devServerFact(opts.url) } : {},
18639
+ desktop: await desktopFact()
18474
18640
  };
18475
18641
  }
18642
+ async function desktopFact() {
18643
+ try {
18644
+ const { check } = await import("@vosjs/driver");
18645
+ const c = await check();
18646
+ return {
18647
+ available: true,
18648
+ version: c.version,
18649
+ screenRecording: c.screenRecording,
18650
+ accessibility: c.accessibility
18651
+ };
18652
+ } catch (error) {
18653
+ const message = error.message;
18654
+ return {
18655
+ available: false,
18656
+ reason: (message ?? "the helper is not installed").replace(/\.$/, "")
18657
+ };
18658
+ }
18659
+ }
18476
18660
  function safeResolve() {
18477
18661
  try {
18478
18662
  return resolveCredential();
@@ -18487,7 +18671,7 @@ function storedAccounts(origin, store = DEFAULT_STORE) {
18487
18671
  }));
18488
18672
  }
18489
18673
  async function cmdSetup(argv) {
18490
- const { flags } = parseArgs(argv, BOOLEAN_FLAGS15);
18674
+ const { flags } = parseArgs(argv, BOOLEAN_FLAGS16);
18491
18675
  const r = reporterFor(flags);
18492
18676
  const root = process.cwd();
18493
18677
  const global = flags.global === true;
@@ -18521,7 +18705,7 @@ async function cmdSetup(argv) {
18521
18705
  const dest = skillsDirFor(home);
18522
18706
  mkdirSync6(dest, { recursive: true });
18523
18707
  for (const name of installedSkills(dir)) {
18524
- cpSync(join32(dir, name), join32(dest, name), { recursive: true });
18708
+ cpSync(join33(dir, name), join33(dest, name), { recursive: true });
18525
18709
  }
18526
18710
  }
18527
18711
  };
@@ -18589,7 +18773,7 @@ async function cmdSetup(argv) {
18589
18773
  let rules = null;
18590
18774
  if (!noRules) {
18591
18775
  const file = rulesFileFor(root);
18592
- const existing = existsSync30(file) ? readFileSync12(file, "utf8") : null;
18776
+ const existing = existsSync31(file) ? readFileSync12(file, "utf8") : null;
18593
18777
  const { text, changed } = applyRulesBlock(existing);
18594
18778
  if (changed) writeFileSync6(file, text);
18595
18779
  rules = { file, changed };
@@ -18620,7 +18804,7 @@ Next: ${report.next_step}`
18620
18804
  return report.ok ? EXIT_OK : EXIT_NO_BROWSER;
18621
18805
  }
18622
18806
  async function cmdDoctor(argv) {
18623
- const { flags } = parseArgs(argv, BOOLEAN_FLAGS15);
18807
+ const { flags } = parseArgs(argv, BOOLEAN_FLAGS16);
18624
18808
  const r = reporterFor(flags);
18625
18809
  const root = process.cwd();
18626
18810
  const homes = detectAgents(root, { home: homedir2(), global: true });
@@ -18639,7 +18823,7 @@ Next: ${report.next_step}`
18639
18823
  return report.ok ? EXIT_OK : EXIT_NO_BROWSER;
18640
18824
  }
18641
18825
  async function cmdWhoami(argv) {
18642
- const { flags } = parseArgs(argv, BOOLEAN_FLAGS15);
18826
+ const { flags } = parseArgs(argv, BOOLEAN_FLAGS16);
18643
18827
  const r = reporterFor(flags);
18644
18828
  const origin = platformOrigin({
18645
18829
  origin: strFlag(flags, "origin"),
@@ -18734,7 +18918,7 @@ async function cmdWhoami(argv) {
18734
18918
  return EXIT_OK;
18735
18919
  }
18736
18920
  function cmdSwitch(argv) {
18737
- const { flags, positionals } = parseArgs(argv, BOOLEAN_FLAGS15);
18921
+ const { flags, positionals } = parseArgs(argv, BOOLEAN_FLAGS16);
18738
18922
  const r = reporterFor(flags);
18739
18923
  const origin = platformOrigin({
18740
18924
  origin: strFlag(flags, "origin"),
@@ -18838,7 +19022,7 @@ function cmdLogout(argv) {
18838
19022
  }
18839
19023
 
18840
19024
  // src/plugin/run.ts
18841
- var BOOLEAN_FLAGS16 = /* @__PURE__ */ new Set([
19025
+ var BOOLEAN_FLAGS17 = /* @__PURE__ */ new Set([
18842
19026
  "json",
18843
19027
  "help",
18844
19028
  "wait",
@@ -18881,6 +19065,8 @@ Take pipeline
18881
19065
  --reuse, recording again into a take that has a cut: the cut (kept as doc.prev.json) goes onto the new footage as vos plan --reuse does; without it the take is planned fresh and its last line says where the cut is
18882
19066
  vos record --hosted --actions actions.json [--url <url>] [--out take] [--title "\u2026"] [--folder <id>] [--header name=value]... [--json]
18883
19067
  the take recorded on vos.so's fleet (no browser here): lands as a private vos with its doc and digest, then fetched into --out with its media
19068
+ vos record --app <name|bundle id> [--out take] [--seconds <n>] [--max-duration <s>] [--background <slug|url|none>] [--json]
19069
+ a desktop app's window (macOS), performed by whoever is at the machine: you or your agent's computer use works the app, and the take has no system pointer in its pixels and the pointer's path beside it, planned like a page take; Ctrl-C ends it, or --seconds; --window <id> names one window, vos record --windows lists what can be recorded; needs Screen Recording for the app this runs from (vos doctor says)
18884
19070
  vos plan <take> [--fresh] [--reuse [--from <doc.json>]] [--style <doc.json|vosId>] [--with <doc.json|vosId>[@end|@start|@step:<id>|@<s>]]... [--background <slug|url|none>] [--motion] [--headline "\u2026"] [--kicker "\u2026"] [--launch LAUNCH.md] [--brand BRAND.md] [--music <slug|mood|none>] [--entrance tilt-in|pull-out|rise|fade|slide|none] [--transitions slide|fade|scale|none] [--end-card on|none|<doc.json|vosId>] [--captions|--captions none] [--clicks none] [--still <t>] [--release v2.1] [--zooms per-beat] [--json]
18885
19071
  --zooms per-beat keeps at most one zoom per beat: the beats are the captioned steps of actions.json (each runs until the next one starts, plus the opening before the first); a step marked "zoom": true in actions.json is its beat's payoff, and the beat keeps the proposal that overlaps it most (one per marked step, never two overlapping), promoted to manual; a beat with no marked step keeps no zoom; when no step of the take is marked, each beat's last click, drag, type or paste stands in (the opening keeps none) and the done line says so; a step marked "zoom": false is never zoomed on; the rest go into doc.rejected like a person deleting them, and a beat with a manual zoom keeps only its manual ones. A media with no captioned step keeps its zooms as planned, and the done line says so
18886
19072
  vos render <take> [out.webm] [--width] [--height] [--fps] [--format webm|mp4] [--parallel N] [--range a..b] [--draft] [--frame <kind>] [--background <url|slug>] [--set <path=value>]... [--json]
@@ -19252,7 +19438,7 @@ lint-gated, so a bad override fails like a bad doc.json):
19252
19438
  first ready loop (the house backdrop the studio opens on), or a flat ground offline
19253
19439
  `;
19254
19440
  async function loadActions(file) {
19255
- const raw = JSON.parse(await readFile19(file, "utf8"));
19441
+ const raw = JSON.parse(await readFile20(file, "utf8"));
19256
19442
  const errors = validateActions(raw);
19257
19443
  if (!errors.length) errors.push(...jsSyntaxProblems(raw));
19258
19444
  if (errors.length)
@@ -19418,8 +19604,8 @@ function takeBrowserArgs(multi) {
19418
19604
  function takeStorageState(flags) {
19419
19605
  const raw = strFlag(flags, "storage-state");
19420
19606
  if (!raw) return void 0;
19421
- const path = resolve22(raw);
19422
- if (!existsSync31(path))
19607
+ const path = resolve23(raw);
19608
+ if (!existsSync32(path))
19423
19609
  throw new UsageError(`--storage-state: no such file: ${path}`);
19424
19610
  return path;
19425
19611
  }
@@ -19432,7 +19618,7 @@ function takeSessionName(flags, storageState) {
19432
19618
  throw new UsageError(
19433
19619
  "--session and --storage-state are two doors to one take: a persistent profile cannot take a storage state. Pass one"
19434
19620
  );
19435
- if (!existsSync31(sessionDir(name)))
19621
+ if (!existsSync32(sessionDir(name)))
19436
19622
  throw new UsageError(
19437
19623
  `no session "${name}". Make one: vos session open <url> --name ${name} (a Chrome window opens; sign in and close it)`
19438
19624
  );
@@ -19450,21 +19636,21 @@ async function inSession(name, actions, fn) {
19450
19636
  }
19451
19637
  function reRecord(outDir, flags, r) {
19452
19638
  const wantsReuse = flags.reuse === true;
19453
- if (wantsReuse && !existsSync31(join33(outDir, "doc.json")))
19639
+ if (wantsReuse && !existsSync32(join34(outDir, "doc.json")))
19454
19640
  throw new UsageError(
19455
19641
  `--reuse: ${outDir} has no cut to keep (no doc.json); record without --reuse`
19456
19642
  );
19457
19643
  let previousCut = null;
19458
19644
  return {
19459
19645
  prepare: async () => {
19460
- if (existsSync31(join33(outDir, "meta.json"))) {
19646
+ if (existsSync32(join34(outDir, "meta.json"))) {
19461
19647
  const { prevDoc, kept } = await prepareReRecord(outDir);
19462
- if (prevDoc) previousCut = join33(outDir, PREV_DOC_NAME);
19648
+ if (prevDoc) previousCut = join34(outDir, PREV_DOC_NAME);
19463
19649
  r.log(
19464
19650
  `note: re-recording ${outDir} \u2014 kept ${kept.length ? kept.join(", ") : "nothing"}` + (prevDoc ? wantsReuse ? "; the previous cut goes onto the new footage when it is recorded (--reuse)" : `; the previous cut is ${PREV_DOC_NAME}` : "")
19465
19651
  );
19466
19652
  }
19467
- await mkdir13(outDir, { recursive: true });
19653
+ await mkdir14(outDir, { recursive: true });
19468
19654
  await ensureTakeDir(outDir);
19469
19655
  },
19470
19656
  plan: async (backdrop) => {
@@ -19474,7 +19660,7 @@ function reRecord(outDir, flags, r) {
19474
19660
  ...from ? {
19475
19661
  reuse: {
19476
19662
  from,
19477
- doc: JSON.parse(await readFile19(from, "utf8"))
19663
+ doc: JSON.parse(await readFile20(from, "utf8"))
19478
19664
  }
19479
19665
  } : {}
19480
19666
  });
@@ -19543,9 +19729,10 @@ function wallGate(flags, r, opts) {
19543
19729
  };
19544
19730
  }
19545
19731
  async function cmdRecord(argv) {
19732
+ if (isDesktopRecord(argv)) return cmdRecordApp(argv);
19546
19733
  const { positionals, flags, multi } = parseArgs(
19547
19734
  argv,
19548
- BOOLEAN_FLAGS16,
19735
+ BOOLEAN_FLAGS17,
19549
19736
  MULTI_FLAGS2
19550
19737
  );
19551
19738
  const actionsPath = strFlag(flags, "actions") ?? positionals[0];
@@ -19561,7 +19748,7 @@ async function cmdRecord(argv) {
19561
19748
  const scheme = urlSchemeProblem2(url);
19562
19749
  if (scheme) throw new UsageError(scheme);
19563
19750
  announceEnvNames(actions, r);
19564
- const outDir = resolve22(strFlag(flags, "out") ?? "take");
19751
+ const outDir = resolve23(strFlag(flags, "out") ?? "take");
19565
19752
  const storageState = takeStorageState(flags);
19566
19753
  const sessionName = takeSessionName(flags, storageState);
19567
19754
  const browserArgs = takeBrowserArgs(multi);
@@ -19581,7 +19768,7 @@ async function cmdRecord(argv) {
19581
19768
  );
19582
19769
  const hostedActions = await scriptForHost(
19583
19770
  actions,
19584
- dirname12(resolve22(actionsPath))
19771
+ dirname12(resolve23(actionsPath))
19585
19772
  ).catch((e) => {
19586
19773
  throw new UsageError(e instanceof Error ? e.message : String(e));
19587
19774
  });
@@ -19691,7 +19878,7 @@ async function cmdRecord(argv) {
19691
19878
  sessionName,
19692
19879
  actions,
19693
19880
  (context2) => recordTake(browser2, url, actions, takePaths(outDir), r.log, {
19694
- actionsDir: dirname12(resolve22(actionsPath)),
19881
+ actionsDir: dirname12(resolve23(actionsPath)),
19695
19882
  storageState,
19696
19883
  headers,
19697
19884
  context: context2,
@@ -19757,7 +19944,7 @@ async function cmdRecord(argv) {
19757
19944
  ...flags["allow-wall"] === true ? ["--allow-wall"] : [],
19758
19945
  ...confirm.map((c) => `--confirm ${c}`),
19759
19946
  // A take that already has a cut keeps it on the new footage.
19760
- ...existsSync31(join33(outDir, "doc.json")) ? ["--reuse"] : []
19947
+ ...existsSync32(join34(outDir, "doc.json")) ? ["--reuse"] : []
19761
19948
  ].join(" ");
19762
19949
  const nextOut = strFlag(flags, "out") ?? "take";
19763
19950
  const guardNote = !unconfirmed.ok ? unconfirmed.unconfirmed.length ? ` (it refuses until you add ${unconfirmed.unconfirmed.map((id) => `--confirm ${id}`).join(" ")}: ${unconfirmed.unconfirmed.length === 1 ? "that step spends" : "those steps spend"} something real)` : ` (${unconfirmed.unknown.map((c) => `--confirm ${c}`).join(", ")} names no guarded step)` : "";
@@ -19799,7 +19986,7 @@ ${lines.join("\n")}
19799
19986
  sessionName,
19800
19987
  actions,
19801
19988
  (context2) => recordTake(browser, url, actions, paths, r.log, {
19802
- actionsDir: dirname12(resolve22(actionsPath)),
19989
+ actionsDir: dirname12(resolve23(actionsPath)),
19803
19990
  maxDurationSeconds,
19804
19991
  storageState,
19805
19992
  headers,
@@ -19887,7 +20074,7 @@ ${lines.join("\n")}
19887
20074
  },
19888
20075
  strictFail ? `STRICT: take recorded but incomplete \u2014 ${strictReason(rec)}; fix the flow and re-record.${skippedNote}${stepNote}${navTimeoutNote(rec)}${kept.line}${exposureNote(rec)}${noticeNote(rec)}` : `Take ready: ${outDir}
19889
20076
  ${(rec.meta.durationMs / 1e3).toFixed(1)}s \xB7 ${rec.frames.length} frames \xB7 ${rec.events.length} cursor events \xB7 ${clicks} clicks \xB7 ${plan.doc.zoom.length} zoom spans planned \xB7 ${rec.freezePct}% frozen \xB7 ${rec.dead.pct}% dead${deadWarns(rec.dead) ? " \u26A0 " + deadLine(rec.dead) : ""}${skippedNote}${stepNote}${navTimeoutNote(rec)}${pageSoundNote(rec)}${kept.line}
19890
- Next: ${kept.next ? `${kept.next}, then` : `edit ${join33(outDir, "doc.json")} (optional), then:`} vos render ${outDir}${exposureNote(rec)}${noticeNote(rec)}${teardownNote(rec)}`
20077
+ Next: ${kept.next ? `${kept.next}, then` : `edit ${join34(outDir, "doc.json")} (optional), then:`} vos render ${outDir}${exposureNote(rec)}${noticeNote(rec)}${teardownNote(rec)}`
19891
20078
  );
19892
20079
  return strictFail ? EXIT_USAGE : EXIT_OK;
19893
20080
  } finally {
@@ -19897,7 +20084,7 @@ ${lines.join("\n")}
19897
20084
  async function cmdCreate2(argv) {
19898
20085
  const { positionals, flags, multi } = parseArgs(
19899
20086
  argv,
19900
- BOOLEAN_FLAGS16,
20087
+ BOOLEAN_FLAGS17,
19901
20088
  MULTI_FLAGS2
19902
20089
  );
19903
20090
  const actionsPath = strFlag(flags, "actions");
@@ -19914,9 +20101,9 @@ async function cmdCreate2(argv) {
19914
20101
  const scheme = urlSchemeProblem2(url);
19915
20102
  if (scheme) throw new UsageError(scheme);
19916
20103
  announceEnvNames(actions, r);
19917
- const outDir = resolve22(strFlag(flags, "out") ?? "take");
20104
+ const outDir = resolve23(strFlag(flags, "out") ?? "take");
19918
20105
  const format = videoFormat(strFlag(flags, "format"), positionals[0]);
19919
- const out = positionals[0] ?? join33(outDir, `out.${format}`);
20106
+ const out = positionals[0] ?? join34(outDir, `out.${format}`);
19920
20107
  const parallel = numFlag(flags, "parallel", 1);
19921
20108
  if (!Number.isInteger(parallel) || parallel < 1 || parallel > 16) {
19922
20109
  throw new UsageError("--parallel expects an integer between 1 and 16");
@@ -19938,7 +20125,7 @@ async function cmdCreate2(argv) {
19938
20125
  sessionName,
19939
20126
  actions,
19940
20127
  (context2) => recordTake(browser, url, actions, paths, r.log, {
19941
- actionsDir: dirname12(resolve22(actionsPath)),
20128
+ actionsDir: dirname12(resolve23(actionsPath)),
19942
20129
  maxDurationSeconds,
19943
20130
  storageState,
19944
20131
  headers,
@@ -20055,7 +20242,7 @@ async function cmdPlan(argvIn) {
20055
20242
  const argv = bareCaptionsFlag(argvIn);
20056
20243
  const { positionals, flags, multi } = parseArgs(
20057
20244
  argv,
20058
- BOOLEAN_FLAGS16,
20245
+ BOOLEAN_FLAGS17,
20059
20246
  /* @__PURE__ */ new Set(["with"])
20060
20247
  );
20061
20248
  const dir = positionals[0];
@@ -20065,24 +20252,24 @@ async function cmdPlan(argvIn) {
20065
20252
  );
20066
20253
  const r = createReporter(flags.json === true);
20067
20254
  if (flags.fresh === true) {
20068
- await rm7(join33(dir, "doc.json"), { force: true });
20255
+ await rm7(join34(dir, "doc.json"), { force: true });
20069
20256
  r.log("note: --fresh discarded the existing doc.json");
20070
20257
  }
20071
20258
  let reuse;
20072
20259
  if (flags.reuse === true) {
20073
- const from = resolve22(strFlag(flags, "from") ?? join33(dir, PREV_DOC_NAME));
20074
- if (!existsSync31(from)) {
20260
+ const from = resolve23(strFlag(flags, "from") ?? join34(dir, PREV_DOC_NAME));
20261
+ if (!existsSync32(from)) {
20075
20262
  throw new UsageError(
20076
20263
  `--reuse: ${from} does not exist \u2014 a re-record into this take writes doc.prev.json, or pass --from <doc.json>`
20077
20264
  );
20078
20265
  }
20079
20266
  reuse = {
20080
20267
  from,
20081
- doc: JSON.parse(await readFile19(from, "utf8"))
20268
+ doc: JSON.parse(await readFile20(from, "utf8"))
20082
20269
  };
20083
20270
  }
20084
20271
  const style = await resolveStyleRef(flags);
20085
- const hasDoc = existsSync31(join33(dir, "doc.json"));
20272
+ const hasDoc = existsSync32(join34(dir, "doc.json"));
20086
20273
  const backdrop = hasDoc ? null : await takeBackdrop(flags, r);
20087
20274
  const release = await releaseInputs(dir, flags, r, multi.with ?? []);
20088
20275
  const stepCaptions = strFlag(flags, "captions") === "steps";
@@ -20162,7 +20349,7 @@ async function cmdPlan(argvIn) {
20162
20349
  ${s.reuse.flagged.join("\n ")}` : "") : "";
20163
20350
  r.done(
20164
20351
  {
20165
- take: resolve22(dir),
20352
+ take: resolve23(dir),
20166
20353
  fresh: s.fresh,
20167
20354
  cursorKept: s.cursorKept,
20168
20355
  zoomAuto,
@@ -20176,7 +20363,7 @@ async function cmdPlan(argvIn) {
20176
20363
  ...captions ? { captions } : {},
20177
20364
  ...perBeat ? { perBeat } : {}
20178
20365
  },
20179
- `${s.reuse ? "Reused" : s.fresh ? "Planned" : "Refreshed"} ${join33(dir, "doc.json")}: ${zoomAuto} auto + ${zoomManual} manual zoom spans${s.cursorKept ? "" : " (cursor track dropped)"}${layoutLines}${motionLines}${reuseLines}${captionLines}${marksLine ? `
20366
+ `${s.reuse ? "Reused" : s.fresh ? "Planned" : "Refreshed"} ${join34(dir, "doc.json")}: ${zoomAuto} auto + ${zoomManual} manual zoom spans${s.cursorKept ? "" : " (cursor track dropped)"}${layoutLines}${motionLines}${reuseLines}${captionLines}${marksLine ? `
20180
20367
  ${marksLine}` : ""}${perBeat ? `
20181
20368
  ${perBeatLine(perBeat)}` : ""}`
20182
20369
  );
@@ -20291,7 +20478,7 @@ async function releaseInputs(dir, flags, r, withRefs = []) {
20291
20478
  async function cmdRender(argv) {
20292
20479
  const { positionals, flags, multi } = parseArgs(
20293
20480
  argv,
20294
- BOOLEAN_FLAGS16,
20481
+ BOOLEAN_FLAGS17,
20295
20482
  MULTI_FLAGS2
20296
20483
  );
20297
20484
  const dir = positionals[0];
@@ -20301,7 +20488,7 @@ async function cmdRender(argv) {
20301
20488
  );
20302
20489
  const r = createReporter(flags.json === true);
20303
20490
  const format = videoFormat(strFlag(flags, "format"), positionals[1]);
20304
- const out = positionals[1] ?? join33(dir, `out.${format}`);
20491
+ const out = positionals[1] ?? join34(dir, `out.${format}`);
20305
20492
  const parallel = numFlag(flags, "parallel", 1);
20306
20493
  if (!Number.isInteger(parallel) || parallel < 1 || parallel > 16) {
20307
20494
  throw new UsageError("--parallel expects an integer between 1 and 16");
@@ -20359,7 +20546,7 @@ async function cmdRender(argv) {
20359
20546
  async function cmdFrames(argv) {
20360
20547
  const { positionals, flags, multi } = parseArgs(
20361
20548
  argv,
20362
- BOOLEAN_FLAGS16,
20549
+ BOOLEAN_FLAGS17,
20363
20550
  MULTI_FLAGS2
20364
20551
  );
20365
20552
  const dir = positionals[0];
@@ -20442,7 +20629,7 @@ async function cmdFrames(argv) {
20442
20629
  async function cmdDeliver(argv) {
20443
20630
  const { positionals, flags, multi } = parseArgs(
20444
20631
  argv,
20445
- BOOLEAN_FLAGS16,
20632
+ BOOLEAN_FLAGS17,
20446
20633
  MULTI_FLAGS2
20447
20634
  );
20448
20635
  const dir = positionals[0];
@@ -20542,15 +20729,15 @@ async function resolveStyleRef(flags) {
20542
20729
  }
20543
20730
  async function resolveDocRef(ref, flags, what) {
20544
20731
  const styleRef = ref;
20545
- const file = existsSync31(styleRef) ? resolve22(
20732
+ const file = existsSync32(styleRef) ? resolve23(
20546
20733
  styleRef,
20547
- existsSync31(join33(styleRef, "doc.json")) ? "doc.json" : ""
20734
+ existsSync32(join34(styleRef, "doc.json")) ? "doc.json" : ""
20548
20735
  ) : null;
20549
- if (file && existsSync31(file)) {
20736
+ if (file && existsSync32(file)) {
20550
20737
  return {
20551
20738
  from: file,
20552
20739
  doc: migrateHostedDoc4(
20553
- JSON.parse(await readFile19(file, "utf8"))
20740
+ JSON.parse(await readFile20(file, "utf8"))
20554
20741
  )
20555
20742
  };
20556
20743
  }
@@ -20592,7 +20779,7 @@ async function officialTemplate(origin, ref) {
20592
20779
  }
20593
20780
  }
20594
20781
  async function cmdDigest(argv) {
20595
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS16);
20782
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS17);
20596
20783
  const dir = positionals[0];
20597
20784
  if (!dir)
20598
20785
  throw new UsageError(
@@ -20602,7 +20789,7 @@ async function cmdDigest(argv) {
20602
20789
  const take = await loadTake(dir);
20603
20790
  if (!take.doc) throw new UsageError(`${dir} has no doc.json \u2014 run plan first`);
20604
20791
  const transcriptPath = strFlag(flags, "transcript");
20605
- const transcript = transcriptPath ? parseTranscript(JSON.parse(await readFile19(transcriptPath, "utf8"))) : null;
20792
+ const transcript = transcriptPath ? parseTranscript(JSON.parse(await readFile20(transcriptPath, "utf8"))) : null;
20606
20793
  const style = await resolveStyleRef(flags);
20607
20794
  const noFrames = flags["no-frames"] === true;
20608
20795
  let browser = null;
@@ -20633,7 +20820,7 @@ async function cmdDigest(argv) {
20633
20820
  kinds,
20634
20821
  frames: d.images.full,
20635
20822
  crops: d.images.crop,
20636
- sheet: d.images.sheet ? join33(result.outDir, d.images.sheet) : null,
20823
+ sheet: d.images.sheet ? join34(result.outDir, d.images.sheet) : null,
20637
20824
  scenes: kinds.scene ?? 0,
20638
20825
  sourceDuration: d.take.sourceDuration,
20639
20826
  outputDuration: d.take.outputDuration,
@@ -20656,19 +20843,19 @@ async function cmdDigest(argv) {
20656
20843
  }
20657
20844
  }
20658
20845
  async function cmdOpen(argv) {
20659
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS16);
20846
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS17);
20660
20847
  const dir = positionals[0];
20661
20848
  if (!dir) throw new UsageError("vos open <take> [--studio <url>]");
20662
20849
  const r = createReporter(flags.json === true);
20663
20850
  const take = await loadTake(dir);
20664
- if (!existsSync31(take.paths.recording)) {
20851
+ if (!existsSync32(take.paths.recording)) {
20665
20852
  throw new UsageError(`${dir} has no recording \u2014 re-run record`);
20666
20853
  }
20667
20854
  const studio = (strFlag(flags, "studio") ?? platformOrigin()).replace(
20668
20855
  /\/+$/,
20669
20856
  ""
20670
20857
  );
20671
- const server = await startTakeServer(resolve22(dir), {});
20858
+ const server = await startTakeServer(resolve23(dir), {});
20672
20859
  const url = `${studio}/studio?take=${encodeURIComponent(server.base)}`;
20673
20860
  r.event({ event: "open", server: server.base, url });
20674
20861
  r.log(`take served at ${server.base}`);
@@ -20691,7 +20878,7 @@ async function cmdOpen(argv) {
20691
20878
  return EXIT_OK;
20692
20879
  }
20693
20880
  async function cmdCallout(argv) {
20694
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS16);
20881
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS17);
20695
20882
  const dir = positionals[0];
20696
20883
  const shape = positionals[1];
20697
20884
  if (!dir || !shape || !isCalloutShape(shape))
@@ -20715,7 +20902,7 @@ async function cmdCallout(argv) {
20715
20902
  `no register: put a BRAND.md beside the take (vos brand <url> --out BRAND.md; its bgA and accent are the ground and the accent), or pass --ground #hex --accent #hex`
20716
20903
  );
20717
20904
  const codeFile = strFlag(flags, "code-file");
20718
- const code = codeFile ? await readFile19(codeFile, "utf8") : strFlag(flags, "code");
20905
+ const code = codeFile ? await readFile20(codeFile, "utf8") : strFlag(flags, "code");
20719
20906
  const words2 = {
20720
20907
  kicker: strFlag(flags, "kicker"),
20721
20908
  title: strFlag(flags, "title"),
@@ -20790,11 +20977,11 @@ async function cmdCallout(argv) {
20790
20977
  return EXIT_OK;
20791
20978
  }
20792
20979
  async function cmdValidate(argv) {
20793
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS16);
20980
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS17);
20794
20981
  const target = positionals[0];
20795
20982
  if (!target) throw new UsageError("vos validate <actions.json|take>");
20796
20983
  const r = createReporter(flags.json === true);
20797
- const kitTarget = target.endsWith("kit.json") ? target : existsSync31(join33(target, "kit.json")) && !isTakeDir(target) ? join33(target, "kit.json") : null;
20984
+ const kitTarget = target.endsWith("kit.json") ? target : existsSync32(join34(target, "kit.json")) && !isTakeDir(target) ? join34(target, "kit.json") : null;
20798
20985
  if (kitTarget) {
20799
20986
  const picture = flags.picture === true;
20800
20987
  const verdict = await validateKit(kitTarget, { picture });
@@ -20826,9 +21013,9 @@ async function cmdValidate(argv) {
20826
21013
  r.done({ valid: true, target }, `${target}: valid actions file`);
20827
21014
  return EXIT_OK;
20828
21015
  }
20829
- if (!isTakeDir(target) && existsSync31(join33(target, "config.json"))) {
21016
+ if (!isTakeDir(target) && existsSync32(join34(target, "config.json"))) {
20830
21017
  const parsed = JSON.parse(
20831
- await readFile19(join33(target, "config.json"), "utf8")
21018
+ await readFile20(join34(target, "config.json"), "utf8")
20832
21019
  );
20833
21020
  const pre = preflightConfig(parsed);
20834
21021
  const problems2 = pre.ok ? [] : pre.issues.map((i) => `config.json: ${i}`);
@@ -20870,7 +21057,7 @@ async function cmdValidate(argv) {
20870
21057
  const problems = [];
20871
21058
  const warnings = [];
20872
21059
  const notes = [];
20873
- if (!existsSync31(take.paths.recording)) {
21060
+ if (!existsSync32(take.paths.recording)) {
20874
21061
  problems.push("missing recording (re-run record)");
20875
21062
  } else {
20876
21063
  const mismatch = containerMismatch(
@@ -20911,7 +21098,7 @@ async function cmdValidate(argv) {
20911
21098
  const found = localFile(rel, target);
20912
21099
  if (!("refused" in found)) continue;
20913
21100
  problems.push(
20914
- existsSync31(resolve22(target, rel)) ? `doc.json: ${ref.where}: ${ref.key} ${found.refused}` : `doc.json: ${ref.where}: ${ref.key} is not a file in the take, so a render plays the film without it (put the file there, or fix the key)`
21101
+ existsSync32(resolve23(target, rel)) ? `doc.json: ${ref.where}: ${ref.key} ${found.refused}` : `doc.json: ${ref.where}: ${ref.key} is not a file in the take, so a render plays the film without it (put the file there, or fix the key)`
20915
21102
  );
20916
21103
  }
20917
21104
  if (flags.picture === true && (take.doc.overlays ?? []).some((o) => o.kind === "html")) {
@@ -20980,7 +21167,7 @@ async function cmdValidate(argv) {
20980
21167
  async function cmdPush3(argv) {
20981
21168
  const { positionals, flags, multi } = parseArgs(
20982
21169
  argv,
20983
- BOOLEAN_FLAGS16,
21170
+ BOOLEAN_FLAGS17,
20984
21171
  MULTI_FLAGS2
20985
21172
  );
20986
21173
  const dir = positionals[0];
@@ -20990,7 +21177,7 @@ async function cmdPush3(argv) {
20990
21177
  );
20991
21178
  const refusal = takePushRefusal({
20992
21179
  vos: strFlag(flags, "vos"),
20993
- trackedVosId: readSyncState(resolve22(dir))?.vosId ?? null,
21180
+ trackedVosId: readSyncState(resolve23(dir))?.vosId ?? null,
20994
21181
  programOnly: ["slug", "tags", "base", "remix-of", "still"].filter(
20995
21182
  (name) => hasFlag(flags, name)
20996
21183
  )
@@ -21009,7 +21196,7 @@ async function cmdPush3(argv) {
21009
21196
  `--claimable creates a NEW claimable vos; ${iterating.map((f) => `--${f}`).join(", ")} ${iterating.length > 1 ? "apply" : "applies"} to a keyed push`
21010
21197
  );
21011
21198
  const claim = await pushTakeClaimable(
21012
- resolve22(dir),
21199
+ resolve23(dir),
21013
21200
  {
21014
21201
  api: strFlag(flags, "api"),
21015
21202
  origin: strFlag(flags, "origin"),
@@ -21033,7 +21220,7 @@ reference and the only credential.`
21033
21220
  }
21034
21221
  const overrides = multi.override;
21035
21222
  const result = await pushTake(
21036
- resolve22(dir),
21223
+ resolve23(dir),
21037
21224
  {
21038
21225
  key: strFlag(flags, "key"),
21039
21226
  api: strFlag(flags, "api"),
@@ -21085,11 +21272,11 @@ ${landedLines(landed)}` : "")
21085
21272
  return EXIT_OK;
21086
21273
  }
21087
21274
  async function cmdPull2(argv) {
21088
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS16, MULTI_FLAGS2);
21275
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS17, MULTI_FLAGS2);
21089
21276
  const dir = positionals[0] ?? ".";
21090
21277
  const r = createReporter(flags.json === true);
21091
21278
  const result = await pullTake(
21092
- resolve22(dir),
21279
+ resolve23(dir),
21093
21280
  {
21094
21281
  key: strFlag(flags, "key"),
21095
21282
  api: strFlag(flags, "api"),
@@ -21270,7 +21457,7 @@ function verdictExit(v, strict, none) {
21270
21457
  async function cmdSession(argv) {
21271
21458
  const { positionals, flags } = parseArgs(
21272
21459
  argv,
21273
- /* @__PURE__ */ new Set([...BOOLEAN_FLAGS16, "headed"])
21460
+ /* @__PURE__ */ new Set([...BOOLEAN_FLAGS17, "headed"])
21274
21461
  );
21275
21462
  const [sub, arg] = positionals;
21276
21463
  const r = createReporter(flags.json === true);
@@ -21315,7 +21502,7 @@ async function cmdSession(argv) {
21315
21502
  if (!arg) throw new UsageError(usage);
21316
21503
  const bad = sessionNameVerdict(arg);
21317
21504
  if (bad) throw new UsageError(bad);
21318
- if (!existsSync31(sessionDir(arg)))
21505
+ if (!existsSync32(sessionDir(arg)))
21319
21506
  throw new UsageError(`no session "${arg}" (vos session list)`);
21320
21507
  const summary3 = await summarizeSession(arg);
21321
21508
  const url = strFlag(flags, "url");
@@ -21349,7 +21536,7 @@ async function cmdSession(argv) {
21349
21536
  if (!arg || !scriptPath) throw new UsageError(usage);
21350
21537
  const bad = sessionNameVerdict(arg);
21351
21538
  if (bad) throw new UsageError(bad);
21352
- if (!existsSync31(sessionDir(arg)))
21539
+ if (!existsSync32(sessionDir(arg)))
21353
21540
  throw new UsageError(`no session "${arg}" (vos session list)`);
21354
21541
  const url = strFlag(flags, "url");
21355
21542
  if (url && !/^https?:\/\//.test(url))
@@ -21434,6 +21621,7 @@ export {
21434
21621
  convertAgentBrowser,
21435
21622
  MULTI_FLAGS2 as MULTI_FLAGS,
21436
21623
  HELP,
21624
+ maxDuration,
21437
21625
  strictFails,
21438
21626
  takeBrowserArgs,
21439
21627
  reRecord,
@@ -21442,4 +21630,4 @@ export {
21442
21630
  verbHelp,
21443
21631
  run
21444
21632
  };
21445
- //# sourceMappingURL=chunk-ACWV3Y6Y.js.map
21633
+ //# sourceMappingURL=chunk-BHWDA2KG.js.map