testdriverai 7.2.64 → 7.2.69

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 (369) hide show
  1. package/agent/index.js +4 -3
  2. package/agent/interface.js +11 -251
  3. package/agent/lib/debugger-server.js +2 -1
  4. package/agent/lib/logger.js +56 -0
  5. package/agent/lib/sandbox.js +6 -7
  6. package/ai/agents/test-writer.md +457 -0
  7. package/{docs/v7/ai.mdx → ai/skills/testdriver:ai/SKILL.md} +3 -5
  8. package/{docs/v7/assert.mdx → ai/skills/testdriver:assert/SKILL.md} +3 -4
  9. package/{docs/v7/aws-setup.mdx → ai/skills/testdriver:aws-setup/SKILL.md} +3 -4
  10. package/{docs/v7/caching.mdx → ai/skills/testdriver:caching/SKILL.md} +3 -7
  11. package/{docs/v7/captcha.mdx → ai/skills/testdriver:captcha/SKILL.md} +4 -5
  12. package/{docs/v7/ci-cd.mdx → ai/skills/testdriver:ci-cd/SKILL.md} +3 -4
  13. package/{docs/v7/click.mdx → ai/skills/testdriver:click/SKILL.md} +3 -4
  14. package/{docs/v7/client.mdx → ai/skills/testdriver:client/SKILL.md} +11 -5
  15. package/{docs/v7/cloud.mdx → ai/skills/testdriver:cloud/SKILL.md} +3 -4
  16. package/{docs/v7/customizing-devices.mdx → ai/skills/testdriver:customizing-devices/SKILL.md} +36 -26
  17. package/{docs/v7/dashcam.mdx → ai/skills/testdriver:dashcam/SKILL.md} +3 -4
  18. package/{docs/v7/device-config.mdx → ai/skills/testdriver:device-config/SKILL.md} +3 -3
  19. package/{docs/v7/double-click.mdx → ai/skills/testdriver:double-click/SKILL.md} +3 -3
  20. package/{docs/v7/elements.mdx → ai/skills/testdriver:elements/SKILL.md} +3 -4
  21. package/{docs/v7/enterprise.mdx → ai/skills/testdriver:enterprise/SKILL.md} +3 -5
  22. package/ai/skills/testdriver:examples/SKILL.md +7 -0
  23. package/{docs/v7/exec.mdx → ai/skills/testdriver:exec/SKILL.md} +3 -4
  24. package/{docs/v7/find.mdx → ai/skills/testdriver:find/SKILL.md} +81 -4
  25. package/{docs/v7/focus-application.mdx → ai/skills/testdriver:focus-application/SKILL.md} +3 -4
  26. package/{docs/v7/generating-tests.mdx → ai/skills/testdriver:generating-tests/SKILL.md} +3 -3
  27. package/{docs/v7/hover.mdx → ai/skills/testdriver:hover/SKILL.md} +3 -4
  28. package/{docs/v7/locating-elements.mdx → ai/skills/testdriver:locating-elements/SKILL.md} +3 -3
  29. package/{docs/v7/making-assertions.mdx → ai/skills/testdriver:making-assertions/SKILL.md} +3 -3
  30. package/ai/skills/testdriver:mcp-workflow/SKILL.md +410 -0
  31. package/{docs/v7/mouse-down.mdx → ai/skills/testdriver:mouse-down/SKILL.md} +3 -3
  32. package/{docs/v7/mouse-up.mdx → ai/skills/testdriver:mouse-up/SKILL.md} +3 -3
  33. package/{docs/v7/performing-actions.mdx → ai/skills/testdriver:performing-actions/SKILL.md} +3 -3
  34. package/{docs/v7/press-keys.mdx → ai/skills/testdriver:press-keys/SKILL.md} +3 -4
  35. package/{docs/v7/quickstart.mdx → ai/skills/testdriver:quickstart/SKILL.md} +3 -4
  36. package/{docs/v7/reusable-code.mdx → ai/skills/testdriver:reusable-code/SKILL.md} +3 -3
  37. package/{docs/v7/right-click.mdx → ai/skills/testdriver:right-click/SKILL.md} +3 -3
  38. package/{docs/v7/running-tests.mdx → ai/skills/testdriver:running-tests/SKILL.md} +3 -3
  39. package/{docs/v7/screenshot.mdx → ai/skills/testdriver:screenshot/SKILL.md} +3 -4
  40. package/{docs/v7/scroll.mdx → ai/skills/testdriver:scroll/SKILL.md} +3 -4
  41. package/{docs/v7/secrets.mdx → ai/skills/testdriver:secrets/SKILL.md} +3 -3
  42. package/{docs/v7/self-hosted.mdx → ai/skills/testdriver:self-hosted/SKILL.md} +3 -4
  43. package/ai/skills/testdriver:testdriver/SKILL.md +31 -0
  44. package/{docs/v7/type.mdx → ai/skills/testdriver:type/SKILL.md} +3 -4
  45. package/{docs/v7/variables.mdx → ai/skills/testdriver:variables/SKILL.md} +3 -3
  46. package/{docs/v7/waiting-for-elements.mdx → ai/skills/testdriver:waiting-for-elements/SKILL.md} +3 -3
  47. package/{docs/v7/what-is-testdriver.mdx → ai/skills/testdriver:what-is-testdriver/SKILL.md} +3 -3
  48. package/interfaces/cli/commands/init.js +278 -1
  49. package/interfaces/cli/commands/setup.js +382 -0
  50. package/interfaces/vitest-plugin.mjs +190 -122
  51. package/lib/sentry.js +4 -3
  52. package/lib/vitest/hooks.mjs +70 -16
  53. package/mcp-server/dist/codegen.d.ts +9 -0
  54. package/mcp-server/dist/codegen.js +165 -0
  55. package/mcp-server/dist/mcp-app.html +114 -0
  56. package/mcp-server/dist/provision-types.d.ts +290 -0
  57. package/mcp-server/dist/provision-types.js +174 -0
  58. package/mcp-server/dist/server.d.ts +6 -0
  59. package/mcp-server/dist/server.js +1441 -0
  60. package/mcp-server/dist/session.d.ts +85 -0
  61. package/mcp-server/dist/session.js +152 -0
  62. package/package.json +30 -9
  63. package/sdk.d.ts +29 -2
  64. package/sdk.js +1 -0
  65. package/.env.example +0 -4
  66. package/.github/workflows/acceptance-linux-scheduled.yaml +0 -45
  67. package/.github/workflows/acceptance-windows-scheduled.yaml +0 -54
  68. package/.github/workflows/acceptance.yaml +0 -87
  69. package/.github/workflows/publish.yaml +0 -68
  70. package/.github/workflows/test-init.yml +0 -145
  71. package/.github/workflows/testdriver.yml +0 -170
  72. package/.github/workflows/windows-self-hosted.yaml +0 -82
  73. package/.prettierignore +0 -4
  74. package/.prettierrc +0 -1
  75. package/CHANGELOG.md +0 -34
  76. package/agents.md +0 -455
  77. package/debugger/bg.png +0 -0
  78. package/debugger/icon.png +0 -0
  79. package/debugger/index.html +0 -797
  80. package/debugger/td.png +0 -0
  81. package/debugger/tray-buffered.png +0 -0
  82. package/debugger/tray.png +0 -0
  83. package/docs/GITHUB_COMMENTS.md +0 -330
  84. package/docs/GITHUB_COMMENTS_ANNOUNCEMENT.md +0 -167
  85. package/docs/QUICK-START-GITHUB-COMMENTS.md +0 -84
  86. package/docs/TEST-GITHUB-COMMENTS.md +0 -129
  87. package/docs/_scripts/link-replacer.js +0 -164
  88. package/docs/_scripts/upload-docs-to-openai.js +0 -284
  89. package/docs/docs.json +0 -393
  90. package/docs/github-integration-setup.md +0 -266
  91. package/docs/guide/best-practices-polling.mdx +0 -154
  92. package/docs/images/content/account/newprojectsettings.png +0 -0
  93. package/docs/images/content/account/projectpage.png +0 -0
  94. package/docs/images/content/account/projectreplays.png +0 -0
  95. package/docs/images/content/account/team-manage.png +0 -0
  96. package/docs/images/content/account/teampage.png +0 -0
  97. package/docs/images/content/extension/cursor.svg +0 -1
  98. package/docs/images/content/extension/vscode.svg +0 -57
  99. package/docs/images/content/extension/windsurf.svg +0 -3
  100. package/docs/images/content/self-hosted/launchtemplateid.png +0 -0
  101. package/docs/images/content/side-by-side.png +0 -0
  102. package/docs/images/content/vscode/ide-full.png +0 -0
  103. package/docs/images/content/vscode/running.png +0 -0
  104. package/docs/images/content/vscode/vscode-2-assert.png +0 -0
  105. package/docs/images/content/vscode/vscode-agent-preview.png +0 -0
  106. package/docs/images/content/vscode/vscode-copilot-ask.png +0 -0
  107. package/docs/images/content/vscode/vscode-file-creation.png +0 -0
  108. package/docs/images/content/vscode/vscode-install.png +0 -0
  109. package/docs/images/content/vscode/vscode-overview.png +0 -0
  110. package/docs/images/content/vscode/vscode-setup-walkthrough.png +0 -0
  111. package/docs/images/content/vscode/vscode-stopchat.png +0 -0
  112. package/docs/images/content/vscode/vscode-stoptest.png +0 -0
  113. package/docs/images/content/vscode/vscode-tdservice.png +0 -0
  114. package/docs/images/content/vscode/vscode-test-output.png +0 -0
  115. package/docs/images/content/vscode/vscode-testhistory.png +0 -0
  116. package/docs/images/content/vscode/vscode-testpane-runtests.png +0 -0
  117. package/docs/images/content/vscode/vscode-testpane.png +0 -0
  118. package/docs/images/template/dark.png +0 -0
  119. package/docs/images/template/icon.png +0 -0
  120. package/docs/images/template/light.png +0 -0
  121. package/docs/snippets/calendar-link.mdx +0 -4
  122. package/docs/snippets/gitignore-warning.mdx +0 -7
  123. package/docs/snippets/lifecycle-warning.mdx +0 -6
  124. package/docs/snippets/test-prereqs.mdx +0 -12
  125. package/docs/snippets/tests/assert-replay.mdx +0 -7
  126. package/docs/snippets/tests/assert-yaml.mdx +0 -8
  127. package/docs/snippets/tests/exec-js-replay.mdx +0 -7
  128. package/docs/snippets/tests/exec-js-yaml.mdx +0 -32
  129. package/docs/snippets/tests/exec-shell-replay.mdx +0 -7
  130. package/docs/snippets/tests/exec-shell-yaml.mdx +0 -15
  131. package/docs/snippets/tests/hover-image-replay.mdx +0 -7
  132. package/docs/snippets/tests/hover-image-yaml.mdx +0 -17
  133. package/docs/snippets/tests/hover-text-replay.mdx +0 -7
  134. package/docs/snippets/tests/hover-text-with-description-replay.mdx +0 -7
  135. package/docs/snippets/tests/hover-text-with-description-yaml.mdx +0 -24
  136. package/docs/snippets/tests/hover-text-yaml.mdx +0 -14
  137. package/docs/snippets/tests/match-image-replay.mdx +0 -7
  138. package/docs/snippets/tests/match-image-yaml.mdx +0 -17
  139. package/docs/snippets/tests/press-keys-replay.mdx +0 -7
  140. package/docs/snippets/tests/press-keys-yaml.mdx +0 -36
  141. package/docs/snippets/tests/remember-replay.mdx +0 -7
  142. package/docs/snippets/tests/remember-yaml.mdx +0 -28
  143. package/docs/snippets/tests/scroll-replay.mdx +0 -7
  144. package/docs/snippets/tests/scroll-until-image-replay.mdx +0 -7
  145. package/docs/snippets/tests/scroll-until-image-yaml.mdx +0 -14
  146. package/docs/snippets/tests/scroll-until-text-replay.mdx +0 -7
  147. package/docs/snippets/tests/scroll-until-text-yaml.mdx +0 -17
  148. package/docs/snippets/tests/scroll-yaml.mdx +0 -30
  149. package/docs/snippets/tests/type-repeated-replay.mdx +0 -7
  150. package/docs/snippets/tests/type-repeated-yaml.mdx +0 -22
  151. package/docs/snippets/tests/type-replay.mdx +0 -7
  152. package/docs/snippets/tests/type-yaml.mdx +0 -28
  153. package/docs/snippets/tests/wait-for-image-replay.mdx +0 -7
  154. package/docs/snippets/tests/wait-for-image-yaml.mdx +0 -18
  155. package/docs/snippets/tests/wait-for-text-replay.mdx +0 -7
  156. package/docs/snippets/tests/wait-for-text-yaml.mdx +0 -18
  157. package/docs/snippets/tests/wait-replay.mdx +0 -7
  158. package/docs/snippets/tests/wait-yaml.mdx +0 -13
  159. package/docs/styles.css +0 -65
  160. package/docs/v6/account/dashboard.mdx +0 -16
  161. package/docs/v6/account/enterprise.mdx +0 -110
  162. package/docs/v6/account/pricing.mdx +0 -33
  163. package/docs/v6/account/projects.mdx +0 -33
  164. package/docs/v6/account/team.mdx +0 -35
  165. package/docs/v6/action/ami.mdx +0 -109
  166. package/docs/v6/action/performance.mdx +0 -105
  167. package/docs/v6/action/secrets.mdx +0 -93
  168. package/docs/v6/apps/chrome-extensions.mdx +0 -48
  169. package/docs/v6/apps/desktop-apps.mdx +0 -93
  170. package/docs/v6/apps/mobile-apps.mdx +0 -26
  171. package/docs/v6/apps/static-websites.mdx +0 -54
  172. package/docs/v6/apps/tauri-apps.mdx +0 -361
  173. package/docs/v6/bugs/jira.mdx +0 -232
  174. package/docs/v6/cli/overview.mdx +0 -66
  175. package/docs/v6/commands/assert.mdx +0 -45
  176. package/docs/v6/commands/exec.mdx +0 -282
  177. package/docs/v6/commands/focus-application.mdx +0 -44
  178. package/docs/v6/commands/hover-image.mdx +0 -69
  179. package/docs/v6/commands/hover-text.mdx +0 -47
  180. package/docs/v6/commands/if.mdx +0 -53
  181. package/docs/v6/commands/match-image.mdx +0 -67
  182. package/docs/v6/commands/press-keys.mdx +0 -87
  183. package/docs/v6/commands/remember.mdx +0 -49
  184. package/docs/v6/commands/run.mdx +0 -44
  185. package/docs/v6/commands/scroll-until-image.mdx +0 -66
  186. package/docs/v6/commands/scroll-until-text.mdx +0 -60
  187. package/docs/v6/commands/scroll.mdx +0 -69
  188. package/docs/v6/commands/type.mdx +0 -45
  189. package/docs/v6/commands/wait-for-image.mdx +0 -54
  190. package/docs/v6/commands/wait-for-text.mdx +0 -48
  191. package/docs/v6/commands/wait.mdx +0 -45
  192. package/docs/v6/exporting/junit.mdx +0 -218
  193. package/docs/v6/exporting/playwright.mdx +0 -197
  194. package/docs/v6/features/auto-healing.mdx +0 -144
  195. package/docs/v6/features/generation.mdx +0 -116
  196. package/docs/v6/features/parallel-testing.mdx +0 -151
  197. package/docs/v6/features/reusable-snippets.mdx +0 -131
  198. package/docs/v6/features/selectorless.mdx +0 -80
  199. package/docs/v6/features/visual-assertions.mdx +0 -139
  200. package/docs/v6/getting-started/ci.mdx +0 -146
  201. package/docs/v6/getting-started/cli.mdx +0 -91
  202. package/docs/v6/getting-started/editing.mdx +0 -100
  203. package/docs/v6/getting-started/playwright.mdx +0 -342
  204. package/docs/v6/getting-started/running.mdx +0 -48
  205. package/docs/v6/getting-started/self-hosting.mdx +0 -408
  206. package/docs/v6/getting-started/vscode.mdx +0 -89
  207. package/docs/v6/guide/assertions.mdx +0 -189
  208. package/docs/v6/guide/authentication.mdx +0 -136
  209. package/docs/v6/guide/code.mdx +0 -65
  210. package/docs/v6/guide/dashcam.mdx +0 -118
  211. package/docs/v6/guide/environment-variables.mdx +0 -26
  212. package/docs/v6/guide/lifecycle.mdx +0 -242
  213. package/docs/v6/guide/locating.mdx +0 -141
  214. package/docs/v6/guide/protips.mdx +0 -43
  215. package/docs/v6/guide/variables.mdx +0 -143
  216. package/docs/v6/guide/waiting.mdx +0 -130
  217. package/docs/v6/importing/csv.mdx +0 -196
  218. package/docs/v6/importing/gherkin.mdx +0 -143
  219. package/docs/v6/importing/jira.mdx +0 -164
  220. package/docs/v6/importing/testrail.mdx +0 -162
  221. package/docs/v6/integrations/electron.mdx +0 -146
  222. package/docs/v6/integrations/netlify.mdx +0 -100
  223. package/docs/v6/integrations/vercel.mdx +0 -125
  224. package/docs/v6/interactive/explore.mdx +0 -99
  225. package/docs/v6/interactive/run.mdx +0 -52
  226. package/docs/v6/interactive/save.mdx +0 -63
  227. package/docs/v6/overview/comparison.mdx +0 -101
  228. package/docs/v6/overview/faq.mdx +0 -162
  229. package/docs/v6/overview/performance.mdx +0 -52
  230. package/docs/v6/overview/quickstart.mdx +0 -137
  231. package/docs/v6/overview/what-is-testdriver.mdx +0 -85
  232. package/docs/v6/scenarios/ai-chatbot.mdx +0 -28
  233. package/docs/v6/scenarios/cookie-banner.mdx +0 -32
  234. package/docs/v6/scenarios/file-upload.mdx +0 -33
  235. package/docs/v6/scenarios/form-filling.mdx +0 -32
  236. package/docs/v6/scenarios/log-in.mdx +0 -75
  237. package/docs/v6/scenarios/pdf-generation.mdx +0 -25
  238. package/docs/v6/scenarios/spell-check.mdx +0 -22
  239. package/docs/v6/security/action.mdx +0 -84
  240. package/docs/v6/security/agent.mdx +0 -73
  241. package/docs/v6/security/platform.mdx +0 -77
  242. package/docs/v6/tutorials/advanced-test.mdx +0 -81
  243. package/docs/v6/tutorials/basic-test.mdx +0 -45
  244. package/docs/v7/_drafts/agents.mdx +0 -852
  245. package/docs/v7/_drafts/architecture.mdx +0 -399
  246. package/docs/v7/_drafts/auto-cache-key.mdx +0 -167
  247. package/docs/v7/_drafts/awesome-logs-quick-ref.mdx +0 -100
  248. package/docs/v7/_drafts/best-practices.mdx +0 -486
  249. package/docs/v7/_drafts/caching-ai.mdx +0 -215
  250. package/docs/v7/_drafts/caching-selectors.mdx +0 -424
  251. package/docs/v7/_drafts/caching.mdx +0 -366
  252. package/docs/v7/_drafts/cli-to-sdk-migration.mdx +0 -425
  253. package/docs/v7/_drafts/commands/assert.mdx +0 -45
  254. package/docs/v7/_drafts/commands/exec.mdx +0 -282
  255. package/docs/v7/_drafts/commands/focus-application.mdx +0 -44
  256. package/docs/v7/_drafts/commands/hover-image.mdx +0 -69
  257. package/docs/v7/_drafts/commands/hover-text.mdx +0 -47
  258. package/docs/v7/_drafts/commands/if.mdx +0 -53
  259. package/docs/v7/_drafts/commands/match-image.mdx +0 -67
  260. package/docs/v7/_drafts/commands/press-keys.mdx +0 -87
  261. package/docs/v7/_drafts/commands/remember.mdx +0 -49
  262. package/docs/v7/_drafts/commands/run.mdx +0 -44
  263. package/docs/v7/_drafts/commands/scroll-until-image.mdx +0 -66
  264. package/docs/v7/_drafts/commands/scroll-until-text.mdx +0 -60
  265. package/docs/v7/_drafts/commands/scroll.mdx +0 -69
  266. package/docs/v7/_drafts/commands/type.mdx +0 -45
  267. package/docs/v7/_drafts/commands/wait-for-image.mdx +0 -54
  268. package/docs/v7/_drafts/commands/wait-for-text.mdx +0 -48
  269. package/docs/v7/_drafts/commands/wait.mdx +0 -45
  270. package/docs/v7/_drafts/configuration.mdx +0 -378
  271. package/docs/v7/_drafts/contributing.mdx +0 -174
  272. package/docs/v7/_drafts/core.mdx +0 -458
  273. package/docs/v7/_drafts/dashcam-title-feature.mdx +0 -89
  274. package/docs/v7/_drafts/debugging.mdx +0 -349
  275. package/docs/v7/_drafts/error-handling.mdx +0 -501
  276. package/docs/v7/_drafts/faq.mdx +0 -393
  277. package/docs/v7/_drafts/hooks.mdx +0 -360
  278. package/docs/v7/_drafts/init-command.mdx +0 -95
  279. package/docs/v7/_drafts/installation.mdx +0 -420
  280. package/docs/v7/_drafts/migration.mdx +0 -562
  281. package/docs/v7/_drafts/observable.mdx +0 -604
  282. package/docs/v7/_drafts/playwright.mdx +0 -342
  283. package/docs/v7/_drafts/plugin-migration.mdx +0 -220
  284. package/docs/v7/_drafts/powerful.mdx +0 -419
  285. package/docs/v7/_drafts/presets.mdx +0 -210
  286. package/docs/v7/_drafts/progressive-disclosure.mdx +0 -230
  287. package/docs/v7/_drafts/prompt-cache.mdx +0 -200
  288. package/docs/v7/_drafts/provision.mdx +0 -390
  289. package/docs/v7/_drafts/quick-start-test-recording.mdx +0 -214
  290. package/docs/v7/_drafts/readme.mdx +0 -135
  291. package/docs/v7/_drafts/reports.mdx +0 -414
  292. package/docs/v7/_drafts/scalable.mdx +0 -754
  293. package/docs/v7/_drafts/screenshot.mdx +0 -155
  294. package/docs/v7/_drafts/sdk-awesome-logs.mdx +0 -468
  295. package/docs/v7/_drafts/sdk-browser-rendering.mdx +0 -167
  296. package/docs/v7/_drafts/sdk-migration.mdx +0 -474
  297. package/docs/v7/_drafts/sdk-v7-complete.mdx +0 -345
  298. package/docs/v7/_drafts/self-hosting.mdx +0 -369
  299. package/docs/v7/_drafts/test-recording.mdx +0 -382
  300. package/docs/v7/_drafts/troubleshooting.mdx +0 -526
  301. package/docs/v7/_drafts/vitest-plugin.mdx +0 -477
  302. package/docs/v7/_drafts/vitest.mdx +0 -535
  303. package/docs/v7/_drafts/writing-tests.mdx +0 -25
  304. package/docs/v7/examples.mdx +0 -5
  305. package/eslint.config.js +0 -67
  306. package/examples/ai.test.mjs +0 -30
  307. package/examples/assert.test.mjs +0 -46
  308. package/examples/captcha-api.test.mjs +0 -50
  309. package/examples/chrome-extension.test.mjs +0 -94
  310. package/examples/drag-and-drop.test.mjs +0 -58
  311. package/examples/element-not-found.test.mjs +0 -26
  312. package/examples/exec-output.test.mjs +0 -59
  313. package/examples/exec-pwsh.test.mjs +0 -57
  314. package/examples/focus-window.test.mjs +0 -36
  315. package/examples/formatted-logging.test.mjs +0 -26
  316. package/examples/hover-image.test.mjs +0 -52
  317. package/examples/hover-text-with-description.test.mjs +0 -56
  318. package/examples/hover-text.test.mjs +0 -27
  319. package/examples/installer.test.mjs +0 -49
  320. package/examples/launch-vscode-linux.test.mjs +0 -54
  321. package/examples/match-image.test.mjs +0 -54
  322. package/examples/no-provision.test.mjs +0 -23
  323. package/examples/press-keys.test.mjs +0 -50
  324. package/examples/prompt.test.mjs +0 -33
  325. package/examples/scroll-keyboard.test.mjs +0 -37
  326. package/examples/scroll-until-image.test.mjs +0 -39
  327. package/examples/scroll-until-text.test.mjs +0 -67
  328. package/examples/scroll.test.mjs +0 -41
  329. package/examples/type.test.mjs +0 -45
  330. package/examples/windows-installer.test.mjs +0 -53
  331. package/interfaces/cli/commands/edit.js +0 -3
  332. package/interfaces/cli/commands/generate.js +0 -3
  333. package/interfaces/cli/commands/run.js +0 -3
  334. package/interfaces/cli/utils/factory.js +0 -71
  335. package/jsconfig.json +0 -26
  336. package/manual/test-init-command.js +0 -223
  337. package/sdk-log-formatter.js +0 -930
  338. package/setup/aws/cloudformation.yaml +0 -470
  339. package/setup/aws/spawn-runner.sh +0 -190
  340. package/test/api-resilience.test.mjs +0 -0
  341. package/test/captcha-solver.test.mjs +0 -70
  342. package/test/chrome-remote-debugging.test.mjs +0 -66
  343. package/test/manual/debug-locate-response.js +0 -82
  344. package/test/manual/reconnect-provision.test.mjs +0 -49
  345. package/test/manual/test-console-logs.test.mjs +0 -42
  346. package/test/manual/test-find-api.js +0 -73
  347. package/test/manual/test-init.sh +0 -54
  348. package/test/manual/test-prompt-cache.js +0 -96
  349. package/test/manual/test-provision-auth.mjs +0 -22
  350. package/test/manual/test-sandbox-render.js +0 -28
  351. package/test/manual/test-sdk-methods.js +0 -15
  352. package/test/manual/test-sdk-refactor.js +0 -53
  353. package/test/manual/test-stack-trace.mjs +0 -57
  354. package/test/manual/verify-element-api.js +0 -89
  355. package/test/manual/verify-types.js +0 -0
  356. package/test/manual-unawaited-promise.test.mjs +0 -31
  357. package/testdriver-plugin/skills/actions/SKILL.md +0 -93
  358. package/testdriver-plugin/skills/assertions/SKILL.md +0 -77
  359. package/testdriver-plugin/skills/caching/SKILL.md +0 -66
  360. package/testdriver-plugin/skills/creating-tests/SKILL.md +0 -104
  361. package/testdriver-plugin/skills/finding-elements/SKILL.md +0 -77
  362. package/testdriver-plugin/skills/github-actions/SKILL.md +0 -100
  363. package/testdriver-plugin/skills/running-tests/SKILL.md +0 -77
  364. package/testdriver-plugin/skills/secrets/SKILL.md +0 -87
  365. package/testdriver-plugin/skills/self-hosting/SKILL.md +0 -89
  366. package/testdriver-plugin/skills/setup/SKILL.md +0 -76
  367. package/testdriver-plugin/skills/variables/SKILL.md +0 -88
  368. package/testdriver-plugin/skills/waiting/SKILL.md +0 -72
  369. package/vitest.config.mjs +0 -29
