koishi-plugin-ccb-plus 0.0.1

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.d.ts ADDED
@@ -0,0 +1,46 @@
1
+ import { Context, Schema } from 'koishi';
2
+ export declare const name = "ccb-plus";
3
+ export interface CCBConfig {
4
+ ywWindow: number;
5
+ ywThreshold: number;
6
+ ywBanDuration: number;
7
+ ywProbability: number;
8
+ whiteList: string[];
9
+ selfCcb: boolean;
10
+ critProb: number;
11
+ isLog: boolean;
12
+ }
13
+ export interface CCBData {
14
+ [groupId: string]: CCBGroupData[];
15
+ }
16
+ export interface CCBActorInfo {
17
+ count: number;
18
+ first: boolean;
19
+ max: boolean;
20
+ }
21
+ export interface CCBGroupData {
22
+ id: string;
23
+ num: number;
24
+ vol: number;
25
+ ccb_by: {
26
+ [actorId: string]: CCBActorInfo;
27
+ };
28
+ max: number;
29
+ }
30
+ export interface CCBLogEntry {
31
+ group: string;
32
+ executor: string;
33
+ target: string;
34
+ time: number;
35
+ vol: string;
36
+ }
37
+ export interface CCBActionTime {
38
+ [userId: string]: number[];
39
+ }
40
+ declare module 'koishi' {
41
+ interface Tables {
42
+ ccb_data: CCBData;
43
+ }
44
+ }
45
+ export declare const Config: Schema<CCBConfig>;
46
+ export declare function apply(ctx: Context, config: CCBConfig): void;
package/lib/index.js ADDED
@@ -0,0 +1,524 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
8
+ var __export = (target, all) => {
9
+ for (var name2 in all)
10
+ __defProp(target, name2, { get: all[name2], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ Config: () => Config,
34
+ apply: () => apply,
35
+ name: () => name
36
+ });
37
+ module.exports = __toCommonJS(src_exports);
38
+ var import_koishi = require("koishi");
39
+ var import_fs = require("fs");
40
+ var path = __toESM(require("path"));
41
+ var name = "ccb-plus";
42
+ var Config = import_koishi.Schema.object({
43
+ ywWindow: import_koishi.Schema.number().default(60).description("触发赛博阳痿的窗口时间(秒)"),
44
+ ywThreshold: import_koishi.Schema.number().default(5).description("窗口时间内最大ccb数"),
45
+ ywBanDuration: import_koishi.Schema.number().default(900).description("养胃时长(秒)"),
46
+ ywProbability: import_koishi.Schema.number().default(0.1).min(0).max(1).description("随机养胃概率"),
47
+ whiteList: import_koishi.Schema.array(String).default([]).description("不能进行ccb的id列表"),
48
+ selfCcb: import_koishi.Schema.boolean().default(false).description("是否允许对自己ccb"),
49
+ critProb: import_koishi.Schema.number().default(0.2).min(0).max(1).description("暴击概率"),
50
+ isLog: import_koishi.Schema.boolean().default(false).description("完整日志记录")
51
+ });
52
+ function apply(ctx, config) {
53
+ const DATA_FILE = path.join(ctx.baseDir, "data", "ccb.json");
54
+ const LOG_FILE = path.join(ctx.baseDir, "data", "ccb_log.json");
55
+ const actionTimes = {};
56
+ const banList = {};
57
+ function getAvatar(userId) {
58
+ return `https://q4.qlogo.cn/headimg_dl?dst_uin=${userId}&spec=640`;
59
+ }
60
+ __name(getAvatar, "getAvatar");
61
+ function makeit(groupData, targetUserId) {
62
+ return groupData.some((item) => item.id === targetUserId) ? 1 : 2;
63
+ }
64
+ __name(makeit, "makeit");
65
+ async function readData() {
66
+ try {
67
+ const data = await import_fs.promises.readFile(DATA_FILE, "utf-8");
68
+ return JSON.parse(data);
69
+ } catch (error) {
70
+ if (error.code === "ENOENT") {
71
+ return {};
72
+ }
73
+ console.error("Error reading CCB data:", error);
74
+ return {};
75
+ }
76
+ }
77
+ __name(readData, "readData");
78
+ async function writeData(data) {
79
+ try {
80
+ const dataDir = path.dirname(DATA_FILE);
81
+ await import_fs.promises.mkdir(dataDir, { recursive: true });
82
+ await import_fs.promises.writeFile(DATA_FILE, JSON.stringify(data, null, 2), "utf-8");
83
+ } catch (error) {
84
+ console.error("Error writing CCB data:", error);
85
+ }
86
+ }
87
+ __name(writeData, "writeData");
88
+ async function appendLog(group_id, executor_id, target_id, time, vol) {
89
+ try {
90
+ let logs = [];
91
+ try {
92
+ const logData = await import_fs.promises.readFile(LOG_FILE, "utf-8");
93
+ logs = JSON.parse(logData);
94
+ if (!Array.isArray(logs)) {
95
+ logs = [];
96
+ }
97
+ } catch (error) {
98
+ if (error.code !== "ENOENT") {
99
+ console.error("Error reading CCB log:", error);
100
+ }
101
+ }
102
+ const entry = {
103
+ group: group_id,
104
+ executor: executor_id,
105
+ target: target_id,
106
+ time,
107
+ vol: vol.toFixed(2)
108
+ };
109
+ logs.push(entry);
110
+ const logDir = path.dirname(LOG_FILE);
111
+ await import_fs.promises.mkdir(logDir, { recursive: true });
112
+ await import_fs.promises.writeFile(LOG_FILE, JSON.stringify(logs, null, 2), "utf-8");
113
+ } catch (error) {
114
+ console.error("append_log 失败:", error);
115
+ }
116
+ }
117
+ __name(appendLog, "appendLog");
118
+ async function getUserNickname(session, userId) {
119
+ try {
120
+ const userInfo = await session.bot.getUser(userId);
121
+ return userInfo?.name || userId;
122
+ } catch (error) {
123
+ try {
124
+ const memberInfo = await session.bot.getGuildMember(session.guildId, userId);
125
+ return memberInfo?.nick || userId;
126
+ } catch (e) {
127
+ return userId;
128
+ }
129
+ }
130
+ }
131
+ __name(getUserNickname, "getUserNickname");
132
+ ctx.command("ccb [target:user]", "和群友赛博sex的插件PLUS", { authority: 1 }).action(async ({ session }, target) => {
133
+ const groupId = session.guildId;
134
+ if (!groupId) {
135
+ return "此命令只能在群聊中使用。";
136
+ }
137
+ const senderId = session.userId;
138
+ const actorId = senderId;
139
+ const now = Date.now() / 1e3;
140
+ const banEnd = banList[actorId] || 0;
141
+ if (now < banEnd) {
142
+ const remain = Math.floor(banEnd - now);
143
+ const m = Math.floor(remain / 60);
144
+ const s = remain % 60;
145
+ return `嘻嘻,你已经一滴不剩了,养胃还剩 ${m}分${s}秒`;
146
+ }
147
+ const times = actionTimes[actorId] = actionTimes[actorId] || [];
148
+ const cutoff = now - config.ywWindow;
149
+ while (times.length > 0 && times[0] < cutoff) {
150
+ times.shift();
151
+ }
152
+ times.push(now);
153
+ if (times.length > config.ywThreshold) {
154
+ banList[actorId] = now + config.ywBanDuration;
155
+ actionTimes[actorId] = [];
156
+ return "冲得出来吗你就冲,再冲就给你折了";
157
+ }
158
+ let targetUserId = senderId;
159
+ if (target) {
160
+ const match = target.match(/^[^:]+:(.+)$/);
161
+ if (match) {
162
+ targetUserId = match[1];
163
+ }
164
+ } else if (session.quote?.user?.id) {
165
+ targetUserId = session.quote.user.id;
166
+ }
167
+ if (config.whiteList.includes(targetUserId)) {
168
+ const nickname = await getUserNickname(session, targetUserId) || targetUserId;
169
+ return `${nickname} 的后门被后户之神霸占了,不能ccb(悲`;
170
+ }
171
+ if (targetUserId === actorId && !config.selfCcb) {
172
+ return "兄啊金箔怎么还能捅到自己的啊(恼)";
173
+ }
174
+ const duration = parseFloat((Math.random() * 59 + 1).toFixed(2));
175
+ let V = parseFloat((Math.random() * 99 + 1).toFixed(2));
176
+ const prob = config.critProb;
177
+ let crit = false;
178
+ if (Math.random() < prob) {
179
+ V = parseFloat((V * 2).toFixed(2));
180
+ crit = true;
181
+ }
182
+ const pic = getAvatar(targetUserId);
183
+ const allData = await readData();
184
+ const groupData = allData[groupId] || [];
185
+ const mode = makeit(groupData, targetUserId);
186
+ if (mode === 1) {
187
+ try {
188
+ const recordIndex = groupData.findIndex((item) => item.id === targetUserId);
189
+ if (recordIndex !== -1) {
190
+ const item = groupData[recordIndex];
191
+ const nickname = await getUserNickname(session, targetUserId) || targetUserId;
192
+ item.num = (item.num || 0) + 1;
193
+ item.vol = parseFloat((item.vol + V).toFixed(2));
194
+ let ccb_by = item.ccb_by || {};
195
+ if (senderId in ccb_by) {
196
+ const current = ccb_by[senderId];
197
+ ccb_by[senderId] = {
198
+ count: (current?.count || 0) + 1,
199
+ first: current?.first || false,
200
+ max: current?.max || false
201
+ };
202
+ } else {
203
+ ccb_by[senderId] = { count: 1, first: false, max: false };
204
+ }
205
+ item.ccb_by = ccb_by;
206
+ let prev_max = item.max || 0;
207
+ if (prev_max === 0) {
208
+ const total_vol = item.vol || 0;
209
+ const total_num = item.num || 0;
210
+ if (total_num > 0) {
211
+ prev_max = parseFloat((total_vol / total_num).toFixed(2));
212
+ }
213
+ }
214
+ if (V > prev_max) {
215
+ item.max = V;
216
+ for (const k in ccb_by) {
217
+ const current = ccb_by[k];
218
+ ccb_by[k] = {
219
+ count: current?.count || 0,
220
+ first: current?.first || false,
221
+ max: false
222
+ };
223
+ }
224
+ const senderData = ccb_by[senderId];
225
+ ccb_by[senderId] = {
226
+ count: senderData?.count || 0,
227
+ first: senderData?.first || false,
228
+ max: true
229
+ };
230
+ } else {
231
+ for (const k in ccb_by) {
232
+ const current = ccb_by[k];
233
+ if (!(current && "max" in current)) {
234
+ ccb_by[k] = {
235
+ count: current?.count || 0,
236
+ first: current?.first || false,
237
+ max: false
238
+ };
239
+ }
240
+ }
241
+ }
242
+ item.ccb_by = ccb_by;
243
+ let resultMessage = crit ? `你和${nickname}发生了${duration}min长的ccb行为,向ta注入了 💥 暴击!${V.toFixed(2)}ml的生命因子` : `你和${nickname}发生了${duration}min长的ccb行为,向ta注入了${V.toFixed(2)}ml的生命因子`;
244
+ const message = [
245
+ resultMessage,
246
+ import_koishi.segment.image(pic),
247
+ `这是ta的第${item.num}次。`
248
+ ].join("\n");
249
+ allData[groupId] = groupData;
250
+ await writeData(allData);
251
+ if (config.isLog) {
252
+ try {
253
+ await appendLog(groupId, senderId, targetUserId, duration, V);
254
+ } catch (e) {
255
+ console.warn("记录日志失败:", e);
256
+ }
257
+ }
258
+ if (Math.random() < config.ywProbability) {
259
+ banList[actorId] = now + config.ywBanDuration;
260
+ return message + "\n💥你的牛牛炸膛了!满身疮痍,再起不能(悲)";
261
+ }
262
+ return message;
263
+ } else {
264
+ return "对方拒绝了和你ccb";
265
+ }
266
+ } catch (e) {
267
+ console.error(`报错: ${e}`);
268
+ return "对方拒绝了和你ccb";
269
+ }
270
+ } else {
271
+ try {
272
+ const nickname = await getUserNickname(session, targetUserId) || targetUserId;
273
+ const resultMessage = `你和${nickname}发生了${duration}min长的ccb行为,向ta注入了${V.toFixed(2)}ml的生命因子`;
274
+ const message = [
275
+ resultMessage,
276
+ import_koishi.segment.image(getAvatar(targetUserId)),
277
+ "这是ta的初体验。"
278
+ ].join("\n");
279
+ const newRecord = {
280
+ id: targetUserId,
281
+ num: 1,
282
+ vol: V,
283
+ ccb_by: { [senderId]: { count: 1, first: true, max: true } },
284
+ max: V
285
+ };
286
+ groupData.push(newRecord);
287
+ allData[groupId] = groupData;
288
+ await writeData(allData);
289
+ if (config.isLog) {
290
+ try {
291
+ await appendLog(groupId, senderId, targetUserId, duration, V);
292
+ } catch (e) {
293
+ console.warn("记录日志失败:", e);
294
+ }
295
+ }
296
+ if (Math.random() < config.ywProbability) {
297
+ banList[actorId] = now + config.ywBanDuration;
298
+ return message + "\n💥你的牛牛炸膛了!满身疮痍,再起不能(悲)";
299
+ }
300
+ return message;
301
+ } catch (e) {
302
+ console.error(`报错: ${e}`);
303
+ return "对方拒绝了和你ccb";
304
+ }
305
+ }
306
+ });
307
+ ctx.command("ccbtop", "按次数排行", { authority: 1 }).action(async ({ session }) => {
308
+ const groupId = session.guildId;
309
+ if (!groupId) {
310
+ return "此命令只能在群聊中使用。";
311
+ }
312
+ const groupData = (await readData())[groupId] || [];
313
+ if (!groupData.length) {
314
+ return "当前群暂无ccb记录。";
315
+ }
316
+ const top5 = groupData.sort((a, b) => (b.num || 0) - (a.num || 0)).slice(0, 5);
317
+ let msg = "被ccb排行榜 TOP5:\n";
318
+ for (let i = 0; i < top5.length; i++) {
319
+ const r = top5[i];
320
+ const uid = r.id;
321
+ const nick = await getUserNickname(session, uid) || uid;
322
+ msg += `${i + 1}. ${nick} - 次数:${r.num}
323
+ `;
324
+ }
325
+ return msg.trim();
326
+ });
327
+ ctx.command("ccbvol", "按注入量排行", { authority: 1 }).action(async ({ session }) => {
328
+ const groupId = session.guildId;
329
+ if (!groupId) {
330
+ return "此命令只能在群聊中使用。";
331
+ }
332
+ const groupData = (await readData())[groupId] || [];
333
+ if (!groupData.length) {
334
+ return "当前群暂无ccb记录。";
335
+ }
336
+ const top5 = groupData.sort((a, b) => (b.vol || 0) - (a.vol || 0)).slice(0, 5);
337
+ let msg = "被注入量排行榜 TOP5:\n";
338
+ for (let i = 0; i < top5.length; i++) {
339
+ const r = top5[i];
340
+ const uid = r.id;
341
+ const nick = await getUserNickname(session, uid) || uid;
342
+ msg += `${i + 1}. ${nick} - 累计注入:${r.vol.toFixed(2)}ml
343
+ `;
344
+ }
345
+ return msg.trim();
346
+ });
347
+ ctx.command("ccbmax", "按max值排行并输出产生者", { authority: 1 }).action(async ({ session }) => {
348
+ const groupId = session.guildId;
349
+ if (!groupId) {
350
+ return "此命令只能在群聊中使用。";
351
+ }
352
+ const groupData = (await readData())[groupId] || [];
353
+ if (!groupData.length) {
354
+ return "当前群暂无ccb记录。";
355
+ }
356
+ const entries = [];
357
+ for (const r of groupData) {
358
+ let max_val = r.max || 0;
359
+ try {
360
+ if (r.max !== void 0 && r.max !== null) {
361
+ max_val = parseFloat(r.max.toString());
362
+ } else {
363
+ const total_vol = r.vol || 0;
364
+ const total_num = r.num || 0;
365
+ if (total_num > 0) {
366
+ max_val = parseFloat((total_vol / total_num).toFixed(2));
367
+ }
368
+ }
369
+ } catch (error) {
370
+ max_val = 0;
371
+ }
372
+ entries.push([r, max_val]);
373
+ }
374
+ entries.sort((a, b) => b[1] - a[1]);
375
+ const top5 = entries.slice(0, 5);
376
+ let msg = "单次最大注入排行榜 TOP5:\n";
377
+ for (let i = 0; i < top5.length; i++) {
378
+ const [r, max_val] = top5[i];
379
+ const uid = r.id;
380
+ let producer_id = null;
381
+ const ccb_by = r.ccb_by || {};
382
+ for (const actor_id in ccb_by) {
383
+ if (ccb_by[actor_id].max) {
384
+ producer_id = actor_id;
385
+ break;
386
+ }
387
+ }
388
+ if (!producer_id && Object.keys(ccb_by).length > 0) {
389
+ try {
390
+ const entries2 = Object.entries(ccb_by);
391
+ const maxEntry = entries2.reduce(
392
+ ([maxId, maxInfo], [currentId, currentInfo]) => (maxInfo?.count || 0) > (currentInfo?.count || 0) ? [maxId, maxInfo] : [currentId, currentInfo]
393
+ );
394
+ producer_id = maxEntry[0];
395
+ } catch (error) {
396
+ producer_id = null;
397
+ }
398
+ }
399
+ const nick = await getUserNickname(session, uid) || uid;
400
+ const producer_nick = producer_id ? await getUserNickname(session, producer_id) : "未知";
401
+ msg += `${i + 1}. ${nick} - 单次最大:${max_val.toFixed(2)}ml(${producer_nick})
402
+ `;
403
+ }
404
+ return msg.trim();
405
+ });
406
+ ctx.command("ccbinfo [target:user]", "查询某人ccb信息:第一次对他ccb的人,被ccb的总次数,注入总量", { authority: 1 }).action(async ({ session }, target) => {
407
+ const groupId = session.guildId;
408
+ if (!groupId) {
409
+ return "此命令只能在群聊中使用。";
410
+ }
411
+ let targetUserId = session.userId;
412
+ if (target) {
413
+ const match = target.match(/^[^:]+:(.+)$/);
414
+ if (match) {
415
+ targetUserId = match[1];
416
+ }
417
+ }
418
+ const allData = await readData();
419
+ const groupData = allData[groupId] || [];
420
+ const record = groupData.find((r) => r.id === targetUserId);
421
+ if (!record) {
422
+ return "该用户暂无ccb记录。";
423
+ }
424
+ const total_num = record.num || 0;
425
+ const total_vol = record.vol || 0;
426
+ let max_val = 0;
427
+ try {
428
+ if (record.max !== void 0 && record.max !== null) {
429
+ max_val = parseFloat(record.max.toString());
430
+ } else {
431
+ if (total_num > 0) {
432
+ max_val = parseFloat((total_vol / total_num).toFixed(2));
433
+ }
434
+ }
435
+ } catch (error) {
436
+ max_val = 0;
437
+ }
438
+ let cb_total = 0;
439
+ try {
440
+ for (const rec of groupData) {
441
+ const by = rec.ccb_by || {};
442
+ const info = by[targetUserId];
443
+ if (info) {
444
+ cb_total += info.count || 0;
445
+ }
446
+ }
447
+ } catch (error) {
448
+ cb_total = 0;
449
+ }
450
+ let first_actor = null;
451
+ const ccb_by = record.ccb_by || {};
452
+ for (const actor_id in ccb_by) {
453
+ if (ccb_by[actor_id].first) {
454
+ first_actor = actor_id;
455
+ break;
456
+ }
457
+ }
458
+ if (!first_actor && Object.keys(ccb_by).length > 0) {
459
+ const entries = Object.entries(ccb_by);
460
+ const maxEntry = entries.reduce(
461
+ ([maxId, maxInfo], [currentId, currentInfo]) => (maxInfo?.count || 0) > (currentInfo?.count || 0) ? [maxId, maxInfo] : [currentId, currentInfo]
462
+ );
463
+ first_actor = maxEntry[0];
464
+ }
465
+ const first_nick = first_actor ? await getUserNickname(session, first_actor) : "未知";
466
+ const target_nick = await getUserNickname(session, targetUserId) || targetUserId;
467
+ const msg = [
468
+ `【${target_nick} 】`,
469
+ `• 破壁人:${first_nick || "未知"}`,
470
+ `• 北朝:${total_num}`,
471
+ `• 朝壁:${cb_total}`,
472
+ `• 诗经:${total_vol.toFixed(2)}ml`,
473
+ `• 马克思:${max_val.toFixed(2)}ml`
474
+ ].join("\n");
475
+ return msg;
476
+ });
477
+ ctx.command("xnn", "XNN榜 - 计算群中最xnn特质的群友", { authority: 1 }).action(async ({ session }) => {
478
+ const w_num = 1;
479
+ const w_vol = 0.1;
480
+ const w_action = 0.5;
481
+ const groupId = session.guildId;
482
+ if (!groupId) {
483
+ return "此命令只能在群聊中使用。";
484
+ }
485
+ const allData = await readData();
486
+ const groupData = allData[groupId] || [];
487
+ if (!groupData.length) {
488
+ return "当前群暂无ccb记录。";
489
+ }
490
+ const actorActions = {};
491
+ for (const record of groupData) {
492
+ const ccb_by = record.ccb_by || {};
493
+ for (const actor_id in ccb_by) {
494
+ actorActions[actor_id] = (actorActions[actor_id] || 0) + (ccb_by[actor_id].count || 0);
495
+ }
496
+ }
497
+ const ranking = [];
498
+ for (const record of groupData) {
499
+ const uid = record.id;
500
+ const num = record.num || 0;
501
+ const vol = record.vol || 0;
502
+ const actions = actorActions[uid] || 0;
503
+ const xnn_value = num * w_num + vol * w_vol - actions * w_action;
504
+ ranking.push([uid, xnn_value]);
505
+ }
506
+ ranking.sort((a, b) => b[1] - a[1]);
507
+ const top5 = ranking.slice(0, 5);
508
+ let msg = "💎 小南梁 TOP5 💎\n";
509
+ for (let i = 0; i < top5.length; i++) {
510
+ const [uid, xnn_val] = top5[i];
511
+ const nick = await getUserNickname(session, uid) || uid;
512
+ msg += `${i + 1}. ${nick} - XNN值:${xnn_val.toFixed(2)}
513
+ `;
514
+ }
515
+ return msg.trim();
516
+ });
517
+ }
518
+ __name(apply, "apply");
519
+ // Annotate the CommonJS export names for ESM import in node:
520
+ 0 && (module.exports = {
521
+ Config,
522
+ apply,
523
+ name
524
+ });
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "koishi-plugin-ccb-plus",
3
+ "description": "Koshi插件,与群友发生ccb行为。(移植自astrbot_plugin_ccb_plus)",
4
+ "version": "0.0.1",
5
+ "main": "lib/index.js",
6
+ "typings": "lib/index.d.ts",
7
+ "files": [
8
+ "lib",
9
+ "dist"
10
+ ],
11
+ "license": "AGPL-3.0-only",
12
+ "keywords": [
13
+ "chatbot",
14
+ "koishi",
15
+ "plugin",
16
+ "ccb",
17
+ "group"
18
+ ],
19
+ "peerDependencies": {
20
+ "koishi": "^4.18.7"
21
+ }
22
+ }
package/readme.md ADDED
@@ -0,0 +1,11 @@
1
+ # koishi-plugin-ccb-plus
2
+
3
+ [![npm](https://img.shields.io/npm/v/koishi-plugin-ccb-plus?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-ccb-plus)
4
+
5
+ Koshi插件,与群友发生ccb行为。(移植自astrbot_plugin_ccb_plus)
6
+
7
+ 原插件:[Koikokokokoro/astrbot_plugin_ccb_plus](https://github.com/Koikokokokoro/astrbot_plugin_ccb_plus)
8
+
9
+ 以后会进行小幅修改
10
+
11
+ > 使用Qwen3-Coder协助完成