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.
Files changed (3) hide show
  1. package/lib/chat.js +152 -46
  2. package/lib/ui.js +14 -4
  3. 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
- // Open inquirer menu
280
- enterMenuMode(function (done) {
281
- var inquirer = require("inquirer");
282
- inquirer.prompt([{
283
- type: "list",
284
- name: "model",
285
- message: chalk.cyan("Select Model"),
286
- choices: [
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
- enterMenuMode(function (done) {
308
- openSettingsPanel(done);
309
- });
292
+ openRawSettings();
310
293
  return;
311
294
  }
312
295
 
313
296
  if (input === "/") {
314
- enterMenuMode(function (done) {
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: "Ob Antworten gestreamt werden." },
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: "permissionMode", label: "Permission", values: ["safe", "normal", "god"], help: "Welche Aktionen BLUN ausfuehren darf." },
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: "statuslineMode", label: "Statusline", values: ["compact", "full"], help: "Wie detailliert die Statuszeile ist." },
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"];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "7.2.12",
3
+ "version": "7.3.1",
4
4
  "description": "BLUN AI Assistant - Command Line Interface",
5
5
  "bin": {
6
6
  "blun": "./bin/blun.js"