@vertaaux/cli 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (248) hide show
  1. package/CHANGELOG.md +116 -0
  2. package/MIGRATION.md +239 -0
  3. package/README.md +62 -17
  4. package/dist/app/interactive-app.d.ts +103 -0
  5. package/dist/app/interactive-app.d.ts.map +1 -0
  6. package/dist/app/interactive-app.js +328 -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 +166 -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 +415 -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 +46 -0
  37. package/dist/auth/ci-token.d.ts +8 -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 +11 -0
  49. package/dist/commands/a11y.d.ts.map +1 -0
  50. package/dist/commands/a11y.js +149 -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 +589 -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 +129 -0
  69. package/dist/commands/audit/policy.d.ts +27 -0
  70. package/dist/commands/audit/policy.d.ts.map +1 -0
  71. package/dist/commands/audit/policy.js +147 -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 +89 -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 -1097
  81. package/dist/commands/baseline.d.ts +2 -0
  82. package/dist/commands/baseline.d.ts.map +1 -1
  83. package/dist/commands/baseline.js +221 -123
  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 +127 -62
  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 +288 -181
  90. package/dist/commands/diff.d.ts +7 -0
  91. package/dist/commands/diff.d.ts.map +1 -1
  92. package/dist/commands/diff.js +181 -143
  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 +135 -77
  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 +166 -19
  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 +242 -156
  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 +154 -90
  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 +263 -92
  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 +160 -98
  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 +270 -125
  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 +128 -74
  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 +180 -83
  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 +207 -82
  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/config/schema.d.ts +4 -0
  148. package/dist/config/schema.d.ts.map +1 -1
  149. package/dist/index.d.ts +3 -2
  150. package/dist/index.d.ts.map +1 -1
  151. package/dist/index.js +127 -991
  152. package/dist/interactive/fix-wizard.d.ts +3 -0
  153. package/dist/interactive/fix-wizard.d.ts.map +1 -1
  154. package/dist/interactive/fix-wizard.js +130 -112
  155. package/dist/interactive/init-wizard.d.ts +3 -1
  156. package/dist/interactive/init-wizard.d.ts.map +1 -1
  157. package/dist/interactive/init-wizard.js +207 -138
  158. package/dist/interactive/prompts.d.ts +7 -3
  159. package/dist/interactive/prompts.d.ts.map +1 -1
  160. package/dist/interactive/prompts.js +44 -23
  161. package/dist/output/envelope.d.ts +9 -0
  162. package/dist/output/envelope.d.ts.map +1 -1
  163. package/dist/output/envelope.js +37 -3
  164. package/dist/output/factory.d.ts +2 -1
  165. package/dist/output/factory.d.ts.map +1 -1
  166. package/dist/output/html.d.ts +2 -1
  167. package/dist/output/html.d.ts.map +1 -1
  168. package/dist/output/html.js +3 -2
  169. package/dist/output/human.d.ts +2 -1
  170. package/dist/output/human.d.ts.map +1 -1
  171. package/dist/output/human.js +3 -2
  172. package/dist/output/json.d.ts +2 -1
  173. package/dist/output/json.d.ts.map +1 -1
  174. package/dist/output/junit.d.ts +2 -1
  175. package/dist/output/junit.d.ts.map +1 -1
  176. package/dist/output/sarif.d.ts +2 -1
  177. package/dist/output/sarif.d.ts.map +1 -1
  178. package/dist/policy/schema.d.ts +137 -0
  179. package/dist/policy/schema.d.ts.map +1 -1
  180. package/dist/policy/schema.js +107 -0
  181. package/dist/prompts/command-catalog.js +9 -9
  182. package/dist/types.d.ts +74 -0
  183. package/dist/types.d.ts.map +1 -0
  184. package/dist/types.js +5 -0
  185. package/dist/ui/banner.d.ts +34 -0
  186. package/dist/ui/banner.d.ts.map +1 -1
  187. package/dist/ui/banner.js +97 -5
  188. package/dist/ui/diagnostics.d.ts +9 -4
  189. package/dist/ui/diagnostics.d.ts.map +1 -1
  190. package/dist/ui/diagnostics.js +32 -82
  191. package/dist/ui/strings.d.ts +373 -0
  192. package/dist/ui/strings.d.ts.map +1 -0
  193. package/dist/ui/strings.js +499 -0
  194. package/dist/ui/table.d.ts +0 -2
  195. package/dist/ui/table.d.ts.map +1 -1
  196. package/dist/ui/table.js +3 -4
  197. package/dist/utils/api-client.d.ts +46 -0
  198. package/dist/utils/api-client.d.ts.map +1 -0
  199. package/dist/utils/api-client.js +170 -0
  200. package/dist/utils/client.d.ts +29 -18
  201. package/dist/utils/client.d.ts.map +1 -1
  202. package/dist/utils/client.js +104 -12
  203. package/dist/utils/formatters.d.ts +38 -0
  204. package/dist/utils/formatters.d.ts.map +1 -0
  205. package/dist/utils/formatters.js +277 -0
  206. package/dist/utils/root-args.d.ts +12 -0
  207. package/dist/utils/root-args.d.ts.map +1 -0
  208. package/dist/utils/root-args.js +44 -0
  209. package/dist/utils/stdin.d.ts +7 -0
  210. package/dist/utils/stdin.d.ts.map +1 -1
  211. package/dist/utils/stdin.js +32 -2
  212. package/dist/utils/url-classify.d.ts.map +1 -1
  213. package/dist/utils/url-classify.js +24 -3
  214. package/node_modules/@vertaaux/tui/dist/index.cjs +1216 -27
  215. package/node_modules/@vertaaux/tui/dist/index.cjs.map +1 -1
  216. package/node_modules/@vertaaux/tui/dist/index.d.cts +361 -4
  217. package/node_modules/@vertaaux/tui/dist/index.d.ts +361 -4
  218. package/node_modules/@vertaaux/tui/dist/index.js +1189 -27
  219. package/node_modules/@vertaaux/tui/dist/index.js.map +1 -1
  220. package/node_modules/@vertaaux/tui/package.json +2 -3
  221. package/node_modules/chalk/license +9 -0
  222. package/node_modules/chalk/package.json +83 -0
  223. package/node_modules/chalk/readme.md +297 -0
  224. package/node_modules/chalk/source/index.d.ts +325 -0
  225. package/node_modules/chalk/source/index.js +225 -0
  226. package/node_modules/chalk/source/utilities.js +33 -0
  227. package/node_modules/chalk/source/vendor/ansi-styles/index.d.ts +236 -0
  228. package/node_modules/chalk/source/vendor/ansi-styles/index.js +223 -0
  229. package/node_modules/chalk/source/vendor/supports-color/browser.d.ts +1 -0
  230. package/node_modules/chalk/source/vendor/supports-color/browser.js +34 -0
  231. package/node_modules/chalk/source/vendor/supports-color/index.d.ts +55 -0
  232. package/node_modules/chalk/source/vendor/supports-color/index.js +190 -0
  233. package/package.json +20 -5
  234. package/dist/commands/client.d.ts +0 -14
  235. package/dist/commands/client.d.ts.map +0 -1
  236. package/dist/commands/client.js +0 -362
  237. package/dist/commands/drift.d.ts +0 -15
  238. package/dist/commands/drift.d.ts.map +0 -1
  239. package/dist/commands/drift.js +0 -309
  240. package/dist/commands/protect.d.ts +0 -16
  241. package/dist/commands/protect.d.ts.map +0 -1
  242. package/dist/commands/protect.js +0 -323
  243. package/dist/commands/report.d.ts +0 -15
  244. package/dist/commands/report.d.ts.map +0 -1
  245. package/dist/commands/report.js +0 -214
  246. package/dist/policy/sync.d.ts +0 -67
  247. package/dist/policy/sync.d.ts.map +0 -1
  248. package/dist/policy/sync.js +0 -147
