@elizaos/plugin-discord 1.3.7 → 2.0.0-alpha.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/dist/index.d.ts +2 -942
- package/package.json +29 -28
- package/LICENSE +0 -21
- package/README.md +0 -531
- package/dist/index.js +0 -11293
- package/dist/index.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elizaos/plugin-discord",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0-alpha.1",
|
|
4
|
+
"description": "",
|
|
4
5
|
"type": "module",
|
|
5
6
|
"main": "dist/index.js",
|
|
6
7
|
"module": "dist/index.js",
|
|
7
8
|
"types": "dist/index.d.ts",
|
|
9
|
+
"sideEffects": false,
|
|
8
10
|
"repository": {
|
|
9
11
|
"type": "git",
|
|
10
12
|
"url": "git+https://github.com/elizaos-plugins/plugin-discord.git"
|
|
@@ -12,20 +14,34 @@
|
|
|
12
14
|
"exports": {
|
|
13
15
|
"./package.json": "./package.json",
|
|
14
16
|
".": {
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"import": "./dist/index.js",
|
|
19
|
+
"default": "./dist/index.js"
|
|
19
20
|
}
|
|
20
21
|
},
|
|
21
22
|
"files": [
|
|
22
23
|
"dist"
|
|
23
24
|
],
|
|
25
|
+
"keywords": [],
|
|
26
|
+
"author": "elizaOS",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "bun run build.ts",
|
|
30
|
+
"build:ts": "bun run build.ts",
|
|
31
|
+
"dev": "bun --hot build.ts",
|
|
32
|
+
"clean": "rm -rf dist .turbo node_modules",
|
|
33
|
+
"test": "vitest run",
|
|
34
|
+
"typecheck": "tsc --noEmit",
|
|
35
|
+
"lint": "bunx @biomejs/biome check --write --unsafe .",
|
|
36
|
+
"lint:check": "bunx @biomejs/biome check .",
|
|
37
|
+
"format": "bunx @biomejs/biome format --write .",
|
|
38
|
+
"format:check": "bunx @biomejs/biome format ."
|
|
39
|
+
},
|
|
24
40
|
"dependencies": {
|
|
25
41
|
"@discordjs/opus": "^0.10.0",
|
|
26
42
|
"@discordjs/rest": "2.4.3",
|
|
27
43
|
"@discordjs/voice": "0.18.0",
|
|
28
|
-
"@elizaos/core": "
|
|
44
|
+
"@elizaos/core": "workspace:*",
|
|
29
45
|
"discord.js": "14.18.0",
|
|
30
46
|
"fast-levenshtein": "^3.0.0",
|
|
31
47
|
"fluent-ffmpeg": "^2.1.3",
|
|
@@ -33,36 +49,21 @@
|
|
|
33
49
|
"libsodium-wrappers": "^0.7.13",
|
|
34
50
|
"opusscript": "^0.1.1",
|
|
35
51
|
"prism-media": "1.3.5",
|
|
36
|
-
"typescript": "^5.
|
|
37
|
-
"zod": "4.
|
|
52
|
+
"typescript": "^5.9.3",
|
|
53
|
+
"zod": "^4.3.5"
|
|
38
54
|
},
|
|
39
55
|
"devDependencies": {
|
|
40
|
-
"@
|
|
41
|
-
"
|
|
42
|
-
"@
|
|
43
|
-
"@typescript-eslint/parser": "^8.22.0",
|
|
44
|
-
"eslint": "^9.17.0",
|
|
45
|
-
"prettier": "3.5.3",
|
|
46
|
-
"tsup": "8.4.0",
|
|
47
|
-
"vitest": "1.6.1"
|
|
48
|
-
},
|
|
49
|
-
"scripts": {
|
|
50
|
-
"build": "tsup",
|
|
51
|
-
"dev": "tsup --watch",
|
|
52
|
-
"test": "elizaos test",
|
|
53
|
-
"lint": "eslint ./src --fix && prettier --write ./src",
|
|
54
|
-
"lint:check": "eslint ./src",
|
|
55
|
-
"clean": "rm -rf dist .turbo node_modules .turbo-tsconfig.json tsconfig.tsbuildinfo",
|
|
56
|
-
"format": "prettier --write ./src",
|
|
57
|
-
"format:check": "prettier --check ./src"
|
|
56
|
+
"@types/node": "^25.0.3",
|
|
57
|
+
"typescript": "^5.9.3",
|
|
58
|
+
"@biomejs/biome": "^2.3.11"
|
|
58
59
|
},
|
|
59
60
|
"peerDependencies": {
|
|
60
|
-
"whatwg-url": "7.1.0"
|
|
61
|
+
"whatwg-url": "7.1.0",
|
|
62
|
+
"@elizaos/core": "workspace:*"
|
|
61
63
|
},
|
|
62
64
|
"publishConfig": {
|
|
63
65
|
"access": "public"
|
|
64
66
|
},
|
|
65
|
-
"gitHead": "646c632924826e2b75c2304a75ee56959fe4a460",
|
|
66
67
|
"agentConfig": {
|
|
67
68
|
"pluginType": "elizaos:plugin:1.0.0",
|
|
68
69
|
"pluginParameters": {
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Shaw Walters and elizaOS Contributors
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
package/README.md
DELETED
|
@@ -1,531 +0,0 @@
|
|
|
1
|
-
# @elizaos/plugin-discord
|
|
2
|
-
|
|
3
|
-
A Discord plugin implementation for ElizaOS, enabling rich integration with Discord servers for managing interactions, voice, and message handling.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- Handle server join events and manage initial configurations
|
|
8
|
-
- Voice event management via the voice manager
|
|
9
|
-
- Manage and process new messages with the message manager
|
|
10
|
-
- Slash command registration and interaction handling
|
|
11
|
-
- Support for Discord attachments and media files
|
|
12
|
-
- Voice channel join/leave functionality
|
|
13
|
-
- Conversation summarization
|
|
14
|
-
- Media transcription capabilities
|
|
15
|
-
- Channel state and voice state providers
|
|
16
|
-
- Channel restriction support (limit bot to specific channels)
|
|
17
|
-
- Robust permissions management and audit event tracking
|
|
18
|
-
- Event-driven architecture with comprehensive event handling
|
|
19
|
-
- History backfill with efficient batch processing
|
|
20
|
-
|
|
21
|
-
## Installation
|
|
22
|
-
|
|
23
|
-
As this is a workspace package, it's installed as part of the ElizaOS monorepo:
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
bun install
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
## Configuration
|
|
30
|
-
|
|
31
|
-
The plugin requires the following environment variables:
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
# Discord API Credentials (Required)
|
|
35
|
-
DISCORD_APPLICATION_ID=your_application_id
|
|
36
|
-
DISCORD_API_TOKEN=your_api_token
|
|
37
|
-
|
|
38
|
-
# Channel Restrictions (Optional)
|
|
39
|
-
# Comma-separated list of Discord channel IDs to restrict the bot to.
|
|
40
|
-
# If not set, the bot operates in all channels.
|
|
41
|
-
# These channels cannot be removed via the leaveChannel action.
|
|
42
|
-
CHANNEL_IDS=123456789012345678,987654321098765432
|
|
43
|
-
|
|
44
|
-
# Listen-only channels (Optional)
|
|
45
|
-
# Comma-separated list of channel IDs where the bot will only listen (not respond).
|
|
46
|
-
DISCORD_LISTEN_CHANNEL_IDS=123456789012345678
|
|
47
|
-
|
|
48
|
-
# Voice Channel (Optional)
|
|
49
|
-
# ID of the voice channel the bot should auto-join when scanning a guild.
|
|
50
|
-
# If not set, the bot selects based on member activity.
|
|
51
|
-
DISCORD_VOICE_CHANNEL_ID=123456789012345678
|
|
52
|
-
|
|
53
|
-
# Behavior Settings (Optional)
|
|
54
|
-
# If true, ignore messages from other bots (default: false)
|
|
55
|
-
DISCORD_SHOULD_IGNORE_BOT_MESSAGES=false
|
|
56
|
-
|
|
57
|
-
# If true, ignore direct messages (default: false)
|
|
58
|
-
DISCORD_SHOULD_IGNORE_DIRECT_MESSAGES=false
|
|
59
|
-
|
|
60
|
-
# If true, only respond when explicitly @mentioned (default: false)
|
|
61
|
-
DISCORD_SHOULD_RESPOND_ONLY_TO_MENTIONS=false
|
|
62
|
-
|
|
63
|
-
# Testing (Optional)
|
|
64
|
-
DISCORD_TEST_CHANNEL_ID=123456789012345678
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
Settings can also be configured in your character file under `settings.discord`:
|
|
68
|
-
|
|
69
|
-
```json
|
|
70
|
-
{
|
|
71
|
-
"settings": {
|
|
72
|
-
"discord": {
|
|
73
|
-
"shouldIgnoreBotMessages": false,
|
|
74
|
-
"shouldIgnoreDirectMessages": false,
|
|
75
|
-
"shouldRespondOnlyToMentions": false,
|
|
76
|
-
"allowedChannelIds": ["123456789012345678"]
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
## Usage
|
|
83
|
-
|
|
84
|
-
```json
|
|
85
|
-
{
|
|
86
|
-
"plugins": ["@elizaos/plugin-discord"]
|
|
87
|
-
}
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
## Slash Command Permissions
|
|
91
|
-
|
|
92
|
-
The plugin uses a hybrid permission system that combines Discord's native features with ElizaOS-specific controls.
|
|
93
|
-
|
|
94
|
-
### Permission Layers
|
|
95
|
-
|
|
96
|
-
Commands go through multiple permission checks in this order:
|
|
97
|
-
|
|
98
|
-
1. **Discord Native Checks** (before interaction fires):
|
|
99
|
-
- User must have required Discord permissions
|
|
100
|
-
- Command must be available in the current context (guild vs DM)
|
|
101
|
-
|
|
102
|
-
2. **ElizaOS Channel Whitelist** (if `CHANNEL_IDS` is set):
|
|
103
|
-
- Commands only work in whitelisted channels
|
|
104
|
-
- Unless command has `bypassChannelWhitelist: true`
|
|
105
|
-
|
|
106
|
-
3. **Custom Validator** (if provided):
|
|
107
|
-
- Runs custom validation logic
|
|
108
|
-
- Full programmatic control
|
|
109
|
-
|
|
110
|
-
### Registering Commands
|
|
111
|
-
|
|
112
|
-
```typescript
|
|
113
|
-
import { PermissionFlagsBits } from 'discord.js';
|
|
114
|
-
|
|
115
|
-
// Simple command (works everywhere)
|
|
116
|
-
const helpCommand = {
|
|
117
|
-
name: 'help',
|
|
118
|
-
description: 'Show help information'
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
// Guild-only command
|
|
122
|
-
const serverInfoCommand = {
|
|
123
|
-
name: 'serverinfo',
|
|
124
|
-
description: 'Show server information',
|
|
125
|
-
guildOnly: true
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
// Requires Discord permission
|
|
129
|
-
const configCommand = {
|
|
130
|
-
name: 'config',
|
|
131
|
-
description: 'Configure bot settings',
|
|
132
|
-
requiredPermissions: PermissionFlagsBits.ManageGuild
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
// Bypasses channel whitelist
|
|
136
|
-
const utilityCommand = {
|
|
137
|
-
name: 'export',
|
|
138
|
-
description: 'Export data',
|
|
139
|
-
bypassChannelWhitelist: true
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
// Advanced: custom validation
|
|
143
|
-
const adminCommand = {
|
|
144
|
-
name: 'admin',
|
|
145
|
-
description: 'Admin-only command',
|
|
146
|
-
validator: async (interaction, runtime) => {
|
|
147
|
-
const adminIds = runtime.getSetting('ADMIN_USER_IDS')?.split(',') ?? [];
|
|
148
|
-
return adminIds.includes(interaction.user.id);
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
// Register commands
|
|
153
|
-
await runtime.emitEvent(['DISCORD_REGISTER_COMMANDS'], {
|
|
154
|
-
commands: [helpCommand, serverInfoCommand, configCommand, utilityCommand, adminCommand]
|
|
155
|
-
});
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### Permission Options
|
|
159
|
-
|
|
160
|
-
| Option | Type | Description |
|
|
161
|
-
|--------|------|-------------|
|
|
162
|
-
| `guildOnly` | `boolean` | If true, command only works in guilds (not DMs) |
|
|
163
|
-
| `bypassChannelWhitelist` | `boolean` | If true, bypasses `CHANNEL_IDS` restrictions |
|
|
164
|
-
| `requiredPermissions` | `bigint \| string` | Discord permission bitfield (e.g., `PermissionFlagsBits.ManageGuild`) |
|
|
165
|
-
| `contexts` | `number[]` | Raw Discord contexts (0=Guild, 1=BotDM, 2=PrivateChannel) |
|
|
166
|
-
| `guildIds` | `string[]` | Register only in specific guilds (instant updates) |
|
|
167
|
-
| `validator` | `function` | Custom validation function for advanced logic |
|
|
168
|
-
|
|
169
|
-
### Common Permission Values
|
|
170
|
-
|
|
171
|
-
From Discord.js `PermissionFlagsBits`:
|
|
172
|
-
|
|
173
|
-
- `ManageGuild` - Server settings
|
|
174
|
-
- `ManageChannels` - Channel management
|
|
175
|
-
- `ManageMessages` - Delete messages
|
|
176
|
-
- `BanMembers` - Ban users
|
|
177
|
-
- `KickMembers` - Kick users
|
|
178
|
-
- `ModerateMembers` - Timeout users
|
|
179
|
-
- `ManageRoles` - Role management
|
|
180
|
-
- `Administrator` - Full access
|
|
181
|
-
|
|
182
|
-
### Design Rationale
|
|
183
|
-
|
|
184
|
-
**Why Hybrid Approach?**
|
|
185
|
-
- Discord's native permissions are powerful but limited to role-based access
|
|
186
|
-
- ElizaOS needs programmatic control for channel restrictions and custom logic
|
|
187
|
-
- Combining both gives developers the best of both worlds
|
|
188
|
-
|
|
189
|
-
**Why Simple Flags?**
|
|
190
|
-
- `guildOnly: true` is clearer than `contexts: [0]`
|
|
191
|
-
- Abstracts Discord API details
|
|
192
|
-
- Sensible defaults: zero config should "just work"
|
|
193
|
-
|
|
194
|
-
**Why Keep Channel Whitelist?**
|
|
195
|
-
- Discord's channel permissions are UI-based (Server Settings > Integrations)
|
|
196
|
-
- Programmatic control is better for developer experience
|
|
197
|
-
- Allows dynamic, runtime-based channel restrictions
|
|
198
|
-
|
|
199
|
-
### Available Actions
|
|
200
|
-
|
|
201
|
-
The plugin provides the following actions:
|
|
202
|
-
|
|
203
|
-
| Action | Description |
|
|
204
|
-
|--------|-------------|
|
|
205
|
-
| **chatWithAttachments** | Handle messages with Discord attachments |
|
|
206
|
-
| **createPoll** | Create a poll in a Discord channel |
|
|
207
|
-
| **downloadMedia** | Download media files from Discord messages |
|
|
208
|
-
| **getUserInfo** | Get information about a Discord user |
|
|
209
|
-
| **joinVoice** | Join a voice channel |
|
|
210
|
-
| **leaveVoice** | Leave a voice channel |
|
|
211
|
-
| **listChannels** | List channels in a Discord server |
|
|
212
|
-
| **pinMessage** | Pin a message in a channel |
|
|
213
|
-
| **reactToMessage** | Add a reaction to a message |
|
|
214
|
-
| **readChannel** | Read messages from a channel |
|
|
215
|
-
| **searchMessages** | Search for messages in a channel |
|
|
216
|
-
| **sendDM** | Send a direct message to a user |
|
|
217
|
-
| **serverInfo** | Get information about the current server |
|
|
218
|
-
| **summarize** | Summarize conversation history |
|
|
219
|
-
| **transcribeMedia** | Transcribe audio/video media to text |
|
|
220
|
-
| **unpinMessage** | Unpin a message from a channel |
|
|
221
|
-
|
|
222
|
-
### Providers
|
|
223
|
-
|
|
224
|
-
The plugin includes two state providers:
|
|
225
|
-
|
|
226
|
-
1. **channelStateProvider** - Provides state information about Discord channels
|
|
227
|
-
2. **voiceStateProvider** - Provides state information about voice channels and connection status
|
|
228
|
-
|
|
229
|
-
### Event Types
|
|
230
|
-
|
|
231
|
-
The plugin emits the following Discord-specific events:
|
|
232
|
-
|
|
233
|
-
| Event | Description |
|
|
234
|
-
|-------|-------------|
|
|
235
|
-
| `DISCORD_MESSAGE_RECEIVED` | When a message is received |
|
|
236
|
-
| `DISCORD_MESSAGE_SENT` | When a message is sent |
|
|
237
|
-
| `DISCORD_SLASH_COMMAND` | When a slash command is invoked |
|
|
238
|
-
| `DISCORD_MODAL_SUBMIT` | When a modal form is submitted |
|
|
239
|
-
| `DISCORD_REACTION_RECEIVED` | When a reaction is added to a message |
|
|
240
|
-
| `DISCORD_REACTION_REMOVED` | When a reaction is removed from a message |
|
|
241
|
-
| `DISCORD_WORLD_JOINED` | When the bot joins a guild |
|
|
242
|
-
| `DISCORD_SERVER_CONNECTED` | When connected to a server |
|
|
243
|
-
| `DISCORD_USER_JOINED` | When a user joins a guild |
|
|
244
|
-
| `DISCORD_USER_LEFT` | When a user leaves a guild |
|
|
245
|
-
| `DISCORD_VOICE_STATE_CHANGED` | When voice state changes |
|
|
246
|
-
| `DISCORD_CHANNEL_PERMISSIONS_CHANGED` | When channel permissions change |
|
|
247
|
-
| `DISCORD_ROLE_PERMISSIONS_CHANGED` | When role permissions change |
|
|
248
|
-
| `DISCORD_MEMBER_ROLES_CHANGED` | When a member's roles change |
|
|
249
|
-
| `DISCORD_ROLE_CREATED` | When a role is created |
|
|
250
|
-
| `DISCORD_ROLE_DELETED` | When a role is deleted |
|
|
251
|
-
|
|
252
|
-
## Key Components
|
|
253
|
-
|
|
254
|
-
### DiscordService
|
|
255
|
-
|
|
256
|
-
Main service class that extends ElizaOS Service:
|
|
257
|
-
- Handles authentication and session management
|
|
258
|
-
- Manages Discord client connection
|
|
259
|
-
- Processes events and interactions
|
|
260
|
-
- Supports channel history backfill with efficient batch processing
|
|
261
|
-
|
|
262
|
-
### MessageManager
|
|
263
|
-
|
|
264
|
-
- Processes incoming messages and responses
|
|
265
|
-
- Handles attachments and media files
|
|
266
|
-
- Supports message formatting and templating
|
|
267
|
-
- Manages conversation context
|
|
268
|
-
|
|
269
|
-
### VoiceManager
|
|
270
|
-
|
|
271
|
-
- Manages voice channel interactions
|
|
272
|
-
- Handles joining and leaving voice channels
|
|
273
|
-
- Processes voice events and audio streams
|
|
274
|
-
- Integrates with transcription services
|
|
275
|
-
|
|
276
|
-
### Attachment Handler
|
|
277
|
-
|
|
278
|
-
- Downloads and processes Discord attachments
|
|
279
|
-
- Supports various media types
|
|
280
|
-
- Integrates with media transcription
|
|
281
|
-
|
|
282
|
-
## Developer Guide
|
|
283
|
-
|
|
284
|
-
### Custom Slash Commands
|
|
285
|
-
|
|
286
|
-
Register slash commands via the `DISCORD_REGISTER_COMMANDS` event, then listen for interactions:
|
|
287
|
-
|
|
288
|
-
```typescript
|
|
289
|
-
// Register custom slash commands
|
|
290
|
-
await runtime.emitEvent(['DISCORD_REGISTER_COMMANDS'], {
|
|
291
|
-
commands: [
|
|
292
|
-
{
|
|
293
|
-
name: 'mycommand',
|
|
294
|
-
description: 'My custom command',
|
|
295
|
-
options: [
|
|
296
|
-
{
|
|
297
|
-
name: 'input',
|
|
298
|
-
description: 'User input',
|
|
299
|
-
type: 3, // STRING type
|
|
300
|
-
required: true,
|
|
301
|
-
},
|
|
302
|
-
],
|
|
303
|
-
},
|
|
304
|
-
{
|
|
305
|
-
name: 'serverinfo',
|
|
306
|
-
description: 'Get server information',
|
|
307
|
-
guildOnly: true, // Only works in guilds, not DMs
|
|
308
|
-
},
|
|
309
|
-
],
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
// Listen for slash command events to handle the interaction
|
|
313
|
-
runtime.registerEvent({
|
|
314
|
-
name: 'DISCORD_SLASH_COMMAND',
|
|
315
|
-
handler: async (payload) => {
|
|
316
|
-
const { interaction, client, commands } = payload;
|
|
317
|
-
|
|
318
|
-
if (interaction.commandName === 'mycommand') {
|
|
319
|
-
const input = interaction.options.getString('input');
|
|
320
|
-
await interaction.reply(`You said: ${input}`);
|
|
321
|
-
}
|
|
322
|
-
},
|
|
323
|
-
});
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
### Building on the Listen System
|
|
327
|
-
|
|
328
|
-
The `DISCORD_LISTEN_CHANNEL_IDS` setting creates "listen-only" channels where the bot receives messages but doesn't respond. This is useful for:
|
|
329
|
-
|
|
330
|
-
- **Monitoring channels** - Track activity without interrupting conversations
|
|
331
|
-
- **Data collection** - Gather messages for analysis or training
|
|
332
|
-
- **Conditional responses** - Build custom logic that decides when to respond
|
|
333
|
-
|
|
334
|
-
```typescript
|
|
335
|
-
// Check if a channel is listen-only
|
|
336
|
-
const listenChannels = runtime.getSetting('DISCORD_LISTEN_CHANNEL_IDS');
|
|
337
|
-
const listenChannelIds = listenChannels?.split(',').map(s => s.trim()) || [];
|
|
338
|
-
|
|
339
|
-
runtime.registerEvent({
|
|
340
|
-
name: 'DISCORD_MESSAGE_RECEIVED',
|
|
341
|
-
handler: async (payload) => {
|
|
342
|
-
const { message } = payload;
|
|
343
|
-
const channelId = message.content.channelId;
|
|
344
|
-
|
|
345
|
-
if (listenChannelIds.includes(channelId)) {
|
|
346
|
-
// This is a listen-only channel - process without responding
|
|
347
|
-
await processMessageSilently(message);
|
|
348
|
-
}
|
|
349
|
-
},
|
|
350
|
-
});
|
|
351
|
-
```
|
|
352
|
-
|
|
353
|
-
### Handling Modal and Component Interactions
|
|
354
|
-
|
|
355
|
-
Modal submits and message components (buttons, select menus) bypass channel whitelists to support multi-step UI flows:
|
|
356
|
-
|
|
357
|
-
```typescript
|
|
358
|
-
// Listen for modal submissions
|
|
359
|
-
runtime.registerEvent({
|
|
360
|
-
name: 'DISCORD_MODAL_SUBMIT',
|
|
361
|
-
handler: async (payload) => {
|
|
362
|
-
const { interaction } = payload;
|
|
363
|
-
const fieldValue = interaction.fields.getTextInputValue('myField');
|
|
364
|
-
await interaction.reply(`Received: ${fieldValue}`);
|
|
365
|
-
},
|
|
366
|
-
});
|
|
367
|
-
```
|
|
368
|
-
|
|
369
|
-
### Permission Audit System
|
|
370
|
-
|
|
371
|
-
The plugin includes a comprehensive permission audit system that tracks all permission changes with full audit log integration. This is useful for:
|
|
372
|
-
|
|
373
|
-
- **Security monitoring** - Detect unauthorized permission escalations
|
|
374
|
-
- **Compliance logging** - Maintain records of who changed what and when
|
|
375
|
-
- **Bot self-protection** - Detect when the bot's permissions are modified
|
|
376
|
-
|
|
377
|
-
#### Event Payloads
|
|
378
|
-
|
|
379
|
-
**DISCORD_CHANNEL_PERMISSIONS_CHANGED** - When channel overwrites change:
|
|
380
|
-
|
|
381
|
-
```typescript
|
|
382
|
-
interface ChannelPermissionsChangedPayload {
|
|
383
|
-
runtime: IAgentRuntime;
|
|
384
|
-
guild: { id: string; name: string };
|
|
385
|
-
channel: { id: string; name: string };
|
|
386
|
-
target: { type: 'role' | 'user'; id: string; name: string };
|
|
387
|
-
action: 'CREATE' | 'UPDATE' | 'DELETE';
|
|
388
|
-
changes: Array<{
|
|
389
|
-
permission: string; // e.g., 'ManageMessages', 'Administrator'
|
|
390
|
-
oldState: 'ALLOW' | 'DENY' | 'NEUTRAL';
|
|
391
|
-
newState: 'ALLOW' | 'DENY' | 'NEUTRAL';
|
|
392
|
-
}>;
|
|
393
|
-
audit: { executorId: string; executorTag: string; reason: string | null } | null;
|
|
394
|
-
}
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
**DISCORD_ROLE_PERMISSIONS_CHANGED** - When role permissions change:
|
|
398
|
-
|
|
399
|
-
```typescript
|
|
400
|
-
interface RolePermissionsChangedPayload {
|
|
401
|
-
runtime: IAgentRuntime;
|
|
402
|
-
guild: { id: string; name: string };
|
|
403
|
-
role: { id: string; name: string };
|
|
404
|
-
changes: PermissionDiff[];
|
|
405
|
-
audit: AuditInfo | null;
|
|
406
|
-
}
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
**DISCORD_MEMBER_ROLES_CHANGED** - When a member's roles change:
|
|
410
|
-
|
|
411
|
-
```typescript
|
|
412
|
-
interface MemberRolesChangedPayload {
|
|
413
|
-
runtime: IAgentRuntime;
|
|
414
|
-
guild: { id: string; name: string };
|
|
415
|
-
member: { id: string; tag: string };
|
|
416
|
-
added: Array<{ id: string; name: string; permissions: string[] }>;
|
|
417
|
-
removed: Array<{ id: string; name: string; permissions: string[] }>;
|
|
418
|
-
audit: AuditInfo | null;
|
|
419
|
-
}
|
|
420
|
-
```
|
|
421
|
-
|
|
422
|
-
**DISCORD_ROLE_CREATED / DISCORD_ROLE_DELETED** - Role lifecycle:
|
|
423
|
-
|
|
424
|
-
```typescript
|
|
425
|
-
interface RoleLifecyclePayload {
|
|
426
|
-
runtime: IAgentRuntime;
|
|
427
|
-
guild: { id: string; name: string };
|
|
428
|
-
role: { id: string; name: string; permissions: string[] };
|
|
429
|
-
audit: AuditInfo | null;
|
|
430
|
-
}
|
|
431
|
-
```
|
|
432
|
-
|
|
433
|
-
#### Example: Security Monitoring
|
|
434
|
-
|
|
435
|
-
```typescript
|
|
436
|
-
import { DiscordEventTypes } from '@elizaos/plugin-discord';
|
|
437
|
-
|
|
438
|
-
// Alert on dangerous permission grants
|
|
439
|
-
runtime.registerEvent({
|
|
440
|
-
name: DiscordEventTypes.CHANNEL_PERMISSIONS_CHANGED,
|
|
441
|
-
handler: async (payload) => {
|
|
442
|
-
const dangerousPerms = ['Administrator', 'ManageGuild', 'ManageRoles'];
|
|
443
|
-
|
|
444
|
-
for (const change of payload.changes) {
|
|
445
|
-
if (dangerousPerms.includes(change.permission) && change.newState === 'ALLOW') {
|
|
446
|
-
console.warn(`⚠️ Dangerous permission granted!`, {
|
|
447
|
-
channel: payload.channel.name,
|
|
448
|
-
target: payload.target.name,
|
|
449
|
-
permission: change.permission,
|
|
450
|
-
grantedBy: payload.audit?.executorTag || 'Unknown',
|
|
451
|
-
});
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
},
|
|
455
|
-
});
|
|
456
|
-
|
|
457
|
-
// Track role escalations
|
|
458
|
-
runtime.registerEvent({
|
|
459
|
-
name: DiscordEventTypes.MEMBER_ROLES_CHANGED,
|
|
460
|
-
handler: async (payload) => {
|
|
461
|
-
const adminRoles = payload.added.filter(r =>
|
|
462
|
-
r.permissions.includes('Administrator')
|
|
463
|
-
);
|
|
464
|
-
|
|
465
|
-
if (adminRoles.length > 0) {
|
|
466
|
-
console.warn(`⚠️ Admin role granted to ${payload.member.tag}`, {
|
|
467
|
-
roles: adminRoles.map(r => r.name),
|
|
468
|
-
grantedBy: payload.audit?.executorTag || 'Unknown',
|
|
469
|
-
});
|
|
470
|
-
}
|
|
471
|
-
},
|
|
472
|
-
});
|
|
473
|
-
|
|
474
|
-
// Log all role creations
|
|
475
|
-
runtime.registerEvent({
|
|
476
|
-
name: DiscordEventTypes.ROLE_CREATED,
|
|
477
|
-
handler: async (payload) => {
|
|
478
|
-
console.log(`New role created: ${payload.role.name}`, {
|
|
479
|
-
permissions: payload.role.permissions,
|
|
480
|
-
createdBy: payload.audit?.executorTag || 'Unknown',
|
|
481
|
-
});
|
|
482
|
-
},
|
|
483
|
-
});
|
|
484
|
-
```
|
|
485
|
-
|
|
486
|
-
#### Bot Self-Protection
|
|
487
|
-
|
|
488
|
-
Monitor when the bot's own permissions change:
|
|
489
|
-
|
|
490
|
-
```typescript
|
|
491
|
-
runtime.registerEvent({
|
|
492
|
-
name: DiscordEventTypes.MEMBER_ROLES_CHANGED,
|
|
493
|
-
handler: async (payload) => {
|
|
494
|
-
const botId = runtime.getSetting('DISCORD_APPLICATION_ID');
|
|
495
|
-
|
|
496
|
-
if (payload.member.id === botId && payload.removed.length > 0) {
|
|
497
|
-
console.error(`🚨 Bot roles removed!`, {
|
|
498
|
-
removed: payload.removed.map(r => r.name),
|
|
499
|
-
by: payload.audit?.executorTag || 'Unknown',
|
|
500
|
-
});
|
|
501
|
-
// Could trigger alerts, notifications, etc.
|
|
502
|
-
}
|
|
503
|
-
},
|
|
504
|
-
});
|
|
505
|
-
```
|
|
506
|
-
|
|
507
|
-
## Cross-Core Compatibility
|
|
508
|
-
|
|
509
|
-
This plugin includes a compatibility layer (`compat.ts`) that allows it to work with both old and new versions of `@elizaos/core`. The compatibility layer:
|
|
510
|
-
|
|
511
|
-
- Automatically handles `serverId` vs `messageServerId` differences
|
|
512
|
-
- Uses a runtime proxy to intercept and adapt API calls
|
|
513
|
-
- Requires no changes to existing code
|
|
514
|
-
|
|
515
|
-
When migrating to a new core version, see the comments in `compat.ts` for removal instructions.
|
|
516
|
-
|
|
517
|
-
## Testing
|
|
518
|
-
|
|
519
|
-
The plugin includes a test suite for validating functionality:
|
|
520
|
-
|
|
521
|
-
```bash
|
|
522
|
-
bun run test
|
|
523
|
-
```
|
|
524
|
-
|
|
525
|
-
## Notes
|
|
526
|
-
|
|
527
|
-
- Ensure that your `.env` file includes the required `DISCORD_API_TOKEN`
|
|
528
|
-
- The bot requires appropriate Discord permissions (send messages, connect to voice, etc.)
|
|
529
|
-
- If no token is provided, the plugin will load but remain non-functional with appropriate warnings
|
|
530
|
-
- The plugin uses Discord.js v14.18.0 with comprehensive intent support
|
|
531
|
-
- Slash commands and modal/component interactions bypass channel whitelists
|