bktide 1.0.1755266193 → 1.0.1755547716
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/README.md +107 -1
- package/WORKFLOW_README.md +1 -1
- package/completions/bktide-dynamic.fish +171 -0
- package/completions/bktide.bash +124 -0
- package/completions/bktide.fish +107 -0
- package/completions/bktide.zsh +139 -0
- package/dist/commands/BaseCommand.js +7 -7
- package/dist/commands/BaseCommand.js.map +1 -1
- package/dist/commands/GenerateCompletions.js +238 -0
- package/dist/commands/GenerateCompletions.js.map +1 -0
- package/dist/commands/ListAnnotations.js +7 -0
- package/dist/commands/ListAnnotations.js.map +1 -1
- package/dist/commands/ListBuilds.js +67 -3
- package/dist/commands/ListBuilds.js.map +1 -1
- package/dist/commands/ListOrganizations.js +6 -0
- package/dist/commands/ListOrganizations.js.map +1 -1
- package/dist/commands/ListPipelines.js +87 -12
- package/dist/commands/ListPipelines.js.map +1 -1
- package/dist/commands/ManageToken.js +32 -9
- package/dist/commands/ManageToken.js.map +1 -1
- package/dist/commands/ShowViewer.js +7 -1
- package/dist/commands/ShowViewer.js.map +1 -1
- package/dist/commands/index.js +1 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/formatters/annotations/PlainTextFormatter.js +37 -9
- package/dist/formatters/annotations/PlainTextFormatter.js.map +1 -1
- package/dist/formatters/builds/PlainTextFormatter.js +82 -60
- package/dist/formatters/builds/PlainTextFormatter.js.map +1 -1
- package/dist/formatters/errors/AlfredFormatter.js +20 -0
- package/dist/formatters/errors/AlfredFormatter.js.map +1 -1
- package/dist/formatters/errors/PlainTextFormatter.js +121 -23
- package/dist/formatters/errors/PlainTextFormatter.js.map +1 -1
- package/dist/formatters/organizations/PlainTextFormatter.js +37 -6
- package/dist/formatters/organizations/PlainTextFormatter.js.map +1 -1
- package/dist/formatters/pipelines/AlfredFormatter.js.map +1 -1
- package/dist/formatters/pipelines/Formatter.js.map +1 -1
- package/dist/formatters/pipelines/JsonFormatter.js.map +1 -1
- package/dist/formatters/pipelines/PlainTextFormatter.js +165 -19
- package/dist/formatters/pipelines/PlainTextFormatter.js.map +1 -1
- package/dist/formatters/token/AlfredFormatter.js +15 -2
- package/dist/formatters/token/AlfredFormatter.js.map +1 -1
- package/dist/formatters/token/PlainTextFormatter.js +56 -18
- package/dist/formatters/token/PlainTextFormatter.js.map +1 -1
- package/dist/formatters/viewer/PlainTextFormatter.js +8 -7
- package/dist/formatters/viewer/PlainTextFormatter.js.map +1 -1
- package/dist/index.js +47 -6
- package/dist/index.js.map +1 -1
- package/dist/services/CredentialManager.js +80 -10
- package/dist/services/CredentialManager.js.map +1 -1
- package/dist/ui/help.js +69 -0
- package/dist/ui/help.js.map +1 -0
- package/dist/ui/progress.js +356 -0
- package/dist/ui/progress.js.map +1 -0
- package/dist/ui/reporter.js +111 -0
- package/dist/ui/reporter.js.map +1 -0
- package/dist/ui/responsive-table.js +183 -0
- package/dist/ui/responsive-table.js.map +1 -0
- package/dist/ui/spinner.js +20 -0
- package/dist/ui/spinner.js.map +1 -0
- package/dist/ui/symbols.js +46 -0
- package/dist/ui/symbols.js.map +1 -0
- package/dist/ui/table.js +32 -0
- package/dist/ui/table.js.map +1 -0
- package/dist/ui/theme.js +280 -0
- package/dist/ui/theme.js.map +1 -0
- package/dist/ui/width.js +111 -0
- package/dist/ui/width.js.map +1 -0
- package/dist/utils/alfred.js +6 -0
- package/dist/utils/alfred.js.map +1 -0
- package/dist/utils/cli-error-handler.js +35 -20
- package/dist/utils/cli-error-handler.js.map +1 -1
- package/dist/utils/pagination.js +92 -0
- package/dist/utils/pagination.js.map +1 -0
- package/info.plist +51 -218
- package/package.json +23 -5
package/dist/ui/theme.js
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enhanced Visual Design System for bktide CLI
|
|
3
|
+
*
|
|
4
|
+
* This module implements a comprehensive color and typography system
|
|
5
|
+
* that enhances information hierarchy and accessibility.
|
|
6
|
+
*/
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import { getSymbols } from './symbols.js';
|
|
9
|
+
function isTTY() {
|
|
10
|
+
return Boolean(process.stdout.isTTY);
|
|
11
|
+
}
|
|
12
|
+
function colorEnabled() {
|
|
13
|
+
if (process.env.NO_COLOR)
|
|
14
|
+
return false;
|
|
15
|
+
const mode = process.env.BKTIDE_COLOR_MODE || 'auto';
|
|
16
|
+
if (mode === 'never')
|
|
17
|
+
return false;
|
|
18
|
+
if (mode === 'always')
|
|
19
|
+
return true;
|
|
20
|
+
return isTTY();
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Semantic color system for different information types
|
|
24
|
+
* Using colorblind-safe palette
|
|
25
|
+
*/
|
|
26
|
+
export const SEMANTIC_COLORS = {
|
|
27
|
+
// Status colors (colorblind-safe)
|
|
28
|
+
success: (s) => colorEnabled() ? chalk.blue(s) : s,
|
|
29
|
+
error: (s) => colorEnabled() ? chalk.rgb(255, 140, 0)(s) : s,
|
|
30
|
+
warning: (s) => colorEnabled() ? chalk.yellow(s) : s,
|
|
31
|
+
info: (s) => colorEnabled() ? chalk.cyan(s) : s,
|
|
32
|
+
// Typography emphasis levels
|
|
33
|
+
heading: (s) => colorEnabled() ? chalk.bold.underline(s) : `== ${s} ==`,
|
|
34
|
+
subheading: (s) => colorEnabled() ? chalk.bold(s) : `** ${s} **`,
|
|
35
|
+
label: (s) => colorEnabled() ? chalk.bold(s) : s.toUpperCase(),
|
|
36
|
+
// Data type highlighting
|
|
37
|
+
identifier: (s) => colorEnabled() ? chalk.cyan(s) : s,
|
|
38
|
+
count: (s) => colorEnabled() ? chalk.magenta(s) : s,
|
|
39
|
+
url: (s) => colorEnabled() ? chalk.underline.cyan(s) : `<${s}>`,
|
|
40
|
+
// De-emphasis (auxiliary information)
|
|
41
|
+
dim: (s) => colorEnabled() ? chalk.dim(s) : s,
|
|
42
|
+
muted: (s) => colorEnabled() ? chalk.gray(s) : s,
|
|
43
|
+
tip: (s) => colorEnabled() ? chalk.dim(s) : `(${s})`,
|
|
44
|
+
help: (s) => colorEnabled() ? chalk.dim.italic(s) : `[${s}]`,
|
|
45
|
+
// Special formatting
|
|
46
|
+
highlight: (s) => colorEnabled() ? chalk.magenta(s) : s,
|
|
47
|
+
code: (s) => colorEnabled() ? chalk.bgGray.white(` ${s} `) : `\`${s}\``,
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Build status specific theming
|
|
51
|
+
* Matches conventions from GitHub Actions, CircleCI, Jenkins
|
|
52
|
+
*/
|
|
53
|
+
export const BUILD_STATUS_THEME = {
|
|
54
|
+
// Success states
|
|
55
|
+
PASSED: {
|
|
56
|
+
color: SEMANTIC_COLORS.success,
|
|
57
|
+
symbol: '✓',
|
|
58
|
+
ascii: '[OK]',
|
|
59
|
+
},
|
|
60
|
+
// Failure states
|
|
61
|
+
FAILED: {
|
|
62
|
+
color: SEMANTIC_COLORS.error,
|
|
63
|
+
symbol: '✖',
|
|
64
|
+
ascii: '[FAIL]',
|
|
65
|
+
},
|
|
66
|
+
FAILING: {
|
|
67
|
+
color: (s) => colorEnabled() ? chalk.rgb(255, 165, 0)(s) : s,
|
|
68
|
+
symbol: '⚠',
|
|
69
|
+
ascii: '[FAILING]',
|
|
70
|
+
},
|
|
71
|
+
// Warning states
|
|
72
|
+
BLOCKED: {
|
|
73
|
+
color: SEMANTIC_COLORS.warning,
|
|
74
|
+
symbol: '⚠',
|
|
75
|
+
ascii: '[BLOCKED]',
|
|
76
|
+
},
|
|
77
|
+
CANCELED: {
|
|
78
|
+
color: SEMANTIC_COLORS.warning,
|
|
79
|
+
symbol: '⊘',
|
|
80
|
+
ascii: '[CANCEL]',
|
|
81
|
+
},
|
|
82
|
+
CANCELING: {
|
|
83
|
+
color: SEMANTIC_COLORS.warning,
|
|
84
|
+
symbol: '⊘',
|
|
85
|
+
ascii: '[...]',
|
|
86
|
+
},
|
|
87
|
+
// Active states
|
|
88
|
+
RUNNING: {
|
|
89
|
+
color: SEMANTIC_COLORS.info,
|
|
90
|
+
symbol: '↻',
|
|
91
|
+
ascii: '[RUN]',
|
|
92
|
+
},
|
|
93
|
+
SCHEDULED: {
|
|
94
|
+
color: SEMANTIC_COLORS.info,
|
|
95
|
+
symbol: '⏱',
|
|
96
|
+
ascii: '[QUEUE]',
|
|
97
|
+
},
|
|
98
|
+
// Inactive states
|
|
99
|
+
SKIPPED: {
|
|
100
|
+
color: SEMANTIC_COLORS.muted,
|
|
101
|
+
symbol: '−',
|
|
102
|
+
ascii: '[SKIP]',
|
|
103
|
+
},
|
|
104
|
+
NOT_RUN: {
|
|
105
|
+
color: SEMANTIC_COLORS.muted,
|
|
106
|
+
symbol: '○',
|
|
107
|
+
ascii: '[--]',
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Format a build status with appropriate color and symbol
|
|
112
|
+
*/
|
|
113
|
+
export function formatBuildStatus(status, options) {
|
|
114
|
+
// Normalize status to uppercase for theme lookup
|
|
115
|
+
const normalizedStatus = status.toUpperCase();
|
|
116
|
+
const theme = BUILD_STATUS_THEME[normalizedStatus];
|
|
117
|
+
if (!theme) {
|
|
118
|
+
return SEMANTIC_COLORS.muted(status);
|
|
119
|
+
}
|
|
120
|
+
const useSymbol = options?.useSymbol ?? true;
|
|
121
|
+
const ascii = options?.ascii ?? false;
|
|
122
|
+
if (useSymbol) {
|
|
123
|
+
const symbol = ascii ? theme.ascii : theme.symbol;
|
|
124
|
+
// Keep original casing for display
|
|
125
|
+
return `${symbol} ${theme.color(status)}`;
|
|
126
|
+
}
|
|
127
|
+
// Keep original casing for display
|
|
128
|
+
return theme.color(status);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Tip display styles for different contexts
|
|
132
|
+
*/
|
|
133
|
+
export var TipStyle;
|
|
134
|
+
(function (TipStyle) {
|
|
135
|
+
TipStyle["GROUPED"] = "grouped";
|
|
136
|
+
TipStyle["INDIVIDUAL"] = "individual";
|
|
137
|
+
TipStyle["ACTIONS"] = "actions";
|
|
138
|
+
TipStyle["FIXES"] = "fixes";
|
|
139
|
+
TipStyle["BOX"] = "box"; // Fancy box with arrows (wide terminals)
|
|
140
|
+
})(TipStyle || (TipStyle = {}));
|
|
141
|
+
/**
|
|
142
|
+
* Format tips with consistent styling based on context
|
|
143
|
+
*/
|
|
144
|
+
export function formatTips(tips, style = TipStyle.GROUPED) {
|
|
145
|
+
if (tips.length === 0)
|
|
146
|
+
return '';
|
|
147
|
+
switch (style) {
|
|
148
|
+
case TipStyle.GROUPED:
|
|
149
|
+
return formatGroupedTips(tips);
|
|
150
|
+
case TipStyle.INDIVIDUAL:
|
|
151
|
+
return formatIndividualTips(tips);
|
|
152
|
+
case TipStyle.ACTIONS:
|
|
153
|
+
return formatActionTips(tips);
|
|
154
|
+
case TipStyle.FIXES:
|
|
155
|
+
return formatFixTips(tips);
|
|
156
|
+
case TipStyle.BOX:
|
|
157
|
+
return formatTipBox(tips); // Use existing function
|
|
158
|
+
default:
|
|
159
|
+
return formatGroupedTips(tips);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function formatGroupedTips(tips) {
|
|
163
|
+
const lines = [];
|
|
164
|
+
lines.push(SEMANTIC_COLORS.dim('Tips:'));
|
|
165
|
+
tips.forEach(tip => {
|
|
166
|
+
lines.push(SEMANTIC_COLORS.dim(` → ${tip}`));
|
|
167
|
+
});
|
|
168
|
+
return lines.join('\n');
|
|
169
|
+
}
|
|
170
|
+
function formatIndividualTips(tips) {
|
|
171
|
+
return tips
|
|
172
|
+
.map(tip => SEMANTIC_COLORS.dim(`→ ${tip}`))
|
|
173
|
+
.join('\n');
|
|
174
|
+
}
|
|
175
|
+
function formatActionTips(tips) {
|
|
176
|
+
const lines = [];
|
|
177
|
+
lines.push(SEMANTIC_COLORS.dim('Next steps:'));
|
|
178
|
+
tips.forEach(tip => {
|
|
179
|
+
lines.push(SEMANTIC_COLORS.dim(` → ${tip}`));
|
|
180
|
+
});
|
|
181
|
+
return lines.join('\n');
|
|
182
|
+
}
|
|
183
|
+
function formatFixTips(tips) {
|
|
184
|
+
const lines = [];
|
|
185
|
+
lines.push(SEMANTIC_COLORS.subheading('To fix this:'));
|
|
186
|
+
tips.forEach((tip, i) => {
|
|
187
|
+
lines.push(` ${i + 1}. ${tip}`);
|
|
188
|
+
});
|
|
189
|
+
return lines.join('\n');
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Create a formatted tip box for better visual separation
|
|
193
|
+
* Only used in wide terminals
|
|
194
|
+
*/
|
|
195
|
+
export function formatTipBox(tips, width) {
|
|
196
|
+
const termWidth = width || process.stdout.columns || 80;
|
|
197
|
+
// Only use fancy box in wide terminals
|
|
198
|
+
if (termWidth < 80 || !colorEnabled()) {
|
|
199
|
+
return formatGroupedTips(tips);
|
|
200
|
+
}
|
|
201
|
+
const lines = [];
|
|
202
|
+
const boxWidth = Math.min(termWidth - 4, 60);
|
|
203
|
+
const border = '─'.repeat(boxWidth - 10);
|
|
204
|
+
lines.push(SEMANTIC_COLORS.dim(`┌─ Tips ${border}`));
|
|
205
|
+
tips.forEach(tip => {
|
|
206
|
+
lines.push(SEMANTIC_COLORS.dim(`│ → ${tip}`));
|
|
207
|
+
});
|
|
208
|
+
lines.push(SEMANTIC_COLORS.dim(`└${'─'.repeat(boxWidth - 1)}`));
|
|
209
|
+
return lines.join('\n');
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Format an error message with consistent styling
|
|
213
|
+
*/
|
|
214
|
+
export function formatError(error, options) {
|
|
215
|
+
const lines = [];
|
|
216
|
+
const symbols = getSymbols();
|
|
217
|
+
// Error header
|
|
218
|
+
lines.push(`${SEMANTIC_COLORS.error(symbols.error)} ${chalk.bold('Error')}`);
|
|
219
|
+
lines.push('');
|
|
220
|
+
// Error message
|
|
221
|
+
const message = typeof error === 'string' ? error : error.message;
|
|
222
|
+
lines.push(message);
|
|
223
|
+
// Suggestions if provided
|
|
224
|
+
if (options?.suggestions && options.suggestions.length > 0) {
|
|
225
|
+
lines.push('');
|
|
226
|
+
lines.push(formatTips(options.suggestions, TipStyle.FIXES));
|
|
227
|
+
}
|
|
228
|
+
// Help command
|
|
229
|
+
if (options?.showHelp && options?.helpCommand) {
|
|
230
|
+
lines.push('');
|
|
231
|
+
lines.push(SEMANTIC_COLORS.help(`Need help? Run: ${options.helpCommand}`));
|
|
232
|
+
}
|
|
233
|
+
return lines.join('\n');
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Format a success message (subtle, not redundant)
|
|
237
|
+
*/
|
|
238
|
+
export function formatSuccess(message, count) {
|
|
239
|
+
const symbols = getSymbols();
|
|
240
|
+
if (count !== undefined) {
|
|
241
|
+
return `${SEMANTIC_COLORS.success(symbols.success)} ${message} ${SEMANTIC_COLORS.count(count.toString())}`;
|
|
242
|
+
}
|
|
243
|
+
return `${SEMANTIC_COLORS.success(symbols.success)} ${message}`;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Format empty state messages
|
|
247
|
+
*/
|
|
248
|
+
export function formatEmptyState(message, suggestions) {
|
|
249
|
+
const lines = [];
|
|
250
|
+
lines.push(SEMANTIC_COLORS.dim(message));
|
|
251
|
+
if (suggestions && suggestions.length > 0) {
|
|
252
|
+
lines.push('');
|
|
253
|
+
suggestions.forEach(s => {
|
|
254
|
+
// Make commands stand out from the dimmed text
|
|
255
|
+
const formatted = s.replace(/--\w+[^ ]*/g, match => chalk.reset(match));
|
|
256
|
+
lines.push(SEMANTIC_COLORS.dim(formatted));
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
return lines.join('\n');
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Legacy color exports for backward compatibility
|
|
263
|
+
* @deprecated Use SEMANTIC_COLORS instead
|
|
264
|
+
*/
|
|
265
|
+
export const COLORS = {
|
|
266
|
+
error: SEMANTIC_COLORS.error,
|
|
267
|
+
warn: SEMANTIC_COLORS.warning,
|
|
268
|
+
success: SEMANTIC_COLORS.success,
|
|
269
|
+
info: SEMANTIC_COLORS.info,
|
|
270
|
+
muted: SEMANTIC_COLORS.muted,
|
|
271
|
+
highlight: SEMANTIC_COLORS.highlight,
|
|
272
|
+
dim: SEMANTIC_COLORS.dim,
|
|
273
|
+
};
|
|
274
|
+
// Export symbols from the symbols module
|
|
275
|
+
export const SYMBOLS = getSymbols();
|
|
276
|
+
export function shouldDecorate(format) {
|
|
277
|
+
const f = (format || '').toLowerCase();
|
|
278
|
+
return f !== 'json' && f !== 'alfred' && colorEnabled();
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=theme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.js","sourceRoot":"/","sources":["ui/theme.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Enhanced Visual Design System for bktide CLI\n * \n * This module implements a comprehensive color and typography system\n * that enhances information hierarchy and accessibility.\n */\nimport chalk from 'chalk';\nimport { getSymbols } from './symbols.js';\n\nfunction isTTY(): boolean {\n return Boolean(process.stdout.isTTY);\n}\n\nfunction colorEnabled(): boolean {\n if (process.env.NO_COLOR) return false;\n const mode = process.env.BKTIDE_COLOR_MODE || 'auto';\n if (mode === 'never') return false;\n if (mode === 'always') return true;\n return isTTY();\n}\n\n/**\n * Semantic color system for different information types\n * Using colorblind-safe palette\n */\nexport const SEMANTIC_COLORS = {\n // Status colors (colorblind-safe)\n success: (s: string) => colorEnabled() ? chalk.blue(s) : s,\n error: (s: string) => colorEnabled() ? chalk.rgb(255, 140, 0)(s) : s,\n warning: (s: string) => colorEnabled() ? chalk.yellow(s) : s,\n info: (s: string) => colorEnabled() ? chalk.cyan(s) : s,\n \n // Typography emphasis levels\n heading: (s: string) => colorEnabled() ? chalk.bold.underline(s) : `== ${s} ==`,\n subheading: (s: string) => colorEnabled() ? chalk.bold(s) : `** ${s} **`,\n label: (s: string) => colorEnabled() ? chalk.bold(s) : s.toUpperCase(),\n \n // Data type highlighting\n identifier: (s: string) => colorEnabled() ? chalk.cyan(s) : s,\n count: (s: string) => colorEnabled() ? chalk.magenta(s) : s,\n url: (s: string) => colorEnabled() ? chalk.underline.cyan(s) : `<${s}>`,\n \n // De-emphasis (auxiliary information)\n dim: (s: string) => colorEnabled() ? chalk.dim(s) : s,\n muted: (s: string) => colorEnabled() ? chalk.gray(s) : s,\n tip: (s: string) => colorEnabled() ? chalk.dim(s) : `(${s})`,\n help: (s: string) => colorEnabled() ? chalk.dim.italic(s) : `[${s}]`,\n \n // Special formatting\n highlight: (s: string) => colorEnabled() ? chalk.magenta(s) : s,\n code: (s: string) => colorEnabled() ? chalk.bgGray.white(` ${s} `) : `\\`${s}\\``,\n};\n\n/**\n * Build status specific theming\n * Matches conventions from GitHub Actions, CircleCI, Jenkins\n */\nexport const BUILD_STATUS_THEME = {\n // Success states\n PASSED: {\n color: SEMANTIC_COLORS.success,\n symbol: '✓',\n ascii: '[OK]',\n },\n \n // Failure states\n FAILED: {\n color: SEMANTIC_COLORS.error,\n symbol: '✖',\n ascii: '[FAIL]',\n },\n FAILING: {\n color: (s: string) => colorEnabled() ? chalk.rgb(255, 165, 0)(s) : s,\n symbol: '⚠',\n ascii: '[FAILING]',\n },\n \n // Warning states\n BLOCKED: {\n color: SEMANTIC_COLORS.warning,\n symbol: '⚠',\n ascii: '[BLOCKED]',\n },\n CANCELED: {\n color: SEMANTIC_COLORS.warning,\n symbol: '⊘',\n ascii: '[CANCEL]',\n },\n CANCELING: {\n color: SEMANTIC_COLORS.warning,\n symbol: '⊘',\n ascii: '[...]',\n },\n \n // Active states\n RUNNING: {\n color: SEMANTIC_COLORS.info,\n symbol: '↻',\n ascii: '[RUN]',\n },\n SCHEDULED: {\n color: SEMANTIC_COLORS.info,\n symbol: '⏱',\n ascii: '[QUEUE]',\n },\n \n // Inactive states\n SKIPPED: {\n color: SEMANTIC_COLORS.muted,\n symbol: '−',\n ascii: '[SKIP]',\n },\n NOT_RUN: {\n color: SEMANTIC_COLORS.muted,\n symbol: '○',\n ascii: '[--]',\n },\n};\n\n/**\n * Format a build status with appropriate color and symbol\n */\nexport function formatBuildStatus(\n status: string, \n options?: { useSymbol?: boolean; ascii?: boolean }\n): string {\n // Normalize status to uppercase for theme lookup\n const normalizedStatus = status.toUpperCase();\n const theme = BUILD_STATUS_THEME[normalizedStatus as keyof typeof BUILD_STATUS_THEME];\n if (!theme) {\n return SEMANTIC_COLORS.muted(status);\n }\n \n const useSymbol = options?.useSymbol ?? true;\n const ascii = options?.ascii ?? false;\n \n if (useSymbol) {\n const symbol = ascii ? theme.ascii : theme.symbol;\n // Keep original casing for display\n return `${symbol} ${theme.color(status)}`;\n }\n \n // Keep original casing for display\n return theme.color(status);\n}\n\n/**\n * Tip display styles for different contexts\n */\nexport enum TipStyle {\n GROUPED = 'grouped', // Tips: with arrows\n INDIVIDUAL = 'individual', // → Individual arrows\n ACTIONS = 'actions', // Next steps: with arrows\n FIXES = 'fixes', // To fix this: numbered\n BOX = 'box' // Fancy box with arrows (wide terminals)\n}\n\n/**\n * Format tips with consistent styling based on context\n */\nexport function formatTips(\n tips: string[], \n style: TipStyle = TipStyle.GROUPED\n): string {\n if (tips.length === 0) return '';\n \n switch (style) {\n case TipStyle.GROUPED:\n return formatGroupedTips(tips);\n case TipStyle.INDIVIDUAL:\n return formatIndividualTips(tips);\n case TipStyle.ACTIONS:\n return formatActionTips(tips);\n case TipStyle.FIXES:\n return formatFixTips(tips);\n case TipStyle.BOX:\n return formatTipBox(tips); // Use existing function\n default:\n return formatGroupedTips(tips);\n }\n}\n\nfunction formatGroupedTips(tips: string[]): string {\n const lines: string[] = [];\n lines.push(SEMANTIC_COLORS.dim('Tips:'));\n tips.forEach(tip => {\n lines.push(SEMANTIC_COLORS.dim(` → ${tip}`));\n });\n return lines.join('\\n');\n}\n\nfunction formatIndividualTips(tips: string[]): string {\n return tips\n .map(tip => SEMANTIC_COLORS.dim(`→ ${tip}`))\n .join('\\n');\n}\n\nfunction formatActionTips(tips: string[]): string {\n const lines: string[] = [];\n lines.push(SEMANTIC_COLORS.dim('Next steps:'));\n tips.forEach(tip => {\n lines.push(SEMANTIC_COLORS.dim(` → ${tip}`));\n });\n return lines.join('\\n');\n}\n\nfunction formatFixTips(tips: string[]): string {\n const lines: string[] = [];\n lines.push(SEMANTIC_COLORS.subheading('To fix this:'));\n tips.forEach((tip, i) => {\n lines.push(` ${i + 1}. ${tip}`);\n });\n return lines.join('\\n');\n}\n\n/**\n * Create a formatted tip box for better visual separation\n * Only used in wide terminals\n */\nexport function formatTipBox(tips: string[], width?: number): string {\n const termWidth = width || process.stdout.columns || 80;\n \n // Only use fancy box in wide terminals\n if (termWidth < 80 || !colorEnabled()) {\n return formatGroupedTips(tips);\n }\n \n const lines: string[] = [];\n const boxWidth = Math.min(termWidth - 4, 60);\n const border = '─'.repeat(boxWidth - 10);\n \n lines.push(SEMANTIC_COLORS.dim(`┌─ Tips ${border}`));\n tips.forEach(tip => {\n lines.push(SEMANTIC_COLORS.dim(`│ → ${tip}`));\n });\n lines.push(SEMANTIC_COLORS.dim(`└${'─'.repeat(boxWidth - 1)}`));\n \n return lines.join('\\n');\n}\n\n/**\n * Format an error message with consistent styling\n */\nexport function formatError(\n error: string | Error, \n options?: { \n showHelp?: boolean; \n helpCommand?: string;\n suggestions?: string[];\n }\n): string {\n const lines: string[] = [];\n const symbols = getSymbols();\n \n // Error header\n lines.push(`${SEMANTIC_COLORS.error(symbols.error)} ${chalk.bold('Error')}`);\n lines.push('');\n \n // Error message\n const message = typeof error === 'string' ? error : error.message;\n lines.push(message);\n \n // Suggestions if provided\n if (options?.suggestions && options.suggestions.length > 0) {\n lines.push('');\n lines.push(formatTips(options.suggestions, TipStyle.FIXES));\n }\n \n // Help command\n if (options?.showHelp && options?.helpCommand) {\n lines.push('');\n lines.push(SEMANTIC_COLORS.help(`Need help? Run: ${options.helpCommand}`));\n }\n \n return lines.join('\\n');\n}\n\n/**\n * Format a success message (subtle, not redundant)\n */\nexport function formatSuccess(message: string, count?: number): string {\n const symbols = getSymbols();\n \n if (count !== undefined) {\n return `${SEMANTIC_COLORS.success(symbols.success)} ${message} ${SEMANTIC_COLORS.count(count.toString())}`;\n }\n \n return `${SEMANTIC_COLORS.success(symbols.success)} ${message}`;\n}\n\n/**\n * Format empty state messages\n */\nexport function formatEmptyState(\n message: string,\n suggestions?: string[]\n): string {\n const lines: string[] = [];\n \n lines.push(SEMANTIC_COLORS.dim(message));\n \n if (suggestions && suggestions.length > 0) {\n lines.push('');\n suggestions.forEach(s => {\n // Make commands stand out from the dimmed text\n const formatted = s.replace(/--\\w+[^ ]*/g, match => chalk.reset(match));\n lines.push(SEMANTIC_COLORS.dim(formatted));\n });\n }\n \n return lines.join('\\n');\n}\n\n/**\n * Legacy color exports for backward compatibility\n * @deprecated Use SEMANTIC_COLORS instead\n */\nexport const COLORS = {\n error: SEMANTIC_COLORS.error,\n warn: SEMANTIC_COLORS.warning,\n success: SEMANTIC_COLORS.success,\n info: SEMANTIC_COLORS.info,\n muted: SEMANTIC_COLORS.muted,\n highlight: SEMANTIC_COLORS.highlight,\n dim: SEMANTIC_COLORS.dim,\n};\n\n// Export symbols from the symbols module\nexport const SYMBOLS = getSymbols();\n\nexport function shouldDecorate(format?: string): boolean {\n const f = (format || '').toLowerCase();\n return f !== 'json' && f !== 'alfred' && colorEnabled();\n}\n\n\n"]}
|
package/dist/ui/width.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal width utilities for responsive display
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Strip ANSI escape codes from a string
|
|
6
|
+
* Used for accurate length calculations
|
|
7
|
+
*/
|
|
8
|
+
export function stripAnsi(str) {
|
|
9
|
+
// Comprehensive regex for ANSI escape codes
|
|
10
|
+
const ansiRegex = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
|
|
11
|
+
return str.replace(ansiRegex, '');
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Get the current terminal width
|
|
15
|
+
* Falls back to 80 columns if not available
|
|
16
|
+
*/
|
|
17
|
+
export function termWidth() {
|
|
18
|
+
// Check environment variable first (for testing)
|
|
19
|
+
const envColumns = process.env.COLUMNS ? parseInt(process.env.COLUMNS, 10) : undefined;
|
|
20
|
+
const columns = envColumns || process.stdout.columns || 80;
|
|
21
|
+
// Ensure minimum width of 40 for readability
|
|
22
|
+
return Math.max(40, columns);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Truncate text to fit within a maximum width
|
|
26
|
+
* Adds ellipsis if text is truncated
|
|
27
|
+
*/
|
|
28
|
+
export function truncate(text, maxWidth) {
|
|
29
|
+
if (text.length <= maxWidth)
|
|
30
|
+
return text;
|
|
31
|
+
if (maxWidth <= 1)
|
|
32
|
+
return text[0] || '';
|
|
33
|
+
return text.slice(0, Math.max(0, maxWidth - 1)) + '…';
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Wrap text to fit within a maximum width
|
|
37
|
+
* Returns an array of lines
|
|
38
|
+
*/
|
|
39
|
+
export function wrapText(text, maxWidth) {
|
|
40
|
+
if (maxWidth <= 0)
|
|
41
|
+
return [text];
|
|
42
|
+
if (text.length <= maxWidth)
|
|
43
|
+
return [text];
|
|
44
|
+
const words = text.split(/\s+/);
|
|
45
|
+
const lines = [];
|
|
46
|
+
let currentLine = '';
|
|
47
|
+
for (const word of words) {
|
|
48
|
+
// If a single word is longer than maxWidth, we need to break it
|
|
49
|
+
if (word.length > maxWidth) {
|
|
50
|
+
// Finish current line if it has content
|
|
51
|
+
if (currentLine) {
|
|
52
|
+
lines.push(currentLine.trim());
|
|
53
|
+
currentLine = '';
|
|
54
|
+
}
|
|
55
|
+
// Break the long word into chunks
|
|
56
|
+
let remaining = word;
|
|
57
|
+
while (remaining.length > maxWidth) {
|
|
58
|
+
lines.push(remaining.slice(0, maxWidth - 1) + '-');
|
|
59
|
+
remaining = remaining.slice(maxWidth - 1);
|
|
60
|
+
}
|
|
61
|
+
currentLine = remaining;
|
|
62
|
+
}
|
|
63
|
+
else if ((currentLine + ' ' + word).trim().length > maxWidth) {
|
|
64
|
+
// Start a new line
|
|
65
|
+
if (currentLine)
|
|
66
|
+
lines.push(currentLine.trim());
|
|
67
|
+
currentLine = word;
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
// Add word to current line
|
|
71
|
+
currentLine += (currentLine ? ' ' : '') + word;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Add any remaining text
|
|
75
|
+
if (currentLine)
|
|
76
|
+
lines.push(currentLine.trim());
|
|
77
|
+
return lines.length > 0 ? lines : [''];
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Calculate column widths for a table based on terminal width
|
|
81
|
+
* Distributes available width evenly among columns
|
|
82
|
+
*/
|
|
83
|
+
export function calculateColumnWidths(numColumns, terminalWidth, padding = 2) {
|
|
84
|
+
if (numColumns <= 0)
|
|
85
|
+
return [];
|
|
86
|
+
// Account for padding between columns (not after last column)
|
|
87
|
+
const totalPadding = padding * (numColumns - 1);
|
|
88
|
+
const availableWidth = Math.max(numColumns, terminalWidth - totalPadding);
|
|
89
|
+
// Distribute width evenly
|
|
90
|
+
const baseWidth = Math.floor(availableWidth / numColumns);
|
|
91
|
+
const remainder = availableWidth % numColumns;
|
|
92
|
+
// Create array with base widths
|
|
93
|
+
const widths = new Array(numColumns).fill(baseWidth);
|
|
94
|
+
// Distribute remainder to first columns
|
|
95
|
+
for (let i = 0; i < remainder; i++) {
|
|
96
|
+
widths[i]++;
|
|
97
|
+
}
|
|
98
|
+
return widths;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Format a table row with proper column widths and truncation
|
|
102
|
+
*/
|
|
103
|
+
export function formatTableRow(cells, columnWidths, separator = ' ') {
|
|
104
|
+
return cells
|
|
105
|
+
.map((cell, i) => {
|
|
106
|
+
const width = columnWidths[i] || 10;
|
|
107
|
+
return truncate(cell ?? '', width).padEnd(width);
|
|
108
|
+
})
|
|
109
|
+
.join(separator);
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=width.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"width.js","sourceRoot":"/","sources":["ui/width.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Terminal width utilities for responsive display\n */\n\n/**\n * Strip ANSI escape codes from a string\n * Used for accurate length calculations\n */\nexport function stripAnsi(str: string): string {\n // Comprehensive regex for ANSI escape codes\n const ansiRegex = /[\\u001b\\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;\n return str.replace(ansiRegex, '');\n}\n\n/**\n * Get the current terminal width\n * Falls back to 80 columns if not available\n */\nexport function termWidth(): number {\n // Check environment variable first (for testing)\n const envColumns = process.env.COLUMNS ? parseInt(process.env.COLUMNS, 10) : undefined;\n const columns = envColumns || process.stdout.columns || 80;\n \n // Ensure minimum width of 40 for readability\n return Math.max(40, columns);\n}\n\n/**\n * Truncate text to fit within a maximum width\n * Adds ellipsis if text is truncated\n */\nexport function truncate(text: string, maxWidth: number): string {\n if (text.length <= maxWidth) return text;\n if (maxWidth <= 1) return text[0] || '';\n return text.slice(0, Math.max(0, maxWidth - 1)) + '…';\n}\n\n/**\n * Wrap text to fit within a maximum width\n * Returns an array of lines\n */\nexport function wrapText(text: string, maxWidth: number): string[] {\n if (maxWidth <= 0) return [text];\n if (text.length <= maxWidth) return [text];\n \n const words = text.split(/\\s+/);\n const lines: string[] = [];\n let currentLine = '';\n \n for (const word of words) {\n // If a single word is longer than maxWidth, we need to break it\n if (word.length > maxWidth) {\n // Finish current line if it has content\n if (currentLine) {\n lines.push(currentLine.trim());\n currentLine = '';\n }\n // Break the long word into chunks\n let remaining = word;\n while (remaining.length > maxWidth) {\n lines.push(remaining.slice(0, maxWidth - 1) + '-');\n remaining = remaining.slice(maxWidth - 1);\n }\n currentLine = remaining;\n } else if ((currentLine + ' ' + word).trim().length > maxWidth) {\n // Start a new line\n if (currentLine) lines.push(currentLine.trim());\n currentLine = word;\n } else {\n // Add word to current line\n currentLine += (currentLine ? ' ' : '') + word;\n }\n }\n \n // Add any remaining text\n if (currentLine) lines.push(currentLine.trim());\n \n return lines.length > 0 ? lines : [''];\n}\n\n/**\n * Calculate column widths for a table based on terminal width\n * Distributes available width evenly among columns\n */\nexport function calculateColumnWidths(\n numColumns: number,\n terminalWidth: number,\n padding = 2\n): number[] {\n if (numColumns <= 0) return [];\n \n // Account for padding between columns (not after last column)\n const totalPadding = padding * (numColumns - 1);\n const availableWidth = Math.max(numColumns, terminalWidth - totalPadding);\n \n // Distribute width evenly\n const baseWidth = Math.floor(availableWidth / numColumns);\n const remainder = availableWidth % numColumns;\n \n // Create array with base widths\n const widths = new Array(numColumns).fill(baseWidth);\n \n // Distribute remainder to first columns\n for (let i = 0; i < remainder; i++) {\n widths[i]++;\n }\n \n return widths;\n}\n\n/**\n * Format a table row with proper column widths and truncation\n */\nexport function formatTableRow(\n cells: string[],\n columnWidths: number[],\n separator = ' '\n): string {\n return cells\n .map((cell, i) => {\n const width = columnWidths[i] || 10;\n return truncate(cell ?? '', width).padEnd(width);\n })\n .join(separator);\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alfred.js","sourceRoot":"/","sources":["utils/alfred.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,iBAAiB;IAC/B,OAAO,OAAO,CACZ,OAAO,CAAC,GAAG,CAAC,cAAc;QAC1B,OAAO,CAAC,GAAG,CAAC,cAAc;QAC1B,OAAO,CAAC,GAAG,CAAC,wBAAwB,CACrC,CAAC;AACJ,CAAC","sourcesContent":["export function isRunningInAlfred(): boolean {\n return Boolean(\n process.env.alfred_version ||\n process.env.ALFRED_VERSION ||\n process.env.alfred_workflow_bundleid\n );\n}\n\n\n"]}
|
|
@@ -34,13 +34,26 @@ export function displayCLIError(error, debug = false, format) {
|
|
|
34
34
|
// Format the error using the selected formatter
|
|
35
35
|
const formattedError = formatter.formatError(error, { debug });
|
|
36
36
|
// Print the formatted output
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
try {
|
|
38
|
+
if (outputFormat === 'plain') {
|
|
39
|
+
// Route plain errors to stderr for CLI best practices
|
|
40
|
+
process.stderr.write(formattedError + '\n');
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
// Machine-readable formats to stdout
|
|
44
|
+
process.stdout.write(formattedError + '\n');
|
|
45
|
+
}
|
|
39
46
|
}
|
|
40
|
-
|
|
41
|
-
logger
|
|
47
|
+
catch {
|
|
48
|
+
// Fallback to logger if direct write fails
|
|
49
|
+
if (outputFormat === 'plain') {
|
|
50
|
+
logger.error(formattedError);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
logger.console(formattedError);
|
|
54
|
+
}
|
|
42
55
|
}
|
|
43
|
-
process.
|
|
56
|
+
process.exitCode = 1;
|
|
44
57
|
}
|
|
45
58
|
/**
|
|
46
59
|
* Get the current global error output format
|
|
@@ -59,21 +72,21 @@ export function getErrorFormat() {
|
|
|
59
72
|
*/
|
|
60
73
|
export function formatErrorForCLI(error, debug = false) {
|
|
61
74
|
let output = '';
|
|
62
|
-
// Add a separator and heading
|
|
63
|
-
output += '\
|
|
75
|
+
// Add a separator and heading (plain text, no inline ANSI)
|
|
76
|
+
output += '\nERROR\n\n';
|
|
64
77
|
if (error instanceof Error) {
|
|
65
78
|
// Handle standard Error objects
|
|
66
|
-
output +=
|
|
79
|
+
output += `${error.name}: ${error.message}\n\n`;
|
|
67
80
|
if (error.stack) {
|
|
68
81
|
const stackLines = error.stack.split('\n');
|
|
69
82
|
// First line usually contains the error message, which we've already displayed
|
|
70
83
|
const stackTrace = stackLines.slice(1).join('\n');
|
|
71
|
-
output +=
|
|
84
|
+
output += `Stack Trace:\n${stackTrace}\n\n`;
|
|
72
85
|
}
|
|
73
86
|
// Handle additional properties that might be present in API errors
|
|
74
87
|
const apiError = error;
|
|
75
88
|
if (apiError.response?.errors) {
|
|
76
|
-
output += '
|
|
89
|
+
output += 'API Errors:\n';
|
|
77
90
|
apiError.response.errors.forEach((e, i) => {
|
|
78
91
|
output += ` Error ${i + 1}: ${e.message || 'Unknown error'}\n`;
|
|
79
92
|
if (e.path)
|
|
@@ -84,20 +97,20 @@ export function formatErrorForCLI(error, debug = false) {
|
|
|
84
97
|
});
|
|
85
98
|
}
|
|
86
99
|
if (debug && apiError.request) {
|
|
87
|
-
output += '
|
|
100
|
+
output += 'Request Details:\n';
|
|
88
101
|
output += ` URL: ${apiError.request.url || 'N/A'}\n`;
|
|
89
102
|
output += ` Method: ${apiError.request.method || 'N/A'}\n\n`;
|
|
90
103
|
}
|
|
91
104
|
// If error has a cause, include it
|
|
92
105
|
if (apiError.cause) {
|
|
93
|
-
output += '
|
|
106
|
+
output += 'Caused by:\n';
|
|
94
107
|
output += formatErrorForCLI(apiError.cause, debug);
|
|
95
108
|
}
|
|
96
109
|
}
|
|
97
110
|
else if (error && typeof error === 'object') {
|
|
98
111
|
// Handle non-Error objects
|
|
99
112
|
try {
|
|
100
|
-
output += '
|
|
113
|
+
output += 'Error Object:\n';
|
|
101
114
|
output += JSON.stringify(error, null, 2) + '\n\n';
|
|
102
115
|
// Try to extract more detailed information
|
|
103
116
|
const errorObj = error;
|
|
@@ -105,7 +118,7 @@ export function formatErrorForCLI(error, debug = false) {
|
|
|
105
118
|
output += `Message: ${errorObj.message}\n`;
|
|
106
119
|
}
|
|
107
120
|
if (debug) {
|
|
108
|
-
output += '
|
|
121
|
+
output += 'Properties:\n';
|
|
109
122
|
for (const key in errorObj) {
|
|
110
123
|
try {
|
|
111
124
|
if (key !== 'stack' && key !== 'message') {
|
|
@@ -121,16 +134,16 @@ export function formatErrorForCLI(error, debug = false) {
|
|
|
121
134
|
}
|
|
122
135
|
}
|
|
123
136
|
catch {
|
|
124
|
-
output += '
|
|
137
|
+
output += 'Unable to stringify error object\n\n';
|
|
125
138
|
}
|
|
126
139
|
}
|
|
127
140
|
else {
|
|
128
141
|
// Handle primitive values
|
|
129
|
-
output +=
|
|
142
|
+
output += `${String(error)}\n\n`;
|
|
130
143
|
}
|
|
131
144
|
if (debug) {
|
|
132
145
|
// Add debug information
|
|
133
|
-
output += '
|
|
146
|
+
output += 'Debug Information:\n';
|
|
134
147
|
output += ` Timestamp: ${new Date().toISOString()}\n`;
|
|
135
148
|
output += ` Node Version: ${process.version}\n`;
|
|
136
149
|
output += ` Platform: ${process.platform} (${process.arch})\n`;
|
|
@@ -139,7 +152,7 @@ export function formatErrorForCLI(error, debug = false) {
|
|
|
139
152
|
const stack = new Error().stack;
|
|
140
153
|
if (stack) {
|
|
141
154
|
const stackLines = stack.split('\n').slice(2); // Skip the Error creation line and this function
|
|
142
|
-
output += '\
|
|
155
|
+
output += '\nCurrent Stack:\n';
|
|
143
156
|
output += stackLines.join('\n') + '\n';
|
|
144
157
|
}
|
|
145
158
|
}
|
|
@@ -148,7 +161,7 @@ export function formatErrorForCLI(error, debug = false) {
|
|
|
148
161
|
}
|
|
149
162
|
}
|
|
150
163
|
// Add a closing separator
|
|
151
|
-
output += '\n
|
|
164
|
+
output += '\n';
|
|
152
165
|
return output;
|
|
153
166
|
}
|
|
154
167
|
/**
|
|
@@ -165,7 +178,9 @@ export function withCLIErrorHandling(fn, options = {}) {
|
|
|
165
178
|
}
|
|
166
179
|
catch (error) {
|
|
167
180
|
displayCLIError(error, options.debugMode || false, options.format);
|
|
168
|
-
process.
|
|
181
|
+
process.exitCode = 1;
|
|
182
|
+
// Return void to satisfy TypeScript
|
|
183
|
+
return;
|
|
169
184
|
}
|
|
170
185
|
};
|
|
171
186
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-error-handler.js","sourceRoot":"/","sources":["utils/cli-error-handler.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * CLI Error Handler - Provides error display for CLI applications\n */\n\nimport { logger } from '../services/logger.js';\nimport { FormatterFactory, FormatterType } from '../formatters/FormatterFactory.js';\nimport { ErrorFormatter } from '../formatters/errors/index.js';\n\n// Default format to use for error output\nlet globalErrorFormat = 'plain';\n\n/**\n * Set the global error output format\n * @param format The format to use ('plain', 'json', 'alfred')\n */\nexport function setErrorFormat(format: string): void {\n const normalizedFormat = format.toLowerCase().trim();\n if (['plain', 'json', 'alfred'].includes(normalizedFormat)) {\n globalErrorFormat = normalizedFormat;\n logger.debug(`Error output format set to ${normalizedFormat}`);\n } else {\n logger.warn(`Unknown format '${format}', error output format remains as ${globalErrorFormat}`);\n }\n}\n\n/**\n * Display a formatted error message\n * \n * @param error The error to display\n * @param debug Whether to include debug information\n * @param format Output format (plain, json, alfred), defaults to global setting\n */\nexport function displayCLIError(\n error: unknown, \n debug = false, \n format?: string\n): void {\n // Use provided format or fall back to global format\n const outputFormat = format || globalErrorFormat;\n \n // Get the appropriate formatter based on format\n const formatter = FormatterFactory.getFormatter(FormatterType.ERROR, outputFormat) as ErrorFormatter;\n \n // Format the error using the selected formatter\n const formattedError = formatter.formatError(error, { debug });\n \n // Print the formatted output\n if (outputFormat === 'plain') {\n logger.error(formattedError);\n } else {\n logger.console(formattedError);\n }\n \n process.exit(1);\n}\n\n/**\n * Get the current global error output format\n * @returns The current format\n */\nexport function getErrorFormat(): string {\n return globalErrorFormat;\n}\n\n/**\n * Format an error object for display in the CLI\n * Extracts as much useful information as possible, including stack traces\n * \n * @param error The error object to format\n * @param debug Whether to include debug information\n * @returns Formatted error message\n */\nexport function formatErrorForCLI(error: unknown, debug = false): string {\n let output = '';\n \n // Add a separator and heading\n output += '\\n\\x1b[31m════════════════════════ ERROR ════════════════════════\\x1b[0m\\n\\n';\n \n if (error instanceof Error) {\n // Handle standard Error objects\n output += `\\x1b[31m${error.name}: ${error.message}\\x1b[0m\\n\\n`;\n \n if (error.stack) {\n const stackLines = error.stack.split('\\n');\n // First line usually contains the error message, which we've already displayed\n const stackTrace = stackLines.slice(1).join('\\n');\n output += `\\x1b[33mStack Trace:\\x1b[0m\\n${stackTrace}\\n\\n`;\n }\n \n // Handle additional properties that might be present in API errors\n const apiError = error as any;\n if (apiError.response?.errors) {\n output += '\\x1b[33mAPI Errors:\\x1b[0m\\n';\n apiError.response.errors.forEach((e: any, i: number) => {\n output += ` Error ${i + 1}: ${e.message || 'Unknown error'}\\n`;\n if (e.path) output += ` Path: ${e.path.join('.')}\\n`;\n if (e.locations) output += ` Locations: ${JSON.stringify(e.locations)}\\n`;\n output += '\\n';\n });\n }\n \n if (debug && apiError.request) {\n output += '\\x1b[36mRequest Details:\\x1b[0m\\n';\n output += ` URL: ${apiError.request.url || 'N/A'}\\n`;\n output += ` Method: ${apiError.request.method || 'N/A'}\\n\\n`;\n }\n \n // If error has a cause, include it\n if (apiError.cause) {\n output += '\\x1b[33mCaused by:\\x1b[0m\\n';\n output += formatErrorForCLI(apiError.cause, debug);\n }\n } else if (error && typeof error === 'object') {\n // Handle non-Error objects\n try {\n output += '\\x1b[31mError Object:\\x1b[0m\\n';\n output += JSON.stringify(error, null, 2) + '\\n\\n';\n \n // Try to extract more detailed information\n const errorObj = error as Record<string, any>;\n if (errorObj.message) {\n output += `Message: ${errorObj.message}\\n`;\n }\n \n if (debug) {\n output += '\\x1b[36mProperties:\\x1b[0m\\n';\n for (const key in errorObj) {\n try {\n if (key !== 'stack' && key !== 'message') {\n const value = errorObj[key];\n output += ` ${key}: ${typeof value === 'object' ? JSON.stringify(value) : value}\\n`;\n }\n } catch {\n output += ` ${key}: [Cannot stringify]\\n`;\n }\n }\n output += '\\n';\n }\n } catch {\n output += '\\x1b[31mUnable to stringify error object\\x1b[0m\\n\\n';\n }\n } else {\n // Handle primitive values\n output += `\\x1b[31m${String(error)}\\x1b[0m\\n\\n`;\n }\n \n if (debug) {\n // Add debug information\n output += '\\x1b[36mDebug Information:\\x1b[0m\\n';\n output += ` Timestamp: ${new Date().toISOString()}\\n`;\n output += ` Node Version: ${process.version}\\n`;\n output += ` Platform: ${process.platform} (${process.arch})\\n`;\n \n try {\n // Get the current call stack\n const stack = new Error().stack;\n if (stack) {\n const stackLines = stack.split('\\n').slice(2); // Skip the Error creation line and this function\n output += '\\n\\x1b[36mCurrent Stack:\\x1b[0m\\n';\n output += stackLines.join('\\n') + '\\n';\n }\n } catch {\n // Ignore stack trace errors\n }\n }\n \n // Add a closing separator\n output += '\\n\\x1b[31m═══════════════════════════════════════════════════════\\x1b[0m\\n';\n \n return output;\n}\n\n/**\n * Wraps a function with CLI error handling\n * \n * @param fn The function to wrap\n * @param options Error handling options\n * @returns A wrapped function with error handling\n */\nexport function withCLIErrorHandling<T extends (...args: any[]) => Promise<any>>(\n fn: T,\n options: {\n debugMode?: boolean;\n format?: string;\n } = {}\n): (...args: Parameters<T>) => Promise<ReturnType<T>> {\n return async function(...args: Parameters<T>): Promise<ReturnType<T>> {\n try {\n return await fn(...args);\n } catch (error) {\n displayCLIError(\n error, \n options.debugMode || false, \n options.format\n );\n process.exit(1);\n }\n };\n} "]}
|
|
1
|
+
{"version":3,"file":"cli-error-handler.js","sourceRoot":"/","sources":["utils/cli-error-handler.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * CLI Error Handler - Provides error display for CLI applications\n */\n\nimport { logger } from '../services/logger.js';\nimport { FormatterFactory, FormatterType } from '../formatters/FormatterFactory.js';\nimport { ErrorFormatter } from '../formatters/errors/index.js';\n\n// Default format to use for error output\nlet globalErrorFormat = 'plain';\n\n/**\n * Set the global error output format\n * @param format The format to use ('plain', 'json', 'alfred')\n */\nexport function setErrorFormat(format: string): void {\n const normalizedFormat = format.toLowerCase().trim();\n if (['plain', 'json', 'alfred'].includes(normalizedFormat)) {\n globalErrorFormat = normalizedFormat;\n logger.debug(`Error output format set to ${normalizedFormat}`);\n } else {\n logger.warn(`Unknown format '${format}', error output format remains as ${globalErrorFormat}`);\n }\n}\n\n/**\n * Display a formatted error message\n * \n * @param error The error to display\n * @param debug Whether to include debug information\n * @param format Output format (plain, json, alfred), defaults to global setting\n */\nexport function displayCLIError(\n error: unknown, \n debug = false, \n format?: string\n): void {\n // Use provided format or fall back to global format\n const outputFormat = format || globalErrorFormat;\n \n // Get the appropriate formatter based on format\n const formatter = FormatterFactory.getFormatter(FormatterType.ERROR, outputFormat) as ErrorFormatter;\n \n // Format the error using the selected formatter\n const formattedError = formatter.formatError(error, { debug });\n \n // Print the formatted output\n try {\n if (outputFormat === 'plain') {\n // Route plain errors to stderr for CLI best practices\n process.stderr.write(formattedError + '\\n');\n } else {\n // Machine-readable formats to stdout\n process.stdout.write(formattedError + '\\n');\n }\n } catch {\n // Fallback to logger if direct write fails\n if (outputFormat === 'plain') {\n logger.error(formattedError);\n } else {\n logger.console(formattedError);\n }\n }\n \n process.exitCode = 1;\n}\n\n/**\n * Get the current global error output format\n * @returns The current format\n */\nexport function getErrorFormat(): string {\n return globalErrorFormat;\n}\n\n/**\n * Format an error object for display in the CLI\n * Extracts as much useful information as possible, including stack traces\n * \n * @param error The error object to format\n * @param debug Whether to include debug information\n * @returns Formatted error message\n */\nexport function formatErrorForCLI(error: unknown, debug = false): string {\n let output = '';\n \n // Add a separator and heading (plain text, no inline ANSI)\n output += '\\nERROR\\n\\n';\n \n if (error instanceof Error) {\n // Handle standard Error objects\n output += `${error.name}: ${error.message}\\n\\n`;\n \n if (error.stack) {\n const stackLines = error.stack.split('\\n');\n // First line usually contains the error message, which we've already displayed\n const stackTrace = stackLines.slice(1).join('\\n');\n output += `Stack Trace:\\n${stackTrace}\\n\\n`;\n }\n \n // Handle additional properties that might be present in API errors\n const apiError = error as any;\n if (apiError.response?.errors) {\n output += 'API Errors:\\n';\n apiError.response.errors.forEach((e: any, i: number) => {\n output += ` Error ${i + 1}: ${e.message || 'Unknown error'}\\n`;\n if (e.path) output += ` Path: ${e.path.join('.')}\\n`;\n if (e.locations) output += ` Locations: ${JSON.stringify(e.locations)}\\n`;\n output += '\\n';\n });\n }\n \n if (debug && apiError.request) {\n output += 'Request Details:\\n';\n output += ` URL: ${apiError.request.url || 'N/A'}\\n`;\n output += ` Method: ${apiError.request.method || 'N/A'}\\n\\n`;\n }\n \n // If error has a cause, include it\n if (apiError.cause) {\n output += 'Caused by:\\n';\n output += formatErrorForCLI(apiError.cause, debug);\n }\n } else if (error && typeof error === 'object') {\n // Handle non-Error objects\n try {\n output += 'Error Object:\\n';\n output += JSON.stringify(error, null, 2) + '\\n\\n';\n \n // Try to extract more detailed information\n const errorObj = error as Record<string, any>;\n if (errorObj.message) {\n output += `Message: ${errorObj.message}\\n`;\n }\n \n if (debug) {\n output += 'Properties:\\n';\n for (const key in errorObj) {\n try {\n if (key !== 'stack' && key !== 'message') {\n const value = errorObj[key];\n output += ` ${key}: ${typeof value === 'object' ? JSON.stringify(value) : value}\\n`;\n }\n } catch {\n output += ` ${key}: [Cannot stringify]\\n`;\n }\n }\n output += '\\n';\n }\n } catch {\n output += 'Unable to stringify error object\\n\\n';\n }\n } else {\n // Handle primitive values\n output += `${String(error)}\\n\\n`;\n }\n \n if (debug) {\n // Add debug information\n output += 'Debug Information:\\n';\n output += ` Timestamp: ${new Date().toISOString()}\\n`;\n output += ` Node Version: ${process.version}\\n`;\n output += ` Platform: ${process.platform} (${process.arch})\\n`;\n \n try {\n // Get the current call stack\n const stack = new Error().stack;\n if (stack) {\n const stackLines = stack.split('\\n').slice(2); // Skip the Error creation line and this function\n output += '\\nCurrent Stack:\\n';\n output += stackLines.join('\\n') + '\\n';\n }\n } catch {\n // Ignore stack trace errors\n }\n }\n \n // Add a closing separator\n output += '\\n';\n \n return output;\n}\n\n/**\n * Wraps a function with CLI error handling\n * \n * @param fn The function to wrap\n * @param options Error handling options\n * @returns A wrapped function with error handling\n */\nexport function withCLIErrorHandling<T extends (...args: any[]) => Promise<any>>(\n fn: T,\n options: {\n debugMode?: boolean;\n format?: string;\n } = {}\n): (...args: Parameters<T>) => Promise<ReturnType<T> | void> {\n return async function(...args: Parameters<T>): Promise<ReturnType<T> | void> {\n try {\n return await fn(...args);\n } catch (error) {\n displayCLIError(\n error, \n options.debugMode || false, \n options.format\n );\n process.exitCode = 1;\n // Return void to satisfy TypeScript\n return;\n }\n };\n} "]}
|