@vertaaux/cli 0.3.3 → 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 +14 -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 -1038
- 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 +268 -95
- 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 +9 -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 +9 -1
- package/dist/output/human.d.ts.map +1 -1
- package/dist/output/human.js +17 -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/local-capture.d.ts +25 -0
- package/dist/utils/local-capture.d.ts.map +1 -0
- package/dist/utils/local-capture.js +57 -0
- package/dist/utils/url-classify.d.ts +18 -0
- package/dist/utils/url-classify.d.ts.map +1 -0
- package/dist/utils/url-classify.js +106 -0
- 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
|
@@ -15,6 +15,7 @@ export interface BaselineCommandOptions {
|
|
|
15
15
|
list?: boolean;
|
|
16
16
|
base?: string;
|
|
17
17
|
}
|
|
18
|
+
export declare function handleBaseline(jobIdArg: string | undefined, cmdOptions: BaselineCommandOptions): Promise<void>;
|
|
18
19
|
/**
|
|
19
20
|
* Register the baseline command with the Commander program.
|
|
20
21
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"baseline.d.ts","sourceRoot":"","sources":["../../src/commands/baseline.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"baseline.d.ts","sourceRoot":"","sources":["../../src/commands/baseline.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsFzC,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,UAAU,EAAE,sBAAsB,GACjC,OAAO,CAAC,IAAI,CAAC,CAkOf;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA4B9D"}
|
|
@@ -8,51 +8,18 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { readFile } from "fs/promises";
|
|
10
10
|
import { existsSync } from "fs";
|
|
11
|
+
import { renderError, renderWarning, runSteps, createRenderer } from "@vertaaux/tui";
|
|
11
12
|
import { ExitCode } from "../utils/exit-codes.js";
|
|
13
|
+
import { createClient } from "../utils/client.js";
|
|
12
14
|
import { loadBaseline, saveBaseline, createBaseline, addToBaseline, DEFAULT_BASELINE_PATH, } from "../baseline/manager.js";
|
|
13
15
|
import { generateFingerprint } from "../baseline/hash.js";
|
|
14
|
-
|
|
16
|
+
import { writeOutput } from "../output/envelope.js";
|
|
17
|
+
import { strings } from "../ui/strings.js";
|
|
15
18
|
/**
|
|
16
|
-
*
|
|
17
|
-
*/
|
|
18
|
-
function getApiBase() {
|
|
19
|
-
return (process.env.VERTAAUX_API_BASE || DEFAULT_API_BASE).replace(/\/$/, "");
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Get API key from environment.
|
|
23
|
-
*/
|
|
24
|
-
function getApiKey() {
|
|
25
|
-
const key = process.env.VERTAAUX_API_KEY;
|
|
26
|
-
if (!key) {
|
|
27
|
-
throw new Error("VERTAAUX_API_KEY is required");
|
|
28
|
-
}
|
|
29
|
-
return key;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Fetch audit results from API.
|
|
19
|
+
* Fetch audit results via SDK client.
|
|
33
20
|
*/
|
|
34
21
|
async function fetchAudit(jobId) {
|
|
35
|
-
|
|
36
|
-
const url = `${base}/audit/${jobId}`;
|
|
37
|
-
const res = await fetch(url, {
|
|
38
|
-
method: "GET",
|
|
39
|
-
headers: {
|
|
40
|
-
"Content-Type": "application/json",
|
|
41
|
-
"X-API-Key": getApiKey(),
|
|
42
|
-
},
|
|
43
|
-
});
|
|
44
|
-
if (!res.ok) {
|
|
45
|
-
let detail = res.statusText;
|
|
46
|
-
try {
|
|
47
|
-
const data = await res.json();
|
|
48
|
-
detail = data.error || data.message || detail;
|
|
49
|
-
}
|
|
50
|
-
catch {
|
|
51
|
-
// ignore
|
|
52
|
-
}
|
|
53
|
-
throw new Error(`HTTP ${res.status}: ${detail}`);
|
|
54
|
-
}
|
|
55
|
-
return (await res.json());
|
|
22
|
+
return createClient().audits.retrieve(jobId);
|
|
56
23
|
}
|
|
57
24
|
/**
|
|
58
25
|
* Normalize issues from various API response formats.
|
|
@@ -106,6 +73,199 @@ function formatBaselineSummary(baseline) {
|
|
|
106
73
|
}
|
|
107
74
|
return lines.join("\n");
|
|
108
75
|
}
|
|
76
|
+
export async function handleBaseline(jobIdArg, cmdOptions) {
|
|
77
|
+
const baselinePath = cmdOptions.path || DEFAULT_BASELINE_PATH;
|
|
78
|
+
const renderer = createRenderer("auto");
|
|
79
|
+
const baseState = {
|
|
80
|
+
phase: "baseline",
|
|
81
|
+
phaseIndex: 1,
|
|
82
|
+
phaseTotal: 1,
|
|
83
|
+
url: "",
|
|
84
|
+
mode: "baseline",
|
|
85
|
+
progress: {},
|
|
86
|
+
totals: {},
|
|
87
|
+
issueCount: 0,
|
|
88
|
+
scorePreview: null,
|
|
89
|
+
verbose: false,
|
|
90
|
+
elapsed: 0,
|
|
91
|
+
};
|
|
92
|
+
const startTime = Date.now();
|
|
93
|
+
// Handle --list: show baseline summary
|
|
94
|
+
if (cmdOptions.list) {
|
|
95
|
+
const steps = [
|
|
96
|
+
{
|
|
97
|
+
id: "fetch",
|
|
98
|
+
actionText: "Fetching baseline...",
|
|
99
|
+
summaryText: "Baseline loaded",
|
|
100
|
+
run: async () => {
|
|
101
|
+
const baseline = await loadBaseline(baselinePath);
|
|
102
|
+
if (!baseline) {
|
|
103
|
+
process.stderr.write(renderWarning({
|
|
104
|
+
message: "No baseline found.",
|
|
105
|
+
suggestion: `vertaa baseline <job-id> --path ${baselinePath}`,
|
|
106
|
+
}) + "\n");
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
writeOutput(formatBaselineSummary(baseline));
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
];
|
|
113
|
+
const { success, states } = await runSteps(steps, {
|
|
114
|
+
failFast: true,
|
|
115
|
+
onStateChange: (stepStates) => {
|
|
116
|
+
renderer.update({ ...baseState, stepStates, elapsed: Date.now() - startTime });
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
renderer.finish({ url: "", mode: "baseline", overallScore: 0, scores: {}, issueCount: 0, passed: success, elapsed: Date.now() - startTime });
|
|
120
|
+
if (!success) {
|
|
121
|
+
const failed = states.find(s => s.status === "failed");
|
|
122
|
+
process.stderr.write(renderError({
|
|
123
|
+
message: failed?.failReason || "Command failed",
|
|
124
|
+
suggestion: "vertaa doctor",
|
|
125
|
+
}) + "\n");
|
|
126
|
+
process.exitCode = ExitCode.ERROR;
|
|
127
|
+
}
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
// Handle --ignore: add single issue to baseline
|
|
131
|
+
if (cmdOptions.ignore) {
|
|
132
|
+
const issueId = cmdOptions.ignore;
|
|
133
|
+
const steps = [
|
|
134
|
+
{
|
|
135
|
+
id: "update",
|
|
136
|
+
actionText: "Updating baseline...",
|
|
137
|
+
summaryText: "Baseline updated",
|
|
138
|
+
run: async () => {
|
|
139
|
+
let baseline = await loadBaseline(baselinePath);
|
|
140
|
+
if (!baseline) {
|
|
141
|
+
throw new Error("No baseline found. Create one first with: vertaa baseline <job-id>");
|
|
142
|
+
}
|
|
143
|
+
// Need to find the issue to add it properly
|
|
144
|
+
let issue;
|
|
145
|
+
if (jobIdArg) {
|
|
146
|
+
const audit = await fetchAudit(jobIdArg);
|
|
147
|
+
const issues = normalizeIssues(audit.issues);
|
|
148
|
+
const found = findIssueById(issues, issueId);
|
|
149
|
+
if (!found) {
|
|
150
|
+
throw new Error(`Issue "${issueId}" not found in job ${jobIdArg}`);
|
|
151
|
+
}
|
|
152
|
+
issue = found;
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
// Create minimal issue from ID only
|
|
156
|
+
issue = { id: issueId, description: `Ignored: ${issueId}` };
|
|
157
|
+
}
|
|
158
|
+
baseline = addToBaseline(baseline, issue, cmdOptions.reason);
|
|
159
|
+
await saveBaseline(baseline, baselinePath);
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
];
|
|
163
|
+
const { success: ignoreSuccess, states: ignoreStates } = await runSteps(steps, {
|
|
164
|
+
failFast: true,
|
|
165
|
+
onStateChange: (stepStates) => {
|
|
166
|
+
renderer.update({ ...baseState, stepStates, elapsed: Date.now() - startTime });
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
renderer.finish({ url: "", mode: "baseline", overallScore: 0, scores: {}, issueCount: 0, passed: ignoreSuccess, elapsed: Date.now() - startTime });
|
|
170
|
+
if (!ignoreSuccess) {
|
|
171
|
+
const failed = ignoreStates.find(s => s.status === "failed");
|
|
172
|
+
process.stderr.write(renderError({
|
|
173
|
+
message: failed?.failReason || "Command failed",
|
|
174
|
+
suggestion: "vertaa doctor",
|
|
175
|
+
}) + "\n");
|
|
176
|
+
process.exitCode = ExitCode.ERROR;
|
|
177
|
+
}
|
|
178
|
+
writeOutput(`Added issue ${issueId} to baseline${cmdOptions.reason ? `\nReason: ${cmdOptions.reason}` : ""}`);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
// Handle --from-file: create baseline from JSON file
|
|
182
|
+
if (cmdOptions.fromFile) {
|
|
183
|
+
const filePath = cmdOptions.fromFile;
|
|
184
|
+
if (!existsSync(filePath)) {
|
|
185
|
+
process.stderr.write(renderError({
|
|
186
|
+
message: `File not found: ${filePath}`,
|
|
187
|
+
suggestion: "vertaa audit <url>",
|
|
188
|
+
exitCode: ExitCode.ERROR,
|
|
189
|
+
}) + "\n");
|
|
190
|
+
process.exit(ExitCode.ERROR);
|
|
191
|
+
}
|
|
192
|
+
const steps = [
|
|
193
|
+
{
|
|
194
|
+
id: "save",
|
|
195
|
+
actionText: "Saving baseline...",
|
|
196
|
+
summaryText: "Baseline saved",
|
|
197
|
+
run: async () => {
|
|
198
|
+
const content = await readFile(filePath, "utf-8");
|
|
199
|
+
const data = JSON.parse(content);
|
|
200
|
+
const issues = normalizeIssues(data.issues);
|
|
201
|
+
const url = data.url || "unknown";
|
|
202
|
+
const baseline = createBaseline(issues, url);
|
|
203
|
+
await saveBaseline(baseline, baselinePath);
|
|
204
|
+
writeOutput(`Baseline created with ${issues.length} issues\nSaved to: ${baselinePath}`);
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
];
|
|
208
|
+
const { success: fileSuccess, states: fileStates } = await runSteps(steps, {
|
|
209
|
+
failFast: true,
|
|
210
|
+
onStateChange: (stepStates) => {
|
|
211
|
+
renderer.update({ ...baseState, stepStates, elapsed: Date.now() - startTime });
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
renderer.finish({ url: "", mode: "baseline", overallScore: 0, scores: {}, issueCount: 0, passed: fileSuccess, elapsed: Date.now() - startTime });
|
|
215
|
+
if (!fileSuccess) {
|
|
216
|
+
const failed = fileStates.find(s => s.status === "failed");
|
|
217
|
+
process.stderr.write(renderError({
|
|
218
|
+
message: failed?.failReason || "Command failed",
|
|
219
|
+
suggestion: "vertaa doctor",
|
|
220
|
+
}) + "\n");
|
|
221
|
+
process.exitCode = ExitCode.ERROR;
|
|
222
|
+
}
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
// Handle job-id: create baseline from API audit
|
|
226
|
+
if (!jobIdArg) {
|
|
227
|
+
process.stderr.write(renderError({
|
|
228
|
+
message: "Provide job ID or use --from-file or --list",
|
|
229
|
+
context: "Usage: vertaa baseline <job-id>\n vertaa baseline --from-file <audit.json>\n vertaa baseline --list",
|
|
230
|
+
suggestion: "vertaa baseline --list",
|
|
231
|
+
exitCode: ExitCode.ERROR,
|
|
232
|
+
}) + "\n");
|
|
233
|
+
process.exit(ExitCode.ERROR);
|
|
234
|
+
}
|
|
235
|
+
const steps = [
|
|
236
|
+
{
|
|
237
|
+
id: "fetch",
|
|
238
|
+
actionText: "Fetching audit results...",
|
|
239
|
+
summaryText: "Audit results loaded",
|
|
240
|
+
run: async () => {
|
|
241
|
+
const audit = await fetchAudit(jobIdArg);
|
|
242
|
+
if (audit.status !== "completed") {
|
|
243
|
+
throw new Error(strings.fixAll.auditIncomplete(jobIdArg, audit.status || "unknown"));
|
|
244
|
+
}
|
|
245
|
+
const issues = normalizeIssues(audit.issues);
|
|
246
|
+
const url = audit.url || "unknown";
|
|
247
|
+
const baseline = createBaseline(issues, url);
|
|
248
|
+
await saveBaseline(baseline, baselinePath);
|
|
249
|
+
writeOutput(`Baseline created with ${issues.length} issues\nSaved to: ${baselinePath}`);
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
];
|
|
253
|
+
const { success: jobSuccess, states: jobStates } = await runSteps(steps, {
|
|
254
|
+
failFast: true,
|
|
255
|
+
onStateChange: (stepStates) => {
|
|
256
|
+
renderer.update({ ...baseState, stepStates, elapsed: Date.now() - startTime });
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
renderer.finish({ url: "", mode: "baseline", overallScore: 0, scores: {}, issueCount: 0, passed: jobSuccess, elapsed: Date.now() - startTime });
|
|
260
|
+
if (!jobSuccess) {
|
|
261
|
+
const failed = jobStates.find(s => s.status === "failed");
|
|
262
|
+
process.stderr.write(renderError({
|
|
263
|
+
message: failed?.failReason || "Command failed",
|
|
264
|
+
suggestion: "vertaa doctor",
|
|
265
|
+
}) + "\n");
|
|
266
|
+
process.exitCode = ExitCode.ERROR;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
109
269
|
/**
|
|
110
270
|
* Register the baseline command with the Commander program.
|
|
111
271
|
*/
|
|
@@ -120,90 +280,14 @@ export function registerBaselineCommand(program) {
|
|
|
120
280
|
.option("--list", "Show baselined issues count and last update")
|
|
121
281
|
.action(async (jobIdArg, cmdOptions) => {
|
|
122
282
|
try {
|
|
123
|
-
|
|
124
|
-
// Handle --list: show baseline summary
|
|
125
|
-
if (cmdOptions.list) {
|
|
126
|
-
const baseline = await loadBaseline(baselinePath);
|
|
127
|
-
if (!baseline) {
|
|
128
|
-
console.error("No baseline found.");
|
|
129
|
-
console.error(`Create one with: vertaa baseline <job-id> --path ${baselinePath}`);
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
console.error(formatBaselineSummary(baseline));
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
// Handle --ignore: add single issue to baseline
|
|
136
|
-
if (cmdOptions.ignore) {
|
|
137
|
-
const issueId = cmdOptions.ignore;
|
|
138
|
-
let baseline = await loadBaseline(baselinePath);
|
|
139
|
-
if (!baseline) {
|
|
140
|
-
console.error("No baseline found. Create one first with: vertaa baseline <job-id>");
|
|
141
|
-
process.exit(ExitCode.ERROR);
|
|
142
|
-
}
|
|
143
|
-
// Need to find the issue to add it properly
|
|
144
|
-
// If we have a job ID, fetch the audit; otherwise use a minimal issue
|
|
145
|
-
let issue;
|
|
146
|
-
if (jobIdArg) {
|
|
147
|
-
const audit = await fetchAudit(jobIdArg);
|
|
148
|
-
const issues = normalizeIssues(audit.issues);
|
|
149
|
-
const found = findIssueById(issues, issueId);
|
|
150
|
-
if (!found) {
|
|
151
|
-
console.error(`Issue "${issueId}" not found in job ${jobIdArg}`);
|
|
152
|
-
process.exit(ExitCode.ERROR);
|
|
153
|
-
}
|
|
154
|
-
issue = found;
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
// Create minimal issue from ID only
|
|
158
|
-
issue = { id: issueId, description: `Ignored: ${issueId}` };
|
|
159
|
-
}
|
|
160
|
-
baseline = addToBaseline(baseline, issue, cmdOptions.reason);
|
|
161
|
-
await saveBaseline(baseline, baselinePath);
|
|
162
|
-
console.error(`Added issue ${issueId} to baseline`);
|
|
163
|
-
if (cmdOptions.reason) {
|
|
164
|
-
console.error(`Reason: ${cmdOptions.reason}`);
|
|
165
|
-
}
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
// Handle --from-file: create baseline from JSON file
|
|
169
|
-
if (cmdOptions.fromFile) {
|
|
170
|
-
const filePath = cmdOptions.fromFile;
|
|
171
|
-
if (!existsSync(filePath)) {
|
|
172
|
-
console.error(`File not found: ${filePath}`);
|
|
173
|
-
process.exit(ExitCode.ERROR);
|
|
174
|
-
}
|
|
175
|
-
const content = await readFile(filePath, "utf-8");
|
|
176
|
-
const data = JSON.parse(content);
|
|
177
|
-
const issues = normalizeIssues(data.issues);
|
|
178
|
-
const url = data.url || "unknown";
|
|
179
|
-
const baseline = createBaseline(issues, url);
|
|
180
|
-
await saveBaseline(baseline, baselinePath);
|
|
181
|
-
console.error(`Baseline created with ${issues.length} issues`);
|
|
182
|
-
console.error(`Saved to: ${baselinePath}`);
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
// Handle job-id: create baseline from API audit
|
|
186
|
-
if (!jobIdArg) {
|
|
187
|
-
console.error("Provide job ID or use --from-file or --list");
|
|
188
|
-
console.error("Usage: vertaa baseline <job-id>");
|
|
189
|
-
console.error(" vertaa baseline --from-file <audit.json>");
|
|
190
|
-
console.error(" vertaa baseline --list");
|
|
191
|
-
process.exit(ExitCode.ERROR);
|
|
192
|
-
}
|
|
193
|
-
const audit = await fetchAudit(jobIdArg);
|
|
194
|
-
if (audit.status !== "completed") {
|
|
195
|
-
console.error(`Audit ${jobIdArg} is not completed (status: ${audit.status})`);
|
|
196
|
-
process.exit(ExitCode.ERROR);
|
|
197
|
-
}
|
|
198
|
-
const issues = normalizeIssues(audit.issues);
|
|
199
|
-
const url = audit.url || "unknown";
|
|
200
|
-
const baseline = createBaseline(issues, url);
|
|
201
|
-
await saveBaseline(baseline, baselinePath);
|
|
202
|
-
console.error(`Baseline created with ${issues.length} issues`);
|
|
203
|
-
console.error(`Saved to: ${baselinePath}`);
|
|
283
|
+
await handleBaseline(jobIdArg, cmdOptions);
|
|
204
284
|
}
|
|
205
285
|
catch (error) {
|
|
206
|
-
|
|
286
|
+
process.stderr.write(renderError({
|
|
287
|
+
message: error instanceof Error ? error.message : String(error),
|
|
288
|
+
suggestion: "vertaa audit <url>",
|
|
289
|
+
exitCode: ExitCode.ERROR,
|
|
290
|
+
}) + "\n");
|
|
207
291
|
process.exit(ExitCode.ERROR);
|
|
208
292
|
}
|
|
209
293
|
});
|
|
@@ -6,6 +6,28 @@
|
|
|
6
6
|
* Uses sticky comment semantics to update existing comments.
|
|
7
7
|
*/
|
|
8
8
|
import { Command } from "commander";
|
|
9
|
+
import { type MarkdownOptions } from "../output/markdown.js";
|
|
10
|
+
/**
|
|
11
|
+
* Options for comment generation.
|
|
12
|
+
*/
|
|
13
|
+
interface CommentOptions {
|
|
14
|
+
input?: string;
|
|
15
|
+
baseline?: string;
|
|
16
|
+
format?: "markdown" | "json";
|
|
17
|
+
output?: string;
|
|
18
|
+
collapse?: boolean;
|
|
19
|
+
groupBy?: MarkdownOptions["groupBy"];
|
|
20
|
+
post?: boolean;
|
|
21
|
+
githubToken?: string;
|
|
22
|
+
gitlabToken?: string;
|
|
23
|
+
pr?: number;
|
|
24
|
+
repo?: string;
|
|
25
|
+
noPostIfClean?: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Handle the comment command.
|
|
29
|
+
*/
|
|
30
|
+
export declare function handleComment(options: CommentOptions): Promise<void>;
|
|
9
31
|
/**
|
|
10
32
|
* Register the comment command with the Commander program.
|
|
11
33
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"comment.d.ts","sourceRoot":"","sources":["../../src/commands/comment.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"comment.d.ts","sourceRoot":"","sources":["../../src/commands/comment.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,OAAO,EAGL,KAAK,eAAe,EAErB,MAAM,uBAAuB,CAAC;AA0B/B;;GAEG;AACH,UAAU,cAAc;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;IAErC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAqJD;;GAEG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAyQ1E;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAgG7D;AAGD,OAAO,EAAE,qBAAqB,IAAI,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/commands/comment.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import fs from "fs";
|
|
9
9
|
import path from "path";
|
|
10
|
+
import { renderError, runSteps, createRenderer } from "@vertaaux/tui";
|
|
10
11
|
import { loadBaseline } from "../baseline/manager.js";
|
|
11
12
|
import { ExitCode } from "../utils/exit-codes.js";
|
|
12
13
|
import { formatMarkdownComment, categorizeIssuesForComment, } from "../output/markdown.js";
|
|
@@ -14,6 +15,7 @@ import { createEnvelope, writeJsonOutput, writeOutput } from "../output/envelope
|
|
|
14
15
|
import { resolveCommandFormat } from "../output/formats.js";
|
|
15
16
|
import { postOrUpdateGitHubComment, parseRepository, extractPRNumber, } from "../ci/github-api.js";
|
|
16
17
|
import { postOrUpdateGitLabNote, getGitLabConfig, extractMRIid, } from "../ci/gitlab-api.js";
|
|
18
|
+
import { strings } from "../ui/strings.js";
|
|
17
19
|
/**
|
|
18
20
|
* Default path for latest audit results.
|
|
19
21
|
*/
|
|
@@ -126,14 +128,33 @@ async function postComment(context, markdown) {
|
|
|
126
128
|
/**
|
|
127
129
|
* Handle the comment command.
|
|
128
130
|
*/
|
|
129
|
-
async function handleComment(options) {
|
|
131
|
+
export async function handleComment(options) {
|
|
132
|
+
const renderer = createRenderer("auto");
|
|
133
|
+
const baseState = {
|
|
134
|
+
phase: "comment",
|
|
135
|
+
phaseIndex: 1,
|
|
136
|
+
phaseTotal: 1,
|
|
137
|
+
url: "",
|
|
138
|
+
mode: "comment",
|
|
139
|
+
progress: {},
|
|
140
|
+
totals: {},
|
|
141
|
+
issueCount: 0,
|
|
142
|
+
scorePreview: null,
|
|
143
|
+
verbose: false,
|
|
144
|
+
elapsed: 0,
|
|
145
|
+
};
|
|
146
|
+
const startTime = Date.now();
|
|
130
147
|
let auditResult;
|
|
131
|
-
// Load audit results
|
|
148
|
+
// Load audit results (pre-step, may need async iteration for stdin)
|
|
132
149
|
if (options.input) {
|
|
133
150
|
// From file
|
|
134
151
|
const inputPath = path.resolve(process.cwd(), options.input);
|
|
135
152
|
if (!fs.existsSync(inputPath)) {
|
|
136
|
-
|
|
153
|
+
process.stderr.write(renderError({
|
|
154
|
+
message: `Input file not found: ${options.input}`,
|
|
155
|
+
suggestion: "vertaa audit <url>",
|
|
156
|
+
exitCode: ExitCode.ERROR,
|
|
157
|
+
}) + "\n");
|
|
137
158
|
process.exit(ExitCode.ERROR);
|
|
138
159
|
}
|
|
139
160
|
const content = fs.readFileSync(inputPath, "utf-8");
|
|
@@ -156,7 +177,11 @@ async function handleComment(options) {
|
|
|
156
177
|
auditResult = JSON.parse(content);
|
|
157
178
|
}
|
|
158
179
|
else {
|
|
159
|
-
|
|
180
|
+
process.stderr.write(renderError({
|
|
181
|
+
message: strings.comment.errors.noInput,
|
|
182
|
+
suggestion: "vertaa audit <url>",
|
|
183
|
+
exitCode: ExitCode.ERROR,
|
|
184
|
+
}) + "\n");
|
|
160
185
|
process.exit(ExitCode.ERROR);
|
|
161
186
|
}
|
|
162
187
|
}
|
|
@@ -169,58 +194,85 @@ async function handleComment(options) {
|
|
|
169
194
|
// Try default baseline
|
|
170
195
|
baseline = await loadBaseline();
|
|
171
196
|
}
|
|
172
|
-
//
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
// Build comment data
|
|
176
|
-
const commentData = {
|
|
177
|
-
auditId: auditResult.job_id,
|
|
178
|
-
url: auditResult.url,
|
|
179
|
-
newIssues,
|
|
180
|
-
fixedIssues,
|
|
181
|
-
existingIssues,
|
|
182
|
-
scores: auditResult.scores,
|
|
183
|
-
};
|
|
184
|
-
// Generate output
|
|
197
|
+
// State to capture within steps
|
|
198
|
+
let outputContent = "";
|
|
199
|
+
let jsonData = {};
|
|
185
200
|
const isJson = options.format === "json";
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
201
|
+
const steps = [
|
|
202
|
+
{
|
|
203
|
+
id: "generate",
|
|
204
|
+
actionText: "Generating review comment...",
|
|
205
|
+
summaryText: "Comment generated",
|
|
206
|
+
run: async () => {
|
|
207
|
+
// Categorize issues
|
|
208
|
+
const issues = normalizeIssues(auditResult.issues);
|
|
209
|
+
const { newIssues, fixedIssues, existingIssues } = categorizeIssuesForComment(issues, baseline);
|
|
210
|
+
// Build comment data
|
|
211
|
+
const commentData = {
|
|
212
|
+
auditId: auditResult.job_id,
|
|
213
|
+
url: auditResult.url,
|
|
214
|
+
newIssues,
|
|
215
|
+
fixedIssues,
|
|
216
|
+
existingIssues,
|
|
217
|
+
scores: auditResult.scores,
|
|
218
|
+
};
|
|
219
|
+
jsonData = {
|
|
220
|
+
auditId: auditResult.job_id,
|
|
221
|
+
url: auditResult.url,
|
|
222
|
+
newIssues: newIssues.length,
|
|
223
|
+
existingIssues: existingIssues.length,
|
|
224
|
+
fixedIssues: fixedIssues.length,
|
|
225
|
+
issues: {
|
|
226
|
+
new: newIssues,
|
|
227
|
+
existing: existingIssues,
|
|
228
|
+
fixed: fixedIssues,
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
if (isJson) {
|
|
232
|
+
outputContent = JSON.stringify(jsonData, null, 2);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
outputContent = formatMarkdownComment(commentData, {
|
|
236
|
+
groupBy: options.groupBy || "severity",
|
|
237
|
+
collapse: options.collapse ?? newIssues.length > 3,
|
|
238
|
+
collapseThreshold: 3,
|
|
239
|
+
includeEvidence: true,
|
|
240
|
+
includeFixes: true,
|
|
241
|
+
baseUrl: "https://vertaaux.ai",
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
},
|
|
196
245
|
},
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (
|
|
200
|
-
//
|
|
201
|
-
output = JSON.stringify(jsonData, null, 2);
|
|
246
|
+
];
|
|
247
|
+
// Check if posting and we should skip
|
|
248
|
+
if (options.post && options.noPostIfClean) {
|
|
249
|
+
// We need to generate first to check, so we still run the step
|
|
202
250
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
251
|
+
const { success, states } = await runSteps(steps, {
|
|
252
|
+
failFast: true,
|
|
253
|
+
onStateChange: (stepStates) => {
|
|
254
|
+
renderer.update({ ...baseState, stepStates, elapsed: Date.now() - startTime });
|
|
255
|
+
},
|
|
256
|
+
});
|
|
257
|
+
renderer.finish({ url: "", mode: "comment", overallScore: 0, scores: {}, issueCount: 0, passed: success, elapsed: Date.now() - startTime });
|
|
258
|
+
if (!success) {
|
|
259
|
+
const failed = states.find(s => s.status === "failed");
|
|
260
|
+
process.stderr.write(renderError({
|
|
261
|
+
message: failed?.failReason || "Command failed",
|
|
262
|
+
suggestion: "vertaa doctor",
|
|
263
|
+
}) + "\n");
|
|
264
|
+
process.exitCode = ExitCode.ERROR;
|
|
213
265
|
}
|
|
214
266
|
// Handle posting
|
|
215
267
|
if (options.post) {
|
|
268
|
+
const newIssuesCount = jsonData.newIssues ?? 0;
|
|
216
269
|
// Check if we should skip posting
|
|
217
|
-
if (options.noPostIfClean &&
|
|
218
|
-
console.error("No new issues found. Skipping comment post (--no-post-if-clean).");
|
|
270
|
+
if (options.noPostIfClean && newIssuesCount === 0) {
|
|
219
271
|
// Still write output if requested
|
|
220
272
|
if (options.output) {
|
|
221
273
|
const outputPath = path.resolve(process.cwd(), options.output);
|
|
222
|
-
fs.writeFileSync(outputPath,
|
|
223
|
-
|
|
274
|
+
fs.writeFileSync(outputPath, outputContent, "utf-8");
|
|
275
|
+
writeOutput(`Comment written to: ${outputPath}`);
|
|
224
276
|
}
|
|
225
277
|
return;
|
|
226
278
|
}
|
|
@@ -264,30 +316,38 @@ async function handleComment(options) {
|
|
|
264
316
|
context = detectCIContext();
|
|
265
317
|
}
|
|
266
318
|
if (!context) {
|
|
267
|
-
|
|
268
|
-
|
|
319
|
+
process.stderr.write(renderError({
|
|
320
|
+
message: "Cannot post comment — not in a recognized CI environment.",
|
|
321
|
+
context: "Provide --github-token with --repo and --pr, or run in GitHub Actions/GitLab CI.",
|
|
322
|
+
suggestion: "vertaa comment --github-token <token> --repo owner/repo --pr <number>",
|
|
323
|
+
exitCode: ExitCode.ERROR,
|
|
324
|
+
}) + "\n");
|
|
269
325
|
// Output for debugging via stdout
|
|
270
326
|
if (isJson) {
|
|
271
327
|
writeJsonOutput(jsonData, "comment");
|
|
272
328
|
}
|
|
273
329
|
else {
|
|
274
|
-
writeOutput(
|
|
330
|
+
writeOutput(outputContent);
|
|
275
331
|
}
|
|
276
332
|
process.exit(ExitCode.ERROR);
|
|
277
333
|
}
|
|
278
334
|
try {
|
|
279
|
-
const result = await postComment(context,
|
|
280
|
-
|
|
335
|
+
const result = await postComment(context, outputContent);
|
|
336
|
+
writeOutput(`Comment posted: ${result.url}`);
|
|
281
337
|
}
|
|
282
338
|
catch (error) {
|
|
283
|
-
|
|
339
|
+
process.stderr.write(renderError({
|
|
340
|
+
message: `Error posting comment: ${error instanceof Error ? error.message : String(error)}`,
|
|
341
|
+
context: "Generated output written for debugging.",
|
|
342
|
+
suggestion: "vertaa comment --github-token <token> --repo owner/repo --pr <number>",
|
|
343
|
+
exitCode: ExitCode.ERROR,
|
|
344
|
+
}) + "\n");
|
|
284
345
|
// Output for debugging even on failure
|
|
285
|
-
console.error("\nGenerated output (for debugging):");
|
|
286
346
|
if (isJson) {
|
|
287
347
|
writeJsonOutput(jsonData, "comment");
|
|
288
348
|
}
|
|
289
349
|
else {
|
|
290
|
-
writeOutput(
|
|
350
|
+
writeOutput(outputContent);
|
|
291
351
|
}
|
|
292
352
|
process.exit(ExitCode.ERROR);
|
|
293
353
|
}
|
|
@@ -297,9 +357,9 @@ async function handleComment(options) {
|
|
|
297
357
|
const outputPath = path.resolve(process.cwd(), options.output);
|
|
298
358
|
const fileContent = isJson
|
|
299
359
|
? JSON.stringify(createEnvelope(jsonData, "comment"), null, 2)
|
|
300
|
-
:
|
|
360
|
+
: outputContent;
|
|
301
361
|
fs.writeFileSync(outputPath, fileContent, "utf-8");
|
|
302
|
-
|
|
362
|
+
writeOutput(`Comment written to: ${outputPath}`);
|
|
303
363
|
}
|
|
304
364
|
else if (!options.post) {
|
|
305
365
|
// Only print to stdout if not posting (posting already logs URL)
|
|
@@ -307,7 +367,7 @@ async function handleComment(options) {
|
|
|
307
367
|
writeJsonOutput(jsonData, "comment");
|
|
308
368
|
}
|
|
309
369
|
else {
|
|
310
|
-
writeOutput(
|
|
370
|
+
writeOutput(outputContent);
|
|
311
371
|
}
|
|
312
372
|
}
|
|
313
373
|
}
|
|
@@ -354,7 +414,11 @@ export function registerCommentCommand(program) {
|
|
|
354
414
|
});
|
|
355
415
|
}
|
|
356
416
|
catch (error) {
|
|
357
|
-
|
|
417
|
+
process.stderr.write(renderError({
|
|
418
|
+
message: error instanceof Error ? error.message : String(error),
|
|
419
|
+
suggestion: "vertaa audit <url>",
|
|
420
|
+
exitCode: ExitCode.ERROR,
|
|
421
|
+
}) + "\n");
|
|
358
422
|
process.exit(ExitCode.ERROR);
|
|
359
423
|
}
|
|
360
424
|
});
|