bktide 1.0.1755267617 → 1.0.1755547716
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +107 -1
- package/WORKFLOW_README.md +1 -1
- package/completions/bktide-dynamic.fish +171 -0
- package/completions/bktide.bash +124 -0
- package/completions/bktide.fish +107 -0
- package/completions/bktide.zsh +139 -0
- package/dist/commands/BaseCommand.js +7 -7
- package/dist/commands/BaseCommand.js.map +1 -1
- package/dist/commands/GenerateCompletions.js +238 -0
- package/dist/commands/GenerateCompletions.js.map +1 -0
- package/dist/commands/ListAnnotations.js +7 -0
- package/dist/commands/ListAnnotations.js.map +1 -1
- package/dist/commands/ListBuilds.js +67 -3
- package/dist/commands/ListBuilds.js.map +1 -1
- package/dist/commands/ListOrganizations.js +6 -0
- package/dist/commands/ListOrganizations.js.map +1 -1
- package/dist/commands/ListPipelines.js +87 -12
- package/dist/commands/ListPipelines.js.map +1 -1
- package/dist/commands/ManageToken.js +32 -9
- package/dist/commands/ManageToken.js.map +1 -1
- package/dist/commands/ShowViewer.js +7 -1
- package/dist/commands/ShowViewer.js.map +1 -1
- package/dist/commands/index.js +1 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/formatters/annotations/PlainTextFormatter.js +37 -9
- package/dist/formatters/annotations/PlainTextFormatter.js.map +1 -1
- package/dist/formatters/builds/PlainTextFormatter.js +82 -60
- package/dist/formatters/builds/PlainTextFormatter.js.map +1 -1
- package/dist/formatters/errors/AlfredFormatter.js +20 -0
- package/dist/formatters/errors/AlfredFormatter.js.map +1 -1
- package/dist/formatters/errors/PlainTextFormatter.js +121 -23
- package/dist/formatters/errors/PlainTextFormatter.js.map +1 -1
- package/dist/formatters/organizations/PlainTextFormatter.js +37 -6
- package/dist/formatters/organizations/PlainTextFormatter.js.map +1 -1
- package/dist/formatters/pipelines/AlfredFormatter.js.map +1 -1
- package/dist/formatters/pipelines/Formatter.js.map +1 -1
- package/dist/formatters/pipelines/JsonFormatter.js.map +1 -1
- package/dist/formatters/pipelines/PlainTextFormatter.js +165 -19
- package/dist/formatters/pipelines/PlainTextFormatter.js.map +1 -1
- package/dist/formatters/token/AlfredFormatter.js +15 -2
- package/dist/formatters/token/AlfredFormatter.js.map +1 -1
- package/dist/formatters/token/PlainTextFormatter.js +56 -18
- package/dist/formatters/token/PlainTextFormatter.js.map +1 -1
- package/dist/formatters/viewer/PlainTextFormatter.js +8 -7
- package/dist/formatters/viewer/PlainTextFormatter.js.map +1 -1
- package/dist/index.js +47 -6
- package/dist/index.js.map +1 -1
- package/dist/services/CredentialManager.js +80 -10
- package/dist/services/CredentialManager.js.map +1 -1
- package/dist/ui/help.js +69 -0
- package/dist/ui/help.js.map +1 -0
- package/dist/ui/progress.js +356 -0
- package/dist/ui/progress.js.map +1 -0
- package/dist/ui/reporter.js +111 -0
- package/dist/ui/reporter.js.map +1 -0
- package/dist/ui/responsive-table.js +183 -0
- package/dist/ui/responsive-table.js.map +1 -0
- package/dist/ui/spinner.js +20 -0
- package/dist/ui/spinner.js.map +1 -0
- package/dist/ui/symbols.js +46 -0
- package/dist/ui/symbols.js.map +1 -0
- package/dist/ui/table.js +32 -0
- package/dist/ui/table.js.map +1 -0
- package/dist/ui/theme.js +280 -0
- package/dist/ui/theme.js.map +1 -0
- package/dist/ui/width.js +111 -0
- package/dist/ui/width.js.map +1 -0
- package/dist/utils/alfred.js +6 -0
- package/dist/utils/alfred.js.map +1 -0
- package/dist/utils/cli-error-handler.js +35 -20
- package/dist/utils/cli-error-handler.js.map +1 -1
- package/dist/utils/pagination.js +92 -0
- package/dist/utils/pagination.js.map +1 -0
- package/info.plist +51 -218
- package/package.json +23 -5
|
@@ -1,23 +1,29 @@
|
|
|
1
1
|
import { BaseCommand } from './BaseCommand.js';
|
|
2
2
|
import { getViewerFormatter } from '../formatters/index.js';
|
|
3
3
|
import { logger } from '../services/logger.js';
|
|
4
|
+
import { Progress } from '../ui/progress.js';
|
|
4
5
|
export class ShowViewer extends BaseCommand {
|
|
5
6
|
constructor(options) {
|
|
6
7
|
super(options);
|
|
7
8
|
}
|
|
8
9
|
async execute(options) {
|
|
9
10
|
await this.ensureInitialized();
|
|
11
|
+
const format = options.format || 'plain';
|
|
12
|
+
const spinner = Progress.spinner('Fetching viewer…', { format });
|
|
10
13
|
try {
|
|
11
14
|
const data = await this.client.getViewer();
|
|
15
|
+
spinner.stop();
|
|
12
16
|
if (!data?.viewer) {
|
|
13
17
|
throw new Error('Invalid response format: missing viewer data');
|
|
14
18
|
}
|
|
15
|
-
const formatter = getViewerFormatter(
|
|
19
|
+
const formatter = getViewerFormatter(format);
|
|
16
20
|
const output = formatter.formatViewer(data, { debug: options.debug });
|
|
17
21
|
logger.console(output);
|
|
22
|
+
// Success is implicit - data display confirms retrieval
|
|
18
23
|
return 0; // Success
|
|
19
24
|
}
|
|
20
25
|
catch (error) {
|
|
26
|
+
spinner.stop();
|
|
21
27
|
this.handleError(error, options.debug);
|
|
22
28
|
return 1; // Error
|
|
23
29
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ShowViewer.js","sourceRoot":"/","sources":["commands/ShowViewer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAsB,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"ShowViewer.js","sourceRoot":"/","sources":["commands/ShowViewer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAsB,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAE/C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAK7C,MAAM,OAAO,UAAW,SAAQ,WAAW;IACzC,YAAY,OAAgC;QAC1C,KAAK,CAAC,OAAO,CAAC,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAsB;QAClC,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAE/B,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC;QACzC,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;QAEjE,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;YAC3C,OAAO,CAAC,IAAI,EAAE,CAAC;YAEf,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;gBAClB,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;YAClE,CAAC;YAED,MAAM,SAAS,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;YAC7C,MAAM,MAAM,GAAG,SAAS,CAAC,YAAY,CAAC,IAA6B,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;YAE/F,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACvB,wDAAwD;YACxD,OAAO,CAAC,CAAC,CAAC,UAAU;QACtB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,EAAE,CAAC;YACf,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;YACvC,OAAO,CAAC,CAAC,CAAC,QAAQ;QACpB,CAAC;IACH,CAAC;CACF","sourcesContent":["import { BaseCommand, BaseCommandOptions } from './BaseCommand.js';\nimport { getViewerFormatter } from '../formatters/index.js';\nimport { ViewerData } from '../types/index.js';\nimport { logger } from '../services/logger.js';\n\nimport { Progress } from '../ui/progress.js';\n\nexport interface ViewerOptions extends BaseCommandOptions {\n}\n\nexport class ShowViewer extends BaseCommand {\n constructor(options?: Partial<ViewerOptions>) {\n super(options);\n }\n \n async execute(options: ViewerOptions): Promise<number> {\n await this.ensureInitialized();\n \n const format = options.format || 'plain';\n const spinner = Progress.spinner('Fetching viewer…', { format });\n \n try {\n const data = await this.client.getViewer();\n spinner.stop();\n \n if (!data?.viewer) {\n throw new Error('Invalid response format: missing viewer data');\n }\n \n const formatter = getViewerFormatter(format);\n const output = formatter.formatViewer(data as unknown as ViewerData, { debug: options.debug });\n \n logger.console(output);\n // Success is implicit - data display confirms retrieval\n return 0; // Success\n } catch (error) {\n spinner.stop();\n this.handleError(error, options.debug);\n return 1; // Error\n }\n }\n} "]}
|
package/dist/commands/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"/","sources":["commands/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC","sourcesContent":["export * from './BaseCommand.js';\nexport * from './ShowViewer.js';\nexport * from './ListOrganizations.js';\nexport * from './ListBuilds.js';\nexport * from './ListPipelines.js';\nexport * from './ManageToken.js';\nexport * from './ListAnnotations.js';
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"/","sources":["commands/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC","sourcesContent":["export * from './BaseCommand.js';\nexport * from './ShowViewer.js';\nexport * from './ListOrganizations.js';\nexport * from './ListBuilds.js';\nexport * from './ListPipelines.js';\nexport * from './ManageToken.js';\nexport * from './ListAnnotations.js';\nexport * from './GenerateCompletions.js';"]}
|
|
@@ -1,25 +1,48 @@
|
|
|
1
1
|
import { BaseFormatter } from './Formatter.js';
|
|
2
2
|
import { formatAnnotationBody } from '../../utils/textFormatter.js';
|
|
3
|
+
import { SEMANTIC_COLORS, formatEmptyState, formatError } from '../../ui/theme.js';
|
|
3
4
|
export class PlainTextFormatter extends BaseFormatter {
|
|
4
5
|
name = 'PlainText';
|
|
5
6
|
formatAnnotations(annotations, options) {
|
|
6
7
|
if (options?.hasError) {
|
|
7
|
-
return
|
|
8
|
+
return formatError(options.errorMessage || 'Failed to fetch annotations', {
|
|
9
|
+
showHelp: true,
|
|
10
|
+
helpCommand: 'bktide annotations --help'
|
|
11
|
+
});
|
|
8
12
|
}
|
|
9
13
|
if (!annotations || annotations.length === 0) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return
|
|
14
|
+
const message = options?.contextFilter
|
|
15
|
+
? `No annotations found for this build with context '${options.contextFilter}'`
|
|
16
|
+
: 'No annotations found for this build';
|
|
17
|
+
return formatEmptyState(message, [
|
|
18
|
+
'Annotations are created by build steps',
|
|
19
|
+
'Check the build has completed and has annotation steps'
|
|
20
|
+
]);
|
|
14
21
|
}
|
|
15
22
|
const lines = [];
|
|
23
|
+
// Style symbols for different annotation types
|
|
24
|
+
const styleSymbols = {
|
|
25
|
+
error: '✖',
|
|
26
|
+
warning: '⚠',
|
|
27
|
+
info: 'ℹ',
|
|
28
|
+
success: '✓'
|
|
29
|
+
};
|
|
30
|
+
// Style colors for different annotation types
|
|
31
|
+
const styleColors = {
|
|
32
|
+
error: SEMANTIC_COLORS.error,
|
|
33
|
+
warning: SEMANTIC_COLORS.warning,
|
|
34
|
+
info: SEMANTIC_COLORS.info,
|
|
35
|
+
success: SEMANTIC_COLORS.success
|
|
36
|
+
};
|
|
16
37
|
annotations.forEach((annotation, index) => {
|
|
17
38
|
if (index > 0) {
|
|
18
39
|
lines.push(''); // Add blank line between annotations
|
|
19
40
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
41
|
+
const symbol = styleSymbols[annotation.style] || '•';
|
|
42
|
+
const colorFn = styleColors[annotation.style] || ((s) => s);
|
|
43
|
+
// Style with symbol and color
|
|
44
|
+
lines.push(colorFn(`${symbol} ${annotation.context} (${annotation.style})`));
|
|
45
|
+
lines.push('');
|
|
23
46
|
// Format the body HTML with proper HTML/markdown handling
|
|
24
47
|
const formattedBody = formatAnnotationBody(annotation.body.html);
|
|
25
48
|
// Indent the formatted body properly
|
|
@@ -27,8 +50,13 @@ export class PlainTextFormatter extends BaseFormatter {
|
|
|
27
50
|
.split('\n')
|
|
28
51
|
.map(line => ` ${line}`)
|
|
29
52
|
.join('\n');
|
|
30
|
-
lines.push(
|
|
53
|
+
lines.push(indentedBody);
|
|
31
54
|
});
|
|
55
|
+
// Add summary if multiple annotations
|
|
56
|
+
if (annotations.length > 1) {
|
|
57
|
+
lines.push('');
|
|
58
|
+
lines.push(SEMANTIC_COLORS.dim(`${SEMANTIC_COLORS.count(annotations.length.toString())} annotations found`));
|
|
59
|
+
}
|
|
32
60
|
return lines.join('\n');
|
|
33
61
|
}
|
|
34
62
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlainTextFormatter.js","sourceRoot":"/","sources":["formatters/annotations/PlainTextFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA8B,MAAM,gBAAgB,CAAC;AAE3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"PlainTextFormatter.js","sourceRoot":"/","sources":["formatters/annotations/PlainTextFormatter.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseFormatter, AnnotationFormatterOptions } from './Formatter.js';\nimport { Annotation } from '../../types/index.js';\nimport { formatAnnotationBody } from '../../utils/textFormatter.js';\nimport { SEMANTIC_COLORS, formatEmptyState, formatError } from '../../ui/theme.js';\n\nexport class PlainTextFormatter extends BaseFormatter {\n name = 'PlainText';\n\n formatAnnotations(annotations: Annotation[], options?: AnnotationFormatterOptions): string {\n if (options?.hasError) {\n return formatError(options.errorMessage || 'Failed to fetch annotations', {\n showHelp: true,\n helpCommand: 'bktide annotations --help'\n });\n }\n\n if (!annotations || annotations.length === 0) {\n const message = options?.contextFilter\n ? `No annotations found for this build with context '${options.contextFilter}'`\n : 'No annotations found for this build';\n \n return formatEmptyState(message, [\n 'Annotations are created by build steps',\n 'Check the build has completed and has annotation steps'\n ]);\n }\n\n const lines: string[] = [];\n \n // Style symbols for different annotation types\n const styleSymbols: Record<string, string> = {\n error: '✖',\n warning: '⚠',\n info: 'ℹ',\n success: '✓'\n };\n \n // Style colors for different annotation types\n const styleColors: Record<string, (s: string) => string> = {\n error: SEMANTIC_COLORS.error,\n warning: SEMANTIC_COLORS.warning,\n info: SEMANTIC_COLORS.info,\n success: SEMANTIC_COLORS.success\n };\n \n annotations.forEach((annotation, index) => {\n if (index > 0) {\n lines.push(''); // Add blank line between annotations\n }\n \n const symbol = styleSymbols[annotation.style] || '•';\n const colorFn = styleColors[annotation.style] || ((s: string) => s);\n \n // Style with symbol and color\n lines.push(colorFn(`${symbol} ${annotation.context} (${annotation.style})`));\n lines.push('');\n \n // Format the body HTML with proper HTML/markdown handling\n const formattedBody = formatAnnotationBody(annotation.body.html);\n \n // Indent the formatted body properly\n const indentedBody = formattedBody\n .split('\\n')\n .map(line => ` ${line}`)\n .join('\\n');\n \n lines.push(indentedBody);\n });\n \n // Add summary if multiple annotations\n if (annotations.length > 1) {\n lines.push('');\n lines.push(SEMANTIC_COLORS.dim(`${SEMANTIC_COLORS.count(annotations.length.toString())} annotations found`));\n }\n\n return lines.join('\\n');\n }\n}\n"]}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { BaseFormatter } from './Formatter.js';
|
|
2
|
+
import { renderTable } from '../../ui/table.js';
|
|
3
|
+
import { renderResponsiveTable, isNarrowTerminal, isMobileTerminal } from '../../ui/responsive-table.js';
|
|
4
|
+
import { SEMANTIC_COLORS, formatBuildStatus, formatEmptyState, formatError, formatTips, TipStyle } from '../../ui/theme.js';
|
|
2
5
|
export class PlainTextFormatter extends BaseFormatter {
|
|
3
6
|
name = 'plain-text';
|
|
4
7
|
formatBuilds(builds, options) {
|
|
@@ -19,95 +22,114 @@ export class PlainTextFormatter extends BaseFormatter {
|
|
|
19
22
|
}
|
|
20
23
|
// Handle empty results (no error, just no data)
|
|
21
24
|
if (builds.length === 0) {
|
|
22
|
-
let
|
|
25
|
+
let message = 'No builds found';
|
|
26
|
+
const suggestions = [];
|
|
23
27
|
// Add user info if provided
|
|
24
28
|
if (options?.userName) {
|
|
25
|
-
|
|
29
|
+
message = `No builds found for ${SEMANTIC_COLORS.label(options.userName)}`;
|
|
26
30
|
if (options?.userEmail || options?.userId) {
|
|
27
|
-
|
|
31
|
+
message += ` ${SEMANTIC_COLORS.dim(`(${options.userEmail || options.userId})`)}`;
|
|
28
32
|
}
|
|
29
|
-
output += '.';
|
|
30
33
|
}
|
|
31
|
-
// Add
|
|
34
|
+
// Add suggestions based on context
|
|
32
35
|
if (!options?.orgSpecified) {
|
|
33
|
-
|
|
36
|
+
suggestions.push('Try specifying an organization with --org <name>');
|
|
34
37
|
}
|
|
35
|
-
|
|
38
|
+
suggestions.push('Use --count to increase the number of results');
|
|
39
|
+
return formatEmptyState(message, suggestions);
|
|
36
40
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
new Date(build.started_at || build.startedAt).toLocaleString() : 'Not started';
|
|
49
|
-
const finishedDate = (build.finished_at || build.finishedAt) ?
|
|
50
|
-
new Date(build.finished_at || build.finishedAt).toLocaleString() : 'Not finished';
|
|
51
|
-
output += `Created: ${createdDate}\n`;
|
|
52
|
-
output += `Started: ${startedDate}\n`;
|
|
53
|
-
output += `Finished: ${finishedDate}\n`;
|
|
54
|
-
output += `URL: ${build.web_url || build.url || 'No URL'}\n`;
|
|
55
|
-
output += '------------------\n';
|
|
56
|
-
}
|
|
57
|
-
catch (error) {
|
|
58
|
-
output += `Error displaying build: ${error}\n`;
|
|
59
|
-
if (options?.debug) {
|
|
60
|
-
output += `Build data: ${JSON.stringify(build, null, 2)}\n`;
|
|
61
|
-
}
|
|
62
|
-
output += '------------------\n';
|
|
63
|
-
}
|
|
41
|
+
const lines = [];
|
|
42
|
+
// Build a tabular summary view for scan-ability
|
|
43
|
+
const headers = ['PIPELINE', 'NUMBER', 'STATE', 'BRANCH'].map(h => SEMANTIC_COLORS.heading(h));
|
|
44
|
+
const dataRows = [];
|
|
45
|
+
builds.forEach((b) => {
|
|
46
|
+
dataRows.push([
|
|
47
|
+
b.pipeline?.slug || SEMANTIC_COLORS.muted('unknown'),
|
|
48
|
+
SEMANTIC_COLORS.identifier(`#${b.number}`),
|
|
49
|
+
formatBuildStatus(b.state || 'UNKNOWN', { useSymbol: false }),
|
|
50
|
+
b.branch || SEMANTIC_COLORS.dim('(no branch)')
|
|
51
|
+
]);
|
|
64
52
|
});
|
|
65
|
-
//
|
|
66
|
-
|
|
53
|
+
// Use responsive table for narrow terminals
|
|
54
|
+
if (isNarrowTerminal()) {
|
|
55
|
+
// Configure columns with priorities for narrow displays
|
|
56
|
+
const columns = [
|
|
57
|
+
{ header: 'PIPELINE', priority: 3, minWidth: 10, truncate: true },
|
|
58
|
+
{ header: 'NUMBER', priority: 10, minWidth: 6, align: 'right' },
|
|
59
|
+
{ header: 'STATE', priority: 9, minWidth: 8 },
|
|
60
|
+
{ header: 'BRANCH', priority: 1, minWidth: 6, truncate: true }
|
|
61
|
+
];
|
|
62
|
+
if (isMobileTerminal()) {
|
|
63
|
+
// For very narrow terminals, show only most important columns
|
|
64
|
+
columns[0].priority = 2; // Lower pipeline priority
|
|
65
|
+
columns[3].priority = 0; // Hide branch on mobile
|
|
66
|
+
}
|
|
67
|
+
lines.push(renderResponsiveTable(headers, dataRows, { columns }));
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
// Use standard table for wide terminals
|
|
71
|
+
const rows = [headers, ...dataRows];
|
|
72
|
+
lines.push(renderTable(rows, { preserveWidths: true }));
|
|
73
|
+
}
|
|
74
|
+
// Summary line (dimmed as auxiliary info)
|
|
75
|
+
lines.push('');
|
|
76
|
+
lines.push(SEMANTIC_COLORS.dim(`Found ${SEMANTIC_COLORS.count(builds.length.toString())} builds`));
|
|
77
|
+
// Add contextual hints if searching multiple orgs
|
|
67
78
|
if (options?.organizationsCount && options.organizationsCount > 1 && !options.orgSpecified) {
|
|
68
|
-
|
|
79
|
+
const hints = [`Searched across ${options.organizationsCount} organizations. Use --org to filter to a specific organization.`];
|
|
80
|
+
lines.push('');
|
|
81
|
+
lines.push(formatTips(hints, TipStyle.INDIVIDUAL));
|
|
69
82
|
}
|
|
70
|
-
return
|
|
83
|
+
return lines.join('\n');
|
|
71
84
|
}
|
|
72
85
|
formatAccessError(options) {
|
|
73
|
-
let
|
|
74
|
-
if (options?.userName) {
|
|
75
|
-
output = `No builds found for ${options.userName}`;
|
|
76
|
-
if (options?.userEmail || options?.userId) {
|
|
77
|
-
output += ` (${options.userEmail || options.userId})`;
|
|
78
|
-
}
|
|
79
|
-
output += '. ';
|
|
80
|
-
}
|
|
86
|
+
let message = 'Access Denied';
|
|
81
87
|
if (options?.orgSpecified && options?.accessErrors && options.accessErrors.length > 0) {
|
|
82
|
-
|
|
88
|
+
message = options.accessErrors[0];
|
|
83
89
|
}
|
|
84
90
|
else {
|
|
85
|
-
|
|
91
|
+
message = 'You don\'t have access to the specified organization(s).';
|
|
86
92
|
}
|
|
87
|
-
return
|
|
93
|
+
return formatError(message, {
|
|
94
|
+
showHelp: true,
|
|
95
|
+
helpCommand: 'bktide orgs',
|
|
96
|
+
suggestions: [
|
|
97
|
+
'Check your organization name is correct',
|
|
98
|
+
'Run "bktide orgs" to see available organizations',
|
|
99
|
+
'Verify your token has the correct permissions'
|
|
100
|
+
]
|
|
101
|
+
});
|
|
88
102
|
}
|
|
89
103
|
formatNotFoundError(options) {
|
|
90
|
-
let
|
|
104
|
+
let message = 'No builds found';
|
|
91
105
|
if (options?.userName) {
|
|
92
|
-
|
|
106
|
+
message = `No builds found for ${options.userName}`;
|
|
93
107
|
if (options?.userEmail || options?.userId) {
|
|
94
|
-
|
|
108
|
+
message += ` (${options.userEmail || options.userId})`;
|
|
95
109
|
}
|
|
96
|
-
output += '.';
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
output = 'No builds found.';
|
|
100
110
|
}
|
|
111
|
+
const suggestions = [];
|
|
101
112
|
if (!options?.orgSpecified) {
|
|
102
|
-
|
|
113
|
+
suggestions.push('Try specifying an organization with --org <name>');
|
|
103
114
|
}
|
|
104
|
-
|
|
115
|
+
suggestions.push('Check your filters are correct');
|
|
116
|
+
suggestions.push('Try broadening your search');
|
|
117
|
+
return formatEmptyState(message, suggestions);
|
|
105
118
|
}
|
|
106
119
|
formatApiError(options) {
|
|
107
|
-
|
|
120
|
+
const message = options?.errorMessage || 'Failed to fetch builds from Buildkite';
|
|
121
|
+
return formatError(message, {
|
|
122
|
+
showHelp: true,
|
|
123
|
+
helpCommand: 'bktide builds --help',
|
|
124
|
+
suggestions: ['This might be a temporary issue. Try again in a moment.']
|
|
125
|
+
});
|
|
108
126
|
}
|
|
109
127
|
formatGenericError(options) {
|
|
110
|
-
|
|
128
|
+
const message = options?.errorMessage || 'An unexpected error occurred';
|
|
129
|
+
return formatError(message, {
|
|
130
|
+
showHelp: true,
|
|
131
|
+
helpCommand: 'bktide builds --help'
|
|
132
|
+
});
|
|
111
133
|
}
|
|
112
134
|
}
|
|
113
135
|
//# sourceMappingURL=PlainTextFormatter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlainTextFormatter.js","sourceRoot":"/","sources":["formatters/builds/PlainTextFormatter.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseFormatter, BuildFormatterOptions } from './Formatter.js';\nimport { Build } from '../../types/index.js';\n\nexport class PlainTextFormatter extends BaseFormatter {\n name = 'plain-text';\n \n formatBuilds(builds: Build[], options?: BuildFormatterOptions): string {\n // Handle error cases first\n if (options?.hasError) {\n if (options.errorType === 'access') {\n return this.formatAccessError(options);\n } else if (options.errorType === 'not_found') {\n return this.formatNotFoundError(options);\n } else if (options.errorType === 'api') {\n return this.formatApiError(options);\n } else {\n return this.formatGenericError(options);\n }\n }\n \n // Handle empty results (no error, just no data)\n if (builds.length === 0) {\n let output = 'No builds found.';\n \n // Add user info if provided\n if (options?.userName) {\n output = `No builds found for ${options.userName}`;\n if (options?.userEmail || options?.userId) {\n output += ` (${options.userEmail || options.userId})`;\n }\n output += '.';\n }\n \n // Add organization suggestion if applicable\n if (!options?.orgSpecified) {\n output += '\\nTry specifying an organization with --org to narrow your search.';\n }\n \n return output;\n }\n\n let output = `Found ${builds.length} builds:\\n`;\n output += '==============================================\\n';\n \n builds.forEach((build: Build) => {\n try {\n output += `${build.pipeline?.slug || 'Unknown pipeline'} #${build.number}\\n`;\n output += `State: ${build.state || 'Unknown'}\\n`;\n output += `Branch: ${build.branch || 'Unknown'}\\n`;\n output += `Message: ${build.message || 'No message'}\\n`;\n \n const createdDate = (build.created_at || build.createdAt) ? \n new Date(build.created_at || build.createdAt as string).toLocaleString() : 'Unknown';\n \n const startedDate = (build.started_at || build.startedAt) ? \n new Date(build.started_at || build.startedAt as string).toLocaleString() : 'Not started';\n \n const finishedDate = (build.finished_at || build.finishedAt) ? \n new Date(build.finished_at || build.finishedAt as string).toLocaleString() : 'Not finished';\n \n output += `Created: ${createdDate}\\n`;\n output += `Started: ${startedDate}\\n`;\n output += `Finished: ${finishedDate}\\n`;\n output += `URL: ${build.web_url || build.url || 'No URL'}\\n`;\n output += '------------------\\n';\n } catch (error) {\n output += `Error displaying build: ${error}\\n`;\n if (options?.debug) {\n output += `Build data: ${JSON.stringify(build, null, 2)}\\n`;\n }\n output += '------------------\\n';\n }\n });\n \n // Summary and guidance lines\n output += `\\nShowing ${builds.length} builds. Use --count and --page options to see more.\\n`;\n if (options?.organizationsCount && options.organizationsCount > 1 && !options.orgSpecified) {\n output += `Searched across ${options.organizationsCount} organizations. Use --org to filter to a specific organization.\\n`;\n }\n \n return output;\n }\n \n private formatAccessError(options?: BuildFormatterOptions): string {\n let output = '';\n \n if (options?.userName) {\n output = `No builds found for ${options.userName}`;\n if (options?.userEmail || options?.userId) {\n output += ` (${options.userEmail || options.userId})`;\n }\n output += '. ';\n }\n \n if (options?.orgSpecified && options?.accessErrors && options.accessErrors.length > 0) {\n output += options.accessErrors[0];\n } else {\n output += 'You don\\'t have access to the specified organization(s).';\n }\n \n return output;\n }\n \n private formatNotFoundError(options?: BuildFormatterOptions): string {\n let output = '';\n \n if (options?.userName) {\n output = `No builds found for ${options.userName}`;\n if (options?.userEmail || options?.userId) {\n output += ` (${options.userEmail || options.userId})`;\n }\n output += '.';\n } else {\n output = 'No builds found.';\n }\n \n if (!options?.orgSpecified) {\n output += '\\nTry specifying an organization with --org to narrow your search.';\n }\n \n return output;\n }\n \n private formatApiError(options?: BuildFormatterOptions): string {\n return options?.errorMessage || 'An API error occurred while fetching builds.';\n }\n \n private formatGenericError(options?: BuildFormatterOptions): string {\n return options?.errorMessage || 'An error occurred while fetching builds.';\n }\n} "]}
|
|
1
|
+
{"version":3,"file":"PlainTextFormatter.js","sourceRoot":"/","sources":["formatters/builds/PlainTextFormatter.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseFormatter, BuildFormatterOptions } from './Formatter.js';\nimport { Build } from '../../types/index.js';\nimport { renderTable } from '../../ui/table.js';\nimport { renderResponsiveTable, isNarrowTerminal, isMobileTerminal } from '../../ui/responsive-table.js';\nimport { \n SEMANTIC_COLORS, \n formatBuildStatus,\n formatEmptyState,\n formatError,\n formatTips,\n TipStyle\n} from '../../ui/theme.js';\n\nexport class PlainTextFormatter extends BaseFormatter {\n name = 'plain-text';\n \n formatBuilds(builds: Build[], options?: BuildFormatterOptions): string {\n // Handle error cases first\n if (options?.hasError) {\n if (options.errorType === 'access') {\n return this.formatAccessError(options);\n } else if (options.errorType === 'not_found') {\n return this.formatNotFoundError(options);\n } else if (options.errorType === 'api') {\n return this.formatApiError(options);\n } else {\n return this.formatGenericError(options);\n }\n }\n \n // Handle empty results (no error, just no data)\n if (builds.length === 0) {\n let message = 'No builds found';\n const suggestions: string[] = [];\n \n // Add user info if provided\n if (options?.userName) {\n message = `No builds found for ${SEMANTIC_COLORS.label(options.userName)}`;\n if (options?.userEmail || options?.userId) {\n message += ` ${SEMANTIC_COLORS.dim(`(${options.userEmail || options.userId})`)}`;\n }\n }\n \n // Add suggestions based on context\n if (!options?.orgSpecified) {\n suggestions.push('Try specifying an organization with --org <name>');\n }\n suggestions.push('Use --count to increase the number of results');\n \n return formatEmptyState(message, suggestions);\n }\n\n const lines: string[] = [];\n \n // Build a tabular summary view for scan-ability\n const headers = ['PIPELINE', 'NUMBER', 'STATE', 'BRANCH'].map(\n h => SEMANTIC_COLORS.heading(h)\n );\n \n const dataRows: string[][] = [];\n builds.forEach((b: Build) => {\n dataRows.push([\n b.pipeline?.slug || SEMANTIC_COLORS.muted('unknown'),\n SEMANTIC_COLORS.identifier(`#${b.number}`),\n formatBuildStatus(b.state || 'UNKNOWN', { useSymbol: false }),\n b.branch || SEMANTIC_COLORS.dim('(no branch)')\n ]);\n });\n \n // Use responsive table for narrow terminals\n if (isNarrowTerminal()) {\n // Configure columns with priorities for narrow displays\n const columns = [\n { header: 'PIPELINE', priority: 3, minWidth: 10, truncate: true },\n { header: 'NUMBER', priority: 10, minWidth: 6, align: 'right' as const },\n { header: 'STATE', priority: 9, minWidth: 8 },\n { header: 'BRANCH', priority: 1, minWidth: 6, truncate: true }\n ];\n \n if (isMobileTerminal()) {\n // For very narrow terminals, show only most important columns\n columns[0].priority = 2; // Lower pipeline priority\n columns[3].priority = 0; // Hide branch on mobile\n }\n \n lines.push(renderResponsiveTable(headers, dataRows, { columns }));\n } else {\n // Use standard table for wide terminals\n const rows: string[][] = [headers, ...dataRows];\n lines.push(renderTable(rows, { preserveWidths: true }));\n }\n \n // Summary line (dimmed as auxiliary info)\n lines.push('');\n lines.push(SEMANTIC_COLORS.dim(`Found ${SEMANTIC_COLORS.count(builds.length.toString())} builds`));\n \n // Add contextual hints if searching multiple orgs\n if (options?.organizationsCount && options.organizationsCount > 1 && !options.orgSpecified) {\n const hints = [`Searched across ${options.organizationsCount} organizations. Use --org to filter to a specific organization.`];\n lines.push('');\n lines.push(formatTips(hints, TipStyle.INDIVIDUAL));\n }\n \n return lines.join('\\n');\n }\n \n private formatAccessError(options?: BuildFormatterOptions): string {\n let message = 'Access Denied';\n \n if (options?.orgSpecified && options?.accessErrors && options.accessErrors.length > 0) {\n message = options.accessErrors[0];\n } else {\n message = 'You don\\'t have access to the specified organization(s).';\n }\n \n return formatError(message, {\n showHelp: true,\n helpCommand: 'bktide orgs',\n suggestions: [\n 'Check your organization name is correct',\n 'Run \"bktide orgs\" to see available organizations',\n 'Verify your token has the correct permissions'\n ]\n });\n }\n \n private formatNotFoundError(options?: BuildFormatterOptions): string {\n let message = 'No builds found';\n \n if (options?.userName) {\n message = `No builds found for ${options.userName}`;\n if (options?.userEmail || options?.userId) {\n message += ` (${options.userEmail || options.userId})`;\n }\n }\n \n const suggestions: string[] = [];\n if (!options?.orgSpecified) {\n suggestions.push('Try specifying an organization with --org <name>');\n }\n suggestions.push('Check your filters are correct');\n suggestions.push('Try broadening your search');\n \n return formatEmptyState(message, suggestions);\n }\n \n private formatApiError(options?: BuildFormatterOptions): string {\n const message = options?.errorMessage || 'Failed to fetch builds from Buildkite';\n return formatError(message, {\n showHelp: true,\n helpCommand: 'bktide builds --help',\n suggestions: ['This might be a temporary issue. Try again in a moment.']\n });\n }\n \n private formatGenericError(options?: BuildFormatterOptions): string {\n const message = options?.errorMessage || 'An unexpected error occurred';\n return formatError(message, {\n showHelp: true,\n helpCommand: 'bktide builds --help'\n });\n }\n} "]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseErrorFormatter } from './Formatter.js';
|
|
2
|
+
import { isRunningInAlfred } from '../../utils/alfred.js';
|
|
2
3
|
/**
|
|
3
4
|
* Alfred formatter for errors
|
|
4
5
|
*
|
|
@@ -16,6 +17,25 @@ export class AlfredFormatter extends BaseErrorFormatter {
|
|
|
16
17
|
*/
|
|
17
18
|
formatError(errors, options) {
|
|
18
19
|
const errorArray = Array.isArray(errors) ? errors : [errors];
|
|
20
|
+
// Alfred first-run UX: if running in Alfred and token is missing, show setup item
|
|
21
|
+
const missingToken = errorArray.some(err => {
|
|
22
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
23
|
+
return /API token required|No token/i.test(msg);
|
|
24
|
+
});
|
|
25
|
+
if (isRunningInAlfred() && missingToken && !process.env.BUILDKITE_API_TOKEN && !process.env.BK_TOKEN) {
|
|
26
|
+
return JSON.stringify({
|
|
27
|
+
items: [
|
|
28
|
+
{
|
|
29
|
+
uid: 'set-token',
|
|
30
|
+
title: 'Set Buildkite token',
|
|
31
|
+
subtitle: 'Open Workflow Configuration to paste your token',
|
|
32
|
+
arg: 'alfred:open-config',
|
|
33
|
+
icon: { path: 'icons/info.png' },
|
|
34
|
+
valid: true
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
});
|
|
38
|
+
}
|
|
19
39
|
const items = [];
|
|
20
40
|
for (const error of errorArray) {
|
|
21
41
|
// Add main error item
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AlfredFormatter.js","sourceRoot":"/","sources":["formatters/errors/AlfredFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAyC,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"AlfredFormatter.js","sourceRoot":"/","sources":["formatters/errors/AlfredFormatter.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseErrorFormatter, ErrorFormatter, ErrorFormatterOptions } from './Formatter.js';\nimport { isRunningInAlfred } from '../../utils/alfred.js';\n\n/**\n * Alfred formatter for errors\n * \n * This formatter provides Alfred-compatible JSON output for error conditions\n * that can be processed by Alfred workflows\n */\nexport class AlfredFormatter extends BaseErrorFormatter implements ErrorFormatter {\n name = 'alfred';\n\n /**\n * Format one or more errors for display in Alfred JSON format\n * \n * @param errors The error(s) to format\n * @param options Formatting options\n * @returns Alfred JSON formatted error message\n */\n formatError(errors: unknown | unknown[], options?: ErrorFormatterOptions): string {\n const errorArray = Array.isArray(errors) ? errors : [errors];\n\n // Alfred first-run UX: if running in Alfred and token is missing, show setup item\n const missingToken = errorArray.some(err => {\n const msg = err instanceof Error ? err.message : String(err);\n return /API token required|No token/i.test(msg);\n });\n if (isRunningInAlfred() && missingToken && !process.env.BUILDKITE_API_TOKEN && !process.env.BK_TOKEN) {\n return JSON.stringify({\n items: [\n {\n uid: 'set-token',\n title: 'Set Buildkite token',\n subtitle: 'Open Workflow Configuration to paste your token',\n arg: 'alfred:open-config',\n icon: { path: 'icons/info.png' },\n valid: true\n }\n ]\n });\n }\n const items = [];\n\n for (const error of errorArray) {\n // Add main error item\n items.push({\n uid: 'error',\n title: `Error: ${this.getErrorMessage(error)}`,\n subtitle: this.getErrorSubtitle(error),\n arg: this.getErrorMessage(error),\n icon: {\n path: 'icons/error.png'\n },\n valid: true\n });\n\n // Add stack trace items if debug is enabled\n if (options?.debug) {\n const stack = this.getStackTrace(error);\n if (stack) {\n const stackItems = stack.split('\\n').map((line, index) => ({\n uid: `stack-${index}`,\n title: line.trim(),\n subtitle: 'Stack trace line',\n arg: line,\n icon: {\n path: 'icons/stack.png'\n },\n valid: true\n }));\n items.push(...stackItems);\n }\n\n // Add API errors if present\n const apiErrors = this.getApiErrors(error);\n if (apiErrors?.length) {\n apiErrors.forEach((apiError, index) => {\n items.push({\n uid: `api-error-${index}`,\n title: `API Error: ${apiError.message || 'Unknown error'}`,\n subtitle: apiError.path ? `Path: ${apiError.path.join('.')}` : 'API Error',\n arg: apiError.message || 'Unknown error',\n icon: {\n path: 'icons/api-error.png'\n },\n valid: true\n });\n });\n }\n\n // Add request details if available\n const request = this.getRequestDetails(error);\n if (request) {\n items.push({\n uid: 'request-details',\n title: 'Request Details',\n subtitle: `${request.method || 'Unknown'} ${request.url || 'Unknown URL'}`,\n arg: `${request.method || 'Unknown'} ${request.url || 'Unknown URL'}`,\n icon: {\n path: 'icons/request.png'\n },\n valid: false\n });\n }\n }\n }\n\n // Add system info if debug is enabled\n if (options?.debug) {\n items.push({\n uid: 'system-info',\n title: 'System Information',\n subtitle: `Node ${process.version} on ${process.platform} (${process.arch})`,\n arg: `Node ${process.version} on ${process.platform} (${process.arch})`,\n icon: {\n path: 'icons/info.png'\n },\n valid: false\n });\n }\n\n return JSON.stringify({ items });\n }\n\n /**\n * Get a subtitle for the error to display in Alfred\n * @param error The error object\n * @returns A subtitle string\n */\n private getErrorSubtitle(error: unknown): string {\n const errorName = this.getErrorName(error);\n const apiErrors = this.getApiErrors(error);\n \n if (apiErrors?.length) {\n const firstError = apiErrors[0];\n return `API Error: ${firstError.message || 'Unknown error'}`;\n }\n \n return `${errorName} - Press Enter to copy error message`;\n }\n} "]}
|