blun-king-cli 5.1.7 → 5.2.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.
Files changed (2) hide show
  1. package/blun-cli.js +42 -98
  2. package/package.json +1 -1
package/blun-cli.js CHANGED
@@ -2604,84 +2604,71 @@ async function main() {
2604
2604
 
2605
2605
  if (!isTrusted) {
2606
2606
  console.log("");
2607
- console.log(C.yellow + " " + BOX.bot + " Working in: " + C.brightWhite + process.cwd() + C.reset);
2608
- console.log(C.gray + " Do you trust this folder? BLUN King will read/write files here." + C.reset);
2607
+ console.log(C.yellow + C.bold + " Quick safety check:" + C.reset);
2608
+ console.log(C.gray + " Is " + C.brightWhite + process.cwd() + C.gray + " a project you trust?" + C.reset);
2609
+ console.log(C.dim + " BLUN King will read and write files in this folder." + C.reset);
2609
2610
  console.log("");
2610
2611
 
2611
2612
  var trustOptions = [
2612
- { label: "Yes, trust this folder", action: "trust" },
2613
- { label: "Always trust this folder", action: "always" },
2614
- { label: "Choose another folder", action: "choose" }
2613
+ { label: "Yes, I trust this folder", action: "trust" },
2614
+ { label: "No, exit", action: "exit" }
2615
2615
  ];
2616
2616
  var trustSel = 0;
2617
2617
  var trustResult = await new Promise(function(resolve) {
2618
2618
  function render() {
2619
- process.stdout.write("\x1b[3A\r");
2619
+ process.stdout.write("\x1b[2A\r");
2620
2620
  trustOptions.forEach(function(opt, i) {
2621
2621
  var prefix = i === trustSel ? "\x1b[32m\x1b[1m \u276F " : " ";
2622
2622
  var color = i === trustSel ? "\x1b[97m\x1b[1m" : "\x1b[90m";
2623
- process.stdout.write("\x1b[2K" + prefix + color + (i + 1) + ". " + opt.label + "\x1b[0m\n");
2623
+ process.stdout.write("\x1b[2K" + prefix + color + opt.label + "\x1b[0m\n");
2624
2624
  });
2625
2625
  }
2626
- console.log(""); console.log(""); console.log("");
2626
+ console.log(""); console.log("");
2627
2627
  render();
2628
2628
  process.stdin.setRawMode(true);
2629
2629
  process.stdin.resume();
2630
2630
  process.stdin.setEncoding("utf8");
2631
2631
  function onKey(key) {
2632
2632
  if (key === "\x1b[A") { trustSel = Math.max(0, trustSel - 1); render(); return; }
2633
- if (key === "\x1b[B") { trustSel = Math.min(2, trustSel + 1); render(); return; }
2634
- if (key === "1" || key === "2" || key === "3") { trustSel = parseInt(key) - 1; process.stdin.removeListener("data", onKey); process.stdin.setRawMode(false); resolve(trustOptions[trustSel]); return; }
2635
- if (key === "\r" || key === "\n") { process.stdin.removeListener("data", onKey); process.stdin.setRawMode(false); resolve(trustOptions[trustSel]); return; }
2633
+ if (key === "\x1b[B") { trustSel = Math.min(1, trustSel + 1); render(); return; }
2634
+ if (key === "\r" || key === "\n") {
2635
+ process.stdin.removeListener("data", onKey);
2636
+ process.stdin.setRawMode(false);
2637
+ process.stdin.pause();
2638
+ resolve(trustOptions[trustSel]);
2639
+ return;
2640
+ }
2636
2641
  if (key === "\x03") { process.exit(0); }
2637
2642
  }
2638
2643
  process.stdin.on("data", onKey);
2639
2644
  });
2640
- var trustChoice = trustResult.action;
2641
-
2642
- if (trustChoice === "always") {
2643
- trustedDirs.push(process.cwd());
2644
- fs.writeFileSync(trustFile, JSON.stringify(trustedDirs, null, 2));
2645
- printSuccess("Folder trusted permanently.");
2646
- } else if (trustChoice === "choose") {
2647
- // Open Windows folder picker if available
2648
- var newDir = null;
2649
- if (process.platform === "win32") {
2650
- try {
2651
- printInfo("Opening folder picker...");
2652
- var 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\' }"';
2653
- newDir = require("child_process").execSync(psCmd, { encoding: "utf8", timeout: 60000 }).trim();
2654
- if (newDir === "CANCELLED") newDir = null;
2655
- } catch(e) { newDir = null; }
2656
- }
2657
- // Fallback to text input
2658
- if (!newDir) {
2659
- var rlDir = readline.createInterface({ input: process.stdin, output: process.stdout });
2660
- newDir = await new Promise(function(resolve) {
2661
- rlDir.question(C.brightBlue + " Enter path: " + C.reset, resolve);
2662
- });
2663
- rlDir.close();
2664
- newDir = newDir ? newDir.trim() : null;
2665
- }
2666
- if (newDir && fs.existsSync(newDir)) {
2667
- config.workdir = newDir;
2668
- try { fs.writeFileSync(path.join(CONFIG_DIR, "last-workdir.json"), JSON.stringify({ dir: config.workdir, ts: new Date().toISOString() })); } catch(e) {}
2669
- printSuccess("Workspace: " + config.workdir);
2670
- } else if (newDir) {
2671
- printError("Invalid path, using current directory.");
2672
- }
2645
+
2646
+ if (trustResult.action === "exit") {
2647
+ console.log("");
2648
+ printInfo("Bye!");
2649
+ process.exit(0);
2673
2650
  }
2674
- // trust = trust for this session only
2675
2651
  console.log("");
2676
2652
  }
2677
2653
  }
2678
2654
 
2679
2655
  // API Key check — prompt if missing (BEFORE header, so user sees it immediately)
2680
- var hasKey = (config.api.key && config.api.key.length > 3) || (config.auth.api_key && config.auth.api_key.length > 3);
2681
- if (!hasKey && !process.argv.includes("--api-key")) {
2656
+ // Test if key actually works by hitting /health
2657
+ var hasKey = false;
2658
+ var existingKey = config.api.key || config.auth.api_key || "";
2659
+ if (existingKey.length > 3) {
2660
+ try {
2661
+ var testH = await apiCall("GET", "/health");
2662
+ hasKey = (testH.status === 200);
2663
+ } catch(e) { hasKey = false; }
2664
+ }
2665
+ if (!hasKey) {
2682
2666
  console.log("");
2683
- console.log(C.yellow + " " + BOX.bot + " No API key configured." + C.reset);
2684
- console.log(C.gray + " Enter your BLUN King API key (or press Enter to skip):" + C.reset);
2667
+ console.log(C.yellow + C.bold + " API Key required" + C.reset);
2668
+ if (existingKey.length > 3) {
2669
+ console.log(C.red + " Saved key didn't work — please re-enter." + C.reset);
2670
+ }
2671
+ console.log(C.gray + " Enter your BLUN King API key:" + C.reset);
2685
2672
  process.stdout.write(C.brightBlue + " API Key: " + C.reset);
2686
2673
  var apiKeyAnswer = await new Promise(function(resolve) {
2687
2674
  var buf = "";
@@ -2693,6 +2680,7 @@ async function main() {
2693
2680
  if (key === "\r" || key === "\n") {
2694
2681
  process.stdin.removeListener("data", onKeyApi);
2695
2682
  process.stdin.setRawMode(false);
2683
+ process.stdin.pause();
2696
2684
  process.stdout.write("\n");
2697
2685
  resolve(buf.trim());
2698
2686
  return;
@@ -2709,15 +2697,10 @@ async function main() {
2709
2697
  if (apiKeyAnswer) {
2710
2698
  config.api.key = apiKeyAnswer;
2711
2699
  config.auth.api_key = apiKeyAnswer;
2712
- var cfgFile = path.join(CONFIG_DIR, "config.json");
2713
- var cfgData = {};
2714
- if (fs.existsSync(cfgFile)) { try { cfgData = JSON.parse(fs.readFileSync(cfgFile, "utf8")); } catch(e) {} }
2715
- if (!cfgData.api) cfgData.api = {};
2716
- if (!cfgData.auth) cfgData.auth = {};
2717
- cfgData.api.key = apiKeyAnswer;
2718
- cfgData.auth.api_key = apiKeyAnswer;
2719
- fs.writeFileSync(cfgFile, JSON.stringify(cfgData, null, 2));
2700
+ saveConfig(config);
2720
2701
  printSuccess("API key saved.");
2702
+ } else {
2703
+ printError("No API key — some features won't work.");
2721
2704
  }
2722
2705
  }
2723
2706
 
@@ -2738,47 +2721,8 @@ async function main() {
2738
2721
  printInfo("Run: blun setup — to configure");
2739
2722
  }
2740
2723
 
2741
- // Mode selection at startup
2742
- var sessionMode = "chat"; // chat or agent
2743
- if (!process.argv.includes("--agent") && !process.argv.includes("--chat")) {
2744
- console.log("");
2745
- console.log(C.brightWhite + C.bold + " How do you want to work?" + C.reset);
2746
- console.log("");
2747
- var modeOptions = [
2748
- { label: "Chat \u2014 talk back and forth", mode: "chat" },
2749
- { label: "Agent \u2014 give a goal, I do the rest autonomously", mode: "agent" }
2750
- ];
2751
- var modeSel = 0;
2752
- var modeChoice = await new Promise(function(resolve) {
2753
- function render() {
2754
- process.stdout.write("\x1b[2A\r");
2755
- modeOptions.forEach(function(opt, i) {
2756
- var prefix = i === modeSel ? "\x1b[32m\x1b[1m \u276F " : " ";
2757
- var color = i === modeSel ? "\x1b[97m\x1b[1m" : "\x1b[90m";
2758
- process.stdout.write("\x1b[2K" + prefix + color + (i + 1) + ". " + opt.label + "\x1b[0m\n");
2759
- });
2760
- }
2761
- console.log(""); console.log("");
2762
- render();
2763
- process.stdin.setRawMode(true);
2764
- process.stdin.resume();
2765
- process.stdin.setEncoding("utf8");
2766
- function onKey(key) {
2767
- if (key === "\x1b[A") { modeSel = 0; render(); return; }
2768
- if (key === "\x1b[B") { modeSel = 1; render(); return; }
2769
- if (key === "1") { process.stdin.removeListener("data", onKey); process.stdin.setRawMode(false); resolve("chat"); return; }
2770
- if (key === "2") { process.stdin.removeListener("data", onKey); process.stdin.setRawMode(false); resolve("agent"); return; }
2771
- if (key === "\r" || key === "\n") { process.stdin.removeListener("data", onKey); process.stdin.setRawMode(false); resolve(modeOptions[modeSel].mode); return; }
2772
- if (key === "\x03") { process.exit(0); }
2773
- }
2774
- process.stdin.on("data", onKey);
2775
- });
2776
- sessionMode = modeChoice;
2777
- printSuccess("Mode: " + (sessionMode === "agent" ? "Agent (autonomous)" : "Chat (interactive)"));
2778
- console.log("");
2779
- } else {
2780
- sessionMode = process.argv.includes("--agent") ? "agent" : "chat";
2781
- }
2724
+ // Auto-detect mode from input (no startup selection like Claude Code)
2725
+ var sessionMode = process.argv.includes("--agent") ? "agent" : "chat";
2782
2726
 
2783
2727
  var ALL_COMMANDS = [
2784
2728
  "/help", "/clear", "/skills", "/skill", "/search", "/learn", "/learn-url",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "5.1.7",
3
+ "version": "5.2.0",
4
4
  "description": "BLUN King CLI — Your local AI assistant powered by Gemma4",
5
5
  "type": "commonjs",
6
6
  "bin": {