@vertaaux/cli 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) 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 +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 +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 -1097
  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 +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 +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 +2 -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 +2 -1
  168. package/dist/output/human.d.ts.map +1 -1
  169. package/dist/output/human.js +3 -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/url-classify.d.ts.map +1 -1
  201. package/dist/utils/url-classify.js +24 -3
  202. package/node_modules/@vertaaux/tui/dist/index.cjs +713 -20
  203. package/node_modules/@vertaaux/tui/dist/index.cjs.map +1 -1
  204. package/node_modules/@vertaaux/tui/dist/index.d.cts +361 -4
  205. package/node_modules/@vertaaux/tui/dist/index.d.ts +361 -4
  206. package/node_modules/@vertaaux/tui/dist/index.js +689 -21
  207. package/node_modules/@vertaaux/tui/dist/index.js.map +1 -1
  208. package/package.json +13 -5
  209. package/dist/commands/client.d.ts +0 -14
  210. package/dist/commands/client.d.ts.map +0 -1
  211. package/dist/commands/client.js +0 -362
  212. package/dist/commands/drift.d.ts +0 -15
  213. package/dist/commands/drift.d.ts.map +0 -1
  214. package/dist/commands/drift.js +0 -309
  215. package/dist/commands/protect.d.ts +0 -16
  216. package/dist/commands/protect.d.ts.map +0 -1
  217. package/dist/commands/protect.js +0 -323
  218. package/dist/commands/report.d.ts +0 -15
  219. package/dist/commands/report.d.ts.map +0 -1
  220. package/dist/commands/report.js +0 -214
  221. package/dist/policy/sync.d.ts +0 -67
  222. package/dist/policy/sync.d.ts.map +0 -1
  223. package/dist/policy/sync.js +0 -147
@@ -6,12 +6,14 @@
6
6
  * - vertaa logout: Clear stored credentials
7
7
  * - vertaa whoami: Show current authentication status
8
8
  */
9
- import chalk from "chalk";
9
+ import { colorize, bold, brand, severity as severityPalette, renderError, renderWarning, runSteps, createRenderer } from "@vertaaux/tui";
10
10
  import { saveToken, loadToken, clearToken, isTokenExpired, } from "../auth/token-store.js";
11
11
  import { startDeviceFlow } from "../auth/device-flow.js";
12
12
  import { validateCIToken, getCIToken, getTokenInfo } from "../auth/ci-token.js";
13
13
  import { isInteractive } from "../interactive/prompts.js";
14
14
  import { ExitCode } from "../utils/exit-codes.js";
15
+ import { writeOutput } from "../output/envelope.js";
16
+ import { strings } from "../ui/strings.js";
15
17
  /**
16
18
  * OAuth client ID for the CLI.
17
19
  * This is a public client ID, not a secret.
@@ -40,147 +42,285 @@ function getApiBase() {
40
42
  /**
41
43
  * Handle the login command.
42
44
  */
