bktide 1.0.1755655078 → 1.0.1765378562

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 (39) hide show
  1. package/README.md +67 -19
  2. package/dist/commands/SmartShow.js +250 -0
  3. package/dist/commands/SmartShow.js.map +1 -0
  4. package/dist/commands/index.js +1 -0
  5. package/dist/commands/index.js.map +1 -1
  6. package/dist/formatters/pipeline-detail/AlfredFormatter.js +57 -0
  7. package/dist/formatters/pipeline-detail/AlfredFormatter.js.map +1 -0
  8. package/dist/formatters/pipeline-detail/Formatter.js +7 -0
  9. package/dist/formatters/pipeline-detail/Formatter.js.map +1 -0
  10. package/dist/formatters/pipeline-detail/JsonFormatter.js +11 -0
  11. package/dist/formatters/pipeline-detail/JsonFormatter.js.map +1 -0
  12. package/dist/formatters/pipeline-detail/PlainFormatter.js +55 -0
  13. package/dist/formatters/pipeline-detail/PlainFormatter.js.map +1 -0
  14. package/dist/formatters/pipeline-detail/index.js +5 -0
  15. package/dist/formatters/pipeline-detail/index.js.map +1 -0
  16. package/dist/formatters/step-logs/AlfredFormatter.js +72 -0
  17. package/dist/formatters/step-logs/AlfredFormatter.js.map +1 -0
  18. package/dist/formatters/step-logs/Formatter.js +7 -0
  19. package/dist/formatters/step-logs/Formatter.js.map +1 -0
  20. package/dist/formatters/step-logs/JsonFormatter.js +11 -0
  21. package/dist/formatters/step-logs/JsonFormatter.js.map +1 -0
  22. package/dist/formatters/step-logs/PlainFormatter.js +47 -0
  23. package/dist/formatters/step-logs/PlainFormatter.js.map +1 -0
  24. package/dist/formatters/step-logs/index.js +5 -0
  25. package/dist/formatters/step-logs/index.js.map +1 -0
  26. package/dist/graphql/queries.js +22 -0
  27. package/dist/graphql/queries.js.map +1 -1
  28. package/dist/index.js +45 -4
  29. package/dist/index.js.map +1 -1
  30. package/dist/services/BuildkiteClient.js +18 -1
  31. package/dist/services/BuildkiteClient.js.map +1 -1
  32. package/dist/services/BuildkiteRestClient.js +73 -0
  33. package/dist/services/BuildkiteRestClient.js.map +1 -1
  34. package/dist/types/buildkite.js.map +1 -1
  35. package/dist/utils/formatUtils.js +91 -0
  36. package/dist/utils/formatUtils.js.map +1 -0
  37. package/dist/utils/parseBuildkiteReference.js +93 -0
  38. package/dist/utils/parseBuildkiteReference.js.map +1 -0
  39. package/package.json +1 -1
package/README.md CHANGED
@@ -37,25 +37,35 @@ echo 'source <(bktide completions zsh)' >> ~/.zshrc
37
37
  ```
38
38
 
39
39
  Completions provide:
40
- - Command suggestions (`bktide <Tab>`)
41
- - Option completions (`bktide builds --<Tab>`)
42
- - Value completions (`bktide --format <Tab>`)
40
+ - Command suggestions (ie `bktide <Tab>`)
41
+ - Option completions (ie `bktide builds --<Tab>`)
42
+ - Value completions (ie `bktide --format <Tab>`)
43
43
  - Dynamic completions for organizations and pipelines (Fish with jq installed)
44
44
 
45
45
  See [Shell Completions Guide](docs/shell-completions.md) for detailed installation and troubleshooting.
46
46
 
47
47
  ## Documentation
48
48
 
49
- - [Shell Completions](docs/shell-completions.md) - Complete guide for shell auto-completion setup
50
- - [Development Guide](docs/development.md) - Information about running and developing the CLI
51
- - [Authentication](docs/authentication.md) - How to authenticate with Buildkite
52
- - [Caching](docs/caching.md) - Information about the CLI's caching system
53
- - [Testing Guide](docs/testing-guide.md) - Running tests and testing strategy
54
- - [API Reference](docs/api-reference.md) - Complete command reference
55
- - [Troubleshooting](docs/troubleshooting.md) - Common issues and solutions
56
- - [Alfred Integration (Overview)](docs/alfred.md) - What the Alfred integration does and quick usage
57
- - [Alfred Installation](docs/alfred-installation.md) - End-user install, configuration, and troubleshooting
58
- - [Alfred Development](docs/alfred-development.md) - Packaging, wrapper behavior, metadata, and workflow wiring
49
+ Our documentation is organized by audience to help you find what you need:
50
+
51
+ ### 📖 [User Documentation](docs/user/) - For end users
52
+ - [Getting Started](docs/user/getting-started.md) - Quick start guide for new users
53
+ - [Authentication](docs/user/authentication.md) - How to authenticate with Buildkite
54
+ - [Shell Completions](docs/user/shell-completions.md) - Setting up auto-completion
55
+ - [Troubleshooting](docs/user/troubleshooting.md) - Common issues and solutions
56
+ - [Alfred Integration](docs/user/alfred/) - macOS Alfred workflow (installation, troubleshooting)
57
+
58
+ ### 👨‍💻 [Developer Documentation](docs/developer/) - For contributors
59
+ - [Contributing Guide](docs/developer/contributing.md) - How to contribute to the project
60
+ - [Development Guide](docs/developer/development.md) - Setup and coding guidelines
61
+ - [Alfred Workflow Development](docs/developer/alfred-workflow-development.md) - Building and packaging
62
+ - [Testing Strategy](docs/developer/testing/README.md) - Testing approach and procedures
63
+
64
+ ### 📚 [Reference Documentation](docs/reference/) - For everyone
65
+ - [Changelogs](docs/reference/) - What changed and when
66
+ - [Release Process](docs/reference/releasing.md) - How releases work
67
+
68
+ See [Documentation Overview](docs/README.md) for the complete structure and classification guide.
59
69
 
60
70
  ## Testing
61
71
 
@@ -67,7 +77,7 @@ npm run test:coverage # Generate coverage report
67
77
  npm run test:extract-patterns # Extract patterns from real data (requires token)
68
78
  ```
