@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.cjs CHANGED
@@ -2,15 +2,35 @@
2
2
 
3
3
  var path = require('path');
4
4
  var fs = require('fs');
5
+ var readline = require('readline');
5
6
 
6
7
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
8
 
9
+ function _interopNamespace(e) {
10
+ if (e && e.__esModule) return e;
11
+ var n = Object.create(null);
12
+ if (e) {
13
+ Object.keys(e).forEach(function (k) {
14
+ if (k !== 'default') {
15
+ var d = Object.getOwnPropertyDescriptor(e, k);
16
+ Object.defineProperty(n, k, d.get ? d : {
17
+ enumerable: true,
18
+ get: function () { return e[k]; }
19
+ });
20
+ }
21
+ });
22
+ }
23
+ n.default = e;
24
+ return Object.freeze(n);
25
+ }
26
+
8
27
  var path__default = /*#__PURE__*/_interopDefault(path);
28
+ var readline__namespace = /*#__PURE__*/_interopNamespace(readline);
9
29
 
10
30
  // src/colors.ts
11
31
  var CSI = "\x1B[";
12
32
  var RESET = "\x1B[0m";
13
- var createColor = (...codes) => (text) => `${CSI}${codes.join(";")}m${text}${RESET}`;
33
+ var createColor = (...codes) => (text2) => `${CSI}${codes.join(";")}m${text2}${RESET}`;
14
34
  var accentBlue = "38;5;39";
15
35
  var accentViolet = "38;5;99";
16
36
  var accentTeal = "38;5;51";
@@ -38,16 +58,20 @@ var colors = {
38
58
  inverse: createColor(7)
39
59
  };
40
60
  var symbolCharacters = {
41
- success: "OK",
42
- error: "ERR",
43
- warning: "WARN",
44
- info: "\u2139",
61
+ success: "\u2713",
62
+ error: "\u2717",
63
+ warning: "\u26A0",
64
+ info: "\u25C6",
45
65
  bullet: "\u2022",
46
- clock: "TIME",
47
- folder: "DIR",
48
- package: "\u203A",
49
- pointer: "\u203A",
50
- section: "\u2502"
66
+ clock: "\u25F7",
67
+ folder: "\u25B8",
68
+ package: "\u25C6",
69
+ pointer: "\u276F",
70
+ section: "\u2502",
71
+ step: "\u25CB",
72
+ stepDone: "\u25CF",
73
+ arrow: "\u2192",
74
+ diamond: "\u25C6"
51
75
  };
