@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.
Files changed (587) hide show
  1. package/LICENSE +168 -0
  2. package/README.md +520 -0
  3. package/dist/adapters/cypress.d.ts +10 -0
  4. package/dist/adapters/cypress.d.ts.map +1 -0
  5. package/dist/adapters/cypress.js +86 -0
  6. package/dist/adapters/framework_adapter.d.ts +41 -0
  7. package/dist/adapters/framework_adapter.d.ts.map +1 -0
  8. package/dist/adapters/framework_adapter.js +152 -0
  9. package/dist/adapters/playwright.d.ts +10 -0
  10. package/dist/adapters/playwright.d.ts.map +1 -0
  11. package/dist/adapters/playwright.js +86 -0
  12. package/dist/adapters/pytest.d.ts +10 -0
  13. package/dist/adapters/pytest.d.ts.map +1 -0
  14. package/dist/adapters/pytest.js +96 -0
  15. package/dist/adapters/supertest.d.ts +12 -0
  16. package/dist/adapters/supertest.d.ts.map +1 -0
  17. package/dist/adapters/supertest.js +85 -0
  18. package/dist/agent/api_catalog.d.ts +11 -0
  19. package/dist/agent/api_catalog.d.ts.map +1 -0
  20. package/dist/agent/api_catalog.js +210 -0
  21. package/dist/agent/config.d.ts +193 -0
  22. package/dist/agent/config.d.ts.map +1 -0
  23. package/dist/agent/config.js +875 -0
  24. package/dist/agent/feedback.d.ts +91 -0
  25. package/dist/agent/feedback.d.ts.map +1 -0
  26. package/dist/agent/feedback.js +323 -0
  27. package/dist/agent/git.d.ts +19 -0
  28. package/dist/agent/git.d.ts.map +1 -0
  29. package/dist/agent/git.js +257 -0
  30. package/dist/agent/handoff.d.ts +22 -0
  31. package/dist/agent/handoff.d.ts.map +1 -0
  32. package/dist/agent/handoff.js +180 -0
  33. package/dist/agent/llm_agents_flow.d.ts +15 -0
  34. package/dist/agent/llm_agents_flow.d.ts.map +1 -0
  35. package/dist/agent/llm_agents_flow.js +434 -0
  36. package/dist/agent/native_flow.d.ts +6 -0
  37. package/dist/agent/native_flow.d.ts.map +1 -0
  38. package/dist/agent/native_flow.js +179 -0
  39. package/dist/agent/pipeline.d.ts +7 -0
  40. package/dist/agent/pipeline.d.ts.map +1 -0
  41. package/dist/agent/pipeline.js +260 -0
  42. package/dist/agent/pipeline_types.d.ts +54 -0
  43. package/dist/agent/pipeline_types.d.ts.map +1 -0
  44. package/dist/agent/pipeline_types.js +4 -0
  45. package/dist/agent/pipeline_utils.d.ts +12 -0
  46. package/dist/agent/pipeline_utils.d.ts.map +1 -0
  47. package/dist/agent/pipeline_utils.js +156 -0
  48. package/dist/agent/plan.d.ts +170 -0
  49. package/dist/agent/plan.d.ts.map +1 -0
  50. package/dist/agent/plan.js +86 -0
  51. package/dist/agent/playwright_report.d.ts +8 -0
  52. package/dist/agent/playwright_report.d.ts.map +1 -0
  53. package/dist/agent/playwright_report.js +126 -0
  54. package/dist/agent/process_runner.d.ts +10 -0
  55. package/dist/agent/process_runner.d.ts.map +1 -0
  56. package/dist/agent/process_runner.js +92 -0
  57. package/dist/agent/spec_generator.d.ts +5 -0
  58. package/dist/agent/spec_generator.d.ts.map +1 -0
  59. package/dist/agent/spec_generator.js +253 -0
  60. package/dist/agent/test_path.d.ts +2 -0
  61. package/dist/agent/test_path.d.ts.map +1 -0
  62. package/dist/agent/test_path.js +23 -0
  63. package/dist/agent/traceability_capture.d.ts +18 -0
  64. package/dist/agent/traceability_capture.d.ts.map +1 -0
  65. package/dist/agent/traceability_capture.js +313 -0
  66. package/dist/agent/traceability_ingest.d.ts +21 -0
  67. package/dist/agent/traceability_ingest.d.ts.map +1 -0
  68. package/dist/agent/traceability_ingest.js +237 -0
  69. package/dist/agent/types.d.ts +42 -0
  70. package/dist/agent/types.d.ts.map +1 -0
  71. package/dist/agent/types.js +4 -0
  72. package/dist/agent/utils.d.ts +13 -0
  73. package/dist/agent/utils.d.ts.map +1 -0
  74. package/dist/agent/utils.js +152 -0
  75. package/dist/agent/validation_runner.d.ts +5 -0
  76. package/dist/agent/validation_runner.d.ts.map +1 -0
  77. package/dist/agent/validation_runner.js +77 -0
  78. package/dist/agentic/fix_loop.d.ts +26 -0
  79. package/dist/agentic/fix_loop.d.ts.map +1 -0
  80. package/dist/agentic/fix_loop.js +96 -0
  81. package/dist/agentic/playwright_runner.d.ts +43 -0
  82. package/dist/agentic/playwright_runner.d.ts.map +1 -0
  83. package/dist/agentic/playwright_runner.js +165 -0
  84. package/dist/agentic/runner.d.ts +27 -0
  85. package/dist/agentic/runner.d.ts.map +1 -0
  86. package/dist/agentic/runner.js +210 -0
  87. package/dist/agentic/types.d.ts +62 -0
  88. package/dist/agentic/types.d.ts.map +1 -0
  89. package/dist/agentic/types.js +4 -0
  90. package/dist/agents/coverage-evaluator.d.ts +8 -0
  91. package/dist/agents/coverage-evaluator.d.ts.map +1 -0
  92. package/dist/agents/coverage-evaluator.js +41 -0
  93. package/dist/agents/cross-impact.d.ts +13 -0
  94. package/dist/agents/cross-impact.d.ts.map +1 -0
  95. package/dist/agents/cross-impact.js +140 -0
  96. package/dist/agents/executor.d.ts +8 -0
  97. package/dist/agents/executor.d.ts.map +1 -0
  98. package/dist/agents/executor.js +75 -0
  99. package/dist/agents/explorer.d.ts +12 -0
  100. package/dist/agents/explorer.d.ts.map +1 -0
  101. package/dist/agents/explorer.js +43 -0
  102. package/dist/agents/generator.d.ts +8 -0
  103. package/dist/agents/generator.d.ts.map +1 -0
  104. package/dist/agents/generator.js +77 -0
  105. package/dist/agents/healer.d.ts +8 -0
  106. package/dist/agents/healer.d.ts.map +1 -0
  107. package/dist/agents/healer.js +31 -0
  108. package/dist/agents/impact-analyst.d.ts +8 -0
  109. package/dist/agents/impact-analyst.d.ts.map +1 -0
  110. package/dist/agents/impact-analyst.js +38 -0
  111. package/dist/agents/regression-advisor.d.ts +8 -0
  112. package/dist/agents/regression-advisor.d.ts.map +1 -0
  113. package/dist/agents/regression-advisor.js +116 -0
  114. package/dist/agents/strategist.d.ts +9 -0
  115. package/dist/agents/strategist.d.ts.map +1 -0
  116. package/dist/agents/strategist.js +92 -0
  117. package/dist/agents/test-designer.d.ts +8 -0
  118. package/dist/agents/test-designer.d.ts.map +1 -0
  119. package/dist/agents/test-designer.js +111 -0
  120. package/dist/anthropic_provider.d.ts +65 -0
  121. package/dist/anthropic_provider.d.ts.map +1 -0
  122. package/dist/anthropic_provider.js +334 -0
  123. package/dist/api.d.ts +48 -0
  124. package/dist/api.d.ts.map +1 -0
  125. package/dist/api.js +151 -0
  126. package/dist/base_provider.d.ts +109 -0
  127. package/dist/base_provider.d.ts.map +1 -0
  128. package/dist/base_provider.js +203 -0
  129. package/dist/budget_ledger.d.ts +28 -0
  130. package/dist/budget_ledger.d.ts.map +1 -0
  131. package/dist/budget_ledger.js +62 -0
  132. package/dist/cache/cached_provider.d.ts +49 -0
  133. package/dist/cache/cached_provider.d.ts.map +1 -0
  134. package/dist/cache/cached_provider.js +91 -0
  135. package/dist/cache/response_cache.d.ts +79 -0
  136. package/dist/cache/response_cache.d.ts.map +1 -0
  137. package/dist/cache/response_cache.js +177 -0
  138. package/dist/cli/commands/analyze.d.ts +3 -0
  139. package/dist/cli/commands/analyze.d.ts.map +1 -0
  140. package/dist/cli/commands/analyze.js +77 -0
  141. package/dist/cli/commands/bootstrap.d.ts +3 -0
  142. package/dist/cli/commands/bootstrap.d.ts.map +1 -0
  143. package/dist/cli/commands/bootstrap.js +109 -0
  144. package/dist/cli/commands/cost_report.d.ts +3 -0
  145. package/dist/cli/commands/cost_report.d.ts.map +1 -0
  146. package/dist/cli/commands/cost_report.js +115 -0
  147. package/dist/cli/commands/crew.d.ts +3 -0
  148. package/dist/cli/commands/crew.d.ts.map +1 -0
  149. package/dist/cli/commands/crew.js +255 -0
  150. package/dist/cli/commands/feedback.d.ts +3 -0
  151. package/dist/cli/commands/feedback.d.ts.map +1 -0
  152. package/dist/cli/commands/feedback.js +39 -0
  153. package/dist/cli/commands/finalize.d.ts +3 -0
  154. package/dist/cli/commands/finalize.d.ts.map +1 -0
  155. package/dist/cli/commands/finalize.js +41 -0
  156. package/dist/cli/commands/gate.d.ts +3 -0
  157. package/dist/cli/commands/gate.d.ts.map +1 -0
  158. package/dist/cli/commands/gate.js +89 -0
  159. package/dist/cli/commands/generate.d.ts +4 -0
  160. package/dist/cli/commands/generate.d.ts.map +1 -0
  161. package/dist/cli/commands/generate.js +108 -0
  162. package/dist/cli/commands/heal.d.ts +3 -0
  163. package/dist/cli/commands/heal.d.ts.map +1 -0
  164. package/dist/cli/commands/heal.js +60 -0
  165. package/dist/cli/commands/impact.d.ts +4 -0
  166. package/dist/cli/commands/impact.d.ts.map +1 -0
  167. package/dist/cli/commands/impact.js +33 -0
  168. package/dist/cli/commands/init.d.ts +2 -0
  169. package/dist/cli/commands/init.d.ts.map +1 -0
  170. package/dist/cli/commands/init.js +169 -0
  171. package/dist/cli/commands/llm_health.d.ts +2 -0
  172. package/dist/cli/commands/llm_health.d.ts.map +1 -0
  173. package/dist/cli/commands/llm_health.js +22 -0
  174. package/dist/cli/commands/plan.d.ts +4 -0
  175. package/dist/cli/commands/plan.d.ts.map +1 -0
  176. package/dist/cli/commands/plan.js +120 -0
  177. package/dist/cli/commands/plan_crew.d.ts +17 -0
  178. package/dist/cli/commands/plan_crew.d.ts.map +1 -0
  179. package/dist/cli/commands/plan_crew.js +316 -0
  180. package/dist/cli/commands/traceability.d.ts +4 -0
  181. package/dist/cli/commands/traceability.d.ts.map +1 -0
  182. package/dist/cli/commands/traceability.js +77 -0
  183. package/dist/cli/commands/train.d.ts +3 -0
  184. package/dist/cli/commands/train.d.ts.map +1 -0
  185. package/dist/cli/commands/train.js +391 -0
  186. package/dist/cli/defaults.d.ts +35 -0
  187. package/dist/cli/defaults.d.ts.map +1 -0
  188. package/dist/cli/defaults.js +172 -0
  189. package/dist/cli/errors.d.ts +27 -0
  190. package/dist/cli/errors.d.ts.map +1 -0
  191. package/dist/cli/errors.js +57 -0
  192. package/dist/cli/parse_args.d.ts +6 -0
  193. package/dist/cli/parse_args.d.ts.map +1 -0
  194. package/dist/cli/parse_args.js +257 -0
  195. package/dist/cli/types.d.ts +87 -0
  196. package/dist/cli/types.d.ts.map +1 -0
  197. package/dist/cli/types.js +4 -0
  198. package/dist/cli/usage.d.ts +2 -0
  199. package/dist/cli/usage.d.ts.map +1 -0
  200. package/dist/cli/usage.js +109 -0
  201. package/dist/cli.d.ts +3 -0
  202. package/dist/cli.d.ts.map +1 -0
  203. package/dist/cli.js +194 -0
  204. package/dist/crew/context.d.ts +55 -0
  205. package/dist/crew/context.d.ts.map +1 -0
  206. package/dist/crew/context.js +36 -0
  207. package/dist/crew/orchestrator.d.ts +50 -0
  208. package/dist/crew/orchestrator.d.ts.map +1 -0
  209. package/dist/crew/orchestrator.js +329 -0
  210. package/dist/crew/protocol.d.ts +46 -0
  211. package/dist/crew/protocol.d.ts.map +1 -0
  212. package/dist/crew/protocol.js +4 -0
  213. package/dist/crew/provider.d.ts +17 -0
  214. package/dist/crew/provider.d.ts.map +1 -0
  215. package/dist/crew/provider.js +36 -0
  216. package/dist/crew/sanitize.d.ts +3 -0
  217. package/dist/crew/sanitize.d.ts.map +1 -0
  218. package/dist/crew/sanitize.js +31 -0
  219. package/dist/crew/types.d.ts +52 -0
  220. package/dist/crew/types.d.ts.map +1 -0
  221. package/dist/crew/types.js +4 -0
  222. package/dist/crew/workflows.d.ts +52 -0
  223. package/dist/crew/workflows.d.ts.map +1 -0
  224. package/dist/crew/workflows.js +36 -0
  225. package/dist/custom_provider.d.ts +20 -0
  226. package/dist/custom_provider.d.ts.map +1 -0
  227. package/dist/custom_provider.js +277 -0
  228. package/dist/engine/ai_enrichment.d.ts +44 -0
  229. package/dist/engine/ai_enrichment.d.ts.map +1 -0
  230. package/dist/engine/ai_enrichment.js +267 -0
  231. package/dist/engine/diff_loader.d.ts +11 -0
  232. package/dist/engine/diff_loader.d.ts.map +1 -0
  233. package/dist/engine/diff_loader.js +63 -0
  234. package/dist/engine/impact_engine.d.ts +72 -0
  235. package/dist/engine/impact_engine.d.ts.map +1 -0
  236. package/dist/engine/impact_engine.js +298 -0
  237. package/dist/engine/plan_builder.d.ts +11 -0
  238. package/dist/engine/plan_builder.d.ts.map +1 -0
  239. package/dist/engine/plan_builder.js +599 -0
  240. package/dist/esm/adapters/cypress.js +49 -0
  241. package/dist/esm/adapters/framework_adapter.js +114 -0
  242. package/dist/esm/adapters/playwright.js +49 -0
  243. package/dist/esm/adapters/pytest.js +59 -0
  244. package/dist/esm/adapters/supertest.js +48 -0
  245. package/dist/esm/agent/api_catalog.js +199 -0
  246. package/dist/esm/agent/config.js +872 -0
  247. package/dist/esm/agent/feedback.js +317 -0
  248. package/dist/esm/agent/git.js +252 -0
  249. package/dist/esm/agent/handoff.js +177 -0
  250. package/dist/esm/agent/llm_agents_flow.js +421 -0
  251. package/dist/esm/agent/native_flow.js +175 -0
  252. package/dist/esm/agent/pipeline.js +256 -0
  253. package/dist/esm/agent/pipeline_types.js +3 -0
  254. package/dist/esm/agent/pipeline_utils.js +146 -0
  255. package/dist/esm/agent/plan.js +83 -0
  256. package/dist/esm/agent/playwright_report.js +123 -0
  257. package/dist/esm/agent/process_runner.js +83 -0
  258. package/dist/esm/agent/spec_generator.js +249 -0
  259. package/dist/esm/agent/test_path.js +20 -0
  260. package/dist/esm/agent/traceability_capture.js +310 -0
  261. package/dist/esm/agent/traceability_ingest.js +234 -0
  262. package/dist/esm/agent/types.js +3 -0
  263. package/dist/esm/agent/utils.js +138 -0
  264. package/dist/esm/agent/validation_runner.js +73 -0
  265. package/dist/esm/agentic/fix_loop.js +91 -0
  266. package/dist/esm/agentic/playwright_runner.js +161 -0
  267. package/dist/esm/agentic/runner.js +207 -0
  268. package/dist/esm/agentic/types.js +3 -0
  269. package/dist/esm/agents/coverage-evaluator.js +37 -0
  270. package/dist/esm/agents/cross-impact.js +136 -0
  271. package/dist/esm/agents/executor.js +71 -0
  272. package/dist/esm/agents/explorer.js +39 -0
  273. package/dist/esm/agents/generator.js +73 -0
  274. package/dist/esm/agents/healer.js +27 -0
  275. package/dist/esm/agents/impact-analyst.js +34 -0
  276. package/dist/esm/agents/regression-advisor.js +112 -0
  277. package/dist/esm/agents/strategist.js +88 -0
  278. package/dist/esm/agents/test-designer.js +107 -0
  279. package/dist/esm/anthropic_provider.js +326 -0
  280. package/dist/esm/api.js +143 -0
  281. package/dist/esm/base_provider.js +198 -0
  282. package/dist/esm/budget_ledger.js +58 -0
  283. package/dist/esm/cache/cached_provider.js +85 -0
  284. package/dist/esm/cache/response_cache.js +140 -0
  285. package/dist/esm/cli/commands/analyze.js +74 -0
  286. package/dist/esm/cli/commands/bootstrap.js +106 -0
  287. package/dist/esm/cli/commands/cost_report.js +112 -0
  288. package/dist/esm/cli/commands/crew.js +252 -0
  289. package/dist/esm/cli/commands/feedback.js +36 -0
  290. package/dist/esm/cli/commands/finalize.js +38 -0
  291. package/dist/esm/cli/commands/gate.js +86 -0
  292. package/dist/esm/cli/commands/generate.js +105 -0
  293. package/dist/esm/cli/commands/heal.js +57 -0
  294. package/dist/esm/cli/commands/impact.js +30 -0
  295. package/dist/esm/cli/commands/init.js +133 -0
  296. package/dist/esm/cli/commands/llm_health.js +19 -0
  297. package/dist/esm/cli/commands/plan.js +117 -0
  298. package/dist/esm/cli/commands/plan_crew.js +309 -0
  299. package/dist/esm/cli/commands/traceability.js +73 -0
  300. package/dist/esm/cli/commands/train.js +355 -0
  301. package/dist/esm/cli/defaults.js +165 -0
  302. package/dist/esm/cli/errors.js +52 -0
  303. package/dist/esm/cli/parse_args.js +251 -0
  304. package/dist/esm/cli/types.js +3 -0
  305. package/dist/esm/cli/usage.js +106 -0
  306. package/dist/esm/cli.js +192 -0
  307. package/dist/esm/crew/context.js +32 -0
  308. package/dist/esm/crew/orchestrator.js +325 -0
  309. package/dist/esm/crew/protocol.js +3 -0
  310. package/dist/esm/crew/provider.js +33 -0
  311. package/dist/esm/crew/sanitize.js +27 -0
  312. package/dist/esm/crew/types.js +3 -0
  313. package/dist/esm/crew/workflows.js +33 -0
  314. package/dist/esm/custom_provider.js +273 -0
  315. package/dist/esm/engine/ai_enrichment.js +264 -0
  316. package/dist/esm/engine/diff_loader.js +59 -0
  317. package/dist/esm/engine/impact_engine.js +291 -0
  318. package/dist/esm/engine/plan_builder.js +593 -0
  319. package/dist/esm/index.js +72 -0
  320. package/dist/esm/knowledge/api_surface.js +408 -0
  321. package/dist/esm/knowledge/cluster_utils.js +60 -0
  322. package/dist/esm/knowledge/context_loader.js +85 -0
  323. package/dist/esm/knowledge/failure_history.js +121 -0
  324. package/dist/esm/knowledge/kg_bridge.js +381 -0
  325. package/dist/esm/knowledge/kg_types.js +3 -0
  326. package/dist/esm/knowledge/route_families.js +393 -0
  327. package/dist/esm/knowledge/spec_index.js +122 -0
  328. package/dist/esm/logger.js +115 -0
  329. package/dist/esm/mcp-server.js +621 -0
  330. package/dist/esm/metrics/prometheus.js +149 -0
  331. package/dist/esm/model_router.js +59 -0
  332. package/dist/esm/ollama_provider.js +301 -0
  333. package/dist/esm/openai_provider.js +243 -0
  334. package/dist/esm/package.json +3 -0
  335. package/dist/esm/pipeline/orchestrator.js +228 -0
  336. package/dist/esm/pipeline/spec_verifier.js +75 -0
  337. package/dist/esm/pipeline/stage0_preprocess.js +102 -0
  338. package/dist/esm/pipeline/stage1_impact.js +140 -0
  339. package/dist/esm/pipeline/stage2_coverage.js +153 -0
  340. package/dist/esm/pipeline/stage3_generation.js +284 -0
  341. package/dist/esm/pipeline/stage4_heal.js +288 -0
  342. package/dist/esm/progress.js +112 -0
  343. package/dist/esm/prompts/coverage.js +57 -0
  344. package/dist/esm/prompts/cross-impact.js +53 -0
  345. package/dist/esm/prompts/generation.js +297 -0
  346. package/dist/esm/prompts/generation_profile.js +147 -0
  347. package/dist/esm/prompts/heal.js +91 -0
  348. package/dist/esm/prompts/impact.js +63 -0
  349. package/dist/esm/prompts/json_extract.js +36 -0
  350. package/dist/esm/prompts/strategist.js +61 -0
  351. package/dist/esm/prompts/test-designer.js +92 -0
  352. package/dist/esm/provider_factory.js +366 -0
  353. package/dist/esm/provider_interface.js +23 -0
  354. package/dist/esm/provider_utils.js +96 -0
  355. package/dist/esm/qa-agent/cli.js +205 -0
  356. package/dist/esm/qa-agent/orchestrator.js +120 -0
  357. package/dist/esm/qa-agent/phase1/runner.js +139 -0
  358. package/dist/esm/qa-agent/phase1/scope.js +126 -0
  359. package/dist/esm/qa-agent/phase2/agent_browser.js +95 -0
  360. package/dist/esm/qa-agent/phase2/agent_loop.js +351 -0
  361. package/dist/esm/qa-agent/phase2/exploration_state.js +97 -0
  362. package/dist/esm/qa-agent/phase2/tools.js +386 -0
  363. package/dist/esm/qa-agent/phase2/vision.js +75 -0
  364. package/dist/esm/qa-agent/phase3/feedback.js +34 -0
  365. package/dist/esm/qa-agent/phase3/reporter.js +145 -0
  366. package/dist/esm/qa-agent/phase3/spec_generator.js +62 -0
  367. package/dist/esm/qa-agent/phase3/verdict.js +66 -0
  368. package/dist/esm/qa-agent/safe_env.js +23 -0
  369. package/dist/esm/qa-agent/types.js +3 -0
  370. package/dist/esm/reporters/junit.js +86 -0
  371. package/dist/esm/reporters/reporter.js +3 -0
  372. package/dist/esm/reporters/sarif.js +132 -0
  373. package/dist/esm/resilience/circuit_breaker.js +78 -0
  374. package/dist/esm/resilience/retry.js +56 -0
  375. package/dist/esm/sanitize.js +66 -0
  376. package/dist/esm/training/enricher.js +345 -0
  377. package/dist/esm/training/kg_scanner.js +115 -0
  378. package/dist/esm/training/merger.js +204 -0
  379. package/dist/esm/training/scanner.js +923 -0
  380. package/dist/esm/training/types.js +6 -0
  381. package/dist/esm/training/validator.js +254 -0
  382. package/dist/esm/validation/guardrails.js +101 -0
  383. package/dist/esm/validation/output_schema.js +80 -0
  384. package/dist/esm/version.js +33 -0
  385. package/dist/index.d.ts +99 -0
  386. package/dist/index.d.ts.map +1 -0
  387. package/dist/index.js +169 -0
  388. package/dist/knowledge/api_surface.d.ts +37 -0
  389. package/dist/knowledge/api_surface.d.ts.map +1 -0
  390. package/dist/knowledge/api_surface.js +418 -0
  391. package/dist/knowledge/cluster_utils.d.ts +28 -0
  392. package/dist/knowledge/cluster_utils.d.ts.map +1 -0
  393. package/dist/knowledge/cluster_utils.js +67 -0
  394. package/dist/knowledge/context_loader.d.ts +13 -0
  395. package/dist/knowledge/context_loader.d.ts.map +1 -0
  396. package/dist/knowledge/context_loader.js +90 -0
  397. package/dist/knowledge/failure_history.d.ts +39 -0
  398. package/dist/knowledge/failure_history.d.ts.map +1 -0
  399. package/dist/knowledge/failure_history.js +128 -0
  400. package/dist/knowledge/kg_bridge.d.ts +31 -0
  401. package/dist/knowledge/kg_bridge.d.ts.map +1 -0
  402. package/dist/knowledge/kg_bridge.js +388 -0
  403. package/dist/knowledge/kg_types.d.ts +75 -0
  404. package/dist/knowledge/kg_types.d.ts.map +1 -0
  405. package/dist/knowledge/kg_types.js +4 -0
  406. package/dist/knowledge/route_families.d.ts +98 -0
  407. package/dist/knowledge/route_families.d.ts.map +1 -0
  408. package/dist/knowledge/route_families.js +410 -0
  409. package/dist/knowledge/spec_index.d.ts +18 -0
  410. package/dist/knowledge/spec_index.d.ts.map +1 -0
  411. package/dist/knowledge/spec_index.js +128 -0
  412. package/dist/logger.d.ts +31 -0
  413. package/dist/logger.d.ts.map +1 -0
  414. package/dist/logger.js +119 -0
  415. package/dist/mcp-server.d.ts +68 -0
  416. package/dist/mcp-server.d.ts.map +1 -0
  417. package/dist/mcp-server.js +629 -0
  418. package/dist/metrics/prometheus.d.ts +37 -0
  419. package/dist/metrics/prometheus.d.ts.map +1 -0
  420. package/dist/metrics/prometheus.js +153 -0
  421. package/dist/model_router.d.ts +28 -0
  422. package/dist/model_router.d.ts.map +1 -0
  423. package/dist/model_router.js +63 -0
  424. package/dist/ollama_provider.d.ts +65 -0
  425. package/dist/ollama_provider.d.ts.map +1 -0
  426. package/dist/ollama_provider.js +309 -0
  427. package/dist/openai_provider.d.ts +23 -0
  428. package/dist/openai_provider.d.ts.map +1 -0
  429. package/dist/openai_provider.js +251 -0
  430. package/dist/pipeline/orchestrator.d.ts +33 -0
  431. package/dist/pipeline/orchestrator.d.ts.map +1 -0
  432. package/dist/pipeline/orchestrator.js +231 -0
  433. package/dist/pipeline/spec_verifier.d.ts +20 -0
  434. package/dist/pipeline/spec_verifier.d.ts.map +1 -0
  435. package/dist/pipeline/spec_verifier.js +79 -0
  436. package/dist/pipeline/stage0_preprocess.d.ts +31 -0
  437. package/dist/pipeline/stage0_preprocess.d.ts.map +1 -0
  438. package/dist/pipeline/stage0_preprocess.js +105 -0
  439. package/dist/pipeline/stage1_impact.d.ts +19 -0
  440. package/dist/pipeline/stage1_impact.d.ts.map +1 -0
  441. package/dist/pipeline/stage1_impact.js +143 -0
  442. package/dist/pipeline/stage2_coverage.d.ts +19 -0
  443. package/dist/pipeline/stage2_coverage.d.ts.map +1 -0
  444. package/dist/pipeline/stage2_coverage.js +156 -0
  445. package/dist/pipeline/stage3_generation.d.ts +43 -0
  446. package/dist/pipeline/stage3_generation.d.ts.map +1 -0
  447. package/dist/pipeline/stage3_generation.js +287 -0
  448. package/dist/pipeline/stage4_heal.d.ts +62 -0
  449. package/dist/pipeline/stage4_heal.d.ts.map +1 -0
  450. package/dist/pipeline/stage4_heal.js +294 -0
  451. package/dist/progress.d.ts +22 -0
  452. package/dist/progress.d.ts.map +1 -0
  453. package/dist/progress.js +116 -0
  454. package/dist/prompts/coverage.d.ts +39 -0
  455. package/dist/prompts/coverage.d.ts.map +1 -0
  456. package/dist/prompts/coverage.js +61 -0
  457. package/dist/prompts/cross-impact.d.ts +23 -0
  458. package/dist/prompts/cross-impact.d.ts.map +1 -0
  459. package/dist/prompts/cross-impact.js +57 -0
  460. package/dist/prompts/generation.d.ts +25 -0
  461. package/dist/prompts/generation.d.ts.map +1 -0
  462. package/dist/prompts/generation.js +302 -0
  463. package/dist/prompts/generation_profile.d.ts +29 -0
  464. package/dist/prompts/generation_profile.d.ts.map +1 -0
  465. package/dist/prompts/generation_profile.js +151 -0
  466. package/dist/prompts/heal.d.ts +23 -0
  467. package/dist/prompts/heal.d.ts.map +1 -0
  468. package/dist/prompts/heal.js +95 -0
  469. package/dist/prompts/impact.d.ts +31 -0
  470. package/dist/prompts/impact.d.ts.map +1 -0
  471. package/dist/prompts/impact.js +67 -0
  472. package/dist/prompts/json_extract.d.ts +14 -0
  473. package/dist/prompts/json_extract.d.ts.map +1 -0
  474. package/dist/prompts/json_extract.js +39 -0
  475. package/dist/prompts/strategist.d.ts +25 -0
  476. package/dist/prompts/strategist.d.ts.map +1 -0
  477. package/dist/prompts/strategist.js +65 -0
  478. package/dist/prompts/test-designer.d.ts +35 -0
  479. package/dist/prompts/test-designer.d.ts.map +1 -0
  480. package/dist/prompts/test-designer.js +96 -0
  481. package/dist/provider_factory.d.ts +104 -0
  482. package/dist/provider_factory.d.ts.map +1 -0
  483. package/dist/provider_factory.js +371 -0
  484. package/dist/provider_interface.d.ts +365 -0
  485. package/dist/provider_interface.d.ts.map +1 -0
  486. package/dist/provider_interface.js +28 -0
  487. package/dist/provider_utils.d.ts +39 -0
  488. package/dist/provider_utils.d.ts.map +1 -0
  489. package/dist/provider_utils.js +103 -0
  490. package/dist/qa-agent/cli.d.ts +3 -0
  491. package/dist/qa-agent/cli.d.ts.map +1 -0
  492. package/dist/qa-agent/cli.js +207 -0
  493. package/dist/qa-agent/orchestrator.d.ts +3 -0
  494. package/dist/qa-agent/orchestrator.d.ts.map +1 -0
  495. package/dist/qa-agent/orchestrator.js +123 -0
  496. package/dist/qa-agent/phase1/runner.d.ts +3 -0
  497. package/dist/qa-agent/phase1/runner.d.ts.map +1 -0
  498. package/dist/qa-agent/phase1/runner.js +142 -0
  499. package/dist/qa-agent/phase1/scope.d.ts +6 -0
  500. package/dist/qa-agent/phase1/scope.d.ts.map +1 -0
  501. package/dist/qa-agent/phase1/scope.js +129 -0
  502. package/dist/qa-agent/phase2/agent_browser.d.ts +35 -0
  503. package/dist/qa-agent/phase2/agent_browser.d.ts.map +1 -0
  504. package/dist/qa-agent/phase2/agent_browser.js +99 -0
  505. package/dist/qa-agent/phase2/agent_loop.d.ts +3 -0
  506. package/dist/qa-agent/phase2/agent_loop.d.ts.map +1 -0
  507. package/dist/qa-agent/phase2/agent_loop.js +357 -0
  508. package/dist/qa-agent/phase2/exploration_state.d.ts +12 -0
  509. package/dist/qa-agent/phase2/exploration_state.d.ts.map +1 -0
  510. package/dist/qa-agent/phase2/exploration_state.js +109 -0
  511. package/dist/qa-agent/phase2/tools.d.ts +28 -0
  512. package/dist/qa-agent/phase2/tools.d.ts.map +1 -0
  513. package/dist/qa-agent/phase2/tools.js +390 -0
  514. package/dist/qa-agent/phase2/vision.d.ts +3 -0
  515. package/dist/qa-agent/phase2/vision.d.ts.map +1 -0
  516. package/dist/qa-agent/phase2/vision.js +78 -0
  517. package/dist/qa-agent/phase3/feedback.d.ts +3 -0
  518. package/dist/qa-agent/phase3/feedback.d.ts.map +1 -0
  519. package/dist/qa-agent/phase3/feedback.js +37 -0
  520. package/dist/qa-agent/phase3/reporter.d.ts +3 -0
  521. package/dist/qa-agent/phase3/reporter.d.ts.map +1 -0
  522. package/dist/qa-agent/phase3/reporter.js +148 -0
  523. package/dist/qa-agent/phase3/spec_generator.d.ts +3 -0
  524. package/dist/qa-agent/phase3/spec_generator.d.ts.map +1 -0
  525. package/dist/qa-agent/phase3/spec_generator.js +65 -0
  526. package/dist/qa-agent/phase3/verdict.d.ts +3 -0
  527. package/dist/qa-agent/phase3/verdict.d.ts.map +1 -0
  528. package/dist/qa-agent/phase3/verdict.js +69 -0
  529. package/dist/qa-agent/safe_env.d.ts +3 -0
  530. package/dist/qa-agent/safe_env.d.ts.map +1 -0
  531. package/dist/qa-agent/safe_env.js +26 -0
  532. package/dist/qa-agent/types.d.ts +130 -0
  533. package/dist/qa-agent/types.d.ts.map +1 -0
  534. package/dist/qa-agent/types.js +4 -0
  535. package/dist/reporters/junit.d.ts +6 -0
  536. package/dist/reporters/junit.d.ts.map +1 -0
  537. package/dist/reporters/junit.js +89 -0
  538. package/dist/reporters/reporter.d.ts +42 -0
  539. package/dist/reporters/reporter.d.ts.map +1 -0
  540. package/dist/reporters/reporter.js +4 -0
  541. package/dist/reporters/sarif.d.ts +7 -0
  542. package/dist/reporters/sarif.d.ts.map +1 -0
  543. package/dist/reporters/sarif.js +135 -0
  544. package/dist/resilience/circuit_breaker.d.ts +36 -0
  545. package/dist/resilience/circuit_breaker.d.ts.map +1 -0
  546. package/dist/resilience/circuit_breaker.js +82 -0
  547. package/dist/resilience/retry.d.ts +11 -0
  548. package/dist/resilience/retry.d.ts.map +1 -0
  549. package/dist/resilience/retry.js +59 -0
  550. package/dist/sanitize.d.ts +15 -0
  551. package/dist/sanitize.d.ts.map +1 -0
  552. package/dist/sanitize.js +71 -0
  553. package/dist/training/enricher.d.ts +17 -0
  554. package/dist/training/enricher.d.ts.map +1 -0
  555. package/dist/training/enricher.js +350 -0
  556. package/dist/training/kg_scanner.d.ts +13 -0
  557. package/dist/training/kg_scanner.d.ts.map +1 -0
  558. package/dist/training/kg_scanner.js +118 -0
  559. package/dist/training/merger.d.ts +15 -0
  560. package/dist/training/merger.d.ts.map +1 -0
  561. package/dist/training/merger.js +208 -0
  562. package/dist/training/scanner.d.ts +36 -0
  563. package/dist/training/scanner.d.ts.map +1 -0
  564. package/dist/training/scanner.js +932 -0
  565. package/dist/training/types.d.ts +117 -0
  566. package/dist/training/types.d.ts.map +1 -0
  567. package/dist/training/types.js +9 -0
  568. package/dist/training/validator.d.ts +21 -0
  569. package/dist/training/validator.d.ts.map +1 -0
  570. package/dist/training/validator.js +262 -0
  571. package/dist/validation/guardrails.d.ts +31 -0
  572. package/dist/validation/guardrails.d.ts.map +1 -0
  573. package/dist/validation/guardrails.js +112 -0
  574. package/dist/validation/output_schema.d.ts +67 -0
  575. package/dist/validation/output_schema.d.ts.map +1 -0
  576. package/dist/validation/output_schema.js +84 -0
  577. package/dist/version.d.ts +6 -0
  578. package/dist/version.d.ts.map +1 -0
  579. package/dist/version.js +36 -0
  580. package/package.json +126 -0
  581. package/schemas/flow-decision.schema.json +83 -0
  582. package/schemas/gap.schema.json +18 -0
  583. package/schemas/impact.schema.json +455 -0
  584. package/schemas/plan.schema.json +491 -0
  585. package/schemas/route-families.schema.json +137 -0
  586. package/schemas/subsystem-risk-map.schema.json +62 -0
  587. package/schemas/traceability-input.schema.json +122 -0
