bktide 1.0.1755267617 → 1.0.1755559112

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/README.md +107 -1
  2. package/WORKFLOW_README.md +1 -1
  3. package/completions/bktide-dynamic.fish +171 -0
  4. package/completions/bktide.bash +124 -0
  5. package/completions/bktide.fish +107 -0
  6. package/completions/bktide.zsh +139 -0
  7. package/dist/commands/BaseCommand.js +7 -7
  8. package/dist/commands/BaseCommand.js.map +1 -1
  9. package/dist/commands/GenerateCompletions.js +238 -0
  10. package/dist/commands/GenerateCompletions.js.map +1 -0
  11. package/dist/commands/ListAnnotations.js +7 -0
  12. package/dist/commands/ListAnnotations.js.map +1 -1
  13. package/dist/commands/ListBuilds.js +67 -3
  14. package/dist/commands/ListBuilds.js.map +1 -1
  15. package/dist/commands/ListOrganizations.js +6 -0
  16. package/dist/commands/ListOrganizations.js.map +1 -1
  17. package/dist/commands/ListPipelines.js +87 -12
  18. package/dist/commands/ListPipelines.js.map +1 -1
  19. package/dist/commands/ManageToken.js +32 -9
  20. package/dist/commands/ManageToken.js.map +1 -1
  21. package/dist/commands/ShowBuild.js +88 -0
  22. package/dist/commands/ShowBuild.js.map +1 -0
  23. package/dist/commands/ShowViewer.js +7 -1
  24. package/dist/commands/ShowViewer.js.map +1 -1
  25. package/dist/commands/index.js +2 -0
  26. package/dist/commands/index.js.map +1 -1
  27. package/dist/formatters/FormatterFactory.js +4 -0
  28. package/dist/formatters/FormatterFactory.js.map +1 -1
  29. package/dist/formatters/annotations/PlainTextFormatter.js +37 -9
  30. package/dist/formatters/annotations/PlainTextFormatter.js.map +1 -1
  31. package/dist/formatters/build-detail/AlfredFormatter.js +113 -0
  32. package/dist/formatters/build-detail/AlfredFormatter.js.map +1 -0
  33. package/dist/formatters/build-detail/Formatter.js +3 -0
  34. package/dist/formatters/build-detail/Formatter.js.map +1 -0
  35. package/dist/formatters/build-detail/JsonFormatter.js +132 -0
  36. package/dist/formatters/build-detail/JsonFormatter.js.map +1 -0
  37. package/dist/formatters/build-detail/PlainTextFormatter.js +680 -0
  38. package/dist/formatters/build-detail/PlainTextFormatter.js.map +1 -0
  39. package/dist/formatters/build-detail/index.js +21 -0
  40. package/dist/formatters/build-detail/index.js.map +1 -0
  41. package/dist/formatters/builds/PlainTextFormatter.js +82 -60
  42. package/dist/formatters/builds/PlainTextFormatter.js.map +1 -1
  43. package/dist/formatters/errors/AlfredFormatter.js +20 -0
  44. package/dist/formatters/errors/AlfredFormatter.js.map +1 -1
  45. package/dist/formatters/errors/PlainTextFormatter.js +121 -23
  46. package/dist/formatters/errors/PlainTextFormatter.js.map +1 -1
  47. package/dist/formatters/organizations/PlainTextFormatter.js +37 -6
  48. package/dist/formatters/organizations/PlainTextFormatter.js.map +1 -1
  49. package/dist/formatters/pipelines/AlfredFormatter.js.map +1 -1
  50. package/dist/formatters/pipelines/Formatter.js.map +1 -1
  51. package/dist/formatters/pipelines/JsonFormatter.js.map +1 -1
  52. package/dist/formatters/pipelines/PlainTextFormatter.js +165 -19
  53. package/dist/formatters/pipelines/PlainTextFormatter.js.map +1 -1
  54. package/dist/formatters/token/AlfredFormatter.js +15 -2
  55. package/dist/formatters/token/AlfredFormatter.js.map +1 -1
  56. package/dist/formatters/token/PlainTextFormatter.js +56 -18
  57. package/dist/formatters/token/PlainTextFormatter.js.map +1 -1
  58. package/dist/formatters/viewer/PlainTextFormatter.js +8 -7
  59. package/dist/formatters/viewer/PlainTextFormatter.js.map +1 -1
  60. package/dist/graphql/queries.js +181 -0
  61. package/dist/graphql/queries.js.map +1 -1
  62. package/dist/index.js +67 -6
  63. package/dist/index.js.map +1 -1
  64. package/dist/services/BuildkiteClient.js +61 -1
  65. package/dist/services/BuildkiteClient.js.map +1 -1
  66. package/dist/services/CredentialManager.js +80 -10
  67. package/dist/services/CredentialManager.js.map +1 -1
  68. package/dist/ui/help.js +69 -0
  69. package/dist/ui/help.js.map +1 -0
  70. package/dist/ui/progress.js +356 -0
  71. package/dist/ui/progress.js.map +1 -0
  72. package/dist/ui/reporter.js +111 -0
  73. package/dist/ui/reporter.js.map +1 -0
  74. package/dist/ui/responsive-table.js +183 -0
  75. package/dist/ui/responsive-table.js.map +1 -0
  76. package/dist/ui/spinner.js +20 -0
  77. package/dist/ui/spinner.js.map +1 -0
  78. package/dist/ui/symbols.js +46 -0
  79. package/dist/ui/symbols.js.map +1 -0
  80. package/dist/ui/table.js +32 -0
  81. package/dist/ui/table.js.map +1 -0
  82. package/dist/ui/theme.js +280 -0
  83. package/dist/ui/theme.js.map +1 -0
  84. package/dist/ui/width.js +111 -0
  85. package/dist/ui/width.js.map +1 -0
  86. package/dist/utils/alfred.js +6 -0
  87. package/dist/utils/alfred.js.map +1 -0
  88. package/dist/utils/cli-error-handler.js +35 -20
  89. package/dist/utils/cli-error-handler.js.map +1 -1
  90. package/dist/utils/pagination.js +92 -0
  91. package/dist/utils/pagination.js.map +1 -0
  92. package/info.plist +51 -218
  93. package/package.json +24 -5
