blun-king-cli 2.4.1 → 2.5.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 +82 -49
  2. package/package.json +1 -1
package/bin/blun.js CHANGED
@@ -2334,59 +2334,50 @@ async function main() {
2334
2334
  var menuSelected = 0;
2335
2335
  var cursorPos = 0;
2336
2336
  var processing = false;
2337
- var drawnLines = 0; // total lines drawn by the UI (box + menu)
2337
+ var uiStartRow = -1; // row where UI starts on screen
2338
2338
 
2339
2339
  function getTermWidth() { return process.stdout.columns || 80; }
2340
2340
 
2341
- // Erase everything we drew and move cursor back to start
2341
+ // Get current cursor row via sync trick
2342
+ function getCursorRow() {
2343
+ // Fallback: track manually
2344
+ return -1;
2345
+ }
2346
+
2347
+ // Erase UI using readline module (Windows-safe)
2342
2348
  function eraseUI() {
2343
- if (drawnLines <= 0) return;
2344
- // Move cursor up to where we started drawing
2345
- process.stdout.write("\x1b[?25l");
2346
- // Go up drawnLines from current cursor position
2347
- // Cursor is on content line (line 2), so we need to go up 1 to reach top
2348
- process.stdout.write("\x1b[" + (drawnLines) + "A\r");
2349
- // Clear all lines we drew + extra buffer
2350
- for (var i = 0; i < drawnLines + 3; i++) {
2351
- process.stdout.write("\x1b[2K");
2352
- if (i < drawnLines + 2) process.stdout.write("\n");
2353
- }
2354
- // Go back up
2355
- process.stdout.write("\x1b[" + (drawnLines + 3) + "A\r");
2356
- process.stdout.write("\x1b[?25h");
2357
- drawnLines = 0;
2349
+ if (uiStartRow < 0) return;
2350
+ // Move cursor to where UI started
2351
+ readline.cursorTo(process.stdout, 0, uiStartRow);
2352
+ // Clear everything from here down
2353
+ readline.clearScreenDown(process.stdout);
2354
+ uiStartRow = -1;
2358
2355
  }
2359
2356
 
2360
- // Draw the complete UI (box + menu) from scratch
2361
- function drawUI() {
2362
- process.stdout.write("\x1b[?25l"); // hide cursor
2357
+ // Build UI lines as array, then write all at once
2358
+ function buildUILines() {
2363
2359
  var w = Math.min(getTermWidth() - 4, 76);
2364
2360
  var displayText = inputBuffer;
2365
2361
  if (displayText.length > w - 4) displayText = displayText.slice(-(w - 4));
2366
- var pad = Math.max(0, w - 3 - displayText.length);
2367
- var lines = 0;
2368
-
2369
- // Box top
2370
- process.stdout.write("\x1b[2K" + C.brightBlue + " \u256D" + "\u2500".repeat(w - 2) + "\u256E" + C.reset + "\n"); lines++;
2371
- // Box content
2372
- process.stdout.write("\x1b[2K" + C.brightBlue + " \u2502 " + C.reset + C.brightWhite + displayText + C.reset + " ".repeat(pad) + C.brightBlue + "\u2502" + C.reset + "\n"); lines++;
2373
- // Box bottom
2374
- process.stdout.write("\x1b[2K" + C.brightBlue + " \u2570" + "\u2500".repeat(w - 2) + "\u256F" + C.reset + "\n"); lines++;
2375
-
2376
- // Status bar (permission mode + model + workdir)
2377
- var rawPerm = getSetting("permissions.defaultMode");
2378
- var permMode = typeof rawPerm === "string" ? rawPerm : "ask";
2379
- // Check if --dangerously-skip-permissions or godmode
2380
- var isDangerous = process.argv.includes("--dangerously-skip-permissions") || permMode === "allow";
2362
+ var inner = w - 2;
2363
+ var textPad = Math.max(0, inner - 2 - displayText.length);
2364
+ var lines = [];
2365
+
2366
+ // Box
2367
+ lines.push(C.brightBlue + " \u256D" + "\u2500".repeat(inner) + "\u256E" + C.reset);
2368
+ lines.push(C.brightBlue + " \u2502 " + C.reset + C.brightWhite + displayText + C.reset + " ".repeat(textPad) + " " + C.brightBlue + "\u2502" + C.reset);
2369
+ lines.push(C.brightBlue + " \u2570" + "\u2500".repeat(inner) + "\u256F" + C.reset);
2370
+
2371
+ // Status bar
2372
+ var permData = loadPermissions();
2373
+ var permMode = permData.mode || "ask";
2374
+ var isDangerous = process.argv.includes("--dangerously-skip-permissions") || permMode === "allow" || permMode === "allow-all";
2381
2375
  var permLabel = isDangerous ? "GOD MODE" : permMode === "deny" ? "LOCKED" : "ask permission";
2382
2376
  var permIcon = isDangerous ? "\u26A1" : permMode === "deny" ? "\u2718" : "\u2753";
2383
2377
  var permColor = isDangerous ? C.red + C.bold : permMode === "deny" ? C.red : C.yellow;
2384
2378
  var modelName = typeof config.model === "string" ? config.model : (config.model && config.model.name ? config.model.name : "default");
2385
2379
  var wdShort = config.workdir ? path.basename(config.workdir) : "~";
2386
- var statusLine = permColor + " " + permIcon + " " + permLabel + C.reset + C.dim + " \u2502 " + C.reset +
2387
- C.cyan + modelName + C.reset + C.dim + " \u2502 " + C.reset +
2388
- C.dim + wdShort + C.reset;
2389
- process.stdout.write("\x1b[2K" + statusLine + "\n"); lines++;
2380
+ 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);
2390
2381
 
2391
2382
  // Menu
2392
2383
  if (menuVisible && menuItems.length > 0) {
@@ -2397,25 +2388,67 @@ async function main() {
2397
2388
  var descStr = item.desc.slice(0, getTermWidth() - 28);
2398
2389
  var cmdColor = i === menuSelected ? C.green + C.bold : C.green;
2399
2390
  var descColor = i === menuSelected ? C.brightWhite : C.white;
2400
- process.stdout.write("\x1b[2K" + prefix + cmdColor + cmdStr + descColor + descStr + C.reset + "\n");
2401
- lines++;
2391
+ lines.push(prefix + cmdColor + cmdStr + descColor + descStr + C.reset);
2402
2392
  });
2403
2393
  if (menuItems.length > 8) {
2404
- process.stdout.write("\x1b[2K" + C.dim + " ... " + (menuItems.length - 8) + " more" + C.reset + "\n");
2405
- lines++;
2394
+ lines.push(C.dim + " ... " + (menuItems.length - 8) + " more" + C.reset);
2406
2395
  }
2407
2396
  }
2408
2397
 
2409
- drawnLines = lines;
2398
+ return { lines: lines, cursorLine: 1, cursorCol: 4 + displayText.length };
2399
+ }
2400
+
2401
+ function drawUI() {
2402
+ process.stdout.write("\x1b[?25l"); // hide cursor
2403
+ // Remember where we start drawing
2404
+ uiStartRow = (process.stdout.rows || 24) - 1; // approximate
2405
+ // Use getCursorPosition trick: write lines, then position cursor
2406
+ var ui = buildUILines();
2407
+
2408
+ // Save absolute position before drawing
2409
+ // Write a marker to know our row
2410
+ process.stdout.write("\x1b[6n"); // request cursor position (async, but we don't wait)
2411
+
2412
+ // Actually just track rows manually
2413
+ uiStartRow = -1; // will be set below
2414
+
2415
+ // Clear any previous content and write fresh
2416
+ var output = ui.lines.join("\n") + "\n";
2417
+ process.stdout.write(output);
2418
+
2419
+ // Now cursor is at bottom. Calculate how many lines we wrote.
2420
+ var totalLines = ui.lines.length;
2421
+
2422
+ // Move cursor back to input position (line index 1 = content line)
2423
+ // We're at totalLines below start, need to go up (totalLines - 1 - cursorLine) from current minus 1
2424
+ var upMoves = totalLines - ui.cursorLine;
2425
+ process.stdout.write("\x1b[" + upMoves + "A");
2426
+ process.stdout.write("\r\x1b[" + ui.cursorCol + "C");
2427
+
2428
+ // Track for eraseUI: store how far up the start is from cursor
2429
+ uiStartRow = totalLines; // repurpose as "total lines drawn"
2410
2430
 
2411
- // Position cursor inside the box (line 2, after text)
2412
- process.stdout.write("\x1b[" + (lines - 1) + "A"); // back to content line
2413
- process.stdout.write("\r\x1b[" + (4 + displayText.length) + "C"); // right to cursor pos
2414
2431
  process.stdout.write("\x1b[?25h"); // show cursor
2415
2432
  }
