mioku 0.9.5 → 0.9.7
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/dist/cli/index.cjs +15 -43
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +11 -38
- package/dist/cli/index.js.map +1 -1
- package/dist/exec-BojymP61.cjs +217 -0
- package/dist/exec-BojymP61.cjs.map +1 -0
- package/dist/exec-BzODBZwA.js +153 -0
- package/dist/exec-BzODBZwA.js.map +1 -0
- package/dist/index.cjs +226 -70
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +67 -5
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +67 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +223 -81
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-CUT6urMc.cjs +0 -30
package/dist/index.cjs
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
const
|
|
2
|
-
const fs =
|
|
3
|
-
const path =
|
|
4
|
-
const url =
|
|
5
|
-
const fs_promises =
|
|
6
|
-
const
|
|
1
|
+
const require_exec = require('./exec-BojymP61.cjs');
|
|
2
|
+
const fs = require_exec.__toESM(require("fs"));
|
|
3
|
+
const path = require_exec.__toESM(require("path"));
|
|
4
|
+
const url = require_exec.__toESM(require("url"));
|
|
5
|
+
const fs_promises = require_exec.__toESM(require("fs/promises"));
|
|
6
|
+
const node_url = require_exec.__toESM(require("node:url"));
|
|
7
|
+
const mioki = require_exec.__toESM(require("mioki"));
|
|
7
8
|
|
|
8
9
|
//#region src/core/logger.ts
|
|
9
10
|
const fallbackLogger = {
|
|
@@ -43,7 +44,7 @@ async function resolveRealpath(p) {
|
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
46
|
function toImportPath(filePath) {
|
|
46
|
-
if (process.platform === "win32") return
|
|
47
|
+
if (process.platform === "win32") return (0, node_url.pathToFileURL)(filePath).href;
|
|
47
48
|
return filePath;
|
|
48
49
|
}
|
|
49
50
|
async function scanLocalDir(dir) {
|
|
@@ -177,6 +178,125 @@ function getOrCreate(key, factory) {
|
|
|
177
178
|
return s[key];
|
|
178
179
|
}
|
|
179
180
|
|
|
181
|
+
//#endregion
|
|
182
|
+
//#region src/core/plugin-manifest.ts
|
|
183
|
+
const PLUGIN_CONFIG_KEYS = new Set([
|
|
184
|
+
"services",
|
|
185
|
+
"help",
|
|
186
|
+
"accessHooks"
|
|
187
|
+
]);
|
|
188
|
+
const ACCESS_HOOK_KEYS = new Set([
|
|
189
|
+
"id",
|
|
190
|
+
"match",
|
|
191
|
+
"event",
|
|
192
|
+
"description"
|
|
193
|
+
]);
|
|
194
|
+
const HELP_COMMAND_KEYS = new Set([
|
|
195
|
+
"cmd",
|
|
196
|
+
"desc",
|
|
197
|
+
"usage",
|
|
198
|
+
"role"
|
|
199
|
+
]);
|
|
200
|
+
function warnUnknownFields(prefix, obj, allowed) {
|
|
201
|
+
for (const key of Object.keys(obj)) if (!allowed.has(key)) logger.warn(`[plugin-manifest] ${prefix} 含未知字段 "${key}"(将被忽略)`);
|
|
202
|
+
}
|
|
203
|
+
function isPlainObject(value) {
|
|
204
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
205
|
+
}
|
|
206
|
+
function validateHelp(value, pluginName) {
|
|
207
|
+
if (value === void 0) return void 0;
|
|
208
|
+
if (!isPlainObject(value)) {
|
|
209
|
+
logger.warn(`[plugin-manifest] ${pluginName}.help 必须是对象,已忽略`);
|
|
210
|
+
return void 0;
|
|
211
|
+
}
|
|
212
|
+
warnUnknownFields(`${pluginName}.help`, value, HELP_COMMAND_KEYS);
|
|
213
|
+
const title = String(value.title ?? "").trim();
|
|
214
|
+
const description = String(value.description ?? "").trim();
|
|
215
|
+
const rawCommands = value.commands;
|
|
216
|
+
if (!title) logger.warn(`[plugin-manifest] ${pluginName}.help.title 缺失或为空`);
|
|
217
|
+
if (!description) logger.warn(`[plugin-manifest] ${pluginName}.help.description 缺失或为空`);
|
|
218
|
+
if (!Array.isArray(rawCommands)) {
|
|
219
|
+
logger.warn(`[plugin-manifest] ${pluginName}.help.commands 必须是数组`);
|
|
220
|
+
return {
|
|
221
|
+
title,
|
|
222
|
+
description,
|
|
223
|
+
commands: []
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
const commands = [];
|
|
227
|
+
for (const cmd of rawCommands) {
|
|
228
|
+
if (!isPlainObject(cmd)) {
|
|
229
|
+
logger.warn(`[plugin-manifest] ${pluginName}.help.commands 项不是对象`);
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
warnUnknownFields(`${pluginName}.help.commands[]`, cmd, HELP_COMMAND_KEYS);
|
|
233
|
+
const cmdName = String(cmd.cmd ?? "").trim();
|
|
234
|
+
const desc = String(cmd.desc ?? "").trim();
|
|
235
|
+
if (!cmdName || !desc) {
|
|
236
|
+
logger.warn(`[plugin-manifest] ${pluginName}.help.commands 项缺少 cmd 或 desc`);
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
commands.push({
|
|
240
|
+
cmd: cmdName,
|
|
241
|
+
desc,
|
|
242
|
+
usage: typeof cmd.usage === "string" ? cmd.usage : void 0,
|
|
243
|
+
role: typeof cmd.role === "string" ? cmd.role : void 0
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
return {
|
|
247
|
+
title,
|
|
248
|
+
description,
|
|
249
|
+
commands
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
function validateAccessHooks(value, pluginName) {
|
|
253
|
+
if (value === void 0) return void 0;
|
|
254
|
+
if (!Array.isArray(value)) {
|
|
255
|
+
logger.warn(`[plugin-manifest] ${pluginName}.accessHooks 必须是数组`);
|
|
256
|
+
return void 0;
|
|
257
|
+
}
|
|
258
|
+
const hooks = [];
|
|
259
|
+
for (const hook of value) {
|
|
260
|
+
if (!isPlainObject(hook)) {
|
|
261
|
+
logger.warn(`[plugin-manifest] ${pluginName}.accessHooks 项不是对象`);
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
warnUnknownFields(`${pluginName}.accessHooks[]`, hook, ACCESS_HOOK_KEYS);
|
|
265
|
+
const id = String(hook.id ?? "").trim();
|
|
266
|
+
if (!id) {
|
|
267
|
+
logger.warn(`[plugin-manifest] ${pluginName}.accessHooks 项缺少 id,已忽略`);
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
hooks.push({
|
|
271
|
+
id,
|
|
272
|
+
match: typeof hook.match === "string" ? hook.match : void 0,
|
|
273
|
+
event: typeof hook.event === "string" ? hook.event : void 0,
|
|
274
|
+
description: typeof hook.description === "string" ? hook.description : void 0
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
return hooks;
|
|
278
|
+
}
|
|
279
|
+
function validatePluginPackageConfig(raw, pluginName) {
|
|
280
|
+
const config = {};
|
|
281
|
+
if (raw === void 0 || raw === null) return config;
|
|
282
|
+
if (!isPlainObject(raw)) {
|
|
283
|
+
logger.warn(`[plugin-manifest] ${pluginName} 的 mioku 字段必须是对象,已使用空配置`);
|
|
284
|
+
return config;
|
|
285
|
+
}
|
|
286
|
+
warnUnknownFields(`${pluginName}.mioku`, raw, PLUGIN_CONFIG_KEYS);
|
|
287
|
+
if (raw.services !== void 0) if (Array.isArray(raw.services)) {
|
|
288
|
+
const services = raw.services.filter((s) => typeof s === "string" && s.length > 0);
|
|
289
|
+
const dropped = raw.services.length - services.length;
|
|
290
|
+
if (dropped > 0) logger.warn(`[plugin-manifest] ${pluginName}.services 丢弃 ${dropped} 个非字符串项`);
|
|
291
|
+
config.services = services;
|
|
292
|
+
} else logger.warn(`[plugin-manifest] ${pluginName}.services 必须是字符串数组`);
|
|
293
|
+
const help = validateHelp(raw.help, pluginName);
|
|
294
|
+
if (help) config.help = help;
|
|
295
|
+
const hooks = validateAccessHooks(raw.accessHooks, pluginName);
|
|
296
|
+
if (hooks) config.accessHooks = hooks;
|
|
297
|
+
return config;
|
|
298
|
+
}
|
|
299
|
+
|
|
180
300
|
//#endregion
|
|
181
301
|
//#region src/core/plugin-manager.ts
|
|
182
302
|
const PLUGIN_PREFIX = "mioku-plugin-";
|
|
@@ -211,7 +331,7 @@ var PluginManager = class PluginManager {
|
|
|
211
331
|
} catch (error) {
|
|
212
332
|
logger.warn(`[plugin-manager] 读取 ${name} 的 package.json 失败: ${error}`);
|
|
213
333
|
}
|
|
214
|
-
const config = packageJson?.mioku
|
|
334
|
+
const config = validatePluginPackageConfig(packageJson?.mioku, name);
|
|
215
335
|
return {
|
|
216
336
|
name,
|
|
217
337
|
version: packageJson?.version ?? "0.0.0",
|
|
@@ -381,68 +501,49 @@ async function bootstrapMioku(deps) {
|
|
|
381
501
|
}
|
|
382
502
|
|
|
383
503
|
//#endregion
|
|
384
|
-
//#region src/core/
|
|
385
|
-
function
|
|
386
|
-
return
|
|
387
|
-
}
|
|
388
|
-
function
|
|
389
|
-
|
|
390
|
-
moduleExports?.default,
|
|
391
|
-
moduleExports?.skills,
|
|
392
|
-
moduleExports
|
|
393
|
-
];
|
|
394
|
-
for (const candidate of candidates) {
|
|
395
|
-
if (Array.isArray(candidate)) return candidate.filter(isAISkill);
|
|
396
|
-
if (isAISkill(candidate)) return [candidate];
|
|
397
|
-
}
|
|
398
|
-
return [];
|
|
399
|
-
}
|
|
400
|
-
async function resolveSkillsEntry(pluginPath) {
|
|
401
|
-
const tsPath = path.join(pluginPath, "skills.ts");
|
|
402
|
-
if (await pathExists(tsPath)) return tsPath;
|
|
403
|
-
const jsPath = path.join(pluginPath, "skills.js");
|
|
404
|
-
if (await pathExists(jsPath)) return jsPath;
|
|
405
|
-
return null;
|
|
504
|
+
//#region src/core/service.ts
|
|
505
|
+
function defineService(id) {
|
|
506
|
+
return { id };
|
|
507
|
+
}
|
|
508
|
+
function getService(ctx, ref) {
|
|
509
|
+
return ctx.services[ref.id];
|
|
406
510
|
}
|
|
511
|
+
function requireService(ctx, ref) {
|
|
512
|
+
const svc = ctx.services[ref.id];
|
|
513
|
+
if (svc === void 0) throw new Error(`[mioku] required service "${ref.id}" is not available`);
|
|
514
|
+
return svc;
|
|
515
|
+
}
|
|
516
|
+
function hasService(ctx, ref) {
|
|
517
|
+
return ctx.services[ref.id] !== void 0;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
//#endregion
|
|
521
|
+
//#region src/core/services.ts
|
|
522
|
+
const Services = {
|
|
523
|
+
AI: defineService("ai"),
|
|
524
|
+
Config: defineService("config"),
|
|
525
|
+
Screenshot: defineService("screenshot"),
|
|
526
|
+
Help: defineService("help")
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
//#endregion
|
|
530
|
+
//#region src/core/plugin-artifact-registry.ts
|
|
407
531
|
function hasPublicKeyword(keywords) {
|
|
408
532
|
return Array.isArray(keywords) && keywords.includes("mioku");
|
|
409
533
|
}
|
|
410
534
|
async function registerPluginArtifacts(ctx) {
|
|
411
535
|
const enabledPlugins = new Set(mioki.botConfig.plugins ?? []);
|
|
412
536
|
const pluginMetadata = plugin_manager_default.getAllMetadata().filter((metadata) => enabledPlugins.size > 0 ? enabledPlugins.has(metadata.name) : true);
|
|
413
|
-
const helpService = ctx.
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
let helpCount = 0;
|
|
417
|
-
for (const metadata of pluginMetadata) {
|
|
418
|
-
if (!metadata.config.help) continue;
|
|
419
|
-
if (!hasPublicKeyword(metadata.packageJson?.keywords)) continue;
|
|
420
|
-
helpService.registerHelp(metadata.name, metadata.config.help);
|
|
421
|
-
helpCount += 1;
|
|
422
|
-
}
|
|
423
|
-
logger.info(`[plugin-artifacts] Registered ${helpCount} help manifest(s)`);
|
|
424
|
-
}
|
|
425
|
-
if (!aiService) return;
|
|
426
|
-
let skillCount = 0;
|
|
537
|
+
const helpService = getService(ctx, Services.Help);
|
|
538
|
+
if (!helpService) return;
|
|
539
|
+
let helpCount = 0;
|
|
427
540
|
for (const metadata of pluginMetadata) {
|
|
428
|
-
|
|
429
|
-
if (!
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
const skills = extractSkills(moduleExports);
|
|
433
|
-
if (skills.length === 0) {
|
|
434
|
-
logger.warn(`[plugin-artifacts] Plugin ${metadata.name} has ${path.basename(skillsEntry)} but exported no valid skill`);
|
|
435
|
-
continue;
|
|
436
|
-
}
|
|
437
|
-
for (const skill of skills) {
|
|
438
|
-
aiService.registerSkill(skill);
|
|
439
|
-
skillCount += 1;
|
|
440
|
-
}
|
|
441
|
-
} catch (error) {
|
|
442
|
-
logger.error(`[plugin-artifacts] Failed to load skills for plugin ${metadata.name}: ${error}`);
|
|
443
|
-
}
|
|
541
|
+
if (!metadata.config.help) continue;
|
|
542
|
+
if (!hasPublicKeyword(metadata.packageJson?.keywords)) continue;
|
|
543
|
+
helpService.registerHelp(metadata.name, metadata.config.help);
|
|
544
|
+
helpCount += 1;
|
|
444
545
|
}
|
|
445
|
-
logger.info(`[plugin-artifacts] Registered ${
|
|
546
|
+
logger.info(`[plugin-artifacts] Registered ${helpCount} help manifest(s)`);
|
|
446
547
|
}
|
|
447
548
|
|
|
448
549
|
//#endregion
|
|
@@ -498,6 +599,11 @@ async function deleteServiceConfig(serviceName, configName) {
|
|
|
498
599
|
|
|
499
600
|
//#endregion
|
|
500
601
|
//#region src/types.ts
|
|
602
|
+
function normalizeSkillPermissionRole(role) {
|
|
603
|
+
const normalized = String(role ?? "").trim().toLowerCase();
|
|
604
|
+
if (normalized === "master" || normalized === "owner" || normalized === "admin" || normalized === "member") return normalized;
|
|
605
|
+
return "member";
|
|
606
|
+
}
|
|
501
607
|
const TOOL_RESULT_FOLLOWUP_KEY = "__miokuFollowup";
|
|
502
608
|
|
|
503
609
|
//#endregion
|
|
@@ -529,17 +635,36 @@ function ensureDataDir(pluginName) {
|
|
|
529
635
|
//#endregion
|
|
530
636
|
//#region src/core/plugin-runtime-state.ts
|
|
531
637
|
const store = getOrCreate("plugin-runtime-state", () => ({}));
|
|
532
|
-
function
|
|
533
|
-
|
|
534
|
-
|
|
638
|
+
function defineState(name, initial) {
|
|
639
|
+
return {
|
|
640
|
+
name,
|
|
641
|
+
get() {
|
|
642
|
+
const current = store[name];
|
|
643
|
+
return current === void 0 ? initial : current;
|
|
644
|
+
},
|
|
645
|
+
set(next) {
|
|
646
|
+
store[name] = next;
|
|
647
|
+
},
|
|
648
|
+
reset() {
|
|
649
|
+
delete store[name];
|
|
650
|
+
}
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
function hasPluginState(name) {
|
|
654
|
+
return store[name] !== void 0;
|
|
655
|
+
}
|
|
656
|
+
function getPluginRuntimeState(name) {
|
|
657
|
+
if (!store[name]) store[name] = {};
|
|
658
|
+
return store[name];
|
|
659
|
+
}
|
|
660
|
+
function setPluginRuntimeState(name, state) {
|
|
661
|
+
store[name] = state;
|
|
535
662
|
}
|
|
536
|
-
function
|
|
537
|
-
|
|
538
|
-
Object.assign(store[pluginName], state);
|
|
539
|
-
return store[pluginName];
|
|
663
|
+
function resetPluginRuntimeState(name) {
|
|
664
|
+
delete store[name];
|
|
540
665
|
}
|
|
541
|
-
function
|
|
542
|
-
|
|
666
|
+
function getAllPluginRuntimeStates() {
|
|
667
|
+
return { ...store };
|
|
543
668
|
}
|
|
544
669
|
|
|
545
670
|
//#endregion
|
|
@@ -552,6 +677,23 @@ async function start(options = {}) {
|
|
|
552
677
|
if (cwd) process.chdir(cwd);
|
|
553
678
|
const { start: startMioki, logger: logger$1, botConfig: botConfig$1 } = await import("mioki");
|
|
554
679
|
setMiokuLogger(logger$1);
|
|
680
|
+
let shuttingDown = false;
|
|
681
|
+
const shutdown = async (signal) => {
|
|
682
|
+
if (shuttingDown) return;
|
|
683
|
+
shuttingDown = true;
|
|
684
|
+
logger$1.info(`收到 ${signal} 信号,正在关闭服务...`);
|
|
685
|
+
const timer = setTimeout(() => {
|
|
686
|
+
logger$1.error("服务关闭超时,强制退出");
|
|
687
|
+
process.exit(1);
|
|
688
|
+
}, 15e3);
|
|
689
|
+
timer.unref();
|
|
690
|
+
await service_manager_default.disposeAll();
|
|
691
|
+
clearTimeout(timer);
|
|
692
|
+
logger$1.info("Mioku 服务已完全关闭");
|
|
693
|
+
process.exit(0);
|
|
694
|
+
};
|
|
695
|
+
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
696
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
555
697
|
logger$1.info("こんにちは..");
|
|
556
698
|
logger$1.info("---------------------------------------");
|
|
557
699
|
logger$1.info("---------- Mioku 正在启动 ------------");
|
|
@@ -574,23 +716,37 @@ function readVersion() {
|
|
|
574
716
|
const version = readVersion();
|
|
575
717
|
|
|
576
718
|
//#endregion
|
|
719
|
+
exports.Services = Services;
|
|
577
720
|
exports.TOOL_RESULT_FOLLOWUP_KEY = TOOL_RESULT_FOLLOWUP_KEY;
|
|
721
|
+
exports.buildSpawnPlan = require_exec.buildSpawnPlan;
|
|
722
|
+
exports.commandExists = require_exec.commandExists;
|
|
578
723
|
exports.definePlugin = definePlugin;
|
|
724
|
+
exports.defineService = defineService;
|
|
725
|
+
exports.defineState = defineState;
|
|
579
726
|
exports.deleteServiceConfig = deleteServiceConfig;
|
|
580
727
|
exports.ensureDataDir = ensureDataDir;
|
|
728
|
+
exports.getAllPluginRuntimeStates = getAllPluginRuntimeStates;
|
|
581
729
|
exports.getConfigDir = getConfigDir;
|
|
582
730
|
exports.getDataDir = getDataDir;
|
|
583
731
|
exports.getPluginConfigDir = getPluginConfigDir;
|
|
584
732
|
exports.getPluginDataDir = getPluginDataDir;
|
|
585
733
|
exports.getPluginRuntimeState = getPluginRuntimeState;
|
|
734
|
+
exports.getService = getService;
|
|
586
735
|
exports.getServiceConfig = getServiceConfig;
|
|
587
736
|
exports.getServiceConfigDir = getServiceConfigDir;
|
|
588
737
|
exports.getServiceConfigs = getServiceConfigs;
|
|
589
738
|
exports.getServiceDataDir = getServiceDataDir;
|
|
739
|
+
exports.hasPluginState = hasPluginState;
|
|
740
|
+
exports.hasService = hasService;
|
|
741
|
+
exports.normalizeSkillPermissionRole = normalizeSkillPermissionRole;
|
|
590
742
|
exports.pluginManager = plugin_manager_default;
|
|
591
743
|
exports.registerPluginArtifacts = registerPluginArtifacts;
|
|
592
744
|
exports.registerServiceConfig = registerServiceConfig;
|
|
745
|
+
exports.requireService = requireService;
|
|
593
746
|
exports.resetPluginRuntimeState = resetPluginRuntimeState;
|
|
747
|
+
exports.resolveCommand = require_exec.resolveCommand;
|
|
748
|
+
exports.runCommand = require_exec.runCommand;
|
|
749
|
+
exports.runCommandInherit = require_exec.runCommandInherit;
|
|
594
750
|
exports.serviceManager = service_manager_default;
|
|
595
751
|
exports.setPluginRuntimeState = setPluginRuntimeState;
|
|
596
752
|
exports.start = start;
|