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.
- 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/ShowBuild.js +88 -0
- package/dist/commands/ShowBuild.js.map +1 -0
- package/dist/commands/ShowViewer.js +7 -1
- package/dist/commands/ShowViewer.js.map +1 -1
- package/dist/commands/index.js +2 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/formatters/FormatterFactory.js +4 -0
- package/dist/formatters/FormatterFactory.js.map +1 -1
- package/dist/formatters/annotations/PlainTextFormatter.js +37 -9
- package/dist/formatters/annotations/PlainTextFormatter.js.map +1 -1
- package/dist/formatters/build-detail/AlfredFormatter.js +113 -0
- package/dist/formatters/build-detail/AlfredFormatter.js.map +1 -0
- package/dist/formatters/build-detail/Formatter.js +3 -0
- package/dist/formatters/build-detail/Formatter.js.map +1 -0
- package/dist/formatters/build-detail/JsonFormatter.js +132 -0
- package/dist/formatters/build-detail/JsonFormatter.js.map +1 -0
- package/dist/formatters/build-detail/PlainTextFormatter.js +680 -0
- package/dist/formatters/build-detail/PlainTextFormatter.js.map +1 -0
- package/dist/formatters/build-detail/index.js +21 -0
- package/dist/formatters/build-detail/index.js.map +1 -0
- 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/graphql/queries.js +181 -0
- package/dist/graphql/queries.js.map +1 -1
- package/dist/index.js +67 -6
- package/dist/index.js.map +1 -1
- package/dist/services/BuildkiteClient.js +61 -1
- package/dist/services/BuildkiteClient.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 +24 -5
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { BaseErrorFormatter } from './Formatter.js';
|
|
2
|
+
import { COLORS, SYMBOLS, formatTips, TipStyle } from '../../ui/theme.js';
|
|
3
|
+
import { wrapText, termWidth } from '../../ui/width.js';
|
|
2
4
|
/**
|
|
3
|
-
* Plain text formatter for errors
|
|
5
|
+
* Plain text formatter for errors with structured sections
|
|
4
6
|
*/
|
|
5
7
|
export class PlainTextFormatter extends BaseErrorFormatter {
|
|
6
8
|
name = 'plain';
|
|
@@ -13,40 +15,136 @@ export class PlainTextFormatter extends BaseErrorFormatter {
|
|
|
13
15
|
*/
|
|
14
16
|
formatError(errors, options) {
|
|
15
17
|
const errorArray = Array.isArray(errors) ? errors : [errors];
|
|
16
|
-
|
|
18
|
+
const sections = [];
|
|
19
|
+
const width = termWidth();
|
|
20
|
+
const contentWidth = Math.min(width - 4, 76); // Leave some margin, cap at 76 chars
|
|
17
21
|
for (const error of errorArray) {
|
|
18
|
-
if (
|
|
19
|
-
|
|
20
|
-
//
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
if (sections.length > 0)
|
|
23
|
+
sections.push(''); // Add spacing between multiple errors
|
|
24
|
+
// Title section with icon
|
|
25
|
+
const errorName = this.getErrorName(error);
|
|
26
|
+
const errorMessage = this.getErrorMessage(error);
|
|
27
|
+
sections.push(COLORS.error(`${SYMBOLS.error} ERROR ${errorName}`));
|
|
28
|
+
// Message section (wrapped for readability)
|
|
29
|
+
if (errorMessage && errorMessage !== errorName) {
|
|
30
|
+
const wrappedMessage = wrapText(errorMessage, contentWidth);
|
|
31
|
+
wrappedMessage.forEach(line => {
|
|
32
|
+
sections.push(` ${line}`);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
// Cause section (if available)
|
|
36
|
+
const cause = this.getErrorCause(error);
|
|
37
|
+
if (cause) {
|
|
38
|
+
sections.push('');
|
|
39
|
+
sections.push(COLORS.muted(`CAUSE ${cause}`));
|
|
26
40
|
}
|
|
27
|
-
//
|
|
41
|
+
// API errors section
|
|
28
42
|
const apiErrors = this.getApiErrors(error);
|
|
29
43
|
if (apiErrors?.length) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (apiError.
|
|
36
|
-
|
|
44
|
+
sections.push('');
|
|
45
|
+
sections.push(COLORS.warn(`${SYMBOLS.warn} DETAILS`));
|
|
46
|
+
apiErrors.forEach((apiError) => {
|
|
47
|
+
const message = apiError.message || 'Unknown error';
|
|
48
|
+
sections.push(` ${SYMBOLS.bullet} ${message}`);
|
|
49
|
+
if (apiError.path) {
|
|
50
|
+
sections.push(COLORS.muted(` Path: ${apiError.path.join('.')}`));
|
|
51
|
+
}
|
|
37
52
|
});
|
|
38
53
|
}
|
|
39
|
-
//
|
|
54
|
+
// Stack trace (debug only)
|
|
55
|
+
const stack = this.getStackTrace(error);
|
|
56
|
+
if (stack && options?.debug) {
|
|
57
|
+
sections.push('');
|
|
58
|
+
sections.push(COLORS.muted('STACK'));
|
|
59
|
+
// Indent stack trace lines
|
|
60
|
+
stack.split('\n').forEach(line => {
|
|
61
|
+
sections.push(COLORS.muted(` ${line}`));
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
// Request details (debug only)
|
|
40
65
|
const request = this.getRequestDetails(error);
|
|
41
66
|
if (request && options?.debug) {
|
|
42
|
-
|
|
67
|
+
sections.push('');
|
|
68
|
+
sections.push(COLORS.muted('REQUEST'));
|
|
43
69
|
if (request.url)
|
|
44
|
-
|
|
70
|
+
sections.push(COLORS.muted(` URL: ${request.url}`));
|
|
45
71
|
if (request.method)
|
|
46
|
-
|
|
72
|
+
sections.push(COLORS.muted(` Method: ${request.method}`));
|
|
73
|
+
}
|
|
74
|
+
// Hints section - context-aware suggestions
|
|
75
|
+
const hints = this.getContextualHints(error, errorMessage);
|
|
76
|
+
if (hints.length > 0) {
|
|
77
|
+
sections.push('');
|
|
78
|
+
sections.push(formatTips(hints, TipStyle.FIXES));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return sections.join('\n');
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Get contextual hints based on the error
|
|
85
|
+
*/
|
|
86
|
+
getContextualHints(_error, message) {
|
|
87
|
+
const hints = [];
|
|
88
|
+
const lowerMessage = message.toLowerCase();
|
|
89
|
+
// Authentication errors
|
|
90
|
+
if (lowerMessage.includes('auth') || lowerMessage.includes('unauthorized') ||
|
|
91
|
+
lowerMessage.includes('401') || lowerMessage.includes('token')) {
|
|
92
|
+
hints.push('Check your token: bktide token --check');
|
|
93
|
+
hints.push('Store a new token: bktide token --store');
|
|
94
|
+
hints.push('Set token via: export BUILDKITE_API_TOKEN=<your-token>');
|
|
95
|
+
}
|
|
96
|
+
// Network errors
|
|
97
|
+
else if (lowerMessage.includes('econnrefused') || lowerMessage.includes('network') ||
|
|
98
|
+
lowerMessage.includes('etimedout') || lowerMessage.includes('dns')) {
|
|
99
|
+
hints.push('Check your internet connection');
|
|
100
|
+
hints.push('Verify Buildkite API is accessible');
|
|
101
|
+
hints.push('Try again with --no-cache to bypass cache');
|
|
102
|
+
}
|
|
103
|
+
// Permission errors
|
|
104
|
+
else if (lowerMessage.includes('permission') || lowerMessage.includes('forbidden') ||
|
|
105
|
+
lowerMessage.includes('403')) {
|
|
106
|
+
hints.push('Verify you have access to this resource');
|
|
107
|
+
hints.push('Check organization permissions');
|
|
108
|
+
hints.push('List accessible orgs: bktide orgs');
|
|
109
|
+
}
|
|
110
|
+
// Not found errors
|
|
111
|
+
else if (lowerMessage.includes('not found') || lowerMessage.includes('404')) {
|
|
112
|
+
hints.push('Verify the resource exists');
|
|
113
|
+
hints.push('Check spelling of organization/pipeline/build names');
|
|
114
|
+
hints.push('List available resources with appropriate list command');
|
|
115
|
+
}
|
|
116
|
+
// Rate limit errors
|
|
117
|
+
else if (lowerMessage.includes('rate limit') || lowerMessage.includes('429')) {
|
|
118
|
+
hints.push('Wait a moment before retrying');
|
|
119
|
+
hints.push('Use --no-cache to avoid repeated API calls');
|
|
120
|
+
hints.push('Consider using --count with a smaller value');
|
|
121
|
+
}
|
|
122
|
+
// Generic hints
|
|
123
|
+
else {
|
|
124
|
+
hints.push('Run with --debug for detailed error information');
|
|
125
|
+
hints.push('Check command syntax: bktide <command> --help');
|
|
126
|
+
hints.push('Report issues: https://github.com/your-repo/issues');
|
|
127
|
+
}
|
|
128
|
+
// Always include debug hint if not already in debug mode
|
|
129
|
+
if (!hints.some(h => h.includes('--debug'))) {
|
|
130
|
+
hints.push('Use --debug flag for stack trace');
|
|
131
|
+
}
|
|
132
|
+
return hints;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Try to extract a cause from the error
|
|
136
|
+
*/
|
|
137
|
+
getErrorCause(error) {
|
|
138
|
+
if (error && typeof error === 'object' && 'cause' in error) {
|
|
139
|
+
const cause = error.cause;
|
|
140
|
+
if (cause instanceof Error) {
|
|
141
|
+
return cause.message;
|
|
142
|
+
}
|
|
143
|
+
if (typeof cause === 'string') {
|
|
144
|
+
return cause;
|
|
47
145
|
}
|
|
48
146
|
}
|
|
49
|
-
return
|
|
147
|
+
return null;
|
|
50
148
|
}
|
|
51
149
|
}
|
|
52
150
|
//# sourceMappingURL=PlainTextFormatter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlainTextFormatter.js","sourceRoot":"/","sources":["formatters/errors/PlainTextFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAyC,MAAM,gBAAgB,CAAC;AAE3F;;GAEG;AACH,MAAM,OAAO,kBAAmB,SAAQ,kBAAkB;IACxD,IAAI,GAAG,OAAO,CAAC;IAEf;;;;;;OAMG;IACH,WAAW,CAAC,MAA2B,EAAE,OAA+B;QACtE,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAC7D,IAAI,MAAM,GAAG,EAAE,CAAC;QAEhB,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;YAC/B,IAAI,MAAM;gBAAE,MAAM,IAAI,MAAM,CAAC,CAAC,sCAAsC;YAEpE,mBAAmB;YACnB,MAAM,IAAI,WAAW,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,WAAW,CAAC;YAEzF,oDAAoD;YACpD,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YACxC,IAAI,KAAK,IAAI,OAAO,EAAE,KAAK,EAAE,CAAC;gBAC5B,MAAM,IAAI,kCAAkC,KAAK,IAAI,CAAC;YACxD,CAAC;YAED,4BAA4B;YAC5B,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;YAC3C,IAAI,SAAS,EAAE,MAAM,EAAE,CAAC;gBACtB,MAAM,IAAI,gCAAgC,CAAC;gBAC3C,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE;oBACpC,MAAM,IAAI,WAAW,KAAK,GAAG,CAAC,KAAK,QAAQ,CAAC,OAAO,IAAI,eAAe,IAAI,CAAC;oBAC3E,IAAI,QAAQ,CAAC,IAAI;wBAAE,MAAM,IAAI,WAAW,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;oBACpE,IAAI,QAAQ,CAAC,SAAS;wBAAE,MAAM,IAAI,gBAAgB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC;gBAC3F,CAAC,CAAC,CAAC;YACL,CAAC;YAED,wDAAwD;YACxD,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;YAC9C,IAAI,OAAO,IAAI,OAAO,EAAE,KAAK,EAAE,CAAC;gBAC9B,MAAM,IAAI,qCAAqC,CAAC;gBAChD,IAAI,OAAO,CAAC,GAAG;oBAAE,MAAM,IAAI,UAAU,OAAO,CAAC,GAAG,IAAI,CAAC;gBACrD,IAAI,OAAO,CAAC,MAAM;oBAAE,MAAM,IAAI,aAAa,OAAO,CAAC,MAAM,IAAI,CAAC;YAChE,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF","sourcesContent":["import { BaseErrorFormatter, ErrorFormatter, ErrorFormatterOptions } from './Formatter.js';\n\n/**\n * Plain text formatter for errors\n */\nexport class PlainTextFormatter extends BaseErrorFormatter implements ErrorFormatter {\n name = 'plain';\n\n /**\n * Format one or more errors for display in plain text\n * \n * @param errors The error(s) to format\n * @param options Formatting options\n * @returns Formatted error message\n */\n formatError(errors: unknown | unknown[], options?: ErrorFormatterOptions): string {\n const errorArray = Array.isArray(errors) ? errors : [errors];\n let output = '';\n\n for (const error of errorArray) {\n if (output) output += '\\n\\n'; // Add spacing between multiple errors\n\n // Add error header\n output += `\\x1b[31m${this.getErrorName(error)}: ${this.getErrorMessage(error)}\\x1b[0m\\n`;\n\n // Add stack trace if available and debug is enabled\n const stack = this.getStackTrace(error);\n if (stack && options?.debug) {\n output += `\\n\\x1b[33mStack Trace:\\x1b[0m\\n${stack}\\n`;\n }\n\n // Add API errors if present\n const apiErrors = this.getApiErrors(error);\n if (apiErrors?.length) {\n output += '\\n\\x1b[33mAPI Errors:\\x1b[0m\\n';\n apiErrors.forEach((apiError, index) => {\n output += ` Error ${index + 1}: ${apiError.message || 'Unknown error'}\\n`;\n if (apiError.path) output += ` Path: ${apiError.path.join('.')}\\n`;\n if (apiError.locations) output += ` Locations: ${JSON.stringify(apiError.locations)}\\n`;\n });\n }\n\n // Add request details if available and debug is enabled\n const request = this.getRequestDetails(error);\n if (request && options?.debug) {\n output += '\\n\\x1b[36mRequest Details:\\x1b[0m\\n';\n if (request.url) output += ` URL: ${request.url}\\n`;\n if (request.method) output += ` Method: ${request.method}\\n`;\n }\n }\n\n return output;\n }\n} "]}
|
|
1
|
+
{"version":3,"file":"PlainTextFormatter.js","sourceRoot":"/","sources":["formatters/errors/PlainTextFormatter.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseErrorFormatter, ErrorFormatter, ErrorFormatterOptions } from './Formatter.js';\nimport { COLORS, SYMBOLS, formatTips, TipStyle } from '../../ui/theme.js';\nimport { wrapText, termWidth } from '../../ui/width.js';\n\n/**\n * Plain text formatter for errors with structured sections\n */\nexport class PlainTextFormatter extends BaseErrorFormatter implements ErrorFormatter {\n name = 'plain';\n\n /**\n * Format one or more errors for display in plain text\n * \n * @param errors The error(s) to format\n * @param options Formatting options\n * @returns Formatted error message\n */\n formatError(errors: unknown | unknown[], options?: ErrorFormatterOptions): string {\n const errorArray = Array.isArray(errors) ? errors : [errors];\n const sections: string[] = [];\n const width = termWidth();\n const contentWidth = Math.min(width - 4, 76); // Leave some margin, cap at 76 chars\n \n for (const error of errorArray) {\n if (sections.length > 0) sections.push(''); // Add spacing between multiple errors\n \n // Title section with icon\n const errorName = this.getErrorName(error);\n const errorMessage = this.getErrorMessage(error);\n sections.push(COLORS.error(`${SYMBOLS.error} ERROR ${errorName}`));\n \n // Message section (wrapped for readability)\n if (errorMessage && errorMessage !== errorName) {\n const wrappedMessage = wrapText(errorMessage, contentWidth);\n wrappedMessage.forEach(line => {\n sections.push(` ${line}`);\n });\n }\n \n // Cause section (if available)\n const cause = this.getErrorCause(error);\n if (cause) {\n sections.push('');\n sections.push(COLORS.muted(`CAUSE ${cause}`));\n }\n \n // API errors section\n const apiErrors = this.getApiErrors(error);\n if (apiErrors?.length) {\n sections.push('');\n sections.push(COLORS.warn(`${SYMBOLS.warn} DETAILS`));\n apiErrors.forEach((apiError) => {\n const message = apiError.message || 'Unknown error';\n sections.push(` ${SYMBOLS.bullet} ${message}`);\n if (apiError.path) {\n sections.push(COLORS.muted(` Path: ${apiError.path.join('.')}`));\n }\n });\n }\n \n // Stack trace (debug only)\n const stack = this.getStackTrace(error);\n if (stack && options?.debug) {\n sections.push('');\n sections.push(COLORS.muted('STACK'));\n // Indent stack trace lines\n stack.split('\\n').forEach(line => {\n sections.push(COLORS.muted(` ${line}`));\n });\n }\n \n // Request details (debug only)\n const request = this.getRequestDetails(error);\n if (request && options?.debug) {\n sections.push('');\n sections.push(COLORS.muted('REQUEST'));\n if (request.url) sections.push(COLORS.muted(` URL: ${request.url}`));\n if (request.method) sections.push(COLORS.muted(` Method: ${request.method}`));\n }\n \n // Hints section - context-aware suggestions\n const hints = this.getContextualHints(error, errorMessage);\n if (hints.length > 0) {\n sections.push('');\n sections.push(formatTips(hints, TipStyle.FIXES));\n }\n }\n \n return sections.join('\\n');\n }\n \n /**\n * Get contextual hints based on the error\n */\n private getContextualHints(_error: unknown, message: string): string[] {\n const hints: string[] = [];\n const lowerMessage = message.toLowerCase();\n \n // Authentication errors\n if (lowerMessage.includes('auth') || lowerMessage.includes('unauthorized') || \n lowerMessage.includes('401') || lowerMessage.includes('token')) {\n hints.push('Check your token: bktide token --check');\n hints.push('Store a new token: bktide token --store');\n hints.push('Set token via: export BUILDKITE_API_TOKEN=<your-token>');\n }\n // Network errors\n else if (lowerMessage.includes('econnrefused') || lowerMessage.includes('network') ||\n lowerMessage.includes('etimedout') || lowerMessage.includes('dns')) {\n hints.push('Check your internet connection');\n hints.push('Verify Buildkite API is accessible');\n hints.push('Try again with --no-cache to bypass cache');\n }\n // Permission errors\n else if (lowerMessage.includes('permission') || lowerMessage.includes('forbidden') ||\n lowerMessage.includes('403')) {\n hints.push('Verify you have access to this resource');\n hints.push('Check organization permissions');\n hints.push('List accessible orgs: bktide orgs');\n }\n // Not found errors\n else if (lowerMessage.includes('not found') || lowerMessage.includes('404')) {\n hints.push('Verify the resource exists');\n hints.push('Check spelling of organization/pipeline/build names');\n hints.push('List available resources with appropriate list command');\n }\n // Rate limit errors\n else if (lowerMessage.includes('rate limit') || lowerMessage.includes('429')) {\n hints.push('Wait a moment before retrying');\n hints.push('Use --no-cache to avoid repeated API calls');\n hints.push('Consider using --count with a smaller value');\n }\n // Generic hints\n else {\n hints.push('Run with --debug for detailed error information');\n hints.push('Check command syntax: bktide <command> --help');\n hints.push('Report issues: https://github.com/your-repo/issues');\n }\n \n // Always include debug hint if not already in debug mode\n if (!hints.some(h => h.includes('--debug'))) {\n hints.push('Use --debug flag for stack trace');\n }\n \n return hints;\n }\n \n /**\n * Try to extract a cause from the error\n */\n private getErrorCause(error: unknown): string | null {\n if (error && typeof error === 'object' && 'cause' in error) {\n const cause = (error as any).cause;\n if (cause instanceof Error) {\n return cause.message;\n }\n if (typeof cause === 'string') {\n return cause;\n }\n }\n return null;\n }\n} "]}
|
|
@@ -1,15 +1,46 @@
|
|
|
1
1
|
import { BaseFormatter } from './Formatter.js';
|
|
2
|
+
import { renderTable } from '../../ui/table.js';
|
|
3
|
+
import { isMobileTerminal } from '../../ui/responsive-table.js';
|
|
4
|
+
import { SEMANTIC_COLORS, formatEmptyState } from '../../ui/theme.js';
|
|
2
5
|
export class PlainTextFormatter extends BaseFormatter {
|
|
3
6
|
name = 'plain-text';
|
|
4
7
|
formatOrganizations(organizations, _options) {
|
|
5
8
|
if (!organizations || organizations.length === 0) {
|
|
6
|
-
return 'No organizations found
|
|
9
|
+
return formatEmptyState('No organizations found', [
|
|
10
|
+
'Check your API token has the correct permissions',
|
|
11
|
+
'Run "bktide token --check" to verify your access'
|
|
12
|
+
]);
|
|
7
13
|
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
const lines = [];
|
|
15
|
+
if (isMobileTerminal()) {
|
|
16
|
+
// For very narrow terminals, use a vertical list format
|
|
17
|
+
organizations.forEach((org, i) => {
|
|
18
|
+
if (i > 0)
|
|
19
|
+
lines.push(''); // Separator between items
|
|
20
|
+
lines.push(SEMANTIC_COLORS.heading(org.name || 'Unknown'));
|
|
21
|
+
lines.push(` ${SEMANTIC_COLORS.label('Slug:')} ${org.slug || '-'}`);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
// Build table with enhanced headers
|
|
26
|
+
const rows = [];
|
|
27
|
+
// Bold + underlined headers for emphasis
|
|
28
|
+
const headers = ['NAME', 'SLUG'].map(h => SEMANTIC_COLORS.heading(h));
|
|
29
|
+
rows.push(headers);
|
|
30
|
+
organizations.forEach((org) => {
|
|
31
|
+
rows.push([
|
|
32
|
+
org.name || SEMANTIC_COLORS.muted('-'),
|
|
33
|
+
org.slug || SEMANTIC_COLORS.muted('-')
|
|
34
|
+
]);
|
|
35
|
+
});
|
|
36
|
+
lines.push(renderTable(rows, { preserveWidths: true }));
|
|
37
|
+
}
|
|
38
|
+
// Add summary line (dimmed)
|
|
39
|
+
lines.push('');
|
|
40
|
+
lines.push(SEMANTIC_COLORS.dim(organizations.length === 1
|
|
41
|
+
? '1 organization accessible'
|
|
42
|
+
: `${SEMANTIC_COLORS.count(organizations.length.toString())} organizations accessible`));
|
|
43
|
+
return lines.join('\n');
|
|
13
44
|
}
|
|
14
45
|
}
|
|
15
46
|
//# sourceMappingURL=PlainTextFormatter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlainTextFormatter.js","sourceRoot":"/","sources":["formatters/organizations/PlainTextFormatter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"PlainTextFormatter.js","sourceRoot":"/","sources":["formatters/organizations/PlainTextFormatter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAEtE,MAAM,OAAO,kBAAmB,SAAQ,aAAa;IACnD,IAAI,GAAG,YAAY,CAAC;IAEpB,mBAAmB,CAAC,aAA6B,EAAE,QAA2B;QAC5E,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjD,OAAO,gBAAgB,CACrB,wBAAwB,EACxB;gBACE,kDAAkD;gBAClD,kDAAkD;aACnD,CACF,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAa,EAAE,CAAC;QAE3B,IAAI,gBAAgB,EAAE,EAAE,CAAC;YACvB,wDAAwD;YACxD,aAAa,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;gBAC/B,IAAI,CAAC,GAAG,CAAC;oBAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,0BAA0B;gBACrD,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,SAAS,CAAC,CAAC,CAAC;gBAC3D,KAAK,CAAC,IAAI,CAAC,KAAK,eAAe,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC,CAAC;YACvE,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,oCAAoC;YACpC,MAAM,IAAI,GAAe,EAAE,CAAC;YAE5B,yCAAyC;YACzC,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;YACtE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAEnB,aAAa,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;gBAC5B,IAAI,CAAC,IAAI,CAAC;oBACR,GAAG,CAAC,IAAI,IAAI,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC;oBACtC,GAAG,CAAC,IAAI,IAAI,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC;iBACvC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC1D,CAAC;QAED,4BAA4B;QAC5B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAC5B,aAAa,CAAC,MAAM,KAAK,CAAC;YACxB,CAAC,CAAC,2BAA2B;YAC7B,CAAC,CAAC,GAAG,eAAe,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,2BAA2B,CACzF,CAAC,CAAC;QAEH,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;CACF","sourcesContent":["import { FormatterOptions } from '../BaseFormatter.js';\nimport { BaseFormatter } from './Formatter.js';\nimport { Organization } from '../../types/index.js';\nimport { renderTable } from '../../ui/table.js';\nimport { isMobileTerminal } from '../../ui/responsive-table.js';\nimport { SEMANTIC_COLORS, formatEmptyState } from '../../ui/theme.js';\n\nexport class PlainTextFormatter extends BaseFormatter {\n name = 'plain-text';\n \n formatOrganizations(organizations: Organization[], _options?: FormatterOptions): string {\n if (!organizations || organizations.length === 0) {\n return formatEmptyState(\n 'No organizations found',\n [\n 'Check your API token has the correct permissions',\n 'Run \"bktide token --check\" to verify your access'\n ]\n );\n }\n\n const lines: string[] = [];\n\n if (isMobileTerminal()) {\n // For very narrow terminals, use a vertical list format\n organizations.forEach((org, i) => {\n if (i > 0) lines.push(''); // Separator between items\n lines.push(SEMANTIC_COLORS.heading(org.name || 'Unknown'));\n lines.push(` ${SEMANTIC_COLORS.label('Slug:')} ${org.slug || '-'}`);\n });\n } else {\n // Build table with enhanced headers\n const rows: string[][] = [];\n \n // Bold + underlined headers for emphasis\n const headers = ['NAME', 'SLUG'].map(h => SEMANTIC_COLORS.heading(h));\n rows.push(headers);\n \n organizations.forEach((org) => {\n rows.push([\n org.name || SEMANTIC_COLORS.muted('-'),\n org.slug || SEMANTIC_COLORS.muted('-')\n ]);\n });\n\n lines.push(renderTable(rows, { preserveWidths: true }));\n }\n \n // Add summary line (dimmed)\n lines.push('');\n lines.push(SEMANTIC_COLORS.dim(\n organizations.length === 1 \n ? '1 organization accessible'\n : `${SEMANTIC_COLORS.count(organizations.length.toString())} organizations accessible`\n ));\n \n return lines.join('\\n');\n }\n} "]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AlfredFormatter.js","sourceRoot":"/","sources":["formatters/pipelines/AlfredFormatter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AlfredFormatter.js","sourceRoot":"/","sources":["formatters/pipelines/AlfredFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA4B,MAAM,gBAAgB,CAAC;AAGzE,MAAM,OAAO,eAAgB,SAAQ,aAAa;IAChD,IAAI,GAAG,QAAQ,CAAC;IAEhB,eAAe,CAAC,SAAqB,EAAE,cAAwB,EAAE,QAAmC;QAClG,mDAAmD;QACnD,MAAM,WAAW,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,QAAkB,EAAE,EAAE;YACvD,6DAA6D;YAC7D,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG;gBAC9B,yBAAyB,QAAQ,CAAC,YAAY,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;YAEpE,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC;YAC1B,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC;YAC5B,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,IAAI,EAAE,CAAC;YAC5C,MAAM,YAAY,GAAG,GAAG,QAAQ,CAAC,YAAY,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;YACjE,MAAM,KAAK,GAAG,GAAG,QAAQ,CAAC,YAAY,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;YAE1D,OAAO;gBACL,GAAG,EAAE,GAAG;gBACR,KAAK,EAAE,KAAK;gBACZ,QAAQ,EAAE,QAAQ;gBAClB,KAAK,EAAE,KAAK;gBACZ,GAAG,EAAE,WAAW;gBAChB,YAAY,EAAE,YAAY;gBAC1B,IAAI,EAAE;oBACJ,GAAG,EAAE;wBACH,QAAQ,EAAE,iBAAiB,QAAQ,CAAC,YAAY,EAAE;wBAClD,GAAG,EAAE,WAAW;qBACjB;oBACD,GAAG,EAAE;wBACH,QAAQ,EAAE,SAAS,QAAQ,CAAC,IAAI,EAAE;wBAClC,GAAG,EAAE,WAAW;qBACjB;iBACF;gBACD,IAAI,EAAE;oBACJ,IAAI,EAAE,WAAW;oBACjB,SAAS,EAAE,GAAG,QAAQ,CAAC,IAAI,mBAAmB,QAAQ,CAAC,YAAY,WAAW,QAAQ,CAAC,IAAI,EAAE;iBAC9F;aACF,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,mCAAmC;QACnC,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACzD,CAAC;CACF","sourcesContent":["import { BaseFormatter, PipelineFormatterOptions } from './Formatter.js';\nimport { Pipeline } from '../../types/index.js';\n\nexport class AlfredFormatter extends BaseFormatter {\n name = 'alfred';\n \n formatPipelines(pipelines: Pipeline[], _organizations: string[], _options?: PipelineFormatterOptions): string {\n // Format pipelines as Alfred-compatible JSON items\n const alfredItems = pipelines.map((pipeline: Pipeline) => {\n // Generate web URL for the pipeline (if not already present)\n const pipelineUrl = pipeline.url || \n `https://buildkite.com/${pipeline.organization}/${pipeline.slug}`;\n \n const uid = pipeline.uuid;\n const title = pipeline.slug;\n const subtitle = pipeline.description || '';\n const autocomplete = `${pipeline.organization}/${pipeline.name}`;\n const match = `${pipeline.organization}/${pipeline.slug}`;\n\n return {\n uid: uid,\n title: title,\n subtitle: subtitle,\n match: match,\n arg: pipelineUrl,\n autocomplete: autocomplete,\n mods: {\n alt: {\n subtitle: `Organization: ${pipeline.organization}`,\n arg: pipelineUrl\n },\n cmd: {\n subtitle: `Name: ${pipeline.name}`,\n arg: pipelineUrl\n }\n },\n text: {\n copy: pipelineUrl,\n largetype: `${pipeline.name}\\nOrganization: ${pipeline.organization}\\nSlug: ${pipeline.slug}`\n }\n };\n });\n \n // Return formatted JSON for Alfred\n return JSON.stringify({ items: alfredItems }, null, 2);\n }\n} "]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Formatter.js","sourceRoot":"/","sources":["formatters/pipelines/Formatter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"Formatter.js","sourceRoot":"/","sources":["formatters/pipelines/Formatter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAoBlD,MAAM,OAAgB,aAAa;IAKjC,MAAM,CAAI,IAAS,EAAE,QAA2D,EAAE,OAA0B;QAC1G,IAAI,OAAO,EAAE,KAAK,EAAE,CAAC;YACnB,MAAM,CAAC,KAAK,CAAC,mBAAmB,IAAI,CAAC,IAAI,YAAY,CAAC,CAAC;QACzD,CAAC;QACD,OAAO,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACjC,CAAC;CACF","sourcesContent":["import { BaseFormatter as BaseFormatterInterface, FormatterOptions } from '../BaseFormatter.js';\nimport { Pipeline } from '../../types/index.js';\nimport { logger } from '../../services/logger.js';\n\nexport interface PipelineFormatterOptions extends FormatterOptions {\n filterActive?: boolean;\n filterText?: string;\n truncated?: boolean;\n hasMoreAvailable?: boolean; // Whether there are more pipelines on the server\n totalBeforeFilter?: number;\n requestedLimit?: number; // The limit that was requested (via --count or default)\n organizationsCount?: number;\n orgSpecified?: boolean;\n hasError?: boolean;\n errorType?: 'access' | 'not_found' | 'api' | 'generic';\n errorMessage?: string;\n}\n\nexport interface PipelineFormatter extends BaseFormatterInterface {\n formatPipelines(pipelines: Pipeline[], organizations: string[], options?: PipelineFormatterOptions): string;\n}\n\nexport abstract class BaseFormatter implements PipelineFormatter {\n abstract name: string;\n \n abstract formatPipelines(pipelines: Pipeline[], organizations: string[], options?: PipelineFormatterOptions): string;\n \n format<T>(data: T[], formatFn: (data: T[], options?: FormatterOptions) => string, options?: FormatterOptions): string {\n if (options?.debug) {\n logger.debug(`Formatting with ${this.name} formatter`);\n }\n return formatFn(data, options);\n }\n} "]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JsonFormatter.js","sourceRoot":"/","sources":["formatters/pipelines/JsonFormatter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"JsonFormatter.js","sourceRoot":"/","sources":["formatters/pipelines/JsonFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA4B,MAAM,gBAAgB,CAAC;AAGzE,MAAM,OAAO,aAAc,SAAQ,aAAa;IAC9C,IAAI,GAAG,MAAM,CAAC;IAEd,eAAe,CAAC,SAAqB,EAAE,aAAuB,EAAE,QAAmC;QACjG,MAAM,MAAM,GAAG;YACb,KAAK,EAAE,SAAS,CAAC,MAAM;YACvB,aAAa;YACb,SAAS;SACV,CAAC;QAEF,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACzC,CAAC;CACF","sourcesContent":["import { BaseFormatter, PipelineFormatterOptions } from './Formatter.js';\nimport { Pipeline } from '../../types/index.js';\n\nexport class JsonFormatter extends BaseFormatter {\n name = 'json';\n \n formatPipelines(pipelines: Pipeline[], organizations: string[], _options?: PipelineFormatterOptions): string {\n const result = {\n count: pipelines.length,\n organizations,\n pipelines\n };\n \n return JSON.stringify(result, null, 2);\n }\n} "]}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { AbstractFormatter } from '../BaseFormatter.js';
|
|
2
|
+
import { renderTable } from '../../ui/table.js';
|
|
3
|
+
import { renderResponsiveTable, isNarrowTerminal, isMobileTerminal } from '../../ui/responsive-table.js';
|
|
4
|
+
import { SEMANTIC_COLORS, formatEmptyState, formatTips, TipStyle } from '../../ui/theme.js';
|
|
2
5
|
export class PlainTextFormatter extends AbstractFormatter {
|
|
3
6
|
constructor() {
|
|
4
7
|
super('plain-text');
|
|
@@ -6,40 +9,183 @@ export class PlainTextFormatter extends AbstractFormatter {
|
|
|
6
9
|
formatPipelines(pipelines, organizations, options) {
|
|
7
10
|
// If no organizations are found, handle that case
|
|
8
11
|
if (organizations.length === 0) {
|
|
9
|
-
return 'No organizations found
|
|
12
|
+
return formatEmptyState('No organizations found', ['Check your API token has the correct permissions']);
|
|
10
13
|
}
|
|
11
14
|
return this.format(pipelines, this.formatPipelinesImpl.bind(this, organizations), options);
|
|
12
15
|
}
|
|
13
|
-
formatPipelinesImpl(organizations, pipelines,
|
|
16
|
+
formatPipelinesImpl(organizations, pipelines, options) {
|
|
14
17
|
const output = [];
|
|
15
18
|
if (pipelines.length === 0) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
// Build context-aware empty state message
|
|
20
|
+
let message;
|
|
21
|
+
const suggestions = [];
|
|
22
|
+
if (options?.filterActive && options?.filterText) {
|
|
23
|
+
// Filter returned no results
|
|
24
|
+
message = `No pipelines match filter '${SEMANTIC_COLORS.label(options.filterText)}'`;
|
|
25
|
+
suggestions.push('Try a broader search term');
|
|
26
|
+
suggestions.push('The filter searches pipeline names, slugs, and descriptions');
|
|
27
|
+
suggestions.push('Remove the filter to see all pipelines');
|
|
28
|
+
}
|
|
29
|
+
else if (organizations.length === 1) {
|
|
30
|
+
// Specific organization has no pipelines
|
|
31
|
+
message = `No pipelines found in organization ${SEMANTIC_COLORS.label(organizations[0])}`;
|
|
32
|
+
suggestions.push('Check the organization name is correct');
|
|
33
|
+
suggestions.push('Verify you have access to pipelines in this organization');
|
|
34
|
+
suggestions.push('Run "bktide orgs" to see available organizations');
|
|
19
35
|
}
|
|
20
36
|
else {
|
|
21
|
-
|
|
37
|
+
// No pipelines across all organizations
|
|
38
|
+
message = `No pipelines found across ${organizations.length === 0 ? 'any accessible' : organizations.length.toString()} organizations`;
|
|
39
|
+
suggestions.push('Check your API token has the correct permissions');
|
|
40
|
+
suggestions.push('Run "bktide token --check" to verify your access');
|
|
41
|
+
if (organizations.length > 0) {
|
|
42
|
+
suggestions.push('Some organizations may not have any pipelines configured');
|
|
43
|
+
}
|
|
22
44
|
}
|
|
23
|
-
return
|
|
45
|
+
return formatEmptyState(message, suggestions);
|
|
24
46
|
}
|
|
25
|
-
|
|
26
|
-
|
|
47
|
+
// Build table rows
|
|
48
|
+
// Check if we're on a mobile terminal
|
|
49
|
+
if (isMobileTerminal()) {
|
|
50
|
+
// Use a vertical list format for very narrow terminals
|
|
51
|
+
const items = pipelines.map(p => ({
|
|
52
|
+
name: p.name || 'Unknown',
|
|
53
|
+
slug: p.slug || '-',
|
|
54
|
+
org: p.organization || '-'
|
|
55
|
+
}));
|
|
56
|
+
items.forEach((item, i) => {
|
|
57
|
+
if (i > 0)
|
|
58
|
+
output.push(''); // Separator between items
|
|
59
|
+
output.push(SEMANTIC_COLORS.heading(item.name));
|
|
60
|
+
output.push(` ${SEMANTIC_COLORS.label('Slug:')} ${SEMANTIC_COLORS.dim(item.slug)}`);
|
|
61
|
+
if (organizations.length > 1) {
|
|
62
|
+
output.push(` ${SEMANTIC_COLORS.label('Org:')} ${item.org}`);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
27
65
|
}
|
|
28
|
-
else {
|
|
29
|
-
|
|
66
|
+
else if (isNarrowTerminal()) {
|
|
67
|
+
// Use responsive table for narrow terminals
|
|
68
|
+
if (organizations.length > 1) {
|
|
69
|
+
const headers = ['ORGANIZATION', 'NAME', 'SLUG'].map(h => SEMANTIC_COLORS.heading(h));
|
|
70
|
+
const dataRows = pipelines.map((p) => [
|
|
71
|
+
p.organization || SEMANTIC_COLORS.muted('-'),
|
|
72
|
+
p.name || SEMANTIC_COLORS.muted('-'),
|
|
73
|
+
p.slug ? SEMANTIC_COLORS.dim(p.slug) : SEMANTIC_COLORS.muted('-')
|
|
74
|
+
]);
|
|
75
|
+
const columns = [
|
|
76
|
+
{ header: 'ORGANIZATION', priority: 2, minWidth: 8, truncate: true },
|
|
77
|
+
{ header: 'NAME', priority: 10, minWidth: 10, truncate: true },
|
|
78
|
+
{ header: 'SLUG', priority: 5, minWidth: 8, truncate: true }
|
|
79
|
+
];
|
|
80
|
+
output.push(renderResponsiveTable(headers, dataRows, { columns }));
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
const headers = ['NAME', 'SLUG'].map(h => SEMANTIC_COLORS.heading(h));
|
|
84
|
+
const dataRows = pipelines.map((p) => [
|
|
85
|
+
p.name || SEMANTIC_COLORS.muted('-'),
|
|
86
|
+
p.slug ? SEMANTIC_COLORS.dim(p.slug) : SEMANTIC_COLORS.muted('-')
|
|
87
|
+
]);
|
|
88
|
+
const columns = [
|
|
89
|
+
{ header: 'NAME', priority: 10, minWidth: 15, truncate: true },
|
|
90
|
+
{ header: 'SLUG', priority: 5, minWidth: 10, truncate: true }
|
|
91
|
+
];
|
|
92
|
+
output.push(renderResponsiveTable(headers, dataRows, { columns }));
|
|
93
|
+
}
|
|
30
94
|
}
|
|
31
|
-
|
|
95
|
+
else {
|
|
96
|
+
// Use standard table for wide terminals
|
|
97
|
+
const rows = [];
|
|
32
98
|
if (organizations.length > 1) {
|
|
33
|
-
|
|
99
|
+
const headers = ['ORGANIZATION', 'NAME', 'SLUG'].map(h => SEMANTIC_COLORS.heading(h));
|
|
100
|
+
rows.push(headers);
|
|
101
|
+
pipelines.forEach((p) => {
|
|
102
|
+
rows.push([
|
|
103
|
+
p.organization || SEMANTIC_COLORS.muted('-'),
|
|
104
|
+
p.name || SEMANTIC_COLORS.muted('-'),
|
|
105
|
+
p.slug ? SEMANTIC_COLORS.dim(p.slug) : SEMANTIC_COLORS.muted('-')
|
|
106
|
+
]);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
const headers = ['NAME', 'SLUG'].map(h => SEMANTIC_COLORS.heading(h));
|
|
111
|
+
rows.push(headers);
|
|
112
|
+
pipelines.forEach((p) => {
|
|
113
|
+
rows.push([
|
|
114
|
+
p.name || SEMANTIC_COLORS.muted('-'),
|
|
115
|
+
p.slug ? SEMANTIC_COLORS.dim(p.slug) : SEMANTIC_COLORS.muted('-')
|
|
116
|
+
]);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
output.push(renderTable(rows, { preserveWidths: true }));
|
|
120
|
+
}
|
|
121
|
+
// Summary line (dimmed)
|
|
122
|
+
output.push('');
|
|
123
|
+
// Check if we're showing a subset (we hit the limit and there might be more)
|
|
124
|
+
// But NOT when filtering (filtered results are already a subset)
|
|
125
|
+
const isShowingSubset = !options?.filterActive && (options?.hasMoreAvailable ||
|
|
126
|
+
(options?.truncated && pipelines.length >= (options?.requestedLimit || 0)));
|
|
127
|
+
if (organizations.length === 1) {
|
|
128
|
+
if (isShowingSubset) {
|
|
129
|
+
output.push(SEMANTIC_COLORS.dim(`Showing ${SEMANTIC_COLORS.count(pipelines.length.toString())} pipelines from ${organizations[0]}`));
|
|
34
130
|
}
|
|
35
131
|
else {
|
|
36
|
-
output.push(
|
|
132
|
+
output.push(SEMANTIC_COLORS.dim(`${SEMANTIC_COLORS.count(pipelines.length.toString())} ${pipelines.length === 1 ? 'pipeline' : 'pipelines'} in ${organizations[0]}`));
|
|
37
133
|
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
if (isShowingSubset) {
|
|
137
|
+
output.push(SEMANTIC_COLORS.dim(`Showing ${SEMANTIC_COLORS.count(pipelines.length.toString())} pipelines from ${organizations.length} organizations`));
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
output.push(SEMANTIC_COLORS.dim(`${SEMANTIC_COLORS.count(pipelines.length.toString())} pipelines across ${organizations.length} organizations`));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// Add contextual hints based on results
|
|
144
|
+
const hints = [];
|
|
145
|
+
// Add filter hints
|
|
146
|
+
if (options?.filterActive && options?.filterText) {
|
|
147
|
+
output.push(SEMANTIC_COLORS.dim(`Showing pipelines matching '${options.filterText}'`));
|
|
148
|
+
hints.push('Remove --filter to see all pipelines');
|
|
149
|
+
}
|
|
150
|
+
else if (pipelines.length > 20) {
|
|
151
|
+
// Many pipelines - suggest filtering
|
|
152
|
+
hints.push('Use --filter <text> to search by name or description');
|
|
153
|
+
}
|
|
154
|
+
// Add organization hints
|
|
155
|
+
if (organizations.length > 1 && !options?.orgSpecified) {
|
|
156
|
+
hints.push('Use --org <name> to focus on a specific organization');
|
|
157
|
+
if (pipelines.length > 10) {
|
|
158
|
+
hints.push('Pipeline slugs are unique within each organization');
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// Add pagination hints
|
|
162
|
+
if (options?.truncated || options?.hasMoreAvailable) {
|
|
163
|
+
const currentCount = pipelines.length;
|
|
164
|
+
const requestedLimit = options?.requestedLimit || currentCount;
|
|
165
|
+
// Only show pagination hints if we actually hit the limit
|
|
166
|
+
// (not if we got fewer results than requested)
|
|
167
|
+
if (currentCount >= requestedLimit) {
|
|
168
|
+
// Calculate reasonable next count suggestion
|
|
169
|
+
let nextCount;
|
|
170
|
+
if (requestedLimit < 100) {
|
|
171
|
+
nextCount = Math.min(requestedLimit * 2, 100); // Double up to 100
|
|
172
|
+
}
|
|
173
|
+
else if (requestedLimit < 500) {
|
|
174
|
+
nextCount = Math.min(requestedLimit + 100, 500); // Add 100 up to 500
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
nextCount = requestedLimit + 250; // Add 250 for larger requests
|
|
178
|
+
}
|
|
179
|
+
// Show pagination hint without duplicating the count
|
|
180
|
+
if (options?.hasMoreAvailable || options?.truncated) {
|
|
181
|
+
hints.push(`Use --count ${nextCount} to see more`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// Display hints if any
|
|
186
|
+
if (hints.length > 0) {
|
|
187
|
+
output.push('');
|
|
188
|
+
output.push(formatTips(hints, TipStyle.GROUPED));
|
|
43
189
|
}
|
|
44
190
|
return output.join('\n');
|
|
45
191
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlainTextFormatter.js","sourceRoot":"/","sources":["formatters/pipelines/PlainTextFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAI1E,MAAM,OAAO,kBAAmB,SAAQ,iBAAiB;IACvD;QACE,KAAK,CAAC,YAAY,CAAC,CAAC;IACtB,CAAC;IAED,eAAe,CAAC,SAAqB,EAAE,aAAuB,EAAE,OAA0B;QACxF,kDAAkD;QAClD,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO,yBAAyB,CAAC;QACnC,CAAC;QAED,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC,EAAE,OAAO,CAAC,CAAC;IAC7F,CAAC;IAEO,mBAAmB,CAAC,aAAuB,EAAE,SAAqB,EAAE,QAA2B;QACrG,MAAM,MAAM,GAAa,EAAE,CAAC;QAE5B,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;YACnC,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC/B,MAAM,CAAC,IAAI,CAAC,sCAAsC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACzE,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,CAAC,6BAA6B,aAAa,CAAC,MAAM,iBAAiB,CAAC,CAAC;YAClF,CAAC;YACD,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;QAED,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,MAAM,CAAC,IAAI,CAAC,iBAAiB,aAAa,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,MAAM,UAAU,CAAC,CAAC;QAChF,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,wCAAwC,SAAS,CAAC,MAAM,UAAU,CAAC,CAAC;QAClF,CAAC;QAED,SAAS,CAAC,OAAO,CAAC,CAAC,QAAkB,EAAE,EAAE;YACvC,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC7B,MAAM,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,YAAY,KAAK,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,GAAG,CAAC,CAAC;YAClF,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,GAAG,CAAC,CAAC;YACvD,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,8CAA8C;QAC9C,MAAM,CAAC,IAAI,CAAC,WAAW,SAAS,CAAC,MAAM,aAAa,CAAC,CAAC;QAEtD,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,MAAM,CAAC,IAAI,CAAC,qBAAqB,aAAa,CAAC,MAAM,iEAAiE,CAAC,CAAC;QAC1H,CAAC;QAED,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;CACF","sourcesContent":["import { FormatterOptions, AbstractFormatter } from '../BaseFormatter.js';\nimport { PipelineFormatter } from './Formatter.js';\nimport { Pipeline } from '../../types/index.js';\n\nexport class PlainTextFormatter extends AbstractFormatter implements PipelineFormatter {\n constructor() {\n super('plain-text');\n }\n\n formatPipelines(pipelines: Pipeline[], organizations: string[], options?: FormatterOptions): string {\n // If no organizations are found, handle that case\n if (organizations.length === 0) {\n return 'No organizations found.';\n }\n \n return this.format(pipelines, this.formatPipelinesImpl.bind(this, organizations), options);\n }\n\n private formatPipelinesImpl(organizations: string[], pipelines: Pipeline[], _options?: FormatterOptions): string {\n const output: string[] = [];\n \n if (pipelines.length === 0) {\n output.push('No pipelines found.');\n if (organizations.length === 1) {\n output.push(`No pipelines found in organization ${organizations[0]}.`);\n } else {\n output.push(`No pipelines found across ${organizations.length} organizations.`);\n }\n return output.join('\\n');\n }\n \n if (organizations.length === 1) {\n output.push(`Pipelines for ${organizations[0]} (${pipelines.length} total):`);\n } else {\n output.push(`Pipelines across your organizations (${pipelines.length} total):`);\n }\n \n pipelines.forEach((pipeline: Pipeline) => {\n if (organizations.length > 1) {\n output.push(`- [${pipeline.organization}] ${pipeline.name} (${pipeline.slug})`);\n } else {\n output.push(`- ${pipeline.name} (${pipeline.slug})`);\n }\n });\n \n // Summary line showing total pipelines listed\n output.push(`Showing ${pipelines.length} pipelines.`);\n \n if (organizations.length > 1) {\n output.push(`\\nSearched across ${organizations.length} organizations. Use --org to filter to a specific organization.`);\n }\n \n return output.join('\\n');\n }\n} "]}
|
|
1
|
+
{"version":3,"file":"PlainTextFormatter.js","sourceRoot":"/","sources":["formatters/pipelines/PlainTextFormatter.ts"],"names":[],"mappings":"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","sourcesContent":["import { AbstractFormatter } from '../BaseFormatter.js';\nimport { PipelineFormatter, PipelineFormatterOptions } from './Formatter.js';\nimport { Pipeline } from '../../types/index.js';\nimport { renderTable } from '../../ui/table.js';\nimport { renderResponsiveTable, isNarrowTerminal, isMobileTerminal } from '../../ui/responsive-table.js';\nimport { SEMANTIC_COLORS, formatEmptyState, formatTips, TipStyle } from '../../ui/theme.js';\n\nexport class PlainTextFormatter extends AbstractFormatter implements PipelineFormatter {\n constructor() {\n super('plain-text');\n }\n\n formatPipelines(pipelines: Pipeline[], organizations: string[], options?: PipelineFormatterOptions): string {\n // If no organizations are found, handle that case\n if (organizations.length === 0) {\n return formatEmptyState(\n 'No organizations found',\n ['Check your API token has the correct permissions']\n );\n }\n \n return this.format(pipelines, this.formatPipelinesImpl.bind(this, organizations), options);\n }\n\n private formatPipelinesImpl(organizations: string[], pipelines: Pipeline[], options?: PipelineFormatterOptions): string {\n const output: string[] = [];\n \n if (pipelines.length === 0) {\n // Build context-aware empty state message\n let message: string;\n const suggestions: string[] = [];\n \n if (options?.filterActive && options?.filterText) {\n // Filter returned no results\n message = `No pipelines match filter '${SEMANTIC_COLORS.label(options.filterText)}'`;\n suggestions.push('Try a broader search term');\n suggestions.push('The filter searches pipeline names, slugs, and descriptions');\n suggestions.push('Remove the filter to see all pipelines');\n } else if (organizations.length === 1) {\n // Specific organization has no pipelines\n message = `No pipelines found in organization ${SEMANTIC_COLORS.label(organizations[0])}`;\n suggestions.push('Check the organization name is correct');\n suggestions.push('Verify you have access to pipelines in this organization');\n suggestions.push('Run \"bktide orgs\" to see available organizations');\n } else {\n // No pipelines across all organizations\n message = `No pipelines found across ${organizations.length === 0 ? 'any accessible' : organizations.length.toString()} organizations`;\n suggestions.push('Check your API token has the correct permissions');\n suggestions.push('Run \"bktide token --check\" to verify your access');\n if (organizations.length > 0) {\n suggestions.push('Some organizations may not have any pipelines configured');\n }\n }\n \n return formatEmptyState(message, suggestions);\n }\n\n // Build table rows\n // Check if we're on a mobile terminal\n if (isMobileTerminal()) {\n // Use a vertical list format for very narrow terminals\n const items = pipelines.map(p => ({\n name: p.name || 'Unknown',\n slug: p.slug || '-',\n org: p.organization || '-'\n }));\n \n items.forEach((item, i) => {\n if (i > 0) output.push(''); // Separator between items\n output.push(SEMANTIC_COLORS.heading(item.name));\n output.push(` ${SEMANTIC_COLORS.label('Slug:')} ${SEMANTIC_COLORS.dim(item.slug)}`);\n if (organizations.length > 1) {\n output.push(` ${SEMANTIC_COLORS.label('Org:')} ${item.org}`);\n }\n });\n } else if (isNarrowTerminal()) {\n // Use responsive table for narrow terminals\n if (organizations.length > 1) {\n const headers = ['ORGANIZATION', 'NAME', 'SLUG'].map(h => SEMANTIC_COLORS.heading(h));\n const dataRows: string[][] = pipelines.map((p: Pipeline) => [\n p.organization || SEMANTIC_COLORS.muted('-'),\n p.name || SEMANTIC_COLORS.muted('-'),\n p.slug ? SEMANTIC_COLORS.dim(p.slug) : SEMANTIC_COLORS.muted('-')\n ]);\n \n const columns = [\n { header: 'ORGANIZATION', priority: 2, minWidth: 8, truncate: true },\n { header: 'NAME', priority: 10, minWidth: 10, truncate: true },\n { header: 'SLUG', priority: 5, minWidth: 8, truncate: true }\n ];\n \n output.push(renderResponsiveTable(headers, dataRows, { columns }));\n } else {\n const headers = ['NAME', 'SLUG'].map(h => SEMANTIC_COLORS.heading(h));\n const dataRows: string[][] = pipelines.map((p: Pipeline) => [\n p.name || SEMANTIC_COLORS.muted('-'),\n p.slug ? SEMANTIC_COLORS.dim(p.slug) : SEMANTIC_COLORS.muted('-')\n ]);\n \n const columns = [\n { header: 'NAME', priority: 10, minWidth: 15, truncate: true },\n { header: 'SLUG', priority: 5, minWidth: 10, truncate: true }\n ];\n \n output.push(renderResponsiveTable(headers, dataRows, { columns }));\n }\n } else {\n // Use standard table for wide terminals\n const rows: string[][] = [];\n if (organizations.length > 1) {\n const headers = ['ORGANIZATION', 'NAME', 'SLUG'].map(h => SEMANTIC_COLORS.heading(h));\n rows.push(headers);\n pipelines.forEach((p: Pipeline) => {\n rows.push([\n p.organization || SEMANTIC_COLORS.muted('-'),\n p.name || SEMANTIC_COLORS.muted('-'),\n p.slug ? SEMANTIC_COLORS.dim(p.slug) : SEMANTIC_COLORS.muted('-')\n ]);\n });\n } else {\n const headers = ['NAME', 'SLUG'].map(h => SEMANTIC_COLORS.heading(h));\n rows.push(headers);\n pipelines.forEach((p: Pipeline) => {\n rows.push([\n p.name || SEMANTIC_COLORS.muted('-'),\n p.slug ? SEMANTIC_COLORS.dim(p.slug) : SEMANTIC_COLORS.muted('-')\n ]);\n });\n }\n output.push(renderTable(rows, { preserveWidths: true }));\n }\n \n // Summary line (dimmed)\n output.push('');\n \n // Check if we're showing a subset (we hit the limit and there might be more)\n // But NOT when filtering (filtered results are already a subset)\n const isShowingSubset = !options?.filterActive && (\n options?.hasMoreAvailable || \n (options?.truncated && pipelines.length >= (options?.requestedLimit || 0))\n );\n \n if (organizations.length === 1) {\n if (isShowingSubset) {\n output.push(SEMANTIC_COLORS.dim(\n `Showing ${SEMANTIC_COLORS.count(pipelines.length.toString())} pipelines from ${organizations[0]}`\n ));\n } else {\n output.push(SEMANTIC_COLORS.dim(\n `${SEMANTIC_COLORS.count(pipelines.length.toString())} ${pipelines.length === 1 ? 'pipeline' : 'pipelines'} in ${organizations[0]}`\n ));\n }\n } else {\n if (isShowingSubset) {\n output.push(SEMANTIC_COLORS.dim(\n `Showing ${SEMANTIC_COLORS.count(pipelines.length.toString())} pipelines from ${organizations.length} organizations`\n ));\n } else {\n output.push(SEMANTIC_COLORS.dim(\n `${SEMANTIC_COLORS.count(pipelines.length.toString())} pipelines across ${organizations.length} organizations`\n ));\n }\n }\n \n // Add contextual hints based on results\n const hints: string[] = [];\n \n // Add filter hints\n if (options?.filterActive && options?.filterText) {\n output.push(SEMANTIC_COLORS.dim(`Showing pipelines matching '${options.filterText}'`));\n hints.push('Remove --filter to see all pipelines');\n } else if (pipelines.length > 20) {\n // Many pipelines - suggest filtering\n hints.push('Use --filter <text> to search by name or description');\n }\n \n // Add organization hints\n if (organizations.length > 1 && !options?.orgSpecified) {\n hints.push('Use --org <name> to focus on a specific organization');\n if (pipelines.length > 10) {\n hints.push('Pipeline slugs are unique within each organization');\n }\n }\n \n // Add pagination hints\n if (options?.truncated || options?.hasMoreAvailable) {\n const currentCount = pipelines.length;\n const requestedLimit = options?.requestedLimit || currentCount;\n \n // Only show pagination hints if we actually hit the limit\n // (not if we got fewer results than requested)\n if (currentCount >= requestedLimit) {\n // Calculate reasonable next count suggestion\n let nextCount: number;\n if (requestedLimit < 100) {\n nextCount = Math.min(requestedLimit * 2, 100); // Double up to 100\n } else if (requestedLimit < 500) {\n nextCount = Math.min(requestedLimit + 100, 500); // Add 100 up to 500\n } else {\n nextCount = requestedLimit + 250; // Add 250 for larger requests\n }\n \n // Show pagination hint without duplicating the count\n if (options?.hasMoreAvailable || options?.truncated) {\n hints.push(`Use --count ${nextCount} to see more`);\n }\n }\n }\n \n // Display hints if any\n if (hints.length > 0) {\n output.push('');\n output.push(formatTips(hints, TipStyle.GROUPED));\n }\n \n return output.join('\\n');\n }\n} "]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isRunningInAlfred } from '../../utils/alfred.js';
|
|
1
2
|
import { BaseTokenFormatter } from './Formatter.js';
|
|
2
3
|
/**
|
|
3
4
|
* Alfred formatter for tokens
|
|
@@ -108,10 +109,22 @@ export class AlfredFormatter extends BaseTokenFormatter {
|
|
|
108
109
|
}
|
|
109
110
|
formatTokenStatusAsItems(status) {
|
|
110
111
|
const items = [];
|
|
111
|
-
|
|
112
|
+
const inAlfred = isRunningInAlfred();
|
|
113
|
+
// Alfred-first UX: if no token, present actionable item to open config
|
|
114
|
+
if (inAlfred && !status.hasToken) {
|
|
115
|
+
items.push({
|
|
116
|
+
title: 'Set Buildkite token',
|
|
117
|
+
subtitle: 'Open Workflow Configuration to set BUILDKITE_API_TOKEN',
|
|
118
|
+
icon: 'icons/info.png',
|
|
119
|
+
arg: 'alfred:open-config'
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
// Add token status item with context-aware subtitle
|
|
112
123
|
items.push({
|
|
113
124
|
title: `Token Status: ${status.hasToken ? 'Present' : 'Not Present'}`,
|
|
114
|
-
subtitle: status.hasToken
|
|
125
|
+
subtitle: status.hasToken
|
|
126
|
+
? (inAlfred ? 'Token provided via Workflow Configuration' : 'Token is stored in system keychain')
|
|
127
|
+
: (inAlfred ? 'No token set in Workflow Configuration' : 'No token found in system keychain'),
|
|
115
128
|
icon: this.getIcon(status.hasToken),
|
|
116
129
|
arg: status.hasToken ? 'token:present' : 'token:not-present'
|
|
117
130
|
});
|