blun-king-cli 1.0.0 → 1.2.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.
Files changed (2) hide show
  1. package/bin/blun.js +388 -34
  2. package/package.json +1 -1
package/bin/blun.js CHANGED
@@ -47,10 +47,16 @@ var config = loadConfig();
47
47
 
48
48
  // ── Colors ──
49
49
  const C = {
50
- reset: "\x1b[0m", bold: "\x1b[1m", dim: "\x1b[2m",
50
+ reset: "\x1b[0m", bold: "\x1b[1m", dim: "\x1b[2m", italic: "\x1b[3m",
51
51
  red: "\x1b[31m", green: "\x1b[32m", yellow: "\x1b[33m",
52
52
  blue: "\x1b[34m", magenta: "\x1b[35m", cyan: "\x1b[36m", white: "\x1b[37m",
53
- bg_blue: "\x1b[44m", bg_green: "\x1b[42m"
53
+ gray: "\x1b[90m", brightBlue: "\x1b[94m", brightCyan: "\x1b[96m", brightWhite: "\x1b[97m",
54
+ bg_blue: "\x1b[44m", bg_green: "\x1b[42m", bg_gray: "\x1b[100m", bg_darkBlue: "\x1b[48;5;17m"
55
+ };
56
+ // Box drawing helpers
57
+ const BOX = {
58
+ tl: "╭", tr: "╮", bl: "╰", br: "╯", h: "─", v: "│",
59
+ sep: "├", sepR: "┤", dot: "●", arrow: "❯", chat: "💬", bot: "🤖", user: "👤"
54
60
  };
55
61
 
56
62
  function log(msg) { if (config.verbose) fs.appendFileSync(LOG_FILE, new Date().toISOString() + " " + msg + "\n"); }
@@ -98,51 +104,68 @@ var chatHistory = [];
98
104
 
99
105
  // ── Print Helpers ──
100
106
  function printHeader() {
107
+ var w = Math.min(process.stdout.columns || 60, 60);
108
+ var line = BOX.h.repeat(w - 4);
101
109
  console.log("");
102
- console.log(C.bold + C.blue + " ╔══════════════════════════════════════╗" + C.reset);
103
- console.log(C.bold + C.blue + " BLUN KING CLI v1.0 ║" + C.reset);
104
- console.log(C.bold + C.blue + " Premium KI — Local First" + C.reset);
105
- console.log(C.bold + C.blue + " ╚══════════════════════════════════════╝" + C.reset);
106
- console.log("");
107
- console.log(C.dim + " API: " + config.api.base_url + C.reset);
108
- console.log(C.dim + " Auth: " + config.auth.type + (config.auth.api_key ? " (key set)" : " (no key)") + C.reset);
109
- console.log(C.dim + " Model: " + config.model + C.reset);
110
- console.log(C.dim + " Workdir: " + config.workdir + C.reset);
110
+ console.log(C.brightBlue + " " + BOX.tl + line + BOX.tr + C.reset);
111
+ console.log(C.brightBlue + " " + BOX.v + C.reset + C.bold + C.brightWhite + " " + BOX.bot + " BLUN KING CLI" + C.reset + C.dim + " v1.1" + C.reset + " ".repeat(Math.max(0, w - 24)) + C.brightBlue + BOX.v + C.reset);
112
+ console.log(C.brightBlue + " " + BOX.v + C.reset + C.gray + " Premium KI — Local First — Autonom" + C.reset + " ".repeat(Math.max(0, w - 41)) + C.brightBlue + BOX.v + C.reset);
113
+ console.log(C.brightBlue + " " + BOX.v + line + BOX.v + C.reset);
114
+ console.log(C.brightBlue + " " + BOX.v + C.reset + C.gray + " API " + C.brightCyan + config.api.base_url + C.reset + " ".repeat(Math.max(0, w - 14 - config.api.base_url.length)) + C.brightBlue + BOX.v + C.reset);
115
+ console.log(C.brightBlue + " " + BOX.v + C.reset + C.gray + " Model " + C.brightCyan + config.model + C.reset + " ".repeat(Math.max(0, w - 14 - config.model.length)) + C.brightBlue + BOX.v + C.reset);
116
+ var wdShort = config.workdir.length > w - 16 ? "..." + config.workdir.slice(-(w - 19)) : config.workdir;
117
+ console.log(C.brightBlue + " " + BOX.v + C.reset + C.gray + " Dir " + C.brightCyan + wdShort + C.reset + " ".repeat(Math.max(0, w - 14 - wdShort.length)) + C.brightBlue + BOX.v + C.reset);
118
+ console.log(C.brightBlue + " " + BOX.bl + line + BOX.br + C.reset);
111
119
  console.log("");
112
- console.log(C.dim + " Type /help for commands, or just chat." + C.reset);
120
+ console.log(C.gray + " /help " + C.dim + "for commands " + C.gray + BOX.dot + " just type to chat" + C.reset);
113
121
  console.log("");
114
122
  }
