@vosjs/cli 0.83.2 → 0.85.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 -1
- package/dist/{chunk-HDJFCTOG.js → chunk-NJBUBXFE.js} +676 -183
- package/dist/chunk-NJBUBXFE.js.map +1 -0
- package/dist/{chunk-OWYOJB7K.js → chunk-PF2NEZYU.js} +5 -1
- package/dist/chunk-PF2NEZYU.js.map +1 -0
- package/dist/cli.js +4 -4
- package/dist/index.d.ts +13 -7
- package/dist/index.js +2 -2
- package/dist/manifest-GPE4CVDR.js +8 -0
- package/dist/{run-7ZKIV6EU.js → run-XFKADM6I.js} +2 -2
- package/package.json +6 -6
- package/dist/chunk-HDJFCTOG.js.map +0 -1
- package/dist/chunk-OWYOJB7K.js.map +0 -1
- package/dist/manifest-VTOIEUHJ.js +0 -8
- /package/dist/{manifest-VTOIEUHJ.js.map → manifest-GPE4CVDR.js.map} +0 -0
- /package/dist/{run-7ZKIV6EU.js.map → run-XFKADM6I.js.map} +0 -0
|
@@ -148,9 +148,9 @@ function landedLines(l) {
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
// src/plugin/run.ts
|
|
151
|
-
import { mkdir as mkdir13, readFile as
|
|
152
|
-
import { existsSync as
|
|
153
|
-
import { dirname as
|
|
151
|
+
import { mkdir as mkdir13, readFile as readFile19, rm as rm7 } from "fs/promises";
|
|
152
|
+
import { existsSync as existsSync31 } from "fs";
|
|
153
|
+
import { dirname as dirname12, join as join33, resolve as resolve22 } from "path";
|
|
154
154
|
import {
|
|
155
155
|
END_CARD_FROM as END_CARD_FROM2,
|
|
156
156
|
docOutputDuration as docOutputDuration5,
|
|
@@ -4157,6 +4157,7 @@ import {
|
|
|
4157
4157
|
sameMedia,
|
|
4158
4158
|
spanOutputExtent as spanOutputExtent3
|
|
4159
4159
|
} from "@vosjs/studio-core";
|
|
4160
|
+
import { rankBeds, trackBySlug } from "@vosjs/shared/music";
|
|
4160
4161
|
|
|
4161
4162
|
// src/plugin/captionFit.ts
|
|
4162
4163
|
var CAPTION_MAX = 3;
|
|
@@ -4289,10 +4290,30 @@ function proposeTransitions(input, kind) {
|
|
|
4289
4290
|
}
|
|
4290
4291
|
return { doc, count, skipped };
|
|
4291
4292
|
}
|
|
4292
|
-
function
|
|
4293
|
+
function pickBed(catalog, ask, film) {
|
|
4293
4294
|
if (!catalog || !ask || off(ask)) return null;
|
|
4294
4295
|
const want = ask.trim().toLowerCase();
|
|
4295
|
-
|
|
4296
|
+
const exact = trackBySlug(catalog.tracks, want);
|
|
4297
|
+
if (exact) return { track: exact, via: "slug", ranked: null, runnerUp: null };
|
|
4298
|
+
if (film) {
|
|
4299
|
+
const oneWord = !/\s/.test(want);
|
|
4300
|
+
const ranked = rankBeds(catalog.tracks, {
|
|
4301
|
+
...film,
|
|
4302
|
+
...oneWord ? { mood: want } : { words: want }
|
|
4303
|
+
}).filter((r) => r.score !== null);
|
|
4304
|
+
const named = oneWord ? catalog.tracks.some(
|
|
4305
|
+
(t) => (t.mood ?? "").toLowerCase() === want || (t.tags ?? []).some((x) => x.toLowerCase() === want)
|
|
4306
|
+
) : ranked.some((r) => (r.scores?.fit ?? 0) > 0);
|
|
4307
|
+
if (!named || !ranked.length) return null;
|
|
4308
|
+
return {
|
|
4309
|
+
track: ranked[0].track,
|
|
4310
|
+
via: "ranked",
|
|
4311
|
+
ranked: ranked[0],
|
|
4312
|
+
runnerUp: ranked[1] ?? null
|
|
4313
|
+
};
|
|
4314
|
+
}
|
|
4315
|
+
const first = catalog.tracks.find((t) => (t.mood ?? "").toLowerCase() === want) ?? null;
|
|
4316
|
+
return first ? { track: first, via: "first", ranked: null, runnerUp: null } : null;
|
|
4296
4317
|
}
|
|
4297
4318
|
function clickTimes(doc, range2) {
|
|
4298
4319
|
const rated = ratedSegments4(doc);
|
|
@@ -4533,26 +4554,32 @@ function proposeMotion(input, opts) {
|
|
|
4533
4554
|
const clips = (doc.audio ?? []).filter(
|
|
4534
4555
|
(a) => a.id !== BED_ID && !a.id.startsWith(CLICK_ID_PREFIX)
|
|
4535
4556
|
);
|
|
4536
|
-
const
|
|
4537
|
-
if (
|
|
4557
|
+
const picked = pickBed(catalog, launch.music, opts.film);
|
|
4558
|
+
if (picked) {
|
|
4559
|
+
const { track } = picked;
|
|
4538
4560
|
const hasMic = !!doc.source.micKey;
|
|
4539
4561
|
const fadeOut = Math.min(2.5, length * 0.15);
|
|
4562
|
+
const place2 = picked.ranked?.placement ?? null;
|
|
4563
|
+
const start = place2 ? place2.in : 0;
|
|
4564
|
+
const covers = track.duration - start >= length;
|
|
4540
4565
|
clips.push({
|
|
4541
4566
|
id: BED_ID,
|
|
4542
4567
|
key: track.url,
|
|
4543
4568
|
name: track.title,
|
|
4544
4569
|
start: 0,
|
|
4545
|
-
in:
|
|
4546
|
-
out: Math.min(track.duration, length),
|
|
4570
|
+
in: start,
|
|
4571
|
+
out: place2 ? place2.out : Math.min(track.duration, length),
|
|
4547
4572
|
duration: track.duration,
|
|
4548
4573
|
gain: hasMic ? 0.35 : 0.5,
|
|
4549
|
-
fadeIn: 0.6,
|
|
4574
|
+
fadeIn: start > 0 ? 0.8 : 0.6,
|
|
4550
4575
|
fadeOut,
|
|
4551
|
-
loop:
|
|
4552
|
-
loopLen:
|
|
4576
|
+
loop: place2 ? place2.loop : !covers,
|
|
4577
|
+
loopLen: place2 ? place2.loopLen : !covers ? Math.round(length * 1e3) / 1e3 : void 0,
|
|
4553
4578
|
duck: hasMic
|
|
4554
4579
|
});
|
|
4555
|
-
notes.push(
|
|
4580
|
+
notes.push(
|
|
4581
|
+
picked.via === "ranked" && picked.ranked ? `bed ${track.slug} (${picked.ranked.reasons.slice(0, 2).join(", ") || "ranked"}${picked.runnerUp ? `; runner-up ${picked.runnerUp.slug}` : ""})` : `bed ${track.slug}`
|
|
4582
|
+
);
|
|
4556
4583
|
} else if (launch.music && !off(launch.music)) {
|
|
4557
4584
|
skipped.push(
|
|
4558
4585
|
`music "${launch.music}" is not a catalog track or mood${catalog ? "" : " (the catalog could not be read)"}`
|
|
@@ -6039,14 +6066,14 @@ function chromeTree(rows, pid) {
|
|
|
6039
6066
|
}
|
|
6040
6067
|
function readChromeTree(pid) {
|
|
6041
6068
|
if (process.platform === "win32") return Promise.resolve(null);
|
|
6042
|
-
return new Promise((
|
|
6069
|
+
return new Promise((resolve23) => {
|
|
6043
6070
|
execFile2(
|
|
6044
6071
|
"ps",
|
|
6045
6072
|
["-A", "-o", "pid=", "-o", "ppid=", "-o", "command="],
|
|
6046
6073
|
{ maxBuffer: 16 * 1024 * 1024, timeout: 5e3 },
|
|
6047
6074
|
(err, stdout) => {
|
|
6048
|
-
if (err)
|
|
6049
|
-
else
|
|
6075
|
+
if (err) resolve23(null);
|
|
6076
|
+
else resolve23(chromeTree(parseProcessTable(stdout), pid));
|
|
6050
6077
|
}
|
|
6051
6078
|
);
|
|
6052
6079
|
});
|
|
@@ -6148,7 +6175,7 @@ function enterPressed() {
|
|
|
6148
6175
|
} };
|
|
6149
6176
|
const rl = createInterface({ input: process.stdin });
|
|
6150
6177
|
const pressed = new Promise(
|
|
6151
|
-
(
|
|
6178
|
+
(resolve23) => rl.once("line", () => resolve23())
|
|
6152
6179
|
);
|
|
6153
6180
|
return { pressed, close: () => rl.close() };
|
|
6154
6181
|
}
|
|
@@ -6321,14 +6348,14 @@ async function openSessionWindow(opts) {
|
|
|
6321
6348
|
const child = spawn(exe, args, { stdio: "ignore" });
|
|
6322
6349
|
let failed = null;
|
|
6323
6350
|
let code = null;
|
|
6324
|
-
const exited = new Promise((
|
|
6351
|
+
const exited = new Promise((resolve23) => {
|
|
6325
6352
|
child.once("exit", (c) => {
|
|
6326
6353
|
code = c;
|
|
6327
|
-
|
|
6354
|
+
resolve23();
|
|
6328
6355
|
});
|
|
6329
6356
|
child.once("error", (e) => {
|
|
6330
6357
|
failed = e;
|
|
6331
|
-
|
|
6358
|
+
resolve23();
|
|
6332
6359
|
});
|
|
6333
6360
|
});
|
|
6334
6361
|
try {
|
|
@@ -6776,12 +6803,13 @@ async function encodeRecording(browser, takeDir, onProgress) {
|
|
|
6776
6803
|
// src/plugin/plan.ts
|
|
6777
6804
|
import { existsSync as existsSync11 } from "fs";
|
|
6778
6805
|
import { readFile as readFile9 } from "fs/promises";
|
|
6779
|
-
import { join as join11 } from "path";
|
|
6806
|
+
import { basename, join as join11 } from "path";
|
|
6780
6807
|
import {
|
|
6781
6808
|
DEFAULT_FRAME_STYLE,
|
|
6782
6809
|
STYLE_FIELDS,
|
|
6783
6810
|
copyLayout,
|
|
6784
6811
|
copyStyle,
|
|
6812
|
+
filmSummaryOf,
|
|
6785
6813
|
isRejected,
|
|
6786
6814
|
isStageClip,
|
|
6787
6815
|
layoutOf,
|
|
@@ -7382,7 +7410,10 @@ async function planTake(dir, opts = {}) {
|
|
|
7382
7410
|
withPageSound(doc, meta.media);
|
|
7383
7411
|
let motion;
|
|
7384
7412
|
if (opts.motion && (fresh || opts.motion.again)) {
|
|
7385
|
-
const proposed = proposeMotion(doc,
|
|
7413
|
+
const proposed = proposeMotion(doc, {
|
|
7414
|
+
...opts.motion,
|
|
7415
|
+
film: filmSummaryOf(doc, { seed: basename(join11(dir)) })
|
|
7416
|
+
});
|
|
7386
7417
|
doc = proposed.doc;
|
|
7387
7418
|
motion = {
|
|
7388
7419
|
notes: proposed.notes,
|
|
@@ -7415,14 +7446,14 @@ import { createHash } from "crypto";
|
|
|
7415
7446
|
import { existsSync as existsSync13, readFileSync as readFileSync3, readdirSync as readdirSync2 } from "fs";
|
|
7416
7447
|
import { readFile as readFile11 } from "fs/promises";
|
|
7417
7448
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
7418
|
-
import { basename as
|
|
7449
|
+
import { basename as basename3, join as join14 } from "path";
|
|
7419
7450
|
import { lowerToComposition as lowerToComposition3, migrateHostedDoc as migrateHostedDoc2 } from "@vosjs/studio-core";
|
|
7420
7451
|
|
|
7421
7452
|
// src/plugin/takeScript.ts
|
|
7422
7453
|
import { existsSync as existsSync12 } from "fs";
|
|
7423
7454
|
import { readFile as readFile10, writeFile as writeFile6 } from "fs/promises";
|
|
7424
7455
|
import { readFileSync as readFileSync2 } from "fs";
|
|
7425
|
-
import { basename, join as join12 } from "path";
|
|
7456
|
+
import { basename as basename2, join as join12 } from "path";
|
|
7426
7457
|
function scriptFromText(text) {
|
|
7427
7458
|
try {
|
|
7428
7459
|
const v = JSON.parse(text);
|
|
@@ -7468,7 +7499,7 @@ function publicPeers(peers) {
|
|
|
7468
7499
|
if (!p || typeof p !== "object") return p;
|
|
7469
7500
|
const peer = p;
|
|
7470
7501
|
if (typeof peer.storageState !== "string") return peer;
|
|
7471
|
-
return { ...peer, storageState:
|
|
7502
|
+
return { ...peer, storageState: basename2(peer.storageState) };
|
|
7472
7503
|
});
|
|
7473
7504
|
}
|
|
7474
7505
|
function embedScript(doc, dir) {
|
|
@@ -7926,10 +7957,19 @@ function printChanges(r, changes, protectedIds) {
|
|
|
7926
7957
|
r.event({ event: "protected", nodes: protectedIds });
|
|
7927
7958
|
}
|
|
7928
7959
|
}
|
|
7960
|
+
var DESCRIPTION_MAX = 500;
|
|
7961
|
+
function descriptionProblem(desc) {
|
|
7962
|
+
if (desc === void 0) return null;
|
|
7963
|
+
if (!desc.trim())
|
|
7964
|
+
return "--desc is empty: give the sentence that says what the video shows";
|
|
7965
|
+
if (desc.length > DESCRIPTION_MAX)
|
|
7966
|
+
return `--desc is ${desc.length} characters and a vos keeps ${DESCRIPTION_MAX}: shorten it`;
|
|
7967
|
+
return null;
|
|
7968
|
+
}
|
|
7929
7969
|
function takePushRefusal(ask) {
|
|
7930
7970
|
if (ask.programOnly.length) {
|
|
7931
7971
|
const list = ask.programOnly.map((f) => `--${f}`).join(", ");
|
|
7932
|
-
return `${list} ${ask.programOnly.length > 1 ? "belong" : "belongs"} to a PROGRAM push (a config.json); a take push reads --vos, --title, --label, --note, --folder, --override and --yes`;
|
|
7972
|
+
return `${list} ${ask.programOnly.length > 1 ? "belong" : "belongs"} to a PROGRAM push (a config.json); a take push reads --vos, --title, --desc, --prompt, --label, --note, --folder, --override and --yes`;
|
|
7933
7973
|
}
|
|
7934
7974
|
if (ask.vos !== void 0 && ask.trackedVosId !== null && ask.trackedVosId !== ask.vos)
|
|
7935
7975
|
return `this take tracks vos ${ask.trackedVosId} (its vos.json), not ${ask.vos}. Drop --vos to push there, or remove vos.json to adopt ${ask.vos} instead`;
|
|
@@ -8089,7 +8129,7 @@ async function pushTake(dir, flags, r) {
|
|
|
8089
8129
|
const lowered = lowerToComposition3(docForPush);
|
|
8090
8130
|
const config = { ...lowered.config, data: lowered.data };
|
|
8091
8131
|
if (!state) {
|
|
8092
|
-
const title = flags.title ?? `Take ${
|
|
8132
|
+
const title = flags.title ?? `Take ${basename3(dir)} ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`;
|
|
8093
8133
|
const slug = `${title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40) || "take"}-${Date.now().toString(36)}`;
|
|
8094
8134
|
const created = await api(ctx, "/vos", {
|
|
8095
8135
|
method: "POST",
|
|
@@ -8104,7 +8144,8 @@ async function pushTake(dir, flags, r) {
|
|
|
8104
8144
|
...folderId ? { folderId } : {},
|
|
8105
8145
|
...flags.label ? { label: flags.label } : {},
|
|
8106
8146
|
...flags.note ? { note: flags.note } : {},
|
|
8107
|
-
...flags.prompt ? { prompt: flags.prompt } : {}
|
|
8147
|
+
...flags.prompt ? { prompt: flags.prompt } : {},
|
|
8148
|
+
...flags.description ? { description: flags.description } : {}
|
|
8108
8149
|
}
|
|
8109
8150
|
});
|
|
8110
8151
|
if (created.status !== 201) {
|
|
@@ -8155,14 +8196,18 @@ async function pushTake(dir, flags, r) {
|
|
|
8155
8196
|
);
|
|
8156
8197
|
}
|
|
8157
8198
|
serverWarnings(pushed.json, (l) => r.log(l));
|
|
8158
|
-
|
|
8199
|
+
const words2 = {
|
|
8200
|
+
...flags.prompt ? { prompt: flags.prompt } : {},
|
|
8201
|
+
...flags.description ? { description: flags.description } : {}
|
|
8202
|
+
};
|
|
8203
|
+
if (Object.keys(words2).length) {
|
|
8159
8204
|
const set = await api(ctx, `/vos/${state.vosId}`, {
|
|
8160
8205
|
method: "PATCH",
|
|
8161
|
-
body:
|
|
8206
|
+
body: words2
|
|
8162
8207
|
});
|
|
8163
8208
|
if (set.status !== 200)
|
|
8164
8209
|
r.warn(
|
|
8165
|
-
`could not set the
|
|
8210
|
+
`could not set the ${Object.keys(words2).join(" and ")} (${set.status}): ${String(set.json.error ?? "")}${detailLine(set.json)}`
|
|
8166
8211
|
);
|
|
8167
8212
|
}
|
|
8168
8213
|
const version = pushed.json.version;
|
|
@@ -8276,7 +8321,7 @@ async function pullTake(dir, flags, r) {
|
|
|
8276
8321
|
const doc = hostedDoc;
|
|
8277
8322
|
const localRecording = takeMediaFile(dir, "recording", RECORDING_NAME);
|
|
8278
8323
|
if (existsSync13(localRecording)) {
|
|
8279
|
-
doc.source.videoKey =
|
|
8324
|
+
doc.source.videoKey = basename3(localRecording);
|
|
8280
8325
|
}
|
|
8281
8326
|
await writeJson(join14(dir, "doc.json"), doc, true);
|
|
8282
8327
|
const media = flags.media ? await pullMedia(ctx, dir, doc, r.log) : void 0;
|
|
@@ -8376,10 +8421,11 @@ async function pushTakeClaimable(dir, flags, r) {
|
|
|
8376
8421
|
}
|
|
8377
8422
|
const lowered = lowerToComposition3(docForPush);
|
|
8378
8423
|
const config = { ...lowered.config, data: lowered.data };
|
|
8379
|
-
const title = (flags.title ?? (state?.title ? `${state.title} remix` :
|
|
8424
|
+
const title = (flags.title ?? (state?.title ? `${state.title} remix` : basename3(dir))).slice(0, 200);
|
|
8380
8425
|
const body = { title, config, doc: docForPush };
|
|
8381
8426
|
if (state?.vosId) body.remixOfId = state.vosId;
|
|
8382
8427
|
if (flags.prompt) body.prompt = flags.prompt;
|
|
8428
|
+
if (flags.description) body.description = flags.description;
|
|
8383
8429
|
if (flags.share) body.share = true;
|
|
8384
8430
|
const origin = platformOrigin(flags);
|
|
8385
8431
|
r.log(`creating a claimable push of ${title}\u2026`);
|
|
@@ -8403,7 +8449,7 @@ async function pushTakeClaimable(dir, flags, r) {
|
|
|
8403
8449
|
import { existsSync as existsSync15 } from "fs";
|
|
8404
8450
|
import { mkdir as mkdir7, readFile as readFile12 } from "fs/promises";
|
|
8405
8451
|
import { createInterface as createInterface3 } from "readline/promises";
|
|
8406
|
-
import { basename as
|
|
8452
|
+
import { basename as basename5, dirname as dirname2, join as join15 } from "path";
|
|
8407
8453
|
import {
|
|
8408
8454
|
CURRENT_CONFIG_VERSION,
|
|
8409
8455
|
migrateConfig,
|
|
@@ -8412,7 +8458,7 @@ import {
|
|
|
8412
8458
|
import { lowerProgramDoc, migrateHostedDoc as migrateHostedDoc3 } from "@vosjs/studio-core";
|
|
8413
8459
|
|
|
8414
8460
|
// src/plugin/programFiles.ts
|
|
8415
|
-
import { basename as
|
|
8461
|
+
import { basename as basename4, extname as extname2, relative as relative2 } from "path";
|
|
8416
8462
|
import { existsSync as existsSync14, realpathSync as realpathSync2 } from "fs";
|
|
8417
8463
|
function isLocalName(value) {
|
|
8418
8464
|
if (/^(https?:|data:|blob:|asset:|media:)/.test(value)) return false;
|
|
@@ -8423,7 +8469,7 @@ function isLocalName(value) {
|
|
|
8423
8469
|
}
|
|
8424
8470
|
var FILE_EXT = /\.(png|jpe?g|webp|gif|avif|svg|mp4|webm|mov|mp3|m4a|ogg|wav|flac|aac|glb|gltf|woff2?|ttf|otf|hdr|exr)$/i;
|
|
8425
8471
|
function manifestName(file, taken) {
|
|
8426
|
-
const stem =
|
|
8472
|
+
const stem = basename4(file, extname2(file)).replace(/[^A-Za-z0-9_]/g, "_").replace(/^(?=[0-9])/, "_") || "file";
|
|
8427
8473
|
let name = stem;
|
|
8428
8474
|
for (let n = 2; taken.has(name); n++) name = `${stem}_${n}`;
|
|
8429
8475
|
taken.add(name);
|
|
@@ -8842,7 +8888,7 @@ async function cmdPushProgram(argv) {
|
|
|
8842
8888
|
"--claimable creates a NEW claimable vos and cannot iterate (--vos). After the human claims it, iterate with their key: vos push --vos <id>"
|
|
8843
8889
|
);
|
|
8844
8890
|
}
|
|
8845
|
-
const fallback = state?.title ? `${state.title} remix` :
|
|
8891
|
+
const fallback = state?.title ? `${state.title} remix` : basename5(source).replace(/\.json$/i, "") || "vos program";
|
|
8846
8892
|
const title2 = (strFlag(flags, "title") ?? fallback).slice(0, 100);
|
|
8847
8893
|
const files2 = await collectFiles(config, programDoc, dir, r);
|
|
8848
8894
|
let uploadToken;
|
|
@@ -8918,9 +8964,11 @@ with their key: vos push ${source} --vos ${String(created2.id ?? "<id>")}`
|
|
|
8918
8964
|
});
|
|
8919
8965
|
if (pushTarget.kind === "refuse") throw new UsageError(pushTarget.why);
|
|
8920
8966
|
const vosId = pushTarget.kind === "version" ? pushTarget.vosId : null;
|
|
8921
|
-
|
|
8967
|
+
const descProblem = descriptionProblem(desc);
|
|
8968
|
+
if (descProblem) throw new UsageError(descProblem);
|
|
8969
|
+
if (vosId && (tagsFlag || folderRef)) {
|
|
8922
8970
|
throw new UsageError(
|
|
8923
|
-
"--
|
|
8971
|
+
"--tags/--folder apply when CREATING a vos. On an existing one: vos folder move <id> --to <folder> for filing; edit tags on vos.so"
|
|
8924
8972
|
);
|
|
8925
8973
|
}
|
|
8926
8974
|
if (vosId) {
|
|
@@ -8966,13 +9014,18 @@ with their key: vos push ${source} --vos ${String(created2.id ?? "<id>")}`
|
|
|
8966
9014
|
if (res.status !== 201)
|
|
8967
9015
|
throw new Error(apiError(`push version to ${vosId}`, res));
|
|
8968
9016
|
serverWarnings(res.body, say(r));
|
|
8969
|
-
|
|
9017
|
+
const words2 = {
|
|
9018
|
+
...prompt ? { prompt } : {},
|
|
9019
|
+
...desc ? { description: desc } : {}
|
|
9020
|
+
};
|
|
9021
|
+
if (Object.keys(words2).length) {
|
|
8970
9022
|
const set = await apiJson(origin, `/api/vos/${vosId}`, {
|
|
8971
9023
|
method: "PATCH",
|
|
8972
9024
|
key,
|
|
8973
|
-
body:
|
|
9025
|
+
body: words2
|
|
8974
9026
|
});
|
|
8975
|
-
if (set.status !== 200)
|
|
9027
|
+
if (set.status !== 200)
|
|
9028
|
+
r.warn(apiError(`set the ${Object.keys(words2).join(" and ")}`, set));
|
|
8976
9029
|
}
|
|
8977
9030
|
const version = res.body.version ?? {};
|
|
8978
9031
|
if (typeof version.id === "string") {
|
|
@@ -9009,7 +9062,7 @@ ${landedLines(landed2)}` : "")
|
|
|
9009
9062
|
return EXIT_OK;
|
|
9010
9063
|
}
|
|
9011
9064
|
const remixOfId = pushTarget.kind === "create" ? pushTarget.remixOfId : void 0;
|
|
9012
|
-
const fallbackTitle = state?.title ? `${state.title} remix` :
|
|
9065
|
+
const fallbackTitle = state?.title ? `${state.title} remix` : basename5(source).replace(/\.json$/i, "") || "vos remix";
|
|
9013
9066
|
const title = (strFlag(flags, "title") ?? fallbackTitle).slice(0, 100);
|
|
9014
9067
|
const pushFolder = folderRef ? await resolvePushFolder(origin, key, folderRef) : void 0;
|
|
9015
9068
|
const folderId = pushFolder?.id;
|
|
@@ -9335,7 +9388,7 @@ async function writeProgramDoc(dir, hosted) {
|
|
|
9335
9388
|
// src/plugin/asset.ts
|
|
9336
9389
|
import { createHash as createHash2 } from "crypto";
|
|
9337
9390
|
import { readFileSync as readFileSync4 } from "fs";
|
|
9338
|
-
import { basename as
|
|
9391
|
+
import { basename as basename6 } from "path";
|
|
9339
9392
|
|
|
9340
9393
|
// src/plugin/assetWords.ts
|
|
9341
9394
|
function hostedFile(raw) {
|
|
@@ -9600,7 +9653,7 @@ async function cmdPush(argv) {
|
|
|
9600
9653
|
const folder = folderRef ? resolveFolder(await listFolders(origin, key), folderRef) : null;
|
|
9601
9654
|
const uploaded = [];
|
|
9602
9655
|
for (const file of positionals) {
|
|
9603
|
-
const name =
|
|
9656
|
+
const name = basename6(file);
|
|
9604
9657
|
const body = readFileSync4(file);
|
|
9605
9658
|
const media = resolveMediaType({
|
|
9606
9659
|
head: body.subarray(0, MEDIA_HEAD_BYTES),
|
|
@@ -10118,7 +10171,7 @@ function trackingCwd(vosId) {
|
|
|
10118
10171
|
|
|
10119
10172
|
// src/plugin/buildProgram.ts
|
|
10120
10173
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
|
|
10121
|
-
import { basename as
|
|
10174
|
+
import { basename as basename7, dirname as dirname3, join as join17, resolve as resolve8 } from "path";
|
|
10122
10175
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
10123
10176
|
import { parse } from "acorn";
|
|
10124
10177
|
import { fullAncestor } from "acorn-walk";
|
|
@@ -10326,7 +10379,7 @@ async function cmdBuild(argv) {
|
|
|
10326
10379
|
throw new UsageError(
|
|
10327
10380
|
`${source} exports no program: \`export default { version: 2, duration, camera, createContent, createTimeline, \u2026 }\``
|
|
10328
10381
|
);
|
|
10329
|
-
const built = buildProgram(program,
|
|
10382
|
+
const built = buildProgram(program, basename7(file), text);
|
|
10330
10383
|
for (const p of built.problems) r.log(`error ${p.fn}: ${p.message}`);
|
|
10331
10384
|
if (built.problems.length) {
|
|
10332
10385
|
r.done(
|
|
@@ -10561,7 +10614,7 @@ import { findFontFamily as findFontFamily3 } from "@vosjs/shared";
|
|
|
10561
10614
|
import { existsSync as existsSync18, readFileSync as readFileSync6, readdirSync as readdirSync3, statSync as statSync5 } from "fs";
|
|
10562
10615
|
import { createServer as createServer2 } from "http";
|
|
10563
10616
|
import { createRequire } from "module";
|
|
10564
|
-
import { basename as
|
|
10617
|
+
import { basename as basename8, extname as extname3, join as join19 } from "path";
|
|
10565
10618
|
function themeColors(sources) {
|
|
10566
10619
|
const out = {};
|
|
10567
10620
|
const re = /\bconst\s+([A-Za-z_$][\w$]*)\s*(?::\s*string\s*)?=\s*['"](#[0-9a-fA-F]{3,8})['"]/g;
|
|
@@ -10841,7 +10894,7 @@ async function readRemotion(dir, log) {
|
|
|
10841
10894
|
const sources = sourceTexts(dir);
|
|
10842
10895
|
const publicDir = join19(dir, "public");
|
|
10843
10896
|
const media = tree.audio.map((a) => {
|
|
10844
|
-
const name =
|
|
10897
|
+
const name = basename8(a.src.split("?")[0]);
|
|
10845
10898
|
const local = existsSync18(join19(publicDir, name)) ? `public/${name}` : a.src;
|
|
10846
10899
|
return {
|
|
10847
10900
|
kind: "audio",
|
|
@@ -11344,7 +11397,7 @@ async function readInventory(source, opts) {
|
|
|
11344
11397
|
// src/plugin/portScaffold.ts
|
|
11345
11398
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
11346
11399
|
import { copyFileSync, existsSync as existsSync20, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
11347
|
-
import { basename as
|
|
11400
|
+
import { basename as basename9, dirname as dirname6, join as join21, resolve as resolve11 } from "path";
|
|
11348
11401
|
import { findFontFamily as findFontFamily4, fontFaceUrl, nearestFontWeight } from "@vosjs/shared";
|
|
11349
11402
|
|
|
11350
11403
|
// src/plugin/painterLib.ts
|
|
@@ -11754,7 +11807,7 @@ function planScaffold(inv, opts) {
|
|
|
11754
11807
|
const copies = [];
|
|
11755
11808
|
inv.media.filter((m) => m.kind === "audio" && m.src).forEach((m, i) => {
|
|
11756
11809
|
const from = resolve11(opts.sourceDir, m.src);
|
|
11757
|
-
const name =
|
|
11810
|
+
const name = basename9(from);
|
|
11758
11811
|
if (!existsSync20(from)) {
|
|
11759
11812
|
report.push(
|
|
11760
11813
|
`- the audio ${m.src} is not in the source folder; add it to doc.json by hand`
|
|
@@ -11907,7 +11960,7 @@ ${sceneTodos}${springHint}
|
|
|
11907
11960
|
}
|
|
11908
11961
|
function reportText(inv, r) {
|
|
11909
11962
|
const lines = [
|
|
11910
|
-
`# Port report: ${inv.source === "." && inv.root ?
|
|
11963
|
+
`# Port report: ${inv.source === "." && inv.root ? basename9(inv.root) : inv.source}`,
|
|
11911
11964
|
"",
|
|
11912
11965
|
`${inv.engine} piece, ${inv.width}\xD7${inv.height}${inv.fps ? ` at ${inv.fps} fps` : ""}, ${inv.duration ?? "?"} s. A program has no size of its own: render it with \`--width ${inv.width} --height ${inv.height}\`.`,
|
|
11913
11966
|
"",
|
|
@@ -12071,11 +12124,11 @@ function scaffoldSourceDir(inv) {
|
|
|
12071
12124
|
// src/plugin/recipe.ts
|
|
12072
12125
|
import { createHash as createHash3 } from "crypto";
|
|
12073
12126
|
import { readFileSync as readFileSync9 } from "fs";
|
|
12074
|
-
import { basename as
|
|
12127
|
+
import { basename as basename10 } from "path";
|
|
12075
12128
|
var BOOLEAN_FLAGS9 = /* @__PURE__ */ new Set(["json", "help"]);
|
|
12076
12129
|
var USAGE = "vos recipe push <file.md> (--folder <folderId|slug> | --asset <assetId>)";
|
|
12077
12130
|
function recipeFilename(file) {
|
|
12078
|
-
const name =
|
|
12131
|
+
const name = basename10(file);
|
|
12079
12132
|
if (!/\.md$/i.test(name)) {
|
|
12080
12133
|
throw new UsageError(`a recipe is a markdown file \u2014 ${name} is not .md`);
|
|
12081
12134
|
}
|
|
@@ -13129,8 +13182,8 @@ async function cmdActions(argv) {
|
|
|
13129
13182
|
if (!m) throw new UsageError("--viewport expects WxH, e.g. 1280x720");
|
|
13130
13183
|
viewport = { width: Number(m[1]), height: Number(m[2]) };
|
|
13131
13184
|
}
|
|
13132
|
-
const { readFile:
|
|
13133
|
-
const text = await
|
|
13185
|
+
const { readFile: readFile20 } = await import("fs/promises");
|
|
13186
|
+
const text = await readFile20(resolve14(input), "utf8");
|
|
13134
13187
|
const { records, problems } = parseAgentBrowserLog(text);
|
|
13135
13188
|
for (const p of problems) r.log(` ${p}`);
|
|
13136
13189
|
const result = convertAgentBrowser(records, {
|
|
@@ -13167,9 +13220,9 @@ function summary2(result) {
|
|
|
13167
13220
|
}
|
|
13168
13221
|
async function cmdActionsScript(input, flags) {
|
|
13169
13222
|
const r = createReporter(flags.json === true);
|
|
13170
|
-
const { readFile:
|
|
13223
|
+
const { readFile: readFile20 } = await import("fs/promises");
|
|
13171
13224
|
const { shotList, formatShotList } = await import("./shotList-PL7XP6AC.js");
|
|
13172
|
-
const raw = JSON.parse(await
|
|
13225
|
+
const raw = JSON.parse(await readFile20(resolve14(input), "utf8"));
|
|
13173
13226
|
const errors = validateActions(raw);
|
|
13174
13227
|
if (errors.length) throw new UsageError(`${input}:
|
|
13175
13228
|
${errors.join("\n ")}`);
|
|
@@ -13181,7 +13234,7 @@ async function cmdActionsScript(input, flags) {
|
|
|
13181
13234
|
// src/plugin/ingest.ts
|
|
13182
13235
|
import { existsSync as existsSync22 } from "fs";
|
|
13183
13236
|
import { copyFile, mkdir as mkdir8, readFile as readFile13, stat as stat2 } from "fs/promises";
|
|
13184
|
-
import { basename as
|
|
13237
|
+
import { basename as basename11, join as join23, resolve as resolve15 } from "path";
|
|
13185
13238
|
|
|
13186
13239
|
// src/plugin/traceInflate.ts
|
|
13187
13240
|
import { inflateRawSync } from "zlib";
|
|
@@ -13308,7 +13361,7 @@ async function copyRecording(src, dest, ext2) {
|
|
|
13308
13361
|
}
|
|
13309
13362
|
}
|
|
13310
13363
|
async function readTraceFile(path, offsetMs) {
|
|
13311
|
-
const kind = traceKindOf(
|
|
13364
|
+
const kind = traceKindOf(basename11(path));
|
|
13312
13365
|
if (!kind) {
|
|
13313
13366
|
throw new UsageError(
|
|
13314
13367
|
`${path}: not a trace the recorder reads (trace.zip, .trace, .jsonl, .json or .csv)`
|
|
@@ -13329,7 +13382,7 @@ async function readTraceFile(path, offsetMs) {
|
|
|
13329
13382
|
return cursorFromPlaywrightTrace(text2, { offsetMs });
|
|
13330
13383
|
}
|
|
13331
13384
|
const text = await readFile13(path, "utf8");
|
|
13332
|
-
return cursorFromTrace(
|
|
13385
|
+
return cursorFromTrace(basename11(path), text, { offsetMs });
|
|
13333
13386
|
}
|
|
13334
13387
|
function parseViewport(v) {
|
|
13335
13388
|
if (!v) return null;
|
|
@@ -13360,7 +13413,7 @@ async function cmdIngest(argv) {
|
|
|
13360
13413
|
"note: finished footage opens bare, so --background is not used (pass --as take for the screen-recording card and its ground)"
|
|
13361
13414
|
);
|
|
13362
13415
|
const backdrop = footage ? null : await takeBackdrop(flags, r);
|
|
13363
|
-
r.log(`probing ${
|
|
13416
|
+
r.log(`probing ${basename11(videoPath)}\u2026`);
|
|
13364
13417
|
const probed = await probeVideoFile(videoPath);
|
|
13365
13418
|
if (!(probed.durationMs > 0)) {
|
|
13366
13419
|
throw new UsageError(
|
|
@@ -13409,13 +13462,13 @@ async function cmdIngest(argv) {
|
|
|
13409
13462
|
const clicks = events.filter((e) => e.type === "down").length;
|
|
13410
13463
|
const seconds = (probed.durationMs / 1e3).toFixed(1);
|
|
13411
13464
|
const facts = `${seconds}s, ${probed.width}\xD7${probed.height} @ ${meta.fps} fps${probed.hasAudio ? ", audio" : ", no audio"}${remuxed ? "" : ", copied as is"}`;
|
|
13412
|
-
const cursorLine = trace ? `${events.length} cursor events (${clicks} clicks) from ${
|
|
13465
|
+
const cursorLine = trace ? `${events.length} cursor events (${clicks} clicks) from ${basename11(cursorPath)}${trace.dropped ? `, ${trace.dropped} not placed` : ""}; ${plan.zoomAuto} zoom${plan.zoomAuto === 1 ? "" : "s"} planned` : "no cursor track, so nothing was planned";
|
|
13413
13466
|
const opened = footage ? `opened as finished footage: no card, no browser bar, no drawn cursor, ${meta.fps > 30 ? 60 : 30} fps export (--as take for a screen recording's card)` : `opened as a screen recording: the card, its ground and the drawn cursor (--as footage to open it bare)`;
|
|
13414
13467
|
const next = footage && !trace ? `Next: vos push ${outDir} --wait \u2014 it lands as it is; trim or add to it in the studio` : 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`;
|
|
13415
13468
|
r.done(
|
|
13416
13469
|
{
|
|
13417
13470
|
out: outDir,
|
|
13418
|
-
recording:
|
|
13471
|
+
recording: basename11(recording),
|
|
13419
13472
|
durationMs: probed.durationMs,
|
|
13420
13473
|
width: probed.width,
|
|
13421
13474
|
height: probed.height,
|
|
@@ -13424,7 +13477,7 @@ async function cmdIngest(argv) {
|
|
|
13424
13477
|
hasAudio: probed.hasAudio,
|
|
13425
13478
|
remuxed,
|
|
13426
13479
|
cursor: trace ? {
|
|
13427
|
-
file:
|
|
13480
|
+
file: basename11(cursorPath),
|
|
13428
13481
|
kind: trace.kind,
|
|
13429
13482
|
events: events.length,
|
|
13430
13483
|
clicks,
|
|
@@ -13436,7 +13489,7 @@ async function cmdIngest(argv) {
|
|
|
13436
13489
|
backdrop: plan.backdrop ?? null,
|
|
13437
13490
|
as: footage ? "footage" : "take"
|
|
13438
13491
|
},
|
|
13439
|
-
`Ingested ${
|
|
13492
|
+
`Ingested ${basename11(videoPath)} \u2192 ${outDir}/${basename11(recording)} (${facts})
|
|
13440
13493
|
${opened}
|
|
13441
13494
|
${cursorLine}
|
|
13442
13495
|
${next}`
|
|
@@ -13448,7 +13501,7 @@ async function cmdIngest(argv) {
|
|
|
13448
13501
|
import { createRequire as createRequire2 } from "module";
|
|
13449
13502
|
import { existsSync as existsSync23 } from "fs";
|
|
13450
13503
|
import { mkdir as mkdir9, readFile as readFile14, stat as stat3, writeFile as writeFile7 } from "fs/promises";
|
|
13451
|
-
import { basename as
|
|
13504
|
+
import { basename as basename12, dirname as dirname8, extname as extname4, join as join24, resolve as resolve16 } from "path";
|
|
13452
13505
|
import { ALL_FORMATS as ALL_FORMATS2, FilePathSource as FilePathSource2, Input as Input2 } from "mediabunny";
|
|
13453
13506
|
|
|
13454
13507
|
// src/plugin/videoChecks.ts
|
|
@@ -13970,7 +14023,7 @@ async function checkVideo(browser, file, outDir) {
|
|
|
13970
14023
|
void page.evaluate(decodeInPage, {
|
|
13971
14024
|
mbCode: await mediabunnyBundle(),
|
|
13972
14025
|
meterSrc: String(createLoudnessMeter),
|
|
13973
|
-
videoUrl: `/${encodeURIComponent(
|
|
14026
|
+
videoUrl: `/${encodeURIComponent(basename12(file))}`,
|
|
13974
14027
|
sampleFps,
|
|
13975
14028
|
thumbW: side(facts.width),
|
|
13976
14029
|
thumbH: side(facts.height),
|
|
@@ -14078,7 +14131,7 @@ async function cmdCheckVideo(argv) {
|
|
|
14078
14131
|
const r = createReporter(flags.json === true);
|
|
14079
14132
|
const strict = flags.strict === true;
|
|
14080
14133
|
const outDir = resolve16(
|
|
14081
|
-
strFlag(flags, "out") ?? join24(dirname8(file), `${
|
|
14134
|
+
strFlag(flags, "out") ?? join24(dirname8(file), `${basename12(file, extname4(file))}-check`)
|
|
14082
14135
|
);
|
|
14083
14136
|
const browser = await launchBrowser();
|
|
14084
14137
|
try {
|
|
@@ -14096,7 +14149,7 @@ async function cmdCheckVideo(argv) {
|
|
|
14096
14149
|
import { existsSync as existsSync26, readdirSync as readdirSync5, statSync as statSync7 } from "fs";
|
|
14097
14150
|
import { copyFile as copyFile3, mkdir as mkdir11, readFile as readFile17, rm as rm4 } from "fs/promises";
|
|
14098
14151
|
import {
|
|
14099
|
-
basename as
|
|
14152
|
+
basename as basename14,
|
|
14100
14153
|
dirname as dirname9,
|
|
14101
14154
|
isAbsolute as isAbsolute4,
|
|
14102
14155
|
join as join27,
|
|
@@ -14127,13 +14180,15 @@ import {
|
|
|
14127
14180
|
writeFile as writeFile8
|
|
14128
14181
|
} from "fs/promises";
|
|
14129
14182
|
import { tmpdir as tmpdir2 } from "os";
|
|
14130
|
-
import { basename as
|
|
14183
|
+
import { basename as basename13, isAbsolute as isAbsolute3, join as join25, relative as relative4, resolve as resolve17, sep as sep3 } from "path";
|
|
14184
|
+
import { rankBeds as rankBeds2 } from "@vosjs/shared/music";
|
|
14131
14185
|
import {
|
|
14132
14186
|
NORMALIZE_MAX_LUFS as NORMALIZE_MAX_LUFS2,
|
|
14133
14187
|
NORMALIZE_MIN_LUFS as NORMALIZE_MIN_LUFS2,
|
|
14134
14188
|
clipGain as clipGain2,
|
|
14135
14189
|
docMediaList,
|
|
14136
14190
|
docOutputDuration as docOutputDuration3,
|
|
14191
|
+
filmSummaryOf as filmSummaryOf2,
|
|
14137
14192
|
findStep as findStep2,
|
|
14138
14193
|
ratedSegments as ratedSegments7,
|
|
14139
14194
|
resolveAnchor as resolveAnchor4
|
|
@@ -14442,7 +14497,7 @@ async function measureInBrowser(path) {
|
|
|
14442
14497
|
const bytes = await readFile15(path);
|
|
14443
14498
|
if (bytes.length > BROWSER_DECODE_MAX_BYTES)
|
|
14444
14499
|
throw new Error(
|
|
14445
|
-
`${
|
|
14500
|
+
`${basename13(path)} is ${Math.round(bytes.length / 1048576)} MB, past the ${BROWSER_DECODE_MAX_BYTES / 1048576} MB the browser decode takes whole`
|
|
14446
14501
|
);
|
|
14447
14502
|
const browser = await launchBrowser();
|
|
14448
14503
|
try {
|
|
@@ -14546,12 +14601,12 @@ async function resolveTrack(dir, ref, flags, dryRun) {
|
|
|
14546
14601
|
if (existsSync24(local)) {
|
|
14547
14602
|
const rel = relative4(resolve17(dir), local);
|
|
14548
14603
|
const inside = !!rel && !rel.startsWith(`..${sep3}`) && rel !== ".." && !isAbsolute3(rel);
|
|
14549
|
-
const key = inside ? rel.split(sep3).join("/") : `music/${
|
|
14604
|
+
const key = inside ? rel.split(sep3).join("/") : `music/${basename13(local)}`;
|
|
14550
14605
|
if (!inside && !dryRun) {
|
|
14551
14606
|
await mkdir10(join25(dir, "music"), { recursive: true });
|
|
14552
14607
|
await copyFile2(local, join25(dir, key));
|
|
14553
14608
|
}
|
|
14554
|
-
return { path: local, key, name:
|
|
14609
|
+
return { path: local, key, name: basename13(local) };
|
|
14555
14610
|
}
|
|
14556
14611
|
const origin = platformOrigin({
|
|
14557
14612
|
origin: strFlag(flags, "origin"),
|
|
@@ -14566,7 +14621,7 @@ async function resolveTrack(dir, ref, flags, dryRun) {
|
|
|
14566
14621
|
const res = await fetch(track.url);
|
|
14567
14622
|
if (!res.ok) throw new Error(`GET ${track.url} answered ${res.status}`);
|
|
14568
14623
|
const tmp = await mkdtemp(join25(tmpdir2(), "vos-score-"));
|
|
14569
|
-
const path = join25(tmp,
|
|
14624
|
+
const path = join25(tmp, basename13(new URL(track.url).pathname) || "track");
|
|
14570
14625
|
await writeFile8(path, new Uint8Array(await res.arrayBuffer()));
|
|
14571
14626
|
return {
|
|
14572
14627
|
path,
|
|
@@ -14576,7 +14631,7 @@ async function resolveTrack(dir, ref, flags, dryRun) {
|
|
|
14576
14631
|
};
|
|
14577
14632
|
}
|
|
14578
14633
|
var BOOLEAN_FLAGS12 = /* @__PURE__ */ new Set(["json", "help", "dry-run"]);
|
|
14579
|
-
var USAGE2 =
|
|
14634
|
+
var USAGE2 = 'vos score <take> --track <slug|file|best> [--at <step id|output seconds>] [--mood <slug|tag>] [--words "\u2026"] [--gain 0..1] [--normalize <lufs|off>] [--fade-in <s>] [--fade-out <s>] [--dry-run] [--json]';
|
|
14580
14635
|
async function cmdScore(argv) {
|
|
14581
14636
|
const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS12);
|
|
14582
14637
|
const dir = positionals[0];
|
|
@@ -14603,8 +14658,39 @@ async function cmdScore(argv) {
|
|
|
14603
14658
|
throw new UsageError(`${dir} has no doc.json; run vos plan first`);
|
|
14604
14659
|
const doc = take.doc;
|
|
14605
14660
|
const atRaw = strFlag(flags, "at");
|
|
14606
|
-
|
|
14607
|
-
|
|
14661
|
+
let at2 = atRaw !== void 0 ? resolveAt(doc, atRaw) : null;
|
|
14662
|
+
let chosen = trackRef;
|
|
14663
|
+
if (trackRef === "best") {
|
|
14664
|
+
const origin = platformOrigin({
|
|
14665
|
+
origin: strFlag(flags, "origin"),
|
|
14666
|
+
api: strFlag(flags, "api")
|
|
14667
|
+
});
|
|
14668
|
+
const catalog = await fetchMusicCatalog(origin);
|
|
14669
|
+
const film2 = filmSummaryOf2(doc, {
|
|
14670
|
+
seed: readSyncState(dir)?.vosId ?? basename13(resolve17(dir)),
|
|
14671
|
+
...at2 ? { payoff: at2.at } : {},
|
|
14672
|
+
mood: strFlag(flags, "mood"),
|
|
14673
|
+
words: strFlag(flags, "words")
|
|
14674
|
+
});
|
|
14675
|
+
const ranked = rankBeds2(catalog.tracks, film2).filter(
|
|
14676
|
+
(x) => x.score !== null
|
|
14677
|
+
);
|
|
14678
|
+
const best = ranked[0];
|
|
14679
|
+
if (!best)
|
|
14680
|
+
throw new UsageError(
|
|
14681
|
+
`no bed in the library fits this ${film2.duration.toFixed(1)}s film (every track refused); compose a score instead, or name a track with --track <slug>`
|
|
14682
|
+
);
|
|
14683
|
+
chosen = best.slug;
|
|
14684
|
+
if (!at2 && film2.payoff !== void 0)
|
|
14685
|
+
at2 = {
|
|
14686
|
+
at: film2.payoff,
|
|
14687
|
+
via: `the film's payoff (${film2.payoff.toFixed(2)}s)`
|
|
14688
|
+
};
|
|
14689
|
+
r.log(
|
|
14690
|
+
`picked ${best.slug} (${best.reasons.join("; ") || "ranked first"})${ranked[1] ? `; runner-up ${ranked[1].slug}` : ""}`
|
|
14691
|
+
);
|
|
14692
|
+
}
|
|
14693
|
+
const track = await resolveTrack(dir, chosen, flags, dryRun);
|
|
14608
14694
|
let measured;
|
|
14609
14695
|
try {
|
|
14610
14696
|
r.log(`measuring ${track.name}\u2026`);
|
|
@@ -16198,7 +16284,7 @@ function joinDocs(parts, opts = {}) {
|
|
|
16198
16284
|
{
|
|
16199
16285
|
id,
|
|
16200
16286
|
key: d.source.videoKey,
|
|
16201
|
-
name:
|
|
16287
|
+
name: basename14(part.file.path),
|
|
16202
16288
|
start: round33(at2.start),
|
|
16203
16289
|
in: round33(seg.in),
|
|
16204
16290
|
out: round33(seg.out),
|
|
@@ -16443,7 +16529,7 @@ async function cmdJoin(argv) {
|
|
|
16443
16529
|
const remuxed = await copyRecording(c.from, to, c.remux);
|
|
16444
16530
|
if (!remuxed && c.remux !== "mov")
|
|
16445
16531
|
plan.notes.push(
|
|
16446
|
-
`could not read ${
|
|
16532
|
+
`could not read ${basename14(c.from)}'s audio in Node, so it was copied as it is; its length comes from the container`
|
|
16447
16533
|
);
|
|
16448
16534
|
} else await copyFile3(c.from, to);
|
|
16449
16535
|
}
|
|
@@ -16817,7 +16903,7 @@ async function cmdTakeInfo(argv) {
|
|
|
16817
16903
|
// src/plugin/audio.ts
|
|
16818
16904
|
import { mkdtemp as mkdtemp2, rm as rm5, writeFile as writeFile9 } from "fs/promises";
|
|
16819
16905
|
import { tmpdir as tmpdir3 } from "os";
|
|
16820
|
-
import { basename as
|
|
16906
|
+
import { basename as basename15, join as join29 } from "path";
|
|
16821
16907
|
import { clipGain as clipGain3 } from "@vosjs/studio-core";
|
|
16822
16908
|
var USAGE4 = "vos audio measure <take> [--json]";
|
|
16823
16909
|
async function fileFor(dir, key, fetchImpl) {
|
|
@@ -16830,7 +16916,7 @@ async function fileFor(dir, key, fetchImpl) {
|
|
|
16830
16916
|
const res = await fetchImpl(key);
|
|
16831
16917
|
if (!res.ok) return { skipped: `GET ${key} answered ${res.status}` };
|
|
16832
16918
|
const tmp = await mkdtemp2(join29(tmpdir3(), "vos-audio-"));
|
|
16833
|
-
const path = join29(tmp,
|
|
16919
|
+
const path = join29(tmp, basename15(new URL(key).pathname) || "audio");
|
|
16834
16920
|
await writeFile9(path, new Uint8Array(await res.arrayBuffer()));
|
|
16835
16921
|
return { path, cleanup: () => rm5(tmp, { recursive: true, force: true }) };
|
|
16836
16922
|
}
|
|
@@ -16910,10 +16996,238 @@ async function cmdAudio(argv) {
|
|
|
16910
16996
|
return failed.length ? EXIT_ERROR : EXIT_OK;
|
|
16911
16997
|
}
|
|
16912
16998
|
|
|
16999
|
+
// src/plugin/musicCmd.ts
|
|
17000
|
+
import { existsSync as existsSync27, readFileSync as readFileSync10, statSync as statSync8 } from "fs";
|
|
17001
|
+
import { basename as basename16, resolve as resolve20 } from "path";
|
|
17002
|
+
import { rankBeds as rankBeds3, trackBySlug as trackBySlug2 } from "@vosjs/shared/music";
|
|
17003
|
+
import { filmSummaryOf as filmSummaryOf3, musicSlugsOfDoc } from "@vosjs/studio-core";
|
|
17004
|
+
var BOOLEAN_FLAGS14 = /* @__PURE__ */ new Set([
|
|
17005
|
+
"json",
|
|
17006
|
+
"help",
|
|
17007
|
+
"loops",
|
|
17008
|
+
"voice",
|
|
17009
|
+
"no-voice",
|
|
17010
|
+
"fade-in"
|
|
17011
|
+
]);
|
|
17012
|
+
var MULTI_FLAGS3 = /* @__PURE__ */ new Set(["like"]);
|
|
17013
|
+
var USAGE5 = 'vos music ls [--mood <slug>] [--vocals none|chops|lead] [--loops] [--bpm <lo>-<hi>] [--min-length <s>] [--q <words>] [--json]\nvos music pick <take|config.json> [--at <step id|seconds>] [--mood <slug|tag>] [--words "\u2026"] [--voice|--no-voice] [--like <vos id|slug>]... [--top <n>] [--json]';
|
|
17014
|
+
var mmss = (s) => {
|
|
17015
|
+
const whole = Math.round(s);
|
|
17016
|
+
return `${Math.floor(whole / 60)}:${String(whole % 60).padStart(2, "0")}`;
|
|
17017
|
+
};
|
|
17018
|
+
var VOCAL_WORDS = {
|
|
17019
|
+
none: "no vocals",
|
|
17020
|
+
chops: "vocal chops",
|
|
17021
|
+
lead: "sung lead"
|
|
17022
|
+
};
|
|
17023
|
+
function trackLine(t) {
|
|
17024
|
+
const bpm = t.bpm === null || t.bpm === void 0 ? "\u2014" : `${t.bpm} bpm${t.beatConfidence === "low" ? "?" : t.beatConfidence === "confirmed" ? "" : ""}`;
|
|
17025
|
+
return [
|
|
17026
|
+
t.slug.padEnd(26),
|
|
17027
|
+
(t.mood ?? "").padEnd(10),
|
|
17028
|
+
mmss(t.duration).padStart(5),
|
|
17029
|
+
bpm.padStart(10),
|
|
17030
|
+
VOCAL_WORDS[t.vocals ?? "none"].padEnd(11),
|
|
17031
|
+
t.loops ? "loops" : " ",
|
|
17032
|
+
t.description ? JSON.stringify(t.description) : ""
|
|
17033
|
+
].join(" ");
|
|
17034
|
+
}
|
|
17035
|
+
function bpmRange(raw) {
|
|
17036
|
+
if (!raw) return null;
|
|
17037
|
+
const m = /^(\d+(?:\.\d+)?)\s*-\s*(\d+(?:\.\d+)?)$/.exec(raw.trim());
|
|
17038
|
+
if (m) return [Number(m[1]), Number(m[2])];
|
|
17039
|
+
const one = Number(raw);
|
|
17040
|
+
if (Number.isFinite(one)) return [one, Infinity];
|
|
17041
|
+
throw new UsageError(`--bpm expects <lo>-<hi>, got "${raw}"`);
|
|
17042
|
+
}
|
|
17043
|
+
function filterTracks(tracks, f) {
|
|
17044
|
+
const q = f.q?.toLowerCase().trim();
|
|
17045
|
+
const words2 = q ? q.split(/\s+/).filter(Boolean) : [];
|
|
17046
|
+
return tracks.filter((t) => {
|
|
17047
|
+
if (t.removedAt) return false;
|
|
17048
|
+
if (f.mood && (t.mood ?? "").toLowerCase() !== f.mood.toLowerCase()) {
|
|
17049
|
+
if (!(t.tags ?? []).some((x) => x.toLowerCase() === f.mood.toLowerCase()))
|
|
17050
|
+
return false;
|
|
17051
|
+
}
|
|
17052
|
+
if (f.vocals && (t.vocals ?? "none") !== f.vocals) return false;
|
|
17053
|
+
if (f.loops && !t.loops) return false;
|
|
17054
|
+
if (f.bpm) {
|
|
17055
|
+
if (t.bpm === null || t.bpm === void 0) return false;
|
|
17056
|
+
if (t.bpm < f.bpm[0] || t.bpm > f.bpm[1]) return false;
|
|
17057
|
+
}
|
|
17058
|
+
if (f.minLength !== void 0 && t.duration < f.minLength && !t.loops)
|
|
17059
|
+
return false;
|
|
17060
|
+
if (words2.length) {
|
|
17061
|
+
const hay = [
|
|
17062
|
+
t.slug,
|
|
17063
|
+
t.title,
|
|
17064
|
+
t.artist ?? "",
|
|
17065
|
+
t.mood ?? "",
|
|
17066
|
+
...t.tags ?? [],
|
|
17067
|
+
t.description ?? ""
|
|
17068
|
+
].join(" ").toLowerCase();
|
|
17069
|
+
if (!words2.every((w) => hay.includes(w))) return false;
|
|
17070
|
+
}
|
|
17071
|
+
return true;
|
|
17072
|
+
});
|
|
17073
|
+
}
|
|
17074
|
+
async function loadFilm(ref) {
|
|
17075
|
+
const path = resolve20(ref);
|
|
17076
|
+
if (!existsSync27(path)) throw new UsageError(`${ref}: no such take or file`);
|
|
17077
|
+
if (statSync8(path).isDirectory()) {
|
|
17078
|
+
const take = await loadTake(path);
|
|
17079
|
+
if (!take.doc)
|
|
17080
|
+
throw new UsageError(`${ref} has no doc.json; run vos plan first`);
|
|
17081
|
+
const sync = readSyncState(path);
|
|
17082
|
+
return { doc: take.doc, seed: sync?.vosId ?? basename16(path), dir: path };
|
|
17083
|
+
}
|
|
17084
|
+
let config;
|
|
17085
|
+
try {
|
|
17086
|
+
config = JSON.parse(readFileSync10(path, "utf8"));
|
|
17087
|
+
} catch {
|
|
17088
|
+
throw new UsageError(`${ref}: not a take directory or a JSON config`);
|
|
17089
|
+
}
|
|
17090
|
+
if (!config || typeof config !== "object" || !("version" in config))
|
|
17091
|
+
throw new UsageError(`${ref}: a program's config.json carries a version`);
|
|
17092
|
+
const doc = {
|
|
17093
|
+
program: { config },
|
|
17094
|
+
audio: [],
|
|
17095
|
+
overlays: [],
|
|
17096
|
+
objects: []
|
|
17097
|
+
};
|
|
17098
|
+
return { doc, seed: basename16(path, ".json"), dir: null };
|
|
17099
|
+
}
|
|
17100
|
+
async function likedSlugs(refs, origin) {
|
|
17101
|
+
const slugs = /* @__PURE__ */ new Set();
|
|
17102
|
+
const notes = [];
|
|
17103
|
+
for (const ref of refs) {
|
|
17104
|
+
const id = parseVosId(ref);
|
|
17105
|
+
if (!id) {
|
|
17106
|
+
slugs.add(ref.toLowerCase());
|
|
17107
|
+
continue;
|
|
17108
|
+
}
|
|
17109
|
+
try {
|
|
17110
|
+
const vos = await (await fetch(`${origin}/api/vos/${id}`)).json();
|
|
17111
|
+
if (!vos.currentVersionId) throw new Error("no version");
|
|
17112
|
+
const doc = await (await fetch(
|
|
17113
|
+
`${origin}/api/vos/${id}/versions/${vos.currentVersionId}/doc`
|
|
17114
|
+
)).json();
|
|
17115
|
+
for (const s of musicSlugsOfDoc(doc)) slugs.add(s);
|
|
17116
|
+
} catch {
|
|
17117
|
+
notes.push(
|
|
17118
|
+
`--like ${ref}: could not read that vos's document (is it public?)`
|
|
17119
|
+
);
|
|
17120
|
+
}
|
|
17121
|
+
}
|
|
17122
|
+
return { slugs: [...slugs], notes };
|
|
17123
|
+
}
|
|
17124
|
+
function scoreLine(take, r, film) {
|
|
17125
|
+
const at2 = r.placement?.swellAt ?? film.payoff;
|
|
17126
|
+
return `vos score ${take ?? "<take>"} --track ${r.slug}${at2 !== void 0 && at2 !== null ? ` --at ${at2}` : ""}`;
|
|
17127
|
+
}
|
|
17128
|
+
function pickWords(picks, all, film, take) {
|
|
17129
|
+
const refused = all.filter((r) => r.score === null);
|
|
17130
|
+
const head = `${film.duration.toFixed(1)}s film, ${film.cuts.length} cut${film.cuts.length === 1 ? "" : "s"}${film.payoff !== void 0 ? `, payoff at ${mmss(film.payoff)}` : ""}${film.voice ? ", a voice" : ""}${film.mood ? `, asked ${film.mood}` : ""}${film.words ? `, asked "${film.words}"` : ""}`;
|
|
17131
|
+
if (!picks.length) {
|
|
17132
|
+
return `${head}
|
|
17133
|
+
No bed in the library fits: ${refused.length} refused (${[...new Set(refused.map((r) => r.refused))].slice(0, 3).join("; ")}). Compose a score instead (the vos-score skill), or ask with --words.`;
|
|
17134
|
+
}
|
|
17135
|
+
const lines = picks.map((r, i) => {
|
|
17136
|
+
const t = r.track;
|
|
17137
|
+
const facts = [
|
|
17138
|
+
t.mood,
|
|
17139
|
+
t.bpm !== null && t.bpm !== void 0 ? `${t.bpm} bpm${t.beatConfidence === "low" ? "?" : ""}` : null,
|
|
17140
|
+
VOCAL_WORDS[t.vocals ?? "none"],
|
|
17141
|
+
t.loops ? "loops" : null
|
|
17142
|
+
].filter(Boolean).join(", ");
|
|
17143
|
+
return ` ${i + 1}. ${r.slug} ${t.title} ${(r.score ?? 0).toFixed(2)} (${facts})
|
|
17144
|
+
${r.reasons.join("; ") || "fits"}
|
|
17145
|
+
${scoreLine(take, r, film)}`;
|
|
17146
|
+
});
|
|
17147
|
+
const tail = refused.length ? `
|
|
17148
|
+
${refused.length} refused: ${refused.slice(0, 4).map((r) => `${r.slug} (${r.refused})`).join("; ")}${refused.length > 4 ? "; \u2026" : ""}` : "";
|
|
17149
|
+
return `${head}
|
|
17150
|
+
${lines.join("\n")}${tail}`;
|
|
17151
|
+
}
|
|
17152
|
+
async function cmdMusic(argv) {
|
|
17153
|
+
const { positionals, flags, multi } = parseArgs(
|
|
17154
|
+
argv,
|
|
17155
|
+
BOOLEAN_FLAGS14,
|
|
17156
|
+
MULTI_FLAGS3
|
|
17157
|
+
);
|
|
17158
|
+
const verb = positionals[0];
|
|
17159
|
+
if (flags.help === true || !verb || !["ls", "pick"].includes(verb))
|
|
17160
|
+
throw new UsageError(USAGE5);
|
|
17161
|
+
const r = createReporter(flags.json === true);
|
|
17162
|
+
const origin = platformOrigin({
|
|
17163
|
+
origin: strFlag(flags, "origin"),
|
|
17164
|
+
api: strFlag(flags, "api")
|
|
17165
|
+
});
|
|
17166
|
+
const catalog = await fetchMusicCatalog(origin);
|
|
17167
|
+
if (verb === "ls") {
|
|
17168
|
+
const vocals = strFlag(flags, "vocals");
|
|
17169
|
+
if (vocals && !["none", "chops", "lead"].includes(vocals))
|
|
17170
|
+
throw new UsageError("--vocals expects none, chops or lead");
|
|
17171
|
+
const kept = filterTracks(catalog.tracks, {
|
|
17172
|
+
mood: strFlag(flags, "mood"),
|
|
17173
|
+
vocals,
|
|
17174
|
+
loops: flags.loops === true,
|
|
17175
|
+
bpm: bpmRange(strFlag(flags, "bpm")),
|
|
17176
|
+
minLength: strFlag(flags, "min-length") !== void 0 ? numFlag(flags, "min-length", 0) : void 0,
|
|
17177
|
+
q: strFlag(flags, "q")
|
|
17178
|
+
});
|
|
17179
|
+
r.done(
|
|
17180
|
+
{ origin, tracks: kept, total: catalog.tracks.length },
|
|
17181
|
+
kept.length ? kept.map(trackLine).join("\n") : `No track matches; the library holds ${catalog.tracks.length} (GET ${origin}/api/music).`
|
|
17182
|
+
);
|
|
17183
|
+
return EXIT_OK;
|
|
17184
|
+
}
|
|
17185
|
+
const ref = positionals[1];
|
|
17186
|
+
if (!ref) throw new UsageError(USAGE5);
|
|
17187
|
+
const { doc, seed, dir } = await loadFilm(ref);
|
|
17188
|
+
const atRaw = strFlag(flags, "at");
|
|
17189
|
+
const at2 = atRaw !== void 0 ? resolveAt(doc, atRaw) : null;
|
|
17190
|
+
if (flags.voice === true && flags["no-voice"] === true)
|
|
17191
|
+
throw new UsageError("--voice and --no-voice together say nothing");
|
|
17192
|
+
const liked = await likedSlugs(multi.like ?? [], origin);
|
|
17193
|
+
const film = filmSummaryOf3(doc, {
|
|
17194
|
+
seed,
|
|
17195
|
+
...at2 ? { payoff: at2.at } : {},
|
|
17196
|
+
...flags.voice === true ? { voice: true } : flags["no-voice"] === true ? { voice: false } : {},
|
|
17197
|
+
mood: strFlag(flags, "mood"),
|
|
17198
|
+
words: strFlag(flags, "words"),
|
|
17199
|
+
like: liked.slugs,
|
|
17200
|
+
fadeIn: flags["fade-in"] === true
|
|
17201
|
+
});
|
|
17202
|
+
const top = Math.max(1, Math.round(numFlag(flags, "top", 3)));
|
|
17203
|
+
const all = rankBeds3(catalog.tracks, film);
|
|
17204
|
+
const picks = all.filter((x) => x.score !== null).slice(0, top);
|
|
17205
|
+
for (const n of liked.notes) r.warn(n);
|
|
17206
|
+
const asked = strFlag(flags, "mood");
|
|
17207
|
+
if (asked && trackBySlug2(catalog.tracks, asked))
|
|
17208
|
+
r.warn(
|
|
17209
|
+
`--mood ${asked} is a track's slug; to place that track, run vos score --track ${asked}`
|
|
17210
|
+
);
|
|
17211
|
+
r.done(
|
|
17212
|
+
{
|
|
17213
|
+
origin,
|
|
17214
|
+
film,
|
|
17215
|
+
picks: picks.map((x) => ({
|
|
17216
|
+
...x,
|
|
17217
|
+
command: scoreLine(dir ? ref : null, x, film)
|
|
17218
|
+
})),
|
|
17219
|
+
all
|
|
17220
|
+
},
|
|
17221
|
+
pickWords(picks, all, film, dir ? ref : null)
|
|
17222
|
+
);
|
|
17223
|
+
return EXIT_OK;
|
|
17224
|
+
}
|
|
17225
|
+
|
|
16913
17226
|
// src/plugin/look.ts
|
|
16914
|
-
import { mkdir as mkdir12 } from "fs/promises";
|
|
16915
|
-
import { existsSync as
|
|
16916
|
-
import {
|
|
17227
|
+
import { mkdir as mkdir12, mkdtemp as mkdtemp3, readFile as readFile18, rm as rm6 } from "fs/promises";
|
|
17228
|
+
import { existsSync as existsSync28 } from "fs";
|
|
17229
|
+
import { tmpdir as tmpdir4 } from "os";
|
|
17230
|
+
import { dirname as dirname10, join as join30, resolve as resolve21 } from "path";
|
|
16917
17231
|
import { headersFor, urlSchemeProblem } from "@vosjs/render-core/record";
|
|
16918
17232
|
function quote(value) {
|
|
16919
17233
|
return `"${value.replace(/\s+/g, " ").replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
@@ -17316,19 +17630,19 @@ async function lookAt(page, url, opts) {
|
|
|
17316
17630
|
});
|
|
17317
17631
|
const ran = [];
|
|
17318
17632
|
if (!wall || wall.level === "soft") {
|
|
17319
|
-
for (const
|
|
17320
|
-
const all = page.locator(
|
|
17633
|
+
for (const step of opts.steps ?? []) {
|
|
17634
|
+
const all = page.locator(step.selector);
|
|
17321
17635
|
const target = all.first();
|
|
17322
17636
|
try {
|
|
17323
17637
|
await target.waitFor({ state: "visible", timeout: STEP_TIMEOUT_MS });
|
|
17324
17638
|
} catch {
|
|
17325
17639
|
throw new UsageError(
|
|
17326
|
-
`--${
|
|
17640
|
+
`--${step.do} ${step.selector}: no visible element matches it after ${STEP_TIMEOUT_MS / 1e3} s. Look without the step and take a selector from the list`
|
|
17327
17641
|
);
|
|
17328
17642
|
}
|
|
17329
17643
|
const count = await all.count();
|
|
17330
17644
|
const note = count > 1 ? `the first of ${count} matches` : void 0;
|
|
17331
|
-
if (
|
|
17645
|
+
if (step.do === "click") {
|
|
17332
17646
|
const words2 = await target.evaluate(
|
|
17333
17647
|
(el) => [
|
|
17334
17648
|
el.getAttribute("aria-label"),
|
|
@@ -17344,25 +17658,37 @@ async function lookAt(page, url, opts) {
|
|
|
17344
17658
|
if (word) {
|
|
17345
17659
|
const label = words2.find((w) => spendWord([w])) ?? word;
|
|
17346
17660
|
throw new LookRefusal(
|
|
17347
|
-
refusalLine(
|
|
17661
|
+
refusalLine(step.selector, label.slice(0, 60), word)
|
|
17348
17662
|
);
|
|
17349
17663
|
}
|
|
17350
|
-
log(`click ${
|
|
17664
|
+
log(`click ${step.selector}${note ? ` (${note})` : ""}`);
|
|
17351
17665
|
await target.click({ timeout: STEP_TIMEOUT_MS });
|
|
17352
17666
|
} else {
|
|
17353
17667
|
log(
|
|
17354
|
-
`type ${
|
|
17668
|
+
`type ${step.text.length} chars into ${step.selector}${note ? ` (${note})` : ""}`
|
|
17355
17669
|
);
|
|
17356
|
-
await target.fill(
|
|
17670
|
+
await target.fill(step.text, { timeout: STEP_TIMEOUT_MS });
|
|
17357
17671
|
}
|
|
17358
17672
|
ran.push({
|
|
17359
|
-
do:
|
|
17360
|
-
selector:
|
|
17673
|
+
do: step.do,
|
|
17674
|
+
selector: step.selector,
|
|
17361
17675
|
...note ? { note } : {}
|
|
17362
17676
|
});
|
|
17363
17677
|
settled = await settle(page);
|
|
17364
17678
|
}
|
|
17365
17679
|
}
|
|
17680
|
+
return inspectPage(page, {
|
|
17681
|
+
url,
|
|
17682
|
+
outDir: opts.outDir,
|
|
17683
|
+
waitMs: opts.waitMs,
|
|
17684
|
+
wall,
|
|
17685
|
+
steps: ran,
|
|
17686
|
+
settled
|
|
17687
|
+
});
|
|
17688
|
+
}
|
|
17689
|
+
async function inspectPage(page, opts) {
|
|
17690
|
+
const { url, wall, settled } = opts;
|
|
17691
|
+
const ran = opts.steps;
|
|
17366
17692
|
if (opts.waitMs && opts.waitMs > 0) await page.waitForTimeout(opts.waitMs);
|
|
17367
17693
|
await mkdir12(opts.outDir, { recursive: true });
|
|
17368
17694
|
const screenshot = join30(opts.outDir, "look.png");
|
|
@@ -17420,7 +17746,27 @@ async function lookAt(page, url, opts) {
|
|
|
17420
17746
|
settled
|
|
17421
17747
|
};
|
|
17422
17748
|
}
|
|
17423
|
-
var
|
|
17749
|
+
var USAGE6 = "vos look <url> [--session <name> | --storage-state <file>] [--viewport WxH] [--headed] [--click <selector>]... [--type <selector>=<text>]... [--wait <ms>] [--out <dir>] [--json]\n vos look [url] --actions actions.json --until <step id> [--session <name> | --storage-state <file>] [--viewport WxH] [--headed] [--wait <ms>] [--out <dir>] [--json]";
|
|
17750
|
+
function untilProblem(given, steps) {
|
|
17751
|
+
if (given.until !== void 0 && given.actions === void 0)
|
|
17752
|
+
return "--until names a step of a script: pass the script with --actions actions.json";
|
|
17753
|
+
if (given.actions === void 0) return null;
|
|
17754
|
+
if (given.clicks)
|
|
17755
|
+
return "--actions walks the script; --click and --type walk by hand. Pass one";
|
|
17756
|
+
if (given.until === void 0)
|
|
17757
|
+
return "--actions needs --until <step id>: the step whose page you want to see";
|
|
17758
|
+
if (!steps) return null;
|
|
17759
|
+
if (steps.some((s) => s.id === given.until)) return null;
|
|
17760
|
+
const ids = steps.map((s) => s.id).filter((id) => !!id);
|
|
17761
|
+
return `--until ${given.until}: no step in ${given.actions} has that id. ${ids.length ? `Its ids: ${ids.join(", ")}` : 'Its steps have no ids; give the step you want an "id"'}`;
|
|
17762
|
+
}
|
|
17763
|
+
function walkedSteps(steps) {
|
|
17764
|
+
return steps.map((s) => ({
|
|
17765
|
+
do: s.id ? `${s.do} (${s.id})` : s.do,
|
|
17766
|
+
selector: s.selector ?? "",
|
|
17767
|
+
...s.skipped ? { note: `SKIPPED: ${s.reason ?? "not found"}` } : s.guard ? { note: `guarded (${s.guard}), hovered, not pressed` } : {}
|
|
17768
|
+
}));
|
|
17769
|
+
}
|
|
17424
17770
|
function lookReport(r) {
|
|
17425
17771
|
const inDialog = r.controls.filter((c) => c.inDialog).length;
|
|
17426
17772
|
const head = `Looked at ${r.landed} (${r.viewport.width}\xD7${r.viewport.height}): ${r.screenshot}${r.settled ? "" : "\n note: the page never held still for 0.8 s; looked at it as it was"}`;
|
|
@@ -17449,21 +17795,39 @@ async function cmdLook(argv) {
|
|
|
17449
17795
|
);
|
|
17450
17796
|
void multi.click;
|
|
17451
17797
|
void multi.type;
|
|
17452
|
-
const
|
|
17453
|
-
|
|
17798
|
+
const actionsArg = strFlag(flags, "actions");
|
|
17799
|
+
const untilId = strFlag(flags, "until");
|
|
17800
|
+
const early = untilProblem({
|
|
17801
|
+
actions: actionsArg,
|
|
17802
|
+
until: untilId,
|
|
17803
|
+
clicks: steps.length
|
|
17804
|
+
});
|
|
17805
|
+
if (early) throw new UsageError(early);
|
|
17806
|
+
let actions;
|
|
17807
|
+
if (actionsArg) {
|
|
17808
|
+
actions = await loadLookActions(resolve21(actionsArg));
|
|
17809
|
+
const bad = untilProblem(
|
|
17810
|
+
{ actions: actionsArg, until: untilId, clicks: 0 },
|
|
17811
|
+
actions.steps
|
|
17812
|
+
);
|
|
17813
|
+
if (bad) throw new UsageError(bad);
|
|
17814
|
+
}
|
|
17815
|
+
const url = positionals[0] ?? actions?.url;
|
|
17816
|
+
if (!url) throw new UsageError(USAGE6);
|
|
17454
17817
|
const scheme = urlSchemeProblem(url);
|
|
17455
17818
|
if (scheme) throw new UsageError(scheme);
|
|
17456
17819
|
const r = createReporter(flags.json === true);
|
|
17457
|
-
const
|
|
17458
|
-
const
|
|
17820
|
+
const viewportFlag = strFlag(flags, "viewport");
|
|
17821
|
+
const viewport = !viewportFlag && actions?.viewport ? actions.viewport : parseViewport2(viewportFlag);
|
|
17822
|
+
const outDir = resolve21(strFlag(flags, "out") ?? "look");
|
|
17459
17823
|
const headed = flags.headed === true;
|
|
17460
17824
|
const waitRaw = strFlag(flags, "wait");
|
|
17461
17825
|
const waitMs = waitRaw === void 0 ? 0 : Number(waitRaw);
|
|
17462
17826
|
if (!Number.isFinite(waitMs) || waitMs < 0 || waitMs > 6e4)
|
|
17463
17827
|
throw new UsageError("--wait expects milliseconds, 0 to 60000");
|
|
17464
17828
|
const storageRaw = strFlag(flags, "storage-state");
|
|
17465
|
-
const storageState = storageRaw ?
|
|
17466
|
-
if (storageState && !
|
|
17829
|
+
const storageState = storageRaw ? resolve21(storageRaw) : void 0;
|
|
17830
|
+
if (storageState && !existsSync28(storageState))
|
|
17467
17831
|
throw new UsageError(`--storage-state: no such file: ${storageState}`);
|
|
17468
17832
|
const sessionName = strFlag(flags, "session");
|
|
17469
17833
|
if (sessionName) {
|
|
@@ -17473,7 +17837,7 @@ async function cmdLook(argv) {
|
|
|
17473
17837
|
throw new UsageError(
|
|
17474
17838
|
"--session and --storage-state are two doors to one page: a persistent profile cannot take a storage state. Pass one"
|
|
17475
17839
|
);
|
|
17476
|
-
if (!
|
|
17840
|
+
if (!existsSync28(sessionDir(sessionName)))
|
|
17477
17841
|
throw new UsageError(
|
|
17478
17842
|
`no session "${sessionName}". Make one: vos session open <url> --name ${sessionName} (a Chrome window opens; sign in and close it)`
|
|
17479
17843
|
);
|
|
@@ -17485,6 +17849,22 @@ async function cmdLook(argv) {
|
|
|
17485
17849
|
throw new UsageError(e instanceof Error ? e.message : String(e));
|
|
17486
17850
|
}
|
|
17487
17851
|
const browserArgs = (multi["browser-arg"] ?? []).filter(Boolean);
|
|
17852
|
+
if (actions && untilId && actionsArg)
|
|
17853
|
+
return lookUntil({
|
|
17854
|
+
r,
|
|
17855
|
+
url,
|
|
17856
|
+
actions,
|
|
17857
|
+
actionsPath: resolve21(actionsArg),
|
|
17858
|
+
untilId,
|
|
17859
|
+
viewport,
|
|
17860
|
+
outDir,
|
|
17861
|
+
waitMs,
|
|
17862
|
+
headed,
|
|
17863
|
+
storageState,
|
|
17864
|
+
sessionName,
|
|
17865
|
+
headers,
|
|
17866
|
+
browserArgs
|
|
17867
|
+
});
|
|
17488
17868
|
const inContext = async (ctx) => {
|
|
17489
17869
|
if (Object.keys(headers).length)
|
|
17490
17870
|
await ctx.route("**/*", async (route) => {
|
|
@@ -17531,14 +17911,116 @@ async function cmdLook(argv) {
|
|
|
17531
17911
|
);
|
|
17532
17912
|
return result.wall?.level === "hard" ? EXIT_WALL : EXIT_OK;
|
|
17533
17913
|
}
|
|
17914
|
+
async function loadLookActions(file) {
|
|
17915
|
+
let raw;
|
|
17916
|
+
try {
|
|
17917
|
+
raw = JSON.parse(await readFile18(file, "utf8"));
|
|
17918
|
+
} catch (e) {
|
|
17919
|
+
throw new UsageError(
|
|
17920
|
+
`--actions ${file}: ${e instanceof Error ? e.message : String(e)}`
|
|
17921
|
+
);
|
|
17922
|
+
}
|
|
17923
|
+
const errors = validateActions(raw);
|
|
17924
|
+
if (!errors.length) errors.push(...jsSyntaxProblems(raw));
|
|
17925
|
+
if (errors.length)
|
|
17926
|
+
throw new UsageError(`invalid actions file:
|
|
17927
|
+
${errors.join("\n ")}`);
|
|
17928
|
+
return raw;
|
|
17929
|
+
}
|
|
17930
|
+
async function lookUntil(o) {
|
|
17931
|
+
const { r } = o;
|
|
17932
|
+
const actions = { ...o.actions, viewport: o.viewport };
|
|
17933
|
+
let wall = null;
|
|
17934
|
+
let looked = null;
|
|
17935
|
+
const scratch = await mkdtemp3(join30(tmpdir4(), "vos-look-"));
|
|
17936
|
+
r.log(
|
|
17937
|
+
`walking ${o.actionsPath} to step ${o.untilId} (a rehearsal: guarded steps hovered, never pressed)\u2026`
|
|
17938
|
+
);
|
|
17939
|
+
const browser = await launchBrowser(o.browserArgs, { headless: !o.headed });
|
|
17940
|
+
let rec;
|
|
17941
|
+
try {
|
|
17942
|
+
const walk = (context2) => recordTake(browser, o.url, actions, takePaths(scratch), r.log, {
|
|
17943
|
+
actionsDir: dirname10(o.actionsPath),
|
|
17944
|
+
storageState: o.storageState,
|
|
17945
|
+
headers: o.headers,
|
|
17946
|
+
context: context2,
|
|
17947
|
+
dryRun: true,
|
|
17948
|
+
stopOnHang: true,
|
|
17949
|
+
onEvent: (e) => r.event(e),
|
|
17950
|
+
onArrival: (arrival) => {
|
|
17951
|
+
const verdict = wallVerdict(arrival);
|
|
17952
|
+
if (verdict && verdict.level === "hard") throw new WallError(verdict);
|
|
17953
|
+
if (verdict) r.log(` WARNING: ${verdict.message}`);
|
|
17954
|
+
wall = verdict;
|
|
17955
|
+
return verdict;
|
|
17956
|
+
},
|
|
17957
|
+
until: {
|
|
17958
|
+
id: o.untilId,
|
|
17959
|
+
at: async (raw) => {
|
|
17960
|
+
const page = raw;
|
|
17961
|
+
const settled = await settle(page);
|
|
17962
|
+
looked = await inspectPage(page, {
|
|
17963
|
+
url: o.url,
|
|
17964
|
+
outDir: o.outDir,
|
|
17965
|
+
waitMs: o.waitMs,
|
|
17966
|
+
wall,
|
|
17967
|
+
steps: [],
|
|
17968
|
+
settled
|
|
17969
|
+
});
|
|
17970
|
+
}
|
|
17971
|
+
}
|
|
17972
|
+
});
|
|
17973
|
+
rec = o.sessionName ? await withSession(o.sessionName, (ctx) => walk(ctx), {
|
|
17974
|
+
headless: !o.headed,
|
|
17975
|
+
viewport: o.viewport
|
|
17976
|
+
}) : await walk(void 0);
|
|
17977
|
+
} finally {
|
|
17978
|
+
await browser.close();
|
|
17979
|
+
await rm6(scratch, { recursive: true, force: true });
|
|
17980
|
+
}
|
|
17981
|
+
const result = looked;
|
|
17982
|
+
const ran = walkedSteps(rec.meta.steps ?? []);
|
|
17983
|
+
const skipped = rec.skipped.length;
|
|
17984
|
+
const teardown = rec.teardown ? `
|
|
17985
|
+
${teardownLine(rec.teardown)}` : "";
|
|
17986
|
+
if (!result) {
|
|
17987
|
+
const why = rec.stopped ? rec.stopped.reason : "the walk ended before it reached that step";
|
|
17988
|
+
r.done(
|
|
17989
|
+
{
|
|
17990
|
+
ok: false,
|
|
17991
|
+
until: o.untilId,
|
|
17992
|
+
steps: ran,
|
|
17993
|
+
skipped: rec.skipped,
|
|
17994
|
+
...rec.teardown ? { teardown: rec.teardown } : {}
|
|
17995
|
+
},
|
|
17996
|
+
`NOT LOOKED: step ${o.untilId} was never reached: ${why}.${ran.length ? `
|
|
17997
|
+
walked: ${ran.map((s) => `${s.do}${s.selector ? ` ${s.selector}` : ""}${s.note ? ` (${s.note})` : ""}`).join(", then ")}` : ""}
|
|
17998
|
+
Rehearse the script (vos record --actions ${o.actionsPath} --dry-run) to see where it stops.${teardown}`
|
|
17999
|
+
);
|
|
18000
|
+
return EXIT_USAGE;
|
|
18001
|
+
}
|
|
18002
|
+
const full = { ...result, steps: ran };
|
|
18003
|
+
const warn = skipped ? `
|
|
18004
|
+
WARNING: ${skipped} step${skipped === 1 ? " was" : "s were"} SKIPPED on the way, so this may not be the page the script reaches. Fix ${skipped === 1 ? "it" : "them"}, then look again.` : "";
|
|
18005
|
+
r.done(
|
|
18006
|
+
{
|
|
18007
|
+
ok: skipped === 0 && (!full.wall || full.wall.level === "soft"),
|
|
18008
|
+
until: o.untilId,
|
|
18009
|
+
...full,
|
|
18010
|
+
...rec.teardown ? { teardown: rec.teardown } : {}
|
|
18011
|
+
},
|
|
18012
|
+
`${lookReport(full)}${warn}${teardown}`
|
|
18013
|
+
);
|
|
18014
|
+
return skipped ? EXIT_USAGE : EXIT_OK;
|
|
18015
|
+
}
|
|
17534
18016
|
|
|
17535
18017
|
// src/plugin/machineCmd.ts
|
|
17536
18018
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
17537
18019
|
import {
|
|
17538
18020
|
cpSync,
|
|
17539
|
-
existsSync as
|
|
18021
|
+
existsSync as existsSync30,
|
|
17540
18022
|
mkdirSync as mkdirSync6,
|
|
17541
|
-
readFileSync as
|
|
18023
|
+
readFileSync as readFileSync12,
|
|
17542
18024
|
rmSync as rmSync3,
|
|
17543
18025
|
writeFileSync as writeFileSync6
|
|
17544
18026
|
} from "fs";
|
|
@@ -17547,8 +18029,8 @@ import { join as join32 } from "path";
|
|
|
17547
18029
|
import { chromium as chromium2 } from "playwright";
|
|
17548
18030
|
|
|
17549
18031
|
// src/plugin/machine.ts
|
|
17550
|
-
import { existsSync as
|
|
17551
|
-
import { dirname as
|
|
18032
|
+
import { existsSync as existsSync29, readFileSync as readFileSync11, readdirSync as readdirSync6, statSync as statSync9 } from "fs";
|
|
18033
|
+
import { dirname as dirname11, join as join31 } from "path";
|
|
17552
18034
|
var AGENT_NAMES = [
|
|
17553
18035
|
"claude",
|
|
17554
18036
|
"cursor",
|
|
@@ -17568,7 +18050,7 @@ var HOME_DIRS = {
|
|
|
17568
18050
|
copilot: [".copilot"]
|
|
17569
18051
|
};
|
|
17570
18052
|
function detectAgents(root, opts = {}) {
|
|
17571
|
-
const exists = opts.exists ??
|
|
18053
|
+
const exists = opts.exists ?? existsSync29;
|
|
17572
18054
|
const out = [];
|
|
17573
18055
|
for (const agent of AGENT_NAMES) {
|
|
17574
18056
|
for (const rel of PROJECT_DIRS[agent]) {
|
|
@@ -17615,7 +18097,7 @@ function skillsDirFor(home) {
|
|
|
17615
18097
|
function fallbackSkillsHome(root) {
|
|
17616
18098
|
return { agent: "codex", dir: join31(root, ".agents"), scope: "project" };
|
|
17617
18099
|
}
|
|
17618
|
-
function installedSkills(dir, exists =
|
|
18100
|
+
function installedSkills(dir, exists = existsSync29, list = (p) => {
|
|
17619
18101
|
try {
|
|
17620
18102
|
return readdirSync6(p);
|
|
17621
18103
|
} catch {
|
|
@@ -17656,7 +18138,7 @@ ${RULES_BLOCK}
|
|
|
17656
18138
|
}
|
|
17657
18139
|
return { text, changed: text !== current };
|
|
17658
18140
|
}
|
|
17659
|
-
function rulesFileFor(root, exists =
|
|
18141
|
+
function rulesFileFor(root, exists = existsSync29) {
|
|
17660
18142
|
const agents = join31(root, "AGENTS.md");
|
|
17661
18143
|
if (exists(agents)) return agents;
|
|
17662
18144
|
const claude = join31(root, "CLAUDE.md");
|
|
@@ -17761,27 +18243,27 @@ function doctorReport(facts) {
|
|
|
17761
18243
|
}
|
|
17762
18244
|
function bundledSkillsVersion(dir) {
|
|
17763
18245
|
try {
|
|
17764
|
-
const v =
|
|
18246
|
+
const v = readFileSync11(join31(dir, "VERSION"), "utf8").trim();
|
|
17765
18247
|
return /^\d+\.\d+\.\d+$/.test(v) ? v : null;
|
|
17766
18248
|
} catch {
|
|
17767
18249
|
return null;
|
|
17768
18250
|
}
|
|
17769
18251
|
}
|
|
17770
18252
|
function bundledSkillsDir(from) {
|
|
17771
|
-
let dir =
|
|
18253
|
+
let dir = dirname11(from);
|
|
17772
18254
|
for (let i = 0; i < 6; i++) {
|
|
17773
18255
|
const pkg = join31(dir, "package.json");
|
|
17774
|
-
if (
|
|
18256
|
+
if (existsSync29(pkg)) {
|
|
17775
18257
|
try {
|
|
17776
|
-
const name = JSON.parse(
|
|
18258
|
+
const name = JSON.parse(readFileSync11(pkg, "utf8")).name;
|
|
17777
18259
|
if (name === "@vosjs/cli") {
|
|
17778
18260
|
const skills = join31(dir, "skills");
|
|
17779
|
-
return
|
|
18261
|
+
return existsSync29(skills) && statSync9(skills).isDirectory() ? skills : null;
|
|
17780
18262
|
}
|
|
17781
18263
|
} catch {
|
|
17782
18264
|
}
|
|
17783
18265
|
}
|
|
17784
|
-
const up =
|
|
18266
|
+
const up = dirname11(dir);
|
|
17785
18267
|
if (up === dir) break;
|
|
17786
18268
|
dir = up;
|
|
17787
18269
|
}
|
|
@@ -17789,7 +18271,7 @@ function bundledSkillsDir(from) {
|
|
|
17789
18271
|
}
|
|
17790
18272
|
|
|
17791
18273
|
// src/plugin/machineCmd.ts
|
|
17792
|
-
var
|
|
18274
|
+
var BOOLEAN_FLAGS15 = /* @__PURE__ */ new Set([
|
|
17793
18275
|
"json",
|
|
17794
18276
|
"help",
|
|
17795
18277
|
"global",
|
|
@@ -17812,7 +18294,7 @@ function npx() {
|
|
|
17812
18294
|
function bundledChromium() {
|
|
17813
18295
|
try {
|
|
17814
18296
|
const p = chromium2.executablePath();
|
|
17815
|
-
return p &&
|
|
18297
|
+
return p && existsSync30(p) ? p : null;
|
|
17816
18298
|
} catch {
|
|
17817
18299
|
return null;
|
|
17818
18300
|
}
|
|
@@ -17821,7 +18303,7 @@ function probe2() {
|
|
|
17821
18303
|
return probeBrowser({
|
|
17822
18304
|
platform: process.platform,
|
|
17823
18305
|
env: process.env,
|
|
17824
|
-
exists:
|
|
18306
|
+
exists: existsSync30,
|
|
17825
18307
|
bundled: bundledChromium
|
|
17826
18308
|
});
|
|
17827
18309
|
}
|
|
@@ -17872,7 +18354,7 @@ async function doctorFacts(opts) {
|
|
|
17872
18354
|
};
|
|
17873
18355
|
}
|
|
17874
18356
|
async function cmdSetup(argv) {
|
|
17875
|
-
const { flags } = parseArgs(argv,
|
|
18357
|
+
const { flags } = parseArgs(argv, BOOLEAN_FLAGS15);
|
|
17876
18358
|
const r = reporterFor(flags);
|
|
17877
18359
|
const root = process.cwd();
|
|
17878
18360
|
const global = flags.global === true;
|
|
@@ -17974,7 +18456,7 @@ async function cmdSetup(argv) {
|
|
|
17974
18456
|
let rules = null;
|
|
17975
18457
|
if (!noRules) {
|
|
17976
18458
|
const file = rulesFileFor(root);
|
|
17977
|
-
const existing =
|
|
18459
|
+
const existing = existsSync30(file) ? readFileSync12(file, "utf8") : null;
|
|
17978
18460
|
const { text, changed } = applyRulesBlock(existing);
|
|
17979
18461
|
if (changed) writeFileSync6(file, text);
|
|
17980
18462
|
rules = { file, changed };
|
|
@@ -18005,7 +18487,7 @@ Next: ${report.next_step}`
|
|
|
18005
18487
|
return report.ok ? EXIT_OK : EXIT_NO_BROWSER;
|
|
18006
18488
|
}
|
|
18007
18489
|
async function cmdDoctor(argv) {
|
|
18008
|
-
const { flags } = parseArgs(argv,
|
|
18490
|
+
const { flags } = parseArgs(argv, BOOLEAN_FLAGS15);
|
|
18009
18491
|
const r = reporterFor(flags);
|
|
18010
18492
|
const root = process.cwd();
|
|
18011
18493
|
const homes = detectAgents(root, { home: homedir2(), global: true });
|
|
@@ -18024,7 +18506,7 @@ Next: ${report.next_step}`
|
|
|
18024
18506
|
return report.ok ? EXIT_OK : EXIT_NO_BROWSER;
|
|
18025
18507
|
}
|
|
18026
18508
|
async function cmdWhoami(argv) {
|
|
18027
|
-
const { flags } = parseArgs(argv,
|
|
18509
|
+
const { flags } = parseArgs(argv, BOOLEAN_FLAGS15);
|
|
18028
18510
|
const r = reporterFor(flags);
|
|
18029
18511
|
const origin = platformOrigin({
|
|
18030
18512
|
origin: strFlag(flags, "origin"),
|
|
@@ -18086,9 +18568,9 @@ async function cmdWhoami(argv) {
|
|
|
18086
18568
|
return EXIT_OK;
|
|
18087
18569
|
}
|
|
18088
18570
|
function cmdLogout(argv) {
|
|
18089
|
-
const { flags } = parseArgs(argv,
|
|
18571
|
+
const { flags } = parseArgs(argv, BOOLEAN_FLAGS15);
|
|
18090
18572
|
const r = reporterFor(flags);
|
|
18091
|
-
const had =
|
|
18573
|
+
const had = existsSync30(CREDENTIALS_PATH);
|
|
18092
18574
|
rmSync3(CREDENTIALS_PATH, { force: true });
|
|
18093
18575
|
const envKey = Boolean(process.env.VOS_API_KEY?.trim());
|
|
18094
18576
|
r.done(
|
|
@@ -18104,7 +18586,7 @@ function cmdLogout(argv) {
|
|
|
18104
18586
|
}
|
|
18105
18587
|
|
|
18106
18588
|
// src/plugin/run.ts
|
|
18107
|
-
var
|
|
18589
|
+
var BOOLEAN_FLAGS16 = /* @__PURE__ */ new Set([
|
|
18108
18590
|
"json",
|
|
18109
18591
|
"help",
|
|
18110
18592
|
"wait",
|
|
@@ -18168,8 +18650,12 @@ Take pipeline
|
|
|
18168
18650
|
vos join <take> <take|file.mp4>... --out <dir> [--keep-edits|--force] [--captions] [--zooms per-beat] [--mute <file>]... [--json]
|
|
18169
18651
|
several takes (and plain video files) as ONE take, cut in argument order: the first is the primary (its frame, cursor, export and sound), each next one a media m1, m2, \u2026 with its footage copied, its spans tagged and renamed, its layers moved to where it now starts; a file opens full-bleed and its own sound plays as an audio clip (--mute <file> leaves it out). --captions lands every step's caption anchored to its step, starting as the step begins (anchor.at "start"), each ending with its clip. --zooms per-beat keeps a beat's zoom on its steps marked "zoom": true (as vos plan --zooms per-beat). The result must pass vos validate before anything is written
|
|
18170
18652
|
--keep-edits joins again over an edited joined take and keeps its edits: inputs are matched to their media by source file (join.json records each input's path and footage hash), a kept input keeps its id and everything on it (segments in their edited order, spans, rejections, anchored layers, its sound), the frame, export, styles and still stay, a new input is joined fresh under a new id (and only it is captioned or re-planned), a re-recorded input (changed footage at its path, or the same script at a new one) keeps its edits re-timed by its steps as vos plan --reuse does, and an input that is gone takes its edits with it, each named. A new input's segments go before the next kept input's; reordering the kept inputs regroups the segments in argument order. The first input must stay the primary. --force replaces the take instead
|
|
18171
|
-
vos
|
|
18172
|
-
the
|
|
18653
|
+
vos music ls [--mood <slug>] [--vocals none|chops|lead] [--loops] [--bpm <lo>-<hi>] [--min-length <s>] [--q <words>] [--json]
|
|
18654
|
+
the library as an agent reads it, one line per track: slug, genre, length, tempo (a ? on an uncertain beat), vocals, loops, the sentence a person wrote. The facts are GET /api/music's
|
|
18655
|
+
vos music pick <take|config.json> [--at <step id|seconds>] [--mood <slug|tag>] [--words "\u2026"] [--voice|--no-voice] [--like <vos id|slug>]... [--top 3] [--json]
|
|
18656
|
+
the beds that fit THIS film, best first, each with its reasons and the vos score line that places it: the film's length, its cuts (captions, joins, page changes, zoom marks), its payoff (--at, else the last step marked "zoom": true, else the last cut) and its voice are read from the document and every track is scored (a swell on the payoff, cuts on the beat, the asked mood or words, calm under a voice, an ending that meets the film's) after the hard rules (covers the film or loops, no quiet intro under frame one, no sung lead under a voice). --json carries every track, the refused with their reason. Ties fall to the take, so two films asking the same thing get different beds
|
|
18657
|
+
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]
|
|
18658
|
+
the film's music as one audio clip (id score): reads the track's loudness, finds its strongest swell and offsets the track so the swell lands at --at (a step, resolved through the cut, or output seconds); without --at it starts where the track first rises above its median level. --track best runs vos music pick and places its first pick, its payoff as --at unless one is given. The clip carries its measured loudness and a target, --normalize (default -16 LUFS), with --gain (default 0.5) a trim on it; --normalize off plays it at --gain alone
|
|
18173
18659
|
vos audio measure <take> [--json]
|
|
18174
18660
|
every audio clip's loudness (BS.1770 integrated LUFS and sample peak, the meter check-video reads a render with), written beside it in doc.json as loudness { lufs, peakDb, at, src }; a clip's normalize (a target in LUFS, -30..-6) plays it at the gain that reaches it, past 1 if need be, capped so its peak stays under -1 dBFS, and only once it is measured for its own key
|
|
18175
18661
|
vos port inventory <page.html|project dir> [--render <their render.mp4>] [--out port] [--json]
|
|
@@ -18503,7 +18989,7 @@ lint-gated, so a bad override fails like a bad doc.json):
|
|
|
18503
18989
|
first ready loop (the house backdrop the studio opens on), or a flat ground offline
|
|
18504
18990
|
`;
|
|
18505
18991
|
async function loadActions(file) {
|
|
18506
|
-
const raw = JSON.parse(await
|
|
18992
|
+
const raw = JSON.parse(await readFile19(file, "utf8"));
|
|
18507
18993
|
const errors = validateActions(raw);
|
|
18508
18994
|
if (!errors.length) errors.push(...jsSyntaxProblems(raw));
|
|
18509
18995
|
if (errors.length)
|
|
@@ -18669,8 +19155,8 @@ function takeBrowserArgs(multi) {
|
|
|
18669
19155
|
function takeStorageState(flags) {
|
|
18670
19156
|
const raw = strFlag(flags, "storage-state");
|
|
18671
19157
|
if (!raw) return void 0;
|
|
18672
|
-
const path =
|
|
18673
|
-
if (!
|
|
19158
|
+
const path = resolve22(raw);
|
|
19159
|
+
if (!existsSync31(path))
|
|
18674
19160
|
throw new UsageError(`--storage-state: no such file: ${path}`);
|
|
18675
19161
|
return path;
|
|
18676
19162
|
}
|
|
@@ -18683,7 +19169,7 @@ function takeSessionName(flags, storageState) {
|
|
|
18683
19169
|
throw new UsageError(
|
|
18684
19170
|
"--session and --storage-state are two doors to one take: a persistent profile cannot take a storage state. Pass one"
|
|
18685
19171
|
);
|
|
18686
|
-
if (!
|
|
19172
|
+
if (!existsSync31(sessionDir(name)))
|
|
18687
19173
|
throw new UsageError(
|
|
18688
19174
|
`no session "${name}". Make one: vos session open <url> --name ${name} (a Chrome window opens; sign in and close it)`
|
|
18689
19175
|
);
|
|
@@ -18701,14 +19187,14 @@ async function inSession(name, actions, fn) {
|
|
|
18701
19187
|
}
|
|
18702
19188
|
function reRecord(outDir, flags, r) {
|
|
18703
19189
|
const wantsReuse = flags.reuse === true;
|
|
18704
|
-
if (wantsReuse && !
|
|
19190
|
+
if (wantsReuse && !existsSync31(join33(outDir, "doc.json")))
|
|
18705
19191
|
throw new UsageError(
|
|
18706
19192
|
`--reuse: ${outDir} has no cut to keep (no doc.json); record without --reuse`
|
|
18707
19193
|
);
|
|
18708
19194
|
let previousCut = null;
|
|
18709
19195
|
return {
|
|
18710
19196
|
prepare: async () => {
|
|
18711
|
-
if (
|
|
19197
|
+
if (existsSync31(join33(outDir, "meta.json"))) {
|
|
18712
19198
|
const { prevDoc, kept } = await prepareReRecord(outDir);
|
|
18713
19199
|
if (prevDoc) previousCut = join33(outDir, PREV_DOC_NAME);
|
|
18714
19200
|
r.log(
|
|
@@ -18725,7 +19211,7 @@ function reRecord(outDir, flags, r) {
|
|
|
18725
19211
|
...from ? {
|
|
18726
19212
|
reuse: {
|
|
18727
19213
|
from,
|
|
18728
|
-
doc: JSON.parse(await
|
|
19214
|
+
doc: JSON.parse(await readFile19(from, "utf8"))
|
|
18729
19215
|
}
|
|
18730
19216
|
} : {}
|
|
18731
19217
|
});
|
|
@@ -18796,7 +19282,7 @@ function wallGate(flags, r, opts) {
|
|
|
18796
19282
|
async function cmdRecord(argv) {
|
|
18797
19283
|
const { positionals, flags, multi } = parseArgs(
|
|
18798
19284
|
argv,
|
|
18799
|
-
|
|
19285
|
+
BOOLEAN_FLAGS16,
|
|
18800
19286
|
MULTI_FLAGS2
|
|
18801
19287
|
);
|
|
18802
19288
|
const actionsPath = strFlag(flags, "actions") ?? positionals[0];
|
|
@@ -18812,7 +19298,7 @@ async function cmdRecord(argv) {
|
|
|
18812
19298
|
const scheme = urlSchemeProblem2(url);
|
|
18813
19299
|
if (scheme) throw new UsageError(scheme);
|
|
18814
19300
|
announceEnvNames(actions, r);
|
|
18815
|
-
const outDir =
|
|
19301
|
+
const outDir = resolve22(strFlag(flags, "out") ?? "take");
|
|
18816
19302
|
const storageState = takeStorageState(flags);
|
|
18817
19303
|
const sessionName = takeSessionName(flags, storageState);
|
|
18818
19304
|
const browserArgs = takeBrowserArgs(multi);
|
|
@@ -18832,7 +19318,7 @@ async function cmdRecord(argv) {
|
|
|
18832
19318
|
);
|
|
18833
19319
|
const hostedActions = await scriptForHost(
|
|
18834
19320
|
actions,
|
|
18835
|
-
|
|
19321
|
+
dirname12(resolve22(actionsPath))
|
|
18836
19322
|
).catch((e) => {
|
|
18837
19323
|
throw new UsageError(e instanceof Error ? e.message : String(e));
|
|
18838
19324
|
});
|
|
@@ -18942,7 +19428,7 @@ async function cmdRecord(argv) {
|
|
|
18942
19428
|
sessionName,
|
|
18943
19429
|
actions,
|
|
18944
19430
|
(context2) => recordTake(browser2, url, actions, takePaths(outDir), r.log, {
|
|
18945
|
-
actionsDir:
|
|
19431
|
+
actionsDir: dirname12(resolve22(actionsPath)),
|
|
18946
19432
|
storageState,
|
|
18947
19433
|
headers,
|
|
18948
19434
|
context: context2,
|
|
@@ -19008,7 +19494,7 @@ async function cmdRecord(argv) {
|
|
|
19008
19494
|
...flags["allow-wall"] === true ? ["--allow-wall"] : [],
|
|
19009
19495
|
...confirm.map((c) => `--confirm ${c}`),
|
|
19010
19496
|
// A take that already has a cut keeps it on the new footage.
|
|
19011
|
-
...
|
|
19497
|
+
...existsSync31(join33(outDir, "doc.json")) ? ["--reuse"] : []
|
|
19012
19498
|
].join(" ");
|
|
19013
19499
|
const nextOut = strFlag(flags, "out") ?? "take";
|
|
19014
19500
|
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)` : "";
|
|
@@ -19050,7 +19536,7 @@ ${lines.join("\n")}
|
|
|
19050
19536
|
sessionName,
|
|
19051
19537
|
actions,
|
|
19052
19538
|
(context2) => recordTake(browser, url, actions, paths, r.log, {
|
|
19053
|
-
actionsDir:
|
|
19539
|
+
actionsDir: dirname12(resolve22(actionsPath)),
|
|
19054
19540
|
maxDurationSeconds,
|
|
19055
19541
|
storageState,
|
|
19056
19542
|
headers,
|
|
@@ -19148,7 +19634,7 @@ ${lines.join("\n")}
|
|
|
19148
19634
|
async function cmdCreate2(argv) {
|
|
19149
19635
|
const { positionals, flags, multi } = parseArgs(
|
|
19150
19636
|
argv,
|
|
19151
|
-
|
|
19637
|
+
BOOLEAN_FLAGS16,
|
|
19152
19638
|
MULTI_FLAGS2
|
|
19153
19639
|
);
|
|
19154
19640
|
const actionsPath = strFlag(flags, "actions");
|
|
@@ -19165,7 +19651,7 @@ async function cmdCreate2(argv) {
|
|
|
19165
19651
|
const scheme = urlSchemeProblem2(url);
|
|
19166
19652
|
if (scheme) throw new UsageError(scheme);
|
|
19167
19653
|
announceEnvNames(actions, r);
|
|
19168
|
-
const outDir =
|
|
19654
|
+
const outDir = resolve22(strFlag(flags, "out") ?? "take");
|
|
19169
19655
|
const format = videoFormat(strFlag(flags, "format"), positionals[0]);
|
|
19170
19656
|
const out = positionals[0] ?? join33(outDir, `out.${format}`);
|
|
19171
19657
|
const parallel = numFlag(flags, "parallel", 1);
|
|
@@ -19189,7 +19675,7 @@ async function cmdCreate2(argv) {
|
|
|
19189
19675
|
sessionName,
|
|
19190
19676
|
actions,
|
|
19191
19677
|
(context2) => recordTake(browser, url, actions, paths, r.log, {
|
|
19192
|
-
actionsDir:
|
|
19678
|
+
actionsDir: dirname12(resolve22(actionsPath)),
|
|
19193
19679
|
maxDurationSeconds,
|
|
19194
19680
|
storageState,
|
|
19195
19681
|
headers,
|
|
@@ -19306,7 +19792,7 @@ async function cmdPlan(argvIn) {
|
|
|
19306
19792
|
const argv = bareCaptionsFlag(argvIn);
|
|
19307
19793
|
const { positionals, flags, multi } = parseArgs(
|
|
19308
19794
|
argv,
|
|
19309
|
-
|
|
19795
|
+
BOOLEAN_FLAGS16,
|
|
19310
19796
|
/* @__PURE__ */ new Set(["with"])
|
|
19311
19797
|
);
|
|
19312
19798
|
const dir = positionals[0];
|
|
@@ -19316,24 +19802,24 @@ async function cmdPlan(argvIn) {
|
|
|
19316
19802
|
);
|
|
19317
19803
|
const r = createReporter(flags.json === true);
|
|
19318
19804
|
if (flags.fresh === true) {
|
|
19319
|
-
await
|
|
19805
|
+
await rm7(join33(dir, "doc.json"), { force: true });
|
|
19320
19806
|
r.log("note: --fresh discarded the existing doc.json");
|
|
19321
19807
|
}
|
|
19322
19808
|
let reuse;
|
|
19323
19809
|
if (flags.reuse === true) {
|
|
19324
|
-
const from =
|
|
19325
|
-
if (!
|
|
19810
|
+
const from = resolve22(strFlag(flags, "from") ?? join33(dir, PREV_DOC_NAME));
|
|
19811
|
+
if (!existsSync31(from)) {
|
|
19326
19812
|
throw new UsageError(
|
|
19327
19813
|
`--reuse: ${from} does not exist \u2014 a re-record into this take writes doc.prev.json, or pass --from <doc.json>`
|
|
19328
19814
|
);
|
|
19329
19815
|
}
|
|
19330
19816
|
reuse = {
|
|
19331
19817
|
from,
|
|
19332
|
-
doc: JSON.parse(await
|
|
19818
|
+
doc: JSON.parse(await readFile19(from, "utf8"))
|
|
19333
19819
|
};
|
|
19334
19820
|
}
|
|
19335
19821
|
const style = await resolveStyleRef(flags);
|
|
19336
|
-
const hasDoc =
|
|
19822
|
+
const hasDoc = existsSync31(join33(dir, "doc.json"));
|
|
19337
19823
|
const backdrop = hasDoc ? null : await takeBackdrop(flags, r);
|
|
19338
19824
|
const release = await releaseInputs(dir, flags, r, multi.with ?? []);
|
|
19339
19825
|
const stepCaptions = strFlag(flags, "captions") === "steps";
|
|
@@ -19413,7 +19899,7 @@ async function cmdPlan(argvIn) {
|
|
|
19413
19899
|
${s.reuse.flagged.join("\n ")}` : "") : "";
|
|
19414
19900
|
r.done(
|
|
19415
19901
|
{
|
|
19416
|
-
take:
|
|
19902
|
+
take: resolve22(dir),
|
|
19417
19903
|
fresh: s.fresh,
|
|
19418
19904
|
cursorKept: s.cursorKept,
|
|
19419
19905
|
zoomAuto,
|
|
@@ -19542,7 +20028,7 @@ async function releaseInputs(dir, flags, r, withRefs = []) {
|
|
|
19542
20028
|
async function cmdRender(argv) {
|
|
19543
20029
|
const { positionals, flags, multi } = parseArgs(
|
|
19544
20030
|
argv,
|
|
19545
|
-
|
|
20031
|
+
BOOLEAN_FLAGS16,
|
|
19546
20032
|
MULTI_FLAGS2
|
|
19547
20033
|
);
|
|
19548
20034
|
const dir = positionals[0];
|
|
@@ -19610,7 +20096,7 @@ async function cmdRender(argv) {
|
|
|
19610
20096
|
async function cmdFrames(argv) {
|
|
19611
20097
|
const { positionals, flags, multi } = parseArgs(
|
|
19612
20098
|
argv,
|
|
19613
|
-
|
|
20099
|
+
BOOLEAN_FLAGS16,
|
|
19614
20100
|
MULTI_FLAGS2
|
|
19615
20101
|
);
|
|
19616
20102
|
const dir = positionals[0];
|
|
@@ -19693,7 +20179,7 @@ async function cmdFrames(argv) {
|
|
|
19693
20179
|
async function cmdDeliver(argv) {
|
|
19694
20180
|
const { positionals, flags, multi } = parseArgs(
|
|
19695
20181
|
argv,
|
|
19696
|
-
|
|
20182
|
+
BOOLEAN_FLAGS16,
|
|
19697
20183
|
MULTI_FLAGS2
|
|
19698
20184
|
);
|
|
19699
20185
|
const dir = positionals[0];
|
|
@@ -19793,15 +20279,15 @@ async function resolveStyleRef(flags) {
|
|
|
19793
20279
|
}
|
|
19794
20280
|
async function resolveDocRef(ref, flags, what) {
|
|
19795
20281
|
const styleRef = ref;
|
|
19796
|
-
const file =
|
|
20282
|
+
const file = existsSync31(styleRef) ? resolve22(
|
|
19797
20283
|
styleRef,
|
|
19798
|
-
|
|
20284
|
+
existsSync31(join33(styleRef, "doc.json")) ? "doc.json" : ""
|
|
19799
20285
|
) : null;
|
|
19800
|
-
if (file &&
|
|
20286
|
+
if (file && existsSync31(file)) {
|
|
19801
20287
|
return {
|
|
19802
20288
|
from: file,
|
|
19803
20289
|
doc: migrateHostedDoc4(
|
|
19804
|
-
JSON.parse(await
|
|
20290
|
+
JSON.parse(await readFile19(file, "utf8"))
|
|
19805
20291
|
)
|
|
19806
20292
|
};
|
|
19807
20293
|
}
|
|
@@ -19843,7 +20329,7 @@ async function officialTemplate(origin, ref) {
|
|
|
19843
20329
|
}
|
|
19844
20330
|
}
|
|
19845
20331
|
async function cmdDigest(argv) {
|
|
19846
|
-
const { positionals, flags } = parseArgs(argv,
|
|
20332
|
+
const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS16);
|
|
19847
20333
|
const dir = positionals[0];
|
|
19848
20334
|
if (!dir)
|
|
19849
20335
|
throw new UsageError(
|
|
@@ -19853,7 +20339,7 @@ async function cmdDigest(argv) {
|
|
|
19853
20339
|
const take = await loadTake(dir);
|
|
19854
20340
|
if (!take.doc) throw new UsageError(`${dir} has no doc.json \u2014 run plan first`);
|
|
19855
20341
|
const transcriptPath = strFlag(flags, "transcript");
|
|
19856
|
-
const transcript = transcriptPath ? parseTranscript(JSON.parse(await
|
|
20342
|
+
const transcript = transcriptPath ? parseTranscript(JSON.parse(await readFile19(transcriptPath, "utf8"))) : null;
|
|
19857
20343
|
const style = await resolveStyleRef(flags);
|
|
19858
20344
|
const noFrames = flags["no-frames"] === true;
|
|
19859
20345
|
let browser = null;
|
|
@@ -19907,19 +20393,19 @@ async function cmdDigest(argv) {
|
|
|
19907
20393
|
}
|
|
19908
20394
|
}
|
|
19909
20395
|
async function cmdOpen(argv) {
|
|
19910
|
-
const { positionals, flags } = parseArgs(argv,
|
|
20396
|
+
const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS16);
|
|
19911
20397
|
const dir = positionals[0];
|
|
19912
20398
|
if (!dir) throw new UsageError("vos open <take> [--studio <url>]");
|
|
19913
20399
|
const r = createReporter(flags.json === true);
|
|
19914
20400
|
const take = await loadTake(dir);
|
|
19915
|
-
if (!
|
|
20401
|
+
if (!existsSync31(take.paths.recording)) {
|
|
19916
20402
|
throw new UsageError(`${dir} has no recording \u2014 re-run record`);
|
|
19917
20403
|
}
|
|
19918
20404
|
const studio = (strFlag(flags, "studio") ?? platformOrigin()).replace(
|
|
19919
20405
|
/\/+$/,
|
|
19920
20406
|
""
|
|
19921
20407
|
);
|
|
19922
|
-
const server = await startTakeServer(
|
|
20408
|
+
const server = await startTakeServer(resolve22(dir), {});
|
|
19923
20409
|
const url = `${studio}/studio?take=${encodeURIComponent(server.base)}`;
|
|
19924
20410
|
r.event({ event: "open", server: server.base, url });
|
|
19925
20411
|
r.log(`take served at ${server.base}`);
|
|
@@ -19942,7 +20428,7 @@ async function cmdOpen(argv) {
|
|
|
19942
20428
|
return EXIT_OK;
|
|
19943
20429
|
}
|
|
19944
20430
|
async function cmdCallout(argv) {
|
|
19945
|
-
const { positionals, flags } = parseArgs(argv,
|
|
20431
|
+
const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS16);
|
|
19946
20432
|
const dir = positionals[0];
|
|
19947
20433
|
const shape = positionals[1];
|
|
19948
20434
|
if (!dir || !shape || !isCalloutShape(shape))
|
|
@@ -19966,7 +20452,7 @@ async function cmdCallout(argv) {
|
|
|
19966
20452
|
`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`
|
|
19967
20453
|
);
|
|
19968
20454
|
const codeFile = strFlag(flags, "code-file");
|
|
19969
|
-
const code = codeFile ? await
|
|
20455
|
+
const code = codeFile ? await readFile19(codeFile, "utf8") : strFlag(flags, "code");
|
|
19970
20456
|
const words2 = {
|
|
19971
20457
|
kicker: strFlag(flags, "kicker"),
|
|
19972
20458
|
title: strFlag(flags, "title"),
|
|
@@ -20041,11 +20527,11 @@ async function cmdCallout(argv) {
|
|
|
20041
20527
|
return EXIT_OK;
|
|
20042
20528
|
}
|
|
20043
20529
|
async function cmdValidate(argv) {
|
|
20044
|
-
const { positionals, flags } = parseArgs(argv,
|
|
20530
|
+
const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS16);
|
|
20045
20531
|
const target = positionals[0];
|
|
20046
20532
|
if (!target) throw new UsageError("vos validate <actions.json|take>");
|
|
20047
20533
|
const r = createReporter(flags.json === true);
|
|
20048
|
-
const kitTarget = target.endsWith("kit.json") ? target :
|
|
20534
|
+
const kitTarget = target.endsWith("kit.json") ? target : existsSync31(join33(target, "kit.json")) && !isTakeDir(target) ? join33(target, "kit.json") : null;
|
|
20049
20535
|
if (kitTarget) {
|
|
20050
20536
|
const picture = flags.picture === true;
|
|
20051
20537
|
const verdict = await validateKit(kitTarget, { picture });
|
|
@@ -20077,9 +20563,9 @@ async function cmdValidate(argv) {
|
|
|
20077
20563
|
r.done({ valid: true, target }, `${target}: valid actions file`);
|
|
20078
20564
|
return EXIT_OK;
|
|
20079
20565
|
}
|
|
20080
|
-
if (!isTakeDir(target) &&
|
|
20566
|
+
if (!isTakeDir(target) && existsSync31(join33(target, "config.json"))) {
|
|
20081
20567
|
const parsed = JSON.parse(
|
|
20082
|
-
await
|
|
20568
|
+
await readFile19(join33(target, "config.json"), "utf8")
|
|
20083
20569
|
);
|
|
20084
20570
|
const pre = preflightConfig(parsed);
|
|
20085
20571
|
const problems2 = pre.ok ? [] : pre.issues.map((i) => `config.json: ${i}`);
|
|
@@ -20121,7 +20607,7 @@ async function cmdValidate(argv) {
|
|
|
20121
20607
|
const problems = [];
|
|
20122
20608
|
const warnings = [];
|
|
20123
20609
|
const notes = [];
|
|
20124
|
-
if (!
|
|
20610
|
+
if (!existsSync31(take.paths.recording)) {
|
|
20125
20611
|
problems.push("missing recording (re-run record)");
|
|
20126
20612
|
} else {
|
|
20127
20613
|
const mismatch = containerMismatch(
|
|
@@ -20162,7 +20648,7 @@ async function cmdValidate(argv) {
|
|
|
20162
20648
|
const found = localFile(rel, target);
|
|
20163
20649
|
if (!("refused" in found)) continue;
|
|
20164
20650
|
problems.push(
|
|
20165
|
-
|
|
20651
|
+
existsSync31(resolve22(target, rel)) ? `doc.json: ${ref.where}: ${ref.key} ${found.refused}` : `doc.json: ${ref.where}: ${ref.key} is not a file in the take, so a render plays the film without it (put the file there, or fix the key)`
|
|
20166
20652
|
);
|
|
20167
20653
|
}
|
|
20168
20654
|
if (flags.picture === true && (take.doc.overlays ?? []).some((o) => o.kind === "html")) {
|
|
@@ -20231,22 +20717,25 @@ async function cmdValidate(argv) {
|
|
|
20231
20717
|
async function cmdPush3(argv) {
|
|
20232
20718
|
const { positionals, flags, multi } = parseArgs(
|
|
20233
20719
|
argv,
|
|
20234
|
-
|
|
20720
|
+
BOOLEAN_FLAGS16,
|
|
20235
20721
|
MULTI_FLAGS2
|
|
20236
20722
|
);
|
|
20237
20723
|
const dir = positionals[0];
|
|
20238
20724
|
if (!dir)
|
|
20239
20725
|
throw new UsageError(
|
|
20240
|
-
"vos push <take> [--vos|--title|--label|--note|--prompt|--folder|--override|--yes|--key|--api|--bake|--claimable [--share]]"
|
|
20726
|
+
"vos push <take> [--vos|--title|--desc|--label|--note|--prompt|--folder|--override|--yes|--key|--api|--bake|--claimable [--share]]"
|
|
20241
20727
|
);
|
|
20242
20728
|
const refusal = takePushRefusal({
|
|
20243
20729
|
vos: strFlag(flags, "vos"),
|
|
20244
|
-
trackedVosId: readSyncState(
|
|
20245
|
-
programOnly: ["slug", "
|
|
20730
|
+
trackedVosId: readSyncState(resolve22(dir))?.vosId ?? null,
|
|
20731
|
+
programOnly: ["slug", "tags", "base", "remix-of", "still"].filter(
|
|
20246
20732
|
(name) => hasFlag(flags, name)
|
|
20247
20733
|
)
|
|
20248
20734
|
});
|
|
20249
20735
|
if (refusal) throw new UsageError(refusal);
|
|
20736
|
+
const description = strFlag(flags, "desc");
|
|
20737
|
+
const descProblem = descriptionProblem(description);
|
|
20738
|
+
if (descProblem) throw new UsageError(descProblem);
|
|
20250
20739
|
const r = createReporter(flags.json === true);
|
|
20251
20740
|
if (flags.claimable === true) {
|
|
20252
20741
|
const iterating = ["vos", "folder", "override", "base"].filter(
|
|
@@ -20257,12 +20746,13 @@ async function cmdPush3(argv) {
|
|
|
20257
20746
|
`--claimable creates a NEW claimable vos; ${iterating.map((f) => `--${f}`).join(", ")} ${iterating.length > 1 ? "apply" : "applies"} to a keyed push`
|
|
20258
20747
|
);
|
|
20259
20748
|
const claim = await pushTakeClaimable(
|
|
20260
|
-
|
|
20749
|
+
resolve22(dir),
|
|
20261
20750
|
{
|
|
20262
20751
|
api: strFlag(flags, "api"),
|
|
20263
20752
|
origin: strFlag(flags, "origin"),
|
|
20264
20753
|
title: strFlag(flags, "title"),
|
|
20265
20754
|
prompt: strFlag(flags, "prompt"),
|
|
20755
|
+
description,
|
|
20266
20756
|
share: flags.share === true,
|
|
20267
20757
|
bake: flags.bake === true
|
|
20268
20758
|
},
|
|
@@ -20280,7 +20770,7 @@ reference and the only credential.`
|
|
|
20280
20770
|
}
|
|
20281
20771
|
const overrides = multi.override;
|
|
20282
20772
|
const result = await pushTake(
|
|
20283
|
-
|
|
20773
|
+
resolve22(dir),
|
|
20284
20774
|
{
|
|
20285
20775
|
key: strFlag(flags, "key"),
|
|
20286
20776
|
api: strFlag(flags, "api"),
|
|
@@ -20293,6 +20783,7 @@ reference and the only credential.`
|
|
|
20293
20783
|
folder: strFlag(flags, "folder"),
|
|
20294
20784
|
overrides,
|
|
20295
20785
|
prompt: strFlag(flags, "prompt"),
|
|
20786
|
+
description,
|
|
20296
20787
|
bake: flags.bake === true
|
|
20297
20788
|
},
|
|
20298
20789
|
r
|
|
@@ -20331,11 +20822,11 @@ ${landedLines(landed)}` : "")
|
|
|
20331
20822
|
return EXIT_OK;
|
|
20332
20823
|
}
|
|
20333
20824
|
async function cmdPull2(argv) {
|
|
20334
|
-
const { positionals, flags } = parseArgs(argv,
|
|
20825
|
+
const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS16, MULTI_FLAGS2);
|
|
20335
20826
|
const dir = positionals[0] ?? ".";
|
|
20336
20827
|
const r = createReporter(flags.json === true);
|
|
20337
20828
|
const result = await pullTake(
|
|
20338
|
-
|
|
20829
|
+
resolve22(dir),
|
|
20339
20830
|
{
|
|
20340
20831
|
key: strFlag(flags, "key"),
|
|
20341
20832
|
api: strFlag(flags, "api"),
|
|
@@ -20470,6 +20961,8 @@ async function run(argv) {
|
|
|
20470
20961
|
return await cmdScore(rest);
|
|
20471
20962
|
case "audio":
|
|
20472
20963
|
return await cmdAudio(rest);
|
|
20964
|
+
case "music":
|
|
20965
|
+
return await cmdMusic(rest);
|
|
20473
20966
|
case "look":
|
|
20474
20967
|
return await cmdLook(rest);
|
|
20475
20968
|
default:
|
|
@@ -20512,7 +21005,7 @@ function verdictExit(v, strict, none) {
|
|
|
20512
21005
|
async function cmdSession(argv) {
|
|
20513
21006
|
const { positionals, flags } = parseArgs(
|
|
20514
21007
|
argv,
|
|
20515
|
-
/* @__PURE__ */ new Set([...
|
|
21008
|
+
/* @__PURE__ */ new Set([...BOOLEAN_FLAGS16, "headed"])
|
|
20516
21009
|
);
|
|
20517
21010
|
const [sub, arg] = positionals;
|
|
20518
21011
|
const r = createReporter(flags.json === true);
|
|
@@ -20557,7 +21050,7 @@ async function cmdSession(argv) {
|
|
|
20557
21050
|
if (!arg) throw new UsageError(usage);
|
|
20558
21051
|
const bad = sessionNameVerdict(arg);
|
|
20559
21052
|
if (bad) throw new UsageError(bad);
|
|
20560
|
-
if (!
|
|
21053
|
+
if (!existsSync31(sessionDir(arg)))
|
|
20561
21054
|
throw new UsageError(`no session "${arg}" (vos session list)`);
|
|
20562
21055
|
const summary3 = await summarizeSession(arg);
|
|
20563
21056
|
const url = strFlag(flags, "url");
|
|
@@ -20591,7 +21084,7 @@ async function cmdSession(argv) {
|
|
|
20591
21084
|
if (!arg || !scriptPath) throw new UsageError(usage);
|
|
20592
21085
|
const bad = sessionNameVerdict(arg);
|
|
20593
21086
|
if (bad) throw new UsageError(bad);
|
|
20594
|
-
if (!
|
|
21087
|
+
if (!existsSync31(sessionDir(arg)))
|
|
20595
21088
|
throw new UsageError(`no session "${arg}" (vos session list)`);
|
|
20596
21089
|
const url = strFlag(flags, "url");
|
|
20597
21090
|
if (url && !/^https?:\/\//.test(url))
|
|
@@ -20684,4 +21177,4 @@ export {
|
|
|
20684
21177
|
verbHelp,
|
|
20685
21178
|
run
|
|
20686
21179
|
};
|
|
20687
|
-
//# sourceMappingURL=chunk-
|
|
21180
|
+
//# sourceMappingURL=chunk-NJBUBXFE.js.map
|