52
76
  var symbols = {
53
77
  success: colors.success(symbolCharacters.success),
@@ -55,11 +79,15 @@ var symbols = {
55
79
  warning: colors.warning(symbolCharacters.warning),
56
80
  info: colors.info(symbolCharacters.info),
57
81
  bullet: colors.muted(symbolCharacters.bullet),
58
- clock: colors.info(symbolCharacters.clock),
82
+ clock: colors.muted(symbolCharacters.clock),
59
83
  folder: colors.primary(symbolCharacters.folder),
60
84
  package: colors.accent(symbolCharacters.package),
61
85
  pointer: colors.primary(symbolCharacters.pointer),
62
- section: colors.primary(symbolCharacters.section)
86
+ section: colors.muted(symbolCharacters.section),
87
+ step: colors.muted(symbolCharacters.step),
88
+ stepDone: colors.success(symbolCharacters.stepDone),
89
+ arrow: colors.primary(symbolCharacters.arrow),
90
+ diamond: colors.primary(symbolCharacters.diamond)
63
91
  };
64
92
  var isTruthyEnv = (value) => {
65
93
  if (!value) {
@@ -87,7 +115,7 @@ var supportsColor = (() => {
87
115
  }
88
116
  return true;
89
117
  })();
90
- var passthrough = (fn) => (text) => supportsColor ? fn(text) : text;
118
+ var passthrough = (fn) => (text2) => supportsColor ? fn(text2) : text2;
91
119
  var safeColors = {
92
120
  success: passthrough(colors.success),
93
121
  error: passthrough(colors.error),
@@ -109,30 +137,26 @@ var safeSymbols = {
109
137
  success: supportsColor ? symbols.success : "\u2713",
110
138
  error: supportsColor ? symbols.error : "\u2717",
111
139
  warning: supportsColor ? symbols.warning : "\u26A0",
112
- info: supportsColor ? symbols.info : "\u2192",
140
+ info: supportsColor ? symbols.info : "\u25C6",
113
141
  bullet: supportsColor ? symbols.bullet : "\u2022",
114
- clock: supportsColor ? symbols.clock : "time",
115
- folder: supportsColor ? symbols.folder : "dir",
116
- package: supportsColor ? symbols.package : "\u203A",
117
- pointer: supportsColor ? symbols.pointer : ">",
118
- section: supportsColor ? symbols.section : "|",
119
- // Box-drawing characters for modern side border
142
+ clock: supportsColor ? symbols.clock : "\u25F7",
143
+ folder: supportsColor ? symbols.folder : "\u25B8",
144
+ package: supportsColor ? symbols.package : "\u25C6",
145
+ pointer: supportsColor ? symbols.pointer : "\u276F",
146
+ section: supportsColor ? symbols.section : "\u2502",
147
+ step: supportsColor ? symbols.step : "\u25CB",
148
+ stepDone: supportsColor ? symbols.stepDone : "\u25CF",
149
+ arrow: supportsColor ? symbols.arrow : "\u2192",
150
+ diamond: supportsColor ? symbols.diamond : "\u25C6",
151
+ // Box-drawing characters
120
152
  separator: "\u2500",
121
- // Horizontal line
122
153
  border: "\u2502",
123
- // Vertical line
124
154
  topLeft: "\u250C",
125
- // Top-left corner
126
155
  topRight: "\u2510",
127
- // Top-right corner
128
156
  bottomLeft: "\u2514",
129
- // Bottom-left corner
130
157
  bottomRight: "\u2518",
131
- // Bottom-right corner
132
158
  leftT: "\u251C",
133
- // Left T-junction
134
159
  rightT: "\u2524"
135
- // Right T-junction
136
160
  };
137
161
 
138
162
  // src/loader.ts
@@ -187,8 +211,8 @@ var Loader = class {
187
211
  }
188
212
  if (!this.intervalId) {
189
213
  if (this.options.spinner) {
190
- const text = this.options.text ?? "Loading...";
191
- console.log(`${safeSymbols.info} ${text}`);
214
+ const text2 = this.options.text ?? "Loading...";
215
+ console.log(`${safeSymbols.info} ${text2}`);
192
216
  } else if (this.options.total !== void 0) {
193
217
  this.updateProgress();
194
218
  }
@@ -228,33 +252,33 @@ var Loader = class {
228
252
  const barLength = 20;
229
253
  const filledLength = Math.round(current / total * barLength);
230
254
  const bar = "\u2588".repeat(filledLength) + "\u2591".repeat(barLength - filledLength);
231
- const text = this.options.text || "Progress";
232
- process.stdout.write(`\r${safeColors.info("\u2192")} ${text}... ${bar} ${percentage}% (${current}/${total})`);
255
+ const text2 = this.options.text || "Progress";
256
+ process.stdout.write(`\r${safeColors.info("\u2192")} ${text2}... ${bar} ${percentage}% (${current}/${total})`);
233
257
  }
234
258
  };
235
- function createSpinner(text, jsonMode = false) {
236
- return new Loader({ text, spinner: true, jsonMode });
259
+ function createSpinner(text2, jsonMode = false) {
260
+ return new Loader({ text: text2, spinner: true, jsonMode });
237
261
  }
238
- function createProgressBar(text, total, jsonMode = false) {
239
- return new Loader({ text, spinner: false, total, current: 0, jsonMode });
262
+ function createProgressBar(text2, total, jsonMode = false) {
263
+ return new Loader({ text: text2, spinner: false, total, current: 0, jsonMode });
240
264
  }
241
- function showLoading(text, jsonMode = false) {
265
+ function showLoading(text2, jsonMode = false) {
242
266
  if (!jsonMode) {
243
- console.log(`${safeColors.info("\u2192")} ${text}...`);
267
+ console.log(`${safeColors.info("\u2192")} ${text2}...`);
244
268
  }
245
269
  }
246
- function showSuccess(text, jsonMode = false) {
270
+ function showSuccess(text2, jsonMode = false) {
247
271
  if (!jsonMode) {
248
- console.log(`${safeSymbols.success} ${text}`);
272
+ console.log(`${safeSymbols.success} ${text2}`);
249
273
  }
250
274
  }
251
- function showError(text, jsonMode = false) {
275
+ function showError(text2, jsonMode = false) {
252
276
  if (!jsonMode) {
253
- console.log(`${safeSymbols.error} ${text}`);
277
+ console.log(`${safeSymbols.error} ${text2}`);
254
278
  }
255
279
  }
256
- function useLoader(text, options) {
257
- return new Loader({ text, jsonMode: _jsonMode, ...options });
280
+ function useLoader(text2, options) {
281
+ return new Loader({ text: text2, jsonMode: _jsonMode, ...options });
258
282
  }
259
283
 
260
284
  // src/format.ts
@@ -441,14 +465,14 @@ function getDateParts(date, timeZone) {
441
465
  second: lookup.second ?? date.getUTCSeconds()
442
466
  };
443
467
  }
444
- function headline(text) {
445
- return safeColors.primary(safeColors.bold(text));
468
+ function headline(text2) {
469
+ return safeColors.primary(safeColors.bold(text2));
446
470
  }
447
- function accentLabel(text) {
448
- return safeColors.accent(safeColors.bold(text));
471
+ function accentLabel(text2) {
472
+ return safeColors.accent(safeColors.bold(text2));
449
473
  }
450
- function muted(text) {
451
- return safeColors.muted(text);
474
+ function muted(text2) {
475
+ return safeColors.muted(text2);
452
476
  }
453
477
  function formatSize(bytes) {
454
478
  const units = ["B", "KB", "MB", "GB"];
@@ -460,9 +484,9 @@ function formatSize(bytes) {
460
484
  }
461
485
  return `${size.toFixed(unitIndex === 0 ? 0 : 1)} ${units[unitIndex]}`;
462
486
  }
463
- function formatRelativeTime(timestamp) {
487
+ function formatRelativeTime(timestamp2) {
464
488
  const now = /* @__PURE__ */ new Date();
465
- const time = toDate(timestamp);
489
+ const time = toDate(timestamp2);
466
490
  if (!isValidDate(time)) {
467
491
  return "Invalid date";
468
492
  }
@@ -481,7 +505,7 @@ function formatRelativeTime(timestamp) {
481
505
  return `${seconds} second${seconds > 1 ? "s" : ""} ago`;
482
506
  }
483
507
  }
484
- function formatTimestamp(timestamp, options = {}) {
508
+ function formatTimestamp(timestamp2, options = {}) {
485
509
  const {
486
510
  mode = "local",
487
511
  timeZone,
@@ -489,7 +513,7 @@ function formatTimestamp(timestamp, options = {}) {
489
513
  includeMilliseconds = true,
490
514
  includeOffset = true
491
515
  } = options;
492
- const date = toDate(timestamp);
516
+ const date = toDate(timestamp2);
493
517
  if (!isValidDate(date)) {
494
518
  return "Invalid date";
495
519
  }
@@ -507,26 +531,26 @@ function formatTimestamp(timestamp, options = {}) {
507
531
  ].join(" ");
508
532
  return `${base}${offsetSuffix}`;
509
533
  }
510
- function truncate(text, maxLength) {
511
- if (text.length <= maxLength) {
512
- return text;
534
+ function truncate(text2, maxLength) {
535
+ if (text2.length <= maxLength) {
536
+ return text2;
513
537
  }
514
- return text.substring(0, maxLength - 3) + "...";
538
+ return text2.substring(0, maxLength - 3) + "...";
515
539
  }
516
- function pad(text, width, align = "left") {
517
- if (text.length >= width) {
518
- return text;
540
+ function pad(text2, width, align = "left") {
541
+ if (text2.length >= width) {
542
+ return text2;
519
543
  }
520
- const padding = width - text.length;
544
+ const padding = width - text2.length;
521
545
  switch (align) {
522
546
  case "right":
523
- return " ".repeat(padding) + text;
547
+ return " ".repeat(padding) + text2;
524
548
  case "center":
525
549
  const leftPad = Math.floor(padding / 2);
526
550
  const rightPad = padding - leftPad;
527
- return " ".repeat(leftPad) + text + " ".repeat(rightPad);
551
+ return " ".repeat(leftPad) + text2 + " ".repeat(rightPad);
528
552
  default:
529
- return text + " ".repeat(padding);
553
+ return text2 + " ".repeat(padding);
530
554
  }
531
555
  }
532
556
 
@@ -1260,10 +1284,10 @@ async function discoverArtifacts(baseDir, patterns) {
1260
1284
  function visualWidth(str) {
1261
1285
  const ansiRegex = /\x1B\[[0-9;]*[a-zA-Z]/g;
1262
1286
  const cleanStr = str.replace(ansiRegex, "");
1263
- 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;
1264
- const emojiMatches = cleanStr.match(emojiRegex);
1265
- const emojiCount = emojiMatches ? emojiMatches.length : 0;
1266
- return cleanStr.length - emojiCount + emojiCount * 2;
1287
+ 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;
1288
+ const wideMatches = cleanStr.match(doubleWidthRegex);
1289
+ const wideCount = wideMatches ? wideMatches.length : 0;
1290
+ return [...cleanStr].length + wideCount;
1267
1291
  }
1268
1292
  function padVisual(str, width, padChar = " ") {
1269
1293
  const vWidth = visualWidth(str);
@@ -1348,8 +1372,8 @@ function shouldUseAIFormat(format, jsonMode) {
1348
1372
  }
1349
1373
 
1350
1374
  // src/debug/formatters/human.ts
1351
- function formatTimestamp2(timestamp) {
1352
- const date = new Date(timestamp);
1375
+ function formatTimestamp2(timestamp2) {
1376
+ const date = new Date(timestamp2);
1353
1377
  return date.toISOString();
1354
1378
  }
1355
1379
  function formatDuration(duration) {
@@ -2301,63 +2325,141 @@ async function withRetry(fn, options = {}) {
2301
2325
  throw lastError;
2302
2326
  }
2303
2327
 
2328
+ // src/utils/errors.ts
2329
+ function validationError(ctx, message, hint, isJson) {
2330
+ if (isJson) {
2331
+ ctx.ui?.json?.({ ok: false, error: { code: "INVALID_ARGS", message, ...hint && { hint } } });
2332
+ } else {
2333
+ ctx.ui?.error?.(message, { ...hint && { hint } });
2334
+ }
2335
+ }
2336
+ function handleError(ctx, err, isJson) {
2337
+ const message = err instanceof Error ? err.message : String(err);
2338
+ if (isJson) {
2339
+ ctx.ui?.json?.({ ok: false, error: { code: "INTERNAL_ERROR", message } });
2340
+ } else {
2341
+ ctx.ui?.error?.(message);
2342
+ }
2343
+ }
2344
+ function rethrowForRest(err) {
2345
+ if (err !== null && typeof err === "object" && "statusCode" in err) {
2346
+ throw err;
2347
+ }
2348
+ const message = err instanceof Error ? err.message : String(err);
2349
+ throw Object.assign(new Error(message), {
2350
+ statusCode: 500,
2351
+ code: "INTERNAL_ERROR"
2352
+ });
2353
+ }
2354
+
2355
+ // src/destructive.ts
2356
+ function buildConfirmationSignal(a) {
2357
+ return {
2358
+ ok: false,
2359
+ confirmationRequired: true,
2360
+ destructive: true,
2361
+ irreversible: !a.reversible,
2362
+ severity: a.severity,
2363
+ action: a.action,
2364
+ resource: a.resource,
2365
+ effect: a.effect,
2366
+ reversible: a.reversible,
2367
+ ...a.blastRadius && { blastRadius: a.blastRadius },
2368
+ ...a.recovery && { recovery: a.recovery },
2369
+ confirmWith: a.confirmFlag ?? "--yes",
2370
+ message: renderDestructiveMessage(a)
2371
+ };
2372
+ }
2373
+ function renderDestructiveMessage(a) {
2374
+ const flag = a.confirmFlag ?? "--yes";
2375
+ const br = a.blastRadius;
2376
+ const blast = br ? ` (${[br.count != null ? `${br.count} ${br.unit ?? "item(s)"}` : "", br.scope].filter(Boolean).join(" \xB7 ")})` : "";
2377
+ const lead = a.reversible ? `[${a.severity}]` : `\u26A0 IRREVERSIBLE [${a.severity}]`;
2378
+ const rec = a.recovery ? ` Recovery: ${a.recovery}.` : a.reversible ? "" : " No recovery \u2014 data is permanently lost.";
2379
+ return `${lead} ${a.action} \u2014 ${a.effect} on ${a.resource}${blast}.${rec} Confirm with ${flag}.`;
2380
+ }
2381
+ function confirmDestructive(ctx, opts) {
2382
+ if (opts.confirmed) {
2383
+ return null;
2384
+ }
2385
+ const a = opts.action;
2386
+ if (opts.isJson) {
2387
+ ctx.ui?.json?.(buildConfirmationSignal(a));
2388
+ } else {
2389
+ (ctx.ui?.warn ?? ctx.ui?.error)?.(renderDestructiveMessage(a));
2390
+ }
2391
+ return { exitCode: 1 };
2392
+ }
2393
+
2304
2394
  // src/modern-format.ts
2305
2395
  function sideBorderBox(options) {
2306
- const { title, sections, footer, status, timing } = options;
2396
+ const { title, sections, footer, status, timing, summary } = options;
2307
2397
  const lines = [];
2308
2398
  const terminalWidth = typeof process !== "undefined" && process.stdout?.columns ? process.stdout.columns : 80;
2309
2399
  const itemMaxWidth = Math.max(40, terminalWidth - 4);
2310
- const titleLine = `${safeSymbols.topLeft}${safeSymbols.separator.repeat(2)} ${safeColors.primary(safeColors.bold(title))}`;
2400
+ const titleLine = `${safeColors.primary("\u25C6")} ${safeColors.bold(title)}`;
2311
2401
  lines.push(titleLine);
2312
- lines.push(safeSymbols.border);
2402
+ lines.push(safeColors.muted("\u2502"));
2403
+ if (summary && Object.keys(summary).length > 0) {
2404
+ const entries = Object.entries(summary).map(([k, v]) => [k, String(v)]);
2405
+ const metricsRecord = Object.fromEntries(entries);
2406
+ const metricsLines = metricsList(metricsRecord);
2407
+ for (const line of metricsLines) {
2408
+ lines.push(`${safeColors.muted("\u2502")} ${line}`);
2409
+ }
2410
+ if (sections.length > 0) {
2411
+ lines.push(safeColors.muted("\u2502"));
2412
+ }
2413
+ }
2313
2414
  for (let i = 0; i < sections.length; i++) {
2314
2415
  const section2 = sections[i];
2315
2416
  if (!section2) {
2316
2417
  continue;
2317
2418
  }
2318
2419
  if (section2.header) {
2319
- lines.push(`${safeSymbols.border} ${safeColors.bold(section2.header)}`);
2420
+ lines.push(`${safeColors.muted("\u2502")} ${safeColors.bold(section2.header)}`);
2320
2421
  }
2321
2422
  for (const rawItem of section2.items) {
2322
2423
  const item = typeof rawItem === "string" ? { text: rawItem } : rawItem;
2323
2424
  let displayLines;
2324
2425
  if (item.truncate !== void 0) {
2325
2426
  const vis = stripAnsi(item.text);
2326
- const truncated = vis.length > item.truncate ? vis.slice(0, item.truncate - 1) + "\u2026" : vis;
2327
- displayLines = [item.dim ? safeColors.muted(truncated) : truncated];
2427
+ const truncated = vis.length > item.truncate ? ansiSlice(item.text, item.truncate - 1) + "\u2026" : item.text;
2428
+ displayLines = [item.dim ? safeColors.muted(stripAnsi(truncated)) : truncated];
2328
2429
  } else {
2329
2430
  const wrapped = wrapText(item.text, itemMaxWidth);
2330
2431
  displayLines = item.dim ? wrapped.map((l) => safeColors.muted(l)) : wrapped;
2331
2432
  }
2332
2433
  for (const dl of displayLines) {
2333
- lines.push(`${safeSymbols.border} ${dl}`);
2434
+ lines.push(`${safeColors.muted("\u2502")} ${dl}`);
2334
2435
  }
2335
2436
  }
2336
2437
  if (i < sections.length - 1) {
2337
- lines.push(safeSymbols.border);
2438
+ lines.push(safeColors.muted("\u2502"));
2338
2439
  }
2339
2440
  }
2340
2441
  if (footer || status || timing !== void 0) {
2341
- lines.push(safeSymbols.border);
2442
+ if (lines[lines.length - 1] !== safeColors.muted("\u2502")) {
2443
+ lines.push(safeColors.muted("\u2502"));
2444
+ }
2342
2445
  const footerParts = [];
2343
2446
  if (footer) {
2344
2447
  footerParts.push(footer);
2345
2448
  } else if (status) {
2346
2449
  const statusSymbol = getStatusSymbol(status);
2347
- const statusText = getStatusText(status);
2348
2450
  const statusColor = getStatusColor(status);
2349
- footerParts.push(statusColor(`${statusSymbol} ${statusText}`));
2451
+ footerParts.push(statusColor(`${statusSymbol}`));
2350
2452
  }
2351
2453
  if (timing !== void 0) {
2352
- footerParts.push(formatTiming2(timing));
2454
+ footerParts.push(safeColors.muted(formatTiming2(timing)));
2353
2455
  }
2354
- const footerLine = `${safeSymbols.bottomLeft}${safeSymbols.separator.repeat(2)} ${footerParts.join(" / ")}`;
2456
+ const footerLine = `${safeColors.muted("\u2514")} ${footerParts.join(" ")}`;
2355
2457
  lines.push(footerLine);
2356
2458
  }
2357
2459
  return lines.join("\n");
2358
2460
  }
2359
- function sectionHeader(text) {
2360
- return safeColors.bold(text);
2461
+ function sectionHeader(text2) {
2462
+ return safeColors.bold(text2);
2361
2463
  }
2362
2464
  function metricsList(metrics) {
2363
2465
  const entries = Object.entries(metrics);
@@ -2379,13 +2481,35 @@ var bulletList2 = bulletList;
2379
2481
  var formatTiming2 = formatTiming;
2380
2482
  function statusLine(status, timing) {
2381
2483
  const symbol = getStatusSymbol(status);
2382
- const text = getStatusText(status);
2383
2484
  const color = getStatusColor(status);
2384
- const parts = [color(`${symbol} ${text}`)];
2485
+ const parts = [color(symbol)];
2385
2486
  if (timing !== void 0) {
2386
- parts.push(formatTiming2(timing));
2487
+ parts.push(safeColors.muted(formatTiming2(timing)));
2488
+ }
2489
+ return parts.join(" ");
2490
+ }
2491
+ function ansiSlice(str, maxVisible) {
2492
+ let visible = 0;
2493
+ let i = 0;
2494
+ let result = "";
2495
+ while (i < str.length) {
2496
+ if (str[i] === "\x1B" && str[i + 1] === "[") {
2497
+ let j = i + 2;
2498
+ while (j < str.length && !/[A-Za-z]/.test(str[j])) {
2499
+ j++;
2500
+ }
2501
+ result += str.slice(i, j + 1);
2502
+ i = j + 1;
2503
+ } else {
2504
+ if (visible >= maxVisible) {
2505
+ break;
2506
+ }
2507
+ result += str[i];
2508
+ visible++;
2509
+ i++;
2510
+ }
2387
2511
  }
2388
- return parts.join(" / ");
2512
+ return result;
2389
2513
  }
2390
2514
  function getStatusSymbol(status) {
2391
2515
  switch (status) {
@@ -2399,18 +2523,6 @@ function getStatusSymbol(status) {
2399
2523
  return safeSymbols.info;
2400
2524
  }
2401
2525
  }
2402
- function getStatusText(status) {
2403
- switch (status) {
2404
- case "success":
2405
- return "Success";
2406
- case "error":
2407
- return "Failed";
2408
- case "warning":
2409
- return "Warning";
2410
- case "info":
2411
- return "Info";
2412
- }
2413
- }
2414
2526
  function getStatusColor(status) {
2415
2527
  switch (status) {
2416
2528
  case "success":
@@ -2423,9 +2535,9 @@ function getStatusColor(status) {
2423
2535
  return safeColors.info;
2424
2536
  }
2425
2537
  }
2426
- function wrapText(text, maxWidth) {
2538
+ function wrapText(text2, maxWidth) {
2427
2539
  const result = [];
2428
- const rawLines = text.split("\n");
2540
+ const rawLines = text2.split("\n");
2429
2541
  for (const rawLine of rawLines) {
2430
2542
  const line = rawLine.trimEnd();
2431
2543
  if (stripAnsi(line).length <= maxWidth) {
@@ -2457,6 +2569,80 @@ function wrapText(text, maxWidth) {
2457
2569
  }
2458
2570
  return result.length > 0 ? result : [""];
2459
2571
  }
2572
+ function sideBorderChain(items) {
2573
+ if (items.length === 0) {
2574
+ return "";
2575
+ }
2576
+ if (items.length === 1) {
2577
+ const item = items[0];
2578
+ return sideBorderBox({ title: item.title, sections: item.sections, status: item.status, timing: item.timing });
2579
+ }
2580
+ const lines = [];
2581
+ const terminalWidth = typeof process !== "undefined" && process.stdout?.columns ? process.stdout.columns : 80;
2582
+ const itemMaxWidth = Math.max(40, terminalWidth - 4);
2583
+ for (let blockIdx = 0; blockIdx < items.length; blockIdx++) {
2584
+ const block = items[blockIdx];
2585
+ const isLast = blockIdx === items.length - 1;
2586
+ lines.push(`${safeColors.primary("\u25C6")} ${safeColors.bold(block.title)}`);
2587
+ lines.push(safeColors.muted("\u2502"));
2588
+ if (block.summary && Object.keys(block.summary).length > 0) {
2589
+ const entries = Object.entries(block.summary).map(([k, v]) => [k, String(v)]);
2590
+ const metricsRecord = Object.fromEntries(entries);
2591
+ const metricsLines = metricsList(metricsRecord);
2592
+ for (const line of metricsLines) {
2593
+ lines.push(`${safeColors.muted("\u2502")} ${line}`);
2594
+ }
2595
+ if (block.sections.length > 0) {
2596
+ lines.push(safeColors.muted("\u2502"));
2597
+ }
2598
+ }
2599
+ for (let i = 0; i < block.sections.length; i++) {
2600
+ const section2 = block.sections[i];
2601
+ if (!section2) {
2602
+ continue;
2603
+ }
2604
+ if (section2.header) {
2605
+ lines.push(`${safeColors.muted("\u2502")} ${safeColors.bold(section2.header)}`);
2606
+ }
2607
+ for (const rawItem of section2.items) {
2608
+ const item = typeof rawItem === "string" ? { text: rawItem } : rawItem;
2609
+ let displayLines;
2610
+ if (item.truncate !== void 0) {
2611
+ const vis = stripAnsi(item.text);
2612
+ const truncated = vis.length > item.truncate ? ansiSlice(item.text, item.truncate - 1) + "\u2026" : item.text;
2613
+ displayLines = [item.dim ? safeColors.muted(stripAnsi(truncated)) : truncated];
2614
+ } else {
2615
+ const wrapped = wrapText(item.text, itemMaxWidth);
2616
+ displayLines = item.dim ? wrapped.map((l) => safeColors.muted(l)) : wrapped;
2617
+ }
2618
+ for (const dl of displayLines) {
2619
+ lines.push(`${safeColors.muted("\u2502")} ${dl}`);
2620
+ }
2621
+ }
2622
+ if (i < block.sections.length - 1) {
2623
+ lines.push(safeColors.muted("\u2502"));
2624
+ }
2625
+ }
2626
+ if (isLast) {
2627
+ if (block.status || block.timing !== void 0) {
2628
+ lines.push(safeColors.muted("\u2502"));
2629
+ const footerParts = [];
2630
+ if (block.status) {
2631
+ footerParts.push(getStatusColor(block.status)(getStatusSymbol(block.status)));
2632
+ }
2633
+ if (block.timing !== void 0) {
2634
+ footerParts.push(safeColors.muted(formatTiming2(block.timing)));
2635
+ }
2636
+ lines.push(`${safeColors.muted("\u2514")} ${footerParts.join(" ")}`);
2637
+ }
2638
+ } else {
2639
+ if (lines[lines.length - 1] !== safeColors.muted("\u2502")) {
2640
+ lines.push(safeColors.muted("\u2502"));
2641
+ }
2642
+ }
2643
+ }
2644
+ return lines.join("\n");
2645
+ }
2460
2646
  function formatError(err, opts) {
2461
2647
  const raw = err instanceof Error ? err.message : String(err);
2462
2648
  const allLines = raw.split("\n").map((l) => l.trimEnd()).filter((l) => l.length > 0);
@@ -2623,6 +2809,601 @@ function infoResult(title, data) {
2623
2809
  });
2624
2810
  }
2625
2811
 
2812
+ // src/log-display.ts
2813
+ var LEVEL_CONFIG = {
2814
+ info: { symbol: "\u25C6", label: "INFO ", color: safeColors.info },
2815
+ warn: { symbol: "\u26A0", label: "WARN ", color: safeColors.warning },
2816
+ error: { symbol: "\u2717", label: "ERROR", color: safeColors.error },
2817
+ debug: { symbol: "\u25CB", label: "DEBUG", color: safeColors.muted },
2818
+ verbose: { symbol: "\xB7", label: "VERB ", color: safeColors.muted }
2819
+ };
2820
+ function timestamp() {
2821
+ const now = /* @__PURE__ */ new Date();
2822
+ const h = String(now.getHours()).padStart(2, "0");
2823
+ const m = String(now.getMinutes()).padStart(2, "0");
2824
+ const s = String(now.getSeconds()).padStart(2, "0");
2825
+ return `${h}:${m}:${s}`;
2826
+ }
2827
+ function logLine(level, message) {
2828
+ const cfg = LEVEL_CONFIG[level];
2829
+ const sym = cfg.color(cfg.symbol);
2830
+ const lbl = safeColors.muted(cfg.label);
2831
+ const ts = safeColors.muted(timestamp());
2832
+ return ` ${sym} ${lbl} ${ts} ${message}`;
2833
+ }
2834
+ function logGroup(title, lines) {
2835
+ const header = ` ${safeColors.bold(title)}`;
2836
+ const body = lines.map((l) => ` ${l}`).join("\n");
2837
+ return body ? `${header}
2838
+ ${body}` : header;
2839
+ }
2840
+ function printLog(level, message) {
2841
+ process.stdout.write(logLine(level, message) + "\n");
2842
+ }
2843
+
2844
+ // src/badge.ts
2845
+ var BADGE_COLORS = {
2846
+ success: safeColors.success,
2847
+ error: safeColors.error,
2848
+ warning: safeColors.warning,
2849
+ info: safeColors.info,
2850
+ neutral: safeColors.muted
2851
+ };
2852
+ function badge(label, variant = "neutral") {
2853
+ const colorFn = BADGE_COLORS[variant];
2854
+ return colorFn(`[${label.toUpperCase()}]`);
2855
+ }
2856
+ function statusBadge(status) {
2857
+ const s = status.toLowerCase();
2858
+ if (s === "online" || s === "running" || s === "success" || s === "active" || s === "done") {
2859
+ return badge(status, "success");
2860
+ }
2861
+ if (s === "offline" || s === "failed" || s === "error" || s === "stopped") {
2862
+ return badge(status, "error");
2863
+ }
2864
+ if (s === "degraded" || s === "warning" || s === "reconnecting" || s === "pending") {
2865
+ return badge(status, "warning");
2866
+ }
2867
+ if (s === "starting" || s === "initializing") {
2868
+ return badge(status, "info");
2869
+ }
2870
+ return badge(status, "neutral");
2871
+ }
2872
+ function isInteractive() {
2873
+ return Boolean(
2874
+ process.stdin.isTTY && process.stdout.isTTY && !process.env.CI && !process.env.NO_INTERACTIVE
2875
+ );
2876
+ }
2877
+ function enableRawMode() {
2878
+ if (process.stdin.isTTY) {
2879
+ process.stdin.setRawMode(true);
2880
+ }
2881
+ }
2882
+ function disableRawMode() {
2883
+ if (process.stdin.isTTY) {
2884
+ process.stdin.setRawMode(false);
2885
+ }
2886
+ }
2887
+ function clearLine() {
2888
+ process.stdout.write("\r\x1B[K");
2889
+ }
2890
+ function clearLines(n) {
2891
+ for (let i = 0; i < n; i++) {
2892
+ if (i > 0) {
2893
+ process.stdout.write("\x1B[1A");
2894
+ }
2895
+ clearLine();
2896
+ }
2897
+ }
2898
+ function hideCursor() {
2899
+ process.stdout.write("\x1B[?25l");
2900
+ }
2901
+ function showCursor() {
2902
+ process.stdout.write("\x1B[?25h");
2903
+ }
2904
+ function onKeypress(handler) {
2905
+ readline__namespace.emitKeypressEvents(process.stdin);
2906
+ const listener = (_, key) => {
2907
+ if (key) {
2908
+ handler(key);
2909
+ }
2910
+ };
2911
+ process.stdin.on("keypress", listener);
2912
+ process.stdin.resume();
2913
+ return () => {
2914
+ process.stdin.off("keypress", listener);
2915
+ if (process.stdin.listenerCount("keypress") === 0) {
2916
+ process.stdin.pause();
2917
+ }
2918
+ };
2919
+ }
2920
+ function isUpKey(key) {
2921
+ return key.name === "up" || key.name === "k" && !key.ctrl;
2922
+ }
2923
+ function isDownKey(key) {
2924
+ return key.name === "down" || key.name === "j" && !key.ctrl;
2925
+ }
2926
+ function isEnterKey(key) {
2927
+ return key.name === "return" || key.name === "enter";
2928
+ }
2929
+ function isEscapeKey(key) {
2930
+ return key.name === "escape" || key.name === "c" && key.ctrl || key.name === "q" && !key.ctrl;
2931
+ }
2932
+ function isSpaceKey(key) {
2933
+ return key.name === "space";
2934
+ }
2935
+
2936
+ // src/tasks.ts
2937
+ var SPINNER_FRAMES = ["\u25D0", "\u25D3", "\u25D1", "\u25D2"];
2938
+ function renderTasks(statuses, spinnerFrame) {
2939
+ const lines = [];
2940
+ for (const s of statuses) {
2941
+ let prefix;
2942
+ switch (s.state) {
2943
+ case "pending":
2944
+ prefix = safeColors.muted("\u25CB");
2945
+ break;
2946
+ case "running":
2947
+ prefix = safeColors.primary(SPINNER_FRAMES[spinnerFrame % SPINNER_FRAMES.length] ?? "\u25C6");
2948
+ break;
2949
+ case "done":
2950
+ prefix = safeColors.success("\u25CF");
2951
+ break;
2952
+ case "failed":
2953
+ prefix = safeColors.error("\u2717");
2954
+ break;
2955
+ }
2956
+ lines.push(` ${prefix} ${s.state === "done" ? safeColors.muted(s.title) : s.state === "failed" ? safeColors.error(s.title) : s.title}`);
2957
+ if (s.error) {
2958
+ lines.push(` ${safeColors.muted(s.error)}`);
2959
+ }
2960
+ }
2961
+ process.stdout.write(lines.join("\n") + "\n");
2962
+ return lines.length;
2963
+ }
2964
+ async function runTasks(tasks) {
2965
+ const statuses = tasks.map((t) => ({ title: t.title, state: "pending" }));
2966
+ let lineCount = 0;
2967
+ let spinnerFrame = 0;
2968
+ lineCount = renderTasks(statuses, spinnerFrame);
2969
+ let spinnerInterval;
2970
+ for (let i = 0; i < tasks.length; i++) {
2971
+ const task = tasks[i];
2972
+ const status = statuses[i];
2973
+ if (!task || !status) {
2974
+ continue;
2975
+ }
2976
+ status.state = "running";
2977
+ clearLines(lineCount);
2978
+ lineCount = renderTasks(statuses, spinnerFrame);
2979
+ spinnerInterval = setInterval(() => {
2980
+ spinnerFrame++;
2981
+ clearLines(lineCount);
2982
+ lineCount = renderTasks(statuses, spinnerFrame);
2983
+ }, 80);
2984
+ try {
2985
+ await task.run((newTitle) => {
2986
+ status.title = newTitle;
2987
+ });
2988
+ status.state = "done";
2989
+ } catch (err) {
2990
+ status.state = "failed";
2991
+ status.error = err instanceof Error ? err.message : String(err);
2992
+ } finally {
2993
+ clearInterval(spinnerInterval);
2994
+ spinnerInterval = void 0;
2995
+ }
2996
+ }
2997
+ clearLines(lineCount);
2998
+ renderTasks(statuses, 0);
2999
+ process.stdout.write("\n");
3000
+ const failed = statuses.filter((s) => s.state === "failed");
3001
+ if (failed.length > 0) {
3002
+ throw new Error(`${failed.length} task${failed.length === 1 ? "" : "s"} failed`);
3003
+ }
3004
+ }
3005
+ async function confirm(options) {
3006
+ const { message, defaultValue = false } = options;
3007
+ if (!isInteractive()) {
3008
+ return defaultValue;
3009
+ }
3010
+ const hint = defaultValue ? "(Y/n)" : "(y/N)";
3011
+ process.stdout.write(`${safeColors.primary("\u25C6")} ${safeColors.bold(message)} ${safeColors.muted(hint)} `);
3012
+ return new Promise((resolve) => {
3013
+ const rl = readline__namespace.createInterface({ input: process.stdin, output: void 0 });
3014
+ rl.once("line", (line) => {
3015
+ rl.close();
3016
+ const trimmed = line.trim().toLowerCase();
3017
+ process.stdout.write("\n");
3018
+ if (trimmed === "") {
3019
+ resolve(defaultValue);
3020
+ } else {
3021
+ resolve(trimmed === "y" || trimmed === "yes");
3022
+ }
3023
+ });
3024
+ rl.once("close", () => {
3025
+ resolve(defaultValue);
3026
+ });
3027
+ });
3028
+ }
3029
+ async function text(options) {
3030
+ const { message, placeholder, defaultValue = "", validate, mask = false } = options;
3031
+ if (!isInteractive()) {
3032
+ return defaultValue;
3033
+ }
3034
+ const hint = placeholder ? safeColors.muted(` (${placeholder})`) : "";
3035
+ process.stdout.write(`${safeColors.primary("\u25C6")} ${safeColors.bold(message)}${hint}
3036
+ `);
3037
+ process.stdout.write(`${safeColors.muted("\u2502")} `);
3038
+ return new Promise((resolve) => {
3039
+ const rl = readline__namespace.createInterface({
3040
+ input: process.stdin,
3041
+ output: mask ? void 0 : process.stdout,
3042
+ terminal: !mask
3043
+ });
3044
+ if (mask) {
3045
+ process.stdin.on("data", (char) => {
3046
+ const c = char.toString();
3047
+ if (c === "\n" || c === "\r") {
3048
+ return;
3049
+ }
3050
+ process.stdout.write("*");
3051
+ });
3052
+ }
3053
+ rl.once("line", (line) => {
3054
+ rl.close();
3055
+ const value = line.trim() || defaultValue;
3056
+ if (validate) {
3057
+ const error = validate(value);
3058
+ if (error) {
3059
+ process.stdout.write(`${safeColors.error("\u2717")} ${safeColors.error(error)}
3060
+ `);
3061
+ resolve(text(options));
3062
+ return;
3063
+ }
3064
+ }
3065
+ process.stdout.write(`${safeColors.muted("\u2514")}
3066
+ `);
3067
+ resolve(value);
3068
+ });
3069
+ rl.once("close", () => {
3070
+ resolve(defaultValue);
3071
+ });
3072
+ });
3073
+ }
3074
+
3075
+ // src/interactive/select.ts
3076
+ function renderSelect(message, choices, activeIndex, isFirst) {
3077
+ const lines = [];
3078
+ if (isFirst) {
3079
+ lines.push(`${safeColors.primary("\u25C6")} ${safeColors.bold(message)}`);
3080
+ lines.push(safeColors.muted("\u2502"));
3081
+ }
3082
+ for (let i = 0; i < choices.length; i++) {
3083
+ const choice = choices[i];
3084
+ if (!choice) {
3085
+ continue;
3086
+ }
3087
+ const isActive = i === activeIndex;
3088
+ const pointer = isActive ? safeColors.primary("\u276F") : " ";
3089
+ const label = isActive ? safeColors.bold(choice.label) : safeColors.muted(choice.label);
3090
+ const hint = choice.hint ? safeColors.muted(` \u2014 ${choice.hint}`) : "";
3091
+ lines.push(`${safeColors.muted("\u2502")} ${pointer} ${label}${hint}`);
3092
+ }
3093
+ lines.push(safeColors.muted("\u2502"));
3094
+ process.stdout.write(lines.join("\n") + "\n");
3095
+ return lines.length;
3096
+ }
3097
+ async function select(options) {
3098
+ const { message, choices, initialIndex = 0 } = options;
3099
+ if (!isInteractive() || choices.length === 0) {
3100
+ return choices[Math.min(initialIndex, choices.length - 1)].value;
3101
+ }
3102
+ let activeIndex = Math.min(initialIndex, choices.length - 1);
3103
+ let lineCount = 0;
3104
+ hideCursor();
3105
+ enableRawMode();
3106
+ lineCount = renderSelect(message, choices, activeIndex, true);
3107
+ return new Promise((resolve) => {
3108
+ const unsubscribe = onKeypress((key) => {
3109
+ if (isUpKey(key)) {
3110
+ activeIndex = (activeIndex - 1 + choices.length) % choices.length;
3111
+ clearLines(lineCount);
3112
+ lineCount = renderSelect(message, choices, activeIndex, false);
3113
+ return;
3114
+ }
3115
+ if (isDownKey(key)) {
3116
+ activeIndex = (activeIndex + 1) % choices.length;
3117
+ clearLines(lineCount);
3118
+ lineCount = renderSelect(message, choices, activeIndex, false);
3119
+ return;
3120
+ }
3121
+ if (isEnterKey(key)) {
3122
+ unsubscribe();
3123
+ disableRawMode();
3124
+ showCursor();
3125
+ clearLines(lineCount + 2);
3126
+ const selected = choices[activeIndex];
3127
+ process.stdout.write(`${safeColors.primary("\u25C6")} ${safeColors.bold(message)} ${safeColors.muted(selected.label)}
3128
+ `);
3129
+ process.stdout.write(`${safeColors.muted("\u2514")}
3130
+ `);
3131
+ resolve(selected.value);
3132
+ return;
3133
+ }
3134
+ if (isEscapeKey(key)) {
3135
+ unsubscribe();
3136
+ disableRawMode();
3137
+ showCursor();
3138
+ clearLines(lineCount + 2);
3139
+ process.stdout.write(`${safeColors.muted("\u25C6")} ${safeColors.muted(message)} ${safeColors.muted("cancelled")}
3140
+ `);
3141
+ process.stdout.write(`${safeColors.muted("\u2514")}
3142
+ `);
3143
+ resolve(choices[initialIndex].value);
3144
+ return;
3145
+ }
3146
+ });
3147
+ });
3148
+ }
3149
+
3150
+ // src/interactive/multi-select.ts
3151
+ function renderMultiSelect(message, choices, checked, activeIndex, isFirst, error) {
3152
+ const lines = [];
3153
+ if (isFirst) {
3154
+ lines.push(`${safeColors.primary("\u25C6")} ${safeColors.bold(message)} ${safeColors.muted("Space to toggle, Enter to confirm")}`);
3155
+ lines.push(safeColors.muted("\u2502"));
3156
+ }
3157
+ for (let i = 0; i < choices.length; i++) {
3158
+ const choice = choices[i];
3159
+ if (!choice) {
3160
+ continue;
3161
+ }
3162
+ const isActive = i === activeIndex;
3163
+ const isChecked = checked.has(i);
3164
+ const checkbox = isChecked ? safeColors.success("\u25C9") : safeColors.muted("\u25CB");
3165
+ const pointer = isActive ? safeColors.primary("\u276F") : " ";
3166
+ const label = isActive ? safeColors.bold(choice.label) : isChecked ? choice.label : safeColors.muted(choice.label);
3167
+ const hint = choice.hint ? safeColors.muted(` \u2014 ${choice.hint}`) : "";
3168
+ lines.push(`${safeColors.muted("\u2502")} ${pointer} ${checkbox} ${label}${hint}`);
3169
+ }
3170
+ if (error) {
3171
+ lines.push(`${safeColors.muted("\u2502")}`);
3172
+ lines.push(`${safeColors.muted("\u2502")} ${safeColors.error("\u2717")} ${safeColors.error(error)}`);
3173
+ }
3174
+ lines.push(safeColors.muted("\u2502"));
3175
+ process.stdout.write(lines.join("\n") + "\n");
3176
+ return lines.length;
3177
+ }
3178
+ async function multiSelect(options) {
3179
+ const { message, choices, min } = options;
3180
+ if (!isInteractive() || choices.length === 0) {
3181
+ return choices.filter((c) => c.checked).map((c) => c.value);
3182
+ }
3183
+ let activeIndex = 0;
3184
+ const checked = new Set(
3185
+ choices.map((c, i) => c.checked ? i : -1).filter((i) => i >= 0)
3186
+ );
3187
+ let lineCount = 0;
3188
+ let error;
3189
+ hideCursor();
3190
+ enableRawMode();
3191
+ lineCount = renderMultiSelect(message, choices, checked, activeIndex, true, error);
3192
+ return new Promise((resolve) => {
3193
+ const unsubscribe = onKeypress((key) => {
3194
+ if (isUpKey(key)) {
3195
+ activeIndex = (activeIndex - 1 + choices.length) % choices.length;
3196
+ clearLines(lineCount);
3197
+ lineCount = renderMultiSelect(message, choices, checked, activeIndex, false, error);
3198
+ return;
3199
+ }
3200
+ if (isDownKey(key)) {
3201
+ activeIndex = (activeIndex + 1) % choices.length;
3202
+ clearLines(lineCount);
3203
+ lineCount = renderMultiSelect(message, choices, checked, activeIndex, false, error);
3204
+ return;
3205
+ }
3206
+ if (isSpaceKey(key)) {
3207
+ if (checked.has(activeIndex)) {
3208
+ checked.delete(activeIndex);
3209
+ } else {
3210
+ checked.add(activeIndex);
3211
+ }
3212
+ error = void 0;
3213
+ clearLines(lineCount);
3214
+ lineCount = renderMultiSelect(message, choices, checked, activeIndex, false, error);
3215
+ return;
3216
+ }
3217
+ if (key.name === "a" && !key.ctrl) {
3218
+ if (checked.size === choices.length) {
3219
+ checked.clear();
3220
+ } else {
3221
+ choices.forEach((_, i) => checked.add(i));
3222
+ }
3223
+ clearLines(lineCount);
3224
+ lineCount = renderMultiSelect(message, choices, checked, activeIndex, false, error);
3225
+ return;
3226
+ }
3227
+ if (isEnterKey(key)) {
3228
+ if (min !== void 0 && checked.size < min) {
3229
+ error = `Select at least ${min} option${min === 1 ? "" : "s"}`;
3230
+ clearLines(lineCount);
3231
+ lineCount = renderMultiSelect(message, choices, checked, activeIndex, false, error);
3232
+ return;
3233
+ }
3234
+ unsubscribe();
3235
+ disableRawMode();
3236
+ showCursor();
3237
+ const headerLines = 2;
3238
+ clearLines(lineCount + headerLines);
3239
+ const selectedLabels = choices.filter((_, i) => checked.has(i)).map((c) => c.label).join(", ");
3240
+ process.stdout.write(`${safeColors.primary("\u25C6")} ${safeColors.bold(message)} ${safeColors.muted(selectedLabels || "none")}
3241
+ `);
3242
+ process.stdout.write(`${safeColors.muted("\u2514")}
3243
+ `);
3244
+ resolve(choices.filter((_, i) => checked.has(i)).map((c) => c.value));
3245
+ return;
3246
+ }
3247
+ if (isEscapeKey(key)) {
3248
+ unsubscribe();
3249
+ disableRawMode();
3250
+ showCursor();
3251
+ clearLines(lineCount + 2);
3252
+ process.stdout.write(`${safeColors.muted("\u25C6")} ${safeColors.muted(message)} ${safeColors.muted("cancelled")}
3253
+ `);
3254
+ process.stdout.write(`${safeColors.muted("\u2514")}
3255
+ `);
3256
+ resolve([]);
3257
+ return;
3258
+ }
3259
+ });
3260
+ });
3261
+ }
3262
+
3263
+ // src/stdout-ui.ts
3264
+ var NOOP_PROMPTS = {
3265
+ confirm: async (_, opts) => opts?.defaultValue ?? false,
3266
+ prompt: async (_, opts) => opts?.default ?? "",
3267
+ select: async (_, choices) => choices[0]?.value,
3268
+ multiSelect: async (_, choices) => choices.filter((c) => c.checked).map((c) => c.value)
3269
+ };
3270
+ function createBaseStdoutUI(prompts, log) {
3271
+ return {
3272
+ colors: safeColors,
3273
+ symbols: safeSymbols,
3274
+ write: (text2) => {
3275
+ process.stdout.write(text2 + "\n");
3276
+ },
3277
+ info: (msg, options) => {
3278
+ const extra = options?.sections ?? [];
3279
+ console.log(sideBorderBox({
3280
+ title: options?.title ?? "Info",
3281
+ sections: [{ items: [msg] }, ...extra],
3282
+ status: "info",
3283
+ timing: options?.timing,
3284
+ summary: options?.summary
3285
+ }));
3286
+ },
3287
+ success: (msg, options) => {
3288
+ const extra = options?.sections ?? [];
3289
+ console.log(sideBorderBox({
3290
+ title: options?.title ?? "Success",
3291
+ sections: [{ items: [msg] }, ...extra],
3292
+ status: "success",
3293
+ timing: options?.timing,
3294
+ summary: options?.summary
3295
+ }));
3296
+ },
3297
+ warn: (msg, options) => {
3298
+ const extra = options?.sections ?? [];
3299
+ console.log(sideBorderBox({
3300
+ title: options?.title ?? "Warning",
3301
+ sections: [{ items: [msg] }, ...extra],
3302
+ status: "warning",
3303
+ timing: options?.timing,
3304
+ summary: options?.summary
3305
+ }));
3306
+ },
3307
+ error: (err, options) => {
3308
+ const message = err instanceof Error ? err.message : err;
3309
+ const sections = [
3310
+ { items: [message] }
3311
+ ];
3312
+ if (options?.sections?.length) {
3313
+ sections.push(...options.sections.map((s) => ({ header: s.header, items: s.items })));
3314
+ }
3315
+ if (options?.cause) {
3316
+ sections.push({ header: "Cause", items: [{ text: options.cause, dim: true }] });
3317
+ }
3318
+ if (options?.hint) {
3319
+ const hintItems = [options.hint];
3320
+ if (options.command) {
3321
+ hintItems.push({ text: `$ ${options.command}`, dim: true });
3322
+ }
3323
+ sections.push({ header: "Hint", items: hintItems });
3324
+ } else if (options?.command) {
3325
+ sections.push({ header: "Hint", items: [{ text: `$ ${options.command}`, dim: true }] });
3326
+ }
3327
+ console.error(sideBorderBox({
3328
+ title: options?.title ?? "Error",
3329
+ sections,
3330
+ status: "error",
3331
+ timing: options?.timing,
3332
+ summary: options?.summary
3333
+ }));
3334
+ },
3335
+ debug: (msg) => {
3336
+ if (process.env.DEBUG) {
3337
+ console.debug(msg);
3338
+ }
3339
+ },
3340
+ spinner: (msg) => {
3341
+ console.log(`${safeColors.primary("\u25C6")} ${msg}`);
3342
+ return {
3343
+ update: (m) => console.log(`${safeColors.primary("\u25C6")} ${m}`),
3344
+ succeed: (m) => console.log(`${safeColors.success("\u2713")} ${m ?? msg}`),
3345
+ fail: (m) => console.log(`${safeColors.error("\u2717")} ${m ?? msg}`),
3346
+ stop: () => {
3347
+ }
3348
+ };
3349
+ },
3350
+ table: (data, columns) => {
3351
+ if (data.length === 0) {
3352
+ return;
3353
+ }
3354
+ const cols = columns ?? Object.keys(data[0]).map((k) => ({ header: k, key: k }));
3355
+ const rows = data.map((row) => cols.map((col) => String(row[col.key] ?? "")));
3356
+ const lines = formatTable(
3357
+ cols.map((c) => ({ header: c.header, width: c.width, align: c.align })),
3358
+ rows,
3359
+ { separator: "" }
3360
+ );
3361
+ for (const line of lines) {
3362
+ console.log(` ${line}`);
3363
+ }
3364
+ },
3365
+ json: (data, options) => console.log(options?.pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data)),
3366
+ newline: () => console.log(),
3367
+ divider: () => console.log(safeColors.muted("\u2500".repeat(process.stdout.columns || 80))),
3368
+ box: (content, title) => {
3369
+ console.log(sideBorderBox({
3370
+ title: title || "",
3371
+ sections: [{ items: content.split("\n") }],
3372
+ status: "info"
3373
+ }));
3374
+ },
3375
+ sideBox: (options) => {
3376
+ const allSections = [];
3377
+ if (options.summary && Object.keys(options.summary).length > 0) {
3378
+ allSections.push({ items: metricsList(options.summary) });
3379
+ }
3380
+ allSections.push(...(options.sections ?? []).map((s) => ({ header: s.header, items: s.items })));
3381
+ console.log(sideBorderBox({
3382
+ title: options.title,
3383
+ sections: allSections,
3384
+ status: options.status,
3385
+ timing: options.timing
3386
+ }));
3387
+ },
3388
+ chain: (items) => {
3389
+ console.log(sideBorderChain(
3390
+ items.map((item) => ({
3391
+ title: item.title,
3392
+ sections: (item.sections ?? []).map((s) => ({ header: s.header, items: s.items })),
3393
+ summary: item.summary,
3394
+ status: item.status,
3395
+ timing: item.timing
3396
+ }))
3397
+ ));
3398
+ },
3399
+ confirm: prompts.confirm,
3400
+ prompt: prompts.prompt,
3401
+ select: prompts.select,
3402
+ multiSelect: prompts.multiSelect,
3403
+ log
3404
+ };
3405
+ }
3406
+
2626
3407
  exports.DebugOutput = DebugOutput;
2627
3408
  exports.DebugSection = DebugSection;
2628
3409
  exports.DebugTrace = DebugTrace;
@@ -2630,12 +3411,18 @@ exports.DebugTree = DebugTree;
2630
3411
  exports.DynamicCommandDiscovery = DynamicCommandDiscovery;
2631
3412
  exports.Loader = Loader;
2632
3413
  exports.MultiCLISuggestions = MultiCLISuggestions;
3414
+ exports.NOOP_PROMPTS = NOOP_PROMPTS;
2633
3415
  exports.StaticCommandDiscovery = StaticCommandDiscovery;
2634
3416
  exports.TimingTracker = TimingTracker;
2635
3417
  exports.accentLabel = accentLabel;
3418
+ exports.badge = badge;
2636
3419
  exports.box = box;
3420
+ exports.buildConfirmationSignal = buildConfirmationSignal;
2637
3421
  exports.bulletList = bulletList;
2638
3422
  exports.colors = colors;
3423
+ exports.confirm = confirm;
3424
+ exports.confirmDestructive = confirmDestructive;
3425
+ exports.createBaseStdoutUI = createBaseStdoutUI;
2639
3426
  exports.createCommandDiscovery = createCommandDiscovery;
2640
3427
  exports.createCommandRegistry = createCommandRegistry;
2641
3428
  exports.createCommandRunner = createCommandRunner;
@@ -2694,15 +3481,20 @@ exports.getCommandInfo = getCommandInfo;
2694
3481
  exports.getContextCwd = getContextCwd;
2695
3482
  exports.groupByGroup = groupByGroup;
2696
3483
  exports.groupByNamespace = groupByNamespace;
3484
+ exports.handleError = handleError;
2697
3485
  exports.hasAnsi = hasAnsi;
2698
3486
  exports.headline = headline;
2699
3487
  exports.indent = indent;
2700
3488
  exports.infoResult = infoResult;
2701
3489
  exports.isCommandAvailable = isCommandAvailable;
3490
+ exports.isInteractive = isInteractive;
2702
3491
  exports.isJsonMode = isJsonMode;
2703
3492
  exports.keyValue = keyValue;
3493
+ exports.logGroup = logGroup;
3494
+ exports.logLine = logLine;
2704
3495
  exports.mergeFlags = mergeFlags;
2705
3496
  exports.metricsList = metricsList;
3497
+ exports.multiSelect = multiSelect;
2706
3498
  exports.muted = muted;
2707
3499
  exports.pad = pad;
2708
3500
  exports.parseBoolean = parseBoolean;
@@ -2711,28 +3503,37 @@ exports.parseFlagsFromInput = parseFlagsFromInput;
2711
3503
  exports.parseNumber = parseNumber;
2712
3504
  exports.parseNumberFlag = parseNumberFlag;
2713
3505
  exports.parseString = parseString;
3506
+ exports.printLog = printLog;
3507
+ exports.renderDestructiveMessage = renderDestructiveMessage;
3508
+ exports.rethrowForRest = rethrowForRest;
3509
+ exports.runTasks = runTasks;
2714
3510
  exports.safeColors = safeColors;
2715
3511
  exports.safeKeyValue = safeKeyValue;
2716
3512
  exports.safeSymbols = safeSymbols;
2717
3513
  exports.searchInLogs = searchInLogs;
2718
3514
  exports.section = section;
2719
3515
  exports.sectionHeader = sectionHeader;
3516
+ exports.select = select;
2720
3517
  exports.setJsonMode = setJsonMode;
2721
3518
  exports.shouldUseAIFormat = shouldUseAIFormat;
2722
3519
  exports.showError = showError;
2723
3520
  exports.showLoading = showLoading;
2724
3521
  exports.showSuccess = showSuccess;
2725
3522
  exports.sideBorderBox = sideBorderBox;
3523
+ exports.sideBorderChain = sideBorderChain;
3524
+ exports.statusBadge = statusBadge;
2726
3525
  exports.statusLine = statusLine;
2727
3526
  exports.stripAnsi = stripAnsi;
2728
3527
  exports.successResult = successResult;
2729
3528
  exports.supportsColor = supportsColor;
2730
3529
  exports.symbols = symbols;
2731
3530
  exports.table = table;
3531
+ exports.text = text;
2732
3532
  exports.toPosixPath = toPosixPath;
2733
3533
  exports.truncate = truncate;
2734
3534
  exports.useLoader = useLoader;
2735
3535
  exports.validateSuggestions = validateSuggestions;
3536
+ exports.validationError = validationError;
2736
3537
  exports.warningResult = warningResult;
2737
3538
  exports.withRetry = withRetry;
2738
3539
  //# sourceMappingURL=index.cjs.map