@yasserkhanorg/e2e-agents 1.3.2 → 1.5.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/README.md +40 -9
- package/dist/agent/feedback.d.ts +16 -0
- package/dist/agent/feedback.d.ts.map +1 -1
- package/dist/agent/feedback.js +62 -0
- package/dist/agent/process_runner.d.ts +1 -1
- package/dist/agent/process_runner.d.ts.map +1 -1
- package/dist/agent/process_runner.js +3 -3
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +5 -2
- package/dist/cli/commands/train.d.ts +3 -0
- package/dist/cli/commands/train.d.ts.map +1 -0
- package/dist/cli/commands/train.js +307 -0
- package/dist/cli/parse_args.d.ts.map +1 -1
- package/dist/cli/parse_args.js +7 -1
- package/dist/cli/types.d.ts +6 -1
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/cli/usage.d.ts.map +1 -1
- package/dist/cli/usage.js +7 -1
- package/dist/cli.js +5 -0
- package/dist/engine/plan_builder.d.ts +2 -1
- package/dist/engine/plan_builder.d.ts.map +1 -1
- package/dist/engine/plan_builder.js +22 -9
- package/dist/esm/agent/feedback.js +61 -0
- package/dist/esm/agent/process_runner.js +3 -3
- package/dist/esm/api.js +5 -2
- package/dist/esm/cli/commands/train.js +271 -0
- package/dist/esm/cli/parse_args.js +7 -1
- package/dist/esm/cli/usage.js +7 -1
- package/dist/esm/cli.js +5 -0
- package/dist/esm/engine/plan_builder.js +22 -9
- package/dist/esm/index.js +6 -1
- package/dist/esm/knowledge/route_families.js +2 -2
- package/dist/esm/pipeline/spec_verifier.js +75 -0
- package/dist/esm/pipeline/stage3_generation.js +122 -4
- package/dist/esm/pipeline/stage4_heal.js +146 -3
- package/dist/esm/prompts/heal.js +4 -0
- package/dist/esm/qa-agent/phase2/agent_loop.js +60 -24
- package/dist/esm/qa-agent/phase2/exploration_state.js +21 -0
- package/dist/esm/qa-agent/phase2/tools.js +99 -1
- package/dist/esm/qa-agent/phase3/reporter.js +31 -4
- package/dist/esm/training/enricher.js +273 -0
- package/dist/esm/training/merger.js +137 -0
- package/dist/esm/training/scanner.js +386 -0
- package/dist/esm/training/types.js +6 -0
- package/dist/esm/training/validator.js +153 -0
- package/dist/esm/validation/guardrails.js +1 -0
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -1
- package/dist/knowledge/route_families.d.ts +2 -0
- package/dist/knowledge/route_families.d.ts.map +1 -1
- package/dist/knowledge/route_families.js +2 -0
- package/dist/pipeline/orchestrator.d.ts.map +1 -1
- package/dist/pipeline/spec_verifier.d.ts +20 -0
- package/dist/pipeline/spec_verifier.d.ts.map +1 -0
- package/dist/pipeline/spec_verifier.js +79 -0
- package/dist/pipeline/stage3_generation.d.ts +10 -0
- package/dist/pipeline/stage3_generation.d.ts.map +1 -1
- package/dist/pipeline/stage3_generation.js +120 -2
- package/dist/pipeline/stage4_heal.d.ts +4 -0
- package/dist/pipeline/stage4_heal.d.ts.map +1 -1
- package/dist/pipeline/stage4_heal.js +145 -2
- package/dist/prompts/heal.d.ts +2 -0
- package/dist/prompts/heal.d.ts.map +1 -1
- package/dist/prompts/heal.js +4 -0
- package/dist/qa-agent/phase2/agent_loop.d.ts.map +1 -1
- package/dist/qa-agent/phase2/agent_loop.js +60 -24
- package/dist/qa-agent/phase2/exploration_state.d.ts.map +1 -1
- package/dist/qa-agent/phase2/exploration_state.js +21 -0
- package/dist/qa-agent/phase2/tools.d.ts.map +1 -1
- package/dist/qa-agent/phase2/tools.js +99 -1
- package/dist/qa-agent/phase3/reporter.js +31 -4
- package/dist/qa-agent/types.d.ts +9 -1
- package/dist/qa-agent/types.d.ts.map +1 -1
- package/dist/training/enricher.d.ts +15 -0
- package/dist/training/enricher.d.ts.map +1 -0
- package/dist/training/enricher.js +278 -0
- package/dist/training/merger.d.ts +5 -0
- package/dist/training/merger.d.ts.map +1 -0
- package/dist/training/merger.js +141 -0
- package/dist/training/scanner.d.ts +5 -0
- package/dist/training/scanner.d.ts.map +1 -0
- package/dist/training/scanner.js +391 -0
- package/dist/training/types.d.ts +109 -0
- package/dist/training/types.d.ts.map +1 -0
- package/dist/training/types.js +9 -0
- package/dist/training/validator.d.ts +16 -0
- package/dist/training/validator.d.ts.map +1 -0
- package/dist/training/validator.js +160 -0
- package/dist/validation/guardrails.d.ts +2 -0
- package/dist/validation/guardrails.d.ts.map +1 -1
- package/dist/validation/guardrails.js +4 -1
- package/package.json +1 -1
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
import { readdirSync, readFileSync, lstatSync, existsSync } from 'fs';
|
|
4
|
+
import { join, relative, basename, resolve } from 'path';
|
|
5
|
+
const SOURCE_MAX_DEPTH = 3;
|
|
6
|
+
// One deeper than source to account for test framework wrapper dirs (e2e/, integration/)
|
|
7
|
+
const TEST_MAX_DEPTH = 5;
|
|
8
|
+
const SPEC_FILES_MAX_DEPTH = 10;
|
|
9
|
+
const SOURCE_ROOTS = ['src', 'app', 'pages', 'components', 'features', 'modules'];
|
|
10
|
+
const SERVER_ROOTS = ['server', 'api', 'cmd', 'model', 'services'];
|
|
11
|
+
const SKIP_DIRS = new Set([
|
|
12
|
+
'node_modules', '.git', '.next', '.nuxt', 'dist', 'build',
|
|
13
|
+
'coverage', '__pycache__', '.e2e-ai-agents', '.cache',
|
|
14
|
+
'vendor', 'third_party',
|
|
15
|
+
]);
|
|
16
|
+
const TEST_EXTENSIONS = ['.spec.ts', '.test.ts', '.spec.js', '.test.js', '.spec.tsx', '.test.tsx'];
|
|
17
|
+
const GO_TEST_SUFFIX = '_test.go';
|
|
18
|
+
/** Type-safe includes check for readonly arrays */
|
|
19
|
+
const includes = (arr, v) => arr.includes(v);
|
|
20
|
+
function isSkipped(name) {
|
|
21
|
+
return name.startsWith('.') || SKIP_DIRS.has(name);
|
|
22
|
+
}
|
|
23
|
+
function normalizeId(name) {
|
|
24
|
+
return name
|
|
25
|
+
.replace(/[A-Z]/g, (c, idx) => (idx > 0 ? `_${c.toLowerCase()}` : c.toLowerCase()))
|
|
26
|
+
.replace(/[^a-z0-9_]/g, '_')
|
|
27
|
+
.replace(/_+/g, '_')
|
|
28
|
+
.replace(/^_|_$/g, '');
|
|
29
|
+
}
|
|
30
|
+
function extractFamilyHint(dirPath, projectRoot) {
|
|
31
|
+
const rel = relative(projectRoot, dirPath).replace(/\\/g, '/');
|
|
32
|
+
const parts = rel.split('/').filter(Boolean);
|
|
33
|
+
// Skip the root category dir (src/, server/, tests/, etc.)
|
|
34
|
+
// Return the first meaningful subdirectory name
|
|
35
|
+
for (let i = 1; i < parts.length; i++) {
|
|
36
|
+
const part = parts[i];
|
|
37
|
+
if (!isSkipped(part) && part !== 'e2e' && part !== 'integration' && part !== 'functional') {
|
|
38
|
+
return normalizeId(part);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return normalizeId(parts[parts.length - 1] || basename(dirPath));
|
|
42
|
+
}
|
|
43
|
+
function walkDirs(root, projectRoot, category, maxDepth, results, depth = 0) {
|
|
44
|
+
if (depth > maxDepth || !existsSync(root)) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
let entries;
|
|
48
|
+
try {
|
|
49
|
+
entries = readdirSync(root);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// ENOENT or EACCES — skip inaccessible entries
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const hasSourceFiles = entries.some((e) => {
|
|
56
|
+
const ext = e.slice(e.lastIndexOf('.'));
|
|
57
|
+
return ['.ts', '.tsx', '.js', '.jsx', '.go', '.py', '.rs'].includes(ext);
|
|
58
|
+
});
|
|
59
|
+
const subdirs = entries.filter((e) => {
|
|
60
|
+
if (isSkipped(e))
|
|
61
|
+
return false;
|
|
62
|
+
try {
|
|
63
|
+
const stat = lstatSync(join(root, e));
|
|
64
|
+
if (stat.isSymbolicLink())
|
|
65
|
+
return false;
|
|
66
|
+
return stat.isDirectory();
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// ENOENT or EACCES — skip inaccessible entries
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
if (hasSourceFiles && depth >= 1) {
|
|
74
|
+
results.push({
|
|
75
|
+
path: resolve(root),
|
|
76
|
+
relativePath: relative(projectRoot, root).replace(/\\/g, '/'),
|
|
77
|
+
category,
|
|
78
|
+
familyHint: extractFamilyHint(root, projectRoot),
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
for (const sub of subdirs) {
|
|
82
|
+
walkDirs(join(root, sub), projectRoot, category, maxDepth, results, depth + 1);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
export function discoverSourceDirs(projectRoot) {
|
|
86
|
+
const results = [];
|
|
87
|
+
const resolved = resolve(projectRoot);
|
|
88
|
+
let entries;
|
|
89
|
+
try {
|
|
90
|
+
entries = readdirSync(resolved);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// ENOENT or EACCES — skip inaccessible entries
|
|
94
|
+
return results;
|
|
95
|
+
}
|
|
96
|
+
for (const entry of entries) {
|
|
97
|
+
if (isSkipped(entry))
|
|
98
|
+
continue;
|
|
99
|
+
const fullPath = join(resolved, entry);
|
|
100
|
+
try {
|
|
101
|
+
const stat = lstatSync(fullPath);
|
|
102
|
+
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// ENOENT or EACCES — skip inaccessible entries
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (includes(SOURCE_ROOTS, entry)) {
|
|
110
|
+
walkDirs(fullPath, resolved, 'webapp', SOURCE_MAX_DEPTH, results);
|
|
111
|
+
}
|
|
112
|
+
else if (includes(SERVER_ROOTS, entry)) {
|
|
113
|
+
walkDirs(fullPath, resolved, 'server', SOURCE_MAX_DEPTH, results);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return results;
|
|
117
|
+
}
|
|
118
|
+
export function discoverTestDirs(projectRoot) {
|
|
119
|
+
const results = [];
|
|
120
|
+
const resolved = resolve(projectRoot);
|
|
121
|
+
function walk(dir, category, depth) {
|
|
122
|
+
if (depth > TEST_MAX_DEPTH || !existsSync(dir))
|
|
123
|
+
return;
|
|
124
|
+
let entries;
|
|
125
|
+
try {
|
|
126
|
+
entries = readdirSync(dir);
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// ENOENT or EACCES — skip inaccessible entries
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const hasTests = entries.some((e) => {
|
|
133
|
+
return TEST_EXTENSIONS.some((ext) => e.endsWith(ext)) || e.endsWith(GO_TEST_SUFFIX);
|
|
134
|
+
});
|
|
135
|
+
if (hasTests) {
|
|
136
|
+
results.push({
|
|
137
|
+
path: resolve(dir),
|
|
138
|
+
relativePath: relative(resolved, dir).replace(/\\/g, '/'),
|
|
139
|
+
category,
|
|
140
|
+
familyHint: extractFamilyHint(dir, resolved),
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
for (const entry of entries) {
|
|
144
|
+
if (isSkipped(entry))
|
|
145
|
+
continue;
|
|
146
|
+
const full = join(dir, entry);
|
|
147
|
+
try {
|
|
148
|
+
const stat = lstatSync(full);
|
|
149
|
+
if (stat.isSymbolicLink())
|
|
150
|
+
continue;
|
|
151
|
+
if (stat.isDirectory()) {
|
|
152
|
+
walk(full, category, depth + 1);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// ENOENT or EACCES — skip inaccessible entries
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const testRoots = ['tests', 'test', 'e2e-tests', 'e2e', 'specs', 'spec'];
|
|
161
|
+
const cypressRoots = ['cypress/e2e', 'cypress/integration'];
|
|
162
|
+
for (const root of testRoots) {
|
|
163
|
+
walk(join(resolved, root), 'test', 0);
|
|
164
|
+
}
|
|
165
|
+
for (const root of cypressRoots) {
|
|
166
|
+
walk(join(resolved, root), 'cypress', 0);
|
|
167
|
+
}
|
|
168
|
+
// Also scan server dirs for Go test files
|
|
169
|
+
for (const root of SERVER_ROOTS) {
|
|
170
|
+
const serverPath = join(resolved, root);
|
|
171
|
+
if (existsSync(serverPath)) {
|
|
172
|
+
walk(serverPath, 'test', 0);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return results;
|
|
176
|
+
}
|
|
177
|
+
function extractTags(specFiles) {
|
|
178
|
+
const tags = new Set();
|
|
179
|
+
for (const file of specFiles) {
|
|
180
|
+
try {
|
|
181
|
+
const content = readFileSync(file, 'utf-8');
|
|
182
|
+
const matches = content.match(/@[a-zA-Z][a-zA-Z0-9_-]*/g);
|
|
183
|
+
if (matches) {
|
|
184
|
+
for (const m of matches) {
|
|
185
|
+
if (!m.startsWith('@playwright') && !m.startsWith('@param') && !m.startsWith('@returns')) {
|
|
186
|
+
tags.add(m);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
// ENOENT or EACCES — skip unreadable files
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return Array.from(tags);
|
|
196
|
+
}
|
|
197
|
+
function getSpecFiles(dir, depth = 0) {
|
|
198
|
+
if (depth > SPEC_FILES_MAX_DEPTH)
|
|
199
|
+
return [];
|
|
200
|
+
const files = [];
|
|
201
|
+
try {
|
|
202
|
+
for (const entry of readdirSync(dir)) {
|
|
203
|
+
const full = join(dir, entry);
|
|
204
|
+
try {
|
|
205
|
+
const stat = lstatSync(full);
|
|
206
|
+
if (stat.isSymbolicLink())
|
|
207
|
+
continue;
|
|
208
|
+
if (stat.isDirectory()) {
|
|
209
|
+
files.push(...getSpecFiles(full, depth + 1));
|
|
210
|
+
}
|
|
211
|
+
else if (TEST_EXTENSIONS.some((ext) => entry.endsWith(ext))) {
|
|
212
|
+
files.push(full);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
// ENOENT or EACCES — skip inaccessible entries
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
// ENOENT or EACCES — skip inaccessible directories
|
|
222
|
+
}
|
|
223
|
+
return files;
|
|
224
|
+
}
|
|
225
|
+
function buildGlobPattern(relativePath) {
|
|
226
|
+
const normalized = relativePath.replace(/\\/g, '/');
|
|
227
|
+
return `${normalized}/*`;
|
|
228
|
+
}
|
|
229
|
+
function groupByFamily(dirs) {
|
|
230
|
+
const groups = new Map();
|
|
231
|
+
for (const dir of dirs) {
|
|
232
|
+
const key = normalizeId(dir.familyHint);
|
|
233
|
+
if (!groups.has(key)) {
|
|
234
|
+
groups.set(key, { webapp: [], server: [], test: [], cypress: [] });
|
|
235
|
+
}
|
|
236
|
+
const group = groups.get(key);
|
|
237
|
+
if (dir.category === 'webapp')
|
|
238
|
+
group.webapp.push(dir);
|
|
239
|
+
else if (dir.category === 'server')
|
|
240
|
+
group.server.push(dir);
|
|
241
|
+
else if (dir.category === 'cypress')
|
|
242
|
+
group.cypress.push(dir);
|
|
243
|
+
else
|
|
244
|
+
group.test.push(dir);
|
|
245
|
+
}
|
|
246
|
+
return groups;
|
|
247
|
+
}
|
|
248
|
+
function detectFeatures(familyId, group, projectRoot) {
|
|
249
|
+
const features = [];
|
|
250
|
+
const webappSubdirs = new Map();
|
|
251
|
+
for (const dir of group.webapp) {
|
|
252
|
+
try {
|
|
253
|
+
for (const entry of readdirSync(dir.path)) {
|
|
254
|
+
if (isSkipped(entry))
|
|
255
|
+
continue;
|
|
256
|
+
const full = join(dir.path, entry);
|
|
257
|
+
try {
|
|
258
|
+
const stat = lstatSync(full);
|
|
259
|
+
if (stat.isSymbolicLink())
|
|
260
|
+
continue;
|
|
261
|
+
if (stat.isDirectory()) {
|
|
262
|
+
const hint = normalizeId(entry);
|
|
263
|
+
if (!webappSubdirs.has(hint))
|
|
264
|
+
webappSubdirs.set(hint, []);
|
|
265
|
+
webappSubdirs.get(hint).push({
|
|
266
|
+
path: full,
|
|
267
|
+
relativePath: relative(projectRoot, full).replace(/\\/g, '/'),
|
|
268
|
+
category: 'webapp',
|
|
269
|
+
familyHint: entry,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
catch {
|
|
274
|
+
// ENOENT or EACCES — skip inaccessible entries
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
catch {
|
|
279
|
+
// ENOENT or EACCES — skip inaccessible directories
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
for (const testDir of group.test) {
|
|
283
|
+
try {
|
|
284
|
+
for (const entry of readdirSync(testDir.path)) {
|
|
285
|
+
if (isSkipped(entry))
|
|
286
|
+
continue;
|
|
287
|
+
const full = join(testDir.path, entry);
|
|
288
|
+
try {
|
|
289
|
+
const stat = lstatSync(full);
|
|
290
|
+
if (stat.isSymbolicLink())
|
|
291
|
+
continue;
|
|
292
|
+
if (!stat.isDirectory())
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
296
|
+
// ENOENT or EACCES — skip inaccessible entries
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
const hint = normalizeId(entry);
|
|
300
|
+
if (webappSubdirs.has(hint)) {
|
|
301
|
+
const webDirs = webappSubdirs.get(hint);
|
|
302
|
+
features.push({
|
|
303
|
+
id: `${familyId}/${hint}`,
|
|
304
|
+
webappPaths: webDirs.map((d) => buildGlobPattern(d.relativePath)),
|
|
305
|
+
serverPaths: [],
|
|
306
|
+
specDirs: [relative(projectRoot, full).replace(/\\/g, '/') + '/'],
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
catch {
|
|
312
|
+
// ENOENT or EACCES — skip inaccessible directories
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return features;
|
|
316
|
+
}
|
|
317
|
+
export function scanProject(projectRoot) {
|
|
318
|
+
const resolved = resolve(projectRoot);
|
|
319
|
+
const sourceDirs = discoverSourceDirs(resolved);
|
|
320
|
+
const testDirs = discoverTestDirs(resolved);
|
|
321
|
+
const allDirs = [...sourceDirs, ...testDirs];
|
|
322
|
+
const groups = groupByFamily(allDirs);
|
|
323
|
+
const families = [];
|
|
324
|
+
for (const [familyId, group] of groups) {
|
|
325
|
+
const hasSrc = group.webapp.length > 0 || group.server.length > 0;
|
|
326
|
+
const hasTests = group.test.length > 0 || group.cypress.length > 0;
|
|
327
|
+
if (!hasSrc && !hasTests)
|
|
328
|
+
continue;
|
|
329
|
+
const allSpecFiles = [];
|
|
330
|
+
for (const td of [...group.test, ...group.cypress]) {
|
|
331
|
+
allSpecFiles.push(...getSpecFiles(td.path));
|
|
332
|
+
}
|
|
333
|
+
const features = detectFeatures(familyId, group, resolved);
|
|
334
|
+
families.push({
|
|
335
|
+
id: familyId,
|
|
336
|
+
routes: [`/${familyId}`],
|
|
337
|
+
webappPaths: group.webapp.map((d) => buildGlobPattern(d.relativePath)),
|
|
338
|
+
serverPaths: group.server.map((d) => buildGlobPattern(d.relativePath)),
|
|
339
|
+
specDirs: group.test.map((d) => d.relativePath + '/'),
|
|
340
|
+
cypressSpecDirs: group.cypress.map((d) => d.relativePath + '/'),
|
|
341
|
+
tags: extractTags(allSpecFiles),
|
|
342
|
+
features,
|
|
343
|
+
routesGuessed: true,
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
const familyIds = new Set(families.map((f) => f.id));
|
|
347
|
+
const unmatchedSourceDirs = sourceDirs.filter((d) => !familyIds.has(normalizeId(d.familyHint)));
|
|
348
|
+
const unmatchedTestDirs = testDirs.filter((d) => !familyIds.has(normalizeId(d.familyHint)));
|
|
349
|
+
let totalSourceFiles = 0;
|
|
350
|
+
let totalTestFiles = 0;
|
|
351
|
+
for (const dir of sourceDirs) {
|
|
352
|
+
try {
|
|
353
|
+
totalSourceFiles += readdirSync(dir.path).filter((e) => {
|
|
354
|
+
try {
|
|
355
|
+
const stat = lstatSync(join(dir.path, e));
|
|
356
|
+
return !stat.isSymbolicLink() && !stat.isDirectory();
|
|
357
|
+
}
|
|
358
|
+
catch {
|
|
359
|
+
// ENOENT or EACCES — skip inaccessible entries
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
362
|
+
}).length;
|
|
363
|
+
}
|
|
364
|
+
catch {
|
|
365
|
+
// ENOENT or EACCES — skip inaccessible directories
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
for (const dir of testDirs) {
|
|
369
|
+
try {
|
|
370
|
+
totalTestFiles += getSpecFiles(dir.path).length;
|
|
371
|
+
}
|
|
372
|
+
catch {
|
|
373
|
+
// ENOENT or EACCES — skip inaccessible directories
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return {
|
|
377
|
+
families,
|
|
378
|
+
unmatchedSourceDirs,
|
|
379
|
+
unmatchedTestDirs,
|
|
380
|
+
stats: {
|
|
381
|
+
totalSourceFiles,
|
|
382
|
+
totalTestFiles,
|
|
383
|
+
familyCount: families.length,
|
|
384
|
+
},
|
|
385
|
+
};
|
|
386
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
/** Routes that look like bare "/<id>" are scanner-generated guesses */
|
|
4
|
+
export function isGuessedRoute(routes) {
|
|
5
|
+
return routes.every((r) => /^\/[a-z][a-z0-9_]*$/.test(r));
|
|
6
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
import { execFileSync } from 'child_process';
|
|
4
|
+
import { resolve } from 'path';
|
|
5
|
+
import { bindFilesToFamilies } from '../knowledge/route_families.js';
|
|
6
|
+
export function parseGitLog(log) {
|
|
7
|
+
const commits = [];
|
|
8
|
+
let current = null;
|
|
9
|
+
for (const line of log.split('\n')) {
|
|
10
|
+
const trimmed = line.trim();
|
|
11
|
+
if (!trimmed) {
|
|
12
|
+
if (current) {
|
|
13
|
+
commits.push(current);
|
|
14
|
+
current = null;
|
|
15
|
+
}
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
if (trimmed.includes('|') && /^[0-9a-f]{7,40}\|/.test(trimmed)) {
|
|
19
|
+
if (current) {
|
|
20
|
+
commits.push(current);
|
|
21
|
+
}
|
|
22
|
+
const [hash, ...rest] = trimmed.split('|');
|
|
23
|
+
current = { hash, message: rest.join('|'), files: [] };
|
|
24
|
+
}
|
|
25
|
+
else if (current) {
|
|
26
|
+
current.files.push(trimmed);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (current) {
|
|
30
|
+
commits.push(current);
|
|
31
|
+
}
|
|
32
|
+
return commits;
|
|
33
|
+
}
|
|
34
|
+
export function getCommitFiles(projectRoot, since) {
|
|
35
|
+
const resolved = resolve(projectRoot);
|
|
36
|
+
let log;
|
|
37
|
+
try {
|
|
38
|
+
log = execFileSync('git', ['log', '--name-only', '--pretty=format:%H|%s', `${since}..HEAD`], {
|
|
39
|
+
cwd: resolved,
|
|
40
|
+
encoding: 'utf-8',
|
|
41
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
42
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
console.warn(`[train] git log failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
return parseGitLog(log);
|
|
50
|
+
}
|
|
51
|
+
export function validateCommit(manifest, files, hash, message) {
|
|
52
|
+
// Filter out non-source files
|
|
53
|
+
const sourceFiles = files.filter((f) => {
|
|
54
|
+
return !f.endsWith('.md') && !f.endsWith('.json') && !f.endsWith('.yml') && !f.endsWith('.yaml') &&
|
|
55
|
+
!f.startsWith('.') && !f.includes('node_modules/');
|
|
56
|
+
});
|
|
57
|
+
if (sourceFiles.length === 0) {
|
|
58
|
+
return { hash, message, changedFiles: [], boundFiles: 0, unboundFiles: [], familiesHit: [] };
|
|
59
|
+
}
|
|
60
|
+
const bindings = bindFilesToFamilies(sourceFiles, manifest);
|
|
61
|
+
const bound = bindings.filter((b) => b.bindings.length > 0);
|
|
62
|
+
const unbound = bindings.filter((b) => b.bindings.length === 0);
|
|
63
|
+
const familiesHit = new Set();
|
|
64
|
+
for (const b of bound) {
|
|
65
|
+
for (const binding of b.bindings) {
|
|
66
|
+
familiesHit.add(binding.family);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
hash,
|
|
71
|
+
message,
|
|
72
|
+
changedFiles: sourceFiles,
|
|
73
|
+
boundFiles: bound.length,
|
|
74
|
+
unboundFiles: unbound.map((b) => b.file),
|
|
75
|
+
familiesHit: Array.from(familiesHit),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
export function buildValidationReport(commits, manifest) {
|
|
79
|
+
let totalFiles = 0;
|
|
80
|
+
let boundFiles = 0;
|
|
81
|
+
let unboundFiles = 0;
|
|
82
|
+
const familyHits = {};
|
|
83
|
+
const unboundCounts = {};
|
|
84
|
+
for (const commit of commits) {
|
|
85
|
+
totalFiles += commit.changedFiles.length;
|
|
86
|
+
boundFiles += commit.boundFiles;
|
|
87
|
+
unboundFiles += commit.unboundFiles.length;
|
|
88
|
+
for (const fam of commit.familiesHit) {
|
|
89
|
+
familyHits[fam] = (familyHits[fam] || 0) + 1;
|
|
90
|
+
}
|
|
91
|
+
for (const uf of commit.unboundFiles) {
|
|
92
|
+
unboundCounts[uf] = (unboundCounts[uf] || 0) + 1;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const allFamilyIds = manifest.families.map((f) => f.id);
|
|
96
|
+
const hitFamilyIds = new Set(Object.keys(familyHits));
|
|
97
|
+
const neverHitFamilies = allFamilyIds.filter((id) => !hitFamilyIds.has(id));
|
|
98
|
+
// Cluster unbound files by directory
|
|
99
|
+
const dirCounts = {};
|
|
100
|
+
for (const [file, count] of Object.entries(unboundCounts)) {
|
|
101
|
+
const dir = file.split('/').slice(0, -1).join('/');
|
|
102
|
+
dirCounts[dir] = (dirCounts[dir] || 0) + count;
|
|
103
|
+
}
|
|
104
|
+
const unboundFileClusters = Object.entries(dirCounts)
|
|
105
|
+
.sort(([, a], [, b]) => b - a)
|
|
106
|
+
.slice(0, 20)
|
|
107
|
+
.map(([pattern, count]) => ({
|
|
108
|
+
pattern: `${pattern}/*`,
|
|
109
|
+
count,
|
|
110
|
+
suggestedFamily: pattern.split('/').pop() || 'unknown',
|
|
111
|
+
}));
|
|
112
|
+
return {
|
|
113
|
+
totalCommits: commits.length,
|
|
114
|
+
totalFiles,
|
|
115
|
+
boundFiles,
|
|
116
|
+
unboundFiles,
|
|
117
|
+
coveragePercent: totalFiles > 0 ? Math.round((boundFiles / totalFiles) * 100) : 100,
|
|
118
|
+
commits,
|
|
119
|
+
familyHits,
|
|
120
|
+
neverHitFamilies,
|
|
121
|
+
unboundFileClusters,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
export function formatValidationReport(report) {
|
|
125
|
+
const lines = [];
|
|
126
|
+
lines.push(`Validated against ${report.totalCommits} commits`);
|
|
127
|
+
lines.push('');
|
|
128
|
+
lines.push(`Coverage: ${report.coveragePercent}% of files bound (${report.boundFiles}/${report.totalFiles})`);
|
|
129
|
+
lines.push('');
|
|
130
|
+
// Family hit distribution
|
|
131
|
+
const sorted = Object.entries(report.familyHits).sort(([, a], [, b]) => b - a);
|
|
132
|
+
if (sorted.length > 0) {
|
|
133
|
+
lines.push('Family hit distribution:');
|
|
134
|
+
const maxHits = sorted[0][1];
|
|
135
|
+
for (const [family, hits] of sorted) {
|
|
136
|
+
const bar = '\u2588'.repeat(Math.max(1, Math.round((hits / maxHits) * 12)));
|
|
137
|
+
lines.push(` ${family.padEnd(20)} ${bar} ${hits} commits`);
|
|
138
|
+
}
|
|
139
|
+
if (report.neverHitFamilies.length > 0) {
|
|
140
|
+
lines.push(` (never hit)${' '.repeat(8)}${report.neverHitFamilies.join(', ')}`);
|
|
141
|
+
}
|
|
142
|
+
lines.push('');
|
|
143
|
+
}
|
|
144
|
+
// Unbound file clusters
|
|
145
|
+
if (report.unboundFileClusters.length > 0) {
|
|
146
|
+
lines.push(`Unbound files (${report.unboundFiles} files across ${report.totalCommits} commits):`);
|
|
147
|
+
for (const cluster of report.unboundFileClusters.slice(0, 10)) {
|
|
148
|
+
lines.push(` ${cluster.pattern.padEnd(50)} — ${cluster.count} commits (suggest: ${cluster.suggestedFamily})`);
|
|
149
|
+
}
|
|
150
|
+
lines.push('');
|
|
151
|
+
}
|
|
152
|
+
return lines.join('\n');
|
|
153
|
+
}
|
|
@@ -93,3 +93,4 @@ export function computeOverallConfidence(decisions) {
|
|
|
93
93
|
const avgConfidence = actionable.reduce((sum, d) => sum + d.confidence, 0) / actionable.length;
|
|
94
94
|
return classifyConfidence(avgConfidence);
|
|
95
95
|
}
|
|
96
|
+
export { compileCheckSpec, smokeRunSpec } from '../pipeline/spec_verifier.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -24,8 +24,8 @@ export { analyzeImpact as analyzeImpactV2, getGaps, getPartialGaps } from './eng
|
|
|
24
24
|
export type { ImpactResult, ImpactedFeature, CoverageStatus, ImpactEngineOptions, SpecWithScenarios } from './engine/impact_engine.js';
|
|
25
25
|
export { extractScenarios } from './engine/impact_engine.js';
|
|
26
26
|
export { buildPlanFromImpact } from './engine/plan_builder.js';
|
|
27
|
-
export { appendFeedbackAndRecompute, readCalibration, readFlakyTests } from './agent/feedback.js';
|
|
28
|
-
export type { RecommendationFeedbackEntry, CalibrationSummary, FlakySummary } from './agent/feedback.js';
|
|
27
|
+
export { appendFeedbackAndRecompute, readCalibration, readFlakyTests, getAdaptiveThresholds } from './agent/feedback.js';
|
|
28
|
+
export type { RecommendationFeedbackEntry, CalibrationSummary, FlakySummary, AdaptiveThresholds } from './agent/feedback.js';
|
|
29
29
|
export { finalizeGeneratedTests } from './agent/handoff.js';
|
|
30
30
|
export type { FinalizeGeneratedTestsOptions, FinalizeGeneratedTestsResult } from './agent/handoff.js';
|
|
31
31
|
export { ingestTraceabilityInput } from './agent/traceability_ingest.js';
|
|
@@ -54,4 +54,9 @@ export type { PlanReport } from './agent/plan.js';
|
|
|
54
54
|
export { runAgenticGeneration } from './agentic/runner.js';
|
|
55
55
|
export type { ScenarioInput, AgenticRunOptions } from './agentic/runner.js';
|
|
56
56
|
export type { AgenticConfig, AgenticResult, AgenticSummary, PlaywrightRunResult, TestFailure } from './agentic/types.js';
|
|
57
|
+
export { scanProject } from './training/scanner.js';
|
|
58
|
+
export { mergeFamilies, detectStaleFamilies } from './training/merger.js';
|
|
59
|
+
export { enrichFamilies } from './training/enricher.js';
|
|
60
|
+
export { getCommitFiles, validateCommit, buildValidationReport, formatValidationReport } from './training/validator.js';
|
|
61
|
+
export type { ScanResult, ScannedFamily, ScannedFeature, DiscoveredDir, EnrichmentResult, ValidationReport, CommitValidation, MergeResult, TrainOptions, } from './training/types.js';
|
|
57
62
|
//# 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,0BAA0B,EAAE,2BAA2B,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,mBAAmB,EAAC,MAAM,UAAU,CAAC;AACjJ,YAAY,EACR,eAAe,EACf,sBAAsB,EACtB,4BAA4B,EAC5B,6BAA6B,GAChC,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAC,aAAa,IAAI,eAAe,EAAE,OAAO,EAAE,cAAc,EAAC,MAAM,2BAA2B,CAAC;AACpG,YAAY,EAAC,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,mBAAmB,EAAE,iBAAiB,EAAC,MAAM,2BAA2B,CAAC;AACrI,OAAO,EAAC,gBAAgB,EAAC,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAC,mBAAmB,EAAC,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAC,0BAA0B,EAAE,eAAe,EAAE,cAAc,EAAC,MAAM,qBAAqB,CAAC;
|
|
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,0BAA0B,EAAE,2BAA2B,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,mBAAmB,EAAC,MAAM,UAAU,CAAC;AACjJ,YAAY,EACR,eAAe,EACf,sBAAsB,EACtB,4BAA4B,EAC5B,6BAA6B,GAChC,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAC,aAAa,IAAI,eAAe,EAAE,OAAO,EAAE,cAAc,EAAC,MAAM,2BAA2B,CAAC;AACpG,YAAY,EAAC,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,mBAAmB,EAAE,iBAAiB,EAAC,MAAM,2BAA2B,CAAC;AACrI,OAAO,EAAC,gBAAgB,EAAC,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAC,mBAAmB,EAAC,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAC,0BAA0B,EAAE,eAAe,EAAE,cAAc,EAAE,qBAAqB,EAAC,MAAM,qBAAqB,CAAC;AACvH,YAAY,EAAC,2BAA2B,EAAE,kBAAkB,EAAE,YAAY,EAAE,kBAAkB,EAAC,MAAM,qBAAqB,CAAC;AAC3H,OAAO,EAAC,sBAAsB,EAAC,MAAM,oBAAoB,CAAC;AAC1D,YAAY,EAAC,6BAA6B,EAAE,4BAA4B,EAAC,MAAM,oBAAoB,CAAC;AACpG,OAAO,EAAC,uBAAuB,EAAC,MAAM,gCAAgC,CAAC;AACvE,YAAY,EAAC,yBAAyB,EAAE,wBAAwB,EAAE,uBAAuB,EAAC,MAAM,gCAAgC,CAAC;AACjI,OAAO,EAAC,wBAAwB,EAAC,MAAM,iCAAiC,CAAC;AACzE,YAAY,EAAC,0BAA0B,EAAE,yBAAyB,EAAC,MAAM,iCAAiC,CAAC;AAG3G,OAAO,EAAC,WAAW,EAAC,MAAM,4BAA4B,CAAC;AACvD,YAAY,EAAC,cAAc,EAAE,cAAc,EAAC,MAAM,4BAA4B,CAAC;AAC/E,YAAY,EAAC,YAAY,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,UAAU,EAAE,cAAc,EAAC,MAAM,+BAA+B,CAAC;AACrI,OAAO,EAAC,kBAAkB,EAAC,MAAM,iCAAiC,CAAC;AACnE,YAAY,EAAC,gBAAgB,EAAE,gBAAgB,EAAE,aAAa,EAAC,MAAM,iCAAiC,CAAC;AACvG,OAAO,EAAC,qBAAqB,EAAE,uBAAuB,EAAE,yBAAyB,EAAC,MAAM,yBAAyB,CAAC;AAClH,YAAY,EAAC,uBAAuB,EAAE,uBAAuB,EAAC,MAAM,yBAAyB,CAAC;AAC9F,OAAO,EAAC,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,kBAAkB,EAAC,MAAM,2BAA2B,CAAC;AAC/G,YAAY,EAAC,UAAU,EAAE,UAAU,EAAE,UAAU,EAAC,MAAM,2BAA2B,CAAC;AAClF,OAAO,EAAC,eAAe,EAAE,qBAAqB,EAAC,MAAM,mBAAmB,CAAC;AACzE,YAAY,EAAC,iBAAiB,EAAC,MAAM,mBAAmB,CAAC;AAGzD,OAAO,EAAC,uBAAuB,EAAE,mBAAmB,EAAE,4BAA4B,EAAE,qBAAqB,EAAE,sBAAsB,EAAC,MAAM,+BAA+B,CAAC;AACxK,YAAY,EAAC,WAAW,EAAE,YAAY,EAAE,mBAAmB,EAAE,WAAW,EAAE,eAAe,EAAC,MAAM,+BAA+B,CAAC;AAChI,OAAO,EAAC,eAAe,EAAE,qBAAqB,EAAC,MAAM,4BAA4B,CAAC;AAClF,YAAY,EAAC,iBAAiB,EAAE,iBAAiB,EAAC,MAAM,4BAA4B,CAAC;AACrF,OAAO,EAAC,cAAc,EAAE,iBAAiB,EAAC,MAAM,2BAA2B,CAAC;AAC5E,YAAY,EAAC,SAAS,EAAE,SAAS,EAAC,MAAM,2BAA2B,CAAC;AAGpE,YAAY,EAAC,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAC,MAAM,kBAAkB,CAAC;AACnG,YAAY,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAC;AAGhD,OAAO,EAAC,oBAAoB,EAAC,MAAM,qBAAqB,CAAC;AACzD,YAAY,EAAC,aAAa,EAAE,iBAAiB,EAAC,MAAM,qBAAqB,CAAC;AAC1E,YAAY,EAAC,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,mBAAmB,EAAE,WAAW,EAAC,MAAM,oBAAoB,CAAC;AAGvH,OAAO,EAAC,WAAW,EAAC,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAC,aAAa,EAAE,mBAAmB,EAAC,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAC,cAAc,EAAC,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAC,cAAc,EAAE,cAAc,EAAE,qBAAqB,EAAE,sBAAsB,EAAC,MAAM,yBAAyB,CAAC;AACtH,YAAY,EACR,UAAU,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EACxD,gBAAgB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,WAAW,EAAE,YAAY,GAClF,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
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.runAgenticGeneration = 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.readFlakyTests = exports.readCalibration = exports.appendFeedbackAndRecompute = exports.buildPlanFromImpact = exports.extractScenarios = 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;
|
|
5
|
+
exports.scanProject = exports.runAgenticGeneration = 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.getAdaptiveThresholds = exports.readFlakyTests = exports.readCalibration = exports.appendFeedbackAndRecompute = exports.buildPlanFromImpact = exports.extractScenarios = 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
|
+
exports.formatValidationReport = exports.buildValidationReport = exports.validateCommit = exports.getCommitFiles = exports.enrichFamilies = exports.detectStaleFamilies = exports.mergeFamilies = void 0;
|
|
6
7
|
var provider_interface_js_1 = require("./provider_interface.js");
|
|
7
8
|
Object.defineProperty(exports, "LLMProviderError", { enumerable: true, get: function () { return provider_interface_js_1.LLMProviderError; } });
|
|
8
9
|
Object.defineProperty(exports, "UnsupportedCapabilityError", { enumerable: true, get: function () { return provider_interface_js_1.UnsupportedCapabilityError; } });
|
|
@@ -42,6 +43,7 @@ var feedback_js_1 = require("./agent/feedback.js");
|
|
|
42
43
|
Object.defineProperty(exports, "appendFeedbackAndRecompute", { enumerable: true, get: function () { return feedback_js_1.appendFeedbackAndRecompute; } });
|
|
43
44
|
Object.defineProperty(exports, "readCalibration", { enumerable: true, get: function () { return feedback_js_1.readCalibration; } });
|
|
44
45
|
Object.defineProperty(exports, "readFlakyTests", { enumerable: true, get: function () { return feedback_js_1.readFlakyTests; } });
|
|
46
|
+
Object.defineProperty(exports, "getAdaptiveThresholds", { enumerable: true, get: function () { return feedback_js_1.getAdaptiveThresholds; } });
|
|
45
47
|
var handoff_js_1 = require("./agent/handoff.js");
|
|
46
48
|
Object.defineProperty(exports, "finalizeGeneratedTests", { enumerable: true, get: function () { return handoff_js_1.finalizeGeneratedTests; } });
|
|
47
49
|
var traceability_ingest_js_1 = require("./agent/traceability_ingest.js");
|
|
@@ -81,3 +83,16 @@ Object.defineProperty(exports, "getSpecsForFamily", { enumerable: true, get: fun
|
|
|
81
83
|
// Agentic generation
|
|
82
84
|
var runner_js_1 = require("./agentic/runner.js");
|
|
83
85
|
Object.defineProperty(exports, "runAgenticGeneration", { enumerable: true, get: function () { return runner_js_1.runAgenticGeneration; } });
|
|
86
|
+
// Training (route-families bootstrap and maintenance)
|
|
87
|
+
var scanner_js_1 = require("./training/scanner.js");
|
|
88
|
+
Object.defineProperty(exports, "scanProject", { enumerable: true, get: function () { return scanner_js_1.scanProject; } });
|
|
89
|
+
var merger_js_1 = require("./training/merger.js");
|
|
90
|
+
Object.defineProperty(exports, "mergeFamilies", { enumerable: true, get: function () { return merger_js_1.mergeFamilies; } });
|
|
91
|
+
Object.defineProperty(exports, "detectStaleFamilies", { enumerable: true, get: function () { return merger_js_1.detectStaleFamilies; } });
|
|
92
|
+
var enricher_js_1 = require("./training/enricher.js");
|
|
93
|
+
Object.defineProperty(exports, "enrichFamilies", { enumerable: true, get: function () { return enricher_js_1.enrichFamilies; } });
|
|
94
|
+
var validator_js_1 = require("./training/validator.js");
|
|
95
|
+
Object.defineProperty(exports, "getCommitFiles", { enumerable: true, get: function () { return validator_js_1.getCommitFiles; } });
|
|
96
|
+
Object.defineProperty(exports, "validateCommit", { enumerable: true, get: function () { return validator_js_1.validateCommit; } });
|
|
97
|
+
Object.defineProperty(exports, "buildValidationReport", { enumerable: true, get: function () { return validator_js_1.buildValidationReport; } });
|
|
98
|
+
Object.defineProperty(exports, "formatValidationReport", { enumerable: true, get: function () { return validator_js_1.formatValidationReport; } });
|
|
@@ -39,6 +39,8 @@ export interface RouteFamilyConfig {
|
|
|
39
39
|
manifestPath?: string;
|
|
40
40
|
strict?: boolean;
|
|
41
41
|
}
|
|
42
|
+
export declare function matchesGlob(filePath: string, pattern: string): boolean;
|
|
43
|
+
export declare function matchesAnyPattern(filePath: string, patterns: string[]): boolean;
|
|
42
44
|
export declare function loadRouteFamilyManifest(testsRoot: string, config?: RouteFamilyConfig): RouteFamilyManifest | null;
|
|
43
45
|
export declare function bindFilesToFamilies(changedFiles: string[], manifest: RouteFamilyManifest): FileBinding[];
|
|
44
46
|
export declare function getFamilyById(manifest: RouteFamilyManifest, familyId: string): RouteFamily | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route_families.d.ts","sourceRoot":"","sources":["../../src/knowledge/route_families.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEjD,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,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,mBAAmB;IAChC,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;CACvD;AAED,MAAM,WAAW,iBAAiB;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;CACpB;AA+
|
|
1
|
+
{"version":3,"file":"route_families.d.ts","sourceRoot":"","sources":["../../src/knowledge/route_families.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,8 @@
|
|
|
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.matchesGlob = matchesGlob;
|
|
6
|
+
exports.matchesAnyPattern = matchesAnyPattern;
|
|
5
7
|
exports.loadRouteFamilyManifest = loadRouteFamilyManifest;
|
|
6
8
|
exports.bindFilesToFamilies = bindFilesToFamilies;
|
|
7
9
|
exports.getFamilyById = getFamilyById;
|