@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.
Files changed (100) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +1 -0
  3. package/agent/tools/blacklist.ts +33 -0
  4. package/agent/tools/create_role.ts +25 -0
  5. package/agent/tools/delete_role.ts +21 -0
  6. package/agent/tools/grant_role.ts +22 -0
  7. package/agent/tools/list_roles.ts +27 -0
  8. package/agent/tools/revoke_role.ts +22 -0
  9. package/lib/agent/tools/blacklist.js +33 -0
  10. package/lib/agent/tools/blacklist.js.map +1 -0
  11. package/lib/agent/tools/create_role.js +25 -0
  12. package/lib/agent/tools/create_role.js.map +1 -0
  13. package/lib/agent/tools/delete_role.js +21 -0
  14. package/lib/agent/tools/delete_role.js.map +1 -0
  15. package/lib/agent/tools/grant_role.js +22 -0
  16. package/lib/agent/tools/grant_role.js.map +1 -0
  17. package/lib/agent/tools/list_roles.js +27 -0
  18. package/lib/agent/tools/list_roles.js.map +1 -0
  19. package/lib/agent/tools/revoke_role.js +22 -0
  20. package/lib/agent/tools/revoke_role.js.map +1 -0
  21. package/lib/{adapter.js → src/adapter.js} +1 -1
  22. package/lib/src/adapter.js.map +1 -0
  23. package/lib/{endpoint.js → src/endpoint.js} +76 -55
  24. package/lib/src/endpoint.js.map +1 -0
  25. package/lib/src/index.js +197 -0
  26. package/lib/src/index.js.map +1 -0
  27. package/lib/src/kook-agent-deps.js +10 -0
  28. package/lib/src/kook-agent-deps.js.map +1 -0
  29. package/lib/src/kook-asset-upload.js.map +1 -0
  30. package/lib/src/kook-inbound.js.map +1 -0
  31. package/lib/src/kook-msg-route.js.map +1 -0
  32. package/lib/{kook-side-events.js → src/kook-side-events.js} +11 -34
  33. package/lib/src/kook-side-events.js.map +1 -0
  34. package/lib/{outbound-keyboard.js → src/outbound-keyboard.js} +4 -1
  35. package/lib/src/outbound-keyboard.js.map +1 -0
  36. package/lib/{outbound-media.js → src/outbound-media.js} +4 -1
  37. package/lib/src/outbound-media.js.map +1 -0
  38. package/lib/src/outbound-sendable.js.map +1 -0
  39. package/lib/{platform-permit.js → src/platform-permit.js} +3 -0
  40. package/lib/src/platform-permit.js.map +1 -0
  41. package/lib/src/segment-mapper.js.map +1 -0
  42. package/lib/src/types.js.map +1 -0
  43. package/package.json +25 -15
  44. package/src/adapter.ts +2 -3
  45. package/src/endpoint.ts +77 -64
  46. package/src/index.ts +10 -164
  47. package/src/kook-agent-deps.ts +22 -0
  48. package/src/kook-side-events.ts +19 -39
  49. package/src/outbound-keyboard.ts +1 -2
  50. package/src/outbound-media.ts +1 -8
  51. package/src/platform-permit.ts +3 -4
  52. package/src/types.ts +1 -2
  53. package/lib/adapter.d.ts +0 -30
  54. package/lib/adapter.d.ts.map +0 -1
  55. package/lib/adapter.js.map +0 -1
  56. package/lib/endpoint.d.ts +0 -155
  57. package/lib/endpoint.d.ts.map +0 -1
  58. package/lib/endpoint.js.map +0 -1
  59. package/lib/index.d.ts +0 -18
  60. package/lib/index.d.ts.map +0 -1
  61. package/lib/index.js +0 -350
  62. package/lib/index.js.map +0 -1
  63. package/lib/kook-asset-upload.d.ts +0 -12
  64. package/lib/kook-asset-upload.d.ts.map +0 -1
  65. package/lib/kook-asset-upload.js.map +0 -1
  66. package/lib/kook-inbound.d.ts +0 -6
  67. package/lib/kook-inbound.d.ts.map +0 -1
  68. package/lib/kook-inbound.js.map +0 -1
  69. package/lib/kook-msg-route.d.ts +0 -34
  70. package/lib/kook-msg-route.d.ts.map +0 -1
  71. package/lib/kook-msg-route.js.map +0 -1
  72. package/lib/kook-side-events.d.ts +0 -46
  73. package/lib/kook-side-events.d.ts.map +0 -1
  74. package/lib/kook-side-events.js.map +0 -1
  75. package/lib/outbound-keyboard.d.ts +0 -13
  76. package/lib/outbound-keyboard.d.ts.map +0 -1
  77. package/lib/outbound-keyboard.js.map +0 -1
  78. package/lib/outbound-media.d.ts +0 -10
  79. package/lib/outbound-media.d.ts.map +0 -1
  80. package/lib/outbound-media.js.map +0 -1
  81. package/lib/outbound-sendable.d.ts +0 -12
  82. package/lib/outbound-sendable.d.ts.map +0 -1
  83. package/lib/outbound-sendable.js.map +0 -1
  84. package/lib/platform-permit.d.ts +0 -14
  85. package/lib/platform-permit.d.ts.map +0 -1
  86. package/lib/platform-permit.js.map +0 -1
  87. package/lib/segment-mapper.d.ts +0 -2
  88. package/lib/segment-mapper.d.ts.map +0 -1
  89. package/lib/segment-mapper.js.map +0 -1
  90. package/lib/types.d.ts +0 -54
  91. package/lib/types.d.ts.map +0 -1
  92. package/lib/types.js.map +0 -1
  93. /package/{skills/kook → agent}/PERMITS.md +0 -0
  94. /package/{skills/kook/SKILL.md → agent/skills/kook.md} +0 -0
  95. /package/lib/{kook-asset-upload.js → src/kook-asset-upload.js} +0 -0
  96. /package/lib/{kook-inbound.js → src/kook-inbound.js} +0 -0
  97. /package/lib/{kook-msg-route.js → src/kook-msg-route.js} +0 -0
  98. /package/lib/{outbound-sendable.js → src/outbound-sendable.js} +0 -0
  99. /package/lib/{segment-mapper.js → src/segment-mapper.js} +0 -0
  100. /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 { KookEndpointConfig, KookSenderInfo, KookRawMessage } from "./types.js";
