@testdriverai/agent 7.8.0-canary.10

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 (528) hide show
  1. package/.claude/settings.local.json +7 -0
  2. package/.env.example +4 -0
  3. package/.prettierignore +4 -0
  4. package/.prettierrc +1 -0
  5. package/CHANGELOG.md +953 -0
  6. package/README.md +81 -0
  7. package/agent/events.js +135 -0
  8. package/agent/index.js +2450 -0
  9. package/agent/interface.js +35 -0
  10. package/agent/lib/analytics.js +22 -0
  11. package/agent/lib/censorship.js +75 -0
  12. package/agent/lib/commander.js +246 -0
  13. package/agent/lib/commands.js +1684 -0
  14. package/agent/lib/config.js +60 -0
  15. package/agent/lib/generator.js +91 -0
  16. package/agent/lib/http.js +144 -0
  17. package/agent/lib/logger.js +56 -0
  18. package/agent/lib/outputs.js +29 -0
  19. package/agent/lib/parser.js +209 -0
  20. package/agent/lib/redraw.js +386 -0
  21. package/agent/lib/resources/cursor-2.png +0 -0
  22. package/agent/lib/sandbox.js +1104 -0
  23. package/agent/lib/sdk.js +633 -0
  24. package/agent/lib/session.js +25 -0
  25. package/agent/lib/source-mapper.js +342 -0
  26. package/agent/lib/subimage/index.js +77 -0
  27. package/agent/lib/subimage/opencv.js +69 -0
  28. package/agent/lib/system.js +204 -0
  29. package/agent/lib/theme.js +14 -0
  30. package/agent/lib/valid-version.js +21 -0
  31. package/agent/lib/validation.js +169 -0
  32. package/ai/.claude-plugin/plugin.json +9 -0
  33. package/ai/agents/testdriver.md +638 -0
  34. package/ai/skills/testdriver-ai/SKILL.md +204 -0
  35. package/ai/skills/testdriver-assert/SKILL.md +315 -0
  36. package/ai/skills/testdriver-aws-setup/SKILL.md +448 -0
  37. package/ai/skills/testdriver-cache/SKILL.md +221 -0
  38. package/ai/skills/testdriver-caching/SKILL.md +124 -0
  39. package/ai/skills/testdriver-captcha/SKILL.md +158 -0
  40. package/ai/skills/testdriver-ci-cd/SKILL.md +602 -0
  41. package/ai/skills/testdriver-click/SKILL.md +286 -0
  42. package/ai/skills/testdriver-client/SKILL.md +477 -0
  43. package/ai/skills/testdriver-cloud/SKILL.md +119 -0
  44. package/ai/skills/testdriver-customizing-devices/SKILL.md +319 -0
  45. package/ai/skills/testdriver-dashcam/SKILL.md +418 -0
  46. package/ai/skills/testdriver-debugging-with-screenshots/SKILL.md +401 -0
  47. package/ai/skills/testdriver-device-config/SKILL.md +317 -0
  48. package/ai/skills/testdriver-double-click/SKILL.md +102 -0
  49. package/ai/skills/testdriver-elements/SKILL.md +605 -0
  50. package/ai/skills/testdriver-enterprise/SKILL.md +114 -0
  51. package/ai/skills/testdriver-errors/SKILL.md +246 -0
  52. package/ai/skills/testdriver-events/SKILL.md +356 -0
  53. package/ai/skills/testdriver-examples/SKILL.md +7 -0
  54. package/ai/skills/testdriver-exec/SKILL.md +317 -0
  55. package/ai/skills/testdriver-find/SKILL.md +829 -0
  56. package/ai/skills/testdriver-focus-application/SKILL.md +293 -0
  57. package/ai/skills/testdriver-generating-tests/SKILL.md +36 -0
  58. package/ai/skills/testdriver-hover/SKILL.md +278 -0
  59. package/ai/skills/testdriver-locating-elements/SKILL.md +71 -0
  60. package/ai/skills/testdriver-making-assertions/SKILL.md +32 -0
  61. package/ai/skills/testdriver-mcp/SKILL.md +7 -0
  62. package/ai/skills/testdriver-mcp-workflow/SKILL.md +410 -0
  63. package/ai/skills/testdriver-mouse-down/SKILL.md +161 -0
  64. package/ai/skills/testdriver-mouse-up/SKILL.md +164 -0
  65. package/ai/skills/testdriver-parse/SKILL.md +236 -0
  66. package/ai/skills/testdriver-performing-actions/SKILL.md +54 -0
  67. package/ai/skills/testdriver-press-keys/SKILL.md +348 -0
  68. package/ai/skills/testdriver-provision/SKILL.md +331 -0
  69. package/ai/skills/testdriver-quickstart/SKILL.md +144 -0
  70. package/ai/skills/testdriver-redraw/SKILL.md +214 -0
  71. package/ai/skills/testdriver-reusable-code/SKILL.md +249 -0
  72. package/ai/skills/testdriver-right-click/SKILL.md +123 -0
  73. package/ai/skills/testdriver-running-tests/SKILL.md +185 -0
  74. package/ai/skills/testdriver-screenshot/SKILL.md +248 -0
  75. package/ai/skills/testdriver-screenshots/SKILL.md +184 -0
  76. package/ai/skills/testdriver-scroll/SKILL.md +335 -0
  77. package/ai/skills/testdriver-secrets/SKILL.md +115 -0
  78. package/ai/skills/testdriver-self-hosted/SKILL.md +65 -0
  79. package/ai/skills/testdriver-test-writer/SKILL.md +448 -0
  80. package/ai/skills/testdriver-testdriver/SKILL.md +628 -0
  81. package/ai/skills/testdriver-testdriver-mechanic/SKILL.md +165 -0
  82. package/ai/skills/testdriver-type/SKILL.md +357 -0
  83. package/ai/skills/testdriver-variables/SKILL.md +111 -0
  84. package/ai/skills/testdriver-wait/SKILL.md +50 -0
  85. package/ai/skills/testdriver-waiting-for-elements/SKILL.md +90 -0
  86. package/ai/skills/testdriver-what-is-testdriver/SKILL.md +54 -0
  87. package/bin/testdriverai.js +22 -0
  88. package/debugger/bg.png +0 -0
  89. package/debugger/icon.png +0 -0
  90. package/debugger/index.html +469 -0
  91. package/debugger/td.png +0 -0
  92. package/debugger/tray-buffered.png +0 -0
  93. package/debugger/tray.png +0 -0
  94. package/docs/GITHUB_COMMENTS.md +330 -0
  95. package/docs/GITHUB_COMMENTS_ANNOUNCEMENT.md +167 -0
  96. package/docs/QUICK-START-GITHUB-COMMENTS.md +84 -0
  97. package/docs/TEST-GITHUB-COMMENTS.md +129 -0
  98. package/docs/_data/examples-manifest.json +177 -0
  99. package/docs/_data/examples-manifest.schema.json +41 -0
  100. package/docs/_scripts/extract-example-urls.js +165 -0
  101. package/docs/_scripts/generate-examples.js +560 -0
  102. package/docs/_scripts/generate-skills.js +154 -0
  103. package/docs/_scripts/link-replacer.js +164 -0
  104. package/docs/_scripts/upload-docs-to-openai.js +284 -0
  105. package/docs/changelog.mdx +161 -0
  106. package/docs/claude-mcp-plugin.mdx +160 -0
  107. package/docs/docs.json +442 -0
  108. package/docs/github-integration-setup.md +266 -0
  109. package/docs/guide/best-practices-polling.mdx +174 -0
  110. package/docs/images/content/account/newprojectsettings.png +0 -0
  111. package/docs/images/content/account/projectpage.png +0 -0
  112. package/docs/images/content/account/projectreplays.png +0 -0
  113. package/docs/images/content/account/team-manage.png +0 -0
  114. package/docs/images/content/account/teampage.png +0 -0
  115. package/docs/images/content/extension/cursor.svg +1 -0
  116. package/docs/images/content/extension/vscode.svg +57 -0
  117. package/docs/images/content/extension/windsurf.svg +3 -0
  118. package/docs/images/content/parse/output.png +0 -0
  119. package/docs/images/content/self-hosted/launchtemplateid.png +0 -0
  120. package/docs/images/content/side-by-side.png +0 -0
  121. package/docs/images/content/vscode/ide-full.png +0 -0
  122. package/docs/images/content/vscode/running.png +0 -0
  123. package/docs/images/content/vscode/v7-chat.png +0 -0
  124. package/docs/images/content/vscode/v7-choose-agent.png +0 -0
  125. package/docs/images/content/vscode/v7-full.png +0 -0
  126. package/docs/images/content/vscode/v7-onboarding.png +0 -0
  127. package/docs/images/content/vscode/vscode-2-assert.png +0 -0
  128. package/docs/images/content/vscode/vscode-agent-preview.png +0 -0
  129. package/docs/images/content/vscode/vscode-copilot-ask.png +0 -0
  130. package/docs/images/content/vscode/vscode-file-creation.png +0 -0
  131. package/docs/images/content/vscode/vscode-install.png +0 -0
  132. package/docs/images/content/vscode/vscode-overview.png +0 -0
  133. package/docs/images/content/vscode/vscode-setup-walkthrough.png +0 -0
  134. package/docs/images/content/vscode/vscode-stopchat.png +0 -0
  135. package/docs/images/content/vscode/vscode-stoptest.png +0 -0
  136. package/docs/images/content/vscode/vscode-tdservice.png +0 -0
  137. package/docs/images/content/vscode/vscode-test-output.png +0 -0
  138. package/docs/images/content/vscode/vscode-testhistory.png +0 -0
  139. package/docs/images/content/vscode/vscode-testpane-runtests.png +0 -0
  140. package/docs/images/content/vscode/vscode-testpane.png +0 -0
  141. package/docs/images/template/dark.png +0 -0
  142. package/docs/images/template/icon.png +0 -0
  143. package/docs/images/template/light.png +0 -0
  144. package/docs/snippets/calendar-link.mdx +4 -0
  145. package/docs/snippets/gitignore-warning.mdx +7 -0
  146. package/docs/snippets/lifecycle-warning.mdx +6 -0
  147. package/docs/snippets/test-prereqs.mdx +12 -0
  148. package/docs/snippets/tests/assert-replay.mdx +7 -0
  149. package/docs/snippets/tests/assert-yaml.mdx +8 -0
  150. package/docs/snippets/tests/exec-js-replay.mdx +7 -0
  151. package/docs/snippets/tests/exec-js-yaml.mdx +32 -0
  152. package/docs/snippets/tests/exec-shell-replay.mdx +7 -0
  153. package/docs/snippets/tests/exec-shell-yaml.mdx +15 -0
  154. package/docs/snippets/tests/hover-image-replay.mdx +7 -0
  155. package/docs/snippets/tests/hover-image-yaml.mdx +17 -0
  156. package/docs/snippets/tests/hover-text-replay.mdx +7 -0
  157. package/docs/snippets/tests/hover-text-with-description-replay.mdx +7 -0
  158. package/docs/snippets/tests/hover-text-with-description-yaml.mdx +24 -0
  159. package/docs/snippets/tests/hover-text-yaml.mdx +14 -0
  160. package/docs/snippets/tests/match-image-replay.mdx +7 -0
  161. package/docs/snippets/tests/match-image-yaml.mdx +17 -0
  162. package/docs/snippets/tests/press-keys-replay.mdx +7 -0
  163. package/docs/snippets/tests/press-keys-yaml.mdx +36 -0
  164. package/docs/snippets/tests/remember-replay.mdx +7 -0
  165. package/docs/snippets/tests/remember-yaml.mdx +28 -0
  166. package/docs/snippets/tests/scroll-replay.mdx +7 -0
  167. package/docs/snippets/tests/scroll-until-image-replay.mdx +7 -0
  168. package/docs/snippets/tests/scroll-until-image-yaml.mdx +14 -0
  169. package/docs/snippets/tests/scroll-until-text-replay.mdx +7 -0
  170. package/docs/snippets/tests/scroll-until-text-yaml.mdx +17 -0
  171. package/docs/snippets/tests/scroll-yaml.mdx +30 -0
  172. package/docs/snippets/tests/type-repeated-replay.mdx +7 -0
  173. package/docs/snippets/tests/type-repeated-yaml.mdx +22 -0
  174. package/docs/snippets/tests/type-replay.mdx +7 -0
  175. package/docs/snippets/tests/type-yaml.mdx +28 -0
  176. package/docs/snippets/tests/wait-for-image-replay.mdx +7 -0
  177. package/docs/snippets/tests/wait-for-image-yaml.mdx +18 -0
  178. package/docs/snippets/tests/wait-for-text-replay.mdx +7 -0
  179. package/docs/snippets/tests/wait-for-text-yaml.mdx +18 -0
  180. package/docs/snippets/tests/wait-replay.mdx +7 -0
  181. package/docs/snippets/tests/wait-yaml.mdx +13 -0
  182. package/docs/styles.css +65 -0
  183. package/docs/v6/account/dashboard.mdx +16 -0
  184. package/docs/v6/account/enterprise.mdx +110 -0
  185. package/docs/v6/account/pricing.mdx +33 -0
  186. package/docs/v6/account/projects.mdx +33 -0
  187. package/docs/v6/account/team.mdx +35 -0
  188. package/docs/v6/action/ami.mdx +109 -0
  189. package/docs/v6/action/performance.mdx +105 -0
  190. package/docs/v6/action/secrets.mdx +93 -0
  191. package/docs/v6/apps/chrome-extensions.mdx +48 -0
  192. package/docs/v6/apps/desktop-apps.mdx +93 -0
  193. package/docs/v6/apps/mobile-apps.mdx +26 -0
  194. package/docs/v6/apps/static-websites.mdx +54 -0
  195. package/docs/v6/apps/tauri-apps.mdx +361 -0
  196. package/docs/v6/bugs/jira.mdx +232 -0
  197. package/docs/v6/cli/overview.mdx +66 -0
  198. package/docs/v6/commands/assert.mdx +45 -0
  199. package/docs/v6/commands/exec.mdx +276 -0
  200. package/docs/v6/commands/focus-application.mdx +44 -0
  201. package/docs/v6/commands/hover-image.mdx +69 -0
  202. package/docs/v6/commands/hover-text.mdx +47 -0
  203. package/docs/v6/commands/if.mdx +53 -0
  204. package/docs/v6/commands/match-image.mdx +67 -0
  205. package/docs/v6/commands/press-keys.mdx +87 -0
  206. package/docs/v6/commands/remember.mdx +49 -0
  207. package/docs/v6/commands/run.mdx +44 -0
  208. package/docs/v6/commands/scroll-until-image.mdx +66 -0
  209. package/docs/v6/commands/scroll-until-text.mdx +60 -0
  210. package/docs/v6/commands/scroll.mdx +69 -0
  211. package/docs/v6/commands/type.mdx +45 -0
  212. package/docs/v6/commands/wait-for-image.mdx +54 -0
  213. package/docs/v6/commands/wait-for-text.mdx +48 -0
  214. package/docs/v6/commands/wait.mdx +45 -0
  215. package/docs/v6/exporting/junit.mdx +218 -0
  216. package/docs/v6/exporting/playwright.mdx +197 -0
  217. package/docs/v6/features/auto-healing.mdx +144 -0
  218. package/docs/v6/features/generation.mdx +116 -0
  219. package/docs/v6/features/parallel-testing.mdx +151 -0
  220. package/docs/v6/features/reusable-snippets.mdx +131 -0
  221. package/docs/v6/features/selectorless.mdx +80 -0
  222. package/docs/v6/features/visual-assertions.mdx +139 -0
  223. package/docs/v6/getting-started/ci.mdx +146 -0
  224. package/docs/v6/getting-started/cli.mdx +91 -0
  225. package/docs/v6/getting-started/editing.mdx +100 -0
  226. package/docs/v6/getting-started/playwright.mdx +342 -0
  227. package/docs/v6/getting-started/running.mdx +48 -0
  228. package/docs/v6/getting-started/self-hosting.mdx +408 -0
  229. package/docs/v6/getting-started/vscode.mdx +88 -0
  230. package/docs/v6/guide/assertions.mdx +189 -0
  231. package/docs/v6/guide/authentication.mdx +136 -0
  232. package/docs/v6/guide/code.mdx +65 -0
  233. package/docs/v6/guide/dashcam.mdx +118 -0
  234. package/docs/v6/guide/environment-variables.mdx +26 -0
  235. package/docs/v6/guide/lifecycle.mdx +242 -0
  236. package/docs/v6/guide/locating.mdx +141 -0
  237. package/docs/v6/guide/protips.mdx +43 -0
  238. package/docs/v6/guide/variables.mdx +143 -0
  239. package/docs/v6/guide/waiting.mdx +130 -0
  240. package/docs/v6/importing/csv.mdx +196 -0
  241. package/docs/v6/importing/gherkin.mdx +143 -0
  242. package/docs/v6/importing/jira.mdx +164 -0
  243. package/docs/v6/importing/testrail.mdx +162 -0
  244. package/docs/v6/integrations/electron.mdx +146 -0
  245. package/docs/v6/integrations/netlify.mdx +100 -0
  246. package/docs/v6/integrations/vercel.mdx +125 -0
  247. package/docs/v6/interactive/explore.mdx +99 -0
  248. package/docs/v6/interactive/run.mdx +52 -0
  249. package/docs/v6/interactive/save.mdx +63 -0
  250. package/docs/v6/overview/comparison.mdx +101 -0
  251. package/docs/v6/overview/faq.mdx +162 -0
  252. package/docs/v6/overview/performance.mdx +52 -0
  253. package/docs/v6/overview/quickstart.mdx +137 -0
  254. package/docs/v6/overview/what-is-testdriver.mdx +85 -0
  255. package/docs/v6/scenarios/ai-chatbot.mdx +28 -0
  256. package/docs/v6/scenarios/cookie-banner.mdx +32 -0
  257. package/docs/v6/scenarios/file-upload.mdx +33 -0
  258. package/docs/v6/scenarios/form-filling.mdx +32 -0
  259. package/docs/v6/scenarios/log-in.mdx +75 -0
  260. package/docs/v6/scenarios/pdf-generation.mdx +25 -0
  261. package/docs/v6/scenarios/spell-check.mdx +22 -0
  262. package/docs/v6/security/action.mdx +84 -0
  263. package/docs/v6/security/agent.mdx +73 -0
  264. package/docs/v6/security/platform.mdx +77 -0
  265. package/docs/v6/tutorials/advanced-test.mdx +81 -0
  266. package/docs/v6/tutorials/basic-test.mdx +45 -0
  267. package/docs/v7/_drafts/agents.mdx +843 -0
  268. package/docs/v7/_drafts/architecture.mdx +399 -0
  269. package/docs/v7/_drafts/auto-cache-key.mdx +167 -0
  270. package/docs/v7/_drafts/awesome-logs-quick-ref.mdx +100 -0
  271. package/docs/v7/_drafts/best-practices.mdx +486 -0
  272. package/docs/v7/_drafts/caching-ai.mdx +215 -0
  273. package/docs/v7/_drafts/caching-selectors.mdx +424 -0
  274. package/docs/v7/_drafts/caching.mdx +366 -0
  275. package/docs/v7/_drafts/cli-to-sdk-migration.mdx +425 -0
  276. package/docs/v7/_drafts/commands/assert.mdx +45 -0
  277. package/docs/v7/_drafts/commands/exec.mdx +276 -0
  278. package/docs/v7/_drafts/commands/focus-application.mdx +44 -0
  279. package/docs/v7/_drafts/commands/hover-image.mdx +69 -0
  280. package/docs/v7/_drafts/commands/hover-text.mdx +47 -0
  281. package/docs/v7/_drafts/commands/if.mdx +53 -0
  282. package/docs/v7/_drafts/commands/match-image.mdx +67 -0
  283. package/docs/v7/_drafts/commands/press-keys.mdx +87 -0
  284. package/docs/v7/_drafts/commands/remember.mdx +49 -0
  285. package/docs/v7/_drafts/commands/run.mdx +44 -0
  286. package/docs/v7/_drafts/commands/scroll-until-image.mdx +66 -0
  287. package/docs/v7/_drafts/commands/scroll-until-text.mdx +60 -0
  288. package/docs/v7/_drafts/commands/scroll.mdx +69 -0
  289. package/docs/v7/_drafts/commands/type.mdx +45 -0
  290. package/docs/v7/_drafts/commands/wait-for-image.mdx +54 -0
  291. package/docs/v7/_drafts/commands/wait-for-text.mdx +48 -0
  292. package/docs/v7/_drafts/commands/wait.mdx +45 -0
  293. package/docs/v7/_drafts/configuration.mdx +378 -0
  294. package/docs/v7/_drafts/contributing.mdx +174 -0
  295. package/docs/v7/_drafts/core.mdx +458 -0
  296. package/docs/v7/_drafts/dashcam-title-feature.mdx +89 -0
  297. package/docs/v7/_drafts/debugging.mdx +349 -0
  298. package/docs/v7/_drafts/error-handling.mdx +501 -0
  299. package/docs/v7/_drafts/faq.mdx +393 -0
  300. package/docs/v7/_drafts/hooks.mdx +360 -0
  301. package/docs/v7/_drafts/init-command.mdx +95 -0
  302. package/docs/v7/_drafts/installation.mdx +420 -0
  303. package/docs/v7/_drafts/migration.mdx +562 -0
  304. package/docs/v7/_drafts/observable.mdx +604 -0
  305. package/docs/v7/_drafts/playwright.mdx +342 -0
  306. package/docs/v7/_drafts/plugin-migration.mdx +220 -0
  307. package/docs/v7/_drafts/powerful.mdx +419 -0
  308. package/docs/v7/_drafts/presets.mdx +210 -0
  309. package/docs/v7/_drafts/progressive-disclosure.mdx +230 -0
  310. package/docs/v7/_drafts/prompt-cache.mdx +200 -0
  311. package/docs/v7/_drafts/provision.mdx +390 -0
  312. package/docs/v7/_drafts/quick-start-test-recording.mdx +214 -0
  313. package/docs/v7/_drafts/readme.mdx +135 -0
  314. package/docs/v7/_drafts/reports.mdx +414 -0
  315. package/docs/v7/_drafts/scalable.mdx +763 -0
  316. package/docs/v7/_drafts/screenshot.mdx +155 -0
  317. package/docs/v7/_drafts/sdk-awesome-logs.mdx +468 -0
  318. package/docs/v7/_drafts/sdk-browser-rendering.mdx +167 -0
  319. package/docs/v7/_drafts/sdk-migration.mdx +474 -0
  320. package/docs/v7/_drafts/sdk-v7-complete.mdx +345 -0
  321. package/docs/v7/_drafts/self-hosting.mdx +369 -0
  322. package/docs/v7/_drafts/test-recording.mdx +382 -0
  323. package/docs/v7/_drafts/troubleshooting.mdx +526 -0
  324. package/docs/v7/_drafts/vitest-plugin.mdx +477 -0
  325. package/docs/v7/_drafts/vitest.mdx +535 -0
  326. package/docs/v7/_drafts/writing-tests.mdx +25 -0
  327. package/docs/v7/ai.mdx +205 -0
  328. package/docs/v7/assert.mdx +316 -0
  329. package/docs/v7/aws-setup.mdx +449 -0
  330. package/docs/v7/cache.mdx +223 -0
  331. package/docs/v7/caching.mdx +128 -0
  332. package/docs/v7/captcha.mdx +159 -0
  333. package/docs/v7/ci-cd.mdx +603 -0
  334. package/docs/v7/click.mdx +287 -0
  335. package/docs/v7/client.mdx +478 -0
  336. package/docs/v7/copilot/auto-healing.mdx +265 -0
  337. package/docs/v7/copilot/creating-tests.mdx +156 -0
  338. package/docs/v7/copilot/github.mdx +143 -0
  339. package/docs/v7/copilot/running-tests.mdx +149 -0
  340. package/docs/v7/copilot/setup.mdx +143 -0
  341. package/docs/v7/customizing-devices.mdx +319 -0
  342. package/docs/v7/dashcam.mdx +419 -0
  343. package/docs/v7/debugging-with-screenshots.mdx +402 -0
  344. package/docs/v7/device-config.mdx +317 -0
  345. package/docs/v7/double-click.mdx +102 -0
  346. package/docs/v7/elements.mdx +606 -0
  347. package/docs/v7/enterprise.mdx +9 -0
  348. package/docs/v7/errors.mdx +248 -0
  349. package/docs/v7/events.mdx +358 -0
  350. package/docs/v7/examples/ai.mdx +72 -0
  351. package/docs/v7/examples/assert.mdx +72 -0
  352. package/docs/v7/examples/captcha-api.mdx +92 -0
  353. package/docs/v7/examples/chrome-extension.mdx +132 -0
  354. package/docs/v7/examples/drag-and-drop.mdx +100 -0
  355. package/docs/v7/examples/element-not-found.mdx +67 -0
  356. package/docs/v7/examples/exec-output.mdx +85 -0
  357. package/docs/v7/examples/exec-pwsh.mdx +83 -0
  358. package/docs/v7/examples/focus-window.mdx +62 -0
  359. package/docs/v7/examples/hover-image.mdx +94 -0
  360. package/docs/v7/examples/hover-text.mdx +69 -0
  361. package/docs/v7/examples/installer.mdx +91 -0
  362. package/docs/v7/examples/launch-vscode-linux.mdx +101 -0
  363. package/docs/v7/examples/match-image.mdx +96 -0
  364. package/docs/v7/examples/press-keys.mdx +92 -0
  365. package/docs/v7/examples/scroll-keyboard.mdx +79 -0
  366. package/docs/v7/examples/scroll-until-image.mdx +81 -0
  367. package/docs/v7/examples/scroll-until-text.mdx +109 -0
  368. package/docs/v7/examples/scroll.mdx +81 -0
  369. package/docs/v7/examples/type.mdx +92 -0
  370. package/docs/v7/examples/windows-installer.mdx +89 -0
  371. package/docs/v7/exec.mdx +318 -0
  372. package/docs/v7/find.mdx +830 -0
  373. package/docs/v7/focus-application.mdx +294 -0
  374. package/docs/v7/generating-tests.mdx +36 -0
  375. package/docs/v7/hosted.mdx +158 -0
  376. package/docs/v7/hover.mdx +279 -0
  377. package/docs/v7/locating-elements.mdx +71 -0
  378. package/docs/v7/making-assertions.mdx +32 -0
  379. package/docs/v7/mcp.mdx +9 -0
  380. package/docs/v7/mouse-down.mdx +161 -0
  381. package/docs/v7/mouse-up.mdx +164 -0
  382. package/docs/v7/parse.mdx +237 -0
  383. package/docs/v7/performing-actions.mdx +54 -0
  384. package/docs/v7/press-keys.mdx +349 -0
  385. package/docs/v7/provision.mdx +333 -0
  386. package/docs/v7/quickstart.mdx +173 -0
  387. package/docs/v7/redraw.mdx +216 -0
  388. package/docs/v7/reusable-code.mdx +249 -0
  389. package/docs/v7/right-click.mdx +123 -0
  390. package/docs/v7/running-tests.mdx +185 -0
  391. package/docs/v7/screenshot.mdx +249 -0
  392. package/docs/v7/screenshots.mdx +186 -0
  393. package/docs/v7/scroll.mdx +336 -0
  394. package/docs/v7/secrets.mdx +115 -0
  395. package/docs/v7/self-hosted.mdx +149 -0
  396. package/docs/v7/type.mdx +358 -0
  397. package/docs/v7/variables.mdx +111 -0
  398. package/docs/v7/wait.mdx +52 -0
  399. package/docs/v7/waiting-for-elements.mdx +90 -0
  400. package/docs/v7/what-is-testdriver.mdx +54 -0
  401. package/eslint.config.js +67 -0
  402. package/examples/ai.test.mjs +31 -0
  403. package/examples/assert.test.mjs +47 -0
  404. package/examples/chrome-extension.test.mjs +97 -0
  405. package/examples/config.mjs +5 -0
  406. package/examples/element-not-found.test.mjs +27 -0
  407. package/examples/exec-output.test.mjs +60 -0
  408. package/examples/exec-pwsh.test.mjs +58 -0
  409. package/examples/findall-coffee-icons.test.mjs +42 -0
  410. package/examples/focus-window.test.mjs +37 -0
  411. package/examples/formatted-logging.test.mjs +27 -0
  412. package/examples/hover-image.test.mjs +53 -0
  413. package/examples/hover-text-with-description.test.mjs +57 -0
  414. package/examples/hover-text.test.mjs +28 -0
  415. package/examples/installer.test.mjs +50 -0
  416. package/examples/launch-vscode-linux.test.mjs +55 -0
  417. package/examples/match-image.test.mjs +55 -0
  418. package/examples/parse.test.mjs +19 -0
  419. package/examples/press-keys.test.mjs +44 -0
  420. package/examples/prompt.test.mjs +34 -0
  421. package/examples/scroll-keyboard.test.mjs +38 -0
  422. package/examples/scroll-until-image.test.mjs +40 -0
  423. package/examples/scroll.test.mjs +42 -0
  424. package/examples/type.test.mjs +46 -0
  425. package/examples/windows-installer.test.mjs +54 -0
  426. package/index.js +2 -0
  427. package/interfaces/cli/commands/init.js +438 -0
  428. package/interfaces/cli/commands/setup.js +382 -0
  429. package/interfaces/cli/lib/base.js +285 -0
  430. package/interfaces/cli.js +20 -0
  431. package/interfaces/junit-reporter.js +290 -0
  432. package/interfaces/logger.js +388 -0
  433. package/interfaces/readline.js +234 -0
  434. package/interfaces/shared-test-state.mjs +64 -0
  435. package/interfaces/vitest-plugin.d.ts +115 -0
  436. package/interfaces/vitest-plugin.mjs +1698 -0
  437. package/lib/captcha/solver.js +358 -0
  438. package/lib/core/Dashcam.js +533 -0
  439. package/lib/core/index.d.ts +172 -0
  440. package/lib/core/index.js +12 -0
  441. package/lib/environments.json +18 -0
  442. package/lib/github-comment-formatter.js +263 -0
  443. package/lib/github-comment.mjs +452 -0
  444. package/lib/init-project.js +575 -0
  445. package/lib/presets/index.mjs +331 -0
  446. package/lib/resolve-channel.js +46 -0
  447. package/lib/sentry.js +417 -0
  448. package/lib/vitest/hooks.d.ts +57 -0
  449. package/lib/vitest/hooks.mjs +674 -0
  450. package/lib/vitest/setup-aws.mjs +247 -0
  451. package/lib/vitest/setup-self-hosted.mjs +151 -0
  452. package/lib/vitest/setup.mjs +46 -0
  453. package/manual/captcha-api.test.mjs +51 -0
  454. package/manual/drag-and-drop.test.mjs +59 -0
  455. package/manual/flake-diffthreshold-001.test.mjs +9 -0
  456. package/manual/flake-diffthreshold-01.test.mjs +9 -0
  457. package/manual/flake-diffthreshold-05.test.mjs +9 -0
  458. package/manual/flake-noredraw-cache.test.mjs +9 -0
  459. package/manual/flake-noredraw-nocache.test.mjs +9 -0
  460. package/manual/flake-redraw-cache.test.mjs +9 -0
  461. package/manual/flake-redraw-nocache.test.mjs +9 -0
  462. package/manual/flake-rocket-match.test.mjs +30 -0
  463. package/manual/flake-shared.mjs +51 -0
  464. package/manual/no-provision.test.mjs +31 -0
  465. package/manual/packer-hover-image.test.mjs +176 -0
  466. package/manual/scroll-until-text.test.mjs +68 -0
  467. package/manual/test-init-command.js +223 -0
  468. package/mcp-server/README.md +322 -0
  469. package/mcp-server/dist/codegen.d.ts +9 -0
  470. package/mcp-server/dist/codegen.js +165 -0
  471. package/mcp-server/dist/mcp-app.html +114 -0
  472. package/mcp-server/dist/package.json +1 -0
  473. package/mcp-server/dist/provision-types.d.ts +290 -0
  474. package/mcp-server/dist/provision-types.js +174 -0
  475. package/mcp-server/dist/server.d.ts +6 -0
  476. package/mcp-server/dist/server.mjs +1925 -0
  477. package/mcp-server/dist/session.d.ts +85 -0
  478. package/mcp-server/dist/session.js +152 -0
  479. package/mcp-server/mcp-app.html +28 -0
  480. package/mcp-server/mcp-config.example.json +19 -0
  481. package/mcp-server/package-lock.json +4027 -0
  482. package/mcp-server/package.json +31 -0
  483. package/mcp-server/src/codegen.ts +189 -0
  484. package/mcp-server/src/mcp-app.css +360 -0
  485. package/mcp-server/src/mcp-app.ts +547 -0
  486. package/mcp-server/src/provision-types.ts +209 -0
  487. package/mcp-server/src/server.ts +2391 -0
  488. package/mcp-server/src/session.ts +194 -0
  489. package/mcp-server/tsconfig.json +16 -0
  490. package/mcp-server/vite.config.ts +23 -0
  491. package/package.json +158 -0
  492. package/schema.json +1046 -0
  493. package/scripts/generate-skills.js +94 -0
  494. package/sdk-log-formatter.js +1157 -0
  495. package/sdk.d.ts +1486 -0
  496. package/sdk.js +4336 -0
  497. package/setup/aws/cloudformation.yaml +463 -0
  498. package/setup/aws/disable-defender.sh +42 -0
  499. package/setup/aws/install-dev-runner.sh +79 -0
  500. package/setup/aws/spawn-runner.sh +289 -0
  501. package/test/captcha-solver.test.mjs +152 -0
  502. package/test/chrome-remote-debugging.test.mjs +66 -0
  503. package/test/duckduckgo/experiment.test.mjs +28 -0
  504. package/test/duckduckgo/setup.test.mjs +29 -0
  505. package/test/manual/debug-locate-response.js +82 -0
  506. package/test/manual/reconnect-provision.test.mjs +49 -0
  507. package/test/manual/test-console-logs.test.mjs +42 -0
  508. package/test/manual/test-find-api.js +73 -0
  509. package/test/manual/test-init.sh +54 -0
  510. package/test/manual/test-prompt-cache.js +97 -0
  511. package/test/manual/test-provision-auth.mjs +22 -0
  512. package/test/manual/test-sandbox-render.js +29 -0
  513. package/test/manual/test-sdk-methods.js +15 -0
  514. package/test/manual/test-sdk-refactor.js +53 -0
  515. package/test/manual/test-stack-trace.mjs +57 -0
  516. package/test/manual/verify-element-api.js +89 -0
  517. package/test/manual/verify-types.js +0 -0
  518. package/test/manual-unawaited-promise.test.mjs +31 -0
  519. package/vitest.config.mjs +58 -0
  520. package/vitest.runner.config.mjs +33 -0
  521. package/vscode-extension/.vscodeignore +12 -0
  522. package/vscode-extension/README.md +94 -0
  523. package/vscode-extension/media/icon.png +0 -0
  524. package/vscode-extension/package-lock.json +4126 -0
  525. package/vscode-extension/package.json +86 -0
  526. package/vscode-extension/src/extension.ts +829 -0
  527. package/vscode-extension/testdriverai-0.1.0.vsix +0 -0
  528. package/vscode-extension/tsconfig.json +16 -0
