@vosjs/cli 0.46.1 → 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 (39) hide show
  1. package/README.md +15 -5
  2. package/dist/{chunk-UE66DC2K.js → chunk-ANKECV7F.js} +658 -60
  3. package/dist/chunk-ANKECV7F.js.map +1 -0
  4. package/dist/{chunk-ID4OUS5L.js → chunk-AUPGJJTL.js} +18 -1
  5. package/dist/chunk-AUPGJJTL.js.map +1 -0
  6. package/dist/{chunk-EFI3WUQB.js → chunk-P3X5KVA6.js} +15 -2
  7. package/dist/{chunk-EFI3WUQB.js.map → chunk-P3X5KVA6.js.map} +1 -1
  8. package/dist/cli.js +4 -4
  9. package/dist/index.js +3 -3
  10. package/dist/manifest-A4R367EM.js +8 -0
  11. package/dist/{run-2OZS25ER.js → run-CYHH56KA.js} +3 -3
  12. package/dist/{shotList-JC4A3FBT.js → shotList-7F2FE3RU.js} +2 -2
  13. package/package.json +9 -7
  14. package/schema/actions.schema.json +2 -2
  15. package/skills/VERSION +1 -0
  16. package/skills/launch-kit/SKILL.md +356 -0
  17. package/skills/launch-kit/references/channel-specs.md +56 -0
  18. package/skills/product-video/SKILL.md +263 -0
  19. package/skills/product-video/references/destinations.md +71 -0
  20. package/skills/product-video/references/sessions.md +226 -0
  21. package/skills/product-video/references/taste.md +115 -0
  22. package/skills/product-video/references/troubleshooting.md +116 -0
  23. package/skills/vos-authoring/SKILL.md +191 -0
  24. package/skills/vos-authoring/references/examples.md +239 -0
  25. package/skills/vos-authoring/references/schema-reference.md +468 -0
  26. package/skills/vos-create/SKILL.md +258 -0
  27. package/skills/vos-cut/SKILL.md +241 -0
  28. package/skills/vos-footage/SKILL.md +98 -0
  29. package/skills/vos-migrate/SKILL.md +108 -0
  30. package/skills/vos-remix/SKILL.md +136 -0
  31. package/skills/vos-remix/references/3d-recipe.md +37 -0
  32. package/skills/vos-remix/references/params-knobs.md +80 -0
  33. package/skills/vos-remix/references/remix-contract.md +81 -0
  34. package/dist/chunk-ID4OUS5L.js.map +0 -1
  35. package/dist/chunk-UE66DC2K.js.map +0 -1
  36. package/dist/manifest-UCS6OVWZ.js +0 -8
  37. /package/dist/{manifest-UCS6OVWZ.js.map → manifest-A4R367EM.js.map} +0 -0
  38. /package/dist/{run-2OZS25ER.js.map → run-CYHH56KA.js.map} +0 -0
  39. /package/dist/{shotList-JC4A3FBT.js.map → shotList-7F2FE3RU.js.map} +0 -0
@@ -21,6 +21,18 @@ function pointerTravelMs(dist) {
21
21
  Math.max(POINTER_MIN_MS, Math.round(dist * POINTER_MS_PER_PX))
22
22
  );
23
23
  }