115
123
 
116
- function printAnswer(answer) {
124
+ function printAnswer(answer, meta) {
117
125
  console.log("");
118
- console.log(C.green + C.bold + "BLUN King:" + C.reset);
119
- // Simple markdown rendering
126
+ console.log(C.green + C.bold + " " + BOX.bot + " BLUN King" + C.reset + (meta ? C.gray + " " + BOX.dot + " " + meta + C.reset : ""));
127
+ console.log(C.green + " " + BOX.h.repeat(40) + C.reset);
128
+ // Markdown rendering
120
129
  var lines = answer.split("\n");
121
130
  var inCode = false;
122
131
  for (var i = 0; i < lines.length; i++) {
123
132
  var line = lines[i];
124
133
  if (line.startsWith("```")) {
125
134
  inCode = !inCode;
126
- console.log(C.dim + line + C.reset);
135
+ if (inCode) {
136
+ var lang = line.slice(3).trim();
137
+ console.log(C.dim + " " + BOX.tl + BOX.h.repeat(38) + (lang ? " " + lang + " " : "") + C.reset);
138
+ } else {
139
+ console.log(C.dim + " " + BOX.bl + BOX.h.repeat(38) + C.reset);
140
+ }
127
141
  } else if (inCode) {
128
- console.log(C.cyan + line + C.reset);
142
+ console.log(C.cyan + " " + BOX.v + " " + line + C.reset);
129
143
  } else if (line.startsWith("# ")) {
130
- console.log(C.bold + C.yellow + line + C.reset);
144
+ console.log(C.bold + C.yellow + " " + line + C.reset);
131
145
  } else if (line.startsWith("## ")) {
132
- console.log(C.bold + C.magenta + line + C.reset);
146
+ console.log(C.bold + C.magenta + " " + line + C.reset);
133
147
  } else if (line.startsWith("### ")) {
134
- console.log(C.bold + line + C.reset);
148
+ console.log(C.bold + " " + line + C.reset);
135
149
  } else if (line.startsWith("- ") || line.startsWith("* ")) {
136
- console.log(C.white + " " + line + C.reset);
150
+ console.log(C.white + " " + line + C.reset);
137
151
  } else if (line.match(/^\d+\./)) {
138
- console.log(C.white + " " + line + C.reset);
152
+ console.log(C.white + " " + line + C.reset);
153
+ } else if (line.startsWith("**") && line.endsWith("**")) {
154
+ console.log(C.bold + C.brightWhite + " " + line + C.reset);
139
155
  } else {
140
- console.log(line);
156
+ console.log(" " + line);
141
157
  }
142
158
  }
143
159
  console.log("");
144
160
  }
145
161
 
162
+ function printUserMessage(msg) {
163
+ console.log("");
164
+ console.log(C.brightBlue + C.bold + " " + BOX.user + " Du" + C.reset);
165
+ console.log(C.brightBlue + " " + BOX.h.repeat(40) + C.reset);
166
+ console.log(C.brightWhite + " " + msg + C.reset);
167
+ }
168
+
146
169
  function printError(msg) { console.log(C.red + "ERROR: " + msg + C.reset); }
147
170
  function printInfo(msg) { console.log(C.cyan + msg + C.reset); }
148
171
  function printSuccess(msg) { console.log(C.green + "✓ " + msg + C.reset); }
@@ -185,6 +208,16 @@ async function handleCommand(input) {
185
208
  console.log(" /set telegram Configure Telegram bridge");
186
209
  console.log(" /set verbose Toggle verbose logging");
187
210
  console.log("");
211
+ console.log(C.yellow + " DEV" + C.reset);
212
+ console.log(" /sh <cmd> Run shell command");
213
+ console.log(" /git <cmd> Git commands (status, log, diff, add, commit, push, pull, branch, checkout, clone, init)");
214
+ console.log(" /ssh add/del/list Connect & manage SSH hosts");
215
+ console.log(" /ssh <host> <cmd> Run command on remote host");
216
+ console.log(" /deploy <method> Deploy: git, ssh, sync, pm2");
217
+ console.log(" /read <file> Read a file");
218
+ console.log(" /write <file> Write/create a file");
219
+ console.log(" /init Init project (AGENT.md, .gitignore, git init)");
220
+ console.log("");
188
221
  console.log(C.yellow + " SYSTEM" + C.reset);
189
222
  console.log(" /status Runtime status");
190
223
  console.log(" /versions Prompt versions");
@@ -272,6 +305,34 @@ async function handleCommand(input) {
272
305
  cmdFiles();
273
306
  break;
274
307
 
308
+ case "/sh":
309
+ cmdShell(args);
310
+ break;
311
+
312
+ case "/git":
313
+ cmdGit(args);
314
+ break;
315
+
316
+ case "/ssh":
317
+ cmdSsh(args);
318
+ break;
319
+
320
+ case "/deploy":
321
+ cmdDeploy(args);
322
+ break;
323
+
324
+ case "/read":
325
+ cmdRead(args);
326
+ break;
327
+
328
+ case "/write":
329
+ cmdWrite(args);
330
+ break;
331
+
332
+ case "/init":
333
+ cmdInit();
334
+ break;
335
+
275
336
  case "/exit":
276
337
  case "/quit":
277
338
  case "/q":
@@ -286,12 +347,22 @@ async function handleCommand(input) {
286
347
  // ── Chat ──
287
348
  async function sendChat(message) {
288
349
  try {
289
- process.stdout.write(C.dim + "⏳ thinking..." + C.reset);
350
+ printUserMessage(message);
351
+ // Animated thinking
352
+ var dots = 0;
353
+ var thinkFrames = ["thinking", "thinking.", "thinking..", "thinking..."];
354
+ var thinkTimer = setInterval(function() {
355
+ process.stdout.write("\r" + C.dim + " " + BOX.bot + " " + thinkFrames[dots % 4] + " " + C.reset);
356
+ dots++;
357
+ }, 300);
358
+
290
359
  var resp = await apiCall("POST", "/chat", {
291
360
  message: message,
292
361
  history: chatHistory.slice(-10)
293
362
  });
294
- process.stdout.write("\r" + " ".repeat(30) + "\r");
363
+
364
+ clearInterval(thinkTimer);
365
+ process.stdout.write("\r" + " ".repeat(40) + "\r");
295
366
 
296
367
  if (resp.status !== 200) {
297
368
  printError(resp.data.error || "API Error " + resp.status);
@@ -301,17 +372,14 @@ async function sendChat(message) {
301
372
  chatHistory.push({ role: "user", content: message });
302
373
  chatHistory.push({ role: "assistant", content: resp.data.answer });
303
374
 
304
- printAnswer(resp.data.answer);
305
-
306
- // Status line
307
375
  var q = resp.data.quality || {};
308
- console.log(C.dim + " [" + resp.data.task_type + "/" + resp.data.role + " | score: " + (q.score || "?") +
309
- (q.retried ? " | retried" : "") +
310
- (q.flags && q.flags.length > 0 ? " | flags: " + q.flags.join(", ") : "") + "]" + C.reset);
311
- console.log("");
376
+ var meta = resp.data.task_type + "/" + resp.data.role + " " + BOX.dot + " score: " + (q.score || "?") +
377
+ (q.retried ? " " + BOX.dot + " retried" : "");
378
+ printAnswer(resp.data.answer, meta);
312
379
 
313
380
  } catch(e) {
314
- process.stdout.write("\r" + " ".repeat(30) + "\r");
381
+ if (typeof thinkTimer !== "undefined") clearInterval(thinkTimer);
382
+ process.stdout.write("\r" + " ".repeat(40) + "\r");
315
383
  printError("Connection failed: " + e.message);
316
384
  }
317
385
  }
@@ -733,6 +801,277 @@ function cmdFiles() {
733
801
  } catch(e) { printError(e.message); }
734
802
  }
735
803
 
804
+ // ── Shell Execution ──
805
+ function cmdShell(command) {
806
+ if (!command) { printError("Usage: /sh <command>"); return; }
807
+ try {
808
+ console.log(C.dim + "$ " + command + C.reset);
809
+ var output = execSync(command, { cwd: config.workdir, encoding: "utf8", timeout: 30000, stdio: ["pipe", "pipe", "pipe"] });
810
+ console.log(output);
811
+ } catch(e) {
812
+ if (e.stdout) console.log(e.stdout);
813
+ if (e.stderr) console.log(C.red + e.stderr + C.reset);
814
+ printError("Exit code: " + (e.status || "unknown"));
815
+ }
816
+ }
817
+
818
+ // ── Git Commands ──
819
+ function cmdGit(args) {
820
+ if (!args) {
821
+ // Show git status
822
+ cmdShell("git status --short");
823
+ return;
824
+ }
825
+ var sub = args.split(/\s+/)[0];
826
+ var rest = args.slice(sub.length).trim();
827
+
828
+ switch(sub) {
829
+ case "status": cmdShell("git status"); break;
830
+ case "log": cmdShell("git log --oneline -10"); break;
831
+ case "diff": cmdShell("git diff --stat"); break;
832
+ case "add":
833
+ cmdShell("git add " + (rest || "."));
834
+ printSuccess("Files staged.");
835
+ break;
836
+ case "commit":
837
+ if (!rest) { printError("Usage: /git commit <message>"); return; }
838
+ cmdShell('git commit -m "' + rest.replace(/"/g, '\\"') + '"');
839
+ break;
840
+ case "push":
841
+ var remote = rest || "origin";
842
+ try {
843
+ var branch = execSync("git branch --show-current", { cwd: config.workdir, encoding: "utf8" }).trim();
844
+ printInfo("Pushing " + branch + " to " + remote + "...");
845
+ cmdShell("git push " + remote + " " + branch);
846
+ printSuccess("Pushed!");
847
+ } catch(e) { printError("Push failed: " + e.message); }
848
+ break;
849
+ case "pull":
850
+ cmdShell("git pull " + (rest || ""));
851
+ break;
852
+ case "branch":
853
+ cmdShell("git branch " + (rest || "-a"));
854
+ break;
855
+ case "checkout":
856
+ if (!rest) { printError("Usage: /git checkout <branch>"); return; }
857
+ cmdShell("git checkout " + rest);
858
+ break;
859
+ case "clone":
860
+ if (!rest) { printError("Usage: /git clone <url>"); return; }
861
+ cmdShell("git clone " + rest);
862
+ break;
863
+ case "init":
864
+ cmdShell("git init");
865
+ break;
866
+ case "remote":
867
+ cmdShell("git remote -v");
868
+ break;
869
+ default:
870
+ cmdShell("git " + args);
871
+ }
872
+ }
873
+
874
+ // ── SSH Commands ──
875
+ function cmdSsh(args) {
876
+ if (!args) {
877
+ // Show saved connections
878
+ var sshFile = path.join(CONFIG_DIR, "ssh.json");
879
+ if (fs.existsSync(sshFile)) {
880
+ var connections = JSON.parse(fs.readFileSync(sshFile, "utf8"));
881
+ console.log("");
882
+ console.log(C.bold + "SSH Connections:" + C.reset);
883
+ for (var name in connections) {
884
+ var c = connections[name];
885
+ console.log(" " + C.yellow + name + C.reset + " — " + c.user + "@" + c.host + (c.port !== 22 ? ":" + c.port : ""));
886
+ }
887
+ console.log("");
888
+ console.log(C.dim + " /ssh <name> <command> — Run command" + C.reset);
889
+ console.log(C.dim + " /ssh add <name> <user@host> — Add connection" + C.reset);
890
+ console.log(C.dim + " /ssh del <name> — Remove connection" + C.reset);
891
+ } else {
892
+ printInfo("No SSH connections saved. Use /ssh add <name> <user@host>");
893
+ }
894
+ return;
895
+ }
896
+
897
+ var parts = args.split(/\s+/);
898
+ var sshFile = path.join(CONFIG_DIR, "ssh.json");
899
+ var connections = {};
900
+ if (fs.existsSync(sshFile)) {
901
+ try { connections = JSON.parse(fs.readFileSync(sshFile, "utf8")); } catch(e) {}
902
+ }
903
+
904
+ if (parts[0] === "add" && parts[1] && parts[2]) {
905
+ var match = parts[2].match(/^([^@]+)@([^:]+)(?::(\d+))?$/);
906
+ if (!match) { printError("Format: user@host or user@host:port"); return; }
907
+ connections[parts[1]] = { user: match[1], host: match[2], port: parseInt(match[3] || "22"), key: parts[3] || null };
908
+ fs.writeFileSync(sshFile, JSON.stringify(connections, null, 2));
909
+ printSuccess("SSH connection '" + parts[1] + "' saved.");
910
+ return;
911
+ }
912
+
913
+ if (parts[0] === "del" && parts[1]) {
914
+ delete connections[parts[1]];
915
+ fs.writeFileSync(sshFile, JSON.stringify(connections, null, 2));
916
+ printSuccess("SSH connection '" + parts[1] + "' removed.");
917
+ return;
918
+ }
919
+
920
+ // Execute command on saved connection
921
+ var connName = parts[0];
922
+ var remoteCmd = parts.slice(1).join(" ");
923
+ if (!connections[connName]) { printError("Unknown connection: " + connName + ". Use /ssh to list."); return; }
924
+ if (!remoteCmd) { printError("Usage: /ssh " + connName + " <command>"); return; }
925
+
926
+ var conn = connections[connName];
927
+ var sshCmd = "ssh";
928
+ if (conn.key) sshCmd += " -i " + conn.key;
929
+ sshCmd += " -o ConnectTimeout=10 -o StrictHostKeyChecking=no";
930
+ sshCmd += " -p " + conn.port;
931
+ sshCmd += " " + conn.user + "@" + conn.host;
932
+ sshCmd += ' "' + remoteCmd.replace(/"/g, '\\"') + '"';
933
+
934
+ printInfo("SSH " + connName + ": " + remoteCmd);
935
+ cmdShell(sshCmd);
936
+ }
937
+
938
+ // ── Deploy Command ──
939
+ async function cmdDeploy(args) {
940
+ if (!args) {
941
+ console.log("");
942
+ console.log(C.bold + "Deploy Options:" + C.reset);
943
+ console.log(" /deploy git — git add + commit + push");
944
+ console.log(" /deploy ssh <name> <cmd> — Run deploy command via SSH");
945
+ console.log(" /deploy sync <name> — rsync workdir to server");
946
+ console.log(" /deploy pm2 <name> <app> — pm2 restart on server");
947
+ console.log("");
948
+ return;
949
+ }
950
+
951
+ var parts = args.split(/\s+/);
952
+ var action = parts[0];
953
+
954
+ if (action === "git") {
955
+ printInfo("Deploying via git...");
956
+ try {
957
+ var status = execSync("git status --porcelain", { cwd: config.workdir, encoding: "utf8" }).trim();
958
+ if (status) {
959
+ cmdShell("git add .");
960
+ var msg = parts.slice(1).join(" ") || "deploy: " + new Date().toISOString().slice(0, 16);
961
+ cmdShell('git commit -m "' + msg + '"');
962
+ }
963
+ var branch = execSync("git branch --show-current", { cwd: config.workdir, encoding: "utf8" }).trim();
964
+ cmdShell("git push origin " + branch);
965
+ printSuccess("Deployed via git push!");
966
+ } catch(e) { printError("Deploy failed: " + e.message); }
967
+
968
+ } else if (action === "ssh" && parts[1]) {
969
+ cmdSsh(parts.slice(1).join(" "));
970
+
971
+ } else if (action === "sync" && parts[1]) {
972
+ var sshFile = path.join(CONFIG_DIR, "ssh.json");
973
+ if (!fs.existsSync(sshFile)) { printError("No SSH connections. Use /ssh add first."); return; }
974
+ var connections = JSON.parse(fs.readFileSync(sshFile, "utf8"));
975
+ var conn = connections[parts[1]];
976
+ if (!conn) { printError("Unknown connection: " + parts[1]); return; }
977
+ var dest = parts[2] || "/root/" + path.basename(config.workdir);
978
+ var rsyncCmd = "rsync -avz --exclude node_modules --exclude .git";
979
+ if (conn.key) rsyncCmd += " -e 'ssh -i " + conn.key + " -p " + conn.port + "'";
980
+ rsyncCmd += " " + config.workdir + "/ " + conn.user + "@" + conn.host + ":" + dest + "/";
981
+ printInfo("Syncing to " + parts[1] + ":" + dest);
982
+ cmdShell(rsyncCmd);
983
+
984
+ } else if (action === "pm2" && parts[1] && parts[2]) {
985
+ cmdSsh(parts[1] + " pm2 restart " + parts[2]);
986
+
987
+ } else {
988
+ printError("Unknown deploy action. Use /deploy for help.");
989
+ }
990
+ }
991
+
992
+ // ── Read/Write Files ──
993
+ function cmdRead(filePath) {
994
+ if (!filePath) { printError("Usage: /read <file>"); return; }
995
+ var full = path.resolve(config.workdir, filePath);
996
+ if (!fs.existsSync(full)) { printError("File not found: " + full); return; }
997
+ var content = fs.readFileSync(full, "utf8");
998
+ console.log("");
999
+ console.log(C.bold + "File: " + full + C.reset);
1000
+ console.log(C.dim + "─".repeat(50) + C.reset);
1001
+ var lines = content.split("\n");
1002
+ for (var i = 0; i < lines.length; i++) {
1003
+ console.log(C.dim + String(i + 1).padStart(4) + " │ " + C.reset + lines[i]);
1004
+ }
1005
+ console.log("");
1006
+ }
1007
+
1008
+ function cmdWrite(args) {
1009
+ if (!args) { printError("Usage: /write <file> <content> or /write <file> (then type content, end with EOF)"); return; }
1010
+ var parts = args.split(/\s+/);
1011
+ var filePath = parts[0];
1012
+ var content = parts.slice(1).join(" ");
1013
+ var full = path.resolve(config.workdir, filePath);
1014
+
1015
+ if (content) {
1016
+ fs.writeFileSync(full, content);
1017
+ printSuccess("Written: " + full + " (" + content.length + " bytes)");
1018
+ } else {
1019
+ printInfo("Type content (end with line 'EOF'):");
1020
+ // This will be handled differently in interactive mode
1021
+ printError("For multi-line write, use: /generate instead");
1022
+ }
1023
+ }
1024
+
1025
+ // ── Project Init ──
1026
+ function cmdInit(args) {
1027
+ var name = args || path.basename(config.workdir);
1028
+ var projectDir = args ? path.join(config.workdir, args) : config.workdir;
1029
+
1030
+ if (args && !fs.existsSync(projectDir)) {
1031
+ fs.mkdirSync(projectDir, { recursive: true });
1032
+ }
1033
+
1034
+ // Create project memory file
1035
+ var memFile = path.join(projectDir, "AGENT.md");
1036
+ if (!fs.existsSync(memFile)) {
1037
+ var agentContent = "# " + name + "\n\n" +
1038
+ "## Projekt\n" +
1039
+ "Beschreibung: \n\n" +
1040
+ "## Stack\n" +
1041
+ "- \n\n" +
1042
+ "## Regeln\n" +
1043
+ "- \n\n" +
1044
+ "## Status\n" +
1045
+ "Erstellt: " + new Date().toISOString().split("T")[0] + "\n";
1046
+ fs.writeFileSync(memFile, agentContent);
1047
+ printSuccess("AGENT.md erstellt in " + projectDir);
1048
+ } else {
1049
+ printInfo("AGENT.md existiert bereits.");
1050
+ }
1051
+
1052
+ // Git init if not already
1053
+ try {
1054
+ execSync("git rev-parse --git-dir", { cwd: projectDir, stdio: "pipe" });
1055
+ printInfo("Git repo already initialized.");
1056
+ } catch(e) {
1057
+ execSync("git init", { cwd: projectDir, stdio: "pipe" });
1058
+ printSuccess("Git repo initialized.");
1059
+ }
1060
+
1061
+ // Create .gitignore if missing
1062
+ var gitignore = path.join(projectDir, ".gitignore");
1063
+ if (!fs.existsSync(gitignore)) {
1064
+ fs.writeFileSync(gitignore, "node_modules/\n.env\n*.log\n.blun/\n");
1065
+ printSuccess(".gitignore erstellt.");
1066
+ }
1067
+
1068
+ if (args) {
1069
+ config.workdir = projectDir;
1070
+ saveConfig(config);
1071
+ printSuccess("Workdir set to: " + projectDir);
1072
+ }
1073
+ }
1074
+
736
1075
  // ── Main Loop ──
737
1076
  async function main() {
738
1077
  // Handle CLI args
@@ -783,10 +1122,25 @@ async function main() {
783
1122
  printInfo("Run: blun setup — to configure");
784
1123
  }
785
1124
 
1125
+ var ALL_COMMANDS = [
1126
+ "/help", "/clear", "/skills", "/skill", "/search", "/learn", "/learn-url",
1127
+ "/generate", "/analyze", "/score", "/eval", "/settings", "/set",
1128
+ "/status", "/versions", "/health", "/watchdog", "/memory", "/files",
1129
+ "/sh", "/git", "/ssh", "/deploy", "/read", "/write", "/init",
1130
+ "/screenshot", "/render", "/agent", "/exit"
1131
+ ];
1132
+
786
1133
  var rl = readline.createInterface({
787
1134
  input: process.stdin,
788
1135
  output: process.stdout,
789
- prompt: C.blue + C.bold + "blun > " + C.reset
1136
+ prompt: "\n" + C.brightBlue + C.bold + " " + BOX.arrow + " " + C.reset,
1137
+ completer: function(line) {
1138
+ if (line.startsWith("/")) {
1139
+ var hits = ALL_COMMANDS.filter(function(c) { return c.startsWith(line); });
1140
+ return [hits.length ? hits : ALL_COMMANDS, line];
1141
+ }
1142
+ return [[], line];
1143
+ }
790
1144
  });
791
1145
 
792
1146
  rl.prompt();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "BLUN King CLI — Premium KI Console",
5
5
  "bin": {
6
6
  "blun": "./bin/blun.js"