@yasserkhanorg/e2e-agents 1.8.5 → 1.10.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 (274) hide show
  1. package/README.md +95 -8
  2. package/dist/adapters/cypress.d.ts +10 -0
  3. package/dist/adapters/cypress.d.ts.map +1 -0
  4. package/dist/adapters/cypress.js +86 -0
  5. package/dist/adapters/framework_adapter.d.ts +41 -0
  6. package/dist/adapters/framework_adapter.d.ts.map +1 -0
  7. package/dist/adapters/framework_adapter.js +152 -0
  8. package/dist/adapters/playwright.d.ts +10 -0
  9. package/dist/adapters/playwright.d.ts.map +1 -0
  10. package/dist/adapters/playwright.js +86 -0
  11. package/dist/adapters/pytest.d.ts +10 -0
  12. package/dist/adapters/pytest.d.ts.map +1 -0
  13. package/dist/adapters/pytest.js +96 -0
  14. package/dist/adapters/supertest.d.ts +12 -0
  15. package/dist/adapters/supertest.d.ts.map +1 -0
  16. package/dist/adapters/supertest.js +85 -0
  17. package/dist/agent/config.d.ts +1 -1
  18. package/dist/agent/config.d.ts.map +1 -1
  19. package/dist/agent/git.d.ts +1 -0
  20. package/dist/agent/git.d.ts.map +1 -1
  21. package/dist/agent/git.js +3 -0
  22. package/dist/agentic/fix_loop.d.ts.map +1 -1
  23. package/dist/agentic/fix_loop.js +5 -4
  24. package/dist/agentic/runner.d.ts +2 -0
  25. package/dist/agentic/runner.d.ts.map +1 -1
  26. package/dist/agentic/runner.js +15 -12
  27. package/dist/agents/cross-impact.d.ts.map +1 -1
  28. package/dist/agents/cross-impact.js +6 -1
  29. package/dist/agents/executor.d.ts.map +1 -1
  30. package/dist/agents/executor.js +6 -1
  31. package/dist/agents/strategist.d.ts.map +1 -1
  32. package/dist/agents/strategist.js +6 -1
  33. package/dist/agents/test-designer.d.ts.map +1 -1
  34. package/dist/agents/test-designer.js +6 -1
  35. package/dist/anthropic_provider.d.ts.map +1 -1
  36. package/dist/anthropic_provider.js +1 -0
  37. package/dist/base_provider.d.ts +56 -0
  38. package/dist/base_provider.d.ts.map +1 -1
  39. package/dist/base_provider.js +123 -1
  40. package/dist/budget_ledger.d.ts +28 -0
  41. package/dist/budget_ledger.d.ts.map +1 -0
  42. package/dist/budget_ledger.js +62 -0
  43. package/dist/cache/cached_provider.d.ts +45 -0
  44. package/dist/cache/cached_provider.d.ts.map +1 -0
  45. package/dist/cache/cached_provider.js +88 -0
  46. package/dist/cache/response_cache.d.ts +79 -0
  47. package/dist/cache/response_cache.d.ts.map +1 -0
  48. package/dist/cache/response_cache.js +177 -0
  49. package/dist/cli/commands/bootstrap.d.ts +3 -0
  50. package/dist/cli/commands/bootstrap.d.ts.map +1 -0
  51. package/dist/cli/commands/bootstrap.js +109 -0
  52. package/dist/cli/commands/cost_report.d.ts +3 -0
  53. package/dist/cli/commands/cost_report.d.ts.map +1 -0
  54. package/dist/cli/commands/cost_report.js +115 -0
  55. package/dist/cli/commands/crew.d.ts.map +1 -1
  56. package/dist/cli/commands/crew.js +118 -1
  57. package/dist/cli/commands/gate.d.ts +3 -0
  58. package/dist/cli/commands/gate.d.ts.map +1 -0
  59. package/dist/cli/commands/gate.js +86 -0
  60. package/dist/cli/commands/init.d.ts.map +1 -1
  61. package/dist/cli/commands/init.js +7 -62
  62. package/dist/cli/commands/train.d.ts.map +1 -1
  63. package/dist/cli/commands/train.js +16 -21
  64. package/dist/cli/defaults.d.ts +35 -0
  65. package/dist/cli/defaults.d.ts.map +1 -0
  66. package/dist/cli/defaults.js +125 -0
  67. package/dist/cli/errors.d.ts +27 -0
  68. package/dist/cli/errors.d.ts.map +1 -0
  69. package/dist/cli/errors.js +57 -0
  70. package/dist/cli/parse_args.d.ts.map +1 -1
  71. package/dist/cli/parse_args.js +24 -2
  72. package/dist/cli/types.d.ts +7 -1
  73. package/dist/cli/types.d.ts.map +1 -1
  74. package/dist/cli.js +47 -2
  75. package/dist/crew/context.d.ts +15 -0
  76. package/dist/crew/context.d.ts.map +1 -1
  77. package/dist/crew/orchestrator.d.ts +14 -0
  78. package/dist/crew/orchestrator.d.ts.map +1 -1
  79. package/dist/crew/orchestrator.js +162 -4
  80. package/dist/crew/protocol.d.ts +13 -0
  81. package/dist/crew/protocol.d.ts.map +1 -1
  82. package/dist/crew/provider.d.ts +15 -1
  83. package/dist/crew/provider.d.ts.map +1 -1
  84. package/dist/crew/provider.js +24 -4
  85. package/dist/custom_provider.d.ts.map +1 -1
  86. package/dist/custom_provider.js +1 -0
  87. package/dist/engine/diff_loader.d.ts.map +1 -1
  88. package/dist/engine/diff_loader.js +3 -14
  89. package/dist/engine/impact_engine.d.ts.map +1 -1
  90. package/dist/engine/impact_engine.js +9 -23
  91. package/dist/esm/adapters/cypress.js +49 -0
  92. package/dist/esm/adapters/framework_adapter.js +114 -0
  93. package/dist/esm/adapters/playwright.js +49 -0
  94. package/dist/esm/adapters/pytest.js +59 -0
  95. package/dist/esm/adapters/supertest.js +48 -0
  96. package/dist/esm/agent/git.js +3 -1
  97. package/dist/esm/agentic/fix_loop.js +5 -4
  98. package/dist/esm/agentic/runner.js +15 -12
  99. package/dist/esm/agents/cross-impact.js +6 -1
  100. package/dist/esm/agents/executor.js +6 -1
  101. package/dist/esm/agents/strategist.js +6 -1
  102. package/dist/esm/agents/test-designer.js +6 -1
  103. package/dist/esm/anthropic_provider.js +1 -0
  104. package/dist/esm/base_provider.js +121 -0
  105. package/dist/esm/budget_ledger.js +58 -0
  106. package/dist/esm/cache/cached_provider.js +82 -0
  107. package/dist/esm/cache/response_cache.js +140 -0
  108. package/dist/esm/cli/commands/bootstrap.js +106 -0
  109. package/dist/esm/cli/commands/cost_report.js +112 -0
  110. package/dist/esm/cli/commands/crew.js +118 -1
  111. package/dist/esm/cli/commands/gate.js +83 -0
  112. package/dist/esm/cli/commands/init.js +3 -58
  113. package/dist/esm/cli/commands/train.js +16 -21
  114. package/dist/esm/cli/defaults.js +118 -0
  115. package/dist/esm/cli/errors.js +52 -0
  116. package/dist/esm/cli/parse_args.js +24 -2
  117. package/dist/esm/cli.js +47 -2
  118. package/dist/esm/crew/orchestrator.js +162 -4
  119. package/dist/esm/crew/provider.js +24 -4
  120. package/dist/esm/custom_provider.js +1 -0
  121. package/dist/esm/engine/diff_loader.js +1 -12
  122. package/dist/esm/engine/impact_engine.js +9 -23
  123. package/dist/esm/index.js +21 -0
  124. package/dist/esm/knowledge/api_surface.js +265 -34
  125. package/dist/esm/knowledge/cluster_utils.js +60 -0
  126. package/dist/esm/knowledge/failure_history.js +121 -0
  127. package/dist/esm/knowledge/kg_bridge.js +381 -0
  128. package/dist/esm/knowledge/kg_types.js +3 -0
  129. package/dist/esm/knowledge/route_families.js +119 -0
  130. package/dist/esm/mcp-server.js +2 -4
  131. package/dist/esm/metrics/prometheus.js +149 -0
  132. package/dist/esm/model_router.js +59 -0
  133. package/dist/esm/ollama_provider.js +1 -0
  134. package/dist/esm/openai_provider.js +1 -0
  135. package/dist/esm/pipeline/orchestrator.js +6 -12
  136. package/dist/esm/pipeline/stage0_preprocess.js +12 -19
  137. package/dist/esm/pipeline/stage1_impact.js +19 -3
  138. package/dist/esm/pipeline/stage2_coverage.js +29 -7
  139. package/dist/esm/pipeline/stage3_generation.js +21 -1
  140. package/dist/esm/progress.js +112 -0
  141. package/dist/esm/prompts/coverage.js +17 -24
  142. package/dist/esm/prompts/cross-impact.js +3 -21
  143. package/dist/esm/prompts/generation.js +201 -45
  144. package/dist/esm/prompts/generation_profile.js +147 -0
  145. package/dist/esm/prompts/heal.js +33 -15
  146. package/dist/esm/prompts/impact.js +3 -22
  147. package/dist/esm/prompts/json_extract.js +36 -0
  148. package/dist/esm/prompts/strategist.js +2 -20
  149. package/dist/esm/prompts/test-designer.js +6 -21
  150. package/dist/esm/provider_factory.js +6 -4
  151. package/dist/esm/reporters/junit.js +86 -0
  152. package/dist/esm/reporters/reporter.js +3 -0
  153. package/dist/esm/reporters/sarif.js +131 -0
  154. package/dist/esm/resilience/circuit_breaker.js +78 -0
  155. package/dist/esm/resilience/retry.js +56 -0
  156. package/dist/esm/sanitize.js +66 -0
  157. package/dist/esm/training/kg_scanner.js +115 -0
  158. package/dist/esm/training/scanner.js +27 -34
  159. package/dist/esm/validation/guardrails.js +5 -0
  160. package/dist/esm/version.js +33 -0
  161. package/dist/index.d.ts +21 -1
  162. package/dist/index.d.ts.map +1 -1
  163. package/dist/index.js +45 -1
  164. package/dist/knowledge/api_surface.d.ts +12 -0
  165. package/dist/knowledge/api_surface.d.ts.map +1 -1
  166. package/dist/knowledge/api_surface.js +268 -34
  167. package/dist/knowledge/cluster_utils.d.ts +28 -0
  168. package/dist/knowledge/cluster_utils.d.ts.map +1 -0
  169. package/dist/knowledge/cluster_utils.js +67 -0
  170. package/dist/knowledge/failure_history.d.ts +39 -0
  171. package/dist/knowledge/failure_history.d.ts.map +1 -0
  172. package/dist/knowledge/failure_history.js +128 -0
  173. package/dist/knowledge/kg_bridge.d.ts +31 -0
  174. package/dist/knowledge/kg_bridge.d.ts.map +1 -0
  175. package/dist/knowledge/kg_bridge.js +388 -0
  176. package/dist/knowledge/kg_types.d.ts +75 -0
  177. package/dist/knowledge/kg_types.d.ts.map +1 -0
  178. package/dist/knowledge/kg_types.js +4 -0
  179. package/dist/knowledge/route_families.d.ts +29 -0
  180. package/dist/knowledge/route_families.d.ts.map +1 -1
  181. package/dist/knowledge/route_families.js +122 -0
  182. package/dist/mcp-server.d.ts.map +1 -1
  183. package/dist/mcp-server.js +2 -4
  184. package/dist/metrics/prometheus.d.ts +37 -0
  185. package/dist/metrics/prometheus.d.ts.map +1 -0
  186. package/dist/metrics/prometheus.js +153 -0
  187. package/dist/model_router.d.ts +28 -0
  188. package/dist/model_router.d.ts.map +1 -0
  189. package/dist/model_router.js +63 -0
  190. package/dist/ollama_provider.d.ts.map +1 -1
  191. package/dist/ollama_provider.js +1 -0
  192. package/dist/openai_provider.d.ts.map +1 -1
  193. package/dist/openai_provider.js +1 -0
  194. package/dist/pipeline/orchestrator.d.ts +2 -0
  195. package/dist/pipeline/orchestrator.d.ts.map +1 -1
  196. package/dist/pipeline/orchestrator.js +6 -12
  197. package/dist/pipeline/stage0_preprocess.d.ts.map +1 -1
  198. package/dist/pipeline/stage0_preprocess.js +11 -18
  199. package/dist/pipeline/stage1_impact.d.ts +1 -1
  200. package/dist/pipeline/stage1_impact.d.ts.map +1 -1
  201. package/dist/pipeline/stage1_impact.js +18 -2
  202. package/dist/pipeline/stage2_coverage.d.ts +2 -0
  203. package/dist/pipeline/stage2_coverage.d.ts.map +1 -1
  204. package/dist/pipeline/stage2_coverage.js +29 -7
  205. package/dist/pipeline/stage3_generation.d.ts +2 -0
  206. package/dist/pipeline/stage3_generation.d.ts.map +1 -1
  207. package/dist/pipeline/stage3_generation.js +21 -1
  208. package/dist/pipeline/stage4_heal.d.ts +2 -0
  209. package/dist/pipeline/stage4_heal.d.ts.map +1 -1
  210. package/dist/progress.d.ts +22 -0
  211. package/dist/progress.d.ts.map +1 -0
  212. package/dist/progress.js +116 -0
  213. package/dist/prompts/coverage.d.ts +2 -0
  214. package/dist/prompts/coverage.d.ts.map +1 -1
  215. package/dist/prompts/coverage.js +17 -24
  216. package/dist/prompts/cross-impact.d.ts +1 -0
  217. package/dist/prompts/cross-impact.d.ts.map +1 -1
  218. package/dist/prompts/cross-impact.js +3 -21
  219. package/dist/prompts/generation.d.ts +4 -2
  220. package/dist/prompts/generation.d.ts.map +1 -1
  221. package/dist/prompts/generation.js +201 -45
  222. package/dist/prompts/generation_profile.d.ts +29 -0
  223. package/dist/prompts/generation_profile.d.ts.map +1 -0
  224. package/dist/prompts/generation_profile.js +151 -0
  225. package/dist/prompts/heal.d.ts +3 -1
  226. package/dist/prompts/heal.d.ts.map +1 -1
  227. package/dist/prompts/heal.js +33 -15
  228. package/dist/prompts/impact.d.ts +1 -0
  229. package/dist/prompts/impact.d.ts.map +1 -1
  230. package/dist/prompts/impact.js +3 -22
  231. package/dist/prompts/json_extract.d.ts +14 -0
  232. package/dist/prompts/json_extract.d.ts.map +1 -0
  233. package/dist/prompts/json_extract.js +39 -0
  234. package/dist/prompts/strategist.d.ts.map +1 -1
  235. package/dist/prompts/strategist.js +2 -20
  236. package/dist/prompts/test-designer.d.ts +2 -0
  237. package/dist/prompts/test-designer.d.ts.map +1 -1
  238. package/dist/prompts/test-designer.js +6 -21
  239. package/dist/provider_factory.d.ts.map +1 -1
  240. package/dist/provider_factory.js +6 -4
  241. package/dist/reporters/junit.d.ts +6 -0
  242. package/dist/reporters/junit.d.ts.map +1 -0
  243. package/dist/reporters/junit.js +89 -0
  244. package/dist/reporters/reporter.d.ts +42 -0
  245. package/dist/reporters/reporter.d.ts.map +1 -0
  246. package/dist/reporters/reporter.js +4 -0
  247. package/dist/reporters/sarif.d.ts +7 -0
  248. package/dist/reporters/sarif.d.ts.map +1 -0
  249. package/dist/reporters/sarif.js +134 -0
  250. package/dist/resilience/circuit_breaker.d.ts +36 -0
  251. package/dist/resilience/circuit_breaker.d.ts.map +1 -0
  252. package/dist/resilience/circuit_breaker.js +82 -0
  253. package/dist/resilience/retry.d.ts +11 -0
  254. package/dist/resilience/retry.d.ts.map +1 -0
  255. package/dist/resilience/retry.js +59 -0
  256. package/dist/sanitize.d.ts +15 -0
  257. package/dist/sanitize.d.ts.map +1 -0
  258. package/dist/sanitize.js +71 -0
  259. package/dist/training/kg_scanner.d.ts +13 -0
  260. package/dist/training/kg_scanner.d.ts.map +1 -0
  261. package/dist/training/kg_scanner.js +118 -0
  262. package/dist/training/scanner.d.ts +7 -2
  263. package/dist/training/scanner.d.ts.map +1 -1
  264. package/dist/training/scanner.js +27 -34
  265. package/dist/validation/guardrails.d.ts +2 -0
  266. package/dist/validation/guardrails.d.ts.map +1 -1
  267. package/dist/validation/guardrails.js +5 -0
  268. package/dist/validation/output_schema.d.ts +3 -0
  269. package/dist/validation/output_schema.d.ts.map +1 -1
  270. package/dist/version.d.ts +6 -0
  271. package/dist/version.d.ts.map +1 -0
  272. package/dist/version.js +36 -0
  273. package/package.json +7 -2
  274. package/schemas/route-families.schema.json +31 -1
