@yasserkhanorg/e2e-agents 0.5.16 → 0.7.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.
- package/dist/agent/pipeline.d.ts +1 -1
- package/dist/agent/pipeline.d.ts.map +1 -1
- package/dist/agent/plan.d.ts +2 -13
- package/dist/agent/plan.d.ts.map +1 -1
- package/dist/agent/plan.js +0 -365
- package/dist/agent/types.d.ts +42 -0
- package/dist/agent/types.d.ts.map +1 -0
- package/dist/agent/types.js +4 -0
- package/dist/api.d.ts +14 -14
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +67 -59
- package/dist/cli.js +86 -176
- package/dist/engine/ai_enrichment.d.ts +43 -0
- package/dist/engine/ai_enrichment.d.ts.map +1 -0
- package/dist/engine/ai_enrichment.js +235 -0
- package/dist/engine/diff_loader.d.ts +11 -0
- package/dist/engine/diff_loader.d.ts.map +1 -0
- package/dist/engine/diff_loader.js +74 -0
- package/dist/engine/impact_engine.d.ts +36 -0
- package/dist/engine/impact_engine.d.ts.map +1 -0
- package/dist/engine/impact_engine.js +196 -0
- package/dist/engine/plan_builder.d.ts +10 -0
- package/dist/engine/plan_builder.d.ts.map +1 -0
- package/dist/engine/plan_builder.js +374 -0
- package/dist/esm/agent/plan.js +1 -360
- package/dist/esm/agent/types.js +3 -0
- package/dist/esm/api.js +62 -54
- package/dist/esm/cli.js +87 -177
- package/dist/esm/engine/ai_enrichment.js +232 -0
- package/dist/esm/engine/diff_loader.js +70 -0
- package/dist/esm/engine/impact_engine.js +191 -0
- package/dist/esm/engine/plan_builder.js +368 -0
- package/dist/esm/index.js +6 -3
- package/dist/esm/knowledge/route_families.js +59 -1
- package/dist/index.d.ts +9 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -5
- package/dist/knowledge/route_families.d.ts +19 -0
- package/dist/knowledge/route_families.d.ts.map +1 -1
- package/dist/knowledge/route_families.js +62 -1
- package/package.json +1 -1
- package/dist/agent/ai_flow_analysis.d.ts +0 -13
- package/dist/agent/ai_flow_analysis.d.ts.map +0 -1
- package/dist/agent/ai_flow_analysis.js +0 -334
- package/dist/agent/ai_mapping.d.ts +0 -14
- package/dist/agent/ai_mapping.d.ts.map +0 -1
- package/dist/agent/ai_mapping.js +0 -560
- package/dist/agent/analysis.d.ts +0 -64
- package/dist/agent/analysis.d.ts.map +0 -1
- package/dist/agent/analysis.js +0 -292
- package/dist/agent/blast_radius.d.ts +0 -4
- package/dist/agent/blast_radius.d.ts.map +0 -1
- package/dist/agent/blast_radius.js +0 -37
- package/dist/agent/dependency_graph.d.ts +0 -14
- package/dist/agent/dependency_graph.d.ts.map +0 -1
- package/dist/agent/dependency_graph.js +0 -227
- package/dist/agent/flags.d.ts +0 -23
- package/dist/agent/flags.d.ts.map +0 -1
- package/dist/agent/flags.js +0 -171
- package/dist/agent/flow_catalog.d.ts +0 -25
- package/dist/agent/flow_catalog.d.ts.map +0 -1
- package/dist/agent/flow_catalog.js +0 -115
- package/dist/agent/flow_mapping.d.ts +0 -10
- package/dist/agent/flow_mapping.d.ts.map +0 -1
- package/dist/agent/flow_mapping.js +0 -84
- package/dist/agent/framework.d.ts +0 -13
- package/dist/agent/framework.d.ts.map +0 -1
- package/dist/agent/framework.js +0 -149
- package/dist/agent/gap_suggestions.d.ts +0 -14
- package/dist/agent/gap_suggestions.d.ts.map +0 -1
- package/dist/agent/gap_suggestions.js +0 -101
- package/dist/agent/generator.d.ts +0 -10
- package/dist/agent/generator.d.ts.map +0 -1
- package/dist/agent/generator.js +0 -115
- package/dist/agent/operational_insights.d.ts +0 -41
- package/dist/agent/operational_insights.d.ts.map +0 -1
- package/dist/agent/operational_insights.js +0 -127
- package/dist/agent/report.d.ts +0 -97
- package/dist/agent/report.d.ts.map +0 -1
- package/dist/agent/report.js +0 -159
- package/dist/agent/runner.d.ts +0 -7
- package/dist/agent/runner.d.ts.map +0 -1
- package/dist/agent/runner.js +0 -898
- package/dist/agent/selectors.d.ts +0 -10
- package/dist/agent/selectors.d.ts.map +0 -1
- package/dist/agent/selectors.js +0 -75
- package/dist/agent/subsystem_risk.d.ts +0 -23
- package/dist/agent/subsystem_risk.d.ts.map +0 -1
- package/dist/agent/subsystem_risk.js +0 -207
- package/dist/agent/tests.d.ts +0 -19
- package/dist/agent/tests.d.ts.map +0 -1
- package/dist/agent/tests.js +0 -116
- package/dist/agent/traceability.d.ts +0 -22
- package/dist/agent/traceability.d.ts.map +0 -1
- package/dist/agent/traceability.js +0 -183
- package/dist/esm/agent/ai_flow_analysis.js +0 -331
- package/dist/esm/agent/ai_mapping.js +0 -557
- package/dist/esm/agent/analysis.js +0 -287
- package/dist/esm/agent/blast_radius.js +0 -34
- package/dist/esm/agent/dependency_graph.js +0 -224
- package/dist/esm/agent/flags.js +0 -160
- package/dist/esm/agent/flow_catalog.js +0 -112
- package/dist/esm/agent/flow_mapping.js +0 -81
- package/dist/esm/agent/framework.js +0 -145
- package/dist/esm/agent/gap_suggestions.js +0 -98
- package/dist/esm/agent/generator.js +0 -112
- package/dist/esm/agent/operational_insights.js +0 -124
- package/dist/esm/agent/report.js +0 -156
- package/dist/esm/agent/runner.js +0 -894
- package/dist/esm/agent/selectors.js +0 -71
- package/dist/esm/agent/subsystem_risk.js +0 -204
- package/dist/esm/agent/tests.js +0 -111
- package/dist/esm/agent/traceability.js +0 -180
package/dist/api.js
CHANGED
|
@@ -2,28 +2,23 @@
|
|
|
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.analyzeImpact = analyzeImpact;
|
|
6
|
-
exports.findGaps = findGaps;
|
|
7
|
-
exports.recommendTests = recommendTests;
|
|
8
5
|
exports.handoffGeneratedTests = handoffGeneratedTests;
|
|
9
6
|
exports.ingestTraceability = ingestTraceability;
|
|
7
|
+
exports.analyzeImpactDeterministic = analyzeImpactDeterministic;
|
|
8
|
+
exports.recommendTestsDeterministic = recommendTestsDeterministic;
|
|
9
|
+
exports.recommendTestsAI = recommendTestsAI;
|
|
10
10
|
exports.captureTraceability = captureTraceability;
|
|
11
|
-
const fs_1 = require("fs");
|
|
12
|
-
const path_1 = require("path");
|
|
13
11
|
const config_js_1 = require("./agent/config.js");
|
|
14
|
-
const runner_js_1 = require("./agent/runner.js");
|
|
15
12
|
const plan_js_1 = require("./agent/plan.js");
|
|
16
|
-
const
|
|
13
|
+
const impact_engine_js_1 = require("./engine/impact_engine.js");
|
|
14
|
+
const plan_builder_js_1 = require("./engine/plan_builder.js");
|
|
15
|
+
const git_js_1 = require("./agent/git.js");
|
|
16
|
+
const diff_loader_js_1 = require("./engine/diff_loader.js");
|
|
17
|
+
const ai_enrichment_js_1 = require("./engine/ai_enrichment.js");
|
|
18
|
+
const anthropic_provider_js_1 = require("./anthropic_provider.js");
|
|
17
19
|
const handoff_js_1 = require("./agent/handoff.js");
|
|
18
20
|
const traceability_ingest_js_1 = require("./agent/traceability_ingest.js");
|
|
19
21
|
const traceability_capture_js_1 = require("./agent/traceability_capture.js");
|
|
20
|
-
function readReportJson(reportPath) {
|
|
21
|
-
if (!(0, fs_1.existsSync)(reportPath)) {
|
|
22
|
-
throw new Error(`Expected report not found: ${reportPath}`);
|
|
23
|
-
}
|
|
24
|
-
const raw = (0, fs_1.readFileSync)(reportPath, 'utf-8');
|
|
25
|
-
return JSON.parse(raw);
|
|
26
|
-
}
|
|
27
22
|
function resolveAgent(options, mode) {
|
|
28
23
|
const cwd = options.cwd || process.cwd();
|
|
29
24
|
const { config } = (0, config_js_1.resolveConfig)(cwd, options.configPath, {
|
|
@@ -35,51 +30,6 @@ function resolveAgent(options, mode) {
|
|
|
35
30
|
}
|
|
36
31
|
return config;
|
|
37
32
|
}
|
|
38
|
-
function reportPathFor(configPath, mode) {
|
|
39
|
-
return (0, path_1.join)(configPath, '.e2e-ai-agents', mode === 'impact' ? 'impact.json' : 'gap.json');
|
|
40
|
-
}
|
|
41
|
-
async function analyzeImpact(options = {}) {
|
|
42
|
-
const config = resolveAgent(options, 'impact');
|
|
43
|
-
await (0, runner_js_1.runImpact)(config, { apply: options.apply ?? false });
|
|
44
|
-
const reportRoot = config.testsRoot || config.path;
|
|
45
|
-
const reportPath = reportPathFor(reportRoot, 'impact');
|
|
46
|
-
const report = readReportJson(reportPath);
|
|
47
|
-
return { report, reportPath };
|
|
48
|
-
}
|
|
49
|
-
async function findGaps(options = {}) {
|
|
50
|
-
const config = resolveAgent(options, 'gap');
|
|
51
|
-
await (0, runner_js_1.runGap)(config, { apply: options.apply ?? false });
|
|
52
|
-
const reportRoot = config.testsRoot || config.path;
|
|
53
|
-
const reportPath = reportPathFor(reportRoot, 'gap');
|
|
54
|
-
const report = readReportJson(reportPath);
|
|
55
|
-
return { report, reportPath };
|
|
56
|
-
}
|
|
57
|
-
async function recommendTests(options = {}) {
|
|
58
|
-
const config = resolveAgent(options, 'impact');
|
|
59
|
-
await (0, runner_js_1.runImpact)(config, { apply: options.apply ?? false });
|
|
60
|
-
const reportRoot = config.testsRoot || config.path;
|
|
61
|
-
const impactPath = reportPathFor(reportRoot, 'impact');
|
|
62
|
-
const report = readReportJson(impactPath);
|
|
63
|
-
const basePlan = (0, plan_js_1.buildPlanFromImpactReport)(report, config.policy);
|
|
64
|
-
const withActions = (0, plan_js_1.attachDeveloperActions)(basePlan, {
|
|
65
|
-
appPath: config.path,
|
|
66
|
-
testsRoot: reportRoot,
|
|
67
|
-
sinceRef: config.git.since,
|
|
68
|
-
});
|
|
69
|
-
const plan = (0, operational_insights_js_1.applyOperationalInsights)(withActions, reportRoot);
|
|
70
|
-
const planPath = (0, plan_js_1.writePlanReport)(reportRoot, plan);
|
|
71
|
-
const ciSummaryMarkdown = (0, plan_js_1.renderCiSummaryMarkdown)(plan);
|
|
72
|
-
const ciSummaryPath = (0, plan_js_1.writeCiSummary)(reportRoot, ciSummaryMarkdown);
|
|
73
|
-
(0, plan_js_1.appendPlanMetrics)(reportRoot, plan);
|
|
74
|
-
return {
|
|
75
|
-
report,
|
|
76
|
-
reportPath: impactPath,
|
|
77
|
-
plan,
|
|
78
|
-
planPath,
|
|
79
|
-
ciSummaryMarkdown,
|
|
80
|
-
ciSummaryPath,
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
33
|
function handoffGeneratedTests(options) {
|
|
84
34
|
return (0, handoff_js_1.finalizeGeneratedTests)(options);
|
|
85
35
|
}
|
|
@@ -93,6 +43,64 @@ function ingestTraceability(options) {
|
|
|
93
43
|
const reportRoot = config.testsRoot || config.path;
|
|
94
44
|
return (0, traceability_ingest_js_1.ingestTraceabilityInput)(reportRoot, config.impact.traceability, options.payload, options.options);
|
|
95
45
|
}
|
|
46
|
+
function analyzeImpactDeterministic(options = {}) {
|
|
47
|
+
const config = resolveAgent(options, 'impact');
|
|
48
|
+
const reportRoot = config.testsRoot || config.path;
|
|
49
|
+
const gitResult = (0, git_js_1.getChangedFiles)(config.path, config.git.since, { includeUncommitted: config.git.includeUncommitted });
|
|
50
|
+
return (0, impact_engine_js_1.analyzeImpact)(gitResult.files, {
|
|
51
|
+
testsRoot: reportRoot,
|
|
52
|
+
routeFamilies: config.routeFamilies,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function recommendTestsDeterministic(options = {}) {
|
|
56
|
+
const config = resolveAgent(options, 'impact');
|
|
57
|
+
const reportRoot = config.testsRoot || config.path;
|
|
58
|
+
const gitResult = (0, git_js_1.getChangedFiles)(config.path, config.git.since, { includeUncommitted: config.git.includeUncommitted });
|
|
59
|
+
const impact = (0, impact_engine_js_1.analyzeImpact)(gitResult.files, {
|
|
60
|
+
testsRoot: reportRoot,
|
|
61
|
+
routeFamilies: config.routeFamilies,
|
|
62
|
+
});
|
|
63
|
+
const plan = (0, plan_builder_js_1.buildPlanFromImpact)(impact, config.policy);
|
|
64
|
+
const planPath = (0, plan_builder_js_1.writePlanReport)(reportRoot, plan);
|
|
65
|
+
const ciSummaryMarkdown = (0, plan_builder_js_1.renderCiSummaryMarkdown)(plan);
|
|
66
|
+
const ciSummaryPath = (0, plan_builder_js_1.writeCiSummary)(reportRoot, ciSummaryMarkdown);
|
|
67
|
+
(0, plan_js_1.appendPlanMetrics)(reportRoot, plan);
|
|
68
|
+
return { impact, plan, planPath, ciSummaryMarkdown, ciSummaryPath };
|
|
69
|
+
}
|
|
70
|
+
async function recommendTestsAI(options = {}) {
|
|
71
|
+
const config = resolveAgent(options, 'impact');
|
|
72
|
+
const reportRoot = config.testsRoot || config.path;
|
|
73
|
+
const gitResult = (0, git_js_1.getChangedFiles)(config.path, config.git.since, { includeUncommitted: config.git.includeUncommitted });
|
|
74
|
+
const impact = (0, impact_engine_js_1.analyzeImpact)(gitResult.files, {
|
|
75
|
+
testsRoot: reportRoot,
|
|
76
|
+
routeFamilies: config.routeFamilies,
|
|
77
|
+
});
|
|
78
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
79
|
+
let aiEnrichment;
|
|
80
|
+
if (apiKey) {
|
|
81
|
+
const diffs = (0, diff_loader_js_1.loadDiffs)(config.path, config.git.since, gitResult.files);
|
|
82
|
+
const provider = new anthropic_provider_js_1.AnthropicProvider({ apiKey });
|
|
83
|
+
// Collect all known spec paths from impacted features
|
|
84
|
+
const specSet = new Set();
|
|
85
|
+
for (const feature of impact.impactedFeatures) {
|
|
86
|
+
for (const s of feature.playwrightSpecs) {
|
|
87
|
+
specSet.add(s);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
aiEnrichment = await (0, ai_enrichment_js_1.enrichImpactWithAI)({
|
|
91
|
+
deterministicImpact: impact,
|
|
92
|
+
diffs,
|
|
93
|
+
provider,
|
|
94
|
+
specList: [...specSet],
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
const plan = (0, plan_builder_js_1.buildPlanFromImpact)(impact, config.policy, aiEnrichment);
|
|
98
|
+
const planPath = (0, plan_builder_js_1.writePlanReport)(reportRoot, plan);
|
|
99
|
+
const ciSummaryMarkdown = (0, plan_builder_js_1.renderCiSummaryMarkdown)(plan);
|
|
100
|
+
const ciSummaryPath = (0, plan_builder_js_1.writeCiSummary)(reportRoot, ciSummaryMarkdown);
|
|
101
|
+
(0, plan_js_1.appendPlanMetrics)(reportRoot, plan);
|
|
102
|
+
return { impact, plan, planPath, ciSummaryMarkdown, ciSummaryPath, aiEnrichment };
|
|
103
|
+
}
|
|
96
104
|
function captureTraceability(options) {
|
|
97
105
|
const cwd = options.cwd || process.cwd();
|
|
98
106
|
const { config } = (0, config_js_1.resolveConfig)(cwd, options.configPath, {
|
package/dist/cli.js
CHANGED
|
@@ -8,9 +8,10 @@ const path_1 = require("path");
|
|
|
8
8
|
const config_js_1 = require("./agent/config.js");
|
|
9
9
|
const anthropic_provider_js_1 = require("./anthropic_provider.js");
|
|
10
10
|
const provider_interface_js_1 = require("./provider_interface.js");
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
11
|
+
const impact_engine_js_1 = require("./engine/impact_engine.js");
|
|
12
|
+
const plan_builder_js_1 = require("./engine/plan_builder.js");
|
|
13
|
+
const git_js_1 = require("./agent/git.js");
|
|
14
|
+
const api_js_1 = require("./api.js");
|
|
14
15
|
const feedback_js_1 = require("./agent/feedback.js");
|
|
15
16
|
const handoff_js_1 = require("./agent/handoff.js");
|
|
16
17
|
const traceability_ingest_js_1 = require("./agent/traceability_ingest.js");
|
|
@@ -61,13 +62,9 @@ function printUsage() {
|
|
|
61
62
|
console.log([
|
|
62
63
|
'Usage:',
|
|
63
64
|
' e2e-ai-agents impact --path <app-root> [options]',
|
|
64
|
-
' e2e-ai-agents gap --path <app-root> [options]',
|
|
65
65
|
' e2e-ai-agents plan --path <app-root> [options]',
|
|
66
|
-
' e2e-ai-agents generate --path <app-root> [options]',
|
|
67
|
-
' e2e-ai-agents heal --path <app-root> --traceability-report <json> [options]',
|
|
68
66
|
' e2e-ai-agents suggest --path <app-root> [options]',
|
|
69
|
-
' e2e-ai-agents
|
|
70
|
-
' e2e-ai-agents auto-heal-pr --path <app-root> [options]',
|
|
67
|
+
' e2e-ai-agents heal --path <app-root> --traceability-report <json> [options]',
|
|
71
68
|
' e2e-ai-agents finalize-generated-tests --path <app-root> [options]',
|
|
72
69
|
' e2e-ai-agents feedback --path <app-root> --feedback-input <json>',
|
|
73
70
|
' e2e-ai-agents traceability-capture --path <app-root> --traceability-report <json>',
|
|
@@ -146,13 +143,9 @@ function parseArgs(argv) {
|
|
|
146
143
|
}
|
|
147
144
|
const command = argv[0];
|
|
148
145
|
if (command === 'impact'
|
|
149
|
-
|| command === 'gap'
|
|
150
146
|
|| command === 'plan'
|
|
151
|
-
|| command === 'generate'
|
|
152
147
|
|| command === 'heal'
|
|
153
148
|
|| command === 'suggest'
|
|
154
|
-
|| command === 'approve-and-generate'
|
|
155
|
-
|| command === 'auto-heal-pr'
|
|
156
149
|
|| command === 'finalize-generated-tests'
|
|
157
150
|
|| command === 'feedback'
|
|
158
151
|
|| command === 'traceability-capture'
|
|
@@ -502,6 +495,10 @@ function parseArgs(argv) {
|
|
|
502
495
|
i += 1;
|
|
503
496
|
continue;
|
|
504
497
|
}
|
|
498
|
+
if (arg === '--no-ai') {
|
|
499
|
+
parsed.noAi = true;
|
|
500
|
+
continue;
|
|
501
|
+
}
|
|
505
502
|
}
|
|
506
503
|
return parsed;
|
|
507
504
|
}
|
|
@@ -761,117 +758,6 @@ async function main() {
|
|
|
761
758
|
}
|
|
762
759
|
return;
|
|
763
760
|
}
|
|
764
|
-
if (args.command === 'auto-heal-pr') {
|
|
765
|
-
if (!args.path && !autoConfig) {
|
|
766
|
-
// eslint-disable-next-line no-console
|
|
767
|
-
console.error('Error: --path is required for auto-heal-pr command');
|
|
768
|
-
process.exit(1);
|
|
769
|
-
}
|
|
770
|
-
const { config } = (0, config_js_1.resolveConfig)(process.cwd(), autoConfig, {
|
|
771
|
-
path: args.path,
|
|
772
|
-
profile: args.profile,
|
|
773
|
-
testsRoot: args.testsRoot,
|
|
774
|
-
mode: 'gap',
|
|
775
|
-
framework: args.framework,
|
|
776
|
-
timeLimitMinutes: args.timeLimitMinutes,
|
|
777
|
-
budget: {
|
|
778
|
-
maxUSD: args.budgetUSD,
|
|
779
|
-
maxTokens: args.budgetTokens,
|
|
780
|
-
},
|
|
781
|
-
testPatterns: args.testPatterns,
|
|
782
|
-
flowPatterns: args.flowPatterns,
|
|
783
|
-
flowExclude: args.flowExclude,
|
|
784
|
-
flowCatalogPath: args.flowCatalogPath,
|
|
785
|
-
specPDF: args.specPDF,
|
|
786
|
-
gitSince: args.gitSince,
|
|
787
|
-
pipeline: {
|
|
788
|
-
enabled: true,
|
|
789
|
-
scenarios: args.pipelineScenarios,
|
|
790
|
-
outputDir: args.pipelineOutput,
|
|
791
|
-
baseUrl: args.pipelineBaseUrl,
|
|
792
|
-
browser: args.pipelineBrowser,
|
|
793
|
-
headless: args.pipelineHeadless,
|
|
794
|
-
project: args.pipelineProject,
|
|
795
|
-
parallel: args.pipelineParallel,
|
|
796
|
-
dryRun: args.pipelineDryRun,
|
|
797
|
-
mcp: args.pipelineMcp,
|
|
798
|
-
mcpAllowFallback: args.pipelineMcpAllowFallback,
|
|
799
|
-
mcpOnly: args.pipelineMcpOnly,
|
|
800
|
-
},
|
|
801
|
-
llmProvider: args.llmProvider,
|
|
802
|
-
});
|
|
803
|
-
if (args.allowFallback) {
|
|
804
|
-
config.impact.allowFallback = true;
|
|
805
|
-
}
|
|
806
|
-
await (0, runner_js_1.runGap)(config, { apply: true });
|
|
807
|
-
const reportRoot = config.testsRoot || config.path;
|
|
808
|
-
if (args.traceabilityReportPath) {
|
|
809
|
-
const unstableSpecs = (0, playwright_report_js_1.extractPlaywrightUnstableSpecs)(args.traceabilityReportPath, [reportRoot, config.path]);
|
|
810
|
-
if (unstableSpecs.length > 0) {
|
|
811
|
-
const targetedSummary = (0, pipeline_js_1.runTargetedSpecHeal)(reportRoot, unstableSpecs.map((spec) => ({
|
|
812
|
-
specPath: spec.specPath,
|
|
813
|
-
status: spec.status,
|
|
814
|
-
reason: `Playwright report: failingTests=${spec.failingTests}, flakyTests=${spec.flakyTests}`,
|
|
815
|
-
})), {
|
|
816
|
-
...config.pipeline,
|
|
817
|
-
enabled: true,
|
|
818
|
-
heal: true,
|
|
819
|
-
});
|
|
820
|
-
const healedCount = targetedSummary.results.filter((result) => result.healStatus === 'success').length;
|
|
821
|
-
// eslint-disable-next-line no-console
|
|
822
|
-
console.log(`Auto-heal targeted unstable specs: ${unstableSpecs.length} (healed=${healedCount})`);
|
|
823
|
-
if (targetedSummary.warnings.length > 0) {
|
|
824
|
-
// eslint-disable-next-line no-console
|
|
825
|
-
console.log(`Auto-heal warnings: ${targetedSummary.warnings.join(' | ')}`);
|
|
826
|
-
}
|
|
827
|
-
const gapPath = (0, path_1.join)(reportRoot, '.e2e-ai-agents', 'gap.json');
|
|
828
|
-
if ((0, fs_1.existsSync)(gapPath)) {
|
|
829
|
-
const gap = JSON.parse((0, fs_1.readFileSync)(gapPath, 'utf-8'));
|
|
830
|
-
const existingResults = Array.isArray(gap.pipeline?.results) ? gap.pipeline?.results : [];
|
|
831
|
-
const existingWarnings = Array.isArray(gap.pipeline?.warnings) ? gap.pipeline?.warnings : [];
|
|
832
|
-
gap.pipeline = {
|
|
833
|
-
runner: gap.pipeline?.runner || targetedSummary.runner,
|
|
834
|
-
results: [...existingResults, ...targetedSummary.results],
|
|
835
|
-
warnings: Array.from(new Set([...(existingWarnings || []), ...targetedSummary.warnings])),
|
|
836
|
-
};
|
|
837
|
-
(0, fs_1.writeFileSync)(gapPath, `${JSON.stringify(gap, null, 2)}\n`, 'utf-8');
|
|
838
|
-
}
|
|
839
|
-
}
|
|
840
|
-
else {
|
|
841
|
-
// eslint-disable-next-line no-console
|
|
842
|
-
console.log('Auto-heal targeted unstable specs: 0');
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
const branchSuffix = new Date().toISOString().replace(/[:.]/g, '-');
|
|
846
|
-
const result = (0, handoff_js_1.finalizeGeneratedTests)({
|
|
847
|
-
appPath: config.path,
|
|
848
|
-
testsRoot: reportRoot,
|
|
849
|
-
branch: args.branch || `auto-heal-${branchSuffix}`,
|
|
850
|
-
commitMessage: args.commitMessage || 'test(e2e): auto-heal generated specs',
|
|
851
|
-
createPr: true,
|
|
852
|
-
prTitle: args.prTitle || 'test(e2e): auto-heal generated specs',
|
|
853
|
-
prBody: args.prBody || 'Automated e2e-heal run generated by @yasserkhanorg/e2e-agents.',
|
|
854
|
-
baseBranch: args.prBase || 'master',
|
|
855
|
-
dryRun: args.dryRun,
|
|
856
|
-
});
|
|
857
|
-
// eslint-disable-next-line no-console
|
|
858
|
-
console.log(`Auto-heal repo root: ${result.repoRoot}`);
|
|
859
|
-
// eslint-disable-next-line no-console
|
|
860
|
-
console.log(`Auto-heal branch: ${result.branch}`);
|
|
861
|
-
// eslint-disable-next-line no-console
|
|
862
|
-
console.log(`Auto-heal staged paths: ${result.stagedPaths.join(', ') || 'none'}`);
|
|
863
|
-
// eslint-disable-next-line no-console
|
|
864
|
-
console.log(`Auto-heal commit: ${result.committed ? 'created' : 'skipped'}`);
|
|
865
|
-
if (result.commitSha) {
|
|
866
|
-
// eslint-disable-next-line no-console
|
|
867
|
-
console.log(`Auto-heal commit sha: ${result.commitSha}`);
|
|
868
|
-
}
|
|
869
|
-
if (result.prUrl) {
|
|
870
|
-
// eslint-disable-next-line no-console
|
|
871
|
-
console.log(`Auto-heal PR: ${result.prUrl}`);
|
|
872
|
-
}
|
|
873
|
-
return;
|
|
874
|
-
}
|
|
875
761
|
if (args.command === 'heal') {
|
|
876
762
|
if (!args.path && !autoConfig) {
|
|
877
763
|
// eslint-disable-next-line no-console
|
|
@@ -936,13 +822,11 @@ async function main() {
|
|
|
936
822
|
printUsage();
|
|
937
823
|
process.exit(1);
|
|
938
824
|
}
|
|
939
|
-
const
|
|
940
|
-
const forceAIPipelineFromApproval = args.command === 'approve-and-generate' || args.command === 'generate';
|
|
941
|
-
const { config, configPath } = (0, config_js_1.resolveConfig)(process.cwd(), autoConfig, {
|
|
825
|
+
const { config } = (0, config_js_1.resolveConfig)(process.cwd(), autoConfig, {
|
|
942
826
|
path: args.path,
|
|
943
827
|
profile: args.profile,
|
|
944
828
|
testsRoot: args.testsRoot,
|
|
945
|
-
mode:
|
|
829
|
+
mode: 'impact',
|
|
946
830
|
framework: args.framework,
|
|
947
831
|
timeLimitMinutes: args.timeLimitMinutes,
|
|
948
832
|
budget: {
|
|
@@ -956,7 +840,7 @@ async function main() {
|
|
|
956
840
|
specPDF: args.specPDF,
|
|
957
841
|
gitSince: args.gitSince,
|
|
958
842
|
llmProvider: args.llmProvider,
|
|
959
|
-
pipeline:
|
|
843
|
+
pipeline: args.pipeline
|
|
960
844
|
? {
|
|
961
845
|
enabled: true,
|
|
962
846
|
scenarios: args.pipelineScenarios,
|
|
@@ -967,9 +851,9 @@ async function main() {
|
|
|
967
851
|
project: args.pipelineProject,
|
|
968
852
|
parallel: args.pipelineParallel,
|
|
969
853
|
dryRun: args.pipelineDryRun,
|
|
970
|
-
mcp: args.pipelineMcp
|
|
854
|
+
mcp: args.pipelineMcp,
|
|
971
855
|
mcpAllowFallback: args.pipelineMcpAllowFallback,
|
|
972
|
-
mcpOnly: args.pipelineMcpOnly
|
|
856
|
+
mcpOnly: args.pipelineMcpOnly,
|
|
973
857
|
mcpCommandTimeoutMs: args.pipelineMcpTimeoutMs,
|
|
974
858
|
mcpRetries: args.pipelineMcpRetries,
|
|
975
859
|
}
|
|
@@ -990,46 +874,81 @@ async function main() {
|
|
|
990
874
|
}
|
|
991
875
|
: undefined,
|
|
992
876
|
});
|
|
993
|
-
if (args.allowFallback) {
|
|
994
|
-
config.impact.allowFallback = true;
|
|
995
|
-
}
|
|
996
877
|
if (args.command === 'impact') {
|
|
997
|
-
|
|
878
|
+
const reportRoot = config.testsRoot || config.path;
|
|
879
|
+
const gitResult = (0, git_js_1.getChangedFiles)(config.path, config.git.since, { includeUncommitted: config.git.includeUncommitted });
|
|
880
|
+
const impactResult = (0, impact_engine_js_1.analyzeImpact)(gitResult.files, {
|
|
881
|
+
testsRoot: reportRoot,
|
|
882
|
+
routeFamilies: config.routeFamilies,
|
|
883
|
+
});
|
|
884
|
+
// eslint-disable-next-line no-console
|
|
885
|
+
console.log(`Impact: ${impactResult.changedFiles.length} changed files → ${impactResult.impactedFeatures.length} features impacted`);
|
|
886
|
+
// eslint-disable-next-line no-console
|
|
887
|
+
console.log(`Unbound files: ${impactResult.unboundFiles.length}`);
|
|
888
|
+
for (const f of impactResult.impactedFeatures) {
|
|
889
|
+
const label = f.featureId || f.familyId;
|
|
890
|
+
// eslint-disable-next-line no-console
|
|
891
|
+
console.log(` [${f.priority}] ${label}: ${f.coverageStatus} (PW=${f.playwrightSpecs.length}, Cy=${f.cypressSpecs.length})`);
|
|
892
|
+
}
|
|
893
|
+
if (impactResult.warnings.length > 0) {
|
|
894
|
+
for (const w of impactResult.warnings) {
|
|
895
|
+
// eslint-disable-next-line no-console
|
|
896
|
+
console.warn(` Warning: ${w}`);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
998
899
|
return;
|
|
999
900
|
}
|
|
1000
901
|
if (args.command === 'suggest' || args.command === 'plan') {
|
|
1001
902
|
const reportRoot = config.testsRoot || config.path;
|
|
1002
|
-
const
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
903
|
+
const apiOptions = {
|
|
904
|
+
cwd: process.cwd(),
|
|
905
|
+
configPath: autoConfig,
|
|
906
|
+
path: args.path,
|
|
907
|
+
profile: args.profile,
|
|
908
|
+
testsRoot: args.testsRoot,
|
|
909
|
+
gitSince: args.gitSince,
|
|
910
|
+
llmProvider: args.llmProvider,
|
|
911
|
+
policy: args.policyMinConfidence !== undefined ||
|
|
912
|
+
args.policySafeMergeConfidence !== undefined ||
|
|
913
|
+
args.policyWarningsThreshold !== undefined ||
|
|
914
|
+
(args.policyRiskyPatterns && args.policyRiskyPatterns.length > 0) ||
|
|
915
|
+
args.policyEnforcementMode !== undefined ||
|
|
916
|
+
(args.policyBlockActions && args.policyBlockActions.length > 0)
|
|
917
|
+
? {
|
|
918
|
+
minConfidenceForTargeted: args.policyMinConfidence,
|
|
919
|
+
safeMergeMinConfidence: args.policySafeMergeConfidence,
|
|
920
|
+
forceFullOnWarningsAtOrAbove: args.policyWarningsThreshold,
|
|
921
|
+
riskyFilePatterns: args.policyRiskyPatterns,
|
|
922
|
+
enforcementMode: args.policyEnforcementMode,
|
|
923
|
+
blockOnActions: args.policyBlockActions,
|
|
924
|
+
}
|
|
925
|
+
: undefined,
|
|
926
|
+
};
|
|
927
|
+
let result;
|
|
928
|
+
if (args.noAi) {
|
|
929
|
+
result = (0, api_js_1.recommendTestsDeterministic)(apiOptions);
|
|
930
|
+
}
|
|
931
|
+
else {
|
|
932
|
+
result = await (0, api_js_1.recommendTestsAI)(apiOptions);
|
|
933
|
+
if (result.aiEnrichment) {
|
|
934
|
+
const { aiEnrichment } = result;
|
|
1010
935
|
// eslint-disable-next-line no-console
|
|
1011
|
-
console.
|
|
936
|
+
console.log(`AI enrichment: ${aiEnrichment.enrichedFeatures.length} features enriched (${aiEnrichment.tokenUsage.input + aiEnrichment.tokenUsage.output} tokens)`);
|
|
1012
937
|
}
|
|
1013
|
-
else {
|
|
1014
|
-
|
|
938
|
+
else if (!process.env.ANTHROPIC_API_KEY) {
|
|
939
|
+
// eslint-disable-next-line no-console
|
|
940
|
+
console.log('Tip: set ANTHROPIC_API_KEY to enable AI-powered enrichment');
|
|
1015
941
|
}
|
|
1016
942
|
}
|
|
1017
|
-
|
|
1018
|
-
|
|
943
|
+
const { plan, planPath, ciSummaryMarkdown, ciSummaryPath } = result;
|
|
944
|
+
// Write CI summary to an additional path if --ci-comment-path was specified
|
|
945
|
+
if (args.ciCommentPath) {
|
|
946
|
+
(0, plan_builder_js_1.writeCiSummary)(reportRoot, ciSummaryMarkdown, args.ciCommentPath);
|
|
1019
947
|
}
|
|
1020
|
-
const
|
|
1021
|
-
|
|
1022
|
-
const
|
|
1023
|
-
|
|
1024
|
-
testsRoot: reportRoot,
|
|
1025
|
-
sinceRef: config.git.since,
|
|
1026
|
-
configPath,
|
|
1027
|
-
});
|
|
1028
|
-
const plan = (0, operational_insights_js_1.applyOperationalInsights)(withActions, reportRoot);
|
|
1029
|
-
const planPath = (0, plan_js_1.writePlanReport)(reportRoot, plan);
|
|
1030
|
-
const summaryMarkdown = (0, plan_js_1.renderCiSummaryMarkdown)(plan);
|
|
1031
|
-
const summaryPath = (0, plan_js_1.writeCiSummary)(reportRoot, summaryMarkdown, args.ciCommentPath);
|
|
1032
|
-
const metrics = (0, plan_js_1.appendPlanMetrics)(reportRoot, plan);
|
|
948
|
+
const summaryPath = ciSummaryPath;
|
|
949
|
+
// Compute metrics paths (api already wrote metrics; derive paths for GHA output)
|
|
950
|
+
const metricsEventsPath = (0, path_1.join)(reportRoot, '.e2e-ai-agents/metrics.jsonl');
|
|
951
|
+
const metricsSummaryPath = (0, path_1.join)(reportRoot, '.e2e-ai-agents/metrics-summary.json');
|
|
1033
952
|
const ghaOutput = args.githubOutputPath || process.env.GITHUB_OUTPUT;
|
|
1034
953
|
if (ghaOutput) {
|
|
1035
954
|
(0, fs_1.appendFileSync)(ghaOutput, `run_set=${plan.runSet}\n`);
|
|
@@ -1041,8 +960,8 @@ async function main() {
|
|
|
1041
960
|
(0, fs_1.appendFileSync)(ghaOutput, `required_new_tests_count=${plan.requiredNewTests.length}\n`);
|
|
1042
961
|
(0, fs_1.appendFileSync)(ghaOutput, `plan_path=${planPath}\n`);
|
|
1043
962
|
(0, fs_1.appendFileSync)(ghaOutput, `summary_path=${summaryPath}\n`);
|
|
1044
|
-
(0, fs_1.appendFileSync)(ghaOutput, `metrics_events_path=${
|
|
1045
|
-
(0, fs_1.appendFileSync)(ghaOutput, `metrics_summary_path=${
|
|
963
|
+
(0, fs_1.appendFileSync)(ghaOutput, `metrics_events_path=${metricsEventsPath}\n`);
|
|
964
|
+
(0, fs_1.appendFileSync)(ghaOutput, `metrics_summary_path=${metricsSummaryPath}\n`);
|
|
1046
965
|
}
|
|
1047
966
|
// eslint-disable-next-line no-console
|
|
1048
967
|
console.log(`Suggested run set: ${plan.runSet} (confidence ${plan.confidence})`);
|
|
@@ -1055,26 +974,17 @@ async function main() {
|
|
|
1055
974
|
// eslint-disable-next-line no-console
|
|
1056
975
|
console.log(`CI summary: ${summaryPath}`);
|
|
1057
976
|
// eslint-disable-next-line no-console
|
|
1058
|
-
console.log(`Plan metrics: ${
|
|
1059
|
-
if (plan.nextActions) {
|
|
1060
|
-
// eslint-disable-next-line no-console
|
|
1061
|
-
console.log(`Next action (run existing): ${plan.nextActions.runRecommendedTests || plan.nextActions.runSmokeSuite}`);
|
|
1062
|
-
// eslint-disable-next-line no-console
|
|
1063
|
-
console.log(`Next action (approve + generate): ${plan.nextActions.approveAndGenerate || plan.nextActions.generateMissingTests}`);
|
|
1064
|
-
// eslint-disable-next-line no-console
|
|
1065
|
-
console.log(`Next action (heal): ${plan.nextActions.healGeneratedTests}`);
|
|
1066
|
-
}
|
|
977
|
+
console.log(`Plan metrics: ${metricsSummaryPath}`);
|
|
1067
978
|
const failOnLegacyFlag = args.failOnMustAddTests && plan.decision.action === 'must-add-tests';
|
|
1068
979
|
if (failOnLegacyFlag || plan.enforcement.shouldFail) {
|
|
1069
980
|
process.exit(2);
|
|
1070
981
|
}
|
|
1071
982
|
return;
|
|
1072
983
|
}
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
await (0, runner_js_1.runGap)(config, { apply: args.apply });
|
|
984
|
+
// eslint-disable-next-line no-console
|
|
985
|
+
console.error(`Unknown command: ${args.command}`);
|
|
986
|
+
printUsage();
|
|
987
|
+
process.exit(1);
|
|
1078
988
|
}
|
|
1079
989
|
async function runLlmHealth() {
|
|
1080
990
|
if (!process.env.ANTHROPIC_API_KEY) {
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { LLMProvider } from '../provider_interface.js';
|
|
2
|
+
import type { ImpactResult } from './impact_engine.js';
|
|
3
|
+
import type { FeaturePriority } from '../knowledge/route_families.js';
|
|
4
|
+
export interface EnrichedFeature {
|
|
5
|
+
familyId: string;
|
|
6
|
+
featureId?: string;
|
|
7
|
+
priority: FeaturePriority;
|
|
8
|
+
changedFiles: string[];
|
|
9
|
+
coverageStatus: string;
|
|
10
|
+
playwrightSpecs: string[];
|
|
11
|
+
cypressSpecs: string[];
|
|
12
|
+
userFlows: string[];
|
|
13
|
+
aiReasons: string[];
|
|
14
|
+
aiMissingScenarios: string[];
|
|
15
|
+
aiCoveredBy: string[];
|
|
16
|
+
}
|
|
17
|
+
export interface AIEnrichmentResult {
|
|
18
|
+
enrichedFeatures: EnrichedFeature[];
|
|
19
|
+
unboundFileInsights: Array<{
|
|
20
|
+
file: string;
|
|
21
|
+
likelyFeature: string;
|
|
22
|
+
reason: string;
|
|
23
|
+
}>;
|
|
24
|
+
warnings: string[];
|
|
25
|
+
providerName: string;
|
|
26
|
+
tokenUsage: {
|
|
27
|
+
input: number;
|
|
28
|
+
output: number;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export interface AIEnrichmentOptions {
|
|
32
|
+
deterministicImpact: ImpactResult;
|
|
33
|
+
diffs: Map<string, string>;
|
|
34
|
+
provider: LLMProvider;
|
|
35
|
+
specList: string[];
|
|
36
|
+
manifestSummary?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Enriches a deterministic impact result with AI-generated reasons,
|
|
40
|
+
* missing test scenarios, and coverage insights.
|
|
41
|
+
*/
|
|
42
|
+
export declare function enrichImpactWithAI(options: AIEnrichmentOptions): Promise<AIEnrichmentResult>;
|
|
43
|
+
//# sourceMappingURL=ai_enrichment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai_enrichment.d.ts","sourceRoot":"","sources":["../../src/engine/ai_enrichment.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAC,YAAY,EAAkB,MAAM,oBAAoB,CAAC;AACtE,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,gCAAgC,CAAC;AAGpE,MAAM,WAAW,eAAe;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,eAAe,CAAC;IAC1B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,WAAW,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IAC/B,gBAAgB,EAAE,eAAe,EAAE,CAAC;IACpC,mBAAmB,EAAE,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;IAClF,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,CAAC;CAC/C;AAED,MAAM,WAAW,mBAAmB;IAChC,mBAAmB,EAAE,YAAY,CAAC;IAClC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,QAAQ,EAAE,WAAW,CAAC;IACtB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B;AAoJD;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAkIlG"}
|