@yasserkhanorg/e2e-agents 1.8.0 → 1.8.2

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 (49) hide show
  1. package/README.md +55 -0
  2. package/dist/agent/plan.d.ts +29 -0
  3. package/dist/agent/plan.d.ts.map +1 -1
  4. package/dist/api.d.ts.map +1 -1
  5. package/dist/api.js +15 -4
  6. package/dist/cli/commands/generate.js +1 -1
  7. package/dist/cli/commands/plan.d.ts.map +1 -1
  8. package/dist/cli/commands/plan.js +51 -18
  9. package/dist/cli/commands/plan_crew.d.ts +11 -0
  10. package/dist/cli/commands/plan_crew.d.ts.map +1 -0
  11. package/dist/cli/commands/plan_crew.js +149 -0
  12. package/dist/cli/parse_args.d.ts.map +1 -1
  13. package/dist/cli/parse_args.js +2 -0
  14. package/dist/cli/types.d.ts +1 -0
  15. package/dist/cli/types.d.ts.map +1 -1
  16. package/dist/cli/usage.d.ts.map +1 -1
  17. package/dist/cli/usage.js +2 -0
  18. package/dist/crew/context.d.ts.map +1 -1
  19. package/dist/esm/api.js +15 -4
  20. package/dist/esm/cli/commands/generate.js +1 -1
  21. package/dist/esm/cli/commands/plan.js +52 -19
  22. package/dist/esm/cli/commands/plan_crew.js +143 -0
  23. package/dist/esm/cli/parse_args.js +2 -0
  24. package/dist/esm/cli/usage.js +2 -0
  25. package/dist/esm/knowledge/route_families.js +2 -2
  26. package/dist/esm/logger.js +1 -2
  27. package/dist/esm/mcp-server.js +147 -6
  28. package/dist/esm/ollama_provider.js +1 -1
  29. package/dist/esm/provider_factory.js +17 -10
  30. package/dist/esm/training/enricher.js +4 -3
  31. package/dist/esm/training/validator.js +2 -1
  32. package/dist/knowledge/route_families.d.ts.map +1 -1
  33. package/dist/knowledge/route_families.js +2 -2
  34. package/dist/logger.d.ts +1 -2
  35. package/dist/logger.d.ts.map +1 -1
  36. package/dist/logger.js +1 -2
  37. package/dist/mcp-server.d.ts +33 -0
  38. package/dist/mcp-server.d.ts.map +1 -1
  39. package/dist/mcp-server.js +150 -5
  40. package/dist/ollama_provider.js +1 -1
  41. package/dist/provider_factory.d.ts +5 -0
  42. package/dist/provider_factory.d.ts.map +1 -1
  43. package/dist/provider_factory.js +17 -10
  44. package/dist/training/enricher.d.ts.map +1 -1
  45. package/dist/training/enricher.js +4 -3
  46. package/dist/training/validator.d.ts.map +1 -1
  47. package/dist/training/validator.js +2 -1
  48. package/package.json +4 -3
  49. package/schemas/plan.schema.json +158 -0
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AAEH,oBAAY,QAAQ;IAChB,KAAK,IAAI;IACT,IAAI,IAAI;IACR,IAAI,IAAI;IACR,KAAK,IAAI;CACZ;AAqCD,qBAAa,MAAM;IACf,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,QAAQ,CAAU;gBAEd,QAAQ,CAAC,EAAE,QAAQ;IAK/B,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAM/D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAM9D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAM9D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAM/D,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAI/B,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAInC;;;OAGG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG;QAAC,GAAG,EAAE,MAAM,MAAM,CAAA;KAAC;IAWzC,OAAO,CAAC,GAAG;CAoBd;AAGD,eAAO,MAAM,MAAM,QAAe,CAAC"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAGA;;;GAGG;AAEH,oBAAY,QAAQ;IAChB,KAAK,IAAI;IACT,IAAI,IAAI;IACR,IAAI,IAAI;IACR,KAAK,IAAI;CACZ;AAqCD,qBAAa,MAAM;IACf,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,QAAQ,CAAU;gBAEd,QAAQ,CAAC,EAAE,QAAQ;IAK/B,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAM/D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAM9D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAM9D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAM/D,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAI/B,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAInC;;;OAGG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG;QAAC,GAAG,EAAE,MAAM,MAAM,CAAA;KAAC;IAWzC,OAAO,CAAC,GAAG;CAoBd;AAGD,eAAO,MAAM,MAAM,QAAe,CAAC"}
package/dist/logger.js CHANGED
@@ -4,8 +4,7 @@
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.logger = exports.Logger = exports.LogLevel = void 0;
6
6
  /**
7
- * Simple structured logging system
8
- * Replaces 18 console.log statements with configurable logging
7
+ * Structured logging system.
9
8
  * Environment variable: LOG_LEVEL (ERROR, WARN, INFO, DEBUG)
10
9
  */
11
10
  var LogLevel;
