@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,599 @@
1
+ "use strict";
2
+ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
3
+ // See LICENSE.txt for license information.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.buildPlanFromImpact = buildPlanFromImpact;
6
+ exports.writePlanReport = writePlanReport;
7
+ exports.renderCiSummaryMarkdown = renderCiSummaryMarkdown;
8
+ exports.writeCiSummary = writeCiSummary;
9
+ const fs_1 = require("fs");
10
+ const path_1 = require("path");
11
+ const minimatch_1 = require("minimatch");
12
+ const test_path_js_1 = require("../agent/test_path.js");
13
+ const impact_engine_js_1 = require("./impact_engine.js");
14
+ const route_families_js_1 = require("../knowledge/route_families.js");
15
+ const DEFAULT_POLICY = {
16
+ minConfidenceForTargeted: 60,
17
+ safeMergeMinConfidence: 85,
18
+ forceFullOnWarningsAtOrAbove: 2,
19
+ forceFullOnP0WithGaps: true,
20
+ forceFullOnRiskyFiles: true,
21
+ riskyFilePatterns: [
22
+ '**/auth/**',
23
+ '**/login/**',
24
+ '**/permissions/**',
25
+ '**/admin/**',
26
+ '**/security/**',
27
+ '**/migrations/**',
28
+ '**/schema/**',
29
+ '**/*.sql',
30
+ '**/webhook/**',
31
+ ],
32
+ enforcementMode: 'advisory',
33
+ blockOnActions: ['must-add-tests'],
34
+ };
35
+ function featureLabel(f) {
36
+ return f.featureId || f.familyId;
37
+ }
38
+ function computeConfidence(impact) {
39
+ const gaps = (0, impact_engine_js_1.getGaps)(impact);
40
+ const totalFeatures = impact.impactedFeatures.length;
41
+ const boundRatio = totalFeatures > 0
42
+ ? (totalFeatures / (totalFeatures + impact.unboundFiles.length))
43
+ : 1;
44
+ // Graph-resolved bindings start at 100
45
+ let confidence = 100;
46
+ // Deduct for unbound files (not mapped to any family)
47
+ if (impact.unboundFiles.length > 0) {
48
+ const unboundPenalty = Math.min(30, impact.unboundFiles.length * 3);
49
+ confidence -= unboundPenalty;
50
+ }
51
+ // Deduct for gaps
52
+ confidence -= Math.min(20, gaps.length * 5);
53
+ // Deduct for warnings
54
+ confidence -= Math.min(15, impact.warnings.length * 5);
55
+ // Bonus for high bound ratio
56
+ if (boundRatio >= 0.9) {
57
+ confidence = Math.min(100, confidence + 5);
58
+ }
59
+ return Math.max(0, Math.min(100, confidence));
60
+ }
61
+ function findRiskyFiles(changedFiles, patterns) {
62
+ return [...new Set(changedFiles.filter((file) => patterns.some((pattern) => (0, minimatch_1.minimatch)(file, pattern, { matchBase: true }))))];
63
+ }
64
+ function pickRunSet(impact, confidence, policy) {
65
+ const gaps = (0, impact_engine_js_1.getGaps)(impact);
66
+ const reasons = [];
67
+ const triggeredRules = [];
68
+ const riskyFiles = findRiskyFiles(impact.changedFiles, policy.riskyFilePatterns);
69
+ const hasP0 = impact.impactedFeatures.some((f) => f.priority === 'P0');
70
+ if (gaps.length > 0) {
71
+ reasons.push(`${gaps.length} uncovered P0/P1 feature(s) detected.`);
72
+ }
73
+ if (hasP0) {
74
+ reasons.push('P0 features are impacted by this change set.');
75
+ }
76
+ if (policy.forceFullOnRiskyFiles && riskyFiles.length > 0) {
77
+ triggeredRules.push('risky-files');
78
+ reasons.push(`Risky file patterns matched: ${riskyFiles.join(', ')}`);
79
+ }
80
+ if (confidence < policy.minConfidenceForTargeted) {
81
+ triggeredRules.push('low-confidence');
82
+ }
83
+ if (impact.warnings.length >= policy.forceFullOnWarningsAtOrAbove) {
84
+ triggeredRules.push('warning-threshold');
85
+ reasons.push('Warning threshold exceeded.');
86
+ }
87
+ if (policy.forceFullOnP0WithGaps && hasP0 && gaps.length > 0) {
88
+ triggeredRules.push('p0-with-gaps');
89
+ }
90
+ if (triggeredRules.length > 0) {
91
+ return {
92
+ runSet: 'full',
93
+ reasons: reasons.length > 0 ? reasons : ['Policy rules triggered full suite.'],
94
+ triggeredRules,
95
+ riskyFiles,
96
+ };
97
+ }
98
+ // If we have impacted features with specs, recommend targeted
99
+ const coveredFeatures = impact.impactedFeatures.filter((f) => f.coverageStatus !== 'uncovered');
100
+ if (coveredFeatures.length > 0) {
101
+ return {
102
+ runSet: 'targeted',
103
+ reasons: reasons.length > 0 ? reasons : ['Impacted features have test coverage.'],
104
+ triggeredRules,
105
+ riskyFiles,
106
+ };
107
+ }
108
+ return {
109
+ runSet: 'smoke',
110
+ reasons: reasons.length > 0 ? reasons : ['No targeted tests mapped from impacted features.'],
111
+ triggeredRules,
112
+ riskyFiles,
113
+ };
114
+ }
115
+ /**
116
+ * Check which gaps have matching PR-included E2E spec files by binding
117
+ * spec files to families via the manifest. Returns familyIds that are covered.
118
+ */
119
+ function matchPrSpecsToGaps(prTestFiles, gaps, testsRoot) {
120
+ const coveredFamilies = new Set();
121
+ const prE2ESpecs = prTestFiles.filter((t) => t.type === 'playwright' || t.type === 'cypress');
122
+ if (prE2ESpecs.length === 0 || !testsRoot) {
123
+ return coveredFamilies;
124
+ }
125
+ // Try to bind PR spec files to families via the manifest
126
+ const manifest = (0, route_families_js_1.loadRouteFamilyManifest)(testsRoot);
127
+ if (manifest) {
128
+ const specBindings = (0, route_families_js_1.bindFilesToFamilies)(prE2ESpecs.map((s) => s.file), manifest);
129
+ for (const sb of specBindings) {
130
+ for (const binding of sb.bindings) {
131
+ coveredFamilies.add(binding.family);
132
+ }
133
+ }
134
+ }
135
+ // Fallback heuristic: if manifest binding didn't match (common for Cypress specs
136
+ // in directories not mapped in the manifest), check path-based keyword overlap.
137
+ if (coveredFamilies.size === 0) {
138
+ const gapFamilyIds = new Set(gaps.map((g) => g.familyId));
139
+ for (const spec of prE2ESpecs) {
140
+ const specLower = spec.file.toLowerCase().replace(/[_\-/\\]/g, ' ');
141
+ for (const familyId of gapFamilyIds) {
142
+ // Check if the spec path contains the family name or related terms
143
+ if (specLower.includes(familyId.toLowerCase())) {
144
+ coveredFamilies.add(familyId);
145
+ }
146
+ }
147
+ }
148
+ }
149
+ return coveredFamilies;
150
+ }
151
+ function buildDecision(impact, runSet, confidence, policy) {
152
+ const gaps = (0, impact_engine_js_1.getGapsWithSuppressed)(impact).gaps;
153
+ if (gaps.length > 0) {
154
+ const prE2ESpecs = (impact.prIncludedTestFiles ?? [])
155
+ .filter((t) => t.type === 'playwright' || t.type === 'cypress');
156
+ if (prE2ESpecs.length > 0) {
157
+ // Bind PR specs to families โ€” only soften gaps that have matching specs
158
+ const coveredFamilies = matchPrSpecsToGaps(impact.prIncludedTestFiles ?? [], gaps);
159
+ const uncoveredGaps = gaps.filter((g) => !coveredFamilies.has(g.familyId));
160
+ if (uncoveredGaps.length === 0) {
161
+ // ALL gaps have matching PR specs
162
+ return {
163
+ action: 'run-now',
164
+ title: 'Run now',
165
+ 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.`,
166
+ };
167
+ }
168
+ if (uncoveredGaps.length < gaps.length) {
169
+ // SOME gaps covered by PR specs, others not
170
+ return {
171
+ action: 'must-add-tests',
172
+ title: 'Must add tests',
173
+ summary: `Detected ${gaps.length} coverage gap(s). PR includes E2E tests for ${gaps.length - uncoveredGaps.length}, but ${uncoveredGaps.length} flow(s) still need coverage.`,
174
+ };
175
+ }
176
+ // No gaps matched by PR specs โ€” but PR still has E2E files.
177
+ // Soften to run-now since the developer is actively writing tests.
178
+ return {
179
+ action: 'run-now',
180
+ title: 'Run now',
181
+ summary: `Detected ${gaps.length} coverage gap(s), but the PR includes ${prE2ESpecs.length} E2E test file(s). Verify the new tests cover impacted flows.`,
182
+ };
183
+ }
184
+ return {
185
+ action: 'must-add-tests',
186
+ title: 'Must add tests',
187
+ summary: `Detected ${gaps.length} uncovered P0/P1 feature(s). Add or update tests before merge.`,
188
+ };
189
+ }
190
+ if (impact.changedFiles.length === 0 && impact.impactedFeatures.length === 0) {
191
+ return {
192
+ action: 'safe-to-merge',
193
+ title: 'Safe to merge',
194
+ summary: 'No app file changes detected โ€” no E2E coverage required for this change set.',
195
+ };
196
+ }
197
+ if (runSet === 'smoke' && confidence >= policy.safeMergeMinConfidence && impact.warnings.length === 0) {
198
+ return {
199
+ action: 'safe-to-merge',
200
+ title: 'Safe to merge',
201
+ summary: 'No critical coverage gaps were detected and confidence is high.',
202
+ };
203
+ }
204
+ const coveredCount = impact.impactedFeatures.filter((f) => f.coverageStatus !== 'uncovered').length;
205
+ const coveredSuffix = coveredCount > 0
206
+ ? ` All ${coveredCount} impacted feature(s) have test coverage.`
207
+ : '';
208
+ // When files changed but no flows were mapped, be transparent about the gap
209
+ if (impact.impactedFeatures.length === 0 && impact.changedFiles.length > 0) {
210
+ const unboundNote = impact.unboundFiles.length > 0
211
+ ? ` ${impact.unboundFiles.length} file(s) could not be mapped to any known flow โ€” consider adding route-families bindings.`
212
+ : '';
213
+ return {
214
+ action: 'run-now',
215
+ title: 'Run now',
216
+ summary: `Changed files could not be mapped to E2E flows โ€” manual review recommended.${unboundNote} Verify with the E2E suite before merge.`,
217
+ };
218
+ }
219
+ return {
220
+ action: 'run-now',
221
+ title: 'Run now',
222
+ summary: `Impacted features are covered by existing tests.${coveredSuffix} Verify with the E2E suite before merge.`,
223
+ };
224
+ }
225
+ function evaluateEnforcement(decision, policy) {
226
+ const blockOnActions = (policy.blockOnActions && policy.blockOnActions.length > 0)
227
+ ? [...policy.blockOnActions]
228
+ : ['must-add-tests'];
229
+ const matchedAction = blockOnActions.includes(decision.action);
230
+ if (policy.enforcementMode === 'block' && matchedAction) {
231
+ return {
232
+ mode: policy.enforcementMode,
233
+ blockOnActions,
234
+ matchedAction,
235
+ shouldFail: true,
236
+ summary: `Blocking mode active: decision "${decision.action}" is configured to fail CI.`,
237
+ };
238
+ }
239
+ if (policy.enforcementMode === 'warn' && matchedAction) {
240
+ return {
241
+ mode: policy.enforcementMode,
242
+ blockOnActions,
243
+ matchedAction,
244
+ shouldFail: false,
245
+ summary: `Warning mode active: decision "${decision.action}" is advisory-only for CI.`,
246
+ };
247
+ }
248
+ if (policy.enforcementMode === 'block') {
249
+ return {
250
+ mode: policy.enforcementMode,
251
+ blockOnActions,
252
+ matchedAction,
253
+ shouldFail: false,
254
+ summary: `Blocking mode active, but decision "${decision.action}" is not configured for CI failure.`,
255
+ };
256
+ }
257
+ return {
258
+ mode: policy.enforcementMode,
259
+ blockOnActions,
260
+ matchedAction,
261
+ shouldFail: false,
262
+ summary: 'Advisory mode active: recommendations do not fail CI by default.',
263
+ };
264
+ }
265
+ /**
266
+ * Build recommended test list from impacted features' Playwright specs.
267
+ * When alwaysIncludeSubsystems is provided, specs from those subsystems are
268
+ * included regardless of their coverage status (blind-spot protection).
269
+ */
270
+ function buildRecommendedTests(impact, alwaysIncludeSubsystems = []) {
271
+ const tests = new Set();
272
+ const alwaysSet = new Set(alwaysIncludeSubsystems);
273
+ for (const feature of impact.impactedFeatures) {
274
+ const shouldInclude = feature.coverageStatus !== 'uncovered' ||
275
+ feature.playwrightSpecs.some((spec) => alwaysSet.has((0, test_path_js_1.inferSubsystemFromTestPath)(spec)));
276
+ if (shouldInclude) {
277
+ for (const spec of feature.playwrightSpecs) {
278
+ tests.add(spec);
279
+ }
280
+ }
281
+ }
282
+ return [...tests];
283
+ }
284
+ function buildPlanFromImpact(impact, policyOverride, aiEnrichment, adaptiveThresholds) {
285
+ const policy = { ...DEFAULT_POLICY, ...(policyOverride || {}) };
286
+ // Apply adaptive calibration overrides (if available and not explicitly overridden)
287
+ if (adaptiveThresholds && policyOverride?.minConfidenceForTargeted === undefined) {
288
+ policy.minConfidenceForTargeted = adaptiveThresholds.minConfidenceForTargeted;
289
+ }
290
+ if (adaptiveThresholds && policyOverride?.safeMergeMinConfidence === undefined) {
291
+ policy.safeMergeMinConfidence = adaptiveThresholds.safeMergeMinConfidence;
292
+ }
293
+ // Apply alwaysIncludeSubsystems: force their tests into the recommended set
294
+ const alwaysIncludeSubsystems = adaptiveThresholds?.alwaysIncludeSubsystems ?? [];
295
+ const confidence = computeConfidence(impact);
296
+ const runSetResult = pickRunSet(impact, confidence, policy);
297
+ const decision = buildDecision(impact, runSetResult.runSet, confidence, policy);
298
+ const enforcement = evaluateEnforcement(decision, policy);
299
+ const { gaps, suppressedGaps } = (0, impact_engine_js_1.getGapsWithSuppressed)(impact);
300
+ const partialGaps = (0, impact_engine_js_1.getPartialGaps)(impact);
301
+ // Build two separate lookup maps from aiEnrichment: one by featureId, one by familyId.
302
+ // The familyId map stores only the FIRST feature encountered to avoid last-write-wins collisions.
303
+ const aiFeatureByFeatureId = new Map();
304
+ const aiFeatureByFamilyId = new Map();
305
+ if (aiEnrichment) {
306
+ for (const ef of aiEnrichment.enrichedFeatures) {
307
+ if (ef.featureId) {
308
+ aiFeatureByFeatureId.set(ef.featureId, ef);
309
+ }
310
+ if (ef.familyId && !aiFeatureByFamilyId.has(ef.familyId)) {
311
+ aiFeatureByFamilyId.set(ef.familyId, ef);
312
+ }
313
+ }
314
+ }
315
+ const gapDetails = gaps.map((f) => {
316
+ const label = featureLabel(f);
317
+ const aiFeature = f.featureId
318
+ ? (aiFeatureByFeatureId.get(f.featureId) ?? aiFeatureByFamilyId.get(f.familyId))
319
+ : aiFeatureByFamilyId.get(f.familyId);
320
+ const baseReasons = [`No E2E tests found for ${label}`];
321
+ let aiReasonsList = [];
322
+ if (aiFeature) {
323
+ if (aiFeature.aiReasons.length > 0) {
324
+ aiReasonsList = aiFeature.aiReasons.slice(0, 2);
325
+ }
326
+ else {
327
+ // Fallback: LLM returned scenarios but no reasons โ€” synthesize a description
328
+ const fileHint = f.changedFiles.slice(0, 3).map((p) => p.split('/').pop()).join(', ');
329
+ aiReasonsList = [`Changes to ${fileHint} affect the ${label} feature, which currently lacks E2E coverage.`];
330
+ }
331
+ }
332
+ const reasons = aiReasonsList.length > 0
333
+ ? [...baseReasons, ...aiReasonsList]
334
+ : baseReasons;
335
+ const missingScenarios = aiFeature && aiFeature.aiMissingScenarios.length > 0
336
+ ? aiFeature.aiMissingScenarios
337
+ : (f.userFlows.length > 0 ? f.userFlows.slice(0, 5) : undefined);
338
+ return {
339
+ id: label,
340
+ name: label,
341
+ priority: f.priority,
342
+ reasons,
343
+ files: f.changedFiles.slice(0, 6),
344
+ missingScenarios,
345
+ source: aiFeature ? 'ai+deterministic' : 'deterministic',
346
+ };
347
+ });
348
+ // Add partial gaps as advisory info (Cypress-only coverage โ€” Playwright migration recommended)
349
+ for (const f of partialGaps) {
350
+ const label = featureLabel(f);
351
+ const aiFeature = f.featureId
352
+ ? (aiFeatureByFeatureId.get(f.featureId) ?? aiFeatureByFamilyId.get(f.familyId))
353
+ : aiFeatureByFamilyId.get(f.familyId);
354
+ const baseReasons = [`${label} is covered by Cypress only โ€” consider adding Playwright tests`];
355
+ let partialAiReasons = [];
356
+ if (aiFeature) {
357
+ if (aiFeature.aiReasons.length > 0) {
358
+ partialAiReasons = aiFeature.aiReasons.slice(0, 2);
359
+ }
360
+ else {
361
+ const fileHint = f.changedFiles.slice(0, 3).map((p) => p.split('/').pop()).join(', ');
362
+ partialAiReasons = [`Changes to ${fileHint} affect the ${label} feature, which has Cypress but no Playwright coverage.`];
363
+ }
364
+ }
365
+ const reasons = partialAiReasons.length > 0
366
+ ? [...baseReasons, ...partialAiReasons]
367
+ : baseReasons;
368
+ gapDetails.push({
369
+ id: label,
370
+ name: `${label} (partial)`,
371
+ priority: f.priority,
372
+ reasons,
373
+ files: f.changedFiles.slice(0, 6),
374
+ source: aiFeature ? 'ai+deterministic' : 'deterministic',
375
+ });
376
+ }
377
+ const coveredFlows = impact.impactedFeatures
378
+ .filter((f) => f.coverageStatus === 'covered')
379
+ .map((f) => {
380
+ const aiFeature = f.featureId
381
+ ? (aiFeatureByFeatureId.get(f.featureId) ?? aiFeatureByFamilyId.get(f.familyId))
382
+ : aiFeatureByFamilyId.get(f.familyId);
383
+ // Only surface advisory scenarios when AI found new behavior in this diff
384
+ let advisoryScenarios = aiFeature?.aiMissingScenarios?.length
385
+ ? [...aiFeature.aiMissingScenarios]
386
+ : undefined;
387
+ // Promote suppressed gaps to advisory on covered flows that share changed files.
388
+ // When a family-level gap is suppressed (e.g. "post" because post.go is also in
389
+ // a covered feature like "channels/threads"), the behavioral change should appear
390
+ // here as "new behavior detected" instead of vanishing.
391
+ for (const sg of suppressedGaps) {
392
+ const sharedFiles = sg.changedFiles.filter((file) => f.changedFiles.includes(file));
393
+ if (sharedFiles.length > 0) {
394
+ const sgAi = sg.featureId
395
+ ? (aiFeatureByFeatureId.get(sg.featureId) ?? aiFeatureByFamilyId.get(sg.familyId))
396
+ : aiFeatureByFamilyId.get(sg.familyId);
397
+ const sgScenarios = sgAi?.aiMissingScenarios?.length
398
+ ? sgAi.aiMissingScenarios
399
+ : sg.userFlows.slice(0, 3);
400
+ if (sgScenarios.length > 0) {
401
+ advisoryScenarios = [...(advisoryScenarios || []), ...sgScenarios];
402
+ }
403
+ }
404
+ }
405
+ return {
406
+ id: featureLabel(f),
407
+ name: featureLabel(f),
408
+ priority: f.priority,
409
+ coveredBy: [
410
+ ...(f.playwrightSpecs.length > 0 ? [`${f.playwrightSpecs.length} Playwright spec(s)`] : []),
411
+ ...(f.cypressSpecs.length > 0 ? [`${f.cypressSpecs.length} Cypress spec(s)`] : []),
412
+ ].slice(0, 3),
413
+ advisoryScenarios,
414
+ };
415
+ });
416
+ const recommendedTests = buildRecommendedTests(impact, alwaysIncludeSubsystems);
417
+ const requiredNewTests = gaps.map((f) => `${featureLabel(f)}: Add E2E tests`);
418
+ const p0 = impact.impactedFeatures.filter((f) => f.priority === 'P0').length;
419
+ const p1 = impact.impactedFeatures.filter((f) => f.priority === 'P1').length;
420
+ const p2 = impact.impactedFeatures.filter((f) => f.priority === 'P2').length;
421
+ const coveredCount = impact.impactedFeatures.filter((f) => f.coverageStatus === 'covered').length;
422
+ const partialCount = impact.impactedFeatures.filter((f) => f.coverageStatus === 'partial').length;
423
+ const runId = `plan-${Date.now().toString(36)}`;
424
+ const planSource = aiEnrichment ? 'ai+deterministic' : 'impact';
425
+ return {
426
+ schemaVersion: '1.0.0',
427
+ runId,
428
+ generatedAt: new Date().toISOString(),
429
+ source: planSource,
430
+ runSet: runSetResult.runSet,
431
+ confidence,
432
+ reasons: runSetResult.reasons,
433
+ recommendedTests,
434
+ requiredNewTests,
435
+ gapDetails,
436
+ coveredFlows,
437
+ policy: {
438
+ riskyFiles: runSetResult.riskyFiles,
439
+ triggeredRules: runSetResult.triggeredRules,
440
+ applied: policy,
441
+ },
442
+ decision,
443
+ enforcement,
444
+ metrics: {
445
+ changedFiles: impact.changedFiles.length,
446
+ impactedFlows: impact.impactedFeatures.length,
447
+ p0Flows: p0,
448
+ p1Flows: p1,
449
+ p2Flows: p2,
450
+ coveredFlows: coveredCount,
451
+ partialFlows: partialCount,
452
+ uncoveredP0P1Flows: gaps.length,
453
+ unboundFiles: impact.unboundFiles.length,
454
+ warnings: impact.warnings.length,
455
+ },
456
+ };
457
+ }
458
+ function writePlanReport(appRoot, plan) {
459
+ const baseDir = (0, path_1.join)(appRoot, '.e2e-ai-agents');
460
+ (0, fs_1.mkdirSync)(baseDir, { recursive: true });
461
+ const planPath = (0, path_1.join)(baseDir, 'plan.json');
462
+ (0, fs_1.writeFileSync)(planPath, JSON.stringify(plan, null, 2), 'utf-8');
463
+ return planPath;
464
+ }
465
+ function renderCiSummaryMarkdown(plan) {
466
+ const lines = [];
467
+ const { uncoveredP0P1Flows, changedFiles, impactedFlows, coveredFlows: coveredCount, partialFlows: partialCount, unboundFiles: unboundCount } = plan.metrics;
468
+ const mustAddTests = plan.decision.action === 'must-add-tests';
469
+ const hasGapsButPrHasSpecs = !mustAddTests && plan.gapDetails.filter((g) => !g.name.includes('(partial)')).length > 0;
470
+ const flowsWithAdvisory = plan.coveredFlows.filter((f) => f.advisoryScenarios && f.advisoryScenarios.length > 0);
471
+ const cleanFlows = plan.coveredFlows.filter((f) => !f.advisoryScenarios || f.advisoryScenarios.length === 0);
472
+ const statusEmoji = mustAddTests ? '๐Ÿ”ด' : plan.decision.action === 'safe-to-merge' ? '๐ŸŸข' : '๐ŸŸก';
473
+ lines.push(`## ${statusEmoji} E2E Coverage: ${plan.decision.title}`);
474
+ lines.push('');
475
+ lines.push(`${plan.decision.summary}`);
476
+ lines.push('');
477
+ // Coverage breakdown: "3 covered ยท 2 new ยท 1 gap ยท 1 partial"
478
+ const parts = [];
479
+ if ((coveredCount ?? 0) > 0) {
480
+ parts.push(`${coveredCount} covered`);
481
+ }
482
+ if (flowsWithAdvisory.length > 0) {
483
+ parts.push(`${flowsWithAdvisory.length} new behavior`);
484
+ }
485
+ if (uncoveredP0P1Flows > 0) {
486
+ parts.push(`${uncoveredP0P1Flows} gap${uncoveredP0P1Flows !== 1 ? 's' : ''}`);
487
+ }
488
+ if ((partialCount ?? 0) > 0) {
489
+ parts.push(`${partialCount} partial`);
490
+ }
491
+ const breakdown = parts.length > 0 ? ` (${parts.join(' ยท ')})` : '';
492
+ lines.push(`**${changedFiles}** files changed โ†’ **${impactedFlows}** features impacted${breakdown}`);
493
+ // โ”€โ”€ Blocking gaps โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
494
+ if (mustAddTests && plan.requiredNewTests.length > 0) {
495
+ lines.push('');
496
+ lines.push(`### โš ๏ธ Missing coverage for ${uncoveredP0P1Flows} P0/P1 flow(s)`);
497
+ lines.push('');
498
+ for (const gap of plan.gapDetails.filter((g) => !g.name.includes('(partial)'))) {
499
+ const aiLabel = gap.source === 'ai+deterministic' ? ' โœฆ AI-enriched' : '';
500
+ // Warning box: name + priority + AI reason (always visible)
501
+ lines.push(`> [!WARNING]`);
502
+ lines.push(`> **${gap.name}** ยท ${gap.priority}${aiLabel}`);
503
+ const aiReasons = gap.reasons.slice(1);
504
+ if (aiReasons.length > 0) {
505
+ lines.push(`> ${aiReasons.join(' ')}`);
506
+ }
507
+ lines.push('');
508
+ // Scenarios: collapsible below the warning box
509
+ if (gap.missingScenarios && gap.missingScenarios.length > 0) {
510
+ lines.push(`<details><summary>๐Ÿ“‹ Suggested test scenarios (${gap.missingScenarios.length})</summary>`);
511
+ lines.push('');
512
+ for (const scenario of gap.missingScenarios) {
513
+ lines.push(`- [ ] ${scenario}`);
514
+ }
515
+ lines.push('');
516
+ lines.push('</details>');
517
+ lines.push('');
518
+ }
519
+ }
520
+ }
521
+ // โ”€โ”€ Informational gaps (PR includes E2E specs) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
522
+ if (hasGapsButPrHasSpecs) {
523
+ const infoGaps = plan.gapDetails.filter((g) => !g.name.includes('(partial)'));
524
+ lines.push('');
525
+ lines.push(`### โ„น๏ธ Coverage gaps detected (PR includes E2E tests)`);
526
+ lines.push('');
527
+ lines.push('> The PR adds E2E test files. Verify they cover these flows:');
528
+ lines.push('');
529
+ for (const gap of infoGaps) {
530
+ const aiLabel = gap.source === 'ai+deterministic' ? ' โœฆ AI-enriched' : '';
531
+ lines.push(`- **${gap.name}** ยท ${gap.priority}${aiLabel}`);
532
+ const aiReasons = gap.reasons.slice(1);
533
+ if (aiReasons.length > 0) {
534
+ lines.push(` ${aiReasons.join(' ')}`);
535
+ }
536
+ }
537
+ lines.push('');
538
+ }
539
+ // โ”€โ”€ Advisory: covered flows with new behavior โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
540
+ if (flowsWithAdvisory.length > 0) {
541
+ lines.push('');
542
+ lines.push(`### ๐Ÿ’ก New behavior detected in ${flowsWithAdvisory.length} covered feature${flowsWithAdvisory.length !== 1 ? 's' : ''} โ€” consider adding tests`);
543
+ lines.push('');
544
+ for (const flow of flowsWithAdvisory) {
545
+ const specParts = [];
546
+ for (const s of flow.coveredBy) {
547
+ // Strip "N Playwright spec(s)" โ†’ "N PW" and "N Cypress spec(s)" โ†’ "N Cy"
548
+ specParts.push(s.replace(/ Playwright spec\(s\)/, ' PW').replace(/ Cypress spec\(s\)/, ' Cy'));
549
+ }
550
+ const specSummary = specParts.length > 0 ? ` โ€” ${specParts.join(' ยท ')}` : '';
551
+ const scenarioCount = flow.advisoryScenarios.length;
552
+ lines.push(`<details><summary>๐Ÿ’ก <strong>${flow.name}</strong> ยท ${flow.priority}${specSummary} ยท ${scenarioCount} scenario${scenarioCount !== 1 ? 's' : ''}</summary>`);
553
+ lines.push('');
554
+ for (const s of flow.advisoryScenarios) {
555
+ lines.push(`- [ ] ${s}`);
556
+ }
557
+ lines.push('');
558
+ lines.push('</details>');
559
+ lines.push('');
560
+ }
561
+ }
562
+ // โ”€โ”€ Clean covered flows (collapsed) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
563
+ if (cleanFlows.length > 0) {
564
+ lines.push('');
565
+ lines.push(`<details><summary>โœ… Covered flows (${cleanFlows.length})</summary>`);
566
+ lines.push('');
567
+ for (const flow of cleanFlows) {
568
+ lines.push(`- **${flow.name}** [${flow.priority}] โ€” ${flow.coveredBy.join(', ')}`);
569
+ }
570
+ lines.push('');
571
+ lines.push('</details>');
572
+ }
573
+ // โ”€โ”€ Risky files detected โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
574
+ if (plan.policy.riskyFiles.length > 0) {
575
+ lines.push('');
576
+ lines.push(`### โš ๏ธ Risky file patterns matched`);
577
+ lines.push('');
578
+ for (const f of plan.policy.riskyFiles) {
579
+ lines.push(`- \`${f}\``);
580
+ }
581
+ }
582
+ // โ”€โ”€ Unbound files warning โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
583
+ if ((unboundCount ?? 0) > 0) {
584
+ lines.push('');
585
+ lines.push(`> **${unboundCount}** changed file(s) could not be mapped to any E2E flow. Consider updating \`route-families.json\` to cover these files.`);
586
+ }
587
+ if (plan.confidence < 100) {
588
+ lines.push('');
589
+ lines.push(`**Confidence**: ${plan.confidence}%`);
590
+ }
591
+ return lines.join('\n');
592
+ }
593
+ function writeCiSummary(appRoot, markdown, relativePath = '.e2e-ai-agents/ci-summary.md') {
594
+ const fullPath = (0, path_1.join)(appRoot, relativePath);
595
+ const dir = (0, path_1.dirname)(fullPath);
596
+ (0, fs_1.mkdirSync)(dir, { recursive: true });
597
+ (0, fs_1.writeFileSync)(fullPath, markdown, 'utf-8');
598
+ return fullPath;
599
+ }
@@ -0,0 +1,49 @@
1
+ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2
+ // See LICENSE.txt for license information.
3
+ /**
4
+ * Cypress Adapter โ€” FrameworkAdapter implementation for Cypress.
5
+ */
6
+ import * as fs from 'node:fs';
7
+ import * as path from 'node:path';
8
+ export class CypressAdapter {
9
+ constructor() {
10
+ this.name = 'cypress';
11
+ this.specGlob = '**/*.cy.{ts,js,tsx,jsx}';
12
+ this.extractTestPattern = /\b(?:it|describe|context)\s*\(/g;
13
+ this.configFileNames = ['cypress.config.ts', 'cypress.config.js'];
14
+ }
15
+ detect(projectRoot) {
16
+ const pkgPath = path.join(projectRoot, 'package.json');
17
+ if (!fs.existsSync(pkgPath)) {
18
+ return false;
19
+ }
20
+ try {
21
+ const raw = fs.readFileSync(pkgPath, 'utf-8');
22
+ const pkg = JSON.parse(raw);
23
+ const allDeps = {
24
+ ...pkg.dependencies,
25
+ ...pkg.devDependencies,
26
+ };
27
+ return 'cypress' in allDeps;
28
+ }
29
+ catch {
30
+ return false;
31
+ }
32
+ }
33
+ buildRunCommand(specPath, options) {
34
+ const args = ['cypress', 'run', '--spec', specPath];
35
+ if (options?.headed) {
36
+ args.push('--headed');
37
+ }
38
+ if (options?.browser) {
39
+ args.push('--browser', options.browser);
40
+ }
41
+ if (options?.project) {
42
+ args.push('--project', options.project);
43
+ }
44
+ if (options?.timeout != null) {
45
+ args.push('--config', `defaultCommandTimeout=${options.timeout}`);
46
+ }
47
+ return { executable: 'npx', args };
48
+ }
49
+ }