@vosjs/cli 0.87.0 → 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.
- package/README.md +16 -2
- package/dist/{chunk-7A3PZARL.js → chunk-BDFC2L2O.js} +2 -2
- package/dist/chunk-BDFC2L2O.js.map +1 -0
- package/dist/{chunk-ACWV3Y6Y.js → chunk-BHWDA2KG.js} +408 -220
- package/dist/chunk-BHWDA2KG.js.map +1 -0
- package/dist/cli.js +4 -4
- package/dist/index.js +2 -2
- package/dist/manifest-E4KFN42P.js +8 -0
- package/dist/{run-OT54QJ4T.js → run-B52VR6J6.js} +4 -2
- package/package.json +5 -4
- package/schema/digest.schema.json +9 -2
- package/dist/chunk-7A3PZARL.js.map +0 -1
- package/dist/chunk-ACWV3Y6Y.js.map +0 -1
- package/dist/manifest-OLVFUZTW.js +0 -8
- /package/dist/{manifest-OLVFUZTW.js.map → manifest-E4KFN42P.js.map} +0 -0
- /package/dist/{run-OT54QJ4T.js.map → run-B52VR6J6.js.map} +0 -0
|
@@ -165,9 +165,9 @@ function landedLines(l) {
|
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
// src/plugin/run.ts
|
|
168
|
-
import { mkdir as
|
|
169
|
-
import { existsSync as
|
|
170
|
-
import { dirname as dirname12, join as
|
|
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((
|
|
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)
|
|
6099
|
-
else
|
|
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
|
-
(
|
|
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((
|
|
6374
|
+
const exited = new Promise((resolve24) => {
|
|
6375
6375
|
child.once("exit", (c) => {
|
|
6376
6376
|
code = c;
|
|
6377
|
-
|
|
6377
|
+
resolve24();
|
|
6378
6378
|
});
|
|
6379
6379
|
child.once("error", (e) => {
|
|
6380
6380
|
failed = e;
|
|
6381
|
-
|
|
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:
|
|
13295
|
-
const text = await
|
|
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:
|
|
13332
|
+
const { readFile: readFile21 } = await import("fs/promises");
|
|
13333
13333
|
const { shotList, formatShotList } = await import("./shotList-PL7XP6AC.js");
|
|
13334
|
-
const raw = JSON.parse(await
|
|
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
|
|
13612
|
-
import { mkdir as
|
|
13613
|
-
import { basename as basename12, dirname as dirname8, extname as extname4, join as
|
|
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
|
|
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 =
|
|
13897
|
-
if (
|
|
13898
|
-
return
|
|
13899
|
-
|
|
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(
|
|
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
|
|
14157
|
-
const firstFile =
|
|
14158
|
-
const lastFile =
|
|
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
|
-
|
|
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"}; ${
|
|
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,
|
|
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 (!
|
|
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 =
|
|
14243
|
-
strFlag(flags, "out") ??
|
|
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
|
|
14259
|
-
import { copyFile as copyFile3, mkdir as
|
|
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
|
|
14422
|
+
join as join28,
|
|
14265
14423
|
relative as relative5,
|
|
14266
|
-
resolve as
|
|
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
|
|
14440
|
+
import { existsSync as existsSync25 } from "fs";
|
|
14283
14441
|
import {
|
|
14284
14442
|
copyFile as copyFile2,
|
|
14285
|
-
mkdir as
|
|
14443
|
+
mkdir as mkdir11,
|
|
14286
14444
|
mkdtemp,
|
|
14287
|
-
readFile as
|
|
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
|
|
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
|
|
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 =
|
|
14710
|
-
if (
|
|
14711
|
-
const rel = relative4(
|
|
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
|
|
14716
|
-
await copyFile2(local,
|
|
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(
|
|
14733
|
-
const path =
|
|
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
|
|
14743
|
-
var
|
|
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,
|
|
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(
|
|
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(
|
|
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:
|
|
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
|
|
15409
|
-
import { readFile as
|
|
15410
|
-
import { join as
|
|
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 =
|
|
15436
|
-
return
|
|
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 =
|
|
15440
|
-
if (!
|
|
15597
|
+
const file = join27(dir, JOIN_RECORD_NAME);
|
|
15598
|
+
if (!existsSync26(file)) return null;
|
|
15441
15599
|
try {
|
|
15442
|
-
const v = JSON.parse(await
|
|
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 =
|
|
15453
|
-
return
|
|
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:
|
|
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:
|
|
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
|
|
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
|
|
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 =
|
|
16460
|
-
if (!
|
|
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 (!
|
|
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,
|
|
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(
|
|
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 =
|
|
16510
|
-
const inputs = positionals.map((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(
|
|
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 (
|
|
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 (!
|
|
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 =
|
|
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
|
|
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(),
|
|
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 =
|
|
16627
|
-
if (
|
|
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 (
|
|
16632
|
-
await
|
|
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 =
|
|
16636
|
-
await
|
|
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(
|
|
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(
|
|
16822
|
+
await writeJson(join28(out, "meta.json"), doc.source.meta, true);
|
|
16665
16823
|
if (doc.source.cursor.length)
|
|
16666
|
-
await writeJson(
|
|
16824
|
+
await writeJson(join28(out, "cursor.json"), doc.source.cursor);
|
|
16667
16825
|
if (parts[0].actions)
|
|
16668
|
-
await writeJson(
|
|
16669
|
-
await writeJson(
|
|
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
|
-
|
|
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
|
|
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:
|
|
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
|
|
17173
|
+
import { basename as basename15, join as join30 } from "path";
|
|
17016
17174
|
import { clipGain as clipGain3 } from "@vosjs/studio-core";
|
|
17017
|
-
var
|
|
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(
|
|
17028
|
-
const path =
|
|
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(
|
|
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
|
|
17110
|
-
import { basename as basename16, resolve as
|
|
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
|
|
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
|
|
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 =
|
|
17185
|
-
if (!
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
|
17337
|
-
import { existsSync as
|
|
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
|
|
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
|
|
17803
|
-
const screenshot =
|
|
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
|
|
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(
|
|
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(
|
|
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 =
|
|
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 ?
|
|
17939
|
-
if (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 (!
|
|
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:
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
18141
|
-
import { dirname as dirname11, join as
|
|
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 ??
|
|
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 =
|
|
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(
|
|
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:
|
|
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 =
|
|
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:
|
|
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
|
|
18361
|
+
return join32(home.dir, "skills");
|
|
18204
18362
|
}
|
|
18205
18363
|
function fallbackSkillsHome(root) {
|
|
18206
|
-
return { agent: "codex", dir:
|
|
18364
|
+
return { agent: "codex", dir: join32(root, ".agents"), scope: "project" };
|
|
18207
18365
|
}
|
|
18208
|
-
function installedSkills(dir, exists =
|
|
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(
|
|
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 =
|
|
18250
|
-
const agents =
|
|
18407
|
+
function rulesFileFor(root, exists = existsSync30) {
|
|
18408
|
+
const agents = join32(root, "AGENTS.md");
|
|
18251
18409
|
if (exists(agents)) return agents;
|
|
18252
|
-
const claude =
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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 =
|
|
18374
|
-
if (
|
|
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 =
|
|
18379
|
-
return
|
|
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
|
|
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([...
|
|
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 &&
|
|
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:
|
|
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,
|
|
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(
|
|
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 =
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
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
|
|
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 =
|
|
19422
|
-
if (!
|
|
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 (!
|
|
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 && !
|
|
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 (
|
|
19646
|
+
if (existsSync32(join34(outDir, "meta.json"))) {
|
|
19461
19647
|
const { prevDoc, kept } = await prepareReRecord(outDir);
|
|
19462
|
-
if (prevDoc) previousCut =
|
|
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
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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(
|
|
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(
|
|
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
|
-
...
|
|
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(
|
|
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 ${
|
|
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
|
-
|
|
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 =
|
|
20104
|
+
const outDir = resolve23(strFlag(flags, "out") ?? "take");
|
|
19918
20105
|
const format = videoFormat(strFlag(flags, "format"), positionals[0]);
|
|
19919
|
-
const out = positionals[0] ??
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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 =
|
|
20074
|
-
if (!
|
|
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
|
|
20268
|
+
doc: JSON.parse(await readFile20(from, "utf8"))
|
|
20082
20269
|
};
|
|
20083
20270
|
}
|
|
20084
20271
|
const style = await resolveStyleRef(flags);
|
|
20085
|
-
const hasDoc =
|
|
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:
|
|
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"} ${
|
|
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
|
-
|
|
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] ??
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
20732
|
+
const file = existsSync32(styleRef) ? resolve23(
|
|
20546
20733
|
styleRef,
|
|
20547
|
-
|
|
20734
|
+
existsSync32(join34(styleRef, "doc.json")) ? "doc.json" : ""
|
|
20548
20735
|
) : null;
|
|
20549
|
-
if (file &&
|
|
20736
|
+
if (file && existsSync32(file)) {
|
|
20550
20737
|
return {
|
|
20551
20738
|
from: file,
|
|
20552
20739
|
doc: migrateHostedDoc4(
|
|
20553
|
-
JSON.parse(await
|
|
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,
|
|
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
|
|
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 ?
|
|
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,
|
|
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 (!
|
|
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(
|
|
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,
|
|
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
|
|
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,
|
|
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 :
|
|
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) &&
|
|
21016
|
+
if (!isTakeDir(target) && existsSync32(join34(target, "config.json"))) {
|
|
20830
21017
|
const parsed = JSON.parse(
|
|
20831
|
-
await
|
|
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 (!
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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([...
|
|
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 (!
|
|
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 (!
|
|
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-
|
|
21633
|
+
//# sourceMappingURL=chunk-BHWDA2KG.js.map
|