@@ -34,10 +34,11 @@ function loadFileSnippet(appPath, filePath) {
34
34
  }
35
35
  function preprocess(changedFiles, config) {
36
36
  const warnings = [];
37
- // Load route family manifest
38
- const manifest = (0, route_families_js_1.loadRouteFamilyManifest)(config.testsRoot, config.routeFamilies);
37
+ // Load route family manifest, fall back to heuristic families
38
+ let manifest = (0, route_families_js_1.loadRouteFamilyManifest)(config.testsRoot, config.routeFamilies);
39
39
  if (!manifest) {
40
- warnings.push('Route family manifest not found. File-to-family binding will be skipped; AI will operate without route constraints.');
40
+ manifest = (0, route_families_js_1.buildHeuristicFamilies)(changedFiles, config.testsRoot);
41
+ warnings.push('Route family manifest not found. Using directory-based heuristics (lower accuracy).', 'Tip: Run `e2e-ai-agents train` to generate a proper manifest.');
41
42
  }
42
43
  // Load API surface catalog
43
44
  const apiSurface = (0, api_surface_js_1.loadOrBuildApiSurface)(config.testsRoot, config.apiSurface);
@@ -49,21 +50,13 @@ function preprocess(changedFiles, config) {
49
50
  // Load context documents
50
51
  const context = (0, context_loader_js_1.loadContextDocuments)(config.testsRoot, config.appPath);
51
52
  warnings.push(...context.warnings);
52
- // Bind files to families
53
- let fileBindings = [];
54
- let unboundFiles = [];
55
- if (manifest) {
56
- fileBindings = (0, route_families_js_1.bindFilesToFamilies)(changedFiles, manifest);
57
- unboundFiles = fileBindings
58
- .filter((fb) => fb.bindings.length === 0)
59
- .map((fb) => fb.file);
60
- if (unboundFiles.length > 0) {
61
- warnings.push(`${unboundFiles.length} changed file(s) did not match any route family: ${unboundFiles.slice(0, 5).join(', ')}${unboundFiles.length > 5 ? '...' : ''}`);
62
- }
63
- }
64
- else {
65
- fileBindings = changedFiles.map((f) => ({ file: f, bindings: [] }));
66
- unboundFiles = changedFiles;
53
+ // Bind files to families (manifest is always non-null now — either real or heuristic)
54
+ const fileBindings = (0, route_families_js_1.bindFilesToFamilies)(changedFiles, manifest);
55
+ const unboundFiles = fileBindings
56
+ .filter((fb) => fb.bindings.length === 0)
57
+ .map((fb) => fb.file);
58
+ if (unboundFiles.length > 0) {
59
+ warnings.push(`${unboundFiles.length} changed file(s) did not match any route family: ${unboundFiles.slice(0, 5).join(', ')}${unboundFiles.length > 5 ? '...' : ''}`);
67
60
  }
68
61
  // Group files by family+feature
69
62
  const groupMap = new Map();
@@ -15,5 +15,5 @@ export interface ImpactResult {
15
15
  warnings: string[];
16
16
  providerName: string;
17
17
  }
18
- export declare function runImpactStage(familyGroups: FamilyGroup[], manifest: RouteFamilyManifest | null, specIndex: SpecIndex, apiSurface: ApiSurfaceCatalog, context: LoadedContext, config: ImpactConfig): Promise<ImpactResult>;
18
+ export declare function runImpactStage(familyGroups: FamilyGroup[], manifest: RouteFamilyManifest | null, specIndex: SpecIndex, apiSurface: ApiSurfaceCatalog, context: LoadedContext, config: ImpactConfig, testsRoot?: string): Promise<ImpactResult>;
19
19
  //# sourceMappingURL=stage1_impact.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stage1_impact.d.ts","sourceRoot":"","sources":["../../src/pipeline/stage1_impact.ts"],"names":[],"mappings":"AAOA,OAAO,EAAgB,KAAK,mBAAmB,EAAC,MAAM,gCAAgC,CAAC;AACvF,OAAO,EAAoB,KAAK,SAAS,EAAC,MAAM,4BAA4B,CAAC;AAC7E,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,6BAA6B,CAAC;AACnE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,gCAAgC,CAAC;AAClE,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAC,YAAY,EAA+B,MAAM,gCAAgC,CAAC;AAG/F,MAAM,WAAW,YAAY;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IACzB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACxB;AAgBD,wBAAsB,cAAc,CAChC,YAAY,EAAE,WAAW,EAAE,EAC3B,QAAQ,EAAE,mBAAmB,GAAG,IAAI,EACpC,SAAS,EAAE,SAAS,EACpB,UAAU,EAAE,iBAAiB,EAC7B,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,YAAY,GACrB,OAAO,CAAC,YAAY,CAAC,CAmHvB"}
1
+ {"version":3,"file":"stage1_impact.d.ts","sourceRoot":"","sources":["../../src/pipeline/stage1_impact.ts"],"names":[],"mappings":"AAOA,OAAO,EAAgD,KAAK,mBAAmB,EAAC,MAAM,gCAAgC,CAAC;AAEvH,OAAO,EAAoB,KAAK,SAAS,EAAC,MAAM,4BAA4B,CAAC;AAC7E,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,6BAA6B,CAAC;AACnE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,gCAAgC,CAAC;AAClE,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAC,YAAY,EAA+B,MAAM,gCAAgC,CAAC;AAG/F,MAAM,WAAW,YAAY;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IACzB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACxB;AAgBD,wBAAsB,cAAc,CAChC,YAAY,EAAE,WAAW,EAAE,EAC3B,QAAQ,EAAE,mBAAmB,GAAG,IAAI,EACpC,SAAS,EAAE,SAAS,EACpB,UAAU,EAAE,iBAAiB,EAC7B,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,YAAY,EACpB,SAAS,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,YAAY,CAAC,CAqIvB"}
@@ -7,6 +7,7 @@ const provider_factory_js_1 = require("../provider_factory.js");
7
7
  const impact_js_1 = require("../prompts/impact.js");
8
8
  const context_loader_js_1 = require("../knowledge/context_loader.js");
9
9
  const route_families_js_1 = require("../knowledge/route_families.js");
10
+ const failure_history_js_1 = require("../knowledge/failure_history.js");
10
11
  const spec_index_js_1 = require("../knowledge/spec_index.js");
11
12
  const guardrails_js_1 = require("../validation/guardrails.js");
12
13
  function normalizePriority(value) {
@@ -21,7 +22,7 @@ async function getProvider(config) {
21
22
  }
22
23
  return provider_factory_js_1.LLMProviderFactory.createFromEnv();
23
24
  }
24
- async function runImpactStage(familyGroups, manifest, specIndex, apiSurface, context, config) {
25
+ async function runImpactStage(familyGroups, manifest, specIndex, apiSurface, context, config, testsRoot) {
25
26
  const warnings = [];
26
27
  const allDecisions = [];
27
28
  if (familyGroups.length === 0) {
@@ -38,6 +39,8 @@ async function runImpactStage(familyGroups, manifest, specIndex, apiSurface, con
38
39
  return { decisions: [], warnings, providerName: 'none' };
39
40
  }
40
41
  const contextBlock = (0, context_loader_js_1.formatContextForPrompt)(context);
42
+ // Load historical failure correlations for confidence boosting
43
+ const failureHistory = testsRoot ? (0, failure_history_js_1.loadFailureHistory)(testsRoot) : null;
41
44
  for (const group of familyGroups) {
42
45
  const family = manifest ? (0, route_families_js_1.getFamilyById)(manifest, group.familyId) : null;
43
46
  if (!family) {
@@ -86,15 +89,27 @@ async function runImpactStage(familyGroups, manifest, specIndex, apiSurface, con
86
89
  if (!flow.id || !flow.changedFiles || !Array.isArray(flow.changedFiles)) {
87
90
  continue;
88
91
  }
92
+ // Compute confidence with optional historical failure boost
93
+ const changedFilesList = Array.isArray(flow.changedFiles)
94
+ ? flow.changedFiles.filter((f) => typeof f === 'string')
95
+ : [];
96
+ const historyBoost = failureHistory
97
+ ? Math.max(...changedFilesList.map((f) => (0, failure_history_js_1.getConfidenceBoost)(failureHistory, f)), 0)
98
+ : 0;
89
99
  const confidence = typeof flow.confidence === 'number'
90
- ? Math.max(0, Math.min(100, flow.confidence))
100
+ ? Math.min(100, Math.max(0, flow.confidence) + historyBoost)
91
101
  : (0, guardrails_js_1.computeConfidence)({
92
102
  hasRouteFamily: true,
93
103
  hasSpecificRoute: Boolean(flow.route),
94
104
  hasPageObject: Boolean(flow.pageObjects && flow.pageObjects.length > 0),
95
105
  hasUserAction: Boolean(flow.userActions && flow.userActions.length > 0),
96
106
  hasExistingSpecCited: false,
107
+ historyBoost,
97
108
  });
109
+ // Resolve assertion patterns from manifest for this flow's family/feature
110
+ const assertionPatterns = manifest
111
+ ? (0, route_families_js_1.getAssertionPatternsForBinding)(manifest, { family: group.familyId, feature: group.featureId })
112
+ : [];
98
113
  const decision = {
99
114
  flowId: flow.id,
100
115
  flowName: flow.name || flow.id,
@@ -110,6 +125,7 @@ async function runImpactStage(familyGroups, manifest, specIndex, apiSurface, con
110
125
  blockingReason: (0, guardrails_js_1.shouldForceCannotDetermine)(confidence) ? 'Confidence too low to determine action.' : undefined,
111
126
  priority: normalizePriority(flow.priority),
112
127
  userActions: Array.isArray(flow.userActions) ? flow.userActions.filter((a) => typeof a === 'string') : [],
128
+ assertionPatterns: assertionPatterns.length > 0 ? assertionPatterns : undefined,
113
129
  };
114
130
  allDecisions.push(decision);
115
131
  }
@@ -1,12 +1,14 @@
1
1
  import { type LoadedContext } from '../knowledge/context_loader.js';
2
2
  import { type SpecIndex } from '../knowledge/spec_index.js';
3
3
  import type { FlowDecision } from '../validation/output_schema.js';
4
+ import type { GenerationProfile } from '../prompts/generation_profile.js';
4
5
  export interface CoverageConfig {
5
6
  provider?: string;
6
7
  maxTokens?: number;
7
8
  temperature?: number;
8
9
  timeout?: number;
9
10
  maxSpecContentChars?: number;
11
+ profile?: GenerationProfile;
10
12
  }
11
13
  export interface CoverageResult {
12
14
  decisions: FlowDecision[];
@@ -1 +1 @@
1
- {"version":3,"file":"stage2_coverage.d.ts","sourceRoot":"","sources":["../../src/pipeline/stage2_coverage.ts"],"names":[],"mappings":"AAMA,OAAO,EAA8C,KAAK,aAAa,EAAC,MAAM,gCAAgC,CAAC;AAC/G,OAAO,EAAoB,KAAK,SAAS,EAAC,MAAM,4BAA4B,CAAC;AAC7E,OAAO,KAAK,EAAC,YAAY,EAA4B,MAAM,gCAAgC,CAAC;AAE5F,MAAM,WAAW,cAAc;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,cAAc;IAC3B,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACxB;AAYD,wBAAsB,gBAAgB,CAClC,SAAS,EAAE,YAAY,EAAE,EACzB,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,aAAa,EACtB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,cAAc,GACvB,OAAO,CAAC,cAAc,CAAC,CAmIzB"}
1
+ {"version":3,"file":"stage2_coverage.d.ts","sourceRoot":"","sources":["../../src/pipeline/stage2_coverage.ts"],"names":[],"mappings":"AAMA,OAAO,EAA8C,KAAK,aAAa,EAAC,MAAM,gCAAgC,CAAC;AAC/G,OAAO,EAAoB,KAAK,SAAS,EAAC,MAAM,4BAA4B,CAAC;AAC7E,OAAO,KAAK,EAAC,YAAY,EAA4B,MAAM,gCAAgC,CAAC;AAC5F,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,kCAAkC,CAAC;AAExE,MAAM,WAAW,cAAc;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC/B;AAED,MAAM,WAAW,cAAc;IAC3B,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACxB;AAYD,wBAAsB,gBAAgB,CAClC,SAAS,EAAE,YAAY,EAAE,EACzB,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,aAAa,EACtB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,cAAc,GACvB,OAAO,CAAC,cAAc,CAAC,CAyJzB"}
@@ -46,13 +46,26 @@ async function runCoverageStage(decisions, specIndex, context, testsRoot, config
46
46
  for (const [familyId, familyDecisions] of byFamily) {
47
47
  // Gather relevant specs
48
48
  const specs = (0, spec_index_js_1.getSpecsForFamily)(specIndex, familyId);
49
- const specsWithContent = specs
50
- .map((s) => {
49
+ // Two-tier approach: send all spec titles (compact), full content for top matches only
50
+ const allSpecSummaries = specs.map((s) => ({
51
+ relativePath: s.relativePath,
52
+ testTitles: s.testTitles,
53
+ }));
54
+ // Load full content with a total budget of 200K chars (~50K tokens) to avoid blowing context windows
55
+ const MAX_TOTAL_SPEC_CHARS = 200000;
56
+ let totalSpecChars = 0;
57
+ const specsWithContent = [];
58
+ for (const s of specs) {
59
+ if (specsWithContent.length >= 30)
60
+ break;
51
61
  const content = (0, context_loader_js_1.loadSpecFileContent)(testsRoot, s.relativePath, maxSpecChars);
52
- return content ? { relativePath: s.relativePath, content, testTitles: s.testTitles } : null;
53
- })
54
- .filter((s) => s !== null)
55
- .slice(0, 15); // Limit to 15 specs per family to stay within token budget
62
+ if (!content)
63
+ continue;
64
+ if (totalSpecChars + content.length > MAX_TOTAL_SPEC_CHARS)
65
+ break;
66
+ totalSpecChars += content.length;
67
+ specsWithContent.push({ relativePath: s.relativePath, content, testTitles: s.testTitles });
68
+ }
56
69
  if (specsWithContent.length === 0) {
57
70
  // No specs to evaluate — mark all as create_spec
58
71
  for (const d of familyDecisions) {
@@ -73,10 +86,19 @@ async function runCoverageStage(decisions, specIndex, context, testsRoot, config
73
86
  evidence: d.evidence,
74
87
  priority: d.priority,
75
88
  }));
89
+ // Include titles-only summaries for specs beyond the content limit
90
+ const extraSummaries = allSpecSummaries
91
+ .slice(specsWithContent.length)
92
+ .map((s) => ` - ${s.relativePath}: ${s.testTitles.join(', ')}`)
93
+ .join('\n');
94
+ const extraContext = extraSummaries
95
+ ? `\nADDITIONAL SPECS (titles only, no content loaded):\n${extraSummaries}\n`
96
+ : '';
76
97
  const prompt = (0, coverage_js_1.buildCoveragePrompt)({
77
98
  flows,
78
99
  specs: specsWithContent,
79
- contextBlock,
100
+ contextBlock: contextBlock + extraContext,
101
+ profile: config.profile,
80
102
  });
81
103
  try {
82
104
  const response = await provider.generateText(prompt, {
@@ -1,6 +1,7 @@
1
1
  import { loadSpecFileContent } from '../knowledge/context_loader.js';
2
2
  import type { FlowDecision } from '../validation/output_schema.js';
3
3
  import type { ApiSurfaceCatalog } from '../knowledge/api_surface.js';
4
+ import type { GenerationProfile } from '../prompts/generation_profile.js';
4
5
  export interface GenerationConfig {
5
6
  provider?: string;
6
7
  maxTokens?: number;
@@ -12,6 +13,7 @@ export interface GenerationConfig {
12
13
  warnOnHallucinations?: boolean;
13
14
  /** When true, only log what would be written without actually writing files */
14
15
  dryRun?: boolean;
16
+ profile?: GenerationProfile;
15
17
  }
16
18
  export interface GeneratedSpec {
17
19
  flowId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"stage3_generation.d.ts","sourceRoot":"","sources":["../../src/pipeline/stage3_generation.ts"],"names":[],"mappings":"AAQA,OAAO,EAAC,mBAAmB,EAAC,MAAM,gCAAgC,CAAC;AAInE,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,gCAAgC,CAAC;AACjE,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,6BAA6B,CAAC;AAEnE,MAAM,WAAW,gBAAgB;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,yEAAyE;IACzE,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,+EAA+E;IAC/E,MAAM,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,aAAa,GAAG,eAAe,CAAC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yCAAyC;IACzC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAgB;IAC7B,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,cAAc,EAAE,MAAM,CAAC;IACvB,6CAA6C;IAC7C,aAAa,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,WAAW,EAAE,MAAM,CAAC;CACvB;AAyCD,wBAAsB,kBAAkB,CACpC,SAAS,EAAE,YAAY,EAAE,EACzB,UAAU,EAAE,iBAAiB,EAC7B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,gBAAgB,GACzB,OAAO,CAAC,gBAAgB,CAAC,CA0I3B;AAqHD,OAAO,EAAC,mBAAmB,EAAC,CAAC"}
1
+ {"version":3,"file":"stage3_generation.d.ts","sourceRoot":"","sources":["../../src/pipeline/stage3_generation.ts"],"names":[],"mappings":"AAQA,OAAO,EAAC,mBAAmB,EAAC,MAAM,gCAAgC,CAAC;AAInE,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,gCAAgC,CAAC;AACjE,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,6BAA6B,CAAC;AACnE,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,kCAAkC,CAAC;AAExE,MAAM,WAAW,gBAAgB;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,yEAAyE;IACzE,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,+EAA+E;IAC/E,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC/B;AAED,MAAM,WAAW,aAAa;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,aAAa,GAAG,eAAe,CAAC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yCAAyC;IACzC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAgB;IAC7B,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,cAAc,EAAE,MAAM,CAAC;IACvB,6CAA6C;IAC7C,aAAa,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,WAAW,EAAE,MAAM,CAAC;CACvB;AAyCD,wBAAsB,kBAAkB,CACpC,SAAS,EAAE,YAAY,EAAE,EACzB,UAAU,EAAE,iBAAiB,EAC7B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,gBAAgB,GACzB,OAAO,CAAC,gBAAgB,CAAC,CA8J3B;AAqHD,OAAO,EAAC,mBAAmB,EAAC,CAAC"}
@@ -91,6 +91,7 @@ async function runGenerationStage(decisions, apiSurface, testsRoot, config) {
91
91
  existingSpecContent,
92
92
  specPath,
93
93
  mode,
94
+ profile: config.profile,
94
95
  });
95
96
  try {
96
97
  const response = await provider.generateText(prompt, {
@@ -105,10 +106,29 @@ async function runGenerationStage(decisions, apiSurface, testsRoot, config) {
105
106
  skipped.push(`${decision.flowId}: invalid code returned`);
106
107
  continue;
107
108
  }
108
- // Hallucination detection
109
+ // Hallucination detection — block specs with hallucinated methods
109
110
  const hallucinationWarnings = (0, generation_js_1.detectHallucinatedMethods)(parsed.code, apiSurface);
110
111
  if (hallucinationWarnings.length > 0) {
111
112
  warnings.push(`Flow ${decision.flowId}: suspected hallucinated methods: ${hallucinationWarnings.join(', ')}`);
113
+ if (!config.warnOnHallucinations) {
114
+ // Block: move to needs-review instead of writing to specs dir
115
+ if (!dryRun) {
116
+ const reviewDir = (0, path_1.join)(testsRoot, 'generated-needs-review');
117
+ (0, fs_1.mkdirSync)(reviewDir, { recursive: true });
118
+ const safeName = decision.flowId.replace(/[^a-zA-Z0-9_-]/g, '_').toLowerCase();
119
+ const reviewPath = (0, path_1.join)(reviewDir, `${safeName}-${Date.now().toString(36)}.spec.ts`);
120
+ (0, fs_1.writeFileSync)(reviewPath, `${parsed.code}\n`, 'utf-8');
121
+ warnings.push(`Flow ${decision.flowId}: blocked — moved to ${reviewPath}`);
122
+ }
123
+ generated.push({
124
+ flowId: decision.flowId,
125
+ specPath,
126
+ mode,
127
+ written: false,
128
+ hallucinationWarnings,
129
+ });
130
+ continue;
131
+ }
112
132
  }
113
133
  let written = false;
114
134
  if (!dryRun) {
@@ -1,6 +1,7 @@
1
1
  import type { PipelineSummary } from '../agent/pipeline.js';
2
2
  import type { FlowDecision, FlowDecisionReport } from '../validation/output_schema.js';
3
3
  import type { GeneratedSpec } from './stage3_generation.js';
4
+ import type { GenerationProfile } from '../prompts/generation_profile.js';
4
5
  export interface HealConfig {
5
6
  /** Enable MCP-backed heal via playwright-test-healer agent */
6
7
  mcp?: boolean;
@@ -11,6 +12,7 @@ export interface HealConfig {
11
12
  dryRun?: boolean;
12
13
  /** Output directory for healed/re-generated specs */
13
14
  outputDir?: string;
15
+ profile?: GenerationProfile;
14
16
  }
15
17
  export interface HealTarget {
16
18
  specPath: string;
@@ -1 +1 @@
1
- {"version":3,"file":"stage4_heal.d.ts","sourceRoot":"","sources":["../../src/pipeline/stage4_heal.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAiB,eAAe,EAAC,MAAM,sBAAsB,CAAC;AAI1E,OAAO,KAAK,EAAC,YAAY,EAAE,kBAAkB,EAAC,MAAM,gCAAgC,CAAC;AACrF,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAE1D,MAAM,WAAW,UAAU;IACvB,8DAA8D;IAC9D,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC3B,yDAAyD;IACzD,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACvB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,OAAO,EAAE,eAAe,CAAC;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,iDAAiD;IACjD,YAAY,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,WAAW,EAAE,MAAM,CAAC;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAC9B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;IACL,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;IACjC,eAAe,CAAC,EAAE,KAAK,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;CAC5F,EACD,SAAS,EAAE,YAAY,EAAE,GAC1B,UAAU,EAAE,CAqDd;AAsGD,wBAAsB,YAAY,CAC9B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,UAAU,EAAE,EACrB,MAAM,EAAE,UAAU,GACnB,OAAO,CAAC,UAAU,CAAC,CA4GrB;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAChC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,kBAAkB,EAC1B,OAAO,EAAE;IACL,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;IACjC,UAAU,CAAC,EAAE,UAAU,CAAC;CAC3B,GACF,OAAO,CAAC,UAAU,CAAC,CAWrB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAqC7D"}
1
+ {"version":3,"file":"stage4_heal.d.ts","sourceRoot":"","sources":["../../src/pipeline/stage4_heal.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAiB,eAAe,EAAC,MAAM,sBAAsB,CAAC;AAI1E,OAAO,KAAK,EAAC,YAAY,EAAE,kBAAkB,EAAC,MAAM,gCAAgC,CAAC;AACrF,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,kCAAkC,CAAC;AAExE,MAAM,WAAW,UAAU;IACvB,8DAA8D;IAC9D,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC/B;AAED,MAAM,WAAW,UAAU;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC3B,yDAAyD;IACzD,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACvB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,OAAO,EAAE,eAAe,CAAC;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,iDAAiD;IACjD,YAAY,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,WAAW,EAAE,MAAM,CAAC;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAC9B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;IACL,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;IACjC,eAAe,CAAC,EAAE,KAAK,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;CAC5F,EACD,SAAS,EAAE,YAAY,EAAE,GAC1B,UAAU,EAAE,CAqDd;AAsGD,wBAAsB,YAAY,CAC9B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,UAAU,EAAE,EACrB,MAAM,EAAE,UAAU,GACnB,OAAO,CAAC,UAAU,CAAC,CA4GrB;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAChC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,kBAAkB,EAC1B,OAAO,EAAE;IACL,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;IACjC,UAAU,CAAC,EAAE,UAAU,CAAC;CAC3B,GACF,OAAO,CAAC,UAAU,CAAC,CAWrB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAqC7D"}
@@ -0,0 +1,22 @@
1
+ import { EventEmitter } from 'events';
2
+ interface ProgressReporterOptions {
3
+ isTTY?: boolean;
4
+ quiet?: boolean;
5
+ jsonMode?: boolean;
6
+ }
7
+ export declare class ProgressReporter extends EventEmitter {
8
+ private isTTY;
9
+ private silent;
10
+ private completedAgents;
11
+ private totalAgents;
12
+ private currentPhase;
13
+ constructor(options?: ProgressReporterOptions);
14
+ phaseStart(phase: string, agentCount: number): void;
15
+ agentStart(agent: string, family?: string): void;
16
+ agentComplete(agent: string, family: string | undefined, tokens: number, cost: number, durationMs: number): void;
17
+ phaseComplete(phase: string, elapsedMs: number): void;
18
+ workflowComplete(totalCost: number, totalTokens: number, elapsedMs: number): void;
19
+ private writeLine;
20
+ }
21
+ export {};
22
+ //# sourceMappingURL=progress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../src/progress.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,YAAY,EAAC,MAAM,QAAQ,CAAC;AAEpC,UAAU,uBAAuB;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AA+BD,qBAAa,gBAAiB,SAAQ,YAAY;IAC9C,OAAO,CAAC,KAAK,CAAU;IACvB,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAAS;gBAEjB,OAAO,CAAC,EAAE,uBAAuB;IAS7C,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAgBnD,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAoBhD,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAwBhH,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAarD,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAejF,OAAO,CAAC,SAAS;CAGpB"}
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
3
+ // See LICENSE.txt for license information.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.ProgressReporter = void 0;
6
+ const events_1 = require("events");
7
+ class ProgressReporter extends events_1.EventEmitter {
8
+ constructor(options) {
9
+ super();
10
+ this.isTTY = options?.isTTY ?? (process.stdout.isTTY === true);
11
+ this.silent = (options?.quiet ?? false) || (options?.jsonMode ?? false);
12
+ this.completedAgents = 0;
13
+ this.totalAgents = 0;
14
+ this.currentPhase = '';
15
+ }
16
+ phaseStart(phase, agentCount) {
17
+ const payload = { phase, agentCount };
18
+ this.emit('phase-start', payload);
19
+ if (this.silent) {
20
+ return;
21
+ }
22
+ this.currentPhase = phase;
23
+ this.completedAgents = 0;
24
+ this.totalAgents = agentCount;
25
+ const message = `--- Phase: ${phase} (${agentCount} agent${agentCount !== 1 ? 's' : ''}) ---`;
26
+ this.writeLine(message);
27
+ }
28
+ agentStart(agent, family) {
29
+ const payload = { agent, family };
30
+ this.emit('agent-start', payload);
31
+ if (this.silent) {
32
+ return;
33
+ }
34
+ const familyLabel = family ? ` processing ${family}` : '';
35
+ if (this.isTTY) {
36
+ const progress = `[${this.completedAgents}/${this.totalAgents} agents]`;
37
+ const message = `${progress} ${this.currentPhase}: ${agent}${familyLabel}...`;
38
+ process.stdout.write(`\r${clearLine()}${message}`);
39
+ }
40
+ else {
41
+ const message = `[${this.currentPhase}] ${agent} started${familyLabel ? ':' + familyLabel : ''}`;
42
+ this.writeLine(message);
43
+ }
44
+ }
45
+ agentComplete(agent, family, tokens, cost, durationMs) {
46
+ const payload = { agent, family, tokens, cost, durationMs };
47
+ this.emit('agent-complete', payload);
48
+ if (this.silent) {
49
+ return;
50
+ }
51
+ this.completedAgents++;
52
+ const costStr = formatCost(cost);
53
+ const durationStr = formatDuration(durationMs);
54
+ const tokensStr = formatTokens(tokens);
55
+ const familyLabel = family ? ` ${family}` : '';
56
+ if (this.isTTY) {
57
+ const progress = `[${this.completedAgents}/${this.totalAgents} agents]`;
58
+ const message = `${progress} ${this.currentPhase}: ${agent} complete${familyLabel} (${tokensStr}, ${costStr}, ${durationStr})`;
59
+ process.stdout.write(`\r${clearLine()}${message}\n`);
60
+ }
61
+ else {
62
+ const message = `[${this.currentPhase}] ${agent} complete:${familyLabel} (${tokensStr}, ${costStr}, ${durationStr})`;
63
+ this.writeLine(message);
64
+ }
65
+ }
66
+ phaseComplete(phase, elapsedMs) {
67
+ const payload = { phase, elapsedMs };
68
+ this.emit('phase-complete', payload);
69
+ if (this.silent) {
70
+ return;
71
+ }
72
+ const durationStr = formatDuration(elapsedMs);
73
+ const message = `--- Phase ${phase} complete (${durationStr}) ---`;
74
+ this.writeLine(message);
75
+ }
76
+ workflowComplete(totalCost, totalTokens, elapsedMs) {
77
+ const payload = { totalCost, totalTokens, elapsedMs };
78
+ this.emit('workflow-complete', payload);
79
+ if (this.silent) {
80
+ return;
81
+ }
82
+ const costStr = formatCost(totalCost);
83
+ const tokensStr = formatTokens(totalTokens);
84
+ const durationStr = formatDuration(elapsedMs);
85
+ const message = `=== Workflow complete: ${tokensStr}, ${costStr}, ${durationStr} ===`;
86
+ this.writeLine(message);
87
+ }
88
+ writeLine(message) {
89
+ process.stdout.write(message + '\n');
90
+ }
91
+ }
92
+ exports.ProgressReporter = ProgressReporter;
93
+ function clearLine() {
94
+ return '\x1B[2K';
95
+ }
96
+ function formatCost(cost) {
97
+ return `$${cost.toFixed(2)}`;
98
+ }
99
+ function formatTokens(tokens) {
100
+ if (tokens >= 1000000) {
101
+ return `${(tokens / 1000000).toFixed(1)}M tokens`;
102
+ }
103
+ if (tokens >= 1000) {
104
+ return `${(tokens / 1000).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, ',')} tokens`;
105
+ }
106
+ return `${tokens} tokens`;
107
+ }
108
+ function formatDuration(ms) {
109
+ const seconds = Math.round(ms / 1000);
110
+ if (seconds >= 60) {
111
+ const minutes = Math.floor(seconds / 60);
112
+ const remainingSeconds = seconds % 60;
113
+ return remainingSeconds > 0 ? `${minutes}m${remainingSeconds}s` : `${minutes}m`;
114
+ }
115
+ return `${seconds}s`;
116
+ }
@@ -1,3 +1,4 @@
1
+ import type { GenerationProfile } from './generation_profile.js';
1
2
  export interface CoveragePromptFlow {
2
3
  flowId: string;
3
4
  flowName: string;
@@ -14,6 +15,7 @@ export interface CoveragePromptContext {
14
15
  testTitles: string[];
15
16
  }>;
16
17
  contextBlock: string;
18
+ profile?: GenerationProfile;
17
19
  }
18
20
  export declare function buildCoveragePrompt(ctx: CoveragePromptContext): string;
19
21
  export interface CoverageAgentResponse {
@@ -1 +1 @@
1
- {"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../src/prompts/coverage.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,kBAAkB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB;IAClC,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC5B,KAAK,EAAE,KAAK,CAAC;QACT,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,EAAE,CAAC;KACxB,CAAC,CAAC;IACH,YAAY,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,qBAAqB,GAAG,MAAM,CAyCtE;AAED,MAAM,WAAW,qBAAqB;IAClC,QAAQ,EAAE,KAAK,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,aAAa,CAAC,EAAE,KAAK,CAAC;YAClB,IAAI,EAAE,MAAM,CAAC;YACb,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;YACtB,aAAa,CAAC,EAAE,MAAM,CAAC;YACvB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;SAC/B,CAAC,CAAC;QACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,UAAU,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC,CAAC;CACN;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,qBAAqB,GAAG,IAAI,CAqBhF"}
1
+ {"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../src/prompts/coverage.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,yBAAyB,CAAC;AAE/D,MAAM,WAAW,kBAAkB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB;IAClC,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC5B,KAAK,EAAE,KAAK,CAAC;QACT,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,EAAE,CAAC;KACxB,CAAC,CAAC;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC/B;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,qBAAqB,GAAG,MAAM,CAmDtE;AAED,MAAM,WAAW,qBAAqB;IAClC,QAAQ,EAAE,KAAK,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,aAAa,CAAC,EAAE,KAAK,CAAC;YAClB,IAAI,EAAE,MAAM,CAAC;YACb,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;YACtB,aAAa,CAAC,EAAE,MAAM,CAAC;YACvB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;SAC/B,CAAC,CAAC;QACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,UAAU,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC,CAAC;CACN;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,qBAAqB,GAAG,IAAI,CAMhF"}
@@ -4,11 +4,13 @@
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.buildCoveragePrompt = buildCoveragePrompt;
6
6
  exports.parseCoverageResponse = parseCoverageResponse;
7
+ const json_extract_js_1 = require("./json_extract.js");
8
+ const sanitize_js_1 = require("../crew/sanitize.js");
7
9
  function buildCoveragePrompt(ctx) {
8
10
  const flowsBlock = ctx.flows
9
11
  .map((f) => {
10
- const actions = f.userActions.length > 0 ? f.userActions.join('; ') : 'unknown';
11
- return `- ${f.flowId} (${f.priority}): ${f.flowName}\n Route: ${f.route}\n User actions: ${actions}\n Evidence: ${f.evidence}`;
12
+ const actions = f.userActions.length > 0 ? f.userActions.map((a) => (0, sanitize_js_1.sanitizeForPrompt)(a)).join('; ') : 'unknown';
13
+ return `- ${f.flowId} (${f.priority}): ${f.flowName}\n Route: ${f.route}\n User actions: ${actions}\n Evidence: ${(0, sanitize_js_1.sanitizeForPrompt)(f.evidence)}`;
12
14
  })
13
15
  .join('\n\n');
14
16
  const specsBlock = ctx.specs
@@ -17,7 +19,7 @@ function buildCoveragePrompt(ctx) {
17
19
  })
18
20
  .join('\n\n');
19
21
  return [
20
- 'You are evaluating whether existing Mattermost Playwright E2E tests cover the impacted flows.',
22
+ `You are evaluating whether existing ${ctx.profile?.projectName || 'Mattermost'} ${ctx.profile?.testFramework || 'Playwright'} E2E tests cover the impacted flows.`,
21
23
  '',
22
24
  `IMPACTED FLOWS (${ctx.flows.length}):`,
23
25
  flowsBlock,
@@ -40,29 +42,20 @@ function buildCoveragePrompt(ctx) {
40
42
  ' Wrong: "test the new isEditing state"',
41
43
  ' Right: "test editing a scheduled message while it is in pending state"',
42
44
  '- For add_scenarios, specify which existing spec file to extend in targetSpec.',
43
- '- For create_spec, suggest a path following Mattermost conventions.',
45
+ `- For create_spec, suggest a path following ${ctx.profile?.projectName || 'Mattermost'} conventions.`,
44
46
  '- Prefer adding scenarios to existing specs over creating new spec files.',
47
+ '',
48
+ 'SEMANTIC MATCHING RULES (critical for accuracy):',
49
+ '- A happy-path test does NOT cover the negative/error path of the same feature.',
50
+ ' "user can edit post" does NOT cover "user without permission cannot edit post".',
51
+ '- A test for one user role does NOT cover a different role.',
52
+ ' "admin can delete channel" does NOT cover "member cannot delete channel".',
53
+ '- A test for creation does NOT cover editing or deletion of the same entity.',
54
+ '- "partial" means: same feature area but different specific scenario.',
55
+ '- "full" means: the exact user action sequence and outcome is tested.',
56
+ '- When in doubt between "full" and "partial", choose "partial".',
45
57
  ].join('\n');
46
58
  }
47
59
  function parseCoverageResponse(text) {
48
- const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
49
- const candidates = fenced ? [fenced[1], text] : [text];
50
- for (const candidate of candidates) {
51
- const start = candidate.indexOf('{');
52
- const end = candidate.lastIndexOf('}');
53
- if (start < 0 || end <= start) {
54
- continue;
55
- }
56
- const raw = candidate.slice(start, end + 1);
57
- try {
58
- const parsed = JSON.parse(raw);
59
- if (parsed && Array.isArray(parsed.coverage)) {
60
- return parsed;
61
- }
62
- }
63
- catch {
64
- continue;
65
- }
66
- }
67
- return null;
60
+ return (0, json_extract_js_1.extractJsonFromResponse)(text, (obj) => obj != null && typeof obj === 'object' && Array.isArray(obj.coverage));
68
61
  }
@@ -7,6 +7,7 @@ export interface CrossImpactPromptContext {
7
7
  families: RouteFamily[];
8
8
  /** The families directly impacted by changed files */
9
9
  directlyImpactedFamilyIds: string[];
10
+ projectName?: string;
10
11
  }
11
12
  export declare function buildCrossImpactPrompt(ctx: CrossImpactPromptContext): string;
12
13
  export interface CrossImpactAgentResponse {
@@ -1 +1 @@
1
- {"version":3,"file":"cross-impact.d.ts","sourceRoot":"","sources":["../../src/prompts/cross-impact.ts"],"names":[],"mappings":"AAGA;;GAEG;AAEH,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,gCAAgC,CAAC;AAIhE,MAAM,WAAW,wBAAwB;IACrC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,sDAAsD;IACtD,yBAAyB,EAAE,MAAM,EAAE,CAAC;CACvC;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,wBAAwB,GAAG,MAAM,CA+C5E;AAED,MAAM,WAAW,wBAAwB;IACrC,YAAY,EAAE,KAAK,CAAC;QAChB,YAAY,EAAE,MAAM,CAAC;QACrB,cAAc,EAAE,MAAM,CAAC;QACvB,gBAAgB,EAAE,MAAM,CAAC;QACzB,SAAS,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;QAC9C,QAAQ,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACN;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,wBAAwB,GAAG,IAAI,CAqBtF"}
1
+ {"version":3,"file":"cross-impact.d.ts","sourceRoot":"","sources":["../../src/prompts/cross-impact.ts"],"names":[],"mappings":"AAGA;;GAEG;AAEH,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,gCAAgC,CAAC;AAKhE,MAAM,WAAW,wBAAwB;IACrC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,sDAAsD;IACtD,yBAAyB,EAAE,MAAM,EAAE,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,wBAAwB,GAAG,MAAM,CA+C5E;AAED,MAAM,WAAW,wBAAwB;IACrC,YAAY,EAAE,KAAK,CAAC;QAChB,YAAY,EAAE,MAAM,CAAC;QACrB,cAAc,EAAE,MAAM,CAAC;QACvB,gBAAgB,EAAE,MAAM,CAAC;QACzB,SAAS,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;QAC9C,QAAQ,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACN;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,wBAAwB,GAAG,IAAI,CAMtF"}
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.buildCrossImpactPrompt = buildCrossImpactPrompt;
6
6
  exports.parseCrossImpactResponse = parseCrossImpactResponse;
7
7
  const sanitize_js_1 = require("../crew/sanitize.js");
8
+ const json_extract_js_1 = require("./json_extract.js");
8
9
  function buildCrossImpactPrompt(ctx) {
9
10
  const familiesBlock = ctx.families
10
11
  .map((f) => {
@@ -18,7 +19,7 @@ function buildCrossImpactPrompt(ctx) {
18
19
  .join('\n');
19
20
  const changedBlock = ctx.changedFiles.map((f) => (0, sanitize_js_1.sanitizeForPrompt)(f)).join('\n');
20
21
  return [
21
- 'You are analyzing code changes in Mattermost to identify cross-family ripple effects.',
22
+ `You are analyzing code changes in ${ctx.projectName || 'Mattermost'} to identify cross-family ripple effects.`,
22
23
  'When a change in one route family could affect another family through shared dependencies,',
23
24
  'that is a cross-impact.',
24
25
  '',
@@ -52,24 +53,5 @@ function buildCrossImpactPrompt(ctx) {
52
53
  ].join('\n');
53
54
  }
54
55
  function parseCrossImpactResponse(text) {
55
- const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
56
- const candidates = fenced ? [fenced[1], text] : [text];
57
- for (const candidate of candidates) {
58
- const start = candidate.indexOf('{');
59
- const end = candidate.lastIndexOf('}');
60
- if (start < 0 || end <= start) {
61
- continue;
62
- }
63
- const raw = candidate.slice(start, end + 1);
64
- try {
65
- const parsed = JSON.parse(raw);
66
- if (parsed && Array.isArray(parsed.crossImpacts)) {
67
- return parsed;
68
- }
69
- }
70
- catch {
71
- continue;
72
- }
73
- }
74
- return null;
56
+ return (0, json_extract_js_1.extractJsonFromResponse)(text, (obj) => obj != null && typeof obj === 'object' && Array.isArray(obj.crossImpacts));
75
57
  }
@@ -1,11 +1,13 @@
1
1
  import type { FlowDecision } from '../validation/output_schema.js';
2
2
  import type { ApiSurfaceCatalog } from '../knowledge/api_surface.js';
3
+ import type { GenerationProfile } from './generation_profile.js';
3
4
  export interface GenerationPromptContext {
4
5
  decision: FlowDecision;
5
6
  apiSurface: ApiSurfaceCatalog;
6
7
  existingSpecContent?: string;
7
8
  specPath: string;
8
9
  mode: 'create_spec' | 'add_scenarios';
10
+ profile?: GenerationProfile;
9
11
  }
10
12
  export declare function buildGenerationPrompt(ctx: GenerationPromptContext): string;
11
13
  export interface GenerationAgentResponse {
@@ -14,10 +16,10 @@ export interface GenerationAgentResponse {
14
16
  mode: 'create_spec' | 'add_scenarios';
15
17
  flowId: string;
16
18
  }
17
- export declare function parseGenerationResponse(text: string, expectedPath: string, mode: 'create_spec' | 'add_scenarios', flowId: string): GenerationAgentResponse | null;
19
+ export declare function parseGenerationResponse(text: string, expectedPath: string, mode: 'create_spec' | 'add_scenarios', flowId: string, profile?: GenerationProfile): GenerationAgentResponse | null;
18
20
  /**
19
21
  * Returns method names that appear in generated code but do not exist in the API surface.
20
- * Used for logging; does not block generation.
22
+ * Detects all call patterns: await X.Y(), X.Y(), const z = X.Y(), chained calls.
21
23
  */
22
24
  export declare function detectHallucinatedMethods(code: string, apiSurface: ApiSurfaceCatalog): string[];
23
25
  //# sourceMappingURL=generation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"generation.d.ts","sourceRoot":"","sources":["../../src/prompts/generation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,gCAAgC,CAAC;AACjE,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,6BAA6B,CAAC;AAGnE,MAAM,WAAW,uBAAuB;IACpC,QAAQ,EAAE,YAAY,CAAC;IACvB,UAAU,EAAE,iBAAiB,CAAC;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,aAAa,GAAG,eAAe,CAAC;CACzC;AA6BD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,uBAAuB,GAAG,MAAM,CA2E1E;AAED,MAAM,WAAW,uBAAuB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,GAAG,eAAe,CAAC;IACtC,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,uBAAuB,CACnC,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,aAAa,GAAG,eAAe,EACrC,MAAM,EAAE,MAAM,GACf,uBAAuB,GAAG,IAAI,CAgBhC;AAoBD;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,iBAAiB,GAAG,MAAM,EAAE,CAc/F"}
1
+ {"version":3,"file":"generation.d.ts","sourceRoot":"","sources":["../../src/prompts/generation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,YAAY,EAAmB,MAAM,gCAAgC,CAAC;AACnF,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,6BAA6B,CAAC;AAGnE,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,yBAAyB,CAAC;AAG/D,MAAM,WAAW,uBAAuB;IACpC,QAAQ,EAAE,YAAY,CAAC;IACvB,UAAU,EAAE,iBAAiB,CAAC;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,aAAa,GAAG,eAAe,CAAC;IACtC,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC/B;AA0CD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,uBAAuB,GAAG,MAAM,CA0H1E;AAgFD,MAAM,WAAW,uBAAuB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,GAAG,eAAe,CAAC;IACtC,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,uBAAuB,CACnC,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,aAAa,GAAG,eAAe,EACrC,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,iBAAiB,GAC5B,uBAAuB,GAAG,IAAI,CAuBhC;AAwBD;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,iBAAiB,GAAG,MAAM,EAAE,CAsC/F"}