@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/debug.cjs +19 -11
- package/dist/debug.cjs.map +1 -1
- package/dist/debug.js +19 -11
- package/dist/debug.js.map +1 -1
- package/dist/index.cjs +905 -104
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +239 -5
- package/dist/index.d.ts +239 -5
- package/dist/index.js +867 -105
- package/dist/index.js.map +1 -1
- package/dist/interactive/index.cjs +462 -0
- package/dist/interactive/index.cjs.map +1 -0
- package/dist/interactive/index.d.cts +74 -0
- package/dist/interactive/index.d.ts +74 -0
- package/dist/interactive/index.js +436 -0
- package/dist/interactive/index.js.map +1 -0
- package/package.json +12 -4
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) => (
|
|
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: "
|
|
36
|
-
error: "
|
|
37
|
-
warning: "
|
|
38
|
-
info: "\
|
|
36
|
+
success: "\u2713",
|
|
37
|
+
error: "\u2717",
|
|
38
|
+
warning: "\u26A0",
|
|
39
|
+
info: "\u25C6",
|
|
39
40
|
bullet: "\u2022",
|
|
40
|
-
clock: "
|
|
41
|
-
folder: "
|
|
42
|
-
package: "\
|
|
43
|
-
pointer: "\
|
|
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.
|
|
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.
|
|
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) => (
|
|
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 : "\
|
|
115
|
+
info: supportsColor ? symbols.info : "\u25C6",
|
|
107
116
|
bullet: supportsColor ? symbols.bullet : "\u2022",
|
|
108
|
-
clock: supportsColor ? symbols.clock : "
|
|
109
|
-
folder: supportsColor ? symbols.folder : "
|
|
110
|
-
package: supportsColor ? symbols.package : "\
|
|
111
|
-
pointer: supportsColor ? symbols.pointer : "
|
|
112
|
-
section: supportsColor ? symbols.section : "
|
|
113
|
-
|
|
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
|
|
185
|
-
console.log(`${safeSymbols.info} ${
|
|
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
|
|
226
|
-
process.stdout.write(`\r${safeColors.info("\u2192")} ${
|
|
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(
|
|
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(
|
|
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(
|
|
240
|
+
function showLoading(text2, jsonMode = false) {
|
|
236
241
|
if (!jsonMode) {
|
|
237
|
-
console.log(`${safeColors.info("\u2192")} ${
|
|
242
|
+
console.log(`${safeColors.info("\u2192")} ${text2}...`);
|
|
238
243
|
}
|
|
239
244
|
}
|
|
240
|
-
function showSuccess(
|
|
245
|
+
function showSuccess(text2, jsonMode = false) {
|
|
241
246
|
if (!jsonMode) {
|
|
242
|
-
console.log(`${safeSymbols.success} ${
|
|
247
|
+
console.log(`${safeSymbols.success} ${text2}`);
|
|
243
248
|
}
|
|
244
249
|
}
|
|
245
|
-
function showError(
|
|
250
|
+
function showError(text2, jsonMode = false) {
|
|
246
251
|
if (!jsonMode) {
|
|
247
|
-
console.log(`${safeSymbols.error} ${
|
|
252
|
+
console.log(`${safeSymbols.error} ${text2}`);
|
|
248
253
|
}
|
|
249
254
|
}
|
|
250
|
-
function useLoader(
|
|
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(
|
|
439
|
-
return safeColors.primary(safeColors.bold(
|
|
443
|
+
function headline(text2) {
|
|
444
|
+
return safeColors.primary(safeColors.bold(text2));
|
|
440
445
|
}
|
|
441
|
-
function accentLabel(
|
|
442
|
-
return safeColors.accent(safeColors.bold(
|
|
446
|
+
function accentLabel(text2) {
|
|
447
|
+
return safeColors.accent(safeColors.bold(text2));
|
|
443
448
|
}
|
|
444
|
-
function muted(
|
|
445
|
-
return safeColors.muted(
|
|
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(
|
|
462
|
+
function formatRelativeTime(timestamp2) {
|
|
458
463
|
const now = /* @__PURE__ */ new Date();
|
|
459
|
-
const time = toDate(
|
|
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(
|
|
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(
|
|
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(
|
|
505
|
-
if (
|
|
506
|
-
return
|
|
509
|
+
function truncate(text2, maxLength) {
|
|
510
|
+
if (text2.length <= maxLength) {
|
|
511
|
+
return text2;
|
|
507
512
|
}
|
|
508
|
-
return
|
|
513
|
+
return text2.substring(0, maxLength - 3) + "...";
|
|
509
514
|
}
|
|
510
|
-
function pad(
|
|
511
|
-
if (
|
|
512
|
-
return
|
|
515
|
+
function pad(text2, width, align = "left") {
|
|
516
|
+
if (text2.length >= width) {
|
|
517
|
+
return text2;
|
|
513
518
|
}
|
|
514
|
-
const padding = width -
|
|
519
|
+
const padding = width - text2.length;
|
|
515
520
|
switch (align) {
|
|
516
521
|
case "right":
|
|
517
|
-
return " ".repeat(padding) +
|
|
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) +
|
|
526
|
+
return " ".repeat(leftPad) + text2 + " ".repeat(rightPad);
|
|
522
527
|
default:
|
|
523
|
-
return
|
|
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
|
|
1258
|
-
const
|
|
1259
|
-
const
|
|
1260
|
-
return cleanStr.length
|
|
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(
|
|
1346
|
-
const date = new Date(
|
|
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 = `${
|
|
2375
|
+
const titleLine = `${safeColors.primary("\u25C6")} ${safeColors.bold(title)}`;
|
|
2305
2376
|
lines.push(titleLine);
|
|
2306
|
-
lines.push(
|
|
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(`${
|
|
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 ?
|
|
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(`${
|
|
2409
|
+
lines.push(`${safeColors.muted("\u2502")} ${dl}`);
|
|
2328
2410
|
}
|
|
2329
2411
|
}
|
|
2330
2412
|
if (i < sections.length - 1) {
|
|
2331
|
-
lines.push(
|
|
2413
|
+
lines.push(safeColors.muted("\u2502"));
|
|
2332
2414
|
}
|
|
2333
2415
|
}
|
|
2334
2416
|
if (footer || status || timing !== void 0) {
|
|
2335
|
-
lines.
|
|
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}
|
|
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 = `${
|
|
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(
|
|
2354
|
-
return safeColors.bold(
|
|
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(
|
|
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
|
|
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(
|
|
2513
|
+
function wrapText(text2, maxWidth) {
|
|
2421
2514
|
const result = [];
|
|
2422
|
-
const rawLines =
|
|
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
|
-
|
|
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
|