@aiready/cli 0.14.10 → 0.14.12

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.
@@ -7,6 +7,95 @@ import {
7
7
  getRatingDisplay,
8
8
  } from '@aiready/core';
9
9
 
10
+ /**
11
+ * Generate a visual progress bar for a score.
12
+ *
13
+ * @param score - The score value (0-100)
14
+ * @param width - The width of the progress bar
15
+ * @returns A colored progress bar string
16
+ */
17
+ function generateProgressBar(score: number, width: number = 20): string {
18
+ const filled = Math.round((score / 100) * width);
19
+ const empty = width - filled;
20
+
21
+ let color = chalk.red;
22
+ if (score >= 90) color = chalk.green;
23
+ else if (score >= 75) color = chalk.cyan;
24
+ else if (score >= 60) color = chalk.yellow;
25
+
26
+ const bar = '█'.repeat(filled) + '░'.repeat(empty);
27
+ return color(bar);
28
+ }
29
+
30
+ /**
31
+ * Count issues by severity level from all tool results.
32
+ *
33
+ * @param results - The unified results object
34
+ * @returns Object with counts for each severity level
35
+ */
36
+ function countIssuesBySeverity(results: any): {
37
+ critical: number;
38
+ major: number;
39
+ minor: number;
40
+ } {
41
+ let critical = 0;
42
+ let major = 0;
43
+ let minor = 0;
44
+
45
+ if (results.summary?.toolsRun) {
46
+ for (const toolId of results.summary.toolsRun) {
47
+ const toolRes = results[toolId];
48
+ if (toolRes?.results) {
49
+ for (const fileRes of toolRes.results) {
50
+ if (fileRes.issues) {
51
+ for (const issue of fileRes.issues) {
52
+ const sev = issue.severity?.toLowerCase();
53
+ if (sev === 'critical') critical++;
54
+ else if (sev === 'major') major++;
55
+ else minor++;
56
+ }
57
+ }
58
+ }
59
+ }
60
+ }
61
+ }
62
+
63
+ return { critical, major, minor };
64
+ }
65
+
66
+ /**
67
+ * Get top files with most issues.
68
+ *
69
+ * @param results - The unified results object
70
+ * @param limit - Maximum number of files to return
71
+ * @returns Array of files with issue counts
72
+ */
73
+ function getTopFilesWithIssues(
74
+ results: any,
75
+ limit: number = 5
76
+ ): Array<{ file: string; count: number }> {
77
+ const fileCounts = new Map<string, number>();
78
+
79
+ if (results.summary?.toolsRun) {
80
+ for (const toolId of results.summary.toolsRun) {
81
+ const toolRes = results[toolId];
82
+ if (toolRes?.results) {
83
+ for (const fileRes of toolRes.results) {
84
+ if (fileRes.issues?.length > 0) {
85
+ const current = fileCounts.get(fileRes.fileName) || 0;
86
+ fileCounts.set(fileRes.fileName, current + fileRes.issues.length);
87
+ }
88
+ }
89
+ }
90
+ }
91
+ }
92
+
93
+ return Array.from(fileCounts.entries())
94
+ .map(([file, count]) => ({ file, count }))
95
+ .sort((a, b) => b.count - a.count)
96
+ .slice(0, limit);
97
+ }
98
+
10
99
  /**
11
100
  * Handle console output for the scan results.
12
101
  *
@@ -14,12 +103,48 @@ import {
14
103
  * @param startTime - The timestamp when the scan started.
15
104
  */
16
105
  export function printScanSummary(results: any, startTime: number) {
106
+ // Count issues by severity
107
+ const severity = countIssuesBySeverity(results);
108
+ const totalIssues = severity.critical + severity.major + severity.minor;
109
+
110
+ // Get top files with issues
111
+ const topFiles = getTopFilesWithIssues(results);
112
+
17
113
  console.log(chalk.cyan('\n=== AIReady Run Summary ==='));
114
+ console.log(` Total issues: ${chalk.bold(String(totalIssues))}`);
115
+
116
+ // Severity breakdown
117
+ if (totalIssues > 0) {
118
+ console.log(chalk.dim(' Severity breakdown:'));
119
+ if (severity.critical > 0) {
120
+ console.log(
121
+ ` ${chalk.red('●')} Critical: ${chalk.bold(severity.critical)}`
122
+ );
123
+ }
124
+ if (severity.major > 0) {
125
+ console.log(
126
+ ` ${chalk.yellow('●')} Major: ${chalk.bold(severity.major)}`
127
+ );
128
+ }
129
+ if (severity.minor > 0) {
130
+ console.log(
131
+ ` ${chalk.blue('●')} Minor: ${chalk.bold(severity.minor)}`
132
+ );
133
+ }
134
+ }
135
+
136
+ // Top files with issues
137
+ if (topFiles.length > 0) {
138
+ console.log(chalk.dim('\n Top files with issues:'));
139
+ topFiles.forEach((item) => {
140
+ console.log(
141
+ ` ${chalk.yellow('→')} ${item.file}: ${chalk.bold(item.count)} issues`
142
+ );
143
+ });
144
+ }
145
+
18
146
  console.log(
19
- ` Total issues (all tools): ${chalk.bold(String(results.summary.totalIssues ?? 0))}`
20
- );
21
- console.log(
22
- ` Execution time: ${chalk.bold(((Date.now() - startTime) / 1000).toFixed(2) + 's')}`
147
+ `\n Execution time: ${chalk.bold(((Date.now() - startTime) / 1000).toFixed(2) + 's')}`
23
148
  );
24
149
  }
25
150
 
@@ -64,18 +189,19 @@ export function printScoring(
64
189
  scoringResult.breakdown.forEach((tool: any) => {
65
190
  const rating = getRating(tool.score);
66
191
  const emoji = getRatingDisplay(rating).emoji;
192
+ const progressBar = generateProgressBar(tool.score, 15);
67
193
  console.log(
68
- ` - ${tool.toolName}: ${tool.score}/100 (${rating}) ${emoji}`
194
+ ` ${progressBar} ${tool.score}/100 (${rating}) ${emoji} ${tool.toolName}`
69
195
  );
70
196
  });
71
197
 
72
- // Top Actionable Recommendations
198
+ // Top Actionable Recommendations - increased from 3 to 5
73
199
  const allRecs = scoringResult.breakdown
74
200
  .flatMap((t: any) =>
75
201
  (t.recommendations ?? []).map((r: any) => ({ ...r, tool: t.toolName }))
76
202
  )
77
203
  .sort((a: any, b: any) => b.estimatedImpact - a.estimatedImpact)
78
- .slice(0, 3);
204
+ .slice(0, 5); // Increased from 3 to 5
79
205
 
80
206
  if (allRecs.length > 0) {
81
207
  console.log(chalk.bold('\n🎯 Top Actionable Recommendations:'));