69
79
 
70
- See [Testing Guide](docs/testing/README.md) for details on the hybrid testing strategy.
80
+ See [Testing Strategy](docs/developer/testing/README.md) for details on the hybrid testing approach.
71
81
 
72
82
  ## Usage
73
83
 
@@ -139,7 +149,7 @@ bktide annotations <build>
139
149
 
140
150
  The build reference can be specified in two formats:
141
151
  - **Slug format**: `org/pipeline/number` (e.g., `gusto/zenpayroll/1287418`)
142
- - **URL format**: `@https://buildkite.com/org/pipeline/builds/number` or `https://buildkite.com/org/pipeline/builds/number`
152
+ - **URL format**: `https://buildkite.com/org/pipeline/builds/number`
143
153
 
144
154
  Additional options:
145
155
  ```bash
@@ -165,7 +175,7 @@ View detailed information about a specific build including jobs and annotations.
165
175
  bktide build org/pipeline/123
166
176
 
167
177
  # View build by URL format
168
- bktide build @https://buildkite.com/org/pipeline/builds/123
178
+ bktide build https://buildkite.com/org/pipeline/builds/123
169
179
  ```
170
180
 
171
181
  Additional options:
@@ -183,6 +193,44 @@ bktide build org/pipeline/123 --annotations
183
193
  bktide build org/pipeline/123 --jobs --failed --annotations
184
194
  ```
185
195
 
196
+ ### Smart Reference Command
197
+
198
+ Paste any Buildkite URL or use short-hand formats, and bktide will figure out what to show.
199
+
200
+ **Supported formats:**
201
+
202
+ ```bash
203
+ # Pipeline view (shows metadata + recent builds)
204
+ bktide gusto/schemaflow
205
+ bktide https://buildkite.com/gusto/schemaflow
206
+
207
+ # Build view (shows comprehensive build details)
208
+ bktide gusto/schemaflow/76
209
+ bktide gusto/schemaflow#76
210
+ bktide https://buildkite.com/gusto/schemaflow/builds/76
211
+
212
+ # Step logs (shows build context + step logs)
213
+ bktide https://buildkite.com/gusto/schemaflow/builds/76?sid=019adb19-bd83-4149-b2a7-ece1d7a41c9d
214
+ ```
215
+
216
+ **Log display options:**
217
+
218
+ ```bash
219
+ # Show last 50 lines (default)
220
+ bktide https://buildkite.com/org/pipeline/builds/123?sid=<step-id>
221
+
222
+ # Show all lines
223
+ bktide https://buildkite.com/org/pipeline/builds/123?sid=<step-id> --full
224
+
225
+ # Show last N lines
226
+ bktide https://buildkite.com/org/pipeline/builds/123?sid=<step-id> --lines 100
227
+
228
+ # Save logs to file
229
+ bktide https://buildkite.com/org/pipeline/builds/123?sid=<step-id> --save logs.txt
230
+ ```
231
+
232
+ **Note:** Viewing step logs requires `read_build_logs` scope on your API token.
233
+
186
234
  ### Generate Shell Completions
187
235
 
188
236
  ```bash
@@ -315,12 +363,12 @@ Available log levels (from most to least verbose):
315
363
 
316
364
  ## Log Files
317
365
 
318
- All logs are written to `log/cli.log` in JSON format, which can be processed with tools like jq:
366
+ All logs are written to `~/.local/state/bktide/logs/cli.log` in JSON format, which can be processed with tools like jq:
319
367
 
320
368
  ```bash
321
369
  # View recent errors
322
- cat log/cli.log | grep -v '"level":30' | jq
370
+ cat ~/.local/state/bktide/logs/cli.log | grep -v '"level":30' | jq
323
371
 
324
372
  # Analyze performance
325
- cat log/cli.log | jq 'select(.duration != null) | {msg, duration}'
373
+ cat ~/.local/state/bktide/logs/cli.log | jq 'select(.duration != null) | {msg, duration}'
326
374
  ```
