@kb-labs/shared-cli-ui 2.94.0 → 2.96.0

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/dist/index.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import path from 'path';
2
2
  import { promises } from 'fs';
3
+ import * as readline from 'readline';
3
4
 
4
5
  // src/colors.ts
5
6
  var CSI = "\x1B[";
6
7
  var RESET = "\x1B[0m";
7
- var createColor = (...codes) => (text) => `${CSI}${codes.join(";")}m${text}${RESET}`;
8
+ var createColor = (...codes) => (text2) => `${CSI}${codes.join(";")}m${text2}${RESET}`;
8
9
  var accentBlue = "38;5;39";
9
10
  var accentViolet = "38;5;99";
10
11
  var accentTeal = "38;5;51";
@@ -32,16 +33,20 @@ var colors = {
32
33
  inverse: createColor(7)
33
34
  };
34
35
  var symbolCharacters = {
35
- success: "OK",
36
- error: "ERR",
37
- warning: "WARN",
38
- info: "\u2139",
36
+ success: "\u2713",
37
+ error: "\u2717",
38
+ warning: "\u26A0",
39
+ info: "\u25C6",
39
40
  bullet: "\u2022",
40
- clock: "TIME",
41
- folder: "DIR",
42
- package: "\u203A",
43
- pointer: "\u203A",
44
- section: "\u2502"
41
+ clock: "\u25F7",
42
+ folder: "\u25B8",
43
+ package: "\u25C6",
44
+ pointer: "\u276F",
45
+ section: "\u2502",
46
+ step: "\u25CB",
47
+ stepDone: "\u25CF",
48
+ arrow: "\u2192",
49
+ diamond: "\u25C6"
45
50
  };
