@vertaaux/cli 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +345 -0
- package/dist/auth/ci-token.d.ts +49 -0
- package/dist/auth/ci-token.d.ts.map +1 -0
- package/dist/auth/ci-token.js +83 -0
- package/dist/auth/device-flow.d.ts +66 -0
- package/dist/auth/device-flow.d.ts.map +1 -0
- package/dist/auth/device-flow.js +156 -0
- package/dist/auth/token-store.d.ts +53 -0
- package/dist/auth/token-store.d.ts.map +1 -0
- package/dist/auth/token-store.js +78 -0
- package/dist/baseline/diff.d.ts +57 -0
- package/dist/baseline/diff.d.ts.map +1 -0
- package/dist/baseline/diff.js +152 -0
- package/dist/baseline/hash.d.ts +54 -0
- package/dist/baseline/hash.d.ts.map +1 -0
- package/dist/baseline/hash.js +66 -0
- package/dist/baseline/manager.d.ts +89 -0
- package/dist/baseline/manager.d.ts.map +1 -0
- package/dist/baseline/manager.js +157 -0
- package/dist/cache/index.d.ts +8 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +7 -0
- package/dist/cache/route-cache.d.ts +119 -0
- package/dist/cache/route-cache.d.ts.map +1 -0
- package/dist/cache/route-cache.js +213 -0
- package/dist/ci/changed-routes.d.ts +95 -0
- package/dist/ci/changed-routes.d.ts.map +1 -0
- package/dist/ci/changed-routes.js +304 -0
- package/dist/ci/github-api.d.ts +68 -0
- package/dist/ci/github-api.d.ts.map +1 -0
- package/dist/ci/github-api.js +138 -0
- package/dist/ci/gitlab-api.d.ts +75 -0
- package/dist/ci/gitlab-api.d.ts.map +1 -0
- package/dist/ci/gitlab-api.js +180 -0
- package/dist/ci/index.d.ts +6 -0
- package/dist/ci/index.d.ts.map +1 -0
- package/dist/ci/index.js +4 -0
- package/dist/commands/audit.d.ts +58 -0
- package/dist/commands/audit.d.ts.map +1 -0
- package/dist/commands/audit.js +862 -0
- package/dist/commands/baseline.d.ts +22 -0
- package/dist/commands/baseline.d.ts.map +1 -0
- package/dist/commands/baseline.js +210 -0
- package/dist/commands/comment.d.ts +14 -0
- package/dist/commands/comment.d.ts.map +1 -0
- package/dist/commands/comment.js +363 -0
- package/dist/commands/diff.d.ts +24 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +196 -0
- package/dist/commands/doctor.d.ts +58 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +338 -0
- package/dist/commands/download.d.ts +12 -0
- package/dist/commands/download.d.ts.map +1 -0
- package/dist/commands/download.js +183 -0
- package/dist/commands/explain.d.ts +62 -0
- package/dist/commands/explain.d.ts.map +1 -0
- package/dist/commands/explain.js +302 -0
- package/dist/commands/init.d.ts +12 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +212 -0
- package/dist/commands/login.d.ts +14 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +222 -0
- package/dist/commands/policy.d.ts +13 -0
- package/dist/commands/policy.d.ts.map +1 -0
- package/dist/commands/policy.js +347 -0
- package/dist/commands/upload.d.ts +12 -0
- package/dist/commands/upload.d.ts.map +1 -0
- package/dist/commands/upload.js +158 -0
- package/dist/config/defaults.d.ts +21 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +49 -0
- package/dist/config/loader.d.ts +66 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +167 -0
- package/dist/config/schema.d.ts +55 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +6 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1090 -0
- package/dist/interactive/fix-wizard.d.ts +44 -0
- package/dist/interactive/fix-wizard.d.ts.map +1 -0
- package/dist/interactive/fix-wizard.js +286 -0
- package/dist/interactive/init-wizard.d.ts +32 -0
- package/dist/interactive/init-wizard.d.ts.map +1 -0
- package/dist/interactive/init-wizard.js +193 -0
- package/dist/interactive/prompts.d.ts +62 -0
- package/dist/interactive/prompts.d.ts.map +1 -0
- package/dist/interactive/prompts.js +78 -0
- package/dist/monorepo/detector.d.ts +70 -0
- package/dist/monorepo/detector.d.ts.map +1 -0
- package/dist/monorepo/detector.js +278 -0
- package/dist/monorepo/index.d.ts +9 -0
- package/dist/monorepo/index.d.ts.map +1 -0
- package/dist/monorepo/index.js +8 -0
- package/dist/monorepo/workspace.d.ts +142 -0
- package/dist/monorepo/workspace.d.ts.map +1 -0
- package/dist/monorepo/workspace.js +171 -0
- package/dist/output/envelope.d.ts +21 -0
- package/dist/output/envelope.d.ts.map +1 -0
- package/dist/output/envelope.js +27 -0
- package/dist/output/factory.d.ts +73 -0
- package/dist/output/factory.d.ts.map +1 -0
- package/dist/output/factory.js +60 -0
- package/dist/output/formats.d.ts +11 -0
- package/dist/output/formats.d.ts.map +1 -0
- package/dist/output/formats.js +41 -0
- package/dist/output/html.d.ts +45 -0
- package/dist/output/html.d.ts.map +1 -0
- package/dist/output/html.js +607 -0
- package/dist/output/human.d.ts +41 -0
- package/dist/output/human.d.ts.map +1 -0
- package/dist/output/human.js +274 -0
- package/dist/output/json.d.ts +42 -0
- package/dist/output/json.d.ts.map +1 -0
- package/dist/output/json.js +37 -0
- package/dist/output/junit.d.ts +56 -0
- package/dist/output/junit.d.ts.map +1 -0
- package/dist/output/junit.js +135 -0
- package/dist/output/markdown.d.ts +77 -0
- package/dist/output/markdown.d.ts.map +1 -0
- package/dist/output/markdown.js +411 -0
- package/dist/output/sarif.d.ts +160 -0
- package/dist/output/sarif.d.ts.map +1 -0
- package/dist/output/sarif.js +207 -0
- package/dist/policy/evaluator.d.ts +111 -0
- package/dist/policy/evaluator.d.ts.map +1 -0
- package/dist/policy/evaluator.js +362 -0
- package/dist/policy/index.d.ts +15 -0
- package/dist/policy/index.d.ts.map +1 -0
- package/dist/policy/index.js +11 -0
- package/dist/policy/loader.d.ts +97 -0
- package/dist/policy/loader.d.ts.map +1 -0
- package/dist/policy/loader.js +281 -0
- package/dist/policy/schema.d.ts +297 -0
- package/dist/policy/schema.d.ts.map +1 -0
- package/dist/policy/schema.js +230 -0
- package/dist/quality-gate/evaluator.d.ts +58 -0
- package/dist/quality-gate/evaluator.d.ts.map +1 -0
- package/dist/quality-gate/evaluator.js +274 -0
- package/dist/quality-gate/index.d.ts +10 -0
- package/dist/quality-gate/index.d.ts.map +1 -0
- package/dist/quality-gate/index.js +7 -0
- package/dist/quality-gate/types.d.ts +103 -0
- package/dist/quality-gate/types.d.ts.map +1 -0
- package/dist/quality-gate/types.js +23 -0
- package/dist/templates/azure-devops.d.ts +25 -0
- package/dist/templates/azure-devops.d.ts.map +1 -0
- package/dist/templates/azure-devops.js +109 -0
- package/dist/templates/circleci.d.ts +28 -0
- package/dist/templates/circleci.d.ts.map +1 -0
- package/dist/templates/circleci.js +86 -0
- package/dist/templates/github-actions.d.ts +81 -0
- package/dist/templates/github-actions.d.ts.map +1 -0
- package/dist/templates/github-actions.js +393 -0
- package/dist/templates/gitlab-ci.d.ts +26 -0
- package/dist/templates/gitlab-ci.d.ts.map +1 -0
- package/dist/templates/gitlab-ci.js +70 -0
- package/dist/templates/index.d.ts +72 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/templates/index.js +112 -0
- package/dist/templates/jenkins.d.ts +26 -0
- package/dist/templates/jenkins.d.ts.map +1 -0
- package/dist/templates/jenkins.js +110 -0
- package/dist/ui/banner.d.ts +31 -0
- package/dist/ui/banner.d.ts.map +1 -0
- package/dist/ui/banner.js +84 -0
- package/dist/ui/diagnostics.d.ts +39 -0
- package/dist/ui/diagnostics.d.ts.map +1 -0
- package/dist/ui/diagnostics.js +153 -0
- package/dist/ui/spinner.d.ts +61 -0
- package/dist/ui/spinner.d.ts.map +1 -0
- package/dist/ui/spinner.js +101 -0
- package/dist/ui/table.d.ts +63 -0
- package/dist/ui/table.d.ts.map +1 -0
- package/dist/ui/table.js +236 -0
- package/dist/utils/client.d.ts +82 -0
- package/dist/utils/client.d.ts.map +1 -0
- package/dist/utils/client.js +128 -0
- package/dist/utils/detect-env.d.ts +59 -0
- package/dist/utils/detect-env.d.ts.map +1 -0
- package/dist/utils/detect-env.js +115 -0
- package/dist/utils/exit-codes.d.ts +47 -0
- package/dist/utils/exit-codes.d.ts.map +1 -0
- package/dist/utils/exit-codes.js +61 -0
- package/dist/utils/logger.d.ts +87 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +185 -0
- package/dist/utils/sanitize.d.ts +36 -0
- package/dist/utils/sanitize.d.ts.map +1 -0
- package/dist/utils/sanitize.js +64 -0
- package/dist/utils/validators.d.ts +41 -0
- package/dist/utils/validators.d.ts.map +1 -0
- package/dist/utils/validators.js +123 -0
- package/package.json +63 -0
- package/schemas/vertaaux.config.schema.json +103 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive fix wizard for stepping through issues one by one.
|
|
3
|
+
*
|
|
4
|
+
* Provides a guided workflow to:
|
|
5
|
+
* - Review issues sorted by severity
|
|
6
|
+
* - Accept fix suggestions with diff preview
|
|
7
|
+
* - Skip issues
|
|
8
|
+
* - Add issues to baseline
|
|
9
|
+
* - Get detailed explanations
|
|
10
|
+
*
|
|
11
|
+
* CLI-09: vertaa audit --interactive steps through fixes
|
|
12
|
+
*/
|
|
13
|
+
import { type EvidenceIssue } from "../commands/explain.js";
|
|
14
|
+
import type { Issue } from "../baseline/hash.js";
|
|
15
|
+
import type { VertaauxConfig } from "../config/schema.js";
|
|
16
|
+
/**
|
|
17
|
+
* Options for running the fix wizard.
|
|
18
|
+
*/
|
|
19
|
+
export interface FixWizardOptions {
|
|
20
|
+
/** Audit job ID for fetching patches */
|
|
21
|
+
jobId?: string;
|
|
22
|
+
/** URL that was audited (for baseline) */
|
|
23
|
+
url: string;
|
|
24
|
+
/** API base URL override */
|
|
25
|
+
base?: string;
|
|
26
|
+
/** Config for API key */
|
|
27
|
+
config?: VertaauxConfig;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Run the interactive fix wizard.
|
|
31
|
+
*
|
|
32
|
+
* Steps through issues one by one, offering:
|
|
33
|
+
* - Accept fix suggestion
|
|
34
|
+
* - Skip this issue
|
|
35
|
+
* - Explain in detail
|
|
36
|
+
* - Add to baseline
|
|
37
|
+
* - Quit wizard
|
|
38
|
+
*
|
|
39
|
+
* @param issues - Issues from audit results
|
|
40
|
+
* @param options - Wizard options
|
|
41
|
+
* @returns Promise that resolves when wizard completes
|
|
42
|
+
*/
|
|
43
|
+
export declare function runFixWizard(issues: (Issue | EvidenceIssue)[], options: FixWizardOptions): Promise<void>;
|
|
44
|
+
//# sourceMappingURL=fix-wizard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fix-wizard.d.ts","sourceRoot":"","sources":["../../src/interactive/fix-wizard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAS1E,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAOjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAqB1D;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,GAAG,EAAE,MAAM,CAAC;IACZ,4BAA4B;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yBAAyB;IACzB,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB;AAwHD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,CAAC,KAAK,GAAG,aAAa,CAAC,EAAE,EACjC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,IAAI,CAAC,CA4Mf"}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive fix wizard for stepping through issues one by one.
|
|
3
|
+
*
|
|
4
|
+
* Provides a guided workflow to:
|
|
5
|
+
* - Review issues sorted by severity
|
|
6
|
+
* - Accept fix suggestions with diff preview
|
|
7
|
+
* - Skip issues
|
|
8
|
+
* - Add issues to baseline
|
|
9
|
+
* - Get detailed explanations
|
|
10
|
+
*
|
|
11
|
+
* CLI-09: vertaa audit --interactive steps through fixes
|
|
12
|
+
*/
|
|
13
|
+
import { select, confirm, input } from "@inquirer/prompts";
|
|
14
|
+
import chalk from "chalk";
|
|
15
|
+
import { explainIssue } from "../commands/explain.js";
|
|
16
|
+
import { loadBaseline, saveBaseline, createBaseline, addToBaseline, DEFAULT_BASELINE_PATH, } from "../baseline/manager.js";
|
|
17
|
+
import { requireInteractive } from "./prompts.js";
|
|
18
|
+
import { resolveApiBase, getApiKey, apiRequest, } from "../utils/client.js";
|
|
19
|
+
/**
|
|
20
|
+
* Get severity display with color.
|
|
21
|
+
*/
|
|
22
|
+
function coloredSeverity(severity) {
|
|
23
|
+
const sev = (severity || "info").toLowerCase();
|
|
24
|
+
switch (sev) {
|
|
25
|
+
case "critical":
|
|
26
|
+
case "error":
|
|
27
|
+
return chalk.red.bold(sev.toUpperCase());
|
|
28
|
+
case "serious":
|
|
29
|
+
case "warning":
|
|
30
|
+
return chalk.yellow.bold(sev.toUpperCase());
|
|
31
|
+
case "moderate":
|
|
32
|
+
case "minor":
|
|
33
|
+
return chalk.cyan(sev.toUpperCase());
|
|
34
|
+
default:
|
|
35
|
+
return chalk.dim(sev.toUpperCase());
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get severity rank for sorting (higher = more severe).
|
|
40
|
+
*/
|
|
41
|
+
function severityRank(severity) {
|
|
42
|
+
const sev = (severity || "info").toLowerCase();
|
|
43
|
+
switch (sev) {
|
|
44
|
+
case "critical":
|
|
45
|
+
case "error":
|
|
46
|
+
return 4;
|
|
47
|
+
case "serious":
|
|
48
|
+
case "warning":
|
|
49
|
+
return 3;
|
|
50
|
+
case "moderate":
|
|
51
|
+
case "minor":
|
|
52
|
+
return 2;
|
|
53
|
+
default:
|
|
54
|
+
return 1;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get rule ID from issue.
|
|
59
|
+
*/
|
|
60
|
+
function getRuleId(issue) {
|
|
61
|
+
return issue.ruleId || issue.rule_id || issue.id || "unknown";
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Format a diff for display.
|
|
65
|
+
*/
|
|
66
|
+
function formatDiff(search, replace) {
|
|
67
|
+
const lines = [];
|
|
68
|
+
lines.push(chalk.dim("--- before"));
|
|
69
|
+
lines.push(chalk.dim("+++ after"));
|
|
70
|
+
lines.push(chalk.dim("@@ -1,1 +1,1 @@"));
|
|
71
|
+
lines.push(chalk.red(`-${search}`));
|
|
72
|
+
lines.push(chalk.green(`+${replace}`));
|
|
73
|
+
return lines.join("\n");
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Display issue summary for wizard.
|
|
77
|
+
*/
|
|
78
|
+
function displayIssueSummary(issue, index, total) {
|
|
79
|
+
const ruleId = getRuleId(issue);
|
|
80
|
+
const severity = coloredSeverity(issue.severity);
|
|
81
|
+
console.log("");
|
|
82
|
+
console.log(chalk.bold(`[${index + 1}/${total}] ${severity}: ${ruleId}`));
|
|
83
|
+
console.log(issue.description || issue.title || "No description");
|
|
84
|
+
console.log(chalk.dim(`Selector: ${issue.selector || "N/A"}`));
|
|
85
|
+
if (issue.wcag_reference) {
|
|
86
|
+
console.log(chalk.dim(`WCAG: ${issue.wcag_reference}`));
|
|
87
|
+
}
|
|
88
|
+
console.log("");
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Fetch patch suggestion from API.
|
|
92
|
+
*/
|
|
93
|
+
async function fetchPatchSuggestion(jobId, issueId, base, apiKey) {
|
|
94
|
+
try {
|
|
95
|
+
const response = await apiRequest(base, "/patch", {
|
|
96
|
+
method: "POST",
|
|
97
|
+
body: {
|
|
98
|
+
job_id: jobId,
|
|
99
|
+
issue_id: issueId,
|
|
100
|
+
// Note: file_content not required for suggestion preview
|
|
101
|
+
},
|
|
102
|
+
}, apiKey);
|
|
103
|
+
if (response.success && response.patch) {
|
|
104
|
+
return response.patch;
|
|
105
|
+
}
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Run the interactive fix wizard.
|
|
114
|
+
*
|
|
115
|
+
* Steps through issues one by one, offering:
|
|
116
|
+
* - Accept fix suggestion
|
|
117
|
+
* - Skip this issue
|
|
118
|
+
* - Explain in detail
|
|
119
|
+
* - Add to baseline
|
|
120
|
+
* - Quit wizard
|
|
121
|
+
*
|
|
122
|
+
* @param issues - Issues from audit results
|
|
123
|
+
* @param options - Wizard options
|
|
124
|
+
* @returns Promise that resolves when wizard completes
|
|
125
|
+
*/
|
|
126
|
+
export async function runFixWizard(issues, options) {
|
|
127
|
+
// Require interactive TTY
|
|
128
|
+
requireInteractive();
|
|
129
|
+
if (issues.length === 0) {
|
|
130
|
+
console.log(chalk.green("\nNo issues to review. Great job!"));
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
// Sort issues by severity (critical first)
|
|
134
|
+
const sortedIssues = [...issues].sort((a, b) => severityRank(b.severity) - severityRank(a.severity));
|
|
135
|
+
console.log(chalk.bold(`\nFound ${sortedIssues.length} issues to review:\n`));
|
|
136
|
+
// Load or create baseline
|
|
137
|
+
let baseline = await loadBaseline();
|
|
138
|
+
if (!baseline) {
|
|
139
|
+
baseline = createBaseline([], options.url);
|
|
140
|
+
}
|
|
141
|
+
// Track stats
|
|
142
|
+
let accepted = 0;
|
|
143
|
+
let skipped = 0;
|
|
144
|
+
let baselined = 0;
|
|
145
|
+
// Resolve API settings
|
|
146
|
+
const base = resolveApiBase(options.base);
|
|
147
|
+
let apiKey = null;
|
|
148
|
+
try {
|
|
149
|
+
apiKey = getApiKey(options.config?.apiKey);
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
// API key not available - patches won't work but other actions will
|
|
153
|
+
}
|
|
154
|
+
// Process each issue
|
|
155
|
+
let i = 0;
|
|
156
|
+
while (i < sortedIssues.length) {
|
|
157
|
+
const issue = sortedIssues[i];
|
|
158
|
+
displayIssueSummary(issue, i, sortedIssues.length);
|
|
159
|
+
const action = await select({
|
|
160
|
+
message: "Action:",
|
|
161
|
+
choices: [
|
|
162
|
+
{
|
|
163
|
+
name: "Accept fix suggestion",
|
|
164
|
+
value: "accept",
|
|
165
|
+
description: "View and apply the suggested fix",
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
name: "Skip this issue",
|
|
169
|
+
value: "skip",
|
|
170
|
+
description: "Move to the next issue",
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
name: "Explain in detail",
|
|
174
|
+
value: "explain",
|
|
175
|
+
description: "Show full evidence bundle",
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: "Add to baseline",
|
|
179
|
+
value: "baseline",
|
|
180
|
+
description: "Mark as accepted technical debt",
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
name: "Quit wizard",
|
|
184
|
+
value: "quit",
|
|
185
|
+
description: "Exit without processing remaining issues",
|
|
186
|
+
},
|
|
187
|
+
],
|
|
188
|
+
});
|
|
189
|
+
switch (action) {
|
|
190
|
+
case "accept": {
|
|
191
|
+
// Try to fetch and show patch suggestion
|
|
192
|
+
if (options.jobId && apiKey) {
|
|
193
|
+
console.log(chalk.dim("\nFetching fix suggestion..."));
|
|
194
|
+
const patch = await fetchPatchSuggestion(options.jobId, getRuleId(issue), base, apiKey);
|
|
195
|
+
if (patch) {
|
|
196
|
+
console.log("");
|
|
197
|
+
console.log(chalk.bold(`SUGGESTED FIX (Confidence: ${patch.confidence.label} ${patch.confidence.percentage}%)`));
|
|
198
|
+
console.log("");
|
|
199
|
+
console.log(formatDiff(patch.search, patch.replace));
|
|
200
|
+
console.log("");
|
|
201
|
+
if (patch.explanation) {
|
|
202
|
+
console.log(chalk.dim(patch.explanation));
|
|
203
|
+
console.log("");
|
|
204
|
+
}
|
|
205
|
+
const applyFix = await confirm({
|
|
206
|
+
message: "Apply this fix?",
|
|
207
|
+
default: true,
|
|
208
|
+
});
|
|
209
|
+
if (applyFix) {
|
|
210
|
+
// Note: Actual file modification is deferred to future version
|
|
211
|
+
console.log(chalk.green("Fix accepted (would apply in future version)"));
|
|
212
|
+
accepted++;
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
console.log(chalk.dim("Fix declined, moving to next issue"));
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
console.log(chalk.yellow("\nNo fix suggestion available for this issue."));
|
|
220
|
+
const skipOrBaseline = await select({
|
|
221
|
+
message: "What would you like to do?",
|
|
222
|
+
choices: [
|
|
223
|
+
{ name: "Skip to next issue", value: "skip" },
|
|
224
|
+
{ name: "Add to baseline", value: "baseline" },
|
|
225
|
+
],
|
|
226
|
+
});
|
|
227
|
+
if (skipOrBaseline === "baseline") {
|
|
228
|
+
const reason = await input({
|
|
229
|
+
message: "Reason for baseline (optional):",
|
|
230
|
+
});
|
|
231
|
+
baseline = addToBaseline(baseline, issue, reason || undefined);
|
|
232
|
+
await saveBaseline(baseline, DEFAULT_BASELINE_PATH);
|
|
233
|
+
console.log(chalk.dim("Added to baseline"));
|
|
234
|
+
baselined++;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
console.log(chalk.yellow("\nFix suggestions require a job ID and API key."));
|
|
240
|
+
console.log(chalk.dim("Run with `vertaa audit <url> --wait --interactive` for full functionality."));
|
|
241
|
+
}
|
|
242
|
+
i++;
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
245
|
+
case "skip":
|
|
246
|
+
skipped++;
|
|
247
|
+
i++;
|
|
248
|
+
break;
|
|
249
|
+
case "explain": {
|
|
250
|
+
// Show full evidence bundle
|
|
251
|
+
console.log("");
|
|
252
|
+
console.log(explainIssue(issue));
|
|
253
|
+
console.log("");
|
|
254
|
+
// Don't increment i - stay on same issue to pick another action
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
case "baseline": {
|
|
258
|
+
const reason = await input({
|
|
259
|
+
message: "Reason for baseline (optional):",
|
|
260
|
+
});
|
|
261
|
+
baseline = addToBaseline(baseline, issue, reason || undefined);
|
|
262
|
+
await saveBaseline(baseline, DEFAULT_BASELINE_PATH);
|
|
263
|
+
console.log(chalk.dim("Added to baseline"));
|
|
264
|
+
baselined++;
|
|
265
|
+
i++;
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
case "quit":
|
|
269
|
+
console.log("");
|
|
270
|
+
console.log(chalk.bold("Wizard Summary:"));
|
|
271
|
+
console.log(` Accepted: ${accepted}`);
|
|
272
|
+
console.log(` Skipped: ${skipped}`);
|
|
273
|
+
console.log(` Baselined: ${baselined}`);
|
|
274
|
+
console.log(` Remaining: ${sortedIssues.length - i}`);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
// Summary
|
|
279
|
+
console.log("");
|
|
280
|
+
console.log(chalk.bold.green("All issues reviewed!"));
|
|
281
|
+
console.log("");
|
|
282
|
+
console.log(chalk.bold("Summary:"));
|
|
283
|
+
console.log(` Accepted: ${accepted}`);
|
|
284
|
+
console.log(` Skipped: ${skipped}`);
|
|
285
|
+
console.log(` Baselined: ${baselined}`);
|
|
286
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive wizard for `vertaa init` command.
|
|
3
|
+
*
|
|
4
|
+
* Guides users through project setup with sensible defaults.
|
|
5
|
+
*/
|
|
6
|
+
import type { AuditMode, FailOnSeverity, CITemplate } from "../config/schema.js";
|
|
7
|
+
/**
|
|
8
|
+
* Configuration generated by the init wizard.
|
|
9
|
+
*/
|
|
10
|
+
export interface InitConfig {
|
|
11
|
+
/** Default URL to audit */
|
|
12
|
+
defaultUrl?: string;
|
|
13
|
+
/** Audit mode */
|
|
14
|
+
mode: AuditMode;
|
|
15
|
+
/** Fail on severity level */
|
|
16
|
+
failOn: FailOnSeverity | "none";
|
|
17
|
+
/** Minimum score threshold (0 = disabled) */
|
|
18
|
+
threshold: number;
|
|
19
|
+
/** Auto-update baseline on main branch */
|
|
20
|
+
autoUpdateBaseline: boolean;
|
|
21
|
+
/** CI provider for template generation */
|
|
22
|
+
ciProvider: CITemplate;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Run the interactive init wizard.
|
|
26
|
+
*
|
|
27
|
+
* Guides user through configuration options and returns the chosen settings.
|
|
28
|
+
*
|
|
29
|
+
* @returns Configuration object for writing to file
|
|
30
|
+
*/
|
|
31
|
+
export declare function runInitWizard(): Promise<InitConfig>;
|
|
32
|
+
//# sourceMappingURL=init-wizard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-wizard.d.ts","sourceRoot":"","sources":["../../src/interactive/init-wizard.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjF;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,2BAA2B;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB;IACjB,IAAI,EAAE,SAAS,CAAC;IAChB,6BAA6B;IAC7B,MAAM,EAAE,cAAc,GAAG,MAAM,CAAC;IAChC,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,kBAAkB,EAAE,OAAO,CAAC;IAC5B,0CAA0C;IAC1C,UAAU,EAAE,UAAU,CAAC;CACxB;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC,CAgMzD"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive wizard for `vertaa init` command.
|
|
3
|
+
*
|
|
4
|
+
* Guides users through project setup with sensible defaults.
|
|
5
|
+
*/
|
|
6
|
+
import { select, confirm, input } from "@inquirer/prompts";
|
|
7
|
+
/**
|
|
8
|
+
* Run the interactive init wizard.
|
|
9
|
+
*
|
|
10
|
+
* Guides user through configuration options and returns the chosen settings.
|
|
11
|
+
*
|
|
12
|
+
* @returns Configuration object for writing to file
|
|
13
|
+
*/
|
|
14
|
+
export async function runInitWizard() {
|
|
15
|
+
console.log("\n Welcome to VertaaUX!\n");
|
|
16
|
+
console.log(" This wizard will help you configure VertaaUX for your project.\n");
|
|
17
|
+
// Step 1: Default URL
|
|
18
|
+
const defaultUrl = await input({
|
|
19
|
+
message: "What URL would you like to audit? (optional)",
|
|
20
|
+
default: "",
|
|
21
|
+
validate: (value) => {
|
|
22
|
+
if (!value)
|
|
23
|
+
return true; // Optional
|
|
24
|
+
try {
|
|
25
|
+
new URL(value);
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return "Please enter a valid URL (e.g., https://example.com)";
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
// Step 2: Audit mode
|
|
34
|
+
const mode = await select({
|
|
35
|
+
message: "Select audit mode:",
|
|
36
|
+
choices: [
|
|
37
|
+
{
|
|
38
|
+
name: "Basic - Quick scan for common issues",
|
|
39
|
+
value: "basic",
|
|
40
|
+
description: "Fastest, covers essential accessibility and UX checks",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: "Standard - Comprehensive analysis",
|
|
44
|
+
value: "standard",
|
|
45
|
+
description: "Balanced depth and speed, recommended for most projects",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: "Deep - Thorough multi-page audit",
|
|
49
|
+
value: "deep",
|
|
50
|
+
description: "Most thorough, includes page flow and cross-page issues",
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
default: "standard",
|
|
54
|
+
});
|
|
55
|
+
// Step 3: Configure baseline rules
|
|
56
|
+
const configureBaseline = await confirm({
|
|
57
|
+
message: "Configure baseline rules? (controls CI failure conditions)",
|
|
58
|
+
default: true,
|
|
59
|
+
});
|
|
60
|
+
let failOn = "error";
|
|
61
|
+
let threshold = 0;
|
|
62
|
+
let autoUpdateBaseline = false;
|
|
63
|
+
if (configureBaseline) {
|
|
64
|
+
// Step 3a: Fail-on severity
|
|
65
|
+
failOn = await select({
|
|
66
|
+
message: "Fail CI build when issues of this severity are found:",
|
|
67
|
+
choices: [
|
|
68
|
+
{
|
|
69
|
+
name: "Error - Only critical/error severity",
|
|
70
|
+
value: "error",
|
|
71
|
+
description: "Strictest, blocks on critical issues only",
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: "Warning - Warnings and above",
|
|
75
|
+
value: "warning",
|
|
76
|
+
description: "Blocks on warning and error severity",
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: "Info - Any issues",
|
|
80
|
+
value: "info",
|
|
81
|
+
description: "Most strict, blocks on all issues",
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: "None - Never fail on issues",
|
|
85
|
+
value: "none",
|
|
86
|
+
description: "Report only, never fail CI",
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
default: "error",
|
|
90
|
+
});
|
|
91
|
+
// Step 3b: Score threshold
|
|
92
|
+
const setThreshold = await confirm({
|
|
93
|
+
message: "Set a minimum score threshold?",
|
|
94
|
+
default: false,
|
|
95
|
+
});
|
|
96
|
+
if (setThreshold) {
|
|
97
|
+
const thresholdStr = await input({
|
|
98
|
+
message: "Minimum passing score (0-100):",
|
|
99
|
+
default: "70",
|
|
100
|
+
validate: (value) => {
|
|
101
|
+
const num = parseInt(value, 10);
|
|
102
|
+
if (isNaN(num) || num < 0 || num > 100) {
|
|
103
|
+
return "Please enter a number between 0 and 100";
|
|
104
|
+
}
|
|
105
|
+
return true;
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
threshold = parseInt(thresholdStr, 10);
|
|
109
|
+
}
|
|
110
|
+
// Step 3c: Auto-update baseline
|
|
111
|
+
autoUpdateBaseline = await confirm({
|
|
112
|
+
message: "Auto-update baseline when issues are fixed on main branch?",
|
|
113
|
+
default: false,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
// Step 4: CI integration
|
|
117
|
+
const configureCI = await confirm({
|
|
118
|
+
message: "Configure CI integration?",
|
|
119
|
+
default: true,
|
|
120
|
+
});
|
|
121
|
+
let ciProvider = "none";
|
|
122
|
+
if (configureCI) {
|
|
123
|
+
ciProvider = await select({
|
|
124
|
+
message: "Which CI provider?",
|
|
125
|
+
choices: [
|
|
126
|
+
{
|
|
127
|
+
name: "GitHub Actions",
|
|
128
|
+
value: "github",
|
|
129
|
+
description: "Creates .github/workflows/vertaa.yml with SARIF upload",
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
name: "GitLab CI",
|
|
133
|
+
value: "gitlab",
|
|
134
|
+
description: "Creates .gitlab-ci-vertaa.yml with JUnit and Code Quality reports",
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: "CircleCI",
|
|
138
|
+
value: "circleci",
|
|
139
|
+
description: "Creates .circleci/config-vertaa.yml with test results",
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
name: "Azure DevOps",
|
|
143
|
+
value: "azure",
|
|
144
|
+
description: "Creates azure-pipelines-vertaa.yml with Advanced Security",
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
name: "Jenkins",
|
|
148
|
+
value: "jenkins",
|
|
149
|
+
description: "Creates Jenkinsfile-vertaa with Warnings NG plugin",
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
name: "None - Skip CI setup",
|
|
153
|
+
value: "none",
|
|
154
|
+
},
|
|
155
|
+
],
|
|
156
|
+
default: "github",
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
// Step 5: Summary
|
|
160
|
+
console.log("\n Configuration Summary:");
|
|
161
|
+
console.log(" ----------------------");
|
|
162
|
+
if (defaultUrl) {
|
|
163
|
+
console.log(` URL: ${defaultUrl}`);
|
|
164
|
+
}
|
|
165
|
+
console.log(` Mode: ${mode}`);
|
|
166
|
+
console.log(` Fail on: ${failOn}`);
|
|
167
|
+
if (threshold > 0) {
|
|
168
|
+
console.log(` Threshold: ${threshold}`);
|
|
169
|
+
}
|
|
170
|
+
if (autoUpdateBaseline) {
|
|
171
|
+
console.log(` Auto-update: enabled`);
|
|
172
|
+
}
|
|
173
|
+
if (ciProvider !== "none") {
|
|
174
|
+
console.log(` CI: ${ciProvider}`);
|
|
175
|
+
}
|
|
176
|
+
console.log("");
|
|
177
|
+
// Step 6: Confirm
|
|
178
|
+
const create = await confirm({
|
|
179
|
+
message: "Create configuration?",
|
|
180
|
+
default: true,
|
|
181
|
+
});
|
|
182
|
+
if (!create) {
|
|
183
|
+
throw new Error("Configuration cancelled by user");
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
defaultUrl: defaultUrl || undefined,
|
|
187
|
+
mode,
|
|
188
|
+
failOn,
|
|
189
|
+
threshold,
|
|
190
|
+
autoUpdateBaseline,
|
|
191
|
+
ciProvider,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reusable prompt patterns for interactive CLI mode.
|
|
3
|
+
*
|
|
4
|
+
* Wraps @inquirer/prompts with consistent styling.
|
|
5
|
+
* Keyboard navigation is handled natively by @inquirer/prompts:
|
|
6
|
+
* - Arrow keys for navigation
|
|
7
|
+
* - Enter to confirm
|
|
8
|
+
* - Space to select (multi-select)
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Choice option for select prompts.
|
|
12
|
+
*/
|
|
13
|
+
export interface SelectChoice<T = string> {
|
|
14
|
+
/** Display name */
|
|
15
|
+
name: string;
|
|
16
|
+
/** Return value when selected */
|
|
17
|
+
value: T;
|
|
18
|
+
/** Optional description shown below the choice */
|
|
19
|
+
description?: string;
|
|
20
|
+
/** Mark as disabled (shows but can't select) */
|
|
21
|
+
disabled?: boolean | string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Prompt user to select from a list of options.
|
|
25
|
+
*
|
|
26
|
+
* Uses arrow keys for navigation, Enter to confirm.
|
|
27
|
+
*
|
|
28
|
+
* @param message - Prompt message
|
|
29
|
+
* @param choices - List of options
|
|
30
|
+
* @returns Selected value
|
|
31
|
+
*/
|
|
32
|
+
export declare function selectAction<T = string>(message: string, choices: SelectChoice<T>[]): Promise<T>;
|
|
33
|
+
/**
|
|
34
|
+
* Prompt user for yes/no confirmation.
|
|
35
|
+
*
|
|
36
|
+
* @param message - Question to confirm
|
|
37
|
+
* @param defaultValue - Default value if user just presses Enter
|
|
38
|
+
* @returns true for yes, false for no
|
|
39
|
+
*/
|
|
40
|
+
export declare function confirmAction(message: string, defaultValue?: boolean): Promise<boolean>;
|
|
41
|
+
/**
|
|
42
|
+
* Prompt user for text input.
|
|
43
|
+
*
|
|
44
|
+
* @param message - Prompt message
|
|
45
|
+
* @param defaultValue - Optional default value
|
|
46
|
+
* @param required - Whether input is required (default: false)
|
|
47
|
+
* @returns User input string
|
|
48
|
+
*/
|
|
49
|
+
export declare function inputText(message: string, defaultValue?: string, required?: boolean): Promise<string>;
|
|
50
|
+
/**
|
|
51
|
+
* Check if running in an interactive TTY environment.
|
|
52
|
+
*
|
|
53
|
+
* @returns true if stdin/stdout are TTY
|
|
54
|
+
*/
|
|
55
|
+
export declare function isInteractive(): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Assert that the environment is interactive, throwing if not.
|
|
58
|
+
*
|
|
59
|
+
* @throws Error if not in interactive TTY mode
|
|
60
|
+
*/
|
|
61
|
+
export declare function requireInteractive(): void;
|
|
62
|
+
//# sourceMappingURL=prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/interactive/prompts.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,MAAM;IACtC,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,KAAK,EAAE,CAAC,CAAC;IACT,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CAC7B;AAED;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAAC,CAAC,GAAG,MAAM,EAC3C,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,GACzB,OAAO,CAAC,CAAC,CAAC,CAUZ;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,YAAY,GAAE,OAAc,GAC3B,OAAO,CAAC,OAAO,CAAC,CAKlB;AAED;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAC7B,OAAO,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,MAAM,EACrB,QAAQ,GAAE,OAAe,GACxB,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAMzC"}
|