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,139 @@
1
+ #compdef bktide
2
+ # Zsh completions for bktide CLI
3
+ # Install by adding to ~/.zshrc: source <(bktide completions zsh)
4
+ # Or copy to a directory in your $fpath
5
+
6
+ _bktide() {
7
+ local -a commands global_opts
8
+
9
+ commands=(
10
+ 'viewer:Show logged in user information'
11
+ 'orgs:List organizations'
12
+ 'pipelines:List pipelines for an organization'
13
+ 'builds:List builds for the current user'
14
+ 'token:Manage API tokens'
15
+ 'annotations:Show annotations for a build'
16
+ 'completions:Generate shell completions'
17
+ 'boom:Test error handling'
18
+ )
19
+
20
+ global_opts=(
21
+ '--log-level[Set logging level]:level:(trace debug info warn error fatal)'
22
+ {-d,--debug}'[Show debug information for errors]'
23
+ '--no-cache[Disable caching of API responses]'
24
+ '--cache-ttl[Set cache TTL in milliseconds]:milliseconds:'
25
+ '--clear-cache[Clear all cached data before executing]'
26
+ {-t,--token}'[Buildkite API token]:token:'
27
+ '--save-token[Save the token to system keychain]'
28
+ {-f,--format}'[Output format]:format:(plain json alfred)'
29
+ '--color[Color output mode]:mode:(auto always never)'
30
+ {-q,--quiet}'[Suppress non-error output]'
31
+ '--tips[Show helpful tips and suggestions]'
32
+ '--no-tips[Hide helpful tips and suggestions]'
33
+ '--ascii[Use ASCII symbols instead of Unicode]'
34
+ {-h,--help}'[Show help]'
35
+ {-V,--version}'[Show version]'
36
+ )
37
+
38
+ # Main command completion
39
+ if (( CURRENT == 2 )); then
40
+ _describe -t commands 'bktide commands' commands
41
+ return
42
+ fi
43
+
44
+ local cmd="${words[2]}"
45
+
46
+ # Command-specific completions
47
+ case "$cmd" in
48
+ pipelines)
49
+ _arguments \
50
+ {-o,--org}'[Organization slug]:org:->orgs' \
51
+ {-n,--count}'[Limit to specified number]:count:' \
52
+ '--filter[Filter pipelines by name]:filter:' \
53
+ $global_opts
54
+
55
+ case "$state" in
56
+ orgs)
57
+ # Dynamic org completion
58
+ local -a orgs
59
+ orgs=(${(f)"$(bktide orgs --format json --quiet 2>/dev/null | jq -r '.[].slug' 2>/dev/null)"})
60
+ _describe -t orgs 'organizations' orgs
61
+ ;;
62
+ esac
63
+ ;;
64
+
65
+ builds)
66
+ _arguments \
67
+ {-o,--org}'[Organization slug]:org:->orgs' \
68
+ {-p,--pipeline}'[Filter by pipeline slug]:pipeline:->pipelines' \
69
+ {-b,--branch}'[Filter by branch name]:branch:->branches' \
70
+ {-s,--state}'[Filter by build state]:state:(running scheduled passed failing failed canceled blocked canceling skipped not_run)' \
71
+ {-n,--count}'[Number of builds per page]:count:' \
72
+ '--page[Page number]:page:' \
73
+ '--filter[Fuzzy filter builds]:filter:' \
74
+ $global_opts
75
+
76
+ case "$state" in
77
+ orgs)
78
+ local -a orgs
79
+ orgs=(${(f)"$(bktide orgs --format json --quiet 2>/dev/null | jq -r '.[].slug' 2>/dev/null)"})
80
+ _describe -t orgs 'organizations' orgs
81
+ ;;
82
+ pipelines)
83
+ local -a pipelines
84
+ pipelines=(${(f)"$(bktide pipelines --format json --quiet 2>/dev/null | jq -r '.[].slug' 2>/dev/null)"})
85
+ _describe -t pipelines 'pipelines' pipelines
86
+ ;;
87
+ branches)
88
+ local -a branches
89
+ branches=(main master develop staging production)
90
+ if git rev-parse --git-dir &>/dev/null; then
91
+ branches+=(${(f)"$(git branch -r 2>/dev/null | sed 's/.*origin\///' | grep -v HEAD)"})
92
+ fi
93
+ _describe -t branches 'branches' branches
94
+ ;;
95
+ esac
96
+ ;;
97
+
98
+ token)
99
+ _arguments \
100
+ '--check[Check if a token is stored]' \
101
+ '--store[Store a token in the system keychain]' \
102
+ '--reset[Delete the stored token]' \
103
+ $global_opts
104
+ ;;
105
+
106
+ annotations)
107
+ _arguments \
108
+ ':build reference:(org/pipeline/123)' \
109
+ '--context[Filter annotations by context]:context:' \
110
+ $global_opts
111
+ ;;
112
+
113
+ completions)
114
+ if (( CURRENT == 3 )); then
115
+ local -a shells
116
+ shells=(fish bash zsh)
117
+ _describe -t shells 'shell type' shells
118
+ else
119
+ _arguments $global_opts
120
+ fi
121
+ ;;
122
+
123
+ boom)
124
+ _arguments \
125
+ '--type[Type of error to throw]:type:(basic api object)' \
126
+ $global_opts
127
+ ;;
128
+
129
+ *)
130
+ _arguments $global_opts
131
+ ;;
132
+ esac
133
+ }
134
+
135
+ # Also support bin/bktide
136
+ compdef _bktide bin/bktide
137
+
138
+ _bktide "$@"
139
+
@@ -118,7 +118,12 @@ export class BaseCommand {
118
118
  if (options.token) {
119
119
  return options.token;
120
120
  }
121
- // Next try to get token from keyring
121
+ // Prefer environment variables first under Alfred or if explicitly provided
122
+ const envToken = process.env.BUILDKITE_API_TOKEN || process.env.BK_TOKEN;
123
+ if (envToken) {
124
+ return envToken;
125
+ }
126
+ // Next try to get token from keyring (outside Alfred this will lazy-load)
122
127
  try {
123
128
  const storedToken = await this.credentialManager.getToken();
124
129
  if (storedToken) {
@@ -129,13 +134,8 @@ export class BaseCommand {
129
134
  catch (error) {
130
135
  logger.debug('Error retrieving token from keychain', error);
131
136
  }
132
- // Finally fall back to environment variable
133
- const envToken = process.env.BK_TOKEN;
134
- if (envToken) {
135
- return envToken;
136
- }
137
137
  if (options.requiresToken) {
138
- throw new Error('API token required. Set via --token, BK_TOKEN environment variable, or store it using --save-token.');
138
+ throw new Error('API token required. Set via --token, BUILDKITE_API_TOKEN/BK_TOKEN env vars, or store it using --save-token.');
139
139
  }
140
140
  else {
141
141
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"BaseCommand.js","sourceRoot":"/","sources":["commands/BaseCommand.ts"],"names":[],"mappings":"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","sourcesContent":["import { BuildkiteClient } from '../services/BuildkiteClient.js';\nimport { BuildkiteRestClient, BuildkiteRestClientOptions } from '../services/BuildkiteRestClient.js';\nimport { FormatterFactory, FormatterType } from '../formatters/index.js';\nimport { logger } from '../services/logger.js';\nimport { CredentialManager } from '../services/CredentialManager.js';\n\nexport interface BaseCommandOptions {\n cacheTTL?: number;\n clearCache?: boolean;\n debug?: boolean;\n filter?: string;\n format?: string;\n noCache?: boolean;\n token?: string;\n}\n\n// Extended Error interface for API and GraphQL errors\ninterface ApiError extends Error {\n response?: {\n errors?: Array<{\n message: string;\n path?: string[];\n locations?: Array<{line: number; column: number}>;\n }>;\n };\n request?: {\n url?: string;\n method?: string;\n };\n}\n\nexport abstract class BaseCommand {\n protected token: string | undefined;\n protected requiresToken: boolean = true;\n private _client: BuildkiteClient | undefined;\n private _restClient: BuildkiteRestClient | undefined;\n private _restClientOptions: BuildkiteRestClientOptions | undefined;\n \n protected options: Partial<BaseCommandOptions>;\n protected initialized: boolean = false;\n protected static credentialManager = new CredentialManager();\n\n constructor(options?: Partial<BaseCommandOptions>) {\n this.options = options || {};\n this.token = this.options.token;\n \n if (this.options.debug) {\n // Include token length (not the actual token) for debugging auth issues\n // Debug mode is already handled here by logger.debug use\n logger.debug('BaseCommandHandler options:', {\n ...options,\n token: this.token ? `${this.token.substring(0, 4)}...${this.token.substring(this.token.length - 4)} (${this.token.length} chars)` : 'Not provided'\n });\n }\n }\n\n get client(): BuildkiteClient {\n if (this._client) {\n return this._client;\n } else {\n if (this.token) {\n this._client = new BuildkiteClient(this.token, this.options);\n return this._client;\n } else {\n throw new Error('No token provided');\n }\n }\n }\n\n get restClient(): BuildkiteRestClient {\n if (this._restClient) {\n return this._restClient;\n } else {\n if (this.token) {\n this._restClient = new BuildkiteRestClient(this.token, this.options);\n return this._restClient;\n } else {\n throw new Error('No token provided');\n }\n }\n }\n\n get restClientOptions(): BuildkiteRestClientOptions {\n if (this._restClientOptions) {\n return this._restClientOptions;\n } else {\n // Configure REST client with the same caching options\n const restClientOptions: BuildkiteRestClientOptions = {\n debug: this.options?.debug,\n caching: !this.options?.noCache,\n };\n \n // If a specific cache TTL is provided, apply it to REST client\n if (this.options?.cacheTTL) {\n restClientOptions.cacheTTLs = {\n default: this.options.cacheTTL,\n builds: this.options.cacheTTL,\n };\n }\n return restClientOptions;\n }\n }\n\n static get requiresToken(): boolean {\n return true;\n }\n \n protected async ensureInitialized(): Promise<void> {\n // No additional initialization needed\n return Promise.resolve();\n }\n\n protected handleError(error: any, debug: boolean = false): void {\n // Only log the error message and stack trace\n if (error instanceof Error) {\n logger.error(error, 'Error occurred');\n \n // If it's a GraphQL error or API error, show more details\n const apiError = error as ApiError;\n if (apiError.response?.errors) {\n apiError.response.errors.forEach((gqlError, index) => {\n logger.error({ path: gqlError.path }, `GraphQL Error ${index + 1}: ${gqlError.message}`);\n });\n }\n \n // Show request details if available and in debug mode\n if (debug && apiError.request) {\n logger.debug({ \n url: apiError.request.url,\n method: apiError.request.method \n }, 'Request Details');\n }\n } else if (typeof error === 'object') {\n logger.error({ error }, 'Unknown error occurred');\n } else {\n logger.error({ error }, 'Unknown error occurred');\n }\n \n if (debug) {\n logger.debug({ \n timestamp: new Date().toISOString(),\n nodeVersion: process.version,\n platform: `${process.platform} (${process.arch})`\n }, 'Debug Information');\n }\n }\n\n // Static helper to get token from options, keyring, or environment\n static async getToken(options: any): Promise<string | undefined> {\n // First check if token is provided directly in options\n if (options.token) {\n return options.token;\n }\n \n // Next try to get token from keyring\n try {\n const storedToken = await this.credentialManager.getToken();\n if (storedToken) {\n logger.debug('Using token from system keychain');\n return storedToken;\n }\n } catch (error) {\n logger.debug('Error retrieving token from keychain', error);\n }\n \n // Finally fall back to environment variable\n const envToken = process.env.BK_TOKEN;\n if (envToken) {\n return envToken;\n }\n \n if (options.requiresToken) {\n throw new Error('API token required. Set via --token, BK_TOKEN environment variable, or store it using --save-token.');\n } else {\n return\n }\n }\n\n /**\n * Get the appropriate formatter based on command-specific type and format option\n * @param type The formatter type ('pipeline', 'build', 'viewer')\n * @param options Command options that may include a format\n * @returns The appropriate formatter\n */\n protected getFormatter(type: FormatterType, options: BaseCommandOptions) {\n // Format precedence: command line option > constructor option > default\n const format = options.format || this.options.format || 'plain';\n if (options.debug) {\n logger.debug(`Using ${format} formatter for ${type}`);\n }\n return FormatterFactory.getFormatter(type, format);\n }\n\n /**\n * Execute the command with the given options\n * @param options Command options\n * @returns A promise that resolves to an exit code (0 for success, non-zero for errors)\n */\n abstract execute(options: BaseCommandOptions): Promise<number>;\n}"]}
1
+ {"version":3,"file":"BaseCommand.js","sourceRoot":"/","sources":["commands/BaseCommand.ts"],"names":[],"mappings":"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","sourcesContent":["import { BuildkiteClient } from '../services/BuildkiteClient.js';\nimport { BuildkiteRestClient, BuildkiteRestClientOptions } from '../services/BuildkiteRestClient.js';\nimport { FormatterFactory, FormatterType } from '../formatters/index.js';\nimport { logger } from '../services/logger.js';\nimport { CredentialManager } from '../services/CredentialManager.js';\n\nexport interface BaseCommandOptions {\n cacheTTL?: number;\n clearCache?: boolean;\n debug?: boolean;\n filter?: string;\n format?: string;\n noCache?: boolean;\n quiet?: boolean;\n tips?: boolean;\n token?: string;\n}\n\n// Extended Error interface for API and GraphQL errors\ninterface ApiError extends Error {\n response?: {\n errors?: Array<{\n message: string;\n path?: string[];\n locations?: Array<{line: number; column: number}>;\n }>;\n };\n request?: {\n url?: string;\n method?: string;\n };\n}\n\nexport abstract class BaseCommand {\n protected token: string | undefined;\n protected requiresToken: boolean = true;\n private _client: BuildkiteClient | undefined;\n private _restClient: BuildkiteRestClient | undefined;\n private _restClientOptions: BuildkiteRestClientOptions | undefined;\n \n protected options: Partial<BaseCommandOptions>;\n protected initialized: boolean = false;\n protected static credentialManager = new CredentialManager();\n\n constructor(options?: Partial<BaseCommandOptions>) {\n this.options = options || {};\n this.token = this.options.token;\n \n if (this.options.debug) {\n // Include token length (not the actual token) for debugging auth issues\n // Debug mode is already handled here by logger.debug use\n logger.debug('BaseCommandHandler options:', {\n ...options,\n token: this.token ? `${this.token.substring(0, 4)}...${this.token.substring(this.token.length - 4)} (${this.token.length} chars)` : 'Not provided'\n });\n }\n }\n\n get client(): BuildkiteClient {\n if (this._client) {\n return this._client;\n } else {\n if (this.token) {\n this._client = new BuildkiteClient(this.token, this.options);\n return this._client;\n } else {\n throw new Error('No token provided');\n }\n }\n }\n\n get restClient(): BuildkiteRestClient {\n if (this._restClient) {\n return this._restClient;\n } else {\n if (this.token) {\n this._restClient = new BuildkiteRestClient(this.token, this.options);\n return this._restClient;\n } else {\n throw new Error('No token provided');\n }\n }\n }\n\n get restClientOptions(): BuildkiteRestClientOptions {\n if (this._restClientOptions) {\n return this._restClientOptions;\n } else {\n // Configure REST client with the same caching options\n const restClientOptions: BuildkiteRestClientOptions = {\n debug: this.options?.debug,\n caching: !this.options?.noCache,\n };\n \n // If a specific cache TTL is provided, apply it to REST client\n if (this.options?.cacheTTL) {\n restClientOptions.cacheTTLs = {\n default: this.options.cacheTTL,\n builds: this.options.cacheTTL,\n };\n }\n return restClientOptions;\n }\n }\n\n static get requiresToken(): boolean {\n return true;\n }\n \n protected async ensureInitialized(): Promise<void> {\n // No additional initialization needed\n return Promise.resolve();\n }\n\n protected handleError(error: any, debug: boolean = false): void {\n // Only log the error message and stack trace\n if (error instanceof Error) {\n logger.error(error, 'Error occurred');\n \n // If it's a GraphQL error or API error, show more details\n const apiError = error as ApiError;\n if (apiError.response?.errors) {\n apiError.response.errors.forEach((gqlError, index) => {\n logger.error({ path: gqlError.path }, `GraphQL Error ${index + 1}: ${gqlError.message}`);\n });\n }\n \n // Show request details if available and in debug mode\n if (debug && apiError.request) {\n logger.debug({ \n url: apiError.request.url,\n method: apiError.request.method \n }, 'Request Details');\n }\n } else if (typeof error === 'object') {\n logger.error({ error }, 'Unknown error occurred');\n } else {\n logger.error({ error }, 'Unknown error occurred');\n }\n \n if (debug) {\n logger.debug({ \n timestamp: new Date().toISOString(),\n nodeVersion: process.version,\n platform: `${process.platform} (${process.arch})`\n }, 'Debug Information');\n }\n }\n\n // Static helper to get token from options, keyring, or environment\n static async getToken(options: any): Promise<string | undefined> {\n // First check if token is provided directly in options\n if (options.token) {\n return options.token;\n }\n \n // Prefer environment variables first under Alfred or if explicitly provided\n const envToken = process.env.BUILDKITE_API_TOKEN || process.env.BK_TOKEN;\n if (envToken) {\n return envToken;\n }\n \n // Next try to get token from keyring (outside Alfred this will lazy-load)\n try {\n const storedToken = await this.credentialManager.getToken();\n if (storedToken) {\n logger.debug('Using token from system keychain');\n return storedToken;\n }\n } catch (error) {\n logger.debug('Error retrieving token from keychain', error);\n }\n \n if (options.requiresToken) {\n throw new Error('API token required. Set via --token, BUILDKITE_API_TOKEN/BK_TOKEN env vars, or store it using --save-token.');\n } else {\n return\n }\n }\n\n /**\n * Get the appropriate formatter based on command-specific type and format option\n * @param type The formatter type ('pipeline', 'build', 'viewer')\n * @param options Command options that may include a format\n * @returns The appropriate formatter\n */\n protected getFormatter(type: FormatterType, options: BaseCommandOptions) {\n // Format precedence: command line option > constructor option > default\n const format = options.format || this.options.format || 'plain';\n if (options.debug) {\n logger.debug(`Using ${format} formatter for ${type}`);\n }\n return FormatterFactory.getFormatter(type, format);\n }\n\n /**\n * Execute the command with the given options\n * @param options Command options\n * @returns A promise that resolves to an exit code (0 for success, non-zero for errors)\n */\n abstract execute(options: BaseCommandOptions): Promise<number>;\n}"]}
@@ -0,0 +1,238 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import { BaseCommand } from './BaseCommand.js';
5
+ import { logger } from '../services/logger.js';
6
+ export class GenerateCompletions extends BaseCommand {
7
+ static requiresToken = false;
8
+ async execute(options) {
9
+ const shell = options.shell || this.detectShell();
10
+ if (!shell) {
11
+ logger.error('Could not detect shell. Please specify with: bktide completions <shell>');
12
+ logger.info('Supported shells: fish, bash, zsh');
13
+ return 1;
14
+ }
15
+ try {
16
+ const completionScript = await this.getCompletionScript(shell);
17
+ if (completionScript) {
18
+ // Output the completion script to stdout
19
+ console.log(completionScript);
20
+ if (!options.quiet && process.stderr.isTTY) {
21
+ // Show installation instructions on stderr
22
+ this.showInstallInstructions(shell);
23
+ }
24
+ return 0;
25
+ }
26
+ else {
27
+ logger.error(`No completion script available for shell: ${shell}`);
28
+ logger.info('Supported shells: fish, bash, zsh');
29
+ return 1;
30
+ }
31
+ }
32
+ catch (error) {
33
+ this.handleError(error, options.debug);
34
+ return 1;
35
+ }
36
+ }
37
+ detectShell() {
38
+ // Try to detect the current shell
39
+ const shellEnv = process.env.SHELL;
40
+ if (shellEnv) {
41
+ const shellName = path.basename(shellEnv);
42
+ if (['fish', 'bash', 'zsh'].includes(shellName)) {
43
+ return shellName;
44
+ }
45
+ }
46
+ return undefined;
47
+ }
48
+ async getCompletionScript(shell) {
49
+ const __filename = fileURLToPath(import.meta.url);
50
+ const __dirname = path.dirname(__filename);
51
+ // Look for completion scripts in the completions directory
52
+ const completionsDir = path.resolve(__dirname, '../../completions');
53
+ let scriptFile;
54
+ switch (shell) {
55
+ case 'fish':
56
+ // Use the dynamic version if jq is available, otherwise static
57
+ if (await this.isCommandAvailable('jq')) {
58
+ scriptFile = path.join(completionsDir, 'bktide-dynamic.fish');
59
+ }
60
+ else {
61
+ scriptFile = path.join(completionsDir, 'bktide.fish');
62
+ }
63
+ break;
64
+ case 'bash':
65
+ scriptFile = path.join(completionsDir, 'bktide.bash');
66
+ break;
67
+ case 'zsh':
68
+ scriptFile = path.join(completionsDir, 'bktide.zsh');
69
+ break;
70
+ default:
71
+ return undefined;
72
+ }
73
+ // Check if the completion script exists
74
+ if (fs.existsSync(scriptFile)) {
75
+ return fs.readFileSync(scriptFile, 'utf-8');
76
+ }
77
+ // Fallback: Generate basic completion based on shell type
78
+ return this.generateBasicCompletion(shell);
79
+ }
80
+ async isCommandAvailable(command) {
81
+ try {
82
+ const { exec } = await import('child_process');
83
+ return new Promise((resolve) => {
84
+ exec(`which ${command}`, (error) => {
85
+ resolve(!error);
86
+ });
87
+ });
88
+ }
89
+ catch {
90
+ return false;
91
+ }
92
+ }
93
+ generateBasicCompletion(shell) {
94
+ // Basic completion generation for shells
95
+ const commands = ['viewer', 'orgs', 'pipelines', 'builds', 'token', 'annotations', 'completions', 'boom'];
96
+ const globalOptions = [
97
+ '--log-level', '--debug', '--no-cache', '--cache-ttl', '--clear-cache',
98
+ '--token', '--save-token', '--format', '--color', '--quiet', '--tips',
99
+ '--no-tips', '--ascii', '--help', '--version'
100
+ ];
101
+ switch (shell) {
102
+ case 'fish':
103
+ return this.generateFishCompletion(commands, globalOptions);
104
+ case 'bash':
105
+ return this.generateBashCompletion(commands, globalOptions);
106
+ case 'zsh':
107
+ return this.generateZshCompletion(commands, globalOptions);
108
+ default:
109
+ return '';
110
+ }
111
+ }
112
+ generateFishCompletion(commands, options) {
113
+ let script = '# Fish completions for bktide\n';
114
+ script += '# Generated by bktide completions fish\n\n';
115
+ script += '# Disable file completions\n';
116
+ script += 'complete -c bktide -f\n';
117
+ script += 'complete -c bin/bktide -f\n\n';
118
+ script += '# Commands\n';
119
+ for (const cmd of commands) {
120
+ script += `complete -c bktide -n __fish_use_subcommand -a ${cmd}\n`;
121
+ script += `complete -c bin/bktide -n __fish_use_subcommand -a ${cmd}\n`;
122
+ }
123
+ script += '\n# Global options\n';
124
+ for (const opt of options) {
125
+ const shortOpt = this.getShortOption(opt);
126
+ if (shortOpt) {
127
+ script += `complete -c bktide -s ${shortOpt} -l ${opt.replace('--', '')}\n`;
128
+ script += `complete -c bin/bktide -s ${shortOpt} -l ${opt.replace('--', '')}\n`;
129
+ }
130
+ else {
131
+ script += `complete -c bktide -l ${opt.replace('--', '')}\n`;
132
+ script += `complete -c bin/bktide -l ${opt.replace('--', '')}\n`;
133
+ }
134
+ }
135
+ return script;
136
+ }
137
+ generateBashCompletion(commands, options) {
138
+ let script = '#!/bin/bash\n';
139
+ script += '# Bash completions for bktide\n';
140
+ script += '# Generated by bktide completions bash\n\n';
141
+ script += '_bktide() {\n';
142
+ script += ' local cur prev commands options\n';
143
+ script += ' COMPREPLY=()\n';
144
+ script += ' cur="${COMP_WORDS[COMP_CWORD]}"\n';
145
+ script += ' prev="${COMP_WORDS[COMP_CWORD-1]}"\n';
146
+ script += ` commands="${commands.join(' ')}"\n`;
147
+ script += ` options="${options.join(' ')}"\n\n`;
148
+ script += ' if [[ ${COMP_CWORD} -eq 1 ]]; then\n';
149
+ script += ' COMPREPLY=( $(compgen -W "${commands}" -- ${cur}) )\n';
150
+ script += ' else\n';
151
+ script += ' COMPREPLY=( $(compgen -W "${options}" -- ${cur}) )\n';
152
+ script += ' fi\n';
153
+ script += ' return 0\n';
154
+ script += '}\n\n';
155
+ script += 'complete -F _bktide bktide\n';
156
+ script += 'complete -F _bktide bin/bktide\n';
157
+ return script;
158
+ }
159
+ generateZshCompletion(commands, options) {
160
+ let script = '#compdef bktide\n';
161
+ script += '# Zsh completions for bktide\n';
162
+ script += '# Generated by bktide completions zsh\n\n';
163
+ script += '_bktide() {\n';
164
+ script += ' local -a commands options\n';
165
+ script += ` commands=(${commands.map(c => `'${c}'`).join(' ')})\n`;
166
+ script += ` options=(${options.map(o => `'${o}'`).join(' ')})\n\n`;
167
+ script += ' if (( CURRENT == 2 )); then\n';
168
+ script += ' _describe -t commands "bktide commands" commands\n';
169
+ script += ' else\n';
170
+ script += ' _describe -t options "bktide options" options\n';
171
+ script += ' fi\n';
172
+ script += '}\n\n';
173
+ script += '_bktide "$@"\n';
174
+ return script;
175
+ }
176
+ getShortOption(longOption) {
177
+ const shortMap = {
178
+ '--debug': 'd',
179
+ '--token': 't',
180
+ '--format': 'f',
181
+ '--quiet': 'q',
182
+ '--help': 'h',
183
+ '--version': 'V',
184
+ };
185
+ return shortMap[longOption];
186
+ }
187
+ showInstallInstructions(shell) {
188
+ // Use console.error to ensure instructions go to stderr, not stdout
189
+ console.error('\n');
190
+ console.error(`To install ${shell} completions:`);
191
+ switch (shell) {
192
+ case 'fish':
193
+ console.error(' Option 1 (User-specific):');
194
+ console.error(' bktide completions fish > ~/.config/fish/completions/bktide.fish');
195
+ console.error('');
196
+ console.error(' Option 2 (System-wide - requires sudo):');
197
+ console.error(' bktide completions fish | sudo tee /usr/share/fish/vendor_completions.d/bktide.fish');
198
+ console.error('');
199
+ console.error(' For local development with bin/bktide:');
200
+ console.error(' The completions will work for both "bktide" and "bin/bktide" automatically');
201
+ break;
202
+ case 'bash':
203
+ console.error(' Option 1 (User-specific - add to ~/.bashrc):');
204
+ console.error(' source <(bktide completions bash)');
205
+ console.error('');
206
+ console.error(' Option 2 (System-wide - requires sudo):');
207
+ console.error(' bktide completions bash | sudo tee /etc/bash_completion.d/bktide');
208
+ console.error('');
209
+ console.error(' For macOS with Homebrew bash-completion:');
210
+ console.error(' bktide completions bash > $(brew --prefix)/etc/bash_completion.d/bktide');
211
+ break;
212
+ case 'zsh':
213
+ console.error(' Option 1 (User-specific - add to ~/.zshrc):');
214
+ console.error(' source <(bktide completions zsh)');
215
+ console.error('');
216
+ console.error(' Option 2 (Add to fpath - add to ~/.zshrc):');
217
+ console.error(' mkdir -p ~/.zsh/completions');
218
+ console.error(' bktide completions zsh > ~/.zsh/completions/_bktide');
219
+ console.error(' echo "fpath=(~/.zsh/completions $fpath)" >> ~/.zshrc');
220
+ console.error(' echo "autoload -U compinit && compinit" >> ~/.zshrc');
221
+ break;
222
+ }
223
+ console.error('');
224
+ console.error('After installation, restart your shell or run:');
225
+ switch (shell) {
226
+ case 'fish':
227
+ console.error(' source ~/.config/fish/config.fish');
228
+ break;
229
+ case 'bash':
230
+ console.error(' source ~/.bashrc');
231
+ break;
232
+ case 'zsh':
233
+ console.error(' source ~/.zshrc');
234
+ break;
235
+ }
236
+ }
237
+ }
238
+ //# sourceMappingURL=GenerateCompletions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GenerateCompletions.js","sourceRoot":"/","sources":["commands/GenerateCompletions.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport { BaseCommand, BaseCommandOptions } from './BaseCommand.js';\nimport { logger } from '../services/logger.js';\n\nexport interface GenerateCompletionsOptions extends BaseCommandOptions {\n shell?: string;\n}\n\nexport class GenerateCompletions extends BaseCommand {\n static requiresToken = false;\n\n async execute(options: GenerateCompletionsOptions): Promise<number> {\n const shell = options.shell || this.detectShell();\n \n if (!shell) {\n logger.error('Could not detect shell. Please specify with: bktide completions <shell>');\n logger.info('Supported shells: fish, bash, zsh');\n return 1;\n }\n\n try {\n const completionScript = await this.getCompletionScript(shell);\n \n if (completionScript) {\n // Output the completion script to stdout\n console.log(completionScript);\n \n if (!options.quiet && process.stderr.isTTY) {\n // Show installation instructions on stderr\n this.showInstallInstructions(shell);\n }\n \n return 0;\n } else {\n logger.error(`No completion script available for shell: ${shell}`);\n logger.info('Supported shells: fish, bash, zsh');\n return 1;\n }\n } catch (error) {\n this.handleError(error, options.debug);\n return 1;\n }\n }\n\n private detectShell(): string | undefined {\n // Try to detect the current shell\n const shellEnv = process.env.SHELL;\n if (shellEnv) {\n const shellName = path.basename(shellEnv);\n if (['fish', 'bash', 'zsh'].includes(shellName)) {\n return shellName;\n }\n }\n return undefined;\n }\n\n private async getCompletionScript(shell: string): Promise<string | undefined> {\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = path.dirname(__filename);\n \n // Look for completion scripts in the completions directory\n const completionsDir = path.resolve(__dirname, '../../completions');\n \n let scriptFile: string;\n switch (shell) {\n case 'fish':\n // Use the dynamic version if jq is available, otherwise static\n if (await this.isCommandAvailable('jq')) {\n scriptFile = path.join(completionsDir, 'bktide-dynamic.fish');\n } else {\n scriptFile = path.join(completionsDir, 'bktide.fish');\n }\n break;\n case 'bash':\n scriptFile = path.join(completionsDir, 'bktide.bash');\n break;\n case 'zsh':\n scriptFile = path.join(completionsDir, 'bktide.zsh');\n break;\n default:\n return undefined;\n }\n\n // Check if the completion script exists\n if (fs.existsSync(scriptFile)) {\n return fs.readFileSync(scriptFile, 'utf-8');\n }\n\n // Fallback: Generate basic completion based on shell type\n return this.generateBasicCompletion(shell);\n }\n\n private async isCommandAvailable(command: string): Promise<boolean> {\n try {\n const { exec } = await import('child_process');\n return new Promise((resolve) => {\n exec(`which ${command}`, (error) => {\n resolve(!error);\n });\n });\n } catch {\n return false;\n }\n }\n\n private generateBasicCompletion(shell: string): string {\n // Basic completion generation for shells\n const commands = ['viewer', 'orgs', 'pipelines', 'builds', 'token', 'annotations', 'completions', 'boom'];\n const globalOptions = [\n '--log-level', '--debug', '--no-cache', '--cache-ttl', '--clear-cache',\n '--token', '--save-token', '--format', '--color', '--quiet', '--tips',\n '--no-tips', '--ascii', '--help', '--version'\n ];\n\n switch (shell) {\n case 'fish':\n return this.generateFishCompletion(commands, globalOptions);\n case 'bash':\n return this.generateBashCompletion(commands, globalOptions);\n case 'zsh':\n return this.generateZshCompletion(commands, globalOptions);\n default:\n return '';\n }\n }\n\n private generateFishCompletion(commands: string[], options: string[]): string {\n let script = '# Fish completions for bktide\\n';\n script += '# Generated by bktide completions fish\\n\\n';\n script += '# Disable file completions\\n';\n script += 'complete -c bktide -f\\n';\n script += 'complete -c bin/bktide -f\\n\\n';\n \n script += '# Commands\\n';\n for (const cmd of commands) {\n script += `complete -c bktide -n __fish_use_subcommand -a ${cmd}\\n`;\n script += `complete -c bin/bktide -n __fish_use_subcommand -a ${cmd}\\n`;\n }\n \n script += '\\n# Global options\\n';\n for (const opt of options) {\n const shortOpt = this.getShortOption(opt);\n if (shortOpt) {\n script += `complete -c bktide -s ${shortOpt} -l ${opt.replace('--', '')}\\n`;\n script += `complete -c bin/bktide -s ${shortOpt} -l ${opt.replace('--', '')}\\n`;\n } else {\n script += `complete -c bktide -l ${opt.replace('--', '')}\\n`;\n script += `complete -c bin/bktide -l ${opt.replace('--', '')}\\n`;\n }\n }\n \n return script;\n }\n\n private generateBashCompletion(commands: string[], options: string[]): string {\n let script = '#!/bin/bash\\n';\n script += '# Bash completions for bktide\\n';\n script += '# Generated by bktide completions bash\\n\\n';\n \n script += '_bktide() {\\n';\n script += ' local cur prev commands options\\n';\n script += ' COMPREPLY=()\\n';\n script += ' cur=\"${COMP_WORDS[COMP_CWORD]}\"\\n';\n script += ' prev=\"${COMP_WORDS[COMP_CWORD-1]}\"\\n';\n script += ` commands=\"${commands.join(' ')}\"\\n`;\n script += ` options=\"${options.join(' ')}\"\\n\\n`;\n \n script += ' if [[ ${COMP_CWORD} -eq 1 ]]; then\\n';\n script += ' COMPREPLY=( $(compgen -W \"${commands}\" -- ${cur}) )\\n';\n script += ' else\\n';\n script += ' COMPREPLY=( $(compgen -W \"${options}\" -- ${cur}) )\\n';\n script += ' fi\\n';\n script += ' return 0\\n';\n script += '}\\n\\n';\n \n script += 'complete -F _bktide bktide\\n';\n script += 'complete -F _bktide bin/bktide\\n';\n \n return script;\n }\n\n private generateZshCompletion(commands: string[], options: string[]): string {\n let script = '#compdef bktide\\n';\n script += '# Zsh completions for bktide\\n';\n script += '# Generated by bktide completions zsh\\n\\n';\n \n script += '_bktide() {\\n';\n script += ' local -a commands options\\n';\n script += ` commands=(${commands.map(c => `'${c}'`).join(' ')})\\n`;\n script += ` options=(${options.map(o => `'${o}'`).join(' ')})\\n\\n`;\n \n script += ' if (( CURRENT == 2 )); then\\n';\n script += ' _describe -t commands \"bktide commands\" commands\\n';\n script += ' else\\n';\n script += ' _describe -t options \"bktide options\" options\\n';\n script += ' fi\\n';\n script += '}\\n\\n';\n \n script += '_bktide \"$@\"\\n';\n \n return script;\n }\n\n private getShortOption(longOption: string): string | undefined {\n const shortMap: Record<string, string> = {\n '--debug': 'd',\n '--token': 't',\n '--format': 'f',\n '--quiet': 'q',\n '--help': 'h',\n '--version': 'V',\n };\n return shortMap[longOption];\n }\n\n private showInstallInstructions(shell: string): void {\n // Use console.error to ensure instructions go to stderr, not stdout\n console.error('\\n');\n console.error(`To install ${shell} completions:`);\n \n switch (shell) {\n case 'fish':\n console.error(' Option 1 (User-specific):');\n console.error(' bktide completions fish > ~/.config/fish/completions/bktide.fish');\n console.error('');\n console.error(' Option 2 (System-wide - requires sudo):');\n console.error(' bktide completions fish | sudo tee /usr/share/fish/vendor_completions.d/bktide.fish');\n console.error('');\n console.error(' For local development with bin/bktide:');\n console.error(' The completions will work for both \"bktide\" and \"bin/bktide\" automatically');\n break;\n \n case 'bash':\n console.error(' Option 1 (User-specific - add to ~/.bashrc):');\n console.error(' source <(bktide completions bash)');\n console.error('');\n console.error(' Option 2 (System-wide - requires sudo):');\n console.error(' bktide completions bash | sudo tee /etc/bash_completion.d/bktide');\n console.error('');\n console.error(' For macOS with Homebrew bash-completion:');\n console.error(' bktide completions bash > $(brew --prefix)/etc/bash_completion.d/bktide');\n break;\n \n case 'zsh':\n console.error(' Option 1 (User-specific - add to ~/.zshrc):');\n console.error(' source <(bktide completions zsh)');\n console.error('');\n console.error(' Option 2 (Add to fpath - add to ~/.zshrc):');\n console.error(' mkdir -p ~/.zsh/completions');\n console.error(' bktide completions zsh > ~/.zsh/completions/_bktide');\n console.error(' echo \"fpath=(~/.zsh/completions $fpath)\" >> ~/.zshrc');\n console.error(' echo \"autoload -U compinit && compinit\" >> ~/.zshrc');\n break;\n }\n \n console.error('');\n console.error('After installation, restart your shell or run:');\n switch (shell) {\n case 'fish':\n console.error(' source ~/.config/fish/config.fish');\n break;\n case 'bash':\n console.error(' source ~/.bashrc');\n break;\n case 'zsh':\n console.error(' source ~/.zshrc');\n break;\n }\n }\n}\n"]}
@@ -2,6 +2,7 @@ import { BaseCommand } from './BaseCommand.js';
2
2
  import { logger } from '../services/logger.js';
3
3
  import { parseBuildRef } from '../utils/parseBuildRef.js';
4
4
  import { FormatterFactory, FormatterType } from '../formatters/index.js';
5
+ import { Progress } from '../ui/progress.js';
5
6
  export class ListAnnotations extends BaseCommand {
6
7
  static requiresToken = true;
7
8
  async execute(options) {
@@ -12,6 +13,9 @@ export class ListAnnotations extends BaseCommand {
12
13
  logger.error('Build reference is required');
13
14
  return 1;
14
15
  }
16
+ // Initialize reporter and spinner early
17
+ const format = options.format || 'plain';
18
+ const spinner = Progress.spinner('Fetching annotations…', { format });
15
19
  try {
16
20
  // Ensure the command is initialized
17
21
  await this.ensureInitialized();
@@ -22,6 +26,7 @@ export class ListAnnotations extends BaseCommand {
22
26
  // Fetch annotations from the GraphQL API
23
27
  const buildSlug = `${buildRef.org}/${buildRef.pipeline}/${buildRef.number}`;
24
28
  const result = await this.client.getBuildAnnotations(buildSlug);
29
+ spinner.stop();
25
30
  // Extract annotations from the GraphQL response
26
31
  let annotations = result.build?.annotations?.edges?.map((edge) => edge.node) || [];
27
32
  // Filter by context if specified
@@ -40,9 +45,11 @@ export class ListAnnotations extends BaseCommand {
40
45
  contextFilter: options.context
41
46
  });
42
47
  logger.console(output);
48
+ // Success is implicit - data display confirms retrieval
43
49
  return 0;
44
50
  }
45
51
  catch (error) {
52
+ spinner.stop();
46
53
  logger.error('Failed to fetch annotations:', error);
47
54
  // Handle the error with the formatter
48
55
  const formatter = FormatterFactory.getFormatter(FormatterType.ANNOTATION, options.format || 'plain'); // Cast to any since FormatterFactory returns BaseFormatter
@@ -1 +1 @@
1
- {"version":3,"file":"ListAnnotations.js","sourceRoot":"/","sources":["commands/ListAnnotations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAGzE,MAAM,OAAO,eAAgB,SAAQ,WAAW;IAC9C,MAAM,CAAC,aAAa,GAAG,IAAI,CAAC;IAE5B,KAAK,CAAC,OAAO,CAAC,OAAY;QACxB,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YAClB,MAAM,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAC7D,CAAC;QAGD,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;YACtB,MAAM,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;YAC5C,OAAO,CAAC,CAAC;QACX,CAAC;QAED,IAAI,CAAC;YACH,oCAAoC;YACpC,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAE/B,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YACjD,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;gBAClB,MAAM,CAAC,KAAK,CAAC,yBAAyB,EAAE,QAAQ,CAAC,CAAC;YACpD,CAAC;YAED,yCAAyC;YACzC,MAAM,SAAS,GAAG,GAAG,QAAQ,CAAC,GAAG,IAAI,QAAQ,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;YAC5E,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;YAEhE,gDAAgD;YAChD,IAAI,WAAW,GAAiB,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,IAAS,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YAEtG,iCAAiC;YACjC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBACpB,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;gBACpD,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAC5C,UAAU,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,aAAa,CACnD,CAAC;gBAEF,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;oBAClB,MAAM,CAAC,KAAK,CAAC,oCAAoC,OAAO,CAAC,OAAO,MAAM,WAAW,CAAC,MAAM,QAAQ,CAAC,CAAC;gBACpG,CAAC;YACH,CAAC;YAED,gCAAgC;YAChC,MAAM,SAAS,GAAG,gBAAgB,CAAC,YAAY,CAC7C,aAAa,CAAC,UAAU,EACxB,OAAO,CAAC,MAAM,IAAI,OAAO,CACnB,CAAC,CAAC,2DAA2D;YAErE,gCAAgC;YAChC,MAAM,MAAM,GAAG,SAAS,CAAC,iBAAiB,CAAC,WAAW,EAAE;gBACtD,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,aAAa,EAAE,OAAO,CAAC,OAAO;aAC/B,CAAC,CAAC;YAEH,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAEvB,OAAO,CAAC,CAAC;QACX,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;YAEpD,sCAAsC;YACtC,MAAM,SAAS,GAAG,gBAAgB,CAAC,YAAY,CAC7C,aAAa,CAAC,UAAU,EACxB,OAAO,CAAC,MAAM,IAAI,OAAO,CACnB,CAAC,CAAC,2DAA2D;YAErE,MAAM,WAAW,GAAG,SAAS,CAAC,iBAAiB,CAAC,EAAE,EAAE;gBAClD,QAAQ,EAAE,IAAI;gBACd,YAAY,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB;gBAC/E,SAAS,EAAE,KAAK;gBAChB,KAAK,EAAE,OAAO,CAAC,KAAK;aACrB,CAAC,CAAC;YAEH,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;YAC5B,OAAO,CAAC,CAAC;QACX,CAAC;IACH,CAAC","sourcesContent":["import { BaseCommand } from './BaseCommand.js';\nimport { logger } from '../services/logger.js';\nimport { parseBuildRef } from '../utils/parseBuildRef.js';\nimport { FormatterFactory, FormatterType } from '../formatters/index.js';\nimport { Annotation } from '../types/index.js';\n\nexport class ListAnnotations extends BaseCommand {\n static requiresToken = true;\n\n async execute(options: any): Promise<number> {\n if (options.debug) {\n logger.debug('Starting ListAnnotations command execution');\n }\n \n \n if (!options.buildArg) {\n logger.error('Build reference is required');\n return 1;\n }\n \n try {\n // Ensure the command is initialized\n await this.ensureInitialized();\n \n const buildRef = parseBuildRef(options.buildArg);\n if (options.debug) {\n logger.debug('Parsed build reference:', buildRef);\n }\n \n // Fetch annotations from the GraphQL API\n const buildSlug = `${buildRef.org}/${buildRef.pipeline}/${buildRef.number}`;\n const result = await this.client.getBuildAnnotations(buildSlug);\n \n // Extract annotations from the GraphQL response\n let annotations: Annotation[] = result.build?.annotations?.edges?.map((edge: any) => edge.node) || [];\n \n // Filter by context if specified\n if (options.context) {\n const contextFilter = options.context.toLowerCase();\n annotations = annotations.filter(annotation => \n annotation.context.toLowerCase() === contextFilter\n );\n \n if (options.debug) {\n logger.debug(`Filtered annotations by context '${options.context}': ${annotations.length} found`);\n }\n }\n \n // Get the appropriate formatter\n const formatter = FormatterFactory.getFormatter(\n FormatterType.ANNOTATION,\n options.format || 'plain'\n ) as any; // Cast to any since FormatterFactory returns BaseFormatter\n \n // Format and output the results\n const output = formatter.formatAnnotations(annotations, {\n debug: options.debug,\n contextFilter: options.context\n });\n \n logger.console(output);\n \n return 0;\n } catch (error) {\n logger.error('Failed to fetch annotations:', error);\n \n // Handle the error with the formatter\n const formatter = FormatterFactory.getFormatter(\n FormatterType.ANNOTATION,\n options.format || 'plain'\n ) as any; // Cast to any since FormatterFactory returns BaseFormatter\n \n const errorOutput = formatter.formatAnnotations([], {\n hasError: true,\n errorMessage: error instanceof Error ? error.message : 'Unknown error occurred',\n errorType: 'api',\n debug: options.debug\n });\n \n logger.console(errorOutput);\n return 1;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"ListAnnotations.js","sourceRoot":"/","sources":["commands/ListAnnotations.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseCommand } from './BaseCommand.js';\nimport { logger } from '../services/logger.js';\nimport { parseBuildRef } from '../utils/parseBuildRef.js';\nimport { FormatterFactory, FormatterType } from '../formatters/index.js';\nimport { Annotation } from '../types/index.js';\n\nimport { Progress } from '../ui/progress.js';\n\nexport class ListAnnotations extends BaseCommand {\n static requiresToken = true;\n\n async execute(options: any): Promise<number> {\n if (options.debug) {\n logger.debug('Starting ListAnnotations command execution');\n }\n \n \n if (!options.buildArg) {\n logger.error('Build reference is required');\n return 1;\n }\n \n // Initialize reporter and spinner early\n const format = options.format || 'plain';\n const spinner = Progress.spinner('Fetching annotations…', { format });\n \n try {\n // Ensure the command is initialized\n await this.ensureInitialized();\n \n const buildRef = parseBuildRef(options.buildArg);\n if (options.debug) {\n logger.debug('Parsed build reference:', buildRef);\n }\n \n // Fetch annotations from the GraphQL API\n const buildSlug = `${buildRef.org}/${buildRef.pipeline}/${buildRef.number}`;\n const result = await this.client.getBuildAnnotations(buildSlug);\n spinner.stop();\n \n // Extract annotations from the GraphQL response\n let annotations: Annotation[] = result.build?.annotations?.edges?.map((edge: any) => edge.node) || [];\n \n // Filter by context if specified\n if (options.context) {\n const contextFilter = options.context.toLowerCase();\n annotations = annotations.filter(annotation => \n annotation.context.toLowerCase() === contextFilter\n );\n \n if (options.debug) {\n logger.debug(`Filtered annotations by context '${options.context}': ${annotations.length} found`);\n }\n }\n \n // Get the appropriate formatter\n const formatter = FormatterFactory.getFormatter(\n FormatterType.ANNOTATION,\n options.format || 'plain'\n ) as any; // Cast to any since FormatterFactory returns BaseFormatter\n \n // Format and output the results\n const output = formatter.formatAnnotations(annotations, {\n debug: options.debug,\n contextFilter: options.context\n });\n \n logger.console(output);\n // Success is implicit - data display confirms retrieval\n \n return 0;\n } catch (error) {\n spinner.stop();\n logger.error('Failed to fetch annotations:', error);\n \n // Handle the error with the formatter\n const formatter = FormatterFactory.getFormatter(\n FormatterType.ANNOTATION,\n options.format || 'plain'\n ) as any; // Cast to any since FormatterFactory returns BaseFormatter\n \n const errorOutput = formatter.formatAnnotations([], {\n hasError: true,\n errorMessage: error instanceof Error ? error.message : 'Unknown error occurred',\n errorType: 'api',\n debug: options.debug\n });\n \n logger.console(errorOutput);\n return 1;\n }\n }\n}\n"]}