@@ -10,28 +10,53 @@
10
10
  * vertaa suggest "compare two pages"
11
11
  * vertaa suggest "set up CI quality gate"
12
12
  */
13
- import chalk from "chalk";
13
+ import { bold, dim, colorize, boldColor, brand, severity as severityPalette, runSteps, createRenderer, renderWarning, renderError, isCI, isTTY } from "@vertaaux/tui";
14
14
  import { ExitCode } from "../utils/exit-codes.js";
15
15
  import { resolveApiBase, getApiKey, hasApiKey, apiRequest } from "../utils/client.js";
16
16
  import { resolveConfig } from "../config/loader.js";
17
- import { writeJsonOutput, writeOutput } from "../output/envelope.js";
17
+ import { writeDataOutput, writeJsonOutput, writeOutput } from "../output/envelope.js";
18
18
  import { resolveCommandFormat } from "../output/formats.js";
19
- import { createSpinner, succeedSpinner, failSpinner } from "../ui/spinner.js";
20
19
  import { findMatches } from "../prompts/command-catalog.js";
21
20
  import { AI_TIMEOUT_MS } from "../utils/ai-error.js";
21
+ import { strings } from "../ui/strings.js";
22
+ function tokenizeCommand(command) {
23
+ return command.match(/"[^"]*"|'[^']*'|\S+/g) ?? [];
24
+ }
25
+ function stripQuotes(token) {
26
+ if ((token.startsWith("\"") && token.endsWith("\"")) ||
27
+ (token.startsWith("'") && token.endsWith("'"))) {
28
+ return token.slice(1, -1);
29
+ }
30
+ return token;
31
+ }
32
+ function toSuggestionStages(command) {
33
+ return command
34
+ .split("|")
35
+ .map((segment) => segment.trim())
36
+ .filter(Boolean)
37
+ .map((segment) => {
38
+ const tokens = tokenizeCommand(segment).map(stripQuotes);
39
+ const [executable = "vertaa", ...argv] = tokens;
40
+ return {
41
+ executable,
42
+ argv,
43
+ placeholders: argv.filter((token) => /^<.+>$/.test(token)),
44
+ };
45
+ });
46
+ }
22
47
  /**
23
48
  * Format suggestion for human-readable output.
24
49
  */
