terminal-richjs 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -7,8 +7,6 @@ import chalk from 'chalk';
7
7
  import tinycolor from 'tinycolor2';
8
8
  import fs from 'fs';
9
9
  import hljs from 'highlight.js';
10
- import ansiEscapes from 'ansi-escapes';
11
- import cliSpinners from 'cli-spinners';
12
10
  import boxes from 'cli-boxes';
13
11
  import readline from 'readline';
14
12
  import { marked } from 'marked';
@@ -51,6 +49,12 @@ var Terminal = class {
51
49
  }
52
50
  };
53
51
  var Style = class _Style {
52
+ /**
53
+ * Apply this style to text (alias for render).
54
+ */
55
+ apply(text) {
56
+ return this.render(text);
57
+ }
54
58
  color;
55
59
  backgroundColor;
56
60
  bold;
@@ -1034,253 +1038,488 @@ function getRenderResult(renderable, console, options) {
1034
1038
  // approximation
1035
1039
  };
1036
1040
  }
1037
- var Live = class {
1038
- constructor(renderable, console, autoRefresh = true) {
1039
- this.renderable = renderable;
1040
- this.console = console;
1041
- this.autoRefresh = autoRefresh;
1041
+
1042
+ // src/status/spinners.ts
1043
+ var SPINNERS = {
1044
+ dots: {
1045
+ interval: 80,
1046
+ frames: "\u280B\u2819\u2839\u2838\u283C\u2834\u2826\u2827\u2807\u280F"
1047
+ },
1048
+ dots2: {
1049
+ interval: 80,
1050
+ frames: "\u28FE\u28FD\u28FB\u28BF\u287F\u28DF\u28EF\u28F7"
1051
+ },
1052
+ dots3: {
1053
+ interval: 80,
1054
+ frames: "\u280B\u2819\u281A\u281E\u2816\u2826\u2834\u2832\u2833\u2813"
1055
+ },
1056
+ line: {
1057
+ interval: 130,
1058
+ frames: ["-", "\\", "|", "/"]
1059
+ },
1060
+ line2: {
1061
+ interval: 100,
1062
+ frames: "\u2802-\u2013\u2014\u2013-"
1063
+ },
1064
+ pipe: {
1065
+ interval: 100,
1066
+ frames: "\u2524\u2518\u2534\u2514\u251C\u250C\u252C\u2510"
1067
+ },
1068
+ simpleDots: {
1069
+ interval: 400,
1070
+ frames: [". ", ".. ", "...", " "]
1071
+ },
1072
+ simpleDotsScrolling: {
1073
+ interval: 200,
1074
+ frames: [". ", ".. ", "...", " ..", " .", " "]
1075
+ },
1076
+ star: {
1077
+ interval: 70,
1078
+ frames: "\u2736\u2738\u2739\u273A\u2739\u2737"
1079
+ },
1080
+ star2: {
1081
+ interval: 80,
1082
+ frames: "+x*"
1083
+ },
1084
+ flip: {
1085
+ interval: 70,
1086
+ frames: "___-``'\xB4-___"
1087
+ },
1088
+ hamburger: {
1089
+ interval: 100,
1090
+ frames: "\u2631\u2632\u2634"
1091
+ },
1092
+ growVertical: {
1093
+ interval: 120,
1094
+ frames: "\u2581\u2583\u2584\u2585\u2586\u2587\u2586\u2585\u2584\u2583"
1095
+ },
1096
+ growHorizontal: {
1097
+ interval: 120,
1098
+ frames: "\u258F\u258E\u258D\u258C\u258B\u258A\u2589\u258A\u258B\u258C\u258D\u258E"
1099
+ },
1100
+ balloon: {
1101
+ interval: 140,
1102
+ frames: " .oO@* "
1103
+ },
1104
+ balloon2: {
1105
+ interval: 120,
1106
+ frames: ".oO\xB0Oo."
1107
+ },
1108
+ noise: {
1109
+ interval: 100,
1110
+ frames: "\u2593\u2592\u2591"
1111
+ },
1112
+ bounce: {
1113
+ interval: 120,
1114
+ frames: "\u2801\u2802\u2804\u2802"
1115
+ },
1116
+ boxBounce: {
1117
+ interval: 120,
1118
+ frames: "\u2596\u2598\u259D\u2597"
1119
+ },
1120
+ boxBounce2: {
1121
+ interval: 100,
1122
+ frames: "\u258C\u2580\u2590\u2584"
1123
+ },
1124
+ triangle: {
1125
+ interval: 50,
1126
+ frames: "\u25E2\u25E3\u25E4\u25E5"
1127
+ },
1128
+ arc: {
1129
+ interval: 100,
1130
+ frames: "\u25DC\u25E0\u25DD\u25DE\u25E1\u25DF"
1131
+ },
1132
+ circle: {
1133
+ interval: 120,
1134
+ frames: "\u25E1\u2299\u25E0"
1135
+ },
1136
+ squareCorners: {
1137
+ interval: 180,
1138
+ frames: "\u25F0\u25F3\u25F2\u25F1"
1139
+ },
1140
+ circleQuarters: {
1141
+ interval: 120,
1142
+ frames: "\u25F4\u25F7\u25F6\u25F5"
1143
+ },
1144
+ circleHalves: {
1145
+ interval: 50,
1146
+ frames: "\u25D0\u25D3\u25D1\u25D2"
1147
+ },
1148
+ toggle: {
1149
+ interval: 250,
1150
+ frames: "\u22B6\u22B7"
1151
+ },
1152
+ toggle2: {
1153
+ interval: 80,
1154
+ frames: "\u25AB\u25AA"
1155
+ },
1156
+ toggle3: {
1157
+ interval: 120,
1158
+ frames: "\u25A1\u25A0"
1159
+ },
1160
+ arrow: {
1161
+ interval: 100,
1162
+ frames: "\u2190\u2196\u2191\u2197\u2192\u2198\u2193\u2199"
1163
+ },
1164
+ arrow3: {
1165
+ interval: 120,
1166
+ frames: ["\u25B9\u25B9\u25B9\u25B9\u25B9", "\u25B8\u25B9\u25B9\u25B9\u25B9", "\u25B9\u25B8\u25B9\u25B9\u25B9", "\u25B9\u25B9\u25B8\u25B9\u25B9", "\u25B9\u25B9\u25B9\u25B8\u25B9", "\u25B9\u25B9\u25B9\u25B9\u25B8"]
1167
+ },
1168
+ bouncingBar: {
1169
+ interval: 80,
1170
+ frames: [
1171
+ "[ ]",
1172
+ "[= ]",
1173
+ "[== ]",
1174
+ "[=== ]",
1175
+ "[ ===]",
1176
+ "[ ==]",
1177
+ "[ =]",
1178
+ "[ ]",
1179
+ "[ =]",
1180
+ "[ ==]",
1181
+ "[ ===]",
1182
+ "[====]",
1183
+ "[=== ]",
1184
+ "[== ]",
1185
+ "[= ]"
1186
+ ]
1187
+ },
1188
+ bouncingBall: {
1189
+ interval: 80,
1190
+ frames: [
1191
+ "( \u25CF )",
1192
+ "( \u25CF )",
1193
+ "( \u25CF )",
1194
+ "( \u25CF )",
1195
+ "( \u25CF)",
1196
+ "( \u25CF )",
1197
+ "( \u25CF )",
1198
+ "( \u25CF )",
1199
+ "( \u25CF )",
1200
+ "(\u25CF )"
1201
+ ]
1202
+ },
1203
+ smiley: {
1204
+ interval: 200,
1205
+ frames: ["\u{1F604} ", "\u{1F61D} "]
1206
+ },
1207
+ monkey: {
1208
+ interval: 300,
1209
+ frames: ["\u{1F648} ", "\u{1F648} ", "\u{1F649} ", "\u{1F64A} "]
1210
+ },
1211
+ hearts: {
1212
+ interval: 100,
1213
+ frames: ["\u{1F49B} ", "\u{1F499} ", "\u{1F49C} ", "\u{1F49A} ", "\u2764\uFE0F "]
1214
+ },
1215
+ clock: {
1216
+ interval: 100,
1217
+ frames: ["\u{1F55B} ", "\u{1F550} ", "\u{1F551} ", "\u{1F552} ", "\u{1F553} ", "\u{1F554} ", "\u{1F555} ", "\u{1F556} ", "\u{1F557} ", "\u{1F558} ", "\u{1F559} ", "\u{1F55A} "]
1218
+ },
1219
+ earth: {
1220
+ interval: 180,
1221
+ frames: ["\u{1F30D} ", "\u{1F30E} ", "\u{1F30F} "]
1222
+ },
1223
+ moon: {
1224
+ interval: 80,
1225
+ frames: ["\u{1F311} ", "\u{1F312} ", "\u{1F313} ", "\u{1F314} ", "\u{1F315} ", "\u{1F316} ", "\u{1F317} ", "\u{1F318} "]
1226
+ },
1227
+ runner: {
1228
+ interval: 140,
1229
+ frames: ["\u{1F6B6} ", "\u{1F3C3} "]
1230
+ },
1231
+ weather: {
1232
+ interval: 100,
1233
+ frames: [
1234
+ "\u2600\uFE0F ",
1235
+ "\u{1F324} ",
1236
+ "\u26C5\uFE0F ",
1237
+ "\u{1F325} ",
1238
+ "\u2601\uFE0F ",
1239
+ "\u{1F327} ",
1240
+ "\u{1F328} ",
1241
+ "\u26C8 ",
1242
+ "\u{1F327} ",
1243
+ "\u2601\uFE0F ",
1244
+ "\u{1F325} ",
1245
+ "\u26C5\uFE0F ",
1246
+ "\u{1F324} ",
1247
+ "\u2600\uFE0F "
1248
+ ]
1249
+ },
1250
+ christmas: {
1251
+ interval: 400,
1252
+ frames: "\u{1F332}\u{1F384}"
1253
+ },
1254
+ point: {
1255
+ interval: 125,
1256
+ frames: ["\u2219\u2219\u2219", "\u25CF\u2219\u2219", "\u2219\u25CF\u2219", "\u2219\u2219\u25CF", "\u2219\u2219\u2219"]
1257
+ },
1258
+ layer: {
1259
+ interval: 150,
1260
+ frames: "-=\u2261"
1261
+ },
1262
+ aesthetic: {
1263
+ interval: 80,
1264
+ frames: [
1265
+ "\u25B0\u25B1\u25B1\u25B1\u25B1\u25B1\u25B1",
1266
+ "\u25B0\u25B0\u25B1\u25B1\u25B1\u25B1\u25B1",
1267
+ "\u25B0\u25B0\u25B0\u25B1\u25B1\u25B1\u25B1",
1268
+ "\u25B0\u25B0\u25B0\u25B0\u25B1\u25B1\u25B1",
1269
+ "\u25B0\u25B0\u25B0\u25B0\u25B0\u25B1\u25B1",
1270
+ "\u25B0\u25B0\u25B0\u25B0\u25B0\u25B0\u25B1",
1271
+ "\u25B0\u25B0\u25B0\u25B0\u25B0\u25B0\u25B0",
1272
+ "\u25B0\u25B1\u25B1\u25B1\u25B1\u25B1\u25B1"
1273
+ ]
1274
+ }
1275
+ };
1276
+ function getSpinner(name) {
1277
+ return SPINNERS[name];
1278
+ }
1279
+ function listSpinners() {
1280
+ return Object.keys(SPINNERS);
1281
+ }
1282
+
1283
+ // src/status/spinner.ts
1284
+ var Spinner = class {
1285
+ name;
1286
+ frames;
1287
+ interval;
1288
+ text;
1289
+ style;
1290
+ speed;
1291
+ startTime = null;
1292
+ frameNoOffset = 0;
1293
+ constructor(name = "dots", options = {}) {
1294
+ const spinner = SPINNERS[name];
1295
+ if (!spinner) {
1296
+ throw new Error(`No spinner called '${name}'. Use listSpinners() to see available spinners.`);
1297
+ }
1298
+ this.name = name;
1299
+ this.frames = typeof spinner.frames === "string" ? [...spinner.frames] : [...spinner.frames];
1300
+ this.interval = spinner.interval;
1301
+ this.text = options.text ?? "";
1302
+ this.style = options.style ?? "green";
1303
+ this.speed = options.speed ?? 1;
1304
+ }
1305
+ /**
1306
+ * Render the spinner for a given time.
1307
+ */
1308
+ render(time) {
1309
+ if (this.startTime === null) {
1310
+ this.startTime = time;
1311
+ }
1312
+ const frameNo = (time - this.startTime) * this.speed / (this.interval / 1e3) + this.frameNoOffset;
1313
+ const frame = this.frames[Math.floor(frameNo) % this.frames.length];
1314
+ const styledFrame = Style.parse(this.style).apply(frame);
1315
+ if (this.text) {
1316
+ return `${styledFrame} ${this.text}`;
1317
+ }
1318
+ return styledFrame;
1319
+ }
1320
+ /**
1321
+ * Get the current frame without time advancement (for static rendering).
1322
+ */
1323
+ getCurrentFrame() {
1324
+ const now = Date.now() / 1e3;
1325
+ return this.render(now);
1326
+ }
1327
+ /**
1328
+ * Update spinner properties.
1329
+ */
1330
+ update(options) {
1331
+ if (options.text !== void 0) this.text = options.text;
1332
+ if (options.style !== void 0) this.style = options.style;
1333
+ if (options.speed !== void 0) {
1334
+ this.frameNoOffset = this.startTime !== null ? (Date.now() / 1e3 - this.startTime) * this.speed / (this.interval / 1e3) + this.frameNoOffset : 0;
1335
+ this.startTime = Date.now() / 1e3;
1336
+ this.speed = options.speed;
1337
+ }
1338
+ }
1339
+ __rich_console__(_console, _consoleOptions) {
1340
+ const frame = this.getCurrentFrame();
1341
+ return {
1342
+ segments: [new Segment(`${frame}
1343
+ `, Style.null())],
1344
+ width: frame.length
1345
+ };
1346
+ }
1347
+ };
1348
+ function listSpinners2() {
1349
+ return Object.keys(SPINNERS);
1350
+ }
1351
+
1352
+ // src/status/status.ts
1353
+ var Status = class {
1354
+ spinner;
1355
+ message;
1356
+ interval = null;
1357
+ started = false;
1358
+ lastRenderedLines = 0;
1359
+ constructor(message, options = {}) {
1360
+ this.message = message;
1361
+ this.spinner = new Spinner(options.spinnerName ?? "dots");
1042
1362
  }
1043
- _started = false;
1044
- _lastHeight = 0;
1045
1363
  start() {
1046
- this._started = true;
1364
+ if (this.started) return;
1365
+ this.started = true;
1366
+ process.stdout.write("\x1B[?25l");
1367
+ this.interval = setInterval(() => {
1368
+ this.refresh();
1369
+ }, this.spinner.interval);
1047
1370
  this.refresh();
1048
1371
  }
1049
1372
  stop() {
1050
- this._started = false;
1051
- this.console.print("");
1373
+ if (!this.started) return;
1374
+ if (this.interval) {
1375
+ clearInterval(this.interval);
1376
+ this.interval = null;
1377
+ }
1378
+ if (this.lastRenderedLines > 0) {
1379
+ process.stdout.write(`\x1B[${this.lastRenderedLines}A`);
1380
+ for (let i = 0; i < this.lastRenderedLines; i++) {
1381
+ process.stdout.write("\x1B[2K\n");
1382
+ }
1383
+ process.stdout.write(`\x1B[${this.lastRenderedLines}A`);
1384
+ }
1385
+ process.stdout.write("\x1B[?25h");
1386
+ this.started = false;
1052
1387
  }
1053
- update(renderable) {
1054
- this.renderable = renderable;
1055
- this.refresh();
1388
+ update(message) {
1389
+ this.message = message;
1390
+ if (this.started) {
1391
+ this.refresh();
1392
+ }
1056
1393
  }
1057
1394
  refresh() {
1058
- if (!this._started) return;
1059
- if (this._lastHeight > 0) {
1060
- process.stdout.write(ansiEscapes.eraseLines(this._lastHeight));
1395
+ if (this.lastRenderedLines > 0) {
1396
+ process.stdout.write(`\x1B[${this.lastRenderedLines}A`);
1397
+ for (let i = 0; i < this.lastRenderedLines; i++) {
1398
+ process.stdout.write("\x1B[2K\n");
1399
+ }
1400
+ process.stdout.write(`\x1B[${this.lastRenderedLines}A`);
1061
1401
  }
1062
- const output = this.console.render(this.renderable);
1063
- const lines = output.split("\n").length;
1064
- this._lastHeight = lines;
1402
+ const frame = this.spinner.getCurrentFrame();
1403
+ const output = `${frame} ${this.message}
1404
+ `;
1405
+ this.lastRenderedLines = 1;
1065
1406
  process.stdout.write(output);
1066
1407
  }
1067
1408
  };
1068
- var Spinner = class {
1069
- // Type definition issues with cli-spinners
1070
- constructor(name = "dots", style = Style.null()) {
1071
- this.name = name;
1072
- this.style = style;
1073
- this.spinner = cliSpinners[name];
1409
+
1410
+ // src/console/console.ts
1411
+ var Console = class {
1412
+ error(message) {
1413
+ const text = String(message);
1414
+ process2.stderr.write(`\x1B[31m${text}\x1B[0m
1415
+ `);
1074
1416
  }
1075
- frame = 0;
1076
- // @ts-ignore
1077
- spinner;
1078
- get currentFrame() {
1079
- return this.spinner.frames[this.frame];
1417
+ terminal;
1418
+ markupParser;
1419
+ options;
1420
+ theme;
1421
+ constructor(options = {}) {
1422
+ this.options = options;
1423
+ this.terminal = new Terminal();
1424
+ this.theme = options.theme ?? DEFAULT_THEME;
1425
+ this.markupParser = new MarkupParser(this.theme);
1080
1426
  }
1081
- __rich_console__(_console, _options) {
1082
- return {
1083
- segments: [new Segment(this.currentFrame, this.style)],
1084
- width: 1
1085
- // approximates
1086
- };
1427
+ get width() {
1428
+ return this.options.width ?? this.terminal.width;
1087
1429
  }
1088
- nextFrame() {
1089
- this.frame = (this.frame + 1) % this.spinner.frames.length;
1430
+ get height() {
1431
+ return this.options.height ?? this.terminal.height;
1090
1432
  }
1091
- };
1092
-
1093
- // src/core/lines.ts
1094
- function splitLines(segments) {
1095
- const lines = [];
1096
- let currentLine = [];
1097
- for (const segment of segments) {
1098
- if (segment.text.includes("\n")) {
1099
- const parts = segment.text.split("\n");
1100
- for (let i = 0; i < parts.length; i++) {
1101
- const part = parts[i];
1102
- if (part) {
1103
- currentLine.push(new Segment(part, segment.style, segment.isControl));
1104
- }
1105
- if (i < parts.length - 1) {
1106
- lines.push(currentLine);
1107
- currentLine = [];
1108
- }
1109
- }
1110
- } else {
1111
- currentLine.push(segment);
1433
+ /**
1434
+ * Prints objects to the console.
1435
+ */
1436
+ print(...objects) {
1437
+ const lastObj = objects[objects.length - 1];
1438
+ let printObjects = objects;
1439
+ let options = {};
1440
+ if (objects.length > 1 && typeof lastObj === "object" && lastObj !== null && !isRenderable(lastObj) && ("style" in lastObj || "markup" in lastObj)) {
1441
+ options = objects.pop();
1442
+ printObjects = objects;
1112
1443
  }
1444
+ const output = printObjects.map((obj) => {
1445
+ if (typeof obj === "string") {
1446
+ return this.renderString(obj, options.markup ?? true);
1447
+ }
1448
+ if (isRenderable(obj)) {
1449
+ return this.render(obj);
1450
+ }
1451
+ return String(obj);
1452
+ }).join(" ");
1453
+ this.write(`${output}
1454
+ `);
1113
1455
  }
1114
- if (currentLine.length > 0) {
1115
- lines.push(currentLine);
1456
+ /**
1457
+ * Prints a formatted exception.
1458
+ */
1459
+ printException(error) {
1460
+ const traceback = new Traceback(error);
1461
+ this.print(traceback);
1116
1462
  }
1117
- return lines;
1118
- }
1119
- function padLine(line, width, style = Style.null()) {
1120
- const currentWidth = line.reduce((acc, s) => acc + s.cellLength(), 0);
1121
- if (currentWidth >= width) return line;
1122
- const padding = width - currentWidth;
1123
- return [...line, new Segment(" ".repeat(padding), style)];
1124
- }
1125
-
1126
- // src/layout/layout.ts
1127
- var Layout = class _Layout {
1128
- _renderable = null;
1129
- _children = [];
1130
- _direction = "column";
1131
- size;
1132
- ratio = 1;
1133
- minimumSize = 0;
1134
- visible = true;
1135
- constructor(renderable, options = {}) {
1136
- if (renderable) this._renderable = renderable;
1137
- this.size = options.size;
1138
- this.ratio = options.ratio ?? 1;
1139
- this.minimumSize = options.minimumSize ?? 0;
1140
- this.visible = options.visible ?? true;
1463
+ /**
1464
+ * Displays a status spinner.
1465
+ */
1466
+ status(message, options = {}) {
1467
+ return new Status(message, { spinnerName: options.spinner, ...options });
1141
1468
  }
1142
1469
  /**
1143
- * Split the layout into a row (horizontal split).
1470
+ * Run a task with a status spinner.
1144
1471
  */
1145
- splitRow(...layouts) {
1146
- this._direction = "row";
1147
- this._children = layouts.map((l) => l instanceof _Layout ? l : new _Layout(l));
1472
+ async withStatus(message, task, options = {}) {
1473
+ const status = new Status(message, { spinnerName: options.spinner });
1474
+ status.start();
1475
+ try {
1476
+ return await task(status);
1477
+ } finally {
1478
+ status.stop();
1479
+ }
1148
1480
  }
1149
1481
  /**
1150
- * Split the layout into a column (vertical split).
1482
+ * Renders a renderable object to a string.
1151
1483
  */
1152
- splitColumn(...layouts) {
1153
- this._direction = "column";
1154
- this._children = layouts.map((l) => l instanceof _Layout ? l : new _Layout(l));
1484
+ render(renderable) {
1485
+ const result = getRenderResult(renderable, this, this.options);
1486
+ return result.segments.map((s) => s.render()).join("");
1155
1487
  }
1156
- get renderable() {
1157
- return this._renderable;
1488
+ /**
1489
+ * Internal string rendering with markup and wrapping.
1490
+ */
1491
+ renderString(text, markup = true) {
1492
+ const segments = markup ? this.markupParser.parse(text) : [new Segment(text)];
1493
+ const rendered = segments.map((s) => s.render()).join("");
1494
+ return wrapAnsi(rendered, this.width, { hard: true });
1158
1495
  }
1159
- update(renderable) {
1160
- this._renderable = renderable;
1496
+ /**
1497
+ * Low-level write to stdout.
1498
+ */
1499
+ write(text) {
1500
+ process2.stdout.write(text);
1501
+ }
1502
+ };
1503
+ var Text = class {
1504
+ constructor(content, style = Style.null(), justify = "left", overflow = "fold", noWrap = false) {
1505
+ this.style = style;
1506
+ this.justify = justify;
1507
+ this.overflow = overflow;
1508
+ this.noWrap = noWrap;
1509
+ if (typeof content === "string") {
1510
+ const parser = new MarkupParser();
1511
+ this.segments = parser.parse(content);
1512
+ } else {
1513
+ this.segments = content;
1514
+ }
1161
1515
  }
1516
+ segments;
1162
1517
  __rich_console__(console, options) {
1163
- if (!this.visible) return { segments: [], width: 0, height: 0 };
1164
1518
  const width = options.width ?? console.width;
1165
- const height = options.height ?? console.height;
1166
- if (this._children.length === 0) {
1167
- if (this._renderable) {
1168
- return getRenderResult(this._renderable, console, { ...options, width, height });
1169
- }
1170
- return { segments: [], width, height: 0 };
1171
- }
1172
- const segments = [];
1173
- if (this._direction === "column") {
1174
- for (const child of this._children) {
1175
- if (!child.visible) continue;
1176
- const result = getRenderResult(child, console, { ...options, width });
1177
- segments.push(...result.segments);
1178
- const last = result.segments[result.segments.length - 1];
1179
- if (last && !last.text.endsWith("\n")) {
1180
- segments.push(new Segment("\n"));
1181
- }
1182
- }
1183
- } else {
1184
- const childWidths = this.calculateSizes(width, this._children);
1185
- const renderedLines = [];
1186
- let maxHeight = 0;
1187
- this._children.forEach((child, i) => {
1188
- if (!child.visible) {
1189
- renderedLines.push([]);
1190
- return;
1191
- }
1192
- const w = childWidths[i];
1193
- const result = getRenderResult(child, console, { ...options, width: w });
1194
- let childSegments = result.segments;
1195
- const lines = splitLines(childSegments);
1196
- renderedLines.push(lines);
1197
- if (lines.length > maxHeight) maxHeight = lines.length;
1198
- });
1199
- for (let y = 0; y < maxHeight; y++) {
1200
- for (let x = 0; x < this._children.length; x++) {
1201
- if (!this._children[x].visible) continue;
1202
- const lines = renderedLines[x];
1203
- const w = childWidths[x];
1204
- if (y < lines.length) {
1205
- const line = lines[y];
1206
- segments.push(...padLine(line, w));
1207
- } else {
1208
- segments.push(new Segment(" ".repeat(w)));
1209
- }
1210
- }
1211
- segments.push(new Segment("\n"));
1212
- }
1213
- }
1214
- return { segments, width, height };
1215
- }
1216
- /**
1217
- * Calculates the size (width for rows, height for columns) for each child
1218
- * based on constraints.
1219
- */
1220
- calculateSizes(availableSpace, children) {
1221
- const sizes = new Array(children.length).fill(0);
1222
- const visibleChildren = children.map((c, i) => ({ child: c, index: i })).filter((x) => x.child.visible);
1223
- if (visibleChildren.length === 0) return sizes;
1224
- let remainingSpace = availableSpace;
1225
- let totalRatio = 0;
1226
- for (const { child, index } of visibleChildren) {
1227
- if (child.size !== void 0) {
1228
- const size = Math.min(child.size, remainingSpace);
1229
- sizes[index] = size;
1230
- remainingSpace -= size;
1231
- } else if (child.minimumSize > 0) {
1232
- sizes[index] = child.minimumSize;
1233
- remainingSpace -= child.minimumSize;
1234
- }
1235
- if (child.size === void 0) {
1236
- totalRatio += child.ratio;
1237
- }
1238
- }
1239
- if (remainingSpace <= 0) return sizes;
1240
- if (totalRatio > 0) {
1241
- let distributed = 0;
1242
- for (let i = 0; i < visibleChildren.length; i++) {
1243
- const { child, index } = visibleChildren[i];
1244
- if (child.size === void 0) {
1245
- const share = Math.floor(child.ratio / totalRatio * remainingSpace);
1246
- sizes[index] += share;
1247
- distributed += share;
1248
- }
1249
- }
1250
- const dust = remainingSpace - distributed;
1251
- if (dust > 0) {
1252
- for (let i = visibleChildren.length - 1; i >= 0; i--) {
1253
- const { child, index } = visibleChildren[i];
1254
- if (child.size === void 0) {
1255
- sizes[index] += dust;
1256
- break;
1257
- }
1258
- }
1259
- }
1260
- }
1261
- return sizes;
1262
- }
1263
- };
1264
- var Text = class {
1265
- constructor(content, style = Style.null(), justify = "left", overflow = "fold", noWrap = false) {
1266
- this.style = style;
1267
- this.justify = justify;
1268
- this.overflow = overflow;
1269
- this.noWrap = noWrap;
1270
- if (typeof content === "string") {
1271
- const parser = new MarkupParser();
1272
- this.segments = parser.parse(content);
1273
- } else {
1274
- this.segments = content;
1275
- }
1276
- }
1277
- segments;
1278
- __rich_console__(console, options) {
1279
- const width = options.width ?? console.width;
1280
- const text = this.segments.map((s) => s.render()).join("");
1281
- let wrapped = text;
1282
- if (!this.noWrap) {
1283
- wrapped = wrapAnsi(text, width, { hard: true, trim: false });
1519
+ const text = this.segments.map((s) => s.render()).join("");
1520
+ let wrapped = text;
1521
+ if (!this.noWrap) {
1522
+ wrapped = wrapAnsi(text, width, { hard: true, trim: false });
1284
1523
  }
1285
1524
  const resultSegments = wrapped.split("\n").flatMap((line) => {
1286
1525
  return [new Segment(line), new Segment("\n", Style.null(), true)];
@@ -1291,131 +1530,6 @@ var Text = class {
1291
1530
  };
1292
1531
  }
1293
1532
  };
1294
-
1295
- // src/status/status.ts
1296
- var Status = class {
1297
- live;
1298
- spinner;
1299
- message;
1300
- interval = null;
1301
- constructor(message, options = {}) {
1302
- this.message = message;
1303
- this.spinner = new Spinner(options.spinner ?? "dots");
1304
- const console = options.console ?? new Console();
1305
- this.live = new Live(this.render(), console);
1306
- }
1307
- start() {
1308
- this.live.start();
1309
- this.interval = setInterval(() => {
1310
- this.spinner.nextFrame();
1311
- this.live.update(this.render());
1312
- }, 80);
1313
- }
1314
- stop() {
1315
- if (this.interval) clearInterval(this.interval);
1316
- this.live.stop();
1317
- }
1318
- update(message) {
1319
- this.message = message;
1320
- this.live.update(this.render());
1321
- }
1322
- render() {
1323
- const layout = new Layout();
1324
- layout.splitRow(
1325
- this.spinner,
1326
- new Text(" " + this.message)
1327
- );
1328
- return layout;
1329
- }
1330
- };
1331
-
1332
- // src/console/console.ts
1333
- var Console = class {
1334
- terminal;
1335
- markupParser;
1336
- options;
1337
- theme;
1338
- constructor(options = {}) {
1339
- this.options = options;
1340
- this.terminal = new Terminal();
1341
- this.theme = options.theme ?? DEFAULT_THEME;
1342
- this.markupParser = new MarkupParser(this.theme);
1343
- }
1344
- get width() {
1345
- return this.options.width ?? this.terminal.width;
1346
- }
1347
- get height() {
1348
- return this.options.height ?? this.terminal.height;
1349
- }
1350
- /**
1351
- * Prints objects to the console.
1352
- */
1353
- print(...objects) {
1354
- const lastObj = objects[objects.length - 1];
1355
- let printObjects = objects;
1356
- let options = {};
1357
- if (objects.length > 1 && typeof lastObj === "object" && lastObj !== null && !isRenderable(lastObj) && ("style" in lastObj || "markup" in lastObj)) {
1358
- options = objects.pop();
1359
- printObjects = objects;
1360
- }
1361
- const output = printObjects.map((obj) => {
1362
- if (typeof obj === "string") {
1363
- return this.renderString(obj, options.markup ?? true);
1364
- }
1365
- if (isRenderable(obj)) {
1366
- return this.render(obj);
1367
- }
1368
- return String(obj);
1369
- }).join(" ");
1370
- this.write(output + "\n");
1371
- }
1372
- /**
1373
- * Prints a formatted exception.
1374
- */
1375
- printException(error) {
1376
- const traceback = new Traceback(error);
1377
- this.print(traceback);
1378
- }
1379
- /**
1380
- * Displays a status spinner.
1381
- */
1382
- status(message, options = {}) {
1383
- return new Status(message, { console: this, ...options });
1384
- }
1385
- /**
1386
- * Run a task with a status spinner.
1387
- */
1388
- async withStatus(message, task, options = {}) {
1389
- const status = new Status(message, { console: this, ...options });
1390
- status.start();
1391
- try {
1392
- return await task(status);
1393
- } finally {
1394
- status.stop();
1395
- }
1396
- }
1397
- /**
1398
- * Renders a renderable object to a string.
1399
- */
1400
- render(renderable) {
1401
- const result = getRenderResult(renderable, this, this.options);
1402
- return result.segments.map((s) => s.render()).join("");
1403
- }
1404
- /**
1405
- * Internal string rendering with markup and wrapping.
1406
- */
1407
- renderString(text, markup = true) {
1408
- const segments = markup ? this.markupParser.parse(text) : [new Segment(text)];
1409
- const rendered = segments.map((s) => s.render()).join("");
1410
- return wrapAnsi(rendered, this.width, { hard: true });
1411
- }
1412
- /**
1413
- * Low-level write to stdout.
1414
- */
1415
- write(text) {
1416
- process2.stdout.write(text);
1417
- }
1418
- };
1419
1533
  var CUSTOM_BOXES = {
1420
1534
  // Rounded corners (may not be in all versions of cli-boxes)
1421
1535
  rounded: {
@@ -1624,6 +1738,39 @@ function listBoxStyles() {
1624
1738
  const cliBoxStyles = Object.keys(boxes);
1625
1739
  return [.../* @__PURE__ */ new Set([...customStyles, ...cliBoxStyles])];
1626
1740
  }
1741
+
1742
+ // src/core/lines.ts
1743
+ function splitLines(segments) {
1744
+ const lines = [];
1745
+ let currentLine = [];
1746
+ for (const segment of segments) {
1747
+ if (segment.text.includes("\n")) {
1748
+ const parts = segment.text.split("\n");
1749
+ for (let i = 0; i < parts.length; i++) {
1750
+ const part = parts[i];
1751
+ if (part) {
1752
+ currentLine.push(new Segment(part, segment.style, segment.isControl));
1753
+ }
1754
+ if (i < parts.length - 1) {
1755
+ lines.push(currentLine);
1756
+ currentLine = [];
1757
+ }
1758
+ }
1759
+ } else {
1760
+ currentLine.push(segment);
1761
+ }
1762
+ }
1763
+ if (currentLine.length > 0) {
1764
+ lines.push(currentLine);
1765
+ }
1766
+ return lines;
1767
+ }
1768
+ function padLine(line, width, style = Style.null()) {
1769
+ const currentWidth = line.reduce((acc, s) => acc + s.cellLength(), 0);
1770
+ if (currentWidth >= width) return line;
1771
+ const padding = width - currentWidth;
1772
+ return [...line, new Segment(" ".repeat(padding), style)];
1773
+ }
1627
1774
  var Panel = class _Panel {
1628
1775
  constructor(renderable, options = {}) {
1629
1776
  this.renderable = renderable;
@@ -2137,6 +2284,145 @@ var Tree = class _Tree {
2137
2284
  }
2138
2285
  };
2139
2286
 
2287
+ // src/layout/layout.ts
2288
+ var Layout = class _Layout {
2289
+ _renderable = null;
2290
+ _children = [];
2291
+ _direction = "column";
2292
+ size;
2293
+ ratio = 1;
2294
+ minimumSize = 0;
2295
+ visible = true;
2296
+ constructor(renderable, options = {}) {
2297
+ if (renderable) this._renderable = renderable;
2298
+ this.size = options.size;
2299
+ this.ratio = options.ratio ?? 1;
2300
+ this.minimumSize = options.minimumSize ?? 0;
2301
+ this.visible = options.visible ?? true;
2302
+ }
2303
+ /**
2304
+ * Split the layout into a row (horizontal split).
2305
+ */
2306
+ splitRow(...layouts) {
2307
+ this._direction = "row";
2308
+ this._children = layouts.map((l) => l instanceof _Layout ? l : new _Layout(l));
2309
+ }
2310
+ /**
2311
+ * Split the layout into a column (vertical split).
2312
+ */
2313
+ splitColumn(...layouts) {
2314
+ this._direction = "column";
2315
+ this._children = layouts.map((l) => l instanceof _Layout ? l : new _Layout(l));
2316
+ }
2317
+ get renderable() {
2318
+ return this._renderable;
2319
+ }
2320
+ update(renderable) {
2321
+ this._renderable = renderable;
2322
+ }
2323
+ __rich_console__(console, options) {
2324
+ if (!this.visible) return { segments: [], width: 0, height: 0 };
2325
+ const width = options.width ?? console.width;
2326
+ const height = options.height ?? console.height;
2327
+ if (this._children.length === 0) {
2328
+ if (this._renderable) {
2329
+ return getRenderResult(this._renderable, console, { ...options, width, height });
2330
+ }
2331
+ return { segments: [], width, height: 0 };
2332
+ }
2333
+ const segments = [];
2334
+ if (this._direction === "column") {
2335
+ for (const child of this._children) {
2336
+ if (!child.visible) continue;
2337
+ const result = getRenderResult(child, console, { ...options, width });
2338
+ segments.push(...result.segments);
2339
+ const last = result.segments[result.segments.length - 1];
2340
+ if (last && !last.text.endsWith("\n")) {
2341
+ segments.push(new Segment("\n"));
2342
+ }
2343
+ }
2344
+ } else {
2345
+ const childWidths = this.calculateSizes(width, this._children);
2346
+ const renderedLines = [];
2347
+ let maxHeight = 0;
2348
+ this._children.forEach((child, i) => {
2349
+ if (!child.visible) {
2350
+ renderedLines.push([]);
2351
+ return;
2352
+ }
2353
+ const w = childWidths[i];
2354
+ const result = getRenderResult(child, console, { ...options, width: w });
2355
+ let childSegments = result.segments;
2356
+ const lines = splitLines(childSegments);
2357
+ renderedLines.push(lines);
2358
+ if (lines.length > maxHeight) maxHeight = lines.length;
2359
+ });
2360
+ for (let y = 0; y < maxHeight; y++) {
2361
+ for (let x = 0; x < this._children.length; x++) {
2362
+ if (!this._children[x].visible) continue;
2363
+ const lines = renderedLines[x];
2364
+ const w = childWidths[x];
2365
+ if (y < lines.length) {
2366
+ const line = lines[y];
2367
+ segments.push(...padLine(line, w));
2368
+ } else {
2369
+ segments.push(new Segment(" ".repeat(w)));
2370
+ }
2371
+ }
2372
+ segments.push(new Segment("\n"));
2373
+ }
2374
+ }
2375
+ return { segments, width, height };
2376
+ }
2377
+ /**
2378
+ * Calculates the size (width for rows, height for columns) for each child
2379
+ * based on constraints.
2380
+ */
2381
+ calculateSizes(availableSpace, children) {
2382
+ const sizes = new Array(children.length).fill(0);
2383
+ const visibleChildren = children.map((c, i) => ({ child: c, index: i })).filter((x) => x.child.visible);
2384
+ if (visibleChildren.length === 0) return sizes;
2385
+ let remainingSpace = availableSpace;
2386
+ let totalRatio = 0;
2387
+ for (const { child, index } of visibleChildren) {
2388
+ if (child.size !== void 0) {
2389
+ const size = Math.min(child.size, remainingSpace);
2390
+ sizes[index] = size;
2391
+ remainingSpace -= size;
2392
+ } else if (child.minimumSize > 0) {
2393
+ sizes[index] = child.minimumSize;
2394
+ remainingSpace -= child.minimumSize;
2395
+ }
2396
+ if (child.size === void 0) {
2397
+ totalRatio += child.ratio;
2398
+ }
2399
+ }
2400
+ if (remainingSpace <= 0) return sizes;
2401
+ if (totalRatio > 0) {
2402
+ let distributed = 0;
2403
+ for (let i = 0; i < visibleChildren.length; i++) {
2404
+ const { child, index } = visibleChildren[i];
2405
+ if (child.size === void 0) {
2406
+ const share = Math.floor(child.ratio / totalRatio * remainingSpace);
2407
+ sizes[index] += share;
2408
+ distributed += share;
2409
+ }
2410
+ }
2411
+ const dust = remainingSpace - distributed;
2412
+ if (dust > 0) {
2413
+ for (let i = visibleChildren.length - 1; i >= 0; i--) {
2414
+ const { child, index } = visibleChildren[i];
2415
+ if (child.size === void 0) {
2416
+ sizes[index] += dust;
2417
+ break;
2418
+ }
2419
+ }
2420
+ }
2421
+ }
2422
+ return sizes;
2423
+ }
2424
+ };
2425
+
2140
2426
  // src/layout/grid.ts
2141
2427
  var Grid = class extends Layout {
2142
2428
  constructor() {
@@ -2249,6 +2535,187 @@ var Align = class _Align {
2249
2535
  return { segments, width };
2250
2536
  }
2251
2537
  };
2538
+
2539
+ // src/renderables/columns.ts
2540
+ var Columns = class {
2541
+ renderables;
2542
+ options;
2543
+ constructor(renderables = [], options = {}) {
2544
+ this.renderables = Array.from(renderables);
2545
+ this.options = {
2546
+ padding: options.padding ?? 1,
2547
+ expand: options.expand ?? false,
2548
+ equal: options.equal ?? false,
2549
+ columnFirst: options.columnFirst ?? false,
2550
+ rightToLeft: options.rightToLeft ?? false,
2551
+ ...options
2552
+ };
2553
+ }
2554
+ /**
2555
+ * Add a renderable to the columns.
2556
+ */
2557
+ add(renderable) {
2558
+ this.renderables.push(renderable);
2559
+ return this;
2560
+ }
2561
+ __rich_console__(console, consoleOptions) {
2562
+ if (this.renderables.length === 0) {
2563
+ return { segments: [], width: 0 };
2564
+ }
2565
+ const items = this.renderables.map((r) => {
2566
+ if (typeof r === "string") {
2567
+ return r;
2568
+ }
2569
+ const result = r.__rich_console__(console, consoleOptions);
2570
+ if ("segments" in result) {
2571
+ return result.segments.map((s) => s.text).join("");
2572
+ }
2573
+ return "";
2574
+ });
2575
+ const terminalWidth = consoleOptions.width ?? console.width ?? 80;
2576
+ const padding = this.options.padding ?? 1;
2577
+ const paddingStr = " ".repeat(padding);
2578
+ let columnWidth;
2579
+ if (this.options.width) {
2580
+ columnWidth = this.options.width;
2581
+ } else if (this.options.equal) {
2582
+ columnWidth = Math.max(...items.map((item) => this.getDisplayWidth(item)));
2583
+ } else {
2584
+ columnWidth = Math.max(...items.map((item) => this.getDisplayWidth(item)));
2585
+ }
2586
+ const columnCount = Math.max(
2587
+ 1,
2588
+ Math.floor((terminalWidth + padding) / (columnWidth + padding))
2589
+ );
2590
+ const lines = [];
2591
+ if (this.options.title) {
2592
+ lines.push(this.options.title);
2593
+ }
2594
+ const rows = [];
2595
+ if (this.options.columnFirst) {
2596
+ const rowCount = Math.ceil(items.length / columnCount);
2597
+ for (let row = 0; row < rowCount; row++) {
2598
+ const rowItems = [];
2599
+ for (let col = 0; col < columnCount; col++) {
2600
+ const index = col * rowCount + row;
2601
+ if (index < items.length) {
2602
+ rowItems.push(this.padItem(items[index], columnWidth));
2603
+ }
2604
+ }
2605
+ rows.push(rowItems);
2606
+ }
2607
+ } else {
2608
+ for (let i = 0; i < items.length; i += columnCount) {
2609
+ const rowItems = [];
2610
+ for (let j = 0; j < columnCount && i + j < items.length; j++) {
2611
+ rowItems.push(this.padItem(items[i + j], columnWidth));
2612
+ }
2613
+ rows.push(rowItems);
2614
+ }
2615
+ }
2616
+ for (const row of rows) {
2617
+ let rowItems = row;
2618
+ if (this.options.rightToLeft) {
2619
+ rowItems = [...row].reverse();
2620
+ }
2621
+ lines.push(rowItems.join(paddingStr));
2622
+ }
2623
+ const output = `${lines.join("\n")}
2624
+ `;
2625
+ return {
2626
+ segments: [new Segment(output, Style.null())],
2627
+ width: terminalWidth
2628
+ };
2629
+ }
2630
+ /**
2631
+ * Get the display width of a string (accounting for ANSI codes).
2632
+ */
2633
+ getDisplayWidth(text) {
2634
+ const stripped = text.replace(/\x1b\[[0-9;]*m/g, "");
2635
+ return stripped.length;
2636
+ }
2637
+ /**
2638
+ * Pad an item to the specified width.
2639
+ */
2640
+ padItem(item, width) {
2641
+ const currentWidth = this.getDisplayWidth(item);
2642
+ if (currentWidth >= width) {
2643
+ return item;
2644
+ }
2645
+ return item + " ".repeat(width - currentWidth);
2646
+ }
2647
+ };
2648
+
2649
+ // src/renderables/json.ts
2650
+ var JSON2 = class _JSON {
2651
+ text;
2652
+ highlight;
2653
+ constructor(json, options = {}) {
2654
+ const { indent = 2, sortKeys = false } = options;
2655
+ this.highlight = options.highlight ?? true;
2656
+ try {
2657
+ let data = globalThis.JSON.parse(json);
2658
+ if (sortKeys && typeof data === "object" && data !== null) {
2659
+ data = this.sortObject(data);
2660
+ }
2661
+ this.text = globalThis.JSON.stringify(data, null, indent);
2662
+ } catch {
2663
+ this.text = json;
2664
+ }
2665
+ }
2666
+ /**
2667
+ * Create JSON from any data object.
2668
+ */
2669
+ static fromData(data, options = {}) {
2670
+ const { indent = 2, sortKeys = false } = options;
2671
+ let processedData = data;
2672
+ if (sortKeys && typeof data === "object" && data !== null) {
2673
+ processedData = _JSON.prototype.sortObject(data);
2674
+ }
2675
+ const json = globalThis.JSON.stringify(processedData, null, indent);
2676
+ const instance = new _JSON(json, { ...options, sortKeys: false });
2677
+ return instance;
2678
+ }
2679
+ sortObject(obj) {
2680
+ if (Array.isArray(obj)) {
2681
+ return obj.map((item) => this.sortObject(item));
2682
+ }
2683
+ if (obj !== null && typeof obj === "object") {
2684
+ const sorted = {};
2685
+ const keys = Object.keys(obj).sort();
2686
+ for (const key of keys) {
2687
+ sorted[key] = this.sortObject(obj[key]);
2688
+ }
2689
+ return sorted;
2690
+ }
2691
+ return obj;
2692
+ }
2693
+ /**
2694
+ * Apply JSON syntax highlighting.
2695
+ */
2696
+ highlightJSON(text) {
2697
+ if (!this.highlight) {
2698
+ return text;
2699
+ }
2700
+ const highlighted = text.replace(/"([^"\\]|\\.)*"/g, (match) => {
2701
+ return Style.parse("#f1fa8c").apply(match);
2702
+ }).replace(/\b(-?\d+\.?\d*(?:e[+-]?\d+)?)\b/gi, (match) => {
2703
+ return Style.parse("#bd93f9").apply(match);
2704
+ }).replace(/\b(true|false)\b/g, (match) => {
2705
+ return match === "true" ? Style.parse("#50fa7b").apply(match) : Style.parse("#ff79c6").apply(match);
2706
+ }).replace(/\bnull\b/g, (match) => {
2707
+ return Style.parse("#8be9fd italic").apply(match);
2708
+ });
2709
+ return highlighted;
2710
+ }
2711
+ __rich_console__(_console, _consoleOptions) {
2712
+ const highlighted = this.highlightJSON(this.text);
2713
+ return {
2714
+ segments: [new Segment(highlighted + "\n", Style.null())],
2715
+ width: this.text.split("\n").reduce((max, line) => Math.max(max, line.length), 0)
2716
+ };
2717
+ }
2718
+ };
2252
2719
  var Prompt = class {
2253
2720
  static async ask(message, options = {}) {
2254
2721
  const console = options.console ?? new Console();
@@ -2403,6 +2870,9 @@ var ProgressBar = class {
2403
2870
  this.completed = completed;
2404
2871
  this.options = options;
2405
2872
  }
2873
+ render(_arg0) {
2874
+ throw new Error("Method not implemented.");
2875
+ }
2406
2876
  pulseOffset = 0;
2407
2877
  lastPulseTime = 0;
2408
2878
  __rich_console__(console, consoleOptions) {
@@ -2532,13 +3002,10 @@ var TimeRemainingColumn = class {
2532
3002
  // src/progress/progress.ts
2533
3003
  var Progress = class {
2534
3004
  tasks = [];
2535
- live;
2536
- console;
2537
3005
  taskIdCounter = 0;
2538
- constructor(options = {}) {
2539
- this.console = options.console ?? new Console();
2540
- this.live = new Live(new Layout(), this.console);
2541
- }
3006
+ started = false;
3007
+ refreshInterval = null;
3008
+ lastRenderedLines = 0;
2542
3009
  addTask(description, options = {}) {
2543
3010
  const taskId = this.taskIdCounter++;
2544
3011
  this.tasks.push({
@@ -2566,27 +3033,50 @@ var Progress = class {
2566
3033
  this.refresh();
2567
3034
  }
2568
3035
  start() {
2569
- this.live.start();
3036
+ if (this.started) return;
3037
+ this.started = true;
3038
+ process.stdout.write("\x1B[?25l");
3039
+ this.refreshInterval = setInterval(() => this.refresh(), 100);
3040
+ this.refresh();
2570
3041
  }
2571
3042
  stop() {
2572
- this.live.stop();
3043
+ if (!this.started) return;
3044
+ if (this.refreshInterval) {
3045
+ clearInterval(this.refreshInterval);
3046
+ this.refreshInterval = null;
3047
+ }
3048
+ process.stdout.write("\x1B[?25h");
3049
+ this.started = false;
2573
3050
  }
2574
3051
  refresh() {
2575
- const layout = new Layout();
2576
- const children = this.tasks.filter((t) => t.visible).map((task) => {
2577
- const row = new Layout();
2578
- row.splitRow(
2579
- new Text(task.description, void 0, "right"),
2580
- // Label
2581
- new ProgressBar(task.total, task.completed),
2582
- // Bar
2583
- new Text(`${Math.floor(task.completed / task.total * 100)}%`)
2584
- // Percent
2585
- );
2586
- return row;
2587
- });
2588
- layout.splitColumn(...children);
2589
- this.live.update(layout);
3052
+ if (!this.started) return;
3053
+ if (this.lastRenderedLines > 0) {
3054
+ process.stdout.write(`\x1B[${this.lastRenderedLines}A`);
3055
+ for (let i = 0; i < this.lastRenderedLines; i++) {
3056
+ process.stdout.write("\x1B[2K\n");
3057
+ }
3058
+ process.stdout.write(`\x1B[${this.lastRenderedLines}A`);
3059
+ }
3060
+ const lines = [];
3061
+ for (const task of this.tasks.filter((t) => t.visible)) {
3062
+ const percent = Math.floor(task.completed / task.total * 100);
3063
+ const barStr = this.renderSimpleBar(task.completed, task.total, 30);
3064
+ const percentStyle = percent >= 100 ? Style.parse("#50fa7b bold") : Style.parse("#61afef");
3065
+ lines.push(`${task.description.padEnd(20)} ${barStr} ${percentStyle.apply(`${percent}%`)}`);
3066
+ }
3067
+ const output = lines.join("\n") + "\n";
3068
+ this.lastRenderedLines = lines.length;
3069
+ process.stdout.write(output);
3070
+ }
3071
+ renderSimpleBar(completed, total, width) {
3072
+ const percentage = Math.min(1, Math.max(0, completed / total));
3073
+ const filledWidth = Math.floor(width * percentage);
3074
+ const remainingWidth = width - filledWidth;
3075
+ const filledStyle = percentage >= 1 ? Style.parse("#50fa7b bold") : Style.parse("#61afef");
3076
+ const remainingStyle = Style.parse("#3a3a3a dim");
3077
+ const filled = filledStyle.apply("\u2501".repeat(filledWidth));
3078
+ const remaining = remainingStyle.apply("\u2501".repeat(remainingWidth));
3079
+ return filled + remaining;
2590
3080
  }
2591
3081
  };
2592
3082
 
@@ -2607,6 +3097,293 @@ function* track(sequence, description = "Working...") {
2607
3097
  }
2608
3098
  }
2609
3099
 
3100
+ // src/live/live.ts
3101
+ var Live = class {
3102
+ transient;
3103
+ started = false;
3104
+ refreshThread = null;
3105
+ lastRenderedLines = 0;
3106
+ currentContent = "";
3107
+ constructor(options = {}) {
3108
+ this.transient = options.transient ?? false;
3109
+ }
3110
+ /**
3111
+ * Check if live display is currently running.
3112
+ */
3113
+ get isStarted() {
3114
+ return this.started;
3115
+ }
3116
+ /**
3117
+ * Update the displayed content.
3118
+ */
3119
+ update(content) {
3120
+ this.currentContent = content;
3121
+ }
3122
+ /**
3123
+ * Refresh the display with current content.
3124
+ */
3125
+ refresh() {
3126
+ if (!this.started) return;
3127
+ if (this.lastRenderedLines > 0) {
3128
+ process.stdout.write(`\x1B[${this.lastRenderedLines}A`);
3129
+ for (let i = 0; i < this.lastRenderedLines; i++) {
3130
+ process.stdout.write("\x1B[2K\n");
3131
+ }
3132
+ process.stdout.write(`\x1B[${this.lastRenderedLines}A`);
3133
+ }
3134
+ this.lastRenderedLines = (this.currentContent.match(/\n/g) || []).length + 1;
3135
+ process.stdout.write(`${this.currentContent}
3136
+ `);
3137
+ }
3138
+ /**
3139
+ * Start live display with a callback function.
3140
+ * The callback receives an update function to change the displayed content.
3141
+ */
3142
+ async start(callback) {
3143
+ if (this.started) {
3144
+ throw new Error("Live display already started");
3145
+ }
3146
+ this.started = true;
3147
+ process.stdout.write("\x1B[?25l");
3148
+ const updateFn = (content) => {
3149
+ this.currentContent = content;
3150
+ this.refresh();
3151
+ };
3152
+ try {
3153
+ await callback(updateFn);
3154
+ } finally {
3155
+ this.stop();
3156
+ }
3157
+ }
3158
+ /**
3159
+ * Stop live display.
3160
+ */
3161
+ stop() {
3162
+ if (!this.started) return;
3163
+ if (this.refreshThread) {
3164
+ clearInterval(this.refreshThread);
3165
+ this.refreshThread = null;
3166
+ }
3167
+ process.stdout.write("\x1B[?25h");
3168
+ if (this.transient && this.lastRenderedLines > 0) {
3169
+ process.stdout.write(`\x1B[${this.lastRenderedLines}A`);
3170
+ for (let i = 0; i < this.lastRenderedLines; i++) {
3171
+ process.stdout.write("\x1B[2K\n");
3172
+ }
3173
+ process.stdout.write(`\x1B[${this.lastRenderedLines}A`);
3174
+ }
3175
+ this.started = false;
3176
+ }
3177
+ };
3178
+ function sleep(ms) {
3179
+ return new Promise((resolve) => setTimeout(resolve, ms));
3180
+ }
3181
+
3182
+ // src/utils/emoji.ts
3183
+ var EMOJI = {
3184
+ // Common emojis
3185
+ rocket: "\u{1F680}",
3186
+ star: "\u2B50",
3187
+ sparkles: "\u2728",
3188
+ fire: "\u{1F525}",
3189
+ heart: "\u2764\uFE0F",
3190
+ thumbs_up: "\u{1F44D}",
3191
+ thumbs_down: "\u{1F44E}",
3192
+ clap: "\u{1F44F}",
3193
+ wave: "\u{1F44B}",
3194
+ ok_hand: "\u{1F44C}",
3195
+ // Faces
3196
+ smile: "\u{1F60A}",
3197
+ grin: "\u{1F601}",
3198
+ joy: "\u{1F602}",
3199
+ wink: "\u{1F609}",
3200
+ thinking: "\u{1F914}",
3201
+ sunglasses: "\u{1F60E}",
3202
+ heart_eyes: "\u{1F60D}",
3203
+ sob: "\u{1F62D}",
3204
+ angry: "\u{1F620}",
3205
+ scream: "\u{1F631}",
3206
+ skull: "\u{1F480}",
3207
+ ghost: "\u{1F47B}",
3208
+ robot: "\u{1F916}",
3209
+ // Status
3210
+ check: "\u2705",
3211
+ check_mark: "\u2714\uFE0F",
3212
+ x: "\u274C",
3213
+ cross_mark: "\u274C",
3214
+ warning: "\u26A0\uFE0F",
3215
+ exclamation: "\u2757",
3216
+ question: "\u2753",
3217
+ info: "\u2139\uFE0F",
3218
+ bulb: "\u{1F4A1}",
3219
+ gear: "\u2699\uFE0F",
3220
+ wrench: "\u{1F527}",
3221
+ hammer: "\u{1F528}",
3222
+ bug: "\u{1F41B}",
3223
+ construction: "\u{1F6A7}",
3224
+ // Weather & Nature
3225
+ sun: "\u2600\uFE0F",
3226
+ moon: "\u{1F319}",
3227
+ cloud: "\u2601\uFE0F",
3228
+ rain: "\u{1F327}\uFE0F",
3229
+ snow: "\u2744\uFE0F",
3230
+ thunder: "\u26A1",
3231
+ rainbow: "\u{1F308}",
3232
+ tree: "\u{1F333}",
3233
+ flower: "\u{1F338}",
3234
+ leaf: "\u{1F343}",
3235
+ // Objects
3236
+ book: "\u{1F4D6}",
3237
+ books: "\u{1F4DA}",
3238
+ pencil: "\u270F\uFE0F",
3239
+ pen: "\u{1F58A}\uFE0F",
3240
+ clipboard: "\u{1F4CB}",
3241
+ folder: "\u{1F4C1}",
3242
+ file_folder: "\u{1F4C1}",
3243
+ package: "\u{1F4E6}",
3244
+ inbox: "\u{1F4E5}",
3245
+ outbox: "\u{1F4E4}",
3246
+ email: "\u{1F4E7}",
3247
+ computer: "\u{1F4BB}",
3248
+ keyboard: "\u2328\uFE0F",
3249
+ phone: "\u{1F4F1}",
3250
+ camera: "\u{1F4F7}",
3251
+ video_camera: "\u{1F4F9}",
3252
+ clock: "\u{1F550}",
3253
+ hourglass: "\u23F3",
3254
+ key: "\u{1F511}",
3255
+ lock: "\u{1F512}",
3256
+ unlock: "\u{1F513}",
3257
+ link: "\u{1F517}",
3258
+ trophy: "\u{1F3C6}",
3259
+ medal: "\u{1F3C5}",
3260
+ crown: "\u{1F451}",
3261
+ gem: "\u{1F48E}",
3262
+ money: "\u{1F4B0}",
3263
+ coin: "\u{1FA99}",
3264
+ // Arrows & Symbols
3265
+ arrow_right: "\u27A1\uFE0F",
3266
+ arrow_left: "\u2B05\uFE0F",
3267
+ arrow_up: "\u2B06\uFE0F",
3268
+ arrow_down: "\u2B07\uFE0F",
3269
+ arrow_forward: "\u25B6\uFE0F",
3270
+ arrow_backward: "\u25C0\uFE0F",
3271
+ play: "\u25B6\uFE0F",
3272
+ pause: "\u23F8\uFE0F",
3273
+ stop: "\u23F9\uFE0F",
3274
+ refresh: "\u{1F504}",
3275
+ plus: "\u2795",
3276
+ minus: "\u2796",
3277
+ // Animals
3278
+ dog: "\u{1F415}",
3279
+ cat: "\u{1F408}",
3280
+ bird: "\u{1F426}",
3281
+ fish: "\u{1F41F}",
3282
+ butterfly: "\u{1F98B}",
3283
+ bee: "\u{1F41D}",
3284
+ snake: "\u{1F40D}",
3285
+ turtle: "\u{1F422}",
3286
+ crab: "\u{1F980}",
3287
+ octopus: "\u{1F419}",
3288
+ unicorn: "\u{1F984}",
3289
+ dragon: "\u{1F409}",
3290
+ // Food & Drink
3291
+ coffee: "\u2615",
3292
+ tea: "\u{1F375}",
3293
+ beer: "\u{1F37A}",
3294
+ wine: "\u{1F377}",
3295
+ pizza: "\u{1F355}",
3296
+ burger: "\u{1F354}",
3297
+ fries: "\u{1F35F}",
3298
+ taco: "\u{1F32E}",
3299
+ sushi: "\u{1F363}",
3300
+ apple: "\u{1F34E}",
3301
+ banana: "\u{1F34C}",
3302
+ cake: "\u{1F382}",
3303
+ cookie: "\u{1F36A}",
3304
+ // Celebrations
3305
+ party: "\u{1F389}",
3306
+ balloon: "\u{1F388}",
3307
+ confetti: "\u{1F38A}",
3308
+ gift: "\u{1F381}",
3309
+ christmas_tree: "\u{1F384}",
3310
+ fireworks: "\u{1F386}",
3311
+ // Hands
3312
+ point_up: "\u261D\uFE0F",
3313
+ point_down: "\u{1F447}",
3314
+ point_left: "\u{1F448}",
3315
+ point_right: "\u{1F449}",
3316
+ raised_hand: "\u270B",
3317
+ fist: "\u270A",
3318
+ v: "\u270C\uFE0F",
3319
+ muscle: "\u{1F4AA}",
3320
+ pray: "\u{1F64F}",
3321
+ // Transport
3322
+ car: "\u{1F697}",
3323
+ bus: "\u{1F68C}",
3324
+ train: "\u{1F686}",
3325
+ plane: "\u2708\uFE0F",
3326
+ ship: "\u{1F6A2}",
3327
+ bike: "\u{1F6B2}",
3328
+ // Places
3329
+ house: "\u{1F3E0}",
3330
+ office: "\u{1F3E2}",
3331
+ hospital: "\u{1F3E5}",
3332
+ school: "\u{1F3EB}",
3333
+ globe: "\u{1F30D}",
3334
+ earth: "\u{1F30D}",
3335
+ earth_americas: "\u{1F30E}",
3336
+ earth_asia: "\u{1F30F}",
3337
+ // Colors
3338
+ red_circle: "\u{1F534}",
3339
+ orange_circle: "\u{1F7E0}",
3340
+ yellow_circle: "\u{1F7E1}",
3341
+ green_circle: "\u{1F7E2}",
3342
+ blue_circle: "\u{1F535}",
3343
+ purple_circle: "\u{1F7E3}",
3344
+ white_circle: "\u26AA",
3345
+ black_circle: "\u26AB",
3346
+ // Misc
3347
+ zap: "\u26A1",
3348
+ boom: "\u{1F4A5}",
3349
+ hundred: "\u{1F4AF}",
3350
+ zzz: "\u{1F4A4}",
3351
+ speech_balloon: "\u{1F4AC}",
3352
+ thought_balloon: "\u{1F4AD}",
3353
+ mega: "\u{1F4E3}",
3354
+ bell: "\u{1F514}",
3355
+ pin: "\u{1F4CC}",
3356
+ scissors: "\u2702\uFE0F",
3357
+ art: "\u{1F3A8}",
3358
+ music: "\u{1F3B5}",
3359
+ notes: "\u{1F3B6}",
3360
+ mic: "\u{1F3A4}",
3361
+ headphones: "\u{1F3A7}",
3362
+ game: "\u{1F3AE}",
3363
+ dice: "\u{1F3B2}",
3364
+ // Programming
3365
+ terminal: "\u{1F4BB}",
3366
+ code: "\u{1F4BB}",
3367
+ database: "\u{1F5C4}\uFE0F",
3368
+ api: "\u{1F50C}",
3369
+ test_tube: "\u{1F9EA}",
3370
+ microscope: "\u{1F52C}",
3371
+ satellite: "\u{1F6F0}\uFE0F",
3372
+ atom: "\u269B\uFE0F"
3373
+ };
3374
+ function replaceEmoji(text) {
3375
+ return text.replace(/:([a-z0-9_]+):/gi, (match, name) => {
3376
+ const emoji = EMOJI[name.toLowerCase()];
3377
+ return emoji ?? match;
3378
+ });
3379
+ }
3380
+ function listEmoji() {
3381
+ return Object.keys(EMOJI);
3382
+ }
3383
+ function hasEmoji(name) {
3384
+ return name.toLowerCase() in EMOJI;
3385
+ }
3386
+
2610
3387
  // src/logging/logger.ts
2611
3388
  var Logger = class {
2612
3389
  handler;
@@ -2669,6 +3446,6 @@ function inspect(obj, options = {}) {
2669
3446
  var globalConsole = new Console();
2670
3447
  var print = globalConsole.print.bind(globalConsole);
2671
3448
 
2672
- export { Align, Color, Confirm, Console, DEFAULT_THEME, DRACULA, GITHUB_LIGHT, Grid, Layout, Logger, MONOKAI, MONOKAI_THEME, Markdown, MarkupParser, ONE_DARK, Padding, Palette, Panel, PercentageColumn, Progress, ProgressBar, Prompt, RichHandler, Rule, SYNTAX_THEMES, Segment, Spinner, Status, Style, Syntax, Table, Text, Theme, TimeElapsedColumn, TimeRemainingColumn, Traceback, Tree, getBox, getTheme, inspect, install, installTracebackHandler, isRenderable, listBoxStyles, print, track };
3449
+ export { Align, Color, Columns, Confirm, Console, DEFAULT_THEME, DRACULA, EMOJI, GITHUB_LIGHT, Grid, JSON2 as JSON, Layout, Live, Logger, MONOKAI, MONOKAI_THEME, Markdown, MarkupParser, ONE_DARK, Padding, Palette, Panel, PercentageColumn, Progress, ProgressBar, Prompt, RichHandler, Rule, SPINNERS, SYNTAX_THEMES, Segment, Spinner, Status, Style, Syntax, Table, Text, Theme, TimeElapsedColumn, TimeRemainingColumn, Traceback, Tree, getBox, getSpinner, listSpinners as getSpinnerNames, getTheme, hasEmoji, inspect, install, installTracebackHandler, isRenderable, listBoxStyles, listEmoji, listSpinners2 as listSpinners, print, replaceEmoji, sleep, track };
2673
3450
  //# sourceMappingURL=index.js.map
2674
3451
  //# sourceMappingURL=index.js.map