26
- import { KookPermission } from "./types.js";
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 图片格式: ![alt](url)
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 matches: Array<{ index: number; length: number; element: MessageElement }> = [];
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
- elements.push(match.element);
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 /!\[.*?\]\(.*?\)|\(met\)|\(emj\)|\(chn\)|@\S+/.test(text);
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, platformPermit, registerKookPlatformPermitChecker } from "./platform-permit.js";
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
+ }
@@ -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 { Notice, formatCompact, Message, type NoticeType } from "zhin.js";
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
- ): ReturnType<typeof Notice.from<KookGatewayEvent>> {
146
+ ) {
165
147
  const extra = event.extra ?? {};
166
148
  const body = extra.body ?? {};
167
149
  const rawType = String(extra.type ?? "unknown");
168
- const $type = resolveNoticeZhinType(rawType);
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
- const mapped = NOTICE_TYPE_MAP[rawType] != null;
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
- $subType: mapped ? rawType : undefined,
188
- $channel: channel,
189
- $operator: senderFromId(operatorId),
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.$subType,
199
- channel: `${notice.$channel.type}(${notice.$channel.id})`,
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
  }
@@ -1,8 +1,7 @@
1
1
  /**
2
2
  * core keyboard 段 → KOOK 卡片消息(action-group + button)
3
3
  */
4
- import type { KeyboardSegmentData, MessageElement } from "zhin.js";
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,
@@ -1,14 +1,7 @@
1
1
  /**
2
2
  * KOOK 出站 media:base64 / 本地文件须先走 /v3/asset/create 上传,再嵌入 KMarkdown。
3
3
  */
4
- import type { MessageElement, MessageSegment, SendContent } from "zhin.js";
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>;
@@ -1,10 +1,9 @@
1
1
  /**
2
2
  * KOOK platform permit — guild / channel 差异化门禁
3
3
  */
4
- import type { Message } from 'zhin.js';
5
- import { registerPlatformPermitChecker } from 'zhin.js';
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 { PrivateMessageEvent, ChannelMessageEvent } from "kook-client";
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
@@ -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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}