@yasserkhanorg/e2e-agents 0.3.2
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/LICENSE +168 -0
- package/README.md +620 -0
- package/dist/agent/analysis.d.ts +62 -0
- package/dist/agent/analysis.d.ts.map +1 -0
- package/dist/agent/analysis.js +292 -0
- package/dist/agent/blast_radius.d.ts +4 -0
- package/dist/agent/blast_radius.d.ts.map +1 -0
- package/dist/agent/blast_radius.js +37 -0
- package/dist/agent/cache_utils.d.ts +38 -0
- package/dist/agent/cache_utils.d.ts.map +1 -0
- package/dist/agent/cache_utils.js +67 -0
- package/dist/agent/config.d.ts +148 -0
- package/dist/agent/config.d.ts.map +1 -0
- package/dist/agent/config.js +640 -0
- package/dist/agent/dependency_graph.d.ts +14 -0
- package/dist/agent/dependency_graph.d.ts.map +1 -0
- package/dist/agent/dependency_graph.js +227 -0
- package/dist/agent/feedback.d.ts +55 -0
- package/dist/agent/feedback.d.ts.map +1 -0
- package/dist/agent/feedback.js +257 -0
- package/dist/agent/flags.d.ts +23 -0
- package/dist/agent/flags.d.ts.map +1 -0
- package/dist/agent/flags.js +171 -0
- package/dist/agent/flow_catalog.d.ts +25 -0
- package/dist/agent/flow_catalog.d.ts.map +1 -0
- package/dist/agent/flow_catalog.js +106 -0
- package/dist/agent/flow_mapping.d.ts +10 -0
- package/dist/agent/flow_mapping.d.ts.map +1 -0
- package/dist/agent/flow_mapping.js +84 -0
- package/dist/agent/framework.d.ts +13 -0
- package/dist/agent/framework.d.ts.map +1 -0
- package/dist/agent/framework.js +149 -0
- package/dist/agent/gap_suggestions.d.ts +14 -0
- package/dist/agent/gap_suggestions.d.ts.map +1 -0
- package/dist/agent/gap_suggestions.js +101 -0
- package/dist/agent/generator.d.ts +10 -0
- package/dist/agent/generator.d.ts.map +1 -0
- package/dist/agent/generator.js +115 -0
- package/dist/agent/git.d.ts +11 -0
- package/dist/agent/git.d.ts.map +1 -0
- package/dist/agent/git.js +90 -0
- package/dist/agent/handoff.d.ts +22 -0
- package/dist/agent/handoff.d.ts.map +1 -0
- package/dist/agent/handoff.js +180 -0
- package/dist/agent/impact-analyzer.d.ts +114 -0
- package/dist/agent/impact-analyzer.d.ts.map +1 -0
- package/dist/agent/impact-analyzer.js +557 -0
- package/dist/agent/index.d.ts +21 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +38 -0
- package/dist/agent/model-router.d.ts +57 -0
- package/dist/agent/model-router.d.ts.map +1 -0
- package/dist/agent/model-router.js +154 -0
- package/dist/agent/operational_insights.d.ts +41 -0
- package/dist/agent/operational_insights.d.ts.map +1 -0
- package/dist/agent/operational_insights.js +126 -0
- package/dist/agent/pipeline.d.ts +23 -0
- package/dist/agent/pipeline.d.ts.map +1 -0
- package/dist/agent/pipeline.js +609 -0
- package/dist/agent/plan.d.ts +91 -0
- package/dist/agent/plan.d.ts.map +1 -0
- package/dist/agent/plan.js +331 -0
- package/dist/agent/playwright_report.d.ts +8 -0
- package/dist/agent/playwright_report.d.ts.map +1 -0
- package/dist/agent/playwright_report.js +126 -0
- package/dist/agent/report-generator.d.ts +24 -0
- package/dist/agent/report-generator.d.ts.map +1 -0
- package/dist/agent/report-generator.js +250 -0
- package/dist/agent/report.d.ts +81 -0
- package/dist/agent/report.d.ts.map +1 -0
- package/dist/agent/report.js +147 -0
- package/dist/agent/runner.d.ts +7 -0
- package/dist/agent/runner.d.ts.map +1 -0
- package/dist/agent/runner.js +576 -0
- package/dist/agent/selectors.d.ts +10 -0
- package/dist/agent/selectors.d.ts.map +1 -0
- package/dist/agent/selectors.js +75 -0
- package/dist/agent/spec-bridge.d.ts +101 -0
- package/dist/agent/spec-bridge.d.ts.map +1 -0
- package/dist/agent/spec-bridge.js +273 -0
- package/dist/agent/spec-builder.d.ts +102 -0
- package/dist/agent/spec-builder.d.ts.map +1 -0
- package/dist/agent/spec-builder.js +273 -0
- package/dist/agent/subsystem_risk.d.ts +23 -0
- package/dist/agent/subsystem_risk.d.ts.map +1 -0
- package/dist/agent/subsystem_risk.js +207 -0
- package/dist/agent/telemetry.d.ts +84 -0
- package/dist/agent/telemetry.d.ts.map +1 -0
- package/dist/agent/telemetry.js +220 -0
- package/dist/agent/test_path.d.ts +2 -0
- package/dist/agent/test_path.d.ts.map +1 -0
- package/dist/agent/test_path.js +23 -0
- package/dist/agent/tests.d.ts +18 -0
- package/dist/agent/tests.d.ts.map +1 -0
- package/dist/agent/tests.js +106 -0
- package/dist/agent/traceability.d.ts +22 -0
- package/dist/agent/traceability.d.ts.map +1 -0
- package/dist/agent/traceability.js +183 -0
- package/dist/agent/traceability_capture.d.ts +18 -0
- package/dist/agent/traceability_capture.d.ts.map +1 -0
- package/dist/agent/traceability_capture.js +313 -0
- package/dist/agent/traceability_ingest.d.ts +21 -0
- package/dist/agent/traceability_ingest.d.ts.map +1 -0
- package/dist/agent/traceability_ingest.js +237 -0
- package/dist/agent/utils.d.ts +13 -0
- package/dist/agent/utils.d.ts.map +1 -0
- package/dist/agent/utils.js +152 -0
- package/dist/agent/validators/selector-validator.d.ts +74 -0
- package/dist/agent/validators/selector-validator.d.ts.map +1 -0
- package/dist/agent/validators/selector-validator.js +165 -0
- package/dist/anthropic_provider.d.ts +65 -0
- package/dist/anthropic_provider.d.ts.map +1 -0
- package/dist/anthropic_provider.js +332 -0
- package/dist/api.d.ts +48 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +113 -0
- package/dist/base_provider.d.ts +53 -0
- package/dist/base_provider.d.ts.map +1 -0
- package/dist/base_provider.js +81 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +843 -0
- package/dist/custom_provider.d.ts +20 -0
- package/dist/custom_provider.d.ts.map +1 -0
- package/dist/custom_provider.js +276 -0
- package/dist/e2e-test-gen/index.d.ts +51 -0
- package/dist/e2e-test-gen/index.d.ts.map +1 -0
- package/dist/e2e-test-gen/index.js +57 -0
- package/dist/e2e-test-gen/spec_parser.d.ts +142 -0
- package/dist/e2e-test-gen/spec_parser.d.ts.map +1 -0
- package/dist/e2e-test-gen/spec_parser.js +786 -0
- package/dist/e2e-test-gen/types.d.ts +185 -0
- package/dist/e2e-test-gen/types.d.ts.map +1 -0
- package/dist/e2e-test-gen/types.js +4 -0
- package/dist/esm/agent/analysis.js +287 -0
- package/dist/esm/agent/blast_radius.js +34 -0
- package/dist/esm/agent/cache_utils.js +63 -0
- package/dist/esm/agent/config.js +637 -0
- package/dist/esm/agent/dependency_graph.js +224 -0
- package/dist/esm/agent/feedback.js +253 -0
- package/dist/esm/agent/flags.js +160 -0
- package/dist/esm/agent/flow_catalog.js +103 -0
- package/dist/esm/agent/flow_mapping.js +81 -0
- package/dist/esm/agent/framework.js +145 -0
- package/dist/esm/agent/gap_suggestions.js +98 -0
- package/dist/esm/agent/generator.js +112 -0
- package/dist/esm/agent/git.js +87 -0
- package/dist/esm/agent/handoff.js +177 -0
- package/dist/esm/agent/impact-analyzer.js +548 -0
- package/dist/esm/agent/index.js +22 -0
- package/dist/esm/agent/model-router.js +150 -0
- package/dist/esm/agent/operational_insights.js +123 -0
- package/dist/esm/agent/pipeline.js +605 -0
- package/dist/esm/agent/plan.js +324 -0
- package/dist/esm/agent/playwright_report.js +123 -0
- package/dist/esm/agent/report-generator.js +247 -0
- package/dist/esm/agent/report.js +144 -0
- package/dist/esm/agent/runner.js +572 -0
- package/dist/esm/agent/selectors.js +71 -0
- package/dist/esm/agent/spec-bridge.js +267 -0
- package/dist/esm/agent/spec-builder.js +267 -0
- package/dist/esm/agent/subsystem_risk.js +204 -0
- package/dist/esm/agent/telemetry.js +216 -0
- package/dist/esm/agent/test_path.js +20 -0
- package/dist/esm/agent/tests.js +101 -0
- package/dist/esm/agent/traceability.js +180 -0
- package/dist/esm/agent/traceability_capture.js +310 -0
- package/dist/esm/agent/traceability_ingest.js +234 -0
- package/dist/esm/agent/utils.js +138 -0
- package/dist/esm/agent/validators/selector-validator.js +160 -0
- package/dist/esm/anthropic_provider.js +324 -0
- package/dist/esm/api.js +105 -0
- package/dist/esm/base_provider.js +77 -0
- package/dist/esm/cli.js +841 -0
- package/dist/esm/custom_provider.js +272 -0
- package/dist/esm/e2e-test-gen/index.js +50 -0
- package/dist/esm/e2e-test-gen/spec_parser.js +782 -0
- package/dist/esm/e2e-test-gen/types.js +3 -0
- package/dist/esm/index.js +16 -0
- package/dist/esm/logger.js +89 -0
- package/dist/esm/mcp-server.js +465 -0
- package/dist/esm/ollama_provider.js +300 -0
- package/dist/esm/openai_provider.js +242 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/plan-and-test-constants.js +126 -0
- package/dist/esm/provider_factory.js +336 -0
- package/dist/esm/provider_interface.js +23 -0
- package/dist/esm/provider_utils.js +96 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/logger.d.ts +23 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +93 -0
- package/dist/mcp-server.d.ts +35 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +469 -0
- package/dist/ollama_provider.d.ts +65 -0
- package/dist/ollama_provider.d.ts.map +1 -0
- package/dist/ollama_provider.js +308 -0
- package/dist/openai_provider.d.ts +23 -0
- package/dist/openai_provider.d.ts.map +1 -0
- package/dist/openai_provider.js +250 -0
- package/dist/plan-and-test-constants.d.ts +110 -0
- package/dist/plan-and-test-constants.d.ts.map +1 -0
- package/dist/plan-and-test-constants.js +132 -0
- package/dist/provider_factory.d.ts +99 -0
- package/dist/provider_factory.d.ts.map +1 -0
- package/dist/provider_factory.js +341 -0
- package/dist/provider_interface.d.ts +358 -0
- package/dist/provider_interface.d.ts.map +1 -0
- package/dist/provider_interface.js +28 -0
- package/dist/provider_utils.d.ts +39 -0
- package/dist/provider_utils.d.ts.map +1 -0
- package/dist/provider_utils.js +103 -0
- package/package.json +101 -0
- package/schemas/gap.schema.json +18 -0
- package/schemas/impact.schema.json +418 -0
- package/schemas/plan.schema.json +285 -0
- package/schemas/subsystem-risk-map.schema.json +62 -0
- package/schemas/traceability-input.schema.json +122 -0
|
@@ -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.normalizeRole = normalizeRole;
|
|
6
|
+
exports.normalizeRoles = normalizeRoles;
|
|
7
|
+
exports.normalizeFlagSource = normalizeFlagSource;
|
|
8
|
+
exports.normalizeFlagState = normalizeFlagState;
|
|
9
|
+
exports.mergeFlags = mergeFlags;
|
|
10
|
+
exports.extractFlagHits = extractFlagHits;
|
|
11
|
+
exports.inferAudienceFromPath = inferAudienceFromPath;
|
|
12
|
+
exports.formatFlags = formatFlags;
|
|
13
|
+
exports.computeBlastRadius = computeBlastRadius;
|
|
14
|
+
const ROLE_ORDER = [
|
|
15
|
+
'system_admin',
|
|
16
|
+
'team_admin',
|
|
17
|
+
'channel_admin',
|
|
18
|
+
'member',
|
|
19
|
+
'guest',
|
|
20
|
+
'deactivated',
|
|
21
|
+
];
|
|
22
|
+
const FEATURE_FLAG_REGEX = /\bFeatureFlags?\.(\w+)\b/g;
|
|
23
|
+
const FEATURE_FLAG_STRING_REGEX = /\b(?:isFeatureEnabled|getFeatureFlag|featureFlag)\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
24
|
+
const SERVICE_SETTINGS_REGEX = /\bServiceSettings\.(\w+)\b/g;
|
|
25
|
+
const TEST_GATE_REGEX = /\bskipIfFeatureFlagNotSet\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
26
|
+
const ROLE_ALIASES = {
|
|
27
|
+
'system admin': 'system_admin',
|
|
28
|
+
'system_admin': 'system_admin',
|
|
29
|
+
sysadmin: 'system_admin',
|
|
30
|
+
'team admin': 'team_admin',
|
|
31
|
+
'team_admin': 'team_admin',
|
|
32
|
+
'channel admin': 'channel_admin',
|
|
33
|
+
'channel_admin': 'channel_admin',
|
|
34
|
+
member: 'member',
|
|
35
|
+
members: 'member',
|
|
36
|
+
guest: 'guest',
|
|
37
|
+
guests: 'guest',
|
|
38
|
+
deactivated: 'deactivated',
|
|
39
|
+
inactive: 'deactivated',
|
|
40
|
+
disabled: 'deactivated',
|
|
41
|
+
};
|
|
42
|
+
function normalizeRole(role) {
|
|
43
|
+
const key = role.trim().toLowerCase();
|
|
44
|
+
return ROLE_ALIASES[key] ?? null;
|
|
45
|
+
}
|
|
46
|
+
function normalizeRoles(roles, fallback) {
|
|
47
|
+
const normalized = roles
|
|
48
|
+
.map((role) => normalizeRole(role))
|
|
49
|
+
.filter((role) => Boolean(role));
|
|
50
|
+
const combined = normalized.length > 0 ? normalized : fallback;
|
|
51
|
+
const unique = new Set(combined);
|
|
52
|
+
return ROLE_ORDER.filter((role) => unique.has(role));
|
|
53
|
+
}
|
|
54
|
+
function normalizeFlagSource(source) {
|
|
55
|
+
if (!source) {
|
|
56
|
+
return 'featureFlag';
|
|
57
|
+
}
|
|
58
|
+
const value = source.trim().toLowerCase();
|
|
59
|
+
if (['feature', 'featureflag', 'feature_flag', 'flag'].includes(value)) {
|
|
60
|
+
return 'featureFlag';
|
|
61
|
+
}
|
|
62
|
+
if (['config', 'service', 'servicesettings', 'server'].includes(value)) {
|
|
63
|
+
return 'configFlag';
|
|
64
|
+
}
|
|
65
|
+
if (['test', 'gate', 'testgate'].includes(value)) {
|
|
66
|
+
return 'testGate';
|
|
67
|
+
}
|
|
68
|
+
return 'featureFlag';
|
|
69
|
+
}
|
|
70
|
+
function normalizeFlagState(value, fallback) {
|
|
71
|
+
if (!value) {
|
|
72
|
+
return fallback;
|
|
73
|
+
}
|
|
74
|
+
const lowered = value.trim().toLowerCase();
|
|
75
|
+
if (lowered === 'on' || lowered === 'off' || lowered === 'unknown') {
|
|
76
|
+
return lowered;
|
|
77
|
+
}
|
|
78
|
+
return fallback;
|
|
79
|
+
}
|
|
80
|
+
function mergeFlags(flags, defaultState) {
|
|
81
|
+
const map = new Map();
|
|
82
|
+
for (const flag of flags) {
|
|
83
|
+
const key = `${flag.source}:${flag.name.toLowerCase()}`;
|
|
84
|
+
if (!map.has(key)) {
|
|
85
|
+
map.set(key, {
|
|
86
|
+
...flag,
|
|
87
|
+
defaultState: flag.defaultState ?? defaultState,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return Array.from(map.values());
|
|
92
|
+
}
|
|
93
|
+
function extractFlagHits(content, config) {
|
|
94
|
+
if (!content) {
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
97
|
+
const hits = [];
|
|
98
|
+
const defaultState = config.flags.defaultState;
|
|
99
|
+
for (const match of content.matchAll(FEATURE_FLAG_REGEX)) {
|
|
100
|
+
if (match[1]) {
|
|
101
|
+
hits.push({ name: match[1], source: 'featureFlag', defaultState });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
for (const match of content.matchAll(FEATURE_FLAG_STRING_REGEX)) {
|
|
105
|
+
if (match[1]) {
|
|
106
|
+
hits.push({ name: match[1], source: 'featureFlag', defaultState });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
for (const match of content.matchAll(SERVICE_SETTINGS_REGEX)) {
|
|
110
|
+
if (match[1]) {
|
|
111
|
+
hits.push({ name: match[1], source: 'configFlag', defaultState });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
for (const match of content.matchAll(TEST_GATE_REGEX)) {
|
|
115
|
+
if (match[1]) {
|
|
116
|
+
hits.push({ name: match[1], source: 'testGate', defaultState });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return mergeFlags(hits, defaultState);
|
|
120
|
+
}
|
|
121
|
+
function inferAudienceFromPath(relativePath, config) {
|
|
122
|
+
const normalized = relativePath.toLowerCase();
|
|
123
|
+
if (normalized.includes('admin_console') || normalized.includes('system_console')) {
|
|
124
|
+
return normalizeRoles(['system_admin'], config.audience.defaultRoles);
|
|
125
|
+
}
|
|
126
|
+
if (normalized.includes('team') && normalized.includes('admin')) {
|
|
127
|
+
return normalizeRoles(['team_admin'], config.audience.defaultRoles);
|
|
128
|
+
}
|
|
129
|
+
if (normalized.includes('channel') && normalized.includes('admin')) {
|
|
130
|
+
return normalizeRoles(['channel_admin'], config.audience.defaultRoles);
|
|
131
|
+
}
|
|
132
|
+
return normalizeRoles(config.audience.defaultRoles, config.audience.defaultRoles);
|
|
133
|
+
}
|
|
134
|
+
function formatFlags(flags) {
|
|
135
|
+
if (flags.length === 0) {
|
|
136
|
+
return 'none';
|
|
137
|
+
}
|
|
138
|
+
return flags.map((flag) => `${flag.name} (${flag.defaultState})`).join(', ');
|
|
139
|
+
}
|
|
140
|
+
function computeBlastRadius(audience, flags, config) {
|
|
141
|
+
const normalizedAudience = normalizeRoles(audience, config.audience.defaultRoles);
|
|
142
|
+
const normalizedFlags = mergeFlags(flags, config.flags.defaultState);
|
|
143
|
+
const hasMember = normalizedAudience.includes('member');
|
|
144
|
+
const hasGuest = normalizedAudience.includes('guest');
|
|
145
|
+
const hasAdmin = normalizedAudience.some((role) => role === 'system_admin' || role === 'team_admin' || role === 'channel_admin');
|
|
146
|
+
const scope = hasMember || hasGuest ? 'broad' : hasAdmin ? 'admin-only' : 'unknown';
|
|
147
|
+
const flagState = normalizedFlags.length === 0
|
|
148
|
+
? 'unflagged'
|
|
149
|
+
: normalizedFlags.some((flag) => flag.defaultState === 'off')
|
|
150
|
+
? 'flagged-off'
|
|
151
|
+
: 'flagged-on';
|
|
152
|
+
let scoreDelta = 0;
|
|
153
|
+
if (hasMember) {
|
|
154
|
+
scoreDelta += config.blastRadius.memberBonus;
|
|
155
|
+
}
|
|
156
|
+
if (hasGuest) {
|
|
157
|
+
scoreDelta += config.blastRadius.guestBonus;
|
|
158
|
+
}
|
|
159
|
+
if (!hasMember && !hasGuest) {
|
|
160
|
+
scoreDelta += config.blastRadius.adminOnlyPenalty;
|
|
161
|
+
}
|
|
162
|
+
if (normalizedFlags.some((flag) => flag.defaultState === 'off')) {
|
|
163
|
+
scoreDelta += config.blastRadius.flagOffPenalty;
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
audience: normalizedAudience,
|
|
167
|
+
flags: normalizedFlags,
|
|
168
|
+
summary: `${scope}; ${flagState}`,
|
|
169
|
+
scoreDelta,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { AgentConfig, AudienceRole } from './config.js';
|
|
2
|
+
import type { FlowPriority } from './analysis.js';
|
|
3
|
+
import { type FlagHit } from './flags.js';
|
|
4
|
+
export interface FlowCatalogFlag {
|
|
5
|
+
name: string;
|
|
6
|
+
source?: string;
|
|
7
|
+
defaultState?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface FlowCatalogEntry {
|
|
10
|
+
id: string;
|
|
11
|
+
name?: string;
|
|
12
|
+
priority: FlowPriority;
|
|
13
|
+
keywords?: string[];
|
|
14
|
+
paths?: string[];
|
|
15
|
+
tests?: string[];
|
|
16
|
+
description?: string;
|
|
17
|
+
audience?: AudienceRole[];
|
|
18
|
+
flags?: FlagHit[];
|
|
19
|
+
}
|
|
20
|
+
export interface FlowCatalog {
|
|
21
|
+
flows: FlowCatalogEntry[];
|
|
22
|
+
source: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function loadFlowCatalog(config: AgentConfig): FlowCatalog | null;
|
|
25
|
+
//# sourceMappingURL=flow_catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow_catalog.d.ts","sourceRoot":"","sources":["../../src/agent/flow_catalog.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,WAAW,EAAE,YAAY,EAAC,MAAM,aAAa,CAAC;AAC3D,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,eAAe,CAAC;AAChD,OAAO,EAA0D,KAAK,OAAO,EAAC,MAAM,YAAY,CAAC;AAGjG,MAAM,WAAW,eAAe;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,YAAY,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IACxB,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;CAClB;AA8FD,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,GAAG,IAAI,CAiBvE"}
|
|
@@ -0,0 +1,106 @@
|
|
|
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.loadFlowCatalog = loadFlowCatalog;
|
|
6
|
+
const fs_1 = require("fs");
|
|
7
|
+
const path_1 = require("path");
|
|
8
|
+
const flags_js_1 = require("./flags.js");
|
|
9
|
+
const utils_js_1 = require("./utils.js");
|
|
10
|
+
const catalogCache = new Map();
|
|
11
|
+
function normalizePriority(value) {
|
|
12
|
+
const upper = value.toUpperCase();
|
|
13
|
+
if (upper === 'P0' || upper === 'P1' || upper === 'P2') {
|
|
14
|
+
return upper;
|
|
15
|
+
}
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
function normalizeEntry(entry, config) {
|
|
19
|
+
if (!entry.id || !entry.priority) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
const priority = normalizePriority(entry.priority);
|
|
23
|
+
if (!priority) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
const rawAudience = Array.isArray(entry.audience)
|
|
27
|
+
? entry.audience.filter((role) => typeof role === 'string')
|
|
28
|
+
: [];
|
|
29
|
+
const normalizedAudience = (0, flags_js_1.normalizeRoles)(rawAudience, config.audience.defaultRoles);
|
|
30
|
+
const rawFlags = Array.isArray(entry.flags) ? entry.flags : [];
|
|
31
|
+
const normalizedFlags = [];
|
|
32
|
+
for (const flag of rawFlags) {
|
|
33
|
+
if (typeof flag === 'string') {
|
|
34
|
+
normalizedFlags.push({
|
|
35
|
+
name: flag,
|
|
36
|
+
source: 'featureFlag',
|
|
37
|
+
defaultState: config.flags.defaultState,
|
|
38
|
+
});
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (flag && typeof flag === 'object' && typeof flag.name === 'string') {
|
|
42
|
+
normalizedFlags.push({
|
|
43
|
+
name: flag.name,
|
|
44
|
+
source: (0, flags_js_1.normalizeFlagSource)(flag.source),
|
|
45
|
+
defaultState: (0, flags_js_1.normalizeFlagState)(flag.defaultState, config.flags.defaultState),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
...entry,
|
|
51
|
+
id: (0, utils_js_1.normalizePath)(entry.id),
|
|
52
|
+
name: entry.name || (0, utils_js_1.titleCase)(entry.id),
|
|
53
|
+
priority,
|
|
54
|
+
keywords: (entry.keywords || []).map((keyword) => keyword.toLowerCase()),
|
|
55
|
+
paths: (entry.paths || []).map((path) => (0, utils_js_1.normalizePath)(path)),
|
|
56
|
+
tests: (entry.tests || []).map((path) => (0, utils_js_1.normalizePath)(path)),
|
|
57
|
+
audience: normalizedAudience,
|
|
58
|
+
flags: normalizedFlags,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function readCatalog(path, config) {
|
|
62
|
+
try {
|
|
63
|
+
if (!(0, fs_1.existsSync)(path)) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
const mtimeMs = (0, fs_1.statSync)(path).mtimeMs;
|
|
67
|
+
const cached = catalogCache.get(path);
|
|
68
|
+
if (cached && cached.mtimeMs === mtimeMs) {
|
|
69
|
+
return cached.catalog;
|
|
70
|
+
}
|
|
71
|
+
const raw = JSON.parse((0, fs_1.readFileSync)(path, 'utf-8'));
|
|
72
|
+
if (!raw.flows || !Array.isArray(raw.flows)) {
|
|
73
|
+
catalogCache.set(path, { mtimeMs, catalog: null });
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
const flows = raw.flows
|
|
77
|
+
.map((flow) => normalizeEntry(flow, config))
|
|
78
|
+
.filter((flow) => Boolean(flow));
|
|
79
|
+
if (flows.length === 0) {
|
|
80
|
+
catalogCache.set(path, { mtimeMs, catalog: null });
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
const catalog = { flows, source: path };
|
|
84
|
+
catalogCache.set(path, { mtimeMs, catalog });
|
|
85
|
+
return catalog;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function loadFlowCatalog(config) {
|
|
92
|
+
const candidates = [];
|
|
93
|
+
if (config.flowCatalogPath) {
|
|
94
|
+
candidates.push(config.flowCatalogPath);
|
|
95
|
+
}
|
|
96
|
+
const testsRoot = config.testsRoot || config.path;
|
|
97
|
+
candidates.push((0, path_1.join)(testsRoot, '.e2e-ai-agents', 'flows.json'));
|
|
98
|
+
candidates.push((0, path_1.join)(config.path, '.e2e-ai-agents', 'flows.json'));
|
|
99
|
+
for (const candidate of candidates) {
|
|
100
|
+
const catalog = readCatalog(candidate, config);
|
|
101
|
+
if (catalog) {
|
|
102
|
+
return catalog;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FlowImpact } from './analysis.js';
|
|
2
|
+
import type { AgentConfig } from './config.js';
|
|
3
|
+
import type { FlowCatalog } from './flow_catalog.js';
|
|
4
|
+
export interface CatalogMappingResult {
|
|
5
|
+
flows: FlowImpact[];
|
|
6
|
+
testsByFlow: Map<string, string[]>;
|
|
7
|
+
warnings: string[];
|
|
8
|
+
}
|
|
9
|
+
export declare function mapChangesToCatalogFlows(catalog: FlowCatalog, changedFiles: string[], mode: 'impact' | 'gap', config: AgentConfig): CatalogMappingResult;
|
|
10
|
+
//# sourceMappingURL=flow_mapping.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow_mapping.d.ts","sourceRoot":"","sources":["../../src/agent/flow_mapping.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,mBAAmB,CAAC;AAGnD,MAAM,WAAW,oBAAoB;IACjC,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACnC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACtB;AAqBD,wBAAgB,wBAAwB,CACpC,OAAO,EAAE,WAAW,EACpB,YAAY,EAAE,MAAM,EAAE,EACtB,IAAI,EAAE,QAAQ,GAAG,KAAK,EACtB,MAAM,EAAE,WAAW,GACpB,oBAAoB,CAuEtB"}
|
|
@@ -0,0 +1,84 @@
|
|
|
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.mapChangesToCatalogFlows = mapChangesToCatalogFlows;
|
|
6
|
+
const utils_js_1 = require("./utils.js");
|
|
7
|
+
function pathMatches(patterns, filePath) {
|
|
8
|
+
for (const pattern of patterns) {
|
|
9
|
+
if ((0, utils_js_1.matchGlob)(filePath, pattern)) {
|
|
10
|
+
return pattern;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
function keywordMatches(keywords, filePath) {
|
|
16
|
+
const tokens = (0, utils_js_1.tokenize)(filePath);
|
|
17
|
+
for (const keyword of keywords) {
|
|
18
|
+
if (tokens.includes(keyword.toLowerCase())) {
|
|
19
|
+
return keyword;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
function mapChangesToCatalogFlows(catalog, changedFiles, mode, config) {
|
|
25
|
+
const warnings = [];
|
|
26
|
+
const flows = [];
|
|
27
|
+
const testsByFlow = new Map();
|
|
28
|
+
const normalizedChanges = Array.from(new Set(changedFiles.map((file) => (0, utils_js_1.normalizePath)(file))));
|
|
29
|
+
for (const flow of catalog.flows) {
|
|
30
|
+
const reasons = [];
|
|
31
|
+
const matchedFiles = new Set();
|
|
32
|
+
let matched = false;
|
|
33
|
+
if (flow.paths && flow.paths.length > 0) {
|
|
34
|
+
for (const file of normalizedChanges) {
|
|
35
|
+
const match = pathMatches(flow.paths, file);
|
|
36
|
+
if (match) {
|
|
37
|
+
matchedFiles.add(file);
|
|
38
|
+
reasons.push(`Path match: ${match}`);
|
|
39
|
+
matched = true;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (!matched && flow.keywords && flow.keywords.length > 0) {
|
|
44
|
+
for (const file of normalizedChanges) {
|
|
45
|
+
const keyword = keywordMatches(flow.keywords, file);
|
|
46
|
+
if (keyword) {
|
|
47
|
+
matchedFiles.add(file);
|
|
48
|
+
reasons.push(`Keyword match: ${keyword}`);
|
|
49
|
+
matched = true;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (mode === 'impact' && !matched) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (mode === 'gap' && reasons.length === 0) {
|
|
57
|
+
reasons.push('Catalog flow');
|
|
58
|
+
}
|
|
59
|
+
const priorityScore = config.catalogScoring?.priorityScores?.[flow.priority] ??
|
|
60
|
+
(flow.priority === 'P0' ? 10 : flow.priority === 'P1' ? 6 : 3);
|
|
61
|
+
const fileMatchWeight = config.catalogScoring?.fileMatchWeight ?? 1;
|
|
62
|
+
const score = priorityScore + matchedFiles.size * fileMatchWeight;
|
|
63
|
+
const matchedFilesList = Array.from(matchedFiles);
|
|
64
|
+
flows.push({
|
|
65
|
+
id: flow.id,
|
|
66
|
+
name: flow.name || flow.id,
|
|
67
|
+
kind: 'flow',
|
|
68
|
+
score,
|
|
69
|
+
priority: flow.priority,
|
|
70
|
+
reasons: (0, utils_js_1.uniqueTokens)(reasons),
|
|
71
|
+
keywords: flow.keywords || [],
|
|
72
|
+
files: (0, utils_js_1.uniqueTokens)(matchedFilesList),
|
|
73
|
+
audience: flow.audience,
|
|
74
|
+
flags: flow.flags,
|
|
75
|
+
});
|
|
76
|
+
if (flow.tests && flow.tests.length > 0) {
|
|
77
|
+
testsByFlow.set(flow.id, flow.tests.map((test) => (0, utils_js_1.normalizePath)(test)));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (flows.length === 0 && mode === 'impact') {
|
|
81
|
+
warnings.push('No flow catalog entries matched changed files.');
|
|
82
|
+
}
|
|
83
|
+
return { flows, testsByFlow, warnings };
|
|
84
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { FrameworkType } from './config.js';
|
|
2
|
+
export interface FrameworkDetection {
|
|
3
|
+
framework: FrameworkType;
|
|
4
|
+
configPath?: string;
|
|
5
|
+
reason: string;
|
|
6
|
+
}
|
|
7
|
+
export interface TestPatternResolution {
|
|
8
|
+
patterns: string[];
|
|
9
|
+
source: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function detectFramework(appRoot: string, explicitFramework?: FrameworkType): FrameworkDetection;
|
|
12
|
+
export declare function resolveTestPatterns(appRoot: string, detection: FrameworkDetection, explicitPatterns?: string[]): TestPatternResolution;
|
|
13
|
+
//# sourceMappingURL=framework.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"framework.d.ts","sourceRoot":"","sources":["../../src/agent/framework.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,aAAa,CAAC;AAE/C,MAAM,WAAW,kBAAkB;IAC/B,SAAS,EAAE,aAAa,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IAClC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAClB;AAmCD,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,aAAa,GAAG,kBAAkB,CAmCtG;AA0CD,wBAAgB,mBAAmB,CAC/B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,kBAAkB,EAC7B,gBAAgB,CAAC,EAAE,MAAM,EAAE,GAC5B,qBAAqB,CA+CvB"}
|
|
@@ -0,0 +1,149 @@
|
|
|
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.detectFramework = detectFramework;
|
|
6
|
+
exports.resolveTestPatterns = resolveTestPatterns;
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const path_1 = require("path");
|
|
9
|
+
const PLAYWRIGHT_CONFIG_FILES = ['playwright.config.ts', 'playwright.config.js'];
|
|
10
|
+
const CYPRESS_CONFIG_FILES = ['cypress.config.ts', 'cypress.config.js'];
|
|
11
|
+
const SELENIUM_CONFIG_FILES = ['selenium.config.ts', 'selenium.config.js', 'wdio.conf.ts', 'wdio.conf.js'];
|
|
12
|
+
function readPackageJson(appRoot) {
|
|
13
|
+
const pkgPath = (0, path_1.join)(appRoot, 'package.json');
|
|
14
|
+
if (!(0, fs_1.existsSync)(pkgPath)) {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
return JSON.parse((0, fs_1.readFileSync)(pkgPath, 'utf-8'));
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function hasDependency(pkg, dep) {
|
|
25
|
+
if (!pkg)
|
|
26
|
+
return false;
|
|
27
|
+
const dependencies = pkg.dependencies || {};
|
|
28
|
+
const devDependencies = pkg.devDependencies || {};
|
|
29
|
+
return Boolean(dependencies[dep] || devDependencies[dep]);
|
|
30
|
+
}
|
|
31
|
+
function findConfigFile(appRoot, candidates) {
|
|
32
|
+
for (const file of candidates) {
|
|
33
|
+
const fullPath = (0, path_1.join)(appRoot, file);
|
|
34
|
+
if ((0, fs_1.existsSync)(fullPath)) {
|
|
35
|
+
return fullPath;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
function detectFramework(appRoot, explicitFramework) {
|
|
41
|
+
if (explicitFramework && explicitFramework !== 'auto') {
|
|
42
|
+
return {
|
|
43
|
+
framework: explicitFramework,
|
|
44
|
+
reason: 'explicit',
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const playwrightConfig = findConfigFile(appRoot, PLAYWRIGHT_CONFIG_FILES);
|
|
48
|
+
if (playwrightConfig) {
|
|
49
|
+
return { framework: 'playwright', configPath: playwrightConfig, reason: 'config' };
|
|
50
|
+
}
|
|
51
|
+
const cypressConfig = findConfigFile(appRoot, CYPRESS_CONFIG_FILES);
|
|
52
|
+
if (cypressConfig) {
|
|
53
|
+
return { framework: 'cypress', configPath: cypressConfig, reason: 'config' };
|
|
54
|
+
}
|
|
55
|
+
const seleniumConfig = findConfigFile(appRoot, SELENIUM_CONFIG_FILES);
|
|
56
|
+
if (seleniumConfig) {
|
|
57
|
+
return { framework: 'selenium', configPath: seleniumConfig, reason: 'config' };
|
|
58
|
+
}
|
|
59
|
+
const pkg = readPackageJson(appRoot);
|
|
60
|
+
if (hasDependency(pkg, '@playwright/test') || hasDependency(pkg, 'playwright')) {
|
|
61
|
+
return { framework: 'playwright', reason: 'package.json' };
|
|
62
|
+
}
|
|
63
|
+
if (hasDependency(pkg, 'cypress')) {
|
|
64
|
+
return { framework: 'cypress', reason: 'package.json' };
|
|
65
|
+
}
|
|
66
|
+
if (hasDependency(pkg, 'selenium-webdriver') || hasDependency(pkg, 'webdriverio')) {
|
|
67
|
+
return { framework: 'selenium', reason: 'package.json' };
|
|
68
|
+
}
|
|
69
|
+
return { framework: 'unknown', reason: 'unknown' };
|
|
70
|
+
}
|
|
71
|
+
function extractQuotedStrings(value) {
|
|
72
|
+
const matches = value.match(/['"]([^'"]+)['"]/g);
|
|
73
|
+
if (!matches) {
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
return matches.map((match) => match.slice(1, -1)).filter(Boolean);
|
|
77
|
+
}
|
|
78
|
+
function parsePlaywrightPatterns(content) {
|
|
79
|
+
const testDirMatch = content.match(/testDir\s*:\s*['"]([^'"]+)['"]/);
|
|
80
|
+
if (testDirMatch) {
|
|
81
|
+
const testDir = testDirMatch[1];
|
|
82
|
+
return [
|
|
83
|
+
(0, path_1.join)(testDir, '**/*.spec.{ts,tsx,js,jsx}'),
|
|
84
|
+
(0, path_1.join)(testDir, '**/*.test.{ts,tsx,js,jsx}'),
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
const testMatchMatch = content.match(/testMatch\s*:\s*(\[[^\]]+\]|['"][^'"]+['"])/);
|
|
88
|
+
if (testMatchMatch) {
|
|
89
|
+
const patterns = extractQuotedStrings(testMatchMatch[1]);
|
|
90
|
+
if (patterns.length > 0) {
|
|
91
|
+
return patterns;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
function parseCypressPatterns(content) {
|
|
97
|
+
const specPatternMatch = content.match(/specPattern\s*:\s*(\[[^\]]+\]|['"][^'"]+['"])/);
|
|
98
|
+
if (specPatternMatch) {
|
|
99
|
+
const patterns = extractQuotedStrings(specPatternMatch[1]);
|
|
100
|
+
if (patterns.length > 0) {
|
|
101
|
+
return patterns;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
function resolveTestPatterns(appRoot, detection, explicitPatterns) {
|
|
107
|
+
if (explicitPatterns && explicitPatterns.length > 0) {
|
|
108
|
+
return { patterns: explicitPatterns, source: 'config' };
|
|
109
|
+
}
|
|
110
|
+
if (detection.configPath) {
|
|
111
|
+
try {
|
|
112
|
+
const configContent = (0, fs_1.readFileSync)(detection.configPath, 'utf-8');
|
|
113
|
+
if (detection.framework === 'playwright') {
|
|
114
|
+
const parsed = parsePlaywrightPatterns(configContent);
|
|
115
|
+
if (parsed.length > 0) {
|
|
116
|
+
return { patterns: parsed, source: (0, path_1.basename)(detection.configPath) };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (detection.framework === 'cypress') {
|
|
120
|
+
const parsed = parseCypressPatterns(configContent);
|
|
121
|
+
if (parsed.length > 0) {
|
|
122
|
+
return { patterns: parsed, source: (0, path_1.basename)(detection.configPath) };
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// Fall through to defaults
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (detection.framework === 'playwright') {
|
|
131
|
+
return {
|
|
132
|
+
patterns: ['tests/**/*.{spec,test}.{ts,tsx,js,jsx}'],
|
|
133
|
+
source: 'default-playwright',
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
if (detection.framework === 'cypress') {
|
|
137
|
+
return {
|
|
138
|
+
patterns: ['cypress/e2e/**/*.cy.{js,jsx,ts,tsx}'],
|
|
139
|
+
source: 'default-cypress',
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
if (detection.framework === 'selenium') {
|
|
143
|
+
return {
|
|
144
|
+
patterns: ['tests/selenium/**/*.{spec,test}.{js,ts}'],
|
|
145
|
+
source: 'default-selenium',
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
return { patterns: [], source: 'none' };
|
|
149
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { FrameworkType } from './config.js';
|
|
2
|
+
import type { FlowImpact } from './analysis.js';
|
|
3
|
+
export interface GapTestSuggestion {
|
|
4
|
+
flowId: string;
|
|
5
|
+
flowName: string;
|
|
6
|
+
priority: string;
|
|
7
|
+
rationale: string;
|
|
8
|
+
sourceFiles: string[];
|
|
9
|
+
suggestedTestPath: string;
|
|
10
|
+
framework: Exclude<FrameworkType, 'auto' | 'unknown'>;
|
|
11
|
+
skeleton: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function buildGapTestSuggestions(testsRoot: string, flowsWithGaps: FlowImpact[], framework: FrameworkType, testPatterns: string[]): GapTestSuggestion[];
|
|
14
|
+
//# sourceMappingURL=gap_suggestions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gap_suggestions.d.ts","sourceRoot":"","sources":["../../src/agent/gap_suggestions.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,eAAe,CAAC;AAG9C,MAAM,WAAW,iBAAiB;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACtD,QAAQ,EAAE,MAAM,CAAC;CACpB;AA0ED,wBAAgB,uBAAuB,CACnC,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,UAAU,EAAE,EAC3B,SAAS,EAAE,aAAa,EACxB,YAAY,EAAE,MAAM,EAAE,GACvB,iBAAiB,EAAE,CA0BrB"}
|