autokap 1.0.7 → 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 (278) hide show
  1. package/assets/cursors/macos.svg +4 -0
  2. package/assets/cursors/windows.svg +15 -0
  3. package/assets/skill/OPCODE-REFERENCE.md +607 -0
  4. package/assets/skill/README.md +39 -0
  5. package/assets/skill/SKILL.md +453 -468
  6. package/assets/skill/STUDIO-SKILL.md +476 -0
  7. package/assets/skill/references/examples.md +104 -0
  8. package/assets/skill/references/interactive-demo.md +225 -0
  9. package/assets/skill/references/mock-data.md +178 -0
  10. package/dist/action-verifier.d.ts +29 -0
  11. package/dist/action-verifier.js +133 -0
  12. package/dist/agent-action-recovery.d.ts +45 -0
  13. package/dist/agent-action-recovery.js +370 -0
  14. package/dist/agent-message-utils.d.ts +21 -0
  15. package/dist/agent-message-utils.js +77 -0
  16. package/dist/agent-url-utils.d.ts +30 -0
  17. package/dist/agent-url-utils.js +138 -0
  18. package/dist/agent.d.ts +92 -8
  19. package/dist/agent.js +2936 -781
  20. package/dist/ak-tree.d.ts +39 -0
  21. package/dist/ak-tree.js +368 -0
  22. package/dist/alt-text.d.ts +26 -0
  23. package/dist/alt-text.js +55 -0
  24. package/dist/auth-capture.d.ts +17 -0
  25. package/dist/auth-capture.js +164 -0
  26. package/dist/benchmark.d.ts +59 -0
  27. package/dist/benchmark.js +135 -0
  28. package/dist/browser-bar.d.ts +14 -6
  29. package/dist/browser-bar.js +145 -8
  30. package/dist/browser-pool.d.ts +7 -0
  31. package/dist/browser-pool.js +15 -5
  32. package/dist/browser-utils.d.ts +31 -0
  33. package/dist/browser-utils.js +97 -0
  34. package/dist/browser.d.ts +51 -1
  35. package/dist/browser.js +1481 -31
  36. package/dist/capture-alt-text.js +2 -1
  37. package/dist/capture-language-preflight.js +14 -0
  38. package/dist/capture-llm-page-identity.js +22 -10
  39. package/dist/capture-page-identity.d.ts +5 -7
  40. package/dist/capture-page-identity.js +211 -78
  41. package/dist/capture-preset-credentials.d.ts +50 -0
  42. package/dist/capture-preset-credentials.js +127 -0
  43. package/dist/capture-request-plan.d.ts +2 -2
  44. package/dist/capture-request-plan.js +64 -16
  45. package/dist/capture-run-optimizer.js +48 -33
  46. package/dist/capture-selector-memory.d.ts +5 -0
  47. package/dist/capture-selector-memory.js +18 -0
  48. package/dist/capture-strategy.d.ts +36 -0
  49. package/dist/capture-strategy.js +95 -0
  50. package/dist/capture-studio-sync.d.ts +1 -0
  51. package/dist/capture-studio-sync.js +9 -3
  52. package/dist/capture-surface-contract.d.ts +36 -0
  53. package/dist/capture-surface-contract.js +299 -0
  54. package/dist/capture-transition-engine.d.ts +28 -0
  55. package/dist/capture-transition-engine.js +292 -0
  56. package/dist/capture-variant-state.d.ts +2 -0
  57. package/dist/capture-variant-state.js +26 -0
  58. package/dist/capture-verification.d.ts +35 -0
  59. package/dist/capture-verification.js +95 -0
  60. package/dist/capture-viewport-lock.d.ts +48 -0
  61. package/dist/capture-viewport-lock.js +74 -0
  62. package/dist/circuit-breaker.d.ts +42 -0
  63. package/dist/circuit-breaker.js +119 -0
  64. package/dist/cli-config.d.ts +8 -1
  65. package/dist/cli-config.js +62 -6
  66. package/dist/cli-contract.d.ts +15 -0
  67. package/dist/cli-contract.js +167 -0
  68. package/dist/cli-runner-local.d.ts +12 -0
  69. package/dist/cli-runner-local.js +102 -0
  70. package/dist/cli-runner.d.ts +34 -0
  71. package/dist/cli-runner.js +433 -0
  72. package/dist/cli-utils.d.ts +0 -1
  73. package/dist/cli-utils.js +2 -5
  74. package/dist/cli.js +1005 -267
  75. package/dist/clip-orchestrator.js +9 -2
  76. package/dist/clip-postprocess.js +25 -16
  77. package/dist/cookie-dismiss.d.ts +2 -0
  78. package/dist/cookie-dismiss.js +48 -13
  79. package/dist/cost-logging.d.ts +8 -0
  80. package/dist/cost-logging.js +160 -46
  81. package/dist/cost-resolution-monitor.d.ts +16 -0
  82. package/dist/cost-resolution-monitor.js +34 -0
  83. package/dist/credential-templates.js +2 -2
  84. package/dist/cursor-overlay-script.d.ts +6 -0
  85. package/dist/cursor-overlay-script.js +169 -0
  86. package/dist/dom-css-purger.d.ts +65 -0
  87. package/dist/dom-css-purger.js +333 -0
  88. package/dist/dom-font-inliner.d.ts +45 -0
  89. package/dist/dom-font-inliner.js +148 -0
  90. package/dist/dom-patch-resolver.d.ts +52 -0
  91. package/dist/dom-patch-resolver.js +242 -0
  92. package/dist/dom-serializer.d.ts +82 -0
  93. package/dist/dom-serializer.js +378 -0
  94. package/dist/element-capture.d.ts +1 -41
  95. package/dist/element-capture.js +202 -446
  96. package/dist/env-validation.d.ts +5 -0
  97. package/dist/env-validation.js +29 -0
  98. package/dist/execution-schema.d.ts +4423 -0
  99. package/dist/execution-schema.js +507 -0
  100. package/dist/execution-types.d.ts +886 -0
  101. package/dist/execution-types.js +65 -0
  102. package/dist/fonts-loader.d.ts +14 -0
  103. package/dist/fonts-loader.js +55 -0
  104. package/dist/hybrid-navigator.js +12 -12
  105. package/dist/index.d.ts +9 -6
  106. package/dist/index.js +10 -4
  107. package/dist/legacy/agent-action-recovery.d.ts +45 -0
  108. package/dist/legacy/agent-action-recovery.js +370 -0
  109. package/dist/legacy/agent-message-utils.d.ts +21 -0
  110. package/dist/legacy/agent-message-utils.js +77 -0
  111. package/dist/legacy/agent-url-utils.d.ts +30 -0
  112. package/dist/legacy/agent-url-utils.js +138 -0
  113. package/dist/legacy/agent.d.ts +226 -0
  114. package/dist/legacy/agent.js +6666 -0
  115. package/dist/legacy/clip-orchestrator.d.ts +148 -0
  116. package/dist/legacy/clip-orchestrator.js +957 -0
  117. package/dist/legacy/credential-templates.d.ts +5 -0
  118. package/dist/legacy/credential-templates.js +60 -0
  119. package/dist/legacy/hybrid-navigator.d.ts +138 -0
  120. package/dist/legacy/hybrid-navigator.js +468 -0
  121. package/dist/legacy/llm-usage.d.ts +17 -0
  122. package/dist/legacy/llm-usage.js +45 -0
  123. package/dist/legacy/prompt-cache.d.ts +10 -0
  124. package/dist/legacy/prompt-cache.js +24 -0
  125. package/dist/legacy/prompts.d.ts +175 -0
  126. package/dist/legacy/prompts.js +1038 -0
  127. package/dist/legacy/tools.d.ts +4 -0
  128. package/dist/legacy/tools.js +216 -0
  129. package/dist/legacy/video-agent.d.ts +143 -0
  130. package/dist/legacy/video-agent.js +4788 -0
  131. package/dist/legacy/video-observation.d.ts +36 -0
  132. package/dist/legacy/video-observation.js +192 -0
  133. package/dist/legacy/video-planner.d.ts +12 -0
  134. package/dist/legacy/video-planner.js +501 -0
  135. package/dist/legacy/video-prompts.d.ts +37 -0
  136. package/dist/legacy/video-prompts.js +569 -0
  137. package/dist/legacy/video-tools.d.ts +3 -0
  138. package/dist/legacy/video-tools.js +59 -0
  139. package/dist/legacy/video-variant-state.d.ts +29 -0
  140. package/dist/legacy/video-variant-state.js +80 -0
  141. package/dist/legacy/vision-model.d.ts +17 -0
  142. package/dist/legacy/vision-model.js +74 -0
  143. package/dist/llm-healer.d.ts +63 -0
  144. package/dist/llm-healer.js +166 -0
  145. package/dist/llm-provider.d.ts +29 -0
  146. package/dist/llm-provider.js +80 -0
  147. package/dist/logger.d.ts +6 -2
  148. package/dist/logger.js +15 -1
  149. package/dist/mockup-html.js +35 -25
  150. package/dist/mockup.d.ts +95 -2
  151. package/dist/mockup.js +427 -166
  152. package/dist/mouse-animation.d.ts +2 -2
  153. package/dist/mouse-animation.js +34 -20
  154. package/dist/opcode-actions.d.ts +42 -0
  155. package/dist/opcode-actions.js +511 -0
  156. package/dist/opcode-runner.d.ts +51 -0
  157. package/dist/opcode-runner.js +770 -0
  158. package/dist/openrouter-client.d.ts +40 -0
  159. package/dist/openrouter-client.js +16 -0
  160. package/dist/overlay-engine.d.ts +24 -0
  161. package/dist/overlay-engine.js +176 -0
  162. package/dist/postcondition.d.ts +16 -0
  163. package/dist/postcondition.js +269 -0
  164. package/dist/program-patcher.d.ts +25 -0
  165. package/dist/program-patcher.js +44 -0
  166. package/dist/prompts.d.ts +13 -5
  167. package/dist/prompts.js +224 -351
  168. package/dist/provider-config.d.ts +12 -0
  169. package/dist/provider-config.js +15 -0
  170. package/dist/recovery-chain.d.ts +37 -0
  171. package/dist/recovery-chain.js +350 -0
  172. package/dist/remote-browser.d.ts +28 -4
  173. package/dist/remote-browser.js +60 -5
  174. package/dist/safari-browser-bar.d.ts +15 -0
  175. package/dist/safari-browser-bar.js +95 -0
  176. package/dist/safari-toolbar-asset.d.ts +15 -0
  177. package/dist/safari-toolbar-asset.js +12 -0
  178. package/dist/security.d.ts +2 -1
  179. package/dist/security.js +49 -10
  180. package/dist/selector-resolver.d.ts +34 -0
  181. package/dist/selector-resolver.js +181 -0
  182. package/dist/semantic-resolver.d.ts +35 -0
  183. package/dist/semantic-resolver.js +161 -0
  184. package/dist/server-capture-runtime.d.ts +5 -3
  185. package/dist/server-capture-runtime.js +42 -95
  186. package/dist/server-credit-usage.d.ts +2 -2
  187. package/dist/server-project-webhooks.d.ts +15 -1
  188. package/dist/server-project-webhooks.js +34 -8
  189. package/dist/server-screenshot-watermark.js +27 -5
  190. package/dist/session-profile.js +164 -1
  191. package/dist/sf-pro-symbols.d.ts +1 -0
  192. package/dist/sf-pro-symbols.js +55 -0
  193. package/dist/skill-packaging.d.ts +28 -0
  194. package/dist/skill-packaging.js +169 -0
  195. package/dist/smart-wait.d.ts +27 -0
  196. package/dist/smart-wait.js +81 -0
  197. package/dist/status-bar-render.d.ts +20 -0
  198. package/dist/status-bar-render.js +410 -0
  199. package/dist/status-bar.d.ts +9 -0
  200. package/dist/status-bar.js +298 -14
  201. package/dist/svg-browser-bar.d.ts +33 -0
  202. package/dist/svg-browser-bar.js +206 -0
  203. package/dist/svg-status-bar.d.ts +36 -0
  204. package/dist/svg-status-bar.js +597 -0
  205. package/dist/svg-text.d.ts +61 -0
  206. package/dist/svg-text.js +118 -0
  207. package/dist/tools.js +89 -451
  208. package/dist/types.d.ts +240 -5
  209. package/dist/types.js +23 -1
  210. package/dist/v2/action-verifier.d.ts +29 -0
  211. package/dist/v2/action-verifier.js +133 -0
  212. package/dist/v2/alt-text.d.ts +26 -0
  213. package/dist/v2/alt-text.js +55 -0
  214. package/dist/v2/benchmark.d.ts +59 -0
  215. package/dist/v2/benchmark.js +135 -0
  216. package/dist/v2/capture-strategy.d.ts +30 -0
  217. package/dist/v2/capture-strategy.js +67 -0
  218. package/dist/v2/capture-verification.d.ts +35 -0
  219. package/dist/v2/capture-verification.js +95 -0
  220. package/dist/v2/circuit-breaker.d.ts +42 -0
  221. package/dist/v2/circuit-breaker.js +119 -0
  222. package/dist/v2/cli-runner-local.d.ts +11 -0
  223. package/dist/v2/cli-runner-local.js +91 -0
  224. package/dist/v2/cli-runner.d.ts +34 -0
  225. package/dist/v2/cli-runner.js +300 -0
  226. package/dist/v2/compiler-prompts.d.ts +27 -0
  227. package/dist/v2/compiler-prompts.js +123 -0
  228. package/dist/v2/compiler.d.ts +37 -0
  229. package/dist/v2/compiler.js +147 -0
  230. package/dist/v2/explorer.d.ts +41 -0
  231. package/dist/v2/explorer.js +56 -0
  232. package/dist/v2/index.d.ts +37 -0
  233. package/dist/v2/index.js +31 -0
  234. package/dist/v2/llm-healer.d.ts +62 -0
  235. package/dist/v2/llm-healer.js +166 -0
  236. package/dist/v2/llm-provider.d.ts +29 -0
  237. package/dist/v2/llm-provider.js +80 -0
  238. package/dist/v2/opcode-runner.d.ts +47 -0
  239. package/dist/v2/opcode-runner.js +634 -0
  240. package/dist/v2/overlay-engine.d.ts +24 -0
  241. package/dist/v2/overlay-engine.js +150 -0
  242. package/dist/v2/postcondition.d.ts +16 -0
  243. package/dist/v2/postcondition.js +249 -0
  244. package/dist/v2/program-patcher.d.ts +25 -0
  245. package/dist/v2/program-patcher.js +44 -0
  246. package/dist/v2/recovery-chain.d.ts +30 -0
  247. package/dist/v2/recovery-chain.js +368 -0
  248. package/dist/v2/schema.d.ts +2580 -0
  249. package/dist/v2/schema.js +295 -0
  250. package/dist/v2/selector-resolver.d.ts +34 -0
  251. package/dist/v2/selector-resolver.js +181 -0
  252. package/dist/v2/semantic-resolver.d.ts +35 -0
  253. package/dist/v2/semantic-resolver.js +161 -0
  254. package/dist/v2/smart-wait.d.ts +27 -0
  255. package/dist/v2/smart-wait.js +81 -0
  256. package/dist/v2/types.d.ts +444 -0
  257. package/dist/v2/types.js +19 -0
  258. package/dist/v2/web-playwright-local.d.ts +69 -0
  259. package/dist/v2/web-playwright-local.js +392 -0
  260. package/dist/version.d.ts +1 -0
  261. package/dist/version.js +5 -0
  262. package/dist/video-agent.js +18 -13
  263. package/dist/video-planner.js +2 -1
  264. package/dist/video-prompts.js +3 -3
  265. package/dist/web-playwright-local.d.ts +126 -0
  266. package/dist/web-playwright-local.js +819 -0
  267. package/dist/ws-auth.js +4 -1
  268. package/dist/ws-broadcast.d.ts +34 -0
  269. package/dist/ws-broadcast.js +85 -0
  270. package/dist/ws-connection-limits.d.ts +12 -0
  271. package/dist/ws-connection-limits.js +44 -0
  272. package/dist/ws-handler-utils.d.ts +32 -0
  273. package/dist/ws-handler-utils.js +139 -0
  274. package/dist/ws-handler.js +294 -164
  275. package/dist/ws-metrics-server.d.ts +9 -0
  276. package/dist/ws-metrics-server.js +31 -0
  277. package/dist/ws-server.js +41 -1
  278. package/package.json +51 -34