@@ -0,0 +1,88 @@
1
+ import { BaseCommand } from './BaseCommand.js';
2
+ import { logger } from '../services/logger.js';
3
+ import { parseBuildRef } from '../utils/parseBuildRef.js';
4
+ import { FormatterFactory, FormatterType } from '../formatters/index.js';
5
+ import { Progress } from '../ui/progress.js';
6
+ export class ShowBuild extends BaseCommand {
7
+ static requiresToken = true;
8
+ async execute(options) {
9
+ if (options.debug) {
10
+ logger.debug('Starting ShowBuild command execution', options);
11
+ }
12
+ if (!options.buildArg) {
13
+ logger.error('Build reference is required');
14
+ return 1;
15
+ }
16
+ // Adjust options based on implications
17
+ const adjustedOptions = { ...options };
18
+ if (options.failed) {
19
+ adjustedOptions.jobs = true; // --failed implies --jobs
20
+ }
21
+ if (options.annotationsFull) {
22
+ adjustedOptions.annotations = true; // --annotations-full implies --annotations
23
+ }
24
+ if (options.full) {
25
+ // --full shows everything
26
+ adjustedOptions.jobs = true;
27
+ adjustedOptions.annotations = true;
28
+ }
29
+ // Initialize spinner early
30
+ const format = options.format || 'plain';
31
+ const spinner = Progress.spinner('Fetching build details…', { format });
32
+ try {
33
+ // Ensure the command is initialized
34
+ await this.ensureInitialized();
35
+ // Parse build reference
36
+ const buildRef = parseBuildRef(options.buildArg);
37
+ if (options.debug) {
38
+ logger.debug('Parsed build reference:', buildRef);
39
+ }
40
+ // Construct build slug for GraphQL
41
+ const buildSlug = `${buildRef.org}/${buildRef.pipeline}/${buildRef.number}`;
42
+ // Fetch build data based on what's needed
43
+ const buildData = await this.fetchBuildData(buildSlug, adjustedOptions);
44
+ spinner.stop();
45
+ // Get the appropriate formatter
46
+ const formatter = FormatterFactory.getFormatter(FormatterType.BUILD_DETAIL, options.format || 'plain');
47
+ // Format and output the results
48
+ const output = formatter.formatBuildDetail(buildData, adjustedOptions);
49
+ logger.console(output);
50
+ return 0;
51
+ }
52
+ catch (error) {
53
+ spinner.stop();
54
+ logger.error('Failed to fetch build:', error);
55
+ // Handle the error with the formatter
56
+ const formatter = FormatterFactory.getFormatter(FormatterType.BUILD_DETAIL, options.format || 'plain');
57
+ const errorOutput = formatter.formatBuildDetail(null, {
58
+ ...adjustedOptions,
59
+ hasError: true,
60
+ errorMessage: error instanceof Error ? error.message : 'Unknown error occurred',
61
+ errorType: 'api',
62
+ });
63
+ logger.console(errorOutput);
64
+ return 1;
65
+ }
66
+ }
67
+ async fetchBuildData(buildSlug, options) {
68
+ // Determine what data we need to fetch based on options
69
+ const needsJobs = options.jobs || options.failed || options.full;
70
+ const needsAnnotations = options.annotations || options.annotationsFull || options.full;
71
+ if (options.debug) {
72
+ logger.debug('Fetching build data', {
73
+ buildSlug,
74
+ needsJobs,
75
+ needsAnnotations,
76
+ full: options.full
77
+ });
78
+ }
79
+ // Fetch the appropriate level of detail
80
+ if (options.full || needsJobs) {
81
+ return await this.client.getBuildFull(buildSlug);
82
+ }
83
+ else {
84
+ return await this.client.getBuildSummary(buildSlug);
85
+ }
86
+ }
87
+ }
88
+ //# sourceMappingURL=ShowBuild.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ShowBuild.js","sourceRoot":"/","sources":["commands/ShowBuild.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseCommand, BaseCommandOptions } from './BaseCommand.js';\nimport { logger } from '../services/logger.js';\nimport { parseBuildRef } from '../utils/parseBuildRef.js';\nimport { FormatterFactory, FormatterType } from '../formatters/index.js';\nimport { Progress } from '../ui/progress.js';\n\nexport interface ShowBuildOptions extends BaseCommandOptions {\n jobs?: boolean;\n failed?: boolean;\n annotations?: boolean;\n annotationsFull?: boolean;\n full?: boolean;\n summary?: boolean;\n buildArg?: string;\n}\n\nexport class ShowBuild extends BaseCommand {\n static requiresToken = true;\n\n async execute(options: ShowBuildOptions): Promise<number> {\n if (options.debug) {\n logger.debug('Starting ShowBuild command execution', options);\n }\n \n if (!options.buildArg) {\n logger.error('Build reference is required');\n return 1;\n }\n \n // Adjust options based on implications\n const adjustedOptions = { ...options };\n if (options.failed) {\n adjustedOptions.jobs = true; // --failed implies --jobs\n }\n if (options.annotationsFull) {\n adjustedOptions.annotations = true; // --annotations-full implies --annotations\n }\n if (options.full) {\n // --full shows everything\n adjustedOptions.jobs = true;\n adjustedOptions.annotations = true;\n }\n \n // Initialize spinner early\n const format = options.format || 'plain';\n const spinner = Progress.spinner('Fetching build details…', { format });\n \n try {\n // Ensure the command is initialized\n await this.ensureInitialized();\n \n // Parse build reference\n const buildRef = parseBuildRef(options.buildArg);\n if (options.debug) {\n logger.debug('Parsed build reference:', buildRef);\n }\n \n // Construct build slug for GraphQL\n const buildSlug = `${buildRef.org}/${buildRef.pipeline}/${buildRef.number}`;\n \n // Fetch build data based on what's needed\n const buildData = await this.fetchBuildData(buildSlug, adjustedOptions);\n spinner.stop();\n \n // Get the appropriate formatter\n const formatter = FormatterFactory.getFormatter(\n FormatterType.BUILD_DETAIL,\n options.format || 'plain'\n ) as any;\n \n // Format and output the results\n const output = formatter.formatBuildDetail(buildData, adjustedOptions);\n \n logger.console(output);\n \n return 0;\n } catch (error) {\n spinner.stop();\n logger.error('Failed to fetch build:', error);\n \n // Handle the error with the formatter\n const formatter = FormatterFactory.getFormatter(\n FormatterType.BUILD_DETAIL,\n options.format || 'plain'\n ) as any;\n \n const errorOutput = formatter.formatBuildDetail(null, {\n ...adjustedOptions,\n hasError: true,\n errorMessage: error instanceof Error ? error.message : 'Unknown error occurred',\n errorType: 'api',\n });\n \n logger.console(errorOutput);\n return 1;\n }\n }\n \n private async fetchBuildData(buildSlug: string, options: ShowBuildOptions): Promise<any> {\n // Determine what data we need to fetch based on options\n const needsJobs = options.jobs || options.failed || options.full;\n const needsAnnotations = options.annotations || options.annotationsFull || options.full;\n \n if (options.debug) {\n logger.debug('Fetching build data', {\n buildSlug,\n needsJobs,\n needsAnnotations,\n full: options.full\n });\n }\n \n // Fetch the appropriate level of detail\n if (options.full || needsJobs) {\n return await this.client.getBuildFull(buildSlug);\n } else {\n return await this.client.getBuildSummary(buildSlug);\n }\n }\n}\n"]}
@@ -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(options.format || 'plain');
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;AAK/C,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,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;YAE3C,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;gBAClB,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;YAClE,CAAC;YAED,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC;YAChE,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,OAAO,CAAC,CAAC,CAAC,UAAU;QACtB,CAAC;QAAC,OAAO,KAAK,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\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 try {\n const data = await this.client.getViewer();\n \n if (!data?.viewer) {\n throw new Error('Invalid response format: missing viewer data');\n }\n \n const formatter = getViewerFormatter(options.format || 'plain');\n const output = formatter.formatViewer(data as unknown as ViewerData, { debug: options.debug });\n \n logger.console(output);\n return 0; // Success\n } catch (error) {\n this.handleError(error, options.debug);\n return 1; // Error\n }\n }\n} "]}
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} "]}
@@ -5,4 +5,6 @@ export * from './ListBuilds.js';
5
5
  export * from './ListPipelines.js';
