@vosjs/cli 0.69.1 → 0.71.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 +7 -3
- package/dist/{chunk-NHJRD2XC.js → chunk-XB5XRE4Q.js} +519 -273
- package/dist/chunk-XB5XRE4Q.js.map +1 -0
- package/dist/cli.js +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/{run-6VQWD42R.js → run-QPHIGP6N.js} +2 -2
- package/dist/{shotList-KH6FTX4L.js → shotList-MAQVLZBY.js} +4 -2
- package/dist/shotList-MAQVLZBY.js.map +1 -0
- package/package.json +6 -6
- package/schema/actions.schema.json +111 -4
- package/dist/chunk-NHJRD2XC.js.map +0 -1
- package/dist/shotList-KH6FTX4L.js.map +0 -1
- /package/dist/{run-6VQWD42R.js.map → run-QPHIGP6N.js.map} +0 -0
|
@@ -131,9 +131,9 @@ function landedLines(l) {
|
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
// src/plugin/run.ts
|
|
134
|
-
import { mkdir as mkdir8, readFile as
|
|
135
|
-
import { existsSync as
|
|
136
|
-
import { join as
|
|
134
|
+
import { mkdir as mkdir8, readFile as readFile13, rm as rm2 } from "fs/promises";
|
|
135
|
+
import { existsSync as existsSync23 } from "fs";
|
|
136
|
+
import { join as join25, resolve as resolve13 } from "path";
|
|
137
137
|
import {
|
|
138
138
|
END_CARD_FROM as END_CARD_FROM2,
|
|
139
139
|
docOutputDuration as docOutputDuration3,
|
|
@@ -2710,15 +2710,21 @@ import { mkdir, readFile as readFile2, rename, writeFile as writeFile2 } from "f
|
|
|
2710
2710
|
import { existsSync as existsSync2 } from "fs";
|
|
2711
2711
|
import { join as join2, resolve } from "path";
|
|
2712
2712
|
import {
|
|
2713
|
+
CHANGE_GRID,
|
|
2714
|
+
CHANGE_LEAD,
|
|
2715
|
+
CHANGE_OFFSETS,
|
|
2713
2716
|
DIGEST_CROP_MAX,
|
|
2714
2717
|
DIGEST_FULL_MAX,
|
|
2715
2718
|
DIGEST_VERSION,
|
|
2716
2719
|
MOTION_DELTA,
|
|
2720
|
+
ambientDrift,
|
|
2717
2721
|
buildDigest,
|
|
2722
|
+
changedRegion,
|
|
2718
2723
|
cropBox,
|
|
2719
2724
|
frameGeometry,
|
|
2720
2725
|
momentsFromDoc,
|
|
2721
2726
|
outputDurationOf,
|
|
2727
|
+
pickChange,
|
|
2722
2728
|
planForDigest,
|
|
2723
2729
|
sceneChanges
|
|
2724
2730
|
} from "@vosjs/studio-core";
|
|
@@ -2762,7 +2768,40 @@ async function binsInPage(opts) {
|
|
|
2762
2768
|
prev = luma;
|
|
2763
2769
|
w.__progress = (i + 1) / n;
|
|
2764
2770
|
}
|
|
2765
|
-
|
|
2771
|
+
const g = document.createElement("canvas");
|
|
2772
|
+
g.width = opts.grid.w;
|
|
2773
|
+
g.height = opts.grid.h;
|
|
2774
|
+
const gctx = g.getContext("2d", { willReadFrequently: true });
|
|
2775
|
+
const gridAt = async (t) => {
|
|
2776
|
+
const el = await getFrame(Math.max(0, Math.min(opts.durationS, t)));
|
|
2777
|
+
gctx.drawImage(el, 0, 0, opts.grid.w, opts.grid.h);
|
|
2778
|
+
const d = gctx.getImageData(0, 0, opts.grid.w, opts.grid.h).data;
|
|
2779
|
+
const out = new Array(opts.grid.w * opts.grid.h);
|
|
2780
|
+
for (let p = 0; p < out.length; p++) {
|
|
2781
|
+
const o = p * 4;
|
|
2782
|
+
out[p] = (d[o] * 299 + d[o + 1] * 587 + d[o + 2] * 114) / 1e3;
|
|
2783
|
+
}
|
|
2784
|
+
return out;
|
|
2785
|
+
};
|
|
2786
|
+
const changes = [];
|
|
2787
|
+
for (const seed of opts.seeds) {
|
|
2788
|
+
const samples = [];
|
|
2789
|
+
if (seed.t - opts.lead >= 0)
|
|
2790
|
+
samples.push({ dt: -opts.lead, luma: await gridAt(seed.t - opts.lead) });
|
|
2791
|
+
samples.push({ dt: 0, luma: await gridAt(seed.t) });
|
|
2792
|
+
for (const dt of opts.offsets) {
|
|
2793
|
+
if (seed.t + dt > opts.durationS) break;
|
|
2794
|
+
samples.push({ dt, luma: await gridAt(seed.t + dt) });
|
|
2795
|
+
}
|
|
2796
|
+
changes.push({ id: seed.id, samples });
|
|
2797
|
+
}
|
|
2798
|
+
w.__done = {
|
|
2799
|
+
ok: true,
|
|
2800
|
+
bins,
|
|
2801
|
+
width: size.width,
|
|
2802
|
+
height: size.height,
|
|
2803
|
+
changes
|
|
2804
|
+
};
|
|
2766
2805
|
} catch (e) {
|
|
2767
2806
|
w.__error = String(e instanceof Error && e.stack || e);
|
|
2768
2807
|
}
|
|
@@ -2985,23 +3024,66 @@ async function digestTake(browser, dir, opts = {}) {
|
|
|
2985
3024
|
});
|
|
2986
3025
|
await page.goto(`${server.base}/digest.html`);
|
|
2987
3026
|
await page.waitForFunction("window.__pageReady__ === true");
|
|
2988
|
-
|
|
3027
|
+
const seeds = momentsFromDoc(doc, plan, {}).filter(
|
|
3028
|
+
(m) => m.at !== null && (m.kind === "click" || m.kind === "typing")
|
|
3029
|
+
).map((m) => ({
|
|
3030
|
+
id: m.id,
|
|
3031
|
+
t: m.kind === "click" ? m.at : m.source.out
|
|
3032
|
+
}));
|
|
3033
|
+
void page.evaluate(binsInPage, {
|
|
3034
|
+
source,
|
|
3035
|
+
durationS: durS,
|
|
3036
|
+
delta: MOTION_DELTA,
|
|
3037
|
+
seeds,
|
|
3038
|
+
grid: { ...CHANGE_GRID },
|
|
3039
|
+
offsets: [...CHANGE_OFFSETS],
|
|
3040
|
+
lead: CHANGE_LEAD
|
|
3041
|
+
}).catch(() => {
|
|
2989
3042
|
});
|
|
2990
3043
|
const b = await waitForPageDone(
|
|
2991
3044
|
page,
|
|
2992
3045
|
"digest bins",
|
|
2993
3046
|
() => {
|
|
2994
3047
|
},
|
|
2995
|
-
6e4 + durS * 400
|
|
3048
|
+
6e4 + durS * 400 + seeds.length * 2e3
|
|
2996
3049
|
);
|
|
2997
3050
|
bins = b.bins;
|
|
2998
3051
|
plan = planForDigest(doc, bins);
|
|
2999
3052
|
frameW = b.width;
|
|
3000
3053
|
frameH = b.height;
|
|
3054
|
+
const sampled = b.changes ?? [];
|
|
3055
|
+
const changes = seeds.flatMap((seed) => {
|
|
3056
|
+
const row = sampled.find((c) => c.id === seed.id);
|
|
3057
|
+
const at2 = row?.samples.find((smp) => smp.dt === 0);
|
|
3058
|
+
const earlier = row?.samples.find((smp) => smp.dt < 0);
|
|
3059
|
+
const after = row?.samples.filter((smp) => smp.dt > 0) ?? [];
|
|
3060
|
+
if (!row || !at2 || !after.length) return [];
|
|
3061
|
+
const before = { ...CHANGE_GRID, luma: at2.luma };
|
|
3062
|
+
const rate = earlier ? ambientDrift(
|
|
3063
|
+
{ ...CHANGE_GRID, luma: earlier.luma },
|
|
3064
|
+
before,
|
|
3065
|
+
-earlier.dt
|
|
3066
|
+
) : null;
|
|
3067
|
+
const w = pickChange(
|
|
3068
|
+
{ id: seed.id, at: seed.t },
|
|
3069
|
+
after.map((smp) => ({
|
|
3070
|
+
dt: smp.dt,
|
|
3071
|
+
region: changedRegion(
|
|
3072
|
+
before,
|
|
3073
|
+
{ ...CHANGE_GRID, luma: smp.luma },
|
|
3074
|
+
MOTION_DELTA,
|
|
3075
|
+
1,
|
|
3076
|
+
rate ? { rate, dt: smp.dt } : null
|
|
3077
|
+
)
|
|
3078
|
+
}))
|
|
3079
|
+
);
|
|
3080
|
+
return w ? [w] : [];
|
|
3081
|
+
});
|
|
3001
3082
|
moments = momentsFromDoc(doc, plan, {
|
|
3002
3083
|
bins,
|
|
3003
3084
|
scenes: sceneChanges(bins),
|
|
3004
|
-
transcript
|
|
3085
|
+
transcript,
|
|
3086
|
+
changes
|
|
3005
3087
|
});
|
|
3006
3088
|
const geo = frameGeometry(doc, frameW, frameH);
|
|
3007
3089
|
const shots = moments.filter((m) => m.at !== null).map((m) => {
|
|
@@ -5341,8 +5423,12 @@ import {
|
|
|
5341
5423
|
} from "@vosjs/studio-core";
|
|
5342
5424
|
|
|
5343
5425
|
// src/plugin/reuse.ts
|
|
5344
|
-
import { docFreezes } from "@vosjs/studio-core";
|
|
5426
|
+
import { docFreezes, ratedSegments as ratedSegments6 } from "@vosjs/studio-core";
|
|
5345
5427
|
var MIN_SPAN = 0.15;
|
|
5428
|
+
var AFTER_STEP = 1;
|
|
5429
|
+
var LAYER_AFTER_STEP = 5;
|
|
5430
|
+
var WINDOW_SLACK = 0.05;
|
|
5431
|
+
var LAYER_DRIFT = 0.5;
|
|
5346
5432
|
function matchStep(old, newSteps) {
|
|
5347
5433
|
const usable = (s) => !!s && s.skipped !== true;
|
|
5348
5434
|
if (old.id) {
|
|
@@ -5358,6 +5444,19 @@ function matchStep(old, newSteps) {
|
|
|
5358
5444
|
);
|
|
5359
5445
|
return old.selector !== void 0 && bySignature.length === 1 ? bySignature[0] : usable(atIndex) && old.selector === void 0 && atIndex.do === old.do ? atIndex : null;
|
|
5360
5446
|
}
|
|
5447
|
+
function stepByRef(steps, ref) {
|
|
5448
|
+
return typeof ref === "string" ? steps.find((s) => s.id === ref) : steps.find((s) => s.step === ref);
|
|
5449
|
+
}
|
|
5450
|
+
var stepName = (s) => String(s.id ?? s.step);
|
|
5451
|
+
function stepUnder(t, steps, after = AFTER_STEP) {
|
|
5452
|
+
const gestures = steps.filter((s) => s.do !== "wait" && !s.skipped);
|
|
5453
|
+
const holding = gestures.find(
|
|
5454
|
+
(s) => s.tStart - WINDOW_SLACK <= t && t <= s.tEnd + WINDOW_SLACK
|
|
5455
|
+
);
|
|
5456
|
+
if (holding) return holding;
|
|
5457
|
+
const before = gestures.filter((s) => s.tEnd <= t && t - s.tEnd <= after).sort((a, b) => b.tEnd - a.tEnd);
|
|
5458
|
+
return before[0] ?? null;
|
|
5459
|
+
}
|
|
5361
5460
|
function buildStepMap(oldSteps, newSteps, oldDuration, newDuration) {
|
|
5362
5461
|
const points = [
|
|
5363
5462
|
{ from: 0, to: 0 },
|
|
@@ -5401,34 +5500,57 @@ function buildStepMap(oldSteps, newSteps, oldDuration, newDuration) {
|
|
|
5401
5500
|
return { map, unmatched, matched };
|
|
5402
5501
|
}
|
|
5403
5502
|
function resolveAnchor2(anchor, newSteps) {
|
|
5404
|
-
const step =
|
|
5503
|
+
const step = stepByRef(newSteps, anchor.step);
|
|
5405
5504
|
if (!step || step.skipped) return null;
|
|
5406
5505
|
const base = anchor.at === "end" ? step.tEnd : step.tStart;
|
|
5407
5506
|
return base + (anchor.offset ?? 0);
|
|
5408
5507
|
}
|
|
5409
|
-
function
|
|
5508
|
+
function framed(span) {
|
|
5509
|
+
const s = span;
|
|
5510
|
+
if (typeof s.level === "number" && typeof s.cx === "number") {
|
|
5511
|
+
return ` (it framed ${s.cx.toFixed(2)}, ${(s.cy ?? 0).toFixed(2)} at ${s.level.toFixed(1)}\xD7)`;
|
|
5512
|
+
}
|
|
5513
|
+
if (typeof s.rate === "number") return ` (${s.rate}\xD7 speed)`;
|
|
5514
|
+
if (typeof s.rx === "number" || typeof s.ry === "number") {
|
|
5515
|
+
return ` (lean ${s.rx ?? 0}\xB0, ${s.ry ?? 0}\xB0)`;
|
|
5516
|
+
}
|
|
5517
|
+
if (typeof s.seconds === "number") return ` (a ${s.seconds} s hold)`;
|
|
5518
|
+
return "";
|
|
5519
|
+
}
|
|
5520
|
+
function placeMoment(t, anchor, ctx) {
|
|
5521
|
+
if (anchor) {
|
|
5522
|
+
const at2 = resolveAnchor2(anchor, ctx.newSteps);
|
|
5523
|
+
if (at2 === null) return { gone: String(anchor.step) };
|
|
5524
|
+
ctx.report.anchored++;
|
|
5525
|
+
return { at: at2, via: "anchor" };
|
|
5526
|
+
}
|
|
5527
|
+
const under = stepUnder(t, ctx.oldSteps);
|
|
5528
|
+
if (under) {
|
|
5529
|
+
const hit = matchStep(under, ctx.newSteps);
|
|
5530
|
+
if (!hit) return { gone: under };
|
|
5531
|
+
ctx.report.anchored++;
|
|
5532
|
+
return { at: hit.tStart + (t - under.tStart), via: "step" };
|
|
5533
|
+
}
|
|
5534
|
+
ctx.report.mapped++;
|
|
5535
|
+
return { at: ctx.stepMap.map(t), via: "map" };
|
|
5536
|
+
}
|
|
5537
|
+
var goneWords = (gone) => typeof gone === "string" ? `its anchored step (${gone}) is missing or skipped in the new recording` : `it sat on step ${stepName(gone)} (${gone.do}${gone.selector ? ` ${gone.selector}` : ""}), which is missing or skipped in the new recording`;
|
|
5538
|
+
function retimeSpans(kind, spans, ctx, opts = { overlap: "trim" }) {
|
|
5410
5539
|
const out = [];
|
|
5411
5540
|
for (const span of spans) {
|
|
5412
5541
|
const length = span.out - span.in;
|
|
5413
|
-
|
|
5414
|
-
if (
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
);
|
|
5420
|
-
} else {
|
|
5421
|
-
report.anchored++;
|
|
5422
|
-
}
|
|
5423
|
-
}
|
|
5424
|
-
if (nextIn === null) {
|
|
5425
|
-
nextIn = stepMap.map(span.in);
|
|
5426
|
-
report.mapped++;
|
|
5542
|
+
const placed = placeMoment(span.in, span.anchor, ctx);
|
|
5543
|
+
if ("gone" in placed) {
|
|
5544
|
+
ctx.report.flagged.push(
|
|
5545
|
+
`${kind} ${span.id}: ${goneWords(placed.gone)} \u2014 dropped; re-aim it on the new footage${framed(span)}`
|
|
5546
|
+
);
|
|
5547
|
+
continue;
|
|
5427
5548
|
}
|
|
5428
|
-
const
|
|
5429
|
-
const
|
|
5549
|
+
const nextIn = placed.at;
|
|
5550
|
+
const nextOut = Math.min(nextIn + length, ctx.newDuration);
|
|
5551
|
+
const clampedIn = Math.max(0, Math.min(nextIn, ctx.newDuration));
|
|
5430
5552
|
if (nextOut - clampedIn < MIN_SPAN) {
|
|
5431
|
-
report.flagged.push(
|
|
5553
|
+
ctx.report.flagged.push(
|
|
5432
5554
|
`${kind} ${span.id}: lands outside the new recording (${clampedIn.toFixed(2)}s) \u2014 dropped`
|
|
5433
5555
|
);
|
|
5434
5556
|
continue;
|
|
@@ -5436,18 +5558,19 @@ function retimeSpans(kind, spans, stepMap, newSteps, newDuration, report) {
|
|
|
5436
5558
|
out.push({ ...span, in: +clampedIn.toFixed(3), out: +nextOut.toFixed(3) });
|
|
5437
5559
|
}
|
|
5438
5560
|
out.sort((a, b) => a.in - b.in);
|
|
5561
|
+
if (opts.overlap === "keep") return out;
|
|
5439
5562
|
const kept = [];
|
|
5440
5563
|
for (const span of out) {
|
|
5441
5564
|
const prev = kept.at(-1);
|
|
5442
5565
|
if (prev && span.in < prev.out) {
|
|
5443
5566
|
const trimmed = { ...span, in: +prev.out.toFixed(3) };
|
|
5444
5567
|
if (trimmed.out - trimmed.in < MIN_SPAN) {
|
|
5445
|
-
report.flagged.push(
|
|
5568
|
+
ctx.report.flagged.push(
|
|
5446
5569
|
`${kind} ${span.id}: fully overlapped ${prev.id} after re-timing \u2014 dropped`
|
|
5447
5570
|
);
|
|
5448
5571
|
continue;
|
|
5449
5572
|
}
|
|
5450
|
-
report.flagged.push(
|
|
5573
|
+
ctx.report.flagged.push(
|
|
5451
5574
|
`${kind} ${span.id}: overlapped ${prev.id} after re-timing \u2014 trimmed to ${trimmed.in.toFixed(2)}s`
|
|
5452
5575
|
);
|
|
5453
5576
|
kept.push(trimmed);
|
|
@@ -5466,9 +5589,10 @@ function retimeCut(prev, newSteps, newDurationMs) {
|
|
|
5466
5589
|
for (const miss of stepMap.unmatched) {
|
|
5467
5590
|
if (miss.do === "wait") continue;
|
|
5468
5591
|
report.flagged.push(
|
|
5469
|
-
`step ${miss
|
|
5592
|
+
`step ${stepName(miss)} (${miss.do}${miss.selector ? ` ${miss.selector}` : ""}) has no match in the new recording \u2014 times near it interpolate`
|
|
5470
5593
|
);
|
|
5471
5594
|
}
|
|
5595
|
+
const ctx = { oldSteps, newSteps, stepMap, newDuration, report };
|
|
5472
5596
|
const untrimmed = prev.segments.length === 0 || prev.segments.length === 1 && prev.segments[0].in <= 0.05 && prev.segments[0].out >= oldDuration - 0.05;
|
|
5473
5597
|
const segments = untrimmed ? [{ in: 0, out: +newDuration.toFixed(3) }] : prev.segments.map((s) => ({
|
|
5474
5598
|
in: +stepMap.map(s.in).toFixed(3),
|
|
@@ -5482,49 +5606,34 @@ function retimeCut(prev, newSteps, newDurationMs) {
|
|
|
5482
5606
|
const zoom = retimeSpans(
|
|
5483
5607
|
"zoom",
|
|
5484
5608
|
prev.zoom.filter((z) => z.source === "manual"),
|
|
5485
|
-
|
|
5486
|
-
newSteps,
|
|
5487
|
-
newDuration,
|
|
5488
|
-
report
|
|
5609
|
+
ctx
|
|
5489
5610
|
);
|
|
5490
5611
|
const speed = retimeSpans(
|
|
5491
5612
|
"speed",
|
|
5492
5613
|
(prev.speed ?? []).filter((s) => s.source !== "auto"),
|
|
5493
|
-
|
|
5494
|
-
newSteps,
|
|
5495
|
-
newDuration,
|
|
5496
|
-
report
|
|
5614
|
+
ctx
|
|
5497
5615
|
);
|
|
5498
5616
|
const tilt = retimeSpans(
|
|
5499
5617
|
"tilt",
|
|
5500
5618
|
(prev.tilt ?? []).filter((t) => t.source !== "auto"),
|
|
5501
|
-
|
|
5502
|
-
newSteps,
|
|
5503
|
-
newDuration,
|
|
5504
|
-
report
|
|
5619
|
+
ctx
|
|
5505
5620
|
);
|
|
5506
5621
|
const freeze = [];
|
|
5507
5622
|
for (const f of docFreezes(prev)) {
|
|
5508
|
-
|
|
5509
|
-
if (
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
);
|
|
5515
|
-
} else report.anchored++;
|
|
5516
|
-
}
|
|
5517
|
-
if (at2 === null) {
|
|
5518
|
-
at2 = stepMap.map(f.at);
|
|
5519
|
-
report.mapped++;
|
|
5623
|
+
const placed = placeMoment(f.at, f.anchor, ctx);
|
|
5624
|
+
if ("gone" in placed) {
|
|
5625
|
+
report.flagged.push(
|
|
5626
|
+
`freeze ${f.id}: ${goneWords(placed.gone)} \u2014 dropped; re-place it on the new footage${framed(f)}`
|
|
5627
|
+
);
|
|
5628
|
+
continue;
|
|
5520
5629
|
}
|
|
5521
|
-
if (
|
|
5630
|
+
if (placed.at < 0 || placed.at > newDuration) {
|
|
5522
5631
|
report.flagged.push(
|
|
5523
|
-
`freeze ${f.id}: lands outside the new recording (${
|
|
5632
|
+
`freeze ${f.id}: lands outside the new recording (${placed.at.toFixed(2)}s) \u2014 dropped`
|
|
5524
5633
|
);
|
|
5525
5634
|
continue;
|
|
5526
5635
|
}
|
|
5527
|
-
freeze.push({ ...f, at: +
|
|
5636
|
+
freeze.push({ ...f, at: +placed.at.toFixed(3) });
|
|
5528
5637
|
}
|
|
5529
5638
|
freeze.sort((a, b) => a.at - b.at);
|
|
5530
5639
|
const rejected = [];
|
|
@@ -5533,15 +5642,97 @@ function retimeCut(prev, newSteps, newDurationMs) {
|
|
|
5533
5642
|
...retimeSpans(
|
|
5534
5643
|
`rejected ${lane}`,
|
|
5535
5644
|
(prev.rejected ?? []).filter((r) => r.lane === lane),
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
newDuration,
|
|
5539
|
-
report
|
|
5645
|
+
ctx,
|
|
5646
|
+
{ overlap: "keep" }
|
|
5540
5647
|
)
|
|
5541
5648
|
);
|
|
5542
5649
|
}
|
|
5543
5650
|
return { segments, zoom, speed, freeze, tilt, rejected, report };
|
|
5544
5651
|
}
|
|
5652
|
+
function sourceToOutput(pieces, s) {
|
|
5653
|
+
let acc = 0;
|
|
5654
|
+
for (const p of pieces) {
|
|
5655
|
+
const rate = p.rate && p.rate > 0 ? p.rate : 1;
|
|
5656
|
+
const len = Math.max(0, p.out - p.in) / rate;
|
|
5657
|
+
if (s < p.in) return acc;
|
|
5658
|
+
if (s <= p.out) return acc + (s - p.in) / rate;
|
|
5659
|
+
acc += len;
|
|
5660
|
+
}
|
|
5661
|
+
return acc;
|
|
5662
|
+
}
|
|
5663
|
+
function outputToSource(pieces, t) {
|
|
5664
|
+
let acc = 0;
|
|
5665
|
+
for (const p of pieces) {
|
|
5666
|
+
const rate = p.rate && p.rate > 0 ? p.rate : 1;
|
|
5667
|
+
const len = Math.max(0, p.out - p.in) / rate;
|
|
5668
|
+
if (acc + len >= t) return p.in + Math.max(0, t - acc) * rate;
|
|
5669
|
+
acc += len;
|
|
5670
|
+
}
|
|
5671
|
+
return pieces.at(-1)?.out ?? t;
|
|
5672
|
+
}
|
|
5673
|
+
function retimeOverlays(prev, next, report) {
|
|
5674
|
+
const overlays = prev.overlays ?? [];
|
|
5675
|
+
if (!overlays.length) return [];
|
|
5676
|
+
const oldSteps = prev.source.meta.steps ?? [];
|
|
5677
|
+
const newSteps = next.source.meta.steps ?? [];
|
|
5678
|
+
const oldPieces = ratedSegments6(prev);
|
|
5679
|
+
const newPieces = ratedSegments6(next);
|
|
5680
|
+
const oldDuration = prev.source.meta.durationMs / 1e3;
|
|
5681
|
+
const newDuration = next.source.meta.durationMs / 1e3;
|
|
5682
|
+
const stepMap = buildStepMap(oldSteps, newSteps, oldDuration, newDuration);
|
|
5683
|
+
const ctx = { oldSteps, newSteps, stepMap, report };
|
|
5684
|
+
const follow = (o, oldRef, newRef) => {
|
|
5685
|
+
const offset = o.start - sourceToOutput(oldPieces, oldRef);
|
|
5686
|
+
const start = Math.max(0, sourceToOutput(newPieces, newRef) + offset);
|
|
5687
|
+
return { ...o, start: +start.toFixed(3) };
|
|
5688
|
+
};
|
|
5689
|
+
return overlays.map((o) => {
|
|
5690
|
+
const pin = o.pin;
|
|
5691
|
+
if (pin?.step !== void 0) {
|
|
5692
|
+
const was = stepByRef(oldSteps, pin.step);
|
|
5693
|
+
const now2 = was ? matchStep(was, newSteps) : stepByRef(newSteps, pin.step);
|
|
5694
|
+
if (!now2 || now2.skipped) {
|
|
5695
|
+
report.flagged.push(
|
|
5696
|
+
`overlay ${o.id}: pinned to step ${String(pin.step)}, which is missing or skipped in the new recording \u2014 kept at ${o.start.toFixed(2)}s; re-pin or re-place it`
|
|
5697
|
+
);
|
|
5698
|
+
return o;
|
|
5699
|
+
}
|
|
5700
|
+
report.anchored++;
|
|
5701
|
+
return follow(o, was?.tStart ?? now2.tStart, now2.tStart);
|
|
5702
|
+
}
|
|
5703
|
+
if (typeof pin?.press === "number") {
|
|
5704
|
+
const placed = placeMoment(pin.press, void 0, ctx);
|
|
5705
|
+
if ("gone" in placed) {
|
|
5706
|
+
report.flagged.push(
|
|
5707
|
+
`overlay ${o.id}: pinned to a press at ${pin.press.toFixed(2)}s, and ${goneWords(placed.gone)} \u2014 kept at ${o.start.toFixed(2)}s; re-pin or re-place it`
|
|
5708
|
+
);
|
|
5709
|
+
return o;
|
|
5710
|
+
}
|
|
5711
|
+
const moved = follow(o, pin.press, placed.at);
|
|
5712
|
+
return { ...moved, pin: { ...pin, press: +placed.at.toFixed(3) } };
|
|
5713
|
+
}
|
|
5714
|
+
const under = stepUnder(
|
|
5715
|
+
outputToSource(oldPieces, o.start),
|
|
5716
|
+
oldSteps,
|
|
5717
|
+
LAYER_AFTER_STEP
|
|
5718
|
+
);
|
|
5719
|
+
if (!under) return o;
|
|
5720
|
+
const now = matchStep(under, newSteps);
|
|
5721
|
+
if (!now) {
|
|
5722
|
+
report.flagged.push(
|
|
5723
|
+
`overlay ${o.id} (${o.start.toFixed(2)}s): it sat over step ${stepName(under)}, which is missing or skipped in the new recording \u2014 kept at its output time; re-place it`
|
|
5724
|
+
);
|
|
5725
|
+
return o;
|
|
5726
|
+
}
|
|
5727
|
+
const expected = follow(o, under.tStart, now.tStart).start;
|
|
5728
|
+
if (Math.abs(expected - o.start) > LAYER_DRIFT) {
|
|
5729
|
+
report.flagged.push(
|
|
5730
|
+
`overlay ${o.id} (${o.start.toFixed(2)}s): it sat over step ${stepName(under)}, which now plays at ${expected.toFixed(2)}s in the cut \u2014 kept at ${o.start.toFixed(2)}s by the output-time contract; pin it to follow (pin: { step: ${JSON.stringify(under.id ?? under.step)} }) or move it`
|
|
5731
|
+
);
|
|
5732
|
+
}
|
|
5733
|
+
return o;
|
|
5734
|
+
});
|
|
5735
|
+
}
|
|
5545
5736
|
|
|
5546
5737
|
// src/plugin/plan.ts
|
|
5547
5738
|
var overlaps = (a, b) => a.in < b.out && b.in < a.out;
|
|
@@ -5590,7 +5781,8 @@ function planOtherMedia(doc, activity) {
|
|
|
5590
5781
|
height: m.meta.height,
|
|
5591
5782
|
duration: m.meta.durationMs / 1e3,
|
|
5592
5783
|
style: doc.zoomStyle,
|
|
5593
|
-
params: doc.zoomParams
|
|
5784
|
+
params: doc.zoomParams,
|
|
5785
|
+
steps: m.meta.steps
|
|
5594
5786
|
}).filter((z) => !manualZoom.some((x) => overlaps(z, x))).filter((z) => !isRejected("zoom", z, rejected)).map((z) => ({ ...z, id: `${z.id}-${m.id}`, media: m.id }))
|
|
5595
5787
|
);
|
|
5596
5788
|
const manualSpeed = (doc.speed ?? []).filter(
|
|
@@ -5600,7 +5792,8 @@ function planOtherMedia(doc, activity) {
|
|
|
5600
5792
|
...planAutoSpeed(m.cursor, {
|
|
5601
5793
|
durationMs: m.meta.durationMs,
|
|
5602
5794
|
params: doc.speedParams,
|
|
5603
|
-
activity
|
|
5795
|
+
activity,
|
|
5796
|
+
steps: m.meta.steps
|
|
5604
5797
|
}).filter((x) => !manualSpeed.some((y) => x.in < y.out && x.out > y.in)).filter((x) => !isRejected("speed", x, rejected)).map((x) => ({ ...x, id: `${x.id}-${m.id}`, media: m.id }))
|
|
5605
5798
|
);
|
|
5606
5799
|
}
|
|
@@ -5633,14 +5826,16 @@ async function planTake(dir, opts = {}) {
|
|
|
5633
5826
|
height: doc.source.meta.height,
|
|
5634
5827
|
duration: doc.source.meta.durationMs / 1e3,
|
|
5635
5828
|
style: doc.zoomStyle,
|
|
5636
|
-
params: doc.zoomParams
|
|
5829
|
+
params: doc.zoomParams,
|
|
5830
|
+
steps: doc.source.meta.steps
|
|
5637
5831
|
}).filter((z) => !manualZoom.some((m) => overlaps(z, m))).filter((z) => !isRejected("zoom", z, doc.rejected));
|
|
5638
5832
|
doc.zoom = [...manualZoom, ...autoZoom].sort((a, b) => a.in - b.in);
|
|
5639
5833
|
const manualSpeed = rt.speed;
|
|
5640
5834
|
const autoSpeed = planAutoSpeed(doc.source.cursor, {
|
|
5641
5835
|
durationMs: doc.source.meta.durationMs,
|
|
5642
5836
|
params: doc.speedParams,
|
|
5643
|
-
activity
|
|
5837
|
+
activity,
|
|
5838
|
+
steps: doc.source.meta.steps
|
|
5644
5839
|
}).filter((s) => !manualSpeed.some((m) => s.in < m.out && s.out > m.in)).filter((s) => !isRejected("speed", s, doc.rejected));
|
|
5645
5840
|
doc.speed = [...manualSpeed, ...autoSpeed].sort((a, b) => a.in - b.in);
|
|
5646
5841
|
{
|
|
@@ -5655,7 +5850,9 @@ async function planTake(dir, opts = {}) {
|
|
|
5655
5850
|
].sort((a, b) => a.in - b.in);
|
|
5656
5851
|
}
|
|
5657
5852
|
if (rt.tilt.length) doc.tilt = rt.tilt;
|
|
5658
|
-
if (prev.overlays?.length)
|
|
5853
|
+
if (prev.overlays?.length) {
|
|
5854
|
+
doc.overlays = retimeOverlays(prev, doc, rt.report);
|
|
5855
|
+
}
|
|
5659
5856
|
if (prev.objects?.length) doc.objects = prev.objects;
|
|
5660
5857
|
if (prev.audio.length) doc.audio = prev.audio;
|
|
5661
5858
|
if (prev.camMotion?.length) doc.camMotion = prev.camMotion;
|
|
@@ -5686,7 +5883,8 @@ async function planTake(dir, opts = {}) {
|
|
|
5686
5883
|
height: doc.source.meta.height,
|
|
5687
5884
|
duration: doc.source.meta.durationMs / 1e3,
|
|
5688
5885
|
style: doc.zoomStyle,
|
|
5689
|
-
params: doc.zoomParams
|
|
5886
|
+
params: doc.zoomParams,
|
|
5887
|
+
steps: doc.source.meta.steps
|
|
5690
5888
|
}).filter((z) => !manual.some((m) => overlaps(z, m))).filter((z) => !isRejected("zoom", z, doc.rejected));
|
|
5691
5889
|
doc.zoom = [...manual, ...auto].sort((a, b) => a.in - b.in);
|
|
5692
5890
|
const manualSpeed = (doc.speed ?? []).filter(
|
|
@@ -5695,7 +5893,8 @@ async function planTake(dir, opts = {}) {
|
|
|
5695
5893
|
const autoSpeed = planAutoSpeed(doc.source.cursor, {
|
|
5696
5894
|
durationMs: doc.source.meta.durationMs,
|
|
5697
5895
|
params: doc.speedParams,
|
|
5698
|
-
activity
|
|
5896
|
+
activity,
|
|
5897
|
+
steps: doc.source.meta.steps
|
|
5699
5898
|
}).filter((s) => !manualSpeed.some((m) => s.in < m.out && s.out > m.in)).filter((s) => !isRejected("speed", s, doc.rejected));
|
|
5700
5899
|
doc.speed = [...manualSpeed, ...autoSpeed].sort((a, b) => a.in - b.in);
|
|
5701
5900
|
{
|
|
@@ -5726,12 +5925,14 @@ async function planTake(dir, opts = {}) {
|
|
|
5726
5925
|
height: doc.source.meta.height,
|
|
5727
5926
|
duration: doc.source.meta.durationMs / 1e3,
|
|
5728
5927
|
style: doc.zoomStyle,
|
|
5729
|
-
params: doc.zoomParams
|
|
5928
|
+
params: doc.zoomParams,
|
|
5929
|
+
steps: doc.source.meta.steps
|
|
5730
5930
|
});
|
|
5731
5931
|
doc.speed = planAutoSpeed(doc.source.cursor, {
|
|
5732
5932
|
durationMs: doc.source.meta.durationMs,
|
|
5733
5933
|
params: doc.speedParams,
|
|
5734
|
-
activity
|
|
5934
|
+
activity,
|
|
5935
|
+
steps: doc.source.meta.steps
|
|
5735
5936
|
});
|
|
5736
5937
|
fresh = true;
|
|
5737
5938
|
}
|
|
@@ -5763,15 +5964,48 @@ async function planTake(dir, opts = {}) {
|
|
|
5763
5964
|
|
|
5764
5965
|
// src/plugin/sync.ts
|
|
5765
5966
|
import { createHash } from "crypto";
|
|
5766
|
-
import { existsSync as
|
|
5767
|
-
import { readFile as
|
|
5967
|
+
import { existsSync as existsSync11, readFileSync as readFileSync3, readdirSync as readdirSync2 } from "fs";
|
|
5968
|
+
import { readFile as readFile10 } from "fs/promises";
|
|
5768
5969
|
import { createInterface } from "readline/promises";
|
|
5769
|
-
import { basename, join as
|
|
5970
|
+
import { basename, join as join13 } from "path";
|
|
5770
5971
|
import { lowerToComposition as lowerToComposition3, migrateHostedDoc as migrateHostedDoc2 } from "@vosjs/studio-core";
|
|
5771
5972
|
|
|
5772
|
-
// src/plugin/
|
|
5773
|
-
import {
|
|
5973
|
+
// src/plugin/takeScript.ts
|
|
5974
|
+
import { existsSync as existsSync10 } from "fs";
|
|
5975
|
+
import { readFile as readFile9, writeFile as writeFile7 } from "fs/promises";
|
|
5976
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
5774
5977
|
import { join as join11 } from "path";
|
|
5978
|
+
function scriptFromText(text) {
|
|
5979
|
+
try {
|
|
5980
|
+
const v = JSON.parse(text);
|
|
5981
|
+
return v && typeof v === "object" && !Array.isArray(v) ? v : null;
|
|
5982
|
+
} catch {
|
|
5983
|
+
return null;
|
|
5984
|
+
}
|
|
5985
|
+
}
|
|
5986
|
+
function scriptToWrite(doc, hasLocal) {
|
|
5987
|
+
const script = doc.source.script;
|
|
5988
|
+
if (hasLocal || !script || typeof script !== "object") return null;
|
|
5989
|
+
return `${JSON.stringify(script, null, 2)}
|
|
5990
|
+
`;
|
|
5991
|
+
}
|
|
5992
|
+
function embedScript(doc, dir) {
|
|
5993
|
+
const path = join11(dir, "actions.json");
|
|
5994
|
+
if (!existsSync10(path)) return;
|
|
5995
|
+
const script = scriptFromText(readFileSync2(path, "utf8"));
|
|
5996
|
+
if (script) doc.source.script = script;
|
|
5997
|
+
}
|
|
5998
|
+
async function writeScriptBeside(dir, doc) {
|
|
5999
|
+
const path = join11(dir, "actions.json");
|
|
6000
|
+
const text = scriptToWrite(doc, existsSync10(path));
|
|
6001
|
+
if (text === null) return false;
|
|
6002
|
+
await writeFile7(path, text, "utf8");
|
|
6003
|
+
return true;
|
|
6004
|
+
}
|
|
6005
|
+
|
|
6006
|
+
// src/plugin/folder.ts
|
|
6007
|
+
import { mkdir as mkdir5, writeFile as writeFile8 } from "fs/promises";
|
|
6008
|
+
import { join as join12 } from "path";
|
|
5775
6009
|
import { recipeHints } from "@vosjs/shared/frontmatter";
|
|
5776
6010
|
import { migrateHostedDoc } from "@vosjs/studio-core";
|
|
5777
6011
|
var BOOLEAN_FLAGS = /* @__PURE__ */ new Set(["json", "help", "media"]);
|
|
@@ -5947,25 +6181,25 @@ async function cmdPull(argv) {
|
|
|
5947
6181
|
throw new Error(apiError(`pull folder ${folder.slug}`, res));
|
|
5948
6182
|
const payload = res.body;
|
|
5949
6183
|
const out = strFlag(flags, "out") ?? folder.slug;
|
|
5950
|
-
await mkdir5(
|
|
6184
|
+
await mkdir5(join12(out, "recipes"), { recursive: true });
|
|
5951
6185
|
const lines = [];
|
|
5952
6186
|
const recipes = [];
|
|
5953
6187
|
for (const rec of payload.recipes) {
|
|
5954
|
-
const path =
|
|
5955
|
-
await
|
|
6188
|
+
const path = join12(out, "recipes", safeName(rec.filename));
|
|
6189
|
+
await writeFile8(path, rec.body ?? "");
|
|
5956
6190
|
recipes.push({ path, line: recipeLine(rec.filename, rec.body ?? "") });
|
|
5957
6191
|
}
|
|
5958
6192
|
for (const rec of payload.inheritedRecipes) {
|
|
5959
6193
|
const from = safeName(rec.folderSlug ?? "inherited");
|
|
5960
|
-
await mkdir5(
|
|
5961
|
-
const path =
|
|
6194
|
+
await mkdir5(join12(out, "recipes", "_inherited", from), { recursive: true });
|
|
6195
|
+
const path = join12(
|
|
5962
6196
|
out,
|
|
5963
6197
|
"recipes",
|
|
5964
6198
|
"_inherited",
|
|
5965
6199
|
from,
|
|
5966
6200
|
safeName(rec.filename)
|
|
5967
6201
|
);
|
|
5968
|
-
await
|
|
6202
|
+
await writeFile8(path, rec.body ?? "");
|
|
5969
6203
|
recipes.push({
|
|
5970
6204
|
path,
|
|
5971
6205
|
line: `${recipeLine(rec.filename, rec.body ?? "")} [inherited from ${rec.folderName ?? from}]`
|
|
@@ -5973,15 +6207,15 @@ async function cmdPull(argv) {
|
|
|
5973
6207
|
}
|
|
5974
6208
|
const members = [];
|
|
5975
6209
|
for (const v of payload.voses) {
|
|
5976
|
-
const dir =
|
|
6210
|
+
const dir = join12(out, "members", safeName(v.slug || v.title || v.id));
|
|
5977
6211
|
await mkdir5(dir, { recursive: true });
|
|
5978
6212
|
const cfg = await apiJson(origin, `/api/vos/${v.id}/config`, { key });
|
|
5979
6213
|
if (cfg.status !== 200) {
|
|
5980
6214
|
lines.push(`skipped ${v.title}: ${apiError("fetch config", cfg)}`);
|
|
5981
6215
|
continue;
|
|
5982
6216
|
}
|
|
5983
|
-
await
|
|
5984
|
-
|
|
6217
|
+
await writeFile8(
|
|
6218
|
+
join12(dir, "config.json"),
|
|
5985
6219
|
JSON.stringify(cfg.body.config, null, 2)
|
|
5986
6220
|
);
|
|
5987
6221
|
let take = false;
|
|
@@ -5992,8 +6226,8 @@ async function cmdPull(argv) {
|
|
|
5992
6226
|
{ key }
|
|
5993
6227
|
);
|
|
5994
6228
|
if (doc.status === 200) {
|
|
5995
|
-
await
|
|
5996
|
-
|
|
6229
|
+
await writeFile8(
|
|
6230
|
+
join12(dir, "doc.json"),
|
|
5997
6231
|
JSON.stringify(doc.body, null, 2)
|
|
5998
6232
|
);
|
|
5999
6233
|
take = true;
|
|
@@ -6119,8 +6353,8 @@ function storageStateInDir(dir) {
|
|
|
6119
6353
|
if (!f.endsWith(".json") || f === "doc.json" || f === "meta.json" || f === "actions.json" || f === "cursor.json" || f === "vos.json" || f === "doc.prev.json")
|
|
6120
6354
|
continue;
|
|
6121
6355
|
try {
|
|
6122
|
-
const v = JSON.parse(
|
|
6123
|
-
if (looksLikeStorageState(v)) return
|
|
6356
|
+
const v = JSON.parse(readFileSync3(join13(dir, f), "utf8"));
|
|
6357
|
+
if (looksLikeStorageState(v)) return join13(dir, f);
|
|
6124
6358
|
} catch {
|
|
6125
6359
|
}
|
|
6126
6360
|
}
|
|
@@ -6141,7 +6375,7 @@ async function pushTake(dir, flags, r) {
|
|
|
6141
6375
|
throw new Error(`doc.json fails lint:
|
|
6142
6376
|
${lint.problems.join("\n ")}`);
|
|
6143
6377
|
}
|
|
6144
|
-
if (!
|
|
6378
|
+
if (!existsSync11(take.paths.recording)) {
|
|
6145
6379
|
throw new Error(
|
|
6146
6380
|
"no recording in this take \u2014 record it, or `vos pull --media` to bring it home"
|
|
6147
6381
|
);
|
|
@@ -6190,7 +6424,7 @@ async function pushTake(dir, flags, r) {
|
|
|
6190
6424
|
throw new Error("push cancelled");
|
|
6191
6425
|
}
|
|
6192
6426
|
}
|
|
6193
|
-
const bytes = await
|
|
6427
|
+
const bytes = await readFile10(take.paths.recording);
|
|
6194
6428
|
const hash = createHash("sha256").update(bytes).digest("hex");
|
|
6195
6429
|
const { type: contentType } = resolveMediaType({
|
|
6196
6430
|
head: bytes.subarray(0, MEDIA_HEAD_BYTES),
|
|
@@ -6225,6 +6459,7 @@ async function pushTake(dir, flags, r) {
|
|
|
6225
6459
|
if (upload.reused) r.log(" recording already hosted \u2014 reused");
|
|
6226
6460
|
const docForPush = structuredClone(take.doc);
|
|
6227
6461
|
docForPush.source.videoKey = assetUrl;
|
|
6462
|
+
embedScript(docForPush, dir);
|
|
6228
6463
|
await uploadDocRefs(sourceSidecarRefs(docForPush), dir, ctx, (l) => r.log(l));
|
|
6229
6464
|
for (const field of ["micKey", "camKey"]) {
|
|
6230
6465
|
const key = docForPush.source[field];
|
|
@@ -6362,9 +6597,9 @@ async function pullTake(dir, flags, r) {
|
|
|
6362
6597
|
};
|
|
6363
6598
|
}
|
|
6364
6599
|
let media2;
|
|
6365
|
-
if (flags.media &&
|
|
6600
|
+
if (flags.media && existsSync11(join13(dir, "doc.json"))) {
|
|
6366
6601
|
const local = JSON.parse(
|
|
6367
|
-
await
|
|
6602
|
+
await readFile10(join13(dir, "doc.json"), "utf8")
|
|
6368
6603
|
);
|
|
6369
6604
|
media2 = await pullMedia(ctx, dir, local, r.log);
|
|
6370
6605
|
}
|
|
@@ -6425,11 +6660,14 @@ async function pullTake(dir, flags, r) {
|
|
|
6425
6660
|
const hostedDoc = migrateHostedDoc2(docRes.json);
|
|
6426
6661
|
const doc = hostedDoc;
|
|
6427
6662
|
const localRecording = takeMediaFile(dir, "recording", RECORDING_NAME);
|
|
6428
|
-
if (
|
|
6663
|
+
if (existsSync11(localRecording)) {
|
|
6429
6664
|
doc.source.videoKey = basename(localRecording);
|
|
6430
6665
|
}
|
|
6431
|
-
await writeJson(
|
|
6666
|
+
await writeJson(join13(dir, "doc.json"), doc, true);
|
|
6432
6667
|
const media = flags.media ? await pullMedia(ctx, dir, doc, r.log) : void 0;
|
|
6668
|
+
if (flags.media && await writeScriptBeside(dir, doc)) {
|
|
6669
|
+
r.log(" actions.json written from the document");
|
|
6670
|
+
}
|
|
6433
6671
|
const versions = await api(ctx, `/vos/${vosId}/versions`);
|
|
6434
6672
|
const headRow = (versions.json.versions ?? []).find((v) => v.id === head);
|
|
6435
6673
|
writeSyncState(dir, {
|
|
@@ -6463,6 +6701,7 @@ async function pushTakeClaimable(dir, flags, r) {
|
|
|
6463
6701
|
const state = readSyncState(dir);
|
|
6464
6702
|
const hosted = state?.hostedMedia ?? {};
|
|
6465
6703
|
const docForPush = structuredClone(take.doc);
|
|
6704
|
+
embedScript(docForPush, dir);
|
|
6466
6705
|
const refs = [
|
|
6467
6706
|
...isTakeRelativeKey(docForPush.source.videoKey) ? [
|
|
6468
6707
|
{
|
|
@@ -6484,8 +6723,8 @@ async function pushTakeClaimable(dir, flags, r) {
|
|
|
6484
6723
|
`${ref.where} (${file}) is not a file this take fetched from vos.so, and a claimable push never uploads footage. Push the take with an account (vos login, then vos push ${dir}), or remix a public take fetched with \`vos fetch <url> --media\``
|
|
6485
6724
|
);
|
|
6486
6725
|
}
|
|
6487
|
-
const path =
|
|
6488
|
-
const now =
|
|
6726
|
+
const path = join13(dir, file);
|
|
6727
|
+
const now = existsSync11(path) ? await fileSha256(path) : null;
|
|
6489
6728
|
if (now !== origin2.sha256) {
|
|
6490
6729
|
throw new Error(
|
|
6491
6730
|
`${ref.where} (${file}) changed since it was fetched, so it is no longer the hosted file. A claimable push names only the original; push with an account to upload the new one`
|
|
@@ -6519,10 +6758,10 @@ async function pushTakeClaimable(dir, flags, r) {
|
|
|
6519
6758
|
}
|
|
6520
6759
|
|
|
6521
6760
|
// src/plugin/program.ts
|
|
6522
|
-
import { existsSync as
|
|
6523
|
-
import { mkdir as mkdir6, readFile as
|
|
6761
|
+
import { existsSync as existsSync13 } from "fs";
|
|
6762
|
+
import { mkdir as mkdir6, readFile as readFile11, writeFile as writeFile9 } from "fs/promises";
|
|
6524
6763
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
6525
|
-
import { basename as basename3, dirname as dirname2, join as
|
|
6764
|
+
import { basename as basename3, dirname as dirname2, join as join14 } from "path";
|
|
6526
6765
|
import {
|
|
6527
6766
|
CURRENT_CONFIG_VERSION,
|
|
6528
6767
|
migrateConfig,
|
|
@@ -6656,12 +6895,12 @@ async function handoffLogin(url, r, opts = {}) {
|
|
|
6656
6895
|
|
|
6657
6896
|
// src/plugin/programFiles.ts
|
|
6658
6897
|
import { basename as basename2, extname as extname2, relative as relative2 } from "path";
|
|
6659
|
-
import { existsSync as
|
|
6898
|
+
import { existsSync as existsSync12, realpathSync } from "fs";
|
|
6660
6899
|
function isLocalName(value) {
|
|
6661
6900
|
if (/^(https?:|data:|blob:|asset:|media:)/.test(value)) return false;
|
|
6662
6901
|
if (value.startsWith("$")) return false;
|
|
6663
6902
|
if (value.startsWith("<svg") || value.startsWith("<?xml")) return false;
|
|
6664
|
-
if (value.startsWith("/")) return
|
|
6903
|
+
if (value.startsWith("/")) return existsSync12(value);
|
|
6665
6904
|
return true;
|
|
6666
6905
|
}
|
|
6667
6906
|
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;
|
|
@@ -6836,8 +7075,8 @@ function preflightConfig(parsed) {
|
|
|
6836
7075
|
}
|
|
6837
7076
|
function resolveConfigPath(target) {
|
|
6838
7077
|
if (target.endsWith(".json")) return target;
|
|
6839
|
-
const inDir =
|
|
6840
|
-
if (
|
|
7078
|
+
const inDir = join14(target, "config.json");
|
|
7079
|
+
if (existsSync13(inDir)) return inDir;
|
|
6841
7080
|
throw new UsageError(
|
|
6842
7081
|
`${target} has no config.json (and is not a take \u2014 no doc.json)`
|
|
6843
7082
|
);
|
|
@@ -6864,8 +7103,8 @@ async function cmdFetch(argv) {
|
|
|
6864
7103
|
const slug = typeof vosMeta.slug === "string" && vosMeta.slug ? vosMeta.slug : vosId;
|
|
6865
7104
|
const out = strFlag(flags, "out") ?? slug;
|
|
6866
7105
|
await mkdir6(out, { recursive: true });
|
|
6867
|
-
await
|
|
6868
|
-
|
|
7106
|
+
await writeFile9(
|
|
7107
|
+
join14(out, "config.json"),
|
|
6869
7108
|
JSON.stringify(cfg.body.config, null, 2)
|
|
6870
7109
|
);
|
|
6871
7110
|
const title = typeof vosMeta.title === "string" ? vosMeta.title : "";
|
|
@@ -6890,30 +7129,33 @@ async function cmdFetch(argv) {
|
|
|
6890
7129
|
const hosted = migrateHostedDoc3(doc.body);
|
|
6891
7130
|
const { config: own } = await writeProgramDoc(out, hosted);
|
|
6892
7131
|
if (own) {
|
|
6893
|
-
await
|
|
7132
|
+
await writeFile9(join14(out, "config.json"), JSON.stringify(own, null, 2));
|
|
6894
7133
|
}
|
|
6895
7134
|
} else if (doc.status === 200) {
|
|
6896
7135
|
take = true;
|
|
6897
7136
|
const hosted = migrateHostedDoc3(doc.body);
|
|
6898
|
-
await
|
|
7137
|
+
await writeFile9(join14(out, "doc.json"), JSON.stringify(hosted, null, 2));
|
|
6899
7138
|
if (flags.media === true) {
|
|
6900
7139
|
const media = await pullMedia({ origin, key }, out, hosted, r.log);
|
|
6901
7140
|
await recordHostedMedia(out, vosId, media);
|
|
7141
|
+
if (await writeScriptBeside(out, hosted)) {
|
|
7142
|
+
r.log(" actions.json written from the document");
|
|
7143
|
+
}
|
|
6902
7144
|
mediaLine = media.downloaded.length ? ` + ${media.downloaded.map((m) => m.file).join(", ")}` : "";
|
|
6903
7145
|
}
|
|
6904
7146
|
}
|
|
6905
7147
|
}
|
|
6906
7148
|
let assetsLine = "";
|
|
6907
7149
|
if (!take) {
|
|
6908
|
-
const configPath =
|
|
6909
|
-
const written = JSON.parse(await
|
|
7150
|
+
const configPath = join14(out, "config.json");
|
|
7151
|
+
const written = JSON.parse(await readFile11(configPath, "utf8"));
|
|
6910
7152
|
const hostedCount = manifestRefs(written).filter(
|
|
6911
7153
|
({ ref }) => hostedAssetId(ref, [origin, "https://vos.so", "https://www.vos.so"])
|
|
6912
7154
|
).length;
|
|
6913
7155
|
if (hostedCount && flags.media === true) {
|
|
6914
7156
|
const pulled = await pullManifest({ origin, key }, out, written, r.log);
|
|
6915
7157
|
if (pulled) {
|
|
6916
|
-
await
|
|
7158
|
+
await writeFile9(
|
|
6917
7159
|
configPath,
|
|
6918
7160
|
JSON.stringify({ ...written, assets: pulled.assets }, null, 2)
|
|
6919
7161
|
);
|
|
@@ -7033,7 +7275,7 @@ async function cmdPushProgram(argv) {
|
|
|
7033
7275
|
api: strFlag(flags, "api")
|
|
7034
7276
|
});
|
|
7035
7277
|
const dir = dirname2(source);
|
|
7036
|
-
const parsed = JSON.parse(await
|
|
7278
|
+
const parsed = JSON.parse(await readFile11(source, "utf8"));
|
|
7037
7279
|
const pre = preflightConfig(parsed);
|
|
7038
7280
|
if (!pre.ok || !pre.config) {
|
|
7039
7281
|
for (const issue of pre.issues) r.log(`error ${issue}`);
|
|
@@ -7381,10 +7623,10 @@ async function cmdPullProgram(argv) {
|
|
|
7381
7623
|
const cfg = await apiJson(origin, `/api/vos/${vosId}/config`, { key });
|
|
7382
7624
|
if (cfg.status !== 200)
|
|
7383
7625
|
throw new Error(apiError(`fetch head config for ${vosId}`, cfg));
|
|
7384
|
-
const configPath =
|
|
7626
|
+
const configPath = join14(dir, "config.json");
|
|
7385
7627
|
let backedUp = false;
|
|
7386
|
-
if (
|
|
7387
|
-
await
|
|
7628
|
+
if (existsSync13(configPath)) {
|
|
7629
|
+
await writeFile9(join14(dir, "config.backup.json"), await readFile11(configPath));
|
|
7388
7630
|
backedUp = true;
|
|
7389
7631
|
}
|
|
7390
7632
|
let headConfig = cfg.body.config;
|
|
@@ -7403,7 +7645,7 @@ async function cmdPullProgram(argv) {
|
|
|
7403
7645
|
if (own) headConfig = own;
|
|
7404
7646
|
}
|
|
7405
7647
|
}
|
|
7406
|
-
await
|
|
7648
|
+
await writeFile9(configPath, JSON.stringify(headConfig, null, 2));
|
|
7407
7649
|
writeSyncState(dir, {
|
|
7408
7650
|
vosId,
|
|
7409
7651
|
versionId: typeof head.id === "string" ? head.id : since
|
|
@@ -7417,7 +7659,7 @@ async function cmdPullProgram(argv) {
|
|
|
7417
7659
|
protected: protectedIds,
|
|
7418
7660
|
changes,
|
|
7419
7661
|
out: configPath,
|
|
7420
|
-
backup: backedUp ?
|
|
7662
|
+
backup: backedUp ? join14(dir, "config.backup.json") : null
|
|
7421
7663
|
},
|
|
7422
7664
|
`Pulled ${changes.length} version${changes.length === 1 ? "" : "s"} \u2192 ${configPath}` + (backedUp ? ` (previous copy: config.backup.json)` : "") + `
|
|
7423
7665
|
Re-apply your edit on the new head, then: vos push ${configPath} --vos ${vosId}`
|
|
@@ -7525,9 +7767,9 @@ function storedProgramConfig(config, programDoc) {
|
|
|
7525
7767
|
return lowerProgramDoc(doc).config;
|
|
7526
7768
|
}
|
|
7527
7769
|
async function readProgramDoc(dir, config) {
|
|
7528
|
-
const docPath =
|
|
7529
|
-
if (!
|
|
7530
|
-
const parsed = JSON.parse(await
|
|
7770
|
+
const docPath = join14(dir, "doc.json");
|
|
7771
|
+
if (!existsSync13(docPath)) return null;
|
|
7772
|
+
const parsed = JSON.parse(await readFile11(docPath, "utf8"));
|
|
7531
7773
|
if (typeof parsed !== "object" || parsed === null || "source" in parsed)
|
|
7532
7774
|
return null;
|
|
7533
7775
|
const raw = parsed;
|
|
@@ -7535,23 +7777,23 @@ async function readProgramDoc(dir, config) {
|
|
|
7535
7777
|
return { ...raw, program: { ...program, config } };
|
|
7536
7778
|
}
|
|
7537
7779
|
async function setProgramStill(dir, t) {
|
|
7538
|
-
const docPath =
|
|
7780
|
+
const docPath = join14(dir, "doc.json");
|
|
7539
7781
|
let doc = { program: {}, audio: [] };
|
|
7540
|
-
if (
|
|
7541
|
-
const parsed = JSON.parse(await
|
|
7782
|
+
if (existsSync13(docPath)) {
|
|
7783
|
+
const parsed = JSON.parse(await readFile11(docPath, "utf8"));
|
|
7542
7784
|
if (!parsed || typeof parsed !== "object" || "source" in parsed)
|
|
7543
7785
|
throw new UsageError(
|
|
7544
7786
|
`${docPath} is a take's document; a take's cover is its own "still" field`
|
|
7545
7787
|
);
|
|
7546
7788
|
doc = parsed;
|
|
7547
7789
|
}
|
|
7548
|
-
await
|
|
7790
|
+
await writeFile9(docPath, JSON.stringify({ ...doc, still: t }, null, 2) + "\n");
|
|
7549
7791
|
}
|
|
7550
7792
|
async function writeProgramDoc(dir, hosted) {
|
|
7551
7793
|
const program = hosted.program && typeof hosted.program === "object" ? hosted.program : {};
|
|
7552
7794
|
const { config, ...rest } = program;
|
|
7553
7795
|
const onDisk = { ...hosted, program: rest };
|
|
7554
|
-
await
|
|
7796
|
+
await writeFile9(join14(dir, "doc.json"), JSON.stringify(onDisk, null, 2));
|
|
7555
7797
|
return {
|
|
7556
7798
|
config: config && typeof config === "object" ? config : null
|
|
7557
7799
|
};
|
|
@@ -7559,7 +7801,7 @@ async function writeProgramDoc(dir, hosted) {
|
|
|
7559
7801
|
|
|
7560
7802
|
// src/plugin/asset.ts
|
|
7561
7803
|
import { createHash as createHash2 } from "crypto";
|
|
7562
|
-
import { readFileSync as
|
|
7804
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
7563
7805
|
import { basename as basename4 } from "path";
|
|
7564
7806
|
|
|
7565
7807
|
// src/plugin/assetWords.ts
|
|
@@ -7702,7 +7944,7 @@ async function cmdPush(argv) {
|
|
|
7702
7944
|
const uploaded = [];
|
|
7703
7945
|
for (const file of positionals) {
|
|
7704
7946
|
const name = basename4(file);
|
|
7705
|
-
const body =
|
|
7947
|
+
const body = readFileSync4(file);
|
|
7706
7948
|
const media = resolveMediaType({
|
|
7707
7949
|
head: body.subarray(0, MEDIA_HEAD_BYTES),
|
|
7708
7950
|
filename: name
|
|
@@ -7963,8 +8205,8 @@ async function cmdAsset(argv) {
|
|
|
7963
8205
|
}
|
|
7964
8206
|
|
|
7965
8207
|
// src/plugin/remove.ts
|
|
7966
|
-
import { existsSync as
|
|
7967
|
-
import { join as
|
|
8208
|
+
import { existsSync as existsSync14, rmSync as rmSync2, statSync as statSync3 } from "fs";
|
|
8209
|
+
import { join as join15 } from "path";
|
|
7968
8210
|
import { createInterface as createInterface3 } from "readline/promises";
|
|
7969
8211
|
|
|
7970
8212
|
// src/plugin/trash.ts
|
|
@@ -8143,7 +8385,7 @@ async function cmdDelete(argv) {
|
|
|
8143
8385
|
api: strFlag(flags, "api")
|
|
8144
8386
|
}).replace(/\/+$/, "");
|
|
8145
8387
|
const key = requireCredential(strFlag(flags, "key"));
|
|
8146
|
-
const dir =
|
|
8388
|
+
const dir = existsSync14(target) && statSync3(target).isDirectory() ? target : null;
|
|
8147
8389
|
const vosId = dir ? readSyncState(dir)?.vosId : parseVosId(target);
|
|
8148
8390
|
if (!vosId)
|
|
8149
8391
|
throw new UsageError(
|
|
@@ -8186,7 +8428,7 @@ async function cmdDelete(argv) {
|
|
|
8186
8428
|
const tracking = dir ?? trackingCwd(vosId);
|
|
8187
8429
|
let unlinked = false;
|
|
8188
8430
|
if (tracking) {
|
|
8189
|
-
rmSync2(
|
|
8431
|
+
rmSync2(join15(tracking, SYNC_STATE_NAME), { force: true });
|
|
8190
8432
|
unlinked = true;
|
|
8191
8433
|
}
|
|
8192
8434
|
const trashed = res.body.trashed === true;
|
|
@@ -8211,13 +8453,13 @@ async function cmdDelete(argv) {
|
|
|
8211
8453
|
}
|
|
8212
8454
|
function trackingCwd(vosId) {
|
|
8213
8455
|
const cwd = process.cwd();
|
|
8214
|
-
if (!
|
|
8456
|
+
if (!existsSync14(join15(cwd, SYNC_STATE_NAME))) return null;
|
|
8215
8457
|
return readSyncState(cwd)?.vosId === vosId ? cwd : null;
|
|
8216
8458
|
}
|
|
8217
8459
|
|
|
8218
8460
|
// src/plugin/buildProgram.ts
|
|
8219
|
-
import { readFileSync as
|
|
8220
|
-
import { basename as basename5, dirname as dirname3, join as
|
|
8461
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
|
|
8462
|
+
import { basename as basename5, dirname as dirname3, join as join16, resolve as resolve5 } from "path";
|
|
8221
8463
|
import { pathToFileURL } from "url";
|
|
8222
8464
|
import { parse } from "acorn";
|
|
8223
8465
|
import { fullAncestor } from "acorn-walk";
|
|
@@ -8418,7 +8660,7 @@ async function cmdBuild(argv) {
|
|
|
8418
8660
|
throw new UsageError("vos build <program.mjs> [--out config.json] [--json]");
|
|
8419
8661
|
const r = createReporter(flags.json === true);
|
|
8420
8662
|
const file = resolve5(source);
|
|
8421
|
-
const text =
|
|
8663
|
+
const text = readFileSync5(file, "utf8");
|
|
8422
8664
|
const mod = await import(`${pathToFileURL(file).href}?t=${Date.now()}`);
|
|
8423
8665
|
const program = mod.default ?? mod.program;
|
|
8424
8666
|
if (!program || typeof program !== "object")
|
|
@@ -8435,7 +8677,7 @@ async function cmdBuild(argv) {
|
|
|
8435
8677
|
return EXIT_ERROR;
|
|
8436
8678
|
}
|
|
8437
8679
|
const out = resolve5(
|
|
8438
|
-
strFlag(flags, "out") ??
|
|
8680
|
+
strFlag(flags, "out") ?? join16(dirname3(file), "config.json")
|
|
8439
8681
|
);
|
|
8440
8682
|
writeFileSync2(out, JSON.stringify(built.config, null, 2) + "\n");
|
|
8441
8683
|
const sidecar = out.replace(/\.json$/, "") + ".sources.json";
|
|
@@ -8452,8 +8694,8 @@ async function cmdBuild(argv) {
|
|
|
8452
8694
|
|
|
8453
8695
|
// src/plugin/compare.ts
|
|
8454
8696
|
import { spawnSync } from "child_process";
|
|
8455
|
-
import { existsSync as
|
|
8456
|
-
import { dirname as dirname4, join as
|
|
8697
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync2, statSync as statSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
8698
|
+
import { dirname as dirname4, join as join17, resolve as resolve6 } from "path";
|
|
8457
8699
|
var BOOLEAN_FLAGS7 = /* @__PURE__ */ new Set(["json", "help"]);
|
|
8458
8700
|
function sampleTimes(duration, every) {
|
|
8459
8701
|
const step = every > 0 ? every : 1;
|
|
@@ -8520,7 +8762,7 @@ async function cmdCompare(argv) {
|
|
|
8520
8762
|
const config = loaded.config;
|
|
8521
8763
|
const duration = configDuration(config) ?? 5;
|
|
8522
8764
|
const assets = await programAssets(config, {
|
|
8523
|
-
baseDir: /^https?:\/\//.test(source) ? null :
|
|
8765
|
+
baseDir: /^https?:\/\//.test(source) ? null : existsSync15(source) && statSync4(source).isDirectory() ? source : dirname4(source),
|
|
8524
8766
|
origin: platformOrigin({}),
|
|
8525
8767
|
key: resolveCredential(),
|
|
8526
8768
|
log: (line) => r.log(line)
|
|
@@ -8543,9 +8785,9 @@ async function cmdCompare(argv) {
|
|
|
8543
8785
|
try {
|
|
8544
8786
|
for (const t of times) {
|
|
8545
8787
|
const tag = t.toFixed(2);
|
|
8546
|
-
const refPng =
|
|
8547
|
-
const vosPng =
|
|
8548
|
-
const sheet =
|
|
8788
|
+
const refPng = join17(outDir, `src-${tag}.png`);
|
|
8789
|
+
const vosPng = join17(outDir, `vos-${tag}.png`);
|
|
8790
|
+
const sheet = join17(outDir, `sheet-${tag}.png`);
|
|
8549
8791
|
const grab = ffmpeg([
|
|
8550
8792
|
"-v",
|
|
8551
8793
|
"error",
|
|
@@ -8602,7 +8844,7 @@ async function cmdCompare(argv) {
|
|
|
8602
8844
|
} finally {
|
|
8603
8845
|
await browser.close();
|
|
8604
8846
|
}
|
|
8605
|
-
const overview =
|
|
8847
|
+
const overview = join17(outDir, "overview.png");
|
|
8606
8848
|
if (scores.length) {
|
|
8607
8849
|
const inputs = scores.flatMap((s) => ["-i", s.sheet]);
|
|
8608
8850
|
const scaled = scores.map((_, i) => `[${i}:v]scale=iw/3:-2[s${i}]`).join(";");
|
|
@@ -8628,7 +8870,7 @@ async function cmdCompare(argv) {
|
|
|
8628
8870
|
overview
|
|
8629
8871
|
};
|
|
8630
8872
|
writeFileSync3(
|
|
8631
|
-
|
|
8873
|
+
join17(outDir, "report.json"),
|
|
8632
8874
|
JSON.stringify(report, null, 2) + "\n"
|
|
8633
8875
|
);
|
|
8634
8876
|
r.done(
|
|
@@ -8639,28 +8881,28 @@ async function cmdCompare(argv) {
|
|
|
8639
8881
|
}
|
|
8640
8882
|
|
|
8641
8883
|
// src/plugin/port.ts
|
|
8642
|
-
import { existsSync as
|
|
8643
|
-
import { dirname as dirname7, join as
|
|
8884
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync5, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
|
|
8885
|
+
import { dirname as dirname7, join as join21, resolve as resolve9 } from "path";
|
|
8644
8886
|
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
8645
8887
|
|
|
8646
8888
|
// src/plugin/portInventory.ts
|
|
8647
8889
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
8648
8890
|
import {
|
|
8649
|
-
existsSync as
|
|
8891
|
+
existsSync as existsSync17,
|
|
8650
8892
|
mkdirSync as mkdirSync3,
|
|
8651
|
-
readFileSync as
|
|
8893
|
+
readFileSync as readFileSync7,
|
|
8652
8894
|
readdirSync as readdirSync4,
|
|
8653
8895
|
statSync as statSync6
|
|
8654
8896
|
} from "fs";
|
|
8655
|
-
import { dirname as dirname5, join as
|
|
8897
|
+
import { dirname as dirname5, join as join19, relative as relative3, resolve as resolve7 } from "path";
|
|
8656
8898
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
8657
8899
|
import { findFontFamily as findFontFamily3 } from "@vosjs/shared";
|
|
8658
8900
|
|
|
8659
8901
|
// src/plugin/portRemotion.ts
|
|
8660
|
-
import { existsSync as
|
|
8902
|
+
import { existsSync as existsSync16, readFileSync as readFileSync6, readdirSync as readdirSync3, statSync as statSync5 } from "fs";
|
|
8661
8903
|
import { createServer as createServer2 } from "http";
|
|
8662
8904
|
import { createRequire } from "module";
|
|
8663
|
-
import { basename as basename6, extname as extname3, join as
|
|
8905
|
+
import { basename as basename6, extname as extname3, join as join18 } from "path";
|
|
8664
8906
|
function themeColors(sources) {
|
|
8665
8907
|
const out = {};
|
|
8666
8908
|
const re = /\bconst\s+([A-Za-z_$][\w$]*)\s*(?::\s*string\s*)?=\s*['"](#[0-9a-fA-F]{3,8})['"]/g;
|
|
@@ -8726,14 +8968,14 @@ function sourceTexts(dir) {
|
|
|
8726
8968
|
if (depth > 4 || out.length > 200) return;
|
|
8727
8969
|
for (const name of readdirSync3(d)) {
|
|
8728
8970
|
if (name === "node_modules" || name.startsWith(".")) continue;
|
|
8729
|
-
const p =
|
|
8971
|
+
const p = join18(d, name);
|
|
8730
8972
|
if (statSync5(p).isDirectory()) walk(p, depth + 1);
|
|
8731
8973
|
else if (/\.(tsx?|jsx?|mjs)$/.test(name))
|
|
8732
|
-
out.push(
|
|
8974
|
+
out.push(readFileSync6(p, "utf8"));
|
|
8733
8975
|
}
|
|
8734
8976
|
};
|
|
8735
|
-
const src =
|
|
8736
|
-
walk(
|
|
8977
|
+
const src = join18(dir, "src");
|
|
8978
|
+
walk(existsSync16(src) ? src : dir, 0);
|
|
8737
8979
|
return out;
|
|
8738
8980
|
}
|
|
8739
8981
|
function entryPoint(dir) {
|
|
@@ -8745,7 +8987,7 @@ function entryPoint(dir) {
|
|
|
8745
8987
|
"remotion/index.ts",
|
|
8746
8988
|
"remotion/index.tsx"
|
|
8747
8989
|
])
|
|
8748
|
-
if (
|
|
8990
|
+
if (existsSync16(join18(dir, p))) return join18(dir, p);
|
|
8749
8991
|
return null;
|
|
8750
8992
|
}
|
|
8751
8993
|
var TYPES = {
|
|
@@ -8820,7 +9062,7 @@ async function readRemotion(dir, log) {
|
|
|
8820
9062
|
const entry = entryPoint(dir);
|
|
8821
9063
|
let bundler;
|
|
8822
9064
|
try {
|
|
8823
|
-
bundler = createRequire(
|
|
9065
|
+
bundler = createRequire(join18(dir, "package.json"))("@remotion/bundler");
|
|
8824
9066
|
} catch {
|
|
8825
9067
|
log?.(
|
|
8826
9068
|
"a Remotion project whose dependencies are not installed: run `npm install` in it so vos can read its compositions (words, scenes, faces); reading only the render"
|
|
@@ -8837,13 +9079,13 @@ async function readRemotion(dir, log) {
|
|
|
8837
9079
|
} });
|
|
8838
9080
|
const server = createServer2((rq, rs) => {
|
|
8839
9081
|
const path = decodeURIComponent(new URL(rq.url ?? "/", "http://x").pathname);
|
|
8840
|
-
let f =
|
|
8841
|
-
if (!f.startsWith(out) || !
|
|
8842
|
-
f =
|
|
9082
|
+
let f = join18(out, path);
|
|
9083
|
+
if (!f.startsWith(out) || !existsSync16(f) || statSync5(f).isDirectory())
|
|
9084
|
+
f = join18(out, "index.html");
|
|
8843
9085
|
rs.writeHead(200, {
|
|
8844
9086
|
"content-type": TYPES[extname3(f)] ?? "application/octet-stream"
|
|
8845
9087
|
});
|
|
8846
|
-
rs.end(
|
|
9088
|
+
rs.end(readFileSync6(f));
|
|
8847
9089
|
}).listen(0, "127.0.0.1");
|
|
8848
9090
|
await new Promise((r) => server.once("listening", r));
|
|
8849
9091
|
const port = server.address().port;
|
|
@@ -8938,10 +9180,10 @@ async function readRemotion(dir, log) {
|
|
|
8938
9180
|
perScene.push({ scene: s.name, texts: read.texts ?? [] });
|
|
8939
9181
|
}
|
|
8940
9182
|
const sources = sourceTexts(dir);
|
|
8941
|
-
const publicDir =
|
|
9183
|
+
const publicDir = join18(dir, "public");
|
|
8942
9184
|
const media = tree.audio.map((a) => {
|
|
8943
9185
|
const name = basename6(a.src.split("?")[0]);
|
|
8944
|
-
const local =
|
|
9186
|
+
const local = existsSync16(join18(publicDir, name)) ? `public/${name}` : a.src;
|
|
8945
9187
|
return {
|
|
8946
9188
|
kind: "audio",
|
|
8947
9189
|
src: local,
|
|
@@ -8982,11 +9224,11 @@ async function readRemotion(dir, log) {
|
|
|
8982
9224
|
|
|
8983
9225
|
// src/plugin/portInventory.ts
|
|
8984
9226
|
function detectEngine(dir) {
|
|
8985
|
-
if (
|
|
8986
|
-
const pkg =
|
|
8987
|
-
if (
|
|
9227
|
+
if (existsSync17(join19(dir, "hyperframes.json"))) return "hyperframes";
|
|
9228
|
+
const pkg = join19(dir, "package.json");
|
|
9229
|
+
if (existsSync17(pkg)) {
|
|
8988
9230
|
try {
|
|
8989
|
-
const p = JSON.parse(
|
|
9231
|
+
const p = JSON.parse(readFileSync7(pkg, "utf8"));
|
|
8990
9232
|
const deps = { ...p.dependencies ?? {}, ...p.devDependencies ?? {} };
|
|
8991
9233
|
if ("remotion" in deps) return "remotion";
|
|
8992
9234
|
if ("hyperframes" in deps) return "hyperframes";
|
|
@@ -8998,14 +9240,14 @@ function detectEngine(dir) {
|
|
|
8998
9240
|
return "page";
|
|
8999
9241
|
}
|
|
9000
9242
|
function sourcePage(source) {
|
|
9001
|
-
if (!
|
|
9243
|
+
if (!existsSync17(source)) return null;
|
|
9002
9244
|
if (statSync6(source).isFile()) return /\.html?$/i.test(source) ? source : null;
|
|
9003
|
-
const index =
|
|
9004
|
-
return
|
|
9245
|
+
const index = join19(source, "index.html");
|
|
9246
|
+
return existsSync17(index) ? index : null;
|
|
9005
9247
|
}
|
|
9006
9248
|
function findRender(dir) {
|
|
9007
|
-
const videos = (d) =>
|
|
9008
|
-
for (const d of [
|
|
9249
|
+
const videos = (d) => existsSync17(d) ? readdirSync4(d).filter((f) => /\.(mp4|webm|mov)$/i.test(f)).map((f) => join19(d, f)) : [];
|
|
9250
|
+
for (const d of [join19(dir, "renders"), join19(dir, "out"), dir]) {
|
|
9009
9251
|
const found = videos(d);
|
|
9010
9252
|
if (found.length) return found[0];
|
|
9011
9253
|
}
|
|
@@ -9276,7 +9518,7 @@ var SEEK_AND_READ = `((args) => {
|
|
|
9276
9518
|
})`;
|
|
9277
9519
|
async function readInventory(source, opts) {
|
|
9278
9520
|
const abs = resolve7(source);
|
|
9279
|
-
const dir =
|
|
9521
|
+
const dir = existsSync17(abs) && statSync6(abs).isDirectory() ? abs : dirname5(abs);
|
|
9280
9522
|
const engine = detectEngine(dir);
|
|
9281
9523
|
const page = sourcePage(abs);
|
|
9282
9524
|
const render = opts.render === void 0 ? findRender(dir) : opts.render;
|
|
@@ -9379,7 +9621,7 @@ async function readInventory(source, opts) {
|
|
|
9379
9621
|
if (render && duration) {
|
|
9380
9622
|
const has = spawnSync2("ffmpeg", ["-version"]).status === 0;
|
|
9381
9623
|
if (has) {
|
|
9382
|
-
const refDir =
|
|
9624
|
+
const refDir = join19(opts.outDir, "ref");
|
|
9383
9625
|
mkdirSync3(refDir, { recursive: true });
|
|
9384
9626
|
const times = read.scenes.length >= 3 ? read.scenes.map(
|
|
9385
9627
|
(s) => s.start + (s.duration ?? 1) / 2
|
|
@@ -9388,7 +9630,7 @@ async function readInventory(source, opts) {
|
|
|
9388
9630
|
(_, i) => i + 0.5
|
|
9389
9631
|
);
|
|
9390
9632
|
for (const t of times.filter((t2) => t2 < duration)) {
|
|
9391
|
-
const file =
|
|
9633
|
+
const file = join19(refDir, `src-${t.toFixed(2)}.png`);
|
|
9392
9634
|
const ok = spawnSync2("ffmpeg", [
|
|
9393
9635
|
"-v",
|
|
9394
9636
|
"error",
|
|
@@ -9442,8 +9684,8 @@ async function readInventory(source, opts) {
|
|
|
9442
9684
|
|
|
9443
9685
|
// src/plugin/portScaffold.ts
|
|
9444
9686
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
9445
|
-
import { copyFileSync, existsSync as
|
|
9446
|
-
import { basename as basename7, dirname as dirname6, join as
|
|
9687
|
+
import { copyFileSync, existsSync as existsSync18, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
9688
|
+
import { basename as basename7, dirname as dirname6, join as join20, resolve as resolve8 } from "path";
|
|
9447
9689
|
import { findFontFamily as findFontFamily4, fontFaceUrl, nearestFontWeight } from "@vosjs/shared";
|
|
9448
9690
|
|
|
9449
9691
|
// src/plugin/painterLib.ts
|
|
@@ -9854,7 +10096,7 @@ function planScaffold(inv, opts) {
|
|
|
9854
10096
|
inv.media.filter((m) => m.kind === "audio" && m.src).forEach((m, i) => {
|
|
9855
10097
|
const from = resolve8(opts.sourceDir, m.src);
|
|
9856
10098
|
const name = basename7(from);
|
|
9857
|
-
if (!
|
|
10099
|
+
if (!existsSync18(from)) {
|
|
9858
10100
|
report.push(
|
|
9859
10101
|
`- the audio ${m.src} is not in the source folder; add it to doc.json by hand`
|
|
9860
10102
|
);
|
|
@@ -10052,13 +10294,13 @@ function reportText(inv, r) {
|
|
|
10052
10294
|
}
|
|
10053
10295
|
function writeScaffold(plan, outDir) {
|
|
10054
10296
|
mkdirSync4(outDir, { recursive: true });
|
|
10055
|
-
writeFileSync4(
|
|
10297
|
+
writeFileSync4(join20(outDir, "program.mjs"), plan.program);
|
|
10056
10298
|
writeFileSync4(
|
|
10057
|
-
|
|
10299
|
+
join20(outDir, "doc.json"),
|
|
10058
10300
|
JSON.stringify(plan.doc, null, 2) + "\n"
|
|
10059
10301
|
);
|
|
10060
|
-
writeFileSync4(
|
|
10061
|
-
for (const [from, name] of plan.copies) copyFileSync(from,
|
|
10302
|
+
writeFileSync4(join20(dirname6(outDir), "REPORT.md"), plan.report);
|
|
10303
|
+
for (const [from, name] of plan.copies) copyFileSync(from, join20(outDir, name));
|
|
10062
10304
|
}
|
|
10063
10305
|
function probeAudioDuration(file) {
|
|
10064
10306
|
const res = spawnSync3(
|
|
@@ -10092,7 +10334,7 @@ async function inventory(argv) {
|
|
|
10092
10334
|
outDir,
|
|
10093
10335
|
log: (l) => r.log(`note: ${l}`)
|
|
10094
10336
|
});
|
|
10095
|
-
const file =
|
|
10337
|
+
const file = join21(outDir, "inventory.json");
|
|
10096
10338
|
writeFileSync5(file, JSON.stringify(inv, null, 2) + "\n");
|
|
10097
10339
|
const missing = inv.fonts.filter((f) => !f.catalog).map((f) => f.family);
|
|
10098
10340
|
r.log(
|
|
@@ -10124,32 +10366,32 @@ function summary(inv) {
|
|
|
10124
10366
|
async function scaffold(argv) {
|
|
10125
10367
|
const { flags } = parseArgs(argv, BOOLEAN_FLAGS8);
|
|
10126
10368
|
const r = createReporter(flags.json === true);
|
|
10127
|
-
const from = resolve9(strFlag(flags, "from") ??
|
|
10128
|
-
if (!
|
|
10369
|
+
const from = resolve9(strFlag(flags, "from") ?? join21("port", "inventory.json"));
|
|
10370
|
+
if (!existsSync19(from))
|
|
10129
10371
|
throw new UsageError(
|
|
10130
10372
|
`no inventory at ${from}: run npx vos port inventory <source> first`
|
|
10131
10373
|
);
|
|
10132
|
-
const inv = JSON.parse(
|
|
10374
|
+
const inv = JSON.parse(readFileSync8(from, "utf8"));
|
|
10133
10375
|
const outDir = resolve9(
|
|
10134
|
-
strFlag(flags, "out") ??
|
|
10376
|
+
strFlag(flags, "out") ?? join21(dirname7(from), "program")
|
|
10135
10377
|
);
|
|
10136
10378
|
const plan = planScaffold(inv, {
|
|
10137
10379
|
sourceDir: scaffoldSourceDir(inv),
|
|
10138
10380
|
probeDuration: probeAudioDuration
|
|
10139
10381
|
});
|
|
10140
10382
|
writeScaffold(plan, outDir);
|
|
10141
|
-
const programFile =
|
|
10383
|
+
const programFile = join21(outDir, "program.mjs");
|
|
10142
10384
|
const mod = await import(`${pathToFileURL3(programFile).href}?t=${Date.now()}`);
|
|
10143
10385
|
const built = buildProgram(mod.default, "program.mjs", plan.program);
|
|
10144
10386
|
for (const p of built.problems) r.log(`error ${p.fn}: ${p.message}`);
|
|
10145
10387
|
if (built.problems.length) return EXIT_ERROR;
|
|
10146
10388
|
writeFileSync5(
|
|
10147
|
-
|
|
10389
|
+
join21(outDir, "config.json"),
|
|
10148
10390
|
JSON.stringify(built.config, null, 2) + "\n"
|
|
10149
10391
|
);
|
|
10150
10392
|
r.done(
|
|
10151
|
-
{ program: outDir, report:
|
|
10152
|
-
`Wrote ${outDir}/program.mjs, config.json and doc.json, and ${
|
|
10393
|
+
{ program: outDir, report: join21(dirname7(outDir), "REPORT.md") },
|
|
10394
|
+
`Wrote ${outDir}/program.mjs, config.json and doc.json, and ${join21(dirname7(outDir), "REPORT.md")}. Translate the motion where it says TODO, then: npx vos build program.mjs && npx vos compare . --against <their render>`
|
|
10153
10395
|
);
|
|
10154
10396
|
return EXIT_OK;
|
|
10155
10397
|
}
|
|
@@ -10160,7 +10402,7 @@ function scaffoldSourceDir(inv) {
|
|
|
10160
10402
|
|
|
10161
10403
|
// src/plugin/recipe.ts
|
|
10162
10404
|
import { createHash as createHash3 } from "crypto";
|
|
10163
|
-
import { readFileSync as
|
|
10405
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
10164
10406
|
import { basename as basename8 } from "path";
|
|
10165
10407
|
var BOOLEAN_FLAGS9 = /* @__PURE__ */ new Set(["json", "help"]);
|
|
10166
10408
|
var USAGE = "vos recipe push <file.md> (--folder <folderId|slug> | --asset <assetId>)";
|
|
@@ -10180,7 +10422,7 @@ async function cmdPush2(argv) {
|
|
|
10180
10422
|
throw new UsageError(USAGE);
|
|
10181
10423
|
}
|
|
10182
10424
|
const filename = recipeFilename(file);
|
|
10183
|
-
const body =
|
|
10425
|
+
const body = readFileSync9(file);
|
|
10184
10426
|
const r = createReporter(flags.json === true);
|
|
10185
10427
|
const origin = platformOrigin({
|
|
10186
10428
|
origin: strFlag(flags, "origin"),
|
|
@@ -10246,7 +10488,7 @@ async function cmdRecipe(argv) {
|
|
|
10246
10488
|
}
|
|
10247
10489
|
|
|
10248
10490
|
// src/plugin/brand.ts
|
|
10249
|
-
import { writeFile as
|
|
10491
|
+
import { writeFile as writeFile10 } from "fs/promises";
|
|
10250
10492
|
import { resolve as resolve10 } from "path";
|
|
10251
10493
|
import { parseFrontmatter as parseFrontmatter2 } from "@vosjs/shared/frontmatter";
|
|
10252
10494
|
import { lookKindForGround } from "@vosjs/studio-core";
|
|
@@ -10600,7 +10842,7 @@ async function cmdBrand(argv) {
|
|
|
10600
10842
|
composition,
|
|
10601
10843
|
llms?.claim ?? design?.description ?? null
|
|
10602
10844
|
);
|
|
10603
|
-
await
|
|
10845
|
+
await writeFile10(out, md);
|
|
10604
10846
|
const k = composition.kit;
|
|
10605
10847
|
r.done(
|
|
10606
10848
|
{
|
|
@@ -10715,7 +10957,7 @@ async function recordHosted(input) {
|
|
|
10715
10957
|
}
|
|
10716
10958
|
|
|
10717
10959
|
// src/plugin/agentBrowser.ts
|
|
10718
|
-
import { writeFile as
|
|
10960
|
+
import { writeFile as writeFile11 } from "fs/promises";
|
|
10719
10961
|
import { resolve as resolve11 } from "path";
|
|
10720
10962
|
function parseAgentBrowserLog(text) {
|
|
10721
10963
|
const records = [];
|
|
@@ -11195,8 +11437,8 @@ async function cmdActions(argv) {
|
|
|
11195
11437
|
if (!m) throw new UsageError("--viewport expects WxH, e.g. 1280x720");
|
|
11196
11438
|
viewport = { width: Number(m[1]), height: Number(m[2]) };
|
|
11197
11439
|
}
|
|
11198
|
-
const { readFile:
|
|
11199
|
-
const text = await
|
|
11440
|
+
const { readFile: readFile14 } = await import("fs/promises");
|
|
11441
|
+
const text = await readFile14(resolve11(input), "utf8");
|
|
11200
11442
|
const { records, problems } = parseAgentBrowserLog(text);
|
|
11201
11443
|
for (const p of problems) r.log(` ${p}`);
|
|
11202
11444
|
const result = convertAgentBrowser(records, {
|
|
@@ -11213,7 +11455,7 @@ async function cmdActions(argv) {
|
|
|
11213
11455
|
);
|
|
11214
11456
|
return EXIT_ERROR;
|
|
11215
11457
|
}
|
|
11216
|
-
await
|
|
11458
|
+
await writeFile11(out, `${JSON.stringify(result.actions, null, 2)}
|
|
11217
11459
|
`);
|
|
11218
11460
|
r.done(
|
|
11219
11461
|
{ ok: true, out, url: result.actions.url ?? null, ...summary2(result) },
|
|
@@ -11233,9 +11475,9 @@ function summary2(result) {
|
|
|
11233
11475
|
}
|
|
11234
11476
|
async function cmdActionsScript(input, flags) {
|
|
11235
11477
|
const r = createReporter(flags.json === true);
|
|
11236
|
-
const { readFile:
|
|
11237
|
-
const { shotList, formatShotList } = await import("./shotList-
|
|
11238
|
-
const raw = JSON.parse(await
|
|
11478
|
+
const { readFile: readFile14 } = await import("fs/promises");
|
|
11479
|
+
const { shotList, formatShotList } = await import("./shotList-MAQVLZBY.js");
|
|
11480
|
+
const raw = JSON.parse(await readFile14(resolve11(input), "utf8"));
|
|
11239
11481
|
const errors = validateActions(raw);
|
|
11240
11482
|
if (errors.length) throw new UsageError(`${input}:
|
|
11241
11483
|
${errors.join("\n ")}`);
|
|
@@ -11245,9 +11487,9 @@ async function cmdActionsScript(input, flags) {
|
|
|
11245
11487
|
}
|
|
11246
11488
|
|
|
11247
11489
|
// src/plugin/ingest.ts
|
|
11248
|
-
import { existsSync as
|
|
11249
|
-
import { copyFile, mkdir as mkdir7, readFile as
|
|
11250
|
-
import { basename as basename9, join as
|
|
11490
|
+
import { existsSync as existsSync20 } from "fs";
|
|
11491
|
+
import { copyFile, mkdir as mkdir7, readFile as readFile12, stat as stat2 } from "fs/promises";
|
|
11492
|
+
import { basename as basename9, join as join22, resolve as resolve12 } from "path";
|
|
11251
11493
|
import { inflateRawSync } from "zlib";
|
|
11252
11494
|
import {
|
|
11253
11495
|
cursorFromPlaywrightTrace,
|
|
@@ -11335,7 +11577,7 @@ async function readTraceFile(path, offsetMs) {
|
|
|
11335
11577
|
);
|
|
11336
11578
|
}
|
|
11337
11579
|
if (kind === "zip") {
|
|
11338
|
-
const bytes = new Uint8Array(await
|
|
11580
|
+
const bytes = new Uint8Array(await readFile12(path));
|
|
11339
11581
|
const entry = playwrightTraceEntry(zipEntries(bytes));
|
|
11340
11582
|
if (!entry) {
|
|
11341
11583
|
throw new UsageError(
|
|
@@ -11348,7 +11590,7 @@ async function readTraceFile(path, offsetMs) {
|
|
|
11348
11590
|
);
|
|
11349
11591
|
return cursorFromPlaywrightTrace(text2, { offsetMs });
|
|
11350
11592
|
}
|
|
11351
|
-
const text = await
|
|
11593
|
+
const text = await readFile12(path, "utf8");
|
|
11352
11594
|
return cursorFromTrace(basename9(path), text, { offsetMs });
|
|
11353
11595
|
}
|
|
11354
11596
|
function parseViewport(v) {
|
|
@@ -11365,7 +11607,7 @@ async function cmdIngest(argv) {
|
|
|
11365
11607
|
"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]"
|
|
11366
11608
|
);
|
|
11367
11609
|
const videoPath = resolve12(source);
|
|
11368
|
-
if (!
|
|
11610
|
+
if (!existsSync20(videoPath)) throw new UsageError(`${source}: no such file`);
|
|
11369
11611
|
const r = createReporter(flags.json === true);
|
|
11370
11612
|
const outDir = resolve12(strFlag(flags, "out") ?? "take");
|
|
11371
11613
|
const offsetMs = numFlag(flags, "offset", 0);
|
|
@@ -11392,7 +11634,7 @@ async function cmdIngest(argv) {
|
|
|
11392
11634
|
trace = await readTraceFile(resolve12(cursorPath), offsetMs);
|
|
11393
11635
|
for (const n of trace.notes) r.log(`note: ${n}`);
|
|
11394
11636
|
}
|
|
11395
|
-
if (
|
|
11637
|
+
if (existsSync20(join22(outDir, "meta.json"))) {
|
|
11396
11638
|
const { prevDoc, kept } = await prepareReRecord(outDir);
|
|
11397
11639
|
r.log(
|
|
11398
11640
|
`note: re-ingesting into ${outDir}; kept ${kept.length ? kept.join(", ") : "nothing"}` + (prevDoc ? `; apply the previous cut with: vos plan ${outDir} --reuse` : "")
|
|
@@ -11400,7 +11642,7 @@ async function cmdIngest(argv) {
|
|
|
11400
11642
|
}
|
|
11401
11643
|
await mkdir7(outDir, { recursive: true });
|
|
11402
11644
|
const paths = await ensureTakeDir(outDir);
|
|
11403
|
-
const recording =
|
|
11645
|
+
const recording = join22(outDir, `recording.${probed.ext}`);
|
|
11404
11646
|
r.log("copying the recording\u2026");
|
|
11405
11647
|
const remuxed = await copyRecording(videoPath, recording, probed.ext);
|
|
11406
11648
|
const viewport = viewportFlag ?? trace?.viewport ?? {
|
|
@@ -11468,19 +11710,19 @@ async function cmdIngest(argv) {
|
|
|
11468
11710
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
11469
11711
|
import {
|
|
11470
11712
|
cpSync,
|
|
11471
|
-
existsSync as
|
|
11713
|
+
existsSync as existsSync22,
|
|
11472
11714
|
mkdirSync as mkdirSync6,
|
|
11473
|
-
readFileSync as
|
|
11715
|
+
readFileSync as readFileSync11,
|
|
11474
11716
|
rmSync as rmSync3,
|
|
11475
11717
|
writeFileSync as writeFileSync6
|
|
11476
11718
|
} from "fs";
|
|
11477
11719
|
import { homedir as homedir2 } from "os";
|
|
11478
|
-
import { join as
|
|
11720
|
+
import { join as join24 } from "path";
|
|
11479
11721
|
import { chromium as chromium2 } from "playwright";
|
|
11480
11722
|
|
|
11481
11723
|
// src/plugin/machine.ts
|
|
11482
|
-
import { existsSync as
|
|
11483
|
-
import { dirname as dirname8, join as
|
|
11724
|
+
import { existsSync as existsSync21, readFileSync as readFileSync10, readdirSync as readdirSync5, statSync as statSync7 } from "fs";
|
|
11725
|
+
import { dirname as dirname8, join as join23 } from "path";
|
|
11484
11726
|
var AGENT_NAMES = [
|
|
11485
11727
|
"claude",
|
|
11486
11728
|
"cursor",
|
|
@@ -11500,17 +11742,17 @@ var HOME_DIRS = {
|
|
|
11500
11742
|
copilot: [".copilot"]
|
|
11501
11743
|
};
|
|
11502
11744
|
function detectAgents(root, opts = {}) {
|
|
11503
|
-
const exists = opts.exists ??
|
|
11745
|
+
const exists = opts.exists ?? existsSync21;
|
|
11504
11746
|
const out = [];
|
|
11505
11747
|
for (const agent of AGENT_NAMES) {
|
|
11506
11748
|
for (const rel of PROJECT_DIRS[agent]) {
|
|
11507
|
-
const dir =
|
|
11749
|
+
const dir = join23(root, rel);
|
|
11508
11750
|
if (exists(dir)) out.push({ agent, dir, scope: "project" });
|
|
11509
11751
|
}
|
|
11510
|
-
if (agent === "copilot" && !out.some((h) => h.agent === "copilot") && exists(
|
|
11752
|
+
if (agent === "copilot" && !out.some((h) => h.agent === "copilot") && exists(join23(root, ".github", "copilot-instructions.md"))) {
|
|
11511
11753
|
out.push({
|
|
11512
11754
|
agent,
|
|
11513
|
-
dir:
|
|
11755
|
+
dir: join23(root, ".github", "copilot"),
|
|
11514
11756
|
scope: "project"
|
|
11515
11757
|
});
|
|
11516
11758
|
}
|
|
@@ -11518,7 +11760,7 @@ function detectAgents(root, opts = {}) {
|
|
|
11518
11760
|
if (opts.global && opts.home) {
|
|
11519
11761
|
for (const agent of AGENT_NAMES) {
|
|
11520
11762
|
for (const rel of HOME_DIRS[agent]) {
|
|
11521
|
-
const dir =
|
|
11763
|
+
const dir = join23(opts.home, rel);
|
|
11522
11764
|
if (exists(dir)) out.push({ agent, dir, scope: "global" });
|
|
11523
11765
|
}
|
|
11524
11766
|
}
|
|
@@ -11536,18 +11778,18 @@ function agentsFromFlag(value, root) {
|
|
|
11536
11778
|
return {
|
|
11537
11779
|
homes: wanted.map((agent) => ({
|
|
11538
11780
|
agent,
|
|
11539
|
-
dir:
|
|
11781
|
+
dir: join23(root, PROJECT_DIRS[agent][0]),
|
|
11540
11782
|
scope: "project"
|
|
11541
11783
|
}))
|
|
11542
11784
|
};
|
|
11543
11785
|
}
|
|
11544
11786
|
function skillsDirFor(home) {
|
|
11545
|
-
return
|
|
11787
|
+
return join23(home.dir, "skills");
|
|
11546
11788
|
}
|
|
11547
11789
|
function fallbackSkillsHome(root) {
|
|
11548
|
-
return { agent: "codex", dir:
|
|
11790
|
+
return { agent: "codex", dir: join23(root, ".agents"), scope: "project" };
|
|
11549
11791
|
}
|
|
11550
|
-
function installedSkills(dir, exists =
|
|
11792
|
+
function installedSkills(dir, exists = existsSync21, list = (p) => {
|
|
11551
11793
|
try {
|
|
11552
11794
|
return readdirSync5(p);
|
|
11553
11795
|
} catch {
|
|
@@ -11555,7 +11797,7 @@ function installedSkills(dir, exists = existsSync20, list = (p) => {
|
|
|
11555
11797
|
}
|
|
11556
11798
|
}) {
|
|
11557
11799
|
if (!exists(dir)) return [];
|
|
11558
|
-
return list(dir).filter((name) => exists(
|
|
11800
|
+
return list(dir).filter((name) => exists(join23(dir, name, "SKILL.md"))).sort();
|
|
11559
11801
|
}
|
|
11560
11802
|
var RULES_BEGIN = "<!-- vos:begin (written by vos setup; the block is replaced on the next run) -->";
|
|
11561
11803
|
var RULES_END = "<!-- vos:end -->";
|
|
@@ -11588,10 +11830,10 @@ ${RULES_BLOCK}
|
|
|
11588
11830
|
}
|
|
11589
11831
|
return { text, changed: text !== current };
|
|
11590
11832
|
}
|
|
11591
|
-
function rulesFileFor(root, exists =
|
|
11592
|
-
const agents =
|
|
11833
|
+
function rulesFileFor(root, exists = existsSync21) {
|
|
11834
|
+
const agents = join23(root, "AGENTS.md");
|
|
11593
11835
|
if (exists(agents)) return agents;
|
|
11594
|
-
const claude =
|
|
11836
|
+
const claude = join23(root, "CLAUDE.md");
|
|
11595
11837
|
if (exists(claude)) return claude;
|
|
11596
11838
|
return agents;
|
|
11597
11839
|
}
|
|
@@ -11600,14 +11842,14 @@ function chromeCandidates(platform, env) {
|
|
|
11600
11842
|
return ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"];
|
|
11601
11843
|
if (platform === "win32")
|
|
11602
11844
|
return [
|
|
11603
|
-
|
|
11845
|
+
join23(
|
|
11604
11846
|
env["PROGRAMFILES"] ?? "C:\\Program Files",
|
|
11605
11847
|
"Google",
|
|
11606
11848
|
"Chrome",
|
|
11607
11849
|
"Application",
|
|
11608
11850
|
"chrome.exe"
|
|
11609
11851
|
),
|
|
11610
|
-
|
|
11852
|
+
join23(
|
|
11611
11853
|
env["LOCALAPPDATA"] ?? "",
|
|
11612
11854
|
"Google",
|
|
11613
11855
|
"Chrome",
|
|
@@ -11694,13 +11936,13 @@ function doctorReport(facts) {
|
|
|
11694
11936
|
function bundledSkillsDir(from) {
|
|
11695
11937
|
let dir = dirname8(from);
|
|
11696
11938
|
for (let i = 0; i < 6; i++) {
|
|
11697
|
-
const pkg =
|
|
11698
|
-
if (
|
|
11939
|
+
const pkg = join23(dir, "package.json");
|
|
11940
|
+
if (existsSync21(pkg)) {
|
|
11699
11941
|
try {
|
|
11700
|
-
const name = JSON.parse(
|
|
11942
|
+
const name = JSON.parse(readFileSync10(pkg, "utf8")).name;
|
|
11701
11943
|
if (name === "@vosjs/cli") {
|
|
11702
|
-
const skills =
|
|
11703
|
-
return
|
|
11944
|
+
const skills = join23(dir, "skills");
|
|
11945
|
+
return existsSync21(skills) && statSync7(skills).isDirectory() ? skills : null;
|
|
11704
11946
|
}
|
|
11705
11947
|
} catch {
|
|
11706
11948
|
}
|
|
@@ -11731,7 +11973,7 @@ function npx() {
|
|
|
11731
11973
|
function bundledChromium() {
|
|
11732
11974
|
try {
|
|
11733
11975
|
const p = chromium2.executablePath();
|
|
11734
|
-
return p &&
|
|
11976
|
+
return p && existsSync22(p) ? p : null;
|
|
11735
11977
|
} catch {
|
|
11736
11978
|
return null;
|
|
11737
11979
|
}
|
|
@@ -11740,7 +11982,7 @@ function probe2() {
|
|
|
11740
11982
|
return probeBrowser({
|
|
11741
11983
|
platform: process.platform,
|
|
11742
11984
|
env: process.env,
|
|
11743
|
-
exists:
|
|
11985
|
+
exists: existsSync22,
|
|
11744
11986
|
bundled: bundledChromium
|
|
11745
11987
|
});
|
|
11746
11988
|
}
|
|
@@ -11844,7 +12086,7 @@ async function cmdSetup(argv) {
|
|
|
11844
12086
|
const dest = skillsDirFor(home);
|
|
11845
12087
|
mkdirSync6(dest, { recursive: true });
|
|
11846
12088
|
for (const name of installedSkills(bundled)) {
|
|
11847
|
-
cpSync(
|
|
12089
|
+
cpSync(join24(bundled, name), join24(dest, name), { recursive: true });
|
|
11848
12090
|
}
|
|
11849
12091
|
}
|
|
11850
12092
|
skillsVia = "bundled";
|
|
@@ -11879,7 +12121,7 @@ async function cmdSetup(argv) {
|
|
|
11879
12121
|
let rules = null;
|
|
11880
12122
|
if (!noRules) {
|
|
11881
12123
|
const file = rulesFileFor(root);
|
|
11882
|
-
const existing =
|
|
12124
|
+
const existing = existsSync22(file) ? readFileSync11(file, "utf8") : null;
|
|
11883
12125
|
const { text, changed } = applyRulesBlock(existing);
|
|
11884
12126
|
if (changed) writeFileSync6(file, text);
|
|
11885
12127
|
rules = { file, changed };
|
|
@@ -11993,7 +12235,7 @@ async function cmdWhoami(argv) {
|
|
|
11993
12235
|
function cmdLogout(argv) {
|
|
11994
12236
|
const { flags } = parseArgs(argv, BOOLEAN_FLAGS11);
|
|
11995
12237
|
const r = reporterFor(flags);
|
|
11996
|
-
const had =
|
|
12238
|
+
const had = existsSync22(CREDENTIALS_PATH);
|
|
11997
12239
|
rmSync3(CREDENTIALS_PATH, { force: true });
|
|
11998
12240
|
const envKey = Boolean(process.env.VOS_API_KEY?.trim());
|
|
11999
12241
|
r.done(
|
|
@@ -12199,12 +12441,16 @@ The re-render loop (re-recording the same script after the product
|
|
|
12199
12441
|
changed): record into the SAME take dir \u2014 footage/cursor/meta are
|
|
12200
12442
|
replaced, the cut survives as doc.prev.json \u2014 then plan --reuse re-times
|
|
12201
12443
|
it onto the new recording. meta.json carries steps (when each actions
|
|
12202
|
-
step ran); a span
|
|
12203
|
-
|
|
12204
|
-
|
|
12205
|
-
|
|
12206
|
-
|
|
12207
|
-
|
|
12444
|
+
step ran); a human span follows the step it was made on (its window, or
|
|
12445
|
+
the gesture just before it), keeping its offset exactly, or an explicit
|
|
12446
|
+
anchor {step, at, offset}; a span between steps maps piecewise through
|
|
12447
|
+
matched step edges; a span whose step vanished is dropped and named with
|
|
12448
|
+
what it framed; autos re-plan; a layer pinned to a step follows its new
|
|
12449
|
+
output time, every other layer and audio keep OUTPUT times, and a layer
|
|
12450
|
+
over a step that moved is named with the pin to write. The done event's
|
|
12451
|
+
reuse block NAMES whatever could not follow \u2014 fix by exception, never
|
|
12452
|
+
re-cut from scratch. Give steps ids in actions.json so re-timing survives
|
|
12453
|
+
script edits.
|
|
12208
12454
|
|
|
12209
12455
|
record --strict exits 2 when any selector was skipped, the page never
|
|
12210
12456
|
reached networkidle, or the take hit --max-duration (the done event lists
|
|
@@ -12328,7 +12574,7 @@ lint-gated, so a bad override fails like a bad doc.json):
|
|
|
12328
12574
|
first ready loop (the house backdrop the studio opens on), or a flat ground offline
|
|
12329
12575
|
`;
|
|
12330
12576
|
async function loadActions(file) {
|
|
12331
|
-
const raw = JSON.parse(await
|
|
12577
|
+
const raw = JSON.parse(await readFile13(file, "utf8"));
|
|
12332
12578
|
const errors = validateActions(raw);
|
|
12333
12579
|
if (errors.length)
|
|
12334
12580
|
throw new UsageError(`invalid actions file:
|
|
@@ -12391,7 +12637,7 @@ function takeStorageState(flags) {
|
|
|
12391
12637
|
const raw = strFlag(flags, "storage-state");
|
|
12392
12638
|
if (!raw) return void 0;
|
|
12393
12639
|
const path = resolve13(raw);
|
|
12394
|
-
if (!
|
|
12640
|
+
if (!existsSync23(path))
|
|
12395
12641
|
throw new UsageError(`--storage-state: no such file: ${path}`);
|
|
12396
12642
|
return path;
|
|
12397
12643
|
}
|
|
@@ -12404,7 +12650,7 @@ function takeSessionName(flags, storageState) {
|
|
|
12404
12650
|
throw new UsageError(
|
|
12405
12651
|
"--session and --storage-state are two doors to one take: a persistent profile cannot take a storage state. Pass one"
|
|
12406
12652
|
);
|
|
12407
|
-
if (!
|
|
12653
|
+
if (!existsSync23(sessionDir(name)))
|
|
12408
12654
|
throw new UsageError(
|
|
12409
12655
|
`no session "${name}". Make one: vos session open <url> --name ${name} (a Chrome window opens; sign in and close it)`
|
|
12410
12656
|
);
|
|
@@ -12627,7 +12873,7 @@ ${lines.join("\n")}
|
|
|
12627
12873
|
}
|
|
12628
12874
|
const paths = takePaths(outDir);
|
|
12629
12875
|
const prepare = async () => {
|
|
12630
|
-
if (
|
|
12876
|
+
if (existsSync23(join25(outDir, "meta.json"))) {
|
|
12631
12877
|
const { prevDoc, kept } = await prepareReRecord(outDir);
|
|
12632
12878
|
r.log(
|
|
12633
12879
|
`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" : "")
|
|
@@ -12692,7 +12938,7 @@ ${lines.join("\n")}
|
|
|
12692
12938
|
},
|
|
12693
12939
|
strictFail ? `STRICT: take recorded but incomplete \u2014 ${strictReason(rec)}; fix the flow and re-record.${skippedNote}${exposureNote(rec)}` : `Take ready: ${outDir}
|
|
12694
12940
|
${(rec.meta.durationMs / 1e3).toFixed(1)}s \xB7 ${rec.frames.length} frames \xB7 ${rec.events.length} cursor events \xB7 ${clicks} clicks \xB7 ${plan.doc.zoom.length} zoom spans planned \xB7 ${rec.freezePct}% frozen \xB7 ${rec.dead.pct}% dead${deadWarns(rec.dead) ? " \u26A0 " + deadLine(rec.dead) : ""}${skippedNote}
|
|
12695
|
-
Next: edit ${
|
|
12941
|
+
Next: edit ${join25(outDir, "doc.json")} (optional), then: vos render ${outDir}${exposureNote(rec)}`
|
|
12696
12942
|
);
|
|
12697
12943
|
return strictFail ? EXIT_USAGE : EXIT_OK;
|
|
12698
12944
|
} finally {
|
|
@@ -12718,7 +12964,7 @@ async function cmdCreate2(argv) {
|
|
|
12718
12964
|
throw new UsageError('no URL \u2014 set "url" in the actions file or pass --url');
|
|
12719
12965
|
const outDir = resolve13(strFlag(flags, "out") ?? "take");
|
|
12720
12966
|
const format = videoFormat(strFlag(flags, "format"), positionals[0]);
|
|
12721
|
-
const out = positionals[0] ??
|
|
12967
|
+
const out = positionals[0] ?? join25(outDir, `out.${format}`);
|
|
12722
12968
|
const parallel = numFlag(flags, "parallel", 1);
|
|
12723
12969
|
if (!Number.isInteger(parallel) || parallel < 1 || parallel > 16) {
|
|
12724
12970
|
throw new UsageError("--parallel expects an integer between 1 and 16");
|
|
@@ -12731,7 +12977,7 @@ async function cmdCreate2(argv) {
|
|
|
12731
12977
|
const headers = takeHeaders(multi);
|
|
12732
12978
|
const paths = takePaths(outDir);
|
|
12733
12979
|
const prepare = async () => {
|
|
12734
|
-
if (
|
|
12980
|
+
if (existsSync23(join25(outDir, "meta.json"))) {
|
|
12735
12981
|
const { prevDoc, kept } = await prepareReRecord(outDir);
|
|
12736
12982
|
r.log(
|
|
12737
12983
|
`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" : "")
|
|
@@ -12838,24 +13084,24 @@ async function cmdPlan(argv) {
|
|
|
12838
13084
|
);
|
|
12839
13085
|
const r = createReporter(flags.json === true);
|
|
12840
13086
|
if (flags.fresh === true) {
|
|
12841
|
-
await rm2(
|
|
13087
|
+
await rm2(join25(dir, "doc.json"), { force: true });
|
|
12842
13088
|
r.log("note: --fresh discarded the existing doc.json");
|
|
12843
13089
|
}
|
|
12844
13090
|
let reuse;
|
|
12845
13091
|
if (flags.reuse === true) {
|
|
12846
|
-
const from = resolve13(strFlag(flags, "from") ??
|
|
12847
|
-
if (!
|
|
13092
|
+
const from = resolve13(strFlag(flags, "from") ?? join25(dir, PREV_DOC_NAME));
|
|
13093
|
+
if (!existsSync23(from)) {
|
|
12848
13094
|
throw new UsageError(
|
|
12849
13095
|
`--reuse: ${from} does not exist \u2014 a re-record into this take writes doc.prev.json, or pass --from <doc.json>`
|
|
12850
13096
|
);
|
|
12851
13097
|
}
|
|
12852
13098
|
reuse = {
|
|
12853
13099
|
from,
|
|
12854
|
-
doc: JSON.parse(await
|
|
13100
|
+
doc: JSON.parse(await readFile13(from, "utf8"))
|
|
12855
13101
|
};
|
|
12856
13102
|
}
|
|
12857
13103
|
const style = await resolveStyleRef(flags);
|
|
12858
|
-
const hasDoc =
|
|
13104
|
+
const hasDoc = existsSync23(join25(dir, "doc.json"));
|
|
12859
13105
|
const backdrop = hasDoc ? null : await takeBackdrop(flags, r);
|
|
12860
13106
|
const release = await releaseInputs(dir, flags, r, multi.with ?? []);
|
|
12861
13107
|
const motionWanted = !hasDoc || flags.motion === true || flags.fresh === true;
|
|
@@ -12913,7 +13159,7 @@ async function cmdPlan(argv) {
|
|
|
12913
13159
|
...s.motion ? { motion: s.motion } : {},
|
|
12914
13160
|
...s.reuse ? { reuse: s.reuse } : {}
|
|
12915
13161
|
},
|
|
12916
|
-
`${s.reuse ? "Reused" : s.fresh ? "Planned" : "Refreshed"} ${
|
|
13162
|
+
`${s.reuse ? "Reused" : s.fresh ? "Planned" : "Refreshed"} ${join25(dir, "doc.json")}: ${s.zoomAuto} auto + ${s.zoomManual} manual zoom spans${s.cursorKept ? "" : " (cursor track dropped)"}${layoutLines}${motionLines}${reuseLines}`
|
|
12917
13163
|
);
|
|
12918
13164
|
return EXIT_OK;
|
|
12919
13165
|
}
|
|
@@ -13036,7 +13282,7 @@ async function cmdRender(argv) {
|
|
|
13036
13282
|
);
|
|
13037
13283
|
const r = createReporter(flags.json === true);
|
|
13038
13284
|
const format = videoFormat(strFlag(flags, "format"), positionals[1]);
|
|
13039
|
-
const out = positionals[1] ??
|
|
13285
|
+
const out = positionals[1] ?? join25(dir, `out.${format}`);
|
|
13040
13286
|
const parallel = numFlag(flags, "parallel", 1);
|
|
13041
13287
|
if (!Number.isInteger(parallel) || parallel < 1 || parallel > 16) {
|
|
13042
13288
|
throw new UsageError("--parallel expects an integer between 1 and 16");
|
|
@@ -13267,15 +13513,15 @@ async function resolveStyleRef(flags) {
|
|
|
13267
13513
|
}
|
|
13268
13514
|
async function resolveDocRef(ref, flags, what) {
|
|
13269
13515
|
const styleRef = ref;
|
|
13270
|
-
const file =
|
|
13516
|
+
const file = existsSync23(styleRef) ? resolve13(
|
|
13271
13517
|
styleRef,
|
|
13272
|
-
|
|
13518
|
+
existsSync23(join25(styleRef, "doc.json")) ? "doc.json" : ""
|
|
13273
13519
|
) : null;
|
|
13274
|
-
if (file &&
|
|
13520
|
+
if (file && existsSync23(file)) {
|
|
13275
13521
|
return {
|
|
13276
13522
|
from: file,
|
|
13277
13523
|
doc: migrateHostedDoc4(
|
|
13278
|
-
JSON.parse(await
|
|
13524
|
+
JSON.parse(await readFile13(file, "utf8"))
|
|
13279
13525
|
)
|
|
13280
13526
|
};
|
|
13281
13527
|
}
|
|
@@ -13327,7 +13573,7 @@ async function cmdDigest(argv) {
|
|
|
13327
13573
|
const take = await loadTake(dir);
|
|
13328
13574
|
if (!take.doc) throw new UsageError(`${dir} has no doc.json \u2014 run plan first`);
|
|
13329
13575
|
const transcriptPath = strFlag(flags, "transcript");
|
|
13330
|
-
const transcript = transcriptPath ? parseTranscript(JSON.parse(await
|
|
13576
|
+
const transcript = transcriptPath ? parseTranscript(JSON.parse(await readFile13(transcriptPath, "utf8"))) : null;
|
|
13331
13577
|
const style = await resolveStyleRef(flags);
|
|
13332
13578
|
const noFrames = flags["no-frames"] === true;
|
|
13333
13579
|
let browser = null;
|
|
@@ -13358,7 +13604,7 @@ async function cmdDigest(argv) {
|
|
|
13358
13604
|
kinds,
|
|
13359
13605
|
frames: d.images.full,
|
|
13360
13606
|
crops: d.images.crop,
|
|
13361
|
-
sheet: d.images.sheet ?
|
|
13607
|
+
sheet: d.images.sheet ? join25(result.outDir, d.images.sheet) : null,
|
|
13362
13608
|
scenes: kinds.scene ?? 0,
|
|
13363
13609
|
sourceDuration: d.take.sourceDuration,
|
|
13364
13610
|
outputDuration: d.take.outputDuration,
|
|
@@ -13386,7 +13632,7 @@ async function cmdOpen(argv) {
|
|
|
13386
13632
|
if (!dir) throw new UsageError("vos open <take> [--studio <url>]");
|
|
13387
13633
|
const r = createReporter(flags.json === true);
|
|
13388
13634
|
const take = await loadTake(dir);
|
|
13389
|
-
if (!
|
|
13635
|
+
if (!existsSync23(take.paths.recording)) {
|
|
13390
13636
|
throw new UsageError(`${dir} has no recording \u2014 re-run record`);
|
|
13391
13637
|
}
|
|
13392
13638
|
const studio = (strFlag(flags, "studio") ?? platformOrigin()).replace(
|
|
@@ -13443,7 +13689,7 @@ async function cmdCallout(argv) {
|
|
|
13443
13689
|
`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`
|
|
13444
13690
|
);
|
|
13445
13691
|
const codeFile = strFlag(flags, "code-file");
|
|
13446
|
-
const code = codeFile ? await
|
|
13692
|
+
const code = codeFile ? await readFile13(codeFile, "utf8") : strFlag(flags, "code");
|
|
13447
13693
|
const words2 = {
|
|
13448
13694
|
kicker: strFlag(flags, "kicker"),
|
|
13449
13695
|
title: strFlag(flags, "title"),
|
|
@@ -13522,7 +13768,7 @@ async function cmdValidate(argv) {
|
|
|
13522
13768
|
const target = positionals[0];
|
|
13523
13769
|
if (!target) throw new UsageError("vos validate <actions.json|take>");
|
|
13524
13770
|
const r = createReporter(flags.json === true);
|
|
13525
|
-
const kitTarget = target.endsWith("kit.json") ? target :
|
|
13771
|
+
const kitTarget = target.endsWith("kit.json") ? target : existsSync23(join25(target, "kit.json")) && !isTakeDir(target) ? join25(target, "kit.json") : null;
|
|
13526
13772
|
if (kitTarget) {
|
|
13527
13773
|
const picture = flags.picture === true;
|
|
13528
13774
|
const verdict = await validateKit(kitTarget, { picture });
|
|
@@ -13554,9 +13800,9 @@ async function cmdValidate(argv) {
|
|
|
13554
13800
|
r.done({ valid: true, target }, `${target}: valid actions file`);
|
|
13555
13801
|
return EXIT_OK;
|
|
13556
13802
|
}
|
|
13557
|
-
if (!isTakeDir(target) &&
|
|
13803
|
+
if (!isTakeDir(target) && existsSync23(join25(target, "config.json"))) {
|
|
13558
13804
|
const parsed = JSON.parse(
|
|
13559
|
-
await
|
|
13805
|
+
await readFile13(join25(target, "config.json"), "utf8")
|
|
13560
13806
|
);
|
|
13561
13807
|
const pre = preflightConfig(parsed);
|
|
13562
13808
|
const problems2 = pre.ok ? [] : pre.issues.map((i) => `config.json: ${i}`);
|
|
@@ -13597,7 +13843,7 @@ async function cmdValidate(argv) {
|
|
|
13597
13843
|
const take = await loadTake(target);
|
|
13598
13844
|
const problems = [];
|
|
13599
13845
|
const warnings = [];
|
|
13600
|
-
if (!
|
|
13846
|
+
if (!existsSync23(take.paths.recording)) {
|
|
13601
13847
|
problems.push("missing recording (re-run record)");
|
|
13602
13848
|
} else {
|
|
13603
13849
|
const mismatch = containerMismatch(
|
|
@@ -13982,7 +14228,7 @@ async function cmdSession(argv) {
|
|
|
13982
14228
|
if (!arg) throw new UsageError(usage);
|
|
13983
14229
|
const bad = sessionNameVerdict(arg);
|
|
13984
14230
|
if (bad) throw new UsageError(bad);
|
|
13985
|
-
if (!
|
|
14231
|
+
if (!existsSync23(sessionDir(arg)))
|
|
13986
14232
|
throw new UsageError(`no session "${arg}" (vos session list)`);
|
|
13987
14233
|
const summary3 = await summarizeSession(arg);
|
|
13988
14234
|
const url = strFlag(flags, "url");
|
|
@@ -14082,4 +14328,4 @@ export {
|
|
|
14082
14328
|
verbHelp,
|
|
14083
14329
|
run
|
|
14084
14330
|
};
|
|
14085
|
-
//# sourceMappingURL=chunk-
|
|
14331
|
+
//# sourceMappingURL=chunk-XB5XRE4Q.js.map
|