@vosjs/cli 0.77.1 → 0.79.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 +163 -21
- package/dist/{assetManifest-MQ7HO7RZ.js → assetManifest-U25FJER6.js} +3 -3
- package/dist/{chunk-UY2N42P2.js → chunk-4ZUHEXUX.js} +13 -4
- package/dist/chunk-4ZUHEXUX.js.map +1 -0
- package/dist/{chunk-B4U4URE3.js → chunk-J3KHIZCH.js} +466 -412
- package/dist/chunk-J3KHIZCH.js.map +1 -0
- package/dist/{chunk-2KEQ3LKH.js → chunk-OWYOJB7K.js} +22 -2
- package/dist/chunk-OWYOJB7K.js.map +1 -0
- package/dist/{chunk-IJZ3C435.js → chunk-TWAP4BKR.js} +4372 -587
- package/dist/chunk-TWAP4BKR.js.map +1 -0
- package/dist/{chunk-KDIRW72G.js → chunk-Z6TLHRFQ.js} +7 -4
- package/dist/chunk-Z6TLHRFQ.js.map +1 -0
- package/dist/cli.js +9 -8
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +41 -29
- package/dist/index.js +5 -5
- package/dist/manifest-VTOIEUHJ.js +8 -0
- package/dist/{run-UNOXIGZ3.js → run-UKWKAGDK.js} +7 -5
- package/dist/{shotList-MAQVLZBY.js → shotList-EE3S5LVF.js} +52 -7
- package/dist/shotList-EE3S5LVF.js.map +1 -0
- package/package.json +4 -4
- package/schema/actions.schema.json +489 -12
- package/schema/doc.schema.json +63 -3
- package/skills/VERSION +1 -1
- package/skills/launch-kit/SKILL.md +6 -1
- package/skills/product-video/SKILL.md +7 -0
- package/skills/vos-authoring/SKILL.md +8 -1
- package/skills/vos-create/SKILL.md +5 -0
- package/skills/vos-cut/SKILL.md +8 -0
- package/skills/vos-footage/SKILL.md +4 -0
- package/skills/vos-migrate/SKILL.md +4 -0
- package/dist/chunk-2KEQ3LKH.js.map +0 -1
- package/dist/chunk-B4U4URE3.js.map +0 -1
- package/dist/chunk-IJZ3C435.js.map +0 -1
- package/dist/chunk-KDIRW72G.js.map +0 -1
- package/dist/chunk-UY2N42P2.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-U25FJER6.js.map} +0 -0
- /package/dist/{manifest-QLQKVSML.js.map → manifest-VTOIEUHJ.js.map} +0 -0
- /package/dist/{run-UNOXIGZ3.js.map → run-UKWKAGDK.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,12 @@ 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' | 'sounds' | 'files'> & {
|
|
127
|
+
/**
|
|
128
|
+
* The actions file's directory: where a drag's path file and a paste's
|
|
129
|
+
* file are read from. Absent, a script that names one is refused.
|
|
130
|
+
*/
|
|
131
|
+
actionsDir?: string;
|
|
147
132
|
/**
|
|
148
133
|
* A ready-made context to record IN, instead of one made from `browser`:
|
|
149
134
|
* `--session <name>`, a persistent profile the person signed in to.
|
|
@@ -152,6 +137,29 @@ type RecordOpts = Omit<RecordOpts$1, 'context' | 'env' | 'platform'> & {
|
|
|
152
137
|
};
|
|
153
138
|
declare function recordTake(browser: Browser, url: string, actions: ActionsFile, paths: TakePaths, log: (msg: string) => void, opts?: RecordOpts): Promise<_vosjs_render_core_record.RecordResult>;
|
|
154
139
|
|
|
140
|
+
/** Entry point — the delegation contract for @vosjs/cli: the host forwards
|
|
141
|
+
every non-engine verb here (`vos <verb>`). The exported `manifest` (index.ts)
|
|
142
|
+
tells the host which verbs exist and how to summarize them in help. */
|
|
143
|
+
declare function run(argv: string[]): Promise<number>;
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* The verb manifest of the take pipeline and the vos.so verbs — what
|
|
147
|
+
* `vos help` lists under the engine verbs. It kept the shape a separately
|
|
148
|
+
* installed plugin once handed the host (name + host range), so a script
|
|
149
|
+
* reading it keeps working.
|
|
150
|
+
*/
|
|
151
|
+
interface PluginVerb {
|
|
152
|
+
name: string;
|
|
153
|
+
summary: string;
|
|
154
|
+
}
|
|
155
|
+
interface PluginManifest {
|
|
156
|
+
name: string;
|
|
157
|
+
/** Host versions this plugin speaks the run(argv) contract with. */
|
|
158
|
+
hostRange: string;
|
|
159
|
+
verbs: PluginVerb[];
|
|
160
|
+
}
|
|
161
|
+
declare const manifest: PluginManifest;
|
|
162
|
+
|
|
155
163
|
declare function encodeRecording(browser: Browser, takeDir: string, onProgress: (fraction: number) => void): Promise<{
|
|
156
164
|
bytes: number;
|
|
157
165
|
}>;
|
|
@@ -518,14 +526,18 @@ declare function platformOrigin(flags?: {
|
|
|
518
526
|
*/
|
|
519
527
|
declare function parseVosId(input: string): string;
|
|
520
528
|
/**
|
|
521
|
-
* The full documented ladder: explicit --key → VOS_API_KEY → the
|
|
522
|
-
*
|
|
529
|
+
* The full documented ladder: explicit --key → VOS_API_KEY → the
|
|
530
|
+
* credential `vos login` stored. A vos_rg_ remix grant is just a key here.
|
|
523
531
|
* Returns null when nothing resolves — callers decide whether auth is needed.
|
|
532
|
+
* A stored key is remembered with its origin: it is only ever SENT there
|
|
533
|
+
* (`bearerFor`).
|
|
524
534
|
*/
|
|
525
|
-
declare function resolveCredential(explicit?: string): string | null;
|
|
535
|
+
declare function resolveCredential(explicit?: string, path?: string): string | null;
|
|
526
536
|
interface ApiResult {
|
|
527
537
|
status: number;
|
|
528
538
|
body: Record<string, unknown>;
|
|
539
|
+
/** The origin that answered. */
|
|
540
|
+
origin?: string;
|
|
529
541
|
}
|
|
530
542
|
declare function apiJson(origin: string, path: string, init?: {
|
|
531
543
|
method?: string;
|
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-TWAP4BKR.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-Z6TLHRFQ.js";
|
|
27
27
|
import {
|
|
28
28
|
RECORDING_NAME,
|
|
29
29
|
loadTake,
|
|
30
30
|
pullMedia,
|
|
31
31
|
takePaths
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-4ZUHEXUX.js";
|
|
33
33
|
import {
|
|
34
34
|
apiError,
|
|
35
35
|
apiJson,
|
|
@@ -38,11 +38,11 @@ import {
|
|
|
38
38
|
readSyncState,
|
|
39
39
|
resolveCredential,
|
|
40
40
|
writeSyncState
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-J3KHIZCH.js";
|
|
42
42
|
import "./chunk-6XPFWQKP.js";
|
|
43
43
|
import {
|
|
44
44
|
manifest
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-OWYOJB7K.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-
|
|
12
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-TWAP4BKR.js";
|
|
11
|
+
import "./chunk-Z6TLHRFQ.js";
|
|
12
|
+
import "./chunk-4ZUHEXUX.js";
|
|
13
|
+
import "./chunk-J3KHIZCH.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-UKWKAGDK.js.map
|
|
@@ -4,6 +4,18 @@ import {
|
|
|
4
4
|
} from "./chunk-6XPFWQKP.js";
|
|
5
5
|
|
|
6
6
|
// src/plugin/shotList.ts
|
|
7
|
+
import { pressSequence, splitChord } from "@vosjs/render-core/record";
|
|
8
|
+
function sayChord(chord) {
|
|
9
|
+
const { mods, key } = splitChord(chord);
|
|
10
|
+
const word = (k) => k === "Mod" || k === "ControlOrMeta" ? "\u2318/Ctrl" : k === "Control" ? "Ctrl" : k === "Meta" ? "\u2318" : k === "Alt" ? "Alt/Option" : k === " " ? "Space" : k;
|
|
11
|
+
return [...mods, key].map(word).join("+");
|
|
12
|
+
}
|
|
13
|
+
function sayPoint(p) {
|
|
14
|
+
const x = p.x ?? 0;
|
|
15
|
+
const y = p.y ?? 0;
|
|
16
|
+
return `the spot at ${Math.round(x)}, ${Math.round(y)} (${y < 360 ? "upper" : "lower"} ${x < 640 ? "left" : "right"})`;
|
|
17
|
+
}
|
|
18
|
+
var thenList = (xs) => xs.length <= 1 ? xs[0] ?? "" : `${xs.slice(0, -1).join(", ")} then ${xs[xs.length - 1]}`;
|
|
7
19
|
function sayTarget(selector) {
|
|
8
20
|
const text = /^text=(['"]?)(.+?)\1$/.exec(selector);
|
|
9
21
|
if (text) return `"${text[2]}"`;
|
|
@@ -31,26 +43,58 @@ function sayStepTarget(step) {
|
|
|
31
43
|
const byId = sayId(step.id);
|
|
32
44
|
return byId ? `${byId} (${bySelector})` : bySelector;
|
|
33
45
|
}
|
|
46
|
+
function sayCondition(c) {
|
|
47
|
+
if (c.text !== void 0) return `"${c.text}" shows on the page`;
|
|
48
|
+
if (c.gone !== void 0) return `${sayTarget(c.gone)} is gone`;
|
|
49
|
+
const target = sayStepTarget({ selector: c.selector ?? "", id: c.id });
|
|
50
|
+
if (c.enabled === true) return `${target} is enabled`;
|
|
51
|
+
if (c.enabled === false) return `${target} is disabled`;
|
|
52
|
+
return `${target} is showing`;
|
|
53
|
+
}
|
|
34
54
|
function beatOf(step) {
|
|
55
|
+
const line = gestureBeat(step);
|
|
56
|
+
return line && step.guard ? `${line} (this spends something real: do it only if you mean to)` : line;
|
|
57
|
+
}
|
|
58
|
+
function gestureBeat(step) {
|
|
35
59
|
const cap = step.caption;
|
|
36
60
|
const named = cap ? `${cap}: ` : "";
|
|
37
61
|
switch (step.do) {
|
|
62
|
+
case "expect":
|
|
63
|
+
return `${named}Check that ${sayCondition(step)}`;
|
|
64
|
+
case "await":
|
|
65
|
+
return `${named}Wait until ${sayCondition({ ...step.until, id: step.id })} (off camera: pause the recording meanwhile)`;
|
|
66
|
+
case "download":
|
|
67
|
+
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
68
|
case "wait":
|
|
39
69
|
return null;
|
|
40
70
|
case "hover":
|
|
41
|
-
return `${named}Rest the pointer on ${sayStepTarget(step)}`;
|
|
42
|
-
case "click":
|
|
43
|
-
|
|
71
|
+
return `${named}Rest the pointer on ${step.selector !== void 0 ? sayStepTarget({ selector: step.selector, id: step.id }) : sayPoint(step)}`;
|
|
72
|
+
case "click": {
|
|
73
|
+
const verb = step.count === 3 ? "Triple-click" : step.count === 2 ? "Double-click" : "Click";
|
|
74
|
+
const button = step.button === "right" ? " with the right button" : step.button === "middle" ? " with the middle button" : "";
|
|
75
|
+
const target = step.selector !== void 0 ? sayStepTarget({ selector: step.selector, id: step.id }) : sayPoint(step);
|
|
76
|
+
const holding = step.modifiers?.length ? `Hold ${step.modifiers.map(sayChord).join("+")} and ${verb.toLowerCase()}` : verb;
|
|
77
|
+
return `${named}${holding} ${target}${button}`;
|
|
78
|
+
}
|
|
44
79
|
case "type":
|
|
45
80
|
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" : ""}`;
|
|
46
81
|
case "press":
|
|
47
|
-
return `${named}Press ${step.
|
|
82
|
+
return `${named}Press ${thenList(pressSequence(step).map(sayChord))}${step.selector ? ` in ${sayStepTarget(step)}` : ""}`;
|
|
83
|
+
case "paste": {
|
|
84
|
+
const what = step.text !== void 0 ? `"${step.text.length > 60 ? `${step.text.slice(0, 57)}...` : step.text}"` : `the file ${step.file}`;
|
|
85
|
+
return `${named}Copy ${what}, then paste it${step.selector ? ` into ${sayStepTarget({ selector: step.selector, id: step.id })}` : ""} (\u2318/Ctrl+V)`;
|
|
86
|
+
}
|
|
48
87
|
case "scroll":
|
|
49
88
|
return `${named}Scroll ${step.dy < 0 ? "up" : "down"} ${step.dy < 0 ? "a little" : "a little"}`;
|
|
50
89
|
case "move":
|
|
51
90
|
return `${named}Move the pointer to the ${step.y < 360 ? "upper" : "lower"} ${step.x < 640 ? "left" : "right"}`;
|
|
52
|
-
case "drag":
|
|
53
|
-
|
|
91
|
+
case "drag": {
|
|
92
|
+
const holding = step.modifiers?.length ? `Hold ${step.modifiers.map(sayChord).join("+")} and ` : "";
|
|
93
|
+
const verb = holding ? "drag" : "Drag";
|
|
94
|
+
if (step.path !== void 0)
|
|
95
|
+
return `${named}${holding}${holding ? "draw" : "Draw"} the stroke ${typeof step.path === "string" ? `in ${step.path}` : `of ${step.path.length} points`}, in one press`;
|
|
96
|
+
return `${named}${holding}${verb} ${step.selector ? sayStepTarget(step) : "from the start point"} across`;
|
|
97
|
+
}
|
|
54
98
|
}
|
|
55
99
|
}
|
|
56
100
|
function shotList(actions) {
|
|
@@ -106,8 +150,9 @@ function formatShotList(list) {
|
|
|
106
150
|
}
|
|
107
151
|
export {
|
|
108
152
|
formatShotList,
|
|
153
|
+
sayChord,
|
|
109
154
|
sayId,
|
|
110
155
|
sayTarget,
|
|
111
156
|
shotList
|
|
112
157
|
};
|
|
113
|
-
//# sourceMappingURL=shotList-
|
|
158
|
+
//# sourceMappingURL=shotList-EE3S5LVF.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'\nimport { pressSequence, splitChord } from '@vosjs/render-core/record'\n\n/** A key or a chord as a person reads it: `Mod` is ⌘ on a Mac, Ctrl elsewhere. */\nexport function sayChord(chord: string): string {\n const { mods, key } = splitChord(chord)\n const word = (k: string) =>\n k === 'Mod' || k === 'ControlOrMeta'\n ? '⌘/Ctrl'\n : k === 'Control'\n ? 'Ctrl'\n : k === 'Meta'\n ? '⌘'\n : k === 'Alt'\n ? 'Alt/Option'\n : k === ' '\n ? 'Space'\n : k\n return [...mods, key].map(word).join('+')\n}\n\n/** A viewport point as a person finds it: where it is, and the script's numbers. */\nfunction sayPoint(p: { x?: number; y?: number }): string {\n const x = p.x ?? 0\n const y = p.y ?? 0\n return `the spot at ${Math.round(x)}, ${Math.round(y)} (${y < 360 ? 'upper' : 'lower'} ${x < 640 ? 'left' : 'right'})`\n}\n\n/** A list in words: `a`, `a then b`, `a, b then c`. */\nconst thenList = (xs: string[]): string =>\n xs.length <= 1\n ? (xs[0] ?? '')\n : `${xs.slice(0, -1).join(', ')} then ${xs[xs.length - 1]}`\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 ${step.selector !== undefined ? sayStepTarget({ selector: step.selector, id: step.id }) : sayPoint(step)}`\n case 'click': {\n const verb =\n step.count === 3\n ? 'Triple-click'\n : step.count === 2\n ? 'Double-click'\n : 'Click'\n const button =\n step.button === 'right'\n ? ' with the right button'\n : step.button === 'middle'\n ? ' with the middle button'\n : ''\n const target =\n step.selector !== undefined\n ? sayStepTarget({ selector: step.selector, id: step.id })\n : sayPoint(step)\n const holding = step.modifiers?.length\n ? `Hold ${step.modifiers.map(sayChord).join('+')} and ${verb.toLowerCase()}`\n : verb\n return `${named}${holding} ${target}${button}`\n }\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 ${thenList(pressSequence(step).map(sayChord))}${step.selector ? ` in ${sayStepTarget(step as { selector: string; id?: string })}` : ''}`\n case 'paste': {\n const what =\n step.text !== undefined\n ? `\"${step.text.length > 60 ? `${step.text.slice(0, 57)}...` : step.text}\"`\n : `the file ${step.file}`\n return `${named}Copy ${what}, then paste it${step.selector ? ` into ${sayStepTarget({ selector: step.selector, id: step.id })}` : ''} (⌘/Ctrl+V)`\n }\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 const holding = step.modifiers?.length\n ? `Hold ${step.modifiers.map(sayChord).join('+')} and `\n : ''\n const verb = holding ? 'drag' : 'Drag'\n if (step.path !== undefined)\n return `${named}${holding}${holding ? 'draw' : 'Draw'} the stroke ${typeof step.path === 'string' ? `in ${step.path}` : `of ${step.path.length} points`}, in one press`\n return `${named}${holding}${verb} ${step.selector ? sayStepTarget(step as { selector: string; id?: string }) : 'from the start point'} across`\n }\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.79.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",
|
|
56
|
+
"@vosjs/render-core": "^0.8.0",
|
|
57
|
+
"@vosjs/studio-core": "^0.44.0",
|
|
55
58
|
"@vosjs/elements": "^0.12.1",
|
|
56
|
-
"@vosjs/render-core": "^0.6.0",
|
|
57
|
-
"@vosjs/core": "^0.31.0",
|
|
58
59
|
"@vosjs/shared": "^0.7.0",
|
|
59
|
-
"@vosjs/studio-core": "^0.42.3",
|
|
60
60
|
"@vosjs/timeline": "^0.5.0",
|
|
61
61
|
"@vosjs/tween": "^0.8.3"
|
|
62
62
|
},
|