@vertaaux/cli 0.4.0 → 0.5.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/CHANGELOG.md +97 -0
- package/MIGRATION.md +239 -0
- package/README.md +34 -16
- package/dist/app/interactive-app.d.ts +101 -0
- package/dist/app/interactive-app.d.ts.map +1 -0
- package/dist/app/interactive-app.js +309 -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 +181 -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 +372 -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 +45 -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 +9 -0
- package/dist/commands/a11y.d.ts.map +1 -0
- package/dist/commands/a11y.js +76 -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 +564 -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 +130 -0
- package/dist/commands/audit/policy.d.ts +19 -0
- package/dist/commands/audit/policy.d.ts.map +1 -0
- package/dist/commands/audit/policy.js +102 -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 +88 -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 +1 -0
- package/dist/commands/baseline.d.ts.map +1 -1
- package/dist/commands/baseline.js +205 -121
- package/dist/commands/comment.d.ts +22 -0
- package/dist/commands/comment.d.ts.map +1 -1
- package/dist/commands/comment.js +122 -58
- package/dist/commands/compare.d.ts +17 -0
- package/dist/commands/compare.d.ts.map +1 -1
- package/dist/commands/compare.js +287 -180
- package/dist/commands/diff.d.ts +5 -0
- package/dist/commands/diff.d.ts.map +1 -1
- package/dist/commands/diff.js +168 -141
- package/dist/commands/doc.d.ts +10 -0
- package/dist/commands/doc.d.ts.map +1 -1
- package/dist/commands/doc.js +134 -76
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +164 -17
- 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 +241 -155
- 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 +152 -89
- 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 +159 -97
- package/dist/commands/policy.d.ts +31 -0
- package/dist/commands/policy.d.ts.map +1 -1
- package/dist/commands/policy.js +269 -124
- 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 +127 -73
- 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 +153 -82
- package/dist/commands/triage.d.ts +35 -0
- package/dist/commands/triage.d.ts.map +1 -1
- package/dist/commands/triage.js +206 -81
- 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/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +125 -990
- 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 +2 -0
- package/dist/output/envelope.d.ts.map +1 -1
- package/dist/output/envelope.js +18 -2
- 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/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 +102 -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/url-classify.d.ts.map +1 -1
- package/dist/utils/url-classify.js +24 -3
- package/node_modules/@vertaaux/tui/dist/index.cjs +713 -20
- 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 +689 -21
- package/node_modules/@vertaaux/tui/dist/index.js.map +1 -1
- package/package.json +13 -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
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit command for VertaaUX CLI.
|
|
3
|
+
*
|
|
4
|
+
* Runs UX and accessibility audits on web pages.
|
|
5
|
+
* Supports various targets, output formats, and CI integration.
|
|
6
|
+
*/
|
|
7
|
+
import { colorize, dim, brand, severity as severityPalette } from "@vertaaux/tui";
|
|
8
|
+
import { resolveConfig } from "../../config/loader.js";
|
|
9
|
+
import { ExitCode } from "../../utils/exit-codes.js";
|
|
10
|
+
import { parseTimeout, parseInterval, parseConcurrency, parseThreshold, parseMode, parseFailOn, parseGroupBy, parseBudget, validateNumeric, } from "../../utils/validators.js";
|
|
11
|
+
import { resolveApiBase, getApiKey, apiRequest, waitForAudit, createClient, } from "../../utils/client.js";
|
|
12
|
+
import { createOutput } from "../../output/factory.js";
|
|
13
|
+
import { resolveCommandFormat } from "../../output/formats.js";
|
|
14
|
+
import { writeOutput } from "../../output/envelope.js";
|
|
15
|
+
import { createRenderer, createKeyboardHandler, runSteps, renderWarning, renderError, isCI, isTTY as tuiIsTTY, phaseIndex, phaseTotal, } from "@vertaaux/tui";
|
|
16
|
+
import { runFixWizard } from "../../interactive/fix-wizard.js";
|
|
17
|
+
import { isInteractive } from "../../interactive/prompts.js";
|
|
18
|
+
import { evaluateQualityGate, } from "../../quality-gate/index.js";
|
|
19
|
+
import { loadBaseline } from "../../baseline/manager.js";
|
|
20
|
+
import { getChangedRoutes, detectBaseBranch, getBudgetConfig, } from "../../ci/index.js";
|
|
21
|
+
import { detectMonorepo, getAuditableApps, generateMatrixConfig, } from "../../monorepo/index.js";
|
|
22
|
+
import { createLogger } from "../../utils/logger.js";
|
|
23
|
+
import { validateBranchName } from "../../utils/sanitize.js";
|
|
24
|
+
import { isLocalUrl } from "../../utils/url-classify.js";
|
|
25
|
+
import { captureLocalPage } from "../../utils/local-capture.js";
|
|
26
|
+
import { strings } from "../../ui/strings.js";
|
|
27
|
+
import { detectPRLabels } from "./ci-detection.js";
|
|
28
|
+
import { normalizeIssues, filterBySeverity, filterByCategory } from "./filters.js";
|
|
29
|
+
import { mapStatusToPhase, getOverallScoreFromResult, extractNumericScores, countTotalIssues } from "./scoring.js";
|
|
30
|
+
import { saveReproArtifacts, saveArtifactBundle } from "./artifacts.js";
|
|
31
|
+
import { outputFireAndForget, outputFormattedResults, outputQualityGateResult } from "./output.js";
|
|
32
|
+
import { loadAndResolvePolicy, buildQualityGateConfig } from "./policy.js";
|
|
33
|
+
import { runInlineExplanation } from "./explain.js";
|
|
34
|
+
/**
|
|
35
|
+
* Apply filters, evaluate quality gate, and output results after audit completes.
|
|
36
|
+
*/
|
|
37
|
+
async function runPostAuditAnalysis(params) {
|
|
38
|
+
const { result, createdJobId, targetUrl, format, formatter, groupBy, options, config, interactive, quiet } = params;
|
|
39
|
+
// Save repro artifacts if requested
|
|
40
|
+
if (createdJobId) {
|
|
41
|
+
saveReproArtifacts(createdJobId, result, options, quiet);
|
|
42
|
+
}
|
|
43
|
+
// Apply filters to issues
|
|
44
|
+
let issues = normalizeIssues(result.issues);
|
|
45
|
+
if (options.severity)
|
|
46
|
+
issues = filterBySeverity(issues, options.severity);
|
|
47
|
+
if (options.category)
|
|
48
|
+
issues = filterByCategory(issues, options.category);
|
|
49
|
+
const filteredResult = { ...result, issues };
|
|
50
|
+
// Load and apply policy (CICD-17)
|
|
51
|
+
await loadAndResolvePolicy(options, quiet);
|
|
52
|
+
// Build quality gate config and evaluate
|
|
53
|
+
const gateConfig = buildQualityGateConfig(config, options);
|
|
54
|
+
const baselinePath = options.baseline || config.baseline?.path;
|
|
55
|
+
const baseline = baselinePath ? await loadBaseline(baselinePath) : null;
|
|
56
|
+
const prLabels = detectPRLabels();
|
|
57
|
+
const gateResult = evaluateQualityGate({
|
|
58
|
+
auditResult: {
|
|
59
|
+
issues,
|
|
60
|
+
scores: result.scores,
|
|
61
|
+
},
|
|
62
|
+
baseline,
|
|
63
|
+
config: gateConfig,
|
|
64
|
+
labels: prLabels,
|
|
65
|
+
});
|
|
66
|
+
// Format and output results
|
|
67
|
+
outputFormattedResults(filteredResult, format, formatter, groupBy, options, quiet);
|
|
68
|
+
// Inline AI explanation (--explain flag, PROG-04)
|
|
69
|
+
if (options.explain && issues.length > 0) {
|
|
70
|
+
await runInlineExplanation(issues, result, targetUrl, options, config);
|
|
71
|
+
}
|
|
72
|
+
// Output quality gate result
|
|
73
|
+
if (!quiet)
|
|
74
|
+
outputQualityGateResult(gateResult);
|
|
75
|
+
// Save CI artifact bundle if requested
|
|
76
|
+
if (options.uploadArtifacts && createdJobId) {
|
|
77
|
+
const artifactJobId = options.jobId || createdJobId;
|
|
78
|
+
saveArtifactBundle(artifactJobId, result, issues, gateResult.exitCode, quiet);
|
|
79
|
+
}
|
|
80
|
+
// Interactive mode: run fix wizard if there are issues
|
|
81
|
+
if (interactive && issues.length > 0) {
|
|
82
|
+
await runFixWizard(issues, { jobId: result.job_id, url: targetUrl, base: options.base, config });
|
|
83
|
+
}
|
|
84
|
+
// Set exit code
|
|
85
|
+
if (gateResult.exitCode !== ExitCode.SUCCESS) {
|
|
86
|
+
process.exitCode = gateResult.exitCode;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Execute the audit command — exported as handleAudit for CommandRunnerView.
|
|
91
|
+
*/
|
|
92
|
+
export async function handleAudit(rawUrl, options, config) {
|
|
93
|
+
// Normalize URL: add https:// if no protocol specified
|
|
94
|
+
const targetUrl = /^https?:\/\//i.test(rawUrl) ? rawUrl : `https://${rawUrl}`;
|
|
95
|
+
// SECVAL-5: Reject non-http(s) schemes explicitly
|
|
96
|
+
try {
|
|
97
|
+
const parsed = new URL(targetUrl);
|
|
98
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
99
|
+
process.stderr.write(renderError({
|
|
100
|
+
message: `Unsupported URL scheme "${parsed.protocol}" — only http: and https: are allowed`,
|
|
101
|
+
suggestion: "Provide a URL starting with http:// or https://",
|
|
102
|
+
exitCode: ExitCode.ERROR,
|
|
103
|
+
}) + "\n");
|
|
104
|
+
process.exitCode = ExitCode.ERROR;
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
process.stderr.write(renderError({
|
|
110
|
+
message: `Invalid URL: "${targetUrl}"`,
|
|
111
|
+
suggestion: "Provide a valid http:// or https:// URL",
|
|
112
|
+
exitCode: ExitCode.ERROR,
|
|
113
|
+
}) + "\n");
|
|
114
|
+
process.exitCode = ExitCode.ERROR;
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
// Resolve options with precedence: flags > env > config > defaults
|
|
118
|
+
const mode = options.mode || config.mode || "basic";
|
|
119
|
+
const timeout = options.timeout || config.timeout || 60000;
|
|
120
|
+
const interval = options.interval || config.interval || 5000;
|
|
121
|
+
const wait = options.wait ?? true; // Default to waiting for completion
|
|
122
|
+
const quiet = options.quiet ?? false;
|
|
123
|
+
const interactive = options.interactive ?? false;
|
|
124
|
+
// Interactive mode validation
|
|
125
|
+
if (interactive) {
|
|
126
|
+
if (!wait) {
|
|
127
|
+
throw new Error("--interactive requires --wait (audit must complete before interactive mode)");
|
|
128
|
+
}
|
|
129
|
+
if (!isInteractive()) {
|
|
130
|
+
throw new Error("Interactive mode requires a terminal. Use --format json in CI or piped environments.");
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Resolve fail-fast mode: --strict > --continue-on-error > auto-detect
|
|
134
|
+
let failFast;
|
|
135
|
+
if (options.strict && options.continueOnError) {
|
|
136
|
+
writeOutput(renderWarning({ message: "--strict and --continue-on-error both set — --strict takes precedence" }));
|
|
137
|
+
failFast = true;
|
|
138
|
+
}
|
|
139
|
+
else if (options.strict) {
|
|
140
|
+
failFast = true;
|
|
141
|
+
}
|
|
142
|
+
else if (options.continueOnError) {
|
|
143
|
+
failFast = false;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
failFast = isCI() || !tuiIsTTY();
|
|
147
|
+
}
|
|
148
|
+
// Resolve API settings
|
|
149
|
+
const base = resolveApiBase(options.base);
|
|
150
|
+
const apiKey = getApiKey(config.apiKey);
|
|
151
|
+
const sdkClient = createClient({ base: options.base, apiKey: config.apiKey });
|
|
152
|
+
// Resolve output format using per-command registry
|
|
153
|
+
// --json flag is a shorthand for --format json (convenient for piping)
|
|
154
|
+
const machineMode = options.machine || false;
|
|
155
|
+
const explicitFormat = options.json ? "json" : (options.format || config.output?.format);
|
|
156
|
+
const validatedFormat = resolveCommandFormat("audit", explicitFormat, machineMode);
|
|
157
|
+
const format = validatedFormat;
|
|
158
|
+
const formatter = createOutput(format);
|
|
159
|
+
const groupBy = options.groupBy || config.output?.groupBy || "severity";
|
|
160
|
+
// Keyboard handler for abort
|
|
161
|
+
let keyboard = null;
|
|
162
|
+
let aborted = false;
|
|
163
|
+
// Create renderer for step-list display
|
|
164
|
+
const renderer = createRenderer("auto");
|
|
165
|
+
keyboard = createKeyboardHandler();
|
|
166
|
+
keyboard.on("quit", () => {
|
|
167
|
+
aborted = true;
|
|
168
|
+
renderer.dispose();
|
|
169
|
+
keyboard?.dispose();
|
|
170
|
+
writeOutput("\nAudit aborted by user.\n");
|
|
171
|
+
process.exitCode = ExitCode.ERROR;
|
|
172
|
+
});
|
|
173
|
+
keyboard.start();
|
|
174
|
+
const auditStartTime = Date.now();
|
|
175
|
+
const baseState = {
|
|
176
|
+
phase: strings.audit.run.action,
|
|
177
|
+
phaseIndex: 1,
|
|
178
|
+
phaseTotal: 3,
|
|
179
|
+
url: targetUrl,
|
|
180
|
+
mode,
|
|
181
|
+
progress: {},
|
|
182
|
+
totals: {},
|
|
183
|
+
issueCount: 0,
|
|
184
|
+
scorePreview: null,
|
|
185
|
+
verbose: false,
|
|
186
|
+
elapsed: 0,
|
|
187
|
+
};
|
|
188
|
+
let auditResult = null;
|
|
189
|
+
let createdJobId;
|
|
190
|
+
const steps = [
|
|
191
|
+
{
|
|
192
|
+
id: "fetch",
|
|
193
|
+
actionText: isLocalUrl(targetUrl)
|
|
194
|
+
? strings.audit.localFetch.action
|
|
195
|
+
: strings.audit.run.action,
|
|
196
|
+
summaryText: isLocalUrl(targetUrl)
|
|
197
|
+
? strings.audit.localFetch.done()
|
|
198
|
+
: strings.audit.localAnalyze.done(),
|
|
199
|
+
run: async () => {
|
|
200
|
+
if (aborted)
|
|
201
|
+
return;
|
|
202
|
+
if (isLocalUrl(targetUrl)) {
|
|
203
|
+
// Local URL — capture HTML on this machine, send to /analyze
|
|
204
|
+
// Note: informational messages moved to step summaryText to avoid
|
|
205
|
+
// writing to stderr during ComposedRenderer step execution.
|
|
206
|
+
let captured;
|
|
207
|
+
try {
|
|
208
|
+
captured = await captureLocalPage(targetUrl, { timeoutMs: timeout });
|
|
209
|
+
}
|
|
210
|
+
catch (captureErr) {
|
|
211
|
+
throw new Error(`Cannot reach ${targetUrl}. Ensure your local server is running.\n` +
|
|
212
|
+
` ${captureErr instanceof Error ? captureErr.message : String(captureErr)}`);
|
|
213
|
+
}
|
|
214
|
+
const created = await apiRequest(base, "/analyze", {
|
|
215
|
+
method: "POST",
|
|
216
|
+
body: { html: captured.html, url: targetUrl, mode },
|
|
217
|
+
}, apiKey);
|
|
218
|
+
auditResult = created;
|
|
219
|
+
createdJobId = created.job_id;
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
// Public URL — send to cloud API
|
|
223
|
+
const created = await sdkClient.audits.create({ url: targetUrl, mode: mode });
|
|
224
|
+
auditResult = created;
|
|
225
|
+
createdJobId = created.job_id;
|
|
226
|
+
// If not waiting, just output the job info and stop processing.
|
|
227
|
+
// Return early so the "wait" and "analyze" steps are skipped — the
|
|
228
|
+
// quality gate must NOT run for --no-wait jobs since the audit may
|
|
229
|
+
// not be complete yet (or may be from a sync server that returns the
|
|
230
|
+
// completed result immediately).
|
|
231
|
+
if (!wait) {
|
|
232
|
+
renderer.finish({
|
|
233
|
+
url: targetUrl,
|
|
234
|
+
mode,
|
|
235
|
+
overallScore: 0,
|
|
236
|
+
scores: {},
|
|
237
|
+
issueCount: 0,
|
|
238
|
+
passed: true,
|
|
239
|
+
elapsed: Date.now() - auditStartTime,
|
|
240
|
+
});
|
|
241
|
+
keyboard?.dispose();
|
|
242
|
+
outputFireAndForget(created, format, formatter, options, quiet);
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
id: "wait",
|
|
250
|
+
actionText: strings.audit.wait.action,
|
|
251
|
+
summaryText: strings.audit.wait.done(0),
|
|
252
|
+
run: async () => {
|
|
253
|
+
if (aborted || !wait || !auditResult)
|
|
254
|
+
return;
|
|
255
|
+
const created = auditResult;
|
|
256
|
+
if (created.status === "failed") {
|
|
257
|
+
throw new Error(created.error || "Audit failed on server");
|
|
258
|
+
}
|
|
259
|
+
const isSyncResponse = created.status === "completed" && created.scores;
|
|
260
|
+
if (isSyncResponse) {
|
|
261
|
+
// Already done — nothing to wait for
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
if (!created.job_id) {
|
|
265
|
+
throw new Error("Audit response missing job_id");
|
|
266
|
+
}
|
|
267
|
+
const result = await waitForAudit(sdkClient, created.job_id, timeout, interval, (progress, status) => {
|
|
268
|
+
if (aborted)
|
|
269
|
+
return;
|
|
270
|
+
const phase = mapStatusToPhase(status);
|
|
271
|
+
renderer.update({
|
|
272
|
+
...baseState,
|
|
273
|
+
phase,
|
|
274
|
+
phaseIndex: phaseIndex(phase),
|
|
275
|
+
phaseTotal: phaseTotal(),
|
|
276
|
+
progress: { audit: progress },
|
|
277
|
+
totals: { audit: 100 },
|
|
278
|
+
elapsed: Date.now() - auditStartTime,
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
auditResult = result;
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
id: "analyze",
|
|
286
|
+
actionText: strings.audit.localAnalyze.action,
|
|
287
|
+
summaryText: strings.audit.run.done(0, targetUrl),
|
|
288
|
+
run: async () => {
|
|
289
|
+
// No-op: analysis output is written AFTER renderer.finish()
|
|
290
|
+
// to avoid breaking ComposedRenderer's cursor arithmetic.
|
|
291
|
+
if (aborted || !auditResult || !wait)
|
|
292
|
+
return;
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
];
|
|
296
|
+
const { success, states } = await runSteps(steps, {
|
|
297
|
+
failFast,
|
|
298
|
+
onStateChange: (stepStates) => {
|
|
299
|
+
renderer.update({
|
|
300
|
+
...baseState,
|
|
301
|
+
stepStates,
|
|
302
|
+
elapsed: Date.now() - auditStartTime,
|
|
303
|
+
});
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
if (success && auditResult) {
|
|
307
|
+
const resolvedResult = auditResult;
|
|
308
|
+
const overallScore = getOverallScoreFromResult(resolvedResult);
|
|
309
|
+
renderer.finish({
|
|
310
|
+
url: targetUrl,
|
|
311
|
+
mode,
|
|
312
|
+
overallScore: overallScore ?? 0,
|
|
313
|
+
scores: extractNumericScores(resolvedResult.scores),
|
|
314
|
+
issueCount: countTotalIssues(resolvedResult.issues),
|
|
315
|
+
passed: (overallScore ?? 0) >= 70,
|
|
316
|
+
elapsed: Date.now() - auditStartTime,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
renderer.finish({
|
|
321
|
+
url: targetUrl,
|
|
322
|
+
mode,
|
|
323
|
+
overallScore: 0,
|
|
324
|
+
scores: {},
|
|
325
|
+
issueCount: 0,
|
|
326
|
+
passed: false,
|
|
327
|
+
elapsed: Date.now() - auditStartTime,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
keyboard?.dispose();
|
|
331
|
+
if (!success) {
|
|
332
|
+
const failedStep = states.find((s) => s.status === "failed");
|
|
333
|
+
const reason = failedStep?.failReason || "(no reason captured)";
|
|
334
|
+
process.stderr.write(renderError({
|
|
335
|
+
message: `Audit failed — ${reason}`,
|
|
336
|
+
suggestion: "vertaa doctor",
|
|
337
|
+
}) + "\n");
|
|
338
|
+
process.exitCode = ExitCode.ERROR;
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
// Run post-audit analysis AFTER renderer.finish() so output
|
|
342
|
+
// doesn't break ComposedRenderer's cursor arithmetic
|
|
343
|
+
if (auditResult && wait && !aborted) {
|
|
344
|
+
await runPostAuditAnalysis({
|
|
345
|
+
result: auditResult,
|
|
346
|
+
createdJobId,
|
|
347
|
+
targetUrl,
|
|
348
|
+
format,
|
|
349
|
+
formatter,
|
|
350
|
+
groupBy,
|
|
351
|
+
options,
|
|
352
|
+
config,
|
|
353
|
+
interactive,
|
|
354
|
+
quiet,
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Register the audit command with the Commander program.
|
|
360
|
+
*/
|
|
361
|
+
export function registerAuditCommand(program) {
|
|
362
|
+
program
|
|
363
|
+
.command("audit [url]")
|
|
364
|
+
.description("Run UX and accessibility audit. Localhost and private URLs are " +
|
|
365
|
+
"captured locally and analyzed via static HTML analysis.")
|
|
366
|
+
.option("-u, --url <url>", "URL to audit")
|
|
367
|
+
.option("--repo <repo>", "GitHub repository to audit (owner/repo)")
|
|
368
|
+
.option("--storybook <url>", "Storybook URL to audit")
|
|
369
|
+
.option("--routes <routes>", "Comma-separated list of routes to audit")
|
|
370
|
+
.option("--auth-profile <profile>", "Authentication profile for protected pages")
|
|
371
|
+
.option("--mode <mode>", "Audit depth: basic|standard|deep", parseMode, "basic")
|
|
372
|
+
.option("--format <format>", "Output format: json|sarif|junit|html|human (default: human in terminal, auto-detected in CI)")
|
|
373
|
+
.option("--json", "Shorthand for --format json (convenient for piping)")
|
|
374
|
+
.option("-o, --output <path>", "Output file path")
|
|
375
|
+
.option("--group-by <field>", "Group issues by: severity|category|route", parseGroupBy)
|
|
376
|
+
.option("--wait", "Wait for audit completion (default)")
|
|
377
|
+
.option("--no-wait", "Don't wait for audit completion")
|
|
378
|
+
.option("--severity <levels>", "Filter issues by severity: error|warning|info (comma-separated)")
|
|
379
|
+
.option("--category <categories>", "Filter issues by category (comma-separated)")
|
|
380
|
+
.option("--fail-on <severity>", "Exit 1 if new issues at or above severity: error|warning|info|none", parseFailOn)
|
|
381
|
+
.option("--threshold <score>", "Exit 3 if overall score below threshold (0-100)", parseThreshold)
|
|
382
|
+
.option("--max-new-errors <n>", "Maximum allowed new error-severity issues (default: 0)", (v) => validateNumeric(v, "max-new-errors", { min: 0, integer: true }))
|
|
383
|
+
.option("--max-new-warnings <n>", "Maximum allowed new warning-severity issues (default: unlimited)", (v) => validateNumeric(v, "max-new-warnings", { min: 0, integer: true }))
|
|
384
|
+
.option("--fail-on-existing", "Also fail on existing issues (legacy mode)")
|
|
385
|
+
.option("--bypass-labels <labels>", "Comma-separated PR labels that bypass quality gate")
|
|
386
|
+
.option("--baseline <path>", "Path to baseline file for new issue detection")
|
|
387
|
+
.option("--timeout <ms>", "Wait timeout in milliseconds (1-300000)", parseTimeout)
|
|
388
|
+
.option("--interval <ms>", "Poll interval in milliseconds (1-300000)", parseInterval)
|
|
389
|
+
.option("--interactive", "Step through issues interactively (requires --wait)")
|
|
390
|
+
// Repro artifact options (CLI-17)
|
|
391
|
+
.option("--save-trace", "Save Playwright trace for debugging")
|
|
392
|
+
.option("--save-har", "Save HAR network log")
|
|
393
|
+
.option("--screenshots", "Save page screenshots")
|
|
394
|
+
.option("--dom-snapshots", "Save DOM snapshots")
|
|
395
|
+
// Performance options (CLI-18)
|
|
396
|
+
.option("--concurrency <n>", "Number of concurrent audits (1-50, default: 3)", parseConcurrency)
|
|
397
|
+
.option("--cache", "Enable route caching to speed up repeated audits")
|
|
398
|
+
// CI artifact bundling (CICD-08)
|
|
399
|
+
.option("--upload-artifacts", "Save all outputs to .vertaaux/artifacts/ for CI upload")
|
|
400
|
+
.option("--job-id <id>", "Job identifier for artifact directory naming")
|
|
401
|
+
// Incremental mode (CICD-07)
|
|
402
|
+
.option("--incremental", "Only audit routes changed in PR")
|
|
403
|
+
.option("--base-branch <branch>", "Base branch for comparison (default: auto-detect)")
|
|
404
|
+
// Budget mode (CICD-13)
|
|
405
|
+
.option("--budget <mode>", "Budget mode: quick|standard|full", parseBudget)
|
|
406
|
+
// Monorepo options (CICD-16)
|
|
407
|
+
.option("--workspace <name>", "Audit specific workspace in monorepo")
|
|
408
|
+
.option("--all-workspaces", "Audit all workspaces in monorepo")
|
|
409
|
+
.option("--parallel", "Run workspace audits in parallel")
|
|
410
|
+
.option("--detect-matrix", "Output CI matrix config for monorepo (JSON)")
|
|
411
|
+
// Caching options (CICD-14)
|
|
412
|
+
.option("--no-cache", "Disable route caching")
|
|
413
|
+
.option("--cache-dir <path>", "Custom cache directory")
|
|
414
|
+
// Logging options (CICD-18)
|
|
415
|
+
.option("--json-logs", "Output structured JSON logs for CI")
|
|
416
|
+
// Policy options (CICD-17)
|
|
417
|
+
.option("--policy <file>", "Path to policy file (default: auto-detect vertaa.policy.yml)")
|
|
418
|
+
.option("--explain", "Append AI explanation to audit results")
|
|
419
|
+
.option("--strict", "Fail immediately on first step error")
|
|
420
|
+
.option("--continue-on-error", "Continue on step errors even in CI")
|
|
421
|
+
.action(async (urlArg, cmdOptions, command) => {
|
|
422
|
+
try {
|
|
423
|
+
// Initialize structured logger
|
|
424
|
+
const logger = createLogger({
|
|
425
|
+
json: cmdOptions.jsonLogs || false,
|
|
426
|
+
level: cmdOptions.quiet ? "error" : "info",
|
|
427
|
+
});
|
|
428
|
+
// Load config (supports --config global option)
|
|
429
|
+
const globalOpts = command.optsWithGlobals();
|
|
430
|
+
const config = await resolveConfig(globalOpts.config);
|
|
431
|
+
// Propagate global --machine and --base flags to command options
|
|
432
|
+
cmdOptions.machine = globalOpts.machine || false;
|
|
433
|
+
cmdOptions.base = globalOpts.base || cmdOptions.base;
|
|
434
|
+
// Handle monorepo detection and matrix output (CICD-16)
|
|
435
|
+
if (cmdOptions.detectMatrix || cmdOptions.allWorkspaces || cmdOptions.workspace) {
|
|
436
|
+
const monorepo = await detectMonorepo();
|
|
437
|
+
if (monorepo.type === "none") {
|
|
438
|
+
if (cmdOptions.detectMatrix) {
|
|
439
|
+
// Output empty matrix for non-monorepo
|
|
440
|
+
process.stdout.write(JSON.stringify({ include: [] }) + "\n");
|
|
441
|
+
process.exit(ExitCode.SUCCESS);
|
|
442
|
+
}
|
|
443
|
+
// Not a monorepo, continue with normal audit
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
logger.info(`Detected ${monorepo.type} monorepo`, {
|
|
447
|
+
workspaces: monorepo.workspaces.length,
|
|
448
|
+
});
|
|
449
|
+
const apps = getAuditableApps(monorepo);
|
|
450
|
+
logger.info(`Found ${apps.length} auditable apps`, {
|
|
451
|
+
apps: apps.map((a) => a.name),
|
|
452
|
+
});
|
|
453
|
+
// Output matrix config for CI
|
|
454
|
+
if (cmdOptions.detectMatrix) {
|
|
455
|
+
const matrix = generateMatrixConfig(apps);
|
|
456
|
+
process.stdout.write(JSON.stringify(matrix) + "\n");
|
|
457
|
+
process.exit(ExitCode.SUCCESS);
|
|
458
|
+
}
|
|
459
|
+
// Audit specific workspace
|
|
460
|
+
if (cmdOptions.workspace) {
|
|
461
|
+
const workspace = monorepo.workspaces.find((w) => w.name === cmdOptions.workspace);
|
|
462
|
+
if (!workspace) {
|
|
463
|
+
writeOutput(`Error: Workspace "${cmdOptions.workspace}" not found\nAvailable: ${monorepo.workspaces.map((w) => w.name).join(", ")}\n`);
|
|
464
|
+
process.exit(ExitCode.ERROR);
|
|
465
|
+
}
|
|
466
|
+
// Use workspace URL or infer from type
|
|
467
|
+
if (workspace.url) {
|
|
468
|
+
urlArg = workspace.url;
|
|
469
|
+
logger.info(`Auditing workspace`, { workspace: workspace.name, url: urlArg });
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
// Audit all workspaces — not yet implemented (placeholder removed to prevent false-green CI results)
|
|
473
|
+
if (cmdOptions.allWorkspaces) {
|
|
474
|
+
// TODO: Implement real workspace audit execution (iterate apps, call executeAudit per workspace)
|
|
475
|
+
writeOutput(colorize(strings.audit.errors.allWorkspacesNotImplemented, severityPalette.warning) +
|
|
476
|
+
"\n" +
|
|
477
|
+
apps.map((app) => dim(` vertaa audit ${app.url || app.name}`)).join("\n") +
|
|
478
|
+
"\n");
|
|
479
|
+
process.exit(ExitCode.ERROR);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
// Handle incremental mode (CICD-07)
|
|
484
|
+
if (cmdOptions.incremental) {
|
|
485
|
+
const baseBranch = validateBranchName(cmdOptions.baseBranch || detectBaseBranch());
|
|
486
|
+
const changedResult = await getChangedRoutes({
|
|
487
|
+
baseBranch,
|
|
488
|
+
routePatterns: [], // Use default patterns
|
|
489
|
+
});
|
|
490
|
+
if (!changedResult.hasChanges) {
|
|
491
|
+
writeOutput(colorize(strings.audit.noRouteChanges, brand.lime) + "\n");
|
|
492
|
+
process.exit(ExitCode.SUCCESS);
|
|
493
|
+
}
|
|
494
|
+
// Log which routes will be audited
|
|
495
|
+
writeOutput(dim(`Incremental mode: Auditing ${changedResult.routes.length} changed routes`) + "\n");
|
|
496
|
+
for (const route of changedResult.routes) {
|
|
497
|
+
writeOutput(dim(` - ${route}`) + "\n");
|
|
498
|
+
}
|
|
499
|
+
// If routes were detected, use them instead of URL argument
|
|
500
|
+
if (!config.defaultUrl) {
|
|
501
|
+
writeOutput("Error: --incremental requires defaultUrl in config to construct full URLs.\n");
|
|
502
|
+
process.exit(ExitCode.ERROR);
|
|
503
|
+
}
|
|
504
|
+
// Set routes option for executeAudit
|
|
505
|
+
cmdOptions.routes = changedResult.routes.join(",");
|
|
506
|
+
}
|
|
507
|
+
// Handle budget mode (CICD-13)
|
|
508
|
+
if (cmdOptions.budget) {
|
|
509
|
+
const budgetConfig = getBudgetConfig(cmdOptions.budget);
|
|
510
|
+
// Apply budget constraints to options
|
|
511
|
+
if (!cmdOptions.concurrency) {
|
|
512
|
+
cmdOptions.concurrency = budgetConfig.concurrency;
|
|
513
|
+
}
|
|
514
|
+
if (!cmdOptions.timeout) {
|
|
515
|
+
cmdOptions.timeout = budgetConfig.maxTime;
|
|
516
|
+
}
|
|
517
|
+
writeOutput(dim(`Budget mode: ${cmdOptions.budget} (max ${budgetConfig.maxPages} pages, ${budgetConfig.maxTime / 1000}s timeout, ${budgetConfig.concurrency} concurrent)`) + "\n");
|
|
518
|
+
}
|
|
519
|
+
// Resolve target URL
|
|
520
|
+
// Priority: positional > --url > --repo > --storybook > --routes > config default
|
|
521
|
+
let targetUrl;
|
|
522
|
+
if (urlArg) {
|
|
523
|
+
targetUrl = urlArg;
|
|
524
|
+
}
|
|
525
|
+
else if (cmdOptions.url) {
|
|
526
|
+
targetUrl = cmdOptions.url;
|
|
527
|
+
}
|
|
528
|
+
else if (cmdOptions.repo) {
|
|
529
|
+
// For repo audits, construct a special URL or handle differently
|
|
530
|
+
// For now, we'll just pass it as a marker
|
|
531
|
+
targetUrl = `repo:${cmdOptions.repo}`;
|
|
532
|
+
}
|
|
533
|
+
else if (cmdOptions.storybook) {
|
|
534
|
+
targetUrl = cmdOptions.storybook;
|
|
535
|
+
}
|
|
536
|
+
else if (cmdOptions.routes) {
|
|
537
|
+
// Routes require a base URL from config
|
|
538
|
+
if (!config.defaultUrl) {
|
|
539
|
+
writeOutput("Error: --routes requires defaultUrl in config or a base URL.\n");
|
|
540
|
+
process.exit(ExitCode.ERROR);
|
|
541
|
+
}
|
|
542
|
+
// For routes, we'll handle them as comma-separated paths
|
|
543
|
+
const routes = cmdOptions.routes.split(",").map((r) => r.trim());
|
|
544
|
+
targetUrl = `${config.defaultUrl}${routes[0]}`; // First route for now
|
|
545
|
+
}
|
|
546
|
+
else if (config.defaultUrl) {
|
|
547
|
+
targetUrl = config.defaultUrl;
|
|
548
|
+
}
|
|
549
|
+
if (!targetUrl) {
|
|
550
|
+
writeOutput("Error: URL is required. Provide as argument, --url flag, or defaultUrl in config.\n");
|
|
551
|
+
process.exit(ExitCode.ERROR);
|
|
552
|
+
}
|
|
553
|
+
await handleAudit(targetUrl, cmdOptions, config);
|
|
554
|
+
}
|
|
555
|
+
catch (error) {
|
|
556
|
+
process.stderr.write(renderError({
|
|
557
|
+
message: error instanceof Error ? error.message : String(error),
|
|
558
|
+
suggestion: "vertaa doctor",
|
|
559
|
+
exitCode: ExitCode.ERROR,
|
|
560
|
+
}) + "\n");
|
|
561
|
+
process.exit(ExitCode.ERROR);
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Output formatting helpers for the audit command.
|
|
3
|
+
*/
|
|
4
|
+
import type { AuditResponse } from "../../utils/client.js";
|
|
5
|
+
import { createOutput } from "../../output/factory.js";
|
|
6
|
+
import { evaluateQualityGate } from "../../quality-gate/index.js";
|
|
7
|
+
import type { OutputFormat } from "../../utils/detect-env.js";
|
|
8
|
+
import type { IssueLike, AuditCommandOptions } from "./types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Write output to file. Returns the resolved path if written to file, undefined otherwise.
|
|
11
|
+
*/
|
|
12
|
+
export declare function writeOutputToFile(content: string, outputPath: string | undefined, defaultPath?: string): string | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Get default output path based on format.
|
|
15
|
+
* Returns undefined for formats that should go to stdout by default.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getDefaultOutputPath(format: OutputFormat): string | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Output results in fire-and-forget mode (--no-wait).
|
|
20
|
+
*/
|
|
21
|
+
export declare function outputFireAndForget(created: AuditResponse, format: OutputFormat, formatter: ReturnType<typeof createOutput>, options: AuditCommandOptions, quiet: boolean): void;
|
|
22
|
+
/**
|
|
23
|
+
* Print quality gate result to stderr.
|
|
24
|
+
*/
|
|
25
|
+
export declare function outputQualityGateResult(gateResult: ReturnType<typeof evaluateQualityGate>): void;
|
|
26
|
+
/**
|
|
27
|
+
* Write formatted audit results to output or stdout.
|
|
28
|
+
*/
|
|
29
|
+
export declare function outputFormattedResults(filteredResult: Omit<AuditResponse, "issues"> & {
|
|
30
|
+
issues: IssueLike[];
|
|
31
|
+
}, format: OutputFormat, formatter: ReturnType<typeof createOutput>, groupBy: "severity" | "category" | "route", options: AuditCommandOptions, quiet: boolean): void;
|
|
32
|
+
//# sourceMappingURL=output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../../src/commands/audit/output.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAsB,MAAM,yBAAyB,CAAC;AAG3E,OAAO,EACL,mBAAmB,EACpB,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAGjE;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,GAAG,SAAS,CAgBpB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAO7E;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,EAC1C,OAAO,EAAE,mBAAmB,EAC5B,KAAK,EAAE,OAAO,GACb,IAAI,CAqBN;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,GACjD,IAAI,CAyBN;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,cAAc,EAAE,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,GAAG;IAAE,MAAM,EAAE,SAAS,EAAE,CAAA;CAAE,EACvE,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,EAC1C,OAAO,EAAE,UAAU,GAAG,UAAU,GAAG,OAAO,EAC1C,OAAO,EAAE,mBAAmB,EAC5B,KAAK,EAAE,OAAO,GACb,IAAI,CA6BN"}
|