@rotorsoft/gent 1.17.1 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2221,7 +2221,7 @@ import { homedir } from "os";
2221
2221
  // package.json
2222
2222
  var package_default = {
2223
2223
  name: "@rotorsoft/gent",
2224
- version: "1.17.1",
2224
+ version: "1.18.0",
2225
2225
  description: "AI-powered GitHub workflow CLI - leverage AI (Claude, Gemini, or Codex) to create tickets, implement features, and manage PRs",
2226
2226
  keywords: [
2227
2227
  "cli",
@@ -3109,142 +3109,9 @@ function clearScreen() {
3109
3109
  }
3110
3110
 
3111
3111
  // src/tui/modal.ts
3112
- import chalk4 from "chalk";
3113
- function modalTopRow(title, w) {
3114
- const label = ` ${title} `;
3115
- const fill = w - 2 - label.length;
3116
- return chalk4.bold("\u250C") + chalk4.bold.cyan(label) + chalk4.bold("\u2500".repeat(Math.max(0, fill)) + "\u2510");
3117
- }
3118
- function modalDivRow(w) {
3119
- return chalk4.bold("\u251C" + "\u2500".repeat(w - 2) + "\u2524");
3120
- }
3121
- function modalBotRow(w) {
3122
- return chalk4.bold("\u2514" + "\u2500".repeat(w - 2) + "\u2518");
3123
- }
3124
- function modalRow(text, w) {
3125
- const inner = w - 4;
3126
- const fitted = truncateAnsi(text, inner);
3127
- const pad = Math.max(0, inner - visibleLen(fitted));
3128
- return chalk4.bold("\u2502") + " " + fitted + " ".repeat(pad) + " " + chalk4.bold("\u2502");
3129
- }
3130
- function modalEmptyRow(w) {
3131
- return modalRow("", w);
3132
- }
3133
- function buildModalFrame(title, contentLines, footerText, width) {
3134
- const lines = [];
3135
- lines.push(modalTopRow(title, width));
3136
- lines.push(modalEmptyRow(width));
3137
- for (const line of contentLines) {
3138
- lines.push(modalRow(line, width));
3139
- }
3140
- lines.push(modalEmptyRow(width));
3141
- lines.push(modalDivRow(width));
3142
- lines.push(modalRow(chalk4.dim(footerText), width));
3143
- lines.push(modalBotRow(width));
3144
- return lines;
3145
- }
3146
- function isSeparator(entry) {
3147
- return "separator" in entry;
3148
- }
3149
- function buildSelectContent(items, selectedIndex, maxWidth, currentIndex) {
3150
- const lines = [];
3151
- let selectableIdx = 0;
3152
- for (const item of items) {
3153
- if (isSeparator(item)) {
3154
- lines.push(chalk4.dim(item.separator));
3155
- } else {
3156
- const isSelected = selectableIdx === selectedIndex;
3157
- const isCurrent = currentIndex != null && selectableIdx === currentIndex;
3158
- const prefix = isSelected ? chalk4.cyan.bold("> ") : " ";
3159
- const bullet = chalk4.dim("\xB7 ");
3160
- const label = truncateAnsi(item.name, maxWidth - 4);
3161
- const styledLabel = isSelected ? chalk4.bold(label) : isCurrent ? chalk4.cyan(label) : label;
3162
- lines.push(prefix + bullet + styledLabel);
3163
- selectableIdx++;
3164
- }
3165
- }
3166
- return lines;
3167
- }
3168
- function buildConfirmContent(message, selectedYes) {
3169
- const yes = selectedYes ? chalk4.cyan.bold("> Yes") : chalk4.dim(" Yes");
3170
- const no = !selectedYes ? chalk4.cyan.bold("> No") : chalk4.dim(" No");
3171
- return [message, "", yes, no];
3172
- }
3173
- function buildInputContent(label, value, cursorVisible) {
3174
- const cursor = cursorVisible ? chalk4.cyan("_") : " ";
3175
- return [label, "", chalk4.cyan("> ") + value + cursor];
3176
- }
3177
- function buildMultilineInputContent(label, value, cursorVisible, maxWidth) {
3178
- const cursor = cursorVisible ? chalk4.cyan("_") : " ";
3179
- const lines = [label, ""];
3180
- if (value === "") {
3181
- lines.push(chalk4.cyan(" ") + cursor);
3182
- } else {
3183
- const inputLines = value.split("\n");
3184
- const contentWidth = maxWidth - 2;
3185
- for (let i = 0; i < inputLines.length; i++) {
3186
- const raw = inputLines[i];
3187
- const wrapped = wrapLine(raw, contentWidth);
3188
- for (let j = 0; j < wrapped.length; j++) {
3189
- const isLastLine = i === inputLines.length - 1 && j === wrapped.length - 1;
3190
- const text = wrapped[j] + (isLastLine ? cursor : "");
3191
- lines.push(chalk4.cyan(" ") + text);
3192
- }
3193
- }
3194
- }
3195
- return lines;
3196
- }
3197
- function wrapLine(text, width) {
3198
- if (width <= 0) return [text];
3199
- if (text.length <= width) return [text];
3200
- const result = [];
3201
- let remaining = text;
3202
- while (remaining.length > width) {
3203
- let breakAt = remaining.lastIndexOf(" ", width);
3204
- if (breakAt <= 0) breakAt = width;
3205
- result.push(remaining.slice(0, breakAt));
3206
- remaining = remaining.slice(breakAt).replace(/^ /, "");
3207
- }
3208
- if (remaining.length > 0 || result.length === 0) {
3209
- result.push(remaining);
3210
- }
3211
- return result;
3212
- }
3213
- function termSize() {
3214
- return {
3215
- cols: process.stdout.columns || 80,
3216
- rows: process.stdout.rows || 24
3217
- };
3218
- }
3219
- function moveTo(row2, col) {
3220
- return `\x1B[${row2};${col}H`;
3221
- }
3222
- function hideCursor() {
3223
- return "\x1B[?25l";
3224
- }
3225
- function showCursor() {
3226
- return "\x1B[?25h";
3227
- }
3228
- function modalWidth() {
3229
- const cols = process.stdout.columns || 80;
3230
- return Math.min(60, cols - 4);
3231
- }
3232
- function renderOverlay(dashboardLines, modalLines, mWidth) {
3233
- const { cols, rows } = termSize();
3234
- process.stdout.write("\x1B[2J\x1B[0f");
3235
- process.stdout.write(hideCursor());
3236
- for (let i = 0; i < dashboardLines.length && i < rows; i++) {
3237
- process.stdout.write(
3238
- moveTo(i + 1, 1) + chalk4.dim(stripAnsi(dashboardLines[i]))
3239
- );
3240
- }
3241
- const startRow = Math.max(1, Math.floor((rows - modalLines.length) / 2));
3242
- const startCol = Math.max(1, Math.floor((cols - mWidth) / 2));
3243
- for (let i = 0; i < modalLines.length; i++) {
3244
- process.stdout.write(moveTo(startRow + i, startCol) + modalLines[i]);
3245
- }
3246
- process.stdout.write(moveTo(startRow + modalLines.length + 1, 1));
3247
- }
3112
+ import chalk8 from "chalk";
3113
+
3114
+ // src/tui/key-reader.ts
3248
3115
  function readKey() {
3249
3116
  return new Promise((resolve) => {
3250
3117
  const { stdin } = process;
@@ -3268,6 +3135,20 @@ function readKey() {
3268
3135
  resolve({ name: "right", raw: data });
3269
3136
  } else if (data === "\x1B[D") {
3270
3137
  resolve({ name: "left", raw: data });
3138
+ } else if (data === "\x1B[1;5C" || data === "\x1B[5C") {
3139
+ resolve({ name: "ctrl-right", raw: data });
3140
+ } else if (data === "\x1B[1;5D" || data === "\x1B[5D") {
3141
+ resolve({ name: "ctrl-left", raw: data });
3142
+ } else if (data === "\x1B[3~") {
3143
+ resolve({ name: "delete", raw: data });
3144
+ } else if (data === "\x1B[H" || data === "\x1B[1~") {
3145
+ resolve({ name: "home", raw: data });
3146
+ } else if (data === "\x1B[F" || data === "\x1B[4~") {
3147
+ resolve({ name: "end", raw: data });
3148
+ } else if (data === "") {
3149
+ resolve({ name: "home", raw: data });
3150
+ } else if (data === "") {
3151
+ resolve({ name: "end", raw: data });
3271
3152
  } else if (data === "\r" || data === "\n") {
3272
3153
  resolve({ name: "enter", raw: data });
3273
3154
  } else if (data === "\x7F" || data === "\b") {
@@ -3287,39 +3168,30 @@ function readKey() {
3287
3168
  stdin.on("data", onData);
3288
3169
  });
3289
3170
  }
3290
- async function showConfirm(opts) {
3291
- const w = modalWidth();
3292
- let selectedYes = true;
3293
- const render = () => {
3294
- const content = buildConfirmContent(opts.message, selectedYes);
3295
- const footer = "\u2191\u2193 Select Enter Confirm Esc Cancel";
3296
- const lines = buildModalFrame(opts.title, content, footer, w);
3297
- renderOverlay(opts.dashboardLines, lines, w);
3298
- };
3299
- render();
3300
- while (true) {
3301
- const key = await readKey();
3302
- switch (key.name) {
3303
- case "up":
3304
- case "down":
3305
- case "tab":
3306
- selectedYes = !selectedYes;
3307
- render();
3308
- break;
3309
- case "enter":
3310
- process.stdout.write(showCursor());
3311
- return selectedYes;
3312
- case "escape":
3313
- process.stdout.write(showCursor());
3314
- return false;
3315
- case "y":
3316
- process.stdout.write(showCursor());
3317
- return true;
3318
- case "n":
3319
- process.stdout.write(showCursor());
3320
- return false;
3171
+
3172
+ // src/tui/select-dialog.ts
3173
+ import chalk4 from "chalk";
3174
+ function isSeparator(entry) {
3175
+ return "separator" in entry;
3176
+ }
3177
+ function buildSelectContent(items, selectedIndex, maxWidth, currentIndex) {
3178
+ const lines = [];
3179
+ let selectableIdx = 0;
3180
+ for (const item of items) {
3181
+ if (isSeparator(item)) {
3182
+ lines.push(chalk4.dim(item.separator));
3183
+ } else {
3184
+ const isSelected = selectableIdx === selectedIndex;
3185
+ const isCurrent = currentIndex != null && selectableIdx === currentIndex;
3186
+ const prefix = isSelected ? chalk4.cyan.bold("> ") : " ";
3187
+ const bullet = chalk4.dim("\xB7 ");
3188
+ const label = truncateAnsi(item.name, maxWidth - 4);
3189
+ const styledLabel = isSelected ? chalk4.bold(label) : isCurrent ? chalk4.cyan(label) : label;
3190
+ lines.push(prefix + bullet + styledLabel);
3191
+ selectableIdx++;
3321
3192
  }
3322
3193
  }
3194
+ return lines;
3323
3195
  }
3324
3196
  function selectableCount(items) {
3325
3197
  return items.filter((i) => !isSeparator(i)).length;
@@ -3364,6 +3236,55 @@ async function showSelect(opts) {
3364
3236
  }
3365
3237
  }
3366
3238
  }
3239
+
3240
+ // src/tui/confirm-dialog.ts
3241
+ import chalk5 from "chalk";
3242
+ function buildConfirmContent(message, selectedYes) {
3243
+ const yes = selectedYes ? chalk5.cyan.bold("> Yes") : chalk5.dim(" Yes");
3244
+ const no = !selectedYes ? chalk5.cyan.bold("> No") : chalk5.dim(" No");
3245
+ return [message, "", yes, no];
3246
+ }
3247
+ async function showConfirm(opts) {
3248
+ const w = modalWidth();
3249
+ let selectedYes = true;
3250
+ const render = () => {
3251
+ const content = buildConfirmContent(opts.message, selectedYes);
3252
+ const footer = "\u2191\u2193 Select Enter Confirm Esc Cancel";
3253
+ const lines = buildModalFrame(opts.title, content, footer, w);
3254
+ renderOverlay(opts.dashboardLines, lines, w);
3255
+ };
3256
+ render();
3257
+ while (true) {
3258
+ const key = await readKey();
3259
+ switch (key.name) {
3260
+ case "up":
3261
+ case "down":
3262
+ case "tab":
3263
+ selectedYes = !selectedYes;
3264
+ render();
3265
+ break;
3266
+ case "enter":
3267
+ process.stdout.write(showCursor());
3268
+ return selectedYes;
3269
+ case "escape":
3270
+ process.stdout.write(showCursor());
3271
+ return false;
3272
+ case "y":
3273
+ process.stdout.write(showCursor());
3274
+ return true;
3275
+ case "n":
3276
+ process.stdout.write(showCursor());
3277
+ return false;
3278
+ }
3279
+ }
3280
+ }
3281
+
3282
+ // src/tui/input-dialog.ts
3283
+ import chalk6 from "chalk";
3284
+ function buildInputContent(label, value, cursorVisible) {
3285
+ const cursorChar = cursorVisible ? chalk6.inverse(" ") : "";
3286
+ return [label, "", chalk6.cyan("> ") + value + cursorChar];
3287
+ }
3367
3288
  async function showInput(opts) {
3368
3289
  const w = modalWidth();
3369
3290
  let value = "";
@@ -3402,9 +3323,115 @@ async function showInput(opts) {
3402
3323
  }
3403
3324
  }
3404
3325
  }
3326
+
3327
+ // src/tui/multiline-input.ts
3328
+ import chalk7 from "chalk";
3329
+ function wrapLineWithMap(text, width) {
3330
+ if (width <= 0) return [{ text, offset: 0 }];
3331
+ if (text.length <= width) return [{ text, offset: 0 }];
3332
+ const result = [];
3333
+ let pos = 0;
3334
+ let remaining = text;
3335
+ while (remaining.length > width) {
3336
+ let breakAt = remaining.lastIndexOf(" ", width);
3337
+ if (breakAt <= 0) breakAt = width;
3338
+ result.push({ text: remaining.slice(0, breakAt), offset: pos });
3339
+ pos += breakAt;
3340
+ remaining = remaining.slice(breakAt);
3341
+ if (remaining.startsWith(" ")) {
3342
+ remaining = remaining.slice(1);
3343
+ pos += 1;
3344
+ }
3345
+ }
3346
+ if (remaining.length > 0 || result.length === 0) {
3347
+ result.push({ text: remaining, offset: pos });
3348
+ }
3349
+ return result;
3350
+ }
3351
+ function getVisualLines(value, contentWidth) {
3352
+ const inputLines = value.split("\n");
3353
+ const result = [];
3354
+ let globalPos = 0;
3355
+ for (let i = 0; i < inputLines.length; i++) {
3356
+ const raw = inputLines[i];
3357
+ const wrapped = wrapLineWithMap(raw, contentWidth);
3358
+ for (const seg of wrapped) {
3359
+ result.push({
3360
+ text: seg.text,
3361
+ globalOffset: globalPos + seg.offset,
3362
+ length: seg.text.length
3363
+ });
3364
+ }
3365
+ globalPos += raw.length + 1;
3366
+ }
3367
+ return result;
3368
+ }
3369
+ function findCursorVisualPos(visualLines, cursorPos) {
3370
+ for (let i = 0; i < visualLines.length; i++) {
3371
+ const vl = visualLines[i];
3372
+ if (cursorPos >= vl.globalOffset && cursorPos <= vl.globalOffset + vl.length) {
3373
+ return { row: i, col: cursorPos - vl.globalOffset };
3374
+ }
3375
+ }
3376
+ const last = visualLines[visualLines.length - 1];
3377
+ return { row: visualLines.length - 1, col: last.length };
3378
+ }
3379
+ function moveCursorVertical(value, cursorPos, contentWidth, direction) {
3380
+ const visualLines = getVisualLines(value, contentWidth);
3381
+ const { row: row2, col } = findCursorVisualPos(visualLines, cursorPos);
3382
+ const newRow = row2 + direction;
3383
+ if (newRow < 0 || newRow >= visualLines.length) return cursorPos;
3384
+ const targetLine = visualLines[newRow];
3385
+ const newCol = Math.min(col, targetLine.length);
3386
+ return targetLine.globalOffset + newCol;
3387
+ }
3388
+ function moveCursorHome(value, cursorPos, contentWidth) {
3389
+ const visualLines = getVisualLines(value, contentWidth);
3390
+ const { row: row2 } = findCursorVisualPos(visualLines, cursorPos);
3391
+ return visualLines[row2].globalOffset;
3392
+ }
3393
+ function moveCursorEnd(value, cursorPos, contentWidth) {
3394
+ const visualLines = getVisualLines(value, contentWidth);
3395
+ const { row: row2 } = findCursorVisualPos(visualLines, cursorPos);
3396
+ return visualLines[row2].globalOffset + visualLines[row2].length;
3397
+ }
3398
+ function moveCursorWordLeft(value, cursorPos) {
3399
+ if (cursorPos <= 0) return 0;
3400
+ let pos = cursorPos - 1;
3401
+ while (pos > 0 && !/\w/.test(value[pos])) pos--;
3402
+ while (pos > 0 && /\w/.test(value[pos - 1])) pos--;
3403
+ return pos;
3404
+ }
3405
+ function moveCursorWordRight(value, cursorPos) {
3406
+ if (cursorPos >= value.length) return value.length;
3407
+ let pos = cursorPos;
3408
+ while (pos < value.length && /\w/.test(value[pos])) pos++;
3409
+ while (pos < value.length && !/\w/.test(value[pos])) pos++;
3410
+ return pos;
3411
+ }
3412
+ function buildMultilineInputContent(label, value, cursorVisible, maxWidth, cursorPos) {
3413
+ const cp = cursorPos ?? value.length;
3414
+ const lines = [label, ""];
3415
+ const contentWidth = maxWidth - 2;
3416
+ const visualLines = getVisualLines(value, contentWidth);
3417
+ const { row: cursorRow, col: cursorCol } = findCursorVisualPos(visualLines, cp);
3418
+ for (let i = 0; i < visualLines.length; i++) {
3419
+ const text = visualLines[i].text;
3420
+ if (i === cursorRow && cursorVisible) {
3421
+ const charUnderCursor = cursorCol < text.length ? text[cursorCol] : " ";
3422
+ lines.push(
3423
+ chalk7.cyan(" ") + text.slice(0, cursorCol) + chalk7.inverse(charUnderCursor) + text.slice(cursorCol + 1)
3424
+ );
3425
+ } else {
3426
+ lines.push(chalk7.cyan(" ") + text);
3427
+ }
3428
+ }
3429
+ return lines;
3430
+ }
3405
3431
  async function showMultilineInput(opts) {
3406
3432
  const w = modalWidth();
3407
3433
  let value = "";
3434
+ let cursorPos = 0;
3408
3435
  let cursorBlink = true;
3409
3436
  const contentWidth = w - 6;
3410
3437
  const render = () => {
@@ -3412,7 +3439,8 @@ async function showMultilineInput(opts) {
3412
3439
  opts.label,
3413
3440
  value,
3414
3441
  cursorBlink,
3415
- contentWidth
3442
+ contentWidth,
3443
+ cursorPos
3416
3444
  );
3417
3445
  const footer = "Enter Newline Ctrl+S Submit Esc Cancel";
3418
3446
  const lines = buildModalFrame(opts.title, content, footer, w);
@@ -3426,7 +3454,8 @@ async function showMultilineInput(opts) {
3426
3454
  process.stdout.write(showCursor());
3427
3455
  return value.trim() || null;
3428
3456
  case "enter":
3429
- value += "\n";
3457
+ value = value.slice(0, cursorPos) + "\n" + value.slice(cursorPos);
3458
+ cursorPos++;
3430
3459
  cursorBlink = true;
3431
3460
  render();
3432
3461
  break;
@@ -3434,14 +3463,54 @@ async function showMultilineInput(opts) {
3434
3463
  process.stdout.write(showCursor());
3435
3464
  return null;
3436
3465
  case "backspace":
3437
- if (value.length > 0) {
3438
- value = value.slice(0, -1);
3466
+ if (cursorPos > 0) {
3467
+ value = value.slice(0, cursorPos - 1) + value.slice(cursorPos);
3468
+ cursorPos--;
3469
+ }
3470
+ render();
3471
+ break;
3472
+ case "delete":
3473
+ if (cursorPos < value.length) {
3474
+ value = value.slice(0, cursorPos) + value.slice(cursorPos + 1);
3439
3475
  }
3440
3476
  render();
3441
3477
  break;
3478
+ case "left":
3479
+ if (cursorPos > 0) cursorPos--;
3480
+ render();
3481
+ break;
3482
+ case "right":
3483
+ if (cursorPos < value.length) cursorPos++;
3484
+ render();
3485
+ break;
3486
+ case "up":
3487
+ cursorPos = moveCursorVertical(value, cursorPos, contentWidth - 2, -1);
3488
+ render();
3489
+ break;
3490
+ case "down":
3491
+ cursorPos = moveCursorVertical(value, cursorPos, contentWidth - 2, 1);
3492
+ render();
3493
+ break;
3494
+ case "home":
3495
+ cursorPos = moveCursorHome(value, cursorPos, contentWidth - 2);
3496
+ render();
3497
+ break;
3498
+ case "end":
3499
+ cursorPos = moveCursorEnd(value, cursorPos, contentWidth - 2);
3500
+ render();
3501
+ break;
3502
+ case "ctrl-left":
3503
+ cursorPos = moveCursorWordLeft(value, cursorPos);
3504
+ render();
3505
+ break;
3506
+ case "ctrl-right":
3507
+ cursorPos = moveCursorWordRight(value, cursorPos);
3508
+ render();
3509
+ break;
3442
3510
  default:
3443
3511
  if (key.raw.length === 1 && key.raw.charCodeAt(0) >= 32) {
3444
- value += key.raw;
3512
+ value = value.slice(0, cursorPos) + key.raw + value.slice(cursorPos);
3513
+ cursorPos++;
3445
3514
  cursorBlink = true;
3446
3515
  render();
3447
3516
  }
@@ -3449,6 +3518,76 @@ async function showMultilineInput(opts) {
3449
3518
  }
3450
3519
  }
3451
3520
  }
3521
+
3522
+ // src/tui/modal.ts
3523
+ function modalTopRow(title, w) {
3524
+ const label = ` ${title} `;
3525
+ const fill = w - 2 - label.length;
3526
+ return chalk8.bold("\u250C") + chalk8.bold.cyan(label) + chalk8.bold("\u2500".repeat(Math.max(0, fill)) + "\u2510");
3527
+ }
3528
+ function modalDivRow(w) {
3529
+ return chalk8.bold("\u251C" + "\u2500".repeat(w - 2) + "\u2524");
3530
+ }
3531
+ function modalBotRow(w) {
3532
+ return chalk8.bold("\u2514" + "\u2500".repeat(w - 2) + "\u2518");
3533
+ }
3534
+ function modalRow(text, w) {
3535
+ const inner = w - 4;
3536
+ const fitted = truncateAnsi(text, inner);
3537
+ const pad = Math.max(0, inner - visibleLen(fitted));
3538
+ return chalk8.bold("\u2502") + " " + fitted + " ".repeat(pad) + " " + chalk8.bold("\u2502");
3539
+ }
3540
+ function modalEmptyRow(w) {
3541
+ return modalRow("", w);
3542
+ }
3543
+ function buildModalFrame(title, contentLines, footerText, width) {
3544
+ const lines = [];
3545
+ lines.push(modalTopRow(title, width));
3546
+ lines.push(modalEmptyRow(width));
3547
+ for (const line of contentLines) {
3548
+ lines.push(modalRow(line, width));
3549
+ }
3550
+ lines.push(modalEmptyRow(width));
3551
+ lines.push(modalDivRow(width));
3552
+ lines.push(modalRow(chalk8.dim(footerText), width));
3553
+ lines.push(modalBotRow(width));
3554
+ return lines;
3555
+ }
3556
+ function termSize() {
3557
+ return {
3558
+ cols: process.stdout.columns || 80,
3559
+ rows: process.stdout.rows || 24
3560
+ };
3561
+ }
3562
+ function moveTo(row2, col) {
3563
+ return `\x1B[${row2};${col}H`;
3564
+ }
3565
+ function hideCursor() {
3566
+ return "\x1B[?25l";
3567
+ }
3568
+ function showCursor() {
3569
+ return "\x1B[?25h";
3570
+ }
3571
+ function modalWidth() {
3572
+ const cols = process.stdout.columns || 80;
3573
+ return Math.min(60, cols - 4);
3574
+ }
3575
+ function renderOverlay(dashboardLines, modalLines, mWidth) {
3576
+ const { cols, rows } = termSize();
3577
+ process.stdout.write("\x1B[2J\x1B[0f");
3578
+ process.stdout.write(hideCursor());
3579
+ for (let i = 0; i < dashboardLines.length && i < rows; i++) {
3580
+ process.stdout.write(
3581
+ moveTo(i + 1, 1) + chalk8.dim(stripAnsi(dashboardLines[i]))
3582
+ );
3583
+ }
3584
+ const startRow = Math.max(1, Math.floor((rows - modalLines.length) / 2));
3585
+ const startCol = Math.max(1, Math.floor((cols - mWidth) / 2));
3586
+ for (let i = 0; i < modalLines.length; i++) {
3587
+ process.stdout.write(moveTo(startRow + i, startCol) + modalLines[i]);
3588
+ }
3589
+ process.stdout.write(moveTo(startRow + modalLines.length + 1, 1));
3590
+ }
3452
3591
  function showStatus(title, message, dashboardLines) {
3453
3592
  const w = modalWidth();
3454
3593
  const content = [message];