testdriverai 7.2.63 → 7.2.65

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 (362) hide show
  1. package/agent/index.js +77 -59
  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 +79 -29
  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/core/Dashcam.js +22 -15
  52. package/lib/sentry.js +4 -3
  53. package/lib/vitest/hooks.mjs +70 -16
  54. package/lib/vitest/setup-aws.mjs +0 -10
  55. package/package.json +29 -9
  56. package/sdk.d.ts +32 -5
  57. package/sdk.js +10 -9
  58. package/.env.example +0 -4
  59. package/.github/workflows/acceptance-linux-scheduled.yaml +0 -45
  60. package/.github/workflows/acceptance-windows-scheduled.yaml +0 -54
  61. package/.github/workflows/acceptance.yaml +0 -87
  62. package/.github/workflows/publish.yaml +0 -68
  63. package/.github/workflows/test-init.yml +0 -145
  64. package/.github/workflows/testdriver.yml +0 -170
  65. package/.github/workflows/windows-self-hosted.yaml +0 -82
  66. package/.prettierignore +0 -4
  67. package/.prettierrc +0 -1
  68. package/CHANGELOG.md +0 -30
  69. package/agents.md +0 -455
  70. package/debugger/bg.png +0 -0
  71. package/debugger/icon.png +0 -0
  72. package/debugger/index.html +0 -797
  73. package/debugger/td.png +0 -0
  74. package/debugger/tray-buffered.png +0 -0
  75. package/debugger/tray.png +0 -0
  76. package/docs/GITHUB_COMMENTS.md +0 -330
  77. package/docs/GITHUB_COMMENTS_ANNOUNCEMENT.md +0 -167
  78. package/docs/QUICK-START-GITHUB-COMMENTS.md +0 -84
  79. package/docs/TEST-GITHUB-COMMENTS.md +0 -129
  80. package/docs/_scripts/link-replacer.js +0 -164
  81. package/docs/_scripts/upload-docs-to-openai.js +0 -284
  82. package/docs/docs.json +0 -393
  83. package/docs/github-integration-setup.md +0 -266
  84. package/docs/guide/best-practices-polling.mdx +0 -154
  85. package/docs/images/content/account/newprojectsettings.png +0 -0
  86. package/docs/images/content/account/projectpage.png +0 -0
  87. package/docs/images/content/account/projectreplays.png +0 -0
  88. package/docs/images/content/account/team-manage.png +0 -0
  89. package/docs/images/content/account/teampage.png +0 -0
  90. package/docs/images/content/extension/cursor.svg +0 -1
  91. package/docs/images/content/extension/vscode.svg +0 -57
  92. package/docs/images/content/extension/windsurf.svg +0 -3
  93. package/docs/images/content/self-hosted/launchtemplateid.png +0 -0
  94. package/docs/images/content/side-by-side.png +0 -0
  95. package/docs/images/content/vscode/ide-full.png +0 -0
  96. package/docs/images/content/vscode/running.png +0 -0
  97. package/docs/images/content/vscode/vscode-2-assert.png +0 -0
  98. package/docs/images/content/vscode/vscode-agent-preview.png +0 -0
  99. package/docs/images/content/vscode/vscode-copilot-ask.png +0 -0
  100. package/docs/images/content/vscode/vscode-file-creation.png +0 -0
  101. package/docs/images/content/vscode/vscode-install.png +0 -0
  102. package/docs/images/content/vscode/vscode-overview.png +0 -0
  103. package/docs/images/content/vscode/vscode-setup-walkthrough.png +0 -0
  104. package/docs/images/content/vscode/vscode-stopchat.png +0 -0
  105. package/docs/images/content/vscode/vscode-stoptest.png +0 -0
  106. package/docs/images/content/vscode/vscode-tdservice.png +0 -0
  107. package/docs/images/content/vscode/vscode-test-output.png +0 -0
  108. package/docs/images/content/vscode/vscode-testhistory.png +0 -0
  109. package/docs/images/content/vscode/vscode-testpane-runtests.png +0 -0
  110. package/docs/images/content/vscode/vscode-testpane.png +0 -0
  111. package/docs/images/template/dark.png +0 -0
  112. package/docs/images/template/icon.png +0 -0
  113. package/docs/images/template/light.png +0 -0
  114. package/docs/snippets/calendar-link.mdx +0 -4
  115. package/docs/snippets/gitignore-warning.mdx +0 -7
  116. package/docs/snippets/lifecycle-warning.mdx +0 -6
  117. package/docs/snippets/test-prereqs.mdx +0 -12
  118. package/docs/snippets/tests/assert-replay.mdx +0 -7
  119. package/docs/snippets/tests/assert-yaml.mdx +0 -8
  120. package/docs/snippets/tests/exec-js-replay.mdx +0 -7
  121. package/docs/snippets/tests/exec-js-yaml.mdx +0 -32
  122. package/docs/snippets/tests/exec-shell-replay.mdx +0 -7
  123. package/docs/snippets/tests/exec-shell-yaml.mdx +0 -15
  124. package/docs/snippets/tests/hover-image-replay.mdx +0 -7
  125. package/docs/snippets/tests/hover-image-yaml.mdx +0 -17
  126. package/docs/snippets/tests/hover-text-replay.mdx +0 -7
  127. package/docs/snippets/tests/hover-text-with-description-replay.mdx +0 -7
  128. package/docs/snippets/tests/hover-text-with-description-yaml.mdx +0 -24
  129. package/docs/snippets/tests/hover-text-yaml.mdx +0 -14
  130. package/docs/snippets/tests/match-image-replay.mdx +0 -7
  131. package/docs/snippets/tests/match-image-yaml.mdx +0 -17
  132. package/docs/snippets/tests/press-keys-replay.mdx +0 -7
  133. package/docs/snippets/tests/press-keys-yaml.mdx +0 -36
  134. package/docs/snippets/tests/remember-replay.mdx +0 -7
  135. package/docs/snippets/tests/remember-yaml.mdx +0 -28
  136. package/docs/snippets/tests/scroll-replay.mdx +0 -7
  137. package/docs/snippets/tests/scroll-until-image-replay.mdx +0 -7
  138. package/docs/snippets/tests/scroll-until-image-yaml.mdx +0 -14
  139. package/docs/snippets/tests/scroll-until-text-replay.mdx +0 -7
  140. package/docs/snippets/tests/scroll-until-text-yaml.mdx +0 -17
  141. package/docs/snippets/tests/scroll-yaml.mdx +0 -30
  142. package/docs/snippets/tests/type-repeated-replay.mdx +0 -7
  143. package/docs/snippets/tests/type-repeated-yaml.mdx +0 -22
  144. package/docs/snippets/tests/type-replay.mdx +0 -7
  145. package/docs/snippets/tests/type-yaml.mdx +0 -28
  146. package/docs/snippets/tests/wait-for-image-replay.mdx +0 -7
  147. package/docs/snippets/tests/wait-for-image-yaml.mdx +0 -18
  148. package/docs/snippets/tests/wait-for-text-replay.mdx +0 -7
  149. package/docs/snippets/tests/wait-for-text-yaml.mdx +0 -18
  150. package/docs/snippets/tests/wait-replay.mdx +0 -7
  151. package/docs/snippets/tests/wait-yaml.mdx +0 -13
  152. package/docs/styles.css +0 -65
  153. package/docs/v6/account/dashboard.mdx +0 -16
  154. package/docs/v6/account/enterprise.mdx +0 -110
  155. package/docs/v6/account/pricing.mdx +0 -33
  156. package/docs/v6/account/projects.mdx +0 -33
  157. package/docs/v6/account/team.mdx +0 -35
  158. package/docs/v6/action/ami.mdx +0 -109
  159. package/docs/v6/action/performance.mdx +0 -105
  160. package/docs/v6/action/secrets.mdx +0 -93
  161. package/docs/v6/apps/chrome-extensions.mdx +0 -48
  162. package/docs/v6/apps/desktop-apps.mdx +0 -93
  163. package/docs/v6/apps/mobile-apps.mdx +0 -26
  164. package/docs/v6/apps/static-websites.mdx +0 -54
  165. package/docs/v6/apps/tauri-apps.mdx +0 -361
  166. package/docs/v6/bugs/jira.mdx +0 -232
  167. package/docs/v6/cli/overview.mdx +0 -66
  168. package/docs/v6/commands/assert.mdx +0 -45
  169. package/docs/v6/commands/exec.mdx +0 -282
  170. package/docs/v6/commands/focus-application.mdx +0 -44
  171. package/docs/v6/commands/hover-image.mdx +0 -69
  172. package/docs/v6/commands/hover-text.mdx +0 -47
  173. package/docs/v6/commands/if.mdx +0 -53
  174. package/docs/v6/commands/match-image.mdx +0 -67
  175. package/docs/v6/commands/press-keys.mdx +0 -87
  176. package/docs/v6/commands/remember.mdx +0 -49
  177. package/docs/v6/commands/run.mdx +0 -44
  178. package/docs/v6/commands/scroll-until-image.mdx +0 -66
  179. package/docs/v6/commands/scroll-until-text.mdx +0 -60
  180. package/docs/v6/commands/scroll.mdx +0 -69
  181. package/docs/v6/commands/type.mdx +0 -45
  182. package/docs/v6/commands/wait-for-image.mdx +0 -54
  183. package/docs/v6/commands/wait-for-text.mdx +0 -48
  184. package/docs/v6/commands/wait.mdx +0 -45
  185. package/docs/v6/exporting/junit.mdx +0 -218
  186. package/docs/v6/exporting/playwright.mdx +0 -197
  187. package/docs/v6/features/auto-healing.mdx +0 -144
  188. package/docs/v6/features/generation.mdx +0 -116
  189. package/docs/v6/features/parallel-testing.mdx +0 -151
  190. package/docs/v6/features/reusable-snippets.mdx +0 -131
  191. package/docs/v6/features/selectorless.mdx +0 -80
  192. package/docs/v6/features/visual-assertions.mdx +0 -139
  193. package/docs/v6/getting-started/ci.mdx +0 -146
  194. package/docs/v6/getting-started/cli.mdx +0 -91
  195. package/docs/v6/getting-started/editing.mdx +0 -100
  196. package/docs/v6/getting-started/playwright.mdx +0 -342
  197. package/docs/v6/getting-started/running.mdx +0 -48
  198. package/docs/v6/getting-started/self-hosting.mdx +0 -408
  199. package/docs/v6/getting-started/vscode.mdx +0 -89
  200. package/docs/v6/guide/assertions.mdx +0 -189
  201. package/docs/v6/guide/authentication.mdx +0 -136
  202. package/docs/v6/guide/code.mdx +0 -65
  203. package/docs/v6/guide/dashcam.mdx +0 -118
  204. package/docs/v6/guide/environment-variables.mdx +0 -26
  205. package/docs/v6/guide/lifecycle.mdx +0 -242
  206. package/docs/v6/guide/locating.mdx +0 -141
  207. package/docs/v6/guide/protips.mdx +0 -43
  208. package/docs/v6/guide/variables.mdx +0 -143
  209. package/docs/v6/guide/waiting.mdx +0 -130
  210. package/docs/v6/importing/csv.mdx +0 -196
  211. package/docs/v6/importing/gherkin.mdx +0 -143
  212. package/docs/v6/importing/jira.mdx +0 -164
  213. package/docs/v6/importing/testrail.mdx +0 -162
  214. package/docs/v6/integrations/electron.mdx +0 -146
  215. package/docs/v6/integrations/netlify.mdx +0 -100
  216. package/docs/v6/integrations/vercel.mdx +0 -125
  217. package/docs/v6/interactive/explore.mdx +0 -99
  218. package/docs/v6/interactive/run.mdx +0 -52
  219. package/docs/v6/interactive/save.mdx +0 -63
  220. package/docs/v6/overview/comparison.mdx +0 -101
  221. package/docs/v6/overview/faq.mdx +0 -162
  222. package/docs/v6/overview/performance.mdx +0 -52
  223. package/docs/v6/overview/quickstart.mdx +0 -137
  224. package/docs/v6/overview/what-is-testdriver.mdx +0 -85
  225. package/docs/v6/scenarios/ai-chatbot.mdx +0 -28
  226. package/docs/v6/scenarios/cookie-banner.mdx +0 -32
  227. package/docs/v6/scenarios/file-upload.mdx +0 -33
  228. package/docs/v6/scenarios/form-filling.mdx +0 -32
  229. package/docs/v6/scenarios/log-in.mdx +0 -75
  230. package/docs/v6/scenarios/pdf-generation.mdx +0 -25
  231. package/docs/v6/scenarios/spell-check.mdx +0 -22
  232. package/docs/v6/security/action.mdx +0 -84
  233. package/docs/v6/security/agent.mdx +0 -73
  234. package/docs/v6/security/platform.mdx +0 -77
  235. package/docs/v6/tutorials/advanced-test.mdx +0 -81
  236. package/docs/v6/tutorials/basic-test.mdx +0 -45
  237. package/docs/v7/_drafts/agents.mdx +0 -852
  238. package/docs/v7/_drafts/architecture.mdx +0 -399
  239. package/docs/v7/_drafts/auto-cache-key.mdx +0 -167
  240. package/docs/v7/_drafts/awesome-logs-quick-ref.mdx +0 -100
  241. package/docs/v7/_drafts/best-practices.mdx +0 -486
  242. package/docs/v7/_drafts/caching-ai.mdx +0 -215
  243. package/docs/v7/_drafts/caching-selectors.mdx +0 -424
  244. package/docs/v7/_drafts/caching.mdx +0 -366
  245. package/docs/v7/_drafts/cli-to-sdk-migration.mdx +0 -425
  246. package/docs/v7/_drafts/commands/assert.mdx +0 -45
  247. package/docs/v7/_drafts/commands/exec.mdx +0 -282
  248. package/docs/v7/_drafts/commands/focus-application.mdx +0 -44
  249. package/docs/v7/_drafts/commands/hover-image.mdx +0 -69
  250. package/docs/v7/_drafts/commands/hover-text.mdx +0 -47
  251. package/docs/v7/_drafts/commands/if.mdx +0 -53
  252. package/docs/v7/_drafts/commands/match-image.mdx +0 -67
  253. package/docs/v7/_drafts/commands/press-keys.mdx +0 -87
  254. package/docs/v7/_drafts/commands/remember.mdx +0 -49
  255. package/docs/v7/_drafts/commands/run.mdx +0 -44
  256. package/docs/v7/_drafts/commands/scroll-until-image.mdx +0 -66
  257. package/docs/v7/_drafts/commands/scroll-until-text.mdx +0 -60
  258. package/docs/v7/_drafts/commands/scroll.mdx +0 -69
  259. package/docs/v7/_drafts/commands/type.mdx +0 -45
  260. package/docs/v7/_drafts/commands/wait-for-image.mdx +0 -54
  261. package/docs/v7/_drafts/commands/wait-for-text.mdx +0 -48
  262. package/docs/v7/_drafts/commands/wait.mdx +0 -45
  263. package/docs/v7/_drafts/configuration.mdx +0 -378
  264. package/docs/v7/_drafts/contributing.mdx +0 -174
  265. package/docs/v7/_drafts/core.mdx +0 -458
  266. package/docs/v7/_drafts/dashcam-title-feature.mdx +0 -89
  267. package/docs/v7/_drafts/debugging.mdx +0 -349
  268. package/docs/v7/_drafts/error-handling.mdx +0 -501
  269. package/docs/v7/_drafts/faq.mdx +0 -393
  270. package/docs/v7/_drafts/hooks.mdx +0 -360
  271. package/docs/v7/_drafts/init-command.mdx +0 -95
  272. package/docs/v7/_drafts/installation.mdx +0 -420
  273. package/docs/v7/_drafts/migration.mdx +0 -562
  274. package/docs/v7/_drafts/observable.mdx +0 -604
  275. package/docs/v7/_drafts/playwright.mdx +0 -342
  276. package/docs/v7/_drafts/plugin-migration.mdx +0 -220
  277. package/docs/v7/_drafts/powerful.mdx +0 -419
  278. package/docs/v7/_drafts/presets.mdx +0 -210
  279. package/docs/v7/_drafts/progressive-disclosure.mdx +0 -230
  280. package/docs/v7/_drafts/prompt-cache.mdx +0 -200
  281. package/docs/v7/_drafts/provision.mdx +0 -390
  282. package/docs/v7/_drafts/quick-start-test-recording.mdx +0 -214
  283. package/docs/v7/_drafts/readme.mdx +0 -135
  284. package/docs/v7/_drafts/reports.mdx +0 -414
  285. package/docs/v7/_drafts/scalable.mdx +0 -754
  286. package/docs/v7/_drafts/screenshot.mdx +0 -155
  287. package/docs/v7/_drafts/sdk-awesome-logs.mdx +0 -468
  288. package/docs/v7/_drafts/sdk-browser-rendering.mdx +0 -167
  289. package/docs/v7/_drafts/sdk-migration.mdx +0 -474
  290. package/docs/v7/_drafts/sdk-v7-complete.mdx +0 -345
  291. package/docs/v7/_drafts/self-hosting.mdx +0 -369
  292. package/docs/v7/_drafts/test-recording.mdx +0 -382
  293. package/docs/v7/_drafts/troubleshooting.mdx +0 -526
  294. package/docs/v7/_drafts/vitest-plugin.mdx +0 -477
  295. package/docs/v7/_drafts/vitest.mdx +0 -535
  296. package/docs/v7/_drafts/writing-tests.mdx +0 -25
  297. package/docs/v7/examples.mdx +0 -5
  298. package/eslint.config.js +0 -67
  299. package/examples/ai.test.mjs +0 -30
  300. package/examples/assert.test.mjs +0 -46
  301. package/examples/captcha-api.test.mjs +0 -50
  302. package/examples/chrome-extension.test.mjs +0 -94
  303. package/examples/drag-and-drop.test.mjs +0 -58
  304. package/examples/element-not-found.test.mjs +0 -26
  305. package/examples/exec-output.test.mjs +0 -59
  306. package/examples/exec-pwsh.test.mjs +0 -57
  307. package/examples/focus-window.test.mjs +0 -36
  308. package/examples/formatted-logging.test.mjs +0 -26
  309. package/examples/hover-image.test.mjs +0 -52
  310. package/examples/hover-text-with-description.test.mjs +0 -56
  311. package/examples/hover-text.test.mjs +0 -27
  312. package/examples/installer.test.mjs +0 -49
  313. package/examples/launch-vscode-linux.test.mjs +0 -54
  314. package/examples/match-image.test.mjs +0 -54
  315. package/examples/no-provision.test.mjs +0 -23
  316. package/examples/press-keys.test.mjs +0 -50
  317. package/examples/prompt.test.mjs +0 -33
  318. package/examples/scroll-keyboard.test.mjs +0 -37
  319. package/examples/scroll-until-image.test.mjs +0 -39
  320. package/examples/scroll-until-text.test.mjs +0 -67
  321. package/examples/scroll.test.mjs +0 -41
  322. package/examples/type.test.mjs +0 -45
  323. package/examples/windows-installer.test.mjs +0 -53
  324. package/interfaces/cli/commands/edit.js +0 -3
  325. package/interfaces/cli/commands/generate.js +0 -3
  326. package/interfaces/cli/commands/run.js +0 -3
  327. package/interfaces/cli/utils/factory.js +0 -71
  328. package/jsconfig.json +0 -26
  329. package/manual/test-init-command.js +0 -223
  330. package/sdk-log-formatter.js +0 -930
  331. package/setup/aws/cloudformation.yaml +0 -470
  332. package/setup/aws/spawn-runner.sh +0 -190
  333. package/test/api-resilience.test.mjs +0 -0
  334. package/test/captcha-solver.test.mjs +0 -70
  335. package/test/chrome-remote-debugging.test.mjs +0 -66
  336. package/test/manual/debug-locate-response.js +0 -82
  337. package/test/manual/reconnect-provision.test.mjs +0 -49
  338. package/test/manual/test-console-logs.test.mjs +0 -42
  339. package/test/manual/test-find-api.js +0 -73
  340. package/test/manual/test-init.sh +0 -54
  341. package/test/manual/test-prompt-cache.js +0 -96
  342. package/test/manual/test-provision-auth.mjs +0 -22
  343. package/test/manual/test-sandbox-render.js +0 -28
  344. package/test/manual/test-sdk-methods.js +0 -15
  345. package/test/manual/test-sdk-refactor.js +0 -53
  346. package/test/manual/test-stack-trace.mjs +0 -57
  347. package/test/manual/verify-element-api.js +0 -89
  348. package/test/manual/verify-types.js +0 -0
  349. package/test/manual-unawaited-promise.test.mjs +0 -31
  350. package/testdriver-plugin/skills/actions/SKILL.md +0 -93
  351. package/testdriver-plugin/skills/assertions/SKILL.md +0 -77
  352. package/testdriver-plugin/skills/caching/SKILL.md +0 -66
  353. package/testdriver-plugin/skills/creating-tests/SKILL.md +0 -104
  354. package/testdriver-plugin/skills/finding-elements/SKILL.md +0 -77
  355. package/testdriver-plugin/skills/github-actions/SKILL.md +0 -100
  356. package/testdriver-plugin/skills/running-tests/SKILL.md +0 -77
  357. package/testdriver-plugin/skills/secrets/SKILL.md +0 -87
  358. package/testdriver-plugin/skills/self-hosting/SKILL.md +0 -89
  359. package/testdriver-plugin/skills/setup/SKILL.md +0 -76
  360. package/testdriver-plugin/skills/variables/SKILL.md +0 -88
  361. package/testdriver-plugin/skills/waiting/SKILL.md +0 -72
  362. package/vitest.config.mjs +0 -29
