@vosjs/cli 0.47.0 → 0.48.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 +15 -5
- package/dist/{chunk-E42NCNWP.js → chunk-ANKECV7F.js} +634 -56
- package/dist/chunk-ANKECV7F.js.map +1 -0
- package/dist/{chunk-EFI3WUQB.js → chunk-P3X5KVA6.js} +15 -2
- package/dist/{chunk-EFI3WUQB.js.map → chunk-P3X5KVA6.js.map} +1 -1
- package/dist/cli.js +4 -4
- package/dist/index.js +2 -2
- package/dist/manifest-A4R367EM.js +8 -0
- package/dist/{run-DA5QXZ6F.js → run-CYHH56KA.js} +2 -2
- package/package.json +8 -6
- package/skills/VERSION +1 -0
- package/skills/launch-kit/SKILL.md +356 -0
- package/skills/launch-kit/references/channel-specs.md +56 -0
- package/skills/product-video/SKILL.md +263 -0
- package/skills/product-video/references/destinations.md +71 -0
- package/skills/product-video/references/sessions.md +226 -0
- package/skills/product-video/references/taste.md +115 -0
- package/skills/product-video/references/troubleshooting.md +116 -0
- package/skills/vos-authoring/SKILL.md +191 -0
- package/skills/vos-authoring/references/examples.md +239 -0
- package/skills/vos-authoring/references/schema-reference.md +468 -0
- package/skills/vos-create/SKILL.md +258 -0
- package/skills/vos-cut/SKILL.md +241 -0
- package/skills/vos-footage/SKILL.md +98 -0
- package/skills/vos-migrate/SKILL.md +108 -0
- package/skills/vos-remix/SKILL.md +136 -0
- package/skills/vos-remix/references/3d-recipe.md +37 -0
- package/skills/vos-remix/references/params-knobs.md +80 -0
- package/skills/vos-remix/references/remix-contract.md +81 -0
- package/dist/chunk-E42NCNWP.js.map +0 -1
- package/dist/manifest-UCS6OVWZ.js +0 -8
- /package/dist/{manifest-UCS6OVWZ.js.map → manifest-A4R367EM.js.map} +0 -0
- /package/dist/{run-DA5QXZ6F.js.map → run-CYHH56KA.js.map} +0 -0
|
@@ -27,8 +27,8 @@ import {
|
|
|
27
27
|
|
|
28
28
|
// src/plugin/run.ts
|
|
29
29
|
import { mkdir as mkdir10, readFile as readFile15, rm as rm5 } from "fs/promises";
|
|
30
|
-
import { existsSync as
|
|
31
|
-
import { join as
|
|
30
|
+
import { existsSync as existsSync18 } from "fs";
|
|
31
|
+
import { join as join21, resolve as resolve9 } from "path";
|
|
32
32
|
import {
|
|
33
33
|
END_CARD_FROM as END_CARD_FROM2,
|
|
34
34
|
docOutputDuration as docOutputDuration3,
|
|
@@ -2393,6 +2393,16 @@ function startTakeServer(rootDir, pages) {
|
|
|
2393
2393
|
const server = createServer((req, res) => {
|
|
2394
2394
|
const url = new URL(req.url ?? "/", "http://x");
|
|
2395
2395
|
res.setHeader("access-control-allow-origin", "*");
|
|
2396
|
+
res.setHeader("access-control-allow-private-network", "true");
|
|
2397
|
+
if (req.method === "OPTIONS") {
|
|
2398
|
+
res.writeHead(204, {
|
|
2399
|
+
"access-control-allow-methods": "GET, POST, OPTIONS",
|
|
2400
|
+
"access-control-allow-headers": "*",
|
|
2401
|
+
"access-control-max-age": "600"
|
|
2402
|
+
});
|
|
2403
|
+
res.end();
|
|
2404
|
+
return;
|
|
2405
|
+
}
|
|
2396
2406
|
if (req.method === "POST" && url.pathname === "/save") {
|
|
2397
2407
|
const name = (url.searchParams.get("name") ?? "out.bin").replace(
|
|
2398
2408
|
/[^\w.-]/g,
|
|
@@ -5120,7 +5130,7 @@ async function pickStillTimes(browser, dir, doc, duration, opts) {
|
|
|
5120
5130
|
const vh = meta.captureHeight ?? meta.height;
|
|
5121
5131
|
const probeDir = await mkdtemp(join8(tmpdir(), "vos-moments-"));
|
|
5122
5132
|
try {
|
|
5123
|
-
const
|
|
5133
|
+
const probe2 = await framesTake(browser, dir, {
|
|
5124
5134
|
times: candidates.map((c) => c.time),
|
|
5125
5135
|
width: PROBE_WIDTH,
|
|
5126
5136
|
height: Math.max(2, Math.round(PROBE_WIDTH * vh / vw / 2) * 2),
|
|
@@ -5131,7 +5141,7 @@ async function pickStillTimes(browser, dir, doc, duration, opts) {
|
|
|
5131
5141
|
}
|
|
5132
5142
|
});
|
|
5133
5143
|
const byTime = /* @__PURE__ */ new Map();
|
|
5134
|
-
for (const frame of
|
|
5144
|
+
for (const frame of probe2.frames) {
|
|
5135
5145
|
const img = decodePng(new Uint8Array(await readFile6(frame.file)));
|
|
5136
5146
|
if (!img) continue;
|
|
5137
5147
|
const whole = { x: 0, y: 0, w: img.w, h: img.h };
|
|
@@ -9623,9 +9633,9 @@ async function cmdLogin(argv) {
|
|
|
9623
9633
|
return storeKey(key, origin, r);
|
|
9624
9634
|
}
|
|
9625
9635
|
async function storeKey(key, origin, r) {
|
|
9626
|
-
const
|
|
9627
|
-
if (
|
|
9628
|
-
throw new Error(apiError("validate key",
|
|
9636
|
+
const probe2 = await apiJson(origin, "/api/folders", { key });
|
|
9637
|
+
if (probe2.status === 401 || probe2.status === 403) {
|
|
9638
|
+
throw new Error(apiError("validate key", probe2));
|
|
9629
9639
|
}
|
|
9630
9640
|
const path = writeCredential(key);
|
|
9631
9641
|
r.done(
|
|
@@ -10764,8 +10774,551 @@ async function cmdActionsScript(input, flags) {
|
|
|
10764
10774
|
return EXIT_OK;
|
|
10765
10775
|
}
|
|
10766
10776
|
|
|
10767
|
-
// src/plugin/
|
|
10777
|
+
// src/plugin/machineCmd.ts
|
|
10778
|
+
import { spawnSync } from "child_process";
|
|
10779
|
+
import {
|
|
10780
|
+
cpSync,
|
|
10781
|
+
existsSync as existsSync17,
|
|
10782
|
+
mkdirSync as mkdirSync3,
|
|
10783
|
+
readFileSync as readFileSync8,
|
|
10784
|
+
rmSync as rmSync2,
|
|
10785
|
+
writeFileSync as writeFileSync3
|
|
10786
|
+
} from "fs";
|
|
10787
|
+
import { homedir as homedir3 } from "os";
|
|
10788
|
+
import { join as join20 } from "path";
|
|
10789
|
+
import { chromium as chromium2 } from "playwright";
|
|
10790
|
+
|
|
10791
|
+
// src/plugin/machine.ts
|
|
10792
|
+
import { existsSync as existsSync16, readFileSync as readFileSync7, readdirSync as readdirSync4, statSync as statSync4 } from "fs";
|
|
10793
|
+
import { dirname as dirname5, join as join19 } from "path";
|
|
10794
|
+
var AGENT_NAMES = [
|
|
10795
|
+
"claude",
|
|
10796
|
+
"cursor",
|
|
10797
|
+
"codex",
|
|
10798
|
+
"copilot"
|
|
10799
|
+
];
|
|
10800
|
+
var PROJECT_DIRS = {
|
|
10801
|
+
claude: [".claude"],
|
|
10802
|
+
cursor: [".cursor"],
|
|
10803
|
+
codex: [".codex", ".agents"],
|
|
10804
|
+
copilot: [".github/copilot"]
|
|
10805
|
+
};
|
|
10806
|
+
var HOME_DIRS = {
|
|
10807
|
+
claude: [".claude"],
|
|
10808
|
+
cursor: [".cursor"],
|
|
10809
|
+
codex: [".codex", ".agents"],
|
|
10810
|
+
copilot: [".copilot"]
|
|
10811
|
+
};
|
|
10812
|
+
function detectAgents(root, opts = {}) {
|
|
10813
|
+
const exists = opts.exists ?? existsSync16;
|
|
10814
|
+
const out = [];
|
|
10815
|
+
for (const agent of AGENT_NAMES) {
|
|
10816
|
+
for (const rel of PROJECT_DIRS[agent]) {
|
|
10817
|
+
const dir = join19(root, rel);
|
|
10818
|
+
if (exists(dir)) out.push({ agent, dir, scope: "project" });
|
|
10819
|
+
}
|
|
10820
|
+
if (agent === "copilot" && !out.some((h) => h.agent === "copilot") && exists(join19(root, ".github", "copilot-instructions.md"))) {
|
|
10821
|
+
out.push({
|
|
10822
|
+
agent,
|
|
10823
|
+
dir: join19(root, ".github", "copilot"),
|
|
10824
|
+
scope: "project"
|
|
10825
|
+
});
|
|
10826
|
+
}
|
|
10827
|
+
}
|
|
10828
|
+
if (opts.global && opts.home) {
|
|
10829
|
+
for (const agent of AGENT_NAMES) {
|
|
10830
|
+
for (const rel of HOME_DIRS[agent]) {
|
|
10831
|
+
const dir = join19(opts.home, rel);
|
|
10832
|
+
if (exists(dir)) out.push({ agent, dir, scope: "global" });
|
|
10833
|
+
}
|
|
10834
|
+
}
|
|
10835
|
+
}
|
|
10836
|
+
return out;
|
|
10837
|
+
}
|
|
10838
|
+
function agentsFromFlag(value, root) {
|
|
10839
|
+
const wanted = value.trim() === "all" ? [...AGENT_NAMES] : value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
10840
|
+
const bad = wanted.filter((w) => !AGENT_NAMES.includes(w));
|
|
10841
|
+
if (bad.length)
|
|
10842
|
+
return {
|
|
10843
|
+
error: `--agent takes ${AGENT_NAMES.join(", ")} or all, not "${bad.join(", ")}"`
|
|
10844
|
+
};
|
|
10845
|
+
if (!wanted.length) return { error: "--agent expects a name" };
|
|
10846
|
+
return {
|
|
10847
|
+
homes: wanted.map((agent) => ({
|
|
10848
|
+
agent,
|
|
10849
|
+
dir: join19(root, PROJECT_DIRS[agent][0]),
|
|
10850
|
+
scope: "project"
|
|
10851
|
+
}))
|
|
10852
|
+
};
|
|
10853
|
+
}
|
|
10854
|
+
function skillsDirFor(home) {
|
|
10855
|
+
return join19(home.dir, "skills");
|
|
10856
|
+
}
|
|
10857
|
+
function fallbackSkillsHome(root) {
|
|
10858
|
+
return { agent: "codex", dir: join19(root, ".agents"), scope: "project" };
|
|
10859
|
+
}
|
|
10860
|
+
function installedSkills(dir, exists = existsSync16, list = (p) => {
|
|
10861
|
+
try {
|
|
10862
|
+
return readdirSync4(p);
|
|
10863
|
+
} catch {
|
|
10864
|
+
return [];
|
|
10865
|
+
}
|
|
10866
|
+
}) {
|
|
10867
|
+
if (!exists(dir)) return [];
|
|
10868
|
+
return list(dir).filter((name) => exists(join19(dir, name, "SKILL.md"))).sort();
|
|
10869
|
+
}
|
|
10870
|
+
var RULES_BEGIN = "<!-- vos:begin (written by vos setup; the block is replaced on the next run) -->";
|
|
10871
|
+
var RULES_END = "<!-- vos:end -->";
|
|
10872
|
+
var RULES_BODY = `## Product videos (vosso)
|
|
10873
|
+
- Skill: product-video (npx skills add vosjs/skills) records the real product from actions.json
|
|
10874
|
+
- Look before you cut: vos frames take --at-zooms; edit take/doc.json and re-render, never re-record
|
|
10875
|
+
- Hand back: vos open take serves the take into the studio at vos.so, doc.json intact
|
|
10876
|
+
- Local by default: vos push only when asked for a link, the shelf or a cloud render
|
|
10877
|
+
- Credentials: VOS_API_KEY, then ~/.config/vos/credentials, then vos login; never print one
|
|
10878
|
+
- Reference: https://vos.so/llms-full.txt`;
|
|
10879
|
+
var RULES_BLOCK = `${RULES_BEGIN}
|
|
10880
|
+
${RULES_BODY}
|
|
10881
|
+
${RULES_END}`;
|
|
10882
|
+
function applyRulesBlock(existing) {
|
|
10883
|
+
const current = existing ?? "";
|
|
10884
|
+
const begin = current.indexOf(RULES_BEGIN);
|
|
10885
|
+
const end = current.indexOf(RULES_END);
|
|
10886
|
+
let text;
|
|
10887
|
+
if (begin !== -1 && end !== -1 && end > begin) {
|
|
10888
|
+
text = current.slice(0, begin) + RULES_BLOCK + current.slice(end + RULES_END.length);
|
|
10889
|
+
} else if (current.trim() === "") {
|
|
10890
|
+
text = `${RULES_BLOCK}
|
|
10891
|
+
`;
|
|
10892
|
+
} else {
|
|
10893
|
+
text = `${current.replace(/\s*$/, "")}
|
|
10894
|
+
|
|
10895
|
+
${RULES_BLOCK}
|
|
10896
|
+
`;
|
|
10897
|
+
}
|
|
10898
|
+
return { text, changed: text !== current };
|
|
10899
|
+
}
|
|
10900
|
+
function rulesFileFor(root, exists = existsSync16) {
|
|
10901
|
+
const agents = join19(root, "AGENTS.md");
|
|
10902
|
+
if (exists(agents)) return agents;
|
|
10903
|
+
const claude = join19(root, "CLAUDE.md");
|
|
10904
|
+
if (exists(claude)) return claude;
|
|
10905
|
+
return agents;
|
|
10906
|
+
}
|
|
10907
|
+
function chromeCandidates(platform, env) {
|
|
10908
|
+
if (platform === "darwin")
|
|
10909
|
+
return ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"];
|
|
10910
|
+
if (platform === "win32")
|
|
10911
|
+
return [
|
|
10912
|
+
join19(
|
|
10913
|
+
env["PROGRAMFILES"] ?? "C:\\Program Files",
|
|
10914
|
+
"Google",
|
|
10915
|
+
"Chrome",
|
|
10916
|
+
"Application",
|
|
10917
|
+
"chrome.exe"
|
|
10918
|
+
),
|
|
10919
|
+
join19(
|
|
10920
|
+
env["LOCALAPPDATA"] ?? "",
|
|
10921
|
+
"Google",
|
|
10922
|
+
"Chrome",
|
|
10923
|
+
"Application",
|
|
10924
|
+
"chrome.exe"
|
|
10925
|
+
)
|
|
10926
|
+
];
|
|
10927
|
+
return [
|
|
10928
|
+
"/usr/bin/google-chrome",
|
|
10929
|
+
"/usr/bin/google-chrome-stable",
|
|
10930
|
+
"/opt/google/chrome/chrome"
|
|
10931
|
+
];
|
|
10932
|
+
}
|
|
10933
|
+
function probeBrowser(opts) {
|
|
10934
|
+
const explicit = opts.env.VOS_BROWSER_PATH?.trim();
|
|
10935
|
+
if (explicit) {
|
|
10936
|
+
return opts.exists(explicit) ? { kind: "env", path: explicit, line: `${explicit} (VOS_BROWSER_PATH)` } : {
|
|
10937
|
+
kind: "none",
|
|
10938
|
+
path: null,
|
|
10939
|
+
line: `VOS_BROWSER_PATH points at ${explicit}, which does not exist`
|
|
10940
|
+
};
|
|
10941
|
+
}
|
|
10942
|
+
const chrome = chromeCandidates(opts.platform, opts.env).find(opts.exists);
|
|
10943
|
+
if (chrome) return { kind: "chrome", path: chrome, line: "Chrome (system)" };
|
|
10944
|
+
const chromium3 = opts.bundled();
|
|
10945
|
+
if (chromium3)
|
|
10946
|
+
return { kind: "chromium", path: chromium3, line: "Chromium (Playwright)" };
|
|
10947
|
+
return {
|
|
10948
|
+
kind: "none",
|
|
10949
|
+
path: null,
|
|
10950
|
+
line: "none: install Google Chrome, or run npx playwright install chromium"
|
|
10951
|
+
};
|
|
10952
|
+
}
|
|
10953
|
+
var NODE_MIN_MAJOR = 18;
|
|
10954
|
+
function major(version) {
|
|
10955
|
+
return parseInt(version.split(".")[0] ?? "0", 10);
|
|
10956
|
+
}
|
|
10957
|
+
function doctorReport(facts) {
|
|
10958
|
+
const lines = [];
|
|
10959
|
+
const nodeOk = major(facts.node) >= NODE_MIN_MAJOR;
|
|
10960
|
+
lines.push(
|
|
10961
|
+
`node ${facts.node} ${nodeOk ? "\u2713" : `\u2717 ${NODE_MIN_MAJOR} or newer is needed`}`
|
|
10962
|
+
);
|
|
10963
|
+
const browserOk = facts.browser.kind !== "none";
|
|
10964
|
+
lines.push(`browser ${facts.browser.line} ${browserOk ? "\u2713" : "\u2717"}`);
|
|
10965
|
+
lines.push(
|
|
10966
|
+
`ffmpeg ${facts.ffmpeg ? `${facts.ffmpeg} \u2713` : "absent (optional)"}`
|
|
10967
|
+
);
|
|
10968
|
+
const withSkills = facts.skills.filter((s) => s.names.length);
|
|
10969
|
+
if (withSkills.length) {
|
|
10970
|
+
const names = [...new Set(withSkills.flatMap((s) => s.names))].sort();
|
|
10971
|
+
const agents = [
|
|
10972
|
+
...new Set(
|
|
10973
|
+
withSkills.map(
|
|
10974
|
+
(s) => s.scope === "global" ? `${s.agent} (global)` : s.agent
|
|
10975
|
+
)
|
|
10976
|
+
)
|
|
10977
|
+
];
|
|
10978
|
+
lines.push(`skills ${names.join(", ")} (${agents.join(", ")}) \u2713`);
|
|
10979
|
+
} else {
|
|
10980
|
+
lines.push("skills none \u2717 run: npx vos setup");
|
|
10981
|
+
}
|
|
10982
|
+
lines.push(
|
|
10983
|
+
`credential ${facts.credential ? "present \u2713" : "absent (vos login when you need hosting)"}`
|
|
10984
|
+
);
|
|
10985
|
+
if (facts.devServer) {
|
|
10986
|
+
const d = facts.devServer;
|
|
10987
|
+
lines.push(
|
|
10988
|
+
`dev server ${d.url} ${d.ok ? "answers \u2713" : `does not answer \u2717${d.error ? ` (${d.error})` : d.status ? ` (HTTP ${d.status})` : ""}`}`
|
|
10989
|
+
);
|
|
10990
|
+
}
|
|
10991
|
+
let next_step;
|
|
10992
|
+
if (!nodeOk)
|
|
10993
|
+
next_step = `Install Node ${NODE_MIN_MAJOR} or newer, then run npx vos doctor again`;
|
|
10994
|
+
else if (!browserOk)
|
|
10995
|
+
next_step = "Install Google Chrome, or run: npx playwright install chromium";
|
|
10996
|
+
else if (facts.devServer && !facts.devServer.ok)
|
|
10997
|
+
next_step = `Start the dev server so ${facts.devServer.url} answers, then record`;
|
|
10998
|
+
else if (!withSkills.length) next_step = "Run: npx vos setup";
|
|
10999
|
+
else
|
|
11000
|
+
next_step = "Record: npx vos record --actions actions.json --out take --strict (the product-video skill writes actions.json)";
|
|
11001
|
+
return { ok: nodeOk && browserOk, lines, next_step, facts };
|
|
11002
|
+
}
|
|
11003
|
+
function bundledSkillsDir(from) {
|
|
11004
|
+
let dir = dirname5(from);
|
|
11005
|
+
for (let i = 0; i < 6; i++) {
|
|
11006
|
+
const pkg = join19(dir, "package.json");
|
|
11007
|
+
if (existsSync16(pkg)) {
|
|
11008
|
+
try {
|
|
11009
|
+
const name = JSON.parse(readFileSync7(pkg, "utf8")).name;
|
|
11010
|
+
if (name === "@vosjs/cli") {
|
|
11011
|
+
const skills = join19(dir, "skills");
|
|
11012
|
+
return existsSync16(skills) && statSync4(skills).isDirectory() ? skills : null;
|
|
11013
|
+
}
|
|
11014
|
+
} catch {
|
|
11015
|
+
}
|
|
11016
|
+
}
|
|
11017
|
+
const up = dirname5(dir);
|
|
11018
|
+
if (up === dir) break;
|
|
11019
|
+
dir = up;
|
|
11020
|
+
}
|
|
11021
|
+
return null;
|
|
11022
|
+
}
|
|
11023
|
+
|
|
11024
|
+
// src/plugin/machineCmd.ts
|
|
10768
11025
|
var BOOLEAN_FLAGS5 = /* @__PURE__ */ new Set([
|
|
11026
|
+
"json",
|
|
11027
|
+
"help",
|
|
11028
|
+
"global",
|
|
11029
|
+
"no-skills",
|
|
11030
|
+
"no-rules",
|
|
11031
|
+
"no-browser"
|
|
11032
|
+
]);
|
|
11033
|
+
var SKILLS_SOURCE = "vosjs/skills";
|
|
11034
|
+
function reporterFor(flags) {
|
|
11035
|
+
return createReporter(flags.json === true || process.stdout.isTTY !== true);
|
|
11036
|
+
}
|
|
11037
|
+
function npx() {
|
|
11038
|
+
return process.platform === "win32" ? "npx.cmd" : "npx";
|
|
11039
|
+
}
|
|
11040
|
+
function bundledChromium() {
|
|
11041
|
+
try {
|
|
11042
|
+
const p = chromium2.executablePath();
|
|
11043
|
+
return p && existsSync17(p) ? p : null;
|
|
11044
|
+
} catch {
|
|
11045
|
+
return null;
|
|
11046
|
+
}
|
|
11047
|
+
}
|
|
11048
|
+
function probe() {
|
|
11049
|
+
return probeBrowser({
|
|
11050
|
+
platform: process.platform,
|
|
11051
|
+
env: process.env,
|
|
11052
|
+
exists: existsSync17,
|
|
11053
|
+
bundled: bundledChromium
|
|
11054
|
+
});
|
|
11055
|
+
}
|
|
11056
|
+
function ffmpegVersion() {
|
|
11057
|
+
const res = spawnSync("ffmpeg", ["-version"], { encoding: "utf8" });
|
|
11058
|
+
if (res.status !== 0 || !res.stdout) return null;
|
|
11059
|
+
const m = /ffmpeg version (\S+)/.exec(res.stdout);
|
|
11060
|
+
return m ? m[1] : "present";
|
|
11061
|
+
}
|
|
11062
|
+
async function devServerFact(url) {
|
|
11063
|
+
try {
|
|
11064
|
+
const res = await fetch(url, {
|
|
11065
|
+
signal: AbortSignal.timeout(2e3),
|
|
11066
|
+
redirect: "manual"
|
|
11067
|
+
});
|
|
11068
|
+
return { url, ok: res.status < 500, status: res.status };
|
|
11069
|
+
} catch (e) {
|
|
11070
|
+
return {
|
|
11071
|
+
url,
|
|
11072
|
+
ok: false,
|
|
11073
|
+
status: null,
|
|
11074
|
+
error: e instanceof Error ? e.message.split("\n")[0] : String(e)
|
|
11075
|
+
};
|
|
11076
|
+
}
|
|
11077
|
+
}
|
|
11078
|
+
function catalogNames() {
|
|
11079
|
+
const bundled = bundledSkillsDir(import.meta.url.replace("file://", ""));
|
|
11080
|
+
return bundled ? installedSkills(bundled) : null;
|
|
11081
|
+
}
|
|
11082
|
+
function skillsFacts(homes) {
|
|
11083
|
+
const ours = catalogNames();
|
|
11084
|
+
return homes.map((h) => ({
|
|
11085
|
+
agent: h.agent,
|
|
11086
|
+
scope: h.scope,
|
|
11087
|
+
names: installedSkills(skillsDirFor(h)).filter(
|
|
11088
|
+
(n) => !ours || ours.includes(n)
|
|
11089
|
+
)
|
|
11090
|
+
}));
|
|
11091
|
+
}
|
|
11092
|
+
async function doctorFacts(opts) {
|
|
11093
|
+
return {
|
|
11094
|
+
node: process.versions.node,
|
|
11095
|
+
browser: probe(),
|
|
11096
|
+
ffmpeg: ffmpegVersion(),
|
|
11097
|
+
skills: skillsFacts(opts.homes),
|
|
11098
|
+
credential: resolveCredential() !== null,
|
|
11099
|
+
...opts.url ? { devServer: await devServerFact(opts.url) } : {}
|
|
11100
|
+
};
|
|
11101
|
+
}
|
|
11102
|
+
async function cmdSetup(argv) {
|
|
11103
|
+
const { flags } = parseArgs(argv, BOOLEAN_FLAGS5);
|
|
11104
|
+
const r = reporterFor(flags);
|
|
11105
|
+
const root = process.cwd();
|
|
11106
|
+
const global = flags.global === true;
|
|
11107
|
+
const url = strFlag(flags, "url");
|
|
11108
|
+
const noSkills = flags["no-skills"] === true;
|
|
11109
|
+
const noRules = flags["no-rules"] === true;
|
|
11110
|
+
const noBrowser = flags["no-browser"] === true;
|
|
11111
|
+
const wanted = strFlag(flags, "agent");
|
|
11112
|
+
let homes;
|
|
11113
|
+
if (wanted) {
|
|
11114
|
+
const v = agentsFromFlag(wanted, root);
|
|
11115
|
+
if ("error" in v) throw new UsageError(v.error);
|
|
11116
|
+
homes = v.homes;
|
|
11117
|
+
} else {
|
|
11118
|
+
homes = detectAgents(root, { home: homedir3(), global });
|
|
11119
|
+
}
|
|
11120
|
+
const agents = [...new Set(homes.map((h) => h.agent))];
|
|
11121
|
+
r.event({ event: "agents", agents, global });
|
|
11122
|
+
r.log(
|
|
11123
|
+
agents.length ? `agents: ${agents.join(", ")}` : "agents: none detected here (the skills land in .agents/skills, which every agent reads)"
|
|
11124
|
+
);
|
|
11125
|
+
let skillsVia = "skipped";
|
|
11126
|
+
let skillNames = [];
|
|
11127
|
+
if (!noSkills) {
|
|
11128
|
+
const args = [
|
|
11129
|
+
"skills",
|
|
11130
|
+
"add",
|
|
11131
|
+
SKILLS_SOURCE,
|
|
11132
|
+
"-y",
|
|
11133
|
+
...global ? ["-g"] : []
|
|
11134
|
+
];
|
|
11135
|
+
r.log(`installing the vos skills: npx ${args.join(" ")}`);
|
|
11136
|
+
const res = spawnSync(npx(), args, {
|
|
11137
|
+
cwd: root,
|
|
11138
|
+
encoding: "utf8",
|
|
11139
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
11140
|
+
shell: process.platform === "win32",
|
|
11141
|
+
timeout: 12e4
|
|
11142
|
+
});
|
|
11143
|
+
if (res.status === 0) {
|
|
11144
|
+
skillsVia = "skills.sh";
|
|
11145
|
+
} else {
|
|
11146
|
+
const bundled = bundledSkillsDir(import.meta.url.replace("file://", ""));
|
|
11147
|
+
if (!bundled)
|
|
11148
|
+
throw new Error(
|
|
11149
|
+
`could not install the skills: npx skills add ${SKILLS_SOURCE} failed (${(res.stderr ?? "").trim().split("\n").at(-1) ?? res.error?.message ?? "no output"}) and this build carries no bundled copy`
|
|
11150
|
+
);
|
|
11151
|
+
const targets = homes.length ? homes : [fallbackSkillsHome(root)];
|
|
11152
|
+
for (const home of targets) {
|
|
11153
|
+
const dest = skillsDirFor(home);
|
|
11154
|
+
mkdirSync3(dest, { recursive: true });
|
|
11155
|
+
for (const name of installedSkills(bundled)) {
|
|
11156
|
+
cpSync(join20(bundled, name), join20(dest, name), { recursive: true });
|
|
11157
|
+
}
|
|
11158
|
+
}
|
|
11159
|
+
skillsVia = "bundled";
|
|
11160
|
+
r.log(
|
|
11161
|
+
`skills.sh did not answer; copied the bundled skills into ${targets.map((t) => skillsDirFor(t)).join(", ")}`
|
|
11162
|
+
);
|
|
11163
|
+
}
|
|
11164
|
+
skillNames = [
|
|
11165
|
+
...new Set(
|
|
11166
|
+
(homes.length ? homes : [fallbackSkillsHome(root)]).flatMap(
|
|
11167
|
+
(h) => installedSkills(skillsDirFor(h))
|
|
11168
|
+
)
|
|
11169
|
+
)
|
|
11170
|
+
].sort();
|
|
11171
|
+
}
|
|
11172
|
+
r.event({ event: "skills", via: skillsVia, names: skillNames });
|
|
11173
|
+
let browser = probe();
|
|
11174
|
+
if (browser.kind === "none" && !noBrowser) {
|
|
11175
|
+
r.log(
|
|
11176
|
+
"no browser found; installing Chromium: npx playwright install chromium"
|
|
11177
|
+
);
|
|
11178
|
+
spawnSync(npx(), ["playwright", "install", "chromium"], {
|
|
11179
|
+
cwd: root,
|
|
11180
|
+
stdio: ["ignore", "ignore", "inherit"],
|
|
11181
|
+
shell: process.platform === "win32",
|
|
11182
|
+
timeout: 6e5
|
|
11183
|
+
});
|
|
11184
|
+
browser = probe();
|
|
11185
|
+
}
|
|
11186
|
+
r.event({ event: "browser", kind: browser.kind, path: browser.path });
|
|
11187
|
+
r.log(`browser: ${browser.line}`);
|
|
11188
|
+
let rules = null;
|
|
11189
|
+
if (!noRules) {
|
|
11190
|
+
const file = rulesFileFor(root);
|
|
11191
|
+
const existing = existsSync17(file) ? readFileSync8(file, "utf8") : null;
|
|
11192
|
+
const { text, changed } = applyRulesBlock(existing);
|
|
11193
|
+
if (changed) writeFileSync3(file, text);
|
|
11194
|
+
rules = { file, changed };
|
|
11195
|
+
r.log(
|
|
11196
|
+
changed ? `rules: wrote the vosso block into ${file}` : `rules: ${file} already carries the block`
|
|
11197
|
+
);
|
|
11198
|
+
}
|
|
11199
|
+
r.event({ event: "rules", ...rules ?? { file: null, changed: false } });
|
|
11200
|
+
const report = doctorReport(
|
|
11201
|
+
await doctorFacts({
|
|
11202
|
+
homes: homes.length ? homes : [fallbackSkillsHome(root)],
|
|
11203
|
+
url
|
|
11204
|
+
})
|
|
11205
|
+
);
|
|
11206
|
+
r.done(
|
|
11207
|
+
{
|
|
11208
|
+
agents,
|
|
11209
|
+
skills: { via: skillsVia, names: skillNames },
|
|
11210
|
+
browser: { kind: browser.kind, path: browser.path },
|
|
11211
|
+
rules,
|
|
11212
|
+
doctor: { ok: report.ok, ...report.facts },
|
|
11213
|
+
next_step: report.next_step
|
|
11214
|
+
},
|
|
11215
|
+
`${report.lines.join("\n")}
|
|
11216
|
+
|
|
11217
|
+
Next: ${report.next_step}`
|
|
11218
|
+
);
|
|
11219
|
+
return report.ok ? EXIT_OK : EXIT_NO_BROWSER;
|
|
11220
|
+
}
|
|
11221
|
+
async function cmdDoctor(argv) {
|
|
11222
|
+
const { flags } = parseArgs(argv, BOOLEAN_FLAGS5);
|
|
11223
|
+
const r = reporterFor(flags);
|
|
11224
|
+
const root = process.cwd();
|
|
11225
|
+
const homes = detectAgents(root, { home: homedir3(), global: true });
|
|
11226
|
+
const report = doctorReport(
|
|
11227
|
+
await doctorFacts({
|
|
11228
|
+
homes: homes.length ? homes : [fallbackSkillsHome(root)],
|
|
11229
|
+
url: strFlag(flags, "url")
|
|
11230
|
+
})
|
|
11231
|
+
);
|
|
11232
|
+
r.done(
|
|
11233
|
+
{ ok: report.ok, ...report.facts, next_step: report.next_step },
|
|
11234
|
+
`${report.lines.join("\n")}
|
|
11235
|
+
|
|
11236
|
+
Next: ${report.next_step}`
|
|
11237
|
+
);
|
|
11238
|
+
return report.ok ? EXIT_OK : EXIT_NO_BROWSER;
|
|
11239
|
+
}
|
|
11240
|
+
async function cmdWhoami(argv) {
|
|
11241
|
+
const { flags } = parseArgs(argv, BOOLEAN_FLAGS5);
|
|
11242
|
+
const r = reporterFor(flags);
|
|
11243
|
+
const origin = platformOrigin({
|
|
11244
|
+
origin: strFlag(flags, "origin"),
|
|
11245
|
+
api: strFlag(flags, "api")
|
|
11246
|
+
});
|
|
11247
|
+
const key = resolveCredential(strFlag(flags, "key"));
|
|
11248
|
+
if (!key) {
|
|
11249
|
+
r.done(
|
|
11250
|
+
{
|
|
11251
|
+
signedIn: false,
|
|
11252
|
+
origin,
|
|
11253
|
+
next_step: "vos login (only needed for hosting, sharing or cloud rendering)"
|
|
11254
|
+
},
|
|
11255
|
+
`Not signed in to ${origin}. Recording and rendering need no account; vos login when you want a link.`
|
|
11256
|
+
);
|
|
11257
|
+
return EXIT_ERROR;
|
|
11258
|
+
}
|
|
11259
|
+
const res = await apiJson(origin, "/api/user/whoami", { key });
|
|
11260
|
+
if (res.status === 404) {
|
|
11261
|
+
r.done(
|
|
11262
|
+
{
|
|
11263
|
+
signedIn: true,
|
|
11264
|
+
origin,
|
|
11265
|
+
user: null,
|
|
11266
|
+
key: null,
|
|
11267
|
+
next_step: "vos push when you want the work hosted"
|
|
11268
|
+
},
|
|
11269
|
+
`A credential is present for ${origin} (this origin cannot say whose).`
|
|
11270
|
+
);
|
|
11271
|
+
return EXIT_OK;
|
|
11272
|
+
}
|
|
11273
|
+
if (res.status === 401 || res.status === 403) {
|
|
11274
|
+
r.done(
|
|
11275
|
+
{
|
|
11276
|
+
signedIn: false,
|
|
11277
|
+
origin,
|
|
11278
|
+
error: apiError("whoami", res),
|
|
11279
|
+
next_step: "vos login"
|
|
11280
|
+
},
|
|
11281
|
+
`The stored credential is refused by ${origin}: ${apiError("whoami", res)}. Run vos login.`
|
|
11282
|
+
);
|
|
11283
|
+
return EXIT_ERROR;
|
|
11284
|
+
}
|
|
11285
|
+
if (res.status !== 200) throw new Error(apiError("whoami", res));
|
|
11286
|
+
const user = res.body.user;
|
|
11287
|
+
const k = res.body.key;
|
|
11288
|
+
const who = user?.username ? `@${user.username}` : user?.name ?? "an account";
|
|
11289
|
+
const keyLine = k ? `key "${k.name ?? ""}" (${k.prefix ?? "\u2026"}, ${(k.scopes ?? []).join(", ") || "no scopes"})` : "a session, not a key";
|
|
11290
|
+
r.done(
|
|
11291
|
+
{
|
|
11292
|
+
signedIn: true,
|
|
11293
|
+
origin,
|
|
11294
|
+
user,
|
|
11295
|
+
key: k,
|
|
11296
|
+
next_step: "vos push when you want the work hosted"
|
|
11297
|
+
},
|
|
11298
|
+
`Signed in to ${origin} as ${who}, with ${keyLine}.`
|
|
11299
|
+
);
|
|
11300
|
+
return EXIT_OK;
|
|
11301
|
+
}
|
|
11302
|
+
function cmdLogout(argv) {
|
|
11303
|
+
const { flags } = parseArgs(argv, BOOLEAN_FLAGS5);
|
|
11304
|
+
const r = reporterFor(flags);
|
|
11305
|
+
const had = existsSync17(CREDENTIALS_PATH);
|
|
11306
|
+
rmSync2(CREDENTIALS_PATH, { force: true });
|
|
11307
|
+
const envKey = Boolean(process.env.VOS_API_KEY?.trim());
|
|
11308
|
+
r.done(
|
|
11309
|
+
{
|
|
11310
|
+
path: CREDENTIALS_PATH,
|
|
11311
|
+
removed: had,
|
|
11312
|
+
envCredential: envKey,
|
|
11313
|
+
next_step: envKey ? "unset VOS_API_KEY as well; it still resolves" : "vos login when you next need hosting"
|
|
11314
|
+
},
|
|
11315
|
+
(had ? `Removed ${CREDENTIALS_PATH}.` : `Nothing stored at ${CREDENTIALS_PATH}.`) + (envKey ? " VOS_API_KEY is still set in this shell and still resolves." : "")
|
|
11316
|
+
);
|
|
11317
|
+
return EXIT_OK;
|
|
11318
|
+
}
|
|
11319
|
+
|
|
11320
|
+
// src/plugin/run.ts
|
|
11321
|
+
var BOOLEAN_FLAGS6 = /* @__PURE__ */ new Set([
|
|
10769
11322
|
"json",
|
|
10770
11323
|
"help",
|
|
10771
11324
|
"picture",
|
|
@@ -10811,6 +11364,22 @@ Take pipeline
|
|
|
10811
11364
|
vos actions script <actions.json> [--json]
|
|
10812
11365
|
the flow as numbered beats in words, for a person recording it by hand
|
|
10813
11366
|
|
|
11367
|
+
This machine (no account)
|
|
11368
|
+
vos setup [--agent claude,cursor,codex,copilot|all] [--global] [--no-skills] [--no-rules] [--no-browser] [--url <dev server>] [--json]
|
|
11369
|
+
ready this computer for the loop: the vos skills into your
|
|
11370
|
+
agent's directories (npx skills add vosjs/skills, else the copy
|
|
11371
|
+
bundled in this package), a browser found or installed, one
|
|
11372
|
+
idempotent block in AGENTS.md (or CLAUDE.md), then doctor.
|
|
11373
|
+
NDJSON whenever stdout is not a TTY; done carries next_step
|
|
11374
|
+
vos doctor [--url <dev server>] [--json]
|
|
11375
|
+
what is ready, in words: node, browser, ffmpeg, the skills per
|
|
11376
|
+
agent, a credential (present or absent, never printed), and the
|
|
11377
|
+
dev server when --url names one. Exit 3 when no browser
|
|
11378
|
+
vos whoami [--json]
|
|
11379
|
+
the key's name and the account it belongs to, never the key
|
|
11380
|
+
vos logout [--json]
|
|
11381
|
+
remove ~/.config/vos/credentials (VOS_API_KEY still resolves)
|
|
11382
|
+
|
|
10814
11383
|
Platform (vos.so) \u2014 fetch, edit, push, pull, repeat
|
|
10815
11384
|
vos login [--key <vos_sk_\u2026>] [--label <name>] [--no-browser]
|
|
10816
11385
|
sign in via the browser (approve at vos.so/cli/auth; works
|
|
@@ -11014,7 +11583,8 @@ before them (-u gives links their href); what the recorder cannot follow
|
|
|
11014
11583
|
dropped. Then: vos record --actions actions.json --strict.
|
|
11015
11584
|
open serves the take and loads it into the studio (?take=<server>) \u2014
|
|
11016
11585
|
doc.json edits arrive intact; a human can drag every zoom span. Keeps
|
|
11017
|
-
serving until Ctrl-C
|
|
11586
|
+
serving until Ctrl-C. The studio is https://vos.so by default (VOS_ORIGIN
|
|
11587
|
+
moves it; --studio http://localhost:6060 for a dev server).
|
|
11018
11588
|
|
|
11019
11589
|
push/pull \u2014 the hosted iteration loop (credentials: --key, VOS_API_KEY, or
|
|
11020
11590
|
~/.config/vos/credentials via vos login; origin via VOS_ORIGIN, default
|
|
@@ -11106,7 +11676,7 @@ function takeStorageState(flags) {
|
|
|
11106
11676
|
const raw = strFlag(flags, "storage-state");
|
|
11107
11677
|
if (!raw) return void 0;
|
|
11108
11678
|
const path = resolve9(raw);
|
|
11109
|
-
if (!
|
|
11679
|
+
if (!existsSync18(path))
|
|
11110
11680
|
throw new UsageError(`--storage-state: no such file: ${path}`);
|
|
11111
11681
|
return path;
|
|
11112
11682
|
}
|
|
@@ -11119,7 +11689,7 @@ function takeSessionName(flags, storageState) {
|
|
|
11119
11689
|
throw new UsageError(
|
|
11120
11690
|
"--session and --storage-state are two doors to one take: a persistent profile cannot take a storage state. Pass one"
|
|
11121
11691
|
);
|
|
11122
|
-
if (!
|
|
11692
|
+
if (!existsSync18(sessionDir(name)))
|
|
11123
11693
|
throw new UsageError(
|
|
11124
11694
|
`no session "${name}". Make one: vos session open <url> --name ${name} (a Chrome window opens; sign in and close it)`
|
|
11125
11695
|
);
|
|
@@ -11175,7 +11745,7 @@ function wallGate(flags, r, opts) {
|
|
|
11175
11745
|
async function cmdRecord(argv) {
|
|
11176
11746
|
const { positionals, flags, multi } = parseArgs(
|
|
11177
11747
|
argv,
|
|
11178
|
-
|
|
11748
|
+
BOOLEAN_FLAGS6,
|
|
11179
11749
|
MULTI_FLAGS2
|
|
11180
11750
|
);
|
|
11181
11751
|
const actionsPath = strFlag(flags, "actions") ?? positionals[0];
|
|
@@ -11252,7 +11822,7 @@ ${lines.join("\n")}
|
|
|
11252
11822
|
}
|
|
11253
11823
|
const paths = takePaths(outDir);
|
|
11254
11824
|
const prepare = async () => {
|
|
11255
|
-
if (
|
|
11825
|
+
if (existsSync18(join21(outDir, "meta.json"))) {
|
|
11256
11826
|
const { prevDoc, kept } = await prepareReRecord(outDir);
|
|
11257
11827
|
r.log(
|
|
11258
11828
|
`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" : "")
|
|
@@ -11317,7 +11887,7 @@ ${lines.join("\n")}
|
|
|
11317
11887
|
},
|
|
11318
11888
|
strictFail ? `STRICT: take recorded but incomplete \u2014 ${strictReason(rec)}; fix the flow and re-record.${skippedNote}${exposureNote(rec)}` : `Take ready: ${outDir}
|
|
11319
11889
|
${(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}
|
|
11320
|
-
Next: edit ${
|
|
11890
|
+
Next: edit ${join21(outDir, "doc.json")} (optional), then: vos render ${outDir}${exposureNote(rec)}`
|
|
11321
11891
|
);
|
|
11322
11892
|
return strictFail ? EXIT_USAGE : EXIT_OK;
|
|
11323
11893
|
} finally {
|
|
@@ -11327,7 +11897,7 @@ ${lines.join("\n")}
|
|
|
11327
11897
|
async function cmdCreate2(argv) {
|
|
11328
11898
|
const { positionals, flags, multi } = parseArgs(
|
|
11329
11899
|
argv,
|
|
11330
|
-
|
|
11900
|
+
BOOLEAN_FLAGS6,
|
|
11331
11901
|
MULTI_FLAGS2
|
|
11332
11902
|
);
|
|
11333
11903
|
const actionsPath = strFlag(flags, "actions");
|
|
@@ -11346,7 +11916,7 @@ async function cmdCreate2(argv) {
|
|
|
11346
11916
|
if (fmtRaw !== "webm" && fmtRaw !== "mp4")
|
|
11347
11917
|
throw new UsageError("--format must be webm or mp4");
|
|
11348
11918
|
const format = fmtRaw;
|
|
11349
|
-
const out = positionals[0] ??
|
|
11919
|
+
const out = positionals[0] ?? join21(outDir, `out.${format}`);
|
|
11350
11920
|
const parallel = numFlag(flags, "parallel", 1);
|
|
11351
11921
|
if (!Number.isInteger(parallel) || parallel < 1 || parallel > 16) {
|
|
11352
11922
|
throw new UsageError("--parallel expects an integer between 1 and 16");
|
|
@@ -11359,7 +11929,7 @@ async function cmdCreate2(argv) {
|
|
|
11359
11929
|
const headers = takeHeaders(multi);
|
|
11360
11930
|
const paths = takePaths(outDir);
|
|
11361
11931
|
const prepare = async () => {
|
|
11362
|
-
if (
|
|
11932
|
+
if (existsSync18(join21(outDir, "meta.json"))) {
|
|
11363
11933
|
const { prevDoc, kept } = await prepareReRecord(outDir);
|
|
11364
11934
|
r.log(
|
|
11365
11935
|
`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" : "")
|
|
@@ -11456,7 +12026,7 @@ async function cmdCreate2(argv) {
|
|
|
11456
12026
|
async function cmdPlan(argv) {
|
|
11457
12027
|
const { positionals, flags, multi } = parseArgs(
|
|
11458
12028
|
argv,
|
|
11459
|
-
|
|
12029
|
+
BOOLEAN_FLAGS6,
|
|
11460
12030
|
/* @__PURE__ */ new Set(["with"])
|
|
11461
12031
|
);
|
|
11462
12032
|
const dir = positionals[0];
|
|
@@ -11466,13 +12036,13 @@ async function cmdPlan(argv) {
|
|
|
11466
12036
|
);
|
|
11467
12037
|
const r = createReporter(flags.json === true);
|
|
11468
12038
|
if (flags.fresh === true) {
|
|
11469
|
-
await rm5(
|
|
12039
|
+
await rm5(join21(dir, "doc.json"), { force: true });
|
|
11470
12040
|
r.log("note: --fresh discarded the existing doc.json");
|
|
11471
12041
|
}
|
|
11472
12042
|
let reuse;
|
|
11473
12043
|
if (flags.reuse === true) {
|
|
11474
|
-
const from = resolve9(strFlag(flags, "from") ??
|
|
11475
|
-
if (!
|
|
12044
|
+
const from = resolve9(strFlag(flags, "from") ?? join21(dir, PREV_DOC_NAME));
|
|
12045
|
+
if (!existsSync18(from)) {
|
|
11476
12046
|
throw new UsageError(
|
|
11477
12047
|
`--reuse: ${from} does not exist \u2014 a re-record into this take writes doc.prev.json, or pass --from <doc.json>`
|
|
11478
12048
|
);
|
|
@@ -11483,7 +12053,7 @@ async function cmdPlan(argv) {
|
|
|
11483
12053
|
};
|
|
11484
12054
|
}
|
|
11485
12055
|
const style = await resolveStyleRef(flags);
|
|
11486
|
-
const hasDoc =
|
|
12056
|
+
const hasDoc = existsSync18(join21(dir, "doc.json"));
|
|
11487
12057
|
const backdrop = hasDoc ? null : await takeBackdrop(flags, r);
|
|
11488
12058
|
const release = await releaseInputs(dir, flags, r, multi.with ?? []);
|
|
11489
12059
|
const motionWanted = !hasDoc || flags.motion === true || flags.fresh === true;
|
|
@@ -11541,7 +12111,7 @@ async function cmdPlan(argv) {
|
|
|
11541
12111
|
...s.motion ? { motion: s.motion } : {},
|
|
11542
12112
|
...s.reuse ? { reuse: s.reuse } : {}
|
|
11543
12113
|
},
|
|
11544
|
-
`${s.reuse ? "Reused" : s.fresh ? "Planned" : "Refreshed"} ${
|
|
12114
|
+
`${s.reuse ? "Reused" : s.fresh ? "Planned" : "Refreshed"} ${join21(dir, "doc.json")}: ${s.zoomAuto} auto + ${s.zoomManual} manual zoom spans${s.cursorKept ? "" : " (cursor track dropped)"}${layoutLines}${motionLines}${reuseLines}`
|
|
11545
12115
|
);
|
|
11546
12116
|
return EXIT_OK;
|
|
11547
12117
|
}
|
|
@@ -11654,7 +12224,7 @@ async function releaseInputs(dir, flags, r, withRefs = []) {
|
|
|
11654
12224
|
async function cmdRender(argv) {
|
|
11655
12225
|
const { positionals, flags, multi } = parseArgs(
|
|
11656
12226
|
argv,
|
|
11657
|
-
|
|
12227
|
+
BOOLEAN_FLAGS6,
|
|
11658
12228
|
MULTI_FLAGS2
|
|
11659
12229
|
);
|
|
11660
12230
|
const dir = positionals[0];
|
|
@@ -11667,7 +12237,7 @@ async function cmdRender(argv) {
|
|
|
11667
12237
|
if (fmtRaw !== "webm" && fmtRaw !== "mp4")
|
|
11668
12238
|
throw new UsageError("--format must be webm or mp4");
|
|
11669
12239
|
const format = fmtRaw;
|
|
11670
|
-
const out = positionals[1] ??
|
|
12240
|
+
const out = positionals[1] ?? join21(dir, `out.${format}`);
|
|
11671
12241
|
const parallel = numFlag(flags, "parallel", 1);
|
|
11672
12242
|
if (!Number.isInteger(parallel) || parallel < 1 || parallel > 16) {
|
|
11673
12243
|
throw new UsageError("--parallel expects an integer between 1 and 16");
|
|
@@ -11725,7 +12295,7 @@ async function cmdRender(argv) {
|
|
|
11725
12295
|
async function cmdFrames(argv) {
|
|
11726
12296
|
const { positionals, flags, multi } = parseArgs(
|
|
11727
12297
|
argv,
|
|
11728
|
-
|
|
12298
|
+
BOOLEAN_FLAGS6,
|
|
11729
12299
|
MULTI_FLAGS2
|
|
11730
12300
|
);
|
|
11731
12301
|
const dir = positionals[0];
|
|
@@ -11798,7 +12368,7 @@ async function cmdFrames(argv) {
|
|
|
11798
12368
|
async function cmdDeliver(argv) {
|
|
11799
12369
|
const { positionals, flags, multi } = parseArgs(
|
|
11800
12370
|
argv,
|
|
11801
|
-
|
|
12371
|
+
BOOLEAN_FLAGS6,
|
|
11802
12372
|
MULTI_FLAGS2
|
|
11803
12373
|
);
|
|
11804
12374
|
const dir = positionals[0];
|
|
@@ -11914,11 +12484,11 @@ async function resolveStyleRef(flags) {
|
|
|
11914
12484
|
}
|
|
11915
12485
|
async function resolveDocRef(ref, flags, what) {
|
|
11916
12486
|
const styleRef = ref;
|
|
11917
|
-
const file =
|
|
12487
|
+
const file = existsSync18(styleRef) ? resolve9(
|
|
11918
12488
|
styleRef,
|
|
11919
|
-
|
|
12489
|
+
existsSync18(join21(styleRef, "doc.json")) ? "doc.json" : ""
|
|
11920
12490
|
) : null;
|
|
11921
|
-
if (file &&
|
|
12491
|
+
if (file && existsSync18(file)) {
|
|
11922
12492
|
return {
|
|
11923
12493
|
from: file,
|
|
11924
12494
|
doc: migrateHostedDoc5(
|
|
@@ -11964,7 +12534,7 @@ async function officialTemplate(origin, ref) {
|
|
|
11964
12534
|
}
|
|
11965
12535
|
}
|
|
11966
12536
|
async function cmdDigest(argv) {
|
|
11967
|
-
const { positionals, flags } = parseArgs(argv,
|
|
12537
|
+
const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS6);
|
|
11968
12538
|
const dir = positionals[0];
|
|
11969
12539
|
if (!dir)
|
|
11970
12540
|
throw new UsageError(
|
|
@@ -12005,7 +12575,7 @@ async function cmdDigest(argv) {
|
|
|
12005
12575
|
kinds,
|
|
12006
12576
|
frames: d.images.full,
|
|
12007
12577
|
crops: d.images.crop,
|
|
12008
|
-
sheet: d.images.sheet ?
|
|
12578
|
+
sheet: d.images.sheet ? join21(result.outDir, d.images.sheet) : null,
|
|
12009
12579
|
scenes: kinds.scene ?? 0,
|
|
12010
12580
|
sourceDuration: d.take.sourceDuration,
|
|
12011
12581
|
outputDuration: d.take.outputDuration,
|
|
@@ -12028,15 +12598,15 @@ async function cmdDigest(argv) {
|
|
|
12028
12598
|
}
|
|
12029
12599
|
}
|
|
12030
12600
|
async function cmdOpen(argv) {
|
|
12031
|
-
const { positionals, flags } = parseArgs(argv,
|
|
12601
|
+
const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS6);
|
|
12032
12602
|
const dir = positionals[0];
|
|
12033
12603
|
if (!dir) throw new UsageError("vos open <take> [--studio <url>]");
|
|
12034
12604
|
const r = createReporter(flags.json === true);
|
|
12035
12605
|
const take = await loadTake(dir);
|
|
12036
|
-
if (!
|
|
12606
|
+
if (!existsSync18(take.paths.recording)) {
|
|
12037
12607
|
throw new UsageError(`${dir} has no recording \u2014 re-run record`);
|
|
12038
12608
|
}
|
|
12039
|
-
const studio = (strFlag(flags, "studio") ??
|
|
12609
|
+
const studio = (strFlag(flags, "studio") ?? platformOrigin()).replace(
|
|
12040
12610
|
/\/+$/,
|
|
12041
12611
|
""
|
|
12042
12612
|
);
|
|
@@ -12066,7 +12636,7 @@ async function cmdOpen(argv) {
|
|
|
12066
12636
|
return EXIT_OK;
|
|
12067
12637
|
}
|
|
12068
12638
|
async function cmdJudge(argv) {
|
|
12069
|
-
const { positionals, flags } = parseArgs(argv,
|
|
12639
|
+
const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS6);
|
|
12070
12640
|
const target = positionals[0];
|
|
12071
12641
|
const against = strFlag(flags, "against");
|
|
12072
12642
|
if (!target || !against)
|
|
@@ -12074,9 +12644,9 @@ async function cmdJudge(argv) {
|
|
|
12074
12644
|
"vos judge <kit.json> --against <MANIFEST.json> [--out dir] [--json]\n(the manifest names the reference set: id, file, role, layout, facts, rule per asset)"
|
|
12075
12645
|
);
|
|
12076
12646
|
const r = createReporter(flags.json === true);
|
|
12077
|
-
const kitFile = target.endsWith("kit.json") ? target :
|
|
12078
|
-
if (!
|
|
12079
|
-
if (!
|
|
12647
|
+
const kitFile = target.endsWith("kit.json") ? target : join21(target, "kit.json");
|
|
12648
|
+
if (!existsSync18(kitFile)) throw new UsageError(`${kitFile}: no kit manifest`);
|
|
12649
|
+
if (!existsSync18(against))
|
|
12080
12650
|
throw new UsageError(`${against}: no reference manifest`);
|
|
12081
12651
|
const result = await judgeKit(kitFile, against, strFlag(flags, "out"));
|
|
12082
12652
|
const verdicts = JSON.parse(await readFile15(result.verdictFile, "utf8")).verdicts;
|
|
@@ -12095,7 +12665,7 @@ Win rate so far: ${rate.wins} win(s), ${rate.ties} tie(s) of ${rate.judged} judg
|
|
|
12095
12665
|
return EXIT_OK;
|
|
12096
12666
|
}
|
|
12097
12667
|
async function cmdCallout(argv) {
|
|
12098
|
-
const { positionals, flags } = parseArgs(argv,
|
|
12668
|
+
const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS6);
|
|
12099
12669
|
const dir = positionals[0];
|
|
12100
12670
|
const shape = positionals[1];
|
|
12101
12671
|
if (!dir || !shape || !isCalloutShape(shape))
|
|
@@ -12194,11 +12764,11 @@ async function cmdCallout(argv) {
|
|
|
12194
12764
|
return EXIT_OK;
|
|
12195
12765
|
}
|
|
12196
12766
|
async function cmdValidate(argv) {
|
|
12197
|
-
const { positionals, flags } = parseArgs(argv,
|
|
12767
|
+
const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS6);
|
|
12198
12768
|
const target = positionals[0];
|
|
12199
12769
|
if (!target) throw new UsageError("vos validate <actions.json|take>");
|
|
12200
12770
|
const r = createReporter(flags.json === true);
|
|
12201
|
-
const kitTarget = target.endsWith("kit.json") ? target :
|
|
12771
|
+
const kitTarget = target.endsWith("kit.json") ? target : existsSync18(join21(target, "kit.json")) && !isTakeDir(target) ? join21(target, "kit.json") : null;
|
|
12202
12772
|
if (kitTarget) {
|
|
12203
12773
|
const picture = flags.picture === true;
|
|
12204
12774
|
const verdict = await validateKit(kitTarget, { picture });
|
|
@@ -12230,9 +12800,9 @@ async function cmdValidate(argv) {
|
|
|
12230
12800
|
r.done({ valid: true, target }, `${target}: valid actions file`);
|
|
12231
12801
|
return EXIT_OK;
|
|
12232
12802
|
}
|
|
12233
|
-
if (!isTakeDir(target) &&
|
|
12803
|
+
if (!isTakeDir(target) && existsSync18(join21(target, "config.json"))) {
|
|
12234
12804
|
const parsed = JSON.parse(
|
|
12235
|
-
await readFile15(
|
|
12805
|
+
await readFile15(join21(target, "config.json"), "utf8")
|
|
12236
12806
|
);
|
|
12237
12807
|
const pre = preflightConfig(parsed);
|
|
12238
12808
|
const problems2 = pre.ok ? [] : pre.issues.map((i) => `config.json: ${i}`);
|
|
@@ -12248,9 +12818,9 @@ async function cmdValidate(argv) {
|
|
|
12248
12818
|
...collectConfigMediaUrls(pre.config ?? parsed),
|
|
12249
12819
|
...collectDocMediaUrls(doc)
|
|
12250
12820
|
];
|
|
12251
|
-
const
|
|
12252
|
-
problems2.push(...
|
|
12253
|
-
warnings2.push(...
|
|
12821
|
+
const probe2 = mediaProbeLints(await probeMediaUrls([...new Set(urls)]));
|
|
12822
|
+
problems2.push(...probe2.problems);
|
|
12823
|
+
warnings2.push(...probe2.warnings);
|
|
12254
12824
|
}
|
|
12255
12825
|
if (problems2.length) {
|
|
12256
12826
|
r.done(
|
|
@@ -12273,7 +12843,7 @@ async function cmdValidate(argv) {
|
|
|
12273
12843
|
const take = await loadTake(target);
|
|
12274
12844
|
const problems = [];
|
|
12275
12845
|
const warnings = [];
|
|
12276
|
-
if (!
|
|
12846
|
+
if (!existsSync18(take.paths.recording)) {
|
|
12277
12847
|
problems.push("missing recording (re-run record)");
|
|
12278
12848
|
} else {
|
|
12279
12849
|
const mismatch = containerMismatch(
|
|
@@ -12299,11 +12869,11 @@ async function cmdValidate(argv) {
|
|
|
12299
12869
|
const lint = lintDoc(take.doc);
|
|
12300
12870
|
problems.push(...lint.problems.map((p) => `doc.json: ${p}`));
|
|
12301
12871
|
warnings.push(...lint.warnings.map((w) => `doc.json: ${w}`));
|
|
12302
|
-
const
|
|
12872
|
+
const probe2 = mediaProbeLints(
|
|
12303
12873
|
await probeMediaUrls(collectDocMediaUrls(take.doc))
|
|
12304
12874
|
);
|
|
12305
|
-
problems.push(...
|
|
12306
|
-
warnings.push(...
|
|
12875
|
+
problems.push(...probe2.problems);
|
|
12876
|
+
warnings.push(...probe2.warnings);
|
|
12307
12877
|
if (flags.picture === true && (take.doc.overlays ?? []).some((o) => o.kind === "html")) {
|
|
12308
12878
|
const doc = take.doc;
|
|
12309
12879
|
const times = [
|
|
@@ -12356,7 +12926,7 @@ async function cmdValidate(argv) {
|
|
|
12356
12926
|
async function cmdPush3(argv) {
|
|
12357
12927
|
const { positionals, flags, multi } = parseArgs(
|
|
12358
12928
|
argv,
|
|
12359
|
-
|
|
12929
|
+
BOOLEAN_FLAGS6,
|
|
12360
12930
|
MULTI_FLAGS2
|
|
12361
12931
|
);
|
|
12362
12932
|
const dir = positionals[0];
|
|
@@ -12403,7 +12973,7 @@ async function cmdPush3(argv) {
|
|
|
12403
12973
|
return EXIT_OK;
|
|
12404
12974
|
}
|
|
12405
12975
|
async function cmdPull2(argv) {
|
|
12406
|
-
const { positionals, flags } = parseArgs(argv,
|
|
12976
|
+
const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS6, MULTI_FLAGS2);
|
|
12407
12977
|
const dir = positionals[0] ?? ".";
|
|
12408
12978
|
const r = createReporter(flags.json === true);
|
|
12409
12979
|
const result = await pullTake(
|
|
@@ -12490,6 +13060,14 @@ async function run(argv) {
|
|
|
12490
13060
|
return await cmdDuplicate(rest);
|
|
12491
13061
|
case "login":
|
|
12492
13062
|
return await cmdLogin(rest);
|
|
13063
|
+
case "setup":
|
|
13064
|
+
return await cmdSetup(rest);
|
|
13065
|
+
case "doctor":
|
|
13066
|
+
return await cmdDoctor(rest);
|
|
13067
|
+
case "whoami":
|
|
13068
|
+
return await cmdWhoami(rest);
|
|
13069
|
+
case "logout":
|
|
13070
|
+
return cmdLogout(rest);
|
|
12493
13071
|
case "push": {
|
|
12494
13072
|
const target = rest.find((a) => !a.startsWith("-"));
|
|
12495
13073
|
if (target && isTakeDir(target)) {
|
|
@@ -12550,7 +13128,7 @@ async function run(argv) {
|
|
|
12550
13128
|
}
|
|
12551
13129
|
}
|
|
12552
13130
|
async function cmdSession(argv) {
|
|
12553
|
-
const { positionals, flags } = parseArgs(argv,
|
|
13131
|
+
const { positionals, flags } = parseArgs(argv, BOOLEAN_FLAGS6);
|
|
12554
13132
|
const [sub, arg] = positionals;
|
|
12555
13133
|
const r = createReporter(flags.json === true);
|
|
12556
13134
|
const usage = "vos session open <url> --name <app> | check <name> [--url <url>] | list | rm <name>";
|
|
@@ -12586,7 +13164,7 @@ async function cmdSession(argv) {
|
|
|
12586
13164
|
if (!arg) throw new UsageError(usage);
|
|
12587
13165
|
const bad = sessionNameVerdict(arg);
|
|
12588
13166
|
if (bad) throw new UsageError(bad);
|
|
12589
|
-
if (!
|
|
13167
|
+
if (!existsSync18(sessionDir(arg)))
|
|
12590
13168
|
throw new UsageError(`no session "${arg}" (vos session list)`);
|
|
12591
13169
|
const summary2 = await summarizeSession(arg);
|
|
12592
13170
|
const url = strFlag(flags, "url");
|
|
@@ -12696,4 +13274,4 @@ export {
|
|
|
12696
13274
|
verbHelp,
|
|
12697
13275
|
run
|
|
12698
13276
|
};
|
|
12699
|
-
//# sourceMappingURL=chunk-
|
|
13277
|
+
//# sourceMappingURL=chunk-ANKECV7F.js.map
|