blun-king-cli 7.2.12 → 7.3.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/lib/chat.js +152 -46
- package/lib/ui.js +14 -4
- 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,139 @@ function startChat() {
|
|
|
413
377
|
});
|
|
414
378
|
}
|
|
415
379
|
|
|
380
|
+
// ── Raw-Mode Settings Panel (no inquirer needed) ──────
|
|
381
|
+
// ── Generic dropdown below input panel ─────────────────
|
|
382
|
+
function openDropdownBelow(items, onSelect, onClose) {
|
|
383
|
+
var active = true;
|
|
384
|
+
var selected = 0;
|
|
385
|
+
|
|
386
|
+
function getMenuStart() {
|
|
387
|
+
var rows = getRows();
|
|
388
|
+
var panelTop = rows - INPUT_PANEL_HEIGHT + 1;
|
|
389
|
+
return panelTop + 5; // right after the bottom frame of input panel
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function clearMenu() {
|
|
393
|
+
var start = getMenuStart();
|
|
394
|
+
var rows = getRows();
|
|
395
|
+
for (var r = start; r <= rows; r++) {
|
|
396
|
+
process.stdout.write(cursorTo(r, 1) + clearLine());
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function drawMenu() {
|
|
401
|
+
var cols = getCols();
|
|
402
|
+
var t = ui.getTheme();
|
|
403
|
+
var start = getMenuStart();
|
|
404
|
+
|
|
405
|
+
process.stdout.write(saveCursor());
|
|
406
|
+
|
|
407
|
+
for (var i = 0; i < items.length; i++) {
|
|
408
|
+
var row = start + i;
|
|
409
|
+
process.stdout.write(cursorTo(row, 1) + clearLine());
|
|
410
|
+
var marker = i === selected ? chalk.cyan(" ▸ ") : " ";
|
|
411
|
+
process.stdout.write(marker + items[i].display);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Help line
|
|
415
|
+
var helpRow = start + items.length;
|
|
416
|
+
process.stdout.write(cursorTo(helpRow, 1) + clearLine());
|
|
417
|
+
process.stdout.write(chalk.dim(" ↑↓ select " + (items[0].help || "Enter confirm Esc close")));
|
|
418
|
+
|
|
419
|
+
process.stdout.write(restoreCursor());
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
process.stdin.removeAllListeners("data");
|
|
423
|
+
|
|
424
|
+
function onKey(key) {
|
|
425
|
+
if (!active) return;
|
|
426
|
+
|
|
427
|
+
// Escape
|
|
428
|
+
if ((key === "\u001b" && key.length === 1) || key === "\u0003") {
|
|
429
|
+
active = false;
|
|
430
|
+
process.stdin.removeAllListeners("data");
|
|
431
|
+
clearMenu();
|
|
432
|
+
if (onClose) onClose();
|
|
433
|
+
startRawInput();
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// Up
|
|
438
|
+
if (key === "\u001b[A") {
|
|
439
|
+
selected = (selected - 1 + items.length) % items.length;
|
|
440
|
+
drawMenu();
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// Down
|
|
445
|
+
if (key === "\u001b[B") {
|
|
446
|
+
selected = (selected + 1) % items.length;
|
|
447
|
+
drawMenu();
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Left/Right for settings cycling
|
|
452
|
+
if (key === "\u001b[D" || key === "\u001b[C") {
|
|
453
|
+
if (items[selected].onCycle) {
|
|
454
|
+
items[selected].onCycle(key === "\u001b[C" ? 1 : -1);
|
|
455
|
+
drawMenu();
|
|
456
|
+
}
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// Enter
|
|
461
|
+
if (key === "\r" || key === "\n") {
|
|
462
|
+
active = false;
|
|
463
|
+
process.stdin.removeAllListeners("data");
|
|
464
|
+
clearMenu();
|
|
465
|
+
if (onSelect) onSelect(items[selected]);
|
|
466
|
+
startRawInput();
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
process.stdin.on("data", onKey);
|
|
472
|
+
drawMenu();
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function openRawSettings() {
|
|
476
|
+
var fields = ui.SETTINGS_FIELDS;
|
|
477
|
+
var items = fields.map(function (f) {
|
|
478
|
+
return {
|
|
479
|
+
display: chalk.white(f.label) + " ".repeat(Math.max(1, 16 - f.label.length)) + ui.formatSettingValue(f, settings[f.key]),
|
|
480
|
+
field: f,
|
|
481
|
+
help: "← → change Enter/Esc close",
|
|
482
|
+
onCycle: function (dir) {
|
|
483
|
+
var values = f.values;
|
|
484
|
+
var curIdx = values.indexOf(settings[f.key]);
|
|
485
|
+
if (curIdx < 0) curIdx = 0;
|
|
486
|
+
var newIdx = (curIdx + dir + values.length) % values.length;
|
|
487
|
+
settings[f.key] = values[newIdx];
|
|
488
|
+
if (f.key === "theme") ui.setTheme(settings.theme);
|
|
489
|
+
auth.saveSettings(settings);
|
|
490
|
+
// Update display text
|
|
491
|
+
this.display = chalk.white(f.label) + " ".repeat(Math.max(1, 16 - f.label.length)) + ui.formatSettingValue(f, settings[f.key]);
|
|
492
|
+
drawInputPanel(); // refresh status bar
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
});
|
|
496
|
+
openDropdownBelow(items, function () { drawInputPanel(); }, function () { drawInputPanel(); });
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
function openRawCommandPicker() {
|
|
500
|
+
var items = SLASH_COMMANDS.map(function (c) {
|
|
501
|
+
return {
|
|
502
|
+
display: chalk.green(c[0]) + " ".repeat(Math.max(1, 14 - c[0].length)) + chalk.gray(c[1]),
|
|
503
|
+
cmd: c[0],
|
|
504
|
+
help: "Enter run Esc close"
|
|
505
|
+
};
|
|
506
|
+
});
|
|
507
|
+
openDropdownBelow(items, function (item) {
|
|
508
|
+
drawInputPanel();
|
|
509
|
+
processCommand(item.cmd);
|
|
510
|
+
}, function () { drawInputPanel(); });
|
|
511
|
+
}
|
|
512
|
+
|
|
416
513
|
// ── Settings Panel (inquirer) ─────────────────────────
|
|
417
514
|
function openSettingsPanel(done) {
|
|
418
515
|
var inquirer = require("inquirer");
|
|
@@ -605,6 +702,15 @@ function startChat() {
|
|
|
605
702
|
inputBuffer = inputBuffer.slice(0, cursorPos) + key + inputBuffer.slice(cursorPos);
|
|
606
703
|
cursorPos += key.length;
|
|
607
704
|
drawInputPanel();
|
|
705
|
+
|
|
706
|
+
// Live "/" dropdown — show command picker as soon as "/" is typed
|
|
707
|
+
if (inputBuffer === "/") {
|
|
708
|
+
inputBuffer = "";
|
|
709
|
+
cursorPos = 0;
|
|
710
|
+
drawInputPanel();
|
|
711
|
+
openRawCommandPicker();
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
608
714
|
});
|
|
609
715
|
}
|
|
610
716
|
|
package/lib/ui.js
CHANGED
|
@@ -61,13 +61,23 @@ function setTheme(name) {
|
|
|
61
61
|
// ── Settings Fields ───────────────────────────────────────
|
|
62
62
|
var SETTINGS_FIELDS = [
|
|
63
63
|
{ section: "Core", key: "model", label: "Model", values: ["auto", "gemma4", "claude", "llama"], help: "Welches Modell standardmaessig antwortet." },
|
|
64
|
-
{ section: "Core", key: "language", label: "Language", values: ["de", "en"], help: "Primaere Antwortsprache." },
|
|
64
|
+
{ section: "Core", key: "language", label: "Language", values: ["de", "en", "tr", "fr", "es"], help: "Primaere Antwortsprache." },
|
|
65
|
+
{ section: "Core", key: "permissionMode", label: "Permission", values: ["safe", "normal", "god"], help: "Welche Aktionen BLUN ausfuehren darf." },
|
|
66
|
+
{ section: "Core", key: "maxTokens", label: "Max Tokens", values: [1024, 2048, 4096, 8192, 16384], help: "Maximale Antwortlaenge." },
|
|
65
67
|
{ section: "Console", key: "theme", label: "Theme", values: ["neon", "midnight", "minimal"], help: "Farbstimmung der Konsole." },
|
|
66
|
-
{ section: "Console", key: "streamLevel", label: "Stream", values: ["off", "normal"], help: "
|
|
68
|
+
{ section: "Console", key: "streamLevel", label: "Stream", values: ["off", "normal", "verbose"], help: "Wie Antworten angezeigt werden." },
|
|
69
|
+
{ section: "Console", key: "markdownRendering", label: "Markdown", values: [true, false], help: "Markdown in Antworten rendern." },
|
|
70
|
+
{ section: "Console", key: "codeHighlight", label: "Syntax", values: [true, false], help: "Code-Syntax-Highlighting." },
|
|
71
|
+
{ section: "Console", key: "statuslineMode", label: "Statusline", values: ["compact", "full", "off"], help: "Wie detailliert die Statuszeile ist." },
|
|
67
72
|
{ section: "Runtime", key: "voice", label: "Voice", values: [true, false], help: "Voice-Features an/aus." },
|
|
68
|
-
{ section: "Runtime", key: "
|
|
73
|
+
{ section: "Runtime", key: "autoSave", label: "AutoSave", values: [true, false], help: "Chat-Verlauf automatisch speichern." },
|
|
74
|
+
{ section: "Runtime", key: "contextMemory", label: "Memory", values: [true, false], help: "Kontext aus vorherigen Chats nutzen." },
|
|
75
|
+
{ section: "Runtime", key: "fileAccess", label: "File Access", values: ["ask", "auto", "off"], help: "Dateizugriff: fragen/automatisch/aus." },
|
|
76
|
+
{ section: "Runtime", key: "shellAccess", label: "Shell", values: ["ask", "auto", "off"], help: "Shell-Befehle: fragen/automatisch/aus." },
|
|
69
77
|
{ section: "Workflow", key: "costVisibility", label: "Cost", values: [true, false], help: "Token-/Kosten-Footer anzeigen." },
|
|
70
|
-
{ section: "Workflow", key: "
|
|
78
|
+
{ section: "Workflow", key: "autoCommit", label: "AutoCommit", values: [true, false], help: "Automatisch Git-Commits erstellen." },
|
|
79
|
+
{ section: "Workflow", key: "codeReview", label: "Review", values: [true, false], help: "Code-Review vor Aenderungen." },
|
|
80
|
+
{ section: "Workflow", key: "notifications", label: "Notify", values: [true, false], help: "Desktop-Benachrichtigungen." },
|
|
71
81
|
];
|
|
72
82
|
|
|
73
83
|
var PERMISSION_MODES = ["safe", "normal", "god"];
|