@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,214 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
2
+ import { mkdtemp, rm, readFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { tmpdir } from "node:os";
5
+ import { SessionManager } from "../session-manager/session-manager.js";
6
+ import { createInitialSessionState, createChannelSession, } from "../session-manager/types.js";
7
+ import { SessionManagerError, SessionStateReadError, SessionStateWriteError, SessionDirectoryCreateError, SessionErrorCode, } from "../session-manager/errors.js";
8
+ const createMockLogger = () => ({
9
+ debug: vi.fn(),
10
+ info: vi.fn(),
11
+ warn: vi.fn(),
12
+ error: vi.fn(),
13
+ });
14
+ describe("SessionManager", () => {
15
+ let tempDir;
16
+ beforeEach(async () => {
17
+ tempDir = await mkdtemp(join(tmpdir(), "slack-session-test-"));
18
+ });
19
+ afterEach(async () => {
20
+ await rm(tempDir, { recursive: true, force: true });
21
+ });
22
+ const createManager = (agentName = "test-agent", expiryHours = 24) => {
23
+ return new SessionManager({
24
+ agentName,
25
+ stateDir: tempDir,
26
+ sessionExpiryHours: expiryHours,
27
+ logger: createMockLogger(),
28
+ });
29
+ };
30
+ describe("getOrCreateSession", () => {
31
+ it("creates a new session for unknown channel", async () => {
32
+ const manager = createManager();
33
+ const result = await manager.getOrCreateSession("C0123456789");
34
+ expect(result.isNew).toBe(true);
35
+ expect(result.sessionId).toMatch(/^slack-test-agent-/);
36
+ });
37
+ it("returns existing session for known channel", async () => {
38
+ const manager = createManager();
39
+ const first = await manager.getOrCreateSession("C0123456789");
40
+ const second = await manager.getOrCreateSession("C0123456789");
41
+ expect(second.isNew).toBe(false);
42
+ expect(second.sessionId).toBe(first.sessionId);
43
+ });
44
+ it("creates different sessions for different channels", async () => {
45
+ const manager = createManager();
46
+ const first = await manager.getOrCreateSession("C0123456789");
47
+ const second = await manager.getOrCreateSession("C9876543210");
48
+ expect(first.sessionId).not.toBe(second.sessionId);
49
+ });
50
+ });
51
+ describe("getSession", () => {
52
+ it("returns null for unknown channel", async () => {
53
+ const manager = createManager();
54
+ const session = await manager.getSession("C_UNKNOWN");
55
+ expect(session).toBeNull();
56
+ });
57
+ it("returns session for known channel", async () => {
58
+ const manager = createManager();
59
+ await manager.getOrCreateSession("C0123456789");
60
+ const session = await manager.getSession("C0123456789");
61
+ expect(session).not.toBeNull();
62
+ expect(session.sessionId).toMatch(/^slack-test-agent-/);
63
+ });
64
+ it("returns null for expired sessions", async () => {
65
+ // 0 hours expiry = immediately expired
66
+ const manager = createManager("test-agent", 0);
67
+ await manager.getOrCreateSession("C0123456789");
68
+ // Wait a tick so the session is expired
69
+ await new Promise((resolve) => setTimeout(resolve, 10));
70
+ const session = await manager.getSession("C0123456789");
71
+ expect(session).toBeNull();
72
+ });
73
+ });
74
+ describe("touchSession", () => {
75
+ it("updates last message timestamp", async () => {
76
+ const manager = createManager();
77
+ await manager.getOrCreateSession("C0123456789");
78
+ const before = await manager.getSession("C0123456789");
79
+ const beforeTime = new Date(before.lastMessageAt).getTime();
80
+ // Wait enough for a distinct timestamp
81
+ await new Promise((resolve) => setTimeout(resolve, 50));
82
+ await manager.touchSession("C0123456789");
83
+ const after = await manager.getSession("C0123456789");
84
+ const afterTime = new Date(after.lastMessageAt).getTime();
85
+ expect(afterTime).toBeGreaterThanOrEqual(beforeTime);
86
+ });
87
+ it("does not throw for unknown channel", async () => {
88
+ const manager = createManager();
89
+ await expect(manager.touchSession("C_UNKNOWN")).resolves.toBeUndefined();
90
+ });
91
+ });
92
+ describe("setSession", () => {
93
+ it("creates or updates a session", async () => {
94
+ const manager = createManager();
95
+ await manager.setSession("C0123456789", "custom-session-id");
96
+ const session = await manager.getSession("C0123456789");
97
+ expect(session).not.toBeNull();
98
+ expect(session.sessionId).toBe("custom-session-id");
99
+ });
100
+ it("overwrites existing session", async () => {
101
+ const manager = createManager();
102
+ await manager.getOrCreateSession("C0123456789");
103
+ await manager.setSession("C0123456789", "new-session-id");
104
+ const session = await manager.getSession("C0123456789");
105
+ expect(session.sessionId).toBe("new-session-id");
106
+ });
107
+ });
108
+ describe("clearSession", () => {
109
+ it("removes a session and returns true", async () => {
110
+ const manager = createManager();
111
+ await manager.getOrCreateSession("C0123456789");
112
+ const result = await manager.clearSession("C0123456789");
113
+ expect(result).toBe(true);
114
+ const session = await manager.getSession("C0123456789");
115
+ expect(session).toBeNull();
116
+ });
117
+ it("returns false for unknown channel", async () => {
118
+ const manager = createManager();
119
+ const result = await manager.clearSession("C_UNKNOWN");
120
+ expect(result).toBe(false);
121
+ });
122
+ });
123
+ describe("cleanupExpiredSessions", () => {
124
+ it("removes expired sessions", async () => {
125
+ const manager = createManager("test-agent", 0);
126
+ await manager.getOrCreateSession("C001");
127
+ await manager.getOrCreateSession("C002");
128
+ await new Promise((resolve) => setTimeout(resolve, 10));
129
+ const count = await manager.cleanupExpiredSessions();
130
+ expect(count).toBe(2);
131
+ });
132
+ it("keeps active sessions", async () => {
133
+ const manager = createManager("test-agent", 24);
134
+ await manager.getOrCreateSession("C001");
135
+ const count = await manager.cleanupExpiredSessions();
136
+ expect(count).toBe(0);
137
+ });
138
+ });
139
+ describe("getActiveSessionCount", () => {
140
+ it("returns 0 when no sessions", async () => {
141
+ const manager = createManager();
142
+ expect(await manager.getActiveSessionCount()).toBe(0);
143
+ });
144
+ it("counts active sessions", async () => {
145
+ const manager = createManager();
146
+ await manager.getOrCreateSession("C001");
147
+ await manager.getOrCreateSession("C002");
148
+ expect(await manager.getActiveSessionCount()).toBe(2);
149
+ });
150
+ });
151
+ describe("persistence", () => {
152
+ it("persists state to YAML file", async () => {
153
+ const manager = createManager();
154
+ await manager.getOrCreateSession("C0123456789");
155
+ const filePath = join(tempDir, "slack-sessions", "test-agent.yaml");
156
+ const content = await readFile(filePath, "utf-8");
157
+ expect(content).toContain("version: 2");
158
+ expect(content).toContain("agentName: test-agent");
159
+ expect(content).toContain("C0123456789");
160
+ });
161
+ it("survives recreation with same state dir", async () => {
162
+ const manager1 = createManager();
163
+ const result1 = await manager1.getOrCreateSession("C0123456789");
164
+ // Create new manager pointing to same dir
165
+ const manager2 = createManager();
166
+ const result2 = await manager2.getOrCreateSession("C0123456789");
167
+ expect(result2.isNew).toBe(false);
168
+ expect(result2.sessionId).toBe(result1.sessionId);
169
+ });
170
+ });
171
+ });
172
+ describe("Session manager types", () => {
173
+ describe("createInitialSessionState", () => {
174
+ it("creates state with empty channels", () => {
175
+ const state = createInitialSessionState("my-agent");
176
+ expect(state.version).toBe(2);
177
+ expect(state.agentName).toBe("my-agent");
178
+ expect(state.channels).toEqual({});
179
+ });
180
+ });
181
+ describe("createChannelSession", () => {
182
+ it("creates channel session", () => {
183
+ const session = createChannelSession("session-123");
184
+ expect(session.sessionId).toBe("session-123");
185
+ expect(session.lastMessageAt).toBeDefined();
186
+ });
187
+ });
188
+ });
189
+ describe("Session manager errors", () => {
190
+ it("SessionManagerError has correct properties", () => {
191
+ const error = new SessionManagerError("test error", SessionErrorCode.STATE_READ_FAILED, "test-agent");
192
+ expect(error.message).toBe("test error");
193
+ expect(error.code).toBe(SessionErrorCode.STATE_READ_FAILED);
194
+ expect(error.agentName).toBe("test-agent");
195
+ expect(error.name).toBe("SessionManagerError");
196
+ });
197
+ it("SessionStateReadError has formatted message", () => {
198
+ const error = new SessionStateReadError("test-agent", "/path/to/state");
199
+ expect(error.message).toContain("test-agent");
200
+ expect(error.message).toContain("/path/to/state");
201
+ expect(error.code).toBe(SessionErrorCode.STATE_READ_FAILED);
202
+ });
203
+ it("SessionStateWriteError has formatted message", () => {
204
+ const error = new SessionStateWriteError("test-agent", "/path/to/state");
205
+ expect(error.message).toContain("test-agent");
206
+ expect(error.code).toBe(SessionErrorCode.STATE_WRITE_FAILED);
207
+ });
208
+ it("SessionDirectoryCreateError has formatted message", () => {
209
+ const error = new SessionDirectoryCreateError("test-agent", "/path/to/dir");
210
+ expect(error.message).toContain("test-agent");
211
+ expect(error.code).toBe(SessionErrorCode.DIRECTORY_CREATE_FAILED);
212
+ });
213
+ });
214
+ //# sourceMappingURL=session-manager.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-manager.test.js","sourceRoot":"","sources":["../../src/__tests__/session-manager.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=slack-connector.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack-connector.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/slack-connector.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,376 @@
1
+ import { describe, it, expect, vi } from "vitest";
2
+ import { SlackConnector } from "../slack-connector.js";
3
+ const BOT_USER_ID = "U0123456789";
4
+ const CHANNEL_ID = "C_GENERAL";
5
+ const AGENT_NAME = "test-agent";
6
+ const createMockLogger = () => ({
7
+ debug: vi.fn(),
8
+ info: vi.fn(),
9
+ warn: vi.fn(),
10
+ error: vi.fn(),
11
+ });
12
+ const createMockSessionManager = (overrides = {}) => ({
13
+ agentName: AGENT_NAME,
14
+ getOrCreateSession: vi.fn().mockResolvedValue({ sessionId: "s1", isNew: true }),
15
+ getSession: vi.fn().mockResolvedValue(null),
16
+ setSession: vi.fn().mockResolvedValue(undefined),
17
+ touchSession: vi.fn().mockResolvedValue(undefined),
18
+ clearSession: vi.fn().mockResolvedValue(true),
19
+ cleanupExpiredSessions: vi.fn().mockResolvedValue(0),
20
+ getActiveSessionCount: vi.fn().mockResolvedValue(0),
21
+ ...overrides,
22
+ });
23
+ /**
24
+ * Helper to create a connector with a fake Bolt app and trigger handlers.
25
+ *
26
+ * We bypass connect() (which imports @slack/bolt) and instead inject a mock
27
+ * app object, then call registerEventHandlers() via reflection.
28
+ */
29
+ function createTestConnector(options) {
30
+ const channelAgentMap = options?.channelAgentMap ?? new Map([[CHANNEL_ID, AGENT_NAME]]);
31
+ const channelConfigs = options?.channelConfigs;
32
+ const sessionManagers = options?.sessionManagers ??
33
+ new Map([[AGENT_NAME, createMockSessionManager()]]);
34
+ const connector = new SlackConnector({
35
+ botToken: "xoxb-fake",
36
+ appToken: "xapp-fake",
37
+ channelAgentMap,
38
+ channelConfigs,
39
+ sessionManagers,
40
+ logger: createMockLogger(),
41
+ });
42
+ // Collect registered handlers
43
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
+ const handlers = {};
45
+ // Mock Bolt app
46
+ const mockApp = {
47
+ event: vi.fn((eventName, handler) => {
48
+ handlers[`event:${eventName}`] = handler;
49
+ }),
50
+ message: vi.fn((handler) => {
51
+ handlers["message"] = handler;
52
+ }),
53
+ client: {
54
+ reactions: {
55
+ add: vi.fn().mockResolvedValue({}),
56
+ remove: vi.fn().mockResolvedValue({}),
57
+ },
58
+ },
59
+ };
60
+ // Inject mock app and botUserId via private field access
61
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
62
+ connector.app = mockApp;
63
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
64
+ connector.botUserId = BOT_USER_ID;
65
+ // Trigger registerEventHandlers
66
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
67
+ connector.registerEventHandlers();
68
+ const say = vi.fn().mockResolvedValue(undefined);
69
+ return { connector, handlers, say, mockApp, channelAgentMap, sessionManagers };
70
+ }
71
+ // Helper to capture emitted message events
72
+ function captureMessages(connector) {
73
+ const messages = [];
74
+ connector.on("message", (msg) => messages.push(msg));
75
+ return messages;
76
+ }
77
+ describe("SlackConnector registerEventHandlers", () => {
78
+ describe("app_mention handler", () => {
79
+ it("emits message event for @mention in configured channel", async () => {
80
+ const { connector, handlers, say } = createTestConnector();
81
+ const messages = captureMessages(connector);
82
+ await handlers["event:app_mention"]({
83
+ event: {
84
+ type: "app_mention",
85
+ user: "UUSER1",
86
+ text: `<@${BOT_USER_ID}> help me`,
87
+ ts: "1707930001.000001",
88
+ channel: CHANNEL_ID,
89
+ },
90
+ say,
91
+ });
92
+ expect(messages).toHaveLength(1);
93
+ expect(messages[0].agentName).toBe(AGENT_NAME);
94
+ expect(messages[0].prompt).toBe("help me");
95
+ expect(messages[0].metadata.wasMentioned).toBe(true);
96
+ expect(messages[0].metadata.channelId).toBe(CHANNEL_ID);
97
+ });
98
+ it("ignores @mention in unconfigured channel", async () => {
99
+ const { connector, handlers, say } = createTestConnector();
100
+ const messages = captureMessages(connector);
101
+ await handlers["event:app_mention"]({
102
+ event: {
103
+ type: "app_mention",
104
+ user: "UUSER1",
105
+ text: `<@${BOT_USER_ID}> help`,
106
+ ts: "1707930001.000001",
107
+ channel: "C_UNKNOWN",
108
+ },
109
+ say,
110
+ });
111
+ expect(messages).toHaveLength(0);
112
+ });
113
+ });
114
+ describe("message handler — channel routing", () => {
115
+ it("routes message in configured channel to agent", async () => {
116
+ const { connector, handlers, say } = createTestConnector({
117
+ channelConfigs: new Map([[CHANNEL_ID, { mode: "auto", contextMessages: 10 }]]),
118
+ });
119
+ const messages = captureMessages(connector);
120
+ await handlers["event:message"]({
121
+ event: {
122
+ type: "message",
123
+ user: "UUSER1",
124
+ text: "hello bot",
125
+ ts: "1707930001.000001",
126
+ channel: CHANNEL_ID,
127
+ },
128
+ say,
129
+ });
130
+ expect(messages).toHaveLength(1);
131
+ expect(messages[0].agentName).toBe(AGENT_NAME);
132
+ expect(messages[0].prompt).toBe("hello bot");
133
+ expect(messages[0].metadata.wasMentioned).toBe(false);
134
+ expect(messages[0].metadata.channelId).toBe(CHANNEL_ID);
135
+ });
136
+ it("routes thread reply in configured channel to agent", async () => {
137
+ const { connector, handlers, say } = createTestConnector({
138
+ channelConfigs: new Map([[CHANNEL_ID, { mode: "auto", contextMessages: 10 }]]),
139
+ });
140
+ const messages = captureMessages(connector);
141
+ // Thread reply — should still route via channel
142
+ await handlers["event:message"]({
143
+ event: {
144
+ type: "message",
145
+ user: "UUSER1",
146
+ text: "follow up in thread",
147
+ ts: "1707930002.000001",
148
+ channel: CHANNEL_ID,
149
+ thread_ts: "1707930001.000001",
150
+ },
151
+ say,
152
+ });
153
+ expect(messages).toHaveLength(1);
154
+ expect(messages[0].agentName).toBe(AGENT_NAME);
155
+ expect(messages[0].prompt).toBe("follow up in thread");
156
+ });
157
+ it("ignores top-level message in mention-mode channel (default)", async () => {
158
+ const { connector, handlers, say } = createTestConnector();
159
+ const messages = captureMessages(connector);
160
+ await handlers["event:message"]({
161
+ event: {
162
+ type: "message",
163
+ user: "UUSER1",
164
+ text: "hello bot",
165
+ ts: "1707930001.000001",
166
+ channel: CHANNEL_ID,
167
+ },
168
+ say,
169
+ });
170
+ expect(messages).toHaveLength(0);
171
+ });
172
+ it("ignores message in unconfigured channel", async () => {
173
+ const { connector, handlers, say } = createTestConnector();
174
+ const messages = captureMessages(connector);
175
+ await handlers["event:message"]({
176
+ event: {
177
+ type: "message",
178
+ user: "UUSER1",
179
+ text: "hello",
180
+ ts: "1707930001.000001",
181
+ channel: "C_UNKNOWN",
182
+ },
183
+ say,
184
+ });
185
+ expect(messages).toHaveLength(0);
186
+ });
187
+ });
188
+ describe("@mention dedup", () => {
189
+ it("message handler skips messages containing @mention (handled by app_mention)", async () => {
190
+ const { connector, handlers, say } = createTestConnector();
191
+ const messages = captureMessages(connector);
192
+ await handlers["event:message"]({
193
+ event: {
194
+ type: "message",
195
+ user: "UUSER1",
196
+ text: `<@${BOT_USER_ID}> do something`,
197
+ ts: "1707930001.000001",
198
+ channel: CHANNEL_ID,
199
+ },
200
+ say,
201
+ });
202
+ // Should be skipped — app_mention handler processes these
203
+ expect(messages).toHaveLength(0);
204
+ });
205
+ it("app_mention and message for same @mention produce exactly one event", async () => {
206
+ const { connector, handlers, say } = createTestConnector();
207
+ const messages = captureMessages(connector);
208
+ // Slack sends both events for an @mention
209
+ await handlers["event:app_mention"]({
210
+ event: {
211
+ type: "app_mention",
212
+ user: "UUSER1",
213
+ text: `<@${BOT_USER_ID}> help`,
214
+ ts: "1707930001.000001",
215
+ channel: CHANNEL_ID,
216
+ },
217
+ say,
218
+ });
219
+ await handlers["event:message"]({
220
+ event: {
221
+ type: "message",
222
+ user: "UUSER1",
223
+ text: `<@${BOT_USER_ID}> help`,
224
+ ts: "1707930001.000001",
225
+ channel: CHANNEL_ID,
226
+ },
227
+ say,
228
+ });
229
+ // Only one message event should be emitted (from app_mention)
230
+ expect(messages).toHaveLength(1);
231
+ expect(messages[0].metadata.wasMentioned).toBe(true);
232
+ });
233
+ });
234
+ describe("bot message filtering", () => {
235
+ it("ignores messages from bots", async () => {
236
+ const { connector, handlers, say } = createTestConnector();
237
+ const messages = captureMessages(connector);
238
+ await handlers["event:message"]({
239
+ event: {
240
+ type: "message",
241
+ bot_id: "BBOT123",
242
+ text: "I am a bot",
243
+ ts: "1707930001.000001",
244
+ channel: CHANNEL_ID,
245
+ },
246
+ say,
247
+ });
248
+ expect(messages).toHaveLength(0);
249
+ });
250
+ it("ignores messages with bot_message subtype", async () => {
251
+ const { connector, handlers, say } = createTestConnector();
252
+ const messages = captureMessages(connector);
253
+ await handlers["event:message"]({
254
+ event: {
255
+ type: "message",
256
+ subtype: "bot_message",
257
+ user: "UUSER1",
258
+ text: "bot subtype message",
259
+ ts: "1707930001.000001",
260
+ channel: CHANNEL_ID,
261
+ },
262
+ say,
263
+ });
264
+ expect(messages).toHaveLength(0);
265
+ });
266
+ it("ignores messages from the bot itself", async () => {
267
+ const { connector, handlers, say } = createTestConnector();
268
+ const messages = captureMessages(connector);
269
+ await handlers["event:message"]({
270
+ event: {
271
+ type: "message",
272
+ user: BOT_USER_ID,
273
+ text: "my own message",
274
+ ts: "1707930001.000001",
275
+ channel: CHANNEL_ID,
276
+ },
277
+ say,
278
+ });
279
+ expect(messages).toHaveLength(0);
280
+ });
281
+ });
282
+ describe("message stats", () => {
283
+ it("increments received and ignored counts correctly", async () => {
284
+ const { connector, handlers, say } = createTestConnector();
285
+ // Bot message -> received + ignored
286
+ await handlers["event:message"]({
287
+ event: {
288
+ type: "message",
289
+ bot_id: "BBOT123",
290
+ text: "bot msg",
291
+ ts: "1707930001.000001",
292
+ channel: CHANNEL_ID,
293
+ },
294
+ say,
295
+ });
296
+ // Unknown channel -> received + ignored
297
+ await handlers["event:message"]({
298
+ event: {
299
+ type: "message",
300
+ user: "UUSER1",
301
+ text: "hello",
302
+ ts: "1707930002.000001",
303
+ channel: "C_UNKNOWN",
304
+ },
305
+ say,
306
+ });
307
+ // Top-level in configured channel with default mention mode -> also ignored
308
+ await handlers["event:message"]({
309
+ event: {
310
+ type: "message",
311
+ user: "UUSER1",
312
+ text: "hello bot",
313
+ ts: "1707930003.000001",
314
+ channel: CHANNEL_ID,
315
+ },
316
+ say,
317
+ });
318
+ const state = connector.getState();
319
+ expect(state.messageStats.received).toBe(3);
320
+ expect(state.messageStats.ignored).toBe(3);
321
+ });
322
+ });
323
+ describe("reply function", () => {
324
+ it("sends reply in the channel (no thread_ts)", async () => {
325
+ const { connector, handlers, say } = createTestConnector({
326
+ channelConfigs: new Map([[CHANNEL_ID, { mode: "auto", contextMessages: 10 }]]),
327
+ });
328
+ const messages = captureMessages(connector);
329
+ await handlers["event:message"]({
330
+ event: {
331
+ type: "message",
332
+ user: "UUSER1",
333
+ text: "hello",
334
+ ts: "1707930001.000001",
335
+ channel: CHANNEL_ID,
336
+ },
337
+ say,
338
+ });
339
+ expect(messages).toHaveLength(1);
340
+ await messages[0].reply("hi back!");
341
+ expect(say).toHaveBeenCalledWith({
342
+ text: "hi back!",
343
+ });
344
+ });
345
+ it("converts markdown to mrkdwn in replies", async () => {
346
+ const { connector, handlers, say } = createTestConnector({
347
+ channelConfigs: new Map([[CHANNEL_ID, { mode: "auto", contextMessages: 10 }]]),
348
+ });
349
+ const messages = captureMessages(connector);
350
+ await handlers["event:message"]({
351
+ event: {
352
+ type: "message",
353
+ user: "UUSER1",
354
+ text: "hello",
355
+ ts: "1707930002.000001",
356
+ channel: CHANNEL_ID,
357
+ },
358
+ say,
359
+ });
360
+ await messages[0].reply("**bold** and [link](https://example.com)");
361
+ const sentText = say.mock.calls[say.mock.calls.length - 1][0].text;
362
+ expect(sentText).toContain("*bold*");
363
+ expect(sentText).not.toContain("**bold**");
364
+ expect(sentText).toContain("<https://example.com|link>");
365
+ });
366
+ });
367
+ describe("event handler registration", () => {
368
+ it("registers both app_mention and message via app.event()", () => {
369
+ const { mockApp } = createTestConnector();
370
+ expect(mockApp.event).toHaveBeenCalledTimes(2);
371
+ expect(mockApp.event).toHaveBeenCalledWith("app_mention", expect.any(Function));
372
+ expect(mockApp.event).toHaveBeenCalledWith("message", expect.any(Function));
373
+ });
374
+ });
375
+ });
376
+ //# sourceMappingURL=slack-connector.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack-connector.test.js","sourceRoot":"","sources":["../../src/__tests__/slack-connector.test.ts"],"names":[],"mappings":"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"}