@zhin.js/adapter-slack 4.0.1 → 4.1.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 (118) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +207 -98
  3. package/{skills/slack/SKILL.md → agent/skills/slack.md} +2 -0
  4. package/agent/tools/add_reaction.ts +26 -0
  5. package/agent/tools/archive_channel.ts +24 -0
  6. package/agent/tools/edit_message.ts +27 -0
  7. package/agent/tools/invite_to_channel.ts +26 -0
  8. package/agent/tools/pin_message.ts +26 -0
  9. package/agent/tools/remove_reaction.ts +26 -0
  10. package/agent/tools/set_purpose.ts +26 -0
  11. package/agent/tools/set_topic.ts +26 -0
  12. package/agent/tools/unarchive.ts +24 -0
  13. package/agent/tools/unpin_message.ts +26 -0
  14. package/agent/tools/user_info.ts +31 -0
  15. package/lib/agent/tools/add_reaction.js +21 -0
  16. package/lib/agent/tools/add_reaction.js.map +1 -0
  17. package/lib/agent/tools/archive_channel.js +21 -0
  18. package/lib/agent/tools/archive_channel.js.map +1 -0
  19. package/lib/agent/tools/edit_message.js +22 -0
  20. package/lib/agent/tools/edit_message.js.map +1 -0
  21. package/lib/agent/tools/invite_to_channel.js +22 -0
  22. package/lib/agent/tools/invite_to_channel.js.map +1 -0
  23. package/lib/agent/tools/pin_message.js +22 -0
  24. package/lib/agent/tools/pin_message.js.map +1 -0
  25. package/lib/agent/tools/remove_reaction.js +21 -0
  26. package/lib/agent/tools/remove_reaction.js.map +1 -0
  27. package/lib/agent/tools/set_purpose.js +22 -0
  28. package/lib/agent/tools/set_purpose.js.map +1 -0
  29. package/lib/agent/tools/set_topic.js +22 -0
  30. package/lib/agent/tools/set_topic.js.map +1 -0
  31. package/lib/agent/tools/unarchive.js +21 -0
  32. package/lib/agent/tools/unarchive.js.map +1 -0
  33. package/lib/agent/tools/unpin_message.js +22 -0
  34. package/lib/agent/tools/unpin_message.js.map +1 -0
  35. package/lib/agent/tools/user_info.js +28 -0
  36. package/lib/agent/tools/user_info.js.map +1 -0
  37. package/lib/{adapter.js → src/adapter.js} +19 -3
  38. package/lib/src/adapter.js.map +1 -0
  39. package/lib/src/endpoint.js +312 -0
  40. package/lib/src/endpoint.js.map +1 -0
  41. package/lib/src/event-dispatcher.js +233 -0
  42. package/lib/src/event-dispatcher.js.map +1 -0
  43. package/lib/src/index.js +51 -0
  44. package/lib/src/index.js.map +1 -0
  45. package/lib/src/markdown-to-mrkdwn.js +61 -0
  46. package/lib/src/markdown-to-mrkdwn.js.map +1 -0
  47. package/lib/src/mrkdwn-to-markdown.js +31 -0
  48. package/lib/src/mrkdwn-to-markdown.js.map +1 -0
  49. package/lib/{platform-permit.js → src/platform-permit.js} +3 -0
  50. package/lib/src/platform-permit.js.map +1 -0
  51. package/lib/src/segment-mapper.js.map +1 -0
  52. package/lib/src/signing.js +21 -0
  53. package/lib/src/signing.js.map +1 -0
  54. package/lib/src/slack-agent-deps.js +10 -0
  55. package/lib/src/slack-agent-deps.js.map +1 -0
  56. package/lib/src/slack-inbound-filter.js +47 -0
  57. package/lib/src/slack-inbound-filter.js.map +1 -0
  58. package/lib/src/slack-inbound.js +127 -0
  59. package/lib/src/slack-inbound.js.map +1 -0
  60. package/lib/src/slack-message-ref.js +18 -0
  61. package/lib/src/slack-message-ref.js.map +1 -0
  62. package/lib/src/slack-outbound.js +223 -0
  63. package/lib/src/slack-outbound.js.map +1 -0
  64. package/lib/src/slack-reaction.js +27 -0
  65. package/lib/src/slack-reaction.js.map +1 -0
  66. package/lib/src/slack-response-url.js +17 -0
  67. package/lib/src/slack-response-url.js.map +1 -0
  68. package/lib/src/slack-side-events.js +64 -0
  69. package/lib/src/slack-side-events.js.map +1 -0
  70. package/lib/src/transport-http.js +83 -0
  71. package/lib/src/transport-http.js.map +1 -0
  72. package/lib/src/transport-socket.js +68 -0
  73. package/lib/src/transport-socket.js.map +1 -0
  74. package/lib/src/types.js +5 -0
  75. package/lib/src/types.js.map +1 -0
  76. package/package.json +24 -6
  77. package/src/adapter.ts +28 -7
  78. package/src/endpoint.ts +206 -604
  79. package/src/event-dispatcher.ts +255 -0
  80. package/src/index.ts +31 -239
  81. package/src/markdown-to-mrkdwn.ts +58 -0
  82. package/src/mrkdwn-to-markdown.ts +29 -0
  83. package/src/platform-permit.ts +1 -2
  84. package/src/signing.ts +28 -0
  85. package/src/slack-agent-deps.ts +22 -0
  86. package/src/slack-inbound-filter.ts +60 -0
  87. package/src/slack-inbound.ts +140 -0
  88. package/src/slack-message-ref.ts +18 -0
  89. package/src/slack-outbound.ts +269 -0
  90. package/src/slack-reaction.ts +23 -0
  91. package/src/slack-response-url.ts +26 -0
  92. package/src/slack-side-events.ts +74 -0
  93. package/src/transport-http.ts +95 -0
  94. package/src/transport-socket.ts +77 -0
  95. package/src/types.ts +99 -4
  96. package/lib/adapter.d.ts +0 -19
  97. package/lib/adapter.d.ts.map +0 -1
  98. package/lib/adapter.js.map +0 -1
  99. package/lib/endpoint.d.ts +0 -108
  100. package/lib/endpoint.d.ts.map +0 -1
  101. package/lib/endpoint.js +0 -677
  102. package/lib/endpoint.js.map +0 -1
  103. package/lib/index.d.ts +0 -10
  104. package/lib/index.d.ts.map +0 -1
  105. package/lib/index.js +0 -252
  106. package/lib/index.js.map +0 -1
  107. package/lib/platform-permit.d.ts +0 -17
  108. package/lib/platform-permit.d.ts.map +0 -1
  109. package/lib/platform-permit.js.map +0 -1
  110. package/lib/segment-mapper.d.ts +0 -2
  111. package/lib/segment-mapper.d.ts.map +0 -1
  112. package/lib/segment-mapper.js.map +0 -1
  113. package/lib/types.d.ts +0 -17
  114. package/lib/types.d.ts.map +0 -1
  115. package/lib/types.js +0 -2
  116. package/lib/types.js.map +0 -1
  117. /package/{skills/slack → agent}/PERMITS.md +0 -0
  118. /package/lib/{segment-mapper.js → src/segment-mapper.js} +0 -0
