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.
- package/agent/index.js +77 -59
- package/agent/interface.js +11 -251
- package/agent/lib/debugger-server.js +2 -1
- package/agent/lib/logger.js +56 -0
- package/agent/lib/sandbox.js +79 -29
- package/ai/agents/test-writer.md +457 -0
- package/{docs/v7/ai.mdx → ai/skills/testdriver:ai/SKILL.md} +3 -5
- package/{docs/v7/assert.mdx → ai/skills/testdriver:assert/SKILL.md} +3 -4
- package/{docs/v7/aws-setup.mdx → ai/skills/testdriver:aws-setup/SKILL.md} +3 -4
- package/{docs/v7/caching.mdx → ai/skills/testdriver:caching/SKILL.md} +3 -7
- package/{docs/v7/captcha.mdx → ai/skills/testdriver:captcha/SKILL.md} +4 -5
- package/{docs/v7/ci-cd.mdx → ai/skills/testdriver:ci-cd/SKILL.md} +3 -4
- package/{docs/v7/click.mdx → ai/skills/testdriver:click/SKILL.md} +3 -4
- package/{docs/v7/client.mdx → ai/skills/testdriver:client/SKILL.md} +11 -5
- package/{docs/v7/cloud.mdx → ai/skills/testdriver:cloud/SKILL.md} +3 -4
- package/{docs/v7/customizing-devices.mdx → ai/skills/testdriver:customizing-devices/SKILL.md} +36 -26
- package/{docs/v7/dashcam.mdx → ai/skills/testdriver:dashcam/SKILL.md} +3 -4
- package/{docs/v7/device-config.mdx → ai/skills/testdriver:device-config/SKILL.md} +3 -3
- package/{docs/v7/double-click.mdx → ai/skills/testdriver:double-click/SKILL.md} +3 -3
- package/{docs/v7/elements.mdx → ai/skills/testdriver:elements/SKILL.md} +3 -4
- package/{docs/v7/enterprise.mdx → ai/skills/testdriver:enterprise/SKILL.md} +3 -5
- package/ai/skills/testdriver:examples/SKILL.md +7 -0
- package/{docs/v7/exec.mdx → ai/skills/testdriver:exec/SKILL.md} +3 -4
- package/{docs/v7/find.mdx → ai/skills/testdriver:find/SKILL.md} +81 -4
- package/{docs/v7/focus-application.mdx → ai/skills/testdriver:focus-application/SKILL.md} +3 -4
- package/{docs/v7/generating-tests.mdx → ai/skills/testdriver:generating-tests/SKILL.md} +3 -3
- package/{docs/v7/hover.mdx → ai/skills/testdriver:hover/SKILL.md} +3 -4
- package/{docs/v7/locating-elements.mdx → ai/skills/testdriver:locating-elements/SKILL.md} +3 -3
- package/{docs/v7/making-assertions.mdx → ai/skills/testdriver:making-assertions/SKILL.md} +3 -3
- package/ai/skills/testdriver:mcp-workflow/SKILL.md +410 -0
- package/{docs/v7/mouse-down.mdx → ai/skills/testdriver:mouse-down/SKILL.md} +3 -3
- package/{docs/v7/mouse-up.mdx → ai/skills/testdriver:mouse-up/SKILL.md} +3 -3
- package/{docs/v7/performing-actions.mdx → ai/skills/testdriver:performing-actions/SKILL.md} +3 -3
- package/{docs/v7/press-keys.mdx → ai/skills/testdriver:press-keys/SKILL.md} +3 -4
- package/{docs/v7/quickstart.mdx → ai/skills/testdriver:quickstart/SKILL.md} +3 -4
- package/{docs/v7/reusable-code.mdx → ai/skills/testdriver:reusable-code/SKILL.md} +3 -3
- package/{docs/v7/right-click.mdx → ai/skills/testdriver:right-click/SKILL.md} +3 -3
- package/{docs/v7/running-tests.mdx → ai/skills/testdriver:running-tests/SKILL.md} +3 -3
- package/{docs/v7/screenshot.mdx → ai/skills/testdriver:screenshot/SKILL.md} +3 -4
- package/{docs/v7/scroll.mdx → ai/skills/testdriver:scroll/SKILL.md} +3 -4
- package/{docs/v7/secrets.mdx → ai/skills/testdriver:secrets/SKILL.md} +3 -3
- package/{docs/v7/self-hosted.mdx → ai/skills/testdriver:self-hosted/SKILL.md} +3 -4
- package/ai/skills/testdriver:testdriver/SKILL.md +31 -0
- package/{docs/v7/type.mdx → ai/skills/testdriver:type/SKILL.md} +3 -4
- package/{docs/v7/variables.mdx → ai/skills/testdriver:variables/SKILL.md} +3 -3
- package/{docs/v7/waiting-for-elements.mdx → ai/skills/testdriver:waiting-for-elements/SKILL.md} +3 -3
- package/{docs/v7/what-is-testdriver.mdx → ai/skills/testdriver:what-is-testdriver/SKILL.md} +3 -3
- package/interfaces/cli/commands/init.js +278 -1
- package/interfaces/cli/commands/setup.js +382 -0
- package/interfaces/vitest-plugin.mjs +190 -122
- package/lib/core/Dashcam.js +22 -15
- package/lib/sentry.js +4 -3
- package/lib/vitest/hooks.mjs +70 -16
- package/lib/vitest/setup-aws.mjs +0 -10
- package/package.json +29 -9
- package/sdk.d.ts +32 -5
- package/sdk.js +10 -9
- package/.env.example +0 -4
- package/.github/workflows/acceptance-linux-scheduled.yaml +0 -45
- package/.github/workflows/acceptance-windows-scheduled.yaml +0 -54
- package/.github/workflows/acceptance.yaml +0 -87
- package/.github/workflows/publish.yaml +0 -68
- package/.github/workflows/test-init.yml +0 -145
- package/.github/workflows/testdriver.yml +0 -170
- package/.github/workflows/windows-self-hosted.yaml +0 -82
- package/.prettierignore +0 -4
- package/.prettierrc +0 -1
- package/CHANGELOG.md +0 -30
- package/agents.md +0 -455
- package/debugger/bg.png +0 -0
- package/debugger/icon.png +0 -0
- package/debugger/index.html +0 -797
- package/debugger/td.png +0 -0
- package/debugger/tray-buffered.png +0 -0
- package/debugger/tray.png +0 -0
- package/docs/GITHUB_COMMENTS.md +0 -330
- package/docs/GITHUB_COMMENTS_ANNOUNCEMENT.md +0 -167
- package/docs/QUICK-START-GITHUB-COMMENTS.md +0 -84
- package/docs/TEST-GITHUB-COMMENTS.md +0 -129
- package/docs/_scripts/link-replacer.js +0 -164
- package/docs/_scripts/upload-docs-to-openai.js +0 -284
- package/docs/docs.json +0 -393
- package/docs/github-integration-setup.md +0 -266
- package/docs/guide/best-practices-polling.mdx +0 -154
- package/docs/images/content/account/newprojectsettings.png +0 -0
- package/docs/images/content/account/projectpage.png +0 -0
- package/docs/images/content/account/projectreplays.png +0 -0
- package/docs/images/content/account/team-manage.png +0 -0
- package/docs/images/content/account/teampage.png +0 -0
- package/docs/images/content/extension/cursor.svg +0 -1
- package/docs/images/content/extension/vscode.svg +0 -57
- package/docs/images/content/extension/windsurf.svg +0 -3
- package/docs/images/content/self-hosted/launchtemplateid.png +0 -0
- package/docs/images/content/side-by-side.png +0 -0
- package/docs/images/content/vscode/ide-full.png +0 -0
- package/docs/images/content/vscode/running.png +0 -0
- package/docs/images/content/vscode/vscode-2-assert.png +0 -0
- package/docs/images/content/vscode/vscode-agent-preview.png +0 -0
- package/docs/images/content/vscode/vscode-copilot-ask.png +0 -0
- package/docs/images/content/vscode/vscode-file-creation.png +0 -0
- package/docs/images/content/vscode/vscode-install.png +0 -0
- package/docs/images/content/vscode/vscode-overview.png +0 -0
- package/docs/images/content/vscode/vscode-setup-walkthrough.png +0 -0
- package/docs/images/content/vscode/vscode-stopchat.png +0 -0
- package/docs/images/content/vscode/vscode-stoptest.png +0 -0
- package/docs/images/content/vscode/vscode-tdservice.png +0 -0
- package/docs/images/content/vscode/vscode-test-output.png +0 -0
- package/docs/images/content/vscode/vscode-testhistory.png +0 -0
- package/docs/images/content/vscode/vscode-testpane-runtests.png +0 -0
- package/docs/images/content/vscode/vscode-testpane.png +0 -0
- package/docs/images/template/dark.png +0 -0
- package/docs/images/template/icon.png +0 -0
- package/docs/images/template/light.png +0 -0
- package/docs/snippets/calendar-link.mdx +0 -4
- package/docs/snippets/gitignore-warning.mdx +0 -7
- package/docs/snippets/lifecycle-warning.mdx +0 -6
- package/docs/snippets/test-prereqs.mdx +0 -12
- package/docs/snippets/tests/assert-replay.mdx +0 -7
- package/docs/snippets/tests/assert-yaml.mdx +0 -8
- package/docs/snippets/tests/exec-js-replay.mdx +0 -7
- package/docs/snippets/tests/exec-js-yaml.mdx +0 -32
- package/docs/snippets/tests/exec-shell-replay.mdx +0 -7
- package/docs/snippets/tests/exec-shell-yaml.mdx +0 -15
- package/docs/snippets/tests/hover-image-replay.mdx +0 -7
- package/docs/snippets/tests/hover-image-yaml.mdx +0 -17
- package/docs/snippets/tests/hover-text-replay.mdx +0 -7
- package/docs/snippets/tests/hover-text-with-description-replay.mdx +0 -7
- package/docs/snippets/tests/hover-text-with-description-yaml.mdx +0 -24
- package/docs/snippets/tests/hover-text-yaml.mdx +0 -14
- package/docs/snippets/tests/match-image-replay.mdx +0 -7
- package/docs/snippets/tests/match-image-yaml.mdx +0 -17
- package/docs/snippets/tests/press-keys-replay.mdx +0 -7
- package/docs/snippets/tests/press-keys-yaml.mdx +0 -36
- package/docs/snippets/tests/remember-replay.mdx +0 -7
- package/docs/snippets/tests/remember-yaml.mdx +0 -28
- package/docs/snippets/tests/scroll-replay.mdx +0 -7
- package/docs/snippets/tests/scroll-until-image-replay.mdx +0 -7
- package/docs/snippets/tests/scroll-until-image-yaml.mdx +0 -14
- package/docs/snippets/tests/scroll-until-text-replay.mdx +0 -7
- package/docs/snippets/tests/scroll-until-text-yaml.mdx +0 -17
- package/docs/snippets/tests/scroll-yaml.mdx +0 -30
- package/docs/snippets/tests/type-repeated-replay.mdx +0 -7
- package/docs/snippets/tests/type-repeated-yaml.mdx +0 -22
- package/docs/snippets/tests/type-replay.mdx +0 -7
- package/docs/snippets/tests/type-yaml.mdx +0 -28
- package/docs/snippets/tests/wait-for-image-replay.mdx +0 -7
- package/docs/snippets/tests/wait-for-image-yaml.mdx +0 -18
- package/docs/snippets/tests/wait-for-text-replay.mdx +0 -7
- package/docs/snippets/tests/wait-for-text-yaml.mdx +0 -18
- package/docs/snippets/tests/wait-replay.mdx +0 -7
- package/docs/snippets/tests/wait-yaml.mdx +0 -13
- package/docs/styles.css +0 -65
- package/docs/v6/account/dashboard.mdx +0 -16
- package/docs/v6/account/enterprise.mdx +0 -110
- package/docs/v6/account/pricing.mdx +0 -33
- package/docs/v6/account/projects.mdx +0 -33
- package/docs/v6/account/team.mdx +0 -35
- package/docs/v6/action/ami.mdx +0 -109
- package/docs/v6/action/performance.mdx +0 -105
- package/docs/v6/action/secrets.mdx +0 -93
- package/docs/v6/apps/chrome-extensions.mdx +0 -48
- package/docs/v6/apps/desktop-apps.mdx +0 -93
- package/docs/v6/apps/mobile-apps.mdx +0 -26
- package/docs/v6/apps/static-websites.mdx +0 -54
- package/docs/v6/apps/tauri-apps.mdx +0 -361
- package/docs/v6/bugs/jira.mdx +0 -232
- package/docs/v6/cli/overview.mdx +0 -66
- package/docs/v6/commands/assert.mdx +0 -45
- package/docs/v6/commands/exec.mdx +0 -282
- package/docs/v6/commands/focus-application.mdx +0 -44
- package/docs/v6/commands/hover-image.mdx +0 -69
- package/docs/v6/commands/hover-text.mdx +0 -47
- package/docs/v6/commands/if.mdx +0 -53
- package/docs/v6/commands/match-image.mdx +0 -67
- package/docs/v6/commands/press-keys.mdx +0 -87
- package/docs/v6/commands/remember.mdx +0 -49
- package/docs/v6/commands/run.mdx +0 -44
- package/docs/v6/commands/scroll-until-image.mdx +0 -66
- package/docs/v6/commands/scroll-until-text.mdx +0 -60
- package/docs/v6/commands/scroll.mdx +0 -69
- package/docs/v6/commands/type.mdx +0 -45
- package/docs/v6/commands/wait-for-image.mdx +0 -54
- package/docs/v6/commands/wait-for-text.mdx +0 -48
- package/docs/v6/commands/wait.mdx +0 -45
- package/docs/v6/exporting/junit.mdx +0 -218
- package/docs/v6/exporting/playwright.mdx +0 -197
- package/docs/v6/features/auto-healing.mdx +0 -144
- package/docs/v6/features/generation.mdx +0 -116
- package/docs/v6/features/parallel-testing.mdx +0 -151
- package/docs/v6/features/reusable-snippets.mdx +0 -131
- package/docs/v6/features/selectorless.mdx +0 -80
- package/docs/v6/features/visual-assertions.mdx +0 -139
- package/docs/v6/getting-started/ci.mdx +0 -146
- package/docs/v6/getting-started/cli.mdx +0 -91
- package/docs/v6/getting-started/editing.mdx +0 -100
- package/docs/v6/getting-started/playwright.mdx +0 -342
- package/docs/v6/getting-started/running.mdx +0 -48
- package/docs/v6/getting-started/self-hosting.mdx +0 -408
- package/docs/v6/getting-started/vscode.mdx +0 -89
- package/docs/v6/guide/assertions.mdx +0 -189
- package/docs/v6/guide/authentication.mdx +0 -136
- package/docs/v6/guide/code.mdx +0 -65
- package/docs/v6/guide/dashcam.mdx +0 -118
- package/docs/v6/guide/environment-variables.mdx +0 -26
- package/docs/v6/guide/lifecycle.mdx +0 -242
- package/docs/v6/guide/locating.mdx +0 -141
- package/docs/v6/guide/protips.mdx +0 -43
- package/docs/v6/guide/variables.mdx +0 -143
- package/docs/v6/guide/waiting.mdx +0 -130
- package/docs/v6/importing/csv.mdx +0 -196
- package/docs/v6/importing/gherkin.mdx +0 -143
- package/docs/v6/importing/jira.mdx +0 -164
- package/docs/v6/importing/testrail.mdx +0 -162
- package/docs/v6/integrations/electron.mdx +0 -146
- package/docs/v6/integrations/netlify.mdx +0 -100
- package/docs/v6/integrations/vercel.mdx +0 -125
- package/docs/v6/interactive/explore.mdx +0 -99
- package/docs/v6/interactive/run.mdx +0 -52
- package/docs/v6/interactive/save.mdx +0 -63
- package/docs/v6/overview/comparison.mdx +0 -101
- package/docs/v6/overview/faq.mdx +0 -162
- package/docs/v6/overview/performance.mdx +0 -52
- package/docs/v6/overview/quickstart.mdx +0 -137
- package/docs/v6/overview/what-is-testdriver.mdx +0 -85
- package/docs/v6/scenarios/ai-chatbot.mdx +0 -28
- package/docs/v6/scenarios/cookie-banner.mdx +0 -32
- package/docs/v6/scenarios/file-upload.mdx +0 -33
- package/docs/v6/scenarios/form-filling.mdx +0 -32
- package/docs/v6/scenarios/log-in.mdx +0 -75
- package/docs/v6/scenarios/pdf-generation.mdx +0 -25
- package/docs/v6/scenarios/spell-check.mdx +0 -22
- package/docs/v6/security/action.mdx +0 -84
- package/docs/v6/security/agent.mdx +0 -73
- package/docs/v6/security/platform.mdx +0 -77
- package/docs/v6/tutorials/advanced-test.mdx +0 -81
- package/docs/v6/tutorials/basic-test.mdx +0 -45
- package/docs/v7/_drafts/agents.mdx +0 -852
- package/docs/v7/_drafts/architecture.mdx +0 -399
- package/docs/v7/_drafts/auto-cache-key.mdx +0 -167
- package/docs/v7/_drafts/awesome-logs-quick-ref.mdx +0 -100
- package/docs/v7/_drafts/best-practices.mdx +0 -486
- package/docs/v7/_drafts/caching-ai.mdx +0 -215
- package/docs/v7/_drafts/caching-selectors.mdx +0 -424
- package/docs/v7/_drafts/caching.mdx +0 -366
- package/docs/v7/_drafts/cli-to-sdk-migration.mdx +0 -425
- package/docs/v7/_drafts/commands/assert.mdx +0 -45
- package/docs/v7/_drafts/commands/exec.mdx +0 -282
- package/docs/v7/_drafts/commands/focus-application.mdx +0 -44
- package/docs/v7/_drafts/commands/hover-image.mdx +0 -69
- package/docs/v7/_drafts/commands/hover-text.mdx +0 -47
- package/docs/v7/_drafts/commands/if.mdx +0 -53
- package/docs/v7/_drafts/commands/match-image.mdx +0 -67
- package/docs/v7/_drafts/commands/press-keys.mdx +0 -87
- package/docs/v7/_drafts/commands/remember.mdx +0 -49
- package/docs/v7/_drafts/commands/run.mdx +0 -44
- package/docs/v7/_drafts/commands/scroll-until-image.mdx +0 -66
- package/docs/v7/_drafts/commands/scroll-until-text.mdx +0 -60
- package/docs/v7/_drafts/commands/scroll.mdx +0 -69
- package/docs/v7/_drafts/commands/type.mdx +0 -45
- package/docs/v7/_drafts/commands/wait-for-image.mdx +0 -54
- package/docs/v7/_drafts/commands/wait-for-text.mdx +0 -48
- package/docs/v7/_drafts/commands/wait.mdx +0 -45
- package/docs/v7/_drafts/configuration.mdx +0 -378
- package/docs/v7/_drafts/contributing.mdx +0 -174
- package/docs/v7/_drafts/core.mdx +0 -458
- package/docs/v7/_drafts/dashcam-title-feature.mdx +0 -89
- package/docs/v7/_drafts/debugging.mdx +0 -349
- package/docs/v7/_drafts/error-handling.mdx +0 -501
- package/docs/v7/_drafts/faq.mdx +0 -393
- package/docs/v7/_drafts/hooks.mdx +0 -360
- package/docs/v7/_drafts/init-command.mdx +0 -95
- package/docs/v7/_drafts/installation.mdx +0 -420
- package/docs/v7/_drafts/migration.mdx +0 -562
- package/docs/v7/_drafts/observable.mdx +0 -604
- package/docs/v7/_drafts/playwright.mdx +0 -342
- package/docs/v7/_drafts/plugin-migration.mdx +0 -220
- package/docs/v7/_drafts/powerful.mdx +0 -419
- package/docs/v7/_drafts/presets.mdx +0 -210
- package/docs/v7/_drafts/progressive-disclosure.mdx +0 -230
- package/docs/v7/_drafts/prompt-cache.mdx +0 -200
- package/docs/v7/_drafts/provision.mdx +0 -390
- package/docs/v7/_drafts/quick-start-test-recording.mdx +0 -214
- package/docs/v7/_drafts/readme.mdx +0 -135
- package/docs/v7/_drafts/reports.mdx +0 -414
- package/docs/v7/_drafts/scalable.mdx +0 -754
- package/docs/v7/_drafts/screenshot.mdx +0 -155
- package/docs/v7/_drafts/sdk-awesome-logs.mdx +0 -468
- package/docs/v7/_drafts/sdk-browser-rendering.mdx +0 -167
- package/docs/v7/_drafts/sdk-migration.mdx +0 -474
- package/docs/v7/_drafts/sdk-v7-complete.mdx +0 -345
- package/docs/v7/_drafts/self-hosting.mdx +0 -369
- package/docs/v7/_drafts/test-recording.mdx +0 -382
- package/docs/v7/_drafts/troubleshooting.mdx +0 -526
- package/docs/v7/_drafts/vitest-plugin.mdx +0 -477
- package/docs/v7/_drafts/vitest.mdx +0 -535
- package/docs/v7/_drafts/writing-tests.mdx +0 -25
- package/docs/v7/examples.mdx +0 -5
- package/eslint.config.js +0 -67
- package/examples/ai.test.mjs +0 -30
- package/examples/assert.test.mjs +0 -46
- package/examples/captcha-api.test.mjs +0 -50
- package/examples/chrome-extension.test.mjs +0 -94
- package/examples/drag-and-drop.test.mjs +0 -58
- package/examples/element-not-found.test.mjs +0 -26
- package/examples/exec-output.test.mjs +0 -59
- package/examples/exec-pwsh.test.mjs +0 -57
- package/examples/focus-window.test.mjs +0 -36
- package/examples/formatted-logging.test.mjs +0 -26
- package/examples/hover-image.test.mjs +0 -52
- package/examples/hover-text-with-description.test.mjs +0 -56
- package/examples/hover-text.test.mjs +0 -27
- package/examples/installer.test.mjs +0 -49
- package/examples/launch-vscode-linux.test.mjs +0 -54
- package/examples/match-image.test.mjs +0 -54
- package/examples/no-provision.test.mjs +0 -23
- package/examples/press-keys.test.mjs +0 -50
- package/examples/prompt.test.mjs +0 -33
- package/examples/scroll-keyboard.test.mjs +0 -37
- package/examples/scroll-until-image.test.mjs +0 -39
- package/examples/scroll-until-text.test.mjs +0 -67
- package/examples/scroll.test.mjs +0 -41
- package/examples/type.test.mjs +0 -45
- package/examples/windows-installer.test.mjs +0 -53
- package/interfaces/cli/commands/edit.js +0 -3
- package/interfaces/cli/commands/generate.js +0 -3
- package/interfaces/cli/commands/run.js +0 -3
- package/interfaces/cli/utils/factory.js +0 -71
- package/jsconfig.json +0 -26
- package/manual/test-init-command.js +0 -223
- package/sdk-log-formatter.js +0 -930
- package/setup/aws/cloudformation.yaml +0 -470
- package/setup/aws/spawn-runner.sh +0 -190
- package/test/api-resilience.test.mjs +0 -0
- package/test/captcha-solver.test.mjs +0 -70
- package/test/chrome-remote-debugging.test.mjs +0 -66
- package/test/manual/debug-locate-response.js +0 -82
- package/test/manual/reconnect-provision.test.mjs +0 -49
- package/test/manual/test-console-logs.test.mjs +0 -42
- package/test/manual/test-find-api.js +0 -73
- package/test/manual/test-init.sh +0 -54
- package/test/manual/test-prompt-cache.js +0 -96
- package/test/manual/test-provision-auth.mjs +0 -22
- package/test/manual/test-sandbox-render.js +0 -28
- package/test/manual/test-sdk-methods.js +0 -15
- package/test/manual/test-sdk-refactor.js +0 -53
- package/test/manual/test-stack-trace.mjs +0 -57
- package/test/manual/verify-element-api.js +0 -89
- package/test/manual/verify-types.js +0 -0
- package/test/manual-unawaited-promise.test.mjs +0 -31
- package/testdriver-plugin/skills/actions/SKILL.md +0 -93
- package/testdriver-plugin/skills/assertions/SKILL.md +0 -77
- package/testdriver-plugin/skills/caching/SKILL.md +0 -66
- package/testdriver-plugin/skills/creating-tests/SKILL.md +0 -104
- package/testdriver-plugin/skills/finding-elements/SKILL.md +0 -77
- package/testdriver-plugin/skills/github-actions/SKILL.md +0 -100
- package/testdriver-plugin/skills/running-tests/SKILL.md +0 -77
- package/testdriver-plugin/skills/secrets/SKILL.md +0 -87
- package/testdriver-plugin/skills/self-hosting/SKILL.md +0 -89
- package/testdriver-plugin/skills/setup/SKILL.md +0 -76
- package/testdriver-plugin/skills/variables/SKILL.md +0 -88
- package/testdriver-plugin/skills/waiting/SKILL.md +0 -72
- 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
|
-
|
|
114
|
-
|
|
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(
|
|
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
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
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
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
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
|
-
|
|
991
|
+
logger.log("Created generate directory:", generateDir);
|
|
992
992
|
} else {
|
|
993
|
-
|
|
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(),
|
|
1630
|
-
return path.join(testdriverDir,
|
|
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 ||
|
|
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") +
|
|
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 =
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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 ===
|
|
2126
|
+
if (response.type === "create.queued") {
|
|
2116
2127
|
this.emitter.emit(
|
|
2117
2128
|
events.log.narration,
|
|
2118
|
-
formatter.getPrefix("queue") +
|
|
2119
|
-
|
|
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
|
|
2145
|
-
|
|
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 {
|
package/agent/interface.js
CHANGED
|
@@ -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
|
-
|
|
26
|
-
description: "
|
|
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
|
-
|
|
214
|
-
|
|
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
|
-
|
|
263
|
-
description:
|
|
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
|
-
|
|
268
|
-
|
|
269
|
-
|
|
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
|
-
|
|
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
|
+
};
|