@yasserkhanorg/e2e-agents 1.8.5 → 1.9.5

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 (256) 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/cluster_utils.js +60 -0
  125. package/dist/esm/knowledge/kg_bridge.js +381 -0
  126. package/dist/esm/knowledge/kg_types.js +3 -0
  127. package/dist/esm/knowledge/route_families.js +89 -0
  128. package/dist/esm/mcp-server.js +2 -4
  129. package/dist/esm/metrics/prometheus.js +149 -0
  130. package/dist/esm/model_router.js +59 -0
  131. package/dist/esm/ollama_provider.js +1 -0
  132. package/dist/esm/openai_provider.js +1 -0
  133. package/dist/esm/pipeline/orchestrator.js +6 -12
  134. package/dist/esm/pipeline/stage0_preprocess.js +12 -19
  135. package/dist/esm/pipeline/stage2_coverage.js +1 -0
  136. package/dist/esm/pipeline/stage3_generation.js +1 -0
  137. package/dist/esm/progress.js +112 -0
  138. package/dist/esm/prompts/coverage.js +7 -24
  139. package/dist/esm/prompts/cross-impact.js +3 -21
  140. package/dist/esm/prompts/generation.js +158 -36
  141. package/dist/esm/prompts/generation_profile.js +147 -0
  142. package/dist/esm/prompts/heal.js +33 -15
  143. package/dist/esm/prompts/impact.js +3 -22
  144. package/dist/esm/prompts/json_extract.js +36 -0
  145. package/dist/esm/prompts/strategist.js +2 -20
  146. package/dist/esm/prompts/test-designer.js +6 -21
  147. package/dist/esm/provider_factory.js +6 -4
  148. package/dist/esm/reporters/junit.js +86 -0
  149. package/dist/esm/reporters/reporter.js +3 -0
  150. package/dist/esm/reporters/sarif.js +131 -0
  151. package/dist/esm/resilience/circuit_breaker.js +78 -0
  152. package/dist/esm/resilience/retry.js +56 -0
  153. package/dist/esm/sanitize.js +66 -0
  154. package/dist/esm/training/kg_scanner.js +115 -0
  155. package/dist/esm/training/scanner.js +27 -34
  156. package/dist/esm/version.js +33 -0
  157. package/dist/index.d.ts +21 -1
  158. package/dist/index.d.ts.map +1 -1
  159. package/dist/index.js +45 -1
  160. package/dist/knowledge/cluster_utils.d.ts +28 -0
  161. package/dist/knowledge/cluster_utils.d.ts.map +1 -0
  162. package/dist/knowledge/cluster_utils.js +67 -0
  163. package/dist/knowledge/kg_bridge.d.ts +31 -0
  164. package/dist/knowledge/kg_bridge.d.ts.map +1 -0
  165. package/dist/knowledge/kg_bridge.js +388 -0
  166. package/dist/knowledge/kg_types.d.ts +75 -0
  167. package/dist/knowledge/kg_types.d.ts.map +1 -0
  168. package/dist/knowledge/kg_types.js +4 -0
  169. package/dist/knowledge/route_families.d.ts +18 -0
  170. package/dist/knowledge/route_families.d.ts.map +1 -1
  171. package/dist/knowledge/route_families.js +91 -0
  172. package/dist/mcp-server.d.ts.map +1 -1
  173. package/dist/mcp-server.js +2 -4
  174. package/dist/metrics/prometheus.d.ts +37 -0
  175. package/dist/metrics/prometheus.d.ts.map +1 -0
  176. package/dist/metrics/prometheus.js +153 -0
  177. package/dist/model_router.d.ts +28 -0
  178. package/dist/model_router.d.ts.map +1 -0
  179. package/dist/model_router.js +63 -0
  180. package/dist/ollama_provider.d.ts.map +1 -1
  181. package/dist/ollama_provider.js +1 -0
  182. package/dist/openai_provider.d.ts.map +1 -1
  183. package/dist/openai_provider.js +1 -0
  184. package/dist/pipeline/orchestrator.d.ts +2 -0
  185. package/dist/pipeline/orchestrator.d.ts.map +1 -1
  186. package/dist/pipeline/orchestrator.js +6 -12
  187. package/dist/pipeline/stage0_preprocess.d.ts.map +1 -1
  188. package/dist/pipeline/stage0_preprocess.js +11 -18
  189. package/dist/pipeline/stage2_coverage.d.ts +2 -0
  190. package/dist/pipeline/stage2_coverage.d.ts.map +1 -1
  191. package/dist/pipeline/stage2_coverage.js +1 -0
  192. package/dist/pipeline/stage3_generation.d.ts +2 -0
  193. package/dist/pipeline/stage3_generation.d.ts.map +1 -1
  194. package/dist/pipeline/stage3_generation.js +1 -0
  195. package/dist/pipeline/stage4_heal.d.ts +2 -0
  196. package/dist/pipeline/stage4_heal.d.ts.map +1 -1
  197. package/dist/progress.d.ts +22 -0
  198. package/dist/progress.d.ts.map +1 -0
  199. package/dist/progress.js +116 -0
  200. package/dist/prompts/coverage.d.ts +2 -0
  201. package/dist/prompts/coverage.d.ts.map +1 -1
  202. package/dist/prompts/coverage.js +7 -24
  203. package/dist/prompts/cross-impact.d.ts +1 -0
  204. package/dist/prompts/cross-impact.d.ts.map +1 -1
  205. package/dist/prompts/cross-impact.js +3 -21
  206. package/dist/prompts/generation.d.ts +3 -1
  207. package/dist/prompts/generation.d.ts.map +1 -1
  208. package/dist/prompts/generation.js +158 -36
  209. package/dist/prompts/generation_profile.d.ts +29 -0
  210. package/dist/prompts/generation_profile.d.ts.map +1 -0
  211. package/dist/prompts/generation_profile.js +151 -0
  212. package/dist/prompts/heal.d.ts +3 -1
  213. package/dist/prompts/heal.d.ts.map +1 -1
  214. package/dist/prompts/heal.js +33 -15
  215. package/dist/prompts/impact.d.ts +1 -0
  216. package/dist/prompts/impact.d.ts.map +1 -1
  217. package/dist/prompts/impact.js +3 -22
  218. package/dist/prompts/json_extract.d.ts +14 -0
  219. package/dist/prompts/json_extract.d.ts.map +1 -0
  220. package/dist/prompts/json_extract.js +39 -0
  221. package/dist/prompts/strategist.d.ts.map +1 -1
  222. package/dist/prompts/strategist.js +2 -20
  223. package/dist/prompts/test-designer.d.ts +2 -0
  224. package/dist/prompts/test-designer.d.ts.map +1 -1
  225. package/dist/prompts/test-designer.js +6 -21
  226. package/dist/provider_factory.d.ts.map +1 -1
  227. package/dist/provider_factory.js +6 -4
  228. package/dist/reporters/junit.d.ts +6 -0
  229. package/dist/reporters/junit.d.ts.map +1 -0
  230. package/dist/reporters/junit.js +89 -0
  231. package/dist/reporters/reporter.d.ts +42 -0
  232. package/dist/reporters/reporter.d.ts.map +1 -0
  233. package/dist/reporters/reporter.js +4 -0
  234. package/dist/reporters/sarif.d.ts +7 -0
  235. package/dist/reporters/sarif.d.ts.map +1 -0
  236. package/dist/reporters/sarif.js +134 -0
  237. package/dist/resilience/circuit_breaker.d.ts +36 -0
  238. package/dist/resilience/circuit_breaker.d.ts.map +1 -0
  239. package/dist/resilience/circuit_breaker.js +82 -0
  240. package/dist/resilience/retry.d.ts +11 -0
  241. package/dist/resilience/retry.d.ts.map +1 -0
  242. package/dist/resilience/retry.js +59 -0
  243. package/dist/sanitize.d.ts +15 -0
  244. package/dist/sanitize.d.ts.map +1 -0
  245. package/dist/sanitize.js +71 -0
  246. package/dist/training/kg_scanner.d.ts +13 -0
  247. package/dist/training/kg_scanner.d.ts.map +1 -0
  248. package/dist/training/kg_scanner.js +118 -0
  249. package/dist/training/scanner.d.ts +7 -2
  250. package/dist/training/scanner.d.ts.map +1 -1
  251. package/dist/training/scanner.js +27 -34
  252. package/dist/version.d.ts +6 -0
  253. package/dist/version.d.ts.map +1 -0
  254. package/dist/version.js +36 -0
  255. package/package.json +7 -2
  256. package/schemas/route-families.schema.json +31 -1
