autokap 1.6.2 → 1.6.4

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.
@@ -1,625 +0,0 @@
1
- # AutoKap Opcode Reference
2
-
3
- Detailed parameter documentation for all 24 opcodes. For workflow, rules, and examples, see [SKILL.md](SKILL.md).
4
-
5
- ## Common Fields (all opcodes)
6
-
7
- | Field | Type | Required | Default | Description |
8
- |-------|------|----------|---------|-------------|
9
- | `kind` | string | yes | — | Opcode type (see sections below) |
10
- | `description` | string | yes | — | Human-readable description of this step |
11
- | `postcondition` | PostconditionSpec | yes | — | Condition that must hold after execution |
12
- | `recovery` | RecoveryPolicy | yes | — | Recovery behavior on failure |
13
- | `timeoutMs` | number | yes | 15000 | Max time (ms) including recovery |
14
- | `maxFailures` | number | yes | 3 | Max recovery attempts before fatal |
15
-
16
- ### RecoveryPolicy
17
-
18
- | Field | Type | Default | Description |
19
- |-------|------|---------|-------------|
20
- | `retries` | number (0-10) | 2 | Deterministic retry attempts |
21
- | `useSelectorMemory` | boolean | true | Try known-good selectors from previous runs |
22
- | `useAltInteraction` | boolean | true | Try keyboard/JS/coordinate click |
23
- | `allowReload` | boolean | false | Reload page and retry. **Use sparingly** — loses UI state (open modals, form data). Only safe after full page transitions. |
24
- | `allowHealer` | boolean | true | Allow LLM to rewrite the failing opcode as last resort |
25
-
26
- ### SemanticTarget (optional on interaction opcodes)
27
-
28
- Fallback when CSS selector fails. The runtime resolves via Playwright semantic locators, then AKTree fuzzy matching.
29
-
30
- | Field | Type | Description |
31
- |-------|------|-------------|
32
- | `text` | string | Visible text content (substring match by default) |
33
- | `role` | string | ARIA role: `"button"`, `"link"`, `"textbox"`, `"checkbox"`, `"tab"`, `"menuitem"` |
34
- | `label` | string | `aria-label`, associated `<label>` text, or `title` attribute |
35
- | `near` | string | Nearby text for disambiguation (e.g. `"in the pricing section"`) |
36
- | `placeholder` | string | Input placeholder text |
37
- | `exact` | boolean | If `true`, match text exactly. Default: `false` (substring) |
38
-
39
- ### PostconditionSpec
40
-
41
- | Field | Type | Used by | Description |
42
- |-------|------|---------|-------------|
43
- | `type` | string | all | One of the 8 postcondition types (see SKILL.md) |
44
- | `pattern` | string | `route_matches` | URL glob pattern (`*` = segment, `**` = any path) |
45
- | `selector` | string | `element_visible`, `element_absent`, `text_contains` | CSS selector to check |
46
- | `text` | string | `text_contains` | Expected text substring |
47
- | `threshold` | number (0-1) | `screenshot_stable` | Pixel diff tolerance. Default: `0.01` |
48
- | `waitMs` | number | all except `always` | Max polling time (ms). Default: `5000` |
49
-
50
- `any_change` is verifier-backed: the runtime must observe a URL, DOM, element state, overlay, or scroll change after the action. No-op actions fail.
51
-
52
- ---
53
-
54
- ## NAVIGATE
55
-
56
- Navigate to a URL.
57
-
58
- | Param | Type | Required | Description |
59
- |-------|------|----------|-------------|
60
- | `url` | string | yes | Full URL to navigate to |
61
-
62
- **Can:** Load any URL, follow redirects, handle SPA route changes.
63
- **Cannot:** Open new tabs/windows. Use CLICK with `button: "middle"` for that.
64
-
65
- ```json
66
- { "kind": "NAVIGATE", "url": "https://app.example.com/pricing", "postcondition": { "type": "route_matches", "pattern": "/pricing" } }
67
- ```
68
-
69
- ## DISMISS_OVERLAYS
70
-
71
- Automatically dismisses cookie banners, newsletter popups, chat widgets, and age gates. Multi-pass: adapter dismissal, Escape key, close-button clicks (multilingual patterns).
72
-
73
- No additional parameters.
74
-
75
- **Can:** Handle common overlays in any language (en, fr, de, es, it patterns).
76
- **Cannot:** Dismiss overlays that require form input (e.g. age verification with date entry) or CAPTCHAs.
77
-
78
- ```json
79
- { "kind": "DISMISS_OVERLAYS", "postcondition": { "type": "overlay_dismissed" } }
80
- ```
81
-
82
- ## CLICK
83
-
84
- Click an element.
85
-
86
- | Param | Type | Required | Default | Description |
87
- |-------|------|----------|---------|-------------|
88
- | `selector` | string | yes | — | CSS selector (use `data-ak` attributes) |
89
- | `target` | SemanticTarget | no | — | Fallback for recovery chain |
90
- | `button` | `"right"` \| `"middle"` | no | left | `"right"` = context menu, `"middle"` = new tab |
91
- | `fingerprint` | string | no | — | AKTree fingerprint for fuzzy matching |
92
- | `selectorAlternates` | string[] | no | — | Alternative selectors tried in order |
93
-
94
- **Can:** Left/right/middle click, trigger navigation, open modals, toggle dropdowns.
95
- **Cannot:** Drag-and-drop, long-press, touch gestures.
96
-
97
- ```json
98
- { "kind": "CLICK", "selector": "[data-ak=\"pricing-btn\"]", "postcondition": { "type": "element_visible", "selector": "[data-ak=\"pricing-modal\"]", "waitMs": 5000 } }
99
- ```
100
-
101
- ## TYPE
102
-
103
- Type text into a form field.
104
-
105
- | Param | Type | Required | Default | Description |
106
- |-------|------|----------|---------|-------------|
107
- | `selector` | string | yes | — | CSS selector of the input/textarea |
108
- | `text` | string | yes | — | Text to type. Use `{{email}}` / `{{password}}` for credentials |
109
- | `clearFirst` | boolean | yes | true | Clear existing value before typing |
110
- | `target` | SemanticTarget | no | — | Fallback for recovery chain |
111
- | `fingerprint` | string | no | — | AKTree fingerprint |
112
- | `selectorAlternates` | string[] | no | — | Alternative selectors |
113
-
114
- **Can:** Type into text inputs, textareas, contenteditable elements. Clear existing values. Use credential placeholders.
115
- **Cannot:** Type into file inputs (use file upload instead). Paste from clipboard.
116
-
117
- ```json
118
- { "kind": "TYPE", "selector": "[data-ak=\"search-input\"]", "text": "dashboard", "clearFirst": true, "postcondition": { "type": "any_change" } }
119
- ```
120
-
121
- ## PRESS_KEY
122
-
123
- Press a keyboard key.
124
-
125
- | Param | Type | Required | Description |
126
- |-------|------|----------|-------------|
127
- | `key` | string | yes | Key name: `"Enter"`, `"Escape"`, `"Tab"`, `"ArrowDown"`, `"Backspace"`, etc. |
128
-
129
- **Can:** Submit forms (Enter), close modals (Escape), navigate focus (Tab), trigger keyboard shortcuts.
130
- **Cannot:** Key combinations (Ctrl+C, Cmd+V). For shortcuts, use the individual key name that Playwright supports.
131
-
132
- ```json
133
- { "kind": "PRESS_KEY", "key": "Enter", "postcondition": { "type": "any_change" } }
134
- ```
135
-
136
- ## WAIT_FOR
137
-
138
- Wait for an element to appear.
139
-
140
- | Param | Type | Required | Default | Description |
141
- |-------|------|----------|---------|-------------|
142
- | `selector` | string | no* | — | CSS selector to wait for |
143
- | `target` | SemanticTarget | no* | — | Semantic target to wait for |
144
- | `state` | `"visible"` \| `"attached"` | yes | — | `"visible"` = rendered and visible. `"attached"` = in DOM but may be hidden |
145
-
146
- *At least one of `selector` or `target` is required.
147
-
148
- **Can:** Wait for page content to load, modals to appear, dynamic elements to render.
149
- **Cannot:** Wait for network requests or API responses directly. Use `state: "attached"` for elements that exist in DOM but are initially hidden (e.g. lazy-loaded tabs).
150
-
151
- ```json
152
- { "kind": "WAIT_FOR", "selector": "[data-ak=\"dashboard\"]", "state": "visible", "postcondition": { "type": "element_visible", "selector": "[data-ak=\"dashboard\"]", "waitMs": 10000 } }
153
- ```
154
-
155
- ## SLEEP
156
-
157
- Pause execution for a fixed duration. For demo videos, use SLEEP as an explicit narration anchor with `stepId`, `narrationTextByLocale`, and `durationMs: 1`. `autokap run` generates TTS once per app-locale voice row, measures the audio, and rewrites `durationMs` to the maximum duration for that `stepId` before executing the opcodes, so one runtime program works for every language/theme variant.
158
-
159
- | Param | Type | Required | Default | Description |
160
- |-------|------|----------|---------|-------------|
161
- | `durationMs` | integer (1..60000) | yes | — | How long to sleep, in milliseconds |
162
- | `narrationTextByLocale` | object `{ [locale]: string }` | video narration | — | Spoken text for every TTS locale used by `narration_by_app_locale`. Current TTS catalogue supports `en` and `fr`. |
163
- | `narrationText` | string | legacy single-row only | — | Backward-compatible fallback when only one TTS row is requested. Prefer `narrationTextByLocale`. |
164
-
165
- **Can:** Hold the runtime for a precise wall-clock duration without DOM polling.
166
- **Cannot:** React to a selector / postcondition — use `WAIT_FOR` for that.
167
-
168
- ```json
169
- { "kind": "SLEEP", "description": "Hold for narration on 'open-pricing'", "stepId": "open-pricing", "durationMs": 1, "narrationTextByLocale": { "en": "Let's open pricing and look at the plan structure.", "fr": "On ouvre les tarifs et on regarde la structure des offres." }, "postcondition": { "type": "always" }, "recovery": { "retries": 0, "useSelectorMemory": false, "useAltInteraction": false, "allowReload": false, "allowHealer": false }, "timeoutMs": 65000, "maxFailures": 1 }
170
- ```
171
-
172
- ## SCROLL
173
-
174
- Scroll the page or scroll an element into view.
175
-
176
- | Param | Type | Required | Default | Description |
177
- |-------|------|----------|---------|-------------|
178
- | `direction` | `"up"` \| `"down"` \| `"left"` \| `"right"` | yes | — | Scroll direction |
179
- | `amount` | number | no | viewport height | Pixels to scroll |
180
- | `targetSelector` | string | no | — | CSS selector to scroll into view |
181
- | `target` | SemanticTarget | no | — | Semantic target to scroll into view |
182
-
183
- **Can:** Scroll page in any direction, scroll specific element into view, scroll by pixel amount.
184
- **Cannot:** Scroll inside a specific scrollable container (always scrolls the page). For nested scrollable areas, use CLICK to focus the container first.
185
-
186
- **Tip:** When `targetSelector` is provided, the runtime scrolls the element into view regardless of `direction`/`amount`. Use `direction` + `amount` for blind scrolling, `targetSelector` for precise positioning.
187
-
188
- ```json
189
- { "kind": "SCROLL", "direction": "down", "targetSelector": "[data-ak=\"pricing\"]", "postcondition": { "type": "element_visible", "selector": "[data-ak=\"pricing\"]" } }
190
- ```
191
-
192
- ## HOVER
193
-
194
- Hover over an element.
195
-
196
- | Param | Type | Required | Description |
197
- |-------|------|----------|-------------|
198
- | `selector` | string | yes | CSS selector |
199
- | `target` | SemanticTarget | no | Fallback for recovery chain |
200
- | `fingerprint` | string | no | AKTree fingerprint |
201
- | `selectorAlternates` | string[] | no | Alternative selectors |
202
-
203
- **Can:** Trigger tooltips, dropdown menus, CSS `:hover` states, hover cards.
204
- **Cannot:** Hover state persists only until the next interaction. If you need to capture a hover state, place CAPTURE_SCREENSHOT immediately after HOVER.
205
-
206
- ```json
207
- { "kind": "HOVER", "selector": "[data-ak=\"nav-products\"]", "postcondition": { "type": "element_visible", "selector": "[data-ak=\"products-dropdown\"]", "waitMs": 3000 } }
208
- ```
209
-
210
- ## SELECT_OPTION
211
-
212
- Select an option in a **native `<select>` element**.
213
-
214
- | Param | Type | Required | Description |
215
- |-------|------|----------|-------------|
216
- | `selector` | string | yes | CSS selector of the `<select>` element |
217
- | `optionLabel` | string | no* | Select by visible label text |
218
- | `optionValue` | string | no* | Select by `value` attribute |
219
- | `optionIndex` | number | no* | Select by zero-based index |
220
- | `target` | SemanticTarget | no | Fallback for recovery chain |
221
- | `fingerprint` | string | no | AKTree fingerprint |
222
- | `selectorAlternates` | string[] | no | Alternative selectors |
223
-
224
- *Exactly one of `optionLabel`, `optionValue`, or `optionIndex` must be provided. Prefer `optionLabel` for readability.
225
-
226
- **Can:** Select from native `<select>` dropdowns.
227
- **Cannot:** Select from custom dropdowns (Radix Select, Headless UI Listbox, MUI Select, cmdk). For custom dropdowns, use a CLICK + WAIT_FOR + CLICK sequence: click to open, wait for options, click the option.
228
-
229
- ```json
230
- { "kind": "SELECT_OPTION", "selector": "[data-ak=\"country-select\"]", "optionLabel": "France", "postcondition": { "type": "text_contains", "selector": "[data-ak=\"country-select\"]", "text": "France" } }
231
- ```
232
-
233
- ## CHECK
234
-
235
- Set a checkbox or toggle to a specific state.
236
-
237
- | Param | Type | Required | Description |
238
- |-------|------|----------|-------------|
239
- | `selector` | string | yes | CSS selector of the checkbox/toggle |
240
- | `checked` | boolean | yes | `true` = checked, `false` = unchecked |
241
- | `target` | SemanticTarget | no | Fallback for recovery chain |
242
- | `fingerprint` | string | no | AKTree fingerprint |
243
- | `selectorAlternates` | string[] | no | Alternative selectors |
244
-
245
- **Can:** Idempotently set checkbox state. Safer than CLICK because it sets the desired state directly without toggling.
246
- **Cannot:** Interact with custom toggle components that don't use native checkbox semantics. For those, use CLICK.
247
-
248
- ```json
249
- { "kind": "CHECK", "selector": "[data-ak=\"terms-checkbox\"]", "checked": true, "postcondition": { "type": "always" } }
250
- ```
251
-
252
- ## DOUBLE_CLICK
253
-
254
- Double-click an element.
255
-
256
- | Param | Type | Required | Description |
257
- |-------|------|----------|-------------|
258
- | `selector` | string | yes | CSS selector |
259
- | `target` | SemanticTarget | no | Fallback for recovery chain |
260
- | `fingerprint` | string | no | AKTree fingerprint |
261
- | `selectorAlternates` | string[] | no | Alternative selectors |
262
-
263
- **Can:** Trigger inline editing, text selection, and any UI that responds to `dblclick`.
264
- **Cannot:** Triple-click (select paragraph). Use TYPE with `clearFirst: true` to replace full text content instead.
265
-
266
- ```json
267
- { "kind": "DOUBLE_CLICK", "selector": "[data-ak=\"editable-title\"]", "postcondition": { "type": "element_visible", "selector": "[data-ak=\"title-editor\"]", "waitMs": 3000 } }
268
- ```
269
-
270
- ## DRAG
271
-
272
- Drag the source element from point A to point B with an animated cursor. In clip recordings the cursor overlay glides along a Bezier curve, shows a pressed state during the drag, and emits a drop pulse at the destination.
273
-
274
- | Param | Type | Required | Description |
275
- |-------|------|----------|-------------|
276
- | `selector` | string | yes | CSS selector of the source element (the one being dragged) |
277
- | `target` | SemanticTarget | no | Semantic fallback for the source |
278
- | `fingerprint` | string | no | AKTree fingerprint for the source |
279
- | `selectorAlternates` | string[] | no | Alternative source selectors |
280
- | `toSelector` | string | no* | CSS selector of the drop target element |
281
- | `toTarget` | SemanticTarget | no* | Semantic fallback for the drop target |
282
- | `toSelectorAlternates` | string[] | no | Alternative destination selectors |
283
- | `offset` | `{ dx: number, dy: number }` | no* | Pixel offset from the source center (use for sliders, canvas drawing, or any drop that isn't a DOM node) |
284
-
285
- *Provide EITHER `toSelector` / `toTarget` (element drag) OR `offset` (relative drag). Not both.
286
-
287
- **Can:** Element-to-element drag (Kanban columns, sortable lists), slider adjustments, canvas drawing, any interaction driven by mousedown + mousemove + mouseup. Works with native HTML5 drag, dnd-kit, react-dnd, Radix DnD primitives — `page.mouse.*` fires both mouse and pointer events.
288
- **Cannot:** Multi-touch gestures, drag between different browser windows, file drops (use a file input instead).
289
-
290
- ```json
291
- { "kind": "DRAG", "selector": "[data-ak=\"task-card-todo-1\"]", "toSelector": "[data-ak=\"column-in-progress\"]", "postcondition": { "type": "element_visible", "selector": "[data-ak=\"column-in-progress\"] [data-ak=\"task-card-todo-1\"]", "waitMs": 3000 } }
292
- ```
293
-
294
- ```json
295
- { "kind": "DRAG", "selector": "[data-ak=\"volume-slider-thumb\"]", "offset": { "dx": 120, "dy": 0 }, "postcondition": { "type": "any_change" } }
296
- ```
297
-
298
- ## SET_LOCALE
299
-
300
- Set the application's locale/language for the current variant.
301
-
302
- | Param | Type | Required | Description |
303
- |-------|------|----------|-------------|
304
- | `locale` | string | yes | BCP-47 locale (e.g. `"fr"`, `"en-US"`). Use `"$variant"` for runtime substitution |
305
- | `method` | `"browser_context"` \| `"ui_interaction"` \| `"storage"` | yes | How to apply the locale |
306
- | `selector` | string | no | Element to click (for `ui_interaction` only) |
307
- | `storageHints` | StorageHint[] | no | Storage writes (for `storage` only) |
308
-
309
- **StorageHint:** `{ "storage": "localStorage" | "sessionStorage" | "cookie", "key": string, "value": string }`
310
-
311
- **Can:** Switch locale via storage writes (instant, reliable), browser context, or UI click.
312
- **Cannot:** Handle URL-based routing (e.g. `/fr/page`). For URL-based i18n, use NAVIGATE with the locale path.
313
-
314
- **Method decision tree:**
315
- - **next-intl** -> `method: "storage"`, `storage: "cookie"`, key: `"NEXT_LOCALE"`
316
- - **i18next / react-intl** -> `method: "storage"`, `storage: "localStorage"`, key: `"i18nextLng"`
317
- - **URL-based** (e.g. `/fr/page`) -> Use NAVIGATE instead
318
- - **Browser-level only** -> `method: "browser_context"`
319
-
320
- ```json
321
- { "kind": "SET_LOCALE", "locale": "$variant", "method": "storage", "storageHints": [{ "storage": "cookie", "key": "NEXT_LOCALE", "value": "$variant" }], "postcondition": { "type": "always" } }
322
- ```
323
-
324
- ## SET_THEME
325
-
326
- Set the application's color theme for the current variant.
327
-
328
- | Param | Type | Required | Description |
329
- |-------|------|----------|-------------|
330
- | `theme` | `"light"` \| `"dark"` \| `"$variant"` | yes | Target theme. Use `"$variant"` for runtime substitution |
331
- | `method` | `"color_scheme"` \| `"ui_interaction"` \| `"storage"` | yes | How to apply the theme |
332
- | `selector` | string | no | Element to click (for `ui_interaction` only) |
333
- | `storageHints` | StorageHint[] | no | Storage writes (for `storage` only) |
334
-
335
- **Can:** Switch theme via storage writes (instant, reliable), CSS `prefers-color-scheme`, or UI click.
336
- **Cannot:** Handle complex theme systems with more than light/dark (e.g. "system", "sepia"). For those, use `method: "storage"` with the exact value the app expects.
337
-
338
- **Method decision tree:**
339
- - **next-themes** -> `method: "storage"`, `storage: "localStorage"`, key: `"theme"`
340
- - **CSS only** (reads `prefers-color-scheme`) -> `method: "color_scheme"`
341
- - **Custom storage** -> `method: "storage"` with app-specific key
342
-
343
- ```json
344
- { "kind": "SET_THEME", "theme": "$variant", "method": "storage", "storageHints": [{ "storage": "localStorage", "key": "theme", "value": "$variant" }], "postcondition": { "type": "always" } }
345
- ```
346
-
347
- ## ASSERT_ROUTE
348
-
349
- Assert the current URL matches a pattern. Pure validation, no navigation.
350
-
351
- | Param | Type | Required | Description |
352
- |-------|------|----------|-------------|
353
- | `urlPattern` | string | yes | URL glob pattern (`*` = segment, `**` = any path) |
354
-
355
- **Can:** Validate the browser is on the expected page. Useful as a checkpoint before capture.
356
- **Cannot:** Navigate or change the URL. Use NAVIGATE for that.
357
-
358
- `urlPattern` is the assertion source of truth. Use `postcondition: { "type": "always" }` or repeat the same `route_matches` pattern.
359
-
360
- ```json
361
- { "kind": "ASSERT_ROUTE", "urlPattern": "/dashboard/**", "postcondition": { "type": "route_matches", "pattern": "/dashboard/**" } }
362
- ```
363
-
364
- ## ASSERT_SURFACE
365
-
366
- Assert that specific elements are visible on the page. Pure validation.
367
-
368
- | Param | Type | Required | Default | Description |
369
- |-------|------|----------|---------|-------------|
370
- | `selectors` | string[] | yes | — | CSS selectors that must be visible |
371
- | `matchAll` | boolean | yes | true | `true` = ALL must match, `false` = ANY one suffices |
372
-
373
- **Can:** Validate page state before capture. Confirm multiple elements are rendered.
374
- **Cannot:** Interact with elements or wait for them. Use WAIT_FOR for dynamic elements.
375
-
376
- `selectors` and `matchAll` are the assertion source of truth. Use `postcondition: { "type": "always" }` or an `element_visible` postcondition for one of the asserted selectors.
377
-
378
- ```json
379
- { "kind": "ASSERT_SURFACE", "selectors": ["[data-ak=\"header\"]", "[data-ak=\"sidebar\"]"], "matchAll": true, "postcondition": { "type": "always" } }
380
- ```
381
-
382
- ## CAPTURE_SCREENSHOT
383
-
384
- Capture a screenshot of the viewport or a specific element.
385
-
386
- | Param | Type | Required | Description |
387
- |-------|------|----------|-------------|
388
- | `captureId` | string | no | Stable identifier for Studio/dev links. Should match preset page/element id |
389
- | `captureName` | string | no | Human-readable label shown in Studio |
390
- | `elementSelector` | string | no | CSS selector for element-level capture (crops to element bounds) |
391
- | `outscale` | OutscaleConfig | no | Padding around the captured element (only applied with `elementSelector`). Typically set by the user post-generation. Omit by default. |
392
-
393
- **Can:** Full-page viewport capture, element-level capture (cropped), LLM verification (detects blank/error/loading/overlay states), alt text generation, favicon extraction.
394
- **Cannot:** Capture content below the fold in a single shot (use SCROLL first). Capture cross-origin iframe content.
395
-
396
- **Tip:** Without `elementSelector`, captures the full viewport. With `elementSelector`, captures only that element's bounding box — useful for component-level screenshots.
397
-
398
- **`outscale` shape:** all fields optional. `padding` is uniform (pixels). `paddingTop/Right/Bottom/Left` override per side. `paddingPercent` (0–100) scales with the element. `clampToViewport` (default `true`) prevents the crop from exceeding the document. `backgroundColor` fills any uncovered area.
399
-
400
- ```json
401
- { "kind": "CAPTURE_SCREENSHOT", "captureId": "dashboard-main", "captureName": "Dashboard", "elementSelector": "[data-ak=\"main-content\"]", "postcondition": { "type": "always" } }
402
- ```
403
-
404
- ```json
405
- { "kind": "CAPTURE_SCREENSHOT", "captureName": "Pricing card", "elementSelector": "[data-ak=\"pricing\"]", "outscale": { "padding": 24 }, "postcondition": { "type": "always" } }
406
- ```
407
-
408
- ## BEGIN_CLIP
409
-
410
- Start recording a clip. All interactions between BEGIN_CLIP and END_CLIP are recorded.
411
-
412
- | Param | Type | Required | Description |
413
- |-------|------|----------|-------------|
414
- | `clipId` | string | no | Stable identifier for Studio/dev links. Should match preset clip id |
415
- | `clipName` | string | no | Human-readable label shown in Studio |
416
-
417
- **Can:** Record viewport interactions as a clip.
418
- **Cannot:** Record element-level clips (always full viewport). Record audio.
419
-
420
- ```json
421
- { "kind": "BEGIN_CLIP", "clipId": "open-modal-flow", "clipName": "Open modal", "postcondition": { "type": "always" } }
422
- ```
423
-
424
- ## END_CLIP
425
-
426
- Stop recording the clip. Must pair with a prior BEGIN_CLIP.
427
-
428
- | Param | Type | Required | Description |
429
- |-------|------|----------|-------------|
430
- | `clipId` | string | no | Must match the BEGIN_CLIP's `clipId` |
431
- | `clipName` | string | no | Must match the BEGIN_CLIP's `clipName` |
432
-
433
- **Can:** Finalize recording and produce GIF/MP4 artifact.
434
- **Cannot:** Trim or edit the recording. The full BEGIN_CLIP to END_CLIP duration is captured.
435
-
436
- ```json
437
- { "kind": "END_CLIP", "clipId": "open-modal-flow", "clipName": "Open modal", "postcondition": { "type": "always" } }
438
- ```
439
-
440
- ## CLONE_ELEMENT
441
-
442
- Duplicate a template element N times into a container. **Non-blocking** — if a selector misses, the opcode is skipped and the run continues.
443
-
444
- | Param | Type | Required | Default | Description |
445
- |-------|------|----------|---------|-------------|
446
- | `sourceSelector` | string | yes | — | CSS selector of the element to clone |
447
- | `containerSelector` | string | yes | — | CSS selector of the container that receives the clones |
448
- | `count` | number (1-500) | yes | — | Number of clones to produce |
449
- | `removeSource` | boolean | no | false | If true, remove the template after cloning (template must be a child of the container) |
450
-
451
- **Can:** Duplicate any DOM node including its descendants and attributes. Optionally remove the source after cloning.
452
- **Cannot:** Clone content from cross-origin iframes. Clone the shadow tree of Web Components (only the host is cloned).
453
-
454
- **Soft-failure semantics:** Throws if `sourceSelector` or `containerSelector` is missing. The runner converts the throw into `status: "skipped"` and the variant continues.
455
-
456
- ```json
457
- { "kind": "CLONE_ELEMENT", "description": "Clone customer row 5 times", "sourceSelector": "[data-ak=\"customer-row\"]", "containerSelector": "[data-ak=\"customers-tbody\"]", "count": 5, "postcondition": { "type": "always" }, "recovery": { "retries": 0, "useSelectorMemory": false, "useAltInteraction": false, "allowReload": false, "allowHealer": false }, "timeoutMs": 5000, "maxFailures": 1 }
458
- ```
459
-
460
- ## INJECT_MOCK_DATA
461
-
462
- Orchestrator opcode that fills a fillable region with mock data. Carries fields for **two complementary delivery mechanisms** and applies BOTH whenever they are wired:
463
-
464
- - **Clone**: clones a template DOM element N times into a container and writes each slot value into the cloned descendants. Provides instant visual feedback even before any state-driven re-render. Works for any container whose children are pure markup the runtime can mutate.
465
- - **Trigger**: writes the JSON-encoded `defaultValues` array into a hidden `<input>` the user's app exposed, then clicks a hidden trigger element via `element.click()`. The user's `onClick` handler reads the input, parses the JSON, and re-renders the widget through normal React/Vue/Svelte state updates. Survives any future re-renders that would clobber the cloned DOM, and works for libraries that own their DOM (Chart.js, Recharts, D3).
466
-
467
- The two mechanisms are independent and additive. **Wire both whenever possible** — clone for instant paint, trigger to survive re-renders. The runtime applies clone first, then trigger. The opcode is recorded as `applied` if AT LEAST ONE mechanism succeeds.
468
-
469
- The named group is looked up from `ExecutionProgram.mockDataGroups` (compiled from `PresetConfig.mockDataInjection.groups`). **Non-blocking** — if both mechanisms fail (or neither was wired), the opcode is recorded as `mockDataGroupResults[groupName] = "skipped"` and the run continues.
470
-
471
- ### Common params
472
-
473
- | Param | Type | Required | Description |
474
- |-------|------|----------|-------------|
475
- | `groupName` | string | yes | Name of the MockDataGroup to use (must exist in the preset's `mockDataInjection.groups`) |
476
-
477
- ### Clone params (optional but typically populated)
478
-
479
- | Param | Type | Required | Default | Description |
480
- |-------|------|----------|---------|-------------|
481
- | `containerSelector` | string | conditional | — | CSS selector of the container that holds the cloned items. Required if any other clone field is present. |
482
- | `templateSelector` | string | no | first child of container | CSS selector of the element to clone (defaults to `${containerSelector} > *:first-child`) |
483
- | `count` | number (1-500) | no | `defaultValues.length` | Override the row count |
484
- | `removeTemplate` | boolean | no | `false` | If true, remove the template after cloning (use to replace empty-state placeholders) |
485
- | `slotMappings` | array of `{ slot, selector, attribute? }` | conditional | — | Maps each slot name to a target inside a cloned item. Required if `containerSelector` is present. |
486
-
487
- **`slotMappings` entry:**
488
-
489
- | Field | Type | Required | Description |
490
- |-------|------|----------|-------------|
491
- | `slot` | string | yes | Name of a slot from the MockDataGroup |
492
- | `selector` | string | yes | CSS selector RELATIVE to the cloned item |
493
- | `attribute` | string | no | If present, write to `setAttribute(name, value)`. If absent, write to `textContent`. |
494
-
495
- The runtime tags each clone with `data-ak-mock-clone="<i>"` so slot selectors are addressed via the tag rather than `nth-child` math — robust against non-template siblings (placeholders, headers).
496
-
497
- ### Trigger params (optional but typically populated)
498
-
499
- | Param | Type | Required | Description |
500
- |-------|------|----------|-------------|
501
- | `inputSelector` | string | conditional | CSS selector of the hidden `<input>` / `<textarea>` / `<select>` that receives the JSON payload. Required if `triggerSelector` is present. Use `[data-ak-fill-input="<group>"]`. |
502
- | `triggerSelector` | string | conditional | CSS selector of the hidden trigger element AutoKap clicks programmatically. Required if `inputSelector` is present. Use `[data-ak-fill-trigger="<group>"]`. |
503
-
504
- The runtime serializes `defaultValues` as a JSON array (`JSON.stringify(group.defaultValues)`) and writes it into the input via the React-aware native value setter, then dispatches `input` and `change` events, then calls `triggerElement.click()` directly. The user's `onClick` handler is responsible for parsing and applying the data.
505
-
506
- ### Validation
507
-
508
- At least one mechanism must be complete (clone = `containerSelector` + `slotMappings`; trigger = `inputSelector` + `triggerSelector`). Partial mechanisms are rejected at compile time.
509
-
510
- ### Capabilities
511
-
512
- **Can:**
513
- - Apply both mechanisms additively for the same group, in a single opcode.
514
- - Populate tables, lists, card grids, badge rows, and any container with text or image-source values via the clone mechanism.
515
- - Re-render charts, maps, calendars, and any programmatic widget via the trigger mechanism, by asking the user's app to handle the seed data through normal state updates.
516
-
517
- **Cannot:**
518
- - Trigger mechanism cannot work without app-side cooperation (the assistant must add a hidden trigger + input + `onClick` handler to the user's source code). The handler must JSON.parse the input value and validate the shape defensively.
519
- - Clone mechanism cannot persist DOM mutations into React/Vue/Svelte state — on the next render the framework reconciles its virtual tree against the real DOM and overwrites the cloned children. (This is exactly why you should also wire the trigger mechanism — it routes the same data through state, so the next render preserves it.)
520
-
521
- ### Soft-failure semantics
522
-
523
- Returns failure if the group is missing, has no `defaultValues`, the opcode declares neither mechanism, or both wired mechanisms fail at runtime. The runner converts failure into `status: "skipped"` and records `mockDataGroupResults[groupName] = "skipped"`. If at least one mechanism succeeds, the group is recorded as `"applied"` even if the other failed.
524
-
525
- ### Example — Both mechanisms (recommended)
526
-
527
- ```json
528
- {
529
- "kind": "INJECT_MOCK_DATA",
530
- "description": "Populate preset cards with mock data",
531
- "groupName": "preset-cards",
532
-
533
- "containerSelector": "[data-ak=\"preset-card-grid\"]",
534
- "templateSelector": "[data-ak=\"preset-card-grid\"] > [data-ak=\"preset-card\"]",
535
- "removeTemplate": true,
536
- "slotMappings": [
537
- { "slot": "title", "selector": "[data-ak=\"preset-card-title\"]" },
538
- { "slot": "lastCapture", "selector": "[data-ak=\"preset-card-last-capture\"]" },
539
- { "slot": "variantCount", "selector": "[data-ak=\"preset-card-variant-count\"]" },
540
- { "slot": "creditCost", "selector": "[data-ak=\"preset-card-credit-cost\"]" },
541
- { "slot": "typeBadge", "selector": "[data-ak=\"preset-card-type-badge\"]" }
542
- ],
543
-
544
- "inputSelector": "[data-ak-fill-input=\"preset-cards\"]",
545
- "triggerSelector": "[data-ak-fill-trigger=\"preset-cards\"]",
546
-
547
- "postcondition": { "type": "always" },
548
- "recovery": { "retries": 0, "useSelectorMemory": false, "useAltInteraction": false, "allowReload": false, "allowHealer": false },
549
- "timeoutMs": 5000,
550
- "maxFailures": 1
551
- }
552
- ```
553
-
554
- ### Example — Clone-only (static HTML, no app state)
555
-
556
- ```json
557
- {
558
- "kind": "INJECT_MOCK_DATA",
559
- "description": "Populate static customers table",
560
- "groupName": "customers-table",
561
- "containerSelector": "[data-ak=\"customers-tbody\"]",
562
- "templateSelector": "[data-ak=\"customers-tbody\"] > [data-ak=\"customer-row\"]",
563
- "removeTemplate": true,
564
- "slotMappings": [
565
- { "slot": "name", "selector": "[data-ak=\"customer-name\"]" },
566
- { "slot": "avatar", "selector": "[data-ak=\"customer-avatar\"]", "attribute": "src" }
567
- ],
568
- "postcondition": { "type": "always" },
569
- "recovery": { "retries": 0, "useSelectorMemory": false, "useAltInteraction": false, "allowReload": false, "allowHealer": false },
570
- "timeoutMs": 5000,
571
- "maxFailures": 1
572
- }
573
- ```
574
-
575
- ### Example — Trigger-only (pure D3 widget, no DOM template to clone)
576
-
577
- ```json
578
- {
579
- "kind": "INJECT_MOCK_DATA",
580
- "description": "Seed revenue chart with mock data",
581
- "groupName": "revenue-chart",
582
- "inputSelector": "[data-ak-fill-input=\"revenue-chart\"]",
583
- "triggerSelector": "[data-ak-fill-trigger=\"revenue-chart\"]",
584
- "postcondition": { "type": "always" },
585
- "recovery": { "retries": 0, "useSelectorMemory": false, "useAltInteraction": false, "allowReload": false, "allowHealer": false },
586
- "timeoutMs": 5000,
587
- "maxFailures": 1
588
- }
589
- ```
590
-
591
- ## REMOVE_ELEMENT
592
-
593
- Remove all elements matching a CSS selector. **Non-blocking.**
594
-
595
- | Param | Type | Required | Description |
596
- |-------|------|----------|-------------|
597
- | `selector` | string | yes | CSS selector — every match is removed |
598
-
599
- **Can:** Strip empty-state illustrations, debug banners, "powered by" footers, or any visual noise that would distract from the screenshot.
600
- **Cannot:** Remove an element from a parent that re-renders it via React state — the next render will recreate it.
601
-
602
- **Soft-failure semantics:** Throws if the selector matches zero elements. The runner converts the throw into `status: "skipped"`.
603
-
604
- ```json
605
- { "kind": "REMOVE_ELEMENT", "description": "Remove empty-state illustration", "selector": "[data-ak=\"empty-state\"]", "postcondition": { "type": "always" }, "recovery": { "retries": 0, "useSelectorMemory": false, "useAltInteraction": false, "allowReload": false, "allowHealer": false }, "timeoutMs": 3000, "maxFailures": 1 }
606
- ```
607
-
608
- ## SET_ATTRIBUTE
609
-
610
- Set an attribute on the first matching element. **Non-blocking.**
611
-
612
- | Param | Type | Required | Description |
613
- |-------|------|----------|-------------|
614
- | `selector` | string | yes | CSS selector of the target element (first match only) |
615
- | `attribute` | string | yes | Attribute name (e.g. `"src"`, `"href"`, `"data-state"`) |
616
- | `value` | string | yes | Attribute value |
617
-
618
- **Can:** Swap an `<img src>`, change a `data-*` flag to trigger CSS state, set `aria-*` for a11y previews, or override `href` on a link.
619
- **Cannot:** Trigger React state updates — only the DOM attribute changes. Replace `style` reliably (prefer setting a `class` or `data-*` and letting CSS handle the visual).
620
-
621
- **Soft-failure semantics:** Throws if the selector is unmatched. The runner converts the throw into `status: "skipped"`.
622
-
623
- ```json
624
- { "kind": "SET_ATTRIBUTE", "description": "Override hero image src", "selector": "[data-ak=\"hero-image\"]", "attribute": "src", "value": "https://picsum.photos/1200/600", "postcondition": { "type": "always" }, "recovery": { "retries": 0, "useSelectorMemory": false, "useAltInteraction": false, "allowReload": false, "allowHealer": false }, "timeoutMs": 3000, "maxFailures": 1 }
625
- ```
@@ -1,38 +0,0 @@
1
- # AutoKap Skill Packaging
2
-
3
- `assets/skill/` is the canonical source of truth for the AutoKap skill system.
4
- Edit files here first.
5
-
6
- ## Packaging model
7
-
8
- - `SKILL.md` is the core preset contract and must stay short enough to remain
9
- readable.
10
- - `references/*.md` holds longer mode-specific guidance and examples.
11
- - `src/skill-packaging.ts` compiles these sources into the outputs each agent
12
- expects.
13
-
14
- ## Agent parity rules
15
-
16
- - Codex installs a local bundle: `SKILL.md` plus companion files in
17
- `references/`.
18
- - Claude Code, Cursor, Windsurf, Copilot, and the HTTP download endpoint use a
19
- flattened single-file export generated from the same source.
20
- - The bundle and single-file exports must carry the same instructions. Change
21
- semantics once in `assets/skill/`, then regenerate every output.
22
-
23
- ## Maintenance rules
24
-
25
- 1. Keep non-negotiable contract rules in `SKILL.md`.
26
- 2. Move long examples or mode-specific detail into `references/*.md`.
27
- 3. Do not hand-edit `package/assets/skill/`. It is a published mirror synced
28
- from this directory.
29
- 4. After editing skill assets, run `npm run sync:package` or any build path
30
- that executes `scripts/sync-package-bundle.mjs`.
31
- 5. Before merging, run:
32
- - `npx vitest run src/skill-packaging.test.ts src/package-bundle.test.ts`
33
- - `npx tsc --noEmit`
34
-
35
- ## Published mirror
36
-
37
- `package/assets/skill/` must stay byte-for-byte aligned with this directory.
38
- Tests enforce that parity so the npm package and the repo sources cannot drift.