@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.
Files changed (227) hide show
  1. package/CHANGELOG.md +97 -0
  2. package/MIGRATION.md +239 -0
  3. package/README.md +34 -16
  4. package/dist/app/interactive-app.d.ts +101 -0
  5. package/dist/app/interactive-app.d.ts.map +1 -0
  6. package/dist/app/interactive-app.js +309 -0
  7. package/dist/app/layout/canvas.d.ts +23 -0
  8. package/dist/app/layout/canvas.d.ts.map +1 -0
  9. package/dist/app/layout/canvas.js +36 -0
  10. package/dist/app/layout/footer.d.ts +31 -0
  11. package/dist/app/layout/footer.d.ts.map +1 -0
  12. package/dist/app/layout/footer.js +41 -0
  13. package/dist/app/layout/header.d.ts +20 -0
  14. package/dist/app/layout/header.d.ts.map +1 -0
  15. package/dist/app/layout/header.js +27 -0
  16. package/dist/app/menu/categories.d.ts +20 -0
  17. package/dist/app/menu/categories.d.ts.map +1 -0
  18. package/dist/app/menu/categories.js +181 -0
  19. package/dist/app/menu/filter.d.ts +17 -0
  20. package/dist/app/menu/filter.d.ts.map +1 -0
  21. package/dist/app/menu/filter.js +33 -0
  22. package/dist/app/menu/menu-view.d.ts +35 -0
  23. package/dist/app/menu/menu-view.d.ts.map +1 -0
  24. package/dist/app/menu/menu-view.js +230 -0
  25. package/dist/app/menu/recent.d.ts +24 -0
  26. package/dist/app/menu/recent.d.ts.map +1 -0
  27. package/dist/app/menu/recent.js +49 -0
  28. package/dist/app/types.d.ts +43 -0
  29. package/dist/app/types.d.ts.map +1 -0
  30. package/dist/app/types.js +7 -0
  31. package/dist/app/views/command-runner.d.ts +36 -0
  32. package/dist/app/views/command-runner.d.ts.map +1 -0
  33. package/dist/app/views/command-runner.js +372 -0
  34. package/dist/app/views/help-overlay.d.ts +21 -0
  35. package/dist/app/views/help-overlay.d.ts.map +1 -0
  36. package/dist/app/views/help-overlay.js +45 -0
  37. package/dist/auth/ci-token.d.ts +14 -2
  38. package/dist/auth/ci-token.d.ts.map +1 -1
  39. package/dist/auth/ci-token.js +15 -30
  40. package/dist/auth/device-flow.d.ts +2 -1
  41. package/dist/auth/device-flow.d.ts.map +1 -1
  42. package/dist/auth/device-flow.js +13 -10
  43. package/dist/auth/token-store.d.ts.map +1 -1
  44. package/dist/auth/token-store.js +12 -2
  45. package/dist/baseline/diff.d.ts +2 -2
  46. package/dist/baseline/diff.d.ts.map +1 -1
  47. package/dist/baseline/diff.js +15 -34
  48. package/dist/commands/a11y.d.ts +9 -0
  49. package/dist/commands/a11y.d.ts.map +1 -0
  50. package/dist/commands/a11y.js +76 -0
  51. package/dist/commands/audit/artifacts.d.ts +27 -0
  52. package/dist/commands/audit/artifacts.d.ts.map +1 -0
  53. package/dist/commands/audit/artifacts.js +158 -0
  54. package/dist/commands/audit/ci-detection.d.ts +18 -0
  55. package/dist/commands/audit/ci-detection.d.ts.map +1 -0
  56. package/dist/commands/audit/ci-detection.js +71 -0
  57. package/dist/commands/audit/explain.d.ts +11 -0
  58. package/dist/commands/audit/explain.d.ts.map +1 -0
  59. package/dist/commands/audit/explain.js +45 -0
  60. package/dist/commands/audit/filters.d.ts +17 -0
  61. package/dist/commands/audit/filters.d.ts.map +1 -0
  62. package/dist/commands/audit/filters.js +40 -0
  63. package/dist/commands/audit/index.d.ts +18 -0
  64. package/dist/commands/audit/index.d.ts.map +1 -0
  65. package/dist/commands/audit/index.js +564 -0
  66. package/dist/commands/audit/output.d.ts +32 -0
  67. package/dist/commands/audit/output.d.ts.map +1 -0
  68. package/dist/commands/audit/output.js +130 -0
  69. package/dist/commands/audit/policy.d.ts +19 -0
  70. package/dist/commands/audit/policy.d.ts.map +1 -0
  71. package/dist/commands/audit/policy.js +102 -0
  72. package/dist/commands/audit/scoring.d.ts +23 -0
  73. package/dist/commands/audit/scoring.d.ts.map +1 -0
  74. package/dist/commands/audit/scoring.js +70 -0
  75. package/dist/commands/audit/types.d.ts +88 -0
  76. package/dist/commands/audit/types.d.ts.map +1 -0
  77. package/dist/commands/audit/types.js +8 -0
  78. package/dist/commands/audit.d.ts +2 -60
  79. package/dist/commands/audit.d.ts.map +1 -1
  80. package/dist/commands/audit.js +2 -1038
  81. package/dist/commands/baseline.d.ts +1 -0
  82. package/dist/commands/baseline.d.ts.map +1 -1
  83. package/dist/commands/baseline.js +205 -121
  84. package/dist/commands/comment.d.ts +22 -0
  85. package/dist/commands/comment.d.ts.map +1 -1
  86. package/dist/commands/comment.js +122 -58
  87. package/dist/commands/compare.d.ts +17 -0
  88. package/dist/commands/compare.d.ts.map +1 -1
  89. package/dist/commands/compare.js +287 -180
  90. package/dist/commands/diff.d.ts +5 -0
  91. package/dist/commands/diff.d.ts.map +1 -1
  92. package/dist/commands/diff.js +168 -141
  93. package/dist/commands/doc.d.ts +10 -0
  94. package/dist/commands/doc.d.ts.map +1 -1
  95. package/dist/commands/doc.js +134 -76
  96. package/dist/commands/doctor.d.ts +2 -0
  97. package/dist/commands/doctor.d.ts.map +1 -1
  98. package/dist/commands/doctor.js +164 -17
  99. package/dist/commands/download.d.ts +10 -0
  100. package/dist/commands/download.d.ts.map +1 -1
  101. package/dist/commands/download.js +169 -112
  102. package/dist/commands/explain.d.ts +5 -0
  103. package/dist/commands/explain.d.ts.map +1 -1
  104. package/dist/commands/explain.js +241 -155
  105. package/dist/commands/fix-all.d.ts +25 -0
  106. package/dist/commands/fix-all.d.ts.map +1 -0
  107. package/dist/commands/fix-all.js +206 -0
  108. package/dist/commands/fix-plan.d.ts +9 -0
  109. package/dist/commands/fix-plan.d.ts.map +1 -1
  110. package/dist/commands/fix-plan.js +152 -89
  111. package/dist/commands/fix.d.ts +17 -0
  112. package/dist/commands/fix.d.ts.map +1 -0
  113. package/dist/commands/fix.js +111 -0
  114. package/dist/commands/init.d.ts +11 -0
  115. package/dist/commands/init.d.ts.map +1 -1
  116. package/dist/commands/init.js +94 -42
  117. package/dist/commands/login.d.ts +18 -0
  118. package/dist/commands/login.d.ts.map +1 -1
  119. package/dist/commands/login.js +268 -95
  120. package/dist/commands/patch-review.d.ts +11 -0
  121. package/dist/commands/patch-review.d.ts.map +1 -1
  122. package/dist/commands/patch-review.js +159 -97
  123. package/dist/commands/policy.d.ts +31 -0
  124. package/dist/commands/policy.d.ts.map +1 -1
  125. package/dist/commands/policy.js +269 -124
  126. package/dist/commands/release-notes.d.ts +10 -0
  127. package/dist/commands/release-notes.d.ts.map +1 -1
  128. package/dist/commands/release-notes.js +127 -73
  129. package/dist/commands/scan.d.ts +13 -0
  130. package/dist/commands/scan.d.ts.map +1 -0
  131. package/dist/commands/scan.js +133 -0
  132. package/dist/commands/status.d.ts +9 -0
  133. package/dist/commands/status.d.ts.map +1 -0
  134. package/dist/commands/status.js +81 -0
  135. package/dist/commands/suggest.d.ts +10 -0
  136. package/dist/commands/suggest.d.ts.map +1 -1
  137. package/dist/commands/suggest.js +153 -82
  138. package/dist/commands/triage.d.ts +35 -0
  139. package/dist/commands/triage.d.ts.map +1 -1
  140. package/dist/commands/triage.js +206 -81
  141. package/dist/commands/upload.d.ts +9 -0
  142. package/dist/commands/upload.d.ts.map +1 -1
  143. package/dist/commands/upload.js +140 -101
  144. package/dist/commands/verify.d.ts +13 -0
  145. package/dist/commands/verify.d.ts.map +1 -0
  146. package/dist/commands/verify.js +118 -0
  147. package/dist/index.d.ts +3 -2
  148. package/dist/index.d.ts.map +1 -1
  149. package/dist/index.js +125 -990
  150. package/dist/interactive/fix-wizard.d.ts +3 -0
  151. package/dist/interactive/fix-wizard.d.ts.map +1 -1
  152. package/dist/interactive/fix-wizard.js +130 -112
  153. package/dist/interactive/init-wizard.d.ts +3 -1
  154. package/dist/interactive/init-wizard.d.ts.map +1 -1
  155. package/dist/interactive/init-wizard.js +207 -138
  156. package/dist/interactive/prompts.d.ts +7 -3
  157. package/dist/interactive/prompts.d.ts.map +1 -1
  158. package/dist/interactive/prompts.js +44 -23
  159. package/dist/output/envelope.d.ts +2 -0
  160. package/dist/output/envelope.d.ts.map +1 -1
  161. package/dist/output/envelope.js +18 -2
  162. package/dist/output/factory.d.ts +9 -1
  163. package/dist/output/factory.d.ts.map +1 -1
  164. package/dist/output/html.d.ts +2 -1
  165. package/dist/output/html.d.ts.map +1 -1
  166. package/dist/output/html.js +3 -2
  167. package/dist/output/human.d.ts +9 -1
  168. package/dist/output/human.d.ts.map +1 -1
  169. package/dist/output/human.js +17 -2
  170. package/dist/output/json.d.ts +2 -1
  171. package/dist/output/json.d.ts.map +1 -1
  172. package/dist/output/junit.d.ts +2 -1
  173. package/dist/output/junit.d.ts.map +1 -1
  174. package/dist/output/sarif.d.ts +2 -1
  175. package/dist/output/sarif.d.ts.map +1 -1
  176. package/dist/types.d.ts +74 -0
  177. package/dist/types.d.ts.map +1 -0
  178. package/dist/types.js +5 -0
  179. package/dist/ui/banner.d.ts +34 -0
  180. package/dist/ui/banner.d.ts.map +1 -1
  181. package/dist/ui/banner.js +97 -5
  182. package/dist/ui/diagnostics.d.ts +9 -4
  183. package/dist/ui/diagnostics.d.ts.map +1 -1
  184. package/dist/ui/diagnostics.js +32 -82
  185. package/dist/ui/strings.d.ts +373 -0
  186. package/dist/ui/strings.d.ts.map +1 -0
  187. package/dist/ui/strings.js +499 -0
  188. package/dist/ui/table.d.ts +0 -2
  189. package/dist/ui/table.d.ts.map +1 -1
  190. package/dist/ui/table.js +3 -4
  191. package/dist/utils/api-client.d.ts +46 -0
  192. package/dist/utils/api-client.d.ts.map +1 -0
  193. package/dist/utils/api-client.js +170 -0
  194. package/dist/utils/client.d.ts +29 -18
  195. package/dist/utils/client.d.ts.map +1 -1
  196. package/dist/utils/client.js +102 -12
  197. package/dist/utils/formatters.d.ts +38 -0
  198. package/dist/utils/formatters.d.ts.map +1 -0
  199. package/dist/utils/formatters.js +277 -0
  200. package/dist/utils/local-capture.d.ts +25 -0
  201. package/dist/utils/local-capture.d.ts.map +1 -0
  202. package/dist/utils/local-capture.js +57 -0
  203. package/dist/utils/url-classify.d.ts +18 -0
  204. package/dist/utils/url-classify.d.ts.map +1 -0
  205. package/dist/utils/url-classify.js +106 -0
  206. package/node_modules/@vertaaux/tui/dist/index.cjs +713 -20
  207. package/node_modules/@vertaaux/tui/dist/index.cjs.map +1 -1
  208. package/node_modules/@vertaaux/tui/dist/index.d.cts +361 -4
  209. package/node_modules/@vertaaux/tui/dist/index.d.ts +361 -4
  210. package/node_modules/@vertaaux/tui/dist/index.js +689 -21
  211. package/node_modules/@vertaaux/tui/dist/index.js.map +1 -1
  212. package/package.json +13 -5
  213. package/dist/commands/client.d.ts +0 -14
  214. package/dist/commands/client.d.ts.map +0 -1
  215. package/dist/commands/client.js +0 -362
  216. package/dist/commands/drift.d.ts +0 -15
  217. package/dist/commands/drift.d.ts.map +0 -1
  218. package/dist/commands/drift.js +0 -309
  219. package/dist/commands/protect.d.ts +0 -16
  220. package/dist/commands/protect.d.ts.map +0 -1
  221. package/dist/commands/protect.js +0 -323
  222. package/dist/commands/report.d.ts +0 -15
  223. package/dist/commands/report.d.ts.map +0 -1
  224. package/dist/commands/report.js +0 -214
  225. package/dist/policy/sync.d.ts +0 -67
  226. package/dist/policy/sync.d.ts.map +0 -1
  227. package/dist/policy/sync.js +0 -147
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Legacy fix-all command handler.
3
+ * Generates fix patches for all issues in an audit.
4
+ */
5
+ import { renderError, createRenderer, runSteps } from "@vertaaux/tui";
6
+ import { ExitCode } from "../utils/exit-codes.js";
7
+ import { resolveApiBase, resolveFormat, getString, getBool, createClient, } from "../utils/api-client.js";
8
+ import { normalizeIssues, isAutoFixable, formatBatchMarkdown, } from "../utils/formatters.js";
9
+ import { writeJsonOutput, writeOutput } from "../output/envelope.js";
10
+ import { strings } from "../ui/strings.js";
11
+ const BATCH_LIMIT = 10;
12
+ export async function handleFixAll(opts) {
13
+ const { jobId } = opts;
14
+ const autoFixOnly = opts.autoFixOnly || false;
15
+ const format = opts.format || "md";
16
+ if (!opts.fileContent) {
17
+ throw new Error(strings.fixAll.errors.missingArgs);
18
+ }
19
+ const renderer = createRenderer("auto");
20
+ const baseState = {
21
+ phase: "fix-all",
22
+ phaseIndex: 1,
23
+ phaseTotal: 2,
24
+ url: "",
25
+ mode: "fix-all",
26
+ progress: {},
27
+ totals: {},
28
+ issueCount: 0,
29
+ scorePreview: null,
30
+ verbose: false,
31
+ elapsed: 0,
32
+ };
33
+ const startTime = Date.now();
34
+ const client = createClient({ base: opts.base });
35
+ const ctx = { results: null };
36
+ const steps = [
37
+ {
38
+ id: "analyze",
39
+ actionText: "Analyzing fixable issues...",
40
+ summaryText: "Issues identified",
41
+ run: async () => {
42
+ const audit = await client.audits.retrieve(jobId);
43
+ if (audit.status !== "completed") {
44
+ throw new Error(`Audit ${jobId} is not completed (status: ${audit.status})`);
45
+ }
46
+ // Normalize and filter issues
47
+ let issues = normalizeIssues(audit.issues);
48
+ const totalRequested = issues.length;
49
+ if (autoFixOnly) {
50
+ issues = issues.filter((issue) => {
51
+ const typeId = issue.id || "";
52
+ return isAutoFixable(typeId);
53
+ });
54
+ }
55
+ // Respect batch limit
56
+ const totalSkipped = Math.max(0, issues.length - BATCH_LIMIT);
57
+ ctx.results = {
58
+ successes: [],
59
+ failures: [],
60
+ totalRequested,
61
+ totalSkipped,
62
+ };
63
+ // --dry-run: show what would be processed and exit
64
+ if (opts.dryRun) {
65
+ const issuesToShow = issues.slice(0, BATCH_LIMIT);
66
+ const lines = [];
67
+ lines.push(`[dry-run] Would generate patches for ${issuesToShow.length} issues:`);
68
+ for (const issue of issuesToShow) {
69
+ lines.push(` - ${issue.id || "unknown"}: ${issue.title || issue.description || "(no title)"}`);
70
+ }
71
+ if (totalSkipped > 0) {
72
+ lines.push(` (${totalSkipped} additional issues skipped — batch limit ${BATCH_LIMIT})`);
73
+ }
74
+ lines.push("\nNo patches generated. Remove --dry-run to execute.");
75
+ writeOutput(lines.join("\n"));
76
+ }
77
+ },
78
+ },
79
+ {
80
+ id: "fix",
81
+ actionText: "Applying fixes...",
82
+ summaryText: "Fixes applied",
83
+ run: async () => {
84
+ if (opts.dryRun || !ctx.results)
85
+ return;
86
+ const audit = await client.audits.retrieve(jobId);
87
+ let issues = normalizeIssues(audit.issues);
88
+ if (autoFixOnly) {
89
+ issues = issues.filter((issue) => {
90
+ const typeId = issue.id || "";
91
+ return isAutoFixable(typeId);
92
+ });
93
+ }
94
+ const issuesToProcess = issues.slice(0, BATCH_LIMIT);
95
+ for (let i = 0; i < issuesToProcess.length; i++) {
96
+ const issue = issuesToProcess[i];
97
+ const curIssueId = issue.id || `issue-${i}`;
98
+ try {
99
+ const patchResult = await client.patches.generate({
100
+ job_id: jobId,
101
+ issue_id: curIssueId,
102
+ file_content: opts.fileContent,
103
+ });
104
+ if (patchResult.success && patchResult.patch) {
105
+ ctx.results.successes.push({
106
+ issueId: curIssueId,
107
+ patch: patchResult.patch,
108
+ });
109
+ }
110
+ else {
111
+ ctx.results.failures.push({
112
+ issueId: curIssueId,
113
+ reason: patchResult.error?.code || "PATCH_FAILED",
114
+ details: patchResult.error?.message,
115
+ });
116
+ }
117
+ }
118
+ catch (err) {
119
+ ctx.results.failures.push({
120
+ issueId: curIssueId,
121
+ reason: "REQUEST_ERROR",
122
+ details: err instanceof Error ? err.message : String(err),
123
+ });
124
+ }
125
+ }
126
+ },
127
+ },
128
+ ];
129
+ const { success, states } = await runSteps(steps, {
130
+ onStateChange: (stepStates) => {
131
+ renderer.update({ ...baseState, stepStates, elapsed: Date.now() - startTime });
132
+ },
133
+ });
134
+ renderer.finish({
135
+ url: "",
136
+ mode: "fix-all",
137
+ overallScore: success ? 100 : 0,
138
+ scores: {},
139
+ issueCount: 0,
140
+ passed: success,
141
+ elapsed: Date.now() - startTime,
142
+ });
143
+ if (!success) {
144
+ const failed = states.find(s => s.status === "failed");
145
+ process.stderr.write(renderError({
146
+ message: failed?.failReason || "Command failed",
147
+ suggestion: "vertaa doctor",
148
+ }) + "\n");
149
+ process.exitCode = ExitCode.ERROR;
150
+ }
151
+ const finalResults = ctx.results;
152
+ if (!opts.dryRun && finalResults !== null) {
153
+ // Exit code 1 if any failures
154
+ if (finalResults.failures.length > 0) {
155
+ process.exitCode = 1;
156
+ }
157
+ if (format === "json") {
158
+ writeJsonOutput(finalResults, "fix-all");
159
+ }
160
+ else {
161
+ writeOutput(formatBatchMarkdown(finalResults));
162
+ }
163
+ }
164
+ }
165
+ /**
166
+ * Shared fix-all runner used by the fix-all command (legacy wrapper for backward compat).
167
+ */
168
+ export async function runFixAllCommand(base, jobId, flags, globalFlags = {}) {
169
+ const fileContent = getString(flags, "file-content");
170
+ const autoFixOnly = getBool(flags, "auto-fix-only");
171
+ const format = resolveFormat(flags);
172
+ if (!fileContent) {
173
+ throw new Error(strings.fixAll.errors.missingArgs);
174
+ }
175
+ await handleFixAll({
176
+ base,
177
+ jobId,
178
+ fileContent,
179
+ autoFixOnly,
180
+ format,
181
+ dryRun: globalFlags.dryRun,
182
+ yes: globalFlags.yes,
183
+ });
184
+ }
185
+ export function registerFixAllCommand(program) {
186
+ program
187
+ .command("fix-all <jobId>")
188
+ .description("Generate fix patches for all issues in an audit")
189
+ .requiredOption("--file-content <code>", "Source code content")
190
+ .option("--auto-fix-only", "Only process auto-fixable issues")
191
+ .action(async (jobId, cmdOptions, command) => {
192
+ try {
193
+ const globalOpts = command.optsWithGlobals();
194
+ const base = resolveApiBase(cmdOptions);
195
+ await runFixAllCommand(base, jobId, cmdOptions, { dryRun: !!globalOpts.dryRun, yes: !!globalOpts.yes });
196
+ }
197
+ catch (error) {
198
+ process.stderr.write(renderError({
199
+ message: error instanceof Error ? error.message : String(error),
200
+ suggestion: "vertaa explain <id>",
201
+ exitCode: ExitCode.ERROR,
202
+ }) + "\n");
203
+ process.exit(ExitCode.ERROR);
204
+ }
205
+ });
206
+ }
@@ -11,5 +11,14 @@
11
11
  * vertaa fix-plan --file audit.json --json
