@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,408 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
import { existsSync, readFileSync, readdirSync, writeFileSync } from 'fs';
|
|
4
|
+
import { join, extname } from 'path';
|
|
5
|
+
import ts from 'typescript';
|
|
6
|
+
// ── TypeScript AST-based extraction ────────────────────────
|
|
7
|
+
function extractMethodsFromAST(sourceFile, checker) {
|
|
8
|
+
const surfaces = [];
|
|
9
|
+
ts.forEachChild(sourceFile, (node) => {
|
|
10
|
+
if (!ts.isClassDeclaration(node) || !node.name) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const className = node.name.text;
|
|
14
|
+
const methods = [];
|
|
15
|
+
const seen = new Set();
|
|
16
|
+
// Get base class name if extends
|
|
17
|
+
let extendsName;
|
|
18
|
+
if (node.heritageClauses) {
|
|
19
|
+
for (const clause of node.heritageClauses) {
|
|
20
|
+
if (clause.token === ts.SyntaxKind.ExtendsKeyword && clause.types.length > 0) {
|
|
21
|
+
const expr = clause.types[0].expression;
|
|
22
|
+
if (ts.isIdentifier(expr)) {
|
|
23
|
+
extendsName = expr.text;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
for (const member of node.members) {
|
|
29
|
+
// Skip constructor
|
|
30
|
+
if (ts.isConstructorDeclaration(member)) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
// Skip private/protected members
|
|
34
|
+
const modifiers = ts.canHaveModifiers(member) ? ts.getModifiers(member) : undefined;
|
|
35
|
+
if (modifiers?.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword || m.kind === ts.SyntaxKind.ProtectedKeyword)) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const name = member.name && ts.isIdentifier(member.name) ? member.name.text : null;
|
|
39
|
+
if (!name || name.startsWith('_') || seen.has(name)) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
seen.add(name);
|
|
43
|
+
if (ts.isMethodDeclaration(member)) {
|
|
44
|
+
const isAsync = modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) ?? false;
|
|
45
|
+
const params = extractParams(member.parameters, checker);
|
|
46
|
+
const returnType = extractReturnType(member, checker);
|
|
47
|
+
methods.push({
|
|
48
|
+
name,
|
|
49
|
+
kind: 'method',
|
|
50
|
+
async: isAsync ? true : undefined,
|
|
51
|
+
params: params.length > 0 ? params : undefined,
|
|
52
|
+
returnType: returnType || undefined,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
else if (ts.isGetAccessorDeclaration(member)) {
|
|
56
|
+
methods.push({ name, kind: 'getter' });
|
|
57
|
+
}
|
|
58
|
+
else if (ts.isPropertyDeclaration(member)) {
|
|
59
|
+
// Check if it's an arrow function property (e.g., name = async () => {})
|
|
60
|
+
if (member.initializer && (ts.isArrowFunction(member.initializer) || ts.isFunctionExpression(member.initializer))) {
|
|
61
|
+
const fn = member.initializer;
|
|
62
|
+
const fnModifiers = ts.canHaveModifiers(fn) ? ts.getModifiers(fn) : undefined;
|
|
63
|
+
const isAsync = fnModifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) ?? false;
|
|
64
|
+
const params = extractParams(fn.parameters, checker);
|
|
65
|
+
methods.push({
|
|
66
|
+
name,
|
|
67
|
+
kind: 'method',
|
|
68
|
+
async: isAsync ? true : undefined,
|
|
69
|
+
params: params.length > 0 ? params : undefined,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
methods.push({ name, kind: 'property' });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (methods.length > 0) {
|
|
78
|
+
surfaces.push({
|
|
79
|
+
className,
|
|
80
|
+
file: sourceFile.fileName,
|
|
81
|
+
methods,
|
|
82
|
+
extends: extendsName,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
return surfaces;
|
|
87
|
+
}
|
|
88
|
+
function extractParams(params, checker) {
|
|
89
|
+
return params.map((p) => {
|
|
90
|
+
const name = ts.isIdentifier(p.name) ? p.name.text : p.name.getText();
|
|
91
|
+
const optional = p.questionToken !== undefined || p.initializer !== undefined;
|
|
92
|
+
let type;
|
|
93
|
+
if (p.type) {
|
|
94
|
+
type = p.type.getText();
|
|
95
|
+
}
|
|
96
|
+
else if (checker) {
|
|
97
|
+
try {
|
|
98
|
+
const symbol = checker.getSymbolAtLocation(p.name);
|
|
99
|
+
if (symbol) {
|
|
100
|
+
const t = checker.getTypeOfSymbolAtLocation(symbol, p);
|
|
101
|
+
type = checker.typeToString(t);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// Type inference failure is non-fatal
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return { name, type, optional: optional || undefined };
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
function extractReturnType(method, checker) {
|
|
112
|
+
if (method.type) {
|
|
113
|
+
return method.type.getText();
|
|
114
|
+
}
|
|
115
|
+
if (checker) {
|
|
116
|
+
try {
|
|
117
|
+
const signature = checker.getSignatureFromDeclaration(method);
|
|
118
|
+
if (signature) {
|
|
119
|
+
const returnType = checker.getReturnTypeOfSignature(signature);
|
|
120
|
+
const typeStr = checker.typeToString(returnType);
|
|
121
|
+
// Skip overly verbose inferred types
|
|
122
|
+
if (typeStr.length < 100) {
|
|
123
|
+
return typeStr;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// Type inference failure is non-fatal
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Extract page objects using the TypeScript Compiler API.
|
|
135
|
+
* Falls back to regex if compilation fails.
|
|
136
|
+
*/
|
|
137
|
+
function extractWithAST(files) {
|
|
138
|
+
if (files.length === 0) {
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
// Find the nearest tsconfig.json
|
|
142
|
+
const firstDir = join(files[0], '..');
|
|
143
|
+
const tsconfigPath = ts.findConfigFile(firstDir, ts.sys.fileExists, 'tsconfig.json');
|
|
144
|
+
let program;
|
|
145
|
+
if (tsconfigPath) {
|
|
146
|
+
const configFile = ts.readConfigFile(tsconfigPath, ts.sys.readFile);
|
|
147
|
+
const parsedConfig = ts.parseJsonConfigFileContent(configFile.config, ts.sys, join(tsconfigPath, '..'));
|
|
148
|
+
// Only compile the files we care about, using the config's compiler options
|
|
149
|
+
program = ts.createProgram(files, parsedConfig.options);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
program = ts.createProgram(files, {
|
|
153
|
+
target: ts.ScriptTarget.ES2022,
|
|
154
|
+
module: ts.ModuleKind.ESNext,
|
|
155
|
+
moduleResolution: ts.ModuleResolutionKind.Bundler,
|
|
156
|
+
strict: true,
|
|
157
|
+
allowJs: false,
|
|
158
|
+
noEmit: true,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
const checker = program.getTypeChecker();
|
|
162
|
+
const surfaces = [];
|
|
163
|
+
for (const filePath of files) {
|
|
164
|
+
const sourceFile = program.getSourceFile(filePath);
|
|
165
|
+
if (!sourceFile) {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
surfaces.push(...extractMethodsFromAST(sourceFile, checker));
|
|
169
|
+
}
|
|
170
|
+
// Resolve inherited methods: if class extends another class in the catalog,
|
|
171
|
+
// merge parent methods that the child doesn't override
|
|
172
|
+
resolveInheritance(surfaces);
|
|
173
|
+
return surfaces;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Merge parent class methods into child classes that extend them.
|
|
177
|
+
*/
|
|
178
|
+
function resolveInheritance(surfaces) {
|
|
179
|
+
const byName = new Map(surfaces.map((s) => [s.className, s]));
|
|
180
|
+
for (const surface of surfaces) {
|
|
181
|
+
if (!surface.extends) {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
const parent = byName.get(surface.extends);
|
|
185
|
+
if (!parent) {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
const childMethodNames = new Set(surface.methods.map((m) => m.name));
|
|
189
|
+
for (const parentMethod of parent.methods) {
|
|
190
|
+
if (!childMethodNames.has(parentMethod.name)) {
|
|
191
|
+
surface.methods.push({ ...parentMethod });
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// ── Regex-based extraction (fallback) ──────────────────────
|
|
197
|
+
const RESERVED_WORDS = new Set([
|
|
198
|
+
'private', 'protected', 'static', 'abstract', 'override',
|
|
199
|
+
'if', 'for', 'while', 'switch', 'return',
|
|
200
|
+
'const', 'let', 'var', 'import', 'export',
|
|
201
|
+
'class', 'type', 'interface', 'constructor',
|
|
202
|
+
]);
|
|
203
|
+
function extractMethodsFromRegex(content) {
|
|
204
|
+
const methods = [];
|
|
205
|
+
const seen = new Set();
|
|
206
|
+
const asyncMethodRe = /(?:async\s+)([a-zA-Z_]\w*)\s*\(/g;
|
|
207
|
+
let match;
|
|
208
|
+
while ((match = asyncMethodRe.exec(content)) !== null) {
|
|
209
|
+
const name = match[1];
|
|
210
|
+
if (!RESERVED_WORDS.has(name) && !seen.has(name)) {
|
|
211
|
+
seen.add(name);
|
|
212
|
+
methods.push({ name, kind: 'method', async: true });
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
const methodRe = /^\s+(?:readonly\s+)?([a-zA-Z_]\w*)\s*(?:\(|=\s*(?:async\s*)?\()/gm;
|
|
216
|
+
while ((match = methodRe.exec(content)) !== null) {
|
|
217
|
+
const name = match[1];
|
|
218
|
+
if (!RESERVED_WORDS.has(name) && !seen.has(name)) {
|
|
219
|
+
seen.add(name);
|
|
220
|
+
const isAsync = match[0].includes('async');
|
|
221
|
+
methods.push({ name, kind: 'method', async: isAsync ? true : undefined });
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
const arrowRe = /^\s+([a-zA-Z_]\w*)\s*=\s*(async\s+)?(?:\([^)]*\)|[a-zA-Z_]\w*)\s*=>/gm;
|
|
225
|
+
while ((match = arrowRe.exec(content)) !== null) {
|
|
226
|
+
const name = match[1];
|
|
227
|
+
if (!RESERVED_WORDS.has(name) && !seen.has(name)) {
|
|
228
|
+
seen.add(name);
|
|
229
|
+
methods.push({ name, kind: 'method', async: match[2] ? true : undefined });
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const getterRe = /\bget\s+([a-zA-Z_]\w*)\s*\(\)/g;
|
|
233
|
+
while ((match = getterRe.exec(content)) !== null) {
|
|
234
|
+
const name = match[1];
|
|
235
|
+
if (!seen.has(name)) {
|
|
236
|
+
seen.add(name);
|
|
237
|
+
methods.push({ name, kind: 'getter' });
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const propRe = /^\s+(?:readonly\s+)?([a-zA-Z_]\w*)\s*[:=]/gm;
|
|
241
|
+
while ((match = propRe.exec(content)) !== null) {
|
|
242
|
+
const name = match[1];
|
|
243
|
+
if (!RESERVED_WORDS.has(name) && !seen.has(name)) {
|
|
244
|
+
seen.add(name);
|
|
245
|
+
methods.push({ name, kind: 'property' });
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return methods;
|
|
249
|
+
}
|
|
250
|
+
function extractClassName(content) {
|
|
251
|
+
const match = content.match(/(?:export\s+)?class\s+(\w+)/);
|
|
252
|
+
return match ? match[1] : null;
|
|
253
|
+
}
|
|
254
|
+
// ── Directory scanning ─────────────────────────────────────
|
|
255
|
+
function collectTypeScriptFiles(dir) {
|
|
256
|
+
const files = [];
|
|
257
|
+
if (!existsSync(dir)) {
|
|
258
|
+
return files;
|
|
259
|
+
}
|
|
260
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
261
|
+
for (const entry of entries) {
|
|
262
|
+
const fullPath = join(dir, entry.name);
|
|
263
|
+
if (entry.isDirectory()) {
|
|
264
|
+
files.push(...collectTypeScriptFiles(fullPath));
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
const ext = extname(entry.name);
|
|
268
|
+
if (ext === '.ts' || ext === '.tsx') {
|
|
269
|
+
files.push(fullPath);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return files;
|
|
273
|
+
}
|
|
274
|
+
function scanDirectoryWithRegex(dir) {
|
|
275
|
+
const surfaces = [];
|
|
276
|
+
if (!existsSync(dir)) {
|
|
277
|
+
return surfaces;
|
|
278
|
+
}
|
|
279
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
280
|
+
for (const entry of entries) {
|
|
281
|
+
const fullPath = join(dir, entry.name);
|
|
282
|
+
if (entry.isDirectory()) {
|
|
283
|
+
surfaces.push(...scanDirectoryWithRegex(fullPath));
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
const ext = extname(entry.name);
|
|
287
|
+
if (ext !== '.ts' && ext !== '.tsx') {
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
try {
|
|
291
|
+
const content = readFileSync(fullPath, 'utf-8');
|
|
292
|
+
const className = extractClassName(content);
|
|
293
|
+
if (!className) {
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
const extractedMethods = extractMethodsFromRegex(content);
|
|
297
|
+
if (extractedMethods.length > 0) {
|
|
298
|
+
surfaces.push({ className, file: fullPath, methods: extractedMethods });
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
catch {
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return surfaces;
|
|
306
|
+
}
|
|
307
|
+
// ── Public API ──────────────────────────────────────────────
|
|
308
|
+
export function buildApiSurface(testsRoot, config) {
|
|
309
|
+
const pageObjectsDir = config?.pageObjectsDir
|
|
310
|
+
? join(testsRoot, config.pageObjectsDir)
|
|
311
|
+
: join(testsRoot, 'lib', 'src', 'ui', 'pages');
|
|
312
|
+
const componentsDir = config?.componentsDir
|
|
313
|
+
? join(testsRoot, config.componentsDir)
|
|
314
|
+
: join(testsRoot, 'lib', 'src', 'ui', 'components');
|
|
315
|
+
let pageObjects;
|
|
316
|
+
if (config?.useRegexFallback) {
|
|
317
|
+
pageObjects = [
|
|
318
|
+
...scanDirectoryWithRegex(pageObjectsDir),
|
|
319
|
+
...scanDirectoryWithRegex(componentsDir),
|
|
320
|
+
];
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
// Use TypeScript AST — full type info, inheritance, params
|
|
324
|
+
const allFiles = [
|
|
325
|
+
...collectTypeScriptFiles(pageObjectsDir),
|
|
326
|
+
...collectTypeScriptFiles(componentsDir),
|
|
327
|
+
];
|
|
328
|
+
try {
|
|
329
|
+
pageObjects = extractWithAST(allFiles);
|
|
330
|
+
}
|
|
331
|
+
catch {
|
|
332
|
+
// Fall back to regex if AST extraction fails
|
|
333
|
+
pageObjects = [
|
|
334
|
+
...scanDirectoryWithRegex(pageObjectsDir),
|
|
335
|
+
...scanDirectoryWithRegex(componentsDir),
|
|
336
|
+
];
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return {
|
|
340
|
+
pageObjects,
|
|
341
|
+
generatedAt: new Date().toISOString(),
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
export function loadOrBuildApiSurface(testsRoot, config) {
|
|
345
|
+
if (!config?.enabled) {
|
|
346
|
+
return { pageObjects: [], generatedAt: new Date().toISOString() };
|
|
347
|
+
}
|
|
348
|
+
const cachePath = config.cachePath
|
|
349
|
+
? join(testsRoot, config.cachePath)
|
|
350
|
+
: join(testsRoot, '.e2e-ai-agents', 'api-surface.json');
|
|
351
|
+
if (existsSync(cachePath)) {
|
|
352
|
+
try {
|
|
353
|
+
const cached = JSON.parse(readFileSync(cachePath, 'utf-8'));
|
|
354
|
+
if (cached.pageObjects && Array.isArray(cached.pageObjects)) {
|
|
355
|
+
return cached;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
catch {
|
|
359
|
+
// Rebuild if cache is corrupt
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
const catalog = buildApiSurface(testsRoot, config);
|
|
363
|
+
try {
|
|
364
|
+
const dir = join(cachePath, '..');
|
|
365
|
+
if (existsSync(dir)) {
|
|
366
|
+
writeFileSync(cachePath, JSON.stringify(catalog, null, 2), 'utf-8');
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
catch {
|
|
370
|
+
// Cache write failure is non-fatal
|
|
371
|
+
}
|
|
372
|
+
return catalog;
|
|
373
|
+
}
|
|
374
|
+
export function getMethodsForPageObject(catalog, className) {
|
|
375
|
+
const surface = catalog.pageObjects.find((po) => po.className === className);
|
|
376
|
+
return surface?.methods || [];
|
|
377
|
+
}
|
|
378
|
+
export function validateMethodCall(catalog, className, methodName) {
|
|
379
|
+
const methods = getMethodsForPageObject(catalog, className);
|
|
380
|
+
return methods.some((m) => m.name === methodName);
|
|
381
|
+
}
|
|
382
|
+
export function formatApiSurfaceForPrompt(catalog, classNames) {
|
|
383
|
+
const sections = [];
|
|
384
|
+
for (const name of classNames) {
|
|
385
|
+
const surface = catalog.pageObjects.find((po) => po.className === name);
|
|
386
|
+
if (!surface) {
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
const methodList = surface.methods
|
|
390
|
+
.map((m) => {
|
|
391
|
+
if (m.kind === 'property') {
|
|
392
|
+
return ` ${m.name} (property)`;
|
|
393
|
+
}
|
|
394
|
+
if (m.kind === 'getter') {
|
|
395
|
+
return ` get ${m.name}()`;
|
|
396
|
+
}
|
|
397
|
+
const prefix = m.async ? 'async ' : '';
|
|
398
|
+
const paramStr = m.params
|
|
399
|
+
? m.params.map((p) => `${p.name}${p.optional ? '?' : ''}${p.type ? `: ${p.type}` : ''}`).join(', ')
|
|
400
|
+
: '';
|
|
401
|
+
const retStr = m.returnType ? `: ${m.returnType}` : '';
|
|
402
|
+
return ` ${prefix}${m.name}(${paramStr})${retStr}`;
|
|
403
|
+
})
|
|
404
|
+
.join('\n');
|
|
405
|
+
sections.push(`${name}:\n${methodList}`);
|
|
406
|
+
}
|
|
407
|
+
return sections.join('\n\n');
|
|
408
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
/**
|
|
4
|
+
* Shared cluster ID derivation for knowledge graph processing.
|
|
5
|
+
* Used by both kg_bridge.ts and kg_scanner.ts.
|
|
6
|
+
*/
|
|
7
|
+
/** Default directories to skip when deriving cluster IDs from file paths. */
|
|
8
|
+
const DEFAULT_SKIP_DIRS = new Set([
|
|
9
|
+
'src', 'app', 'lib', 'packages', 'server', 'api', 'pages',
|
|
10
|
+
'components', 'features', 'modules',
|
|
11
|
+
]);
|
|
12
|
+
/** Extended skip set that also excludes test directories. */
|
|
13
|
+
const SKIP_DIRS_WITH_TESTS = new Set([
|
|
14
|
+
...DEFAULT_SKIP_DIRS,
|
|
15
|
+
'test', 'tests', 'e2e', 'spec', 'specs',
|
|
16
|
+
]);
|
|
17
|
+
/**
|
|
18
|
+
* Normalize a name to a snake_case cluster ID.
|
|
19
|
+
* Handles camelCase conversion, then strips non-alphanumeric characters.
|
|
20
|
+
*/
|
|
21
|
+
export function normalizeToClusterId(name) {
|
|
22
|
+
return name
|
|
23
|
+
.replace(/[A-Z]/g, (c, idx) => (idx > 0 ? `_${c.toLowerCase()}` : c.toLowerCase()))
|
|
24
|
+
.replace(/[^a-z0-9_]/g, '_')
|
|
25
|
+
.replace(/_+/g, '_')
|
|
26
|
+
.replace(/^_|_$/g, '');
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Derive a cluster ID from a node that has an optional filePath and name.
|
|
30
|
+
* Prefers file path grouping for consistency.
|
|
31
|
+
*/
|
|
32
|
+
export function deriveClusterId(node, skipDirs) {
|
|
33
|
+
if (node.filePath) {
|
|
34
|
+
return deriveClusterIdFromPath(node.filePath, skipDirs);
|
|
35
|
+
}
|
|
36
|
+
const name = normalizeToClusterId(node.name);
|
|
37
|
+
return name && name.length > 1 ? name : null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Derive a cluster ID from a file path by finding the first meaningful
|
|
41
|
+
* directory segment after skipping common structural prefixes.
|
|
42
|
+
*/
|
|
43
|
+
export function deriveClusterIdFromPath(filePath, skipDirs = DEFAULT_SKIP_DIRS) {
|
|
44
|
+
const parts = filePath.replace(/\\/g, '/').split('/').filter(Boolean);
|
|
45
|
+
for (const part of parts) {
|
|
46
|
+
if (skipDirs.has(part))
|
|
47
|
+
continue;
|
|
48
|
+
if (part.includes('.'))
|
|
49
|
+
continue; // skip files
|
|
50
|
+
const normalized = part.toLowerCase()
|
|
51
|
+
.replace(/[^a-z0-9_]/g, '_')
|
|
52
|
+
.replace(/_+/g, '_')
|
|
53
|
+
.replace(/^_|_$/g, '');
|
|
54
|
+
if (normalized && normalized.length > 1) {
|
|
55
|
+
return normalized;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
export { DEFAULT_SKIP_DIRS, SKIP_DIRS_WITH_TESTS };
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
import { existsSync, readFileSync } from 'fs';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
const MAX_CHARS_PER_DOC = 15000;
|
|
6
|
+
const MAX_TOTAL_CHARS = 40000;
|
|
7
|
+
const DEFAULT_CONTEXT_FILES = [
|
|
8
|
+
'CLAUDE.OPTIONAL.md',
|
|
9
|
+
'.claude/CLAUDE.OPTIONAL.md',
|
|
10
|
+
'README.md',
|
|
11
|
+
];
|
|
12
|
+
export function loadContextDocuments(testsRoot, appRoot, additionalFiles) {
|
|
13
|
+
const warnings = [];
|
|
14
|
+
const documents = [];
|
|
15
|
+
let totalChars = 0;
|
|
16
|
+
const files = [...DEFAULT_CONTEXT_FILES, ...(additionalFiles || [])];
|
|
17
|
+
const seen = new Set();
|
|
18
|
+
for (const file of files) {
|
|
19
|
+
if (totalChars >= MAX_TOTAL_CHARS) {
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
const candidates = [
|
|
23
|
+
join(testsRoot, file),
|
|
24
|
+
...(appRoot && appRoot !== testsRoot ? [join(appRoot, file)] : []),
|
|
25
|
+
];
|
|
26
|
+
let found = false;
|
|
27
|
+
for (const candidate of candidates) {
|
|
28
|
+
const normalized = candidate.replace(/\\/g, '/');
|
|
29
|
+
if (seen.has(normalized)) {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
seen.add(normalized);
|
|
33
|
+
if (!existsSync(candidate)) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const raw = readFileSync(candidate, 'utf-8').trim();
|
|
38
|
+
if (!raw) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const remaining = MAX_TOTAL_CHARS - totalChars;
|
|
42
|
+
const content = raw.slice(0, Math.min(MAX_CHARS_PER_DOC, remaining));
|
|
43
|
+
documents.push({
|
|
44
|
+
name: file,
|
|
45
|
+
path: normalized,
|
|
46
|
+
content,
|
|
47
|
+
});
|
|
48
|
+
totalChars += content.length;
|
|
49
|
+
found = true;
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (!found && DEFAULT_CONTEXT_FILES.includes(file)) {
|
|
57
|
+
// Only warn for default files, not user-provided ones
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (documents.length === 0) {
|
|
61
|
+
warnings.push('No context documents found (CLAUDE.OPTIONAL.md, README.md). AI agents will have reduced context.');
|
|
62
|
+
}
|
|
63
|
+
return { documents, warnings };
|
|
64
|
+
}
|
|
65
|
+
export function formatContextForPrompt(context) {
|
|
66
|
+
if (context.documents.length === 0) {
|
|
67
|
+
return 'No repository context documents available.';
|
|
68
|
+
}
|
|
69
|
+
return context.documents
|
|
70
|
+
.map((doc) => `### Context: ${doc.name}\n${doc.content}`)
|
|
71
|
+
.join('\n\n');
|
|
72
|
+
}
|
|
73
|
+
export function loadSpecFileContent(testsRoot, relativePath, maxChars = 20000) {
|
|
74
|
+
const fullPath = join(testsRoot, relativePath);
|
|
75
|
+
if (!existsSync(fullPath)) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
const content = readFileSync(fullPath, 'utf-8');
|
|
80
|
+
return content.slice(0, maxChars);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
/**
|
|
4
|
+
* Tracks historical test failure correlations: which tests fail when certain files change.
|
|
5
|
+
* Used to boost confidence in impact analysis — if a file change historically breaks a test,
|
|
6
|
+
* future changes to that file should prioritize that test.
|
|
7
|
+
*
|
|
8
|
+
* Data is stored as a JSON file at .e2e-ai-agents/failure-history.json.
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
11
|
+
import { join, dirname } from 'path';
|
|
12
|
+
const DEFAULT_HISTORY = {
|
|
13
|
+
correlations: [],
|
|
14
|
+
totalRuns: 0,
|
|
15
|
+
updatedAt: new Date().toISOString(),
|
|
16
|
+
};
|
|
17
|
+
export function loadFailureHistory(testsRoot) {
|
|
18
|
+
const historyPath = join(testsRoot, '.e2e-ai-agents', 'failure-history.json');
|
|
19
|
+
if (!existsSync(historyPath)) {
|
|
20
|
+
return { ...DEFAULT_HISTORY };
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const raw = JSON.parse(readFileSync(historyPath, 'utf-8'));
|
|
24
|
+
if (!Array.isArray(raw.correlations)) {
|
|
25
|
+
return { ...DEFAULT_HISTORY };
|
|
26
|
+
}
|
|
27
|
+
return raw;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return { ...DEFAULT_HISTORY };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export function saveFailureHistory(testsRoot, history) {
|
|
34
|
+
const historyPath = join(testsRoot, '.e2e-ai-agents', 'failure-history.json');
|
|
35
|
+
try {
|
|
36
|
+
const dir = dirname(historyPath);
|
|
37
|
+
if (!existsSync(dir)) {
|
|
38
|
+
mkdirSync(dir, { recursive: true });
|
|
39
|
+
}
|
|
40
|
+
history.updatedAt = new Date().toISOString();
|
|
41
|
+
writeFileSync(historyPath, JSON.stringify(history, null, 2), 'utf-8');
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Non-fatal — history is advisory, not required
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Record that a set of changed files caused a set of spec failures.
|
|
49
|
+
* Call this after a test run where failures were observed.
|
|
50
|
+
*/
|
|
51
|
+
export function recordFailures(history, changedFiles, failedSpecs) {
|
|
52
|
+
const now = new Date().toISOString();
|
|
53
|
+
const updated = { ...history, totalRuns: history.totalRuns + 1, correlations: [...history.correlations] };
|
|
54
|
+
for (const changedFile of changedFiles) {
|
|
55
|
+
for (const specFile of failedSpecs) {
|
|
56
|
+
const existing = updated.correlations.find((c) => c.changedFile === changedFile && c.specFile === specFile);
|
|
57
|
+
if (existing) {
|
|
58
|
+
existing.count++;
|
|
59
|
+
existing.lastSeen = now;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
updated.correlations.push({
|
|
63
|
+
changedFile,
|
|
64
|
+
specFile,
|
|
65
|
+
count: 1,
|
|
66
|
+
lastSeen: now,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Prune stale correlations (not seen in 90 days)
|
|
72
|
+
const cutoff = new Date();
|
|
73
|
+
cutoff.setDate(cutoff.getDate() - 90);
|
|
74
|
+
const cutoffStr = cutoff.toISOString();
|
|
75
|
+
updated.correlations = updated.correlations.filter((c) => c.lastSeen >= cutoffStr);
|
|
76
|
+
return updated;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get a confidence boost (0-20) for a file based on historical failure patterns.
|
|
80
|
+
* A file that historically causes test failures gets a higher confidence boost
|
|
81
|
+
* when detected as impacted, meaning the system is more confident it needs testing.
|
|
82
|
+
*/
|
|
83
|
+
export function getConfidenceBoost(history, changedFile) {
|
|
84
|
+
const correlations = history.correlations.filter((c) => c.changedFile === changedFile);
|
|
85
|
+
if (correlations.length === 0) {
|
|
86
|
+
return 0;
|
|
87
|
+
}
|
|
88
|
+
// More correlations and higher counts = more confidence
|
|
89
|
+
const totalCount = correlations.reduce((sum, c) => sum + c.count, 0);
|
|
90
|
+
const uniqueSpecs = correlations.length;
|
|
91
|
+
// Scale: 1 correlation = +5, 3+ = +10, 5+ with high counts = +15, max +20
|
|
92
|
+
if (totalCount >= 10 && uniqueSpecs >= 5)
|
|
93
|
+
return 20;
|
|
94
|
+
if (totalCount >= 5 && uniqueSpecs >= 3)
|
|
95
|
+
return 15;
|
|
96
|
+
if (totalCount >= 3)
|
|
97
|
+
return 10;
|
|
98
|
+
return 5;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Get the most likely failing specs for a set of changed files, based on history.
|
|
102
|
+
* Returns specs sorted by correlation strength (count * recency).
|
|
103
|
+
*/
|
|
104
|
+
export function getPredictedFailures(history, changedFiles, limit = 10) {
|
|
105
|
+
const specScores = new Map();
|
|
106
|
+
for (const changedFile of changedFiles) {
|
|
107
|
+
for (const c of history.correlations) {
|
|
108
|
+
if (c.changedFile !== changedFile)
|
|
109
|
+
continue;
|
|
110
|
+
// Score: count weighted by recency (days since last seen)
|
|
111
|
+
const daysSince = (Date.now() - new Date(c.lastSeen).getTime()) / (1000 * 60 * 60 * 24);
|
|
112
|
+
const recencyWeight = Math.max(0.1, 1 - daysSince / 90);
|
|
113
|
+
const score = c.count * recencyWeight;
|
|
114
|
+
specScores.set(c.specFile, (specScores.get(c.specFile) || 0) + score);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return Array.from(specScores.entries())
|
|
118
|
+
.map(([specFile, score]) => ({ specFile, score }))
|
|
119
|
+
.sort((a, b) => b.score - a.score)
|
|
120
|
+
.slice(0, limit);
|
|
121
|
+
}
|