@yasserkhanorg/e2e-agents 0.3.2 → 0.3.4
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 +29 -20
- package/dist/agent/config.d.ts +3 -0
- package/dist/agent/config.d.ts.map +1 -1
- package/dist/agent/config.js +38 -0
- package/dist/agent/operational_insights.d.ts +1 -1
- package/dist/agent/operational_insights.d.ts.map +1 -1
- package/dist/agent/operational_insights.js +2 -1
- package/dist/agent/pipeline.d.ts +8 -1
- package/dist/agent/pipeline.d.ts.map +1 -1
- package/dist/agent/pipeline.js +844 -33
- package/dist/agent/plan.d.ts +39 -0
- package/dist/agent/plan.d.ts.map +1 -1
- package/dist/agent/plan.js +146 -0
- package/dist/agent/report.d.ts +16 -0
- package/dist/agent/report.d.ts.map +1 -1
- package/dist/agent/report.js +12 -0
- package/dist/agent/runner.d.ts.map +1 -1
- package/dist/agent/runner.js +66 -11
- package/dist/agent/tests.d.ts.map +1 -1
- package/dist/agent/tests.js +12 -2
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +1 -0
- package/dist/cli.js +111 -7
- package/dist/esm/agent/config.js +38 -0
- package/dist/esm/agent/operational_insights.js +2 -1
- package/dist/esm/agent/pipeline.js +844 -33
- package/dist/esm/agent/plan.js +145 -1
- package/dist/esm/agent/report.js +12 -0
- package/dist/esm/agent/runner.js +66 -11
- package/dist/esm/agent/tests.js +12 -2
- package/dist/esm/api.js +2 -1
- package/dist/esm/cli.js +112 -8
- package/package.json +1 -1
- package/schemas/impact.schema.json +37 -0
- package/schemas/plan.schema.json +48 -0
- package/dist/agent/cache_utils.d.ts +0 -38
- package/dist/agent/cache_utils.d.ts.map +0 -1
- package/dist/agent/cache_utils.js +0 -67
- package/dist/agent/impact-analyzer.d.ts +0 -114
- package/dist/agent/impact-analyzer.d.ts.map +0 -1
- package/dist/agent/impact-analyzer.js +0 -557
- package/dist/agent/index.d.ts +0 -21
- package/dist/agent/index.d.ts.map +0 -1
- package/dist/agent/index.js +0 -38
- package/dist/agent/model-router.d.ts +0 -57
- package/dist/agent/model-router.d.ts.map +0 -1
- package/dist/agent/model-router.js +0 -154
- package/dist/agent/report-generator.d.ts +0 -24
- package/dist/agent/report-generator.d.ts.map +0 -1
- package/dist/agent/report-generator.js +0 -250
- package/dist/agent/spec-bridge.d.ts +0 -101
- package/dist/agent/spec-bridge.d.ts.map +0 -1
- package/dist/agent/spec-bridge.js +0 -273
- package/dist/agent/spec-builder.d.ts +0 -102
- package/dist/agent/spec-builder.d.ts.map +0 -1
- package/dist/agent/spec-builder.js +0 -273
- package/dist/agent/telemetry.d.ts +0 -84
- package/dist/agent/telemetry.d.ts.map +0 -1
- package/dist/agent/telemetry.js +0 -220
- package/dist/agent/validators/selector-validator.d.ts +0 -74
- package/dist/agent/validators/selector-validator.d.ts.map +0 -1
- package/dist/agent/validators/selector-validator.js +0 -165
- package/dist/e2e-test-gen/index.d.ts +0 -51
- package/dist/e2e-test-gen/index.d.ts.map +0 -1
- package/dist/e2e-test-gen/index.js +0 -57
- package/dist/e2e-test-gen/spec_parser.d.ts +0 -142
- package/dist/e2e-test-gen/spec_parser.d.ts.map +0 -1
- package/dist/e2e-test-gen/spec_parser.js +0 -786
- package/dist/e2e-test-gen/types.d.ts +0 -185
- package/dist/e2e-test-gen/types.d.ts.map +0 -1
- package/dist/e2e-test-gen/types.js +0 -4
- package/dist/esm/agent/cache_utils.js +0 -63
- package/dist/esm/agent/impact-analyzer.js +0 -548
- package/dist/esm/agent/index.js +0 -22
- package/dist/esm/agent/model-router.js +0 -150
- package/dist/esm/agent/report-generator.js +0 -247
- package/dist/esm/agent/spec-bridge.js +0 -267
- package/dist/esm/agent/spec-builder.js +0 -267
- package/dist/esm/agent/telemetry.js +0 -216
- package/dist/esm/agent/validators/selector-validator.js +0 -160
- package/dist/esm/e2e-test-gen/index.js +0 -50
- package/dist/esm/e2e-test-gen/spec_parser.js +0 -782
- package/dist/esm/e2e-test-gen/types.js +0 -3
- package/dist/esm/plan-and-test-constants.js +0 -126
- package/dist/plan-and-test-constants.d.ts +0 -110
- package/dist/plan-and-test-constants.d.ts.map +0 -1
- package/dist/plan-and-test-constants.js +0 -132
package/dist/esm/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import { resolveConfig } from './agent/config.js';
|
|
|
7
7
|
import { AnthropicProvider } from './anthropic_provider.js';
|
|
8
8
|
import { LLMProviderError } from './provider_interface.js';
|
|
9
9
|
import { runGap, runImpact } from './agent/runner.js';
|
|
10
|
-
import { attachDeveloperActions, buildPlanFromImpactReport, renderCiSummaryMarkdown, writeCiSummary, writePlanReport } from './agent/plan.js';
|
|
10
|
+
import { appendPlanMetrics, attachDeveloperActions, buildPlanFromImpactReport, renderCiSummaryMarkdown, writeCiSummary, writePlanReport, } from './agent/plan.js';
|
|
11
11
|
import { applyOperationalInsights } from './agent/operational_insights.js';
|
|
12
12
|
import { appendFeedbackAndRecompute } from './agent/feedback.js';
|
|
13
13
|
import { finalizeGeneratedTests } from './agent/handoff.js';
|
|
@@ -59,6 +59,9 @@ function printUsage() {
|
|
|
59
59
|
'Usage:',
|
|
60
60
|
' e2e-ai-agents impact --path <app-root> [options]',
|
|
61
61
|
' e2e-ai-agents gap --path <app-root> [options]',
|
|
62
|
+
' e2e-ai-agents plan --path <app-root> [options]',
|
|
63
|
+
' e2e-ai-agents generate --path <app-root> [options]',
|
|
64
|
+
' e2e-ai-agents heal --path <app-root> --traceability-report <json> [options]',
|
|
62
65
|
' e2e-ai-agents suggest --path <app-root> [options]',
|
|
63
66
|
' e2e-ai-agents approve-and-generate --path <app-root> [options]',
|
|
64
67
|
' e2e-ai-agents auto-heal-pr --path <app-root> [options]',
|
|
@@ -84,10 +87,12 @@ function printUsage() {
|
|
|
84
87
|
' --pipeline-base-url Base URL for Playwright runs',
|
|
85
88
|
' --pipeline-browser Browser: chrome|chromium|firefox|webkit',
|
|
86
89
|
' --pipeline-headless Run in headless mode',
|
|
90
|
+
' --pipeline-headed Run in headed mode',
|
|
87
91
|
' --pipeline-project Playwright project name',
|
|
88
92
|
' --pipeline-parallel Enable parallel mode in generator',
|
|
89
93
|
' --pipeline-dry-run Do not execute pipeline (report only)',
|
|
90
94
|
' --pipeline-mcp Use Playwright MCP server for exploration/healing',
|
|
95
|
+
' --pipeline-mcp-allow-fallback Allow non-MCP fallback if official MCP setup fails',
|
|
91
96
|
' --spec <path> Optional spec PDF for context',
|
|
92
97
|
' --since <git-ref> Git ref for impact analysis (default HEAD~1)',
|
|
93
98
|
' --time <minutes> Time limit in minutes',
|
|
@@ -97,6 +102,8 @@ function printUsage() {
|
|
|
97
102
|
' --policy-safe-merge-confidence <n> Confidence needed for safe-to-merge',
|
|
98
103
|
' --policy-force-full-on-warnings <n> Escalate to full at warning count',
|
|
99
104
|
' --policy-risky-patterns <globs> Comma-separated risky file globs',
|
|
105
|
+
' --policy-enforcement-mode <mode> advisory | warn | block',
|
|
106
|
+
' --policy-block-actions <actions> Comma-separated CI actions to block/warn',
|
|
100
107
|
' --ci-comment-path <path> Write CI markdown summary',
|
|
101
108
|
' --github-output <path> Write GitHub Actions outputs',
|
|
102
109
|
' --fail-on-must-add-tests Exit non-zero on must-add-tests decision',
|
|
@@ -130,6 +137,9 @@ function parseArgs(argv) {
|
|
|
130
137
|
const command = argv[0];
|
|
131
138
|
if (command === 'impact'
|
|
132
139
|
|| command === 'gap'
|
|
140
|
+
|| command === 'plan'
|
|
141
|
+
|| command === 'generate'
|
|
142
|
+
|| command === 'heal'
|
|
133
143
|
|| command === 'suggest'
|
|
134
144
|
|| command === 'approve-and-generate'
|
|
135
145
|
|| command === 'auto-heal-pr'
|
|
@@ -203,6 +213,10 @@ function parseArgs(argv) {
|
|
|
203
213
|
parsed.pipelineMcp = true;
|
|
204
214
|
continue;
|
|
205
215
|
}
|
|
216
|
+
if (arg === '--pipeline-mcp-allow-fallback') {
|
|
217
|
+
parsed.pipelineMcpAllowFallback = true;
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
206
220
|
if (arg === '--pipeline-scenarios' && next) {
|
|
207
221
|
const value = Number(next);
|
|
208
222
|
if (Number.isFinite(value)) {
|
|
@@ -233,6 +247,10 @@ function parseArgs(argv) {
|
|
|
233
247
|
parsed.pipelineHeadless = true;
|
|
234
248
|
continue;
|
|
235
249
|
}
|
|
250
|
+
if (arg === '--pipeline-headed') {
|
|
251
|
+
parsed.pipelineHeadless = false;
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
236
254
|
if (arg === '--pipeline-project' && next) {
|
|
237
255
|
parsed.pipelineProject = next;
|
|
238
256
|
i += 1;
|
|
@@ -309,6 +327,21 @@ function parseArgs(argv) {
|
|
|
309
327
|
i += 1;
|
|
310
328
|
continue;
|
|
311
329
|
}
|
|
330
|
+
if (arg === '--policy-enforcement-mode' && next) {
|
|
331
|
+
if (next === 'advisory' || next === 'warn' || next === 'block') {
|
|
332
|
+
parsed.policyEnforcementMode = next;
|
|
333
|
+
}
|
|
334
|
+
i += 1;
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
if (arg === '--policy-block-actions' && next) {
|
|
338
|
+
parsed.policyBlockActions = next
|
|
339
|
+
.split(',')
|
|
340
|
+
.map((value) => value.trim())
|
|
341
|
+
.filter((value) => (value === 'run-now' || value === 'must-add-tests' || value === 'safe-to-merge'));
|
|
342
|
+
i += 1;
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
312
345
|
if (arg === '--ci-comment-path' && next) {
|
|
313
346
|
parsed.ciCommentPath = next;
|
|
314
347
|
i += 1;
|
|
@@ -612,6 +645,7 @@ async function main() {
|
|
|
612
645
|
parallel: args.pipelineParallel,
|
|
613
646
|
dryRun: args.pipelineDryRun,
|
|
614
647
|
mcp: args.pipelineMcp,
|
|
648
|
+
mcpAllowFallback: args.pipelineMcpAllowFallback,
|
|
615
649
|
},
|
|
616
650
|
});
|
|
617
651
|
if (args.allowFallback) {
|
|
@@ -686,17 +720,72 @@ async function main() {
|
|
|
686
720
|
}
|
|
687
721
|
return;
|
|
688
722
|
}
|
|
723
|
+
if (args.command === 'heal') {
|
|
724
|
+
if (!args.path && !autoConfig) {
|
|
725
|
+
// eslint-disable-next-line no-console
|
|
726
|
+
console.error('Error: --path is required for heal command');
|
|
727
|
+
process.exit(1);
|
|
728
|
+
}
|
|
729
|
+
if (!args.traceabilityReportPath) {
|
|
730
|
+
// eslint-disable-next-line no-console
|
|
731
|
+
console.error('Error: --traceability-report <path> is required for heal command');
|
|
732
|
+
process.exit(1);
|
|
733
|
+
}
|
|
734
|
+
const { config } = resolveConfig(process.cwd(), autoConfig, {
|
|
735
|
+
path: args.path,
|
|
736
|
+
testsRoot: args.testsRoot,
|
|
737
|
+
mode: 'gap',
|
|
738
|
+
framework: args.framework,
|
|
739
|
+
pipeline: {
|
|
740
|
+
enabled: true,
|
|
741
|
+
scenarios: args.pipelineScenarios,
|
|
742
|
+
outputDir: args.pipelineOutput,
|
|
743
|
+
baseUrl: args.pipelineBaseUrl,
|
|
744
|
+
browser: args.pipelineBrowser,
|
|
745
|
+
headless: args.pipelineHeadless,
|
|
746
|
+
project: args.pipelineProject,
|
|
747
|
+
parallel: args.pipelineParallel,
|
|
748
|
+
dryRun: args.pipelineDryRun,
|
|
749
|
+
mcp: args.pipelineMcp,
|
|
750
|
+
mcpAllowFallback: args.pipelineMcpAllowFallback,
|
|
751
|
+
},
|
|
752
|
+
});
|
|
753
|
+
const reportRoot = config.testsRoot || config.path;
|
|
754
|
+
const unstableSpecs = extractPlaywrightUnstableSpecs(args.traceabilityReportPath, [reportRoot, config.path]);
|
|
755
|
+
if (unstableSpecs.length === 0) {
|
|
756
|
+
// eslint-disable-next-line no-console
|
|
757
|
+
console.log('Heal targeted unstable specs: 0');
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
const targetedSummary = runTargetedSpecHeal(reportRoot, unstableSpecs.map((spec) => ({
|
|
761
|
+
specPath: spec.specPath,
|
|
762
|
+
status: spec.status,
|
|
763
|
+
reason: `Playwright report: failingTests=${spec.failingTests}, flakyTests=${spec.flakyTests}`,
|
|
764
|
+
})), {
|
|
765
|
+
...config.pipeline,
|
|
766
|
+
enabled: true,
|
|
767
|
+
heal: true,
|
|
768
|
+
});
|
|
769
|
+
const healedCount = targetedSummary.results.filter((result) => result.healStatus === 'success').length;
|
|
770
|
+
// eslint-disable-next-line no-console
|
|
771
|
+
console.log(`Heal targeted unstable specs: ${unstableSpecs.length} (healed=${healedCount})`);
|
|
772
|
+
if (targetedSummary.warnings.length > 0) {
|
|
773
|
+
// eslint-disable-next-line no-console
|
|
774
|
+
console.log(`Heal warnings: ${targetedSummary.warnings.join(' | ')}`);
|
|
775
|
+
}
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
689
778
|
if (!args.path && !autoConfig) {
|
|
690
779
|
// eslint-disable-next-line no-console
|
|
691
780
|
console.error('Error: --path is required (or provide a config file with path set)');
|
|
692
781
|
printUsage();
|
|
693
782
|
process.exit(1);
|
|
694
783
|
}
|
|
695
|
-
const forcePipelineFromApproval = args.command === 'approve-and-generate';
|
|
784
|
+
const forcePipelineFromApproval = args.command === 'approve-and-generate' || args.command === 'generate';
|
|
696
785
|
const { config } = resolveConfig(process.cwd(), autoConfig, {
|
|
697
786
|
path: args.path,
|
|
698
787
|
testsRoot: args.testsRoot,
|
|
699
|
-
mode: (args.command === 'gap' || args.command === 'approve-and-generate') ? 'gap' : 'impact',
|
|
788
|
+
mode: (args.command === 'gap' || args.command === 'approve-and-generate' || args.command === 'generate') ? 'gap' : 'impact',
|
|
700
789
|
framework: args.framework,
|
|
701
790
|
timeLimitMinutes: args.timeLimitMinutes,
|
|
702
791
|
budget: {
|
|
@@ -721,17 +810,22 @@ async function main() {
|
|
|
721
810
|
parallel: args.pipelineParallel,
|
|
722
811
|
dryRun: args.pipelineDryRun,
|
|
723
812
|
mcp: args.pipelineMcp !== undefined ? args.pipelineMcp : forcePipelineFromApproval,
|
|
813
|
+
mcpAllowFallback: args.pipelineMcpAllowFallback,
|
|
724
814
|
}
|
|
725
815
|
: undefined,
|
|
726
816
|
policy: args.policyMinConfidence !== undefined ||
|
|
727
817
|
args.policySafeMergeConfidence !== undefined ||
|
|
728
818
|
args.policyWarningsThreshold !== undefined ||
|
|
729
|
-
(args.policyRiskyPatterns && args.policyRiskyPatterns.length > 0)
|
|
819
|
+
(args.policyRiskyPatterns && args.policyRiskyPatterns.length > 0) ||
|
|
820
|
+
args.policyEnforcementMode !== undefined ||
|
|
821
|
+
(args.policyBlockActions && args.policyBlockActions.length > 0)
|
|
730
822
|
? {
|
|
731
823
|
minConfidenceForTargeted: args.policyMinConfidence,
|
|
732
824
|
safeMergeMinConfidence: args.policySafeMergeConfidence,
|
|
733
825
|
forceFullOnWarningsAtOrAbove: args.policyWarningsThreshold,
|
|
734
826
|
riskyFilePatterns: args.policyRiskyPatterns,
|
|
827
|
+
enforcementMode: args.policyEnforcementMode,
|
|
828
|
+
blockOnActions: args.policyBlockActions,
|
|
735
829
|
}
|
|
736
830
|
: undefined,
|
|
737
831
|
});
|
|
@@ -742,7 +836,7 @@ async function main() {
|
|
|
742
836
|
await runImpact(config, { apply: args.apply });
|
|
743
837
|
return;
|
|
744
838
|
}
|
|
745
|
-
if (args.command === 'suggest') {
|
|
839
|
+
if (args.command === 'suggest' || args.command === 'plan') {
|
|
746
840
|
await runImpact(config, { apply: args.apply });
|
|
747
841
|
const reportRoot = config.testsRoot || config.path;
|
|
748
842
|
const impactPath = join(reportRoot, '.e2e-ai-agents', 'impact.json');
|
|
@@ -760,24 +854,33 @@ async function main() {
|
|
|
760
854
|
const planPath = writePlanReport(reportRoot, plan);
|
|
761
855
|
const summaryMarkdown = renderCiSummaryMarkdown(plan);
|
|
762
856
|
const summaryPath = writeCiSummary(reportRoot, summaryMarkdown, args.ciCommentPath);
|
|
857
|
+
const metrics = appendPlanMetrics(reportRoot, plan);
|
|
763
858
|
const ghaOutput = args.githubOutputPath || process.env.GITHUB_OUTPUT;
|
|
764
859
|
if (ghaOutput) {
|
|
765
860
|
appendFileSync(ghaOutput, `run_set=${plan.runSet}\n`);
|
|
766
861
|
appendFileSync(ghaOutput, `action=${plan.decision.action}\n`);
|
|
767
862
|
appendFileSync(ghaOutput, `confidence=${plan.confidence}\n`);
|
|
863
|
+
appendFileSync(ghaOutput, `enforcement_mode=${plan.enforcement.mode}\n`);
|
|
864
|
+
appendFileSync(ghaOutput, `enforcement_should_fail=${plan.enforcement.shouldFail}\n`);
|
|
768
865
|
appendFileSync(ghaOutput, `recommended_tests_count=${plan.recommendedTests.length}\n`);
|
|
769
866
|
appendFileSync(ghaOutput, `required_new_tests_count=${plan.requiredNewTests.length}\n`);
|
|
770
867
|
appendFileSync(ghaOutput, `plan_path=${planPath}\n`);
|
|
771
868
|
appendFileSync(ghaOutput, `summary_path=${summaryPath}\n`);
|
|
869
|
+
appendFileSync(ghaOutput, `metrics_events_path=${metrics.eventsPath}\n`);
|
|
870
|
+
appendFileSync(ghaOutput, `metrics_summary_path=${metrics.summaryPath}\n`);
|
|
772
871
|
}
|
|
773
872
|
// eslint-disable-next-line no-console
|
|
774
873
|
console.log(`Suggested run set: ${plan.runSet} (confidence ${plan.confidence})`);
|
|
775
874
|
// eslint-disable-next-line no-console
|
|
776
875
|
console.log(`Decision: ${plan.decision.action} - ${plan.decision.summary}`);
|
|
777
876
|
// eslint-disable-next-line no-console
|
|
877
|
+
console.log(`Enforcement: ${plan.enforcement.mode} (shouldFail=${plan.enforcement.shouldFail})`);
|
|
878
|
+
// eslint-disable-next-line no-console
|
|
778
879
|
console.log(`Plan data: ${planPath}`);
|
|
779
880
|
// eslint-disable-next-line no-console
|
|
780
881
|
console.log(`CI summary: ${summaryPath}`);
|
|
882
|
+
// eslint-disable-next-line no-console
|
|
883
|
+
console.log(`Plan metrics: ${metrics.summaryPath}`);
|
|
781
884
|
if (plan.nextActions) {
|
|
782
885
|
// eslint-disable-next-line no-console
|
|
783
886
|
console.log(`Next action (run existing): ${plan.nextActions.runRecommendedTests || plan.nextActions.runSmokeSuite}`);
|
|
@@ -786,13 +889,14 @@ async function main() {
|
|
|
786
889
|
// eslint-disable-next-line no-console
|
|
787
890
|
console.log(`Next action (heal): ${plan.nextActions.healGeneratedTests}`);
|
|
788
891
|
}
|
|
789
|
-
|
|
892
|
+
const failOnLegacyFlag = args.failOnMustAddTests && plan.decision.action === 'must-add-tests';
|
|
893
|
+
if (failOnLegacyFlag || plan.enforcement.shouldFail) {
|
|
790
894
|
process.exit(2);
|
|
791
895
|
}
|
|
792
896
|
return;
|
|
793
897
|
}
|
|
794
|
-
if (args.command === 'approve-and-generate') {
|
|
795
|
-
await runGap(config, { apply:
|
|
898
|
+
if (args.command === 'approve-and-generate' || args.command === 'generate') {
|
|
899
|
+
await runGap(config, { apply: args.apply });
|
|
796
900
|
return;
|
|
797
901
|
}
|
|
798
902
|
await runGap(config, { apply: args.apply });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yasserkhanorg/e2e-agents",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "Pluggable LLM provider library for AI-powered test automation. Use Claude, Ollama, or your own LLM. Integrate with Playwright, Jest, or any test framework. MCP server for test agents, cost tracking, and hybrid provider mode.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -18,6 +18,28 @@
|
|
|
18
18
|
"mode": {
|
|
19
19
|
"const": "impact"
|
|
20
20
|
},
|
|
21
|
+
"runMetadata": {
|
|
22
|
+
"type": "object",
|
|
23
|
+
"required": [
|
|
24
|
+
"runId",
|
|
25
|
+
"startedAt",
|
|
26
|
+
"completedAt",
|
|
27
|
+
"durationMs",
|
|
28
|
+
"sinceRef",
|
|
29
|
+
"appPath",
|
|
30
|
+
"testsRoot"
|
|
31
|
+
],
|
|
32
|
+
"properties": {
|
|
33
|
+
"runId": {"type": "string"},
|
|
34
|
+
"startedAt": {"type": "string", "format": "date-time"},
|
|
35
|
+
"completedAt": {"type": "string", "format": "date-time"},
|
|
36
|
+
"durationMs": {"type": "number"},
|
|
37
|
+
"sinceRef": {"type": "string"},
|
|
38
|
+
"appPath": {"type": "string"},
|
|
39
|
+
"testsRoot": {"type": "string"}
|
|
40
|
+
},
|
|
41
|
+
"additionalProperties": false
|
|
42
|
+
},
|
|
21
43
|
"changedFiles": {
|
|
22
44
|
"type": "array",
|
|
23
45
|
"items": {
|
|
@@ -370,6 +392,21 @@
|
|
|
370
392
|
},
|
|
371
393
|
"error": {
|
|
372
394
|
"type": "string"
|
|
395
|
+
},
|
|
396
|
+
"failureCategory": {
|
|
397
|
+
"enum": [
|
|
398
|
+
"config",
|
|
399
|
+
"environment",
|
|
400
|
+
"generation",
|
|
401
|
+
"validation",
|
|
402
|
+
"runtime",
|
|
403
|
+
"quality",
|
|
404
|
+
"path-safety",
|
|
405
|
+
"unknown"
|
|
406
|
+
]
|
|
407
|
+
},
|
|
408
|
+
"failureCode": {
|
|
409
|
+
"type": "string"
|
|
373
410
|
}
|
|
374
411
|
},
|
|
375
412
|
"additionalProperties": false
|
package/schemas/plan.schema.json
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
"type": "object",
|
|
6
6
|
"required": [
|
|
7
7
|
"schemaVersion",
|
|
8
|
+
"runId",
|
|
8
9
|
"generatedAt",
|
|
9
10
|
"source",
|
|
10
11
|
"runSet",
|
|
@@ -14,12 +15,19 @@
|
|
|
14
15
|
"requiredNewTests",
|
|
15
16
|
"policy",
|
|
16
17
|
"decision",
|
|
18
|
+
"enforcement",
|
|
17
19
|
"metrics"
|
|
18
20
|
],
|
|
19
21
|
"properties": {
|
|
20
22
|
"schemaVersion": {
|
|
21
23
|
"const": "1.0.0"
|
|
22
24
|
},
|
|
25
|
+
"runId": {
|
|
26
|
+
"type": "string"
|
|
27
|
+
},
|
|
28
|
+
"sourceRunId": {
|
|
29
|
+
"type": "string"
|
|
30
|
+
},
|
|
23
31
|
"generatedAt": {
|
|
24
32
|
"type": "string",
|
|
25
33
|
"format": "date-time"
|
|
@@ -108,6 +116,15 @@
|
|
|
108
116
|
"items": {
|
|
109
117
|
"type": "string"
|
|
110
118
|
}
|
|
119
|
+
},
|
|
120
|
+
"enforcementMode": {
|
|
121
|
+
"enum": ["advisory", "warn", "block"]
|
|
122
|
+
},
|
|
123
|
+
"blockOnActions": {
|
|
124
|
+
"type": "array",
|
|
125
|
+
"items": {
|
|
126
|
+
"enum": ["run-now", "must-add-tests", "safe-to-merge"]
|
|
127
|
+
}
|
|
111
128
|
}
|
|
112
129
|
},
|
|
113
130
|
"additionalProperties": false
|
|
@@ -139,6 +156,37 @@
|
|
|
139
156
|
},
|
|
140
157
|
"additionalProperties": false
|
|
141
158
|
},
|
|
159
|
+
"enforcement": {
|
|
160
|
+
"type": "object",
|
|
161
|
+
"required": [
|
|
162
|
+
"mode",
|
|
163
|
+
"blockOnActions",
|
|
164
|
+
"matchedAction",
|
|
165
|
+
"shouldFail",
|
|
166
|
+
"summary"
|
|
167
|
+
],
|
|
168
|
+
"properties": {
|
|
169
|
+
"mode": {
|
|
170
|
+
"enum": ["advisory", "warn", "block"]
|
|
171
|
+
},
|
|
172
|
+
"blockOnActions": {
|
|
173
|
+
"type": "array",
|
|
174
|
+
"items": {
|
|
175
|
+
"enum": ["run-now", "must-add-tests", "safe-to-merge"]
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
"matchedAction": {
|
|
179
|
+
"type": "boolean"
|
|
180
|
+
},
|
|
181
|
+
"shouldFail": {
|
|
182
|
+
"type": "boolean"
|
|
183
|
+
},
|
|
184
|
+
"summary": {
|
|
185
|
+
"type": "string"
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
"additionalProperties": false
|
|
189
|
+
},
|
|
142
190
|
"insights": {
|
|
143
191
|
"type": "object",
|
|
144
192
|
"properties": {
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Simple TTL cache for repository context and file reads
|
|
3
|
-
* Provides 90% faster access on cache hits
|
|
4
|
-
* Default TTL: 5 minutes
|
|
5
|
-
*/
|
|
6
|
-
export interface CacheEntry<T> {
|
|
7
|
-
value: T;
|
|
8
|
-
timestamp: number;
|
|
9
|
-
}
|
|
10
|
-
export declare class SimpleCache<T> {
|
|
11
|
-
private cache;
|
|
12
|
-
private ttlMs;
|
|
13
|
-
constructor(ttlMs?: number);
|
|
14
|
-
/**
|
|
15
|
-
* Get value from cache if it exists and hasn't expired
|
|
16
|
-
*/
|
|
17
|
-
get(key: string): T | undefined;
|
|
18
|
-
/**
|
|
19
|
-
* Set value in cache with current timestamp
|
|
20
|
-
*/
|
|
21
|
-
set(key: string, value: T): void;
|
|
22
|
-
/**
|
|
23
|
-
* Clear all entries from cache
|
|
24
|
-
*/
|
|
25
|
-
clear(): void;
|
|
26
|
-
/**
|
|
27
|
-
* Get cache size
|
|
28
|
-
*/
|
|
29
|
-
size(): number;
|
|
30
|
-
/**
|
|
31
|
-
* Get cache statistics
|
|
32
|
-
*/
|
|
33
|
-
stats(): {
|
|
34
|
-
size: number;
|
|
35
|
-
entries: number;
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
//# sourceMappingURL=cache_utils.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cache_utils.d.ts","sourceRoot":"","sources":["../../src/agent/cache_utils.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AAEH,MAAM,WAAW,UAAU,CAAC,CAAC;IACzB,KAAK,EAAE,CAAC,CAAC;IACT,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,WAAW,CAAC,CAAC;IACtB,OAAO,CAAC,KAAK,CAAyC;IACtD,OAAO,CAAC,KAAK,CAAS;gBAEV,KAAK,GAAE,MAAsB;IAKzC;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAe/B;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAOhC;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,IAAI,IAAI,MAAM;IAId;;OAEG;IACH,KAAK,IAAI;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAC;CAgB3C"}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
3
|
-
// See LICENSE.txt for license information.
|
|
4
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
exports.SimpleCache = void 0;
|
|
6
|
-
class SimpleCache {
|
|
7
|
-
constructor(ttlMs = 5 * 60 * 1000) {
|
|
8
|
-
this.cache = new Map();
|
|
9
|
-
// Default: 5 minutes
|
|
10
|
-
this.ttlMs = ttlMs;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Get value from cache if it exists and hasn't expired
|
|
14
|
-
*/
|
|
15
|
-
get(key) {
|
|
16
|
-
const entry = this.cache.get(key);
|
|
17
|
-
if (!entry) {
|
|
18
|
-
return undefined;
|
|
19
|
-
}
|
|
20
|
-
// Check if entry has expired
|
|
21
|
-
if (Date.now() - entry.timestamp > this.ttlMs) {
|
|
22
|
-
this.cache.delete(key);
|
|
23
|
-
return undefined;
|
|
24
|
-
}
|
|
25
|
-
return entry.value;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Set value in cache with current timestamp
|
|
29
|
-
*/
|
|
30
|
-
set(key, value) {
|
|
31
|
-
this.cache.set(key, {
|
|
32
|
-
value,
|
|
33
|
-
timestamp: Date.now(),
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Clear all entries from cache
|
|
38
|
-
*/
|
|
39
|
-
clear() {
|
|
40
|
-
this.cache.clear();
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Get cache size
|
|
44
|
-
*/
|
|
45
|
-
size() {
|
|
46
|
-
return this.cache.size;
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Get cache statistics
|
|
50
|
-
*/
|
|
51
|
-
stats() {
|
|
52
|
-
// Clean expired entries
|
|
53
|
-
const now = Date.now();
|
|
54
|
-
let expired = 0;
|
|
55
|
-
for (const [key, entry] of this.cache.entries()) {
|
|
56
|
-
if (now - entry.timestamp > this.ttlMs) {
|
|
57
|
-
this.cache.delete(key);
|
|
58
|
-
expired++;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return {
|
|
62
|
-
size: this.cache.size,
|
|
63
|
-
entries: this.cache.size,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
exports.SimpleCache = SimpleCache;
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
3
|
-
* See LICENSE.txt for license information.
|
|
4
|
-
*
|
|
5
|
-
* Impact Analysis Engine
|
|
6
|
-
*
|
|
7
|
-
* Analyzes code changes and identifies which user flows are affected,
|
|
8
|
-
* then maps those flows to test coverage gaps.
|
|
9
|
-
*/
|
|
10
|
-
export interface GitChange {
|
|
11
|
-
path: string;
|
|
12
|
-
status: 'added' | 'modified' | 'deleted';
|
|
13
|
-
ref?: string;
|
|
14
|
-
}
|
|
15
|
-
export interface ChangeAnalysis {
|
|
16
|
-
file: string;
|
|
17
|
-
status: 'added' | 'modified' | 'deleted';
|
|
18
|
-
linesAdded: number;
|
|
19
|
-
linesRemoved: number;
|
|
20
|
-
functions: string[];
|
|
21
|
-
classes: string[];
|
|
22
|
-
imports: Array<{
|
|
23
|
-
from: string;
|
|
24
|
-
names: string[];
|
|
25
|
-
}>;
|
|
26
|
-
}
|
|
27
|
-
export interface Flow {
|
|
28
|
-
id: string;
|
|
29
|
-
name: string;
|
|
30
|
-
priority: 'P0' | 'P1' | 'P2';
|
|
31
|
-
keywords: string[];
|
|
32
|
-
paths: string[];
|
|
33
|
-
tests: string[];
|
|
34
|
-
audience: string[];
|
|
35
|
-
flags: Array<{
|
|
36
|
-
name: string;
|
|
37
|
-
source: string;
|
|
38
|
-
}>;
|
|
39
|
-
}
|
|
40
|
-
export interface FlowImpact {
|
|
41
|
-
flow: Flow;
|
|
42
|
-
matchType: 'path' | 'keyword' | 'import' | 'combined';
|
|
43
|
-
confidence: number;
|
|
44
|
-
affectedFiles: string[];
|
|
45
|
-
existingTests: string[];
|
|
46
|
-
testGaps: string[];
|
|
47
|
-
reasons: string[];
|
|
48
|
-
}
|
|
49
|
-
export interface FlowGroup {
|
|
50
|
-
id: string;
|
|
51
|
-
name: string;
|
|
52
|
-
description: string;
|
|
53
|
-
flows: string[];
|
|
54
|
-
testStrategy: 'sequential' | 'parallel' | 'mixed';
|
|
55
|
-
priority: string;
|
|
56
|
-
affectedFlows: FlowImpact[];
|
|
57
|
-
}
|
|
58
|
-
export interface ImpactReport {
|
|
59
|
-
timestamp: string;
|
|
60
|
-
gitRef: string;
|
|
61
|
-
totalChanges: number;
|
|
62
|
-
affectedFlows: FlowImpact[];
|
|
63
|
-
flowGroups: FlowGroup[];
|
|
64
|
-
ungroupedFlows: FlowImpact[];
|
|
65
|
-
priorityBreakdown: {
|
|
66
|
-
p0: number;
|
|
67
|
-
p1: number;
|
|
68
|
-
p2: number;
|
|
69
|
-
};
|
|
70
|
-
testCoverage: {
|
|
71
|
-
total: number;
|
|
72
|
-
covered: number;
|
|
73
|
-
gaps: number;
|
|
74
|
-
};
|
|
75
|
-
recommendations: string[];
|
|
76
|
-
hasP0Impact: boolean;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Intelligently detect the best git reference for comparison:
|
|
80
|
-
* - If on feature branch: use origin/master, origin/main, or master
|
|
81
|
-
* - If on main branch: use HEAD~1
|
|
82
|
-
* Returns the best available reference to compare against
|
|
83
|
-
*/
|
|
84
|
-
export declare function detectComparisonBase(): string;
|
|
85
|
-
/**
|
|
86
|
-
* Get git changes since a given reference
|
|
87
|
-
* Filters to only include frontend files (webapp and e2e-tests)
|
|
88
|
-
*/
|
|
89
|
-
export declare function getGitChanges(since?: string): GitChange[];
|
|
90
|
-
/**
|
|
91
|
-
* Load flow catalog from flows.json
|
|
92
|
-
*/
|
|
93
|
-
export declare function loadFlowCatalog(catalogPath?: string): Flow[];
|
|
94
|
-
/**
|
|
95
|
-
* Match a flow to changed files
|
|
96
|
-
*/
|
|
97
|
-
export declare function matchFlowToChanges(flow: Flow, changes: ChangeAnalysis[]): FlowImpact | null;
|
|
98
|
-
/**
|
|
99
|
-
* Find existing tests for a flow
|
|
100
|
-
*/
|
|
101
|
-
export declare function findExistingTests(flow: Flow, repoRoot?: string): string[];
|
|
102
|
-
/**
|
|
103
|
-
* Identify test coverage gaps for a flow
|
|
104
|
-
*/
|
|
105
|
-
export declare function identifyTestGaps(flow: Flow, existingTests: string[]): string[];
|
|
106
|
-
/**
|
|
107
|
-
* Analyze code impact and return comprehensive report
|
|
108
|
-
*/
|
|
109
|
-
export declare function analyzeImpact(changes: GitChange[], flows: Flow[], options?: {
|
|
110
|
-
verbose?: boolean;
|
|
111
|
-
includeTests?: boolean;
|
|
112
|
-
repoRoot?: string;
|
|
113
|
-
}): Promise<ImpactReport>;
|
|
114
|
-
//# sourceMappingURL=impact-analyzer.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"impact-analyzer.d.ts","sourceRoot":"","sources":["../../src/agent/impact-analyzer.ts"],"names":[],"mappings":"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"}
|