agent-messenger 2.3.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 (202) 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 +8 -5
  6. package/bun.lock +70 -110
  7. package/bunfig.toml +3 -0
  8. package/dist/package.json +11 -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/client.d.ts.map +1 -1
  38. package/dist/src/platforms/line/client.js +9 -36
  39. package/dist/src/platforms/line/client.js.map +1 -1
  40. package/dist/src/platforms/line/commands/auth.d.ts.map +1 -1
  41. package/dist/src/platforms/line/commands/auth.js +32 -20
  42. package/dist/src/platforms/line/commands/auth.js.map +1 -1
  43. package/dist/src/platforms/teams/commands/reaction.d.ts.map +1 -1
  44. package/dist/src/platforms/teams/commands/reaction.js +2 -0
  45. package/dist/src/platforms/teams/commands/reaction.js.map +1 -1
  46. package/dist/src/platforms/wechatbot/cli.d.ts +5 -0
  47. package/dist/src/platforms/wechatbot/cli.d.ts.map +1 -0
  48. package/dist/src/platforms/wechatbot/cli.js +18 -0
  49. package/dist/src/platforms/wechatbot/cli.js.map +1 -0
  50. package/dist/src/platforms/wechatbot/client.d.ts +36 -0
  51. package/dist/src/platforms/wechatbot/client.d.ts.map +1 -0
  52. package/dist/src/platforms/wechatbot/client.js +208 -0
  53. package/dist/src/platforms/wechatbot/client.js.map +1 -0
  54. package/dist/src/platforms/wechatbot/commands/auth.d.ts +28 -0
  55. package/dist/src/platforms/wechatbot/commands/auth.d.ts.map +1 -0
  56. package/dist/src/platforms/wechatbot/commands/auth.js +164 -0
  57. package/dist/src/platforms/wechatbot/commands/auth.js.map +1 -0
  58. package/dist/src/platforms/wechatbot/commands/index.d.ts +5 -0
  59. package/dist/src/platforms/wechatbot/commands/index.d.ts.map +1 -0
  60. package/dist/src/platforms/wechatbot/commands/index.js +5 -0
  61. package/dist/src/platforms/wechatbot/commands/index.js.map +1 -0
  62. package/dist/src/platforms/wechatbot/commands/message.d.ts +18 -0
  63. package/dist/src/platforms/wechatbot/commands/message.d.ts.map +1 -0
  64. package/dist/src/platforms/wechatbot/commands/message.js +80 -0
  65. package/dist/src/platforms/wechatbot/commands/message.js.map +1 -0
  66. package/dist/src/platforms/wechatbot/commands/shared.d.ts +9 -0
  67. package/dist/src/platforms/wechatbot/commands/shared.d.ts.map +1 -0
  68. package/dist/src/platforms/wechatbot/commands/shared.js +13 -0
  69. package/dist/src/platforms/wechatbot/commands/shared.js.map +1 -0
  70. package/dist/src/platforms/wechatbot/commands/template.d.ts +19 -0
  71. package/dist/src/platforms/wechatbot/commands/template.d.ts.map +1 -0
  72. package/dist/src/platforms/wechatbot/commands/template.js +76 -0
  73. package/dist/src/platforms/wechatbot/commands/template.js.map +1 -0
  74. package/dist/src/platforms/wechatbot/commands/user.d.ts +20 -0
  75. package/dist/src/platforms/wechatbot/commands/user.d.ts.map +1 -0
  76. package/dist/src/platforms/wechatbot/commands/user.js +53 -0
  77. package/dist/src/platforms/wechatbot/commands/user.js.map +1 -0
  78. package/dist/src/platforms/wechatbot/credential-manager.d.ts +17 -0
  79. package/dist/src/platforms/wechatbot/credential-manager.d.ts.map +1 -0
  80. package/dist/src/platforms/wechatbot/credential-manager.js +121 -0
  81. package/dist/src/platforms/wechatbot/credential-manager.js.map +1 -0
  82. package/dist/src/platforms/wechatbot/index.d.ts +5 -0
  83. package/dist/src/platforms/wechatbot/index.d.ts.map +1 -0
  84. package/dist/src/platforms/wechatbot/index.js +4 -0
  85. package/dist/src/platforms/wechatbot/index.js.map +1 -0
  86. package/dist/src/platforms/wechatbot/types.d.ts +94 -0
  87. package/dist/src/platforms/wechatbot/types.d.ts.map +1 -0
  88. package/dist/src/platforms/wechatbot/types.js +54 -0
  89. package/dist/src/platforms/wechatbot/types.js.map +1 -0
  90. package/dist/src/platforms/whatsapp/client.d.ts +1 -0
  91. package/dist/src/platforms/whatsapp/client.d.ts.map +1 -1
  92. package/dist/src/platforms/whatsapp/client.js +27 -13
  93. package/dist/src/platforms/whatsapp/client.js.map +1 -1
  94. package/dist/src/platforms/whatsapp/commands/auth.d.ts.map +1 -1
  95. package/dist/src/platforms/whatsapp/commands/auth.js +21 -18
  96. package/dist/src/platforms/whatsapp/commands/auth.js.map +1 -1
  97. package/dist/src/platforms/whatsapp/credential-manager.d.ts.map +1 -1
  98. package/dist/src/platforms/whatsapp/credential-manager.js +14 -8
  99. package/dist/src/platforms/whatsapp/credential-manager.js.map +1 -1
  100. package/docs/content/docs/agent-skills.mdx +4 -4
  101. package/docs/content/docs/cli/channeltalk.mdx +1 -1
  102. package/docs/content/docs/cli/channeltalkbot.mdx +1 -1
  103. package/docs/content/docs/cli/discord.mdx +1 -1
  104. package/docs/content/docs/cli/discordbot.mdx +1 -1
  105. package/docs/content/docs/cli/instagram.mdx +1 -1
  106. package/docs/content/docs/cli/kakaotalk.mdx +1 -1
  107. package/docs/content/docs/cli/line.mdx +1 -1
  108. package/docs/content/docs/cli/meta.json +1 -0
  109. package/docs/content/docs/cli/slack.mdx +1 -1
  110. package/docs/content/docs/cli/slackbot.mdx +1 -1
  111. package/docs/content/docs/cli/teams.mdx +1 -1
  112. package/docs/content/docs/cli/webex.mdx +1 -1
  113. package/docs/content/docs/cli/wechatbot.mdx +179 -0
  114. package/docs/content/docs/cli/whatsapp.mdx +1 -1
  115. package/docs/content/docs/cli/whatsappbot.mdx +1 -1
  116. package/docs/content/docs/sdk/meta.json +1 -1
  117. package/docs/content/docs/sdk/wechatbot.mdx +282 -0
  118. package/docs/content/docs/tui.mdx +1 -1
  119. package/docs/src/app/page.tsx +5 -5
  120. package/package.json +11 -3
  121. package/skills/agent-channeltalk/SKILL.md +1 -1
  122. package/skills/agent-channeltalkbot/SKILL.md +1 -1
  123. package/skills/agent-discord/SKILL.md +1 -1
  124. package/skills/agent-discordbot/SKILL.md +1 -1
  125. package/skills/agent-instagram/SKILL.md +1 -1
  126. package/skills/agent-kakaotalk/SKILL.md +24 -1
  127. package/skills/agent-line/SKILL.md +7 -11
  128. package/skills/agent-line/references/authentication.md +13 -4
  129. package/skills/agent-slack/SKILL.md +1 -1
  130. package/skills/agent-slackbot/SKILL.md +1 -1
  131. package/skills/agent-teams/SKILL.md +1 -1
  132. package/skills/agent-telegram/SKILL.md +1 -1
  133. package/skills/agent-webex/SKILL.md +1 -1
  134. package/skills/agent-wechatbot/SKILL.md +385 -0
  135. package/skills/agent-whatsapp/SKILL.md +12 -1
  136. package/skills/agent-whatsappbot/SKILL.md +1 -1
  137. package/src/platforms/discord/credential-manager.test.ts +18 -1
  138. package/src/platforms/discordbot/client.ts +2 -2
  139. package/src/platforms/instagram/commands/auth.test.ts +216 -0
  140. package/src/platforms/instagram/commands/chat.test.ts +127 -0
  141. package/src/platforms/instagram/commands/message.test.ts +178 -0
  142. package/src/platforms/kakaotalk/cli.ts +2 -1
  143. package/src/platforms/kakaotalk/client.test.ts +157 -0
  144. package/src/platforms/kakaotalk/client.ts +57 -3
  145. package/src/platforms/kakaotalk/commands/auth.test.ts +299 -0
  146. package/src/platforms/kakaotalk/commands/chat.test.ts +97 -0
  147. package/src/platforms/kakaotalk/commands/index.ts +1 -0
  148. package/src/platforms/kakaotalk/commands/message.test.ts +113 -0
  149. package/src/platforms/kakaotalk/commands/profile.test.ts +84 -0
  150. package/src/platforms/kakaotalk/commands/profile.ts +21 -0
  151. package/src/platforms/kakaotalk/index.test.ts +5 -0
  152. package/src/platforms/kakaotalk/index.ts +2 -0
  153. package/src/platforms/kakaotalk/protocol/session.ts +2 -0
  154. package/src/platforms/kakaotalk/types.ts +18 -0
  155. package/src/platforms/line/client.ts +14 -39
  156. package/src/platforms/line/commands/auth.test.ts +141 -0
  157. package/src/platforms/line/commands/auth.ts +28 -19
  158. package/src/platforms/line/commands/chat.test.ts +110 -0
  159. package/src/platforms/line/commands/friend.test.ts +98 -0
  160. package/src/platforms/line/commands/message.test.ts +119 -0
  161. package/src/platforms/line/commands/profile.test.ts +85 -0
  162. package/src/platforms/slackbot/commands/channel.test.ts +139 -0
  163. package/src/platforms/slackbot/commands/message.test.ts +226 -0
  164. package/src/platforms/slackbot/commands/reaction.test.ts +90 -0
  165. package/src/platforms/slackbot/commands/user.test.ts +143 -0
  166. package/src/platforms/teams/commands/reaction.test.ts +45 -61
  167. package/src/platforms/teams/commands/reaction.ts +2 -0
  168. package/src/platforms/telegram/commands/chat.test.ts +125 -0
  169. package/src/platforms/telegram/commands/message.test.ts +92 -0
  170. package/src/platforms/webex/commands/member.test.ts +65 -58
  171. package/src/platforms/webex/commands/message.test.ts +78 -121
  172. package/src/platforms/webex/commands/snapshot.test.ts +59 -46
  173. package/src/platforms/webex/commands/space.test.ts +49 -48
  174. package/src/platforms/wechatbot/cli.ts +24 -0
  175. package/src/platforms/wechatbot/client.test.ts +497 -0
  176. package/src/platforms/wechatbot/client.ts +268 -0
  177. package/src/platforms/wechatbot/commands/auth.test.ts +211 -0
  178. package/src/platforms/wechatbot/commands/auth.ts +203 -0
  179. package/src/platforms/wechatbot/commands/index.ts +4 -0
  180. package/src/platforms/wechatbot/commands/message.test.ts +155 -0
  181. package/src/platforms/wechatbot/commands/message.ts +104 -0
  182. package/src/platforms/wechatbot/commands/shared.ts +22 -0
  183. package/src/platforms/wechatbot/commands/template.test.ts +199 -0
  184. package/src/platforms/wechatbot/commands/template.ts +102 -0
  185. package/src/platforms/wechatbot/commands/user.test.ts +165 -0
  186. package/src/platforms/wechatbot/commands/user.ts +75 -0
  187. package/src/platforms/wechatbot/credential-manager.test.ts +255 -0
  188. package/src/platforms/wechatbot/credential-manager.ts +148 -0
  189. package/src/platforms/wechatbot/index.test.ts +49 -0
  190. package/src/platforms/wechatbot/index.ts +19 -0
  191. package/src/platforms/wechatbot/types.test.ts +223 -0
  192. package/src/platforms/wechatbot/types.ts +107 -0
  193. package/src/platforms/whatsapp/client.ts +24 -13
  194. package/src/platforms/whatsapp/commands/auth.test.ts +311 -0
  195. package/src/platforms/whatsapp/commands/auth.ts +21 -17
  196. package/src/platforms/whatsapp/commands/chat.test.ts +198 -0
  197. package/src/platforms/whatsapp/commands/message.test.ts +231 -0
  198. package/src/platforms/whatsapp/credential-manager.test.ts +20 -0
  199. package/src/platforms/whatsapp/credential-manager.ts +17 -8
  200. package/src/platforms/whatsappbot/commands/auth.test.ts +217 -0
  201. package/src/platforms/whatsappbot/commands/message.test.ts +198 -0
  202. package/src/platforms/whatsappbot/commands/template.test.ts +112 -0
@@ -0,0 +1,198 @@
1
+ import { beforeEach, describe, expect, mock, test } from 'bun:test'
2
+
3
+ const mockSendTextMessage = mock(() =>
4
+ Promise.resolve({
5
+ messaging_product: 'whatsapp',
6
+ contacts: [{ input: '+1234567890', wa_id: '1234567890' }],
7
+ messages: [{ id: 'wamid.test123' }],
8
+ }),
9
+ )
10
+
11
+ const mockSendTemplateMessage = mock(() =>
12
+ Promise.resolve({
13
+ messaging_product: 'whatsapp',
14
+ contacts: [{ input: '+1234567890', wa_id: '1234567890' }],
15
+ messages: [{ id: 'wamid.template123' }],
16
+ }),
17
+ )
18
+
19
+ const mockSendReaction = mock(() =>
20
+ Promise.resolve({
21
+ messaging_product: 'whatsapp',
22
+ contacts: [{ input: '+1234567890', wa_id: '1234567890' }],
23
+ messages: [{ id: 'wamid.reaction123' }],
24
+ }),
25
+ )
26
+
27
+ const mockSendImageMessage = mock(() =>
28
+ Promise.resolve({
29
+ messaging_product: 'whatsapp',
30
+ contacts: [{ input: '+1234567890', wa_id: '1234567890' }],
31
+ messages: [{ id: 'wamid.image123' }],
32
+ }),
33
+ )
34
+
35
+ const mockSendDocumentMessage = mock(() =>
36
+ Promise.resolve({
37
+ messaging_product: 'whatsapp',
38
+ contacts: [{ input: '+1234567890', wa_id: '1234567890' }],
39
+ messages: [{ id: 'wamid.doc123' }],
40
+ }),
41
+ )
42
+
43
+ const mockClient = {
44
+ sendTextMessage: mockSendTextMessage,
45
+ sendTemplateMessage: mockSendTemplateMessage,
46
+ sendReaction: mockSendReaction,
47
+ sendImageMessage: mockSendImageMessage,
48
+ sendDocumentMessage: mockSendDocumentMessage,
49
+ }
50
+
51
+ mock.module('./shared', () => ({
52
+ getClient: async () => mockClient,
53
+ }))
54
+
55
+ import { sendAction, sendDocumentAction, sendImageAction, sendReactionAction, sendTemplateAction } from './message'
56
+
57
+ describe('message commands', () => {
58
+ beforeEach(() => {
59
+ mockSendTextMessage.mockClear()
60
+ mockSendTemplateMessage.mockClear()
61
+ mockSendReaction.mockClear()
62
+ mockSendImageMessage.mockClear()
63
+ mockSendDocumentMessage.mockClear()
64
+ })
65
+
66
+ describe('sendAction', () => {
67
+ test('sends a text message and returns result', async () => {
68
+ const result = await sendAction('+1234567890', 'Hello!', {})
69
+
70
+ expect(result.messaging_product).toBe('whatsapp')
71
+ expect(result.messages).toHaveLength(1)
72
+ expect(result.messages?.[0].id).toBe('wamid.test123')
73
+ expect(mockSendTextMessage).toHaveBeenCalledWith('+1234567890', 'Hello!')
74
+ })
75
+
76
+ test('returns error when client throws', async () => {
77
+ mockSendTextMessage.mockImplementationOnce(() => Promise.reject(new Error('Network error')))
78
+
79
+ const result = await sendAction('+1234567890', 'Hello!', {})
80
+
81
+ expect(result.error).toBe('Network error')
82
+ })
83
+ })
84
+
85
+ describe('sendTemplateAction', () => {
86
+ test('sends a template message with default language', async () => {
87
+ const result = await sendTemplateAction('+1234567890', 'hello_world', {})
88
+
89
+ expect(result.messaging_product).toBe('whatsapp')
90
+ expect(result.messages?.[0].id).toBe('wamid.template123')
91
+ expect(mockSendTemplateMessage).toHaveBeenCalledWith('+1234567890', 'hello_world', 'en_US', undefined)
92
+ })
93
+
94
+ test('sends a template message with custom language', async () => {
95
+ const result = await sendTemplateAction('+1234567890', 'hello_world', { language: 'pt_BR' })
96
+
97
+ expect(mockSendTemplateMessage).toHaveBeenCalledWith('+1234567890', 'hello_world', 'pt_BR', undefined)
98
+ expect(result.error).toBeUndefined()
99
+ })
100
+
101
+ test('parses and passes components JSON', async () => {
102
+ const components = [{ type: 'body', parameters: [{ type: 'text', text: 'World' }] }]
103
+ const result = await sendTemplateAction('+1234567890', 'hello_world', {
104
+ components: JSON.stringify(components),
105
+ })
106
+
107
+ expect(mockSendTemplateMessage).toHaveBeenCalledWith('+1234567890', 'hello_world', 'en_US', components)
108
+ expect(result.error).toBeUndefined()
109
+ })
110
+
111
+ test('returns error for invalid components JSON', async () => {
112
+ const result = await sendTemplateAction('+1234567890', 'hello_world', {
113
+ components: 'not-valid-json',
114
+ })
115
+
116
+ expect(result.error).toBe('Invalid --components JSON')
117
+ })
118
+
119
+ test('returns error when client throws', async () => {
120
+ mockSendTemplateMessage.mockImplementationOnce(() => Promise.reject(new Error('Template not found')))
121
+
122
+ const result = await sendTemplateAction('+1234567890', 'missing_template', {})
123
+
124
+ expect(result.error).toBe('Template not found')
125
+ })
126
+ })
127
+
128
+ describe('sendReactionAction', () => {
129
+ test('sends a reaction and returns result', async () => {
130
+ const result = await sendReactionAction('+1234567890', 'wamid.msg123', '👍', {})
131
+
132
+ expect(result.messaging_product).toBe('whatsapp')
133
+ expect(result.messages?.[0].id).toBe('wamid.reaction123')
134
+ expect(mockSendReaction).toHaveBeenCalledWith('+1234567890', 'wamid.msg123', '👍')
135
+ })
136
+
137
+ test('returns error when client throws', async () => {
138
+ mockSendReaction.mockImplementationOnce(() => Promise.reject(new Error('Message not found')))
139
+
140
+ const result = await sendReactionAction('+1234567890', 'wamid.bad', '👍', {})
141
+
142
+ expect(result.error).toBe('Message not found')
143
+ })
144
+ })
145
+
146
+ describe('sendImageAction', () => {
147
+ test('sends an image message and returns result', async () => {
148
+ const result = await sendImageAction('+1234567890', 'https://example.com/image.jpg', {})
149
+
150
+ expect(result.messaging_product).toBe('whatsapp')
151
+ expect(result.messages?.[0].id).toBe('wamid.image123')
152
+ expect(mockSendImageMessage).toHaveBeenCalledWith('+1234567890', 'https://example.com/image.jpg', undefined)
153
+ })
154
+
155
+ test('passes caption when provided', async () => {
156
+ const result = await sendImageAction('+1234567890', 'https://example.com/image.jpg', { caption: 'My photo' })
157
+
158
+ expect(mockSendImageMessage).toHaveBeenCalledWith('+1234567890', 'https://example.com/image.jpg', 'My photo')
159
+ expect(result.error).toBeUndefined()
160
+ })
161
+
162
+ test('returns error when client throws', async () => {
163
+ mockSendImageMessage.mockImplementationOnce(() => Promise.reject(new Error('Invalid URL')))
164
+
165
+ const result = await sendImageAction('+1234567890', 'bad-url', {})
166
+
167
+ expect(result.error).toBe('Invalid URL')
168
+ })
169
+ })
170
+
171
+ describe('sendDocumentAction', () => {
172
+ test('sends a document message and returns result', async () => {
173
+ const result = await sendDocumentAction('+1234567890', 'https://example.com/doc.pdf', {})
174
+
175
+ expect(result.messaging_product).toBe('whatsapp')
176
+ expect(result.messages?.[0].id).toBe('wamid.doc123')
177
+ expect(mockSendDocumentMessage).toHaveBeenCalledWith('+1234567890', 'https://example.com/doc.pdf', undefined, undefined)
178
+ })
179
+
180
+ test('passes filename and caption when provided', async () => {
181
+ const result = await sendDocumentAction('+1234567890', 'https://example.com/doc.pdf', {
182
+ filename: 'report.pdf',
183
+ caption: 'Monthly report',
184
+ })
185
+
186
+ expect(mockSendDocumentMessage).toHaveBeenCalledWith('+1234567890', 'https://example.com/doc.pdf', 'report.pdf', 'Monthly report')
187
+ expect(result.error).toBeUndefined()
188
+ })
189
+
190
+ test('returns error when client throws', async () => {
191
+ mockSendDocumentMessage.mockImplementationOnce(() => Promise.reject(new Error('Upload failed')))
192
+
193
+ const result = await sendDocumentAction('+1234567890', 'https://example.com/doc.pdf', {})
194
+
195
+ expect(result.error).toBe('Upload failed')
196
+ })
197
+ })
198
+ })
@@ -0,0 +1,112 @@
1
+ import { beforeEach, describe, expect, mock, test } from 'bun:test'
2
+
3
+ import type { WhatsAppBotTemplate } from '../types'
4
+
5
+ const mockTemplates: WhatsAppBotTemplate[] = [
6
+ {
7
+ name: 'hello_world',
8
+ status: 'APPROVED',
9
+ category: 'UTILITY',
10
+ language: 'en_US',
11
+ components: [{ type: 'BODY', text: 'Hello World!' }],
12
+ },
13
+ {
14
+ name: 'order_confirmation',
15
+ status: 'APPROVED',
16
+ category: 'TRANSACTIONAL',
17
+ language: 'en_US',
18
+ components: [{ type: 'BODY', text: 'Your order {{1}} has been confirmed.' }],
19
+ },
20
+ ]
21
+
22
+ const mockListTemplates = mock(() => Promise.resolve(mockTemplates))
23
+ const mockGetTemplate = mock((name: string) => {
24
+ const template = mockTemplates.find((t) => t.name === name)
25
+ if (!template) {
26
+ return Promise.reject(new Error(`Template "${name}" not found`))
27
+ }
28
+ return Promise.resolve(template)
29
+ })
30
+
31
+ const mockClient = {
32
+ listTemplates: mockListTemplates,
33
+ getTemplate: mockGetTemplate,
34
+ }
35
+
36
+ mock.module('./shared', () => ({
37
+ getClient: async () => mockClient,
38
+ }))
39
+
40
+ import { getAction, listAction } from './template'
41
+
42
+ describe('template commands', () => {
43
+ beforeEach(() => {
44
+ mockListTemplates.mockClear()
45
+ mockGetTemplate.mockClear()
46
+ })
47
+
48
+ describe('listAction', () => {
49
+ test('returns all templates', async () => {
50
+ const result = await listAction({})
51
+
52
+ expect(result.templates).toHaveLength(2)
53
+ expect(result.templates?.[0].name).toBe('hello_world')
54
+ expect(result.templates?.[1].name).toBe('order_confirmation')
55
+ expect(mockListTemplates).toHaveBeenCalledWith(undefined)
56
+ })
57
+
58
+ test('passes limit when provided', async () => {
59
+ const result = await listAction({ limit: '1' })
60
+
61
+ expect(mockListTemplates).toHaveBeenCalledWith({ limit: 1 })
62
+ expect(result.error).toBeUndefined()
63
+ })
64
+
65
+ test('returns error for invalid limit', async () => {
66
+ const result = await listAction({ limit: 'abc' })
67
+
68
+ expect(result.error).toBeDefined()
69
+ expect(result.error).toContain('Invalid --limit')
70
+ })
71
+
72
+ test('returns error for zero limit', async () => {
73
+ const result = await listAction({ limit: '0' })
74
+
75
+ expect(result.error).toBeDefined()
76
+ expect(result.error).toContain('Invalid --limit')
77
+ })
78
+
79
+ test('returns error when client throws', async () => {
80
+ mockListTemplates.mockImplementationOnce(() => Promise.reject(new Error('API error')))
81
+
82
+ const result = await listAction({})
83
+
84
+ expect(result.error).toBe('API error')
85
+ })
86
+ })
87
+
88
+ describe('getAction', () => {
89
+ test('returns a specific template by name', async () => {
90
+ const result = await getAction('hello_world', {})
91
+
92
+ expect(result.template).toBeDefined()
93
+ expect(result.template?.name).toBe('hello_world')
94
+ expect(result.template?.status).toBe('APPROVED')
95
+ expect(mockGetTemplate).toHaveBeenCalledWith('hello_world')
96
+ })
97
+
98
+ test('returns error when template not found', async () => {
99
+ const result = await getAction('nonexistent_template', {})
100
+
101
+ expect(result.error).toContain('nonexistent_template')
102
+ })
103
+
104
+ test('returns error when client throws', async () => {
105
+ mockGetTemplate.mockImplementationOnce(() => Promise.reject(new Error('Network error')))
106
+
107
+ const result = await getAction('hello_world', {})
108
+
109
+ expect(result.error).toBe('Network error')
110
+ })
111
+ })
112
+ })