@herdctl/slack 0.0.1 → 0.2.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.
Files changed (102) hide show
  1. package/LICENSE +21 -0
  2. package/dist/__tests__/command-handler.test.d.ts +2 -0
  3. package/dist/__tests__/command-handler.test.d.ts.map +1 -0
  4. package/dist/__tests__/command-handler.test.js +141 -0
  5. package/dist/__tests__/command-handler.test.js.map +1 -0
  6. package/dist/__tests__/error-handler.test.d.ts +2 -0
  7. package/dist/__tests__/error-handler.test.d.ts.map +1 -0
  8. package/dist/__tests__/error-handler.test.js +168 -0
  9. package/dist/__tests__/error-handler.test.js.map +1 -0
  10. package/dist/__tests__/errors.test.d.ts +2 -0
  11. package/dist/__tests__/errors.test.d.ts.map +1 -0
  12. package/dist/__tests__/errors.test.js +133 -0
  13. package/dist/__tests__/errors.test.js.map +1 -0
  14. package/dist/__tests__/formatting.test.d.ts +2 -0
  15. package/dist/__tests__/formatting.test.d.ts.map +1 -0
  16. package/dist/__tests__/formatting.test.js +216 -0
  17. package/dist/__tests__/formatting.test.js.map +1 -0
  18. package/dist/__tests__/logger.test.d.ts +2 -0
  19. package/dist/__tests__/logger.test.d.ts.map +1 -0
  20. package/dist/__tests__/logger.test.js +97 -0
  21. package/dist/__tests__/logger.test.js.map +1 -0
  22. package/dist/__tests__/message-handler.test.d.ts +2 -0
  23. package/dist/__tests__/message-handler.test.d.ts.map +1 -0
  24. package/dist/__tests__/message-handler.test.js +78 -0
  25. package/dist/__tests__/message-handler.test.js.map +1 -0
  26. package/dist/__tests__/session-manager.test.d.ts +2 -0
  27. package/dist/__tests__/session-manager.test.d.ts.map +1 -0
  28. package/dist/__tests__/session-manager.test.js +214 -0
  29. package/dist/__tests__/session-manager.test.js.map +1 -0
  30. package/dist/__tests__/slack-connector.test.d.ts +2 -0
  31. package/dist/__tests__/slack-connector.test.d.ts.map +1 -0
  32. package/dist/__tests__/slack-connector.test.js +376 -0
  33. package/dist/__tests__/slack-connector.test.js.map +1 -0
  34. package/dist/commands/command-handler.d.ts +72 -0
  35. package/dist/commands/command-handler.d.ts.map +1 -0
  36. package/dist/commands/command-handler.js +85 -0
  37. package/dist/commands/command-handler.js.map +1 -0
  38. package/dist/commands/help.d.ts +6 -0
  39. package/dist/commands/help.d.ts.map +1 -0
  40. package/dist/commands/help.js +22 -0
  41. package/dist/commands/help.js.map +1 -0
  42. package/dist/commands/index.d.ts +11 -0
  43. package/dist/commands/index.d.ts.map +1 -0
  44. package/dist/commands/index.js +10 -0
  45. package/dist/commands/index.js.map +1 -0
  46. package/dist/commands/reset.d.ts +6 -0
  47. package/dist/commands/reset.d.ts.map +1 -0
  48. package/dist/commands/reset.js +18 -0
  49. package/dist/commands/reset.js.map +1 -0
  50. package/dist/commands/status.d.ts +6 -0
  51. package/dist/commands/status.d.ts.map +1 -0
  52. package/dist/commands/status.js +94 -0
  53. package/dist/commands/status.js.map +1 -0
  54. package/dist/error-handler.d.ts +50 -0
  55. package/dist/error-handler.d.ts.map +1 -0
  56. package/dist/error-handler.js +123 -0
  57. package/dist/error-handler.js.map +1 -0
  58. package/dist/errors.d.ts +59 -0
  59. package/dist/errors.d.ts.map +1 -0
  60. package/dist/errors.js +73 -0
  61. package/dist/errors.js.map +1 -0
  62. package/dist/formatting.d.ts +83 -0
  63. package/dist/formatting.d.ts.map +1 -0
  64. package/dist/formatting.js +155 -0
  65. package/dist/formatting.js.map +1 -0
  66. package/dist/index.d.ts +31 -0
  67. package/dist/index.d.ts.map +1 -0
  68. package/dist/index.js +34 -0
  69. package/dist/index.js.map +1 -0
  70. package/dist/logger.d.ts +28 -0
  71. package/dist/logger.d.ts.map +1 -0
  72. package/dist/logger.js +40 -0
  73. package/dist/logger.js.map +1 -0
  74. package/dist/message-handler.d.ts +62 -0
  75. package/dist/message-handler.d.ts.map +1 -0
  76. package/dist/message-handler.js +85 -0
  77. package/dist/message-handler.js.map +1 -0
  78. package/dist/session-manager/errors.d.ts +58 -0
  79. package/dist/session-manager/errors.d.ts.map +1 -0
  80. package/dist/session-manager/errors.js +70 -0
  81. package/dist/session-manager/errors.js.map +1 -0
  82. package/dist/session-manager/index.d.ts +9 -0
  83. package/dist/session-manager/index.d.ts.map +1 -0
  84. package/dist/session-manager/index.js +13 -0
  85. package/dist/session-manager/index.js.map +1 -0
  86. package/dist/session-manager/session-manager.d.ts +62 -0
  87. package/dist/session-manager/session-manager.d.ts.map +1 -0
  88. package/dist/session-manager/session-manager.js +325 -0
  89. package/dist/session-manager/session-manager.js.map +1 -0
  90. package/dist/session-manager/types.d.ts +154 -0
  91. package/dist/session-manager/types.d.ts.map +1 -0
  92. package/dist/session-manager/types.js +57 -0
  93. package/dist/session-manager/types.js.map +1 -0
  94. package/dist/slack-connector.d.ts +53 -0
  95. package/dist/slack-connector.d.ts.map +1 -0
  96. package/dist/slack-connector.js +447 -0
  97. package/dist/slack-connector.js.map +1 -0
  98. package/dist/types.d.ts +211 -0
  99. package/dist/types.d.ts.map +1 -0
  100. package/dist/types.js +8 -0
  101. package/dist/types.js.map +1 -0
  102. package/package.json +42 -4
