blun-king-cli 2.5.2 → 2.6.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/bin/blun.js +75 -19
  2. package/package.json +1 -1
package/bin/blun.js CHANGED
@@ -495,9 +495,17 @@ async function sendChat(message) {
495
495
  chatHistory.push({ role: "user", content: message });
496
496
  chatHistory.push({ role: "assistant", content: resp.data.answer });
497
497
 
498
+ // Token tracking
499
+ var inTok = Math.ceil(message.length / 3.5);
500
+ var outTok = Math.ceil((resp.data.answer || "").length / 3.5);
501
+ sessionCost.requests++;
502
+ sessionCost.inputTokensEst += inTok;
503
+ sessionCost.outputTokensEst += outTok;
504
+
498
505
  var q = resp.data.quality || {};
506
+ var tokInfo = C.dim + (inTok + outTok) + " tok" + C.reset;
499
507
  var meta = resp.data.task_type + "/" + resp.data.role + " " + BOX.dot + " score: " + (q.score || "?") +
500
- (q.retried ? " " + BOX.dot + " retried" : "");
508
+ (q.retried ? " " + BOX.dot + " retried" : "") + " " + BOX.dot + " " + tokInfo;
501
509
  printAnswer(resp.data.answer, meta);
502
510
 
503
511
  // Auto Memory Dream Mode
@@ -2258,36 +2266,82 @@ async function main() {
2258
2266
  console.log("");
2259
2267
  console.log(C.yellow + " " + BOX.bot + " Working in: " + C.brightWhite + process.cwd() + C.reset);
2260
2268
  console.log(C.gray + " Do you trust this folder? BLUN King will read/write files here." + C.reset);
2261
- console.log(C.gray + " [y] Yes, trust [n] Choose another folder [a] Always trust" + C.reset);
2269
+ console.log("");
2270
+
2271
+ var trustOptions = [
2272
+ { label: "Yes, trust this folder", action: "trust" },
2273
+ { label: "Always trust this folder", action: "always" },
2274
+ { label: "Choose another folder", action: "choose" }
2275
+ ];
2276
+ var trustSel = 0;
2277
+
2278
+ // Arrow key menu for trust selection
2279
+ var trustChoice = await new Promise(function(resolve) {
2280
+ function renderTrustMenu() {
2281
+ // Move up and clear previous menu
2282
+ if (trustSel >= 0) process.stdout.write("\x1b[3A\r");
2283
+ trustOptions.forEach(function(opt, i) {
2284
+ var prefix = i === trustSel ? C.green + C.bold + " \u276F " : " ";
2285
+ var color = i === trustSel ? C.brightWhite + C.bold : C.gray;
2286
+ process.stdout.write("\x1b[2K" + prefix + color + (i + 1) + ". " + opt.label + C.reset + "\n");
2287
+ });
2288
+ }
2289
+ // Initial render
2290
+ console.log(""); console.log(""); console.log("");
2291
+ renderTrustMenu();
2262
2292
 
2263
- var trustAnswer = await new Promise(function(resolve) {
2264
2293
  process.stdin.setRawMode(true);
2265
2294
  process.stdin.resume();
2266
2295
  process.stdin.setEncoding("utf8");
2267
- process.stdin.once("data", function(key) {
2268
- process.stdin.setRawMode(false);
2269
- resolve(key.toLowerCase());
2270
- });
2296
+ function onKey(key) {
2297
+ if (key === "\x1b[A") { trustSel = Math.max(0, trustSel - 1); renderTrustMenu(); return; }
2298
+ if (key === "\x1b[B") { trustSel = Math.min(2, trustSel + 1); renderTrustMenu(); return; }
2299
+ if (key === "1") { trustSel = 0; process.stdin.removeListener("data", onKey); process.stdin.setRawMode(false); resolve(trustOptions[0].action); return; }
2300
+ if (key === "2") { trustSel = 1; process.stdin.removeListener("data", onKey); process.stdin.setRawMode(false); resolve(trustOptions[1].action); return; }
2301
+ if (key === "3") { trustSel = 2; process.stdin.removeListener("data", onKey); process.stdin.setRawMode(false); resolve(trustOptions[2].action); return; }
2302
+ if (key === "\r" || key === "\n") {
2303
+ process.stdin.removeListener("data", onKey);
2304
+ process.stdin.setRawMode(false);
2305
+ resolve(trustOptions[trustSel].action);
2306
+ return;
2307
+ }
2308
+ }
2309
+ process.stdin.on("data", onKey);
2271
2310
  });
2272
2311
 
2273
- if (trustAnswer === "a") {
2312
+ if (trustChoice === "always") {
2274
2313
  trustedDirs.push(process.cwd());
2275
2314
  fs.writeFileSync(trustFile, JSON.stringify(trustedDirs, null, 2));
2276
2315
  printSuccess("Folder trusted permanently.");
2277
- } else if (trustAnswer === "n") {
2278
- var rlDir = readline.createInterface({ input: process.stdin, output: process.stdout });
2279
- var newDir = await new Promise(function(resolve) {
2280
- rlDir.question(C.brightBlue + " Enter path: " + C.reset, resolve);
2281
- });
2282
- rlDir.close();
2283
- if (newDir.trim() && fs.existsSync(newDir.trim())) {
2284
- config.workdir = newDir.trim();
2316
+ } else if (trustChoice === "choose") {
2317
+ // Open Windows folder picker if available
2318
+ var newDir = null;
2319
+ if (process.platform === "win32") {
2320
+ try {
2321
+ printInfo("Opening folder picker...");
2322
+ 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\' }"';
2323
+ newDir = require("child_process").execSync(psCmd, { encoding: "utf8", timeout: 60000 }).trim();
2324
+ if (newDir === "CANCELLED") newDir = null;
2325
+ } catch(e) { newDir = null; }
2326
+ }
2327
+ // Fallback to text input
2328
+ if (!newDir) {
2329
+ var rlDir = readline.createInterface({ input: process.stdin, output: process.stdout });
2330
+ newDir = await new Promise(function(resolve) {
2331
+ rlDir.question(C.brightBlue + " Enter path: " + C.reset, resolve);
2332
+ });
2333
+ rlDir.close();
2334
+ newDir = newDir ? newDir.trim() : null;
2335
+ }
2336
+ if (newDir && fs.existsSync(newDir)) {
2337
+ config.workdir = newDir;
2285
2338
  try { fs.writeFileSync(path.join(CONFIG_DIR, "last-workdir.json"), JSON.stringify({ dir: config.workdir, ts: new Date().toISOString() })); } catch(e) {}
2286
- } else {
2339
+ printSuccess("Workspace: " + config.workdir);
2340
+ } else if (newDir) {
2287
2341
  printError("Invalid path, using current directory.");
2288
2342
  }
2289
2343
  }
2290
- // y or anything else = trust for this session
2344
+ // trust = trust for this session only
2291
2345
  console.log("");
2292
2346
  }
2293
2347
  }
@@ -2396,7 +2450,9 @@ async function main() {
2396
2450
  var permColor = isDangerous ? C.red + C.bold : permMode === "deny" ? C.red : C.yellow;
2397
2451
  var modelName = typeof config.model === "string" ? config.model : (config.model && config.model.name ? config.model.name : "default");
2398
2452
  var wdShort = config.workdir ? path.basename(config.workdir) : "~";
2399
- lines.push(permColor + " " + permIcon + " " + permLabel + C.reset + C.dim + " \u2502 " + C.reset + C.cyan + modelName + C.reset + C.dim + " \u2502 " + C.reset + C.dim + wdShort + C.reset);
2453
+ var totalTok = sessionCost.inputTokensEst + sessionCost.outputTokensEst;
2454
+ var tokStr = totalTok > 1000 ? (totalTok / 1000).toFixed(1) + "k" : String(totalTok);
2455
+ lines.push(permColor + " " + permIcon + " " + permLabel + C.reset + C.dim + " \u2502 " + C.reset + C.cyan + modelName + C.reset + C.dim + " \u2502 " + C.reset + C.dim + wdShort + C.reset + C.dim + " \u2502 " + C.reset + C.yellow + tokStr + " tok" + C.reset);
2400
2456
 
2401
2457
  // Menu
2402
2458
  if (menuVisible && menuItems.length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "2.5.2",
3
+ "version": "2.6.1",
4
4
  "description": "BLUN King CLI — Premium KI Console",
5
5
  "bin": {
6
6
  "blun": "./bin/blun.js"