@testdriverai/agent 7.8.0-test.38
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/.claude/settings.local.json +7 -0
- package/.env.example +4 -0
- package/.prettierignore +4 -0
- package/.prettierrc +1 -0
- package/CHANGELOG.md +953 -0
- package/README.md +81 -0
- package/agent/events.js +135 -0
- package/agent/index.js +2450 -0
- package/agent/interface.js +35 -0
- package/agent/lib/analytics.js +22 -0
- package/agent/lib/censorship.js +75 -0
- package/agent/lib/commander.js +246 -0
- package/agent/lib/commands.js +1684 -0
- package/agent/lib/config.js +60 -0
- package/agent/lib/generator.js +91 -0
- package/agent/lib/http.js +144 -0
- package/agent/lib/logger.js +56 -0
- package/agent/lib/outputs.js +29 -0
- package/agent/lib/parser.js +209 -0
- package/agent/lib/redraw.js +386 -0
- package/agent/lib/resources/cursor-2.png +0 -0
- package/agent/lib/sandbox.js +1104 -0
- package/agent/lib/sdk.js +633 -0
- package/agent/lib/session.js +25 -0
- package/agent/lib/source-mapper.js +342 -0
- package/agent/lib/subimage/index.js +77 -0
- package/agent/lib/subimage/opencv.js +69 -0
- package/agent/lib/system.js +204 -0
- package/agent/lib/theme.js +14 -0
- package/agent/lib/valid-version.js +21 -0
- package/agent/lib/validation.js +169 -0
- package/ai/.claude-plugin/plugin.json +9 -0
- package/ai/agents/testdriver.md +638 -0
- package/ai/skills/testdriver-ai/SKILL.md +204 -0
- package/ai/skills/testdriver-assert/SKILL.md +315 -0
- package/ai/skills/testdriver-aws-setup/SKILL.md +448 -0
- package/ai/skills/testdriver-cache/SKILL.md +221 -0
- package/ai/skills/testdriver-caching/SKILL.md +124 -0
- package/ai/skills/testdriver-captcha/SKILL.md +158 -0
- package/ai/skills/testdriver-ci-cd/SKILL.md +602 -0
- package/ai/skills/testdriver-click/SKILL.md +286 -0
- package/ai/skills/testdriver-client/SKILL.md +477 -0
- package/ai/skills/testdriver-cloud/SKILL.md +119 -0
- package/ai/skills/testdriver-customizing-devices/SKILL.md +319 -0
- package/ai/skills/testdriver-dashcam/SKILL.md +418 -0
- package/ai/skills/testdriver-debugging-with-screenshots/SKILL.md +401 -0
- package/ai/skills/testdriver-device-config/SKILL.md +317 -0
- package/ai/skills/testdriver-double-click/SKILL.md +102 -0
- package/ai/skills/testdriver-elements/SKILL.md +605 -0
- package/ai/skills/testdriver-enterprise/SKILL.md +114 -0
- package/ai/skills/testdriver-errors/SKILL.md +246 -0
- package/ai/skills/testdriver-events/SKILL.md +356 -0
- package/ai/skills/testdriver-examples/SKILL.md +7 -0
- package/ai/skills/testdriver-exec/SKILL.md +317 -0
- package/ai/skills/testdriver-find/SKILL.md +829 -0
- package/ai/skills/testdriver-focus-application/SKILL.md +293 -0
- package/ai/skills/testdriver-generating-tests/SKILL.md +36 -0
- package/ai/skills/testdriver-hover/SKILL.md +278 -0
- package/ai/skills/testdriver-locating-elements/SKILL.md +71 -0
- package/ai/skills/testdriver-making-assertions/SKILL.md +32 -0
- package/ai/skills/testdriver-mcp/SKILL.md +7 -0
- package/ai/skills/testdriver-mcp-workflow/SKILL.md +410 -0
- package/ai/skills/testdriver-mouse-down/SKILL.md +161 -0
- package/ai/skills/testdriver-mouse-up/SKILL.md +164 -0
- package/ai/skills/testdriver-parse/SKILL.md +236 -0
- package/ai/skills/testdriver-performing-actions/SKILL.md +54 -0
- package/ai/skills/testdriver-press-keys/SKILL.md +348 -0
- package/ai/skills/testdriver-provision/SKILL.md +331 -0
- package/ai/skills/testdriver-quickstart/SKILL.md +144 -0
- package/ai/skills/testdriver-redraw/SKILL.md +214 -0
- package/ai/skills/testdriver-reusable-code/SKILL.md +249 -0
- package/ai/skills/testdriver-right-click/SKILL.md +123 -0
- package/ai/skills/testdriver-running-tests/SKILL.md +185 -0
- package/ai/skills/testdriver-screenshot/SKILL.md +248 -0
- package/ai/skills/testdriver-screenshots/SKILL.md +184 -0
- package/ai/skills/testdriver-scroll/SKILL.md +335 -0
- package/ai/skills/testdriver-secrets/SKILL.md +115 -0
- package/ai/skills/testdriver-self-hosted/SKILL.md +65 -0
- package/ai/skills/testdriver-test-writer/SKILL.md +448 -0
- package/ai/skills/testdriver-testdriver/SKILL.md +628 -0
- package/ai/skills/testdriver-testdriver-mechanic/SKILL.md +165 -0
- package/ai/skills/testdriver-type/SKILL.md +357 -0
- package/ai/skills/testdriver-variables/SKILL.md +111 -0
- package/ai/skills/testdriver-wait/SKILL.md +50 -0
- package/ai/skills/testdriver-waiting-for-elements/SKILL.md +90 -0
- package/ai/skills/testdriver-what-is-testdriver/SKILL.md +54 -0
- package/bin/testdriverai.js +22 -0
- package/debugger/bg.png +0 -0
- package/debugger/icon.png +0 -0
- package/debugger/index.html +469 -0
- package/debugger/td.png +0 -0
- package/debugger/tray-buffered.png +0 -0
- package/debugger/tray.png +0 -0
- package/docs/GITHUB_COMMENTS.md +330 -0
- package/docs/GITHUB_COMMENTS_ANNOUNCEMENT.md +167 -0
- package/docs/QUICK-START-GITHUB-COMMENTS.md +84 -0
- package/docs/TEST-GITHUB-COMMENTS.md +129 -0
- package/docs/_data/examples-manifest.json +177 -0
- package/docs/_data/examples-manifest.schema.json +41 -0
- package/docs/_scripts/extract-example-urls.js +165 -0
- package/docs/_scripts/generate-examples.js +560 -0
- package/docs/_scripts/generate-skills.js +154 -0
- package/docs/_scripts/link-replacer.js +164 -0
- package/docs/_scripts/upload-docs-to-openai.js +284 -0
- package/docs/changelog.mdx +161 -0
- package/docs/claude-mcp-plugin.mdx +160 -0
- package/docs/docs.json +442 -0
- package/docs/github-integration-setup.md +266 -0
- package/docs/guide/best-practices-polling.mdx +174 -0
- 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 +1 -0
- package/docs/images/content/extension/vscode.svg +57 -0
- package/docs/images/content/extension/windsurf.svg +3 -0
- package/docs/images/content/parse/output.png +0 -0
- 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/v7-chat.png +0 -0
- package/docs/images/content/vscode/v7-choose-agent.png +0 -0
- package/docs/images/content/vscode/v7-full.png +0 -0
- package/docs/images/content/vscode/v7-onboarding.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 +4 -0
- package/docs/snippets/gitignore-warning.mdx +7 -0
- package/docs/snippets/lifecycle-warning.mdx +6 -0
- package/docs/snippets/test-prereqs.mdx +12 -0
- package/docs/snippets/tests/assert-replay.mdx +7 -0
- package/docs/snippets/tests/assert-yaml.mdx +8 -0
- package/docs/snippets/tests/exec-js-replay.mdx +7 -0
- package/docs/snippets/tests/exec-js-yaml.mdx +32 -0
- package/docs/snippets/tests/exec-shell-replay.mdx +7 -0
- package/docs/snippets/tests/exec-shell-yaml.mdx +15 -0
- package/docs/snippets/tests/hover-image-replay.mdx +7 -0
- package/docs/snippets/tests/hover-image-yaml.mdx +17 -0
- package/docs/snippets/tests/hover-text-replay.mdx +7 -0
- package/docs/snippets/tests/hover-text-with-description-replay.mdx +7 -0
- package/docs/snippets/tests/hover-text-with-description-yaml.mdx +24 -0
- package/docs/snippets/tests/hover-text-yaml.mdx +14 -0
- package/docs/snippets/tests/match-image-replay.mdx +7 -0
- package/docs/snippets/tests/match-image-yaml.mdx +17 -0
- package/docs/snippets/tests/press-keys-replay.mdx +7 -0
- package/docs/snippets/tests/press-keys-yaml.mdx +36 -0
- package/docs/snippets/tests/remember-replay.mdx +7 -0
- package/docs/snippets/tests/remember-yaml.mdx +28 -0
- package/docs/snippets/tests/scroll-replay.mdx +7 -0
- package/docs/snippets/tests/scroll-until-image-replay.mdx +7 -0
- package/docs/snippets/tests/scroll-until-image-yaml.mdx +14 -0
- package/docs/snippets/tests/scroll-until-text-replay.mdx +7 -0
- package/docs/snippets/tests/scroll-until-text-yaml.mdx +17 -0
- package/docs/snippets/tests/scroll-yaml.mdx +30 -0
- package/docs/snippets/tests/type-repeated-replay.mdx +7 -0
- package/docs/snippets/tests/type-repeated-yaml.mdx +22 -0
- package/docs/snippets/tests/type-replay.mdx +7 -0
- package/docs/snippets/tests/type-yaml.mdx +28 -0
- package/docs/snippets/tests/wait-for-image-replay.mdx +7 -0
- package/docs/snippets/tests/wait-for-image-yaml.mdx +18 -0
- package/docs/snippets/tests/wait-for-text-replay.mdx +7 -0
- package/docs/snippets/tests/wait-for-text-yaml.mdx +18 -0
- package/docs/snippets/tests/wait-replay.mdx +7 -0
- package/docs/snippets/tests/wait-yaml.mdx +13 -0
- package/docs/styles.css +65 -0
- package/docs/v6/account/dashboard.mdx +16 -0
- package/docs/v6/account/enterprise.mdx +110 -0
- package/docs/v6/account/pricing.mdx +33 -0
- package/docs/v6/account/projects.mdx +33 -0
- package/docs/v6/account/team.mdx +35 -0
- package/docs/v6/action/ami.mdx +109 -0
- package/docs/v6/action/performance.mdx +105 -0
- package/docs/v6/action/secrets.mdx +93 -0
- package/docs/v6/apps/chrome-extensions.mdx +48 -0
- package/docs/v6/apps/desktop-apps.mdx +93 -0
- package/docs/v6/apps/mobile-apps.mdx +26 -0
- package/docs/v6/apps/static-websites.mdx +54 -0
- package/docs/v6/apps/tauri-apps.mdx +361 -0
- package/docs/v6/bugs/jira.mdx +232 -0
- package/docs/v6/cli/overview.mdx +66 -0
- package/docs/v6/commands/assert.mdx +45 -0
- package/docs/v6/commands/exec.mdx +276 -0
- package/docs/v6/commands/focus-application.mdx +44 -0
- package/docs/v6/commands/hover-image.mdx +69 -0
- package/docs/v6/commands/hover-text.mdx +47 -0
- package/docs/v6/commands/if.mdx +53 -0
- package/docs/v6/commands/match-image.mdx +67 -0
- package/docs/v6/commands/press-keys.mdx +87 -0
- package/docs/v6/commands/remember.mdx +49 -0
- package/docs/v6/commands/run.mdx +44 -0
- package/docs/v6/commands/scroll-until-image.mdx +66 -0
- package/docs/v6/commands/scroll-until-text.mdx +60 -0
- package/docs/v6/commands/scroll.mdx +69 -0
- package/docs/v6/commands/type.mdx +45 -0
- package/docs/v6/commands/wait-for-image.mdx +54 -0
- package/docs/v6/commands/wait-for-text.mdx +48 -0
- package/docs/v6/commands/wait.mdx +45 -0
- package/docs/v6/exporting/junit.mdx +218 -0
- package/docs/v6/exporting/playwright.mdx +197 -0
- package/docs/v6/features/auto-healing.mdx +144 -0
- package/docs/v6/features/generation.mdx +116 -0
- package/docs/v6/features/parallel-testing.mdx +151 -0
- package/docs/v6/features/reusable-snippets.mdx +131 -0
- package/docs/v6/features/selectorless.mdx +80 -0
- package/docs/v6/features/visual-assertions.mdx +139 -0
- package/docs/v6/getting-started/ci.mdx +146 -0
- package/docs/v6/getting-started/cli.mdx +91 -0
- package/docs/v6/getting-started/editing.mdx +100 -0
- package/docs/v6/getting-started/playwright.mdx +342 -0
- package/docs/v6/getting-started/running.mdx +48 -0
- package/docs/v6/getting-started/self-hosting.mdx +408 -0
- package/docs/v6/getting-started/vscode.mdx +88 -0
- package/docs/v6/guide/assertions.mdx +189 -0
- package/docs/v6/guide/authentication.mdx +136 -0
- package/docs/v6/guide/code.mdx +65 -0
- package/docs/v6/guide/dashcam.mdx +118 -0
- package/docs/v6/guide/environment-variables.mdx +26 -0
- package/docs/v6/guide/lifecycle.mdx +242 -0
- package/docs/v6/guide/locating.mdx +141 -0
- package/docs/v6/guide/protips.mdx +43 -0
- package/docs/v6/guide/variables.mdx +143 -0
- package/docs/v6/guide/waiting.mdx +130 -0
- package/docs/v6/importing/csv.mdx +196 -0
- package/docs/v6/importing/gherkin.mdx +143 -0
- package/docs/v6/importing/jira.mdx +164 -0
- package/docs/v6/importing/testrail.mdx +162 -0
- package/docs/v6/integrations/electron.mdx +146 -0
- package/docs/v6/integrations/netlify.mdx +100 -0
- package/docs/v6/integrations/vercel.mdx +125 -0
- package/docs/v6/interactive/explore.mdx +99 -0
- package/docs/v6/interactive/run.mdx +52 -0
- package/docs/v6/interactive/save.mdx +63 -0
- package/docs/v6/overview/comparison.mdx +101 -0
- package/docs/v6/overview/faq.mdx +162 -0
- package/docs/v6/overview/performance.mdx +52 -0
- package/docs/v6/overview/quickstart.mdx +137 -0
- package/docs/v6/overview/what-is-testdriver.mdx +85 -0
- package/docs/v6/scenarios/ai-chatbot.mdx +28 -0
- package/docs/v6/scenarios/cookie-banner.mdx +32 -0
- package/docs/v6/scenarios/file-upload.mdx +33 -0
- package/docs/v6/scenarios/form-filling.mdx +32 -0
- package/docs/v6/scenarios/log-in.mdx +75 -0
- package/docs/v6/scenarios/pdf-generation.mdx +25 -0
- package/docs/v6/scenarios/spell-check.mdx +22 -0
- package/docs/v6/security/action.mdx +84 -0
- package/docs/v6/security/agent.mdx +73 -0
- package/docs/v6/security/platform.mdx +77 -0
- package/docs/v6/tutorials/advanced-test.mdx +81 -0
- package/docs/v6/tutorials/basic-test.mdx +45 -0
- package/docs/v7/_drafts/agents.mdx +843 -0
- package/docs/v7/_drafts/architecture.mdx +399 -0
- package/docs/v7/_drafts/auto-cache-key.mdx +167 -0
- package/docs/v7/_drafts/awesome-logs-quick-ref.mdx +100 -0
- package/docs/v7/_drafts/best-practices.mdx +486 -0
- package/docs/v7/_drafts/caching-ai.mdx +215 -0
- package/docs/v7/_drafts/caching-selectors.mdx +424 -0
- package/docs/v7/_drafts/caching.mdx +366 -0
- package/docs/v7/_drafts/cli-to-sdk-migration.mdx +425 -0
- package/docs/v7/_drafts/commands/assert.mdx +45 -0
- package/docs/v7/_drafts/commands/exec.mdx +276 -0
- package/docs/v7/_drafts/commands/focus-application.mdx +44 -0
- package/docs/v7/_drafts/commands/hover-image.mdx +69 -0
- package/docs/v7/_drafts/commands/hover-text.mdx +47 -0
- package/docs/v7/_drafts/commands/if.mdx +53 -0
- package/docs/v7/_drafts/commands/match-image.mdx +67 -0
- package/docs/v7/_drafts/commands/press-keys.mdx +87 -0
- package/docs/v7/_drafts/commands/remember.mdx +49 -0
- package/docs/v7/_drafts/commands/run.mdx +44 -0
- package/docs/v7/_drafts/commands/scroll-until-image.mdx +66 -0
- package/docs/v7/_drafts/commands/scroll-until-text.mdx +60 -0
- package/docs/v7/_drafts/commands/scroll.mdx +69 -0
- package/docs/v7/_drafts/commands/type.mdx +45 -0
- package/docs/v7/_drafts/commands/wait-for-image.mdx +54 -0
- package/docs/v7/_drafts/commands/wait-for-text.mdx +48 -0
- package/docs/v7/_drafts/commands/wait.mdx +45 -0
- package/docs/v7/_drafts/configuration.mdx +378 -0
- package/docs/v7/_drafts/contributing.mdx +174 -0
- package/docs/v7/_drafts/core.mdx +458 -0
- package/docs/v7/_drafts/dashcam-title-feature.mdx +89 -0
- package/docs/v7/_drafts/debugging.mdx +349 -0
- package/docs/v7/_drafts/error-handling.mdx +501 -0
- package/docs/v7/_drafts/faq.mdx +393 -0
- package/docs/v7/_drafts/hooks.mdx +360 -0
- package/docs/v7/_drafts/init-command.mdx +95 -0
- package/docs/v7/_drafts/installation.mdx +420 -0
- package/docs/v7/_drafts/migration.mdx +562 -0
- package/docs/v7/_drafts/observable.mdx +604 -0
- package/docs/v7/_drafts/playwright.mdx +342 -0
- package/docs/v7/_drafts/plugin-migration.mdx +220 -0
- package/docs/v7/_drafts/powerful.mdx +419 -0
- package/docs/v7/_drafts/presets.mdx +210 -0
- package/docs/v7/_drafts/progressive-disclosure.mdx +230 -0
- package/docs/v7/_drafts/prompt-cache.mdx +200 -0
- package/docs/v7/_drafts/provision.mdx +390 -0
- package/docs/v7/_drafts/quick-start-test-recording.mdx +214 -0
- package/docs/v7/_drafts/readme.mdx +135 -0
- package/docs/v7/_drafts/reports.mdx +414 -0
- package/docs/v7/_drafts/scalable.mdx +763 -0
- package/docs/v7/_drafts/screenshot.mdx +155 -0
- package/docs/v7/_drafts/sdk-awesome-logs.mdx +468 -0
- package/docs/v7/_drafts/sdk-browser-rendering.mdx +167 -0
- package/docs/v7/_drafts/sdk-migration.mdx +474 -0
- package/docs/v7/_drafts/sdk-v7-complete.mdx +345 -0
- package/docs/v7/_drafts/self-hosting.mdx +369 -0
- package/docs/v7/_drafts/test-recording.mdx +382 -0
- package/docs/v7/_drafts/troubleshooting.mdx +526 -0
- package/docs/v7/_drafts/vitest-plugin.mdx +477 -0
- package/docs/v7/_drafts/vitest.mdx +535 -0
- package/docs/v7/_drafts/writing-tests.mdx +25 -0
- package/docs/v7/ai.mdx +205 -0
- package/docs/v7/assert.mdx +316 -0
- package/docs/v7/aws-setup.mdx +449 -0
- package/docs/v7/cache.mdx +223 -0
- package/docs/v7/caching.mdx +128 -0
- package/docs/v7/captcha.mdx +159 -0
- package/docs/v7/ci-cd.mdx +603 -0
- package/docs/v7/click.mdx +287 -0
- package/docs/v7/client.mdx +478 -0
- package/docs/v7/copilot/auto-healing.mdx +265 -0
- package/docs/v7/copilot/creating-tests.mdx +156 -0
- package/docs/v7/copilot/github.mdx +143 -0
- package/docs/v7/copilot/running-tests.mdx +149 -0
- package/docs/v7/copilot/setup.mdx +143 -0
- package/docs/v7/customizing-devices.mdx +319 -0
- package/docs/v7/dashcam.mdx +419 -0
- package/docs/v7/debugging-with-screenshots.mdx +402 -0
- package/docs/v7/device-config.mdx +317 -0
- package/docs/v7/double-click.mdx +102 -0
- package/docs/v7/elements.mdx +606 -0
- package/docs/v7/enterprise.mdx +9 -0
- package/docs/v7/errors.mdx +248 -0
- package/docs/v7/events.mdx +358 -0
- package/docs/v7/examples/ai.mdx +72 -0
- package/docs/v7/examples/assert.mdx +72 -0
- package/docs/v7/examples/captcha-api.mdx +92 -0
- package/docs/v7/examples/chrome-extension.mdx +132 -0
- package/docs/v7/examples/drag-and-drop.mdx +100 -0
- package/docs/v7/examples/element-not-found.mdx +67 -0
- package/docs/v7/examples/exec-output.mdx +85 -0
- package/docs/v7/examples/exec-pwsh.mdx +83 -0
- package/docs/v7/examples/focus-window.mdx +62 -0
- package/docs/v7/examples/hover-image.mdx +94 -0
- package/docs/v7/examples/hover-text.mdx +69 -0
- package/docs/v7/examples/installer.mdx +91 -0
- package/docs/v7/examples/launch-vscode-linux.mdx +101 -0
- package/docs/v7/examples/match-image.mdx +96 -0
- package/docs/v7/examples/press-keys.mdx +92 -0
- package/docs/v7/examples/scroll-keyboard.mdx +79 -0
- package/docs/v7/examples/scroll-until-image.mdx +81 -0
- package/docs/v7/examples/scroll-until-text.mdx +109 -0
- package/docs/v7/examples/scroll.mdx +81 -0
- package/docs/v7/examples/type.mdx +92 -0
- package/docs/v7/examples/windows-installer.mdx +89 -0
- package/docs/v7/exec.mdx +318 -0
- package/docs/v7/find.mdx +830 -0
- package/docs/v7/focus-application.mdx +294 -0
- package/docs/v7/generating-tests.mdx +36 -0
- package/docs/v7/hosted.mdx +158 -0
- package/docs/v7/hover.mdx +279 -0
- package/docs/v7/locating-elements.mdx +71 -0
- package/docs/v7/making-assertions.mdx +32 -0
- package/docs/v7/mcp.mdx +9 -0
- package/docs/v7/mouse-down.mdx +161 -0
- package/docs/v7/mouse-up.mdx +164 -0
- package/docs/v7/parse.mdx +237 -0
- package/docs/v7/performing-actions.mdx +54 -0
- package/docs/v7/press-keys.mdx +349 -0
- package/docs/v7/provision.mdx +333 -0
- package/docs/v7/quickstart.mdx +173 -0
- package/docs/v7/redraw.mdx +216 -0
- package/docs/v7/reusable-code.mdx +249 -0
- package/docs/v7/right-click.mdx +123 -0
- package/docs/v7/running-tests.mdx +185 -0
- package/docs/v7/screenshot.mdx +249 -0
- package/docs/v7/screenshots.mdx +186 -0
- package/docs/v7/scroll.mdx +336 -0
- package/docs/v7/secrets.mdx +115 -0
- package/docs/v7/self-hosted.mdx +149 -0
- package/docs/v7/type.mdx +358 -0
- package/docs/v7/variables.mdx +111 -0
- package/docs/v7/wait.mdx +52 -0
- package/docs/v7/waiting-for-elements.mdx +90 -0
- package/docs/v7/what-is-testdriver.mdx +54 -0
- package/eslint.config.js +67 -0
- package/examples/ai.test.mjs +31 -0
- package/examples/assert.test.mjs +47 -0
- package/examples/chrome-extension.test.mjs +97 -0
- package/examples/config.mjs +5 -0
- package/examples/element-not-found.test.mjs +27 -0
- package/examples/exec-output.test.mjs +60 -0
- package/examples/exec-pwsh.test.mjs +58 -0
- package/examples/findall-coffee-icons.test.mjs +42 -0
- package/examples/focus-window.test.mjs +37 -0
- package/examples/formatted-logging.test.mjs +27 -0
- package/examples/hover-image.test.mjs +53 -0
- package/examples/hover-text-with-description.test.mjs +57 -0
- package/examples/hover-text.test.mjs +28 -0
- package/examples/installer.test.mjs +50 -0
- package/examples/launch-vscode-linux.test.mjs +55 -0
- package/examples/match-image.test.mjs +55 -0
- package/examples/parse.test.mjs +19 -0
- package/examples/press-keys.test.mjs +44 -0
- package/examples/prompt.test.mjs +34 -0
- package/examples/scroll-keyboard.test.mjs +38 -0
- package/examples/scroll-until-image.test.mjs +40 -0
- package/examples/scroll.test.mjs +42 -0
- package/examples/type.test.mjs +46 -0
- package/examples/windows-installer.test.mjs +54 -0
- package/index.js +2 -0
- package/interfaces/cli/commands/init.js +438 -0
- package/interfaces/cli/commands/setup.js +382 -0
- package/interfaces/cli/lib/base.js +285 -0
- package/interfaces/cli.js +20 -0
- package/interfaces/junit-reporter.js +290 -0
- package/interfaces/logger.js +388 -0
- package/interfaces/readline.js +234 -0
- package/interfaces/shared-test-state.mjs +64 -0
- package/interfaces/vitest-plugin.d.ts +115 -0
- package/interfaces/vitest-plugin.mjs +1698 -0
- package/lib/captcha/solver.js +358 -0
- package/lib/core/Dashcam.js +533 -0
- package/lib/core/index.d.ts +172 -0
- package/lib/core/index.js +12 -0
- package/lib/environments.json +18 -0
- package/lib/github-comment-formatter.js +263 -0
- package/lib/github-comment.mjs +452 -0
- package/lib/init-project.js +575 -0
- package/lib/presets/index.mjs +331 -0
- package/lib/resolve-channel.js +46 -0
- package/lib/sentry.js +417 -0
- package/lib/vitest/hooks.d.ts +57 -0
- package/lib/vitest/hooks.mjs +674 -0
- package/lib/vitest/setup-aws.mjs +247 -0
- package/lib/vitest/setup-self-hosted.mjs +151 -0
- package/lib/vitest/setup.mjs +46 -0
- package/manual/captcha-api.test.mjs +51 -0
- package/manual/drag-and-drop.test.mjs +59 -0
- package/manual/flake-diffthreshold-001.test.mjs +9 -0
- package/manual/flake-diffthreshold-01.test.mjs +9 -0
- package/manual/flake-diffthreshold-05.test.mjs +9 -0
- package/manual/flake-noredraw-cache.test.mjs +9 -0
- package/manual/flake-noredraw-nocache.test.mjs +9 -0
- package/manual/flake-redraw-cache.test.mjs +9 -0
- package/manual/flake-redraw-nocache.test.mjs +9 -0
- package/manual/flake-rocket-match.test.mjs +30 -0
- package/manual/flake-shared.mjs +51 -0
- package/manual/no-provision.test.mjs +31 -0
- package/manual/packer-hover-image.test.mjs +176 -0
- package/manual/scroll-until-text.test.mjs +68 -0
- package/manual/test-init-command.js +223 -0
- package/mcp-server/README.md +322 -0
- package/mcp-server/dist/codegen.d.ts +9 -0
- package/mcp-server/dist/codegen.js +165 -0
- package/mcp-server/dist/mcp-app.html +114 -0
- package/mcp-server/dist/package.json +1 -0
- package/mcp-server/dist/provision-types.d.ts +290 -0
- package/mcp-server/dist/provision-types.js +174 -0
- package/mcp-server/dist/server.d.ts +6 -0
- package/mcp-server/dist/server.mjs +1925 -0
- package/mcp-server/dist/session.d.ts +85 -0
- package/mcp-server/dist/session.js +152 -0
- package/mcp-server/mcp-app.html +28 -0
- package/mcp-server/mcp-config.example.json +19 -0
- package/mcp-server/package-lock.json +4027 -0
- package/mcp-server/package.json +31 -0
- package/mcp-server/src/codegen.ts +189 -0
- package/mcp-server/src/mcp-app.css +360 -0
- package/mcp-server/src/mcp-app.ts +547 -0
- package/mcp-server/src/provision-types.ts +209 -0
- package/mcp-server/src/server.ts +2391 -0
- package/mcp-server/src/session.ts +194 -0
- package/mcp-server/tsconfig.json +16 -0
- package/mcp-server/vite.config.ts +23 -0
- package/package.json +158 -0
- package/schema.json +1046 -0
- package/scripts/generate-skills.js +94 -0
- package/sdk-log-formatter.js +1157 -0
- package/sdk.d.ts +1486 -0
- package/sdk.js +4336 -0
- package/setup/aws/cloudformation.yaml +463 -0
- package/setup/aws/disable-defender.sh +42 -0
- package/setup/aws/install-dev-runner.sh +79 -0
- package/setup/aws/spawn-runner.sh +289 -0
- package/test/captcha-solver.test.mjs +152 -0
- package/test/chrome-remote-debugging.test.mjs +66 -0
- package/test/duckduckgo/experiment.test.mjs +28 -0
- package/test/duckduckgo/setup.test.mjs +29 -0
- package/test/manual/debug-locate-response.js +82 -0
- package/test/manual/reconnect-provision.test.mjs +49 -0
- package/test/manual/test-console-logs.test.mjs +42 -0
- package/test/manual/test-find-api.js +73 -0
- package/test/manual/test-init.sh +54 -0
- package/test/manual/test-prompt-cache.js +97 -0
- package/test/manual/test-provision-auth.mjs +22 -0
- package/test/manual/test-sandbox-render.js +29 -0
- package/test/manual/test-sdk-methods.js +15 -0
- package/test/manual/test-sdk-refactor.js +53 -0
- package/test/manual/test-stack-trace.mjs +57 -0
- package/test/manual/verify-element-api.js +89 -0
- package/test/manual/verify-types.js +0 -0
- package/test/manual-unawaited-promise.test.mjs +31 -0
- package/vitest.config.mjs +58 -0
- package/vitest.runner.config.mjs +33 -0
- package/vscode-extension/.vscodeignore +12 -0
- package/vscode-extension/README.md +94 -0
- package/vscode-extension/media/icon.png +0 -0
- package/vscode-extension/package-lock.json +4126 -0
- package/vscode-extension/package.json +86 -0
- package/vscode-extension/src/extension.ts +829 -0
- package/vscode-extension/testdriverai-0.1.0.vsix +0 -0
- package/vscode-extension/tsconfig.json +16 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file contains application config factory.
|
|
3
|
+
* It is responsible for creating config instances from environment variables,
|
|
4
|
+
* supplying defaults, and formatting values
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Parse out true and false string values
|
|
8
|
+
function parseValue(value) {
|
|
9
|
+
if (typeof value === "string") {
|
|
10
|
+
const normalizedValue = value.toLowerCase().trim();
|
|
11
|
+
if (["true", "false"].includes(normalizedValue)) {
|
|
12
|
+
return JSON.parse(normalizedValue);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const channelConfig = require("../../lib/resolve-channel.js");
|
|
20
|
+
|
|
21
|
+
// Factory function that creates a config instance
|
|
22
|
+
const createConfig = (environment = {}) => {
|
|
23
|
+
// Start with defaults
|
|
24
|
+
const config = {
|
|
25
|
+
TD_ANALYTICS: true,
|
|
26
|
+
TD_API_ROOT: channelConfig.channels[channelConfig.active],
|
|
27
|
+
TD_API_KEY: null,
|
|
28
|
+
TD_PROFILE: false,
|
|
29
|
+
TD_RESOLUTION: [1366, 768],
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// Store the full environment for interpolation purposes
|
|
33
|
+
config._environment = environment;
|
|
34
|
+
|
|
35
|
+
// Find all env vars starting with TD_
|
|
36
|
+
for (let key in environment) {
|
|
37
|
+
if (key == "TD_RESOLUTION") {
|
|
38
|
+
config[key] = environment[key].split("x").map((x) => parseInt(x.trim()));
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (key.startsWith("TD_")) {
|
|
43
|
+
config[key] = parseValue(environment[key]);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Add support for CI environment variable
|
|
48
|
+
if (environment.CI) {
|
|
49
|
+
config.CI = parseValue(environment.CI);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return config;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Create a default config instance for backward compatibility
|
|
56
|
+
const defaultConfig = createConfig(process.env);
|
|
57
|
+
|
|
58
|
+
// Export both the factory function and the default instance
|
|
59
|
+
module.exports = defaultConfig;
|
|
60
|
+
module.exports.createConfig = createConfig;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// parses markdown content to find code blocks, and then extracts yaml from those code blocks
|
|
2
|
+
const yaml = require("js-yaml");
|
|
3
|
+
const pkg = require("../../package.json");
|
|
4
|
+
const session = require("./session");
|
|
5
|
+
const theme = require("./theme");
|
|
6
|
+
// do the actual parsing
|
|
7
|
+
// this library is very strict
|
|
8
|
+
// note that errors are sent to the AI will it may self-heal
|
|
9
|
+
const manualToYml = async function (inputArgs) {
|
|
10
|
+
// input is like `command=click x=100 y=200 z='this is a string'`
|
|
11
|
+
// convert this to json
|
|
12
|
+
|
|
13
|
+
const pattern = /(\w+)=('[^']*'|[^\s]+)/g;
|
|
14
|
+
|
|
15
|
+
let match;
|
|
16
|
+
let json = {};
|
|
17
|
+
|
|
18
|
+
while ((match = pattern.exec(inputArgs)) !== null) {
|
|
19
|
+
const key = match[1];
|
|
20
|
+
const value = match[2].replace(/'/g, ""); // Remove single quotes if present
|
|
21
|
+
json[key] = value;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
json = {
|
|
25
|
+
commands: [json],
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// use yml dump to convert json to yml
|
|
29
|
+
let yml = await yaml.dump(json);
|
|
30
|
+
|
|
31
|
+
return yml;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const jsonToManual = function (json, colors = true) {
|
|
35
|
+
// Convert the JSON object to key-value pairs
|
|
36
|
+
const params = Object.keys(json)
|
|
37
|
+
.map((key) => {
|
|
38
|
+
let value = json[key];
|
|
39
|
+
|
|
40
|
+
// If the value contains spaces, wrap it in single quotes
|
|
41
|
+
if (typeof value === "string") {
|
|
42
|
+
value = `'${value}'`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (colors) {
|
|
46
|
+
return `${theme.cyan(key)}=${theme.green(value)}`;
|
|
47
|
+
} else {
|
|
48
|
+
return `${key}=${value}`;
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
.join(" ");
|
|
52
|
+
|
|
53
|
+
return params;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const dumpToYML = async function (inputArray, sessionInstance = null) {
|
|
57
|
+
// use yml dump to convert json to yml
|
|
58
|
+
let yml = await yaml.dump({
|
|
59
|
+
version: pkg.version,
|
|
60
|
+
session: sessionInstance ? sessionInstance.get() : session.get(),
|
|
61
|
+
steps: inputArray,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
return yml;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const hydrateFromYML = async function (yml, sessionInstance = null) {
|
|
68
|
+
// use yml load to convert yml to json
|
|
69
|
+
let json = await yaml.load(yml);
|
|
70
|
+
|
|
71
|
+
if (!json) {
|
|
72
|
+
json = {};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const sessionToUse = sessionInstance || session;
|
|
76
|
+
|
|
77
|
+
if (!json?.session) {
|
|
78
|
+
json.session = sessionToUse.get();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
sessionToUse.set(json.session);
|
|
82
|
+
|
|
83
|
+
return json;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
module.exports = {
|
|
87
|
+
manualToYml,
|
|
88
|
+
dumpToYML,
|
|
89
|
+
hydrateFromYML,
|
|
90
|
+
jsonToManual,
|
|
91
|
+
};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared HTTP client for the TestDriver SDK.
|
|
3
|
+
*
|
|
4
|
+
* All SDK HTTP traffic should go through these helpers so that
|
|
5
|
+
* User-Agent, timeouts, Sentry tracing headers, and response
|
|
6
|
+
* parsing are handled in one place.
|
|
7
|
+
*
|
|
8
|
+
* Uses axios under the hood — the same library the rest of the SDK
|
|
9
|
+
* already depends on.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const axios = require("axios");
|
|
13
|
+
const crypto = require("crypto");
|
|
14
|
+
const { version } = require("../../package.json");
|
|
15
|
+
|
|
16
|
+
const USER_AGENT = `TestDriverSDK/${version} (Node.js ${process.version})`;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Generate Sentry distributed-tracing headers from a session ID.
|
|
20
|
+
* Both sandbox.js and sdk.js duplicated this — it now lives here.
|
|
21
|
+
*
|
|
22
|
+
* @param {string} sessionId
|
|
23
|
+
* @returns {object} Headers object (empty if no sessionId)
|
|
24
|
+
*/
|
|
25
|
+
function getSentryTraceHeaders(sessionId) {
|
|
26
|
+
if (!sessionId) return {};
|
|
27
|
+
const traceId = crypto.createHash("md5").update(sessionId).digest("hex");
|
|
28
|
+
const spanId = crypto.randomBytes(8).toString("hex");
|
|
29
|
+
return {
|
|
30
|
+
"sentry-trace": traceId + "-" + spanId + "-1",
|
|
31
|
+
baggage:
|
|
32
|
+
"sentry-trace_id=" +
|
|
33
|
+
traceId +
|
|
34
|
+
",sentry-sample_rate=1.0,sentry-sampled=true",
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Build common request headers.
|
|
40
|
+
* @param {object} [extra] - Additional headers to merge
|
|
41
|
+
* @returns {object}
|
|
42
|
+
*/
|
|
43
|
+
function baseHeaders(extra) {
|
|
44
|
+
return {
|
|
45
|
+
"User-Agent": USER_AGENT,
|
|
46
|
+
...extra,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* POST JSON to `url` and return the parsed response body.
|
|
52
|
+
*
|
|
53
|
+
* @param {string} url - Absolute URL
|
|
54
|
+
* @param {object} [data] - JSON body
|
|
55
|
+
* @param {object} [opts] - Extra axios config (headers, timeout, …)
|
|
56
|
+
* @returns {Promise<object>} Parsed response data
|
|
57
|
+
*/
|
|
58
|
+
async function httpPost(url, data, opts = {}) {
|
|
59
|
+
const { headers: extraHeaders, ...rest } = opts;
|
|
60
|
+
const res = await axios({
|
|
61
|
+
method: "post",
|
|
62
|
+
url,
|
|
63
|
+
headers: baseHeaders({
|
|
64
|
+
"Content-Type": "application/json",
|
|
65
|
+
...extraHeaders,
|
|
66
|
+
}),
|
|
67
|
+
data,
|
|
68
|
+
timeout: opts.timeout || 30000,
|
|
69
|
+
...rest,
|
|
70
|
+
});
|
|
71
|
+
return res.data;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* GET `url` and return the parsed response body.
|
|
76
|
+
*
|
|
77
|
+
* @param {string} url - Absolute URL
|
|
78
|
+
* @param {object} [opts] - Extra axios config
|
|
79
|
+
* @returns {Promise<object>} Parsed response data
|
|
80
|
+
*/
|
|
81
|
+
async function httpGet(url, opts = {}) {
|
|
82
|
+
const { headers: extraHeaders, ...rest } = opts;
|
|
83
|
+
const res = await axios({
|
|
84
|
+
method: "get",
|
|
85
|
+
url,
|
|
86
|
+
headers: baseHeaders(extraHeaders),
|
|
87
|
+
timeout: opts.timeout || 30000,
|
|
88
|
+
...rest,
|
|
89
|
+
});
|
|
90
|
+
return res.data;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* PUT data to `url` (e.g. S3 presigned upload).
|
|
95
|
+
*
|
|
96
|
+
* @param {string} url - Absolute URL
|
|
97
|
+
* @param {Buffer|string} data - Request body
|
|
98
|
+
* @param {object} [opts] - Extra axios config (headers, timeout, …)
|
|
99
|
+
* @returns {Promise<object>} Parsed response data (or empty object for 2xx with no body)
|
|
100
|
+
*/
|
|
101
|
+
async function httpPut(url, data, opts = {}) {
|
|
102
|
+
const { headers: extraHeaders, ...rest } = opts;
|
|
103
|
+
const res = await axios({
|
|
104
|
+
method: "put",
|
|
105
|
+
url,
|
|
106
|
+
headers: baseHeaders(extraHeaders),
|
|
107
|
+
data,
|
|
108
|
+
timeout: opts.timeout || 30000,
|
|
109
|
+
maxBodyLength: Infinity,
|
|
110
|
+
maxContentLength: Infinity,
|
|
111
|
+
...rest,
|
|
112
|
+
});
|
|
113
|
+
return res.data;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Download a URL as a Buffer (e.g. screenshot from S3).
|
|
118
|
+
*
|
|
119
|
+
* @param {string} url - Absolute URL
|
|
120
|
+
* @param {object} [opts] - Extra axios config
|
|
121
|
+
* @returns {Promise<Buffer>}
|
|
122
|
+
*/
|
|
123
|
+
async function downloadBuffer(url, opts = {}) {
|
|
124
|
+
const { headers: extraHeaders, ...rest } = opts;
|
|
125
|
+
const res = await axios({
|
|
126
|
+
method: "get",
|
|
127
|
+
url,
|
|
128
|
+
headers: baseHeaders(extraHeaders),
|
|
129
|
+
responseType: "arraybuffer",
|
|
130
|
+
timeout: opts.timeout || 60000,
|
|
131
|
+
...rest,
|
|
132
|
+
});
|
|
133
|
+
return Buffer.from(res.data);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
module.exports = {
|
|
137
|
+
httpPost,
|
|
138
|
+
httpGet,
|
|
139
|
+
httpPut,
|
|
140
|
+
downloadBuffer,
|
|
141
|
+
getSentryTraceHeaders,
|
|
142
|
+
USER_AGENT,
|
|
143
|
+
baseHeaders,
|
|
144
|
+
};
|
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Factory function to create outputs instance
|
|
2
|
+
function createOutputs() {
|
|
3
|
+
let outputs = {};
|
|
4
|
+
|
|
5
|
+
return {
|
|
6
|
+
getAll: () => {
|
|
7
|
+
return outputs;
|
|
8
|
+
},
|
|
9
|
+
get: (key) => {
|
|
10
|
+
return outputs[key] || null;
|
|
11
|
+
},
|
|
12
|
+
set: (key, value) => {
|
|
13
|
+
if (key && value) {
|
|
14
|
+
outputs[key] = value;
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Export both factory function and legacy static instance for backward compatibility
|
|
21
|
+
const staticOutputs = createOutputs();
|
|
22
|
+
|
|
23
|
+
module.exports = {
|
|
24
|
+
createOutputs,
|
|
25
|
+
// Legacy static exports for backward compatibility
|
|
26
|
+
getAll: staticOutputs.getAll,
|
|
27
|
+
get: staticOutputs.get,
|
|
28
|
+
set: staticOutputs.set,
|
|
29
|
+
};
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
// parses markdown content to find code blocks, and then extracts yaml from those code blocks
|
|
2
|
+
const Parser = require("markdown-parser");
|
|
3
|
+
const yaml = require("js-yaml");
|
|
4
|
+
const Ajv = require("ajv/dist/2020");
|
|
5
|
+
const theme = require("./theme");
|
|
6
|
+
const { events } = require("../events.js");
|
|
7
|
+
|
|
8
|
+
let parser = new Parser();
|
|
9
|
+
|
|
10
|
+
function formatAjvError(error) {
|
|
11
|
+
return [
|
|
12
|
+
theme.red("Validation Failure"),
|
|
13
|
+
`${theme.yellow("Path:")} ${theme.white(error.instancePath)}`,
|
|
14
|
+
`${theme.yellow("Schema:")} ${theme.cyan(error.schemaPath)}`,
|
|
15
|
+
`${theme.yellow("Keyword:")} ${theme.magenta(error.keyword)}`,
|
|
16
|
+
error.params?.missingProperty
|
|
17
|
+
? `${theme.yellow("Missing:")} ${theme.yellow(
|
|
18
|
+
error.params.missingProperty,
|
|
19
|
+
)}`
|
|
20
|
+
: "",
|
|
21
|
+
`${theme.yellow("Message:")} ${theme.white(error.message)}`,
|
|
22
|
+
`\n`,
|
|
23
|
+
]
|
|
24
|
+
.filter(Boolean)
|
|
25
|
+
.join("\n");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// use markdown parser to find code blocks within AI response
|
|
29
|
+
const findCodeBlocks = async function (markdownContent) {
|
|
30
|
+
let md = markdownContent.match(/```yaml\n([\s\S]*?)```/);
|
|
31
|
+
|
|
32
|
+
if (md) {
|
|
33
|
+
return [{ code: md[1] }];
|
|
34
|
+
} else {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// use markdown parser to find code blocks within AI response
|
|
40
|
+
const findGenerativePrompts = async function (markdownContent) {
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
parser.parse(markdownContent, async (err, result) => {
|
|
43
|
+
if (err) {
|
|
44
|
+
return reject(err);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// parse the markdown content of each code block
|
|
48
|
+
let codes = result.codes.map((code) => {
|
|
49
|
+
return new Promise((resolve2, reject2) => {
|
|
50
|
+
try {
|
|
51
|
+
const yamlContent = getYAMLFromCodeBlock(code);
|
|
52
|
+
const parsedYaml = parseYAML(yamlContent);
|
|
53
|
+
resolve2(parsedYaml);
|
|
54
|
+
} catch (err) {
|
|
55
|
+
reject2(err);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// use Promise.all to wait for all the promises to resolve
|
|
61
|
+
let parsedCodes = await Promise.all(codes);
|
|
62
|
+
|
|
63
|
+
return resolve(parsedCodes);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// parse the yml from the included codeblock and clean it up
|
|
69
|
+
const getYAMLFromCodeBlock = function (codeblock) {
|
|
70
|
+
let lines = codeblock.code.split("\n");
|
|
71
|
+
|
|
72
|
+
// if first line is yaml or yml, remove it
|
|
73
|
+
if (lines[0].indexOf("yaml") > -1 || lines[0].indexOf("yml") > -1) {
|
|
74
|
+
lines.shift();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// count the whitespace in each line, and remove the line if it's all whitespace
|
|
78
|
+
lines = lines.filter((line) => {
|
|
79
|
+
return line.trim().length > 0 && line.trim()[0] !== ",";
|
|
80
|
+
// sometimes it produces yaml with breaks, or just a single comma
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
return lines.join("\n");
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// do the actual parsing
|
|
87
|
+
// this library is very strict
|
|
88
|
+
// note that errors are sent to the AI will it may self-heal
|
|
89
|
+
const parseYAML = async function (inputYaml) {
|
|
90
|
+
let doc = await yaml.load(inputYaml);
|
|
91
|
+
return doc;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// Replace ${VAR} with the value from the vars object
|
|
95
|
+
// Will skip variables that are not in the vars object
|
|
96
|
+
// Will skip escaped variables like \${VAR}
|
|
97
|
+
function interpolate(yaml, vars) {
|
|
98
|
+
let newyaml = yaml;
|
|
99
|
+
Object.keys(vars).forEach((key) => {
|
|
100
|
+
newyaml = newyaml.replace(
|
|
101
|
+
new RegExp(`(?<!\\\\)\\$\\{${key}\\}`, "g"),
|
|
102
|
+
vars[key],
|
|
103
|
+
);
|
|
104
|
+
});
|
|
105
|
+
// Replace \$ with $
|
|
106
|
+
newyaml = newyaml.replace(/\\(\${[^}]+})/g, "$1");
|
|
107
|
+
|
|
108
|
+
return newyaml;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Function to gather all variables in the YAMl that have not been replaced
|
|
112
|
+
function collectUnreplacedVariables(yaml) {
|
|
113
|
+
let unreplaced = [];
|
|
114
|
+
|
|
115
|
+
// Use a regex to find all ${VAR} patterns
|
|
116
|
+
const regex = /\$\{([^}]+)\}/g;
|
|
117
|
+
let match;
|
|
118
|
+
while ((match = regex.exec(yaml)) !== null) {
|
|
119
|
+
const variable = match[1];
|
|
120
|
+
// Check if the variable is already in the unreplaced array
|
|
121
|
+
if (!unreplaced.includes(variable)) {
|
|
122
|
+
unreplaced.push(variable);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return unreplaced;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Factory function to create parser with emitter
|
|
130
|
+
function createParser(emitter) {
|
|
131
|
+
// validate yaml using schema.json in root
|
|
132
|
+
let schema = require("../../schema.json");
|
|
133
|
+
const validateYAML = async function (yaml) {
|
|
134
|
+
let ajv = new Ajv({
|
|
135
|
+
allowUnionTypes: true,
|
|
136
|
+
strict: false,
|
|
137
|
+
});
|
|
138
|
+
let validate = ajv.compile(schema);
|
|
139
|
+
let valid = validate(await parseYAML(yaml));
|
|
140
|
+
|
|
141
|
+
if (!valid) {
|
|
142
|
+
validate.errors.forEach((err) => {
|
|
143
|
+
const formattedError = formatAjvError(err);
|
|
144
|
+
emitter.emit(events.error.fatal, formattedError);
|
|
145
|
+
});
|
|
146
|
+
// throw new Error("Invalid YAML");
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return yaml;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
findCodeBlocks,
|
|
154
|
+
findGenerativePrompts,
|
|
155
|
+
getYAMLFromCodeBlock,
|
|
156
|
+
interpolate,
|
|
157
|
+
collectUnreplacedVariables,
|
|
158
|
+
validateYAML,
|
|
159
|
+
getCommands: async function (codeBlock) {
|
|
160
|
+
const yml = getYAMLFromCodeBlock(codeBlock);
|
|
161
|
+
let yamlArray = await parseYAML(yml);
|
|
162
|
+
|
|
163
|
+
let steps = yamlArray?.steps;
|
|
164
|
+
|
|
165
|
+
if (steps) {
|
|
166
|
+
let commands = [];
|
|
167
|
+
|
|
168
|
+
// combine them all as if they were a single step
|
|
169
|
+
steps.forEach((s) => {
|
|
170
|
+
commands = commands.concat(s.commands);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// filter undefined values
|
|
174
|
+
commands = commands.filter((r) => {
|
|
175
|
+
return r;
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
if (!commands.length) {
|
|
179
|
+
throw new Error(
|
|
180
|
+
"No actions found in yaml. Individual commands must be under the `commands` key.",
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return commands;
|
|
185
|
+
} else {
|
|
186
|
+
let commands = yamlArray?.commands;
|
|
187
|
+
|
|
188
|
+
if (!commands?.length) {
|
|
189
|
+
throw new Error(
|
|
190
|
+
"No actions found in yaml. Individual commands must be under the `commands` key.",
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return commands;
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Export both the factory function and the static functions for backward compatibility
|
|
201
|
+
module.exports = {
|
|
202
|
+
createParser,
|
|
203
|
+
// Static exports for backward compatibility
|
|
204
|
+
findCodeBlocks,
|
|
205
|
+
findGenerativePrompts,
|
|
206
|
+
getYAMLFromCodeBlock,
|
|
207
|
+
interpolate,
|
|
208
|
+
collectUnreplacedVariables,
|
|
209
|
+
};
|