bktide 1.0.1755267617 → 1.0.1755559112

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 (93) hide show
  1. package/README.md +107 -1
  2. package/WORKFLOW_README.md +1 -1
  3. package/completions/bktide-dynamic.fish +171 -0
  4. package/completions/bktide.bash +124 -0
  5. package/completions/bktide.fish +107 -0
  6. package/completions/bktide.zsh +139 -0
  7. package/dist/commands/BaseCommand.js +7 -7
  8. package/dist/commands/BaseCommand.js.map +1 -1
  9. package/dist/commands/GenerateCompletions.js +238 -0
  10. package/dist/commands/GenerateCompletions.js.map +1 -0
  11. package/dist/commands/ListAnnotations.js +7 -0
  12. package/dist/commands/ListAnnotations.js.map +1 -1
  13. package/dist/commands/ListBuilds.js +67 -3
  14. package/dist/commands/ListBuilds.js.map +1 -1
  15. package/dist/commands/ListOrganizations.js +6 -0
  16. package/dist/commands/ListOrganizations.js.map +1 -1
  17. package/dist/commands/ListPipelines.js +87 -12
  18. package/dist/commands/ListPipelines.js.map +1 -1
  19. package/dist/commands/ManageToken.js +32 -9
  20. package/dist/commands/ManageToken.js.map +1 -1
  21. package/dist/commands/ShowBuild.js +88 -0
  22. package/dist/commands/ShowBuild.js.map +1 -0
  23. package/dist/commands/ShowViewer.js +7 -1
  24. package/dist/commands/ShowViewer.js.map +1 -1
  25. package/dist/commands/index.js +2 -0
  26. package/dist/commands/index.js.map +1 -1
  27. package/dist/formatters/FormatterFactory.js +4 -0
  28. package/dist/formatters/FormatterFactory.js.map +1 -1
  29. package/dist/formatters/annotations/PlainTextFormatter.js +37 -9
  30. package/dist/formatters/annotations/PlainTextFormatter.js.map +1 -1
  31. package/dist/formatters/build-detail/AlfredFormatter.js +113 -0
  32. package/dist/formatters/build-detail/AlfredFormatter.js.map +1 -0
  33. package/dist/formatters/build-detail/Formatter.js +3 -0
  34. package/dist/formatters/build-detail/Formatter.js.map +1 -0
  35. package/dist/formatters/build-detail/JsonFormatter.js +132 -0
  36. package/dist/formatters/build-detail/JsonFormatter.js.map +1 -0
  37. package/dist/formatters/build-detail/PlainTextFormatter.js +680 -0
  38. package/dist/formatters/build-detail/PlainTextFormatter.js.map +1 -0
  39. package/dist/formatters/build-detail/index.js +21 -0
  40. package/dist/formatters/build-detail/index.js.map +1 -0
  41. package/dist/formatters/builds/PlainTextFormatter.js +82 -60
  42. package/dist/formatters/builds/PlainTextFormatter.js.map +1 -1
  43. package/dist/formatters/errors/AlfredFormatter.js +20 -0
  44. package/dist/formatters/errors/AlfredFormatter.js.map +1 -1
  45. package/dist/formatters/errors/PlainTextFormatter.js +121 -23
  46. package/dist/formatters/errors/PlainTextFormatter.js.map +1 -1
  47. package/dist/formatters/organizations/PlainTextFormatter.js +37 -6
  48. package/dist/formatters/organizations/PlainTextFormatter.js.map +1 -1
  49. package/dist/formatters/pipelines/AlfredFormatter.js.map +1 -1
  50. package/dist/formatters/pipelines/Formatter.js.map +1 -1
  51. package/dist/formatters/pipelines/JsonFormatter.js.map +1 -1
  52. package/dist/formatters/pipelines/PlainTextFormatter.js +165 -19
  53. package/dist/formatters/pipelines/PlainTextFormatter.js.map +1 -1
  54. package/dist/formatters/token/AlfredFormatter.js +15 -2
  55. package/dist/formatters/token/AlfredFormatter.js.map +1 -1
  56. package/dist/formatters/token/PlainTextFormatter.js +56 -18
  57. package/dist/formatters/token/PlainTextFormatter.js.map +1 -1
  58. package/dist/formatters/viewer/PlainTextFormatter.js +8 -7
  59. package/dist/formatters/viewer/PlainTextFormatter.js.map +1 -1
  60. package/dist/graphql/queries.js +181 -0
  61. package/dist/graphql/queries.js.map +1 -1
  62. package/dist/index.js +67 -6
  63. package/dist/index.js.map +1 -1
  64. package/dist/services/BuildkiteClient.js +61 -1
  65. package/dist/services/BuildkiteClient.js.map +1 -1
  66. package/dist/services/CredentialManager.js +80 -10
  67. package/dist/services/CredentialManager.js.map +1 -1
  68. package/dist/ui/help.js +69 -0
  69. package/dist/ui/help.js.map +1 -0
  70. package/dist/ui/progress.js +356 -0
  71. package/dist/ui/progress.js.map +1 -0
  72. package/dist/ui/reporter.js +111 -0
  73. package/dist/ui/reporter.js.map +1 -0
  74. package/dist/ui/responsive-table.js +183 -0
  75. package/dist/ui/responsive-table.js.map +1 -0
  76. package/dist/ui/spinner.js +20 -0
  77. package/dist/ui/spinner.js.map +1 -0
  78. package/dist/ui/symbols.js +46 -0
  79. package/dist/ui/symbols.js.map +1 -0
  80. package/dist/ui/table.js +32 -0
  81. package/dist/ui/table.js.map +1 -0
  82. package/dist/ui/theme.js +280 -0
  83. package/dist/ui/theme.js.map +1 -0
  84. package/dist/ui/width.js +111 -0
  85. package/dist/ui/width.js.map +1 -0
  86. package/dist/utils/alfred.js +6 -0
  87. package/dist/utils/alfred.js.map +1 -0
  88. package/dist/utils/cli-error-handler.js +35 -20
  89. package/dist/utils/cli-error-handler.js.map +1 -1
  90. package/dist/utils/pagination.js +92 -0
  91. package/dist/utils/pagination.js.map +1 -0
  92. package/info.plist +51 -218
  93. package/package.json +24 -5
