@yasserkhanorg/e2e-agents 1.7.7 → 1.8.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 (100) hide show
  1. package/dist/agent/git.d.ts +5 -0
  2. package/dist/agent/git.d.ts.map +1 -1
  3. package/dist/agent/git.js +13 -0
  4. package/dist/agents/coverage-evaluator.d.ts +8 -0
  5. package/dist/agents/coverage-evaluator.d.ts.map +1 -0
  6. package/dist/agents/coverage-evaluator.js +41 -0
  7. package/dist/agents/cross-impact.d.ts +13 -0
  8. package/dist/agents/cross-impact.d.ts.map +1 -0
  9. package/dist/agents/cross-impact.js +135 -0
  10. package/dist/agents/executor.d.ts +8 -0
  11. package/dist/agents/executor.d.ts.map +1 -0
  12. package/dist/agents/executor.js +70 -0
  13. package/dist/agents/explorer.d.ts +12 -0
  14. package/dist/agents/explorer.d.ts.map +1 -0
  15. package/dist/agents/explorer.js +43 -0
  16. package/dist/agents/generator.d.ts +8 -0
  17. package/dist/agents/generator.d.ts.map +1 -0
  18. package/dist/agents/generator.js +77 -0
  19. package/dist/agents/healer.d.ts +8 -0
  20. package/dist/agents/healer.d.ts.map +1 -0
  21. package/dist/agents/healer.js +31 -0
  22. package/dist/agents/impact-analyst.d.ts +8 -0
  23. package/dist/agents/impact-analyst.d.ts.map +1 -0
  24. package/dist/agents/impact-analyst.js +38 -0
  25. package/dist/agents/regression-advisor.d.ts +8 -0
  26. package/dist/agents/regression-advisor.d.ts.map +1 -0
  27. package/dist/agents/regression-advisor.js +116 -0
  28. package/dist/agents/strategist.d.ts +9 -0
  29. package/dist/agents/strategist.d.ts.map +1 -0
  30. package/dist/agents/strategist.js +87 -0
  31. package/dist/agents/test-designer.d.ts +8 -0
  32. package/dist/agents/test-designer.d.ts.map +1 -0
  33. package/dist/agents/test-designer.js +106 -0
  34. package/dist/cli/commands/crew.d.ts +3 -0
  35. package/dist/cli/commands/crew.d.ts.map +1 -0
  36. package/dist/cli/commands/crew.js +137 -0
  37. package/dist/cli/parse_args.d.ts.map +1 -1
  38. package/dist/cli/parse_args.js +2 -1
  39. package/dist/cli/types.d.ts +2 -1
  40. package/dist/cli/types.d.ts.map +1 -1
  41. package/dist/cli.js +5 -0
  42. package/dist/crew/context.d.ts +40 -0
  43. package/dist/crew/context.d.ts.map +1 -0
  44. package/dist/crew/context.js +36 -0
  45. package/dist/crew/orchestrator.d.ts +36 -0
  46. package/dist/crew/orchestrator.d.ts.map +1 -0
  47. package/dist/crew/orchestrator.js +171 -0
  48. package/dist/crew/protocol.d.ts +33 -0
  49. package/dist/crew/protocol.d.ts.map +1 -0
  50. package/dist/crew/protocol.js +4 -0
  51. package/dist/crew/provider.d.ts +3 -0
  52. package/dist/crew/provider.d.ts.map +1 -0
  53. package/dist/crew/provider.js +16 -0
  54. package/dist/crew/sanitize.d.ts +3 -0
  55. package/dist/crew/sanitize.d.ts.map +1 -0
  56. package/dist/crew/sanitize.js +31 -0
  57. package/dist/crew/types.d.ts +52 -0
  58. package/dist/crew/types.d.ts.map +1 -0
  59. package/dist/crew/types.js +4 -0
  60. package/dist/crew/workflows.d.ts +52 -0
  61. package/dist/crew/workflows.d.ts.map +1 -0
  62. package/dist/crew/workflows.js +36 -0
  63. package/dist/esm/agent/git.js +12 -0
  64. package/dist/esm/agents/coverage-evaluator.js +37 -0
  65. package/dist/esm/agents/cross-impact.js +131 -0
  66. package/dist/esm/agents/executor.js +66 -0
  67. package/dist/esm/agents/explorer.js +39 -0
  68. package/dist/esm/agents/generator.js +73 -0
  69. package/dist/esm/agents/healer.js +27 -0
  70. package/dist/esm/agents/impact-analyst.js +34 -0
  71. package/dist/esm/agents/regression-advisor.js +112 -0
  72. package/dist/esm/agents/strategist.js +83 -0
  73. package/dist/esm/agents/test-designer.js +102 -0
  74. package/dist/esm/cli/commands/crew.js +134 -0
  75. package/dist/esm/cli/parse_args.js +2 -1
  76. package/dist/esm/cli.js +5 -0
  77. package/dist/esm/crew/context.js +32 -0
  78. package/dist/esm/crew/orchestrator.js +167 -0
  79. package/dist/esm/crew/protocol.js +3 -0
  80. package/dist/esm/crew/provider.js +13 -0
  81. package/dist/esm/crew/sanitize.js +27 -0
  82. package/dist/esm/crew/types.js +3 -0
  83. package/dist/esm/crew/workflows.js +33 -0
  84. package/dist/esm/index.js +14 -0
  85. package/dist/esm/prompts/cross-impact.js +71 -0
  86. package/dist/esm/prompts/strategist.js +79 -0
  87. package/dist/esm/prompts/test-designer.js +107 -0
  88. package/dist/index.d.ts +17 -0
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +27 -1
  91. package/dist/prompts/cross-impact.d.ts +22 -0
  92. package/dist/prompts/cross-impact.d.ts.map +1 -0
  93. package/dist/prompts/cross-impact.js +75 -0
  94. package/dist/prompts/strategist.d.ts +25 -0
  95. package/dist/prompts/strategist.d.ts.map +1 -0
  96. package/dist/prompts/strategist.js +83 -0
  97. package/dist/prompts/test-designer.d.ts +33 -0
  98. package/dist/prompts/test-designer.d.ts.map +1 -0
  99. package/dist/prompts/test-designer.js +111 -0
  100. package/package.json +1 -1
