@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
package/dist/progress.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
3
|
+
// See LICENSE.txt for license information.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.ProgressReporter = void 0;
|
|
6
|
+
const events_1 = require("events");
|
|
7
|
+
class ProgressReporter extends events_1.EventEmitter {
|
|
8
|
+
constructor(options) {
|
|
9
|
+
super();
|
|
10
|
+
this.isTTY = options?.isTTY ?? (process.stdout.isTTY === true);
|
|
11
|
+
this.silent = (options?.quiet ?? false) || (options?.jsonMode ?? false);
|
|
12
|
+
this.completedAgents = 0;
|
|
13
|
+
this.totalAgents = 0;
|
|
14
|
+
this.currentPhase = '';
|
|
15
|
+
}
|
|
16
|
+
phaseStart(phase, agentCount) {
|
|
17
|
+
const payload = { phase, agentCount };
|
|
18
|
+
this.emit('phase-start', payload);
|
|
19
|
+
if (this.silent) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
this.currentPhase = phase;
|
|
23
|
+
this.completedAgents = 0;
|
|
24
|
+
this.totalAgents = agentCount;
|
|
25
|
+
const message = `--- Phase: ${phase} (${agentCount} agent${agentCount !== 1 ? 's' : ''}) ---`;
|
|
26
|
+
this.writeLine(message);
|
|
27
|
+
}
|
|
28
|
+
agentStart(agent, family) {
|
|
29
|
+
const payload = { agent, family };
|
|
30
|
+
this.emit('agent-start', payload);
|
|
31
|
+
if (this.silent) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const familyLabel = family ? ` processing ${family}` : '';
|
|
35
|
+
if (this.isTTY) {
|
|
36
|
+
const progress = `[${this.completedAgents}/${this.totalAgents} agents]`;
|
|
37
|
+
const message = `${progress} ${this.currentPhase}: ${agent}${familyLabel}...`;
|
|
38
|
+
process.stdout.write(`\r${clearLine()}${message}`);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
const message = `[${this.currentPhase}] ${agent} started${familyLabel ? ':' + familyLabel : ''}`;
|
|
42
|
+
this.writeLine(message);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
agentComplete(agent, family, tokens, cost, durationMs) {
|
|
46
|
+
const payload = { agent, family, tokens, cost, durationMs };
|
|
47
|
+
this.emit('agent-complete', payload);
|
|
48
|
+
if (this.silent) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
this.completedAgents++;
|
|
52
|
+
const costStr = formatCost(cost);
|
|
53
|
+
const durationStr = formatDuration(durationMs);
|
|
54
|
+
const tokensStr = formatTokens(tokens);
|
|
55
|
+
const familyLabel = family ? ` ${family}` : '';
|
|
56
|
+
if (this.isTTY) {
|
|
57
|
+
const progress = `[${this.completedAgents}/${this.totalAgents} agents]`;
|
|
58
|
+
const message = `${progress} ${this.currentPhase}: ${agent} complete${familyLabel} (${tokensStr}, ${costStr}, ${durationStr})`;
|
|
59
|
+
process.stdout.write(`\r${clearLine()}${message}\n`);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
const message = `[${this.currentPhase}] ${agent} complete:${familyLabel} (${tokensStr}, ${costStr}, ${durationStr})`;
|
|
63
|
+
this.writeLine(message);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
phaseComplete(phase, elapsedMs) {
|
|
67
|
+
const payload = { phase, elapsedMs };
|
|
68
|
+
this.emit('phase-complete', payload);
|
|
69
|
+
if (this.silent) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const durationStr = formatDuration(elapsedMs);
|
|
73
|
+
const message = `--- Phase ${phase} complete (${durationStr}) ---`;
|
|
74
|
+
this.writeLine(message);
|
|
75
|
+
}
|
|
76
|
+
workflowComplete(totalCost, totalTokens, elapsedMs) {
|
|
77
|
+
const payload = { totalCost, totalTokens, elapsedMs };
|
|
78
|
+
this.emit('workflow-complete', payload);
|
|
79
|
+
if (this.silent) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const costStr = formatCost(totalCost);
|
|
83
|
+
const tokensStr = formatTokens(totalTokens);
|
|
84
|
+
const durationStr = formatDuration(elapsedMs);
|
|
85
|
+
const message = `=== Workflow complete: ${tokensStr}, ${costStr}, ${durationStr} ===`;
|
|
86
|
+
this.writeLine(message);
|
|
87
|
+
}
|
|
88
|
+
writeLine(message) {
|
|
89
|
+
process.stdout.write(message + '\n');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
exports.ProgressReporter = ProgressReporter;
|
|
93
|
+
function clearLine() {
|
|
94
|
+
return '\x1B[2K';
|
|
95
|
+
}
|
|
96
|
+
function formatCost(cost) {
|
|
97
|
+
return `$${cost.toFixed(2)}`;
|
|
98
|
+
}
|
|
99
|
+
function formatTokens(tokens) {
|
|
100
|
+
if (tokens >= 1000000) {
|
|
101
|
+
return `${(tokens / 1000000).toFixed(1)}M tokens`;
|
|
102
|
+
}
|
|
103
|
+
if (tokens >= 1000) {
|
|
104
|
+
return `${(tokens / 1000).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, ',')} tokens`;
|
|
105
|
+
}
|
|
106
|
+
return `${tokens} tokens`;
|
|
107
|
+
}
|
|
108
|
+
function formatDuration(ms) {
|
|
109
|
+
const seconds = Math.round(ms / 1000);
|
|
110
|
+
if (seconds >= 60) {
|
|
111
|
+
const minutes = Math.floor(seconds / 60);
|
|
112
|
+
const remainingSeconds = seconds % 60;
|
|
113
|
+
return remainingSeconds > 0 ? `${minutes}m${remainingSeconds}s` : `${minutes}m`;
|
|
114
|
+
}
|
|
115
|
+
return `${seconds}s`;
|
|
116
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { GenerationProfile } from './generation_profile.js';
|
|
2
|
+
export interface CoveragePromptFlow {
|
|
3
|
+
flowId: string;
|
|
4
|
+
flowName: string;
|
|
5
|
+
route: string;
|
|
6
|
+
userActions: string[];
|
|
7
|
+
evidence: string;
|
|
8
|
+
priority: string;
|
|
9
|
+
}
|
|
10
|
+
export interface CoveragePromptContext {
|
|
11
|
+
flows: CoveragePromptFlow[];
|
|
12
|
+
specs: Array<{
|
|
13
|
+
relativePath: string;
|
|
14
|
+
content: string;
|
|
15
|
+
testTitles: string[];
|
|
16
|
+
}>;
|
|
17
|
+
contextBlock: string;
|
|
18
|
+
profile?: GenerationProfile;
|
|
19
|
+
}
|
|
20
|
+
export declare function buildCoveragePrompt(ctx: CoveragePromptContext): string;
|
|
21
|
+
export interface CoverageAgentResponse {
|
|
22
|
+
coverage: Array<{
|
|
23
|
+
flowId: string;
|
|
24
|
+
action: string;
|
|
25
|
+
existingSpecs?: Array<{
|
|
26
|
+
path: string;
|
|
27
|
+
testTitles?: string[];
|
|
28
|
+
coverageLevel?: string;
|
|
29
|
+
missingScenarios?: string[];
|
|
30
|
+
}>;
|
|
31
|
+
scenariosToAdd?: string[];
|
|
32
|
+
targetSpec?: string;
|
|
33
|
+
newSpecPath?: string;
|
|
34
|
+
blockingReason?: string;
|
|
35
|
+
confidence?: number;
|
|
36
|
+
}>;
|
|
37
|
+
}
|
|
38
|
+
export declare function parseCoverageResponse(text: string): CoverageAgentResponse | null;
|
|
39
|
+
//# sourceMappingURL=coverage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../src/prompts/coverage.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,yBAAyB,CAAC;AAE/D,MAAM,WAAW,kBAAkB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB;IAClC,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC5B,KAAK,EAAE,KAAK,CAAC;QACT,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,EAAE,CAAC;KACxB,CAAC,CAAC;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC/B;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,qBAAqB,GAAG,MAAM,CAmDtE;AAED,MAAM,WAAW,qBAAqB;IAClC,QAAQ,EAAE,KAAK,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,aAAa,CAAC,EAAE,KAAK,CAAC;YAClB,IAAI,EAAE,MAAM,CAAC;YACb,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;YACtB,aAAa,CAAC,EAAE,MAAM,CAAC;YACvB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;SAC/B,CAAC,CAAC;QACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,UAAU,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC,CAAC;CACN;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,qBAAqB,GAAG,IAAI,CAMhF"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
3
|
+
// See LICENSE.txt for license information.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.buildCoveragePrompt = buildCoveragePrompt;
|
|
6
|
+
exports.parseCoverageResponse = parseCoverageResponse;
|
|
7
|
+
const json_extract_js_1 = require("./json_extract.js");
|
|
8
|
+
const sanitize_js_1 = require("../crew/sanitize.js");
|
|
9
|
+
function buildCoveragePrompt(ctx) {
|
|
10
|
+
const flowsBlock = ctx.flows
|
|
11
|
+
.map((f) => {
|
|
12
|
+
const actions = f.userActions.length > 0 ? f.userActions.map((a) => (0, sanitize_js_1.sanitizeForPrompt)(a)).join('; ') : 'unknown';
|
|
13
|
+
return `- ${f.flowId} (${f.priority}): ${f.flowName}\n Route: ${f.route}\n User actions: ${actions}\n Evidence: ${(0, sanitize_js_1.sanitizeForPrompt)(f.evidence)}`;
|
|
14
|
+
})
|
|
15
|
+
.join('\n\n');
|
|
16
|
+
const specsBlock = ctx.specs
|
|
17
|
+
.map((s) => {
|
|
18
|
+
return `### ${s.relativePath}\nTest titles: ${s.testTitles.join(', ')}\n\`\`\`typescript\n${s.content}\n\`\`\``;
|
|
19
|
+
})
|
|
20
|
+
.join('\n\n');
|
|
21
|
+
return [
|
|
22
|
+
`You are evaluating whether existing ${ctx.profile?.projectName || 'the project'} ${ctx.profile?.testFramework || 'Playwright'} E2E tests cover the impacted flows.`,
|
|
23
|
+
'',
|
|
24
|
+
`IMPACTED FLOWS (${ctx.flows.length}):`,
|
|
25
|
+
flowsBlock,
|
|
26
|
+
'',
|
|
27
|
+
`EXISTING SPEC FILES (${ctx.specs.length}):`,
|
|
28
|
+
specsBlock,
|
|
29
|
+
'',
|
|
30
|
+
ctx.contextBlock,
|
|
31
|
+
'',
|
|
32
|
+
'For each flow, determine coverage.',
|
|
33
|
+
'',
|
|
34
|
+
'Return strict JSON only with this shape:',
|
|
35
|
+
'{"coverage":[{"flowId":"<flow_id>","action":"run_existing|add_scenarios|create_spec|cannot_determine","existingSpecs":[{"path":"<relative path>","testTitles":["<exact test title>"],"coverageLevel":"full|partial|none","missingScenarios":["<specific scenario>"]}],"scenariosToAdd":["<scenario description>"],"targetSpec":"<path to extend>","newSpecPath":"<path for new spec>","blockingReason":"<why cannot_determine>","confidence":0-100}]}',
|
|
36
|
+
'',
|
|
37
|
+
'Rules:',
|
|
38
|
+
'- When claiming coverage exists, you MUST quote the exact test title from the spec file.',
|
|
39
|
+
'- If a spec tests a related but different flow, mark as "partial" not "full".',
|
|
40
|
+
'- Do NOT claim coverage exists if you cannot cite the exact test.',
|
|
41
|
+
'- Scenario gaps must be stated as user actions, not code changes.',
|
|
42
|
+
' Wrong: "test the new isEditing state"',
|
|
43
|
+
' Right: "test editing a scheduled message while it is in pending state"',
|
|
44
|
+
'- For add_scenarios, specify which existing spec file to extend in targetSpec.',
|
|
45
|
+
`- For create_spec, suggest a path following ${ctx.profile?.projectName || 'the project'} conventions.`,
|
|
46
|
+
'- Prefer adding scenarios to existing specs over creating new spec files.',
|
|
47
|
+
'',
|
|
48
|
+
'SEMANTIC MATCHING RULES (critical for accuracy):',
|
|
49
|
+
'- A happy-path test does NOT cover the negative/error path of the same feature.',
|
|
50
|
+
' "user can edit post" does NOT cover "user without permission cannot edit post".',
|
|
51
|
+
'- A test for one user role does NOT cover a different role.',
|
|
52
|
+
' "admin can delete channel" does NOT cover "member cannot delete channel".',
|
|
53
|
+
'- A test for creation does NOT cover editing or deletion of the same entity.',
|
|
54
|
+
'- "partial" means: same feature area but different specific scenario.',
|
|
55
|
+
'- "full" means: the exact user action sequence and outcome is tested.',
|
|
56
|
+
'- When in doubt between "full" and "partial", choose "partial".',
|
|
57
|
+
].join('\n');
|
|
58
|
+
}
|
|
59
|
+
function parseCoverageResponse(text) {
|
|
60
|
+
return (0, json_extract_js_1.extractJsonFromResponse)(text, (obj) => obj != null && typeof obj === 'object' && Array.isArray(obj.coverage));
|
|
61
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-Impact Analyst prompt — finds ripple effects across route families.
|
|
3
|
+
*/
|
|
4
|
+
import type { RouteFamily } from '../knowledge/route_families.js';
|
|
5
|
+
export interface CrossImpactPromptContext {
|
|
6
|
+
changedFiles: string[];
|
|
7
|
+
families: RouteFamily[];
|
|
8
|
+
/** The families directly impacted by changed files */
|
|
9
|
+
directlyImpactedFamilyIds: string[];
|
|
10
|
+
projectName?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function buildCrossImpactPrompt(ctx: CrossImpactPromptContext): string;
|
|
13
|
+
export interface CrossImpactAgentResponse {
|
|
14
|
+
crossImpacts: Array<{
|
|
15
|
+
sourceFamily: string;
|
|
16
|
+
affectedFamily: string;
|
|
17
|
+
sharedDependency: string;
|
|
18
|
+
riskLevel: 'high' | 'medium' | 'low' | string;
|
|
19
|
+
evidence: string;
|
|
20
|
+
}>;
|
|
21
|
+
}
|
|
22
|
+
export declare function parseCrossImpactResponse(text: string): CrossImpactAgentResponse | null;
|
|
23
|
+
//# sourceMappingURL=cross-impact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross-impact.d.ts","sourceRoot":"","sources":["../../src/prompts/cross-impact.ts"],"names":[],"mappings":"AAGA;;GAEG;AAEH,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,gCAAgC,CAAC;AAKhE,MAAM,WAAW,wBAAwB;IACrC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,sDAAsD;IACtD,yBAAyB,EAAE,MAAM,EAAE,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,wBAAwB,GAAG,MAAM,CA+C5E;AAED,MAAM,WAAW,wBAAwB;IACrC,YAAY,EAAE,KAAK,CAAC;QAChB,YAAY,EAAE,MAAM,CAAC;QACrB,cAAc,EAAE,MAAM,CAAC;QACvB,gBAAgB,EAAE,MAAM,CAAC;QACzB,SAAS,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;QAC9C,QAAQ,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACN;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,wBAAwB,GAAG,IAAI,CAMtF"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
3
|
+
// See LICENSE.txt for license information.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.buildCrossImpactPrompt = buildCrossImpactPrompt;
|
|
6
|
+
exports.parseCrossImpactResponse = parseCrossImpactResponse;
|
|
7
|
+
const sanitize_js_1 = require("../crew/sanitize.js");
|
|
8
|
+
const json_extract_js_1 = require("./json_extract.js");
|
|
9
|
+
function buildCrossImpactPrompt(ctx) {
|
|
10
|
+
const familiesBlock = ctx.families
|
|
11
|
+
.map((f) => {
|
|
12
|
+
const paths = [
|
|
13
|
+
...(f.webappPaths || []),
|
|
14
|
+
...(f.serverPaths || []),
|
|
15
|
+
...(f.components || []),
|
|
16
|
+
];
|
|
17
|
+
return `- ${f.id}: routes=[${f.routes.join(', ')}] paths=[${paths.join(', ')}] pageObjects=[${(f.pageObjects || []).join(', ')}]`;
|
|
18
|
+
})
|
|
19
|
+
.join('\n');
|
|
20
|
+
const changedBlock = ctx.changedFiles.map((f) => (0, sanitize_js_1.sanitizeForPrompt)(f)).join('\n');
|
|
21
|
+
return [
|
|
22
|
+
`You are analyzing code changes in ${ctx.projectName || 'the project'} to identify cross-family ripple effects.`,
|
|
23
|
+
'When a change in one route family could affect another family through shared dependencies,',
|
|
24
|
+
'that is a cross-impact.',
|
|
25
|
+
'',
|
|
26
|
+
`CHANGED FILES (${ctx.changedFiles.length}):`,
|
|
27
|
+
changedBlock,
|
|
28
|
+
'',
|
|
29
|
+
`DIRECTLY IMPACTED FAMILIES: ${ctx.directlyImpactedFamilyIds.join(', ')}`,
|
|
30
|
+
'',
|
|
31
|
+
`ALL ROUTE FAMILIES (${ctx.families.length}):`,
|
|
32
|
+
familiesBlock,
|
|
33
|
+
'',
|
|
34
|
+
'TASK: Identify cross-family impacts. For each pair, explain the shared dependency.',
|
|
35
|
+
'',
|
|
36
|
+
'Look for:',
|
|
37
|
+
'1. Shared webapp paths (same component used by multiple families)',
|
|
38
|
+
'2. Shared page objects (same PO class referenced by multiple families)',
|
|
39
|
+
'3. Shared API endpoints (changes affecting data used by multiple families)',
|
|
40
|
+
'4. Shared components (React components imported across family boundaries)',
|
|
41
|
+
'5. Shared state management (Redux stores, contexts used across families)',
|
|
42
|
+
'',
|
|
43
|
+
'Return strict JSON only with this shape:',
|
|
44
|
+
'{"crossImpacts":[{"sourceFamily":"<directly impacted family>","affectedFamily":"<indirectly affected family>","sharedDependency":"<what connects them>","riskLevel":"high|medium|low","evidence":"<specific file/component/API that creates the dependency>"}]}',
|
|
45
|
+
'',
|
|
46
|
+
'Rules:',
|
|
47
|
+
'- Only report cross-impacts where both families are in the manifest.',
|
|
48
|
+
'- sourceFamily must be one of the directly impacted families.',
|
|
49
|
+
'- affectedFamily must be DIFFERENT from sourceFamily.',
|
|
50
|
+
'- Risk levels: high = shared data model/state, medium = shared UI component, low = shared utility.',
|
|
51
|
+
'- Evidence must cite specific files, components, or API paths.',
|
|
52
|
+
'- Return empty array if no cross-impacts are found.',
|
|
53
|
+
].join('\n');
|
|
54
|
+
}
|
|
55
|
+
function parseCrossImpactResponse(text) {
|
|
56
|
+
return (0, json_extract_js_1.extractJsonFromResponse)(text, (obj) => obj != null && typeof obj === 'object' && Array.isArray(obj.crossImpacts));
|
|
57
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { FlowDecision } from '../validation/output_schema.js';
|
|
2
|
+
import type { ApiSurfaceCatalog } from '../knowledge/api_surface.js';
|
|
3
|
+
import type { GenerationProfile } from './generation_profile.js';
|
|
4
|
+
export interface GenerationPromptContext {
|
|
5
|
+
decision: FlowDecision;
|
|
6
|
+
apiSurface: ApiSurfaceCatalog;
|
|
7
|
+
existingSpecContent?: string;
|
|
8
|
+
specPath: string;
|
|
9
|
+
mode: 'create_spec' | 'add_scenarios';
|
|
10
|
+
profile?: GenerationProfile;
|
|
11
|
+
}
|
|
12
|
+
export declare function buildGenerationPrompt(ctx: GenerationPromptContext): string;
|
|
13
|
+
export interface GenerationAgentResponse {
|
|
14
|
+
specPath: string;
|
|
15
|
+
code: string;
|
|
16
|
+
mode: 'create_spec' | 'add_scenarios';
|
|
17
|
+
flowId: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function parseGenerationResponse(text: string, expectedPath: string, mode: 'create_spec' | 'add_scenarios', flowId: string, profile?: GenerationProfile): GenerationAgentResponse | null;
|
|
20
|
+
/**
|
|
21
|
+
* Returns method names that appear in generated code but do not exist in the API surface.
|
|
22
|
+
* Detects all call patterns: await X.Y(), X.Y(), const z = X.Y(), chained calls.
|
|
23
|
+
*/
|
|
24
|
+
export declare function detectHallucinatedMethods(code: string, apiSurface: ApiSurfaceCatalog): string[];
|
|
25
|
+
//# sourceMappingURL=generation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generation.d.ts","sourceRoot":"","sources":["../../src/prompts/generation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,YAAY,EAAmB,MAAM,gCAAgC,CAAC;AACnF,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,6BAA6B,CAAC;AAGnE,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,yBAAyB,CAAC;AAG/D,MAAM,WAAW,uBAAuB;IACpC,QAAQ,EAAE,YAAY,CAAC;IACvB,UAAU,EAAE,iBAAiB,CAAC;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,aAAa,GAAG,eAAe,CAAC;IACtC,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC/B;AA0CD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,uBAAuB,GAAG,MAAM,CA0H1E;AAgFD,MAAM,WAAW,uBAAuB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,GAAG,eAAe,CAAC;IACtC,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,uBAAuB,CACnC,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,aAAa,GAAG,eAAe,EACrC,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,iBAAiB,GAC5B,uBAAuB,GAAG,IAAI,CAuBhC;AAwBD;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,iBAAiB,GAAG,MAAM,EAAE,CAsC/F"}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
3
|
+
// See LICENSE.txt for license information.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.buildGenerationPrompt = buildGenerationPrompt;
|
|
6
|
+
exports.parseGenerationResponse = parseGenerationResponse;
|
|
7
|
+
exports.detectHallucinatedMethods = detectHallucinatedMethods;
|
|
8
|
+
const api_surface_js_1 = require("../knowledge/api_surface.js");
|
|
9
|
+
const sanitize_js_1 = require("../crew/sanitize.js");
|
|
10
|
+
const generation_profile_js_1 = require("./generation_profile.js");
|
|
11
|
+
function resolveRelevantPageObjects(apiSurface, decision) {
|
|
12
|
+
const relevant = [];
|
|
13
|
+
const familyHints = [
|
|
14
|
+
decision.routeFamily,
|
|
15
|
+
decision.featureId,
|
|
16
|
+
...decision.userActions.join(' ').toLowerCase().split(/\s+/),
|
|
17
|
+
]
|
|
18
|
+
.filter(Boolean)
|
|
19
|
+
.map((s) => s.toLowerCase().replace(/[^a-z]/g, ''));
|
|
20
|
+
for (const po of apiSurface.pageObjects) {
|
|
21
|
+
const nameLower = po.className.toLowerCase();
|
|
22
|
+
if (nameLower.includes('channels') ||
|
|
23
|
+
nameLower.includes('page') ||
|
|
24
|
+
familyHints.some((hint) => hint.length > 3 && nameLower.includes(hint))) {
|
|
25
|
+
relevant.push(po.className);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return [...new Set(relevant)].slice(0, 10);
|
|
29
|
+
}
|
|
30
|
+
function buildAssertionPatternsBlock(patterns) {
|
|
31
|
+
if (!patterns || patterns.length === 0) {
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
return [
|
|
35
|
+
'REQUIRED ASSERTION PATTERNS:',
|
|
36
|
+
'Your tests MUST include assertions that verify each of these behaviors.',
|
|
37
|
+
'Do NOT just check element visibility — verify the actual business outcome.',
|
|
38
|
+
...patterns.map((p) => ` - [${p.type}] ${p.pattern}`),
|
|
39
|
+
'',
|
|
40
|
+
];
|
|
41
|
+
}
|
|
42
|
+
function buildGenerationPrompt(ctx) {
|
|
43
|
+
const profile = ctx.profile;
|
|
44
|
+
const isMM = profile ? (0, generation_profile_js_1.isMattermostProfile)(profile) : false;
|
|
45
|
+
const relevantClasses = resolveRelevantPageObjects(ctx.apiSurface, ctx.decision);
|
|
46
|
+
const apiBlock = relevantClasses.length > 0
|
|
47
|
+
? (0, api_surface_js_1.formatApiSurfaceForPrompt)(ctx.apiSurface, relevantClasses)
|
|
48
|
+
: 'No page objects available. Use raw Playwright selectors via page.getByRole/getByTestId.';
|
|
49
|
+
const scenariosBlock = (ctx.decision.scenariosToAdd || [])
|
|
50
|
+
.map((s, i) => ` ${i + 1}. ${s}`)
|
|
51
|
+
.join('\n');
|
|
52
|
+
const existingBlock = ctx.existingSpecContent
|
|
53
|
+
? `\nEXISTING SPEC (extend this file):\n\`\`\`typescript\n${ctx.existingSpecContent}\n\`\`\``
|
|
54
|
+
: '';
|
|
55
|
+
const modeInstruction = ctx.mode === 'create_spec'
|
|
56
|
+
? `Create a NEW spec file at: ${ctx.specPath}`
|
|
57
|
+
: `ADD scenarios to the EXISTING spec at: ${ctx.specPath}`;
|
|
58
|
+
const routeFamilyTag = ctx.decision.routeFamily;
|
|
59
|
+
// Build prompt based on profile
|
|
60
|
+
const projectName = profile?.projectName || 'Project';
|
|
61
|
+
const testFramework = profile?.testFramework || 'Playwright';
|
|
62
|
+
const importStatement = profile?.importStatement || '@playwright/test';
|
|
63
|
+
// API test mode prompt
|
|
64
|
+
if (profile?.testMode === 'api') {
|
|
65
|
+
return buildApiTestPrompt(ctx, profile, scenariosBlock, routeFamilyTag);
|
|
66
|
+
}
|
|
67
|
+
// Build rules from profile conventions or use Mattermost defaults
|
|
68
|
+
const rules = isMM
|
|
69
|
+
? [
|
|
70
|
+
`1. Import ONLY from "${importStatement}" — no other test framework imports.`,
|
|
71
|
+
'2. Every test must call `await pw.initSetup()` first.',
|
|
72
|
+
'3. Use `await pw.testBrowser.login(user)` to log in — never hardcode credentials.',
|
|
73
|
+
'4. Use ONLY page object methods listed above. Do NOT invent methods that are not listed.',
|
|
74
|
+
'5. If a method is not available, use `page.getByRole()` or `page.getByTestId()`.',
|
|
75
|
+
`6. Tag every test: {tag: '@${routeFamilyTag}'}`,
|
|
76
|
+
'7. Write one test per scenario with a descriptive name of what the user does and what is verified.',
|
|
77
|
+
`8. Use \`expect\` from "${importStatement}" — do NOT import from "@playwright/test".`,
|
|
78
|
+
'9. Include the copyright header for new files.',
|
|
79
|
+
'10. NEVER fabricate test IDs (MM-TXXXX). Use descriptive names only.',
|
|
80
|
+
]
|
|
81
|
+
: [
|
|
82
|
+
...(profile?.conventions || []).map((c, i) => `${i + 1}. ${c}`),
|
|
83
|
+
`${(profile?.conventions?.length || 0) + 1}. Use ONLY page object methods listed above. Do NOT invent methods that are not listed.`,
|
|
84
|
+
`${(profile?.conventions?.length || 0) + 2}. If a method is not available, use \`page.getByRole()\` or \`page.getByTestId()\`.`,
|
|
85
|
+
`${(profile?.conventions?.length || 0) + 3}. Tag every test: {tag: '@${routeFamilyTag}'}`,
|
|
86
|
+
];
|
|
87
|
+
// Build example block
|
|
88
|
+
const exampleBlock = isMM
|
|
89
|
+
? [
|
|
90
|
+
'EXAMPLE SPEC STRUCTURE:',
|
|
91
|
+
'```typescript',
|
|
92
|
+
'// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.',
|
|
93
|
+
'// See LICENSE.txt for license information.',
|
|
94
|
+
'',
|
|
95
|
+
`import {expect, test} from '${importStatement}';`,
|
|
96
|
+
'',
|
|
97
|
+
'test(',
|
|
98
|
+
" 'descriptive name of what is tested',",
|
|
99
|
+
` {tag: '@${routeFamilyTag}'},`,
|
|
100
|
+
' async ({pw}) => {',
|
|
101
|
+
' const {user} = await pw.initSetup();',
|
|
102
|
+
' const {channelsPage} = await pw.testBrowser.login(user);',
|
|
103
|
+
' await channelsPage.goto();',
|
|
104
|
+
' await channelsPage.toBeVisible();',
|
|
105
|
+
' // test steps...',
|
|
106
|
+
' },',
|
|
107
|
+
');',
|
|
108
|
+
'```',
|
|
109
|
+
]
|
|
110
|
+
: [
|
|
111
|
+
'EXAMPLE SPEC STRUCTURE:',
|
|
112
|
+
'```typescript',
|
|
113
|
+
...(profile?.copyrightHeader ? [profile.copyrightHeader, ''] : []),
|
|
114
|
+
`import {test, expect} from '${importStatement}';`,
|
|
115
|
+
'',
|
|
116
|
+
'test(',
|
|
117
|
+
" 'descriptive name of what is tested',",
|
|
118
|
+
` {tag: '@${routeFamilyTag}'},`,
|
|
119
|
+
' async ({page}) => {',
|
|
120
|
+
' // test steps...',
|
|
121
|
+
' },',
|
|
122
|
+
');',
|
|
123
|
+
'```',
|
|
124
|
+
];
|
|
125
|
+
return [
|
|
126
|
+
`You are generating ${projectName} ${testFramework} E2E test code.`,
|
|
127
|
+
'',
|
|
128
|
+
`TASK: ${modeInstruction}`,
|
|
129
|
+
'',
|
|
130
|
+
`FLOW: ${(0, sanitize_js_1.sanitizeForPrompt)(ctx.decision.flowName)}`,
|
|
131
|
+
`Route Family: ${ctx.decision.routeFamily}${ctx.decision.featureId ? ` / ${ctx.decision.featureId}` : ''}`,
|
|
132
|
+
`Route: ${ctx.decision.specificRoute || '(not specified)'}`,
|
|
133
|
+
`Priority: ${ctx.decision.priority}`,
|
|
134
|
+
`Evidence: ${(0, sanitize_js_1.sanitizeForPrompt)(ctx.decision.evidence)}`,
|
|
135
|
+
'',
|
|
136
|
+
'SCENARIOS TO IMPLEMENT:',
|
|
137
|
+
scenariosBlock || ' (implement core user actions for this flow)',
|
|
138
|
+
'',
|
|
139
|
+
'USER ACTIONS:',
|
|
140
|
+
ctx.decision.userActions.map((a) => ` - ${(0, sanitize_js_1.sanitizeForPrompt)(a)}`).join('\n') || ' (none specified)',
|
|
141
|
+
'',
|
|
142
|
+
...buildAssertionPatternsBlock(ctx.decision.assertionPatterns),
|
|
143
|
+
'AVAILABLE PAGE OBJECTS AND METHODS:',
|
|
144
|
+
apiBlock,
|
|
145
|
+
existingBlock,
|
|
146
|
+
'',
|
|
147
|
+
'MANDATORY RULES:',
|
|
148
|
+
...rules,
|
|
149
|
+
'',
|
|
150
|
+
...exampleBlock,
|
|
151
|
+
'',
|
|
152
|
+
'Return ONLY the TypeScript code. No explanations, no markdown fences.',
|
|
153
|
+
].join('\n');
|
|
154
|
+
}
|
|
155
|
+
function buildApiTestPrompt(ctx, profile, scenariosBlock, routeFamilyTag) {
|
|
156
|
+
const modeInstruction = ctx.mode === 'create_spec'
|
|
157
|
+
? `Create a NEW test file at: ${ctx.specPath}`
|
|
158
|
+
: `ADD test cases to the EXISTING file at: ${ctx.specPath}`;
|
|
159
|
+
const existingBlock = ctx.existingSpecContent
|
|
160
|
+
? `\nEXISTING FILE (extend this):\n\`\`\`typescript\n${ctx.existingSpecContent}\n\`\`\``
|
|
161
|
+
: '';
|
|
162
|
+
return [
|
|
163
|
+
`You are generating ${profile.projectName} API test code using ${profile.testFramework}.`,
|
|
164
|
+
'',
|
|
165
|
+
`TASK: ${modeInstruction}`,
|
|
166
|
+
'',
|
|
167
|
+
`FLOW: ${(0, sanitize_js_1.sanitizeForPrompt)(ctx.decision.flowName)}`,
|
|
168
|
+
`Route Family: ${ctx.decision.routeFamily}${ctx.decision.featureId ? ` / ${ctx.decision.featureId}` : ''}`,
|
|
169
|
+
`Endpoint: ${ctx.decision.specificRoute || '(not specified)'}`,
|
|
170
|
+
`Priority: ${ctx.decision.priority}`,
|
|
171
|
+
`Evidence: ${(0, sanitize_js_1.sanitizeForPrompt)(ctx.decision.evidence)}`,
|
|
172
|
+
'',
|
|
173
|
+
'SCENARIOS TO IMPLEMENT:',
|
|
174
|
+
scenariosBlock || ' (implement core API endpoint tests)',
|
|
175
|
+
'',
|
|
176
|
+
'USER ACTIONS:',
|
|
177
|
+
ctx.decision.userActions.map((a) => ` - ${(0, sanitize_js_1.sanitizeForPrompt)(a)}`).join('\n') || ' (none specified)',
|
|
178
|
+
'',
|
|
179
|
+
...buildAssertionPatternsBlock(ctx.decision.assertionPatterns),
|
|
180
|
+
existingBlock,
|
|
181
|
+
'',
|
|
182
|
+
'MANDATORY RULES:',
|
|
183
|
+
...profile.conventions.map((c, i) => `${i + 1}. ${c}`),
|
|
184
|
+
`${profile.conventions.length + 1}. Tag every test: {tag: '@${routeFamilyTag}'}`,
|
|
185
|
+
'',
|
|
186
|
+
'EXAMPLE TEST STRUCTURE:',
|
|
187
|
+
...(profile.testFramework.toLowerCase().includes('pytest')
|
|
188
|
+
? [
|
|
189
|
+
'```python',
|
|
190
|
+
...(profile.copyrightHeader ? [profile.copyrightHeader, ''] : []),
|
|
191
|
+
'import pytest',
|
|
192
|
+
'import requests',
|
|
193
|
+
'',
|
|
194
|
+
`BASE_URL = 'http://localhost:3000'`,
|
|
195
|
+
'',
|
|
196
|
+
'',
|
|
197
|
+
`class Test${ctx.decision.routeFamily.replace(/[^a-zA-Z0-9]/g, '')}:`,
|
|
198
|
+
" def test_should_return_200_for_valid_request(self):",
|
|
199
|
+
` res = requests.get(f'{BASE_URL}${ctx.decision.specificRoute || '/api/endpoint'}')`,
|
|
200
|
+
' assert res.status_code == 200',
|
|
201
|
+
'```',
|
|
202
|
+
]
|
|
203
|
+
: [
|
|
204
|
+
'```typescript',
|
|
205
|
+
...(profile.copyrightHeader ? [profile.copyrightHeader, ''] : []),
|
|
206
|
+
`import {describe, it, expect} from '${profile.importStatement}';`,
|
|
207
|
+
"import supertest from 'supertest';",
|
|
208
|
+
'',
|
|
209
|
+
"const request = supertest('http://localhost:3000');",
|
|
210
|
+
'',
|
|
211
|
+
`describe('${ctx.decision.routeFamily}', () => {`,
|
|
212
|
+
" it('should return 200 for valid request', async () => {",
|
|
213
|
+
` const res = await request.get('${ctx.decision.specificRoute || '/api/endpoint'}');`,
|
|
214
|
+
' expect(res.status).toBe(200);',
|
|
215
|
+
' });',
|
|
216
|
+
'});',
|
|
217
|
+
'```',
|
|
218
|
+
]),
|
|
219
|
+
'',
|
|
220
|
+
...(profile.testFramework.toLowerCase().includes('pytest')
|
|
221
|
+
? ['Return ONLY the Python code. No explanations, no markdown fences.']
|
|
222
|
+
: ['Return ONLY the TypeScript code. No explanations, no markdown fences.']),
|
|
223
|
+
].join('\n');
|
|
224
|
+
}
|
|
225
|
+
function parseGenerationResponse(text, expectedPath, mode, flowId, profile) {
|
|
226
|
+
let code = text.trim();
|
|
227
|
+
const fenced = code.match(/^```(?:typescript|ts)?\s*([\s\S]*?)```\s*$/i);
|
|
228
|
+
if (fenced) {
|
|
229
|
+
code = fenced[1].trim();
|
|
230
|
+
}
|
|
231
|
+
if (!code.includes('test(') && !code.includes('it(') && !code.includes('describe(')) {
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
const importStatement = profile?.importStatement || '@playwright/test';
|
|
235
|
+
// Auto-add import if missing
|
|
236
|
+
if (!code.includes(importStatement)) {
|
|
237
|
+
if (profile?.testMode === 'api') {
|
|
238
|
+
code = `import {describe, it, expect} from '${importStatement}';\n\n${code}`;
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
code = `import {expect, test} from '${importStatement}';\n\n${code}`;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return { specPath: expectedPath, code, mode, flowId };
|
|
245
|
+
}
|
|
246
|
+
const BUILT_IN_METHODS = new Set([
|
|
247
|
+
'click', 'fill', 'focus', 'hover', 'press', 'type', 'check', 'uncheck',
|
|
248
|
+
'selectOption', 'waitFor', 'waitForLoadState', 'evaluate', 'dispatchEvent',
|
|
249
|
+
'getAttribute', 'textContent', 'innerText', 'innerHTML',
|
|
250
|
+
'isVisible', 'isEnabled', 'isChecked', 'isHidden',
|
|
251
|
+
'toBeVisible', 'toBeEnabled', 'toBeChecked', 'toBeHidden',
|
|
252
|
+
'toContainText', 'toHaveText', 'toHaveURL', 'toHaveValue',
|
|
253
|
+
'not', 'nth', 'first', 'last', 'all',
|
|
254
|
+
'getByRole', 'getByText', 'getByLabel', 'getByPlaceholder',
|
|
255
|
+
'getByTestId', 'getByTitle', 'getByAltText',
|
|
256
|
+
'locator', 'frame', 'page', 'expect',
|
|
257
|
+
'goBack', 'goForward', 'reload', 'goto',
|
|
258
|
+
'keyboard', 'mouse', 'touchscreen', 'close', 'bringToFront',
|
|
259
|
+
'initSetup', 'login', 'waitUntil', 'skipIfNoLicense', 'ensureLicense',
|
|
260
|
+
'random', 'duration', 'isOutsideRemoteUserHour', 'setTimeout',
|
|
261
|
+
'skip', 'fixme', 'slow', 'fail',
|
|
262
|
+
// API testing built-ins
|
|
263
|
+
'get', 'post', 'put', 'patch', 'delete', 'send', 'set', 'query',
|
|
264
|
+
'toBe', 'toEqual', 'toBeDefined', 'toContain', 'toHaveProperty',
|
|
265
|
+
'toMatchObject', 'toHaveLength', 'toBeTruthy', 'toBeFalsy',
|
|
266
|
+
]);
|
|
267
|
+
/**
|
|
268
|
+
* Returns method names that appear in generated code but do not exist in the API surface.
|
|
269
|
+
* Detects all call patterns: await X.Y(), X.Y(), const z = X.Y(), chained calls.
|
|
270
|
+
*/
|
|
271
|
+
function detectHallucinatedMethods(code, apiSurface) {
|
|
272
|
+
const allMethods = new Set(apiSurface.pageObjects.flatMap((po) => po.methods.map((m) => m.name)));
|
|
273
|
+
const suspected = new Set();
|
|
274
|
+
const callPatterns = [
|
|
275
|
+
/\bawait\s+\w+\.([a-zA-Z_]\w*)\s*\(/g,
|
|
276
|
+
/\b(?:const|let|var)\s+\w+\s*=\s*\w+\.([a-zA-Z_]\w*)\s*\(/g,
|
|
277
|
+
/\b\w+Page\.([a-zA-Z_]\w*)\s*\(/g, // any *Page object (channelsPage, settingsPage, etc.)
|
|
278
|
+
/\b(?:pw|page|this)\.\w*\.?([a-zA-Z_]\w*)\s*\(/g,
|
|
279
|
+
];
|
|
280
|
+
const generalCallRe = /\b[a-zA-Z_]\w*\.([a-zA-Z_]\w*)\s*\(/g;
|
|
281
|
+
for (const re of callPatterns) {
|
|
282
|
+
let match;
|
|
283
|
+
while ((match = re.exec(code)) !== null) {
|
|
284
|
+
const methodName = match[1];
|
|
285
|
+
if (!BUILT_IN_METHODS.has(methodName) && !allMethods.has(methodName) && methodName.length > 3) {
|
|
286
|
+
suspected.add(methodName);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
let match;
|
|
291
|
+
while ((match = generalCallRe.exec(code)) !== null) {
|
|
292
|
+
const methodName = match[1];
|
|
293
|
+
if (!BUILT_IN_METHODS.has(methodName) &&
|
|
294
|
+
!allMethods.has(methodName) &&
|
|
295
|
+
methodName.length > 3 &&
|
|
296
|
+
!methodName.startsWith('to') &&
|
|
297
|
+
!methodName.startsWith('get')) {
|
|
298
|
+
suspected.add(methodName);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return [...suspected];
|
|
302
|
+
}
|