@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.
Files changed (33) hide show
  1. package/README.md +15 -5
  2. package/dist/{chunk-E42NCNWP.js → chunk-ANKECV7F.js} +634 -56
  3. package/dist/chunk-ANKECV7F.js.map +1 -0
  4. package/dist/{chunk-EFI3WUQB.js → chunk-P3X5KVA6.js} +15 -2
  5. package/dist/{chunk-EFI3WUQB.js.map → chunk-P3X5KVA6.js.map} +1 -1
  6. package/dist/cli.js +4 -4
  7. package/dist/index.js +2 -2
  8. package/dist/manifest-A4R367EM.js +8 -0
  9. package/dist/{run-DA5QXZ6F.js → run-CYHH56KA.js} +2 -2
  10. package/package.json +8 -6
  11. package/skills/VERSION +1 -0
  12. package/skills/launch-kit/SKILL.md +356 -0
  13. package/skills/launch-kit/references/channel-specs.md +56 -0
  14. package/skills/product-video/SKILL.md +263 -0
  15. package/skills/product-video/references/destinations.md +71 -0
  16. package/skills/product-video/references/sessions.md +226 -0
  17. package/skills/product-video/references/taste.md +115 -0
  18. package/skills/product-video/references/troubleshooting.md +116 -0
  19. package/skills/vos-authoring/SKILL.md +191 -0
  20. package/skills/vos-authoring/references/examples.md +239 -0
  21. package/skills/vos-authoring/references/schema-reference.md +468 -0
  22. package/skills/vos-create/SKILL.md +258 -0
  23. package/skills/vos-cut/SKILL.md +241 -0
  24. package/skills/vos-footage/SKILL.md +98 -0
  25. package/skills/vos-migrate/SKILL.md +108 -0
  26. package/skills/vos-remix/SKILL.md +136 -0
  27. package/skills/vos-remix/references/3d-recipe.md +37 -0
  28. package/skills/vos-remix/references/params-knobs.md +80 -0
  29. package/skills/vos-remix/references/remix-contract.md +81 -0
  30. package/dist/chunk-E42NCNWP.js.map +0 -1
  31. package/dist/manifest-UCS6OVWZ.js +0 -8
  32. /package/dist/{manifest-UCS6OVWZ.js.map → manifest-A4R367EM.js.map} +0 -0
  33. /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 existsSync16 } from "fs";
31
- import { join as join19, resolve as resolve9 } from "path";
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 probe = await framesTake(browser, dir, {
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 probe.frames) {
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 probe = await apiJson(origin, "/api/folders", { key });
9627
- if (probe.status === 401 || probe.status === 403) {
9628
- throw new Error(apiError("validate key", probe));
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/run.ts
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; --studio overrides the default http://localhost:6060.
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 (!existsSync16(path))
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 (!existsSync16(sessionDir(name)))
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
- BOOLEAN_FLAGS5,
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 (existsSync16(join19(outDir, "meta.json"))) {
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 ${join19(outDir, "doc.json")} (optional), then: vos render ${outDir}${exposureNote(rec)}`
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
- BOOLEAN_FLAGS5,
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] ?? join19(outDir, `out.${format}`);
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 (existsSync16(join19(outDir, "meta.json"))) {
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
- BOOLEAN_FLAGS5,
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(join19(dir, "doc.json"), { force: true });
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") ?? join19(dir, PREV_DOC_NAME));
11475
- if (!existsSync16(from)) {
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 = existsSync16(join19(dir, "doc.json"));
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"} ${join19(dir, "doc.json")}: ${s.zoomAuto} auto + ${s.zoomManual} manual zoom spans${s.cursorKept ? "" : " (cursor track dropped)"}${layoutLines}${motionLines}${reuseLines}`
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
- BOOLEAN_FLAGS5,
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] ?? join19(dir, `out.${format}`);
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
- BOOLEAN_FLAGS5,
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
- BOOLEAN_FLAGS5,
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 = existsSync16(styleRef) ? resolve9(
12487
+ const file = existsSync18(styleRef) ? resolve9(
11918
12488
  styleRef,
11919
- existsSync16(join19(styleRef, "doc.json")) ? "doc.json" : ""
12489
+ existsSync18(join21(styleRef, "doc.json")) ? "doc.json" : ""
11920
12490
  ) : null;
11921
- if (file && existsSync16(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, BOOLEAN_FLAGS5);
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 ? join19(result.outDir, d.images.sheet) : null,
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, BOOLEAN_FLAGS5);
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 (!existsSync16(take.paths.recording)) {
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") ?? "http://localhost:6060").replace(
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, BOOLEAN_FLAGS5);
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 : join19(target, "kit.json");
12078
- if (!existsSync16(kitFile)) throw new UsageError(`${kitFile}: no kit manifest`);
12079
- if (!existsSync16(against))
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, BOOLEAN_FLAGS5);
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, BOOLEAN_FLAGS5);
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 : existsSync16(join19(target, "kit.json")) && !isTakeDir(target) ? join19(target, "kit.json") : null;
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) && existsSync16(join19(target, "config.json"))) {
12803
+ if (!isTakeDir(target) && existsSync18(join21(target, "config.json"))) {
12234
12804
  const parsed = JSON.parse(
12235
- await readFile15(join19(target, "config.json"), "utf8")
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 probe = mediaProbeLints(await probeMediaUrls([...new Set(urls)]));
12252
- problems2.push(...probe.problems);
12253
- warnings2.push(...probe.warnings);
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 (!existsSync16(take.paths.recording)) {
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 probe = mediaProbeLints(
12872
+ const probe2 = mediaProbeLints(
12303
12873
  await probeMediaUrls(collectDocMediaUrls(take.doc))
12304
12874
  );
12305
- problems.push(...probe.problems);
12306
- warnings.push(...probe.warnings);
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
- BOOLEAN_FLAGS5,
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, BOOLEAN_FLAGS5, MULTI_FLAGS2);
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, BOOLEAN_FLAGS5);
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 (!existsSync16(sessionDir(arg)))
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-E42NCNWP.js.map
13277
+ //# sourceMappingURL=chunk-ANKECV7F.js.map