@@ -9,5 +9,10 @@ export interface GitChangeResult {
9
9
  export interface GitChangeOptions {
10
10
  includeUncommitted?: boolean;
11
11
  }
12
+ /**
13
+ * Check if a file path is a test file (spec, test, or in test directories).
14
+ * Shared across pipeline and crew orchestrators.
15
+ */
16
+ export declare function isTestFile(file: string): boolean;
12
17
  export declare function getChangedFiles(appRoot: string, since: string, options?: GitChangeOptions): GitChangeResult;
13
18
  //# sourceMappingURL=git.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/agent/git.ts"],"names":[],"mappings":"AAkHA,MAAM,WAAW,eAAe;IAC5B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,kLAAkL;IAClL,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,YAAY,GAAG,QAAQ,CAAC;CAC1C;AAED,MAAM,WAAW,gBAAgB;IAC7B,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAChC;AAiFD,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,eAAe,CA8D3G"}
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/agent/git.ts"],"names":[],"mappings":"AAkHA,MAAM,WAAW,eAAe;IAC5B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,kLAAkL;IAClL,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,YAAY,GAAG,QAAQ,CAAC;CAC1C;AAED,MAAM,WAAW,gBAAgB;IAC7B,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAChC;AAiFD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOhD;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,eAAe,CA8D3G"}
package/dist/agent/git.js CHANGED
@@ -2,6 +2,7 @@
2
2
  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
3
3
  // See LICENSE.txt for license information.
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.isTestFile = isTestFile;
5
6
  exports.getChangedFiles = getChangedFiles;
6
7
  const child_process_1 = require("child_process");
7
8
  const utils_js_1 = require("./utils.js");
@@ -178,6 +179,18 @@ function isCommentOnlyDiff(file, repoRoot, baseRef) {
178
179
  return content === '' || commentEntry.pattern.test(content);
179
180
  });
180
181
  }