43
- async function handleLogin(options) {
45
+ export async function handleLogin(options) {
44
46
  // Check for SSO placeholder
45
47
  if (options.sso) {
46
- console.error("SSO login is not yet implemented.");
47
- console.error("Use --token for CI/API token authentication or omit flags for device code flow.");
48
+ process.stderr.write(renderWarning({
49
+ message: strings.login.ssoNotImplemented,
50
+ suggestion: "vertaa login",
51
+ }) + "\n");
48
52
  process.exit(ExitCode.ERROR);
49
53
  }
54
+ const renderer = createRenderer("auto");
55
+ const baseState = {
56
+ phase: "login",
57
+ phaseIndex: 1,
58
+ phaseTotal: 1,
59
+ url: "",
60
+ mode: "login",
61
+ progress: {},
62
+ totals: {},
63
+ issueCount: 0,
64
+ scorePreview: null,
65
+ verbose: false,
66
+ elapsed: 0,
67
+ };
68
+ const startTime = Date.now();
50
69
  // Option 1: Direct token authentication (CI mode)
51
70
  if (options.token) {
52
- console.error("Validating token...");
53
- const apiBase = options.base || getApiBase();
54
- const isValid = await validateCIToken(options.token, apiBase);
55
- if (!isValid) {
56
- console.error(chalk.red("Error: Invalid token. Please check your token and try again."));
57
- process.exit(ExitCode.ERROR);
58
- }
59
- // Save the CI token
60
- const tokenData = {
61
- accessToken: options.token,
62
- type: "ci",
63
- savedAt: new Date().toISOString(),
64
- };
65
- await saveToken(tokenData);
66
- console.error(chalk.green("Authentication successful!"));
67
- console.error("Token saved to ~/.vertaaux/credentials.json");
71
+ const steps = [
72
+ {
73
+ id: "validate",
74
+ actionText: strings.login.validatingToken,
75
+ summaryText: "Token validated",
76
+ run: async () => {
77
+ const apiBase = options.base || getApiBase();
78
+ const isValid = await validateCIToken(options.token, apiBase);
79
+ if (!isValid) {
80
+ throw new Error(strings.login.errors.invalidToken);
81
+ }
82
+ },
83
+ },
84
+ {
85
+ id: "save",
86
+ actionText: "Saving credentials...",
87
+ summaryText: "Credentials saved",
88
+ run: async () => {
89
+ const tokenData = {
90
+ accessToken: options.token,
91
+ type: "ci",
92
+ savedAt: new Date().toISOString(),
93
+ };
94
+ await saveToken(tokenData);
95
+ },
96
+ },
97
+ ];
98
+ await runSteps(steps, {
99
+ failFast: true,
100
+ onStateChange: (stepStates) => {
101
+ renderer.update({ ...baseState, stepStates, elapsed: Date.now() - startTime });
102
+ },
103
+ });
104
+ renderer.finish({ url: "", mode: "login", overallScore: 0, scores: {}, issueCount: 0, passed: true, elapsed: Date.now() - startTime });
105
+ writeOutput(colorize(strings.login.success, brand.lime) + "\n" + strings.login.tokenSaved);
68
106
  return;
69
107
  }
70
108
  // Option 2: Check for CI token in environment
71
109
  const envToken = getCIToken();
72
110
  if (envToken && !isInteractive()) {
73
- console.error("Found token in environment, validating...");
74
- const apiBase = options.base || getApiBase();
75
- const isValid = await validateCIToken(envToken, apiBase);
76
- if (!isValid) {
77
- console.error(chalk.red("Error: Environment token is invalid."));
78
- process.exit(ExitCode.ERROR);
79
- }
80
- const tokenData = {
81
- accessToken: envToken,
82
- type: "ci",
83
- savedAt: new Date().toISOString(),
84
- };
85
- await saveToken(tokenData);
86
- console.error(chalk.green("Authentication successful!"));
87
- console.error("Token from environment saved to ~/.vertaaux/credentials.json");
111
+ const steps = [
112
+ {
113
+ id: "validate",
114
+ actionText: strings.login.envTokenFound,
115
+ summaryText: "Environment token validated",
116
+ run: async () => {
117
+ const apiBase = options.base || getApiBase();
118
+ const isValid = await validateCIToken(envToken, apiBase);
119
+ if (!isValid) {
120
+ throw new Error(strings.login.errors.envTokenInvalid);
121
+ }
122
+ },
123
+ },
124
+ {
125
+ id: "save",
126
+ actionText: "Saving credentials...",
127
+ summaryText: "Credentials saved",
128
+ run: async () => {
129
+ const tokenData = {
130
+ accessToken: envToken,
131
+ type: "ci",
132
+ savedAt: new Date().toISOString(),
133
+ };
134
+ await saveToken(tokenData);
135
+ },
136
+ },
137
+ ];
138
+ await runSteps(steps, {
139
+ failFast: true,
140
+ onStateChange: (stepStates) => {
141
+ renderer.update({ ...baseState, stepStates, elapsed: Date.now() - startTime });
142
+ },
143
+ });
144
+ renderer.finish({ url: "", mode: "login", overallScore: 0, scores: {}, issueCount: 0, passed: true, elapsed: Date.now() - startTime });
145
+ writeOutput(colorize(strings.login.success, brand.lime) + "\n" + strings.login.envTokenSaved);
88
146
  return;
89
147
  }
90
148
  // Option 3: Interactive device code flow (requires TTY)
91
149
  if (!isInteractive()) {
92
- console.error(chalk.red("Error: Interactive login requires a terminal."));
93
- console.error("Use --token <token> for non-interactive authentication,");
94
- console.error("or set VERTAAUX_TOKEN environment variable.");
150
+ process.stderr.write(renderError({
151
+ message: strings.login.errors.requiresTerminal,
152
+ suggestion: "vertaa login --token <api-key>",
153
+ exitCode: ExitCode.ERROR,
154
+ }) + "\n");
95
155
  process.exit(ExitCode.ERROR);
96
156
  }
97
157
  // Start device code flow
98
- console.error("Starting authentication...");
99
- try {
100
- const authBase = options.base ? options.base.replace("/v1", "") : getAuthBase();
101
- const result = await startDeviceFlow(CLI_CLIENT_ID, authBase);
102
- // Calculate expiration time
103
- const expiresAt = new Date(Date.now() + result.expiresIn * 1000).toISOString();
104
- // Save token
105
- const tokenData = {
106
- accessToken: result.accessToken,
107
- refreshToken: result.refreshToken,
108
- expiresAt,
109
- type: "device",
110
- savedAt: new Date().toISOString(),
111
- };
112
- await saveToken(tokenData);
113
- console.error(chalk.green("\nAuthentication successful!"));
114
- console.error("Token saved to ~/.vertaaux/credentials.json");
115
- }
116
- catch (error) {
117
- console.error(chalk.red("\nError:"), error instanceof Error ? error.message : String(error));
118
- process.exit(ExitCode.ERROR);
119
- }
158
+ const steps = [
159
+ {
160
+ id: "auth",
161
+ actionText: strings.login.startingAuth,
162
+ summaryText: "Authenticated",
163
+ run: async () => {
164
+ const authBase = options.base ? options.base.replace("/v1", "") : getAuthBase();
165
+ const result = await startDeviceFlow(CLI_CLIENT_ID, authBase);
166
+ // Calculate expiration time
167
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1000).toISOString();
168
+ // Save token
169
+ const tokenData = {
170
+ accessToken: result.accessToken,
171
+ refreshToken: result.refreshToken,
172
+ expiresAt,
173
+ type: "device",
174
+ savedAt: new Date().toISOString(),
175
+ };
176
+ await saveToken(tokenData);
177
+ },
178
+ },
179
+ ];
180
+ await runSteps(steps, {
181
+ failFast: true,
182
+ onStateChange: (stepStates) => {
183
+ renderer.update({ ...baseState, stepStates, elapsed: Date.now() - startTime });
184
+ },
185
+ });
186
+ renderer.finish({ url: "", mode: "login", overallScore: 0, scores: {}, issueCount: 0, passed: true, elapsed: Date.now() - startTime });
187
+ writeOutput(colorize(strings.login.success, brand.lime) + "\n" + strings.login.tokenSaved);
120
188
  }