12
12
  */
13
13
  import { Command } from "commander";
14
+ export interface FixPlanCommandOptions {
15
+ job?: string;
16
+ file?: string;
17
+ format?: string;
18
+ base?: string;
19
+ machine?: boolean;
20
+ apiKey?: string;
21
+ }
22
+ export declare function handleFixPlan(opts: FixPlanCommandOptions): Promise<void>;
14
23
  export declare function registerFixPlanCommand(program: Command): void;
15
24
  //# sourceMappingURL=fix-plan.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fix-plan.d.ts","sourceRoot":"","sources":["../../src/commands/fix-plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuIpC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA6G7D"}
1
+ {"version":3,"file":"fix-plan.d.ts","sourceRoot":"","sources":["../../src/commands/fix-plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA8IpC,MAAM,WAAW,qBAAqB;IACpC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiI9E;AAMD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA0C7D"}
@@ -10,15 +10,15 @@
10
10
  * vertaa fix-plan --job abc123
11
11
  * vertaa fix-plan --file audit.json --json
12
12
  */
13
- import chalk from "chalk";
13
+ import { bold, dim, colorize, boldColor, brand, severity as severityPalette, renderError, createRenderer, runSteps } from "@vertaaux/tui";
14
14
  import { ExitCode } from "../utils/exit-codes.js";
15
- import { resolveApiBase, getApiKey, apiRequest } from "../utils/client.js";
15
+ import { resolveApiBase, getApiKey, apiRequest, createClient } from "../utils/client.js";
16
16
  import { resolveConfig } from "../config/loader.js";
17
17
  import { writeJsonOutput, writeOutput } from "../output/envelope.js";
18
18
  import { resolveCommandFormat } from "../output/formats.js";
19
- import { createSpinner, succeedSpinner } from "../ui/spinner.js";
20
19
  import { readJsonInput } from "../utils/stdin.js";
21
- import { handleAiCommandError, AI_TIMEOUT_MS } from "../utils/ai-error.js";
20
+ import { AI_TIMEOUT_MS } from "../utils/ai-error.js";
21
+ import { strings } from "../ui/strings.js";
22
22
  // ---------------------------------------------------------------------------
23
23
  // Helpers
24
24
  // ---------------------------------------------------------------------------
@@ -50,46 +50,158 @@ function normalizeIssues(issues) {
50
50
  // ---------------------------------------------------------------------------
51
51
  // Formatters
52
52
  // ---------------------------------------------------------------------------
53
- const SEVERITY_COLORS = {
54
- critical: chalk.red.bold,
55
- high: chalk.red,
56
- medium: chalk.yellow,
57
- low: chalk.cyan,
58
- };
53
+ function severityColor(sev, text) {
54
+ switch (sev) {
55
+ case "critical":
56
+ return boldColor(text, severityPalette.critical);
57
+ case "high":
58
+ return colorize(text, severityPalette.error);
59
+ case "medium":
60
+ return colorize(text, severityPalette.warning);
61
+ case "low":
62
+ return colorize(text, brand.cyan);
63
+ default:
64
+ return dim(text);
65
+ }
66
+ }
59
67
  const EFFORT_LABELS = {
60
- trivial: chalk.green("trivial"),
61
- small: chalk.green("small"),
62
- medium: chalk.yellow("medium"),
63
- large: chalk.red("large"),
68
+ trivial: colorize("trivial", brand.lime),
69
+ small: colorize("small", brand.lime),
70
+ medium: colorize("medium", severityPalette.warning),
71
+ large: colorize("large", severityPalette.error),
64
72
  };
65
73
  const FIX_TYPE_LABELS = {
66
- code: chalk.blue("code"),
67
- config: chalk.magenta("config"),
68
- content: chalk.cyan("content"),
69
- design: chalk.yellow("design"),
74
+ code: colorize("code", brand.teal),
75
+ config: colorize("config", brand.tealLight),
76
+ content: colorize("content", brand.cyan),
77
+ design: colorize("design", severityPalette.warning),
70
78
  };
71
79
  function formatFixPlanHuman(data) {
72
80
  const lines = [];
73
- lines.push(chalk.bold(`Remediation Plan (${data.items.length} items)`));
74
- lines.push(chalk.dim(`Estimated total effort: ${data.estimated_total_effort}`));
81
+ lines.push(bold(`Remediation Plan (${data.items.length} items)`));
82
+ lines.push(dim(`Estimated total effort: ${data.estimated_total_effort}`));
75
83
  lines.push("");
76
84
  for (let idx = 0; idx < data.items.length; idx++) {
77
85
  const item = data.items[idx];
78
- const severityFn = SEVERITY_COLORS[item.severity] || chalk.dim;
79
- const effort = EFFORT_LABELS[item.effort] || chalk.dim(item.effort);
80
- const fixType = FIX_TYPE_LABELS[item.fix_type] || chalk.dim(item.fix_type);
81
- lines.push(`${chalk.bold(`${idx + 1}.`)} ${severityFn(`[${item.severity}]`)} ${chalk.bold(item.title)}`);
82
- lines.push(` Effort: ${effort} Type: ${fixType}${item.id ? chalk.dim(` (${item.id})`) : ""}`);
86
+ const effort = EFFORT_LABELS[item.effort] || dim(item.effort);
87
+ const fixType = FIX_TYPE_LABELS[item.fix_type] || dim(item.fix_type);
88
+ lines.push(`${bold(`${idx + 1}.`)} ${severityColor(item.severity, `[${item.severity}]`)} ${bold(item.title)}`);
89
+ lines.push(` Effort: ${effort} Type: ${fixType}${item.id ? dim(` (${item.id})`) : ""}`);
83
90
  for (let s = 0; s < item.steps.length; s++) {
84
- lines.push(` ${chalk.dim(`${s + 1})`)} ${item.steps[s]}`);
91
+ lines.push(` ${dim(`${s + 1})`)} ${item.steps[s]}`);
85
92
  }
86
93
  if (item.code_hint) {
87
- lines.push(` ${chalk.dim("Hint:")} ${chalk.italic(item.code_hint)}`);
94
+ lines.push(` ${dim("Hint:")} ${item.code_hint}`);
88
95
  }
89
96
  lines.push("");
90
97
  }
91
98
  return lines.join("\n");
92
99
  }
