bktide 1.0.1755559112 → 1.0.1755568192

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.
@@ -2,6 +2,7 @@ import fetch from 'node-fetch';
2
2
  import { CacheManager } from './CacheManager.js';
3
3
  import { createHash } from 'crypto';
4
4
  import { logger } from './logger.js';
5
+ import { getProgressIcon } from '../ui/theme.js';
5
6
  /**
6
7
  * BuildkiteRestClient provides methods to interact with the Buildkite REST API
7
8
  */
@@ -84,17 +85,17 @@ export class BuildkiteRestClient {
84
85
  const cached = await this.cacheManager.get(cacheKey, cacheType);
85
86
  if (cached) {
86
87
  if (this.debug) {
87
- logger.debug(`✅ Served from cache: REST ${endpoint}`);
88
+ logger.debug(`${getProgressIcon('SUCCESS_LOG')} Served from cache: REST ${endpoint}`);
88
89
  }
89
90
  return cached;
90
91
  }
91
92
  }
92
93
  const startTime = process.hrtime.bigint();
93
94
  if (this.debug) {
94
- logger.debug(`🕒 Starting REST API request: GET ${endpoint}`);
95
- logger.debug(`🕒 Request URL: ${url.toString()}`);
95
+ logger.debug(`${getProgressIcon('STARTING')} Starting REST API request: GET ${endpoint}`);
96
+ logger.debug(`${getProgressIcon('STARTING')} Request URL: ${url.toString()}`);
96
97
  if (params) {
97
- logger.debug(`🕒 Request params: ${JSON.stringify(params)}`);
98
+ logger.debug(`${getProgressIcon('STARTING')} Request params: ${JSON.stringify(params)}`);
98
99
  }
99
100
  }
