blun-king-cli 7.2.11 → 7.3.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/lib/chat.js +246 -58
- package/package.json +1 -1
package/lib/chat.js
CHANGED
|
@@ -276,61 +276,25 @@ function startChat() {
|
|
|
276
276
|
printToScrollArea(chalk.yellow(" [SYS] Model: " + parts[1]));
|
|
277
277
|
drawInputPanel();
|
|
278
278
|
} else {
|
|
279
|
-
//
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
{ name: "Auto (recommended)", value: "auto" },
|
|
288
|
-
{ name: "Gemma 4", value: "gemma4" },
|
|
289
|
-
{ name: "Claude", value: "claude" },
|
|
290
|
-
{ name: "Llama", value: "llama" },
|
|
291
|
-
],
|
|
292
|
-
}]).then(function (ans) {
|
|
293
|
-
if (ans.model) {
|
|
294
|
-
model = ans.model;
|
|
295
|
-
settings.model = ans.model;
|
|
296
|
-
auth.saveSettings(settings);
|
|
297
|
-
printToScrollArea(chalk.yellow(" [SYS] Model: " + ans.model));
|
|
298
|
-
}
|
|
299
|
-
done();
|
|
300
|
-
});
|
|
301
|
-
});
|
|
279
|
+
// Cycle model
|
|
280
|
+
var models = ["auto", "gemma4", "claude", "llama"];
|
|
281
|
+
var midx = models.indexOf(settings.model || "auto");
|
|
282
|
+
settings.model = models[(midx + 1) % models.length];
|
|
283
|
+
model = settings.model;
|
|
284
|
+
auth.saveSettings(settings);
|
|
285
|
+
printToScrollArea(chalk.yellow(" [SYS] Model: " + settings.model));
|
|
286
|
+
drawInputPanel();
|
|
302
287
|
}
|
|
303
288
|
return;
|
|
304
289
|
}
|
|
305
290
|
|
|
306
291
|
if (input === "/settings") {
|
|
307
|
-
|
|
308
|
-
openSettingsPanel(done);
|
|
309
|
-
});
|
|
292
|
+
openRawSettings();
|
|
310
293
|
return;
|
|
311
294
|
}
|
|
312
295
|
|
|
313
296
|
if (input === "/") {
|
|
314
|
-
|
|
315
|
-
var inquirer = require("inquirer");
|
|
316
|
-
inquirer.prompt([{
|
|
317
|
-
type: "list",
|
|
318
|
-
name: "cmd",
|
|
319
|
-
message: chalk.cyan("Select command"),
|
|
320
|
-
choices: SLASH_COMMANDS.map(function (c) {
|
|
321
|
-
return { name: chalk.green(c[0]) + chalk.gray(" " + c[1]), value: c[0] };
|
|
322
|
-
}).concat([
|
|
323
|
-
new inquirer.Separator(),
|
|
324
|
-
{ name: chalk.dim("Cancel"), value: "" },
|
|
325
|
-
]),
|
|
326
|
-
pageSize: 12,
|
|
327
|
-
}]).then(function (ans) {
|
|
328
|
-
done();
|
|
329
|
-
if (ans.cmd) {
|
|
330
|
-
processCommand(ans.cmd);
|
|
331
|
-
}
|
|
332
|
-
});
|
|
333
|
-
});
|
|
297
|
+
openRawCommandPicker();
|
|
334
298
|
return;
|
|
335
299
|
}
|
|
336
300
|
|
|
@@ -413,6 +377,212 @@ function startChat() {
|
|
|
413
377
|
});
|
|
414
378
|
}
|
|
415
379
|
|
|
380
|
+
// ── Raw-Mode Settings Panel (no inquirer needed) ──────
|
|
381
|
+
function openRawSettings() {
|
|
382
|
+
var settingsActive = true;
|
|
383
|
+
var selectedField = 0;
|
|
384
|
+
var fields = ui.SETTINGS_FIELDS;
|
|
385
|
+
|
|
386
|
+
function drawSettings() {
|
|
387
|
+
var rows = getRows();
|
|
388
|
+
var cols = getCols();
|
|
389
|
+
var t = ui.getTheme();
|
|
390
|
+
var panelTop = rows - INPUT_PANEL_HEIGHT + 1;
|
|
391
|
+
|
|
392
|
+
// Draw settings over the input panel area
|
|
393
|
+
process.stdout.write(saveCursor());
|
|
394
|
+
|
|
395
|
+
// Clear panel area
|
|
396
|
+
for (var r = panelTop; r <= panelTop + 4; r++) {
|
|
397
|
+
process.stdout.write(cursorTo(r, 1) + clearLine());
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Also use scroll area bottom for more space
|
|
401
|
+
var settingsTop = panelTop - fields.length - 3;
|
|
402
|
+
if (settingsTop < 2) settingsTop = 2;
|
|
403
|
+
|
|
404
|
+
// Header
|
|
405
|
+
process.stdout.write(cursorTo(settingsTop, 1) + clearLine());
|
|
406
|
+
process.stdout.write(t.frame(" ╭─ Settings ") + t.frame("─".repeat(Math.max(1, cols - 16))) + t.frame("╮"));
|
|
407
|
+
|
|
408
|
+
// Fields
|
|
409
|
+
for (var i = 0; i < fields.length; i++) {
|
|
410
|
+
var row = settingsTop + 1 + i;
|
|
411
|
+
process.stdout.write(cursorTo(row, 1) + clearLine());
|
|
412
|
+
var marker = i === selectedField ? chalk.cyan(" ▸ ") : " ";
|
|
413
|
+
var label = fields[i].label;
|
|
414
|
+
var value = ui.formatSettingValue(fields[i], settings[fields[i].key]);
|
|
415
|
+
var help = i === selectedField ? chalk.dim(" ← → change") : "";
|
|
416
|
+
process.stdout.write(t.frame(" │") + marker + chalk.white(label) + " ".repeat(Math.max(1, 16 - label.length)) + value + help);
|
|
417
|
+
process.stdout.write(cursorTo(row, cols) + t.frame("│"));
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Footer
|
|
421
|
+
var footerRow = settingsTop + 1 + fields.length;
|
|
422
|
+
process.stdout.write(cursorTo(footerRow, 1) + clearLine());
|
|
423
|
+
process.stdout.write(t.frame(" │") + chalk.dim(" ↑↓ select ← → change Enter/Esc close"));
|
|
424
|
+
process.stdout.write(cursorTo(footerRow, cols) + t.frame("│"));
|
|
425
|
+
|
|
426
|
+
process.stdout.write(cursorTo(footerRow + 1, 1) + clearLine());
|
|
427
|
+
process.stdout.write(t.frame(" ╰") + t.frame("─".repeat(Math.max(1, cols - 4))) + t.frame("╯"));
|
|
428
|
+
|
|
429
|
+
process.stdout.write(restoreCursor());
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// Replace data listener temporarily
|
|
433
|
+
process.stdin.removeAllListeners("data");
|
|
434
|
+
|
|
435
|
+
function onSettingsKey(key) {
|
|
436
|
+
if (!settingsActive) return;
|
|
437
|
+
|
|
438
|
+
// Escape or Enter — close settings
|
|
439
|
+
if (key === "\u001b" && key.length === 1 || key === "\r" || key === "\n") {
|
|
440
|
+
settingsActive = false;
|
|
441
|
+
process.stdin.removeAllListeners("data");
|
|
442
|
+
// Redraw normal UI
|
|
443
|
+
var rows = getRows();
|
|
444
|
+
var settingsTop = rows - INPUT_PANEL_HEIGHT + 1 - fields.length - 3;
|
|
445
|
+
if (settingsTop < 2) settingsTop = 2;
|
|
446
|
+
for (var r = settingsTop; r <= rows; r++) {
|
|
447
|
+
process.stdout.write(cursorTo(r, 1) + clearLine());
|
|
448
|
+
}
|
|
449
|
+
drawInputPanel();
|
|
450
|
+
startRawInput();
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Up arrow
|
|
455
|
+
if (key === "\u001b[A") {
|
|
456
|
+
selectedField = (selectedField - 1 + fields.length) % fields.length;
|
|
457
|
+
drawSettings();
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Down arrow
|
|
462
|
+
if (key === "\u001b[B") {
|
|
463
|
+
selectedField = (selectedField + 1) % fields.length;
|
|
464
|
+
drawSettings();
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// Left/Right arrow — cycle value
|
|
469
|
+
if (key === "\u001b[D" || key === "\u001b[C") {
|
|
470
|
+
var field = fields[selectedField];
|
|
471
|
+
var values = field.values;
|
|
472
|
+
var curIdx = values.indexOf(settings[field.key]);
|
|
473
|
+
if (curIdx < 0) curIdx = 0;
|
|
474
|
+
var dir = key === "\u001b[C" ? 1 : -1;
|
|
475
|
+
var newIdx = (curIdx + dir + values.length) % values.length;
|
|
476
|
+
settings[field.key] = values[newIdx];
|
|
477
|
+
if (field.key === "theme") ui.setTheme(settings.theme);
|
|
478
|
+
auth.saveSettings(settings);
|
|
479
|
+
drawSettings();
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Ctrl+C
|
|
484
|
+
if (key === "\u0003") {
|
|
485
|
+
settingsActive = false;
|
|
486
|
+
process.stdin.removeAllListeners("data");
|
|
487
|
+
drawInputPanel();
|
|
488
|
+
startRawInput();
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
process.stdin.on("data", onSettingsKey);
|
|
494
|
+
drawSettings();
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// ── Raw Command Picker ─────────────────────────────────
|
|
498
|
+
function openRawCommandPicker() {
|
|
499
|
+
var pickerActive = true;
|
|
500
|
+
var selectedCmd = 0;
|
|
501
|
+
|
|
502
|
+
function drawPicker() {
|
|
503
|
+
var rows = getRows();
|
|
504
|
+
var cols = getCols();
|
|
505
|
+
var t = ui.getTheme();
|
|
506
|
+
var panelTop = rows - INPUT_PANEL_HEIGHT + 1;
|
|
507
|
+
var pickerTop = panelTop - SLASH_COMMANDS.length - 3;
|
|
508
|
+
if (pickerTop < 2) pickerTop = 2;
|
|
509
|
+
|
|
510
|
+
process.stdout.write(saveCursor());
|
|
511
|
+
|
|
512
|
+
// Header
|
|
513
|
+
process.stdout.write(cursorTo(pickerTop, 1) + clearLine());
|
|
514
|
+
process.stdout.write(t.frame(" ╭─ Commands ") + t.frame("─".repeat(Math.max(1, cols - 16))) + t.frame("╮"));
|
|
515
|
+
|
|
516
|
+
for (var i = 0; i < SLASH_COMMANDS.length; i++) {
|
|
517
|
+
var row = pickerTop + 1 + i;
|
|
518
|
+
process.stdout.write(cursorTo(row, 1) + clearLine());
|
|
519
|
+
var marker = i === selectedCmd ? chalk.cyan(" ▸ ") : " ";
|
|
520
|
+
process.stdout.write(t.frame(" │") + marker + chalk.green(SLASH_COMMANDS[i][0]) + " ".repeat(Math.max(1, 14 - SLASH_COMMANDS[i][0].length)) + chalk.gray(SLASH_COMMANDS[i][1]));
|
|
521
|
+
process.stdout.write(cursorTo(row, cols) + t.frame("│"));
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
var footerRow = pickerTop + 1 + SLASH_COMMANDS.length;
|
|
525
|
+
process.stdout.write(cursorTo(footerRow, 1) + clearLine());
|
|
526
|
+
process.stdout.write(t.frame(" │") + chalk.dim(" ↑↓ select Enter run Esc close"));
|
|
527
|
+
process.stdout.write(cursorTo(footerRow, cols) + t.frame("│"));
|
|
528
|
+
process.stdout.write(cursorTo(footerRow + 1, 1) + clearLine());
|
|
529
|
+
process.stdout.write(t.frame(" ╰") + t.frame("─".repeat(Math.max(1, cols - 4))) + t.frame("╯"));
|
|
530
|
+
|
|
531
|
+
process.stdout.write(restoreCursor());
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
process.stdin.removeAllListeners("data");
|
|
535
|
+
|
|
536
|
+
function onPickerKey(key) {
|
|
537
|
+
if (!pickerActive) return;
|
|
538
|
+
|
|
539
|
+
if (key === "\u001b" && key.length === 1 || key === "\u0003") {
|
|
540
|
+
pickerActive = false;
|
|
541
|
+
process.stdin.removeAllListeners("data");
|
|
542
|
+
var rows = getRows();
|
|
543
|
+
var pickerTop = rows - INPUT_PANEL_HEIGHT + 1 - SLASH_COMMANDS.length - 3;
|
|
544
|
+
if (pickerTop < 2) pickerTop = 2;
|
|
545
|
+
for (var r = pickerTop; r <= rows; r++) {
|
|
546
|
+
process.stdout.write(cursorTo(r, 1) + clearLine());
|
|
547
|
+
}
|
|
548
|
+
drawInputPanel();
|
|
549
|
+
startRawInput();
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
if (key === "\u001b[A") {
|
|
554
|
+
selectedCmd = (selectedCmd - 1 + SLASH_COMMANDS.length) % SLASH_COMMANDS.length;
|
|
555
|
+
drawPicker();
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
if (key === "\u001b[B") {
|
|
560
|
+
selectedCmd = (selectedCmd + 1) % SLASH_COMMANDS.length;
|
|
561
|
+
drawPicker();
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
if (key === "\r" || key === "\n") {
|
|
566
|
+
pickerActive = false;
|
|
567
|
+
process.stdin.removeAllListeners("data");
|
|
568
|
+
var cmd = SLASH_COMMANDS[selectedCmd][0];
|
|
569
|
+
var rows = getRows();
|
|
570
|
+
var pickerTop = rows - INPUT_PANEL_HEIGHT + 1 - SLASH_COMMANDS.length - 3;
|
|
571
|
+
if (pickerTop < 2) pickerTop = 2;
|
|
572
|
+
for (var r = pickerTop; r <= rows; r++) {
|
|
573
|
+
process.stdout.write(cursorTo(r, 1) + clearLine());
|
|
574
|
+
}
|
|
575
|
+
drawInputPanel();
|
|
576
|
+
startRawInput();
|
|
577
|
+
processCommand(cmd);
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
process.stdin.on("data", onPickerKey);
|
|
583
|
+
drawPicker();
|
|
584
|
+
}
|
|
585
|
+
|
|
416
586
|
// ── Settings Panel (inquirer) ─────────────────────────
|
|
417
587
|
function openSettingsPanel(done) {
|
|
418
588
|
var inquirer = require("inquirer");
|
|
@@ -460,23 +630,35 @@ function startChat() {
|
|
|
460
630
|
// ── Menu Mode (temporarily disable raw input) ────────
|
|
461
631
|
function enterMenuMode(fn) {
|
|
462
632
|
isInMenu = true;
|
|
463
|
-
// Reset
|
|
633
|
+
// Reset everything for inquirer
|
|
464
634
|
var rows = getRows();
|
|
635
|
+
// Remove scroll region
|
|
465
636
|
process.stdout.write(setScrollRegion(1, rows));
|
|
466
|
-
|
|
637
|
+
// Move cursor below the panel area
|
|
638
|
+
process.stdout.write(cursorTo(rows - INPUT_PANEL_HEIGHT - 1, 1));
|
|
467
639
|
process.stdout.write(showCursor());
|
|
468
|
-
|
|
640
|
+
// Exit raw mode and clean up listeners
|
|
469
641
|
process.stdin.removeAllListeners("data");
|
|
642
|
+
process.stdin.removeAllListeners("keypress");
|
|
643
|
+
try { process.stdin.setRawMode(false); } catch (e) {}
|
|
644
|
+
// Fully reset stdin for inquirer
|
|
470
645
|
process.stdin.pause();
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
646
|
+
// Small delay to let stdin settle before inquirer takes over
|
|
647
|
+
setTimeout(function () {
|
|
648
|
+
fn(function () {
|
|
649
|
+
// Re-enter TUI mode
|
|
650
|
+
isInMenu = false;
|
|
651
|
+
console.clear();
|
|
652
|
+
ui.renderBanner();
|
|
653
|
+
var creds3 = auth.getStoredCredentials();
|
|
654
|
+
if (creds3) {
|
|
655
|
+
console.log(chalk.yellow(" [SYS] Connected as " + (creds3.name || creds3.email || "user") + " | Plan: " + (creds3.plan || "free")));
|
|
656
|
+
}
|
|
657
|
+
setupLayout();
|
|
658
|
+
drawInputPanel();
|
|
659
|
+
startRawInput();
|
|
660
|
+
});
|
|
661
|
+
}, 50);
|
|
480
662
|
}
|
|
481
663
|
|
|
482
664
|
// ── Cleanup ──────────────────────────────────────────
|
|
@@ -602,6 +784,12 @@ function startChat() {
|
|
|
602
784
|
setTimeout(function () {
|
|
603
785
|
// Clear screen, draw banner, then enter TUI mode
|
|
604
786
|
console.clear();
|
|
787
|
+
// Push banner down a few lines
|
|
788
|
+
var rows = getRows();
|
|
789
|
+
var contentHeight = 12; // banner ~6 + info ~3 + padding ~3
|
|
790
|
+
var scrollArea = rows - INPUT_PANEL_HEIGHT;
|
|
791
|
+
var topPadding = Math.max(0, Math.floor((scrollArea - contentHeight) / 2));
|
|
792
|
+
for (var p = 0; p < topPadding; p++) console.log("");
|
|
605
793
|
// Render banner in normal mode first (before scroll region)
|
|
606
794
|
ui.renderBanner();
|
|
607
795
|
var creds2 = auth.getStoredCredentials();
|