@zhin.js/adapter-slack 7.0.0 → 7.0.1
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.
- package/CHANGELOG.md +22 -0
- package/README.md +17 -2
- package/adapters/slack.js +0 -5
- package/adapters/slack.ts +0 -5
- package/agent/tools/add_reaction.ts +11 -8
- package/agent/tools/archive_channel.ts +5 -8
- package/agent/tools/edit_message.ts +5 -8
- package/agent/tools/invite_to_channel.ts +5 -8
- package/agent/tools/pin_message.ts +5 -8
- package/agent/tools/remove_reaction.ts +14 -8
- package/agent/tools/set_purpose.ts +5 -8
- package/agent/tools/set_topic.ts +5 -8
- package/agent/tools/unarchive.ts +5 -8
- package/agent/tools/unpin_message.ts +5 -8
- package/agent/tools/user_info.ts +5 -8
- package/lib/client.d.ts +25 -0
- package/lib/client.js +2 -0
- package/lib/endpoint.d.ts +4 -22
- package/lib/endpoint.js +31 -76
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/protocol.d.ts +1 -1
- package/lib/protocol.js +1 -1
- package/lib/side-event-dispatch.d.ts +2 -2
- package/lib/side-event-dispatch.js +3 -3
- package/lib/slack-endpoint-commands.d.ts +1 -1
- package/package.json +15 -14
- package/src/client.ts +30 -0
- package/src/endpoint.ts +33 -93
- package/src/index.ts +4 -6
- package/src/protocol.ts +1 -1
- package/src/side-event-dispatch.ts +4 -4
- package/lib/slack-agent-deps.d.ts +0 -41
- package/lib/slack-agent-deps.js +0 -30
- package/src/slack-agent-deps.ts +0 -71
package/src/endpoint.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Endpoint } from 'zhin.js/adapter';
|
|
1
2
|
/**
|
|
2
3
|
* SlackEndpoint — lifecycle, outbound, admit, Socket Mode, agent tool surface.
|
|
3
4
|
*/
|
|
@@ -7,11 +8,9 @@ import type {
|
|
|
7
8
|
EndpointFriend,
|
|
8
9
|
EndpointGroup,
|
|
9
10
|
EndpointControl,
|
|
10
|
-
EndpointInstance,
|
|
11
11
|
EndpointManagement,
|
|
12
12
|
EndpointSendRequest,
|
|
13
13
|
} from 'zhin.js/adapter';
|
|
14
|
-
import type { MessageGateway, SideEventGateway } from '@zhin.js/core/runtime';
|
|
15
14
|
import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
|
|
16
15
|
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
17
16
|
import type { CapabilityId } from 'zhin.js';
|
|
@@ -28,7 +27,6 @@ import {
|
|
|
28
27
|
type SlackMessageEvent,
|
|
29
28
|
type SlackSlashCommand,
|
|
30
29
|
} from './protocol.js';
|
|
31
|
-
import { registerSlackAgentEndpoint, type SlackUserInfo } from './slack-agent-deps.js';
|
|
32
30
|
import {
|
|
33
31
|
createSlackInboundFilterState,
|
|
34
32
|
shouldDropSlackInboundMessage,
|
|
@@ -92,8 +90,6 @@ export interface SlackWebClientLike extends SlackChatClient {
|
|
|
92
90
|
|
|
93
91
|
export interface SlackEndpointOptions {
|
|
94
92
|
readonly id: CapabilityId;
|
|
95
|
-
readonly gateway: MessageGateway;
|
|
96
|
-
readonly sideEvents?: SideEventGateway;
|
|
97
93
|
readonly config: ResolvedSlackConfig;
|
|
98
94
|
readonly http?: HttpHost;
|
|
99
95
|
readonly createClient?: (token: string) => SlackWebClientLike;
|
|
@@ -103,7 +99,7 @@ export interface SlackEndpointOptions {
|
|
|
103
99
|
}) => SlackSocketLike;
|
|
104
100
|
}
|
|
105
101
|
|
|
106
|
-
export class SlackEndpoint implements
|
|
102
|
+
export class SlackEndpoint extends Endpoint<SlackWebClientLike> implements SlackWebhookHandler {
|
|
107
103
|
readonly #logger!: ReturnType<typeof getAdapterLogger>;
|
|
108
104
|
|
|
109
105
|
readonly #options: SlackEndpointOptions;
|
|
@@ -115,8 +111,7 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
115
111
|
#botUserId?: string;
|
|
116
112
|
#open = false;
|
|
117
113
|
#started = false;
|
|
118
|
-
|
|
119
|
-
readonly management: EndpointManagement = createSlackEndpointManagement(this);
|
|
114
|
+
readonly management: EndpointManagement = createSlackEndpointManagement(() => this.client);
|
|
120
115
|
readonly control: EndpointControl = Object.freeze<EndpointControl>({
|
|
121
116
|
recall: async (message) => {
|
|
122
117
|
const ref = this.resolveMessageRef(message.id, message.conversation.id);
|
|
@@ -126,24 +121,25 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
126
121
|
edit: async (message, content) => {
|
|
127
122
|
const ref = this.resolveMessageRef(message.id, message.conversation.id);
|
|
128
123
|
if (!ref) return null;
|
|
129
|
-
await this
|
|
124
|
+
await this.#editMessage(ref.channel, ref.ts, content);
|
|
130
125
|
return message.id;
|
|
131
126
|
},
|
|
132
127
|
addReaction: async (message, emoji) => {
|
|
133
128
|
const ref = this.resolveMessageRef(message.id, message.conversation.id);
|
|
134
129
|
if (!ref) return null;
|
|
135
130
|
const reaction = normalizeSlackReactionName(emoji);
|
|
136
|
-
await this
|
|
131
|
+
await this.#addReaction(ref.channel, ref.ts, reaction);
|
|
137
132
|
return reaction;
|
|
138
133
|
},
|
|
139
134
|
removeReaction: async (message, reactionId) => {
|
|
140
135
|
const ref = this.resolveMessageRef(message.id, message.conversation.id);
|
|
141
136
|
if (!ref) return;
|
|
142
|
-
await this
|
|
137
|
+
await this.#removeReaction(ref.channel, ref.ts, reactionId);
|
|
143
138
|
},
|
|
144
139
|
});
|
|
145
140
|
|
|
146
141
|
constructor(options: SlackEndpointOptions) {
|
|
142
|
+
super();
|
|
147
143
|
this.#logger = getAdapterLogger('slack', options.config.id);
|
|
148
144
|
this.#options = options;
|
|
149
145
|
}
|
|
@@ -153,7 +149,8 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
153
149
|
return this.#options.config.id;
|
|
154
150
|
}
|
|
155
151
|
|
|
156
|
-
get client(): SlackWebClientLike
|
|
152
|
+
get client(): SlackWebClientLike {
|
|
153
|
+
if (!this.#client) throw new Error('Slack client not connected');
|
|
157
154
|
return this.#client;
|
|
158
155
|
}
|
|
159
156
|
|
|
@@ -173,8 +170,6 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
173
170
|
this.#client = this.#options.createClient?.(config.token)
|
|
174
171
|
?? (new WebClient(config.token) as unknown as SlackWebClientLike);
|
|
175
172
|
|
|
176
|
-
this.#unregisterAgent = registerSlackAgentEndpoint(config.id, this);
|
|
177
|
-
|
|
178
173
|
if (config.mode === 'socket') {
|
|
179
174
|
await this.#startSocket();
|
|
180
175
|
} else {
|
|
@@ -223,8 +218,6 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
223
218
|
this.#socket = undefined;
|
|
224
219
|
}
|
|
225
220
|
for (const release of this.#routeReleases.splice(0)) release();
|
|
226
|
-
this.#unregisterAgent?.();
|
|
227
|
-
this.#unregisterAgent = undefined;
|
|
228
221
|
this.#client = undefined;
|
|
229
222
|
this.#started = false;
|
|
230
223
|
this.#logger.debug(formatCompact({ op: 'disconnect' }));
|
|
@@ -247,6 +240,7 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
247
240
|
/** Test / internal: admit a message event when open. */
|
|
248
241
|
admit(event: SlackMessageEvent | SlackEvent): void {
|
|
249
242
|
if (!this.#open) return;
|
|
243
|
+
void this.#emitPlatformEvent(event.type || 'event', event);
|
|
250
244
|
if (event.type !== 'message' && event.type !== 'app_mention') return;
|
|
251
245
|
const msg = event as SlackMessageEvent;
|
|
252
246
|
if (shouldDropSlackInboundMessage(msg, this.#inboundFilter, this.#botUserId)) return;
|
|
@@ -259,7 +253,7 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
259
253
|
channelType: msg.channel_type,
|
|
260
254
|
threadId: threadTs,
|
|
261
255
|
});
|
|
262
|
-
void this
|
|
256
|
+
void this.emit('message.receive', {
|
|
263
257
|
conversation,
|
|
264
258
|
message: { conversation, id: msg.ts },
|
|
265
259
|
content: formatInboundContent(msg),
|
|
@@ -283,6 +277,7 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
283
277
|
|
|
284
278
|
admitInteraction(payload: SlackInteractionPayload): void {
|
|
285
279
|
if (!this.#open) return;
|
|
280
|
+
void this.#emitPlatformEvent(`interaction.${payload.type}`, payload);
|
|
286
281
|
if (payload.type !== 'block_actions' || !payload.actions?.length) return;
|
|
287
282
|
const channelId = payload.channel?.id ?? '';
|
|
288
283
|
const userId = payload.user.id;
|
|
@@ -296,7 +291,7 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
296
291
|
// block_actions 无 channel_type;无 channel 时按与发起用户的 DM 处理
|
|
297
292
|
channelType: channelId ? undefined : 'im',
|
|
298
293
|
});
|
|
299
|
-
void this
|
|
294
|
+
void this.emit('message.receive', {
|
|
300
295
|
conversation,
|
|
301
296
|
message: { conversation, id: actionTs },
|
|
302
297
|
content: formatInteractionContent(payload),
|
|
@@ -318,11 +313,12 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
318
313
|
|
|
319
314
|
admitSlashCommand(cmd: SlackSlashCommand): void {
|
|
320
315
|
if (!this.#open) return;
|
|
316
|
+
void this.#emitPlatformEvent(`slash.${cmd.command}`, cmd);
|
|
321
317
|
postSlackEphemeral(cmd.response_url, '处理中…', this.#logger);
|
|
322
318
|
const conversation = slackInboundConversation(String(this.#options.id), {
|
|
323
319
|
channelId: cmd.channel_id,
|
|
324
320
|
});
|
|
325
|
-
void this
|
|
321
|
+
void this.emit('message.receive', {
|
|
326
322
|
conversation,
|
|
327
323
|
message: { conversation, id: cmd.trigger_id },
|
|
328
324
|
content: formatSlashContent(cmd),
|
|
@@ -346,8 +342,9 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
346
342
|
if (envelope?.type === 'event_callback' && envelope.event) {
|
|
347
343
|
const event = envelope.event;
|
|
348
344
|
if (event.type !== 'message' && event.type !== 'app_mention') {
|
|
345
|
+
void this.#emitPlatformEvent(event.type || 'event', event);
|
|
349
346
|
receiveSlackSideEvent(
|
|
350
|
-
this
|
|
347
|
+
(name, payload) => this.emit(name, payload),
|
|
351
348
|
String(this.#options.id),
|
|
352
349
|
this.#options.config.id,
|
|
353
350
|
event,
|
|
@@ -388,95 +385,41 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
388
385
|
await this.#client.chat.delete({ channel: ref.channel, ts: ref.ts });
|
|
389
386
|
}
|
|
390
387
|
|
|
391
|
-
async editMessage(channel: string, messageTs: string, content: unknown): Promise<void> {
|
|
388
|
+
async #editMessage(channel: string, messageTs: string, content: unknown): Promise<void> {
|
|
392
389
|
if (!this.#client) throw new Error('Slack client not connected');
|
|
393
390
|
await editSlackContent(this.#client, channel, messageTs, content);
|
|
394
391
|
}
|
|
395
392
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
async inviteToChannel(channel: string, users: string[]): Promise<boolean> {
|
|
399
|
-
await this.#client!.conversations.invite({ channel, users: users.join(',') });
|
|
400
|
-
return true;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
async kickFromChannel(channel: string, user: string): Promise<boolean> {
|
|
404
|
-
await this.#client!.conversations.kick({ channel, user });
|
|
405
|
-
return true;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
async setChannelTopic(channel: string, topic: string): Promise<boolean> {
|
|
409
|
-
await this.#client!.conversations.setTopic({ channel, topic });
|
|
410
|
-
return true;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
async setChannelPurpose(channel: string, purpose: string): Promise<boolean> {
|
|
414
|
-
await this.#client!.conversations.setPurpose({ channel, purpose });
|
|
415
|
-
return true;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
async archiveChannel(channel: string): Promise<boolean> {
|
|
419
|
-
await this.#client!.conversations.archive({ channel });
|
|
420
|
-
return true;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
async unarchiveChannel(channel: string): Promise<boolean> {
|
|
424
|
-
await this.#client!.conversations.unarchive({ channel });
|
|
425
|
-
return true;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
async renameChannel(channel: string, name: string): Promise<boolean> {
|
|
429
|
-
await this.#client!.conversations.rename({ channel, name });
|
|
430
|
-
return true;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
async getChannelMembers(channel: string): Promise<string[]> {
|
|
434
|
-
const result = await this.#client!.conversations.members({ channel });
|
|
435
|
-
return result.members || [];
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
async getChannelInfo(channel: string): Promise<unknown> {
|
|
439
|
-
const result = await this.#client!.conversations.info({ channel });
|
|
440
|
-
return result.channel;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
async getUserInfo(user: string): Promise<SlackUserInfo | undefined> {
|
|
444
|
-
const result = await this.#client!.users.info({ user });
|
|
445
|
-
return result.user as SlackUserInfo | undefined;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
async addReaction(channel: string, timestamp: string, name: string): Promise<boolean> {
|
|
393
|
+
async #addReaction(channel: string, timestamp: string, name: string): Promise<void> {
|
|
449
394
|
const reaction = normalizeSlackReactionName(name);
|
|
450
395
|
try {
|
|
451
396
|
await this.#client!.reactions.add({ channel, timestamp, name: reaction });
|
|
452
|
-
return true;
|
|
453
397
|
} catch (error) {
|
|
454
398
|
const code = (error as { data?: { error?: string } })?.data?.error;
|
|
455
|
-
if (code === 'already_reacted') return
|
|
399
|
+
if (code === 'already_reacted') return;
|
|
456
400
|
throw error;
|
|
457
401
|
}
|
|
458
402
|
}
|
|
459
403
|
|
|
460
|
-
async removeReaction(channel: string, timestamp: string, name: string): Promise<
|
|
404
|
+
async #removeReaction(channel: string, timestamp: string, name: string): Promise<void> {
|
|
461
405
|
const reaction = normalizeSlackReactionName(name);
|
|
462
406
|
try {
|
|
463
407
|
await this.#client!.reactions.remove({ channel, timestamp, name: reaction });
|
|
464
|
-
return true;
|
|
465
408
|
} catch (error) {
|
|
466
409
|
const code = (error as { data?: { error?: string } })?.data?.error;
|
|
467
|
-
if (code === 'no_reaction') return
|
|
410
|
+
if (code === 'no_reaction') return;
|
|
468
411
|
throw error;
|
|
469
412
|
}
|
|
470
413
|
}
|
|
471
414
|
|
|
472
|
-
async
|
|
473
|
-
await this
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
415
|
+
async #emitPlatformEvent(name: string, event: unknown): Promise<void> {
|
|
416
|
+
await this.emitPlatform(name, event).catch((error) => {
|
|
417
|
+
this.#logger.warn(formatCompact({
|
|
418
|
+
op: 'slack_platform_event_failed',
|
|
419
|
+
event: name,
|
|
420
|
+
error: error instanceof Error ? error.message : String(error),
|
|
421
|
+
}));
|
|
422
|
+
});
|
|
480
423
|
}
|
|
481
424
|
|
|
482
425
|
async #startSocket(): Promise<void> {
|
|
@@ -515,12 +458,9 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
515
458
|
/** Slack Web API 分页上限(每页 1000,cursor 翻页直到 next_cursor 为空)。 */
|
|
516
459
|
const SLACK_LIST_PAGE_SIZE = 1000;
|
|
517
460
|
|
|
518
|
-
function createSlackEndpointManagement(
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
if (!client) throw new Error('Slack client not connected');
|
|
522
|
-
return client;
|
|
523
|
-
};
|
|
461
|
+
function createSlackEndpointManagement(
|
|
462
|
+
requireClient: () => SlackWebClientLike,
|
|
463
|
+
): EndpointManagement {
|
|
524
464
|
return Object.freeze<EndpointManagement>({
|
|
525
465
|
// Slack 无"群"概念:public channel 归一为 group(channel 语义由 listChannels 之外省略,
|
|
526
466
|
// Slack channel 本身就是会话载体,避免同一批数据在两个列表里重复)。
|
package/src/index.ts
CHANGED
|
@@ -37,12 +37,10 @@ export {
|
|
|
37
37
|
} from './webhook.js';
|
|
38
38
|
|
|
39
39
|
export {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
type SlackAgentEndpoint,
|
|
45
|
-
} from './slack-agent-deps.js';
|
|
40
|
+
slackClient,
|
|
41
|
+
type SlackClientEventMap,
|
|
42
|
+
type SlackUserInfo,
|
|
43
|
+
} from './client.js';
|
|
46
44
|
|
|
47
45
|
export {
|
|
48
46
|
checkSlackPlatformPermit,
|
package/src/protocol.ts
CHANGED
|
@@ -217,7 +217,7 @@ export function slackInboundConversation(
|
|
|
217
217
|
};
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
-
/** Build inbound text for
|
|
220
|
+
/** Build inbound text for OutboundMessageService.receive. */
|
|
221
221
|
export function formatInboundContent(event: SlackMessageEvent | SlackEvent): string {
|
|
222
222
|
const text = typeof event.text === 'string' ? event.text : '';
|
|
223
223
|
if (text) return mrkdwnToMarkdown(text);
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { buildNotice, mapNoticeParts, senderFromId, SLACK_NOTICE_PARTS_MAP } from '@zhin.js/core';
|
|
2
|
-
import type {
|
|
2
|
+
import type { EndpointEventEmitter } from 'zhin.js/adapter';
|
|
3
3
|
import { formatCompact, type getAdapterLogger } from '@zhin.js/logger';
|
|
4
4
|
import type { SlackEvent } from './protocol.js';
|
|
5
5
|
|
|
6
6
|
export function receiveSlackSideEvent(
|
|
7
|
-
|
|
7
|
+
emit: EndpointEventEmitter,
|
|
8
8
|
endpointKey: string,
|
|
9
9
|
configId: string,
|
|
10
10
|
event: SlackEvent,
|
|
11
11
|
logger: ReturnType<typeof getAdapterLogger>,
|
|
12
12
|
): void {
|
|
13
|
-
if (!
|
|
13
|
+
if (!emit) return;
|
|
14
14
|
const eventType = String(event.type ?? '');
|
|
15
15
|
if (!Object.prototype.hasOwnProperty.call(SLACK_NOTICE_PARTS_MAP, eventType)) return;
|
|
16
16
|
const record = event as Record<string, unknown>;
|
|
@@ -24,7 +24,7 @@ export function receiveSlackSideEvent(
|
|
|
24
24
|
user ?? '',
|
|
25
25
|
String(record.ts ?? record.event_ts ?? ''),
|
|
26
26
|
].join(':');
|
|
27
|
-
void
|
|
27
|
+
void emit('notice.receive', buildNotice(record, {
|
|
28
28
|
$id: `slack:${dedupeKey}`,
|
|
29
29
|
$adapter: 'slack' as never,
|
|
30
30
|
$endpoint: configId,
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agent tool deps for slack.
|
|
3
|
-
* Endpoints register themselves on start; tools look up by config name / endpoint id.
|
|
4
|
-
*/
|
|
5
|
-
export interface SlackAgentEndpoint {
|
|
6
|
-
inviteToChannel(channel: string, users: string[]): Promise<boolean>;
|
|
7
|
-
kickFromChannel(channel: string, user: string): Promise<boolean>;
|
|
8
|
-
setChannelTopic(channel: string, topic: string): Promise<boolean>;
|
|
9
|
-
setChannelPurpose(channel: string, purpose: string): Promise<boolean>;
|
|
10
|
-
archiveChannel(channel: string): Promise<boolean>;
|
|
11
|
-
unarchiveChannel(channel: string): Promise<boolean>;
|
|
12
|
-
renameChannel(channel: string, name: string): Promise<boolean>;
|
|
13
|
-
getChannelMembers(channel: string): Promise<string[]>;
|
|
14
|
-
getChannelInfo(channel: string): Promise<unknown>;
|
|
15
|
-
getUserInfo(user: string): Promise<SlackUserInfo | undefined>;
|
|
16
|
-
addReaction(channel: string, timestamp: string, name: string): Promise<boolean>;
|
|
17
|
-
removeReaction(channel: string, timestamp: string, name: string): Promise<boolean>;
|
|
18
|
-
pinMessage(channel: string, timestamp: string): Promise<boolean>;
|
|
19
|
-
unpinMessage(channel: string, timestamp: string): Promise<boolean>;
|
|
20
|
-
editMessage(channel: string, messageTs: string, content: unknown): Promise<void>;
|
|
21
|
-
}
|
|
22
|
-
/** Slack users.info 返回的用户对象(SDK 响应字段对 agent 工具的投影)。 */
|
|
23
|
-
export interface SlackUserInfo {
|
|
24
|
-
id?: string;
|
|
25
|
-
name?: string;
|
|
26
|
-
real_name?: string;
|
|
27
|
-
is_admin?: boolean;
|
|
28
|
-
is_bot?: boolean;
|
|
29
|
-
profile?: {
|
|
30
|
-
display_name?: string;
|
|
31
|
-
email?: string;
|
|
32
|
-
status_text?: string;
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
export interface SlackAgentDeps {
|
|
36
|
-
getEndpoint: (endpointKey: string) => SlackAgentEndpoint;
|
|
37
|
-
}
|
|
38
|
-
export declare function registerSlackAgentEndpoint(endpointKey: string, endpoint: SlackAgentEndpoint): () => void;
|
|
39
|
-
/** Optional override used by tests / transitional callers. Pass `null` to clear. */
|
|
40
|
-
export declare function setSlackAgentDeps(deps: SlackAgentDeps | null): void;
|
|
41
|
-
export declare function getSlackAgentDeps(): SlackAgentDeps;
|
package/lib/slack-agent-deps.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agent tool deps for slack.
|
|
3
|
-
* Endpoints register themselves on start; tools look up by config name / endpoint id.
|
|
4
|
-
*/
|
|
5
|
-
const endpoints = new Map();
|
|
6
|
-
let override = null;
|
|
7
|
-
export function registerSlackAgentEndpoint(endpointKey, endpoint) {
|
|
8
|
-
endpoints.set(endpointKey, endpoint);
|
|
9
|
-
return () => {
|
|
10
|
-
if (endpoints.get(endpointKey) === endpoint) {
|
|
11
|
-
endpoints.delete(endpointKey);
|
|
12
|
-
}
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
/** Optional override used by tests / transitional callers. Pass `null` to clear. */
|
|
16
|
-
export function setSlackAgentDeps(deps) {
|
|
17
|
-
override = deps;
|
|
18
|
-
}
|
|
19
|
-
export function getSlackAgentDeps() {
|
|
20
|
-
if (override)
|
|
21
|
-
return override;
|
|
22
|
-
return {
|
|
23
|
-
getEndpoint(endpointKey) {
|
|
24
|
-
const registered = endpoints.get(endpointKey);
|
|
25
|
-
if (!registered)
|
|
26
|
-
throw new Error(`Endpoint ${endpointKey} 不存在`);
|
|
27
|
-
return registered;
|
|
28
|
-
},
|
|
29
|
-
};
|
|
30
|
-
}
|
package/src/slack-agent-deps.ts
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agent tool deps for slack.
|
|
3
|
-
* Endpoints register themselves on start; tools look up by config name / endpoint id.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export interface SlackAgentEndpoint {
|
|
7
|
-
inviteToChannel(channel: string, users: string[]): Promise<boolean>;
|
|
8
|
-
kickFromChannel(channel: string, user: string): Promise<boolean>;
|
|
9
|
-
setChannelTopic(channel: string, topic: string): Promise<boolean>;
|
|
10
|
-
setChannelPurpose(channel: string, purpose: string): Promise<boolean>;
|
|
11
|
-
archiveChannel(channel: string): Promise<boolean>;
|
|
12
|
-
unarchiveChannel(channel: string): Promise<boolean>;
|
|
13
|
-
renameChannel(channel: string, name: string): Promise<boolean>;
|
|
14
|
-
getChannelMembers(channel: string): Promise<string[]>;
|
|
15
|
-
getChannelInfo(channel: string): Promise<unknown>;
|
|
16
|
-
getUserInfo(user: string): Promise<SlackUserInfo | undefined>;
|
|
17
|
-
addReaction(channel: string, timestamp: string, name: string): Promise<boolean>;
|
|
18
|
-
removeReaction(channel: string, timestamp: string, name: string): Promise<boolean>;
|
|
19
|
-
pinMessage(channel: string, timestamp: string): Promise<boolean>;
|
|
20
|
-
unpinMessage(channel: string, timestamp: string): Promise<boolean>;
|
|
21
|
-
editMessage(channel: string, messageTs: string, content: unknown): Promise<void>;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** Slack users.info 返回的用户对象(SDK 响应字段对 agent 工具的投影)。 */
|
|
25
|
-
export interface SlackUserInfo {
|
|
26
|
-
id?: string;
|
|
27
|
-
name?: string;
|
|
28
|
-
real_name?: string;
|
|
29
|
-
is_admin?: boolean;
|
|
30
|
-
is_bot?: boolean;
|
|
31
|
-
profile?: {
|
|
32
|
-
display_name?: string;
|
|
33
|
-
email?: string;
|
|
34
|
-
status_text?: string;
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface SlackAgentDeps {
|
|
39
|
-
getEndpoint: (endpointKey: string) => SlackAgentEndpoint;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const endpoints = new Map<string, SlackAgentEndpoint>();
|
|
43
|
-
let override: SlackAgentDeps | null = null;
|
|
44
|
-
|
|
45
|
-
export function registerSlackAgentEndpoint(
|
|
46
|
-
endpointKey: string,
|
|
47
|
-
endpoint: SlackAgentEndpoint,
|
|
48
|
-
): () => void {
|
|
49
|
-
endpoints.set(endpointKey, endpoint);
|
|
50
|
-
return () => {
|
|
51
|
-
if (endpoints.get(endpointKey) === endpoint) {
|
|
52
|
-
endpoints.delete(endpointKey);
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/** Optional override used by tests / transitional callers. Pass `null` to clear. */
|
|
58
|
-
export function setSlackAgentDeps(deps: SlackAgentDeps | null): void {
|
|
59
|
-
override = deps;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export function getSlackAgentDeps(): SlackAgentDeps {
|
|
63
|
-
if (override) return override;
|
|
64
|
-
return {
|
|
65
|
-
getEndpoint(endpointKey: string): SlackAgentEndpoint {
|
|
66
|
-
const registered = endpoints.get(endpointKey);
|
|
67
|
-
if (!registered) throw new Error(`Endpoint ${endpointKey} 不存在`);
|
|
68
|
-
return registered;
|
|
69
|
-
},
|
|
70
|
-
};
|
|
71
|
-
}
|