koishi-plugin-onebot-group-manage 0.0.6 → 0.0.8

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/lib/index.js CHANGED
@@ -31,11 +31,10 @@ var import_koishi = require("koishi");
31
31
  var import_tools = require("@langchain/core/tools");
32
32
  var import_zod = require("zod");
33
33
  var GroupMuteTool = class extends import_tools.StructuredTool {
34
- constructor(ctx, handlers, config, logger, logVerbose) {
34
+ constructor(ctx, handlers, logger, logVerbose) {
35
35
  super();
36
36
  this.ctx = ctx;
37
37
  this.handlers = handlers;
38
- this.config = config;
39
38
  this.logger = logger;
40
39
  this.logVerbose = logVerbose;
41
40
  }
@@ -43,11 +42,11 @@ var GroupMuteTool = class extends import_tools.StructuredTool {
43
42
  __name(this, "GroupMuteTool");
44
43
  }
45
44
  name = "group_mute";
46
- description = "在群内禁言成员";
45
+ description = "在群内禁言成员,duration为0表示取消禁言";
47
46
  schema = import_zod.z.object({
48
- groupId: import_zod.z.string().trim().min(1).describe("目标群号,不填则使用当前会话群").optional(),
49
- userId: import_zod.z.string().trim().min(1).describe("要禁言的成员 QQ 号"),
50
- duration: import_zod.z.number().int().positive().describe("禁言时长(秒)")
47
+ groupId: import_zod.z.string().describe("目标群号,不填则使用当前会话群").optional(),
48
+ userId: import_zod.z.string().describe("要禁言的成员 QQ 号"),
49
+ duration: import_zod.z.number().int().min(0).describe("禁言时长(秒)")
51
50
  });
52
51
  async _call(input, _runManager, runnableConfig) {
53
52
  const session = runnableConfig?.configurable?.session;
@@ -57,7 +56,6 @@ var GroupMuteTool = class extends import_tools.StructuredTool {
57
56
  this.ctx,
58
57
  session,
59
58
  { targetId: input.userId, duration: input.duration, guildId: input.groupId },
60
- this.config,
61
59
  this.logger,
62
60
  this.logVerbose
63
61
  );
@@ -69,11 +67,10 @@ var GroupMuteTool = class extends import_tools.StructuredTool {
69
67
  }
70
68
  };
71
69
  var GroupTitleTool = class extends import_tools.StructuredTool {
72
- constructor(ctx, handlers, config, logger, logVerbose) {
70
+ constructor(ctx, handlers, logger, logVerbose) {
73
71
  super();
74
72
  this.ctx = ctx;
75
73
  this.handlers = handlers;
76
- this.config = config;
77
74
  this.logger = logger;
78
75
  this.logVerbose = logVerbose;
79
76
  }
@@ -83,9 +80,9 @@ var GroupTitleTool = class extends import_tools.StructuredTool {
83
80
  name = "group_set_title";
84
81
  description = "为成员设置群头衔(需群主权限)";
85
82
  schema = import_zod.z.object({
86
- groupId: import_zod.z.string().trim().min(1).describe("目标群号,不填则使用当前会话群").optional(),
87
- userId: import_zod.z.string().trim().min(1).describe("要设置头衔的成员 QQ 号"),
88
- title: import_zod.z.string().trim().min(1).describe("头衔文案")
83
+ groupId: import_zod.z.string().describe("目标群号,不填则使用当前会话群").optional(),
84
+ userId: import_zod.z.string().describe("要设置头衔的成员 QQ 号"),
85
+ title: import_zod.z.string().describe("头衔文案")
89
86
  });
90
87
  async _call(input, _runManager, runnableConfig) {
91
88
  const session = runnableConfig?.configurable?.session;
@@ -95,7 +92,6 @@ var GroupTitleTool = class extends import_tools.StructuredTool {
95
92
  this.ctx,
96
93
  session,
97
94
  { targetId: input.userId, title: input.title, guildId: input.groupId },
98
- this.config,
99
95
  this.logger,
100
96
  this.logVerbose
101
97
  );
@@ -106,7 +102,7 @@ var GroupTitleTool = class extends import_tools.StructuredTool {
106
102
  }
107
103
  }
108
104
  };
109
- function registerChatlunaTools(ctx, config, logger, verbose, handlers) {
105
+ function registerChatlunaTools(ctx, _config, logger, verbose, handlers) {
110
106
  const platform = ctx.chatluna?.platform;
111
107
  if (!platform) {
112
108
  logger.debug("chatluna 未安装,跳过群管工具注册");
@@ -114,13 +110,13 @@ function registerChatlunaTools(ctx, config, logger, verbose, handlers) {
114
110
  }
115
111
  ctx.effect(
116
112
  () => platform.registerTool("group_mute", {
117
- createTool: /* @__PURE__ */ __name(() => new GroupMuteTool(ctx, handlers, config, logger, verbose), "createTool"),
113
+ createTool: /* @__PURE__ */ __name(() => new GroupMuteTool(ctx, handlers, logger, verbose), "createTool"),
118
114
  selector: /* @__PURE__ */ __name(() => true, "selector")
119
115
  })
120
116
  );
121
117
  ctx.effect(
122
118
  () => platform.registerTool("group_set_title", {
123
- createTool: /* @__PURE__ */ __name(() => new GroupTitleTool(ctx, handlers, config, logger, verbose), "createTool"),
119
+ createTool: /* @__PURE__ */ __name(() => new GroupTitleTool(ctx, handlers, logger, verbose), "createTool"),
124
120
  selector: /* @__PURE__ */ __name(() => true, "selector")
125
121
  })
126
122
  );
@@ -351,24 +347,26 @@ function randomInt(min, max) {
351
347
  return Math.floor(Math.random() * (max - min + 1)) + min;
352
348
  }
353
349
  __name(randomInt, "randomInt");
354
- async function performMute(ctx, session, params, config, logger, verbose) {
350
+ async function performMute(ctx, session, params, logger, verbose) {
355
351
  const guildId = params.guildId ?? session.guildId;
356
352
  if (!guildId) return "仅限群聊使用";
357
353
  const targetId = params.targetId ?? parseTargetId(params.targetRaw || "", session);
358
354
  if (!targetId) return "请提供要禁言的用户(@ 或 QQ 号)";
359
355
  const seconds = Number(params.duration);
360
- if (!Number.isFinite(seconds) || seconds <= 0) return "禁言时长必须为大于 0 的整数(秒)";
361
- const msg = await verifyCaller(session, config.mute, logger, verbose, guildId);
362
- if (msg) return msg;
356
+ if (!Number.isFinite(seconds) || seconds < 0) return "禁言时长必须为大于等于 0 的整数(秒)";
363
357
  verbose && logger.info(
364
358
  `mute: guild=${guildId} caller=${session.userId} bot=${botKey(session.bot)} target=${targetId} seconds=${seconds}`
365
359
  );
366
- const picked = await pickManageBot(ctx, guildId, false, logger, session.bot, verbose, session.onebot);
367
- if (!picked) return "没有可用且有群管权限的 Bot";
368
- const targetRole = await getMemberRole(picked.probeOnebot, picked.bot, guildId, targetId, logger, verbose);
360
+ const probeOnebot = session.onebot || getBotOnebot(session.bot);
361
+ const targetRole = await getMemberRole(probeOnebot, session.bot, guildId, targetId, logger, verbose);
369
362
  if (targetRole === "owner") return "无法对群主执行该操作";
363
+ const requireOwner = targetRole === "admin";
364
+ const picked = await pickManageBot(ctx, guildId, requireOwner, logger, session.bot, verbose, probeOnebot);
365
+ if (!picked) {
366
+ return requireOwner ? "目标是管理员,需要群主权限的 Bot,但没有可用" : "没有可用且有群管权限的 Bot";
367
+ }
370
368
  const actionOnebot = getBotOnebot(picked.bot);
371
- if (!actionOnebot) return "选中的 Bot 缺少 onebot 实例,无法执行";
369
+ if (!actionOnebot) return "失败:选中的 Bot 缺少 onebot 实例,无法执行";
372
370
  try {
373
371
  verbose && logger.info(`mute: use bot=${botKey(picked.bot)} role=${picked.role} duration=${seconds}`);
374
372
  if (typeof actionOnebot.setGroupBan === "function") {
@@ -381,29 +379,33 @@ async function performMute(ctx, session, params, config, logger, verbose) {
381
379
  });
382
380
  }
383
381
  roleCache.clear();
384
- return `已使用 ${picked.bot.selfId} 禁言 ${targetId} ${seconds} 秒`;
382
+ const targetRoleStr = targetRole ? `(${targetRole})` : "";
383
+ if (seconds === 0) {
384
+ return `成功:使用 ${picked.bot.selfId}(${picked.role})解除 ${targetId}${targetRoleStr} 的禁言`;
385
+ }
386
+ return `成功:使用 ${picked.bot.selfId}(${picked.role})禁言 ${targetId}${targetRoleStr} ${seconds} 秒`;
385
387
  } catch (error) {
386
388
  logger.warn(error);
387
- return "禁言失败,检查 Bot 权限或参数";
389
+ return `失败:禁言操作出错,Bot=${picked.bot.selfId}(${picked.role}),目标=${targetId}(${targetRole || "unknown"})`;
388
390
  }
389
391
  }
390
392
  __name(performMute, "performMute");
391
- async function performTitle(ctx, session, params, config, logger, verbose) {
393
+ async function performTitle(ctx, session, params, logger, verbose) {
392
394
  const guildId = params.guildId ?? session.guildId;
393
395
  if (!guildId) return "仅限群聊使用";
394
396
  const title = params.title?.trim();
395
397
  if (!title) return "请提供要设置的头衔";
396
398
  const userId = params.targetId ?? parseTargetId(params.targetRaw || "", session);
397
399
  if (!userId) return "请提供要设置头衔的用户(@ 或 QQ 号)";
398
- const msg = await verifyCaller(session, config.title, logger, verbose, guildId);
399
- if (msg) return msg;
400
400
  verbose && logger.info(
401
401
  `title: guild=${guildId} caller=${session.userId} bot=${botKey(session.bot)} target=${userId} title=${title}`
402
402
  );
403
- const picked = await pickManageBot(ctx, guildId, true, logger, session.bot, verbose, session.onebot);
404
- if (!picked) return "没有具备群主权限的 Bot 可用";
403
+ const probeOnebot = session.onebot || getBotOnebot(session.bot);
404
+ const targetRole = await getMemberRole(probeOnebot, session.bot, guildId, userId, logger, verbose);
405
+ const picked = await pickManageBot(ctx, guildId, true, logger, session.bot, verbose, probeOnebot);
406
+ if (!picked) return "失败:没有具备群主权限的 Bot 可用";
405
407
  const actionOnebot = getBotOnebot(picked.bot);
406
- if (!actionOnebot) return "选中的 Bot 缺少 onebot 实例,无法执行";
408
+ if (!actionOnebot) return "失败:选中的 Bot 缺少 onebot 实例,无法执行";
407
409
  try {
408
410
  verbose && logger.info(`title: use bot=${botKey(picked.bot)} role=${picked.role}`);
409
411
  if (typeof actionOnebot.setGroupSpecialTitle === "function") {
@@ -417,10 +419,11 @@ async function performTitle(ctx, session, params, config, logger, verbose) {
417
419
  });
418
420
  }
419
421
  roleCache.clear();
420
- return `已使用 ${picked.bot.selfId} ${userId} 设置头衔:${title}`;
422
+ const targetRoleStr = targetRole ? `(${targetRole})` : "";
423
+ return `成功:使用 ${picked.bot.selfId}(${picked.role})为 ${userId}${targetRoleStr} 设置头衔「${title}」`;
421
424
  } catch (error) {
422
425
  logger.warn(error);
423
- return "设置头衔失败,检查 Bot 权限或参数";
426
+ return `失败:设置头衔出错,Bot=${picked.bot.selfId}(${picked.role}),目标=${userId}(${targetRole || "unknown"})`;
424
427
  }
425
428
  }
426
429
  __name(performTitle, "performTitle");
@@ -474,11 +477,12 @@ function apply(ctx, config) {
474
477
  });
475
478
  ctx.command("group.manage/mute <target:string> <duration:number>", "禁言目标(秒,必须指定)").alias("gmute").action(async ({ session }, target, duration) => {
476
479
  if (!session) return "缺少 session";
480
+ const msg = await verifyCaller(session, config.mute, logger, verbose);
481
+ if (msg) return msg;
477
482
  return performMute(
478
483
  ctx,
479
484
  session,
480
485
  { targetRaw: target, duration: Number(duration) },
481
- config,
482
486
  logger,
483
487
  verbose
484
488
  );
@@ -490,10 +494,14 @@ function apply(ctx, config) {
490
494
  const userId = parseTargetId(target, session);
491
495
  if (!userId) return "请提供要解禁的用户(@ 或 QQ 号)";
492
496
  verbose && logger.info(`unmute: guild=${session.guildId} caller=${session.userId} bot=${botKey(session.bot)} target=${userId}`);
493
- const picked = await pickManageBot(ctx, session.guildId, false, logger, session.bot, verbose, session.onebot);
494
- if (!picked) return "没有可用且有群管权限的 Bot";
495
- const targetRole = await getMemberRole(picked.probeOnebot, picked.bot, session.guildId, userId, logger, verbose);
497
+ const probeOnebot = session.onebot || getBotOnebot(session.bot);
498
+ const targetRole = await getMemberRole(probeOnebot, session.bot, session.guildId, userId, logger, verbose);
496
499
  if (targetRole === "owner") return "无法对群主执行该操作";
500
+ const requireOwner = targetRole === "admin";
501
+ const picked = await pickManageBot(ctx, session.guildId, requireOwner, logger, session.bot, verbose, probeOnebot);
502
+ if (!picked) {
503
+ return requireOwner ? "目标是管理员,需要群主权限的 Bot,但没有可用" : "没有可用且有群管权限的 Bot";
504
+ }
497
505
  const actionOnebot = getBotOnebot(picked.bot);
498
506
  if (!actionOnebot) return "选中的 Bot 缺少 onebot 实例,无法执行";
499
507
  try {
@@ -522,10 +530,14 @@ function apply(ctx, config) {
522
530
  if (!userId) return "请提供要踢出的用户(@ 或 QQ 号)";
523
531
  const reject = Boolean(options?.reject ?? rejectFlag);
524
532
  verbose && logger.info(`kick: guild=${session.guildId} caller=${session.userId} bot=${botKey(session.bot)} target=${userId} reject=${reject}`);
525
- const picked = await pickManageBot(ctx, session.guildId, false, logger, session.bot, verbose, session.onebot);
526
- if (!picked) return "没有可用且有群管权限的 Bot";
527
- const targetRole = await getMemberRole(picked.probeOnebot, picked.bot, session.guildId, userId, logger, verbose);
533
+ const probeOnebot = session.onebot || getBotOnebot(session.bot);
534
+ const targetRole = await getMemberRole(probeOnebot, session.bot, session.guildId, userId, logger, verbose);
528
535
  if (targetRole === "owner") return "无法对群主执行该操作";
536
+ const requireOwner = targetRole === "admin";
537
+ const picked = await pickManageBot(ctx, session.guildId, requireOwner, logger, session.bot, verbose, probeOnebot);
538
+ if (!picked) {
539
+ return requireOwner ? "目标是管理员,需要群主权限的 Bot,但没有可用" : "没有可用且有群管权限的 Bot";
540
+ }
529
541
  const actionOnebot = getBotOnebot(picked.bot);
530
542
  if (!actionOnebot) return "选中的 Bot 缺少 onebot 实例,无法执行";
531
543
  try {
@@ -548,11 +560,12 @@ function apply(ctx, config) {
548
560
  });
549
561
  ctx.command("group.manage/title <target:string> <title:text>", "设置群头衔(需群主 Bot)").alias("gtitle").action(async ({ session }, target, title) => {
550
562
  if (!session) return "缺少 session";
563
+ const msg = await verifyCaller(session, config.title, logger, verbose);
564
+ if (msg) return msg;
551
565
  return performTitle(
552
566
  ctx,
553
567
  session,
554
568
  { targetRaw: target, title: title || "", guildId: session.guildId },
555
- config,
556
569
  logger,
557
570
  verbose
558
571
  );
@@ -568,11 +581,10 @@ function apply(ctx, config) {
568
581
  ctx,
569
582
  session,
570
583
  { targetId: session.userId, duration: seconds, guildId: session.guildId },
571
- config,
572
584
  logger,
573
585
  verbose
574
586
  );
575
- if (typeof result === "string" && result.startsWith("已使用")) return `你已被禁言 ${seconds} 秒`;
587
+ if (typeof result === "string" && result.startsWith("成功")) return `你已被禁言 ${seconds} 秒`;
576
588
  return result;
577
589
  });
578
590
  ctx.command("group.manage/title.apply <title:text>", "申请群头衔(给自己)").alias("gtitle.apply").action(async ({ session }, title) => {
@@ -581,11 +593,10 @@ function apply(ctx, config) {
581
593
  ctx,
582
594
  session,
583
595
  { targetId: session.userId, title: title || "", guildId: session.guildId },
584
- config,
585
596
  logger,
586
597
  verbose
587
598
  );
588
- if (typeof result === "string" && result.startsWith("已使用")) {
599
+ if (typeof result === "string" && result.startsWith("成功")) {
589
600
  return `已为你设置头衔:${(title || "").trim()}`;
590
601
  }
591
602
  return result;
package/lib/tools.d.ts CHANGED
@@ -5,12 +5,12 @@ interface Handlers {
5
5
  targetId: string;
6
6
  duration: number;
7
7
  guildId?: string;
8
- }, config: Config, logger: ReturnType<Context['logger']>, verbose?: boolean) => Promise<string>;
8
+ }, logger: ReturnType<Context['logger']>, verbose?: boolean) => Promise<string>;
9
9
  performTitle: (ctx: Context, session: Session, params: {
10
10
  targetId: string;
11
11
  title: string;
12
12
  guildId?: string;
13
- }, config: Config, logger: ReturnType<Context['logger']>, verbose?: boolean) => Promise<string>;
13
+ }, logger: ReturnType<Context['logger']>, verbose?: boolean) => Promise<string>;
14
14
  }
15
- export declare function registerChatlunaTools(ctx: Context, config: Config, logger: ReturnType<Context['logger']>, verbose: boolean | undefined, handlers: Handlers): void;
15
+ export declare function registerChatlunaTools(ctx: Context, _config: Config, logger: ReturnType<Context['logger']>, verbose: boolean | undefined, handlers: Handlers): void;
16
16
  export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-onebot-group-manage",
3
3
  "description": "主要针对多bot环境的群管插件,自动使用有权限的bot",
4
- "version": "0.0.6",
4
+ "version": "0.0.8",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
@@ -15,8 +15,8 @@
15
15
  "plugin"
16
16
  ],
17
17
  "peerDependencies": {
18
- "koishi": "^4.18.7",
19
18
  "@langchain/core": "^0.3.0",
19
+ "koishi": "^4.18.7",
20
20
  "koishi-plugin-chatluna": "^1.3.0",
21
21
  "zod": "^3.23.8"
22
22
  }