100
+ export async function handleFixPlan(opts) {
101
+ const config = { apiKey: opts.apiKey };
102
+ const format = resolveCommandFormat("fix-plan", opts.format, opts.machine || false);
103
+ const renderer = createRenderer("auto");
104
+ const baseState = {
105
+ phase: "fix-plan",
106
+ phaseIndex: 1,
107
+ phaseTotal: 2,
108
+ url: "",
109
+ mode: "fix-plan",
110
+ progress: {},
111
+ totals: {},
112
+ issueCount: 0,
113
+ scorePreview: null,
114
+ verbose: false,
115
+ elapsed: 0,
116
+ };
117
+ const startTime = Date.now();
118
+ let responseData = null;
119
+ const steps = [
120
+ {
121
+ id: "analyze",
122
+ actionText: strings.fixPlan.generate.action,
123
+ summaryText: "Issues analyzed",
124
+ run: async () => {
125
+ let auditPayload;
126
+ if (opts.job) {
127
+ const sdkClient = createClient({ base: opts.base, apiKey: config.apiKey });
128
+ const result = await sdkClient.audits.retrieve(opts.job);
129
+ const issues = normalizeIssues(result.issues);
130
+ auditPayload = {
131
+ job_id: result.job_id || opts.job,
132
+ url: result.url || null,
133
+ scores: result.scores || null,
134
+ issues,
135
+ };
136
+ }
137
+ else {
138
+ const input = await readJsonInput(opts.file);
139
+ if (!input) {
140
+ throw new Error("No audit data provided.\nUsage:\n vertaa audit https://example.com --json | vertaa fix-plan\n vertaa fix-plan --job <job-id>\n vertaa fix-plan --file audit.json");
141
+ }
142
+ const data = input;
143
+ const innerData = (data.data && typeof data.data === "object" ? data.data : data);
144
+ const issues = normalizeIssues(innerData.issues);
145
+ auditPayload = {
146
+ job_id: innerData.job_id || null,
147
+ url: innerData.url || null,
148
+ scores: innerData.scores || null,
149
+ issues,
150
+ };
151
+ }
152
+ if (!Array.isArray(auditPayload.issues) ||
153
+ auditPayload.issues.length === 0) {
154
+ throw new Error("No issues found in audit data.");
155
+ }
156
+ const base = resolveApiBase(opts.base);
157
+ const apiKey = getApiKey(config.apiKey);
158
+ const response = await Promise.race([
159
+ apiRequest(base, "/cli/ai/fix-plan", { method: "POST", body: { audit: auditPayload } }, apiKey),
160
+ new Promise((_, reject) => setTimeout(() => reject(new Error("LLM request timed out")), AI_TIMEOUT_MS)),
161
+ ]);
162
+ responseData = response.data;
163
+ },
164
+ },
165
+ {
166
+ id: "plan",
167
+ actionText: "Generating fix plan...",
168
+ summaryText: responseData ? strings.fixPlan.generate.done(responseData.items.length) : "Fix plan generated",
169
+ run: async () => {
170
+ // Fix plan generated in analyze step via API call
171
+ },
172
+ },
173
+ ];
174
+ const { success, states } = await runSteps(steps, {
175
+ onStateChange: (stepStates) => {
176
+ renderer.update({ ...baseState, stepStates, elapsed: Date.now() - startTime });
177
+ },
178
+ });
179
+ renderer.finish({
180
+ url: "",
181
+ mode: "fix-plan",
182
+ overallScore: success ? 100 : 0,
183
+ scores: {},
184
+ issueCount: 0,
185
+ passed: success,
186
+ elapsed: Date.now() - startTime,
187
+ });
188
+ if (!success) {
189
+ const failed = states.find(s => s.status === "failed");
190
+ process.stderr.write(renderError({
191
+ message: failed?.failReason || "Command failed",
192
+ suggestion: "vertaa doctor",
193
+ }) + "\n");
194
+ process.exitCode = ExitCode.ERROR;
195
+ }
196
+ if (success && responseData) {
197
+ if (format === "json") {
198
+ writeJsonOutput(responseData, "fix-plan");
199
+ }
200
+ else {
201
+ writeOutput(formatFixPlanHuman(responseData));
202
+ }
203
+ }
204
+ }
93
205
  // ---------------------------------------------------------------------------
