@vertaaux/cli 0.2.3 → 0.3.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.
- package/LICENSE +21 -0
- package/README.md +58 -2
- package/dist/auth/device-flow.js +6 -8
- package/dist/commands/audit.d.ts +2 -0
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +165 -6
- package/dist/commands/compare.d.ts +20 -0
- package/dist/commands/compare.d.ts.map +1 -0
- package/dist/commands/compare.js +335 -0
- package/dist/commands/doc.d.ts +18 -0
- package/dist/commands/doc.d.ts.map +1 -0
- package/dist/commands/doc.js +161 -0
- package/dist/commands/download.d.ts.map +1 -1
- package/dist/commands/download.js +9 -8
- package/dist/commands/explain.d.ts +14 -33
- package/dist/commands/explain.d.ts.map +1 -1
- package/dist/commands/explain.js +277 -179
- package/dist/commands/fix-plan.d.ts +15 -0
- package/dist/commands/fix-plan.d.ts.map +1 -0
- package/dist/commands/fix-plan.js +182 -0
- package/dist/commands/patch-review.d.ts +14 -0
- package/dist/commands/patch-review.d.ts.map +1 -0
- package/dist/commands/patch-review.js +200 -0
- package/dist/commands/release-notes.d.ts +17 -0
- package/dist/commands/release-notes.d.ts.map +1 -0
- package/dist/commands/release-notes.js +145 -0
- package/dist/commands/suggest.d.ts +18 -0
- package/dist/commands/suggest.d.ts.map +1 -0
- package/dist/commands/suggest.js +152 -0
- package/dist/commands/triage.d.ts +17 -0
- package/dist/commands/triage.d.ts.map +1 -0
- package/dist/commands/triage.js +205 -0
- package/dist/commands/upload.d.ts.map +1 -1
- package/dist/commands/upload.js +8 -7
- package/dist/index.js +62 -25
- package/dist/output/formats.d.ts.map +1 -1
- package/dist/output/formats.js +14 -0
- package/dist/output/human.d.ts +1 -10
- package/dist/output/human.d.ts.map +1 -1
- package/dist/output/human.js +26 -98
- package/dist/prompts/command-catalog.d.ts +46 -0
- package/dist/prompts/command-catalog.d.ts.map +1 -0
- package/dist/prompts/command-catalog.js +187 -0
- package/dist/ui/spinner.d.ts +10 -35
- package/dist/ui/spinner.d.ts.map +1 -1
- package/dist/ui/spinner.js +11 -58
- package/dist/ui/table.d.ts +1 -18
- package/dist/ui/table.d.ts.map +1 -1
- package/dist/ui/table.js +56 -163
- package/dist/utils/ai-error.d.ts +48 -0
- package/dist/utils/ai-error.d.ts.map +1 -0
- package/dist/utils/ai-error.js +190 -0
- package/dist/utils/detect-env.d.ts +6 -8
- package/dist/utils/detect-env.d.ts.map +1 -1
- package/dist/utils/detect-env.js +6 -25
- package/dist/utils/stdin.d.ts +50 -0
- package/dist/utils/stdin.d.ts.map +1 -0
- package/dist/utils/stdin.js +93 -0
- package/node_modules/@vertaaux/tui/dist/index.cjs +1157 -0
- package/node_modules/@vertaaux/tui/dist/index.cjs.map +1 -0
- package/node_modules/@vertaaux/tui/dist/index.d.cts +609 -0
- package/node_modules/@vertaaux/tui/dist/index.d.ts +609 -0
- package/node_modules/@vertaaux/tui/dist/index.js +1100 -0
- package/node_modules/@vertaaux/tui/dist/index.js.map +1 -0
- package/node_modules/@vertaaux/tui/package.json +64 -0
- package/package.json +12 -5
package/dist/ui/spinner.js
CHANGED
|
@@ -1,101 +1,54 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Progress spinner wrapper for CLI.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Delegates to @vertaaux/tui for consistent terminal rendering.
|
|
5
|
+
* Writes ONLY to stderr — never pollutes stdout.
|
|
6
6
|
*/
|
|
7
|
-
import
|
|
8
|
-
import chalk from "chalk";
|
|
9
|
-
import { isTTY, shouldUseColor } from "../utils/detect-env.js";
|
|
10
|
-
// Spinner style - classic dots for clean look
|
|
11
|
-
const SPINNER_STYLE = {
|
|
12
|
-
frames: ["\u2807", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"],
|
|
13
|
-
interval: 80,
|
|
14
|
-
};
|
|
15
|
-
// Brand color for spinner
|
|
16
|
-
const BRAND_COLOR = "#78FFB4";
|
|
7
|
+
import { createSpinner as tuiCreateSpinner, } from "@vertaaux/tui";
|
|
17
8
|
/**
|
|
18
9
|
* Create a new spinner instance.
|
|
19
10
|
*
|
|
20
11
|
* Spinner only displays in TTY mode. In non-TTY environments,
|
|
21
12
|
* returns a no-op spinner that still tracks state.
|
|
22
|
-
*
|
|
23
|
-
* @param text - Initial text to display next to spinner
|
|
24
|
-
* @returns An ora spinner instance
|
|
25
13
|
*/
|
|
26
14
|
export function createSpinner(text) {
|
|
27
|
-
|
|
28
|
-
const spinner = ora({
|
|
29
|
-
text,
|
|
30
|
-
spinner: SPINNER_STYLE,
|
|
31
|
-
color: "cyan",
|
|
32
|
-
isEnabled: isTTY(),
|
|
33
|
-
stream: process.stderr, // Write to stderr to avoid mixing with command output
|
|
34
|
-
});
|
|
35
|
-
// Apply brand color if colors are enabled
|
|
36
|
-
if (useColor) {
|
|
37
|
-
spinner.color = "cyan";
|
|
38
|
-
}
|
|
39
|
-
return spinner;
|
|
15
|
+
return tuiCreateSpinner(text);
|
|
40
16
|
}
|
|
41
17
|
/**
|
|
42
18
|
* Update spinner text with optional progress indicator.
|
|
43
|
-
*
|
|
44
|
-
* @param spinner - The spinner instance to update
|
|
45
|
-
* @param text - New text to display
|
|
46
|
-
* @param current - Current progress count (optional)
|
|
47
|
-
* @param total - Total items count (optional)
|
|
48
19
|
*/
|
|
49
20
|
export function updateSpinner(spinner, text, current, total) {
|
|
50
21
|
if (current !== undefined && total !== undefined) {
|
|
51
|
-
|
|
52
|
-
? chalk.dim(`(${current}/${total})`)
|
|
53
|
-
: `(${current}/${total})`;
|
|
54
|
-
spinner.text = `${text} ${progress}`;
|
|
22
|
+
spinner.setText(`${text} (${current}/${total})`);
|
|
55
23
|
}
|
|
56
24
|
else if (current !== undefined) {
|
|
57
|
-
|
|
58
|
-
? chalk.dim(`(${current})`)
|
|
59
|
-
: `(${current})`;
|
|
60
|
-
spinner.text = `${text} ${progress}`;
|
|
25
|
+
spinner.setText(`${text} (${current})`);
|
|
61
26
|
}
|
|
62
27
|
else {
|
|
63
|
-
spinner.text
|
|
28
|
+
spinner.setText(text);
|
|
64
29
|
}
|
|
65
30
|
}
|
|
66
31
|
/**
|
|
67
32
|
* Complete spinner with success state.
|
|
68
|
-
*
|
|
69
|
-
* @param spinner - The spinner instance
|
|
70
|
-
* @param text - Success message to display
|
|
71
33
|
*/
|
|
72
34
|
export function succeedSpinner(spinner, text) {
|
|
73
|
-
spinner.succeed(
|
|
35
|
+
spinner.succeed(text);
|
|
74
36
|
}
|
|
75
37
|
/**
|
|
76
38
|
* Complete spinner with failure state.
|
|
77
|
-
*
|
|
78
|
-
* @param spinner - The spinner instance
|
|
79
|
-
* @param text - Failure message to display
|
|
80
39
|
*/
|
|
81
40
|
export function failSpinner(spinner, text) {
|
|
82
|
-
spinner.fail(
|
|
41
|
+
spinner.fail(text);
|
|
83
42
|
}
|
|
84
43
|
/**
|
|
85
44
|
* Complete spinner with warning state.
|
|
86
|
-
*
|
|
87
|
-
* @param spinner - The spinner instance
|
|
88
|
-
* @param text - Warning message to display
|
|
89
45
|
*/
|
|
90
46
|
export function warnSpinner(spinner, text) {
|
|
91
|
-
spinner.warn(
|
|
47
|
+
spinner.warn(text);
|
|
92
48
|
}
|
|
93
49
|
/**
|
|
94
50
|
* Complete spinner with info state.
|
|
95
|
-
*
|
|
96
|
-
* @param spinner - The spinner instance
|
|
97
|
-
* @param text - Info message to display
|
|
98
51
|
*/
|
|
99
52
|
export function infoSpinner(spinner, text) {
|
|
100
|
-
spinner.info(
|
|
53
|
+
spinner.info(text);
|
|
101
54
|
}
|
package/dist/ui/table.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Table formatting utilities for CLI output.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Delegates to @vertaaux/tui for consistent rendering with severity-based coloring.
|
|
5
5
|
* Respects terminal width and provides truncation for long content.
|
|
6
6
|
*/
|
|
7
7
|
export interface Issue {
|
|
@@ -33,31 +33,14 @@ export declare function groupBySeverity(issues: Issue[]): Map<string, Issue[]>;
|
|
|
33
33
|
export declare function groupByCategory(issues: Issue[]): Map<string, Issue[]>;
|
|
34
34
|
/**
|
|
35
35
|
* Format issues into a table string.
|
|
36
|
-
*
|
|
37
|
-
* Columns: Severity | ID | Description | Selector (optional)
|
|
38
|
-
* Issues are sorted by severity (critical -> info).
|
|
39
|
-
*
|
|
40
|
-
* @param issues - Array of issues to format
|
|
41
|
-
* @param options - Formatting options
|
|
42
|
-
* @returns Formatted table string
|
|
43
36
|
*/
|
|
44
37
|
export declare function formatIssuesTable(issues: Issue[], options?: FormatTableOptions): string;
|
|
45
|
-
export interface Score {
|
|
46
|
-
category: string;
|
|
47
|
-
score: number;
|
|
48
|
-
}
|
|
49
38
|
/**
|
|
50
39
|
* Format scores into a table string.
|
|
51
|
-
*
|
|
52
|
-
* @param scores - Object mapping category names to scores
|
|
53
|
-
* @returns Formatted table string
|
|
54
40
|
*/
|
|
55
41
|
export declare function formatScoresTable(scores: Record<string, number | unknown>): string;
|
|
56
42
|
/**
|
|
57
43
|
* Format a summary line showing issue counts by severity.
|
|
58
|
-
*
|
|
59
|
-
* @param issues - Array of issues
|
|
60
|
-
* @returns Summary string like "3 critical, 5 serious, 12 minor issues"
|
|
61
44
|
*/
|
|
62
45
|
export declare function formatIssueSummary(issues: Issue[]): string;
|
|
63
46
|
//# sourceMappingURL=table.d.ts.map
|
package/dist/ui/table.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../src/ui/table.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../src/ui/table.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAeH,MAAM,WAAW,KAAK;IACpB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,2CAA2C;IAC3C,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,wCAAwC;IACxC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,0CAA0C;IAC1C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,0CAA0C;IAC1C,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAaD;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CASrE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CASrE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,KAAK,EAAE,EACf,OAAO,GAAE,kBAAuB,GAC/B,MAAM,CAuCR;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,MAAM,CA2BlF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CA4B1D"}
|
package/dist/ui/table.js
CHANGED
|
@@ -1,71 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Table formatting utilities for CLI output.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Delegates to @vertaaux/tui for consistent rendering with severity-based coloring.
|
|
5
5
|
* Respects terminal width and provides truncation for long content.
|
|
6
6
|
*/
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import { shouldUseColor, getTerminalWidth } from "../utils/detect-env.js";
|
|
10
|
-
// Severity colors matching brand palette
|
|
11
|
-
const SEVERITY_COLORS = {
|
|
12
|
-
critical: "#FF6B6B", // Red
|
|
13
|
-
error: "#FF6B6B", // Red (alias)
|
|
14
|
-
serious: "#FFD93D", // Yellow
|
|
15
|
-
warning: "#FFD93D", // Yellow (alias)
|
|
16
|
-
minor: "#6BCEFF", // Cyan
|
|
17
|
-
moderate: "#6BCEFF", // Cyan (alias)
|
|
18
|
-
info: "#888888", // Dim gray
|
|
19
|
-
};
|
|
20
|
-
// Severity display labels
|
|
21
|
-
const SEVERITY_LABELS = {
|
|
22
|
-
critical: "CRITICAL",
|
|
23
|
-
error: "ERROR",
|
|
24
|
-
serious: "SERIOUS",
|
|
25
|
-
warning: "WARNING",
|
|
26
|
-
minor: "MINOR",
|
|
27
|
-
moderate: "MODERATE",
|
|
28
|
-
info: "INFO",
|
|
29
|
-
};
|
|
30
|
-
// Severity sort order (highest first)
|
|
31
|
-
const SEVERITY_ORDER = {
|
|
32
|
-
critical: 0,
|
|
33
|
-
error: 1,
|
|
34
|
-
serious: 2,
|
|
35
|
-
warning: 3,
|
|
36
|
-
minor: 4,
|
|
37
|
-
moderate: 5,
|
|
38
|
-
info: 6,
|
|
39
|
-
};
|
|
40
|
-
/**
|
|
41
|
-
* Truncate text to fit within max width, adding ellipsis if truncated.
|
|
42
|
-
*/
|
|
43
|
-
function truncate(text, maxWidth) {
|
|
44
|
-
if (!text)
|
|
45
|
-
return "";
|
|
46
|
-
if (text.length <= maxWidth)
|
|
47
|
-
return text;
|
|
48
|
-
return text.slice(0, maxWidth - 3) + "...";
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Get colored severity label.
|
|
52
|
-
*/
|
|
53
|
-
function colorSeverity(severity) {
|
|
54
|
-
const normalized = severity.toLowerCase();
|
|
55
|
-
const label = SEVERITY_LABELS[normalized] || severity.toUpperCase();
|
|
56
|
-
if (!shouldUseColor()) {
|
|
57
|
-
return label;
|
|
58
|
-
}
|
|
59
|
-
const color = SEVERITY_COLORS[normalized] || "#888888";
|
|
60
|
-
return chalk.hex(color).bold(label);
|
|
61
|
-
}
|
|
7
|
+
import { renderTable, text, } from "@vertaaux/tui";
|
|
8
|
+
import { severityOrder, isColorEnabled, colorize, severity as severityPalette, tokens, } from "@vertaaux/tui";
|
|
62
9
|
/**
|
|
63
10
|
* Sort issues by severity (highest first).
|
|
64
11
|
*/
|
|
65
12
|
function sortBySeverity(issues) {
|
|
66
13
|
return [...issues].sort((a, b) => {
|
|
67
|
-
const orderA =
|
|
68
|
-
const orderB =
|
|
14
|
+
const orderA = severityOrder[a.severity?.toLowerCase() || "info"] ?? 6;
|
|
15
|
+
const orderB = severityOrder[b.severity?.toLowerCase() || "info"] ?? 6;
|
|
69
16
|
return orderA - orderB;
|
|
70
17
|
});
|
|
71
18
|
}
|
|
@@ -75,10 +22,10 @@ function sortBySeverity(issues) {
|
|
|
75
22
|
export function groupBySeverity(issues) {
|
|
76
23
|
const groups = new Map();
|
|
77
24
|
for (const issue of issues) {
|
|
78
|
-
const
|
|
79
|
-
const group = groups.get(
|
|
25
|
+
const sev = issue.severity?.toLowerCase() || "info";
|
|
26
|
+
const group = groups.get(sev) || [];
|
|
80
27
|
group.push(issue);
|
|
81
|
-
groups.set(
|
|
28
|
+
groups.set(sev, group);
|
|
82
29
|
}
|
|
83
30
|
return groups;
|
|
84
31
|
}
|
|
@@ -88,149 +35,95 @@ export function groupBySeverity(issues) {
|
|
|
88
35
|
export function groupByCategory(issues) {
|
|
89
36
|
const groups = new Map();
|
|
90
37
|
for (const issue of issues) {
|
|
91
|
-
const
|
|
92
|
-
const group = groups.get(
|
|
38
|
+
const cat = issue.category || "Uncategorized";
|
|
39
|
+
const group = groups.get(cat) || [];
|
|
93
40
|
group.push(issue);
|
|
94
|
-
groups.set(
|
|
41
|
+
groups.set(cat, group);
|
|
95
42
|
}
|
|
96
43
|
return groups;
|
|
97
44
|
}
|
|
98
45
|
/**
|
|
99
46
|
* Format issues into a table string.
|
|
100
|
-
*
|
|
101
|
-
* Columns: Severity | ID | Description | Selector (optional)
|
|
102
|
-
* Issues are sorted by severity (critical -> info).
|
|
103
|
-
*
|
|
104
|
-
* @param issues - Array of issues to format
|
|
105
|
-
* @param options - Formatting options
|
|
106
|
-
* @returns Formatted table string
|
|
107
47
|
*/
|
|
108
48
|
export function formatIssuesTable(issues, options = {}) {
|
|
109
49
|
if (!issues.length) {
|
|
110
|
-
return
|
|
111
|
-
?
|
|
50
|
+
return isColorEnabled()
|
|
51
|
+
? text.success("No issues found.")
|
|
112
52
|
: "No issues found.";
|
|
113
53
|
}
|
|
114
|
-
const
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const colWidths = [severityWidth, idWidth, maxDescriptionWidth];
|
|
54
|
+
const { maxDescriptionWidth = 50, maxSelectorWidth = 30, showSelector = true, showCategory = false, } = options;
|
|
55
|
+
const sorted = sortBySeverity(issues);
|
|
56
|
+
const columns = [
|
|
57
|
+
{ key: "severity", label: "Severity", width: 10, color: (val) => text.severityBadge(val) },
|
|
58
|
+
{ key: "id", label: "ID", width: 20 },
|
|
59
|
+
{ key: "description", label: "Description", width: maxDescriptionWidth },
|
|
60
|
+
];
|
|
122
61
|
if (showCategory) {
|
|
123
|
-
|
|
124
|
-
colWidths.push(15);
|
|
62
|
+
columns.push({ key: "category", label: "Category", width: 15 });
|
|
125
63
|
}
|
|
126
64
|
if (showSelector) {
|
|
127
|
-
|
|
128
|
-
colWidths.push(maxSelectorWidth);
|
|
65
|
+
columns.push({ key: "selector", label: "Selector", width: maxSelectorWidth });
|
|
129
66
|
}
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
border: useColor ? ["dim"] : [],
|
|
139
|
-
},
|
|
140
|
-
wordWrap: true,
|
|
141
|
-
});
|
|
142
|
-
// Sort and add rows
|
|
143
|
-
const sortedIssues = sortBySeverity(issues);
|
|
144
|
-
for (const issue of sortedIssues) {
|
|
145
|
-
const row = [
|
|
146
|
-
colorSeverity(issue.severity || "info"),
|
|
147
|
-
truncate(issue.id || "-", idWidth - 2),
|
|
148
|
-
truncate(issue.description || issue.title || "-", maxDescriptionWidth - 2),
|
|
149
|
-
];
|
|
150
|
-
if (showCategory) {
|
|
151
|
-
row.push(truncate(issue.category || "-", 13));
|
|
152
|
-
}
|
|
153
|
-
if (showSelector) {
|
|
154
|
-
row.push(truncate(issue.selector || "-", maxSelectorWidth - 2));
|
|
155
|
-
}
|
|
156
|
-
table.push(row);
|
|
157
|
-
}
|
|
158
|
-
return table.toString();
|
|
67
|
+
const rows = sorted.map((issue) => ({
|
|
68
|
+
severity: issue.severity?.toLowerCase() || "info",
|
|
69
|
+
id: issue.id || "-",
|
|
70
|
+
description: issue.description || issue.title || "-",
|
|
71
|
+
category: issue.category || "-",
|
|
72
|
+
selector: issue.selector || "-",
|
|
73
|
+
}));
|
|
74
|
+
return renderTable(rows, columns);
|
|
159
75
|
}
|
|
160
76
|
/**
|
|
161
77
|
* Format scores into a table string.
|
|
162
|
-
*
|
|
163
|
-
* @param scores - Object mapping category names to scores
|
|
164
|
-
* @returns Formatted table string
|
|
165
78
|
*/
|
|
166
79
|
export function formatScoresTable(scores) {
|
|
167
80
|
const entries = Object.entries(scores).filter(([, value]) => typeof value === "number");
|
|
168
81
|
if (!entries.length) {
|
|
169
|
-
return
|
|
170
|
-
?
|
|
82
|
+
return isColorEnabled()
|
|
83
|
+
? text.dim("No scores available.")
|
|
171
84
|
: "No scores available.";
|
|
172
85
|
}
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
:
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
head: useColor ? ["cyan"] : [],
|
|
181
|
-
border: useColor ? ["dim"] : [],
|
|
86
|
+
const columns = [
|
|
87
|
+
{ key: "category", label: "Category", width: 20 },
|
|
88
|
+
{
|
|
89
|
+
key: "score",
|
|
90
|
+
label: "Score",
|
|
91
|
+
width: 10,
|
|
92
|
+
color: (val) => text.scoreBadge(Number(val)),
|
|
182
93
|
},
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
scoreStr = chalk.green.bold(scoreStr);
|
|
190
|
-
}
|
|
191
|
-
else if (numScore >= 70) {
|
|
192
|
-
scoreStr = chalk.yellow(scoreStr);
|
|
193
|
-
}
|
|
194
|
-
else {
|
|
195
|
-
scoreStr = chalk.red(scoreStr);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
table.push([category, scoreStr]);
|
|
199
|
-
}
|
|
200
|
-
return table.toString();
|
|
94
|
+
];
|
|
95
|
+
const rows = entries.map(([category, score]) => ({
|
|
96
|
+
category,
|
|
97
|
+
score: String(score),
|
|
98
|
+
}));
|
|
99
|
+
return renderTable(rows, columns);
|
|
201
100
|
}
|
|
202
101
|
/**
|
|
203
102
|
* Format a summary line showing issue counts by severity.
|
|
204
|
-
*
|
|
205
|
-
* @param issues - Array of issues
|
|
206
|
-
* @returns Summary string like "3 critical, 5 serious, 12 minor issues"
|
|
207
103
|
*/
|
|
208
104
|
export function formatIssueSummary(issues) {
|
|
209
105
|
const counts = {};
|
|
210
106
|
for (const issue of issues) {
|
|
211
|
-
const
|
|
212
|
-
counts[
|
|
107
|
+
const sev = issue.severity?.toLowerCase() || "info";
|
|
108
|
+
counts[sev] = (counts[sev] || 0) + 1;
|
|
213
109
|
}
|
|
214
|
-
const useColor = shouldUseColor();
|
|
215
|
-
const parts = [];
|
|
216
|
-
// Order: critical, serious, minor, info
|
|
217
110
|
const order = ["critical", "error", "serious", "warning", "minor", "moderate", "info"];
|
|
218
|
-
|
|
219
|
-
|
|
111
|
+
const parts = [];
|
|
112
|
+
for (const sev of order) {
|
|
113
|
+
const count = counts[sev];
|
|
220
114
|
if (count) {
|
|
221
|
-
const label = count
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
parts.push(chalk.hex(color)(text));
|
|
115
|
+
const label = `${count} ${sev}`;
|
|
116
|
+
if (isColorEnabled()) {
|
|
117
|
+
const hex = severityPalette[sev] || tokens.muted;
|
|
118
|
+
parts.push(colorize(label, hex));
|
|
226
119
|
}
|
|
227
120
|
else {
|
|
228
|
-
parts.push(
|
|
121
|
+
parts.push(label);
|
|
229
122
|
}
|
|
230
123
|
}
|
|
231
124
|
}
|
|
232
125
|
if (!parts.length) {
|
|
233
|
-
return
|
|
126
|
+
return isColorEnabled() ? text.success("No issues") : "No issues";
|
|
234
127
|
}
|
|
235
128
|
return parts.join(", ") + " issues";
|
|
236
129
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized AI error classification and formatting for CLI commands.
|
|
3
|
+
*
|
|
4
|
+
* Provides consistent error handling across all 8 AI-powered commands.
|
|
5
|
+
* Classifies errors into distinct types (timeout, unreachable, auth, etc.)
|
|
6
|
+
* and formats user-friendly messages with actionable suggestions.
|
|
7
|
+
*/
|
|
8
|
+
import { type SpinnerInstance } from "../ui/spinner.js";
|
|
9
|
+
/** Default timeout for LLM API requests (30 seconds). */
|
|
10
|
+
export declare const AI_TIMEOUT_MS = 30000;
|
|
11
|
+
/**
|
|
12
|
+
* Classification of AI/LLM errors.
|
|
13
|
+
*
|
|
14
|
+
* Each kind maps to a distinct user-facing message with tailored suggestions.
|
|
15
|
+
*/
|
|
16
|
+
export type AiErrorKind = "timeout" | "unreachable" | "auth" | "invalid_response" | "rate_limit" | "server_error" | "unknown";
|
|
17
|
+
/**
|
|
18
|
+
* Classify an unknown error into a specific AI error kind.
|
|
19
|
+
*
|
|
20
|
+
* Inspects error properties (name, code, message, status) to determine
|
|
21
|
+
* the most specific classification. Falls back to `"unknown"` when no
|
|
22
|
+
* pattern matches.
|
|
23
|
+
*
|
|
24
|
+
* @param error - The caught error (any type)
|
|
25
|
+
* @returns The classified error kind
|
|
26
|
+
*/
|
|
27
|
+
export declare function classifyAiError(error: unknown): AiErrorKind;
|
|
28
|
+
/**
|
|
29
|
+
* Format an AI error kind into a user-friendly message with suggestions.
|
|
30
|
+
*
|
|
31
|
+
* @param kind - The classified error kind
|
|
32
|
+
* @param command - The CLI command name (e.g., "explain", "triage")
|
|
33
|
+
* @returns Multi-line string with error description and actionable suggestions
|
|
34
|
+
*/
|
|
35
|
+
export declare function formatAiError(kind: AiErrorKind, command: string): string;
|
|
36
|
+
/**
|
|
37
|
+
* Handle an AI command error: classify, format, display, and exit.
|
|
38
|
+
*
|
|
39
|
+
* This is the primary entry point for error handling in AI commands.
|
|
40
|
+
* It classifies the error, fails the spinner with a summary, writes
|
|
41
|
+
* the full formatted message to stderr, and exits with ExitCode.ERROR.
|
|
42
|
+
*
|
|
43
|
+
* @param error - The caught error
|
|
44
|
+
* @param command - The CLI command name (e.g., "explain", "triage")
|
|
45
|
+
* @param spinner - Active spinner instance to fail
|
|
46
|
+
*/
|
|
47
|
+
export declare function handleAiCommandError(error: unknown, command: string, spinner: SpinnerInstance): never;
|
|
48
|
+
//# sourceMappingURL=ai-error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-error.d.ts","sourceRoot":"","sources":["../../src/utils/ai-error.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAe,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAMrE,yDAAyD;AACzD,eAAO,MAAM,aAAa,QAAS,CAAC;AAMpC;;;;GAIG;AACH,MAAM,MAAM,WAAW,GACnB,SAAS,GACT,aAAa,GACb,MAAM,GACN,kBAAkB,GAClB,YAAY,GACZ,cAAc,GACd,SAAS,CAAC;AAMd;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAoF3D;AAeD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CA2DxE;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,eAAe,GACvB,KAAK,CAQP"}
|