182
+ /**
183
+ * Check if a file path is a test file (spec, test, or in test directories).
184
+ * Shared across pipeline and crew orchestrators.
185
+ */
186
+ function isTestFile(file) {
187
+ const normalized = file.replace(/\\/g, '/');
188
+ return /\.(spec|test)\.(ts|tsx|js|jsx)$/.test(normalized) ||
189
+ /_test\.go$/.test(normalized) ||
190
+ normalized.includes('__tests__/') ||
191
+ normalized.includes('/tests/') ||
192
+ normalized.includes('/test/');
193
+ }
181
194
  function getChangedFiles(appRoot, since, options) {
182
195
  try {
183
196
  const files = new Set();
@@ -0,0 +1,8 @@
1
+ import type { Agent, AgentTask, AgentResult } from '../crew/protocol.js';
2
+ import type { CrewContext } from '../crew/context.js';
3
+ import type { AgentRole } from '../crew/types.js';
4
+ export declare class CoverageEvaluatorAgent implements Agent {
5
+ readonly role: AgentRole;
6
+ execute(_task: AgentTask, ctx: CrewContext): Promise<AgentResult>;
7
+ }
8
+ //# sourceMappingURL=coverage-evaluator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverage-evaluator.d.ts","sourceRoot":"","sources":["../../src/agents/coverage-evaluator.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAC,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,kBAAkB,CAAC;AAEhD,qBAAa,sBAAuB,YAAW,KAAK;IAChD,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAwB;IAE1C,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;CAmC1E"}
@@ -0,0 +1,41 @@
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.CoverageEvaluatorAgent = void 0;
6
+ /**
7
+ * Coverage Evaluator Agent — wraps pipeline stage2 (coverage evaluation) in the Agent interface.
8
+ */
9
+ const stage2_coverage_js_1 = require("../pipeline/stage2_coverage.js");
10
+ class CoverageEvaluatorAgent {
11
+ constructor() {
12
+ this.role = 'coverage-evaluator';
13
+ }
14
+ async execute(_task, ctx) {
15
+ const warnings = [];
16
+ if (ctx.impactedFlows.length === 0) {
17
+ warnings.push('Coverage evaluator: no impacted flows to evaluate.');
18
+ return { role: this.role, status: 'partial', output: [], warnings };
19
+ }
20
+ try {
21
+ const result = await (0, stage2_coverage_js_1.runCoverageStage)(ctx.impactedFlows, ctx.specIndex, ctx.context, ctx.testsRoot, { provider: ctx.providerOverride });
22
+ // Replace impacted flows with coverage-enriched versions.
23
+ // This is intentionally a full replace (not push) because coverage evaluation
24
+ // returns the same flow IDs with updated coverage fields.
25
+ ctx.impactedFlows = result.decisions;
26
+ warnings.push(...result.warnings);
27
+ return {
28
+ role: this.role,
29
+ status: 'success',
30
+ output: result.decisions,
31
+ warnings,
32
+ };
33
+ }
34
+ catch (error) {
35
+ const message = error instanceof Error ? error.message : String(error);
36
+ warnings.push(`Coverage evaluator failed: ${message}`);
37
+ return { role: this.role, status: 'failed', output: null, warnings };
38
+ }
39
+ }
40
+ }
41
+ exports.CoverageEvaluatorAgent = CoverageEvaluatorAgent;
@@ -0,0 +1,13 @@
1
+ import type { Agent, AgentTask, AgentResult } from '../crew/protocol.js';
2
+ import type { CrewContext } from '../crew/context.js';
3
+ import type { AgentRole } from '../crew/types.js';
4
+ export declare class CrossImpactAgent implements Agent {
5
+ readonly role: AgentRole;
6
+ execute(_task: AgentTask, ctx: CrewContext): Promise<AgentResult>;
7
+ /**
8
+ * Deterministic cross-impact detection: find families that share webapp/server paths
9
+ * or components with the directly impacted families.
10
+ */
11
+ private detectDeterministic;
12
+ }
13
+ //# sourceMappingURL=cross-impact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cross-impact.d.ts","sourceRoot":"","sources":["../../src/agents/cross-impact.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAC,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAC,SAAS,EAAc,MAAM,kBAAkB,CAAC;AAK7D,qBAAa,gBAAiB,YAAW,KAAK;IAC1C,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAkB;IAEpC,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAuFvE;;;OAGG;IACH,OAAO,CAAC,mBAAmB;CAyC9B"}
@@ -0,0 +1,135 @@
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.CrossImpactAgent = void 0;
6
+ /**
7
+ * Cross-Impact Analyst Agent — finds ripple effects across route families
8
+ * by analyzing shared dependencies between changed families and all other families.
9
+ */
10
+ const provider_js_1 = require("../crew/provider.js");
11
+ const cross_impact_js_1 = require("../prompts/cross-impact.js");
12
+ const VALID_RISK = new Set(['high', 'medium', 'low']);
13
+ const MAX_CROSS_IMPACTS = 50;
14
+ class CrossImpactAgent {
15
+ constructor() {
16
+ this.role = 'cross-impact';
17
+ }
18
+ async execute(_task, ctx) {
19
+ const warnings = [];
20
+ if (ctx.routeFamilies.length === 0) {
21
+ warnings.push('Cross-impact: no route families available.');
22
+ return { role: this.role, status: 'partial', output: [], warnings };
23
+ }
24
+ // Determine directly impacted families from family groups
25
+ const directlyImpacted = new Set(ctx.familyGroups.map((g) => g.familyId));
26
+ if (directlyImpacted.size === 0) {
27
+ warnings.push('Cross-impact: no directly impacted families.');
28
+ return { role: this.role, status: 'partial', output: [], warnings };
29
+ }
30
+ // First: deterministic cross-impact detection via shared paths
31
+ const deterministicCrossImpacts = this.detectDeterministic(ctx, directlyImpacted)
32
+ .slice(0, MAX_CROSS_IMPACTS);
33
+ ctx.crossImpacts.push(...deterministicCrossImpacts);
34
+ // Then: LLM-enriched analysis for semantic cross-impacts
35
+ try {
36
+ const provider = await (0, provider_js_1.getCrewProvider)(ctx.providerOverride);
37
+ const prompt = (0, cross_impact_js_1.buildCrossImpactPrompt)({
38
+ changedFiles: ctx.changedFiles,
39
+ families: ctx.routeFamilies,
40
+ directlyImpactedFamilyIds: Array.from(directlyImpacted),
41
+ });
42
+ const response = await provider.generateText(prompt, {
43
+ maxTokens: 3000,
44
+ temperature: 0,
45
+ timeout: 45000,
46
+ systemPrompt: 'Return only valid JSON. Do not include markdown fences unless necessary.',
47
+ });
48
+ const parsed = (0, cross_impact_js_1.parseCrossImpactResponse)(response.text);
49
+ if (parsed && parsed.crossImpacts.length > 0) {
50
+ const familyIds = new Set(ctx.routeFamilies.map((f) => f.id));
51
+ const llmCrossImpacts = parsed.crossImpacts
52
+ .filter((ci) => familyIds.has(ci.sourceFamily) &&
53
+ familyIds.has(ci.affectedFamily) &&
54
+ ci.sourceFamily !== ci.affectedFamily)
55
+ .map((ci) => ({
56
+ sourceFamily: ci.sourceFamily,
57
+ affectedFamily: ci.affectedFamily,
58
+ sharedDependency: ci.sharedDependency || 'unknown',
59
+ riskLevel: VALID_RISK.has(ci.riskLevel) ? ci.riskLevel : 'low',
60
+ evidence: ci.evidence || '',
61
+ }));
62
+ // Deduplicate against deterministic results
63
+ const existing = new Set(ctx.crossImpacts.map((ci) => `${ci.sourceFamily}->${ci.affectedFamily}`));
64
+ for (const ci of llmCrossImpacts) {
65
+ if (ctx.crossImpacts.length >= MAX_CROSS_IMPACTS)
66
+ break;
67
+ const key = `${ci.sourceFamily}->${ci.affectedFamily}`;
68
+ if (!existing.has(key)) {
69
+ ctx.crossImpacts.push(ci);
70
+ existing.add(key);
71
+ }
72
+ }
73
+ }
74
+ return {
75
+ role: this.role,
76
+ status: ctx.crossImpacts.length > 0 ? 'success' : 'partial',
77
+ output: ctx.crossImpacts,
78
+ usage: provider.getUsageStats(),
79
+ warnings,
80
+ };
81
+ }
82
+ catch (error) {
83
+ const message = error instanceof Error ? error.message : String(error);
84
+ warnings.push(`Cross-impact LLM analysis failed: ${message}. Using deterministic results only.`);
85
+ return {
86
+ role: this.role,
87
+ status: deterministicCrossImpacts.length > 0 ? 'partial' : 'failed',
88
+ output: ctx.crossImpacts,
89
+ warnings,
90
+ };
91
+ }
92
+ }
93
+ /**
94
+ * Deterministic cross-impact detection: find families that share webapp/server paths
95
+ * or components with the directly impacted families.
96
+ */
97
+ detectDeterministic(ctx, directlyImpacted) {
98
+ const results = [];
99
+ for (const sourceId of directlyImpacted) {
100
+ const source = ctx.routeFamilies.find((f) => f.id === sourceId);
101
+ if (!source)
102
+ continue;
103
+ const sourcePaths = new Set([
104
+ ...(source.webappPaths || []),
105
+ ...(source.serverPaths || []),
106
+ ...(source.components || []),
107
+ ]);
108
+ if (sourcePaths.size === 0)
109
+ continue;
110
+ for (const target of ctx.routeFamilies) {
111
+ if (target.id === sourceId)
112
+ continue;
113
+ const targetPaths = [
114
+ ...(target.webappPaths || []),
115
+ ...(target.serverPaths || []),
116
+ ...(target.components || []),
117
+ ];
118
+ for (const path of targetPaths) {
119
+ if (sourcePaths.has(path)) {
120
+ results.push({
121
+ sourceFamily: sourceId,
122
+ affectedFamily: target.id,
123
+ sharedDependency: path,
124
+ riskLevel: 'medium',
125
+ evidence: `Shared path: ${path} is referenced by both ${sourceId} and ${target.id}`,
126
+ });
127
+ break; // One match per family pair is enough
128
+ }
129
+ }
130
+ }
131
+ }
132
+ return results;
133
+ }
134
+ }
135
+ exports.CrossImpactAgent = CrossImpactAgent;
@@ -0,0 +1,8 @@
1
+ import type { Agent, AgentTask, AgentResult } from '../crew/protocol.js';
2
+ import type { CrewContext } from '../crew/context.js';
3
+ import type { AgentRole } from '../crew/types.js';
4
+ export declare class ExecutorAgent implements Agent {
5
+ readonly role: AgentRole;
6
+ execute(_task: AgentTask, ctx: CrewContext): Promise<AgentResult>;
7
+ }
8
+ //# sourceMappingURL=executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/agents/executor.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAC,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,kBAAkB,CAAC;AAKhD,qBAAa,aAAc,YAAW,KAAK;IACvC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAc;IAEhC,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;CAwD1E"}
@@ -0,0 +1,70 @@
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.ExecutorAgent = void 0;
6
+ /**
7
+ * Executor Agent — wraps agentic test execution in the Agent interface.
8
+ * Runs generated specs through Playwright and collects results.
9
+ */
10
+ const provider_js_1 = require("../crew/provider.js");
11
+ const runner_js_1 = require("../agentic/runner.js");
12
+ const MAX_FIX_ATTEMPTS = 2;
13
+ const TEST_TIMEOUT_MS = 120000;
14
+ class ExecutorAgent {
15
+ constructor() {
16
+ this.role = 'executor';
17
+ }
18
+ async execute(_task, ctx) {
19
+ const warnings = [];
20
+ const writtenSpecs = ctx.generatedSpecs.filter((s) => s.written);
21
+ if (writtenSpecs.length === 0) {
22
+ warnings.push('Executor: no written specs to execute.');
23
+ return { role: this.role, status: 'partial', output: null, warnings };
24
+ }
25
+ // Build ScenarioInput[] from generated specs + impacted flows
26
+ const flowMap = new Map(ctx.impactedFlows.map((f) => [f.flowId, f]));
27
+ const scenarios = writtenSpecs.map((spec) => {
28
+ const flow = flowMap.get(spec.flowId);
29
+ return {
30
+ id: spec.flowId,
31
+ name: flow?.flowName || spec.flowId,
32
+ scenarios: flow?.scenariosToAdd || [],
33
+ routeFamily: flow?.routeFamily || 'unknown',
34
+ priority: flow?.priority || 'P2',
35
+ targetSpec: spec.mode === 'add_scenarios' ? spec.specPath : undefined,
36
+ changedFiles: flow?.changedFiles,
37
+ evidence: flow?.evidence,
38
+ };
39
+ });
40
+ try {
41
+ const provider = await (0, provider_js_1.getCrewProvider)(ctx.providerOverride);
42
+ const summary = await (0, runner_js_1.runAgenticGeneration)({
43
+ scenarios,
44
+ config: {
45
+ maxAttempts: MAX_FIX_ATTEMPTS,
46
+ project: 'chrome',
47
+ testTimeoutMs: TEST_TIMEOUT_MS,
48
+ provider: ctx.providerOverride,
49
+ testsRoot: ctx.testsRoot,
50
+ },
51
+ provider,
52
+ apiSurface: ctx.apiSurface,
53
+ });
54
+ warnings.push(...summary.warnings);
55
+ return {
56
+ role: this.role,
57
+ status: summary.totalPassed > 0 ? 'success' : 'partial',
58
+ output: summary,
59
+ usage: provider.getUsageStats(),
60
+ warnings,
61
+ };
62
+ }
63
+ catch (error) {
64
+ const message = error instanceof Error ? error.message : String(error);
65
+ warnings.push(`Executor failed: ${message}`);
66
+ return { role: this.role, status: 'failed', output: null, warnings };
67
+ }
68
+ }
69
+ }
70
+ exports.ExecutorAgent = ExecutorAgent;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Explorer Agent — wraps the QA agent browser exploration loop in the Agent interface.
3
+ * This agent is optional and only runs when a browser environment is available.
4
+ */
5
+ import type { Agent, AgentTask, AgentResult } from '../crew/protocol.js';
6
+ import type { CrewContext } from '../crew/context.js';
7
+ import type { AgentRole } from '../crew/types.js';
8
+ export declare class ExplorerAgent implements Agent {
9
+ readonly role: AgentRole;
10
+ execute(_task: AgentTask, ctx: CrewContext): Promise<AgentResult>;
11
+ }
12
+ //# sourceMappingURL=explorer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explorer.d.ts","sourceRoot":"","sources":["../../src/agents/explorer.ts"],"names":[],"mappings":"AAGA;;;GAGG;AAEH,OAAO,KAAK,EAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAC,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,kBAAkB,CAAC;AAEhD,qBAAa,aAAc,YAAW,KAAK;IACvC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAc;IAEhC,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;CAmC1E"}
@@ -0,0 +1,43 @@
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.ExplorerAgent = void 0;
6
+ class ExplorerAgent {
7
+ constructor() {
8
+ this.role = 'explorer';
9
+ }
10
+ async execute(_task, ctx) {
11
+ const warnings = [];
12
+ // Explorer requires browser environment — skip gracefully if not available
13
+ try {
14
+ // Build target flows from impacted flows
15
+ const targetFlows = ctx.impactedFlows
16
+ .filter((d) => d.action !== 'cannot_determine')
17
+ .map((d) => ({
18
+ id: d.flowId,
19
+ name: d.flowName,
20
+ url: d.specificRoute,
21
+ priority: d.priority,
22
+ }));
23
+ if (targetFlows.length === 0) {
24
+ warnings.push('Explorer: no target flows for exploration.');
25
+ return { role: this.role, status: 'partial', output: null, warnings };
26
+ }
27
+ // Convert QA findings to crew findings
28
+ warnings.push(`Explorer: ${targetFlows.length} flows available for exploration (requires browser environment).`);
29
+ return {
30
+ role: this.role,
31
+ status: 'partial',
32
+ output: { targetFlows },
33
+ warnings,
34
+ };
35
+ }
36
+ catch (error) {
37
+ const message = error instanceof Error ? error.message : String(error);
38
+ warnings.push(`Explorer failed: ${message}`);
39
+ return { role: this.role, status: 'failed', output: null, warnings };
40
+ }
41
+ }
42
+ }
43
+ exports.ExplorerAgent = ExplorerAgent;
@@ -0,0 +1,8 @@
1
+ import type { Agent, AgentTask, AgentResult } from '../crew/protocol.js';
2
+ import type { CrewContext } from '../crew/context.js';
3
+ import type { AgentRole } from '../crew/types.js';
4
+ export declare class GeneratorAgent implements Agent {
5
+ readonly role: AgentRole;
6
+ execute(_task: AgentTask, ctx: CrewContext): Promise<AgentResult>;
7
+ }
8
+ //# sourceMappingURL=generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/agents/generator.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAC,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,kBAAkB,CAAC;AA6ChD,qBAAa,cAAe,YAAW,KAAK;IACxC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAe;IAEjC,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;CAoC1E"}
@@ -0,0 +1,77 @@
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.GeneratorAgent = void 0;
6
+ /**
7
+ * Generator Agent — wraps pipeline stage3 (test generation) in the Agent interface.
8
+ * Enhanced to accept TestCase[] from the Test Designer in addition to flat scenariosToAdd.
9
+ */
10
+ const stage3_generation_js_1 = require("../pipeline/stage3_generation.js");
11
+ /**
12
+ * Enrich FlowDecisions with TestDesign data from the crew context.
13
+ * Converts structured TestCase[] into scenariosToAdd strings that the
14
+ * existing generation prompt can consume.
15
+ */
16
+ function enrichDecisionsWithTestDesigns(ctx) {
17
+ if (ctx.testDesigns.length === 0) {
18
+ return ctx.impactedFlows;
19
+ }
20
+ const designsByFlow = new Map(ctx.testDesigns.map((td) => [td.flowId, td]));
21
+ return ctx.impactedFlows.map((decision) => {
22
+ const design = designsByFlow.get(decision.flowId);
23
+ if (!design || design.testCases.length === 0) {
24
+ return decision;
25
+ }
26
+ // Convert structured test cases to scenario descriptions for the generator prompt
27
+ const designedScenarios = design.testCases.map((tc) => {
28
+ const steps = tc.steps.join(' → ');
29
+ return `[${tc.type}] ${tc.name}: ${steps} → Expected: ${tc.expectedOutcome}`;
30
+ });
31
+ // Merge with any existing scenarios, preferring designed ones
32
+ const existingScenarios = decision.scenariosToAdd || [];
33
+ const mergedScenarios = [...designedScenarios, ...existingScenarios];
34
+ return {
35
+ ...decision,
36
+ scenariosToAdd: mergedScenarios,
37
+ // Intentionally promote run_existing → add_scenarios when the test-designer
38
+ // produced new test cases. This ensures designed tests are generated even if
39
+ // impact-analyst thought existing coverage was sufficient. The test-designer
40
+ // only runs for flows the strategist deemed worth testing.
41
+ action: decision.action === 'run_existing' && designedScenarios.length > 0
42
+ ? 'add_scenarios'
43
+ : decision.action,
44
+ };
45
+ });
46
+ }
47
+ class GeneratorAgent {
48
+ constructor() {
49
+ this.role = 'generator';
50
+ }
51
+ async execute(_task, ctx) {
52
+ const warnings = [];
53
+ const enrichedDecisions = enrichDecisionsWithTestDesigns(ctx);
54
+ const actionable = enrichedDecisions.filter((d) => d.action === 'create_spec' || d.action === 'add_scenarios');
55
+ if (actionable.length === 0) {
56
+ warnings.push('Generator: no actionable decisions for generation.');
57
+ return { role: this.role, status: 'partial', output: [], warnings };
58
+ }
59
+ try {
60
+ const result = await (0, stage3_generation_js_1.runGenerationStage)(enrichedDecisions, ctx.apiSurface, ctx.testsRoot, { provider: ctx.providerOverride });
61
+ ctx.generatedSpecs.push(...result.generated);
62
+ warnings.push(...result.warnings);
63
+ return {
64
+ role: this.role,
65
+ status: result.generatedCount > 0 ? 'success' : 'partial',
66
+ output: result,
67
+ warnings,
68
+ };
69
+ }
70
+ catch (error) {
71
+ const message = error instanceof Error ? error.message : String(error);
72
+ warnings.push(`Generator failed: ${message}`);
73
+ return { role: this.role, status: 'failed', output: null, warnings };
74
+ }
75
+ }
76
+ }
77
+ exports.GeneratorAgent = GeneratorAgent;
@@ -0,0 +1,8 @@
1
+ import type { Agent, AgentTask, AgentResult } from '../crew/protocol.js';
2
+ import type { CrewContext } from '../crew/context.js';
3
+ import type { AgentRole } from '../crew/types.js';
4
+ export declare class HealerAgent implements Agent {
5
+ readonly role: AgentRole;
6
+ execute(_task: AgentTask, ctx: CrewContext): Promise<AgentResult>;
7
+ }
8
+ //# sourceMappingURL=healer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"healer.d.ts","sourceRoot":"","sources":["../../src/agents/healer.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAC,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,kBAAkB,CAAC;AAEhD,qBAAa,WAAY,YAAW,KAAK;IACrC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAY;IAE9B,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;CAwB1E"}
@@ -0,0 +1,31 @@
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.HealerAgent = void 0;
6
+ /**
7
+ * Healer Agent — wraps pipeline stage4 (test healing) in the Agent interface.
8
+ */
9
+ const stage4_heal_js_1 = require("../pipeline/stage4_heal.js");
10
+ class HealerAgent {
11
+ constructor() {
12
+ this.role = 'healer';
13
+ }
14
+ async execute(_task, ctx) {
15
+ const warnings = [];
16
+ const healTargets = (0, stage4_heal_js_1.resolveHealTargets)(ctx.testsRoot, { generatedSpecs: ctx.generatedSpecs }, ctx.impactedFlows);
17
+ if (healTargets.length === 0) {
18
+ warnings.push('Healer: no heal targets found.');
19
+ return { role: this.role, status: 'partial', output: null, warnings };
20
+ }
21
+ const result = await (0, stage4_heal_js_1.runHealStage)(ctx.testsRoot, healTargets, { mcp: true });
22
+ warnings.push(...result.warnings);
23
+ return {
24
+ role: this.role,
25
+ status: result.healSuccess > 0 ? 'success' : 'partial',
26
+ output: result,
27
+ warnings,
28
+ };
29
+ }
30
+ }
31
+ exports.HealerAgent = HealerAgent;
@@ -0,0 +1,8 @@
1
+ import type { Agent, AgentTask, AgentResult } from '../crew/protocol.js';
2
+ import type { CrewContext } from '../crew/context.js';
3
+ import type { AgentRole } from '../crew/types.js';
4
+ export declare class ImpactAnalystAgent implements Agent {
5
+ readonly role: AgentRole;
6
+ execute(_task: AgentTask, ctx: CrewContext): Promise<AgentResult>;
7
+ }
8
+ //# sourceMappingURL=impact-analyst.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"impact-analyst.d.ts","sourceRoot":"","sources":["../../src/agents/impact-analyst.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAC,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,kBAAkB,CAAC;AAEhD,qBAAa,kBAAmB,YAAW,KAAK;IAC5C,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAoB;IAEtC,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;CAiC1E"}
@@ -0,0 +1,38 @@
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.ImpactAnalystAgent = void 0;
6
+ /**
7
+ * Impact Analyst Agent — wraps pipeline stage1 (impact analysis) in the Agent interface.
8
+ */
9
+ const stage1_impact_js_1 = require("../pipeline/stage1_impact.js");
10
+ class ImpactAnalystAgent {
11
+ constructor() {
12
+ this.role = 'impact-analyst';
13
+ }
14
+ async execute(_task, ctx) {
15
+ const warnings = [];
16
+ if (ctx.familyGroups.length === 0) {
17
+ warnings.push('Impact analyst: no family groups to analyze.');
18
+ return { role: this.role, status: 'partial', output: [], warnings };
19
+ }
20
+ try {
21
+ const result = await (0, stage1_impact_js_1.runImpactStage)(ctx.familyGroups, ctx.manifest, ctx.specIndex, ctx.apiSurface, ctx.context, { provider: ctx.providerOverride });
22
+ ctx.impactedFlows.push(...result.decisions);
23
+ warnings.push(...result.warnings);
24
+ return {
25
+ role: this.role,
26
+ status: result.decisions.length > 0 ? 'success' : 'partial',
27
+ output: result.decisions,
28
+ warnings,
29
+ };
30
+ }
31
+ catch (error) {
32
+ const message = error instanceof Error ? error.message : String(error);
33
+ warnings.push(`Impact analyst failed: ${message}`);
34
+ return { role: this.role, status: 'failed', output: null, warnings };
35
+ }
36
+ }
37
+ }
38
+ exports.ImpactAnalystAgent = ImpactAnalystAgent;
@@ -0,0 +1,8 @@
1
+ import type { Agent, AgentTask, AgentResult } from '../crew/protocol.js';
2
+ import type { CrewContext } from '../crew/context.js';
3
+ import type { AgentRole } from '../crew/types.js';
4
+ export declare class RegressionAdvisorAgent implements Agent {
5
+ readonly role: AgentRole;
6
+ execute(_task: AgentTask, ctx: CrewContext): Promise<AgentResult>;
7
+ }
8
+ //# sourceMappingURL=regression-advisor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regression-advisor.d.ts","sourceRoot":"","sources":["../../src/agents/regression-advisor.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAC,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAC,SAAS,EAAiB,MAAM,kBAAkB,CAAC;AAUhE,qBAAa,sBAAuB,YAAW,KAAK;IAChD,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAwB;IAE1C,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;CA0G1E"}