blun-king-cli 2.4.0 → 2.5.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.
- package/bin/blun.js +93 -51
- package/package.json +1 -1
package/bin/blun.js
CHANGED
|
@@ -106,16 +106,25 @@ var chatHistory = [];
|
|
|
106
106
|
// ── Print Helpers ──
|
|
107
107
|
function printHeader() {
|
|
108
108
|
var w = Math.min(process.stdout.columns || 60, 60);
|
|
109
|
-
var
|
|
109
|
+
var inner = w - 4; // inner width between │ and │
|
|
110
|
+
var line = BOX.h.repeat(inner);
|
|
111
|
+
// Helper: pad text to exact inner width
|
|
112
|
+
function row(text, visLen) { return C.brightBlue + " " + BOX.v + C.reset + text + " ".repeat(Math.max(0, inner - visLen)) + C.brightBlue + BOX.v + C.reset; }
|
|
113
|
+
var modelStr = typeof config.model === "string" ? config.model : (config.model && config.model.name ? config.model.name : "default");
|
|
114
|
+
var wdShort = config.workdir.length > inner - 10 ? "..." + config.workdir.slice(-(inner - 13)) : config.workdir;
|
|
115
|
+
var titleText = " " + BOX.bot + " BLUN KING CLI v" + PKG_VERSION;
|
|
116
|
+
var subText = " Premium KI \u2014 Local First \u2014 Autonom";
|
|
110
117
|
console.log("");
|
|
111
118
|
console.log(C.brightBlue + " " + BOX.tl + line + BOX.tr + C.reset);
|
|
112
|
-
console.log(C.
|
|
113
|
-
console.log(C.
|
|
119
|
+
console.log(row(C.bold + C.brightWhite + titleText + C.reset, titleText.length));
|
|
120
|
+
console.log(row(C.gray + subText + C.reset, subText.length));
|
|
114
121
|
console.log(C.brightBlue + " " + BOX.v + line + BOX.v + C.reset);
|
|
115
|
-
|
|
116
|
-
console.log(C.
|
|
117
|
-
var
|
|
118
|
-
console.log(C.
|
|
122
|
+
var apiText = " API " + config.api.base_url;
|
|
123
|
+
console.log(row(C.gray + " API " + C.brightCyan + config.api.base_url + C.reset, apiText.length));
|
|
124
|
+
var modelText = " Model " + modelStr;
|
|
125
|
+
console.log(row(C.gray + " Model " + C.brightCyan + modelStr + C.reset, modelText.length));
|
|
126
|
+
var dirText = " Dir " + wdShort;
|
|
127
|
+
console.log(row(C.gray + " Dir " + C.brightCyan + wdShort + C.reset, dirText.length));
|
|
119
128
|
console.log(C.brightBlue + " " + BOX.bl + line + BOX.br + C.reset);
|
|
120
129
|
console.log("");
|
|
121
130
|
console.log(C.gray + " /help " + C.dim + "for commands " + C.gray + BOX.dot + " just type to chat" + C.reset);
|
|
@@ -2325,59 +2334,50 @@ async function main() {
|
|
|
2325
2334
|
var menuSelected = 0;
|
|
2326
2335
|
var cursorPos = 0;
|
|
2327
2336
|
var processing = false;
|
|
2328
|
-
var
|
|
2337
|
+
var uiStartRow = -1; // row where UI starts on screen
|
|
2329
2338
|
|
|
2330
2339
|
function getTermWidth() { return process.stdout.columns || 80; }
|
|
2331
2340
|
|
|
2332
|
-
//
|
|
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)
|
|
2333
2348
|
function eraseUI() {
|
|
2334
|
-
if (
|
|
2335
|
-
// Move cursor
|
|
2336
|
-
process.stdout
|
|
2337
|
-
//
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
// Clear all lines we drew + extra buffer
|
|
2341
|
-
for (var i = 0; i < drawnLines + 3; i++) {
|
|
2342
|
-
process.stdout.write("\x1b[2K");
|
|
2343
|
-
if (i < drawnLines + 2) process.stdout.write("\n");
|
|
2344
|
-
}
|
|
2345
|
-
// Go back up
|
|
2346
|
-
process.stdout.write("\x1b[" + (drawnLines + 3) + "A\r");
|
|
2347
|
-
process.stdout.write("\x1b[?25h");
|
|
2348
|
-
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;
|
|
2349
2355
|
}
|
|
2350
2356
|
|
|
2351
|
-
//
|
|
2352
|
-
function
|
|
2353
|
-
process.stdout.write("\x1b[?25l"); // hide cursor
|
|
2357
|
+
// Build UI lines as array, then write all at once
|
|
2358
|
+
function buildUILines() {
|
|
2354
2359
|
var w = Math.min(getTermWidth() - 4, 76);
|
|
2355
2360
|
var displayText = inputBuffer;
|
|
2356
2361
|
if (displayText.length > w - 4) displayText = displayText.slice(-(w - 4));
|
|
2357
|
-
var
|
|
2358
|
-
var
|
|
2362
|
+
var inner = w - 2;
|
|
2363
|
+
var textPad = Math.max(0, inner - 2 - displayText.length);
|
|
2364
|
+
var lines = [];
|
|
2359
2365
|
|
|
2360
|
-
// Box
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
// Box bottom
|
|
2365
|
-
process.stdout.write("\x1b[2K" + C.brightBlue + " \u2570" + "\u2500".repeat(w - 2) + "\u256F" + C.reset + "\n"); lines++;
|
|
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);
|
|
2366
2370
|
|
|
2367
|
-
// Status bar
|
|
2371
|
+
// Status bar
|
|
2368
2372
|
var rawPerm = getSetting("permissions.defaultMode");
|
|
2369
2373
|
var permMode = typeof rawPerm === "string" ? rawPerm : "ask";
|
|
2370
|
-
// Check if --dangerously-skip-permissions or godmode
|
|
2371
2374
|
var isDangerous = process.argv.includes("--dangerously-skip-permissions") || permMode === "allow";
|
|
2372
2375
|
var permLabel = isDangerous ? "GOD MODE" : permMode === "deny" ? "LOCKED" : "ask permission";
|
|
2373
2376
|
var permIcon = isDangerous ? "\u26A1" : permMode === "deny" ? "\u2718" : "\u2753";
|
|
2374
2377
|
var permColor = isDangerous ? C.red + C.bold : permMode === "deny" ? C.red : C.yellow;
|
|
2375
2378
|
var modelName = typeof config.model === "string" ? config.model : (config.model && config.model.name ? config.model.name : "default");
|
|
2376
2379
|
var wdShort = config.workdir ? path.basename(config.workdir) : "~";
|
|
2377
|
-
|
|
2378
|
-
C.cyan + modelName + C.reset + C.dim + " \u2502 " + C.reset +
|
|
2379
|
-
C.dim + wdShort + C.reset;
|
|
2380
|
-
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);
|
|
2381
2381
|
|
|
2382
2382
|
// Menu
|
|
2383
2383
|
if (menuVisible && menuItems.length > 0) {
|
|
@@ -2388,25 +2388,67 @@ async function main() {
|
|
|
2388
2388
|
var descStr = item.desc.slice(0, getTermWidth() - 28);
|
|
2389
2389
|
var cmdColor = i === menuSelected ? C.green + C.bold : C.green;
|
|
2390
2390
|
var descColor = i === menuSelected ? C.brightWhite : C.white;
|
|
2391
|
-
|
|
2392
|
-
lines++;
|
|
2391
|
+
lines.push(prefix + cmdColor + cmdStr + descColor + descStr + C.reset);
|
|
2393
2392
|
});
|
|
2394
2393
|
if (menuItems.length > 8) {
|
|
2395
|
-
|
|
2396
|
-
lines++;
|
|
2394
|
+
lines.push(C.dim + " ... " + (menuItems.length - 8) + " more" + C.reset);
|
|
2397
2395
|
}
|
|
2398
2396
|
}
|
|
2399
2397
|
|
|
2400
|
-
|
|
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"
|
|
2401
2430
|
|
|
2402
|
-
// Position cursor inside the box (line 2, after text)
|
|
2403
|
-
process.stdout.write("\x1b[" + (lines - 1) + "A"); // back to content line
|
|
2404
|
-
process.stdout.write("\r\x1b[" + (4 + displayText.length) + "C"); // right to cursor pos
|
|
2405
2431
|
process.stdout.write("\x1b[?25h"); // show cursor
|
|
2406
2432
|
}
|
|
2407
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
|
+
|
|
2408
2450
|
function refreshUI() {
|
|
2409
|
-
eraseUI();
|
|
2451
|
+
if (uiStartRow > 0) eraseUI();
|
|
2410
2452
|
// Compute menu items
|
|
2411
2453
|
if (inputBuffer.startsWith("/")) {
|
|
2412
2454
|
var filter = inputBuffer.toLowerCase();
|
|
@@ -2425,7 +2467,7 @@ async function main() {
|
|
|
2425
2467
|
function drawPrompt() {
|
|
2426
2468
|
if (processing) return;
|
|
2427
2469
|
console.log(""); // spacing
|
|
2428
|
-
|
|
2470
|
+
uiStartRow = -1;
|
|
2429
2471
|
refreshUI();
|
|
2430
2472
|
}
|
|
2431
2473
|
|