@animalabs/agent-framework 0.1.0
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/LICENSE +21 -0
- package/README.md +233 -0
- package/dist/src/agent.d.ts +130 -0
- package/dist/src/agent.d.ts.map +1 -0
- package/dist/src/agent.js +406 -0
- package/dist/src/agent.js.map +1 -0
- package/dist/src/api/mcp-server.d.ts +37 -0
- package/dist/src/api/mcp-server.d.ts.map +1 -0
- package/dist/src/api/mcp-server.js +598 -0
- package/dist/src/api/mcp-server.js.map +1 -0
- package/dist/src/api/server.d.ts +83 -0
- package/dist/src/api/server.d.ts.map +1 -0
- package/dist/src/api/server.js +785 -0
- package/dist/src/api/server.js.map +1 -0
- package/dist/src/api/types.d.ts +395 -0
- package/dist/src/api/types.d.ts.map +1 -0
- package/dist/src/api/types.js +5 -0
- package/dist/src/api/types.js.map +1 -0
- package/dist/src/framework.d.ts +309 -0
- package/dist/src/framework.d.ts.map +1 -0
- package/dist/src/framework.js +2309 -0
- package/dist/src/framework.js.map +1 -0
- package/dist/src/gate/event-gate.d.ts +75 -0
- package/dist/src/gate/event-gate.d.ts.map +1 -0
- package/dist/src/gate/event-gate.js +503 -0
- package/dist/src/gate/event-gate.js.map +1 -0
- package/dist/src/gate/index.d.ts +3 -0
- package/dist/src/gate/index.d.ts.map +1 -0
- package/dist/src/gate/index.js +2 -0
- package/dist/src/gate/index.js.map +1 -0
- package/dist/src/gate/types.d.ts +82 -0
- package/dist/src/gate/types.d.ts.map +1 -0
- package/dist/src/gate/types.js +9 -0
- package/dist/src/gate/types.js.map +1 -0
- package/dist/src/index.d.ts +17 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +18 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/mcpl/channel-registry.d.ts +141 -0
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -0
- package/dist/src/mcpl/channel-registry.js +647 -0
- package/dist/src/mcpl/channel-registry.js.map +1 -0
- package/dist/src/mcpl/checkpoint-manager.d.ts +79 -0
- package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -0
- package/dist/src/mcpl/checkpoint-manager.js +430 -0
- package/dist/src/mcpl/checkpoint-manager.js.map +1 -0
- package/dist/src/mcpl/errors.d.ts +52 -0
- package/dist/src/mcpl/errors.d.ts.map +1 -0
- package/dist/src/mcpl/errors.js +93 -0
- package/dist/src/mcpl/errors.js.map +1 -0
- package/dist/src/mcpl/feature-set-manager.d.ts +91 -0
- package/dist/src/mcpl/feature-set-manager.d.ts.map +1 -0
- package/dist/src/mcpl/feature-set-manager.js +250 -0
- package/dist/src/mcpl/feature-set-manager.js.map +1 -0
- package/dist/src/mcpl/hook-orchestrator.d.ts +51 -0
- package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -0
- package/dist/src/mcpl/hook-orchestrator.js +217 -0
- package/dist/src/mcpl/hook-orchestrator.js.map +1 -0
- package/dist/src/mcpl/index.d.ts +14 -0
- package/dist/src/mcpl/index.d.ts.map +1 -0
- package/dist/src/mcpl/index.js +21 -0
- package/dist/src/mcpl/index.js.map +1 -0
- package/dist/src/mcpl/inference-router.d.ts +67 -0
- package/dist/src/mcpl/inference-router.d.ts.map +1 -0
- package/dist/src/mcpl/inference-router.js +249 -0
- package/dist/src/mcpl/inference-router.js.map +1 -0
- package/dist/src/mcpl/push-handler.d.ts +60 -0
- package/dist/src/mcpl/push-handler.d.ts.map +1 -0
- package/dist/src/mcpl/push-handler.js +162 -0
- package/dist/src/mcpl/push-handler.js.map +1 -0
- package/dist/src/mcpl/scope-manager.d.ts +76 -0
- package/dist/src/mcpl/scope-manager.d.ts.map +1 -0
- package/dist/src/mcpl/scope-manager.js +213 -0
- package/dist/src/mcpl/scope-manager.js.map +1 -0
- package/dist/src/mcpl/server-connection.d.ts +174 -0
- package/dist/src/mcpl/server-connection.d.ts.map +1 -0
- package/dist/src/mcpl/server-connection.js +559 -0
- package/dist/src/mcpl/server-connection.js.map +1 -0
- package/dist/src/mcpl/server-registry.d.ts +63 -0
- package/dist/src/mcpl/server-registry.d.ts.map +1 -0
- package/dist/src/mcpl/server-registry.js +119 -0
- package/dist/src/mcpl/server-registry.js.map +1 -0
- package/dist/src/mcpl/types.d.ts +755 -0
- package/dist/src/mcpl/types.d.ts.map +1 -0
- package/dist/src/mcpl/types.js +48 -0
- package/dist/src/mcpl/types.js.map +1 -0
- package/dist/src/module-registry.d.ts +93 -0
- package/dist/src/module-registry.d.ts.map +1 -0
- package/dist/src/module-registry.js +386 -0
- package/dist/src/module-registry.js.map +1 -0
- package/dist/src/modules/api/index.d.ts +22 -0
- package/dist/src/modules/api/index.d.ts.map +1 -0
- package/dist/src/modules/api/index.js +63 -0
- package/dist/src/modules/api/index.js.map +1 -0
- package/dist/src/modules/discord/discord-js-client.d.ts +58 -0
- package/dist/src/modules/discord/discord-js-client.d.ts.map +1 -0
- package/dist/src/modules/discord/discord-js-client.js +273 -0
- package/dist/src/modules/discord/discord-js-client.js.map +1 -0
- package/dist/src/modules/discord/index.d.ts +82 -0
- package/dist/src/modules/discord/index.d.ts.map +1 -0
- package/dist/src/modules/discord/index.js +959 -0
- package/dist/src/modules/discord/index.js.map +1 -0
- package/dist/src/modules/discord/types.d.ts +327 -0
- package/dist/src/modules/discord/types.d.ts.map +1 -0
- package/dist/src/modules/discord/types.js +5 -0
- package/dist/src/modules/discord/types.js.map +1 -0
- package/dist/src/modules/index.d.ts +11 -0
- package/dist/src/modules/index.d.ts.map +1 -0
- package/dist/src/modules/index.js +7 -0
- package/dist/src/modules/index.js.map +1 -0
- package/dist/src/modules/workspace/index.d.ts +59 -0
- package/dist/src/modules/workspace/index.d.ts.map +1 -0
- package/dist/src/modules/workspace/index.js +831 -0
- package/dist/src/modules/workspace/index.js.map +1 -0
- package/dist/src/modules/workspace/sync.d.ts +48 -0
- package/dist/src/modules/workspace/sync.d.ts.map +1 -0
- package/dist/src/modules/workspace/sync.js +253 -0
- package/dist/src/modules/workspace/sync.js.map +1 -0
- package/dist/src/modules/workspace/types.d.ts +166 -0
- package/dist/src/modules/workspace/types.d.ts.map +1 -0
- package/dist/src/modules/workspace/types.js +5 -0
- package/dist/src/modules/workspace/types.js.map +1 -0
- package/dist/src/modules/workspace/watcher.d.ts +43 -0
- package/dist/src/modules/workspace/watcher.d.ts.map +1 -0
- package/dist/src/modules/workspace/watcher.js +120 -0
- package/dist/src/modules/workspace/watcher.js.map +1 -0
- package/dist/src/queue.d.ts +50 -0
- package/dist/src/queue.d.ts.map +1 -0
- package/dist/src/queue.js +95 -0
- package/dist/src/queue.js.map +1 -0
- package/dist/src/safe-slice.d.ts +8 -0
- package/dist/src/safe-slice.d.ts.map +1 -0
- package/dist/src/safe-slice.js +18 -0
- package/dist/src/safe-slice.js.map +1 -0
- package/dist/src/types/agent.d.ts +118 -0
- package/dist/src/types/agent.d.ts.map +1 -0
- package/dist/src/types/agent.js +2 -0
- package/dist/src/types/agent.js.map +1 -0
- package/dist/src/types/events.d.ts +220 -0
- package/dist/src/types/events.d.ts.map +1 -0
- package/dist/src/types/events.js +2 -0
- package/dist/src/types/events.js.map +1 -0
- package/dist/src/types/framework.d.ts +184 -0
- package/dist/src/types/framework.d.ts.map +1 -0
- package/dist/src/types/framework.js +2 -0
- package/dist/src/types/framework.js.map +1 -0
- package/dist/src/types/index.d.ts +7 -0
- package/dist/src/types/index.d.ts.map +1 -0
- package/dist/src/types/index.js +7 -0
- package/dist/src/types/index.js.map +1 -0
- package/dist/src/types/inference-log.d.ts +64 -0
- package/dist/src/types/inference-log.d.ts.map +1 -0
- package/dist/src/types/inference-log.js +5 -0
- package/dist/src/types/inference-log.js.map +1 -0
- package/dist/src/types/module.d.ts +302 -0
- package/dist/src/types/module.d.ts.map +1 -0
- package/dist/src/types/module.js +2 -0
- package/dist/src/types/module.js.map +1 -0
- package/dist/src/types/trace.d.ts +173 -0
- package/dist/src/types/trace.d.ts.map +1 -0
- package/dist/src/types/trace.js +2 -0
- package/dist/src/types/trace.js.map +1 -0
- package/dist/test/event-gate.test.d.ts +2 -0
- package/dist/test/event-gate.test.d.ts.map +1 -0
- package/dist/test/event-gate.test.js +535 -0
- package/dist/test/event-gate.test.js.map +1 -0
- package/dist/test/framework.test.d.ts +5 -0
- package/dist/test/framework.test.d.ts.map +1 -0
- package/dist/test/framework.test.js +738 -0
- package/dist/test/framework.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +58 -0
- package/src/agent.ts +512 -0
- package/src/api/mcp-server.ts +687 -0
- package/src/api/server.ts +1023 -0
- package/src/api/types.ts +542 -0
- package/src/framework.ts +2784 -0
- package/src/gate/event-gate.ts +623 -0
- package/src/gate/index.ts +12 -0
- package/src/gate/types.ts +112 -0
- package/src/index.ts +63 -0
- package/src/mcpl/channel-registry.ts +824 -0
- package/src/mcpl/checkpoint-manager.ts +545 -0
- package/src/mcpl/errors.ts +114 -0
- package/src/mcpl/feature-set-manager.ts +333 -0
- package/src/mcpl/hook-orchestrator.ts +281 -0
- package/src/mcpl/index.ts +134 -0
- package/src/mcpl/inference-router.ts +335 -0
- package/src/mcpl/push-handler.ts +232 -0
- package/src/mcpl/scope-manager.ts +262 -0
- package/src/mcpl/server-connection.ts +694 -0
- package/src/mcpl/server-registry.ts +144 -0
- package/src/mcpl/types.ts +991 -0
- package/src/module-registry.ts +547 -0
- package/src/modules/api/index.ts +94 -0
- package/src/modules/discord/discord-js-client.ts +353 -0
- package/src/modules/discord/index.ts +1146 -0
- package/src/modules/discord/types.ts +465 -0
- package/src/modules/index.ts +43 -0
- package/src/modules/workspace/index.ts +969 -0
- package/src/modules/workspace/sync.ts +314 -0
- package/src/modules/workspace/types.ts +202 -0
- package/src/modules/workspace/watcher.ts +142 -0
- package/src/queue.ts +106 -0
- package/src/safe-slice.ts +18 -0
- package/src/types/agent.ts +119 -0
- package/src/types/events.ts +252 -0
- package/src/types/framework.ts +211 -0
- package/src/types/index.ts +6 -0
- package/src/types/inference-log.ts +64 -0
- package/src/types/module.ts +367 -0
- package/src/types/trace.ts +196 -0
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discord.js client adapter implementing DiscordClientInterface
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
Client,
|
|
7
|
+
GatewayIntentBits,
|
|
8
|
+
Partials,
|
|
9
|
+
TextChannel,
|
|
10
|
+
DMChannel,
|
|
11
|
+
type Message,
|
|
12
|
+
type Attachment,
|
|
13
|
+
type User,
|
|
14
|
+
type Guild,
|
|
15
|
+
type GuildBasedChannel,
|
|
16
|
+
} from 'discord.js';
|
|
17
|
+
import type {
|
|
18
|
+
DiscordClientInterface,
|
|
19
|
+
DiscordMessageData,
|
|
20
|
+
DiscordAttachment,
|
|
21
|
+
DiscordGuild,
|
|
22
|
+
DiscordChannel,
|
|
23
|
+
HistoryMessage,
|
|
24
|
+
} from './types.js';
|
|
25
|
+
|
|
26
|
+
export interface DiscordJsClientConfig {
|
|
27
|
+
token: string;
|
|
28
|
+
guildIds?: string[];
|
|
29
|
+
channelIds?: string[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class DiscordJsClient implements DiscordClientInterface {
|
|
33
|
+
private client: Client;
|
|
34
|
+
private token: string;
|
|
35
|
+
private guildIds?: string[];
|
|
36
|
+
private channelIds?: string[];
|
|
37
|
+
|
|
38
|
+
private messageHandler?: (message: DiscordMessageData) => void;
|
|
39
|
+
private editHandler?: (messageId: string, newContent: string) => void;
|
|
40
|
+
private deleteHandler?: (messageId: string) => void;
|
|
41
|
+
private readyHandler?: () => void;
|
|
42
|
+
|
|
43
|
+
constructor(config: DiscordJsClientConfig) {
|
|
44
|
+
this.token = config.token;
|
|
45
|
+
this.guildIds = config.guildIds;
|
|
46
|
+
this.channelIds = config.channelIds;
|
|
47
|
+
|
|
48
|
+
this.client = new Client({
|
|
49
|
+
intents: [
|
|
50
|
+
GatewayIntentBits.Guilds,
|
|
51
|
+
GatewayIntentBits.GuildMessages,
|
|
52
|
+
GatewayIntentBits.MessageContent,
|
|
53
|
+
GatewayIntentBits.DirectMessages,
|
|
54
|
+
GatewayIntentBits.GuildMessageReactions,
|
|
55
|
+
],
|
|
56
|
+
partials: [Partials.Channel, Partials.Message],
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
this.setupEventHandlers();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private setupEventHandlers(): void {
|
|
63
|
+
this.client.on('messageCreate', (message: Message) => {
|
|
64
|
+
if (!this.shouldHandleMessage(message)) return;
|
|
65
|
+
if (this.messageHandler) {
|
|
66
|
+
this.messageHandler(this.convertMessage(message));
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
this.client.on('messageUpdate', (_oldMessage, newMessage) => {
|
|
71
|
+
if (!newMessage.content || !this.editHandler) return;
|
|
72
|
+
this.editHandler(newMessage.id, newMessage.content);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
this.client.on('messageDelete', (message) => {
|
|
76
|
+
if (this.deleteHandler) {
|
|
77
|
+
this.deleteHandler(message.id);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
this.client.on('ready', () => {
|
|
82
|
+
console.log(`[Discord] Logged in as ${this.client.user?.tag}`);
|
|
83
|
+
if (this.readyHandler) {
|
|
84
|
+
this.readyHandler();
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
this.client.on('error', (error: Error) => {
|
|
89
|
+
console.error('[Discord] Client error:', error);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private shouldHandleMessage(message: Message): boolean {
|
|
94
|
+
// Never process our own messages (prevents feedback loop)
|
|
95
|
+
if (message.author.id === this.client.user?.id) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Filter by guild
|
|
100
|
+
if (this.guildIds && this.guildIds.length > 0) {
|
|
101
|
+
if (!message.guildId || !this.guildIds.includes(message.guildId)) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Filter by channel
|
|
107
|
+
if (this.channelIds && this.channelIds.length > 0) {
|
|
108
|
+
if (!this.channelIds.includes(message.channelId)) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private convertMessage(message: Message): DiscordMessageData {
|
|
117
|
+
const attachments: DiscordAttachment[] = message.attachments.map((a: Attachment) => ({
|
|
118
|
+
id: a.id,
|
|
119
|
+
filename: a.name ?? 'unknown',
|
|
120
|
+
url: a.url,
|
|
121
|
+
contentType: a.contentType ?? undefined,
|
|
122
|
+
size: a.size,
|
|
123
|
+
}));
|
|
124
|
+
|
|
125
|
+
// Extract mentioned user IDs
|
|
126
|
+
const mentionedUserIds = message.mentions.users.map((u: User) => u.id);
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
id: message.id,
|
|
130
|
+
content: message.content,
|
|
131
|
+
authorId: message.author.id,
|
|
132
|
+
authorName: message.author.username,
|
|
133
|
+
isBot: message.author.bot,
|
|
134
|
+
channelId: message.channelId,
|
|
135
|
+
guildId: message.guildId ?? null,
|
|
136
|
+
isReply: message.reference !== null,
|
|
137
|
+
replyToId: message.reference?.messageId ?? undefined,
|
|
138
|
+
// Note: replyToAuthorId requires fetching the referenced message
|
|
139
|
+
// We'll leave it undefined for now - can be enhanced later if needed
|
|
140
|
+
replyToAuthorId: undefined,
|
|
141
|
+
mentionedUserIds,
|
|
142
|
+
attachments,
|
|
143
|
+
timestamp: message.createdAt,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async connect(): Promise<void> {
|
|
148
|
+
await this.client.login(this.token);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async disconnect(): Promise<void> {
|
|
152
|
+
this.client.destroy();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
isConnected(): boolean {
|
|
156
|
+
return this.client.isReady();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async sendMessage(
|
|
160
|
+
channelId: string,
|
|
161
|
+
content: string,
|
|
162
|
+
options?: { replyTo?: string; createThread?: { name: string } }
|
|
163
|
+
): Promise<{ messageId: string }> {
|
|
164
|
+
const channel = await this.client.channels.fetch(channelId);
|
|
165
|
+
if (!channel || !('send' in channel)) {
|
|
166
|
+
throw new Error(`Channel ${channelId} not found or not a text channel`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const textChannel = channel as TextChannel | DMChannel;
|
|
170
|
+
const message = await textChannel.send({
|
|
171
|
+
content,
|
|
172
|
+
reply: options?.replyTo ? { messageReference: options.replyTo } : undefined,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
if (options?.createThread && 'threads' in textChannel) {
|
|
176
|
+
await message.startThread({ name: options.createThread.name });
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return { messageId: message.id };
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async sendDM(userId: string, content: string): Promise<{ messageId: string }> {
|
|
183
|
+
const user = await this.client.users.fetch(userId);
|
|
184
|
+
const message = await user.send(content);
|
|
185
|
+
return { messageId: message.id };
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async fetchMessage(channelId: string, messageId: string): Promise<string> {
|
|
189
|
+
const channel = await this.client.channels.fetch(channelId);
|
|
190
|
+
if (!channel || !('messages' in channel)) {
|
|
191
|
+
throw new Error(`Channel ${channelId} not found`);
|
|
192
|
+
}
|
|
193
|
+
const message = await (channel as TextChannel).messages.fetch(messageId);
|
|
194
|
+
return message.content;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async editMessage(channelId: string, messageId: string, content: string): Promise<void> {
|
|
198
|
+
const channel = await this.client.channels.fetch(channelId);
|
|
199
|
+
if (!channel || !('messages' in channel)) {
|
|
200
|
+
throw new Error(`Channel ${channelId} not found`);
|
|
201
|
+
}
|
|
202
|
+
const message = await (channel as TextChannel).messages.fetch(messageId);
|
|
203
|
+
await message.edit(content);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
async deleteMessage(channelId: string, messageId: string): Promise<void> {
|
|
207
|
+
const channel = await this.client.channels.fetch(channelId);
|
|
208
|
+
if (!channel || !('messages' in channel)) {
|
|
209
|
+
throw new Error(`Channel ${channelId} not found`);
|
|
210
|
+
}
|
|
211
|
+
const message = await (channel as TextChannel).messages.fetch(messageId);
|
|
212
|
+
await message.delete();
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async addReaction(channelId: string, messageId: string, emoji: string): Promise<void> {
|
|
216
|
+
const channel = await this.client.channels.fetch(channelId);
|
|
217
|
+
if (!channel || !('messages' in channel)) {
|
|
218
|
+
throw new Error(`Channel ${channelId} not found`);
|
|
219
|
+
}
|
|
220
|
+
const message = await (channel as TextChannel).messages.fetch(messageId);
|
|
221
|
+
await message.react(emoji);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
async createThread(
|
|
225
|
+
channelId: string,
|
|
226
|
+
messageId: string,
|
|
227
|
+
name: string,
|
|
228
|
+
autoArchiveDuration?: number
|
|
229
|
+
): Promise<{ threadId: string }> {
|
|
230
|
+
const channel = await this.client.channels.fetch(channelId);
|
|
231
|
+
if (!channel || !('messages' in channel)) {
|
|
232
|
+
throw new Error(`Channel ${channelId} not found`);
|
|
233
|
+
}
|
|
234
|
+
const message = await (channel as TextChannel).messages.fetch(messageId);
|
|
235
|
+
const thread = await message.startThread({
|
|
236
|
+
name,
|
|
237
|
+
autoArchiveDuration: (autoArchiveDuration as 60 | 1440 | 4320 | 10080) ?? 1440,
|
|
238
|
+
});
|
|
239
|
+
return { threadId: thread.id };
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
onMessage(handler: (message: DiscordMessageData) => void): void {
|
|
243
|
+
this.messageHandler = handler;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
onMessageEdit(handler: (messageId: string, newContent: string) => void): void {
|
|
247
|
+
this.editHandler = handler;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
onMessageDelete(handler: (messageId: string) => void): void {
|
|
251
|
+
this.deleteHandler = handler;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
onReady(handler: () => void): void {
|
|
255
|
+
this.readyHandler = handler;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
getBotUserId(): string | null {
|
|
259
|
+
return this.client.user?.id ?? null;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
async sendTyping(channelId: string): Promise<void> {
|
|
263
|
+
const channel = await this.client.channels.fetch(channelId);
|
|
264
|
+
if (!channel || !('sendTyping' in channel)) {
|
|
265
|
+
throw new Error(`Channel ${channelId} not found or not a text channel`);
|
|
266
|
+
}
|
|
267
|
+
await (channel as TextChannel).sendTyping();
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
async listGuilds(): Promise<DiscordGuild[]> {
|
|
271
|
+
const guilds = this.client.guilds.cache;
|
|
272
|
+
return guilds.map((g: Guild) => ({
|
|
273
|
+
id: g.id,
|
|
274
|
+
name: g.name,
|
|
275
|
+
iconUrl: g.iconURL() ?? undefined,
|
|
276
|
+
memberCount: g.memberCount,
|
|
277
|
+
}));
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
async listChannels(guildId: string): Promise<DiscordChannel[]> {
|
|
281
|
+
const guild = await this.client.guilds.fetch(guildId);
|
|
282
|
+
if (!guild) {
|
|
283
|
+
throw new Error(`Guild ${guildId} not found`);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// guild.channels might be undefined if the guild was fetched without full data
|
|
287
|
+
if (!guild.channels) {
|
|
288
|
+
throw new Error(`Guild ${guildId} channels not available - may need to re-fetch with force`);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const channels = await guild.channels.fetch();
|
|
292
|
+
const result: DiscordChannel[] = [];
|
|
293
|
+
|
|
294
|
+
channels.forEach((c: GuildBasedChannel | null) => {
|
|
295
|
+
if (c) {
|
|
296
|
+
result.push({
|
|
297
|
+
id: c.id,
|
|
298
|
+
name: c.name,
|
|
299
|
+
type: this.mapChannelType(c.type),
|
|
300
|
+
parentId: c.parentId ?? undefined,
|
|
301
|
+
position: 'position' in c ? (c as { position?: number }).position : undefined,
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
return result;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
private mapChannelType(type: number | undefined): DiscordChannel['type'] {
|
|
310
|
+
if (type === undefined) return 'unknown';
|
|
311
|
+
// Discord.js channel types: 0=text, 2=voice, 4=category, 11=thread, 15=forum
|
|
312
|
+
switch (type) {
|
|
313
|
+
case 0: return 'text';
|
|
314
|
+
case 2: return 'voice';
|
|
315
|
+
case 4: return 'category';
|
|
316
|
+
case 11:
|
|
317
|
+
case 12: return 'thread';
|
|
318
|
+
case 15: return 'forum';
|
|
319
|
+
default: return 'unknown';
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
async fetchHistory(
|
|
324
|
+
channelId: string,
|
|
325
|
+
options?: { limit?: number; before?: string }
|
|
326
|
+
): Promise<HistoryMessage[]> {
|
|
327
|
+
const channel = await this.client.channels.fetch(channelId);
|
|
328
|
+
if (!channel || !('messages' in channel)) {
|
|
329
|
+
throw new Error(`Channel ${channelId} not found or not a text channel`);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const textChannel = channel as TextChannel;
|
|
333
|
+
const messages = await textChannel.messages.fetch({
|
|
334
|
+
limit: options?.limit ?? 50,
|
|
335
|
+
before: options?.before,
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
return messages.map((m: Message) => ({
|
|
339
|
+
id: m.id,
|
|
340
|
+
authorId: m.author.id,
|
|
341
|
+
authorName: m.author.username,
|
|
342
|
+
isBot: m.author.bot,
|
|
343
|
+
content: m.content,
|
|
344
|
+
timestamp: m.createdAt,
|
|
345
|
+
replyTo: m.reference
|
|
346
|
+
? {
|
|
347
|
+
messageId: m.reference.messageId ?? '',
|
|
348
|
+
authorId: '', // Would need additional fetch to get this
|
|
349
|
+
}
|
|
350
|
+
: undefined,
|
|
351
|
+
}));
|
|
352
|
+
}
|
|
353
|
+
}
|