@tangle-network/browser-agent-driver 0.33.3 → 0.34.0
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/README.md +42 -1
- package/discovery/llms.txt +27 -0
- package/discovery/tangle-agent.json +36 -0
- package/dist/brain/action-parse.d.ts +16 -0
- package/dist/brain/action-parse.d.ts.map +1 -0
- package/dist/brain/action-parse.js +191 -0
- package/dist/brain/action-parse.js.map +1 -0
- package/dist/brain/decide.d.ts +58 -0
- package/dist/brain/decide.d.ts.map +1 -0
- package/dist/brain/decide.js +418 -0
- package/dist/brain/decide.js.map +1 -0
- package/dist/brain/history-compact.d.ts +19 -0
- package/dist/brain/history-compact.d.ts.map +1 -0
- package/dist/brain/history-compact.js +153 -0
- package/dist/brain/history-compact.js.map +1 -0
- package/dist/brain/index.d.ts +78 -152
- package/dist/brain/index.d.ts.map +1 -1
- package/dist/brain/index.js +62 -2268
- package/dist/brain/index.js.map +1 -1
- package/dist/brain/model-client.d.ts +101 -0
- package/dist/brain/model-client.d.ts.map +1 -0
- package/dist/brain/model-client.js +391 -0
- package/dist/brain/model-client.js.map +1 -0
- package/dist/brain/plan.d.ts +57 -0
- package/dist/brain/plan.d.ts.map +1 -0
- package/dist/brain/plan.js +194 -0
- package/dist/brain/plan.js.map +1 -0
- package/dist/brain/prompts.d.ts +37 -0
- package/dist/brain/prompts.d.ts.map +1 -0
- package/dist/brain/prompts.js +455 -0
- package/dist/brain/prompts.js.map +1 -0
- package/dist/brain/provider-fetch.d.ts +26 -0
- package/dist/brain/provider-fetch.d.ts.map +1 -0
- package/dist/brain/provider-fetch.js +45 -0
- package/dist/brain/provider-fetch.js.map +1 -0
- package/dist/brain/snapshot-budget.d.ts +20 -0
- package/dist/brain/snapshot-budget.d.ts.map +1 -0
- package/dist/brain/snapshot-budget.js +202 -0
- package/dist/brain/snapshot-budget.js.map +1 -0
- package/dist/brain/system-prompt.d.ts +67 -0
- package/dist/brain/system-prompt.d.ts.map +1 -0
- package/dist/brain/system-prompt.js +128 -0
- package/dist/brain/system-prompt.js.map +1 -0
- package/dist/brain/tasks/design-audit.d.ts +33 -0
- package/dist/brain/tasks/design-audit.d.ts.map +1 -0
- package/dist/brain/tasks/design-audit.js +100 -0
- package/dist/brain/tasks/design-audit.js.map +1 -0
- package/dist/brain/tasks/evaluate.d.ts +25 -0
- package/dist/brain/tasks/evaluate.d.ts.map +1 -0
- package/dist/brain/tasks/evaluate.js +55 -0
- package/dist/brain/tasks/evaluate.js.map +1 -0
- package/dist/brain/tasks/goal-verification.d.ts +32 -0
- package/dist/brain/tasks/goal-verification.d.ts.map +1 -0
- package/dist/brain/tasks/goal-verification.js +68 -0
- package/dist/brain/tasks/goal-verification.js.map +1 -0
- package/dist/brain/tasks/knowledge.d.ts +26 -0
- package/dist/brain/tasks/knowledge.d.ts.map +1 -0
- package/dist/brain/tasks/knowledge.js +56 -0
- package/dist/brain/tasks/knowledge.js.map +1 -0
- package/dist/brain/tasks/link-scout.d.ts +37 -0
- package/dist/brain/tasks/link-scout.d.ts.map +1 -0
- package/dist/brain/tasks/link-scout.js +69 -0
- package/dist/brain/tasks/link-scout.js.map +1 -0
- package/dist/brain/types.d.ts +55 -0
- package/dist/brain/types.d.ts.map +1 -0
- package/dist/brain/types.js +7 -0
- package/dist/brain/types.js.map +1 -0
- package/dist/browser/stealth-init-script.d.ts +9 -0
- package/dist/browser/stealth-init-script.d.ts.map +1 -0
- package/dist/browser/stealth-init-script.js +128 -0
- package/dist/browser/stealth-init-script.js.map +1 -0
- package/dist/browser/storage-state.d.ts +29 -0
- package/dist/browser/storage-state.d.ts.map +1 -0
- package/dist/browser/storage-state.js +47 -0
- package/dist/browser/storage-state.js.map +1 -0
- package/dist/cli/args.d.ts +141 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +167 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/benchmark-sync.d.ts +9 -0
- package/dist/cli/benchmark-sync.d.ts.map +1 -0
- package/dist/cli/benchmark-sync.js +43 -0
- package/dist/cli/benchmark-sync.js.map +1 -0
- package/dist/cli/build-config.d.ts +11 -0
- package/dist/cli/build-config.d.ts.map +1 -0
- package/dist/cli/build-config.js +355 -0
- package/dist/cli/build-config.js.map +1 -0
- package/dist/cli/commands/auth.d.ts +3 -0
- package/dist/cli/commands/auth.d.ts.map +1 -0
- package/dist/cli/commands/auth.js +36 -0
- package/dist/cli/commands/auth.js.map +1 -0
- package/dist/cli/commands/chrome-debug.d.ts +7 -0
- package/dist/cli/commands/chrome-debug.d.ts.map +1 -0
- package/dist/cli/commands/chrome-debug.js +11 -0
- package/dist/cli/commands/chrome-debug.js.map +1 -0
- package/dist/cli/commands/design-audit.d.ts +3 -0
- package/dist/cli/commands/design-audit.d.ts.map +1 -0
- package/dist/cli/commands/design-audit.js +68 -0
- package/dist/cli/commands/design-audit.js.map +1 -0
- package/dist/cli/commands/preview.d.ts +14 -0
- package/dist/cli/commands/preview.d.ts.map +1 -0
- package/dist/cli/commands/preview.js +31 -0
- package/dist/cli/commands/preview.js.map +1 -0
- package/dist/cli/commands/run.d.ts +3 -0
- package/dist/cli/commands/run.d.ts.map +1 -0
- package/dist/cli/commands/run.js +728 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/commands/runs.d.ts +8 -0
- package/dist/cli/commands/runs.d.ts.map +1 -0
- package/dist/cli/commands/runs.js +35 -0
- package/dist/cli/commands/runs.js.map +1 -0
- package/dist/cli/commands/share.d.ts +10 -0
- package/dist/cli/commands/share.d.ts.map +1 -0
- package/dist/cli/commands/share.js +32 -0
- package/dist/cli/commands/share.js.map +1 -0
- package/dist/cli/commands/showcase.d.ts +17 -0
- package/dist/cli/commands/showcase.d.ts.map +1 -0
- package/dist/cli/commands/showcase.js +20 -0
- package/dist/cli/commands/showcase.js.map +1 -0
- package/dist/cli/commands/snapshot.d.ts +12 -0
- package/dist/cli/commands/snapshot.d.ts.map +1 -0
- package/dist/cli/commands/snapshot.js +24 -0
- package/dist/cli/commands/snapshot.js.map +1 -0
- package/dist/cli/commands/view.d.ts +7 -0
- package/dist/cli/commands/view.d.ts.map +1 -0
- package/dist/cli/commands/view.js +23 -0
- package/dist/cli/commands/view.js.map +1 -0
- package/dist/cli/constants.d.ts +6 -0
- package/dist/cli/constants.d.ts.map +1 -0
- package/dist/cli/constants.js +3 -0
- package/dist/cli/constants.js.map +1 -0
- package/dist/cli/version.d.ts +7 -0
- package/dist/cli/version.d.ts.map +1 -0
- package/dist/cli/version.js +16 -0
- package/dist/cli/version.js.map +1 -0
- package/dist/cli-design-audit.d.ts +44 -36
- package/dist/cli-design-audit.d.ts.map +1 -1
- package/dist/cli-design-audit.js +137 -1646
- package/dist/cli-design-audit.js.map +1 -1
- package/dist/cli-jobs.js +2 -1
- package/dist/cli-jobs.js.map +1 -1
- package/dist/cli.js +66 -1697
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +5 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +8 -0
- package/dist/config.js.map +1 -1
- package/dist/design/audit/evolve/agent.d.ts +23 -0
- package/dist/design/audit/evolve/agent.d.ts.map +1 -0
- package/dist/design/audit/evolve/agent.js +272 -0
- package/dist/design/audit/evolve/agent.js.map +1 -0
- package/dist/design/audit/evolve/css.d.ts +10 -0
- package/dist/design/audit/evolve/css.d.ts.map +1 -0
- package/dist/design/audit/evolve/css.js +206 -0
- package/dist/design/audit/evolve/css.js.map +1 -0
- package/dist/design/audit/evolve/index.d.ts +13 -0
- package/dist/design/audit/evolve/index.d.ts.map +1 -0
- package/dist/design/audit/evolve/index.js +12 -0
- package/dist/design/audit/evolve/index.js.map +1 -0
- package/dist/design/audit/evolve/report.d.ts +3 -0
- package/dist/design/audit/evolve/report.d.ts.map +1 -0
- package/dist/design/audit/evolve/report.js +45 -0
- package/dist/design/audit/evolve/report.js.map +1 -0
- package/dist/design/audit/evolve/types.d.ts +14 -0
- package/dist/design/audit/evolve/types.d.ts.map +1 -0
- package/dist/design/audit/evolve/types.js +2 -0
- package/dist/design/audit/evolve/types.js.map +1 -0
- package/dist/design/audit/pipeline.d.ts +12 -0
- package/dist/design/audit/pipeline.d.ts.map +1 -1
- package/dist/design/audit/pipeline.js +43 -27
- package/dist/design/audit/pipeline.js.map +1 -1
- package/dist/design/audit/reference/artifact/build.d.ts +33 -0
- package/dist/design/audit/reference/artifact/build.d.ts.map +1 -0
- package/dist/design/audit/reference/artifact/build.js +64 -0
- package/dist/design/audit/reference/artifact/build.js.map +1 -0
- package/dist/design/audit/reference/artifact/render.d.ts +39 -0
- package/dist/design/audit/reference/artifact/render.d.ts.map +1 -0
- package/dist/design/audit/reference/artifact/render.js +213 -0
- package/dist/design/audit/reference/artifact/render.js.map +1 -0
- package/dist/design/audit/reference/artifact/text.d.ts +11 -0
- package/dist/design/audit/reference/artifact/text.d.ts.map +1 -0
- package/dist/design/audit/reference/artifact/text.js +20 -0
- package/dist/design/audit/reference/artifact/text.js.map +1 -0
- package/dist/design/audit/reference/artifact/to-findings.d.ts +57 -0
- package/dist/design/audit/reference/artifact/to-findings.d.ts.map +1 -0
- package/dist/design/audit/reference/artifact/to-findings.js +314 -0
- package/dist/design/audit/reference/artifact/to-findings.js.map +1 -0
- package/dist/design/audit/reference/config.d.ts +50 -0
- package/dist/design/audit/reference/config.d.ts.map +1 -0
- package/dist/design/audit/reference/config.js +108 -0
- package/dist/design/audit/reference/config.js.map +1 -0
- package/dist/design/audit/reference/contracts.d.ts +1030 -0
- package/dist/design/audit/reference/contracts.d.ts.map +1 -0
- package/dist/design/audit/reference/contracts.js +28 -0
- package/dist/design/audit/reference/contracts.js.map +1 -0
- package/dist/design/audit/reference/corpus/build.d.ts +115 -0
- package/dist/design/audit/reference/corpus/build.d.ts.map +1 -0
- package/dist/design/audit/reference/corpus/build.js +152 -0
- package/dist/design/audit/reference/corpus/build.js.map +1 -0
- package/dist/design/audit/reference/corpus/schema.d.ts +33 -0
- package/dist/design/audit/reference/corpus/schema.d.ts.map +1 -0
- package/dist/design/audit/reference/corpus/schema.js +249 -0
- package/dist/design/audit/reference/corpus/schema.js.map +1 -0
- package/dist/design/audit/reference/corpus/store.d.ts +26 -0
- package/dist/design/audit/reference/corpus/store.d.ts.map +1 -0
- package/dist/design/audit/reference/corpus/store.js +104 -0
- package/dist/design/audit/reference/corpus/store.js.map +1 -0
- package/dist/design/audit/reference/dna/delta.d.ts +21 -0
- package/dist/design/audit/reference/dna/delta.d.ts.map +1 -0
- package/dist/design/audit/reference/dna/delta.js +126 -0
- package/dist/design/audit/reference/dna/delta.js.map +1 -0
- package/dist/design/audit/reference/dna/derive.d.ts +31 -0
- package/dist/design/audit/reference/dna/derive.d.ts.map +1 -0
- package/dist/design/audit/reference/dna/derive.js +381 -0
- package/dist/design/audit/reference/dna/derive.js.map +1 -0
- package/dist/design/audit/reference/dna/descriptor.d.ts +36 -0
- package/dist/design/audit/reference/dna/descriptor.d.ts.map +1 -0
- package/dist/design/audit/reference/dna/descriptor.js +209 -0
- package/dist/design/audit/reference/dna/descriptor.js.map +1 -0
- package/dist/design/audit/reference/dna/page-adapter.d.ts +17 -0
- package/dist/design/audit/reference/dna/page-adapter.d.ts.map +1 -0
- package/dist/design/audit/reference/dna/page-adapter.js +35 -0
- package/dist/design/audit/reference/dna/page-adapter.js.map +1 -0
- package/dist/design/audit/reference/dna/scroll-capture.d.ts +93 -0
- package/dist/design/audit/reference/dna/scroll-capture.d.ts.map +1 -0
- package/dist/design/audit/reference/dna/scroll-capture.js +374 -0
- package/dist/design/audit/reference/dna/scroll-capture.js.map +1 -0
- package/dist/design/audit/reference/engine/budget.d.ts +63 -0
- package/dist/design/audit/reference/engine/budget.d.ts.map +1 -0
- package/dist/design/audit/reference/engine/budget.js +110 -0
- package/dist/design/audit/reference/engine/budget.js.map +1 -0
- package/dist/design/audit/reference/engine/core.d.ts +32 -0
- package/dist/design/audit/reference/engine/core.d.ts.map +1 -0
- package/dist/design/audit/reference/engine/core.js +261 -0
- package/dist/design/audit/reference/engine/core.js.map +1 -0
- package/dist/design/audit/reference/engine/guard.d.ts +43 -0
- package/dist/design/audit/reference/engine/guard.d.ts.map +1 -0
- package/dist/design/audit/reference/engine/guard.js +43 -0
- package/dist/design/audit/reference/engine/guard.js.map +1 -0
- package/dist/design/audit/reference/engine/score-core.d.ts +48 -0
- package/dist/design/audit/reference/engine/score-core.d.ts.map +1 -0
- package/dist/design/audit/reference/engine/score-core.js +134 -0
- package/dist/design/audit/reference/engine/score-core.js.map +1 -0
- package/dist/design/audit/reference/engine/wiring.d.ts +35 -0
- package/dist/design/audit/reference/engine/wiring.d.ts.map +1 -0
- package/dist/design/audit/reference/engine/wiring.js +80 -0
- package/dist/design/audit/reference/engine/wiring.js.map +1 -0
- package/dist/design/audit/reference/eval/taste-core.d.ts +77 -0
- package/dist/design/audit/reference/eval/taste-core.d.ts.map +1 -0
- package/dist/design/audit/reference/eval/taste-core.js +95 -0
- package/dist/design/audit/reference/eval/taste-core.js.map +1 -0
- package/dist/design/audit/reference/generate/generator.d.ts +49 -0
- package/dist/design/audit/reference/generate/generator.d.ts.map +1 -0
- package/dist/design/audit/reference/generate/generator.js +94 -0
- package/dist/design/audit/reference/generate/generator.js.map +1 -0
- package/dist/design/audit/reference/generate/parse.d.ts +28 -0
- package/dist/design/audit/reference/generate/parse.d.ts.map +1 -0
- package/dist/design/audit/reference/generate/parse.js +180 -0
- package/dist/design/audit/reference/generate/parse.js.map +1 -0
- package/dist/design/audit/reference/generate/prompt.d.ts +36 -0
- package/dist/design/audit/reference/generate/prompt.d.ts.map +1 -0
- package/dist/design/audit/reference/generate/prompt.js +124 -0
- package/dist/design/audit/reference/generate/prompt.js.map +1 -0
- package/dist/design/audit/reference/index.d.ts +26 -0
- package/dist/design/audit/reference/index.d.ts.map +1 -0
- package/dist/design/audit/reference/index.js +31 -0
- package/dist/design/audit/reference/index.js.map +1 -0
- package/dist/design/audit/reference/judge/image-clamp.d.ts +34 -0
- package/dist/design/audit/reference/judge/image-clamp.d.ts.map +1 -0
- package/dist/design/audit/reference/judge/image-clamp.js +88 -0
- package/dist/design/audit/reference/judge/image-clamp.js.map +1 -0
- package/dist/design/audit/reference/judge/pairwise.d.ts +34 -0
- package/dist/design/audit/reference/judge/pairwise.d.ts.map +1 -0
- package/dist/design/audit/reference/judge/pairwise.js +105 -0
- package/dist/design/audit/reference/judge/pairwise.js.map +1 -0
- package/dist/design/audit/reference/judge/parse.d.ts +31 -0
- package/dist/design/audit/reference/judge/parse.d.ts.map +1 -0
- package/dist/design/audit/reference/judge/parse.js +113 -0
- package/dist/design/audit/reference/judge/parse.js.map +1 -0
- package/dist/design/audit/reference/judge/prompt.d.ts +38 -0
- package/dist/design/audit/reference/judge/prompt.d.ts.map +1 -0
- package/dist/design/audit/reference/judge/prompt.js +111 -0
- package/dist/design/audit/reference/judge/prompt.js.map +1 -0
- package/dist/design/audit/reference/judge/quality.d.ts +28 -0
- package/dist/design/audit/reference/judge/quality.d.ts.map +1 -0
- package/dist/design/audit/reference/judge/quality.js +62 -0
- package/dist/design/audit/reference/judge/quality.js.map +1 -0
- package/dist/design/audit/reference/judge/rank.d.ts +41 -0
- package/dist/design/audit/reference/judge/rank.d.ts.map +1 -0
- package/dist/design/audit/reference/judge/rank.js +196 -0
- package/dist/design/audit/reference/judge/rank.js.map +1 -0
- package/dist/design/audit/reference/judge/text-judge.d.ts +31 -0
- package/dist/design/audit/reference/judge/text-judge.d.ts.map +1 -0
- package/dist/design/audit/reference/judge/text-judge.js +43 -0
- package/dist/design/audit/reference/judge/text-judge.js.map +1 -0
- package/dist/design/audit/reference/judge/vision-judge.d.ts +59 -0
- package/dist/design/audit/reference/judge/vision-judge.d.ts.map +1 -0
- package/dist/design/audit/reference/judge/vision-judge.js +150 -0
- package/dist/design/audit/reference/judge/vision-judge.js.map +1 -0
- package/dist/design/audit/reference/judge/vision-model.d.ts +65 -0
- package/dist/design/audit/reference/judge/vision-model.d.ts.map +1 -0
- package/dist/design/audit/reference/judge/vision-model.js +110 -0
- package/dist/design/audit/reference/judge/vision-model.js.map +1 -0
- package/dist/design/audit/reference/pipeline/evaluate-reference.d.ts +68 -0
- package/dist/design/audit/reference/pipeline/evaluate-reference.d.ts.map +1 -0
- package/dist/design/audit/reference/pipeline/evaluate-reference.js +52 -0
- package/dist/design/audit/reference/pipeline/evaluate-reference.js.map +1 -0
- package/dist/design/audit/reference/reference-context.d.ts +31 -0
- package/dist/design/audit/reference/reference-context.d.ts.map +1 -0
- package/dist/design/audit/reference/reference-context.js +73 -0
- package/dist/design/audit/reference/reference-context.js.map +1 -0
- package/dist/design/audit/reference/retrieval/embedding-hash.d.ts +30 -0
- package/dist/design/audit/reference/retrieval/embedding-hash.d.ts.map +1 -0
- package/dist/design/audit/reference/retrieval/embedding-hash.js +87 -0
- package/dist/design/audit/reference/retrieval/embedding-hash.js.map +1 -0
- package/dist/design/audit/reference/retrieval/embedding-openai.d.ts +38 -0
- package/dist/design/audit/reference/retrieval/embedding-openai.d.ts.map +1 -0
- package/dist/design/audit/reference/retrieval/embedding-openai.js +73 -0
- package/dist/design/audit/reference/retrieval/embedding-openai.js.map +1 -0
- package/dist/design/audit/reference/retrieval/matcher.d.ts +34 -0
- package/dist/design/audit/reference/retrieval/matcher.d.ts.map +1 -0
- package/dist/design/audit/reference/retrieval/matcher.js +107 -0
- package/dist/design/audit/reference/retrieval/matcher.js.map +1 -0
- package/dist/design/audit/reference/run.d.ts +59 -0
- package/dist/design/audit/reference/run.d.ts.map +1 -0
- package/dist/design/audit/reference/run.js +99 -0
- package/dist/design/audit/reference/run.js.map +1 -0
- package/dist/design/audit/report.d.ts +35 -0
- package/dist/design/audit/report.d.ts.map +1 -0
- package/dist/design/audit/report.js +195 -0
- package/dist/design/audit/report.js.map +1 -0
- package/dist/design/audit/tokens/extract.d.ts +71 -0
- package/dist/design/audit/tokens/extract.d.ts.map +1 -0
- package/dist/design/audit/tokens/extract.js +1034 -0
- package/dist/design/audit/tokens/extract.js.map +1 -0
- package/dist/design/audit/types.d.ts +8 -0
- package/dist/design/audit/types.d.ts.map +1 -1
- package/dist/design/compare.d.ts.map +1 -1
- package/dist/design/compare.js +2 -6
- package/dist/design/compare.js.map +1 -1
- package/dist/design/cookie-consent.d.ts +3 -0
- package/dist/design/cookie-consent.d.ts.map +1 -0
- package/dist/design/cookie-consent.js +26 -0
- package/dist/design/cookie-consent.js.map +1 -0
- package/dist/design/viewports.d.ts +18 -0
- package/dist/design/viewports.d.ts.map +1 -0
- package/dist/design/viewports.js +10 -0
- package/dist/design/viewports.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/memory/store.d.ts +19 -1
- package/dist/memory/store.d.ts.map +1 -1
- package/dist/memory/store.js +47 -0
- package/dist/memory/store.js.map +1 -1
- package/dist/provider-defaults.d.ts +18 -0
- package/dist/provider-defaults.d.ts.map +1 -1
- package/dist/provider-defaults.js +33 -0
- package/dist/provider-defaults.js.map +1 -1
- package/dist/runner/allowed-domains.d.ts +11 -0
- package/dist/runner/allowed-domains.d.ts.map +1 -0
- package/dist/runner/allowed-domains.js +14 -0
- package/dist/runner/allowed-domains.js.map +1 -0
- package/dist/runner/batch-fill.d.ts +28 -0
- package/dist/runner/batch-fill.d.ts.map +1 -0
- package/dist/runner/batch-fill.js +80 -0
- package/dist/runner/batch-fill.js.map +1 -0
- package/dist/runner/completion-policy.d.ts +26 -0
- package/dist/runner/completion-policy.d.ts.map +1 -0
- package/dist/runner/completion-policy.js +76 -0
- package/dist/runner/completion-policy.js.map +1 -0
- package/dist/runner/constants.d.ts +14 -0
- package/dist/runner/constants.d.ts.map +1 -0
- package/dist/runner/constants.js +23 -0
- package/dist/runner/constants.js.map +1 -0
- package/dist/runner/decision-screenshot.d.ts +24 -0
- package/dist/runner/decision-screenshot.d.ts.map +1 -0
- package/dist/runner/decision-screenshot.js +23 -0
- package/dist/runner/decision-screenshot.js.map +1 -0
- package/dist/runner/domain-boundary.d.ts +36 -0
- package/dist/runner/domain-boundary.d.ts.map +1 -0
- package/dist/runner/domain-boundary.js +81 -0
- package/dist/runner/domain-boundary.js.map +1 -0
- package/dist/runner/effect-verify.d.ts +28 -0
- package/dist/runner/effect-verify.d.ts.map +1 -0
- package/dist/runner/effect-verify.js +42 -0
- package/dist/runner/effect-verify.js.map +1 -0
- package/dist/runner/execute-plan.d.ts +58 -0
- package/dist/runner/execute-plan.d.ts.map +1 -0
- package/dist/runner/execute-plan.js +426 -0
- package/dist/runner/execute-plan.js.map +1 -0
- package/dist/runner/max-turns-extension.d.ts +19 -0
- package/dist/runner/max-turns-extension.d.ts.map +1 -0
- package/dist/runner/max-turns-extension.js +25 -0
- package/dist/runner/max-turns-extension.js.map +1 -0
- package/dist/runner/micro-plan.d.ts +11 -0
- package/dist/runner/micro-plan.d.ts.map +1 -0
- package/dist/runner/micro-plan.js +29 -0
- package/dist/runner/micro-plan.js.map +1 -0
- package/dist/runner/prompt-snippets.d.ts +5 -0
- package/dist/runner/prompt-snippets.d.ts.map +1 -0
- package/dist/runner/prompt-snippets.js +13 -0
- package/dist/runner/prompt-snippets.js.map +1 -0
- package/dist/runner/replay/contracts.d.ts +300 -0
- package/dist/runner/replay/contracts.d.ts.map +1 -0
- package/dist/runner/replay/contracts.js +42 -0
- package/dist/runner/replay/contracts.js.map +1 -0
- package/dist/runner/replay/controller.d.ts +27 -0
- package/dist/runner/replay/controller.d.ts.map +1 -0
- package/dist/runner/replay/controller.js +197 -0
- package/dist/runner/replay/controller.js.map +1 -0
- package/dist/runner/replay/guard.d.ts +28 -0
- package/dist/runner/replay/guard.d.ts.map +1 -0
- package/dist/runner/replay/guard.js +100 -0
- package/dist/runner/replay/guard.js.map +1 -0
- package/dist/runner/runner.d.ts +44 -51
- package/dist/runner/runner.d.ts.map +1 -1
- package/dist/runner/runner.js +155 -851
- package/dist/runner/runner.js.map +1 -1
- package/dist/runner/scout-feedback.d.ts +51 -0
- package/dist/runner/scout-feedback.d.ts.map +1 -0
- package/dist/runner/scout-feedback.js +149 -0
- package/dist/runner/scout-feedback.js.map +1 -0
- package/dist/skills/macro-loader.d.ts +1 -1
- package/dist/test-runner.d.ts.map +1 -1
- package/dist/test-runner.js +25 -0
- package/dist/test-runner.js.map +1 -1
- package/dist/types/actions.d.ts +241 -0
- package/dist/types/actions.d.ts.map +1 -0
- package/dist/types/actions.js +5 -0
- package/dist/types/actions.js.map +1 -0
- package/dist/types/config.d.ts +211 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +2 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/design-audit.d.ts +92 -0
- package/dist/types/design-audit.d.ts.map +1 -0
- package/dist/types/design-audit.js +5 -0
- package/dist/types/design-audit.js.map +1 -0
- package/dist/types/design-tokens.d.ts +138 -0
- package/dist/types/design-tokens.d.ts.map +1 -0
- package/dist/types/design-tokens.js +5 -0
- package/dist/types/design-tokens.js.map +1 -0
- package/dist/types/page.d.ts +16 -0
- package/dist/types/page.d.ts.map +1 -0
- package/dist/types/page.js +2 -0
- package/dist/types/page.js.map +1 -0
- package/dist/types/plan.d.ts +50 -0
- package/dist/types/plan.d.ts.map +1 -0
- package/dist/types/plan.js +2 -0
- package/dist/types/plan.js.map +1 -0
- package/dist/types/preview.d.ts +9 -0
- package/dist/types/preview.d.ts.map +1 -0
- package/dist/types/preview.js +5 -0
- package/dist/types/preview.js.map +1 -0
- package/dist/types/result.d.ts +62 -0
- package/dist/types/result.d.ts.map +1 -0
- package/dist/types/result.js +2 -0
- package/dist/types/result.js.map +1 -0
- package/dist/types/scenario.d.ts +20 -0
- package/dist/types/scenario.d.ts.map +1 -0
- package/dist/types/scenario.js +5 -0
- package/dist/types/scenario.js.map +1 -0
- package/dist/types/test-runner.d.ts +145 -0
- package/dist/types/test-runner.d.ts.map +1 -0
- package/dist/types/test-runner.js +10 -0
- package/dist/types/test-runner.js.map +1 -0
- package/dist/types/trajectory.d.ts +38 -0
- package/dist/types/trajectory.d.ts.map +1 -0
- package/dist/types/trajectory.js +2 -0
- package/dist/types/trajectory.js.map +1 -0
- package/dist/types/turn.d.ts +50 -0
- package/dist/types/turn.d.ts.map +1 -0
- package/dist/types/turn.js +2 -0
- package/dist/types/turn.js.map +1 -0
- package/dist/types.d.ts +16 -1017
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +15 -8
- package/dist/types.js.map +1 -1
- package/dist/wallet/rpc-interception.d.ts +15 -0
- package/dist/wallet/rpc-interception.d.ts.map +1 -0
- package/dist/wallet/rpc-interception.js +95 -0
- package/dist/wallet/rpc-interception.js.map +1 -0
- package/package.json +6 -2
|
@@ -0,0 +1,728 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { toAgentConfig } from '../../config.js';
|
|
4
|
+
import { buildBrowserLaunchPlan } from '../../browser-launch.js';
|
|
5
|
+
import { runWalletPreflight, startWalletAutoApprover } from '../../wallet/automation.js';
|
|
6
|
+
import { isPersonaId, listPersonaIds, withPersonaDirective } from '../../personas.js';
|
|
7
|
+
import { resolveProviderApiKey, resolveProviderModelName } from '../../provider-defaults.js';
|
|
8
|
+
import { CliRenderer, cliError, cliWarn, cliLog } from '../../cli-ui.js';
|
|
9
|
+
import { ProjectStore } from '../../memory/project-store.js';
|
|
10
|
+
import { RunRegistry } from '../../memory/run-registry.js';
|
|
11
|
+
import { applyStorageStateToPersistentContext } from '../../browser/storage-state.js';
|
|
12
|
+
import { STEALTH_INIT_SCRIPT } from '../../browser/stealth-init-script.js';
|
|
13
|
+
import { installWalletRpcInterception } from '../../wallet/rpc-interception.js';
|
|
14
|
+
import { buildDriverConfig } from '../build-config.js';
|
|
15
|
+
import { readCliVersion } from '../version.js';
|
|
16
|
+
import { syncLocalBenchmarkRun } from '../benchmark-sync.js';
|
|
17
|
+
export async function runRunCommand(values) {
|
|
18
|
+
// Validate inputs
|
|
19
|
+
if (!values.goal && !values.cases && !values['cases-json'] && !values['resume-run'] && !values['fork-run']) {
|
|
20
|
+
cliError('provide --goal "..." --url "..." for a single task, --cases ./cases.json (or --cases-json \'[...]\') for a suite, or --resume-run / --fork-run <runId>.');
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
// Load config file, overlay CLI flags, apply presets.
|
|
24
|
+
const driverConfig = await buildDriverConfig(values);
|
|
25
|
+
const mode = values.mode;
|
|
26
|
+
const launchPlan = buildBrowserLaunchPlan(driverConfig);
|
|
27
|
+
const quiet = values.quiet;
|
|
28
|
+
for (const warning of launchPlan.warnings) {
|
|
29
|
+
if (!quiet) {
|
|
30
|
+
cliWarn(warning);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (launchPlan.errors.length > 0) {
|
|
34
|
+
for (const error of launchPlan.errors) {
|
|
35
|
+
cliError(error);
|
|
36
|
+
}
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
// Dynamic imports keep startup fast. Prefer patchright for lower browser
|
|
40
|
+
// automation fingerprinting, falling back to regular Playwright.
|
|
41
|
+
const isStealthProfile = launchPlan.profile.includes('stealth');
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
43
|
+
let browserLib;
|
|
44
|
+
try {
|
|
45
|
+
browserLib = await import('patchright');
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
browserLib = await import('playwright');
|
|
49
|
+
}
|
|
50
|
+
const { chromium, firefox, webkit } = browserLib;
|
|
51
|
+
const { PlaywrightDriver } = await import('../../drivers/playwright.js');
|
|
52
|
+
const { TestRunner } = await import('../../test-runner.js');
|
|
53
|
+
const { FilesystemSink } = await import('../../artifacts/filesystem-sink.js');
|
|
54
|
+
const { loadExtensions } = await import('../../extensions/loader.js');
|
|
55
|
+
const { TurnEventBus } = await import('../../runner/events.js');
|
|
56
|
+
// Optional live event bus + SSE viewer. Constructed only when `--live` is
|
|
57
|
+
// passed; otherwise the runner uses an internal no-op bus and pays nothing.
|
|
58
|
+
// The bus is shared across the entire suite so a single SSE connection
|
|
59
|
+
// observes all turns of all test cases. When `--stream <url>` is passed
|
|
60
|
+
// the bus is always created so the webhook streamer can subscribe.
|
|
61
|
+
const liveEnabled = values.live === true;
|
|
62
|
+
const streamUrl = typeof values.stream === 'string' && values.stream.length > 0 ? values.stream : undefined;
|
|
63
|
+
const needsBus = liveEnabled || !!streamUrl;
|
|
64
|
+
const liveBus = needsBus ? new TurnEventBus() : undefined;
|
|
65
|
+
const liveCancelController = liveEnabled ? new AbortController() : undefined;
|
|
66
|
+
let liveViewHandle;
|
|
67
|
+
if (liveEnabled && liveBus) {
|
|
68
|
+
const { runLiveView } = await import('../../cli-view-live.js');
|
|
69
|
+
liveViewHandle = await runLiveView({
|
|
70
|
+
bus: liveBus,
|
|
71
|
+
...(liveCancelController ? { cancelController: liveCancelController } : {}),
|
|
72
|
+
port: values.port ? parseInt(values.port, 10) : undefined,
|
|
73
|
+
noOpen: values['no-open'] === true,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
// Webhook streamer. When `--stream <url>` is passed, subscribe
|
|
77
|
+
// to the bus and POST every event to <url> as it fires. Auth via
|
|
78
|
+
// `--stream-token` or $BAD_STREAM_TOKEN. Non-fatal on failure — the
|
|
79
|
+
// canonical record is always events.jsonl on disk.
|
|
80
|
+
let webhookStreamer;
|
|
81
|
+
if (streamUrl && liveBus) {
|
|
82
|
+
const { WebhookStreamer } = await import('../../runner/stream-webhook.js');
|
|
83
|
+
const token = values['stream-token'] || process.env.BAD_STREAM_TOKEN;
|
|
84
|
+
const streamId = `stream_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
85
|
+
webhookStreamer = new WebhookStreamer({
|
|
86
|
+
url: streamUrl,
|
|
87
|
+
authToken: token,
|
|
88
|
+
streamId,
|
|
89
|
+
onError: (err, dropped) => {
|
|
90
|
+
if (!values.json)
|
|
91
|
+
cliWarn(`stream: ${err.message} (dropped ${dropped} event${dropped === 1 ? '' : 's'})`);
|
|
92
|
+
},
|
|
93
|
+
}).attach(liveBus);
|
|
94
|
+
if (!values.json)
|
|
95
|
+
cliLog('stream', `POST → ${streamUrl} (id ${streamId})`);
|
|
96
|
+
}
|
|
97
|
+
// Interrupt controller. `--interrupt` enables keyboard pause/
|
|
98
|
+
// resume/abort during a run. No-op in non-TTY (CI, piped output).
|
|
99
|
+
let interruptController;
|
|
100
|
+
let detachInterrupt;
|
|
101
|
+
if (values.interrupt === true && process.stdin.isTTY) {
|
|
102
|
+
const { InterruptController } = await import('../../runner/interrupt-controller.js');
|
|
103
|
+
interruptController = new InterruptController({
|
|
104
|
+
onStatus: (msg) => { if (!values.json)
|
|
105
|
+
cliLog('interrupt', msg); },
|
|
106
|
+
});
|
|
107
|
+
detachInterrupt = interruptController.attach();
|
|
108
|
+
}
|
|
109
|
+
// Auto-discover bad.config.{ts,mjs,js,...} from cwd plus any explicit
|
|
110
|
+
// --extension paths. Failures are reported but never fatal: a broken user
|
|
111
|
+
// config should warn, not abort the run.
|
|
112
|
+
const explicitExtPaths = (values.extension ?? []);
|
|
113
|
+
const explicitExtArr = Array.isArray(explicitExtPaths)
|
|
114
|
+
? explicitExtPaths
|
|
115
|
+
: explicitExtPaths
|
|
116
|
+
? [explicitExtPaths]
|
|
117
|
+
: [];
|
|
118
|
+
// Domain skills: markdown-based per-host rule libraries under
|
|
119
|
+
// skills/domain/<host>/SKILL.md. They plumb into the same BadExtension
|
|
120
|
+
// pipeline as user `bad.config.mjs` files via addRulesForDomain, so the
|
|
121
|
+
// existing setExtensionRules injection at brain/index.ts:899 picks them up
|
|
122
|
+
// with no second injection site. Gated by BAD_DOMAIN_SKILLS_DISABLED=1.
|
|
123
|
+
const domainSkillsDisabled = process.env.BAD_DOMAIN_SKILLS_DISABLED === '1';
|
|
124
|
+
let domainSkillExtension;
|
|
125
|
+
let domainSkillsLoadedCount = 0;
|
|
126
|
+
if (!domainSkillsDisabled) {
|
|
127
|
+
const { loadDomainSkills, buildDomainSkillExtension } = await import('../../skills/domain-loader.js');
|
|
128
|
+
const domainLoad = await loadDomainSkills();
|
|
129
|
+
if (domainLoad.skills.length > 0) {
|
|
130
|
+
domainSkillExtension = buildDomainSkillExtension(domainLoad.skills);
|
|
131
|
+
domainSkillsLoadedCount = domainLoad.skills.length;
|
|
132
|
+
}
|
|
133
|
+
if (domainLoad.errors.length > 0 && !values.json) {
|
|
134
|
+
for (const err of domainLoad.errors) {
|
|
135
|
+
cliWarn(`domain-skill load failed: ${err.path} — ${err.error}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const extensionLoad = await loadExtensions({ explicitPaths: explicitExtArr });
|
|
140
|
+
if (extensionLoad.loadedFrom.length > 0 && !values.json) {
|
|
141
|
+
cliLog('extensions', `loaded ${extensionLoad.loadedFrom.length}: ${extensionLoad.loadedFrom.join(', ')}`);
|
|
142
|
+
}
|
|
143
|
+
if (extensionLoad.errors.length > 0 && !values.json) {
|
|
144
|
+
for (const err of extensionLoad.errors) {
|
|
145
|
+
cliWarn(`extension load failed: ${err.path} — ${err.error}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (domainSkillExtension && domainSkillsLoadedCount > 0) {
|
|
149
|
+
// Re-resolve the bundle with the domain-skill synthetic extension
|
|
150
|
+
// merged in. Resolving twice is cheap (the list is short) and keeps
|
|
151
|
+
// domainSkillExtension from having to plumb through a separate wire.
|
|
152
|
+
const { resolveExtensions } = await import('../../extensions/types.js');
|
|
153
|
+
const combined = resolveExtensions([...extensionLoad.resolved.extensions, domainSkillExtension]);
|
|
154
|
+
extensionLoad.resolved = combined;
|
|
155
|
+
if (!values.json)
|
|
156
|
+
cliLog('skills', `domain: ${domainSkillsLoadedCount} loaded`);
|
|
157
|
+
}
|
|
158
|
+
// Macros. Loaded alongside domain skills; gated by BAD_MACROS_DISABLED=1.
|
|
159
|
+
// The registry is passed to PlaywrightDriver and its promptBlock to BrowserAgent.
|
|
160
|
+
const macrosDisabled = process.env.BAD_MACROS_DISABLED === '1';
|
|
161
|
+
let macroRegistry;
|
|
162
|
+
if (!macrosDisabled) {
|
|
163
|
+
const { loadMacros, buildMacroRegistry } = await import('../../skills/macro-loader.js');
|
|
164
|
+
const macroLoad = await loadMacros();
|
|
165
|
+
if (macroLoad.errors.length > 0 && !values.json) {
|
|
166
|
+
for (const err of macroLoad.errors) {
|
|
167
|
+
cliWarn(`macro load failed: ${err.path} — ${err.error}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (macroLoad.macros.length > 0) {
|
|
171
|
+
macroRegistry = buildMacroRegistry(macroLoad.macros);
|
|
172
|
+
if (!values.json)
|
|
173
|
+
cliLog('skills', `macros: ${macroLoad.macros.length} loaded`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
const concurrency = launchPlan.concurrency;
|
|
177
|
+
const maxTurns = driverConfig.maxTurns ?? 30;
|
|
178
|
+
const screenshotInterval = driverConfig.screenshotInterval ?? 5;
|
|
179
|
+
const timeoutMs = driverConfig.timeoutMs ?? 600_000;
|
|
180
|
+
const browserName = driverConfig.browser ?? 'chromium';
|
|
181
|
+
const debug = values.debug;
|
|
182
|
+
const sinkDir = driverConfig.outputDir ?? './agent-results';
|
|
183
|
+
const resolvedProvider = driverConfig.provider || 'openai';
|
|
184
|
+
const resolvedApiKey = resolveProviderApiKey(resolvedProvider, driverConfig.apiKey);
|
|
185
|
+
const resolvedModel = resolveProviderModelName(resolvedProvider, driverConfig.model, {
|
|
186
|
+
sandboxBackendType: resolvedProvider === 'sandbox-backend' ? driverConfig.sandboxBackendType : undefined,
|
|
187
|
+
});
|
|
188
|
+
const resolvedNavProvider = driverConfig.navProvider || resolvedProvider;
|
|
189
|
+
const resolvedNavModel = driverConfig.navModel
|
|
190
|
+
? resolveProviderModelName(resolvedNavProvider, driverConfig.navModel, {
|
|
191
|
+
sandboxBackendType: resolvedNavProvider === 'sandbox-backend' ? driverConfig.sandboxBackendType : undefined,
|
|
192
|
+
})
|
|
193
|
+
: undefined;
|
|
194
|
+
const resolvedSupervisorProvider = driverConfig.supervisor?.provider || resolvedProvider;
|
|
195
|
+
const resolvedSupervisorModel = resolveProviderModelName(resolvedSupervisorProvider, driverConfig.supervisor?.model || resolvedModel, {
|
|
196
|
+
sandboxBackendType: resolvedSupervisorProvider === 'sandbox-backend' ? driverConfig.sandboxBackendType : undefined,
|
|
197
|
+
});
|
|
198
|
+
const config = {
|
|
199
|
+
...toAgentConfig(driverConfig),
|
|
200
|
+
model: resolvedModel,
|
|
201
|
+
...(resolvedNavModel ? { navModel: resolvedNavModel } : {}),
|
|
202
|
+
apiKey: resolvedApiKey,
|
|
203
|
+
baseUrl: driverConfig.baseUrl || process.env.LLM_BASE_URL,
|
|
204
|
+
supervisor: driverConfig.supervisor
|
|
205
|
+
? {
|
|
206
|
+
...driverConfig.supervisor,
|
|
207
|
+
provider: resolvedSupervisorProvider,
|
|
208
|
+
model: resolvedSupervisorModel,
|
|
209
|
+
}
|
|
210
|
+
: undefined,
|
|
211
|
+
debug,
|
|
212
|
+
walletMode: Boolean(driverConfig.wallet?.enabled),
|
|
213
|
+
walletAddress: driverConfig.wallet?.address,
|
|
214
|
+
};
|
|
215
|
+
// Create project store for memory + run registry
|
|
216
|
+
const memoryEnabled = driverConfig.memory?.enabled === true;
|
|
217
|
+
const projectStore = memoryEnabled
|
|
218
|
+
? new ProjectStore(driverConfig.memory?.dir)
|
|
219
|
+
: undefined;
|
|
220
|
+
const runRegistry = projectStore
|
|
221
|
+
? new RunRegistry(projectStore.getRoot())
|
|
222
|
+
: undefined;
|
|
223
|
+
// Build test cases
|
|
224
|
+
let cases;
|
|
225
|
+
if (values['resume-run'] || values['fork-run']) {
|
|
226
|
+
// Resume or fork from a previous run
|
|
227
|
+
if (!runRegistry) {
|
|
228
|
+
cliError('--resume-run and --fork-run require memory to be enabled');
|
|
229
|
+
process.exit(1);
|
|
230
|
+
}
|
|
231
|
+
const isResume = Boolean(values['resume-run']);
|
|
232
|
+
const sourceRunId = (values['resume-run'] || values['fork-run']);
|
|
233
|
+
const scenario = isResume
|
|
234
|
+
? runRegistry.buildResumeScenario(sourceRunId, values.goal)
|
|
235
|
+
: runRegistry.buildForkScenario(sourceRunId, values.goal || '');
|
|
236
|
+
if (!scenario) {
|
|
237
|
+
cliError(`run "${sourceRunId}" not found in registry`);
|
|
238
|
+
process.exit(1);
|
|
239
|
+
}
|
|
240
|
+
if (!isResume && !values.goal) {
|
|
241
|
+
cliError('--fork-run requires --goal');
|
|
242
|
+
process.exit(1);
|
|
243
|
+
}
|
|
244
|
+
cases = [{
|
|
245
|
+
id: `${isResume ? 'resume' : 'fork'}-${sourceRunId.slice(0, 20)}`,
|
|
246
|
+
name: scenario.goal.slice(0, 60),
|
|
247
|
+
startUrl: values.url || scenario.startUrl,
|
|
248
|
+
goal: scenario.goal,
|
|
249
|
+
allowedDomains: parseAllowedDomains(values['allowed-domains']),
|
|
250
|
+
maxTurns,
|
|
251
|
+
timeoutMs,
|
|
252
|
+
priority: 0,
|
|
253
|
+
sessionId: scenario.sessionId,
|
|
254
|
+
parentRunId: scenario.parentRunId,
|
|
255
|
+
}];
|
|
256
|
+
}
|
|
257
|
+
else if (values['cases-json'] || values.cases) {
|
|
258
|
+
const raw = values['cases-json'] || fs.readFileSync(path.resolve(values.cases), 'utf-8');
|
|
259
|
+
const parsed = JSON.parse(raw);
|
|
260
|
+
const rawCases = Array.isArray(parsed) ? parsed : [parsed];
|
|
261
|
+
// Ensure required fields — spread raw case first so explicit fields become defaults
|
|
262
|
+
cases = rawCases.map((c, i) => ({
|
|
263
|
+
id: c.id || `case-${i}`,
|
|
264
|
+
name: c.name || c.goal?.slice(0, 60) || `Case ${i}`,
|
|
265
|
+
startUrl: c.startUrl || c.url || values.url || '',
|
|
266
|
+
goal: c.goal || '',
|
|
267
|
+
allowedDomains: Array.isArray(c.allowedDomains)
|
|
268
|
+
? c.allowedDomains.filter((domain) => typeof domain === 'string' && domain.length > 0)
|
|
269
|
+
: parseAllowedDomains(values['allowed-domains']),
|
|
270
|
+
maxTurns: c.maxTurns || maxTurns,
|
|
271
|
+
timeoutMs: c.timeoutMs || timeoutMs,
|
|
272
|
+
priority: c.priority ?? i,
|
|
273
|
+
}));
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
cases = [{
|
|
277
|
+
id: 'cli-task',
|
|
278
|
+
name: values.goal.slice(0, 60),
|
|
279
|
+
startUrl: values.url || '',
|
|
280
|
+
goal: values.goal,
|
|
281
|
+
allowedDomains: parseAllowedDomains(values['allowed-domains']),
|
|
282
|
+
maxTurns,
|
|
283
|
+
timeoutMs,
|
|
284
|
+
priority: 0,
|
|
285
|
+
sessionId: values['session-id'],
|
|
286
|
+
}];
|
|
287
|
+
}
|
|
288
|
+
// Apply --session-id to all cases from file too
|
|
289
|
+
if (values['session-id'] && cases.length > 0 && cases[0].id !== 'cli-task') {
|
|
290
|
+
const sid = values['session-id'];
|
|
291
|
+
cases = cases.map(c => ({ ...c, sessionId: c.sessionId || sid }));
|
|
292
|
+
}
|
|
293
|
+
const persona = values.persona;
|
|
294
|
+
if (persona) {
|
|
295
|
+
if (!isPersonaId(persona)) {
|
|
296
|
+
cliError(`unknown persona "${persona}". Valid personas: ${listPersonaIds().join(', ')}`);
|
|
297
|
+
process.exit(1);
|
|
298
|
+
}
|
|
299
|
+
cases = cases.map((c) => ({
|
|
300
|
+
...c,
|
|
301
|
+
goal: withPersonaDirective({
|
|
302
|
+
persona,
|
|
303
|
+
goal: c.goal,
|
|
304
|
+
startUrl: c.startUrl,
|
|
305
|
+
}),
|
|
306
|
+
}));
|
|
307
|
+
}
|
|
308
|
+
const renderer = (!quiet && !values.json) ? new CliRenderer({ debug }) : null;
|
|
309
|
+
if (renderer) {
|
|
310
|
+
const version = readCliVersion();
|
|
311
|
+
renderer.banner({
|
|
312
|
+
version,
|
|
313
|
+
provider: config.provider || 'openai',
|
|
314
|
+
model: config.model,
|
|
315
|
+
browser: browserName,
|
|
316
|
+
testCount: cases.length,
|
|
317
|
+
concurrency,
|
|
318
|
+
mode: mode || undefined,
|
|
319
|
+
profile: driverConfig.profile,
|
|
320
|
+
adaptiveRouting: config.adaptiveModelRouting ? {
|
|
321
|
+
navProvider: config.navProvider || config.provider || 'openai',
|
|
322
|
+
navModel: config.navModel || 'gpt-4.1-mini',
|
|
323
|
+
} : undefined,
|
|
324
|
+
outputDir: sinkDir,
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
// Set up artifact sink
|
|
328
|
+
const sink = new FilesystemSink(path.resolve(sinkDir));
|
|
329
|
+
const videoDir = path.join(sinkDir, '_videos');
|
|
330
|
+
const viewport = launchPlan.viewport;
|
|
331
|
+
const storageStatePath = driverConfig.storageState
|
|
332
|
+
? path.resolve(driverConfig.storageState)
|
|
333
|
+
: undefined;
|
|
334
|
+
if (storageStatePath && !fs.existsSync(storageStatePath)) {
|
|
335
|
+
cliError(`storage state file not found: ${storageStatePath}`);
|
|
336
|
+
process.exit(1);
|
|
337
|
+
}
|
|
338
|
+
if (launchPlan.persistentContext && !launchPlan.cdpUrl && browserName !== 'chromium') {
|
|
339
|
+
const feature = launchPlan.walletMode ? 'Wallet mode' : '--profile-dir';
|
|
340
|
+
throw new Error(`${feature} requires Chromium. Set --browser chromium.`);
|
|
341
|
+
}
|
|
342
|
+
// Ensure clean exit on interrupt
|
|
343
|
+
process.on('SIGINT', () => { renderer?.destroy(); process.exit(130); });
|
|
344
|
+
process.on('SIGTERM', () => { renderer?.destroy(); process.exit(143); });
|
|
345
|
+
renderer?.launchStart(browserName);
|
|
346
|
+
// Set up browser
|
|
347
|
+
let browser;
|
|
348
|
+
let persistentContext;
|
|
349
|
+
let stopWalletAutoApprover;
|
|
350
|
+
const launchDiagnostics = {};
|
|
351
|
+
// CDP connection — attach to an existing browser (Atlas, Chrome, Brave, etc.)
|
|
352
|
+
let cdpUrl = launchPlan.cdpUrl || process.env.BROWSER_ENDPOINT;
|
|
353
|
+
let cdpConnected = false;
|
|
354
|
+
if (cdpUrl) {
|
|
355
|
+
// Auto-discover WebSocket URL from HTTP endpoint
|
|
356
|
+
if (cdpUrl.startsWith('http://') || cdpUrl.startsWith('https://')) {
|
|
357
|
+
try {
|
|
358
|
+
const versionUrl = cdpUrl.replace(/\/$/, '') + '/json/version';
|
|
359
|
+
const res = await fetch(versionUrl);
|
|
360
|
+
const info = await res.json();
|
|
361
|
+
if (info.webSocketDebuggerUrl) {
|
|
362
|
+
if (info.Browser && !quiet)
|
|
363
|
+
cliLog('cdp', `connected to ${info.Browser}`);
|
|
364
|
+
cdpUrl = info.webSocketDebuggerUrl;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
catch {
|
|
368
|
+
// Fall through — try the URL as-is
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
const cdpStartedAt = Date.now();
|
|
372
|
+
if (cdpUrl.includes('/devtools/') || browserName === 'chromium') {
|
|
373
|
+
browser = await chromium.connectOverCDP(cdpUrl);
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
const browserType = browserName === 'firefox' ? firefox : browserName === 'webkit' ? webkit : chromium;
|
|
377
|
+
browser = await browserType.connect(cdpUrl);
|
|
378
|
+
}
|
|
379
|
+
launchDiagnostics.browserLaunchMs = Date.now() - cdpStartedAt;
|
|
380
|
+
launchDiagnostics.cdpUrl = cdpUrl;
|
|
381
|
+
cdpConnected = true;
|
|
382
|
+
}
|
|
383
|
+
else if (launchPlan.persistentContext) {
|
|
384
|
+
for (const extensionPath of launchPlan.extensionPaths) {
|
|
385
|
+
if (!fs.existsSync(extensionPath)) {
|
|
386
|
+
throw new Error(`Wallet extension path does not exist: ${extensionPath}`);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
const userDataDir = launchPlan.userDataDir ?? path.resolve(launchPlan.walletMode ? '.agent-wallet-profile' : '.agent-profile');
|
|
390
|
+
fs.mkdirSync(userDataDir, { recursive: true });
|
|
391
|
+
const persistentLaunchStartedAt = Date.now();
|
|
392
|
+
persistentContext = await chromium.launchPersistentContext(userDataDir, {
|
|
393
|
+
channel: isStealthProfile ? 'chrome' : 'chromium',
|
|
394
|
+
headless: launchPlan.headless,
|
|
395
|
+
args: launchPlan.browserArgs,
|
|
396
|
+
viewport,
|
|
397
|
+
recordVideo: { dir: videoDir, size: viewport },
|
|
398
|
+
...(launchPlan.proxyServer
|
|
399
|
+
? { proxy: { server: launchPlan.proxyServer, ...(launchPlan.proxyBypass ? { bypass: launchPlan.proxyBypass } : {}) } }
|
|
400
|
+
: {}),
|
|
401
|
+
...(launchPlan.ignoreHTTPSErrors ? { ignoreHTTPSErrors: true } : {}),
|
|
402
|
+
});
|
|
403
|
+
launchDiagnostics.browserLaunchMs = Date.now() - persistentLaunchStartedAt;
|
|
404
|
+
await applyStorageStateToPersistentContext(persistentContext, storageStatePath);
|
|
405
|
+
if (launchPlan.walletMode) {
|
|
406
|
+
const walletConfig = driverConfig.wallet ?? {};
|
|
407
|
+
// Intercept page-level JSON-RPC so dApps see wallet balances from the
|
|
408
|
+
// local Anvil fork. Only forward user-specific calls (eth_getBalance
|
|
409
|
+
// for the wallet, eth_call with wallet address in calldata). Pool data
|
|
410
|
+
// and protocol calls go to real endpoints for reliability.
|
|
411
|
+
const walletRpcUrl = walletConfig.preflight?.chain?.rpcUrl;
|
|
412
|
+
if (walletRpcUrl) {
|
|
413
|
+
await installWalletRpcInterception(persistentContext, {
|
|
414
|
+
rpcUrl: walletRpcUrl,
|
|
415
|
+
walletAddress: walletConfig.address,
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
const shouldAutoApprove = walletConfig.autoApprove ?? true;
|
|
419
|
+
if (shouldAutoApprove) {
|
|
420
|
+
stopWalletAutoApprover = await startWalletAutoApprover(persistentContext, {
|
|
421
|
+
password: walletConfig.password,
|
|
422
|
+
tickMs: walletConfig.tickMs,
|
|
423
|
+
actionSelectors: walletConfig.actionSelectors,
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
const preflightEnabled = walletConfig.preflight?.enabled ?? true;
|
|
427
|
+
const preflightSeedUrls = walletConfig.preflight?.seedUrls && walletConfig.preflight.seedUrls.length > 0
|
|
428
|
+
? walletConfig.preflight.seedUrls
|
|
429
|
+
: [...new Set(cases.map((testCase) => testCase.startUrl).filter(Boolean))];
|
|
430
|
+
if (preflightEnabled && preflightSeedUrls.length > 0) {
|
|
431
|
+
const preflight = await runWalletPreflight(persistentContext, {
|
|
432
|
+
seedUrls: preflightSeedUrls,
|
|
433
|
+
password: walletConfig.password,
|
|
434
|
+
actionSelectors: walletConfig.actionSelectors,
|
|
435
|
+
promptPaths: walletConfig.promptPaths,
|
|
436
|
+
connectSelectors: walletConfig.connectSelectors,
|
|
437
|
+
connectorSelectors: walletConfig.connectorSelectors,
|
|
438
|
+
requestAccounts: walletConfig.preflight?.requestAccounts,
|
|
439
|
+
accountsTimeoutMs: walletConfig.preflight?.accountsTimeoutMs,
|
|
440
|
+
maxChainSwitchAttempts: walletConfig.preflight?.maxChainSwitchAttempts,
|
|
441
|
+
chain: walletConfig.preflight?.chain,
|
|
442
|
+
log: quiet ? undefined : (message) => cliLog('wallet', message),
|
|
443
|
+
});
|
|
444
|
+
if (!preflight.ok) {
|
|
445
|
+
const failed = preflight.results.find((resultEntry) => !resultEntry.ready);
|
|
446
|
+
const details = failed?.details ?? 'unknown reason';
|
|
447
|
+
throw new Error(`Wallet preflight failed for ${preflight.failedUrl ?? 'unknown origin'} (${details})`);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
const browserType = browserName === 'firefox'
|
|
454
|
+
? firefox
|
|
455
|
+
: browserName === 'webkit'
|
|
456
|
+
? webkit
|
|
457
|
+
: chromium;
|
|
458
|
+
const browserLaunchStartedAt = Date.now();
|
|
459
|
+
browser = await browserType.launch({
|
|
460
|
+
headless: launchPlan.headless,
|
|
461
|
+
...(browserName === 'chromium' ? { args: launchPlan.browserArgs } : {}),
|
|
462
|
+
// System Chrome for stealth profiles only — real TLS/JA3 fingerprint
|
|
463
|
+
// fixes anti-bot blocking. But system Chrome renders differently than
|
|
464
|
+
// bundled Chromium on some sites (Allrecipes click timeouts, Amazon
|
|
465
|
+
// layout shifts), so only enable when anti-bot evasion is needed.
|
|
466
|
+
...(isStealthProfile && browserName === 'chromium' ? { channel: 'chrome' } : {}),
|
|
467
|
+
// Residential/SOCKS5/HTTP proxy — routes all traffic through the proxy
|
|
468
|
+
...(launchPlan.proxyServer
|
|
469
|
+
? { proxy: { server: launchPlan.proxyServer, ...(launchPlan.proxyBypass ? { bypass: launchPlan.proxyBypass } : {}) } }
|
|
470
|
+
: {}),
|
|
471
|
+
});
|
|
472
|
+
launchDiagnostics.browserLaunchMs = Date.now() - browserLaunchStartedAt;
|
|
473
|
+
}
|
|
474
|
+
// Headless Chromium sends "HeadlessChrome/..." in the default User-Agent.
|
|
475
|
+
// CDNs like Akamai reject this with ERR_HTTP2_PROTOCOL_ERROR before any JS
|
|
476
|
+
// stealth patches can run. Build a clean UA from the browser version.
|
|
477
|
+
const headlessUserAgent = launchPlan.headless && browser
|
|
478
|
+
? (() => {
|
|
479
|
+
const ver = browser.version();
|
|
480
|
+
const plat = process.platform;
|
|
481
|
+
const platformToken = plat === 'win32'
|
|
482
|
+
? 'Windows NT 10.0; Win64; x64'
|
|
483
|
+
: plat === 'linux'
|
|
484
|
+
? 'X11; Linux x86_64'
|
|
485
|
+
: 'Macintosh; Intel Mac OS X 10_15_7';
|
|
486
|
+
return `Mozilla/5.0 (${platformToken}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${ver} Safari/537.36`;
|
|
487
|
+
})()
|
|
488
|
+
: undefined;
|
|
489
|
+
const driverFactory = async () => {
|
|
490
|
+
const contextStartedAt = Date.now();
|
|
491
|
+
// CDP: reuse the browser's default context (preserves user cookies/sessions).
|
|
492
|
+
// Persistent context: use the already-opened persistent context.
|
|
493
|
+
// Default: create a fresh isolated context.
|
|
494
|
+
let context;
|
|
495
|
+
if (cdpConnected) {
|
|
496
|
+
// Reuse the user's existing browser context — cookies, localStorage, extensions intact
|
|
497
|
+
const contexts = browser.contexts();
|
|
498
|
+
// A freshly-created CDP context still honors egress; the reused contexts[0] is the user's own
|
|
499
|
+
// browser context (see the --cdp-url egress warning in buildBrowserLaunchPlan), left untouched.
|
|
500
|
+
context = contexts[0] ?? await browser.newContext({
|
|
501
|
+
viewport,
|
|
502
|
+
...(launchPlan.ignoreHTTPSErrors ? { ignoreHTTPSErrors: true } : {}),
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
else if (persistentContext) {
|
|
506
|
+
context = persistentContext;
|
|
507
|
+
}
|
|
508
|
+
else {
|
|
509
|
+
context = await browser.newContext({
|
|
510
|
+
viewport,
|
|
511
|
+
recordVideo: { dir: videoDir, size: viewport },
|
|
512
|
+
storageState: storageStatePath,
|
|
513
|
+
locale: 'en-US',
|
|
514
|
+
timezoneId: 'America/New_York',
|
|
515
|
+
...(headlessUserAgent ? { userAgent: headlessUserAgent } : {}),
|
|
516
|
+
// Accept the managed egress proxy's MITM cert (its CA isn't in Chromium's trust store).
|
|
517
|
+
...(launchPlan.ignoreHTTPSErrors ? { ignoreHTTPSErrors: true } : {}),
|
|
518
|
+
extraHTTPHeaders: {
|
|
519
|
+
'Accept-Language': 'en-US,en;q=0.9',
|
|
520
|
+
},
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
// Stealth patches: only for Playwright-controlled contexts (not real user browsers)
|
|
524
|
+
if (!cdpConnected) {
|
|
525
|
+
await context.addInitScript(STEALTH_INIT_SCRIPT);
|
|
526
|
+
}
|
|
527
|
+
const contextCreateMs = Date.now() - contextStartedAt;
|
|
528
|
+
const pageStartedAt = Date.now();
|
|
529
|
+
const page = await context.newPage();
|
|
530
|
+
const pageCreateMs = Date.now() - pageStartedAt;
|
|
531
|
+
// Cap per-action timeout so one stuck click can't consume the whole case budget.
|
|
532
|
+
// Default 30s is fine for long runs; for short cases (120s) use at most 15s.
|
|
533
|
+
const actionTimeout = Math.min(30_000, Math.max(5_000, Math.floor(timeoutMs / 8)));
|
|
534
|
+
const driver = new PlaywrightDriver(page, {
|
|
535
|
+
captureScreenshots: config.vision,
|
|
536
|
+
screenshotQuality: 50,
|
|
537
|
+
disableCdp: driverConfig.disableCdp,
|
|
538
|
+
timeout: actionTimeout,
|
|
539
|
+
visionStrategy: config.visionStrategy,
|
|
540
|
+
screenshotInterval,
|
|
541
|
+
showCursor: values['show-cursor'],
|
|
542
|
+
...(macroRegistry ? { macros: macroRegistry } : {}),
|
|
543
|
+
});
|
|
544
|
+
// Apply resource blocking if configured
|
|
545
|
+
const resourceBlockingStartedAt = Date.now();
|
|
546
|
+
if (driverConfig.resourceBlocking) {
|
|
547
|
+
await driver.setupResourceBlocking(driverConfig.resourceBlocking);
|
|
548
|
+
}
|
|
549
|
+
const resourceBlockingSetupMs = driverConfig.resourceBlocking
|
|
550
|
+
? Date.now() - resourceBlockingStartedAt
|
|
551
|
+
: 0;
|
|
552
|
+
const diagnostics = {
|
|
553
|
+
browserName,
|
|
554
|
+
headless: launchPlan.headless,
|
|
555
|
+
walletMode: launchPlan.walletMode,
|
|
556
|
+
browserLaunchMs: Number(launchDiagnostics.browserLaunchMs ?? 0),
|
|
557
|
+
contextCreateMs,
|
|
558
|
+
pageCreateMs,
|
|
559
|
+
resourceBlockingSetupMs,
|
|
560
|
+
storageStateApplied: Boolean(storageStatePath) && !cdpConnected,
|
|
561
|
+
persistentContext: Boolean(persistentContext),
|
|
562
|
+
cdpConnected,
|
|
563
|
+
};
|
|
564
|
+
// Wrap in a Driver that properly tears down context on close
|
|
565
|
+
const wrappedDriver = {
|
|
566
|
+
observe: () => driver.observe(),
|
|
567
|
+
execute: (action) => driver.execute(action),
|
|
568
|
+
getPage: () => driver.getPage?.(),
|
|
569
|
+
screenshot: () => driver.screenshot(),
|
|
570
|
+
getDiagnostics: () => diagnostics,
|
|
571
|
+
async close() {
|
|
572
|
+
await driver.close().catch(() => { });
|
|
573
|
+
await page.close().catch(() => { });
|
|
574
|
+
if (!persistentContext && !cdpConnected) {
|
|
575
|
+
await context.close().catch(() => { });
|
|
576
|
+
}
|
|
577
|
+
},
|
|
578
|
+
};
|
|
579
|
+
return wrappedDriver;
|
|
580
|
+
};
|
|
581
|
+
// Create a single driver for sequential mode
|
|
582
|
+
let singleDriver;
|
|
583
|
+
if (concurrency <= 1) {
|
|
584
|
+
singleDriver = await driverFactory();
|
|
585
|
+
}
|
|
586
|
+
renderer?.launchDone();
|
|
587
|
+
const runner = new TestRunner({
|
|
588
|
+
config,
|
|
589
|
+
defaultTimeoutMs: timeoutMs,
|
|
590
|
+
driver: singleDriver,
|
|
591
|
+
driverFactory: concurrency > 1 ? driverFactory : undefined,
|
|
592
|
+
enableMemory: memoryEnabled,
|
|
593
|
+
trajectoryStorePath: driverConfig.memory?.dir,
|
|
594
|
+
projectStore,
|
|
595
|
+
concurrency,
|
|
596
|
+
screenshotInterval,
|
|
597
|
+
artifactSink: sink,
|
|
598
|
+
extensions: extensionLoad.resolved,
|
|
599
|
+
...(macroRegistry ? { macroPromptBlock: macroRegistry.promptBlock } : {}),
|
|
600
|
+
...(liveBus ? { eventBus: liveBus } : {}),
|
|
601
|
+
...(interruptController
|
|
602
|
+
? { beforeTurn: async () => { await interruptController.waitIfPaused(); } }
|
|
603
|
+
: {}),
|
|
604
|
+
onProgress: (event) => {
|
|
605
|
+
if (values.json) {
|
|
606
|
+
console.log(JSON.stringify(event));
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
609
|
+
if (!renderer)
|
|
610
|
+
return;
|
|
611
|
+
switch (event.type) {
|
|
612
|
+
case 'suite:start':
|
|
613
|
+
renderer.suiteStart(event.totalTests);
|
|
614
|
+
break;
|
|
615
|
+
case 'test:start':
|
|
616
|
+
renderer.testStart(event.testId, event.testName);
|
|
617
|
+
break;
|
|
618
|
+
case 'test:turn':
|
|
619
|
+
renderer.testTurn(event.testId, event.turn, event.action, event.durationMs, event.modelUsed);
|
|
620
|
+
break;
|
|
621
|
+
case 'test:complete':
|
|
622
|
+
renderer.testComplete(event.testId, event.passed, event.verdict, event.turnsUsed, event.durationMs, event.estimatedCostUsd);
|
|
623
|
+
break;
|
|
624
|
+
case 'suite:complete':
|
|
625
|
+
renderer.suiteComplete(event.passed, event.failed, event.skipped, event.totalMs, event.totalCostUsd, event.manifestUri);
|
|
626
|
+
break;
|
|
627
|
+
}
|
|
628
|
+
},
|
|
629
|
+
});
|
|
630
|
+
let result;
|
|
631
|
+
let runError;
|
|
632
|
+
try {
|
|
633
|
+
// Wire interrupt controller. Pressing `q` aborts via the suite-level signal.
|
|
634
|
+
const interruptSignal = interruptController
|
|
635
|
+
? (() => {
|
|
636
|
+
const ac = new AbortController();
|
|
637
|
+
interruptController.on('abort', () => ac.abort('interrupted by user'));
|
|
638
|
+
if (interruptController.isAborted)
|
|
639
|
+
ac.abort('interrupted by user');
|
|
640
|
+
return ac.signal;
|
|
641
|
+
})()
|
|
642
|
+
: undefined;
|
|
643
|
+
// If --live already provided a signal, merge both. Prefer the user
|
|
644
|
+
// interrupt signal so `q` wins even when --live is set.
|
|
645
|
+
const mergedSignal = interruptSignal ?? liveCancelController?.signal;
|
|
646
|
+
result = await runner.runSuite(cases, mergedSignal ? { signal: mergedSignal } : undefined);
|
|
647
|
+
// Write reports for each configured format
|
|
648
|
+
const { generateReport } = await import('../../test-report.js');
|
|
649
|
+
const reporters = driverConfig.reporters ?? ['json'];
|
|
650
|
+
const reportDir = path.resolve(sinkDir);
|
|
651
|
+
fs.mkdirSync(reportDir, { recursive: true });
|
|
652
|
+
const formatMeta = {
|
|
653
|
+
json: { ext: 'json', contentType: 'application/json' },
|
|
654
|
+
markdown: { ext: 'md', contentType: 'text/markdown' },
|
|
655
|
+
html: { ext: 'html', contentType: 'text/html' },
|
|
656
|
+
junit: { ext: 'xml', contentType: 'application/xml' },
|
|
657
|
+
};
|
|
658
|
+
for (const format of reporters) {
|
|
659
|
+
const meta = formatMeta[format];
|
|
660
|
+
if (!meta)
|
|
661
|
+
continue;
|
|
662
|
+
try {
|
|
663
|
+
const report = generateReport(result, { format, includeTurns: format === 'markdown' });
|
|
664
|
+
const reportPath = path.join(reportDir, `report.${meta.ext}`);
|
|
665
|
+
fs.writeFileSync(reportPath, report);
|
|
666
|
+
renderer?.report(reportPath);
|
|
667
|
+
}
|
|
668
|
+
catch {
|
|
669
|
+
// Report generation is best-effort
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
// Also write report to stdout if JSON mode
|
|
673
|
+
if (values.json && !quiet) {
|
|
674
|
+
console.log(JSON.stringify(result, null, 2));
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
catch (err) {
|
|
678
|
+
runError = err;
|
|
679
|
+
}
|
|
680
|
+
finally {
|
|
681
|
+
renderer?.destroy();
|
|
682
|
+
// Detach interrupt controller first so stdin leaves raw mode before
|
|
683
|
+
// shutdown logs are written.
|
|
684
|
+
if (detachInterrupt)
|
|
685
|
+
detachInterrupt();
|
|
686
|
+
// Flush and close the stream webhook so the final events (run-completed,
|
|
687
|
+
// suite-complete) reach the endpoint before the CLI exits.
|
|
688
|
+
if (webhookStreamer)
|
|
689
|
+
await webhookStreamer.close().catch(() => { });
|
|
690
|
+
await singleDriver?.close?.().catch(() => { });
|
|
691
|
+
stopWalletAutoApprover?.();
|
|
692
|
+
await persistentContext?.close().catch(() => { });
|
|
693
|
+
await browser?.close().catch(() => { });
|
|
694
|
+
}
|
|
695
|
+
if (runError) {
|
|
696
|
+
if (liveViewHandle) {
|
|
697
|
+
await liveViewHandle.close().catch(() => { });
|
|
698
|
+
}
|
|
699
|
+
throw runError;
|
|
700
|
+
}
|
|
701
|
+
const runLabel = values.cases
|
|
702
|
+
? `${path.basename(values.cases)} · cli run`
|
|
703
|
+
: `${(values.goal || values['resume-run'] || values['fork-run'] || 'run').slice(0, 80)} · cli run`;
|
|
704
|
+
await syncLocalBenchmarkRun(path.resolve(sinkDir), runLabel);
|
|
705
|
+
// In --live mode, the user usually wants to scrub the final state in the
|
|
706
|
+
// viewer after the run finishes. Hold the process open until SIGINT and
|
|
707
|
+
// shut down the live server cleanly when the user hits Ctrl+C.
|
|
708
|
+
if (liveViewHandle) {
|
|
709
|
+
cliLog('live', `run complete — viewer at ${liveViewHandle.url} (Ctrl+C to exit)`);
|
|
710
|
+
await new Promise((resolve) => {
|
|
711
|
+
const onSigint = () => {
|
|
712
|
+
liveViewHandle.close().finally(() => resolve());
|
|
713
|
+
};
|
|
714
|
+
process.once('SIGINT', onSigint);
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
process.exit((result?.summary.failed ?? 1) > 0 ? 1 : 0);
|
|
718
|
+
}
|
|
719
|
+
function parseAllowedDomains(value) {
|
|
720
|
+
if (!value)
|
|
721
|
+
return undefined;
|
|
722
|
+
const domains = value
|
|
723
|
+
.split(',')
|
|
724
|
+
.map((entry) => entry.trim().toLowerCase())
|
|
725
|
+
.filter(Boolean);
|
|
726
|
+
return domains.length > 0 ? [...new Set(domains)] : undefined;
|
|
727
|
+
}
|
|
728
|
+
//# sourceMappingURL=run.js.map
|