autokap 1.0.6 → 1.0.8

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.
Files changed (347) hide show
  1. package/assets/chrome/ios-statusbar-comparison-reference.jpg +0 -0
  2. package/assets/chrome/ios-statusbar-dark-reference.jpg +0 -0
  3. package/assets/chrome/ios-statusbar-light-reference.jpg +0 -0
  4. package/assets/cursors/macos.svg +4 -0
  5. package/assets/cursors/windows.svg +15 -0
  6. package/assets/devices/ipad-pro-11-m4.json +52 -0
  7. package/assets/devices/iphone-16-pro.json +53 -0
  8. package/assets/devices/macbook-air-13.json +45 -0
  9. package/assets/frames/MacBook Air 13.svg +242 -0
  10. package/assets/frames/Status bar - iPhone.png +0 -0
  11. Menu bar- iPad.png +0 -0
  12. package/assets/frames/iPad Pro M4 11_.png +0 -0
  13. package/assets/frames/iPhone 16 Pro.png +0 -0
  14. package/assets/icons/Cellular Connection.svg +3 -0
  15. package/assets/icons/Union.svg +6 -0
  16. package/assets/icons/Wifi.svg +3 -0
  17. package/assets/icons/battery.svg +5 -0
  18. package/assets/icons/battery_charging.svg +8 -0
  19. package/assets/skill/OPCODE-REFERENCE.md +607 -0
  20. package/assets/skill/README.md +39 -0
  21. package/assets/skill/SKILL.md +453 -468
  22. package/assets/skill/STUDIO-SKILL.md +476 -0
  23. package/assets/skill/references/examples.md +104 -0
  24. package/assets/skill/references/interactive-demo.md +225 -0
  25. package/assets/skill/references/mock-data.md +178 -0
  26. package/dist/abort.d.ts +5 -0
  27. package/dist/abort.js +44 -0
  28. package/dist/action-verifier.d.ts +29 -0
  29. package/dist/action-verifier.js +133 -0
  30. package/dist/agent-action-recovery.d.ts +45 -0
  31. package/dist/agent-action-recovery.js +370 -0
  32. package/dist/agent-message-utils.d.ts +21 -0
  33. package/dist/agent-message-utils.js +77 -0
  34. package/dist/agent-url-utils.d.ts +30 -0
  35. package/dist/agent-url-utils.js +138 -0
  36. package/dist/agent.d.ts +226 -0
  37. package/dist/agent.js +6666 -0
  38. package/dist/ak-tree.d.ts +39 -0
  39. package/dist/ak-tree.js +368 -0
  40. package/dist/alt-text.d.ts +26 -0
  41. package/dist/alt-text.js +55 -0
  42. package/dist/auth-capture.d.ts +17 -0
  43. package/dist/auth-capture.js +164 -0
  44. package/dist/benchmark.d.ts +59 -0
  45. package/dist/benchmark.js +135 -0
  46. package/dist/billing-operation-logging.d.ts +38 -0
  47. package/dist/billing-operation-logging.js +248 -0
  48. package/dist/browser-bar.d.ts +48 -0
  49. package/dist/browser-bar.js +284 -0
  50. package/dist/browser-pool.d.ts +7 -0
  51. package/dist/browser-pool.js +15 -5
  52. package/dist/browser-utils.d.ts +31 -0
  53. package/dist/browser-utils.js +97 -0
  54. package/dist/browser.d.ts +76 -1
  55. package/dist/browser.js +1657 -39
  56. package/dist/capture-alt-text.d.ts +12 -0
  57. package/dist/capture-alt-text.js +52 -0
  58. package/dist/capture-encryption.d.ts +10 -0
  59. package/dist/capture-encryption.js +41 -0
  60. package/dist/capture-language-preflight.d.ts +41 -0
  61. package/dist/capture-language-preflight.js +300 -0
  62. package/dist/capture-llm-page-identity.d.ts +15 -0
  63. package/dist/capture-llm-page-identity.js +128 -0
  64. package/dist/capture-model-resolution.d.ts +9 -0
  65. package/dist/capture-model-resolution.js +21 -0
  66. package/dist/capture-page-identity.d.ts +7 -0
  67. package/dist/capture-page-identity.js +352 -0
  68. package/dist/capture-preset-credentials.d.ts +62 -0
  69. package/dist/capture-preset-credentials.js +184 -0
  70. package/dist/capture-request-plan.d.ts +58 -0
  71. package/dist/capture-request-plan.js +264 -0
  72. package/dist/capture-run-optimizer.d.ts +139 -0
  73. package/dist/capture-run-optimizer.js +863 -0
  74. package/dist/capture-selector-memory.d.ts +31 -0
  75. package/dist/capture-selector-memory.js +345 -0
  76. package/dist/capture-session-profile-encryption.d.ts +2 -0
  77. package/dist/capture-session-profile-encryption.js +22 -0
  78. package/dist/capture-step-timeout.d.ts +10 -0
  79. package/dist/capture-step-timeout.js +30 -0
  80. package/dist/capture-strategy.d.ts +36 -0
  81. package/dist/capture-strategy.js +95 -0
  82. package/dist/capture-studio-sync.d.ts +23 -0
  83. package/dist/capture-studio-sync.js +172 -0
  84. package/dist/capture-surface-contract.d.ts +36 -0
  85. package/dist/capture-surface-contract.js +299 -0
  86. package/dist/capture-transition-engine.d.ts +28 -0
  87. package/dist/capture-transition-engine.js +292 -0
  88. package/dist/capture-variant-state.d.ts +56 -0
  89. package/dist/capture-variant-state.js +182 -0
  90. package/dist/capture-verification.d.ts +35 -0
  91. package/dist/capture-verification.js +95 -0
  92. package/dist/capture-viewport-lock.d.ts +48 -0
  93. package/dist/capture-viewport-lock.js +74 -0
  94. package/dist/circuit-breaker.d.ts +42 -0
  95. package/dist/circuit-breaker.js +119 -0
  96. package/dist/cli-config.d.ts +8 -1
  97. package/dist/cli-config.js +62 -6
  98. package/dist/cli-contract.d.ts +15 -0
  99. package/dist/cli-contract.js +167 -0
  100. package/dist/cli-runner-local.d.ts +12 -0
  101. package/dist/cli-runner-local.js +102 -0
  102. package/dist/cli-runner.d.ts +34 -0
  103. package/dist/cli-runner.js +433 -0
  104. package/dist/cli-utils.d.ts +0 -1
  105. package/dist/cli-utils.js +2 -5
  106. package/dist/cli.js +1005 -252
  107. package/dist/clip-orchestrator.d.ts +148 -0
  108. package/dist/clip-orchestrator.js +957 -0
  109. package/dist/clip-postprocess.d.ts +42 -0
  110. package/dist/clip-postprocess.js +201 -0
  111. package/dist/cookie-dismiss.d.ts +2 -0
  112. package/dist/cookie-dismiss.js +48 -13
  113. package/dist/cost-logging.d.ts +35 -0
  114. package/dist/cost-logging.js +242 -0
  115. package/dist/cost-resolution-monitor.d.ts +16 -0
  116. package/dist/cost-resolution-monitor.js +34 -0
  117. package/dist/credential-templates.d.ts +5 -0
  118. package/dist/credential-templates.js +60 -0
  119. package/dist/cursor-overlay-script.d.ts +6 -0
  120. package/dist/cursor-overlay-script.js +169 -0
  121. package/dist/dom-css-purger.d.ts +65 -0
  122. package/dist/dom-css-purger.js +333 -0
  123. package/dist/dom-font-inliner.d.ts +45 -0
  124. package/dist/dom-font-inliner.js +148 -0
  125. package/dist/dom-patch-resolver.d.ts +52 -0
  126. package/dist/dom-patch-resolver.js +242 -0
  127. package/dist/dom-serializer.d.ts +82 -0
  128. package/dist/dom-serializer.js +378 -0
  129. package/dist/element-capture.d.ts +13 -0
  130. package/dist/element-capture.js +522 -0
  131. package/dist/env-validation.d.ts +5 -0
  132. package/dist/env-validation.js +29 -0
  133. package/dist/execution-schema.d.ts +4423 -0
  134. package/dist/execution-schema.js +507 -0
  135. package/dist/execution-types.d.ts +886 -0
  136. package/dist/execution-types.js +65 -0
  137. package/dist/fonts-loader.d.ts +14 -0
  138. package/dist/fonts-loader.js +55 -0
  139. package/dist/hybrid-navigator.d.ts +138 -0
  140. package/dist/hybrid-navigator.js +468 -0
  141. package/dist/index.d.ts +18 -0
  142. package/dist/index.js +17 -0
  143. package/dist/legacy/agent-action-recovery.d.ts +45 -0
  144. package/dist/legacy/agent-action-recovery.js +370 -0
  145. package/dist/legacy/agent-message-utils.d.ts +21 -0
  146. package/dist/legacy/agent-message-utils.js +77 -0
  147. package/dist/legacy/agent-url-utils.d.ts +30 -0
  148. package/dist/legacy/agent-url-utils.js +138 -0
  149. package/dist/legacy/agent.d.ts +226 -0
  150. package/dist/legacy/agent.js +6666 -0
  151. package/dist/legacy/clip-orchestrator.d.ts +148 -0
  152. package/dist/legacy/clip-orchestrator.js +957 -0
  153. package/dist/legacy/credential-templates.d.ts +5 -0
  154. package/dist/legacy/credential-templates.js +60 -0
  155. package/dist/legacy/hybrid-navigator.d.ts +138 -0
  156. package/dist/legacy/hybrid-navigator.js +468 -0
  157. package/dist/legacy/llm-usage.d.ts +17 -0
  158. package/dist/legacy/llm-usage.js +45 -0
  159. package/dist/legacy/prompt-cache.d.ts +10 -0
  160. package/dist/legacy/prompt-cache.js +24 -0
  161. package/dist/legacy/prompts.d.ts +175 -0
  162. package/dist/legacy/prompts.js +1038 -0
  163. package/dist/legacy/tools.d.ts +4 -0
  164. package/dist/legacy/tools.js +216 -0
  165. package/dist/legacy/video-agent.d.ts +143 -0
  166. package/dist/legacy/video-agent.js +4788 -0
  167. package/dist/legacy/video-observation.d.ts +36 -0
  168. package/dist/legacy/video-observation.js +192 -0
  169. package/dist/legacy/video-planner.d.ts +12 -0
  170. package/dist/legacy/video-planner.js +501 -0
  171. package/dist/legacy/video-prompts.d.ts +37 -0
  172. package/dist/legacy/video-prompts.js +569 -0
  173. package/dist/legacy/video-tools.d.ts +3 -0
  174. package/dist/legacy/video-tools.js +59 -0
  175. package/dist/legacy/video-variant-state.d.ts +29 -0
  176. package/dist/legacy/video-variant-state.js +80 -0
  177. package/dist/legacy/vision-model.d.ts +17 -0
  178. package/dist/legacy/vision-model.js +74 -0
  179. package/dist/llm-healer.d.ts +63 -0
  180. package/dist/llm-healer.js +166 -0
  181. package/dist/llm-provider.d.ts +29 -0
  182. package/dist/llm-provider.js +80 -0
  183. package/dist/llm-usage.d.ts +17 -0
  184. package/dist/llm-usage.js +45 -0
  185. package/dist/logger.d.ts +6 -2
  186. package/dist/logger.js +15 -1
  187. package/dist/mockup-html.d.ts +119 -0
  188. package/dist/mockup-html.js +263 -0
  189. package/dist/mockup.d.ts +187 -0
  190. package/dist/mockup.js +869 -0
  191. package/dist/mouse-animation.d.ts +46 -0
  192. package/dist/mouse-animation.js +114 -0
  193. package/dist/opcode-actions.d.ts +42 -0
  194. package/dist/opcode-actions.js +511 -0
  195. package/dist/opcode-runner.d.ts +51 -0
  196. package/dist/opcode-runner.js +770 -0
  197. package/dist/openrouter-client.d.ts +40 -0
  198. package/dist/openrouter-client.js +16 -0
  199. package/dist/overlay-engine.d.ts +24 -0
  200. package/dist/overlay-engine.js +176 -0
  201. package/dist/overlay-utils.d.ts +14 -0
  202. package/dist/overlay-utils.js +13 -0
  203. package/dist/postcondition.d.ts +16 -0
  204. package/dist/postcondition.js +269 -0
  205. package/dist/posthog.d.ts +4 -0
  206. package/dist/posthog.js +26 -0
  207. package/dist/program-patcher.d.ts +25 -0
  208. package/dist/program-patcher.js +44 -0
  209. package/dist/prompt-cache.d.ts +10 -0
  210. package/dist/prompt-cache.js +24 -0
  211. package/dist/prompts.d.ts +175 -0
  212. package/dist/prompts.js +1038 -0
  213. package/dist/provider-config.d.ts +12 -0
  214. package/dist/provider-config.js +15 -0
  215. package/dist/recovery-chain.d.ts +37 -0
  216. package/dist/recovery-chain.js +350 -0
  217. package/dist/remote-browser.d.ts +215 -0
  218. package/dist/remote-browser.js +360 -0
  219. package/dist/safari-browser-bar.d.ts +15 -0
  220. package/dist/safari-browser-bar.js +95 -0
  221. package/dist/safari-toolbar-asset.d.ts +15 -0
  222. package/dist/safari-toolbar-asset.js +12 -0
  223. package/dist/security.d.ts +21 -0
  224. package/dist/security.js +608 -0
  225. package/dist/selector-resolver.d.ts +34 -0
  226. package/dist/selector-resolver.js +181 -0
  227. package/dist/semantic-resolver.d.ts +35 -0
  228. package/dist/semantic-resolver.js +161 -0
  229. package/dist/server-capture-runtime.d.ts +125 -0
  230. package/dist/server-capture-runtime.js +585 -0
  231. package/dist/server-credit-usage.d.ts +12 -0
  232. package/dist/server-credit-usage.js +41 -0
  233. package/dist/server-posthog.d.ts +2 -0
  234. package/dist/server-posthog.js +16 -0
  235. package/dist/server-project-webhooks.d.ts +59 -0
  236. package/dist/server-project-webhooks.js +123 -0
  237. package/dist/server-screenshot-watermark.d.ts +7 -0
  238. package/dist/server-screenshot-watermark.js +60 -0
  239. package/dist/session-profile.d.ts +86 -0
  240. package/dist/session-profile.js +1536 -0
  241. package/dist/sf-pro-fonts.d.ts +4 -0
  242. package/dist/sf-pro-fonts.js +7 -0
  243. package/dist/sf-pro-symbols.d.ts +1 -0
  244. package/dist/sf-pro-symbols.js +55 -0
  245. package/dist/skill-packaging.d.ts +28 -0
  246. package/dist/skill-packaging.js +169 -0
  247. package/dist/smart-wait.d.ts +27 -0
  248. package/dist/smart-wait.js +81 -0
  249. package/dist/status-bar-l10n.d.ts +14 -0
  250. package/dist/status-bar-l10n.js +177 -0
  251. package/dist/status-bar-render.d.ts +20 -0
  252. package/dist/status-bar-render.js +410 -0
  253. package/dist/status-bar.d.ts +53 -0
  254. package/dist/status-bar.js +620 -0
  255. package/dist/svg-browser-bar.d.ts +33 -0
  256. package/dist/svg-browser-bar.js +206 -0
  257. package/dist/svg-status-bar.d.ts +36 -0
  258. package/dist/svg-status-bar.js +597 -0
  259. package/dist/svg-text.d.ts +61 -0
  260. package/dist/svg-text.js +118 -0
  261. package/dist/tools.d.ts +4 -0
  262. package/dist/tools.js +216 -0
  263. package/dist/types.d.ts +240 -5
  264. package/dist/types.js +23 -1
  265. package/dist/v2/action-verifier.d.ts +29 -0
  266. package/dist/v2/action-verifier.js +133 -0
  267. package/dist/v2/alt-text.d.ts +26 -0
  268. package/dist/v2/alt-text.js +55 -0
  269. package/dist/v2/benchmark.d.ts +59 -0
  270. package/dist/v2/benchmark.js +135 -0
  271. package/dist/v2/capture-strategy.d.ts +30 -0
  272. package/dist/v2/capture-strategy.js +67 -0
  273. package/dist/v2/capture-verification.d.ts +35 -0
  274. package/dist/v2/capture-verification.js +95 -0
  275. package/dist/v2/circuit-breaker.d.ts +42 -0
  276. package/dist/v2/circuit-breaker.js +119 -0
  277. package/dist/v2/cli-runner-local.d.ts +11 -0
  278. package/dist/v2/cli-runner-local.js +91 -0
  279. package/dist/v2/cli-runner.d.ts +34 -0
  280. package/dist/v2/cli-runner.js +300 -0
  281. package/dist/v2/compiler-prompts.d.ts +27 -0
  282. package/dist/v2/compiler-prompts.js +123 -0
  283. package/dist/v2/compiler.d.ts +37 -0
  284. package/dist/v2/compiler.js +147 -0
  285. package/dist/v2/explorer.d.ts +41 -0
  286. package/dist/v2/explorer.js +56 -0
  287. package/dist/v2/index.d.ts +37 -0
  288. package/dist/v2/index.js +31 -0
  289. package/dist/v2/llm-healer.d.ts +62 -0
  290. package/dist/v2/llm-healer.js +166 -0
  291. package/dist/v2/llm-provider.d.ts +29 -0
  292. package/dist/v2/llm-provider.js +80 -0
  293. package/dist/v2/opcode-runner.d.ts +47 -0
  294. package/dist/v2/opcode-runner.js +634 -0
  295. package/dist/v2/overlay-engine.d.ts +24 -0
  296. package/dist/v2/overlay-engine.js +150 -0
  297. package/dist/v2/postcondition.d.ts +16 -0
  298. package/dist/v2/postcondition.js +249 -0
  299. package/dist/v2/program-patcher.d.ts +25 -0
  300. package/dist/v2/program-patcher.js +44 -0
  301. package/dist/v2/recovery-chain.d.ts +30 -0
  302. package/dist/v2/recovery-chain.js +368 -0
  303. package/dist/v2/schema.d.ts +2580 -0
  304. package/dist/v2/schema.js +295 -0
  305. package/dist/v2/selector-resolver.d.ts +34 -0
  306. package/dist/v2/selector-resolver.js +181 -0
  307. package/dist/v2/semantic-resolver.d.ts +35 -0
  308. package/dist/v2/semantic-resolver.js +161 -0
  309. package/dist/v2/smart-wait.d.ts +27 -0
  310. package/dist/v2/smart-wait.js +81 -0
  311. package/dist/v2/types.d.ts +444 -0
  312. package/dist/v2/types.js +19 -0
  313. package/dist/v2/web-playwright-local.d.ts +69 -0
  314. package/dist/v2/web-playwright-local.js +392 -0
  315. package/dist/version.d.ts +1 -0
  316. package/dist/version.js +5 -0
  317. package/dist/video-agent.d.ts +143 -0
  318. package/dist/video-agent.js +4788 -0
  319. package/dist/video-observation.d.ts +36 -0
  320. package/dist/video-observation.js +192 -0
  321. package/dist/video-planner.d.ts +12 -0
  322. package/dist/video-planner.js +501 -0
  323. package/dist/video-prompts.d.ts +37 -0
  324. package/dist/video-prompts.js +554 -0
  325. package/dist/video-tools.d.ts +3 -0
  326. package/dist/video-tools.js +59 -0
  327. package/dist/video-variant-state.d.ts +29 -0
  328. package/dist/video-variant-state.js +80 -0
  329. package/dist/vision-model.d.ts +17 -0
  330. package/dist/vision-model.js +74 -0
  331. package/dist/web-playwright-local.d.ts +126 -0
  332. package/dist/web-playwright-local.js +819 -0
  333. package/dist/ws-auth.d.ts +20 -0
  334. package/dist/ws-auth.js +70 -0
  335. package/dist/ws-broadcast.d.ts +34 -0
  336. package/dist/ws-broadcast.js +85 -0
  337. package/dist/ws-connection-limits.d.ts +12 -0
  338. package/dist/ws-connection-limits.js +44 -0
  339. package/dist/ws-handler-utils.d.ts +32 -0
  340. package/dist/ws-handler-utils.js +139 -0
  341. package/dist/ws-handler.d.ts +10 -0
  342. package/dist/ws-handler.js +1793 -0
  343. package/dist/ws-metrics-server.d.ts +9 -0
  344. package/dist/ws-metrics-server.js +31 -0
  345. package/dist/ws-server.d.ts +9 -0
  346. package/dist/ws-server.js +92 -0
  347. package/package.json +142 -71
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Capture Agent — Benchmark Harness
3
+ *
4
+ * Runs the same preset through V2, comparing:
5
+ * - Total LLM cost
6
+ * - Total wall-clock time
7
+ * - Success rate
8
+ * - Recovery rate (how often healing was needed)
9
+ *
10
+ * Used to prove V2 >= V1 before cutover.
11
+ */
12
+ import { logger } from '../logger.js';
13
+ export async function runBenchmark(presets, runCapture, options) {
14
+ const runsPerPreset = options?.runs ?? 1;
15
+ const results = [];
16
+ for (const preset of presets) {
17
+ logger.info(`[Benchmark] Running "${preset.name}" (${preset.tier}) — ${runsPerPreset} run(s)`);
18
+ for (let run = 0; run < runsPerPreset; run++) {
19
+ try {
20
+ const runResult = await runCapture(preset.program);
21
+ results.push({
22
+ presetName: preset.name,
23
+ tier: preset.tier,
24
+ success: runResult.success,
25
+ totalDurationMs: runResult.totalDurationMs,
26
+ llmCostEur: runResult.telemetry.llmCostEur,
27
+ llmCallCount: runResult.telemetry.llmCallCount,
28
+ totalOpcodes: runResult.telemetry.totalOpcodes,
29
+ recoveredOpcodes: runResult.telemetry.recoveredOpcodes,
30
+ failedOpcodes: runResult.telemetry.failedOpcodes,
31
+ healerInvocations: runResult.telemetry.healerInvocations,
32
+ circuitBreakerTrips: runResult.telemetry.circuitBreakerTrips,
33
+ variantCount: runResult.variantResults.length,
34
+ successfulVariants: runResult.variantResults.filter(v => v.success).length,
35
+ error: runResult.error,
36
+ });
37
+ }
38
+ catch (err) {
39
+ results.push({
40
+ presetName: preset.name,
41
+ tier: preset.tier,
42
+ success: false,
43
+ totalDurationMs: 0,
44
+ llmCostEur: 0,
45
+ llmCallCount: 0,
46
+ totalOpcodes: 0,
47
+ recoveredOpcodes: 0,
48
+ failedOpcodes: 0,
49
+ healerInvocations: 0,
50
+ circuitBreakerTrips: 0,
51
+ variantCount: 0,
52
+ successfulVariants: 0,
53
+ error: err instanceof Error ? err.message : String(err),
54
+ });
55
+ }
56
+ }
57
+ }
58
+ return computeSummary(results);
59
+ }
60
+ // ── Summary computation ─────────────────────────────────────────────
61
+ function computeSummary(results) {
62
+ const total = results.length;
63
+ const successCount = results.filter(r => r.success).length;
64
+ const failCount = total - successCount;
65
+ const totalDuration = results.reduce((sum, r) => sum + r.totalDurationMs, 0);
66
+ const totalLlmCost = results.reduce((sum, r) => sum + r.llmCostEur, 0);
67
+ const totalOpcodes = results.reduce((sum, r) => sum + r.totalOpcodes, 0);
68
+ const totalRecovered = results.reduce((sum, r) => sum + r.recoveredOpcodes, 0);
69
+ const deterministicRuns = results.filter(r => r.llmCallCount === 0 && r.success).length;
70
+ // By tier
71
+ const byTier = {};
72
+ for (const result of results) {
73
+ if (!byTier[result.tier])
74
+ byTier[result.tier] = { total: 0, success: 0, rate: 0 };
75
+ byTier[result.tier].total++;
76
+ if (result.success)
77
+ byTier[result.tier].success++;
78
+ }
79
+ for (const tier of Object.values(byTier)) {
80
+ tier.rate = tier.total > 0 ? tier.success / tier.total : 0;
81
+ }
82
+ return {
83
+ totalPresets: total,
84
+ successCount,
85
+ failCount,
86
+ successRate: total > 0 ? successCount / total : 0,
87
+ averageDurationMs: total > 0 ? totalDuration / total : 0,
88
+ averageLlmCostEur: total > 0 ? totalLlmCost / total : 0,
89
+ totalLlmCostEur: totalLlmCost,
90
+ deterministicRate: total > 0 ? deterministicRuns / total : 0,
91
+ recoveryRate: totalOpcodes > 0 ? totalRecovered / totalOpcodes : 0,
92
+ results,
93
+ byTier,
94
+ };
95
+ }
96
+ // ── Pretty printer ──────────────────────────────────────────────────
97
+ export function formatBenchmarkSummary(summary) {
98
+ const lines = [];
99
+ lines.push('═══════════════════════════════════════════════════');
100
+ lines.push(' V2 Benchmark Summary');
101
+ lines.push('═══════════════════════════════════════════════════');
102
+ lines.push(` Total presets: ${summary.totalPresets}`);
103
+ lines.push(` Success: ${summary.successCount}/${summary.totalPresets} (${(summary.successRate * 100).toFixed(1)}%)`);
104
+ lines.push(` Deterministic rate: ${(summary.deterministicRate * 100).toFixed(1)}% (no LLM needed)`);
105
+ lines.push(` Recovery rate: ${(summary.recoveryRate * 100).toFixed(1)}% of opcodes`);
106
+ lines.push(` Avg duration: ${(summary.averageDurationMs / 1000).toFixed(1)}s`);
107
+ lines.push(` Avg LLM cost: ${summary.averageLlmCostEur.toFixed(4)} EUR`);
108
+ lines.push(` Total LLM cost: ${summary.totalLlmCostEur.toFixed(4)} EUR`);
109
+ lines.push('───────────────────────────────────────────────────');
110
+ for (const [tier, stats] of Object.entries(summary.byTier)) {
111
+ lines.push(` ${tier.padEnd(18)} ${stats.success}/${stats.total} (${(stats.rate * 100).toFixed(0)}%)`);
112
+ }
113
+ lines.push('───────────────────────────────────────────────────');
114
+ for (const result of summary.results) {
115
+ const status = result.success ? 'OK' : 'FAIL';
116
+ const duration = `${(result.totalDurationMs / 1000).toFixed(1)}s`;
117
+ const cost = result.llmCostEur > 0 ? `${result.llmCostEur.toFixed(4)}EUR` : 'free';
118
+ lines.push(` [${status}] ${result.presetName.padEnd(30)} ${duration.padStart(6)} ${cost.padStart(10)}${result.error ? ` — ${result.error.slice(0, 50)}` : ''}`);
119
+ }
120
+ lines.push('═══════════════════════════════════════════════════');
121
+ // Cutover check
122
+ const simpleStats = summary.byTier['simple'];
123
+ const multiStats = summary.byTier['multi_step'];
124
+ const simpleOk = !simpleStats || simpleStats.rate >= 0.95;
125
+ const multiOk = !multiStats || multiStats.rate >= 0.80;
126
+ const costOk = summary.averageLlmCostEur < 0.05;
127
+ lines.push('');
128
+ lines.push(' Cutover Checklist:');
129
+ lines.push(` ${simpleOk ? '[x]' : '[ ]'} Simple scenarios > 95% (${simpleStats ? (simpleStats.rate * 100).toFixed(0) : 'N/A'}%)`);
130
+ lines.push(` ${multiOk ? '[x]' : '[ ]'} Multi-step > 80% (${multiStats ? (multiStats.rate * 100).toFixed(0) : 'N/A'}%)`);
131
+ lines.push(` ${costOk ? '[x]' : '[ ]'} Avg cost < 0.05 EUR (${summary.averageLlmCostEur.toFixed(4)} EUR)`);
132
+ lines.push('');
133
+ return lines.join('\n');
134
+ }
135
+ //# sourceMappingURL=benchmark.js.map
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Capture Agent — Capture Strategy
3
+ *
4
+ * Abstraction over the two V2 media modes: screenshot and clip.
5
+ * The opcode runner is identical for all three — only the capture
6
+ * opcodes dispatch to different strategies.
7
+ */
8
+ import type { ArtifactSpec, ArtifactResult, RuntimeAdapter, MediaMode } from './types.js';
9
+ export interface CaptureStrategy {
10
+ readonly mediaMode: MediaMode;
11
+ /** Prepare the adapter for capture (e.g. lock viewport, inject cursor overlay) */
12
+ prepare(adapter: RuntimeAdapter, spec: ArtifactSpec): Promise<void>;
13
+ /** Perform the capture and return the raw artifact */
14
+ capture(adapter: RuntimeAdapter, spec: ArtifactSpec): Promise<ArtifactResult>;
15
+ /** Post-process the artifact (mockup frame, status bar, format conversion) */
16
+ postProcess(artifact: ArtifactResult, spec: ArtifactSpec): Promise<ArtifactResult>;
17
+ }
18
+ export declare class ScreenshotStrategy implements CaptureStrategy {
19
+ readonly mediaMode: "screenshot";
20
+ prepare(_adapter: RuntimeAdapter, _spec: ArtifactSpec): Promise<void>;
21
+ capture(adapter: RuntimeAdapter, _spec: ArtifactSpec): Promise<ArtifactResult>;
22
+ postProcess(artifact: ArtifactResult, spec: ArtifactSpec): Promise<ArtifactResult>;
23
+ }
24
+ export declare class ClipStrategy implements CaptureStrategy {
25
+ readonly mediaMode: "clip";
26
+ prepare(adapter: RuntimeAdapter, _spec: ArtifactSpec): Promise<void>;
27
+ capture(adapter: RuntimeAdapter, _spec: ArtifactSpec): Promise<ArtifactResult>;
28
+ postProcess(artifact: ArtifactResult, spec: ArtifactSpec): Promise<ArtifactResult>;
29
+ }
30
+ export declare function createCaptureStrategy(mediaMode: MediaMode): CaptureStrategy;
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Capture Agent — Capture Strategy
3
+ *
4
+ * Abstraction over the two V2 media modes: screenshot and clip.
5
+ * The opcode runner is identical for all three — only the capture
6
+ * opcodes dispatch to different strategies.
7
+ */
8
+ // ── Screenshot strategy ─────────────────────────────────────────────
9
+ export class ScreenshotStrategy {
10
+ mediaMode = 'screenshot';
11
+ async prepare(_adapter, _spec) {
12
+ // Viewport locking is handled externally by the CLI runner
13
+ // when creating the browser context per variant.
14
+ }
15
+ async capture(adapter, _spec) {
16
+ const buffer = await adapter.takeScreenshot();
17
+ return {
18
+ mediaMode: 'screenshot',
19
+ buffer,
20
+ mimeType: 'image/png',
21
+ };
22
+ }
23
+ async postProcess(artifact, spec) {
24
+ // Post-processing (mockup frame, status bar) will be applied
25
+ // by the CLI runner using existing utilities:
26
+ // - applyDeviceFrame() from src/mockup.ts
27
+ // - generateStatusBarHtml() from src/status-bar.ts
28
+ // For now, return as-is. Phase 4 CLI runner handles the orchestration.
29
+ return artifact;
30
+ }
31
+ }
32
+ // ── Clip strategy ───────────────────────────────────────────────────
33
+ export class ClipStrategy {
34
+ mediaMode = 'clip';
35
+ async prepare(adapter, _spec) {
36
+ // Clip recording preparation:
37
+ // - The browser context is created with video recording enabled
38
+ // - Cursor overlay is injected by Browser.forVideoRecording()
39
+ }
40
+ async capture(adapter, _spec) {
41
+ // Clip capture is bounded by BEGIN_CLIP / END_CLIP opcodes.
42
+ // The opcode runner calls adapter.beginRecording() and adapter.endRecording().
43
+ // This method is called for the final artifact assembly.
44
+ const recording = await adapter.endRecording();
45
+ return {
46
+ mediaMode: 'clip',
47
+ buffer: recording.buffer,
48
+ mimeType: recording.mimeType,
49
+ };
50
+ }
51
+ async postProcess(artifact, spec) {
52
+ // Post-processing for clips:
53
+ // - Convert WebM to GIF/MP4 via src/clip-postprocess.ts (if it exists)
54
+ // - Trim start/end
55
+ // - Apply cursor theme
56
+ // Handled by CLI runner using existing video processing utilities.
57
+ return artifact;
58
+ }
59
+ }
60
+ // ── Factory ─────────────────────────────────────────────────────────
61
+ export function createCaptureStrategy(mediaMode) {
62
+ switch (mediaMode) {
63
+ case 'screenshot': return new ScreenshotStrategy();
64
+ case 'clip': return new ClipStrategy();
65
+ }
66
+ }
67
+ //# sourceMappingURL=capture-strategy.js.map
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Capture Agent — Capture Verification
3
+ *
4
+ * Post-capture quality check via LLM vision.
5
+ * Detects: blank pages, error pages, loading spinners, skeletons,
6
+ * obstructing overlays, and other visual issues.
7
+ *
8
+ * This is the ONLY place where AutoKap uses AI at runtime.
9
+ * Cost: ~0.002 EUR per check (1 image + short prompt).
10
+ */
11
+ import { type LLMProviderConfig, type LLMCallResult } from './llm-provider.js';
12
+ export interface VerificationResult {
13
+ /** Whether the screenshot is acceptable for delivery */
14
+ passed: boolean;
15
+ /** Issue detected (if failed) */
16
+ issue?: 'blank_page' | 'error_page' | 'loading' | 'overlay_blocking' | 'wrong_content' | 'other';
17
+ /** Human-readable explanation */
18
+ reason: string;
19
+ /** LLM call metadata */
20
+ llmResult?: LLMCallResult;
21
+ }
22
+ export interface VerificationContext {
23
+ /** What was this screenshot supposed to show? */
24
+ expectedDescription: string;
25
+ /** Target URL */
26
+ url: string;
27
+ /** Locale of this variant */
28
+ locale?: string;
29
+ /** Theme of this variant */
30
+ theme?: string;
31
+ }
32
+ /**
33
+ * Verifies a captured screenshot is clean and ready for delivery.
34
+ */
35
+ export declare function verifyCaptureQuality(screenshot: Buffer, context: VerificationContext, llmConfig: LLMProviderConfig): Promise<VerificationResult>;
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Capture Agent — Capture Verification
3
+ *
4
+ * Post-capture quality check via LLM vision.
5
+ * Detects: blank pages, error pages, loading spinners, skeletons,
6
+ * obstructing overlays, and other visual issues.
7
+ *
8
+ * This is the ONLY place where AutoKap uses AI at runtime.
9
+ * Cost: ~0.002 EUR per check (1 image + short prompt).
10
+ */
11
+ import { callLLM } from './llm-provider.js';
12
+ const SYSTEM_PROMPT = `You are a screenshot quality checker for a web capture tool. You receive a screenshot of a web page and must verify it is clean and ready for delivery.
13
+
14
+ Check for these issues:
15
+ 1. BLANK - The page is completely white/blank or has no meaningful content
16
+ 2. ERROR - The page shows an error message (404, 500, "something went wrong", crash screen)
17
+ 3. LOADING - The page has visible loading indicators (spinners, skeletons, progress bars, "Loading..." text)
18
+ 4. OVERLAY - A modal, popup, cookie banner, or other overlay is blocking the main content
19
+ 5. WRONG - The content doesn't match what was expected
20
+
21
+ Respond with EXACTLY one line in this format:
22
+ PASS: Screenshot looks clean and ready.
23
+ or
24
+ FAIL:<issue>: <explanation>
25
+
26
+ Where <issue> is one of: blank_page, error_page, loading, overlay_blocking, wrong_content, other
27
+
28
+ Examples:
29
+ PASS: Screenshot looks clean and ready.
30
+ FAIL:loading: A skeleton loader is visible in the main content area.
31
+ FAIL:overlay_blocking: A cookie consent banner covers the bottom of the page.
32
+ FAIL:error_page: The page shows a 404 Not Found error.`;
33
+ /**
34
+ * Verifies a captured screenshot is clean and ready for delivery.
35
+ */
36
+ export async function verifyCaptureQuality(screenshot, context, llmConfig) {
37
+ const userPrompt = buildUserPrompt(context);
38
+ try {
39
+ const result = await callLLM(llmConfig, SYSTEM_PROMPT, userPrompt, screenshot);
40
+ return parseVerificationResponse(result.text, result);
41
+ }
42
+ catch (err) {
43
+ // If LLM fails, pass the screenshot — don't block delivery because of LLM issues
44
+ return {
45
+ passed: true,
46
+ reason: `verification skipped (LLM error: ${err instanceof Error ? err.message : String(err)})`,
47
+ };
48
+ }
49
+ }
50
+ function buildUserPrompt(context) {
51
+ const parts = [
52
+ `Expected content: ${context.expectedDescription}`,
53
+ `URL: ${context.url}`,
54
+ ];
55
+ if (context.locale)
56
+ parts.push(`Locale: ${context.locale}`);
57
+ if (context.theme)
58
+ parts.push(`Theme: ${context.theme}`);
59
+ parts.push('\nIs this screenshot clean and ready for delivery?');
60
+ return parts.join('\n');
61
+ }
62
+ function parseVerificationResponse(text, llmResult) {
63
+ const trimmed = text.trim();
64
+ if (trimmed.startsWith('PASS')) {
65
+ return {
66
+ passed: true,
67
+ reason: trimmed.replace(/^PASS:?\s*/, ''),
68
+ llmResult,
69
+ };
70
+ }
71
+ if (trimmed.startsWith('FAIL')) {
72
+ const match = trimmed.match(/^FAIL:(\w+):\s*(.+)/);
73
+ if (match) {
74
+ return {
75
+ passed: false,
76
+ issue: match[1],
77
+ reason: match[2],
78
+ llmResult,
79
+ };
80
+ }
81
+ return {
82
+ passed: false,
83
+ issue: 'other',
84
+ reason: trimmed.replace(/^FAIL:?\s*/, ''),
85
+ llmResult,
86
+ };
87
+ }
88
+ // Ambiguous response — assume pass
89
+ return {
90
+ passed: true,
91
+ reason: `ambiguous LLM response: "${trimmed.slice(0, 100)}"`,
92
+ llmResult,
93
+ };
94
+ }
95
+ //# sourceMappingURL=capture-verification.js.map
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Capture Agent — Circuit Breaker
3
+ *
4
+ * Three-level circuit breaker to prevent infinite recovery loops:
5
+ * - Per-opcode: max failures before the opcode is abandoned
6
+ * - Per-page: max failures across all opcodes on the same page
7
+ * - Per-run: max total failures across the entire program
8
+ */
9
+ import type { CircuitBreakerConfig } from './types.js';
10
+ export type BreakerTrip = 'opcode' | 'page' | 'run';
11
+ export interface BreakerState {
12
+ tripped: boolean;
13
+ level?: BreakerTrip;
14
+ reason: string;
15
+ opcodeFailures: number;
16
+ pageFailures: number;
17
+ runFailures: number;
18
+ }
19
+ export declare class CircuitBreaker {
20
+ private config;
21
+ private opcodeFailures;
22
+ private pageFailures;
23
+ private runFailures;
24
+ private currentPageKey;
25
+ constructor(config?: CircuitBreakerConfig);
26
+ /** Set the current page context (URL-based key) */
27
+ setPage(url: string): void;
28
+ /** Record a failure for an opcode. Returns breaker state. */
29
+ recordFailure(opcodeIndex: number, maxPerOpcode?: number): BreakerState;
30
+ /** Record a success for an opcode (resets opcode-level counter) */
31
+ recordSuccess(opcodeIndex: number): void;
32
+ /** Check if the breaker is currently tripped at any level */
33
+ isTripped(): BreakerState;
34
+ /** Get summary of all failure counts */
35
+ getSummary(): {
36
+ opcodeFailures: Record<number, number>;
37
+ pageFailures: Record<string, number>;
38
+ runFailures: number;
39
+ };
40
+ /** Reset all counters */
41
+ reset(): void;
42
+ }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Capture Agent — Circuit Breaker
3
+ *
4
+ * Three-level circuit breaker to prevent infinite recovery loops:
5
+ * - Per-opcode: max failures before the opcode is abandoned
6
+ * - Per-page: max failures across all opcodes on the same page
7
+ * - Per-run: max total failures across the entire program
8
+ */
9
+ import { DEFAULT_CIRCUIT_BREAKER } from './types.js';
10
+ export class CircuitBreaker {
11
+ config;
12
+ opcodeFailures = new Map();
13
+ pageFailures = new Map();
14
+ runFailures = 0;
15
+ currentPageKey = null;
16
+ constructor(config = DEFAULT_CIRCUIT_BREAKER) {
17
+ this.config = config;
18
+ }
19
+ /** Set the current page context (URL-based key) */
20
+ setPage(url) {
21
+ this.currentPageKey = new URL(url).pathname;
22
+ }
23
+ /** Record a failure for an opcode. Returns breaker state. */
24
+ recordFailure(opcodeIndex, maxPerOpcode = this.config.maxPerOpcode) {
25
+ // Opcode level
26
+ const opcodeFails = (this.opcodeFailures.get(opcodeIndex) ?? 0) + 1;
27
+ this.opcodeFailures.set(opcodeIndex, opcodeFails);
28
+ // Page level
29
+ const pageKey = this.currentPageKey ?? 'unknown';
30
+ const pageFails = (this.pageFailures.get(pageKey) ?? 0) + 1;
31
+ this.pageFailures.set(pageKey, pageFails);
32
+ // Run level
33
+ this.runFailures++;
34
+ // Check breakers from most specific to least
35
+ if (opcodeFails >= maxPerOpcode) {
36
+ return {
37
+ tripped: true,
38
+ level: 'opcode',
39
+ reason: `opcode ${opcodeIndex} reached ${opcodeFails}/${maxPerOpcode} failures`,
40
+ opcodeFailures: opcodeFails,
41
+ pageFailures: pageFails,
42
+ runFailures: this.runFailures,
43
+ };
44
+ }
45
+ if (pageFails >= this.config.maxPerPage) {
46
+ return {
47
+ tripped: true,
48
+ level: 'page',
49
+ reason: `page "${pageKey}" reached ${pageFails}/${this.config.maxPerPage} failures`,
50
+ opcodeFailures: opcodeFails,
51
+ pageFailures: pageFails,
52
+ runFailures: this.runFailures,
53
+ };
54
+ }
55
+ if (this.runFailures >= this.config.maxPerRun) {
56
+ return {
57
+ tripped: true,
58
+ level: 'run',
59
+ reason: `run reached ${this.runFailures}/${this.config.maxPerRun} total failures`,
60
+ opcodeFailures: opcodeFails,
61
+ pageFailures: pageFails,
62
+ runFailures: this.runFailures,
63
+ };
64
+ }
65
+ return {
66
+ tripped: false,
67
+ reason: `opcode ${opcodeIndex}: ${opcodeFails}/${maxPerOpcode}, page: ${pageFails}/${this.config.maxPerPage}, run: ${this.runFailures}/${this.config.maxPerRun}`,
68
+ opcodeFailures: opcodeFails,
69
+ pageFailures: pageFails,
70
+ runFailures: this.runFailures,
71
+ };
72
+ }
73
+ /** Record a success for an opcode (resets opcode-level counter) */
74
+ recordSuccess(opcodeIndex) {
75
+ this.opcodeFailures.delete(opcodeIndex);
76
+ }
77
+ /** Check if the breaker is currently tripped at any level */
78
+ isTripped() {
79
+ if (this.runFailures >= this.config.maxPerRun) {
80
+ return {
81
+ tripped: true,
82
+ level: 'run',
83
+ reason: `run limit reached: ${this.runFailures}/${this.config.maxPerRun}`,
84
+ opcodeFailures: 0,
85
+ pageFailures: 0,
86
+ runFailures: this.runFailures,
87
+ };
88
+ }
89
+ const pageKey = this.currentPageKey ?? 'unknown';
90
+ const pageFails = this.pageFailures.get(pageKey) ?? 0;
91
+ if (pageFails >= this.config.maxPerPage) {
92
+ return {
93
+ tripped: true,
94
+ level: 'page',
95
+ reason: `page limit reached: ${pageFails}/${this.config.maxPerPage}`,
96
+ opcodeFailures: 0,
97
+ pageFailures: pageFails,
98
+ runFailures: this.runFailures,
99
+ };
100
+ }
101
+ return { tripped: false, reason: 'ok', opcodeFailures: 0, pageFailures: pageFails, runFailures: this.runFailures };
102
+ }
103
+ /** Get summary of all failure counts */
104
+ getSummary() {
105
+ return {
106
+ opcodeFailures: Object.fromEntries(this.opcodeFailures),
107
+ pageFailures: Object.fromEntries(this.pageFailures),
108
+ runFailures: this.runFailures,
109
+ };
110
+ }
111
+ /** Reset all counters */
112
+ reset() {
113
+ this.opcodeFailures.clear();
114
+ this.pageFailures.clear();
115
+ this.runFailures = 0;
116
+ this.currentPageKey = null;
117
+ }
118
+ }
119
+ //# sourceMappingURL=circuit-breaker.js.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Capture Agent — CLI command wrapper
3
+ *
4
+ * `autokap run` stays local-first: Playwright runs on the user's machine.
5
+ * The server only provides the compiled program and persists artifacts/results.
6
+ */
7
+ export declare function runLocal(presetId: string, opts: {
8
+ headed: boolean;
9
+ output?: string;
10
+ program?: string;
11
+ }): Promise<void>;
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Capture Agent — CLI command wrapper
3
+ *
4
+ * `autokap run` stays local-first: Playwright runs on the user's machine.
5
+ * The server only provides the compiled program and persists artifacts/results.
6
+ */
7
+ import path from 'node:path';
8
+ import fs from 'node:fs/promises';
9
+ import { logger } from '../logger.js';
10
+ import { parseProgram } from './schema.js';
11
+ import { runCapture } from './cli-runner.js';
12
+ export async function runLocal(presetId, opts) {
13
+ let program;
14
+ if (opts.program) {
15
+ try {
16
+ const raw = await fs.readFile(opts.program, 'utf-8');
17
+ program = parseProgram(JSON.parse(raw));
18
+ logger.info(`[capture] Loaded program from file: ${opts.program}`);
19
+ }
20
+ catch (err) {
21
+ logger.error(`[capture] Failed to load program: ${err instanceof Error ? err.message : String(err)}`);
22
+ process.exit(1);
23
+ }
24
+ }
25
+ const run = await runCapture({
26
+ presetId,
27
+ program,
28
+ headed: opts.headed,
29
+ onProgress: (event) => {
30
+ const prefix = `[capture][${event.variantId}]`;
31
+ switch (event.type) {
32
+ case 'variant_start':
33
+ logger.info(`${prefix} Starting variant`);
34
+ break;
35
+ case 'variant_end':
36
+ logger.info(`${prefix} ${event.status === 'ok' ? 'DONE' : 'FAILED'}: ${event.message}`);
37
+ break;
38
+ case 'opcode_start':
39
+ logger.info(`${prefix}[${event.opcodeIndex}] >> ${event.opcodeKind}: ${event.message}`);
40
+ break;
41
+ case 'opcode_end':
42
+ if (event.status === 'ok') {
43
+ logger.info(`${prefix}[${event.opcodeIndex}] << OK (${event.opcodeKind})`);
44
+ }
45
+ else if (event.status === 'recovered') {
46
+ logger.warn(`${prefix}[${event.opcodeIndex}] << RECOVERED: ${event.message}`);
47
+ }
48
+ else {
49
+ logger.error(`${prefix}[${event.opcodeIndex}] << FAILED: ${event.message}`);
50
+ }
51
+ break;
52
+ case 'recovery':
53
+ logger.warn(`${prefix}[${event.opcodeIndex}] RECOVERY: ${event.message}`);
54
+ break;
55
+ case 'breaker_trip':
56
+ logger.error(`${prefix} CIRCUIT BREAKER: ${event.message}`);
57
+ break;
58
+ }
59
+ },
60
+ });
61
+ if (run.runResult && opts.output) {
62
+ await persistArtifactsLocally(presetId, opts.output, run.runResult.variantResults);
63
+ }
64
+ if (!run.success) {
65
+ logger.error(`Error: ${run.error ?? run.runResult?.error ?? 'capture failed'}`);
66
+ process.exit(1);
67
+ }
68
+ process.exit(0);
69
+ }
70
+ async function persistArtifactsLocally(presetId, outputDirOption, variants) {
71
+ const outputDir = path.resolve(outputDirOption);
72
+ await fs.mkdir(outputDir, { recursive: true });
73
+ for (const variant of variants) {
74
+ for (let index = 0; index < variant.artifacts.length; index += 1) {
75
+ const artifact = variant.artifacts[index];
76
+ const ext = artifact.mimeType === 'image/png'
77
+ ? 'png'
78
+ : artifact.mimeType === 'image/jpeg'
79
+ ? 'jpg'
80
+ : artifact.mimeType.includes('gif')
81
+ ? 'gif'
82
+ : artifact.mimeType.includes('mp4')
83
+ ? 'mp4'
84
+ : 'webm';
85
+ const filePath = path.join(outputDir, `v2-${presetId.slice(0, 8)}-${variant.variantId}-${index}.${ext}`);
86
+ await fs.writeFile(filePath, artifact.buffer);
87
+ logger.info(`[capture] Artifact saved locally: ${filePath}`);
88
+ }
89
+ }
90
+ }
91
+ //# sourceMappingURL=cli-runner-local.js.map
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Capture Agent — CLI Runner
3
+ *
4
+ * Entry point for V2 execution from the CLI.
5
+ * Flow:
6
+ * 1. Authenticate via stored API key
7
+ * 2. Fetch compiled program from server
8
+ * 3. Validate program against Zod schema
9
+ * 4. Launch local Playwright browser per variant
10
+ * 5. Execute program via opcode-runner
11
+ * 6. Upload artifacts + telemetry to server
12
+ */
13
+ import { type ProgressEvent } from './opcode-runner.js';
14
+ import type { ExecutionProgram, RunResult } from './types.js';
15
+ export interface CLIRunnerOptions {
16
+ /** Preset ID to run */
17
+ presetId: string;
18
+ /** Override: provide program directly instead of fetching from server */
19
+ program?: ExecutionProgram;
20
+ /** Selector memory map (fetched from server or cached locally) */
21
+ selectorMemory?: Record<string, string[]>;
22
+ /** Show browser window. Default: false (headless) */
23
+ headed?: boolean;
24
+ /** Abort signal for cancellation */
25
+ abortSignal?: AbortSignal;
26
+ /** Progress callback */
27
+ onProgress?: (event: ProgressEvent) => void;
28
+ }
29
+ export interface CLIRunResult {
30
+ success: boolean;
31
+ runResult?: RunResult;
32
+ error?: string;
33
+ }
34
+ export declare function runCapture(options: CLIRunnerOptions): Promise<CLIRunResult>;