@zhin.js/adapter-discord 1.0.87 → 1.1.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 (91) hide show
  1. package/CHANGELOG.md +949 -66
  2. package/PERMITS.md +25 -0
  3. package/README.md +60 -67
  4. package/adapters/discord/index.js +41 -0
  5. package/adapters/discord/index.ts +57 -0
  6. package/agents/discord/agent.json +20 -0
  7. package/agents/discord/boundaries.md +3 -0
  8. package/agents/discord/conventions.md +3 -0
  9. package/agents/discord/skills/discord/SKILL.md +21 -0
  10. package/agents/discord/skills/discord/tools/add_role/index.js +24 -0
  11. package/agents/discord/skills/discord/tools/add_role/index.ts +26 -0
  12. package/agents/discord/skills/discord/tools/create_thread/index.js +29 -0
  13. package/agents/discord/skills/discord/tools/create_thread/index.ts +28 -0
  14. package/agents/discord/skills/discord/tools/forum_post/index.js +33 -0
  15. package/agents/discord/skills/discord/tools/forum_post/index.ts +33 -0
  16. package/agents/discord/skills/discord/tools/list_roles/index.js +28 -0
  17. package/agents/discord/skills/discord/tools/list_roles/index.ts +34 -0
  18. package/agents/discord/skills/discord/tools/react/index.js +24 -0
  19. package/agents/discord/skills/discord/tools/react/index.ts +24 -0
  20. package/agents/discord/skills/discord/tools/remove_role/index.js +24 -0
  21. package/agents/discord/skills/discord/tools/remove_role/index.ts +26 -0
  22. package/agents/discord/skills/discord/tools/send_embed/index.js +43 -0
  23. package/agents/discord/skills/discord/tools/send_embed/index.ts +38 -0
  24. package/agents/discord/system.md +3 -0
  25. package/commands/discord/endpoint/add/[id]/index.js +3 -0
  26. package/commands/discord/endpoint/add/[id]/index.ts +3 -0
  27. package/commands/discord/endpoint/definition.js +19 -0
  28. package/commands/discord/endpoint/definition.ts +19 -0
  29. package/commands/discord/endpoint/list/index.js +3 -0
  30. package/commands/discord/endpoint/list/index.ts +3 -0
  31. package/commands/discord/endpoint/remove/[id]/index.js +3 -0
  32. package/commands/discord/endpoint/remove/[id]/index.ts +3 -0
  33. package/lib/client.d.ts +16 -0
  34. package/lib/client.js +8 -0
  35. package/lib/discord-runtime-state.d.ts +1 -0
  36. package/lib/discord-runtime-state.js +6 -0
  37. package/lib/endpoint.d.ts +72 -0
  38. package/lib/endpoint.js +458 -0
  39. package/lib/gateway.d.ts +144 -0
  40. package/lib/gateway.js +303 -0
  41. package/lib/index.d.ts +6 -18
  42. package/lib/index.js +6 -323
  43. package/lib/platform-permit.d.ts +14 -0
  44. package/lib/platform-permit.js +42 -0
  45. package/lib/protocol.d.ts +145 -0
  46. package/lib/protocol.js +320 -0
  47. package/lib/side-event-dispatch.d.ts +8 -0
  48. package/lib/side-event-dispatch.js +24 -0
  49. package/lib/webhook.d.ts +14 -0
  50. package/lib/webhook.js +88 -0
  51. package/package.json +74 -30
  52. package/plugin.js +19 -0
  53. package/schema.json +205 -0
  54. package/src/client.ts +24 -0
  55. package/src/discord-runtime-state.ts +7 -0
  56. package/src/endpoint.ts +562 -0
  57. package/src/gateway.ts +426 -0
  58. package/src/index.ts +57 -323
  59. package/src/platform-permit.ts +57 -0
  60. package/src/protocol.ts +475 -0
  61. package/src/side-event-dispatch.ts +37 -0
  62. package/src/webhook.ts +123 -0
  63. package/client/Dashboard.tsx +0 -195
  64. package/client/index.tsx +0 -11
  65. package/client/tsconfig.json +0 -7
  66. package/client/utils/api.ts +0 -17
  67. package/dist/index.js +0 -29
  68. package/lib/adapter.d.ts +0 -19
  69. package/lib/adapter.d.ts.map +0 -1
  70. package/lib/adapter.js +0 -90
  71. package/lib/adapter.js.map +0 -1
  72. package/lib/bot-interactions.d.ts +0 -33
  73. package/lib/bot-interactions.d.ts.map +0 -1
  74. package/lib/bot-interactions.js +0 -278
  75. package/lib/bot-interactions.js.map +0 -1
  76. package/lib/bot.d.ts +0 -117
  77. package/lib/bot.d.ts.map +0 -1
  78. package/lib/bot.js +0 -904
  79. package/lib/bot.js.map +0 -1
  80. package/lib/index.d.ts.map +0 -1
  81. package/lib/index.js.map +0 -1
  82. package/lib/types.d.ts +0 -49
  83. package/lib/types.d.ts.map +0 -1
  84. package/lib/types.js +0 -2
  85. package/lib/types.js.map +0 -1
  86. package/plugin.yml +0 -3
  87. package/skills/discord/SKILL.md +0 -104
  88. package/src/adapter.ts +0 -107
  89. package/src/bot-interactions.ts +0 -348
  90. package/src/bot.ts +0 -1037
  91. package/src/types.ts +0 -60
