@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/crew/context.ts"],"names":[],"mappings":"AAGA;;GAEG;AAEH,OAAO,KAAK,EAAC,WAAW,EAAE,mBAAmB,EAAC,MAAM,gCAAgC,CAAC;AACrF,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,6BAA6B,CAAC;AACnE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,4BAA4B,CAAC;AAC1D,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,gCAAgC,CAAC;AACjE,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,gCAAgC,CAAC;AAClE,OAAO,KAAK,EAAC,WAAW,EAAE,gBAAgB,EAAC,MAAM,kCAAkC,CAAC;AACpF,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAC,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAC,MAAM,YAAY,CAAC;AAEhG,MAAM,WAAW,WAAW;IAExB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,EAAE,WAAW,EAAE,CAAC;IAC7B,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACrC,UAAU,EAAE,iBAAiB,CAAC;IAC9B,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,aAAa,CAAC;IACvB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAG1C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAG1B,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,eAAe,EAAE,aAAa,EAAE,CAAC;IACjC,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,eAAe,EAAE,cAAc,EAAE,CAAC;IAClC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,cAAc,EAAE,aAAa,EAAE,CAAC;IAGhC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,wBAAgB,qBAAqB,IAAI,kBAAkB,CAa1D;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,kBAAkB,EAAE,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAe5F"}
|
|
@@ -0,0 +1,36 @@
|
|
|
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.createEmptyUsageStats = createEmptyUsageStats;
|
|
6
|
+
exports.mergeUsageStats = mergeUsageStats;
|
|
7
|
+
function createEmptyUsageStats() {
|
|
8
|
+
const now = new Date();
|
|
9
|
+
return {
|
|
10
|
+
requestCount: 0,
|
|
11
|
+
totalInputTokens: 0,
|
|
12
|
+
totalOutputTokens: 0,
|
|
13
|
+
totalTokens: 0,
|
|
14
|
+
totalCost: 0,
|
|
15
|
+
averageResponseTimeMs: 0,
|
|
16
|
+
failedRequests: 0,
|
|
17
|
+
startTime: now,
|
|
18
|
+
lastUpdated: now,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function mergeUsageStats(target, source) {
|
|
22
|
+
const prevRequestCount = target.requestCount;
|
|
23
|
+
target.requestCount += source.requestCount;
|
|
24
|
+
target.totalInputTokens += source.totalInputTokens;
|
|
25
|
+
target.totalOutputTokens += source.totalOutputTokens;
|
|
26
|
+
target.totalTokens += source.totalTokens;
|
|
27
|
+
target.totalCost += source.totalCost;
|
|
28
|
+
target.failedRequests += source.failedRequests;
|
|
29
|
+
if (source.requestCount > 0 && target.requestCount > 0) {
|
|
30
|
+
const prevWeight = prevRequestCount / target.requestCount;
|
|
31
|
+
const newWeight = source.requestCount / target.requestCount;
|
|
32
|
+
target.averageResponseTimeMs =
|
|
33
|
+
target.averageResponseTimeMs * prevWeight + source.averageResponseTimeMs * newWeight;
|
|
34
|
+
}
|
|
35
|
+
target.lastUpdated = new Date();
|
|
36
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { RouteFamilyConfig } from '../knowledge/route_families.js';
|
|
2
|
+
import type { ApiSurfaceConfig } from '../knowledge/api_surface.js';
|
|
3
|
+
import type { Agent, AgentMessage, AgentResult } from './protocol.js';
|
|
4
|
+
import type { CrewContext } from './context.js';
|
|
5
|
+
import type { AgentRole } from './types.js';
|
|
6
|
+
import type { WorkflowName } from './workflows.js';
|
|
7
|
+
export interface CrewConfig {
|
|
8
|
+
appPath: string;
|
|
9
|
+
testsRoot: string;
|
|
10
|
+
gitSince: string;
|
|
11
|
+
gitIncludeUncommitted?: boolean;
|
|
12
|
+
routeFamilies?: RouteFamilyConfig;
|
|
13
|
+
apiSurface?: ApiSurfaceConfig;
|
|
14
|
+
workflow?: WorkflowName;
|
|
15
|
+
providerOverride?: string;
|
|
16
|
+
budgetUSD?: number;
|
|
17
|
+
dryRun?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface CrewResult {
|
|
20
|
+
context: CrewContext;
|
|
21
|
+
warnings: string[];
|
|
22
|
+
timings: Record<string, number>;
|
|
23
|
+
}
|
|
24
|
+
export declare class CrewOrchestrator {
|
|
25
|
+
private agents;
|
|
26
|
+
registerAgent(agent: Agent): void;
|
|
27
|
+
run(config: CrewConfig): Promise<CrewResult>;
|
|
28
|
+
dispatch(role: AgentRole, action: string, ctx: CrewContext): Promise<AgentResult>;
|
|
29
|
+
parallel(roles: AgentRole[], action: string, ctx: CrewContext): Promise<AgentResult[]>;
|
|
30
|
+
broadcast(msg: AgentMessage, ctx: CrewContext): Promise<void>;
|
|
31
|
+
private runBuiltInPhase;
|
|
32
|
+
private runParallel;
|
|
33
|
+
private runSequential;
|
|
34
|
+
private checkPhaseResults;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=orchestrator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/crew/orchestrator.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,gCAAgC,CAAC;AACtE,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAC,KAAK,EAAE,YAAY,EAAE,WAAW,EAAY,MAAM,eAAe,CAAC;AAC/E,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,cAAc,CAAC;AAE9C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAA6B,YAAY,EAAC,MAAM,gBAAgB,CAAC;AAG7E,MAAM,WAAW,UAAU;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACvB,OAAO,EAAE,WAAW,CAAC;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,qBAAa,gBAAgB;IACzB,OAAO,CAAC,MAAM,CAA+B;IAE7C,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAI3B,GAAG,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAwE5C,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IA6BjF,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAKtF,SAAS,CAAC,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;YAerD,eAAe;YAwBf,WAAW;YAMX,aAAa;IAS3B,OAAO,CAAC,iBAAiB;CAM5B"}
|
|
@@ -0,0 +1,171 @@
|
|
|
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.CrewOrchestrator = void 0;
|
|
6
|
+
/**
|
|
7
|
+
* Crew Orchestrator — executes workflow definitions by dispatching to agents.
|
|
8
|
+
*/
|
|
9
|
+
const git_js_1 = require("../agent/git.js");
|
|
10
|
+
const stage0_preprocess_js_1 = require("../pipeline/stage0_preprocess.js");
|
|
11
|
+
const logger_js_1 = require("../logger.js");
|
|
12
|
+
const context_js_1 = require("./context.js");
|
|
13
|
+
const workflows_js_1 = require("./workflows.js");
|
|
14
|
+
class CrewOrchestrator {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.agents = new Map();
|
|
17
|
+
}
|
|
18
|
+
registerAgent(agent) {
|
|
19
|
+
this.agents.set(agent.role, agent);
|
|
20
|
+
}
|
|
21
|
+
async run(config) {
|
|
22
|
+
const workflow = workflows_js_1.WORKFLOWS[config.workflow || 'full-qa'];
|
|
23
|
+
const timings = {};
|
|
24
|
+
const warnings = [];
|
|
25
|
+
// Step 1: Get changed files
|
|
26
|
+
const gitResult = (0, git_js_1.getChangedFiles)(config.appPath, config.gitSince, {
|
|
27
|
+
includeUncommitted: config.gitIncludeUncommitted,
|
|
28
|
+
});
|
|
29
|
+
if (gitResult.error) {
|
|
30
|
+
warnings.push(`Git diff warning: ${gitResult.error}`);
|
|
31
|
+
}
|
|
32
|
+
const changedFiles = gitResult.files
|
|
33
|
+
.map((f) => f.replace(/\\/g, '/'))
|
|
34
|
+
.filter((f) => !(0, git_js_1.isTestFile)(f));
|
|
35
|
+
if (changedFiles.length === 0) {
|
|
36
|
+
warnings.push('No changed application files detected.');
|
|
37
|
+
}
|
|
38
|
+
// Initialize context (will be populated during preprocess phase)
|
|
39
|
+
const ctx = {
|
|
40
|
+
changedFiles,
|
|
41
|
+
routeFamilies: [],
|
|
42
|
+
manifest: null,
|
|
43
|
+
apiSurface: { pageObjects: [], generatedAt: '' },
|
|
44
|
+
specIndex: { specs: [], indexedAt: '' },
|
|
45
|
+
context: { documents: [], warnings: [] },
|
|
46
|
+
familyGroups: [],
|
|
47
|
+
preprocessResult: null,
|
|
48
|
+
appPath: config.appPath,
|
|
49
|
+
testsRoot: config.testsRoot,
|
|
50
|
+
gitSince: config.gitSince,
|
|
51
|
+
providerOverride: config.providerOverride,
|
|
52
|
+
impactedFlows: [],
|
|
53
|
+
strategyEntries: [],
|
|
54
|
+
testDesigns: [],
|
|
55
|
+
crossImpacts: [],
|
|
56
|
+
regressionRisks: [],
|
|
57
|
+
findings: [],
|
|
58
|
+
generatedSpecs: [],
|
|
59
|
+
usage: (0, context_js_1.createEmptyUsageStats)(),
|
|
60
|
+
messages: [],
|
|
61
|
+
warnings,
|
|
62
|
+
};
|
|
63
|
+
// Execute each phase
|
|
64
|
+
for (const phase of workflow.phases) {
|
|
65
|
+
const timer = logger_js_1.logger.timer(`crew:${phase.name}`);
|
|
66
|
+
if (phase.handler === 'built-in') {
|
|
67
|
+
await this.runBuiltInPhase(phase.name, ctx, config);
|
|
68
|
+
}
|
|
69
|
+
else if (phase.parallel && phase.parallel.length > 0) {
|
|
70
|
+
await this.runParallel(phase.parallel, phase.name, ctx);
|
|
71
|
+
}
|
|
72
|
+
else if (phase.sequential && phase.sequential.length > 0) {
|
|
73
|
+
await this.runSequential(phase.sequential, phase.name, ctx);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
warnings.push(`Phase '${phase.name}' has no handler, parallel, or sequential agents — skipped.`);
|
|
77
|
+
}
|
|
78
|
+
timings[phase.name] = timer.end();
|
|
79
|
+
// Budget check
|
|
80
|
+
if (config.budgetUSD && ctx.usage.totalCost >= config.budgetUSD) {
|
|
81
|
+
warnings.push(`Budget limit reached ($${ctx.usage.totalCost.toFixed(4)} >= $${config.budgetUSD}). Stopping workflow.`);
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return { context: ctx, warnings, timings };
|
|
86
|
+
}
|
|
87
|
+
async dispatch(role, action, ctx) {
|
|
88
|
+
const agent = this.agents.get(role);
|
|
89
|
+
if (!agent) {
|
|
90
|
+
return {
|
|
91
|
+
role,
|
|
92
|
+
status: 'failed',
|
|
93
|
+
output: null,
|
|
94
|
+
warnings: [`Agent '${role}' is not registered.`],
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
const task = { role, action, input: null };
|
|
98
|
+
try {
|
|
99
|
+
const result = await agent.execute(task, ctx);
|
|
100
|
+
if (result.usage) {
|
|
101
|
+
(0, context_js_1.mergeUsageStats)(ctx.usage, result.usage);
|
|
102
|
+
}
|
|
103
|
+
if (result.warnings && result.warnings.length > 0) {
|
|
104
|
+
ctx.warnings.push(...result.warnings);
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
110
|
+
ctx.warnings.push(`Agent '${role}' failed: ${message}`);
|
|
111
|
+
return { role, status: 'failed', output: null, warnings: [message] };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async parallel(roles, action, ctx) {
|
|
115
|
+
const promises = roles.map((role) => this.dispatch(role, action, ctx));
|
|
116
|
+
return Promise.all(promises);
|
|
117
|
+
}
|
|
118
|
+
async broadcast(msg, ctx) {
|
|
119
|
+
ctx.messages.push(msg);
|
|
120
|
+
const promises = [];
|
|
121
|
+
for (const agent of this.agents.values()) {
|
|
122
|
+
if (agent.onMessage && agent.role !== msg.from) {
|
|
123
|
+
promises.push(agent.onMessage(msg).catch((err) => {
|
|
124
|
+
ctx.warnings.push(`Broadcast to ${agent.role} failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
await Promise.all(promises);
|
|
129
|
+
}
|
|
130
|
+
async runBuiltInPhase(name, ctx, config) {
|
|
131
|
+
if (name === 'preprocess') {
|
|
132
|
+
if (ctx.changedFiles.length === 0) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const result = (0, stage0_preprocess_js_1.preprocess)(ctx.changedFiles, {
|
|
136
|
+
appPath: config.appPath,
|
|
137
|
+
testsRoot: config.testsRoot,
|
|
138
|
+
routeFamilies: config.routeFamilies,
|
|
139
|
+
apiSurface: config.apiSurface,
|
|
140
|
+
});
|
|
141
|
+
ctx.preprocessResult = result;
|
|
142
|
+
ctx.manifest = result.manifest;
|
|
143
|
+
ctx.routeFamilies = result.manifest?.families || [];
|
|
144
|
+
ctx.apiSurface = result.apiSurface;
|
|
145
|
+
ctx.specIndex = result.specIndex;
|
|
146
|
+
ctx.context = result.context;
|
|
147
|
+
ctx.familyGroups = result.familyGroups;
|
|
148
|
+
ctx.warnings.push(...result.warnings);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
async runParallel(roles, phaseName, ctx) {
|
|
152
|
+
logger_js_1.logger.info(`Crew phase '${phaseName}': running ${roles.join(', ')} in parallel`);
|
|
153
|
+
const results = await this.parallel(roles, phaseName, ctx);
|
|
154
|
+
this.checkPhaseResults(phaseName, results, ctx);
|
|
155
|
+
}
|
|
156
|
+
async runSequential(roles, phaseName, ctx) {
|
|
157
|
+
logger_js_1.logger.info(`Crew phase '${phaseName}': running ${roles.join(' → ')} sequentially`);
|
|
158
|
+
const results = [];
|
|
159
|
+
for (const role of roles) {
|
|
160
|
+
results.push(await this.dispatch(role, phaseName, ctx));
|
|
161
|
+
}
|
|
162
|
+
this.checkPhaseResults(phaseName, results, ctx);
|
|
163
|
+
}
|
|
164
|
+
checkPhaseResults(phaseName, results, ctx) {
|
|
165
|
+
const allFailed = results.length > 0 && results.every((r) => r.status === 'failed');
|
|
166
|
+
if (allFailed) {
|
|
167
|
+
ctx.warnings.push(`Phase '${phaseName}': all ${results.length} agent(s) failed. Downstream phases may produce empty results.`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
exports.CrewOrchestrator = CrewOrchestrator;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Crew Protocol — core interfaces for inter-agent communication and execution.
|
|
3
|
+
*/
|
|
4
|
+
import type { ProviderUsageStats } from '../provider_interface.js';
|
|
5
|
+
import type { AgentRole } from './types.js';
|
|
6
|
+
import type { CrewContext } from './context.js';
|
|
7
|
+
export interface AgentMessage {
|
|
8
|
+
id: string;
|
|
9
|
+
from: AgentRole;
|
|
10
|
+
to: AgentRole | 'broadcast';
|
|
11
|
+
type: 'task' | 'result' | 'escalation' | 'finding';
|
|
12
|
+
payload: unknown;
|
|
13
|
+
correlationId: string;
|
|
14
|
+
timestamp: number;
|
|
15
|
+
}
|
|
16
|
+
export interface AgentTask {
|
|
17
|
+
role: AgentRole;
|
|
18
|
+
action: string;
|
|
19
|
+
input: unknown;
|
|
20
|
+
}
|
|
21
|
+
export interface AgentResult {
|
|
22
|
+
role: AgentRole;
|
|
23
|
+
status: 'success' | 'partial' | 'failed';
|
|
24
|
+
output: unknown;
|
|
25
|
+
usage?: ProviderUsageStats;
|
|
26
|
+
warnings: string[];
|
|
27
|
+
}
|
|
28
|
+
export interface Agent {
|
|
29
|
+
role: AgentRole;
|
|
30
|
+
execute(task: AgentTask, ctx: CrewContext): Promise<AgentResult>;
|
|
31
|
+
onMessage?(msg: AgentMessage): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/crew/protocol.ts"],"names":[],"mappings":"AAGA;;GAEG;AAEH,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,cAAc,CAAC;AAE9C,MAAM,WAAW,YAAY;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,SAAS,CAAC;IAChB,EAAE,EAAE,SAAS,GAAG,WAAW,CAAC;IAC5B,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,YAAY,GAAG,SAAS,CAAC;IACnD,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACtB,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;IACzC,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,KAAK;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACjE,SAAS,CAAC,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/crew/provider.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,0BAA0B,CAAC;AAE1D,wBAAsB,eAAe,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAKrF"}
|
|
@@ -0,0 +1,16 @@
|
|
|
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.getCrewProvider = getCrewProvider;
|
|
6
|
+
/**
|
|
7
|
+
* Shared provider creation for crew agents — ensures consistent provider
|
|
8
|
+
* instantiation and prevents usage stats fragmentation.
|
|
9
|
+
*/
|
|
10
|
+
const provider_factory_js_1 = require("../provider_factory.js");
|
|
11
|
+
async function getCrewProvider(providerOverride) {
|
|
12
|
+
if (providerOverride) {
|
|
13
|
+
return provider_factory_js_1.LLMProviderFactory.createFromString(providerOverride);
|
|
14
|
+
}
|
|
15
|
+
return provider_factory_js_1.LLMProviderFactory.createFromEnv();
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../src/crew/sanitize.ts"],"names":[],"mappings":"AAqBA,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMvD;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAExD"}
|
|
@@ -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.sanitizeForPrompt = sanitizeForPrompt;
|
|
6
|
+
exports.sanitizeArray = sanitizeArray;
|
|
7
|
+
/**
|
|
8
|
+
* Sanitize strings before interpolating into LLM prompts.
|
|
9
|
+
* Strips common prompt injection patterns while preserving useful content.
|
|
10
|
+
*/
|
|
11
|
+
const INJECTION_PATTERNS = [
|
|
12
|
+
/ignore\s+(all\s+)?previous\s+instructions/gi,
|
|
13
|
+
/disregard\s+(all\s+)?(above|prior|previous)/gi,
|
|
14
|
+
/system\s*:\s*/gi,
|
|
15
|
+
/\[INST\]/gi,
|
|
16
|
+
/<<SYS>>/gi,
|
|
17
|
+
/<\|im_start\|>/gi,
|
|
18
|
+
/\bHuman\s*:\s*/gi,
|
|
19
|
+
/\bAssistant\s*:\s*/gi,
|
|
20
|
+
];
|
|
21
|
+
const MAX_FIELD_LENGTH = 2000;
|
|
22
|
+
function sanitizeForPrompt(value) {
|
|
23
|
+
let sanitized = value.slice(0, MAX_FIELD_LENGTH);
|
|
24
|
+
for (const pattern of INJECTION_PATTERNS) {
|
|
25
|
+
sanitized = sanitized.replace(pattern, '[filtered]');
|
|
26
|
+
}
|
|
27
|
+
return sanitized;
|
|
28
|
+
}
|
|
29
|
+
function sanitizeArray(values) {
|
|
30
|
+
return values.map((v) => sanitizeForPrompt(v));
|
|
31
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Crew data types — structured test design, cross-impact analysis, and findings.
|
|
3
|
+
*/
|
|
4
|
+
export type TestCaseType = 'happy-path' | 'edge-case' | 'boundary' | 'negative' | 'state-transition' | 'race-condition' | 'permission' | 'accessibility' | 'performance';
|
|
5
|
+
export interface TestCase {
|
|
6
|
+
name: string;
|
|
7
|
+
type: TestCaseType;
|
|
8
|
+
preconditions: string[];
|
|
9
|
+
steps: string[];
|
|
10
|
+
expectedOutcome: string;
|
|
11
|
+
priority: 'P0' | 'P1' | 'P2';
|
|
12
|
+
rationale: string;
|
|
13
|
+
}
|
|
14
|
+
export interface TestDesign {
|
|
15
|
+
flowId: string;
|
|
16
|
+
flowName: string;
|
|
17
|
+
testCases: TestCase[];
|
|
18
|
+
}
|
|
19
|
+
export interface CrossImpact {
|
|
20
|
+
sourceFamily: string;
|
|
21
|
+
affectedFamily: string;
|
|
22
|
+
sharedDependency: string;
|
|
23
|
+
riskLevel: 'high' | 'medium' | 'low';
|
|
24
|
+
evidence: string;
|
|
25
|
+
}
|
|
26
|
+
export interface Finding {
|
|
27
|
+
id: string;
|
|
28
|
+
type: 'bug' | 'gap' | 'risk' | 'flaky';
|
|
29
|
+
severity: 'critical' | 'high' | 'medium' | 'low';
|
|
30
|
+
source: AgentRole;
|
|
31
|
+
summary: string;
|
|
32
|
+
details: string;
|
|
33
|
+
relatedFlows: string[];
|
|
34
|
+
}
|
|
35
|
+
export interface RegressionRisk {
|
|
36
|
+
familyId: string;
|
|
37
|
+
filePattern: string;
|
|
38
|
+
riskScore: number;
|
|
39
|
+
reason: string;
|
|
40
|
+
historicalFailures: number;
|
|
41
|
+
}
|
|
42
|
+
export interface StrategyEntry {
|
|
43
|
+
flowId: string;
|
|
44
|
+
flowName: string;
|
|
45
|
+
priority: 'P0' | 'P1' | 'P2';
|
|
46
|
+
approach: 'full-test' | 'smoke-test' | 'skip' | 'manual-review';
|
|
47
|
+
rationale: string;
|
|
48
|
+
testCategories: TestCaseType[];
|
|
49
|
+
crossImpactRisk: 'high' | 'medium' | 'low' | 'none';
|
|
50
|
+
}
|
|
51
|
+
export type AgentRole = 'strategist' | 'test-designer' | 'cross-impact' | 'regression-advisor' | 'impact-analyst' | 'coverage-evaluator' | 'generator' | 'executor' | 'healer' | 'explorer';
|
|
52
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/crew/types.ts"],"names":[],"mappings":"AAGA;;GAEG;AAEH,MAAM,MAAM,YAAY,GAClB,YAAY,GACZ,WAAW,GACX,UAAU,GACV,UAAU,GACV,kBAAkB,GAClB,gBAAgB,GAChB,YAAY,GACZ,eAAe,GACf,aAAa,CAAC;AAEpB,MAAM,WAAW,QAAQ;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,YAAY,CAAC;IACnB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,QAAQ,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,WAAW;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACrC,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,OAAO;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;IACvC,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACjD,MAAM,EAAE,SAAS,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,aAAa;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC7B,QAAQ,EAAE,WAAW,GAAG,YAAY,GAAG,MAAM,GAAG,eAAe,CAAC;IAChE,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,YAAY,EAAE,CAAC;IAC/B,eAAe,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;CACvD;AAED,MAAM,MAAM,SAAS,GACf,YAAY,GACZ,eAAe,GACf,cAAc,GACd,oBAAoB,GACpB,gBAAgB,GAChB,oBAAoB,GACpB,WAAW,GACX,UAAU,GACV,QAAQ,GACR,UAAU,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Predefined workflow definitions — playbooks that compose agents into phases.
|
|
3
|
+
*
|
|
4
|
+
* Data flow through full-qa workflow:
|
|
5
|
+
*
|
|
6
|
+
* preprocess (built-in)
|
|
7
|
+
* → populates: familyGroups, routeFamilies, manifest, apiSurface, specIndex, context
|
|
8
|
+
*
|
|
9
|
+
* understand (parallel):
|
|
10
|
+
* impact-analyst → writes: impactedFlows
|
|
11
|
+
* cross-impact → writes: crossImpacts
|
|
12
|
+
* regression-advisor → writes: regressionRisks
|
|
13
|
+
*
|
|
14
|
+
* strategize (sequential):
|
|
15
|
+
* strategist → reads: impactedFlows, crossImpacts, regressionRisks
|
|
16
|
+
* → writes: strategyEntries
|
|
17
|
+
* test-designer → reads: strategyEntries, impactedFlows, crossImpacts, apiSurface, specIndex
|
|
18
|
+
* → writes: testDesigns
|
|
19
|
+
*
|
|
20
|
+
* execute (parallel):
|
|
21
|
+
* generator → reads: impactedFlows, testDesigns, apiSurface
|
|
22
|
+
* → writes: generatedSpecs
|
|
23
|
+
*
|
|
24
|
+
* validate (sequential):
|
|
25
|
+
* executor → reads: generatedSpecs, impactedFlows
|
|
26
|
+
* healer → reads: generatedSpecs, impactedFlows
|
|
27
|
+
*/
|
|
28
|
+
import type { AgentRole } from './types.js';
|
|
29
|
+
export type WorkflowPhase = {
|
|
30
|
+
name: string;
|
|
31
|
+
handler: 'built-in';
|
|
32
|
+
parallel?: never;
|
|
33
|
+
sequential?: never;
|
|
34
|
+
} | {
|
|
35
|
+
name: string;
|
|
36
|
+
handler?: never;
|
|
37
|
+
parallel: AgentRole[];
|
|
38
|
+
sequential?: never;
|
|
39
|
+
} | {
|
|
40
|
+
name: string;
|
|
41
|
+
handler?: never;
|
|
42
|
+
parallel?: never;
|
|
43
|
+
sequential: AgentRole[];
|
|
44
|
+
};
|
|
45
|
+
export interface WorkflowDef {
|
|
46
|
+
name: string;
|
|
47
|
+
description: string;
|
|
48
|
+
phases: WorkflowPhase[];
|
|
49
|
+
}
|
|
50
|
+
export type WorkflowName = 'full-qa' | 'quick-check' | 'design-only';
|
|
51
|
+
export declare const WORKFLOWS: Record<WorkflowName, WorkflowDef>;
|
|
52
|
+
//# sourceMappingURL=workflows.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflows.d.ts","sourceRoot":"","sources":["../../src/crew/workflows.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;AAE1C,MAAM,MAAM,aAAa,GACnB;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,EAAE,KAAK,CAAC;IAAC,UAAU,CAAC,EAAE,KAAK,CAAA;CAAC,GACzE;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,SAAS,EAAE,CAAC;IAAC,UAAU,CAAC,EAAE,KAAK,CAAA;CAAC,GAC1E;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,EAAE,KAAK,CAAC;IAAC,UAAU,EAAE,SAAS,EAAE,CAAA;CAAC,CAAC;AAEjF,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,aAAa,GAAG,aAAa,CAAC;AAErE,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,YAAY,EAAE,WAAW,CA8BvD,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
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.WORKFLOWS = void 0;
|
|
6
|
+
exports.WORKFLOWS = {
|
|
7
|
+
'full-qa': {
|
|
8
|
+
name: 'full-qa',
|
|
9
|
+
description: 'Full multi-agent QA analysis: understand → strategize → execute → validate',
|
|
10
|
+
phases: [
|
|
11
|
+
{ name: 'preprocess', handler: 'built-in' },
|
|
12
|
+
{ name: 'understand', parallel: ['impact-analyst', 'cross-impact', 'regression-advisor'] },
|
|
13
|
+
{ name: 'strategize', sequential: ['strategist', 'test-designer'] },
|
|
14
|
+
{ name: 'execute', parallel: ['generator'] },
|
|
15
|
+
{ name: 'validate', sequential: ['executor', 'healer'] },
|
|
16
|
+
],
|
|
17
|
+
},
|
|
18
|
+
'quick-check': {
|
|
19
|
+
name: 'quick-check',
|
|
20
|
+
description: 'Quick impact analysis with strategy recommendations',
|
|
21
|
+
phases: [
|
|
22
|
+
{ name: 'preprocess', handler: 'built-in' },
|
|
23
|
+
{ name: 'understand', parallel: ['impact-analyst'] },
|
|
24
|
+
{ name: 'strategize', sequential: ['strategist'] },
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
'design-only': {
|
|
28
|
+
name: 'design-only',
|
|
29
|
+
description: 'Impact analysis through test design — no generation or execution',
|
|
30
|
+
phases: [
|
|
31
|
+
{ name: 'preprocess', handler: 'built-in' },
|
|
32
|
+
{ name: 'understand', parallel: ['impact-analyst', 'cross-impact'] },
|
|
33
|
+
{ name: 'strategize', sequential: ['strategist', 'test-designer'] },
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
};
|
package/dist/esm/agent/git.js
CHANGED
|
@@ -175,6 +175,18 @@ function isCommentOnlyDiff(file, repoRoot, baseRef) {
|
|
|
175
175
|
return content === '' || commentEntry.pattern.test(content);
|
|
176
176
|
});
|
|
177
177
|
}
|
|
178
|
+
/**
|
|
179
|
+
* Check if a file path is a test file (spec, test, or in test directories).
|
|
180
|
+
* Shared across pipeline and crew orchestrators.
|
|
181
|
+
*/
|
|
182
|
+
export function isTestFile(file) {
|
|
183
|
+
const normalized = file.replace(/\\/g, '/');
|
|
184
|
+
return /\.(spec|test)\.(ts|tsx|js|jsx)$/.test(normalized) ||
|
|
185
|
+
/_test\.go$/.test(normalized) ||
|
|
186
|
+
normalized.includes('__tests__/') ||
|
|
187
|
+
normalized.includes('/tests/') ||
|
|
188
|
+
normalized.includes('/test/');
|
|
189
|
+
}
|
|
178
190
|
export function getChangedFiles(appRoot, since, options) {
|
|
179
191
|
try {
|
|
180
192
|
const files = new Set();
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
/**
|
|
4
|
+
* Coverage Evaluator Agent — wraps pipeline stage2 (coverage evaluation) in the Agent interface.
|
|
5
|
+
*/
|
|
6
|
+
import { runCoverageStage } from '../pipeline/stage2_coverage.js';
|
|
7
|
+
export class CoverageEvaluatorAgent {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.role = 'coverage-evaluator';
|
|
10
|
+
}
|
|
11
|
+
async execute(_task, ctx) {
|
|
12
|
+
const warnings = [];
|
|
13
|
+
if (ctx.impactedFlows.length === 0) {
|
|
14
|
+
warnings.push('Coverage evaluator: no impacted flows to evaluate.');
|
|
15
|
+
return { role: this.role, status: 'partial', output: [], warnings };
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
const result = await runCoverageStage(ctx.impactedFlows, ctx.specIndex, ctx.context, ctx.testsRoot, { provider: ctx.providerOverride });
|
|
19
|
+
// Replace impacted flows with coverage-enriched versions.
|
|
20
|
+
// This is intentionally a full replace (not push) because coverage evaluation
|
|
21
|
+
// returns the same flow IDs with updated coverage fields.
|
|
22
|
+
ctx.impactedFlows = result.decisions;
|
|
23
|
+
warnings.push(...result.warnings);
|
|
24
|
+
return {
|
|
25
|
+
role: this.role,
|
|
26
|
+
status: 'success',
|
|
27
|
+
output: result.decisions,
|
|
28
|
+
warnings,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
33
|
+
warnings.push(`Coverage evaluator failed: ${message}`);
|
|
34
|
+
return { role: this.role, status: 'failed', output: null, warnings };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|