25
50
  function formatSuggestHuman(results) {
26
51
  const lines = [];
27
52
  for (const result of results) {
28
- lines.push(` ${chalk.cyan.bold("$")} ${chalk.bold(result.command)}`);
29
- lines.push(` ${chalk.dim(result.explanation)}`);
53
+ lines.push(` ${boldColor("$", brand.cyan)} ${bold(result.command)}`);
54
+ lines.push(` ${dim(result.explanation)}`);
30
55
  lines.push("");
31
56
  }
32
57
  if (results.length === 0) {
33
- lines.push(chalk.yellow("No matching commands found."));
34
- lines.push(chalk.dim("Try: vertaa --help"));
58
+ lines.push(colorize("No matching commands found.", severityPalette.warning));
59
+ lines.push(dim("Try: vertaa --help"));
35
60
  }
36
61
  return lines.join("\n");
37
62
  }
@@ -42,12 +67,144 @@ function formatSuggestJson(results) {
42
67
  return {
43
68
  suggestions: results.map((r) => ({
44
69
  command: r.command,
70
+ stages: toSuggestionStages(r.command),
45
71
  explanation: r.explanation,
46
72
  source: r.source,
47
73
  confidence: r.confidence,
48
74
  })),
49
75
  };
50
76
  }
77
+ export async function handleSuggest(opts) {
78
+ const format = resolveCommandFormat("suggest", opts.format, opts.machine || false);
79
+ const config = { apiKey: opts.apiKey };
80
+ const intent = opts.intent;
81
+ // Resolve fail-fast mode: --strict > --continue-on-error > auto-detect
82
+ let failFast;
83
+ if (opts.strict && opts.continueOnError) {
84
+ writeOutput(renderWarning({ message: "--strict and --continue-on-error both set — --strict takes precedence" }));
85
+ failFast = true;
86
+ }
87
+ else if (opts.strict) {
88
+ failFast = true;
89
+ }
90
+ else if (opts.continueOnError) {
91
+ failFast = false;
92
+ }
93
+ else {
94
+ failFast = isCI() || !isTTY();
95
+ }
96
+ let results = [];
97
+ const renderer = createRenderer("auto");
98
+ const baseState = {
99
+ phase: "suggest",
100
+ phaseIndex: 1,
101
+ phaseTotal: 1,
102
+ url: "",
103
+ mode: "suggest",
104
+ progress: {},
105
+ totals: {},
106
+ issueCount: 0,
107
+ scorePreview: null,
108
+ verbose: false,
109
+ elapsed: 0,
110
+ };
111
+ const steps = [
112
+ {
113
+ id: "search",
114
+ actionText: strings.suggest.search.action,
115
+ summaryText: strings.suggest.search.done(0),
116
+ run: async () => {
117
+ // Step 1: Local fuzzy match against command catalog
118
+ const localMatches = findMatches(intent);
119
+ if (localMatches.length > 0 && localMatches[0].score >= 0.2) {
120
+ // Good local matches — use them
121
+ results = localMatches.map((m) => ({
122
+ command: m.entry.command,
123
+ explanation: m.entry.description,
124
+ source: "local",
125
+ confidence: Math.round(m.score * 100),
126
+ }));
127
+ }
128
+ else if (hasApiKey(config)) {
129
+ // No strong local match — try API
130
+ const base = resolveApiBase(opts.base);
131
+ const apiKey = getApiKey(config.apiKey);
132
+ try {
133
+ const response = await Promise.race([
134
+ apiRequest(base, "/cli/ai/suggest", { method: "POST", body: { intent } }, apiKey),
135
+ new Promise((_, reject) => setTimeout(() => reject(new Error("LLM request timed out")), AI_TIMEOUT_MS)),
136
+ ]);
137
+ if (response.data?.suggestions?.length) {
138
+ results = response.data.suggestions.map((s) => ({
139
+ command: s.command,
140
+ explanation: s.explanation,
141
+ source: "api",
142
+ confidence: 80,
143
+ }));
144
+ }
145
+ else {
146
+ results = localMatches.map((m) => ({
147
+ command: m.entry.command,
148
+ explanation: m.entry.description,
149
+ source: "local",
150
+ confidence: Math.round(m.score * 100),
151
+ }));
152
+ }
153
+ }
154
+ catch {
155
+ // API failed — suggest degrades gracefully to local catalog
156
+ writeOutput(strings.suggest.errors.apiUnavailable + "\n");
157
+ results = localMatches.map((m) => ({
158
+ command: m.entry.command,
159
+ explanation: m.entry.description,
160
+ source: "local",
161
+ confidence: Math.round(m.score * 100),
162
+ }));
163
+ }
164
+ }
165
+ else {
166
+ // No API key — use partial local matches
167
+ results = localMatches.map((m) => ({
168
+ command: m.entry.command,
169
+ explanation: m.entry.description,
170
+ source: "local",
171
+ confidence: Math.round(m.score * 100),
172
+ }));
173
+ }
174
+ },
175
+ },
176
+ ];
177
+ const { success, states } = await runSteps(steps, {
178
+ failFast,
179
+ onStateChange: (stepStates) => {
180
+ renderer.update({ ...baseState, stepStates });
181
+ },
182
+ });
183
+ renderer.finish({
184
+ url: "",
185
+ mode: "suggest",
186
+ overallScore: success ? 100 : 0,
187
+ scores: {},
188
+ issueCount: 0,
189
+ passed: success,
190
+ elapsed: 0,
191
+ });
192
+ if (!success) {
193
+ const failedStep = states.find((s) => s.status === "failed");
194
+ process.stderr.write(renderError({
195
+ message: strings.suggest.errors.searchFailed(failedStep?.failReason ?? "unknown error"),
196
+ suggestion: "vertaa --help",
197
+ }) + "\n");
198
+ process.exit(ExitCode.ERROR);
199
+ }
200
+ // Output
201
+ if (format === "json") {
202
+ writeJsonOutput(formatSuggestJson(results), "suggest");
203
+ }
204
+ else {
205
+ writeDataOutput(formatSuggestHuman(results));
206
+ }
207
+ }
51
208
  /**
52
209
  * Register the suggest command with the Commander program.
53
210
  */
