bktide 0.0.1

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 (160) hide show
  1. package/README.md +145 -0
  2. package/WORKFLOW_README.md +65 -0
  3. package/bin/alfred-entrypoint +54 -0
  4. package/dist/commands/BaseCommand.js +159 -0
  5. package/dist/commands/BaseCommand.js.map +1 -0
  6. package/dist/commands/BaseCommandHandler.js +80 -0
  7. package/dist/commands/BaseCommandHandler.js.map +1 -0
  8. package/dist/commands/BuildCommandHandler.js +28 -0
  9. package/dist/commands/BuildCommandHandler.js.map +1 -0
  10. package/dist/commands/HelloCommandHandler.js +6 -0
  11. package/dist/commands/HelloCommandHandler.js.map +1 -0
  12. package/dist/commands/ListAnnotations.js +60 -0
  13. package/dist/commands/ListAnnotations.js.map +1 -0
  14. package/dist/commands/ListBuilds.js +137 -0
  15. package/dist/commands/ListBuilds.js.map +1 -0
  16. package/dist/commands/ListOrganizations.js +27 -0
  17. package/dist/commands/ListOrganizations.js.map +1 -0
  18. package/dist/commands/ListPipelines.js +114 -0
  19. package/dist/commands/ListPipelines.js.map +1 -0
  20. package/dist/commands/ManageToken.js +180 -0
  21. package/dist/commands/ManageToken.js.map +1 -0
  22. package/dist/commands/OrganizationCommandHandler.js +53 -0
  23. package/dist/commands/OrganizationCommandHandler.js.map +1 -0
  24. package/dist/commands/PipelineCommandHandler.js +142 -0
  25. package/dist/commands/PipelineCommandHandler.js.map +1 -0
  26. package/dist/commands/ShowViewer.js +26 -0
  27. package/dist/commands/ShowViewer.js.map +1 -0
  28. package/dist/commands/UserBuildsCommandHandler.js +61 -0
  29. package/dist/commands/UserBuildsCommandHandler.js.map +1 -0
  30. package/dist/commands/ViewerBuildsCommandHandler.js +176 -0
  31. package/dist/commands/ViewerBuildsCommandHandler.js.map +1 -0
  32. package/dist/commands/ViewerCommandHandler.js +46 -0
  33. package/dist/commands/ViewerCommandHandler.js.map +1 -0
  34. package/dist/commands/index.js +8 -0
  35. package/dist/commands/index.js.map +1 -0
  36. package/dist/formatters/BaseFormatter.js +14 -0
  37. package/dist/formatters/BaseFormatter.js.map +1 -0
  38. package/dist/formatters/FormatterFactory.js +48 -0
  39. package/dist/formatters/FormatterFactory.js.map +1 -0
  40. package/dist/formatters/annotations/Formatter.js +10 -0
  41. package/dist/formatters/annotations/Formatter.js.map +1 -0
  42. package/dist/formatters/annotations/JsonFormatter.js +20 -0
  43. package/dist/formatters/annotations/JsonFormatter.js.map +1 -0
  44. package/dist/formatters/annotations/PlainTextFormatter.js +35 -0
  45. package/dist/formatters/annotations/PlainTextFormatter.js.map +1 -0
  46. package/dist/formatters/annotations/index.js +23 -0
  47. package/dist/formatters/annotations/index.js.map +1 -0
  48. package/dist/formatters/builds/AlfredFormatter.js +135 -0
  49. package/dist/formatters/builds/AlfredFormatter.js.map +1 -0
  50. package/dist/formatters/builds/Formatter.js +10 -0
  51. package/dist/formatters/builds/Formatter.js.map +1 -0
  52. package/dist/formatters/builds/JsonFormatter.js +44 -0
  53. package/dist/formatters/builds/JsonFormatter.js.map +1 -0
  54. package/dist/formatters/builds/PlainTextFormatter.js +113 -0
  55. package/dist/formatters/builds/PlainTextFormatter.js.map +1 -0
  56. package/dist/formatters/builds/index.js +26 -0
  57. package/dist/formatters/builds/index.js.map +1 -0
  58. package/dist/formatters/errors/AlfredFormatter.js +110 -0
  59. package/dist/formatters/errors/AlfredFormatter.js.map +1 -0
  60. package/dist/formatters/errors/Formatter.js +98 -0
  61. package/dist/formatters/errors/Formatter.js.map +1 -0
  62. package/dist/formatters/errors/JsonFormatter.js +63 -0
  63. package/dist/formatters/errors/JsonFormatter.js.map +1 -0
  64. package/dist/formatters/errors/PlainTextFormatter.js +52 -0
  65. package/dist/formatters/errors/PlainTextFormatter.js.map +1 -0
  66. package/dist/formatters/errors/index.js +26 -0
  67. package/dist/formatters/errors/index.js.map +1 -0
  68. package/dist/formatters/index.js +9 -0
  69. package/dist/formatters/index.js.map +1 -0
  70. package/dist/formatters/organizations/Formatter.js +10 -0
  71. package/dist/formatters/organizations/Formatter.js.map +1 -0
  72. package/dist/formatters/organizations/JsonFormatter.js +16 -0
  73. package/dist/formatters/organizations/JsonFormatter.js.map +1 -0
  74. package/dist/formatters/organizations/PlainTextFormatter.js +15 -0
  75. package/dist/formatters/organizations/PlainTextFormatter.js.map +1 -0
  76. package/dist/formatters/organizations/index.js +21 -0
  77. package/dist/formatters/organizations/index.js.map +1 -0
  78. package/dist/formatters/pipelines/AlfredFormatter.js +42 -0
  79. package/dist/formatters/pipelines/AlfredFormatter.js.map +1 -0
  80. package/dist/formatters/pipelines/Formatter.js +10 -0
  81. package/dist/formatters/pipelines/Formatter.js.map +1 -0
  82. package/dist/formatters/pipelines/JsonFormatter.js +13 -0
  83. package/dist/formatters/pipelines/JsonFormatter.js.map +1 -0
  84. package/dist/formatters/pipelines/PlainTextFormatter.js +47 -0
  85. package/dist/formatters/pipelines/PlainTextFormatter.js.map +1 -0
  86. package/dist/formatters/pipelines/index.js +28 -0
  87. package/dist/formatters/pipelines/index.js.map +1 -0
  88. package/dist/formatters/token/AlfredFormatter.js +191 -0
  89. package/dist/formatters/token/AlfredFormatter.js.map +1 -0
  90. package/dist/formatters/token/Formatter.js +13 -0
  91. package/dist/formatters/token/Formatter.js.map +1 -0
  92. package/dist/formatters/token/JsonFormatter.js +211 -0
  93. package/dist/formatters/token/JsonFormatter.js.map +1 -0
  94. package/dist/formatters/token/PlainTextFormatter.js +184 -0
  95. package/dist/formatters/token/PlainTextFormatter.js.map +1 -0
  96. package/dist/formatters/token/index.js +26 -0
  97. package/dist/formatters/token/index.js.map +1 -0
  98. package/dist/formatters/viewer/Formatter.js +10 -0
  99. package/dist/formatters/viewer/Formatter.js.map +1 -0
  100. package/dist/formatters/viewer/JsonFormatter.js +20 -0
  101. package/dist/formatters/viewer/JsonFormatter.js.map +1 -0
  102. package/dist/formatters/viewer/PlainTextFormatter.js +20 -0
  103. package/dist/formatters/viewer/PlainTextFormatter.js.map +1 -0
  104. package/dist/formatters/viewer/index.js +21 -0
  105. package/dist/formatters/viewer/index.js.map +1 -0
  106. package/dist/graphql/generated/fragment-masking.js +17 -0
  107. package/dist/graphql/generated/fragment-masking.js.map +1 -0
  108. package/dist/graphql/generated/gql.js +13 -0
  109. package/dist/graphql/generated/gql.js.map +1 -0
  110. package/dist/graphql/generated/graphql.js +852 -0
  111. package/dist/graphql/generated/graphql.js.map +1 -0
  112. package/dist/graphql/generated/index.js +3 -0
  113. package/dist/graphql/generated/index.js.map +1 -0
  114. package/dist/graphql/generated/sdk.js +872 -0
  115. package/dist/graphql/generated/sdk.js.map +1 -0
  116. package/dist/graphql/queries.js +138 -0
  117. package/dist/graphql/queries.js.map +1 -0
  118. package/dist/index.js +271 -0
  119. package/dist/index.js.map +1 -0
  120. package/dist/services/BuildkiteClient.js +520 -0
  121. package/dist/services/BuildkiteClient.js.map +1 -0
  122. package/dist/services/BuildkiteRestClient.js +244 -0
  123. package/dist/services/BuildkiteRestClient.js.map +1 -0
  124. package/dist/services/CacheManager.js +221 -0
  125. package/dist/services/CacheManager.js.map +1 -0
  126. package/dist/services/CredentialManager.js +158 -0
  127. package/dist/services/CredentialManager.js.map +1 -0
  128. package/dist/services/EnhancedBuildkiteClient.js +297 -0
  129. package/dist/services/EnhancedBuildkiteClient.js.map +1 -0
  130. package/dist/services/logger.js +107 -0
  131. package/dist/services/logger.js.map +1 -0
  132. package/dist/types/buildkite.js +5 -0
  133. package/dist/types/buildkite.js.map +1 -0
  134. package/dist/types/credentials.js +2 -0
  135. package/dist/types/credentials.js.map +1 -0
  136. package/dist/types/index.js +3 -0
  137. package/dist/types/index.js.map +1 -0
  138. package/dist/utils/cli-error-handler.js +172 -0
  139. package/dist/utils/cli-error-handler.js.map +1 -0
  140. package/dist/utils/errorUtils.js +59 -0
  141. package/dist/utils/errorUtils.js.map +1 -0
  142. package/dist/utils/parseBuildRef.js +31 -0
  143. package/dist/utils/parseBuildRef.js.map +1 -0
  144. package/dist/utils/textFormatter.js +53 -0
  145. package/dist/utils/textFormatter.js.map +1 -0
  146. package/dist/utils/xdgPaths.js +95 -0
  147. package/dist/utils/xdgPaths.js.map +1 -0
  148. package/env.example +66 -0
  149. package/icons/README.md +68 -0
  150. package/icons/blocked.png +0 -0
  151. package/icons/buildkite.png +0 -0
  152. package/icons/failed.png +0 -0
  153. package/icons/failing.png +0 -0
  154. package/icons/passed.png +0 -0
  155. package/icons/running.png +0 -0
  156. package/icons/scheduled.png +0 -0
  157. package/icons/skipped.png +0 -0
  158. package/icons/unknown.png +0 -0
  159. package/info.plist +734 -0
  160. package/package.json +87 -0
