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.
- package/bin/blun.js +271 -1
- 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({
|