@yasserkhanorg/e2e-agents 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +168 -0
- package/README.md +620 -0
- package/dist/agent/analysis.d.ts +62 -0
- package/dist/agent/analysis.d.ts.map +1 -0
- package/dist/agent/analysis.js +292 -0
- package/dist/agent/blast_radius.d.ts +4 -0
- package/dist/agent/blast_radius.d.ts.map +1 -0
- package/dist/agent/blast_radius.js +37 -0
- package/dist/agent/cache_utils.d.ts +38 -0
- package/dist/agent/cache_utils.d.ts.map +1 -0
- package/dist/agent/cache_utils.js +67 -0
- package/dist/agent/config.d.ts +148 -0
- package/dist/agent/config.d.ts.map +1 -0
- package/dist/agent/config.js +640 -0
- package/dist/agent/dependency_graph.d.ts +14 -0
- package/dist/agent/dependency_graph.d.ts.map +1 -0
- package/dist/agent/dependency_graph.js +227 -0
- package/dist/agent/feedback.d.ts +55 -0
- package/dist/agent/feedback.d.ts.map +1 -0
- package/dist/agent/feedback.js +257 -0
- package/dist/agent/flags.d.ts +23 -0
- package/dist/agent/flags.d.ts.map +1 -0
- package/dist/agent/flags.js +171 -0
- package/dist/agent/flow_catalog.d.ts +25 -0
- package/dist/agent/flow_catalog.d.ts.map +1 -0
- package/dist/agent/flow_catalog.js +106 -0
- package/dist/agent/flow_mapping.d.ts +10 -0
- package/dist/agent/flow_mapping.d.ts.map +1 -0
- package/dist/agent/flow_mapping.js +84 -0
- package/dist/agent/framework.d.ts +13 -0
- package/dist/agent/framework.d.ts.map +1 -0
- package/dist/agent/framework.js +149 -0
- package/dist/agent/gap_suggestions.d.ts +14 -0
- package/dist/agent/gap_suggestions.d.ts.map +1 -0
- package/dist/agent/gap_suggestions.js +101 -0
- package/dist/agent/generator.d.ts +10 -0
- package/dist/agent/generator.d.ts.map +1 -0
- package/dist/agent/generator.js +115 -0
- package/dist/agent/git.d.ts +11 -0
- package/dist/agent/git.d.ts.map +1 -0
- package/dist/agent/git.js +90 -0
- package/dist/agent/handoff.d.ts +22 -0
- package/dist/agent/handoff.d.ts.map +1 -0
- package/dist/agent/handoff.js +180 -0
- package/dist/agent/impact-analyzer.d.ts +114 -0
- package/dist/agent/impact-analyzer.d.ts.map +1 -0
- package/dist/agent/impact-analyzer.js +557 -0
- package/dist/agent/index.d.ts +21 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +38 -0
- package/dist/agent/model-router.d.ts +57 -0
- package/dist/agent/model-router.d.ts.map +1 -0
- package/dist/agent/model-router.js +154 -0
- package/dist/agent/operational_insights.d.ts +41 -0
- package/dist/agent/operational_insights.d.ts.map +1 -0
- package/dist/agent/operational_insights.js +126 -0
- package/dist/agent/pipeline.d.ts +23 -0
- package/dist/agent/pipeline.d.ts.map +1 -0
- package/dist/agent/pipeline.js +609 -0
- package/dist/agent/plan.d.ts +91 -0
- package/dist/agent/plan.d.ts.map +1 -0
- package/dist/agent/plan.js +331 -0
- package/dist/agent/playwright_report.d.ts +8 -0
- package/dist/agent/playwright_report.d.ts.map +1 -0
- package/dist/agent/playwright_report.js +126 -0
- package/dist/agent/report-generator.d.ts +24 -0
- package/dist/agent/report-generator.d.ts.map +1 -0
- package/dist/agent/report-generator.js +250 -0
- package/dist/agent/report.d.ts +81 -0
- package/dist/agent/report.d.ts.map +1 -0
- package/dist/agent/report.js +147 -0
- package/dist/agent/runner.d.ts +7 -0
- package/dist/agent/runner.d.ts.map +1 -0
- package/dist/agent/runner.js +576 -0
- package/dist/agent/selectors.d.ts +10 -0
- package/dist/agent/selectors.d.ts.map +1 -0
- package/dist/agent/selectors.js +75 -0
- package/dist/agent/spec-bridge.d.ts +101 -0
- package/dist/agent/spec-bridge.d.ts.map +1 -0
- package/dist/agent/spec-bridge.js +273 -0
- package/dist/agent/spec-builder.d.ts +102 -0
- package/dist/agent/spec-builder.d.ts.map +1 -0
- package/dist/agent/spec-builder.js +273 -0
- package/dist/agent/subsystem_risk.d.ts +23 -0
- package/dist/agent/subsystem_risk.d.ts.map +1 -0
- package/dist/agent/subsystem_risk.js +207 -0
- package/dist/agent/telemetry.d.ts +84 -0
- package/dist/agent/telemetry.d.ts.map +1 -0
- package/dist/agent/telemetry.js +220 -0
- package/dist/agent/test_path.d.ts +2 -0
- package/dist/agent/test_path.d.ts.map +1 -0
- package/dist/agent/test_path.js +23 -0
- package/dist/agent/tests.d.ts +18 -0
- package/dist/agent/tests.d.ts.map +1 -0
- package/dist/agent/tests.js +106 -0
- package/dist/agent/traceability.d.ts +22 -0
- package/dist/agent/traceability.d.ts.map +1 -0
- package/dist/agent/traceability.js +183 -0
- package/dist/agent/traceability_capture.d.ts +18 -0
- package/dist/agent/traceability_capture.d.ts.map +1 -0
- package/dist/agent/traceability_capture.js +313 -0
- package/dist/agent/traceability_ingest.d.ts +21 -0
- package/dist/agent/traceability_ingest.d.ts.map +1 -0
- package/dist/agent/traceability_ingest.js +237 -0
- package/dist/agent/utils.d.ts +13 -0
- package/dist/agent/utils.d.ts.map +1 -0
- package/dist/agent/utils.js +152 -0
- package/dist/agent/validators/selector-validator.d.ts +74 -0
- package/dist/agent/validators/selector-validator.d.ts.map +1 -0
- package/dist/agent/validators/selector-validator.js +165 -0
- package/dist/anthropic_provider.d.ts +65 -0
- package/dist/anthropic_provider.d.ts.map +1 -0
- package/dist/anthropic_provider.js +332 -0
- package/dist/api.d.ts +48 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +113 -0
- package/dist/base_provider.d.ts +53 -0
- package/dist/base_provider.d.ts.map +1 -0
- package/dist/base_provider.js +81 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +843 -0
- package/dist/custom_provider.d.ts +20 -0
- package/dist/custom_provider.d.ts.map +1 -0
- package/dist/custom_provider.js +276 -0
- package/dist/e2e-test-gen/index.d.ts +51 -0
- package/dist/e2e-test-gen/index.d.ts.map +1 -0
- package/dist/e2e-test-gen/index.js +57 -0
- package/dist/e2e-test-gen/spec_parser.d.ts +142 -0
- package/dist/e2e-test-gen/spec_parser.d.ts.map +1 -0
- package/dist/e2e-test-gen/spec_parser.js +786 -0
- package/dist/e2e-test-gen/types.d.ts +185 -0
- package/dist/e2e-test-gen/types.d.ts.map +1 -0
- package/dist/e2e-test-gen/types.js +4 -0
- package/dist/esm/agent/analysis.js +287 -0
- package/dist/esm/agent/blast_radius.js +34 -0
- package/dist/esm/agent/cache_utils.js +63 -0
- package/dist/esm/agent/config.js +637 -0
- package/dist/esm/agent/dependency_graph.js +224 -0
- package/dist/esm/agent/feedback.js +253 -0
- package/dist/esm/agent/flags.js +160 -0
- package/dist/esm/agent/flow_catalog.js +103 -0
- package/dist/esm/agent/flow_mapping.js +81 -0
- package/dist/esm/agent/framework.js +145 -0
- package/dist/esm/agent/gap_suggestions.js +98 -0
- package/dist/esm/agent/generator.js +112 -0
- package/dist/esm/agent/git.js +87 -0
- package/dist/esm/agent/handoff.js +177 -0
- package/dist/esm/agent/impact-analyzer.js +548 -0
- package/dist/esm/agent/index.js +22 -0
- package/dist/esm/agent/model-router.js +150 -0
- package/dist/esm/agent/operational_insights.js +123 -0
- package/dist/esm/agent/pipeline.js +605 -0
- package/dist/esm/agent/plan.js +324 -0
- package/dist/esm/agent/playwright_report.js +123 -0
- package/dist/esm/agent/report-generator.js +247 -0
- package/dist/esm/agent/report.js +144 -0
- package/dist/esm/agent/runner.js +572 -0
- package/dist/esm/agent/selectors.js +71 -0
- package/dist/esm/agent/spec-bridge.js +267 -0
- package/dist/esm/agent/spec-builder.js +267 -0
- package/dist/esm/agent/subsystem_risk.js +204 -0
- package/dist/esm/agent/telemetry.js +216 -0
- package/dist/esm/agent/test_path.js +20 -0
- package/dist/esm/agent/tests.js +101 -0
- package/dist/esm/agent/traceability.js +180 -0
- package/dist/esm/agent/traceability_capture.js +310 -0
- package/dist/esm/agent/traceability_ingest.js +234 -0
- package/dist/esm/agent/utils.js +138 -0
- package/dist/esm/agent/validators/selector-validator.js +160 -0
- package/dist/esm/anthropic_provider.js +324 -0
- package/dist/esm/api.js +105 -0
- package/dist/esm/base_provider.js +77 -0
- package/dist/esm/cli.js +841 -0
- package/dist/esm/custom_provider.js +272 -0
- package/dist/esm/e2e-test-gen/index.js +50 -0
- package/dist/esm/e2e-test-gen/spec_parser.js +782 -0
- package/dist/esm/e2e-test-gen/types.js +3 -0
- package/dist/esm/index.js +16 -0
- package/dist/esm/logger.js +89 -0
- package/dist/esm/mcp-server.js +465 -0
- package/dist/esm/ollama_provider.js +300 -0
- package/dist/esm/openai_provider.js +242 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/plan-and-test-constants.js +126 -0
- package/dist/esm/provider_factory.js +336 -0
- package/dist/esm/provider_interface.js +23 -0
- package/dist/esm/provider_utils.js +96 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/logger.d.ts +23 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +93 -0
- package/dist/mcp-server.d.ts +35 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +469 -0
- package/dist/ollama_provider.d.ts +65 -0
- package/dist/ollama_provider.d.ts.map +1 -0
- package/dist/ollama_provider.js +308 -0
- package/dist/openai_provider.d.ts +23 -0
- package/dist/openai_provider.d.ts.map +1 -0
- package/dist/openai_provider.js +250 -0
- package/dist/plan-and-test-constants.d.ts +110 -0
- package/dist/plan-and-test-constants.d.ts.map +1 -0
- package/dist/plan-and-test-constants.js +132 -0
- package/dist/provider_factory.d.ts +99 -0
- package/dist/provider_factory.d.ts.map +1 -0
- package/dist/provider_factory.js +341 -0
- package/dist/provider_interface.d.ts +358 -0
- package/dist/provider_interface.d.ts.map +1 -0
- package/dist/provider_interface.js +28 -0
- package/dist/provider_utils.d.ts +39 -0
- package/dist/provider_utils.d.ts.map +1 -0
- package/dist/provider_utils.js +103 -0
- package/package.json +101 -0
- package/schemas/gap.schema.json +18 -0
- package/schemas/impact.schema.json +418 -0
- package/schemas/plan.schema.json +285 -0
- package/schemas/subsystem-risk-map.schema.json +62 -0
- package/schemas/traceability-input.schema.json +122 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,843 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
4
|
+
// See LICENSE.txt for license information.
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const fs_1 = require("fs");
|
|
7
|
+
const path_1 = require("path");
|
|
8
|
+
const config_js_1 = require("./agent/config.js");
|
|
9
|
+
const anthropic_provider_js_1 = require("./anthropic_provider.js");
|
|
10
|
+
const provider_interface_js_1 = require("./provider_interface.js");
|
|
11
|
+
const runner_js_1 = require("./agent/runner.js");
|
|
12
|
+
const plan_js_1 = require("./agent/plan.js");
|
|
13
|
+
const operational_insights_js_1 = require("./agent/operational_insights.js");
|
|
14
|
+
const feedback_js_1 = require("./agent/feedback.js");
|
|
15
|
+
const handoff_js_1 = require("./agent/handoff.js");
|
|
16
|
+
const traceability_ingest_js_1 = require("./agent/traceability_ingest.js");
|
|
17
|
+
const traceability_capture_js_1 = require("./agent/traceability_capture.js");
|
|
18
|
+
const pipeline_js_1 = require("./agent/pipeline.js");
|
|
19
|
+
const playwright_report_js_1 = require("./agent/playwright_report.js");
|
|
20
|
+
const CONFIG_CANDIDATES = ['e2e-ai-agents.config.json', '.e2e-ai-agents.config.json'];
|
|
21
|
+
function findConfigUpwards(startDir) {
|
|
22
|
+
if (!startDir) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
let current = (0, path_1.resolve)(startDir);
|
|
26
|
+
while (true) {
|
|
27
|
+
for (const candidate of CONFIG_CANDIDATES) {
|
|
28
|
+
const fullPath = (0, path_1.join)(current, candidate);
|
|
29
|
+
if ((0, fs_1.existsSync)(fullPath)) {
|
|
30
|
+
return fullPath;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const parent = (0, path_1.dirname)(current);
|
|
34
|
+
if (parent === current) {
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
current = parent;
|
|
38
|
+
}
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
function resolveAutoConfig(args) {
|
|
42
|
+
if (args.configPath) {
|
|
43
|
+
return args.configPath;
|
|
44
|
+
}
|
|
45
|
+
const searchRoots = [
|
|
46
|
+
process.cwd(),
|
|
47
|
+
args.testsRoot,
|
|
48
|
+
args.path,
|
|
49
|
+
].filter(Boolean);
|
|
50
|
+
for (const root of searchRoots) {
|
|
51
|
+
const found = findConfigUpwards(root);
|
|
52
|
+
if (found) {
|
|
53
|
+
return found;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
function printUsage() {
|
|
59
|
+
// eslint-disable-next-line no-console
|
|
60
|
+
console.log([
|
|
61
|
+
'Usage:',
|
|
62
|
+
' e2e-ai-agents impact --path <app-root> [options]',
|
|
63
|
+
' e2e-ai-agents gap --path <app-root> [options]',
|
|
64
|
+
' e2e-ai-agents suggest --path <app-root> [options]',
|
|
65
|
+
' e2e-ai-agents approve-and-generate --path <app-root> [options]',
|
|
66
|
+
' e2e-ai-agents auto-heal-pr --path <app-root> [options]',
|
|
67
|
+
' e2e-ai-agents finalize-generated-tests --path <app-root> [options]',
|
|
68
|
+
' e2e-ai-agents feedback --path <app-root> --feedback-input <json>',
|
|
69
|
+
' e2e-ai-agents traceability-capture --path <app-root> --traceability-report <json>',
|
|
70
|
+
' e2e-ai-agents traceability-ingest --path <app-root> --traceability-input <json>',
|
|
71
|
+
' e2e-ai-agents llm-health',
|
|
72
|
+
'',
|
|
73
|
+
'Options:',
|
|
74
|
+
' --config <path> Path to e2e-ai-agents.config.json (auto-discovered if present)',
|
|
75
|
+
' --path <app-root> Path to the web app (required)',
|
|
76
|
+
' --tests-root <path> Path to tests root (optional)',
|
|
77
|
+
' --framework <name> auto | playwright | cypress | selenium',
|
|
78
|
+
' --patterns <globs> Comma-separated test patterns',
|
|
79
|
+
' --flow-patterns <g> Comma-separated flow discovery patterns',
|
|
80
|
+
' --flow-exclude <g> Comma-separated flow exclude patterns',
|
|
81
|
+
' --flow-catalog <path> Path to flow catalog JSON',
|
|
82
|
+
' --allow-fallback Allow impact analysis without diff',
|
|
83
|
+
' --pipeline Run Playwright AI pipeline for missing P0/P1 flows',
|
|
84
|
+
' --pipeline-scenarios Number of scenarios per flow (default 3)',
|
|
85
|
+
' --pipeline-output Output directory for generated tests',
|
|
86
|
+
' --pipeline-base-url Base URL for Playwright runs',
|
|
87
|
+
' --pipeline-browser Browser: chrome|chromium|firefox|webkit',
|
|
88
|
+
' --pipeline-headless Run in headless mode',
|
|
89
|
+
' --pipeline-project Playwright project name',
|
|
90
|
+
' --pipeline-parallel Enable parallel mode in generator',
|
|
91
|
+
' --pipeline-dry-run Do not execute pipeline (report only)',
|
|
92
|
+
' --pipeline-mcp Use Playwright MCP server for exploration/healing',
|
|
93
|
+
' --spec <path> Optional spec PDF for context',
|
|
94
|
+
' --since <git-ref> Git ref for impact analysis (default HEAD~1)',
|
|
95
|
+
' --time <minutes> Time limit in minutes',
|
|
96
|
+
' --budget-usd <amount> Max LLM budget in USD',
|
|
97
|
+
' --budget-tokens <n> Max LLM tokens',
|
|
98
|
+
' --policy-min-confidence <n> Minimum confidence for targeted suite',
|
|
99
|
+
' --policy-safe-merge-confidence <n> Confidence needed for safe-to-merge',
|
|
100
|
+
' --policy-force-full-on-warnings <n> Escalate to full at warning count',
|
|
101
|
+
' --policy-risky-patterns <globs> Comma-separated risky file globs',
|
|
102
|
+
' --ci-comment-path <path> Write CI markdown summary',
|
|
103
|
+
' --github-output <path> Write GitHub Actions outputs',
|
|
104
|
+
' --fail-on-must-add-tests Exit non-zero on must-add-tests decision',
|
|
105
|
+
' --feedback-input <path> Path to recommendation feedback JSON',
|
|
106
|
+
' --traceability-report <path> Path to Playwright JSON report for traceability capture',
|
|
107
|
+
' --traceability-capture-output <path> Output path for generated traceability ingest JSON',
|
|
108
|
+
' --traceability-coverage-map <path> Optional coverage map (test<->files) to enrich traceability capture',
|
|
109
|
+
' --traceability-changed-files <path> Optional changed-files list/JSON fallback for traceability capture',
|
|
110
|
+
' --traceability-input <path> Path to traceability ingest JSON payload',
|
|
111
|
+
' --traceability-min-hits <n> Minimum signal hits required per file mapping',
|
|
112
|
+
' --traceability-max-files-per-test <n> Cap max mapped files per test',
|
|
113
|
+
' --traceability-max-age-days <n> Drop stale mappings older than N days',
|
|
114
|
+
' --branch <name> Optional handoff branch (prefixed with codex/)',
|
|
115
|
+
' --commit-message <m> Commit message for finalize-generated-tests',
|
|
116
|
+
' --create-pr Open PR with gh after commit',
|
|
117
|
+
' --pr-title <title> PR title for finalize-generated-tests',
|
|
118
|
+
' --pr-body <body> PR body for finalize-generated-tests',
|
|
119
|
+
' --pr-base <branch> PR base branch for finalize-generated-tests',
|
|
120
|
+
' (auto-heal-pr defaults to base=master)',
|
|
121
|
+
' --dry-run Preview actions without mutating git state',
|
|
122
|
+
' --apply Apply data-testid patches and generate tests',
|
|
123
|
+
' (legacy shortcut; prefer approve-and-generate)',
|
|
124
|
+
' --help Show help',
|
|
125
|
+
].join('\n'));
|
|
126
|
+
}
|
|
127
|
+
function parseArgs(argv) {
|
|
128
|
+
const parsed = { apply: false, help: false };
|
|
129
|
+
if (argv.length === 0) {
|
|
130
|
+
return parsed;
|
|
131
|
+
}
|
|
132
|
+
const command = argv[0];
|
|
133
|
+
if (command === 'impact'
|
|
134
|
+
|| command === 'gap'
|
|
135
|
+
|| command === 'suggest'
|
|
136
|
+
|| command === 'approve-and-generate'
|
|
137
|
+
|| command === 'auto-heal-pr'
|
|
138
|
+
|| command === 'finalize-generated-tests'
|
|
139
|
+
|| command === 'feedback'
|
|
140
|
+
|| command === 'traceability-capture'
|
|
141
|
+
|| command === 'traceability-ingest'
|
|
142
|
+
|| command === 'llm-health') {
|
|
143
|
+
parsed.command = command;
|
|
144
|
+
}
|
|
145
|
+
for (let i = 1; i < argv.length; i += 1) {
|
|
146
|
+
const arg = argv[i];
|
|
147
|
+
const next = argv[i + 1];
|
|
148
|
+
if (arg === '--help' || arg === '-h') {
|
|
149
|
+
parsed.help = true;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (arg === '--apply') {
|
|
153
|
+
parsed.apply = true;
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (arg === '--config' && next) {
|
|
157
|
+
parsed.configPath = next;
|
|
158
|
+
i += 1;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (arg === '--path' && next) {
|
|
162
|
+
parsed.path = next;
|
|
163
|
+
i += 1;
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
if (arg === '--tests-root' && next) {
|
|
167
|
+
parsed.testsRoot = next;
|
|
168
|
+
i += 1;
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
if (arg === '--framework' && next) {
|
|
172
|
+
parsed.framework = next;
|
|
173
|
+
i += 1;
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (arg === '--patterns' && next) {
|
|
177
|
+
parsed.testPatterns = next.split(',').map((value) => value.trim()).filter(Boolean);
|
|
178
|
+
i += 1;
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (arg === '--flow-patterns' && next) {
|
|
182
|
+
parsed.flowPatterns = next.split(',').map((value) => value.trim()).filter(Boolean);
|
|
183
|
+
i += 1;
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
if (arg === '--flow-exclude' && next) {
|
|
187
|
+
parsed.flowExclude = next.split(',').map((value) => value.trim()).filter(Boolean);
|
|
188
|
+
i += 1;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (arg === '--flow-catalog' && next) {
|
|
192
|
+
parsed.flowCatalogPath = next;
|
|
193
|
+
i += 1;
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
if (arg === '--allow-fallback') {
|
|
197
|
+
parsed.allowFallback = true;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (arg === '--pipeline') {
|
|
201
|
+
parsed.pipeline = true;
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
if (arg === '--pipeline-mcp') {
|
|
205
|
+
parsed.pipelineMcp = true;
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
if (arg === '--pipeline-scenarios' && next) {
|
|
209
|
+
const value = Number(next);
|
|
210
|
+
if (Number.isFinite(value)) {
|
|
211
|
+
parsed.pipelineScenarios = value;
|
|
212
|
+
}
|
|
213
|
+
i += 1;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
if (arg === '--pipeline-output' && next) {
|
|
217
|
+
parsed.pipelineOutput = next;
|
|
218
|
+
i += 1;
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
if (arg === '--pipeline-base-url' && next) {
|
|
222
|
+
parsed.pipelineBaseUrl = next;
|
|
223
|
+
i += 1;
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if (arg === '--pipeline-browser' && next) {
|
|
227
|
+
const value = next;
|
|
228
|
+
if (value === 'chrome' || value === 'chromium' || value === 'firefox' || value === 'webkit') {
|
|
229
|
+
parsed.pipelineBrowser = value;
|
|
230
|
+
}
|
|
231
|
+
i += 1;
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
if (arg === '--pipeline-headless') {
|
|
235
|
+
parsed.pipelineHeadless = true;
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
if (arg === '--pipeline-project' && next) {
|
|
239
|
+
parsed.pipelineProject = next;
|
|
240
|
+
i += 1;
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
if (arg === '--pipeline-parallel') {
|
|
244
|
+
parsed.pipelineParallel = true;
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
if (arg === '--pipeline-dry-run') {
|
|
248
|
+
parsed.pipelineDryRun = true;
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (arg === '--spec' && next) {
|
|
252
|
+
parsed.specPDF = next;
|
|
253
|
+
i += 1;
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
if (arg === '--since' && next) {
|
|
257
|
+
parsed.gitSince = next;
|
|
258
|
+
i += 1;
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
if (arg === '--time' && next) {
|
|
262
|
+
const value = Number(next);
|
|
263
|
+
if (Number.isFinite(value)) {
|
|
264
|
+
parsed.timeLimitMinutes = value;
|
|
265
|
+
}
|
|
266
|
+
i += 1;
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
if (arg === '--budget-usd' && next) {
|
|
270
|
+
const value = Number(next);
|
|
271
|
+
if (Number.isFinite(value)) {
|
|
272
|
+
parsed.budgetUSD = value;
|
|
273
|
+
}
|
|
274
|
+
i += 1;
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
if (arg === '--budget-tokens' && next) {
|
|
278
|
+
const value = Number(next);
|
|
279
|
+
if (Number.isFinite(value)) {
|
|
280
|
+
parsed.budgetTokens = value;
|
|
281
|
+
}
|
|
282
|
+
i += 1;
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
if (arg === '--policy-min-confidence' && next) {
|
|
286
|
+
const value = Number(next);
|
|
287
|
+
if (Number.isFinite(value)) {
|
|
288
|
+
parsed.policyMinConfidence = value;
|
|
289
|
+
}
|
|
290
|
+
i += 1;
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (arg === '--policy-safe-merge-confidence' && next) {
|
|
294
|
+
const value = Number(next);
|
|
295
|
+
if (Number.isFinite(value)) {
|
|
296
|
+
parsed.policySafeMergeConfidence = value;
|
|
297
|
+
}
|
|
298
|
+
i += 1;
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
if (arg === '--policy-force-full-on-warnings' && next) {
|
|
302
|
+
const value = Number(next);
|
|
303
|
+
if (Number.isFinite(value)) {
|
|
304
|
+
parsed.policyWarningsThreshold = value;
|
|
305
|
+
}
|
|
306
|
+
i += 1;
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
if (arg === '--policy-risky-patterns' && next) {
|
|
310
|
+
parsed.policyRiskyPatterns = next.split(',').map((value) => value.trim()).filter(Boolean);
|
|
311
|
+
i += 1;
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
if (arg === '--ci-comment-path' && next) {
|
|
315
|
+
parsed.ciCommentPath = next;
|
|
316
|
+
i += 1;
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
if (arg === '--github-output' && next) {
|
|
320
|
+
parsed.githubOutputPath = next;
|
|
321
|
+
i += 1;
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
if (arg === '--fail-on-must-add-tests') {
|
|
325
|
+
parsed.failOnMustAddTests = true;
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
if (arg === '--feedback-input' && next) {
|
|
329
|
+
parsed.feedbackInputPath = next;
|
|
330
|
+
i += 1;
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
if (arg === '--traceability-report' && next) {
|
|
334
|
+
parsed.traceabilityReportPath = next;
|
|
335
|
+
i += 1;
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
if (arg === '--traceability-capture-output' && next) {
|
|
339
|
+
parsed.traceabilityCaptureOutputPath = next;
|
|
340
|
+
i += 1;
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
if (arg === '--traceability-coverage-map' && next) {
|
|
344
|
+
parsed.traceabilityCoverageMapPath = next;
|
|
345
|
+
i += 1;
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
if (arg === '--traceability-changed-files' && next) {
|
|
349
|
+
parsed.traceabilityChangedFilesPath = next;
|
|
350
|
+
i += 1;
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
if (arg === '--traceability-input' && next) {
|
|
354
|
+
parsed.traceabilityInputPath = next;
|
|
355
|
+
i += 1;
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
if (arg === '--traceability-min-hits' && next) {
|
|
359
|
+
const value = Number(next);
|
|
360
|
+
if (Number.isFinite(value)) {
|
|
361
|
+
parsed.traceabilityMinHits = value;
|
|
362
|
+
}
|
|
363
|
+
i += 1;
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
if (arg === '--traceability-max-files-per-test' && next) {
|
|
367
|
+
const value = Number(next);
|
|
368
|
+
if (Number.isFinite(value)) {
|
|
369
|
+
parsed.traceabilityMaxFilesPerTest = value;
|
|
370
|
+
}
|
|
371
|
+
i += 1;
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
if (arg === '--traceability-max-age-days' && next) {
|
|
375
|
+
const value = Number(next);
|
|
376
|
+
if (Number.isFinite(value)) {
|
|
377
|
+
parsed.traceabilityMaxAgeDays = value;
|
|
378
|
+
}
|
|
379
|
+
i += 1;
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
if (arg === '--branch' && next) {
|
|
383
|
+
parsed.branch = next;
|
|
384
|
+
i += 1;
|
|
385
|
+
continue;
|
|
386
|
+
}
|
|
387
|
+
if (arg === '--commit-message' && next) {
|
|
388
|
+
parsed.commitMessage = next;
|
|
389
|
+
i += 1;
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
392
|
+
if (arg === '--create-pr') {
|
|
393
|
+
parsed.createPr = true;
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
if (arg === '--pr-title' && next) {
|
|
397
|
+
parsed.prTitle = next;
|
|
398
|
+
i += 1;
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
if (arg === '--pr-body' && next) {
|
|
402
|
+
parsed.prBody = next;
|
|
403
|
+
i += 1;
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
if (arg === '--pr-base' && next) {
|
|
407
|
+
parsed.prBase = next;
|
|
408
|
+
i += 1;
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
if (arg === '--dry-run') {
|
|
412
|
+
parsed.dryRun = true;
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
return parsed;
|
|
417
|
+
}
|
|
418
|
+
async function main() {
|
|
419
|
+
const args = parseArgs(process.argv.slice(2));
|
|
420
|
+
const autoConfig = resolveAutoConfig(args);
|
|
421
|
+
if (args.help || !args.command) {
|
|
422
|
+
printUsage();
|
|
423
|
+
process.exit(args.command ? 0 : 1);
|
|
424
|
+
}
|
|
425
|
+
if (args.command === 'llm-health') {
|
|
426
|
+
await runLlmHealth();
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
if (args.command === 'feedback') {
|
|
430
|
+
if (!args.path && !autoConfig) {
|
|
431
|
+
// eslint-disable-next-line no-console
|
|
432
|
+
console.error('Error: --path is required for feedback command');
|
|
433
|
+
process.exit(1);
|
|
434
|
+
}
|
|
435
|
+
if (!args.feedbackInputPath) {
|
|
436
|
+
// eslint-disable-next-line no-console
|
|
437
|
+
console.error('Error: --feedback-input <path> is required for feedback command');
|
|
438
|
+
process.exit(1);
|
|
439
|
+
}
|
|
440
|
+
const { config } = (0, config_js_1.resolveConfig)(process.cwd(), autoConfig, {
|
|
441
|
+
path: args.path,
|
|
442
|
+
testsRoot: args.testsRoot,
|
|
443
|
+
mode: 'impact',
|
|
444
|
+
});
|
|
445
|
+
const reportRoot = config.testsRoot || config.path;
|
|
446
|
+
const raw = JSON.parse((0, fs_1.readFileSync)(args.feedbackInputPath, 'utf-8'));
|
|
447
|
+
const payload = {
|
|
448
|
+
timestamp: raw.timestamp || new Date().toISOString(),
|
|
449
|
+
runSet: raw.runSet || 'targeted',
|
|
450
|
+
recommendedTests: raw.recommendedTests || [],
|
|
451
|
+
executedTests: raw.executedTests || [],
|
|
452
|
+
failedTests: raw.failedTests || [],
|
|
453
|
+
escapedFailures: raw.escapedFailures || [],
|
|
454
|
+
};
|
|
455
|
+
const output = (0, feedback_js_1.appendFeedbackAndRecompute)(reportRoot, payload);
|
|
456
|
+
// eslint-disable-next-line no-console
|
|
457
|
+
console.log(`Feedback data: ${output.feedbackPath}`);
|
|
458
|
+
// eslint-disable-next-line no-console
|
|
459
|
+
console.log(`Calibration data: ${output.calibrationPath}`);
|
|
460
|
+
// eslint-disable-next-line no-console
|
|
461
|
+
console.log(`Calibration overall: precision=${output.calibration.overall.precision}, recall=${output.calibration.overall.recall}, fnr=${output.calibration.overall.falseNegativeRate}`);
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
if (args.command === 'traceability-capture') {
|
|
465
|
+
if (!args.path && !autoConfig) {
|
|
466
|
+
// eslint-disable-next-line no-console
|
|
467
|
+
console.error('Error: --path is required for traceability-capture command');
|
|
468
|
+
process.exit(1);
|
|
469
|
+
}
|
|
470
|
+
if (!args.traceabilityReportPath) {
|
|
471
|
+
// eslint-disable-next-line no-console
|
|
472
|
+
console.error('Error: --traceability-report <path> is required for traceability-capture command');
|
|
473
|
+
process.exit(1);
|
|
474
|
+
}
|
|
475
|
+
const { config } = (0, config_js_1.resolveConfig)(process.cwd(), autoConfig, {
|
|
476
|
+
path: args.path,
|
|
477
|
+
testsRoot: args.testsRoot,
|
|
478
|
+
mode: 'impact',
|
|
479
|
+
gitSince: args.gitSince,
|
|
480
|
+
});
|
|
481
|
+
const reportRoot = config.testsRoot || config.path;
|
|
482
|
+
const output = (0, traceability_capture_js_1.captureTraceabilityInput)({
|
|
483
|
+
appPath: config.path,
|
|
484
|
+
testsRoot: reportRoot,
|
|
485
|
+
reportPath: args.traceabilityReportPath,
|
|
486
|
+
sinceRef: args.gitSince || config.git.since,
|
|
487
|
+
outputPath: args.traceabilityCaptureOutputPath,
|
|
488
|
+
coverageMapPath: args.traceabilityCoverageMapPath,
|
|
489
|
+
changedFilesPath: args.traceabilityChangedFilesPath,
|
|
490
|
+
});
|
|
491
|
+
// eslint-disable-next-line no-console
|
|
492
|
+
console.log(`Traceability input: ${output.outputPath}`);
|
|
493
|
+
// eslint-disable-next-line no-console
|
|
494
|
+
console.log(`Traceability tests seen: ${output.testsSeen}`);
|
|
495
|
+
// eslint-disable-next-line no-console
|
|
496
|
+
console.log(`Traceability runs generated: ${output.runsGenerated}`);
|
|
497
|
+
// eslint-disable-next-line no-console
|
|
498
|
+
console.log(`Traceability changed files used: ${output.changedFilesUsed}`);
|
|
499
|
+
if (output.warnings.length > 0) {
|
|
500
|
+
// eslint-disable-next-line no-console
|
|
501
|
+
console.log(`Traceability warnings: ${output.warnings.join(' | ')}`);
|
|
502
|
+
}
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
if (args.command === 'traceability-ingest') {
|
|
506
|
+
if (!args.path && !autoConfig) {
|
|
507
|
+
// eslint-disable-next-line no-console
|
|
508
|
+
console.error('Error: --path is required for traceability-ingest command');
|
|
509
|
+
process.exit(1);
|
|
510
|
+
}
|
|
511
|
+
if (!args.traceabilityInputPath) {
|
|
512
|
+
// eslint-disable-next-line no-console
|
|
513
|
+
console.error('Error: --traceability-input <path> is required for traceability-ingest command');
|
|
514
|
+
process.exit(1);
|
|
515
|
+
}
|
|
516
|
+
const { config } = (0, config_js_1.resolveConfig)(process.cwd(), autoConfig, {
|
|
517
|
+
path: args.path,
|
|
518
|
+
testsRoot: args.testsRoot,
|
|
519
|
+
mode: 'impact',
|
|
520
|
+
});
|
|
521
|
+
const reportRoot = config.testsRoot || config.path;
|
|
522
|
+
const raw = JSON.parse((0, fs_1.readFileSync)(args.traceabilityInputPath, 'utf-8'));
|
|
523
|
+
const output = (0, traceability_ingest_js_1.ingestTraceabilityInput)(reportRoot, config.impact.traceability, raw, {
|
|
524
|
+
minHits: args.traceabilityMinHits,
|
|
525
|
+
maxFilesPerTest: args.traceabilityMaxFilesPerTest,
|
|
526
|
+
maxAgeDays: args.traceabilityMaxAgeDays,
|
|
527
|
+
});
|
|
528
|
+
// eslint-disable-next-line no-console
|
|
529
|
+
console.log(`Traceability manifest: ${output.manifestPath}`);
|
|
530
|
+
// eslint-disable-next-line no-console
|
|
531
|
+
console.log(`Traceability state: ${output.statePath}`);
|
|
532
|
+
// eslint-disable-next-line no-console
|
|
533
|
+
console.log(`Traceability ingested entries: ${output.entriesIngested}`);
|
|
534
|
+
// eslint-disable-next-line no-console
|
|
535
|
+
console.log(`Traceability tracked tests: ${output.testsTracked}`);
|
|
536
|
+
// eslint-disable-next-line no-console
|
|
537
|
+
console.log(`Traceability tracked edges: ${output.edgesTracked}`);
|
|
538
|
+
if (output.warnings.length > 0) {
|
|
539
|
+
// eslint-disable-next-line no-console
|
|
540
|
+
console.log(`Traceability warnings: ${output.warnings.join(' | ')}`);
|
|
541
|
+
}
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
if (args.command === 'finalize-generated-tests') {
|
|
545
|
+
if (!args.path && !autoConfig) {
|
|
546
|
+
// eslint-disable-next-line no-console
|
|
547
|
+
console.error('Error: --path is required for finalize-generated-tests command');
|
|
548
|
+
process.exit(1);
|
|
549
|
+
}
|
|
550
|
+
const { config } = (0, config_js_1.resolveConfig)(process.cwd(), autoConfig, {
|
|
551
|
+
path: args.path,
|
|
552
|
+
testsRoot: args.testsRoot,
|
|
553
|
+
mode: 'gap',
|
|
554
|
+
});
|
|
555
|
+
const result = (0, handoff_js_1.finalizeGeneratedTests)({
|
|
556
|
+
appPath: config.path,
|
|
557
|
+
testsRoot: config.testsRoot || config.path,
|
|
558
|
+
branch: args.branch,
|
|
559
|
+
commitMessage: args.commitMessage,
|
|
560
|
+
createPr: args.createPr,
|
|
561
|
+
prTitle: args.prTitle,
|
|
562
|
+
prBody: args.prBody,
|
|
563
|
+
baseBranch: args.prBase,
|
|
564
|
+
dryRun: args.dryRun,
|
|
565
|
+
});
|
|
566
|
+
// eslint-disable-next-line no-console
|
|
567
|
+
console.log(`Finalize repo root: ${result.repoRoot}`);
|
|
568
|
+
// eslint-disable-next-line no-console
|
|
569
|
+
console.log(`Finalize branch: ${result.branch}`);
|
|
570
|
+
// eslint-disable-next-line no-console
|
|
571
|
+
console.log(`Finalize staged paths: ${result.stagedPaths.join(', ') || 'none'}`);
|
|
572
|
+
// eslint-disable-next-line no-console
|
|
573
|
+
console.log(`Finalize commit: ${result.committed ? 'created' : 'skipped'}`);
|
|
574
|
+
if (result.commitSha) {
|
|
575
|
+
// eslint-disable-next-line no-console
|
|
576
|
+
console.log(`Finalize commit sha: ${result.commitSha}`);
|
|
577
|
+
}
|
|
578
|
+
if (result.prUrl) {
|
|
579
|
+
// eslint-disable-next-line no-console
|
|
580
|
+
console.log(`Finalize PR: ${result.prUrl}`);
|
|
581
|
+
}
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
if (args.command === 'auto-heal-pr') {
|
|
585
|
+
if (!args.path && !autoConfig) {
|
|
586
|
+
// eslint-disable-next-line no-console
|
|
587
|
+
console.error('Error: --path is required for auto-heal-pr command');
|
|
588
|
+
process.exit(1);
|
|
589
|
+
}
|
|
590
|
+
const { config } = (0, config_js_1.resolveConfig)(process.cwd(), autoConfig, {
|
|
591
|
+
path: args.path,
|
|
592
|
+
testsRoot: args.testsRoot,
|
|
593
|
+
mode: 'gap',
|
|
594
|
+
framework: args.framework,
|
|
595
|
+
timeLimitMinutes: args.timeLimitMinutes,
|
|
596
|
+
budget: {
|
|
597
|
+
maxUSD: args.budgetUSD,
|
|
598
|
+
maxTokens: args.budgetTokens,
|
|
599
|
+
},
|
|
600
|
+
testPatterns: args.testPatterns,
|
|
601
|
+
flowPatterns: args.flowPatterns,
|
|
602
|
+
flowExclude: args.flowExclude,
|
|
603
|
+
flowCatalogPath: args.flowCatalogPath,
|
|
604
|
+
specPDF: args.specPDF,
|
|
605
|
+
gitSince: args.gitSince,
|
|
606
|
+
pipeline: {
|
|
607
|
+
enabled: true,
|
|
608
|
+
scenarios: args.pipelineScenarios,
|
|
609
|
+
outputDir: args.pipelineOutput,
|
|
610
|
+
baseUrl: args.pipelineBaseUrl,
|
|
611
|
+
browser: args.pipelineBrowser,
|
|
612
|
+
headless: args.pipelineHeadless,
|
|
613
|
+
project: args.pipelineProject,
|
|
614
|
+
parallel: args.pipelineParallel,
|
|
615
|
+
dryRun: args.pipelineDryRun,
|
|
616
|
+
mcp: args.pipelineMcp,
|
|
617
|
+
},
|
|
618
|
+
});
|
|
619
|
+
if (args.allowFallback) {
|
|
620
|
+
config.impact.allowFallback = true;
|
|
621
|
+
}
|
|
622
|
+
await (0, runner_js_1.runGap)(config, { apply: true });
|
|
623
|
+
const reportRoot = config.testsRoot || config.path;
|
|
624
|
+
if (args.traceabilityReportPath) {
|
|
625
|
+
const unstableSpecs = (0, playwright_report_js_1.extractPlaywrightUnstableSpecs)(args.traceabilityReportPath, [reportRoot, config.path]);
|
|
626
|
+
if (unstableSpecs.length > 0) {
|
|
627
|
+
const targetedSummary = (0, pipeline_js_1.runTargetedSpecHeal)(reportRoot, unstableSpecs.map((spec) => ({
|
|
628
|
+
specPath: spec.specPath,
|
|
629
|
+
status: spec.status,
|
|
630
|
+
reason: `Playwright report: failingTests=${spec.failingTests}, flakyTests=${spec.flakyTests}`,
|
|
631
|
+
})), {
|
|
632
|
+
...config.pipeline,
|
|
633
|
+
enabled: true,
|
|
634
|
+
heal: true,
|
|
635
|
+
});
|
|
636
|
+
const healedCount = targetedSummary.results.filter((result) => result.healStatus === 'success').length;
|
|
637
|
+
// eslint-disable-next-line no-console
|
|
638
|
+
console.log(`Auto-heal targeted unstable specs: ${unstableSpecs.length} (healed=${healedCount})`);
|
|
639
|
+
if (targetedSummary.warnings.length > 0) {
|
|
640
|
+
// eslint-disable-next-line no-console
|
|
641
|
+
console.log(`Auto-heal warnings: ${targetedSummary.warnings.join(' | ')}`);
|
|
642
|
+
}
|
|
643
|
+
const gapPath = (0, path_1.join)(reportRoot, '.e2e-ai-agents', 'gap.json');
|
|
644
|
+
if ((0, fs_1.existsSync)(gapPath)) {
|
|
645
|
+
const gap = JSON.parse((0, fs_1.readFileSync)(gapPath, 'utf-8'));
|
|
646
|
+
const existingResults = Array.isArray(gap.pipeline?.results) ? gap.pipeline?.results : [];
|
|
647
|
+
const existingWarnings = Array.isArray(gap.pipeline?.warnings) ? gap.pipeline?.warnings : [];
|
|
648
|
+
gap.pipeline = {
|
|
649
|
+
runner: gap.pipeline?.runner || targetedSummary.runner,
|
|
650
|
+
results: [...existingResults, ...targetedSummary.results],
|
|
651
|
+
warnings: Array.from(new Set([...(existingWarnings || []), ...targetedSummary.warnings])),
|
|
652
|
+
};
|
|
653
|
+
(0, fs_1.writeFileSync)(gapPath, `${JSON.stringify(gap, null, 2)}\n`, 'utf-8');
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
else {
|
|
657
|
+
// eslint-disable-next-line no-console
|
|
658
|
+
console.log('Auto-heal targeted unstable specs: 0');
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
const branchSuffix = new Date().toISOString().replace(/[:.]/g, '-');
|
|
662
|
+
const result = (0, handoff_js_1.finalizeGeneratedTests)({
|
|
663
|
+
appPath: config.path,
|
|
664
|
+
testsRoot: reportRoot,
|
|
665
|
+
branch: args.branch || `auto-heal-${branchSuffix}`,
|
|
666
|
+
commitMessage: args.commitMessage || 'test(e2e): auto-heal generated specs',
|
|
667
|
+
createPr: true,
|
|
668
|
+
prTitle: args.prTitle || 'test(e2e): auto-heal generated specs',
|
|
669
|
+
prBody: args.prBody || 'Automated e2e-heal run generated by @yasserkhanorg/e2e-agents.',
|
|
670
|
+
baseBranch: args.prBase || 'master',
|
|
671
|
+
dryRun: args.dryRun,
|
|
672
|
+
});
|
|
673
|
+
// eslint-disable-next-line no-console
|
|
674
|
+
console.log(`Auto-heal repo root: ${result.repoRoot}`);
|
|
675
|
+
// eslint-disable-next-line no-console
|
|
676
|
+
console.log(`Auto-heal branch: ${result.branch}`);
|
|
677
|
+
// eslint-disable-next-line no-console
|
|
678
|
+
console.log(`Auto-heal staged paths: ${result.stagedPaths.join(', ') || 'none'}`);
|
|
679
|
+
// eslint-disable-next-line no-console
|
|
680
|
+
console.log(`Auto-heal commit: ${result.committed ? 'created' : 'skipped'}`);
|
|
681
|
+
if (result.commitSha) {
|
|
682
|
+
// eslint-disable-next-line no-console
|
|
683
|
+
console.log(`Auto-heal commit sha: ${result.commitSha}`);
|
|
684
|
+
}
|
|
685
|
+
if (result.prUrl) {
|
|
686
|
+
// eslint-disable-next-line no-console
|
|
687
|
+
console.log(`Auto-heal PR: ${result.prUrl}`);
|
|
688
|
+
}
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
if (!args.path && !autoConfig) {
|
|
692
|
+
// eslint-disable-next-line no-console
|
|
693
|
+
console.error('Error: --path is required (or provide a config file with path set)');
|
|
694
|
+
printUsage();
|
|
695
|
+
process.exit(1);
|
|
696
|
+
}
|
|
697
|
+
const forcePipelineFromApproval = args.command === 'approve-and-generate';
|
|
698
|
+
const { config } = (0, config_js_1.resolveConfig)(process.cwd(), autoConfig, {
|
|
699
|
+
path: args.path,
|
|
700
|
+
testsRoot: args.testsRoot,
|
|
701
|
+
mode: (args.command === 'gap' || args.command === 'approve-and-generate') ? 'gap' : 'impact',
|
|
702
|
+
framework: args.framework,
|
|
703
|
+
timeLimitMinutes: args.timeLimitMinutes,
|
|
704
|
+
budget: {
|
|
705
|
+
maxUSD: args.budgetUSD,
|
|
706
|
+
maxTokens: args.budgetTokens,
|
|
707
|
+
},
|
|
708
|
+
testPatterns: args.testPatterns,
|
|
709
|
+
flowPatterns: args.flowPatterns,
|
|
710
|
+
flowExclude: args.flowExclude,
|
|
711
|
+
flowCatalogPath: args.flowCatalogPath,
|
|
712
|
+
specPDF: args.specPDF,
|
|
713
|
+
gitSince: args.gitSince,
|
|
714
|
+
pipeline: (args.pipeline || forcePipelineFromApproval)
|
|
715
|
+
? {
|
|
716
|
+
enabled: true,
|
|
717
|
+
scenarios: args.pipelineScenarios,
|
|
718
|
+
outputDir: args.pipelineOutput,
|
|
719
|
+
baseUrl: args.pipelineBaseUrl,
|
|
720
|
+
browser: args.pipelineBrowser,
|
|
721
|
+
headless: args.pipelineHeadless,
|
|
722
|
+
project: args.pipelineProject,
|
|
723
|
+
parallel: args.pipelineParallel,
|
|
724
|
+
dryRun: args.pipelineDryRun,
|
|
725
|
+
mcp: args.pipelineMcp !== undefined ? args.pipelineMcp : forcePipelineFromApproval,
|
|
726
|
+
}
|
|
727
|
+
: undefined,
|
|
728
|
+
policy: args.policyMinConfidence !== undefined ||
|
|
729
|
+
args.policySafeMergeConfidence !== undefined ||
|
|
730
|
+
args.policyWarningsThreshold !== undefined ||
|
|
731
|
+
(args.policyRiskyPatterns && args.policyRiskyPatterns.length > 0)
|
|
732
|
+
? {
|
|
733
|
+
minConfidenceForTargeted: args.policyMinConfidence,
|
|
734
|
+
safeMergeMinConfidence: args.policySafeMergeConfidence,
|
|
735
|
+
forceFullOnWarningsAtOrAbove: args.policyWarningsThreshold,
|
|
736
|
+
riskyFilePatterns: args.policyRiskyPatterns,
|
|
737
|
+
}
|
|
738
|
+
: undefined,
|
|
739
|
+
});
|
|
740
|
+
if (args.allowFallback) {
|
|
741
|
+
config.impact.allowFallback = true;
|
|
742
|
+
}
|
|
743
|
+
if (args.command === 'impact') {
|
|
744
|
+
await (0, runner_js_1.runImpact)(config, { apply: args.apply });
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
if (args.command === 'suggest') {
|
|
748
|
+
await (0, runner_js_1.runImpact)(config, { apply: args.apply });
|
|
749
|
+
const reportRoot = config.testsRoot || config.path;
|
|
750
|
+
const impactPath = (0, path_1.join)(reportRoot, '.e2e-ai-agents', 'impact.json');
|
|
751
|
+
if (!(0, fs_1.existsSync)(impactPath)) {
|
|
752
|
+
throw new Error(`Impact report not found at ${impactPath}`);
|
|
753
|
+
}
|
|
754
|
+
const impact = JSON.parse((0, fs_1.readFileSync)(impactPath, 'utf-8'));
|
|
755
|
+
const basePlan = (0, plan_js_1.buildPlanFromImpactReport)(impact, config.policy);
|
|
756
|
+
const withActions = (0, plan_js_1.attachDeveloperActions)(basePlan, {
|
|
757
|
+
appPath: config.path,
|
|
758
|
+
testsRoot: reportRoot,
|
|
759
|
+
sinceRef: config.git.since,
|
|
760
|
+
});
|
|
761
|
+
const plan = (0, operational_insights_js_1.applyOperationalInsights)(withActions, reportRoot);
|
|
762
|
+
const planPath = (0, plan_js_1.writePlanReport)(reportRoot, plan);
|
|
763
|
+
const summaryMarkdown = (0, plan_js_1.renderCiSummaryMarkdown)(plan);
|
|
764
|
+
const summaryPath = (0, plan_js_1.writeCiSummary)(reportRoot, summaryMarkdown, args.ciCommentPath);
|
|
765
|
+
const ghaOutput = args.githubOutputPath || process.env.GITHUB_OUTPUT;
|
|
766
|
+
if (ghaOutput) {
|
|
767
|
+
(0, fs_1.appendFileSync)(ghaOutput, `run_set=${plan.runSet}\n`);
|
|
768
|
+
(0, fs_1.appendFileSync)(ghaOutput, `action=${plan.decision.action}\n`);
|
|
769
|
+
(0, fs_1.appendFileSync)(ghaOutput, `confidence=${plan.confidence}\n`);
|
|
770
|
+
(0, fs_1.appendFileSync)(ghaOutput, `recommended_tests_count=${plan.recommendedTests.length}\n`);
|
|
771
|
+
(0, fs_1.appendFileSync)(ghaOutput, `required_new_tests_count=${plan.requiredNewTests.length}\n`);
|
|
772
|
+
(0, fs_1.appendFileSync)(ghaOutput, `plan_path=${planPath}\n`);
|
|
773
|
+
(0, fs_1.appendFileSync)(ghaOutput, `summary_path=${summaryPath}\n`);
|
|
774
|
+
}
|
|
775
|
+
// eslint-disable-next-line no-console
|
|
776
|
+
console.log(`Suggested run set: ${plan.runSet} (confidence ${plan.confidence})`);
|
|
777
|
+
// eslint-disable-next-line no-console
|
|
778
|
+
console.log(`Decision: ${plan.decision.action} - ${plan.decision.summary}`);
|
|
779
|
+
// eslint-disable-next-line no-console
|
|
780
|
+
console.log(`Plan data: ${planPath}`);
|
|
781
|
+
// eslint-disable-next-line no-console
|
|
782
|
+
console.log(`CI summary: ${summaryPath}`);
|
|
783
|
+
if (plan.nextActions) {
|
|
784
|
+
// eslint-disable-next-line no-console
|
|
785
|
+
console.log(`Next action (run existing): ${plan.nextActions.runRecommendedTests || plan.nextActions.runSmokeSuite}`);
|
|
786
|
+
// eslint-disable-next-line no-console
|
|
787
|
+
console.log(`Next action (approve + generate): ${plan.nextActions.approveAndGenerate || plan.nextActions.generateMissingTests}`);
|
|
788
|
+
// eslint-disable-next-line no-console
|
|
789
|
+
console.log(`Next action (heal): ${plan.nextActions.healGeneratedTests}`);
|
|
790
|
+
}
|
|
791
|
+
if (args.failOnMustAddTests && plan.decision.action === 'must-add-tests') {
|
|
792
|
+
process.exit(2);
|
|
793
|
+
}
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
if (args.command === 'approve-and-generate') {
|
|
797
|
+
await (0, runner_js_1.runGap)(config, { apply: true });
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
await (0, runner_js_1.runGap)(config, { apply: args.apply });
|
|
801
|
+
}
|
|
802
|
+
async function runLlmHealth() {
|
|
803
|
+
if (!process.env.ANTHROPIC_API_KEY) {
|
|
804
|
+
// eslint-disable-next-line no-console
|
|
805
|
+
console.error('ANTHROPIC_API_KEY is required for llm-health.');
|
|
806
|
+
process.exit(1);
|
|
807
|
+
}
|
|
808
|
+
const model = process.env.ANTHROPIC_MODEL || 'claude-sonnet-4-5-20250929';
|
|
809
|
+
const provider = new anthropic_provider_js_1.AnthropicProvider({
|
|
810
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
811
|
+
model,
|
|
812
|
+
});
|
|
813
|
+
try {
|
|
814
|
+
const response = await provider.generateText('Reply with OK.', { maxTokens: 8, timeout: 15000 });
|
|
815
|
+
const text = response.text.trim();
|
|
816
|
+
// eslint-disable-next-line no-console
|
|
817
|
+
console.log(`Anthropic OK (${model}) -> ${text}`);
|
|
818
|
+
}
|
|
819
|
+
catch (error) {
|
|
820
|
+
if (error instanceof provider_interface_js_1.LLMProviderError) {
|
|
821
|
+
// eslint-disable-next-line no-console
|
|
822
|
+
console.error(`Anthropic failed: ${error.message}`);
|
|
823
|
+
if (error.cause instanceof Error) {
|
|
824
|
+
// eslint-disable-next-line no-console
|
|
825
|
+
console.error(`Cause: ${error.cause.message}`);
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
else if (error instanceof Error) {
|
|
829
|
+
// eslint-disable-next-line no-console
|
|
830
|
+
console.error(`Anthropic failed: ${error.message}`);
|
|
831
|
+
}
|
|
832
|
+
else {
|
|
833
|
+
// eslint-disable-next-line no-console
|
|
834
|
+
console.error(`Anthropic failed: ${String(error)}`);
|
|
835
|
+
}
|
|
836
|
+
process.exit(1);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
main().catch((error) => {
|
|
840
|
+
// eslint-disable-next-line no-console
|
|
841
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
842
|
+
process.exit(1);
|
|
843
|
+
});
|