blun-king-cli 5.0.1 → 5.0.2

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 (2) hide show
  1. package/blun-cli.js +57 -33
  2. package/package.json +1 -1
package/blun-cli.js CHANGED
@@ -506,6 +506,36 @@ async function main() {
506
506
  renderPrompt();
507
507
  }
508
508
 
509
+ // ── Arrow-key menu helper ──
510
+ function arrowMenu(options, count) {
511
+ let sel = 0;
512
+ return new Promise((resolve) => {
513
+ function render() {
514
+ process.stdout.write(`\x1b[${count}A\r`);
515
+ options.forEach((opt, i) => {
516
+ const prefix = i === sel ? "\x1b[32m\x1b[1m \u276F " : " ";
517
+ const color = i === sel ? "\x1b[97m\x1b[1m" : "\x1b[90m";
518
+ process.stdout.write(`\x1b[2K${prefix}${color}${i + 1}. ${opt.label}\x1b[0m\n`);
519
+ });
520
+ }
521
+ for (let i = 0; i < count; i++) console.log("");
522
+ render();
523
+ process.stdin.setRawMode(true);
524
+ process.stdin.resume();
525
+ process.stdin.setEncoding("utf8");
526
+ function onKey(key) {
527
+ if (key === "\x1b[A") { sel = Math.max(0, sel - 1); render(); return; }
528
+ if (key === "\x1b[B") { sel = Math.min(options.length - 1, sel + 1); render(); return; }
529
+ for (let i = 0; i < options.length; i++) {
530
+ if (key === String(i + 1)) { process.stdin.removeListener("data", onKey); process.stdin.setRawMode(false); resolve(options[i]); return; }
531
+ }
532
+ if (key === "\r" || key === "\n") { process.stdin.removeListener("data", onKey); process.stdin.setRawMode(false); resolve(options[sel]); return; }
533
+ if (key === "\x03") { process.exit(0); }
534
+ }
535
+ process.stdin.on("data", onKey);
536
+ });
537
+ }
538
+
509
539
  // ── Trust Prompt ──
510
540
  const TRUST_FILE = path.join(HOME, "trusted.json");
511
541
  let trustedDirs = [];
@@ -514,28 +544,29 @@ async function main() {
514
544
 
515
545
  if (!isTrusted && process.stdin.isTTY) {
516
546
  console.log("");
517
- console.log(` \u{1F4C1} Working in: ${workdir}`);
518
- console.log(" Do you trust this folder? BLUN King will read/write files here.");
547
+ console.log(` \x1b[33m\u{1F4C1} Working in: \x1b[97m${workdir}\x1b[0m`);
548
+ console.log(" \x1b[90mDo you trust this folder? BLUN King will read/write files here.\x1b[0m");
519
549
  console.log("");
520
- const trustRl = readline.createInterface({ input: process.stdin, output: process.stdout });
521
- const trustAnswer = await new Promise((resolve) => {
522
- trustRl.question(" [Y]es / [A]lways / [C]hoose another > ", resolve);
523
- });
524
- trustRl.close();
525
- const t = trustAnswer.trim().toLowerCase();
526
- if (t === "a" || t === "always") {
550
+ const trustChoice = await arrowMenu([
551
+ { label: "Yes, trust this folder", action: "trust" },
552
+ { label: "Always trust this folder", action: "always" },
553
+ { label: "Choose another folder", action: "choose" }
554
+ ], 3);
555
+
556
+ if (trustChoice.action === "always") {
527
557
  trustedDirs.push(workdir);
528
558
  fs.writeFileSync(TRUST_FILE, JSON.stringify(trustedDirs, null, 2));
529
- console.log(" Folder trusted permanently.");
530
- } else if (t === "c" || t === "choose") {
531
- const dirRl = readline.createInterface({ input: process.stdin, output: process.stdout });
532
- const newDir = await new Promise((resolve) => {
533
- dirRl.question(" Enter path: ", resolve);
534
- });
535
- dirRl.close();
536
- if (newDir && fs.existsSync(newDir.trim())) {
537
- process.chdir(newDir.trim());
538
- console.log(` Workspace: ${newDir.trim()}`);
559
+ console.log(" \x1b[32m\u2713 Folder trusted permanently.\x1b[0m");
560
+ } else if (trustChoice.action === "choose") {
561
+ if (process.platform === "win32") {
562
+ try {
563
+ const psCmd = 'powershell -NoProfile -Command "Add-Type -AssemblyName System.Windows.Forms; $f = New-Object System.Windows.Forms.FolderBrowserDialog; $f.Description = \'Choose BLUN King workspace\'; $f.ShowNewFolderButton = $true; if($f.ShowDialog() -eq \'OK\'){ Write-Output $f.SelectedPath } else { Write-Output \'CANCELLED\' }"';
564
+ const newDir = require("child_process").execSync(psCmd, { encoding: "utf8", timeout: 60000 }).trim();
565
+ if (newDir && newDir !== "CANCELLED" && fs.existsSync(newDir)) {
566
+ process.chdir(newDir);
567
+ console.log(` \x1b[32m\u2713 Workspace: ${newDir}\x1b[0m`);
568
+ }
569
+ } catch {}
539
570
  }
540
571
  }
541
572
  console.log("");
@@ -543,21 +574,14 @@ async function main() {
543
574
 
544
575
  // ── Mode Selection ──
545
576
  if (!process.argv.includes("--agent") && !process.argv.includes("--chat") && process.stdin.isTTY) {
546
- console.log(" How do you want to work?");
547
- console.log(" [1] Chat — talk back and forth");
548
- console.log(" [2] Agent — give a goal, I do the rest autonomously");
577
+ console.log(" \x1b[97m\x1b[1mHow do you want to work?\x1b[0m");
549
578
  console.log("");
550
- const modeRl = readline.createInterface({ input: process.stdin, output: process.stdout });
551
- const modeAnswer = await new Promise((resolve) => {
552
- modeRl.question(" > ", resolve);
553
- });
554
- modeRl.close();
555
- if (modeAnswer.trim() === "1" || modeAnswer.trim().toLowerCase() === "chat") {
556
- mode = "chat";
557
- } else {
558
- mode = "agent";
559
- }
560
- console.log(` Mode: ${mode}`);
579
+ const modeChoice = await arrowMenu([
580
+ { label: "Chat \u2014 talk back and forth", mode: "chat" },
581
+ { label: "Agent \u2014 give a goal, I do the rest autonomously", mode: "agent" }
582
+ ], 2);
583
+ mode = modeChoice.mode;
584
+ console.log(` \x1b[32m\u2713 Mode: ${mode === "agent" ? "Agent (autonomous)" : "Chat (interactive)"}\x1b[0m`);
561
585
  console.log("");
562
586
  }
563
587
  if (process.argv.includes("--chat")) mode = "chat";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "5.0.1",
3
+ "version": "5.0.2",
4
4
  "description": "BLUN King CLI — Your local AI assistant powered by Gemma4",
5
5
  "type": "commonjs",
6
6
  "bin": {