blun-king-cli 5.2.5 → 5.3.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 +172 -52
  2. package/package.json +1 -1
package/blun-cli.js CHANGED
@@ -147,8 +147,7 @@ function printHeader() {
147
147
  // ── Update Checker ──
148
148
  function checkForUpdates() {
149
149
  try {
150
- var currentVersion = "1.4.0";
151
- try { currentVersion = require(path.join(__dirname, "..", "package.json")).version; } catch(e) {}
150
+ var currentVersion = PKG_VERSION;
152
151
  var nullDev = process.platform === "win32" ? "2>NUL" : "2>/dev/null";
153
152
  var latest = execSync("npm view blun-king-cli version " + nullDev, { encoding: "utf8", timeout: 8000, stdio: ["pipe", "pipe", "pipe"] }).trim();
154
153
  if (latest && latest !== currentVersion) {
@@ -534,7 +533,7 @@ async function handleCommand(input) {
534
533
  break;
535
534
 
536
535
  case "/login":
537
- cmdLogin(args);
536
+ await cmdLogin(args);
538
537
  break;
539
538
 
540
539
  case "/logout":
@@ -2224,21 +2223,106 @@ function cmdModel(args) {
2224
2223
  // ══════════════════════════════════════════════════
2225
2224
  // ── 9. /login /logout ──
2226
2225
  // ══════════════════════════════════════════════════
2227
- function cmdLogin(args) {
2226
+ async function cmdLogin(args) {
2228
2227
  if (args && args.startsWith("key ")) {
2229
2228
  config.auth.api_key = args.slice(4).trim();
2230
2229
  config.auth.type = "api_key";
2230
+ config.api.key = config.auth.api_key;
2231
2231
  saveConfig(config);
2232
2232
  printSuccess("Logged in with API key.");
2233
- } else if (args === "oauth") {
2234
- printInfo("OAuth login not yet implemented. Use API key for now:");
2235
- printInfo(" /login key <your-api-key>");
2236
- } else {
2233
+ return;
2234
+ }
2235
+
2236
+ // Device Flow (like Claude Code)
2237
+ console.log("");
2238
+ console.log(C.bold + C.brightWhite + " BLUN King Login" + C.reset);
2239
+ console.log(C.gray + " Connecting to " + config.api.base_url + "..." + C.reset);
2240
+
2241
+ try {
2242
+ // Step 1: Start device flow
2243
+ var deviceResp = await apiCall("POST", "/api/king/auth/device", {});
2244
+ if (deviceResp.status !== 200 || !deviceResp.data.user_code) {
2245
+ // Fallback: API key login
2246
+ printInfo("Device flow not available. Use API key:");
2247
+ printInfo(" /login key <your-api-key>");
2248
+ return;
2249
+ }
2250
+
2251
+ var deviceCode = deviceResp.data.device_code;
2252
+ var userCode = deviceResp.data.user_code;
2253
+ var verifyUrl = deviceResp.data.verification_url;
2254
+ var pollInterval = (deviceResp.data.interval || 5) * 1000;
2255
+ var expiresIn = deviceResp.data.expires_in || 900;
2256
+
2237
2257
  console.log("");
2238
- console.log(C.bold + " Login:" + C.reset);
2239
- console.log(" /login key <api-key> — Login with API key");
2240
- console.log(" /login oauth — Login with OAuth (coming soon)");
2258
+ console.log(C.yellow + C.bold + " Code: " + C.brightWhite + userCode + C.reset);
2259
+ console.log(C.gray + " Gib diesen Code im Browser ein:" + C.reset);
2260
+ console.log(C.brightCyan + " " + verifyUrl + C.reset);
2241
2261
  console.log("");
2262
+
2263
+ // Try to open browser
2264
+ try {
2265
+ if (process.platform === "win32") {
2266
+ require("child_process").execSync('start "" "' + verifyUrl + '"', { stdio: "ignore" });
2267
+ } else if (process.platform === "darwin") {
2268
+ require("child_process").execSync('open "' + verifyUrl + '"', { stdio: "ignore" });
2269
+ } else {
2270
+ require("child_process").execSync('xdg-open "' + verifyUrl + '" 2>/dev/null || true', { stdio: "ignore" });
2271
+ }
2272
+ printInfo("Browser geöffnet.");
2273
+ } catch(e) {
2274
+ printInfo("Öffne den Link manuell im Browser.");
2275
+ }
2276
+
2277
+ console.log(C.dim + " Warte auf Freigabe..." + C.reset);
2278
+
2279
+ // Step 2: Poll for authorization
2280
+ var maxPolls = Math.floor(expiresIn * 1000 / pollInterval);
2281
+ var authorized = false;
2282
+ for (var p = 0; p < maxPolls; p++) {
2283
+ await new Promise(function(r) { setTimeout(r, pollInterval); });
2284
+ try {
2285
+ var tokenResp = await apiCall("POST", "/api/king/auth/token", { device_code: deviceCode });
2286
+ if (tokenResp.status === 200 && tokenResp.data.access_token) {
2287
+ // Success!
2288
+ config.auth.type = "oauth";
2289
+ config.auth.oauth_token = tokenResp.data.access_token;
2290
+ config.auth.oauth_expires = new Date(Date.now() + (tokenResp.data.expires_in || 86400) * 1000).toISOString();
2291
+ config.auth.refresh_token = tokenResp.data.refresh_token || "";
2292
+ config.api.key = tokenResp.data.access_token;
2293
+ if (tokenResp.data.user) {
2294
+ config.auth.user = tokenResp.data.user;
2295
+ }
2296
+ saveConfig(config);
2297
+ console.log("");
2298
+ printSuccess("Eingeloggt!" + (tokenResp.data.user ? " (" + (tokenResp.data.user.email || tokenResp.data.user.name) + ")" : ""));
2299
+ if (tokenResp.data.user && tokenResp.data.user.plan) {
2300
+ printInfo("Plan: " + tokenResp.data.user.plan);
2301
+ }
2302
+ authorized = true;
2303
+ break;
2304
+ }
2305
+ // 428 = authorization_pending → keep polling
2306
+ if (tokenResp.status === 428) {
2307
+ process.stdout.write(".");
2308
+ continue;
2309
+ }
2310
+ // Other error
2311
+ if (tokenResp.data && tokenResp.data.error === "expired_token") {
2312
+ printError("Code abgelaufen. Starte /login erneut.");
2313
+ break;
2314
+ }
2315
+ } catch(pollErr) {
2316
+ // Network error, retry
2317
+ continue;
2318
+ }
2319
+ }
2320
+ if (!authorized) {
2321
+ printError("Login fehlgeschlagen oder abgelaufen.");
2322
+ }
2323
+ } catch(e) {
2324
+ printError("Login error: " + e.message);
2325
+ printInfo("Fallback: /login key <your-api-key>");
2242
2326
  }
2243
2327
  }
2244
2328
 
@@ -2558,50 +2642,86 @@ async function main() {
2558
2642
  }
2559
2643
  }
2560
2644
 
2561
- // API KeyALWAYS prompt (like Claude Code login)
2562
- var existingKey = config.api.key || config.auth.api_key || "";
2563
- console.log("");
2564
- console.log(C.yellow + C.bold + " API Key" + C.reset);
2565
- if (existingKey.length > 3) {
2566
- console.log(C.gray + " Current: " + C.green + existingKey.slice(0, 8) + "..." + C.reset);
2567
- console.log(C.gray + " Press Enter to keep, or type a new key:" + C.reset);
2568
- } else {
2569
- console.log(C.gray + " Enter your BLUN King API key:" + C.reset);
2570
- }
2571
- process.stdout.write(C.brightBlue + " API Key: " + C.reset);
2572
- var apiKeyAnswer = await new Promise(function(resolve) {
2573
- var buf = "";
2574
- process.stdin.setRawMode(true);
2575
- process.stdin.resume();
2576
- process.stdin.setEncoding("utf8");
2577
- function onKeyApi(key) {
2578
- if (key === "\x03") { process.exit(0); }
2579
- if (key === "\r" || key === "\n") {
2580
- process.stdin.removeListener("data", onKeyApi);
2581
- process.stdin.setRawMode(false);
2582
- process.stdin.pause();
2583
- process.stdout.write("\n");
2584
- resolve(buf.trim());
2585
- return;
2645
+ // Auth checkif no valid key/token, prompt for login or API key
2646
+ var existingKey = config.api.key || config.auth.api_key || config.auth.oauth_token || "";
2647
+ if (existingKey.length < 3) {
2648
+ console.log("");
2649
+ console.log(C.yellow + C.bold + " Authentication required" + C.reset);
2650
+ console.log(C.gray + " Choose how to connect:" + C.reset);
2651
+ console.log("");
2652
+
2653
+ var authOptions = [
2654
+ { label: "Login (opens browser)", action: "login" },
2655
+ { label: "Enter API key", action: "key" }
2656
+ ];
2657
+ var authSel = 0;
2658
+ var authChoice = await new Promise(function(resolve) {
2659
+ function render() {
2660
+ process.stdout.write("\x1b[2A\r");
2661
+ authOptions.forEach(function(opt, i) {
2662
+ var prefix = i === authSel ? "\x1b[32m\x1b[1m \u276F " : " ";
2663
+ var color = i === authSel ? "\x1b[97m\x1b[1m" : "\x1b[90m";
2664
+ process.stdout.write("\x1b[2K" + prefix + color + opt.label + "\x1b[0m\n");
2665
+ });
2586
2666
  }
2587
- if (key === "\x7f" || key === "\b") {
2588
- if (buf.length > 0) { buf = buf.slice(0, -1); process.stdout.write("\b \b"); }
2589
- return;
2667
+ console.log(""); console.log("");
2668
+ render();
2669
+ process.stdin.setRawMode(true);
2670
+ process.stdin.resume();
2671
+ process.stdin.setEncoding("utf8");
2672
+ function onKey(key) {
2673
+ if (key === "\x1b[A") { authSel = Math.max(0, authSel - 1); render(); return; }
2674
+ if (key === "\x1b[B") { authSel = Math.min(1, authSel + 1); render(); return; }
2675
+ if (key === "\r" || key === "\n") {
2676
+ process.stdin.removeListener("data", onKey);
2677
+ process.stdin.setRawMode(false);
2678
+ process.stdin.pause();
2679
+ resolve(authOptions[authSel].action);
2680
+ return;
2681
+ }
2682
+ if (key === "\x03") { process.exit(0); }
2683
+ }
2684
+ process.stdin.on("data", onKey);
2685
+ });
2686
+
2687
+ if (authChoice === "login") {
2688
+ await cmdLogin("");
2689
+ } else {
2690
+ console.log("");
2691
+ process.stdout.write(C.brightBlue + " API Key: " + C.reset);
2692
+ var apiKeyAnswer = await new Promise(function(resolve) {
2693
+ var buf = "";
2694
+ process.stdin.setRawMode(true);
2695
+ process.stdin.resume();
2696
+ process.stdin.setEncoding("utf8");
2697
+ function onKeyApi(key) {
2698
+ if (key === "\x03") { process.exit(0); }
2699
+ if (key === "\r" || key === "\n") {
2700
+ process.stdin.removeListener("data", onKeyApi);
2701
+ process.stdin.setRawMode(false);
2702
+ process.stdin.pause();
2703
+ process.stdout.write("\n");
2704
+ resolve(buf.trim());
2705
+ return;
2706
+ }
2707
+ if (key === "\x7f" || key === "\b") {
2708
+ if (buf.length > 0) { buf = buf.slice(0, -1); process.stdout.write("\b \b"); }
2709
+ return;
2710
+ }
2711
+ buf += key;
2712
+ process.stdout.write("*");
2713
+ }
2714
+ process.stdin.on("data", onKeyApi);
2715
+ });
2716
+ if (apiKeyAnswer) {
2717
+ config.api.key = apiKeyAnswer;
2718
+ config.auth.api_key = apiKeyAnswer;
2719
+ saveConfig(config);
2720
+ printSuccess("API key saved.");
2721
+ } else {
2722
+ printError("No API key — some features won't work.");
2590
2723
  }
2591
- buf += key;
2592
- process.stdout.write("*");
2593
2724
  }
2594
- process.stdin.on("data", onKeyApi);
2595
- });
2596
- if (apiKeyAnswer) {
2597
- config.api.key = apiKeyAnswer;
2598
- config.auth.api_key = apiKeyAnswer;
2599
- saveConfig(config);
2600
- printSuccess("API key saved.");
2601
- } else if (existingKey.length > 3) {
2602
- printSuccess("Using saved key.");
2603
- } else {
2604
- printError("No API key — some features won't work.");
2605
2725
  }
2606
2726
 
2607
2727
  printHeader();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "5.2.5",
3
+ "version": "5.3.1",
4
4
  "description": "BLUN King CLI — Your local AI assistant powered by Gemma4",
5
5
  "type": "commonjs",
6
6
  "bin": {