2416
2433
 
2434
+ // Override eraseUI to use line count
2435
+ eraseUI = function() {
2436
+ if (uiStartRow <= 0) return;
2437
+ process.stdout.write("\x1b[?25l");
2438
+ // Cursor is on content line (line 1). Move up 1 to reach top.
2439
+ process.stdout.write("\x1b[1A\r");
2440
+ // Clear all lines
2441
+ for (var i = 0; i < uiStartRow + 2; i++) {
2442
+ process.stdout.write("\x1b[2K\x1b[1B");
2443
+ }
2444
+ // Move back up
2445
+ process.stdout.write("\x1b[" + (uiStartRow + 2) + "A\r");
2446
+ process.stdout.write("\x1b[?25h");
2447
+ uiStartRow = -1;
2448
+ };
2449
+
2417
2450
  function refreshUI() {
2418
- eraseUI();
2451
+ if (uiStartRow > 0) eraseUI();
2419
2452
  // Compute menu items
2420
2453
  if (inputBuffer.startsWith("/")) {
2421
2454
  var filter = inputBuffer.toLowerCase();
@@ -2434,7 +2467,7 @@ async function main() {
2434
2467
  function drawPrompt() {
2435
2468
  if (processing) return;
2436
2469
  console.log(""); // spacing
2437
- drawnLines = 0;
2470
+ uiStartRow = -1;
2438
2471
  refreshUI();
2439
2472
  }
2440
2473
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "2.4.1",
3
+ "version": "2.5.1",
4
4
  "description": "BLUN King CLI — Premium KI Console",
5
5
  "bin": {
6
6
  "blun": "./bin/blun.js"