@yasserkhanorg/e2e-agents 1.7.7 → 1.8.1
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.
- package/README.md +55 -0
- package/dist/agent/git.d.ts +5 -0
- package/dist/agent/git.d.ts.map +1 -1
- package/dist/agent/git.js +13 -0
- package/dist/agents/coverage-evaluator.d.ts +8 -0
- package/dist/agents/coverage-evaluator.d.ts.map +1 -0
- package/dist/agents/coverage-evaluator.js +41 -0
- package/dist/agents/cross-impact.d.ts +13 -0
- package/dist/agents/cross-impact.d.ts.map +1 -0
- package/dist/agents/cross-impact.js +135 -0
- package/dist/agents/executor.d.ts +8 -0
- package/dist/agents/executor.d.ts.map +1 -0
- package/dist/agents/executor.js +70 -0
- package/dist/agents/explorer.d.ts +12 -0
- package/dist/agents/explorer.d.ts.map +1 -0
- package/dist/agents/explorer.js +43 -0
- package/dist/agents/generator.d.ts +8 -0
- package/dist/agents/generator.d.ts.map +1 -0
- package/dist/agents/generator.js +77 -0
- package/dist/agents/healer.d.ts +8 -0
- package/dist/agents/healer.d.ts.map +1 -0
- package/dist/agents/healer.js +31 -0
- package/dist/agents/impact-analyst.d.ts +8 -0
- package/dist/agents/impact-analyst.d.ts.map +1 -0
- package/dist/agents/impact-analyst.js +38 -0
- package/dist/agents/regression-advisor.d.ts +8 -0
- package/dist/agents/regression-advisor.d.ts.map +1 -0
- package/dist/agents/regression-advisor.js +116 -0
- package/dist/agents/strategist.d.ts +9 -0
- package/dist/agents/strategist.d.ts.map +1 -0
- package/dist/agents/strategist.js +87 -0
- package/dist/agents/test-designer.d.ts +8 -0
- package/dist/agents/test-designer.d.ts.map +1 -0
- package/dist/agents/test-designer.js +106 -0
- package/dist/cli/commands/crew.d.ts +3 -0
- package/dist/cli/commands/crew.d.ts.map +1 -0
- package/dist/cli/commands/crew.js +137 -0
- package/dist/cli/parse_args.d.ts.map +1 -1
- package/dist/cli/parse_args.js +2 -1
- package/dist/cli/types.d.ts +2 -1
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/cli.js +5 -0
- package/dist/crew/context.d.ts +40 -0
- package/dist/crew/context.d.ts.map +1 -0
- package/dist/crew/context.js +36 -0
- package/dist/crew/orchestrator.d.ts +36 -0
- package/dist/crew/orchestrator.d.ts.map +1 -0
- package/dist/crew/orchestrator.js +171 -0
- package/dist/crew/protocol.d.ts +33 -0
- package/dist/crew/protocol.d.ts.map +1 -0
- package/dist/crew/protocol.js +4 -0
- package/dist/crew/provider.d.ts +3 -0
- package/dist/crew/provider.d.ts.map +1 -0
- package/dist/crew/provider.js +16 -0
- package/dist/crew/sanitize.d.ts +3 -0
- package/dist/crew/sanitize.d.ts.map +1 -0
- package/dist/crew/sanitize.js +31 -0
- package/dist/crew/types.d.ts +52 -0
- package/dist/crew/types.d.ts.map +1 -0
- package/dist/crew/types.js +4 -0
- package/dist/crew/workflows.d.ts +52 -0
- package/dist/crew/workflows.d.ts.map +1 -0
- package/dist/crew/workflows.js +36 -0
- package/dist/esm/agent/git.js +12 -0
- package/dist/esm/agents/coverage-evaluator.js +37 -0
- package/dist/esm/agents/cross-impact.js +131 -0
- package/dist/esm/agents/executor.js +66 -0
- package/dist/esm/agents/explorer.js +39 -0
- package/dist/esm/agents/generator.js +73 -0
- package/dist/esm/agents/healer.js +27 -0
- package/dist/esm/agents/impact-analyst.js +34 -0
- package/dist/esm/agents/regression-advisor.js +112 -0
- package/dist/esm/agents/strategist.js +83 -0
- package/dist/esm/agents/test-designer.js +102 -0
- package/dist/esm/cli/commands/crew.js +134 -0
- package/dist/esm/cli/parse_args.js +2 -1
- package/dist/esm/cli.js +5 -0
- package/dist/esm/crew/context.js +32 -0
- package/dist/esm/crew/orchestrator.js +167 -0
- package/dist/esm/crew/protocol.js +3 -0
- package/dist/esm/crew/provider.js +13 -0
- package/dist/esm/crew/sanitize.js +27 -0
- package/dist/esm/crew/types.js +3 -0
- package/dist/esm/crew/workflows.js +33 -0
- package/dist/esm/index.js +14 -0
- package/dist/esm/knowledge/route_families.js +2 -2
- package/dist/esm/logger.js +1 -2
- package/dist/esm/ollama_provider.js +1 -1
- package/dist/esm/prompts/cross-impact.js +71 -0
- package/dist/esm/prompts/strategist.js +79 -0
- package/dist/esm/prompts/test-designer.js +107 -0
- package/dist/esm/provider_factory.js +6 -10
- package/dist/esm/training/enricher.js +4 -3
- package/dist/esm/training/validator.js +2 -1
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +27 -1
- package/dist/knowledge/route_families.d.ts.map +1 -1
- package/dist/knowledge/route_families.js +2 -2
- package/dist/logger.d.ts +1 -2
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +1 -2
- package/dist/ollama_provider.js +1 -1
- package/dist/prompts/cross-impact.d.ts +22 -0
- package/dist/prompts/cross-impact.d.ts.map +1 -0
- package/dist/prompts/cross-impact.js +75 -0
- package/dist/prompts/strategist.d.ts +25 -0
- package/dist/prompts/strategist.d.ts.map +1 -0
- package/dist/prompts/strategist.js +83 -0
- package/dist/prompts/test-designer.d.ts +33 -0
- package/dist/prompts/test-designer.d.ts.map +1 -0
- package/dist/prompts/test-designer.js +111 -0
- package/dist/provider_factory.d.ts.map +1 -1
- package/dist/provider_factory.js +6 -10
- package/dist/training/enricher.d.ts.map +1 -1
- package/dist/training/enricher.js +4 -3
- package/dist/training/validator.d.ts.map +1 -1
- package/dist/training/validator.js +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,6 +11,9 @@ AI-powered E2E test impact analysis, generation, healing, and autonomous QA for
|
|
|
11
11
|
Given a git diff, `e2e-ai-agents` determines which E2E test flows are impacted, identifies coverage gaps, and can generate or heal Playwright tests — all from the CLI. The companion `e2e-qa-agent` goes further: it opens a real browser, explores your app autonomously, and produces a QA report with findings and a release-readiness verdict.
|
|
12
12
|
|
|
13
13
|
**Pipeline:** `impact` → `plan` → `generate` → `heal` → `finalize`
|
|
14
|
+
**Crew (v1.8.0):** `impact` + `cross-impact` + `regression-advisor` → `strategist` → `test-designer` → `generator` → `executor` → `healer`
|
|
15
|
+
|
|
16
|
+
> **How does this compare to other tools?** See [docs/comparison.md](docs/comparison.md) for a detailed analysis against Launchable, Codecov ATS, Qodo, Testsigma, mabl, GitHub Copilot, and others.
|
|
14
17
|
|
|
15
18
|
## Installation
|
|
16
19
|
|
|
@@ -54,6 +57,58 @@ npx e2e-ai-agents llm-health
|
|
|
54
57
|
|
|
55
58
|
`plan` and `suggest` are aliases. `analyze` is a convenience wrapper that runs impact + plan and optionally generation/healing in one invocation. Use `--help` for all available flags.
|
|
56
59
|
|
|
60
|
+
## Multi-Agent Crew (v1.8.0)
|
|
61
|
+
|
|
62
|
+
The Crew orchestrates 10 specialized agents for deep test analysis. While the standard pipeline gives a fast pass/fail gate, the Crew produces structured test designs, cross-family impact maps, and prioritized test strategies.
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# Quick strategy: impact + strategy recommendations (~$0.10, ~1 min)
|
|
66
|
+
npx e2e-ai-agents crew --workflow quick-check --path /path/to/project --tests-root ./e2e-tests --since origin/master
|
|
67
|
+
|
|
68
|
+
# Full test design without generation (~$0.50-2.00, ~5-40 min)
|
|
69
|
+
npx e2e-ai-agents crew --workflow design-only --path /path/to/project --tests-root ./e2e-tests --since origin/master
|
|
70
|
+
|
|
71
|
+
# End-to-end: design + generate + execute + heal (~$2-5, ~10-60 min)
|
|
72
|
+
npx e2e-ai-agents crew --workflow full-qa --path /path/to/project --tests-root ./e2e-tests --since origin/master
|
|
73
|
+
|
|
74
|
+
# With budget cap and JSON output
|
|
75
|
+
npx e2e-ai-agents crew --workflow design-only --budget-usd 2.00 --json --path /path/to/project --tests-root ./e2e-tests --since origin/master
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### What the Crew Adds Beyond the Pipeline
|
|
79
|
+
|
|
80
|
+
| Capability | Pipeline | Crew |
|
|
81
|
+
|-----------|---------|------|
|
|
82
|
+
| Impact detection | Per-family, isolated | Same + cross-family ripple detection |
|
|
83
|
+
| Test scenarios | Flat `scenariosToAdd` strings | Structured `TestCase[]` with type, preconditions, steps, expected outcome, rationale |
|
|
84
|
+
| Test categories | None | 9: happy-path, edge-case, boundary, negative, state-transition, race-condition, permission, accessibility, performance |
|
|
85
|
+
| Strategy | None | Per-flow approach (full-test / smoke-test / skip) with priority and rationale |
|
|
86
|
+
| Regression awareness | None | Risk scoring from flaky history, calibration data, and file-pattern heuristics |
|
|
87
|
+
|
|
88
|
+
### Programmatic API
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
import { CrewOrchestrator, ImpactAnalystAgent, StrategistAgent, TestDesignerAgent, CrossImpactAgent, RegressionAdvisorAgent } from '@yasserkhanorg/e2e-agents';
|
|
92
|
+
|
|
93
|
+
const orchestrator = new CrewOrchestrator();
|
|
94
|
+
orchestrator.registerAgent(new ImpactAnalystAgent());
|
|
95
|
+
orchestrator.registerAgent(new CrossImpactAgent());
|
|
96
|
+
orchestrator.registerAgent(new RegressionAdvisorAgent());
|
|
97
|
+
orchestrator.registerAgent(new StrategistAgent());
|
|
98
|
+
orchestrator.registerAgent(new TestDesignerAgent());
|
|
99
|
+
|
|
100
|
+
const result = await orchestrator.run({
|
|
101
|
+
appPath: './webapp',
|
|
102
|
+
testsRoot: './e2e-tests',
|
|
103
|
+
gitSince: 'origin/master',
|
|
104
|
+
workflow: 'design-only',
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
console.log(result.context.testDesigns); // Structured test cases
|
|
108
|
+
console.log(result.context.crossImpacts); // Cross-family links
|
|
109
|
+
console.log(result.context.strategyEntries); // Prioritized strategy
|
|
110
|
+
```
|
|
111
|
+
|
|
57
112
|
## Route-Families Training
|
|
58
113
|
|
|
59
114
|
### What it produces
|
package/dist/agent/git.d.ts
CHANGED
|
@@ -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
|
package/dist/agent/git.d.ts.map
CHANGED
|
@@ -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"}
|