@vosjs/cli 0.8.4 → 0.9.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.
@@ -0,0 +1,210 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://vos.so/schemas/actions.schema.json",
4
+ "title": "vosso actions script",
5
+ "description": "Declarative browser flow executed by `vos record` \u2014 the recipe an agent writes after exploring a site. The recorder synthesizes the cursor track from these steps.",
6
+ "type": "object",
7
+ "required": ["steps"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "url": {
11
+ "type": "string",
12
+ "format": "uri",
13
+ "description": "Page to record (overridable with --url)."
14
+ },
15
+ "viewport": {
16
+ "type": "object",
17
+ "required": ["width", "height"],
18
+ "additionalProperties": false,
19
+ "properties": {
20
+ "width": {
21
+ "type": "integer",
22
+ "minimum": 320,
23
+ "default": 1280
24
+ },
25
+ "height": {
26
+ "type": "integer",
27
+ "minimum": 240,
28
+ "default": 720
29
+ }
30
+ }
31
+ },
32
+ "steps": {
33
+ "type": "array",
34
+ "minItems": 1,
35
+ "items": {
36
+ "oneOf": [
37
+ {
38
+ "type": "object",
39
+ "required": ["do", "ms"],
40
+ "additionalProperties": false,
41
+ "properties": {
42
+ "do": {
43
+ "const": "wait"
44
+ },
45
+ "ms": {
46
+ "type": "number",
47
+ "minimum": 0
48
+ },
49
+ "id": {
50
+ "type": "string",
51
+ "minLength": 1,
52
+ "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."
53
+ }
54
+ }
55
+ },
56
+ {
57
+ "type": "object",
58
+ "required": ["do", "selector"],
59
+ "additionalProperties": false,
60
+ "properties": {
61
+ "do": {
62
+ "const": "hover"
63
+ },
64
+ "selector": {
65
+ "type": "string"
66
+ },
67
+ "ms": {
68
+ "type": "number",
69
+ "minimum": 0,
70
+ "default": 700,
71
+ "description": "Dwell \u2014 parked cursor becomes a zoom signal."
72
+ },
73
+ "id": {
74
+ "type": "string",
75
+ "minLength": 1,
76
+ "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."
77
+ }
78
+ }
79
+ },
80
+ {
81
+ "type": "object",
82
+ "required": ["do", "selector"],
83
+ "additionalProperties": false,
84
+ "properties": {
85
+ "do": {
86
+ "const": "click"
87
+ },
88
+ "selector": {
89
+ "type": "string"
90
+ },
91
+ "id": {
92
+ "type": "string",
93
+ "minLength": 1,
94
+ "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."
95
+ }
96
+ }
97
+ },
98
+ {
99
+ "type": "object",
100
+ "required": ["do", "selector", "text"],
101
+ "additionalProperties": false,
102
+ "description": "Typing is a zoom signal \u2014 a type step earns a held frame on its field (the click into it opens the span, the camera releases after the last character). ~0.6s+ of typing qualifies, so pace delayMs like a person (60-90ms) for a camera moment.",
103
+ "properties": {
104
+ "do": {
105
+ "const": "type"
106
+ },
107
+ "selector": {
108
+ "type": "string"
109
+ },
110
+ "text": {
111
+ "type": "string"
112
+ },
113
+ "delayMs": {
114
+ "type": "number",
115
+ "minimum": 0,
116
+ "default": 40
117
+ },
118
+ "id": {
119
+ "type": "string",
120
+ "minLength": 1,
121
+ "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."
122
+ }
123
+ }
124
+ },
125
+ {
126
+ "type": "object",
127
+ "required": ["do", "dy"],
128
+ "additionalProperties": false,
129
+ "properties": {
130
+ "do": {
131
+ "const": "scroll"
132
+ },
133
+ "dy": {
134
+ "type": "number"
135
+ },
136
+ "id": {
137
+ "type": "string",
138
+ "minLength": 1,
139
+ "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."
140
+ }
141
+ }
142
+ },
143
+ {
144
+ "type": "object",
145
+ "required": ["do", "x", "y"],
146
+ "additionalProperties": false,
147
+ "properties": {
148
+ "do": {
149
+ "const": "move"
150
+ },
151
+ "x": {
152
+ "type": "number",
153
+ "minimum": 0
154
+ },
155
+ "y": {
156
+ "type": "number",
157
+ "minimum": 0
158
+ },
159
+ "id": {
160
+ "type": "string",
161
+ "minLength": 1,
162
+ "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."
163
+ }
164
+ }
165
+ },
166
+ {
167
+ "type": "object",
168
+ "required": ["do", "tx", "ty"],
169
+ "additionalProperties": false,
170
+ "description": "Press-move-release: drag an element, slide a range input, move a clip. Start = selector center when given, else (x, y); end = (tx, ty), eased over ms.",
171
+ "properties": {
172
+ "do": {
173
+ "const": "drag"
174
+ },
175
+ "selector": {
176
+ "type": "string"
177
+ },
178
+ "x": {
179
+ "type": "number",
180
+ "minimum": 0
181
+ },
182
+ "y": {
183
+ "type": "number",
184
+ "minimum": 0
185
+ },
186
+ "tx": {
187
+ "type": "number",
188
+ "minimum": 0
189
+ },
190
+ "ty": {
191
+ "type": "number",
192
+ "minimum": 0
193
+ },
194
+ "ms": {
195
+ "type": "number",
196
+ "minimum": 0,
197
+ "default": 700
198
+ },
199
+ "id": {
200
+ "type": "string",
201
+ "minLength": 1,
202
+ "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."
203
+ }
204
+ }
205
+ }
206
+ ]
207
+ }
208
+ }
209
+ }
210
+ }
@@ -0,0 +1,168 @@
1
+ {
2
+ "$comment": "Per-channel launch-asset specs \u2014 the data the launch-kit skill loops over (mirrored as references/channel-specs.md in vosjs/skills; update together). Verified against official platform docs 2026-08-04; platform specs drift, re-verify quarterly. Image specs carry `genre`: 'screenshot' = real UI from the take (store policy demands real UX); 'card' = a composed cover \u2014 rendered from the poster program when one is in hand.",
3
+ "version": 1,
4
+ "verified": "2026-08-04",
5
+ "specs": [
6
+ {
7
+ "channel": "youtube",
8
+ "asset": "main-demo",
9
+ "kind": "video",
10
+ "w": 1920,
11
+ "h": 1080,
12
+ "minSeconds": 60,
13
+ "maxSeconds": 120,
14
+ "format": "mp4 (H.264+AAC)",
15
+ "notes": "Captions burned in. The same public upload serves the Chrome Web Store promo video and Product Hunt video (both take YouTube URLs only)."
16
+ },
17
+ {
18
+ "channel": "x",
19
+ "asset": "feed-cut",
20
+ "kind": "video",
21
+ "w": 1920,
22
+ "h": 1080,
23
+ "minSeconds": 30,
24
+ "maxSeconds": 140,
25
+ "maxBytes": 536870912,
26
+ "format": "mp4 (H.264+AAC ONLY \u2014 HEVC/VP9/AV1 rejected)",
27
+ "notes": "30\u201360s plays best; 140s/512MB is the free-tier ceiling. 1:1 also allowed. Native upload, never a link post."
28
+ },
29
+ {
30
+ "channel": "shorts-linkedin",
31
+ "asset": "vertical-cut",
32
+ "kind": "video",
33
+ "w": 1080,
34
+ "h": 1920,
35
+ "minSeconds": 30,
36
+ "maxSeconds": 90,
37
+ "format": "mp4 (H.264+AAC)",
38
+ "notes": "Critical text inside a centered ~900\u00d71160 safe zone \u2014 platform chrome covers the rest. Serves YouTube Shorts and LinkedIn native vertical."
39
+ },
40
+ {
41
+ "channel": "github",
42
+ "asset": "readme-loop",
43
+ "kind": "video",
44
+ "w": 1920,
45
+ "h": 1080,
46
+ "minSeconds": 10,
47
+ "maxSeconds": 20,
48
+ "maxBytes": 10485760,
49
+ "format": "mp4 (H.264)",
50
+ "notes": "\u226410MB is the free-plan attachment ceiling; two-pass target bitrate from duration."
51
+ },
52
+ {
53
+ "channel": "youtube",
54
+ "asset": "thumbnail",
55
+ "kind": "image",
56
+ "w": 1280,
57
+ "h": 720,
58
+ "maxBytes": 2097152,
59
+ "format": "png|jpg",
60
+ "notes": "",
61
+ "genre": "card"
62
+ },
63
+ {
64
+ "channel": "cws",
65
+ "asset": "screenshot",
66
+ "kind": "image",
67
+ "w": 1280,
68
+ "h": 800,
69
+ "count": "1-5",
70
+ "format": "png|jpg",
71
+ "notes": "Real UX only \u2014 misleading listing images are a removal-grade violation. Full bleed, square corners.",
72
+ "genre": "screenshot"
73
+ },
74
+ {
75
+ "channel": "cws",
76
+ "asset": "small-promo-tile",
77
+ "kind": "image",
78
+ "w": 440,
79
+ "h": 280,
80
+ "format": "png|jpg",
81
+ "notes": "Listings without one rank lower. No text; fill the region; subject centered.",
82
+ "genre": "card"
83
+ },
84
+ {
85
+ "channel": "cws",
86
+ "asset": "marquee",
87
+ "kind": "image",
88
+ "w": 1400,
89
+ "h": 560,
90
+ "format": "png|jpg",
91
+ "notes": "Carousel eligibility.",
92
+ "genre": "card"
93
+ },
94
+ {
95
+ "channel": "cws",
96
+ "asset": "icon",
97
+ "kind": "image",
98
+ "w": 128,
99
+ "h": 128,
100
+ "format": "png",
101
+ "notes": "96\u00d796 art + 16px transparent padding."
102
+ },
103
+ {
104
+ "channel": "producthunt",
105
+ "asset": "thumbnail",
106
+ "kind": "image",
107
+ "w": 240,
108
+ "h": 240,
109
+ "maxBytes": 3145728,
110
+ "format": "gif|png",
111
+ "notes": "GIF animates on hover only \u2014 the first frame must stand alone.",
112
+ "genre": "card"
113
+ },
114
+ {
115
+ "channel": "producthunt",
116
+ "asset": "gallery",
117
+ "kind": "image",
118
+ "w": 1270,
119
+ "h": 760,
120
+ "count": "4-8",
121
+ "format": "png|jpg|gif",
122
+ "notes": "First image is the hero.",
123
+ "genre": "screenshot"
124
+ },
125
+ {
126
+ "channel": "x",
127
+ "asset": "feed-image",
128
+ "kind": "image",
129
+ "w": 1200,
130
+ "h": 675,
131
+ "format": "png|jpg",
132
+ "notes": "",
133
+ "genre": "card"
134
+ },
135
+ {
136
+ "channel": "linkedin",
137
+ "asset": "feed-image",
138
+ "kind": "image",
139
+ "w": 1200,
140
+ "h": 627,
141
+ "format": "png|jpg",
142
+ "notes": "1080\u00d71350 vertical also performs in the mobile feed.",
143
+ "genre": "card"
144
+ },
145
+ {
146
+ "channel": "og",
147
+ "asset": "card",
148
+ "kind": "image",
149
+ "w": 1200,
150
+ "h": 630,
151
+ "maxBytes": 1048576,
152
+ "format": "png|jpg",
153
+ "notes": "Text in the center ~1080\u00d7600. Set twitter:card=summary_large_image explicitly \u2014 og:image alone gets the small card.",
154
+ "genre": "card"
155
+ },
156
+ {
157
+ "channel": "github",
158
+ "asset": "social-preview",
159
+ "kind": "image",
160
+ "w": 1280,
161
+ "h": 640,
162
+ "maxBytes": 1048576,
163
+ "format": "png|jpg",
164
+ "notes": "Key text \u226550px from every edge.",
165
+ "genre": "card"
166
+ }
167
+ ]
168
+ }
@@ -0,0 +1,218 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://vos.so/schemas/digest.schema.json",
4
+ "title": "vosso take digest (digest.json — how an agent sees a recording)",
5
+ "description": "Written by `vos digest <take>` into <take>/digest/. One MOMENT per thing the cursor telemetry says mattered, each with a footage frame and a crop around the target, in the doc's own units: `source` extents are seconds of footage, `output` the same window through trims and speed (null when cut away), `focus`/`rect` are normalized [0..1] fractions of the video frame (the zoom cx/cy convention — copy them into a ZoomSpan). `activity` is the fraction of pixels that changed per SOURCE second. `plan` holds the planners' proposals; `proposed` names which cover each moment. Read digest.json, then sheet.png, then a crop only where you must decide.",
6
+ "type": "object",
7
+ "required": [
8
+ "digestVersion",
9
+ "take",
10
+ "units",
11
+ "moments",
12
+ "plan",
13
+ "doc",
14
+ "images"
15
+ ],
16
+ "properties": {
17
+ "digestVersion": { "type": "integer", "const": 1 },
18
+ "take": {
19
+ "type": "object",
20
+ "properties": {
21
+ "sourceDuration": {
22
+ "type": "number",
23
+ "description": "seconds of footage"
24
+ },
25
+ "outputDuration": {
26
+ "type": "number",
27
+ "description": "seconds of rendered video (trims + speed)"
28
+ },
29
+ "width": { "type": "number", "description": "cursor space (CSS px)" },
30
+ "height": { "type": "number" },
31
+ "captureWidth": { "type": ["number", "null"] },
32
+ "captureHeight": { "type": ["number", "null"] },
33
+ "frameWidth": {
34
+ "type": ["number", "null"],
35
+ "description": "decoded frame px (null with --no-frames)"
36
+ },
37
+ "frameHeight": { "type": ["number", "null"] },
38
+ "surface": { "type": "string", "enum": ["tab", "window", "monitor"] },
39
+ "producer": { "type": "string", "enum": ["extension", "cli"] },
40
+ "pageUrl": { "type": ["string", "null"] },
41
+ "pageTitle": { "type": ["string", "null"] },
42
+ "hasMic": { "type": "boolean" },
43
+ "hasSystemAudio": { "type": "boolean" },
44
+ "hasCursor": {
45
+ "type": "boolean",
46
+ "description": "false = browser-recorder take: moments are head/tail/scenes only"
47
+ },
48
+ "windowFocusedFrac": { "type": ["number", "null"] }
49
+ }
50
+ },
51
+ "units": {
52
+ "type": "object",
53
+ "description": "The unit sentences, repeated so a reader never has to guess."
54
+ },
55
+ "moments": {
56
+ "type": "array",
57
+ "items": {
58
+ "type": "object",
59
+ "required": [
60
+ "id",
61
+ "kind",
62
+ "source",
63
+ "output",
64
+ "at",
65
+ "outputAt",
66
+ "focus",
67
+ "rect",
68
+ "activity",
69
+ "proposed",
70
+ "said",
71
+ "full",
72
+ "crop"
73
+ ],
74
+ "properties": {
75
+ "id": { "type": "string", "pattern": "^m[0-9]{2,}$" },
76
+ "kind": {
77
+ "type": "string",
78
+ "enum": [
79
+ "head",
80
+ "tail",
81
+ "click",
82
+ "typing",
83
+ "scroll",
84
+ "dwell",
85
+ "idle",
86
+ "scene"
87
+ ]
88
+ },
89
+ "source": {
90
+ "type": "object",
91
+ "properties": {
92
+ "in": { "type": "number" },
93
+ "out": { "type": "number" }
94
+ },
95
+ "required": ["in", "out"]
96
+ },
97
+ "output": {
98
+ "type": ["object", "null"],
99
+ "properties": {
100
+ "in": { "type": "number" },
101
+ "out": { "type": "number" }
102
+ }
103
+ },
104
+ "at": {
105
+ "type": ["number", "null"],
106
+ "description": "SOURCE instant of the frame; null = no frame (idle)"
107
+ },
108
+ "outputAt": { "type": ["number", "null"] },
109
+ "focus": {
110
+ "type": ["object", "null"],
111
+ "properties": {
112
+ "cx": { "type": "number" },
113
+ "cy": { "type": "number" }
114
+ }
115
+ },
116
+ "rect": {
117
+ "type": ["object", "null"],
118
+ "properties": {
119
+ "x": { "type": "number" },
120
+ "y": { "type": "number" },
121
+ "w": { "type": "number" },
122
+ "h": { "type": "number" }
123
+ }
124
+ },
125
+ "clicks": { "type": "integer" },
126
+ "pings": {
127
+ "type": "integer",
128
+ "description": "typing-activity pings in the session (never key identity)"
129
+ },
130
+ "activity": {
131
+ "type": ["number", "null"],
132
+ "minimum": 0,
133
+ "maximum": 1
134
+ },
135
+ "proposed": {
136
+ "type": "object",
137
+ "properties": {
138
+ "zoom": { "type": "string" },
139
+ "speed": { "type": "string" },
140
+ "tilt": { "type": "string" }
141
+ }
142
+ },
143
+ "said": { "type": ["string", "null"] },
144
+ "full": {
145
+ "type": ["string", "null"],
146
+ "description": "the footage frame, relative to digest/"
147
+ },
148
+ "crop": {
149
+ "type": ["string", "null"],
150
+ "description": "a crop around rect/focus, relative to digest/"
151
+ },
152
+ "box": {
153
+ "type": ["object", "null"],
154
+ "description": "the crop's source box in FRAME px (not doc units)",
155
+ "properties": {
156
+ "x": { "type": "number" },
157
+ "y": { "type": "number" },
158
+ "w": { "type": "number" },
159
+ "h": { "type": "number" }
160
+ }
161
+ }
162
+ }
163
+ }
164
+ },
165
+ "activity": {
166
+ "type": ["array", "null"],
167
+ "items": { "type": "number" },
168
+ "description": "index = SOURCE second"
169
+ },
170
+ "plan": {
171
+ "type": "object",
172
+ "properties": {
173
+ "zoom": { "type": "array" },
174
+ "speed": { "type": "array" },
175
+ "tilt": { "type": "array" }
176
+ },
177
+ "description": "The three planners run fresh under the doc's own style (source:'auto' spans, ids as in doc.json)."
178
+ },
179
+ "doc": {
180
+ "type": "object",
181
+ "properties": {
182
+ "manual": {
183
+ "type": "object",
184
+ "description": "counts of human-decided spans — never re-plan these away"
185
+ },
186
+ "zoomStyle": { "type": ["string", "null"] },
187
+ "tiltStyle": { "type": ["string", "null"] }
188
+ }
189
+ },
190
+ "style": {
191
+ "type": ["object", "null"],
192
+ "description": "--style: the reference doc's style fields, reported"
193
+ },
194
+ "transcript": {
195
+ "type": ["array", "null"],
196
+ "items": {
197
+ "type": "object",
198
+ "properties": {
199
+ "start": { "type": "number" },
200
+ "end": { "type": "number" },
201
+ "text": { "type": "string" }
202
+ }
203
+ }
204
+ },
205
+ "images": {
206
+ "type": "object",
207
+ "properties": {
208
+ "full": { "type": "integer" },
209
+ "crop": { "type": "integer" },
210
+ "sheet": { "type": ["string", "null"] },
211
+ "tokensEstimateClaude": {
212
+ "type": "integer",
213
+ "description": "sum of (w×h)/750 over full + crop images — a budget hint, not a bill"
214
+ }
215
+ }
216
+ }
217
+ }
218
+ }