@@ -0,0 +1,250 @@
1
+ import { BaseCommand } from './BaseCommand.js';
2
+ import { parseBuildkiteReference } from '../utils/parseBuildkiteReference.js';
3
+ import { logger } from '../services/logger.js';
4
+ import { ShowBuild } from './ShowBuild.js';
5
+ import { PlainPipelineDetailFormatter, JsonPipelineDetailFormatter, AlfredPipelineDetailFormatter } from '../formatters/pipeline-detail/index.js';
6
+ import { PlainStepLogsFormatter, JsonStepLogsFormatter, AlfredStepLogsFormatter } from '../formatters/step-logs/index.js';
7
+ import { SEMANTIC_COLORS, formatError } from '../ui/theme.js';
8
+ import { Progress } from '../ui/progress.js';
9
+ import * as fs from 'fs/promises';
10
+ export class SmartShow extends BaseCommand {
11
+ static requiresToken = true;
12
+ async execute(options) {
13
+ if (options.debug) {
14
+ logger.debug('Starting SmartShow command execution', options);
15
+ }
16
+ if (!options.reference) {
17
+ logger.error('Reference is required');
18
+ return 1;
19
+ }
20
+ try {
21
+ // Parse the reference
22
+ const ref = parseBuildkiteReference(options.reference);
23
+ if (options.debug) {
24
+ logger.debug('Parsed reference:', ref);
25
+ }
26
+ // Route based on reference type
27
+ switch (ref.type) {
28
+ case 'pipeline':
29
+ return await this.showPipeline(ref, options);
30
+ case 'build':
31
+ return await this.showBuild(ref, options);
32
+ case 'build-with-step':
33
+ return await this.showBuildWithStep(ref, options);
34
+ default:
35
+ logger.error('Unknown reference type');
36
+ return 1;
37
+ }
38
+ }
39
+ catch (error) {
40
+ if (error instanceof Error) {
41
+ const errorOutput = formatError(error.message, {
42
+ suggestions: ['Check the reference format', 'Verify you have access to this resource'],
43
+ });
44
+ logger.console(errorOutput);
45
+ }
46
+ else {
47
+ logger.error('Unknown error occurred');
48
+ }
49
+ return 1;
50
+ }
51
+ }
52
+ async showPipeline(ref, options) {
53
+ const format = options.format || 'plain';
54
+ const spinner = Progress.spinner('Fetching pipeline details...', { format });
55
+ try {
56
+ // Initialize token first
57
+ this.token = await BaseCommand.getToken(options);
58
+ // Fetch pipeline details
59
+ const pipeline = await this.client.getPipeline(ref.org, ref.pipeline);
60
+ spinner.stop();
61
+ if (!pipeline) {
62
+ logger.error(`Pipeline not found: ${ref.org}/${ref.pipeline}`);
63
+ return 1;
64
+ }
65
+ // Fetch recent builds using pipeline-specific endpoint
66
+ const builds = await this.restClient.getPipelineBuilds(ref.org, ref.pipeline, {
67
+ per_page: '20',
68
+ });
69
+ // Prepare data for formatter
70
+ const data = {
71
+ org: ref.org,
72
+ pipeline: {
73
+ name: pipeline.name,
74
+ slug: pipeline.slug,
75
+ description: pipeline.description,
76
+ defaultBranch: pipeline.defaultBranch,
77
+ url: pipeline.url,
78
+ repository: pipeline.repository,
79
+ },
80
+ recentBuilds: (builds || []).map((build) => ({
81
+ number: build.number,
82
+ state: build.state,
83
+ branch: build.branch,
84
+ message: build.message,
85
+ startedAt: build.started_at,
86
+ finishedAt: build.finished_at,
87
+ })),
88
+ };
89
+ // Format and display
90
+ let formatter;
91
+ if (format === 'alfred') {
92
+ formatter = new AlfredPipelineDetailFormatter({});
93
+ }
94
+ else if (format === 'json') {
95
+ formatter = new JsonPipelineDetailFormatter({});
96
+ }
97
+ else {
98
+ formatter = new PlainPipelineDetailFormatter({});
99
+ }
100
+ const output = formatter.format(data);
101
+ logger.console(output);
102
+ return 0;
103
+ }
104
+ catch (error) {
105
+ spinner.stop();
106
+ if (error instanceof Error) {
107
+ const errorOutput = formatError(error.message, {
108
+ suggestions: ['Check the reference format', 'Verify you have access to this resource'],
109
+ });
110
+ logger.console(errorOutput);
111
+ }
112
+ else {
113
+ logger.error('Unknown error occurred');
114
+ }
115
+ return 1;
116
+ }
117
+ }
118
+ async showBuild(ref, options) {
119
+ // Route to ShowBuild with enhanced defaults (--jobs --failed)
120
+ const buildCommand = new ShowBuild(options);
121
+ const buildOptions = {
122
+ ...options,
123
+ buildArg: `${ref.org}/${ref.pipeline}/${ref.buildNumber}`,
124
+ jobs: true,
125
+ failed: true,
126
+ };
127
+ return await buildCommand.execute(buildOptions);
128
+ }
129
+ async showBuildWithStep(ref, options) {
130
+ const format = options.format || 'plain';
131
+ const spinner = Progress.spinner('Fetching step logs...', { format });
132
+ try {
133
+ // Initialize token first
134
+ this.token = await BaseCommand.getToken(options);
135
+ // Use REST API to get build with jobs (step.id field needed for matching)
136
+ const build = await this.restClient.getBuild(ref.org, ref.pipeline, ref.buildNumber);
137
+ const jobs = build.jobs || [];
138
+ if (!jobs || jobs.length === 0) {
139
+ spinner.stop();
140
+ logger.error(`Build not found: ${ref.org}/${ref.pipeline}/${ref.buildNumber}`);
141
+ return 1;
142
+ }
143
+ // Find job by step ID (sid from URL) - step.id is different from job.id
144
+ if (options.debug) {
145
+ logger.debug(`Found ${jobs.length} jobs in build`);
146
+ logger.debug(`Looking for step ID: ${ref.stepId}`);
147
+ // Log first few jobs for debugging
148
+ jobs.slice(0, 3).forEach((j) => {
149
+ logger.debug(` Job: id=${j.id}, step.id=${j.step?.id}, name=${j.name}`);
150
+ });
151
+ }
152
+ const job = jobs.find((j) => j.step?.id === ref.stepId);
153
+ if (!job) {
154
+ spinner.stop();
155
+ logger.error(`Step not found in build #${ref.buildNumber}: ${ref.stepId}`);
156
+ return 1;
157
+ }
158
+ // Use job.id (job UUID) for log fetching, not ref.stepId
159
+ const logData = await this.restClient.getJobLog(ref.org, ref.pipeline, ref.buildNumber, job.id);
160
+ spinner.stop();
161
+ // Parse log content
162
+ const logLines = logData.content.split('\n');
163
+ const totalLines = logLines.length;
164
+ // Determine how many lines to display
165
+ const linesToShow = options.full ? totalLines : (options.lines || 50);
166
+ const startLine = Math.max(0, totalLines - linesToShow);
167
+ const displayedLines = logLines.slice(startLine);
168
+ // Save to file if requested
169
+ if (options.save) {
170
+ await fs.writeFile(options.save, logData.content);
171
+ logger.console(SEMANTIC_COLORS.success(`✓ Log saved to ${options.save} (${this.formatSize(logData.size)}, ${totalLines} lines)`));
172
+ }
173
+ // Prepare data for formatter using REST API fields from build object
174
+ const data = {
175
+ build: {
176
+ org: ref.org,
177
+ pipeline: ref.pipeline,
178
+ number: ref.buildNumber,
179
+ state: build.state || 'unknown',
180
+ startedAt: build.started_at,
181
+ finishedAt: build.finished_at,
182
+ url: build.web_url,
183
+ },
184
+ step: {
185
+ id: job.id,
186
+ label: job.name,
187
+ state: job.state,
188
+ exitStatus: job.exit_status,
189
+ startedAt: job.started_at,
190
+ finishedAt: job.finished_at,
191
+ },
192
+ logs: {
193
+ content: displayedLines.join('\n'),
194
+ size: logData.size,
195
+ totalLines,
196
+ displayedLines: displayedLines.length,
197
+ startLine,
198
+ },
199
+ };
200
+ // Format and display (unless only saving)
201
+ if (!options.save || options.format) {
202
+ let formatter;
203
+ if (format === 'alfred') {
204
+ formatter = new AlfredStepLogsFormatter({ full: options.full, lines: options.lines });
205
+ }
206
+ else if (format === 'json') {
207
+ formatter = new JsonStepLogsFormatter({ full: options.full, lines: options.lines });
208
+ }
209
+ else {
210
+ formatter = new PlainStepLogsFormatter({ full: options.full, lines: options.lines });
211
+ }
212
+ const output = formatter.format(data);
213
+ logger.console(output);
214
+ }
215
+ return 0;
216
+ }
217
+ catch (error) {
218
+ spinner.stop();
219
+ if (error instanceof Error) {
220
+ if (error.message.includes('401') || error.message.includes('403')) {
221
+ const errorOutput = formatError('Permission denied', {
222
+ suggestions: [
223
+ 'Your API token needs \'read_build_logs\' scope to view logs',
224
+ 'Update your token at: https://buildkite.com/user/api-access-tokens',
225
+ ],
226
+ });
227
+ logger.console(errorOutput);
228
+ }
229
+ else {
230
+ const errorOutput = formatError(error.message, {
231
+ suggestions: ['Check the reference format', 'Verify you have access to this resource'],
232
+ });
233
+ logger.console(errorOutput);
234
+ }
235
+ }
236
+ else {
237
+ logger.error('Unknown error occurred');
238
+ }
239
+ return 1;
240
+ }
241
+ }
242
+ formatSize(bytes) {
243
+ if (bytes < 1024)
244
+ return `${bytes} B`;
245
+ if (bytes < 1024 * 1024)
246
+ return `${(bytes / 1024).toFixed(1)} KB`;
247
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
248
+ }
249
+ }
250
+ //# sourceMappingURL=SmartShow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SmartShow.js","sourceRoot":"/","sources":["commands/SmartShow.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseCommand, BaseCommandOptions } from './BaseCommand.js';\nimport { parseBuildkiteReference, BuildkiteReference } from '../utils/parseBuildkiteReference.js';\nimport { logger } from '../services/logger.js';\nimport { ShowBuild } from './ShowBuild.js';\nimport { PlainPipelineDetailFormatter, JsonPipelineDetailFormatter, AlfredPipelineDetailFormatter } from '../formatters/pipeline-detail/index.js';\nimport type { PipelineDetailData } from '../formatters/pipeline-detail/Formatter.js';\nimport { PlainStepLogsFormatter, JsonStepLogsFormatter, AlfredStepLogsFormatter } from '../formatters/step-logs/index.js';\nimport type { StepLogsData } from '../formatters/step-logs/Formatter.js';\nimport { SEMANTIC_COLORS, formatError } from '../ui/theme.js';\nimport { Progress } from '../ui/progress.js';\nimport * as fs from 'fs/promises';\n\nexport interface SmartShowOptions extends BaseCommandOptions {\n reference: string;\n // Log display options\n full?: boolean;\n lines?: number;\n save?: string;\n}\n\nexport class SmartShow extends BaseCommand {\n static requiresToken = true;\n\n async execute(options: SmartShowOptions): Promise<number> {\n if (options.debug) {\n logger.debug('Starting SmartShow command execution', options);\n }\n\n if (!options.reference) {\n logger.error('Reference is required');\n return 1;\n }\n\n try {\n // Parse the reference\n const ref = parseBuildkiteReference(options.reference);\n \n if (options.debug) {\n logger.debug('Parsed reference:', ref);\n }\n\n // Route based on reference type\n switch (ref.type) {\n case 'pipeline':\n return await this.showPipeline(ref, options);\n case 'build':\n return await this.showBuild(ref, options);\n case 'build-with-step':\n return await this.showBuildWithStep(ref, options);\n default:\n logger.error('Unknown reference type');\n return 1;\n }\n } catch (error) {\n if (error instanceof Error) {\n const errorOutput = formatError(error.message, {\n suggestions: ['Check the reference format', 'Verify you have access to this resource'],\n });\n logger.console(errorOutput);\n } else {\n logger.error('Unknown error occurred');\n }\n return 1;\n }\n }\n\n private async showPipeline(\n ref: Extract<BuildkiteReference, { type: 'pipeline' }>,\n options: SmartShowOptions\n ): Promise<number> {\n const format = options.format || 'plain';\n const spinner = Progress.spinner('Fetching pipeline details...', { format });\n\n try {\n // Initialize token first\n this.token = await BaseCommand.getToken(options);\n \n // Fetch pipeline details\n const pipeline = await this.client.getPipeline(ref.org, ref.pipeline);\n spinner.stop();\n \n if (!pipeline) {\n logger.error(`Pipeline not found: ${ref.org}/${ref.pipeline}`);\n return 1;\n }\n\n // Fetch recent builds using pipeline-specific endpoint\n const builds = await this.restClient.getPipelineBuilds(ref.org, ref.pipeline, {\n per_page: '20',\n });\n\n // Prepare data for formatter\n const data: PipelineDetailData = {\n org: ref.org,\n pipeline: {\n name: pipeline.name,\n slug: pipeline.slug,\n description: pipeline.description,\n defaultBranch: pipeline.defaultBranch,\n url: pipeline.url,\n repository: pipeline.repository,\n },\n recentBuilds: (builds || []).map((build: any) => ({\n number: build.number,\n state: build.state,\n branch: build.branch,\n message: build.message,\n startedAt: build.started_at,\n finishedAt: build.finished_at,\n })),\n };\n\n // Format and display\n let formatter;\n \n if (format === 'alfred') {\n formatter = new AlfredPipelineDetailFormatter({});\n } else if (format === 'json') {\n formatter = new JsonPipelineDetailFormatter({});\n } else {\n formatter = new PlainPipelineDetailFormatter({});\n }\n\n const output = formatter.format(data);\n logger.console(output);\n\n return 0;\n } catch (error) {\n spinner.stop();\n if (error instanceof Error) {\n const errorOutput = formatError(error.message, {\n suggestions: ['Check the reference format', 'Verify you have access to this resource'],\n });\n logger.console(errorOutput);\n } else {\n logger.error('Unknown error occurred');\n }\n return 1;\n }\n }\n\n private async showBuild(\n ref: Extract<BuildkiteReference, { type: 'build' }>,\n options: SmartShowOptions\n ): Promise<number> {\n // Route to ShowBuild with enhanced defaults (--jobs --failed)\n const buildCommand = new ShowBuild(options);\n \n const buildOptions = {\n ...options,\n buildArg: `${ref.org}/${ref.pipeline}/${ref.buildNumber}`,\n jobs: true,\n failed: true,\n };\n\n return await buildCommand.execute(buildOptions);\n }\n\n private async showBuildWithStep(\n ref: Extract<BuildkiteReference, { type: 'build-with-step' }>,\n options: SmartShowOptions\n ): Promise<number> {\n const format = options.format || 'plain';\n const spinner = Progress.spinner('Fetching step logs...', { format });\n\n try {\n // Initialize token first\n this.token = await BaseCommand.getToken(options);\n\n // Use REST API to get build with jobs (step.id field needed for matching)\n const build = await this.restClient.getBuild(ref.org, ref.pipeline, ref.buildNumber);\n const jobs = build.jobs || [];\n \n if (!jobs || jobs.length === 0) {\n spinner.stop();\n logger.error(`Build not found: ${ref.org}/${ref.pipeline}/${ref.buildNumber}`);\n return 1;\n }\n\n // Find job by step ID (sid from URL) - step.id is different from job.id\n if (options.debug) {\n logger.debug(`Found ${jobs.length} jobs in build`);\n logger.debug(`Looking for step ID: ${ref.stepId}`);\n // Log first few jobs for debugging\n jobs.slice(0, 3).forEach((j: any) => {\n logger.debug(` Job: id=${j.id}, step.id=${j.step?.id}, name=${j.name}`);\n });\n }\n const job = jobs.find((j: any) => j.step?.id === ref.stepId);\n \n if (!job) {\n spinner.stop();\n logger.error(`Step not found in build #${ref.buildNumber}: ${ref.stepId}`);\n return 1;\n }\n\n // Use job.id (job UUID) for log fetching, not ref.stepId\n const logData = await this.restClient.getJobLog(ref.org, ref.pipeline, ref.buildNumber, job.id);\n spinner.stop();\n\n // Parse log content\n const logLines = logData.content.split('\\n');\n const totalLines = logLines.length;\n \n // Determine how many lines to display\n const linesToShow = options.full ? totalLines : (options.lines || 50);\n const startLine = Math.max(0, totalLines - linesToShow);\n const displayedLines = logLines.slice(startLine);\n\n // Save to file if requested\n if (options.save) {\n await fs.writeFile(options.save, logData.content);\n logger.console(SEMANTIC_COLORS.success(`✓ Log saved to ${options.save} (${this.formatSize(logData.size)}, ${totalLines} lines)`));\n }\n\n // Prepare data for formatter using REST API fields from build object\n const data: StepLogsData = {\n build: {\n org: ref.org,\n pipeline: ref.pipeline,\n number: ref.buildNumber,\n state: build.state || 'unknown',\n startedAt: build.started_at,\n finishedAt: build.finished_at,\n url: build.web_url,\n },\n step: {\n id: job.id,\n label: job.name,\n state: job.state,\n exitStatus: job.exit_status,\n startedAt: job.started_at,\n finishedAt: job.finished_at,\n },\n logs: {\n content: displayedLines.join('\\n'),\n size: logData.size,\n totalLines,\n displayedLines: displayedLines.length,\n startLine,\n },\n };\n\n // Format and display (unless only saving)\n if (!options.save || options.format) {\n let formatter;\n \n if (format === 'alfred') {\n formatter = new AlfredStepLogsFormatter({ full: options.full, lines: options.lines });\n } else if (format === 'json') {\n formatter = new JsonStepLogsFormatter({ full: options.full, lines: options.lines });\n } else {\n formatter = new PlainStepLogsFormatter({ full: options.full, lines: options.lines });\n }\n\n const output = formatter.format(data);\n logger.console(output);\n }\n\n return 0;\n } catch (error) {\n spinner.stop();\n if (error instanceof Error) {\n if (error.message.includes('401') || error.message.includes('403')) {\n const errorOutput = formatError('Permission denied', {\n suggestions: [\n 'Your API token needs \\'read_build_logs\\' scope to view logs',\n 'Update your token at: https://buildkite.com/user/api-access-tokens',\n ],\n });\n logger.console(errorOutput);\n } else {\n const errorOutput = formatError(error.message, {\n suggestions: ['Check the reference format', 'Verify you have access to this resource'],\n });\n logger.console(errorOutput);\n }\n } else {\n logger.error('Unknown error occurred');\n }\n return 1;\n }\n }\n\n private formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n }\n}\n"]}
@@ -7,4 +7,5 @@ export * from './ManageToken.js';
7
7
  export * from './ListAnnotations.js';