@@ -56,6 +213,8 @@ export function registerSuggestCommand(program) {
56
213
  .command("suggest <intent...>")
57
214
  .description("Convert natural language to exact CLI command(s)")
58
215
  .option("-f, --format <format>", "Output format: json | human")
216
+ .option("--strict", "Fail immediately on first step error")
217
+ .option("--continue-on-error", "Continue on step errors even in CI")
59
218
  .addHelpText("after", `
60
219
  Examples:
61
220
  vertaa suggest "check accessibility"
@@ -68,84 +227,22 @@ Examples:
68
227
  const globalOpts = command.optsWithGlobals();
69
228
  const config = await resolveConfig(globalOpts.config);
70
229
  const machineMode = globalOpts.machine || false;
71
- const format = resolveCommandFormat("suggest", options.format, machineMode);
72
- const intent = intentParts.join(" ");
73
- // Step 1: Local fuzzy match against command catalog
74
- const localMatches = findMatches(intent);
75
- let results;
76
- if (localMatches.length > 0 && localMatches[0].score >= 0.2) {
77
- // Good local matches — use them
78
- results = localMatches.map((m) => ({
79
- command: m.entry.command,
80
- explanation: m.entry.description,
81
- source: "local",
82
- confidence: Math.round(m.score * 100),
83
- }));
84
- }
85
- else if (hasApiKey(config)) {
86
- // No strong local match — try API
87
- const spinner = createSpinner("Thinking...");
88
- try {
89
- const base = resolveApiBase(globalOpts.base);
90
- const apiKey = getApiKey(config.apiKey);
91
- const response = await Promise.race([
92
- apiRequest(base, "/cli/ai/suggest", {
93
- method: "POST",
94
- body: { intent },
95
- }, apiKey),
96
- new Promise((_, reject) => setTimeout(() => reject(new Error("LLM request timed out")), AI_TIMEOUT_MS)),
97
- ]);
98
- succeedSpinner(spinner, "Done");
99
- if (response.data?.suggestions?.length) {
100
- results = response.data.suggestions.map((s) => ({
101
- command: s.command,
102
- explanation: s.explanation,
103
- source: "api",
104
- confidence: 80,
105
- }));
106
- }
107
- else {
108
- // API returned nothing — fall back to partial local matches
109
- results = localMatches.map((m) => ({
110
- command: m.entry.command,
111
- explanation: m.entry.description,
112
- source: "local",
113
- confidence: Math.round(m.score * 100),
114
- }));
115
- }
116
- }
117
- catch (error) {
118
- // Suggest degrades gracefully — fall back to local catalog
119
- // instead of hard exit via handleAiCommandError
120
- failSpinner(spinner, "API unavailable — using local catalog");
121
- // API failed — use whatever local matches we have
122
- results = localMatches.map((m) => ({
123
- command: m.entry.command,
124
- explanation: m.entry.description,
125
- source: "local",
126
- confidence: Math.round(m.score * 100),
127
- }));
128
- }
129
- }
130
- else {
131
- // No API key — use partial local matches
132
- results = localMatches.map((m) => ({
133
- command: m.entry.command,
134
- explanation: m.entry.description,
135
- source: "local",
136
- confidence: Math.round(m.score * 100),
137
- }));
138
- }
139
- // Output
140
- if (format === "json") {
141
- writeJsonOutput(formatSuggestJson(results), "suggest");
142
- }
143
- else {
144
- writeOutput(formatSuggestHuman(results));
145
- }
230
+ await handleSuggest({
231
+ intent: intentParts.join(" "),
232
+ format: options.format,
233
+ strict: options.strict,
234
+ continueOnError: options.continueOnError,
235
+ machine: machineMode,
236
+ base: globalOpts.base,
237
+ apiKey: config.apiKey,
238
+ });
146
239
  }
147
240
  catch (error) {
148
- console.error("Error:", error instanceof Error ? error.message : String(error));
241
+ process.stderr.write(renderError({
242
+ message: error instanceof Error ? error.message : String(error),
243
+ suggestion: "vertaa --help",
244
+ exitCode: ExitCode.ERROR,
245
+ }) + "\n");
149
246
  process.exit(ExitCode.ERROR);
150
247
  }
151
248
  });
@@ -13,5 +13,40 @@
13
13
  * vertaa triage --file audit.json --verbose
14
14
  */
15
15
  import { Command } from "commander";
16
+ import { type ViewportItem } from "@vertaaux/tui";
17
+ interface TriageItem {
18
+ id: string | null;
19
+ title: string;
20
+ reason: string;
21
+ effort: "trivial" | "small" | "medium" | "large";
22
+ }
23
+ interface TriageApiResponse {
24
+ data: {
25
+ p0_critical: TriageItem[];
26
+ p1_important: TriageItem[];
27
+ p2_nice_to_have: TriageItem[];
28
+ quick_wins: string[];
29
+ };
30
+ }
31
+ /**
32
+ * Flatten triage p0/p1/p2 buckets into a ViewportItem array.
33
+ *
34
+ * Order: p0_critical → p1_important → p2_nice_to_have (preserves API order within buckets).
35
+ * Severity mapping: p0 → "critical", p1 → "warning", p2 → "moderate".
36
+ */
37
+ export declare function buildViewportItems(data: TriageApiResponse["data"]): ViewportItem[];
38
+ export interface TriageCommandOptions {
39
+ job?: string;
40
+ file?: string;
41
+ format?: string;
42
+ strict?: boolean;
43
+ continueOnError?: boolean;
44
+ machine?: boolean;
45
+ verbose?: boolean;
46
+ base?: string;
47
+ apiKey?: string;
48
+ }
49
+ export declare function handleTriage(opts: TriageCommandOptions): Promise<void>;
16
50
  export declare function registerTriageCommand(program: Command): void;
51
+ export {};
17
52
  //# sourceMappingURL=triage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"triage.d.ts","sourceRoot":"","sources":["../../src/commands/triage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuJpC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA+G5D"}
1
+ {"version":3,"file":"triage.d.ts","sourceRoot":"","sources":["../../src/commands/triage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAwK,KAAK,YAAY,EAAqC,MAAM,eAAe,CAAC;AAc3P,UAAU,UAAU;IAClB,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;CAClD;AAED,UAAU,iBAAiB;IACzB,IAAI,EAAE;QACJ,WAAW,EAAE,UAAU,EAAE,CAAC;QAC1B,YAAY,EAAE,UAAU,EAAE,CAAC;QAC3B,eAAe,EAAE,UAAU,EAAE,CAAC;QAC9B,UAAU,EAAE,MAAM,EAAE,CAAC;KACtB,CAAC;CACH;AA0HD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,iBAAiB,CAAC,MAAM,CAAC,GAAG,YAAY,EAAE,CAkClF;AAMD,MAAM,WAAW,oBAAoB;IACnC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwJ5E;AAMD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA+C5D"}