blun-king-cli 5.1.7 → 5.2.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 (2) hide show
  1. package/blun-cli.js +44 -106
  2. package/package.json +1 -1
package/blun-cli.js CHANGED
@@ -2595,93 +2595,74 @@ async function main() {
2595
2595
  }
2596
2596
 
2597
2597
  if (!process.argv.includes("--no-workdir-prompt") && !process.argv.includes("--trust")) {
2598
- var trustedDirs = [];
2599
- var trustFile = path.join(CONFIG_DIR, "trusted.json");
2600
- if (fs.existsSync(trustFile)) {
2601
- try { trustedDirs = JSON.parse(fs.readFileSync(trustFile, "utf8")); } catch(e) {}
2602
- }
2603
- var isTrusted = trustedDirs.includes(process.cwd());
2604
-
2605
- if (!isTrusted) {
2598
+ // Always ask — like Claude Code (every session)
2599
+ {
2606
2600
  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);
2601
+ console.log(C.yellow + C.bold + " Quick safety check:" + C.reset);
2602
+ console.log(C.gray + " Is " + C.brightWhite + process.cwd() + C.gray + " a project you trust?" + C.reset);
2603
+ console.log(C.dim + " BLUN King will read and write files in this folder." + C.reset);
2609
2604
  console.log("");
2610
2605
 
2611
2606
  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" }
2607
+ { label: "Yes, I trust this folder", action: "trust" },
2608
+ { label: "No, exit", action: "exit" }
2615
2609
  ];
2616
2610
  var trustSel = 0;
2617
2611
  var trustResult = await new Promise(function(resolve) {
2618
2612
  function render() {
2619
- process.stdout.write("\x1b[3A\r");
2613
+ process.stdout.write("\x1b[2A\r");
2620
2614
  trustOptions.forEach(function(opt, i) {
2621
2615
  var prefix = i === trustSel ? "\x1b[32m\x1b[1m \u276F " : " ";
2622
2616
  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");
2617
+ process.stdout.write("\x1b[2K" + prefix + color + opt.label + "\x1b[0m\n");
2624
2618
  });
2625
2619
  }
2626
- console.log(""); console.log(""); console.log("");
2620
+ console.log(""); console.log("");
2627
2621
  render();
2628
2622
  process.stdin.setRawMode(true);
2629
2623
  process.stdin.resume();
2630
2624
  process.stdin.setEncoding("utf8");
2631
2625
  function onKey(key) {
2632
2626
  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; }
2627
+ if (key === "\x1b[B") { trustSel = Math.min(1, trustSel + 1); render(); return; }
2628
+ if (key === "\r" || key === "\n") {
2629
+ process.stdin.removeListener("data", onKey);
2630
+ process.stdin.setRawMode(false);
2631
+ process.stdin.pause();
2632
+ resolve(trustOptions[trustSel]);
2633
+ return;
2634
+ }
2636
2635
  if (key === "\x03") { process.exit(0); }
2637
2636
  }
2638
2637
  process.stdin.on("data", onKey);
2639
2638
  });
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
- }
2639
+
2640
+ if (trustResult.action === "exit") {
2641
+ console.log("");
2642
+ printInfo("Bye!");
2643
+ process.exit(0);
2673
2644
  }
2674
- // trust = trust for this session only
2675
2645
  console.log("");
2676
2646
  }
2677
2647
  }
2678
2648
 
2679
2649
  // 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")) {
2650
+ // Test if key actually works by hitting /health
2651
+ var hasKey = false;
2652
+ var existingKey = config.api.key || config.auth.api_key || "";
2653
+ if (existingKey.length > 3) {
2654
+ try {
2655
+ var testH = await apiCall("GET", "/health");
2656
+ hasKey = (testH.status === 200);
2657
+ } catch(e) { hasKey = false; }
2658
+ }
2659
+ if (!hasKey) {
2682
2660
  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);
2661
+ console.log(C.yellow + C.bold + " API Key required" + C.reset);
2662
+ if (existingKey.length > 3) {
2663
+ console.log(C.red + " Saved key didn't work — please re-enter." + C.reset);
2664
+ }
2665
+ console.log(C.gray + " Enter your BLUN King API key:" + C.reset);
2685
2666
  process.stdout.write(C.brightBlue + " API Key: " + C.reset);
2686
2667
  var apiKeyAnswer = await new Promise(function(resolve) {
2687
2668
  var buf = "";
@@ -2693,6 +2674,7 @@ async function main() {
2693
2674
  if (key === "\r" || key === "\n") {
2694
2675
  process.stdin.removeListener("data", onKeyApi);
2695
2676
  process.stdin.setRawMode(false);
2677
+ process.stdin.pause();
2696
2678
  process.stdout.write("\n");
2697
2679
  resolve(buf.trim());
2698
2680
  return;
@@ -2709,15 +2691,10 @@ async function main() {
2709
2691
  if (apiKeyAnswer) {
2710
2692
  config.api.key = apiKeyAnswer;
2711
2693
  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));
2694
+ saveConfig(config);
2720
2695
  printSuccess("API key saved.");
2696
+ } else {
2697
+ printError("No API key — some features won't work.");
2721
2698
  }
2722
2699
  }
2723
2700
 
@@ -2738,47 +2715,8 @@ async function main() {
2738
2715
  printInfo("Run: blun setup — to configure");
2739
2716
  }
2740
2717
 
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
- }
2718
+ // Auto-detect mode from input (no startup selection like Claude Code)
2719
+ var sessionMode = process.argv.includes("--agent") ? "agent" : "chat";
2782
2720
 
2783
2721
  var ALL_COMMANDS = [
2784
2722
  "/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.1",
4
4
  "description": "BLUN King CLI — Your local AI assistant powered by Gemma4",
5
5
  "type": "commonjs",
6
6
  "bin": {