@@ -0,0 +1,560 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Generate Example Docs from Test Files
5
+ *
6
+ * Reads example test files and the examples manifest to generate
7
+ * MDX documentation pages with embedded test run iframes.
8
+ *
9
+ * Usage:
10
+ * node generate-examples.js
11
+ * node generate-examples.js --dry-run
12
+ * node generate-examples.js --skip-ai
13
+ */
14
+
15
+ const fs = require("fs");
16
+ const path = require("path");
17
+
18
+ // Paths
19
+ const EXAMPLES_DIR = path.join(__dirname, "../../examples");
20
+ const MANIFEST_PATH = path.join(__dirname, "../_data/examples-manifest.json");
21
+ const OUTPUT_DIR = path.join(__dirname, "../v7/examples");
22
+ const DOCS_JSON_PATH = path.join(__dirname, "../docs.json");
23
+
24
+ // Icon mapping based on test type/content
25
+ const ICON_MAP = {
26
+ ai: "wand-magic-sparkles",
27
+ assert: "check-circle",
28
+ captcha: "shield-check",
29
+ chrome: "chrome",
30
+ drag: "arrows-up-down-left-right",
31
+ exec: "terminal",
32
+ focus: "window-maximize",
33
+ hover: "hand-pointer",
34
+ installer: "download",
35
+ match: "image",
36
+ press: "keyboard",
37
+ scroll: "scroll",
38
+ type: "keyboard",
39
+ prompt: "message",
40
+ element: "crosshairs",
41
+ window: "window-maximize",
42
+ default: "play",
43
+ };
44
+
45
+ // Parse command line arguments
46
+ function parseArgs() {
47
+ const args = process.argv.slice(2);
48
+ return {
49
+ dryRun: args.includes("--dry-run"),
50
+ help: args.includes("--help") || args.includes("-h"),
51
+ verbose: args.includes("--verbose") || args.includes("-v"),
52
+ };
53
+ }
54
+
55
+ // Load manifest
56
+ function loadManifest() {
57
+ try {
58
+ const content = fs.readFileSync(MANIFEST_PATH, "utf-8");
59
+ return JSON.parse(content);
60
+ } catch (error) {
61
+ console.warn("āš ļø No manifest found, generating docs without URLs");
62
+ return { examples: {} };
63
+ }
64
+ }
65
+
66
+ // Load docs.json
67
+ function loadDocsJson() {
68
+ const content = fs.readFileSync(DOCS_JSON_PATH, "utf-8");
69
+ return JSON.parse(content);
70
+ }
71
+
72
+ // Save docs.json
73
+ function saveDocsJson(docsJson) {
74
+ fs.writeFileSync(DOCS_JSON_PATH, JSON.stringify(docsJson, null, 2) + "\n", "utf-8");
75
+ }
76
+
77
+ // Get all example files
78
+ function getExampleFiles() {
79
+ return fs
80
+ .readdirSync(EXAMPLES_DIR)
81
+ .filter((f) => f.endsWith(".test.mjs"))
82
+ .sort();
83
+ }
84
+
85
+ // Rewrite internal imports and helpers to their public equivalents
86
+ function transformContentForDocs(content) {
87
+ let transformed = content;
88
+
89
+ // Rewrite internal relative import to the public package path
90
+ transformed = transformed.replace(
91
+ /from\s+["']\.\.\/lib\/vitest\/hooks\.mjs["']/g,
92
+ 'from "testdriverai/vitest/hooks"'
93
+ );
94
+
95
+ // Remove internal config helper import
96
+ transformed = transformed.replace(
97
+ /import\s+\{[^}]*getDefaults[^}]*\}\s+from\s+["']\.\/config\.mjs["'];\n?/g,
98
+ ''
99
+ );
100
+
101
+ // Replace getDefaults(context) spread with inline defaults
102
+ transformed = transformed.replace(
103
+ /\{\s*\.\.\.getDefaults\(context\)\s*/g,
104
+ '{ ip: context.ip || process.env.TD_IP'
105
+ );
106
+
107
+ return transformed;
108
+ }
109
+
110
+ // Parse test file to extract metadata
111
+ function parseTestFile(filePath) {
112
+ const raw = fs.readFileSync(filePath, "utf-8");
113
+ const content = transformContentForDocs(raw);
114
+ const filename = path.basename(filePath);
115
+
116
+ // Extract JSDoc comment at top of file
117
+ const jsdocMatch = content.match(/^\/\*\*\n([\s\S]*?)\n\s*\*\//);
118
+ const jsdoc = jsdocMatch
119
+ ? jsdocMatch[1]
120
+ .split("\n")
121
+ .map((line) => line.replace(/^\s*\*\s?/, "").trim())
122
+ .filter((line) => line && !line.startsWith("@"))
123
+ .join(" ")
124
+ : null;
125
+
126
+ // Extract describe() name
127
+ const describeMatch = content.match(/describe\s*\(\s*["'`]([^"'`]+)["'`]/);
128
+ const describeName = describeMatch ? describeMatch[1] : null;
129
+
130
+ // Extract it() name
131
+ const itMatch = content.match(/it\s*\(\s*["'`]([^"'`]+)["'`]/);
132
+ const itName = itMatch ? itMatch[1] : null;
133
+
134
+ // Get icon based on filename
135
+ const icon = Object.entries(ICON_MAP).find(([key]) =>
136
+ filename.toLowerCase().includes(key)
137
+ )?.[1] || ICON_MAP.default;
138
+
139
+ return {
140
+ filename,
141
+ content,
142
+ jsdoc,
143
+ describeName,
144
+ itName,
145
+ icon,
146
+ };
147
+ }
148
+
149
+ // Generate slug from filename
150
+ function generateSlug(filename) {
151
+ return filename
152
+ .replace(".test.mjs", "")
153
+ .replace(/[^a-z0-9]+/gi, "-")
154
+ .toLowerCase();
155
+ }
156
+
157
+ // Generate human-readable title from filename
158
+ function generateTitle(filename, describeName) {
159
+ if (describeName) {
160
+ return describeName;
161
+ }
162
+ return filename
163
+ .replace(".test.mjs", "")
164
+ .split(/[-_]/)
165
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
166
+ .join(" ");
167
+ }
168
+
169
+ // Generate short sidebar title
170
+ function generateSidebarTitle(filename) {
171
+ return filename
172
+ .replace(".test.mjs", "")
173
+ .split(/[-_]/)
174
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
175
+ .join(" ");
176
+ }
177
+
178
+ // Call OpenAI API to generate description
179
+ async function generateAIDescription(testMeta, options) {
180
+ if (options.skipAi) {
181
+ return generateFallbackDescription(testMeta);
182
+ }
183
+
184
+ const apiKey = process.env.OPENAI_API_KEY;
185
+ if (!apiKey) {
186
+ console.warn("āš ļø OPENAI_API_KEY not set, using fallback descriptions");
187
+ return generateFallbackDescription(testMeta);
188
+ }
189
+
190
+ const prompt = `You are a technical writer for TestDriver.ai documentation. Generate a concise 2-3 paragraph description for this test example.
191
+
192
+ Test file: ${testMeta.filename}
193
+ Test suite name: ${testMeta.describeName || "N/A"}
194
+ Test name: ${testMeta.itName || "N/A"}
195
+ JSDoc: ${testMeta.jsdoc || "N/A"}
196
+
197
+ Test code:
198
+ \`\`\`javascript
199
+ ${testMeta.content}
200
+ \`\`\`
201
+
202
+ Write a description that:
203
+ 1. Explains what this test demonstrates (first paragraph)
204
+ 2. Describes the key TestDriver SDK methods used (second paragraph)
205
+ 3. Mentions any important patterns or best practices shown (optional third paragraph)
206
+
207
+ Keep it professional and focused on helping developers understand the example. Do not include code blocks in your response.`;
208
+
209
+ try {
210
+ const response = await fetch("https://api.openai.com/v1/chat/completions", {
211
+ method: "POST",
212
+ headers: {
213
+ "Content-Type": "application/json",
214
+ Authorization: `Bearer ${apiKey}`,
215
+ },
216
+ body: JSON.stringify({
217
+ model: "gpt-4o-mini",
218
+ messages: [{ role: "user", content: prompt }],
219
+ max_tokens: 500,
220
+ temperature: 0.7,
221
+ }),
222
+ });
223
+
224
+ if (!response.ok) {
225
+ throw new Error(`OpenAI API error: ${response.status}`);
226
+ }
227
+
228
+ const data = await response.json();
229
+ return data.choices[0].message.content.trim();
230
+ } catch (error) {
231
+ console.warn(`āš ļø AI generation failed for ${testMeta.filename}: ${error.message}`);
232
+ return generateFallbackDescription(testMeta);
233
+ }
234
+ }
235
+
236
+ // Generate fallback description when AI is not available
237
+ function generateFallbackDescription(testMeta) {
238
+ const parts = [];
239
+
240
+ if (testMeta.jsdoc) {
241
+ parts.push(testMeta.jsdoc);
242
+ } else if (testMeta.describeName && testMeta.itName) {
243
+ parts.push(
244
+ `This example demonstrates the "${testMeta.describeName}" test suite. Specifically, it shows how to ${testMeta.itName.toLowerCase()}.`
245
+ );
246
+ } else {
247
+ const title = generateTitle(testMeta.filename, testMeta.describeName);
248
+ parts.push(
249
+ `This example demonstrates ${title.toLowerCase()} functionality using TestDriver.ai.`
250
+ );
251
+ }
252
+
253
+ parts.push(
254
+ "\nReview the source code below to understand the implementation details and patterns used."
255
+ );
256
+
257
+ return parts.join("\n");
258
+ }
259
+
260
+ // Generate short description for frontmatter
261
+ function generateShortDescription(testMeta) {
262
+ if (testMeta.jsdoc) {
263
+ // Take first sentence
264
+ const firstSentence = testMeta.jsdoc.split(/\.\s/)[0];
265
+ return firstSentence.endsWith(".") ? firstSentence : firstSentence + ".";
266
+ }
267
+ if (testMeta.itName) {
268
+ return `Example: ${testMeta.itName}`;
269
+ }
270
+ return `TestDriver example for ${generateTitle(testMeta.filename, testMeta.describeName).toLowerCase()}`;
271
+ }
272
+
273
+ // Extract testcase ID from manifest URL
274
+ // URL format: http://localhost:3001/runs/{runId}/{testcaseId}
275
+ function extractTestcaseId(url) {
276
+ if (!url) return null;
277
+ const pathParts = new URL(url).pathname.split('/').filter(Boolean);
278
+ // The testcase ID is the last segment (e.g., /runs/runId/testcaseId)
279
+ return pathParts.length >= 2 ? pathParts[pathParts.length - 1] : null;
280
+ }
281
+
282
+ // Generate replay URL from testcase ID
283
+ function generateReplayUrl(testcaseId) {
284
+ // Use the API replay endpoint which handles the redirect with embed=true
285
+ const apiRoot = process.env.TD_API_ROOT || 'https://api.testdriver.ai';
286
+ return `${apiRoot}/api/v1/testdriver/testcase/${testcaseId}/replay`;
287
+ }
288
+
289
+ // Update existing MDX file by finding the marker comment and replacing the iframe
290
+ function updateExistingMDX(existingContent, filename, testcaseId) {
291
+ const marker = `{/* ${filename} output */}`;
292
+
293
+ if (!existingContent.includes(marker)) {
294
+ return null; // Marker not found, can't update
295
+ }
296
+
297
+ const replayUrl = generateReplayUrl(testcaseId);
298
+
299
+ // Pattern to match the marker followed by the iframe tag
300
+ const pattern = new RegExp(
301
+ `(\\{/\\* ${filename.replace('.', '\\.')} output \\*/\\}\\s*)<iframe[^>]*src="[^"]*"([^]*)/>`,
302
+ 's'
303
+ );
304
+
305
+ const replacement = `$1<iframe \n src="${replayUrl}"$2/>`;
306
+ const updated = existingContent.replace(pattern, replacement);
307
+
308
+ if (updated === existingContent) {
309
+ return null; // No change made
310
+ }
311
+
312
+ return updated;
313
+ }
314
+
315
+ // Generate MDX content
316
+ function generateMDX(testMeta, manifest, description) {
317
+ const slug = generateSlug(testMeta.filename);
318
+ const title = generateTitle(testMeta.filename, testMeta.describeName);
319
+ const sidebarTitle = generateSidebarTitle(testMeta.filename);
320
+ const shortDescription = generateShortDescription(testMeta);
321
+ const manifestEntry = manifest.examples[testMeta.filename];
322
+ const testcaseId = manifestEntry?.url ? extractTestcaseId(manifestEntry.url) : null;
323
+
324
+ let mdx = `---
325
+ title: "${title}"
326
+ sidebarTitle: "${sidebarTitle}"
327
+ description: "${shortDescription.replace(/"/g, '\\"')}"
328
+ icon: "${testMeta.icon}"
329
+ ---
330
+
331
+ ## Overview
332
+
333
+ ${description}
334
+
335
+ `;
336
+
337
+ // Add Live Test Run section if URL exists
338
+ if (testcaseId) {
339
+ const replayUrl = generateReplayUrl(testcaseId);
340
+ mdx += `## Live Test Run
341
+
342
+ Watch this test execute in a real sandbox environment:
343
+
344
+ {/* ${testMeta.filename} output */}
345
+ <iframe
346
+ src="${replayUrl}"
347
+ width="100%"
348
+ height="600"
349
+ style={{ border: "1px solid #333", borderRadius: "8px" }}
350
+ allow="fullscreen"
351
+ />
352
+
353
+ `;
354
+ } else {
355
+ mdx += `## Live Test Run
356
+
357
+ <Note>
358
+ A live test recording will be available after the next CI run.
359
+ </Note>
360
+
361
+ `;
362
+ }
363
+
364
+ // Add Source Code section
365
+ mdx += `## Source Code
366
+
367
+ \`\`\`javascript title="${testMeta.filename}"
368
+ ${testMeta.content.trim()}
369
+ \`\`\`
370
+
371
+ ## Running This Example
372
+
373
+ \`\`\`bash
374
+ # Clone the TestDriver repository
375
+ git clone https://github.com/testdriverai/testdriverai
376
+
377
+ # Install dependencies
378
+ cd testdriverai
379
+ npm install
380
+
381
+ # Run this specific example
382
+ npx vitest run examples/${testMeta.filename}
383
+ \`\`\`
384
+
385
+ <Note>
386
+ Make sure you have \`TD_API_KEY\` set in your environment. Get one at [testdriver.ai](https://testdriver.ai).
387
+ </Note>
388
+ `;
389
+
390
+ return mdx;
391
+ }
392
+
393
+ // Update docs.json navigation
394
+ function updateDocsNavigation(docsJson, examplePages, options) {
395
+ // Find v7 version in navigation
396
+ const v7Version = docsJson.navigation.versions.find((v) => v.version === "v7");
397
+ if (!v7Version) {
398
+ console.error("āŒ Could not find v7 version in docs.json");
399
+ return false;
400
+ }
401
+
402
+ // Find or create Examples group
403
+ let examplesGroup = v7Version.groups.find((g) =>
404
+ g.group === "Examples" ||
405
+ (typeof g === "object" && g.group === "Examples")
406
+ );
407
+
408
+ const examplesPages = examplePages.map((slug) => `/v7/examples/${slug}`);
409
+
410
+ if (examplesGroup) {
411
+ // Update existing group
412
+ examplesGroup.pages = examplesPages;
413
+ if (options.verbose) {
414
+ console.log("šŸ”„ Updated existing Examples group in navigation");
415
+ }
416
+ } else {
417
+ // Create new group after Overview
418
+ const overviewIndex = v7Version.groups.findIndex((g) => g.group === "Overview");
419
+ const newGroup = {
420
+ group: "Examples",
421
+ icon: "code",
422
+ pages: examplesPages,
423
+ };
424
+
425
+ if (overviewIndex !== -1) {
426
+ v7Version.groups.splice(overviewIndex + 1, 0, newGroup);
427
+ } else {
428
+ v7Version.groups.push(newGroup);
429
+ }
430
+
431
+ if (options.verbose) {
432
+ console.log("āž• Added new Examples group to navigation");
433
+ }
434
+ }
435
+
436
+ return true;
437
+ }
438
+
439
+ // Show help
440
+ function showHelp() {
441
+ console.log(`
442
+ Update Example Docs Iframe URLs
443
+
444
+ Usage:
445
+ node generate-examples.js [options]
446
+
447
+ Options:
448
+ --dry-run Preview changes without writing files
449
+ --verbose Show detailed output
450
+ --help, -h Show this help message
451
+
452
+ Environment Variables:
453
+ TD_API_ROOT API root URL (default: https://api.testdriver.ai)
454
+
455
+ Description:
456
+ Reads existing MDX files in docs/v7/examples/ and updates the iframe
457
+ src URLs based on the examples-manifest.json.
458
+
459
+ Files must contain a marker comment like: {/* filename.test.mjs output */}
460
+ The iframe following the marker will have its src updated to the
461
+ API replay endpoint.
462
+ `);
463
+ }
464
+
465
+ // Main function
466
+ async function main() {
467
+ const options = parseArgs();
468
+
469
+ if (options.help) {
470
+ showHelp();
471
+ process.exit(0);
472
+ }
473
+
474
+ console.log("šŸš€ Updating example documentation iframes...\n");
475
+
476
+ if (options.dryRun) {
477
+ console.log("šŸ“‹ DRY RUN - no files will be written\n");
478
+ }
479
+
480
+ // Load manifest
481
+ const manifest = loadManifest();
482
+
483
+ // Get existing MDX files in output directory
484
+ const existingFiles = fs.existsSync(OUTPUT_DIR)
485
+ ? fs.readdirSync(OUTPUT_DIR).filter((f) => f.endsWith(".mdx"))
486
+ : [];
487
+
488
+ console.log(`šŸ“‚ Found ${existingFiles.length} existing MDX files\n`);
489
+
490
+ let updated = 0;
491
+ let skipped = 0;
492
+ let errors = 0;
493
+
494
+ for (const mdxFile of existingFiles) {
495
+ const outputPath = path.join(OUTPUT_DIR, mdxFile);
496
+
497
+ try {
498
+ const existingContent = fs.readFileSync(outputPath, 'utf-8');
499
+
500
+ // Find the marker in the file to get the test filename
501
+ const markerMatch = existingContent.match(/\{\/\* ([^*]+\.test\.mjs) output \*\/\}/);
502
+
503
+ if (!markerMatch) {
504
+ skipped++;
505
+ if (options.verbose) {
506
+ console.log(`ā­ļø ${mdxFile} (no marker)`);
507
+ }
508
+ continue;
509
+ }
510
+
511
+ const testFilename = markerMatch[1];
512
+ const manifestEntry = manifest.examples[testFilename];
513
+ const testcaseId = manifestEntry?.url ? extractTestcaseId(manifestEntry.url) : null;
514
+
515
+ if (!testcaseId) {
516
+ skipped++;
517
+ if (options.verbose) {
518
+ console.log(`ā­ļø ${mdxFile} (no URL in manifest for ${testFilename})`);
519
+ }
520
+ continue;
521
+ }
522
+
523
+ const updatedContent = updateExistingMDX(existingContent, testFilename, testcaseId);
524
+
525
+ if (updatedContent) {
526
+ if (!options.dryRun) {
527
+ fs.writeFileSync(outputPath, updatedContent, 'utf-8');
528
+ }
529
+ updated++;
530
+ console.log(`šŸ”„ ${mdxFile} (updated iframe)`);
531
+ } else {
532
+ skipped++;
533
+ if (options.verbose) {
534
+ console.log(`ā­ļø ${mdxFile} (unchanged)`);
535
+ }
536
+ }
537
+ } catch (error) {
538
+ console.error(`āŒ ${mdxFile}: ${error.message}`);
539
+ errors++;
540
+ }
541
+ }
542
+
543
+ console.log(`\n✨ Complete!`);
544
+ console.log(` Updated: ${updated} docs`);
545
+ console.log(` Skipped: ${skipped} unchanged`);
546
+ if (errors > 0) {
547
+ console.log(` Errors: ${errors}`);
548
+ }
549
+ console.log(`\nšŸ“‚ Output: ${OUTPUT_DIR}`);
550
+
551
+ if (options.dryRun) {
552
+ console.log("\nāš ļø This was a dry run - no files were written");
553
+ }
554
+ }
555
+
556
+ // Run
557
+ main().catch((error) => {
558
+ console.error("āŒ Fatal error:", error.message);
559
+ process.exit(1);
560
+ });
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+
6
+ /**
7
+ * Script to generate MCP skills from docs/v7/*.mdx files
8
+ *
9
+ * This script reads the frontmatter from each mdx file and generates
10
+ * SKILL.md files in the skills/ output directory.
11
+ */
12
+
13
+ const DOCS_DIR = path.join(__dirname, "../v7");
14
+ const OUTPUT_DIR = path.join(__dirname, "../../ai/skills");
15
+
16
+ // Parse YAML frontmatter from mdx content
17
+ function parseFrontmatter(content) {
18
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
19
+ if (!frontmatterMatch) {
20
+ return { frontmatter: {}, body: content };
21
+ }
22
+
23
+ const frontmatterText = frontmatterMatch[1];
24
+ const body = content.slice(frontmatterMatch[0].length).trim();
25
+
26
+ // Simple YAML parser for our use case
27
+ const frontmatter = {};
28
+ const lines = frontmatterText.split("\n");
29
+ for (const line of lines) {
30
+ const match = line.match(/^(\w+):\s*"?([^"]*)"?\s*$/);
31
+ if (match) {
32
+ frontmatter[match[1]] = match[2];
33
+ }
34
+ }
35
+
36
+ return { frontmatter, body };
37
+ }
38
+
39
+ // Get skill name from filename (used in SKILL.md frontmatter)
40
+ function getSkillName(filename) {
41
+ return `testdriver:${filename.replace(".mdx", "")}`;
42
+ }
43
+
44
+ // Get directory name from filename (Windows-compatible, uses hyphen instead of colon)
45
+ function getDirName(filename) {
46
+ return `testdriver-${filename.replace(".mdx", "")}`;
47
+ }
48
+
49
+ // Generate SKILL.md content
50
+ function generateSkillContent(filename, frontmatter, body) {
51
+ const skillName = getSkillName(filename);
52
+ const description = frontmatter.description || frontmatter.sidebarTitle || filename.replace(".mdx", "");
53
+
54
+ return `---
55
+ name: ${skillName}
56
+ description: ${description}
57
+ ---
58
+ <!-- Generated from ${filename}. DO NOT EDIT. -->
59
+
60
+ ${body}
61
+ `;
62
+ }
63
+
64
+ // Process all mdx files
65
+ function processFiles() {
66
+ // Ensure output directory exists
67
+ if (!fs.existsSync(OUTPUT_DIR)) {
68
+ fs.mkdirSync(OUTPUT_DIR, { recursive: true });
69
+ }
70
+
71
+ const files = fs.readdirSync(DOCS_DIR);
72
+ const mdxFiles = files.filter(
73
+ (file) => file.endsWith(".mdx") && !file.startsWith("_")
74
+ );
75
+
76
+ console.log(`Found ${mdxFiles.length} mdx files to process\n`);
77
+
78
+ let generated = 0;
79
+ let errors = 0;
80
+
81
+ for (const file of mdxFiles) {
82
+ const filePath = path.join(DOCS_DIR, file);
83
+ const skillName = getSkillName(file);
84
+ const outputDir = path.join(OUTPUT_DIR, getDirName(file));
85
+ const outputPath = path.join(outputDir, "SKILL.md");
86
+
87
+ try {
88
+ const content = fs.readFileSync(filePath, "utf-8");
89
+ const { frontmatter, body } = parseFrontmatter(content);
90
+ const skillContent = generateSkillContent(file, frontmatter, body);
91
+
92
+ // Create skill directory
93
+ if (!fs.existsSync(outputDir)) {
94
+ fs.mkdirSync(outputDir, { recursive: true });
95
+ }
96
+
97
+ fs.writeFileSync(outputPath, skillContent, "utf-8");
98
+ console.log(`āœ… ${skillName}`);
99
+ generated++;
100
+ } catch (error) {
101
+ console.error(`āŒ ${file}: ${error.message}`);
102
+ errors++;
103
+ }
104
+ }
105
+
106
+ return { generated, errors };
107
+ }
108
+
109
+ // Main function
110
+ function main() {
111
+ console.log("šŸš€ Generating MCP skills from docs/v7/*.mdx files...\n");
112
+ console.log(`šŸ“‚ Source: ${DOCS_DIR}`);
113
+ console.log(`šŸ“‚ Output: ${OUTPUT_DIR}\n`);
114
+
115
+ const { generated, errors } = processFiles();
116
+
117
+ console.log(`\n✨ Complete!`);
118
+ console.log(` Generated: ${generated} skills`);
119
+ if (errors > 0) {
120
+ console.log(` Errors: ${errors}`);
121
+ }
122
+ console.log(`\nSkills written to: ${OUTPUT_DIR}`);
123
+ }
124
+
125
+ // Handle command line arguments
126
+ if (process.argv.includes("--help") || process.argv.includes("-h")) {
127
+ console.log(`
128
+ MCP Skills Generator
129
+
130
+ Usage: node generate-skills.js [options]
131
+
132
+ Options:
133
+ --help, -h Show this help message
134
+
135
+ Description:
136
+ This script generates MCP skill files from the docs/v7/*.mdx documentation.
137
+
138
+ Each .mdx file is converted to a SKILL.md file with:
139
+ - name: testdriver:<filename>
140
+ - description: from frontmatter
141
+ - Content: the mdx body
142
+
143
+ Output is written to the skills/ directory.
144
+ `);
145
+ process.exit(0);
146
+ }
147
+
148
+ // Run the script
149
+ try {
150
+ main();
151
+ } catch (error) {
152
+ console.error("āŒ Error:", error.message);
153
+ process.exit(1);
154
+ }