@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/index.d.ts
CHANGED
|
@@ -18,8 +18,11 @@ export { OpenAIProvider, checkOpenAISetup } from './openai_provider.js';
|
|
|
18
18
|
export { CustomProvider } from './custom_provider.js';
|
|
19
19
|
export { LLMProviderFactory, validateProviderSetup } from './provider_factory.js';
|
|
20
20
|
export type { HybridConfig } from './provider_factory.js';
|
|
21
|
-
export {
|
|
22
|
-
export type { AgentApiOptions,
|
|
21
|
+
export { analyzeImpactDeterministic, recommendTestsDeterministic, handoffGeneratedTests, ingestTraceability, captureTraceability } from './api.js';
|
|
22
|
+
export type { AgentApiOptions, RecommendTestsV2Result, TraceabilityIngestApiOptions, TraceabilityCaptureApiOptions, } from './api.js';
|
|
23
|
+
export { analyzeImpact as analyzeImpactV2, getGaps, getPartialGaps } from './engine/impact_engine.js';
|
|
24
|
+
export type { ImpactResult, ImpactedFeature, CoverageStatus, ImpactEngineOptions } from './engine/impact_engine.js';
|
|
25
|
+
export { buildPlanFromImpact } from './engine/plan_builder.js';
|
|
23
26
|
export { appendFeedbackAndRecompute, readCalibration } from './agent/feedback.js';
|
|
24
27
|
export type { RecommendationFeedbackEntry, CalibrationSummary } from './agent/feedback.js';
|
|
25
28
|
export { finalizeGeneratedTests } from './agent/handoff.js';
|
|
@@ -39,10 +42,12 @@ export { runHealStage, healFromReport, resolveHealTargets, renderHealMarkdown }
|
|
|
39
42
|
export type { HealConfig, HealTarget, HealResult } from './pipeline/stage4_heal.js';
|
|
40
43
|
export { buildHealPrompt, buildQualityFixPrompt } from './prompts/heal.js';
|
|
41
44
|
export type { HealPromptContext } from './prompts/heal.js';
|
|
42
|
-
export { loadRouteFamilyManifest, bindFilesToFamilies } from './knowledge/route_families.js';
|
|
43
|
-
export type { RouteFamily, RouteFeature, RouteFamilyManifest, FileBinding } from './knowledge/route_families.js';
|
|
45
|
+
export { loadRouteFamilyManifest, bindFilesToFamilies, getCypressSpecDirsForBinding, getPriorityForBinding, getUserFlowsForBinding } from './knowledge/route_families.js';
|
|
46
|
+
export type { RouteFamily, RouteFeature, RouteFamilyManifest, FileBinding, FeaturePriority } from './knowledge/route_families.js';
|
|
44
47
|
export { buildApiSurface, loadOrBuildApiSurface } from './knowledge/api_surface.js';
|
|
45
48
|
export type { ApiSurfaceCatalog, PageObjectSurface } from './knowledge/api_surface.js';
|
|
46
49
|
export { buildSpecIndex, getSpecsForFamily } from './knowledge/spec_index.js';
|
|
47
50
|
export type { SpecIndex, SpecEntry } from './knowledge/spec_index.js';
|
|
51
|
+
export type { FlowImpact, FlowPriority, FlowCoverage, FlagHit, BlastRadius } from './agent/types.js';
|
|
52
|
+
export type { PlanReport } from './agent/plan.js';
|
|
48
53
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AAGH,YAAY,EACR,WAAW,EACX,eAAe,EACf,UAAU,EACV,WAAW,EACX,UAAU,EACV,oBAAoB,EACpB,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,YAAY,GACf,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAC,gBAAgB,EAAE,0BAA0B,EAAC,MAAM,yBAAyB,CAAC;AAGrF,OAAO,EAAC,iBAAiB,EAAE,mBAAmB,EAAC,MAAM,yBAAyB,CAAC;AAC/E,OAAO,EAAC,cAAc,EAAE,gBAAgB,EAAC,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAC,cAAc,EAAE,gBAAgB,EAAC,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAC,cAAc,EAAC,MAAM,sBAAsB,CAAC;AAGpD,OAAO,EAAC,kBAAkB,EAAE,qBAAqB,EAAC,MAAM,uBAAuB,CAAC;AAChF,YAAY,EAAC,YAAY,EAAC,MAAM,uBAAuB,CAAC;AAGxD,OAAO,EAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -2,7 +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.getSpecsForFamily = exports.buildSpecIndex = exports.loadOrBuildApiSurface = exports.buildApiSurface = exports.bindFilesToFamilies = exports.loadRouteFamilyManifest = exports.buildQualityFixPrompt = exports.buildHealPrompt = exports.renderHealMarkdown = exports.resolveHealTargets = exports.healFromReport = exports.runHealStage = exports.detectHallucinatedMethods = exports.parseGenerationResponse = exports.buildGenerationPrompt = exports.runGenerationStage = exports.runPipeline = exports.captureTraceabilityInput = exports.ingestTraceabilityInput = exports.finalizeGeneratedTests = exports.readCalibration = exports.appendFeedbackAndRecompute = exports.
|
|
5
|
+
exports.getSpecsForFamily = exports.buildSpecIndex = exports.loadOrBuildApiSurface = exports.buildApiSurface = exports.getUserFlowsForBinding = exports.getPriorityForBinding = exports.getCypressSpecDirsForBinding = exports.bindFilesToFamilies = exports.loadRouteFamilyManifest = exports.buildQualityFixPrompt = exports.buildHealPrompt = exports.renderHealMarkdown = exports.resolveHealTargets = exports.healFromReport = exports.runHealStage = exports.detectHallucinatedMethods = exports.parseGenerationResponse = exports.buildGenerationPrompt = exports.runGenerationStage = exports.runPipeline = exports.captureTraceabilityInput = exports.ingestTraceabilityInput = exports.finalizeGeneratedTests = exports.readCalibration = exports.appendFeedbackAndRecompute = exports.buildPlanFromImpact = exports.getPartialGaps = exports.getGaps = exports.analyzeImpactV2 = exports.captureTraceability = exports.ingestTraceability = exports.handoffGeneratedTests = exports.recommendTestsDeterministic = exports.analyzeImpactDeterministic = exports.validateProviderSetup = exports.LLMProviderFactory = exports.CustomProvider = exports.checkOpenAISetup = exports.OpenAIProvider = exports.checkOllamaSetup = exports.OllamaProvider = exports.checkAnthropicSetup = exports.AnthropicProvider = exports.UnsupportedCapabilityError = exports.LLMProviderError = void 0;
|
|
6
6
|
var provider_interface_js_1 = require("./provider_interface.js");
|
|
7
7
|
Object.defineProperty(exports, "LLMProviderError", { enumerable: true, get: function () { return provider_interface_js_1.LLMProviderError; } });
|
|
8
8
|
Object.defineProperty(exports, "UnsupportedCapabilityError", { enumerable: true, get: function () { return provider_interface_js_1.UnsupportedCapabilityError; } });
|
|
@@ -22,14 +22,20 @@ Object.defineProperty(exports, "CustomProvider", { enumerable: true, get: functi
|
|
|
22
22
|
var provider_factory_js_1 = require("./provider_factory.js");
|
|
23
23
|
Object.defineProperty(exports, "LLMProviderFactory", { enumerable: true, get: function () { return provider_factory_js_1.LLMProviderFactory; } });
|
|
24
24
|
Object.defineProperty(exports, "validateProviderSetup", { enumerable: true, get: function () { return provider_factory_js_1.validateProviderSetup; } });
|
|
25
|
-
// Agent API (impact
|
|
25
|
+
// Agent API (deterministic impact + plan, traceability)
|
|
26
26
|
var api_js_1 = require("./api.js");
|
|
27
|
-
Object.defineProperty(exports, "
|
|
28
|
-
Object.defineProperty(exports, "
|
|
29
|
-
Object.defineProperty(exports, "recommendTests", { enumerable: true, get: function () { return api_js_1.recommendTests; } });
|
|
27
|
+
Object.defineProperty(exports, "analyzeImpactDeterministic", { enumerable: true, get: function () { return api_js_1.analyzeImpactDeterministic; } });
|
|
28
|
+
Object.defineProperty(exports, "recommendTestsDeterministic", { enumerable: true, get: function () { return api_js_1.recommendTestsDeterministic; } });
|
|
30
29
|
Object.defineProperty(exports, "handoffGeneratedTests", { enumerable: true, get: function () { return api_js_1.handoffGeneratedTests; } });
|
|
31
30
|
Object.defineProperty(exports, "ingestTraceability", { enumerable: true, get: function () { return api_js_1.ingestTraceability; } });
|
|
32
31
|
Object.defineProperty(exports, "captureTraceability", { enumerable: true, get: function () { return api_js_1.captureTraceability; } });
|
|
32
|
+
// V2 Engine (deterministic impact + plan)
|
|
33
|
+
var impact_engine_js_1 = require("./engine/impact_engine.js");
|
|
34
|
+
Object.defineProperty(exports, "analyzeImpactV2", { enumerable: true, get: function () { return impact_engine_js_1.analyzeImpact; } });
|
|
35
|
+
Object.defineProperty(exports, "getGaps", { enumerable: true, get: function () { return impact_engine_js_1.getGaps; } });
|
|
36
|
+
Object.defineProperty(exports, "getPartialGaps", { enumerable: true, get: function () { return impact_engine_js_1.getPartialGaps; } });
|
|
37
|
+
var plan_builder_js_1 = require("./engine/plan_builder.js");
|
|
38
|
+
Object.defineProperty(exports, "buildPlanFromImpact", { enumerable: true, get: function () { return plan_builder_js_1.buildPlanFromImpact; } });
|
|
33
39
|
var feedback_js_1 = require("./agent/feedback.js");
|
|
34
40
|
Object.defineProperty(exports, "appendFeedbackAndRecompute", { enumerable: true, get: function () { return feedback_js_1.appendFeedbackAndRecompute; } });
|
|
35
41
|
Object.defineProperty(exports, "readCalibration", { enumerable: true, get: function () { return feedback_js_1.readCalibration; } });
|
|
@@ -60,6 +66,9 @@ Object.defineProperty(exports, "buildQualityFixPrompt", { enumerable: true, get:
|
|
|
60
66
|
var route_families_js_1 = require("./knowledge/route_families.js");
|
|
61
67
|
Object.defineProperty(exports, "loadRouteFamilyManifest", { enumerable: true, get: function () { return route_families_js_1.loadRouteFamilyManifest; } });
|
|
62
68
|
Object.defineProperty(exports, "bindFilesToFamilies", { enumerable: true, get: function () { return route_families_js_1.bindFilesToFamilies; } });
|
|
69
|
+
Object.defineProperty(exports, "getCypressSpecDirsForBinding", { enumerable: true, get: function () { return route_families_js_1.getCypressSpecDirsForBinding; } });
|
|
70
|
+
Object.defineProperty(exports, "getPriorityForBinding", { enumerable: true, get: function () { return route_families_js_1.getPriorityForBinding; } });
|
|
71
|
+
Object.defineProperty(exports, "getUserFlowsForBinding", { enumerable: true, get: function () { return route_families_js_1.getUserFlowsForBinding; } });
|
|
63
72
|
var api_surface_js_1 = require("./knowledge/api_surface.js");
|
|
64
73
|
Object.defineProperty(exports, "buildApiSurface", { enumerable: true, get: function () { return api_surface_js_1.buildApiSurface; } });
|
|
65
74
|
Object.defineProperty(exports, "loadOrBuildApiSurface", { enumerable: true, get: function () { return api_surface_js_1.loadOrBuildApiSurface; } });
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
export type FeaturePriority = 'P0' | 'P1' | 'P2';
|
|
1
2
|
export interface RouteFeature {
|
|
2
3
|
id: string;
|
|
3
4
|
routes?: string[];
|
|
4
5
|
webappPaths?: string[];
|
|
5
6
|
serverPaths?: string[];
|
|
6
7
|
specDirs?: string[];
|
|
8
|
+
cypressSpecDirs?: string[];
|
|
7
9
|
tags?: string[];
|
|
10
|
+
priority?: FeaturePriority;
|
|
11
|
+
userFlows?: string[];
|
|
8
12
|
}
|
|
9
13
|
export interface RouteFamily {
|
|
10
14
|
id: string;
|
|
@@ -14,7 +18,10 @@ export interface RouteFamily {
|
|
|
14
18
|
webappPaths?: string[];
|
|
15
19
|
serverPaths?: string[];
|
|
16
20
|
specDirs?: string[];
|
|
21
|
+
cypressSpecDirs?: string[];
|
|
17
22
|
tags?: string[];
|
|
23
|
+
priority?: FeaturePriority;
|
|
24
|
+
userFlows?: string[];
|
|
18
25
|
features?: RouteFeature[];
|
|
19
26
|
}
|
|
20
27
|
export interface RouteFamilyManifest {
|
|
@@ -40,6 +47,18 @@ export declare function getSpecDirsForBinding(manifest: RouteFamilyManifest, bin
|
|
|
40
47
|
family: string;
|
|
41
48
|
feature?: string;
|
|
42
49
|
}): string[];
|
|
50
|
+
export declare function getCypressSpecDirsForBinding(manifest: RouteFamilyManifest, binding: {
|
|
51
|
+
family: string;
|
|
52
|
+
feature?: string;
|
|
53
|
+
}): string[];
|
|
54
|
+
export declare function getPriorityForBinding(manifest: RouteFamilyManifest, binding: {
|
|
55
|
+
family: string;
|
|
56
|
+
feature?: string;
|
|
57
|
+
}): FeaturePriority;
|
|
58
|
+
export declare function getUserFlowsForBinding(manifest: RouteFamilyManifest, binding: {
|
|
59
|
+
family: string;
|
|
60
|
+
feature?: string;
|
|
61
|
+
}): string[];
|
|
43
62
|
export declare function getRoutesForBinding(manifest: RouteFamilyManifest, binding: {
|
|
44
63
|
family: string;
|
|
45
64
|
feature?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route_families.d.ts","sourceRoot":"","sources":["../../src/knowledge/route_families.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,YAAY;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"route_families.d.ts","sourceRoot":"","sources":["../../src/knowledge/route_families.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,9 @@ exports.bindFilesToFamilies = bindFilesToFamilies;
|
|
|
7
7
|
exports.getFamilyById = getFamilyById;
|
|
8
8
|
exports.getFeatureById = getFeatureById;
|
|
9
9
|
exports.getSpecDirsForBinding = getSpecDirsForBinding;
|
|
10
|
+
exports.getCypressSpecDirsForBinding = getCypressSpecDirsForBinding;
|
|
11
|
+
exports.getPriorityForBinding = getPriorityForBinding;
|
|
12
|
+
exports.getUserFlowsForBinding = getUserFlowsForBinding;
|
|
10
13
|
exports.getRoutesForBinding = getRoutesForBinding;
|
|
11
14
|
exports.clearManifestCache = clearManifestCache;
|
|
12
15
|
const fs_1 = require("fs");
|
|
@@ -72,9 +75,18 @@ function validateFamily(family) {
|
|
|
72
75
|
if (Array.isArray(obj.specDirs)) {
|
|
73
76
|
result.specDirs = obj.specDirs.filter((v) => typeof v === 'string');
|
|
74
77
|
}
|
|
78
|
+
if (Array.isArray(obj.cypressSpecDirs)) {
|
|
79
|
+
result.cypressSpecDirs = obj.cypressSpecDirs.filter((v) => typeof v === 'string');
|
|
80
|
+
}
|
|
75
81
|
if (Array.isArray(obj.tags)) {
|
|
76
82
|
result.tags = obj.tags.filter((v) => typeof v === 'string');
|
|
77
83
|
}
|
|
84
|
+
if (obj.priority === 'P0' || obj.priority === 'P1' || obj.priority === 'P2') {
|
|
85
|
+
result.priority = obj.priority;
|
|
86
|
+
}
|
|
87
|
+
if (Array.isArray(obj.userFlows)) {
|
|
88
|
+
result.userFlows = obj.userFlows.filter((v) => typeof v === 'string');
|
|
89
|
+
}
|
|
78
90
|
if (Array.isArray(obj.features)) {
|
|
79
91
|
result.features = obj.features
|
|
80
92
|
.map((f) => validateFeature(f))
|
|
@@ -103,9 +115,18 @@ function validateFeature(feature) {
|
|
|
103
115
|
if (Array.isArray(obj.specDirs)) {
|
|
104
116
|
result.specDirs = obj.specDirs.filter((v) => typeof v === 'string');
|
|
105
117
|
}
|
|
118
|
+
if (Array.isArray(obj.cypressSpecDirs)) {
|
|
119
|
+
result.cypressSpecDirs = obj.cypressSpecDirs.filter((v) => typeof v === 'string');
|
|
120
|
+
}
|
|
106
121
|
if (Array.isArray(obj.tags)) {
|
|
107
122
|
result.tags = obj.tags.filter((v) => typeof v === 'string');
|
|
108
123
|
}
|
|
124
|
+
if (obj.priority === 'P0' || obj.priority === 'P1' || obj.priority === 'P2') {
|
|
125
|
+
result.priority = obj.priority;
|
|
126
|
+
}
|
|
127
|
+
if (Array.isArray(obj.userFlows)) {
|
|
128
|
+
result.userFlows = obj.userFlows.filter((v) => typeof v === 'string');
|
|
129
|
+
}
|
|
109
130
|
return result;
|
|
110
131
|
}
|
|
111
132
|
function loadRouteFamilyManifest(testsRoot, config) {
|
|
@@ -145,7 +166,8 @@ function loadRouteFamilyManifest(testsRoot, config) {
|
|
|
145
166
|
}
|
|
146
167
|
}
|
|
147
168
|
if (config?.strict) {
|
|
148
|
-
|
|
169
|
+
// eslint-disable-next-line no-console
|
|
170
|
+
console.warn('[e2e-agents] Route family manifest not found. The manifest is optional context for AI enrichment — create .e2e-ai-agents/route-families.json to enable family-level routing hints.');
|
|
149
171
|
}
|
|
150
172
|
return null;
|
|
151
173
|
}
|
|
@@ -202,6 +224,45 @@ function getSpecDirsForBinding(manifest, binding) {
|
|
|
202
224
|
}
|
|
203
225
|
return family.specDirs || [];
|
|
204
226
|
}
|
|
227
|
+
function getCypressSpecDirsForBinding(manifest, binding) {
|
|
228
|
+
const family = getFamilyById(manifest, binding.family);
|
|
229
|
+
if (!family) {
|
|
230
|
+
return [];
|
|
231
|
+
}
|
|
232
|
+
if (binding.feature) {
|
|
233
|
+
const feature = getFeatureById(family, binding.feature);
|
|
234
|
+
if (feature?.cypressSpecDirs && feature.cypressSpecDirs.length > 0) {
|
|
235
|
+
return feature.cypressSpecDirs;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return family.cypressSpecDirs || [];
|
|
239
|
+
}
|
|
240
|
+
function getPriorityForBinding(manifest, binding) {
|
|
241
|
+
const family = getFamilyById(manifest, binding.family);
|
|
242
|
+
if (!family) {
|
|
243
|
+
return 'P2';
|
|
244
|
+
}
|
|
245
|
+
if (binding.feature) {
|
|
246
|
+
const feature = getFeatureById(family, binding.feature);
|
|
247
|
+
if (feature?.priority) {
|
|
248
|
+
return feature.priority;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return family.priority || 'P2';
|
|
252
|
+
}
|
|
253
|
+
function getUserFlowsForBinding(manifest, binding) {
|
|
254
|
+
const family = getFamilyById(manifest, binding.family);
|
|
255
|
+
if (!family) {
|
|
256
|
+
return [];
|
|
257
|
+
}
|
|
258
|
+
if (binding.feature) {
|
|
259
|
+
const feature = getFeatureById(family, binding.feature);
|
|
260
|
+
if (feature?.userFlows && feature.userFlows.length > 0) {
|
|
261
|
+
return feature.userFlows;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return family.userFlows || [];
|
|
265
|
+
}
|
|
205
266
|
function getRoutesForBinding(manifest, binding) {
|
|
206
267
|
const family = getFamilyById(manifest, binding.family);
|
|
207
268
|
if (!family) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yasserkhanorg/e2e-agents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Pluggable LLM provider library for AI-powered test automation. Use Claude, Ollama, or your own LLM. Integrate with Playwright, Jest, or any test framework. MCP server for test agents, cost tracking, and hybrid provider mode.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { FileAnalysis, FlowImpact } from './analysis.js';
|
|
2
|
-
import type { AIFlowImpactConfig } from './config.js';
|
|
3
|
-
export interface AIFlowAnalysisResult {
|
|
4
|
-
enabled: boolean;
|
|
5
|
-
used: boolean;
|
|
6
|
-
ran: boolean;
|
|
7
|
-
provider: string;
|
|
8
|
-
flowCount: number;
|
|
9
|
-
warnings: string[];
|
|
10
|
-
flows: FlowImpact[];
|
|
11
|
-
}
|
|
12
|
-
export declare function mapAIFlowsFromFiles(appRoot: string, testsRoot: string, config: AIFlowImpactConfig, files: FileAnalysis[], changedFiles: string[]): Promise<AIFlowAnalysisResult>;
|
|
13
|
-
//# sourceMappingURL=ai_flow_analysis.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ai_flow_analysis.d.ts","sourceRoot":"","sources":["../../src/agent/ai_flow_analysis.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAC,YAAY,EAAE,UAAU,EAAe,MAAM,eAAe,CAAC;AAC1E,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,aAAa,CAAC;AAkBpD,MAAM,WAAW,oBAAoB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,EAAE,UAAU,EAAE,CAAC;CACvB;AA2JD,wBAAsB,mBAAmB,CACrC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,kBAAkB,EAC1B,KAAK,EAAE,YAAY,EAAE,EACrB,YAAY,EAAE,MAAM,EAAE,GACvB,OAAO,CAAC,oBAAoB,CAAC,CAuM/B"}
|
|
@@ -1,334 +0,0 @@
|
|
|
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.mapAIFlowsFromFiles = mapAIFlowsFromFiles;
|
|
6
|
-
const fs_1 = require("fs");
|
|
7
|
-
const path_1 = require("path");
|
|
8
|
-
const provider_factory_js_1 = require("../provider_factory.js");
|
|
9
|
-
const utils_js_1 = require("./utils.js");
|
|
10
|
-
function extractJson(text) {
|
|
11
|
-
const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
12
|
-
const candidates = fenced ? [fenced[1], text] : [text];
|
|
13
|
-
for (const candidate of candidates) {
|
|
14
|
-
const start = candidate.indexOf('{');
|
|
15
|
-
const end = candidate.lastIndexOf('}');
|
|
16
|
-
if (start < 0 || end <= start) {
|
|
17
|
-
continue;
|
|
18
|
-
}
|
|
19
|
-
const raw = candidate.slice(start, end + 1);
|
|
20
|
-
try {
|
|
21
|
-
const parsed = JSON.parse(raw);
|
|
22
|
-
if (parsed && Array.isArray(parsed.flows)) {
|
|
23
|
-
return parsed;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
catch {
|
|
27
|
-
// Ignore parse failure and keep trying other candidates.
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
function resolveContextFiles(appRoot, testsRoot, files) {
|
|
33
|
-
const resolved = [];
|
|
34
|
-
const seen = new Set();
|
|
35
|
-
const maxCharsPerFile = 12000;
|
|
36
|
-
const maxTotalChars = 32000;
|
|
37
|
-
let totalChars = 0;
|
|
38
|
-
for (const file of files) {
|
|
39
|
-
const candidates = (0, path_1.isAbsolute)(file)
|
|
40
|
-
? [file]
|
|
41
|
-
: [(0, path_1.join)(testsRoot, file), (0, path_1.join)(appRoot, file)];
|
|
42
|
-
for (const candidate of candidates) {
|
|
43
|
-
const normalized = (0, utils_js_1.normalizePath)(candidate);
|
|
44
|
-
if (seen.has(normalized) || !(0, fs_1.existsSync)(candidate)) {
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
const content = (0, fs_1.readFileSync)(candidate, 'utf-8');
|
|
48
|
-
const trimmed = content.trim();
|
|
49
|
-
if (!trimmed) {
|
|
50
|
-
seen.add(normalized);
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
const remaining = Math.max(0, maxTotalChars - totalChars);
|
|
54
|
-
if (remaining <= 0) {
|
|
55
|
-
return resolved;
|
|
56
|
-
}
|
|
57
|
-
const clipped = trimmed.slice(0, Math.min(maxCharsPerFile, remaining));
|
|
58
|
-
resolved.push({ path: normalized, content: clipped });
|
|
59
|
-
seen.add(normalized);
|
|
60
|
-
totalChars += clipped.length;
|
|
61
|
-
break;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
return resolved;
|
|
65
|
-
}
|
|
66
|
-
function priorityFromEntry(entry) {
|
|
67
|
-
if (entry.priority === 'P0' || entry.priority === 'P1' || entry.priority === 'P2') {
|
|
68
|
-
return entry.priority;
|
|
69
|
-
}
|
|
70
|
-
const score = typeof entry.score === 'number' ? entry.score : 0;
|
|
71
|
-
if (score >= 8) {
|
|
72
|
-
return 'P0';
|
|
73
|
-
}
|
|
74
|
-
if (score >= 5) {
|
|
75
|
-
return 'P1';
|
|
76
|
-
}
|
|
77
|
-
return 'P2';
|
|
78
|
-
}
|
|
79
|
-
function normalizeFlowId(value) {
|
|
80
|
-
return (0, utils_js_1.normalizePath)(value)
|
|
81
|
-
.replace(/[^a-zA-Z0-9/_-]+/g, '_')
|
|
82
|
-
.replace(/\/{2,}/g, '/')
|
|
83
|
-
.replace(/^\/+/, '')
|
|
84
|
-
.replace(/\/+$/, '')
|
|
85
|
-
.trim();
|
|
86
|
-
}
|
|
87
|
-
function sanitizeReasons(reasons, fallback) {
|
|
88
|
-
if (!Array.isArray(reasons)) {
|
|
89
|
-
return [fallback];
|
|
90
|
-
}
|
|
91
|
-
const cleaned = reasons.filter((entry) => typeof entry === 'string').map((entry) => entry.trim()).filter(Boolean);
|
|
92
|
-
return cleaned.length > 0 ? cleaned : [fallback];
|
|
93
|
-
}
|
|
94
|
-
function sanitizeKeywords(keywords, fallbackTokens) {
|
|
95
|
-
if (!Array.isArray(keywords)) {
|
|
96
|
-
return (0, utils_js_1.uniqueTokens)(fallbackTokens).slice(0, 20);
|
|
97
|
-
}
|
|
98
|
-
const fromAI = keywords.filter((entry) => typeof entry === 'string').flatMap((entry) => (0, utils_js_1.tokenize)(entry));
|
|
99
|
-
return (0, utils_js_1.uniqueTokens)([...fromAI, ...fallbackTokens]).slice(0, 20);
|
|
100
|
-
}
|
|
101
|
-
function summarizeFiles(files, changedFileSet, maxFiles) {
|
|
102
|
-
const sorted = [...files].sort((a, b) => {
|
|
103
|
-
const aChanged = changedFileSet.has(a.relativePath) ? 1 : 0;
|
|
104
|
-
const bChanged = changedFileSet.has(b.relativePath) ? 1 : 0;
|
|
105
|
-
if (aChanged !== bChanged) {
|
|
106
|
-
return bChanged - aChanged;
|
|
107
|
-
}
|
|
108
|
-
const aSignals = (a.isUI ? 1 : 0) + (a.isScreen ? 1 : 0) + (a.isState ? 1 : 0) + (a.hasInteractions ? 1 : 0);
|
|
109
|
-
const bSignals = (b.isUI ? 1 : 0) + (b.isScreen ? 1 : 0) + (b.isState ? 1 : 0) + (b.hasInteractions ? 1 : 0);
|
|
110
|
-
if (aSignals !== bSignals) {
|
|
111
|
-
return bSignals - aSignals;
|
|
112
|
-
}
|
|
113
|
-
return a.relativePath.localeCompare(b.relativePath);
|
|
114
|
-
}).slice(0, Math.max(20, maxFiles));
|
|
115
|
-
return sorted.map((file) => ({
|
|
116
|
-
path: file.relativePath,
|
|
117
|
-
changed: changedFileSet.has(file.relativePath),
|
|
118
|
-
isUI: file.isUI,
|
|
119
|
-
isScreen: file.isScreen,
|
|
120
|
-
isComponent: file.isComponent,
|
|
121
|
-
isState: file.isState,
|
|
122
|
-
isStyle: file.isStyle,
|
|
123
|
-
hasInteractions: file.hasInteractions,
|
|
124
|
-
keywords: file.keywords.slice(0, 20),
|
|
125
|
-
audience: file.audience,
|
|
126
|
-
flags: file.flags?.map((flag) => ({ name: flag.name, source: flag.source, defaultState: flag.defaultState })),
|
|
127
|
-
}));
|
|
128
|
-
}
|
|
129
|
-
function mergeFlow(existing, candidate) {
|
|
130
|
-
if (!existing) {
|
|
131
|
-
return candidate;
|
|
132
|
-
}
|
|
133
|
-
const priorityOrder = { P0: 0, P1: 1, P2: 2 };
|
|
134
|
-
const priority = priorityOrder[candidate.priority] < priorityOrder[existing.priority]
|
|
135
|
-
? candidate.priority
|
|
136
|
-
: existing.priority;
|
|
137
|
-
return {
|
|
138
|
-
...existing,
|
|
139
|
-
name: existing.name || candidate.name,
|
|
140
|
-
kind: existing.kind || candidate.kind,
|
|
141
|
-
score: Math.max(existing.score, candidate.score),
|
|
142
|
-
priority,
|
|
143
|
-
reasons: (0, utils_js_1.uniqueTokens)([...(existing.reasons || []), ...(candidate.reasons || [])]),
|
|
144
|
-
keywords: (0, utils_js_1.uniqueTokens)([...(existing.keywords || []), ...(candidate.keywords || [])]),
|
|
145
|
-
files: (0, utils_js_1.uniqueTokens)([...(existing.files || []), ...(candidate.files || [])]),
|
|
146
|
-
audience: (0, utils_js_1.uniqueTokens)([...(existing.audience || []), ...(candidate.audience || [])]),
|
|
147
|
-
flags: [...(existing.flags || []), ...(candidate.flags || [])],
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
async function mapAIFlowsFromFiles(appRoot, testsRoot, config, files, changedFiles) {
|
|
151
|
-
const providerName = config.provider === 'auto' ? 'auto' : config.provider;
|
|
152
|
-
const warnings = [];
|
|
153
|
-
if (!config.enabled) {
|
|
154
|
-
return {
|
|
155
|
-
enabled: false,
|
|
156
|
-
used: false,
|
|
157
|
-
ran: false,
|
|
158
|
-
provider: providerName,
|
|
159
|
-
flowCount: 0,
|
|
160
|
-
warnings,
|
|
161
|
-
flows: [],
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
if (files.length === 0) {
|
|
165
|
-
warnings.push('AI flow analysis skipped: no analyzable files were found.');
|
|
166
|
-
return {
|
|
167
|
-
enabled: true,
|
|
168
|
-
used: false,
|
|
169
|
-
ran: false,
|
|
170
|
-
provider: providerName,
|
|
171
|
-
flowCount: 0,
|
|
172
|
-
warnings,
|
|
173
|
-
flows: [],
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
const changedFileSet = new Set(changedFiles.map((entry) => (0, utils_js_1.normalizePath)(entry)));
|
|
177
|
-
const summarizedFiles = summarizeFiles(files, changedFileSet, config.maxFilesPerRequest);
|
|
178
|
-
const allowedFiles = new Set(files.map((entry) => entry.relativePath));
|
|
179
|
-
const fileByPath = new Map(files.map((entry) => [entry.relativePath, entry]));
|
|
180
|
-
const contextFiles = resolveContextFiles(appRoot, testsRoot, config.contextFiles || []);
|
|
181
|
-
const contextBlock = contextFiles.length > 0
|
|
182
|
-
? contextFiles.map((entry) => `### Context: ${entry.path}\n${entry.content}`).join('\n\n')
|
|
183
|
-
: 'No optional markdown context files were found.';
|
|
184
|
-
if (contextFiles.length === 0) {
|
|
185
|
-
warnings.push('AI flow analysis context files were not found; continuing without optional markdown context.');
|
|
186
|
-
}
|
|
187
|
-
let provider;
|
|
188
|
-
try {
|
|
189
|
-
provider = config.provider === 'auto'
|
|
190
|
-
? await provider_factory_js_1.LLMProviderFactory.createFromEnv()
|
|
191
|
-
: provider_factory_js_1.LLMProviderFactory.createFromString(config.provider);
|
|
192
|
-
}
|
|
193
|
-
catch (error) {
|
|
194
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
195
|
-
warnings.push(`AI flow analysis unavailable (${providerName}): ${message}`);
|
|
196
|
-
return {
|
|
197
|
-
enabled: true,
|
|
198
|
-
used: false,
|
|
199
|
-
ran: false,
|
|
200
|
-
provider: providerName,
|
|
201
|
-
flowCount: 0,
|
|
202
|
-
warnings,
|
|
203
|
-
flows: [],
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
const prompt = [
|
|
207
|
-
'You are an expert frontend impact analyst for Mattermost.',
|
|
208
|
-
'Build impacted user flows from changed frontend files.',
|
|
209
|
-
'This must be flow-centric, not file-centric.',
|
|
210
|
-
'',
|
|
211
|
-
'Return strict JSON only with this exact shape:',
|
|
212
|
-
'{"flows":[{"id":"<flow_id>","name":"<name>","kind":"flow|screen","priority":"P0|P1|P2","score":10,"reasons":["..."],"keywords":["..."],"files":["relative/path.tsx"]}]}',
|
|
213
|
-
'',
|
|
214
|
-
'Rules:',
|
|
215
|
-
'- Use only file paths listed in FILES.',
|
|
216
|
-
'- Every flow must have at least one file.',
|
|
217
|
-
'- Keep IDs stable and lowercase with underscores when possible.',
|
|
218
|
-
'- Prioritize true user-impacting flows; avoid low-value internal buckets.',
|
|
219
|
-
'- Keep at most 6 file paths per flow.',
|
|
220
|
-
`- Keep at most ${Math.max(1, config.maxFlowsPerRequest)} flows.`,
|
|
221
|
-
'',
|
|
222
|
-
`CHANGED_FILES (${changedFileSet.size}):`,
|
|
223
|
-
JSON.stringify(Array.from(changedFileSet), null, 2),
|
|
224
|
-
'',
|
|
225
|
-
`FILES (${summarizedFiles.length}):`,
|
|
226
|
-
JSON.stringify(summarizedFiles, null, 2),
|
|
227
|
-
'',
|
|
228
|
-
contextBlock,
|
|
229
|
-
].join('\n');
|
|
230
|
-
let parsed = null;
|
|
231
|
-
try {
|
|
232
|
-
const response = await provider.generateText(prompt, {
|
|
233
|
-
maxTokens: Math.max(800, config.maxTokens),
|
|
234
|
-
temperature: Math.max(0, Math.min(1, config.temperature)),
|
|
235
|
-
timeout: 45000,
|
|
236
|
-
systemPrompt: 'Return only valid JSON. Do not include markdown fences unless necessary.',
|
|
237
|
-
});
|
|
238
|
-
parsed = extractJson(response.text);
|
|
239
|
-
}
|
|
240
|
-
catch (error) {
|
|
241
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
242
|
-
warnings.push(`AI flow analysis request failed (${provider.name}): ${message}`);
|
|
243
|
-
return {
|
|
244
|
-
enabled: true,
|
|
245
|
-
used: false,
|
|
246
|
-
ran: false,
|
|
247
|
-
provider: provider.name,
|
|
248
|
-
flowCount: 0,
|
|
249
|
-
warnings,
|
|
250
|
-
flows: [],
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
if (!parsed) {
|
|
254
|
-
warnings.push(`AI flow analysis returned invalid JSON (${provider.name}).`);
|
|
255
|
-
return {
|
|
256
|
-
enabled: true,
|
|
257
|
-
used: false,
|
|
258
|
-
ran: false,
|
|
259
|
-
provider: provider.name,
|
|
260
|
-
flowCount: 0,
|
|
261
|
-
warnings,
|
|
262
|
-
flows: [],
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
|
-
const flowsById = new Map();
|
|
266
|
-
for (const entry of parsed.flows) {
|
|
267
|
-
if (!entry || !Array.isArray(entry.files)) {
|
|
268
|
-
continue;
|
|
269
|
-
}
|
|
270
|
-
const validFiles = Array.from(new Set(entry.files
|
|
271
|
-
.filter((value) => typeof value === 'string')
|
|
272
|
-
.map((value) => (0, utils_js_1.normalizePath)(value))
|
|
273
|
-
.filter((value) => allowedFiles.has(value)))).slice(0, 6);
|
|
274
|
-
if (validFiles.length === 0) {
|
|
275
|
-
continue;
|
|
276
|
-
}
|
|
277
|
-
const rawId = typeof entry.id === 'string' && entry.id.trim()
|
|
278
|
-
? entry.id
|
|
279
|
-
: (typeof entry.name === 'string' && entry.name.trim() ? entry.name : validFiles[0]);
|
|
280
|
-
const id = normalizeFlowId(rawId);
|
|
281
|
-
if (!id) {
|
|
282
|
-
continue;
|
|
283
|
-
}
|
|
284
|
-
const fallbackTokens = (0, utils_js_1.uniqueTokens)([
|
|
285
|
-
...(0, utils_js_1.tokenize)(id),
|
|
286
|
-
...(typeof entry.name === 'string' ? (0, utils_js_1.tokenize)(entry.name) : []),
|
|
287
|
-
...validFiles.flatMap((value) => (0, utils_js_1.tokenize)(value)),
|
|
288
|
-
]);
|
|
289
|
-
const linkedFiles = validFiles.map((path) => fileByPath.get(path)).filter(Boolean);
|
|
290
|
-
const audience = (0, utils_js_1.uniqueTokens)(linkedFiles.flatMap((file) => file.audience || []));
|
|
291
|
-
const flags = linkedFiles.flatMap((file) => file.flags || []);
|
|
292
|
-
const score = typeof entry.score === 'number' && Number.isFinite(entry.score)
|
|
293
|
-
? Math.max(1, Math.min(20, Math.round(entry.score)))
|
|
294
|
-
: Math.max(4, validFiles.length * 2);
|
|
295
|
-
const flow = {
|
|
296
|
-
id,
|
|
297
|
-
name: typeof entry.name === 'string' && entry.name.trim() ? entry.name.trim() : id.replace(/[_/.-]+/g, ' '),
|
|
298
|
-
kind: entry.kind === 'screen' ? 'screen' : 'flow',
|
|
299
|
-
score,
|
|
300
|
-
priority: priorityFromEntry(entry),
|
|
301
|
-
reasons: sanitizeReasons(entry.reasons, 'AI flow analysis identified impacted behavior'),
|
|
302
|
-
keywords: sanitizeKeywords(entry.keywords, fallbackTokens),
|
|
303
|
-
files: validFiles,
|
|
304
|
-
audience,
|
|
305
|
-
flags,
|
|
306
|
-
};
|
|
307
|
-
flowsById.set(id, mergeFlow(flowsById.get(id), flow));
|
|
308
|
-
if (flowsById.size >= Math.max(1, config.maxFlowsPerRequest)) {
|
|
309
|
-
break;
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
const flows = Array.from(flowsById.values());
|
|
313
|
-
if (flows.length === 0) {
|
|
314
|
-
warnings.push('AI flow analysis did not return any valid flows linked to changed files.');
|
|
315
|
-
return {
|
|
316
|
-
enabled: true,
|
|
317
|
-
used: false,
|
|
318
|
-
ran: true, // AI was called and responded — no user-facing flows impacted
|
|
319
|
-
provider: provider.name,
|
|
320
|
-
flowCount: 0,
|
|
321
|
-
warnings,
|
|
322
|
-
flows: [],
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
return {
|
|
326
|
-
enabled: true,
|
|
327
|
-
used: true,
|
|
328
|
-
ran: true,
|
|
329
|
-
provider: provider.name,
|
|
330
|
-
flowCount: flows.length,
|
|
331
|
-
warnings,
|
|
332
|
-
flows,
|
|
333
|
-
};
|
|
334
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { FlowImpact } from './analysis.js';
|
|
2
|
-
import type { AIMappingImpactConfig } from './config.js';
|
|
3
|
-
import type { FlowCoverage, TestFile } from './tests.js';
|
|
4
|
-
export interface AIMappingResult {
|
|
5
|
-
enabled: boolean;
|
|
6
|
-
used: boolean;
|
|
7
|
-
provider: string;
|
|
8
|
-
mappedFlows: number;
|
|
9
|
-
matchedTests: number;
|
|
10
|
-
coverage: FlowCoverage[];
|
|
11
|
-
warnings: string[];
|
|
12
|
-
}
|
|
13
|
-
export declare function mapAITestsToFlows(appRoot: string, testsRoot: string, config: AIMappingImpactConfig, flows: FlowImpact[], tests: TestFile[]): Promise<AIMappingResult>;
|
|
14
|
-
//# sourceMappingURL=ai_mapping.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ai_mapping.d.ts","sourceRoot":"","sources":["../../src/agent/ai_mapping.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,aAAa,CAAC;AACvD,OAAO,KAAK,EAAC,YAAY,EAAE,QAAQ,EAAC,MAAM,YAAY,CAAC;AA4BvD,MAAM,WAAW,eAAe;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACtB;AA4WD,wBAAsB,iBAAiB,CACnC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,qBAAqB,EAC7B,KAAK,EAAE,UAAU,EAAE,EACnB,KAAK,EAAE,QAAQ,EAAE,GAClB,OAAO,CAAC,eAAe,CAAC,CAgP1B"}
|