@@ -0,0 +1,447 @@
1
+ /**
2
+ * Slack Connector
3
+ *
4
+ * Single Bolt App instance with channel->agent routing.
5
+ * Uses Socket Mode for connection (no public URL needed).
6
+ *
7
+ * Key design:
8
+ * - ONE connector shared across all agents (not N connectors)
9
+ * - Channel->agent routing via channelAgentMap
10
+ * - Channel-based conversations (channelId as session key, matching Discord)
11
+ * - Hourglass emoji reaction as typing indicator
12
+ */
13
+ import { EventEmitter } from "node:events";
14
+ import { shouldProcessMessage, processMessage, isBotMentioned, } from "./message-handler.js";
15
+ import { CommandHandler, helpCommand, resetCommand, statusCommand, } from "./commands/index.js";
16
+ import { markdownToMrkdwn } from "./formatting.js";
17
+ import { AlreadyConnectedError, SlackConnectionError } from "./errors.js";
18
+ import { createDefaultSlackLogger } from "./logger.js";
19
+ // =============================================================================
20
+ // Slack Connector Implementation
21
+ // =============================================================================
22
+ export class SlackConnector extends EventEmitter {
23
+ botToken;
24
+ appToken;
25
+ channelAgentMap;
26
+ channelConfigs;
27
+ sessionManagers;
28
+ logger;
29
+ // Bolt App instance (dynamically imported)
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
+ app = null;
32
+ // Command handler for prefix commands (!help, !reset, !status)
33
+ commandHandler = null;
34
+ // Connection state
35
+ status = "disconnected";
36
+ connectedAt = null;
37
+ disconnectedAt = null;
38
+ reconnectAttempts = 0;
39
+ lastError = null;
40
+ botUserId = null;
41
+ botUsername = null;
42
+ // Message stats
43
+ messagesReceived = 0;
44
+ messagesSent = 0;
45
+ messagesIgnored = 0;
46
+ constructor(options) {
47
+ super();
48
+ this.botToken = options.botToken;
49
+ this.appToken = options.appToken;
50
+ this.channelAgentMap = options.channelAgentMap;
51
+ this.channelConfigs = options.channelConfigs ?? new Map();
52
+ this.sessionManagers = options.sessionManagers;
53
+ this.logger = options.logger ?? createDefaultSlackLogger();
54
+ }
55
+ // ===========================================================================
56
+ // ISlackConnector Implementation
57
+ // ===========================================================================
58
+ async connect() {
59
+ if (this.status === "connected" || this.status === "connecting") {
60
+ throw new AlreadyConnectedError();
61
+ }
62
+ this.status = "connecting";
63
+ this.logger.info("Connecting to Slack via Socket Mode...");
64
+ try {
65
+ // Dynamically import @slack/bolt
66
+ const { App } = await import("@slack/bolt");
67
+ this.app = new App({
68
+ token: this.botToken,
69
+ appToken: this.appToken,
70
+ socketMode: true,
71
+ });
72
+ // Register event handlers
73
+ this.registerEventHandlers();
74
+ // Start the app
75
+ await this.app.start();
76
+ // Get bot info
77
+ const authResult = await this.app.client.auth.test();
78
+ this.botUserId = authResult.user_id;
79
+ this.botUsername = authResult.user;
80
+ // Initialize command handler with built-in commands
81
+ this.commandHandler = new CommandHandler({ logger: this.logger });
82
+ this.commandHandler.registerCommand(helpCommand);
83
+ this.commandHandler.registerCommand(resetCommand);
84
+ this.commandHandler.registerCommand(statusCommand);
85
+ this.status = "connected";
86
+ this.connectedAt = new Date().toISOString();
87
+ this.disconnectedAt = null;
88
+ this.reconnectAttempts = 0;
89
+ this.lastError = null;
90
+ this.logger.info("Connected to Slack", {
91
+ botUserId: this.botUserId,
92
+ botUsername: this.botUsername,
93
+ channelCount: this.channelAgentMap.size,
94
+ });
95
+ this.emit("ready", {
96
+ botUser: {
97
+ id: this.botUserId,
98
+ username: this.botUsername ?? "unknown",
99
+ },
100
+ });
101
+ // Clean up expired sessions on startup (matching Discord behavior)
102
+ for (const [agentName, sessionManager] of this.sessionManagers) {
103
+ try {
104
+ const cleaned = await sessionManager.cleanupExpiredSessions();
105
+ if (cleaned > 0) {
106
+ this.logger.info(`Cleaned ${cleaned} expired session(s) for agent '${agentName}'`);
107
+ }
108
+ }
109
+ catch (cleanupError) {
110
+ this.logger.warn(`Failed to cleanup sessions for agent '${agentName}'`, {
111
+ error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError),
112
+ });
113
+ }
114
+ }
115
+ }
116
+ catch (error) {
117
+ this.status = "error";
118
+ this.lastError =
119
+ error instanceof Error ? error.message : String(error);
120
+ this.logger.error("Failed to connect to Slack", {
121
+ error: this.lastError,
122
+ });
123
+ throw new SlackConnectionError(`Failed to connect to Slack: ${this.lastError}`, { cause: error instanceof Error ? error : undefined });
124
+ }
125
+ }
126
+ async disconnect() {
127
+ if (this.status === "disconnected" ||
128
+ this.status === "disconnecting") {
129
+ return;
130
+ }
131
+ this.status = "disconnecting";
132
+ this.logger.info("Disconnecting from Slack...");
133
+ try {
134
+ if (this.app) {
135
+ await this.app.stop();
136
+ this.app = null;
137
+ }
138
+ this.commandHandler = null;
139
+ this.status = "disconnected";
140
+ this.disconnectedAt = new Date().toISOString();
141
+ this.logger.info("Disconnected from Slack", {
142
+ messagesReceived: this.messagesReceived,
143
+ messagesSent: this.messagesSent,
144
+ messagesIgnored: this.messagesIgnored,
145
+ });
146
+ this.emit("disconnect", { reason: "Intentional disconnect" });
147
+ }
148
+ catch (error) {
149
+ this.status = "error";
150
+ this.lastError =
151
+ error instanceof Error ? error.message : String(error);
152
+ this.logger.error("Error disconnecting from Slack", {
153
+ error: this.lastError,
154
+ });
155
+ }
156
+ }
157
+ isConnected() {
158
+ return this.status === "connected" && this.app !== null;
159
+ }
160
+ getState() {
161
+ return {
162
+ status: this.status,
163
+ connectedAt: this.connectedAt,
164
+ disconnectedAt: this.disconnectedAt,
165
+ reconnectAttempts: this.reconnectAttempts,
166
+ lastError: this.lastError,
167
+ botUser: this.botUserId
168
+ ? {
169
+ id: this.botUserId,
170
+ username: this.botUsername ?? "unknown",
171
+ }
172
+ : null,
173
+ messageStats: {
174
+ received: this.messagesReceived,
175
+ sent: this.messagesSent,
176
+ ignored: this.messagesIgnored,
177
+ },
178
+ };
179
+ }
180
+ // ===========================================================================
181
+ // File Upload
182
+ // ===========================================================================
183
+ async uploadFile(params) {
184
+ if (!this.app?.client) {
185
+ throw new Error("Cannot upload file: not connected to Slack");
186
+ }
187
+ const response = await this.app.client.files.uploadV2({
188
+ channel_id: params.channelId,
189
+ file: params.fileBuffer,
190
+ filename: params.filename,
191
+ initial_comment: params.message ?? "",
192
+ });
193
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
194
+ const fileId = response.files?.[0]?.id ?? "unknown";
195
+ this.logger.info("File uploaded to Slack", {
196
+ fileId,
197
+ filename: params.filename,
198
+ channelId: params.channelId,
199
+ size: params.fileBuffer.length,
200
+ });
201
+ return { fileId };
202
+ }
203
+ // ===========================================================================
204
+ // Event Handlers
205
+ // ===========================================================================
206
+ registerEventHandlers() {
207
+ if (!this.app)
208
+ return;
209
+ // Handle @mentions
210
+ this.app.event("app_mention", async ({ event, say }) => {
211
+ this.messagesReceived++;
212
+ if (!this.botUserId)
213
+ return;
214
+ // Find which agent handles this channel
215
+ const agentName = this.channelAgentMap.get(event.channel);
216
+ if (!agentName) {
217
+ this.messagesIgnored++;
218
+ this.emit("messageIgnored", {
219
+ agentName: "unknown",
220
+ reason: "not_configured",
221
+ channelId: event.channel,
222
+ messageTs: event.ts,
223
+ });
224
+ this.logger.debug("Ignoring mention in unconfigured channel", {
225
+ channel: event.channel,
226
+ });
227
+ return;
228
+ }
229
+ const prompt = processMessage(event.text, this.botUserId);
230
+ if (!prompt) {
231
+ this.messagesIgnored++;
232
+ this.emit("messageIgnored", {
233
+ agentName,
234
+ reason: "empty_prompt",
235
+ channelId: event.channel,
236
+ messageTs: event.ts,
237
+ });
238
+ return;
239
+ }
240
+ // Check for prefix commands before processing as a message
241
+ const wasCommand = await this.tryExecuteCommand(prompt, agentName, event.channel, event.user, say);
242
+ if (wasCommand)
243
+ return;
244
+ const messageEvent = this.buildMessageEvent(agentName, prompt, event.channel, event.ts, event.user, true, say);
245
+ this.emit("message", messageEvent);
246
+ });
247
+ // Handle all messages — thread replies AND top-level channel messages
248
+ this.app.event("message", async ({ event, say }) => {
249
+ this.messagesReceived++;
250
+ if (!this.botUserId)
251
+ return;
252
+ // Ignore bot messages and own messages
253
+ if (!shouldProcessMessage(event, this.botUserId)) {
254
+ this.messagesIgnored++;
255
+ this.emit("messageIgnored", {
256
+ agentName: "unknown",
257
+ reason: "bot_message",
258
+ channelId: event.channel,
259
+ messageTs: event.ts,
260
+ });
261
+ this.logger.debug("Skipping bot/own message", {
262
+ channel: event.channel,
263
+ botId: event.bot_id,
264
+ user: event.user,
265
+ });
266
+ return;
267
+ }
268
+ // Skip @mentions — handled by the app_mention handler above
269
+ if (typeof event.text === "string" &&
270
+ isBotMentioned(event.text, this.botUserId)) {
271
+ this.logger.debug("Skipping @mention message (handled by app_mention)", {
272
+ channel: event.channel,
273
+ ts: event.ts,
274
+ });
275
+ return;
276
+ }
277
+ // Resolve agent for this channel
278
+ const resolvedAgent = this.channelAgentMap.get(event.channel);
279
+ if (!resolvedAgent) {
280
+ this.messagesIgnored++;
281
+ this.emit("messageIgnored", {
282
+ agentName: "unknown",
283
+ reason: "no_agent_resolved",
284
+ channelId: event.channel,
285
+ messageTs: event.ts,
286
+ });
287
+ this.logger.debug("No agent resolved for message", {
288
+ channel: event.channel,
289
+ });
290
+ return;
291
+ }
292
+ // For top-level messages (no thread_ts), check channel mode
293
+ if (!event.thread_ts) {
294
+ const channelConfig = this.channelConfigs.get(event.channel);
295
+ const mode = channelConfig?.mode ?? "mention";
296
+ if (mode === "mention") {
297
+ this.messagesIgnored++;
298
+ this.emit("messageIgnored", {
299
+ agentName: resolvedAgent,
300
+ reason: "not_configured",
301
+ channelId: event.channel,
302
+ messageTs: event.ts,
303
+ });
304
+ this.logger.debug("Ignoring top-level message in mention-mode channel", {
305
+ channel: event.channel,
306
+ agent: resolvedAgent,
307
+ mode,
308
+ });
309
+ return;
310
+ }
311
+ this.logger.debug("Top-level channel message (auto mode)", {
312
+ channel: event.channel,
313
+ agent: resolvedAgent,
314
+ ts: event.ts,
315
+ });
316
+ }
317
+ const prompt = processMessage(event.text ?? "", this.botUserId);
318
+ if (!prompt) {
319
+ this.messagesIgnored++;
320
+ this.emit("messageIgnored", {
321
+ agentName: resolvedAgent,
322
+ reason: "empty_prompt",
323
+ channelId: event.channel,
324
+ messageTs: event.ts,
325
+ });
326
+ return;
327
+ }
328
+ // Check for prefix commands before processing as a message
329
+ const wasCommand = await this.tryExecuteCommand(prompt, resolvedAgent, event.channel, event.user ?? "", say);
330
+ if (wasCommand)
331
+ return;
332
+ const messageEvent = this.buildMessageEvent(resolvedAgent, prompt, event.channel, event.ts, event.user ?? "", false, say);
333
+ this.emit("message", messageEvent);
334
+ });
335
+ }
336
+ // ===========================================================================
337
+ // Command Handling
338
+ // ===========================================================================
339
+ /**
340
+ * Try to execute a prefix command. Returns true if a command was handled.
341
+ */
342
+ async tryExecuteCommand(prompt, agentName, channelId, userId,
343
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
344
+ say) {
345
+ if (!this.commandHandler || !this.commandHandler.isCommand(prompt)) {
346
+ return false;
347
+ }
348
+ const sessionManager = this.sessionManagers.get(agentName);
349
+ if (!sessionManager) {
350
+ return false;
351
+ }
352
+ const executed = await this.commandHandler.executeCommand(prompt, {
353
+ agentName,
354
+ channelId,
355
+ userId,
356
+ reply: async (content) => {
357
+ await say({ text: content });
358
+ },
359
+ sessionManager,
360
+ connectorState: this.getState(),
361
+ });
362
+ if (executed) {
363
+ const commandName = prompt.trim().slice(1).split(/\s+/)[0];
364
+ this.logger.info("Command executed", {
365
+ command: commandName,
366
+ agentName,
367
+ channelId,
368
+ });
369
+ this.emit("commandExecuted", {
370
+ agentName,
371
+ commandName,
372
+ userId,
373
+ channelId,
374
+ });
375
+ }
376
+ return executed;
377
+ }
378
+ // ===========================================================================
379
+ // Message Building
380
+ // ===========================================================================
381
+ buildMessageEvent(agentName, prompt, channelId, messageTs, userId, wasMentioned,
382
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
383
+ say) {
384
+ const reply = async (content) => {
385
+ await say({
386
+ text: markdownToMrkdwn(content),
387
+ });
388
+ this.messagesSent++;
389
+ };
390
+ const startProcessingIndicator = () => {
391
+ // Add hourglass reaction while processing
392
+ if (this.app?.client) {
393
+ this.app.client.reactions
394
+ .add({
395
+ channel: channelId,
396
+ name: "hourglass_flowing_sand",
397
+ timestamp: messageTs,
398
+ })
399
+ .catch(() => {
400
+ // Ignore reaction errors — not critical
401
+ });
402
+ }
403
+ return () => {
404
+ // Remove hourglass reaction when done
405
+ if (this.app?.client) {
406
+ this.app.client.reactions
407
+ .remove({
408
+ channel: channelId,
409
+ name: "hourglass_flowing_sand",
410
+ timestamp: messageTs,
411
+ })
412
+ .catch(() => {
413
+ // Ignore reaction errors — not critical
414
+ });
415
+ }
416
+ };
417
+ };
418
+ return {
419
+ agentName,
420
+ prompt,
421
+ metadata: {
422
+ channelId,
423
+ messageTs,
424
+ userId,
425
+ wasMentioned,
426
+ },
427
+ reply,
428
+ startProcessingIndicator,
429
+ };
430
+ }
431
+ // ===========================================================================
432
+ // Type-Safe Event Emitter Overrides
433
+ // ===========================================================================
434
+ emit(event, payload) {
435
+ return super.emit(event, payload);
436
+ }
437
+ on(event, listener) {
438
+ return super.on(event, listener);
439
+ }
440
+ once(event, listener) {
441
+ return super.once(event, listener);
442
+ }
443
+ off(event, listener) {
444
+ return super.off(event, listener);
445
+ }
446
+ }
447
+ //# sourceMappingURL=slack-connector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack-connector.js","sourceRoot":"","sources":["../src/slack-connector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Type definitions for the Slack connector
3
+ *
4
+ * Provides interfaces for connector configuration, state tracking,
5
+ * and event definitions.
6
+ */
7
+ import type { EventEmitter } from "node:events";
8
+ /**
9
+ * Slack connector connection status
10
+ */
11
+ export type SlackConnectionStatus = "disconnected" | "connecting" | "connected" | "reconnecting" | "disconnecting" | "error";
12
+ /**
13
+ * Current state of the Slack connector
14
+ */
15
+ export interface SlackConnectorState {
16
+ /** Current connection status */
17
+ status: SlackConnectionStatus;
18
+ /** ISO timestamp when the connector connected */
19
+ connectedAt: string | null;
20
+ /** ISO timestamp when the connector disconnected */
21
+ disconnectedAt: string | null;
22
+ /** Number of reconnect attempts */
23
+ reconnectAttempts: number;
24
+ /** Last error message */
25
+ lastError: string | null;
26
+ /** Bot user info (only present when connected) */
27
+ botUser: {
28
+ id: string;
29
+ username: string;
30
+ } | null;
31
+ /** Message statistics */
32
+ messageStats: {
33
+ received: number;
34
+ sent: number;
35
+ ignored: number;
36
+ };
37
+ }
38
+ /**
39
+ * Options for creating a SlackConnector
40
+ */
41
+ /**
42
+ * Per-channel configuration
43
+ */
44
+ export interface SlackChannelConfig {
45
+ /** Channel message mode: "mention" = only @mentions, "auto" = all messages */
46
+ mode: "mention" | "auto";
47
+ /** Number of context messages (future use) */
48
+ contextMessages: number;
49
+ }
50
+ /**
51
+ * Options for creating a SlackConnector
52
+ */
53
+ export interface SlackConnectorOptions {
54
+ /** Slack Bot Token (xoxb-...) */
55
+ botToken: string;
56
+ /** Slack App Token for Socket Mode (xapp-...) */
57
+ appToken: string;
58
+ /** Map of channel ID to agent name for routing */
59
+ channelAgentMap: Map<string, string>;
60
+ /** Per-channel configuration (keyed by channel ID) */
61
+ channelConfigs?: Map<string, SlackChannelConfig>;
62
+ /** Session managers keyed by agent name */
63
+ sessionManagers: Map<string, ISlackSessionManager>;
64
+ /** Logger for connector operations */
65
+ logger?: SlackConnectorLogger;
66
+ /** State directory for persistence */
67
+ stateDir?: string;
68
+ }
69
+ /**
70
+ * Logger interface for Slack connector operations
71
+ */
72
+ export interface SlackConnectorLogger {
73
+ debug(message: string, data?: Record<string, unknown>): void;
74
+ info(message: string, data?: Record<string, unknown>): void;
75
+ warn(message: string, data?: Record<string, unknown>): void;
76
+ error(message: string, data?: Record<string, unknown>): void;
77
+ }
78
+ /**
79
+ * Message event payload from SlackConnector
80
+ */
81
+ export interface SlackMessageEvent {
82
+ /** Name of the agent handling this message */
83
+ agentName: string;
84
+ /** The processed prompt text */
85
+ prompt: string;
86
+ /** Slack-specific metadata */
87
+ metadata: {
88
+ /** Channel ID where the message was sent */
89
+ channelId: string;
90
+ /** Message timestamp */
91
+ messageTs: string;
92
+ /** User ID who sent the message */
93
+ userId: string;
94
+ /** Whether this was triggered by a mention */
95
+ wasMentioned: boolean;
96
+ };
97
+ /** Function to send a reply in the same thread */
98
+ reply: (content: string) => Promise<void>;
99
+ /** Add hourglass reaction while processing, returns remove function */
100
+ startProcessingIndicator: () => () => void;
101
+ }
102
+ /**
103
+ * Error event payload from SlackConnector
104
+ */
105
+ export interface SlackErrorEvent {
106
+ agentName: string;
107
+ error: Error;
108
+ }
109
+ /**
110
+ * Interface for the Slack connector
111
+ */
112
+ /**
113
+ * Parameters for uploading a file to Slack
114
+ */
115
+ export interface SlackFileUploadParams {
116
+ /** Channel ID to upload to */
117
+ channelId: string;
118
+ /** File contents */
119
+ fileBuffer: Buffer;
120
+ /** Filename for the upload */
121
+ filename: string;
122
+ /** Optional message to accompany the file */
123
+ message?: string;
124
+ }
125
+ export interface ISlackConnector extends EventEmitter {
126
+ /** Connect to Slack via Socket Mode */
127
+ connect(): Promise<void>;
128
+ /** Disconnect from Slack */
129
+ disconnect(): Promise<void>;
130
+ /** Check if connected */
131
+ isConnected(): boolean;
132
+ /** Get current state */
133
+ getState(): SlackConnectorState;
134
+ /** Upload a file to a Slack channel/thread */
135
+ uploadFile(params: SlackFileUploadParams): Promise<{
136
+ fileId: string;
137
+ }>;
138
+ /** Type-safe event subscription */
139
+ on<K extends SlackConnectorEventName>(event: K, listener: (payload: SlackConnectorEventMap[K]) => void): this;
140
+ once<K extends SlackConnectorEventName>(event: K, listener: (payload: SlackConnectorEventMap[K]) => void): this;
141
+ off<K extends SlackConnectorEventName>(event: K, listener: (payload: SlackConnectorEventMap[K]) => void): this;
142
+ }
143
+ /**
144
+ * Session manager interface for Slack
145
+ *
146
+ * Keyed by channelId (matching Discord's approach).
147
+ */
148
+ export interface ISlackSessionManager {
149
+ readonly agentName: string;
150
+ getOrCreateSession(channelId: string): Promise<{
151
+ sessionId: string;
152
+ isNew: boolean;
153
+ }>;
154
+ getSession(channelId: string): Promise<{
155
+ sessionId: string;
156
+ lastMessageAt: string;
157
+ } | null>;
158
+ setSession(channelId: string, sessionId: string): Promise<void>;
159
+ touchSession(channelId: string): Promise<void>;
160
+ clearSession(channelId: string): Promise<boolean>;
161
+ cleanupExpiredSessions(): Promise<number>;
162
+ getActiveSessionCount(): Promise<number>;
163
+ }
164
+ /**
165
+ * Strongly-typed event map for SlackConnector
166
+ *
167
+ * Uses object syntax matching Discord's DiscordConnectorEventMap pattern.
168
+ */
169
+ export interface SlackConnectorEventMap {
170
+ /** Emitted when connection is established and ready */
171
+ ready: {
172
+ botUser: {
173
+ id: string;
174
+ username: string;
175
+ };
176
+ };
177
+ /** Emitted when connection is lost */
178
+ disconnect: {
179
+ reason: string;
180
+ };
181
+ /** Emitted on connection error */
182
+ error: {
183
+ error: Error;
184
+ };
185
+ /** Emitted when a processable message is received */
186
+ message: SlackMessageEvent;
187
+ /** Emitted when a message is ignored */
188
+ messageIgnored: {
189
+ agentName: string;
190
+ reason: "not_configured" | "bot_message" | "no_agent_resolved" | "empty_prompt";
191
+ channelId: string;
192
+ messageTs: string;
193
+ };
194
+ /** Emitted when a prefix command is executed */
195
+ commandExecuted: {
196
+ agentName: string;
197
+ commandName: string;
198
+ userId: string;
199
+ channelId: string;
200
+ };
201
+ /** Emitted when a session is created, resumed, expired, or cleared */
202
+ sessionLifecycle: {
203
+ agentName: string;
204
+ event: "created" | "resumed" | "expired" | "cleared";
205
+ channelId: string;
206
+ sessionId: string;
207
+ };
208
+ }
209
+ export type SlackConnectorEventName = keyof SlackConnectorEventMap;
210
+ export type SlackConnectorEventPayload<E extends SlackConnectorEventName> = SlackConnectorEventMap[E];
211
+ //# sourceMappingURL=types.d.ts.map