codeant-cli 0.3.1 → 0.3.3

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 (69) hide show
  1. package/dist/178.index.js +1 -1
  2. package/dist/239.index.js +1 -1
  3. package/dist/701.index.js +1 -1
  4. package/dist/880.index.js +1 -1
  5. package/dist/935.index.js +1 -1
  6. package/dist/966.index.js +1 -1
  7. package/dist/index.js +5 -5
  8. package/dist/review/239.index.js +1 -0
  9. package/dist/review/index.js +8 -0
  10. package/dist/review/package.json +3 -0
  11. package/package.json +5 -6
  12. package/src/commands/getBaseUrl.js +0 -21
  13. package/src/commands/login.js +0 -125
  14. package/src/commands/logout.js +0 -30
  15. package/src/commands/review.js +0 -294
  16. package/src/commands/secrets.js +0 -148
  17. package/src/commands/setBaseUrl.js +0 -37
  18. package/src/components/ReviewUI.js +0 -410
  19. package/src/components/SecretsUI.js +0 -366
  20. package/src/components/Welcome.js +0 -144
  21. package/src/index.js +0 -349
  22. package/src/reviewHeadless.js +0 -198
  23. package/src/scm/azure/client.js +0 -21
  24. package/src/scm/azure/getCodeReview.js +0 -20
  25. package/src/scm/azure/getPullRequest.js +0 -30
  26. package/src/scm/azure/index.js +0 -6
  27. package/src/scm/azure/listCodeReviews.js +0 -17
  28. package/src/scm/azure/listPullRequestComments.js +0 -41
  29. package/src/scm/azure/listPullRequests.js +0 -26
  30. package/src/scm/azure/searchComments.js +0 -35
  31. package/src/scm/bitbucket/client.js +0 -18
  32. package/src/scm/bitbucket/getCodeReview.js +0 -3
  33. package/src/scm/bitbucket/getPullRequest.js +0 -26
  34. package/src/scm/bitbucket/index.js +0 -6
  35. package/src/scm/bitbucket/listCodeReviews.js +0 -17
  36. package/src/scm/bitbucket/listPullRequestComments.js +0 -33
  37. package/src/scm/bitbucket/listPullRequests.js +0 -33
  38. package/src/scm/bitbucket/searchComments.js +0 -29
  39. package/src/scm/github/client.js +0 -17
  40. package/src/scm/github/getCodeReview.js +0 -26
  41. package/src/scm/github/getPullRequest.js +0 -27
  42. package/src/scm/github/index.js +0 -6
  43. package/src/scm/github/listCodeReviews.js +0 -17
  44. package/src/scm/github/listPullRequestComments.js +0 -51
  45. package/src/scm/github/listPullRequests.js +0 -32
  46. package/src/scm/github/searchComments.js +0 -30
  47. package/src/scm/gitlab/client.js +0 -16
  48. package/src/scm/gitlab/getCodeReview.js +0 -18
  49. package/src/scm/gitlab/getPullRequest.js +0 -24
  50. package/src/scm/gitlab/index.js +0 -6
  51. package/src/scm/gitlab/listCodeReviews.js +0 -21
  52. package/src/scm/gitlab/listPullRequestComments.js +0 -44
  53. package/src/scm/gitlab/listPullRequests.js +0 -26
  54. package/src/scm/gitlab/searchComments.js +0 -28
  55. package/src/scm/index.js +0 -96
  56. package/src/tools/executeTool.js +0 -31
  57. package/src/tools/globTool.js +0 -9
  58. package/src/tools/grepTool.js +0 -18
  59. package/src/tools/lsTool.js +0 -7
  60. package/src/tools/readTool.js +0 -12
  61. package/src/utils/analytics.js +0 -45
  62. package/src/utils/baseUrl.js +0 -11
  63. package/src/utils/commonApiHelper.js +0 -143
  64. package/src/utils/config.js +0 -42
  65. package/src/utils/fetchApi.js +0 -39
  66. package/src/utils/gitDiffHelper.js +0 -1203
  67. package/src/utils/reviewApiHelper.js +0 -275
  68. package/src/utils/scmAuth.js +0 -136
  69. package/src/utils/secretsApiHelper.js +0 -242
