@zhin.js/adapter-kook 5.0.1 → 5.0.2
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/CHANGELOG.md +19 -0
- package/README.md +1 -0
- package/agent/tools/blacklist.ts +33 -0
- package/agent/tools/create_role.ts +25 -0
- package/agent/tools/delete_role.ts +21 -0
- package/agent/tools/grant_role.ts +22 -0
- package/agent/tools/list_roles.ts +27 -0
- package/agent/tools/revoke_role.ts +22 -0
- package/lib/agent/tools/blacklist.js +33 -0
- package/lib/agent/tools/blacklist.js.map +1 -0
- package/lib/agent/tools/create_role.js +25 -0
- package/lib/agent/tools/create_role.js.map +1 -0
- package/lib/agent/tools/delete_role.js +21 -0
- package/lib/agent/tools/delete_role.js.map +1 -0
- package/lib/agent/tools/grant_role.js +22 -0
- package/lib/agent/tools/grant_role.js.map +1 -0
- package/lib/agent/tools/list_roles.js +27 -0
- package/lib/agent/tools/list_roles.js.map +1 -0
- package/lib/agent/tools/revoke_role.js +22 -0
- package/lib/agent/tools/revoke_role.js.map +1 -0
- package/lib/{adapter.js → src/adapter.js} +1 -1
- package/lib/src/adapter.js.map +1 -0
- package/lib/{endpoint.js → src/endpoint.js} +76 -55
- package/lib/src/endpoint.js.map +1 -0
- package/lib/src/index.js +197 -0
- package/lib/src/index.js.map +1 -0
- package/lib/src/kook-agent-deps.js +10 -0
- package/lib/src/kook-agent-deps.js.map +1 -0
- package/lib/src/kook-asset-upload.js.map +1 -0
- package/lib/src/kook-inbound.js.map +1 -0
- package/lib/src/kook-msg-route.js.map +1 -0
- package/lib/{kook-side-events.js → src/kook-side-events.js} +11 -34
- package/lib/src/kook-side-events.js.map +1 -0
- package/lib/{outbound-keyboard.js → src/outbound-keyboard.js} +4 -1
- package/lib/src/outbound-keyboard.js.map +1 -0
- package/lib/{outbound-media.js → src/outbound-media.js} +4 -1
- package/lib/src/outbound-media.js.map +1 -0
- package/lib/src/outbound-sendable.js.map +1 -0
- package/lib/{platform-permit.js → src/platform-permit.js} +3 -0
- package/lib/src/platform-permit.js.map +1 -0
- package/lib/src/segment-mapper.js.map +1 -0
- package/lib/src/types.js.map +1 -0
- package/package.json +25 -15
- package/src/adapter.ts +2 -3
- package/src/endpoint.ts +77 -64
- package/src/index.ts +10 -164
- package/src/kook-agent-deps.ts +22 -0
- package/src/kook-side-events.ts +19 -39
- package/src/outbound-keyboard.ts +1 -2
- package/src/outbound-media.ts +1 -8
- package/src/platform-permit.ts +3 -4
- package/src/types.ts +1 -2
- package/lib/adapter.d.ts +0 -30
- package/lib/adapter.d.ts.map +0 -1
- package/lib/adapter.js.map +0 -1
- package/lib/endpoint.d.ts +0 -155
- package/lib/endpoint.d.ts.map +0 -1
- package/lib/endpoint.js.map +0 -1
- package/lib/index.d.ts +0 -18
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js +0 -350
- package/lib/index.js.map +0 -1
- package/lib/kook-asset-upload.d.ts +0 -12
- package/lib/kook-asset-upload.d.ts.map +0 -1
- package/lib/kook-asset-upload.js.map +0 -1
- package/lib/kook-inbound.d.ts +0 -6
- package/lib/kook-inbound.d.ts.map +0 -1
- package/lib/kook-inbound.js.map +0 -1
- package/lib/kook-msg-route.d.ts +0 -34
- package/lib/kook-msg-route.d.ts.map +0 -1
- package/lib/kook-msg-route.js.map +0 -1
- package/lib/kook-side-events.d.ts +0 -46
- package/lib/kook-side-events.d.ts.map +0 -1
- package/lib/kook-side-events.js.map +0 -1
- package/lib/outbound-keyboard.d.ts +0 -13
- package/lib/outbound-keyboard.d.ts.map +0 -1
- package/lib/outbound-keyboard.js.map +0 -1
- package/lib/outbound-media.d.ts +0 -10
- package/lib/outbound-media.d.ts.map +0 -1
- package/lib/outbound-media.js.map +0 -1
- package/lib/outbound-sendable.d.ts +0 -12
- package/lib/outbound-sendable.d.ts.map +0 -1
- package/lib/outbound-sendable.js.map +0 -1
- package/lib/platform-permit.d.ts +0 -14
- package/lib/platform-permit.d.ts.map +0 -1
- package/lib/platform-permit.js.map +0 -1
- package/lib/segment-mapper.d.ts +0 -2
- package/lib/segment-mapper.d.ts.map +0 -1
- package/lib/segment-mapper.js.map +0 -1
- package/lib/types.d.ts +0 -54
- package/lib/types.d.ts.map +0 -1
- package/lib/types.js.map +0 -1
- /package/{skills/kook → agent}/PERMITS.md +0 -0
- /package/{skills/kook/SKILL.md → agent/skills/kook.md} +0 -0
- /package/lib/{kook-asset-upload.js → src/kook-asset-upload.js} +0 -0
- /package/lib/{kook-inbound.js → src/kook-inbound.js} +0 -0
- /package/lib/{kook-msg-route.js → src/kook-msg-route.js} +0 -0
- /package/lib/{outbound-sendable.js → src/outbound-sendable.js} +0 -0
- /package/lib/{segment-mapper.js → src/segment-mapper.js} +0 -0
- /package/lib/{types.js → src/types.js} +0 -0
package/src/endpoint.ts
CHANGED
|
@@ -22,8 +22,8 @@ import {
|
|
|
22
22
|
segment,
|
|
23
23
|
expandInteractiveSegmentsInContent,
|
|
24
24
|
MessageType,} from 'zhin.js';
|
|
25
|
-
import type
|
|
26
|
-
|
|
25
|
+
import { KookPermission, type KookEndpointConfig, type KookSenderInfo, type KookRawMessage } from './types.js';
|
|
26
|
+
|
|
27
27
|
import type { KookAdapter } from "./adapter.js";
|
|
28
28
|
import { InboundMessageDeduper } from "./kook-inbound.js";
|
|
29
29
|
import { normalizeKookSenderForPermit } from "./platform-permit.js";
|
|
@@ -508,73 +508,17 @@ export class KookEndpoint extends Client implements Endpoint<KookEndpointConfig,
|
|
|
508
508
|
|
|
509
509
|
private parseMarkdown(content: string): MessageElement[] {
|
|
510
510
|
const elements: MessageElement[] = [];
|
|
511
|
-
|
|
512
|
-
// KMarkdown 图片格式: 
|
|
513
|
-
const imageRegex = /!\[([^\]]*)\]\(([^)]+)\)/g;
|
|
514
|
-
// KMarkdown @提及格式: (met)userId(met) 或 @用户名
|
|
515
|
-
const mentionRegex = /\(met\)(\d+)\(met\)|@([^\s]+)/g;
|
|
516
|
-
// KMarkdown 表情格式: (emj)表情名(emj)[表情ID]
|
|
517
|
-
const emojiRegex = /\(emj\)([^(]+)\(emj\)\[([^\]]+)\]/g;
|
|
518
|
-
// KMarkdown 频道格式: (chn)channelId(chn)
|
|
519
|
-
const channelRegex = /\(chn\)(\d+)\(chn\)/g;
|
|
520
|
-
|
|
521
511
|
let lastIndex = 0;
|
|
522
|
-
const
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
let match: RegExpExecArray | null;
|
|
526
|
-
while ((match = imageRegex.exec(content)) !== null) {
|
|
527
|
-
matches.push({
|
|
528
|
-
index: match.index,
|
|
529
|
-
length: match[0].length,
|
|
530
|
-
element: { type: "image", data: { url: match[2], alt: match[1] } }
|
|
531
|
-
});
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
// 解析 @提及
|
|
535
|
-
while ((match = mentionRegex.exec(content)) !== null) {
|
|
536
|
-
const userId = match[1] || match[2];
|
|
537
|
-
matches.push({
|
|
538
|
-
index: match.index,
|
|
539
|
-
length: match[0].length,
|
|
540
|
-
element: this.buildAtElement(userId),
|
|
541
|
-
});
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
// 解析表情
|
|
545
|
-
while ((match = emojiRegex.exec(content)) !== null) {
|
|
546
|
-
matches.push({
|
|
547
|
-
index: match.index,
|
|
548
|
-
length: match[0].length,
|
|
549
|
-
element: { type: "face", data: { id: match[2], name: match[1] } }
|
|
550
|
-
});
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
// 解析频道引用
|
|
554
|
-
while ((match = channelRegex.exec(content)) !== null) {
|
|
555
|
-
matches.push({
|
|
556
|
-
index: match.index,
|
|
557
|
-
length: match[0].length,
|
|
558
|
-
element: { type: "text", data: { text: `#频道:${match[1]}` } }
|
|
559
|
-
});
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
// 按位置排序
|
|
563
|
-
matches.sort((a, b) => a.index - b.index);
|
|
564
|
-
|
|
565
|
-
// 组装消息段
|
|
566
|
-
for (const match of matches) {
|
|
567
|
-
// 添加之前的文本
|
|
568
|
-
if (match.index > lastIndex) {
|
|
569
|
-
const text = content.slice(lastIndex, match.index);
|
|
512
|
+
for (const token of this.scanKMarkdownTokens(content)) {
|
|
513
|
+
if (token.index > lastIndex) {
|
|
514
|
+
const text = content.slice(lastIndex, token.index);
|
|
570
515
|
if (text) {
|
|
571
516
|
elements.push({ type: "text", data: { text } });
|
|
572
517
|
}
|
|
573
518
|
}
|
|
574
519
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
lastIndex = match.index + match.length;
|
|
520
|
+
elements.push(token.element);
|
|
521
|
+
lastIndex = token.index + token.length;
|
|
578
522
|
}
|
|
579
523
|
|
|
580
524
|
// 添加剩余文本
|
|
@@ -661,7 +605,76 @@ export class KookEndpoint extends Client implements Endpoint<KookEndpointConfig,
|
|
|
661
605
|
* 检查文本是否包含 KMarkdown 特殊语法
|
|
662
606
|
*/
|
|
663
607
|
private hasKMarkdownSyntax(text: string): boolean {
|
|
664
|
-
return
|
|
608
|
+
return text.includes('![')
|
|
609
|
+
|| text.includes('(met)')
|
|
610
|
+
|| text.includes('(emj)')
|
|
611
|
+
|| text.includes('(chn)')
|
|
612
|
+
|| text.includes('@');
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
private scanKMarkdownTokens(content: string): Array<{ index: number; length: number; element: MessageElement }> {
|
|
616
|
+
const tokens: Array<{ index: number; length: number; element: MessageElement }> = [];
|
|
617
|
+
let i = 0;
|
|
618
|
+
while (i < content.length) {
|
|
619
|
+
const token = this.readKMarkdownToken(content, i);
|
|
620
|
+
if (token) {
|
|
621
|
+
tokens.push(token);
|
|
622
|
+
i = token.index + token.length;
|
|
623
|
+
} else {
|
|
624
|
+
i++;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
return tokens;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
private readKMarkdownToken(content: string, index: number): { index: number; length: number; element: MessageElement } | null {
|
|
631
|
+
if (content.startsWith('![', index)) {
|
|
632
|
+
const labelEnd = content.indexOf(']', index + 2);
|
|
633
|
+
if (labelEnd >= 0 && content[labelEnd + 1] === '(') {
|
|
634
|
+
const urlEnd = content.indexOf(')', labelEnd + 2);
|
|
635
|
+
if (urlEnd >= 0) {
|
|
636
|
+
return {
|
|
637
|
+
index,
|
|
638
|
+
length: urlEnd + 1 - index,
|
|
639
|
+
element: { type: "image", data: { url: content.slice(labelEnd + 2, urlEnd), alt: content.slice(index + 2, labelEnd) } },
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
if (content.startsWith('(met)', index)) {
|
|
645
|
+
const idStart = index + '(met)'.length;
|
|
646
|
+
const idEnd = content.indexOf('(met)', idStart);
|
|
647
|
+
if (idEnd > idStart) {
|
|
648
|
+
return { index, length: idEnd + '(met)'.length - index, element: this.buildAtElement(content.slice(idStart, idEnd)) };
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
if (content[index] === '@') {
|
|
652
|
+
let end = index + 1;
|
|
653
|
+
while (end < content.length && !/\s/.test(content[end]!)) end++;
|
|
654
|
+
if (end > index + 1) {
|
|
655
|
+
return { index, length: end - index, element: this.buildAtElement(content.slice(index + 1, end)) };
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
if (content.startsWith('(emj)', index)) {
|
|
659
|
+
const nameStart = index + '(emj)'.length;
|
|
660
|
+
const nameEnd = content.indexOf('(emj)[', nameStart);
|
|
661
|
+
const idEnd = nameEnd >= 0 ? content.indexOf(']', nameEnd + 6) : -1;
|
|
662
|
+
if (nameEnd > nameStart && idEnd > nameEnd) {
|
|
663
|
+
return {
|
|
664
|
+
index,
|
|
665
|
+
length: idEnd + 1 - index,
|
|
666
|
+
element: { type: "face", data: { id: content.slice(nameEnd + 6, idEnd), name: content.slice(nameStart, nameEnd) } },
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
if (content.startsWith('(chn)', index)) {
|
|
671
|
+
const idStart = index + '(chn)'.length;
|
|
672
|
+
const idEnd = content.indexOf('(chn)', idStart);
|
|
673
|
+
if (idEnd > idStart) {
|
|
674
|
+
return { index, length: idEnd + '(chn)'.length - index, element: { type: "text", data: { text: `#频道:${content.slice(idStart, idEnd)}` } } };
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
return null;
|
|
665
678
|
}
|
|
666
679
|
|
|
667
680
|
/**
|
package/src/index.ts
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { usePlugin, type Plugin, type ISceneManagement, createSceneManagementTools, type ToolFeature } from "zhin.js";
|
|
6
6
|
import { KookAdapter } from "./adapter.js";
|
|
7
|
-
import { kookGroupPermitResolver,
|
|
7
|
+
import { kookGroupPermitResolver, registerKookPlatformPermitChecker } from "./platform-permit.js";
|
|
8
|
+
import { setKookAgentDeps } from "./kook-agent-deps.js";
|
|
8
9
|
import { PageManager } from "@zhin.js/host-api";
|
|
9
10
|
|
|
10
11
|
declare module "zhin.js" {
|
|
@@ -44,6 +45,14 @@ provide({
|
|
|
44
45
|
useContext('tool', 'kook', (toolService: ToolFeature, kook: KookAdapter) => {
|
|
45
46
|
const disposers: (() => void)[] = [];
|
|
46
47
|
disposers.push(registerKookPlatformPermitChecker());
|
|
48
|
+
setKookAgentDeps({
|
|
49
|
+
getEndpoint: (endpointId) => {
|
|
50
|
+
const endpoint = kook.endpoints.get(endpointId);
|
|
51
|
+
if (!endpoint) throw new Error(`Endpoint ${endpointId} 不存在`);
|
|
52
|
+
return endpoint;
|
|
53
|
+
},
|
|
54
|
+
getAdapter: () => kook,
|
|
55
|
+
});
|
|
47
56
|
const sceneTools = createSceneManagementTools(
|
|
48
57
|
kook as unknown as ISceneManagement,
|
|
49
58
|
'kook',
|
|
@@ -51,169 +60,6 @@ useContext('tool', 'kook', (toolService: ToolFeature, kook: KookAdapter) => {
|
|
|
51
60
|
);
|
|
52
61
|
disposers.push(...sceneTools.map(t => toolService.addTool(t, plugin.name)));
|
|
53
62
|
|
|
54
|
-
disposers.push(toolService.addTool({
|
|
55
|
-
name: 'kook_grant_role',
|
|
56
|
-
description: '给用户授予 KOOK 服务器角色',
|
|
57
|
-
parameters: {
|
|
58
|
-
type: 'object',
|
|
59
|
-
properties: {
|
|
60
|
-
endpoint_id: { type: 'string', description: 'Endpoint 名称', contextKey: 'endpointId' },
|
|
61
|
-
guild_id: { type: 'string', description: '服务器 ID' },
|
|
62
|
-
user_id: { type: 'string', description: '用户 ID' },
|
|
63
|
-
role_id: { type: 'string', description: '角色 ID' },
|
|
64
|
-
},
|
|
65
|
-
required: ['endpoint_id', 'guild_id', 'user_id', 'role_id'],
|
|
66
|
-
},
|
|
67
|
-
platforms: ['kook'],
|
|
68
|
-
tags: ['kook'],
|
|
69
|
-
permissions: [platformPermit('manage_roles')],
|
|
70
|
-
execute: async (args: Record<string, any>) => {
|
|
71
|
-
const endpoint = kook.endpoints.get(args.endpoint_id);
|
|
72
|
-
if (!endpoint) throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
|
|
73
|
-
const success = await endpoint.grantRole(args.guild_id, args.user_id, args.role_id);
|
|
74
|
-
return { success, message: success ? `已授予用户 ${args.user_id} 角色 ${args.role_id}` : '授予角色失败' };
|
|
75
|
-
},
|
|
76
|
-
}, plugin.name));
|
|
77
|
-
|
|
78
|
-
disposers.push(toolService.addTool({
|
|
79
|
-
name: 'kook_revoke_role',
|
|
80
|
-
description: '撤销用户的 KOOK 服务器角色',
|
|
81
|
-
parameters: {
|
|
82
|
-
type: 'object',
|
|
83
|
-
properties: {
|
|
84
|
-
endpoint_id: { type: 'string', description: 'Endpoint 名称', contextKey: 'endpointId' },
|
|
85
|
-
guild_id: { type: 'string', description: '服务器 ID' },
|
|
86
|
-
user_id: { type: 'string', description: '用户 ID' },
|
|
87
|
-
role_id: { type: 'string', description: '角色 ID' },
|
|
88
|
-
},
|
|
89
|
-
required: ['endpoint_id', 'guild_id', 'user_id', 'role_id'],
|
|
90
|
-
},
|
|
91
|
-
platforms: ['kook'],
|
|
92
|
-
tags: ['kook'],
|
|
93
|
-
permissions: [platformPermit('manage_roles')],
|
|
94
|
-
execute: async (args: Record<string, any>) => {
|
|
95
|
-
const endpoint = kook.endpoints.get(args.endpoint_id);
|
|
96
|
-
if (!endpoint) throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
|
|
97
|
-
const success = await endpoint.revokeRole(args.guild_id, args.user_id, args.role_id);
|
|
98
|
-
return { success, message: success ? `已撤销用户 ${args.user_id} 的角色 ${args.role_id}` : '撤销角色失败' };
|
|
99
|
-
},
|
|
100
|
-
}, plugin.name));
|
|
101
|
-
|
|
102
|
-
disposers.push(toolService.addTool({
|
|
103
|
-
name: 'kook_list_roles',
|
|
104
|
-
description: '获取 KOOK 服务器的角色列表',
|
|
105
|
-
parameters: {
|
|
106
|
-
type: 'object',
|
|
107
|
-
properties: {
|
|
108
|
-
endpoint_id: { type: 'string', description: 'Endpoint 名称', contextKey: 'endpointId' },
|
|
109
|
-
guild_id: { type: 'string', description: '服务器 ID' },
|
|
110
|
-
},
|
|
111
|
-
required: ['endpoint_id', 'guild_id'],
|
|
112
|
-
},
|
|
113
|
-
platforms: ['kook'],
|
|
114
|
-
tags: ['kook'],
|
|
115
|
-
execute: async (args: Record<string, any>) => {
|
|
116
|
-
const endpoint = kook.endpoints.get(args.endpoint_id);
|
|
117
|
-
if (!endpoint) throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
|
|
118
|
-
const roles = await endpoint.getRoleList(args.guild_id);
|
|
119
|
-
return {
|
|
120
|
-
roles: roles.map((r: any) => ({
|
|
121
|
-
id: r.role_id,
|
|
122
|
-
name: r.name,
|
|
123
|
-
color: r.color,
|
|
124
|
-
position: r.position,
|
|
125
|
-
permissions: r.permissions,
|
|
126
|
-
})),
|
|
127
|
-
count: roles.length,
|
|
128
|
-
};
|
|
129
|
-
},
|
|
130
|
-
}, plugin.name));
|
|
131
|
-
|
|
132
|
-
disposers.push(toolService.addTool({
|
|
133
|
-
name: 'kook_create_role',
|
|
134
|
-
description: '在 KOOK 服务器中创建新角色',
|
|
135
|
-
parameters: {
|
|
136
|
-
type: 'object',
|
|
137
|
-
properties: {
|
|
138
|
-
endpoint_id: { type: 'string', description: 'Endpoint 名称', contextKey: 'endpointId' },
|
|
139
|
-
guild_id: { type: 'string', description: '服务器 ID' },
|
|
140
|
-
name: { type: 'string', description: '角色名称' },
|
|
141
|
-
},
|
|
142
|
-
required: ['endpoint_id', 'guild_id', 'name'],
|
|
143
|
-
},
|
|
144
|
-
platforms: ['kook'],
|
|
145
|
-
tags: ['kook'],
|
|
146
|
-
permissions: [platformPermit('guild_owner')],
|
|
147
|
-
execute: async (args: Record<string, any>) => {
|
|
148
|
-
const endpoint = kook.endpoints.get(args.endpoint_id);
|
|
149
|
-
if (!endpoint) throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
|
|
150
|
-
const role = await endpoint.createRole(args.guild_id, args.name);
|
|
151
|
-
return {
|
|
152
|
-
success: true,
|
|
153
|
-
message: `已创建角色 "${args.name}"`,
|
|
154
|
-
role: { id: role.role_id, name: role.name },
|
|
155
|
-
};
|
|
156
|
-
},
|
|
157
|
-
}, plugin.name));
|
|
158
|
-
|
|
159
|
-
disposers.push(toolService.addTool({
|
|
160
|
-
name: 'kook_delete_role',
|
|
161
|
-
description: '删除 KOOK 服务器中的角色',
|
|
162
|
-
parameters: {
|
|
163
|
-
type: 'object',
|
|
164
|
-
properties: {
|
|
165
|
-
endpoint_id: { type: 'string', description: 'Endpoint 名称', contextKey: 'endpointId' },
|
|
166
|
-
guild_id: { type: 'string', description: '服务器 ID' },
|
|
167
|
-
role_id: { type: 'string', description: '角色 ID' },
|
|
168
|
-
},
|
|
169
|
-
required: ['endpoint_id', 'guild_id', 'role_id'],
|
|
170
|
-
},
|
|
171
|
-
platforms: ['kook'],
|
|
172
|
-
tags: ['kook'],
|
|
173
|
-
permissions: [platformPermit('guild_owner')],
|
|
174
|
-
execute: async (args: Record<string, any>) => {
|
|
175
|
-
const endpoint = kook.endpoints.get(args.endpoint_id);
|
|
176
|
-
if (!endpoint) throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
|
|
177
|
-
const success = await endpoint.deleteRole(args.guild_id, args.role_id);
|
|
178
|
-
return { success, message: success ? `已删除角色 ${args.role_id}` : '删除角色失败' };
|
|
179
|
-
},
|
|
180
|
-
}, plugin.name));
|
|
181
|
-
|
|
182
|
-
disposers.push(toolService.addTool({
|
|
183
|
-
name: 'kook_blacklist',
|
|
184
|
-
description: 'KOOK 服务器黑名单管理:添加/移除',
|
|
185
|
-
parameters: {
|
|
186
|
-
type: 'object',
|
|
187
|
-
properties: {
|
|
188
|
-
endpoint_id: { type: 'string', description: 'Endpoint 名称', contextKey: 'endpointId' },
|
|
189
|
-
guild_id: { type: 'string', description: '服务器 ID' },
|
|
190
|
-
action: { type: 'string', description: 'add|remove', enum: ['add', 'remove'] },
|
|
191
|
-
user_id: { type: 'string', description: '用户 ID' },
|
|
192
|
-
remark: { type: 'string', description: '备注(add 可选)' },
|
|
193
|
-
},
|
|
194
|
-
required: ['endpoint_id', 'guild_id', 'action', 'user_id'],
|
|
195
|
-
},
|
|
196
|
-
platforms: ['kook'],
|
|
197
|
-
tags: ['kook'],
|
|
198
|
-
permissions: [platformPermit('guild_admin')],
|
|
199
|
-
execute: async (args: Record<string, any>) => {
|
|
200
|
-
const endpoint = kook.endpoints.get(args.endpoint_id);
|
|
201
|
-
if (!endpoint) throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
|
|
202
|
-
switch (args.action) {
|
|
203
|
-
case 'add': {
|
|
204
|
-
const success = await endpoint.addToBlacklist(args.guild_id, args.user_id, args.remark);
|
|
205
|
-
return { success, message: success ? `已将 ${args.user_id} 加入黑名单` : '操作失败' };
|
|
206
|
-
}
|
|
207
|
-
case 'remove': {
|
|
208
|
-
const success = await endpoint.removeFromBlacklist(args.guild_id, args.user_id);
|
|
209
|
-
return { success, message: success ? `已将 ${args.user_id} 从黑名单移除` : '操作失败' };
|
|
210
|
-
}
|
|
211
|
-
default:
|
|
212
|
-
return { success: false, message: `未知操作: ${args.action}` };
|
|
213
|
-
}
|
|
214
|
-
},
|
|
215
|
-
}, plugin.name));
|
|
216
|
-
|
|
217
63
|
return () => disposers.forEach(d => d());
|
|
218
64
|
});
|
|
219
65
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared runtime deps for kook agent/ authoring tools.
|
|
3
|
+
* Set once from plugin index during init — never call getPlugin() from tool execute.
|
|
4
|
+
*/
|
|
5
|
+
import type { KookAdapter } from './adapter.js';
|
|
6
|
+
import type { KookEndpoint } from './endpoint.js';
|
|
7
|
+
|
|
8
|
+
export interface KookAgentDeps {
|
|
9
|
+
getEndpoint: (endpointId: string) => KookEndpoint;
|
|
10
|
+
getAdapter: () => KookAdapter;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let _deps: KookAgentDeps | null = null;
|
|
14
|
+
|
|
15
|
+
export function setKookAgentDeps(deps: KookAgentDeps): void {
|
|
16
|
+
_deps = deps;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function getKookAgentDeps(): KookAgentDeps {
|
|
20
|
+
if (!_deps) throw new Error('kook agent deps not initialized');
|
|
21
|
+
return _deps;
|
|
22
|
+
}
|
package/src/kook-side-events.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* KOOK Gateway 非聊天入站:系统消息 (type=255) / BROADCAST → Notice
|
|
3
|
-
* @see https://developer.kookapp.cn/doc/event/event-introduction
|
|
4
3
|
*/
|
|
5
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
Notice,
|
|
6
|
+
Message,
|
|
7
|
+
mapNoticeParts,
|
|
8
|
+
senderFromId,
|
|
9
|
+
buildNotice,
|
|
10
|
+
formatCompact,
|
|
11
|
+
} from "zhin.js";
|
|
6
12
|
|
|
7
|
-
/** KOOK WebSocket s=0 时 d 字段(kook-client Receiver 入参) */
|
|
8
13
|
export interface KookGatewayEvent {
|
|
9
14
|
channel_type?: string;
|
|
10
15
|
type?: number;
|
|
@@ -30,7 +35,6 @@ export interface KookGatewayExtra {
|
|
|
30
35
|
|
|
31
36
|
const SYSTEM_MESSAGE_TYPE = 255;
|
|
32
37
|
|
|
33
|
-
/** 是否应由适配器作为 notice 处理(kook-client 对 notice 的 transform 为空实现) */
|
|
34
38
|
export function isKookNoticeGatewayEvent(data: unknown): data is KookGatewayEvent {
|
|
35
39
|
if (!data || typeof data !== "object") return false;
|
|
36
40
|
const ev = data as KookGatewayEvent;
|
|
@@ -50,34 +54,12 @@ export function resolveKookSideEventDedupeKey(
|
|
|
50
54
|
return `${kind}:${ts}_${noticeType}_${scope}`;
|
|
51
55
|
}
|
|
52
56
|
|
|
53
|
-
const NOTICE_TYPE_MAP: Record<string, NoticeType> = {
|
|
54
|
-
joined_guild: "group_member_increase",
|
|
55
|
-
exited_guild: "group_member_decrease",
|
|
56
|
-
deleted_message: "group_recall",
|
|
57
|
-
deleted_private_message: "friend_recall",
|
|
58
|
-
added_reaction: "group_emoji_reaction",
|
|
59
|
-
deleted_reaction: "group_emoji_reaction",
|
|
60
|
-
private_added_reaction: "group_emoji_reaction",
|
|
61
|
-
private_deleted_reaction: "group_emoji_reaction",
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
function resolveNoticeZhinType(rawType: string): NoticeType {
|
|
65
|
-
return NOTICE_TYPE_MAP[rawType] ?? rawType;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function senderFromId(id: unknown, name?: string) {
|
|
69
|
-
if (id == null || id === "") return undefined;
|
|
70
|
-
const s = String(id);
|
|
71
|
-
return { id: s, name: name ?? s };
|
|
72
|
-
}
|
|
73
|
-
|
|
74
57
|
function readString(obj: Record<string, unknown> | undefined, key: string): string | undefined {
|
|
75
58
|
const v = obj?.[key];
|
|
76
59
|
if (v == null || v === "") return undefined;
|
|
77
60
|
return String(v);
|
|
78
61
|
}
|
|
79
62
|
|
|
80
|
-
/** 解析 notice 发生的频道 / 群 / 私聊 */
|
|
81
63
|
export function resolveKookNoticeChannel(
|
|
82
64
|
event: KookGatewayEvent,
|
|
83
65
|
): { id: string; type: "group" | "private" | "channel" } {
|
|
@@ -161,11 +143,11 @@ export function enrichKookGatewayForPlugins(event: KookGatewayEvent): KookGatewa
|
|
|
161
143
|
export function formatKookNotice(
|
|
162
144
|
event: KookGatewayEvent,
|
|
163
145
|
endpointName: string,
|
|
164
|
-
)
|
|
146
|
+
) {
|
|
165
147
|
const extra = event.extra ?? {};
|
|
166
148
|
const body = extra.body ?? {};
|
|
167
149
|
const rawType = String(extra.type ?? "unknown");
|
|
168
|
-
const
|
|
150
|
+
const { scene_type, sub_type } = mapNoticeParts('kook', rawType);
|
|
169
151
|
const channel = resolveKookNoticeChannel(event);
|
|
170
152
|
const ts = event.msg_timestamp ?? Date.now();
|
|
171
153
|
|
|
@@ -177,16 +159,15 @@ export function formatKookNotice(
|
|
|
177
159
|
readString(body, "operator_id")
|
|
178
160
|
?? (event.author_id !== "1" ? event.author_id : undefined);
|
|
179
161
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
return Notice.from(event, {
|
|
162
|
+
return buildNotice(event, {
|
|
183
163
|
$id: resolveKookSideEventDedupeKey(event, "notice"),
|
|
184
164
|
$adapter: "kook",
|
|
185
165
|
$endpoint: endpointName,
|
|
186
|
-
$type,
|
|
187
|
-
$
|
|
188
|
-
$
|
|
189
|
-
$
|
|
166
|
+
$type: "notice",
|
|
167
|
+
$scene_id: channel.id,
|
|
168
|
+
$scene_type: scene_type,
|
|
169
|
+
$sub_type: sub_type,
|
|
170
|
+
$actor: senderFromId(operatorId),
|
|
190
171
|
$target: senderFromId(targetId),
|
|
191
172
|
$timestamp: ts,
|
|
192
173
|
});
|
|
@@ -194,14 +175,13 @@ export function formatKookNotice(
|
|
|
194
175
|
|
|
195
176
|
export function formatKookNoticeLog(notice: ReturnType<typeof formatKookNotice>): string {
|
|
196
177
|
return formatCompact({
|
|
197
|
-
notice: notice.$type
|
|
198
|
-
kook_type: notice.$
|
|
199
|
-
|
|
178
|
+
notice: `${notice.$type}.${notice.$scene_type}.${notice.$sub_type}`,
|
|
179
|
+
kook_type: notice.$sub_type,
|
|
180
|
+
scene: `${notice.$scene_type}(${notice.$scene_id})`,
|
|
200
181
|
endpoint: notice.$endpoint,
|
|
201
182
|
});
|
|
202
183
|
}
|
|
203
184
|
|
|
204
|
-
/** KOOK 卡片按钮点击(type=255, extra.type=message_btn_click) */
|
|
205
185
|
export function isKookButtonClickEvent(event: KookGatewayEvent): boolean {
|
|
206
186
|
return event.type === SYSTEM_MESSAGE_TYPE && event.extra?.type === 'message_btn_click';
|
|
207
187
|
}
|
package/src/outbound-keyboard.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* core keyboard 段 → KOOK 卡片消息(action-group + button)
|
|
3
3
|
*/
|
|
4
|
-
import type
|
|
5
|
-
import { KeyboardSegment, isKeyboardSegment } from "zhin.js";
|
|
4
|
+
import { KeyboardSegment, isKeyboardSegment, type KeyboardSegmentData, type MessageElement } from 'zhin.js';
|
|
6
5
|
|
|
7
6
|
function asKeyboardElement(
|
|
8
7
|
el: MessageElement,
|
package/src/outbound-media.ts
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* KOOK 出站 media:base64 / 本地文件须先走 /v3/asset/create 上传,再嵌入 KMarkdown。
|
|
3
3
|
*/
|
|
4
|
-
import type
|
|
5
|
-
import {
|
|
6
|
-
asMessageElements,
|
|
7
|
-
extractBase64Buffer,
|
|
8
|
-
isMediaSegmentType,
|
|
9
|
-
isRemoteUrl,
|
|
10
|
-
resolveLocalMediaPath,
|
|
11
|
-
} from "zhin.js";
|
|
4
|
+
import { asMessageElements, extractBase64Buffer, isMediaSegmentType, isRemoteUrl, resolveLocalMediaPath, type MessageElement, type MessageSegment, type SendContent } from 'zhin.js';
|
|
12
5
|
|
|
13
6
|
export interface KookMediaUploader {
|
|
14
7
|
uploadMedia(data: string | Buffer): Promise<string>;
|
package/src/platform-permit.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* KOOK platform permit — guild / channel 差异化门禁
|
|
3
3
|
*/
|
|
4
|
-
import type
|
|
5
|
-
|
|
6
|
-
import { KookPermission } from './types.js';
|
|
7
|
-
import type { KookSenderInfo } from './types.js';
|
|
4
|
+
import { registerPlatformPermitChecker, type Message } from 'zhin.js';
|
|
5
|
+
|
|
6
|
+
import { KookPermission, type KookSenderInfo } from './types.js';
|
|
8
7
|
|
|
9
8
|
const ADAPTER = 'kook';
|
|
10
9
|
|
package/src/types.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* KOOK 适配器类型与配置
|
|
3
3
|
*/
|
|
4
|
-
import type
|
|
5
|
-
import type { LogLevel } from "kook-client";
|
|
4
|
+
import { type PrivateMessageEvent, type ChannelMessageEvent, type LogLevel } from 'kook-client';
|
|
6
5
|
|
|
7
6
|
export type { LogLevel };
|
|
8
7
|
|
package/lib/adapter.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* KOOK 适配器
|
|
3
|
-
*/
|
|
4
|
-
import { Adapter, Plugin } from 'zhin.js';
|
|
5
|
-
import { KookEndpoint } from "./endpoint.js";
|
|
6
|
-
import type { KookEndpointConfig } from "./types.js";
|
|
7
|
-
import type { OutboundRichSegmentPolicy } from "zhin.js";
|
|
8
|
-
export declare class KookAdapter extends Adapter<KookEndpoint> {
|
|
9
|
-
static readonly capabilities: readonly ["inbound", "outbound"];
|
|
10
|
-
static outboundRichSegmentPolicy: OutboundRichSegmentPolicy;
|
|
11
|
-
static interactivePolicy: "native";
|
|
12
|
-
constructor(plugin: Plugin);
|
|
13
|
-
createEndpoint(config: KookEndpointConfig): KookEndpoint;
|
|
14
|
-
removeMember(endpointId: string, sceneId: string, userId: string): Promise<boolean>;
|
|
15
|
-
banMember(endpointId: string, sceneId: string, userId: string, reason?: string): Promise<boolean>;
|
|
16
|
-
unbanMember(endpointId: string, sceneId: string, userId: string): Promise<boolean>;
|
|
17
|
-
setMemberNickname(endpointId: string, sceneId: string, userId: string, nickname: string): Promise<boolean>;
|
|
18
|
-
listMembers(endpointId: string, sceneId: string): Promise<{
|
|
19
|
-
members: {
|
|
20
|
-
id: string;
|
|
21
|
-
username: string;
|
|
22
|
-
nickname: string;
|
|
23
|
-
roles: number[];
|
|
24
|
-
}[];
|
|
25
|
-
count: number;
|
|
26
|
-
}>;
|
|
27
|
-
start(): Promise<void>;
|
|
28
|
-
stop(): Promise<void>;
|
|
29
|
-
}
|
|
30
|
-
//# sourceMappingURL=adapter.d.ts.map
|
package/lib/adapter.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAiB,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAC;AAEzD,qBAAa,WAAY,SAAQ,OAAO,CAAC,YAAY,CAAC;IACpD,gBAAyB,YAAY,mCAAoC;IACzE,OAAgB,yBAAyB,EAAE,yBAAyB,CAIlE;IACF,OAAgB,iBAAiB,EAAG,QAAQ,CAAU;gBAE1C,MAAM,EAAE,MAAM;IAI1B,cAAc,CAAC,MAAM,EAAE,kBAAkB,GAAG,YAAY;IAMlD,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAMhE,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;IAM9E,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAM/D,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IAMvF,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;;;;;;;;IAe/C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAI5B"}
|
package/lib/adapter.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
|