@@ -1,4 +1,4 @@
1
- import { mkdtemp } from 'node:fs/promises';
1
+ import { mkdtemp, rm } from 'node:fs/promises';
2
2
  import os from 'node:os';
3
3
  import path from 'node:path';
4
4
  import { logger } from './logger.js';
@@ -891,8 +891,9 @@ async function runClipVariantAttempt(clip, target, lang, theme, navResult, confi
891
891
  clipOptions,
892
892
  parentSignal: config.abortSignal,
893
893
  run: async (_signal, _attempt, _phaseContext) => {
894
+ let outputDir = null;
894
895
  try {
895
- const outputDir = await mkdtemp(path.join(os.tmpdir(), `clip-${clip.id}-`));
896
+ outputDir = await mkdtemp(path.join(os.tmpdir(), `clip-${clip.id}-`));
896
897
  const outputScale = config.outputScale ?? 1;
897
898
  const postResult = await postProcessClipRecording(recordResult.videoPath, outputDir, `${clip.id}_${variantId.replace(/:/g, '_')}`, {
898
899
  ...clipOptions,
@@ -906,6 +907,12 @@ async function runClipVariantAttempt(clip, target, lang, theme, navResult, confi
906
907
  logger.error(`Post-processing failed for clip "${clip.name}" variant ${variantId}: ${err.message}`);
907
908
  return { ok: false, reason: `Post-processing failed: ${err.message}` };
908
909
  }
910
+ finally {
911
+ // Clean up temp directory to avoid orphaned files
912
+ if (outputDir) {
913
+ rm(outputDir, { recursive: true, force: true }).catch(() => { });
914
+ }
915
+ }
909
916
  },
910
917
  });
911
918
  if (!postprocessPhase.ok) {
@@ -1,5 +1,5 @@
1
1
  import { execFile } from 'node:child_process';
2
- import { stat } from 'node:fs/promises';
2
+ import { rm, stat } from 'node:fs/promises';
3
3
  import path from 'node:path';
4
4
  import { promisify } from 'node:util';
5
5
  const execFileAsync = promisify(execFile);
@@ -9,24 +9,33 @@ const DEFAULT_GIF_MAX_WIDTH = 800;
9
9
  const DEFAULT_MAX_DURATION_SEC = 8;
10
10
  const DEFAULT_TRIM_START_SEC = 0.3;
11
11
  // ── ffmpeg detection ────────────────────────────────────────────────
12
- let cachedFfmpegPath = null;
12
+ const cachedBinaryPaths = {};
13
+ async function ensureBinaryAvailable(binaryName) {
14
+ const cached = cachedBinaryPaths[binaryName];
15
+ if (cached)
16
+ return cached;
17
+ const resolver = process.platform === 'win32' ? 'where' : 'which';
18
+ const { stdout } = await execFileAsync(resolver, [binaryName]);
19
+ const resolvedPath = stdout
20
+ .split(/\r?\n/)
21
+ .map(line => line.trim())
22
+ .find(Boolean);
23
+ if (!resolvedPath) {
24
+ throw new Error(`${binaryName} not found`);
25
+ }
26
+ cachedBinaryPaths[binaryName] = resolvedPath;
27
+ return resolvedPath;
28
+ }
13
29
  /**
14
30
  * Resolve the system ffmpeg binary path. Throws if not found.
15
31
  */
16
32
  export async function ensureFfmpegAvailable() {
17
- if (cachedFfmpegPath)
18
- return cachedFfmpegPath;
19
33
  try {
20
- const { stdout } = await execFileAsync('which', ['ffmpeg']);
21
- const ffmpegPath = stdout.trim();
22
- if (!ffmpegPath)
23
- throw new Error('ffmpeg not found');
24
- cachedFfmpegPath = ffmpegPath;
25
- return ffmpegPath;
34
+ return await ensureBinaryAvailable('ffmpeg');
26
35
  }
27
36
  catch {
28
37
  throw new Error('ffmpeg is required for clip post-processing but was not found on your system. ' +
29
- 'Install it via: brew install ffmpeg (macOS) or apt install ffmpeg (Linux).');
38
+ 'Install it via: brew install ffmpeg (macOS), apt install ffmpeg (Linux), or choco install ffmpeg (Windows).');
30
39
  }
31
40
  }
32
41
  // ── Conversion functions ────────────────────────────────────────────
@@ -61,7 +70,8 @@ export async function convertToGif(webmPath, outputPath, opts = {}) {
61
70
  finally {
62
71
  // Clean up palette file
63
72
  try {
64
- await stat(palettePath).then(() => execFileAsync('rm', [palettePath]));
73
+ await stat(palettePath);
74
+ await rm(palettePath, { force: true });
65
75
  }
66
76
  catch { /* ignore */ }
67
77
  }
@@ -110,8 +120,7 @@ export async function trimRecording(inputPath, outputPath, startSec = DEFAULT_TR
110
120
  * Get the duration of a media file in milliseconds.
111
121
  */
112
122
  export async function getMediaDurationMs(filePath) {
113
- const ffmpeg = await ensureFfmpegAvailable();
114
- const ffprobe = ffmpeg.replace(/ffmpeg$/, 'ffprobe');
123
+ const ffprobe = await ensureBinaryAvailable('ffprobe');
115
124
  const { stdout } = await execFileAsync(ffprobe, [
116
125
  '-v', 'error',
117
126
  '-show_entries', 'format=duration',
@@ -178,12 +187,12 @@ export async function postProcessClipRecording(webmPath, outputDir, clipId, opti
178
187
  result.thumbnailPath = thumbnailPath;
179
188
  // Clean up intermediate files
180
189
  try {
181
- await execFileAsync('rm', [trimmedPath]);
190
+ await rm(trimmedPath, { force: true });
182
191
  }
183
192
  catch { /* ignore */ }
184
193
  if (sourcePath !== trimmedPath) {
185
194
  try {
186
- await execFileAsync('rm', [sourcePath]);
195
+ await rm(sourcePath, { force: true });
187
196
  }
188
197
  catch { /* ignore */ }
189
198
  }
@@ -1,4 +1,6 @@
1
1
  import type { Page } from 'playwright';
2
+ export declare function getCaptureHideCSS(): string;
3
+ export declare function ensureCaptureHideStyles(page: Page): Promise<void>;
2
4
  export declare function dismissCookiesAndWidgets(page: Page): Promise<{
3
5
  dismissed: boolean;
4
6
  method: string | null;
@@ -82,6 +82,51 @@ const HIDE_SELECTORS = [
82
82
  '[id*="cookieBanner"]', '[id*="cookieConsent"]',
83
83
  '[class*="gdpr"]', '[id*="gdpr"]',
84
84
  ];
85
+ // Dev-only chrome that should never appear in captures
86
+ const DEV_TOOL_SELECTORS = [
87
+ // Next.js dev indicator / devtools
88
+ 'nextjs-portal',
89
+ '#__next-build-watcher',
90
+ '[data-next-badge-root]',
91
+ // Astro dev toolbar
92
+ 'astro-dev-toolbar',
93
+ // Vite overlays
94
+ 'vite-error-overlay',
95
+ 'vite-plugin-checker-error-overlay',
96
+ // Nuxt devtools
97
+ 'nuxt-devtools',
98
+ 'nuxt-devtools-frame',
99
+ '#nuxt-devtools-anchor',
100
+ '#nuxt-devtools-container',
101
+ ];
102
+ const CAPTURE_HIDE_STYLE_ID = 'autokap-capture-hide-style';
103
+ export function getCaptureHideCSS() {
104
+ return [...HIDE_SELECTORS, ...DEV_TOOL_SELECTORS].map(selector => `${selector} { display: none !important; visibility: hidden !important; pointer-events: none !important; }`).join('\n');
105
+ }
106
+ export async function ensureCaptureHideStyles(page) {
107
+ try {
108
+ await page.evaluate(({ styleId, css }) => {
109
+ const parent = document.head ?? document.documentElement;
110
+ if (!parent)
111
+ return;
112
+ let style = document.getElementById(styleId);
113
+ if (!style) {
114
+ style = document.createElement('style');
115
+ style.id = styleId;
116
+ parent.appendChild(style);
117
+ }
118
+ if (style.textContent !== css) {
119
+ style.textContent = css;
120
+ }
121
+ }, {
122
+ styleId: CAPTURE_HIDE_STYLE_ID,
123
+ css: getCaptureHideCSS(),
124
+ });
125
+ }
126
+ catch {
127
+ // Page might have navigated away
128
+ }
129
+ }
85
130
  export async function dismissCookiesAndWidgets(page) {
86
131
  // Strategy 1: Click known CMP buttons
87
132
  for (const selector of CMP_SELECTORS) {
@@ -91,7 +136,7 @@ export async function dismissCookiesAndWidgets(page) {
91
136
  await button.click({ timeout: 2000 });
92
137
  logger.info(`Cookie dismissed via CMP selector: ${selector}`);
93
138
  await page.waitForTimeout(500);
94
- await injectHideCSS(page);
139
+ await ensureCaptureHideStyles(page);
95
140
  return { dismissed: true, method: `cmp:${selector}` };
96
141
  }
97
142
  }
@@ -148,7 +193,7 @@ export async function dismissCookiesAndWidgets(page) {
148
193
  if (dismissed) {
149
194
  logger.info(`Cookie dismissed via text match: "${dismissed}"`);
150
195
  await page.waitForTimeout(500);
151
- await injectHideCSS(page);
196
+ await ensureCaptureHideStyles(page);
152
197
  return { dismissed: true, method: `text:${dismissed}` };
153
198
  }
154
199
  }
@@ -156,17 +201,7 @@ export async function dismissCookiesAndWidgets(page) {
156
201
  // Text-based search failed
157
202
  }
158
203
  // Strategy 3: Always inject CSS to hide known overlays and widgets
159
- await injectHideCSS(page);
204
+ await ensureCaptureHideStyles(page);
160
205
  return { dismissed: false, method: null };
161
206
  }
162
- async function injectHideCSS(page) {
163
- try {
164
- await page.addStyleTag({
165
- content: HIDE_SELECTORS.map(s => `${s} { display: none !important; visibility: hidden !important; pointer-events: none !important; }`).join('\n'),
166
- });
167
- }
168
- catch {
169
- // Page might have navigated away
170
- }
171
- }
172
207
  //# sourceMappingURL=cookie-dismiss.js.map
@@ -21,6 +21,14 @@ export declare function updateCostLogCaptureContext(supabase: SupabaseClient, co
21
21
  viewportWidth?: number | null;
22
22
  viewportHeight?: number | null;
23
23
  }): Promise<void>;
24
+ /**
25
+ * Retry resolution for previously failed cost logs.
26
+ * Designed to be called by a reconciliation cron job.
27
+ */
28
+ export declare function reconcileUnresolvedCosts(supabase: SupabaseClient, apiKey: string): Promise<{
29
+ retried: number;
30
+ resolved: number;
31
+ }>;
24
32
  export declare function resolveAllCosts(supabase: SupabaseClient, entries: Array<{
25
33
  costLogId: string;
26
34
  generationId: string | null;
@@ -1,49 +1,88 @@
1
+ function isFiniteInteger(value) {
2
+ return typeof value === 'number' && Number.isInteger(value);
3
+ }
4
+ function normalizeUsageForCostLog(step, index) {
5
+ const normalizedStepNumber = isFiniteInteger(step.stepNumber) && step.stepNumber >= 0
6
+ ? step.stepNumber
7
+ : index + 1;
8
+ const normalizedStepType = typeof step.stepType === 'string' && step.stepType.trim().length > 0
9
+ ? step.stepType
10
+ : 'agent_iteration';
11
+ const normalizedModelRequested = typeof step.modelRequested === 'string' && step.modelRequested.trim().length > 0
12
+ ? step.modelRequested
13
+ : step.modelUsed ?? 'unknown';
14
+ const normalizedImagesInPrompt = typeof step.imagesInPrompt === 'number' && Number.isFinite(step.imagesInPrompt)
15
+ ? step.imagesInPrompt
16
+ : 0;
17
+ if (normalizedStepNumber !== step.stepNumber
18
+ || normalizedStepType !== step.stepType
19
+ || normalizedModelRequested !== step.modelRequested
20
+ || normalizedImagesInPrompt !== step.imagesInPrompt) {
21
+ console.warn('Normalizing invalid cost log usage entry:', JSON.stringify({
22
+ stepNumber: step.stepNumber ?? null,
23
+ stepType: step.stepType ?? null,
24
+ modelRequested: step.modelRequested ?? null,
25
+ modelUsed: step.modelUsed ?? null,
26
+ fallbackStepNumber: normalizedStepNumber,
27
+ }));
28
+ }
29
+ return {
30
+ ...step,
31
+ stepNumber: normalizedStepNumber,
32
+ stepType: normalizedStepType,
33
+ modelRequested: normalizedModelRequested,
34
+ imagesInPrompt: normalizedImagesInPrompt,
35
+ };
36
+ }
1
37
  export async function insertCostLogs(supabase, ctx, steps) {
2
38
  if (steps.length === 0)
3
39
  return [];
4
- const rows = steps.map((step) => ({
5
- id: crypto.randomUUID(),
6
- run_id: ctx.runId,
7
- user_id: ctx.userId,
8
- project_id: ctx.projectId ?? null,
9
- preset_id: ctx.presetId ?? null,
10
- capture_id: ctx.captureId ?? null,
11
- step_number: step.stepNumber,
12
- step_type: step.stepType,
13
- model_requested: step.modelRequested,
14
- model_used: step.modelUsed,
15
- generation_id: step.generationId,
16
- prompt_tokens: step.promptTokens,
17
- completion_tokens: step.completionTokens,
18
- total_tokens: step.totalTokens,
19
- cost_resolved: false,
20
- images_in_prompt: step.imagesInPrompt,
21
- lang: ctx.lang ?? null,
22
- theme: ctx.theme ?? null,
23
- capture_type: ctx.captureType ?? null,
24
- element_name: ctx.elementName ?? null,
25
- target_id: ctx.targetId ?? null,
26
- viewport_width: ctx.viewportWidth ?? null,
27
- viewport_height: ctx.viewportHeight ?? null,
28
- system_prompt_chars: step.systemPromptChars ?? null,
29
- tool_schema_chars: step.toolSchemaChars ?? null,
30
- user_payload_chars: step.userPayloadChars ?? null,
31
- accessibility_chars: step.accessibilityChars ?? null,
32
- interactive_element_count: step.interactiveElementCount ?? null,
33
- action_history_count: step.actionHistoryCount ?? null,
34
- elements_chars: step.elementsChars ?? null,
35
- session_summary_chars: step.sessionSummaryChars ?? null,
36
- selector_memory_chars: step.selectorMemoryChars ?? null,
37
- agent_context_chars: step.agentContextChars ?? null,
38
- profile_validation_status: step.profileValidationStatus ?? null,
39
- session_profile_source: step.sessionProfileSource ?? null,
40
- repair_path_used: step.repairPathUsed ?? null,
41
- evaluator_used: step.evaluatorUsed ?? false,
42
- cache_read_tokens: step.cacheReadTokens ?? null,
43
- cache_write_tokens: step.cacheWriteTokens ?? null,
44
- session_profile_reused: step.sessionProfileReused ?? false,
45
- action_replay_used: step.actionReplayUsed ?? false,
46
- }));
40
+ const rows = steps.map((rawStep, index) => {
41
+ const step = normalizeUsageForCostLog(rawStep, index);
42
+ return {
43
+ id: crypto.randomUUID(),
44
+ run_id: ctx.runId,
45
+ user_id: ctx.userId,
46
+ project_id: ctx.projectId ?? null,
47
+ preset_id: ctx.presetId ?? null,
48
+ capture_id: ctx.captureId ?? null,
49
+ step_number: step.stepNumber,
50
+ step_type: step.stepType,
51
+ model_requested: step.modelRequested,
52
+ model_used: step.modelUsed,
53
+ generation_id: step.generationId,
54
+ prompt_tokens: step.promptTokens,
55
+ completion_tokens: step.completionTokens,
56
+ total_tokens: step.totalTokens,
57
+ cost_resolved: false,
58
+ images_in_prompt: step.imagesInPrompt,
59
+ lang: ctx.lang ?? null,
60
+ theme: ctx.theme ?? null,
61
+ capture_type: ctx.captureType ?? null,
62
+ element_name: ctx.elementName ?? null,
63
+ target_id: ctx.targetId ?? null,
64
+ viewport_width: ctx.viewportWidth ?? null,
65
+ viewport_height: ctx.viewportHeight ?? null,
66
+ system_prompt_chars: step.systemPromptChars ?? null,
67
+ tool_schema_chars: step.toolSchemaChars ?? null,
68
+ user_payload_chars: step.userPayloadChars ?? null,
69
+ accessibility_chars: step.accessibilityChars ?? null,
70
+ interactive_element_count: step.interactiveElementCount ?? null,
71
+ action_history_count: step.actionHistoryCount ?? null,
72
+ elements_chars: step.elementsChars ?? null,
73
+ session_summary_chars: step.sessionSummaryChars ?? null,
74
+ selector_memory_chars: step.selectorMemoryChars ?? null,
75
+ agent_context_chars: step.agentContextChars ?? null,
76
+ profile_validation_status: step.profileValidationStatus ?? null,
77
+ session_profile_source: step.sessionProfileSource ?? null,
78
+ repair_path_used: step.repairPathUsed ?? null,
79
+ evaluator_used: step.evaluatorUsed ?? false,
80
+ cache_read_tokens: step.cacheReadTokens ?? null,
81
+ cache_write_tokens: step.cacheWriteTokens ?? null,
82
+ session_profile_reused: step.sessionProfileReused ?? false,
83
+ action_replay_used: step.actionReplayUsed ?? false,
84
+ };
85
+ });
47
86
  try {
48
87
  const { error } = await supabase.from('cost_logs').insert(rows);
49
88
  if (error) {
@@ -79,9 +118,21 @@ export async function updateCostLogCaptureContext(supabase, costLogIds, params)
79
118
  }
80
119
  }
81
120
  async function resolveCost(updateClient, generationId, costLogId, apiKey) {
82
- const delays = [10_000, 20_000, 40_000];
121
+ const delays = [10_000, 20_000, 40_000, 80_000, 160_000];
83
122
  for (let attempt = 0; attempt < delays.length; attempt += 1) {
84
123
  await new Promise((resolve) => setTimeout(resolve, delays[attempt]));
124
+ // Track resolution attempt (best-effort)
125
+ try {
126
+ await updateClient
127
+ .from('cost_logs')
128
+ .update({
129
+ resolution_attempts: attempt + 1,
130
+ last_resolution_attempt_at: new Date().toISOString(),
131
+ cost_resolution_status: 'pending',
132
+ })
133
+ .eq('id', costLogId);
134
+ }
135
+ catch { /* best-effort tracking */ }
85
136
  try {
86
137
  const response = await fetch(`https://openrouter.ai/api/v1/generation?id=${generationId}`, { headers: { Authorization: `Bearer ${apiKey}` } });
87
138
  if (response.status === 404 && attempt < delays.length - 1) {
@@ -89,13 +140,19 @@ async function resolveCost(updateClient, generationId, costLogId, apiKey) {
89
140
  }
90
141
  if (!response.ok) {
91
142
  console.error(`OpenRouter generation lookup failed (${generationId}): HTTP ${response.status}`);
92
- return;
143
+ if (attempt === delays.length - 1) {
144
+ await markCostResolutionFailed(updateClient, costLogId, `HTTP ${response.status}`);
145
+ }
146
+ continue;
93
147
  }
94
148
  const generation = await response.json();
95
149
  const totalCost = generation.data?.total_cost ?? null;
96
150
  if (totalCost == null) {
97
151
  console.warn(`OpenRouter returned no total_cost for generation ${generationId}`);
98
- return;
152
+ if (attempt === delays.length - 1) {
153
+ await markCostResolutionFailed(updateClient, costLogId, 'no total_cost in response');
154
+ }
155
+ continue;
99
156
  }
100
157
  const { error } = await updateClient
101
158
  .from('cost_logs')
@@ -103,6 +160,7 @@ async function resolveCost(updateClient, generationId, costLogId, apiKey) {
103
160
  cost_usd: totalCost,
104
161
  cost_resolved: true,
105
162
  resolved_at: new Date().toISOString(),
163
+ cost_resolution_status: 'resolved',
106
164
  })
107
165
  .eq('id', costLogId);
108
166
  if (error) {
@@ -113,10 +171,66 @@ async function resolveCost(updateClient, generationId, costLogId, apiKey) {
113
171
  catch (error) {
114
172
  if (attempt === delays.length - 1) {
115
173
  console.error(`Cost resolution failed for ${generationId}:`, error.message);
174
+ await markCostResolutionFailed(updateClient, costLogId, error.message);
116
175
  }
117
176
  }
118
177
  }
119
178
  }
179
+ async function markCostResolutionFailed(updateClient, costLogId, reason) {
180
+ try {
181
+ await updateClient
182
+ .from('cost_logs')
183
+ .update({ cost_resolution_status: 'failed' })
184
+ .eq('id', costLogId);
185
+ console.error(`Cost resolution marked as failed for ${costLogId}: ${reason}`);
186
+ }
187
+ catch {
188
+ // best-effort — don't fail the caller
189
+ }
190
+ }
191
+ /**
192
+ * Retry resolution for previously failed cost logs.
193
+ * Designed to be called by a reconciliation cron job.
194
+ */
195
+ export async function reconcileUnresolvedCosts(supabase, apiKey) {
196
+ const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString();
197
+ const { data: failedLogs, error } = await supabase
198
+ .from('cost_logs')
199
+ .select('id, generation_id')
200
+ .eq('cost_resolution_status', 'failed')
201
+ .gt('created_at', sevenDaysAgo)
202
+ .not('generation_id', 'is', null)
203
+ .limit(100);
204
+ if (error || !failedLogs?.length) {
205
+ return { retried: 0, resolved: 0 };
206
+ }
207
+ let resolved = 0;
208
+ for (const log of failedLogs) {
209
+ try {
210
+ const response = await fetch(`https://openrouter.ai/api/v1/generation?id=${log.generation_id}`, { headers: { Authorization: `Bearer ${apiKey}` } });
211
+ if (!response.ok)
212
+ continue;
213
+ const generation = await response.json();
214
+ const totalCost = generation.data?.total_cost ?? null;
215
+ if (totalCost == null)
216
+ continue;
217
+ await supabase
218
+ .from('cost_logs')
219
+ .update({
220
+ cost_usd: totalCost,
221
+ cost_resolved: true,
222
+ resolved_at: new Date().toISOString(),
223
+ cost_resolution_status: 'resolved',
224
+ })
225
+ .eq('id', log.id);
226
+ resolved += 1;
227
+ }
228
+ catch {
229
+ // skip this entry, will be retried next run
230
+ }
231
+ }
232
+ return { retried: failedLogs.length, resolved };
233
+ }
120
234
  export function resolveAllCosts(supabase, entries, apiKey, serviceClient) {
121
235
  const toResolve = entries.filter((entry) => entry.generationId != null);
122
236
  if (toResolve.length === 0) {
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Cost resolution monitoring — exposes metrics for alerting
3
+ * when the failure rate of OpenRouter cost lookups exceeds thresholds.
4
+ */
5
+ import type { SupabaseClient } from '@supabase/supabase-js';
6
+ export interface CostResolutionStats {
7
+ /** Number of cost logs with status 'failed' in the last hour. */
8
+ failedLastHour: number;
9
+ /** Total cost logs created in the last hour. */
10
+ totalLastHour: number;
11
+ /** Failure rate as a percentage (0-100). */
12
+ failureRate: number;
13
+ /** Number of cost logs still pending (older than 5 minutes). */
14
+ stalePending: number;
15
+ }
16
+ export declare function getCostResolutionStats(supabase: SupabaseClient): Promise<CostResolutionStats>;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Cost resolution monitoring — exposes metrics for alerting
3
+ * when the failure rate of OpenRouter cost lookups exceeds thresholds.
4
+ */
5
+ export async function getCostResolutionStats(supabase) {
6
+ const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000).toISOString();
7
+ const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000).toISOString();
8
+ const [failedResult, totalResult, staleResult] = await Promise.all([
9
+ supabase
10
+ .from('cost_logs')
11
+ .select('*', { count: 'exact', head: true })
12
+ .eq('cost_resolution_status', 'failed')
13
+ .gt('created_at', oneHourAgo),
14
+ supabase
15
+ .from('cost_logs')
16
+ .select('*', { count: 'exact', head: true })
17
+ .gt('created_at', oneHourAgo)
18
+ .not('generation_id', 'is', null),
19
+ supabase
20
+ .from('cost_logs')
21
+ .select('*', { count: 'exact', head: true })
22
+ .eq('cost_resolution_status', 'pending')
23
+ .lt('created_at', fiveMinutesAgo)
24
+ .not('generation_id', 'is', null),
25
+ ]);
26
+ const failedLastHour = failedResult.count ?? 0;
27
+ const totalLastHour = totalResult.count ?? 0;
28
+ const stalePending = staleResult.count ?? 0;
29
+ const failureRate = totalLastHour > 0
30
+ ? Math.round((failedLastHour / totalLastHour) * 10000) / 100
31
+ : 0;
32
+ return { failedLastHour, totalLastHour, failureRate, stalePending };
33
+ }
34
+ //# sourceMappingURL=cost-resolution-monitor.js.map
@@ -47,9 +47,9 @@ export function resolveActionCredentialArgs(action, args, credentials) {
47
47
  if (!credentials)
48
48
  return args;
49
49
  const resolved = { ...args };
50
- if (action === "type_text" && typeof resolved.text === "string") {
50
+ if ((action === "type_text" || action === "type") && typeof resolved.text === "string") {
51
51
  resolved.text = resolveCredentialTemplates(resolved.text, credentials);
52
- ensureNoCredentialTemplate("type_text.text", resolved.text);
52
+ ensureNoCredentialTemplate(`${action}.text`, resolved.text);
53
53
  }
54
54
  if (action === "navigate_to" && typeof resolved.url === "string") {
55
55
  resolved.url = resolveCredentialTemplates(resolved.url, credentials);
@@ -0,0 +1,6 @@
1
+ import type { VideoCursorTheme } from './types.js';
2
+ /**
3
+ * JavaScript injected via `context.addInitScript()` to show a visible animated
4
+ * cursor in Playwright video recordings (the native OS cursor is invisible).
5
+ */
6
+ export declare function buildCursorOverlayScript(theme?: VideoCursorTheme): string;