@@ -1,3 +1,4 @@
1
+ #!/usr/bin/env node
1
2
  interface Tool {
2
3
  name: string;
3
4
  description: string;
@@ -31,5 +32,37 @@ export declare class E2EAgentsMCPServer {
31
32
  */
32
33
  getTools(): Tool[];
33
34
  }
35
+ /**
36
+ * Encode a JSON-RPC message with Content-Length framing.
37
+ * Exported for testability.
38
+ */
39
+ export declare function encodeJsonRpcMessage(message: Record<string, unknown>): string;
40
+ /**
41
+ * Parse Content-Length framed JSON-RPC messages from a buffer.
42
+ * Returns parsed messages and the remaining (unconsumed) buffer.
43
+ * Exported for testability.
44
+ */
45
+ export declare function parseJsonRpcFrames(input: Buffer): {
46
+ messages: Array<{
47
+ id?: unknown;
48
+ method?: string;
49
+ params?: Record<string, unknown>;
50
+ }>;
51
+ remainder: Buffer<ArrayBuffer>;
52
+ };
53
+ /**
54
+ * Handle a single JSON-RPC message against the server.
55
+ * Returns the response message (or null for notifications).
56
+ * Exported for testability.
57
+ */
58
+ export declare function handleJsonRpcMessage(server: E2EAgentsMCPServer, message: {
59
+ id?: unknown;
60
+ method?: string;
61
+ params?: Record<string, unknown>;
62
+ }): Promise<Record<string, unknown> | null>;
63
+ /**
64
+ * Start MCP server over stdio using Content-Length framed JSON-RPC messages.
65
+ */
66
+ export declare function startStdioServer(repoRoot?: string): void;
34
67
  export default E2EAgentsMCPServer;
35
68
  //# sourceMappingURL=mcp-server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"AAaA,UAAU,IAAI;IACV,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC;AA4GD;;;GAGG;AACH,qBAAa,kBAAkB;IAC3B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,WAAW,CAAc;gBAErB,QAAQ,GAAE,MAAsB;IAM5C,OAAO,CAAC,WAAW;IAmGnB;;;OAGG;IACG,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAwB5E,OAAO,CAAC,aAAa;IA6BrB,OAAO,CAAC,QAAQ;IAmBhB,OAAO,CAAC,SAAS;IAwCjB,OAAO,CAAC,QAAQ;IAyDhB,OAAO,CAAC,aAAa;IA2BrB,OAAO,CAAC,oBAAoB;IAqD5B,OAAO,CAAC,eAAe;IAwBvB,OAAO,CAAC,sBAAsB;IAW9B;;OAEG;IACH,QAAQ,IAAI,IAAI,EAAE;CAGrB;AAYD,eAAe,kBAAkB,CAAC"}
1
+ {"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":";AAeA,UAAU,IAAI;IACV,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC;AA4GD;;;GAGG;AACH,qBAAa,kBAAkB;IAC3B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,WAAW,CAAc;gBAErB,QAAQ,GAAE,MAAsB;IAM5C,OAAO,CAAC,WAAW;IAmGnB;;;OAGG;IACG,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAwB5E,OAAO,CAAC,aAAa;IA6BrB,OAAO,CAAC,QAAQ;IAmBhB,OAAO,CAAC,SAAS;IAwCjB,OAAO,CAAC,QAAQ;IAyDhB,OAAO,CAAC,aAAa;IA2BrB,OAAO,CAAC,oBAAoB;IAqD5B,OAAO,CAAC,eAAe;IAwBvB,OAAO,CAAC,sBAAsB;IAW9B;;OAEG;IACH,QAAQ,IAAI,IAAI,EAAE;CAGrB;AAgBD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAG7E;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG;IAAC,QAAQ,EAAE,KAAK,CAAC;QAAC,EAAE,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAC,CAAC,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC,WAAW,CAAC,CAAA;CAAC,CA0BtK;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACtC,MAAM,EAAE,kBAAkB,EAC1B,OAAO,EAAE;IAAC,EAAE,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAC,GAC3E,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAmEzC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,GAAE,MAAsB,GAAG,IAAI,CAmCvE;AAMD,eAAe,kBAAkB,CAAC"}
@@ -1,8 +1,13 @@
1
+ #!/usr/bin/env node
1
2
  "use strict";
2
3
  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
3
4
  // See LICENSE.txt for license information.
4
5
  Object.defineProperty(exports, "__esModule", { value: true });
5
6
  exports.E2EAgentsMCPServer = void 0;
7
+ exports.encodeJsonRpcMessage = encodeJsonRpcMessage;
8
+ exports.parseJsonRpcFrames = parseJsonRpcFrames;
9
+ exports.handleJsonRpcMessage = handleJsonRpcMessage;
10
+ exports.startStdioServer = startStdioServer;
6
11
  /**
7
12
  * MCP Server for E2E Agents - SECURITY HARDENED
8
13
  * Exposes tools for Claude and Playwright agents to discover, generate, and heal tests
@@ -475,12 +480,152 @@ class E2EAgentsMCPServer {
475
480
  }
476
481
  exports.E2EAgentsMCPServer = E2EAgentsMCPServer;
477
482
  /**
478
- * Start MCP server
479
- * Usage: node dist/mcp-server.js
483
+ * Read the package version at runtime so the MCP initialize response
484
+ * always reflects the installed version.
480
485
  */
486
+ function getPackageVersion() {
487
+ try {
488
+ const pkgPath = (0, path_1.join)((0, path_1.dirname)(__dirname), 'package.json');
489
+ const pkg = JSON.parse((0, fs_1.readFileSync)(pkgPath, 'utf-8'));
490
+ return pkg.version || '0.0.0';
491
+ }
492
+ catch {
493
+ return '0.0.0';
494
+ }
495
+ }
496
+ /**
497
+ * Encode a JSON-RPC message with Content-Length framing.
498
+ * Exported for testability.
499
+ */
500
+ function encodeJsonRpcMessage(message) {
501
+ const body = JSON.stringify(message);
502
+ return `Content-Length: ${Buffer.byteLength(body, 'utf8')}\r\n\r\n${body}`;
503
+ }
504
+ /**
505
+ * Parse Content-Length framed JSON-RPC messages from a buffer.
506
+ * Returns parsed messages and the remaining (unconsumed) buffer.
507
+ * Exported for testability.
508
+ */
509
+ function parseJsonRpcFrames(input) {
510
+ const messages = [];
511
+ let buffer = Buffer.from(input);
512
+ while (true) {
513
+ const headerEnd = buffer.indexOf('\r\n\r\n');
514
+ if (headerEnd === -1)
515
+ break;
516
+ const headerText = buffer.slice(0, headerEnd).toString('utf8');
517
+ const match = headerText.match(/Content-Length:\s*(\d+)/i);
518
+ if (!match) {
519
+ buffer = Buffer.alloc(0);
520
+ break;
521
+ }
522
+ const contentLength = Number(match[1]);
523
+ const messageEnd = headerEnd + 4 + contentLength;
524
+ if (buffer.length < messageEnd)
525
+ break;
526
+ const body = buffer.slice(headerEnd + 4, messageEnd).toString('utf8');
527
+ buffer = buffer.slice(messageEnd);
528
+ messages.push(JSON.parse(body));
529
+ }
530
+ return { messages, remainder: buffer };
531
+ }
532
+ /**
533
+ * Handle a single JSON-RPC message against the server.
534
+ * Returns the response message (or null for notifications).
535
+ * Exported for testability.
536
+ */
537
+ async function handleJsonRpcMessage(server, message) {
538
+ const { id, method, params } = message;
539
+ const version = getPackageVersion();
540
+ if (method === 'initialize') {
541
+ return {
542
+ jsonrpc: '2.0',
543
+ id,
544
+ result: {
545
+ protocolVersion: typeof params?.protocolVersion === 'string' ? params.protocolVersion : '2024-11-05',
546
+ capabilities: { tools: {}, resources: {}, prompts: {} },
547
+ serverInfo: { name: 'e2e-agents-mcp', version },
548
+ },
549
+ };
550
+ }
551
+ if (method === 'notifications/initialized' || method === 'initialized') {
552
+ return null;
553
+ }
554
+ if (method === 'tools/list') {
555
+ return {
556
+ jsonrpc: '2.0',
557
+ id,
558
+ result: {
559
+ tools: server.getTools().map((tool) => ({
560
+ name: tool.name,
561
+ description: tool.description,
562
+ inputSchema: tool.inputSchema,
563
+ })),
564
+ },
565
+ };
566
+ }
567
+ if (method === 'tools/call') {
568
+ const resultText = await server.callTool(typeof params?.name === 'string' ? params.name : '', typeof params?.arguments === 'object' && params.arguments !== null ? params.arguments : {});
569
+ let isError = false;
570
+ try {
571
+ const parsed = JSON.parse(resultText);
572
+ isError = Boolean(parsed.error);
573
+ }
574
+ catch {
575
+ isError = false;
576
+ }
577
+ return {
578
+ jsonrpc: '2.0',
579
+ id,
580
+ result: { content: [{ type: 'text', text: resultText }], isError },
581
+ };
582
+ }
583
+ if (method === 'resources/list') {
584
+ return { jsonrpc: '2.0', id, result: { resources: [] } };
585
+ }
586
+ if (method === 'prompts/list') {
587
+ return { jsonrpc: '2.0', id, result: { prompts: [] } };
588
+ }
589
+ if (method === 'ping') {
590
+ return { jsonrpc: '2.0', id, result: {} };
591
+ }
592
+ return { jsonrpc: '2.0', id, error: { code: -32601, message: `Method not found: ${method}` } };
593
+ }
594
+ /**
595
+ * Start MCP server over stdio using Content-Length framed JSON-RPC messages.
596
+ */
597
+ function startStdioServer(repoRoot = process.cwd()) {
598
+ const server = new E2EAgentsMCPServer(repoRoot);
599
+ let buffer = Buffer.alloc(0);
600
+ const sendMessage = (message) => {
601
+ process.stdout.write(encodeJsonRpcMessage(message));
602
+ };
603
+ const sendError = (id, code, msg) => {
604
+ sendMessage({ jsonrpc: '2.0', id, error: { code, message: msg } });
605
+ };
606
+ const processBuffer = () => {
607
+ const { messages, remainder } = parseJsonRpcFrames(buffer);
608
+ buffer = remainder;
609
+ for (const parsed of messages) {
610
+ void handleJsonRpcMessage(server, parsed)
611
+ .then((response) => {
612
+ if (response)
613
+ sendMessage(response);
614
+ })
615
+ .catch((error) => {
616
+ sendError(parsed.id ?? null, -32603, error instanceof Error ? error.message : String(error));
617
+ });
618
+ }
619
+ };
620
+ process.stdin.on('data', (chunk) => {
621
+ buffer = Buffer.concat([buffer, chunk]);
622
+ processBuffer();
623
+ });
624
+ process.stdin.on('end', () => {
625
+ process.exit(0);
626
+ });
627
+ }
481
628
  if (require.main === module) {
482
- const server = new E2EAgentsMCPServer();
483
- console.log('E2E Agents MCP Server started');
484
- console.log('Tools:', server.getTools().map((t) => t.name).join(', '));
629
+ startStdioServer();
485
630
  }
486
631
  exports.default = E2EAgentsMCPServer;
@@ -110,7 +110,7 @@ class OllamaProvider extends base_provider_js_1.BaseProvider {
110
110
  // SECURITY: Validate and sanitize URL
111
111
  const urlValidation = validateOllamaUrl(config.baseUrl);
112
112
  if (!urlValidation.valid && urlValidation.warning) {
113
- console.warn(urlValidation.warning);
113
+ logger_js_1.logger.warn(urlValidation.warning);
114
114
  }
115
115
  // SECURITY: Validate timeout
116
116
  const timeout = validateTimeout(config.timeout);
@@ -55,6 +55,11 @@ export declare class LLMProviderFactory {
55
55
  * 5. Error (no provider available)
56
56
  */
57
57
  static createFromEnv(): Promise<LLMProvider>;
58
+ /**
59
+ * Create provider from an explicit preference when supplied, otherwise
60
+ * fall back to environment auto-detection.
61
+ */
62
+ static createFromPreference(providerPreference?: string): Promise<LLMProvider>;
58
63
  /**
59
64
  * Create provider from simple string format
60
65
  *
@@ -1 +1 @@
1
- {"version":3,"file":"provider_factory.d.ts","sourceRoot":"","sources":["../src/provider_factory.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAKR,WAAW,EAIX,cAAc,EAEjB,MAAM,yBAAyB,CAAC;AAGjC;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,kBAAkB;IAC3B;;OAEG;IACH,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,WAAW;IAmBlD;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW;IAWtD;;;;;;;;;OASG;WACU,aAAa,IAAI,OAAO,CAAC,WAAW,CAAC;IA0ElD;;;;;;;;;;OAUG;IACH,MAAM,CAAC,gBAAgB,CAAC,cAAc,EAAE,MAAM,GAAG,WAAW;CAkC/D;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IACzB;;;OAGG;IACH,OAAO,EAAE,cAAc,CAAC;IAExB;;;OAGG;IACH,QAAQ,EAAE,cAAc,CAAC;IAEzB;;;OAGG;IACH,cAAc,CAAC,EAAE,KAAK,CAAC,QAAQ,GAAG,mBAAmB,GAAG,wBAAwB,CAAC,CAAC;CACrF;AAqJD;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,WAAW,GAAG,OAAO,CAAC;IACxE,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,EAAE,CAAC;CAC1B,CAAC,CAsCD"}
1
+ {"version":3,"file":"provider_factory.d.ts","sourceRoot":"","sources":["../src/provider_factory.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAKR,WAAW,EAIX,cAAc,EAEjB,MAAM,yBAAyB,CAAC;AAGjC;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,kBAAkB;IAC3B;;OAEG;IACH,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,WAAW;IAmBlD;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW;IAWtD;;;;;;;;;OASG;WACU,aAAa,IAAI,OAAO,CAAC,WAAW,CAAC;IAyElD;;;OAGG;WACU,oBAAoB,CAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IASpF;;;;;;;;;;OAUG;IACH,MAAM,CAAC,gBAAgB,CAAC,cAAc,EAAE,MAAM,GAAG,WAAW;CAkC/D;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IACzB;;;OAGG;IACH,OAAO,EAAE,cAAc,CAAC;IAExB;;;OAGG;IACH,QAAQ,EAAE,cAAc,CAAC;IAEzB;;;OAGG;IACH,cAAc,CAAC,EAAE,KAAK,CAAC,QAAQ,GAAG,mBAAmB,GAAG,wBAAwB,CAAC,CAAC;CACrF;AA+ID;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,WAAW,GAAG,OAAO,CAAC;IACxE,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,EAAE,CAAC;CAC1B,CAAC,CAsCD"}
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.LLMProviderFactory = void 0;
6
6
  exports.validateProviderSetup = validateProviderSetup;
7
7
  const anthropic_provider_js_1 = require("./anthropic_provider.js");
8
+ const logger_js_1 = require("./logger.js");
8
9
  const custom_provider_js_1 = require("./custom_provider.js");
9
10
  const ollama_provider_js_1 = require("./ollama_provider.js");
10
11
  const openai_provider_js_1 = require("./openai_provider.js");
@@ -135,8 +136,7 @@ class LLMProviderFactory {
135
136
  const ollama = new ollama_provider_js_1.OllamaProvider({});
136
137
  const health = await ollama.checkHealth();
137
138
  if (health.healthy) {
138
- // eslint-disable-next-line no-console
139
- console.log('Auto-detected Ollama provider (free, local)');
139
+ logger_js_1.logger.info('Auto-detected Ollama provider (free, local)');
140
140
  return ollama;
141
141
  }
142
142
  throw new Error('No LLM provider available. Please either:\n' +
@@ -145,6 +145,17 @@ class LLMProviderFactory {
145
145
  '3. Set OPENAI_API_KEY environment variable\n' +
146
146
  '4. Set LLM_PROVIDER environment variable');
147
147
  }
148
+ /**
149
+ * Create provider from an explicit preference when supplied, otherwise
150
+ * fall back to environment auto-detection.
151
+ */
152
+ static async createFromPreference(providerPreference) {
153
+ const normalized = providerPreference?.trim().toLowerCase();
154
+ if (!normalized || normalized === 'auto') {
155
+ return this.createFromEnv();
156
+ }
157
+ return this.createFromString(normalized);
158
+ }
148
159
  /**
149
160
  * Create provider from simple string format
150
161
  *
@@ -223,8 +234,7 @@ class HybridProvider {
223
234
  }
224
235
  async generateText(prompt, options) {
225
236
  // Use primary for text generation (free)
226
- // eslint-disable-next-line no-console
227
- console.log(`[Hybrid] Using ${this.primary.name} for text generation`);
237
+ logger_js_1.logger.debug(`[Hybrid] Using ${this.primary.name} for text generation`);
228
238
  return await this.primary.generateText(prompt, options);
229
239
  }
230
240
  async analyzeImage(images, prompt, options) {
@@ -232,8 +242,7 @@ class HybridProvider {
232
242
  if (this.useFallbackFor.has('vision')) {
233
243
  // Use fallback if primary doesn't support vision
234
244
  if (!this.primary.capabilities.vision) {
235
- // eslint-disable-next-line no-console
236
- console.log(`[Hybrid] Using ${this.fallback.name} for vision analysis (primary doesn't support vision)`);
245
+ logger_js_1.logger.debug(`[Hybrid] Using ${this.fallback.name} for vision analysis (primary doesn't support vision)`);
237
246
  if (!this.fallback.analyzeImage) {
238
247
  throw new provider_interface_js_1.UnsupportedCapabilityError(this.name, 'vision');
239
248
  }
@@ -242,8 +251,7 @@ class HybridProvider {
242
251
  }
243
252
  // Try primary first
244
253
  if (this.primary.analyzeImage) {
245
- // eslint-disable-next-line no-console
246
- console.log(`[Hybrid] Using ${this.primary.name} for vision analysis`);
254
+ logger_js_1.logger.debug(`[Hybrid] Using ${this.primary.name} for vision analysis`);
247
255
  return await this.primary.analyzeImage(images, prompt, options);
248
256
  }
249
257
  throw new provider_interface_js_1.UnsupportedCapabilityError(this.name, 'vision');
@@ -253,8 +261,7 @@ class HybridProvider {
253
261
  if (!this.primary.streamText) {
254
262
  throw new provider_interface_js_1.UnsupportedCapabilityError(this.primary.name, 'streaming');
255
263
  }
256
- // eslint-disable-next-line no-console
257
- console.log(`[Hybrid] Using ${this.primary.name} for streaming`);
264
+ logger_js_1.logger.debug(`[Hybrid] Using ${this.primary.name} for streaming`);
258
265
  yield* this.primary.streamText(prompt, options);
259
266
  }
260
267
  getUsageStats() {
@@ -1 +1 @@
1
- {"version":3,"file":"enricher.d.ts","sourceRoot":"","sources":["../../src/training/enricher.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,gCAAgC,CAAC;AAGhE,OAAO,KAAK,EAAC,gBAAgB,EAAE,aAAa,EAAC,MAAM,YAAY,CAAC;AAkLhE,MAAM,WAAW,aAAa;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,aAAa,EAAE,CAmBlE;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,EAAE,CAwBrE;AAkCD,wBAAsB,cAAc,CAChC,QAAQ,EAAE,WAAW,EAAE,EACvB,OAAO,EAAE,aAAa,EAAE,EACxB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,WAAW,EACrB,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,gBAAgB,CAAC,CAuF3B"}
1
+ {"version":3,"file":"enricher.d.ts","sourceRoot":"","sources":["../../src/training/enricher.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,gCAAgC,CAAC;AAGhE,OAAO,KAAK,EAAC,gBAAgB,EAAE,aAAa,EAAC,MAAM,YAAY,CAAC;AAkLhE,MAAM,WAAW,aAAa;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,aAAa,EAAE,CAmBlE;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,EAAE,CAwBrE;AAkCD,wBAAsB,cAAc,CAChC,QAAQ,EAAE,WAAW,EAAE,EACvB,OAAO,EAAE,aAAa,EAAE,EACxB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,WAAW,EACrB,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,gBAAgB,CAAC,CAuF3B"}
@@ -7,6 +7,7 @@ exports.parseEnrichResponse = parseEnrichResponse;
7
7
  exports.enrichFamilies = enrichFamilies;
8
8
  const fs_1 = require("fs");
9
9
  const path_1 = require("path");
10
+ const logger_js_1 = require("../logger.js");
10
11
  const types_js_1 = require("./types.js");
11
12
  const MAX_FILES_PER_FAMILY = 20;
12
13
  const MAX_LINES_PER_FILE = 50;
@@ -294,11 +295,11 @@ async function enrichFamilies(families, scanned, projectRoot, provider, budgetUS
294
295
  // Truncate at the last complete section boundary to avoid malformed input
295
296
  const lastSectionEnd = prompt.lastIndexOf('\n---\n', MAX_PROMPT_CHARS);
296
297
  if (lastSectionEnd > 0) {
297
- console.warn(`[train] Prompt truncated from ${prompt.length} chars at section boundary`);
298
+ logger_js_1.logger.warn(`[train] Prompt truncated from ${prompt.length} chars at section boundary`);
298
299
  prompt = prompt.slice(0, lastSectionEnd);
299
300
  }
300
301
  else {
301
- console.warn(`[train] Prompt truncated from ${prompt.length} to ${MAX_PROMPT_CHARS} chars`);
302
+ logger_js_1.logger.warn(`[train] Prompt truncated from ${prompt.length} to ${MAX_PROMPT_CHARS} chars`);
302
303
  prompt = prompt.slice(0, MAX_PROMPT_CHARS);
303
304
  }
304
305
  }
@@ -330,7 +331,7 @@ async function enrichFamilies(families, scanned, projectRoot, provider, budgetUS
330
331
  }
331
332
  catch (error) {
332
333
  // On LLM failure, keep families unchanged
333
- console.warn(`[train] LLM enrichment failed for chunk: ${error instanceof Error ? error.message : String(error)}`);
334
+ logger_js_1.logger.warn(`[train] LLM enrichment failed for chunk: ${error instanceof Error ? error.message : String(error)}`);
334
335
  enriched.push(...chunk);
335
336
  }
336
337
  finally {
@@ -1 +1 @@
1
- {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/training/validator.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,gCAAgC,CAAC;AAExE,OAAO,KAAK,EAAC,gBAAgB,EAAE,gBAAgB,EAAC,MAAM,YAAY,CAAC;AAoBnE;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CA6BrD;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAC,CAAC,CA6BhG;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAC,CAAC,CAgB1H;AA+CD,wBAAgB,cAAc,CAC1B,QAAQ,EAAE,mBAAmB,EAC7B,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,MAAM,EAAE,GACxB,gBAAgB,CA+BlB;AAED,wBAAgB,qBAAqB,CACjC,OAAO,EAAE,gBAAgB,EAAE,EAC3B,QAAQ,EAAE,mBAAmB,GAC9B,gBAAgB,CAkDlB;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAgCvE"}
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/training/validator.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,gCAAgC,CAAC;AAExE,OAAO,KAAK,EAAC,gBAAgB,EAAE,gBAAgB,EAAC,MAAM,YAAY,CAAC;AAoBnE;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CA6BrD;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAC,CAAC,CA6BhG;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAC,CAAC,CAgB1H;AA+CD,wBAAgB,cAAc,CAC1B,QAAQ,EAAE,mBAAmB,EAC7B,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,MAAM,EAAE,GACxB,gBAAgB,CA+BlB;AAED,wBAAgB,qBAAqB,CACjC,OAAO,EAAE,gBAAgB,EAAE,EAC3B,QAAQ,EAAE,mBAAmB,GAC9B,gBAAgB,CAkDlB;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAgCvE"}
@@ -10,6 +10,7 @@ exports.buildValidationReport = buildValidationReport;
10
10
  exports.formatValidationReport = formatValidationReport;
11
11
  const child_process_1 = require("child_process");
12
12
  const path_1 = require("path");
13
+ const logger_js_1 = require("../logger.js");
13
14
  const route_families_js_1 = require("../knowledge/route_families.js");
14
15
  /**
15
16
  * Glob-style patterns for infrastructure / cross-cutting files that will never
@@ -111,7 +112,7 @@ function getCommitFiles(projectRoot, since) {
111
112
  });
112
113
  }
113
114
  catch (error) {
114
- console.warn(`[train] git log failed: ${error instanceof Error ? error.message : String(error)}`);
115
+ logger_js_1.logger.warn(`[train] git log failed: ${error instanceof Error ? error.message : String(error)}`);
115
116
  return [];
116
117
  }
117
118
  return parseGitLog(log);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yasserkhanorg/e2e-agents",
3
- "version": "1.8.0",
3
+ "version": "1.8.2",
4
4
  "description": "AI-powered E2E test impact analysis, generation, and healing. Analyzes code changes to identify affected Playwright tests, detects coverage gaps, and generates or repairs specs using pluggable LLM providers (Claude, OpenAI, Ollama). Includes MCP server, traceability, and CI/CD integration.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -28,7 +28,8 @@
28
28
  },
29
29
  "bin": {
30
30
  "e2e-ai-agents": "./dist/cli.js",
31
- "e2e-qa-agent": "./dist/qa-agent/cli.js"
31
+ "e2e-qa-agent": "./dist/qa-agent/cli.js",
32
+ "e2e-agents-mcp": "./dist/mcp-server.js"
32
33
  },
33
34
  "files": [
34
35
  "dist",
@@ -38,7 +39,7 @@
38
39
  ],
39
40
  "scripts": {
40
41
  "build": "npm run build:cjs && npm run build:esm",
41
- "postbuild": "chmod +x dist/cli.js dist/qa-agent/cli.js",
42
+ "postbuild": "chmod +x dist/cli.js dist/qa-agent/cli.js dist/mcp-server.js",
42
43
  "build:cjs": "tsc -p tsconfig.json",
43
44
  "build:esm": "tsc -p tsconfig.esm.json && node scripts/write-esm-package.js",
44
45
  "clean": "rm -rf dist",
@@ -280,6 +280,68 @@
280
280
  },
281
281
  "additionalProperties": false
282
282
  },
283
+ "crew": {
284
+ "type": "object",
285
+ "required": [
286
+ "workflow",
287
+ "providerOverride",
288
+ "summary",
289
+ "impactedFlows",
290
+ "strategyEntries",
291
+ "testDesigns",
292
+ "crossImpacts",
293
+ "regressionRisks",
294
+ "findings",
295
+ "warnings",
296
+ "timings"
297
+ ],
298
+ "properties": {
299
+ "workflow": {"type": "string"},
300
+ "providerOverride": {"type": "string"},
301
+ "summary": {
302
+ "type": "object",
303
+ "required": [
304
+ "impactedFlows",
305
+ "strategyEntries",
306
+ "testDesigns",
307
+ "crossImpacts",
308
+ "highRiskCrossImpacts",
309
+ "regressionRisks",
310
+ "findings",
311
+ "generatedSpecs",
312
+ "manualReviewEntries",
313
+ "totalCostUSD",
314
+ "totalTokens"
315
+ ],
316
+ "properties": {
317
+ "impactedFlows": {"type": "number"},
318
+ "strategyEntries": {"type": "number"},
319
+ "testDesigns": {"type": "number"},
320
+ "crossImpacts": {"type": "number"},
321
+ "highRiskCrossImpacts": {"type": "number"},
322
+ "regressionRisks": {"type": "number"},
323
+ "findings": {"type": "number"},
324
+ "generatedSpecs": {"type": "number"},
325
+ "manualReviewEntries": {"type": "number"},
326
+ "totalCostUSD": {"type": "number"},
327
+ "totalTokens": {"type": "number"}
328
+ },
329
+ "additionalProperties": false
330
+ },
331
+ "impactedFlows": {"type": "array", "items": {"$ref": "#/$defs/flowDecision"}},
332
+ "strategyEntries": {"type": "array", "items": {"$ref": "#/$defs/strategyEntry"}},
333
+ "testDesigns": {"type": "array", "items": {"$ref": "#/$defs/testDesign"}},
334
+ "crossImpacts": {"type": "array", "items": {"$ref": "#/$defs/crossImpact"}},
335
+ "regressionRisks": {"type": "array", "items": {"$ref": "#/$defs/regressionRisk"}},
336
+ "findings": {"type": "array", "items": {"$ref": "#/$defs/finding"}},
337
+ "warnings": {"type": "array", "items": {"type": "string"}},
338
+ "timings": {
339
+ "type": "object",
340
+ "additionalProperties": {"type": "number"}
341
+ }
342
+ },
343
+ "additionalProperties": false
344
+ },
283
345
  "metrics": {
284
346
  "type": "object",
285
347
  "required": [
@@ -327,6 +389,102 @@
327
389
  "details": {"type": "string"}
328
390
  },
329
391
  "additionalProperties": false
392
+ },
393
+ "flowDecision": {
394
+ "type": "object",
395
+ "required": ["flowId", "flowName", "routeFamily", "changedFiles", "evidence", "evidenceSource", "confidence", "existingSpecs", "action", "priority"],
396
+ "properties": {
397
+ "flowId": {"type": "string"},
398
+ "flowName": {"type": "string"},
399
+ "routeFamily": {"type": "string"},
400
+ "changedFiles": {"type": "array", "items": {"type": "string"}},
401
+ "evidence": {"type": "string"},
402
+ "evidenceSource": {"enum": ["deterministic", "ai", "hybrid"]},
403
+ "confidence": {"type": "number"},
404
+ "existingSpecs": {"type": "array", "items": {"type": "string"}},
405
+ "action": {"enum": ["create_spec", "update_spec", "skip"]},
406
+ "priority": {"enum": ["P0", "P1", "P2"]},
407
+ "userActions": {"type": "array", "items": {"type": "string"}}
408
+ },
409
+ "additionalProperties": true
410
+ },
411
+ "strategyEntry": {
412
+ "type": "object",
413
+ "required": ["flowId", "flowName", "priority", "approach", "rationale", "testCategories", "crossImpactRisk"],
414
+ "properties": {
415
+ "flowId": {"type": "string"},
416
+ "flowName": {"type": "string"},
417
+ "priority": {"enum": ["P0", "P1", "P2"]},
418
+ "approach": {"enum": ["full-test", "smoke-test", "skip", "manual-review"]},
419
+ "rationale": {"type": "string"},
420
+ "testCategories": {"type": "array", "items": {"type": "string"}},
421
+ "crossImpactRisk": {"enum": ["high", "medium", "low", "none"]}
422
+ },
423
+ "additionalProperties": false
424
+ },
425
+ "testDesign": {
426
+ "type": "object",
427
+ "required": ["flowId", "flowName", "testCases"],
428
+ "properties": {
429
+ "flowId": {"type": "string"},
430
+ "flowName": {"type": "string"},
431
+ "testCases": {
432
+ "type": "array",
433
+ "items": {
434
+ "type": "object",
435
+ "required": ["name", "type", "preconditions", "steps", "expectedOutcome", "priority", "rationale"],
436
+ "properties": {
437
+ "name": {"type": "string"},
438
+ "type": {"enum": ["happy-path", "edge-case", "boundary", "negative", "state-transition", "race-condition", "permission", "accessibility", "performance"]},
439
+ "preconditions": {"type": "array", "items": {"type": "string"}},
440
+ "steps": {"type": "array", "items": {"type": "string"}},
441
+ "expectedOutcome": {"type": "string"},
442
+ "priority": {"enum": ["P0", "P1", "P2"]},
443
+ "rationale": {"type": "string"}
444
+ },
445
+ "additionalProperties": false
446
+ }
447
+ }
448
+ },
449
+ "additionalProperties": false
450
+ },
451
+ "crossImpact": {
452
+ "type": "object",
453
+ "required": ["sourceFamily", "affectedFamily", "sharedDependency", "riskLevel", "evidence"],
454
+ "properties": {
455
+ "sourceFamily": {"type": "string"},
456
+ "affectedFamily": {"type": "string"},
457
+ "sharedDependency": {"type": "string"},
458
+ "riskLevel": {"enum": ["high", "medium", "low"]},
459
+ "evidence": {"type": "string"}
460
+ },
461
+ "additionalProperties": false
462
+ },
463
+ "regressionRisk": {
464
+ "type": "object",
465
+ "required": ["familyId", "filePattern", "riskScore", "reason", "historicalFailures"],
466
+ "properties": {
467
+ "familyId": {"type": "string"},
468
+ "filePattern": {"type": "string"},
469
+ "riskScore": {"type": "number"},
470
+ "reason": {"type": "string"},
471
+ "historicalFailures": {"type": "number"}
472
+ },
473
+ "additionalProperties": false
474
+ },
475
+ "finding": {
476
+ "type": "object",
477
+ "required": ["id", "type", "severity", "source", "summary", "details", "relatedFlows"],
478
+ "properties": {
479
+ "id": {"type": "string"},
480
+ "type": {"enum": ["bug", "gap", "risk", "flaky"]},
481
+ "severity": {"enum": ["critical", "high", "medium", "low"]},
482
+ "source": {"enum": ["strategist", "test-designer", "cross-impact", "regression-advisor", "impact-analyst", "coverage-evaluator", "generator", "executor", "healer", "explorer"]},
483
+ "summary": {"type": "string"},
484
+ "details": {"type": "string"},
485
+ "relatedFlows": {"type": "array", "items": {"type": "string"}}
486
+ },
487
+ "additionalProperties": false
330
488
  }
331
489
  },
332
490
  "additionalProperties": false