@@ -1,410 +0,0 @@
1
- import React, { useState, useEffect } from 'react';
2
- import { Box, Text } from 'ink';
3
-
4
- // ── Constants ────────────────────────────────────────────────────────────────
5
-
6
- const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
7
- const DIVIDER = '─'.repeat(55);
8
- const STEPS = ['Init', 'Fetch', 'Analyze', 'Reflect'];
9
-
10
- const SEVERITY_COLORS = {
11
- BLOCKER: 'red',
12
- CRITICAL: 'red',
13
- MAJOR: 'yellow',
14
- MINOR: 'cyan',
15
- INFO: 'gray',
16
- };
17
-
18
- // ── Helpers ──────────────────────────────────────────────────────────────────
19
-
20
- export function mapLabelToSeverity(label) {
21
- const mapping = {
22
- 'security': 'CRITICAL',
23
- 'performance': 'MAJOR',
24
- 'maintainability': 'MINOR',
25
- 'code quality': 'MINOR',
26
- 'best practice': 'MINOR',
27
- 'bug': 'MAJOR',
28
- };
29
- // Guard against non-string labels from model output to avoid runtime crash
30
- if (typeof label !== 'string') return 'MINOR';
31
- return mapping[label.toLowerCase().replace(/[^\w\s]/g, '')] || 'MINOR';
32
- }
33
-
34
- function getSeverityColor(sev) {
35
- return SEVERITY_COLORS[sev] || 'gray';
36
- }
37
-
38
- function padEnd(str, len) {
39
- return str + ' '.repeat(Math.max(0, len - str.length));
40
- }
41
-
42
- function formatElapsed(startTime) {
43
- return ((Date.now() - startTime) / 1000).toFixed(1) + 's';
44
- }
45
-
46
- // ── Animated Components ──────────────────────────────────────────────────────
47
-
48
- function Spinner({ color = 'cyan' }) {
49
- const [frame, setFrame] = useState(0);
50
- useEffect(() => {
51
- const timer = setInterval(() => {
52
- setFrame(f => (f + 1) % SPINNER_FRAMES.length);
53
- }, 80);
54
- return () => clearInterval(timer);
55
- }, []);
56
- return React.createElement(Text, { color }, SPINNER_FRAMES[frame]);
57
- }
58
-
59
- function ElapsedTime({ startTime }) {
60
- const [, setTick] = useState(0);
61
- useEffect(() => {
62
- const timer = setInterval(() => setTick(t => t + 1), 100);
63
- return () => clearInterval(timer);
64
- }, []);
65
- return React.createElement(Text, { color: 'gray' }, formatElapsed(startTime));
66
- }
67
-
68
- function StepProgress({ currentStep }) {
69
- const items = STEPS.map((step, i) => {
70
- if (i < currentStep) {
71
- return React.createElement(Text, { key: step, color: 'green' }, `✓ ${step}`);
72
- } else if (i === currentStep) {
73
- return React.createElement(
74
- Box, { key: step },
75
- React.createElement(Spinner, { color: 'cyan' }),
76
- React.createElement(Text, { color: 'cyan' }, ` ${step}`),
77
- );
78
- } else {
79
- return React.createElement(Text, { key: step, color: 'gray', dimColor: true }, `· ${step}`);
80
- }
81
- });
82
- return React.createElement(Box, { gap: 2 }, ...items);
83
- }
84
-
85
- // ── Loading Screen ───────────────────────────────────────────────────────────
86
-
87
- function ReviewLoading({ message, step, startTime, meta }) {
88
- const els = [
89
- React.createElement(
90
- Box, { key: 'status', gap: 1 },
91
- React.createElement(Spinner, {}),
92
- React.createElement(Text, { color: 'white', bold: true }, message),
93
- startTime != null && React.createElement(ElapsedTime, { startTime }),
94
- ),
95
- React.createElement(
96
- Box, { key: 'steps', marginTop: 1 },
97
- React.createElement(StepProgress, { currentStep: step }),
98
- ),
99
- ];
100
-
101
- // Show file list and coverage info when we have metadata (during analyze/reflect)
102
- if (meta && step >= 2) {
103
- const reviewed = meta.reviewed_files || [];
104
- const total = meta.total_changed || 0;
105
- const skipped = meta.skipped || [];
106
-
107
- els.push(React.createElement(Text, { key: 'meta-sp' }, ''));
108
- els.push(React.createElement(
109
- Text, { key: 'meta-hdr', color: 'gray', dimColor: true }, DIVIDER,
110
- ));
111
-
112
- // Coverage line
113
- if (total > 0) {
114
- const coverageColor = reviewed.length === total ? 'green' : 'yellow';
115
- els.push(React.createElement(
116
- Text, { key: 'coverage', color: coverageColor },
117
- `Reviewing ${reviewed.length} of ${total} changed file${total !== 1 ? 's' : ''}`,
118
- ));
119
- }
120
-
121
- // File list
122
- if (reviewed.length > 0) {
123
- els.push(React.createElement(Text, { key: 'files-sp' }, ''));
124
- reviewed.forEach((file, i) => {
125
- const isLast = i === reviewed.length - 1;
126
- const branch = isLast ? '└─' : '├─';
127
- els.push(React.createElement(
128
- Text, { key: `file-${i}`, color: 'white' },
129
- ` ${branch} ${file}`,
130
- ));
131
- });
132
- }
133
-
134
- // Skipped summary
135
- if (skipped.length > 0) {
136
- els.push(React.createElement(Text, { key: 'skip-sp' }, ''));
137
- // Group skip reasons
138
- const reasons = {};
139
- skipped.forEach(s => {
140
- const r = s.reason.split(' (')[0]; // normalize "too large (1234 lines...)" → "too large"
141
- reasons[r] = (reasons[r] || 0) + 1;
142
- });
143
- const parts = Object.entries(reasons).map(([r, n]) => `${n} ${r}`);
144
- els.push(React.createElement(
145
- Text, { key: 'skipped', color: 'gray', dimColor: true },
146
- `Skipped: ${parts.join(' · ')}`,
147
- ));
148
- }
149
-
150
- // Cap warning
151
- if (meta.capped) {
152
- els.push(React.createElement(
153
- Text, { key: 'cap', color: 'yellow', dimColor: true },
154
- `Note: max ${meta.max_files} files per review`,
155
- ));
156
- }
157
- }
158
-
159
- return React.createElement(
160
- Box, { flexDirection: 'column', paddingX: 1, paddingY: 1 }, ...els,
161
- );
162
- }
163
-
164
- // ── Public Render Functions ──────────────────────────────────────────────────
165
-
166
- export function renderInitializing(startTime) {
167
- return React.createElement(ReviewLoading, {
168
- message: 'Initializing...',
169
- step: 0,
170
- startTime,
171
- });
172
- }
173
-
174
- export function renderFetchingDiff(startTime) {
175
- return React.createElement(ReviewLoading, {
176
- message: 'Fetching changes...',
177
- step: 1,
178
- startTime,
179
- });
180
- }
181
-
182
- export function renderReviewing(currentMessage, startTime, meta) {
183
- const step = currentMessage?.toLowerCase().includes('reflector') ? 3 : 2;
184
- return React.createElement(ReviewLoading, {
185
- message: currentMessage || 'Analyzing code...',
186
- step,
187
- startTime,
188
- meta,
189
- });
190
- }
191
-
192
- export function renderNoFiles(scanType, lastNCommits) {
193
- const hints = {
194
- 'staged-only': 'Stage some changes first with "git add".',
195
- 'branch-diff': 'No changes found compared to the base branch.',
196
- 'uncommitted': 'No uncommitted changes found.',
197
- 'last-commit': 'No files found in the last commit.',
198
- 'last-n-commits': `No changes found in the last ${lastNCommits} commit(s).`,
199
- 'all': 'No changes found between your branch and the base.',
200
- 'committed': 'No unpushed commits found.',
201
- };
202
- return React.createElement(
203
- Box, { flexDirection: 'column', paddingX: 1, paddingY: 1 },
204
- React.createElement(Text, { color: 'cyan', bold: true }, 'CodeAnt Review'),
205
- React.createElement(Text, { color: 'gray', dimColor: true }, DIVIDER),
206
- React.createElement(Text, {}, ''),
207
- React.createElement(Text, { color: 'yellow' }, ' No changes to review.'),
208
- React.createElement(Text, { color: 'gray' }, ` ${hints[scanType] || 'No files found.'}`),
209
- React.createElement(Text, {}, ''),
210
- );
211
- }
212
-
213
- export function renderError(error) {
214
- return React.createElement(
215
- Box, { flexDirection: 'column', paddingX: 1, paddingY: 1 },
216
- React.createElement(Text, { color: 'cyan', bold: true }, 'CodeAnt Review'),
217
- React.createElement(Text, { color: 'gray', dimColor: true }, DIVIDER),
218
- React.createElement(Text, {}, ''),
219
- React.createElement(Text, { color: 'red', bold: true }, ` ✗ ${error}`),
220
- React.createElement(Text, {}, ''),
221
- );
222
- }
223
-
224
- export function renderNotLoggedIn() {
225
- return React.createElement(
226
- Box, { flexDirection: 'column', paddingX: 1, paddingY: 1 },
227
- React.createElement(Text, { color: 'cyan', bold: true }, 'CodeAnt Review'),
228
- React.createElement(Text, { color: 'gray', dimColor: true }, DIVIDER),
229
- React.createElement(Text, {}, ''),
230
- React.createElement(Text, { color: 'red', bold: true }, ' ✗ Not logged in'),
231
- React.createElement(Text, { color: 'gray' }, ' Run "codeant login" to authenticate.'),
232
- React.createElement(Text, {}, ''),
233
- );
234
- }
235
-
236
- export function renderDone(issues, summary, failOn, startTime, fileCount, meta) {
237
- const severityOrder = ['INFO', 'MINOR', 'MAJOR', 'CRITICAL', 'BLOCKER'];
238
- const failOnIndex = severityOrder.indexOf(failOn);
239
-
240
- if (failOnIndex === -1) {
241
- return React.createElement(
242
- Box, { flexDirection: 'column', paddingX: 1, paddingY: 1 },
243
- React.createElement(Text, { color: 'red', bold: true }, `✗ Invalid failOn value: ${failOn}`),
244
- );
245
- }
246
-
247
- const blockingIssues = issues.filter(i =>
248
- severityOrder.indexOf(mapLabelToSeverity(i.label)) >= failOnIndex
249
- );
250
- const hasBlocking = blockingIssues.length > 0;
251
- const elapsed = startTime ? formatElapsed(startTime) : null;
252
-
253
- // Count by severity
254
- const counts = {};
255
- issues.forEach(i => {
256
- const sev = mapLabelToSeverity(i.label);
257
- counts[sev] = (counts[sev] || 0) + 1;
258
- });
259
-
260
- // Group issues by file
261
- const grouped = {};
262
- issues.forEach(i => {
263
- const file = i.relevant_file || 'Unknown';
264
- (grouped[file] ??= []).push(i);
265
- });
266
- const sortedFiles = Object.keys(grouped).sort();
267
- sortedFiles.forEach(f =>
268
- grouped[f].sort((a, b) => (a.start_line || 0) - (b.start_line || 0))
269
- );
270
-
271
- const els = [];
272
-
273
- // ── Header ──
274
- els.push(React.createElement(
275
- Box, { key: 'hdr', gap: 1 },
276
- React.createElement(Text, { color: 'cyan', bold: true }, 'CodeAnt Review'),
277
- elapsed && React.createElement(Text, { color: 'gray' }, elapsed),
278
- ));
279
- els.push(React.createElement(
280
- Text, { key: 'div1', color: 'gray', dimColor: true }, DIVIDER,
281
- ));
282
-
283
- if (issues.length === 0) {
284
- // ── Clean pass ──
285
- els.push(React.createElement(Text, { key: 'sp' }, ''));
286
- els.push(React.createElement(
287
- Text, { key: 'ok', color: 'green', bold: true }, ' ✓ No issues found',
288
- ));
289
- els.push(React.createElement(Text, { key: 'sp2' }, ''));
290
- } else {
291
- // ── Issues grouped by file ──
292
- els.push(React.createElement(Text, { key: 'sp1' }, ''));
293
-
294
- sortedFiles.forEach((file, fi) => {
295
- const fileIssues = grouped[file];
296
-
297
- els.push(React.createElement(
298
- Text, { key: `f-${fi}`, color: 'white', bold: true }, ` ${file}`,
299
- ));
300
-
301
- fileIssues.forEach((issue, ii) => {
302
- const sev = mapLabelToSeverity(issue.label);
303
- const sevColor = getSeverityColor(sev);
304
- const isLast = ii === fileIssues.length - 1;
305
- const branch = isLast ? '└─' : '├─';
306
- const cont = isLast ? ' ' : '│ ';
307
- const lineStr = issue.start_line ? `L${issue.start_line}` : '';
308
-
309
- els.push(React.createElement(
310
- Box, { key: `i-${fi}-${ii}` },
311
- React.createElement(Text, { color: 'gray' }, ` ${branch} `),
312
- React.createElement(Text, {
313
- color: sevColor,
314
- bold: sev === 'CRITICAL' || sev === 'BLOCKER',
315
- }, padEnd(sev, 9)),
316
- React.createElement(Text, { color: 'gray' }, padEnd(lineStr, 6)),
317
- React.createElement(Text, { color: 'white', dimColor: true }, issue.label),
318
- ));
319
-
320
- // Safely coerce issue_content — API may return null/non-string, which would crash .trim()
321
- const content = String(issue.issue_content || '').trim();
322
- if (content) {
323
- els.push(React.createElement(
324
- Text, { key: `d-${fi}-${ii}`, color: 'gray' },
325
- ` ${cont} ${content}`,
326
- ));
327
- }
328
- });
329
-
330
- els.push(React.createElement(Text, { key: `g-${fi}` }, ''));
331
- });
332
- }
333
-
334
- // ── Footer ──
335
- els.push(React.createElement(
336
- Text, { key: 'div2', color: 'gray', dimColor: true }, DIVIDER,
337
- ));
338
-
339
- // Coverage line
340
- const totalChanged = meta?.total_changed || 0;
341
- const reviewedCount = meta?.reviewed_files?.length || fileCount;
342
- if (totalChanged > 0) {
343
- const coverageColor = reviewedCount === totalChanged ? 'green' : 'yellow';
344
- els.push(React.createElement(
345
- Text, { key: 'coverage', color: coverageColor },
346
- `Reviewed ${reviewedCount} of ${totalChanged} changed file${totalChanged !== 1 ? 's' : ''}`,
347
- ));
348
- } else if (fileCount) {
349
- els.push(React.createElement(
350
- Text, { key: 'coverage', color: 'gray' },
351
- `${fileCount} file${fileCount !== 1 ? 's' : ''} reviewed`,
352
- ));
353
- }
354
-
355
- // Skipped files summary
356
- const skipped = meta?.skipped || [];
357
- if (skipped.length > 0) {
358
- const reasons = {};
359
- skipped.forEach(s => {
360
- const r = s.reason.split(' (')[0];
361
- reasons[r] = (reasons[r] || 0) + 1;
362
- });
363
- const parts = Object.entries(reasons).map(([r, n]) => `${n} ${r}`);
364
- els.push(React.createElement(
365
- Text, { key: 'skipped', color: 'gray', dimColor: true },
366
- `Skipped: ${parts.join(' · ')}`,
367
- ));
368
- }
369
-
370
- if (meta?.capped) {
371
- els.push(React.createElement(
372
- Text, { key: 'cap', color: 'yellow', dimColor: true },
373
- `Note: max ${meta.max_files} files per review`,
374
- ));
375
- }
376
-
377
- // Issue stats line
378
- const stats = [];
379
- if (issues.length > 0) {
380
- stats.push(`${issues.length} issue${issues.length !== 1 ? 's' : ''}`);
381
- for (const sev of ['CRITICAL', 'MAJOR', 'MINOR', 'INFO']) {
382
- if (counts[sev]) stats.push(`${counts[sev]} ${sev.toLowerCase()}`);
383
- }
384
- els.push(React.createElement(
385
- Text, { key: 'stats', color: 'gray' }, stats.join(' · '),
386
- ));
387
- }
388
-
389
- // Status line
390
- if (hasBlocking) {
391
- els.push(React.createElement(
392
- Text, { key: 'status', color: 'red', bold: true },
393
- `✗ ${blockingIssues.length} blocking issue${blockingIssues.length !== 1 ? 's' : ''} — fix before proceeding`,
394
- ));
395
- } else if (issues.length > 0) {
396
- els.push(React.createElement(
397
- Text, { key: 'status', color: 'green', bold: true },
398
- '✓ All issues are non-blocking',
399
- ));
400
- } else {
401
- els.push(React.createElement(
402
- Text, { key: 'status', color: 'green', bold: true },
403
- '✓ All clear',
404
- ));
405
- }
406
-
407
- return React.createElement(
408
- Box, { flexDirection: 'column', paddingX: 1, paddingY: 1 }, ...els,
409
- );
410
- }