mioku 1.0.8 → 1.0.9

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.js CHANGED
@@ -1,4 +1,4 @@
1
- import { buildSpawnPlan, commandExists, resolveCommand, runCommand, runCommandInherit, version } from "./exec-3C9aJ9OX.js";
1
+ import { buildSpawnPlan, commandExists, resolveCommand, runCommand, runCommandInherit, version } from "./exec-C3QTbHLt.js";
2
2
  import { createRequire } from "node:module";
3
3
  import * as fs$5 from "node:fs";
4
4
  import * as fs$4 from "node:fs";
@@ -871,6 +871,7 @@ var AdapterContextImpl = class {
871
871
  #logger;
872
872
  #emit;
873
873
  #correlator;
874
+ #commands;
874
875
  #pendingStarts = new Set();
875
876
  constructor(options) {
876
877
  this.#state = options.state;
@@ -881,6 +882,7 @@ var AdapterContextImpl = class {
881
882
  this.#logger = options.logger;
882
883
  this.#emit = options.emit;
883
884
  this.#correlator = options.correlator;
885
+ this.#commands = options.commands;
884
886
  }
885
887
  registerBot(bot) {
886
888
  return this.#bots.register(bot);
@@ -955,6 +957,12 @@ var AdapterContextImpl = class {
955
957
  }
956
958
  }
957
959
  }
960
+ if (event.kind === "message") {
961
+ const duplicate = this.#correlator?.observationOf(event)?.duplicate ?? false;
962
+ if (!duplicate) {
963
+ if (await this.#commands.dispatch(event)) return;
964
+ }
965
+ }
958
966
  await this.#bus.dispatch(event);
959
967
  }
960
968
  listen(route, handler) {
@@ -1070,9 +1078,13 @@ var EventBus = class {
1070
1078
  #nextOrder = 0;
1071
1079
  #dispatched = 0;
1072
1080
  #logger = null;
1081
+ #filter = null;
1073
1082
  setLogger(logger) {
1074
1083
  this.#logger = logger;
1075
1084
  }
1085
+ setFilter(filter$1) {
1086
+ this.#filter = filter$1;
1087
+ }
1076
1088
  /** 注册事件监听,返回取消注册函数 */
1077
1089
  register(route, handler, options = {}) {
1078
1090
  if (!route) throw new Error("EventBus.register: route must be a non-empty string");
@@ -1106,6 +1118,11 @@ var EventBus = class {
1106
1118
  const matched = [];
1107
1119
  for (const reg of this.#registrations) {
1108
1120
  if (reg.disposed) continue;
1121
+ if (this.#filter) try {
1122
+ if (!this.#filter(reg, event)) continue;
1123
+ } catch (err) {
1124
+ this.#logger?.("error", `Event registration filter failed for "${reg.source}"`, err);
1125
+ }
1109
1126
  if (isWildcardMatch(reg.route, event.type)) {
1110
1127
  matched.push(reg);
1111
1128
  continue;
@@ -1144,6 +1161,57 @@ var EventBus = class {
1144
1161
  }
1145
1162
  };
1146
1163
 
1164
+ //#endregion
1165
+ //#region src/runtime/permissions.ts
1166
+ const isObject$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1167
+ /** 从事件对象中提取发送者 id(支持裸 id / user_id / sender.user_id) */
1168
+ const toUserId = (value) => {
1169
+ if (typeof value === "number" || typeof value === "string" || typeof value === "bigint") return String(value);
1170
+ if (isObject$1(value)) {
1171
+ if ("user_id" in value) return toUserId(value.user_id);
1172
+ if ("sender" in value) {
1173
+ const sender = value.sender;
1174
+ if (isObject$1(sender) && "user_id" in sender) return toUserId(sender.user_id);
1175
+ }
1176
+ }
1177
+ return void 0;
1178
+ };
1179
+ /** 是否群消息 */
1180
+ const isGroupMessage = (event) => isObject$1(event) && event.kind === "message" && event.message_type === "group";
1181
+ /** 当前群群主(仅限所在群) */
1182
+ const isEventGroupOwner = (event) => {
1183
+ if (!isGroupMessage(event)) return false;
1184
+ return event.sender?.role === "owner";
1185
+ };
1186
+ /** 当前群群主或群管理员(仅限所在群) */
1187
+ const isEventGroupAdmin = (event) => {
1188
+ if (!isGroupMessage(event)) return false;
1189
+ const role = event.sender?.role;
1190
+ return role === "owner" || role === "admin";
1191
+ };
1192
+ /** 仅看 owners 名单:bot 主人(无群身份加成) */
1193
+ const isEventMaster$1 = (event) => {
1194
+ const id = toUserId(event);
1195
+ if (!id) return false;
1196
+ return isOwner(id);
1197
+ };
1198
+ /** 仅看 admins 名单:配置管理员 */
1199
+ const isEventAdminConfigOnly = (event) => {
1200
+ const id = toUserId(event);
1201
+ if (!id) return false;
1202
+ return isAdmin(id);
1203
+ };
1204
+ /**
1205
+ * master 或当前群群主
1206
+ */
1207
+ const isEventOwner$1 = (event) => isEventMaster$1(event) || isEventGroupOwner(event);
1208
+ /**
1209
+ * master、配置管理员、当前群群主或群管理员
1210
+ */
1211
+ const isEventAdmin$1 = (event) => isEventOwner$1(event) || isEventAdminConfigOnly(event) || isEventGroupAdmin(event);
1212
+ const isEventOwnerOrAdmin$1 = (event) => isEventAdmin$1(event);
1213
+ const hasEventRight$1 = (event) => isEventOwnerOrAdmin$1(event);
1214
+
1147
1215
  //#endregion
1148
1216
  //#region src/utils.ts
1149
1217
  const ChromeUA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/131.0.0.0";
@@ -1911,31 +1979,18 @@ const Services = {
1911
1979
 
1912
1980
  //#endregion
1913
1981
  //#region src/runtime/mioku-context.ts
1914
- const isObject$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1915
- /** 从事件对象中提取发送者 id(支持裸 id / user_id / sender.user_id) */
1916
- const toUserId = (value) => {
1917
- if (typeof value === "number" || typeof value === "string" || typeof value === "bigint") return String(value);
1918
- if (isObject$1(value)) {
1919
- if ("user_id" in value) return toUserId(value.user_id);
1920
- if ("sender" in value) {
1921
- const sender = value.sender;
1922
- if (isObject$1(sender) && "user_id" in sender) return toUserId(sender.user_id);
1923
- }
1924
- }
1925
- return void 0;
1926
- };
1927
- const isEventOwner = (event) => {
1928
- const id = toUserId(event);
1929
- if (!id) return false;
1930
- return isOwner(id);
1931
- };
1932
- const isEventAdmin = (event) => {
1933
- const id = toUserId(event);
1934
- if (!id) return false;
1935
- return isAdmin(id);
1936
- };
1937
- const isEventOwnerOrAdmin = (event) => isEventOwner(event) || isEventAdmin(event);
1938
- const hasEventRight = (event) => isEventOwnerOrAdmin(event);
1982
+ /** 仅看 owners 名单:bot 主人(无群身份加成) */
1983
+ const isEventMaster = (event) => isEventMaster$1(event);
1984
+ /**
1985
+ * master 或当前群群主。等价于 `ctx.command({ permission: "owner" })` 的判断。
1986
+ */
1987
+ const isEventOwner = (event) => isEventOwner$1(event);
1988
+ /**
1989
+ * master、配置管理员、当前群群主或群管理员。等价于 `ctx.command({ permission: "admin" })` 的判断。
1990
+ */
1991
+ const isEventAdmin = (event) => isEventAdmin$1(event);
1992
+ const isEventOwnerOrAdmin = (event) => isEventOwnerOrAdmin$1(event);
1993
+ const hasEventRight = (event) => hasEventRight$1(event);
1939
1994
  const CTX_UTILS = {
1940
1995
  localeDate,
1941
1996
  localeTime,
@@ -1990,6 +2045,9 @@ var MiokuContext = class {
1990
2045
  get pluginName() {
1991
2046
  return this.#options.pluginName;
1992
2047
  }
2048
+ get pluginId() {
2049
+ return this.#options.pluginId;
2050
+ }
1993
2051
  /** 第一个已连接的 bot(多数单 bot 场景直接用这个) */
1994
2052
  get bot() {
1995
2053
  return this.#options.bots.all()[0];
@@ -2089,7 +2147,7 @@ var MiokuContext = class {
2089
2147
  const inputRoutes = Array.isArray(route) ? route : [route];
2090
2148
  const bypassDedup = inputRoutes.some((item) => item.startsWith("!"));
2091
2149
  const routes = inputRoutes.map((item) => item.startsWith("!") ? item.slice(1) : item);
2092
- const source = `plugin:${this.#options.pluginName}`;
2150
+ const source = `plugin:${this.#options.pluginId}`;
2093
2151
  const handledEvents = new WeakSet();
2094
2152
  const correlator = bypassDedup ? void 0 : this.#options.correlator;
2095
2153
  const wrappedHandler = async (event) => {
@@ -2111,6 +2169,17 @@ var MiokuContext = class {
2111
2169
  this.#addCleanup(dispose);
2112
2170
  return dispose;
2113
2171
  }
2172
+ command(definitionOrMatcher, handler, options = {}) {
2173
+ const dispose = typeof definitionOrMatcher === "object" && definitionOrMatcher !== null && "name" in definitionOrMatcher ? this.#options.commands.register(this.#options.pluginId, {
2174
+ ...definitionOrMatcher,
2175
+ priority: definitionOrMatcher.priority ?? this.#options.priority
2176
+ }, this) : this.#options.commands.register(this.#options.pluginId, definitionOrMatcher, handler, {
2177
+ ...options,
2178
+ priority: options.priority ?? this.#options.priority
2179
+ }, this);
2180
+ this.#addCleanup(dispose);
2181
+ return dispose;
2182
+ }
2114
2183
  /** 注册 cron 定时任务,插件卸载时自动停止 */
2115
2184
  cron(expression, handler) {
2116
2185
  const task = nodeCron.schedule(expression, async (taskContext) => {
@@ -2167,6 +2236,10 @@ var MiokuContext = class {
2167
2236
  get buses() {
2168
2237
  return this.#options.bus;
2169
2238
  }
2239
+ /** 当前运行时的命令管理器 */
2240
+ get commands() {
2241
+ return this.#options.commands;
2242
+ }
2170
2243
  get segment() {
2171
2244
  return segment;
2172
2245
  }
@@ -2207,24 +2280,30 @@ var MiokuContext = class {
2207
2280
  return noticeAdmins(this.#options.bots.all(), this.#options.config.admins, message, options);
2208
2281
  }
2209
2282
  isGroupMsg(event) {
2210
- return isObject$1(event) && event.kind === "message" && event.message_type === "group";
2283
+ return isObject(event) && event.kind === "message" && event.message_type === "group";
2211
2284
  }
2212
2285
  isPrivateMsg(event) {
2213
- return isObject$1(event) && event.kind === "message" && event.message_type === "private";
2286
+ return isObject(event) && event.kind === "message" && event.message_type === "private";
2214
2287
  }
2215
- /** 事件发送者是否为主人 */
2288
+ /** 事件发送者是否为 bot 主人(仅看 owners 名单,不识别群身份) */
2289
+ isMaster(event) {
2290
+ return isEventMaster(event);
2291
+ }
2292
+ /** 事件发送者是否为 bot 主人或当前群群主;等价于 `permission: "owner"` */
2216
2293
  isOwner(event) {
2217
2294
  return isEventOwner(event);
2218
2295
  }
2219
- /** 事件发送者是否为管理员 */
2296
+ /** 事件发送者是否为 bot 主人、配置管理员、当前群群主或群管理员;等价于 `permission: "admin"` */
2220
2297
  isAdmin(event) {
2221
2298
  return isEventAdmin(event);
2222
2299
  }
2300
+ /** 同 `isAdmin`,保留旧名称 */
2223
2301
  isOwnerOrAdmin(event) {
2224
- return isEventOwnerOrAdmin(event);
2302
+ return isEventAdmin(event);
2225
2303
  }
2304
+ /** 同 `isAdmin`,别名 */
2226
2305
  hasRight(event) {
2227
- return hasEventRight(event);
2306
+ return isEventAdmin(event);
2228
2307
  }
2229
2308
  async dispose() {
2230
2309
  const all = Array.from(this.#cleanup);
@@ -2515,19 +2594,387 @@ var EventCorrelator = class {
2515
2594
  }
2516
2595
  };
2517
2596
 
2597
+ //#endregion
2598
+ //#region src/runtime/commands.ts
2599
+ const normalizeRole = (role) => {
2600
+ const value = String(role ?? "member").trim().toLowerCase();
2601
+ if (value === "master" || value === "owner" || value === "admin") return value;
2602
+ return "member";
2603
+ };
2604
+ const userIdOf = (event) => toUserId(event);
2605
+ const textHookMatches = (text$1, raw) => {
2606
+ const source = String(raw ?? "").trim();
2607
+ if (!source) return false;
2608
+ if (source.startsWith("/") && source.length > 1) {
2609
+ const end = source.lastIndexOf("/");
2610
+ if (end > 0) try {
2611
+ const flags = source.slice(end + 1);
2612
+ const regex = new RegExp(source.slice(1, end), flags);
2613
+ return regex.test(text$1);
2614
+ } catch {
2615
+ return false;
2616
+ }
2617
+ }
2618
+ return text$1 === source || text$1.startsWith(source);
2619
+ };
2620
+ const routeMatches = (event, route) => {
2621
+ if (!route) return false;
2622
+ return event.type === route || event.routes.some((item) => item === route);
2623
+ };
2624
+ const parsePrefixes = (prefixes, defaultPrefix) => {
2625
+ if (prefixes === false) return ["", defaultPrefix];
2626
+ const values = Array.isArray(prefixes) ? prefixes : [prefixes];
2627
+ const normalized = values.map((value) => String(value)).filter((value, index, all) => all.indexOf(value) === index);
2628
+ return normalized.length > 0 ? normalized : [defaultPrefix];
2629
+ };
2630
+ const commandBody = (text$1, prefixes) => {
2631
+ const prefix = [...prefixes].sort((a, b) => b.length - a.length).find((item) => item === "" || text$1.startsWith(item));
2632
+ if (prefix === void 0) return void 0;
2633
+ return text$1.slice(prefix.length).trimStart();
2634
+ };
2635
+ const stringMatch = (body, matcher) => {
2636
+ const value = matcher.trim();
2637
+ if (!value) return void 0;
2638
+ if (body !== value && !(body.startsWith(value) && /\s/.test(body[value.length] ?? ""))) return void 0;
2639
+ const rest = body.slice(value.length).trim();
2640
+ return { args: rest ? rest.split(/\s+/) : [] };
2641
+ };
2642
+ const commandKey$1 = (value) => String(value).trim().replace(/^[#/.]+\s*/, "").split(/\s+/)[0].toLowerCase();
2643
+ const displayCommand = (command, defaultPrefix) => {
2644
+ if (command.prefixes === false) return command.name;
2645
+ const prefixes = command.prefixes === void 0 ? [defaultPrefix] : Array.isArray(command.prefixes) ? command.prefixes : [command.prefixes];
2646
+ return `${prefixes.find((prefix) => prefix.length > 0) ?? ""}${command.name}`;
2647
+ };
2648
+ var CommandManager = class {
2649
+ #getDefaultPrefix;
2650
+ #getOwners;
2651
+ #getAdmins;
2652
+ #logger;
2653
+ #commands = [];
2654
+ #legacy = new Map();
2655
+ #access;
2656
+ #nextOrder = 0;
2657
+ constructor(options) {
2658
+ this.#getDefaultPrefix = options.getDefaultPrefix;
2659
+ this.#getOwners = options.getOwners;
2660
+ this.#getAdmins = options.getAdmins;
2661
+ this.#logger = options.logger;
2662
+ }
2663
+ register(plugin, definitionOrMatcher, handlerOrContext, optionsOrContext = {}, context) {
2664
+ const isDefinition = typeof definitionOrMatcher === "object" && definitionOrMatcher !== null && "name" in definitionOrMatcher;
2665
+ const shortcutOptions = isDefinition ? {} : optionsOrContext;
2666
+ const resolvedContext = isDefinition ? handlerOrContext : context;
2667
+ const handler = isDefinition ? void 0 : handlerOrContext;
2668
+ const definition = isDefinition ? definitionOrMatcher : {
2669
+ ...shortcutOptions,
2670
+ name: shortcutOptions.name ?? String(definitionOrMatcher),
2671
+ match: definitionOrMatcher,
2672
+ handler
2673
+ };
2674
+ if (typeof definition.handler !== "function") throw new Error("CommandManager.register: handler must be a function");
2675
+ if (!resolvedContext) throw new Error("CommandManager.register: context is required");
2676
+ const name = String(definition.name ?? "").trim();
2677
+ if (!name) throw new Error("CommandManager.register: name is required");
2678
+ const matcher = definition.match ?? name;
2679
+ const command = {
2680
+ plugin,
2681
+ id: String(definition.id ?? name).trim() || name,
2682
+ name,
2683
+ aliases: (definition.aliases ?? []).map((item) => String(item).trim()).filter(Boolean),
2684
+ matcher,
2685
+ description: String(definition.description ?? "").trim(),
2686
+ usage: definition.usage,
2687
+ permission: normalizeRole(definition.permission),
2688
+ priority: typeof definition.priority === "number" && !Number.isNaN(definition.priority) ? definition.priority : 0,
2689
+ prefixes: definition.prefixes,
2690
+ handler: definition.handler,
2691
+ order: this.#nextOrder++,
2692
+ context: resolvedContext
2693
+ };
2694
+ this.#commands.push(command);
2695
+ return () => {
2696
+ const index = this.#commands.indexOf(command);
2697
+ if (index >= 0) this.#commands.splice(index, 1);
2698
+ };
2699
+ }
2700
+ setAccessControl(config) {
2701
+ this.#access = config;
2702
+ }
2703
+ syncMetadata(metadata) {
2704
+ this.#legacy.set(metadata.name, { metadata });
2705
+ }
2706
+ removePlugin(plugin) {
2707
+ this.#legacy.delete(plugin);
2708
+ for (let i = this.#commands.length - 1; i >= 0; i--) if (this.#commands[i].plugin === plugin) this.#commands.splice(i, 1);
2709
+ }
2710
+ clear() {
2711
+ this.#commands.length = 0;
2712
+ this.#legacy.clear();
2713
+ this.#access = void 0;
2714
+ }
2715
+ list() {
2716
+ return this.#orderedCommands();
2717
+ }
2718
+ #orderedCommands() {
2719
+ return [...this.#commands].sort((a, b) => a.priority - b.priority || a.order - b.order);
2720
+ }
2721
+ getPluginHelp(plugin) {
2722
+ const metadata = this.#legacy.get(plugin)?.metadata;
2723
+ const runtime = this.#commands.filter((item) => item.plugin === plugin);
2724
+ if (!metadata?.config.help && runtime.length === 0) return void 0;
2725
+ const commands = [];
2726
+ const seen = new Set();
2727
+ const runtimeByKey = new Map(runtime.map((command) => [commandKey$1(command.name), command]));
2728
+ for (const command of metadata?.config.help?.commands ?? []) {
2729
+ const key = commandKey$1(command.cmd);
2730
+ const runtimeCommand = runtimeByKey.get(key);
2731
+ if (runtimeCommand) {
2732
+ const cmd = displayCommand(runtimeCommand, this.#getDefaultPrefix());
2733
+ seen.add(key);
2734
+ commands.push({
2735
+ cmd,
2736
+ desc: runtimeCommand.description || command.desc || cmd,
2737
+ usage: runtimeCommand.usage ?? command.usage,
2738
+ role: runtimeCommand.permission
2739
+ });
2740
+ } else if (!seen.has(key)) {
2741
+ seen.add(key);
2742
+ commands.push(command);
2743
+ }
2744
+ }
2745
+ for (const command of runtime) {
2746
+ const cmd = displayCommand(command, this.#getDefaultPrefix());
2747
+ if (seen.has(commandKey$1(cmd))) continue;
2748
+ seen.add(commandKey$1(cmd));
2749
+ commands.push({
2750
+ cmd,
2751
+ desc: command.description || cmd,
2752
+ usage: command.usage,
2753
+ role: command.permission
2754
+ });
2755
+ }
2756
+ const help = metadata?.config.help;
2757
+ return {
2758
+ title: help?.title || plugin,
2759
+ description: help?.description || metadata?.description || "",
2760
+ commands
2761
+ };
2762
+ }
2763
+ catalog() {
2764
+ const items = [];
2765
+ const plugins = new Set([...this.#legacy.keys(), ...this.#commands.map((item) => item.plugin)]);
2766
+ for (const plugin of plugins) {
2767
+ const metadata = this.#legacy.get(plugin)?.metadata;
2768
+ const help = metadata?.config.help;
2769
+ items.push({
2770
+ kind: "plugin",
2771
+ plugin,
2772
+ id: plugin,
2773
+ label: help?.title || plugin,
2774
+ desc: help?.description || metadata?.description,
2775
+ source: metadata ? "manifest" : "runtime"
2776
+ });
2777
+ const seen = new Set();
2778
+ for (const command of this.#commands.filter((item) => item.plugin === plugin)) {
2779
+ seen.add(commandKey$1(command.id));
2780
+ items.push({
2781
+ kind: "command",
2782
+ plugin,
2783
+ id: command.id,
2784
+ label: command.name,
2785
+ desc: command.description,
2786
+ usage: command.usage,
2787
+ permission: command.permission,
2788
+ priority: command.priority,
2789
+ match: command.matcher instanceof RegExp ? command.matcher.toString() : command.matcher,
2790
+ source: "runtime"
2791
+ });
2792
+ }
2793
+ for (const hook of metadata?.config.accessHooks ?? []) {
2794
+ if (seen.has(commandKey$1(hook.id))) continue;
2795
+ seen.add(commandKey$1(hook.id));
2796
+ items.push({
2797
+ kind: "command",
2798
+ plugin,
2799
+ id: hook.id,
2800
+ label: hook.id,
2801
+ desc: hook.description,
2802
+ match: hook.match,
2803
+ event: hook.event,
2804
+ source: "manifest"
2805
+ });
2806
+ }
2807
+ for (const command of help?.commands ?? []) {
2808
+ if (seen.has(commandKey$1(command.cmd))) continue;
2809
+ seen.add(commandKey$1(command.cmd));
2810
+ items.push({
2811
+ kind: "command",
2812
+ plugin,
2813
+ id: command.cmd,
2814
+ label: command.cmd,
2815
+ desc: command.desc,
2816
+ usage: command.usage,
2817
+ permission: command.role,
2818
+ source: "manifest"
2819
+ });
2820
+ }
2821
+ }
2822
+ return items.sort((a, b) => a.kind === b.kind ? a.plugin.localeCompare(b.plugin) || a.id.localeCompare(b.id) : a.kind === "plugin" ? -1 : 1);
2823
+ }
2824
+ async dispatch(event) {
2825
+ const text$1 = String(event.message?.text?.() ?? "").trim();
2826
+ if (!text$1) return false;
2827
+ const match$1 = this.#find(text$1);
2828
+ if (!match$1) return false;
2829
+ if (!this.#canUse(match$1.command, event)) return true;
2830
+ try {
2831
+ await match$1.command.handler({
2832
+ ctx: match$1.command.context,
2833
+ event,
2834
+ command: match$1.command,
2835
+ text: text$1,
2836
+ body: match$1.body,
2837
+ args: match$1.args,
2838
+ match: match$1.match
2839
+ });
2840
+ } catch (error) {
2841
+ this.#logger?.error(`Command "${match$1.command.plugin}:${match$1.command.id}" failed`, error);
2842
+ }
2843
+ return true;
2844
+ }
2845
+ shouldDispatch(source, event) {
2846
+ if (!source.startsWith("plugin:")) return true;
2847
+ const plugin = source.slice(7);
2848
+ const metadata = this.#legacy.get(plugin)?.metadata;
2849
+ if (!metadata) return this.#pluginAllowed(plugin, event);
2850
+ if (!this.#pluginAllowed(plugin, event)) return false;
2851
+ const text$1 = event.kind === "message" ? String(event.message.text()).trim() : "";
2852
+ const matches = (metadata.config.accessHooks ?? []).filter((hook) => event.kind === "message" && textHookMatches(text$1, hook.match) || routeMatches(event, hook.event));
2853
+ return matches.every((hook) => this.#commandAllowed(plugin, hook.id, event));
2854
+ }
2855
+ #find(text$1) {
2856
+ for (const command of this.#orderedCommands()) {
2857
+ const prefixes = parsePrefixes(command.prefixes ?? this.#getDefaultPrefix(), this.#getDefaultPrefix());
2858
+ const body = commandBody(text$1, prefixes);
2859
+ if (body === void 0) continue;
2860
+ if (typeof command.matcher === "string") {
2861
+ const candidates = [
2862
+ command.matcher,
2863
+ command.name,
2864
+ ...command.aliases
2865
+ ];
2866
+ for (const candidate of candidates) {
2867
+ const result = stringMatch(body, candidate);
2868
+ if (result) return {
2869
+ command,
2870
+ body,
2871
+ args: result.args
2872
+ };
2873
+ }
2874
+ continue;
2875
+ }
2876
+ command.matcher.lastIndex = 0;
2877
+ const matched = body.match(command.matcher);
2878
+ if (!matched) continue;
2879
+ const args = matched.length > 1 ? matched.slice(1).filter((item) => item != null) : body.slice(matched[0].length).trim().split(/\s+/).filter(Boolean);
2880
+ return {
2881
+ command,
2882
+ body,
2883
+ args,
2884
+ match: matched
2885
+ };
2886
+ }
2887
+ return void 0;
2888
+ }
2889
+ #canUse(command, event) {
2890
+ const userId = userIdOf(event);
2891
+ const master = Boolean(userId && this.#isMaster(userId));
2892
+ const owner = master || this.#isGroupOwner(event);
2893
+ const admin = owner || Boolean(userId && this.#isAdmin(userId)) || this.#isGroupAdmin(event);
2894
+ if (command.permission === "master") {
2895
+ if (!master) return false;
2896
+ } else if (command.permission === "owner") {
2897
+ if (!owner) return false;
2898
+ } else if (command.permission === "admin" && !admin) return false;
2899
+ return this.#commandAllowed(command.plugin, command.id, event);
2900
+ }
2901
+ #pluginAllowed(plugin, event) {
2902
+ const userId = event.kind === "message" ? userIdOf(event) : "user_id" in event ? event.user_id : void 0;
2903
+ if (userId && (this.#isMaster(userId) || this.#isAdmin(userId)) || this.#isGroupOwner(event) || this.#isGroupAdmin(event)) return true;
2904
+ return this.#resolveAction(plugin, void 0, event) !== "block";
2905
+ }
2906
+ #commandAllowed(plugin, command, event) {
2907
+ const userId = event.kind === "message" ? userIdOf(event) : "user_id" in event ? event.user_id : void 0;
2908
+ if (userId && (this.#isMaster(userId) || this.#isAdmin(userId)) || this.#isGroupOwner(event) || this.#isGroupAdmin(event)) return true;
2909
+ return this.#resolveAction(plugin, command, event) !== "block";
2910
+ }
2911
+ #resolveAction(plugin, command, event) {
2912
+ const access = this.#access;
2913
+ if (!access) return void 0;
2914
+ const scopes = [
2915
+ (() => {
2916
+ const userId = event.kind === "message" ? userIdOf(event) : "user_id" in event && event.user_id ? String(event.user_id) : void 0;
2917
+ return userId ? access.users[userId] : void 0;
2918
+ })(),
2919
+ (() => {
2920
+ const groupId = "group_id" in event && event.group_id ? String(event.group_id) : void 0;
2921
+ return groupId ? access.groups[groupId] : void 0;
2922
+ })(),
2923
+ access.global
2924
+ ];
2925
+ for (const scope of scopes) {
2926
+ if (!scope) continue;
2927
+ const commandRule = command ? scope.commands?.[plugin]?.[command]?.action : void 0;
2928
+ if (commandRule) return commandRule;
2929
+ const pluginRule = scope.plugins?.[plugin]?.action;
2930
+ if (pluginRule) return pluginRule;
2931
+ }
2932
+ return void 0;
2933
+ }
2934
+ #isMaster(userId) {
2935
+ return this.#owners().includes(userId);
2936
+ }
2937
+ #isAdmin(userId) {
2938
+ return this.#isMaster(userId) || this.#admins().includes(userId);
2939
+ }
2940
+ #isGroupOwner(event) {
2941
+ return isEventGroupOwner(event);
2942
+ }
2943
+ #isGroupAdmin(event) {
2944
+ return isEventGroupAdmin(event);
2945
+ }
2946
+ #owners() {
2947
+ return this.#configIds("owners");
2948
+ }
2949
+ #admins() {
2950
+ return this.#configIds("admins");
2951
+ }
2952
+ #configIds(key) {
2953
+ return [...key === "owners" ? this.#getOwners() : this.#getAdmins()].map(String);
2954
+ }
2955
+ };
2956
+ let activeCommandManager;
2957
+ const setActiveCommandManager = (manager) => {
2958
+ activeCommandManager = manager;
2959
+ };
2960
+ const getActiveCommandManager = () => activeCommandManager;
2961
+
2518
2962
  //#endregion
2519
2963
  //#region src/runtime/plugin-metadata.ts
2520
2964
  const store$1 = getOrCreate("plugin-metadata", () => new Map());
2521
2965
  const setPluginMetadata = (meta) => {
2522
2966
  store$1.set(meta.name, meta);
2967
+ getActiveCommandManager()?.syncMetadata(meta);
2523
2968
  };
2524
2969
  const removePluginMetadata = (name) => {
2525
2970
  store$1.delete(name);
2971
+ getActiveCommandManager()?.removePlugin(name);
2526
2972
  };
2527
2973
  const getPluginMetadata = (name) => store$1.get(name);
2528
2974
  const getPluginMetadataList = () => [...store$1.values()];
2529
2975
  const resetPluginMetadata = () => {
2530
2976
  store$1.clear();
2977
+ getActiveCommandManager()?.clear();
2531
2978
  };
2532
2979
 
2533
2980
  //#endregion
@@ -3187,12 +3634,6 @@ async function sendTextOrForward(options) {
3187
3634
  }
3188
3635
  }
3189
3636
 
3190
- //#endregion
3191
- //#region src/builtin/core/commands/prefix.ts
3192
- function getCommandPrefix() {
3193
- return botConfig.prefix ?? ".";
3194
- }
3195
-
3196
3637
  //#endregion
3197
3638
  //#region src/builtin/core/system/package-manager.ts
3198
3639
  const NPM_REGISTRY = "https://registry.npmjs.org";
@@ -3784,102 +4225,102 @@ async function performUpdateAndReport(ctx, event, names) {
3784
4225
  triggerRestart(marker);
3785
4226
  }
3786
4227
  function registerUpdateCommands(ctx) {
3787
- const dispose = ctx.handle("message", async (event) => {
3788
- const text$1 = ctx.text(event)?.trim();
3789
- if (!text$1 || event?.user_id === event?.self_id) return;
3790
- const prefix = getCommandPrefix();
3791
- if (!text$1.startsWith(`${prefix}update`)) return;
3792
- if (!isEventOwner(event)) {
3793
- ctx.logger.warn("[core] update 指令仅主人可用");
3794
- return;
3795
- }
3796
- const arg = text$1.slice(prefix.length + 6).trim();
3797
- const selfId = String(event?.self_id || "");
3798
- const bot = event.bot;
3799
- if (!bot) return;
3800
- if (arg === "all") {
3801
- const managed = await updateAllManaged();
3802
- if (managed.names.length === 0) {
3803
- await replyText(event, "未找到可更新的 mioku 包");
3804
- return;
3805
- }
3806
- await performUpdateAndReport(ctx, event, managed.names);
3807
- return;
3808
- }
3809
- if (arg === "mioku" || arg === "self") {
3810
- await performUpdateAndReport(ctx, event, ["mioku"]);
3811
- return;
3812
- }
3813
- if (arg.startsWith("plugin ") || arg.startsWith("service ")) {
3814
- const [typeRaw, ...rest] = arg.split(/\s+/);
3815
- const name = rest.join(" ").trim();
3816
- const type = typeRaw === "plugin" ? "plugin" : "service";
3817
- if (!name) {
3818
- await replyText(event, `用法:${prefix}update ${type} <名称>`);
4228
+ const dispose = ctx.command({
4229
+ name: "update",
4230
+ aliases: ["更新"],
4231
+ permission: "master",
4232
+ priority: -1e3,
4233
+ description: "检查并选择插件/服务更新",
4234
+ handler: async ({ event, args }) => {
4235
+ const prefix = String(ctx.config.prefix ?? ".");
4236
+ const arg = args.join(" ").trim();
4237
+ const selfId = String(event?.self_id || "");
4238
+ const bot = event.bot;
4239
+ if (!bot) return;
4240
+ if (arg === "all") {
4241
+ const managed = await updateAllManaged();
4242
+ if (managed.names.length === 0) {
4243
+ await replyText(event, "未找到可更新的 mioku 包");
4244
+ return;
4245
+ }
4246
+ await performUpdateAndReport(ctx, event, managed.names);
3819
4247
  return;
3820
4248
  }
3821
- const pkgPrefix = type === "plugin" ? "mioku-plugin-" : "mioku-service-";
3822
- const fullName = name.startsWith(pkgPrefix) ? name : `${pkgPrefix}${name}`;
3823
- await performUpdateAndReport(ctx, event, [fullName]);
3824
- return;
3825
- }
3826
- if (arg === "check" || arg === "检查") {
3827
- const pending = getPendingMap();
3828
- const key = conversationKey(event);
3829
- const existing = pending.get(key);
3830
- if (existing) {
3831
- existing.disposer();
3832
- clearTimeout(existing.timer);
3833
- pending.delete(key);
3834
- }
3835
- let items;
3836
- try {
3837
- items = await checkUpdates();
3838
- } catch (error) {
3839
- ctx.logger.error(`[core] 检查更新失败: ${error}`);
3840
- await replyText(event, `检查更新失败:${String(error)}`);
4249
+ if (arg === "mioku" || arg === "self") {
4250
+ await performUpdateAndReport(ctx, event, ["mioku"]);
3841
4251
  return;
3842
4252
  }
3843
- if (items.length === 0) {
3844
- await replyText(event, "所有插件与服务均已是最新版本");
4253
+ if (arg.startsWith("plugin ") || arg.startsWith("service ")) {
4254
+ const [typeRaw, ...rest] = arg.split(/\s+/);
4255
+ const name = rest.join(" ").trim();
4256
+ const type = typeRaw === "plugin" ? "plugin" : "service";
4257
+ if (!name) {
4258
+ await replyText(event, `用法:${prefix}update ${type} <名称>`);
4259
+ return;
4260
+ }
4261
+ const pkgPrefix = type === "plugin" ? "mioku-plugin-" : "mioku-service-";
4262
+ const fullName = name.startsWith(pkgPrefix) ? name : `${pkgPrefix}${name}`;
4263
+ await performUpdateAndReport(ctx, event, [fullName]);
3845
4264
  return;
3846
4265
  }
3847
- await replyText(event, renderUpdateList(items));
3848
- const timeoutMs = SELECT_TIMEOUT_MS;
3849
- const listenerDispose = ctx.handle("message", async (ev) => {
3850
- if (String(ev?.self_id || "") !== selfId) return;
3851
- if (conversationKey(ev) !== key) return;
3852
- if (!isEventOwner(ev)) return;
3853
- const evText = ctx.text(ev)?.trim() || "";
3854
- if (evText.startsWith(`${prefix}update`)) return;
3855
- const sel = pending.get(key);
3856
- if (!sel) return;
3857
- clearTimeout(sel.timer);
3858
- sel.disposer();
3859
- pending.delete(key);
3860
- const parsed = parseSelection(evText, sel.items.length);
3861
- const chosen = parsed.all ? sel.items : parsed.indices.map((i) => sel.items[i]).filter(Boolean);
3862
- if (chosen.length === 0) {
3863
- await replyText(event, "未选择任何有效项,已取消");
4266
+ if (arg === "check" || arg === "检查") {
4267
+ const pending = getPendingMap();
4268
+ const key = conversationKey(event);
4269
+ const existing = pending.get(key);
4270
+ if (existing) {
4271
+ existing.disposer();
4272
+ clearTimeout(existing.timer);
4273
+ pending.delete(key);
4274
+ }
4275
+ let items;
4276
+ try {
4277
+ items = await checkUpdates();
4278
+ } catch (error) {
4279
+ ctx.logger.error(`[core] 检查更新失败: ${error}`);
4280
+ await replyText(event, `检查更新失败:${String(error)}`);
3864
4281
  return;
3865
4282
  }
3866
- await performUpdateAndReport(ctx, event, chosen.map((i) => i.name));
3867
- });
3868
- const timer = setTimeout(async () => {
3869
- const sel = pending.get(key);
3870
- if (!sel) return;
3871
- sel.disposer();
3872
- pending.delete(key);
3873
- await replyText(event, "操作超时,已取消更新");
3874
- }, timeoutMs);
3875
- pending.set(key, {
3876
- disposer: listenerDispose,
3877
- timer,
3878
- items
3879
- });
3880
- return;
4283
+ if (items.length === 0) {
4284
+ await replyText(event, "所有插件与服务均已是最新版本");
4285
+ return;
4286
+ }
4287
+ await replyText(event, renderUpdateList(items));
4288
+ const timeoutMs = SELECT_TIMEOUT_MS;
4289
+ const listenerDispose = ctx.handle("message", async (ev) => {
4290
+ if (String(ev?.self_id || "") !== selfId) return;
4291
+ if (conversationKey(ev) !== key) return;
4292
+ if (!isEventMaster(ev)) return;
4293
+ const evText = ctx.text(ev)?.trim() || "";
4294
+ if (evText.startsWith(`${prefix}update`)) return;
4295
+ const sel = pending.get(key);
4296
+ if (!sel) return;
4297
+ clearTimeout(sel.timer);
4298
+ sel.disposer();
4299
+ pending.delete(key);
4300
+ const parsed = parseSelection(evText, sel.items.length);
4301
+ const chosen = parsed.all ? sel.items : parsed.indices.map((i) => sel.items[i]).filter(Boolean);
4302
+ if (chosen.length === 0) {
4303
+ await replyText(event, "未选择任何有效项,已取消");
4304
+ return;
4305
+ }
4306
+ await performUpdateAndReport(ctx, event, chosen.map((i) => i.name));
4307
+ });
4308
+ const timer = setTimeout(async () => {
4309
+ const sel = pending.get(key);
4310
+ if (!sel) return;
4311
+ sel.disposer();
4312
+ pending.delete(key);
4313
+ await replyText(event, "操作超时,已取消更新");
4314
+ }, timeoutMs);
4315
+ pending.set(key, {
4316
+ disposer: listenerDispose,
4317
+ timer,
4318
+ items
4319
+ });
4320
+ return;
4321
+ }
4322
+ await replyText(event, `用法:\n${prefix}update check 检查并选择更新\n${prefix}update all 更新全部\n${prefix}update mioku 更新框架\n${prefix}update plugin <名称>\n${prefix}update service <名称>`);
3881
4323
  }
3882
- await replyText(event, `用法:\n${prefix}update check 检查并选择更新\n${prefix}update all 更新全部\n${prefix}update mioku 更新框架\n${prefix}update plugin <名称>\n${prefix}update service <名称>`);
3883
4324
  });
3884
4325
  return () => {
3885
4326
  dispose();
@@ -3894,15 +4335,13 @@ function registerUpdateCommands(ctx) {
3894
4335
 
3895
4336
  //#endregion
3896
4337
  //#region src/builtin/core/commands/install.ts
3897
- function parseTargetArgs(text$1, head) {
3898
- if (!text$1.startsWith(head)) return null;
3899
- const rest = text$1.slice(head.length).trim();
3900
- const matched = rest.match(/^(plugin|service)\s+([\s\S]+)$/);
3901
- if (!matched) return null;
3902
- const name = matched[2].trim();
4338
+ function parseTargetArgs(args) {
4339
+ const type = args[0];
4340
+ if (type !== "plugin" && type !== "service") return null;
4341
+ const name = args.slice(1).join(" ").trim();
3903
4342
  if (!name) return null;
3904
4343
  return {
3905
- type: matched[1],
4344
+ type,
3906
4345
  name
3907
4346
  };
3908
4347
  }
@@ -3910,68 +4349,70 @@ function typeLabel(type) {
3910
4349
  return type === "plugin" ? "插件" : "服务";
3911
4350
  }
3912
4351
  function registerInstallCommands(ctx) {
3913
- const dispose = ctx.handle("message", async (event) => {
3914
- const text$1 = ctx.text(event)?.trim();
3915
- if (!text$1 || event?.user_id === event?.self_id) return;
3916
- const prefix = getCommandPrefix();
3917
- const installHead = `${prefix}install`;
3918
- const uninstallHead = `${prefix}uninstall`;
3919
- if (!text$1.startsWith(installHead) && !text$1.startsWith(uninstallHead)) return;
3920
- if (!isEventOwner(event)) {
3921
- ctx.logger.warn("[core] install/uninstall 指令仅主人可用");
3922
- return;
3923
- }
3924
- if (text$1.startsWith(installHead)) {
3925
- const parsed$1 = parseTargetArgs(text$1, installHead);
3926
- if (!parsed$1) {
3927
- await replyText(event, `用法:${prefix}install plugin <名称> 或 ${prefix}install service <名称>`);
4352
+ const register = (name) => ctx.command({
4353
+ name,
4354
+ aliases: name === "install" ? ["安装"] : ["卸载"],
4355
+ permission: "master",
4356
+ priority: -1e3,
4357
+ description: name === "install" ? "从 npm 安装插件/服务" : "卸载插件/服务",
4358
+ handler: async ({ event, args }) => {
4359
+ if (name === "install") {
4360
+ const parsed$1 = parseTargetArgs(args);
4361
+ if (!parsed$1) {
4362
+ await replyText(event, `用法:${ctx.config.prefix ?? "."}install plugin <名称> 或 ${ctx.config.prefix ?? "."}install service <名称>`);
4363
+ return;
4364
+ }
4365
+ await replyText(event, `正在从 npm 安装${typeLabel(parsed$1.type)} ${parsed$1.name}...`);
4366
+ try {
4367
+ const result = await installPackage(parsed$1.type, parsed$1.name);
4368
+ if (!result.ok) {
4369
+ ctx.logger.error(`[core] 安装失败: ${result.error || result.output}`);
4370
+ await replyText(event, `安装失败:${result.error || result.output}`);
4371
+ return;
4372
+ }
4373
+ const lines = [
4374
+ `已安装 ${result.packageName}`,
4375
+ result.enabled ? "已在 plugins 中启用" : "",
4376
+ "重启后生效"
4377
+ ].filter(Boolean);
4378
+ await replyText(event, lines.join("\n"));
4379
+ } catch (error) {
4380
+ ctx.logger.error(`[core] 安装失败: ${error}`);
4381
+ await replyText(event, `安装失败:${String(error)}`);
4382
+ }
4383
+ return;
4384
+ }
4385
+ const parsed = parseTargetArgs(args);
4386
+ if (!parsed) {
4387
+ await replyText(event, `用法:${ctx.config.prefix ?? "."}uninstall plugin <名称> 或 ${ctx.config.prefix ?? "."}uninstall service <名称>`);
3928
4388
  return;
3929
4389
  }
3930
- await replyText(event, `正在从 npm 安装${typeLabel(parsed$1.type)} ${parsed$1.name}...`);
4390
+ await replyText(event, `正在卸载${typeLabel(parsed.type)} ${parsed.name}...`);
3931
4391
  try {
3932
- const result = await installPackage(parsed$1.type, parsed$1.name);
4392
+ const result = await uninstallPackage(parsed.type, parsed.name);
3933
4393
  if (!result.ok) {
3934
- ctx.logger.error(`[core] 安装失败: ${result.error || result.output}`);
3935
- await replyText(event, `安装失败:${result.error || result.output}`);
4394
+ ctx.logger.error(`[core] 卸载失败: ${result.error || result.output}`);
4395
+ await replyText(event, `卸载失败:${result.error || result.output}`);
3936
4396
  return;
3937
4397
  }
3938
4398
  const lines = [
3939
- `已安装 ${result.packageName}`,
3940
- result.enabled ? "已在 plugins 中启用" : "",
4399
+ `已卸载 ${result.packageName}`,
4400
+ result.removedFromConfig ? "已从 plugins 中移除" : "",
3941
4401
  "重启后生效"
3942
4402
  ].filter(Boolean);
3943
4403
  await replyText(event, lines.join("\n"));
3944
4404
  } catch (error) {
3945
- ctx.logger.error(`[core] 安装失败: ${error}`);
3946
- await replyText(event, `安装失败:${String(error)}`);
4405
+ ctx.logger.error(`[core] 卸载失败: ${error}`);
4406
+ await replyText(event, `卸载失败:${String(error)}`);
3947
4407
  }
3948
- return;
3949
- }
3950
- const parsed = parseTargetArgs(text$1, uninstallHead);
3951
- if (!parsed) {
3952
- await replyText(event, `用法:${prefix}uninstall plugin <名称> 或 ${prefix}uninstall service <名称>`);
3953
- return;
3954
- }
3955
- await replyText(event, `正在卸载${typeLabel(parsed.type)} ${parsed.name}...`);
3956
- try {
3957
- const result = await uninstallPackage(parsed.type, parsed.name);
3958
- if (!result.ok) {
3959
- ctx.logger.error(`[core] 卸载失败: ${result.error || result.output}`);
3960
- await replyText(event, `卸载失败:${result.error || result.output}`);
3961
- return;
3962
- }
3963
- const lines = [
3964
- `已卸载 ${result.packageName}`,
3965
- result.removedFromConfig ? "已从 plugins 中移除" : "",
3966
- "重启后生效"
3967
- ].filter(Boolean);
3968
- await replyText(event, lines.join("\n"));
3969
- } catch (error) {
3970
- ctx.logger.error(`[core] 卸载失败: ${error}`);
3971
- await replyText(event, `卸载失败:${String(error)}`);
3972
4408
  }
3973
4409
  });
3974
- return dispose;
4410
+ const install = register("install");
4411
+ const uninstall = register("uninstall");
4412
+ return () => {
4413
+ install();
4414
+ uninstall();
4415
+ };
3975
4416
  }
3976
4417
 
3977
4418
  //#endregion
@@ -3985,64 +4426,76 @@ function renderMarketText(kind, items) {
3985
4426
  return [`Mioku ${label}市场(共 ${items.length} 个)`, ...lines].join("\n");
3986
4427
  }
3987
4428
  function registerMarketCommands(ctx) {
3988
- const dispose = ctx.handle("message", async (event) => {
3989
- const text$1 = ctx.text(event)?.trim();
3990
- if (!text$1 || event?.user_id === event?.self_id) return;
3991
- const prefix = getCommandPrefix();
3992
- const kind = text$1 === `${prefix}plugin-market` || text$1 === `${prefix}插件市场` ? "plugin" : text$1 === `${prefix}service-market` || text$1 === `${prefix}服务市场` ? "service" : null;
3993
- if (!kind) return;
3994
- if (!isEventOwner(event)) {
3995
- ctx.logger.warn("[core] market 指令仅主人可用");
3996
- return;
3997
- }
3998
- let items;
3999
- try {
4000
- items = await getMarketItems(kind);
4001
- } catch (error) {
4002
- ctx.logger.error(`[core] 获取市场信息失败: ${error}`);
4003
- await replyText(event, `获取市场失败:${String(error)}`);
4004
- return;
4005
- }
4006
- await sendTextOrForward({
4007
- ctx,
4008
- event,
4009
- text: renderMarketText(kind, items),
4010
- source: `Mioku ${kind === "plugin" ? "插件" : "服务"}市场`,
4011
- summary: `共 ${items.length} 个`
4012
- });
4429
+ const pluginMarket = ctx.command({
4430
+ id: "market",
4431
+ name: "plugin-market",
4432
+ aliases: ["插件市场"],
4433
+ permission: "master",
4434
+ priority: -1e3,
4435
+ description: "查看插件市场",
4436
+ handler: (input) => handleMarket(ctx, input.event, "plugin")
4437
+ });
4438
+ const serviceMarket = ctx.command({
4439
+ id: "market",
4440
+ name: "service-market",
4441
+ aliases: ["服务市场"],
4442
+ permission: "master",
4443
+ priority: -1e3,
4444
+ description: "查看服务市场",
4445
+ handler: (input) => handleMarket(ctx, input.event, "service")
4446
+ });
4447
+ return () => {
4448
+ pluginMarket();
4449
+ serviceMarket();
4450
+ };
4451
+ }
4452
+ async function handleMarket(ctx, event, kind) {
4453
+ let items;
4454
+ try {
4455
+ items = await getMarketItems(kind);
4456
+ } catch (error) {
4457
+ ctx.logger.error(`[core] 获取市场信息失败: ${error}`);
4458
+ await replyText(event, `获取市场失败:${String(error)}`);
4459
+ return;
4460
+ }
4461
+ await sendTextOrForward({
4462
+ ctx,
4463
+ event,
4464
+ text: renderMarketText(kind, items),
4465
+ source: `Mioku ${kind === "plugin" ? "插件" : "服务"}市场`,
4466
+ summary: `共 ${items.length} 个`
4013
4467
  });
4014
- return dispose;
4015
4468
  }
4016
4469
 
4017
4470
  //#endregion
4018
4471
  //#region src/builtin/core/commands/restart.ts
4019
4472
  function registerRestartCommand(ctx) {
4020
- const dispose = ctx.handle("message", async (event) => {
4021
- const text$1 = ctx.text(event)?.trim();
4022
- if (!text$1 || event?.user_id === event?.self_id) return;
4023
- const prefix = getCommandPrefix();
4024
- if (text$1 !== `${prefix}restart` && text$1 !== `${prefix}重启`) return;
4025
- if (!isEventOwner(event)) {
4026
- ctx.logger.warn("[core] restart 指令仅主人可用");
4027
- return;
4028
- }
4029
- const uptimeMs = process.uptime() * 1e3;
4030
- const selfId = Number(event?.self_id || 0);
4031
- const groupId = event?.message_type === "group" && event?.group_id ? Number(event.group_id) : null;
4032
- const userId = Number(event?.user_id || 0);
4033
- const marker = {
4034
- initiatedAt: Date.now(),
4035
- selfId,
4036
- groupId,
4037
- userId
4038
- };
4039
- try {
4040
- await replyText(event, `Bot已运行${formatUptime(uptimeMs)},正在重启...`);
4041
- } catch (error) {
4042
- ctx.logger.warn(`[core] 发送重启提示失败: ${error}`);
4473
+ const dispose = ctx.command({
4474
+ name: "restart",
4475
+ aliases: ["重启"],
4476
+ permission: "master",
4477
+ priority: -1e3,
4478
+ description: "重启机器人进程",
4479
+ handler: async ({ event }) => {
4480
+ if (event?.user_id === event?.self_id) return;
4481
+ const uptimeMs = process.uptime() * 1e3;
4482
+ const selfId = Number(event?.self_id || 0);
4483
+ const groupId = event?.message_type === "group" && event?.group_id ? Number(event.group_id) : null;
4484
+ const userId = Number(event?.user_id || 0);
4485
+ const marker = {
4486
+ initiatedAt: Date.now(),
4487
+ selfId,
4488
+ groupId,
4489
+ userId
4490
+ };
4491
+ try {
4492
+ await replyText(event, `Bot已运行${formatUptime(uptimeMs)},正在重启...`);
4493
+ } catch (error) {
4494
+ ctx.logger.warn(`[core] 发送重启提示失败: ${error}`);
4495
+ }
4496
+ ctx.logger.info(`[core] 正在执行重启命令 ${formatUptime(uptimeMs)}`);
4497
+ triggerRestart(marker);
4043
4498
  }
4044
- ctx.logger.info(`[core] 正在执行重启命令 ${formatUptime(uptimeMs)}`);
4045
- triggerRestart(marker);
4046
4499
  });
4047
4500
  return dispose;
4048
4501
  }
@@ -4080,63 +4533,63 @@ function chunk(arr, size) {
4080
4533
  return result;
4081
4534
  }
4082
4535
  function registerLogCommand(ctx) {
4083
- const dispose = ctx.handle("message", async (event) => {
4084
- const text$1 = ctx.text(event)?.trim();
4085
- if (!text$1 || event?.user_id === event?.self_id) return;
4086
- const prefix = getCommandPrefix();
4087
- if (text$1 !== `${prefix}log` && text$1 !== `${prefix}日志`) return;
4088
- if (!isEventOwner(event)) {
4089
- ctx.logger.warn("[core] 日志指令仅主人可用");
4090
- return;
4091
- }
4092
- const selfId = String(event?.self_id || "");
4093
- const bot = event.bot;
4094
- if (!bot) return;
4095
- const logFile = getActiveLogFile();
4096
- if (!logFile) {
4097
- await replyText(event, "未找到日志文件。");
4098
- return;
4099
- }
4100
- let lines;
4101
- try {
4102
- lines = readLastLines(logFile, LOG_LINE_COUNT);
4103
- } catch (error) {
4104
- ctx.logger.error(`[core] 读取日志失败: ${error}`);
4105
- await replyText(event, `读取日志失败:${String(error)}`);
4106
- return;
4107
- }
4108
- if (lines.length === 0) {
4109
- await replyText(event, "日志为空。");
4110
- return;
4111
- }
4112
- let infoCount = 0;
4113
- let warnCount = 0;
4114
- let errorCount = 0;
4115
- for (const line of lines) if (/\bERROR\b|\berror\b/i.test(line)) errorCount++;
4116
- else if (/\bWARN\b|\bwarn\b/i.test(line)) warnCount++;
4117
- else if (/\bINFO\b|\binfo\b/i.test(line)) infoCount++;
4118
- const summary = `info ${infoCount} warn ${warnCount} error ${errorCount}`;
4119
- const chunks = chunk(lines, LINES_PER_NODE);
4120
- const nodes = chunks.map((chunkLines, idx) => ({
4121
- user_id: selfId,
4122
- nickname: `第${idx + 1}条日志`,
4123
- content: [ctx.segment.text(chunkLines.join("\n"))]
4124
- }));
4125
- try {
4126
- const target = event?.message_type === "group" && event?.group_id ? {
4127
- type: "group",
4128
- group_id: event.group_id
4129
- } : event?.user_id ? {
4130
- type: "private",
4131
- user_id: event.user_id
4132
- } : void 0;
4133
- if (target) await bot.sendForward(target, nodes, {
4134
- source: "最近100条运行日志",
4135
- summary
4136
- });
4137
- } catch (error) {
4138
- ctx.logger.error(`[core] 发送日志转发失败: ${error}`);
4139
- await replyText(event, `发送日志失败:${String(error)}`);
4536
+ const dispose = ctx.command({
4537
+ name: "log",
4538
+ aliases: ["日志"],
4539
+ permission: "master",
4540
+ priority: -1e3,
4541
+ description: "查看最近100条日志",
4542
+ handler: async ({ event }) => {
4543
+ if (event?.user_id === event?.self_id) return;
4544
+ const selfId = String(event?.self_id || "");
4545
+ const bot = event.bot;
4546
+ if (!bot) return;
4547
+ const logFile = getActiveLogFile();
4548
+ if (!logFile) {
4549
+ await replyText(event, "未找到日志文件。");
4550
+ return;
4551
+ }
4552
+ let lines;
4553
+ try {
4554
+ lines = readLastLines(logFile, LOG_LINE_COUNT);
4555
+ } catch (error) {
4556
+ ctx.logger.error(`[core] 读取日志失败: ${error}`);
4557
+ await replyText(event, `读取日志失败:${String(error)}`);
4558
+ return;
4559
+ }
4560
+ if (lines.length === 0) {
4561
+ await replyText(event, "日志为空。");
4562
+ return;
4563
+ }
4564
+ let infoCount = 0;
4565
+ let warnCount = 0;
4566
+ let errorCount = 0;
4567
+ for (const line of lines) if (/\bERROR\b|\berror\b/i.test(line)) errorCount++;
4568
+ else if (/\bWARN\b|\bwarn\b/i.test(line)) warnCount++;
4569
+ else if (/\bINFO\b|\binfo\b/i.test(line)) infoCount++;
4570
+ const summary = `info ${infoCount} warn ${warnCount} error ${errorCount}`;
4571
+ const chunks = chunk(lines, LINES_PER_NODE);
4572
+ const nodes = chunks.map((chunkLines, idx) => ({
4573
+ user_id: selfId,
4574
+ nickname: `第${idx + 1}条日志`,
4575
+ content: [ctx.segment.text(chunkLines.join("\n"))]
4576
+ }));
4577
+ try {
4578
+ const target = event?.message_type === "group" && event?.group_id ? {
4579
+ type: "group",
4580
+ group_id: event.group_id
4581
+ } : event?.user_id ? {
4582
+ type: "private",
4583
+ user_id: event.user_id
4584
+ } : void 0;
4585
+ if (target) await bot.sendForward(target, nodes, {
4586
+ source: "最近100条运行日志",
4587
+ summary
4588
+ });
4589
+ } catch (error) {
4590
+ ctx.logger.error(`[core] 发送日志转发失败: ${error}`);
4591
+ await replyText(event, `发送日志失败:${String(error)}`);
4592
+ }
4140
4593
  }
4141
4594
  });
4142
4595
  return dispose;
@@ -4363,7 +4816,6 @@ const core = definePlugin({
4363
4816
  description: "mioku 内置核心插件",
4364
4817
  async setup(ctx) {
4365
4818
  const rawPrefix = ctx.config.prefix ?? ".";
4366
- const cmdPrefix = new RegExp(`^${escapeRegExp(rawPrefix)}`);
4367
4819
  const displayPrefix = rawPrefix;
4368
4820
  const statusAdminOnly = ctx.config.status_permission === "admin-only";
4369
4821
  rootLogger.info("========================================");
@@ -4381,12 +4833,17 @@ const core = definePlugin({
4381
4833
  }));
4382
4834
  } else ctx.logger.warn("config-service 未加载,core 插件将使用默认配置");
4383
4835
  let accessRules = ensureAccessControlConfig();
4836
+ ctx.commands.setAccessControl(accessRules);
4384
4837
  if (configService) {
4385
4838
  await configService.registerConfig("core", "access-control", accessRules);
4386
4839
  const persisted = await configService.getConfig("core", "access-control");
4387
- if (persisted) accessRules = normalizeAccessConfig(persisted);
4840
+ if (persisted) {
4841
+ accessRules = normalizeAccessConfig(persisted);
4842
+ ctx.commands.setAccessControl(accessRules);
4843
+ }
4388
4844
  disposers.push(configService.onConfigChange("core", "access-control", (next) => {
4389
4845
  accessRules = normalizeAccessConfig(next);
4846
+ ctx.commands.setAccessControl(accessRules);
4390
4847
  }));
4391
4848
  }
4392
4849
  rootLogger.info(`访问控制已挂载: ${ctx.bots.length} 个 bot`);
@@ -4448,17 +4905,49 @@ const core = definePlugin({
4448
4905
  bots: collectBots(),
4449
4906
  adapters: collectAdapters()
4450
4907
  }));
4908
+ ctx.command({
4909
+ name: "help",
4910
+ aliases: ["帮助"],
4911
+ permission: "master",
4912
+ priority: -1e3,
4913
+ description: "显示帮助信息",
4914
+ handler: async ({ event }) => {
4915
+ await event.reply(buildCoreHelpText(displayPrefix));
4916
+ }
4917
+ });
4918
+ ctx.command({
4919
+ name: "status",
4920
+ aliases: ["状态"],
4921
+ priority: -1e3,
4922
+ description: "显示框架状态",
4923
+ handler: async ({ event }) => {
4924
+ if (statusAdminOnly && !isEventOwnerOrAdmin(event)) return;
4925
+ await event.reply(await formatMiokuStatus(await getStatus()));
4926
+ }
4927
+ });
4928
+ ctx.command({
4929
+ name: "adapter",
4930
+ aliases: ["适配器"],
4931
+ priority: -1e3,
4932
+ description: "显示适配器与连接实例",
4933
+ handler: async ({ event }) => {
4934
+ if (statusAdminOnly && !isEventOwnerOrAdmin(event)) return;
4935
+ await event.reply(await getAdapterText());
4936
+ }
4937
+ });
4451
4938
  const atTarget = (event) => {
4452
4939
  const at = event.message.find((seg) => seg.type === "at");
4453
4940
  const qq = at?.data?.qq ?? at?.data?.target;
4454
4941
  return qq != null ? String(qq) : void 0;
4455
4942
  };
4456
- disposers.push(ctx.handle("message", async (event) => {
4943
+ const handleCoreMessage = async (event) => {
4457
4944
  const ev = event;
4458
4945
  const text$1 = ev.message.text();
4459
- if (!cmdPrefix.test(text$1)) return;
4946
+ const currentPrefix = String(ctx.config.prefix ?? ".");
4947
+ const currentCmdPrefix = new RegExp(`^${escapeRegExp(currentPrefix)}`);
4948
+ if (!currentCmdPrefix.test(text$1)) return;
4460
4949
  if (statusAdminOnly && !isEventOwnerOrAdmin(ev)) return;
4461
- const bare = text$1.replace(cmdPrefix, "").trim();
4950
+ const bare = text$1.replace(currentCmdPrefix, "").trim();
4462
4951
  if (bare === "状态" || bare === "status") {
4463
4952
  await ev.reply(await formatMiokuStatus(await getStatus()));
4464
4953
  return;
@@ -4467,10 +4956,10 @@ const core = definePlugin({
4467
4956
  await ev.reply(await getAdapterText());
4468
4957
  return;
4469
4958
  }
4470
- if (!isEventOwner(ev)) return;
4959
+ if (!isEventMaster(ev)) return;
4471
4960
  const { cmd, params } = createCmd(text$1);
4472
4961
  if (!cmd) return;
4473
- const subCmd = cmd.replace(cmdPrefix, "").replace(/\s+/g, "");
4962
+ const subCmd = cmd.replace(currentCmdPrefix, "").replace(/\s+/g, "");
4474
4963
  const target = params[0];
4475
4964
  switch (subCmd) {
4476
4965
  case "help":
@@ -4692,7 +5181,29 @@ const core = definePlugin({
4692
5181
  process.exit(0);
4693
5182
  }
4694
5183
  }
4695
- }));
5184
+ };
5185
+ for (const command of [
5186
+ {
5187
+ name: "plugin",
5188
+ aliases: ["插件"],
5189
+ description: "插件管理"
5190
+ },
5191
+ {
5192
+ name: "settings",
5193
+ aliases: ["设置"],
5194
+ description: "框架设置管理"
5195
+ },
5196
+ {
5197
+ name: "exit",
5198
+ aliases: ["退出"],
5199
+ description: "退出框架进程"
5200
+ }
5201
+ ]) ctx.command({
5202
+ ...command,
5203
+ permission: "master",
5204
+ priority: -1e3,
5205
+ handler: ({ event }) => handleCoreMessage(event)
5206
+ });
4696
5207
  rootLogger.info("========================================");
4697
5208
  rootLogger.info(" Mioku 服务初始化完成");
4698
5209
  rootLogger.info("========================================");
@@ -5100,6 +5611,7 @@ var MiokuRuntime = class {
5100
5611
  #driverFactory;
5101
5612
  #builtinPlugins;
5102
5613
  #correlator;
5614
+ #commands;
5103
5615
  #started = false;
5104
5616
  #stopped = false;
5105
5617
  constructor(options) {
@@ -5117,6 +5629,14 @@ var MiokuRuntime = class {
5117
5629
  });
5118
5630
  this.#bots = new BotRegistry();
5119
5631
  this.#capabilities = new CapabilityRegistry();
5632
+ this.#commands = new CommandManager({
5633
+ getDefaultPrefix: () => String(botConfig.prefix ?? "."),
5634
+ getOwners: () => botConfig.owners,
5635
+ getAdmins: () => botConfig.admins,
5636
+ logger: this.#logger
5637
+ });
5638
+ this.#bus.setFilter((registration, event) => this.#commands.shouldDispatch(registration.source, event));
5639
+ setActiveCommandManager(this.#commands);
5120
5640
  }
5121
5641
  get cwd() {
5122
5642
  return this.#cwd;
@@ -5130,6 +5650,9 @@ var MiokuRuntime = class {
5130
5650
  get bus() {
5131
5651
  return this.#bus;
5132
5652
  }
5653
+ get commands() {
5654
+ return this.#commands;
5655
+ }
5133
5656
  /** 事件关联器(跨适配器去重);为 undefined 时表示已禁用 */
5134
5657
  get correlator() {
5135
5658
  return this.#correlator;
@@ -5148,14 +5671,16 @@ var MiokuRuntime = class {
5148
5671
  return this.#bots.pick(bot_id);
5149
5672
  }
5150
5673
  listPlugins() {
5151
- return Array.from(this.#enabledPlugins.entries()).map(([key, entry]) => {
5674
+ return Array.from(this.#enabledPlugins.entries()).map(([key]) => {
5152
5675
  const colon = key.indexOf(":");
5153
5676
  const type = key.slice(0, colon);
5154
5677
  const name = key.slice(colon + 1);
5678
+ const isExternal = type !== "builtin";
5679
+ const version$2 = isExternal ? getPluginMetadata(name)?.version : void 0;
5155
5680
  return {
5156
5681
  name,
5157
5682
  type: type === "builtin" ? "builtin" : "external",
5158
- version: entry.plugin.version
5683
+ version: version$2
5159
5684
  };
5160
5685
  });
5161
5686
  }
@@ -5242,13 +5767,16 @@ var MiokuRuntime = class {
5242
5767
  capabilities: this.#capabilities,
5243
5768
  logger: this.#logger.child({ adapter: state.definition.name }),
5244
5769
  emit: (event) => this.#emitLifecycle(event),
5245
- correlator: this.#correlator
5770
+ correlator: this.#correlator,
5771
+ commands: this.#commands
5246
5772
  });
5247
5773
  }
5248
5774
  async #loadPlugin(plugin, type) {
5249
5775
  const cleanupTasks = [];
5250
5776
  const ctx = new MiokuContext({
5251
5777
  pluginName: `${type}:${plugin.name}`,
5778
+ pluginId: plugin.name === "mioku-core" ? "core" : plugin.name,
5779
+ commands: this.#commands,
5252
5780
  bus: this.#bus,
5253
5781
  bots: this.#bots,
5254
5782
  driver: this.#driver,
@@ -5546,6 +6074,8 @@ var MiokuRuntime = class {
5546
6074
  this.#capabilities.clear();
5547
6075
  this.#bots.clear();
5548
6076
  this.#correlator?.clear();
6077
+ this.#commands.clear();
6078
+ setActiveCommandManager(void 0);
5549
6079
  resetPluginMetadata();
5550
6080
  try {
5551
6081
  await this.#driver.shutdown();
@@ -5562,22 +6092,38 @@ const createRuntime = (options) => {
5562
6092
 
5563
6093
  //#endregion
5564
6094
  //#region src/runtime/plugin-artifacts.ts
6095
+ const commandKey = (value) => String(value).trim().replace(/^[#/.]+\s*/, "").split(/\s+/)[0].toLowerCase();
5565
6096
  async function registerPluginArtifacts(ctx) {
5566
6097
  const helpService = ctx ? getService(ctx, Services.Help) : servicesRegistry["help"];
5567
6098
  const plugins = getPluginMetadataList();
6099
+ const commandManager = getActiveCommandManager();
6100
+ const metadataByName = new Map(plugins.map((meta) => [meta.name, meta]));
6101
+ const pluginNames = new Set([...metadataByName.keys(), ...(commandManager?.catalog() ?? []).filter((item) => item.kind === "plugin").map((item) => item.plugin)]);
5568
6102
  let helpCount = 0;
5569
- for (const meta of plugins) {
5570
- if (meta.config?.help) if (helpService) {
5571
- helpService.registerHelp(meta.name, meta.config.help);
6103
+ for (const pluginName of pluginNames) {
6104
+ const meta = metadataByName.get(pluginName);
6105
+ const generated = commandManager?.getPluginHelp(pluginName) ?? meta?.config?.help;
6106
+ const existing = helpService?.getHelp(pluginName);
6107
+ const help = generated ? {
6108
+ ...generated,
6109
+ title: existing?.title || generated.title,
6110
+ description: existing?.description || generated.description,
6111
+ commands: [...existing?.commands ?? [], ...generated.commands.filter((command) => {
6112
+ const key = commandKey(command.cmd);
6113
+ return !(existing?.commands ?? []).some((item) => commandKey(item.cmd) === key);
6114
+ })]
6115
+ } : existing;
6116
+ if (help) if (helpService) {
6117
+ helpService.registerHelp(pluginName, help);
5572
6118
  helpCount++;
5573
- } else rootLogger.warn(`[plugin-artifacts] 帮助服务未加载,跳过插件 "${meta.name}" 的帮助注册`);
5574
- const required = meta.config?.services;
6119
+ } else rootLogger.warn(`[plugin-artifacts] 帮助服务未加载,跳过插件 "${pluginName}" 的帮助注册`);
6120
+ const required = meta?.config?.services;
5575
6121
  if (required && required.length > 0) {
5576
6122
  const missing = required.filter((name) => !servicesRegistry[name]);
5577
- if (missing.length > 0) rootLogger.warn(`插件 "${meta.name}" 声明依赖服务 [${missing.join(", ")}],但它们未加载`);
6123
+ if (missing.length > 0) rootLogger.warn(`插件 "${pluginName}" 声明依赖服务 [${missing.join(", ")}],但它们未加载`);
5578
6124
  }
5579
6125
  }
5580
- rootLogger.info(`[plugin-artifacts] 已处理 ${plugins.length} 个插件的元数据,注册帮助 ${helpCount} 个`);
6126
+ rootLogger.info(`[plugin-artifacts] 已处理 ${pluginNames.size} 个插件,注册帮助 ${helpCount} 个`);
5581
6127
  }
5582
6128
 
5583
6129
  //#endregion
@@ -5732,5 +6278,5 @@ function installProcessErrorGuards() {
5732
6278
  }
5733
6279
 
5734
6280
  //#endregion
5735
- export { AI_GEMINI_THINKING_LEVELS, AI_THINKING_LEVELS, AdapterContextImpl, AdapterRegistrationConflictError, ArchMap, BOT_CWD, BUILTIN_PLUGINS, BotRegistry, CORE_PLUGINS, CapabilityRegistry, ChromeUA, DriverShutdownError, EventBus, EventCorrelator, HttpRequestError, MessageSegmentImpl, MiokuContext, MiokuRuntime, ServiceManager, Services, SystemMap, TOOL_RESULT_FOLLOWUP_KEY, UnsupportedCapabilityError, WebSocketConnectTimeoutError, addService, applyLogLevel, asMessage, atOf, avatarGet, avatarSet, base64Decode, base64Encode, bindCapabilities, botConfig, botStatus, box, buildAdapterReport, buildMiokuStatus, buildRoutes, buildSpawnPlan, clamp, collectBotStats, colorize, colors, commandExists, connectedBotKey, connectedBots, conversationGetHistory, createCmd, createDB, createDefaultDriver, createFriendRef, createGroupRef, createImportContext, createMessage, createMiokuLogger, createRuntime, createStore, dayjs, dedent, defineAdapter, defineCapability, definePlugin, defineService, defineState, deleteServiceConfig, discoverAdapterCandidates, discoverPluginCandidates, displayAdapterId, ensureDataDir, filesize, filter, find, findLocalPlugins, formatAdapterReport, formatDuration, formatMiokuStatus, formatMiokuStatusFn, forwardSend, friendDelete, friendGetInfo, friendGetList, fs, getAllPluginRuntimeStates, getBuiltinPlugins, getConfigDir, getDataDir, getGTk, getPluginConfigDir, getPluginDataDir, getPluginMetadata, getPluginMetadataList, getPluginRuntimeState, getService, getServiceConfig, getServiceConfigDir, getServiceConfigs, getServiceDataDir, getTerminalInput, groupGetInfo, groupGetList, groupGetMembers, groupLeave, groupSetName, groupSetPortrait, groupSetWholeBan, hasEventRight, hasPluginState, hasRight, hasService, isAdapterEvent, isAdmin, isBoolean, isBotEvent, isDefined, isEventAdmin, isEventOwner, isEventOwnerOrAdmin, isFunction, isMessage, isMessageEvent, isMetaEvent, isMiokuPlugin, isNoticeEvent, isNumber, isObject, isOwner, isOwnerOrAdmin, isRequestEvent, isSegment, isString, loadAdapterDefinition, loadLocalPlugin, loadNpmPlugin, localNum, localeDate, localeTime, rootLogger as logger, match, md5, memberBan, memberGetInfo, memberKick, memberPoke, memberSetAdmin, memberSetCard, memberSetTitle, messageGet, messageGetForward, messageRecall, messageSend, mriLib as mri, noNullish, normalizeAIThinkingLevel, normalizeAdmins, normalizeOwners, normalizePlugins, normalizeSkillPermissionRole, noticeAdmins, noticeFriends, noticeGroups, noticeOwners, path, prettyMs, profileSet, qs, randomId, randomInt, randomItem, randomItems, readMiokuConfig, readPackageJson, readPackageJsonSafe, registerPluginArtifacts, registerServiceConfig, registerStatusProvider, reloadMiokuConfig, removePluginMetadata, requireService, resetPluginMetadata, resetPluginRuntimeState, resolveCommand, resolveEntry, resolveLocalPluginEntry, resolveLocalPluginPath, rootLogger, runCommand, runCommandInherit, segment, sendMessage, manager_default as serviceManager, servicesRegistry, setBotCwd, setBuiltinPlugins, setPluginMetadata, setPluginRuntimeState, setService, setWritableConfig, start, startRuntime, string2argv, stringifyError, stripAnsi, text, toArray, toId, toUserId, unique, updateMiokuConfig, updateServiceConfig, uuid, version$1 as version, wait, writePackageJson };
6281
+ export { AI_GEMINI_THINKING_LEVELS, AI_THINKING_LEVELS, AdapterContextImpl, AdapterRegistrationConflictError, ArchMap, BOT_CWD, BUILTIN_PLUGINS, BotRegistry, CORE_PLUGINS, CapabilityRegistry, ChromeUA, CommandManager, DriverShutdownError, EventBus, EventCorrelator, HttpRequestError, MessageSegmentImpl, MiokuContext, MiokuRuntime, ServiceManager, Services, SystemMap, TOOL_RESULT_FOLLOWUP_KEY, UnsupportedCapabilityError, WebSocketConnectTimeoutError, addService, applyLogLevel, asMessage, atOf, avatarGet, avatarSet, base64Decode, base64Encode, bindCapabilities, botConfig, botStatus, box, buildAdapterReport, buildMiokuStatus, buildRoutes, buildSpawnPlan, clamp, collectBotStats, colorize, colors, commandExists, connectedBotKey, connectedBots, conversationGetHistory, createCmd, createDB, createDefaultDriver, createFriendRef, createGroupRef, createImportContext, createMessage, createMiokuLogger, createRuntime, createStore, dayjs, dedent, defineAdapter, defineCapability, definePlugin, defineService, defineState, deleteServiceConfig, discoverAdapterCandidates, discoverPluginCandidates, displayAdapterId, ensureDataDir, filesize, filter, find, findLocalPlugins, formatAdapterReport, formatDuration, formatMiokuStatus, formatMiokuStatusFn, forwardSend, friendDelete, friendGetInfo, friendGetList, fs, getActiveCommandManager, getAllPluginRuntimeStates, getBuiltinPlugins, getConfigDir, getDataDir, getGTk, getPluginConfigDir, getPluginDataDir, getPluginMetadata, getPluginMetadataList, getPluginRuntimeState, getService, getServiceConfig, getServiceConfigDir, getServiceConfigs, getServiceDataDir, getTerminalInput, groupGetInfo, groupGetList, groupGetMembers, groupLeave, groupSetName, groupSetPortrait, groupSetWholeBan, hasEventRight, hasPluginState, hasRight, hasService, isAdapterEvent, isAdmin, isBoolean, isBotEvent, isDefined, isEventAdmin, isEventAdminConfigOnly, isEventGroupAdmin, isEventGroupOwner, isEventMaster, isEventOwner, isEventOwnerOrAdmin, isFunction, isMessage, isMessageEvent, isMetaEvent, isMiokuPlugin, isNoticeEvent, isNumber, isObject, isOwner, isOwnerOrAdmin, isRequestEvent, isSegment, isString, loadAdapterDefinition, loadLocalPlugin, loadNpmPlugin, localNum, localeDate, localeTime, rootLogger as logger, match, md5, memberBan, memberGetInfo, memberKick, memberPoke, memberSetAdmin, memberSetCard, memberSetTitle, messageGet, messageGetForward, messageRecall, messageSend, mriLib as mri, noNullish, normalizeAIThinkingLevel, normalizeAdmins, normalizeOwners, normalizePlugins, normalizeSkillPermissionRole, noticeAdmins, noticeFriends, noticeGroups, noticeOwners, path, prettyMs, profileSet, qs, randomId, randomInt, randomItem, randomItems, readMiokuConfig, readPackageJson, readPackageJsonSafe, registerPluginArtifacts, registerServiceConfig, registerStatusProvider, reloadMiokuConfig, removePluginMetadata, requireService, resetPluginMetadata, resetPluginRuntimeState, resolveCommand, resolveEntry, resolveLocalPluginEntry, resolveLocalPluginPath, rootLogger, runCommand, runCommandInherit, segment, sendMessage, manager_default as serviceManager, servicesRegistry, setActiveCommandManager, setBotCwd, setBuiltinPlugins, setPluginMetadata, setPluginRuntimeState, setService, setWritableConfig, start, startRuntime, string2argv, stringifyError, stripAnsi, text, toArray, toId, toUserId, unique, updateMiokuConfig, updateServiceConfig, uuid, version$1 as version, wait, writePackageJson };
5736
6282
  //# sourceMappingURL=index.js.map