121
189
  /**
122
190
  * Handle the logout command.
123
191
  */
124
- async function handleLogout() {
192
+ export async function handleLogout() {
193
+ const renderer = createRenderer("auto");
194
+ const baseState = {
195
+ phase: "logout",
196
+ phaseIndex: 1,
197
+ phaseTotal: 1,
198
+ url: "",
199
+ mode: "logout",
200
+ progress: {},
201
+ totals: {},
202
+ issueCount: 0,
203
+ scorePreview: null,
204
+ verbose: false,
205
+ elapsed: 0,
206
+ };
207
+ const startTime = Date.now();
208
+ const steps = [
209
+ {
210
+ id: "clear",
211
+ actionText: "Clearing credentials...",
212
+ summaryText: "Credentials cleared",
213
+ run: async () => {
214
+ const existingToken = await loadToken();
215
+ if (!existingToken) {
216
+ // Not an error — just nothing to clear
217
+ return;
218
+ }
219
+ await clearToken();
220
+ },
221
+ },
222
+ ];
223
+ // Check if already logged out before step-list
125
224
  const existingToken = await loadToken();
126
225
  if (!existingToken) {
127
- console.error("No stored credentials found.");
226
+ writeOutput(strings.login.noStoredCredentials);
128
227
  return;
129
228
  }
130
- await clearToken();
131
- console.error(chalk.green("Logged out successfully."));
132
- console.error("Credentials removed from ~/.vertaaux/credentials.json");
229
+ await runSteps(steps, {
230
+ failFast: true,
231
+ onStateChange: (stepStates) => {
232
+ renderer.update({ ...baseState, stepStates, elapsed: Date.now() - startTime });
233
+ },
234
+ });
235
+ renderer.finish({ url: "", mode: "logout", overallScore: 0, scores: {}, issueCount: 0, passed: true, elapsed: Date.now() - startTime });
236
+ writeOutput(colorize(strings.login.logoutSuccess, brand.lime) + "\n" + strings.login.credentialsRemoved);
133
237
  }
134
238
  /**
135
239
  * Handle the whoami command.
136
240
  */
137
- async function handleWhoami(options) {
241
+ export async function handleWhoami(options) {
242
+ const renderer = createRenderer("auto");
243
+ const baseState = {
244
+ phase: "whoami",
245
+ phaseIndex: 1,
246
+ phaseTotal: 1,
247
+ url: "",
248
+ mode: "whoami",
249
+ progress: {},
250
+ totals: {},
251
+ issueCount: 0,
252
+ scorePreview: null,
253
+ verbose: false,
254
+ elapsed: 0,
255
+ };
256
+ const startTime = Date.now();
138
257
  // Check for token in credentials file
139
258
  const storedToken = await loadToken();
140
259
  // Check for token in environment
141
260
  const envToken = getCIToken();
142
261
  if (!storedToken && !envToken) {
143
- console.error(chalk.yellow("Not authenticated."));
144
- console.error("\nRun `vertaa login` to authenticate.");
262
+ writeOutput(colorize(strings.login.notAuthenticated, severityPalette.warning) +
263
+ "\n" + strings.login.runLoginHint);
145
264
  return;
146
265
  }
147
266
  // Use stored token or env token
148
267
  const token = storedToken?.accessToken || envToken;
149
- const tokenSource = storedToken ? "stored" : "environment";
150
268
  if (!token) {
151
- console.error(chalk.yellow("Not authenticated."));
152
- console.error("\nRun `vertaa login` to authenticate.");
269
+ writeOutput(colorize(strings.login.notAuthenticated, severityPalette.warning) +
270
+ "\n" + strings.login.runLoginHint);
153
271
  return;
154
272
  }
155
273
  // Check expiration for stored device tokens
156
274
  if (storedToken && storedToken.type === "device" && isTokenExpired(storedToken)) {
157
- console.error(chalk.yellow("Token expired."));
158
- console.error("\nRun `vertaa login` to re-authenticate.");
275
+ writeOutput(colorize(strings.login.tokenExpired, severityPalette.warning) +
276
+ "\n" + strings.login.runLoginRefreshHint);
159
277
  return;
160
278
  }
161
- // Get token info from API
162
- const apiBase = options.base || getApiBase();
163
- const info = await getTokenInfo(token, apiBase);
164
- if (!info || !info.valid) {
165
- console.error(chalk.yellow("Token invalid or expired."));
166
- console.error("\nRun `vertaa login` to re-authenticate.");
279
+ let whoamiResult = null;
280
+ const steps = [
281
+ {
282
+ id: "check",
283
+ actionText: "Checking identity...",
284
+ summaryText: "Identity verified",
285
+ run: async () => {
286
+ const apiBase = options.base || getApiBase();
287
+ whoamiResult = await getTokenInfo(token, apiBase);
288
+ if (!whoamiResult || !whoamiResult.valid) {
289
+ throw new Error(strings.login.tokenInvalidOrExpired);
290
+ }
291
+ },
292
+ },
293
+ ];
294
+ await runSteps(steps, {
295
+ failFast: true,
296
+ onStateChange: (stepStates) => {
297
+ renderer.update({ ...baseState, stepStates, elapsed: Date.now() - startTime });
298
+ },
299
+ });
300
+ renderer.finish({ url: "", mode: "whoami", overallScore: 0, scores: {}, issueCount: 0, passed: true, elapsed: Date.now() - startTime });
301
+ if (!whoamiResult || !whoamiResult.valid) {
302
+ writeOutput(colorize(strings.login.tokenInvalidOrExpired, severityPalette.warning) +
303
+ "\n" + strings.login.runLoginRefreshHint);
167
304
  return;
168
305
  }
169
- // Display auth status
306
+ const info = whoamiResult;
307
+ // Display auth status via writeOutput
170
308
  const displayName = info.name || info.email || info.user_id || "Unknown";
171
- console.error(chalk.green(`Authenticated as ${chalk.bold(displayName)}`));
172
- console.error("");
309
+ const lines = [
310
+ colorize(strings.login.successWithName(bold(displayName)), brand.lime),
311
+ "",
312
+ ];
173
313
  if (info.email) {
174
- console.error(` Email: ${info.email}`);
314
+ lines.push(` Email: ${info.email}`);
175
315
  }
176
316
  if (info.tier) {
177
- console.error(` Plan: ${info.tier.charAt(0).toUpperCase() + info.tier.slice(1)}`);
317
+ lines.push(` Plan: ${info.tier.charAt(0).toUpperCase() + info.tier.slice(1)}`);
178
318
  }
179
319
  if (info.organization) {
180
- console.error(` Organization: ${info.organization}`);
320
+ lines.push(` Organization: ${info.organization}`);
181
321
  }
182
322
  if (info.scopes && info.scopes.length > 0) {
183
- console.error(` Scopes: ${info.scopes.join(", ")}`);
323
+ lines.push(` Scopes: ${info.scopes.join(", ")}`);
184
324
  }
185
325
  if (storedToken?.expiresAt) {
186
326
  const expiresAt = new Date(storedToken.expiresAt);
@@ -188,9 +328,10 @@ async function handleWhoami(options) {
188
328
  const diffMs = expiresAt.getTime() - now.getTime();
189
329
  const diffHours = Math.round(diffMs / (1000 * 60 * 60));
190
330
  if (diffHours > 0) {
191
- console.error(` Expires: in ${diffHours} hour${diffHours === 1 ? "" : "s"}`);
331
+ lines.push(` Expires: in ${diffHours} hour${diffHours === 1 ? "" : "s"}`);
192
332
  }
193
333
  }
334
+ writeOutput(lines.join("\n"));
194
335
  }
195
336
  /**
196
337
  * Register authentication commands with the Commander program.
@@ -199,19 +340,39 @@ export function registerLoginCommand(program) {
199
340
  // Login command
200
341
  program
201
342
  .command("login")
202
- .description("Authenticate with VertaaUX")
203
- .option("--token <token>", "Use API token directly (for CI/non-interactive use)")
343
+ .description("Authenticate with VertaaUX (stores SDK credentials in ~/.vertaaux/credentials.json)")
344
+ .option("--token <token>", "Use API token directly (stored as SDK default credentials)")
204
345
  .option("--sso", "Use SSO login (not yet implemented)")
205
346
  .option("-b, --base <url>", "API base URL")
206
347
  .action(async (options) => {
207
- await handleLogin(options);
348
+ try {
349
+ await handleLogin(options);
350
+ }
351
+ catch (error) {
352
+ process.stderr.write(renderError({
353
+ message: error instanceof Error ? error.message : String(error),
354
+ suggestion: "vertaa login",
355
+ exitCode: ExitCode.ERROR,
356
+ }) + "\n");
357
+ process.exit(ExitCode.ERROR);
358
+ }
208
359
  });
209
360
  // Logout command
210
361
  program
211
362
  .command("logout")
212
363
  .description("Clear stored credentials")
213
364
  .action(async () => {
214
- await handleLogout();
365
+ try {
366
+ await handleLogout();
367
+ }
368
+ catch (error) {
369
+ process.stderr.write(renderError({
370
+ message: error instanceof Error ? error.message : String(error),
371
+ suggestion: "vertaa login",
372
+ exitCode: ExitCode.ERROR,
373
+ }) + "\n");
374
+ process.exit(ExitCode.ERROR);
375
+ }
215
376
  });
216
377
  // Whoami command
217
378
  program
@@ -219,6 +380,16 @@ export function registerLoginCommand(program) {
219
380
  .description("Show current authentication status")
220
381
  .option("-b, --base <url>", "API base URL")
221
382
  .action(async (options) => {
222
- await handleWhoami(options);
383
+ try {
384
+ await handleWhoami(options);
385
+ }
386
+ catch (error) {
387
+ process.stderr.write(renderError({
388
+ message: error instanceof Error ? error.message : String(error),
389
+ suggestion: "vertaa whoami",
390
+ exitCode: ExitCode.ERROR,
391
+ }) + "\n");
392
+ process.exit(ExitCode.ERROR);
393
+ }
223
394
  });
224
395
  }
@@ -10,5 +10,16 @@
10
10
  * cat fix.patch | vertaa patch-review --findings findings.json
11
11
  */
12
12
  import { Command } from "commander";
13
+ export interface PatchReviewCommandOptions {
14
+ job?: string;
15
+ findings?: string;
16
+ diffFile?: string;
17
+ format?: string;
18
+ base?: string;
19
+ machine?: boolean;
20
+ dryRun?: boolean;
21
+ apiKey?: string;
22
+ }
23
+ export declare function handlePatchReview(opts: PatchReviewCommandOptions): Promise<void>;
13
24
  export declare function registerPatchReviewCommand(program: Command): void;
14
25
  //# sourceMappingURL=patch-review.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"patch-review.d.ts","sourceRoot":"","sources":["../../src/commands/patch-review.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmIpC,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA2HjE"}
1
+ {"version":3,"file":"patch-review.d.ts","sourceRoot":"","sources":["../../src/commands/patch-review.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmIpC,MAAM,WAAW,yBAAyB;IACxC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkJtF;AAMD,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA6CjE"}