agent-messenger 2.2.0 → 2.4.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 (229) hide show
  1. package/.claude-plugin/README.md +16 -16
  2. package/.claude-plugin/marketplace.json +29 -29
  3. package/.claude-plugin/plugin.json +5 -5
  4. package/CONTRIBUTING.md +1 -1
  5. package/README.md +9 -6
  6. package/bun.lock +89 -105
  7. package/bunfig.toml +3 -0
  8. package/dist/package.json +13 -3
  9. package/dist/src/platforms/discordbot/client.js +2 -2
  10. package/dist/src/platforms/discordbot/client.js.map +1 -1
  11. package/dist/src/platforms/kakaotalk/cli.d.ts.map +1 -1
  12. package/dist/src/platforms/kakaotalk/cli.js +2 -1
  13. package/dist/src/platforms/kakaotalk/cli.js.map +1 -1
  14. package/dist/src/platforms/kakaotalk/client.d.ts +2 -1
  15. package/dist/src/platforms/kakaotalk/client.d.ts.map +1 -1
  16. package/dist/src/platforms/kakaotalk/client.js +52 -2
  17. package/dist/src/platforms/kakaotalk/client.js.map +1 -1
  18. package/dist/src/platforms/kakaotalk/commands/index.d.ts +1 -0
  19. package/dist/src/platforms/kakaotalk/commands/index.d.ts.map +1 -1
  20. package/dist/src/platforms/kakaotalk/commands/index.js +1 -0
  21. package/dist/src/platforms/kakaotalk/commands/index.js.map +1 -1
  22. package/dist/src/platforms/kakaotalk/commands/profile.d.ts +3 -0
  23. package/dist/src/platforms/kakaotalk/commands/profile.d.ts.map +1 -0
  24. package/dist/src/platforms/kakaotalk/commands/profile.js +19 -0
  25. package/dist/src/platforms/kakaotalk/commands/profile.js.map +1 -0
  26. package/dist/src/platforms/kakaotalk/index.d.ts +2 -2
  27. package/dist/src/platforms/kakaotalk/index.d.ts.map +1 -1
  28. package/dist/src/platforms/kakaotalk/index.js +1 -1
  29. package/dist/src/platforms/kakaotalk/index.js.map +1 -1
  30. package/dist/src/platforms/kakaotalk/protocol/session.d.ts.map +1 -1
  31. package/dist/src/platforms/kakaotalk/protocol/session.js +2 -1
  32. package/dist/src/platforms/kakaotalk/protocol/session.js.map +1 -1
  33. package/dist/src/platforms/kakaotalk/types.d.ts +16 -0
  34. package/dist/src/platforms/kakaotalk/types.d.ts.map +1 -1
  35. package/dist/src/platforms/kakaotalk/types.js +8 -0
  36. package/dist/src/platforms/kakaotalk/types.js.map +1 -1
  37. package/dist/src/platforms/line/commands/auth.d.ts.map +1 -1
  38. package/dist/src/platforms/line/commands/auth.js +32 -20
  39. package/dist/src/platforms/line/commands/auth.js.map +1 -1
  40. package/dist/src/platforms/teams/commands/reaction.d.ts.map +1 -1
  41. package/dist/src/platforms/teams/commands/reaction.js +2 -0
  42. package/dist/src/platforms/teams/commands/reaction.js.map +1 -1
  43. package/dist/src/platforms/webex/client.d.ts +2 -0
  44. package/dist/src/platforms/webex/client.d.ts.map +1 -1
  45. package/dist/src/platforms/webex/client.js +66 -23
  46. package/dist/src/platforms/webex/client.js.map +1 -1
  47. package/dist/src/platforms/webex/commands/auth.d.ts.map +1 -1
  48. package/dist/src/platforms/webex/commands/auth.js +4 -0
  49. package/dist/src/platforms/webex/commands/auth.js.map +1 -1
  50. package/dist/src/platforms/webex/encryption.d.ts +10 -0
  51. package/dist/src/platforms/webex/encryption.d.ts.map +1 -0
  52. package/dist/src/platforms/webex/encryption.js +49 -0
  53. package/dist/src/platforms/webex/encryption.js.map +1 -0
  54. package/dist/src/platforms/webex/ensure-auth.d.ts.map +1 -1
  55. package/dist/src/platforms/webex/ensure-auth.js +4 -0
  56. package/dist/src/platforms/webex/ensure-auth.js.map +1 -1
  57. package/dist/src/platforms/webex/token-extractor.d.ts +6 -5
  58. package/dist/src/platforms/webex/token-extractor.d.ts.map +1 -1
  59. package/dist/src/platforms/webex/token-extractor.js +92 -43
  60. package/dist/src/platforms/webex/token-extractor.js.map +1 -1
  61. package/dist/src/platforms/webex/types.d.ts +4 -0
  62. package/dist/src/platforms/webex/types.d.ts.map +1 -1
  63. package/dist/src/platforms/webex/types.js +2 -0
  64. package/dist/src/platforms/webex/types.js.map +1 -1
  65. package/dist/src/platforms/wechatbot/cli.d.ts +5 -0
  66. package/dist/src/platforms/wechatbot/cli.d.ts.map +1 -0
  67. package/dist/src/platforms/wechatbot/cli.js +18 -0
  68. package/dist/src/platforms/wechatbot/cli.js.map +1 -0
  69. package/dist/src/platforms/wechatbot/client.d.ts +36 -0
  70. package/dist/src/platforms/wechatbot/client.d.ts.map +1 -0
  71. package/dist/src/platforms/wechatbot/client.js +208 -0
  72. package/dist/src/platforms/wechatbot/client.js.map +1 -0
  73. package/dist/src/platforms/wechatbot/commands/auth.d.ts +28 -0
  74. package/dist/src/platforms/wechatbot/commands/auth.d.ts.map +1 -0
  75. package/dist/src/platforms/wechatbot/commands/auth.js +164 -0
  76. package/dist/src/platforms/wechatbot/commands/auth.js.map +1 -0
  77. package/dist/src/platforms/wechatbot/commands/index.d.ts +5 -0
  78. package/dist/src/platforms/wechatbot/commands/index.d.ts.map +1 -0
  79. package/dist/src/platforms/wechatbot/commands/index.js +5 -0
  80. package/dist/src/platforms/wechatbot/commands/index.js.map +1 -0
  81. package/dist/src/platforms/wechatbot/commands/message.d.ts +18 -0
  82. package/dist/src/platforms/wechatbot/commands/message.d.ts.map +1 -0
  83. package/dist/src/platforms/wechatbot/commands/message.js +80 -0
  84. package/dist/src/platforms/wechatbot/commands/message.js.map +1 -0
  85. package/dist/src/platforms/wechatbot/commands/shared.d.ts +9 -0
  86. package/dist/src/platforms/wechatbot/commands/shared.d.ts.map +1 -0
  87. package/dist/src/platforms/wechatbot/commands/shared.js +13 -0
  88. package/dist/src/platforms/wechatbot/commands/shared.js.map +1 -0
  89. package/dist/src/platforms/wechatbot/commands/template.d.ts +19 -0
  90. package/dist/src/platforms/wechatbot/commands/template.d.ts.map +1 -0
  91. package/dist/src/platforms/wechatbot/commands/template.js +76 -0
  92. package/dist/src/platforms/wechatbot/commands/template.js.map +1 -0
  93. package/dist/src/platforms/wechatbot/commands/user.d.ts +20 -0
  94. package/dist/src/platforms/wechatbot/commands/user.d.ts.map +1 -0
  95. package/dist/src/platforms/wechatbot/commands/user.js +53 -0
  96. package/dist/src/platforms/wechatbot/commands/user.js.map +1 -0
  97. package/dist/src/platforms/wechatbot/credential-manager.d.ts +17 -0
  98. package/dist/src/platforms/wechatbot/credential-manager.d.ts.map +1 -0
  99. package/dist/src/platforms/wechatbot/credential-manager.js +121 -0
  100. package/dist/src/platforms/wechatbot/credential-manager.js.map +1 -0
  101. package/dist/src/platforms/wechatbot/index.d.ts +5 -0
  102. package/dist/src/platforms/wechatbot/index.d.ts.map +1 -0
  103. package/dist/src/platforms/wechatbot/index.js +4 -0
  104. package/dist/src/platforms/wechatbot/index.js.map +1 -0
  105. package/dist/src/platforms/wechatbot/types.d.ts +94 -0
  106. package/dist/src/platforms/wechatbot/types.d.ts.map +1 -0
  107. package/dist/src/platforms/wechatbot/types.js +54 -0
  108. package/dist/src/platforms/wechatbot/types.js.map +1 -0
  109. package/dist/src/platforms/whatsapp/client.d.ts +1 -0
  110. package/dist/src/platforms/whatsapp/client.d.ts.map +1 -1
  111. package/dist/src/platforms/whatsapp/client.js +27 -13
  112. package/dist/src/platforms/whatsapp/client.js.map +1 -1
  113. package/dist/src/platforms/whatsapp/commands/auth.d.ts.map +1 -1
  114. package/dist/src/platforms/whatsapp/commands/auth.js +21 -18
  115. package/dist/src/platforms/whatsapp/commands/auth.js.map +1 -1
  116. package/dist/src/platforms/whatsapp/credential-manager.d.ts.map +1 -1
  117. package/dist/src/platforms/whatsapp/credential-manager.js +14 -8
  118. package/dist/src/platforms/whatsapp/credential-manager.js.map +1 -1
  119. package/docs/content/docs/agent-skills.mdx +4 -4
  120. package/docs/content/docs/cli/channeltalk.mdx +1 -1
  121. package/docs/content/docs/cli/channeltalkbot.mdx +1 -1
  122. package/docs/content/docs/cli/discord.mdx +1 -1
  123. package/docs/content/docs/cli/discordbot.mdx +1 -1
  124. package/docs/content/docs/cli/instagram.mdx +1 -1
  125. package/docs/content/docs/cli/kakaotalk.mdx +1 -1
  126. package/docs/content/docs/cli/line.mdx +1 -1
  127. package/docs/content/docs/cli/meta.json +1 -0
  128. package/docs/content/docs/cli/slack.mdx +1 -1
  129. package/docs/content/docs/cli/slackbot.mdx +1 -1
  130. package/docs/content/docs/cli/teams.mdx +1 -1
  131. package/docs/content/docs/cli/webex.mdx +5 -3
  132. package/docs/content/docs/cli/wechatbot.mdx +179 -0
  133. package/docs/content/docs/cli/whatsapp.mdx +1 -1
  134. package/docs/content/docs/cli/whatsappbot.mdx +1 -1
  135. package/docs/content/docs/sdk/meta.json +1 -1
  136. package/docs/content/docs/sdk/wechatbot.mdx +282 -0
  137. package/docs/content/docs/tui.mdx +1 -1
  138. package/docs/src/app/page.tsx +5 -5
  139. package/package.json +13 -3
  140. package/skills/agent-channeltalk/SKILL.md +1 -1
  141. package/skills/agent-channeltalkbot/SKILL.md +1 -1
  142. package/skills/agent-discord/SKILL.md +1 -1
  143. package/skills/agent-discordbot/SKILL.md +1 -1
  144. package/skills/agent-instagram/SKILL.md +1 -1
  145. package/skills/agent-kakaotalk/SKILL.md +24 -1
  146. package/skills/agent-line/SKILL.md +7 -11
  147. package/skills/agent-line/references/authentication.md +13 -4
  148. package/skills/agent-slack/SKILL.md +1 -1
  149. package/skills/agent-slackbot/SKILL.md +1 -1
  150. package/skills/agent-teams/SKILL.md +1 -1
  151. package/skills/agent-telegram/SKILL.md +1 -1
  152. package/skills/agent-webex/SKILL.md +1 -1
  153. package/skills/agent-webex/references/authentication.md +4 -3
  154. package/skills/agent-webex/references/common-patterns.md +1 -1
  155. package/skills/agent-wechatbot/SKILL.md +385 -0
  156. package/skills/agent-whatsapp/SKILL.md +12 -1
  157. package/skills/agent-whatsappbot/SKILL.md +1 -1
  158. package/src/platforms/discord/credential-manager.test.ts +18 -1
  159. package/src/platforms/discordbot/client.ts +2 -2
  160. package/src/platforms/instagram/commands/auth.test.ts +216 -0
  161. package/src/platforms/instagram/commands/chat.test.ts +127 -0
  162. package/src/platforms/instagram/commands/message.test.ts +178 -0
  163. package/src/platforms/kakaotalk/cli.ts +2 -1
  164. package/src/platforms/kakaotalk/client.test.ts +157 -0
  165. package/src/platforms/kakaotalk/client.ts +57 -3
  166. package/src/platforms/kakaotalk/commands/auth.test.ts +299 -0
  167. package/src/platforms/kakaotalk/commands/chat.test.ts +97 -0
  168. package/src/platforms/kakaotalk/commands/index.ts +1 -0
  169. package/src/platforms/kakaotalk/commands/message.test.ts +113 -0
  170. package/src/platforms/kakaotalk/commands/profile.test.ts +84 -0
  171. package/src/platforms/kakaotalk/commands/profile.ts +21 -0
  172. package/src/platforms/kakaotalk/index.test.ts +5 -0
  173. package/src/platforms/kakaotalk/index.ts +2 -0
  174. package/src/platforms/kakaotalk/protocol/session.ts +2 -0
  175. package/src/platforms/kakaotalk/types.ts +18 -0
  176. package/src/platforms/line/commands/auth.test.ts +141 -0
  177. package/src/platforms/line/commands/auth.ts +28 -19
  178. package/src/platforms/line/commands/chat.test.ts +110 -0
  179. package/src/platforms/line/commands/friend.test.ts +98 -0
  180. package/src/platforms/line/commands/message.test.ts +119 -0
  181. package/src/platforms/line/commands/profile.test.ts +85 -0
  182. package/src/platforms/slackbot/commands/channel.test.ts +139 -0
  183. package/src/platforms/slackbot/commands/message.test.ts +226 -0
  184. package/src/platforms/slackbot/commands/reaction.test.ts +90 -0
  185. package/src/platforms/slackbot/commands/user.test.ts +143 -0
  186. package/src/platforms/teams/commands/reaction.test.ts +45 -61
  187. package/src/platforms/teams/commands/reaction.ts +2 -0
  188. package/src/platforms/telegram/commands/chat.test.ts +125 -0
  189. package/src/platforms/telegram/commands/message.test.ts +92 -0
  190. package/src/platforms/webex/client.ts +98 -26
  191. package/src/platforms/webex/commands/auth.ts +4 -0
  192. package/src/platforms/webex/commands/member.test.ts +65 -58
  193. package/src/platforms/webex/commands/message.test.ts +78 -121
  194. package/src/platforms/webex/commands/snapshot.test.ts +59 -46
  195. package/src/platforms/webex/commands/space.test.ts +49 -48
  196. package/src/platforms/webex/encryption.ts +53 -0
  197. package/src/platforms/webex/ensure-auth.ts +4 -0
  198. package/src/platforms/webex/token-extractor.ts +107 -40
  199. package/src/platforms/webex/types.ts +4 -0
  200. package/src/platforms/webex/typings/node-jose.d.ts +27 -0
  201. package/src/platforms/wechatbot/cli.ts +24 -0
  202. package/src/platforms/wechatbot/client.test.ts +497 -0
  203. package/src/platforms/wechatbot/client.ts +268 -0
  204. package/src/platforms/wechatbot/commands/auth.test.ts +211 -0
  205. package/src/platforms/wechatbot/commands/auth.ts +203 -0
  206. package/src/platforms/wechatbot/commands/index.ts +4 -0
  207. package/src/platforms/wechatbot/commands/message.test.ts +155 -0
  208. package/src/platforms/wechatbot/commands/message.ts +104 -0
  209. package/src/platforms/wechatbot/commands/shared.ts +22 -0
  210. package/src/platforms/wechatbot/commands/template.test.ts +199 -0
  211. package/src/platforms/wechatbot/commands/template.ts +102 -0
  212. package/src/platforms/wechatbot/commands/user.test.ts +165 -0
  213. package/src/platforms/wechatbot/commands/user.ts +75 -0
  214. package/src/platforms/wechatbot/credential-manager.test.ts +255 -0
  215. package/src/platforms/wechatbot/credential-manager.ts +148 -0
  216. package/src/platforms/wechatbot/index.test.ts +49 -0
  217. package/src/platforms/wechatbot/index.ts +19 -0
  218. package/src/platforms/wechatbot/types.test.ts +223 -0
  219. package/src/platforms/wechatbot/types.ts +107 -0
  220. package/src/platforms/whatsapp/client.ts +24 -13
  221. package/src/platforms/whatsapp/commands/auth.test.ts +311 -0
  222. package/src/platforms/whatsapp/commands/auth.ts +21 -17
  223. package/src/platforms/whatsapp/commands/chat.test.ts +198 -0
  224. package/src/platforms/whatsapp/commands/message.test.ts +231 -0
  225. package/src/platforms/whatsapp/credential-manager.test.ts +20 -0
  226. package/src/platforms/whatsapp/credential-manager.ts +17 -8
  227. package/src/platforms/whatsappbot/commands/auth.test.ts +217 -0
  228. package/src/platforms/whatsappbot/commands/message.test.ts +198 -0
  229. package/src/platforms/whatsappbot/commands/template.test.ts +112 -0
