blun-king-cli 2.3.1 → 2.4.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 +53 -18
- package/package.json +1 -1
package/bin/blun.js
CHANGED
|
@@ -2267,6 +2267,31 @@ async function main() {
|
|
|
2267
2267
|
printHeader();
|
|
2268
2268
|
checkForUpdates();
|
|
2269
2269
|
|
|
2270
|
+
// API Key check — prompt if missing
|
|
2271
|
+
if (!config.api.key && !process.argv.includes("--api-key")) {
|
|
2272
|
+
console.log("");
|
|
2273
|
+
console.log(C.yellow + " " + BOX.bot + " No API key configured." + C.reset);
|
|
2274
|
+
console.log(C.gray + " Enter your BLUN King API key (or press Enter to skip):" + C.reset);
|
|
2275
|
+
var apiKeyAnswer = await new Promise(function(resolve) {
|
|
2276
|
+
var rlKey = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
2277
|
+
rlKey.question(C.brightBlue + " API Key: " + C.reset, function(answer) {
|
|
2278
|
+
rlKey.close();
|
|
2279
|
+
resolve(answer.trim());
|
|
2280
|
+
});
|
|
2281
|
+
});
|
|
2282
|
+
if (apiKeyAnswer) {
|
|
2283
|
+
config.api.key = apiKeyAnswer;
|
|
2284
|
+
// Save to config file
|
|
2285
|
+
var cfgFile = path.join(CONFIG_DIR, "config.json");
|
|
2286
|
+
var cfgData = {};
|
|
2287
|
+
if (fs.existsSync(cfgFile)) { try { cfgData = JSON.parse(fs.readFileSync(cfgFile, "utf8")); } catch(e) {} }
|
|
2288
|
+
if (!cfgData.api) cfgData.api = {};
|
|
2289
|
+
cfgData.api.key = apiKeyAnswer;
|
|
2290
|
+
fs.writeFileSync(cfgFile, JSON.stringify(cfgData, null, 2));
|
|
2291
|
+
printSuccess("API key saved.");
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
|
|
2270
2295
|
// Load session history for this workdir
|
|
2271
2296
|
var session = loadSessionHistory();
|
|
2272
2297
|
chatHistory = session.history.slice(-20);
|
|
@@ -2307,12 +2332,19 @@ async function main() {
|
|
|
2307
2332
|
// Erase everything we drew and move cursor back to start
|
|
2308
2333
|
function eraseUI() {
|
|
2309
2334
|
if (drawnLines <= 0) return;
|
|
2310
|
-
// Move to
|
|
2311
|
-
process.stdout.write("\x1b["
|
|
2312
|
-
|
|
2313
|
-
|
|
2335
|
+
// Move cursor up to where we started drawing
|
|
2336
|
+
process.stdout.write("\x1b[?25l");
|
|
2337
|
+
// Go up drawnLines from current cursor position
|
|
2338
|
+
// Cursor is on content line (line 2), so we need to go up 1 to reach top
|
|
2339
|
+
process.stdout.write("\x1b[" + (drawnLines) + "A\r");
|
|
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");
|
|
2314
2344
|
}
|
|
2315
|
-
|
|
2345
|
+
// Go back up
|
|
2346
|
+
process.stdout.write("\x1b[" + (drawnLines + 3) + "A\r");
|
|
2347
|
+
process.stdout.write("\x1b[?25h");
|
|
2316
2348
|
drawnLines = 0;
|
|
2317
2349
|
}
|
|
2318
2350
|
|
|
@@ -2322,26 +2354,30 @@ async function main() {
|
|
|
2322
2354
|
var w = Math.min(getTermWidth() - 4, 76);
|
|
2323
2355
|
var displayText = inputBuffer;
|
|
2324
2356
|
if (displayText.length > w - 4) displayText = displayText.slice(-(w - 4));
|
|
2325
|
-
var pad = Math.max(0, w -
|
|
2357
|
+
var pad = Math.max(0, w - 3 - displayText.length);
|
|
2326
2358
|
var lines = 0;
|
|
2327
2359
|
|
|
2328
2360
|
// Box top
|
|
2329
|
-
process.stdout.write(C.brightBlue + " \u256D" + "\u2500".repeat(w - 2) + "\u256E" + C.reset + "\n"); lines++;
|
|
2361
|
+
process.stdout.write("\x1b[2K" + C.brightBlue + " \u256D" + "\u2500".repeat(w - 2) + "\u256E" + C.reset + "\n"); lines++;
|
|
2330
2362
|
// Box content
|
|
2331
|
-
process.stdout.write(C.brightBlue + " \u2502 " + C.reset + C.brightWhite + displayText + C.reset + " ".repeat(pad) + C.brightBlue + "\u2502" + C.reset + "\n"); lines++;
|
|
2363
|
+
process.stdout.write("\x1b[2K" + C.brightBlue + " \u2502 " + C.reset + C.brightWhite + displayText + C.reset + " ".repeat(pad) + C.brightBlue + "\u2502" + C.reset + "\n"); lines++;
|
|
2332
2364
|
// Box bottom
|
|
2333
|
-
process.stdout.write(C.brightBlue + " \u2570" + "\u2500".repeat(w - 2) + "\u256F" + C.reset + "\n"); lines++;
|
|
2365
|
+
process.stdout.write("\x1b[2K" + C.brightBlue + " \u2570" + "\u2500".repeat(w - 2) + "\u256F" + C.reset + "\n"); lines++;
|
|
2334
2366
|
|
|
2335
2367
|
// Status bar (permission mode + model + workdir)
|
|
2336
|
-
var
|
|
2337
|
-
var
|
|
2338
|
-
|
|
2368
|
+
var rawPerm = getSetting("permissions.defaultMode");
|
|
2369
|
+
var permMode = typeof rawPerm === "string" ? rawPerm : "ask";
|
|
2370
|
+
// Check if --dangerously-skip-permissions or godmode
|
|
2371
|
+
var isDangerous = process.argv.includes("--dangerously-skip-permissions") || permMode === "allow";
|
|
2372
|
+
var permLabel = isDangerous ? "GOD MODE" : permMode === "deny" ? "LOCKED" : "ask permission";
|
|
2373
|
+
var permIcon = isDangerous ? "\u26A1" : permMode === "deny" ? "\u2718" : "\u2753";
|
|
2374
|
+
var permColor = isDangerous ? C.red + C.bold : permMode === "deny" ? C.red : C.yellow;
|
|
2339
2375
|
var modelName = typeof config.model === "string" ? config.model : (config.model && config.model.name ? config.model.name : "default");
|
|
2340
2376
|
var wdShort = config.workdir ? path.basename(config.workdir) : "~";
|
|
2341
|
-
var statusLine = permColor + " " + permIcon + " " +
|
|
2377
|
+
var statusLine = permColor + " " + permIcon + " " + permLabel + C.reset + C.dim + " \u2502 " + C.reset +
|
|
2342
2378
|
C.cyan + modelName + C.reset + C.dim + " \u2502 " + C.reset +
|
|
2343
2379
|
C.dim + wdShort + C.reset;
|
|
2344
|
-
process.stdout.write(statusLine + "\
|
|
2380
|
+
process.stdout.write("\x1b[2K" + statusLine + "\n"); lines++;
|
|
2345
2381
|
|
|
2346
2382
|
// Menu
|
|
2347
2383
|
if (menuVisible && menuItems.length > 0) {
|
|
@@ -2352,11 +2388,11 @@ async function main() {
|
|
|
2352
2388
|
var descStr = item.desc.slice(0, getTermWidth() - 28);
|
|
2353
2389
|
var cmdColor = i === menuSelected ? C.green + C.bold : C.green;
|
|
2354
2390
|
var descColor = i === menuSelected ? C.brightWhite : C.white;
|
|
2355
|
-
process.stdout.write(prefix + cmdColor + cmdStr + descColor + descStr + C.reset + "\
|
|
2391
|
+
process.stdout.write("\x1b[2K" + prefix + cmdColor + cmdStr + descColor + descStr + C.reset + "\n");
|
|
2356
2392
|
lines++;
|
|
2357
2393
|
});
|
|
2358
2394
|
if (menuItems.length > 8) {
|
|
2359
|
-
process.stdout.write(C.dim + " ... " + (menuItems.length - 8) + " more" + C.reset + "\
|
|
2395
|
+
process.stdout.write("\x1b[2K" + C.dim + " ... " + (menuItems.length - 8) + " more" + C.reset + "\n");
|
|
2360
2396
|
lines++;
|
|
2361
2397
|
}
|
|
2362
2398
|
}
|
|
@@ -2364,8 +2400,7 @@ async function main() {
|
|
|
2364
2400
|
drawnLines = lines;
|
|
2365
2401
|
|
|
2366
2402
|
// Position cursor inside the box (line 2, after text)
|
|
2367
|
-
process.stdout.write("\x1b[" + lines + "A"); // back to
|
|
2368
|
-
process.stdout.write("\x1b[1B"); // down to content line
|
|
2403
|
+
process.stdout.write("\x1b[" + (lines - 1) + "A"); // back to content line
|
|
2369
2404
|
process.stdout.write("\r\x1b[" + (4 + displayText.length) + "C"); // right to cursor pos
|
|
2370
2405
|
process.stdout.write("\x1b[?25h"); // show cursor
|
|
2371
2406
|
}
|