@vosjs/cli 0.49.0 → 0.50.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.
@@ -12,9 +12,9 @@ import {
12
12
  } from "./chunk-72ADTMWW.js";
13
13
 
14
14
  // src/plugin/run.ts
15
- import { mkdir as mkdir10, readFile as readFile15, rm as rm5 } from "fs/promises";
16
- import { existsSync as existsSync18 } from "fs";
17
- import { join as join21, resolve as resolve9 } from "path";
15
+ import { mkdir as mkdir11, readFile as readFile16, rm as rm5 } from "fs/promises";
16
+ import { existsSync as existsSync19 } from "fs";
17
+ import { join as join22, resolve as resolve10 } from "path";
18
18
  import {
19
19
  END_CARD_FROM as END_CARD_FROM2,
20
20
  docOutputDuration as docOutputDuration3,
@@ -2213,10 +2213,10 @@ function startTakeServer(rootDir, pages) {
2213
2213
  res.writeHead(404).end();
2214
2214
  });
2215
2215
  return new Promise(
2216
- (resolve10) => server.listen(0, () => {
2216
+ (resolve11) => server.listen(0, () => {
2217
2217
  const addr = server.address();
2218
2218
  const port = typeof addr === "object" && addr ? addr.port : 0;
2219
- resolve10({ base: `http://localhost:${port}`, close: () => server.close() });
2219
+ resolve11({ base: `http://localhost:${port}`, close: () => server.close() });
2220
2220
  })
2221
2221
  );
2222
2222
  }
@@ -6554,10 +6554,10 @@ async function openSession(name, url, opts = { log: () => {
6554
6554
  opts.log(
6555
6555
  `a Chrome window opened on session "${name}": sign in to ${new URL(url).host}, ${leave}`
6556
6556
  );
6557
- return new Promise((resolve10, reject) => {
6557
+ return new Promise((resolve11, reject) => {
6558
6558
  const child = spawn(exe, args, { stdio: "ignore" });
6559
6559
  child.on("error", reject);
6560
- child.on("exit", (code) => resolve10({ code }));
6560
+ child.on("exit", (code) => resolve11({ code }));
6561
6561
  });
6562
6562
  }
6563
6563
  async function withSession(name, fn, opts = {}) {
@@ -9890,8 +9890,8 @@ async function cmdActions(argv) {
9890
9890
  if (!m) throw new UsageError("--viewport expects WxH, e.g. 1280x720");
9891
9891
  viewport = { width: Number(m[1]), height: Number(m[2]) };
9892
9892
  }
9893
- const { readFile: readFile16 } = await import("fs/promises");
9894
- const text = await readFile16(resolve8(input), "utf8");
9893
+ const { readFile: readFile17 } = await import("fs/promises");
9894
+ const text = await readFile17(resolve8(input), "utf8");
9895
9895
  const { records, problems } = parseAgentBrowserLog(text);
9896
9896
  for (const p of problems) r.log(` ${p}`);
9897
9897
  const result = convertAgentBrowser(records, {
@@ -9928,9 +9928,9 @@ function summary(result) {
9928
9928
  }
9929
9929
  async function cmdActionsScript(input, flags) {
9930
9930
  const r = createReporter(flags.json === true);
9931
- const { readFile: readFile16 } = await import("fs/promises");
9931
+ const { readFile: readFile17 } = await import("fs/promises");
9932
9932
  const { shotList, formatShotList } = await import("./shotList-IYFDHSIK.js");
9933
- const raw = JSON.parse(await readFile16(resolve8(input), "utf8"));
9933
+ const raw = JSON.parse(await readFile17(resolve8(input), "utf8"));
9934
9934
  const errors = validateActions(raw);
9935
9935
  if (errors.length) throw new UsageError(`${input}:
9936
9936
  ${errors.join("\n ")}`);
@@ -9939,23 +9939,232 @@ async function cmdActionsScript(input, flags) {
9939
9939
  return EXIT_OK;
9940
9940
  }
9941
9941
 
9942
+ // src/plugin/ingest.ts
9943
+ import { existsSync as existsSync16 } from "fs";
9944
+ import { copyFile, mkdir as mkdir10, readFile as readFile15, stat as stat4 } from "fs/promises";
9945
+ import { basename as basename7, join as join19, resolve as resolve9 } from "path";
9946
+ import { inflateRawSync } from "zlib";
9947
+ import {
9948
+ cursorFromPlaywrightTrace,
9949
+ cursorFromTrace,
9950
+ playwrightTraceEntry,
9951
+ traceKindOf,
9952
+ zipEntries,
9953
+ zipEntryBytes
9954
+ } from "@vosjs/studio-core";
9955
+ import {
9956
+ ALL_FORMATS,
9957
+ Conversion,
9958
+ FilePathSource,
9959
+ FilePathTarget,
9960
+ Input,
9961
+ Mp4OutputFormat,
9962
+ Output,
9963
+ WebMOutputFormat
9964
+ } from "mediabunny";
9965
+ var BOOLEAN_FLAGS5 = /* @__PURE__ */ new Set(["json", "help"]);
9966
+ async function probeVideoFile(path) {
9967
+ const input = new Input({
9968
+ source: new FilePathSource(path),
9969
+ formats: ALL_FORMATS
9970
+ });
9971
+ try {
9972
+ const format = await input.getFormat();
9973
+ const video = await input.getPrimaryVideoTrack();
9974
+ if (!video) throw new UsageError(`${path} has no video track`);
9975
+ const [duration, stats, audio] = await Promise.all([
9976
+ input.computeDuration(),
9977
+ video.computePacketStats(240),
9978
+ input.getPrimaryAudioTrack()
9979
+ ]);
9980
+ const mimeType = format.mimeType;
9981
+ const ext = mimeType.includes("mp4") ? "mp4" : mimeType.includes("quicktime") ? "mov" : "webm";
9982
+ return {
9983
+ width: video.displayWidth,
9984
+ height: video.displayHeight,
9985
+ durationMs: Math.round(duration * 1e3),
9986
+ fps: Math.round(stats.averagePacketRate * 100) / 100,
9987
+ hasAudio: !!audio,
9988
+ mimeType,
9989
+ ext
9990
+ };
9991
+ } finally {
9992
+ await input.dispose?.();
9993
+ }
9994
+ }
9995
+ async function copyRecording(src, dest, ext) {
9996
+ if (ext === "mov") {
9997
+ await copyFile(src, dest);
9998
+ return false;
9999
+ }
10000
+ const input = new Input({
10001
+ source: new FilePathSource(src),
10002
+ formats: ALL_FORMATS
10003
+ });
10004
+ const target = new FilePathTarget(dest);
10005
+ const output = new Output({
10006
+ format: ext === "mp4" ? new Mp4OutputFormat({ fastStart: "in-memory" }) : new WebMOutputFormat(),
10007
+ target
10008
+ });
10009
+ try {
10010
+ const conversion = await Conversion.init({ input, output });
10011
+ if (!conversion.isValid || conversion.discardedTracks.length > 0) {
10012
+ await conversion.cancel?.();
10013
+ await copyFile(src, dest);
10014
+ return false;
10015
+ }
10016
+ await conversion.execute();
10017
+ return true;
10018
+ } catch {
10019
+ await copyFile(src, dest);
10020
+ return false;
10021
+ } finally {
10022
+ await input.dispose?.();
10023
+ }
10024
+ }
10025
+ async function readTraceFile(path, offsetMs) {
10026
+ const kind = traceKindOf(basename7(path));
10027
+ if (!kind) {
10028
+ throw new UsageError(
10029
+ `${path}: not a trace the recorder reads (trace.zip, .trace, .jsonl, .json or .csv)`
10030
+ );
10031
+ }
10032
+ if (kind === "zip") {
10033
+ const bytes = new Uint8Array(await readFile15(path));
10034
+ const entry = playwrightTraceEntry(zipEntries(bytes));
10035
+ if (!entry) {
10036
+ throw new UsageError(
10037
+ `${path}: no trace.trace inside; a Playwright trace.zip is what --cursor reads as a zip`
10038
+ );
10039
+ }
10040
+ const raw = zipEntryBytes(bytes, entry);
10041
+ const text2 = new TextDecoder().decode(
10042
+ entry.method === 8 ? new Uint8Array(inflateRawSync(raw)) : raw
10043
+ );
10044
+ return cursorFromPlaywrightTrace(text2, { offsetMs });
10045
+ }
10046
+ const text = await readFile15(path, "utf8");
10047
+ return cursorFromTrace(basename7(path), text, { offsetMs });
10048
+ }
10049
+ function parseViewport(v) {
10050
+ if (!v) return null;
10051
+ const m = /^(\d+)x(\d+)$/i.exec(v.trim());
10052
+ if (!m) throw new UsageError("--viewport expects WxH, like 1280x720");
10053
+ return { width: Number(m[1]), height: Number(m[2]) };
10054
+ }
10055
+ async function cmdIngest(argv) {
10056
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS5, MULTI_FLAGS2);
10057
+ const source = positionals[0];
10058
+ if (!source)
10059
+ throw new UsageError(
10060
+ "vos ingest <video.webm|mp4> [--cursor <trace.zip|steps.jsonl|cursor.csv>] [--out take] [--offset <ms>] [--viewport WxH] [--background <slug|url|none>] [--json]"
10061
+ );
10062
+ const videoPath = resolve9(source);
10063
+ if (!existsSync16(videoPath)) throw new UsageError(`${source}: no such file`);
10064
+ const r = createReporter(flags.json === true);
10065
+ const outDir = resolve9(strFlag(flags, "out") ?? "take");
10066
+ const offsetMs = numFlag(flags, "offset", 0);
10067
+ const viewportFlag = parseViewport(strFlag(flags, "viewport"));
10068
+ const cursorPath = strFlag(flags, "cursor");
10069
+ const backdrop = await takeBackdrop(flags, r);
10070
+ r.log(`probing ${basename7(videoPath)}\u2026`);
10071
+ const probed = await probeVideoFile(videoPath);
10072
+ if (!(probed.durationMs > 0)) {
10073
+ throw new UsageError(
10074
+ `${source}: the file reports no duration; a stream-shaped recording needs its container fixed first (ffmpeg -i in.webm -c copy out.webm)`
10075
+ );
10076
+ }
10077
+ let trace = null;
10078
+ if (cursorPath) {
10079
+ trace = await readTraceFile(resolve9(cursorPath), offsetMs);
10080
+ for (const n of trace.notes) r.log(`note: ${n}`);
10081
+ }
10082
+ if (existsSync16(join19(outDir, "meta.json"))) {
10083
+ const { prevDoc, kept } = await prepareReRecord(outDir);
10084
+ r.log(
10085
+ `note: re-ingesting into ${outDir}; kept ${kept.length ? kept.join(", ") : "nothing"}` + (prevDoc ? `; apply the previous cut with: vos plan ${outDir} --reuse` : "")
10086
+ );
10087
+ }
10088
+ await mkdir10(outDir, { recursive: true });
10089
+ const paths = await ensureTakeDir(outDir);
10090
+ const recording = join19(outDir, `recording.${probed.ext}`);
10091
+ r.log("copying the recording\u2026");
10092
+ const remuxed = await copyRecording(videoPath, recording, probed.ext);
10093
+ const viewport = viewportFlag ?? trace?.viewport ?? {
10094
+ width: probed.width,
10095
+ height: probed.height
10096
+ };
10097
+ const events = trace?.events ?? [];
10098
+ const fileStat = await stat4(videoPath);
10099
+ const meta = {
10100
+ dpr: 1,
10101
+ zoom: 1,
10102
+ t0: trace?.t0 ?? Math.round(fileStat.mtimeMs),
10103
+ durationMs: probed.durationMs,
10104
+ width: viewport.width,
10105
+ height: viewport.height,
10106
+ captureWidth: probed.width,
10107
+ captureHeight: probed.height,
10108
+ fps: probed.fps > 0 ? probed.fps : 30,
10109
+ hasAudio: probed.hasAudio,
10110
+ producer: "ingest",
10111
+ ...events.length ? { captureSurface: "tab" } : {}
10112
+ };
10113
+ await writeJson(paths.meta, meta, true);
10114
+ if (events.length) await writeJson(paths.cursor, events);
10115
+ const plan = await planTake(outDir, { backdrop });
10116
+ const clicks = events.filter((e) => e.type === "down").length;
10117
+ const seconds = (probed.durationMs / 1e3).toFixed(1);
10118
+ const facts = `${seconds}s, ${probed.width}\xD7${probed.height} @ ${meta.fps} fps${probed.hasAudio ? ", audio" : ", no audio"}${remuxed ? "" : ", copied as is"}`;
10119
+ const cursorLine = trace ? `${events.length} cursor events (${clicks} clicks) from ${basename7(cursorPath)}${trace.dropped ? `, ${trace.dropped} not placed` : ""}; ${plan.zoomAuto} zoom${plan.zoomAuto === 1 ? "" : "s"} planned` : "no cursor track, so nothing was planned";
10120
+ const next = trace ? `Next: vos digest ${outDir} \u2014 look before you cut; edit doc.json; vos push ${outDir}` : `Add --cursor <trace> recorded beside the video (a Playwright trace.zip, stamped JSON records, or a t,x,y,type CSV) to plan zooms from its clicks; else place them by eye: vos frames ${outDir} --times 0,25%,50%,75%,100%, then edit doc.json`;
10121
+ r.done(
10122
+ {
10123
+ out: outDir,
10124
+ recording: basename7(recording),
10125
+ durationMs: probed.durationMs,
10126
+ width: probed.width,
10127
+ height: probed.height,
10128
+ viewport,
10129
+ fps: meta.fps,
10130
+ hasAudio: probed.hasAudio,
10131
+ remuxed,
10132
+ cursor: trace ? {
10133
+ file: basename7(cursorPath),
10134
+ kind: trace.kind,
10135
+ events: events.length,
10136
+ clicks,
10137
+ placed: trace.placed,
10138
+ dropped: trace.dropped,
10139
+ notes: trace.notes
10140
+ } : null,
10141
+ zooms: plan.zoomAuto,
10142
+ backdrop: plan.backdrop ?? null
10143
+ },
10144
+ `Ingested ${basename7(videoPath)} \u2192 ${outDir}/${basename7(recording)} (${facts})
10145
+ ${cursorLine}
10146
+ ${next}`
10147
+ );
10148
+ return EXIT_OK;
10149
+ }
10150
+
9942
10151
  // src/plugin/machineCmd.ts
9943
10152
  import { spawnSync } from "child_process";
9944
10153
  import {
9945
10154
  cpSync,
9946
- existsSync as existsSync17,
10155
+ existsSync as existsSync18,
9947
10156
  mkdirSync as mkdirSync3,
9948
10157
  readFileSync as readFileSync7,
9949
10158
  rmSync as rmSync2,
9950
10159
  writeFileSync as writeFileSync3
9951
10160
  } from "fs";
9952
10161
  import { homedir as homedir3 } from "os";
9953
- import { join as join20 } from "path";
10162
+ import { join as join21 } from "path";
9954
10163
  import { chromium as chromium2 } from "playwright";
9955
10164
 
9956
10165
  // src/plugin/machine.ts
9957
- import { existsSync as existsSync16, readFileSync as readFileSync6, readdirSync as readdirSync4, statSync as statSync4 } from "fs";
9958
- import { dirname as dirname5, join as join19 } from "path";
10166
+ import { existsSync as existsSync17, readFileSync as readFileSync6, readdirSync as readdirSync4, statSync as statSync4 } from "fs";
10167
+ import { dirname as dirname5, join as join20 } from "path";
9959
10168
  var AGENT_NAMES = [
9960
10169
  "claude",
9961
10170
  "cursor",
@@ -9975,17 +10184,17 @@ var HOME_DIRS = {
9975
10184
  copilot: [".copilot"]
9976
10185
  };
9977
10186
  function detectAgents(root, opts = {}) {
9978
- const exists = opts.exists ?? existsSync16;
10187
+ const exists = opts.exists ?? existsSync17;
9979
10188
  const out = [];
9980
10189
  for (const agent of AGENT_NAMES) {
9981
10190
  for (const rel of PROJECT_DIRS[agent]) {
9982
- const dir = join19(root, rel);
10191
+ const dir = join20(root, rel);
9983
10192
  if (exists(dir)) out.push({ agent, dir, scope: "project" });
9984
10193
  }
9985
- if (agent === "copilot" && !out.some((h) => h.agent === "copilot") && exists(join19(root, ".github", "copilot-instructions.md"))) {
10194
+ if (agent === "copilot" && !out.some((h) => h.agent === "copilot") && exists(join20(root, ".github", "copilot-instructions.md"))) {
9986
10195
  out.push({
9987
10196
  agent,
9988
- dir: join19(root, ".github", "copilot"),
10197
+ dir: join20(root, ".github", "copilot"),
9989
10198
  scope: "project"
9990
10199
  });
9991
10200
  }
@@ -9993,7 +10202,7 @@ function detectAgents(root, opts = {}) {
9993
10202
  if (opts.global && opts.home) {
9994
10203
  for (const agent of AGENT_NAMES) {
9995
10204
  for (const rel of HOME_DIRS[agent]) {
9996
- const dir = join19(opts.home, rel);
10205
+ const dir = join20(opts.home, rel);
9997
10206
  if (exists(dir)) out.push({ agent, dir, scope: "global" });
9998
10207
  }
9999
10208
  }
@@ -10011,18 +10220,18 @@ function agentsFromFlag(value, root) {
10011
10220
  return {
10012
10221
  homes: wanted.map((agent) => ({
10013
10222
  agent,
10014
- dir: join19(root, PROJECT_DIRS[agent][0]),
10223
+ dir: join20(root, PROJECT_DIRS[agent][0]),
10015
10224
  scope: "project"
10016
10225
  }))
10017
10226
  };
10018
10227
  }
10019
10228
  function skillsDirFor(home) {
10020
- return join19(home.dir, "skills");
10229
+ return join20(home.dir, "skills");
10021
10230
  }
10022
10231
  function fallbackSkillsHome(root) {
10023
- return { agent: "codex", dir: join19(root, ".agents"), scope: "project" };
10232
+ return { agent: "codex", dir: join20(root, ".agents"), scope: "project" };
10024
10233
  }
10025
- function installedSkills(dir, exists = existsSync16, list = (p) => {
10234
+ function installedSkills(dir, exists = existsSync17, list = (p) => {
10026
10235
  try {
10027
10236
  return readdirSync4(p);
10028
10237
  } catch {
@@ -10030,7 +10239,7 @@ function installedSkills(dir, exists = existsSync16, list = (p) => {
10030
10239
  }
10031
10240
  }) {
10032
10241
  if (!exists(dir)) return [];
10033
- return list(dir).filter((name) => exists(join19(dir, name, "SKILL.md"))).sort();
10242
+ return list(dir).filter((name) => exists(join20(dir, name, "SKILL.md"))).sort();
10034
10243
  }
10035
10244
  var RULES_BEGIN = "<!-- vos:begin (written by vos setup; the block is replaced on the next run) -->";
10036
10245
  var RULES_END = "<!-- vos:end -->";
@@ -10062,10 +10271,10 @@ ${RULES_BLOCK}
10062
10271
  }
10063
10272
  return { text, changed: text !== current };
10064
10273
  }
10065
- function rulesFileFor(root, exists = existsSync16) {
10066
- const agents = join19(root, "AGENTS.md");
10274
+ function rulesFileFor(root, exists = existsSync17) {
10275
+ const agents = join20(root, "AGENTS.md");
10067
10276
  if (exists(agents)) return agents;
10068
- const claude = join19(root, "CLAUDE.md");
10277
+ const claude = join20(root, "CLAUDE.md");
10069
10278
  if (exists(claude)) return claude;
10070
10279
  return agents;
10071
10280
  }
@@ -10074,14 +10283,14 @@ function chromeCandidates(platform, env) {
10074
10283
  return ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"];
10075
10284
  if (platform === "win32")
10076
10285
  return [
10077
- join19(
10286
+ join20(
10078
10287
  env["PROGRAMFILES"] ?? "C:\\Program Files",
10079
10288
  "Google",
10080
10289
  "Chrome",
10081
10290
  "Application",
10082
10291
  "chrome.exe"
10083
10292
  ),
10084
- join19(
10293
+ join20(
10085
10294
  env["LOCALAPPDATA"] ?? "",
10086
10295
  "Google",
10087
10296
  "Chrome",
@@ -10168,13 +10377,13 @@ function doctorReport(facts) {
10168
10377
  function bundledSkillsDir(from) {
10169
10378
  let dir = dirname5(from);
10170
10379
  for (let i = 0; i < 6; i++) {
10171
- const pkg = join19(dir, "package.json");
10172
- if (existsSync16(pkg)) {
10380
+ const pkg = join20(dir, "package.json");
10381
+ if (existsSync17(pkg)) {
10173
10382
  try {
10174
10383
  const name = JSON.parse(readFileSync6(pkg, "utf8")).name;
10175
10384
  if (name === "@vosjs/cli") {
10176
- const skills = join19(dir, "skills");
10177
- return existsSync16(skills) && statSync4(skills).isDirectory() ? skills : null;
10385
+ const skills = join20(dir, "skills");
10386
+ return existsSync17(skills) && statSync4(skills).isDirectory() ? skills : null;
10178
10387
  }
10179
10388
  } catch {
10180
10389
  }
@@ -10187,7 +10396,7 @@ function bundledSkillsDir(from) {
10187
10396
  }
10188
10397
 
10189
10398
  // src/plugin/machineCmd.ts
10190
- var BOOLEAN_FLAGS5 = /* @__PURE__ */ new Set([
10399
+ var BOOLEAN_FLAGS6 = /* @__PURE__ */ new Set([
10191
10400
  "json",
10192
10401
  "help",
10193
10402
  "global",
@@ -10205,7 +10414,7 @@ function npx() {
10205
10414
  function bundledChromium() {
10206
10415
  try {
10207
10416
  const p = chromium2.executablePath();
10208
- return p && existsSync17(p) ? p : null;
10417
+ return p && existsSync18(p) ? p : null;
10209
10418
  } catch {
10210
10419
  return null;
10211
10420
  }
@@ -10214,7 +10423,7 @@ function probe() {
10214
10423
  return probeBrowser({
10215
10424
  platform: process.platform,
10216
10425
  env: process.env,
10217
- exists: existsSync17,
10426
+ exists: existsSync18,
10218
10427
  bundled: bundledChromium
10219
10428
  });
10220
10429
  }
@@ -10265,7 +10474,7 @@ async function doctorFacts(opts) {
10265
10474
  };
10266
10475
  }
10267
10476
  async function cmdSetup(argv) {
10268
- const { flags } = parseArgs(argv, BOOLEAN_FLAGS5);
10477
+ const { flags } = parseArgs(argv, BOOLEAN_FLAGS6);
10269
10478
  const r = reporterFor(flags);
10270
10479
  const root = process.cwd();
10271
10480
  const global = flags.global === true;
@@ -10318,7 +10527,7 @@ async function cmdSetup(argv) {
10318
10527
  const dest = skillsDirFor(home);
10319
10528
  mkdirSync3(dest, { recursive: true });
10320
10529
  for (const name of installedSkills(bundled)) {
10321
- cpSync(join20(bundled, name), join20(dest, name), { recursive: true });
10530
+ cpSync(join21(bundled, name), join21(dest, name), { recursive: true });
10322
10531
  }
10323
10532
  }
10324
10533
  skillsVia = "bundled";
@@ -10353,7 +10562,7 @@ async function cmdSetup(argv) {
10353
10562
  let rules = null;
10354
10563
  if (!noRules) {
10355
10564
  const file = rulesFileFor(root);
10356
- const existing = existsSync17(file) ? readFileSync7(file, "utf8") : null;
10565
+ const existing = existsSync18(file) ? readFileSync7(file, "utf8") : null;
10357
10566
  const { text, changed } = applyRulesBlock(existing);
10358
10567
  if (changed) writeFileSync3(file, text);
10359
10568
  rules = { file, changed };
@@ -10384,7 +10593,7 @@ Next: ${report.next_step}`
10384
10593
  return report.ok ? EXIT_OK : EXIT_NO_BROWSER;
10385
10594
  }
10386
10595
  async function cmdDoctor(argv) {
10387
- const { flags } = parseArgs(argv, BOOLEAN_FLAGS5);
10596
+ const { flags } = parseArgs(argv, BOOLEAN_FLAGS6);
10388
10597
  const r = reporterFor(flags);
10389
10598
  const root = process.cwd();
10390
10599
  const homes = detectAgents(root, { home: homedir3(), global: true });
@@ -10403,7 +10612,7 @@ Next: ${report.next_step}`
10403
10612
  return report.ok ? EXIT_OK : EXIT_NO_BROWSER;
10404
10613
  }
10405
10614
  async function cmdWhoami(argv) {
10406
- const { flags } = parseArgs(argv, BOOLEAN_FLAGS5);
10615
+ const { flags } = parseArgs(argv, BOOLEAN_FLAGS6);
10407
10616
  const r = reporterFor(flags);
10408
10617
  const origin = platformOrigin({
10409
10618
  origin: strFlag(flags, "origin"),
@@ -10465,9 +10674,9 @@ async function cmdWhoami(argv) {
10465
10674
  return EXIT_OK;
10466
10675
  }
10467
10676
  function cmdLogout(argv) {
10468
- const { flags } = parseArgs(argv, BOOLEAN_FLAGS5);
10677
+ const { flags } = parseArgs(argv, BOOLEAN_FLAGS6);
10469
10678
  const r = reporterFor(flags);
10470
- const had = existsSync17(CREDENTIALS_PATH);
10679
+ const had = existsSync18(CREDENTIALS_PATH);
10471
10680
  rmSync2(CREDENTIALS_PATH, { force: true });
10472
10681
  const envKey = Boolean(process.env.VOS_API_KEY?.trim());
10473
10682
  r.done(
@@ -10483,7 +10692,7 @@ function cmdLogout(argv) {
10483
10692
  }
10484
10693
 
10485
10694
  // src/plugin/run.ts
10486
- var BOOLEAN_FLAGS6 = /* @__PURE__ */ new Set([
10695
+ var BOOLEAN_FLAGS7 = /* @__PURE__ */ new Set([
10487
10696
  "json",
10488
10697
  "help",
10489
10698
  "picture",
@@ -10526,6 +10735,8 @@ Take pipeline
10526
10735
  vos validate <actions.json|take|kit.json> [--picture] [--json]
10527
10736
  vos judge <kit.json> --against <MANIFEST.json> [--out dir] [--json]
10528
10737
  vos actions from-agent-browser <steps.jsonl> [--out actions.json] [--url <url>] [--viewport WxH] [--json]
10738
+ vos ingest <video.webm|mp4> [--cursor <trace.zip|steps.jsonl|cursor.csv>] [--out take] [--offset <ms>] [--viewport WxH] [--background <slug|url|none>] [--json]
10739
+ a take from a recording someone else made (a cloud agent's PR video, a Playwright run's video, a Loom export): the file becomes recording.<container>, meta.json from its own dimensions and duration, and a trace beside it becomes cursor.json so the planner has clicks to zoom on; without one, nothing is planned and the done event says so
10529
10740
  vos session open <url> --name <app> a plain Chrome window on a vos-owned profile; sign in, close it
10530
10741
  vos session check <name> [--url <url>] headless: does the session still open the page? exit 0/4
10531
10742
  vos session list | rm <name> what exists and how old; delete one
@@ -10783,7 +10994,7 @@ lint-gated, so a bad override fails like a bad doc.json):
10783
10994
  first ready loop (the house backdrop the studio opens on), or a flat ground offline
10784
10995
  `;
10785
10996
  async function loadActions(file) {
10786
- const raw = JSON.parse(await readFile15(file, "utf8"));
10997
+ const raw = JSON.parse(await readFile16(file, "utf8"));
10787
10998
  const errors = validateActions(raw);
10788
10999
  if (errors.length)
10789
11000
  throw new UsageError(`invalid actions file:
@@ -10845,8 +11056,8 @@ function takeBrowserArgs(multi) {
10845
11056
  function takeStorageState(flags) {
10846
11057
  const raw = strFlag(flags, "storage-state");
10847
11058
  if (!raw) return void 0;
10848
- const path = resolve9(raw);
10849
- if (!existsSync18(path))
11059
+ const path = resolve10(raw);
11060
+ if (!existsSync19(path))
10850
11061
  throw new UsageError(`--storage-state: no such file: ${path}`);
10851
11062
  return path;
10852
11063
  }
@@ -10859,7 +11070,7 @@ function takeSessionName(flags, storageState) {
10859
11070
  throw new UsageError(
10860
11071
  "--session and --storage-state are two doors to one take: a persistent profile cannot take a storage state. Pass one"
10861
11072
  );
10862
- if (!existsSync18(sessionDir(name)))
11073
+ if (!existsSync19(sessionDir(name)))
10863
11074
  throw new UsageError(
10864
11075
  `no session "${name}". Make one: vos session open <url> --name ${name} (a Chrome window opens; sign in and close it)`
10865
11076
  );
@@ -10915,7 +11126,7 @@ function wallGate(flags, r, opts) {
10915
11126
  async function cmdRecord(argv) {
10916
11127
  const { positionals, flags, multi } = parseArgs(
10917
11128
  argv,
10918
- BOOLEAN_FLAGS6,
11129
+ BOOLEAN_FLAGS7,
10919
11130
  MULTI_FLAGS2
10920
11131
  );
10921
11132
  const actionsPath = strFlag(flags, "actions") ?? positionals[0];
@@ -10928,7 +11139,7 @@ async function cmdRecord(argv) {
10928
11139
  const url = strFlag(flags, "url") ?? actions.url;
10929
11140
  if (!url)
10930
11141
  throw new UsageError('no URL \u2014 set "url" in the actions file or pass --url');
10931
- const outDir = resolve9(strFlag(flags, "out") ?? "take");
11142
+ const outDir = resolve10(strFlag(flags, "out") ?? "take");
10932
11143
  const storageState = takeStorageState(flags);
10933
11144
  const sessionName = takeSessionName(flags, storageState);
10934
11145
  const browserArgs = takeBrowserArgs(multi);
@@ -11082,13 +11293,13 @@ ${lines.join("\n")}
11082
11293
  }
11083
11294
  const paths = takePaths(outDir);
11084
11295
  const prepare = async () => {
11085
- if (existsSync18(join21(outDir, "meta.json"))) {
11296
+ if (existsSync19(join22(outDir, "meta.json"))) {
11086
11297
  const { prevDoc, kept } = await prepareReRecord(outDir);
11087
11298
  r.log(
11088
11299
  `note: re-recording ${outDir} \u2014 kept ${kept.length ? kept.join(", ") : "nothing"}` + (prevDoc ? "; apply the previous cut to the new footage with: vos plan " + outDir + " --reuse" : "")
11089
11300
  );
11090
11301
  }
11091
- await mkdir10(outDir, { recursive: true });
11302
+ await mkdir11(outDir, { recursive: true });
11092
11303
  await ensureTakeDir(outDir);
11093
11304
  };
11094
11305
  const browser = await launchBrowser(browserArgs);
@@ -11147,7 +11358,7 @@ ${lines.join("\n")}
11147
11358
  },
11148
11359
  strictFail ? `STRICT: take recorded but incomplete \u2014 ${strictReason(rec)}; fix the flow and re-record.${skippedNote}${exposureNote(rec)}` : `Take ready: ${outDir}
11149
11360
  ${(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}
11150
- Next: edit ${join21(outDir, "doc.json")} (optional), then: vos render ${outDir}${exposureNote(rec)}`
11361
+ Next: edit ${join22(outDir, "doc.json")} (optional), then: vos render ${outDir}${exposureNote(rec)}`
11151
11362
  );
11152
11363
  return strictFail ? EXIT_USAGE : EXIT_OK;
11153
11364
  } finally {
@@ -11157,7 +11368,7 @@ ${lines.join("\n")}
11157
11368
  async function cmdCreate2(argv) {
11158
11369
  const { positionals, flags, multi } = parseArgs(
11159
11370
  argv,
11160
- BOOLEAN_FLAGS6,
11371
+ BOOLEAN_FLAGS7,
11161
11372
  MULTI_FLAGS2
11162
11373
  );
11163
11374
  const actionsPath = strFlag(flags, "actions");
@@ -11171,12 +11382,12 @@ async function cmdCreate2(argv) {
11171
11382
  const url = strFlag(flags, "url") ?? actions.url;
11172
11383
  if (!url)
11173
11384
  throw new UsageError('no URL \u2014 set "url" in the actions file or pass --url');
11174
- const outDir = resolve9(strFlag(flags, "out") ?? "take");
11385
+ const outDir = resolve10(strFlag(flags, "out") ?? "take");
11175
11386
  const fmtRaw = strFlag(flags, "format") ?? "webm";
11176
11387
  if (fmtRaw !== "webm" && fmtRaw !== "mp4")
11177
11388
  throw new UsageError("--format must be webm or mp4");
11178
11389
  const format = fmtRaw;
11179
- const out = positionals[0] ?? join21(outDir, `out.${format}`);
11390
+ const out = positionals[0] ?? join22(outDir, `out.${format}`);
11180
11391
  const parallel = numFlag(flags, "parallel", 1);
11181
11392
  if (!Number.isInteger(parallel) || parallel < 1 || parallel > 16) {
11182
11393
  throw new UsageError("--parallel expects an integer between 1 and 16");
@@ -11189,13 +11400,13 @@ async function cmdCreate2(argv) {
11189
11400
  const headers = takeHeaders(multi);
11190
11401
  const paths = takePaths(outDir);
11191
11402
  const prepare = async () => {
11192
- if (existsSync18(join21(outDir, "meta.json"))) {
11403
+ if (existsSync19(join22(outDir, "meta.json"))) {
11193
11404
  const { prevDoc, kept } = await prepareReRecord(outDir);
11194
11405
  r.log(
11195
11406
  `note: re-recording ${outDir} \u2014 kept ${kept.length ? kept.join(", ") : "nothing"}` + (prevDoc ? "; apply the previous cut to the new footage with: vos plan " + outDir + " --reuse" : "")
11196
11407
  );
11197
11408
  }
11198
- await mkdir10(outDir, { recursive: true });
11409
+ await mkdir11(outDir, { recursive: true });
11199
11410
  await ensureTakeDir(outDir);
11200
11411
  };
11201
11412
  const browser = await launchBrowser(browserArgs);
@@ -11286,7 +11497,7 @@ async function cmdCreate2(argv) {
11286
11497
  async function cmdPlan(argv) {
11287
11498
  const { positionals, flags, multi } = parseArgs(
11288
11499
  argv,
11289
- BOOLEAN_FLAGS6,
11500
+ BOOLEAN_FLAGS7,
11290
11501
  /* @__PURE__ */ new Set(["with"])
11291
11502
  );
11292
11503
  const dir = positionals[0];
@@ -11296,24 +11507,24 @@ async function cmdPlan(argv) {
11296
11507
  );
11297
11508
  const r = createReporter(flags.json === true);
11298
11509
  if (flags.fresh === true) {
11299
- await rm5(join21(dir, "doc.json"), { force: true });
11510
+ await rm5(join22(dir, "doc.json"), { force: true });
11300
11511
  r.log("note: --fresh discarded the existing doc.json");
11301
11512
  }
11302
11513
  let reuse;
11303
11514
  if (flags.reuse === true) {
11304
- const from = resolve9(strFlag(flags, "from") ?? join21(dir, PREV_DOC_NAME));
11305
- if (!existsSync18(from)) {
11515
+ const from = resolve10(strFlag(flags, "from") ?? join22(dir, PREV_DOC_NAME));
11516
+ if (!existsSync19(from)) {
11306
11517
  throw new UsageError(
11307
11518
  `--reuse: ${from} does not exist \u2014 a re-record into this take writes doc.prev.json, or pass --from <doc.json>`
11308
11519
  );
11309
11520
  }
11310
11521
  reuse = {
11311
11522
  from,
11312
- doc: JSON.parse(await readFile15(from, "utf8"))
11523
+ doc: JSON.parse(await readFile16(from, "utf8"))
11313
11524
  };
11314
11525
  }
11315
11526
  const style = await resolveStyleRef(flags);
11316
- const hasDoc = existsSync18(join21(dir, "doc.json"));
11527
+ const hasDoc = existsSync19(join22(dir, "doc.json"));
11317
11528
  const backdrop = hasDoc ? null : await takeBackdrop(flags, r);
11318
11529
  const release = await releaseInputs(dir, flags, r, multi.with ?? []);
11319
11530
  const motionWanted = !hasDoc || flags.motion === true || flags.fresh === true;
@@ -11359,7 +11570,7 @@ async function cmdPlan(argv) {
11359
11570
  ${s.reuse.flagged.join("\n ")}` : "") : "";
11360
11571
  r.done(
11361
11572
  {
11362
- take: resolve9(dir),
11573
+ take: resolve10(dir),
11363
11574
  fresh: s.fresh,
11364
11575
  cursorKept: s.cursorKept,
11365
11576
  zoomAuto: s.zoomAuto,
@@ -11371,7 +11582,7 @@ async function cmdPlan(argv) {
11371
11582
  ...s.motion ? { motion: s.motion } : {},
11372
11583
  ...s.reuse ? { reuse: s.reuse } : {}
11373
11584
  },
11374
- `${s.reuse ? "Reused" : s.fresh ? "Planned" : "Refreshed"} ${join21(dir, "doc.json")}: ${s.zoomAuto} auto + ${s.zoomManual} manual zoom spans${s.cursorKept ? "" : " (cursor track dropped)"}${layoutLines}${motionLines}${reuseLines}`
11585
+ `${s.reuse ? "Reused" : s.fresh ? "Planned" : "Refreshed"} ${join22(dir, "doc.json")}: ${s.zoomAuto} auto + ${s.zoomManual} manual zoom spans${s.cursorKept ? "" : " (cursor track dropped)"}${layoutLines}${motionLines}${reuseLines}`
11375
11586
  );
11376
11587
  return EXIT_OK;
11377
11588
  }
@@ -11484,7 +11695,7 @@ async function releaseInputs(dir, flags, r, withRefs = []) {
11484
11695
  async function cmdRender(argv) {
11485
11696
  const { positionals, flags, multi } = parseArgs(
11486
11697
  argv,
11487
- BOOLEAN_FLAGS6,
11698
+ BOOLEAN_FLAGS7,
11488
11699
  MULTI_FLAGS2
11489
11700
  );
11490
11701
  const dir = positionals[0];
@@ -11497,7 +11708,7 @@ async function cmdRender(argv) {
11497
11708
  if (fmtRaw !== "webm" && fmtRaw !== "mp4")
11498
11709
  throw new UsageError("--format must be webm or mp4");
11499
11710
  const format = fmtRaw;
11500
- const out = positionals[1] ?? join21(dir, `out.${format}`);
11711
+ const out = positionals[1] ?? join22(dir, `out.${format}`);
11501
11712
  const parallel = numFlag(flags, "parallel", 1);
11502
11713
  if (!Number.isInteger(parallel) || parallel < 1 || parallel > 16) {
11503
11714
  throw new UsageError("--parallel expects an integer between 1 and 16");
@@ -11555,7 +11766,7 @@ async function cmdRender(argv) {
11555
11766
  async function cmdFrames(argv) {
11556
11767
  const { positionals, flags, multi } = parseArgs(
11557
11768
  argv,
11558
- BOOLEAN_FLAGS6,
11769
+ BOOLEAN_FLAGS7,
11559
11770
  MULTI_FLAGS2
11560
11771
  );
11561
11772
  const dir = positionals[0];
@@ -11628,7 +11839,7 @@ async function cmdFrames(argv) {
11628
11839
  async function cmdDeliver(argv) {
11629
11840
  const { positionals, flags, multi } = parseArgs(
11630
11841
  argv,
11631
- BOOLEAN_FLAGS6,
11842
+ BOOLEAN_FLAGS7,
11632
11843
  MULTI_FLAGS2
11633
11844
  );
11634
11845
  const dir = positionals[0];
@@ -11744,15 +11955,15 @@ async function resolveStyleRef(flags) {
11744
11955
  }
11745
11956
  async function resolveDocRef(ref, flags, what) {
11746
11957
  const styleRef = ref;
11747
- const file = existsSync18(styleRef) ? resolve9(
11958
+ const file = existsSync19(styleRef) ? resolve10(
11748
11959
  styleRef,
11749
- existsSync18(join21(styleRef, "doc.json")) ? "doc.json" : ""
11960
+ existsSync19(join22(styleRef, "doc.json")) ? "doc.json" : ""
11750
11961
  ) : null;
11751
- if (file && existsSync18(file)) {
11962
+ if (file && existsSync19(file)) {
11752
11963
  return {
11753
11964
  from: file,
11754
11965
  doc: migrateHostedDoc5(
11755
- JSON.parse(await readFile15(file, "utf8"))
11966
+ JSON.parse(await readFile16(file, "utf8"))
11756
11967
  )
11757
11968
  };
11758
11969
  }
@@ -11794,7 +12005,7 @@ async function officialTemplate(origin, ref) {
11794
12005
  }
11795
12006
  }
11796
12007
  async function cmdDigest(argv) {
11797
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS6);
12008
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS7);
11798
12009
  const dir = positionals[0];
11799
12010
  if (!dir)
11800
12011
  throw new UsageError(
@@ -11804,7 +12015,7 @@ async function cmdDigest(argv) {
11804
12015
  const take = await loadTake(dir);
11805
12016
  if (!take.doc) throw new UsageError(`${dir} has no doc.json \u2014 run plan first`);
11806
12017
  const transcriptPath = strFlag(flags, "transcript");
11807
- const transcript = transcriptPath ? parseTranscript(JSON.parse(await readFile15(transcriptPath, "utf8"))) : null;
12018
+ const transcript = transcriptPath ? parseTranscript(JSON.parse(await readFile16(transcriptPath, "utf8"))) : null;
11808
12019
  const style = await resolveStyleRef(flags);
11809
12020
  const noFrames = flags["no-frames"] === true;
11810
12021
  let browser = null;
@@ -11835,7 +12046,7 @@ async function cmdDigest(argv) {
11835
12046
  kinds,
11836
12047
  frames: d.images.full,
11837
12048
  crops: d.images.crop,
11838
- sheet: d.images.sheet ? join21(result.outDir, d.images.sheet) : null,
12049
+ sheet: d.images.sheet ? join22(result.outDir, d.images.sheet) : null,
11839
12050
  scenes: kinds.scene ?? 0,
11840
12051
  sourceDuration: d.take.sourceDuration,
11841
12052
  outputDuration: d.take.outputDuration,
@@ -11858,19 +12069,19 @@ async function cmdDigest(argv) {
11858
12069
  }
11859
12070
  }
11860
12071
  async function cmdOpen(argv) {
11861
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS6);
12072
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS7);
11862
12073
  const dir = positionals[0];
11863
12074
  if (!dir) throw new UsageError("vos open <take> [--studio <url>]");
11864
12075
  const r = createReporter(flags.json === true);
11865
12076
  const take = await loadTake(dir);
11866
- if (!existsSync18(take.paths.recording)) {
12077
+ if (!existsSync19(take.paths.recording)) {
11867
12078
  throw new UsageError(`${dir} has no recording \u2014 re-run record`);
11868
12079
  }
11869
12080
  const studio = (strFlag(flags, "studio") ?? platformOrigin()).replace(
11870
12081
  /\/+$/,
11871
12082
  ""
11872
12083
  );
11873
- const server = await startTakeServer(resolve9(dir), {});
12084
+ const server = await startTakeServer(resolve10(dir), {});
11874
12085
  const url = `${studio}/studio?take=${encodeURIComponent(server.base)}`;
11875
12086
  r.event({ event: "open", server: server.base, url });
11876
12087
  r.log(`take served at ${server.base}`);
@@ -11896,7 +12107,7 @@ async function cmdOpen(argv) {
11896
12107
  return EXIT_OK;
11897
12108
  }
11898
12109
  async function cmdJudge(argv) {
11899
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS6);
12110
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS7);
11900
12111
  const target = positionals[0];
11901
12112
  const against = strFlag(flags, "against");
11902
12113
  if (!target || !against)
@@ -11904,12 +12115,12 @@ async function cmdJudge(argv) {
11904
12115
  "vos judge <kit.json> --against <MANIFEST.json> [--out dir] [--json]\n(the manifest names the reference set: id, file, role, layout, facts, rule per asset)"
11905
12116
  );
11906
12117
  const r = createReporter(flags.json === true);
11907
- const kitFile = target.endsWith("kit.json") ? target : join21(target, "kit.json");
11908
- if (!existsSync18(kitFile)) throw new UsageError(`${kitFile}: no kit manifest`);
11909
- if (!existsSync18(against))
12118
+ const kitFile = target.endsWith("kit.json") ? target : join22(target, "kit.json");
12119
+ if (!existsSync19(kitFile)) throw new UsageError(`${kitFile}: no kit manifest`);
12120
+ if (!existsSync19(against))
11910
12121
  throw new UsageError(`${against}: no reference manifest`);
11911
12122
  const result = await judgeKit(kitFile, against, strFlag(flags, "out"));
11912
- const verdicts = JSON.parse(await readFile15(result.verdictFile, "utf8")).verdicts;
12123
+ const verdicts = JSON.parse(await readFile16(result.verdictFile, "utf8")).verdicts;
11913
12124
  const rate = winRate(verdicts);
11914
12125
  const lines = result.sheets.map(
11915
12126
  (s) => `${s.asset} vs ${s.reference}: ${s.sheetA}, ${s.sheetB}, ${s.rubric}`
@@ -11925,7 +12136,7 @@ Win rate so far: ${rate.wins} win(s), ${rate.ties} tie(s) of ${rate.judged} judg
11925
12136
  return EXIT_OK;
11926
12137
  }
11927
12138
  async function cmdCallout(argv) {
11928
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS6);
12139
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS7);
11929
12140
  const dir = positionals[0];
11930
12141
  const shape = positionals[1];
11931
12142
  if (!dir || !shape || !isCalloutShape(shape))
@@ -11949,7 +12160,7 @@ async function cmdCallout(argv) {
11949
12160
  `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`
11950
12161
  );
11951
12162
  const codeFile = strFlag(flags, "code-file");
11952
- const code = codeFile ? await readFile15(codeFile, "utf8") : strFlag(flags, "code");
12163
+ const code = codeFile ? await readFile16(codeFile, "utf8") : strFlag(flags, "code");
11953
12164
  const words = {
11954
12165
  kicker: strFlag(flags, "kicker"),
11955
12166
  title: strFlag(flags, "title"),
@@ -12024,11 +12235,11 @@ async function cmdCallout(argv) {
12024
12235
  return EXIT_OK;
12025
12236
  }
12026
12237
  async function cmdValidate(argv) {
12027
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS6);
12238
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS7);
12028
12239
  const target = positionals[0];
12029
12240
  if (!target) throw new UsageError("vos validate <actions.json|take>");
12030
12241
  const r = createReporter(flags.json === true);
12031
- const kitTarget = target.endsWith("kit.json") ? target : existsSync18(join21(target, "kit.json")) && !isTakeDir(target) ? join21(target, "kit.json") : null;
12242
+ const kitTarget = target.endsWith("kit.json") ? target : existsSync19(join22(target, "kit.json")) && !isTakeDir(target) ? join22(target, "kit.json") : null;
12032
12243
  if (kitTarget) {
12033
12244
  const picture = flags.picture === true;
12034
12245
  const verdict = await validateKit(kitTarget, { picture });
@@ -12060,9 +12271,9 @@ async function cmdValidate(argv) {
12060
12271
  r.done({ valid: true, target }, `${target}: valid actions file`);
12061
12272
  return EXIT_OK;
12062
12273
  }
12063
- if (!isTakeDir(target) && existsSync18(join21(target, "config.json"))) {
12274
+ if (!isTakeDir(target) && existsSync19(join22(target, "config.json"))) {
12064
12275
  const parsed = JSON.parse(
12065
- await readFile15(join21(target, "config.json"), "utf8")
12276
+ await readFile16(join22(target, "config.json"), "utf8")
12066
12277
  );
12067
12278
  const pre = preflightConfig(parsed);
12068
12279
  const problems2 = pre.ok ? [] : pre.issues.map((i) => `config.json: ${i}`);
@@ -12103,7 +12314,7 @@ async function cmdValidate(argv) {
12103
12314
  const take = await loadTake(target);
12104
12315
  const problems = [];
12105
12316
  const warnings = [];
12106
- if (!existsSync18(take.paths.recording)) {
12317
+ if (!existsSync19(take.paths.recording)) {
12107
12318
  problems.push("missing recording (re-run record)");
12108
12319
  } else {
12109
12320
  const mismatch = containerMismatch(
@@ -12186,7 +12397,7 @@ async function cmdValidate(argv) {
12186
12397
  async function cmdPush3(argv) {
12187
12398
  const { positionals, flags, multi } = parseArgs(
12188
12399
  argv,
12189
- BOOLEAN_FLAGS6,
12400
+ BOOLEAN_FLAGS7,
12190
12401
  MULTI_FLAGS2
12191
12402
  );
12192
12403
  const dir = positionals[0];
@@ -12196,7 +12407,7 @@ async function cmdPush3(argv) {
12196
12407
  );
12197
12408
  const refusal = takePushRefusal({
12198
12409
  vos: strFlag(flags, "vos"),
12199
- trackedVosId: readSyncState(resolve9(dir))?.vosId ?? null,
12410
+ trackedVosId: readSyncState(resolve10(dir))?.vosId ?? null,
12200
12411
  programOnly: ["slug", "desc", "tags", "base", "remix-of"].filter(
12201
12412
  (name) => hasFlag(flags, name)
12202
12413
  )
@@ -12205,7 +12416,7 @@ async function cmdPush3(argv) {
12205
12416
  const r = createReporter(flags.json === true);
12206
12417
  const overrides = multi.override;
12207
12418
  const result = await pushTake(
12208
- resolve9(dir),
12419
+ resolve10(dir),
12209
12420
  {
12210
12421
  key: strFlag(flags, "key"),
12211
12422
  api: strFlag(flags, "api"),
@@ -12233,11 +12444,11 @@ async function cmdPush3(argv) {
12233
12444
  return EXIT_OK;
12234
12445
  }
12235
12446
  async function cmdPull2(argv) {
12236
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS6, MULTI_FLAGS2);
12447
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS7, MULTI_FLAGS2);
12237
12448
  const dir = positionals[0] ?? ".";
12238
12449
  const r = createReporter(flags.json === true);
12239
12450
  const result = await pullTake(
12240
- resolve9(dir),
12451
+ resolve10(dir),
12241
12452
  {
12242
12453
  key: strFlag(flags, "key"),
12243
12454
  api: strFlag(flags, "api"),
@@ -12356,6 +12567,8 @@ async function run(argv) {
12356
12567
  return await cmdSession(rest);
12357
12568
  case "actions":
12358
12569
  return await cmdActions(rest);
12570
+ case "ingest":
12571
+ return await cmdIngest(rest);
12359
12572
  default:
12360
12573
  throw new UsageError(`unknown command "${cmd}" \u2014 run: vos help`);
12361
12574
  }
@@ -12388,7 +12601,7 @@ async function run(argv) {
12388
12601
  }
12389
12602
  }
12390
12603
  async function cmdSession(argv) {
12391
- const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS6);
12604
+ const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS7);
12392
12605
  const [sub, arg] = positionals;
12393
12606
  const r = createReporter(flags.json === true);
12394
12607
  const usage = "vos session open <url> --name <app> | check <name> [--url <url>] | list | rm <name>";
@@ -12424,7 +12637,7 @@ async function cmdSession(argv) {
12424
12637
  if (!arg) throw new UsageError(usage);
12425
12638
  const bad = sessionNameVerdict(arg);
12426
12639
  if (bad) throw new UsageError(bad);
12427
- if (!existsSync18(sessionDir(arg)))
12640
+ if (!existsSync19(sessionDir(arg)))
12428
12641
  throw new UsageError(`no session "${arg}" (vos session list)`);
12429
12642
  const summary2 = await summarizeSession(arg);
12430
12643
  const url = strFlag(flags, "url");
@@ -12531,7 +12744,8 @@ export {
12531
12744
  MULTI_FLAGS2 as MULTI_FLAGS,
12532
12745
  HELP,
12533
12746
  takeBrowserArgs,
12747
+ takeBackdrop,
12534
12748
  verbHelp,
12535
12749
  run
12536
12750
  };
12537
- //# sourceMappingURL=chunk-TAWRT7UM.js.map
12751
+ //# sourceMappingURL=chunk-SE4F3OMQ.js.map