@vosjs/cli 0.61.0 → 0.64.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 +6 -4
- package/dist/{assetManifest-NS64PLY5.js → assetManifest-RQYJYQ7Q.js} +3 -3
- package/dist/{chunk-EZW6ZCEH.js → chunk-7CIAU4QP.js} +35 -11
- package/dist/chunk-7CIAU4QP.js.map +1 -0
- package/dist/{chunk-WZGCEAXB.js → chunk-AUFY3M22.js} +2 -2
- package/dist/{chunk-WZGCEAXB.js.map → chunk-AUFY3M22.js.map} +1 -1
- package/dist/{chunk-C4P6MZJG.js → chunk-CODEEH2Z.js} +627 -139
- package/dist/chunk-CODEEH2Z.js.map +1 -0
- package/dist/{chunk-LWHVZ5WI.js → chunk-DU3ANWU4.js} +2 -2
- package/dist/{chunk-WCF6KIOK.js → chunk-WVQAZTYU.js} +29 -2
- package/dist/chunk-WVQAZTYU.js.map +1 -0
- package/dist/cli.js +7 -7
- package/dist/index.js +5 -5
- package/dist/manifest-ZBK6IERM.js +8 -0
- package/dist/{run-IZ72SDZC.js → run-GYCIE77C.js} +5 -5
- package/package.json +5 -5
- package/schema/doc.schema.json +1 -1
- package/skills/VERSION +1 -1
- package/skills/vos-authoring/references/schema-reference.md +2 -0
- package/skills/vos-remix/references/3d-recipe.md +16 -10
- package/dist/chunk-C4P6MZJG.js.map +0 -1
- package/dist/chunk-EZW6ZCEH.js.map +0 -1
- package/dist/chunk-WCF6KIOK.js.map +0 -1
- package/dist/manifest-Q4QMVIYR.js +0 -8
- /package/dist/{assetManifest-NS64PLY5.js.map → assetManifest-RQYJYQ7Q.js.map} +0 -0
- /package/dist/{chunk-LWHVZ5WI.js.map → chunk-DU3ANWU4.js.map} +0 -0
- /package/dist/{manifest-Q4QMVIYR.js.map → manifest-ZBK6IERM.js.map} +0 -0
- /package/dist/{run-IZ72SDZC.js.map → run-GYCIE77C.js.map} +0 -0
|
@@ -9,11 +9,10 @@ import {
|
|
|
9
9
|
reencodeStill,
|
|
10
10
|
renderStill,
|
|
11
11
|
videoFormat
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-DU3ANWU4.js";
|
|
13
13
|
import {
|
|
14
14
|
PREV_DOC_NAME,
|
|
15
15
|
RECORDING_NAME,
|
|
16
|
-
docAudioRefs,
|
|
17
16
|
docLayerRefs,
|
|
18
17
|
docMediaRefs,
|
|
19
18
|
dropScreencastFrames,
|
|
@@ -34,7 +33,7 @@ import {
|
|
|
34
33
|
uploadDocRefs,
|
|
35
34
|
uploadManifest,
|
|
36
35
|
writeJson
|
|
37
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-7CIAU4QP.js";
|
|
38
37
|
import {
|
|
39
38
|
CREDENTIALS_PATH,
|
|
40
39
|
MEDIA_HEAD_BYTES,
|
|
@@ -48,6 +47,7 @@ import {
|
|
|
48
47
|
formatChanges,
|
|
49
48
|
hasFlag,
|
|
50
49
|
hostedAssetId,
|
|
50
|
+
localFile,
|
|
51
51
|
manifestRefs,
|
|
52
52
|
nameForType,
|
|
53
53
|
numFlag2 as numFlag,
|
|
@@ -64,7 +64,7 @@ import {
|
|
|
64
64
|
strFlag,
|
|
65
65
|
writeCredential,
|
|
66
66
|
writeSyncState
|
|
67
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-WVQAZTYU.js";
|
|
68
68
|
import {
|
|
69
69
|
deadLine,
|
|
70
70
|
deadWarns
|
|
@@ -127,7 +127,7 @@ function landedLines(l) {
|
|
|
127
127
|
|
|
128
128
|
// src/plugin/run.ts
|
|
129
129
|
import { mkdir as mkdir9, readFile as readFile15, rm as rm3 } from "fs/promises";
|
|
130
|
-
import { existsSync as
|
|
130
|
+
import { existsSync as existsSync24 } from "fs";
|
|
131
131
|
import { join as join26, resolve as resolve15 } from "path";
|
|
132
132
|
import {
|
|
133
133
|
END_CARD_FROM as END_CARD_FROM2,
|
|
@@ -146,6 +146,15 @@ function createReporter(json) {
|
|
|
146
146
|
json,
|
|
147
147
|
log: (msg) => {
|
|
148
148
|
if (!json) process.stderr.write(`${msg}
|
|
149
|
+
`);
|
|
150
|
+
},
|
|
151
|
+
warn: (msg) => {
|
|
152
|
+
if (json) {
|
|
153
|
+
process.stdout.write(
|
|
154
|
+
`${JSON.stringify({ event: "warning", message: msg })}
|
|
155
|
+
`
|
|
156
|
+
);
|
|
157
|
+
} else process.stderr.write(`warning ${msg}
|
|
149
158
|
`);
|
|
150
159
|
},
|
|
151
160
|
event: (obj) => {
|
|
@@ -346,6 +355,20 @@ function lintFrom(name, from, problems) {
|
|
|
346
355
|
var EPS = 1e-3;
|
|
347
356
|
var isNum = (v) => typeof v === "number" && Number.isFinite(v);
|
|
348
357
|
var isObj = (v) => typeof v === "object" && v !== null;
|
|
358
|
+
function htmlFontUrlProblem(url) {
|
|
359
|
+
if (/^https?:\/\//.test(url)) return null;
|
|
360
|
+
if (/^\/api\/assets\/[^/]+\/file$/.test(url)) return null;
|
|
361
|
+
if (/^(data:|blob:)/.test(url) || url.startsWith("/")) {
|
|
362
|
+
return `must be an https URL, a hosted file (/api/assets/<id>/file) or a .woff2 beside the document (got ${url})`;
|
|
363
|
+
}
|
|
364
|
+
if (url.split(/[\\/]/).includes("..")) {
|
|
365
|
+
return `names ${url}, outside the document's directory: copy the font beside doc.json`;
|
|
366
|
+
}
|
|
367
|
+
if (!/\.woff2$/i.test(url)) {
|
|
368
|
+
return `names ${url}: an HTML layer embeds its faces as woff2, so convert it (for example: pyftsubset or woff2_compress) and name the .woff2`;
|
|
369
|
+
}
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
349
372
|
var entries = (v) => Array.isArray(v) ? v.filter(isObj) : [];
|
|
350
373
|
var spanName = (label, s) => `${label} ${typeof s.id === "string" ? s.id : `@${String(s.in)}`}`;
|
|
351
374
|
var TRANSITION_SPEEDS = ["instant", "fast", "smooth", "slow"];
|
|
@@ -1249,10 +1272,14 @@ function lintDoc(docIn) {
|
|
|
1249
1272
|
);
|
|
1250
1273
|
} else {
|
|
1251
1274
|
o.fonts.forEach((f, fi) => {
|
|
1252
|
-
if (!isObj(f) || typeof f.family !== "string" || typeof f.url !== "string" ||
|
|
1275
|
+
if (!isObj(f) || typeof f.family !== "string" || typeof f.url !== "string" || !f.url) {
|
|
1253
1276
|
problems.push(
|
|
1254
|
-
`${name}.fonts[${fi}] must be { family, url
|
|
1277
|
+
`${name}.fonts[${fi}] must be { family, url, weight?, style? }: a face the catalog does not host. A hosted family needs no entry; name it in the CSS`
|
|
1255
1278
|
);
|
|
1279
|
+
return;
|
|
1280
|
+
}
|
|
1281
|
+
const problem = htmlFontUrlProblem(f.url);
|
|
1282
|
+
if (problem) problems.push(`${name}.fonts[${fi}].url ${problem}`);
|
|
1256
1283
|
});
|
|
1257
1284
|
}
|
|
1258
1285
|
}
|
|
@@ -2526,9 +2553,9 @@ function parsePath(path) {
|
|
|
2526
2553
|
if (expectKey) bad();
|
|
2527
2554
|
const j = path.indexOf("]", i);
|
|
2528
2555
|
if (j < 0) bad();
|
|
2529
|
-
const
|
|
2530
|
-
if (!/^\d+$/.test(
|
|
2531
|
-
segs.push({ key: Number(
|
|
2556
|
+
const num2 = path.slice(i + 1, j);
|
|
2557
|
+
if (!/^\d+$/.test(num2)) bad();
|
|
2558
|
+
segs.push({ key: Number(num2) });
|
|
2532
2559
|
i = j + 1;
|
|
2533
2560
|
} else {
|
|
2534
2561
|
let j = i;
|
|
@@ -3911,11 +3938,11 @@ var DUPLICATE_BITS = 6;
|
|
|
3911
3938
|
var POPULATED_INK = 0.12;
|
|
3912
3939
|
function pickMoments(measured, opts = {}) {
|
|
3913
3940
|
const minInk = opts.minInk ?? 0.06;
|
|
3914
|
-
const
|
|
3941
|
+
const relative4 = opts.relativeInk ?? 0.4;
|
|
3915
3942
|
const bits = opts.duplicateBits ?? DUPLICATE_BITS;
|
|
3916
3943
|
const inks = measured.map((m) => m.ink).sort((a, b) => a - b);
|
|
3917
3944
|
const median2 = inks[inks.length >> 1] ?? 0;
|
|
3918
|
-
const floor = Math.max(minInk, Math.min(POPULATED_INK, median2 *
|
|
3945
|
+
const floor = Math.max(minInk, Math.min(POPULATED_INK, median2 * relative4));
|
|
3919
3946
|
const kept = [];
|
|
3920
3947
|
const dropped = [];
|
|
3921
3948
|
for (const m of measured) {
|
|
@@ -7473,10 +7500,10 @@ async function pullTake(dir, flags, r) {
|
|
|
7473
7500
|
}
|
|
7474
7501
|
|
|
7475
7502
|
// src/plugin/program.ts
|
|
7476
|
-
import { existsSync as
|
|
7503
|
+
import { existsSync as existsSync14 } from "fs";
|
|
7477
7504
|
import { mkdir as mkdir7, readFile as readFile13, writeFile as writeFile9 } from "fs/promises";
|
|
7478
7505
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
7479
|
-
import { basename as
|
|
7506
|
+
import { basename as basename3, dirname as dirname3, join as join15 } from "path";
|
|
7480
7507
|
import {
|
|
7481
7508
|
CURRENT_CONFIG_VERSION,
|
|
7482
7509
|
migrateConfig,
|
|
@@ -7608,6 +7635,112 @@ async function handoffLogin(url, r, opts = {}) {
|
|
|
7608
7635
|
throw new Error(`${said}${hint}`);
|
|
7609
7636
|
}
|
|
7610
7637
|
|
|
7638
|
+
// src/plugin/programFiles.ts
|
|
7639
|
+
import { basename as basename2, extname as extname2, relative as relative2 } from "path";
|
|
7640
|
+
import { existsSync as existsSync13, realpathSync } from "fs";
|
|
7641
|
+
function isLocalName(value) {
|
|
7642
|
+
if (/^(https?:|data:|blob:|asset:|media:)/.test(value)) return false;
|
|
7643
|
+
if (value.startsWith("$")) return false;
|
|
7644
|
+
if (value.startsWith("/")) return existsSync13(value);
|
|
7645
|
+
return true;
|
|
7646
|
+
}
|
|
7647
|
+
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;
|
|
7648
|
+
function manifestName(file, taken) {
|
|
7649
|
+
const stem = basename2(file, extname2(file)).replace(/[^A-Za-z0-9_]/g, "_").replace(/^(?=[0-9])/, "_") || "file";
|
|
7650
|
+
let name = stem;
|
|
7651
|
+
for (let n = 2; taken.has(name); n++) name = `${stem}_${n}`;
|
|
7652
|
+
taken.add(name);
|
|
7653
|
+
return name;
|
|
7654
|
+
}
|
|
7655
|
+
function liftNamedFiles(config, dir) {
|
|
7656
|
+
const manifest = config.assets ?? {};
|
|
7657
|
+
const taken = new Set(Object.keys(manifest));
|
|
7658
|
+
const lifted = [];
|
|
7659
|
+
const lift = (where, value, kind) => {
|
|
7660
|
+
if (typeof value !== "string" || !value || !isLocalName(value)) return null;
|
|
7661
|
+
const found = localFile(value, dir);
|
|
7662
|
+
if ("refused" in found) {
|
|
7663
|
+
if (found.refused.startsWith("which is outside")) {
|
|
7664
|
+
throw new Error(`${where} names ${value}, ${found.refused}`);
|
|
7665
|
+
}
|
|
7666
|
+
return null;
|
|
7667
|
+
}
|
|
7668
|
+
const name = manifestName(value, taken);
|
|
7669
|
+
manifest[name] = kind ? { ref: value, kind } : { ref: value };
|
|
7670
|
+
lifted.push(`${where} \u2192 assets.${name}`);
|
|
7671
|
+
return `$assets.${name}`;
|
|
7672
|
+
};
|
|
7673
|
+
const elements = Array.isArray(config.elements) ? config.elements : [];
|
|
7674
|
+
elements.forEach((el, i) => {
|
|
7675
|
+
const e = el;
|
|
7676
|
+
if (!e || e.type === "text") return;
|
|
7677
|
+
const next = lift(`elements[${i}].src`, e.src);
|
|
7678
|
+
if (next) e.src = next;
|
|
7679
|
+
});
|
|
7680
|
+
const fonts = Array.isArray(config.fonts) ? config.fonts : [];
|
|
7681
|
+
fonts.forEach((f, i) => {
|
|
7682
|
+
const font = f;
|
|
7683
|
+
const next = lift(`fonts[${i}].url`, font?.url, "font");
|
|
7684
|
+
if (next) font.url = next;
|
|
7685
|
+
});
|
|
7686
|
+
if (lifted.length) config.assets = manifest;
|
|
7687
|
+
return lifted;
|
|
7688
|
+
}
|
|
7689
|
+
function localDataRefs(config, dir) {
|
|
7690
|
+
const refs = [];
|
|
7691
|
+
const root = realpathSync(dir);
|
|
7692
|
+
const walk = (value, where, set) => {
|
|
7693
|
+
if (typeof value === "string") {
|
|
7694
|
+
if (!isLocalName(value) || !FILE_EXT.test(value)) return;
|
|
7695
|
+
const found = localFile(value, dir);
|
|
7696
|
+
if ("refused" in found) return;
|
|
7697
|
+
refs.push({ where, key: relative2(root, found.file), set });
|
|
7698
|
+
return;
|
|
7699
|
+
}
|
|
7700
|
+
if (Array.isArray(value)) {
|
|
7701
|
+
value.forEach(
|
|
7702
|
+
(v, i) => walk(v, `${where}[${i}]`, (next) => {
|
|
7703
|
+
value[i] = next;
|
|
7704
|
+
})
|
|
7705
|
+
);
|
|
7706
|
+
return;
|
|
7707
|
+
}
|
|
7708
|
+
if (value && typeof value === "object") {
|
|
7709
|
+
const obj = value;
|
|
7710
|
+
for (const k of Object.keys(obj)) {
|
|
7711
|
+
walk(obj[k], `${where}.${k}`, (next) => {
|
|
7712
|
+
obj[k] = next;
|
|
7713
|
+
});
|
|
7714
|
+
}
|
|
7715
|
+
}
|
|
7716
|
+
};
|
|
7717
|
+
walk(config.data, "data", () => {
|
|
7718
|
+
});
|
|
7719
|
+
return refs;
|
|
7720
|
+
}
|
|
7721
|
+
var FUNCTION_FIELDS = ["setup", "createContent", "createTimeline", "onFrame"];
|
|
7722
|
+
var QUOTED = /(['"`])([^'"`\n]{1,200}?)\1/g;
|
|
7723
|
+
function codeFileWarnings(config, dir) {
|
|
7724
|
+
const out = [];
|
|
7725
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7726
|
+
const scan = (label, src) => {
|
|
7727
|
+
if (typeof src !== "string") return;
|
|
7728
|
+
for (const m of src.matchAll(QUOTED)) {
|
|
7729
|
+
const value = m[2];
|
|
7730
|
+
if (seen.has(value) || !isLocalName(value) || !FILE_EXT.test(value)) {
|
|
7731
|
+
continue;
|
|
7732
|
+
}
|
|
7733
|
+
if ("refused" in localFile(value, dir)) continue;
|
|
7734
|
+
seen.add(value);
|
|
7735
|
+
out.push(
|
|
7736
|
+
`${label} names ${value} in code, which no push can carry. Declare it: "assets": { "name": { "ref": "${value}" } }, and read ctx.assets.name`
|
|
7737
|
+
);
|
|
7738
|
+
}
|
|
7739
|
+
};
|
|
7740
|
+
for (const field of FUNCTION_FIELDS) scan(field, config[field]);
|
|
7741
|
+
return out;
|
|
7742
|
+
}
|
|
7743
|
+
|
|
7611
7744
|
// src/plugin/program.ts
|
|
7612
7745
|
var BOOLEAN_FLAGS2 = /* @__PURE__ */ new Set([
|
|
7613
7746
|
"json",
|
|
@@ -7616,6 +7749,7 @@ var BOOLEAN_FLAGS2 = /* @__PURE__ */ new Set([
|
|
|
7616
7749
|
"check",
|
|
7617
7750
|
"yes",
|
|
7618
7751
|
"claimable",
|
|
7752
|
+
"share",
|
|
7619
7753
|
"no-browser",
|
|
7620
7754
|
"wait"
|
|
7621
7755
|
]);
|
|
@@ -7683,7 +7817,7 @@ function preflightConfig(parsed) {
|
|
|
7683
7817
|
function resolveConfigPath(target) {
|
|
7684
7818
|
if (target.endsWith(".json")) return target;
|
|
7685
7819
|
const inDir = join15(target, "config.json");
|
|
7686
|
-
if (
|
|
7820
|
+
if (existsSync14(inDir)) return inDir;
|
|
7687
7821
|
throw new UsageError(
|
|
7688
7822
|
`${target} has no config.json (and is not a take \u2014 no doc.json)`
|
|
7689
7823
|
);
|
|
@@ -7833,6 +7967,7 @@ async function createProgramVos(opts) {
|
|
|
7833
7967
|
client: clientId()
|
|
7834
7968
|
};
|
|
7835
7969
|
if (opts.description) body.description = opts.description;
|
|
7970
|
+
if (opts.prompt) body.prompt = opts.prompt;
|
|
7836
7971
|
if (opts.tags?.length) body.tags = opts.tags;
|
|
7837
7972
|
if (opts.folderId) body.folderId = opts.folderId;
|
|
7838
7973
|
if (opts.remixOfId) body.remixOfId = opts.remixOfId;
|
|
@@ -7867,7 +8002,7 @@ async function cmdPushProgram(argv) {
|
|
|
7867
8002
|
const target = positionals[0];
|
|
7868
8003
|
if (!target) {
|
|
7869
8004
|
throw new UsageError(
|
|
7870
|
-
|
|
8005
|
+
'vos push <config.json|take> [--vos id] [--title t] [--slug s] [--desc d] [--tags a,b] [--folder <id|slug>] [--remix-of id] [--note n] [--label l] [--base versionId] [--override id]... [--prompt "<the prompt that made it>"] [--claimable [--share]]'
|
|
7871
8006
|
);
|
|
7872
8007
|
}
|
|
7873
8008
|
const source = resolveConfigPath(target);
|
|
@@ -7887,6 +8022,12 @@ async function cmdPushProgram(argv) {
|
|
|
7887
8022
|
}
|
|
7888
8023
|
const config = pre.config;
|
|
7889
8024
|
const state = readSyncState(dir);
|
|
8025
|
+
const prompt = strFlag(flags, "prompt");
|
|
8026
|
+
if (flags.share === true && flags.claimable !== true) {
|
|
8027
|
+
throw new UsageError(
|
|
8028
|
+
'--share asks a claimable push to lead its claim page with "Claim and share". A key can never publish: open the watch page and set it to Unlisted or Public there'
|
|
8029
|
+
);
|
|
8030
|
+
}
|
|
7890
8031
|
const vosFlag = strFlag(flags, "vos");
|
|
7891
8032
|
const explicitVosId = vosFlag ? parseVosId(vosFlag) : null;
|
|
7892
8033
|
const stillFlag = strFlag(flags, "still");
|
|
@@ -7897,7 +8038,8 @@ async function cmdPushProgram(argv) {
|
|
|
7897
8038
|
await setProgramStill(dir, t);
|
|
7898
8039
|
r.log(`cover: ${t}s (doc.json "still")`);
|
|
7899
8040
|
}
|
|
7900
|
-
for (const w of hostedLiteralWarnings(config)) r.
|
|
8041
|
+
for (const w of hostedLiteralWarnings(config)) r.warn(w);
|
|
8042
|
+
for (const w of codeFileWarnings(config, dir)) r.warn(w);
|
|
7901
8043
|
const programDoc = await readProgramDoc(dir, config);
|
|
7902
8044
|
if (programDoc) {
|
|
7903
8045
|
const lint = lintDoc(programDoc);
|
|
@@ -7905,7 +8047,7 @@ async function cmdPushProgram(argv) {
|
|
|
7905
8047
|
throw new Error(`doc.json fails lint:
|
|
7906
8048
|
${lint.problems.join("\n ")}`);
|
|
7907
8049
|
}
|
|
7908
|
-
for (const w of lint.warnings) r.
|
|
8050
|
+
for (const w of lint.warnings) r.warn(`doc.json: ${w}`);
|
|
7909
8051
|
}
|
|
7910
8052
|
if (flags.claimable === true) {
|
|
7911
8053
|
if (explicitVosId) {
|
|
@@ -7913,43 +8055,50 @@ async function cmdPushProgram(argv) {
|
|
|
7913
8055
|
"--claimable creates a NEW claimable vos and cannot iterate (--vos). After the human claims it, iterate with their key: vos push --vos <id>"
|
|
7914
8056
|
);
|
|
7915
8057
|
}
|
|
7916
|
-
const fallback = state?.title ? `${state.title} remix` :
|
|
8058
|
+
const fallback = state?.title ? `${state.title} remix` : basename3(source).replace(/\.json$/i, "") || "vos program";
|
|
7917
8059
|
const title2 = (strFlag(flags, "title") ?? fallback).slice(0, 100);
|
|
7918
|
-
|
|
7919
|
-
|
|
7920
|
-
|
|
7921
|
-
const
|
|
7922
|
-
|
|
7923
|
-
|
|
7924
|
-
|
|
7925
|
-
|
|
7926
|
-
audio: (sound.audio ?? []).filter((a) => !dropped.has(a.key))
|
|
7927
|
-
};
|
|
7928
|
-
r.log(
|
|
7929
|
-
`warning a claimable push carries no files, so ${local.length} local sound${local.length === 1 ? "" : "s"} (${[...dropped].join(", ")}) ${local.length === 1 ? "was" : "were"} left out. After the claim, push again with a key to add ${local.length === 1 ? "it" : "them"}`
|
|
7930
|
-
);
|
|
8060
|
+
const files2 = await collectFiles(config, programDoc, dir, r);
|
|
8061
|
+
let uploadToken;
|
|
8062
|
+
if (files2.count > 0) {
|
|
8063
|
+
const opened = await apiJson(origin, "/api/claim/uploads", {
|
|
8064
|
+
method: "POST"
|
|
8065
|
+
});
|
|
8066
|
+
if (opened.status !== 201) {
|
|
8067
|
+
throw new Error(apiError("open a claim upload session", opened));
|
|
7931
8068
|
}
|
|
7932
|
-
|
|
7933
|
-
|
|
7934
|
-
|
|
7935
|
-
throw new UsageError(
|
|
7936
|
-
`a claimable push carries no files, and this program declares ${stay.length} local file${stay.length === 1 ? "" : "s"} (${stay.join(", ")}). Push with a key instead (vos login, then vos push ${source}), which uploads ${stay.length === 1 ? "it" : "them"}`
|
|
8069
|
+
uploadToken = String(opened.body.uploadToken);
|
|
8070
|
+
r.log(
|
|
8071
|
+
`uploading ${files2.count} file${files2.count === 1 ? "" : "s"} with the claim`
|
|
7937
8072
|
);
|
|
8073
|
+
await files2.upload({
|
|
8074
|
+
origin,
|
|
8075
|
+
key: uploadToken,
|
|
8076
|
+
door: "/api/claim/uploads/files"
|
|
8077
|
+
});
|
|
7938
8078
|
}
|
|
7939
8079
|
const body = {
|
|
7940
8080
|
title: title2,
|
|
7941
|
-
config: storedProgramConfig(config,
|
|
8081
|
+
config: storedProgramConfig(config, programDoc)
|
|
7942
8082
|
};
|
|
8083
|
+
if (uploadToken) body.uploadToken = uploadToken;
|
|
8084
|
+
if (prompt) body.prompt = prompt;
|
|
8085
|
+
if (flags.share === true) body.share = true;
|
|
7943
8086
|
const slug = strFlag(flags, "slug");
|
|
7944
8087
|
if (slug) body.slug = slug;
|
|
7945
8088
|
const res = await apiJson(origin, "/api/claim", { method: "POST", body });
|
|
7946
8089
|
if (res.status !== 201) throw new Error(apiError("claimable push", res));
|
|
7947
|
-
serverWarnings(res.body, (
|
|
8090
|
+
serverWarnings(res.body, say(r));
|
|
7948
8091
|
const claimUrl = String(res.body.claimUrl ?? "");
|
|
7949
8092
|
const expiresAt = String(res.body.expiresAt ?? "");
|
|
7950
8093
|
const created2 = res.body.vos ?? {};
|
|
7951
8094
|
r.done(
|
|
7952
|
-
{
|
|
8095
|
+
{
|
|
8096
|
+
id: created2.id ?? null,
|
|
8097
|
+
title: title2,
|
|
8098
|
+
claimUrl,
|
|
8099
|
+
expiresAt,
|
|
8100
|
+
...uploadToken ? { files: files2.count } : {}
|
|
8101
|
+
},
|
|
7953
8102
|
`Claimable push created (${title2})
|
|
7954
8103
|
claim: ${claimUrl}
|
|
7955
8104
|
expires: ${expiresAt} \u2014 unclaimed work is deleted after 72h
|
|
@@ -7961,15 +8110,8 @@ with their key: vos push ${source} --vos ${String(created2.id ?? "<id>")}`
|
|
|
7961
8110
|
}
|
|
7962
8111
|
const key = requireCredential(strFlag(flags, "key"));
|
|
7963
8112
|
void flags.yes;
|
|
7964
|
-
|
|
7965
|
-
|
|
7966
|
-
docLayerRefs(layersOf(programDoc)),
|
|
7967
|
-
dir,
|
|
7968
|
-
{ origin, key },
|
|
7969
|
-
(l) => r.log(l)
|
|
7970
|
-
);
|
|
7971
|
-
}
|
|
7972
|
-
await uploadManifest(config, dir, { origin, key }, (l) => r.log(l));
|
|
8113
|
+
const files = await collectFiles(config, programDoc, dir, r);
|
|
8114
|
+
await files.upload({ origin, key });
|
|
7973
8115
|
const overrides = [
|
|
7974
8116
|
...multi.override ?? [],
|
|
7975
8117
|
...strFlag(flags, "overrides")?.split(",") ?? []
|
|
@@ -8033,7 +8175,15 @@ with their key: vos push ${source} --vos ${String(created2.id ?? "<id>")}`
|
|
|
8033
8175
|
}
|
|
8034
8176
|
if (res.status !== 201)
|
|
8035
8177
|
throw new Error(apiError(`push version to ${vosId}`, res));
|
|
8036
|
-
serverWarnings(res.body, (
|
|
8178
|
+
serverWarnings(res.body, say(r));
|
|
8179
|
+
if (prompt) {
|
|
8180
|
+
const set = await apiJson(origin, `/api/vos/${vosId}`, {
|
|
8181
|
+
method: "PATCH",
|
|
8182
|
+
key,
|
|
8183
|
+
body: { prompt }
|
|
8184
|
+
});
|
|
8185
|
+
if (set.status !== 200) r.warn(apiError("set the prompt", set));
|
|
8186
|
+
}
|
|
8037
8187
|
const version = res.body.version ?? {};
|
|
8038
8188
|
if (typeof version.id === "string") {
|
|
8039
8189
|
writeSyncState(dir, { vosId, versionId: version.id });
|
|
@@ -8045,7 +8195,7 @@ with their key: vos push ${source} --vos ${String(created2.id ?? "<id>")}`
|
|
|
8045
8195
|
key,
|
|
8046
8196
|
vosId,
|
|
8047
8197
|
versionId: typeof version.id === "string" ? version.id : null,
|
|
8048
|
-
log: (
|
|
8198
|
+
log: say(r)
|
|
8049
8199
|
}) : null;
|
|
8050
8200
|
r.done(
|
|
8051
8201
|
{
|
|
@@ -8069,7 +8219,7 @@ ${landedLines(landed2)}` : "")
|
|
|
8069
8219
|
return EXIT_OK;
|
|
8070
8220
|
}
|
|
8071
8221
|
const remixOfId = pushTarget.kind === "create" ? pushTarget.remixOfId : void 0;
|
|
8072
|
-
const fallbackTitle = state?.title ? `${state.title} remix` :
|
|
8222
|
+
const fallbackTitle = state?.title ? `${state.title} remix` : basename3(source).replace(/\.json$/i, "") || "vos remix";
|
|
8073
8223
|
const title = (strFlag(flags, "title") ?? fallbackTitle).slice(0, 100);
|
|
8074
8224
|
const folderId = folderRef ? resolveFolder(await listFolders(origin, key), folderRef).id : void 0;
|
|
8075
8225
|
const created = await createProgramVos({
|
|
@@ -8081,6 +8231,7 @@ ${landedLines(landed2)}` : "")
|
|
|
8081
8231
|
// (found seeding one-layer members: `--with` then said the vos carried
|
|
8082
8232
|
// no doc).
|
|
8083
8233
|
doc: programDoc ?? void 0,
|
|
8234
|
+
prompt,
|
|
8084
8235
|
title,
|
|
8085
8236
|
slug: strFlag(flags, "slug"),
|
|
8086
8237
|
description: desc,
|
|
@@ -8105,7 +8256,7 @@ ${landedLines(landed2)}` : "")
|
|
|
8105
8256
|
key,
|
|
8106
8257
|
vosId: created.id,
|
|
8107
8258
|
versionId: created.currentVersionId,
|
|
8108
|
-
log: (
|
|
8259
|
+
log: say(r)
|
|
8109
8260
|
}) : null;
|
|
8110
8261
|
r.done(
|
|
8111
8262
|
{
|
|
@@ -8203,7 +8354,7 @@ async function cmdPullProgram(argv) {
|
|
|
8203
8354
|
throw new Error(apiError(`fetch head config for ${vosId}`, cfg));
|
|
8204
8355
|
const configPath = join15(dir, "config.json");
|
|
8205
8356
|
let backedUp = false;
|
|
8206
|
-
if (
|
|
8357
|
+
if (existsSync14(configPath)) {
|
|
8207
8358
|
await writeFile9(join15(dir, "config.backup.json"), await readFile13(configPath));
|
|
8208
8359
|
backedUp = true;
|
|
8209
8360
|
}
|
|
@@ -8308,6 +8459,27 @@ async function storeKey(key, origin, r) {
|
|
|
8308
8459
|
function isTakeDir(target) {
|
|
8309
8460
|
return directoryKind(target) === "take";
|
|
8310
8461
|
}
|
|
8462
|
+
function say(r) {
|
|
8463
|
+
return (line) => {
|
|
8464
|
+
const m = /^\s*warning\s+(.*)$/s.exec(line);
|
|
8465
|
+
if (m) r.warn(m[1]);
|
|
8466
|
+
else r.log(line);
|
|
8467
|
+
};
|
|
8468
|
+
}
|
|
8469
|
+
async function collectFiles(config, programDoc, dir, r) {
|
|
8470
|
+
for (const line of liftNamedFiles(config, dir)) r.log(` ${line}`);
|
|
8471
|
+
const docRefs = programDoc ? docLayerRefs(layersOf(programDoc)) : [];
|
|
8472
|
+
const dataRefs = localDataRefs(config, dir);
|
|
8473
|
+
const count = docRefs.length + localManifestRefs(config).length + dataRefs.length;
|
|
8474
|
+
return {
|
|
8475
|
+
count,
|
|
8476
|
+
upload: async (target) => {
|
|
8477
|
+
await uploadDocRefs(docRefs, dir, target, say(r));
|
|
8478
|
+
await uploadManifest(config, dir, target, say(r));
|
|
8479
|
+
await uploadDocRefs(dataRefs, dir, target, say(r));
|
|
8480
|
+
}
|
|
8481
|
+
};
|
|
8482
|
+
}
|
|
8311
8483
|
function soundOf(doc) {
|
|
8312
8484
|
return { audio: Array.isArray(doc.audio) ? doc.audio : [] };
|
|
8313
8485
|
}
|
|
@@ -8325,7 +8497,7 @@ function storedProgramConfig(config, programDoc) {
|
|
|
8325
8497
|
}
|
|
8326
8498
|
async function readProgramDoc(dir, config) {
|
|
8327
8499
|
const docPath = join15(dir, "doc.json");
|
|
8328
|
-
if (!
|
|
8500
|
+
if (!existsSync14(docPath)) return null;
|
|
8329
8501
|
const parsed = JSON.parse(await readFile13(docPath, "utf8"));
|
|
8330
8502
|
if (typeof parsed !== "object" || parsed === null || "source" in parsed)
|
|
8331
8503
|
return null;
|
|
@@ -8336,7 +8508,7 @@ async function readProgramDoc(dir, config) {
|
|
|
8336
8508
|
async function setProgramStill(dir, t) {
|
|
8337
8509
|
const docPath = join15(dir, "doc.json");
|
|
8338
8510
|
let doc = { program: {}, audio: [] };
|
|
8339
|
-
if (
|
|
8511
|
+
if (existsSync14(docPath)) {
|
|
8340
8512
|
const parsed = JSON.parse(await readFile13(docPath, "utf8"));
|
|
8341
8513
|
if (!parsed || typeof parsed !== "object" || "source" in parsed)
|
|
8342
8514
|
throw new UsageError(
|
|
@@ -8359,7 +8531,107 @@ async function writeProgramDoc(dir, hosted) {
|
|
|
8359
8531
|
// src/plugin/asset.ts
|
|
8360
8532
|
import { createHash as createHash2 } from "crypto";
|
|
8361
8533
|
import { readFileSync as readFileSync3 } from "fs";
|
|
8362
|
-
import { basename as
|
|
8534
|
+
import { basename as basename4 } from "path";
|
|
8535
|
+
|
|
8536
|
+
// src/plugin/assetWords.ts
|
|
8537
|
+
function hostedFile(raw) {
|
|
8538
|
+
const row = raw && typeof raw === "object" ? raw : {};
|
|
8539
|
+
const text = (value, fallback = "") => typeof value === "string" ? value : fallback;
|
|
8540
|
+
return {
|
|
8541
|
+
...row,
|
|
8542
|
+
id: text(row.id),
|
|
8543
|
+
kind: text(row.kind) || text(row.category, "file"),
|
|
8544
|
+
filename: text(row.filename, "unnamed"),
|
|
8545
|
+
size: typeof row.size === "number" ? row.size : 0
|
|
8546
|
+
};
|
|
8547
|
+
}
|
|
8548
|
+
function bytesWords(bytes) {
|
|
8549
|
+
if (!Number.isFinite(bytes) || bytes < 0) return "0 B";
|
|
8550
|
+
if (bytes < 1024) return `${Math.round(bytes)} B`;
|
|
8551
|
+
const units = ["KB", "MB", "GB", "TB"];
|
|
8552
|
+
let value = bytes / 1024;
|
|
8553
|
+
let unit = 0;
|
|
8554
|
+
while (value >= 1024 && unit < units.length - 1) {
|
|
8555
|
+
value /= 1024;
|
|
8556
|
+
unit++;
|
|
8557
|
+
}
|
|
8558
|
+
return `${value >= 100 ? Math.round(value) : value.toFixed(1)} ${units[unit]}`;
|
|
8559
|
+
}
|
|
8560
|
+
var num = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
8561
|
+
function probeLine(file) {
|
|
8562
|
+
const meta = file.metadata ?? {};
|
|
8563
|
+
const parts = [file.kind];
|
|
8564
|
+
const width = num(meta.width);
|
|
8565
|
+
const height = num(meta.height);
|
|
8566
|
+
if (width && height) parts.push(`${width}\xD7${height}`);
|
|
8567
|
+
if (typeof meta.videoCodec === "string") parts.push(meta.videoCodec);
|
|
8568
|
+
else if (typeof meta.audioCodec === "string" && file.kind === "audio") {
|
|
8569
|
+
parts.push(meta.audioCodec);
|
|
8570
|
+
}
|
|
8571
|
+
const seconds = num(file.duration);
|
|
8572
|
+
if (seconds && seconds > 0) {
|
|
8573
|
+
parts.push(`${seconds >= 10 ? seconds.toFixed(1) : seconds.toFixed(2)} s`);
|
|
8574
|
+
}
|
|
8575
|
+
let line = parts.join(" ");
|
|
8576
|
+
if (file.kind === "video" && meta.hasAudio === true) line += ", audio";
|
|
8577
|
+
if (file.kind === "model") {
|
|
8578
|
+
const meshes = num(meta.meshCount);
|
|
8579
|
+
if (meshes !== null) line += ` ${meshes} mesh${meshes === 1 ? "" : "es"}`;
|
|
8580
|
+
}
|
|
8581
|
+
return line;
|
|
8582
|
+
}
|
|
8583
|
+
function manifestName2(filename) {
|
|
8584
|
+
const stem = filename.replace(/\.[^.]+$/, "");
|
|
8585
|
+
const name = stem.replace(/[^A-Za-z0-9_]+/g, "_").replace(/^_+|_+$/g, "").replace(/^(\d)/, "_$1");
|
|
8586
|
+
return name || "file";
|
|
8587
|
+
}
|
|
8588
|
+
var MANIFEST_KINDS = /* @__PURE__ */ new Set([
|
|
8589
|
+
"image",
|
|
8590
|
+
"video",
|
|
8591
|
+
"audio",
|
|
8592
|
+
"model",
|
|
8593
|
+
"font",
|
|
8594
|
+
"hdr"
|
|
8595
|
+
]);
|
|
8596
|
+
function manifestLine(file) {
|
|
8597
|
+
const kind = file.kind === "vector" ? "image" : file.kind;
|
|
8598
|
+
const hint = MANIFEST_KINDS.has(kind) ? `, "kind": "${kind}"` : "";
|
|
8599
|
+
return `"${manifestName2(file.filename)}": { "ref": "asset:${file.id}"${hint} }`;
|
|
8600
|
+
}
|
|
8601
|
+
function listRow(file) {
|
|
8602
|
+
return [
|
|
8603
|
+
file.id,
|
|
8604
|
+
file.kind,
|
|
8605
|
+
bytesWords(file.size),
|
|
8606
|
+
file.kind === "recipe" ? "" : file.uses ? `used in ${file.uses}` : "not used",
|
|
8607
|
+
file.intent === "attached" ? "attached" : "library",
|
|
8608
|
+
file.filename
|
|
8609
|
+
];
|
|
8610
|
+
}
|
|
8611
|
+
function alignRows(rows) {
|
|
8612
|
+
if (rows.length === 0) return [];
|
|
8613
|
+
const widths = rows[0].map(
|
|
8614
|
+
(_, col) => Math.max(...rows.map((row) => (row[col] ?? "").length))
|
|
8615
|
+
);
|
|
8616
|
+
return rows.map(
|
|
8617
|
+
(row) => row.map(
|
|
8618
|
+
(cell, col) => col === row.length - 1 ? cell : cell.padEnd(widths[col])
|
|
8619
|
+
).join(" ").trimEnd()
|
|
8620
|
+
);
|
|
8621
|
+
}
|
|
8622
|
+
function nameFromUrl(url) {
|
|
8623
|
+
try {
|
|
8624
|
+
const last = decodeURIComponent(
|
|
8625
|
+
new URL(url).pathname.split("/").filter(Boolean).pop() ?? ""
|
|
8626
|
+
);
|
|
8627
|
+
const clean = last.replace(/[^\w.\- ]+/g, "_").slice(0, 120);
|
|
8628
|
+
return clean || "download";
|
|
8629
|
+
} catch {
|
|
8630
|
+
return "download";
|
|
8631
|
+
}
|
|
8632
|
+
}
|
|
8633
|
+
|
|
8634
|
+
// src/plugin/asset.ts
|
|
8363
8635
|
var BOOLEAN_FLAGS3 = /* @__PURE__ */ new Set(["json", "help"]);
|
|
8364
8636
|
async function cmdRename(argv) {
|
|
8365
8637
|
const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS3);
|
|
@@ -8400,7 +8672,7 @@ async function cmdPush(argv) {
|
|
|
8400
8672
|
const folder = folderRef ? resolveFolder(await listFolders(origin, key), folderRef) : null;
|
|
8401
8673
|
const uploaded = [];
|
|
8402
8674
|
for (const file of positionals) {
|
|
8403
|
-
const name =
|
|
8675
|
+
const name = basename4(file);
|
|
8404
8676
|
const body = readFileSync3(file);
|
|
8405
8677
|
const media = resolveMediaType({
|
|
8406
8678
|
head: body.subarray(0, MEDIA_HEAD_BYTES),
|
|
@@ -8429,12 +8701,27 @@ async function cmdPush(argv) {
|
|
|
8429
8701
|
filename: stored,
|
|
8430
8702
|
kind: put.kind,
|
|
8431
8703
|
url: put.url,
|
|
8704
|
+
ref: put.ref,
|
|
8705
|
+
size: put.size,
|
|
8706
|
+
...put.duration ? { duration: put.duration } : {},
|
|
8707
|
+
...put.metadata ? { metadata: put.metadata } : {},
|
|
8432
8708
|
...put.reused ? { reused: true } : {},
|
|
8433
8709
|
...put.notes.length ? { notes: put.notes } : {}
|
|
8434
8710
|
});
|
|
8711
|
+
const hosted = {
|
|
8712
|
+
id: put.id,
|
|
8713
|
+
kind: put.kind,
|
|
8714
|
+
filename: stored,
|
|
8715
|
+
size: put.size,
|
|
8716
|
+
duration: put.duration,
|
|
8717
|
+
metadata: put.metadata
|
|
8718
|
+
};
|
|
8435
8719
|
r.log(
|
|
8436
|
-
`uploaded ${stored}
|
|
8720
|
+
`uploaded ${stored}${put.reused ? " \u2014 already yours, nothing sent" : ""}`
|
|
8437
8721
|
);
|
|
8722
|
+
r.log(` ${probeLine(hosted)}, ${bytesWords(put.size)}`);
|
|
8723
|
+
r.log(` ${put.ref} ${put.url}`);
|
|
8724
|
+
r.log(` ${manifestLine(hosted)}`);
|
|
8438
8725
|
for (const note of put.notes) r.log(` note: ${note}`);
|
|
8439
8726
|
}
|
|
8440
8727
|
r.done(
|
|
@@ -8447,6 +8734,181 @@ async function cmdPush(argv) {
|
|
|
8447
8734
|
);
|
|
8448
8735
|
return EXIT_OK;
|
|
8449
8736
|
}
|
|
8737
|
+
var IMPORT_MAX_BYTES = 512 * 1024 * 1024;
|
|
8738
|
+
async function cmdImport(argv) {
|
|
8739
|
+
const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS3);
|
|
8740
|
+
const [url] = positionals;
|
|
8741
|
+
if (!url || !/^https?:\/\//i.test(url)) {
|
|
8742
|
+
throw new UsageError(
|
|
8743
|
+
"vos asset import <http(s) url> [--name <file>] [--folder <slug>] [--license <text>] [--attribution <text>]"
|
|
8744
|
+
);
|
|
8745
|
+
}
|
|
8746
|
+
const r = createReporter(flags.json === true);
|
|
8747
|
+
const origin = platformOrigin({
|
|
8748
|
+
origin: strFlag(flags, "origin"),
|
|
8749
|
+
api: strFlag(flags, "api")
|
|
8750
|
+
});
|
|
8751
|
+
const key = requireCredential(strFlag(flags, "key"));
|
|
8752
|
+
const folderRef = strFlag(flags, "folder");
|
|
8753
|
+
const folder = folderRef ? resolveFolder(await listFolders(origin, key), folderRef) : null;
|
|
8754
|
+
r.log(`fetching ${url}`);
|
|
8755
|
+
const res = await fetch(url, { redirect: "follow" });
|
|
8756
|
+
if (!res.ok)
|
|
8757
|
+
throw new Error(`import ${url}: the address answered ${res.status}`);
|
|
8758
|
+
const declared = Number(res.headers.get("content-length") ?? 0);
|
|
8759
|
+
if (declared > IMPORT_MAX_BYTES) {
|
|
8760
|
+
throw new Error(
|
|
8761
|
+
`import ${url}: ${bytesWords(declared)} is over the ${bytesWords(IMPORT_MAX_BYTES)} an import carries. Download it and use vos asset push`
|
|
8762
|
+
);
|
|
8763
|
+
}
|
|
8764
|
+
const body = new Uint8Array(await res.arrayBuffer());
|
|
8765
|
+
if (body.length > IMPORT_MAX_BYTES) {
|
|
8766
|
+
throw new Error(
|
|
8767
|
+
`import ${url}: ${bytesWords(body.length)} is over the ${bytesWords(IMPORT_MAX_BYTES)} an import carries. Download it and use vos asset push`
|
|
8768
|
+
);
|
|
8769
|
+
}
|
|
8770
|
+
const name = strFlag(flags, "name") ?? nameFromUrl(res.url || url);
|
|
8771
|
+
const license = strFlag(flags, "license");
|
|
8772
|
+
const attribution = strFlag(flags, "attribution");
|
|
8773
|
+
let put;
|
|
8774
|
+
try {
|
|
8775
|
+
put = await uploadAsset({ origin, key }, body, {
|
|
8776
|
+
filename: name,
|
|
8777
|
+
contentHash: createHash2("sha256").update(body).digest("hex"),
|
|
8778
|
+
intent: "library",
|
|
8779
|
+
...folder ? { folderId: folder.id } : {},
|
|
8780
|
+
provenance: {
|
|
8781
|
+
sourceUrl: res.url || url,
|
|
8782
|
+
...license ? { license } : {},
|
|
8783
|
+
...attribution ? { attribution } : {}
|
|
8784
|
+
}
|
|
8785
|
+
});
|
|
8786
|
+
} catch (e) {
|
|
8787
|
+
throw new Error(
|
|
8788
|
+
`import ${name}: ${e instanceof Error ? e.message : String(e)}`
|
|
8789
|
+
);
|
|
8790
|
+
}
|
|
8791
|
+
const hosted = {
|
|
8792
|
+
id: put.id,
|
|
8793
|
+
kind: put.kind,
|
|
8794
|
+
filename: put.filename || name,
|
|
8795
|
+
size: put.size,
|
|
8796
|
+
duration: put.duration,
|
|
8797
|
+
metadata: put.metadata
|
|
8798
|
+
};
|
|
8799
|
+
if (!license) {
|
|
8800
|
+
r.log(
|
|
8801
|
+
"note: no --license was given. Say what lets you use this file, so the next person can tell"
|
|
8802
|
+
);
|
|
8803
|
+
}
|
|
8804
|
+
r.done(
|
|
8805
|
+
{
|
|
8806
|
+
id: put.id,
|
|
8807
|
+
filename: hosted.filename,
|
|
8808
|
+
kind: put.kind,
|
|
8809
|
+
url: put.url,
|
|
8810
|
+
ref: put.ref,
|
|
8811
|
+
size: put.size,
|
|
8812
|
+
sourceUrl: res.url || url,
|
|
8813
|
+
...license ? { license } : {},
|
|
8814
|
+
...attribution ? { attribution } : {},
|
|
8815
|
+
...put.reused ? { reused: true } : {},
|
|
8816
|
+
...put.notes.length ? { notes: put.notes } : {},
|
|
8817
|
+
folder: folder?.slug ?? null
|
|
8818
|
+
},
|
|
8819
|
+
`imported ${hosted.filename}${put.reused ? " \u2014 already yours, nothing sent" : ""}
|
|
8820
|
+
${probeLine(hosted)}, ${bytesWords(put.size)}
|
|
8821
|
+
${put.ref} ${put.url}
|
|
8822
|
+
${manifestLine(hosted)}`
|
|
8823
|
+
);
|
|
8824
|
+
return EXIT_OK;
|
|
8825
|
+
}
|
|
8826
|
+
async function cmdList2(argv) {
|
|
8827
|
+
const { flags } = parseArgs(argv, BOOLEAN_FLAGS3);
|
|
8828
|
+
const r = createReporter(flags.json === true);
|
|
8829
|
+
const origin = platformOrigin({
|
|
8830
|
+
origin: strFlag(flags, "origin"),
|
|
8831
|
+
api: strFlag(flags, "api")
|
|
8832
|
+
});
|
|
8833
|
+
const key = requireCredential(strFlag(flags, "key"));
|
|
8834
|
+
const params = new URLSearchParams({
|
|
8835
|
+
limit: String(Math.min(200, Math.max(1, numFlag(flags, "limit", 50))))
|
|
8836
|
+
});
|
|
8837
|
+
for (const name of ["kind", "q", "sort", "scope"]) {
|
|
8838
|
+
const value = strFlag(flags, name);
|
|
8839
|
+
if (value) params.set(name, value);
|
|
8840
|
+
}
|
|
8841
|
+
const folderRef = strFlag(flags, "folder");
|
|
8842
|
+
if (folderRef) {
|
|
8843
|
+
params.set(
|
|
8844
|
+
"folder",
|
|
8845
|
+
folderRef === "none" ? "none" : resolveFolder(await listFolders(origin, key), folderRef).id
|
|
8846
|
+
);
|
|
8847
|
+
}
|
|
8848
|
+
const res = await apiJson(origin, `/api/assets?${params}`, { key });
|
|
8849
|
+
if (res.status !== 200) throw new Error(apiError("list assets", res));
|
|
8850
|
+
const assets = (res.body.assets ?? []).map(hostedFile);
|
|
8851
|
+
const total = typeof res.body.total === "number" ? res.body.total : assets.length;
|
|
8852
|
+
r.done(
|
|
8853
|
+
{ assets, total, kinds: res.body.kinds ?? {} },
|
|
8854
|
+
assets.length === 0 ? "no files" : `${alignRows(assets.map(listRow)).join("\n")}
|
|
8855
|
+
${assets.length} of ${total} file${total === 1 ? "" : "s"}${total > assets.length ? " (--limit for more, --q to search)" : ""}`
|
|
8856
|
+
);
|
|
8857
|
+
return EXIT_OK;
|
|
8858
|
+
}
|
|
8859
|
+
async function cmdUsage(argv) {
|
|
8860
|
+
const { flags } = parseArgs(argv, BOOLEAN_FLAGS3);
|
|
8861
|
+
const r = createReporter(flags.json === true);
|
|
8862
|
+
const origin = platformOrigin({
|
|
8863
|
+
origin: strFlag(flags, "origin"),
|
|
8864
|
+
api: strFlag(flags, "api")
|
|
8865
|
+
});
|
|
8866
|
+
const key = requireCredential(strFlag(flags, "key"));
|
|
8867
|
+
const res = await apiJson(origin, "/api/user/usage", { key });
|
|
8868
|
+
if (res.status !== 200) throw new Error(apiError("read usage", res));
|
|
8869
|
+
const usage = res.body.usage ?? {};
|
|
8870
|
+
const limits = res.body.limits ?? {};
|
|
8871
|
+
const held = Number(usage.assetBytes ?? 0);
|
|
8872
|
+
const trash = Number(usage.trashBytes ?? 0);
|
|
8873
|
+
const limit = Number(limits.storageBytes ?? 0);
|
|
8874
|
+
const today = usage.uploadsToday ?? {};
|
|
8875
|
+
const perKind = limits.uploadKinds ?? {};
|
|
8876
|
+
const rates = Object.entries(today).filter(([kind]) => perKind[kind]?.perDay).map(([kind, n]) => `${kind} ${n} of ${perKind[kind].perDay}`);
|
|
8877
|
+
r.done(
|
|
8878
|
+
{ plan: res.body.plan, usage, limits },
|
|
8879
|
+
`${bytesWords(held)} of ${bytesWords(limit)} used` + (trash > 0 ? `, ${bytesWords(trash)} of it in Trash (a person empties Trash at vos.so/app/trash; deleting more frees nothing)` : "") + (rates.length ? `
|
|
8880
|
+
uploaded in the last 24 h: ${rates.join(", ")}` : "")
|
|
8881
|
+
);
|
|
8882
|
+
return EXIT_OK;
|
|
8883
|
+
}
|
|
8884
|
+
async function cmdWhy(argv) {
|
|
8885
|
+
const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS3);
|
|
8886
|
+
const [assetId] = positionals;
|
|
8887
|
+
if (!assetId) throw new UsageError("vos assets why <assetId>");
|
|
8888
|
+
const r = createReporter(flags.json === true);
|
|
8889
|
+
const origin = platformOrigin({
|
|
8890
|
+
origin: strFlag(flags, "origin"),
|
|
8891
|
+
api: strFlag(flags, "api")
|
|
8892
|
+
});
|
|
8893
|
+
const key = requireCredential(strFlag(flags, "key"));
|
|
8894
|
+
const res = await apiJson(origin, `/api/assets/${assetId}`, { key });
|
|
8895
|
+
if (res.status !== 200) throw new Error(apiError(`read ${assetId}`, res));
|
|
8896
|
+
const asset = hostedFile(res.body.asset);
|
|
8897
|
+
const usedIn = res.body.usedIn ?? [];
|
|
8898
|
+
const how = (u) => [
|
|
8899
|
+
u.head ? "in what plays now" : "",
|
|
8900
|
+
u.versions ? `${u.versions} version${u.versions === 1 ? "" : "s"}` : "",
|
|
8901
|
+
u.draft ? "an unsaved draft" : "",
|
|
8902
|
+
u.trashed ? "in Trash" : ""
|
|
8903
|
+
].filter(Boolean).join(", ");
|
|
8904
|
+
const lines = [
|
|
8905
|
+
`${asset.filename} ${probeLine(asset)}, ${bytesWords(asset.size)}`,
|
|
8906
|
+
asset.removedAt ? `removed from vos.so: ${asset.removedReason ?? "no reason given"}` : usedIn.length === 0 ? asset.intent === "attached" ? "nothing uses it: an attached file that stays unused is collected after 7 days" : "nothing uses it: it stays because it is in your library" : `used by ${usedIn.length}:`,
|
|
8907
|
+
...usedIn.map((u) => ` ${u.vosId} ${u.title || "Untitled"} (${how(u)})`)
|
|
8908
|
+
];
|
|
8909
|
+
r.done({ asset, usedIn }, lines.join("\n"));
|
|
8910
|
+
return EXIT_OK;
|
|
8911
|
+
}
|
|
8450
8912
|
async function cmdAsset(argv) {
|
|
8451
8913
|
const sub = argv[0];
|
|
8452
8914
|
const rest = argv.slice(1);
|
|
@@ -8455,15 +8917,24 @@ async function cmdAsset(argv) {
|
|
|
8455
8917
|
return cmdRename(rest);
|
|
8456
8918
|
case "push":
|
|
8457
8919
|
return cmdPush(rest);
|
|
8920
|
+
case "import":
|
|
8921
|
+
return cmdImport(rest);
|
|
8922
|
+
case "ls":
|
|
8923
|
+
case "list":
|
|
8924
|
+
return cmdList2(rest);
|
|
8925
|
+
case "usage":
|
|
8926
|
+
return cmdUsage(rest);
|
|
8927
|
+
case "why":
|
|
8928
|
+
return cmdWhy(rest);
|
|
8458
8929
|
default:
|
|
8459
8930
|
throw new UsageError(
|
|
8460
|
-
"vos asset <rename|
|
|
8931
|
+
"vos asset <push|import|rename> | vos assets <ls|usage|why> \u2014 add files to your library, or see what is in it (vos asset push <file...> [--folder <slug>])"
|
|
8461
8932
|
);
|
|
8462
8933
|
}
|
|
8463
8934
|
}
|
|
8464
8935
|
|
|
8465
8936
|
// src/plugin/remove.ts
|
|
8466
|
-
import { existsSync as
|
|
8937
|
+
import { existsSync as existsSync15, rmSync as rmSync2, statSync as statSync3 } from "fs";
|
|
8467
8938
|
import { join as join16 } from "path";
|
|
8468
8939
|
import { createInterface as createInterface3 } from "readline/promises";
|
|
8469
8940
|
|
|
@@ -8643,7 +9114,7 @@ async function cmdDelete(argv) {
|
|
|
8643
9114
|
api: strFlag(flags, "api")
|
|
8644
9115
|
}).replace(/\/+$/, "");
|
|
8645
9116
|
const key = requireCredential(strFlag(flags, "key"));
|
|
8646
|
-
const dir =
|
|
9117
|
+
const dir = existsSync15(target) && statSync3(target).isDirectory() ? target : null;
|
|
8647
9118
|
const vosId = dir ? readSyncState(dir)?.vosId : parseVosId(target);
|
|
8648
9119
|
if (!vosId)
|
|
8649
9120
|
throw new UsageError(
|
|
@@ -8711,7 +9182,7 @@ async function cmdDelete(argv) {
|
|
|
8711
9182
|
|
|
8712
9183
|
// src/plugin/buildProgram.ts
|
|
8713
9184
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
8714
|
-
import { basename as
|
|
9185
|
+
import { basename as basename5, dirname as dirname4, join as join17, resolve as resolve7 } from "path";
|
|
8715
9186
|
import { pathToFileURL } from "url";
|
|
8716
9187
|
import { parse } from "acorn";
|
|
8717
9188
|
import { fullAncestor } from "acorn-walk";
|
|
@@ -8919,7 +9390,7 @@ async function cmdBuild(argv) {
|
|
|
8919
9390
|
throw new UsageError(
|
|
8920
9391
|
`${source} exports no program: \`export default { version: 2, duration, camera, createContent, createTimeline, \u2026 }\``
|
|
8921
9392
|
);
|
|
8922
|
-
const built = buildProgram(program,
|
|
9393
|
+
const built = buildProgram(program, basename5(file), text);
|
|
8923
9394
|
for (const p of built.problems) r.log(`error ${p.fn}: ${p.message}`);
|
|
8924
9395
|
if (built.problems.length) {
|
|
8925
9396
|
r.done(
|
|
@@ -8946,7 +9417,7 @@ async function cmdBuild(argv) {
|
|
|
8946
9417
|
|
|
8947
9418
|
// src/plugin/compare.ts
|
|
8948
9419
|
import { spawnSync } from "child_process";
|
|
8949
|
-
import { existsSync as
|
|
9420
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync2, statSync as statSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
8950
9421
|
import { dirname as dirname5, join as join18, resolve as resolve8 } from "path";
|
|
8951
9422
|
var BOOLEAN_FLAGS7 = /* @__PURE__ */ new Set(["json", "help"]);
|
|
8952
9423
|
function sampleTimes(duration, every) {
|
|
@@ -9014,7 +9485,7 @@ async function cmdCompare(argv) {
|
|
|
9014
9485
|
const config = loaded.config;
|
|
9015
9486
|
const duration = configDuration(config) ?? 5;
|
|
9016
9487
|
const assets = await programAssets(config, {
|
|
9017
|
-
baseDir: /^https?:\/\//.test(source) ? null :
|
|
9488
|
+
baseDir: /^https?:\/\//.test(source) ? null : existsSync16(source) && statSync4(source).isDirectory() ? source : dirname5(source),
|
|
9018
9489
|
origin: platformOrigin({}),
|
|
9019
9490
|
key: resolveCredential(),
|
|
9020
9491
|
log: (line) => r.log(line)
|
|
@@ -9133,28 +9604,28 @@ async function cmdCompare(argv) {
|
|
|
9133
9604
|
}
|
|
9134
9605
|
|
|
9135
9606
|
// src/plugin/port.ts
|
|
9136
|
-
import { existsSync as
|
|
9607
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
9137
9608
|
import { dirname as dirname8, join as join22, resolve as resolve11 } from "path";
|
|
9138
9609
|
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
9139
9610
|
|
|
9140
9611
|
// src/plugin/portInventory.ts
|
|
9141
9612
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
9142
9613
|
import {
|
|
9143
|
-
existsSync as
|
|
9614
|
+
existsSync as existsSync18,
|
|
9144
9615
|
mkdirSync as mkdirSync3,
|
|
9145
9616
|
readFileSync as readFileSync6,
|
|
9146
9617
|
readdirSync as readdirSync4,
|
|
9147
9618
|
statSync as statSync6
|
|
9148
9619
|
} from "fs";
|
|
9149
|
-
import { dirname as dirname6, join as join20, relative as
|
|
9620
|
+
import { dirname as dirname6, join as join20, relative as relative3, resolve as resolve9 } from "path";
|
|
9150
9621
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
9151
9622
|
import { findFontFamily as findFontFamily3 } from "@vosjs/shared";
|
|
9152
9623
|
|
|
9153
9624
|
// src/plugin/portRemotion.ts
|
|
9154
|
-
import { existsSync as
|
|
9625
|
+
import { existsSync as existsSync17, readFileSync as readFileSync5, readdirSync as readdirSync3, statSync as statSync5 } from "fs";
|
|
9155
9626
|
import { createServer as createServer2 } from "http";
|
|
9156
9627
|
import { createRequire } from "module";
|
|
9157
|
-
import { basename as
|
|
9628
|
+
import { basename as basename6, extname as extname3, join as join19 } from "path";
|
|
9158
9629
|
function themeColors(sources) {
|
|
9159
9630
|
const out = {};
|
|
9160
9631
|
const re = /\bconst\s+([A-Za-z_$][\w$]*)\s*(?::\s*string\s*)?=\s*['"](#[0-9a-fA-F]{3,8})['"]/g;
|
|
@@ -9227,7 +9698,7 @@ function sourceTexts(dir) {
|
|
|
9227
9698
|
}
|
|
9228
9699
|
};
|
|
9229
9700
|
const src = join19(dir, "src");
|
|
9230
|
-
walk(
|
|
9701
|
+
walk(existsSync17(src) ? src : dir, 0);
|
|
9231
9702
|
return out;
|
|
9232
9703
|
}
|
|
9233
9704
|
function entryPoint(dir) {
|
|
@@ -9239,7 +9710,7 @@ function entryPoint(dir) {
|
|
|
9239
9710
|
"remotion/index.ts",
|
|
9240
9711
|
"remotion/index.tsx"
|
|
9241
9712
|
])
|
|
9242
|
-
if (
|
|
9713
|
+
if (existsSync17(join19(dir, p))) return join19(dir, p);
|
|
9243
9714
|
return null;
|
|
9244
9715
|
}
|
|
9245
9716
|
var TYPES = {
|
|
@@ -9332,10 +9803,10 @@ async function readRemotion(dir, log) {
|
|
|
9332
9803
|
const server = createServer2((rq, rs) => {
|
|
9333
9804
|
const path = decodeURIComponent(new URL(rq.url ?? "/", "http://x").pathname);
|
|
9334
9805
|
let f = join19(out, path);
|
|
9335
|
-
if (!f.startsWith(out) || !
|
|
9806
|
+
if (!f.startsWith(out) || !existsSync17(f) || statSync5(f).isDirectory())
|
|
9336
9807
|
f = join19(out, "index.html");
|
|
9337
9808
|
rs.writeHead(200, {
|
|
9338
|
-
"content-type": TYPES[
|
|
9809
|
+
"content-type": TYPES[extname3(f)] ?? "application/octet-stream"
|
|
9339
9810
|
});
|
|
9340
9811
|
rs.end(readFileSync5(f));
|
|
9341
9812
|
}).listen(0, "127.0.0.1");
|
|
@@ -9434,8 +9905,8 @@ async function readRemotion(dir, log) {
|
|
|
9434
9905
|
const sources = sourceTexts(dir);
|
|
9435
9906
|
const publicDir = join19(dir, "public");
|
|
9436
9907
|
const media = tree.audio.map((a) => {
|
|
9437
|
-
const name =
|
|
9438
|
-
const local =
|
|
9908
|
+
const name = basename6(a.src.split("?")[0]);
|
|
9909
|
+
const local = existsSync17(join19(publicDir, name)) ? `public/${name}` : a.src;
|
|
9439
9910
|
return {
|
|
9440
9911
|
kind: "audio",
|
|
9441
9912
|
src: local,
|
|
@@ -9476,9 +9947,9 @@ async function readRemotion(dir, log) {
|
|
|
9476
9947
|
|
|
9477
9948
|
// src/plugin/portInventory.ts
|
|
9478
9949
|
function detectEngine(dir) {
|
|
9479
|
-
if (
|
|
9950
|
+
if (existsSync18(join20(dir, "hyperframes.json"))) return "hyperframes";
|
|
9480
9951
|
const pkg = join20(dir, "package.json");
|
|
9481
|
-
if (
|
|
9952
|
+
if (existsSync18(pkg)) {
|
|
9482
9953
|
try {
|
|
9483
9954
|
const p = JSON.parse(readFileSync6(pkg, "utf8"));
|
|
9484
9955
|
const deps = { ...p.dependencies ?? {}, ...p.devDependencies ?? {} };
|
|
@@ -9492,13 +9963,13 @@ function detectEngine(dir) {
|
|
|
9492
9963
|
return "page";
|
|
9493
9964
|
}
|
|
9494
9965
|
function sourcePage(source) {
|
|
9495
|
-
if (!
|
|
9966
|
+
if (!existsSync18(source)) return null;
|
|
9496
9967
|
if (statSync6(source).isFile()) return /\.html?$/i.test(source) ? source : null;
|
|
9497
9968
|
const index = join20(source, "index.html");
|
|
9498
|
-
return
|
|
9969
|
+
return existsSync18(index) ? index : null;
|
|
9499
9970
|
}
|
|
9500
9971
|
function findRender(dir) {
|
|
9501
|
-
const videos = (d) =>
|
|
9972
|
+
const videos = (d) => existsSync18(d) ? readdirSync4(d).filter((f) => /\.(mp4|webm|mov)$/i.test(f)).map((f) => join20(d, f)) : [];
|
|
9502
9973
|
for (const d of [join20(dir, "renders"), join20(dir, "out"), dir]) {
|
|
9503
9974
|
const found = videos(d);
|
|
9504
9975
|
if (found.length) return found[0];
|
|
@@ -9770,7 +10241,7 @@ var SEEK_AND_READ = `((args) => {
|
|
|
9770
10241
|
})`;
|
|
9771
10242
|
async function readInventory(source, opts) {
|
|
9772
10243
|
const abs = resolve9(source);
|
|
9773
|
-
const dir =
|
|
10244
|
+
const dir = existsSync18(abs) && statSync6(abs).isDirectory() ? abs : dirname6(abs);
|
|
9774
10245
|
const engine = detectEngine(dir);
|
|
9775
10246
|
const page = sourcePage(abs);
|
|
9776
10247
|
const render = opts.render === void 0 ? findRender(dir) : opts.render;
|
|
@@ -9900,7 +10371,7 @@ async function readInventory(source, opts) {
|
|
|
9900
10371
|
if (ok)
|
|
9901
10372
|
stills.push({
|
|
9902
10373
|
t: Number(t.toFixed(2)),
|
|
9903
|
-
file:
|
|
10374
|
+
file: relative3(opts.outDir, file)
|
|
9904
10375
|
});
|
|
9905
10376
|
}
|
|
9906
10377
|
} else {
|
|
@@ -9911,7 +10382,7 @@ async function readInventory(source, opts) {
|
|
|
9911
10382
|
}
|
|
9912
10383
|
const scriptStrings = scriptStringsOf(read.scriptText);
|
|
9913
10384
|
return {
|
|
9914
|
-
source:
|
|
10385
|
+
source: relative3(process.cwd(), abs) || ".",
|
|
9915
10386
|
root: abs.endsWith(".html") ? dirname6(abs) : abs,
|
|
9916
10387
|
engine,
|
|
9917
10388
|
width: read.width,
|
|
@@ -9929,15 +10400,15 @@ async function readInventory(source, opts) {
|
|
|
9929
10400
|
variables: read.variables,
|
|
9930
10401
|
scriptStrings,
|
|
9931
10402
|
uses: read.uses ?? sourceUses(read.scriptText ?? ""),
|
|
9932
|
-
render: render ?
|
|
10403
|
+
render: render ? relative3(process.cwd(), render) : null,
|
|
9933
10404
|
stills
|
|
9934
10405
|
};
|
|
9935
10406
|
}
|
|
9936
10407
|
|
|
9937
10408
|
// src/plugin/portScaffold.ts
|
|
9938
10409
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
9939
|
-
import { copyFileSync, existsSync as
|
|
9940
|
-
import { basename as
|
|
10410
|
+
import { copyFileSync, existsSync as existsSync19, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
10411
|
+
import { basename as basename7, dirname as dirname7, join as join21, resolve as resolve10 } from "path";
|
|
9941
10412
|
import { findFontFamily as findFontFamily4, fontFaceUrl, nearestFontWeight } from "@vosjs/shared";
|
|
9942
10413
|
|
|
9943
10414
|
// src/plugin/painterLib.ts
|
|
@@ -10347,8 +10818,8 @@ function planScaffold(inv, opts) {
|
|
|
10347
10818
|
const copies = [];
|
|
10348
10819
|
inv.media.filter((m) => m.kind === "audio" && m.src).forEach((m, i) => {
|
|
10349
10820
|
const from = resolve10(opts.sourceDir, m.src);
|
|
10350
|
-
const name =
|
|
10351
|
-
if (!
|
|
10821
|
+
const name = basename7(from);
|
|
10822
|
+
if (!existsSync19(from)) {
|
|
10352
10823
|
report.push(
|
|
10353
10824
|
`- the audio ${m.src} is not in the source folder; add it to doc.json by hand`
|
|
10354
10825
|
);
|
|
@@ -10491,7 +10962,7 @@ ${sceneTodos}${springHint}
|
|
|
10491
10962
|
}
|
|
10492
10963
|
function reportText(inv, r) {
|
|
10493
10964
|
const lines = [
|
|
10494
|
-
`# Port report: ${inv.source === "." && inv.root ?
|
|
10965
|
+
`# Port report: ${inv.source === "." && inv.root ? basename7(inv.root) : inv.source}`,
|
|
10495
10966
|
"",
|
|
10496
10967
|
`${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}\`.`,
|
|
10497
10968
|
"",
|
|
@@ -10619,7 +11090,7 @@ async function scaffold(argv) {
|
|
|
10619
11090
|
const { flags } = parseArgs(argv, BOOLEAN_FLAGS8);
|
|
10620
11091
|
const r = createReporter(flags.json === true);
|
|
10621
11092
|
const from = resolve11(strFlag(flags, "from") ?? join22("port", "inventory.json"));
|
|
10622
|
-
if (!
|
|
11093
|
+
if (!existsSync20(from))
|
|
10623
11094
|
throw new UsageError(
|
|
10624
11095
|
`no inventory at ${from}: run npx vos port inventory <source> first`
|
|
10625
11096
|
);
|
|
@@ -10655,11 +11126,11 @@ function scaffoldSourceDir(inv) {
|
|
|
10655
11126
|
// src/plugin/recipe.ts
|
|
10656
11127
|
import { createHash as createHash3 } from "crypto";
|
|
10657
11128
|
import { readFileSync as readFileSync8 } from "fs";
|
|
10658
|
-
import { basename as
|
|
11129
|
+
import { basename as basename8 } from "path";
|
|
10659
11130
|
var BOOLEAN_FLAGS9 = /* @__PURE__ */ new Set(["json", "help"]);
|
|
10660
11131
|
var USAGE = "vos recipe push <file.md> (--folder <folderId|slug> | --asset <assetId>)";
|
|
10661
11132
|
function recipeFilename(file) {
|
|
10662
|
-
const name =
|
|
11133
|
+
const name = basename8(file);
|
|
10663
11134
|
if (!/\.md$/i.test(name)) {
|
|
10664
11135
|
throw new UsageError(`a recipe is a markdown file \u2014 ${name} is not .md`);
|
|
10665
11136
|
}
|
|
@@ -11311,8 +11782,8 @@ var quoteAttr = (s) => `"${s.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
|
11311
11782
|
function hrefSelector(href) {
|
|
11312
11783
|
try {
|
|
11313
11784
|
const u = new URL(href);
|
|
11314
|
-
const
|
|
11315
|
-
return `a[href=${quoteAttr(
|
|
11785
|
+
const relative4 = `${u.pathname}${u.search}${u.hash}`;
|
|
11786
|
+
return `a[href=${quoteAttr(relative4)}], a[href=${quoteAttr(href)}]`;
|
|
11316
11787
|
} catch {
|
|
11317
11788
|
return `a[href=${quoteAttr(href)}]`;
|
|
11318
11789
|
}
|
|
@@ -11739,9 +12210,9 @@ async function cmdActionsScript(input, flags) {
|
|
|
11739
12210
|
}
|
|
11740
12211
|
|
|
11741
12212
|
// src/plugin/ingest.ts
|
|
11742
|
-
import { existsSync as
|
|
12213
|
+
import { existsSync as existsSync21 } from "fs";
|
|
11743
12214
|
import { copyFile, mkdir as mkdir8, readFile as readFile14, stat as stat3 } from "fs/promises";
|
|
11744
|
-
import { basename as
|
|
12215
|
+
import { basename as basename9, join as join23, resolve as resolve14 } from "path";
|
|
11745
12216
|
import { inflateRawSync } from "zlib";
|
|
11746
12217
|
import {
|
|
11747
12218
|
cursorFromPlaywrightTrace,
|
|
@@ -11822,7 +12293,7 @@ async function copyRecording(src, dest, ext) {
|
|
|
11822
12293
|
}
|
|
11823
12294
|
}
|
|
11824
12295
|
async function readTraceFile(path, offsetMs) {
|
|
11825
|
-
const kind = traceKindOf(
|
|
12296
|
+
const kind = traceKindOf(basename9(path));
|
|
11826
12297
|
if (!kind) {
|
|
11827
12298
|
throw new UsageError(
|
|
11828
12299
|
`${path}: not a trace the recorder reads (trace.zip, .trace, .jsonl, .json or .csv)`
|
|
@@ -11843,7 +12314,7 @@ async function readTraceFile(path, offsetMs) {
|
|
|
11843
12314
|
return cursorFromPlaywrightTrace(text2, { offsetMs });
|
|
11844
12315
|
}
|
|
11845
12316
|
const text = await readFile14(path, "utf8");
|
|
11846
|
-
return cursorFromTrace(
|
|
12317
|
+
return cursorFromTrace(basename9(path), text, { offsetMs });
|
|
11847
12318
|
}
|
|
11848
12319
|
function parseViewport(v) {
|
|
11849
12320
|
if (!v) return null;
|
|
@@ -11859,7 +12330,7 @@ async function cmdIngest(argv) {
|
|
|
11859
12330
|
"vos ingest <video.webm|mp4> [--cursor <trace.zip|steps.jsonl|cursor.csv>] [--as footage|take] [--out take] [--offset <ms>] [--viewport WxH] [--background <slug|url|none>] [--json]"
|
|
11860
12331
|
);
|
|
11861
12332
|
const videoPath = resolve14(source);
|
|
11862
|
-
if (!
|
|
12333
|
+
if (!existsSync21(videoPath)) throw new UsageError(`${source}: no such file`);
|
|
11863
12334
|
const r = createReporter(flags.json === true);
|
|
11864
12335
|
const outDir = resolve14(strFlag(flags, "out") ?? "take");
|
|
11865
12336
|
const offsetMs = numFlag(flags, "offset", 0);
|
|
@@ -11874,7 +12345,7 @@ async function cmdIngest(argv) {
|
|
|
11874
12345
|
"note: finished footage opens bare, so --background is not used (pass --as take for the screen-recording card and its ground)"
|
|
11875
12346
|
);
|
|
11876
12347
|
const backdrop = footage ? null : await takeBackdrop(flags, r);
|
|
11877
|
-
r.log(`probing ${
|
|
12348
|
+
r.log(`probing ${basename9(videoPath)}\u2026`);
|
|
11878
12349
|
const probed = await probeVideoFile(videoPath);
|
|
11879
12350
|
if (!(probed.durationMs > 0)) {
|
|
11880
12351
|
throw new UsageError(
|
|
@@ -11886,7 +12357,7 @@ async function cmdIngest(argv) {
|
|
|
11886
12357
|
trace = await readTraceFile(resolve14(cursorPath), offsetMs);
|
|
11887
12358
|
for (const n of trace.notes) r.log(`note: ${n}`);
|
|
11888
12359
|
}
|
|
11889
|
-
if (
|
|
12360
|
+
if (existsSync21(join23(outDir, "meta.json"))) {
|
|
11890
12361
|
const { prevDoc, kept } = await prepareReRecord(outDir);
|
|
11891
12362
|
r.log(
|
|
11892
12363
|
`note: re-ingesting into ${outDir}; kept ${kept.length ? kept.join(", ") : "nothing"}` + (prevDoc ? `; apply the previous cut with: vos plan ${outDir} --reuse` : "")
|
|
@@ -11923,13 +12394,13 @@ async function cmdIngest(argv) {
|
|
|
11923
12394
|
const clicks = events.filter((e) => e.type === "down").length;
|
|
11924
12395
|
const seconds = (probed.durationMs / 1e3).toFixed(1);
|
|
11925
12396
|
const facts = `${seconds}s, ${probed.width}\xD7${probed.height} @ ${meta.fps} fps${probed.hasAudio ? ", audio" : ", no audio"}${remuxed ? "" : ", copied as is"}`;
|
|
11926
|
-
const cursorLine = trace ? `${events.length} cursor events (${clicks} clicks) from ${
|
|
12397
|
+
const cursorLine = trace ? `${events.length} cursor events (${clicks} clicks) from ${basename9(cursorPath)}${trace.dropped ? `, ${trace.dropped} not placed` : ""}; ${plan.zoomAuto} zoom${plan.zoomAuto === 1 ? "" : "s"} planned` : "no cursor track, so nothing was planned";
|
|
11927
12398
|
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)`;
|
|
11928
12399
|
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`;
|
|
11929
12400
|
r.done(
|
|
11930
12401
|
{
|
|
11931
12402
|
out: outDir,
|
|
11932
|
-
recording:
|
|
12403
|
+
recording: basename9(recording),
|
|
11933
12404
|
durationMs: probed.durationMs,
|
|
11934
12405
|
width: probed.width,
|
|
11935
12406
|
height: probed.height,
|
|
@@ -11938,7 +12409,7 @@ async function cmdIngest(argv) {
|
|
|
11938
12409
|
hasAudio: probed.hasAudio,
|
|
11939
12410
|
remuxed,
|
|
11940
12411
|
cursor: trace ? {
|
|
11941
|
-
file:
|
|
12412
|
+
file: basename9(cursorPath),
|
|
11942
12413
|
kind: trace.kind,
|
|
11943
12414
|
events: events.length,
|
|
11944
12415
|
clicks,
|
|
@@ -11950,7 +12421,7 @@ async function cmdIngest(argv) {
|
|
|
11950
12421
|
backdrop: plan.backdrop ?? null,
|
|
11951
12422
|
as: footage ? "footage" : "take"
|
|
11952
12423
|
},
|
|
11953
|
-
`Ingested ${
|
|
12424
|
+
`Ingested ${basename9(videoPath)} \u2192 ${outDir}/${basename9(recording)} (${facts})
|
|
11954
12425
|
${opened}
|
|
11955
12426
|
${cursorLine}
|
|
11956
12427
|
${next}`
|
|
@@ -11962,7 +12433,7 @@ async function cmdIngest(argv) {
|
|
|
11962
12433
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
11963
12434
|
import {
|
|
11964
12435
|
cpSync,
|
|
11965
|
-
existsSync as
|
|
12436
|
+
existsSync as existsSync23,
|
|
11966
12437
|
mkdirSync as mkdirSync6,
|
|
11967
12438
|
readFileSync as readFileSync10,
|
|
11968
12439
|
rmSync as rmSync3,
|
|
@@ -11973,7 +12444,7 @@ import { join as join25 } from "path";
|
|
|
11973
12444
|
import { chromium as chromium2 } from "playwright";
|
|
11974
12445
|
|
|
11975
12446
|
// src/plugin/machine.ts
|
|
11976
|
-
import { existsSync as
|
|
12447
|
+
import { existsSync as existsSync22, readFileSync as readFileSync9, readdirSync as readdirSync5, statSync as statSync7 } from "fs";
|
|
11977
12448
|
import { dirname as dirname9, join as join24 } from "path";
|
|
11978
12449
|
var AGENT_NAMES = [
|
|
11979
12450
|
"claude",
|
|
@@ -11994,7 +12465,7 @@ var HOME_DIRS = {
|
|
|
11994
12465
|
copilot: [".copilot"]
|
|
11995
12466
|
};
|
|
11996
12467
|
function detectAgents(root, opts = {}) {
|
|
11997
|
-
const exists = opts.exists ??
|
|
12468
|
+
const exists = opts.exists ?? existsSync22;
|
|
11998
12469
|
const out = [];
|
|
11999
12470
|
for (const agent of AGENT_NAMES) {
|
|
12000
12471
|
for (const rel of PROJECT_DIRS[agent]) {
|
|
@@ -12041,7 +12512,7 @@ function skillsDirFor(home) {
|
|
|
12041
12512
|
function fallbackSkillsHome(root) {
|
|
12042
12513
|
return { agent: "codex", dir: join24(root, ".agents"), scope: "project" };
|
|
12043
12514
|
}
|
|
12044
|
-
function installedSkills(dir, exists =
|
|
12515
|
+
function installedSkills(dir, exists = existsSync22, list = (p) => {
|
|
12045
12516
|
try {
|
|
12046
12517
|
return readdirSync5(p);
|
|
12047
12518
|
} catch {
|
|
@@ -12082,7 +12553,7 @@ ${RULES_BLOCK}
|
|
|
12082
12553
|
}
|
|
12083
12554
|
return { text, changed: text !== current };
|
|
12084
12555
|
}
|
|
12085
|
-
function rulesFileFor(root, exists =
|
|
12556
|
+
function rulesFileFor(root, exists = existsSync22) {
|
|
12086
12557
|
const agents = join24(root, "AGENTS.md");
|
|
12087
12558
|
if (exists(agents)) return agents;
|
|
12088
12559
|
const claude = join24(root, "CLAUDE.md");
|
|
@@ -12189,12 +12660,12 @@ function bundledSkillsDir(from) {
|
|
|
12189
12660
|
let dir = dirname9(from);
|
|
12190
12661
|
for (let i = 0; i < 6; i++) {
|
|
12191
12662
|
const pkg = join24(dir, "package.json");
|
|
12192
|
-
if (
|
|
12663
|
+
if (existsSync22(pkg)) {
|
|
12193
12664
|
try {
|
|
12194
12665
|
const name = JSON.parse(readFileSync9(pkg, "utf8")).name;
|
|
12195
12666
|
if (name === "@vosjs/cli") {
|
|
12196
12667
|
const skills = join24(dir, "skills");
|
|
12197
|
-
return
|
|
12668
|
+
return existsSync22(skills) && statSync7(skills).isDirectory() ? skills : null;
|
|
12198
12669
|
}
|
|
12199
12670
|
} catch {
|
|
12200
12671
|
}
|
|
@@ -12225,7 +12696,7 @@ function npx() {
|
|
|
12225
12696
|
function bundledChromium() {
|
|
12226
12697
|
try {
|
|
12227
12698
|
const p = chromium2.executablePath();
|
|
12228
|
-
return p &&
|
|
12699
|
+
return p && existsSync23(p) ? p : null;
|
|
12229
12700
|
} catch {
|
|
12230
12701
|
return null;
|
|
12231
12702
|
}
|
|
@@ -12234,7 +12705,7 @@ function probe2() {
|
|
|
12234
12705
|
return probeBrowser({
|
|
12235
12706
|
platform: process.platform,
|
|
12236
12707
|
env: process.env,
|
|
12237
|
-
exists:
|
|
12708
|
+
exists: existsSync23,
|
|
12238
12709
|
bundled: bundledChromium
|
|
12239
12710
|
});
|
|
12240
12711
|
}
|
|
@@ -12373,7 +12844,7 @@ async function cmdSetup(argv) {
|
|
|
12373
12844
|
let rules = null;
|
|
12374
12845
|
if (!noRules) {
|
|
12375
12846
|
const file = rulesFileFor(root);
|
|
12376
|
-
const existing =
|
|
12847
|
+
const existing = existsSync23(file) ? readFileSync10(file, "utf8") : null;
|
|
12377
12848
|
const { text, changed } = applyRulesBlock(existing);
|
|
12378
12849
|
if (changed) writeFileSync6(file, text);
|
|
12379
12850
|
rules = { file, changed };
|
|
@@ -12487,7 +12958,7 @@ async function cmdWhoami(argv) {
|
|
|
12487
12958
|
function cmdLogout(argv) {
|
|
12488
12959
|
const { flags } = parseArgs(argv, BOOLEAN_FLAGS11);
|
|
12489
12960
|
const r = reporterFor(flags);
|
|
12490
|
-
const had =
|
|
12961
|
+
const had = existsSync23(CREDENTIALS_PATH);
|
|
12491
12962
|
rmSync3(CREDENTIALS_PATH, { force: true });
|
|
12492
12963
|
const envKey = Boolean(process.env.VOS_API_KEY?.trim());
|
|
12493
12964
|
r.done(
|
|
@@ -12649,10 +13120,26 @@ Platform (vos.so) \u2014 fetch, edit, push, pull, repeat
|
|
|
12649
13120
|
vos asset push <file...> [--folder <folderId|slug>]
|
|
12650
13121
|
add files to your library: models, pictures and SVGs, fonts,
|
|
12651
13122
|
HDR maps, sound, video, captions and recipes. The platform
|
|
12652
|
-
reads each file and answers what it is
|
|
12653
|
-
|
|
12654
|
-
the url a doc.json key takes
|
|
12655
|
-
|
|
13123
|
+
reads each file and answers what it is; the same bytes twice
|
|
13124
|
+
are the same file. Prints, per file, what was read, its
|
|
13125
|
+
asset:<id>, the url a doc.json key takes, and the line that
|
|
13126
|
+
declares it in a program's "assets"
|
|
13127
|
+
vos asset import <url> [--name <file>] [--folder <slug>]
|
|
13128
|
+
[--license <text>] [--attribution <text>]
|
|
13129
|
+
fetch a file from an address and add it, with where it came
|
|
13130
|
+
from kept beside it. Say the license: it is what lets the
|
|
13131
|
+
next person use the file
|
|
13132
|
+
vos assets ls [--kind <kind>] [--folder <slug>|none] [--q <text>]
|
|
13133
|
+
[--sort recent|size|name] [--limit <n>]
|
|
13134
|
+
what is in your library: id, kind, size, whether a program
|
|
13135
|
+
uses it, and whether it is a library file or attached to a
|
|
13136
|
+
document
|
|
13137
|
+
vos assets usage
|
|
13138
|
+
storage held, of how much, and the part in Trash; uploads in
|
|
13139
|
+
the last 24 hours per kind against each daily rate
|
|
13140
|
+
vos assets why <assetId>
|
|
13141
|
+
every program that uses a file, and how (in what plays now,
|
|
13142
|
+
in history, in a draft): why it is kept
|
|
12656
13143
|
vos recipe push <file.md> --folder <folderId|slug>
|
|
12657
13144
|
vos recipe push <file.md> --asset <assetId>
|
|
12658
13145
|
put a recipe (a plain .md) on the shelf: --folder creates it
|
|
@@ -12904,7 +13391,7 @@ function takeStorageState(flags) {
|
|
|
12904
13391
|
const raw = strFlag(flags, "storage-state");
|
|
12905
13392
|
if (!raw) return void 0;
|
|
12906
13393
|
const path = resolve15(raw);
|
|
12907
|
-
if (!
|
|
13394
|
+
if (!existsSync24(path))
|
|
12908
13395
|
throw new UsageError(`--storage-state: no such file: ${path}`);
|
|
12909
13396
|
return path;
|
|
12910
13397
|
}
|
|
@@ -12917,7 +13404,7 @@ function takeSessionName(flags, storageState) {
|
|
|
12917
13404
|
throw new UsageError(
|
|
12918
13405
|
"--session and --storage-state are two doors to one take: a persistent profile cannot take a storage state. Pass one"
|
|
12919
13406
|
);
|
|
12920
|
-
if (!
|
|
13407
|
+
if (!existsSync24(sessionDir(name)))
|
|
12921
13408
|
throw new UsageError(
|
|
12922
13409
|
`no session "${name}". Make one: vos session open <url> --name ${name} (a Chrome window opens; sign in and close it)`
|
|
12923
13410
|
);
|
|
@@ -13140,7 +13627,7 @@ ${lines.join("\n")}
|
|
|
13140
13627
|
}
|
|
13141
13628
|
const paths = takePaths(outDir);
|
|
13142
13629
|
const prepare = async () => {
|
|
13143
|
-
if (
|
|
13630
|
+
if (existsSync24(join26(outDir, "meta.json"))) {
|
|
13144
13631
|
const { prevDoc, kept } = await prepareReRecord(outDir);
|
|
13145
13632
|
r.log(
|
|
13146
13633
|
`note: re-recording ${outDir} \u2014 kept ${kept.length ? kept.join(", ") : "nothing"}` + (prevDoc ? "; apply the previous cut to the new footage with: vos plan " + outDir + " --reuse" : "")
|
|
@@ -13244,7 +13731,7 @@ async function cmdCreate2(argv) {
|
|
|
13244
13731
|
const headers = takeHeaders(multi);
|
|
13245
13732
|
const paths = takePaths(outDir);
|
|
13246
13733
|
const prepare = async () => {
|
|
13247
|
-
if (
|
|
13734
|
+
if (existsSync24(join26(outDir, "meta.json"))) {
|
|
13248
13735
|
const { prevDoc, kept } = await prepareReRecord(outDir);
|
|
13249
13736
|
r.log(
|
|
13250
13737
|
`note: re-recording ${outDir} \u2014 kept ${kept.length ? kept.join(", ") : "nothing"}` + (prevDoc ? "; apply the previous cut to the new footage with: vos plan " + outDir + " --reuse" : "")
|
|
@@ -13357,7 +13844,7 @@ async function cmdPlan(argv) {
|
|
|
13357
13844
|
let reuse;
|
|
13358
13845
|
if (flags.reuse === true) {
|
|
13359
13846
|
const from = resolve15(strFlag(flags, "from") ?? join26(dir, PREV_DOC_NAME));
|
|
13360
|
-
if (!
|
|
13847
|
+
if (!existsSync24(from)) {
|
|
13361
13848
|
throw new UsageError(
|
|
13362
13849
|
`--reuse: ${from} does not exist \u2014 a re-record into this take writes doc.prev.json, or pass --from <doc.json>`
|
|
13363
13850
|
);
|
|
@@ -13368,7 +13855,7 @@ async function cmdPlan(argv) {
|
|
|
13368
13855
|
};
|
|
13369
13856
|
}
|
|
13370
13857
|
const style = await resolveStyleRef(flags);
|
|
13371
|
-
const hasDoc =
|
|
13858
|
+
const hasDoc = existsSync24(join26(dir, "doc.json"));
|
|
13372
13859
|
const backdrop = hasDoc ? null : await takeBackdrop(flags, r);
|
|
13373
13860
|
const release = await releaseInputs(dir, flags, r, multi.with ?? []);
|
|
13374
13861
|
const motionWanted = !hasDoc || flags.motion === true || flags.fresh === true;
|
|
@@ -13796,11 +14283,11 @@ async function resolveStyleRef(flags) {
|
|
|
13796
14283
|
}
|
|
13797
14284
|
async function resolveDocRef(ref, flags, what) {
|
|
13798
14285
|
const styleRef = ref;
|
|
13799
|
-
const file =
|
|
14286
|
+
const file = existsSync24(styleRef) ? resolve15(
|
|
13800
14287
|
styleRef,
|
|
13801
|
-
|
|
14288
|
+
existsSync24(join26(styleRef, "doc.json")) ? "doc.json" : ""
|
|
13802
14289
|
) : null;
|
|
13803
|
-
if (file &&
|
|
14290
|
+
if (file && existsSync24(file)) {
|
|
13804
14291
|
return {
|
|
13805
14292
|
from: file,
|
|
13806
14293
|
doc: migrateHostedDoc5(
|
|
@@ -13915,7 +14402,7 @@ async function cmdOpen(argv) {
|
|
|
13915
14402
|
if (!dir) throw new UsageError("vos open <take> [--studio <url>]");
|
|
13916
14403
|
const r = createReporter(flags.json === true);
|
|
13917
14404
|
const take = await loadTake(dir);
|
|
13918
|
-
if (!
|
|
14405
|
+
if (!existsSync24(take.paths.recording)) {
|
|
13919
14406
|
throw new UsageError(`${dir} has no recording \u2014 re-run record`);
|
|
13920
14407
|
}
|
|
13921
14408
|
const studio = (strFlag(flags, "studio") ?? platformOrigin()).replace(
|
|
@@ -13957,8 +14444,8 @@ async function cmdJudge(argv) {
|
|
|
13957
14444
|
);
|
|
13958
14445
|
const r = createReporter(flags.json === true);
|
|
13959
14446
|
const kitFile = target.endsWith("kit.json") ? target : join26(target, "kit.json");
|
|
13960
|
-
if (!
|
|
13961
|
-
if (!
|
|
14447
|
+
if (!existsSync24(kitFile)) throw new UsageError(`${kitFile}: no kit manifest`);
|
|
14448
|
+
if (!existsSync24(against))
|
|
13962
14449
|
throw new UsageError(`${against}: no reference manifest`);
|
|
13963
14450
|
const result = await judgeKit(kitFile, against, strFlag(flags, "out"));
|
|
13964
14451
|
const verdicts = JSON.parse(await readFile15(result.verdictFile, "utf8")).verdicts;
|
|
@@ -14080,7 +14567,7 @@ async function cmdValidate(argv) {
|
|
|
14080
14567
|
const target = positionals[0];
|
|
14081
14568
|
if (!target) throw new UsageError("vos validate <actions.json|take>");
|
|
14082
14569
|
const r = createReporter(flags.json === true);
|
|
14083
|
-
const kitTarget = target.endsWith("kit.json") ? target :
|
|
14570
|
+
const kitTarget = target.endsWith("kit.json") ? target : existsSync24(join26(target, "kit.json")) && !isTakeDir(target) ? join26(target, "kit.json") : null;
|
|
14084
14571
|
if (kitTarget) {
|
|
14085
14572
|
const picture = flags.picture === true;
|
|
14086
14573
|
const verdict = await validateKit(kitTarget, { picture });
|
|
@@ -14112,7 +14599,7 @@ async function cmdValidate(argv) {
|
|
|
14112
14599
|
r.done({ valid: true, target }, `${target}: valid actions file`);
|
|
14113
14600
|
return EXIT_OK;
|
|
14114
14601
|
}
|
|
14115
|
-
if (!isTakeDir(target) &&
|
|
14602
|
+
if (!isTakeDir(target) && existsSync24(join26(target, "config.json"))) {
|
|
14116
14603
|
const parsed = JSON.parse(
|
|
14117
14604
|
await readFile15(join26(target, "config.json"), "utf8")
|
|
14118
14605
|
);
|
|
@@ -14155,7 +14642,7 @@ async function cmdValidate(argv) {
|
|
|
14155
14642
|
const take = await loadTake(target);
|
|
14156
14643
|
const problems = [];
|
|
14157
14644
|
const warnings = [];
|
|
14158
|
-
if (!
|
|
14645
|
+
if (!existsSync24(take.paths.recording)) {
|
|
14159
14646
|
problems.push("missing recording (re-run record)");
|
|
14160
14647
|
} else {
|
|
14161
14648
|
const mismatch = containerMismatch(
|
|
@@ -14428,6 +14915,7 @@ async function run(argv) {
|
|
|
14428
14915
|
case "folder":
|
|
14429
14916
|
return await cmdFolder(rest);
|
|
14430
14917
|
case "asset":
|
|
14918
|
+
case "assets":
|
|
14431
14919
|
return await cmdAsset(rest);
|
|
14432
14920
|
case "recipe":
|
|
14433
14921
|
return await cmdRecipe(rest);
|
|
@@ -14507,7 +14995,7 @@ async function cmdSession(argv) {
|
|
|
14507
14995
|
if (!arg) throw new UsageError(usage);
|
|
14508
14996
|
const bad = sessionNameVerdict(arg);
|
|
14509
14997
|
if (bad) throw new UsageError(bad);
|
|
14510
|
-
if (!
|
|
14998
|
+
if (!existsSync24(sessionDir(arg)))
|
|
14511
14999
|
throw new UsageError(`no session "${arg}" (vos session list)`);
|
|
14512
15000
|
const summary3 = await summarizeSession(arg);
|
|
14513
15001
|
const url = strFlag(flags, "url");
|
|
@@ -14607,4 +15095,4 @@ export {
|
|
|
14607
15095
|
verbHelp,
|
|
14608
15096
|
run
|
|
14609
15097
|
};
|
|
14610
|
-
//# sourceMappingURL=chunk-
|
|
15098
|
+
//# sourceMappingURL=chunk-CODEEH2Z.js.map
|