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/index.cjs CHANGED
@@ -1,9 +1,10 @@
1
- const require_chunk = require('./chunk-CUT6urMc.cjs');
2
- const fs = require_chunk.__toESM(require("fs"));
3
- const path = require_chunk.__toESM(require("path"));
4
- const url = require_chunk.__toESM(require("url"));
5
- const fs_promises = require_chunk.__toESM(require("fs/promises"));
6
- const mioki = require_chunk.__toESM(require("mioki"));
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 "file:///" + filePath.replace(/\\/g, "/");
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/plugin-artifact-registry.ts
385
- function isAISkill(value) {
386
- return !!value && typeof value === "object" && typeof value.name === "string" && Array.isArray(value.tools);
387
- }
388
- function extractSkills(moduleExports) {
389
- const candidates = [
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.services.help;
414
- const aiService = ctx.services.ai;
415
- if (helpService) {
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
- const skillsEntry = await resolveSkillsEntry(metadata.path);
429
- if (!skillsEntry) continue;
430
- try {
431
- const moduleExports = await import(toImportPath(skillsEntry));
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 ${skillCount} skill(s)`);
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 getPluginRuntimeState(pluginName) {
533
- if (!store[pluginName]) store[pluginName] = {};
534
- return store[pluginName];
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 setPluginRuntimeState(pluginName, state) {
537
- if (!store[pluginName]) store[pluginName] = {};
538
- Object.assign(store[pluginName], state);
539
- return store[pluginName];
663
+ function resetPluginRuntimeState(name) {
664
+ delete store[name];
540
665
  }
541
- function resetPluginRuntimeState(pluginName) {
542
- delete store[pluginName];
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;