autokap 1.6.2 → 1.6.3
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/dist/cli-config.js +69 -25
- package/dist/cli-contract.d.ts +19 -5
- package/dist/cli-contract.js +55 -151
- package/dist/cli-doctor.d.ts +0 -1
- package/dist/cli-doctor.js +15 -143
- package/dist/cli-runner.d.ts +1 -1
- package/dist/cli-runner.js +2 -2
- package/dist/cli.js +24 -1163
- package/dist/execution-schema.d.ts +3 -3
- package/dist/program-signing.d.ts +1 -1
- package/dist/skill-packaging.d.ts +0 -16
- package/dist/skill-packaging.js +1 -51
- package/dist/video-narration-schema.d.ts +1 -1
- package/package.json +2 -6
- package/readme.md +15 -12
- package/assets/skill/OPCODE-REFERENCE.md +0 -625
- package/assets/skill/README.md +0 -38
- package/assets/skill/SKILL.md +0 -590
- package/assets/skill/references/STANDARDS.md +0 -236
- package/assets/skill/references/examples.md +0 -88
- package/assets/skill/references/mock-data.md +0 -178
- package/dist/auth-capture.d.ts +0 -17
- package/dist/auth-capture.js +0 -199
- package/dist/cli-utils.d.ts +0 -5
- package/dist/cli-utils.js +0 -14
- package/dist/version-check.d.ts +0 -4
- package/dist/version-check.js +0 -102
|
@@ -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
|
-
```
|
package/assets/skill/README.md
DELETED
|
@@ -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.
|