8
8
  export * from './GenerateCompletions.js';
9
9
  export * from './ShowBuild.js';
10
+ export * from './SmartShow.js';
10
11
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"/","sources":["commands/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC","sourcesContent":["export * from './BaseCommand.js';\nexport * from './ShowViewer.js';\nexport * from './ListOrganizations.js';\nexport * from './ListBuilds.js';\nexport * from './ListPipelines.js';\nexport * from './ManageToken.js';\nexport * from './ListAnnotations.js';\nexport * from './GenerateCompletions.js';\nexport * from './ShowBuild.js';"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"/","sources":["commands/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC","sourcesContent":["export * from './BaseCommand.js';\nexport * from './ShowViewer.js';\nexport * from './ListOrganizations.js';\nexport * from './ListBuilds.js';\nexport * from './ListPipelines.js';\nexport * from './ManageToken.js';\nexport * from './ListAnnotations.js';\nexport * from './GenerateCompletions.js';\nexport * from './ShowBuild.js';\nexport * from './SmartShow.js';"]}
@@ -0,0 +1,57 @@
1
+ import { PipelineDetailFormatter } from './Formatter.js';
2
+ export class AlfredPipelineDetailFormatter extends PipelineDetailFormatter {
3
+ name = 'alfred';
4
+ constructor(options) {
5
+ super(options);
6
+ }
7
+ format(data) {
8
+ const items = [];
9
+ const { pipeline, recentBuilds } = data;
10
+ // Pipeline header item
11
+ items.push({
12
+ uid: `pipeline-${pipeline.slug}`,
13
+ title: pipeline.name,
14
+ subtitle: pipeline.description || `Pipeline: ${pipeline.slug}`,
15
+ arg: pipeline.url,
16
+ icon: { path: 'icons/buildkite.png' },
17
+ valid: true,
18
+ });
19
+ // Recent builds as items
20
+ for (const build of recentBuilds) {
21
+ const stateIcon = this.getStateIcon(build.state);
22
+ items.push({
23
+ uid: `build-${pipeline.slug}-${build.number}`,
24
+ title: `#${build.number} - ${build.message}`,
25
+ subtitle: `${build.state} | ${build.branch}`,
26
+ arg: `${pipeline.url}/builds/${build.number}`,
27
+ icon: { path: stateIcon },
28
+ valid: true,
29
+ });
30
+ }
31
+ const output = { items };
32
+ return JSON.stringify(output, null, 2);
33
+ }
34
+ getStateIcon(state) {
35
+ const stateUpper = state.toUpperCase();
36
+ switch (stateUpper) {
37
+ case 'PASSED':
38
+ return 'icons/passed.png';
39
+ case 'FAILED':
40
+ return 'icons/failed.png';
41
+ case 'RUNNING':
42
+ return 'icons/running.png';
43
+ case 'BLOCKED':
44
+ return 'icons/blocked.png';
45
+ case 'CANCELED':
46
+ case 'CANCELLED':
47
+ return 'icons/unknown.png';
48
+ case 'SCHEDULED':
49
+ return 'icons/scheduled.png';
50
+ case 'SKIPPED':
51
+ return 'icons/skipped.png';
52
+ default:
53
+ return 'icons/unknown.png';
54
+ }
55
+ }
56
+ }
57
+ //# sourceMappingURL=AlfredFormatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AlfredFormatter.js","sourceRoot":"/","sources":["formatters/pipeline-detail/AlfredFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAsB,MAAM,gBAAgB,CAAC;AAgB7E,MAAM,OAAO,6BAA8B,SAAQ,uBAAuB;IACxE,IAAI,GAAG,QAAQ,CAAC;IAEhB,YAAY,OAAyB;QACnC,KAAK,CAAC,OAAO,CAAC,CAAC;IACjB,CAAC;IAED,MAAM,CAAC,IAAwB;QAC7B,MAAM,KAAK,GAAiB,EAAE,CAAC;QAC/B,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;QAExC,uBAAuB;QACvB,KAAK,CAAC,IAAI,CAAC;YACT,GAAG,EAAE,YAAY,QAAQ,CAAC,IAAI,EAAE;YAChC,KAAK,EAAE,QAAQ,CAAC,IAAI;YACpB,QAAQ,EAAE,QAAQ,CAAC,WAAW,IAAI,aAAa,QAAQ,CAAC,IAAI,EAAE;YAC9D,GAAG,EAAE,QAAQ,CAAC,GAAG;YACjB,IAAI,EAAE,EAAE,IAAI,EAAE,qBAAqB,EAAE;YACrC,KAAK,EAAE,IAAI;SACZ,CAAC,CAAC;QAEH,yBAAyB;QACzB,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;YACjC,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACjD,KAAK,CAAC,IAAI,CAAC;gBACT,GAAG,EAAE,SAAS,QAAQ,CAAC,IAAI,IAAI,KAAK,CAAC,MAAM,EAAE;gBAC7C,KAAK,EAAE,IAAI,KAAK,CAAC,MAAM,MAAM,KAAK,CAAC,OAAO,EAAE;gBAC5C,QAAQ,EAAE,GAAG,KAAK,CAAC,KAAK,MAAM,KAAK,CAAC,MAAM,EAAE;gBAC5C,GAAG,EAAE,GAAG,QAAQ,CAAC,GAAG,WAAW,KAAK,CAAC,MAAM,EAAE;gBAC7C,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;gBACzB,KAAK,EAAE,IAAI;aACZ,CAAC,CAAC;QACL,CAAC;QAED,MAAM,MAAM,GAAiB,EAAE,KAAK,EAAE,CAAC;QACvC,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACzC,CAAC;IAEO,YAAY,CAAC,KAAa;QAChC,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;QACvC,QAAQ,UAAU,EAAE,CAAC;YACnB,KAAK,QAAQ;gBACX,OAAO,kBAAkB,CAAC;YAC5B,KAAK,QAAQ;gBACX,OAAO,kBAAkB,CAAC;YAC5B,KAAK,SAAS;gBACZ,OAAO,mBAAmB,CAAC;YAC7B,KAAK,SAAS;gBACZ,OAAO,mBAAmB,CAAC;YAC7B,KAAK,UAAU,CAAC;YAChB,KAAK,WAAW;gBACd,OAAO,mBAAmB,CAAC;YAC7B,KAAK,WAAW;gBACd,OAAO,qBAAqB,CAAC;YAC/B,KAAK,SAAS;gBACZ,OAAO,mBAAmB,CAAC;YAC7B;gBACE,OAAO,mBAAmB,CAAC;QAC/B,CAAC;IACH,CAAC;CACF","sourcesContent":["import { PipelineDetailFormatter, PipelineDetailData } from './Formatter.js';\nimport { FormatterOptions } from '../BaseFormatter.js';\n\ninterface AlfredItem {\n uid?: string;\n title: string;\n subtitle?: string;\n arg?: string;\n icon?: { path: string };\n valid?: boolean;\n}\n\ninterface AlfredOutput {\n items: AlfredItem[];\n}\n\nexport class AlfredPipelineDetailFormatter extends PipelineDetailFormatter {\n name = 'alfred';\n\n constructor(options: FormatterOptions) {\n super(options);\n }\n\n format(data: PipelineDetailData): string {\n const items: AlfredItem[] = [];\n const { pipeline, recentBuilds } = data;\n\n // Pipeline header item\n items.push({\n uid: `pipeline-${pipeline.slug}`,\n title: pipeline.name,\n subtitle: pipeline.description || `Pipeline: ${pipeline.slug}`,\n arg: pipeline.url,\n icon: { path: 'icons/buildkite.png' },\n valid: true,\n });\n\n // Recent builds as items\n for (const build of recentBuilds) {\n const stateIcon = this.getStateIcon(build.state);\n items.push({\n uid: `build-${pipeline.slug}-${build.number}`,\n title: `#${build.number} - ${build.message}`,\n subtitle: `${build.state} | ${build.branch}`,\n arg: `${pipeline.url}/builds/${build.number}`,\n icon: { path: stateIcon },\n valid: true,\n });\n }\n\n const output: AlfredOutput = { items };\n return JSON.stringify(output, null, 2);\n }\n\n private getStateIcon(state: string): string {\n const stateUpper = state.toUpperCase();\n switch (stateUpper) {\n case 'PASSED':\n return 'icons/passed.png';\n case 'FAILED':\n return 'icons/failed.png';\n case 'RUNNING':\n return 'icons/running.png';\n case 'BLOCKED':\n return 'icons/blocked.png';\n case 'CANCELED':\n case 'CANCELLED':\n return 'icons/unknown.png';\n case 'SCHEDULED':\n return 'icons/scheduled.png';\n case 'SKIPPED':\n return 'icons/skipped.png';\n default:\n return 'icons/unknown.png';\n }\n }\n}\n"]}
@@ -0,0 +1,7 @@
1
+ export class PipelineDetailFormatter {
2
+ options;
3
+ constructor(options) {
4
+ this.options = options;
5
+ }
6
+ }
7
+ //# sourceMappingURL=Formatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Formatter.js","sourceRoot":"/","sources":["formatters/pipeline-detail/Formatter.ts"],"names":[],"mappings":"AAwBA,MAAM,OAAgB,uBAAuB;IAGrB;IAAtB,YAAsB,OAAyB;QAAzB,YAAO,GAAP,OAAO,CAAkB;IAAG,CAAC;CAGpD","sourcesContent":["import { FormatterOptions } from '../BaseFormatter.js';\n\nexport interface PipelineDetailData {\n org: string;\n pipeline: {\n name: string;\n slug: string;\n description?: string;\n defaultBranch?: string;\n url: string;\n repository?: {\n url: string;\n };\n };\n recentBuilds: Array<{\n number: number;\n state: string;\n branch: string;\n message: string;\n startedAt?: string;\n finishedAt?: string;\n }>;\n}\n\nexport abstract class PipelineDetailFormatter {\n abstract name: string;\n \n constructor(protected options: FormatterOptions) {}\n\n abstract format(data: PipelineDetailData): string;\n}\n"]}
@@ -0,0 +1,11 @@
1
+ import { PipelineDetailFormatter } from './Formatter.js';
2
+ export class JsonPipelineDetailFormatter extends PipelineDetailFormatter {
3
+ name = 'json';
4
+ constructor(options) {
5
+ super(options);
6
+ }
7
+ format(data) {
8
+ return JSON.stringify(data, null, 2);
9
+ }
10
+ }
11
+ //# sourceMappingURL=JsonFormatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JsonFormatter.js","sourceRoot":"/","sources":["formatters/pipeline-detail/JsonFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAsB,MAAM,gBAAgB,CAAC;AAG7E,MAAM,OAAO,2BAA4B,SAAQ,uBAAuB;IACtE,IAAI,GAAG,MAAM,CAAC;IAEd,YAAY,OAAyB;QACnC,KAAK,CAAC,OAAO,CAAC,CAAC;IACjB,CAAC;IAED,MAAM,CAAC,IAAwB;QAC7B,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACvC,CAAC;CACF","sourcesContent":["import { PipelineDetailFormatter, PipelineDetailData } from './Formatter.js';\nimport { FormatterOptions } from '../BaseFormatter.js';\n\nexport class JsonPipelineDetailFormatter extends PipelineDetailFormatter {\n name = 'json';\n\n constructor(options: FormatterOptions) {\n super(options);\n }\n\n format(data: PipelineDetailData): string {\n return JSON.stringify(data, null, 2);\n }\n}\n"]}
@@ -0,0 +1,55 @@
1
+ import { PipelineDetailFormatter } from './Formatter.js';
2
+ import { SEMANTIC_COLORS, formatTips, TipStyle } from '../../ui/theme.js';
3
+ import { renderTable } from '../../ui/table.js';
4
+ import { formatStatus, formatRelativeDate, truncate } from '../../utils/formatUtils.js';
5
+ export class PlainPipelineDetailFormatter extends PipelineDetailFormatter {
6
+ name = 'plain';
7
+ constructor(options) {
8
+ super(options);
9
+ }
10
+ format(data) {
11
+ const { org, pipeline, recentBuilds } = data;
12
+ const lines = [];
13
+ // Pipeline header
14
+ lines.push(SEMANTIC_COLORS.heading(`Pipeline: ${pipeline.name}`));
15
+ if (pipeline.description) {
16
+ lines.push(SEMANTIC_COLORS.dim(`Description: ${pipeline.description}`));
17
+ }
18
+ if (pipeline.defaultBranch) {
19
+ lines.push(SEMANTIC_COLORS.dim(`Default Branch: ${pipeline.defaultBranch}`));
20
+ }
21
+ if (pipeline.repository?.url) {
22
+ lines.push(SEMANTIC_COLORS.dim(`Repository: ${pipeline.repository.url}`));
23
+ }
24
+ lines.push('');
25
+ // Recent builds
26
+ if (recentBuilds && recentBuilds.length > 0) {
27
+ lines.push(SEMANTIC_COLORS.subheading('Recent Builds'));
28
+ lines.push('');
29
+ const tableRows = [
30
+ ['Build', 'Status', 'Branch', 'Message', 'Started'],
31
+ ...recentBuilds.map(build => [
32
+ SEMANTIC_COLORS.label(`#${build.number}`),
33
+ formatStatus(build.state),
34
+ build.branch,
35
+ truncate(build.message, 50),
36
+ build.startedAt ? formatRelativeDate(build.startedAt) : '-',
37
+ ])
38
+ ];
39
+ const table = renderTable(tableRows, { preserveWidths: true });
40
+ lines.push(table);
41
+ // Add tips
42
+ lines.push('');
43
+ const tips = formatTips([
44
+ `View a build: bktide ${org}/${pipeline.slug}/<number>`,
45
+ 'Use --format json for machine-readable output',
46
+ ], TipStyle.GROUPED);
47
+ lines.push(tips);
48
+ }
49
+ else {
50
+ lines.push(SEMANTIC_COLORS.dim('No recent builds found'));
51
+ }
52
+ return lines.join('\n');
53
+ }
54
+ }
55
+ //# sourceMappingURL=PlainFormatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlainFormatter.js","sourceRoot":"/","sources":["formatters/pipeline-detail/PlainFormatter.ts"],"names":[],"mappings":"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","sourcesContent":["import { PipelineDetailFormatter, PipelineDetailData } from './Formatter.js';\nimport { FormatterOptions } from '../BaseFormatter.js';\nimport { SEMANTIC_COLORS, formatTips, TipStyle } from '../../ui/theme.js';\nimport { renderTable } from '../../ui/table.js';\nimport { formatStatus, formatRelativeDate, truncate } from '../../utils/formatUtils.js';\n\nexport class PlainPipelineDetailFormatter extends PipelineDetailFormatter {\n name = 'plain';\n\n constructor(options: FormatterOptions) {\n super(options);\n }\n\n format(data: PipelineDetailData): string {\n const { org, pipeline, recentBuilds } = data;\n const lines: string[] = [];\n\n // Pipeline header\n lines.push(SEMANTIC_COLORS.heading(`Pipeline: ${pipeline.name}`));\n \n if (pipeline.description) {\n lines.push(SEMANTIC_COLORS.dim(`Description: ${pipeline.description}`));\n }\n \n if (pipeline.defaultBranch) {\n lines.push(SEMANTIC_COLORS.dim(`Default Branch: ${pipeline.defaultBranch}`));\n }\n \n if (pipeline.repository?.url) {\n lines.push(SEMANTIC_COLORS.dim(`Repository: ${pipeline.repository.url}`));\n }\n \n lines.push('');\n\n // Recent builds\n if (recentBuilds && recentBuilds.length > 0) {\n lines.push(SEMANTIC_COLORS.subheading('Recent Builds'));\n lines.push('');\n\n const tableRows: string[][] = [\n ['Build', 'Status', 'Branch', 'Message', 'Started'],\n ...recentBuilds.map(build => [\n SEMANTIC_COLORS.label(`#${build.number}`),\n formatStatus(build.state),\n build.branch,\n truncate(build.message, 50),\n build.startedAt ? formatRelativeDate(build.startedAt) : '-',\n ])\n ];\n\n const table = renderTable(tableRows, { preserveWidths: true });\n lines.push(table);\n // Add tips\n lines.push('');\n const tips = formatTips([\n `View a build: bktide ${org}/${pipeline.slug}/<number>`,\n 'Use --format json for machine-readable output',\n ], TipStyle.GROUPED);\n lines.push(tips);\n } else {\n lines.push(SEMANTIC_COLORS.dim('No recent builds found'));\n }\n\n return lines.join('\\n');\n }\n}\n"]}
@@ -0,0 +1,5 @@
1
+ export * from './Formatter.js';
2
+ export * from './PlainFormatter.js';
3
+ export * from './JsonFormatter.js';
4
+ export * from './AlfredFormatter.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"/","sources":["formatters/pipeline-detail/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC","sourcesContent":["export * from './Formatter.js';\nexport * from './PlainFormatter.js';\nexport * from './JsonFormatter.js';\nexport * from './AlfredFormatter.js';\n"]}