@@ -0,0 +1,109 @@
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.runBootstrapCommand = runBootstrapCommand;
6
+ /**
7
+ * Bootstrap command — takes a project with an Understand-Anything knowledge graph
8
+ * and generates route-families.json + initial test stubs.
9
+ */
10
+ const fs_1 = require("fs");
11
+ const path_1 = require("path");
12
+ const logger_js_1 = require("../../logger.js");
13
+ const kg_bridge_js_1 = require("../../knowledge/kg_bridge.js");
14
+ const route_families_js_1 = require("../../knowledge/route_families.js");
15
+ const framework_adapter_js_1 = require("../../adapters/framework_adapter.js");
16
+ const generation_profile_js_1 = require("../../prompts/generation_profile.js");
17
+ class BootstrapError extends Error {
18
+ constructor(message) {
19
+ super(message);
20
+ this.name = 'BootstrapError';
21
+ }
22
+ }
23
+ async function runBootstrapCommand(args) {
24
+ const projectRoot = (0, path_1.resolve)(args.path || '.');
25
+ if (args.verbose)
26
+ logger_js_1.logger.setLevel(logger_js_1.LogLevel.DEBUG);
27
+ if (args.jsonOutput)
28
+ logger_js_1.logger.setJsonMode(true);
29
+ logger_js_1.logger.info('e2e-ai-agents bootstrap');
30
+ logger_js_1.logger.info('=======================');
31
+ // ---------- Step 1: Check for knowledge graph ----------
32
+ const kgPath = args.bootstrapKgPath
33
+ ? (0, path_1.resolve)(args.bootstrapKgPath)
34
+ : (0, path_1.join)(projectRoot, '.understand-anything', 'knowledge-graph.json');
35
+ if (!(0, fs_1.existsSync)(kgPath)) {
36
+ throw new BootstrapError(`Knowledge graph not found at: ${kgPath}\n\n` +
37
+ 'To bootstrap, first generate a knowledge graph for your project:\n' +
38
+ ' 1. Install Understand-Anything: npm install -g understand-anything\n' +
39
+ ' 2. Run: understand-anything analyze .\n' +
40
+ ' 3. Then run: e2e-ai-agents bootstrap\n\n' +
41
+ 'Or provide a path: e2e-ai-agents bootstrap --kg-path /path/to/knowledge-graph.json');
42
+ }
43
+ // ---------- Step 2: Load KG and classify ----------
44
+ logger_js_1.logger.info('Loading knowledge graph...');
45
+ const kg = (0, kg_bridge_js_1.loadKnowledgeGraph)(projectRoot, args.bootstrapKgPath ? kgPath : undefined);
46
+ if (!kg) {
47
+ throw new BootstrapError('Failed to load knowledge graph. Ensure it is valid JSON with nodes and edges arrays.');
48
+ }
49
+ const projectType = (0, kg_bridge_js_1.classifyProjectType)(kg);
50
+ logger_js_1.logger.info(`Project: ${kg.project.name || '(unnamed)'}`);
51
+ logger_js_1.logger.info(`Type: ${projectType}`);
52
+ logger_js_1.logger.info(`Frameworks: ${kg.project.frameworks.join(', ')}`);
53
+ logger_js_1.logger.info(`Languages: ${kg.project.languages.join(', ')}`);
54
+ logger_js_1.logger.info(`Nodes: ${kg.nodes.length}, Edges: ${kg.edges.length}`);
55
+ // ---------- Step 3: Transform KG to route families ----------
56
+ logger_js_1.logger.info('');
57
+ logger_js_1.logger.info('Generating route families from knowledge graph...');
58
+ const manifest = (0, kg_bridge_js_1.transformKGToFamilies)(kg);
59
+ const maxFamilies = args.bootstrapMaxFamilies || 50;
60
+ if (manifest.families.length > maxFamilies) {
61
+ logger_js_1.logger.info(`Limiting to top ${maxFamilies} families (of ${manifest.families.length} discovered). Use --max-families to adjust.`);
62
+ manifest.families = manifest.families.slice(0, maxFamilies);
63
+ }
64
+ const p0Count = manifest.families.filter((f) => f.priority === 'P0').length;
65
+ const p1Count = manifest.families.filter((f) => f.priority === 'P1').length;
66
+ const p2Count = manifest.families.filter((f) => f.priority === 'P2').length;
67
+ logger_js_1.logger.info(`Discovered ${manifest.families.length} families: ${p0Count} P0, ${p1Count} P1, ${p2Count} P2`);
68
+ // ---------- Step 4: Detect/scaffold test framework ----------
69
+ const framework = (0, framework_adapter_js_1.detectFramework)(projectRoot);
70
+ const testMode = args.bootstrapTestMode || (0, framework_adapter_js_1.detectTestMode)(projectRoot, kg);
71
+ const profile = (0, generation_profile_js_1.resolveGenerationProfile)({ profile: args.profile, testMode }, kg);
72
+ logger_js_1.logger.info(`Test framework: ${framework.name}`);
73
+ logger_js_1.logger.info(`Test mode: ${testMode}`);
74
+ logger_js_1.logger.info(`Generation profile: ${profile.projectName} (${profile.testFramework})`);
75
+ // ---------- Step 5: Write route-families.json ----------
76
+ const outputDir = (0, path_1.join)(projectRoot, '.e2e-ai-agents');
77
+ const outputPath = (0, path_1.join)(outputDir, 'route-families.json');
78
+ if (args.dryRun) {
79
+ logger_js_1.logger.info('');
80
+ logger_js_1.logger.info('Dry run — proposed manifest:');
81
+ console.log((0, route_families_js_1.serializeManifest)(manifest));
82
+ }
83
+ else {
84
+ if (!(0, fs_1.existsSync)(outputDir)) {
85
+ (0, fs_1.mkdirSync)(outputDir, { recursive: true });
86
+ }
87
+ (0, fs_1.writeFileSync)(outputPath, (0, route_families_js_1.serializeManifest)(manifest), 'utf-8');
88
+ logger_js_1.logger.info(`Wrote ${outputPath}`);
89
+ }
90
+ // ---------- Step 6: Summary and next steps ----------
91
+ logger_js_1.logger.info('');
92
+ logger_js_1.logger.info('Bootstrap complete!');
93
+ logger_js_1.logger.info('');
94
+ logger_js_1.logger.info('Route families summary:');
95
+ for (const family of manifest.families.slice(0, 15)) {
96
+ const endpoints = family.apiEndpoints?.length || 0;
97
+ const endpointSuffix = endpoints > 0 ? ` (${endpoints} API endpoints)` : '';
98
+ logger_js_1.logger.info(` ${family.priority || 'P2'} ${family.id}: ${family.routes.join(', ')}${endpointSuffix}`);
99
+ }
100
+ if (manifest.families.length > 15) {
101
+ logger_js_1.logger.info(` ... and ${manifest.families.length - 15} more`);
102
+ }
103
+ logger_js_1.logger.info('');
104
+ logger_js_1.logger.info('Next steps:');
105
+ logger_js_1.logger.info(' 1. Review and refine .e2e-ai-agents/route-families.json');
106
+ logger_js_1.logger.info(' 2. Run `e2e-ai-agents train --enrich` to add LLM-enriched metadata');
107
+ logger_js_1.logger.info(' 3. Run `e2e-ai-agents plan` to see what tests are needed');
108
+ logger_js_1.logger.info(' 4. Run `e2e-ai-agents generate` to create test stubs');
109
+ }
@@ -0,0 +1,3 @@
1
+ import type { ParsedArgs } from '../types.js';
2
+ export declare function runCostReportCommand(args: ParsedArgs): void;
3
+ //# sourceMappingURL=cost_report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost_report.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/cost_report.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,aAAa,CAAC;AA8C5C,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAgE3D"}
@@ -0,0 +1,115 @@
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.runCostReportCommand = runCostReportCommand;
6
+ /**
7
+ * CLI command: cost-report — displays LLM cost breakdown from metrics.
8
+ */
9
+ const fs_1 = require("fs");
10
+ const path_1 = require("path");
11
+ function parseMetricsFile(filePath) {
12
+ if (!(0, fs_1.existsSync)(filePath)) {
13
+ return [];
14
+ }
15
+ const lines = (0, fs_1.readFileSync)(filePath, 'utf-8').split('\n');
16
+ const events = [];
17
+ for (const line of lines) {
18
+ const trimmed = line.trim();
19
+ if (!trimmed)
20
+ continue;
21
+ try {
22
+ const parsed = JSON.parse(trimmed);
23
+ if (parsed.type === 'crew-run') {
24
+ events.push(parsed);
25
+ }
26
+ }
27
+ catch {
28
+ continue;
29
+ }
30
+ }
31
+ return events;
32
+ }
33
+ function filterByDays(events, days) {
34
+ const cutoff = Date.now() - days * 24 * 60 * 60 * 1000;
35
+ return events.filter((e) => new Date(e.timestamp).getTime() >= cutoff);
36
+ }
37
+ function runCostReportCommand(args) {
38
+ const reportRoot = args.path || args.testsRoot || process.cwd();
39
+ const metricsPath = (0, path_1.join)(reportRoot, '.e2e-ai-agents', 'metrics.jsonl');
40
+ const days = 30; // Default; could be added as a CLI flag later
41
+ const allEvents = parseMetricsFile(metricsPath);
42
+ const events = filterByDays(allEvents, days);
43
+ if (events.length === 0) {
44
+ console.log('No crew metrics found.');
45
+ if (!(0, fs_1.existsSync)(metricsPath)) {
46
+ console.log(`Metrics file not found at: ${metricsPath}`);
47
+ }
48
+ else {
49
+ console.log('Run `e2e-ai-agents crew` to generate cost data.');
50
+ }
51
+ return;
52
+ }
53
+ // JSON output
54
+ if (args.jsonOutput) {
55
+ const report = buildReport(events, days);
56
+ console.log(JSON.stringify(report, null, 2));
57
+ return;
58
+ }
59
+ // Human-readable output
60
+ const totalCost = events.reduce((sum, e) => sum + e.totalCost, 0);
61
+ const totalRuns = events.length;
62
+ console.log(`E2E Agents Cost Report (last ${days} days)`);
63
+ console.log('='.repeat(45));
64
+ console.log(`\nTotal: $${totalCost.toFixed(2)} across ${totalRuns} runs\n`);
65
+ // By workflow
66
+ const byWorkflow = new Map();
67
+ for (const e of events) {
68
+ const entry = byWorkflow.get(e.workflow) || { runs: 0, cost: 0 };
69
+ entry.runs++;
70
+ entry.cost += e.totalCost;
71
+ byWorkflow.set(e.workflow, entry);
72
+ }
73
+ console.log('By workflow:');
74
+ for (const [workflow, data] of [...byWorkflow.entries()].sort((a, b) => b[1].cost - a[1].cost)) {
75
+ const avg = data.cost / data.runs;
76
+ console.log(` ${workflow.padEnd(14)} | ${String(data.runs).padStart(3)} runs | $${data.cost.toFixed(2).padStart(6)} | avg $${avg.toFixed(2)}/run`);
77
+ }
78
+ // By agent (top 5)
79
+ const byAgent = new Map();
80
+ for (const e of events) {
81
+ for (const au of e.agentUsage) {
82
+ byAgent.set(au.agent, (byAgent.get(au.agent) || 0) + au.cost);
83
+ }
84
+ }
85
+ const sortedAgents = [...byAgent.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5);
86
+ if (sortedAgents.length > 0) {
87
+ console.log('\nBy agent (top 5):');
88
+ for (const [agent, cost] of sortedAgents) {
89
+ const pct = totalCost > 0 ? ((cost / totalCost) * 100).toFixed(0) : '0';
90
+ console.log(` ${agent.padEnd(20)} | $${cost.toFixed(2).padStart(6)} | ${pct.padStart(3)}%`);
91
+ }
92
+ }
93
+ }
94
+ function buildReport(events, days) {
95
+ const totalCost = events.reduce((sum, e) => sum + e.totalCost, 0);
96
+ const byWorkflow = {};
97
+ const byAgent = {};
98
+ for (const e of events) {
99
+ if (!byWorkflow[e.workflow]) {
100
+ byWorkflow[e.workflow] = { runs: 0, cost: 0 };
101
+ }
102
+ byWorkflow[e.workflow].runs++;
103
+ byWorkflow[e.workflow].cost += e.totalCost;
104
+ for (const au of e.agentUsage) {
105
+ byAgent[au.agent] = (byAgent[au.agent] || 0) + au.cost;
106
+ }
107
+ }
108
+ return {
109
+ days,
110
+ totalRuns: events.length,
111
+ totalCost,
112
+ byWorkflow,
113
+ byAgent,
114
+ };
115
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"crew.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/crew.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,aAAa,CAAC;AAI5C,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAgIpG"}
1
+ {"version":3,"file":"crew.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/crew.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,aAAa,CAAC;AAI5C,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CA8KpG"}
@@ -6,8 +6,12 @@ exports.runCrewCommand = runCrewCommand;
6
6
  /**
7
7
  * CLI command: crew — runs multi-agent QA analysis workflows.
8
8
  */
