@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.
Files changed (93) hide show
  1. package/README.md +40 -9
  2. package/dist/agent/feedback.d.ts +16 -0
  3. package/dist/agent/feedback.d.ts.map +1 -1
  4. package/dist/agent/feedback.js +62 -0
  5. package/dist/agent/process_runner.d.ts +1 -1
  6. package/dist/agent/process_runner.d.ts.map +1 -1
  7. package/dist/agent/process_runner.js +3 -3
  8. package/dist/api.d.ts.map +1 -1
  9. package/dist/api.js +5 -2
  10. package/dist/cli/commands/train.d.ts +3 -0
  11. package/dist/cli/commands/train.d.ts.map +1 -0
  12. package/dist/cli/commands/train.js +307 -0
  13. package/dist/cli/parse_args.d.ts.map +1 -1
  14. package/dist/cli/parse_args.js +7 -1
  15. package/dist/cli/types.d.ts +6 -1
  16. package/dist/cli/types.d.ts.map +1 -1
  17. package/dist/cli/usage.d.ts.map +1 -1
  18. package/dist/cli/usage.js +7 -1
  19. package/dist/cli.js +5 -0
  20. package/dist/engine/plan_builder.d.ts +2 -1
  21. package/dist/engine/plan_builder.d.ts.map +1 -1
  22. package/dist/engine/plan_builder.js +22 -9
  23. package/dist/esm/agent/feedback.js +61 -0
  24. package/dist/esm/agent/process_runner.js +3 -3
  25. package/dist/esm/api.js +5 -2
  26. package/dist/esm/cli/commands/train.js +271 -0
  27. package/dist/esm/cli/parse_args.js +7 -1
  28. package/dist/esm/cli/usage.js +7 -1
  29. package/dist/esm/cli.js +5 -0
  30. package/dist/esm/engine/plan_builder.js +22 -9
  31. package/dist/esm/index.js +6 -1
  32. package/dist/esm/knowledge/route_families.js +2 -2
  33. package/dist/esm/pipeline/spec_verifier.js +75 -0
  34. package/dist/esm/pipeline/stage3_generation.js +122 -4
  35. package/dist/esm/pipeline/stage4_heal.js +146 -3
  36. package/dist/esm/prompts/heal.js +4 -0
  37. package/dist/esm/qa-agent/phase2/agent_loop.js +60 -24
  38. package/dist/esm/qa-agent/phase2/exploration_state.js +21 -0
  39. package/dist/esm/qa-agent/phase2/tools.js +99 -1
  40. package/dist/esm/qa-agent/phase3/reporter.js +31 -4
  41. package/dist/esm/training/enricher.js +273 -0
  42. package/dist/esm/training/merger.js +137 -0
  43. package/dist/esm/training/scanner.js +386 -0
  44. package/dist/esm/training/types.js +6 -0
  45. package/dist/esm/training/validator.js +153 -0
  46. package/dist/esm/validation/guardrails.js +1 -0
  47. package/dist/index.d.ts +7 -2
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +16 -1
  50. package/dist/knowledge/route_families.d.ts +2 -0
  51. package/dist/knowledge/route_families.d.ts.map +1 -1
  52. package/dist/knowledge/route_families.js +2 -0
  53. package/dist/pipeline/orchestrator.d.ts.map +1 -1
  54. package/dist/pipeline/spec_verifier.d.ts +20 -0
  55. package/dist/pipeline/spec_verifier.d.ts.map +1 -0
  56. package/dist/pipeline/spec_verifier.js +79 -0
  57. package/dist/pipeline/stage3_generation.d.ts +10 -0
  58. package/dist/pipeline/stage3_generation.d.ts.map +1 -1
  59. package/dist/pipeline/stage3_generation.js +120 -2
  60. package/dist/pipeline/stage4_heal.d.ts +4 -0
  61. package/dist/pipeline/stage4_heal.d.ts.map +1 -1
  62. package/dist/pipeline/stage4_heal.js +145 -2
  63. package/dist/prompts/heal.d.ts +2 -0
  64. package/dist/prompts/heal.d.ts.map +1 -1
  65. package/dist/prompts/heal.js +4 -0
  66. package/dist/qa-agent/phase2/agent_loop.d.ts.map +1 -1
  67. package/dist/qa-agent/phase2/agent_loop.js +60 -24
  68. package/dist/qa-agent/phase2/exploration_state.d.ts.map +1 -1
  69. package/dist/qa-agent/phase2/exploration_state.js +21 -0
  70. package/dist/qa-agent/phase2/tools.d.ts.map +1 -1
  71. package/dist/qa-agent/phase2/tools.js +99 -1
  72. package/dist/qa-agent/phase3/reporter.js +31 -4
  73. package/dist/qa-agent/types.d.ts +9 -1
  74. package/dist/qa-agent/types.d.ts.map +1 -1
  75. package/dist/training/enricher.d.ts +15 -0
  76. package/dist/training/enricher.d.ts.map +1 -0
  77. package/dist/training/enricher.js +278 -0
  78. package/dist/training/merger.d.ts +5 -0
  79. package/dist/training/merger.d.ts.map +1 -0
  80. package/dist/training/merger.js +141 -0
  81. package/dist/training/scanner.d.ts +5 -0
  82. package/dist/training/scanner.d.ts.map +1 -0
  83. package/dist/training/scanner.js +391 -0
  84. package/dist/training/types.d.ts +109 -0
  85. package/dist/training/types.d.ts.map +1 -0
  86. package/dist/training/types.js +9 -0
  87. package/dist/training/validator.d.ts +16 -0
  88. package/dist/training/validator.d.ts.map +1 -0
  89. package/dist/training/validator.js +160 -0
  90. package/dist/validation/guardrails.d.ts +2 -0
  91. package/dist/validation/guardrails.d.ts.map +1 -1
  92. package/dist/validation/guardrails.js +4 -1
  93. 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
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
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,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":"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"}
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;