@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,177 @@
1
+ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2
+ // See LICENSE.txt for license information.
3
+ import { execFileSync } from 'child_process';
4
+ import { existsSync, readFileSync } from 'fs';
5
+ import { relative, resolve } from 'path';
6
+ function runCommand(bin, args, cwd, opts = {}) {
7
+ try {
8
+ const stdout = execFileSync(bin, args, { cwd, encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] });
9
+ return { ok: true, stdout: stdout.trim(), stderr: '' };
10
+ }
11
+ catch (error) {
12
+ if (opts.allowFailure) {
13
+ const cause = error;
14
+ const stdout = typeof cause.stdout === 'string' ? cause.stdout : cause.stdout?.toString('utf-8') || '';
15
+ const stderr = typeof cause.stderr === 'string' ? cause.stderr : cause.stderr?.toString('utf-8') || cause.message || '';
16
+ return { ok: false, stdout: stdout.trim(), stderr: stderr.trim() };
17
+ }
18
+ throw error;
19
+ }
20
+ }
21
+ function normalizeBranchName(branch) {
22
+ if (!branch || !branch.trim()) {
23
+ return undefined;
24
+ }
25
+ const trimmed = branch.trim();
26
+ if (trimmed.startsWith('codex/')) {
27
+ return trimmed;
28
+ }
29
+ return `codex/${trimmed.replace(/^\/+/, '')}`;
30
+ }
31
+ function resolveRepoRoot(appPath) {
32
+ const abs = resolve(appPath);
33
+ const result = runCommand('git', ['-C', abs, 'rev-parse', '--show-toplevel'], abs, { allowFailure: true });
34
+ if (!result.ok || !result.stdout) {
35
+ throw new Error(`Unable to find git repository root from ${abs}: ${result.stderr || 'git rev-parse failed'}`);
36
+ }
37
+ return result.stdout;
38
+ }
39
+ function readGapReport(path) {
40
+ if (!existsSync(path)) {
41
+ throw new Error(`Gap report not found: ${path}`);
42
+ }
43
+ try {
44
+ return JSON.parse(readFileSync(path, 'utf-8'));
45
+ }
46
+ catch (error) {
47
+ const message = error instanceof Error ? error.message : String(error);
48
+ throw new Error(`Unable to parse gap report at ${path}: ${message}`);
49
+ }
50
+ }
51
+ function uniq(values) {
52
+ return Array.from(new Set(values.filter(Boolean)));
53
+ }
54
+ function toRepoRelative(repoRoot, absoluteOrRelative) {
55
+ const absolute = resolve(absoluteOrRelative);
56
+ return relative(repoRoot, absolute) || '.';
57
+ }
58
+ function isRepoRelativePathSafe(path) {
59
+ if (!path || path === '.') {
60
+ return false;
61
+ }
62
+ if (path.startsWith('..') || path.includes('/../') || path.includes('\\..\\')) {
63
+ return false;
64
+ }
65
+ return true;
66
+ }
67
+ function collectStageTargets(repoRoot, appPath, testsRoot, gap) {
68
+ const targets = [];
69
+ const applied = gap.applied || {};
70
+ for (const patched of applied.patchedFiles || []) {
71
+ targets.push(toRepoRelative(repoRoot, resolve(appPath, patched)));
72
+ }
73
+ for (const generated of applied.generatedTests || []) {
74
+ targets.push(toRepoRelative(repoRoot, generated));
75
+ }
76
+ for (const result of gap.pipeline?.results || []) {
77
+ if (result.generatedDir) {
78
+ targets.push(toRepoRelative(repoRoot, result.generatedDir));
79
+ }
80
+ }
81
+ const artifacts = ['gap.json', 'impact.json', 'plan.json', 'ci-summary.md', 'pr-comment.md'];
82
+ for (const file of artifacts) {
83
+ targets.push(toRepoRelative(repoRoot, resolve(testsRoot, '.e2e-ai-agents', file)));
84
+ }
85
+ return uniq(targets).filter((path) => isRepoRelativePathSafe(path) && existsSync(resolve(repoRoot, path)));
86
+ }
87
+ function ensureBranch(repoRoot, requestedBranch, dryRun = false) {
88
+ const current = runCommand('git', ['branch', '--show-current'], repoRoot, { allowFailure: true });
89
+ const currentBranch = current.stdout || 'HEAD';
90
+ const normalized = normalizeBranchName(requestedBranch);
91
+ if (!normalized) {
92
+ return currentBranch;
93
+ }
94
+ if (currentBranch === normalized) {
95
+ return currentBranch;
96
+ }
97
+ const exists = runCommand('git', ['rev-parse', '--verify', normalized], repoRoot, { allowFailure: true }).ok;
98
+ if (!dryRun) {
99
+ if (exists) {
100
+ runCommand('git', ['checkout', normalized], repoRoot);
101
+ }
102
+ else {
103
+ runCommand('git', ['checkout', '-b', normalized], repoRoot);
104
+ }
105
+ }
106
+ return normalized;
107
+ }
108
+ function hasStagedChanges(repoRoot) {
109
+ const result = runCommand('git', ['diff', '--cached', '--name-only'], repoRoot, { allowFailure: true });
110
+ if (!result.ok) {
111
+ return false;
112
+ }
113
+ return result.stdout.trim().length > 0;
114
+ }
115
+ export function finalizeGeneratedTests(options) {
116
+ const appPath = resolve(options.appPath);
117
+ const testsRoot = resolve(options.testsRoot || options.appPath);
118
+ const repoRoot = resolveRepoRoot(appPath);
119
+ const gapReportPath = options.gapReportPath || resolve(testsRoot, '.e2e-ai-agents', 'gap.json');
120
+ const gap = readGapReport(gapReportPath);
121
+ const stageTargets = collectStageTargets(repoRoot, appPath, testsRoot, gap);
122
+ const commitMessage = options.commitMessage || 'test(e2e): add generated coverage and healed specs';
123
+ const dryRun = Boolean(options.dryRun);
124
+ const branch = ensureBranch(repoRoot, options.branch, dryRun);
125
+ if (stageTargets.length === 0) {
126
+ return {
127
+ repoRoot,
128
+ branch,
129
+ stagedPaths: [],
130
+ committed: false,
131
+ };
132
+ }
133
+ for (const path of stageTargets) {
134
+ if (!dryRun) {
135
+ runCommand('git', ['add', '--', path], repoRoot, { allowFailure: true });
136
+ }
137
+ }
138
+ let committed = false;
139
+ let commitSha;
140
+ if (!dryRun && hasStagedChanges(repoRoot)) {
141
+ runCommand('git', ['commit', '-m', commitMessage], repoRoot);
142
+ committed = true;
143
+ const head = runCommand('git', ['rev-parse', 'HEAD'], repoRoot, { allowFailure: true });
144
+ if (head.ok) {
145
+ commitSha = head.stdout;
146
+ }
147
+ }
148
+ let prUrl;
149
+ if (!dryRun && options.createPr) {
150
+ const args = ['pr', 'create'];
151
+ if (options.prTitle) {
152
+ args.push('--title', options.prTitle);
153
+ }
154
+ if (options.prBody) {
155
+ args.push('--body', options.prBody);
156
+ }
157
+ if (options.baseBranch) {
158
+ args.push('--base', options.baseBranch);
159
+ }
160
+ if (!options.prTitle && !options.prBody) {
161
+ args.push('--fill');
162
+ }
163
+ const result = runCommand('gh', args, repoRoot, { allowFailure: true });
164
+ if (!result.ok) {
165
+ throw new Error(`Failed to create PR via gh: ${result.stderr || 'unknown error'}`);
166
+ }
167
+ prUrl = result.stdout.split('\n').find((line) => line.startsWith('http')) || result.stdout;
168
+ }
169
+ return {
170
+ repoRoot,
171
+ branch,
172
+ stagedPaths: stageTargets,
173
+ committed,
174
+ commitSha,
175
+ prUrl,
176
+ };
177
+ }
@@ -0,0 +1,421 @@
1
+ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2
+ // See LICENSE.txt for license information.
3
+ import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'fs';
4
+ import { join, relative, resolve } from 'path';
5
+ import { isPathWithinRoot, normalizePath } from './utils.js';
6
+ import { createMcpStatus, firstFlowFiles, toSafeSlug } from './pipeline_utils.js';
7
+ import { validateGeneratedSpecContent } from './spec_generator.js';
8
+ import { resolvePlaywrightBinary, runCommand, runCommandWithRetries, summarizeCommandOutput, resolveMcpCommandTimeoutMs, resolveMcpRetries } from './process_runner.js';
9
+ import { runPlaywrightListValidation, runPlaywrightRuntimeValidation } from './validation_runner.js';
10
+ import { buildApiSurfaceCatalog } from './api_catalog.js';
11
+ export function findSpecFiles(root) {
12
+ if (!existsSync(root)) {
13
+ return [];
14
+ }
15
+ const entries = readdirSync(root, { withFileTypes: true });
16
+ const files = [];
17
+ for (const entry of entries) {
18
+ const fullPath = join(root, entry.name);
19
+ if (entry.isDirectory()) {
20
+ files.push(...findSpecFiles(fullPath));
21
+ }
22
+ else if (entry.isFile() && entry.name.endsWith('.spec.ts')) {
23
+ files.push(fullPath);
24
+ }
25
+ }
26
+ return files;
27
+ }
28
+ export function findDisallowedDescribeFiles(root) {
29
+ const files = findSpecFiles(root);
30
+ return files.filter((file) => /\btest\.describe\s*\(/.test(readFileSync(file, 'utf-8')));
31
+ }
32
+ export function hasCommand(command, cwd) {
33
+ const result = runCommand(command, ['--version'], cwd);
34
+ return result.status === 0;
35
+ }
36
+ export function hasPlaywrightAgentDefinitions(testsRoot) {
37
+ const required = [
38
+ '.mcp.json',
39
+ '.claude/agents/playwright-test-planner.md',
40
+ '.claude/agents/playwright-test-generator.md',
41
+ '.claude/agents/playwright-test-healer.md',
42
+ ];
43
+ return required.every((path) => existsSync(join(testsRoot, path)));
44
+ }
45
+ export function hasPlaywrightConfig(testsRoot) {
46
+ const candidates = [
47
+ 'playwright.config.ts',
48
+ 'playwright.config.js',
49
+ 'playwright.config.mts',
50
+ 'playwright.config.mjs',
51
+ 'playwright.config.cts',
52
+ 'playwright.config.cjs',
53
+ ];
54
+ return candidates.some((candidate) => existsSync(join(testsRoot, candidate)));
55
+ }
56
+ export function bootstrapPlaywrightAgentDefinitions(testsRoot, pipeline, timeoutMs) {
57
+ const args = ['playwright', 'init-agents', '--loop=claude', '--prompts'];
58
+ if (pipeline.project) {
59
+ args.push('--project', pipeline.project);
60
+ }
61
+ return runCommand('npx', args, testsRoot, timeoutMs);
62
+ }
63
+ export function resolveAgentSeedSpec(testsRoot) {
64
+ const preferred = join(testsRoot, 'specs', 'seed.spec.ts');
65
+ const specsRoot = join(testsRoot, 'specs');
66
+ const specFiles = findSpecFiles(specsRoot).filter((file) => !normalizePath(file).includes('/functional/ai-assisted/'));
67
+ const scored = specFiles
68
+ .map((file) => {
69
+ const rel = normalizePath(relative(testsRoot, file));
70
+ const content = readFileSync(file, 'utf-8');
71
+ let score = 0;
72
+ if (rel.endsWith('/seed.spec.ts')) {
73
+ // Generated default seed from init-agents is often a placeholder; prefer real tests.
74
+ if (!/generate code here/i.test(content)) {
75
+ score += 2;
76
+ }
77
+ }
78
+ if (content.includes('@mattermost/playwright-lib')) {
79
+ score += 8;
80
+ }
81
+ if (content.includes('pw.initSetup(')) {
82
+ score += 6;
83
+ }
84
+ if (content.includes('testBrowser.login(')) {
85
+ score += 4;
86
+ }
87
+ if (content.includes('channelsPage')) {
88
+ score += 2;
89
+ }
90
+ if (rel.includes('/functional/channels/')) {
91
+ score += 1;
92
+ }
93
+ return { rel, score };
94
+ })
95
+ .sort((a, b) => b.score - a.score);
96
+ if (scored.length > 0 && scored[0].score > 0) {
97
+ return scored[0].rel;
98
+ }
99
+ if (existsSync(preferred)) {
100
+ return normalizePath(relative(testsRoot, preferred));
101
+ }
102
+ return null;
103
+ }
104
+ export function buildPlaywrightAgentsPrompt(flow, seedFile, planFile, testFile, includeHealer) {
105
+ const linkedFiles = firstFlowFiles(flow).join(', ') || 'N/A';
106
+ const reasons = (flow.reasons || []).slice(0, 5).join(' | ') || 'N/A';
107
+ return [
108
+ 'Use official Playwright Test agents (planner, generator, healer) to implement exactly one high-quality test for this flow.',
109
+ '',
110
+ `Flow ID: ${flow.id}`,
111
+ `Flow Name: ${flow.name}`,
112
+ `Priority: ${flow.priority}`,
113
+ `Linked files: ${linkedFiles}`,
114
+ `Risk reasons: ${reasons}`,
115
+ '',
116
+ 'Workflow requirements:',
117
+ '1) Use #playwright-test-planner to explore and save a focused test plan.',
118
+ '2) Use #playwright-test-generator to generate one test from that plan.',
119
+ includeHealer
120
+ ? '3) Use #playwright-test-healer to run and fix that generated test.'
121
+ : '3) Skip runtime healing and focus on producing compile-ready test code.',
122
+ '',
123
+ `Seed file: ${seedFile}`,
124
+ `Plan file to save: ${planFile}`,
125
+ `Generated test file path (must be exact): ${testFile}`,
126
+ '',
127
+ 'Quality constraints (must follow):',
128
+ '- The generated file must contain a standalone test() and must not use test.describe or test.only.',
129
+ '- Do not mark the test with test.fixme unless user explicitly requests skipping.',
130
+ "- The generated test must include a single tag string '@ai-assisted'.",
131
+ '- Match fixture/import style from the seed file. Prefer existing page-object APIs over raw brittle selectors.',
132
+ '- Only use `pw` and page-object methods that already exist in the seed/current specs (for example, do not invent APIs like `pw.mainClient.*`).',
133
+ '- For system-console/admin flows, avoid `systemConsolePage.toBeVisible()` and brittle class selectors (`.backstage-navbar`, `.admin-console__wrapper`, `.left-panel`, `.panel-card`).',
134
+ '- Prefer stable assertions using URL patterns, test IDs, roles, labels, and established page-object methods.',
135
+ '- Keep the scenario strictly aligned to the flow and linked files, not broad unrelated flows.',
136
+ '',
137
+ 'At the end, return a short summary that includes the generated test file path and whether healing succeeded.',
138
+ ].join('\n');
139
+ }
140
+ export function buildPlaywrightHealerPrompt(testFile, extra) {
141
+ const lines = [
142
+ 'Heal this specific Playwright test file and keep edits minimal.',
143
+ `Target test file: ${testFile}`,
144
+ 'Constraints:',
145
+ '- Do not use test.describe or test.only.',
146
+ "- Keep a single tag string '@ai-assisted'.",
147
+ '- Use only existing Mattermost Playwright fixture/page-object APIs; do not invent new `pw.*` clients or methods.',
148
+ '- Avoid `systemConsolePage.toBeVisible()` and brittle class selectors (`.backstage-navbar`, `.admin-console__wrapper`, `.left-panel`, `.panel-card`).',
149
+ '- Prefer stable checks with URL/test IDs/roles/page-object methods.',
150
+ '- Keep the test intent unchanged and focused.',
151
+ '',
152
+ 'Run and fix this test until it compiles/passes, or mark test.fixme with a clear comment when behavior is truly broken.',
153
+ ];
154
+ if (extra) {
155
+ lines.push('', `Context: ${extra}`);
156
+ }
157
+ return lines.join('\n');
158
+ }
159
+ export function runPlaywrightAgentsFlow(testsRoot, flow, pipeline, outputDir, preferredTestFile, seedFile, apiSurface, playwrightBinary, mcpTimeoutMs, mcpRetries) {
160
+ mkdirSync(outputDir, { recursive: true });
161
+ const slug = toSafeSlug(flow.id);
162
+ const planFile = normalizePath(relative(testsRoot, join(outputDir, `${slug}.plan.md`)));
163
+ const absolutePlanFile = join(testsRoot, planFile);
164
+ const targetTestFile = normalizePath(relative(testsRoot, preferredTestFile));
165
+ const existingSpecFiles = findSpecFiles(outputDir);
166
+ const existingSpecSnapshots = new Map();
167
+ for (const specFile of existingSpecFiles) {
168
+ try {
169
+ existingSpecSnapshots.set(specFile, readFileSync(specFile, 'utf-8'));
170
+ }
171
+ catch {
172
+ continue;
173
+ }
174
+ }
175
+ const originalPlanContent = existsSync(absolutePlanFile) ? readFileSync(absolutePlanFile, 'utf-8') : null;
176
+ const restoreArtifactsOnFailure = () => {
177
+ for (const currentSpecFile of findSpecFiles(outputDir)) {
178
+ const originalSpecContent = existingSpecSnapshots.get(currentSpecFile);
179
+ if (originalSpecContent === undefined) {
180
+ rmSync(currentSpecFile, { force: true });
181
+ continue;
182
+ }
183
+ try {
184
+ if (readFileSync(currentSpecFile, 'utf-8') !== originalSpecContent) {
185
+ writeFileSync(currentSpecFile, originalSpecContent, 'utf-8');
186
+ }
187
+ }
188
+ catch {
189
+ // best-effort restore only
190
+ }
191
+ }
192
+ for (const [specFile, originalSpecContent] of existingSpecSnapshots.entries()) {
193
+ if (!existsSync(specFile)) {
194
+ writeFileSync(specFile, originalSpecContent, 'utf-8');
195
+ }
196
+ }
197
+ if (originalPlanContent === null) {
198
+ rmSync(absolutePlanFile, { force: true });
199
+ }
200
+ else {
201
+ try {
202
+ if (!existsSync(absolutePlanFile) || readFileSync(absolutePlanFile, 'utf-8') !== originalPlanContent) {
203
+ writeFileSync(absolutePlanFile, originalPlanContent, 'utf-8');
204
+ }
205
+ }
206
+ catch {
207
+ // best-effort restore only
208
+ }
209
+ }
210
+ };
211
+ const failFlow = (error) => {
212
+ restoreArtifactsOnFailure();
213
+ return {
214
+ flowId: flow.id,
215
+ flowName: flow.name,
216
+ generatedDir: outputDir,
217
+ generateStatus: 'failed',
218
+ healStatus: pipeline.heal ? 'failed' : undefined,
219
+ error,
220
+ };
221
+ };
222
+ if (pipeline.dryRun) {
223
+ return {
224
+ flowId: flow.id,
225
+ flowName: flow.name,
226
+ generatedDir: outputDir,
227
+ generateStatus: 'skipped',
228
+ healStatus: pipeline.heal ? 'skipped' : undefined,
229
+ };
230
+ }
231
+ const prompt = buildPlaywrightAgentsPrompt(flow, seedFile, planFile, targetTestFile, Boolean(pipeline.heal));
232
+ const runArgs = [
233
+ '-p',
234
+ '--permission-mode',
235
+ 'bypassPermissions',
236
+ '--setting-sources',
237
+ 'project,local',
238
+ '--strict-mcp-config',
239
+ '--mcp-config',
240
+ '.mcp.json',
241
+ '--add-dir',
242
+ testsRoot,
243
+ '--',
244
+ prompt,
245
+ ];
246
+ const runResult = runCommandWithRetries('claude', runArgs, testsRoot, mcpTimeoutMs, mcpRetries);
247
+ if (runResult.status !== 0) {
248
+ return failFlow(summarizeCommandOutput(runResult.stdout, runResult.stderr) || runResult.error || 'Playwright agents run failed');
249
+ }
250
+ let actualTestFile = preferredTestFile;
251
+ if (!existsSync(actualTestFile)) {
252
+ const candidates = findSpecFiles(outputDir);
253
+ if (candidates.length === 1) {
254
+ actualTestFile = candidates[0];
255
+ }
256
+ }
257
+ if (!existsSync(actualTestFile)) {
258
+ return failFlow(`Playwright agents did not produce expected test file: ${targetTestFile}`);
259
+ }
260
+ const relativeActualTestFile = normalizePath(relative(testsRoot, actualTestFile));
261
+ let qualityIssues = validateGeneratedSpecContent(readFileSync(actualTestFile, 'utf-8'), apiSurface);
262
+ if (qualityIssues.length > 0 && pipeline.heal) {
263
+ const healResult = runCommandWithRetries('claude', [
264
+ '-p',
265
+ '--permission-mode',
266
+ 'bypassPermissions',
267
+ '--setting-sources',
268
+ 'project,local',
269
+ '--strict-mcp-config',
270
+ '--agent',
271
+ 'playwright-test-healer',
272
+ '--mcp-config',
273
+ '.mcp.json',
274
+ '--add-dir',
275
+ testsRoot,
276
+ '--',
277
+ buildPlaywrightHealerPrompt(relativeActualTestFile, qualityIssues.map((issue) => issue.message).join(' | ')),
278
+ ], testsRoot, mcpTimeoutMs, mcpRetries);
279
+ if (healResult.status === 0 && existsSync(actualTestFile)) {
280
+ qualityIssues = validateGeneratedSpecContent(readFileSync(actualTestFile, 'utf-8'), apiSurface);
281
+ }
282
+ }
283
+ if (qualityIssues.length > 0) {
284
+ return failFlow(`Playwright agents produced invalid test content: ${qualityIssues.map((issue) => issue.message).join(' | ')}`);
285
+ }
286
+ if (pipeline.heal) {
287
+ let compileValidation = runPlaywrightListValidation(testsRoot, actualTestFile, pipeline, playwrightBinary);
288
+ if (compileValidation.status === 'failed') {
289
+ const healResult = runCommandWithRetries('claude', [
290
+ '-p',
291
+ '--permission-mode',
292
+ 'bypassPermissions',
293
+ '--setting-sources',
294
+ 'project,local',
295
+ '--strict-mcp-config',
296
+ '--agent',
297
+ 'playwright-test-healer',
298
+ '--mcp-config',
299
+ '.mcp.json',
300
+ '--add-dir',
301
+ testsRoot,
302
+ '--',
303
+ buildPlaywrightHealerPrompt(relativeActualTestFile, compileValidation.detail || 'playwright --list failed'),
304
+ ], testsRoot, mcpTimeoutMs, mcpRetries);
305
+ if (healResult.status === 0 && existsSync(actualTestFile)) {
306
+ compileValidation = runPlaywrightListValidation(testsRoot, actualTestFile, pipeline, playwrightBinary);
307
+ }
308
+ if (compileValidation.status === 'failed') {
309
+ return failFlow(`Playwright agents compile validation failed: ${compileValidation.detail || 'playwright --list failed'}`);
310
+ }
311
+ }
312
+ let runtimeValidation = runPlaywrightRuntimeValidation(testsRoot, actualTestFile, pipeline, playwrightBinary);
313
+ if (runtimeValidation.status === 'failed') {
314
+ const healResult = runCommandWithRetries('claude', [
315
+ '-p',
316
+ '--permission-mode',
317
+ 'bypassPermissions',
318
+ '--setting-sources',
319
+ 'project,local',
320
+ '--strict-mcp-config',
321
+ '--agent',
322
+ 'playwright-test-healer',
323
+ '--mcp-config',
324
+ '.mcp.json',
325
+ '--add-dir',
326
+ testsRoot,
327
+ '--',
328
+ buildPlaywrightHealerPrompt(relativeActualTestFile, runtimeValidation.detail || 'playwright runtime failed'),
329
+ ], testsRoot, mcpTimeoutMs, mcpRetries);
330
+ if (healResult.status === 0 && existsSync(actualTestFile)) {
331
+ runtimeValidation = runPlaywrightRuntimeValidation(testsRoot, actualTestFile, pipeline, playwrightBinary);
332
+ }
333
+ if (runtimeValidation.status === 'failed') {
334
+ return failFlow(`Playwright agents runtime validation failed: ${runtimeValidation.detail || 'playwright test failed'}`);
335
+ }
336
+ }
337
+ }
338
+ return {
339
+ flowId: flow.id,
340
+ flowName: flow.name,
341
+ generatedDir: outputDir,
342
+ generateStatus: 'success',
343
+ healStatus: pipeline.heal ? 'success' : undefined,
344
+ };
345
+ }
346
+ export function runPlaywrightAgentsPipeline(testsRoot, flows, pipeline) {
347
+ const warnings = [];
348
+ const results = [];
349
+ const mcpTimeoutMs = resolveMcpCommandTimeoutMs(pipeline);
350
+ const mcpRetries = resolveMcpRetries(pipeline);
351
+ if (!hasCommand('claude', testsRoot)) {
352
+ warnings.push('Claude CLI is required for official Playwright planner/generator/healer execution but was not found.');
353
+ return { runner: 'unknown', results, warnings, mcp: createMcpStatus('unknown', true) };
354
+ }
355
+ if (!hasPlaywrightConfig(testsRoot)) {
356
+ warnings.push('Playwright config file not found in testsRoot; skipping official Playwright agents backend.');
357
+ return { runner: 'unknown', results, warnings, mcp: createMcpStatus('unknown', true) };
358
+ }
359
+ if (!hasPlaywrightAgentDefinitions(testsRoot)) {
360
+ const bootstrap = bootstrapPlaywrightAgentDefinitions(testsRoot, pipeline, mcpTimeoutMs);
361
+ if (bootstrap.status !== 0) {
362
+ warnings.push(summarizeCommandOutput(bootstrap.stdout, bootstrap.stderr) ||
363
+ bootstrap.error ||
364
+ 'Failed to initialize Playwright agents via `npx playwright init-agents`.');
365
+ return { runner: 'unknown', results, warnings, mcp: createMcpStatus('unknown', true) };
366
+ }
367
+ }
368
+ if (!hasPlaywrightAgentDefinitions(testsRoot)) {
369
+ warnings.push('Playwright agent definitions are missing after bootstrap.');
370
+ return { runner: 'unknown', results, warnings, mcp: createMcpStatus('unknown', true) };
371
+ }
372
+ const seedFile = resolveAgentSeedSpec(testsRoot);
373
+ if (!seedFile) {
374
+ warnings.push('No seed spec file found under specs/. Playwright planner cannot be initialized.');
375
+ return { runner: 'unknown', results, warnings, mcp: createMcpStatus('unknown', true) };
376
+ }
377
+ const playwrightBinary = pipeline.heal ? resolvePlaywrightBinary(testsRoot) : null;
378
+ const apiSurface = buildApiSurfaceCatalog(testsRoot, seedFile);
379
+ if (pipeline.heal && !playwrightBinary) {
380
+ warnings.push('Playwright binary was not found. Healer runtime validation may be limited.');
381
+ }
382
+ const outputBase = resolve(testsRoot, pipeline.outputDir || 'specs/functional/ai-assisted');
383
+ if (!isPathWithinRoot(testsRoot, outputBase)) {
384
+ warnings.push(`Pipeline outputDir resolves outside testsRoot and was blocked: ${pipeline.outputDir}`);
385
+ return { runner: 'unknown', results, warnings, mcp: createMcpStatus('unknown', true) };
386
+ }
387
+ for (const flow of flows) {
388
+ if (flow.priority !== 'P0' && flow.priority !== 'P1') {
389
+ continue;
390
+ }
391
+ const slug = toSafeSlug(flow.id);
392
+ const outputDir = normalizePath(join(outputBase, slug));
393
+ if (!isPathWithinRoot(testsRoot, outputDir)) {
394
+ results.push({
395
+ flowId: flow.id,
396
+ flowName: flow.name,
397
+ generatedDir: outputDir,
398
+ generateStatus: 'failed',
399
+ error: 'output directory resolves outside testsRoot',
400
+ });
401
+ continue;
402
+ }
403
+ const testFile = normalizePath(join(outputDir, `${slug}.spec.ts`));
404
+ if (!isPathWithinRoot(testsRoot, testFile)) {
405
+ results.push({
406
+ flowId: flow.id,
407
+ flowName: flow.name,
408
+ generatedDir: outputDir,
409
+ generateStatus: 'failed',
410
+ error: 'generated test path resolves outside testsRoot',
411
+ });
412
+ continue;
413
+ }
414
+ results.push(runPlaywrightAgentsFlow(testsRoot, flow, pipeline, outputDir, testFile, seedFile, apiSurface, playwrightBinary, mcpTimeoutMs, mcpRetries));
415
+ if (pipeline.mcpOnly && results[results.length - 1].generateStatus === 'failed') {
416
+ warnings.push(`MCP-only mode: stopping after first failed flow (${flow.id}).`);
417
+ break;
418
+ }
419
+ }
420
+ return { runner: 'playwright-agents', results, warnings, mcp: createMcpStatus('playwright-agents', true) };
421
+ }