@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,317 @@
1
+ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2
+ // See LICENSE.txt for license information.
3
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
4
+ import { join } from 'path';
5
+ import { inferSubsystemFromTestPath } from './test_path.js';
6
+ function readJson(path) {
7
+ if (!existsSync(path)) {
8
+ return null;
9
+ }
10
+ try {
11
+ return JSON.parse(readFileSync(path, 'utf-8'));
12
+ }
13
+ catch {
14
+ return null;
15
+ }
16
+ }
17
+ function normalizeTestName(test) {
18
+ return test.replace(/ \(flags:.*\)$/, '').trim();
19
+ }
20
+ function asSet(values) {
21
+ return new Set(values.map(normalizeTestName).filter(Boolean));
22
+ }
23
+ function ratio(numerator, denominator) {
24
+ if (denominator <= 0) {
25
+ return 0;
26
+ }
27
+ return Number((numerator / denominator).toFixed(4));
28
+ }
29
+ function subsystemForTest(test) {
30
+ return inferSubsystemFromTestPath(test);
31
+ }
32
+ function parseTimestamp(value) {
33
+ const time = Date.parse(value);
34
+ if (Number.isNaN(time)) {
35
+ return null;
36
+ }
37
+ return time;
38
+ }
39
+ function filterRecent(entries, days) {
40
+ const cutoff = Date.now() - days * 24 * 60 * 60 * 1000;
41
+ return entries.filter((entry) => {
42
+ const time = parseTimestamp(entry.timestamp);
43
+ return time !== null && time >= cutoff;
44
+ });
45
+ }
46
+ function aggregateMetrics(entries) {
47
+ let truePositives = 0;
48
+ let recommendedTotal = 0;
49
+ let failuresTotal = 0;
50
+ let escapedTotal = 0;
51
+ for (const entry of entries) {
52
+ const recommended = asSet(entry.recommendedTests || []);
53
+ const failed = asSet(entry.failedTests || []);
54
+ const escaped = asSet(entry.escapedFailures || []);
55
+ const tp = Array.from(recommended).filter((test) => failed.has(test)).length;
56
+ truePositives += tp;
57
+ recommendedTotal += recommended.size;
58
+ failuresTotal += failed.size;
59
+ escapedTotal += escaped.size;
60
+ }
61
+ return {
62
+ precision: ratio(truePositives, recommendedTotal),
63
+ recall: ratio(truePositives, failuresTotal),
64
+ falseNegativeRate: ratio(escapedTotal, failuresTotal + escapedTotal),
65
+ samples: entries.length,
66
+ };
67
+ }
68
+ function aggregate(entries) {
69
+ const subsystemAcc = new Map();
70
+ for (const entry of entries) {
71
+ const recommended = asSet(entry.recommendedTests || []);
72
+ const failed = asSet(entry.failedTests || []);
73
+ const escaped = asSet(entry.escapedFailures || []);
74
+ const allSubsystems = new Set([
75
+ ...Array.from(recommended).map(subsystemForTest),
76
+ ...Array.from(failed).map(subsystemForTest),
77
+ ...Array.from(escaped).map(subsystemForTest),
78
+ ]);
79
+ for (const subsystem of allSubsystems) {
80
+ const bucket = subsystemAcc.get(subsystem) || { entries: [] };
81
+ bucket.entries.push({
82
+ ...entry,
83
+ recommendedTests: Array.from(recommended).filter((test) => subsystemForTest(test) === subsystem),
84
+ executedTests: (entry.executedTests || []).filter((test) => subsystemForTest(test) === subsystem),
85
+ failedTests: Array.from(failed).filter((test) => subsystemForTest(test) === subsystem),
86
+ escapedFailures: Array.from(escaped).filter((test) => subsystemForTest(test) === subsystem),
87
+ });
88
+ subsystemAcc.set(subsystem, bucket);
89
+ }
90
+ }
91
+ const bySubsystem = {};
92
+ for (const [subsystem, bucket] of subsystemAcc.entries()) {
93
+ const all = aggregateMetrics(bucket.entries);
94
+ const recent7d = aggregateMetrics(filterRecent(bucket.entries, 7));
95
+ const recent30d = aggregateMetrics(filterRecent(bucket.entries, 30));
96
+ bySubsystem[subsystem] = {
97
+ precision: all.precision,
98
+ recall: all.recall,
99
+ falseNegativeRate: all.falseNegativeRate,
100
+ samples: all.samples,
101
+ recent7d,
102
+ recent30d,
103
+ };
104
+ }
105
+ const overall = aggregateMetrics(entries);
106
+ const recent7d = aggregateMetrics(filterRecent(entries, 7));
107
+ const recent30d = aggregateMetrics(filterRecent(entries, 30));
108
+ return {
109
+ schemaVersion: '1.1.0',
110
+ generatedAt: new Date().toISOString(),
111
+ samples: entries.length,
112
+ overall,
113
+ recent7d,
114
+ recent30d,
115
+ bySubsystem,
116
+ };
117
+ }
118
+ function rateFor(runs, failed) {
119
+ return runs > 0 ? Number((failed / runs).toFixed(4)) : 0;
120
+ }
121
+ function trendFor(rate7d, rate30d) {
122
+ if (rate7d - rate30d >= 0.08) {
123
+ return 'up';
124
+ }
125
+ if (rate30d - rate7d >= 0.08) {
126
+ return 'down';
127
+ }
128
+ return 'stable';
129
+ }
130
+ function loadOwners(appRoot) {
131
+ const path = join(appRoot, '.e2e-ai-agents', 'subsystem-owners.json');
132
+ const manifest = readJson(path);
133
+ if (!manifest) {
134
+ return {};
135
+ }
136
+ if (manifest.ownersBySubsystem) {
137
+ return manifest.ownersBySubsystem;
138
+ }
139
+ if (manifest.subsystems) {
140
+ return manifest.subsystems;
141
+ }
142
+ return {};
143
+ }
144
+ function daysSince(value) {
145
+ if (!value) {
146
+ return null;
147
+ }
148
+ const time = parseTimestamp(value);
149
+ if (time === null) {
150
+ return null;
151
+ }
152
+ return (Date.now() - time) / (24 * 60 * 60 * 1000);
153
+ }
154
+ function aggregateFlaky(entries, appRoot) {
155
+ const acc = new Map();
156
+ const cutoff7 = Date.now() - 7 * 24 * 60 * 60 * 1000;
157
+ const cutoff30 = Date.now() - 30 * 24 * 60 * 60 * 1000;
158
+ const ownersBySubsystem = loadOwners(appRoot);
159
+ for (const entry of entries) {
160
+ const executed = asSet(entry.executedTests || []);
161
+ const failed = asSet(entry.failedTests || []);
162
+ const time = parseTimestamp(entry.timestamp);
163
+ for (const test of executed) {
164
+ const bucket = acc.get(test) || {
165
+ runs: 0,
166
+ failed: 0,
167
+ runs7d: 0,
168
+ failed7d: 0,
169
+ runs30d: 0,
170
+ failed30d: 0,
171
+ lastFailureAt: undefined,
172
+ };
173
+ bucket.runs += 1;
174
+ if (time !== null && time >= cutoff7) {
175
+ bucket.runs7d += 1;
176
+ }
177
+ if (time !== null && time >= cutoff30) {
178
+ bucket.runs30d += 1;
179
+ }
180
+ if (failed.has(test)) {
181
+ bucket.failed += 1;
182
+ bucket.lastFailureAt = entry.timestamp;
183
+ if (time !== null && time >= cutoff7) {
184
+ bucket.failed7d += 1;
185
+ }
186
+ if (time !== null && time >= cutoff30) {
187
+ bucket.failed30d += 1;
188
+ }
189
+ }
190
+ acc.set(test, bucket);
191
+ }
192
+ }
193
+ const tests = Array.from(acc.entries())
194
+ .map(([test, bucket]) => {
195
+ const flakeRate = rateFor(bucket.runs, bucket.failed);
196
+ const flakeRate7d = rateFor(bucket.runs7d, bucket.failed7d);
197
+ const flakeRate30d = rateFor(bucket.runs30d, bucket.failed30d);
198
+ const trend = trendFor(flakeRate7d, flakeRate30d);
199
+ const quarantine = (bucket.runs30d >= 5 && flakeRate30d >= 0.35) || (bucket.runs >= 8 && flakeRate >= 0.4);
200
+ const daysFromLastFailure = daysSince(bucket.lastFailureAt);
201
+ const quarantineState = quarantine
202
+ ? (daysFromLastFailure !== null && daysFromLastFailure >= 14 && flakeRate7d <= 0.05 ? 'retire-candidate' : 'active')
203
+ : 'none';
204
+ const subsystem = subsystemForTest(test);
205
+ const owners = ownersBySubsystem[subsystem] || [];
206
+ return {
207
+ test,
208
+ subsystem,
209
+ owners,
210
+ flakeRate,
211
+ flakeRate7d,
212
+ flakeRate30d,
213
+ trend,
214
+ quarantine,
215
+ quarantineState,
216
+ lastFailureAt: bucket.lastFailureAt,
217
+ samples: bucket.runs,
218
+ samples7d: bucket.runs7d,
219
+ samples30d: bucket.runs30d,
220
+ };
221
+ })
222
+ .filter((entry) => entry.flakeRate > 0)
223
+ .sort((a, b) => (b.flakeRate30d || b.flakeRate) - (a.flakeRate30d || a.flakeRate));
224
+ return {
225
+ schemaVersion: '1.1.0',
226
+ generatedAt: new Date().toISOString(),
227
+ tests,
228
+ };
229
+ }
230
+ export function appendFeedbackAndRecompute(appRoot, input) {
231
+ const baseDir = join(appRoot, '.e2e-ai-agents');
232
+ mkdirSync(baseDir, { recursive: true });
233
+ const feedbackPath = join(baseDir, 'feedback.json');
234
+ const existing = readJson(feedbackPath) || { schemaVersion: '1.0.0', entries: [] };
235
+ existing.entries.push({
236
+ ...input,
237
+ recommendedTests: input.recommendedTests || [],
238
+ executedTests: input.executedTests || [],
239
+ failedTests: input.failedTests || [],
240
+ escapedFailures: input.escapedFailures || [],
241
+ });
242
+ writeFileSync(feedbackPath, JSON.stringify(existing, null, 2), 'utf-8');
243
+ const calibration = aggregate(existing.entries);
244
+ const calibrationPath = join(baseDir, 'calibration.json');
245
+ writeFileSync(calibrationPath, JSON.stringify(calibration, null, 2), 'utf-8');
246
+ const flaky = aggregateFlaky(existing.entries, appRoot);
247
+ const flakyPath = join(baseDir, 'flaky-tests.json');
248
+ writeFileSync(flakyPath, JSON.stringify(flaky, null, 2), 'utf-8');
249
+ return { feedbackPath, calibrationPath, calibration };
250
+ }
251
+ export function readCalibration(appRoot) {
252
+ return readJson(join(appRoot, '.e2e-ai-agents', 'calibration.json'));
253
+ }
254
+ const DEFAULT_MIN_CONFIDENCE = 60;
255
+ const DEFAULT_SAFE_MERGE = 85;
256
+ const MIN_CONFIDENCE_FLOOR = 40;
257
+ const MIN_CONFIDENCE_CEILING = 80;
258
+ /**
259
+ * Compute adaptive thresholds based on calibration data.
260
+ * - If recent recall < 0.8: lower minConfidence (catch more escapes)
261
+ * - If recent precision > 0.9: raise minConfidence (fewer unnecessary tests)
262
+ * - Per-subsystem: if falseNegativeRate > 0.3 in 30d, always include tests
263
+ * Returns defaults if no calibration data exists.
264
+ */
265
+ export function getAdaptiveThresholds(appRoot) {
266
+ const calibration = readCalibration(appRoot);
267
+ const reasons = [];
268
+ const alwaysInclude = [];
269
+ if (!calibration || calibration.samples === 0) {
270
+ return {
271
+ minConfidenceForTargeted: DEFAULT_MIN_CONFIDENCE,
272
+ safeMergeMinConfidence: DEFAULT_SAFE_MERGE,
273
+ alwaysIncludeSubsystems: [],
274
+ adjustmentReasons: ['No calibration data — using defaults'],
275
+ };
276
+ }
277
+ let minConfidence = DEFAULT_MIN_CONFIDENCE;
278
+ let safeMerge = DEFAULT_SAFE_MERGE;
279
+ // Adjust based on 7-day recall
280
+ if (calibration.recent7d.samples >= 3) {
281
+ if (calibration.recent7d.recall < 0.8) {
282
+ const adjustment = 10;
283
+ minConfidence -= adjustment;
284
+ safeMerge -= adjustment;
285
+ reasons.push(`Lowering confidence threshold by ${adjustment} (7d recall: ${calibration.recent7d.recall.toFixed(2)})`);
286
+ }
287
+ else if (calibration.recent7d.precision > 0.9) {
288
+ const adjustment = 5;
289
+ minConfidence += adjustment;
290
+ safeMerge += adjustment;
291
+ reasons.push(`Raising confidence threshold by ${adjustment} (7d precision: ${calibration.recent7d.precision.toFixed(2)})`);
292
+ }
293
+ }
294
+ // Clamp to safe ranges
295
+ minConfidence = Math.max(MIN_CONFIDENCE_FLOOR, Math.min(MIN_CONFIDENCE_CEILING, minConfidence));
296
+ safeMerge = Math.max(70, Math.min(95, safeMerge));
297
+ // Per-subsystem blind spot detection (30-day window)
298
+ for (const [subsystem, metrics] of Object.entries(calibration.bySubsystem)) {
299
+ const recent = metrics.recent30d;
300
+ if (recent.samples >= 3 && recent.falseNegativeRate > 0.3) {
301
+ alwaysInclude.push(subsystem);
302
+ reasons.push(`Always including ${subsystem} tests (30d false-negative rate: ${recent.falseNegativeRate.toFixed(2)})`);
303
+ }
304
+ }
305
+ if (reasons.length === 0) {
306
+ reasons.push('Calibration data within normal range — using defaults');
307
+ }
308
+ return {
309
+ minConfidenceForTargeted: minConfidence,
310
+ safeMergeMinConfidence: safeMerge,
311
+ alwaysIncludeSubsystems: alwaysInclude,
312
+ adjustmentReasons: reasons,
313
+ };
314
+ }
315
+ export function readFlakyTests(appRoot) {
316
+ return readJson(join(appRoot, '.e2e-ai-agents', 'flaky-tests.json'));
317
+ }
@@ -0,0 +1,252 @@
1
+ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2
+ // See LICENSE.txt for license information.
3
+ import { spawnSync } from 'child_process';
4
+ import { normalizePath } from './utils.js';
5
+ // Directories that contain CI/tooling/docs/tests — never relevant to impact analysis.
6
+ const IGNORED_DIR_SEGMENTS = [
7
+ '.github',
8
+ '.claude',
9
+ '.vscode',
10
+ '.idea',
11
+ 'node_modules',
12
+ 'e2e-tests',
13
+ '__tests__',
14
+ '__mocks__',
15
+ 'testlib',
16
+ 'scripts',
17
+ ];
18
+ // Exact filenames (basename) that are never relevant.
19
+ const IGNORED_BASENAMES = new Set([
20
+ 'package.json',
21
+ 'package-lock.json',
22
+ '.gitignore',
23
+ '.prettierignore',
24
+ '.prettierrc',
25
+ '.eslintrc',
26
+ '.eslintrc.js',
27
+ '.eslintrc.json',
28
+ '.editorconfig',
29
+ '.npmrc',
30
+ '.mcp.json',
31
+ 'CHANGELOG.md',
32
+ 'README.md',
33
+ 'LICENSE',
34
+ 'LICENSE.txt',
35
+ 'tsconfig.json',
36
+ 'jest.config.js',
37
+ 'jest.config.ts',
38
+ 'babel.config.js',
39
+ 'webpack.config.js',
40
+ 'Makefile',
41
+ 'config.mk',
42
+ 'go.mod',
43
+ 'go.sum',
44
+ ]);
45
+ // Extensions that are never source code.
46
+ const IGNORED_EXTENSIONS = new Set([
47
+ '.md',
48
+ '.txt',
49
+ '.lock',
50
+ '.png', '.jpg', '.jpeg', '.gif', '.svg', '.ico',
51
+ '.woff', '.woff2', '.ttf', '.eot',
52
+ '.yml', '.yaml',
53
+ '.sh',
54
+ ]);
55
+ // File patterns that indicate test/spec files (not production code).
56
+ const TEST_FILE_PATTERNS = [
57
+ /\.spec\.[tj]sx?$/,
58
+ /\.test\.[tj]sx?$/,
59
+ /_test\.go$/,
60
+ /\.stories\.[tj]sx?$/,
61
+ /\.d\.ts$/,
62
+ ];
63
+ // Config file patterns that are not production source code.
64
+ const CONFIG_FILE_PATTERNS = [
65
+ /\.config\.[tj]sx?$/,
66
+ /\.config\.json$/,
67
+ /\.config\.js$/,
68
+ ];
69
+ function isRelevantFile(file) {
70
+ const segments = file.split('/');
71
+ const basename = segments[segments.length - 1] || file;
72
+ if (IGNORED_BASENAMES.has(basename)) {
73
+ return false;
74
+ }
75
+ for (const seg of segments) {
76
+ if (IGNORED_DIR_SEGMENTS.includes(seg)) {
77
+ return false;
78
+ }
79
+ }
80
+ const dotIdx = basename.lastIndexOf('.');
81
+ if (dotIdx > 0) {
82
+ const ext = basename.slice(dotIdx).toLowerCase();
83
+ if (IGNORED_EXTENSIONS.has(ext)) {
84
+ return false;
85
+ }
86
+ }
87
+ // Filter test/spec files — they don't impact production features
88
+ for (const pattern of TEST_FILE_PATTERNS) {
89
+ if (pattern.test(basename)) {
90
+ return false;
91
+ }
92
+ }
93
+ // Filter config files
94
+ for (const pattern of CONFIG_FILE_PATTERNS) {
95
+ if (pattern.test(basename)) {
96
+ return false;
97
+ }
98
+ }
99
+ return true;
100
+ }
101
+ export function runGitRaw(args, cwd) {
102
+ const result = spawnSync('git', args, {
103
+ cwd,
104
+ encoding: 'utf-8',
105
+ timeout: 30000,
106
+ });
107
+ if (result.error || result.status !== 0) {
108
+ return null;
109
+ }
110
+ return result.stdout;
111
+ }
112
+ function runGit(args, cwd) {
113
+ const output = runGitRaw(args, cwd);
114
+ if (output === null) {
115
+ return null;
116
+ }
117
+ return output
118
+ .split('\n')
119
+ .map((file) => file.trim())
120
+ .filter(Boolean)
121
+ .map((file) => normalizePath(file));
122
+ }
123
+ function parseStatusLines(lines) {
124
+ const files = [];
125
+ for (const line of lines) {
126
+ if (!line)
127
+ continue;
128
+ if (line.length < 4)
129
+ continue;
130
+ const pathPart = line.slice(3).trim();
131
+ if (!pathPart)
132
+ continue;
133
+ if (pathPart.includes('->')) {
134
+ const parts = pathPart.split('->').map((part) => part.trim());
135
+ const target = parts[parts.length - 1];
136
+ if (target) {
137
+ files.push(normalizePath(target));
138
+ }
139
+ }
140
+ else {
141
+ files.push(normalizePath(pathPart));
142
+ }
143
+ }
144
+ return files;
145
+ }
146
+ // Comment-line patterns by file extension.
147
+ // A diff that ONLY touches these lines is a comment-only change (typo fix, doc update).
148
+ const COMMENT_PATTERNS = [
149
+ { extensions: ['.go'], pattern: /^\s*(\/\/|\/\*|\*)/ },
150
+ { extensions: ['.ts', '.tsx', '.js', '.jsx'], pattern: /^\s*(\/\/|\/\*|\*|\*\/)/ },
151
+ { extensions: ['.py'], pattern: /^\s*#/ },
152
+ { extensions: ['.css', '.scss'], pattern: /^\s*(\/\*|\*|\*\/)/ },
153
+ ];
154
+ /**
155
+ * Check if a file's diff only changes comment lines (no code changes).
156
+ * Returns true if the diff is comment-only and can be safely excluded.
157
+ */
158
+ function isCommentOnlyDiff(file, repoRoot, baseRef) {
159
+ const diff = runGitRaw(['diff', `${baseRef}..HEAD`, '-U0', '--', file], repoRoot);
160
+ if (!diff)
161
+ return false;
162
+ const ext = file.slice(file.lastIndexOf('.'));
163
+ const commentEntry = COMMENT_PATTERNS.find((cp) => cp.extensions.includes(ext));
164
+ if (!commentEntry)
165
+ return false;
166
+ // Extract only added/removed content lines (skip diff headers)
167
+ const contentLines = diff
168
+ .split('\n')
169
+ .filter((line) => (line.startsWith('+') || line.startsWith('-')) && !line.startsWith('+++') && !line.startsWith('---'));
170
+ if (contentLines.length === 0)
171
+ return false;
172
+ // Every changed line must be a comment line
173
+ return contentLines.every((line) => {
174
+ const content = line.slice(1).trim(); // Remove +/- prefix
175
+ return content === '' || commentEntry.pattern.test(content);
176
+ });
177
+ }
178
+ /**
179
+ * Check if a file path is a test file (spec, test, or in test directories).
180
+ * Shared across pipeline and crew orchestrators.
181
+ */
182
+ export function isTestFile(file) {
183
+ const normalized = file.replace(/\\/g, '/');
184
+ return /\.(spec|test)\.(ts|tsx|js|jsx)$/.test(normalized) ||
185
+ /\.snap$/.test(normalized) ||
186
+ /_test\.go$/.test(normalized) ||
187
+ normalized.includes('__tests__/') ||
188
+ normalized.includes('__snapshots__/') ||
189
+ normalized.includes('/tests/') ||
190
+ normalized.includes('/test/');
191
+ }
192
+ export function getChangedFiles(appRoot, since, options) {
193
+ try {
194
+ const files = new Set();
195
+ let baseRef = since;
196
+ let baseStrategy = 'direct';
197
+ const mergeBase = runGitRaw(['merge-base', since, 'HEAD'], appRoot);
198
+ if (mergeBase) {
199
+ const candidate = mergeBase
200
+ .split('\n')
201
+ .map((line) => line.trim())
202
+ .find(Boolean);
203
+ if (candidate) {
204
+ baseRef = candidate;
205
+ baseStrategy = 'merge-base';
206
+ }
207
+ }
208
+ // Get repo root so we capture ALL changed files (including server/, webapp/, etc.)
209
+ // not just files under the appRoot subdirectory.
210
+ const repoRoot = runGitRaw(['rev-parse', '--show-toplevel'], appRoot)?.trim() || appRoot;
211
+ const diffFiles = runGit(['diff', '--name-only', `${baseRef}..HEAD`], repoRoot);
212
+ if (!diffFiles) {
213
+ return { files: [], filteredTestFiles: [], error: 'git diff failed' };
214
+ }
215
+ diffFiles.forEach((file) => files.add(file));
216
+ if (options?.includeUncommitted) {
217
+ const staged = runGit(['diff', '--name-only', '--cached'], repoRoot) || [];
218
+ staged.forEach((file) => files.add(file));
219
+ const unstaged = runGit(['diff', '--name-only'], repoRoot) || [];
220
+ unstaged.forEach((file) => files.add(file));
221
+ const statusOutput = runGitRaw(['status', '--porcelain'], repoRoot);
222
+ if (statusOutput) {
223
+ const statusLines = statusOutput.split('\n').filter(Boolean);
224
+ parseStatusLines(statusLines).forEach((file) => files.add(file));
225
+ }
226
+ }
227
+ const allFiles = Array.from(files);
228
+ const relevant = [];
229
+ const filteredTestFiles = [];
230
+ for (const f of allFiles) {
231
+ if (isRelevantFile(f)) {
232
+ // Skip files where the diff only touches comments (typo fixes, doc updates)
233
+ if (isCommentOnlyDiff(f, repoRoot, baseRef)) {
234
+ continue;
235
+ }
236
+ relevant.push(f);
237
+ }
238
+ else {
239
+ // Only capture files that were filtered because they match test patterns.
240
+ // Config, docs, workflow files etc. are not useful for PR-test detection.
241
+ const basename = f.split('/').pop() || f;
242
+ if (TEST_FILE_PATTERNS.some((p) => p.test(basename))) {
243
+ filteredTestFiles.push(f);
244
+ }
245
+ }
246
+ }
247
+ return { files: relevant, filteredTestFiles, baseRef, baseStrategy };
248
+ }
249
+ catch {
250
+ return { files: [], filteredTestFiles: [], error: 'git diff failed' };
251
+ }
252
+ }