@@ -0,0 +1,593 @@
1
+ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2
+ // See LICENSE.txt for license information.
3
+ import { mkdirSync, writeFileSync } from 'fs';
4
+ import { dirname, join } from 'path';
5
+ import { minimatch } from 'minimatch';
6
+ import { inferSubsystemFromTestPath } from '../agent/test_path.js';
7
+ import { getGaps, getGapsWithSuppressed, getPartialGaps } from './impact_engine.js';
8
+ import { bindFilesToFamilies, loadRouteFamilyManifest } from '../knowledge/route_families.js';
9
+ const DEFAULT_POLICY = {
10
+ minConfidenceForTargeted: 60,
11
+ safeMergeMinConfidence: 85,
12
+ forceFullOnWarningsAtOrAbove: 2,
13
+ forceFullOnP0WithGaps: true,
14
+ forceFullOnRiskyFiles: true,
15
+ riskyFilePatterns: [
16
+ '**/auth/**',
17
+ '**/login/**',
18
+ '**/permissions/**',
19
+ '**/admin/**',
20
+ '**/security/**',
21
+ '**/migrations/**',
22
+ '**/schema/**',
23
+ '**/*.sql',
24
+ '**/webhook/**',
25
+ ],
26
+ enforcementMode: 'advisory',
27
+ blockOnActions: ['must-add-tests'],
28
+ };
29
+ function featureLabel(f) {
30
+ return f.featureId || f.familyId;
31
+ }
32
+ function computeConfidence(impact) {
33
+ const gaps = getGaps(impact);
34
+ const totalFeatures = impact.impactedFeatures.length;
35
+ const boundRatio = totalFeatures > 0
36
+ ? (totalFeatures / (totalFeatures + impact.unboundFiles.length))
37
+ : 1;
38
+ // Graph-resolved bindings start at 100
39
+ let confidence = 100;
40
+ // Deduct for unbound files (not mapped to any family)
41
+ if (impact.unboundFiles.length > 0) {
42
+ const unboundPenalty = Math.min(30, impact.unboundFiles.length * 3);
43
+ confidence -= unboundPenalty;
44
+ }
45
+ // Deduct for gaps
46
+ confidence -= Math.min(20, gaps.length * 5);
47
+ // Deduct for warnings
48
+ confidence -= Math.min(15, impact.warnings.length * 5);
49
+ // Bonus for high bound ratio
50
+ if (boundRatio >= 0.9) {
51
+ confidence = Math.min(100, confidence + 5);
52
+ }
53
+ return Math.max(0, Math.min(100, confidence));
54
+ }
55
+ function findRiskyFiles(changedFiles, patterns) {
56
+ return [...new Set(changedFiles.filter((file) => patterns.some((pattern) => minimatch(file, pattern, { matchBase: true }))))];
57
+ }
58
+ function pickRunSet(impact, confidence, policy) {
59
+ const gaps = getGaps(impact);
60
+ const reasons = [];
61
+ const triggeredRules = [];
62
+ const riskyFiles = findRiskyFiles(impact.changedFiles, policy.riskyFilePatterns);
63
+ const hasP0 = impact.impactedFeatures.some((f) => f.priority === 'P0');
64
+ if (gaps.length > 0) {
65
+ reasons.push(`${gaps.length} uncovered P0/P1 feature(s) detected.`);
66
+ }
67
+ if (hasP0) {
68
+ reasons.push('P0 features are impacted by this change set.');
69
+ }
70
+ if (policy.forceFullOnRiskyFiles && riskyFiles.length > 0) {
71
+ triggeredRules.push('risky-files');
72
+ reasons.push(`Risky file patterns matched: ${riskyFiles.join(', ')}`);
73
+ }
74
+ if (confidence < policy.minConfidenceForTargeted) {
75
+ triggeredRules.push('low-confidence');
76
+ }
77
+ if (impact.warnings.length >= policy.forceFullOnWarningsAtOrAbove) {
78
+ triggeredRules.push('warning-threshold');
79
+ reasons.push('Warning threshold exceeded.');
80
+ }
81
+ if (policy.forceFullOnP0WithGaps && hasP0 && gaps.length > 0) {
82
+ triggeredRules.push('p0-with-gaps');
83
+ }
84
+ if (triggeredRules.length > 0) {
85
+ return {
86
+ runSet: 'full',
87
+ reasons: reasons.length > 0 ? reasons : ['Policy rules triggered full suite.'],
88
+ triggeredRules,
89
+ riskyFiles,
90
+ };
91
+ }
92
+ // If we have impacted features with specs, recommend targeted
93
+ const coveredFeatures = impact.impactedFeatures.filter((f) => f.coverageStatus !== 'uncovered');
94
+ if (coveredFeatures.length > 0) {
95
+ return {
96
+ runSet: 'targeted',
97
+ reasons: reasons.length > 0 ? reasons : ['Impacted features have test coverage.'],
98
+ triggeredRules,
99
+ riskyFiles,
100
+ };
101
+ }
102
+ return {
103
+ runSet: 'smoke',
104
+ reasons: reasons.length > 0 ? reasons : ['No targeted tests mapped from impacted features.'],
105
+ triggeredRules,
106
+ riskyFiles,
107
+ };
108
+ }
109
+ /**
110
+ * Check which gaps have matching PR-included E2E spec files by binding
111
+ * spec files to families via the manifest. Returns familyIds that are covered.
112
+ */
113
+ function matchPrSpecsToGaps(prTestFiles, gaps, testsRoot) {
114
+ const coveredFamilies = new Set();
115
+ const prE2ESpecs = prTestFiles.filter((t) => t.type === 'playwright' || t.type === 'cypress');
116
+ if (prE2ESpecs.length === 0 || !testsRoot) {
117
+ return coveredFamilies;
118
+ }
119
+ // Try to bind PR spec files to families via the manifest
120
+ const manifest = loadRouteFamilyManifest(testsRoot);
121
+ if (manifest) {
122
+ const specBindings = bindFilesToFamilies(prE2ESpecs.map((s) => s.file), manifest);
123
+ for (const sb of specBindings) {
124
+ for (const binding of sb.bindings) {
125
+ coveredFamilies.add(binding.family);
126
+ }
127
+ }
128
+ }
129
+ // Fallback heuristic: if manifest binding didn't match (common for Cypress specs
130
+ // in directories not mapped in the manifest), check path-based keyword overlap.
131
+ if (coveredFamilies.size === 0) {
132
+ const gapFamilyIds = new Set(gaps.map((g) => g.familyId));
133
+ for (const spec of prE2ESpecs) {
134
+ const specLower = spec.file.toLowerCase().replace(/[_\-/\\]/g, ' ');
135
+ for (const familyId of gapFamilyIds) {
136
+ // Check if the spec path contains the family name or related terms
137
+ if (specLower.includes(familyId.toLowerCase())) {
138
+ coveredFamilies.add(familyId);
139
+ }
140
+ }
141
+ }
142
+ }
143
+ return coveredFamilies;
144
+ }
145
+ function buildDecision(impact, runSet, confidence, policy) {
146
+ const gaps = getGapsWithSuppressed(impact).gaps;
147
+ if (gaps.length > 0) {
148
+ const prE2ESpecs = (impact.prIncludedTestFiles ?? [])
149
+ .filter((t) => t.type === 'playwright' || t.type === 'cypress');
150
+ if (prE2ESpecs.length > 0) {
151
+ // Bind PR specs to families — only soften gaps that have matching specs
152
+ const coveredFamilies = matchPrSpecsToGaps(impact.prIncludedTestFiles ?? [], gaps);
153
+ const uncoveredGaps = gaps.filter((g) => !coveredFamilies.has(g.familyId));
154
+ if (uncoveredGaps.length === 0) {
155
+ // ALL gaps have matching PR specs
156
+ return {
157
+ action: 'run-now',
158
+ title: 'Run now',
159
+ summary: `Detected ${gaps.length} coverage gap(s), but the PR includes ${prE2ESpecs.length} E2E test file(s) covering them. Verify the new tests cover impacted flows.`,
160
+ };
161
+ }
162
+ if (uncoveredGaps.length < gaps.length) {
163
+ // SOME gaps covered by PR specs, others not
164
+ return {
165
+ action: 'must-add-tests',
166
+ title: 'Must add tests',
167
+ summary: `Detected ${gaps.length} coverage gap(s). PR includes E2E tests for ${gaps.length - uncoveredGaps.length}, but ${uncoveredGaps.length} flow(s) still need coverage.`,
168
+ };
169
+ }
170
+ // No gaps matched by PR specs — but PR still has E2E files.
171
+ // Soften to run-now since the developer is actively writing tests.
172
+ return {
173
+ action: 'run-now',
174
+ title: 'Run now',
175
+ summary: `Detected ${gaps.length} coverage gap(s), but the PR includes ${prE2ESpecs.length} E2E test file(s). Verify the new tests cover impacted flows.`,
176
+ };
177
+ }
178
+ return {
179
+ action: 'must-add-tests',
180
+ title: 'Must add tests',
181
+ summary: `Detected ${gaps.length} uncovered P0/P1 feature(s). Add or update tests before merge.`,
182
+ };
183
+ }
184
+ if (impact.changedFiles.length === 0 && impact.impactedFeatures.length === 0) {
185
+ return {
186
+ action: 'safe-to-merge',
187
+ title: 'Safe to merge',
188
+ summary: 'No app file changes detected — no E2E coverage required for this change set.',
189
+ };
190
+ }
191
+ if (runSet === 'smoke' && confidence >= policy.safeMergeMinConfidence && impact.warnings.length === 0) {
192
+ return {
193
+ action: 'safe-to-merge',
194
+ title: 'Safe to merge',
195
+ summary: 'No critical coverage gaps were detected and confidence is high.',
196
+ };
197
+ }
198
+ const coveredCount = impact.impactedFeatures.filter((f) => f.coverageStatus !== 'uncovered').length;
199
+ const coveredSuffix = coveredCount > 0
200
+ ? ` All ${coveredCount} impacted feature(s) have test coverage.`
201
+ : '';
202
+ // When files changed but no flows were mapped, be transparent about the gap
203
+ if (impact.impactedFeatures.length === 0 && impact.changedFiles.length > 0) {
204
+ const unboundNote = impact.unboundFiles.length > 0
205
+ ? ` ${impact.unboundFiles.length} file(s) could not be mapped to any known flow — consider adding route-families bindings.`
206
+ : '';
207
+ return {
208
+ action: 'run-now',
209
+ title: 'Run now',
210
+ summary: `Changed files could not be mapped to E2E flows — manual review recommended.${unboundNote} Verify with the E2E suite before merge.`,
211
+ };
212
+ }
213
+ return {
214
+ action: 'run-now',
215
+ title: 'Run now',
216
+ summary: `Impacted features are covered by existing tests.${coveredSuffix} Verify with the E2E suite before merge.`,
217
+ };
218
+ }
219
+ function evaluateEnforcement(decision, policy) {
220
+ const blockOnActions = (policy.blockOnActions && policy.blockOnActions.length > 0)
221
+ ? [...policy.blockOnActions]
222
+ : ['must-add-tests'];
223
+ const matchedAction = blockOnActions.includes(decision.action);
224
+ if (policy.enforcementMode === 'block' && matchedAction) {
225
+ return {
226
+ mode: policy.enforcementMode,
227
+ blockOnActions,
228
+ matchedAction,
229
+ shouldFail: true,
230
+ summary: `Blocking mode active: decision "${decision.action}" is configured to fail CI.`,
231
+ };
232
+ }
233
+ if (policy.enforcementMode === 'warn' && matchedAction) {
234
+ return {
235
+ mode: policy.enforcementMode,
236
+ blockOnActions,
237
+ matchedAction,
238
+ shouldFail: false,
239
+ summary: `Warning mode active: decision "${decision.action}" is advisory-only for CI.`,
240
+ };
241
+ }
242
+ if (policy.enforcementMode === 'block') {
243
+ return {
244
+ mode: policy.enforcementMode,
245
+ blockOnActions,
246
+ matchedAction,
247
+ shouldFail: false,
248
+ summary: `Blocking mode active, but decision "${decision.action}" is not configured for CI failure.`,
249
+ };
250
+ }
251
+ return {
252
+ mode: policy.enforcementMode,
253
+ blockOnActions,
254
+ matchedAction,
255
+ shouldFail: false,
256
+ summary: 'Advisory mode active: recommendations do not fail CI by default.',
257
+ };
258
+ }
259
+ /**
260
+ * Build recommended test list from impacted features' Playwright specs.
261
+ * When alwaysIncludeSubsystems is provided, specs from those subsystems are
262
+ * included regardless of their coverage status (blind-spot protection).
263
+ */
264
+ function buildRecommendedTests(impact, alwaysIncludeSubsystems = []) {
265
+ const tests = new Set();
266
+ const alwaysSet = new Set(alwaysIncludeSubsystems);
267
+ for (const feature of impact.impactedFeatures) {
268
+ const shouldInclude = feature.coverageStatus !== 'uncovered' ||
269
+ feature.playwrightSpecs.some((spec) => alwaysSet.has(inferSubsystemFromTestPath(spec)));
270
+ if (shouldInclude) {
271
+ for (const spec of feature.playwrightSpecs) {
272
+ tests.add(spec);
273
+ }
274
+ }
275
+ }
276
+ return [...tests];
277
+ }
278
+ export function buildPlanFromImpact(impact, policyOverride, aiEnrichment, adaptiveThresholds) {
279
+ const policy = { ...DEFAULT_POLICY, ...(policyOverride || {}) };
280
+ // Apply adaptive calibration overrides (if available and not explicitly overridden)
281
+ if (adaptiveThresholds && policyOverride?.minConfidenceForTargeted === undefined) {
282
+ policy.minConfidenceForTargeted = adaptiveThresholds.minConfidenceForTargeted;
283
+ }
284
+ if (adaptiveThresholds && policyOverride?.safeMergeMinConfidence === undefined) {
285
+ policy.safeMergeMinConfidence = adaptiveThresholds.safeMergeMinConfidence;
286
+ }
287
+ // Apply alwaysIncludeSubsystems: force their tests into the recommended set
288
+ const alwaysIncludeSubsystems = adaptiveThresholds?.alwaysIncludeSubsystems ?? [];
289
+ const confidence = computeConfidence(impact);
290
+ const runSetResult = pickRunSet(impact, confidence, policy);
291
+ const decision = buildDecision(impact, runSetResult.runSet, confidence, policy);
292
+ const enforcement = evaluateEnforcement(decision, policy);
293
+ const { gaps, suppressedGaps } = getGapsWithSuppressed(impact);
294
+ const partialGaps = getPartialGaps(impact);
295
+ // Build two separate lookup maps from aiEnrichment: one by featureId, one by familyId.
296
+ // The familyId map stores only the FIRST feature encountered to avoid last-write-wins collisions.
297
+ const aiFeatureByFeatureId = new Map();
298
+ const aiFeatureByFamilyId = new Map();
299
+ if (aiEnrichment) {
300
+ for (const ef of aiEnrichment.enrichedFeatures) {
301
+ if (ef.featureId) {
302
+ aiFeatureByFeatureId.set(ef.featureId, ef);
303
+ }
304
+ if (ef.familyId && !aiFeatureByFamilyId.has(ef.familyId)) {
305
+ aiFeatureByFamilyId.set(ef.familyId, ef);
306
+ }
307
+ }
308
+ }
309
+ const gapDetails = gaps.map((f) => {
310
+ const label = featureLabel(f);
311
+ const aiFeature = f.featureId
312
+ ? (aiFeatureByFeatureId.get(f.featureId) ?? aiFeatureByFamilyId.get(f.familyId))
313
+ : aiFeatureByFamilyId.get(f.familyId);
314
+ const baseReasons = [`No E2E tests found for ${label}`];
315
+ let aiReasonsList = [];
316
+ if (aiFeature) {
317
+ if (aiFeature.aiReasons.length > 0) {
318
+ aiReasonsList = aiFeature.aiReasons.slice(0, 2);
319
+ }
320
+ else {
321
+ // Fallback: LLM returned scenarios but no reasons — synthesize a description
322
+ const fileHint = f.changedFiles.slice(0, 3).map((p) => p.split('/').pop()).join(', ');
323
+ aiReasonsList = [`Changes to ${fileHint} affect the ${label} feature, which currently lacks E2E coverage.`];
324
+ }
325
+ }
326
+ const reasons = aiReasonsList.length > 0
327
+ ? [...baseReasons, ...aiReasonsList]
328
+ : baseReasons;
329
+ const missingScenarios = aiFeature && aiFeature.aiMissingScenarios.length > 0
330
+ ? aiFeature.aiMissingScenarios
331
+ : (f.userFlows.length > 0 ? f.userFlows.slice(0, 5) : undefined);
332
+ return {
333
+ id: label,
334
+ name: label,
335
+ priority: f.priority,
336
+ reasons,
337
+ files: f.changedFiles.slice(0, 6),
338
+ missingScenarios,
339
+ source: aiFeature ? 'ai+deterministic' : 'deterministic',
340
+ };
341
+ });
342
+ // Add partial gaps as advisory info (Cypress-only coverage — Playwright migration recommended)
343
+ for (const f of partialGaps) {
344
+ const label = featureLabel(f);
345
+ const aiFeature = f.featureId
346
+ ? (aiFeatureByFeatureId.get(f.featureId) ?? aiFeatureByFamilyId.get(f.familyId))
347
+ : aiFeatureByFamilyId.get(f.familyId);
348
+ const baseReasons = [`${label} is covered by Cypress only — consider adding Playwright tests`];
349
+ let partialAiReasons = [];
350
+ if (aiFeature) {
351
+ if (aiFeature.aiReasons.length > 0) {
352
+ partialAiReasons = aiFeature.aiReasons.slice(0, 2);
353
+ }
354
+ else {
355
+ const fileHint = f.changedFiles.slice(0, 3).map((p) => p.split('/').pop()).join(', ');
356
+ partialAiReasons = [`Changes to ${fileHint} affect the ${label} feature, which has Cypress but no Playwright coverage.`];
357
+ }
358
+ }
359
+ const reasons = partialAiReasons.length > 0
360
+ ? [...baseReasons, ...partialAiReasons]
361
+ : baseReasons;
362
+ gapDetails.push({
363
+ id: label,
364
+ name: `${label} (partial)`,
365
+ priority: f.priority,
366
+ reasons,
367
+ files: f.changedFiles.slice(0, 6),
368
+ source: aiFeature ? 'ai+deterministic' : 'deterministic',
369
+ });
370
+ }
371
+ const coveredFlows = impact.impactedFeatures
372
+ .filter((f) => f.coverageStatus === 'covered')
373
+ .map((f) => {
374
+ const aiFeature = f.featureId
375
+ ? (aiFeatureByFeatureId.get(f.featureId) ?? aiFeatureByFamilyId.get(f.familyId))
376
+ : aiFeatureByFamilyId.get(f.familyId);
377
+ // Only surface advisory scenarios when AI found new behavior in this diff
378
+ let advisoryScenarios = aiFeature?.aiMissingScenarios?.length
379
+ ? [...aiFeature.aiMissingScenarios]
380
+ : undefined;
381
+ // Promote suppressed gaps to advisory on covered flows that share changed files.
382
+ // When a family-level gap is suppressed (e.g. "post" because post.go is also in
383
+ // a covered feature like "channels/threads"), the behavioral change should appear
384
+ // here as "new behavior detected" instead of vanishing.
385
+ for (const sg of suppressedGaps) {
386
+ const sharedFiles = sg.changedFiles.filter((file) => f.changedFiles.includes(file));
387
+ if (sharedFiles.length > 0) {
388
+ const sgAi = sg.featureId
389
+ ? (aiFeatureByFeatureId.get(sg.featureId) ?? aiFeatureByFamilyId.get(sg.familyId))
390
+ : aiFeatureByFamilyId.get(sg.familyId);
391
+ const sgScenarios = sgAi?.aiMissingScenarios?.length
392
+ ? sgAi.aiMissingScenarios
393
+ : sg.userFlows.slice(0, 3);
394
+ if (sgScenarios.length > 0) {
395
+ advisoryScenarios = [...(advisoryScenarios || []), ...sgScenarios];
396
+ }
397
+ }
398
+ }
399
+ return {
400
+ id: featureLabel(f),
401
+ name: featureLabel(f),
402
+ priority: f.priority,
403
+ coveredBy: [
404
+ ...(f.playwrightSpecs.length > 0 ? [`${f.playwrightSpecs.length} Playwright spec(s)`] : []),
405
+ ...(f.cypressSpecs.length > 0 ? [`${f.cypressSpecs.length} Cypress spec(s)`] : []),
406
+ ].slice(0, 3),
407
+ advisoryScenarios,
408
+ };
409
+ });
410
+ const recommendedTests = buildRecommendedTests(impact, alwaysIncludeSubsystems);
411
+ const requiredNewTests = gaps.map((f) => `${featureLabel(f)}: Add E2E tests`);
412
+ const p0 = impact.impactedFeatures.filter((f) => f.priority === 'P0').length;
413
+ const p1 = impact.impactedFeatures.filter((f) => f.priority === 'P1').length;
414
+ const p2 = impact.impactedFeatures.filter((f) => f.priority === 'P2').length;
415
+ const coveredCount = impact.impactedFeatures.filter((f) => f.coverageStatus === 'covered').length;
416
+ const partialCount = impact.impactedFeatures.filter((f) => f.coverageStatus === 'partial').length;
417
+ const runId = `plan-${Date.now().toString(36)}`;
418
+ const planSource = aiEnrichment ? 'ai+deterministic' : 'impact';
419
+ return {
420
+ schemaVersion: '1.0.0',
421
+ runId,
422
+ generatedAt: new Date().toISOString(),
423
+ source: planSource,
424
+ runSet: runSetResult.runSet,
425
+ confidence,
426
+ reasons: runSetResult.reasons,
427
+ recommendedTests,
428
+ requiredNewTests,
429
+ gapDetails,
430
+ coveredFlows,
431
+ policy: {
432
+ riskyFiles: runSetResult.riskyFiles,
433
+ triggeredRules: runSetResult.triggeredRules,
434
+ applied: policy,
435
+ },
436
+ decision,
437
+ enforcement,
438
+ metrics: {
439
+ changedFiles: impact.changedFiles.length,
440
+ impactedFlows: impact.impactedFeatures.length,
441
+ p0Flows: p0,
442
+ p1Flows: p1,
443
+ p2Flows: p2,
444
+ coveredFlows: coveredCount,
445
+ partialFlows: partialCount,
446
+ uncoveredP0P1Flows: gaps.length,
447
+ unboundFiles: impact.unboundFiles.length,
448
+ warnings: impact.warnings.length,
449
+ },
450
+ };
451
+ }
452
+ export function writePlanReport(appRoot, plan) {
453
+ const baseDir = join(appRoot, '.e2e-ai-agents');
454
+ mkdirSync(baseDir, { recursive: true });
455
+ const planPath = join(baseDir, 'plan.json');
456
+ writeFileSync(planPath, JSON.stringify(plan, null, 2), 'utf-8');
457
+ return planPath;
458
+ }
459
+ export function renderCiSummaryMarkdown(plan) {
460
+ const lines = [];
461
+ const { uncoveredP0P1Flows, changedFiles, impactedFlows, coveredFlows: coveredCount, partialFlows: partialCount, unboundFiles: unboundCount } = plan.metrics;
462
+ const mustAddTests = plan.decision.action === 'must-add-tests';
463
+ const hasGapsButPrHasSpecs = !mustAddTests && plan.gapDetails.filter((g) => !g.name.includes('(partial)')).length > 0;
464
+ const flowsWithAdvisory = plan.coveredFlows.filter((f) => f.advisoryScenarios && f.advisoryScenarios.length > 0);
465
+ const cleanFlows = plan.coveredFlows.filter((f) => !f.advisoryScenarios || f.advisoryScenarios.length === 0);
466
+ const statusEmoji = mustAddTests ? '🔴' : plan.decision.action === 'safe-to-merge' ? '🟢' : '🟡';
467
+ lines.push(`## ${statusEmoji} E2E Coverage: ${plan.decision.title}`);
468
+ lines.push('');
469
+ lines.push(`${plan.decision.summary}`);
470
+ lines.push('');
471
+ // Coverage breakdown: "3 covered · 2 new · 1 gap · 1 partial"
472
+ const parts = [];
473
+ if ((coveredCount ?? 0) > 0) {
474
+ parts.push(`${coveredCount} covered`);
475
+ }
476
+ if (flowsWithAdvisory.length > 0) {
477
+ parts.push(`${flowsWithAdvisory.length} new behavior`);
478
+ }
479
+ if (uncoveredP0P1Flows > 0) {
480
+ parts.push(`${uncoveredP0P1Flows} gap${uncoveredP0P1Flows !== 1 ? 's' : ''}`);
481
+ }
482
+ if ((partialCount ?? 0) > 0) {
483
+ parts.push(`${partialCount} partial`);
484
+ }
485
+ const breakdown = parts.length > 0 ? ` (${parts.join(' · ')})` : '';
486
+ lines.push(`**${changedFiles}** files changed → **${impactedFlows}** features impacted${breakdown}`);
487
+ // ── Blocking gaps ──────────────────────────────────────────────────────────
488
+ if (mustAddTests && plan.requiredNewTests.length > 0) {
489
+ lines.push('');
490
+ lines.push(`### ⚠️ Missing coverage for ${uncoveredP0P1Flows} P0/P1 flow(s)`);
491
+ lines.push('');
492
+ for (const gap of plan.gapDetails.filter((g) => !g.name.includes('(partial)'))) {
493
+ const aiLabel = gap.source === 'ai+deterministic' ? ' ✦ AI-enriched' : '';
494
+ // Warning box: name + priority + AI reason (always visible)
495
+ lines.push(`> [!WARNING]`);
496
+ lines.push(`> **${gap.name}** · ${gap.priority}${aiLabel}`);
497
+ const aiReasons = gap.reasons.slice(1);
498
+ if (aiReasons.length > 0) {
499
+ lines.push(`> ${aiReasons.join(' ')}`);
500
+ }
501
+ lines.push('');
502
+ // Scenarios: collapsible below the warning box
503
+ if (gap.missingScenarios && gap.missingScenarios.length > 0) {
504
+ lines.push(`<details><summary>📋 Suggested test scenarios (${gap.missingScenarios.length})</summary>`);
505
+ lines.push('');
506
+ for (const scenario of gap.missingScenarios) {
507
+ lines.push(`- [ ] ${scenario}`);
508
+ }
509
+ lines.push('');
510
+ lines.push('</details>');
511
+ lines.push('');
512
+ }
513
+ }
514
+ }
515
+ // ── Informational gaps (PR includes E2E specs) ─────────────────────────────
516
+ if (hasGapsButPrHasSpecs) {
517
+ const infoGaps = plan.gapDetails.filter((g) => !g.name.includes('(partial)'));
518
+ lines.push('');
519
+ lines.push(`### ℹ️ Coverage gaps detected (PR includes E2E tests)`);
520
+ lines.push('');
521
+ lines.push('> The PR adds E2E test files. Verify they cover these flows:');
522
+ lines.push('');
523
+ for (const gap of infoGaps) {
524
+ const aiLabel = gap.source === 'ai+deterministic' ? ' ✦ AI-enriched' : '';
525
+ lines.push(`- **${gap.name}** · ${gap.priority}${aiLabel}`);
526
+ const aiReasons = gap.reasons.slice(1);
527
+ if (aiReasons.length > 0) {
528
+ lines.push(` ${aiReasons.join(' ')}`);
529
+ }
530
+ }
531
+ lines.push('');
532
+ }
533
+ // ── Advisory: covered flows with new behavior ─────────────────────────────
534
+ if (flowsWithAdvisory.length > 0) {
535
+ lines.push('');
536
+ lines.push(`### 💡 New behavior detected in ${flowsWithAdvisory.length} covered feature${flowsWithAdvisory.length !== 1 ? 's' : ''} — consider adding tests`);
537
+ lines.push('');
538
+ for (const flow of flowsWithAdvisory) {
539
+ const specParts = [];
540
+ for (const s of flow.coveredBy) {
541
+ // Strip "N Playwright spec(s)" → "N PW" and "N Cypress spec(s)" → "N Cy"
542
+ specParts.push(s.replace(/ Playwright spec\(s\)/, ' PW').replace(/ Cypress spec\(s\)/, ' Cy'));
543
+ }
544
+ const specSummary = specParts.length > 0 ? ` — ${specParts.join(' · ')}` : '';
545
+ const scenarioCount = flow.advisoryScenarios.length;
546
+ lines.push(`<details><summary>💡 <strong>${flow.name}</strong> · ${flow.priority}${specSummary} · ${scenarioCount} scenario${scenarioCount !== 1 ? 's' : ''}</summary>`);
547
+ lines.push('');
548
+ for (const s of flow.advisoryScenarios) {
549
+ lines.push(`- [ ] ${s}`);
550
+ }
551
+ lines.push('');
552
+ lines.push('</details>');
553
+ lines.push('');
554
+ }
555
+ }
556
+ // ── Clean covered flows (collapsed) ───────────────────────────────────────
557
+ if (cleanFlows.length > 0) {
558
+ lines.push('');
559
+ lines.push(`<details><summary>✅ Covered flows (${cleanFlows.length})</summary>`);
560
+ lines.push('');
561
+ for (const flow of cleanFlows) {
562
+ lines.push(`- **${flow.name}** [${flow.priority}] — ${flow.coveredBy.join(', ')}`);
563
+ }
564
+ lines.push('');
565
+ lines.push('</details>');
566
+ }
567
+ // ── Risky files detected ──────────────────────────────────────────────────
568
+ if (plan.policy.riskyFiles.length > 0) {
569
+ lines.push('');
570
+ lines.push(`### ⚠️ Risky file patterns matched`);
571
+ lines.push('');
572
+ for (const f of plan.policy.riskyFiles) {
573
+ lines.push(`- \`${f}\``);
574
+ }
575
+ }
576
+ // ── Unbound files warning ────────────────────────────────────────────────
577
+ if ((unboundCount ?? 0) > 0) {
578
+ lines.push('');
579
+ lines.push(`> **${unboundCount}** changed file(s) could not be mapped to any E2E flow. Consider updating \`route-families.json\` to cover these files.`);
580
+ }
581
+ if (plan.confidence < 100) {
582
+ lines.push('');
583
+ lines.push(`**Confidence**: ${plan.confidence}%`);
584
+ }
585
+ return lines.join('\n');
586
+ }
587
+ export function writeCiSummary(appRoot, markdown, relativePath = '.e2e-ai-agents/ci-summary.md') {
588
+ const fullPath = join(appRoot, relativePath);
589
+ const dir = dirname(fullPath);
590
+ mkdirSync(dir, { recursive: true });
591
+ writeFileSync(fullPath, markdown, 'utf-8');
592
+ return fullPath;
593
+ }
@@ -0,0 +1,72 @@
1
+ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2
+ // See LICENSE.txt for license information.
3
+ export { LLMProviderError, UnsupportedCapabilityError } from './provider_interface.js';
4
+ // Provider implementations
5
+ export { AnthropicProvider, checkAnthropicSetup } from './anthropic_provider.js';
6
+ export { OllamaProvider, checkOllamaSetup } from './ollama_provider.js';
7
+ export { OpenAIProvider, checkOpenAISetup } from './openai_provider.js';
8
+ export { CustomProvider } from './custom_provider.js';
9
+ // Factory
10
+ export { LLMProviderFactory, validateProviderSetup } from './provider_factory.js';
11
+ // Agent API (deterministic impact + plan, traceability)
12
+ export { analyzeImpactDeterministic, recommendTestsDeterministic, handoffGeneratedTests, ingestTraceability, captureTraceability } from './api.js';
13
+ // V2 Engine (deterministic impact + plan)
14
+ export { analyzeImpact as analyzeImpactV2, getGaps, getGapsWithSuppressed, getPartialGaps } from './engine/impact_engine.js';
15
+ export { extractScenarios } from './engine/impact_engine.js';
16
+ export { buildPlanFromImpact } from './engine/plan_builder.js';
17
+ export { appendFeedbackAndRecompute, readCalibration, readFlakyTests, getAdaptiveThresholds } from './agent/feedback.js';
18
+ export { finalizeGeneratedTests } from './agent/handoff.js';
19
+ export { ingestTraceabilityInput } from './agent/traceability_ingest.js';
20
+ export { captureTraceabilityInput } from './agent/traceability_capture.js';
21
+ // Pipeline API (route-family-bound impact analysis)
22
+ export { runPipeline } from './pipeline/orchestrator.js';
23
+ export { runGenerationStage } from './pipeline/stage3_generation.js';
24
+ export { buildGenerationPrompt, parseGenerationResponse, detectHallucinatedMethods } from './prompts/generation.js';
25
+ export { runHealStage, healFromReport, resolveHealTargets, renderHealMarkdown } from './pipeline/stage4_heal.js';
26
+ export { buildHealPrompt, buildQualityFixPrompt } from './prompts/heal.js';
27
+ // Knowledge modules
28
+ export { loadRouteFamilyManifest, bindFilesToFamilies, getCypressSpecDirsForBinding, getPriorityForBinding, getUserFlowsForBinding } from './knowledge/route_families.js';
29
+ export { buildApiSurface, loadOrBuildApiSurface } from './knowledge/api_surface.js';
30
+ export { buildSpecIndex, getSpecsForFamily } from './knowledge/spec_index.js';
31
+ // Agentic generation
32
+ export { runAgenticGeneration } from './agentic/runner.js';
33
+ // Crew (multi-agent QA workflows)
34
+ export { CrewOrchestrator } from './crew/orchestrator.js';
35
+ export { WORKFLOWS } from './crew/workflows.js';
36
+ // Crew agents
37
+ export { ImpactAnalystAgent } from './agents/impact-analyst.js';
38
+ export { CoverageEvaluatorAgent } from './agents/coverage-evaluator.js';
39
+ export { GeneratorAgent } from './agents/generator.js';
40
+ export { ExecutorAgent } from './agents/executor.js';
41
+ export { HealerAgent } from './agents/healer.js';
42
+ export { ExplorerAgent } from './agents/explorer.js';
43
+ export { StrategistAgent } from './agents/strategist.js';
44
+ export { TestDesignerAgent } from './agents/test-designer.js';
45
+ export { CrossImpactAgent } from './agents/cross-impact.js';
46
+ export { RegressionAdvisorAgent } from './agents/regression-advisor.js';
47
+ // Base provider (for extending with custom providers)
48
+ export { BaseProvider, BudgetExceededError } from './base_provider.js';
49
+ // Budget tracking
50
+ export { BudgetLedger } from './budget_ledger.js';
51
+ // Model routing
52
+ export { ModelRouter } from './model_router.js';
53
+ // Resilience
54
+ export { withRetry } from './resilience/retry.js';
55
+ export { CircuitBreaker } from './resilience/circuit_breaker.js';
56
+ // Metrics
57
+ export { PrometheusMetrics } from './metrics/prometheus.js';
58
+ // Secret scanning
59
+ export { sanitizeSecrets, containsSecrets, sanitizeObject } from './sanitize.js';
60
+ // CLI errors
61
+ export { CliError, classifyError, EXIT_CODES } from './cli/errors.js';
62
+ // Training (route-families bootstrap and maintenance)
63
+ export { scanProject } from './training/scanner.js';
64
+ export { mergeFamilies, detectStaleFamilies } from './training/merger.js';
65
+ export { enrichFamilies } from './training/enricher.js';
66
+ export { getCommitFiles, validateCommit, buildValidationReport, formatValidationReport } from './training/validator.js';
67
+ export { loadKnowledgeGraph, classifyProjectType, transformKGToFamilies, loadDiffOverlay } from './knowledge/kg_bridge.js';
68
+ export { scanFromKnowledgeGraph } from './training/kg_scanner.js';
69
+ export { resolveGenerationProfile, isMattermostProfile } from './prompts/generation_profile.js';
70
+ export { detectFramework, detectTestMode } from './adapters/framework_adapter.js';
71
+ // Route families (additional)
72
+ export { serializeManifest } from './knowledge/route_families.js';