24
+ var RESPONSE_MS = 400;
25
+ var QUIET_MS = 250;
26
+ var SETTLE_CAP_MS = 1200;
27
+ function settleVerdict(t, c = { response: RESPONSE_MS, quiet: QUIET_MS, cap: SETTLE_CAP_MS }) {
28
+ if (t.sincePress >= c.cap) return "settled";
29
+ if (t.sinceChange === null)
30
+ return t.sincePress >= c.response ? "settled" : "wait";
31
+ return t.sinceChange >= c.quiet ? "settled" : "wait";
32
+ }
33
+ function holdLeftMs(holdMs, sinceChange) {
34
+ return Math.max(0, holdMs - (sinceChange ?? 0));
35
+ }
24
36
  function settleMs(step) {
25
37
  if (typeof step.ms === "number" && step.ms >= 0) return step.ms;
26
38
  const d = step.do;
@@ -55,6 +67,9 @@ function askedMs(step) {
55
67
  switch (step.do) {
56
68
  case "wait":
57
69
  return step.ms ?? 0;
70
+ // A click's ms is the read after the page settled: the author's.
71
+ case "click":
72
+ return step.ms ?? SETTLE_MS.click;
58
73
  case "hover":
59
74
  return step.ms ?? 700;
60
75
  case "drag":
@@ -154,6 +169,8 @@ export {
154
169
  SCROLL_SETTLE_MS,
155
170
  TRAILING_HOLD_MS,
156
171
  pointerTravelMs,
172
+ settleVerdict,
173
+ holdLeftMs,
157
174
  settleMs,
158
175
  clockMotion,
159
176
  clockTyping,
@@ -164,4 +181,4 @@ export {
164
181
  deadWarns,
165
182
  deadLine
166
183
  };
167
- //# sourceMappingURL=chunk-ID4OUS5L.js.map
184
+ //# sourceMappingURL=chunk-AUPGJJTL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/plugin/pace.ts"],"sourcesContent":["/**\n * The recorder's pace — the pure parts.\n *\n * A take of a scripted flow should run as long as the script asks, plus the\n * gestures a person makes between the asks (the pointer's travel, the press,\n * the settle after it) and no more. Measured before this module (§4.5 of\n * the utility-clip retrospective), hovers ran 2× their ask, drags 4.8× and\n * a 25 s script recorded 42 s, for two reasons the numbers here answer:\n *\n * - The motion loops counted STEPS (one per 16 ms of the asked duration)\n * and awaited a `mouse.move` round trip per step, so a page that\n * re-renders per move (a slider) stretched every gesture by the round\n * trip. A gesture is now driven by the CLOCK: its position is a function\n * of the elapsed time, and it ends when the asked duration has elapsed,\n * however many samples the page allowed.\n * - The settles after a gesture were fixed sleeps (500 ms after a click,\n * 250 after every selector lookup). A settle is DATA: `ms` on the step\n * overrides a small default, and the script's own `wait` steps carry\n * the intended pauses.\n */\n\n/** Pointer travel: ms per CSS px, floor and ceiling — a person's hand. */\nexport const POINTER_MS_PER_PX = 0.7\nexport const POINTER_MIN_MS = 250\nexport const POINTER_MAX_MS = 800\n/** The sample cadence a motion loop aims for. */\nexport const MOTION_TICK_MS = 16\n\n/** The settle after a gesture when the step names none, by verb. */\nexport const SETTLE_MS = {\n click: 150,\n type: 150,\n scroll: 200,\n drag: 80,\n} as const\n\n/** The press: the pause before the button goes down, and the hold. */\nexport const PRESS_LEAD_MS = 80\nexport const PRESS_HOLD_MS = 70\n/** The pause between a selector lookup that scrolled the page and the move. */\nexport const SCROLL_SETTLE_MS = 120\n/** The hold after the last step, so the take does not cut on a press. */\nexport const TRAILING_HOLD_MS = 400\n\n/** How long the pointer takes to travel `dist` CSS px. */\nexport function pointerTravelMs(dist: number): number {\n return Math.min(\n POINTER_MAX_MS,\n Math.max(POINTER_MIN_MS, Math.round(dist * POINTER_MS_PER_PX)),\n )\n}\n\n/**\n * A click's `ms` is READING time, held from the page's last visual change,\n * and the recorder pays the settle itself: the same `ms` was read on one\n * run and dead on the next because the hold started at the press and the\n * page's settle varied run to run (0.3 s to 0.7 s on the same step).\n *\n * The settle is watched on the screencast, which emits only on change:\n * after the press, a change that arrives within RESPONSE_MS says the page\n * is answering, and it has settled once QUIET_MS pass with no new frame.\n * No change within RESPONSE_MS means the page did not change (a click that\n * only moves state) and the settle is over. SETTLE_CAP_MS bounds a page\n * that never stops changing (a playing preview), which is a page nothing\n * is dead on, so the hold simply starts.\n */\nexport const RESPONSE_MS = 400\nexport const QUIET_MS = 250\nexport const SETTLE_CAP_MS = 1200\n\n/**\n * Is the page settled? Pure: the recorder feeds it what it knows at each\n * tick since the press.\n */\nexport function settleVerdict(\n t: {\n /** ms since the press. */\n sincePress: number\n /** ms since the last screencast frame, or null when none arrived since the press. */\n sinceChange: number | null\n },\n c = { response: RESPONSE_MS, quiet: QUIET_MS, cap: SETTLE_CAP_MS },\n): 'wait' | 'settled' {\n if (t.sincePress >= c.cap) return 'settled'\n if (t.sinceChange === null)\n return t.sincePress >= c.response ? 'settled' : 'wait'\n return t.sinceChange >= c.quiet ? 'settled' : 'wait'\n}\n\n/**\n * What is left of a hold once the settle is detected: the hold is measured\n * from the last change, so the quiet already spent counts toward it.\n */\nexport function holdLeftMs(holdMs: number, sinceChange: number | null): number {\n return Math.max(0, holdMs - (sinceChange ?? 0))\n}\n\n/** The settle after a step: its own `ms` when it names one, else the verb's. */\nexport function settleMs(step: { do: string; ms?: number }): number {\n if (typeof step.ms === 'number' && step.ms >= 0) return step.ms\n const d = step.do as keyof typeof SETTLE_MS\n return SETTLE_MS[d] ?? 0\n}\n\nexport const easeInOutCubic = (u: number): number =>\n u < 0.5 ? 4 * u * u * u : 1 - Math.pow(-2 * u + 2, 3) / 2\n\n/**\n * Drive a motion by the clock: `at(u)` is called with the eased progress\n * for each sample, and the loop ends when `dur` ms have elapsed, with the\n * last call at u = 1 exactly. Between samples it sleeps to the next tick\n * only when the sample came back early; a slow sample (a page busy\n * re-rendering) is followed at once, so the gesture keeps its length and\n * loses samples, never the other way round.\n */\nexport async function clockMotion(\n dur: number,\n at: (u: number) => Promise<void>,\n clock: { now: () => number; sleep: (ms: number) => Promise<void> },\n): Promise<number> {\n const start = clock.now()\n let samples = 0\n for (;;) {\n const elapsed = clock.now() - start\n if (elapsed >= dur) break\n await at(easeInOutCubic(Math.min(1, elapsed / dur)))\n samples++\n const next =\n start + Math.ceil((clock.now() - start) / MOTION_TICK_MS) * MOTION_TICK_MS\n const wait = Math.min(next, start + dur) - clock.now()\n if (wait > 0) await clock.sleep(wait)\n }\n await at(1)\n return samples + 1\n}\n\n/**\n * Typing paced by the clock: the i-th character is due at `start + i·delay`;\n * after each keystroke the loop sleeps to the next due time only if the\n * keystroke came back early. A slow field (an editor re-rendering per key)\n * types as fast as it can and says so in the pace report.\n */\nexport async function clockTyping(\n chars: readonly string[],\n delay: number,\n type: (ch: string, index: number) => Promise<void>,\n clock: { now: () => number; sleep: (ms: number) => Promise<void> },\n): Promise<void> {\n const start = clock.now()\n for (let i = 0; i < chars.length; i++) {\n await type(chars[i], i)\n const due = start + (i + 1) * delay\n const wait = due - clock.now()\n if (wait > 0 && i < chars.length - 1) await clock.sleep(wait)\n }\n}\n\n/** One step's pace: what the script asked for it and what it took. */\nexport interface StepPace {\n step: number\n do: string\n /** The script's own ask: a wait's ms, a hover's dwell, a drag's ms, typing's chars × delay, a click's read after the settle; 0 for a scroll. */\n askedMs: number\n /** The gesture the recorder adds by design: pointer travel, the press, the settle. */\n gestureMs: number\n wallMs: number\n}\n\nexport interface PaceReport {\n askedMs: number\n gestureMs: number\n wallMs: number\n /** Wall time neither asked nor a gesture: what the page and the round trips cost. */\n overheadMs: number\n overheadPct: number\n /** The steps whose wall ran past their ask plus gesture by more than a third. */\n slow: { step: number; do: string; askedMs: number; wallMs: number }[]\n}\n\n/** What a script asks of a step, in ms: the part of its wall time that is the author's. */\nexport function askedMs(step: {\n do: string\n ms?: number\n text?: string\n delayMs?: number\n}): number {\n switch (step.do) {\n case 'wait':\n return step.ms ?? 0\n // A click's ms is the read after the page settled: the author's.\n case 'click':\n return step.ms ?? SETTLE_MS.click\n case 'hover':\n return step.ms ?? 700\n case 'drag':\n return step.ms ?? 700\n case 'type':\n return (step.text?.length ?? 0) * (step.delayMs ?? 40)\n default:\n return 0\n }\n}\n\nexport function paceReport(steps: readonly StepPace[]): PaceReport {\n const askedMs = steps.reduce((a, s) => a + s.askedMs, 0)\n const gestureMs = steps.reduce((a, s) => a + s.gestureMs, 0)\n const wallMs = steps.reduce((a, s) => a + s.wallMs, 0)\n const overheadMs = Math.max(0, wallMs - askedMs - gestureMs)\n const slow = steps\n .filter((s) => s.wallMs > (s.askedMs + s.gestureMs) * 1.34 + 60)\n .map((s) => ({\n step: s.step,\n do: s.do,\n askedMs: s.askedMs,\n wallMs: s.wallMs,\n }))\n return {\n askedMs,\n gestureMs,\n wallMs,\n overheadMs,\n overheadPct: wallMs > 0 ? Math.round((overheadMs / wallMs) * 100) : 0,\n slow,\n }\n}\n\n/** The pace in one line for the log. */\nexport function paceLine(r: PaceReport): string {\n const s = (ms: number) => `${(ms / 1000).toFixed(1)} s`\n const slow = r.slow.length\n ? `; slow: ${r.slow.map((x) => `#${x.step} ${x.do} ${s(x.wallMs)} for ${s(x.askedMs)} asked`).join(', ')}`\n : ''\n return `pace: the script asked ${s(r.askedMs)}, the gestures added ${s(r.gestureMs)}, the take ran ${s(r.wallMs)} (${r.overheadPct} % overhead${slow})`\n}\n\n/**\n * DEAD TIME, the smoothness fact that replaces the freeze share as the\n * warning. A still frame is not a defect: a page the viewer is reading is\n * content, and a workspace tour is mostly still. What is dead is a still\n * frame under a PARKED cursor past the beat it takes to read what changed:\n * after that the picture, the pointer and the camera all hold and nothing\n * is being said. So the derivation reads, per step, when the page settled\n * after the step's act, how long the settled frame was held, and whether\n * the cursor moved in that hold; a hold past the reading beat is dead.\n *\n * The beat is longer after a page changed (a navigation shows a whole new\n * page to take in) than after a control changed (one thing to see).\n */\nexport const READ_BEAT_MS = { page: 1000, control: 600 } as const\n/** A dead stretch this long is a warning on its own, whatever the share. */\nexport const DEAD_STRETCH_WARN_MS = 1500\n/** The share of the take past which dead time is a warning. */\nexport const DEAD_SHARE_WARN_PCT = 20\n\nexport interface DeadStep {\n step: number\n id?: string\n do: string\n /** ms from the step's act (its press, else its start) to the last frame change in the step. */\n settledMs: number\n /** ms the settled frame was held before the step ended. */\n heldMs: number\n /** the hold past the reading beat, while the cursor was parked; 0 when the hold was read or the pointer moved. */\n deadMs: number\n}\n\nexport interface DeadReport {\n ms: number\n pct: number\n /** the steps that carried any dead time, in order. */\n steps: DeadStep[]\n /** the longest single dead hold. */\n longestMs: number\n}\n\nexport function deadTime(\n steps: readonly {\n step: number\n id?: string\n do: string\n tStart: number\n tEnd: number\n navigated?: boolean\n }[],\n frames: readonly { tMs: number }[],\n events: readonly { t: number; type: string }[],\n durationMs: number,\n): DeadReport {\n const out: DeadStep[] = []\n let ms = 0\n let longestMs = 0\n for (const s of steps) {\n const t0 = s.tStart * 1000\n const t1 = s.tEnd * 1000\n if (!(t1 > t0)) continue\n // The act: the step's first press, else its start (a wait, a move).\n const press = events.find(\n (e) => e.type === 'down' && e.t >= t0 && e.t <= t1,\n )\n const act = press ? press.t : t0\n // The last visual change inside the step, after the act.\n let last = act\n for (const f of frames) {\n if (f.tMs > act && f.tMs <= t1) last = f.tMs\n }\n const settledMs = Math.round(last - act)\n const heldMs = Math.round(t1 - last)\n // Parked: no pointer motion while the settled frame was held.\n const moved = events.some(\n (e) =>\n (e.type === 'move' || e.type === 'scroll') && e.t > last && e.t <= t1,\n )\n // The opening step shows a page the viewer has not seen: a page beat.\n const beat =\n s.navigated || s.step === 0 ? READ_BEAT_MS.page : READ_BEAT_MS.control\n const deadMs = moved ? 0 : Math.max(0, heldMs - beat)\n if (deadMs > 0) {\n out.push({\n step: s.step,\n ...(s.id ? { id: s.id } : {}),\n do: s.do,\n settledMs,\n heldMs,\n deadMs,\n })\n ms += deadMs\n longestMs = Math.max(longestMs, deadMs)\n }\n }\n return {\n ms,\n pct: durationMs > 0 ? Math.round((ms / durationMs) * 100) : 0,\n steps: out,\n longestMs,\n }\n}\n\n/** Whether a dead report earns a warning: the share, or one long hold. */\nexport function deadWarns(r: DeadReport): boolean {\n return r.pct >= DEAD_SHARE_WARN_PCT || r.longestMs >= DEAD_STRETCH_WARN_MS\n}\n\n/** The dead time in words, naming the steps and what to cut. */\nexport function deadLine(r: DeadReport): string {\n const s = (ms: number) => `${(ms / 1000).toFixed(1)} s`\n if (!r.steps.length) return 'dead time: none'\n const parts = r.steps.map(\n (d) =>\n `#${d.step}${d.id ? ` (${d.id})` : ''} ${d.do} held ${s(d.heldMs)} after it settled, ${s(d.deadMs)} past the beat`,\n )\n return `dead time: ${s(r.ms)} (${r.pct} %), a still frame under a parked cursor past the reading beat: ${parts.join('; ')}. Cut those steps' ms; a hold is what it takes to read what changed.`\n}\n"],"mappings":"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","names":["askedMs"]}
@@ -77,11 +77,24 @@ var manifest = {
77
77
  {
78
78
  name: "login",
79
79
  summary: "sign in via the browser (or --key); stores a content key"
80
- }
80
+ },
81
+ {
82
+ name: "setup",
83
+ summary: "ready this machine: the vos skills into your agent, a browser, one rules block, then doctor"
84
+ },
85
+ {
86
+ name: "doctor",
87
+ summary: "what is ready, in words: node, browser, ffmpeg, skills, a credential (never printed), the dev server"
88
+ },
89
+ {
90
+ name: "whoami",
91
+ summary: "the key\u2019s name and the account it belongs to, never the key"
92
+ },
93
+ { name: "logout", summary: "remove ~/.config/vos/credentials" }
81
94
  ]
82
95
  };
83
96
 
84
97
  export {
85
98
  manifest
86
99
  };
87
- //# sourceMappingURL=chunk-EFI3WUQB.js.map
100
+ //# sourceMappingURL=chunk-P3X5KVA6.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/plugin/manifest.ts"],"sourcesContent":["/**\n * The verb manifest of the take pipeline and the vos.so verbs — what\n * `vos help` lists under the engine verbs. It kept the shape a separately\n * installed plugin once handed the host (name + host range), so a script\n * reading it keeps working.\n */\nexport interface PluginVerb {\n name: string\n summary: string\n}\n\nexport interface PluginManifest {\n name: string\n /** Host versions this plugin speaks the run(argv) contract with. */\n hostRange: string\n verbs: PluginVerb[]\n}\n\nexport const manifest: PluginManifest = {\n name: '@vosjs/cli',\n hostRange: '>=0.9.0',\n verbs: [\n {\n name: 'create',\n summary: 'record + auto-plan + render, one command (--strict)',\n },\n {\n name: 'record',\n summary: 'drive actions.json into a take (screencast + cursor track)',\n },\n {\n name: 'plan',\n summary:\n 'plan zoom/cursor effects into doc.json (wand contract); --reuse re-times a previous cut onto a re-recording',\n },\n {\n name: 'render',\n summary: 'render a take directory (engine configs render in the host)',\n },\n {\n name: 'frames',\n summary:\n 'PNG stills at output times / zoom apexes / moments / exact sizes',\n },\n {\n name: 'deliver',\n summary:\n 'render a take to release destinations (CWS, Product Hunt, X, LinkedIn, OG…) + verified kit.json',\n },\n {\n name: 'digest',\n summary:\n 'see a recording before cutting it: moments (clicks, typing, scrolls, idle, scenes) + footage frames + crops, in doc units',\n },\n { name: 'open', summary: 'serve the take into the vos.so studio' },\n {\n name: 'validate',\n summary:\n 'lint actions.json, a take dir (doc.json semantics), or re-measure a kit.json against the channel specs',\n },\n {\n name: 'actions',\n summary:\n 'from-agent-browser: turn an agent-browser walk (steps.jsonl) into actions.json; what cannot follow is named',\n },\n {\n name: 'brand',\n summary:\n \"write a product's BRAND.md, witnessed: /design.md, /llms.txt, then the page (palette, faces, marks, the avoid list)\",\n },\n {\n name: 'fetch',\n summary: 'download a hosted program: config.json + vos.json tracking',\n },\n {\n name: 'push',\n summary: 'push a config.json or take to vos.so (private; versioned)',\n },\n {\n name: 'duplicate',\n summary:\n 'a private sibling of your OWN vos (someone else\\u2019s is remixed: fetch + push --remix-of)',\n },\n {\n name: 'pull',\n summary:\n 'sync what changed on vos.so since your base (--media brings a take’s footage home)',\n },\n {\n name: 'folder',\n summary:\n 'list/create/pull folders, move voses and assets into them (pull = the context package on disk)',\n },\n {\n name: 'asset',\n summary: 'rename one of your assets in place (recipes included)',\n },\n {\n name: 'recipe',\n summary:\n 'push a recipe .md into a folder, or replace one in place (prior body kept)',\n },\n {\n name: 'login',\n summary: 'sign in via the browser (or --key); stores a content key',\n },\n ],\n}\n"],"mappings":";;;AAkBO,IAAM,WAA2B;AAAA,EACtC,MAAM;AAAA,EACN,WAAW;AAAA,EACX,OAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA,EAAE,MAAM,QAAQ,SAAS,wCAAwC;AAAA,IACjE;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/plugin/manifest.ts"],"sourcesContent":["/**\n * The verb manifest of the take pipeline and the vos.so verbs — what\n * `vos help` lists under the engine verbs. It kept the shape a separately\n * installed plugin once handed the host (name + host range), so a script\n * reading it keeps working.\n */\nexport interface PluginVerb {\n name: string\n summary: string\n}\n\nexport interface PluginManifest {\n name: string\n /** Host versions this plugin speaks the run(argv) contract with. */\n hostRange: string\n verbs: PluginVerb[]\n}\n\nexport const manifest: PluginManifest = {\n name: '@vosjs/cli',\n hostRange: '>=0.9.0',\n verbs: [\n {\n name: 'create',\n summary: 'record + auto-plan + render, one command (--strict)',\n },\n {\n name: 'record',\n summary: 'drive actions.json into a take (screencast + cursor track)',\n },\n {\n name: 'plan',\n summary:\n 'plan zoom/cursor effects into doc.json (wand contract); --reuse re-times a previous cut onto a re-recording',\n },\n {\n name: 'render',\n summary: 'render a take directory (engine configs render in the host)',\n },\n {\n name: 'frames',\n summary:\n 'PNG stills at output times / zoom apexes / moments / exact sizes',\n },\n {\n name: 'deliver',\n summary:\n 'render a take to release destinations (CWS, Product Hunt, X, LinkedIn, OG…) + verified kit.json',\n },\n {\n name: 'digest',\n summary:\n 'see a recording before cutting it: moments (clicks, typing, scrolls, idle, scenes) + footage frames + crops, in doc units',\n },\n { name: 'open', summary: 'serve the take into the vos.so studio' },\n {\n name: 'validate',\n summary:\n 'lint actions.json, a take dir (doc.json semantics), or re-measure a kit.json against the channel specs',\n },\n {\n name: 'actions',\n summary:\n 'from-agent-browser: turn an agent-browser walk (steps.jsonl) into actions.json; what cannot follow is named',\n },\n {\n name: 'brand',\n summary:\n \"write a product's BRAND.md, witnessed: /design.md, /llms.txt, then the page (palette, faces, marks, the avoid list)\",\n },\n {\n name: 'fetch',\n summary: 'download a hosted program: config.json + vos.json tracking',\n },\n {\n name: 'push',\n summary: 'push a config.json or take to vos.so (private; versioned)',\n },\n {\n name: 'duplicate',\n summary:\n 'a private sibling of your OWN vos (someone else\\u2019s is remixed: fetch + push --remix-of)',\n },\n {\n name: 'pull',\n summary:\n 'sync what changed on vos.so since your base (--media brings a take’s footage home)',\n },\n {\n name: 'folder',\n summary:\n 'list/create/pull folders, move voses and assets into them (pull = the context package on disk)',\n },\n {\n name: 'asset',\n summary: 'rename one of your assets in place (recipes included)',\n },\n {\n name: 'recipe',\n summary:\n 'push a recipe .md into a folder, or replace one in place (prior body kept)',\n },\n {\n name: 'login',\n summary: 'sign in via the browser (or --key); stores a content key',\n },\n {\n name: 'setup',\n summary:\n 'ready this machine: the vos skills into your agent, a browser, one rules block, then doctor',\n },\n {\n name: 'doctor',\n summary:\n 'what is ready, in words: node, browser, ffmpeg, skills, a credential (never printed), the dev server',\n },\n {\n name: 'whoami',\n summary: 'the key’s name and the account it belongs to, never the key',\n },\n { name: 'logout', summary: 'remove ~/.config/vos/credentials' },\n ],\n}\n"],"mappings":";;;AAkBO,IAAM,WAA2B;AAAA,EACtC,MAAM;AAAA,EACN,WAAW;AAAA,EACX,OAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA,EAAE,MAAM,QAAQ,SAAS,wCAAwC;AAAA,IACjE;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA,EAAE,MAAM,UAAU,SAAS,mCAAmC;AAAA,EAChE;AACF;","names":[]}
package/dist/cli.js CHANGED
@@ -511,7 +511,7 @@ async function cmdCheck(argv) {
511
511
  return result.ok ? EXIT_OK : EXIT_ERROR;
512
512
  }
513
513
  async function delegate(argv, viaAlias = false) {
514
- const { run } = await import("./run-2OZS25ER.js");
514
+ const { run } = await import("./run-CYHH56KA.js");
515
515
  if (viaAlias && argv[0]) {
516
516
  process.stderr.write(
517
517
  `note: "vos voila ${argv[0]}" is now "vos ${argv[0]}".
@@ -522,7 +522,7 @@ async function delegate(argv, viaAlias = false) {
522
522
  }
523
523
  async function printHelp() {
524
524
  process.stdout.write(HELP_ENGINE);
525
- const { manifest } = await import("./manifest-UCS6OVWZ.js");
525
+ const { manifest } = await import("./manifest-A4R367EM.js");
526
526
  process.stdout.write("\nTake pipeline + vos.so verbs\n");
527
527
  for (const v of manifest.verbs) {
528
528
  if (v.name === "render") continue;
@@ -551,7 +551,7 @@ async function main() {
551
551
  const engine = HELP_ENGINE.split("\n").filter(
552
552
  (l) => l.startsWith(` vos ${cmd} `)
553
553
  );
554
- const { verbHelp } = await import("./run-2OZS25ER.js");
554
+ const { verbHelp } = await import("./run-CYHH56KA.js");
555
555
  const take = verbHelp(cmd);
556
556
  process.stdout.write(
557
557
  `${engine.join("\n")}
@@ -583,7 +583,7 @@ ${take.includes("no such verb") ? "" : take}`
583
583
  main().then(async (code) => {
584
584
  if (code === EXIT_OK) {
585
585
  const verb = process.argv[2] ?? "";
586
- const { HELP } = await import("./run-2OZS25ER.js");
586
+ const { HELP } = await import("./run-CYHH56KA.js");
587
587
  const documented = [
588
588
  ...helpFlagsFor(HELP_ENGINE, verb),
589
589
  ...helpFlagsFor(HELP, verb)
package/dist/index.js CHANGED
@@ -30,17 +30,17 @@ import {
30
30
  validateActions,
31
31
  waitForPageDone,
32
32
  writeSyncState
33
- } from "./chunk-UE66DC2K.js";
33
+ } from "./chunk-ANKECV7F.js";
34
34
  import {
35
35
  BrowserUnavailableError,
36
36
  configDuration,
37
37
  launchBrowser,
38
38
  loadVosConfig
39
39
  } from "./chunk-FACYY7VV.js";
40
- import "./chunk-ID4OUS5L.js";
40
+ import "./chunk-AUPGJJTL.js";
41
41
  import {
42
42
  manifest
43
- } from "./chunk-EFI3WUQB.js";
43
+ } from "./chunk-P3X5KVA6.js";
44
44
  export {
45
45
  BrowserUnavailableError,
46
46
  RECORDING_NAME,
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ manifest
4
+ } from "./chunk-P3X5KVA6.js";
5
+ export {
6
+ manifest
7
+ };
8
+ //# sourceMappingURL=manifest-A4R367EM.js.map
@@ -5,9 +5,9 @@ import {
5
5
  run,
6
6
  takeBrowserArgs,
7
7
  verbHelp
8
- } from "./chunk-UE66DC2K.js";
8
+ } from "./chunk-ANKECV7F.js";
9
9
  import "./chunk-FACYY7VV.js";
10
- import "./chunk-ID4OUS5L.js";
10
+ import "./chunk-AUPGJJTL.js";
11
11
  export {
12
12
  HELP,
13
13
  MULTI_FLAGS,
@@ -15,4 +15,4 @@ export {
15
15
  takeBrowserArgs,
16
16
  verbHelp
17
17
  };
18
- //# sourceMappingURL=run-2OZS25ER.js.map
18
+ //# sourceMappingURL=run-CYHH56KA.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  askedMs
4
- } from "./chunk-ID4OUS5L.js";
4
+ } from "./chunk-AUPGJJTL.js";
5
5
 
6
6
  // src/plugin/shotList.ts
7
7
  function sayTarget(selector) {
@@ -108,4 +108,4 @@ export {
108
108
  sayTarget,
109
109
  shotList
110
110
  };
111
- //# sourceMappingURL=shotList-JC4A3FBT.js.map
111
+ //# sourceMappingURL=shotList-7F2FE3RU.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vosjs/cli",
3
- "version": "0.46.1",
3
+ "version": "0.48.0",
4
4
  "description": "The vos CLI: record the real product from a scripted browser flow, auto-zoom from the cursor track, cut as data in doc.json, render deterministic video and stills, deliver a release's media per destination spec, and sync with vos.so. One binary, every verb, MIT.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -42,20 +42,21 @@
42
42
  },
43
43
  "files": [
44
44
  "dist",
45
- "schema"
45
+ "schema",
46
+ "skills"
46
47
  ],
47
48
  "sideEffects": false,
48
49
  "dependencies": {
49
50
  "mediabunny": "^1.55.7",
50
51
  "playwright": "^1.49.0",
51
52
  "@vosjs/core": "^0.25.0",
53
+ "@vosjs/editor": "^1.3.1",
52
54
  "@vosjs/elements": "^0.8.1",
53
- "@vosjs/render-core": "^0.2.8",
55
+ "@vosjs/render-core": "^0.2.9",
54
56
  "@vosjs/shared": "^0.4.1",
55
- "@vosjs/studio-core": "^0.30.1",
56
- "@vosjs/editor": "^1.3.1",
57
- "@vosjs/timeline": "^0.4.1",
58
- "@vosjs/tween": "^0.8.2"
57
+ "@vosjs/studio-core": "^0.30.3",
58
+ "@vosjs/tween": "^0.8.2",
59
+ "@vosjs/timeline": "^0.4.1"
59
60
  },
60
61
  "devDependencies": {
61
62
  "@types/node": "^22",
@@ -68,6 +69,7 @@
68
69
  },
69
70
  "scripts": {
70
71
  "build": "tsup",
72
+ "sync-skills": "node scripts/sync-skills.mjs",
71
73
  "typecheck": "tsc --noEmit",
72
74
  "lint": "eslint .",
73
75
  "test": "vitest run",
@@ -69,7 +69,7 @@
69
69
  },
70
70
  "ms": {
71
71
  "type": "number",
72
- "description": "wait: the pause; other verbs: the settle after (default 150)"
72
+ "description": "wait: the pause; click: the read after the page settled, held from its last visual change (default 150); type and scroll: the settle after (defaults 150/200)"
73
73
  }
74
74
  }
75
75
  }
@@ -165,7 +165,7 @@
165
165
  "ms": {
166
166
  "type": "number",
167
167
  "minimum": 0,
168
- "description": "the settle after the press, ms (default 150): how long the recorder holds before the next step. The script's own wait steps carry the pauses that mean something; this is only the hand lifting."
168
+ "description": "the read after the press, ms (default 150), held from the page's last visual change: the recorder watches the screencast and pays the settle itself (a change within 400 ms says the page is answering, 250 ms of quiet says it settled, 1.2 s bounds a page that never stops), so the same ms reads the same on every run. Size it as a reading beat, about 1000 after a navigation and 600 after a control, never padded for a slow page."
169
169
  },
170
170
  "selector": {
171
171
  "type": "string"
package/skills/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.5.0