46
51
  var symbols = {
47
52
  success: colors.success(symbolCharacters.success),
@@ -49,11 +54,15 @@ var symbols = {
49
54
  warning: colors.warning(symbolCharacters.warning),
50
55
  info: colors.info(symbolCharacters.info),
51
56
  bullet: colors.muted(symbolCharacters.bullet),
52
- clock: colors.info(symbolCharacters.clock),
57
+ clock: colors.muted(symbolCharacters.clock),
53
58
  folder: colors.primary(symbolCharacters.folder),
54
59
  package: colors.accent(symbolCharacters.package),
55
60
  pointer: colors.primary(symbolCharacters.pointer),
56
- section: colors.primary(symbolCharacters.section)
61
+ section: colors.muted(symbolCharacters.section),
62
+ step: colors.muted(symbolCharacters.step),
63
+ stepDone: colors.success(symbolCharacters.stepDone),
64
+ arrow: colors.primary(symbolCharacters.arrow),
65
+ diamond: colors.primary(symbolCharacters.diamond)
57
66
  };
58
67
  var isTruthyEnv = (value) => {
59
68
  if (!value) {
@@ -81,7 +90,7 @@ var supportsColor = (() => {
81
90
  }
82
91
  return true;
83
92
  })();
84
- var passthrough = (fn) => (text) => supportsColor ? fn(text) : text;
93
+ var passthrough = (fn) => (text2) => supportsColor ? fn(text2) : text2;
85
94
  var safeColors = {
86
95
  success: passthrough(colors.success),
87
96
  error: passthrough(colors.error),
@@ -103,30 +112,26 @@ var safeSymbols = {
103
112
  success: supportsColor ? symbols.success : "\u2713",
104
113
  error: supportsColor ? symbols.error : "\u2717",
105
114
  warning: supportsColor ? symbols.warning : "\u26A0",
106
- info: supportsColor ? symbols.info : "\u2192",
115
+ info: supportsColor ? symbols.info : "\u25C6",
107
116
  bullet: supportsColor ? symbols.bullet : "\u2022",
108
- clock: supportsColor ? symbols.clock : "time",
109
- folder: supportsColor ? symbols.folder : "dir",
110
- package: supportsColor ? symbols.package : "\u203A",
111
- pointer: supportsColor ? symbols.pointer : ">",
112
- section: supportsColor ? symbols.section : "|",
113
- // Box-drawing characters for modern side border
117
+ clock: supportsColor ? symbols.clock : "\u25F7",
118
+ folder: supportsColor ? symbols.folder : "\u25B8",
119
+ package: supportsColor ? symbols.package : "\u25C6",
120
+ pointer: supportsColor ? symbols.pointer : "\u276F",
121
+ section: supportsColor ? symbols.section : "\u2502",
122
+ step: supportsColor ? symbols.step : "\u25CB",
123
+ stepDone: supportsColor ? symbols.stepDone : "\u25CF",
124
+ arrow: supportsColor ? symbols.arrow : "\u2192",
125
+ diamond: supportsColor ? symbols.diamond : "\u25C6",
126
+ // Box-drawing characters
114
127
  separator: "\u2500",
115
- // Horizontal line
116
128
  border: "\u2502",
117
- // Vertical line
118
129
  topLeft: "\u250C",
119
- // Top-left corner
120
130
  topRight: "\u2510",
121
- // Top-right corner
122
131
  bottomLeft: "\u2514",
123
- // Bottom-left corner
124
132
  bottomRight: "\u2518",
125
- // Bottom-right corner
126
133
  leftT: "\u251C",
127
- // Left T-junction
128
134
  rightT: "\u2524"
129
- // Right T-junction
130
135
  };
131
136
 
132
137
  // src/loader.ts
@@ -181,8 +186,8 @@ var Loader = class {
181
186
  }
182
187
  if (!this.intervalId) {
183
188
  if (this.options.spinner) {
184
- const text = this.options.text ?? "Loading...";
185
- console.log(`${safeSymbols.info} ${text}`);
189
+ const text2 = this.options.text ?? "Loading...";
190
+ console.log(`${safeSymbols.info} ${text2}`);
186
191
  } else if (this.options.total !== void 0) {
187
192
  this.updateProgress();
188
193
  }
@@ -222,33 +227,33 @@ var Loader = class {
222
227
  const barLength = 20;
223
228
  const filledLength = Math.round(current / total * barLength);
224
229
  const bar = "\u2588".repeat(filledLength) + "\u2591".repeat(barLength - filledLength);
225
- const text = this.options.text || "Progress";
226
- process.stdout.write(`\r${safeColors.info("\u2192")} ${text}... ${bar} ${percentage}% (${current}/${total})`);
230
+ const text2 = this.options.text || "Progress";
231
+ process.stdout.write(`\r${safeColors.info("\u2192")} ${text2}... ${bar} ${percentage}% (${current}/${total})`);
227
232
  }
228
233
  };
229
- function createSpinner(text, jsonMode = false) {
230
- return new Loader({ text, spinner: true, jsonMode });
234
+ function createSpinner(text2, jsonMode = false) {
235
+ return new Loader({ text: text2, spinner: true, jsonMode });
231
236
  }
232
- function createProgressBar(text, total, jsonMode = false) {
233
- return new Loader({ text, spinner: false, total, current: 0, jsonMode });
237
+ function createProgressBar(text2, total, jsonMode = false) {
238
+ return new Loader({ text: text2, spinner: false, total, current: 0, jsonMode });
234
239
  }
235
- function showLoading(text, jsonMode = false) {
240
+ function showLoading(text2, jsonMode = false) {
236
241
  if (!jsonMode) {
237
- console.log(`${safeColors.info("\u2192")} ${text}...`);
242
+ console.log(`${safeColors.info("\u2192")} ${text2}...`);
238
243
  }
239
244
  }
240
- function showSuccess(text, jsonMode = false) {
245
+ function showSuccess(text2, jsonMode = false) {
241
246
  if (!jsonMode) {
242
- console.log(`${safeSymbols.success} ${text}`);
247
+ console.log(`${safeSymbols.success} ${text2}`);
243
248
  }
244
249
  }
245
- function showError(text, jsonMode = false) {
250
+ function showError(text2, jsonMode = false) {
246
251
  if (!jsonMode) {
247
- console.log(`${safeSymbols.error} ${text}`);
252
+ console.log(`${safeSymbols.error} ${text2}`);
248
253
  }
249
254
  }
250
- function useLoader(text, options) {
251
- return new Loader({ text, jsonMode: _jsonMode, ...options });
255
+ function useLoader(text2, options) {
256
+ return new Loader({ text: text2, jsonMode: _jsonMode, ...options });
252
257
  }
253
258
 
254
259
  // src/format.ts
@@ -435,14 +440,14 @@ function getDateParts(date, timeZone) {
435
440
  second: lookup.second ?? date.getUTCSeconds()
436
441
  };
437
442
  }
438
- function headline(text) {
439
- return safeColors.primary(safeColors.bold(text));
443
+ function headline(text2) {
444
+ return safeColors.primary(safeColors.bold(text2));
440
445
  }
441
- function accentLabel(text) {
442
- return safeColors.accent(safeColors.bold(text));
446
+ function accentLabel(text2) {
447
+ return safeColors.accent(safeColors.bold(text2));
443
448
  }
444
- function muted(text) {
445
- return safeColors.muted(text);
449
+ function muted(text2) {
450
+ return safeColors.muted(text2);
446
451
  }
447
452
  function formatSize(bytes) {
448
453
  const units = ["B", "KB", "MB", "GB"];
@@ -454,9 +459,9 @@ function formatSize(bytes) {
454
459
  }
455
460
  return `${size.toFixed(unitIndex === 0 ? 0 : 1)} ${units[unitIndex]}`;
456
461
  }
457
- function formatRelativeTime(timestamp) {
462
+ function formatRelativeTime(timestamp2) {
458
463
  const now = /* @__PURE__ */ new Date();
459
- const time = toDate(timestamp);
464
+ const time = toDate(timestamp2);
460
465
  if (!isValidDate(time)) {
461
466
  return "Invalid date";
462
467
  }
@@ -475,7 +480,7 @@ function formatRelativeTime(timestamp) {
475
480
  return `${seconds} second${seconds > 1 ? "s" : ""} ago`;
476
481
  }
477
482
  }
478
- function formatTimestamp(timestamp, options = {}) {
483
+ function formatTimestamp(timestamp2, options = {}) {
479
484
  const {
480
485
  mode = "local",
481
486
  timeZone,
@@ -483,7 +488,7 @@ function formatTimestamp(timestamp, options = {}) {
483
488
  includeMilliseconds = true,
484
489
  includeOffset = true
485
490
  } = options;
486
- const date = toDate(timestamp);
491
+ const date = toDate(timestamp2);
487
492
  if (!isValidDate(date)) {
488
493
  return "Invalid date";
489
494
  }
@@ -501,26 +506,26 @@ function formatTimestamp(timestamp, options = {}) {
501
506
  ].join(" ");
502
507
  return `${base}${offsetSuffix}`;
503
508
  }
504
- function truncate(text, maxLength) {
505
- if (text.length <= maxLength) {
506
- return text;
509
+ function truncate(text2, maxLength) {
510
+ if (text2.length <= maxLength) {
511
+ return text2;
507
512
  }
508
- return text.substring(0, maxLength - 3) + "...";
513
+ return text2.substring(0, maxLength - 3) + "...";
509
514
  }
510
- function pad(text, width, align = "left") {
511
- if (text.length >= width) {
512
- return text;
515
+ function pad(text2, width, align = "left") {
516
+ if (text2.length >= width) {
517
+ return text2;
513
518
  }
514
- const padding = width - text.length;
519
+ const padding = width - text2.length;
515
520
  switch (align) {
516
521
  case "right":
517
- return " ".repeat(padding) + text;
522
+ return " ".repeat(padding) + text2;
518
523
  case "center":
519
524
  const leftPad = Math.floor(padding / 2);
520
525
  const rightPad = padding - leftPad;
521
- return " ".repeat(leftPad) + text + " ".repeat(rightPad);
526
+ return " ".repeat(leftPad) + text2 + " ".repeat(rightPad);
522
527
  default:
523
- return text + " ".repeat(padding);
528
+ return text2 + " ".repeat(padding);
524
529
  }
525
530
  }
526
531
 
@@ -1254,10 +1259,10 @@ async function discoverArtifacts(baseDir, patterns) {
1254
1259
  function visualWidth(str) {
1255
1260
  const ansiRegex = /\x1B\[[0-9;]*[a-zA-Z]/g;
1256
1261
  const cleanStr = str.replace(ansiRegex, "");
1257
- const emojiRegex = /[\u{1F300}-\u{1F9FF}]|[\u{2600}-\u{26FF}]|[\u{2700}-\u{27BF}]|[\u{1F600}-\u{1F64F}]|[\u{1F680}-\u{1F6FF}]|[\u{1F900}-\u{1F9FF}]|[\u{1FA00}-\u{1FA6F}]|[\u{1FA70}-\u{1FAFF}]|[\u{2190}-\u{21FF}]|[\u{2300}-\u{23FF}]|[\u{24C2}-\u{1F251}]|[\u{2B50}-\u{2B55}]|[\u{3030}-\u{303D}]|[\u{3297}-\u{3299}]|[\u{1F000}-\u{1F02F}]|[\u{1F0A0}-\u{1F0FF}]|[\u{1F100}-\u{1F1FF}]|[\u{1F200}-\u{1F2FF}]|[\u{1F300}-\u{1F5FF}]|[\u{1F600}-\u{1F64F}]|[\u{1F680}-\u{1F6FF}]|[\u{1F700}-\u{1F7FF}]|[\u{1F800}-\u{1F8FF}]|[\u{1F900}-\u{1F9FF}]|[\u{1FA00}-\u{1FA6F}]|[\u{1FA70}-\u{1FAFF}]|[\u{23F0}-\u{23FF}]|[\u{25A0}-\u{25FF}]|[\u{2600}-\u{26FF}]|[\u{2700}-\u{27BF}]|[\u{FE00}-\u{FE0F}]|[\u{1F1E6}-\u{1F1FF}]|[\u{1F3FB}-\u{1F3FF}]|[\u{1F9B0}-\u{1F9B3}]|[\u{20E3}]|[\u{FE0F}]/gu;
1258
- const emojiMatches = cleanStr.match(emojiRegex);
1259
- const emojiCount = emojiMatches ? emojiMatches.length : 0;
1260
- return cleanStr.length - emojiCount + emojiCount * 2;
1262
+ const doubleWidthRegex = /[\u{1100}-\u{115F}]|[\u{2E80}-\u{A4CF}]|[\u{AC00}-\u{D7AF}]|[\u{F900}-\u{FAFF}]|[\u{FE10}-\u{FE1F}]|[\u{FE30}-\u{FE4F}]|[\u{FF01}-\u{FF60}]|[\u{FFE0}-\u{FFE6}]|[\u{1F000}-\u{1FFFF}]/gu;
1263
+ const wideMatches = cleanStr.match(doubleWidthRegex);
1264
+ const wideCount = wideMatches ? wideMatches.length : 0;
1265
+ return [...cleanStr].length + wideCount;
1261
1266
  }
1262
1267
  function padVisual(str, width, padChar = " ") {
1263
1268
  const vWidth = visualWidth(str);
@@ -1342,8 +1347,8 @@ function shouldUseAIFormat(format, jsonMode) {
1342
1347
  }
1343
1348
 
1344
1349
  // src/debug/formatters/human.ts
1345
- function formatTimestamp2(timestamp) {
1346
- const date = new Date(timestamp);
1350
+ function formatTimestamp2(timestamp2) {
1351
+ const date = new Date(timestamp2);
1347
1352
  return date.toISOString();
1348
1353
  }
1349
1354
  function formatDuration(duration) {
@@ -2295,63 +2300,141 @@ async function withRetry(fn, options = {}) {
2295
2300
  throw lastError;
2296
2301
  }
2297
2302
 
2303
+ // src/utils/errors.ts
2304
+ function validationError(ctx, message, hint, isJson) {
2305
+ if (isJson) {
2306
+ ctx.ui?.json?.({ ok: false, error: { code: "INVALID_ARGS", message, ...hint && { hint } } });
2307
+ } else {
2308
+ ctx.ui?.error?.(message, { ...hint && { hint } });
2309
+ }
2310
+ }
2311
+ function handleError(ctx, err, isJson) {
2312
+ const message = err instanceof Error ? err.message : String(err);
2313
+ if (isJson) {
2314
+ ctx.ui?.json?.({ ok: false, error: { code: "INTERNAL_ERROR", message } });
2315
+ } else {
2316
+ ctx.ui?.error?.(message);
2317
+ }
2318
+ }
2319
+ function rethrowForRest(err) {
2320
+ if (err !== null && typeof err === "object" && "statusCode" in err) {
2321
+ throw err;
2322
+ }
2323
+ const message = err instanceof Error ? err.message : String(err);
2324
+ throw Object.assign(new Error(message), {
2325
+ statusCode: 500,
2326
+ code: "INTERNAL_ERROR"
2327
+ });
2328
+ }
2329
+
2330
+ // src/destructive.ts
2331
+ function buildConfirmationSignal(a) {
2332
+ return {
2333
+ ok: false,
2334
+ confirmationRequired: true,
2335
+ destructive: true,
2336
+ irreversible: !a.reversible,
2337
+ severity: a.severity,
2338
+ action: a.action,
2339
+ resource: a.resource,
2340
+ effect: a.effect,
2341
+ reversible: a.reversible,
2342
+ ...a.blastRadius && { blastRadius: a.blastRadius },
2343
+ ...a.recovery && { recovery: a.recovery },
2344
+ confirmWith: a.confirmFlag ?? "--yes",
2345
+ message: renderDestructiveMessage(a)
2346
+ };
2347
+ }
2348
+ function renderDestructiveMessage(a) {
2349
+ const flag = a.confirmFlag ?? "--yes";
2350
+ const br = a.blastRadius;
2351
+ const blast = br ? ` (${[br.count != null ? `${br.count} ${br.unit ?? "item(s)"}` : "", br.scope].filter(Boolean).join(" \xB7 ")})` : "";
2352
+ const lead = a.reversible ? `[${a.severity}]` : `\u26A0 IRREVERSIBLE [${a.severity}]`;
2353
+ const rec = a.recovery ? ` Recovery: ${a.recovery}.` : a.reversible ? "" : " No recovery \u2014 data is permanently lost.";
2354
+ return `${lead} ${a.action} \u2014 ${a.effect} on ${a.resource}${blast}.${rec} Confirm with ${flag}.`;
2355
+ }
2356
+ function confirmDestructive(ctx, opts) {
2357
+ if (opts.confirmed) {
2358
+ return null;
2359
+ }
2360
+ const a = opts.action;
2361
+ if (opts.isJson) {
2362
+ ctx.ui?.json?.(buildConfirmationSignal(a));
2363
+ } else {
2364
+ (ctx.ui?.warn ?? ctx.ui?.error)?.(renderDestructiveMessage(a));
2365
+ }
2366
+ return { exitCode: 1 };
2367
+ }
2368
+
2298
2369
  // src/modern-format.ts
2299
2370
  function sideBorderBox(options) {
2300
- const { title, sections, footer, status, timing } = options;
2371
+ const { title, sections, footer, status, timing, summary } = options;
2301
2372
  const lines = [];
2302
2373
  const terminalWidth = typeof process !== "undefined" && process.stdout?.columns ? process.stdout.columns : 80;
2303
2374
  const itemMaxWidth = Math.max(40, terminalWidth - 4);
2304
- const titleLine = `${safeSymbols.topLeft}${safeSymbols.separator.repeat(2)} ${safeColors.primary(safeColors.bold(title))}`;
2375
+ const titleLine = `${safeColors.primary("\u25C6")} ${safeColors.bold(title)}`;
2305
2376
  lines.push(titleLine);
2306
- lines.push(safeSymbols.border);
2377
+ lines.push(safeColors.muted("\u2502"));
2378
+ if (summary && Object.keys(summary).length > 0) {
2379
+ const entries = Object.entries(summary).map(([k, v]) => [k, String(v)]);
2380
+ const metricsRecord = Object.fromEntries(entries);
2381
+ const metricsLines = metricsList(metricsRecord);
2382
+ for (const line of metricsLines) {
2383
+ lines.push(`${safeColors.muted("\u2502")} ${line}`);
2384
+ }
2385
+ if (sections.length > 0) {
2386
+ lines.push(safeColors.muted("\u2502"));
2387
+ }
2388
+ }
2307
2389
  for (let i = 0; i < sections.length; i++) {
2308
2390
  const section2 = sections[i];
2309
2391
  if (!section2) {
2310
2392
  continue;
2311
2393
  }
2312
2394
  if (section2.header) {
2313
- lines.push(`${safeSymbols.border} ${safeColors.bold(section2.header)}`);
2395
+ lines.push(`${safeColors.muted("\u2502")} ${safeColors.bold(section2.header)}`);
2314
2396
  }
2315
2397
  for (const rawItem of section2.items) {
2316
2398
  const item = typeof rawItem === "string" ? { text: rawItem } : rawItem;
2317
2399
  let displayLines;
2318
2400
  if (item.truncate !== void 0) {
2319
2401
  const vis = stripAnsi(item.text);
2320
- const truncated = vis.length > item.truncate ? vis.slice(0, item.truncate - 1) + "\u2026" : vis;
2321
- displayLines = [item.dim ? safeColors.muted(truncated) : truncated];
2402
+ const truncated = vis.length > item.truncate ? ansiSlice(item.text, item.truncate - 1) + "\u2026" : item.text;
2403
+ displayLines = [item.dim ? safeColors.muted(stripAnsi(truncated)) : truncated];
2322
2404
  } else {
2323
2405
  const wrapped = wrapText(item.text, itemMaxWidth);
2324
2406
  displayLines = item.dim ? wrapped.map((l) => safeColors.muted(l)) : wrapped;
2325
2407
  }
2326
2408
  for (const dl of displayLines) {
2327
- lines.push(`${safeSymbols.border} ${dl}`);
2409
+ lines.push(`${safeColors.muted("\u2502")} ${dl}`);
2328
2410
  }
2329
2411
  }
2330
2412
  if (i < sections.length - 1) {
2331
- lines.push(safeSymbols.border);
2413
+ lines.push(safeColors.muted("\u2502"));
2332
2414
  }
2333
2415
  }
2334
2416
  if (footer || status || timing !== void 0) {
2335
- lines.push(safeSymbols.border);
2417
+ if (lines[lines.length - 1] !== safeColors.muted("\u2502")) {
2418
+ lines.push(safeColors.muted("\u2502"));
2419
+ }
2336
2420
  const footerParts = [];
2337
2421
  if (footer) {
2338
2422
  footerParts.push(footer);
2339
2423
  } else if (status) {
2340
2424
  const statusSymbol = getStatusSymbol(status);
2341
- const statusText = getStatusText(status);
2342
2425
  const statusColor = getStatusColor(status);
2343
- footerParts.push(statusColor(`${statusSymbol} ${statusText}`));
2426
+ footerParts.push(statusColor(`${statusSymbol}`));
2344
2427
  }
2345
2428
  if (timing !== void 0) {
2346
- footerParts.push(formatTiming2(timing));
2429
+ footerParts.push(safeColors.muted(formatTiming2(timing)));
2347
2430
  }
2348
- const footerLine = `${safeSymbols.bottomLeft}${safeSymbols.separator.repeat(2)} ${footerParts.join(" / ")}`;
2431
+ const footerLine = `${safeColors.muted("\u2514")} ${footerParts.join(" ")}`;
2349
2432
  lines.push(footerLine);
2350
2433
  }
2351
2434
  return lines.join("\n");
2352
2435
  }
2353
- function sectionHeader(text) {
2354
- return safeColors.bold(text);
2436
+ function sectionHeader(text2) {
2437
+ return safeColors.bold(text2);
2355
2438
  }
2356
2439
  function metricsList(metrics) {
2357
2440
  const entries = Object.entries(metrics);
@@ -2373,13 +2456,35 @@ var bulletList2 = bulletList;
2373
2456
  var formatTiming2 = formatTiming;
2374
2457
  function statusLine(status, timing) {
2375
2458
  const symbol = getStatusSymbol(status);
2376
- const text = getStatusText(status);
2377
2459
  const color = getStatusColor(status);
2378
- const parts = [color(`${symbol} ${text}`)];
2460
+ const parts = [color(symbol)];
2379
2461
  if (timing !== void 0) {
2380
- parts.push(formatTiming2(timing));
2462
+ parts.push(safeColors.muted(formatTiming2(timing)));
2463
+ }
2464
+ return parts.join(" ");
2465
+ }
2466
+ function ansiSlice(str, maxVisible) {
2467
+ let visible = 0;
2468
+ let i = 0;
2469
+ let result = "";
2470
+ while (i < str.length) {
2471
+ if (str[i] === "\x1B" && str[i + 1] === "[") {
2472
+ let j = i + 2;
2473
+ while (j < str.length && !/[A-Za-z]/.test(str[j])) {
2474
+ j++;
2475
+ }
2476
+ result += str.slice(i, j + 1);
2477
+ i = j + 1;
2478
+ } else {
2479
+ if (visible >= maxVisible) {
2480
+ break;
2481
+ }
2482
+ result += str[i];
2483
+ visible++;
2484
+ i++;
2485
+ }
2381
2486
  }
2382
- return parts.join(" / ");
2487
+ return result;
2383
2488
  }
2384
2489
  function getStatusSymbol(status) {
2385
2490
  switch (status) {
@@ -2393,18 +2498,6 @@ function getStatusSymbol(status) {
2393
2498
  return safeSymbols.info;
2394
2499
  }
2395
2500
  }
2396
- function getStatusText(status) {
2397
- switch (status) {
2398
- case "success":
2399
- return "Success";
2400
- case "error":
2401
- return "Failed";
2402
- case "warning":
2403
- return "Warning";
2404
- case "info":
2405
- return "Info";
2406
- }
2407
- }
2408
2501
  function getStatusColor(status) {
2409
2502
  switch (status) {
2410
2503
  case "success":
@@ -2417,9 +2510,9 @@ function getStatusColor(status) {
2417
2510
  return safeColors.info;
2418
2511
  }
2419
2512
  }
2420
- function wrapText(text, maxWidth) {
2513
+ function wrapText(text2, maxWidth) {
2421
2514
  const result = [];
2422
- const rawLines = text.split("\n");
2515
+ const rawLines = text2.split("\n");
2423
2516
  for (const rawLine of rawLines) {
2424
2517
  const line = rawLine.trimEnd();
2425
2518
  if (stripAnsi(line).length <= maxWidth) {
@@ -2451,6 +2544,80 @@ function wrapText(text, maxWidth) {
2451
2544
  }
2452
2545
  return result.length > 0 ? result : [""];
2453
2546
  }
2547
+ function sideBorderChain(items) {
2548
+ if (items.length === 0) {
2549
+ return "";
2550
+ }
2551
+ if (items.length === 1) {
2552
+ const item = items[0];
2553
+ return sideBorderBox({ title: item.title, sections: item.sections, status: item.status, timing: item.timing });
2554
+ }
2555
+ const lines = [];
2556
+ const terminalWidth = typeof process !== "undefined" && process.stdout?.columns ? process.stdout.columns : 80;
2557
+ const itemMaxWidth = Math.max(40, terminalWidth - 4);
2558
+ for (let blockIdx = 0; blockIdx < items.length; blockIdx++) {
2559
+ const block = items[blockIdx];
2560
+ const isLast = blockIdx === items.length - 1;
2561
+ lines.push(`${safeColors.primary("\u25C6")} ${safeColors.bold(block.title)}`);
2562
+ lines.push(safeColors.muted("\u2502"));
2563
+ if (block.summary && Object.keys(block.summary).length > 0) {
2564
+ const entries = Object.entries(block.summary).map(([k, v]) => [k, String(v)]);
2565
+ const metricsRecord = Object.fromEntries(entries);
2566
+ const metricsLines = metricsList(metricsRecord);
2567
+ for (const line of metricsLines) {
2568
+ lines.push(`${safeColors.muted("\u2502")} ${line}`);
2569
+ }
2570
+ if (block.sections.length > 0) {
2571
+ lines.push(safeColors.muted("\u2502"));
2572
+ }
2573
+ }
2574
+ for (let i = 0; i < block.sections.length; i++) {
2575
+ const section2 = block.sections[i];
2576
+ if (!section2) {
2577
+ continue;
2578
+ }
2579
+ if (section2.header) {
2580
+ lines.push(`${safeColors.muted("\u2502")} ${safeColors.bold(section2.header)}`);
2581
+ }
2582
+ for (const rawItem of section2.items) {
2583
+ const item = typeof rawItem === "string" ? { text: rawItem } : rawItem;
2584
+ let displayLines;
2585
+ if (item.truncate !== void 0) {
2586
+ const vis = stripAnsi(item.text);
2587
+ const truncated = vis.length > item.truncate ? ansiSlice(item.text, item.truncate - 1) + "\u2026" : item.text;
2588
+ displayLines = [item.dim ? safeColors.muted(stripAnsi(truncated)) : truncated];
2589
+ } else {
2590
+ const wrapped = wrapText(item.text, itemMaxWidth);
2591
+ displayLines = item.dim ? wrapped.map((l) => safeColors.muted(l)) : wrapped;
2592
+ }
2593
+ for (const dl of displayLines) {
2594
+ lines.push(`${safeColors.muted("\u2502")} ${dl}`);
2595
+ }
2596
+ }
2597
+ if (i < block.sections.length - 1) {
2598
+ lines.push(safeColors.muted("\u2502"));
2599
+ }
2600
+ }
2601
+ if (isLast) {
2602
+ if (block.status || block.timing !== void 0) {
2603
+ lines.push(safeColors.muted("\u2502"));
2604
+ const footerParts = [];
2605
+ if (block.status) {
2606
+ footerParts.push(getStatusColor(block.status)(getStatusSymbol(block.status)));
2607
+ }
2608
+ if (block.timing !== void 0) {
2609
+ footerParts.push(safeColors.muted(formatTiming2(block.timing)));
2610
+ }
2611
+ lines.push(`${safeColors.muted("\u2514")} ${footerParts.join(" ")}`);
2612
+ }
2613
+ } else {
2614
+ if (lines[lines.length - 1] !== safeColors.muted("\u2502")) {
2615
+ lines.push(safeColors.muted("\u2502"));
2616
+ }
2617
+ }
2618
+ }
2619
+ return lines.join("\n");
2620
+ }
2454
2621
  function formatError(err, opts) {
2455
2622
  const raw = err instanceof Error ? err.message : String(err);
2456
2623
  const allLines = raw.split("\n").map((l) => l.trimEnd()).filter((l) => l.length > 0);
@@ -2617,6 +2784,601 @@ function infoResult(title, data) {
2617
2784
  });
2618
2785
  }
2619
2786
 
2620
- export { DebugOutput, DebugSection, DebugTrace, DebugTree, DynamicCommandDiscovery, Loader, MultiCLISuggestions, StaticCommandDiscovery, TimingTracker, accentLabel, box, bulletList, colors, createCommandDiscovery, createCommandRegistry, createCommandRunner, createDebugTree, createDetailedResult, createKBLabsCommandDiscovery, createProgressBar, createSimpleResult, createSpinner, defineEnv, defineFlags, describeEntriesAI, describeEntriesHuman, describeEntriesTimeline, discoverArtifacts, displayArtifacts, displayArtifactsCompact, displaySingleArtifact, errorResult, exportDebugEntries, exportToChromeFormat, exportToJSON, exportToPlainText, extractCommandGroups, extractCommandIds, filterByLevel, filterByNamespace, filterByTimeRange, filterDebugEntries, findCommandById, findCommandsByGroup, formatCommandHelp, formatCommandOutput, formatCommandResult, formatDebugEntriesAI, formatDebugEntriesHuman, formatDebugEntryAI, formatDebugEntryHuman, formatDebugOutput, formatDebugOutputs, formatError, formatKeyValueTable, formatRelativeTime, formatSize, formatTable, formatTimeline, formatTimelineNode, formatTimelineWithSummary, formatTimestamp, formatTiming, formatTimingBreakdown, generateDevlinkSuggestions, generateGroupSuggestions, generateQuickActions, getCommandInfo, getContextCwd, groupByGroup, groupByNamespace, hasAnsi, headline, indent, infoResult, isCommandAvailable, isJsonMode, keyValue, mergeFlags, metricsList, muted, pad, parseBoolean, parseEnvFromRuntime, parseFlagsFromInput, parseNumber, parseNumberFlag, parseString, safeColors, safeKeyValue, safeSymbols, searchInLogs, section, sectionHeader, setJsonMode, shouldUseAIFormat, showError, showLoading, showSuccess, sideBorderBox, statusLine, stripAnsi, successResult, supportsColor, symbols, table, toPosixPath, truncate, useLoader, validateSuggestions, warningResult, withRetry };
2787
+ // src/log-display.ts
2788
+ var LEVEL_CONFIG = {
2789
+ info: { symbol: "\u25C6", label: "INFO ", color: safeColors.info },
2790
+ warn: { symbol: "\u26A0", label: "WARN ", color: safeColors.warning },
2791
+ error: { symbol: "\u2717", label: "ERROR", color: safeColors.error },
2792
+ debug: { symbol: "\u25CB", label: "DEBUG", color: safeColors.muted },
2793
+ verbose: { symbol: "\xB7", label: "VERB ", color: safeColors.muted }
2794
+ };
2795
+ function timestamp() {
2796
+ const now = /* @__PURE__ */ new Date();
2797
+ const h = String(now.getHours()).padStart(2, "0");
2798
+ const m = String(now.getMinutes()).padStart(2, "0");
2799
+ const s = String(now.getSeconds()).padStart(2, "0");
2800
+ return `${h}:${m}:${s}`;
2801
+ }
2802
+ function logLine(level, message) {
2803
+ const cfg = LEVEL_CONFIG[level];
2804
+ const sym = cfg.color(cfg.symbol);
2805
+ const lbl = safeColors.muted(cfg.label);
2806
+ const ts = safeColors.muted(timestamp());
2807
+ return ` ${sym} ${lbl} ${ts} ${message}`;
2808
+ }
2809
+ function logGroup(title, lines) {
2810
+ const header = ` ${safeColors.bold(title)}`;
2811
+ const body = lines.map((l) => ` ${l}`).join("\n");
2812
+ return body ? `${header}
2813
+ ${body}` : header;
2814
+ }
2815
+ function printLog(level, message) {
2816
+ process.stdout.write(logLine(level, message) + "\n");
2817
+ }
2818
+
2819
+ // src/badge.ts
2820
+ var BADGE_COLORS = {
2821
+ success: safeColors.success,
2822
+ error: safeColors.error,
2823
+ warning: safeColors.warning,
2824
+ info: safeColors.info,
2825
+ neutral: safeColors.muted
2826
+ };
2827
+ function badge(label, variant = "neutral") {
2828
+ const colorFn = BADGE_COLORS[variant];
2829
+ return colorFn(`[${label.toUpperCase()}]`);
2830
+ }
2831
+ function statusBadge(status) {
2832
+ const s = status.toLowerCase();
2833
+ if (s === "online" || s === "running" || s === "success" || s === "active" || s === "done") {
2834
+ return badge(status, "success");
2835
+ }
2836
+ if (s === "offline" || s === "failed" || s === "error" || s === "stopped") {
2837
+ return badge(status, "error");
2838
+ }
2839
+ if (s === "degraded" || s === "warning" || s === "reconnecting" || s === "pending") {
2840
+ return badge(status, "warning");
2841
+ }
2842
+ if (s === "starting" || s === "initializing") {
2843
+ return badge(status, "info");
2844
+ }
2845
+ return badge(status, "neutral");
2846
+ }
2847
+ function isInteractive() {
2848
+ return Boolean(
2849
+ process.stdin.isTTY && process.stdout.isTTY && !process.env.CI && !process.env.NO_INTERACTIVE
2850
+ );
2851
+ }
2852
+ function enableRawMode() {
2853
+ if (process.stdin.isTTY) {
2854
+ process.stdin.setRawMode(true);
2855
+ }
2856
+ }
2857
+ function disableRawMode() {
2858
+ if (process.stdin.isTTY) {
2859
+ process.stdin.setRawMode(false);
2860
+ }
2861
+ }
2862
+ function clearLine() {
2863
+ process.stdout.write("\r\x1B[K");
2864
+ }
2865
+ function clearLines(n) {
2866
+ for (let i = 0; i < n; i++) {
2867
+ if (i > 0) {
2868
+ process.stdout.write("\x1B[1A");
2869
+ }
2870
+ clearLine();
2871
+ }
2872
+ }
2873
+ function hideCursor() {
2874
+ process.stdout.write("\x1B[?25l");
2875
+ }
2876
+ function showCursor() {
2877
+ process.stdout.write("\x1B[?25h");
2878
+ }
2879
+ function onKeypress(handler) {
2880
+ readline.emitKeypressEvents(process.stdin);
2881
+ const listener = (_, key) => {
2882
+ if (key) {
2883
+ handler(key);
2884
+ }
2885
+ };
2886
+ process.stdin.on("keypress", listener);
2887
+ process.stdin.resume();
2888
+ return () => {
2889
+ process.stdin.off("keypress", listener);
2890
+ if (process.stdin.listenerCount("keypress") === 0) {
2891
+ process.stdin.pause();
2892
+ }
2893
+ };
2894
+ }
2895
+ function isUpKey(key) {
2896
+ return key.name === "up" || key.name === "k" && !key.ctrl;
2897
+ }
2898
+ function isDownKey(key) {
2899
+ return key.name === "down" || key.name === "j" && !key.ctrl;
2900
+ }
2901
+ function isEnterKey(key) {
2902
+ return key.name === "return" || key.name === "enter";
2903
+ }
2904
+ function isEscapeKey(key) {
2905
+ return key.name === "escape" || key.name === "c" && key.ctrl || key.name === "q" && !key.ctrl;
2906
+ }
2907
+ function isSpaceKey(key) {
2908
+ return key.name === "space";
2909
+ }
2910
+
2911
+ // src/tasks.ts
2912
+ var SPINNER_FRAMES = ["\u25D0", "\u25D3", "\u25D1", "\u25D2"];
2913
+ function renderTasks(statuses, spinnerFrame) {
2914
+ const lines = [];
2915
+ for (const s of statuses) {
2916
+ let prefix;
2917
+ switch (s.state) {
2918
+ case "pending":
2919
+ prefix = safeColors.muted("\u25CB");
2920
+ break;
2921
+ case "running":
2922
+ prefix = safeColors.primary(SPINNER_FRAMES[spinnerFrame % SPINNER_FRAMES.length] ?? "\u25C6");
2923
+ break;
2924
+ case "done":
2925
+ prefix = safeColors.success("\u25CF");
2926
+ break;
2927
+ case "failed":
2928
+ prefix = safeColors.error("\u2717");
2929
+ break;
2930
+ }
2931
+ lines.push(` ${prefix} ${s.state === "done" ? safeColors.muted(s.title) : s.state === "failed" ? safeColors.error(s.title) : s.title}`);
2932
+ if (s.error) {
2933
+ lines.push(` ${safeColors.muted(s.error)}`);
2934
+ }
2935
+ }
2936
+ process.stdout.write(lines.join("\n") + "\n");
2937
+ return lines.length;
2938
+ }
2939
+ async function runTasks(tasks) {
2940
+ const statuses = tasks.map((t) => ({ title: t.title, state: "pending" }));
2941
+ let lineCount = 0;
2942
+ let spinnerFrame = 0;
2943
+ lineCount = renderTasks(statuses, spinnerFrame);
2944
+ let spinnerInterval;
2945
+ for (let i = 0; i < tasks.length; i++) {
2946
+ const task = tasks[i];
2947
+ const status = statuses[i];
2948
+ if (!task || !status) {
2949
+ continue;
2950
+ }
2951
+ status.state = "running";
2952
+ clearLines(lineCount);
2953
+ lineCount = renderTasks(statuses, spinnerFrame);
2954
+ spinnerInterval = setInterval(() => {
2955
+ spinnerFrame++;
2956
+ clearLines(lineCount);
2957
+ lineCount = renderTasks(statuses, spinnerFrame);
2958
+ }, 80);
2959
+ try {
2960
+ await task.run((newTitle) => {
2961
+ status.title = newTitle;
2962
+ });
2963
+ status.state = "done";
2964
+ } catch (err) {
2965
+ status.state = "failed";
2966
+ status.error = err instanceof Error ? err.message : String(err);
2967
+ } finally {
2968
+ clearInterval(spinnerInterval);
2969
+ spinnerInterval = void 0;
2970
+ }
2971
+ }
2972
+ clearLines(lineCount);
2973
+ renderTasks(statuses, 0);
2974
+ process.stdout.write("\n");
2975
+ const failed = statuses.filter((s) => s.state === "failed");
2976
+ if (failed.length > 0) {
2977
+ throw new Error(`${failed.length} task${failed.length === 1 ? "" : "s"} failed`);
2978
+ }
2979
+ }
2980
+ async function confirm(options) {
2981
+ const { message, defaultValue = false } = options;
2982
+ if (!isInteractive()) {
2983
+ return defaultValue;
2984
+ }
2985
+ const hint = defaultValue ? "(Y/n)" : "(y/N)";
2986
+ process.stdout.write(`${safeColors.primary("\u25C6")} ${safeColors.bold(message)} ${safeColors.muted(hint)} `);
2987
+ return new Promise((resolve) => {
2988
+ const rl = readline.createInterface({ input: process.stdin, output: void 0 });
2989
+ rl.once("line", (line) => {
2990
+ rl.close();
2991
+ const trimmed = line.trim().toLowerCase();
2992
+ process.stdout.write("\n");
2993
+ if (trimmed === "") {
2994
+ resolve(defaultValue);
2995
+ } else {
2996
+ resolve(trimmed === "y" || trimmed === "yes");
2997
+ }
2998
+ });
2999
+ rl.once("close", () => {
3000
+ resolve(defaultValue);
3001
+ });
3002
+ });
3003
+ }
3004
+ async function text(options) {
3005
+ const { message, placeholder, defaultValue = "", validate, mask = false } = options;
3006
+ if (!isInteractive()) {
3007
+ return defaultValue;
3008
+ }
3009
+ const hint = placeholder ? safeColors.muted(` (${placeholder})`) : "";
3010
+ process.stdout.write(`${safeColors.primary("\u25C6")} ${safeColors.bold(message)}${hint}
3011
+ `);
3012
+ process.stdout.write(`${safeColors.muted("\u2502")} `);
3013
+ return new Promise((resolve) => {
3014
+ const rl = readline.createInterface({
3015
+ input: process.stdin,
3016
+ output: mask ? void 0 : process.stdout,
3017
+ terminal: !mask
3018
+ });
3019
+ if (mask) {
3020
+ process.stdin.on("data", (char) => {
3021
+ const c = char.toString();
3022
+ if (c === "\n" || c === "\r") {
3023
+ return;
3024
+ }
3025
+ process.stdout.write("*");
3026
+ });
3027
+ }
3028
+ rl.once("line", (line) => {
3029
+ rl.close();
3030
+ const value = line.trim() || defaultValue;
3031
+ if (validate) {
3032
+ const error = validate(value);
3033
+ if (error) {
3034
+ process.stdout.write(`${safeColors.error("\u2717")} ${safeColors.error(error)}
3035
+ `);
3036
+ resolve(text(options));
3037
+ return;
3038
+ }
3039
+ }
3040
+ process.stdout.write(`${safeColors.muted("\u2514")}
3041
+ `);
3042
+ resolve(value);
3043
+ });
3044
+ rl.once("close", () => {
3045
+ resolve(defaultValue);
3046
+ });
3047
+ });
3048
+ }
3049
+
3050
+ // src/interactive/select.ts
3051
+ function renderSelect(message, choices, activeIndex, isFirst) {
3052
+ const lines = [];
3053
+ if (isFirst) {
3054
+ lines.push(`${safeColors.primary("\u25C6")} ${safeColors.bold(message)}`);
3055
+ lines.push(safeColors.muted("\u2502"));
3056
+ }
3057
+ for (let i = 0; i < choices.length; i++) {
3058
+ const choice = choices[i];
3059
+ if (!choice) {
3060
+ continue;
3061
+ }
3062
+ const isActive = i === activeIndex;
3063
+ const pointer = isActive ? safeColors.primary("\u276F") : " ";
3064
+ const label = isActive ? safeColors.bold(choice.label) : safeColors.muted(choice.label);
3065
+ const hint = choice.hint ? safeColors.muted(` \u2014 ${choice.hint}`) : "";
3066
+ lines.push(`${safeColors.muted("\u2502")} ${pointer} ${label}${hint}`);
3067
+ }
3068
+ lines.push(safeColors.muted("\u2502"));
3069
+ process.stdout.write(lines.join("\n") + "\n");
3070
+ return lines.length;
3071
+ }
3072
+ async function select(options) {
3073
+ const { message, choices, initialIndex = 0 } = options;
3074
+ if (!isInteractive() || choices.length === 0) {
3075
+ return choices[Math.min(initialIndex, choices.length - 1)].value;
3076
+ }
3077
+ let activeIndex = Math.min(initialIndex, choices.length - 1);
3078
+ let lineCount = 0;
3079
+ hideCursor();
3080
+ enableRawMode();
3081
+ lineCount = renderSelect(message, choices, activeIndex, true);
3082
+ return new Promise((resolve) => {
3083
+ const unsubscribe = onKeypress((key) => {
3084
+ if (isUpKey(key)) {
3085
+ activeIndex = (activeIndex - 1 + choices.length) % choices.length;
3086
+ clearLines(lineCount);
3087
+ lineCount = renderSelect(message, choices, activeIndex, false);
3088
+ return;
3089
+ }
3090
+ if (isDownKey(key)) {
3091
+ activeIndex = (activeIndex + 1) % choices.length;
3092
+ clearLines(lineCount);
3093
+ lineCount = renderSelect(message, choices, activeIndex, false);
3094
+ return;
3095
+ }
3096
+ if (isEnterKey(key)) {
3097
+ unsubscribe();
3098
+ disableRawMode();
3099
+ showCursor();
3100
+ clearLines(lineCount + 2);
3101
+ const selected = choices[activeIndex];
3102
+ process.stdout.write(`${safeColors.primary("\u25C6")} ${safeColors.bold(message)} ${safeColors.muted(selected.label)}
3103
+ `);
3104
+ process.stdout.write(`${safeColors.muted("\u2514")}
3105
+ `);
3106
+ resolve(selected.value);
3107
+ return;
3108
+ }
3109
+ if (isEscapeKey(key)) {
3110
+ unsubscribe();
3111
+ disableRawMode();
3112
+ showCursor();
3113
+ clearLines(lineCount + 2);
3114
+ process.stdout.write(`${safeColors.muted("\u25C6")} ${safeColors.muted(message)} ${safeColors.muted("cancelled")}
3115
+ `);
3116
+ process.stdout.write(`${safeColors.muted("\u2514")}
3117
+ `);
3118
+ resolve(choices[initialIndex].value);
3119
+ return;
3120
+ }
3121
+ });
3122
+ });
3123
+ }
3124
+
3125
+ // src/interactive/multi-select.ts
3126
+ function renderMultiSelect(message, choices, checked, activeIndex, isFirst, error) {
3127
+ const lines = [];
3128
+ if (isFirst) {
3129
+ lines.push(`${safeColors.primary("\u25C6")} ${safeColors.bold(message)} ${safeColors.muted("Space to toggle, Enter to confirm")}`);
3130
+ lines.push(safeColors.muted("\u2502"));
3131
+ }
3132
+ for (let i = 0; i < choices.length; i++) {
3133
+ const choice = choices[i];
3134
+ if (!choice) {
3135
+ continue;
3136
+ }
3137
+ const isActive = i === activeIndex;
3138
+ const isChecked = checked.has(i);
3139
+ const checkbox = isChecked ? safeColors.success("\u25C9") : safeColors.muted("\u25CB");
3140
+ const pointer = isActive ? safeColors.primary("\u276F") : " ";
3141
+ const label = isActive ? safeColors.bold(choice.label) : isChecked ? choice.label : safeColors.muted(choice.label);
3142
+ const hint = choice.hint ? safeColors.muted(` \u2014 ${choice.hint}`) : "";
3143
+ lines.push(`${safeColors.muted("\u2502")} ${pointer} ${checkbox} ${label}${hint}`);
3144
+ }
3145
+ if (error) {
3146
+ lines.push(`${safeColors.muted("\u2502")}`);
3147
+ lines.push(`${safeColors.muted("\u2502")} ${safeColors.error("\u2717")} ${safeColors.error(error)}`);
3148
+ }
3149
+ lines.push(safeColors.muted("\u2502"));
3150
+ process.stdout.write(lines.join("\n") + "\n");
3151
+ return lines.length;
3152
+ }
3153
+ async function multiSelect(options) {
3154
+ const { message, choices, min } = options;
3155
+ if (!isInteractive() || choices.length === 0) {
3156
+ return choices.filter((c) => c.checked).map((c) => c.value);
3157
+ }
3158
+ let activeIndex = 0;
3159
+ const checked = new Set(
3160
+ choices.map((c, i) => c.checked ? i : -1).filter((i) => i >= 0)
3161
+ );
3162
+ let lineCount = 0;
3163
+ let error;
3164
+ hideCursor();
3165
+ enableRawMode();
3166
+ lineCount = renderMultiSelect(message, choices, checked, activeIndex, true, error);
3167
+ return new Promise((resolve) => {
3168
+ const unsubscribe = onKeypress((key) => {
3169
+ if (isUpKey(key)) {
3170
+ activeIndex = (activeIndex - 1 + choices.length) % choices.length;
3171
+ clearLines(lineCount);
3172
+ lineCount = renderMultiSelect(message, choices, checked, activeIndex, false, error);
3173
+ return;
3174
+ }
3175
+ if (isDownKey(key)) {
3176
+ activeIndex = (activeIndex + 1) % choices.length;
3177
+ clearLines(lineCount);
3178
+ lineCount = renderMultiSelect(message, choices, checked, activeIndex, false, error);
3179
+ return;
3180
+ }
3181
+ if (isSpaceKey(key)) {
3182
+ if (checked.has(activeIndex)) {
3183
+ checked.delete(activeIndex);
3184
+ } else {
3185
+ checked.add(activeIndex);
3186
+ }
3187
+ error = void 0;
3188
+ clearLines(lineCount);
3189
+ lineCount = renderMultiSelect(message, choices, checked, activeIndex, false, error);
3190
+ return;
3191
+ }
3192
+ if (key.name === "a" && !key.ctrl) {
3193
+ if (checked.size === choices.length) {
3194
+ checked.clear();
3195
+ } else {
3196
+ choices.forEach((_, i) => checked.add(i));
3197
+ }
3198
+ clearLines(lineCount);
3199
+ lineCount = renderMultiSelect(message, choices, checked, activeIndex, false, error);
3200
+ return;
3201
+ }
3202
+ if (isEnterKey(key)) {
3203
+ if (min !== void 0 && checked.size < min) {
3204
+ error = `Select at least ${min} option${min === 1 ? "" : "s"}`;
3205
+ clearLines(lineCount);
3206
+ lineCount = renderMultiSelect(message, choices, checked, activeIndex, false, error);
3207
+ return;
3208
+ }
3209
+ unsubscribe();
3210
+ disableRawMode();
3211
+ showCursor();
3212
+ const headerLines = 2;
3213
+ clearLines(lineCount + headerLines);
3214
+ const selectedLabels = choices.filter((_, i) => checked.has(i)).map((c) => c.label).join(", ");
3215
+ process.stdout.write(`${safeColors.primary("\u25C6")} ${safeColors.bold(message)} ${safeColors.muted(selectedLabels || "none")}
3216
+ `);
3217
+ process.stdout.write(`${safeColors.muted("\u2514")}
3218
+ `);
3219
+ resolve(choices.filter((_, i) => checked.has(i)).map((c) => c.value));
3220
+ return;
3221
+ }
3222
+ if (isEscapeKey(key)) {
3223
+ unsubscribe();
3224
+ disableRawMode();
3225
+ showCursor();
3226
+ clearLines(lineCount + 2);
3227
+ process.stdout.write(`${safeColors.muted("\u25C6")} ${safeColors.muted(message)} ${safeColors.muted("cancelled")}
3228
+ `);
3229
+ process.stdout.write(`${safeColors.muted("\u2514")}
3230
+ `);
3231
+ resolve([]);
3232
+ return;
3233
+ }
3234
+ });
3235
+ });
3236
+ }
3237
+
3238
+ // src/stdout-ui.ts
3239
+ var NOOP_PROMPTS = {
3240
+ confirm: async (_, opts) => opts?.defaultValue ?? false,
3241
+ prompt: async (_, opts) => opts?.default ?? "",
3242
+ select: async (_, choices) => choices[0]?.value,
3243
+ multiSelect: async (_, choices) => choices.filter((c) => c.checked).map((c) => c.value)
3244
+ };
3245
+ function createBaseStdoutUI(prompts, log) {
3246
+ return {
3247
+ colors: safeColors,
3248
+ symbols: safeSymbols,
3249
+ write: (text2) => {
3250
+ process.stdout.write(text2 + "\n");
3251
+ },
3252
+ info: (msg, options) => {
3253
+ const extra = options?.sections ?? [];
3254
+ console.log(sideBorderBox({
3255
+ title: options?.title ?? "Info",
3256
+ sections: [{ items: [msg] }, ...extra],
3257
+ status: "info",
3258
+ timing: options?.timing,
3259
+ summary: options?.summary
3260
+ }));
3261
+ },
3262
+ success: (msg, options) => {
3263
+ const extra = options?.sections ?? [];
3264
+ console.log(sideBorderBox({
3265
+ title: options?.title ?? "Success",
3266
+ sections: [{ items: [msg] }, ...extra],
3267
+ status: "success",
3268
+ timing: options?.timing,
3269
+ summary: options?.summary
3270
+ }));
3271
+ },
3272
+ warn: (msg, options) => {
3273
+ const extra = options?.sections ?? [];
3274
+ console.log(sideBorderBox({
3275
+ title: options?.title ?? "Warning",
3276
+ sections: [{ items: [msg] }, ...extra],
3277
+ status: "warning",
3278
+ timing: options?.timing,
3279
+ summary: options?.summary
3280
+ }));
3281
+ },
3282
+ error: (err, options) => {
3283
+ const message = err instanceof Error ? err.message : err;
3284
+ const sections = [
3285
+ { items: [message] }
3286
+ ];
3287
+ if (options?.sections?.length) {
3288
+ sections.push(...options.sections.map((s) => ({ header: s.header, items: s.items })));
3289
+ }
3290
+ if (options?.cause) {
3291
+ sections.push({ header: "Cause", items: [{ text: options.cause, dim: true }] });
3292
+ }
3293
+ if (options?.hint) {
3294
+ const hintItems = [options.hint];
3295
+ if (options.command) {
3296
+ hintItems.push({ text: `$ ${options.command}`, dim: true });
3297
+ }
3298
+ sections.push({ header: "Hint", items: hintItems });
3299
+ } else if (options?.command) {
3300
+ sections.push({ header: "Hint", items: [{ text: `$ ${options.command}`, dim: true }] });
3301
+ }
3302
+ console.error(sideBorderBox({
3303
+ title: options?.title ?? "Error",
3304
+ sections,
3305
+ status: "error",
3306
+ timing: options?.timing,
3307
+ summary: options?.summary
3308
+ }));
3309
+ },
3310
+ debug: (msg) => {
3311
+ if (process.env.DEBUG) {
3312
+ console.debug(msg);
3313
+ }
3314
+ },
3315
+ spinner: (msg) => {
3316
+ console.log(`${safeColors.primary("\u25C6")} ${msg}`);
3317
+ return {
3318
+ update: (m) => console.log(`${safeColors.primary("\u25C6")} ${m}`),
3319
+ succeed: (m) => console.log(`${safeColors.success("\u2713")} ${m ?? msg}`),
3320
+ fail: (m) => console.log(`${safeColors.error("\u2717")} ${m ?? msg}`),
3321
+ stop: () => {
3322
+ }
3323
+ };
3324
+ },
3325
+ table: (data, columns) => {
3326
+ if (data.length === 0) {
3327
+ return;
3328
+ }
3329
+ const cols = columns ?? Object.keys(data[0]).map((k) => ({ header: k, key: k }));
3330
+ const rows = data.map((row) => cols.map((col) => String(row[col.key] ?? "")));
3331
+ const lines = formatTable(
3332
+ cols.map((c) => ({ header: c.header, width: c.width, align: c.align })),
3333
+ rows,
3334
+ { separator: "" }
3335
+ );
3336
+ for (const line of lines) {
3337
+ console.log(` ${line}`);
3338
+ }
3339
+ },
3340
+ json: (data, options) => console.log(options?.pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data)),
3341
+ newline: () => console.log(),
3342
+ divider: () => console.log(safeColors.muted("\u2500".repeat(process.stdout.columns || 80))),
3343
+ box: (content, title) => {
3344
+ console.log(sideBorderBox({
3345
+ title: title || "",
3346
+ sections: [{ items: content.split("\n") }],
3347
+ status: "info"
3348
+ }));
3349
+ },
3350
+ sideBox: (options) => {
3351
+ const allSections = [];
3352
+ if (options.summary && Object.keys(options.summary).length > 0) {
3353
+ allSections.push({ items: metricsList(options.summary) });
3354
+ }
3355
+ allSections.push(...(options.sections ?? []).map((s) => ({ header: s.header, items: s.items })));
3356
+ console.log(sideBorderBox({
3357
+ title: options.title,
3358
+ sections: allSections,
3359
+ status: options.status,
3360
+ timing: options.timing
3361
+ }));
3362
+ },
3363
+ chain: (items) => {
3364
+ console.log(sideBorderChain(
3365
+ items.map((item) => ({
3366
+ title: item.title,
3367
+ sections: (item.sections ?? []).map((s) => ({ header: s.header, items: s.items })),
3368
+ summary: item.summary,
3369
+ status: item.status,
3370
+ timing: item.timing
3371
+ }))
3372
+ ));
3373
+ },
3374
+ confirm: prompts.confirm,
3375
+ prompt: prompts.prompt,
3376
+ select: prompts.select,
3377
+ multiSelect: prompts.multiSelect,
3378
+ log
3379
+ };
3380
+ }
3381
+
3382
+ export { DebugOutput, DebugSection, DebugTrace, DebugTree, DynamicCommandDiscovery, Loader, MultiCLISuggestions, NOOP_PROMPTS, StaticCommandDiscovery, TimingTracker, accentLabel, badge, box, buildConfirmationSignal, bulletList, colors, confirm, confirmDestructive, createBaseStdoutUI, createCommandDiscovery, createCommandRegistry, createCommandRunner, createDebugTree, createDetailedResult, createKBLabsCommandDiscovery, createProgressBar, createSimpleResult, createSpinner, defineEnv, defineFlags, describeEntriesAI, describeEntriesHuman, describeEntriesTimeline, discoverArtifacts, displayArtifacts, displayArtifactsCompact, displaySingleArtifact, errorResult, exportDebugEntries, exportToChromeFormat, exportToJSON, exportToPlainText, extractCommandGroups, extractCommandIds, filterByLevel, filterByNamespace, filterByTimeRange, filterDebugEntries, findCommandById, findCommandsByGroup, formatCommandHelp, formatCommandOutput, formatCommandResult, formatDebugEntriesAI, formatDebugEntriesHuman, formatDebugEntryAI, formatDebugEntryHuman, formatDebugOutput, formatDebugOutputs, formatError, formatKeyValueTable, formatRelativeTime, formatSize, formatTable, formatTimeline, formatTimelineNode, formatTimelineWithSummary, formatTimestamp, formatTiming, formatTimingBreakdown, generateDevlinkSuggestions, generateGroupSuggestions, generateQuickActions, getCommandInfo, getContextCwd, groupByGroup, groupByNamespace, handleError, hasAnsi, headline, indent, infoResult, isCommandAvailable, isInteractive, isJsonMode, keyValue, logGroup, logLine, mergeFlags, metricsList, multiSelect, muted, pad, parseBoolean, parseEnvFromRuntime, parseFlagsFromInput, parseNumber, parseNumberFlag, parseString, printLog, renderDestructiveMessage, rethrowForRest, runTasks, safeColors, safeKeyValue, safeSymbols, searchInLogs, section, sectionHeader, select, setJsonMode, shouldUseAIFormat, showError, showLoading, showSuccess, sideBorderBox, sideBorderChain, statusBadge, statusLine, stripAnsi, successResult, supportsColor, symbols, table, text, toPosixPath, truncate, useLoader, validateSuggestions, validationError, warningResult, withRetry };
2621
3383
  //# sourceMappingURL=index.js.map
2622
3384
  //# sourceMappingURL=index.js.map