100
101
  try {
@@ -144,7 +145,7 @@ export class BuildkiteRestClient {
144
145
  const endTime = process.hrtime.bigint();
145
146
  const duration = Number(endTime - startTime) / 1000000; // Convert to milliseconds
146
147
  if (this.debug) {
147
- logger.debug(`✅ REST API request completed: GET ${endpoint} (${duration.toFixed(2)}ms)`);
148
+ logger.debug(`${getProgressIcon('SUCCESS_LOG')} REST API request completed: GET ${endpoint} (${duration.toFixed(2)}ms)`);
148
149
  }
149
150
  return data;
150
151
  }
@@ -187,13 +188,13 @@ export class BuildkiteRestClient {
187
188
  const endpoint = `/organizations/${org}/builds`;
188
189
  const startTime = process.hrtime.bigint();
189
190
  if (this.debug) {
190
- logger.debug(`🕒 Fetching builds for organization: ${org}`);
191
+ logger.debug(`${getProgressIcon('STARTING')} Fetching builds for organization: ${org}`);
191
192
  }
192
193
  const builds = await this.get(endpoint, params);
193
194
  const endTime = process.hrtime.bigint();
194
195
  const duration = Number(endTime - startTime) / 1000000; // Convert to milliseconds
195
196
  if (this.debug) {
196
- logger.debug(`✅ Retrieved ${builds.length} builds for ${org} (${duration.toFixed(2)}ms)`);
197
+ logger.debug(`${getProgressIcon('SUCCESS_LOG')} Retrieved ${builds.length} builds for ${org} (${duration.toFixed(2)}ms)`);
197
198
  }
198
199
  return builds;
199
200
  }
@@ -1 +1 @@
1
- {"version":3,"file":"BuildkiteRestClient.js","sourceRoot":"/","sources":["services/BuildkiteRestClient.ts"],"names":[],"mappings":"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","sourcesContent":["import fetch from 'node-fetch';\nimport { CacheManager } from './CacheManager.js';\nimport { createHash } from 'crypto';\nimport { logger } from './logger.js';\n\nexport interface BuildkiteRestClientOptions {\n baseUrl?: string;\n caching?: boolean;\n cacheTTLs?: Partial<{\n builds: number;\n default: number;\n }>;\n debug?: boolean;\n}\n\nexport interface RateLimitInfo {\n remaining: number;\n limit: number;\n reset: number;\n}\n\n/**\n * BuildkiteRestClient provides methods to interact with the Buildkite REST API\n */\nexport class BuildkiteRestClient {\n private token: string;\n private baseUrl: string = 'https://api.buildkite.com/v2';\n private cacheManager: CacheManager | null = null;\n private debug: boolean = false;\n private rateLimitInfo: RateLimitInfo | null = null;\n\n /**\n * Create a new BuildkiteRestClient\n * @param token Your Buildkite API token\n * @param options Configuration options\n */\n constructor(token: string, options?: BuildkiteRestClientOptions) {\n this.token = token;\n this.debug = options?.debug || false;\n \n if (options?.baseUrl) {\n this.baseUrl = options.baseUrl;\n }\n \n // Initialize cache if caching is enabled\n if (options?.caching !== false) {\n this.cacheManager = new CacheManager(options?.cacheTTLs, this.debug);\n // Initialize cache and set token hash (async, but we don't wait)\n this.initCache();\n }\n }\n \n /**\n * Initialize cache asynchronously\n */\n private async initCache(): Promise<void> {\n if (this.cacheManager) {\n await this.cacheManager.init();\n await this.cacheManager.setTokenHash(this.token);\n }\n }\n \n /**\n * Generate a cache key for a REST endpoint\n */\n private generateCacheKey(endpoint: string, params?: Record<string, string>): string {\n const paramsString = params ? JSON.stringify(params) : '';\n return `REST:${endpoint}:${this.hashString(paramsString)}`;\n }\n \n /**\n * Hash a string using SHA256\n */\n private hashString(str: string): string {\n return createHash('sha256').update(str).digest('hex');\n }\n\n /**\n * Get cache type from endpoint\n */\n private getCacheTypeFromEndpoint(endpoint: string): string {\n if (endpoint.includes('/builds')) {\n return 'builds';\n }\n return 'default';\n }\n\n /**\n * Make a GET request to the Buildkite REST API\n * @param endpoint The API endpoint\n * @param params Query parameters\n * @returns The API response\n */\n private async get<T = any>(endpoint: string, params?: Record<string, string>): Promise<T> {\n const url = new URL(`${this.baseUrl}${endpoint}`);\n \n // Add query parameters\n if (params) {\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n url.searchParams.append(key, value);\n }\n });\n }\n \n // Generate cache key\n const cacheKey = this.generateCacheKey(endpoint, params);\n const cacheType = this.getCacheTypeFromEndpoint(endpoint);\n \n // Check cache first if enabled\n if (this.cacheManager) {\n const cached = await this.cacheManager.get(cacheKey, cacheType as any);\n if (cached) {\n if (this.debug) {\n logger.debug(`✅ Served from cache: REST ${endpoint}`);\n }\n return cached as T;\n }\n }\n\n const startTime = process.hrtime.bigint();\n if (this.debug) {\n logger.debug(`🕒 Starting REST API request: GET ${endpoint}`);\n logger.debug(`🕒 Request URL: ${url.toString()}`);\n if (params) {\n logger.debug(`🕒 Request params: ${JSON.stringify(params)}`);\n }\n }\n \n try {\n const response = await fetch(url.toString(), {\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n });\n\n // Update rate limit info from headers\n this.rateLimitInfo = {\n remaining: parseInt(response.headers.get('RateLimit-Remaining') || '0'),\n limit: parseInt(response.headers.get('RateLimit-Limit') || '0'),\n reset: parseInt(response.headers.get('RateLimit-Reset') || '0'),\n };\n\n if (this.debug) {\n logger.debug('Rate limit info:', this.rateLimitInfo);\n }\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage = `API request failed with status ${response.status}: ${errorText}`;\n \n // Try to parse the error as JSON for more details\n try {\n const errorJson = JSON.parse(errorText);\n if (errorJson.message) {\n errorMessage = `API request failed: ${errorJson.message}`;\n }\n if (errorJson.errors && Array.isArray(errorJson.errors)) {\n errorMessage += `\\nErrors: ${errorJson.errors.map((e: any) => e.message).join(', ')}`;\n }\n } catch (e) {\n // If parsing fails, use the original error text\n }\n \n // Check if this is an authentication error\n const isAuthError = this.isAuthenticationError(response.status, errorMessage);\n if (isAuthError && this.debug) {\n logger.debug('Authentication error detected, not caching result');\n }\n \n throw new Error(errorMessage);\n }\n \n const data = await response.json() as T;\n \n // Cache the response if caching is enabled\n if (this.cacheManager) {\n await this.cacheManager.set(cacheKey, data, cacheType as any);\n }\n \n const endTime = process.hrtime.bigint();\n const duration = Number(endTime - startTime) / 1000000; // Convert to milliseconds\n if (this.debug) {\n logger.debug(`✅ REST API request completed: GET ${endpoint} (${duration.toFixed(2)}ms)`);\n }\n \n return data;\n } catch (error: unknown) {\n if (this.debug) {\n logger.error('Error in get request:', error);\n }\n throw error;\n }\n }\n\n /**\n * Check if an error is an authentication error\n */\n private isAuthenticationError(status: number, message: string): boolean {\n // Check for HTTP status codes that indicate auth issues\n if (status === 401 || status === 403) {\n return true;\n }\n \n // Check error message for auth-related keywords\n const lowerMessage = message.toLowerCase();\n return lowerMessage.includes('unauthorized') || \n lowerMessage.includes('authentication') || \n lowerMessage.includes('permission') ||\n lowerMessage.includes('invalid token');\n }\n\n /**\n * Get the current rate limit information\n * @returns Current rate limit information or null if not available\n */\n public getRateLimitInfo(): RateLimitInfo | null {\n return this.rateLimitInfo;\n }\n\n /**\n * Get builds from an organization filtered by specific parameters\n * @param org Organization slug\n * @param params Query parameters\n * @returns List of builds\n */\n public async getBuilds(org: string, params?: {\n creator?: string; // Creator's user ID, email or API access token\n pipeline?: string;\n branch?: string;\n commit?: string;\n state?: string;\n per_page?: string;\n page?: string;\n }): Promise<any[]> {\n const endpoint = `/organizations/${org}/builds`;\n const startTime = process.hrtime.bigint();\n if (this.debug) {\n logger.debug(`🕒 Fetching builds for organization: ${org}`);\n }\n \n const builds = await this.get<any[]>(endpoint, params as Record<string, string>);\n \n const endTime = process.hrtime.bigint();\n const duration = Number(endTime - startTime) / 1000000; // Convert to milliseconds\n if (this.debug) {\n logger.debug(`✅ Retrieved ${builds.length} builds for ${org} (${duration.toFixed(2)}ms)`);\n }\n \n return builds;\n }\n\n\n\n public async hasBuildAccess(org: string): Promise<boolean> {\n try {\n await this.getBuilds(org, { per_page: '1' });\n return true;\n } catch (error) {\n return false;\n }\n }\n \n /**\n * Check if the current user has access to an organization\n * @param org Organization slug\n * @returns True if the user has access, false otherwise\n */\n public async hasOrganizationAccess(org: string): Promise<boolean> {\n try {\n const endpoint = `/organizations/${org}`;\n await this.get(endpoint);\n return true;\n } catch (error) {\n if (this.debug) {\n logger.debug(`User does not have access to organization: ${org}`);\n }\n return false;\n }\n }\n \n /**\n * Clear all cache entries\n */\n public async clearCache(): Promise<void> {\n if (this.cacheManager) {\n await this.cacheManager.clear();\n }\n }\n\n /**\n * Invalidate a specific cache type\n */\n public async invalidateCache(type: string): Promise<void> {\n if (this.cacheManager) {\n await this.cacheManager.invalidateType(type);\n }\n }\n} "]}
1
+ {"version":3,"file":"BuildkiteRestClient.js","sourceRoot":"/","sources":["services/BuildkiteRestClient.ts"],"names":[],"mappings":"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","sourcesContent":["import fetch from 'node-fetch';\nimport { CacheManager } from './CacheManager.js';\nimport { createHash } from 'crypto';\nimport { logger } from './logger.js';\nimport { getProgressIcon } from '../ui/theme.js';\n\nexport interface BuildkiteRestClientOptions {\n baseUrl?: string;\n caching?: boolean;\n cacheTTLs?: Partial<{\n builds: number;\n default: number;\n }>;\n debug?: boolean;\n}\n\nexport interface RateLimitInfo {\n remaining: number;\n limit: number;\n reset: number;\n}\n\n/**\n * BuildkiteRestClient provides methods to interact with the Buildkite REST API\n */\nexport class BuildkiteRestClient {\n private token: string;\n private baseUrl: string = 'https://api.buildkite.com/v2';\n private cacheManager: CacheManager | null = null;\n private debug: boolean = false;\n private rateLimitInfo: RateLimitInfo | null = null;\n\n /**\n * Create a new BuildkiteRestClient\n * @param token Your Buildkite API token\n * @param options Configuration options\n */\n constructor(token: string, options?: BuildkiteRestClientOptions) {\n this.token = token;\n this.debug = options?.debug || false;\n \n if (options?.baseUrl) {\n this.baseUrl = options.baseUrl;\n }\n \n // Initialize cache if caching is enabled\n if (options?.caching !== false) {\n this.cacheManager = new CacheManager(options?.cacheTTLs, this.debug);\n // Initialize cache and set token hash (async, but we don't wait)\n this.initCache();\n }\n }\n \n /**\n * Initialize cache asynchronously\n */\n private async initCache(): Promise<void> {\n if (this.cacheManager) {\n await this.cacheManager.init();\n await this.cacheManager.setTokenHash(this.token);\n }\n }\n \n /**\n * Generate a cache key for a REST endpoint\n */\n private generateCacheKey(endpoint: string, params?: Record<string, string>): string {\n const paramsString = params ? JSON.stringify(params) : '';\n return `REST:${endpoint}:${this.hashString(paramsString)}`;\n }\n \n /**\n * Hash a string using SHA256\n */\n private hashString(str: string): string {\n return createHash('sha256').update(str).digest('hex');\n }\n\n /**\n * Get cache type from endpoint\n */\n private getCacheTypeFromEndpoint(endpoint: string): string {\n if (endpoint.includes('/builds')) {\n return 'builds';\n }\n return 'default';\n }\n\n /**\n * Make a GET request to the Buildkite REST API\n * @param endpoint The API endpoint\n * @param params Query parameters\n * @returns The API response\n */\n private async get<T = any>(endpoint: string, params?: Record<string, string>): Promise<T> {\n const url = new URL(`${this.baseUrl}${endpoint}`);\n \n // Add query parameters\n if (params) {\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n url.searchParams.append(key, value);\n }\n });\n }\n \n // Generate cache key\n const cacheKey = this.generateCacheKey(endpoint, params);\n const cacheType = this.getCacheTypeFromEndpoint(endpoint);\n \n // Check cache first if enabled\n if (this.cacheManager) {\n const cached = await this.cacheManager.get(cacheKey, cacheType as any);\n if (cached) {\n if (this.debug) {\n logger.debug(`${getProgressIcon('SUCCESS_LOG')} Served from cache: REST ${endpoint}`);\n }\n return cached as T;\n }\n }\n\n const startTime = process.hrtime.bigint();\n if (this.debug) {\n logger.debug(`${getProgressIcon('STARTING')} Starting REST API request: GET ${endpoint}`);\n logger.debug(`${getProgressIcon('STARTING')} Request URL: ${url.toString()}`);\n if (params) {\n logger.debug(`${getProgressIcon('STARTING')} Request params: ${JSON.stringify(params)}`);\n }\n }\n \n try {\n const response = await fetch(url.toString(), {\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n });\n\n // Update rate limit info from headers\n this.rateLimitInfo = {\n remaining: parseInt(response.headers.get('RateLimit-Remaining') || '0'),\n limit: parseInt(response.headers.get('RateLimit-Limit') || '0'),\n reset: parseInt(response.headers.get('RateLimit-Reset') || '0'),\n };\n\n if (this.debug) {\n logger.debug('Rate limit info:', this.rateLimitInfo);\n }\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage = `API request failed with status ${response.status}: ${errorText}`;\n \n // Try to parse the error as JSON for more details\n try {\n const errorJson = JSON.parse(errorText);\n if (errorJson.message) {\n errorMessage = `API request failed: ${errorJson.message}`;\n }\n if (errorJson.errors && Array.isArray(errorJson.errors)) {\n errorMessage += `\\nErrors: ${errorJson.errors.map((e: any) => e.message).join(', ')}`;\n }\n } catch (e) {\n // If parsing fails, use the original error text\n }\n \n // Check if this is an authentication error\n const isAuthError = this.isAuthenticationError(response.status, errorMessage);\n if (isAuthError && this.debug) {\n logger.debug('Authentication error detected, not caching result');\n }\n \n throw new Error(errorMessage);\n }\n \n const data = await response.json() as T;\n \n // Cache the response if caching is enabled\n if (this.cacheManager) {\n await this.cacheManager.set(cacheKey, data, cacheType as any);\n }\n \n const endTime = process.hrtime.bigint();\n const duration = Number(endTime - startTime) / 1000000; // Convert to milliseconds\n if (this.debug) {\n logger.debug(`${getProgressIcon('SUCCESS_LOG')} REST API request completed: GET ${endpoint} (${duration.toFixed(2)}ms)`);\n }\n \n return data;\n } catch (error: unknown) {\n if (this.debug) {\n logger.error('Error in get request:', error);\n }\n throw error;\n }\n }\n\n /**\n * Check if an error is an authentication error\n */\n private isAuthenticationError(status: number, message: string): boolean {\n // Check for HTTP status codes that indicate auth issues\n if (status === 401 || status === 403) {\n return true;\n }\n \n // Check error message for auth-related keywords\n const lowerMessage = message.toLowerCase();\n return lowerMessage.includes('unauthorized') || \n lowerMessage.includes('authentication') || \n lowerMessage.includes('permission') ||\n lowerMessage.includes('invalid token');\n }\n\n /**\n * Get the current rate limit information\n * @returns Current rate limit information or null if not available\n */\n public getRateLimitInfo(): RateLimitInfo | null {\n return this.rateLimitInfo;\n }\n\n /**\n * Get builds from an organization filtered by specific parameters\n * @param org Organization slug\n * @param params Query parameters\n * @returns List of builds\n */\n public async getBuilds(org: string, params?: {\n creator?: string; // Creator's user ID, email or API access token\n pipeline?: string;\n branch?: string;\n commit?: string;\n state?: string;\n per_page?: string;\n page?: string;\n }): Promise<any[]> {\n const endpoint = `/organizations/${org}/builds`;\n const startTime = process.hrtime.bigint();\n if (this.debug) {\n logger.debug(`${getProgressIcon('STARTING')} Fetching builds for organization: ${org}`);\n }\n \n const builds = await this.get<any[]>(endpoint, params as Record<string, string>);\n \n const endTime = process.hrtime.bigint();\n const duration = Number(endTime - startTime) / 1000000; // Convert to milliseconds\n if (this.debug) {\n logger.debug(`${getProgressIcon('SUCCESS_LOG')} Retrieved ${builds.length} builds for ${org} (${duration.toFixed(2)}ms)`);\n }\n \n return builds;\n }\n\n\n\n public async hasBuildAccess(org: string): Promise<boolean> {\n try {\n await this.getBuilds(org, { per_page: '1' });\n return true;\n } catch (error) {\n return false;\n }\n }\n \n /**\n * Check if the current user has access to an organization\n * @param org Organization slug\n * @returns True if the user has access, false otherwise\n */\n public async hasOrganizationAccess(org: string): Promise<boolean> {\n try {\n const endpoint = `/organizations/${org}`;\n await this.get(endpoint);\n return true;\n } catch (error) {\n if (this.debug) {\n logger.debug(`User does not have access to organization: ${org}`);\n }\n return false;\n }\n }\n \n /**\n * Clear all cache entries\n */\n public async clearCache(): Promise<void> {\n if (this.cacheManager) {\n await this.cacheManager.clear();\n }\n }\n\n /**\n * Invalidate a specific cache type\n */\n public async invalidateCache(type: string): Promise<void> {\n if (this.cacheManager) {\n await this.cacheManager.invalidateType(type);\n }\n }\n} "]}
package/dist/ui/theme.js CHANGED
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import chalk from 'chalk';
8
8
  import { getSymbols } from './symbols.js';
9
+ import { terminalLink } from '../utils/terminal-links.js';
9
10
  function isTTY() {
10
11
  return Boolean(process.stdout.isTTY);
11
12
  }
@@ -36,7 +37,7 @@ export const SEMANTIC_COLORS = {
36
37
  // Data type highlighting
37
38
  identifier: (s) => colorEnabled() ? chalk.cyan(s) : s,
38
39
  count: (s) => colorEnabled() ? chalk.magenta(s) : s,
39
- url: (s) => colorEnabled() ? chalk.underline.cyan(s) : `<${s}>`,
40
+ url: (s, label) => terminalLink(s, label),
40
41
  // De-emphasis (auxiliary information)
41
42
  dim: (s) => colorEnabled() ? chalk.dim(s) : s,
42
43
  muted: (s) => colorEnabled() ? chalk.gray(s) : s,
@@ -141,22 +142,28 @@ export var TipStyle;
141
142
  /**
142
143
  * Format tips with consistent styling based on context
143
144
  */
144
- export function formatTips(tips, style = TipStyle.GROUPED) {
145
+ export function formatTips(tips, style = TipStyle.GROUPED, includeTurnOff = true) {
145
146
  if (tips.length === 0)
146
147
  return '';
148
+ // Add the turn-off tip if not already included
149
+ const allTips = [...tips];
150
+ const turnOffMessage = 'Use --no-tips to hide these hints';
151
+ if (includeTurnOff && !tips.some(tip => tip.includes('--no-tips'))) {
152
+ allTips.push(turnOffMessage);
153
+ }
147
154
  switch (style) {
148
155
  case TipStyle.GROUPED:
149
- return formatGroupedTips(tips);
156
+ return formatGroupedTips(allTips);
150
157
  case TipStyle.INDIVIDUAL:
151
- return formatIndividualTips(tips);
158
+ return formatIndividualTips(allTips);
152
159
  case TipStyle.ACTIONS:
153
- return formatActionTips(tips);
160
+ return formatActionTips(allTips);
154
161
  case TipStyle.FIXES:
155
- return formatFixTips(tips);
162
+ return formatFixTips(allTips);
156
163
  case TipStyle.BOX:
157
- return formatTipBox(tips); // Use existing function
164
+ return formatTipBox(allTips); // Use existing function
158
165
  default:
159
- return formatGroupedTips(tips);
166
+ return formatGroupedTips(allTips);
160
167
  }
161
168
  }
162
169
  function formatGroupedTips(tips) {
@@ -277,4 +284,182 @@ export function shouldDecorate(format) {
277
284
  const f = (format || '').toLowerCase();
278
285
  return f !== 'json' && f !== 'alfred' && colorEnabled();
279
286
  }
287
+ /**
288
+ * Icon Display Modes
289
+ */
290
+ export var IconMode;
291
+ (function (IconMode) {
292
+ IconMode["EMOJI"] = "emoji";
293
+ IconMode["UTF8"] = "utf8";
294
+ IconMode["ASCII"] = "ascii"; // ASCII-only fallback
295
+ })(IconMode || (IconMode = {}));
296
+ /**
297
+ * Build and Job State Icons
298
+ * Each has emoji, UTF-8, and ASCII alternatives
299
+ */
300
+ export const STATE_ICONS = {
301
+ PASSED: {
302
+ emoji: '✅',
303
+ utf8: '✓', // U+2713 Check mark
304
+ ascii: '[OK]'
305
+ },
306
+ FAILED: {
307
+ emoji: '❌',
308
+ utf8: '✗', // U+2717 Ballot X
309
+ ascii: '[FAIL]'
310
+ },
311
+ RUNNING: {
312
+ emoji: '🔄',
313
+ utf8: '↻', // U+21BB Clockwise arrow
314
+ ascii: '[RUN]'
315
+ },
316
+ BLOCKED: {
317
+ emoji: '⏸️',
318
+ utf8: '‖', // U+2016 Double vertical line
319
+ ascii: '[BLOCK]'
320
+ },
321
+ CANCELED: {
322
+ emoji: '🚫',
323
+ utf8: '⊘', // U+2298 Circled division slash
324
+ ascii: '[CANCEL]'
325
+ },
326
+ SCHEDULED: {
327
+ emoji: '📅',
328
+ utf8: '⏰', // U+23F0 Alarm clock
329
+ ascii: '[SCHED]'
330
+ },
331
+ SKIPPED: {
332
+ emoji: '⏭️',
333
+ utf8: '»', // U+00BB Right-pointing double angle
334
+ ascii: '[SKIP]'
335
+ },
336
+ UNKNOWN: {
337
+ emoji: '❓',
338
+ utf8: '?', // Regular question mark
339
+ ascii: '[?]'
340
+ }
341
+ };
342
+ /**
343
+ * Annotation Style Icons
344
+ */
345
+ export const ANNOTATION_ICONS = {
346
+ ERROR: {
347
+ emoji: '❌',
348
+ utf8: '✗', // U+2717 Ballot X
349
+ ascii: '[ERR]'
350
+ },
351
+ WARNING: {
352
+ emoji: '⚠️',
353
+ utf8: '⚠', // U+26A0 Warning sign (without emoji variant)
354
+ ascii: '[WARN]'
355
+ },
356
+ INFO: {
357
+ emoji: 'ℹ️',
358
+ utf8: 'ℹ', // U+2139 Information source (no circle)
359
+ ascii: '[INFO]'
360
+ },
361
+ SUCCESS: {
362
+ emoji: '✅',
363
+ utf8: '✓', // U+2713 Check mark
364
+ ascii: '[OK]'
365
+ },
366
+ DEFAULT: {
367
+ emoji: '📝',
368
+ utf8: '◆', // U+25C6 Black diamond
369
+ ascii: '[NOTE]'
370
+ }
371
+ };
372
+ /**
373
+ * Progress and Debug Icons
374
+ */
375
+ export const PROGRESS_ICONS = {
376
+ TIMING: {
377
+ emoji: '⏱️',
378
+ utf8: '⧗', // U+29D7 Black hourglass
379
+ ascii: '[TIME]'
380
+ },
381
+ STARTING: {
382
+ emoji: '🕒',
383
+ utf8: '◷', // U+25F7 White circle with upper right quadrant
384
+ ascii: '[>>>]'
385
+ },
386
+ RETRY: {
387
+ emoji: '🔄',
388
+ utf8: '↻', // U+21BB Clockwise arrow
389
+ ascii: '[RETRY]'
390
+ },
391
+ SUCCESS_LOG: {
392
+ emoji: '✅',
393
+ utf8: '✓', // U+2713 Check mark
394
+ ascii: '[✓]'
395
+ },
396
+ BLOCKED_MESSAGE: {
397
+ emoji: '🚫',
398
+ utf8: '⊘', // U+2298 Circled division slash
399
+ ascii: '[BLOCKED]'
400
+ },
401
+ PARALLEL: {
402
+ emoji: '📊',
403
+ utf8: '═', // U+2550 Box drawings double horizontal
404
+ ascii: '[||]'
405
+ }
406
+ };
407
+ /**
408
+ * Get current icon mode based on environment and flags
409
+ */
410
+ export function getIconMode() {
411
+ // Check command-line flags first
412
+ if (process.argv.includes('--ascii')) {
413
+ return IconMode.ASCII;
414
+ }
415
+ if (process.argv.includes('--emoji')) {
416
+ return IconMode.EMOJI;
417
+ }
418
+ // Check environment variables
419
+ if (process.env.BKTIDE_ASCII === '1') {
420
+ return IconMode.ASCII;
421
+ }
422
+ if (process.env.BKTIDE_EMOJI === '1') {
423
+ return IconMode.EMOJI;
424
+ }
425
+ // Default to UTF-8 symbols (clean, universal, works in most modern terminals)
426
+ // ASCII is only used if explicitly requested via flag or env var
427
+ return IconMode.UTF8;
428
+ }
429
+ /**
430
+ * Helper to get icon based on current mode
431
+ */
432
+ export function getIcon(iconDef) {
433
+ const mode = getIconMode();
434
+ switch (mode) {
435
+ case IconMode.ASCII:
436
+ return iconDef.ascii;
437
+ case IconMode.UTF8:
438
+ return iconDef.utf8;
439
+ default:
440
+ return iconDef.emoji;
441
+ }
442
+ }
443
+ /**
444
+ * Get state icon for build/job states
445
+ */
446
+ export function getStateIcon(state) {
447
+ const upperState = state.toUpperCase().replace('CANCELING', 'CANCELED');
448
+ const iconDef = STATE_ICONS[upperState] || STATE_ICONS.UNKNOWN;
449
+ return getIcon(iconDef);
450
+ }
451
+ /**
452
+ * Get annotation style icon
453
+ */
454
+ export function getAnnotationIcon(style) {
455
+ const upperStyle = style.toUpperCase();
456
+ const iconDef = ANNOTATION_ICONS[upperStyle] || ANNOTATION_ICONS.DEFAULT;
457
+ return getIcon(iconDef);
458
+ }
459
+ /**
460
+ * Get progress/debug icon
461
+ */
462
+ export function getProgressIcon(type) {
463
+ return getIcon(PROGRESS_ICONS[type]);
464
+ }
280
465
  //# sourceMappingURL=theme.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"theme.js","sourceRoot":"/","sources":["ui/theme.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Enhanced Visual Design System for bktide CLI\n * \n * This module implements a comprehensive color and typography system\n * that enhances information hierarchy and accessibility.\n */\nimport chalk from 'chalk';\nimport { getSymbols } from './symbols.js';\n\nfunction isTTY(): boolean {\n return Boolean(process.stdout.isTTY);\n}\n\nfunction colorEnabled(): boolean {\n if (process.env.NO_COLOR) return false;\n const mode = process.env.BKTIDE_COLOR_MODE || 'auto';\n if (mode === 'never') return false;\n if (mode === 'always') return true;\n return isTTY();\n}\n\n/**\n * Semantic color system for different information types\n * Using colorblind-safe palette\n */\nexport const SEMANTIC_COLORS = {\n // Status colors (colorblind-safe)\n success: (s: string) => colorEnabled() ? chalk.blue(s) : s,\n error: (s: string) => colorEnabled() ? chalk.rgb(255, 140, 0)(s) : s,\n warning: (s: string) => colorEnabled() ? chalk.yellow(s) : s,\n info: (s: string) => colorEnabled() ? chalk.cyan(s) : s,\n \n // Typography emphasis levels\n heading: (s: string) => colorEnabled() ? chalk.bold.underline(s) : `== ${s} ==`,\n subheading: (s: string) => colorEnabled() ? chalk.bold(s) : `** ${s} **`,\n label: (s: string) => colorEnabled() ? chalk.bold(s) : s.toUpperCase(),\n \n // Data type highlighting\n identifier: (s: string) => colorEnabled() ? chalk.cyan(s) : s,\n count: (s: string) => colorEnabled() ? chalk.magenta(s) : s,\n url: (s: string) => colorEnabled() ? chalk.underline.cyan(s) : `<${s}>`,\n \n // De-emphasis (auxiliary information)\n dim: (s: string) => colorEnabled() ? chalk.dim(s) : s,\n muted: (s: string) => colorEnabled() ? chalk.gray(s) : s,\n tip: (s: string) => colorEnabled() ? chalk.dim(s) : `(${s})`,\n help: (s: string) => colorEnabled() ? chalk.dim.italic(s) : `[${s}]`,\n \n // Special formatting\n highlight: (s: string) => colorEnabled() ? chalk.magenta(s) : s,\n code: (s: string) => colorEnabled() ? chalk.bgGray.white(` ${s} `) : `\\`${s}\\``,\n};\n\n/**\n * Build status specific theming\n * Matches conventions from GitHub Actions, CircleCI, Jenkins\n */\nexport const BUILD_STATUS_THEME = {\n // Success states\n PASSED: {\n color: SEMANTIC_COLORS.success,\n symbol: '✓',\n ascii: '[OK]',\n },\n \n // Failure states\n FAILED: {\n color: SEMANTIC_COLORS.error,\n symbol: '✖',\n ascii: '[FAIL]',\n },\n FAILING: {\n color: (s: string) => colorEnabled() ? chalk.rgb(255, 165, 0)(s) : s,\n symbol: '⚠',\n ascii: '[FAILING]',\n },\n \n // Warning states\n BLOCKED: {\n color: SEMANTIC_COLORS.warning,\n symbol: '⚠',\n ascii: '[BLOCKED]',\n },\n CANCELED: {\n color: SEMANTIC_COLORS.warning,\n symbol: '⊘',\n ascii: '[CANCEL]',\n },\n CANCELING: {\n color: SEMANTIC_COLORS.warning,\n symbol: '⊘',\n ascii: '[...]',\n },\n \n // Active states\n RUNNING: {\n color: SEMANTIC_COLORS.info,\n symbol: '↻',\n ascii: '[RUN]',\n },\n SCHEDULED: {\n color: SEMANTIC_COLORS.info,\n symbol: '⏱',\n ascii: '[QUEUE]',\n },\n \n // Inactive states\n SKIPPED: {\n color: SEMANTIC_COLORS.muted,\n symbol: '−',\n ascii: '[SKIP]',\n },\n NOT_RUN: {\n color: SEMANTIC_COLORS.muted,\n symbol: '○',\n ascii: '[--]',\n },\n};\n\n/**\n * Format a build status with appropriate color and symbol\n */\nexport function formatBuildStatus(\n status: string, \n options?: { useSymbol?: boolean; ascii?: boolean }\n): string {\n // Normalize status to uppercase for theme lookup\n const normalizedStatus = status.toUpperCase();\n const theme = BUILD_STATUS_THEME[normalizedStatus as keyof typeof BUILD_STATUS_THEME];\n if (!theme) {\n return SEMANTIC_COLORS.muted(status);\n }\n \n const useSymbol = options?.useSymbol ?? true;\n const ascii = options?.ascii ?? false;\n \n if (useSymbol) {\n const symbol = ascii ? theme.ascii : theme.symbol;\n // Keep original casing for display\n return `${symbol} ${theme.color(status)}`;\n }\n \n // Keep original casing for display\n return theme.color(status);\n}\n\n/**\n * Tip display styles for different contexts\n */\nexport enum TipStyle {\n GROUPED = 'grouped', // Tips: with arrows\n INDIVIDUAL = 'individual', // → Individual arrows\n ACTIONS = 'actions', // Next steps: with arrows\n FIXES = 'fixes', // To fix this: numbered\n BOX = 'box' // Fancy box with arrows (wide terminals)\n}\n\n/**\n * Format tips with consistent styling based on context\n */\nexport function formatTips(\n tips: string[], \n style: TipStyle = TipStyle.GROUPED\n): string {\n if (tips.length === 0) return '';\n \n switch (style) {\n case TipStyle.GROUPED:\n return formatGroupedTips(tips);\n case TipStyle.INDIVIDUAL:\n return formatIndividualTips(tips);\n case TipStyle.ACTIONS:\n return formatActionTips(tips);\n case TipStyle.FIXES:\n return formatFixTips(tips);\n case TipStyle.BOX:\n return formatTipBox(tips); // Use existing function\n default:\n return formatGroupedTips(tips);\n }\n}\n\nfunction formatGroupedTips(tips: string[]): string {\n const lines: string[] = [];\n lines.push(SEMANTIC_COLORS.dim('Tips:'));\n tips.forEach(tip => {\n lines.push(SEMANTIC_COLORS.dim(` → ${tip}`));\n });\n return lines.join('\\n');\n}\n\nfunction formatIndividualTips(tips: string[]): string {\n return tips\n .map(tip => SEMANTIC_COLORS.dim(`→ ${tip}`))\n .join('\\n');\n}\n\nfunction formatActionTips(tips: string[]): string {\n const lines: string[] = [];\n lines.push(SEMANTIC_COLORS.dim('Next steps:'));\n tips.forEach(tip => {\n lines.push(SEMANTIC_COLORS.dim(` → ${tip}`));\n });\n return lines.join('\\n');\n}\n\nfunction formatFixTips(tips: string[]): string {\n const lines: string[] = [];\n lines.push(SEMANTIC_COLORS.subheading('To fix this:'));\n tips.forEach((tip, i) => {\n lines.push(` ${i + 1}. ${tip}`);\n });\n return lines.join('\\n');\n}\n\n/**\n * Create a formatted tip box for better visual separation\n * Only used in wide terminals\n */\nexport function formatTipBox(tips: string[], width?: number): string {\n const termWidth = width || process.stdout.columns || 80;\n \n // Only use fancy box in wide terminals\n if (termWidth < 80 || !colorEnabled()) {\n return formatGroupedTips(tips);\n }\n \n const lines: string[] = [];\n const boxWidth = Math.min(termWidth - 4, 60);\n const border = '─'.repeat(boxWidth - 10);\n \n lines.push(SEMANTIC_COLORS.dim(`┌─ Tips ${border}`));\n tips.forEach(tip => {\n lines.push(SEMANTIC_COLORS.dim(`│ → ${tip}`));\n });\n lines.push(SEMANTIC_COLORS.dim(`└${'─'.repeat(boxWidth - 1)}`));\n \n return lines.join('\\n');\n}\n\n/**\n * Format an error message with consistent styling\n */\nexport function formatError(\n error: string | Error, \n options?: { \n showHelp?: boolean; \n helpCommand?: string;\n suggestions?: string[];\n }\n): string {\n const lines: string[] = [];\n const symbols = getSymbols();\n \n // Error header\n lines.push(`${SEMANTIC_COLORS.error(symbols.error)} ${chalk.bold('Error')}`);\n lines.push('');\n \n // Error message\n const message = typeof error === 'string' ? error : error.message;\n lines.push(message);\n \n // Suggestions if provided\n if (options?.suggestions && options.suggestions.length > 0) {\n lines.push('');\n lines.push(formatTips(options.suggestions, TipStyle.FIXES));\n }\n \n // Help command\n if (options?.showHelp && options?.helpCommand) {\n lines.push('');\n lines.push(SEMANTIC_COLORS.help(`Need help? Run: ${options.helpCommand}`));\n }\n \n return lines.join('\\n');\n}\n\n/**\n * Format a success message (subtle, not redundant)\n */\nexport function formatSuccess(message: string, count?: number): string {\n const symbols = getSymbols();\n \n if (count !== undefined) {\n return `${SEMANTIC_COLORS.success(symbols.success)} ${message} ${SEMANTIC_COLORS.count(count.toString())}`;\n }\n \n return `${SEMANTIC_COLORS.success(symbols.success)} ${message}`;\n}\n\n/**\n * Format empty state messages\n */\nexport function formatEmptyState(\n message: string,\n suggestions?: string[]\n): string {\n const lines: string[] = [];\n \n lines.push(SEMANTIC_COLORS.dim(message));\n \n if (suggestions && suggestions.length > 0) {\n lines.push('');\n suggestions.forEach(s => {\n // Make commands stand out from the dimmed text\n const formatted = s.replace(/--\\w+[^ ]*/g, match => chalk.reset(match));\n lines.push(SEMANTIC_COLORS.dim(formatted));\n });\n }\n \n return lines.join('\\n');\n}\n\n/**\n * Legacy color exports for backward compatibility\n * @deprecated Use SEMANTIC_COLORS instead\n */\nexport const COLORS = {\n error: SEMANTIC_COLORS.error,\n warn: SEMANTIC_COLORS.warning,\n success: SEMANTIC_COLORS.success,\n info: SEMANTIC_COLORS.info,\n muted: SEMANTIC_COLORS.muted,\n highlight: SEMANTIC_COLORS.highlight,\n dim: SEMANTIC_COLORS.dim,\n};\n\n// Export symbols from the symbols module\nexport const SYMBOLS = getSymbols();\n\nexport function shouldDecorate(format?: string): boolean {\n const f = (format || '').toLowerCase();\n return f !== 'json' && f !== 'alfred' && colorEnabled();\n}\n\n\n"]}
1
+ {"version":3,"file":"theme.js","sourceRoot":"/","sources":["ui/theme.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Enhanced Visual Design System for bktide CLI\n * \n * This module implements a comprehensive color and typography system\n * that enhances information hierarchy and accessibility.\n */\nimport chalk from 'chalk';\nimport { getSymbols } from './symbols.js';\nimport { terminalLink } from '../utils/terminal-links.js';\n\nfunction isTTY(): boolean {\n return Boolean(process.stdout.isTTY);\n}\n\nfunction colorEnabled(): boolean {\n if (process.env.NO_COLOR) return false;\n const mode = process.env.BKTIDE_COLOR_MODE || 'auto';\n if (mode === 'never') return false;\n if (mode === 'always') return true;\n return isTTY();\n}\n\n/**\n * Semantic color system for different information types\n * Using colorblind-safe palette\n */\nexport const SEMANTIC_COLORS = {\n // Status colors (colorblind-safe)\n success: (s: string) => colorEnabled() ? chalk.blue(s) : s,\n error: (s: string) => colorEnabled() ? chalk.rgb(255, 140, 0)(s) : s,\n warning: (s: string) => colorEnabled() ? chalk.yellow(s) : s,\n info: (s: string) => colorEnabled() ? chalk.cyan(s) : s,\n \n // Typography emphasis levels\n heading: (s: string) => colorEnabled() ? chalk.bold.underline(s) : `== ${s} ==`,\n subheading: (s: string) => colorEnabled() ? chalk.bold(s) : `** ${s} **`,\n label: (s: string) => colorEnabled() ? chalk.bold(s) : s.toUpperCase(),\n \n // Data type highlighting\n identifier: (s: string) => colorEnabled() ? chalk.cyan(s) : s,\n count: (s: string) => colorEnabled() ? chalk.magenta(s) : s,\n url: (s: string, label?: string) => terminalLink(s, label),\n \n // De-emphasis (auxiliary information)\n dim: (s: string) => colorEnabled() ? chalk.dim(s) : s,\n muted: (s: string) => colorEnabled() ? chalk.gray(s) : s,\n tip: (s: string) => colorEnabled() ? chalk.dim(s) : `(${s})`,\n help: (s: string) => colorEnabled() ? chalk.dim.italic(s) : `[${s}]`,\n \n // Special formatting\n highlight: (s: string) => colorEnabled() ? chalk.magenta(s) : s,\n code: (s: string) => colorEnabled() ? chalk.bgGray.white(` ${s} `) : `\\`${s}\\``,\n};\n\n/**\n * Build status specific theming\n * Matches conventions from GitHub Actions, CircleCI, Jenkins\n */\nexport const BUILD_STATUS_THEME = {\n // Success states\n PASSED: {\n color: SEMANTIC_COLORS.success,\n symbol: '✓',\n ascii: '[OK]',\n },\n \n // Failure states\n FAILED: {\n color: SEMANTIC_COLORS.error,\n symbol: '✖',\n ascii: '[FAIL]',\n },\n FAILING: {\n color: (s: string) => colorEnabled() ? chalk.rgb(255, 165, 0)(s) : s,\n symbol: '⚠',\n ascii: '[FAILING]',\n },\n \n // Warning states\n BLOCKED: {\n color: SEMANTIC_COLORS.warning,\n symbol: '⚠',\n ascii: '[BLOCKED]',\n },\n CANCELED: {\n color: SEMANTIC_COLORS.warning,\n symbol: '⊘',\n ascii: '[CANCEL]',\n },\n CANCELING: {\n color: SEMANTIC_COLORS.warning,\n symbol: '⊘',\n ascii: '[...]',\n },\n \n // Active states\n RUNNING: {\n color: SEMANTIC_COLORS.info,\n symbol: '↻',\n ascii: '[RUN]',\n },\n SCHEDULED: {\n color: SEMANTIC_COLORS.info,\n symbol: '⏱',\n ascii: '[QUEUE]',\n },\n \n // Inactive states\n SKIPPED: {\n color: SEMANTIC_COLORS.muted,\n symbol: '−',\n ascii: '[SKIP]',\n },\n NOT_RUN: {\n color: SEMANTIC_COLORS.muted,\n symbol: '○',\n ascii: '[--]',\n },\n};\n\n/**\n * Format a build status with appropriate color and symbol\n */\nexport function formatBuildStatus(\n status: string, \n options?: { useSymbol?: boolean; ascii?: boolean }\n): string {\n // Normalize status to uppercase for theme lookup\n const normalizedStatus = status.toUpperCase();\n const theme = BUILD_STATUS_THEME[normalizedStatus as keyof typeof BUILD_STATUS_THEME];\n if (!theme) {\n return SEMANTIC_COLORS.muted(status);\n }\n \n const useSymbol = options?.useSymbol ?? true;\n const ascii = options?.ascii ?? false;\n \n if (useSymbol) {\n const symbol = ascii ? theme.ascii : theme.symbol;\n // Keep original casing for display\n return `${symbol} ${theme.color(status)}`;\n }\n \n // Keep original casing for display\n return theme.color(status);\n}\n\n/**\n * Tip display styles for different contexts\n */\nexport enum TipStyle {\n GROUPED = 'grouped', // Tips: with arrows\n INDIVIDUAL = 'individual', // → Individual arrows\n ACTIONS = 'actions', // Next steps: with arrows\n FIXES = 'fixes', // To fix this: numbered\n BOX = 'box' // Fancy box with arrows (wide terminals)\n}\n\n/**\n * Format tips with consistent styling based on context\n */\nexport function formatTips(\n tips: string[], \n style: TipStyle = TipStyle.GROUPED,\n includeTurnOff: boolean = true\n): string {\n if (tips.length === 0) return '';\n \n // Add the turn-off tip if not already included\n const allTips = [...tips];\n const turnOffMessage = 'Use --no-tips to hide these hints';\n if (includeTurnOff && !tips.some(tip => tip.includes('--no-tips'))) {\n allTips.push(turnOffMessage);\n }\n \n switch (style) {\n case TipStyle.GROUPED:\n return formatGroupedTips(allTips);\n case TipStyle.INDIVIDUAL:\n return formatIndividualTips(allTips);\n case TipStyle.ACTIONS:\n return formatActionTips(allTips);\n case TipStyle.FIXES:\n return formatFixTips(allTips);\n case TipStyle.BOX:\n return formatTipBox(allTips); // Use existing function\n default:\n return formatGroupedTips(allTips);\n }\n}\n\nfunction formatGroupedTips(tips: string[]): string {\n const lines: string[] = [];\n lines.push(SEMANTIC_COLORS.dim('Tips:'));\n tips.forEach(tip => {\n lines.push(SEMANTIC_COLORS.dim(` → ${tip}`));\n });\n return lines.join('\\n');\n}\n\nfunction formatIndividualTips(tips: string[]): string {\n return tips\n .map(tip => SEMANTIC_COLORS.dim(`→ ${tip}`))\n .join('\\n');\n}\n\nfunction formatActionTips(tips: string[]): string {\n const lines: string[] = [];\n lines.push(SEMANTIC_COLORS.dim('Next steps:'));\n tips.forEach(tip => {\n lines.push(SEMANTIC_COLORS.dim(` → ${tip}`));\n });\n return lines.join('\\n');\n}\n\nfunction formatFixTips(tips: string[]): string {\n const lines: string[] = [];\n lines.push(SEMANTIC_COLORS.subheading('To fix this:'));\n tips.forEach((tip, i) => {\n lines.push(` ${i + 1}. ${tip}`);\n });\n return lines.join('\\n');\n}\n\n/**\n * Create a formatted tip box for better visual separation\n * Only used in wide terminals\n */\nexport function formatTipBox(tips: string[], width?: number): string {\n const termWidth = width || process.stdout.columns || 80;\n \n // Only use fancy box in wide terminals\n if (termWidth < 80 || !colorEnabled()) {\n return formatGroupedTips(tips);\n }\n \n const lines: string[] = [];\n const boxWidth = Math.min(termWidth - 4, 60);\n const border = '─'.repeat(boxWidth - 10);\n \n lines.push(SEMANTIC_COLORS.dim(`┌─ Tips ${border}`));\n tips.forEach(tip => {\n lines.push(SEMANTIC_COLORS.dim(`│ → ${tip}`));\n });\n lines.push(SEMANTIC_COLORS.dim(`└${'─'.repeat(boxWidth - 1)}`));\n \n return lines.join('\\n');\n}\n\n/**\n * Format an error message with consistent styling\n */\nexport function formatError(\n error: string | Error, \n options?: { \n showHelp?: boolean; \n helpCommand?: string;\n suggestions?: string[];\n }\n): string {\n const lines: string[] = [];\n const symbols = getSymbols();\n \n // Error header\n lines.push(`${SEMANTIC_COLORS.error(symbols.error)} ${chalk.bold('Error')}`);\n lines.push('');\n \n // Error message\n const message = typeof error === 'string' ? error : error.message;\n lines.push(message);\n \n // Suggestions if provided\n if (options?.suggestions && options.suggestions.length > 0) {\n lines.push('');\n lines.push(formatTips(options.suggestions, TipStyle.FIXES));\n }\n \n // Help command\n if (options?.showHelp && options?.helpCommand) {\n lines.push('');\n lines.push(SEMANTIC_COLORS.help(`Need help? Run: ${options.helpCommand}`));\n }\n \n return lines.join('\\n');\n}\n\n/**\n * Format a success message (subtle, not redundant)\n */\nexport function formatSuccess(message: string, count?: number): string {\n const symbols = getSymbols();\n \n if (count !== undefined) {\n return `${SEMANTIC_COLORS.success(symbols.success)} ${message} ${SEMANTIC_COLORS.count(count.toString())}`;\n }\n \n return `${SEMANTIC_COLORS.success(symbols.success)} ${message}`;\n}\n\n/**\n * Format empty state messages\n */\nexport function formatEmptyState(\n message: string,\n suggestions?: string[]\n): string {\n const lines: string[] = [];\n \n lines.push(SEMANTIC_COLORS.dim(message));\n \n if (suggestions && suggestions.length > 0) {\n lines.push('');\n suggestions.forEach(s => {\n // Make commands stand out from the dimmed text\n const formatted = s.replace(/--\\w+[^ ]*/g, match => chalk.reset(match));\n lines.push(SEMANTIC_COLORS.dim(formatted));\n });\n }\n \n return lines.join('\\n');\n}\n\n/**\n * Legacy color exports for backward compatibility\n * @deprecated Use SEMANTIC_COLORS instead\n */\nexport const COLORS = {\n error: SEMANTIC_COLORS.error,\n warn: SEMANTIC_COLORS.warning,\n success: SEMANTIC_COLORS.success,\n info: SEMANTIC_COLORS.info,\n muted: SEMANTIC_COLORS.muted,\n highlight: SEMANTIC_COLORS.highlight,\n dim: SEMANTIC_COLORS.dim,\n};\n\n// Export symbols from the symbols module\nexport const SYMBOLS = getSymbols();\n\nexport function shouldDecorate(format?: string): boolean {\n const f = (format || '').toLowerCase();\n return f !== 'json' && f !== 'alfred' && colorEnabled();\n}\n\n/**\n * Icon Display Modes\n */\nexport enum IconMode {\n EMOJI = 'emoji', // Full emoji support\n UTF8 = 'utf8', // UTF-8 symbols (no emoji)\n ASCII = 'ascii' // ASCII-only fallback\n}\n\n/**\n * Build and Job State Icons\n * Each has emoji, UTF-8, and ASCII alternatives\n */\nexport const STATE_ICONS = {\n PASSED: {\n emoji: '✅',\n utf8: '✓', // U+2713 Check mark\n ascii: '[OK]'\n },\n FAILED: {\n emoji: '❌',\n utf8: '✗', // U+2717 Ballot X\n ascii: '[FAIL]'\n },\n RUNNING: {\n emoji: '🔄',\n utf8: '↻', // U+21BB Clockwise arrow\n ascii: '[RUN]'\n },\n BLOCKED: {\n emoji: '⏸️',\n utf8: '‖', // U+2016 Double vertical line\n ascii: '[BLOCK]'\n },\n CANCELED: {\n emoji: '🚫',\n utf8: '⊘', // U+2298 Circled division slash\n ascii: '[CANCEL]'\n },\n SCHEDULED: {\n emoji: '📅',\n utf8: '⏰', // U+23F0 Alarm clock\n ascii: '[SCHED]'\n },\n SKIPPED: {\n emoji: '⏭️',\n utf8: '»', // U+00BB Right-pointing double angle\n ascii: '[SKIP]'\n },\n UNKNOWN: {\n emoji: '❓',\n utf8: '?', // Regular question mark\n ascii: '[?]'\n }\n};\n\n/**\n * Annotation Style Icons\n */\nexport const ANNOTATION_ICONS = {\n ERROR: {\n emoji: '❌',\n utf8: '✗', // U+2717 Ballot X\n ascii: '[ERR]'\n },\n WARNING: {\n emoji: '⚠️',\n utf8: '⚠', // U+26A0 Warning sign (without emoji variant)\n ascii: '[WARN]'\n },\n INFO: {\n emoji: 'ℹ️',\n utf8: 'ℹ', // U+2139 Information source (no circle)\n ascii: '[INFO]'\n },\n SUCCESS: {\n emoji: '✅',\n utf8: '✓', // U+2713 Check mark\n ascii: '[OK]'\n },\n DEFAULT: {\n emoji: '📝',\n utf8: '◆', // U+25C6 Black diamond\n ascii: '[NOTE]'\n }\n};\n\n/**\n * Progress and Debug Icons\n */\nexport const PROGRESS_ICONS = {\n TIMING: {\n emoji: '⏱️',\n utf8: '⧗', // U+29D7 Black hourglass\n ascii: '[TIME]'\n },\n STARTING: {\n emoji: '🕒',\n utf8: '◷', // U+25F7 White circle with upper right quadrant\n ascii: '[>>>]'\n },\n RETRY: {\n emoji: '🔄',\n utf8: '↻', // U+21BB Clockwise arrow\n ascii: '[RETRY]'\n },\n SUCCESS_LOG: {\n emoji: '✅',\n utf8: '✓', // U+2713 Check mark\n ascii: '[✓]'\n },\n BLOCKED_MESSAGE: {\n emoji: '🚫',\n utf8: '⊘', // U+2298 Circled division slash\n ascii: '[BLOCKED]'\n },\n PARALLEL: {\n emoji: '📊',\n utf8: '═', // U+2550 Box drawings double horizontal\n ascii: '[||]'\n }\n};\n\n/**\n * Get current icon mode based on environment and flags\n */\nexport function getIconMode(): IconMode {\n // Check command-line flags first\n if (process.argv.includes('--ascii')) {\n return IconMode.ASCII;\n }\n if (process.argv.includes('--emoji')) {\n return IconMode.EMOJI;\n }\n \n // Check environment variables\n if (process.env.BKTIDE_ASCII === '1') {\n return IconMode.ASCII;\n }\n if (process.env.BKTIDE_EMOJI === '1') {\n return IconMode.EMOJI;\n }\n \n // Default to UTF-8 symbols (clean, universal, works in most modern terminals)\n // ASCII is only used if explicitly requested via flag or env var\n return IconMode.UTF8;\n}\n\n/**\n * Helper to get icon based on current mode\n */\nexport function getIcon(iconDef: { emoji: string; utf8: string; ascii: string }): string {\n const mode = getIconMode();\n switch (mode) {\n case IconMode.ASCII:\n return iconDef.ascii;\n case IconMode.UTF8:\n return iconDef.utf8;\n default:\n return iconDef.emoji;\n }\n}\n\n/**\n * Get state icon for build/job states\n */\nexport function getStateIcon(state: string): string {\n const upperState = state.toUpperCase().replace('CANCELING', 'CANCELED');\n const iconDef = STATE_ICONS[upperState as keyof typeof STATE_ICONS] || STATE_ICONS.UNKNOWN;\n return getIcon(iconDef);\n}\n\n/**\n * Get annotation style icon\n */\nexport function getAnnotationIcon(style: string): string {\n const upperStyle = style.toUpperCase();\n const iconDef = ANNOTATION_ICONS[upperStyle as keyof typeof ANNOTATION_ICONS] || ANNOTATION_ICONS.DEFAULT;\n return getIcon(iconDef);\n}\n\n/**\n * Get progress/debug icon\n */\nexport function getProgressIcon(type: keyof typeof PROGRESS_ICONS): string {\n return getIcon(PROGRESS_ICONS[type]);\n}\n\n\n"]}
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Terminal hyperlink support for clickable URLs
3
+ *
4
+ * Uses OSC 8 escape sequences for terminals that support it.
5
+ * Similar to color handling, provides auto-detection with override options.
6
+ */
7
+ import chalk from 'chalk';
8
+ /**
9
+ * Check if the terminal supports hyperlinks
10
+ * Based on known terminal programs and environment variables
11
+ */
12
+ function supportsHyperlinks() {
13
+ // Check for common CI environments where hyperlinks won't work
14
+ if (process.env.CI) {
15
+ return false;
16
+ }
17
+ const termProgram = process.env.TERM_PROGRAM?.toLowerCase() || '';
18
+ const termName = process.env.TERM?.toLowerCase() || '';
19
+ // Known terminals that support OSC 8 hyperlinks
20
+ const supportedTerminals = [
21
+ 'vscode',
22
+ 'cursor',
23
+ 'iterm.app',
24
+ 'iterm2',
25
+ 'hyper',
26
+ 'wezterm',
27
+ 'kitty',
28
+ 'ghostty',
29
+ 'tabby',
30
+ 'terminus',
31
+ 'konsole',
32
+ 'rio',
33
+ ];
34
+ // Check TERM_PROGRAM
35
+ if (supportedTerminals.some(t => termProgram.includes(t))) {
36
+ return true;
37
+ }
38
+ // Check TERM for some terminals
39
+ if (termName.includes('kitty') || termName.includes('wezterm')) {
40
+ return true;
41
+ }
42
+ // Windows Terminal sets this
43
+ if (process.env.WT_SESSION) {
44
+ return true;
45
+ }
46
+ // VS Code integrated terminal
47
+ if (process.env.VSCODE_GIT_IPC_HANDLE || process.env.VSCODE_INJECTION) {
48
+ return true;
49
+ }
50
+ return false;
51
+ }
52
+ /**
53
+ * Check if TTY is available (similar to color detection)
54
+ */
55
+ function isTTY() {
56
+ return Boolean(process.stdout.isTTY);
57
+ }
58
+ /**
59
+ * Determine if hyperlinks should be enabled
60
+ * Follows same pattern as color detection
61
+ */
62
+ export function hyperlinksEnabled() {
63
+ // Respect NO_COLOR as it indicates plain text preference
64
+ if (process.env.NO_COLOR)
65
+ return false;
66
+ // Check for explicit hyperlink mode
67
+ const mode = process.env.BKTIDE_HYPERLINK_MODE || process.env.FORCE_HYPERLINK || 'auto';
68
+ if (mode === 'never' || mode === '0')
69
+ return false;
70
+ if (mode === 'always' || mode === '1')
71
+ return true;
72
+ // Auto mode: check if TTY and terminal supports it
73
+ return isTTY() && supportsHyperlinks();
74
+ }
75
+ /**
76
+ * Format a terminal hyperlink using OSC 8 escape sequence
77
+ *
78
+ * @param url - The URL to link to
79
+ * @param label - Optional label text (defaults to URL)
80
+ * @returns Formatted string with hyperlink if supported, fallback otherwise
81
+ */
82
+ export function terminalLink(url, label) {
83
+ const text = label || url;
84
+ if (!url) {
85
+ return text;
86
+ }
87
+ // If hyperlinks are enabled, use OSC 8 escape sequence
88
+ if (hyperlinksEnabled()) {
89
+ // OSC 8 format: ESC]8;;URL\aLABEL\ESC]8;;\a
90
+ // \x1b = ESC, \x07 = BEL (more compatible than ST)
91
+ return `\x1b]8;;${url}\x07${text}\x1b]8;;\x07`;
92
+ }
93
+ // Fallback: use chalk underline if colors are enabled
94
+ // This matches the existing url formatting in theme.ts
95
+ if (process.stdout.isTTY && !process.env.NO_COLOR) {
96
+ return chalk.underline.cyan(text);
97
+ }
98
+ // Final fallback: plain text with angle brackets if URL differs from label
99
+ if (label && label !== url) {
100
+ return `${label} <${url}>`;
101
+ }
102
+ return `<${url}>`;
103
+ }
104
+ /**
105
+ * Create a hyperlink with automatic Buildkite URL construction
106
+ *
107
+ * @param org - Organization slug
108
+ * @param pipeline - Pipeline slug (optional)
109
+ * @param buildNumber - Build number (optional)
110
+ * @param label - Optional label text
111
+ */
112
+ export function buildkiteLink(org, pipeline, buildNumber, label) {
113
+ let url = `https://buildkite.com/${org}`;
114
+ if (pipeline) {
115
+ url += `/${pipeline}`;
116
+ if (buildNumber) {
117
+ url += `/builds/${buildNumber}`;
118
+ }
119
+ }
120
+ return terminalLink(url, label);
121
+ }
122
+ /**
123
+ * Create a GitHub pull request link
124
+ *
125
+ * @param repoUrl - Repository URL (GitHub format)
126
+ * @param prNumber - Pull request number or ID
127
+ * @param label - Optional label text
128
+ */
129
+ export function githubPRLink(repoUrl, prNumber, label) {
130
+ // Extract owner/repo from various GitHub URL formats
131
+ const match = repoUrl.match(/github\.com[/:]([^/]+)\/([^/.]+)/);
132
+ if (!match) {
133
+ return label || `PR #${prNumber}`;
134
+ }
135
+ const [, owner, repo] = match;
136
+ const url = `https://github.com/${owner}/${repo}/pull/${prNumber}`;
137
+ return terminalLink(url, label || `PR #${prNumber}`);
138
+ }
139
+ /**
140
+ * Parse and linkify URLs in text content
141
+ * Useful for annotation content that might contain URLs
142
+ *
143
+ * @param text - Text that might contain URLs
144
+ * @returns Text with URLs converted to hyperlinks
145
+ */
146
+ export function linkifyUrls(text) {
147
+ if (!hyperlinksEnabled()) {
148
+ return text;
149
+ }
150
+ // Simple URL regex - matches http(s) URLs
151
+ const urlRegex = /https?:\/\/[^\s<>"\{\}\|\\\^\[\]`]+/gi;
152
+ return text.replace(urlRegex, (url) => {
153
+ // Clean up common trailing punctuation that might not be part of the URL
154
+ const cleanUrl = url.replace(/[.,;:!?]+$/, '');
155
+ const trailing = url.slice(cleanUrl.length);
156
+ return terminalLink(cleanUrl) + trailing;
157
+ });
158
+ }
159
+ /**
160
+ * Format a help URL with appropriate styling
161
+ */
162
+ export function helpLink(url, label = 'Learn more') {
163
+ return terminalLink(url, label);
164
+ }
165
+ //# sourceMappingURL=terminal-links.js.map