@yasserkhanorg/e2e-agents 1.6.0 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/train.d.ts.map +1 -1
- package/dist/cli/commands/train.js +112 -50
- package/dist/cli/parse_args.d.ts.map +1 -1
- package/dist/cli/parse_args.js +2 -0
- package/dist/cli/types.d.ts +2 -0
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/esm/cli/commands/train.js +112 -50
- package/dist/esm/cli/parse_args.js +2 -0
- package/dist/esm/knowledge/route_families.js +3 -0
- package/dist/esm/logger.js +29 -2
- package/dist/esm/pipeline/orchestrator.js +17 -3
- package/dist/esm/training/enricher.js +11 -4
- package/dist/esm/training/scanner.js +190 -12
- package/dist/esm/training/validator.js +101 -4
- package/dist/knowledge/route_families.d.ts.map +1 -1
- package/dist/knowledge/route_families.js +3 -0
- package/dist/logger.d.ts +9 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +29 -2
- package/dist/pipeline/orchestrator.d.ts.map +1 -1
- package/dist/pipeline/orchestrator.js +17 -3
- package/dist/training/enricher.d.ts.map +1 -1
- package/dist/training/enricher.js +11 -4
- package/dist/training/scanner.d.ts +15 -2
- package/dist/training/scanner.d.ts.map +1 -1
- package/dist/training/scanner.js +192 -12
- package/dist/training/types.d.ts +4 -0
- package/dist/training/types.d.ts.map +1 -1
- package/dist/training/validator.d.ts +6 -1
- package/dist/training/validator.d.ts.map +1 -1
- package/dist/training/validator.js +102 -4
- package/package.json +1 -1
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
4
4
|
import { join } from 'path';
|
|
5
5
|
import { getChangedFiles } from '../agent/git.js';
|
|
6
|
+
import { logger } from '../logger.js';
|
|
6
7
|
import { preprocess } from './stage0_preprocess.js';
|
|
7
8
|
import { runImpactStage } from './stage1_impact.js';
|
|
8
9
|
import { runCoverageStage } from './stage2_coverage.js';
|
|
@@ -58,20 +59,25 @@ export async function runPipeline(config) {
|
|
|
58
59
|
const reportPath = writeReport(config.testsRoot, emptyReport);
|
|
59
60
|
return { report: emptyReport, reportPath, warnings: allWarnings };
|
|
60
61
|
}
|
|
62
|
+
const timings = {};
|
|
61
63
|
// Step 2: Preprocess — deterministic file classification + route family binding
|
|
64
|
+
const preprocessTimer = logger.timer('preprocess');
|
|
62
65
|
const preprocessResult = preprocess(changedFiles, {
|
|
63
66
|
appPath: config.appPath,
|
|
64
67
|
testsRoot: config.testsRoot,
|
|
65
68
|
routeFamilies: config.routeFamilies,
|
|
66
69
|
apiSurface: config.apiSurface,
|
|
67
70
|
});
|
|
71
|
+
timings.preprocess = preprocessTimer.end();
|
|
68
72
|
allWarnings.push(...preprocessResult.warnings);
|
|
69
73
|
let decisions = [];
|
|
70
74
|
// Step 3: Impact stage — AI-powered flow identification per family
|
|
71
75
|
if (stages.includes('impact')) {
|
|
76
|
+
const impactTimer = logger.timer('impact');
|
|
72
77
|
const impactResult = await runImpactStage(preprocessResult.familyGroups, preprocessResult.manifest, preprocessResult.specIndex, preprocessResult.apiSurface, preprocessResult.context, config.impact || {});
|
|
73
78
|
decisions = impactResult.decisions;
|
|
74
79
|
allWarnings.push(...impactResult.warnings);
|
|
80
|
+
timings.impact = impactTimer.end();
|
|
75
81
|
// Check cannot_determine ratio
|
|
76
82
|
const cannotDetermineRatio = computeCannotDetermineRatio(decisions);
|
|
77
83
|
if (cannotDetermineRatio > 0.3) {
|
|
@@ -80,18 +86,23 @@ export async function runPipeline(config) {
|
|
|
80
86
|
}
|
|
81
87
|
// Step 4: Coverage stage — AI-powered spec coverage evaluation
|
|
82
88
|
if (stages.includes('coverage') && decisions.length > 0) {
|
|
89
|
+
const coverageTimer = logger.timer('coverage');
|
|
83
90
|
const coverageResult = await runCoverageStage(decisions, preprocessResult.specIndex, preprocessResult.context, config.testsRoot, config.coverage || {});
|
|
84
91
|
decisions = coverageResult.decisions;
|
|
92
|
+
timings.coverage = coverageTimer.end();
|
|
85
93
|
allWarnings.push(...coverageResult.warnings);
|
|
86
94
|
}
|
|
87
95
|
// Step 5: Generation stage — AI-powered spec generation for create_spec / add_scenarios
|
|
88
96
|
if (stages.includes('generation') && decisions.length > 0) {
|
|
97
|
+
const generationTimer = logger.timer('generation');
|
|
89
98
|
const generationResult = await runGenerationStage(decisions, preprocessResult.apiSurface, config.testsRoot, config.generation || {});
|
|
90
99
|
generatedSpecs = generationResult.generated;
|
|
100
|
+
timings.generation = generationTimer.end();
|
|
91
101
|
allWarnings.push(...generationResult.warnings);
|
|
92
102
|
}
|
|
93
103
|
// Step 6: Heal stage — MCP-backed playwright-test-healer for failing/flaky specs
|
|
94
104
|
if (stages.includes('heal')) {
|
|
105
|
+
const healTimer = logger.timer('heal');
|
|
95
106
|
const healTargets = resolveHealTargets(config.testsRoot, {
|
|
96
107
|
playwrightReportPath: config.playwrightReportPath,
|
|
97
108
|
generatedSpecs,
|
|
@@ -103,6 +114,7 @@ export async function runPipeline(config) {
|
|
|
103
114
|
else {
|
|
104
115
|
allWarnings.push('Heal stage: no targets found (no failing specs in report, no generated specs).');
|
|
105
116
|
}
|
|
117
|
+
timings.heal = healTimer.end();
|
|
106
118
|
}
|
|
107
119
|
// Build report
|
|
108
120
|
const report = {
|
|
@@ -118,16 +130,18 @@ export async function runPipeline(config) {
|
|
|
118
130
|
generationAgent: stages.includes('generation') ? (config.generation?.provider || 'auto') : undefined,
|
|
119
131
|
},
|
|
120
132
|
};
|
|
121
|
-
const reportPath = writeReport(config.testsRoot, report, healResult);
|
|
133
|
+
const reportPath = writeReport(config.testsRoot, report, healResult, timings);
|
|
122
134
|
return { report, reportPath, warnings: allWarnings, generated: generatedSpecs, healResult };
|
|
123
135
|
}
|
|
124
|
-
function writeReport(testsRoot, report, healResult) {
|
|
136
|
+
function writeReport(testsRoot, report, healResult, timings) {
|
|
125
137
|
const outputDir = join(testsRoot, '.e2e-ai-agents');
|
|
126
138
|
if (!existsSync(outputDir)) {
|
|
127
139
|
mkdirSync(outputDir, { recursive: true });
|
|
128
140
|
}
|
|
141
|
+
// Include timings in the JSON report if available
|
|
142
|
+
const reportWithTimings = timings ? { ...report, timings } : report;
|
|
129
143
|
const jsonPath = join(outputDir, 'pipeline-report.json');
|
|
130
|
-
writeFileSync(jsonPath, JSON.stringify(
|
|
144
|
+
writeFileSync(jsonPath, JSON.stringify(reportWithTimings, null, 2), 'utf-8');
|
|
131
145
|
const mdPath = join(outputDir, 'pipeline-report.md');
|
|
132
146
|
writeFileSync(mdPath, renderMarkdown(report, healResult), 'utf-8');
|
|
133
147
|
return jsonPath;
|
|
@@ -263,6 +263,8 @@ export async function enrichFamilies(families, scanned, projectRoot, provider, b
|
|
|
263
263
|
const enriched = [];
|
|
264
264
|
let totalTokens = 0;
|
|
265
265
|
let totalCost = 0;
|
|
266
|
+
let requestCount = 0;
|
|
267
|
+
let totalResponseMs = 0;
|
|
266
268
|
const skipped = [];
|
|
267
269
|
// Process in chunks of 4 families
|
|
268
270
|
const chunkSize = 4;
|
|
@@ -295,15 +297,18 @@ export async function enrichFamilies(families, scanned, projectRoot, provider, b
|
|
|
295
297
|
prompt = prompt.slice(0, MAX_PROMPT_CHARS);
|
|
296
298
|
}
|
|
297
299
|
}
|
|
298
|
-
let
|
|
300
|
+
let timeoutTimer;
|
|
299
301
|
try {
|
|
300
302
|
const timeoutPromise = new Promise((_, reject) => {
|
|
301
|
-
|
|
303
|
+
timeoutTimer = setTimeout(() => reject(new Error('LLM request timed out')), LLM_TIMEOUT_MS);
|
|
302
304
|
});
|
|
305
|
+
const reqStart = performance.now();
|
|
303
306
|
const response = await Promise.race([
|
|
304
307
|
provider.generateText(prompt, { maxTokens: 4096, temperature: 0.3 }),
|
|
305
308
|
timeoutPromise,
|
|
306
309
|
]);
|
|
310
|
+
totalResponseMs += performance.now() - reqStart;
|
|
311
|
+
requestCount++;
|
|
307
312
|
totalTokens += (response.usage?.inputTokens ?? 0) + (response.usage?.outputTokens ?? 0);
|
|
308
313
|
totalCost += response.cost ?? 0;
|
|
309
314
|
const entries = parseEnrichResponse(response.text);
|
|
@@ -324,8 +329,8 @@ export async function enrichFamilies(families, scanned, projectRoot, provider, b
|
|
|
324
329
|
enriched.push(...chunk);
|
|
325
330
|
}
|
|
326
331
|
finally {
|
|
327
|
-
if (
|
|
328
|
-
clearTimeout(
|
|
332
|
+
if (timeoutTimer)
|
|
333
|
+
clearTimeout(timeoutTimer);
|
|
329
334
|
}
|
|
330
335
|
}
|
|
331
336
|
return {
|
|
@@ -333,5 +338,7 @@ export async function enrichFamilies(families, scanned, projectRoot, provider, b
|
|
|
333
338
|
tokensUsed: totalTokens,
|
|
334
339
|
costUSD: Math.round(totalCost * 100) / 100,
|
|
335
340
|
skippedFamilies: skipped,
|
|
341
|
+
requestCount,
|
|
342
|
+
avgResponseMs: requestCount > 0 ? Math.round(totalResponseMs / requestCount) : 0,
|
|
336
343
|
};
|
|
337
344
|
}
|
|
@@ -513,15 +513,15 @@ export function discoverServerDerivedFamilies(serverRoot) {
|
|
|
513
513
|
}
|
|
514
514
|
}
|
|
515
515
|
// Build families from grouped domains.
|
|
516
|
-
//
|
|
517
|
-
|
|
516
|
+
// Multi-tier families (≥2 tiers) can be new families.
|
|
517
|
+
// Single-tier families can only merge into existing families.
|
|
518
|
+
const multiTierFamilies = [];
|
|
519
|
+
const singleTierFamilies = [];
|
|
518
520
|
for (const [domain, paths] of familyPaths) {
|
|
519
521
|
if (paths.size === 0)
|
|
520
522
|
continue;
|
|
521
523
|
const tierCount = familyTiers.get(domain)?.size ?? 0;
|
|
522
|
-
|
|
523
|
-
continue; // Skip single-tier domains (likely infrastructure)
|
|
524
|
-
families.push({
|
|
524
|
+
const family = {
|
|
525
525
|
id: domain,
|
|
526
526
|
routes: [`/${domain.replace(/_/g, '-')}`],
|
|
527
527
|
webappPaths: [],
|
|
@@ -531,9 +531,15 @@ export function discoverServerDerivedFamilies(serverRoot) {
|
|
|
531
531
|
tags: [],
|
|
532
532
|
features: [],
|
|
533
533
|
routesGuessed: true,
|
|
534
|
-
}
|
|
534
|
+
};
|
|
535
|
+
if (tierCount >= 2) {
|
|
536
|
+
multiTierFamilies.push(family);
|
|
537
|
+
}
|
|
538
|
+
else {
|
|
539
|
+
singleTierFamilies.push(family);
|
|
540
|
+
}
|
|
535
541
|
}
|
|
536
|
-
return
|
|
542
|
+
return { multiTierFamilies, singleTierFamilies };
|
|
537
543
|
}
|
|
538
544
|
export function discoverTestDerivedFamilies(testsRoot) {
|
|
539
545
|
const resolved = resolve(testsRoot);
|
|
@@ -620,7 +626,136 @@ export function discoverTestDerivedFamilies(testsRoot) {
|
|
|
620
626
|
}
|
|
621
627
|
return Array.from(familyMap.values());
|
|
622
628
|
}
|
|
623
|
-
|
|
629
|
+
/**
|
|
630
|
+
* Discover test library paths (page objects, helpers) organized by feature.
|
|
631
|
+
* Walks well-known test lib directories and maps subdirectories and files to family IDs.
|
|
632
|
+
*/
|
|
633
|
+
export function discoverTestLibPaths(testsRoot) {
|
|
634
|
+
const resolved = resolve(testsRoot);
|
|
635
|
+
const result = new Map();
|
|
636
|
+
const libDirs = [
|
|
637
|
+
'lib/src/ui/components',
|
|
638
|
+
'lib/src/ui/pages',
|
|
639
|
+
'lib/src/server',
|
|
640
|
+
];
|
|
641
|
+
for (const libDir of libDirs) {
|
|
642
|
+
const fullDir = join(resolved, libDir);
|
|
643
|
+
if (!existsSync(fullDir))
|
|
644
|
+
continue;
|
|
645
|
+
let entries;
|
|
646
|
+
try {
|
|
647
|
+
entries = readdirSync(fullDir);
|
|
648
|
+
}
|
|
649
|
+
catch {
|
|
650
|
+
continue;
|
|
651
|
+
}
|
|
652
|
+
for (const entry of entries) {
|
|
653
|
+
if (isSkipped(entry))
|
|
654
|
+
continue;
|
|
655
|
+
const fullPath = join(fullDir, entry);
|
|
656
|
+
try {
|
|
657
|
+
const stat = lstatSync(fullPath);
|
|
658
|
+
if (stat.isSymbolicLink())
|
|
659
|
+
continue;
|
|
660
|
+
if (stat.isDirectory()) {
|
|
661
|
+
// Subdirectory → family ID from dir name
|
|
662
|
+
const familyId = normalizeId(entry);
|
|
663
|
+
const relPath = relative(resolved, fullPath).replace(/\\/g, '/');
|
|
664
|
+
if (!result.has(familyId))
|
|
665
|
+
result.set(familyId, []);
|
|
666
|
+
result.get(familyId).push(`${relPath}/*`);
|
|
667
|
+
}
|
|
668
|
+
else if (stat.isFile()) {
|
|
669
|
+
// File → family ID from basename (e.g., channel.ts → channel)
|
|
670
|
+
const ext = entry.slice(entry.lastIndexOf('.'));
|
|
671
|
+
if (!['.ts', '.tsx', '.js', '.jsx'].includes(ext))
|
|
672
|
+
continue;
|
|
673
|
+
const baseName = entry.slice(0, entry.lastIndexOf('.'));
|
|
674
|
+
const familyId = normalizeId(baseName);
|
|
675
|
+
if (familyId.length < 3)
|
|
676
|
+
continue;
|
|
677
|
+
const relPath = relative(resolved, fullPath).replace(/\\/g, '/');
|
|
678
|
+
if (!result.has(familyId))
|
|
679
|
+
result.set(familyId, []);
|
|
680
|
+
result.get(familyId).push(relPath);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
catch {
|
|
684
|
+
continue;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
return result;
|
|
689
|
+
}
|
|
690
|
+
/**
|
|
691
|
+
* Discover files in well-known directories (types, utils) whose basename
|
|
692
|
+
* maps directly to a family ID.
|
|
693
|
+
*/
|
|
694
|
+
export function discoverNameMatchedPaths(appPath, gitRepoRoot) {
|
|
695
|
+
const result = new Map();
|
|
696
|
+
const resolvedApp = resolve(appPath);
|
|
697
|
+
const scanRoots = [
|
|
698
|
+
{ root: join(resolvedApp, 'src/utils'), base: resolvedApp },
|
|
699
|
+
{ root: join(resolvedApp, 'src/types'), base: resolvedApp },
|
|
700
|
+
];
|
|
701
|
+
// Monorepo-aware: scan platform types and server model directories
|
|
702
|
+
if (gitRepoRoot) {
|
|
703
|
+
const resolvedGitRoot = resolve(gitRepoRoot);
|
|
704
|
+
const platformTypes = join(resolvedGitRoot, 'webapp/platform/types/src');
|
|
705
|
+
if (existsSync(platformTypes)) {
|
|
706
|
+
scanRoots.push({ root: platformTypes, base: resolvedGitRoot });
|
|
707
|
+
}
|
|
708
|
+
const platformClient = join(resolvedGitRoot, 'webapp/platform/client/src');
|
|
709
|
+
if (existsSync(platformClient)) {
|
|
710
|
+
scanRoots.push({ root: platformClient, base: resolvedGitRoot });
|
|
711
|
+
}
|
|
712
|
+
const serverModel = join(resolvedGitRoot, 'server/public/model');
|
|
713
|
+
if (existsSync(serverModel)) {
|
|
714
|
+
scanRoots.push({ root: serverModel, base: resolvedGitRoot });
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
for (const { root, base } of scanRoots) {
|
|
718
|
+
if (!existsSync(root))
|
|
719
|
+
continue;
|
|
720
|
+
let entries;
|
|
721
|
+
try {
|
|
722
|
+
entries = readdirSync(root);
|
|
723
|
+
}
|
|
724
|
+
catch {
|
|
725
|
+
continue;
|
|
726
|
+
}
|
|
727
|
+
for (const entry of entries) {
|
|
728
|
+
if (entry.startsWith('.'))
|
|
729
|
+
continue;
|
|
730
|
+
const ext = entry.slice(entry.lastIndexOf('.'));
|
|
731
|
+
if (!['.ts', '.tsx', '.js', '.jsx', '.go'].includes(ext))
|
|
732
|
+
continue;
|
|
733
|
+
// Skip Go test files
|
|
734
|
+
if (entry.endsWith('_test.go'))
|
|
735
|
+
continue;
|
|
736
|
+
const fullPath = join(root, entry);
|
|
737
|
+
try {
|
|
738
|
+
const stat = lstatSync(fullPath);
|
|
739
|
+
if (!stat.isFile() || stat.isSymbolicLink())
|
|
740
|
+
continue;
|
|
741
|
+
}
|
|
742
|
+
catch {
|
|
743
|
+
continue;
|
|
744
|
+
}
|
|
745
|
+
// Strip extension and normalize
|
|
746
|
+
const baseName = entry.slice(0, entry.lastIndexOf('.'));
|
|
747
|
+
const familyId = normalizeId(baseName);
|
|
748
|
+
if (familyId.length < 3)
|
|
749
|
+
continue;
|
|
750
|
+
const relPath = relative(base, fullPath).replace(/\\/g, '/');
|
|
751
|
+
if (!result.has(familyId))
|
|
752
|
+
result.set(familyId, []);
|
|
753
|
+
result.get(familyId).push(relPath);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
return result;
|
|
757
|
+
}
|
|
758
|
+
export function scanProject(projectRoot, testsRoot, serverRoot, gitRepoRoot) {
|
|
624
759
|
const resolved = resolve(projectRoot);
|
|
625
760
|
const resolvedTestsRoot = testsRoot ? resolve(testsRoot) : resolved;
|
|
626
761
|
const sourceDirs = discoverSourceDirs(resolved);
|
|
@@ -683,9 +818,12 @@ export function scanProject(projectRoot, testsRoot, serverRoot) {
|
|
|
683
818
|
// When a separate serverRoot is provided, discover families from Go source
|
|
684
819
|
// filenames across the three-tier backend (api4, app, store).
|
|
685
820
|
if (serverRoot) {
|
|
686
|
-
const
|
|
821
|
+
const { multiTierFamilies: serverMulti, singleTierFamilies: serverSingle } = discoverServerDerivedFamilies(resolve(serverRoot));
|
|
687
822
|
const existingIds = new Set(families.map((f) => f.id));
|
|
688
|
-
|
|
823
|
+
// Merge ALL server families (multi + single tier) into existing families,
|
|
824
|
+
// but only add NEW families if they span ≥2 tiers.
|
|
825
|
+
const allServerFamilies = [...serverMulti, ...serverSingle];
|
|
826
|
+
for (const sf of allServerFamilies) {
|
|
689
827
|
// Try exact match, then singular/plural variants
|
|
690
828
|
let target = families.find((f) => f.id === sf.id);
|
|
691
829
|
if (!target && !sf.id.endsWith('s')) {
|
|
@@ -702,13 +840,53 @@ export function scanProject(projectRoot, testsRoot, serverRoot) {
|
|
|
702
840
|
}
|
|
703
841
|
}
|
|
704
842
|
}
|
|
705
|
-
else {
|
|
706
|
-
//
|
|
843
|
+
else if (serverMulti.includes(sf)) {
|
|
844
|
+
// Only add new families if they span ≥2 tiers
|
|
707
845
|
families.push(sf);
|
|
708
846
|
existingIds.add(sf.id);
|
|
709
847
|
}
|
|
710
848
|
}
|
|
711
849
|
}
|
|
850
|
+
// Merge test library paths (page objects, helpers) into existing families
|
|
851
|
+
if (testsRoot) {
|
|
852
|
+
const testLibPaths = discoverTestLibPaths(resolvedTestsRoot);
|
|
853
|
+
for (const [libFamilyId, patterns] of testLibPaths) {
|
|
854
|
+
let target = families.find((f) => f.id === libFamilyId);
|
|
855
|
+
if (!target && !libFamilyId.endsWith('s')) {
|
|
856
|
+
target = families.find((f) => f.id === libFamilyId + 's');
|
|
857
|
+
}
|
|
858
|
+
if (!target && libFamilyId.endsWith('s')) {
|
|
859
|
+
target = families.find((f) => f.id === libFamilyId.slice(0, -1));
|
|
860
|
+
}
|
|
861
|
+
if (target) {
|
|
862
|
+
for (const p of patterns) {
|
|
863
|
+
if (!target.webappPaths.includes(p)) {
|
|
864
|
+
target.webappPaths.push(p);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
// Merge name-matched type/util files into existing families
|
|
871
|
+
{
|
|
872
|
+
const nameMatchedPaths = discoverNameMatchedPaths(resolved, gitRepoRoot);
|
|
873
|
+
for (const [nmFamilyId, paths] of nameMatchedPaths) {
|
|
874
|
+
let target = families.find((f) => f.id === nmFamilyId);
|
|
875
|
+
if (!target && !nmFamilyId.endsWith('s')) {
|
|
876
|
+
target = families.find((f) => f.id === nmFamilyId + 's');
|
|
877
|
+
}
|
|
878
|
+
if (!target && nmFamilyId.endsWith('s')) {
|
|
879
|
+
target = families.find((f) => f.id === nmFamilyId.slice(0, -1));
|
|
880
|
+
}
|
|
881
|
+
if (target) {
|
|
882
|
+
for (const p of paths) {
|
|
883
|
+
if (!target.webappPaths.includes(p)) {
|
|
884
|
+
target.webappPaths.push(p);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
}
|
|
712
890
|
const familyIds = new Set(families.map((f) => f.id));
|
|
713
891
|
const unmatchedSourceDirs = sourceDirs.filter((d) => !familyIds.has(normalizeId(d.familyHint)));
|
|
714
892
|
const unmatchedTestDirs = testDirs.filter((d) => !familyIds.has(normalizeId(d.familyHint)));
|
|
@@ -3,6 +3,63 @@
|
|
|
3
3
|
import { execFileSync } from 'child_process';
|
|
4
4
|
import { resolve } from 'path';
|
|
5
5
|
import { bindFilesToFamilies } from '../knowledge/route_families.js';
|
|
6
|
+
/**
|
|
7
|
+
* Glob-style patterns for infrastructure / cross-cutting files that will never
|
|
8
|
+
* belong to a single route family. Excluded from coverage calculations.
|
|
9
|
+
*/
|
|
10
|
+
const INFRA_GLOBS = [
|
|
11
|
+
'Makefile', 'go.mod', 'go.sum',
|
|
12
|
+
'*.lock',
|
|
13
|
+
'**/mocks/*', '**/storetest/*', '**/testlib/*',
|
|
14
|
+
'**/i18n/*',
|
|
15
|
+
'**/.github/*', '**/.ci/*', '**/scripts/*',
|
|
16
|
+
'**/docker-compose*',
|
|
17
|
+
'**/__fixtures__/*', '**/test_templates/*',
|
|
18
|
+
'playwright.config.ts', 'global-setup.ts',
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* Check if a file path matches any infrastructure glob pattern.
|
|
22
|
+
* Uses simple string matching — no external glob library needed.
|
|
23
|
+
*/
|
|
24
|
+
export function isInfraFile(filePath) {
|
|
25
|
+
const normalized = filePath.replace(/\\/g, '/');
|
|
26
|
+
for (const pattern of INFRA_GLOBS) {
|
|
27
|
+
if (pattern.startsWith('**/')) {
|
|
28
|
+
// Match anywhere in the path
|
|
29
|
+
const suffix = pattern.slice(3);
|
|
30
|
+
if (suffix.endsWith('/*')) {
|
|
31
|
+
// Directory match: **/mocks/* → any segment named "mocks" with a child
|
|
32
|
+
const dirName = suffix.slice(0, -2);
|
|
33
|
+
if (normalized.includes(`/${dirName}/`) || normalized.startsWith(`${dirName}/`))
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
else if (suffix.endsWith('*')) {
|
|
37
|
+
// Prefix match: **/docker-compose* → file starting with docker-compose
|
|
38
|
+
const prefix = suffix.slice(0, -1);
|
|
39
|
+
const base = normalized.split('/').pop() || '';
|
|
40
|
+
if (base.startsWith(prefix))
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
if (normalized.endsWith(`/${suffix}`) || normalized === suffix)
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else if (pattern.startsWith('*.')) {
|
|
49
|
+
// Extension match: *.lock
|
|
50
|
+
const ext = pattern.slice(1);
|
|
51
|
+
if (normalized.endsWith(ext))
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
// Exact basename match: Makefile, go.mod, go.sum
|
|
56
|
+
const base = normalized.split('/').pop() || '';
|
|
57
|
+
if (base === pattern)
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
6
63
|
export function parseGitLog(log) {
|
|
7
64
|
const commits = [];
|
|
8
65
|
let current = null;
|
|
@@ -48,16 +105,56 @@ export function getCommitFiles(projectRoot, since) {
|
|
|
48
105
|
}
|
|
49
106
|
return parseGitLog(log);
|
|
50
107
|
}
|
|
51
|
-
|
|
52
|
-
|
|
108
|
+
/**
|
|
109
|
+
* For each file, try matching both the original path and any prefix-stripped
|
|
110
|
+
* variant against the manifest. Returns one FileBinding per original file.
|
|
111
|
+
*/
|
|
112
|
+
function bindWithPrefixes(files, manifest, prefixes) {
|
|
113
|
+
if (prefixes.length === 0) {
|
|
114
|
+
return bindFilesToFamilies(files, manifest);
|
|
115
|
+
}
|
|
116
|
+
// Build candidate variants for each file
|
|
117
|
+
const variants = files.map((f) => {
|
|
118
|
+
const normalized = f.replace(/\\/g, '/');
|
|
119
|
+
const candidates = [normalized];
|
|
120
|
+
for (const prefix of prefixes) {
|
|
121
|
+
if (normalized.startsWith(prefix)) {
|
|
122
|
+
candidates.push(normalized.slice(prefix.length));
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return candidates;
|
|
127
|
+
});
|
|
128
|
+
// Bind all variants and merge results per original file
|
|
129
|
+
return files.map((f, i) => {
|
|
130
|
+
const normalized = f.replace(/\\/g, '/');
|
|
131
|
+
const allBindings = [];
|
|
132
|
+
const seen = new Set();
|
|
133
|
+
for (const variant of variants[i]) {
|
|
134
|
+
const [result] = bindFilesToFamilies([variant], manifest);
|
|
135
|
+
for (const b of result.bindings) {
|
|
136
|
+
const key = `${b.family}:${b.feature || ''}`;
|
|
137
|
+
if (!seen.has(key)) {
|
|
138
|
+
seen.add(key);
|
|
139
|
+
allBindings.push(b);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return { file: normalized, bindings: allBindings };
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
export function validateCommit(manifest, files, hash, message, pathPrefixes) {
|
|
147
|
+
// Filter out non-source files and infrastructure files
|
|
53
148
|
const sourceFiles = files.filter((f) => {
|
|
54
149
|
return !f.endsWith('.md') && !f.endsWith('.json') && !f.endsWith('.yml') && !f.endsWith('.yaml') &&
|
|
55
|
-
!f.startsWith('.') && !f.includes('node_modules/');
|
|
150
|
+
!f.startsWith('.') && !f.includes('node_modules/') && !isInfraFile(f);
|
|
56
151
|
});
|
|
57
152
|
if (sourceFiles.length === 0) {
|
|
58
153
|
return { hash, message, changedFiles: [], boundFiles: 0, unboundFiles: [], familiesHit: [] };
|
|
59
154
|
}
|
|
60
|
-
const bindings =
|
|
155
|
+
const bindings = pathPrefixes
|
|
156
|
+
? bindWithPrefixes(sourceFiles, manifest, pathPrefixes)
|
|
157
|
+
: bindFilesToFamilies(sourceFiles, manifest);
|
|
61
158
|
const bound = bindings.filter((b) => b.bindings.length > 0);
|
|
62
159
|
const unbound = bindings.filter((b) => b.bindings.length === 0);
|
|
63
160
|
const familiesHit = new Set();
|
|
@@ -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;AAID,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAwBtE;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAE/E;AA+FD,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,iBAAiB,GAAG,mBAAmB,GAAG,IAAI,CA0CjH;AAED,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,mBAAmB,GAAG,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"route_families.d.ts","sourceRoot":"","sources":["../../src/knowledge/route_families.ts"],"names":[],"mappings":"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"}
|
|
@@ -185,6 +185,7 @@ function bindFilesToFamilies(changedFiles, manifest) {
|
|
|
185
185
|
const featurePatterns = [
|
|
186
186
|
...(feature.webappPaths || []),
|
|
187
187
|
...(feature.serverPaths || []),
|
|
188
|
+
...(feature.specDirs || []),
|
|
188
189
|
];
|
|
189
190
|
if (featurePatterns.length > 0 && matchesAnyPattern(normalized, featurePatterns)) {
|
|
190
191
|
featureBindings.push({ family: family.id, feature: feature.id });
|
|
@@ -199,6 +200,8 @@ function bindFilesToFamilies(changedFiles, manifest) {
|
|
|
199
200
|
const familyPatterns = [
|
|
200
201
|
...(family.webappPaths || []),
|
|
201
202
|
...(family.serverPaths || []),
|
|
203
|
+
...(family.specDirs || []),
|
|
204
|
+
...(family.cypressSpecDirs || []),
|
|
202
205
|
];
|
|
203
206
|
if (familyPatterns.length > 0 && matchesAnyPattern(normalized, familyPatterns)) {
|
|
204
207
|
bindings.push({ family: family.id });
|
package/dist/logger.d.ts
CHANGED
|
@@ -11,12 +11,21 @@ export declare enum LogLevel {
|
|
|
11
11
|
}
|
|
12
12
|
export declare class Logger {
|
|
13
13
|
private level;
|
|
14
|
+
private jsonMode;
|
|
14
15
|
constructor(minLevel?: LogLevel);
|
|
15
16
|
error(message: string, context?: Record<string, unknown>): void;
|
|
16
17
|
warn(message: string, context?: Record<string, unknown>): void;
|
|
17
18
|
info(message: string, context?: Record<string, unknown>): void;
|
|
18
19
|
debug(message: string, context?: Record<string, unknown>): void;
|
|
19
20
|
setLevel(level: LogLevel): void;
|
|
21
|
+
setJsonMode(enabled: boolean): void;
|
|
22
|
+
/**
|
|
23
|
+
* Start a timer for measuring duration of an operation.
|
|
24
|
+
* Returns an object with `end()` that logs at DEBUG level and returns elapsed ms.
|
|
25
|
+
*/
|
|
26
|
+
timer(label: string): {
|
|
27
|
+
end: () => number;
|
|
28
|
+
};
|
|
20
29
|
private log;
|
|
21
30
|
}
|
|
22
31
|
export declare const logger: Logger;
|
package/dist/logger.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AAEH,oBAAY,QAAQ;IAChB,KAAK,IAAI;IACT,IAAI,IAAI;IACR,IAAI,IAAI;IACR,KAAK,IAAI;CACZ;AAqCD,qBAAa,MAAM;IACf,OAAO,CAAC,KAAK,CAAW;
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AAEH,oBAAY,QAAQ;IAChB,KAAK,IAAI;IACT,IAAI,IAAI;IACR,IAAI,IAAI;IACR,KAAK,IAAI;CACZ;AAqCD,qBAAa,MAAM;IACf,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,QAAQ,CAAU;gBAEd,QAAQ,CAAC,EAAE,QAAQ;IAK/B,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAM/D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAM9D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAM9D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAM/D,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAI/B,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAInC;;;OAGG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG;QAAC,GAAG,EAAE,MAAM,MAAM,CAAA;KAAC;IAWzC,OAAO,CAAC,GAAG;CAoBd;AAGD,eAAO,MAAM,MAAM,QAAe,CAAC"}
|
package/dist/logger.js
CHANGED
|
@@ -51,6 +51,7 @@ function logLevelToString(level) {
|
|
|
51
51
|
class Logger {
|
|
52
52
|
constructor(minLevel) {
|
|
53
53
|
this.level = minLevel ?? getLogLevelFromEnv();
|
|
54
|
+
this.jsonMode = process.env.LOG_FORMAT?.toLowerCase() === 'json';
|
|
54
55
|
}
|
|
55
56
|
error(message, context) {
|
|
56
57
|
if (this.level >= LogLevel.ERROR) {
|
|
@@ -75,11 +76,37 @@ class Logger {
|
|
|
75
76
|
setLevel(level) {
|
|
76
77
|
this.level = level;
|
|
77
78
|
}
|
|
79
|
+
setJsonMode(enabled) {
|
|
80
|
+
this.jsonMode = enabled;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Start a timer for measuring duration of an operation.
|
|
84
|
+
* Returns an object with `end()` that logs at DEBUG level and returns elapsed ms.
|
|
85
|
+
*/
|
|
86
|
+
timer(label) {
|
|
87
|
+
const start = performance.now();
|
|
88
|
+
return {
|
|
89
|
+
end: () => {
|
|
90
|
+
const elapsed = Math.round(performance.now() - start);
|
|
91
|
+
this.debug(`${label} completed`, { durationMs: elapsed });
|
|
92
|
+
return elapsed;
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
78
96
|
log(level, message, context) {
|
|
79
97
|
const timestamp = new Date().toISOString();
|
|
80
98
|
const levelStr = logLevelToString(level);
|
|
81
|
-
|
|
82
|
-
|
|
99
|
+
let output;
|
|
100
|
+
if (this.jsonMode) {
|
|
101
|
+
const entry = { ts: timestamp, level: levelStr, msg: message };
|
|
102
|
+
if (context)
|
|
103
|
+
entry.ctx = context;
|
|
104
|
+
output = JSON.stringify(entry);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
const contextStr = context ? ` ${JSON.stringify(context)}` : '';
|
|
108
|
+
output = `[${timestamp}] [${levelStr}] ${message}${contextStr}`;
|
|
109
|
+
}
|
|
83
110
|
if (level <= LogLevel.WARN) {
|
|
84
111
|
console.error(output);
|
|
85
112
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/pipeline/orchestrator.ts"],"names":[],"mappings":"AAQA,OAAO,EAAiB,KAAK,YAAY,EAAC,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAmB,KAAK,cAAc,EAAC,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EAAqB,KAAK,gBAAgB,EAAE,KAAK,aAAa,EAAC,MAAM,wBAAwB,CAAC;AACrG,OAAO,EAAuD,KAAK,UAAU,EAAE,KAAK,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACxH,OAAO,EAAe,KAAK,kBAAkB,EAAoB,MAAM,gCAAgC,CAAC;AAExG,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,gCAAgC,CAAC;AACtE,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,6BAA6B,CAAC;AAElE,MAAM,WAAW,cAAc;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,iEAAiE;IACjE,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,MAAM,CAAC,EAAE,KAAK,CAAC,YAAY,GAAG,QAAQ,GAAG,UAAU,GAAG,YAAY,GAAG,MAAM,CAAC,CAAC;CAChF;AAED,MAAM,WAAW,cAAc;IAC3B,MAAM,EAAE,kBAAkB,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,CAAC,EAAE,aAAa,EAAE,CAAC;IAC5B,UAAU,CAAC,EAAE,UAAU,CAAC;CAC3B;AAqBD,wBAAsB,WAAW,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,
|
|
1
|
+
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/pipeline/orchestrator.ts"],"names":[],"mappings":"AAQA,OAAO,EAAiB,KAAK,YAAY,EAAC,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAmB,KAAK,cAAc,EAAC,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EAAqB,KAAK,gBAAgB,EAAE,KAAK,aAAa,EAAC,MAAM,wBAAwB,CAAC;AACrG,OAAO,EAAuD,KAAK,UAAU,EAAE,KAAK,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACxH,OAAO,EAAe,KAAK,kBAAkB,EAAoB,MAAM,gCAAgC,CAAC;AAExG,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,gCAAgC,CAAC;AACtE,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,6BAA6B,CAAC;AAElE,MAAM,WAAW,cAAc;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,iEAAiE;IACjE,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,MAAM,CAAC,EAAE,KAAK,CAAC,YAAY,GAAG,QAAQ,GAAG,UAAU,GAAG,YAAY,GAAG,MAAM,CAAC,CAAC;CAChF;AAED,MAAM,WAAW,cAAc;IAC3B,MAAM,EAAE,kBAAkB,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,CAAC,EAAE,aAAa,EAAE,CAAC;IAC5B,UAAU,CAAC,EAAE,UAAU,CAAC;CAC3B;AAqBD,wBAAsB,WAAW,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CA6IjF"}
|