@vosjs/cli 0.77.1 → 0.78.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 +83 -16
- package/dist/{assetManifest-MQ7HO7RZ.js → assetManifest-S6H5F2VE.js} +2 -2
- package/dist/{chunk-IJZ3C435.js → chunk-INRUYQ6J.js} +3223 -325
- package/dist/chunk-INRUYQ6J.js.map +1 -0
- package/dist/{chunk-KDIRW72G.js → chunk-JYCW4EOA.js} +6 -3
- package/dist/chunk-JYCW4EOA.js.map +1 -0
- package/dist/{chunk-2KEQ3LKH.js → chunk-RUDDBHQ7.js} +18 -2
- package/dist/chunk-RUDDBHQ7.js.map +1 -0
- package/dist/{chunk-UY2N42P2.js → chunk-ZSJEISKL.js} +6 -2
- package/dist/{chunk-UY2N42P2.js.map → chunk-ZSJEISKL.js.map} +1 -1
- package/dist/cli.js +6 -6
- package/dist/index.d.ts +29 -26
- package/dist/index.js +4 -4
- package/dist/manifest-6DJSPKVH.js +8 -0
- package/dist/{run-UNOXIGZ3.js → run-TIFM3ZHI.js} +6 -4
- package/dist/{shotList-MAQVLZBY.js → shotList-SCA234OS.js} +19 -1
- package/dist/shotList-SCA234OS.js.map +1 -0
- package/package.json +4 -4
- package/schema/actions.schema.json +192 -0
- package/schema/doc.schema.json +26 -2
- package/dist/chunk-2KEQ3LKH.js.map +0 -1
- package/dist/chunk-IJZ3C435.js.map +0 -1
- package/dist/chunk-KDIRW72G.js.map +0 -1
- package/dist/manifest-QLQKVSML.js +0 -8
- package/dist/shotList-MAQVLZBY.js.map +0 -1
- /package/dist/{assetManifest-MQ7HO7RZ.js.map → assetManifest-S6H5F2VE.js.map} +0 -0
- /package/dist/{manifest-QLQKVSML.js.map → manifest-6DJSPKVH.js.map} +0 -0
- /package/dist/{run-UNOXIGZ3.js.map → run-TIFM3ZHI.js.map} +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -91,32 +91,12 @@ declare class BrowserUnavailableError extends Error {
|
|
|
91
91
|
* `args` are extra Chromium switches (`--browser-arg` on the verbs that
|
|
92
92
|
* record). Some product surfaces cannot be reached without one: a recorder
|
|
93
93
|
* needs a fake capture device to get past a permission prompt, an extension
|
|
94
|
-
* page needs the extension loaded. Passed through verbatim.
|
|
94
|
+
* page needs the extension loaded. Passed through verbatim. `headless:
|
|
95
|
+
* false` opens a window (`vos look --headed`).
|
|
95
96
|
*/
|
|
96
|
-
declare function launchBrowser(args?: string[]
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
every non-engine verb here (`vos <verb>`). The exported `manifest` (index.ts)
|
|
100
|
-
tells the host which verbs exist and how to summarize them in help. */
|
|
101
|
-
declare function run(argv: string[]): Promise<number>;
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* The verb manifest of the take pipeline and the vos.so verbs — what
|
|
105
|
-
* `vos help` lists under the engine verbs. It kept the shape a separately
|
|
106
|
-
* installed plugin once handed the host (name + host range), so a script
|
|
107
|
-
* reading it keeps working.
|
|
108
|
-
*/
|
|
109
|
-
interface PluginVerb {
|
|
110
|
-
name: string;
|
|
111
|
-
summary: string;
|
|
112
|
-
}
|
|
113
|
-
interface PluginManifest {
|
|
114
|
-
name: string;
|
|
115
|
-
/** Host versions this plugin speaks the run(argv) contract with. */
|
|
116
|
-
hostRange: string;
|
|
117
|
-
verbs: PluginVerb[];
|
|
118
|
-
}
|
|
119
|
-
declare const manifest: PluginManifest;
|
|
97
|
+
declare function launchBrowser(args?: string[], launch?: {
|
|
98
|
+
headless?: boolean;
|
|
99
|
+
}): Promise<Browser>;
|
|
120
100
|
|
|
121
101
|
/** The name `record` writes its footage under — its encoder emits WebM. */
|
|
122
102
|
declare const RECORDING_NAME = "recording.webm";
|
|
@@ -143,7 +123,7 @@ interface TakeData {
|
|
|
143
123
|
/** Load a take directory; cursor+meta are required, doc/actions optional. */
|
|
144
124
|
declare function loadTake(dir: string): Promise<TakeData>;
|
|
145
125
|
|
|
146
|
-
type RecordOpts = Omit<RecordOpts$1, 'context' | 'env' | 'platform'> & {
|
|
126
|
+
type RecordOpts = Omit<RecordOpts$1, 'context' | 'env' | 'platform' | 'outputs'> & {
|
|
147
127
|
/**
|
|
148
128
|
* A ready-made context to record IN, instead of one made from `browser`:
|
|
149
129
|
* `--session <name>`, a persistent profile the person signed in to.
|
|
@@ -152,6 +132,29 @@ type RecordOpts = Omit<RecordOpts$1, 'context' | 'env' | 'platform'> & {
|
|
|
152
132
|
};
|
|
153
133
|
declare function recordTake(browser: Browser, url: string, actions: ActionsFile, paths: TakePaths, log: (msg: string) => void, opts?: RecordOpts): Promise<_vosjs_render_core_record.RecordResult>;
|
|
154
134
|
|
|
135
|
+
/** Entry point — the delegation contract for @vosjs/cli: the host forwards
|
|
136
|
+
every non-engine verb here (`vos <verb>`). The exported `manifest` (index.ts)
|
|
137
|
+
tells the host which verbs exist and how to summarize them in help. */
|
|
138
|
+
declare function run(argv: string[]): Promise<number>;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* The verb manifest of the take pipeline and the vos.so verbs — what
|
|
142
|
+
* `vos help` lists under the engine verbs. It kept the shape a separately
|
|
143
|
+
* installed plugin once handed the host (name + host range), so a script
|
|
144
|
+
* reading it keeps working.
|
|
145
|
+
*/
|
|
146
|
+
interface PluginVerb {
|
|
147
|
+
name: string;
|
|
148
|
+
summary: string;
|
|
149
|
+
}
|
|
150
|
+
interface PluginManifest {
|
|
151
|
+
name: string;
|
|
152
|
+
/** Host versions this plugin speaks the run(argv) contract with. */
|
|
153
|
+
hostRange: string;
|
|
154
|
+
verbs: PluginVerb[];
|
|
155
|
+
}
|
|
156
|
+
declare const manifest: PluginManifest;
|
|
157
|
+
|
|
155
158
|
declare function encodeRecording(browser: Browser, takeDir: string, onProgress: (fraction: number) => void): Promise<{
|
|
156
159
|
bytes: number;
|
|
157
160
|
}>;
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
startTakeServer,
|
|
15
15
|
validateActions,
|
|
16
16
|
waitForPageDone
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-INRUYQ6J.js";
|
|
18
18
|
import {
|
|
19
19
|
BrowserUnavailableError,
|
|
20
20
|
configDuration,
|
|
@@ -23,13 +23,13 @@ import {
|
|
|
23
23
|
previewPages,
|
|
24
24
|
renderStill,
|
|
25
25
|
renderVideo
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-JYCW4EOA.js";
|
|
27
27
|
import {
|
|
28
28
|
RECORDING_NAME,
|
|
29
29
|
loadTake,
|
|
30
30
|
pullMedia,
|
|
31
31
|
takePaths
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-ZSJEISKL.js";
|
|
33
33
|
import {
|
|
34
34
|
apiError,
|
|
35
35
|
apiJson,
|
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
import "./chunk-6XPFWQKP.js";
|
|
43
43
|
import {
|
|
44
44
|
manifest
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-RUDDBHQ7.js";
|
|
46
46
|
export {
|
|
47
47
|
BrowserUnavailableError,
|
|
48
48
|
RECORDING_NAME,
|
|
@@ -3,20 +3,22 @@ import {
|
|
|
3
3
|
HELP,
|
|
4
4
|
MULTI_FLAGS,
|
|
5
5
|
run,
|
|
6
|
+
strictFails,
|
|
6
7
|
takeBackdrop,
|
|
7
8
|
takeBrowserArgs,
|
|
8
9
|
verbHelp
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-INRUYQ6J.js";
|
|
11
|
+
import "./chunk-JYCW4EOA.js";
|
|
12
|
+
import "./chunk-ZSJEISKL.js";
|
|
12
13
|
import "./chunk-B4U4URE3.js";
|
|
13
14
|
import "./chunk-6XPFWQKP.js";
|
|
14
15
|
export {
|
|
15
16
|
HELP,
|
|
16
17
|
MULTI_FLAGS,
|
|
17
18
|
run,
|
|
19
|
+
strictFails,
|
|
18
20
|
takeBackdrop,
|
|
19
21
|
takeBrowserArgs,
|
|
20
22
|
verbHelp
|
|
21
23
|
};
|
|
22
|
-
//# sourceMappingURL=run-
|
|
24
|
+
//# sourceMappingURL=run-TIFM3ZHI.js.map
|
|
@@ -31,10 +31,28 @@ function sayStepTarget(step) {
|
|
|
31
31
|
const byId = sayId(step.id);
|
|
32
32
|
return byId ? `${byId} (${bySelector})` : bySelector;
|
|
33
33
|
}
|
|
34
|
+
function sayCondition(c) {
|
|
35
|
+
if (c.text !== void 0) return `"${c.text}" shows on the page`;
|
|
36
|
+
if (c.gone !== void 0) return `${sayTarget(c.gone)} is gone`;
|
|
37
|
+
const target = sayStepTarget({ selector: c.selector ?? "", id: c.id });
|
|
38
|
+
if (c.enabled === true) return `${target} is enabled`;
|
|
39
|
+
if (c.enabled === false) return `${target} is disabled`;
|
|
40
|
+
return `${target} is showing`;
|
|
41
|
+
}
|
|
34
42
|
function beatOf(step) {
|
|
43
|
+
const line = gestureBeat(step);
|
|
44
|
+
return line && step.guard ? `${line} (this spends something real: do it only if you mean to)` : line;
|
|
45
|
+
}
|
|
46
|
+
function gestureBeat(step) {
|
|
35
47
|
const cap = step.caption;
|
|
36
48
|
const named = cap ? `${cap}: ` : "";
|
|
37
49
|
switch (step.do) {
|
|
50
|
+
case "expect":
|
|
51
|
+
return `${named}Check that ${sayCondition(step)}`;
|
|
52
|
+
case "await":
|
|
53
|
+
return `${named}Wait until ${sayCondition({ ...step.until, id: step.id })} (off camera: pause the recording meanwhile)`;
|
|
54
|
+
case "download":
|
|
55
|
+
return step.selector !== void 0 ? `${named}Download the file ${sayStepTarget({ selector: step.selector, id: step.id })} gives${step.as ? `, as ${step.as}` : ""}` : `${named}Download what ${sayTarget(step.src ?? "")} plays${step.as ? `, as ${step.as}` : ""}`;
|
|
38
56
|
case "wait":
|
|
39
57
|
return null;
|
|
40
58
|
case "hover":
|
|
@@ -110,4 +128,4 @@ export {
|
|
|
110
128
|
sayTarget,
|
|
111
129
|
shotList
|
|
112
130
|
};
|
|
113
|
-
//# sourceMappingURL=shotList-
|
|
131
|
+
//# sourceMappingURL=shotList-SCA234OS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugin/shotList.ts"],"sourcesContent":["/**\n * The shot list: an `actions.json` said in words, for a person who will\n * record it by hand. The last rung of the session ladder is \"the human\n * records, the agent cuts\", and an agent that falls to it should hand over\n * more than an apology: the flow it worked out, as numbered beats with the\n * pace it wanted, so its knowledge survives the hop to a human. The take\n * comes back through the ordinary handoff and the agent cuts it.\n *\n * Pure: an ActionsFile in, lines out. Selectors are said as what they name\n * where the script says (an id, a caption, a text= locator), and as the\n * selector itself where it does not: a person reading `#filter-late` can\n * find it; a person reading nothing cannot.\n */\nimport type { ActionStep, ActionsFile } from './actions'\nimport { askedMs } from './pace'\n\nexport interface ShotBeat {\n n: number\n /** what to do, in words */\n line: string\n /** how long to hold after, in seconds, when the script asks for a hold */\n holdS?: number\n}\n\nexport interface ShotList {\n url?: string\n viewport?: { width: number; height: number }\n beats: ShotBeat[]\n /** the take's asked length, from the script's own pacing */\n aboutS: number\n setup: number\n}\n\n/** A selector as a person reads it: the text it names, or the selector itself. */\nexport function sayTarget(selector: string): string {\n const text = /^text=(['\"]?)(.+?)\\1$/.exec(selector)\n if (text) return `\"${text[2]}\"`\n const has = /:has-text\\((['\"])(.+?)\\1\\)/.exec(selector)\n if (has) return `\"${has[2]}\"`\n const role = /getByRole\\(['\"](\\w+)['\"],\\s*\\{\\s*name:\\s*(['\"])(.+?)\\2/.exec(\n selector,\n )\n if (role) return `the ${role[1]} \"${role[3]}\"`\n const label = /\\[aria-label=(['\"])(.+?)\\1\\]/.exec(selector)\n if (label) return `\"${label[2]}\"`\n const ph = /\\[placeholder=(['\"])(.+?)\\1\\]/.exec(selector)\n if (ph) return `the \"${ph[2]}\" field`\n return `\\`${selector}\\``\n}\n\nconst s1 = (ms: number) => `${Math.round(ms / 100) / 10}`.replace(/\\.0$/, '')\n\n/** A step's id, said as a name when it reads as one (`late`, `new-order`, `openBilling`). */\nexport function sayId(id: string | undefined): string | null {\n if (!id || /^\\d+$/.test(id) || id.length < 3) return null\n const words = id\n .replace(/([a-z])([A-Z])/g, '$1 $2')\n .replace(/[-_]+/g, ' ')\n .toLowerCase()\n .trim()\n return words.length >= 3 ? words : null\n}\n\n/** What a step points at, for a person: the words the selector names, else the id's, else the selector. */\nfunction sayStepTarget(step: { selector: string; id?: string }): string {\n const bySelector = sayTarget(step.selector)\n if (!bySelector.startsWith('`')) return bySelector\n const byId = sayId(step.id)\n return byId ? `${byId} (${bySelector})` : bySelector\n}\n\n/** A page condition, for a person: what they should see before going on. */\nfunction sayCondition(c: {\n selector?: string\n text?: string\n gone?: string\n enabled?: boolean\n id?: string\n}): string {\n if (c.text !== undefined) return `\"${c.text}\" shows on the page`\n if (c.gone !== undefined) return `${sayTarget(c.gone)} is gone`\n const target = sayStepTarget({ selector: c.selector ?? '', id: c.id })\n if (c.enabled === true) return `${target} is enabled`\n if (c.enabled === false) return `${target} is disabled`\n return `${target} is showing`\n}\n\nfunction beatOf(step: ActionStep): string | null {\n const line = gestureBeat(step)\n // A step that spends something real is marked where a person reads it.\n return line && step.guard\n ? `${line} (this spends something real: do it only if you mean to)`\n : line\n}\n\nfunction gestureBeat(step: ActionStep): string | null {\n const cap = step.caption\n const named = cap ? `${cap}: ` : ''\n switch (step.do) {\n case 'expect':\n return `${named}Check that ${sayCondition(step)}`\n case 'await':\n return `${named}Wait until ${sayCondition({ ...step.until, id: step.id })} (off camera: pause the recording meanwhile)`\n case 'download':\n return step.selector !== undefined\n ? `${named}Download the file ${sayStepTarget({ selector: step.selector, id: step.id })} gives${step.as ? `, as ${step.as}` : ''}`\n : `${named}Download what ${sayTarget(step.src ?? '')} plays${step.as ? `, as ${step.as}` : ''}`\n case 'wait':\n return null\n case 'hover':\n return `${named}Rest the pointer on ${sayStepTarget(step)}`\n case 'click':\n return `${named}Click ${sayStepTarget(step)}`\n case 'type':\n return `${named}${step.replace ? 'Replace what is in' : 'Type'}${step.replace ? ` ${sayStepTarget(step)} with \"${step.text}\"` : ` \"${step.text}\" into ${sayStepTarget(step)}`}${step.at === 'end' ? ', at the end' : step.at === 'start' ? ', at the start' : ''}`\n case 'press':\n return `${named}Press ${step.key}${step.selector ? ` in ${sayStepTarget(step as { selector: string; id?: string })}` : ''}`\n case 'scroll':\n return `${named}Scroll ${step.dy < 0 ? 'up' : 'down'} ${step.dy < 0 ? 'a little' : 'a little'}`\n case 'move':\n return `${named}Move the pointer to the ${step.y < 360 ? 'upper' : 'lower'} ${step.x < 640 ? 'left' : 'right'}`\n case 'drag':\n return `${named}Drag ${step.selector ? sayStepTarget(step as { selector: string; id?: string }) : 'from the start point'} across`\n }\n}\n\nexport function shotList(actions: ActionsFile): ShotList {\n const beats: ShotBeat[] = []\n let pendingHold = 0\n let total = 0\n for (const step of actions.steps) {\n total += askedMs(step)\n if (step.do === 'wait') {\n // A wait after a beat is that beat's hold; a leading wait is the\n // settle before the first, which a person does without being told.\n if (beats.length) {\n const last = beats[beats.length - 1]\n last.holdS = (last.holdS ?? 0) + step.ms / 1000\n } else pendingHold += step.ms\n continue\n }\n const line = beatOf(step)\n if (!line) continue\n const beat: ShotBeat = { n: beats.length + 1, line }\n if (step.do === 'hover') beat.holdS = askedMs(step) / 1000\n beats.push(beat)\n }\n void pendingHold\n return {\n url: actions.url,\n viewport: actions.viewport,\n beats,\n // gestures the recorder adds around each ask: about a second a beat\n aboutS: Math.round((total + beats.length * 1000) / 1000),\n setup: actions.setup?.length ?? 0,\n }\n}\n\n/** The list as the person reads it. */\nexport function formatShotList(list: ShotList): string {\n const out: string[] = []\n out.push(\n `Record this with the vosso extension in your own signed-in browser, about ${list.aboutS} seconds${list.viewport ? `, window about ${list.viewport.width}×${list.viewport.height}` : ''}.`,\n )\n if (list.url)\n out.push(`Start on ${list.url}, signed in, with the page settled.`)\n if (list.setup)\n out.push(\n `Before you press record: the script's ${list.setup} setup step${list.setup === 1 ? '' : 's'} (sign in, dismiss banners) are yours to do first; they are not part of the take.`,\n )\n out.push('')\n for (const b of list.beats) {\n const hold =\n b.holdS && b.holdS >= 0.4 ? ` Hold ${s1(b.holdS * 1000)} s.` : ''\n out.push(`${b.n}. ${b.line}.${hold}`)\n }\n out.push('')\n out.push(\n 'Move at a talking pace, let each screen settle before the next beat, and end on the finished state. Press the icon again to stop; the take opens in the studio and saves to your shelf.',\n )\n return out.join('\\n')\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vosjs/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.78.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, deliver a release's video cuts per destination spec, and sync with vos.so. One binary, every verb, MIT.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -51,12 +51,12 @@
|
|
|
51
51
|
"acorn-walk": "^8.3.5",
|
|
52
52
|
"mediabunny": "^1.55.7",
|
|
53
53
|
"playwright": "^1.49.0",
|
|
54
|
+
"@vosjs/core": "^0.31.0",
|
|
54
55
|
"@vosjs/editor": "^1.6.0",
|
|
55
56
|
"@vosjs/elements": "^0.12.1",
|
|
56
|
-
"@vosjs/render-core": "^0.
|
|
57
|
-
"@vosjs/core": "^0.31.0",
|
|
57
|
+
"@vosjs/render-core": "^0.7.0",
|
|
58
58
|
"@vosjs/shared": "^0.7.0",
|
|
59
|
-
"@vosjs/studio-core": "^0.
|
|
59
|
+
"@vosjs/studio-core": "^0.43.0",
|
|
60
60
|
"@vosjs/timeline": "^0.5.0",
|
|
61
61
|
"@vosjs/tween": "^0.8.3"
|
|
62
62
|
},
|
|
@@ -202,6 +202,11 @@
|
|
|
202
202
|
"type": "string",
|
|
203
203
|
"minLength": 1,
|
|
204
204
|
"description": "a selector whose words the recorder keeps once the step has settled (meta.steps[].text, trimmed, at most 2 KB): the take's own payload, which a layer quotes instead of a replay; on a click, what the click opened"
|
|
205
|
+
},
|
|
206
|
+
"guard": {
|
|
207
|
+
"type": "string",
|
|
208
|
+
"enum": ["spend"],
|
|
209
|
+
"description": "the step costs something real (credits, a purchase, a message sent): `vos record --dry-run` hovers it and never presses it, and `vos record` presses it only with `--confirm <id>`, refusing before any capture otherwise. Needs an id. A hosted take refuses a guarded step"
|
|
205
210
|
}
|
|
206
211
|
}
|
|
207
212
|
},
|
|
@@ -259,6 +264,11 @@
|
|
|
259
264
|
"type": "string",
|
|
260
265
|
"enum": ["end", "start"],
|
|
261
266
|
"description": "where the caret goes after the focusing click, before the first character: a click lands it where the pointer hit, and a code editor line is typed at its end"
|
|
267
|
+
},
|
|
268
|
+
"guard": {
|
|
269
|
+
"type": "string",
|
|
270
|
+
"enum": ["spend"],
|
|
271
|
+
"description": "the step costs something real (credits, a purchase, a message sent): `vos record --dry-run` hovers it and never presses it, and `vos record` presses it only with `--confirm <id>`, refusing before any capture otherwise. Needs an id. A hosted take refuses a guarded step"
|
|
262
272
|
}
|
|
263
273
|
}
|
|
264
274
|
},
|
|
@@ -313,6 +323,11 @@
|
|
|
313
323
|
"type": "string",
|
|
314
324
|
"minLength": 1,
|
|
315
325
|
"description": "a selector whose words the recorder keeps once the step has settled (meta.steps[].text, trimmed, at most 2 KB): the take's own payload, which a layer quotes instead of a replay; on a click, what the click opened"
|
|
326
|
+
},
|
|
327
|
+
"guard": {
|
|
328
|
+
"type": "string",
|
|
329
|
+
"enum": ["spend"],
|
|
330
|
+
"description": "the step costs something real (credits, a purchase, a message sent): `vos record --dry-run` hovers it and never presses it, and `vos record` presses it only with `--confirm <id>`, refusing before any capture otherwise. Needs an id. A hosted take refuses a guarded step"
|
|
316
331
|
}
|
|
317
332
|
}
|
|
318
333
|
},
|
|
@@ -431,6 +446,183 @@
|
|
|
431
446
|
"description": "a selector whose words the recorder keeps once the step has settled (meta.steps[].text, trimmed, at most 2 KB): the take's own payload, which a layer quotes instead of a replay; on a click, what the click opened"
|
|
432
447
|
}
|
|
433
448
|
}
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
"type": "object",
|
|
452
|
+
"required": ["do"],
|
|
453
|
+
"additionalProperties": false,
|
|
454
|
+
"description": "Check the page is as the flow expects, on camera, with no cursor move: exactly one of selector (visible; with enabled, enabled or disabled), text (some visible text contains it) or gone (no longer visible). A condition that never holds is a skip with its reason, which --strict turns into exit 2.",
|
|
455
|
+
"oneOf": [
|
|
456
|
+
{
|
|
457
|
+
"required": ["selector"]
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
"required": ["text"]
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
"required": ["gone"]
|
|
464
|
+
}
|
|
465
|
+
],
|
|
466
|
+
"properties": {
|
|
467
|
+
"do": {
|
|
468
|
+
"const": "expect"
|
|
469
|
+
},
|
|
470
|
+
"selector": {
|
|
471
|
+
"type": "string",
|
|
472
|
+
"minLength": 1
|
|
473
|
+
},
|
|
474
|
+
"text": {
|
|
475
|
+
"type": "string",
|
|
476
|
+
"minLength": 1
|
|
477
|
+
},
|
|
478
|
+
"gone": {
|
|
479
|
+
"type": "string",
|
|
480
|
+
"minLength": 1
|
|
481
|
+
},
|
|
482
|
+
"enabled": {
|
|
483
|
+
"type": "boolean",
|
|
484
|
+
"description": "with selector: wait for the element to be enabled (true) or disabled (false)"
|
|
485
|
+
},
|
|
486
|
+
"timeout": {
|
|
487
|
+
"type": "number",
|
|
488
|
+
"exclusiveMinimum": 0,
|
|
489
|
+
"default": 5,
|
|
490
|
+
"description": "seconds to wait for the condition"
|
|
491
|
+
},
|
|
492
|
+
"id": {
|
|
493
|
+
"type": "string",
|
|
494
|
+
"minLength": 1,
|
|
495
|
+
"description": "Optional stable identity: doc.json anchors name a step by this id (else by index), so a step survives moving or gaining neighbours across script edits. Unique across steps when present."
|
|
496
|
+
},
|
|
497
|
+
"caption": {
|
|
498
|
+
"type": "string",
|
|
499
|
+
"maxLength": 80,
|
|
500
|
+
"description": "a beat's caption: vos deliver lands it as a lower-third at this step's moment on cuts that take words (feed cuts, the demo), never on a loop"
|
|
501
|
+
},
|
|
502
|
+
"read": {
|
|
503
|
+
"type": "string",
|
|
504
|
+
"minLength": 1,
|
|
505
|
+
"description": "a selector whose words the recorder keeps once the step has settled (meta.steps[].text, trimmed, at most 2 KB): the take's own payload, which a layer quotes instead of a replay; on a click, what the click opened"
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
"type": "object",
|
|
511
|
+
"required": ["do", "until"],
|
|
512
|
+
"additionalProperties": false,
|
|
513
|
+
"description": "Wait OFF CAMERA for something slow (a render, a generated result): the capture stops, the condition is polled, and the capture resumes when it holds, so the footage has no gap and no frozen stretch. The cut lands in meta.skips[] ({ step, id, at, ms }) and becomes a segment boundary in the planned doc.json. A rehearsal waits for real and prints the time.",
|
|
514
|
+
"properties": {
|
|
515
|
+
"do": {
|
|
516
|
+
"const": "await"
|
|
517
|
+
},
|
|
518
|
+
"until": {
|
|
519
|
+
"type": "object",
|
|
520
|
+
"additionalProperties": false,
|
|
521
|
+
"minProperties": 1,
|
|
522
|
+
"maxProperties": 1,
|
|
523
|
+
"properties": {
|
|
524
|
+
"selector": {
|
|
525
|
+
"type": "string",
|
|
526
|
+
"minLength": 1
|
|
527
|
+
},
|
|
528
|
+
"text": {
|
|
529
|
+
"type": "string",
|
|
530
|
+
"minLength": 1
|
|
531
|
+
},
|
|
532
|
+
"gone": {
|
|
533
|
+
"type": "string",
|
|
534
|
+
"minLength": 1
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
},
|
|
538
|
+
"timeout": {
|
|
539
|
+
"type": "number",
|
|
540
|
+
"exclusiveMinimum": 0,
|
|
541
|
+
"default": 600,
|
|
542
|
+
"description": "the most seconds to wait"
|
|
543
|
+
},
|
|
544
|
+
"poll": {
|
|
545
|
+
"type": "number",
|
|
546
|
+
"exclusiveMinimum": 0,
|
|
547
|
+
"default": 2,
|
|
548
|
+
"description": "seconds between looks"
|
|
549
|
+
},
|
|
550
|
+
"reload": {
|
|
551
|
+
"type": "boolean",
|
|
552
|
+
"default": false,
|
|
553
|
+
"description": "reload the page between looks"
|
|
554
|
+
},
|
|
555
|
+
"onTimeout": {
|
|
556
|
+
"type": "string",
|
|
557
|
+
"enum": ["fail", "continue"],
|
|
558
|
+
"default": "fail",
|
|
559
|
+
"description": "fail: the take stops there, exit 1; continue: the capture resumes and the skip records timedOut"
|
|
560
|
+
},
|
|
561
|
+
"id": {
|
|
562
|
+
"type": "string",
|
|
563
|
+
"minLength": 1,
|
|
564
|
+
"description": "Optional stable identity: doc.json anchors name a step by this id (else by index), so a step survives moving or gaining neighbours across script edits. Unique across steps when present."
|
|
565
|
+
},
|
|
566
|
+
"caption": {
|
|
567
|
+
"type": "string",
|
|
568
|
+
"maxLength": 80,
|
|
569
|
+
"description": "a beat's caption: vos deliver lands it as a lower-third at this step's moment on cuts that take words (feed cuts, the demo), never on a loop"
|
|
570
|
+
},
|
|
571
|
+
"read": {
|
|
572
|
+
"type": "string",
|
|
573
|
+
"minLength": 1,
|
|
574
|
+
"description": "a selector whose words the recorder keeps once the step has settled (meta.steps[].text, trimmed, at most 2 KB): the take's own payload, which a layer quotes instead of a replay; on a click, what the click opened"
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
},
|
|
578
|
+
{
|
|
579
|
+
"type": "object",
|
|
580
|
+
"required": ["do"],
|
|
581
|
+
"additionalProperties": false,
|
|
582
|
+
"description": "Keep a file the page makes, in the take's outputs/: selector clicks a control and waits up to 30 s for the browser's download; src fetches the currentSrc of a video, audio or img element with the page's own cookies. Listed in meta.outputs[] ({ step, id, name, bytes, contentType }). A download that never arrives is a skip with its reason. A hosted take refuses a download.",
|
|
583
|
+
"oneOf": [
|
|
584
|
+
{
|
|
585
|
+
"required": ["selector"]
|
|
586
|
+
},
|
|
587
|
+
{
|
|
588
|
+
"required": ["src"]
|
|
589
|
+
}
|
|
590
|
+
],
|
|
591
|
+
"properties": {
|
|
592
|
+
"do": {
|
|
593
|
+
"const": "download"
|
|
594
|
+
},
|
|
595
|
+
"selector": {
|
|
596
|
+
"type": "string",
|
|
597
|
+
"minLength": 1
|
|
598
|
+
},
|
|
599
|
+
"src": {
|
|
600
|
+
"type": "string",
|
|
601
|
+
"minLength": 1,
|
|
602
|
+
"description": "a selector (the same grammar as every other step) of a video, audio or img element"
|
|
603
|
+
},
|
|
604
|
+
"as": {
|
|
605
|
+
"type": "string",
|
|
606
|
+
"minLength": 1,
|
|
607
|
+
"pattern": "^(?!\\.)(?!.*\\.\\.)[^/\\\\]+$",
|
|
608
|
+
"description": "the file name inside outputs/ (a plain name: no path separator, no \"..\"); absent, the name the page suggested"
|
|
609
|
+
},
|
|
610
|
+
"id": {
|
|
611
|
+
"type": "string",
|
|
612
|
+
"minLength": 1,
|
|
613
|
+
"description": "Optional stable identity: doc.json anchors name a step by this id (else by index), so a step survives moving or gaining neighbours across script edits. Unique across steps when present."
|
|
614
|
+
},
|
|
615
|
+
"caption": {
|
|
616
|
+
"type": "string",
|
|
617
|
+
"maxLength": 80,
|
|
618
|
+
"description": "a beat's caption: vos deliver lands it as a lower-third at this step's moment on cuts that take words (feed cuts, the demo), never on a loop"
|
|
619
|
+
},
|
|
620
|
+
"read": {
|
|
621
|
+
"type": "string",
|
|
622
|
+
"minLength": 1,
|
|
623
|
+
"description": "a selector whose words the recorder keeps once the step has settled (meta.steps[].text, trimmed, at most 2 KB): the take's own payload, which a layer quotes instead of a replay; on a click, what the click opened"
|
|
624
|
+
}
|
|
625
|
+
}
|
|
434
626
|
}
|
|
435
627
|
]
|
|
436
628
|
}
|
package/schema/doc.schema.json
CHANGED
|
@@ -957,14 +957,38 @@
|
|
|
957
957
|
"start": {
|
|
958
958
|
"type": "number",
|
|
959
959
|
"minimum": 0,
|
|
960
|
-
"description": "OUTPUT seconds"
|
|
960
|
+
"description": "OUTPUT seconds. With an `anchor` it is the fallback, used when the anchor cannot resolve"
|
|
961
|
+
},
|
|
962
|
+
"anchor": {
|
|
963
|
+
"type": "object",
|
|
964
|
+
"required": ["step"],
|
|
965
|
+
"additionalProperties": false,
|
|
966
|
+
"description": "When the layer starts, as a recorder step: the lowering maps the step's moment (meta.steps, SOURCE seconds of its media) through the segments, speed spans and freezes exactly as a source-anchored span is mapped, and adds `offset`. A trim, a speed change or a re-record moves the layer with its step; `start` is the fallback when the step is missing, skipped or cut out (validate says which), and `duration` stays the layer's own. A text layer's {elapsed} fills with the anchored step's off-camera wait (the meta.skips entry naming the step, else its offCameraMs; a step that waited for nothing reads the nearest earlier wait on its media) as a rounded duration, like \"12 minutes\". Not the re-record `anchor` on spans, which the lowering never reads",
|
|
967
|
+
"properties": {
|
|
968
|
+
"step": {
|
|
969
|
+
"type": ["string", "integer"],
|
|
970
|
+
"description": "the step: its actions.json `id` (meta.steps[].id), else its index"
|
|
971
|
+
},
|
|
972
|
+
"media": {
|
|
973
|
+
"type": "string",
|
|
974
|
+
"description": "whose steps: a media[].id (absent = the primary)"
|
|
975
|
+
},
|
|
976
|
+
"at": {
|
|
977
|
+
"enum": ["start", "end"],
|
|
978
|
+
"description": "which edge of the step is its moment (default start)"
|
|
979
|
+
},
|
|
980
|
+
"offset": {
|
|
981
|
+
"type": "number",
|
|
982
|
+
"description": "OUTPUT seconds after the step's moment (negative = before; default 0)"
|
|
983
|
+
}
|
|
984
|
+
}
|
|
961
985
|
},
|
|
962
986
|
"duration": {
|
|
963
987
|
"type": "number",
|
|
964
988
|
"exclusiveMinimum": 0
|
|
965
989
|
},
|
|
966
990
|
"text": {
|
|
967
|
-
"description": "the words; \\n breaks lines. A string, or a list of RUNS when parts of it are set differently: each run is a piece of text and the fields in which it departs from the layer's style. Example: [{ \"text\": \"Ship \" }, { \"text\": \"faster\", \"weight\": 700, \"underline\": true }]. There is no markup in the words: an asterisk is an asterisk. A run may hold \\n, a style may start and end anywhere, and a word-by-word reveal keeps every word in its own style",
|
|
991
|
+
"description": "the words; \\n breaks lines. On an anchored layer, {elapsed} fills with the anchored step's off-camera wait. A string, or a list of RUNS when parts of it are set differently: each run is a piece of text and the fields in which it departs from the layer's style. Example: [{ \"text\": \"Ship \" }, { \"text\": \"faster\", \"weight\": 700, \"underline\": true }]. There is no markup in the words: an asterisk is an asterisk. A run may hold \\n, a style may start and end anywhere, and a word-by-word reveal keeps every word in its own style",
|
|
968
992
|
"oneOf": [
|
|
969
993
|
{ "type": "string" },
|
|
970
994
|
{
|
|
@@ -1 +0,0 @@
|
|
|
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 video destinations (YouTube, X, Shorts/LinkedIn, GitHub) + 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: 'ingest',\n summary:\n 'a take from a recording someone else made, with its cursor track from a trace beside it (Playwright trace.zip, stamped records, CSV); without one nothing is planned',\n },\n {\n name: 'port',\n summary:\n 'bring a page, a HyperFrames or a Remotion piece: inventory (its words, colours, faces, media, scenes) then scaffold (a data-first program.mjs to translate the motion into)',\n },\n {\n name: 'build',\n summary:\n 'program.mjs (real functions) → config.json, refusing what cannot run on its own (module-scope reads, syntax the page cannot parse, non-JSON data)',\n },\n {\n name: 'compare',\n summary:\n \"a program against the source's own render: per-frame SSIM and source | vos | difference sheets; exits 1 when any frame is under the threshold\",\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:\n 'your files: push or import one, list them (assets ls), see storage (assets usage) and what uses a file (assets why)',\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,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,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,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,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA,EAAE,MAAM,UAAU,SAAS,mCAAmC;AAAA,EAChE;AACF;","names":[]}
|