blun-king-cli 1.2.0 → 1.3.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 +271 -1
  2. package/package.json +1 -1
package/bin/blun.js CHANGED
@@ -121,6 +121,19 @@ function printHeader() {
121
121
  console.log("");
122
122
  }
123
123
 
124
+ // ── Update Checker ──
125
+ function checkForUpdates() {
126
+ try {
127
+ var currentVersion = "1.3.0";
128
+ var latest = execSync("npm view blun-king-cli version 2>/dev/null", { encoding: "utf8", timeout: 5000 }).trim();
129
+ if (latest && latest !== currentVersion) {
130
+ console.log(C.yellow + C.bold + " " + BOX.arrow + " Update available: " + currentVersion + " → " + latest + C.reset);
131
+ console.log(C.yellow + " npm update -g blun-king-cli" + C.reset);
132
+ console.log("");
133
+ }
134
+ } catch(e) { /* silent */ }
135
+ }
136
+
124
137
  function printAnswer(answer, meta) {
125
138
  console.log("");
126
139
  console.log(C.green + C.bold + " " + BOX.bot + " BLUN King" + C.reset + (meta ? C.gray + " " + BOX.dot + " " + meta + C.reset : ""));
@@ -199,6 +212,16 @@ async function handleCommand(input) {
199
212
  console.log(" /score <text> Score a response");
200
213
  console.log(" /eval Run eval suite");
201
214
  console.log("");
215
+ console.log(C.yellow + " PLUGINS (MCP)" + C.reset);
216
+ console.log(" /plugin list List installed plugins");
217
+ console.log(" /plugin add <cmd> Add MCP server (npm pkg or local path)");
218
+ console.log(" /plugin remove <n>Remove a plugin");
219
+ console.log(" /plugin run <n> Start a plugin server");
220
+ console.log(" /plugin stop <n> Stop a plugin server");
221
+ console.log(" /permissions Show permission settings");
222
+ console.log(" /permissions allow-all Allow all tool calls");
223
+ console.log(" /permissions ask Ask before each tool call");
224
+ console.log("");
202
225
  console.log(C.yellow + " SETTINGS" + C.reset);
203
226
  console.log(" /settings Show all settings");
204
227
  console.log(" /set auth api Switch to API key auth");
@@ -333,6 +356,26 @@ async function handleCommand(input) {
333
356
  cmdInit();
334
357
  break;
335
358
 
359
+ case "/plugin":
360
+ cmdPlugin(args);
361
+ break;
362
+
363
+ case "/permissions":
364
+ cmdPermissions(args);
365
+ break;
366
+
367
+ case "/agent":
368
+ await cmdAgent(args);
369
+ break;
370
+
371
+ case "/screenshot":
372
+ await cmdScreenshot(args);
373
+ break;
374
+
375
+ case "/render":
376
+ await cmdRender(args);
377
+ break;
378
+
336
379
  case "/exit":
337
380
  case "/quit":
338
381
  case "/q":
@@ -1072,6 +1115,232 @@ function cmdInit(args) {
1072
1115
  }
1073
1116
  }
1074
1117
 
1118
+ // ── Plugins (MCP-style) ──
1119
+ const PLUGINS_FILE = path.join(CONFIG_DIR, "plugins.json");
1120
+ const PERMISSIONS_FILE = path.join(CONFIG_DIR, "permissions.json");
1121
+
1122
+ function loadPlugins() {
1123
+ if (fs.existsSync(PLUGINS_FILE)) {
1124
+ try { return JSON.parse(fs.readFileSync(PLUGINS_FILE, "utf8")); } catch(e) {}
1125
+ }
1126
+ return {};
1127
+ }
1128
+
1129
+ function savePlugins(p) { fs.writeFileSync(PLUGINS_FILE, JSON.stringify(p, null, 2)); }
1130
+
1131
+ function loadPermissions() {
1132
+ if (fs.existsSync(PERMISSIONS_FILE)) {
1133
+ try { return JSON.parse(fs.readFileSync(PERMISSIONS_FILE, "utf8")); } catch(e) {}
1134
+ }
1135
+ return { mode: "ask", allowed: [], denied: [] };
1136
+ }
1137
+
1138
+ function savePermissions(p) { fs.writeFileSync(PERMISSIONS_FILE, JSON.stringify(p, null, 2)); }
1139
+
1140
+ // Built-in plugin templates
1141
+ var PLUGIN_TEMPLATES = {
1142
+ telegram: {
1143
+ name: "telegram",
1144
+ description: "Telegram Bot Bridge — send/receive messages",
1145
+ type: "builtin",
1146
+ config: { bot_token: "", chat_id: "" },
1147
+ commands: ["/tg send <msg>", "/tg status"],
1148
+ setup: ["bot_token", "chat_id"]
1149
+ },
1150
+ github: {
1151
+ name: "github",
1152
+ description: "GitHub Integration — repos, issues, PRs",
1153
+ type: "builtin",
1154
+ config: { token: "", default_repo: "" },
1155
+ commands: ["/gh repos", "/gh issues", "/gh pr"],
1156
+ setup: ["token"]
1157
+ },
1158
+ browser: {
1159
+ name: "browser",
1160
+ description: "Playwright Browser — screenshots, rendering, scraping",
1161
+ type: "builtin",
1162
+ config: {},
1163
+ commands: ["/screenshot <url>", "/render <url>"],
1164
+ setup: []
1165
+ },
1166
+ slack: {
1167
+ name: "slack",
1168
+ description: "Slack Webhook — send messages to channels",
1169
+ type: "builtin",
1170
+ config: { webhook_url: "" },
1171
+ commands: ["/slack send <msg>"],
1172
+ setup: ["webhook_url"]
1173
+ },
1174
+ docker: {
1175
+ name: "docker",
1176
+ description: "Docker Management — containers, images, logs",
1177
+ type: "builtin",
1178
+ config: { host: "localhost" },
1179
+ commands: ["/docker ps", "/docker logs <container>"],
1180
+ setup: []
1181
+ }
1182
+ };
1183
+
1184
+ function cmdPlugin(args) {
1185
+ var plugins = loadPlugins();
1186
+ var parts = (args || "").split(/\s+/);
1187
+ var action = parts[0] || "list";
1188
+
1189
+ if (action === "list") {
1190
+ console.log("");
1191
+ console.log(C.bold + " " + BOX.bot + " Installed Plugins:" + C.reset);
1192
+ console.log(C.brightBlue + " " + BOX.h.repeat(40) + C.reset);
1193
+ var names = Object.keys(plugins);
1194
+ if (names.length === 0) {
1195
+ console.log(C.gray + " (none installed)" + C.reset);
1196
+ } else {
1197
+ names.forEach(function(name) {
1198
+ var p = plugins[name];
1199
+ var status = p.running ? C.green + BOX.dot + " running" : C.gray + BOX.dot + " stopped";
1200
+ console.log(" " + C.brightCyan + name + C.reset + " — " + (p.description || "") + " " + status + C.reset);
1201
+ });
1202
+ }
1203
+ console.log("");
1204
+ console.log(C.gray + " Available: " + Object.keys(PLUGIN_TEMPLATES).join(", ") + C.reset);
1205
+ console.log(C.gray + " Or add custom: /plugin add <npm-package> or /plugin add <path>" + C.reset);
1206
+ console.log("");
1207
+
1208
+ } else if (action === "add" && parts[1]) {
1209
+ var pluginName = parts[1];
1210
+ if (PLUGIN_TEMPLATES[pluginName]) {
1211
+ // Built-in plugin
1212
+ var tmpl = PLUGIN_TEMPLATES[pluginName];
1213
+ plugins[pluginName] = {
1214
+ name: tmpl.name,
1215
+ description: tmpl.description,
1216
+ type: tmpl.type,
1217
+ config: Object.assign({}, tmpl.config),
1218
+ commands: tmpl.commands,
1219
+ installed: new Date().toISOString(),
1220
+ running: false
1221
+ };
1222
+
1223
+ // If setup fields needed, prompt
1224
+ if (tmpl.setup && tmpl.setup.length > 0) {
1225
+ printInfo("Plugin '" + pluginName + "' needs configuration:");
1226
+ tmpl.setup.forEach(function(field) {
1227
+ printInfo(" Set with: /set plugin." + pluginName + "." + field + " <value>");
1228
+ });
1229
+ }
1230
+
1231
+ savePlugins(plugins);
1232
+ printSuccess("Plugin '" + pluginName + "' installed!");
1233
+ } else {
1234
+ // Custom: npm package or local path
1235
+ printInfo("Installing custom plugin: " + pluginName);
1236
+ try {
1237
+ execSync("npm install " + pluginName, { cwd: CONFIG_DIR, encoding: "utf8", stdio: "pipe" });
1238
+ plugins[pluginName] = {
1239
+ name: pluginName,
1240
+ description: "Custom MCP server",
1241
+ type: "npm",
1242
+ config: {},
1243
+ commands: [],
1244
+ installed: new Date().toISOString(),
1245
+ running: false
1246
+ };
1247
+ savePlugins(plugins);
1248
+ printSuccess("Plugin '" + pluginName + "' installed via npm!");
1249
+ } catch(e) {
1250
+ printError("Install failed: " + e.message.slice(0, 200));
1251
+ }
1252
+ }
1253
+
1254
+ } else if (action === "remove" && parts[1]) {
1255
+ delete plugins[parts[1]];
1256
+ savePlugins(plugins);
1257
+ printSuccess("Plugin '" + parts[1] + "' removed.");
1258
+
1259
+ } else if (action === "run" && parts[1]) {
1260
+ if (!plugins[parts[1]]) { printError("Plugin not found: " + parts[1]); return; }
1261
+ plugins[parts[1]].running = true;
1262
+ savePlugins(plugins);
1263
+ printSuccess("Plugin '" + parts[1] + "' started.");
1264
+
1265
+ } else if (action === "stop" && parts[1]) {
1266
+ if (!plugins[parts[1]]) { printError("Plugin not found: " + parts[1]); return; }
1267
+ plugins[parts[1]].running = false;
1268
+ savePlugins(plugins);
1269
+ printSuccess("Plugin '" + parts[1] + "' stopped.");
1270
+
1271
+ } else {
1272
+ printError("Usage: /plugin list|add|remove|run|stop <name>");
1273
+ }
1274
+ }
1275
+
1276
+ function cmdPermissions(args) {
1277
+ var perms = loadPermissions();
1278
+ if (!args) {
1279
+ console.log("");
1280
+ console.log(C.bold + " Permissions:" + C.reset);
1281
+ console.log(" Mode: " + C.brightCyan + perms.mode + C.reset);
1282
+ console.log(" Allowed: " + (perms.allowed.length > 0 ? perms.allowed.join(", ") : C.gray + "(none)" + C.reset));
1283
+ console.log(" Denied: " + (perms.denied.length > 0 ? perms.denied.join(", ") : C.gray + "(none)" + C.reset));
1284
+ console.log("");
1285
+ console.log(C.gray + " /permissions allow-all — Skip all permission prompts" + C.reset);
1286
+ console.log(C.gray + " /permissions ask — Ask before each tool call" + C.reset);
1287
+ console.log("");
1288
+ } else if (args === "allow-all") {
1289
+ perms.mode = "allow-all";
1290
+ savePermissions(perms);
1291
+ printSuccess("Permission mode: allow-all (no prompts)");
1292
+ } else if (args === "ask") {
1293
+ perms.mode = "ask";
1294
+ savePermissions(perms);
1295
+ printSuccess("Permission mode: ask (prompt before each tool call)");
1296
+ }
1297
+ }
1298
+
1299
+ // ── Agent Loop (CLI wrapper) ──
1300
+ async function cmdAgent(args) {
1301
+ if (!args) { printError("Usage: /agent <goal>"); return; }
1302
+ try {
1303
+ printUserMessage(args);
1304
+ process.stdout.write(C.dim + " " + BOX.bot + " working autonomously..." + C.reset);
1305
+ var resp = await apiCall("POST", "/agent", { goal: args, verbose: true });
1306
+ process.stdout.write("\r" + " ".repeat(50) + "\r");
1307
+ if (resp.status !== 200) { printError(resp.data.error || "Error"); return; }
1308
+ var d = resp.data;
1309
+ var meta = d.steps_executed + " steps" + (d.files.length > 0 ? " " + BOX.dot + " " + d.files.length + " files" : "");
1310
+ printAnswer(d.answer, meta);
1311
+ if (d.files.length > 0) {
1312
+ console.log(C.green + " Files:" + C.reset);
1313
+ d.files.forEach(function(f) { console.log(" " + C.brightCyan + f.name + C.reset + " → " + config.api.base_url + f.download); });
1314
+ console.log("");
1315
+ }
1316
+ } catch(e) { printError(e.message); }
1317
+ }
1318
+
1319
+ // ── Screenshot/Render (CLI wrapper) ──
1320
+ async function cmdScreenshot(args) {
1321
+ if (!args) { printError("Usage: /screenshot <url>"); return; }
1322
+ try {
1323
+ printInfo("Taking screenshot of " + args + "...");
1324
+ var resp = await apiCall("POST", "/screenshot", { url: args });
1325
+ if (resp.status !== 200) { printError(resp.data.error || "Error"); return; }
1326
+ printSuccess("Screenshot: " + resp.data.title);
1327
+ console.log(" Download: " + C.brightCyan + config.api.base_url + resp.data.screenshot + C.reset);
1328
+ console.log("");
1329
+ } catch(e) { printError(e.message); }
1330
+ }
1331
+
1332
+ async function cmdRender(args) {
1333
+ if (!args) { printError("Usage: /render <url>"); return; }
1334
+ try {
1335
+ printInfo("Rendering " + args + " with Playwright...");
1336
+ var resp = await apiCall("POST", "/render", { url: args });
1337
+ if (resp.status !== 200) { printError(resp.data.error || "Error"); return; }
1338
+ printSuccess("Rendered: " + resp.data.title + " (" + resp.data.html_length + " chars)");
1339
+ if (resp.data.screenshot) console.log(" Screenshot: " + C.brightCyan + resp.data.screenshot + C.reset);
1340
+ console.log("");
1341
+ } catch(e) { printError(e.message); }
1342
+ }
1343
+
1075
1344
  // ── Main Loop ──
1076
1345
  async function main() {
1077
1346
  // Handle CLI args
@@ -1111,6 +1380,7 @@ async function main() {
1111
1380
 
1112
1381
  // Interactive mode
1113
1382
  printHeader();
1383
+ checkForUpdates();
1114
1384
 
1115
1385
  // Health check
1116
1386
  try {
@@ -1127,7 +1397,7 @@ async function main() {
1127
1397
  "/generate", "/analyze", "/score", "/eval", "/settings", "/set",
1128
1398
  "/status", "/versions", "/health", "/watchdog", "/memory", "/files",
1129
1399
  "/sh", "/git", "/ssh", "/deploy", "/read", "/write", "/init",
1130
- "/screenshot", "/render", "/agent", "/exit"
1400
+ "/screenshot", "/render", "/agent", "/plugin", "/permissions", "/exit"
1131
1401
  ];
1132
1402
 
1133
1403
  var rl = readline.createInterface({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "BLUN King CLI — Premium KI Console",
5
5
  "bin": {
6
6
  "blun": "./bin/blun.js"