@@ -0,0 +1,139 @@
1
+ import { beforeEach, describe, expect, mock, test } from 'bun:test'
2
+
3
+ const mockResolveChannel = mock((_channel: string) => Promise.resolve('C123456'))
4
+ const mockListChannels = mock(() =>
5
+ Promise.resolve([
6
+ {
7
+ id: 'C123456',
8
+ name: 'general',
9
+ is_private: false,
10
+ is_archived: false,
11
+ created: 1609459200,
12
+ creator: 'U123',
13
+ },
14
+ {
15
+ id: 'C789012',
16
+ name: 'random',
17
+ is_private: false,
18
+ is_archived: false,
19
+ created: 1609459200,
20
+ creator: 'U123',
21
+ },
22
+ ]),
23
+ )
24
+ const mockGetChannelInfo = mock(() =>
25
+ Promise.resolve({
26
+ id: 'C123456',
27
+ name: 'general',
28
+ is_private: false,
29
+ is_archived: false,
30
+ created: 1609459200,
31
+ creator: 'U123',
32
+ topic: { value: 'General discussion', creator: 'U123', last_set: 1609459200 },
33
+ purpose: { value: 'Company-wide announcements', creator: 'U123', last_set: 1609459200 },
34
+ }),
35
+ )
36
+
37
+ mock.module('../client', () => ({
38
+ SlackBotClient: class MockSlackBotClient {
39
+ async login(_credentials?: { token: string }) {
40
+ return this
41
+ }
42
+ resolveChannel = mockResolveChannel
43
+ listChannels = mockListChannels
44
+ getChannelInfo = mockGetChannelInfo
45
+ },
46
+ }))
47
+
48
+ import { SlackBotClient } from '../client'
49
+
50
+ describe('channel commands', () => {
51
+ beforeEach(() => {
52
+ mockResolveChannel.mockClear()
53
+ mockListChannels.mockClear()
54
+ mockGetChannelInfo.mockClear()
55
+ })
56
+
57
+ describe('listChannels', () => {
58
+ test('returns list of channels', async () => {
59
+ // given
60
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
61
+
62
+ // when
63
+ const channels = await client.listChannels()
64
+
65
+ // then
66
+ expect(channels).toHaveLength(2)
67
+ expect(channels[0].name).toBe('general')
68
+ expect(channels[1].name).toBe('random')
69
+ })
70
+
71
+ test('includes channel metadata', async () => {
72
+ // given
73
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
74
+
75
+ // when
76
+ const channels = await client.listChannels()
77
+ const channel = channels[0]
78
+
79
+ // then
80
+ expect(channel.id).toBeDefined()
81
+ expect(channel.name).toBeDefined()
82
+ expect(channel.is_private).toBe(false)
83
+ expect(channel.is_archived).toBe(false)
84
+ expect(channel.created).toBeDefined()
85
+ })
86
+
87
+ test('passes limit option', async () => {
88
+ // given
89
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
90
+
91
+ // when
92
+ await client.listChannels({ limit: 50 })
93
+
94
+ // then
95
+ expect(mockListChannels).toHaveBeenCalledWith({ limit: 50 })
96
+ })
97
+ })
98
+
99
+ describe('getChannelInfo', () => {
100
+ test('returns channel details', async () => {
101
+ // given
102
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
103
+
104
+ // when
105
+ const channel = await client.getChannelInfo('C123456')
106
+
107
+ // then
108
+ expect(channel.id).toBe('C123456')
109
+ expect(channel.name).toBe('general')
110
+ expect(channel.is_private).toBe(false)
111
+ })
112
+
113
+ test('includes topic and purpose', async () => {
114
+ // given
115
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
116
+
117
+ // when
118
+ const channel = await client.getChannelInfo('C123456')
119
+
120
+ // then
121
+ expect(channel.topic?.value).toBe('General discussion')
122
+ expect(channel.purpose?.value).toBe('Company-wide announcements')
123
+ })
124
+ })
125
+
126
+ describe('resolveChannel', () => {
127
+ test('resolves channel name to ID', async () => {
128
+ // given
129
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
130
+
131
+ // when
132
+ const channelId = await client.resolveChannel('general')
133
+
134
+ // then
135
+ expect(channelId).toBe('C123456')
136
+ expect(mockResolveChannel).toHaveBeenCalledWith('general')
137
+ })
138
+ })
139
+ })
@@ -0,0 +1,226 @@
1
+ import { beforeEach, describe, expect, mock, test } from 'bun:test'
2
+
3
+ const mockResolveChannel = mock((_channel: string) => Promise.resolve('C123456'))
4
+ const mockPostMessage = mock(() =>
5
+ Promise.resolve({
6
+ ts: '1234567890.000100',
7
+ text: 'Hello world',
8
+ type: 'message',
9
+ user: 'U123',
10
+ }),
11
+ )
12
+ const mockGetConversationHistory = mock(() =>
13
+ Promise.resolve([
14
+ { ts: '1234567890.000100', text: 'Hello', type: 'message', user: 'U123' },
15
+ { ts: '1234567890.000200', text: 'World', type: 'message', user: 'U456' },
16
+ ]),
17
+ )
18
+ const mockGetMessage = mock(() =>
19
+ Promise.resolve({
20
+ ts: '1234567890.000100',
21
+ text: 'Hello world',
22
+ type: 'message',
23
+ user: 'U123',
24
+ }),
25
+ )
26
+ const mockUpdateMessage = mock(() =>
27
+ Promise.resolve({
28
+ ts: '1234567890.000100',
29
+ text: 'Updated text',
30
+ type: 'message',
31
+ user: 'U123',
32
+ }),
33
+ )
34
+ const mockDeleteMessage = mock(() => Promise.resolve())
35
+ const mockGetThreadReplies = mock(() =>
36
+ Promise.resolve([
37
+ { ts: '1234567890.000100', text: 'Thread reply 1', type: 'message', user: 'U123' },
38
+ { ts: '1234567890.000200', text: 'Thread reply 2', type: 'message', user: 'U456' },
39
+ ]),
40
+ )
41
+
42
+ mock.module('../client', () => ({
43
+ SlackBotClient: class MockSlackBotClient {
44
+ async login(_credentials?: { token: string }) {
45
+ return this
46
+ }
47
+ resolveChannel = mockResolveChannel
48
+ postMessage = mockPostMessage
49
+ getConversationHistory = mockGetConversationHistory
50
+ getMessage = mockGetMessage
51
+ updateMessage = mockUpdateMessage
52
+ deleteMessage = mockDeleteMessage
53
+ getThreadReplies = mockGetThreadReplies
54
+ },
55
+ }))
56
+
57
+ import { SlackBotClient } from '../client'
58
+
59
+ describe('message commands', () => {
60
+ beforeEach(() => {
61
+ mockResolveChannel.mockClear()
62
+ mockPostMessage.mockClear()
63
+ mockGetConversationHistory.mockClear()
64
+ mockGetMessage.mockClear()
65
+ mockUpdateMessage.mockClear()
66
+ mockDeleteMessage.mockClear()
67
+ mockGetThreadReplies.mockClear()
68
+ })
69
+
70
+ describe('postMessage', () => {
71
+ test('sends message to channel', async () => {
72
+ // given
73
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
74
+
75
+ // when
76
+ const result = await client.postMessage('C123456', 'Hello world')
77
+
78
+ // then
79
+ expect(result.ts).toBe('1234567890.000100')
80
+ expect(result.text).toBe('Hello world')
81
+ expect(result.type).toBe('message')
82
+ })
83
+
84
+ test('sends message with thread_ts', async () => {
85
+ // given
86
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
87
+
88
+ // when
89
+ await client.postMessage('C123456', 'Thread reply', { thread_ts: '1234567890.000100' })
90
+
91
+ // then
92
+ expect(mockPostMessage).toHaveBeenCalledWith('C123456', 'Thread reply', { thread_ts: '1234567890.000100' })
93
+ })
94
+ })
95
+
96
+ describe('getConversationHistory', () => {
97
+ test('returns messages from channel', async () => {
98
+ // given
99
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
100
+
101
+ // when
102
+ const messages = await client.getConversationHistory('C123456', { limit: 20 })
103
+
104
+ // then
105
+ expect(messages).toHaveLength(2)
106
+ expect(messages[0].text).toBe('Hello')
107
+ expect(messages[1].text).toBe('World')
108
+ })
109
+
110
+ test('passes limit option', async () => {
111
+ // given
112
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
113
+
114
+ // when
115
+ await client.getConversationHistory('C123456', { limit: 50 })
116
+
117
+ // then
118
+ expect(mockGetConversationHistory).toHaveBeenCalledWith('C123456', { limit: 50 })
119
+ })
120
+ })
121
+
122
+ describe('getMessage', () => {
123
+ test('returns single message by ts', async () => {
124
+ // given
125
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
126
+
127
+ // when
128
+ const message = await client.getMessage('C123456', '1234567890.000100')
129
+
130
+ // then
131
+ expect(message).not.toBeNull()
132
+ expect(message?.ts).toBe('1234567890.000100')
133
+ expect(message?.text).toBe('Hello world')
134
+ })
135
+
136
+ test('returns null when message not found', async () => {
137
+ // given
138
+ mockGetMessage.mockResolvedValueOnce(null)
139
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
140
+
141
+ // when
142
+ const message = await client.getMessage('C123456', 'nonexistent.ts')
143
+
144
+ // then
145
+ expect(message).toBeNull()
146
+ })
147
+ })
148
+
149
+ describe('updateMessage', () => {
150
+ test('updates message text', async () => {
151
+ // given
152
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
153
+
154
+ // when
155
+ const result = await client.updateMessage('C123456', '1234567890.000100', 'Updated text')
156
+
157
+ // then
158
+ expect(result.ts).toBe('1234567890.000100')
159
+ expect(result.text).toBe('Updated text')
160
+ })
161
+
162
+ test('called with correct arguments', async () => {
163
+ // given
164
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
165
+
166
+ // when
167
+ await client.updateMessage('C123456', '1234567890.000100', 'New text')
168
+
169
+ // then
170
+ expect(mockUpdateMessage).toHaveBeenCalledWith('C123456', '1234567890.000100', 'New text')
171
+ })
172
+ })
173
+
174
+ describe('deleteMessage', () => {
175
+ test('deletes message by ts', async () => {
176
+ // given
177
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
178
+
179
+ // when
180
+ await client.deleteMessage('C123456', '1234567890.000100')
181
+
182
+ // then
183
+ expect(mockDeleteMessage).toHaveBeenCalledWith('C123456', '1234567890.000100')
184
+ })
185
+ })
186
+
187
+ describe('getThreadReplies', () => {
188
+ test('returns thread replies', async () => {
189
+ // given
190
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
191
+
192
+ // when
193
+ const replies = await client.getThreadReplies('C123456', '1234567890.000100', { limit: 100 })
194
+
195
+ // then
196
+ expect(replies).toHaveLength(2)
197
+ expect(replies[0].text).toBe('Thread reply 1')
198
+ expect(replies[1].text).toBe('Thread reply 2')
199
+ })
200
+
201
+ test('passes limit option', async () => {
202
+ // given
203
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
204
+
205
+ // when
206
+ await client.getThreadReplies('C123456', '1234567890.000100', { limit: 50 })
207
+
208
+ // then
209
+ expect(mockGetThreadReplies).toHaveBeenCalledWith('C123456', '1234567890.000100', { limit: 50 })
210
+ })
211
+ })
212
+
213
+ describe('resolveChannel', () => {
214
+ test('resolves channel name to ID', async () => {
215
+ // given
216
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
217
+
218
+ // when
219
+ const channelId = await client.resolveChannel('general')
220
+
221
+ // then
222
+ expect(channelId).toBe('C123456')
223
+ expect(mockResolveChannel).toHaveBeenCalledWith('general')
224
+ })
225
+ })
226
+ })
@@ -0,0 +1,90 @@
1
+ import { beforeEach, describe, expect, mock, test } from 'bun:test'
2
+
3
+ const mockResolveChannel = mock((_channel: string) => Promise.resolve('C123456'))
4
+ const mockAddReaction = mock(() => Promise.resolve())
5
+ const mockRemoveReaction = mock(() => Promise.resolve())
6
+
7
+ mock.module('../client', () => ({
8
+ SlackBotClient: class MockSlackBotClient {
9
+ async login(_credentials?: { token: string }) {
10
+ return this
11
+ }
12
+ resolveChannel = mockResolveChannel
13
+ addReaction = mockAddReaction
14
+ removeReaction = mockRemoveReaction
15
+ },
16
+ }))
17
+
18
+ import { SlackBotClient } from '../client'
19
+
20
+ describe('reaction commands', () => {
21
+ beforeEach(() => {
22
+ mockResolveChannel.mockClear()
23
+ mockAddReaction.mockClear()
24
+ mockRemoveReaction.mockClear()
25
+ })
26
+
27
+ describe('addReaction', () => {
28
+ test('adds emoji reaction to message', async () => {
29
+ // given
30
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
31
+
32
+ // when
33
+ await client.addReaction('C123456', '1234567890.000100', 'thumbsup')
34
+
35
+ // then
36
+ expect(mockAddReaction).toHaveBeenCalledWith('C123456', '1234567890.000100', 'thumbsup')
37
+ })
38
+
39
+ test('called with correct arguments', async () => {
40
+ // given
41
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
42
+
43
+ // when
44
+ await client.addReaction('C123456', '1234567890.000200', 'heart')
45
+
46
+ // then
47
+ expect(mockAddReaction).toHaveBeenCalledTimes(1)
48
+ expect(mockAddReaction).toHaveBeenCalledWith('C123456', '1234567890.000200', 'heart')
49
+ })
50
+ })
51
+
52
+ describe('removeReaction', () => {
53
+ test('removes emoji reaction from message', async () => {
54
+ // given
55
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
56
+
57
+ // when
58
+ await client.removeReaction('C123456', '1234567890.000100', 'thumbsup')
59
+
60
+ // then
61
+ expect(mockRemoveReaction).toHaveBeenCalledWith('C123456', '1234567890.000100', 'thumbsup')
62
+ })
63
+
64
+ test('called with correct arguments', async () => {
65
+ // given
66
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
67
+
68
+ // when
69
+ await client.removeReaction('C123456', '1234567890.000200', 'wave')
70
+
71
+ // then
72
+ expect(mockRemoveReaction).toHaveBeenCalledTimes(1)
73
+ expect(mockRemoveReaction).toHaveBeenCalledWith('C123456', '1234567890.000200', 'wave')
74
+ })
75
+ })
76
+
77
+ describe('resolveChannel', () => {
78
+ test('resolves channel name before reaction', async () => {
79
+ // given
80
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
81
+
82
+ // when
83
+ const channelId = await client.resolveChannel('general')
84
+
85
+ // then
86
+ expect(channelId).toBe('C123456')
87
+ expect(mockResolveChannel).toHaveBeenCalledWith('general')
88
+ })
89
+ })
90
+ })
@@ -0,0 +1,143 @@
1
+ import { beforeEach, describe, expect, mock, test } from 'bun:test'
2
+
3
+ const mockListUsers = mock(() =>
4
+ Promise.resolve([
5
+ {
6
+ id: 'U123',
7
+ name: 'alice',
8
+ real_name: 'Alice Smith',
9
+ is_admin: false,
10
+ is_owner: false,
11
+ is_bot: false,
12
+ is_app_user: false,
13
+ profile: { email: 'alice@example.com', title: 'Engineer' },
14
+ },
15
+ {
16
+ id: 'U456',
17
+ name: 'bob',
18
+ real_name: 'Bob Jones',
19
+ is_admin: true,
20
+ is_owner: false,
21
+ is_bot: false,
22
+ is_app_user: false,
23
+ profile: { email: 'bob@example.com', title: 'Manager' },
24
+ },
25
+ ]),
26
+ )
27
+ const mockGetUserInfo = mock(() =>
28
+ Promise.resolve({
29
+ id: 'U123',
30
+ name: 'alice',
31
+ real_name: 'Alice Smith',
32
+ is_admin: false,
33
+ is_owner: false,
34
+ is_bot: false,
35
+ is_app_user: false,
36
+ profile: {
37
+ email: 'alice@example.com',
38
+ phone: '+1-555-0100',
39
+ title: 'Engineer',
40
+ status_text: 'Working from home',
41
+ },
42
+ }),
43
+ )
44
+
45
+ mock.module('../client', () => ({
46
+ SlackBotClient: class MockSlackBotClient {
47
+ async login(_credentials?: { token: string }) {
48
+ return this
49
+ }
50
+ listUsers = mockListUsers
51
+ getUserInfo = mockGetUserInfo
52
+ },
53
+ }))
54
+
55
+ import { SlackBotClient } from '../client'
56
+
57
+ describe('user commands', () => {
58
+ beforeEach(() => {
59
+ mockListUsers.mockClear()
60
+ mockGetUserInfo.mockClear()
61
+ })
62
+
63
+ describe('listUsers', () => {
64
+ test('returns list of users', async () => {
65
+ // given
66
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
67
+
68
+ // when
69
+ const users = await client.listUsers()
70
+
71
+ // then
72
+ expect(users).toHaveLength(2)
73
+ expect(users[0].name).toBe('alice')
74
+ expect(users[1].name).toBe('bob')
75
+ })
76
+
77
+ test('includes user metadata', async () => {
78
+ // given
79
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
80
+
81
+ // when
82
+ const users = await client.listUsers()
83
+ const user = users[0]
84
+
85
+ // then
86
+ expect(user.id).toBeDefined()
87
+ expect(user.name).toBeDefined()
88
+ expect(user.real_name).toBeDefined()
89
+ expect(user.is_bot).toBe(false)
90
+ expect(user.is_admin).toBe(false)
91
+ })
92
+
93
+ test('passes limit option', async () => {
94
+ // given
95
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
96
+
97
+ // when
98
+ await client.listUsers({ limit: 50 })
99
+
100
+ // then
101
+ expect(mockListUsers).toHaveBeenCalledWith({ limit: 50 })
102
+ })
103
+ })
104
+
105
+ describe('getUserInfo', () => {
106
+ test('returns user details by ID', async () => {
107
+ // given
108
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
109
+
110
+ // when
111
+ const user = await client.getUserInfo('U123')
112
+
113
+ // then
114
+ expect(user.id).toBe('U123')
115
+ expect(user.name).toBe('alice')
116
+ expect(user.real_name).toBe('Alice Smith')
117
+ })
118
+
119
+ test('includes profile information', async () => {
120
+ // given
121
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
122
+
123
+ // when
124
+ const user = await client.getUserInfo('U123')
125
+
126
+ // then
127
+ expect(user.profile?.email).toBe('alice@example.com')
128
+ expect(user.profile?.title).toBe('Engineer')
129
+ expect(user.profile?.status_text).toBe('Working from home')
130
+ })
131
+
132
+ test('called with correct user ID', async () => {
133
+ // given
134
+ const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
135
+
136
+ // when
137
+ await client.getUserInfo('U456')
138
+
139
+ // then
140
+ expect(mockGetUserInfo).toHaveBeenCalledWith('U456')
141
+ })
142
+ })
143
+ })