package/agent/index.js CHANGED
@@ -36,6 +36,7 @@ const { createOutputs } = require("./lib/outputs.js");
36
36
  const isValidVersion = require("./lib/valid-version.js");
37
37
  const { events, createEmitter } = require("./events.js");
38
38
  const { createDebuggerProcess } = require("./lib/debugger.js");
39
+ const logger = require("./lib/logger.js");
39
40
  let debuggerProcess = null; // single debugger process for all instances. otherwise they'll fight over ports. this should be in `web` anyway
40
41
  let debuggerStarted = false;
41
42
 
@@ -110,8 +111,8 @@ class TestDriverAgent extends EventEmitter2 {
110
111
  this.sandbox = createSandbox(this.emitter, this.analytics, this.session);
111
112
 
112
113
  // Attach Sentry log listeners to capture CLI logs as breadcrumbs
113
- const sentry = require("../lib/sentry");
114
- sentry.attachLogListeners(this.emitter);
114
+ const sentry = require("../lib/sentry");
115
+ sentry.attachLogListeners(this.emitter);
115
116
 
116
117
  // Set the OS for the sandbox to use
117
118
  this.sandbox.os = this.sandboxOs;
@@ -191,7 +192,14 @@ class TestDriverAgent extends EventEmitter2 {
191
192
  // allows us to save the current state, run lifecycle hooks, and track analytics
192
193
  async exit(failed = true, shouldSave = false, shouldRunPostrun = false) {
193
194
  const { formatter } = require("../sdk-log-formatter.js");
194
- this.emitter.emit(events.log.narration, formatter.getPrefix("disconnect") + " " + theme.yellow.bold("Exiting") + theme.dim("..."), true);
195
+ this.emitter.emit(
196
+ events.log.narration,
197
+ formatter.getPrefix("disconnect") +
198
+ " " +
199
+ theme.yellow.bold("Exiting") +
200
+ theme.dim("..."),
201
+ true,
202
+ );
195
203
 
196
204
  // Clean up redraw interval
197
205
  if (this.redraw && this.redraw.cleanup) {
@@ -240,9 +248,7 @@ class TestDriverAgent extends EventEmitter2 {
240
248
  if (errorContext) {
241
249
  this.emitter.emit(events.error.fatal, errorContext);
242
250
  } else {
243
- this.emitter.emit(
244
- events.error.fatal,error,
245
- );
251
+ this.emitter.emit(events.error.fatal, error);
246
252
  }
247
253
 
248
254
  if (skipPostrun) {
@@ -436,15 +442,12 @@ class TestDriverAgent extends EventEmitter2 {
436
442
  let mousePosition = await this.system.getMousePosition();
437
443
  let activeWindow = await this.system.activeWin();
438
444
 
439
- let response = await this.sdk.req(
440
- "check",
441
- {
442
- tasks: this.tasks,
443
- images,
444
- mousePosition,
445
- activeWindow,
446
- }
447
- );
445
+ let response = await this.sdk.req("check", {
446
+ tasks: this.tasks,
447
+ images,
448
+ mousePosition,
449
+ activeWindow,
450
+ });
448
451
 
449
452
  // Use log.log (not markdown.static) so output goes through console spy to sandbox
450
453
  this.emitter.emit(events.log.log, response.data);
@@ -878,7 +881,7 @@ commands:
878
881
  currentTask,
879
882
  dry = false,
880
883
  validateAndLoop = false,
881
- shouldSave = true
884
+ shouldSave = true,
882
885
  ) {
883
886
  // Check if execution has been stopped
884
887
  if (this.stopped) {
@@ -901,15 +904,12 @@ commands:
901
904
 
902
905
  this.lastScreenshot = await this.system.captureScreenBase64();
903
906
 
904
- let message = await this.sdk.req(
905
- "input",
906
- {
907
- input: currentTask,
908
- mousePosition: await this.system.getMousePosition(),
909
- activeWindow: await this.system.activeWin(),
910
- image: this.lastScreenshot,
911
- }
912
- );
907
+ let message = await this.sdk.req("input", {
908
+ input: currentTask,
909
+ mousePosition: await this.system.getMousePosition(),
910
+ activeWindow: await this.system.activeWin(),
911
+ image: this.lastScreenshot,
912
+ });
913
913
 
914
914
  this.emitter.emit(events.log.log, message.data);
915
915
 
@@ -988,9 +988,9 @@ commands:
988
988
  const generateDir = path.join(this.workingDir, "testdriver", "generate");
989
989
  if (!fs.existsSync(generateDir)) {
990
990
  fs.mkdirSync(generateDir);
991
- console.log("Created generate directory:", generateDir);
991
+ logger.log("Created generate directory:", generateDir);
992
992
  } else {
993
- console.log("Generate directory already exists:", generateDir);
993
+ logger.log("Generate directory already exists:", generateDir);
994
994
  }
995
995
 
996
996
  let list = testPrompt.steps;
@@ -1626,8 +1626,8 @@ ${regression}
1626
1626
 
1627
1627
  // Returns the path to the last sandbox file
1628
1628
  getLastSandboxFilePath() {
1629
- const testdriverDir = path.join(process.cwd(), '.testdriver');
1630
- return path.join(testdriverDir, 'last-sandbox');
1629
+ const testdriverDir = path.join(process.cwd(), ".testdriver");
1630
+ return path.join(testdriverDir, "last-sandbox");
1631
1631
  }
1632
1632
 
1633
1633
  // Returns full sandbox info from last-sandbox file (no timeout - let API validate)
@@ -1648,7 +1648,7 @@ ${regression}
1648
1648
 
1649
1649
  return {
1650
1650
  sandboxId: sandboxInfo.sandboxId || sandboxInfo.instanceId || null,
1651
- os: sandboxInfo.os || 'linux',
1651
+ os: sandboxInfo.os || "linux",
1652
1652
  ami: sandboxInfo.ami || null,
1653
1653
  instanceType: sandboxInfo.instanceType || null,
1654
1654
  timestamp: sandboxInfo.timestamp || null,
@@ -1663,7 +1663,7 @@ ${regression}
1663
1663
  // Returns sandboxId to use if AMI/instance type match current requirements
1664
1664
  getRecentSandboxId() {
1665
1665
  const sandboxInfo = this.getLastSandboxId();
1666
-
1666
+
1667
1667
  if (!sandboxInfo || !sandboxInfo.sandboxId) {
1668
1668
  return null;
1669
1669
  }
@@ -1690,13 +1690,13 @@ ${regression}
1690
1690
  saveLastSandboxId(sandboxId, osType = "linux") {
1691
1691
  const lastSandboxFile = this.getLastSandboxFilePath();
1692
1692
  const testdriverDir = path.dirname(lastSandboxFile);
1693
-
1693
+
1694
1694
  try {
1695
1695
  // Ensure .testdriver directory exists
1696
1696
  if (!fs.existsSync(testdriverDir)) {
1697
1697
  fs.mkdirSync(testdriverDir, { recursive: true });
1698
1698
  }
1699
-
1699
+
1700
1700
  const sandboxInfo = {
1701
1701
  sandboxId: sandboxId,
1702
1702
  os: osType,
@@ -1757,15 +1757,9 @@ ${regression}
1757
1757
  // Also clear this.sandboxId to prevent reconnection attempts
1758
1758
  this.sandboxId = null;
1759
1759
  if (!this.config.CI && !this.newSandbox) {
1760
- this.emitter.emit(
1761
- events.log.log,
1762
- theme.dim("--`new` flag detected, will create a new sandbox"),
1763
- );
1760
+ this.emitter.emit(events.log.log, theme.dim("Creating a new sandbox"));
1764
1761
  } else if (this.newSandbox) {
1765
- this.emitter.emit(
1766
- events.log.log,
1767
- theme.dim("--new-sandbox flag detected, will create a new sandbox"),
1768
- );
1762
+ this.emitter.emit(events.log.log, theme.dim("Creating a new sandbox"));
1769
1763
  }
1770
1764
  }
1771
1765
 
@@ -1802,7 +1796,7 @@ ${regression}
1802
1796
  theme.dim(`using recent sandbox: ${recentId}`),
1803
1797
  );
1804
1798
  this.sandboxId = recentId;
1805
-
1799
+
1806
1800
  try {
1807
1801
  let instance = await this.connectToSandboxDirect(
1808
1802
  this.sandboxId,
@@ -1850,13 +1844,17 @@ ${regression}
1850
1844
  console.error("Failed to reconnect to sandbox:", error);
1851
1845
  }
1852
1846
  }
1853
-
1847
+
1854
1848
  // Create new sandbox (either because createNew is true, or no existing sandbox to connect to)
1855
1849
  if (!this.instance) {
1856
1850
  const { formatter } = require("../sdk-log-formatter.js");
1857
1851
  this.emitter.emit(
1858
1852
  events.log.narration,
1859
- formatter.getPrefix("connect") + " " + theme.green.bold("Creating") + " " + theme.cyan(`new sandbox...`),
1853
+ formatter.getPrefix("connect") +
1854
+ " " +
1855
+ theme.green.bold("Creating") +
1856
+ " " +
1857
+ theme.cyan(`new sandbox...`),
1860
1858
  );
1861
1859
  // We don't have resiliency/retries baked in, so let's at least give it 1 attempt
1862
1860
  // to see if that fixes the issue.
@@ -1869,11 +1867,12 @@ ${regression}
1869
1867
  });
1870
1868
 
1871
1869
  // Extract the sandbox ID from the newly created sandbox
1872
- this.sandboxId = newSandbox?.sandbox?.sandboxId || newSandbox?.sandbox?.instanceId;
1873
-
1870
+ this.sandboxId =
1871
+ newSandbox?.sandbox?.sandboxId || newSandbox?.sandbox?.instanceId;
1872
+
1874
1873
  // Use the configured sandbox OS type
1875
1874
  this.saveLastSandboxId(this.sandboxId, this.sandboxOs);
1876
-
1875
+
1877
1876
  let instance = await this.connectToSandboxDirect(
1878
1877
  this.sandboxId,
1879
1878
  true, // always persist by default
@@ -2002,7 +2001,6 @@ ${regression}
2002
2001
  }
2003
2002
 
2004
2003
  async renderSandbox(instance, headless = false) {
2005
-
2006
2004
  if (!headless) {
2007
2005
  let url;
2008
2006
 
@@ -2019,7 +2017,7 @@ ${regression}
2019
2017
  "/vnc_lite.html?token=V3b8wG9";
2020
2018
  } else {
2021
2019
  // If we don't have URL or IP, we can't render
2022
- console.warn("renderSandbox: Missing URL and IP in instance", instance);
2020
+ logger.warn("renderSandbox: Missing URL and IP in instance", instance);
2023
2021
  return;
2024
2022
  }
2025
2023
 
@@ -2056,7 +2054,13 @@ Please check your network connection, TD_API_KEY, or the service status.`,
2056
2054
  }
2057
2055
 
2058
2056
  const { formatter } = require("../sdk-log-formatter.js");
2059
- this.emitter.emit(events.log.narration, formatter.getPrefix("connect") + " " + theme.green.bold("Authenticating") + theme.dim("..."));
2057
+ this.emitter.emit(
2058
+ events.log.narration,
2059
+ formatter.getPrefix("connect") +
2060
+ " " +
2061
+ theme.green.bold("Authenticating") +
2062
+ theme.dim("..."),
2063
+ );
2060
2064
  let ableToAuth = await this.sandbox.auth(this.config.TD_API_KEY);
2061
2065
 
2062
2066
  if (!ableToAuth) {
@@ -2070,7 +2074,14 @@ Please check your network connection, TD_API_KEY, or the service status.`,
2070
2074
 
2071
2075
  async connectToSandboxDirect(sandboxId, persist = false, keepAlive = null) {
2072
2076
  const { formatter } = require("../sdk-log-formatter.js");
2073
- this.emitter.emit(events.log.narration, formatter.getPrefix("connect") + " " + theme.green.bold("Connecting") + " " + theme.cyan(`to sandbox...`));
2077
+ this.emitter.emit(
2078
+ events.log.narration,
2079
+ formatter.getPrefix("connect") +
2080
+ " " +
2081
+ theme.green.bold("Connecting") +
2082
+ " " +
2083
+ theme.cyan(`to sandbox...`),
2084
+ );
2074
2085
  let reply = await this.sandbox.connect(sandboxId, persist, keepAlive);
2075
2086
 
2076
2087
  // reply includes { success, url, sandbox: {...} }
@@ -2112,15 +2123,18 @@ Please check your network connection, TD_API_KEY, or the service status.`,
2112
2123
  let response = await this.sandbox.send(sandboxConfig, 60000 * 8);
2113
2124
 
2114
2125
  // Check if queued (all slots in use)
2115
- if (response.type === 'create.queued') {
2126
+ if (response.type === "create.queued") {
2116
2127
  this.emitter.emit(
2117
2128
  events.log.narration,
2118
- formatter.getPrefix("queue") + " " + theme.yellow.bold("Waiting") + " " +
2119
- theme.dim(response.message),
2129
+ formatter.getPrefix("queue") +
2130
+ " " +
2131
+ theme.yellow.bold("Waiting") +
2132
+ " " +
2133
+ theme.dim(response.message),
2120
2134
  );
2121
2135
 
2122
2136
  // Wait then retry
2123
- await new Promise(resolve => setTimeout(resolve, retryDelay));
2137
+ await new Promise((resolve) => setTimeout(resolve, retryDelay));
2124
2138
  continue;
2125
2139
  }
2126
2140
 
@@ -2139,10 +2153,14 @@ Please check your network connection, TD_API_KEY, or the service status.`,
2139
2153
  // should be start of new session
2140
2154
  // If sandbox is connected, get system info; otherwise pass empty objects
2141
2155
  const isSandboxConnected = this.sandbox.apiSocketConnected;
2142
-
2156
+
2143
2157
  const sessionRes = await this.sdk.req("session/start", {
2144
- systemInformationOsInfo: isSandboxConnected ? await this.system.getSystemInformationOsInfo() : {},
2145
- mousePosition: isSandboxConnected ? await this.system.getMousePosition() : {},
2158
+ systemInformationOsInfo: isSandboxConnected
2159
+ ? await this.system.getSystemInformationOsInfo()
2160
+ : {},
2161
+ mousePosition: isSandboxConnected
2162
+ ? await this.system.getMousePosition()
2163
+ : {},
2146
2164
  activeWindow: isSandboxConnected ? await this.system.activeWin() : {},
2147
2165
  });
2148
2166
 
@@ -2153,7 +2171,7 @@ Please check your network connection, TD_API_KEY, or the service status.`,
2153
2171
  }
2154
2172
 
2155
2173
  this.session.set(sessionRes.data.id);
2156
-
2174
+
2157
2175
  // Set Sentry session trace context for distributed tracing
2158
2176
  // This links CLI errors/logs to the same trace as API calls
2159
2177
  try {
@@ -1,6 +1,4 @@
1
- const path = require("path");
2
1
  const { Args, Flags } = require("@oclif/core");
3
- const { events } = require("./events.js");
4
2
 
5
3
  /**
6
4
  * Creates command definitions using oclif format as the single source of truth
@@ -8,265 +6,27 @@ const { events } = require("./events.js");
8
6
  * @returns {Object} Command definitions object in oclif format
9
7
  */
10
8
  function createCommandDefinitions(agent) {
11
- const normalizeFilePath = (file) => {
12
- if (!file) {
13
- file = "testdriver/testdriver.yaml";
14
- }
15
-
16
- file = path.join(agent.workingDir, file);
17
- if (!file.endsWith(".yaml") && !file.endsWith(".yml")) {
18
- file += ".yaml";
19
- }
20
-
21
- return file;
22
- };
23
-
24
9
  return {
25
- run: {
26
- description: "Run a test file",
27
- args: {
28
- file: Args.string({
29
- description: "Test file to run",
30
- default: "testdriver/testdriver.yaml",
31
- required: false,
32
- }),
33
- },
34
- flags: {
35
- heal: Flags.boolean({
36
- description: "Enable automatic error recovery mode",
37
- default: false,
38
- }),
39
- write: Flags.boolean({
40
- description: "Save AI modifications to the test file",
41
- default: false,
42
- }),
43
- headless: Flags.boolean({
44
- description: "Run in headless mode (no GUI)",
45
- default: false,
46
- }),
47
- new: Flags.boolean({
48
- description:
49
- "Create a new sandbox instead of reconnecting to an existing one",
50
- default: false,
51
- }),
52
- "sandbox-ami": Flags.string({
53
- description: "Specify AMI ID for sandbox instance (e.g., ami-1234)",
54
- }),
55
- "sandbox-instance": Flags.string({
56
- description: "Specify EC2 instance type for sandbox (e.g., i3.metal)",
57
- }),
58
- ip: Flags.string({
59
- description:
60
- "Connect directly to a sandbox at the specified IP address",
61
- }),
62
- summary: Flags.string({
63
- description: "Specify output file for summarize results",
64
- }),
65
- junit: Flags.string({
66
- description: "Generate JUnit XML test report to specified file",
67
- default: false,
68
- }),
69
- os: Flags.string({
70
- description: "Operating system for the sandbox (windows or linux)",
71
- options: ["windows", "linux"],
72
- default: "linux",
73
- }),
74
- },
75
- handler: async (args, flags) => {
76
- // Use --path flag if provided, otherwise fall back to args.file
77
- const file = normalizeFilePath(args.file);
78
- const testStartTime = Date.now();
79
-
80
- try {
81
- await agent.runLifecycle("prerun");
82
- // When run() is called through run.js CLI command, shouldExit should be true
83
- const shouldExit = agent.cliArgs?.command === "run";
84
- await agent.run(file, flags.write, shouldExit);
85
-
86
- const testEndTime = Date.now();
87
- const testDuration = testEndTime - testStartTime;
88
-
89
- // Emit test success event for the entire test execution
90
- agent.emitter.emit(events.test.success, {
91
- filePath: file,
92
- duration: testDuration,
93
- timestamp: testEndTime,
94
- });
95
- } catch (error) {
96
- const testEndTime = Date.now();
97
- const testDuration = testEndTime - testStartTime;
98
-
99
- // Emit test error event for the entire test execution
100
- agent.emitter.emit(events.test.error, {
101
- filePath: file,
102
- error: error.message,
103
- duration: testDuration,
104
- timestamp: testEndTime,
105
- });
106
-
107
- throw error; // Re-throw to maintain existing error handling
108
- }
109
- },
110
- },
111
-
112
- edit: {
113
- description: "Edit a test file interactively",
114
- args: {
115
- file: Args.string({
116
- description: "Test file to edit",
117
- default: "testdriver/testdriver.yaml",
118
- required: false,
119
- }),
120
- },
121
- flags: {
122
- heal: Flags.boolean({
123
- description: "Enable automatic error recovery mode",
124
- default: false,
125
- }),
126
- headless: Flags.boolean({
127
- description: "Run in headless mode",
128
- default: false,
129
- }),
130
- new: Flags.boolean({
131
- description:
132
- "Create a new sandbox instead of reconnecting to an existing one",
133
- default: false,
134
- }),
135
- "sandbox-ami": Flags.string({
136
- description: "Specify AMI ID for sandbox instance (e.g., ami-1234)",
137
- }),
138
- "sandbox-instance": Flags.string({
139
- description: "Specify EC2 instance type for sandbox (e.g., i3.metal)",
140
- }),
141
- ip: Flags.string({
142
- description:
143
- "Connect directly to a sandbox at the specified IP address",
144
- }),
145
- summary: Flags.string({
146
- description: "Specify output file for summarize results",
147
- }),
148
- os: Flags.string({
149
- description: "Operating system for the sandbox (windows or linux)",
150
- options: ["windows", "linux"],
151
- default: "windows",
152
- }),
153
- },
154
- handler: async () => {
155
- // Edit mode is handled by the CLI interface via factory.js
156
- // This handler should not be called directly
157
- throw new Error("Edit mode should be handled by CLI interface");
158
- },
159
- },
160
-
161
- // Interactive commands that can be used within edit mode
162
- explore: {
163
- description: "Explore and interact with the current environment",
164
- args: {
165
- prompt: Args.string({
166
- description: "What you want to explore or do",
167
- required: false,
168
- }),
169
- },
170
- flags: {},
171
- handler: async (args) => {
172
- await agent.exploratoryLoop(args.prompt || "", false, true, true);
173
- },
174
- },
175
-
176
- save: {
177
- description: "Save the current test script",
178
- args: {
179
- filename: Args.string({
180
- description: "Optional filename to save to",
181
- required: false,
182
- }),
183
- },
184
- flags: {},
185
- handler: async (args) => {
186
- await agent.save(args.filename);
187
- },
188
- },
189
-
190
- exit: {
191
- description: "Exit the TestDriver agent",
192
- args: {},
193
- flags: {},
194
- handler: async () => {
195
- await agent.exit(false);
196
- },
197
- },
198
-
199
- help: {
200
- description: "Show help information",
201
- args: {},
202
- flags: {},
203
- handler: async () => {
204
- agent.showHelp();
205
- },
206
- },
207
-
208
- version: {
209
- description: "Show version information",
10
+ init: {
11
+ description: "Initialize a new TestDriver project with Vitest SDK examples",
210
12
  args: {},
211
13
  flags: {},
212
14
  handler: async () => {
213
- const packageJson = require("../package.json");
214
- console.log(`TestDriver.ai v${packageJson.version}`);
215
- },
216
- },
217
-
218
- generate: {
219
- description: "Generate test files based on current screen state",
220
- args: {
221
- prompt: Args.string({
222
- description: "Multi-line text prompt describing what to generate",
223
- required: false,
224
- }),
225
- },
226
- flags: {
227
- count: Flags.integer({
228
- description: "Number of test files to generate",
229
- default: 3,
230
- }),
231
- headless: Flags.boolean({
232
- description: "Run in headless mode (no GUI)",
233
- default: false,
234
- }),
235
- new: Flags.boolean({
236
- description:
237
- "Create a new sandbox instead of reconnecting to an existing one",
238
- default: false,
239
- }),
240
- "sandbox-ami": Flags.string({
241
- description: "Specify AMI ID for sandbox instance (e.g., ami-1234)",
242
- }),
243
- "sandbox-instance": Flags.string({
244
- description: "Specify EC2 instance type for sandbox (e.g., i3.metal)",
245
- }),
246
- ip: Flags.string({
247
- description:
248
- "Connect directly to a sandbox at the specified IP address",
249
- }),
250
- os: Flags.string({
251
- description: "Operating system for the sandbox (windows or linux)",
252
- options: ["windows", "linux"],
253
- default: "linux",
254
- }),
255
- },
256
- handler: async (args, flags) => {
257
- // Call generate with the count and prompt
258
- await agent.generate(flags.count || 3, args.prompt);
15
+ // This handler is special - it doesn't need an agent instance
16
+ // It just scaffolds files, so it will be handled by the CLI command
17
+ throw new Error("Init mode should be handled by CLI interface");
259
18
  },
260
19
  },
261
20
 
262
- init: {
263
- description: "Initialize a new TestDriver project with Vitest SDK examples",
21
+ "setup": {
22
+ description:
23
+ "Set up TestDriver skills, agents, and MCP server for Claude Code",
264
24
  args: {},
265
25
  flags: {},
266
26
  handler: async () => {
267
- // This handler is special - it doesn't need an agent instance
268
- // It just scaffolds files, so it will be handled by the CLI command
269
- throw new Error("Init mode should be handled by CLI interface");
27
+ throw new Error(
28
+ "setup should be handled by CLI interface",
29
+ );
270
30
  },
271
31
  },
272
32
  };
@@ -3,6 +3,7 @@ const http = require("http");
3
3
  const path = require("path");
4
4
  const fs = require("fs");
5
5
  const { eventsArray } = require("../events.js");
6
+ const logger = require("./logger");
6
7
 
7
8
  let server = null;
8
9
  let wss = null;
@@ -131,7 +132,7 @@ function stopDebugger() {
131
132
  }
132
133
 
133
134
  clients.clear();
134
- console.log("Debugger server stopped");
135
+ logger.log("Debugger server stopped");
135
136
  }
136
137
 
137
138
  module.exports = {
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Logger utility for TestDriver
3
+ *
4
+ * By default, outputs to stdout (console.log).
5
+ * When TD_STDIO=stderr is set, outputs to stderr (console.error).
6
+ * This is necessary for MCP servers which use stdout exclusively for JSON-RPC.
7
+ */
8
+
9
+ const useStderr = process.env.TD_STDIO === 'stderr';
10
+
11
+ /**
12
+ * Log a message - uses stdout by default, stderr if TD_STDIO=stderr
13
+ * @param {...any} args - Arguments to log
14
+ */
15
+ function log(...args) {
16
+ if (useStderr) {
17
+ console.error(...args);
18
+ } else {
19
+ console.log(...args);
20
+ }
21
+ }
22
+
23
+ /**
24
+ * Log an error - always uses stderr
25
+ * @param {...any} args - Arguments to log
26
+ */
27
+ function error(...args) {
28
+ console.error(...args);
29
+ }
30
+
31
+ /**
32
+ * Log a warning - uses stdout by default, stderr if TD_STDIO=stderr
33
+ * @param {...any} args - Arguments to log
34
+ */
35
+ function warn(...args) {
36
+ if (useStderr) {
37
+ console.error(...args);
38
+ } else {
39
+ console.warn(...args);
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Check if logger is configured to use stderr
45
+ * @returns {boolean}
46
+ */
47
+ function isStderrMode() {
48
+ return useStderr;
49
+ }
50
+
51
+ module.exports = {
52
+ log,
53
+ error,
54
+ warn,
55
+ isStderrMode,
56
+ };