@@ -1,348 +0,0 @@
1
- /**
2
- * Discord Interactions Bot 实现
3
- */
4
- import {
5
- Client,
6
- GatewayIntentBits,
7
- Message as DiscordMessage,
8
- TextChannel,
9
- DMChannel,
10
- NewsChannel,
11
- ThreadChannel,
12
- EmbedBuilder,
13
- AttachmentBuilder,
14
- MessageCreateOptions,
15
- ChannelType,
16
- REST,
17
- Routes,
18
- ApplicationCommandData,
19
- ChatInputCommandInteraction,
20
- InteractionType,
21
- InteractionResponseType,
22
- } from "discord.js";
23
- import nacl from "tweetnacl";
24
- import { Bot, Message, SendOptions, SendContent, MessageSegment, segment } from "zhin.js";
25
- import type { Context } from "koa";
26
- import type { DiscordInteractionsConfig } from "./types.js";
27
- import type { DiscordAdapter } from "./adapter.js";
28
-
29
- export class DiscordInteractionsBot
30
- extends Client
31
- implements Bot<DiscordInteractionsConfig, any> {
32
- $connected: boolean;
33
- private router: import("@zhin.js/http").Router;
34
- private slashCommandHandlers: Map<
35
- string,
36
- (interaction: any) => Promise<void>
37
- > = new Map();
38
-
39
- get pluginLogger() {
40
- return this.adapter.plugin.logger;
41
- }
42
-
43
- get $id() {
44
- return this.$config.name;
45
- }
46
-
47
- constructor(public adapter: DiscordAdapter, router: import("@zhin.js/http").Router, public $config: DiscordInteractionsConfig) {
48
- const intents = $config.intents || [
49
- GatewayIntentBits.Guilds,
50
- GatewayIntentBits.GuildMessages,
51
- GatewayIntentBits.MessageContent,
52
- ];
53
-
54
- super({ intents });
55
- this.$connected = false;
56
- this.router = router;
57
-
58
- // 设置交互端点路由
59
- this.setupInteractionsEndpoint();
60
- }
61
-
62
- private setupInteractionsEndpoint(): void {
63
- // 设置路由处理 Discord Interactions
64
- this.router.post(this.$config.interactionsPath, (ctx: Context) => {
65
- this.handleInteraction(ctx);
66
- });
67
- }
68
-
69
- private async handleInteraction(ctx: Context): Promise<void> {
70
- try {
71
- const signature = ctx.get("x-signature-ed25519");
72
- const timestamp = ctx.get("x-signature-timestamp");
73
- const bodyString = JSON.stringify((ctx.request as any).body);
74
-
75
- // 验证请求签名
76
- if (!this.verifyDiscordSignature(bodyString, signature, timestamp)) {
77
- this.pluginLogger.warn("Invalid Discord signature");
78
- ctx.status = 401;
79
- ctx.body = "Unauthorized";
80
- return;
81
- }
82
-
83
- const interaction = (ctx.request as any).body;
84
-
85
- // 处理不同类型的交互
86
- if (interaction.type === InteractionType.Ping) {
87
- // PING - Discord 验证端点
88
- ctx.body = { type: InteractionResponseType.Pong };
89
- } else if (interaction.type === InteractionType.ApplicationCommand) {
90
- // APPLICATION_COMMAND - 应用命令
91
- const response = await this.handleApplicationCommand(interaction);
92
- ctx.body = response;
93
- } else {
94
- // 其他交互类型
95
- ctx.status = 400;
96
- ctx.body = "Unsupported interaction type";
97
- }
98
- } catch (error) {
99
- this.pluginLogger.error("Interactions error:", error);
100
- ctx.status = 500;
101
- ctx.body = "Internal Server Error";
102
- }
103
- }
104
-
105
- private verifyDiscordSignature(
106
- body: string,
107
- signature: string,
108
- timestamp: string
109
- ): boolean {
110
- try {
111
- const publicKey = Buffer.from(this.$config.publicKey, "hex");
112
- const sig = Buffer.from(signature, "hex");
113
- const message = Buffer.from(timestamp + body, "utf8");
114
-
115
- return nacl.sign.detached.verify(message, sig, publicKey);
116
- } catch (error) {
117
- this.pluginLogger.error("Signature verification error:", error);
118
- return false;
119
- }
120
- }
121
-
122
- private async handleApplicationCommand(interaction: any): Promise<any> {
123
- // 处理应用命令
124
- const commandName = interaction.data.name;
125
-
126
- // 转换为标准消息格式并分发
127
- const message = this.formatInteractionAsMessage(interaction);
128
- this.adapter.emit("message.receive", message);
129
-
130
- // 查找自定义处理器
131
- const handler = this.slashCommandHandlers.get(commandName);
132
- if (handler) {
133
- try {
134
- await handler(interaction);
135
- } catch (error) {
136
- this.pluginLogger.error(
137
- `Error in slash command handler for ${commandName}:`,
138
- error
139
- );
140
- }
141
- }
142
-
143
- // 默认响应
144
- return {
145
- type: InteractionResponseType.ChannelMessageWithSource,
146
- data: {
147
- content: `处理命令: ${commandName}`,
148
- flags: 64, // EPHEMERAL - 只有用户可见
149
- },
150
- };
151
- }
152
-
153
- private formatInteractionAsMessage(interaction: any): Message<any> {
154
- const channelType = interaction.guild_id ? "channel" : "private";
155
- const channelId = interaction.channel_id;
156
-
157
- // 解析命令参数为内容
158
- const options = interaction.data.options || [];
159
- const content = [segment.text(`/${interaction.data.name}`)];
160
-
161
- for (const option of options) {
162
- content.push(segment.text(` ${option.name}:${option.value}`));
163
- }
164
-
165
- return Message.from(interaction, {
166
- $id: interaction.id,
167
- $adapter: "discord",
168
- $bot: this.$config.name,
169
- $sender: {
170
- id: interaction.user?.id || interaction.member?.user?.id,
171
- name: interaction.user?.username || interaction.member?.user?.username,
172
- },
173
- $channel: {
174
- id: channelId,
175
- type: channelType as any,
176
- },
177
- $raw: JSON.stringify(interaction),
178
- $timestamp: Date.now(),
179
- $content: content,
180
- $recall: async () => {
181
- // Interactions 消息无法撤回
182
- },
183
- $reply: async (content: SendContent): Promise<string> => {
184
- return this.$sendMessage({
185
- ...this.$formatMessage(interaction),
186
- content: content,
187
- });
188
- },
189
- });
190
- }
191
-
192
- private formatSendContent(content: SendContent): any {
193
- if (typeof content === "string") {
194
- return { content };
195
- }
196
-
197
- if (Array.isArray(content)) {
198
- const textParts: string[] = [];
199
- let embed: any = null;
200
-
201
- for (const item of content) {
202
- if (typeof item === "string") {
203
- textParts.push(item);
204
- } else {
205
- const segment = item as MessageSegment;
206
- switch (segment.type) {
207
- case "text":
208
- textParts.push(segment.data.text || segment.data.content || "");
209
- break;
210
- case "embed":
211
- embed = segment.data;
212
- break;
213
- }
214
- }
215
- }
216
-
217
- const result: any = {};
218
- if (textParts.length > 0) {
219
- result.content = textParts.join("");
220
- }
221
- if (embed) {
222
- result.embeds = [embed];
223
- }
224
-
225
- return result;
226
- }
227
-
228
- return { content: String(content) };
229
- }
230
-
231
- async $connect(): Promise<void> {
232
- try {
233
- // 注册 Slash Commands
234
- if (this.$config.slashCommands) {
235
- await this.registerSlashCommands();
236
- }
237
-
238
- // 如果启用 Gateway,连接 Discord Gateway
239
- if (this.$config.useGateway) {
240
- await this.login(this.$config.token);
241
-
242
- // 设置活动状态
243
- if (this.$config.defaultActivity) {
244
- this.user?.setActivity(this.$config.defaultActivity.name, {
245
- type: this.getActivityType(this.$config.defaultActivity.type),
246
- url: this.$config.defaultActivity.url,
247
- });
248
- }
249
- }
250
-
251
- this.$connected = true;
252
- this.pluginLogger.info(
253
- `Discord interactions bot connected: ${this.$config.name}`
254
- );
255
- this.pluginLogger.info(
256
- `Interactions endpoint: ${this.$config.interactionsPath}`
257
- );
258
- } catch (error) {
259
- this.pluginLogger.error("Failed to connect Discord interactions bot:", error);
260
- throw error;
261
- }
262
- }
263
-
264
- async $disconnect(): Promise<void> {
265
- try {
266
- if (this.isReady()) {
267
- await this.destroy();
268
- }
269
- this.$connected = false;
270
- this.pluginLogger.info("Discord interactions bot disconnected");
271
- } catch (error) {
272
- this.pluginLogger.error(
273
- "Error disconnecting Discord interactions bot:",
274
- error
275
- );
276
- }
277
- }
278
-
279
- // Slash Commands 管理
280
- private async registerSlashCommands(): Promise<void> {
281
- if (!this.$config.slashCommands) return;
282
-
283
- try {
284
- const rest = new REST({ version: "10" }).setToken(this.$config.token);
285
-
286
- if (this.$config.globalCommands) {
287
- await rest.put(Routes.applicationCommands(this.$config.applicationId), {
288
- body: this.$config.slashCommands,
289
- });
290
- this.pluginLogger.info("Successfully registered global slash commands");
291
- } else {
292
- this.pluginLogger.info(
293
- "Note: Guild commands registration requires connecting to Gateway first"
294
- );
295
- }
296
- } catch (error) {
297
- this.pluginLogger.error("Failed to register slash commands:", error);
298
- }
299
- }
300
-
301
- // 添加 Slash Command 处理器
302
- addSlashCommandHandler(
303
- commandName: string,
304
- handler: (interaction: any) => Promise<void>
305
- ): void {
306
- this.slashCommandHandlers.set(commandName, handler);
307
- }
308
-
309
- // 移除 Slash Command 处理器
310
- removeSlashCommandHandler(commandName: string): boolean {
311
- return this.slashCommandHandlers.delete(commandName);
312
- }
313
-
314
- // 工具方法
315
- private getActivityType(type: string): any {
316
- const activityTypes: any = {
317
- PLAYING: 0,
318
- STREAMING: 1,
319
- LISTENING: 2,
320
- WATCHING: 3,
321
- COMPETING: 5,
322
- };
323
- return activityTypes[type] || 0;
324
- }
325
-
326
- // 简化实现 - 只支持基本消息格式化和发送
327
- $formatMessage(msg: any): Message<any> {
328
- return this.formatInteractionAsMessage(msg);
329
- }
330
-
331
- async $sendMessage(options: SendOptions): Promise<string> {
332
- // 简化实现 - 通过 REST API 发送消息
333
- try {
334
- const rest = new REST({ version: "10" }).setToken(this.$config.token);
335
- const messageContent = this.formatSendContent(options.content);
336
-
337
- await rest.post(Routes.channelMessages(options.id), {
338
- body: messageContent,
339
- });
340
- } catch (error) {
341
- this.pluginLogger.error("Failed to send message:", error);
342
- }
343
- return "";
344
- }
345
- async $recallMessage(id: string): Promise<void> { }
346
- }
347
-
348
- // 定义 Adapter 类