@yasserkhanorg/impact-gate 2.0.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/LICENSE +168 -0
- package/README.md +520 -0
- package/dist/adapters/cypress.d.ts +10 -0
- package/dist/adapters/cypress.d.ts.map +1 -0
- package/dist/adapters/cypress.js +86 -0
- package/dist/adapters/framework_adapter.d.ts +41 -0
- package/dist/adapters/framework_adapter.d.ts.map +1 -0
- package/dist/adapters/framework_adapter.js +152 -0
- package/dist/adapters/playwright.d.ts +10 -0
- package/dist/adapters/playwright.d.ts.map +1 -0
- package/dist/adapters/playwright.js +86 -0
- package/dist/adapters/pytest.d.ts +10 -0
- package/dist/adapters/pytest.d.ts.map +1 -0
- package/dist/adapters/pytest.js +96 -0
- package/dist/adapters/supertest.d.ts +12 -0
- package/dist/adapters/supertest.d.ts.map +1 -0
- package/dist/adapters/supertest.js +85 -0
- package/dist/agent/api_catalog.d.ts +11 -0
- package/dist/agent/api_catalog.d.ts.map +1 -0
- package/dist/agent/api_catalog.js +210 -0
- package/dist/agent/config.d.ts +193 -0
- package/dist/agent/config.d.ts.map +1 -0
- package/dist/agent/config.js +875 -0
- package/dist/agent/feedback.d.ts +91 -0
- package/dist/agent/feedback.d.ts.map +1 -0
- package/dist/agent/feedback.js +323 -0
- package/dist/agent/git.d.ts +19 -0
- package/dist/agent/git.d.ts.map +1 -0
- package/dist/agent/git.js +257 -0
- package/dist/agent/handoff.d.ts +22 -0
- package/dist/agent/handoff.d.ts.map +1 -0
- package/dist/agent/handoff.js +180 -0
- package/dist/agent/llm_agents_flow.d.ts +15 -0
- package/dist/agent/llm_agents_flow.d.ts.map +1 -0
- package/dist/agent/llm_agents_flow.js +434 -0
- package/dist/agent/native_flow.d.ts +6 -0
- package/dist/agent/native_flow.d.ts.map +1 -0
- package/dist/agent/native_flow.js +179 -0
- package/dist/agent/pipeline.d.ts +7 -0
- package/dist/agent/pipeline.d.ts.map +1 -0
- package/dist/agent/pipeline.js +260 -0
- package/dist/agent/pipeline_types.d.ts +54 -0
- package/dist/agent/pipeline_types.d.ts.map +1 -0
- package/dist/agent/pipeline_types.js +4 -0
- package/dist/agent/pipeline_utils.d.ts +12 -0
- package/dist/agent/pipeline_utils.d.ts.map +1 -0
- package/dist/agent/pipeline_utils.js +156 -0
- package/dist/agent/plan.d.ts +170 -0
- package/dist/agent/plan.d.ts.map +1 -0
- package/dist/agent/plan.js +86 -0
- package/dist/agent/playwright_report.d.ts +8 -0
- package/dist/agent/playwright_report.d.ts.map +1 -0
- package/dist/agent/playwright_report.js +126 -0
- package/dist/agent/process_runner.d.ts +10 -0
- package/dist/agent/process_runner.d.ts.map +1 -0
- package/dist/agent/process_runner.js +92 -0
- package/dist/agent/spec_generator.d.ts +5 -0
- package/dist/agent/spec_generator.d.ts.map +1 -0
- package/dist/agent/spec_generator.js +253 -0
- package/dist/agent/test_path.d.ts +2 -0
- package/dist/agent/test_path.d.ts.map +1 -0
- package/dist/agent/test_path.js +23 -0
- package/dist/agent/traceability_capture.d.ts +18 -0
- package/dist/agent/traceability_capture.d.ts.map +1 -0
- package/dist/agent/traceability_capture.js +313 -0
- package/dist/agent/traceability_ingest.d.ts +21 -0
- package/dist/agent/traceability_ingest.d.ts.map +1 -0
- package/dist/agent/traceability_ingest.js +237 -0
- package/dist/agent/types.d.ts +42 -0
- package/dist/agent/types.d.ts.map +1 -0
- package/dist/agent/types.js +4 -0
- package/dist/agent/utils.d.ts +13 -0
- package/dist/agent/utils.d.ts.map +1 -0
- package/dist/agent/utils.js +152 -0
- package/dist/agent/validation_runner.d.ts +5 -0
- package/dist/agent/validation_runner.d.ts.map +1 -0
- package/dist/agent/validation_runner.js +77 -0
- package/dist/agentic/fix_loop.d.ts +26 -0
- package/dist/agentic/fix_loop.d.ts.map +1 -0
- package/dist/agentic/fix_loop.js +96 -0
- package/dist/agentic/playwright_runner.d.ts +43 -0
- package/dist/agentic/playwright_runner.d.ts.map +1 -0
- package/dist/agentic/playwright_runner.js +165 -0
- package/dist/agentic/runner.d.ts +27 -0
- package/dist/agentic/runner.d.ts.map +1 -0
- package/dist/agentic/runner.js +210 -0
- package/dist/agentic/types.d.ts +62 -0
- package/dist/agentic/types.d.ts.map +1 -0
- package/dist/agentic/types.js +4 -0
- package/dist/agents/coverage-evaluator.d.ts +8 -0
- package/dist/agents/coverage-evaluator.d.ts.map +1 -0
- package/dist/agents/coverage-evaluator.js +41 -0
- package/dist/agents/cross-impact.d.ts +13 -0
- package/dist/agents/cross-impact.d.ts.map +1 -0
- package/dist/agents/cross-impact.js +140 -0
- package/dist/agents/executor.d.ts +8 -0
- package/dist/agents/executor.d.ts.map +1 -0
- package/dist/agents/executor.js +75 -0
- package/dist/agents/explorer.d.ts +12 -0
- package/dist/agents/explorer.d.ts.map +1 -0
- package/dist/agents/explorer.js +43 -0
- package/dist/agents/generator.d.ts +8 -0
- package/dist/agents/generator.d.ts.map +1 -0
- package/dist/agents/generator.js +77 -0
- package/dist/agents/healer.d.ts +8 -0
- package/dist/agents/healer.d.ts.map +1 -0
- package/dist/agents/healer.js +31 -0
- package/dist/agents/impact-analyst.d.ts +8 -0
- package/dist/agents/impact-analyst.d.ts.map +1 -0
- package/dist/agents/impact-analyst.js +38 -0
- package/dist/agents/regression-advisor.d.ts +8 -0
- package/dist/agents/regression-advisor.d.ts.map +1 -0
- package/dist/agents/regression-advisor.js +116 -0
- package/dist/agents/strategist.d.ts +9 -0
- package/dist/agents/strategist.d.ts.map +1 -0
- package/dist/agents/strategist.js +92 -0
- package/dist/agents/test-designer.d.ts +8 -0
- package/dist/agents/test-designer.d.ts.map +1 -0
- package/dist/agents/test-designer.js +111 -0
- package/dist/anthropic_provider.d.ts +65 -0
- package/dist/anthropic_provider.d.ts.map +1 -0
- package/dist/anthropic_provider.js +334 -0
- package/dist/api.d.ts +48 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +151 -0
- package/dist/base_provider.d.ts +109 -0
- package/dist/base_provider.d.ts.map +1 -0
- package/dist/base_provider.js +203 -0
- package/dist/budget_ledger.d.ts +28 -0
- package/dist/budget_ledger.d.ts.map +1 -0
- package/dist/budget_ledger.js +62 -0
- package/dist/cache/cached_provider.d.ts +49 -0
- package/dist/cache/cached_provider.d.ts.map +1 -0
- package/dist/cache/cached_provider.js +91 -0
- package/dist/cache/response_cache.d.ts +79 -0
- package/dist/cache/response_cache.d.ts.map +1 -0
- package/dist/cache/response_cache.js +177 -0
- package/dist/cli/commands/analyze.d.ts +3 -0
- package/dist/cli/commands/analyze.d.ts.map +1 -0
- package/dist/cli/commands/analyze.js +77 -0
- package/dist/cli/commands/bootstrap.d.ts +3 -0
- package/dist/cli/commands/bootstrap.d.ts.map +1 -0
- package/dist/cli/commands/bootstrap.js +109 -0
- package/dist/cli/commands/cost_report.d.ts +3 -0
- package/dist/cli/commands/cost_report.d.ts.map +1 -0
- package/dist/cli/commands/cost_report.js +115 -0
- package/dist/cli/commands/crew.d.ts +3 -0
- package/dist/cli/commands/crew.d.ts.map +1 -0
- package/dist/cli/commands/crew.js +255 -0
- package/dist/cli/commands/feedback.d.ts +3 -0
- package/dist/cli/commands/feedback.d.ts.map +1 -0
- package/dist/cli/commands/feedback.js +39 -0
- package/dist/cli/commands/finalize.d.ts +3 -0
- package/dist/cli/commands/finalize.d.ts.map +1 -0
- package/dist/cli/commands/finalize.js +41 -0
- package/dist/cli/commands/gate.d.ts +3 -0
- package/dist/cli/commands/gate.d.ts.map +1 -0
- package/dist/cli/commands/gate.js +89 -0
- package/dist/cli/commands/generate.d.ts +4 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/generate.js +108 -0
- package/dist/cli/commands/heal.d.ts +3 -0
- package/dist/cli/commands/heal.d.ts.map +1 -0
- package/dist/cli/commands/heal.js +60 -0
- package/dist/cli/commands/impact.d.ts +4 -0
- package/dist/cli/commands/impact.d.ts.map +1 -0
- package/dist/cli/commands/impact.js +33 -0
- package/dist/cli/commands/init.d.ts +2 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +169 -0
- package/dist/cli/commands/llm_health.d.ts +2 -0
- package/dist/cli/commands/llm_health.d.ts.map +1 -0
- package/dist/cli/commands/llm_health.js +22 -0
- package/dist/cli/commands/plan.d.ts +4 -0
- package/dist/cli/commands/plan.d.ts.map +1 -0
- package/dist/cli/commands/plan.js +120 -0
- package/dist/cli/commands/plan_crew.d.ts +17 -0
- package/dist/cli/commands/plan_crew.d.ts.map +1 -0
- package/dist/cli/commands/plan_crew.js +316 -0
- package/dist/cli/commands/traceability.d.ts +4 -0
- package/dist/cli/commands/traceability.d.ts.map +1 -0
- package/dist/cli/commands/traceability.js +77 -0
- package/dist/cli/commands/train.d.ts +3 -0
- package/dist/cli/commands/train.d.ts.map +1 -0
- package/dist/cli/commands/train.js +391 -0
- package/dist/cli/defaults.d.ts +35 -0
- package/dist/cli/defaults.d.ts.map +1 -0
- package/dist/cli/defaults.js +172 -0
- package/dist/cli/errors.d.ts +27 -0
- package/dist/cli/errors.d.ts.map +1 -0
- package/dist/cli/errors.js +57 -0
- package/dist/cli/parse_args.d.ts +6 -0
- package/dist/cli/parse_args.d.ts.map +1 -0
- package/dist/cli/parse_args.js +257 -0
- package/dist/cli/types.d.ts +87 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +4 -0
- package/dist/cli/usage.d.ts +2 -0
- package/dist/cli/usage.d.ts.map +1 -0
- package/dist/cli/usage.js +109 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +194 -0
- package/dist/crew/context.d.ts +55 -0
- package/dist/crew/context.d.ts.map +1 -0
- package/dist/crew/context.js +36 -0
- package/dist/crew/orchestrator.d.ts +50 -0
- package/dist/crew/orchestrator.d.ts.map +1 -0
- package/dist/crew/orchestrator.js +329 -0
- package/dist/crew/protocol.d.ts +46 -0
- package/dist/crew/protocol.d.ts.map +1 -0
- package/dist/crew/protocol.js +4 -0
- package/dist/crew/provider.d.ts +17 -0
- package/dist/crew/provider.d.ts.map +1 -0
- package/dist/crew/provider.js +36 -0
- package/dist/crew/sanitize.d.ts +3 -0
- package/dist/crew/sanitize.d.ts.map +1 -0
- package/dist/crew/sanitize.js +31 -0
- package/dist/crew/types.d.ts +52 -0
- package/dist/crew/types.d.ts.map +1 -0
- package/dist/crew/types.js +4 -0
- package/dist/crew/workflows.d.ts +52 -0
- package/dist/crew/workflows.d.ts.map +1 -0
- package/dist/crew/workflows.js +36 -0
- package/dist/custom_provider.d.ts +20 -0
- package/dist/custom_provider.d.ts.map +1 -0
- package/dist/custom_provider.js +277 -0
- package/dist/engine/ai_enrichment.d.ts +44 -0
- package/dist/engine/ai_enrichment.d.ts.map +1 -0
- package/dist/engine/ai_enrichment.js +267 -0
- package/dist/engine/diff_loader.d.ts +11 -0
- package/dist/engine/diff_loader.d.ts.map +1 -0
- package/dist/engine/diff_loader.js +63 -0
- package/dist/engine/impact_engine.d.ts +72 -0
- package/dist/engine/impact_engine.d.ts.map +1 -0
- package/dist/engine/impact_engine.js +298 -0
- package/dist/engine/plan_builder.d.ts +11 -0
- package/dist/engine/plan_builder.d.ts.map +1 -0
- package/dist/engine/plan_builder.js +599 -0
- package/dist/esm/adapters/cypress.js +49 -0
- package/dist/esm/adapters/framework_adapter.js +114 -0
- package/dist/esm/adapters/playwright.js +49 -0
- package/dist/esm/adapters/pytest.js +59 -0
- package/dist/esm/adapters/supertest.js +48 -0
- package/dist/esm/agent/api_catalog.js +199 -0
- package/dist/esm/agent/config.js +872 -0
- package/dist/esm/agent/feedback.js +317 -0
- package/dist/esm/agent/git.js +252 -0
- package/dist/esm/agent/handoff.js +177 -0
- package/dist/esm/agent/llm_agents_flow.js +421 -0
- package/dist/esm/agent/native_flow.js +175 -0
- package/dist/esm/agent/pipeline.js +256 -0
- package/dist/esm/agent/pipeline_types.js +3 -0
- package/dist/esm/agent/pipeline_utils.js +146 -0
- package/dist/esm/agent/plan.js +83 -0
- package/dist/esm/agent/playwright_report.js +123 -0
- package/dist/esm/agent/process_runner.js +83 -0
- package/dist/esm/agent/spec_generator.js +249 -0
- package/dist/esm/agent/test_path.js +20 -0
- package/dist/esm/agent/traceability_capture.js +310 -0
- package/dist/esm/agent/traceability_ingest.js +234 -0
- package/dist/esm/agent/types.js +3 -0
- package/dist/esm/agent/utils.js +138 -0
- package/dist/esm/agent/validation_runner.js +73 -0
- package/dist/esm/agentic/fix_loop.js +91 -0
- package/dist/esm/agentic/playwright_runner.js +161 -0
- package/dist/esm/agentic/runner.js +207 -0
- package/dist/esm/agentic/types.js +3 -0
- package/dist/esm/agents/coverage-evaluator.js +37 -0
- package/dist/esm/agents/cross-impact.js +136 -0
- package/dist/esm/agents/executor.js +71 -0
- package/dist/esm/agents/explorer.js +39 -0
- package/dist/esm/agents/generator.js +73 -0
- package/dist/esm/agents/healer.js +27 -0
- package/dist/esm/agents/impact-analyst.js +34 -0
- package/dist/esm/agents/regression-advisor.js +112 -0
- package/dist/esm/agents/strategist.js +88 -0
- package/dist/esm/agents/test-designer.js +107 -0
- package/dist/esm/anthropic_provider.js +326 -0
- package/dist/esm/api.js +143 -0
- package/dist/esm/base_provider.js +198 -0
- package/dist/esm/budget_ledger.js +58 -0
- package/dist/esm/cache/cached_provider.js +85 -0
- package/dist/esm/cache/response_cache.js +140 -0
- package/dist/esm/cli/commands/analyze.js +74 -0
- package/dist/esm/cli/commands/bootstrap.js +106 -0
- package/dist/esm/cli/commands/cost_report.js +112 -0
- package/dist/esm/cli/commands/crew.js +252 -0
- package/dist/esm/cli/commands/feedback.js +36 -0
- package/dist/esm/cli/commands/finalize.js +38 -0
- package/dist/esm/cli/commands/gate.js +86 -0
- package/dist/esm/cli/commands/generate.js +105 -0
- package/dist/esm/cli/commands/heal.js +57 -0
- package/dist/esm/cli/commands/impact.js +30 -0
- package/dist/esm/cli/commands/init.js +133 -0
- package/dist/esm/cli/commands/llm_health.js +19 -0
- package/dist/esm/cli/commands/plan.js +117 -0
- package/dist/esm/cli/commands/plan_crew.js +309 -0
- package/dist/esm/cli/commands/traceability.js +73 -0
- package/dist/esm/cli/commands/train.js +355 -0
- package/dist/esm/cli/defaults.js +165 -0
- package/dist/esm/cli/errors.js +52 -0
- package/dist/esm/cli/parse_args.js +251 -0
- package/dist/esm/cli/types.js +3 -0
- package/dist/esm/cli/usage.js +106 -0
- package/dist/esm/cli.js +192 -0
- package/dist/esm/crew/context.js +32 -0
- package/dist/esm/crew/orchestrator.js +325 -0
- package/dist/esm/crew/protocol.js +3 -0
- package/dist/esm/crew/provider.js +33 -0
- package/dist/esm/crew/sanitize.js +27 -0
- package/dist/esm/crew/types.js +3 -0
- package/dist/esm/crew/workflows.js +33 -0
- package/dist/esm/custom_provider.js +273 -0
- package/dist/esm/engine/ai_enrichment.js +264 -0
- package/dist/esm/engine/diff_loader.js +59 -0
- package/dist/esm/engine/impact_engine.js +291 -0
- package/dist/esm/engine/plan_builder.js +593 -0
- package/dist/esm/index.js +72 -0
- package/dist/esm/knowledge/api_surface.js +408 -0
- package/dist/esm/knowledge/cluster_utils.js +60 -0
- package/dist/esm/knowledge/context_loader.js +85 -0
- package/dist/esm/knowledge/failure_history.js +121 -0
- package/dist/esm/knowledge/kg_bridge.js +381 -0
- package/dist/esm/knowledge/kg_types.js +3 -0
- package/dist/esm/knowledge/route_families.js +393 -0
- package/dist/esm/knowledge/spec_index.js +122 -0
- package/dist/esm/logger.js +115 -0
- package/dist/esm/mcp-server.js +621 -0
- package/dist/esm/metrics/prometheus.js +149 -0
- package/dist/esm/model_router.js +59 -0
- package/dist/esm/ollama_provider.js +301 -0
- package/dist/esm/openai_provider.js +243 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/pipeline/orchestrator.js +228 -0
- package/dist/esm/pipeline/spec_verifier.js +75 -0
- package/dist/esm/pipeline/stage0_preprocess.js +102 -0
- package/dist/esm/pipeline/stage1_impact.js +140 -0
- package/dist/esm/pipeline/stage2_coverage.js +153 -0
- package/dist/esm/pipeline/stage3_generation.js +284 -0
- package/dist/esm/pipeline/stage4_heal.js +288 -0
- package/dist/esm/progress.js +112 -0
- package/dist/esm/prompts/coverage.js +57 -0
- package/dist/esm/prompts/cross-impact.js +53 -0
- package/dist/esm/prompts/generation.js +297 -0
- package/dist/esm/prompts/generation_profile.js +147 -0
- package/dist/esm/prompts/heal.js +91 -0
- package/dist/esm/prompts/impact.js +63 -0
- package/dist/esm/prompts/json_extract.js +36 -0
- package/dist/esm/prompts/strategist.js +61 -0
- package/dist/esm/prompts/test-designer.js +92 -0
- package/dist/esm/provider_factory.js +366 -0
- package/dist/esm/provider_interface.js +23 -0
- package/dist/esm/provider_utils.js +96 -0
- package/dist/esm/qa-agent/cli.js +205 -0
- package/dist/esm/qa-agent/orchestrator.js +120 -0
- package/dist/esm/qa-agent/phase1/runner.js +139 -0
- package/dist/esm/qa-agent/phase1/scope.js +126 -0
- package/dist/esm/qa-agent/phase2/agent_browser.js +95 -0
- package/dist/esm/qa-agent/phase2/agent_loop.js +351 -0
- package/dist/esm/qa-agent/phase2/exploration_state.js +97 -0
- package/dist/esm/qa-agent/phase2/tools.js +386 -0
- package/dist/esm/qa-agent/phase2/vision.js +75 -0
- package/dist/esm/qa-agent/phase3/feedback.js +34 -0
- package/dist/esm/qa-agent/phase3/reporter.js +145 -0
- package/dist/esm/qa-agent/phase3/spec_generator.js +62 -0
- package/dist/esm/qa-agent/phase3/verdict.js +66 -0
- package/dist/esm/qa-agent/safe_env.js +23 -0
- package/dist/esm/qa-agent/types.js +3 -0
- package/dist/esm/reporters/junit.js +86 -0
- package/dist/esm/reporters/reporter.js +3 -0
- package/dist/esm/reporters/sarif.js +132 -0
- package/dist/esm/resilience/circuit_breaker.js +78 -0
- package/dist/esm/resilience/retry.js +56 -0
- package/dist/esm/sanitize.js +66 -0
- package/dist/esm/training/enricher.js +345 -0
- package/dist/esm/training/kg_scanner.js +115 -0
- package/dist/esm/training/merger.js +204 -0
- package/dist/esm/training/scanner.js +923 -0
- package/dist/esm/training/types.js +6 -0
- package/dist/esm/training/validator.js +254 -0
- package/dist/esm/validation/guardrails.js +101 -0
- package/dist/esm/validation/output_schema.js +80 -0
- package/dist/esm/version.js +33 -0
- package/dist/index.d.ts +99 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +169 -0
- package/dist/knowledge/api_surface.d.ts +37 -0
- package/dist/knowledge/api_surface.d.ts.map +1 -0
- package/dist/knowledge/api_surface.js +418 -0
- package/dist/knowledge/cluster_utils.d.ts +28 -0
- package/dist/knowledge/cluster_utils.d.ts.map +1 -0
- package/dist/knowledge/cluster_utils.js +67 -0
- package/dist/knowledge/context_loader.d.ts +13 -0
- package/dist/knowledge/context_loader.d.ts.map +1 -0
- package/dist/knowledge/context_loader.js +90 -0
- package/dist/knowledge/failure_history.d.ts +39 -0
- package/dist/knowledge/failure_history.d.ts.map +1 -0
- package/dist/knowledge/failure_history.js +128 -0
- package/dist/knowledge/kg_bridge.d.ts +31 -0
- package/dist/knowledge/kg_bridge.d.ts.map +1 -0
- package/dist/knowledge/kg_bridge.js +388 -0
- package/dist/knowledge/kg_types.d.ts +75 -0
- package/dist/knowledge/kg_types.d.ts.map +1 -0
- package/dist/knowledge/kg_types.js +4 -0
- package/dist/knowledge/route_families.d.ts +98 -0
- package/dist/knowledge/route_families.d.ts.map +1 -0
- package/dist/knowledge/route_families.js +410 -0
- package/dist/knowledge/spec_index.d.ts +18 -0
- package/dist/knowledge/spec_index.d.ts.map +1 -0
- package/dist/knowledge/spec_index.js +128 -0
- package/dist/logger.d.ts +31 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +119 -0
- package/dist/mcp-server.d.ts +68 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +629 -0
- package/dist/metrics/prometheus.d.ts +37 -0
- package/dist/metrics/prometheus.d.ts.map +1 -0
- package/dist/metrics/prometheus.js +153 -0
- package/dist/model_router.d.ts +28 -0
- package/dist/model_router.d.ts.map +1 -0
- package/dist/model_router.js +63 -0
- package/dist/ollama_provider.d.ts +65 -0
- package/dist/ollama_provider.d.ts.map +1 -0
- package/dist/ollama_provider.js +309 -0
- package/dist/openai_provider.d.ts +23 -0
- package/dist/openai_provider.d.ts.map +1 -0
- package/dist/openai_provider.js +251 -0
- package/dist/pipeline/orchestrator.d.ts +33 -0
- package/dist/pipeline/orchestrator.d.ts.map +1 -0
- package/dist/pipeline/orchestrator.js +231 -0
- package/dist/pipeline/spec_verifier.d.ts +20 -0
- package/dist/pipeline/spec_verifier.d.ts.map +1 -0
- package/dist/pipeline/spec_verifier.js +79 -0
- package/dist/pipeline/stage0_preprocess.d.ts +31 -0
- package/dist/pipeline/stage0_preprocess.d.ts.map +1 -0
- package/dist/pipeline/stage0_preprocess.js +105 -0
- package/dist/pipeline/stage1_impact.d.ts +19 -0
- package/dist/pipeline/stage1_impact.d.ts.map +1 -0
- package/dist/pipeline/stage1_impact.js +143 -0
- package/dist/pipeline/stage2_coverage.d.ts +19 -0
- package/dist/pipeline/stage2_coverage.d.ts.map +1 -0
- package/dist/pipeline/stage2_coverage.js +156 -0
- package/dist/pipeline/stage3_generation.d.ts +43 -0
- package/dist/pipeline/stage3_generation.d.ts.map +1 -0
- package/dist/pipeline/stage3_generation.js +287 -0
- package/dist/pipeline/stage4_heal.d.ts +62 -0
- package/dist/pipeline/stage4_heal.d.ts.map +1 -0
- package/dist/pipeline/stage4_heal.js +294 -0
- package/dist/progress.d.ts +22 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +116 -0
- package/dist/prompts/coverage.d.ts +39 -0
- package/dist/prompts/coverage.d.ts.map +1 -0
- package/dist/prompts/coverage.js +61 -0
- package/dist/prompts/cross-impact.d.ts +23 -0
- package/dist/prompts/cross-impact.d.ts.map +1 -0
- package/dist/prompts/cross-impact.js +57 -0
- package/dist/prompts/generation.d.ts +25 -0
- package/dist/prompts/generation.d.ts.map +1 -0
- package/dist/prompts/generation.js +302 -0
- package/dist/prompts/generation_profile.d.ts +29 -0
- package/dist/prompts/generation_profile.d.ts.map +1 -0
- package/dist/prompts/generation_profile.js +151 -0
- package/dist/prompts/heal.d.ts +23 -0
- package/dist/prompts/heal.d.ts.map +1 -0
- package/dist/prompts/heal.js +95 -0
- package/dist/prompts/impact.d.ts +31 -0
- package/dist/prompts/impact.d.ts.map +1 -0
- package/dist/prompts/impact.js +67 -0
- package/dist/prompts/json_extract.d.ts +14 -0
- package/dist/prompts/json_extract.d.ts.map +1 -0
- package/dist/prompts/json_extract.js +39 -0
- package/dist/prompts/strategist.d.ts +25 -0
- package/dist/prompts/strategist.d.ts.map +1 -0
- package/dist/prompts/strategist.js +65 -0
- package/dist/prompts/test-designer.d.ts +35 -0
- package/dist/prompts/test-designer.d.ts.map +1 -0
- package/dist/prompts/test-designer.js +96 -0
- package/dist/provider_factory.d.ts +104 -0
- package/dist/provider_factory.d.ts.map +1 -0
- package/dist/provider_factory.js +371 -0
- package/dist/provider_interface.d.ts +365 -0
- package/dist/provider_interface.d.ts.map +1 -0
- package/dist/provider_interface.js +28 -0
- package/dist/provider_utils.d.ts +39 -0
- package/dist/provider_utils.d.ts.map +1 -0
- package/dist/provider_utils.js +103 -0
- package/dist/qa-agent/cli.d.ts +3 -0
- package/dist/qa-agent/cli.d.ts.map +1 -0
- package/dist/qa-agent/cli.js +207 -0
- package/dist/qa-agent/orchestrator.d.ts +3 -0
- package/dist/qa-agent/orchestrator.d.ts.map +1 -0
- package/dist/qa-agent/orchestrator.js +123 -0
- package/dist/qa-agent/phase1/runner.d.ts +3 -0
- package/dist/qa-agent/phase1/runner.d.ts.map +1 -0
- package/dist/qa-agent/phase1/runner.js +142 -0
- package/dist/qa-agent/phase1/scope.d.ts +6 -0
- package/dist/qa-agent/phase1/scope.d.ts.map +1 -0
- package/dist/qa-agent/phase1/scope.js +129 -0
- package/dist/qa-agent/phase2/agent_browser.d.ts +35 -0
- package/dist/qa-agent/phase2/agent_browser.d.ts.map +1 -0
- package/dist/qa-agent/phase2/agent_browser.js +99 -0
- package/dist/qa-agent/phase2/agent_loop.d.ts +3 -0
- package/dist/qa-agent/phase2/agent_loop.d.ts.map +1 -0
- package/dist/qa-agent/phase2/agent_loop.js +357 -0
- package/dist/qa-agent/phase2/exploration_state.d.ts +12 -0
- package/dist/qa-agent/phase2/exploration_state.d.ts.map +1 -0
- package/dist/qa-agent/phase2/exploration_state.js +109 -0
- package/dist/qa-agent/phase2/tools.d.ts +28 -0
- package/dist/qa-agent/phase2/tools.d.ts.map +1 -0
- package/dist/qa-agent/phase2/tools.js +390 -0
- package/dist/qa-agent/phase2/vision.d.ts +3 -0
- package/dist/qa-agent/phase2/vision.d.ts.map +1 -0
- package/dist/qa-agent/phase2/vision.js +78 -0
- package/dist/qa-agent/phase3/feedback.d.ts +3 -0
- package/dist/qa-agent/phase3/feedback.d.ts.map +1 -0
- package/dist/qa-agent/phase3/feedback.js +37 -0
- package/dist/qa-agent/phase3/reporter.d.ts +3 -0
- package/dist/qa-agent/phase3/reporter.d.ts.map +1 -0
- package/dist/qa-agent/phase3/reporter.js +148 -0
- package/dist/qa-agent/phase3/spec_generator.d.ts +3 -0
- package/dist/qa-agent/phase3/spec_generator.d.ts.map +1 -0
- package/dist/qa-agent/phase3/spec_generator.js +65 -0
- package/dist/qa-agent/phase3/verdict.d.ts +3 -0
- package/dist/qa-agent/phase3/verdict.d.ts.map +1 -0
- package/dist/qa-agent/phase3/verdict.js +69 -0
- package/dist/qa-agent/safe_env.d.ts +3 -0
- package/dist/qa-agent/safe_env.d.ts.map +1 -0
- package/dist/qa-agent/safe_env.js +26 -0
- package/dist/qa-agent/types.d.ts +130 -0
- package/dist/qa-agent/types.d.ts.map +1 -0
- package/dist/qa-agent/types.js +4 -0
- package/dist/reporters/junit.d.ts +6 -0
- package/dist/reporters/junit.d.ts.map +1 -0
- package/dist/reporters/junit.js +89 -0
- package/dist/reporters/reporter.d.ts +42 -0
- package/dist/reporters/reporter.d.ts.map +1 -0
- package/dist/reporters/reporter.js +4 -0
- package/dist/reporters/sarif.d.ts +7 -0
- package/dist/reporters/sarif.d.ts.map +1 -0
- package/dist/reporters/sarif.js +135 -0
- package/dist/resilience/circuit_breaker.d.ts +36 -0
- package/dist/resilience/circuit_breaker.d.ts.map +1 -0
- package/dist/resilience/circuit_breaker.js +82 -0
- package/dist/resilience/retry.d.ts +11 -0
- package/dist/resilience/retry.d.ts.map +1 -0
- package/dist/resilience/retry.js +59 -0
- package/dist/sanitize.d.ts +15 -0
- package/dist/sanitize.d.ts.map +1 -0
- package/dist/sanitize.js +71 -0
- package/dist/training/enricher.d.ts +17 -0
- package/dist/training/enricher.d.ts.map +1 -0
- package/dist/training/enricher.js +350 -0
- package/dist/training/kg_scanner.d.ts +13 -0
- package/dist/training/kg_scanner.d.ts.map +1 -0
- package/dist/training/kg_scanner.js +118 -0
- package/dist/training/merger.d.ts +15 -0
- package/dist/training/merger.d.ts.map +1 -0
- package/dist/training/merger.js +208 -0
- package/dist/training/scanner.d.ts +36 -0
- package/dist/training/scanner.d.ts.map +1 -0
- package/dist/training/scanner.js +932 -0
- package/dist/training/types.d.ts +117 -0
- package/dist/training/types.d.ts.map +1 -0
- package/dist/training/types.js +9 -0
- package/dist/training/validator.d.ts +21 -0
- package/dist/training/validator.d.ts.map +1 -0
- package/dist/training/validator.js +262 -0
- package/dist/validation/guardrails.d.ts +31 -0
- package/dist/validation/guardrails.d.ts.map +1 -0
- package/dist/validation/guardrails.js +112 -0
- package/dist/validation/output_schema.d.ts +67 -0
- package/dist/validation/output_schema.d.ts.map +1 -0
- package/dist/validation/output_schema.js +84 -0
- package/dist/version.d.ts +6 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +36 -0
- package/package.json +126 -0
- package/schemas/flow-decision.schema.json +83 -0
- package/schemas/gap.schema.json +18 -0
- package/schemas/impact.schema.json +455 -0
- package/schemas/plan.schema.json +491 -0
- package/schemas/route-families.schema.json +137 -0
- package/schemas/subsystem-risk-map.schema.json +62 -0
- package/schemas/traceability-input.schema.json +122 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
import { relative } from 'path';
|
|
4
|
+
import { normalizePath } from './utils.js';
|
|
5
|
+
import { runCommand, summarizeCommandOutput } from './process_runner.js';
|
|
6
|
+
export function runPlaywrightRuntimeValidation(testsRoot, testFile, pipeline, playwrightBinary) {
|
|
7
|
+
if (!playwrightBinary) {
|
|
8
|
+
return {
|
|
9
|
+
status: 'failed',
|
|
10
|
+
detail: 'Playwright binary not found; cannot execute runtime validation.',
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
const relativeSpecPath = normalizePath(relative(testsRoot, testFile));
|
|
14
|
+
if (relativeSpecPath.startsWith('../') || relativeSpecPath.startsWith('..\\')) {
|
|
15
|
+
return {
|
|
16
|
+
status: 'failed',
|
|
17
|
+
detail: 'Generated spec path resolved outside testsRoot during runtime validation.',
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const args = ['test', relativeSpecPath, '--workers', '1', '--retries', '0', '--max-failures', '1', '--reporter', 'line'];
|
|
21
|
+
if (pipeline.headless === false) {
|
|
22
|
+
args.push('--headed');
|
|
23
|
+
}
|
|
24
|
+
if (pipeline.project) {
|
|
25
|
+
args.push('--project', pipeline.project);
|
|
26
|
+
}
|
|
27
|
+
const commandResult = runCommand(playwrightBinary, args, testsRoot, 10 * 60 * 1000);
|
|
28
|
+
if (commandResult.status === 0) {
|
|
29
|
+
return { status: 'passed' };
|
|
30
|
+
}
|
|
31
|
+
const summary = summarizeCommandOutput(commandResult.stdout, commandResult.stderr);
|
|
32
|
+
return {
|
|
33
|
+
status: 'failed',
|
|
34
|
+
detail: summary || commandResult.error || `playwright test failed with status ${commandResult.status}`,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export function runPlaywrightListValidation(testsRoot, testFile, pipeline, playwrightBinary) {
|
|
38
|
+
if (!playwrightBinary) {
|
|
39
|
+
return {
|
|
40
|
+
status: 'skipped',
|
|
41
|
+
detail: 'Playwright binary not found under testsRoot/node_modules/.bin; runtime compile validation skipped.',
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const relativeSpecPath = normalizePath(relative(testsRoot, testFile));
|
|
45
|
+
if (relativeSpecPath.startsWith('../') || relativeSpecPath.startsWith('..\\')) {
|
|
46
|
+
return {
|
|
47
|
+
status: 'failed',
|
|
48
|
+
detail: 'Generated spec path resolved outside testsRoot during validation.',
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const args = ['test', '--list', relativeSpecPath];
|
|
52
|
+
if (pipeline.headless === false) {
|
|
53
|
+
args.push('--headed');
|
|
54
|
+
}
|
|
55
|
+
if (pipeline.project) {
|
|
56
|
+
args.push('--project', pipeline.project);
|
|
57
|
+
}
|
|
58
|
+
const commandResult = runCommand(playwrightBinary, args, testsRoot);
|
|
59
|
+
if (commandResult.error && /ENOENT/.test(commandResult.error)) {
|
|
60
|
+
return {
|
|
61
|
+
status: 'skipped',
|
|
62
|
+
detail: 'Playwright binary was not executable; runtime compile validation skipped.',
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (commandResult.status === 0) {
|
|
66
|
+
return { status: 'passed' };
|
|
67
|
+
}
|
|
68
|
+
const summary = summarizeCommandOutput(commandResult.stdout, commandResult.stderr);
|
|
69
|
+
return {
|
|
70
|
+
status: 'failed',
|
|
71
|
+
detail: summary || commandResult.error || `playwright --list failed with status ${commandResult.status}`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
import { sanitizeForPrompt } from '../crew/sanitize.js';
|
|
4
|
+
export function buildFixPrompt(ctx) {
|
|
5
|
+
const isCompileError = ctx.failures.some((f) => f.testTitle === '(compile)');
|
|
6
|
+
const failuresBlock = ctx.failures.map((f) => {
|
|
7
|
+
const lines = [` Test: ${sanitizeForPrompt(f.testTitle)}`, ` Error: ${sanitizeForPrompt(f.error)}`];
|
|
8
|
+
if (f.stack)
|
|
9
|
+
lines.push(` Stack: ${sanitizeForPrompt(f.stack)}`);
|
|
10
|
+
if (f.line)
|
|
11
|
+
lines.push(` Line: ${f.line}`);
|
|
12
|
+
if (f.expected)
|
|
13
|
+
lines.push(` Expected: ${sanitizeForPrompt(f.expected)}`);
|
|
14
|
+
if (f.actual)
|
|
15
|
+
lines.push(` Actual: ${sanitizeForPrompt(f.actual)}`);
|
|
16
|
+
return lines.join('\n');
|
|
17
|
+
}).join('\n\n');
|
|
18
|
+
const errorType = isCompileError ? 'COMPILE ERROR' : 'TEST FAILURE';
|
|
19
|
+
const apiBlock = ctx.apiSurfaceHint
|
|
20
|
+
? `\nAVAILABLE PAGE OBJECT API:\n${ctx.apiSurfaceHint}\n`
|
|
21
|
+
: '';
|
|
22
|
+
return [
|
|
23
|
+
`Fix this Playwright E2E test. This is attempt ${ctx.attempt} of ${ctx.maxAttempts}.`,
|
|
24
|
+
'',
|
|
25
|
+
`## ${errorType}`,
|
|
26
|
+
'',
|
|
27
|
+
failuresBlock,
|
|
28
|
+
'',
|
|
29
|
+
'## CURRENT SPEC CODE',
|
|
30
|
+
'',
|
|
31
|
+
'```typescript',
|
|
32
|
+
ctx.specCode,
|
|
33
|
+
'```',
|
|
34
|
+
apiBlock,
|
|
35
|
+
'## RULES',
|
|
36
|
+
'',
|
|
37
|
+
'1. Import ONLY from "@mattermost/playwright-lib" — no "@playwright/test" imports.',
|
|
38
|
+
'2. Every test must call `await pw.initSetup()` first.',
|
|
39
|
+
'3. Use `await pw.testBrowser.login(user)` to log in.',
|
|
40
|
+
'4. Use ONLY page object methods listed in the API above. Do NOT invent methods.',
|
|
41
|
+
'5. If a method is not available, use `page.getByRole()` or `page.getByTestId()`.',
|
|
42
|
+
'6. For flaky/timing issues: add `await expect(locator).toBeVisible()` waits before interactions.',
|
|
43
|
+
'7. Keep the same test scenarios — fix the implementation, not the intent.',
|
|
44
|
+
'8. Return the COMPLETE fixed spec file — not a diff or partial code.',
|
|
45
|
+
'',
|
|
46
|
+
isCompileError
|
|
47
|
+
? 'The file does not compile. Fix syntax errors, missing imports, or invalid method calls.'
|
|
48
|
+
: 'The test compiles but fails at runtime. Fix selectors, waits, or assertion logic.',
|
|
49
|
+
'',
|
|
50
|
+
'Return ONLY the complete TypeScript code. No explanations, no markdown fences (except wrapping the code).',
|
|
51
|
+
].join('\n');
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Extract fixed spec code from an LLM response.
|
|
55
|
+
* Returns null if the response doesn't contain valid test code.
|
|
56
|
+
*/
|
|
57
|
+
export function applyFix(llmResponse) {
|
|
58
|
+
let code = llmResponse.trim();
|
|
59
|
+
if (!code)
|
|
60
|
+
return null;
|
|
61
|
+
// Strip markdown fences
|
|
62
|
+
const fenced = code.match(/```(?:typescript|ts)?\s*([\s\S]*?)```/i);
|
|
63
|
+
if (fenced) {
|
|
64
|
+
code = fenced[1].trim();
|
|
65
|
+
}
|
|
66
|
+
// Must contain test( to be valid
|
|
67
|
+
if (!code.includes('test('))
|
|
68
|
+
return null;
|
|
69
|
+
// Ensure it has the right import
|
|
70
|
+
if (!code.includes('@mattermost/playwright-lib')) {
|
|
71
|
+
code = `import {expect, test} from '@mattermost/playwright-lib';\n\n${code}`;
|
|
72
|
+
}
|
|
73
|
+
return code;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Run one fix attempt: call LLM with failure context, return fixed code.
|
|
77
|
+
*/
|
|
78
|
+
export async function generateFix(provider, ctx) {
|
|
79
|
+
const prompt = buildFixPrompt(ctx);
|
|
80
|
+
const response = await provider.generateText(prompt, {
|
|
81
|
+
maxTokens: 8000,
|
|
82
|
+
temperature: 0.1,
|
|
83
|
+
timeout: 60000,
|
|
84
|
+
systemPrompt: 'You are an expert Playwright test fixer for Mattermost. Return only TypeScript code.',
|
|
85
|
+
});
|
|
86
|
+
const code = applyFix(response.text);
|
|
87
|
+
return {
|
|
88
|
+
code,
|
|
89
|
+
tokensUsed: { input: response.usage?.inputTokens || 0, output: response.usage?.outputTokens || 0 },
|
|
90
|
+
};
|
|
91
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
import { spawnSync } from 'child_process';
|
|
4
|
+
import { existsSync, readFileSync, mkdirSync, rmSync } from 'fs';
|
|
5
|
+
import { join, resolve } from 'path';
|
|
6
|
+
const MAX_STDOUT_CHARS = 8000;
|
|
7
|
+
const MAX_ERROR_CHARS = 2000;
|
|
8
|
+
const MAX_STACK_CHARS = 1000;
|
|
9
|
+
function extractSpecs(suites) {
|
|
10
|
+
const specs = [];
|
|
11
|
+
for (const suite of suites) {
|
|
12
|
+
specs.push(...suite.specs);
|
|
13
|
+
if (suite.suites) {
|
|
14
|
+
specs.push(...extractSpecs(suite.suites));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return specs;
|
|
18
|
+
}
|
|
19
|
+
export function parsePlaywrightJsonReport(report, specPath) {
|
|
20
|
+
const failures = [];
|
|
21
|
+
const allSpecs = extractSpecs(report.suites);
|
|
22
|
+
let passed = 0;
|
|
23
|
+
let failed = 0;
|
|
24
|
+
for (const spec of allSpecs) {
|
|
25
|
+
if (spec.ok) {
|
|
26
|
+
passed++;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
failed++;
|
|
30
|
+
const lastResult = spec.tests[0]?.results?.at(-1);
|
|
31
|
+
failures.push({
|
|
32
|
+
testTitle: spec.title,
|
|
33
|
+
specPath,
|
|
34
|
+
error: (lastResult?.error?.message || 'Unknown error').slice(0, MAX_ERROR_CHARS),
|
|
35
|
+
stack: (lastResult?.error?.stack || '').slice(0, MAX_STACK_CHARS),
|
|
36
|
+
line: extractLineNumber(lastResult?.error?.stack),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
specPath,
|
|
42
|
+
passed,
|
|
43
|
+
failed,
|
|
44
|
+
flaky: report.stats.flaky || 0,
|
|
45
|
+
skipped: report.stats.skipped || 0,
|
|
46
|
+
failures,
|
|
47
|
+
stdout: '',
|
|
48
|
+
durationMs: report.stats.duration || 0,
|
|
49
|
+
compiled: true,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function extractLineNumber(stack) {
|
|
53
|
+
if (!stack)
|
|
54
|
+
return undefined;
|
|
55
|
+
const match = stack.match(/:(\d+):\d+\)?$/m);
|
|
56
|
+
return match ? parseInt(match[1], 10) : undefined;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Run a single Playwright spec file and return structured results.
|
|
60
|
+
* Uses a temp JSON reporter to get machine-readable output.
|
|
61
|
+
*/
|
|
62
|
+
export function runPlaywrightSpec(specPath, testsRoot, options) {
|
|
63
|
+
// SECURITY: Validate spec path is within testsRoot and has valid extension
|
|
64
|
+
const resolvedSpec = resolve(specPath);
|
|
65
|
+
const resolvedRoot = resolve(testsRoot);
|
|
66
|
+
if (!resolvedSpec.startsWith(resolvedRoot + '/')) {
|
|
67
|
+
throw new Error(`Security: spec path ${specPath} is outside testsRoot`);
|
|
68
|
+
}
|
|
69
|
+
if (!resolvedSpec.endsWith('.spec.ts') && !resolvedSpec.endsWith('.test.ts')) {
|
|
70
|
+
throw new Error(`Security: spec path must end in .spec.ts or .test.ts`);
|
|
71
|
+
}
|
|
72
|
+
const reportDir = join(testsRoot, '.e2e-ai-agents', 'agentic-reports');
|
|
73
|
+
if (!existsSync(reportDir)) {
|
|
74
|
+
mkdirSync(reportDir, { recursive: true });
|
|
75
|
+
}
|
|
76
|
+
const reportPath = join(reportDir, `report-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.json`);
|
|
77
|
+
const args = [
|
|
78
|
+
'playwright', 'test',
|
|
79
|
+
specPath,
|
|
80
|
+
'--reporter', 'json',
|
|
81
|
+
'--project', options.project || 'chrome',
|
|
82
|
+
];
|
|
83
|
+
if (options.baseUrl) {
|
|
84
|
+
args.push('--config', 'playwright.config.ts');
|
|
85
|
+
}
|
|
86
|
+
const startTime = Date.now();
|
|
87
|
+
const result = spawnSync('npx', args, {
|
|
88
|
+
cwd: testsRoot,
|
|
89
|
+
encoding: 'utf-8',
|
|
90
|
+
timeout: options.timeoutMs || 120000,
|
|
91
|
+
maxBuffer: 2 * 1024 * 1024,
|
|
92
|
+
env: {
|
|
93
|
+
...process.env,
|
|
94
|
+
PLAYWRIGHT_JSON_OUTPUT_NAME: reportPath,
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
const durationMs = Date.now() - startTime;
|
|
98
|
+
const stdout = (result.stdout || '').slice(0, MAX_STDOUT_CHARS);
|
|
99
|
+
const stderr = (result.stderr || '').slice(0, MAX_STDOUT_CHARS);
|
|
100
|
+
// Check for compile errors
|
|
101
|
+
if (stderr.includes('SyntaxError') || stderr.includes('Cannot find module') || stderr.includes('TypeError')) {
|
|
102
|
+
return {
|
|
103
|
+
specPath,
|
|
104
|
+
passed: 0,
|
|
105
|
+
failed: 1,
|
|
106
|
+
flaky: 0,
|
|
107
|
+
skipped: 0,
|
|
108
|
+
failures: [{
|
|
109
|
+
testTitle: '(compile)',
|
|
110
|
+
specPath,
|
|
111
|
+
error: stderr.slice(0, MAX_ERROR_CHARS),
|
|
112
|
+
stack: '',
|
|
113
|
+
}],
|
|
114
|
+
stdout: `${stdout}\n${stderr}`,
|
|
115
|
+
durationMs,
|
|
116
|
+
compiled: false,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
// Try to parse JSON report from stdout (Playwright JSON reporter writes to stdout)
|
|
120
|
+
try {
|
|
121
|
+
const jsonReport = JSON.parse(stdout);
|
|
122
|
+
const parsed = parsePlaywrightJsonReport(jsonReport, specPath);
|
|
123
|
+
parsed.durationMs = durationMs;
|
|
124
|
+
parsed.stdout = stdout;
|
|
125
|
+
return parsed;
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// Fallback: try the file-based report
|
|
129
|
+
}
|
|
130
|
+
// Try file-based report
|
|
131
|
+
if (existsSync(reportPath)) {
|
|
132
|
+
try {
|
|
133
|
+
const jsonReport = JSON.parse(readFileSync(reportPath, 'utf-8'));
|
|
134
|
+
const parsed = parsePlaywrightJsonReport(jsonReport, specPath);
|
|
135
|
+
parsed.durationMs = durationMs;
|
|
136
|
+
parsed.stdout = stdout;
|
|
137
|
+
try {
|
|
138
|
+
rmSync(reportPath);
|
|
139
|
+
}
|
|
140
|
+
catch { /* ignore */ }
|
|
141
|
+
return parsed;
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
// Fallback to exit code
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// Last resort: use exit code
|
|
148
|
+
return {
|
|
149
|
+
specPath,
|
|
150
|
+
passed: result.status === 0 ? 1 : 0,
|
|
151
|
+
failed: result.status === 0 ? 0 : 1,
|
|
152
|
+
flaky: 0,
|
|
153
|
+
skipped: 0,
|
|
154
|
+
failures: result.status !== 0
|
|
155
|
+
? [{ testTitle: '(unknown)', specPath, error: stderr.slice(0, MAX_ERROR_CHARS), stack: '' }]
|
|
156
|
+
: [],
|
|
157
|
+
stdout,
|
|
158
|
+
durationMs,
|
|
159
|
+
compiled: !stderr.includes('Error'),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
4
|
+
import { dirname, join, resolve } from 'path';
|
|
5
|
+
import { runPlaywrightSpec } from './playwright_runner.js';
|
|
6
|
+
import { generateFix } from './fix_loop.js';
|
|
7
|
+
import { parseGenerationResponse } from '../prompts/generation.js';
|
|
8
|
+
import { formatApiSurfaceForPrompt } from '../knowledge/api_surface.js';
|
|
9
|
+
import { sanitizeForPrompt } from '../crew/sanitize.js';
|
|
10
|
+
function buildGeneratePrompt(scenario, apiSurfaceHint, profile) {
|
|
11
|
+
const projectName = profile?.projectName || 'Mattermost';
|
|
12
|
+
const importSource = profile?.importStatement || '@mattermost/playwright-lib';
|
|
13
|
+
const scenariosBlock = scenario.scenarios
|
|
14
|
+
.map((s, i) => ` ${i + 1}. ${sanitizeForPrompt(s)}`)
|
|
15
|
+
.join('\n');
|
|
16
|
+
return [
|
|
17
|
+
`Generate a ${projectName} Playwright E2E test file.`,
|
|
18
|
+
'',
|
|
19
|
+
`FLOW: ${sanitizeForPrompt(scenario.name)}`,
|
|
20
|
+
`Route Family: ${scenario.routeFamily}`,
|
|
21
|
+
`Priority: ${scenario.priority}`,
|
|
22
|
+
scenario.evidence ? `Evidence: ${sanitizeForPrompt(scenario.evidence)}` : '',
|
|
23
|
+
'',
|
|
24
|
+
'SCENARIOS TO IMPLEMENT:',
|
|
25
|
+
scenariosBlock,
|
|
26
|
+
'',
|
|
27
|
+
'AVAILABLE PAGE OBJECTS AND METHODS:',
|
|
28
|
+
apiSurfaceHint || 'Use page.getByRole() or page.getByTestId() for selectors.',
|
|
29
|
+
'',
|
|
30
|
+
'MANDATORY RULES:',
|
|
31
|
+
`1. Import ONLY from "${importSource}" — no other test framework imports.`,
|
|
32
|
+
'2. Every test must call `await pw.initSetup()` first.',
|
|
33
|
+
'3. Use `await pw.testBrowser.login(user)` to log in — never hardcode credentials.',
|
|
34
|
+
'4. Use ONLY page object methods listed above. Do NOT invent methods.',
|
|
35
|
+
'5. If a method is not available, use `page.getByRole()` or `page.getByTestId()`.',
|
|
36
|
+
`6. Tag every test: {tag: '@${scenario.routeFamily}'}`,
|
|
37
|
+
'7. Write one test per scenario with a descriptive name.',
|
|
38
|
+
`8. Use \`expect\` from "${importSource}".`,
|
|
39
|
+
'9. Include the copyright header.',
|
|
40
|
+
'10. NEVER fabricate test IDs (MM-TXXXX). Use descriptive names only.',
|
|
41
|
+
'',
|
|
42
|
+
'EXAMPLE STRUCTURE:',
|
|
43
|
+
'```typescript',
|
|
44
|
+
'// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.',
|
|
45
|
+
'// See LICENSE.txt for license information.',
|
|
46
|
+
'',
|
|
47
|
+
`import {expect, test} from '${importSource}';`,
|
|
48
|
+
'',
|
|
49
|
+
'test(',
|
|
50
|
+
" 'user can post a message in channel',",
|
|
51
|
+
` {tag: '@${scenario.routeFamily}'},`,
|
|
52
|
+
' async ({pw}) => {',
|
|
53
|
+
' const {user} = await pw.initSetup();',
|
|
54
|
+
' const {channelsPage} = await pw.testBrowser.login(user);',
|
|
55
|
+
' await channelsPage.goto();',
|
|
56
|
+
' await channelsPage.toBeVisible();',
|
|
57
|
+
' // test steps...',
|
|
58
|
+
' },',
|
|
59
|
+
');',
|
|
60
|
+
'```',
|
|
61
|
+
'',
|
|
62
|
+
'Return ONLY the TypeScript code. No explanations.',
|
|
63
|
+
].filter(Boolean).join('\n');
|
|
64
|
+
}
|
|
65
|
+
function resolveSpecPath(scenario, testsRoot) {
|
|
66
|
+
let specPath;
|
|
67
|
+
if (scenario.targetSpec) {
|
|
68
|
+
specPath = join(testsRoot, scenario.targetSpec);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
const safeName = scenario.id.replace(/[^a-zA-Z0-9_-]/g, '_').toLowerCase();
|
|
72
|
+
const outputDir = join(testsRoot, 'specs', 'functional', 'ai-assisted');
|
|
73
|
+
specPath = join(outputDir, `${safeName}.spec.ts`);
|
|
74
|
+
}
|
|
75
|
+
// SECURITY: Prevent path traversal
|
|
76
|
+
const resolved = resolve(specPath);
|
|
77
|
+
const resolvedRoot = resolve(testsRoot);
|
|
78
|
+
if (!resolved.startsWith(resolvedRoot + '/') && resolved !== resolvedRoot) {
|
|
79
|
+
throw new Error(`Path traversal blocked: ${specPath} resolves outside testsRoot`);
|
|
80
|
+
}
|
|
81
|
+
if (!resolved.endsWith('.spec.ts') && !resolved.endsWith('.test.ts')) {
|
|
82
|
+
throw new Error(`Invalid spec path: must end in .spec.ts or .test.ts`);
|
|
83
|
+
}
|
|
84
|
+
return specPath;
|
|
85
|
+
}
|
|
86
|
+
async function generateInitialSpec(provider, scenario, specPath, apiSurfaceHint, profile) {
|
|
87
|
+
const prompt = buildGeneratePrompt(scenario, apiSurfaceHint, profile);
|
|
88
|
+
const response = await provider.generateText(prompt, {
|
|
89
|
+
maxTokens: 8000,
|
|
90
|
+
temperature: 0.1,
|
|
91
|
+
timeout: 60000,
|
|
92
|
+
systemPrompt: `You are an expert Playwright test writer for ${profile?.projectName || 'Mattermost'}. Return only TypeScript code.`,
|
|
93
|
+
});
|
|
94
|
+
// Reuse existing parsing logic from prompts/generation.ts
|
|
95
|
+
const parsed = parseGenerationResponse(response.text, specPath, 'create_spec', scenario.id);
|
|
96
|
+
return parsed?.code ?? null;
|
|
97
|
+
}
|
|
98
|
+
async function runSingleScenario(scenario, options) {
|
|
99
|
+
const { config, provider } = options;
|
|
100
|
+
const warnings = [];
|
|
101
|
+
const specPath = resolveSpecPath(scenario, config.testsRoot);
|
|
102
|
+
// Build API surface hint
|
|
103
|
+
let apiHint = options.apiSurfaceHint || '';
|
|
104
|
+
if (!apiHint && options.apiSurface) {
|
|
105
|
+
const allClassNames = options.apiSurface.pageObjects.map((po) => po.className);
|
|
106
|
+
apiHint = formatApiSurfaceForPrompt(options.apiSurface, allClassNames);
|
|
107
|
+
}
|
|
108
|
+
// Step 1: Generate initial spec
|
|
109
|
+
let specCode;
|
|
110
|
+
try {
|
|
111
|
+
specCode = await generateInitialSpec(provider, scenario, specPath, apiHint, options.generationProfile);
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
115
|
+
warnings.push(`Generation failed for ${scenario.id}: ${msg}`);
|
|
116
|
+
return { specPath, scenarioSource: scenario.id, status: 'failed', attempts: 0, warnings };
|
|
117
|
+
}
|
|
118
|
+
if (!specCode) {
|
|
119
|
+
warnings.push(`LLM returned invalid code for ${scenario.id}`);
|
|
120
|
+
return { specPath, scenarioSource: scenario.id, status: 'failed', attempts: 0, warnings };
|
|
121
|
+
}
|
|
122
|
+
// Write the spec file
|
|
123
|
+
const dir = dirname(specPath);
|
|
124
|
+
if (!existsSync(dir)) {
|
|
125
|
+
mkdirSync(dir, { recursive: true });
|
|
126
|
+
}
|
|
127
|
+
writeFileSync(specPath, specCode, 'utf-8');
|
|
128
|
+
// Dry run: skip execution
|
|
129
|
+
if (config.dryRun) {
|
|
130
|
+
return { specPath, scenarioSource: scenario.id, status: 'skipped', attempts: 0, warnings };
|
|
131
|
+
}
|
|
132
|
+
// Step 2: Run -> Fix loop
|
|
133
|
+
let lastRun;
|
|
134
|
+
for (let attempt = 1; attempt <= config.maxAttempts; attempt++) {
|
|
135
|
+
lastRun = runPlaywrightSpec(specPath, config.testsRoot, {
|
|
136
|
+
project: config.project,
|
|
137
|
+
baseUrl: config.baseUrl,
|
|
138
|
+
timeoutMs: config.testTimeoutMs,
|
|
139
|
+
});
|
|
140
|
+
// All passed!
|
|
141
|
+
if (lastRun.failed === 0 && lastRun.compiled) {
|
|
142
|
+
return {
|
|
143
|
+
specPath,
|
|
144
|
+
scenarioSource: scenario.id,
|
|
145
|
+
status: 'passed',
|
|
146
|
+
attempts: attempt,
|
|
147
|
+
finalRun: lastRun,
|
|
148
|
+
warnings,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
// If this is the last attempt, don't try to fix
|
|
152
|
+
if (attempt >= config.maxAttempts) {
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
// Step 3: Fix
|
|
156
|
+
const currentCode = readFileSync(specPath, 'utf-8');
|
|
157
|
+
try {
|
|
158
|
+
const fixResult = await generateFix(provider, {
|
|
159
|
+
specCode: currentCode,
|
|
160
|
+
failures: lastRun.failures,
|
|
161
|
+
attempt,
|
|
162
|
+
maxAttempts: config.maxAttempts,
|
|
163
|
+
apiSurfaceHint: apiHint,
|
|
164
|
+
});
|
|
165
|
+
if (fixResult.code) {
|
|
166
|
+
writeFileSync(specPath, fixResult.code, 'utf-8');
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
warnings.push(`Fix attempt ${attempt} returned invalid code for ${scenario.id}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
174
|
+
warnings.push(`Fix attempt ${attempt} failed for ${scenario.id}: ${msg}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
specPath,
|
|
179
|
+
scenarioSource: scenario.id,
|
|
180
|
+
status: lastRun?.compiled === false ? 'compile-error' : 'max-attempts',
|
|
181
|
+
attempts: config.maxAttempts,
|
|
182
|
+
finalRun: lastRun,
|
|
183
|
+
warnings,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
export async function runAgenticGeneration(options) {
|
|
187
|
+
const startTime = Date.now();
|
|
188
|
+
const results = [];
|
|
189
|
+
const warnings = [];
|
|
190
|
+
for (const scenario of options.scenarios) {
|
|
191
|
+
const result = await runSingleScenario(scenario, options);
|
|
192
|
+
results.push(result);
|
|
193
|
+
warnings.push(...result.warnings);
|
|
194
|
+
}
|
|
195
|
+
const totalPassed = results.filter((r) => r.status === 'passed').length;
|
|
196
|
+
const totalFailed = results.filter((r) => r.status !== 'passed' && r.status !== 'skipped').length;
|
|
197
|
+
const totalAttempts = results.reduce((sum, r) => sum + r.attempts, 0);
|
|
198
|
+
return {
|
|
199
|
+
results,
|
|
200
|
+
totalGenerated: results.length,
|
|
201
|
+
totalPassed,
|
|
202
|
+
totalFailed,
|
|
203
|
+
totalAttempts,
|
|
204
|
+
durationMs: Date.now() - startTime,
|
|
205
|
+
warnings,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
/**
|
|
4
|
+
* Coverage Evaluator Agent — wraps pipeline stage2 (coverage evaluation) in the Agent interface.
|
|
5
|
+
*/
|
|
6
|
+
import { runCoverageStage } from '../pipeline/stage2_coverage.js';
|
|
7
|
+
export class CoverageEvaluatorAgent {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.role = 'coverage-evaluator';
|
|
10
|
+
}
|
|
11
|
+
async execute(_task, ctx) {
|
|
12
|
+
const warnings = [];
|
|
13
|
+
if (ctx.impactedFlows.length === 0) {
|
|
14
|
+
warnings.push('Coverage evaluator: no impacted flows to evaluate.');
|
|
15
|
+
return { role: this.role, status: 'partial', output: [], warnings };
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
const result = await runCoverageStage(ctx.impactedFlows, ctx.specIndex, ctx.context, ctx.testsRoot, { provider: ctx.providerOverride });
|
|
19
|
+
// Replace impacted flows with coverage-enriched versions.
|
|
20
|
+
// This is intentionally a full replace (not push) because coverage evaluation
|
|
21
|
+
// returns the same flow IDs with updated coverage fields.
|
|
22
|
+
ctx.impactedFlows = result.decisions;
|
|
23
|
+
warnings.push(...result.warnings);
|
|
24
|
+
return {
|
|
25
|
+
role: this.role,
|
|
26
|
+
status: 'success',
|
|
27
|
+
output: result.decisions,
|
|
28
|
+
warnings,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
33
|
+
warnings.push(`Coverage evaluator failed: ${message}`);
|
|
34
|
+
return { role: this.role, status: 'failed', output: null, warnings };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|