package/lib/endpoint.js DELETED
@@ -1,677 +0,0 @@
1
- /**
2
- * Slack Endpoint 实现
3
- */
4
- import { App as SlackApp, LogLevel } from "@slack/bolt";
5
- import { WebClient } from "@slack/web-api";
6
- import { formatCompact, Message, segment, expandInteractiveSegmentsInContent, } from 'zhin.js';
7
- import { normalizeSlackSenderForPermit } from "./platform-permit.js";
8
- import { fromCanonicalSegments, toCanonicalSegments } from './segment-mapper.js';
9
- export class SlackEndpoint {
10
- adapter;
11
- $config;
12
- $connected;
13
- /** 延迟到 `$connect`,避免子类 mock `$connect` 时仍在构造函数里创建 Bolt/WebClient(会在后台触发 Slack API) */
14
- app;
15
- client;
16
- get logger() {
17
- return this.adapter.plugin.logger;
18
- }
19
- get $id() {
20
- return this.$config.name;
21
- }
22
- constructor(adapter, $config) {
23
- this.adapter = adapter;
24
- this.$config = $config;
25
- this.$connected = false;
26
- }
27
- #ensureSlackRuntime() {
28
- if (this.app && this.client)
29
- return;
30
- const $config = this.$config;
31
- if ($config.socketMode && $config.appToken) {
32
- this.app = new SlackApp({
33
- token: $config.token,
34
- signingSecret: $config.signingSecret,
35
- appToken: $config.appToken,
36
- socketMode: true,
37
- logLevel: $config.logLevel || LogLevel.INFO,
38
- });
39
- }
40
- else {
41
- this.app = new SlackApp({
42
- token: $config.token,
43
- signingSecret: $config.signingSecret,
44
- socketMode: false,
45
- logLevel: $config.logLevel || LogLevel.INFO,
46
- });
47
- }
48
- this.client = new WebClient($config.token);
49
- }
50
- async $connect() {
51
- this.#ensureSlackRuntime();
52
- try {
53
- // Set up message event handler
54
- this.app.message(async ({ message, say }) => {
55
- await this.handleSlackMessage(message);
56
- });
57
- // Set up app mention handler
58
- this.app.event("app_mention", async ({ event, say }) => {
59
- await this.handleSlackMessage(event);
60
- });
61
- // Start the app
62
- const port = this.$config.port || 3000;
63
- if (this.$config.socketMode) {
64
- await this.app.start();
65
- }
66
- else {
67
- await this.app.start(port);
68
- }
69
- this.$connected = true;
70
- // Get bot info
71
- const authTest = await this.client.auth.test();
72
- this.logger.info(formatCompact({ endpoint: this.$config.name, user: authTest.user }));
73
- if (!this.$config.socketMode) {
74
- this.logger.info(formatCompact({ op: "listen", port }));
75
- }
76
- }
77
- catch (error) {
78
- this.logger.error("Failed to connect Slack bot:", error);
79
- this.$connected = false;
80
- throw error;
81
- }
82
- }
83
- async $disconnect() {
84
- if (!this.app) {
85
- this.$connected = false;
86
- return;
87
- }
88
- try {
89
- await this.app.stop();
90
- this.$connected = false;
91
- this.logger.info(formatCompact({ op: "disconnect", endpoint: this.$config.name }));
92
- }
93
- catch (error) {
94
- this.logger.error("Error disconnecting Slack bot:", error);
95
- throw error;
96
- }
97
- }
98
- senderPermitCache = new Map();
99
- async enrichChannelSender(message, msg) {
100
- if (message.$channel.type !== "group" || !("user" in msg) || !msg.user)
101
- return;
102
- const channelId = msg.channel;
103
- const userId = msg.user;
104
- const key = `${channelId}:${userId}`;
105
- const now = Date.now();
106
- const cached = this.senderPermitCache.get(key);
107
- if (cached && now - cached.at < 60_000) {
108
- message.$sender.role = cached.role;
109
- message.$sender.permissions = cached.permissions;
110
- return;
111
- }
112
- try {
113
- const user = await this.getUserInfo(userId);
114
- let isChannelManager = false;
115
- try {
116
- const channel = await this.getChannelInfo(channelId);
117
- if (channel?.creator === userId)
118
- isChannelManager = true;
119
- }
120
- catch {
121
- // ignore
122
- }
123
- const normalized = normalizeSlackSenderForPermit({
124
- isWorkspaceOwner: user.is_owner === true,
125
- isWorkspaceAdmin: user.is_admin === true,
126
- isChannelManager,
127
- });
128
- const entry = {
129
- at: now,
130
- role: normalized.role,
131
- permissions: normalized.permissions ?? [],
132
- };
133
- this.senderPermitCache.set(key, entry);
134
- message.$sender.role = entry.role;
135
- message.$sender.permissions = entry.permissions;
136
- }
137
- catch {
138
- // 保守拒绝
139
- }
140
- }
141
- async handleSlackMessage(msg) {
142
- // Ignore bot messages and message changes
143
- if ("subtype" in msg && (msg.subtype === "bot_message" || msg.subtype === "message_changed")) {
144
- return;
145
- }
146
- const message = this.$formatMessage(msg);
147
- await this.enrichChannelSender(message, msg);
148
- this.adapter.emit("message.receive", message);
149
- this.logger.debug(`${this.$config.name} recv ${message.$channel.type}(${message.$channel.id}): ${segment.raw(message.$content)}`);
150
- }
151
- $formatMessage(msg) {
152
- // Determine channel type based on channel ID
153
- const channelType = "channel_type" in msg && msg.channel_type === "im" ? "private" : "group";
154
- const channelId = msg.channel;
155
- // Parse message content
156
- const wire = this.parseMessageContent(msg);
157
- const content = toCanonicalSegments(wire);
158
- // Extract user info safely
159
- const userId = ("user" in msg ? msg.user : "") || "";
160
- const userName = ("username" in msg ? msg.username : null) || userId || "Unknown";
161
- const messageText = ("text" in msg ? msg.text : "") || "";
162
- const result = Message.from(msg, {
163
- $id: msg.ts,
164
- $adapter: "slack",
165
- $endpoint: this.$config.name,
166
- $sender: {
167
- id: userId,
168
- name: userName,
169
- },
170
- $channel: {
171
- id: channelId,
172
- type: channelType,
173
- },
174
- $content: content,
175
- $raw: messageText,
176
- $timestamp: parseFloat(msg.ts) * 1000,
177
- $recall: async () => {
178
- try {
179
- await this.client.chat.delete({
180
- channel: channelId,
181
- ts: result.$id,
182
- });
183
- }
184
- catch (error) {
185
- this.logger.error("Error recalling Slack message:", error);
186
- throw error;
187
- }
188
- },
189
- $reply: async (content, quote) => {
190
- if (!Array.isArray(content))
191
- content = [content];
192
- const sendOptions = {
193
- channel: channelId,
194
- };
195
- // Handle thread reply
196
- if (quote) {
197
- const threadTs = typeof quote === "boolean" ? result.$id : quote;
198
- sendOptions.thread_ts = threadTs;
199
- }
200
- return await this.adapter.sendMessage({
201
- context: "slack",
202
- endpoint: this.$config.name,
203
- id: channelId,
204
- type: "channel",
205
- content: content,
206
- });
207
- },
208
- });
209
- return result;
210
- }
211
- parseMessageContent(msg) {
212
- const segments = [];
213
- // Handle text
214
- if ("text" in msg && msg.text) {
215
- // Parse Slack formatting
216
- segments.push(...this.parseSlackText(msg.text));
217
- }
218
- // Handle files
219
- if ("files" in msg && msg.files) {
220
- for (const file of msg.files) {
221
- if (file.mimetype?.startsWith("image/")) {
222
- segments.push({
223
- type: "image",
224
- data: {
225
- id: file.id,
226
- name: file.name,
227
- url: file.url_private || file.permalink,
228
- size: file.size,
229
- mimetype: file.mimetype,
230
- },
231
- });
232
- }
233
- else if (file.mimetype?.startsWith("video/")) {
234
- segments.push({
235
- type: "video",
236
- data: {
237
- id: file.id,
238
- name: file.name,
239
- url: file.url_private || file.permalink,
240
- size: file.size,
241
- mimetype: file.mimetype,
242
- },
243
- });
244
- }
245
- else if (file.mimetype?.startsWith("audio/")) {
246
- segments.push({
247
- type: "audio",
248
- data: {
249
- id: file.id,
250
- name: file.name,
251
- url: file.url_private || file.permalink,
252
- size: file.size,
253
- mimetype: file.mimetype,
254
- },
255
- });
256
- }
257
- else {
258
- segments.push({
259
- type: "file",
260
- data: {
261
- id: file.id,
262
- name: file.name,
263
- url: file.url_private || file.permalink,
264
- size: file.size,
265
- mimetype: file.mimetype,
266
- },
267
- });
268
- }
269
- }
270
- }
271
- // Handle attachments
272
- if ("attachments" in msg && msg.attachments) {
273
- for (const attachment of msg.attachments) {
274
- if (attachment.image_url) {
275
- segments.push({
276
- type: "image",
277
- data: {
278
- url: attachment.image_url,
279
- title: attachment.title,
280
- text: attachment.text,
281
- },
282
- });
283
- }
284
- }
285
- }
286
- return segments.length > 0
287
- ? segments
288
- : [{ type: "text", data: { text: "" } }];
289
- }
290
- parseSlackText(text) {
291
- const segments = [];
292
- let lastIndex = 0;
293
- // Match user mentions <@U12345678>
294
- const userMentionRegex = /<@([UW][A-Z0-9]+)(?:\|([^>]+))?>/g;
295
- // Match channel mentions <#C12345678|general>
296
- const channelMentionRegex = /<#([C][A-Z0-9]+)(?:\|([^>]+))?>/g;
297
- // Match links <http://example.com|Example>
298
- const linkRegex = /<(https?:\/\/[^|>]+)(?:\|([^>]+))?>/g;
299
- const allMatches = [];
300
- // Collect all matches
301
- let match;
302
- while ((match = userMentionRegex.exec(text)) !== null) {
303
- allMatches.push({ match, type: "user" });
304
- }
305
- while ((match = channelMentionRegex.exec(text)) !== null) {
306
- allMatches.push({ match, type: "channel" });
307
- }
308
- while ((match = linkRegex.exec(text)) !== null) {
309
- allMatches.push({ match, type: "link" });
310
- }
311
- // Sort by position
312
- allMatches.sort((a, b) => a.match.index - b.match.index);
313
- // Process matches
314
- for (const { match, type } of allMatches) {
315
- const matchStart = match.index;
316
- const matchEnd = matchStart + match[0].length;
317
- // Add text before match
318
- if (matchStart > lastIndex) {
319
- const beforeText = text.slice(lastIndex, matchStart);
320
- if (beforeText.trim()) {
321
- segments.push({ type: "text", data: { text: beforeText } });
322
- }
323
- }
324
- // Add special segment
325
- switch (type) {
326
- case "user":
327
- segments.push({
328
- type: "at",
329
- data: {
330
- id: match[1],
331
- name: match[2] || match[1],
332
- text: match[0],
333
- },
334
- });
335
- break;
336
- case "channel":
337
- segments.push({
338
- type: "channel_mention",
339
- data: {
340
- id: match[1],
341
- name: match[2] || match[1],
342
- text: match[0],
343
- },
344
- });
345
- break;
346
- case "link":
347
- segments.push({
348
- type: "link",
349
- data: {
350
- url: match[1],
351
- text: match[2] || match[1],
352
- },
353
- });
354
- break;
355
- }
356
- lastIndex = matchEnd;
357
- }
358
- // Add remaining text
359
- if (lastIndex < text.length) {
360
- const remainingText = text.slice(lastIndex);
361
- if (remainingText.trim()) {
362
- segments.push({ type: "text", data: { text: remainingText } });
363
- }
364
- }
365
- return segments.length > 0
366
- ? segments
367
- : [{ type: "text", data: { text } }];
368
- }
369
- async $sendMessage(options) {
370
- try {
371
- const canonical = expandInteractiveSegmentsInContent(options.content);
372
- const wire = fromCanonicalSegments(canonical);
373
- const result = await this.sendContentToChannel(options.id, wire);
374
- this.logger.debug(`${this.$config.name} send ${options.type}(${options.id}): ${segment.raw(options.content)}`);
375
- return result.ts || "";
376
- }
377
- catch (error) {
378
- this.logger.error("Failed to send Slack message:", error);
379
- throw error;
380
- }
381
- }
382
- async sendContentToChannel(channel, content, extraOptions = {}) {
383
- if (!Array.isArray(content))
384
- content = [content];
385
- let textContent = "";
386
- const attachments = [];
387
- for (const segment of content) {
388
- if (typeof segment === "string") {
389
- textContent += segment;
390
- continue;
391
- }
392
- const { type, data } = segment;
393
- switch (type) {
394
- case "text":
395
- textContent += data.text || "";
396
- break;
397
- case "at":
398
- textContent += `<@${data.id}>`;
399
- break;
400
- case "channel_mention":
401
- textContent += `<#${data.id}>`;
402
- break;
403
- case "link":
404
- if (data.text && data.text !== data.url) {
405
- textContent += `<${data.url}|${data.text}>`;
406
- }
407
- else {
408
- textContent += `<${data.url}>`;
409
- }
410
- break;
411
- case "image":
412
- if (data.url) {
413
- attachments.push({
414
- image_url: data.url,
415
- title: data.name || data.title,
416
- });
417
- }
418
- break;
419
- case "file":
420
- // Files need to be uploaded separately
421
- if (data.file) {
422
- try {
423
- await this.client.files.upload({
424
- channels: channel,
425
- file: data.file,
426
- filename: data.name,
427
- });
428
- }
429
- catch (error) {
430
- this.logger.error("Failed to upload file:", error);
431
- }
432
- }
433
- break;
434
- default:
435
- textContent += data.text || `[${type}]`;
436
- }
437
- }
438
- // Send message
439
- const messageOptions = {
440
- channel,
441
- text: textContent.trim() || "Message",
442
- ...extraOptions,
443
- };
444
- if (attachments.length > 0) {
445
- messageOptions.attachments = attachments;
446
- }
447
- const result = await this.client.chat.postMessage(messageOptions);
448
- return result.message || {};
449
- }
450
- async $recallMessage(id) {
451
- // Slack requires both channel and ts (timestamp) to delete a message
452
- // The Endpoint interface only provides message ID (ts), making recall impossible
453
- // Users should use message.$recall() instead, which has the full context
454
- throw new Error("SlackEndpoint.$recallMessage: Message recall not supported without channel information. " +
455
- "Use message.$recall() method instead, which contains the required context.");
456
- }
457
- // ==================== 工作区管理 API ====================
458
- /**
459
- * 邀请用户到频道
460
- * @param channel 频道 ID
461
- * @param users 用户 ID 列表
462
- */
463
- async inviteToChannel(channel, users) {
464
- try {
465
- await this.client.conversations.invite({ channel, users: users.join(',') });
466
- this.logger.debug(formatCompact({ op: "invite", endpoint: this.$id, channel, users: users.join(",") }));
467
- return true;
468
- }
469
- catch (error) {
470
- this.logger.error(`Slack Endpoint ${this.$id} 邀请用户失败:`, error);
471
- throw error;
472
- }
473
- }
474
- /**
475
- * 从频道踢出用户
476
- * @param channel 频道 ID
477
- * @param user 用户 ID
478
- */
479
- async kickFromChannel(channel, user) {
480
- try {
481
- await this.client.conversations.kick({ channel, user });
482
- this.logger.debug(formatCompact({ op: "kick", endpoint: this.$id, channel, user }));
483
- return true;
484
- }
485
- catch (error) {
486
- this.logger.error(`Slack Endpoint ${this.$id} 踢出用户失败:`, error);
487
- throw error;
488
- }
489
- }
490
- /**
491
- * 设置频道话题
492
- * @param channel 频道 ID
493
- * @param topic 话题
494
- */
495
- async setChannelTopic(channel, topic) {
496
- try {
497
- await this.client.conversations.setTopic({ channel, topic });
498
- this.logger.debug(formatCompact({ op: "set_topic", endpoint: this.$id, channel }));
499
- return true;
500
- }
501
- catch (error) {
502
- this.logger.error(`Slack Endpoint ${this.$id} 设置话题失败:`, error);
503
- throw error;
504
- }
505
- }
506
- /**
507
- * 设置频道目的
508
- * @param channel 频道 ID
509
- * @param purpose 目的
510
- */
511
- async setChannelPurpose(channel, purpose) {
512
- try {
513
- await this.client.conversations.setPurpose({ channel, purpose });
514
- this.logger.debug(formatCompact({ op: "set_purpose", endpoint: this.$id, channel }));
515
- return true;
516
- }
517
- catch (error) {
518
- this.logger.error(`Slack Endpoint ${this.$id} 设置目的失败:`, error);
519
- throw error;
520
- }
521
- }
522
- /**
523
- * 归档频道
524
- * @param channel 频道 ID
525
- */
526
- async archiveChannel(channel) {
527
- try {
528
- await this.client.conversations.archive({ channel });
529
- this.logger.debug(formatCompact({ op: "archive", endpoint: this.$id, channel }));
530
- return true;
531
- }
532
- catch (error) {
533
- this.logger.error(`Slack Endpoint ${this.$id} 归档频道失败:`, error);
534
- throw error;
535
- }
536
- }
537
- /**
538
- * 取消归档频道
539
- * @param channel 频道 ID
540
- */
541
- async unarchiveChannel(channel) {
542
- try {
543
- await this.client.conversations.unarchive({ channel });
544
- this.logger.debug(formatCompact({ op: "unarchive", endpoint: this.$id, channel }));
545
- return true;
546
- }
547
- catch (error) {
548
- this.logger.error(`Slack Endpoint ${this.$id} 取消归档失败:`, error);
549
- throw error;
550
- }
551
- }
552
- /**
553
- * 重命名频道
554
- * @param channel 频道 ID
555
- * @param name 新名称
556
- */
557
- async renameChannel(channel, name) {
558
- try {
559
- await this.client.conversations.rename({ channel, name });
560
- this.logger.debug(formatCompact({ op: "rename", endpoint: this.$id, channel, name }));
561
- return true;
562
- }
563
- catch (error) {
564
- this.logger.error(`Slack Endpoint ${this.$id} 重命名频道失败:`, error);
565
- throw error;
566
- }
567
- }
568
- /**
569
- * 获取频道成员列表
570
- * @param channel 频道 ID
571
- */
572
- async getChannelMembers(channel) {
573
- try {
574
- const result = await this.client.conversations.members({ channel });
575
- return result.members || [];
576
- }
577
- catch (error) {
578
- this.logger.error(`Slack Endpoint ${this.$id} 获取成员列表失败:`, error);
579
- throw error;
580
- }
581
- }
582
- /**
583
- * 获取频道信息
584
- * @param channel 频道 ID
585
- */
586
- async getChannelInfo(channel) {
587
- try {
588
- const result = await this.client.conversations.info({ channel });
589
- return result.channel;
590
- }
591
- catch (error) {
592
- this.logger.error(`Slack Endpoint ${this.$id} 获取频道信息失败:`, error);
593
- throw error;
594
- }
595
- }
596
- /**
597
- * 获取用户信息
598
- * @param user 用户 ID
599
- */
600
- async getUserInfo(user) {
601
- try {
602
- const result = await this.client.users.info({ user });
603
- return result.user;
604
- }
605
- catch (error) {
606
- this.logger.error(`Slack Endpoint ${this.$id} 获取用户信息失败:`, error);
607
- throw error;
608
- }
609
- }
610
- /**
611
- * 添加消息反应
612
- * @param channel 频道 ID
613
- * @param timestamp 消息时间戳
614
- * @param name 表情名称
615
- */
616
- async addReaction(channel, timestamp, name) {
617
- try {
618
- await this.client.reactions.add({ channel, timestamp, name });
619
- this.logger.debug(formatCompact({ op: "reaction_add", endpoint: this.$id, name }));
620
- return true;
621
- }
622
- catch (error) {
623
- this.logger.error(`Slack Endpoint ${this.$id} 添加反应失败:`, error);
624
- throw error;
625
- }
626
- }
627
- /**
628
- * 移除消息反应
629
- * @param channel 频道 ID
630
- * @param timestamp 消息时间戳
631
- * @param name 表情名称
632
- */
633
- async removeReaction(channel, timestamp, name) {
634
- try {
635
- await this.client.reactions.remove({ channel, timestamp, name });
636
- this.logger.debug(formatCompact({ op: "reaction_remove", endpoint: this.$id, name }));
637
- return true;
638
- }
639
- catch (error) {
640
- this.logger.error(`Slack Endpoint ${this.$id} 移除反应失败:`, error);
641
- throw error;
642
- }
643
- }
644
- /**
645
- * 置顶消息
646
- * @param channel 频道 ID
647
- * @param timestamp 消息时间戳
648
- */
649
- async pinMessage(channel, timestamp) {
650
- try {
651
- await this.client.pins.add({ channel, timestamp });
652
- this.logger.debug(formatCompact({ op: "pin", endpoint: this.$id, channel }));
653
- return true;
654
- }
655
- catch (error) {
656
- this.logger.error(`Slack Endpoint ${this.$id} 置顶消息失败:`, error);
657
- throw error;
658
- }
659
- }
660
- /**
661
- * 取消置顶消息
662
- * @param channel 频道 ID
663
- * @param timestamp 消息时间戳
664
- */
665
- async unpinMessage(channel, timestamp) {
666
- try {
667
- await this.client.pins.remove({ channel, timestamp });
668
- this.logger.debug(formatCompact({ op: "unpin", endpoint: this.$id, channel }));
669
- return true;
670
- }
671
- catch (error) {
672
- this.logger.error(`Slack Endpoint ${this.$id} 取消置顶失败:`, error);
673
- throw error;
674
- }
675
- }
676
- }
677
- //# sourceMappingURL=endpoint.js.map