@zhin.js/adapter-slack 6.0.14 → 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 +36 -0
- package/README.md +17 -2
- package/adapters/slack.js +1 -5
- package/adapters/slack.ts +1 -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 +5 -22
- package/lib/endpoint.js +57 -73
- 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 +56 -90
- 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
|
*/
|
|
@@ -6,11 +7,10 @@ import { WebClient } from '@slack/web-api';
|
|
|
6
7
|
import type {
|
|
7
8
|
EndpointFriend,
|
|
8
9
|
EndpointGroup,
|
|
9
|
-
|
|
10
|
+
EndpointControl,
|
|
10
11
|
EndpointManagement,
|
|
11
12
|
EndpointSendRequest,
|
|
12
13
|
} from 'zhin.js/adapter';
|
|
13
|
-
import type { MessageGateway, SideEventGateway } from '@zhin.js/core/runtime';
|
|
14
14
|
import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
|
|
15
15
|
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
16
16
|
import type { CapabilityId } from 'zhin.js';
|
|
@@ -27,7 +27,6 @@ import {
|
|
|
27
27
|
type SlackMessageEvent,
|
|
28
28
|
type SlackSlashCommand,
|
|
29
29
|
} from './protocol.js';
|
|
30
|
-
import { registerSlackAgentEndpoint, type SlackUserInfo } from './slack-agent-deps.js';
|
|
31
30
|
import {
|
|
32
31
|
createSlackInboundFilterState,
|
|
33
32
|
shouldDropSlackInboundMessage,
|
|
@@ -91,8 +90,6 @@ export interface SlackWebClientLike extends SlackChatClient {
|
|
|
91
90
|
|
|
92
91
|
export interface SlackEndpointOptions {
|
|
93
92
|
readonly id: CapabilityId;
|
|
94
|
-
readonly gateway: MessageGateway;
|
|
95
|
-
readonly sideEvents?: SideEventGateway;
|
|
96
93
|
readonly config: ResolvedSlackConfig;
|
|
97
94
|
readonly http?: HttpHost;
|
|
98
95
|
readonly createClient?: (token: string) => SlackWebClientLike;
|
|
@@ -102,7 +99,7 @@ export interface SlackEndpointOptions {
|
|
|
102
99
|
}) => SlackSocketLike;
|
|
103
100
|
}
|
|
104
101
|
|
|
105
|
-
export class SlackEndpoint implements
|
|
102
|
+
export class SlackEndpoint extends Endpoint<SlackWebClientLike> implements SlackWebhookHandler {
|
|
106
103
|
readonly #logger!: ReturnType<typeof getAdapterLogger>;
|
|
107
104
|
|
|
108
105
|
readonly #options: SlackEndpointOptions;
|
|
@@ -114,10 +111,35 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
114
111
|
#botUserId?: string;
|
|
115
112
|
#open = false;
|
|
116
113
|
#started = false;
|
|
117
|
-
|
|
118
|
-
readonly
|
|
114
|
+
readonly management: EndpointManagement = createSlackEndpointManagement(() => this.client);
|
|
115
|
+
readonly control: EndpointControl = Object.freeze<EndpointControl>({
|
|
116
|
+
recall: async (message) => {
|
|
117
|
+
const ref = this.resolveMessageRef(message.id, message.conversation.id);
|
|
118
|
+
if (!ref || !this.#client) return;
|
|
119
|
+
await this.#client.chat.delete(ref);
|
|
120
|
+
},
|
|
121
|
+
edit: async (message, content) => {
|
|
122
|
+
const ref = this.resolveMessageRef(message.id, message.conversation.id);
|
|
123
|
+
if (!ref) return null;
|
|
124
|
+
await this.#editMessage(ref.channel, ref.ts, content);
|
|
125
|
+
return message.id;
|
|
126
|
+
},
|
|
127
|
+
addReaction: async (message, emoji) => {
|
|
128
|
+
const ref = this.resolveMessageRef(message.id, message.conversation.id);
|
|
129
|
+
if (!ref) return null;
|
|
130
|
+
const reaction = normalizeSlackReactionName(emoji);
|
|
131
|
+
await this.#addReaction(ref.channel, ref.ts, reaction);
|
|
132
|
+
return reaction;
|
|
133
|
+
},
|
|
134
|
+
removeReaction: async (message, reactionId) => {
|
|
135
|
+
const ref = this.resolveMessageRef(message.id, message.conversation.id);
|
|
136
|
+
if (!ref) return;
|
|
137
|
+
await this.#removeReaction(ref.channel, ref.ts, reactionId);
|
|
138
|
+
},
|
|
139
|
+
});
|
|
119
140
|
|
|
120
141
|
constructor(options: SlackEndpointOptions) {
|
|
142
|
+
super();
|
|
121
143
|
this.#logger = getAdapterLogger('slack', options.config.id);
|
|
122
144
|
this.#options = options;
|
|
123
145
|
}
|
|
@@ -127,7 +149,8 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
127
149
|
return this.#options.config.id;
|
|
128
150
|
}
|
|
129
151
|
|
|
130
|
-
get client(): SlackWebClientLike
|
|
152
|
+
get client(): SlackWebClientLike {
|
|
153
|
+
if (!this.#client) throw new Error('Slack client not connected');
|
|
131
154
|
return this.#client;
|
|
132
155
|
}
|
|
133
156
|
|
|
@@ -147,8 +170,6 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
147
170
|
this.#client = this.#options.createClient?.(config.token)
|
|
148
171
|
?? (new WebClient(config.token) as unknown as SlackWebClientLike);
|
|
149
172
|
|
|
150
|
-
this.#unregisterAgent = registerSlackAgentEndpoint(config.id, this);
|
|
151
|
-
|
|
152
173
|
if (config.mode === 'socket') {
|
|
153
174
|
await this.#startSocket();
|
|
154
175
|
} else {
|
|
@@ -197,8 +218,6 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
197
218
|
this.#socket = undefined;
|
|
198
219
|
}
|
|
199
220
|
for (const release of this.#routeReleases.splice(0)) release();
|
|
200
|
-
this.#unregisterAgent?.();
|
|
201
|
-
this.#unregisterAgent = undefined;
|
|
202
221
|
this.#client = undefined;
|
|
203
222
|
this.#started = false;
|
|
204
223
|
this.#logger.debug(formatCompact({ op: 'disconnect' }));
|
|
@@ -221,6 +240,7 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
221
240
|
/** Test / internal: admit a message event when open. */
|
|
222
241
|
admit(event: SlackMessageEvent | SlackEvent): void {
|
|
223
242
|
if (!this.#open) return;
|
|
243
|
+
void this.#emitPlatformEvent(event.type || 'event', event);
|
|
224
244
|
if (event.type !== 'message' && event.type !== 'app_mention') return;
|
|
225
245
|
const msg = event as SlackMessageEvent;
|
|
226
246
|
if (shouldDropSlackInboundMessage(msg, this.#inboundFilter, this.#botUserId)) return;
|
|
@@ -233,7 +253,7 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
233
253
|
channelType: msg.channel_type,
|
|
234
254
|
threadId: threadTs,
|
|
235
255
|
});
|
|
236
|
-
void this
|
|
256
|
+
void this.emit('message.receive', {
|
|
237
257
|
conversation,
|
|
238
258
|
message: { conversation, id: msg.ts },
|
|
239
259
|
content: formatInboundContent(msg),
|
|
@@ -257,6 +277,7 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
257
277
|
|
|
258
278
|
admitInteraction(payload: SlackInteractionPayload): void {
|
|
259
279
|
if (!this.#open) return;
|
|
280
|
+
void this.#emitPlatformEvent(`interaction.${payload.type}`, payload);
|
|
260
281
|
if (payload.type !== 'block_actions' || !payload.actions?.length) return;
|
|
261
282
|
const channelId = payload.channel?.id ?? '';
|
|
262
283
|
const userId = payload.user.id;
|
|
@@ -270,7 +291,7 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
270
291
|
// block_actions 无 channel_type;无 channel 时按与发起用户的 DM 处理
|
|
271
292
|
channelType: channelId ? undefined : 'im',
|
|
272
293
|
});
|
|
273
|
-
void this
|
|
294
|
+
void this.emit('message.receive', {
|
|
274
295
|
conversation,
|
|
275
296
|
message: { conversation, id: actionTs },
|
|
276
297
|
content: formatInteractionContent(payload),
|
|
@@ -292,11 +313,12 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
292
313
|
|
|
293
314
|
admitSlashCommand(cmd: SlackSlashCommand): void {
|
|
294
315
|
if (!this.#open) return;
|
|
316
|
+
void this.#emitPlatformEvent(`slash.${cmd.command}`, cmd);
|
|
295
317
|
postSlackEphemeral(cmd.response_url, '处理中…', this.#logger);
|
|
296
318
|
const conversation = slackInboundConversation(String(this.#options.id), {
|
|
297
319
|
channelId: cmd.channel_id,
|
|
298
320
|
});
|
|
299
|
-
void this
|
|
321
|
+
void this.emit('message.receive', {
|
|
300
322
|
conversation,
|
|
301
323
|
message: { conversation, id: cmd.trigger_id },
|
|
302
324
|
content: formatSlashContent(cmd),
|
|
@@ -320,8 +342,9 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
320
342
|
if (envelope?.type === 'event_callback' && envelope.event) {
|
|
321
343
|
const event = envelope.event;
|
|
322
344
|
if (event.type !== 'message' && event.type !== 'app_mention') {
|
|
345
|
+
void this.#emitPlatformEvent(event.type || 'event', event);
|
|
323
346
|
receiveSlackSideEvent(
|
|
324
|
-
this
|
|
347
|
+
(name, payload) => this.emit(name, payload),
|
|
325
348
|
String(this.#options.id),
|
|
326
349
|
this.#options.config.id,
|
|
327
350
|
event,
|
|
@@ -362,95 +385,41 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
362
385
|
await this.#client.chat.delete({ channel: ref.channel, ts: ref.ts });
|
|
363
386
|
}
|
|
364
387
|
|
|
365
|
-
async editMessage(channel: string, messageTs: string, content: unknown): Promise<void> {
|
|
388
|
+
async #editMessage(channel: string, messageTs: string, content: unknown): Promise<void> {
|
|
366
389
|
if (!this.#client) throw new Error('Slack client not connected');
|
|
367
390
|
await editSlackContent(this.#client, channel, messageTs, content);
|
|
368
391
|
}
|
|
369
392
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
async inviteToChannel(channel: string, users: string[]): Promise<boolean> {
|
|
373
|
-
await this.#client!.conversations.invite({ channel, users: users.join(',') });
|
|
374
|
-
return true;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
async kickFromChannel(channel: string, user: string): Promise<boolean> {
|
|
378
|
-
await this.#client!.conversations.kick({ channel, user });
|
|
379
|
-
return true;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
async setChannelTopic(channel: string, topic: string): Promise<boolean> {
|
|
383
|
-
await this.#client!.conversations.setTopic({ channel, topic });
|
|
384
|
-
return true;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
async setChannelPurpose(channel: string, purpose: string): Promise<boolean> {
|
|
388
|
-
await this.#client!.conversations.setPurpose({ channel, purpose });
|
|
389
|
-
return true;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
async archiveChannel(channel: string): Promise<boolean> {
|
|
393
|
-
await this.#client!.conversations.archive({ channel });
|
|
394
|
-
return true;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
async unarchiveChannel(channel: string): Promise<boolean> {
|
|
398
|
-
await this.#client!.conversations.unarchive({ channel });
|
|
399
|
-
return true;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
async renameChannel(channel: string, name: string): Promise<boolean> {
|
|
403
|
-
await this.#client!.conversations.rename({ channel, name });
|
|
404
|
-
return true;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
async getChannelMembers(channel: string): Promise<string[]> {
|
|
408
|
-
const result = await this.#client!.conversations.members({ channel });
|
|
409
|
-
return result.members || [];
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
async getChannelInfo(channel: string): Promise<unknown> {
|
|
413
|
-
const result = await this.#client!.conversations.info({ channel });
|
|
414
|
-
return result.channel;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
async getUserInfo(user: string): Promise<SlackUserInfo | undefined> {
|
|
418
|
-
const result = await this.#client!.users.info({ user });
|
|
419
|
-
return result.user as SlackUserInfo | undefined;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
async addReaction(channel: string, timestamp: string, name: string): Promise<boolean> {
|
|
393
|
+
async #addReaction(channel: string, timestamp: string, name: string): Promise<void> {
|
|
423
394
|
const reaction = normalizeSlackReactionName(name);
|
|
424
395
|
try {
|
|
425
396
|
await this.#client!.reactions.add({ channel, timestamp, name: reaction });
|
|
426
|
-
return true;
|
|
427
397
|
} catch (error) {
|
|
428
398
|
const code = (error as { data?: { error?: string } })?.data?.error;
|
|
429
|
-
if (code === 'already_reacted') return
|
|
399
|
+
if (code === 'already_reacted') return;
|
|
430
400
|
throw error;
|
|
431
401
|
}
|
|
432
402
|
}
|
|
433
403
|
|
|
434
|
-
async removeReaction(channel: string, timestamp: string, name: string): Promise<
|
|
404
|
+
async #removeReaction(channel: string, timestamp: string, name: string): Promise<void> {
|
|
435
405
|
const reaction = normalizeSlackReactionName(name);
|
|
436
406
|
try {
|
|
437
407
|
await this.#client!.reactions.remove({ channel, timestamp, name: reaction });
|
|
438
|
-
return true;
|
|
439
408
|
} catch (error) {
|
|
440
409
|
const code = (error as { data?: { error?: string } })?.data?.error;
|
|
441
|
-
if (code === 'no_reaction') return
|
|
410
|
+
if (code === 'no_reaction') return;
|
|
442
411
|
throw error;
|
|
443
412
|
}
|
|
444
413
|
}
|
|
445
414
|
|
|
446
|
-
async
|
|
447
|
-
await this
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
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
|
+
});
|
|
454
423
|
}
|
|
455
424
|
|
|
456
425
|
async #startSocket(): Promise<void> {
|
|
@@ -489,12 +458,9 @@ export class SlackEndpoint implements EndpointInstance, SlackWebhookHandler {
|
|
|
489
458
|
/** Slack Web API 分页上限(每页 1000,cursor 翻页直到 next_cursor 为空)。 */
|
|
490
459
|
const SLACK_LIST_PAGE_SIZE = 1000;
|
|
491
460
|
|
|
492
|
-
function createSlackEndpointManagement(
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
if (!client) throw new Error('Slack client not connected');
|
|
496
|
-
return client;
|
|
497
|
-
};
|
|
461
|
+
function createSlackEndpointManagement(
|
|
462
|
+
requireClient: () => SlackWebClientLike,
|
|
463
|
+
): EndpointManagement {
|
|
498
464
|
return Object.freeze<EndpointManagement>({
|
|
499
465
|
// Slack 无"群"概念:public channel 归一为 group(channel 语义由 listChannels 之外省略,
|
|
500
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
|
-
}
|