94
206
  // Command Registration
95
207
  // ---------------------------------------------------------------------------
@@ -112,70 +224,21 @@ Examples:
112
224
  const globalOpts = command.optsWithGlobals();
113
225
  const config = await resolveConfig(globalOpts.config);
114
226
  const machineMode = globalOpts.machine || false;
115
- const format = resolveCommandFormat("fix-plan", options.format, machineMode);
116
- // Resolve audit data
117
- let auditPayload;
118
- if (options.job) {
119
- const base = resolveApiBase(globalOpts.base);
120
- const apiKey = getApiKey(config.apiKey);
121
- const result = await apiRequest(base, `/audit/${options.job}`, { method: "GET" }, apiKey);
122
- const issues = normalizeIssues(result.issues);
123
- auditPayload = {
124
- job_id: result.job_id || options.job,
125
- url: result.url || null,
126
- scores: result.scores || null,
127
- issues,
128
- };
129
- }
130
- else {
131
- const input = await readJsonInput(options.file);
132
- if (!input) {
133
- console.error("Error: No audit data provided.");
134
- console.error("Usage:");
135
- console.error(" vertaa audit https://example.com --json | vertaa fix-plan");
136
- console.error(" vertaa fix-plan --job <job-id>");
137
- console.error(" vertaa fix-plan --file audit.json");
138
- process.exit(ExitCode.ERROR);
139
- }
140
- const data = input;
141
- const innerData = (data.data && typeof data.data === "object" ? data.data : data);
142
- const issues = normalizeIssues(innerData.issues);
143
- auditPayload = {
144
- job_id: innerData.job_id || null,
145
- url: innerData.url || null,
146
- scores: innerData.scores || null,
147
- issues,
148
- };
149
- }
150
- if (!Array.isArray(auditPayload.issues) ||
151
- auditPayload.issues.length === 0) {
152
- console.error("Error: No issues found in audit data.");
153
- process.exit(ExitCode.ERROR);
154
- }
155
- // Auth check
156
- const base = resolveApiBase(globalOpts.base);
157
- const apiKey = getApiKey(config.apiKey);
158
- // Call LLM fix-plan API
159
- const spinner = createSpinner("Generating remediation plan...");
160
- try {
161
- const response = await Promise.race([
162
- apiRequest(base, "/cli/ai/fix-plan", { method: "POST", body: { audit: auditPayload } }, apiKey),
163
- new Promise((_, reject) => setTimeout(() => reject(new Error("LLM request timed out")), AI_TIMEOUT_MS)),
164
- ]);
165
- succeedSpinner(spinner, "Plan ready");
166
- if (format === "json") {
167
- writeJsonOutput(response.data, "fix-plan");
168
- }
169
- else {
170
- writeOutput(formatFixPlanHuman(response.data));
171
- }
172
- }
173
- catch (error) {
174
- handleAiCommandError(error, "fix-plan", spinner);
175
- }
227
+ await handleFixPlan({
228
+ job: options.job,
229
+ file: options.file,
230
+ format: options.format,
231
+ base: globalOpts.base,
232
+ machine: machineMode,
233
+ apiKey: config.apiKey,
234
+ });
176
235
  }
