bktide 1.0.1755568192 → 1.0.1755655078
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -0
- package/dist/commands/ShowBuild.js +27 -5
- package/dist/commands/ShowBuild.js.map +1 -1
- package/dist/formatters/annotations/PlainTextFormatter.js +79 -20
- package/dist/formatters/annotations/PlainTextFormatter.js.map +1 -1
- package/dist/formatters/build-detail/PlainTextFormatter.js +373 -133
- package/dist/formatters/build-detail/PlainTextFormatter.js.map +1 -1
- package/dist/graphql/fragments/index.js +3 -0
- package/dist/graphql/fragments/index.js.map +1 -0
- package/dist/graphql/fragments/jobs.js +112 -0
- package/dist/graphql/fragments/jobs.js.map +1 -0
- package/dist/graphql/queries.js +35 -57
- package/dist/graphql/queries.js.map +1 -1
- package/dist/scripts/extract-data-patterns.js +118 -0
- package/dist/scripts/extract-data-patterns.js.map +1 -0
- package/dist/services/BuildkiteClient.js +77 -1
- package/dist/services/BuildkiteClient.js.map +1 -1
- package/dist/test-helpers/DataProfiler.js +307 -0
- package/dist/test-helpers/DataProfiler.js.map +1 -0
- package/dist/test-helpers/PatternMockGenerator.js +590 -0
- package/dist/test-helpers/PatternMockGenerator.js.map +1 -0
- package/package.json +19 -3
package/README.md
CHANGED
|
@@ -50,10 +50,25 @@ See [Shell Completions Guide](docs/shell-completions.md) for detailed installati
|
|
|
50
50
|
- [Development Guide](docs/development.md) - Information about running and developing the CLI
|
|
51
51
|
- [Authentication](docs/authentication.md) - How to authenticate with Buildkite
|
|
52
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
|
|
53
56
|
- [Alfred Integration (Overview)](docs/alfred.md) - What the Alfred integration does and quick usage
|
|
54
57
|
- [Alfred Installation](docs/alfred-installation.md) - End-user install, configuration, and troubleshooting
|
|
55
58
|
- [Alfred Development](docs/alfred-development.md) - Packaging, wrapper behavior, metadata, and workflow wiring
|
|
56
59
|
|
|
60
|
+
## Testing
|
|
61
|
+
|
|
62
|
+
Run the test suite with:
|
|
63
|
+
```bash
|
|
64
|
+
npm test # Run all tests
|
|
65
|
+
npm run test:watch # Watch mode for development
|
|
66
|
+
npm run test:coverage # Generate coverage report
|
|
67
|
+
npm run test:extract-patterns # Extract patterns from real data (requires token)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
See [Testing Guide](docs/testing/README.md) for details on the hybrid testing strategy.
|
|
71
|
+
|
|
57
72
|
## Usage
|
|
58
73
|
|
|
59
74
|
### Show Your Login Information
|
|
@@ -141,6 +156,33 @@ bktide annotations https://buildkite.com/gusto/zenpayroll/builds/1287418 --forma
|
|
|
141
156
|
bktide annotations gusto/zenpayroll/1287418 --context build-resources --format json
|
|
142
157
|
```
|
|
143
158
|
|
|
159
|
+
### Show Build Details
|
|
160
|
+
|
|
161
|
+
View detailed information about a specific build including jobs and annotations.
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
# View build by slug format
|
|
165
|
+
bktide build org/pipeline/123
|
|
166
|
+
|
|
167
|
+
# View build by URL format
|
|
168
|
+
bktide build @https://buildkite.com/org/pipeline/builds/123
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Additional options:
|
|
172
|
+
```bash
|
|
173
|
+
# Fetch all jobs (handles pagination for large builds)
|
|
174
|
+
bktide build org/pipeline/123 --jobs
|
|
175
|
+
|
|
176
|
+
# Show failure details and error summaries
|
|
177
|
+
bktide build org/pipeline/123 --failed
|
|
178
|
+
|
|
179
|
+
# Include full annotation content
|
|
180
|
+
bktide build org/pipeline/123 --annotations
|
|
181
|
+
|
|
182
|
+
# Combine options for comprehensive view
|
|
183
|
+
bktide build org/pipeline/123 --jobs --failed --annotations
|
|
184
|
+
```
|
|
185
|
+
|
|
144
186
|
### Generate Shell Completions
|
|
145
187
|
|
|
146
188
|
```bash
|
|
@@ -70,21 +70,43 @@ export class ShowBuild extends BaseCommand {
|
|
|
70
70
|
}
|
|
71
71
|
async fetchBuildData(buildSlug, options) {
|
|
72
72
|
// Determine what data we need to fetch based on options
|
|
73
|
-
const
|
|
73
|
+
const needsAllJobs = options.jobs || options.failed || options.full;
|
|
74
74
|
const needsAnnotations = options.annotations || options.annotationsFull || options.full;
|
|
75
75
|
if (options.debug) {
|
|
76
76
|
logger.debug('Fetching build data', {
|
|
77
77
|
buildSlug,
|
|
78
|
-
|
|
78
|
+
needsAllJobs,
|
|
79
79
|
needsAnnotations,
|
|
80
80
|
full: options.full
|
|
81
81
|
});
|
|
82
82
|
}
|
|
83
|
-
//
|
|
84
|
-
if (
|
|
85
|
-
|
|
83
|
+
// Use the new pagination-aware method when we need all jobs
|
|
84
|
+
if (needsAllJobs) {
|
|
85
|
+
// Show progress when fetching many jobs (only in plain format)
|
|
86
|
+
const progressCallback = options.format === 'plain' || !options.format
|
|
87
|
+
? (fetched, total) => {
|
|
88
|
+
const totalStr = total ? `/${total}` : '';
|
|
89
|
+
process.stderr.write(`\rFetching jobs: ${fetched}${totalStr}...`);
|
|
90
|
+
}
|
|
91
|
+
: undefined;
|
|
92
|
+
const buildData = await this.client.getBuildSummaryWithAllJobs(buildSlug, {
|
|
93
|
+
fetchAllJobs: true,
|
|
94
|
+
onProgress: progressCallback
|
|
95
|
+
});
|
|
96
|
+
// Clear the progress line
|
|
97
|
+
if (progressCallback) {
|
|
98
|
+
process.stderr.write('\r\x1b[K'); // Clear the line
|
|
99
|
+
}
|
|
100
|
+
// If we need full details (like command text), fetch that separately
|
|
101
|
+
if (options.full) {
|
|
102
|
+
// For now, getBuildFull still provides more detailed fields
|
|
103
|
+
// In the future, we could enhance the pagination query to include these
|
|
104
|
+
return await this.client.getBuildFull(buildSlug);
|
|
105
|
+
}
|
|
106
|
+
return buildData;
|
|
86
107
|
}
|
|
87
108
|
else {
|
|
109
|
+
// Just get the summary with first 100 jobs
|
|
88
110
|
return await this.client.getBuildSummary(buildSlug);
|
|
89
111
|
}
|
|
90
112
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ShowBuild.js","sourceRoot":"/","sources":["commands/ShowBuild.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"ShowBuild.js","sourceRoot":"/","sources":["commands/ShowBuild.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseCommand, BaseCommandOptions } from './BaseCommand.js';\nimport { logger } from '../services/logger.js';\nimport { parseBuildRef } from '../utils/parseBuildRef.js';\nimport { FormatterFactory, FormatterType } from '../formatters/index.js';\nimport { Progress } from '../ui/progress.js';\n\nexport interface ShowBuildOptions extends BaseCommandOptions {\n jobs?: boolean;\n failed?: boolean;\n annotations?: boolean;\n annotationsFull?: boolean;\n full?: boolean;\n summary?: boolean;\n allJobs?: boolean;\n buildArg?: string;\n}\n\nexport class ShowBuild extends BaseCommand {\n static requiresToken = true;\n\n async execute(options: ShowBuildOptions): Promise<number> {\n if (options.debug) {\n logger.debug('Starting ShowBuild command execution', options);\n }\n \n if (!options.buildArg) {\n logger.error('Build reference is required');\n return 1;\n }\n \n // Adjust options based on implications\n const adjustedOptions = { ...options };\n if (options.failed) {\n adjustedOptions.jobs = true; // --failed implies --jobs\n }\n if (options.annotationsFull) {\n adjustedOptions.annotations = true; // --annotations-full implies --annotations\n }\n if (options.allJobs) {\n adjustedOptions.jobs = true; // --all-jobs implies --jobs\n }\n if (options.full) {\n // --full shows everything\n adjustedOptions.jobs = true;\n adjustedOptions.annotations = true;\n adjustedOptions.allJobs = true; // --full shows all jobs\n }\n \n // Initialize spinner early\n const format = options.format || 'plain';\n const spinner = Progress.spinner('Fetching build details…', { format });\n \n try {\n // Ensure the command is initialized\n await this.ensureInitialized();\n \n // Parse build reference\n const buildRef = parseBuildRef(options.buildArg);\n if (options.debug) {\n logger.debug('Parsed build reference:', buildRef);\n }\n \n // Construct build slug for GraphQL\n const buildSlug = `${buildRef.org}/${buildRef.pipeline}/${buildRef.number}`;\n \n // Fetch build data based on what's needed\n const buildData = await this.fetchBuildData(buildSlug, adjustedOptions);\n spinner.stop();\n \n // Get the appropriate formatter\n const formatter = FormatterFactory.getFormatter(\n FormatterType.BUILD_DETAIL,\n options.format || 'plain'\n ) as any;\n \n // Format and output the results\n const output = formatter.formatBuildDetail(buildData, adjustedOptions);\n \n logger.console(output);\n \n return 0;\n } catch (error) {\n spinner.stop();\n logger.error('Failed to fetch build:', error);\n \n // Handle the error with the formatter\n const formatter = FormatterFactory.getFormatter(\n FormatterType.BUILD_DETAIL,\n options.format || 'plain'\n ) as any;\n \n const errorOutput = formatter.formatBuildDetail(null, {\n ...adjustedOptions,\n hasError: true,\n errorMessage: error instanceof Error ? error.message : 'Unknown error occurred',\n errorType: 'api',\n });\n \n logger.console(errorOutput);\n return 1;\n }\n }\n \n private async fetchBuildData(buildSlug: string, options: ShowBuildOptions): Promise<any> {\n // Determine what data we need to fetch based on options\n const needsAllJobs = options.jobs || options.failed || options.full;\n const needsAnnotations = options.annotations || options.annotationsFull || options.full;\n \n if (options.debug) {\n logger.debug('Fetching build data', {\n buildSlug,\n needsAllJobs,\n needsAnnotations,\n full: options.full\n });\n }\n \n // Use the new pagination-aware method when we need all jobs\n if (needsAllJobs) {\n // Show progress when fetching many jobs (only in plain format)\n const progressCallback = options.format === 'plain' || !options.format\n ? (fetched: number, total?: number) => {\n const totalStr = total ? `/${total}` : '';\n process.stderr.write(`\\rFetching jobs: ${fetched}${totalStr}...`);\n }\n : undefined;\n \n const buildData = await this.client.getBuildSummaryWithAllJobs(buildSlug, {\n fetchAllJobs: true,\n onProgress: progressCallback\n });\n \n // Clear the progress line\n if (progressCallback) {\n process.stderr.write('\\r\\x1b[K'); // Clear the line\n }\n \n // If we need full details (like command text), fetch that separately\n if (options.full) {\n // For now, getBuildFull still provides more detailed fields\n // In the future, we could enhance the pagination query to include these\n return await this.client.getBuildFull(buildSlug);\n }\n \n return buildData;\n } else {\n // Just get the summary with first 100 jobs\n return await this.client.getBuildSummary(buildSlug);\n }\n }\n}\n"]}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { BaseFormatter } from './Formatter.js';
|
|
2
2
|
import { formatAnnotationBody } from '../../utils/textFormatter.js';
|
|
3
3
|
import { SEMANTIC_COLORS, formatEmptyState, formatError } from '../../ui/theme.js';
|
|
4
|
+
import { useAscii } from '../../ui/symbols.js';
|
|
5
|
+
import { termWidth } from '../../ui/width.js';
|
|
4
6
|
export class PlainTextFormatter extends BaseFormatter {
|
|
5
7
|
name = 'PlainText';
|
|
6
8
|
formatAnnotations(annotations, options) {
|
|
@@ -20,40 +22,97 @@ export class PlainTextFormatter extends BaseFormatter {
|
|
|
20
22
|
]);
|
|
21
23
|
}
|
|
22
24
|
const lines = [];
|
|
23
|
-
|
|
25
|
+
const isAscii = useAscii();
|
|
26
|
+
const terminalWidth = termWidth();
|
|
27
|
+
// Box drawing characters
|
|
28
|
+
const boxChars = isAscii ? {
|
|
29
|
+
horizontal: '-',
|
|
30
|
+
vertical: '|',
|
|
31
|
+
topLeft: '+',
|
|
32
|
+
topRight: '+',
|
|
33
|
+
bottomLeft: '+',
|
|
34
|
+
bottomRight: '+',
|
|
35
|
+
cross: '+',
|
|
36
|
+
verticalRight: '+',
|
|
37
|
+
verticalLeft: '+',
|
|
38
|
+
horizontalDown: '+',
|
|
39
|
+
horizontalUp: '+'
|
|
40
|
+
} : {
|
|
41
|
+
horizontal: '─',
|
|
42
|
+
vertical: '│',
|
|
43
|
+
topLeft: '┌',
|
|
44
|
+
topRight: '┐',
|
|
45
|
+
bottomLeft: '└',
|
|
46
|
+
bottomRight: '┘',
|
|
47
|
+
cross: '┼',
|
|
48
|
+
verticalRight: '├',
|
|
49
|
+
verticalLeft: '┤',
|
|
50
|
+
horizontalDown: '┬',
|
|
51
|
+
horizontalUp: '┴'
|
|
52
|
+
};
|
|
53
|
+
// Style symbols for different annotation types (handle both cases)
|
|
24
54
|
const styleSymbols = {
|
|
25
|
-
error: '✖',
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
55
|
+
error: isAscii ? '[X]' : '✖',
|
|
56
|
+
ERROR: isAscii ? '[X]' : '✖',
|
|
57
|
+
warning: isAscii ? '[!]' : '⚠',
|
|
58
|
+
WARNING: isAscii ? '[!]' : '⚠',
|
|
59
|
+
info: isAscii ? '[i]' : 'ℹ',
|
|
60
|
+
INFO: isAscii ? '[i]' : 'ℹ',
|
|
61
|
+
success: isAscii ? '[✓]' : '✓',
|
|
62
|
+
SUCCESS: isAscii ? '[✓]' : '✓'
|
|
29
63
|
};
|
|
30
|
-
// Style colors for different annotation types
|
|
64
|
+
// Style colors for different annotation types (handle both cases)
|
|
31
65
|
const styleColors = {
|
|
32
66
|
error: SEMANTIC_COLORS.error,
|
|
67
|
+
ERROR: SEMANTIC_COLORS.error,
|
|
33
68
|
warning: SEMANTIC_COLORS.warning,
|
|
69
|
+
WARNING: SEMANTIC_COLORS.warning,
|
|
34
70
|
info: SEMANTIC_COLORS.info,
|
|
35
|
-
|
|
71
|
+
INFO: SEMANTIC_COLORS.info,
|
|
72
|
+
success: SEMANTIC_COLORS.success,
|
|
73
|
+
SUCCESS: SEMANTIC_COLORS.success
|
|
74
|
+
};
|
|
75
|
+
// Create a horizontal divider with padding and centering
|
|
76
|
+
const createDivider = (width = 80) => {
|
|
77
|
+
const padding = 2; // 1 space on each side
|
|
78
|
+
const maxWidth = Math.min(width, terminalWidth - padding);
|
|
79
|
+
const dividerLength = Math.max(20, maxWidth - padding); // Minimum 20 chars
|
|
80
|
+
const divider = boxChars.horizontal.repeat(dividerLength);
|
|
81
|
+
// Center the divider within the terminal width
|
|
82
|
+
const totalPadding = terminalWidth - dividerLength;
|
|
83
|
+
const leftPadding = Math.floor(totalPadding / 2);
|
|
84
|
+
const spaces = ' '.repeat(Math.max(0, leftPadding));
|
|
85
|
+
return SEMANTIC_COLORS.dim(spaces + divider);
|
|
36
86
|
};
|
|
37
87
|
annotations.forEach((annotation, index) => {
|
|
88
|
+
const symbol = styleSymbols[annotation.style] || (isAscii ? '*' : '•');
|
|
89
|
+
const colorFn = styleColors[annotation.style] || ((s) => s);
|
|
90
|
+
// Add divider between annotations (but not before the first one)
|
|
38
91
|
if (index > 0) {
|
|
39
|
-
lines.push('');
|
|
92
|
+
lines.push('');
|
|
93
|
+
lines.push(createDivider());
|
|
94
|
+
lines.push('');
|
|
40
95
|
}
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
lines.push(
|
|
45
|
-
|
|
96
|
+
// Single line header with pipe: "│ ℹ info: test-mapping-build"
|
|
97
|
+
const pipe = colorFn(boxChars.vertical);
|
|
98
|
+
const header = `${pipe} ${symbol} ${annotation.style.toLowerCase()}: ${annotation.context}`;
|
|
99
|
+
lines.push(header);
|
|
100
|
+
// Add blank line with pipe for visual continuity
|
|
101
|
+
lines.push(pipe);
|
|
46
102
|
// Format the body HTML with proper HTML/markdown handling
|
|
47
103
|
const formattedBody = formatAnnotationBody(annotation.body.html);
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
104
|
+
// Add vertical pipes to the left of the body content for visual continuity
|
|
105
|
+
// Use the same color as the header for the pipes
|
|
106
|
+
const bodyLines = formattedBody.split('\n');
|
|
107
|
+
bodyLines.forEach((line) => {
|
|
108
|
+
const paddedLine = line ? ` ${line}` : '';
|
|
109
|
+
lines.push(`${pipe}${paddedLine}`);
|
|
110
|
+
});
|
|
54
111
|
});
|
|
55
|
-
// Add summary
|
|
112
|
+
// Add summary footer
|
|
56
113
|
if (annotations.length > 1) {
|
|
114
|
+
lines.push('');
|
|
115
|
+
lines.push(createDivider());
|
|
57
116
|
lines.push('');
|
|
58
117
|
lines.push(SEMANTIC_COLORS.dim(`${SEMANTIC_COLORS.count(annotations.length.toString())} annotations found`));
|
|
59
118
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlainTextFormatter.js","sourceRoot":"/","sources":["formatters/annotations/PlainTextFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA8B,MAAM,gBAAgB,CAAC;AAE3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"PlainTextFormatter.js","sourceRoot":"/","sources":["formatters/annotations/PlainTextFormatter.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseFormatter, AnnotationFormatterOptions } from './Formatter.js';\nimport { Annotation } from '../../types/index.js';\nimport { formatAnnotationBody } from '../../utils/textFormatter.js';\nimport { SEMANTIC_COLORS, formatEmptyState, formatError } from '../../ui/theme.js';\nimport { useAscii } from '../../ui/symbols.js';\nimport { termWidth } from '../../ui/width.js';\n\nexport class PlainTextFormatter extends BaseFormatter {\n name = 'PlainText';\n\n formatAnnotations(annotations: Annotation[], options?: AnnotationFormatterOptions): string {\n if (options?.hasError) {\n return formatError(options.errorMessage || 'Failed to fetch annotations', {\n showHelp: true,\n helpCommand: 'bktide annotations --help'\n });\n }\n\n if (!annotations || annotations.length === 0) {\n const message = options?.contextFilter\n ? `No annotations found for this build with context '${options.contextFilter}'`\n : 'No annotations found for this build';\n \n return formatEmptyState(message, [\n 'Annotations are created by build steps',\n 'Check the build has completed and has annotation steps'\n ]);\n }\n\n const lines: string[] = [];\n const isAscii = useAscii();\n const terminalWidth = termWidth();\n \n // Box drawing characters\n const boxChars = isAscii ? {\n horizontal: '-',\n vertical: '|',\n topLeft: '+',\n topRight: '+',\n bottomLeft: '+',\n bottomRight: '+',\n cross: '+',\n verticalRight: '+',\n verticalLeft: '+',\n horizontalDown: '+',\n horizontalUp: '+'\n } : {\n horizontal: '─',\n vertical: '│',\n topLeft: '┌',\n topRight: '┐',\n bottomLeft: '└',\n bottomRight: '┘',\n cross: '┼',\n verticalRight: '├',\n verticalLeft: '┤',\n horizontalDown: '┬',\n horizontalUp: '┴'\n };\n \n // Style symbols for different annotation types (handle both cases)\n const styleSymbols: Record<string, string> = {\n error: isAscii ? '[X]' : '✖',\n ERROR: isAscii ? '[X]' : '✖',\n warning: isAscii ? '[!]' : '⚠',\n WARNING: isAscii ? '[!]' : '⚠',\n info: isAscii ? '[i]' : 'ℹ',\n INFO: isAscii ? '[i]' : 'ℹ',\n success: isAscii ? '[✓]' : '✓',\n SUCCESS: isAscii ? '[✓]' : '✓'\n };\n \n // Style colors for different annotation types (handle both cases)\n const styleColors: Record<string, (s: string) => string> = {\n error: SEMANTIC_COLORS.error,\n ERROR: SEMANTIC_COLORS.error,\n warning: SEMANTIC_COLORS.warning,\n WARNING: SEMANTIC_COLORS.warning,\n info: SEMANTIC_COLORS.info,\n INFO: SEMANTIC_COLORS.info,\n success: SEMANTIC_COLORS.success,\n SUCCESS: SEMANTIC_COLORS.success\n };\n \n // Create a horizontal divider with padding and centering\n const createDivider = (width: number = 80) => {\n const padding = 2; // 1 space on each side\n const maxWidth = Math.min(width, terminalWidth - padding);\n const dividerLength = Math.max(20, maxWidth - padding); // Minimum 20 chars\n const divider = boxChars.horizontal.repeat(dividerLength);\n \n // Center the divider within the terminal width\n const totalPadding = terminalWidth - dividerLength;\n const leftPadding = Math.floor(totalPadding / 2);\n const spaces = ' '.repeat(Math.max(0, leftPadding));\n \n return SEMANTIC_COLORS.dim(spaces + divider);\n };\n \n annotations.forEach((annotation, index) => {\n const symbol = styleSymbols[annotation.style] || (isAscii ? '*' : '•');\n const colorFn = styleColors[annotation.style] || ((s: string) => s);\n \n // Add divider between annotations (but not before the first one)\n if (index > 0) {\n lines.push('');\n lines.push(createDivider());\n lines.push('');\n }\n \n // Single line header with pipe: \"│ ℹ info: test-mapping-build\"\n const pipe = colorFn(boxChars.vertical);\n const header = `${pipe} ${symbol} ${annotation.style.toLowerCase()}: ${annotation.context}`;\n lines.push(header);\n \n // Add blank line with pipe for visual continuity\n lines.push(pipe);\n \n // Format the body HTML with proper HTML/markdown handling\n const formattedBody = formatAnnotationBody(annotation.body.html);\n \n // Add vertical pipes to the left of the body content for visual continuity\n // Use the same color as the header for the pipes\n const bodyLines = formattedBody.split('\\n');\n bodyLines.forEach((line) => {\n const paddedLine = line ? ` ${line}` : '';\n lines.push(`${pipe}${paddedLine}`);\n });\n });\n \n // Add summary footer\n if (annotations.length > 1) {\n lines.push('');\n lines.push(createDivider());\n lines.push('');\n lines.push(SEMANTIC_COLORS.dim(`${SEMANTIC_COLORS.count(annotations.length.toString())} annotations found`));\n }\n\n return lines.join('\\n');\n }\n}\n"]}
|