@@ -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"]}
@@ -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,6 @@
1
+ export function isRunningInAlfred() {
2
+ return Boolean(process.env.alfred_version ||
3
+ process.env.ALFRED_VERSION ||
4
+ process.env.alfred_workflow_bundleid);
5
+ }
6
+ //# sourceMappingURL=alfred.js.map
@@ -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
- if (outputFormat === 'plain') {
38
- logger.error(formattedError);
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
- else {
41
- logger.console(formattedError);
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.exit(1);
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 += '\n\x1b[31m════════════════════════ ERROR ════════════════════════\x1b[0m\n\n';
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 += `\x1b[31m${error.name}: ${error.message}\x1b[0m\n\n`;
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 += `\x1b[33mStack Trace:\x1b[0m\n${stackTrace}\n\n`;
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 += '\x1b[33mAPI Errors:\x1b[0m\n';
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 += '\x1b[36mRequest Details:\x1b[0m\n';
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 += '\x1b[33mCaused by:\x1b[0m\n';
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 += '\x1b[31mError Object:\x1b[0m\n';
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 += '\x1b[36mProperties:\x1b[0m\n';
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 += '\x1b[31mUnable to stringify error object\x1b[0m\n\n';
137
+ output += 'Unable to stringify error object\n\n';
125
138
  }
126
139
  }
127
140
  else {
128
141
  // Handle primitive values
129
- output += `\x1b[31m${String(error)}\x1b[0m\n\n`;
142
+ output += `${String(error)}\n\n`;
130
143
  }
131
144
  if (debug) {
132
145
  // Add debug information
133
- output += '\x1b[36mDebug Information:\x1b[0m\n';
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 += '\n\x1b[36mCurrent Stack:\x1b[0m\n';
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\x1b[31m═══════════════════════════════════════════════════════\x1b[0m\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.exit(1);
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} "]}