177
236
  catch (error) {
178
- console.error("Error:", error instanceof Error ? error.message : String(error));
237
+ process.stderr.write(renderError({
238
+ message: error instanceof Error ? error.message : String(error),
239
+ suggestion: "vertaa explain <id>",
240
+ exitCode: ExitCode.ERROR,
241
+ }) + "\n");
179
242
  process.exit(ExitCode.ERROR);
180
243
  }
181
244
  });
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Legacy fix command handler.
3
+ * Generates a fix patch for an issue.
4
+ */
5
+ import type { Command } from "commander";
6
+ import type { Flags } from "../types.js";
7
+ /**
8
+ * Shared fix runner used by the fix command.
9
+ */
10
+ export declare function runFixCommand(base: string, jobId: string, issueId: string, flags: Flags, globalFlags?: {
11
+ dryRun?: boolean;
12
+ }): Promise<void>;
13
+ export declare function handleFix(jobId: string, cmdOptions: Flags, globalFlags?: {
14
+ dryRun?: boolean;
15
+ }): Promise<void>;
16
+ export declare function registerFixCommand(program: Command): void;
17
+ //# sourceMappingURL=fix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fix.d.ts","sourceRoot":"","sources":["../../src/commands/fix.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAczC,OAAO,KAAK,EAAE,KAAK,EAAiB,MAAM,aAAa,CAAC;AAGxD;;GAEG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,KAAK,EACZ,WAAW,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,iBAiCvC;AAED,wBAAsB,SAAS,CAC7B,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,KAAK,EACjB,WAAW,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACrC,OAAO,CAAC,IAAI,CAAC,CAiDf;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAqBzD"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Legacy fix command handler.
3
+ * Generates a fix patch for an issue.
4
+ */
5
+ import { renderError, runSteps, createRenderer } from "@vertaaux/tui";
6
+ import { ExitCode } from "../utils/exit-codes.js";
7
+ import { resolveApiBase, resolveFormat, getString, createClient, } from "../utils/api-client.js";
8
+ import { formatPatchMarkdown, } from "../utils/formatters.js";
9
+ import { writeOutput } from "../output/envelope.js";
10
+ import { strings } from "../ui/strings.js";
11
+ /**
12
+ * Shared fix runner used by the fix command.
13
+ */
14
+ export async function runFixCommand(base, jobId, issueId, flags, globalFlags = {}) {
15
+ const fileContent = getString(flags, "file-content");
16
+ const format = resolveFormat(flags);
17
+ if (!fileContent) {
18
+ throw new Error(strings.fix.errors.missingArgs);
19
+ }
20
+ const client = createClient({ base });
21
+ const result = await client.patches.generate({
22
+ job_id: jobId,
23
+ issue_id: issueId,
24
+ file_content: fileContent,
25
+ });
26
+ if (!result.success) {
27
+ process.exitCode = 1;
28
+ }
29
+ if (format === "json") {
30
+ const output = globalFlags.dryRun ? { ...result, dry_run: true } : result;
31
+ process.stdout.write(JSON.stringify(output, null, 2) + "\n");
32
+ }
33
+ else {
34
+ if (globalFlags.dryRun) {
35
+ writeOutput(strings.fix.dryRun);
36
+ }
37
+ if (result.success && result.patch) {
38
+ writeOutput(formatPatchMarkdown(result.patch));
39
+ }
40
+ else {
41
+ writeOutput(`## Patch Generation Failed\n\n${result.error?.message || "Unknown error"}`);
42
+ }
43
+ }
44
+ }
45
+ export async function handleFix(jobId, cmdOptions, globalFlags = {}) {
46
+ const renderer = createRenderer("auto");
47
+ const baseState = {
48
+ phase: "fix",
49
+ phaseIndex: 1,
50
+ phaseTotal: 1,
51
+ url: "",
52
+ mode: "fix",
53
+ progress: {},
54
+ totals: {},
55
+ issueCount: 0,
56
+ scorePreview: null,
57
+ verbose: false,
58
+ elapsed: 0,
59
+ };
60
+ const startTime = Date.now();
61
+ const steps = [
62
+ {
63
+ id: "generate",
64
+ actionText: "Generating patch...",
65
+ summaryText: "Patch generated",
66
+ run: async () => {
67
+ const base = resolveApiBase(cmdOptions);
68
+ const issueId = getString(cmdOptions, "issue");
69
+ if (!issueId)
70
+ throw new Error("--issue is required");
71
+ await runFixCommand(base, jobId, issueId, cmdOptions, globalFlags);
72
+ },
73
+ },
74
+ ];
75
+ const { success, states } = await runSteps(steps, {
76
+ failFast: true,
77
+ onStateChange: (stepStates) => {
78
+ renderer.update({ ...baseState, stepStates, elapsed: Date.now() - startTime });
79
+ },
80
+ });
81
+ renderer.finish({ url: "", mode: "fix", overallScore: 0, scores: {}, issueCount: 0, passed: success, elapsed: Date.now() - startTime });
82
+ if (!success) {
83
+ const failed = states.find(s => s.status === "failed");
84
+ process.stderr.write(renderError({
85
+ message: failed?.failReason || "Command failed",
86
+ suggestion: "vertaa doctor",
87
+ }) + "\n");
88
+ process.exitCode = ExitCode.ERROR;
89
+ }
90
+ }
91
+ export function registerFixCommand(program) {
92
+ program
93
+ .command("fix <jobId>")
94
+ .description("Generate a fix patch for an issue")
95
+ .requiredOption("--issue <id>", "Issue ID to fix")
96
+ .requiredOption("--file-content <code>", "Source code content")
97
+ .action(async (jobId, cmdOptions, command) => {
98
+ try {
99
+ const globalOpts = command.optsWithGlobals();
100
+ await handleFix(jobId, cmdOptions, { dryRun: !!globalOpts.dryRun });
101
+ }
102
+ catch (error) {
103
+ process.stderr.write(renderError({
104
+ message: error instanceof Error ? error.message : String(error),
105
+ suggestion: "vertaa explain <id>",
106
+ exitCode: ExitCode.ERROR,
107
+ }) + "\n");
108
+ process.exit(ExitCode.ERROR);
109
+ }
110
+ });
111
+ }
@@ -5,6 +5,17 @@
5
5
  * Generates CI templates for popular platforms.
6
6
  */
7
7
  import type { Command } from "commander";
8
+ import type { CITemplate, FailOnSeverity } from "../config/schema.js";
9
+ /**
10
+ * Handle the init command.
11
+ */
12
+ export declare function handleInit(options: {
13
+ yes?: boolean;
14
+ ci?: CITemplate;
15
+ failOn?: FailOnSeverity;
16
+ threshold?: number;
17
+ force?: boolean;
18
+ }): Promise<void>;
8
19
  /**
9
20
  * Register the init command with the Commander program.
10
21
  */
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA6NzC;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAgC1D"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOzC,OAAO,KAAK,EAAkB,UAAU,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AA0HtF;;GAEG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE;IACxC,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,EAAE,CAAC,EAAE,UAAU,CAAC;IAChB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuIhB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmC1D"}