koishi-plugin-chatluna-toolbox 0.0.1 → 0.0.4

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.
Files changed (2) hide show
  1. package/lib/index.js +149 -57
  2. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -22,6 +22,7 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  Config: () => ConfigSchema,
24
24
  ConfigSchema: () => ConfigSchema,
25
+ DEFAULT_GROUP_INFO_ITEMS: () => DEFAULT_GROUP_INFO_ITEMS,
25
26
  DEFAULT_MEMBER_INFO_ITEMS: () => DEFAULT_MEMBER_INFO_ITEMS,
26
27
  NativeToolsSchema: () => NativeToolsSchema,
27
28
  RAW_INTERCEPTOR_TAG: () => RAW_INTERCEPTOR_TAG,
@@ -132,6 +133,13 @@ var DEFAULT_MEMBER_INFO_ITEMS = [
132
133
  "joinTime",
133
134
  "lastSentTime"
134
135
  ];
136
+ var DEFAULT_GROUP_INFO_ITEMS = [
137
+ "groupName",
138
+ "groupId",
139
+ "memberCount",
140
+ "ownerList",
141
+ "adminList"
142
+ ];
135
143
  var RAW_INTERCEPTOR_TAG = "__chatlunaToolboxRawInterceptor";
136
144
 
137
145
  // src/schema/variables.ts
@@ -172,9 +180,16 @@ var VariablesSchema = import_koishi3.Schema.object({
172
180
  }).description("\u673A\u5668\u4EBA\u4FE1\u606F\u53D8\u91CF").collapse(),
173
181
  groupInfo: import_koishi3.Schema.object({
174
182
  variableName: import_koishi3.Schema.string().default("groupInfo").description("\u53D8\u91CF\u540D\u79F0"),
175
- includeMemberCount: import_koishi3.Schema.boolean().default(true).description("\u662F\u5426\u5305\u542B\u6210\u5458\u6570\u91CF"),
176
- includeCreateTime: import_koishi3.Schema.boolean().default(true).description("\u662F\u5426\u5305\u542B\u521B\u5EFA\u65F6\u95F4"),
177
- includeOwnersAndAdmins: import_koishi3.Schema.boolean().default(true).description("\u662F\u5426\u5C55\u793A\u7FA4\u4E3B\u4E0E\u7BA1\u7406\u5458\u540D\u5355")
183
+ items: import_koishi3.Schema.array(
184
+ import_koishi3.Schema.union([
185
+ import_koishi3.Schema.const("groupName").description("\u7FA4\u540D\u79F0"),
186
+ import_koishi3.Schema.const("groupId").description("\u7FA4\u53F7"),
187
+ import_koishi3.Schema.const("memberCount").description("\u6210\u5458\u6570\u91CF"),
188
+ import_koishi3.Schema.const("createTime").description("\u521B\u5EFA\u65F6\u95F4\uFF08\u4EC5\u90E8\u5206\u5B9E\u73B0\u652F\u6301\uFF09"),
189
+ import_koishi3.Schema.const("ownerList").description("\u7FA4\u4E3B\u540D\u5355"),
190
+ import_koishi3.Schema.const("adminList").description("\u7BA1\u7406\u5458\u540D\u5355")
191
+ ])
192
+ ).role("checkbox").default([...DEFAULT_GROUP_INFO_ITEMS]).description("\u663E\u793A\u7684\u7FA4\u4FE1\u606F\u9879")
178
193
  }).description("\u7FA4\u4FE1\u606F\u53D8\u91CF").collapse(),
179
194
  random: import_koishi3.Schema.object({
180
195
  variableName: import_koishi3.Schema.string().default("random").description("\u53D8\u91CF\u540D\u79F0"),
@@ -182,13 +197,14 @@ var VariablesSchema = import_koishi3.Schema.object({
182
197
  max: import_koishi3.Schema.number().default(100).description("\u9ED8\u8BA4\u968F\u673A\u6570\u4E0A\u9650")
183
198
  }).description("\u968F\u673A\u6570\u53D8\u91CF").collapse()
184
199
  }).default({
185
- userInfo: { variableName: "userInfo", items: [...DEFAULT_MEMBER_INFO_ITEMS] },
200
+ userInfo: {
201
+ variableName: "userInfo",
202
+ items: [...DEFAULT_MEMBER_INFO_ITEMS]
203
+ },
186
204
  botInfo: { variableName: "botInfo", items: [...DEFAULT_MEMBER_INFO_ITEMS] },
187
205
  groupInfo: {
188
206
  variableName: "groupInfo",
189
- includeMemberCount: true,
190
- includeCreateTime: true,
191
- includeOwnersAndAdmins: true
207
+ items: [...DEFAULT_GROUP_INFO_ITEMS]
192
208
  },
193
209
  random: { variableName: "random", min: 0, max: 100 }
194
210
  }).description("\u5176\u4ED6\u53D8\u91CF");
