blun-king-cli 6.4.2 → 7.0.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/lib/client.js CHANGED
@@ -1,65 +1,127 @@
1
- const https = require('https');
2
- const auth = require('./auth');
1
+ /**
2
+ * BLUN King CLI v7.0.0 - API Client
3
+ * CommonJS - uses native https + fetch
4
+ */
3
5
 
4
- const BASE_HOST = 'blun.ai';
6
+ var https = require("https");
7
+ var auth = require("./auth");
8
+
9
+ var BASE_HOST = "blun.ai";
5
10
 
6
11
  function request(method, urlPath, body) {
7
- return new Promise((resolve, reject) => {
8
- const authHeader = auth.getAuthHeader() || {};
9
- const headers = { 'Content-Type': 'application/json', ...authHeader };
10
- const req = https.request({ hostname: BASE_HOST, path: urlPath, method, headers }, (res) => {
11
- let data = '';
12
- res.on('data', (c) => data += c);
13
- res.on('end', () => {
14
- try { resolve({ status: res.statusCode, data: JSON.parse(data) }); }
15
- catch { resolve({ status: res.statusCode, data }); }
16
- });
12
+ return new Promise(function (resolve, reject) {
13
+ var authHeader = auth.getAuthHeader() || {};
14
+ var headers = { "Content-Type": "application/json" };
15
+ Object.keys(authHeader).forEach(function (k) {
16
+ headers[k] = authHeader[k];
17
17
  });
18
- req.on('error', reject);
18
+ var req = https.request(
19
+ { hostname: BASE_HOST, path: urlPath, method: method, headers: headers },
20
+ function (res) {
21
+ var data = "";
22
+ res.on("data", function (c) {
23
+ data += c;
24
+ });
25
+ res.on("end", function () {
26
+ try {
27
+ resolve({ status: res.statusCode, data: JSON.parse(data) });
28
+ } catch (e) {
29
+ resolve({ status: res.statusCode, data: data });
30
+ }
31
+ });
32
+ }
33
+ );
34
+ req.on("error", reject);
19
35
  if (body) req.write(JSON.stringify(body));
20
36
  req.end();
21
37
  });
22
38
  }
23
39
 
24
- async function sendMessage(message, options) {
40
+ function sendMessage(message, options) {
25
41
  options = options || {};
26
- const body = { message, model: options.model || 'auto', stream: false };
27
- return request('POST', '/api/king/chat', body);
42
+ var body = { message: message, model: options.model || "auto", stream: false };
43
+ return request("POST", "/api/king/chat", body);
28
44
  }
29
45
 
30
- async function sendMessageStream(message, options) {
46
+ function sendMessageStream(message, options) {
31
47
  options = options || {};
32
- return new Promise((resolve, reject) => {
33
- const body = JSON.stringify({ message, model: options.model || 'auto', stream: true });
34
- const authHeader = auth.getAuthHeader() || {};
35
- const headers = { 'Content-Type': 'application/json', ...authHeader };
36
- const req = https.request({ hostname: BASE_HOST, path: '/api/king/chat', method: 'POST', headers }, (res) => {
37
- let fullText = '';
38
- res.on('data', (chunk) => {
39
- const lines = chunk.toString().split('\n');
40
- for (const line of lines) {
41
- if (line.startsWith('data: ')) {
48
+ return new Promise(function (resolve, reject) {
49
+ var body = JSON.stringify({
50
+ message: message,
51
+ model: options.model || "auto",
52
+ stream: true,
53
+ });
54
+ var authHeader = auth.getAuthHeader() || {};
55
+ var headers = { "Content-Type": "application/json" };
56
+ Object.keys(authHeader).forEach(function (k) {
57
+ headers[k] = authHeader[k];
58
+ });
59
+ var req = https.request(
60
+ {
61
+ hostname: BASE_HOST,
62
+ path: "/api/king/chat",
63
+ method: "POST",
64
+ headers: headers,
65
+ },
66
+ function (res) {
67
+ var fullText = "";
68
+ var lastUsage = null;
69
+ var buffer = "";
70
+ res.on("data", function (chunk) {
71
+ buffer += chunk.toString();
72
+ var lines = buffer.split("\n");
73
+ // Keep last incomplete line in buffer
74
+ buffer = lines.pop() || "";
75
+ for (var i = 0; i < lines.length; i++) {
76
+ var line = lines[i].trim();
77
+ if (line.startsWith("data: ")) {
78
+ var payload = line.slice(6).trim();
79
+ if (payload === "[DONE]") continue;
80
+ try {
81
+ var parsed = JSON.parse(payload);
82
+ if (parsed.text) {
83
+ fullText += parsed.text;
84
+ if (options.onChunk) options.onChunk(parsed.text);
85
+ }
86
+ if (parsed.usage) {
87
+ lastUsage = parsed.usage;
88
+ if (options.onUsage) options.onUsage(parsed.usage);
89
+ }
90
+ } catch (e) {
91
+ // ignore parse errors on partial lines
92
+ }
93
+ }
94
+ }
95
+ });
96
+ res.on("end", function () {
97
+ // Process remaining buffer
98
+ if (buffer.trim().startsWith("data: ")) {
42
99
  try {
43
- const parsed = JSON.parse(line.slice(6));
100
+ var parsed = JSON.parse(buffer.trim().slice(6));
44
101
  if (parsed.text) {
45
102
  fullText += parsed.text;
46
103
  if (options.onChunk) options.onChunk(parsed.text);
47
104
  }
48
- if (parsed.usage && options.onUsage) options.onUsage(parsed.usage);
49
- } catch {}
105
+ if (parsed.usage) lastUsage = parsed.usage;
106
+ } catch (e) {}
50
107
  }
51
- }
52
- });
53
- res.on('end', () => resolve({ text: fullText }));
54
- });
55
- req.on('error', reject);
108
+ resolve({ text: fullText, usage: lastUsage });
109
+ });
110
+ res.on("error", reject);
111
+ }
112
+ );
113
+ req.on("error", reject);
56
114
  req.write(body);
57
115
  req.end();
58
116
  });
59
117
  }
60
118
 
61
- async function getHealth() {
62
- return request('GET', '/api/monitoring/health');
119
+ function getHealth() {
120
+ return request("GET", "/api/monitoring/health");
63
121
  }
64
122
 
65
- module.exports = { sendMessage, sendMessageStream, getHealth };
123
+ module.exports = {
124
+ sendMessage: sendMessage,
125
+ sendMessageStream: sendMessageStream,
126
+ getHealth: getHealth,
127
+ };
package/lib/ui.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * BLUN King CLI - Rich Terminal UI Module
2
+ * BLUN King CLI v7.0.0 - Rich Terminal UI Module
3
3
  * Claude Code-style terminal experience
4
4
  * CommonJS - chalk@4, ora@5, boxen@5
5
5
  */
@@ -27,6 +27,14 @@ var colors = {
27
27
  code: chalk.bgGray.white,
28
28
  };
29
29
 
30
+ // Permission modes
31
+ var PERMISSION_MODES = ["safe", "normal", "god"];
32
+ var permissionLabels = {
33
+ safe: chalk.green("safe"),
34
+ normal: chalk.yellow("normal"),
35
+ god: chalk.red("god mode"),
36
+ };
37
+
30
38
  function renderBanner() {
31
39
  var art;
32
40
  try {
@@ -51,16 +59,22 @@ function getInputBoxWidth() {
51
59
  return Math.min((process.stdout.columns || 80) - 2, 76);
52
60
  }
53
61
 
54
- function renderInputBox(username, model) {
62
+ function renderInputBox(username, model, permMode) {
55
63
  var w = getInputBoxWidth();
56
64
  var u = username || "user";
57
65
  var m = model || "auto";
66
+ var pm = permMode || "normal";
58
67
  var hints = "/help \u2502 /settings \u2502 /model \u2502 /exit";
59
68
  var labelText = " " + u + " [" + m + "] ";
60
69
  var hintsText = " " + hints + " ";
61
70
  var topFill = w - labelText.length - hintsText.length;
62
71
  if (topFill < 2) topFill = 2;
63
- var topLine = chalk.dim("\u256d") + chalk.cyan(labelText) + chalk.dim("\u2500".repeat(topFill)) + chalk.dim(hintsText) + chalk.dim("\u256e");
72
+ var topLine =
73
+ chalk.dim("\u256d") +
74
+ chalk.cyan(labelText) +
75
+ chalk.dim("\u2500".repeat(topFill)) +
76
+ chalk.dim(hintsText) +
77
+ chalk.dim("\u256e");
64
78
  console.log(topLine);
65
79
  }
66
80
 
@@ -69,16 +83,27 @@ function renderInputBoxClose() {
69
83
  console.log(chalk.dim("\u2570" + "\u2500".repeat(w) + "\u256f"));
70
84
  }
71
85
 
72
- function renderPrompt(username, model) {
73
- // Called by readline as the prompt string
74
- // Show left border + cursor arrow
86
+ function renderPrompt() {
75
87
  return chalk.dim("\u2502") + " " + chalk.green.bold("\u276f") + " ";
76
88
  }
77
89
 
90
+ function renderPermissionLine(permMode) {
91
+ var pm = permMode || "normal";
92
+ var label = permissionLabels[pm] || permissionLabels.normal;
93
+ console.log(
94
+ chalk.dim(" bypass permissions ") +
95
+ label +
96
+ chalk.dim(" (shift+tab to cycle)")
97
+ );
98
+ }
99
+
78
100
  function renderWelcomeInfo() {
79
101
  var w = getInputBoxWidth();
80
102
  console.log(chalk.dim("\u2502"));
81
- console.log(chalk.dim("\u2502") + chalk.dim(" Tip: Type a message and press Enter. Use /help for all commands."));
103
+ console.log(
104
+ chalk.dim("\u2502") +
105
+ chalk.dim(" Tip: Type a message and press Enter. Use /help for all commands.")
106
+ );
82
107
  console.log(chalk.dim("\u2570" + "\u2500".repeat(w) + "\u256f"));
83
108
  }
84
109
 
@@ -89,7 +114,6 @@ function renderResponse(text, type) {
89
114
  var rendered = renderMarkdown(text);
90
115
 
91
116
  if (type === "agent") {
92
- // Agent responses in a box
93
117
  console.log(
94
118
  boxen(rendered, {
95
119
  title: chalk.green.bold(" \u2728 BLUN "),
@@ -111,6 +135,9 @@ function renderResponse(text, type) {
111
135
  borderColor: "red",
112
136
  })
113
137
  );
138
+ } else if (type === "system") {
139
+ console.log(chalk.yellow.bold(" [SYS] ") + chalk.yellow(rendered));
140
+ console.log();
114
141
  } else {
115
142
  var prefix = colorFn.bold(" [" + label + "] ");
116
143
  var lines = rendered.split("\n");
@@ -125,17 +152,79 @@ function renderResponse(text, type) {
125
152
  }
126
153
  }
127
154
 
155
+ function renderStreamStart() {
156
+ // Print box top for streaming response
157
+ var w = getInputBoxWidth();
158
+ console.log(
159
+ chalk.dim(" ") +
160
+ chalk.green("\u256d") +
161
+ chalk.green.bold(" \u2728 BLUN ") +
162
+ chalk.green("\u2500".repeat(Math.max(2, w - 12))) +
163
+ chalk.green("\u256e")
164
+ );
165
+ process.stdout.write(chalk.green(" \u2502 "));
166
+ }
167
+
168
+ function renderStreamChunk(text) {
169
+ process.stdout.write(text);
170
+ }
171
+
172
+ function renderStreamEnd() {
173
+ var w = getInputBoxWidth();
174
+ console.log();
175
+ console.log(
176
+ chalk.dim(" ") +
177
+ chalk.green("\u2570") +
178
+ chalk.green("\u2500".repeat(w - 2)) +
179
+ chalk.green("\u256f")
180
+ );
181
+ }
182
+
128
183
  function renderMarkdown(text) {
129
184
  var out = text;
130
- out = out.replace(/^### (.+)$/gm, function (_, h) { return chalk.bold.underline(h); });
131
- out = out.replace(/^## (.+)$/gm, function (_, h) { return chalk.bold.yellow(h); });
132
- out = out.replace(/^# (.+)$/gm, function (_, h) { return chalk.bold.magenta.underline(h); });
133
- out = out.replace(/\*\*\*(.+?)\*\*\*/g, function (_, t) { return chalk.bold.italic(t); });
134
- out = out.replace(/\*\*(.+?)\*\*/g, function (_, t) { return chalk.bold(t); });
135
- out = out.replace(/\*(.+?)\*/g, function (_, t) { return chalk.italic(t); });
136
- out = out.replace(/`([^`]+)`/g, function (_, c) { return chalk.bgGray.white(" " + c + " "); });
137
- out = out.replace(/^(\s*)[-*] (.+)$/gm, function (_, sp, t) { return sp + chalk.green("\u25cf") + " " + t; });
138
- out = out.replace(/^(\s*)\d+\. (.+)$/gm, function (_, sp, t) { return sp + chalk.yellow("\u25b8") + " " + t; });
185
+ // Code blocks
186
+ out = out.replace(/```(\w*)\n([\s\S]*?)```/g, function (_, lang, code) {
187
+ var header = lang ? chalk.dim.italic(" " + lang + " ") : "";
188
+ var lines = code.split("\n").map(function (l) {
189
+ return chalk.dim(" \u2502 ") + chalk.white(l);
190
+ });
191
+ return (
192
+ chalk.dim(" \u250c\u2500\u2500") +
193
+ header +
194
+ chalk.dim("\u2500".repeat(Math.max(1, 48 - (lang || "").length))) +
195
+ "\n" +
196
+ lines.join("\n") +
197
+ "\n" +
198
+ chalk.dim(" \u2514" + "\u2500".repeat(52))
199
+ );
200
+ });
201
+ out = out.replace(/^### (.+)$/gm, function (_, h) {
202
+ return chalk.bold.underline(h);
203
+ });
204
+ out = out.replace(/^## (.+)$/gm, function (_, h) {
205
+ return chalk.bold.yellow(h);
206
+ });
207
+ out = out.replace(/^# (.+)$/gm, function (_, h) {
208
+ return chalk.bold.magenta.underline(h);
209
+ });
210
+ out = out.replace(/\*\*\*(.+?)\*\*\*/g, function (_, t) {
211
+ return chalk.bold.italic(t);
212
+ });
213
+ out = out.replace(/\*\*(.+?)\*\*/g, function (_, t) {
214
+ return chalk.bold(t);
215
+ });
216
+ out = out.replace(/\*(.+?)\*/g, function (_, t) {
217
+ return chalk.italic(t);
218
+ });
219
+ out = out.replace(/`([^`]+)`/g, function (_, c) {
220
+ return chalk.bgGray.white(" " + c + " ");
221
+ });
222
+ out = out.replace(/^(\s*)[-*] (.+)$/gm, function (_, sp, t) {
223
+ return sp + chalk.green("\u25cf") + " " + t;
224
+ });
225
+ out = out.replace(/^(\s*)\d+\. (.+)$/gm, function (_, sp, t) {
226
+ return sp + chalk.yellow("\u25b8") + " " + t;
227
+ });
139
228
  return out;
140
229
  }
141
230
 
@@ -161,16 +250,20 @@ function stopSpinner(success, message) {
161
250
 
162
251
  function renderTable(headers, rows) {
163
252
  var table = new Table({
164
- head: headers.map(function (h) { return chalk.cyan.bold(h); }),
253
+ head: headers.map(function (h) {
254
+ return chalk.cyan.bold(h);
255
+ }),
165
256
  chars: {
166
- "top": "\u2500", "top-mid": "\u252c", "top-left": "\u250c", "top-right": "\u2510",
167
- "bottom": "\u2500", "bottom-mid": "\u2534", "bottom-left": "\u2514", "bottom-right": "\u2518",
168
- "left": "\u2502", "left-mid": "\u251c", "mid": "\u2500", "mid-mid": "\u253c",
169
- "right": "\u2502", "right-mid": "\u2524", "middle": "\u2502",
257
+ top: "\u2500", "top-mid": "\u252c", "top-left": "\u250c", "top-right": "\u2510",
258
+ bottom: "\u2500", "bottom-mid": "\u2534", "bottom-left": "\u2514", "bottom-right": "\u2518",
259
+ left: "\u2502", "left-mid": "\u251c", mid: "\u2500", "mid-mid": "\u253c",
260
+ right: "\u2502", "right-mid": "\u2524", middle: "\u2502",
170
261
  },
171
262
  style: { "padding-left": 1, "padding-right": 1 },
172
263
  });
173
- rows.forEach(function (r) { table.push(r); });
264
+ rows.forEach(function (r) {
265
+ table.push(r);
266
+ });
174
267
  console.log(table.toString());
175
268
  console.log();
176
269
  }
@@ -196,13 +289,27 @@ function renderCodeBlock(code, language) {
196
289
  console.log(chalk.dim(" \u250c\u2500\u2500") + lang + chalk.dim("\u2500".repeat(lineLen)));
197
290
  code.split("\n").forEach(function (line) {
198
291
  var highlighted = line;
199
- highlighted = highlighted.replace(/"[^"]*"/g, function (m) { return chalk.yellow(m); });
200
- highlighted = highlighted.replace(/'[^']*'/g, function (m) { return chalk.yellow(m); });
201
- var kws = ["const","let","var","function","return","if","else","for","while","class","import","export","from","require","async","await","try","catch","throw","new"];
202
- var kwRe = new RegExp("\b(" + kws.join("|") + ")\b", "g");
203
- highlighted = highlighted.replace(kwRe, function (m) { return chalk.magenta(m); });
204
- highlighted = highlighted.replace(/\b(\d+\.?\d*)\b/g, function (m) { return chalk.cyan(m); });
205
- highlighted = highlighted.replace(/(\/\/.*)$/g, function (m) { return chalk.dim(m); });
292
+ highlighted = highlighted.replace(/"[^"]*"/g, function (m) {
293
+ return chalk.yellow(m);
294
+ });
295
+ highlighted = highlighted.replace(/'[^']*'/g, function (m) {
296
+ return chalk.yellow(m);
297
+ });
298
+ var kws = [
299
+ "const", "let", "var", "function", "return", "if", "else", "for",
300
+ "while", "class", "import", "export", "from", "require", "async",
301
+ "await", "try", "catch", "throw", "new",
302
+ ];
303
+ var kwRe = new RegExp("\\b(" + kws.join("|") + ")\\b", "g");
304
+ highlighted = highlighted.replace(kwRe, function (m) {
305
+ return chalk.magenta(m);
306
+ });
307
+ highlighted = highlighted.replace(/\b(\d+\.?\d*)\b/g, function (m) {
308
+ return chalk.cyan(m);
309
+ });
310
+ highlighted = highlighted.replace(/(\/\/.*)$/g, function (m) {
311
+ return chalk.dim(m);
312
+ });
206
313
  console.log(chalk.dim(" \u2502 ") + highlighted);
207
314
  });
208
315
  console.log(chalk.dim(" \u2514" + "\u2500".repeat(54)));
@@ -213,11 +320,13 @@ function renderMiniStatus(model, tokens) {
213
320
  var elapsed = Math.floor((Date.now() - startTime) / 1000);
214
321
  var mins = Math.floor(elapsed / 60);
215
322
  var secs = elapsed % 60;
323
+ var costEst = totalCost > 0 ? "$" + totalCost.toFixed(4) : "~$" + (totalTokens * 0.000003).toFixed(4);
216
324
  var parts = [];
217
- parts.push(chalk.bgCyan.black(" " + (model || "auto") + " "));
325
+ parts.push(chalk.bgCyan.black(" " + (model || "chat") + " "));
218
326
  if (tokens) parts.push(chalk.dim("Tokens: " + tokens.toLocaleString()));
219
327
  parts.push(chalk.dim("Total: " + totalTokens.toLocaleString()));
220
- parts.push(chalk.dim(mins + "m " + secs + "s"));
328
+ parts.push(chalk.dim(mins + "m " + (secs < 10 ? "0" : "") + secs + "s"));
329
+ parts.push(chalk.dim(costEst));
221
330
  console.log(" " + parts.join(chalk.dim(" \u2502 ")));
222
331
  console.log();
223
332
  }
@@ -252,13 +361,15 @@ function renderProgress(current, total, label) {
252
361
  var bar = chalk.green("\u2588".repeat(filled)) + chalk.dim("\u2591".repeat(empty));
253
362
  var pctStr = chalk.bold(Math.round(pct * 100) + "%");
254
363
  var lbl = label ? chalk.dim(" " + label) : "";
255
- process.stdout.write("\r " + bar + " " + pctStr + lbl + " (" + current + "/" + total + ")");
364
+ process.stdout.write(
365
+ "\r " + bar + " " + pctStr + lbl + " (" + current + "/" + total + ")"
366
+ );
256
367
  if (current >= total) console.log();
257
368
  }
258
369
 
259
370
  function addTokens(count, costPerToken) {
260
371
  totalTokens += count;
261
- totalCost += count * (costPerToken || 0);
372
+ totalCost += count * (costPerToken || 0.000003);
262
373
  }
263
374
 
264
375
  function getStats() {
@@ -271,8 +382,12 @@ module.exports = {
271
382
  renderInputBox: renderInputBox,
272
383
  renderInputBoxClose: renderInputBoxClose,
273
384
  renderWelcomeInfo: renderWelcomeInfo,
385
+ renderPermissionLine: renderPermissionLine,
274
386
  renderMiniStatus: renderMiniStatus,
275
387
  renderResponse: renderResponse,
388
+ renderStreamStart: renderStreamStart,
389
+ renderStreamChunk: renderStreamChunk,
390
+ renderStreamEnd: renderStreamEnd,
276
391
  renderSpinner: renderSpinner,
277
392
  stopSpinner: stopSpinner,
278
393
  renderTable: renderTable,
@@ -284,4 +399,5 @@ module.exports = {
284
399
  addTokens: addTokens,
285
400
  getStats: getStats,
286
401
  colors: colors,
402
+ PERMISSION_MODES: PERMISSION_MODES,
287
403
  };
package/lib/workspace.js CHANGED
@@ -1,22 +1,26 @@
1
- const inquirer = require("inquirer");
2
- const fs = require("fs");
3
- const path = require("path");
4
- const os = require("os");
5
- const readline = require("readline");
6
- const chalk = require("chalk");
1
+ /**
2
+ * BLUN King CLI v7.0.0 - Workspace Trust Module
3
+ * CommonJS - inquirer@8
4
+ */
7
5
 
8
- const TRUST_FILE = path.join(os.homedir(), ".blun", "trusted-folders.json");
6
+ var inquirer = require("inquirer");
7
+ var fs = require("fs");
8
+ var path = require("path");
9
+ var os = require("os");
10
+ var chalk = require("chalk");
11
+
12
+ var TRUST_FILE = path.join(os.homedir(), ".blun", "trusted-folders.json");
9
13
 
10
14
  function loadTrusted() {
11
15
  try {
12
16
  return JSON.parse(fs.readFileSync(TRUST_FILE, "utf8"));
13
- } catch {
17
+ } catch (e) {
14
18
  return [];
15
19
  }
16
20
  }
17
21
 
18
22
  function saveTrusted(folders) {
19
- const dir = path.dirname(TRUST_FILE);
23
+ var dir = path.dirname(TRUST_FILE);
20
24
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
21
25
  fs.writeFileSync(TRUST_FILE, JSON.stringify(folders, null, 2));
22
26
  }
@@ -26,8 +30,8 @@ function isTrusted(folder) {
26
30
  }
27
31
 
28
32
  function trustFolder(folder) {
29
- const abs = path.resolve(folder);
30
- const trusted = loadTrusted();
33
+ var abs = path.resolve(folder);
34
+ var trusted = loadTrusted();
31
35
  if (!trusted.includes(abs)) {
32
36
  trusted.push(abs);
33
37
  saveTrusted(trusted);
@@ -35,46 +39,61 @@ function trustFolder(folder) {
35
39
  return abs;
36
40
  }
37
41
 
38
- function prompt(question) {
39
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
40
- return new Promise((resolve) => rl.question(question, (a) => { rl.close(); resolve(a.trim()); }));
41
- }
42
-
43
- async function selectFolder(initialFolder) {
44
- const chalk = require("chalk");
45
- const fs = require("fs");
46
- const folder = initialFolder || process.cwd();
47
-
48
- console.log(chalk.cyan(" Workspace: ") + chalk.white(folder));
42
+ function selectFolder(initialFolder) {
43
+ var folder = initialFolder || process.cwd();
44
+ var alreadyTrusted = isTrusted(folder);
49
45
 
50
- const alreadyTrusted = isTrusted(folder);
51
- const { trust } = await inquirer.prompt([{
52
- type: "list",
53
- name: "trust",
54
- message: chalk.yellow("Do you trust the files in this folder?"),
55
- choices: [
56
- { name: chalk.green("Yes, trust this folder") + (alreadyTrusted ? chalk.dim(" (previously trusted)") : ""), value: "yes" },
57
- { name: "Choose a different folder", value: "choose" },
58
- { name: "No, exit", value: "no" }
59
- ]
60
- }]);
46
+ console.log();
47
+ console.log(chalk.bold.white(" Do you trust the files in this folder?"));
48
+ console.log(chalk.dim(" " + folder));
49
+ console.log();
61
50
 
62
- if (trust === "no") { process.exit(0); }
63
- if (trust === "choose") {
64
- const { newFolder } = await inquirer.prompt([{ type: "input", name: "newFolder", message: "Folder path:" }]);
65
- const resolved = require("path").resolve(newFolder);
66
- if (!fs.existsSync(resolved)) { console.log(chalk.red(" Folder not found.")); process.exit(1); }
67
- return selectFolder(resolved);
68
- }
69
- trustFolder(folder);
70
- console.log(chalk.green(" \u2713 Folder trusted. Starting BLUN King...\n"));
71
- return folder;
51
+ return inquirer
52
+ .prompt([
53
+ {
54
+ type: "list",
55
+ name: "trust",
56
+ message: chalk.yellow("Trust decision"),
57
+ choices: [
58
+ {
59
+ name:
60
+ chalk.green("Yes, trust this folder") +
61
+ (alreadyTrusted ? chalk.dim(" (previously trusted)") : ""),
62
+ value: "yes",
63
+ },
64
+ { name: "Choose a different folder", value: "choose" },
65
+ { name: chalk.red("No, exit"), value: "no" },
66
+ ],
67
+ },
68
+ ])
69
+ .then(function (res) {
70
+ if (res.trust === "no") {
71
+ process.exit(0);
72
+ }
73
+ if (res.trust === "choose") {
74
+ return inquirer
75
+ .prompt([
76
+ { type: "input", name: "newFolder", message: "Folder path:" },
77
+ ])
78
+ .then(function (res2) {
79
+ var resolved = path.resolve(res2.newFolder);
80
+ if (!fs.existsSync(resolved)) {
81
+ console.log(chalk.red(" Folder not found."));
82
+ process.exit(1);
83
+ }
84
+ return selectFolder(resolved);
85
+ });
86
+ }
87
+ trustFolder(folder);
88
+ console.log(chalk.green(" \u2713 Folder trusted.\n"));
89
+ return folder;
90
+ });
72
91
  }
73
92
 
74
93
  function loadProjectConfig(folder) {
75
- const mdPath = path.join(folder, "BLUN.md");
94
+ var mdPath = path.join(folder, "BLUN.md");
76
95
  if (fs.existsSync(mdPath)) {
77
- const content = fs.readFileSync(mdPath, "utf8");
96
+ var content = fs.readFileSync(mdPath, "utf8");
78
97
  console.log(chalk.green(" Found project config: BLUN.md"));
79
98
  return content;
80
99
  }
@@ -82,17 +101,26 @@ function loadProjectConfig(folder) {
82
101
  }
83
102
 
84
103
  function initProject(folder) {
85
- const dir = path.resolve(folder);
86
- const blunDir = path.join(dir, ".blun");
104
+ var dir = path.resolve(folder);
105
+ var blunDir = path.join(dir, ".blun");
87
106
  if (!fs.existsSync(blunDir)) fs.mkdirSync(blunDir, { recursive: true });
88
107
 
89
- const mdPath = path.join(dir, "BLUN.md");
108
+ var mdPath = path.join(dir, "BLUN.md");
90
109
  if (!fs.existsSync(mdPath)) {
91
- fs.writeFileSync(mdPath, `# Project Name\n\nYour project name here.\n\n## Description\n\nBrief description of the project.\n\n## Rules\n\n- Add project-specific rules here\n\n## Context\n\n- Add relevant context for the AI assistant\n`);
110
+ fs.writeFileSync(
111
+ mdPath,
112
+ "# Project Name\n\nYour project name here.\n\n## Description\n\nBrief description of the project.\n\n## Rules\n\n- Add project-specific rules here\n\n## Context\n\n- Add relevant context for the AI assistant\n"
113
+ );
92
114
  }
93
- console.log(chalk.green(" Initialized BLUN project in " + dir));
115
+ console.log(chalk.green(" \u2713 Initialized BLUN project in " + dir));
94
116
  console.log(chalk.dim(" Created: .blun/ directory"));
95
117
  console.log(chalk.dim(" Created: BLUN.md template"));
96
118
  }
97
119
 
98
- module.exports = { trustFolder, isTrusted, selectFolder, initProject, loadProjectConfig };
120
+ module.exports = {
121
+ trustFolder: trustFolder,
122
+ isTrusted: isTrusted,
123
+ selectFolder: selectFolder,
124
+ initProject: initProject,
125
+ loadProjectConfig: loadProjectConfig,
126
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "6.4.2",
3
+ "version": "7.0.0",
4
4
  "description": "BLUN AI Assistant - Command Line Interface",
5
5
  "bin": {
6
6
  "blun": "./bin/blun.js"