@@ -1,930 +0,0 @@
1
- const chalk = require("chalk");
2
-
3
- /**
4
- * AWESOME Log formatter for TestDriver SDK 🎨
5
- * Provides beautiful, emoji-rich formatting with great DX for logs sent to dashcam
6
- * ANSI codes are preserved through the log pipeline: SDK → sandbox → /tmp/testdriver.log → dashcam
7
- *
8
- * Now with full UTF-8 and emoji support! 🚀
9
- */
10
-
11
- // Duration threshold configurations for different contexts
12
- const DURATION_THRESHOLDS = {
13
- default: { fast: 3000, medium: 10000 },
14
- action: { fast: 100, medium: 500 },
15
- redraw: { fast: 5000, medium: 10000 },
16
- quickAction: { fast: 50, medium: 200 },
17
- test: { fast: 1000, medium: 5000 },
18
- };
19
-
20
- class SDKLogFormatter {
21
- constructor(options = {}) {
22
- this.testContext = {
23
- currentTest: null,
24
- currentFile: null,
25
- startTime: null,
26
- };
27
- this.eventCount = 0;
28
- this.useColors = options.colors !== false;
29
- this.useEmojis = options.emojis !== false;
30
- }
31
-
32
- /**
33
- * Set the current test context from Vitest
34
- * @param {Object} context - Test context with file, test name, etc.
35
- */
36
- setTestContext(context) {
37
- if (context.file) this.testContext.currentFile = context.file;
38
- if (context.test) this.testContext.currentTest = context.test;
39
- if (context.startTime) this.testContext.startTime = context.startTime;
40
- }
41
-
42
- /**
43
- * Get elapsed time since test start
44
- * @returns {string} Formatted elapsed time
45
- */
46
- getElapsedTime() {
47
- if (!this.testContext.startTime) return "";
48
- const elapsed = Date.now() - this.testContext.startTime;
49
- const seconds = (elapsed / 1000).toFixed(2);
50
- return `[${seconds}s]`;
51
- }
52
-
53
- /**
54
- * Add elapsed time to parts array if available
55
- * @param {Array} parts - Array to push time string to
56
- * @param {boolean} dim - Whether to dim the time string
57
- */
58
- addTimestamp(parts, dim = true) {
59
- const timeStr = this.getElapsedTime();
60
- if (timeStr) {
61
- parts.push(dim ? chalk.dim(timeStr) : timeStr);
62
- }
63
- }
64
-
65
- /**
66
- * Get color function based on duration and thresholds
67
- * @param {number} durationMs - Duration in milliseconds
68
- * @param {string} thresholdKey - Key from DURATION_THRESHOLDS
69
- * @returns {Function} Chalk color function
70
- */
71
- getDurationColor(durationMs, thresholdKey = "default") {
72
- const thresholds = DURATION_THRESHOLDS[thresholdKey] || DURATION_THRESHOLDS.default;
73
- if (durationMs < thresholds.fast) return chalk.green;
74
- if (durationMs < thresholds.medium) return chalk.yellow;
75
- return chalk.red;
76
- }
77
-
78
- /**
79
- * Format duration with appropriate color
80
- * @param {number|string} duration - Duration in ms
81
- * @param {string} thresholdKey - Key from DURATION_THRESHOLDS
82
- * @param {boolean} showSeconds - Show as seconds (true) or raw (false)
83
- * @returns {string} Formatted duration string
84
- */
85
- formatDurationColored(duration, thresholdKey = "default", showSeconds = true) {
86
- const durationMs = parseInt(duration);
87
- const color = this.getDurationColor(durationMs, thresholdKey);
88
- const display = showSeconds ? `(${(durationMs / 1000).toFixed(1)}s)` : `(${duration})`;
89
- return color(display);
90
- }
91
-
92
- /**
93
- * Join metadata parts with separator
94
- * @param {Array} metaParts - Array of metadata strings
95
- * @returns {string} Joined metadata string with separators
96
- */
97
- joinMetaParts(metaParts) {
98
- if (metaParts.length === 0) return "";
99
- return chalk.dim("·") + " " + metaParts.join(chalk.dim(" · "));
100
- }
101
-
102
- /**
103
- * Create an indented result line prefix (for child results)
104
- * @returns {string} Indented arrow prefix
105
- */
106
- getResultPrefix() {
107
- return " " + chalk.dim("→");
108
- }
109
-
110
- /**
111
- * Format a nested action result line (scrolled, clicked, typed, pressed keys, etc.)
112
- * @param {string} message - The action message (e.g., "scrolled down 300px", "pressed keys: tab")
113
- * @param {number} durationMs - Duration in milliseconds
114
- * @returns {string} Formatted nested result line
115
- */
116
- formatNestedAction(message, durationMs) {
117
- return this.getResultPrefix() + " " + chalk.dim(message) + " " + this.formatDurationColored(durationMs);
118
- }
119
-
120
- /**
121
- * Format a redraw/idle wait completion line
122
- * @param {number} durationMs - Duration in milliseconds
123
- * @returns {string} Formatted redraw complete line
124
- */
125
- formatRedrawComplete(durationMs) {
126
- return this.formatNestedAction("flake protection", durationMs);
127
- }
128
-
129
- /**
130
- * Format a scroll action result
131
- * @param {string} direction - Scroll direction (up, down, left, right)
132
- * @param {number} amount - Scroll amount in pixels
133
- * @param {number} durationMs - Duration in milliseconds
134
- * @returns {string} Formatted scroll result line
135
- */
136
- formatScrollResult(direction, amount, durationMs) {
137
- return this.formatNestedAction(`scrolled ${direction} ${amount}px`, durationMs);
138
- }
139
-
140
- /**
141
- * Format a click action result
142
- * @param {string} button - Button type (left, right, middle)
143
- * @param {number} x - X coordinate
144
- * @param {number} y - Y coordinate
145
- * @param {number} durationMs - Duration in milliseconds
146
- * @returns {string} Formatted click result line
147
- */
148
- formatClickResult(button, x, y, durationMs) {
149
- return this.formatNestedAction(`click ${button} clicking at ${x}, ${y}`, durationMs);
150
- }
151
-
152
- /**
153
- * Format a type action result
154
- * @param {string} text - Text that was typed (or "****" for secrets)
155
- * @param {boolean} isSecret - Whether the text is a secret
156
- * @param {number} durationMs - Duration in milliseconds
157
- * @returns {string} Formatted type result line
158
- */
159
- formatTypeResult(text, isSecret, durationMs) {
160
- const displayText = isSecret ? "secret ****" : `"${text}"`;
161
- return this.formatNestedAction(`typed ${displayText}`, durationMs);
162
- }
163
-
164
- /**
165
- * Format a press keys action result
166
- * @param {string} keysDisplay - Keys that were pressed (comma-separated)
167
- * @param {number} durationMs - Duration in milliseconds
168
- * @returns {string} Formatted press keys result line
169
- */
170
- formatPressKeysResult(keysDisplay, durationMs) {
171
- return this.formatNestedAction(`pressed keys: ${keysDisplay}`, durationMs);
172
- }
173
-
174
- /**
175
- * Format a nested code display line (for exec commands)
176
- * @param {string} codeDisplay - The code to display
177
- * @returns {string} Formatted code line
178
- */
179
- formatCodeLine(codeDisplay) {
180
- return this.getResultPrefix() + " " + chalk.dim(codeDisplay);
181
- }
182
-
183
- /**
184
- * Format an exec complete result
185
- * @param {number} exitCode - The exit code
186
- * @param {number} durationMs - Duration in milliseconds
187
- * @returns {string} Formatted exec result line
188
- */
189
- formatExecComplete(exitCode, durationMs) {
190
- const statusText = exitCode !== 0
191
- ? `failed (exit code ${exitCode})`
192
- : `complete (exit code 0)`;
193
- const statusColor = exitCode !== 0 ? chalk.red : chalk.green;
194
-
195
- return this.formatResultLine(
196
- statusText,
197
- statusColor,
198
- { duration: durationMs },
199
- "action"
200
- );
201
- }
202
-
203
- /**
204
- * Format a log message in Vitest style
205
- * @param {string} type - Log type (info, success, error, action, debug)
206
- * @param {string} message - The message to format
207
- * @param {Object} meta - Additional metadata
208
- * @returns {string} Formatted log message
209
- */
210
- format(type, message, meta = {}) {
211
- this.eventCount++;
212
-
213
- const parts = [];
214
-
215
- // Add timestamp/elapsed time
216
- this.addTimestamp(parts, false);
217
-
218
- // Add type prefix with color
219
- const prefix = this.getPrefix(type);
220
- if (prefix) parts.push(prefix);
221
-
222
- // Add message
223
- parts.push(this.formatMessage(type, message));
224
-
225
- // Add metadata if present
226
- if (meta.duration) {
227
- parts.push(chalk.dim(`(${meta.duration})`));
228
- }
229
-
230
- return parts.join(" ");
231
- }
232
-
233
- /**
234
- * Get prefix for log type with AWESOME colors and emojis 🎨
235
- * @param {string} type - Log type
236
- * @returns {string} Colored prefix with emoji
237
- */
238
- getPrefix(type) {
239
- if (!this.useEmojis) {
240
- // Fallback to simple symbols without emojis
241
- const simplePrefixes = {
242
- info: chalk.blue("ℹ"),
243
- success: chalk.green("✓"),
244
- error: chalk.red("✖"),
245
- action: chalk.cyan("→"),
246
- debug: chalk.gray("⚙"),
247
- find: chalk.magenta("⌕"),
248
- click: chalk.cyan("▸"),
249
- type: chalk.yellow("⌨"),
250
- assert: chalk.green("✓"),
251
- scroll: chalk.blue("↕"),
252
- hover: chalk.cyan("→"),
253
- wait: chalk.yellow("⏱"),
254
- connect: chalk.green("⚡"),
255
- disconnect: chalk.red("⏹"),
256
- };
257
- return simplePrefixes[type] || chalk.gray("•");
258
- }
259
-
260
- const prefixes = {
261
- // Core actions - hand gestures
262
- info: chalk.blue("ℹ️"),
263
- success: chalk.green("✅"),
264
- error: chalk.red("❌"),
265
- warning: chalk.yellow("⚠️"),
266
-
267
- // Finding elements
268
- find: chalk.magenta("🔍"),
269
- findAll: chalk.magenta("🔎"),
270
-
271
- // Mouse actions
272
- click: chalk.cyan("👆"),
273
- doubleClick: chalk.cyan("👆👆"),
274
- rightClick: chalk.cyan("🖱️"),
275
- hover: chalk.cyan("👉"),
276
- drag: chalk.cyan("✊"),
277
-
278
- // Keyboard actions
279
- type: chalk.yellow("⌨️ "),
280
- pressKeys: chalk.yellow("🎹"),
281
-
282
- // Navigation
283
- scroll: chalk.blue("📜"),
284
- scrollUp: chalk.blue("⬆️"),
285
- scrollDown: chalk.blue("⬇️"),
286
- navigate: chalk.blue("🧭"),
287
-
288
- // Validation
289
- assert: chalk.green("✅"),
290
- verify: chalk.green("🔍"),
291
- extract: chalk.blue("🧠"),
292
-
293
- // System
294
- connect: chalk.green("🔌"),
295
- disconnect: chalk.red("🔌"),
296
- screenshot: chalk.blue("📸"),
297
- wait: chalk.yellow("⏳"),
298
-
299
- // Focus & Windows
300
- focusApplication: chalk.cyan("🎯"),
301
-
302
- // Cache
303
- cacheHit: chalk.yellow("⚡"),
304
- cacheMiss: chalk.gray("💤"),
305
-
306
- // Debug
307
- debug: chalk.gray("🔧"),
308
-
309
- // Default
310
- action: chalk.cyan("▶️ "),
311
- };
312
- return prefixes[type] || chalk.gray("•");
313
- }
314
-
315
- /**
316
- * Format the message content with appropriate styling
317
- * @param {string} type - Log type
318
- * @param {string} message - Raw message
319
- * @returns {string} Formatted message
320
- */
321
- formatMessage(type, message) {
322
- if (!this.useColors) return message;
323
-
324
- const formatters = {
325
- success: (msg) => chalk.green(msg),
326
- error: (msg) => chalk.red(msg),
327
- debug: (msg) => chalk.dim(msg),
328
- };
329
-
330
- return formatters[type] ? formatters[type](message) : message;
331
- }
332
-
333
- /**
334
- * Format a "finding" style message (when search starts) 🔍
335
- * @param {string} prefixType - Prefix type for getPrefix
336
- * @param {string} label - Action label (e.g., "Finding", "Finding All", "Asserting")
337
- * @param {string} description - Element/assertion description
338
- * @returns {string} Formatted message
339
- */
340
- formatFindingStyle(prefixType, label, description) {
341
- const parts = [];
342
- this.addTimestamp(parts);
343
- parts.push(this.getPrefix(prefixType));
344
- parts.push(chalk.bold.cyan(label));
345
- parts.push(chalk.cyan(`"${description}"`));
346
- return parts.join(" ");
347
- }
348
-
349
- /**
350
- * Format an element finding message (when search starts) 🔍
351
- * @param {string} description - Element description
352
- * @returns {string} Formatted message
353
- */
354
- formatElementFinding(description) {
355
- return this.formatFindingStyle("find", "Finding", description);
356
- }
357
-
358
- /**
359
- * Build common metadata parts for result messages
360
- * @param {Object} meta - Metadata object
361
- * @param {string} thresholdKey - Duration threshold key
362
- * @returns {Array} Array of formatted metadata strings
363
- */
364
- buildResultMetaParts(meta, thresholdKey = "default") {
365
- const metaParts = [];
366
-
367
- if (meta.x !== undefined && meta.y !== undefined) {
368
- metaParts.push(chalk.dim.gray(`📍 (${meta.x}, ${meta.y})`));
369
- }
370
- if (meta.selectorId && meta.consoleUrl) {
371
- const cacheUrl = `${meta.consoleUrl}/cache/${meta.selectorId}`;
372
- metaParts.push(chalk.blue.underline(cacheUrl));
373
- }
374
- if (meta.error) {
375
- metaParts.push(chalk.dim.red(meta.error));
376
- }
377
- if (meta.cacheHit) {
378
- metaParts.push(chalk.bold.yellow("⚡ cached"));
379
- }
380
- // Duration always last
381
- if (meta.duration) {
382
- metaParts.push(this.formatDurationColored(meta.duration, thresholdKey));
383
- }
384
-
385
- return metaParts;
386
- }
387
-
388
- /**
389
- * Format a result line (indented child result)
390
- * @param {string} statusText - Status text (e.g., "found", "not found")
391
- * @param {Function} statusColor - Chalk color function for status
392
- * @param {Object} meta - Metadata object
393
- * @param {string} thresholdKey - Duration threshold key
394
- * @returns {string} Formatted result line
395
- */
396
- formatResultLine(statusText, statusColor, meta = {}, thresholdKey = "default") {
397
- const parts = [];
398
- this.addTimestamp(parts);
399
- parts.push(this.getResultPrefix());
400
- parts.push(statusColor(statusText));
401
-
402
- const metaParts = this.buildResultMetaParts(meta, thresholdKey);
403
- if (metaParts.length > 0) {
404
- parts.push(this.joinMetaParts(metaParts));
405
- }
406
-
407
- return parts.join(" ");
408
- }
409
-
410
- /**
411
- * Format an element found message with AWESOME styling 🎯
412
- * @param {string} description - Element description
413
- * @param {Object} meta - Element metadata (coordinates, duration, cache hit)
414
- * @returns {string} Formatted message
415
- */
416
- formatElementFound(description, meta = {}) {
417
- return this.formatResultLine("found", chalk.green, meta);
418
- }
419
-
420
- /**
421
- * Format an element not found message with styling ❌
422
- * @param {string} description - Element description
423
- * @param {Object} meta - Metadata (duration, error)
424
- * @returns {string} Formatted message
425
- */
426
- formatElementNotFound(description, meta = {}) {
427
- return this.formatResultLine("not found", chalk.red, meta);
428
- }
429
-
430
- /**
431
- * Format a finding all message (when search starts) 🔎
432
- * @param {string} description - Element description
433
- * @returns {string} Formatted message
434
- */
435
- formatElementsFinding(description) {
436
- return this.formatFindingStyle("findAll", "Finding All", description);
437
- }
438
-
439
- /**
440
- * Format a found all message with AWESOME styling 🎯
441
- * @param {string} description - Element description
442
- * @param {number} count - Number of elements found
443
- * @param {Object} meta - Metadata (duration, cache hit)
444
- * @returns {string} Formatted message
445
- */
446
- formatElementsFound(description, count, meta = {}) {
447
- const parts = [];
448
- this.addTimestamp(parts);
449
- parts.push(this.getResultPrefix());
450
- parts.push(chalk.green(`found ${count} elements`));
451
-
452
- const metaParts = [];
453
- if (meta.cacheHit) {
454
- metaParts.push(chalk.bold.yellow("⚡ cached"));
455
- }
456
- if (meta.duration) {
457
- metaParts.push(this.formatDurationColored(meta.duration));
458
- }
459
-
460
- if (metaParts.length > 0) {
461
- parts.push(this.joinMetaParts(metaParts));
462
- }
463
-
464
- return parts.join(" ");
465
- }
466
-
467
- /**
468
- * Format an asserting message (when assertion starts) ✓
469
- * @param {string} assertion - What is being asserted
470
- * @returns {string} Formatted message
471
- */
472
- formatAsserting(assertion) {
473
- return this.formatFindingStyle("assert", "Asserting", assertion);
474
- }
475
- /**
476
- * Format the assertion result as a subtask line
477
- * @param {boolean} passed - Whether assertion passed
478
- * @param {string} response - The AI response message
479
- * @param {number} durationMs - Duration in milliseconds
480
- * @returns {string} Formatted result line
481
- */
482
- formatAssertResult(passed, response, durationMs) {
483
- const parts = [];
484
- this.addTimestamp(parts);
485
- parts.push(this.getResultPrefix());
486
-
487
- if (passed) {
488
- parts.push(chalk.green("passed"));
489
- } else {
490
- parts.push(chalk.red("failed"));
491
- }
492
-
493
- // Add the response message (trimmed)
494
- if (response) {
495
- const trimmedResponse = response.trim().split('\n')[0]; // First line only
496
- parts.push(chalk.dim(trimmedResponse));
497
- }
498
-
499
- // Add duration
500
- if (durationMs) {
501
- parts.push(this.formatDurationColored(durationMs, "action"));
502
- }
503
-
504
- return parts.join(" ");
505
- }
506
-
507
- // Action color mapping (shared between formatAction and formatActionComplete)
508
- static ACTION_COLORS = {
509
- click: chalk.bold.cyan,
510
- hover: chalk.bold.blue,
511
- type: chalk.bold.yellow,
512
- scroll: chalk.bold.magenta,
513
- assert: chalk.bold.green,
514
- wait: chalk.bold.yellow,
515
- };
516
-
517
- /**
518
- * Build action message parts (shared logic for formatAction and formatActionComplete)
519
- * @param {string} action - Action type
520
- * @param {string} description - Description or target
521
- * @returns {Array} Array of formatted parts
522
- */
523
- buildActionParts(action, description) {
524
- const parts = [];
525
- this.addTimestamp(parts);
526
-
527
- const actionKey = action.toLowerCase().replace(/\s+/g, "");
528
- parts.push(this.getPrefix(actionKey));
529
-
530
- const actionText = action.charAt(0).toUpperCase() + action.slice(1).toLowerCase();
531
- const colorFn = SDKLogFormatter.ACTION_COLORS[actionKey] || chalk.bold.white;
532
- parts.push(colorFn(actionText));
533
-
534
- if (description) {
535
- parts.push(chalk.cyan(`"${description}"`));
536
- }
537
-
538
- return { parts, actionKey };
539
- }
540
-
541
- /**
542
- * Format an action message with AWESOME emojis! 🎬
543
- * @param {string} action - Action type
544
- * @param {string} description - Description or target
545
- * @param {Object} meta - Action metadata
546
- * @returns {string} Formatted message
547
- */
548
- formatAction(action, description, meta = {}) {
549
- const { parts } = this.buildActionParts(action, description);
550
-
551
- const metaParts = [];
552
- if (meta.text) {
553
- metaParts.push(chalk.gray(`→ ${chalk.white(meta.text)}`));
554
- }
555
- if (meta.duration) {
556
- metaParts.push(chalk.dim(`⏱️ ${this.formatDurationColored(meta.duration, "quickAction", false)}`));
557
- }
558
-
559
- if (metaParts.length > 0) {
560
- parts.push(this.joinMetaParts(metaParts));
561
- }
562
-
563
- return parts.join(" ");
564
- }
565
-
566
- /**
567
- * Format an action complete message with separate action and redraw durations 🎬
568
- * @param {string} action - Action type
569
- * @param {string} description - Description or target
570
- * @param {Object} meta - Action metadata
571
- * @param {number} meta.actionDuration - Duration of the action itself in ms
572
- * @param {number} meta.redrawDuration - Duration of the redraw wait in ms
573
- * @param {boolean} meta.cacheHit - Whether cache was hit
574
- * @returns {string} Formatted message
575
- */
576
- formatActionComplete(action, description, meta = {}) {
577
- const { parts } = this.buildActionParts(action, description);
578
-
579
- const metaParts = [];
580
-
581
- if (meta.actionDuration !== undefined) {
582
- const durationMs = parseInt(meta.actionDuration);
583
- const durationSec = (durationMs / 1000).toFixed(1) + 's';
584
- const color = this.getDurationColor(durationMs, "action");
585
- metaParts.push(chalk.dim(`⚡ ${color(durationSec)}`));
586
- }
587
-
588
- if (meta.redrawDuration !== undefined) {
589
- const durationMs = parseInt(meta.redrawDuration);
590
- const durationSec = (durationMs / 1000).toFixed(1) + 's';
591
- const color = this.getDurationColor(durationMs, "redraw");
592
- metaParts.push(chalk.dim(`🔄 ${color(durationSec)}`));
593
- }
594
-
595
- if (meta.cacheHit) {
596
- metaParts.push(chalk.bold.yellow("⚡ cached"));
597
- }
598
-
599
- if (metaParts.length > 0) {
600
- parts.push(this.joinMetaParts(metaParts));
601
- }
602
-
603
- return parts.join(" ");
604
- }
605
-
606
- /**
607
- * Format an assertion message with beautiful status indicators 🎯
608
- * @param {string} assertion - What is being asserted
609
- * @param {boolean} passed - Whether assertion passed
610
- * @param {Object} meta - Assertion metadata
611
- * @returns {string} Formatted message
612
- */
613
- formatAssertion(assertion, passed, meta = {}) {
614
- const parts = [];
615
- this.addTimestamp(parts);
616
-
617
- if (passed) {
618
- parts.push(this.getPrefix("success"));
619
- parts.push(chalk.bold.green("Assert"));
620
- parts.push(chalk.cyan(`"${assertion}"`));
621
- parts.push(chalk.dim("·"));
622
- parts.push(chalk.bold.green("✓ PASSED"));
623
- } else {
624
- parts.push(this.getPrefix("error"));
625
- parts.push(chalk.bold.red("Assert"));
626
- parts.push(chalk.cyan(`"${assertion}"`));
627
- parts.push(chalk.dim("·"));
628
- parts.push(chalk.bold.red("✗ FAILED"));
629
- }
630
-
631
- if (meta.duration) {
632
- parts.push(chalk.dim("·"));
633
- parts.push(chalk.dim(`⏱️ ${this.formatDurationColored(meta.duration, "action", false)}`));
634
- }
635
-
636
- return parts.join(" ");
637
- }
638
-
639
- /**
640
- * Format an error message with clear visual indicators 🚨
641
- * @param {string} message - Error message
642
- * @param {Error} error - Error object
643
- * @returns {string} Formatted error
644
- */
645
- formatError(message, error) {
646
- const parts = [];
647
- this.addTimestamp(parts);
648
- parts.push(this.getPrefix("error"));
649
- parts.push(chalk.red.bold(message));
650
-
651
- if (error && error.message) {
652
- parts.push(chalk.dim("→"));
653
- parts.push(chalk.red(error.message));
654
- }
655
-
656
- return parts.join(" ");
657
- }
658
-
659
- /**
660
- * Format a connection/disconnection message 🔌
661
- * @param {string} type - 'connect' or 'disconnect'
662
- * @param {Object} meta - Connection metadata
663
- * @returns {string} Formatted message
664
- */
665
- formatConnection(type, meta = {}) {
666
- const parts = [];
667
- this.addTimestamp(parts);
668
- parts.push(this.getPrefix(type));
669
-
670
- if (type === "connect") {
671
- parts.push(chalk.bold.green("Connected"));
672
- if (meta.sandboxId) {
673
- parts.push(chalk.dim("·"));
674
- parts.push(chalk.cyan(`Sandbox: ${meta.sandboxId}`));
675
- }
676
- if (meta.os) {
677
- parts.push(chalk.dim("·"));
678
- parts.push(chalk.gray(`OS: ${meta.os}`));
679
- }
680
- } else {
681
- parts.push(chalk.bold.yellow("Disconnected"));
682
- }
683
-
684
- return parts.join(" ");
685
- }
686
-
687
- /**
688
- * Format a screenshot message 📸
689
- * @param {Object} meta - Screenshot metadata
690
- * @returns {string} Formatted message
691
- */
692
- formatScreenshot(meta = {}) {
693
- const parts = [];
694
- this.addTimestamp(parts);
695
- parts.push(this.getPrefix("screenshot"));
696
- parts.push(chalk.bold.blue("Screenshot"));
697
-
698
- if (meta.path) {
699
- parts.push(chalk.dim("·"));
700
- parts.push(chalk.cyan(meta.path));
701
- }
702
-
703
- if (meta.size) {
704
- parts.push(chalk.dim("·"));
705
- parts.push(chalk.gray(`${meta.size}`));
706
- }
707
-
708
- return parts.join(" ");
709
- }
710
-
711
- /**
712
- * Format a cache status message ⚡
713
- * @param {boolean} hit - Whether it was a cache hit
714
- * @param {Object} meta - Cache metadata
715
- * @returns {string} Formatted message
716
- */
717
- formatCacheStatus(hit, meta = {}) {
718
- const parts = [];
719
- parts.push(this.getPrefix(hit ? "cacheHit" : "cacheMiss"));
720
-
721
- if (hit) {
722
- parts.push(chalk.bold.yellow("Cache HIT"));
723
- if (meta.similarity !== undefined) {
724
- const similarity = (meta.similarity * 100).toFixed(1);
725
- parts.push(chalk.dim("·"));
726
- parts.push(chalk.green(`${similarity}% similar`));
727
- }
728
- } else {
729
- parts.push(chalk.dim.gray("Cache MISS"));
730
- }
731
-
732
- if (meta.strategy) {
733
- parts.push(chalk.dim("·"));
734
- parts.push(chalk.gray(meta.strategy));
735
- }
736
-
737
- return parts.join(" ");
738
- }
739
-
740
- /**
741
- * Create a beautiful section header with box drawing 📦
742
- * @param {string} title - Section title
743
- * @param {string} emoji - Optional emoji to prefix
744
- * @returns {string} Formatted header
745
- */
746
- formatHeader(title, emoji = "✨") {
747
- const width = Math.min(60, Math.max(title.length + 4, 40));
748
- const topLine = chalk.dim("╭" + "─".repeat(width - 2) + "╮");
749
- const titleLine =
750
- `${chalk.dim("│")} ${emoji} ${chalk.bold.white(title)}`.padEnd(width + 20) + chalk.dim("│");
751
- const bottomLine = chalk.dim("╰" + "─".repeat(width - 2) + "╯");
752
- return `\n${topLine}\n${titleLine}\n${bottomLine}\n`;
753
- }
754
-
755
- /**
756
- * Format a simple divider
757
- * @param {string} char - Character to use for divider
758
- * @returns {string} Formatted divider
759
- */
760
- formatDivider(char = "─") {
761
- return chalk.dim(char.repeat(60));
762
- }
763
-
764
- /**
765
- * Format a beautiful summary line with stats 📊
766
- * @param {Object} stats - Test statistics
767
- * @returns {string} Formatted summary
768
- */
769
- formatSummary(stats) {
770
- const parts = [];
771
-
772
- if (stats.passed > 0) {
773
- parts.push(chalk.bold.green(`✓ ${stats.passed} passed`));
774
- }
775
- if (stats.failed > 0) {
776
- parts.push(chalk.bold.red(`✗ ${stats.failed} failed`));
777
- }
778
- if (stats.skipped > 0) {
779
- parts.push(chalk.yellow(`⊘ ${stats.skipped} skipped`));
780
- }
781
- if (stats.total > 0) {
782
- parts.push(chalk.dim(`${stats.total} total`));
783
- }
784
- if (stats.duration) {
785
- parts.push(chalk.dim(`⏱️ ${stats.duration}`));
786
- }
787
-
788
- const divider = this.formatDivider();
789
- const separator = chalk.dim(" │ ");
790
- return `\n${divider}\n${parts.join(separator)}\n${divider}\n`;
791
- }
792
-
793
- /**
794
- * Format a progress indicator 📈
795
- * @param {number} current - Current step
796
- * @param {number} total - Total steps
797
- * @param {string} message - Progress message
798
- * @returns {string} Formatted progress
799
- */
800
- formatProgress(current, total, message = "") {
801
- const percentage = Math.round((current / total) * 100);
802
- const barWidth = 20;
803
- const filled = Math.round((current / total) * barWidth);
804
- const empty = barWidth - filled;
805
-
806
- const bar = chalk.green("█".repeat(filled)) + chalk.dim("░".repeat(empty));
807
- const stats = chalk.dim(`${current}/${total}`);
808
-
809
- const parts = [
810
- chalk.bold("Progress"),
811
- bar,
812
- chalk.cyan(`${percentage}%`),
813
- stats,
814
- ];
815
-
816
- if (message) {
817
- parts.push(chalk.dim("·"));
818
- parts.push(chalk.gray(message));
819
- }
820
-
821
- return parts.join(" ");
822
- }
823
-
824
- /**
825
- * Format a waiting/loading message ⏳
826
- * @param {string} message - What we're waiting for
827
- * @param {number} elapsed - Elapsed time in ms
828
- * @returns {string} Formatted waiting message
829
- */
830
- formatWaiting(message, elapsed) {
831
- const parts = [];
832
- parts.push(this.getPrefix("wait"));
833
- parts.push(chalk.bold.yellow("Waiting"));
834
- parts.push(chalk.cyan(message));
835
-
836
- if (elapsed) {
837
- const seconds = (elapsed / 1000).toFixed(1);
838
- parts.push(chalk.dim("·"));
839
- parts.push(chalk.gray(`${seconds}s`));
840
- }
841
-
842
- return parts.join(" ");
843
- }
844
-
845
- /**
846
- * Format test start message 🚀
847
- * @param {string} testName - Name of the test
848
- * @returns {string} Formatted test start
849
- */
850
- formatTestStart(testName) {
851
- return `\n${chalk.bold.cyan("▶️ Running:")} ${chalk.white(testName)}\n`;
852
- }
853
-
854
- /**
855
- * Format test end message with result 🏁
856
- * @param {string} testName - Name of the test
857
- * @param {boolean} passed - Whether test passed
858
- * @param {number} duration - Test duration in ms
859
- * @returns {string} Formatted test end
860
- */
861
- formatTestEnd(testName, passed, duration) {
862
- const parts = [];
863
-
864
- if (passed) {
865
- parts.push(chalk.bold.green("✅ PASSED"));
866
- } else {
867
- parts.push(chalk.bold.red("❌ FAILED"));
868
- }
869
-
870
- parts.push(chalk.white(testName));
871
-
872
- if (duration) {
873
- const seconds = (duration / 1000).toFixed(2);
874
- const color = this.getDurationColor(duration, "test");
875
- parts.push(chalk.dim("·"));
876
- parts.push(color(`${seconds}s`));
877
- }
878
-
879
- return `\n${parts.join(" ")}\n`;
880
- }
881
-
882
- /**
883
- * Format ai() start message - provides visual scope boundary
884
- * @param {string} task - The task being executed
885
- * @returns {string} Formatted ai start message
886
- */
887
- formatAIStart(task) {
888
- const parts = [];
889
- this.addTimestamp(parts);
890
- parts.push(this.getPrefix("action"));
891
- parts.push(chalk.bold.cyan("AI"));
892
- parts.push(chalk.cyan(`"${task}"`));
893
- return parts.join(" ");
894
- }
895
-
896
- /**
897
- * Format ai() completion message - provides visual scope boundary
898
- * @param {number} durationMs - Duration in milliseconds
899
- * @param {boolean} success - Whether the ai completed successfully
900
- * @param {string} [error] - Error message if failed
901
- * @returns {string} Formatted ai complete message
902
- */
903
- formatAIComplete(durationMs, success, error = null) {
904
- const parts = [];
905
- this.addTimestamp(parts);
906
- parts.push(this.getResultPrefix());
907
-
908
- if (success) {
909
- parts.push(chalk.green("complete"));
910
- } else {
911
- parts.push(chalk.red("failed"));
912
- if (error) {
913
- parts.push(chalk.dim("·"));
914
- parts.push(chalk.red(error));
915
- }
916
- }
917
-
918
- parts.push(this.formatDurationColored(durationMs, "default"));
919
-
920
- return parts.join(" ");
921
- }
922
- }
923
-
924
- // Export singleton instance
925
- const formatter = new SDKLogFormatter();
926
-
927
- module.exports = {
928
- SDKLogFormatter,
929
- formatter,
930
- };