6
6
  export * from './ManageToken.js';
7
7
  export * from './ListAnnotations.js';
8
+ export * from './GenerateCompletions.js';
9
+ export * from './ShowBuild.js';
8
10
  //# sourceMappingURL=index.js.map
@@ -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;AACzC,cAAc,gBAAgB,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';\nexport * from './ShowBuild.js';"]}
@@ -5,6 +5,7 @@ import { getOrganizationFormatter } from './organizations/index.js';
5
5
  import { getErrorFormatter } from './errors/index.js';
6
6
  import { getTokenFormatter } from './token/index.js';
7
7
  import { getAnnotationFormatter } from './annotations/index.js';
8
+ import { getBuildDetailFormatter } from './build-detail/index.js';
8
9
  export var FormatterType;
9
10
  (function (FormatterType) {
10
11
  FormatterType["PIPELINE"] = "pipeline";
@@ -14,6 +15,7 @@ export var FormatterType;
14
15
  FormatterType["ERROR"] = "error";
15
16
  FormatterType["TOKEN"] = "token";
16
17
  FormatterType["ANNOTATION"] = "annotation";
18
+ FormatterType["BUILD_DETAIL"] = "build-detail";
17
19
  })(FormatterType || (FormatterType = {}));
18
20
  export class FormatterFactory {
19
21
  /**
@@ -40,6 +42,8 @@ export class FormatterFactory {
40
42
  return getTokenFormatter(normalizedFormat);
41
43
  case FormatterType.ANNOTATION:
42
44
  return getAnnotationFormatter(normalizedFormat);
45
+ case FormatterType.BUILD_DETAIL:
46
+ return getBuildDetailFormatter(normalizedFormat);
43
47
  default:
44
48
  throw new Error(`Unknown formatter type: ${type}`);
45
49
  }
@@ -1 +1 @@
1
- {"version":3,"file":"FormatterFactory.js","sourceRoot":"/","sources":["formatters/FormatterFactory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,MAAM,CAAN,IAAY,aAQX;AARD,WAAY,aAAa;IACvB,sCAAqB,CAAA;IACrB,gCAAe,CAAA;IACf,kCAAiB,CAAA;IACjB,8CAA6B,CAAA;IAC7B,gCAAe,CAAA;IACf,gCAAe,CAAA;IACf,0CAAyB,CAAA;AAC3B,CAAC,EARW,aAAa,KAAb,aAAa,QAQxB;AAED,MAAM,OAAO,gBAAgB;IAC3B;;;;;OAKG;IACH,MAAM,CAAC,YAAY,CAAC,IAAmB,EAAE,SAAiB,OAAO;QAC/D,8BAA8B;QAC9B,MAAM,gBAAgB,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;QAErD,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,aAAa,CAAC,QAAQ;gBACzB,OAAO,oBAAoB,CAAC,gBAAgB,CAAC,CAAC;YAChD,KAAK,aAAa,CAAC,KAAK;gBACtB,OAAO,iBAAiB,CAAC,gBAAgB,CAAC,CAAC;YAC7C,KAAK,aAAa,CAAC,MAAM;gBACvB,OAAO,kBAAkB,CAAC,gBAAgB,CAAC,CAAC;YAC9C,KAAK,aAAa,CAAC,YAAY;gBAC7B,OAAO,wBAAwB,CAAC,gBAAgB,CAAC,CAAC;YACpD,KAAK,aAAa,CAAC,KAAK;gBACtB,OAAO,iBAAiB,CAAC,gBAAgB,CAAC,CAAC;YAC7C,KAAK,aAAa,CAAC,KAAK;gBACtB,OAAO,iBAAiB,CAAC,gBAAgB,CAAC,CAAC;YAC7C,KAAK,aAAa,CAAC,UAAU;gBAC3B,OAAO,sBAAsB,CAAC,gBAAgB,CAAC,CAAC;YAClD;gBACE,MAAM,IAAI,KAAK,CAAC,2BAA2B,IAAI,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;CACF","sourcesContent":["import { BaseFormatter } from './BaseFormatter.js';\nimport { getPipelineFormatter } from './pipelines/index.js';\nimport { getBuildFormatter } from './builds/index.js';\nimport { getViewerFormatter } from './viewer/index.js';\nimport { getOrganizationFormatter } from './organizations/index.js';\nimport { getErrorFormatter } from './errors/index.js';\nimport { getTokenFormatter } from './token/index.js';\nimport { getAnnotationFormatter } from './annotations/index.js';\n\nexport enum FormatterType {\n PIPELINE = 'pipeline',\n BUILD = 'build', \n VIEWER = 'viewer',\n ORGANIZATION = 'organization',\n ERROR = 'error',\n TOKEN = 'token',\n ANNOTATION = 'annotation'\n}\n\nexport class FormatterFactory {\n /**\n * Get the appropriate formatter based on the type and format\n * @param type The formatter type ('pipeline', 'build', 'viewer', 'organization', 'error', 'token', 'annotation')\n * @param format The format to use ('plain', 'json', 'alfred')\n * @returns The appropriate formatter instance\n */\n static getFormatter(type: FormatterType, format: string = 'plain'): BaseFormatter {\n // Normalize the format string\n const normalizedFormat = format.toLowerCase().trim();\n \n switch (type) {\n case FormatterType.PIPELINE:\n return getPipelineFormatter(normalizedFormat);\n case FormatterType.BUILD:\n return getBuildFormatter(normalizedFormat);\n case FormatterType.VIEWER:\n return getViewerFormatter(normalizedFormat);\n case FormatterType.ORGANIZATION:\n return getOrganizationFormatter(normalizedFormat);\n case FormatterType.ERROR:\n return getErrorFormatter(normalizedFormat);\n case FormatterType.TOKEN:\n return getTokenFormatter(normalizedFormat);\n case FormatterType.ANNOTATION:\n return getAnnotationFormatter(normalizedFormat);\n default:\n throw new Error(`Unknown formatter type: ${type}`);\n }\n }\n} "]}
1
+ {"version":3,"file":"FormatterFactory.js","sourceRoot":"/","sources":["formatters/FormatterFactory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAElE,MAAM,CAAN,IAAY,aASX;AATD,WAAY,aAAa;IACvB,sCAAqB,CAAA;IACrB,gCAAe,CAAA;IACf,kCAAiB,CAAA;IACjB,8CAA6B,CAAA;IAC7B,gCAAe,CAAA;IACf,gCAAe,CAAA;IACf,0CAAyB,CAAA;IACzB,8CAA6B,CAAA;AAC/B,CAAC,EATW,aAAa,KAAb,aAAa,QASxB;AAED,MAAM,OAAO,gBAAgB;IAC3B;;;;;OAKG;IACH,MAAM,CAAC,YAAY,CAAC,IAAmB,EAAE,SAAiB,OAAO;QAC/D,8BAA8B;QAC9B,MAAM,gBAAgB,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;QAErD,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,aAAa,CAAC,QAAQ;gBACzB,OAAO,oBAAoB,CAAC,gBAAgB,CAAC,CAAC;YAChD,KAAK,aAAa,CAAC,KAAK;gBACtB,OAAO,iBAAiB,CAAC,gBAAgB,CAAC,CAAC;YAC7C,KAAK,aAAa,CAAC,MAAM;gBACvB,OAAO,kBAAkB,CAAC,gBAAgB,CAAC,CAAC;YAC9C,KAAK,aAAa,CAAC,YAAY;gBAC7B,OAAO,wBAAwB,CAAC,gBAAgB,CAAC,CAAC;YACpD,KAAK,aAAa,CAAC,KAAK;gBACtB,OAAO,iBAAiB,CAAC,gBAAgB,CAAC,CAAC;YAC7C,KAAK,aAAa,CAAC,KAAK;gBACtB,OAAO,iBAAiB,CAAC,gBAAgB,CAAC,CAAC;YAC7C,KAAK,aAAa,CAAC,UAAU;gBAC3B,OAAO,sBAAsB,CAAC,gBAAgB,CAAC,CAAC;YAClD,KAAK,aAAa,CAAC,YAAY;gBAC7B,OAAO,uBAAuB,CAAC,gBAAgB,CAAQ,CAAC;YAC1D;gBACE,MAAM,IAAI,KAAK,CAAC,2BAA2B,IAAI,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;CACF","sourcesContent":["import { BaseFormatter } from './BaseFormatter.js';\nimport { getPipelineFormatter } from './pipelines/index.js';\nimport { getBuildFormatter } from './builds/index.js';\nimport { getViewerFormatter } from './viewer/index.js';\nimport { getOrganizationFormatter } from './organizations/index.js';\nimport { getErrorFormatter } from './errors/index.js';\nimport { getTokenFormatter } from './token/index.js';\nimport { getAnnotationFormatter } from './annotations/index.js';\nimport { getBuildDetailFormatter } from './build-detail/index.js';\n\nexport enum FormatterType {\n PIPELINE = 'pipeline',\n BUILD = 'build', \n VIEWER = 'viewer',\n ORGANIZATION = 'organization',\n ERROR = 'error',\n TOKEN = 'token',\n ANNOTATION = 'annotation',\n BUILD_DETAIL = 'build-detail'\n}\n\nexport class FormatterFactory {\n /**\n * Get the appropriate formatter based on the type and format\n * @param type The formatter type ('pipeline', 'build', 'viewer', 'organization', 'error', 'token', 'annotation')\n * @param format The format to use ('plain', 'json', 'alfred')\n * @returns The appropriate formatter instance\n */\n static getFormatter(type: FormatterType, format: string = 'plain'): BaseFormatter {\n // Normalize the format string\n const normalizedFormat = format.toLowerCase().trim();\n \n switch (type) {\n case FormatterType.PIPELINE:\n return getPipelineFormatter(normalizedFormat);\n case FormatterType.BUILD:\n return getBuildFormatter(normalizedFormat);\n case FormatterType.VIEWER:\n return getViewerFormatter(normalizedFormat);\n case FormatterType.ORGANIZATION:\n return getOrganizationFormatter(normalizedFormat);\n case FormatterType.ERROR:\n return getErrorFormatter(normalizedFormat);\n case FormatterType.TOKEN:\n return getTokenFormatter(normalizedFormat);\n case FormatterType.ANNOTATION:\n return getAnnotationFormatter(normalizedFormat);\n case FormatterType.BUILD_DETAIL:\n return getBuildDetailFormatter(normalizedFormat) as any;\n default:\n throw new Error(`Unknown formatter type: ${type}`);\n }\n }\n} "]}
@@ -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 `Error: ${options.errorMessage || 'Unknown error occurred'}`;
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
- if (options?.contextFilter) {
11
- return `No annotations found for this build with context '${options.contextFilter}'.`;
12
- }
13
- return 'No annotations found for this build.';
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
- lines.push(`Annotation ${index + 1}:`);
21
- lines.push(` Context: ${annotation.context}`);
22
- lines.push(` Style: ${annotation.style}`);
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(` Body: ${indentedBody}`);
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;AAEpE,MAAM,OAAO,kBAAmB,SAAQ,aAAa;IACnD,IAAI,GAAG,WAAW,CAAC;IAEnB,iBAAiB,CAAC,WAAyB,EAAE,OAAoC;QAC/E,IAAI,OAAO,EAAE,QAAQ,EAAE,CAAC;YACtB,OAAO,UAAU,OAAO,CAAC,YAAY,IAAI,wBAAwB,EAAE,CAAC;QACtE,CAAC;QAED,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7C,IAAI,OAAO,EAAE,aAAa,EAAE,CAAC;gBAC3B,OAAO,qDAAqD,OAAO,CAAC,aAAa,IAAI,CAAC;YACxF,CAAC;YACD,OAAO,sCAAsC,CAAC;QAChD,CAAC;QAED,MAAM,KAAK,GAAa,EAAE,CAAC;QAE3B,WAAW,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,EAAE;YACxC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;gBACd,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,qCAAqC;YACvD,CAAC;YAED,KAAK,CAAC,IAAI,CAAC,cAAc,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;YACvC,KAAK,CAAC,IAAI,CAAC,cAAc,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC;YAC/C,KAAK,CAAC,IAAI,CAAC,YAAY,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC;YAE3C,0DAA0D;YAC1D,MAAM,aAAa,GAAG,oBAAoB,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAEjE,qCAAqC;YACrC,MAAM,YAAY,GAAG,aAAa;iBAC/B,KAAK,CAAC,IAAI,CAAC;iBACX,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;iBACxB,IAAI,CAAC,IAAI,CAAC,CAAC;YAEd,KAAK,CAAC,IAAI,CAAC,WAAW,YAAY,EAAE,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QAEH,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;CACF","sourcesContent":["import { BaseFormatter, AnnotationFormatterOptions } from './Formatter.js';\nimport { Annotation } from '../../types/index.js';\nimport { formatAnnotationBody } from '../../utils/textFormatter.js';\n\nexport class PlainTextFormatter extends BaseFormatter {\n name = 'PlainText';\n\n formatAnnotations(annotations: Annotation[], options?: AnnotationFormatterOptions): string {\n if (options?.hasError) {\n return `Error: ${options.errorMessage || 'Unknown error occurred'}`;\n }\n\n if (!annotations || annotations.length === 0) {\n if (options?.contextFilter) {\n return `No annotations found for this build with context '${options.contextFilter}'.`;\n }\n return 'No annotations found for this build.';\n }\n\n const lines: string[] = [];\n \n annotations.forEach((annotation, index) => {\n if (index > 0) {\n lines.push(''); // Add blank line between annotations\n }\n \n lines.push(`Annotation ${index + 1}:`);\n lines.push(` Context: ${annotation.context}`);\n lines.push(` Style: ${annotation.style}`);\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(` Body: ${indentedBody}`);\n });\n\n return lines.join('\\n');\n }\n}\n"]}
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"]}
@@ -0,0 +1,113 @@
1
+ import { BaseBuildDetailFormatter } from './Formatter.js';
2
+ export class AlfredFormatter extends BaseBuildDetailFormatter {
3
+ name = 'alfred';
4
+ formatBuildDetail(buildData, options) {
5
+ if (options?.hasError || !buildData) {
6
+ return JSON.stringify({
7
+ items: [{
8
+ uid: 'error',
9
+ title: 'Error fetching build',
10
+ subtitle: options?.errorMessage || 'An error occurred',
11
+ valid: false,
12
+ icon: {
13
+ path: './icons/error.png'
14
+ }
15
+ }]
16
+ });
17
+ }
18
+ const build = buildData.build;
19
+ const items = [];
20
+ // Main build item
21
+ const duration = this.formatDuration(build);
22
+ const mainItem = {
23
+ uid: build.id,
24
+ title: `#${build.number}: ${build.message || 'No message'}`,
25
+ subtitle: `${build.state} • ${build.branch} • ${duration}`,
26
+ arg: build.url,
27
+ icon: {
28
+ path: this.getIconPath(build.state)
29
+ },
30
+ mods: {
31
+ cmd: {
32
+ subtitle: 'Open in browser',
33
+ arg: build.url
34
+ },
35
+ alt: {
36
+ subtitle: 'Copy build number',
37
+ arg: build.number.toString()
38
+ }
39
+ }
40
+ };
41
+ items.push(mainItem);
42
+ // Add failed jobs if present
43
+ if (options?.failed || build.state === 'FAILED') {
44
+ const failedJobs = (build.jobs?.edges || [])
45
+ .filter((j) => j.node.state === 'FAILED' || j.node.exitStatus !== 0);
46
+ for (const job of failedJobs) {
47
+ items.push({
48
+ uid: job.node.id,
49
+ title: `❌ ${job.node.label}`,
50
+ subtitle: `Failed with exit code ${job.node.exitStatus || 1}`,
51
+ valid: false,
52
+ icon: {
53
+ path: './icons/failed.png'
54
+ }
55
+ });
56
+ }
57
+ }
58
+ // Add annotation summary if present
59
+ if (build.annotations?.edges?.length > 0) {
60
+ const annotationCount = build.annotations.edges.length;
61
+ items.push({
62
+ uid: 'annotations',
63
+ title: `📝 ${annotationCount} annotation${annotationCount > 1 ? 's' : ''}`,
64
+ subtitle: 'View build annotations',
65
+ valid: false,
66
+ icon: {
67
+ path: './icons/annotation.png'
68
+ }
69
+ });
70
+ }
71
+ return JSON.stringify({ items });
72
+ }
73
+ formatDuration(build) {
74
+ if (!build.startedAt) {
75
+ return 'not started';
76
+ }
77
+ const start = new Date(build.startedAt);
78
+ const end = build.finishedAt ? new Date(build.finishedAt) : new Date();
79
+ const durationMs = end.getTime() - start.getTime();
80
+ const minutes = Math.floor(durationMs / 60000);
81
+ const seconds = Math.floor((durationMs % 60000) / 1000);
82
+ if (build.state === 'RUNNING') {
83
+ return `${minutes}m ${seconds}s elapsed`;
84
+ }
85
+ return `${minutes}m ${seconds}s`;
86
+ }
87
+ getIconPath(state) {
88
+ const iconMap = {
89
+ 'PASSED': './icons/passed.png',
90
+ 'FAILED': './icons/failed.png',
91
+ 'RUNNING': './icons/running.png',
92
+ 'BLOCKED': './icons/blocked.png',
93
+ 'CANCELED': './icons/canceled.png',
94
+ 'SCHEDULED': './icons/scheduled.png',
95
+ 'SKIPPED': './icons/skipped.png'
96
+ };
97
+ return iconMap[state] || './icons/unknown.png';
98
+ }
99
+ formatError(action, error) {
100
+ return JSON.stringify({
101
+ items: [{
102
+ uid: 'error',
103
+ title: `Error ${action}`,
104
+ subtitle: error instanceof Error ? error.message : String(error),
105
+ valid: false,
106
+ icon: {
107
+ path: './icons/error.png'
108
+ }
109
+ }]
110
+ });
111
+ }
112
+ }
113
+ //# sourceMappingURL=AlfredFormatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AlfredFormatter.js","sourceRoot":"/","sources":["formatters/build-detail/AlfredFormatter.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseBuildDetailFormatter, BuildDetail, BuildDetailFormatterOptions } from './Formatter.js';\n\nexport class AlfredFormatter extends BaseBuildDetailFormatter {\n name = 'alfred';\n \n formatBuildDetail(buildData: BuildDetail | null, options?: BuildDetailFormatterOptions): string {\n if (options?.hasError || !buildData) {\n return JSON.stringify({\n items: [{\n uid: 'error',\n title: 'Error fetching build',\n subtitle: options?.errorMessage || 'An error occurred',\n valid: false,\n icon: {\n path: './icons/error.png'\n }\n }]\n });\n }\n \n const build = buildData.build;\n const items: any[] = [];\n \n // Main build item\n const duration = this.formatDuration(build);\n const mainItem = {\n uid: build.id,\n title: `#${build.number}: ${build.message || 'No message'}`,\n subtitle: `${build.state} • ${build.branch} • ${duration}`,\n arg: build.url,\n icon: {\n path: this.getIconPath(build.state)\n },\n mods: {\n cmd: {\n subtitle: 'Open in browser',\n arg: build.url\n },\n alt: {\n subtitle: 'Copy build number',\n arg: build.number.toString()\n }\n }\n };\n \n items.push(mainItem);\n \n // Add failed jobs if present\n if (options?.failed || build.state === 'FAILED') {\n const failedJobs = (build.jobs?.edges || [])\n .filter((j: any) => j.node.state === 'FAILED' || j.node.exitStatus !== 0);\n \n for (const job of failedJobs) {\n items.push({\n uid: job.node.id,\n title: `❌ ${job.node.label}`,\n subtitle: `Failed with exit code ${job.node.exitStatus || 1}`,\n valid: false,\n icon: {\n path: './icons/failed.png'\n }\n });\n }\n }\n \n // Add annotation summary if present\n if (build.annotations?.edges?.length > 0) {\n const annotationCount = build.annotations.edges.length;\n items.push({\n uid: 'annotations',\n title: `📝 ${annotationCount} annotation${annotationCount > 1 ? 's' : ''}`,\n subtitle: 'View build annotations',\n valid: false,\n icon: {\n path: './icons/annotation.png'\n }\n });\n }\n \n return JSON.stringify({ items });\n }\n \n private formatDuration(build: any): string {\n if (!build.startedAt) {\n return 'not started';\n }\n \n const start = new Date(build.startedAt);\n const end = build.finishedAt ? new Date(build.finishedAt) : new Date();\n const durationMs = end.getTime() - start.getTime();\n \n const minutes = Math.floor(durationMs / 60000);\n const seconds = Math.floor((durationMs % 60000) / 1000);\n \n if (build.state === 'RUNNING') {\n return `${minutes}m ${seconds}s elapsed`;\n }\n \n return `${minutes}m ${seconds}s`;\n }\n \n private getIconPath(state: string): string {\n const iconMap: Record<string, string> = {\n 'PASSED': './icons/passed.png',\n 'FAILED': './icons/failed.png',\n 'RUNNING': './icons/running.png',\n 'BLOCKED': './icons/blocked.png',\n 'CANCELED': './icons/canceled.png',\n 'SCHEDULED': './icons/scheduled.png',\n 'SKIPPED': './icons/skipped.png'\n };\n \n return iconMap[state] || './icons/unknown.png';\n }\n \n formatError(action: string, error: any): string {\n return JSON.stringify({\n items: [{\n uid: 'error',\n title: `Error ${action}`,\n subtitle: error instanceof Error ? error.message : String(error),\n valid: false,\n icon: {\n path: './icons/error.png'\n }\n }]\n });\n }\n}\n"]}
@@ -0,0 +1,3 @@
1
+ export class BaseBuildDetailFormatter {
2
+ }
3
+ //# sourceMappingURL=Formatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Formatter.js","sourceRoot":"/","sources":["formatters/build-detail/Formatter.ts"],"names":[],"mappings":"AAcA,MAAM,OAAgB,wBAAwB;CAI7C","sourcesContent":["import { ShowBuildOptions } from '../../commands/ShowBuild.js';\n\nexport interface BuildDetail {\n build: any;\n jobs?: any[];\n annotations?: any[];\n}\n\nexport interface BuildDetailFormatterOptions extends ShowBuildOptions {\n hasError?: boolean;\n errorMessage?: string;\n errorType?: 'access' | 'not_found' | 'api';\n}\n\nexport abstract class BaseBuildDetailFormatter {\n abstract name: string;\n abstract formatBuildDetail(buildData: BuildDetail | null, options?: BuildDetailFormatterOptions): string;\n abstract formatError(action: string, error: any): string;\n}\n"]}
@@ -0,0 +1,132 @@
1
+ import { BaseBuildDetailFormatter } from './Formatter.js';
2
+ export class JsonFormatter extends BaseBuildDetailFormatter {
3
+ name = 'json';
4
+ formatBuildDetail(buildData, options) {
5
+ if (options?.hasError || !buildData) {
6
+ return JSON.stringify({
7
+ error: true,
8
+ errorType: options?.errorType || 'unknown',
9
+ message: options?.errorMessage || 'An error occurred'
10
+ }, null, 2);
11
+ }
12
+ const build = buildData.build;
13
+ // Transform based on options
14
+ let output = {
15
+ id: build.id,
16
+ number: build.number,
17
+ state: build.state,
18
+ branch: build.branch,
19
+ message: build.message,
20
+ commit: build.commit,
21
+ url: build.url,
22
+ createdAt: build.createdAt,
23
+ startedAt: build.startedAt,
24
+ finishedAt: build.finishedAt
25
+ };
26
+ // Add creator info
27
+ if (build.createdBy) {
28
+ output.createdBy = {
29
+ name: build.createdBy.name,
30
+ email: build.createdBy.email
31
+ };
32
+ }
33
+ // Add organization and pipeline
34
+ if (build.organization) {
35
+ output.organization = {
36
+ id: build.organization.id,
37
+ name: build.organization.name,
38
+ slug: build.organization.slug
39
+ };
40
+ }
41
+ if (build.pipeline) {
42
+ output.pipeline = {
43
+ id: build.pipeline.id,
44
+ name: build.pipeline.name,
45
+ slug: build.pipeline.slug
46
+ };
47
+ }
48
+ // Add jobs if requested or failed
49
+ if (options?.jobs || options?.failed || options?.full) {
50
+ const jobs = build.jobs?.edges || [];
51
+ if (options?.failed) {
52
+ // Filter to only failed jobs
53
+ output.jobs = jobs
54
+ .filter((j) => j.node.state === 'FAILED' || j.node.exitStatus !== 0)
55
+ .map((j) => this.formatJob(j.node));
56
+ }
57
+ else {
58
+ output.jobs = jobs.map((j) => this.formatJob(j.node));
59
+ }
60
+ }
61
+ // Add annotations if requested
62
+ if (options?.annotations || options?.annotationsFull || options?.full) {
63
+ const annotations = build.annotations?.edges || [];
64
+ output.annotations = annotations.map((a) => ({
65
+ id: a.node.id,
66
+ style: a.node.style,
67
+ context: a.node.context,
68
+ body: options?.annotationsFull ? a.node.body?.html : undefined,
69
+ createdAt: a.node.createdAt,
70
+ updatedAt: a.node.updatedAt
71
+ }));
72
+ }
73
+ // Add extra details if full
74
+ if (options?.full) {
75
+ if (build.pullRequest) {
76
+ output.pullRequest = {
77
+ id: build.pullRequest.id,
78
+ number: build.pullRequest.number,
79
+ repository: build.pullRequest.repository
80
+ };
81
+ }
82
+ if (build.triggeredFrom) {
83
+ output.triggeredFrom = {
84
+ id: build.triggeredFrom.id,
85
+ number: build.triggeredFrom.number,
86
+ url: build.triggeredFrom.url,
87
+ pipeline: build.triggeredFrom.pipeline
88
+ };
89
+ }
90
+ if (build.blockedState) {
91
+ output.blockedState = build.blockedState;
92
+ }
93
+ }
94
+ return JSON.stringify(output, null, 2);
95
+ }
96
+ formatJob(job) {
97
+ const formatted = {
98
+ id: job.id,
99
+ uuid: job.uuid,
100
+ label: job.label,
101
+ state: job.state,
102
+ exitStatus: job.exitStatus,
103
+ passed: job.passed,
104
+ soft_failed: job.soft_failed,
105
+ startedAt: job.startedAt,
106
+ finishedAt: job.finishedAt
107
+ };
108
+ if (job.command) {
109
+ formatted.command = job.command;
110
+ }
111
+ if (job.agent) {
112
+ formatted.agent = {
113
+ id: job.agent.id,
114
+ name: job.agent.name,
115
+ hostname: job.agent.hostname
116
+ };
117
+ }
118
+ if (job.retried !== undefined) {
119
+ formatted.retried = job.retried;
120
+ }
121
+ return formatted;
122
+ }
123
+ formatError(action, error) {
124
+ return JSON.stringify({
125
+ error: true,
126
+ action,
127
+ message: error instanceof Error ? error.message : String(error),
128
+ timestamp: new Date().toISOString()
129
+ }, null, 2);
130
+ }
131
+ }
132
+ //# sourceMappingURL=JsonFormatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JsonFormatter.js","sourceRoot":"/","sources":["formatters/build-detail/JsonFormatter.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseBuildDetailFormatter, BuildDetail, BuildDetailFormatterOptions } from './Formatter.js';\n\nexport class JsonFormatter extends BaseBuildDetailFormatter {\n name = 'json';\n \n formatBuildDetail(buildData: BuildDetail | null, options?: BuildDetailFormatterOptions): string {\n if (options?.hasError || !buildData) {\n return JSON.stringify({\n error: true,\n errorType: options?.errorType || 'unknown',\n message: options?.errorMessage || 'An error occurred'\n }, null, 2);\n }\n \n const build = buildData.build;\n \n // Transform based on options\n let output: any = {\n id: build.id,\n number: build.number,\n state: build.state,\n branch: build.branch,\n message: build.message,\n commit: build.commit,\n url: build.url,\n createdAt: build.createdAt,\n startedAt: build.startedAt,\n finishedAt: build.finishedAt\n };\n \n // Add creator info\n if (build.createdBy) {\n output.createdBy = {\n name: build.createdBy.name,\n email: build.createdBy.email\n };\n }\n \n // Add organization and pipeline\n if (build.organization) {\n output.organization = {\n id: build.organization.id,\n name: build.organization.name,\n slug: build.organization.slug\n };\n }\n \n if (build.pipeline) {\n output.pipeline = {\n id: build.pipeline.id,\n name: build.pipeline.name,\n slug: build.pipeline.slug\n };\n }\n \n // Add jobs if requested or failed\n if (options?.jobs || options?.failed || options?.full) {\n const jobs = build.jobs?.edges || [];\n \n if (options?.failed) {\n // Filter to only failed jobs\n output.jobs = jobs\n .filter((j: any) => j.node.state === 'FAILED' || j.node.exitStatus !== 0)\n .map((j: any) => this.formatJob(j.node));\n } else {\n output.jobs = jobs.map((j: any) => this.formatJob(j.node));\n }\n }\n \n // Add annotations if requested\n if (options?.annotations || options?.annotationsFull || options?.full) {\n const annotations = build.annotations?.edges || [];\n output.annotations = annotations.map((a: any) => ({\n id: a.node.id,\n style: a.node.style,\n context: a.node.context,\n body: options?.annotationsFull ? a.node.body?.html : undefined,\n createdAt: a.node.createdAt,\n updatedAt: a.node.updatedAt\n }));\n }\n \n // Add extra details if full\n if (options?.full) {\n if (build.pullRequest) {\n output.pullRequest = {\n id: build.pullRequest.id,\n number: build.pullRequest.number,\n repository: build.pullRequest.repository\n };\n }\n \n if (build.triggeredFrom) {\n output.triggeredFrom = {\n id: build.triggeredFrom.id,\n number: build.triggeredFrom.number,\n url: build.triggeredFrom.url,\n pipeline: build.triggeredFrom.pipeline\n };\n }\n \n if (build.blockedState) {\n output.blockedState = build.blockedState;\n }\n }\n \n return JSON.stringify(output, null, 2);\n }\n \n private formatJob(job: any): any {\n const formatted: any = {\n id: job.id,\n uuid: job.uuid,\n label: job.label,\n state: job.state,\n exitStatus: job.exitStatus,\n passed: job.passed,\n soft_failed: job.soft_failed,\n startedAt: job.startedAt,\n finishedAt: job.finishedAt\n };\n \n if (job.command) {\n formatted.command = job.command;\n }\n \n if (job.agent) {\n formatted.agent = {\n id: job.agent.id,\n name: job.agent.name,\n hostname: job.agent.hostname\n };\n }\n \n if (job.retried !== undefined) {\n formatted.retried = job.retried;\n }\n \n return formatted;\n }\n \n formatError(action: string, error: any): string {\n return JSON.stringify({\n error: true,\n action,\n message: error instanceof Error ? error.message : String(error),\n timestamp: new Date().toISOString()\n }, null, 2);\n }\n}\n"]}