@vertaaux/cli 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +116 -0
- package/MIGRATION.md +239 -0
- package/README.md +62 -17
- package/dist/app/interactive-app.d.ts +103 -0
- package/dist/app/interactive-app.d.ts.map +1 -0
- package/dist/app/interactive-app.js +328 -0
- package/dist/app/layout/canvas.d.ts +23 -0
- package/dist/app/layout/canvas.d.ts.map +1 -0
- package/dist/app/layout/canvas.js +36 -0
- package/dist/app/layout/footer.d.ts +31 -0
- package/dist/app/layout/footer.d.ts.map +1 -0
- package/dist/app/layout/footer.js +41 -0
- package/dist/app/layout/header.d.ts +20 -0
- package/dist/app/layout/header.d.ts.map +1 -0
- package/dist/app/layout/header.js +27 -0
- package/dist/app/menu/categories.d.ts +20 -0
- package/dist/app/menu/categories.d.ts.map +1 -0
- package/dist/app/menu/categories.js +166 -0
- package/dist/app/menu/filter.d.ts +17 -0
- package/dist/app/menu/filter.d.ts.map +1 -0
- package/dist/app/menu/filter.js +33 -0
- package/dist/app/menu/menu-view.d.ts +35 -0
- package/dist/app/menu/menu-view.d.ts.map +1 -0
- package/dist/app/menu/menu-view.js +230 -0
- package/dist/app/menu/recent.d.ts +24 -0
- package/dist/app/menu/recent.d.ts.map +1 -0
- package/dist/app/menu/recent.js +49 -0
- package/dist/app/types.d.ts +43 -0
- package/dist/app/types.d.ts.map +1 -0
- package/dist/app/types.js +7 -0
- package/dist/app/views/command-runner.d.ts +36 -0
- package/dist/app/views/command-runner.d.ts.map +1 -0
- package/dist/app/views/command-runner.js +415 -0
- package/dist/app/views/help-overlay.d.ts +21 -0
- package/dist/app/views/help-overlay.d.ts.map +1 -0
- package/dist/app/views/help-overlay.js +46 -0
- package/dist/auth/ci-token.d.ts +8 -2
- package/dist/auth/ci-token.d.ts.map +1 -1
- package/dist/auth/ci-token.js +15 -30
- package/dist/auth/device-flow.d.ts +2 -1
- package/dist/auth/device-flow.d.ts.map +1 -1
- package/dist/auth/device-flow.js +13 -10
- package/dist/auth/token-store.d.ts.map +1 -1
- package/dist/auth/token-store.js +12 -2
- package/dist/baseline/diff.d.ts +2 -2
- package/dist/baseline/diff.d.ts.map +1 -1
- package/dist/baseline/diff.js +15 -34
- package/dist/commands/a11y.d.ts +11 -0
- package/dist/commands/a11y.d.ts.map +1 -0
- package/dist/commands/a11y.js +149 -0
- package/dist/commands/audit/artifacts.d.ts +27 -0
- package/dist/commands/audit/artifacts.d.ts.map +1 -0
- package/dist/commands/audit/artifacts.js +158 -0
- package/dist/commands/audit/ci-detection.d.ts +18 -0
- package/dist/commands/audit/ci-detection.d.ts.map +1 -0
- package/dist/commands/audit/ci-detection.js +71 -0
- package/dist/commands/audit/explain.d.ts +11 -0
- package/dist/commands/audit/explain.d.ts.map +1 -0
- package/dist/commands/audit/explain.js +45 -0
- package/dist/commands/audit/filters.d.ts +17 -0
- package/dist/commands/audit/filters.d.ts.map +1 -0
- package/dist/commands/audit/filters.js +40 -0
- package/dist/commands/audit/index.d.ts +18 -0
- package/dist/commands/audit/index.d.ts.map +1 -0
- package/dist/commands/audit/index.js +589 -0
- package/dist/commands/audit/output.d.ts +32 -0
- package/dist/commands/audit/output.d.ts.map +1 -0
- package/dist/commands/audit/output.js +129 -0
- package/dist/commands/audit/policy.d.ts +27 -0
- package/dist/commands/audit/policy.d.ts.map +1 -0
- package/dist/commands/audit/policy.js +147 -0
- package/dist/commands/audit/scoring.d.ts +23 -0
- package/dist/commands/audit/scoring.d.ts.map +1 -0
- package/dist/commands/audit/scoring.js +70 -0
- package/dist/commands/audit/types.d.ts +89 -0
- package/dist/commands/audit/types.d.ts.map +1 -0
- package/dist/commands/audit/types.js +8 -0
- package/dist/commands/audit.d.ts +2 -60
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +2 -1097
- package/dist/commands/baseline.d.ts +2 -0
- package/dist/commands/baseline.d.ts.map +1 -1
- package/dist/commands/baseline.js +221 -123
- package/dist/commands/comment.d.ts +22 -0
- package/dist/commands/comment.d.ts.map +1 -1
- package/dist/commands/comment.js +127 -62
- package/dist/commands/compare.d.ts +17 -0
- package/dist/commands/compare.d.ts.map +1 -1
- package/dist/commands/compare.js +288 -181
- package/dist/commands/diff.d.ts +7 -0
- package/dist/commands/diff.d.ts.map +1 -1
- package/dist/commands/diff.js +181 -143
- package/dist/commands/doc.d.ts +10 -0
- package/dist/commands/doc.d.ts.map +1 -1
- package/dist/commands/doc.js +135 -77
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +166 -19
- package/dist/commands/download.d.ts +10 -0
- package/dist/commands/download.d.ts.map +1 -1
- package/dist/commands/download.js +169 -112
- package/dist/commands/explain.d.ts +5 -0
- package/dist/commands/explain.d.ts.map +1 -1
- package/dist/commands/explain.js +242 -156
- package/dist/commands/fix-all.d.ts +25 -0
- package/dist/commands/fix-all.d.ts.map +1 -0
- package/dist/commands/fix-all.js +206 -0
- package/dist/commands/fix-plan.d.ts +9 -0
- package/dist/commands/fix-plan.d.ts.map +1 -1
- package/dist/commands/fix-plan.js +154 -90
- package/dist/commands/fix.d.ts +17 -0
- package/dist/commands/fix.d.ts.map +1 -0
- package/dist/commands/fix.js +111 -0
- package/dist/commands/init.d.ts +11 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +94 -42
- package/dist/commands/login.d.ts +18 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +263 -92
- package/dist/commands/patch-review.d.ts +11 -0
- package/dist/commands/patch-review.d.ts.map +1 -1
- package/dist/commands/patch-review.js +160 -98
- package/dist/commands/policy.d.ts +31 -0
- package/dist/commands/policy.d.ts.map +1 -1
- package/dist/commands/policy.js +270 -125
- package/dist/commands/release-notes.d.ts +10 -0
- package/dist/commands/release-notes.d.ts.map +1 -1
- package/dist/commands/release-notes.js +128 -74
- package/dist/commands/scan.d.ts +13 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +133 -0
- package/dist/commands/status.d.ts +9 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +81 -0
- package/dist/commands/suggest.d.ts +10 -0
- package/dist/commands/suggest.d.ts.map +1 -1
- package/dist/commands/suggest.js +180 -83
- package/dist/commands/triage.d.ts +35 -0
- package/dist/commands/triage.d.ts.map +1 -1
- package/dist/commands/triage.js +207 -82
- package/dist/commands/upload.d.ts +9 -0
- package/dist/commands/upload.d.ts.map +1 -1
- package/dist/commands/upload.js +140 -101
- package/dist/commands/verify.d.ts +13 -0
- package/dist/commands/verify.d.ts.map +1 -0
- package/dist/commands/verify.js +118 -0
- package/dist/config/schema.d.ts +4 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +127 -991
- package/dist/interactive/fix-wizard.d.ts +3 -0
- package/dist/interactive/fix-wizard.d.ts.map +1 -1
- package/dist/interactive/fix-wizard.js +130 -112
- package/dist/interactive/init-wizard.d.ts +3 -1
- package/dist/interactive/init-wizard.d.ts.map +1 -1
- package/dist/interactive/init-wizard.js +207 -138
- package/dist/interactive/prompts.d.ts +7 -3
- package/dist/interactive/prompts.d.ts.map +1 -1
- package/dist/interactive/prompts.js +44 -23
- package/dist/output/envelope.d.ts +9 -0
- package/dist/output/envelope.d.ts.map +1 -1
- package/dist/output/envelope.js +37 -3
- package/dist/output/factory.d.ts +2 -1
- package/dist/output/factory.d.ts.map +1 -1
- package/dist/output/html.d.ts +2 -1
- package/dist/output/html.d.ts.map +1 -1
- package/dist/output/html.js +3 -2
- package/dist/output/human.d.ts +2 -1
- package/dist/output/human.d.ts.map +1 -1
- package/dist/output/human.js +3 -2
- package/dist/output/json.d.ts +2 -1
- package/dist/output/json.d.ts.map +1 -1
- package/dist/output/junit.d.ts +2 -1
- package/dist/output/junit.d.ts.map +1 -1
- package/dist/output/sarif.d.ts +2 -1
- package/dist/output/sarif.d.ts.map +1 -1
- package/dist/policy/schema.d.ts +137 -0
- package/dist/policy/schema.d.ts.map +1 -1
- package/dist/policy/schema.js +107 -0
- package/dist/prompts/command-catalog.js +9 -9
- package/dist/types.d.ts +74 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/ui/banner.d.ts +34 -0
- package/dist/ui/banner.d.ts.map +1 -1
- package/dist/ui/banner.js +97 -5
- package/dist/ui/diagnostics.d.ts +9 -4
- package/dist/ui/diagnostics.d.ts.map +1 -1
- package/dist/ui/diagnostics.js +32 -82
- package/dist/ui/strings.d.ts +373 -0
- package/dist/ui/strings.d.ts.map +1 -0
- package/dist/ui/strings.js +499 -0
- package/dist/ui/table.d.ts +0 -2
- package/dist/ui/table.d.ts.map +1 -1
- package/dist/ui/table.js +3 -4
- package/dist/utils/api-client.d.ts +46 -0
- package/dist/utils/api-client.d.ts.map +1 -0
- package/dist/utils/api-client.js +170 -0
- package/dist/utils/client.d.ts +29 -18
- package/dist/utils/client.d.ts.map +1 -1
- package/dist/utils/client.js +104 -12
- package/dist/utils/formatters.d.ts +38 -0
- package/dist/utils/formatters.d.ts.map +1 -0
- package/dist/utils/formatters.js +277 -0
- package/dist/utils/root-args.d.ts +12 -0
- package/dist/utils/root-args.d.ts.map +1 -0
- package/dist/utils/root-args.js +44 -0
- package/dist/utils/stdin.d.ts +7 -0
- package/dist/utils/stdin.d.ts.map +1 -1
- package/dist/utils/stdin.js +32 -2
- package/dist/utils/url-classify.d.ts.map +1 -1
- package/dist/utils/url-classify.js +24 -3
- package/node_modules/@vertaaux/tui/dist/index.cjs +1216 -27
- package/node_modules/@vertaaux/tui/dist/index.cjs.map +1 -1
- package/node_modules/@vertaaux/tui/dist/index.d.cts +361 -4
- package/node_modules/@vertaaux/tui/dist/index.d.ts +361 -4
- package/node_modules/@vertaaux/tui/dist/index.js +1189 -27
- package/node_modules/@vertaaux/tui/dist/index.js.map +1 -1
- package/node_modules/@vertaaux/tui/package.json +2 -3
- package/node_modules/chalk/license +9 -0
- package/node_modules/chalk/package.json +83 -0
- package/node_modules/chalk/readme.md +297 -0
- package/node_modules/chalk/source/index.d.ts +325 -0
- package/node_modules/chalk/source/index.js +225 -0
- package/node_modules/chalk/source/utilities.js +33 -0
- package/node_modules/chalk/source/vendor/ansi-styles/index.d.ts +236 -0
- package/node_modules/chalk/source/vendor/ansi-styles/index.js +223 -0
- package/node_modules/chalk/source/vendor/supports-color/browser.d.ts +1 -0
- package/node_modules/chalk/source/vendor/supports-color/browser.js +34 -0
- package/node_modules/chalk/source/vendor/supports-color/index.d.ts +55 -0
- package/node_modules/chalk/source/vendor/supports-color/index.js +190 -0
- package/package.json +20 -5
- package/dist/commands/client.d.ts +0 -14
- package/dist/commands/client.d.ts.map +0 -1
- package/dist/commands/client.js +0 -362
- package/dist/commands/drift.d.ts +0 -15
- package/dist/commands/drift.d.ts.map +0 -1
- package/dist/commands/drift.js +0 -309
- package/dist/commands/protect.d.ts +0 -16
- package/dist/commands/protect.d.ts.map +0 -1
- package/dist/commands/protect.js +0 -323
- package/dist/commands/report.d.ts +0 -15
- package/dist/commands/report.d.ts.map +0 -1
- package/dist/commands/report.js +0 -214
- package/dist/policy/sync.d.ts +0 -67
- package/dist/policy/sync.d.ts.map +0 -1
- package/dist/policy/sync.js +0 -147
package/dist/commands/explain.js
CHANGED
|
@@ -17,15 +17,15 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import fs from "fs";
|
|
19
19
|
import path from "path";
|
|
20
|
-
import
|
|
20
|
+
import { bold, dim, colorize, boldColor, brand, severity as severityPalette, renderError, createRenderer, runSteps } from "@vertaaux/tui";
|
|
21
21
|
import { ExitCode } from "../utils/exit-codes.js";
|
|
22
|
-
import { resolveApiBase, getApiKey, apiRequest } from "../utils/client.js";
|
|
22
|
+
import { resolveApiBase, getApiKey, apiRequest, createClient } from "../utils/client.js";
|
|
23
23
|
import { resolveConfig } from "../config/loader.js";
|
|
24
|
-
import {
|
|
24
|
+
import { writeDataOutput, writeJsonOutput } from "../output/envelope.js";
|
|
25
25
|
import { resolveCommandFormat } from "../output/formats.js";
|
|
26
|
-
import { createSpinner, succeedSpinner } from "../ui/spinner.js";
|
|
27
26
|
import { readJsonInput } from "../utils/stdin.js";
|
|
28
|
-
import {
|
|
27
|
+
import { AI_TIMEOUT_MS } from "../utils/ai-error.js";
|
|
28
|
+
import { strings } from "../ui/strings.js";
|
|
29
29
|
// ---------------------------------------------------------------------------
|
|
30
30
|
// Constants
|
|
31
31
|
// ---------------------------------------------------------------------------
|
|
@@ -61,15 +61,15 @@ function coloredSeverity(severity) {
|
|
|
61
61
|
switch (sev) {
|
|
62
62
|
case "critical":
|
|
63
63
|
case "error":
|
|
64
|
-
return
|
|
64
|
+
return boldColor(sev.toUpperCase(), severityPalette.error);
|
|
65
65
|
case "serious":
|
|
66
66
|
case "warning":
|
|
67
|
-
return
|
|
67
|
+
return boldColor(sev.toUpperCase(), severityPalette.warning);
|
|
68
68
|
case "moderate":
|
|
69
69
|
case "minor":
|
|
70
|
-
return
|
|
70
|
+
return colorize(sev.toUpperCase(), brand.cyan);
|
|
71
71
|
default:
|
|
72
|
-
return
|
|
72
|
+
return dim(sev.toUpperCase());
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
function truncate(str, maxLength) {
|
|
@@ -87,37 +87,37 @@ export function formatEvidenceBundle(issue) {
|
|
|
87
87
|
const lines = [];
|
|
88
88
|
const ruleId = getRuleId(issue);
|
|
89
89
|
const severity = coloredSeverity(issue.severity);
|
|
90
|
-
lines.push(
|
|
90
|
+
lines.push(bold(`ISSUE: ${ruleId} (${severity})`));
|
|
91
91
|
lines.push("");
|
|
92
|
-
lines.push(
|
|
92
|
+
lines.push(boldColor("DESCRIPTION", brand.cyan));
|
|
93
93
|
lines.push(issue.description || issue.title || "No description available");
|
|
94
94
|
lines.push("");
|
|
95
95
|
if (issue.selector) {
|
|
96
|
-
lines.push(
|
|
97
|
-
lines.push(
|
|
96
|
+
lines.push(boldColor("SELECTOR", brand.cyan));
|
|
97
|
+
lines.push(dim(issue.selector));
|
|
98
98
|
lines.push("");
|
|
99
99
|
}
|
|
100
100
|
if (issue.wcag_reference) {
|
|
101
|
-
lines.push(
|
|
101
|
+
lines.push(boldColor("WCAG REFERENCE", brand.cyan));
|
|
102
102
|
lines.push(issue.wcag_reference);
|
|
103
103
|
lines.push("");
|
|
104
104
|
}
|
|
105
105
|
const recommendation = issue.recommendation || issue.recommended_fix;
|
|
106
106
|
if (recommendation) {
|
|
107
|
-
lines.push(
|
|
107
|
+
lines.push(boldColor("RECOMMENDATION", brand.cyan));
|
|
108
108
|
lines.push(recommendation);
|
|
109
109
|
lines.push("");
|
|
110
110
|
}
|
|
111
111
|
const hasEvidence = issue.screenshot || issue.html || issue.element || issue.helpUrl;
|
|
112
112
|
if (hasEvidence) {
|
|
113
|
-
lines.push(
|
|
113
|
+
lines.push(boldColor("EVIDENCE", brand.cyan));
|
|
114
114
|
if (issue.screenshot)
|
|
115
|
-
lines.push(`- Screenshot: ${
|
|
115
|
+
lines.push(`- Screenshot: ${issue.screenshot}`);
|
|
116
116
|
if (issue.html || issue.element) {
|
|
117
|
-
lines.push(`- DOM Snapshot: ${
|
|
117
|
+
lines.push(`- DOM Snapshot: ${dim(truncate(issue.html || issue.element || "", 100))}`);
|
|
118
118
|
}
|
|
119
119
|
if (issue.helpUrl)
|
|
120
|
-
lines.push(`- Help: ${
|
|
120
|
+
lines.push(`- Help: ${issue.helpUrl}`);
|
|
121
121
|
}
|
|
122
122
|
return lines.join("\n");
|
|
123
123
|
}
|
|
@@ -147,27 +147,27 @@ export function explainIssue(issue) {
|
|
|
147
147
|
function formatAiExplainHuman(response, verbose, issues) {
|
|
148
148
|
const lines = [];
|
|
149
149
|
// 3-bullet summary
|
|
150
|
-
lines.push(
|
|
150
|
+
lines.push(bold("Summary"));
|
|
151
151
|
for (const bullet of response.summary) {
|
|
152
|
-
lines.push(` ${
|
|
152
|
+
lines.push(` ${colorize(">", brand.cyan)} ${bullet}`);
|
|
153
153
|
}
|
|
154
154
|
lines.push("");
|
|
155
155
|
// Issues grouped by severity
|
|
156
|
-
lines.push(
|
|
156
|
+
lines.push(bold("Issues"));
|
|
157
157
|
lines.push("");
|
|
158
158
|
for (const issue of response.issues) {
|
|
159
159
|
const severity = coloredSeverity(issue.severity);
|
|
160
|
-
lines.push(` ${severity} ${
|
|
160
|
+
lines.push(` ${severity} ${bold(issue.title)}${issue.id ? dim(` (${issue.id})`) : ""}`);
|
|
161
161
|
lines.push(` ${issue.explanation}`);
|
|
162
|
-
lines.push(` ${
|
|
162
|
+
lines.push(` ${colorize("Fix:", brand.lime)} ${issue.fix}`);
|
|
163
163
|
if (verbose && issues) {
|
|
164
164
|
// Find the matching original issue for full evidence
|
|
165
165
|
const original = issues.find((i) => getRuleId(i) === issue.id || i.id === issue.id);
|
|
166
166
|
if (original) {
|
|
167
167
|
if (original.selector)
|
|
168
|
-
lines.push(` ${
|
|
168
|
+
lines.push(` ${dim("Selector:")} ${original.selector}`);
|
|
169
169
|
if (original.wcag_reference)
|
|
170
|
-
lines.push(` ${
|
|
170
|
+
lines.push(` ${dim("WCAG:")} ${original.wcag_reference}`);
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
173
|
lines.push("");
|
|
@@ -177,13 +177,12 @@ function formatAiExplainHuman(response, verbose, issues) {
|
|
|
177
177
|
// ---------------------------------------------------------------------------
|
|
178
178
|
// Evidence mode handler (backward compat)
|
|
179
179
|
// ---------------------------------------------------------------------------
|
|
180
|
-
async function
|
|
180
|
+
async function resolveEvidenceIssue(findingId, options, config) {
|
|
181
181
|
let issue = null;
|
|
182
182
|
if (options.file) {
|
|
183
183
|
const filePath = path.resolve(process.cwd(), options.file);
|
|
184
184
|
if (!fs.existsSync(filePath)) {
|
|
185
|
-
|
|
186
|
-
process.exit(ExitCode.ERROR);
|
|
185
|
+
throw new Error(strings.explain.errors.fileNotFound(filePath));
|
|
187
186
|
}
|
|
188
187
|
const data = JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
189
188
|
let issues;
|
|
@@ -206,9 +205,8 @@ async function handleEvidenceMode(findingId, options, config, format) {
|
|
|
206
205
|
}
|
|
207
206
|
}
|
|
208
207
|
else if (options.job) {
|
|
209
|
-
const
|
|
210
|
-
const
|
|
211
|
-
const result = await apiRequest(base, `/audit/${options.job}`, { method: "GET" }, apiKey);
|
|
208
|
+
const sdkClient = createClient({ base: options.base, apiKey: config.apiKey });
|
|
209
|
+
const result = await sdkClient.audits.retrieve(options.job);
|
|
212
210
|
const issues = normalizeIssues(result.issues);
|
|
213
211
|
issue = issues.find((i) => i.id === findingId ||
|
|
214
212
|
getRuleId(i) === findingId ||
|
|
@@ -218,14 +216,12 @@ async function handleEvidenceMode(findingId, options, config, format) {
|
|
|
218
216
|
else {
|
|
219
217
|
const recent = loadRecentAudits();
|
|
220
218
|
if (recent.length === 0) {
|
|
221
|
-
|
|
222
|
-
process.exit(ExitCode.ERROR);
|
|
219
|
+
throw new Error(strings.explain.errors.noRecentAudits);
|
|
223
220
|
}
|
|
224
|
-
const
|
|
225
|
-
const apiKey = getApiKey(config.apiKey);
|
|
221
|
+
const sdkClient = createClient({ base: options.base, apiKey: config.apiKey });
|
|
226
222
|
for (const audit of recent) {
|
|
227
223
|
try {
|
|
228
|
-
const result = await
|
|
224
|
+
const result = await sdkClient.audits.retrieve(audit.jobId);
|
|
229
225
|
const issues = normalizeIssues(result.issues);
|
|
230
226
|
issue = issues.find((i) => i.id === findingId ||
|
|
231
227
|
getRuleId(i) === findingId ||
|
|
@@ -240,123 +236,208 @@ async function handleEvidenceMode(findingId, options, config, format) {
|
|
|
240
236
|
}
|
|
241
237
|
}
|
|
242
238
|
if (!issue) {
|
|
243
|
-
|
|
244
|
-
if (options.job)
|
|
245
|
-
console.error(`Looked in job: ${options.job}`);
|
|
246
|
-
else if (options.file)
|
|
247
|
-
console.error(`Looked in file: ${options.file}`);
|
|
248
|
-
else
|
|
249
|
-
console.error("Try specifying --job or --file to narrow the search.");
|
|
250
|
-
process.exit(ExitCode.ERROR);
|
|
251
|
-
}
|
|
252
|
-
if (format === "json") {
|
|
253
|
-
writeJsonOutput({
|
|
254
|
-
ruleId: getRuleId(issue),
|
|
255
|
-
severity: issue.severity,
|
|
256
|
-
category: issue.category,
|
|
257
|
-
description: issue.description || issue.title,
|
|
258
|
-
selector: issue.selector,
|
|
259
|
-
wcagReference: issue.wcag_reference,
|
|
260
|
-
recommendation: issue.recommendation || issue.recommended_fix,
|
|
261
|
-
evidence: {
|
|
262
|
-
screenshot: issue.screenshot,
|
|
263
|
-
html: issue.html || issue.element,
|
|
264
|
-
helpUrl: issue.helpUrl,
|
|
265
|
-
},
|
|
266
|
-
}, "explain");
|
|
267
|
-
}
|
|
268
|
-
else {
|
|
269
|
-
writeOutput(formatEvidenceBundle(issue));
|
|
239
|
+
throw new Error(strings.explain.errors.findingNotFound(findingId, options.job || options.file));
|
|
270
240
|
}
|
|
241
|
+
return issue;
|
|
271
242
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
243
|
+
export async function handleExplain(opts) {
|
|
244
|
+
const config = { apiKey: opts.apiKey };
|
|
245
|
+
const format = resolveCommandFormat("explain", opts.format, opts.machine || false);
|
|
246
|
+
const verbose = opts.verbose || false;
|
|
247
|
+
const renderer = createRenderer("auto");
|
|
248
|
+
const baseState = {
|
|
249
|
+
phase: "explain",
|
|
250
|
+
phaseIndex: 1,
|
|
251
|
+
phaseTotal: 2,
|
|
252
|
+
url: "",
|
|
253
|
+
mode: "explain",
|
|
254
|
+
progress: {},
|
|
255
|
+
totals: {},
|
|
256
|
+
issueCount: 0,
|
|
257
|
+
scorePreview: null,
|
|
258
|
+
verbose: false,
|
|
259
|
+
elapsed: 0,
|
|
260
|
+
};
|
|
261
|
+
const startTime = Date.now();
|
|
262
|
+
if (opts.findingId) {
|
|
263
|
+
// Evidence mode — fetch and display a specific finding
|
|
264
|
+
let foundIssue = null;
|
|
265
|
+
const steps = [
|
|
266
|
+
{
|
|
267
|
+
id: "fetch",
|
|
268
|
+
actionText: "Fetching audit finding...",
|
|
269
|
+
summaryText: "Finding loaded",
|
|
270
|
+
run: async () => {
|
|
271
|
+
foundIssue = await resolveEvidenceIssue(opts.findingId, { job: opts.job, file: opts.file, base: opts.base }, config);
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
id: "explain",
|
|
276
|
+
actionText: "Generating explanation...",
|
|
277
|
+
summaryText: "Explanation generated",
|
|
278
|
+
run: async () => {
|
|
279
|
+
// Explanation is the formatted evidence bundle; output after steps
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
];
|
|
283
|
+
const { success, states } = await runSteps(steps, {
|
|
284
|
+
onStateChange: (stepStates) => {
|
|
285
|
+
renderer.update({ ...baseState, stepStates, elapsed: Date.now() - startTime });
|
|
286
|
+
},
|
|
287
|
+
});
|
|
288
|
+
renderer.finish({
|
|
289
|
+
url: "",
|
|
290
|
+
mode: "explain",
|
|
291
|
+
overallScore: success ? 100 : 0,
|
|
292
|
+
scores: {},
|
|
293
|
+
issueCount: 0,
|
|
294
|
+
passed: success,
|
|
295
|
+
elapsed: Date.now() - startTime,
|
|
296
|
+
});
|
|
297
|
+
if (!success) {
|
|
298
|
+
const failed = states.find(s => s.status === "failed");
|
|
299
|
+
process.stderr.write(renderError({
|
|
300
|
+
message: failed?.failReason || "Command failed",
|
|
301
|
+
suggestion: "vertaa audit <url>",
|
|
302
|
+
}) + "\n");
|
|
303
|
+
process.exitCode = ExitCode.ERROR;
|
|
304
|
+
}
|
|
305
|
+
if (success && foundIssue) {
|
|
306
|
+
const issue = foundIssue;
|
|
307
|
+
if (format === "json") {
|
|
308
|
+
writeJsonOutput({
|
|
309
|
+
ruleId: getRuleId(issue),
|
|
310
|
+
severity: issue.severity,
|
|
311
|
+
category: issue.category,
|
|
312
|
+
description: issue.description || issue.title,
|
|
313
|
+
selector: issue.selector,
|
|
314
|
+
wcagReference: issue.wcag_reference,
|
|
315
|
+
recommendation: issue.recommendation || issue.recommended_fix,
|
|
316
|
+
evidence: {
|
|
317
|
+
screenshot: issue.screenshot,
|
|
318
|
+
html: issue.html || issue.element,
|
|
319
|
+
helpUrl: issue.helpUrl,
|
|
320
|
+
},
|
|
321
|
+
}, "explain");
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
writeDataOutput(formatEvidenceBundle(issue));
|
|
325
|
+
}
|
|
312
326
|
}
|
|
313
|
-
const data = input;
|
|
314
|
-
// Handle the envelope format { meta: {...}, data: {...} }
|
|
315
|
-
const innerData = (data.data && typeof data.data === "object" ? data.data : data);
|
|
316
|
-
rawIssues = normalizeIssues(innerData.issues);
|
|
317
|
-
auditData = {
|
|
318
|
-
job_id: innerData.job_id || null,
|
|
319
|
-
url: innerData.url || null,
|
|
320
|
-
scores: innerData.scores || null,
|
|
321
|
-
issues: rawIssues.map((i) => ({
|
|
322
|
-
id: i.id || getRuleId(i),
|
|
323
|
-
title: i.title || i.description || null,
|
|
324
|
-
description: i.description || null,
|
|
325
|
-
severity: i.severity || null,
|
|
326
|
-
category: i.category || null,
|
|
327
|
-
selector: i.selector || null,
|
|
328
|
-
wcag_reference: i.wcag_reference || null,
|
|
329
|
-
recommendation: i.recommendation || i.recommended_fix || null,
|
|
330
|
-
})),
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
if (!auditData ||
|
|
334
|
-
!Array.isArray(auditData.issues) ||
|
|
335
|
-
auditData.issues.length === 0) {
|
|
336
|
-
console.error("Error: No issues found in audit data.");
|
|
337
|
-
process.exit(ExitCode.ERROR);
|
|
338
327
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
328
|
+
else {
|
|
329
|
+
// AI mode — explain all issues in an audit
|
|
330
|
+
let responseData = null;
|
|
331
|
+
let rawIssues = [];
|
|
332
|
+
const steps = [
|
|
333
|
+
{
|
|
334
|
+
id: "fetch",
|
|
335
|
+
actionText: strings.explain.run.action,
|
|
336
|
+
summaryText: "Finding loaded",
|
|
337
|
+
run: async () => {
|
|
338
|
+
let auditData = null;
|
|
339
|
+
if (opts.job) {
|
|
340
|
+
const sdkClient = createClient({ base: opts.base, apiKey: config.apiKey });
|
|
341
|
+
const result = await sdkClient.audits.retrieve(opts.job);
|
|
342
|
+
rawIssues = normalizeIssues(result.issues);
|
|
343
|
+
auditData = {
|
|
344
|
+
job_id: result.job_id || opts.job,
|
|
345
|
+
url: result.url || null,
|
|
346
|
+
scores: result.scores || null,
|
|
347
|
+
issues: rawIssues.map((i) => ({
|
|
348
|
+
id: i.id || getRuleId(i),
|
|
349
|
+
title: i.title || i.description || null,
|
|
350
|
+
description: i.description || null,
|
|
351
|
+
severity: i.severity || null,
|
|
352
|
+
category: i.category || null,
|
|
353
|
+
selector: i.selector || null,
|
|
354
|
+
wcag_reference: i.wcag_reference || null,
|
|
355
|
+
recommendation: i.recommendation || i.recommended_fix || null,
|
|
356
|
+
})),
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
const input = await readJsonInput(opts.file);
|
|
361
|
+
if (!input) {
|
|
362
|
+
throw new Error(strings.explain.errors.noAuditData);
|
|
363
|
+
}
|
|
364
|
+
const data = input;
|
|
365
|
+
const innerData = (data.data && typeof data.data === "object" ? data.data : data);
|
|
366
|
+
rawIssues = normalizeIssues(innerData.issues);
|
|
367
|
+
auditData = {
|
|
368
|
+
job_id: innerData.job_id || null,
|
|
369
|
+
url: innerData.url || null,
|
|
370
|
+
scores: innerData.scores || null,
|
|
371
|
+
issues: rawIssues.map((i) => ({
|
|
372
|
+
id: i.id || getRuleId(i),
|
|
373
|
+
title: i.title || i.description || null,
|
|
374
|
+
description: i.description || null,
|
|
375
|
+
severity: i.severity || null,
|
|
376
|
+
category: i.category || null,
|
|
377
|
+
selector: i.selector || null,
|
|
378
|
+
wcag_reference: i.wcag_reference || null,
|
|
379
|
+
recommendation: i.recommendation || i.recommended_fix || null,
|
|
380
|
+
})),
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
if (!auditData ||
|
|
384
|
+
!Array.isArray(auditData.issues) ||
|
|
385
|
+
auditData.issues.length === 0) {
|
|
386
|
+
throw new Error(strings.explain.errors.noIssuesFound);
|
|
387
|
+
}
|
|
388
|
+
const base = resolveApiBase(opts.base);
|
|
389
|
+
const apiKey = getApiKey(config.apiKey);
|
|
390
|
+
const response = await Promise.race([
|
|
391
|
+
apiRequest(base, "/cli/ai/explain", { method: "POST", body: { audit: auditData } }, apiKey),
|
|
392
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("LLM request timed out")), AI_TIMEOUT_MS)),
|
|
393
|
+
]);
|
|
394
|
+
responseData = response.data;
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
id: "explain",
|
|
399
|
+
actionText: "Generating explanation...",
|
|
400
|
+
summaryText: responseData ? strings.explain.run.done(responseData.issues.length) : "Explanation generated",
|
|
401
|
+
run: async () => {
|
|
402
|
+
// Explanation data gathered in fetch step; output after steps
|
|
403
|
+
},
|
|
404
|
+
},
|
|
405
|
+
];
|
|
406
|
+
const { success, states } = await runSteps(steps, {
|
|
407
|
+
onStateChange: (stepStates) => {
|
|
408
|
+
renderer.update({ ...baseState, stepStates, elapsed: Date.now() - startTime });
|
|
409
|
+
},
|
|
410
|
+
});
|
|
411
|
+
renderer.finish({
|
|
412
|
+
url: "",
|
|
413
|
+
mode: "explain",
|
|
414
|
+
overallScore: success ? 100 : 0,
|
|
415
|
+
scores: {},
|
|
416
|
+
issueCount: 0,
|
|
417
|
+
passed: success,
|
|
418
|
+
elapsed: Date.now() - startTime,
|
|
419
|
+
});
|
|
420
|
+
if (!success) {
|
|
421
|
+
const failed = states.find(s => s.status === "failed");
|
|
422
|
+
process.stderr.write(renderError({
|
|
423
|
+
message: failed?.failReason || "Command failed",
|
|
424
|
+
suggestion: "vertaa audit <url>",
|
|
425
|
+
}) + "\n");
|
|
426
|
+
process.exitCode = ExitCode.ERROR;
|
|
351
427
|
}
|
|
352
|
-
|
|
353
|
-
|
|
428
|
+
if (success && responseData) {
|
|
429
|
+
if (format === "json") {
|
|
430
|
+
writeJsonOutput(responseData, "explain");
|
|
431
|
+
}
|
|
432
|
+
else {
|
|
433
|
+
writeDataOutput(formatAiExplainHuman(responseData, verbose, rawIssues));
|
|
434
|
+
}
|
|
354
435
|
}
|
|
355
436
|
}
|
|
356
|
-
catch (error) {
|
|
357
|
-
handleAiCommandError(error, "explain", spinner);
|
|
358
|
-
}
|
|
359
437
|
}
|
|
438
|
+
// ---------------------------------------------------------------------------
|
|
439
|
+
// Command Registration
|
|
440
|
+
// ---------------------------------------------------------------------------
|
|
360
441
|
export function registerExplainCommand(program) {
|
|
361
442
|
program
|
|
362
443
|
.command("explain [finding-id]")
|
|
@@ -382,18 +463,23 @@ Modes:
|
|
|
382
463
|
const config = await resolveConfig(globalOpts.config);
|
|
383
464
|
const machineMode = globalOpts.machine || false;
|
|
384
465
|
const verbose = globalOpts.verbose || false;
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
466
|
+
await handleExplain({
|
|
467
|
+
findingId,
|
|
468
|
+
job: options.job,
|
|
469
|
+
file: options.file,
|
|
470
|
+
format: options.format,
|
|
471
|
+
base: globalOpts.base,
|
|
472
|
+
verbose,
|
|
473
|
+
machine: machineMode,
|
|
474
|
+
apiKey: config.apiKey,
|
|
475
|
+
});
|
|
394
476
|
}
|
|
395
477
|
catch (error) {
|
|
396
|
-
|
|
478
|
+
process.stderr.write(renderError({
|
|
479
|
+
message: error instanceof Error ? error.message : String(error),
|
|
480
|
+
suggestion: "vertaa audit <url>",
|
|
481
|
+
exitCode: ExitCode.ERROR,
|
|
482
|
+
}) + "\n");
|
|
397
483
|
process.exit(ExitCode.ERROR);
|
|
398
484
|
}
|
|
399
485
|
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Legacy fix-all command handler.
|
|
3
|
+
* Generates fix patches for all issues in an audit.
|
|
4
|
+
*/
|
|
5
|
+
import type { Command } from "commander";
|
|
6
|
+
import type { Flags } from "../types.js";
|
|
7
|
+
export interface FixAllCommandOptions {
|
|
8
|
+
base?: string;
|
|
9
|
+
jobId: string;
|
|
10
|
+
fileContent: string;
|
|
11
|
+
autoFixOnly?: boolean;
|
|
12
|
+
format?: string;
|
|
13
|
+
dryRun?: boolean;
|
|
14
|
+
yes?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function handleFixAll(opts: FixAllCommandOptions): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Shared fix-all runner used by the fix-all command (legacy wrapper for backward compat).
|
|
19
|
+
*/
|
|
20
|
+
export declare function runFixAllCommand(base: string, jobId: string, flags: Flags, globalFlags?: {
|
|
21
|
+
dryRun?: boolean;
|
|
22
|
+
yes?: boolean;
|
|
23
|
+
}): Promise<void>;
|
|
24
|
+
export declare function registerFixAllCommand(program: Command): void;
|
|
25
|
+
//# sourceMappingURL=fix-all.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fix-all.d.ts","sourceRoot":"","sources":["../../src/commands/fix-all.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAezC,OAAO,KAAK,EAAE,KAAK,EAAkD,MAAM,aAAa,CAAC;AAUzF,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CA4K5E;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,KAAK,EACZ,WAAW,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAO,iBAmBtD;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsB5D"}
|