@@ -591,9 +607,12 @@ function createXmlInterceptor(deps) {
591
607
  let currentGuildId = null;
592
608
  let lastSession = null;
593
609
  const pendingSessions = [];
610
+ let responseSeq = 0;
611
+ const processedResponses = /* @__PURE__ */ new Set();
594
612
  let monitorHandle = null;
595
613
  let fastRetryHandle = null;
596
614
  let startupHandle = null;
615
+ const responseRetryHandles = /* @__PURE__ */ new Map();
597
616
  let activeService = null;
598
617
  let activeLogger = null;
599
618
  let originalDebug = null;
@@ -642,6 +661,45 @@ function createXmlInterceptor(deps) {
642
661
  }
643
662
  return resolved.key ? sessionMap.get(resolved.key) || resolved.session : resolved.session;
644
663
  };
664
+ const markProcessed = (responseId) => {
665
+ processedResponses.add(responseId);
666
+ if (processedResponses.size > 100) {
667
+ const first = processedResponses.values().next().value;
668
+ if (first) processedResponses.delete(first);
669
+ }
670
+ };
671
+ const runResponse = (responseId, response, session) => {
672
+ const handled = onResponse(response, session);
673
+ if (handled) {
674
+ markProcessed(responseId);
675
+ const retryHandle = responseRetryHandles.get(responseId);
676
+ if (retryHandle) {
677
+ retryHandle();
678
+ responseRetryHandles.delete(responseId);
679
+ }
680
+ }
681
+ return handled;
682
+ };
683
+ const retryResponse = (responseId, response) => {
684
+ if (responseRetryHandles.has(responseId) || processedResponses.has(responseId))
685
+ return;
686
+ const handle = ctx.setTimeout(() => {
687
+ responseRetryHandles.delete(responseId);
688
+ if (processedResponses.has(responseId)) return;
689
+ const session = resolveSession();
690
+ if (!session) {
691
+ if (config.debugLogging) {
692
+ log?.("warn", "\u62E6\u622A\u5230\u539F\u59CB\u8F93\u51FA\u4F46\u7F3A\u5C11\u4F1A\u8BDD\u4E0A\u4E0B\u6587\uFF0CXML \u5DE5\u5177\u4E0D\u4F1A\u6267\u884C", {
693
+ length: response.length
694
+ });
695
+ }
696
+ runResponse(responseId, response, null);
697
+ return;
698
+ }
699
+ runResponse(responseId, response, session);
700
+ }, 200);
701
+ responseRetryHandles.set(responseId, handle);
702
+ };
645
703
  const attach = () => {
646
704
  const characterService = ctx.chatluna_character;
647
705
  if (!characterService) return false;
@@ -669,17 +727,20 @@ function createXmlInterceptor(deps) {
669
727
  const wrapped = (...args) => {
670
728
  raw(...args);
671
729
  const message = args[0];
672
- if (typeof message !== "string" || !message.startsWith("model response: "))
673
- return;
674
- const response = message.substring("model response: ".length);
730
+ if (typeof message !== "string") return;
731
+ const prefix = ["model response: ", "model response:\n"].find(
732
+ (item) => message.startsWith(item)
733
+ );
734
+ if (!prefix) return;
735
+ const response = message.substring(prefix.length);
675
736
  if (!response) return;
737
+ const responseId = `${Date.now()}:${responseSeq++}`;
676
738
  const session = resolveSession();
677
- if (!session && config.debugLogging) {
678
- log?.("warn", "\u62E6\u622A\u5230\u539F\u59CB\u8F93\u51FA\u4F46\u7F3A\u5C11\u4F1A\u8BDD\u4E0A\u4E0B\u6587\uFF0CXML \u5DE5\u5177\u4E0D\u4F1A\u6267\u884C", {
679
- length: response.length
680
- });
739
+ if (!session) {
740
+ retryResponse(responseId, response);
741
+ return;
681
742
  }
682
- onResponse(response, session);
743
+ runResponse(responseId, response, session);
683
744
  };
684
745
  wrapped[RAW_INTERCEPTOR_TAG] = true;
685
746
  loggerService.debug = wrapped;
@@ -751,6 +812,9 @@ function createXmlInterceptor(deps) {
751
812
  }
752
813
  stopFastRetry();
753
814
  stopMonitor();
815
+ for (const handle of responseRetryHandles.values()) handle();
816
+ responseRetryHandles.clear();
817
+ processedResponses.clear();
754
818
  restore();
755
819
  sessionMap.clear();
756
820
  pendingSessions.length = 0;
@@ -790,10 +854,12 @@ function registerXmlTools(deps) {
790
854
  log,
791
855
  onResponse: (response, session) => {
792
856
  const actions = parseXmlActions(response);
857
+ let handled = false;
793
858
  if (config.enablePokeXmlTool && actions.pokeUserIds.length > 0) {
794
859
  if (!session) {
795
860
  log?.("warn", "\u68C0\u6D4B\u5230\u6233\u4E00\u6233\u6807\u8BB0\u4F46\u7F3A\u5C11\u4F1A\u8BDD\u4E0A\u4E0B\u6587");
796
861
  } else {
862
+ handled = true;
797
863
  for (const userId of actions.pokeUserIds) {
798
864
  void sendPoke({ session, userId, protocol, log }).catch((error) => {
799
865
  log?.("warn", "XML \u89E6\u53D1 poke \u5931\u8D25", error);
@@ -805,6 +871,7 @@ function registerXmlTools(deps) {
805
871
  if (!session) {
806
872
  log?.("warn", "\u68C0\u6D4B\u5230\u8868\u60C5\u6807\u8BB0\u4F46\u7F3A\u5C11\u4F1A\u8BDD\u4E0A\u4E0B\u6587");
807
873
  } else {
874
+ handled = true;
808
875
  for (const item of actions.emojis) {
809
876
  void sendMsgEmoji({
810
877
  session,
@@ -822,6 +889,7 @@ function registerXmlTools(deps) {
822
889
  if (!session) {
823
890
  log?.("warn", "\u68C0\u6D4B\u5230\u64A4\u56DE\u6807\u8BB0\u4F46\u7F3A\u5C11\u4F1A\u8BDD\u4E0A\u4E0B\u6587");
824
891
  } else {
892
+ handled = true;
825
893
  for (const messageId of actions.deleteMessageIds) {
826
894
  void sendDeleteMessage({ session, messageId, log }).catch(
827
895
  (error) => {
@@ -831,6 +899,7 @@ function registerXmlTools(deps) {
831
899
  }
832
900
  }
833
901
  }
902
+ return handled;
834
903
  }
835
904
  });
836
905
  return {
@@ -1082,16 +1151,24 @@ async function fetchOwnersAndAdmins(session, log) {
1082
1151
  const list = await bot.getGuildMemberList(guildId);
1083
1152
  members = list?.data || null;
1084
1153
  }
1085
- if (!members || !Array.isArray(members) || members.length === 0) return null;
1154
+ if (!members || !Array.isArray(members) || members.length === 0)
1155
+ return null;
1086
1156
  const owners = [];
1087
1157
  const admins = [];
1088
1158
  for (const member of members) {
1089
1159
  const roleRaw = member.role || member.roleName || member.permission || member.identity || (Array.isArray(member.roles) ? member.roles[0] : "") || "";
1090
1160
  const role = String(roleRaw || "").toLowerCase();
1091
- const userId = String(member.user_id || member.userId || member.id || member.qq || member.uid || "");
1092
- const candidates = [member.card, member.remark, member.displayName, member.nick, member.nickname, member.name].map(
1093
- (item) => item ? String(item).trim() : ""
1161
+ const userId = String(
1162
+ member.user_id || member.userId || member.id || member.qq || member.uid || ""
1094
1163
  );
1164
+ const candidates = [
1165
+ member.card,
1166
+ member.remark,
1167
+ member.displayName,
1168
+ member.nick,
1169
+ member.nickname,
1170
+ member.name
1171
+ ].map((item) => item ? String(item).trim() : "");
1095
1172
  const name2 = candidates.find((item) => item) || userId;
1096
1173
  const label = userId ? `${name2}(${userId})` : name2;
1097
1174
  if (role === "owner" || role === "master" || role === "leader") {
@@ -1106,26 +1183,56 @@ async function fetchOwnersAndAdmins(session, log) {
1106
1183
  return null;
1107
1184
  }
1108
1185
  }
1109
- function formatGroupInfo(group, options) {
1110
- const { includeMemberCount, includeCreateTime } = options;
1111
- const id = group.group_id ?? group.groupId ?? group.id ?? "\u672A\u77E5\u7FA4\u53F7";
1112
- const name2 = group.group_name ?? group.groupName ?? group.name ?? "\u672A\u547D\u540D\u7FA4";
1186
+ function formatDateOnly2(value) {
1187
+ if (value == null || value === "") return "";
1188
+ const timestamp = Number(value);
1189
+ if (!Number.isFinite(timestamp)) return "";
1190
+ const date = new Date(timestamp < 1e11 ? timestamp * 1e3 : timestamp);
1191
+ if (Number.isNaN(date.valueOf())) return "";
1192
+ return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
1193
+ }
1194
+ function renderGroupInfo(group, items, roles) {
1195
+ const values = [];
1196
+ const id = String(group.group_id ?? group.groupId ?? group.id ?? "").trim();
1197
+ const name2 = String(
1198
+ group.group_name ?? group.groupName ?? group.name ?? ""
1199
+ ).trim();
1113
1200
  const memberCount = group.member_count ?? group.memberCount ?? group.max_member_count;
1114
- let createTime = "";
1115
- if (includeCreateTime) {
1116
- const raw = group.create_time ?? group.createTime;
1117
- if (raw) {
1118
- const timestamp = Number(raw);
1119
- if (Number.isFinite(timestamp)) {
1120
- const date = new Date(timestamp < 1e11 ? timestamp * 1e3 : timestamp);
1121
- if (!Number.isNaN(date.valueOf())) {
1122
- createTime = `\uFF0C\u521B\u5EFA\u65F6\u95F4\uFF1A${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
1123
- }
1201
+ const createTime = formatDateOnly2(group.create_time ?? group.createTime);
1202
+ for (const item of items) {
1203
+ switch (item) {
1204
+ case "groupName":
1205
+ if (name2) values.push(`\u7FA4\u540D\uFF1A${name2}`);
1206
+ break;
1207
+ case "groupId":
1208
+ if (id) values.push(`\u7FA4\u53F7\uFF1A${id}`);
1209
+ break;
1210
+ case "memberCount":
1211
+ if (memberCount != null) values.push(`\u6210\u5458\u6570\u91CF\uFF1A${memberCount}`);
1212
+ break;
1213
+ case "createTime":
1214
+ if (createTime) values.push(`\u521B\u5EFA\u65F6\u95F4\uFF1A${createTime}`);
1215
+ break;
1216
+ case "ownerList": {
1217
+ if (!roles) break;
1218
+ values.push(
1219
+ `\u7FA4\u4E3B\uFF1A${roles.owners.length ? roles.owners.join("\u3001") : "\u65E0"}`
1220
+ );
1221
+ break;
1222
+ }
1223
+ case "adminList": {
1224
+ if (!roles) break;
1225
+ values.push(
1226
+ `\u7BA1\u7406\u5458\uFF1A${roles.admins.length ? roles.admins.join("\u3001") : "\u65E0"}`
1227
+ );
1228
+ break;
1124
1229
  }
1230
+ default:
1231
+ break;
1125
1232
  }
1126
1233
  }
1127
- const members = includeMemberCount ? `\uFF0C\u4EBA\u6570: ${memberCount ?? "\u672A\u77E5"}` : "";
1128
- return `\u7FA4\u53F7\uFF1A${id}\uFF0C\u7FA4\u540D\u79F0\uFF1A${name2}${members}${createTime}`;
1234
+ if (values.length === 0) return id || name2 || "\u672A\u80FD\u83B7\u53D6\u5F53\u524D\u7FA4\u4FE1\u606F\u3002";
1235
+ return values.join("\n");
1129
1236
  }
1130
1237
  function createGroupInfoProvider(deps) {
1131
1238
  const { config, log } = deps;
@@ -1134,29 +1241,13 @@ function createGroupInfoProvider(deps) {
1134
1241
  if (!session) return "\u6682\u65E0\u7FA4\u4FE1\u606F\u3002";
1135
1242
  if (!session.guildId) return "";
1136
1243
  if (session.platform !== "onebot") return "\u5F53\u524D\u5E73\u53F0\u6682\u4E0D\u652F\u6301\u67E5\u8BE2\u7FA4\u4FE1\u606F\u3002";
1137
- const groupInfoCfg = config.groupInfo || {
1138
- includeMemberCount: true,
1139
- includeCreateTime: true,
1140
- includeOwnersAndAdmins: true
1141
- };
1244
+ const items = Array.isArray(config.groupInfo?.items) && config.groupInfo.items.length ? config.groupInfo.items : DEFAULT_GROUP_INFO_ITEMS;
1142
1245
  try {
1143
1246
  const groupInfo = await fetchGroupInfo(session);
1144
1247
  if (!groupInfo) return "\u672A\u80FD\u83B7\u53D6\u5F53\u524D\u7FA4\u4FE1\u606F\u3002";
1145
- const baseText = formatGroupInfo(groupInfo, {
1146
- includeMemberCount: groupInfoCfg.includeMemberCount !== false,
1147
- includeCreateTime: groupInfoCfg.includeCreateTime !== false
1148
- });
1149
- if (groupInfoCfg.includeOwnersAndAdmins) {
1150
- const roles = await fetchOwnersAndAdmins(session, log);
1151
- if (roles) {
1152
- const ownersText = roles.owners.length ? roles.owners.join("\u3001") : "\u65E0";
1153
- const adminsText = roles.admins.length ? roles.admins.join("\u3001") : "\u65E0";
1154
- return `${baseText}
1155
- \u7FA4\u4E3B\uFF1A${ownersText}
1156
- \u7BA1\u7406\u5458\uFF1A${adminsText}`;
1157
- }
1158
- }
1159
- return baseText;
1248
+ const needRoles = items.includes("ownerList") || items.includes("adminList");
1249
+ const roles = needRoles ? await fetchOwnersAndAdmins(session, log) : null;
1250
+ return renderGroupInfo(groupInfo, items, roles);
1160
1251
  } catch (error) {
1161
1252
  log?.("debug", "\u7FA4\u4FE1\u606F\u53D8\u91CF\u89E3\u6790\u5931\u8D25", error);
1162
1253
  return "\u83B7\u53D6\u7FA4\u4FE1\u606F\u5931\u8D25\u3002";
@@ -1194,7 +1285,7 @@ function normalizeTimestamp2(raw) {
1194
1285
  if (!Number.isFinite(numeric)) return null;
1195
1286
  return numeric < 1e11 ? numeric * 1e3 : numeric;
1196
1287
  }
1197
- function formatDateOnly2(value) {
1288
+ function formatDateOnly3(value) {
1198
1289
  if (!value) return "";
1199
1290
  const date = new Date(value);
1200
1291
  if (Number.isNaN(date.valueOf())) return "";
@@ -1328,7 +1419,7 @@ function renderUserInfo(session, member, items) {
1328
1419
  break;
1329
1420
  }
1330
1421
  case "joinTime": {
1331
- const joinTime = formatDateOnly2(
1422
+ const joinTime = formatDateOnly3(
1332
1423
  normalizeTimestamp2(
1333
1424
  pickFirst2(
1334
1425
  member?.join_time,
@@ -1447,6 +1538,7 @@ function apply(ctx, config) {
1447
1538
  0 && (module.exports = {
1448
1539
  Config,
1449
1540
  ConfigSchema,
1541
+ DEFAULT_GROUP_INFO_ITEMS,
1450
1542
  DEFAULT_MEMBER_INFO_ITEMS,
1451
1543
  NativeToolsSchema,
1452
1544
  RAW_INTERCEPTOR_TAG,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-chatluna-toolbox",
3
3
  "description": "为 ChatLuna 提供更多原生工具、XML 工具与变量。",
4
- "version": "0.0.1",
4
+ "version": "0.0.4",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [