@rv404/mcp-launchpad 1.0.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 (139) hide show
  1. package/.env.example +29 -0
  2. package/README.md +248 -0
  3. package/dist/backends/clickup.d.ts +3 -0
  4. package/dist/backends/clickup.d.ts.map +1 -0
  5. package/dist/backends/clickup.js +1550 -0
  6. package/dist/backends/clickup.js.map +1 -0
  7. package/dist/backends/email.d.ts +9 -0
  8. package/dist/backends/email.d.ts.map +1 -0
  9. package/dist/backends/email.js +452 -0
  10. package/dist/backends/email.js.map +1 -0
  11. package/dist/backends/firecrawl.d.ts +3 -0
  12. package/dist/backends/firecrawl.d.ts.map +1 -0
  13. package/dist/backends/firecrawl.js +297 -0
  14. package/dist/backends/firecrawl.js.map +1 -0
  15. package/dist/backends/gemini.d.ts +3 -0
  16. package/dist/backends/gemini.d.ts.map +1 -0
  17. package/dist/backends/gemini.js +702 -0
  18. package/dist/backends/gemini.js.map +1 -0
  19. package/dist/backends/github.d.ts +3 -0
  20. package/dist/backends/github.d.ts.map +1 -0
  21. package/dist/backends/github.js +2129 -0
  22. package/dist/backends/github.js.map +1 -0
  23. package/dist/backends/index.d.ts +2 -0
  24. package/dist/backends/index.d.ts.map +1 -0
  25. package/dist/backends/index.js +27 -0
  26. package/dist/backends/index.js.map +1 -0
  27. package/dist/backends/kie.d.ts +3 -0
  28. package/dist/backends/kie.d.ts.map +1 -0
  29. package/dist/backends/kie.js +399 -0
  30. package/dist/backends/kie.js.map +1 -0
  31. package/dist/backends/n8n.d.ts +3 -0
  32. package/dist/backends/n8n.d.ts.map +1 -0
  33. package/dist/backends/n8n.js +414 -0
  34. package/dist/backends/n8n.js.map +1 -0
  35. package/dist/backends/notion.d.ts +3 -0
  36. package/dist/backends/notion.d.ts.map +1 -0
  37. package/dist/backends/notion.js +375 -0
  38. package/dist/backends/notion.js.map +1 -0
  39. package/dist/backends/quickbooks.d.ts +3 -0
  40. package/dist/backends/quickbooks.d.ts.map +1 -0
  41. package/dist/backends/quickbooks.js +2183 -0
  42. package/dist/backends/quickbooks.js.map +1 -0
  43. package/dist/backends/slack.d.ts +3 -0
  44. package/dist/backends/slack.d.ts.map +1 -0
  45. package/dist/backends/slack.js +1725 -0
  46. package/dist/backends/slack.js.map +1 -0
  47. package/dist/backends/youtube.d.ts +3 -0
  48. package/dist/backends/youtube.d.ts.map +1 -0
  49. package/dist/backends/youtube.js +936 -0
  50. package/dist/backends/youtube.js.map +1 -0
  51. package/dist/index.d.ts +3 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +150 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/router.d.ts +36 -0
  56. package/dist/router.d.ts.map +1 -0
  57. package/dist/router.js +283 -0
  58. package/dist/router.js.map +1 -0
  59. package/dist/types.d.ts +103 -0
  60. package/dist/types.d.ts.map +1 -0
  61. package/dist/types.js +65 -0
  62. package/dist/types.js.map +1 -0
  63. package/lib/mcp-file-output/dist/index.d.ts +99 -0
  64. package/lib/mcp-file-output/dist/index.d.ts.map +1 -0
  65. package/lib/mcp-file-output/dist/index.js +215 -0
  66. package/lib/mcp-file-output/dist/index.js.map +1 -0
  67. package/lib/mcp-file-output/node_modules/@types/node/LICENSE +21 -0
  68. package/lib/mcp-file-output/node_modules/@types/node/README.md +15 -0
  69. package/lib/mcp-file-output/node_modules/@types/node/assert/strict.d.ts +8 -0
  70. package/lib/mcp-file-output/node_modules/@types/node/assert.d.ts +1062 -0
  71. package/lib/mcp-file-output/node_modules/@types/node/async_hooks.d.ts +605 -0
  72. package/lib/mcp-file-output/node_modules/@types/node/buffer.buffer.d.ts +471 -0
  73. package/lib/mcp-file-output/node_modules/@types/node/buffer.d.ts +1936 -0
  74. package/lib/mcp-file-output/node_modules/@types/node/child_process.d.ts +1475 -0
  75. package/lib/mcp-file-output/node_modules/@types/node/cluster.d.ts +577 -0
  76. package/lib/mcp-file-output/node_modules/@types/node/compatibility/disposable.d.ts +16 -0
  77. package/lib/mcp-file-output/node_modules/@types/node/compatibility/index.d.ts +9 -0
  78. package/lib/mcp-file-output/node_modules/@types/node/compatibility/indexable.d.ts +20 -0
  79. package/lib/mcp-file-output/node_modules/@types/node/compatibility/iterators.d.ts +21 -0
  80. package/lib/mcp-file-output/node_modules/@types/node/console.d.ts +452 -0
  81. package/lib/mcp-file-output/node_modules/@types/node/constants.d.ts +21 -0
  82. package/lib/mcp-file-output/node_modules/@types/node/crypto.d.ts +4590 -0
  83. package/lib/mcp-file-output/node_modules/@types/node/dgram.d.ts +597 -0
  84. package/lib/mcp-file-output/node_modules/@types/node/diagnostics_channel.d.ts +578 -0
  85. package/lib/mcp-file-output/node_modules/@types/node/dns/promises.d.ts +479 -0
  86. package/lib/mcp-file-output/node_modules/@types/node/dns.d.ts +871 -0
  87. package/lib/mcp-file-output/node_modules/@types/node/domain.d.ts +170 -0
  88. package/lib/mcp-file-output/node_modules/@types/node/events.d.ts +977 -0
  89. package/lib/mcp-file-output/node_modules/@types/node/fs/promises.d.ts +1270 -0
  90. package/lib/mcp-file-output/node_modules/@types/node/fs.d.ts +4375 -0
  91. package/lib/mcp-file-output/node_modules/@types/node/globals.d.ts +172 -0
  92. package/lib/mcp-file-output/node_modules/@types/node/globals.typedarray.d.ts +38 -0
  93. package/lib/mcp-file-output/node_modules/@types/node/http.d.ts +2049 -0
  94. package/lib/mcp-file-output/node_modules/@types/node/http2.d.ts +2631 -0
  95. package/lib/mcp-file-output/node_modules/@types/node/https.d.ts +578 -0
  96. package/lib/mcp-file-output/node_modules/@types/node/index.d.ts +93 -0
  97. package/lib/mcp-file-output/node_modules/@types/node/inspector.generated.d.ts +3966 -0
  98. package/lib/mcp-file-output/node_modules/@types/node/module.d.ts +539 -0
  99. package/lib/mcp-file-output/node_modules/@types/node/net.d.ts +1012 -0
  100. package/lib/mcp-file-output/node_modules/@types/node/os.d.ts +506 -0
  101. package/lib/mcp-file-output/node_modules/@types/node/package.json +140 -0
  102. package/lib/mcp-file-output/node_modules/@types/node/path.d.ts +200 -0
  103. package/lib/mcp-file-output/node_modules/@types/node/perf_hooks.d.ts +961 -0
  104. package/lib/mcp-file-output/node_modules/@types/node/process.d.ts +1957 -0
  105. package/lib/mcp-file-output/node_modules/@types/node/punycode.d.ts +117 -0
  106. package/lib/mcp-file-output/node_modules/@types/node/querystring.d.ts +152 -0
  107. package/lib/mcp-file-output/node_modules/@types/node/readline/promises.d.ts +162 -0
  108. package/lib/mcp-file-output/node_modules/@types/node/readline.d.ts +589 -0
  109. package/lib/mcp-file-output/node_modules/@types/node/repl.d.ts +430 -0
  110. package/lib/mcp-file-output/node_modules/@types/node/sea.d.ts +153 -0
  111. package/lib/mcp-file-output/node_modules/@types/node/stream/consumers.d.ts +38 -0
  112. package/lib/mcp-file-output/node_modules/@types/node/stream/promises.d.ts +90 -0
  113. package/lib/mcp-file-output/node_modules/@types/node/stream/web.d.ts +533 -0
  114. package/lib/mcp-file-output/node_modules/@types/node/stream.d.ts +1675 -0
  115. package/lib/mcp-file-output/node_modules/@types/node/string_decoder.d.ts +67 -0
  116. package/lib/mcp-file-output/node_modules/@types/node/test.d.ts +1787 -0
  117. package/lib/mcp-file-output/node_modules/@types/node/timers/promises.d.ts +108 -0
  118. package/lib/mcp-file-output/node_modules/@types/node/timers.d.ts +286 -0
  119. package/lib/mcp-file-output/node_modules/@types/node/tls.d.ts +1255 -0
  120. package/lib/mcp-file-output/node_modules/@types/node/trace_events.d.ts +197 -0
  121. package/lib/mcp-file-output/node_modules/@types/node/ts5.6/buffer.buffer.d.ts +468 -0
  122. package/lib/mcp-file-output/node_modules/@types/node/ts5.6/globals.typedarray.d.ts +34 -0
  123. package/lib/mcp-file-output/node_modules/@types/node/ts5.6/index.d.ts +93 -0
  124. package/lib/mcp-file-output/node_modules/@types/node/tty.d.ts +208 -0
  125. package/lib/mcp-file-output/node_modules/@types/node/url.d.ts +964 -0
  126. package/lib/mcp-file-output/node_modules/@types/node/util.d.ts +2331 -0
  127. package/lib/mcp-file-output/node_modules/@types/node/v8.d.ts +809 -0
  128. package/lib/mcp-file-output/node_modules/@types/node/vm.d.ts +1001 -0
  129. package/lib/mcp-file-output/node_modules/@types/node/wasi.d.ts +181 -0
  130. package/lib/mcp-file-output/node_modules/@types/node/web-globals/abortcontroller.d.ts +34 -0
  131. package/lib/mcp-file-output/node_modules/@types/node/web-globals/domexception.d.ts +68 -0
  132. package/lib/mcp-file-output/node_modules/@types/node/web-globals/events.d.ts +97 -0
  133. package/lib/mcp-file-output/node_modules/@types/node/web-globals/fetch.d.ts +46 -0
  134. package/lib/mcp-file-output/node_modules/@types/node/worker_threads.d.ts +715 -0
  135. package/lib/mcp-file-output/node_modules/@types/node/zlib.d.ts +540 -0
  136. package/lib/mcp-file-output/package.json +19 -0
  137. package/lib/mcp-file-output/src/index.ts +309 -0
  138. package/lib/mcp-file-output/tsconfig.json +20 -0
  139. package/package.json +64 -0
@@ -0,0 +1,1725 @@
1
+ import axios from 'axios';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ const SLACK_BOT_TOKEN = process.env.SLACK_BOT_TOKEN || '';
5
+ const BASE_URL = 'https://slack.com/api';
6
+ const headers = () => ({
7
+ 'Authorization': `Bearer ${SLACK_BOT_TOKEN}`,
8
+ 'Content-Type': 'application/json',
9
+ });
10
+ // ============================================================================
11
+ // ACTION DEFINITIONS
12
+ // ============================================================================
13
+ const actions = [
14
+ // --------------------------------------------------------------------------
15
+ // CONVERSATIONS / CHANNELS
16
+ // --------------------------------------------------------------------------
17
+ {
18
+ name: 'list_channels',
19
+ description: 'List public channels in the workspace with pagination',
20
+ params: [
21
+ { name: 'limit', type: 'number', required: false, description: 'Maximum number of channels to return (default 100, max 1000)' },
22
+ { name: 'cursor', type: 'string', required: false, description: 'Pagination cursor for next page of results' },
23
+ { name: 'types', type: 'string', required: false, description: 'Channel types: public_channel, private_channel, mpim, im (comma-separated, default: public_channel)' },
24
+ { name: 'exclude_archived', type: 'boolean', required: false, description: 'Exclude archived channels (default: false)' },
25
+ ],
26
+ },
27
+ {
28
+ name: 'get_channel_info',
29
+ description: 'Get detailed information about a channel',
30
+ params: [
31
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel' },
32
+ { name: 'include_num_members', type: 'boolean', required: false, description: 'Include member count (default: false)' },
33
+ ],
34
+ },
35
+ {
36
+ name: 'create_channel',
37
+ description: 'Create a new public or private channel',
38
+ params: [
39
+ { name: 'name', type: 'string', required: true, description: 'Name of the channel (no spaces, lowercase, max 80 chars)' },
40
+ { name: 'is_private', type: 'boolean', required: false, description: 'Create as private channel (default: false)' },
41
+ { name: 'description', type: 'string', required: false, description: 'Channel description' },
42
+ ],
43
+ },
44
+ {
45
+ name: 'archive_channel',
46
+ description: 'Archive a channel',
47
+ params: [
48
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel to archive' },
49
+ ],
50
+ },
51
+ {
52
+ name: 'unarchive_channel',
53
+ description: 'Unarchive a channel',
54
+ params: [
55
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel to unarchive' },
56
+ ],
57
+ },
58
+ {
59
+ name: 'rename_channel',
60
+ description: 'Rename a channel',
61
+ params: [
62
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel' },
63
+ { name: 'name', type: 'string', required: true, description: 'New name for the channel' },
64
+ ],
65
+ },
66
+ {
67
+ name: 'set_channel_topic',
68
+ description: 'Set the topic of a channel',
69
+ params: [
70
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel' },
71
+ { name: 'topic', type: 'string', required: true, description: 'The new topic (max 250 chars)' },
72
+ ],
73
+ },
74
+ {
75
+ name: 'set_channel_purpose',
76
+ description: 'Set the purpose of a channel',
77
+ params: [
78
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel' },
79
+ { name: 'purpose', type: 'string', required: true, description: 'The new purpose (max 250 chars)' },
80
+ ],
81
+ },
82
+ {
83
+ name: 'join_channel',
84
+ description: 'Join a public channel',
85
+ params: [
86
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel to join' },
87
+ ],
88
+ },
89
+ {
90
+ name: 'leave_channel',
91
+ description: 'Leave a channel',
92
+ params: [
93
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel to leave' },
94
+ ],
95
+ },
96
+ {
97
+ name: 'invite_to_channel',
98
+ description: 'Invite users to a channel',
99
+ params: [
100
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel' },
101
+ { name: 'user_ids', type: 'array', required: true, description: 'Array of user IDs to invite' },
102
+ ],
103
+ },
104
+ {
105
+ name: 'kick_from_channel',
106
+ description: 'Remove a user from a channel',
107
+ params: [
108
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel' },
109
+ { name: 'user_id', type: 'string', required: true, description: 'The ID of the user to remove' },
110
+ ],
111
+ },
112
+ {
113
+ name: 'get_channel_members',
114
+ description: 'Get members of a channel',
115
+ params: [
116
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel' },
117
+ { name: 'limit', type: 'number', required: false, description: 'Maximum members to return (default 100, max 1000)' },
118
+ { name: 'cursor', type: 'string', required: false, description: 'Pagination cursor' },
119
+ ],
120
+ },
121
+ // --------------------------------------------------------------------------
122
+ // DIRECT MESSAGES
123
+ // --------------------------------------------------------------------------
124
+ {
125
+ name: 'open_dm',
126
+ description: 'Open a direct message channel with a user (or get existing DM channel)',
127
+ params: [
128
+ { name: 'user_id', type: 'string', required: false, description: 'User ID to open DM with (for 1:1 DM)' },
129
+ { name: 'user_ids', type: 'array', required: false, description: 'Array of user IDs for group DM (2-8 users)' },
130
+ { name: 'return_im', type: 'boolean', required: false, description: 'Return the full IM object (default: false)' },
131
+ ],
132
+ },
133
+ {
134
+ name: 'post_dm',
135
+ description: 'Send a direct message to a user',
136
+ params: [
137
+ { name: 'user_id', type: 'string', required: true, description: 'The ID of the user to message' },
138
+ { name: 'text', type: 'string', required: true, description: 'The message text' },
139
+ { name: 'blocks', type: 'array', required: false, description: 'Block Kit blocks for rich formatting' },
140
+ ],
141
+ },
142
+ // --------------------------------------------------------------------------
143
+ // MESSAGES
144
+ // --------------------------------------------------------------------------
145
+ {
146
+ name: 'post_message',
147
+ description: 'Post a new message to a Slack channel',
148
+ params: [
149
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel to post to' },
150
+ { name: 'text', type: 'string', required: true, description: 'The message text to post' },
151
+ { name: 'blocks', type: 'array', required: false, description: 'Block Kit blocks for rich formatting' },
152
+ { name: 'attachments', type: 'array', required: false, description: 'Secondary attachments' },
153
+ { name: 'unfurl_links', type: 'boolean', required: false, description: 'Enable link unfurling (default: true)' },
154
+ { name: 'unfurl_media', type: 'boolean', required: false, description: 'Enable media unfurling (default: true)' },
155
+ { name: 'mrkdwn', type: 'boolean', required: false, description: 'Enable markdown parsing (default: true)' },
156
+ ],
157
+ },
158
+ {
159
+ name: 'reply_to_thread',
160
+ description: 'Reply to a specific message thread in Slack',
161
+ params: [
162
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel containing the thread' },
163
+ { name: 'thread_ts', type: 'string', required: true, description: "The timestamp of the parent message (format: '1234567890.123456')" },
164
+ { name: 'text', type: 'string', required: true, description: 'The reply text' },
165
+ { name: 'blocks', type: 'array', required: false, description: 'Block Kit blocks for rich formatting' },
166
+ { name: 'broadcast', type: 'boolean', required: false, description: 'Also post to channel (default: false)' },
167
+ ],
168
+ },
169
+ {
170
+ name: 'update_message',
171
+ description: 'Update an existing message',
172
+ params: [
173
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel' },
174
+ { name: 'ts', type: 'string', required: true, description: 'Timestamp of the message to update' },
175
+ { name: 'text', type: 'string', required: true, description: 'New message text' },
176
+ { name: 'blocks', type: 'array', required: false, description: 'Block Kit blocks for rich formatting' },
177
+ { name: 'attachments', type: 'array', required: false, description: 'Secondary attachments' },
178
+ ],
179
+ },
180
+ {
181
+ name: 'delete_message',
182
+ description: 'Delete a message',
183
+ params: [
184
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel' },
185
+ { name: 'ts', type: 'string', required: true, description: 'Timestamp of the message to delete' },
186
+ ],
187
+ },
188
+ {
189
+ name: 'get_channel_history',
190
+ description: 'Get recent messages from a channel',
191
+ params: [
192
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel' },
193
+ { name: 'limit', type: 'number', required: false, description: 'Number of messages to retrieve (default 100, max 1000)' },
194
+ { name: 'cursor', type: 'string', required: false, description: 'Pagination cursor' },
195
+ { name: 'oldest', type: 'string', required: false, description: 'Start of time range (Unix timestamp)' },
196
+ { name: 'latest', type: 'string', required: false, description: 'End of time range (Unix timestamp)' },
197
+ { name: 'inclusive', type: 'boolean', required: false, description: 'Include messages with oldest/latest timestamps' },
198
+ ],
199
+ },
200
+ {
201
+ name: 'get_thread_replies',
202
+ description: 'Get all replies in a message thread',
203
+ params: [
204
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel containing the thread' },
205
+ { name: 'thread_ts', type: 'string', required: true, description: "The timestamp of the parent message (format: '1234567890.123456')" },
206
+ { name: 'limit', type: 'number', required: false, description: 'Number of replies to retrieve (default 100, max 1000)' },
207
+ { name: 'cursor', type: 'string', required: false, description: 'Pagination cursor' },
208
+ ],
209
+ },
210
+ {
211
+ name: 'get_permalink',
212
+ description: 'Get a permalink URL for a message',
213
+ params: [
214
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel' },
215
+ { name: 'message_ts', type: 'string', required: true, description: 'Timestamp of the message' },
216
+ ],
217
+ },
218
+ // --------------------------------------------------------------------------
219
+ // SCHEDULED MESSAGES
220
+ // --------------------------------------------------------------------------
221
+ {
222
+ name: 'schedule_message',
223
+ description: 'Schedule a message to be sent at a future time',
224
+ params: [
225
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel' },
226
+ { name: 'text', type: 'string', required: true, description: 'The message text' },
227
+ { name: 'post_at', type: 'number', required: true, description: 'Unix timestamp for when to send (must be in future)' },
228
+ { name: 'blocks', type: 'array', required: false, description: 'Block Kit blocks for rich formatting' },
229
+ { name: 'thread_ts', type: 'string', required: false, description: 'Thread timestamp to reply to' },
230
+ ],
231
+ },
232
+ {
233
+ name: 'list_scheduled_messages',
234
+ description: 'List scheduled messages',
235
+ params: [
236
+ { name: 'channel_id', type: 'string', required: false, description: 'Filter by channel ID' },
237
+ { name: 'limit', type: 'number', required: false, description: 'Maximum number to return (default 100, max 100)' },
238
+ { name: 'cursor', type: 'string', required: false, description: 'Pagination cursor' },
239
+ ],
240
+ },
241
+ {
242
+ name: 'delete_scheduled_message',
243
+ description: 'Delete a scheduled message before it is sent',
244
+ params: [
245
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel' },
246
+ { name: 'scheduled_message_id', type: 'string', required: true, description: 'ID of the scheduled message to delete' },
247
+ ],
248
+ },
249
+ // --------------------------------------------------------------------------
250
+ // REACTIONS
251
+ // --------------------------------------------------------------------------
252
+ {
253
+ name: 'add_reaction',
254
+ description: 'Add a reaction emoji to a message',
255
+ params: [
256
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel containing the message' },
257
+ { name: 'timestamp', type: 'string', required: true, description: 'The timestamp of the message to react to' },
258
+ { name: 'reaction', type: 'string', required: true, description: 'The name of the emoji reaction (without ::)' },
259
+ ],
260
+ },
261
+ {
262
+ name: 'remove_reaction',
263
+ description: 'Remove a reaction from a message',
264
+ params: [
265
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel' },
266
+ { name: 'timestamp', type: 'string', required: true, description: 'The timestamp of the message' },
267
+ { name: 'reaction', type: 'string', required: true, description: 'The name of the emoji reaction to remove' },
268
+ ],
269
+ },
270
+ {
271
+ name: 'get_reactions',
272
+ description: 'Get reactions for a specific message',
273
+ params: [
274
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel' },
275
+ { name: 'timestamp', type: 'string', required: true, description: 'The timestamp of the message' },
276
+ { name: 'full', type: 'boolean', required: false, description: 'Include full user info for each reaction' },
277
+ ],
278
+ },
279
+ {
280
+ name: 'list_reactions',
281
+ description: 'List items the calling user has reacted to',
282
+ params: [
283
+ { name: 'user_id', type: 'string', required: false, description: 'User ID to show reactions for (default: calling user)' },
284
+ { name: 'limit', type: 'number', required: false, description: 'Maximum items to return (default 100, max 100)' },
285
+ { name: 'cursor', type: 'string', required: false, description: 'Pagination cursor' },
286
+ ],
287
+ },
288
+ // --------------------------------------------------------------------------
289
+ // PINS
290
+ // --------------------------------------------------------------------------
291
+ {
292
+ name: 'pin_message',
293
+ description: 'Pin a message to a channel',
294
+ params: [
295
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel' },
296
+ { name: 'timestamp', type: 'string', required: true, description: 'The timestamp of the message to pin' },
297
+ ],
298
+ },
299
+ {
300
+ name: 'unpin_message',
301
+ description: 'Unpin a message from a channel',
302
+ params: [
303
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel' },
304
+ { name: 'timestamp', type: 'string', required: true, description: 'The timestamp of the message to unpin' },
305
+ ],
306
+ },
307
+ {
308
+ name: 'list_pins',
309
+ description: 'List pinned items in a channel',
310
+ params: [
311
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel' },
312
+ ],
313
+ },
314
+ // --------------------------------------------------------------------------
315
+ // BOOKMARKS
316
+ // --------------------------------------------------------------------------
317
+ {
318
+ name: 'add_bookmark',
319
+ description: 'Add a bookmark to a channel',
320
+ params: [
321
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel' },
322
+ { name: 'title', type: 'string', required: true, description: 'Title for the bookmark' },
323
+ { name: 'type', type: 'string', required: true, description: 'Type of bookmark: link' },
324
+ { name: 'link', type: 'string', required: false, description: 'URL for link bookmarks' },
325
+ { name: 'emoji', type: 'string', required: false, description: 'Emoji icon for the bookmark' },
326
+ ],
327
+ },
328
+ {
329
+ name: 'edit_bookmark',
330
+ description: 'Edit a bookmark',
331
+ params: [
332
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel' },
333
+ { name: 'bookmark_id', type: 'string', required: true, description: 'The ID of the bookmark to edit' },
334
+ { name: 'title', type: 'string', required: false, description: 'New title' },
335
+ { name: 'link', type: 'string', required: false, description: 'New URL' },
336
+ { name: 'emoji', type: 'string', required: false, description: 'New emoji icon' },
337
+ ],
338
+ },
339
+ {
340
+ name: 'remove_bookmark',
341
+ description: 'Remove a bookmark from a channel',
342
+ params: [
343
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel' },
344
+ { name: 'bookmark_id', type: 'string', required: true, description: 'The ID of the bookmark to remove' },
345
+ ],
346
+ },
347
+ {
348
+ name: 'list_bookmarks',
349
+ description: 'List bookmarks in a channel',
350
+ params: [
351
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel' },
352
+ ],
353
+ },
354
+ // --------------------------------------------------------------------------
355
+ // FILES
356
+ // --------------------------------------------------------------------------
357
+ {
358
+ name: 'upload_file',
359
+ description: 'Upload a file (PDF, PNG, image, document, etc.) to a Slack channel',
360
+ params: [
361
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel to upload to' },
362
+ { name: 'file_path', type: 'string', required: true, description: 'Absolute path to the file on disk' },
363
+ { name: 'title', type: 'string', required: false, description: 'Title for the file in Slack (defaults to filename)' },
364
+ { name: 'initial_comment', type: 'string', required: false, description: 'Message to include with the file' },
365
+ { name: 'thread_ts', type: 'string', required: false, description: 'Thread timestamp to reply with file (for threaded uploads)' },
366
+ ],
367
+ },
368
+ {
369
+ name: 'list_files',
370
+ description: 'List files shared in the workspace',
371
+ params: [
372
+ { name: 'channel_id', type: 'string', required: false, description: 'Filter by channel ID' },
373
+ { name: 'user_id', type: 'string', required: false, description: 'Filter by user ID' },
374
+ { name: 'types', type: 'string', required: false, description: 'File types: all, spaces, snippets, images, gdocs, zips, pdfs' },
375
+ { name: 'limit', type: 'number', required: false, description: 'Maximum files to return (default 100, max 100)' },
376
+ { name: 'cursor', type: 'string', required: false, description: 'Pagination cursor' },
377
+ ],
378
+ },
379
+ {
380
+ name: 'get_file_info',
381
+ description: 'Get information about a file',
382
+ params: [
383
+ { name: 'file_id', type: 'string', required: true, description: 'The ID of the file' },
384
+ ],
385
+ },
386
+ {
387
+ name: 'delete_file',
388
+ description: 'Delete a file',
389
+ params: [
390
+ { name: 'file_id', type: 'string', required: true, description: 'The ID of the file to delete' },
391
+ ],
392
+ },
393
+ {
394
+ name: 'share_file',
395
+ description: 'Share a file to a channel',
396
+ params: [
397
+ { name: 'file_id', type: 'string', required: true, description: 'The ID of the file' },
398
+ { name: 'channel_id', type: 'string', required: true, description: 'The ID of the channel to share to' },
399
+ ],
400
+ },
401
+ // --------------------------------------------------------------------------
402
+ // REMINDERS
403
+ // --------------------------------------------------------------------------
404
+ {
405
+ name: 'create_reminder',
406
+ description: 'Create a reminder',
407
+ params: [
408
+ { name: 'text', type: 'string', required: true, description: 'The reminder text' },
409
+ { name: 'time', type: 'string', required: true, description: 'When to remind: Unix timestamp, or natural language like "in 20 minutes", "tomorrow at 9am"' },
410
+ { name: 'user_id', type: 'string', required: false, description: 'User to remind (default: calling user)' },
411
+ ],
412
+ },
413
+ {
414
+ name: 'list_reminders',
415
+ description: 'List reminders for the calling user',
416
+ params: [],
417
+ },
418
+ {
419
+ name: 'delete_reminder',
420
+ description: 'Delete a reminder',
421
+ params: [
422
+ { name: 'reminder_id', type: 'string', required: true, description: 'The ID of the reminder to delete' },
423
+ ],
424
+ },
425
+ {
426
+ name: 'complete_reminder',
427
+ description: 'Mark a reminder as complete',
428
+ params: [
429
+ { name: 'reminder_id', type: 'string', required: true, description: 'The ID of the reminder to complete' },
430
+ ],
431
+ },
432
+ // --------------------------------------------------------------------------
433
+ // USERS
434
+ // --------------------------------------------------------------------------
435
+ {
436
+ name: 'get_users',
437
+ description: 'Get a list of all users in the workspace with their basic profile information',
438
+ params: [
439
+ { name: 'limit', type: 'number', required: false, description: 'Maximum number of users to return (default 100, max 200)' },
440
+ { name: 'cursor', type: 'string', required: false, description: 'Pagination cursor for next page of results' },
441
+ ],
442
+ },
443
+ {
444
+ name: 'get_user_profile',
445
+ description: 'Get detailed profile information for a specific user',
446
+ params: [
447
+ { name: 'user_id', type: 'string', required: true, description: 'The ID of the user' },
448
+ ],
449
+ },
450
+ {
451
+ name: 'get_user_by_email',
452
+ description: 'Find a user by their email address',
453
+ params: [
454
+ { name: 'email', type: 'string', required: true, description: 'Email address to look up' },
455
+ ],
456
+ },
457
+ {
458
+ name: 'get_user_presence',
459
+ description: 'Get a user\'s current presence status',
460
+ params: [
461
+ { name: 'user_id', type: 'string', required: true, description: 'The ID of the user' },
462
+ ],
463
+ },
464
+ {
465
+ name: 'set_user_presence',
466
+ description: 'Set the calling user\'s presence (auto or away)',
467
+ params: [
468
+ { name: 'presence', type: 'string', required: true, description: 'Presence status: auto or away' },
469
+ ],
470
+ },
471
+ // --------------------------------------------------------------------------
472
+ // USER GROUPS
473
+ // --------------------------------------------------------------------------
474
+ {
475
+ name: 'list_usergroups',
476
+ description: 'List user groups in the workspace',
477
+ params: [
478
+ { name: 'include_count', type: 'boolean', required: false, description: 'Include user counts (default: false)' },
479
+ { name: 'include_disabled', type: 'boolean', required: false, description: 'Include disabled groups (default: false)' },
480
+ { name: 'include_users', type: 'boolean', required: false, description: 'Include user lists (default: false)' },
481
+ ],
482
+ },
483
+ {
484
+ name: 'create_usergroup',
485
+ description: 'Create a user group',
486
+ params: [
487
+ { name: 'name', type: 'string', required: true, description: 'Name of the user group' },
488
+ { name: 'handle', type: 'string', required: false, description: 'Mention handle (without @)' },
489
+ { name: 'description', type: 'string', required: false, description: 'Description of the group' },
490
+ { name: 'channels', type: 'array', required: false, description: 'Default channels for the group' },
491
+ ],
492
+ },
493
+ {
494
+ name: 'update_usergroup',
495
+ description: 'Update a user group',
496
+ params: [
497
+ { name: 'usergroup_id', type: 'string', required: true, description: 'The ID of the user group' },
498
+ { name: 'name', type: 'string', required: false, description: 'New name' },
499
+ { name: 'handle', type: 'string', required: false, description: 'New mention handle' },
500
+ { name: 'description', type: 'string', required: false, description: 'New description' },
501
+ { name: 'channels', type: 'array', required: false, description: 'New default channels' },
502
+ ],
503
+ },
504
+ {
505
+ name: 'enable_usergroup',
506
+ description: 'Enable a disabled user group',
507
+ params: [
508
+ { name: 'usergroup_id', type: 'string', required: true, description: 'The ID of the user group' },
509
+ ],
510
+ },
511
+ {
512
+ name: 'disable_usergroup',
513
+ description: 'Disable a user group',
514
+ params: [
515
+ { name: 'usergroup_id', type: 'string', required: true, description: 'The ID of the user group' },
516
+ ],
517
+ },
518
+ {
519
+ name: 'list_usergroup_users',
520
+ description: 'List users in a user group',
521
+ params: [
522
+ { name: 'usergroup_id', type: 'string', required: true, description: 'The ID of the user group' },
523
+ { name: 'include_disabled', type: 'boolean', required: false, description: 'Include disabled users' },
524
+ ],
525
+ },
526
+ {
527
+ name: 'update_usergroup_users',
528
+ description: 'Update the members of a user group',
529
+ params: [
530
+ { name: 'usergroup_id', type: 'string', required: true, description: 'The ID of the user group' },
531
+ { name: 'user_ids', type: 'array', required: true, description: 'Array of user IDs to set as members' },
532
+ ],
533
+ },
534
+ // --------------------------------------------------------------------------
535
+ // STARS
536
+ // --------------------------------------------------------------------------
537
+ {
538
+ name: 'add_star',
539
+ description: 'Star an item (message, file, channel)',
540
+ params: [
541
+ { name: 'channel_id', type: 'string', required: false, description: 'Channel ID (for starring a channel or message)' },
542
+ { name: 'timestamp', type: 'string', required: false, description: 'Message timestamp (for starring a message)' },
543
+ { name: 'file_id', type: 'string', required: false, description: 'File ID (for starring a file)' },
544
+ ],
545
+ },
546
+ {
547
+ name: 'remove_star',
548
+ description: 'Remove a star from an item',
549
+ params: [
550
+ { name: 'channel_id', type: 'string', required: false, description: 'Channel ID' },
551
+ { name: 'timestamp', type: 'string', required: false, description: 'Message timestamp' },
552
+ { name: 'file_id', type: 'string', required: false, description: 'File ID' },
553
+ ],
554
+ },
555
+ {
556
+ name: 'list_stars',
557
+ description: 'List starred items for the calling user',
558
+ params: [
559
+ { name: 'limit', type: 'number', required: false, description: 'Maximum items to return (default 100, max 100)' },
560
+ { name: 'cursor', type: 'string', required: false, description: 'Pagination cursor' },
561
+ ],
562
+ },
563
+ // --------------------------------------------------------------------------
564
+ // EMOJI
565
+ // --------------------------------------------------------------------------
566
+ {
567
+ name: 'list_emoji',
568
+ description: 'List custom emoji in the workspace',
569
+ params: [
570
+ { name: 'include_categories', type: 'boolean', required: false, description: 'Include emoji categories' },
571
+ ],
572
+ },
573
+ // --------------------------------------------------------------------------
574
+ // TEAM / WORKSPACE
575
+ // --------------------------------------------------------------------------
576
+ {
577
+ name: 'get_team_info',
578
+ description: 'Get information about the workspace/team',
579
+ params: [],
580
+ },
581
+ // --------------------------------------------------------------------------
582
+ // SEARCH
583
+ // --------------------------------------------------------------------------
584
+ {
585
+ name: 'search_messages',
586
+ description: 'Search for messages in the workspace',
587
+ params: [
588
+ { name: 'query', type: 'string', required: true, description: 'Search query (supports Slack search modifiers)' },
589
+ { name: 'sort', type: 'string', required: false, description: 'Sort order: score or timestamp (default: score)' },
590
+ { name: 'sort_dir', type: 'string', required: false, description: 'Sort direction: asc or desc (default: desc)' },
591
+ { name: 'count', type: 'number', required: false, description: 'Number of results per page (default 20, max 100)' },
592
+ { name: 'page', type: 'number', required: false, description: 'Page number (default 1)' },
593
+ ],
594
+ },
595
+ {
596
+ name: 'search_files',
597
+ description: 'Search for files in the workspace',
598
+ params: [
599
+ { name: 'query', type: 'string', required: true, description: 'Search query (supports Slack search modifiers)' },
600
+ { name: 'sort', type: 'string', required: false, description: 'Sort order: score or timestamp (default: score)' },
601
+ { name: 'sort_dir', type: 'string', required: false, description: 'Sort direction: asc or desc (default: desc)' },
602
+ { name: 'count', type: 'number', required: false, description: 'Number of results per page (default 20, max 100)' },
603
+ { name: 'page', type: 'number', required: false, description: 'Page number (default 1)' },
604
+ ],
605
+ },
606
+ {
607
+ name: 'search_all',
608
+ description: 'Search for messages and files in the workspace',
609
+ params: [
610
+ { name: 'query', type: 'string', required: true, description: 'Search query (supports Slack search modifiers)' },
611
+ { name: 'sort', type: 'string', required: false, description: 'Sort order: score or timestamp (default: score)' },
612
+ { name: 'sort_dir', type: 'string', required: false, description: 'Sort direction: asc or desc (default: desc)' },
613
+ { name: 'count', type: 'number', required: false, description: 'Number of results per page (default 20, max 100)' },
614
+ { name: 'page', type: 'number', required: false, description: 'Page number (default 1)' },
615
+ ],
616
+ },
617
+ // --------------------------------------------------------------------------
618
+ // APP HOME / VIEWS
619
+ // --------------------------------------------------------------------------
620
+ {
621
+ name: 'publish_home_view',
622
+ description: 'Publish a view to a user\'s App Home tab',
623
+ params: [
624
+ { name: 'user_id', type: 'string', required: true, description: 'User ID to publish to' },
625
+ { name: 'view', type: 'object', required: true, description: 'View payload with type: home and blocks array' },
626
+ ],
627
+ },
628
+ // --------------------------------------------------------------------------
629
+ // DO NOT DISTURB
630
+ // --------------------------------------------------------------------------
631
+ {
632
+ name: 'get_dnd_info',
633
+ description: 'Get Do Not Disturb settings for a user',
634
+ params: [
635
+ { name: 'user_id', type: 'string', required: false, description: 'User ID (default: calling user)' },
636
+ ],
637
+ },
638
+ {
639
+ name: 'set_snooze',
640
+ description: 'Turn on Do Not Disturb for the calling user',
641
+ params: [
642
+ { name: 'num_minutes', type: 'number', required: true, description: 'Number of minutes to snooze' },
643
+ ],
644
+ },
645
+ {
646
+ name: 'end_snooze',
647
+ description: 'End Do Not Disturb for the calling user',
648
+ params: [],
649
+ },
650
+ {
651
+ name: 'end_dnd',
652
+ description: 'End the current DND session immediately',
653
+ params: [],
654
+ },
655
+ ];
656
+ // ============================================================================
657
+ // ACTION IMPLEMENTATIONS
658
+ // ============================================================================
659
+ // --------------------------------------------------------------------------
660
+ // CONVERSATIONS / CHANNELS
661
+ // --------------------------------------------------------------------------
662
+ async function listChannels(params) {
663
+ const { limit = 100, cursor, types = 'public_channel', exclude_archived = false } = params;
664
+ const queryParams = {
665
+ limit: Math.min(Number(limit) || 100, 1000),
666
+ types: String(types),
667
+ exclude_archived: Boolean(exclude_archived),
668
+ };
669
+ if (cursor)
670
+ queryParams.cursor = cursor;
671
+ const response = await axios.get(`${BASE_URL}/conversations.list`, {
672
+ headers: headers(),
673
+ params: queryParams,
674
+ });
675
+ return response.data;
676
+ }
677
+ async function getChannelInfo(params) {
678
+ const { channel_id, include_num_members = false } = params;
679
+ if (!channel_id)
680
+ throw new Error('channel_id is required');
681
+ const response = await axios.get(`${BASE_URL}/conversations.info`, {
682
+ headers: headers(),
683
+ params: {
684
+ channel: channel_id,
685
+ include_num_members: Boolean(include_num_members),
686
+ },
687
+ });
688
+ return response.data;
689
+ }
690
+ async function createChannel(params) {
691
+ const { name, is_private = false, description } = params;
692
+ if (!name)
693
+ throw new Error('name is required');
694
+ const payload = {
695
+ name: String(name),
696
+ is_private: Boolean(is_private),
697
+ };
698
+ const response = await axios.post(`${BASE_URL}/conversations.create`, payload, { headers: headers() });
699
+ // Set description/purpose if provided
700
+ if (response.data.ok && description && response.data.channel?.id) {
701
+ await axios.post(`${BASE_URL}/conversations.setPurpose`, {
702
+ channel: response.data.channel.id,
703
+ purpose: String(description),
704
+ }, { headers: headers() });
705
+ }
706
+ return response.data;
707
+ }
708
+ async function archiveChannel(params) {
709
+ const { channel_id } = params;
710
+ if (!channel_id)
711
+ throw new Error('channel_id is required');
712
+ const response = await axios.post(`${BASE_URL}/conversations.archive`, {
713
+ channel: channel_id,
714
+ }, { headers: headers() });
715
+ return response.data;
716
+ }
717
+ async function unarchiveChannel(params) {
718
+ const { channel_id } = params;
719
+ if (!channel_id)
720
+ throw new Error('channel_id is required');
721
+ const response = await axios.post(`${BASE_URL}/conversations.unarchive`, {
722
+ channel: channel_id,
723
+ }, { headers: headers() });
724
+ return response.data;
725
+ }
726
+ async function renameChannel(params) {
727
+ const { channel_id, name } = params;
728
+ if (!channel_id || !name)
729
+ throw new Error('channel_id and name are required');
730
+ const response = await axios.post(`${BASE_URL}/conversations.rename`, {
731
+ channel: channel_id,
732
+ name: String(name),
733
+ }, { headers: headers() });
734
+ return response.data;
735
+ }
736
+ async function setChannelTopic(params) {
737
+ const { channel_id, topic } = params;
738
+ if (!channel_id || topic === undefined)
739
+ throw new Error('channel_id and topic are required');
740
+ const response = await axios.post(`${BASE_URL}/conversations.setTopic`, {
741
+ channel: channel_id,
742
+ topic: String(topic),
743
+ }, { headers: headers() });
744
+ return response.data;
745
+ }
746
+ async function setChannelPurpose(params) {
747
+ const { channel_id, purpose } = params;
748
+ if (!channel_id || purpose === undefined)
749
+ throw new Error('channel_id and purpose are required');
750
+ const response = await axios.post(`${BASE_URL}/conversations.setPurpose`, {
751
+ channel: channel_id,
752
+ purpose: String(purpose),
753
+ }, { headers: headers() });
754
+ return response.data;
755
+ }
756
+ async function joinChannel(params) {
757
+ const { channel_id } = params;
758
+ if (!channel_id)
759
+ throw new Error('channel_id is required');
760
+ const response = await axios.post(`${BASE_URL}/conversations.join`, {
761
+ channel: channel_id,
762
+ }, { headers: headers() });
763
+ return response.data;
764
+ }
765
+ async function leaveChannel(params) {
766
+ const { channel_id } = params;
767
+ if (!channel_id)
768
+ throw new Error('channel_id is required');
769
+ const response = await axios.post(`${BASE_URL}/conversations.leave`, {
770
+ channel: channel_id,
771
+ }, { headers: headers() });
772
+ return response.data;
773
+ }
774
+ async function inviteToChannel(params) {
775
+ const { channel_id, user_ids } = params;
776
+ if (!channel_id || !user_ids)
777
+ throw new Error('channel_id and user_ids are required');
778
+ const users = Array.isArray(user_ids) ? user_ids.join(',') : String(user_ids);
779
+ const response = await axios.post(`${BASE_URL}/conversations.invite`, {
780
+ channel: channel_id,
781
+ users,
782
+ }, { headers: headers() });
783
+ return response.data;
784
+ }
785
+ async function kickFromChannel(params) {
786
+ const { channel_id, user_id } = params;
787
+ if (!channel_id || !user_id)
788
+ throw new Error('channel_id and user_id are required');
789
+ const response = await axios.post(`${BASE_URL}/conversations.kick`, {
790
+ channel: channel_id,
791
+ user: user_id,
792
+ }, { headers: headers() });
793
+ return response.data;
794
+ }
795
+ async function getChannelMembers(params) {
796
+ const { channel_id, limit = 100, cursor } = params;
797
+ if (!channel_id)
798
+ throw new Error('channel_id is required');
799
+ const queryParams = {
800
+ channel: channel_id,
801
+ limit: Math.min(Number(limit) || 100, 1000),
802
+ };
803
+ if (cursor)
804
+ queryParams.cursor = cursor;
805
+ const response = await axios.get(`${BASE_URL}/conversations.members`, {
806
+ headers: headers(),
807
+ params: queryParams,
808
+ });
809
+ return response.data;
810
+ }
811
+ // --------------------------------------------------------------------------
812
+ // DIRECT MESSAGES
813
+ // --------------------------------------------------------------------------
814
+ async function openDm(params) {
815
+ const { user_id, user_ids, return_im = false } = params;
816
+ const payload = {
817
+ return_im: Boolean(return_im),
818
+ };
819
+ if (user_ids && Array.isArray(user_ids)) {
820
+ payload.users = user_ids.join(',');
821
+ }
822
+ else if (user_id) {
823
+ payload.users = String(user_id);
824
+ }
825
+ else {
826
+ throw new Error('user_id or user_ids is required');
827
+ }
828
+ const response = await axios.post(`${BASE_URL}/conversations.open`, payload, { headers: headers() });
829
+ return response.data;
830
+ }
831
+ async function postDm(params) {
832
+ const { user_id, text, blocks } = params;
833
+ if (!user_id || !text)
834
+ throw new Error('user_id and text are required');
835
+ // First open/get the DM channel
836
+ const openResponse = await axios.post(`${BASE_URL}/conversations.open`, {
837
+ users: String(user_id),
838
+ }, { headers: headers() });
839
+ if (!openResponse.data.ok) {
840
+ throw new Error(`Failed to open DM: ${openResponse.data.error}`);
841
+ }
842
+ const channelId = openResponse.data.channel.id;
843
+ // Then post the message
844
+ const payload = {
845
+ channel: channelId,
846
+ text: String(text),
847
+ };
848
+ if (blocks)
849
+ payload.blocks = blocks;
850
+ const response = await axios.post(`${BASE_URL}/chat.postMessage`, payload, { headers: headers() });
851
+ return response.data;
852
+ }
853
+ // --------------------------------------------------------------------------
854
+ // MESSAGES
855
+ // --------------------------------------------------------------------------
856
+ async function postMessage(params) {
857
+ const { channel_id, text, blocks, attachments, unfurl_links, unfurl_media, mrkdwn } = params;
858
+ if (!channel_id || !text)
859
+ throw new Error('channel_id and text are required');
860
+ const payload = {
861
+ channel: channel_id,
862
+ text: String(text),
863
+ };
864
+ if (blocks)
865
+ payload.blocks = blocks;
866
+ if (attachments)
867
+ payload.attachments = attachments;
868
+ if (unfurl_links !== undefined)
869
+ payload.unfurl_links = Boolean(unfurl_links);
870
+ if (unfurl_media !== undefined)
871
+ payload.unfurl_media = Boolean(unfurl_media);
872
+ if (mrkdwn !== undefined)
873
+ payload.mrkdwn = Boolean(mrkdwn);
874
+ const response = await axios.post(`${BASE_URL}/chat.postMessage`, payload, { headers: headers() });
875
+ return response.data;
876
+ }
877
+ async function replyToThread(params) {
878
+ const { channel_id, thread_ts, text, blocks, broadcast = false } = params;
879
+ if (!channel_id || !thread_ts || !text)
880
+ throw new Error('channel_id, thread_ts, and text are required');
881
+ const payload = {
882
+ channel: channel_id,
883
+ thread_ts: String(thread_ts),
884
+ text: String(text),
885
+ reply_broadcast: Boolean(broadcast),
886
+ };
887
+ if (blocks)
888
+ payload.blocks = blocks;
889
+ const response = await axios.post(`${BASE_URL}/chat.postMessage`, payload, { headers: headers() });
890
+ return response.data;
891
+ }
892
+ async function updateMessage(params) {
893
+ const { channel_id, ts, text, blocks, attachments } = params;
894
+ if (!channel_id || !ts || !text)
895
+ throw new Error('channel_id, ts, and text are required');
896
+ const payload = {
897
+ channel: channel_id,
898
+ ts: String(ts),
899
+ text: String(text),
900
+ };
901
+ if (blocks)
902
+ payload.blocks = blocks;
903
+ if (attachments)
904
+ payload.attachments = attachments;
905
+ const response = await axios.post(`${BASE_URL}/chat.update`, payload, { headers: headers() });
906
+ return response.data;
907
+ }
908
+ async function deleteMessage(params) {
909
+ const { channel_id, ts } = params;
910
+ if (!channel_id || !ts)
911
+ throw new Error('channel_id and ts are required');
912
+ const response = await axios.post(`${BASE_URL}/chat.delete`, {
913
+ channel: channel_id,
914
+ ts: String(ts),
915
+ }, { headers: headers() });
916
+ return response.data;
917
+ }
918
+ async function getChannelHistory(params) {
919
+ const { channel_id, limit = 100, cursor, oldest, latest, inclusive } = params;
920
+ if (!channel_id)
921
+ throw new Error('channel_id is required');
922
+ const queryParams = {
923
+ channel: channel_id,
924
+ limit: Math.min(Number(limit) || 100, 1000),
925
+ };
926
+ if (cursor)
927
+ queryParams.cursor = cursor;
928
+ if (oldest)
929
+ queryParams.oldest = String(oldest);
930
+ if (latest)
931
+ queryParams.latest = String(latest);
932
+ if (inclusive !== undefined)
933
+ queryParams.inclusive = Boolean(inclusive);
934
+ const response = await axios.get(`${BASE_URL}/conversations.history`, {
935
+ headers: headers(),
936
+ params: queryParams,
937
+ });
938
+ return response.data;
939
+ }
940
+ async function getThreadReplies(params) {
941
+ const { channel_id, thread_ts, limit = 100, cursor } = params;
942
+ if (!channel_id || !thread_ts)
943
+ throw new Error('channel_id and thread_ts are required');
944
+ const queryParams = {
945
+ channel: channel_id,
946
+ ts: thread_ts,
947
+ limit: Math.min(Number(limit) || 100, 1000),
948
+ };
949
+ if (cursor)
950
+ queryParams.cursor = cursor;
951
+ const response = await axios.get(`${BASE_URL}/conversations.replies`, {
952
+ headers: headers(),
953
+ params: queryParams,
954
+ });
955
+ return response.data;
956
+ }
957
+ async function getPermalink(params) {
958
+ const { channel_id, message_ts } = params;
959
+ if (!channel_id || !message_ts)
960
+ throw new Error('channel_id and message_ts are required');
961
+ const response = await axios.get(`${BASE_URL}/chat.getPermalink`, {
962
+ headers: headers(),
963
+ params: {
964
+ channel: channel_id,
965
+ message_ts: String(message_ts),
966
+ },
967
+ });
968
+ return response.data;
969
+ }
970
+ // --------------------------------------------------------------------------
971
+ // SCHEDULED MESSAGES
972
+ // --------------------------------------------------------------------------
973
+ async function scheduleMessage(params) {
974
+ const { channel_id, text, post_at, blocks, thread_ts } = params;
975
+ if (!channel_id || !text || !post_at)
976
+ throw new Error('channel_id, text, and post_at are required');
977
+ const payload = {
978
+ channel: channel_id,
979
+ text: String(text),
980
+ post_at: Number(post_at),
981
+ };
982
+ if (blocks)
983
+ payload.blocks = blocks;
984
+ if (thread_ts)
985
+ payload.thread_ts = String(thread_ts);
986
+ const response = await axios.post(`${BASE_URL}/chat.scheduleMessage`, payload, { headers: headers() });
987
+ return response.data;
988
+ }
989
+ async function listScheduledMessages(params) {
990
+ const { channel_id, limit = 100, cursor } = params;
991
+ const queryParams = {
992
+ limit: Math.min(Number(limit) || 100, 100),
993
+ };
994
+ if (channel_id)
995
+ queryParams.channel = channel_id;
996
+ if (cursor)
997
+ queryParams.cursor = cursor;
998
+ const response = await axios.post(`${BASE_URL}/chat.scheduledMessages.list`, queryParams, { headers: headers() });
999
+ return response.data;
1000
+ }
1001
+ async function deleteScheduledMessage(params) {
1002
+ const { channel_id, scheduled_message_id } = params;
1003
+ if (!channel_id || !scheduled_message_id)
1004
+ throw new Error('channel_id and scheduled_message_id are required');
1005
+ const response = await axios.post(`${BASE_URL}/chat.deleteScheduledMessage`, {
1006
+ channel: channel_id,
1007
+ scheduled_message_id: String(scheduled_message_id),
1008
+ }, { headers: headers() });
1009
+ return response.data;
1010
+ }
1011
+ // --------------------------------------------------------------------------
1012
+ // REACTIONS
1013
+ // --------------------------------------------------------------------------
1014
+ async function addReaction(params) {
1015
+ const { channel_id, timestamp, reaction } = params;
1016
+ if (!channel_id || !timestamp || !reaction)
1017
+ throw new Error('channel_id, timestamp, and reaction are required');
1018
+ const response = await axios.post(`${BASE_URL}/reactions.add`, {
1019
+ channel: channel_id,
1020
+ timestamp: String(timestamp),
1021
+ name: String(reaction),
1022
+ }, { headers: headers() });
1023
+ return response.data;
1024
+ }
1025
+ async function removeReaction(params) {
1026
+ const { channel_id, timestamp, reaction } = params;
1027
+ if (!channel_id || !timestamp || !reaction)
1028
+ throw new Error('channel_id, timestamp, and reaction are required');
1029
+ const response = await axios.post(`${BASE_URL}/reactions.remove`, {
1030
+ channel: channel_id,
1031
+ timestamp: String(timestamp),
1032
+ name: String(reaction),
1033
+ }, { headers: headers() });
1034
+ return response.data;
1035
+ }
1036
+ async function getReactions(params) {
1037
+ const { channel_id, timestamp, full = false } = params;
1038
+ if (!channel_id || !timestamp)
1039
+ throw new Error('channel_id and timestamp are required');
1040
+ const response = await axios.get(`${BASE_URL}/reactions.get`, {
1041
+ headers: headers(),
1042
+ params: {
1043
+ channel: channel_id,
1044
+ timestamp: String(timestamp),
1045
+ full: Boolean(full),
1046
+ },
1047
+ });
1048
+ return response.data;
1049
+ }
1050
+ async function listReactions(params) {
1051
+ const { user_id, limit = 100, cursor } = params;
1052
+ const queryParams = {
1053
+ count: Math.min(Number(limit) || 100, 100),
1054
+ };
1055
+ if (user_id)
1056
+ queryParams.user = user_id;
1057
+ if (cursor)
1058
+ queryParams.cursor = cursor;
1059
+ const response = await axios.get(`${BASE_URL}/reactions.list`, {
1060
+ headers: headers(),
1061
+ params: queryParams,
1062
+ });
1063
+ return response.data;
1064
+ }
1065
+ // --------------------------------------------------------------------------
1066
+ // PINS
1067
+ // --------------------------------------------------------------------------
1068
+ async function pinMessage(params) {
1069
+ const { channel_id, timestamp } = params;
1070
+ if (!channel_id || !timestamp)
1071
+ throw new Error('channel_id and timestamp are required');
1072
+ const response = await axios.post(`${BASE_URL}/pins.add`, {
1073
+ channel: channel_id,
1074
+ timestamp: String(timestamp),
1075
+ }, { headers: headers() });
1076
+ return response.data;
1077
+ }
1078
+ async function unpinMessage(params) {
1079
+ const { channel_id, timestamp } = params;
1080
+ if (!channel_id || !timestamp)
1081
+ throw new Error('channel_id and timestamp are required');
1082
+ const response = await axios.post(`${BASE_URL}/pins.remove`, {
1083
+ channel: channel_id,
1084
+ timestamp: String(timestamp),
1085
+ }, { headers: headers() });
1086
+ return response.data;
1087
+ }
1088
+ async function listPins(params) {
1089
+ const { channel_id } = params;
1090
+ if (!channel_id)
1091
+ throw new Error('channel_id is required');
1092
+ const response = await axios.get(`${BASE_URL}/pins.list`, {
1093
+ headers: headers(),
1094
+ params: { channel: channel_id },
1095
+ });
1096
+ return response.data;
1097
+ }
1098
+ // --------------------------------------------------------------------------
1099
+ // BOOKMARKS
1100
+ // --------------------------------------------------------------------------
1101
+ async function addBookmark(params) {
1102
+ const { channel_id, title, type, link, emoji } = params;
1103
+ if (!channel_id || !title || !type)
1104
+ throw new Error('channel_id, title, and type are required');
1105
+ const payload = {
1106
+ channel_id: String(channel_id),
1107
+ title: String(title),
1108
+ type: String(type),
1109
+ };
1110
+ if (link)
1111
+ payload.link = String(link);
1112
+ if (emoji)
1113
+ payload.emoji = String(emoji);
1114
+ const response = await axios.post(`${BASE_URL}/bookmarks.add`, payload, { headers: headers() });
1115
+ return response.data;
1116
+ }
1117
+ async function editBookmark(params) {
1118
+ const { channel_id, bookmark_id, title, link, emoji } = params;
1119
+ if (!channel_id || !bookmark_id)
1120
+ throw new Error('channel_id and bookmark_id are required');
1121
+ const payload = {
1122
+ channel_id: String(channel_id),
1123
+ bookmark_id: String(bookmark_id),
1124
+ };
1125
+ if (title)
1126
+ payload.title = String(title);
1127
+ if (link)
1128
+ payload.link = String(link);
1129
+ if (emoji)
1130
+ payload.emoji = String(emoji);
1131
+ const response = await axios.post(`${BASE_URL}/bookmarks.edit`, payload, { headers: headers() });
1132
+ return response.data;
1133
+ }
1134
+ async function removeBookmark(params) {
1135
+ const { channel_id, bookmark_id } = params;
1136
+ if (!channel_id || !bookmark_id)
1137
+ throw new Error('channel_id and bookmark_id are required');
1138
+ const response = await axios.post(`${BASE_URL}/bookmarks.remove`, {
1139
+ channel_id: String(channel_id),
1140
+ bookmark_id: String(bookmark_id),
1141
+ }, { headers: headers() });
1142
+ return response.data;
1143
+ }
1144
+ async function listBookmarks(params) {
1145
+ const { channel_id } = params;
1146
+ if (!channel_id)
1147
+ throw new Error('channel_id is required');
1148
+ const response = await axios.get(`${BASE_URL}/bookmarks.list`, {
1149
+ headers: headers(),
1150
+ params: { channel_id },
1151
+ });
1152
+ return response.data;
1153
+ }
1154
+ // --------------------------------------------------------------------------
1155
+ // FILES
1156
+ // --------------------------------------------------------------------------
1157
+ async function uploadFile(params) {
1158
+ const { channel_id, file_path, title, initial_comment, thread_ts } = params;
1159
+ if (!channel_id || !file_path)
1160
+ throw new Error('channel_id and file_path are required');
1161
+ const filePath = String(file_path);
1162
+ if (!fs.existsSync(filePath))
1163
+ throw new Error(`File not found: ${filePath}`);
1164
+ const stats = fs.statSync(filePath);
1165
+ if (stats.size === 0)
1166
+ throw new Error('File is empty');
1167
+ const filename = path.basename(filePath);
1168
+ const fileSize = stats.size;
1169
+ // Step 1: Get upload URL
1170
+ const uploadUrlResponse = await axios.get(`${BASE_URL}/files.getUploadURLExternal`, {
1171
+ headers: headers(),
1172
+ params: { filename, length: fileSize },
1173
+ });
1174
+ if (!uploadUrlResponse.data.ok) {
1175
+ throw new Error(`Slack API error (getUploadURLExternal): ${uploadUrlResponse.data.error}`);
1176
+ }
1177
+ const { upload_url, file_id } = uploadUrlResponse.data;
1178
+ // Step 2: Upload file content
1179
+ const fileContent = fs.readFileSync(filePath);
1180
+ await axios.post(upload_url, fileContent, {
1181
+ headers: { 'Content-Type': 'application/octet-stream' },
1182
+ maxContentLength: Infinity,
1183
+ maxBodyLength: Infinity,
1184
+ });
1185
+ // Step 3: Complete the upload
1186
+ const fileTitle = title ? String(title) : filename;
1187
+ const completePayload = {
1188
+ files: [{ id: file_id, title: fileTitle }],
1189
+ channel_id: String(channel_id),
1190
+ };
1191
+ if (initial_comment)
1192
+ completePayload.initial_comment = String(initial_comment);
1193
+ if (thread_ts)
1194
+ completePayload.thread_ts = String(thread_ts);
1195
+ const completeResponse = await axios.post(`${BASE_URL}/files.completeUploadExternal`, completePayload, { headers: headers() });
1196
+ if (!completeResponse.data.ok) {
1197
+ throw new Error(`Slack API error (completeUploadExternal): ${completeResponse.data.error}`);
1198
+ }
1199
+ const uploadedFile = completeResponse.data.files?.[0];
1200
+ return {
1201
+ ok: true,
1202
+ file: {
1203
+ id: uploadedFile?.id || file_id,
1204
+ name: uploadedFile?.name || filename,
1205
+ title: uploadedFile?.title || fileTitle,
1206
+ mimetype: uploadedFile?.mimetype,
1207
+ size: fileSize,
1208
+ url_private: uploadedFile?.url_private,
1209
+ permalink: uploadedFile?.permalink,
1210
+ },
1211
+ channel: channel_id,
1212
+ thread_ts: thread_ts || null,
1213
+ };
1214
+ }
1215
+ async function listFiles(params) {
1216
+ const { channel_id, user_id, types, limit = 100, cursor } = params;
1217
+ const queryParams = {
1218
+ count: Math.min(Number(limit) || 100, 100),
1219
+ };
1220
+ if (channel_id)
1221
+ queryParams.channel = channel_id;
1222
+ if (user_id)
1223
+ queryParams.user = user_id;
1224
+ if (types)
1225
+ queryParams.types = String(types);
1226
+ if (cursor)
1227
+ queryParams.cursor = cursor;
1228
+ const response = await axios.get(`${BASE_URL}/files.list`, {
1229
+ headers: headers(),
1230
+ params: queryParams,
1231
+ });
1232
+ return response.data;
1233
+ }
1234
+ async function getFileInfo(params) {
1235
+ const { file_id } = params;
1236
+ if (!file_id)
1237
+ throw new Error('file_id is required');
1238
+ const response = await axios.get(`${BASE_URL}/files.info`, {
1239
+ headers: headers(),
1240
+ params: { file: file_id },
1241
+ });
1242
+ return response.data;
1243
+ }
1244
+ async function deleteFile(params) {
1245
+ const { file_id } = params;
1246
+ if (!file_id)
1247
+ throw new Error('file_id is required');
1248
+ const response = await axios.post(`${BASE_URL}/files.delete`, {
1249
+ file: file_id,
1250
+ }, { headers: headers() });
1251
+ return response.data;
1252
+ }
1253
+ async function shareFile(params) {
1254
+ const { file_id, channel_id } = params;
1255
+ if (!file_id || !channel_id)
1256
+ throw new Error('file_id and channel_id are required');
1257
+ const response = await axios.post(`${BASE_URL}/files.sharedPublicURL`, {
1258
+ file: file_id,
1259
+ }, { headers: headers() });
1260
+ // Also share to channel
1261
+ if (response.data.ok) {
1262
+ // Use chat.postMessage with the file
1263
+ await axios.post(`${BASE_URL}/chat.postMessage`, {
1264
+ channel: channel_id,
1265
+ text: `<${response.data.file?.permalink_public || ''}>`,
1266
+ }, { headers: headers() });
1267
+ }
1268
+ return response.data;
1269
+ }
1270
+ // --------------------------------------------------------------------------
1271
+ // REMINDERS
1272
+ // --------------------------------------------------------------------------
1273
+ async function createReminder(params) {
1274
+ const { text, time, user_id } = params;
1275
+ if (!text || !time)
1276
+ throw new Error('text and time are required');
1277
+ const payload = {
1278
+ text: String(text),
1279
+ time: String(time),
1280
+ };
1281
+ if (user_id)
1282
+ payload.user = String(user_id);
1283
+ const response = await axios.post(`${BASE_URL}/reminders.add`, payload, { headers: headers() });
1284
+ return response.data;
1285
+ }
1286
+ async function listReminders() {
1287
+ const response = await axios.get(`${BASE_URL}/reminders.list`, { headers: headers() });
1288
+ return response.data;
1289
+ }
1290
+ async function deleteReminder(params) {
1291
+ const { reminder_id } = params;
1292
+ if (!reminder_id)
1293
+ throw new Error('reminder_id is required');
1294
+ const response = await axios.post(`${BASE_URL}/reminders.delete`, {
1295
+ reminder: reminder_id,
1296
+ }, { headers: headers() });
1297
+ return response.data;
1298
+ }
1299
+ async function completeReminder(params) {
1300
+ const { reminder_id } = params;
1301
+ if (!reminder_id)
1302
+ throw new Error('reminder_id is required');
1303
+ const response = await axios.post(`${BASE_URL}/reminders.complete`, {
1304
+ reminder: reminder_id,
1305
+ }, { headers: headers() });
1306
+ return response.data;
1307
+ }
1308
+ // --------------------------------------------------------------------------
1309
+ // USERS
1310
+ // --------------------------------------------------------------------------
1311
+ async function getUsers(params) {
1312
+ const { limit = 100, cursor } = params;
1313
+ const queryParams = {
1314
+ limit: Math.min(Number(limit) || 100, 200),
1315
+ };
1316
+ if (cursor)
1317
+ queryParams.cursor = cursor;
1318
+ const response = await axios.get(`${BASE_URL}/users.list`, {
1319
+ headers: headers(),
1320
+ params: queryParams,
1321
+ });
1322
+ return response.data;
1323
+ }
1324
+ async function getUserProfile(params) {
1325
+ const { user_id } = params;
1326
+ if (!user_id)
1327
+ throw new Error('user_id is required');
1328
+ const response = await axios.get(`${BASE_URL}/users.profile.get`, {
1329
+ headers: headers(),
1330
+ params: { user: user_id },
1331
+ });
1332
+ return response.data;
1333
+ }
1334
+ async function getUserByEmail(params) {
1335
+ const { email } = params;
1336
+ if (!email)
1337
+ throw new Error('email is required');
1338
+ const response = await axios.get(`${BASE_URL}/users.lookupByEmail`, {
1339
+ headers: headers(),
1340
+ params: { email: String(email) },
1341
+ });
1342
+ return response.data;
1343
+ }
1344
+ async function getUserPresence(params) {
1345
+ const { user_id } = params;
1346
+ if (!user_id)
1347
+ throw new Error('user_id is required');
1348
+ const response = await axios.get(`${BASE_URL}/users.getPresence`, {
1349
+ headers: headers(),
1350
+ params: { user: user_id },
1351
+ });
1352
+ return response.data;
1353
+ }
1354
+ async function setUserPresence(params) {
1355
+ const { presence } = params;
1356
+ if (!presence)
1357
+ throw new Error('presence is required (auto or away)');
1358
+ const response = await axios.post(`${BASE_URL}/users.setPresence`, {
1359
+ presence: String(presence),
1360
+ }, { headers: headers() });
1361
+ return response.data;
1362
+ }
1363
+ // --------------------------------------------------------------------------
1364
+ // USER GROUPS
1365
+ // --------------------------------------------------------------------------
1366
+ async function listUsergroups(params) {
1367
+ const { include_count = false, include_disabled = false, include_users = false } = params;
1368
+ const response = await axios.get(`${BASE_URL}/usergroups.list`, {
1369
+ headers: headers(),
1370
+ params: {
1371
+ include_count: Boolean(include_count),
1372
+ include_disabled: Boolean(include_disabled),
1373
+ include_users: Boolean(include_users),
1374
+ },
1375
+ });
1376
+ return response.data;
1377
+ }
1378
+ async function createUsergroup(params) {
1379
+ const { name, handle, description, channels } = params;
1380
+ if (!name)
1381
+ throw new Error('name is required');
1382
+ const payload = { name: String(name) };
1383
+ if (handle)
1384
+ payload.handle = String(handle);
1385
+ if (description)
1386
+ payload.description = String(description);
1387
+ if (channels && Array.isArray(channels))
1388
+ payload.channels = channels.join(',');
1389
+ const response = await axios.post(`${BASE_URL}/usergroups.create`, payload, { headers: headers() });
1390
+ return response.data;
1391
+ }
1392
+ async function updateUsergroup(params) {
1393
+ const { usergroup_id, name, handle, description, channels } = params;
1394
+ if (!usergroup_id)
1395
+ throw new Error('usergroup_id is required');
1396
+ const payload = { usergroup: usergroup_id };
1397
+ if (name)
1398
+ payload.name = String(name);
1399
+ if (handle)
1400
+ payload.handle = String(handle);
1401
+ if (description)
1402
+ payload.description = String(description);
1403
+ if (channels && Array.isArray(channels))
1404
+ payload.channels = channels.join(',');
1405
+ const response = await axios.post(`${BASE_URL}/usergroups.update`, payload, { headers: headers() });
1406
+ return response.data;
1407
+ }
1408
+ async function enableUsergroup(params) {
1409
+ const { usergroup_id } = params;
1410
+ if (!usergroup_id)
1411
+ throw new Error('usergroup_id is required');
1412
+ const response = await axios.post(`${BASE_URL}/usergroups.enable`, {
1413
+ usergroup: usergroup_id,
1414
+ }, { headers: headers() });
1415
+ return response.data;
1416
+ }
1417
+ async function disableUsergroup(params) {
1418
+ const { usergroup_id } = params;
1419
+ if (!usergroup_id)
1420
+ throw new Error('usergroup_id is required');
1421
+ const response = await axios.post(`${BASE_URL}/usergroups.disable`, {
1422
+ usergroup: usergroup_id,
1423
+ }, { headers: headers() });
1424
+ return response.data;
1425
+ }
1426
+ async function listUsergroupUsers(params) {
1427
+ const { usergroup_id, include_disabled = false } = params;
1428
+ if (!usergroup_id)
1429
+ throw new Error('usergroup_id is required');
1430
+ const response = await axios.get(`${BASE_URL}/usergroups.users.list`, {
1431
+ headers: headers(),
1432
+ params: {
1433
+ usergroup: usergroup_id,
1434
+ include_disabled: Boolean(include_disabled),
1435
+ },
1436
+ });
1437
+ return response.data;
1438
+ }
1439
+ async function updateUsergroupUsers(params) {
1440
+ const { usergroup_id, user_ids } = params;
1441
+ if (!usergroup_id || !user_ids)
1442
+ throw new Error('usergroup_id and user_ids are required');
1443
+ const users = Array.isArray(user_ids) ? user_ids.join(',') : String(user_ids);
1444
+ const response = await axios.post(`${BASE_URL}/usergroups.users.update`, {
1445
+ usergroup: usergroup_id,
1446
+ users,
1447
+ }, { headers: headers() });
1448
+ return response.data;
1449
+ }
1450
+ // --------------------------------------------------------------------------
1451
+ // STARS
1452
+ // --------------------------------------------------------------------------
1453
+ async function addStar(params) {
1454
+ const { channel_id, timestamp, file_id } = params;
1455
+ if (!channel_id && !file_id)
1456
+ throw new Error('channel_id or file_id is required');
1457
+ const payload = {};
1458
+ if (channel_id)
1459
+ payload.channel = channel_id;
1460
+ if (timestamp)
1461
+ payload.timestamp = String(timestamp);
1462
+ if (file_id)
1463
+ payload.file = file_id;
1464
+ const response = await axios.post(`${BASE_URL}/stars.add`, payload, { headers: headers() });
1465
+ return response.data;
1466
+ }
1467
+ async function removeStar(params) {
1468
+ const { channel_id, timestamp, file_id } = params;
1469
+ if (!channel_id && !file_id)
1470
+ throw new Error('channel_id or file_id is required');
1471
+ const payload = {};
1472
+ if (channel_id)
1473
+ payload.channel = channel_id;
1474
+ if (timestamp)
1475
+ payload.timestamp = String(timestamp);
1476
+ if (file_id)
1477
+ payload.file = file_id;
1478
+ const response = await axios.post(`${BASE_URL}/stars.remove`, payload, { headers: headers() });
1479
+ return response.data;
1480
+ }
1481
+ async function listStars(params) {
1482
+ const { limit = 100, cursor } = params;
1483
+ const queryParams = {
1484
+ count: Math.min(Number(limit) || 100, 100),
1485
+ };
1486
+ if (cursor)
1487
+ queryParams.cursor = cursor;
1488
+ const response = await axios.get(`${BASE_URL}/stars.list`, {
1489
+ headers: headers(),
1490
+ params: queryParams,
1491
+ });
1492
+ return response.data;
1493
+ }
1494
+ // --------------------------------------------------------------------------
1495
+ // EMOJI
1496
+ // --------------------------------------------------------------------------
1497
+ async function listEmoji(params) {
1498
+ const { include_categories = false } = params;
1499
+ const response = await axios.get(`${BASE_URL}/emoji.list`, {
1500
+ headers: headers(),
1501
+ params: { include_categories: Boolean(include_categories) },
1502
+ });
1503
+ return response.data;
1504
+ }
1505
+ // --------------------------------------------------------------------------
1506
+ // TEAM / WORKSPACE
1507
+ // --------------------------------------------------------------------------
1508
+ async function getTeamInfo() {
1509
+ const response = await axios.get(`${BASE_URL}/team.info`, { headers: headers() });
1510
+ return response.data;
1511
+ }
1512
+ // --------------------------------------------------------------------------
1513
+ // SEARCH
1514
+ // --------------------------------------------------------------------------
1515
+ async function searchMessages(params) {
1516
+ const { query, sort = 'score', sort_dir = 'desc', count = 20, page = 1 } = params;
1517
+ if (!query)
1518
+ throw new Error('query is required');
1519
+ const response = await axios.get(`${BASE_URL}/search.messages`, {
1520
+ headers: headers(),
1521
+ params: {
1522
+ query: String(query),
1523
+ sort: String(sort),
1524
+ sort_dir: String(sort_dir),
1525
+ count: Math.min(Number(count) || 20, 100),
1526
+ page: Number(page) || 1,
1527
+ },
1528
+ });
1529
+ return response.data;
1530
+ }
1531
+ async function searchFiles(params) {
1532
+ const { query, sort = 'score', sort_dir = 'desc', count = 20, page = 1 } = params;
1533
+ if (!query)
1534
+ throw new Error('query is required');
1535
+ const response = await axios.get(`${BASE_URL}/search.files`, {
1536
+ headers: headers(),
1537
+ params: {
1538
+ query: String(query),
1539
+ sort: String(sort),
1540
+ sort_dir: String(sort_dir),
1541
+ count: Math.min(Number(count) || 20, 100),
1542
+ page: Number(page) || 1,
1543
+ },
1544
+ });
1545
+ return response.data;
1546
+ }
1547
+ async function searchAll(params) {
1548
+ const { query, sort = 'score', sort_dir = 'desc', count = 20, page = 1 } = params;
1549
+ if (!query)
1550
+ throw new Error('query is required');
1551
+ const response = await axios.get(`${BASE_URL}/search.all`, {
1552
+ headers: headers(),
1553
+ params: {
1554
+ query: String(query),
1555
+ sort: String(sort),
1556
+ sort_dir: String(sort_dir),
1557
+ count: Math.min(Number(count) || 20, 100),
1558
+ page: Number(page) || 1,
1559
+ },
1560
+ });
1561
+ return response.data;
1562
+ }
1563
+ // --------------------------------------------------------------------------
1564
+ // APP HOME / VIEWS
1565
+ // --------------------------------------------------------------------------
1566
+ async function publishHomeView(params) {
1567
+ const { user_id, view } = params;
1568
+ if (!user_id || !view)
1569
+ throw new Error('user_id and view are required');
1570
+ const response = await axios.post(`${BASE_URL}/views.publish`, {
1571
+ user_id: String(user_id),
1572
+ view,
1573
+ }, { headers: headers() });
1574
+ return response.data;
1575
+ }
1576
+ // --------------------------------------------------------------------------
1577
+ // DO NOT DISTURB
1578
+ // --------------------------------------------------------------------------
1579
+ async function getDndInfo(params) {
1580
+ const { user_id } = params;
1581
+ const queryParams = {};
1582
+ if (user_id)
1583
+ queryParams.user = user_id;
1584
+ const response = await axios.get(`${BASE_URL}/dnd.info`, {
1585
+ headers: headers(),
1586
+ params: queryParams,
1587
+ });
1588
+ return response.data;
1589
+ }
1590
+ async function setSnooze(params) {
1591
+ const { num_minutes } = params;
1592
+ if (!num_minutes)
1593
+ throw new Error('num_minutes is required');
1594
+ const response = await axios.post(`${BASE_URL}/dnd.setSnooze`, {
1595
+ num_minutes: Number(num_minutes),
1596
+ }, { headers: headers() });
1597
+ return response.data;
1598
+ }
1599
+ async function endSnooze() {
1600
+ const response = await axios.post(`${BASE_URL}/dnd.endSnooze`, {}, { headers: headers() });
1601
+ return response.data;
1602
+ }
1603
+ async function endDnd() {
1604
+ const response = await axios.post(`${BASE_URL}/dnd.endDnd`, {}, { headers: headers() });
1605
+ return response.data;
1606
+ }
1607
+ // ============================================================================
1608
+ // BACKEND EXPORT
1609
+ // ============================================================================
1610
+ export const slackBackend = {
1611
+ name: 'slack',
1612
+ description: 'Comprehensive Slack workspace integration: messaging, channels, DMs, files, reminders, search, user groups, reactions, pins, bookmarks, and more',
1613
+ actions,
1614
+ async execute(action, params) {
1615
+ switch (action) {
1616
+ // Conversations / Channels
1617
+ case 'list_channels': return listChannels(params);
1618
+ case 'get_channel_info': return getChannelInfo(params);
1619
+ case 'create_channel': return createChannel(params);
1620
+ case 'archive_channel': return archiveChannel(params);
1621
+ case 'unarchive_channel': return unarchiveChannel(params);
1622
+ case 'rename_channel': return renameChannel(params);
1623
+ case 'set_channel_topic': return setChannelTopic(params);
1624
+ case 'set_channel_purpose': return setChannelPurpose(params);
1625
+ case 'join_channel': return joinChannel(params);
1626
+ case 'leave_channel': return leaveChannel(params);
1627
+ case 'invite_to_channel': return inviteToChannel(params);
1628
+ case 'kick_from_channel': return kickFromChannel(params);
1629
+ case 'get_channel_members': return getChannelMembers(params);
1630
+ // Direct Messages
1631
+ case 'open_dm': return openDm(params);
1632
+ case 'post_dm': return postDm(params);
1633
+ // Messages
1634
+ case 'post_message': return postMessage(params);
1635
+ case 'reply_to_thread': return replyToThread(params);
1636
+ case 'update_message': return updateMessage(params);
1637
+ case 'delete_message': return deleteMessage(params);
1638
+ case 'get_channel_history': return getChannelHistory(params);
1639
+ case 'get_thread_replies': return getThreadReplies(params);
1640
+ case 'get_permalink': return getPermalink(params);
1641
+ // Scheduled Messages
1642
+ case 'schedule_message': return scheduleMessage(params);
1643
+ case 'list_scheduled_messages': return listScheduledMessages(params);
1644
+ case 'delete_scheduled_message': return deleteScheduledMessage(params);
1645
+ // Reactions
1646
+ case 'add_reaction': return addReaction(params);
1647
+ case 'remove_reaction': return removeReaction(params);
1648
+ case 'get_reactions': return getReactions(params);
1649
+ case 'list_reactions': return listReactions(params);
1650
+ // Pins
1651
+ case 'pin_message': return pinMessage(params);
1652
+ case 'unpin_message': return unpinMessage(params);
1653
+ case 'list_pins': return listPins(params);
1654
+ // Bookmarks
1655
+ case 'add_bookmark': return addBookmark(params);
1656
+ case 'edit_bookmark': return editBookmark(params);
1657
+ case 'remove_bookmark': return removeBookmark(params);
1658
+ case 'list_bookmarks': return listBookmarks(params);
1659
+ // Files
1660
+ case 'upload_file': return uploadFile(params);
1661
+ case 'list_files': return listFiles(params);
1662
+ case 'get_file_info': return getFileInfo(params);
1663
+ case 'delete_file': return deleteFile(params);
1664
+ case 'share_file': return shareFile(params);
1665
+ // Reminders
1666
+ case 'create_reminder': return createReminder(params);
1667
+ case 'list_reminders': return listReminders();
1668
+ case 'delete_reminder': return deleteReminder(params);
1669
+ case 'complete_reminder': return completeReminder(params);
1670
+ // Users
1671
+ case 'get_users': return getUsers(params);
1672
+ case 'get_user_profile': return getUserProfile(params);
1673
+ case 'get_user_by_email': return getUserByEmail(params);
1674
+ case 'get_user_presence': return getUserPresence(params);
1675
+ case 'set_user_presence': return setUserPresence(params);
1676
+ // User Groups
1677
+ case 'list_usergroups': return listUsergroups(params);
1678
+ case 'create_usergroup': return createUsergroup(params);
1679
+ case 'update_usergroup': return updateUsergroup(params);
1680
+ case 'enable_usergroup': return enableUsergroup(params);
1681
+ case 'disable_usergroup': return disableUsergroup(params);
1682
+ case 'list_usergroup_users': return listUsergroupUsers(params);
1683
+ case 'update_usergroup_users': return updateUsergroupUsers(params);
1684
+ // Stars
1685
+ case 'add_star': return addStar(params);
1686
+ case 'remove_star': return removeStar(params);
1687
+ case 'list_stars': return listStars(params);
1688
+ // Emoji
1689
+ case 'list_emoji': return listEmoji(params);
1690
+ // Team / Workspace
1691
+ case 'get_team_info': return getTeamInfo();
1692
+ // Search
1693
+ case 'search_messages': return searchMessages(params);
1694
+ case 'search_files': return searchFiles(params);
1695
+ case 'search_all': return searchAll(params);
1696
+ // App Home / Views
1697
+ case 'publish_home_view': return publishHomeView(params);
1698
+ // Do Not Disturb
1699
+ case 'get_dnd_info': return getDndInfo(params);
1700
+ case 'set_snooze': return setSnooze(params);
1701
+ case 'end_snooze': return endSnooze();
1702
+ case 'end_dnd': return endDnd();
1703
+ default:
1704
+ throw new Error(`Unknown action: ${action}`);
1705
+ }
1706
+ },
1707
+ async healthCheck() {
1708
+ if (!SLACK_BOT_TOKEN) {
1709
+ return { status: 'unavailable', latency_ms: 0, error: 'SLACK_BOT_TOKEN not configured' };
1710
+ }
1711
+ try {
1712
+ const start = Date.now();
1713
+ const response = await axios.post(`${BASE_URL}/auth.test`, {}, { headers: headers() });
1714
+ const latency = Date.now() - start;
1715
+ if (response.data.ok) {
1716
+ return { status: 'healthy', latency_ms: latency };
1717
+ }
1718
+ return { status: 'unavailable', latency_ms: latency, error: response.data.error };
1719
+ }
1720
+ catch (error) {
1721
+ return { status: 'unavailable', latency_ms: 0, error: error instanceof Error ? error.message : String(error) };
1722
+ }
1723
+ },
1724
+ };
1725
+ //# sourceMappingURL=slack.js.map