9
+ const fs_1 = require("fs");
10
+ const path_1 = require("path");
9
11
  const config_js_1 = require("../../agent/config.js");
10
12
  const orchestrator_js_1 = require("../../crew/orchestrator.js");
13
+ const response_cache_js_1 = require("../../cache/response_cache.js");
14
+ const workflows_js_1 = require("../../crew/workflows.js");
11
15
  const impact_analyst_js_1 = require("../../agents/impact-analyst.js");
12
16
  const generator_js_1 = require("../../agents/generator.js");
13
17
  const executor_js_1 = require("../../agents/executor.js");
@@ -37,6 +41,23 @@ async function runCrewCommand(args, autoConfig) {
37
41
  process.exit(1);
38
42
  }
39
43
  const workflowName = rawWorkflow;
44
+ // Degraded mode: skip all AI features, deterministic analysis only
45
+ const degraded = args.degradedMode || process.env.E2E_AGENTS_DEGRADED === 'true';
46
+ if (degraded) {
47
+ console.log('Running in degraded mode — deterministic analysis only, no LLM calls.');
48
+ }
49
+ // Prune expired cache entries to prevent unbounded growth on CI
50
+ try {
51
+ const cache = new response_cache_js_1.ResponseCache(testsRoot);
52
+ const pruned = cache.prune();
53
+ if (pruned > 0) {
54
+ console.log(`Cache: pruned ${pruned} expired entries.`);
55
+ }
56
+ }
57
+ catch (err) {
58
+ const msg = err instanceof Error ? err.message : String(err);
59
+ console.error(`Cache prune warning: ${msg}`);
60
+ }
40
61
  const crewConfig = {
41
62
  appPath: config.path,
42
63
  testsRoot,
@@ -46,7 +67,7 @@ async function runCrewCommand(args, autoConfig) {
46
67
  workflow: workflowName,
47
68
  providerOverride: args.llmProvider,
48
69
  budgetUSD: args.budgetUSD,
49
- dryRun: args.dryRun,
70
+ dryRun: degraded || args.dryRun,
50
71
  };
51
72
  // Create orchestrator and register all agents
52
73
  const orchestrator = new orchestrator_js_1.CrewOrchestrator();
@@ -68,6 +89,33 @@ async function runCrewCommand(args, autoConfig) {
68
89
  process.exit(1);
69
90
  }
70
91
  const ctx = result.context;
92
+ // Dry-run output
93
+ if (result.dryRun) {
94
+ printDryRunOutput(result, workflowName, args.jsonOutput);
95
+ return;
96
+ }
97
+ // Write crew metrics to metrics.jsonl for cost-report
98
+ if (ctx.usage.requestCount > 0) {
99
+ try {
100
+ const baseDir = (0, path_1.join)(testsRoot, '.e2e-ai-agents');
101
+ (0, fs_1.mkdirSync)(baseDir, { recursive: true });
102
+ const metricsPath = (0, path_1.join)(baseDir, 'metrics.jsonl');
103
+ const crewMetric = {
104
+ type: 'crew-run',
105
+ timestamp: new Date().toISOString(),
106
+ workflow: workflowName,
107
+ totalCost: ctx.usage.totalCost,
108
+ totalTokens: ctx.usage.totalTokens,
109
+ totalInputTokens: ctx.usage.totalInputTokens,
110
+ totalOutputTokens: ctx.usage.totalOutputTokens,
111
+ agentUsage: ctx.agentUsage,
112
+ };
113
+ (0, fs_1.appendFileSync)(metricsPath, `${JSON.stringify(crewMetric)}\n`, 'utf-8');
114
+ }
115
+ catch {
116
+ // Non-fatal: metrics writing should not break the workflow
117
+ }
118
+ }
71
119
  // JSON output mode
72
120
  if (args.jsonOutput) {
73
121
  const jsonReport = {
@@ -135,3 +183,72 @@ async function runCrewCommand(args, autoConfig) {
135
183
  }
136
184
  }
137
185
  }
186
+ function printDryRunOutput(result, workflowName, jsonOutput) {
187
+ const ctx = result.context;
188
+ const workflow = workflows_js_1.WORKFLOWS[workflowName];
189
+ if (jsonOutput) {
190
+ console.log(JSON.stringify({
191
+ dryRun: true,
192
+ workflow: workflowName,
193
+ changedFiles: ctx.changedFiles,
194
+ familyGroups: ctx.familyGroups.map((fg) => ({
195
+ familyId: fg.familyId,
196
+ featureId: fg.featureId,
197
+ files: fg.files,
198
+ })),
199
+ phases: workflow.phases.map((p) => ({
200
+ name: p.name,
201
+ agents: p.parallel || p.sequential || [],
202
+ })),
203
+ manifestSource: ctx.manifest?.source || 'none',
204
+ warnings: result.warnings,
205
+ }, null, 2));
206
+ return;
207
+ }
208
+ console.log('Dry run — no LLM calls will be made.\n');
209
+ console.log(`Changed files (${ctx.changedFiles.length}):`);
210
+ for (const f of ctx.changedFiles.slice(0, 20)) {
211
+ console.log(` ${f}`);
212
+ }
213
+ if (ctx.changedFiles.length > 20) {
214
+ console.log(` ... and ${ctx.changedFiles.length - 20} more`);
215
+ }
216
+ console.log(`\nAffected families (${ctx.familyGroups.length}):`);
217
+ for (const fg of ctx.familyGroups) {
218
+ const label = fg.featureId ? `${fg.familyId}/${fg.featureId}` : fg.familyId;
219
+ console.log(` ${label} (${fg.files.length} files)`);
220
+ }
221
+ if (ctx.manifest?.source === 'heuristic') {
222
+ console.log('\n Note: Using directory-based heuristics. Run `e2e-ai-agents train` for better accuracy.');
223
+ }
224
+ console.log(`\nWorkflow: ${workflowName}`);
225
+ const phaseNames = workflow.phases
226
+ .map((p) => {
227
+ const agents = p.parallel || p.sequential || [];
228
+ return agents.length > 0 ? `${p.name} (${agents.join(', ')})` : p.name;
229
+ })
230
+ .join(' → ');
231
+ console.log(`Phases: ${phaseNames}`);
232
+ // Cost estimation based on workflow and family count
233
+ const familyCount = Math.max(ctx.familyGroups.length, 1);
234
+ const agentCount = workflow.phases.reduce((sum, p) => sum + (p.parallel?.length || 0) + (p.sequential?.length || 0), 0);
235
+ const costEstimate = estimateCost(workflowName, familyCount, agentCount);
236
+ console.log(`\nEstimated cost: $${costEstimate.low.toFixed(2)}-$${costEstimate.high.toFixed(2)}`);
237
+ if (ctx.modelRoutingProviderType) {
238
+ console.log(` With model routing: $${(costEstimate.low * 0.5).toFixed(2)}-$${(costEstimate.high * 0.5).toFixed(2)} (Haiku for classification)`);
239
+ }
240
+ }
241
+ /** Rough cost estimation based on observed averages per workflow type */
242
+ function estimateCost(workflow, families, _agents) {
243
+ // Per-family cost ranges by workflow (based on typical Sonnet pricing)
244
+ const ranges = {
245
+ 'quick-check': { low: 0.03, high: 0.10 },
246
+ 'design-only': { low: 0.10, high: 0.40 },
247
+ 'full-qa': { low: 0.30, high: 1.00 },
248
+ };
249
+ const range = ranges[workflow] || ranges['full-qa'];
250
+ return {
251
+ low: range.low * families,
252
+ high: range.high * families,
253
+ };
254
+ }
@@ -0,0 +1,3 @@
1
+ import type { ParsedArgs } from '../types.js';
2
+ export declare function runGateCommand(args: ParsedArgs, autoConfig: string | undefined): Promise<void>;
3
+ //# sourceMappingURL=gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/gate.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,aAAa,CAAC;AAE5C,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CA6EpG"}
@@ -0,0 +1,86 @@
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.runGateCommand = runGateCommand;
6
+ /**
7
+ * CLI command: gate — CI coverage gate that exits 1 if coverage is below threshold.
8
+ *
9
+ * Runs deterministic impact analysis (no LLM required) and checks what
10
+ * percentage of impacted features have test coverage.
11
+ *
12
+ * Usage:
13
+ * e2e-ai-agents gate --threshold 80 --path . --since origin/main
14
+ */
15
+ const config_js_1 = require("../../agent/config.js");
16
+ const git_js_1 = require("../../agent/git.js");
17
+ const impact_engine_js_1 = require("../../engine/impact_engine.js");
18
+ async function runGateCommand(args, autoConfig) {
19
+ if (!args.path && !autoConfig) {
20
+ console.error('Error: --path is required for gate command');
21
+ process.exit(1);
22
+ }
23
+ const threshold = args.gateThreshold ?? 80;
24
+ const { config } = (0, config_js_1.resolveConfig)(process.cwd(), autoConfig, {
25
+ path: args.path,
26
+ profile: args.profile,
27
+ testsRoot: args.testsRoot,
28
+ mode: 'impact',
29
+ gitSince: args.gitSince,
30
+ });
31
+ const testsRoot = config.testsRoot || config.path;
32
+ const gitSince = args.gitSince || config.git.since;
33
+ // Get changed files
34
+ const result = await (0, git_js_1.getChangedFiles)(config.path, gitSince);
35
+ const changedFiles = result.files;
36
+ if (changedFiles.length === 0) {
37
+ console.log('No changed files detected. Gate passes.');
38
+ process.exit(0);
39
+ }
40
+ // Run deterministic impact analysis
41
+ const impact = (0, impact_engine_js_1.analyzeImpact)(changedFiles, {
42
+ testsRoot,
43
+ routeFamilies: config.routeFamilies,
44
+ });
45
+ const totalFeatures = impact.impactedFeatures.length;
46
+ if (totalFeatures === 0) {
47
+ console.log('No impacted features detected. Gate passes.');
48
+ process.exit(0);
49
+ }
50
+ const coveredFeatures = impact.impactedFeatures.filter((f) => f.coverageStatus === 'covered' || f.coverageStatus === 'partial').length;
51
+ const coveragePercent = Math.round((coveredFeatures / totalFeatures) * 100);
52
+ // Output
53
+ if (args.jsonOutput) {
54
+ console.log(JSON.stringify({
55
+ threshold,
56
+ coveragePercent,
57
+ totalFeatures,
58
+ coveredFeatures,
59
+ passed: coveragePercent >= threshold,
60
+ uncoveredFeatures: impact.impactedFeatures
61
+ .filter((f) => f.coverageStatus === 'uncovered')
62
+ .map((f) => ({ id: f.featureId || f.familyId, priority: f.priority })),
63
+ }, null, 2));
64
+ }
65
+ else {
66
+ console.log(`Coverage gate: ${coveragePercent}% (${coveredFeatures}/${totalFeatures} features covered)`);
67
+ console.log(`Threshold: ${threshold}%`);
68
+ if (coveragePercent < threshold) {
69
+ console.log(`\nFAILED — coverage ${coveragePercent}% is below ${threshold}% threshold`);
70
+ const uncovered = impact.impactedFeatures.filter((f) => f.coverageStatus === 'uncovered');
71
+ if (uncovered.length > 0) {
72
+ console.log('\nUncovered features:');
73
+ for (const f of uncovered.slice(0, 10)) {
74
+ console.log(` ${f.priority || 'P2'} ${f.featureId || f.familyId}`);
75
+ }
76
+ if (uncovered.length > 10) {
77
+ console.log(` ... and ${uncovered.length - 10} more`);
78
+ }
79
+ }
80
+ }
81
+ else {
82
+ console.log('\nPASSED');
83
+ }
84
+ }
85
+ process.exit(coveragePercent >= threshold ? 0 : 1);
86
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAgIA,wBAAsB,cAAc,CAAC,GAAG,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA6F/D"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAyEA,wBAAsB,cAAc,CAAC,GAAG,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA6F/D"}
@@ -37,9 +37,9 @@ var __importStar = (this && this.__importStar) || (function () {
37
37
  Object.defineProperty(exports, "__esModule", { value: true });
38
38
  exports.runInitCommand = runInitCommand;
39
39
  const fs_1 = require("fs");
40
- const child_process_1 = require("child_process");
41
40
  const path_1 = require("path");
42
41
  const readline = __importStar(require("readline"));
42
+ const defaults_js_1 = require("../defaults.js");
43
43
  const CONFIG_FILENAME = 'e2e-ai-agents.config.json';
44
44
  function createInterface() {
45
45
  return readline.createInterface({
@@ -55,61 +55,6 @@ function ask(rl, question, defaultValue) {
55
55
  });
56
56
  });
57
57
  }
58
- function detectFramework(appPath) {
59
- const resolvedPath = (0, path_1.resolve)(appPath);
60
- const pkgPath = (0, path_1.join)(resolvedPath, 'package.json');
61
- if (!(0, fs_1.existsSync)(pkgPath)) {
62
- return 'auto';
63
- }
64
- try {
65
- const pkg = JSON.parse((0, fs_1.readFileSync)(pkgPath, 'utf-8'));
66
- const allDeps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
67
- if (allDeps['@playwright/test'] || allDeps.playwright) {
68
- return 'playwright';
69
- }
70
- if (allDeps.cypress) {
71
- return 'cypress';
72
- }
73
- if (allDeps['selenium-webdriver'] || allDeps.webdriverio) {
74
- return 'selenium';
75
- }
76
- }
77
- catch {
78
- // ignore
79
- }
80
- return 'auto';
81
- }
82
- function detectGitDefaultBranch(appPath) {
83
- try {
84
- const result = (0, child_process_1.execFileSync)('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
85
- cwd: (0, path_1.resolve)(appPath),
86
- encoding: 'utf-8',
87
- stdio: ['pipe', 'pipe', 'pipe'],
88
- }).trim();
89
- return `origin/${result}`;
90
- }
91
- catch {
92
- return 'origin/main';
93
- }
94
- }
95
- function detectTestsRoot(appPath) {
96
- const resolvedPath = (0, path_1.resolve)(appPath);
97
- const candidates = [
98
- 'e2e-tests/playwright',
99
- 'e2e-tests',
100
- 'e2e',
101
- 'tests/e2e',
102
- 'test/e2e',
103
- 'tests',
104
- 'test',
105
- ];
106
- for (const candidate of candidates) {
107
- if ((0, fs_1.existsSync)((0, path_1.join)(resolvedPath, candidate))) {
108
- return candidate;
109
- }
110
- }
111
- return undefined;
112
- }
113
58
  function buildConfig(answers) {
114
59
  const config = {
115
60
  path: answers.path,
@@ -155,9 +100,9 @@ async function runInitCommand(yes = false) {
155
100
  const appPath = '.';
156
101
  const answers = {
157
102
  path: appPath,
158
- testsRoot: detectTestsRoot(appPath) || '.',
159
- framework: detectFramework(appPath),
160
- gitSince: detectGitDefaultBranch(appPath),
103
+ testsRoot: (0, defaults_js_1.detectTestsRoot)(appPath) || '.',
104
+ framework: (0, defaults_js_1.detectFramework)(appPath),
105
+ gitSince: (0, defaults_js_1.detectGitDefaultBranch)(appPath),
161
106
  provider: 'auto',
162
107
  enableAi: true,
163
108
  enforcementMode: 'advisory',
@@ -178,11 +123,11 @@ async function runInitCommand(yes = false) {
178
123
  const rl = createInterface();
179
124
  try {
180
125
  const appPath = await ask(rl, ' Path to your web app root', '.');
181
- const detectedFramework = detectFramework(appPath);
126
+ const detectedFramework = (0, defaults_js_1.detectFramework)(appPath);
182
127
  const framework = await ask(rl, ' Test framework (auto | playwright | cypress | selenium)', detectedFramework);
183
- const detectedTestsRoot = detectTestsRoot(appPath);
128
+ const detectedTestsRoot = (0, defaults_js_1.detectTestsRoot)(appPath);
184
129
  const testsRoot = await ask(rl, ' Path to tests root (relative to app root, "." if same)', detectedTestsRoot || '.');
185
- const detectedBranch = detectGitDefaultBranch(appPath);
130
+ const detectedBranch = (0, defaults_js_1.detectGitDefaultBranch)(appPath);
186
131
  const gitSince = await ask(rl, ' Git ref to diff against', detectedBranch);
187
132
  const providerAnswer = await ask(rl, ' LLM provider for AI features (anthropic | openai | ollama | auto)', 'auto');
188
133
  const enableAi = providerAnswer !== 'none';
@@ -1 +1 @@
1
- {"version":3,"file":"train.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/train.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,aAAa,CAAC;AAqJ5C,wBAAsB,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsP1F"}
1
+ {"version":3,"file":"train.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/train.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,aAAa,CAAC;AAqI5C,wBAAsB,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgQ1F"}