package/README.md ADDED
@@ -0,0 +1,145 @@
1
+ # bktide
2
+
3
+ A command-line tool for interacting with Buildkite's GraphQL API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g bktide
9
+ ```
10
+
11
+ ## Documentation
12
+
13
+ - [Development Guide](docs/development.md) - Information about running and developing the CLI
14
+ - [Authentication](docs/authentication.md) - How to authenticate with Buildkite
15
+ - [Caching](docs/caching.md) - Information about the CLI's caching system
16
+ - [Alfred Integration (Overview)](docs/alfred.md) - What the Alfred integration does and quick usage
17
+ - [Alfred Installation](docs/alfred-installation.md) - End-user install, configuration, and troubleshooting
18
+ - [Alfred Development](docs/alfred-development.md) - Packaging, wrapper behavior, metadata, and workflow wiring
19
+
20
+ ## Usage
21
+
22
+ ### Show Your Login Information
23
+
24
+ ```bash
25
+ npm run dev -- viewer
26
+ ```
27
+
28
+ ### List Your Organizations
29
+
30
+ ```bash
31
+ npm run dev -- orgs
32
+ ```
33
+
34
+ ### List Pipelines in an Organization
35
+
36
+ ```bash
37
+ npm run dev -- pipelines
38
+ ```
39
+
40
+ Additional options:
41
+ ```bash
42
+ # Filter by organization
43
+ npm run dev -- pipelines --org your-org-slug
44
+
45
+ # Limit the number of results
46
+ npm run dev -- pipelines --count 20
47
+ ```
48
+
49
+ ### List Your Builds
50
+
51
+ ```bash
52
+ npm run dev -- builds
53
+ ```
54
+
55
+ Additional options:
56
+ ```bash
57
+ # Filter by organization
58
+ npm run dev -- builds --org your-org-slug
59
+
60
+ # Filter by pipeline
61
+ npm run dev -- builds --pipeline pipeline-slug
62
+
63
+ # Filter by branch
64
+ npm run dev -- builds --branch main
65
+
66
+ # Filter by state
67
+ npm run dev -- builds --state passed
68
+
69
+ # Pagination
70
+ npm run dev -- builds --count 20 --page 2
71
+
72
+ # Output in JSON format
73
+ npm run dev -- builds --json
74
+
75
+ # Output in Alfred-compatible JSON format
76
+ npm run dev -- builds --alfred
77
+ ```
78
+
79
+ ### Show Build Annotations
80
+
81
+ ```bash
82
+ npm run dev -- annotations <build>
83
+ ```
84
+
85
+ The build reference can be specified in two formats:
86
+ - **Slug format**: `org/pipeline/number` (e.g., `gusto/zenpayroll/1287418`)
87
+ - **URL format**: `@https://buildkite.com/org/pipeline/builds/number` or `https://buildkite.com/org/pipeline/builds/number`
88
+
89
+ Additional options:
90
+ ```bash
91
+ # Filter by context
92
+ npm run dev -- annotations gusto/zenpayroll/1287418 --context rspec
93
+
94
+ # Output in JSON format
95
+ npm run dev -- annotations gusto/zenpayroll/1287418 --format json
96
+
97
+ # Output in plain text format (default)
98
+ npm run dev -- annotations https://buildkite.com/gusto/zenpayroll/builds/1287418 --format plain
99
+
100
+ # Combine filtering and formatting
101
+ npm run dev -- annotations gusto/zenpayroll/1287418 --context build-resources --format json
102
+ ```
103
+
104
+ ## API Token
105
+
106
+ You'll need a Buildkite API token with GraphQL scopes. Create one at:
107
+ https://buildkite.com/user/api-access-tokens
108
+
109
+ # Logging System
110
+
111
+ The CLI uses a structured logging system based on Pino. This provides several benefits:
112
+
113
+ - Different log levels (trace, debug, info, warn, error, fatal)
114
+ - JSON logs saved to disk (in `log/cli.log`)
115
+ - Pretty-printed logs to the console
116
+ - Performance measurements
117
+
118
+ ## Log Level Configuration
119
+
120
+ You can configure the log level with the `--log-level` option:
121
+
122
+ ```bash
123
+ bktide orgs --log-level=debug # Show debug messages
124
+ bktide builds --log-level=trace # Show all messages including trace
125
+ ```
126
+
127
+ Available log levels (from most to least verbose):
128
+ - trace: Very detailed tracing for debugging
129
+ - debug: Detailed information for developers
130
+ - info: General information (default)
131
+ - warn: Warning conditions
132
+ - error: Error conditions
133
+ - fatal: Severe errors causing termination
134
+
135
+ ## Log Files
136
+
137
+ All logs are written to `log/cli.log` in JSON format, which can be processed with tools like jq:
138
+
139
+ ```bash
140
+ # View recent errors
141
+ cat log/cli.log | grep -v '"level":30' | jq
142
+
143
+ # Analyze performance
144
+ cat log/cli.log | jq 'select(.duration != null) | {msg, duration}'
145
+ ```
@@ -0,0 +1,65 @@
1
+ # bktide Alfred Workflow
2
+
3
+ A powerful Alfred workflow for interacting with Buildkite builds, pipelines, and organizations.
4
+
5
+ ## Quick Start
6
+
7
+ 1. **Install Node.js 18+** (required)
8
+ - Download from [nodejs.org](https://nodejs.org/) or install via Homebrew: `brew install node`
9
+
10
+ 2. **Set up your Buildkite token**
11
+ - Open Alfred: `bktide token store`
12
+ - Enter your Buildkite API token
13
+
14
+ 3. **Start using the workflow**
15
+ - `bktide viewer` - Show your user info
16
+ - `bktide orgs` - List organizations
17
+ - `bktide pipelines` - List pipelines
18
+ - `bktide builds` - List recent builds
19
+
20
+ ## Commands
21
+
22
+ | Command | Description |
23
+ |---------|-------------|
24
+ | `bktide viewer` | Show your Buildkite user information |
25
+ | `bktide orgs` | List your accessible organizations |
26
+ | `bktide pipelines [org]` | List pipelines, optionally filtered by org |
27
+ | `bktide builds [filter]` | List recent builds with optional filtering |
28
+ | `bktide annotations <build-ref>` | Show annotations for a specific build |
29
+
30
+ ## Configuration
31
+
32
+ If Node.js is not in your PATH, create `~/.config/bktide/env`:
33
+
34
+ ```bash
35
+ # For Homebrew on Apple Silicon
36
+ export PATH="/opt/homebrew/bin:$PATH"
37
+ NODE_BIN=/opt/homebrew/bin/node
38
+
39
+ # For Homebrew on Intel
40
+ export PATH="/usr/local/bin:$PATH"
41
+ NODE_BIN=/usr/local/bin/node
42
+
43
+ # For nvm
44
+ NODE_BIN=/Users/username/.nvm/versions/node/v18.17.0/bin/node
45
+ ```
46
+
47
+ See `env.example` in this workflow for more configuration options.
48
+
49
+ ## Troubleshooting
50
+
51
+ **"node: command not found"**
52
+ - Install Node.js or configure the path in `~/.config/bktide/env`
53
+
54
+ **"Authentication failed"**
55
+ - Run `bktide token store` to set up your Buildkite API token
56
+
57
+ **Workflow is slow**
58
+ - Clear cache: `rm -rf ~/.cache/bktide`
59
+ - Check logs: `~/.local/state/bktide/logs/alfred.log`
60
+
61
+ ## Support
62
+
63
+ - Full documentation: See included `docs/alfred-installation.md`
64
+ - Issues: [GitHub Issues](https://github.com/yourusername/bktide/issues)
65
+ - Logs: `~/.local/state/bktide/logs/alfred.log`
@@ -0,0 +1,54 @@
1
+ #!/bin/bash
2
+
3
+ set -e
4
+ set -x
5
+
6
+ workflow_dir="$(dirname "$0")/.."
7
+ cd "$workflow_dir"
8
+
9
+ # Prefer Alfred's cache directory for logs; fall back to XDG if unavailable
10
+ if [[ -n "$alfred_workflow_cache" ]]; then
11
+ log_file="$alfred_workflow_cache/alfred.log"
12
+ else
13
+ log_file="$HOME/.local/state/bktide/logs/alfred.log"
14
+ fi
15
+ mkdir -p "$(dirname "$log_file")"
16
+
17
+ # Optionally source user-provided environment to customize PATH, NODE_BIN, etc.
18
+ xdg_config_home="${XDG_CONFIG_HOME:-$HOME/.config}"
19
+ user_env_file="$xdg_config_home/bktide/env"
20
+ workflow_env_file="$workflow_dir/.env"
21
+
22
+ if [[ -f "$user_env_file" ]]; then
23
+ # Export variables defined in the file
24
+ set -a
25
+ # shellcheck disable=SC1090
26
+ source "$user_env_file"
27
+ set +a
28
+ elif [[ -f "$workflow_env_file" ]]; then
29
+ set -a
30
+ # shellcheck disable=SC1090
31
+ source "$workflow_env_file"
32
+ set +a
33
+ fi
34
+
35
+ command="$1"
36
+ shift
37
+
38
+ if [[ -z "$command" ]]; then
39
+ echo "Usage: $0 <command> [filter]"
40
+ exit 1
41
+ fi
42
+
43
+ if [[ -z "$NODE_BIN" ]]; then
44
+ export NODE_BIN=node
45
+ fi
46
+
47
+ # Enable CLI debug mode if user config sets DEBUG=true/1 (compatible with macOS bash 3.2)
48
+ extra_flags=()
49
+ if [[ "$DEBUG" == "true" || "$DEBUG" == "TRUE" || "$DEBUG" == "True" || "$DEBUG" == "1" ]]; then
50
+ extra_flags+=("--debug")
51
+ fi
52
+
53
+ echo "Running command: $NODE_BIN $workflow_dir/dist/index.js $command" "$@" >> "$log_file"
54
+ "$NODE_BIN" "$workflow_dir/dist/index.js" "$command" --format alfred "${extra_flags[@]}" "$@" 2>&1 | tee -a "$log_file"
@@ -0,0 +1,159 @@
1
+ import { BuildkiteClient } from '../services/BuildkiteClient.js';
2
+ import { BuildkiteRestClient } from '../services/BuildkiteRestClient.js';
3
+ import { FormatterFactory } from '../formatters/index.js';
4
+ import { logger } from '../services/logger.js';
5
+ import { CredentialManager } from '../services/CredentialManager.js';
6
+ export class BaseCommand {
7
+ token;
8
+ requiresToken = true;
9
+ _client;
10
+ _restClient;
11
+ _restClientOptions;
12
+ options;
13
+ initialized = false;
14
+ static credentialManager = new CredentialManager();
15
+ constructor(options) {
16
+ this.options = options || {};
17
+ this.token = this.options.token;
18
+ if (this.options.debug) {
19
+ // Include token length (not the actual token) for debugging auth issues
20
+ // Debug mode is already handled here by logger.debug use
21
+ logger.debug('BaseCommandHandler options:', {
22
+ ...options,
23
+ token: this.token ? `${this.token.substring(0, 4)}...${this.token.substring(this.token.length - 4)} (${this.token.length} chars)` : 'Not provided'
24
+ });
25
+ }
26
+ }
27
+ get client() {
28
+ if (this._client) {
29
+ return this._client;
30
+ }
31
+ else {
32
+ if (this.token) {
33
+ this._client = new BuildkiteClient(this.token, this.options);
34
+ return this._client;
35
+ }
36
+ else {
37
+ throw new Error('No token provided');
38
+ }
39
+ }
40
+ }
41
+ get restClient() {
42
+ if (this._restClient) {
43
+ return this._restClient;
44
+ }
45
+ else {
46
+ if (this.token) {
47
+ this._restClient = new BuildkiteRestClient(this.token, this.options);
48
+ return this._restClient;
49
+ }
50
+ else {
51
+ throw new Error('No token provided');
52
+ }
53
+ }
54
+ }
55
+ get restClientOptions() {
56
+ if (this._restClientOptions) {
57
+ return this._restClientOptions;
58
+ }
59
+ else {
60
+ // Configure REST client with the same caching options
61
+ const restClientOptions = {
62
+ debug: this.options?.debug,
63
+ caching: !this.options?.noCache,
64
+ };
65
+ // If a specific cache TTL is provided, apply it to REST client
66
+ if (this.options?.cacheTTL) {
67
+ restClientOptions.cacheTTLs = {
68
+ default: this.options.cacheTTL,
69
+ builds: this.options.cacheTTL,
70
+ };
71
+ }
72
+ return restClientOptions;
73
+ }
74
+ }
75
+ static get requiresToken() {
76
+ return true;
77
+ }
78
+ async ensureInitialized() {
79
+ // No additional initialization needed
80
+ return Promise.resolve();
81
+ }
82
+ handleError(error, debug = false) {
83
+ // Only log the error message and stack trace
84
+ if (error instanceof Error) {
85
+ logger.error(error, 'Error occurred');
86
+ // If it's a GraphQL error or API error, show more details
87
+ const apiError = error;
88
+ if (apiError.response?.errors) {
89
+ apiError.response.errors.forEach((gqlError, index) => {
90
+ logger.error({ path: gqlError.path }, `GraphQL Error ${index + 1}: ${gqlError.message}`);
91
+ });
92
+ }
93
+ // Show request details if available and in debug mode
94
+ if (debug && apiError.request) {
95
+ logger.debug({
96
+ url: apiError.request.url,
97
+ method: apiError.request.method
98
+ }, 'Request Details');
99
+ }
100
+ }
101
+ else if (typeof error === 'object') {
102
+ logger.error({ error }, 'Unknown error occurred');
103
+ }
104
+ else {
105
+ logger.error({ error }, 'Unknown error occurred');
106
+ }
107
+ if (debug) {
108
+ logger.debug({
109
+ timestamp: new Date().toISOString(),
110
+ nodeVersion: process.version,
111
+ platform: `${process.platform} (${process.arch})`
112
+ }, 'Debug Information');
113
+ }
114
+ }
115
+ // Static helper to get token from options, keyring, or environment
116
+ static async getToken(options) {
117
+ // First check if token is provided directly in options
118
+ if (options.token) {
119
+ return options.token;
120
+ }
121
+ // Next try to get token from keyring
122
+ try {
123
+ const storedToken = await this.credentialManager.getToken();
124
+ if (storedToken) {
125
+ logger.debug('Using token from system keychain');
126
+ return storedToken;
127
+ }
128
+ }
129
+ catch (error) {
130
+ logger.debug('Error retrieving token from keychain', error);
131
+ }
132
+ // Finally fall back to environment variable
133
+ const envToken = process.env.BK_TOKEN;
134
+ if (envToken) {
135
+ return envToken;
136
+ }
137
+ if (options.requiresToken) {
138
+ throw new Error('API token required. Set via --token, BK_TOKEN environment variable, or store it using --save-token.');
139
+ }
140
+ else {
141
+ return;
142
+ }
143
+ }
144
+ /**
145
+ * Get the appropriate formatter based on command-specific type and format option
146
+ * @param type The formatter type ('pipeline', 'build', 'viewer')
147
+ * @param options Command options that may include a format
148
+ * @returns The appropriate formatter
149
+ */
150
+ getFormatter(type, options) {
151
+ // Format precedence: command line option > constructor option > default
152
+ const format = options.format || this.options.format || 'plain';
153
+ if (options.debug) {
154
+ logger.debug(`Using ${format} formatter for ${type}`);
155
+ }
156
+ return FormatterFactory.getFormatter(type, format);
157
+ }
158
+ }
159
+ //# sourceMappingURL=BaseCommand.js.map
@@ -0,0 +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}"]}
@@ -0,0 +1,80 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { BuildkiteClient } from '../services/BuildkiteClient.js';
11
+ export class BaseCommandHandler {
12
+ constructor(token, options) {
13
+ this.initialized = false;
14
+ this.token = token;
15
+ this.options = options || {};
16
+ if (options === null || options === void 0 ? void 0 : options.debug) {
17
+ console.log('Debug: BaseCommandHandler options:', JSON.stringify(options));
18
+ }
19
+ this.client = new BuildkiteClient(token);
20
+ this.initialized = true; // Client is initialized in constructor
21
+ }
22
+ ensureInitialized() {
23
+ return __awaiter(this, void 0, void 0, function* () {
24
+ // No additional initialization needed
25
+ return Promise.resolve();
26
+ });
27
+ }
28
+ handleError(error, debug = false) {
29
+ var _a;
30
+ console.error('\x1b[31m%s\x1b[0m', '🔥 Error Details:');
31
+ if (error instanceof Error) {
32
+ console.error('\x1b[31m%s\x1b[0m', `Message: ${error.message}`);
33
+ // Always print the stack trace for proper debugging
34
+ if (error.stack) {
35
+ console.error('\x1b[33m%s\x1b[0m', 'Stack Trace:');
36
+ console.error('\x1b[33m%s\x1b[0m', error.stack);
37
+ }
38
+ // If it's a GraphQL error or API error, show more details
39
+ const apiError = error;
40
+ if ((_a = apiError.response) === null || _a === void 0 ? void 0 : _a.errors) {
41
+ console.error('\x1b[33m%s\x1b[0m', 'GraphQL Errors:');
42
+ apiError.response.errors.forEach((gqlError, index) => {
43
+ console.error(` Error ${index + 1}: ${gqlError.message}`);
44
+ if (gqlError.path)
45
+ console.error(` Path: ${gqlError.path.join('.')}`);
46
+ if (gqlError.locations)
47
+ console.error(` Locations: ${JSON.stringify(gqlError.locations)}`);
48
+ console.error('');
49
+ });
50
+ }
51
+ // Show request details if available and in debug mode
52
+ if (debug && apiError.request) {
53
+ console.error('\x1b[36m%s\x1b[0m', 'Request Details:');
54
+ console.error(` URL: ${apiError.request.url || 'N/A'}`);
55
+ console.error(` Method: ${apiError.request.method || 'N/A'}`);
56
+ }
57
+ }
58
+ else if (typeof error === 'object') {
59
+ console.error('\x1b[31m%s\x1b[0m', JSON.stringify(error, null, 2));
60
+ }
61
+ else {
62
+ console.error('\x1b[31m%s\x1b[0m', 'An unknown error occurred:', error);
63
+ }
64
+ if (debug) {
65
+ console.error('\x1b[36m%s\x1b[0m', '\nDebug Information:');
66
+ console.error('\x1b[36m%s\x1b[0m', `⏰ Timestamp: ${new Date().toISOString()}`);
67
+ console.error('\x1b[36m%s\x1b[0m', `🔧 Node Version: ${process.version}`);
68
+ console.error('\x1b[36m%s\x1b[0m', `💻 Platform: ${process.platform} (${process.arch})`);
69
+ }
70
+ }
71
+ // Static helper to get token from options or environment
72
+ static getToken(options) {
73
+ const token = options.token || process.env.BK_TOKEN;
74
+ if (!token) {
75
+ throw new Error('API token required. Set via --token or BK_TOKEN environment variable.');
76
+ }
77
+ return token;
78
+ }
79
+ }
80
+ //# sourceMappingURL=BaseCommandHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseCommandHandler.js","sourceRoot":"/","sources":["commands/BaseCommandHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import { BuildkiteClient } from '../services/BuildkiteClient.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 BaseCommandHandler {\n protected token: string;\n protected client: BuildkiteClient;\n protected options: Partial<BaseCommandOptions>;\n protected initialized: boolean = false;\n\n constructor(token: string, options?: Partial<BaseCommandOptions>) {\n this.token = token;\n this.options = options || {};\n if (options?.debug) {\n console.log('Debug: BaseCommandHandler options:', JSON.stringify(options));\n }\n this.client = new BuildkiteClient(token);\n this.initialized = true; // Client is initialized in constructor\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 console.error('\\x1b[31m%s\\x1b[0m', '🔥 Error Details:');\n \n if (error instanceof Error) {\n console.error('\\x1b[31m%s\\x1b[0m', `Message: ${error.message}`);\n \n // Always print the stack trace for proper debugging\n if (error.stack) {\n console.error('\\x1b[33m%s\\x1b[0m', 'Stack Trace:');\n console.error('\\x1b[33m%s\\x1b[0m', error.stack);\n }\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 console.error('\\x1b[33m%s\\x1b[0m', 'GraphQL Errors:');\n apiError.response.errors.forEach((gqlError, index) => {\n console.error(` Error ${index + 1}: ${gqlError.message}`);\n if (gqlError.path) console.error(` Path: ${gqlError.path.join('.')}`);\n if (gqlError.locations) console.error(` Locations: ${JSON.stringify(gqlError.locations)}`);\n console.error('');\n });\n }\n \n // Show request details if available and in debug mode\n if (debug && apiError.request) {\n console.error('\\x1b[36m%s\\x1b[0m', 'Request Details:');\n console.error(` URL: ${apiError.request.url || 'N/A'}`);\n console.error(` Method: ${apiError.request.method || 'N/A'}`);\n }\n } else if (typeof error === 'object') {\n console.error('\\x1b[31m%s\\x1b[0m', JSON.stringify(error, null, 2));\n } else {\n console.error('\\x1b[31m%s\\x1b[0m', 'An unknown error occurred:', error);\n }\n \n if (debug) {\n console.error('\\x1b[36m%s\\x1b[0m', '\\nDebug Information:');\n console.error('\\x1b[36m%s\\x1b[0m', `⏰ Timestamp: ${new Date().toISOString()}`);\n console.error('\\x1b[36m%s\\x1b[0m', `🔧 Node Version: ${process.version}`);\n console.error('\\x1b[36m%s\\x1b[0m', `💻 Platform: ${process.platform} (${process.arch})`);\n }\n }\n\n // Static helper to get token from options or environment\n static getToken(options: any): string {\n const token = options.token || process.env.BK_TOKEN;\n if (!token) {\n throw new Error('API token required. Set via --token or BK_TOKEN environment variable.');\n }\n return token;\n }\n} "]}
@@ -0,0 +1,28 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { BaseCommandHandler } from './BaseCommandHandler.js';
11
+ export class BuildCommandHandler extends BaseCommandHandler {
12
+ triggerBuild(options) {
13
+ return __awaiter(this, void 0, void 0, function* () {
14
+ try {
15
+ // Currently just logging, but would implement the actual API call
16
+ console.log('Triggering build with options:', options);
17
+ // Implementation would go here
18
+ // TODO: Implement build triggering logic using the Buildkite API
19
+ }
20
+ catch (error) {
21
+ console.error('Error triggering build:');
22
+ this.handleError(error, options.debug);
23
+ process.exit(1);
24
+ }
25
+ });
26
+ }
27
+ }
28
+ //# sourceMappingURL=BuildCommandHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BuildCommandHandler.js","sourceRoot":"","sources":["../../src/commands/BuildCommandHandler.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAW7D,MAAM,OAAO,mBAAoB,SAAQ,kBAAkB;IACnD,YAAY,CAAC,OAAqB;;YACtC,IAAI,CAAC;gBACH,kEAAkE;gBAClE,OAAO,CAAC,GAAG,CAAC,gCAAgC,EAAE,OAAO,CAAC,CAAC;gBAEvD,+BAA+B;gBAC/B,iEAAiE;YAEnE,CAAC;YAAC,OAAO,KAAU,EAAE,CAAC;gBACpB,OAAO,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;gBACzC,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;gBACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;KAAA;CACF"}
@@ -0,0 +1,6 @@
1
+ export class HelloCommandHandler {
2
+ execute() {
3
+ console.log('Hello from bk-cli!');
4
+ }
5
+ }
6
+ //# sourceMappingURL=HelloCommandHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HelloCommandHandler.js","sourceRoot":"","sources":["../../src/commands/HelloCommandHandler.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,mBAAmB;IAC9B,OAAO;QACL,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IACpC,CAAC;CACF"}
@@ -0,0 +1,60 @@
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
+ export class ListAnnotations extends BaseCommand {
6
+ static requiresToken = true;
7
+ async execute(options) {
8
+ if (options.debug) {
9
+ logger.debug('Starting ListAnnotations command execution');
10
+ }
11
+ if (!options.buildArg) {
12
+ logger.error('Build reference is required');
13
+ return 1;
14
+ }
15
+ try {
16
+ // Ensure the command is initialized
17
+ await this.ensureInitialized();
18
+ const buildRef = parseBuildRef(options.buildArg);
19
+ if (options.debug) {
20
+ logger.debug('Parsed build reference:', buildRef);
21
+ }
22
+ // Fetch annotations from the GraphQL API
23
+ const buildSlug = `${buildRef.org}/${buildRef.pipeline}/${buildRef.number}`;
24
+ const result = await this.client.getBuildAnnotations(buildSlug);
25
+ // Extract annotations from the GraphQL response
26
+ let annotations = result.build?.annotations?.edges?.map((edge) => edge.node) || [];
27
+ // Filter by context if specified
28
+ if (options.context) {
29
+ const contextFilter = options.context.toLowerCase();
30
+ annotations = annotations.filter(annotation => annotation.context.toLowerCase() === contextFilter);
31
+ if (options.debug) {
32
+ logger.debug(`Filtered annotations by context '${options.context}': ${annotations.length} found`);
33
+ }
34
+ }
35
+ // Get the appropriate formatter
36
+ const formatter = FormatterFactory.getFormatter(FormatterType.ANNOTATION, options.format || 'plain'); // Cast to any since FormatterFactory returns BaseFormatter
37
+ // Format and output the results
38
+ const output = formatter.formatAnnotations(annotations, {
39
+ debug: options.debug,
40
+ contextFilter: options.context
41
+ });
42
+ logger.console(output);
43
+ return 0;
44
+ }
45
+ catch (error) {
46
+ logger.error('Failed to fetch annotations:', error);
47
+ // Handle the error with the formatter
48
+ const formatter = FormatterFactory.getFormatter(FormatterType.ANNOTATION, options.format || 'plain'); // Cast to any since FormatterFactory returns BaseFormatter
49
+ const errorOutput = formatter.formatAnnotations([], {
50
+ hasError: true,
51
+ errorMessage: error instanceof Error ? error.message : 'Unknown error occurred',
52
+ errorType: 'api',
53
+ debug: options.debug
54
+ });
55
+ logger.console(errorOutput);
56
+ return 1;
57
+ }
58
+ }
59
+ }
60
+ //# sourceMappingURL=ListAnnotations.js.map
@@ -0,0 +1 @@
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\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"]}