@zhin.js/adapter-slack 1.0.77 → 1.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.
- package/CHANGELOG.md +642 -0
- package/README.md +112 -158
- package/adapters/slack.js +40 -0
- package/adapters/slack.ts +45 -0
- package/agent/PERMITS.md +24 -0
- package/{skills/slack/SKILL.md → agent/skills/slack.md} +2 -0
- package/agent/tools/add_reaction.ts +29 -0
- package/agent/tools/archive_channel.ts +21 -0
- package/agent/tools/edit_message.ts +25 -0
- package/agent/tools/invite_to_channel.ts +23 -0
- package/agent/tools/pin_message.ts +23 -0
- package/agent/tools/remove_reaction.ts +32 -0
- package/agent/tools/set_purpose.ts +23 -0
- package/agent/tools/set_topic.ts +23 -0
- package/agent/tools/unarchive.ts +21 -0
- package/agent/tools/unpin_message.ts +23 -0
- package/agent/tools/user_info.ts +29 -0
- package/commands/endpoint/add/[id].js +3 -0
- package/commands/endpoint/add/[id].ts +3 -0
- package/commands/endpoint/list.js +3 -0
- package/commands/endpoint/list.ts +3 -0
- package/commands/endpoint/remove/[id].js +3 -0
- package/commands/endpoint/remove/[id].ts +3 -0
- package/lib/client.d.ts +25 -0
- package/lib/client.js +2 -0
- package/lib/endpoint.d.ts +153 -0
- package/lib/endpoint.js +425 -0
- package/lib/index.d.ts +10 -10
- package/lib/index.js +10 -242
- package/lib/markdown-to-mrkdwn.d.ts +9 -0
- package/lib/markdown-to-mrkdwn.js +121 -0
- package/lib/mrkdwn-to-markdown.d.ts +4 -0
- package/lib/mrkdwn-to-markdown.js +30 -0
- package/lib/platform-permit.d.ts +15 -0
- package/lib/platform-permit.js +43 -0
- package/lib/protocol.d.ts +153 -0
- package/lib/protocol.js +272 -0
- package/lib/side-event-dispatch.d.ts +4 -0
- package/lib/side-event-dispatch.js +45 -0
- package/lib/slack-endpoint-commands.d.ts +1 -0
- package/lib/slack-endpoint-commands.js +18 -0
- package/lib/slack-inbound-filter.d.ts +12 -0
- package/lib/slack-inbound-filter.js +46 -0
- package/lib/slack-message-ref.d.ts +7 -0
- package/lib/slack-message-ref.js +17 -0
- package/lib/slack-outbound.d.ts +24 -0
- package/lib/slack-outbound.js +111 -0
- package/lib/slack-reaction.d.ts +1 -0
- package/lib/slack-reaction.js +26 -0
- package/lib/slack-response-url.d.ts +5 -0
- package/lib/slack-response-url.js +16 -0
- package/lib/slack-runtime-state.d.ts +1 -0
- package/lib/slack-runtime-state.js +6 -0
- package/lib/webhook.d.ts +14 -0
- package/lib/webhook.js +72 -0
- package/package.json +67 -15
- package/plugin.js +19 -0
- package/schema.json +95 -0
- package/src/client.ts +30 -0
- package/src/endpoint.ts +526 -0
- package/src/index.ts +59 -265
- package/src/markdown-to-mrkdwn.ts +117 -0
- package/src/mrkdwn-to-markdown.ts +29 -0
- package/src/platform-permit.ts +59 -0
- package/src/protocol.ts +435 -0
- package/src/side-event-dispatch.ts +54 -0
- package/src/slack-endpoint-commands.ts +19 -0
- package/src/slack-inbound-filter.ts +60 -0
- package/src/slack-message-ref.ts +18 -0
- package/src/slack-outbound.ts +170 -0
- package/src/slack-reaction.ts +23 -0
- package/src/slack-response-url.ts +26 -0
- package/src/slack-runtime-state.ts +7 -0
- package/src/webhook.ts +106 -0
- package/lib/adapter.d.ts +0 -16
- package/lib/adapter.d.ts.map +0 -1
- package/lib/adapter.js +0 -43
- package/lib/adapter.js.map +0 -1
- package/lib/bot.d.ts +0 -106
- package/lib/bot.d.ts.map +0 -1
- package/lib/bot.js +0 -628
- package/lib/bot.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/types.d.ts +0 -17
- package/lib/types.d.ts.map +0 -1
- package/lib/types.js +0 -2
- package/lib/types.js.map +0 -1
- package/plugin.yml +0 -3
- package/src/adapter.ts +0 -52
- package/src/bot.ts +0 -688
- package/src/types.ts +0 -18
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack outbound — chat.postMessage + Block Kit + files.uploadV2
|
|
3
|
+
*/
|
|
4
|
+
import type { Logger } from '@zhin.js/logger';
|
|
5
|
+
import { markdownToMrkdwn, mrkdwnToPlainFallback, splitMrkdwnText } from './markdown-to-mrkdwn.js';
|
|
6
|
+
import { formatOutboundWire, keyboardToBlockKitBlocks } from './protocol.js';
|
|
7
|
+
|
|
8
|
+
export interface SlackOutboundResult {
|
|
9
|
+
ts: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface SlackSendOptions {
|
|
13
|
+
channel: string;
|
|
14
|
+
threadTs?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface SlackChatClient {
|
|
18
|
+
chat: {
|
|
19
|
+
postMessage(opts: Record<string, unknown>): Promise<{ ts?: string }>;
|
|
20
|
+
update(opts: Record<string, unknown>): Promise<unknown>;
|
|
21
|
+
};
|
|
22
|
+
filesUploadV2?(opts: Record<string, unknown>): Promise<unknown>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const SLACK_MAX_BLOCKS_PER_MESSAGE = 48;
|
|
26
|
+
|
|
27
|
+
export async function sendSlackContent(
|
|
28
|
+
client: SlackChatClient,
|
|
29
|
+
content: unknown,
|
|
30
|
+
opts: SlackSendOptions,
|
|
31
|
+
logger: Logger,
|
|
32
|
+
): Promise<SlackOutboundResult> {
|
|
33
|
+
const wire = formatOutboundWire(content);
|
|
34
|
+
const blocks = [...wire.blocks];
|
|
35
|
+
const textDelivery = applyTextMrkdwnBlocks(wire.text, blocks);
|
|
36
|
+
|
|
37
|
+
for (const pf of wire.files) {
|
|
38
|
+
try {
|
|
39
|
+
await uploadFile(client, opts.channel, pf, opts.threadTs);
|
|
40
|
+
} catch (e) {
|
|
41
|
+
logger.error('Failed to upload file:', e);
|
|
42
|
+
throw e;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return postSlackMessage(client, {
|
|
47
|
+
channel: opts.channel,
|
|
48
|
+
threadTs: opts.threadTs,
|
|
49
|
+
blocks,
|
|
50
|
+
attachments: wire.attachments,
|
|
51
|
+
fallbackText: textDelivery.fallbackText,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export async function editSlackContent(
|
|
56
|
+
client: SlackChatClient,
|
|
57
|
+
channel: string,
|
|
58
|
+
ts: string,
|
|
59
|
+
content: unknown,
|
|
60
|
+
): Promise<void> {
|
|
61
|
+
const wire = formatOutboundWire(content);
|
|
62
|
+
const blocks = [...wire.blocks];
|
|
63
|
+
const textDelivery = applyTextMrkdwnBlocks(wire.text, blocks);
|
|
64
|
+
const payloadBlocks = blocks.slice(0, SLACK_MAX_BLOCKS_PER_MESSAGE);
|
|
65
|
+
|
|
66
|
+
const updateOpts: Record<string, unknown> = {
|
|
67
|
+
channel,
|
|
68
|
+
ts,
|
|
69
|
+
text: textDelivery.fallbackText || ' ',
|
|
70
|
+
};
|
|
71
|
+
if (payloadBlocks.length > 0) updateOpts.blocks = payloadBlocks;
|
|
72
|
+
await client.chat.update(updateOpts);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function applyTextMrkdwnBlocks(
|
|
76
|
+
textContent: string,
|
|
77
|
+
blocks: Record<string, unknown>[],
|
|
78
|
+
): { fallbackText: string } {
|
|
79
|
+
const trimmed = textContent.trim();
|
|
80
|
+
if (!trimmed) return { fallbackText: '' };
|
|
81
|
+
|
|
82
|
+
const mrkdwn = markdownToMrkdwn(trimmed);
|
|
83
|
+
const sections = splitMrkdwnText(mrkdwn).map((chunk) => ({
|
|
84
|
+
type: 'section',
|
|
85
|
+
text: { type: 'mrkdwn', text: chunk },
|
|
86
|
+
}));
|
|
87
|
+
|
|
88
|
+
if (blocks.length > 0) {
|
|
89
|
+
blocks.unshift(...sections);
|
|
90
|
+
return { fallbackText: '' };
|
|
91
|
+
}
|
|
92
|
+
blocks.push(...sections);
|
|
93
|
+
return { fallbackText: mrkdwnToPlainFallback(mrkdwn) };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function postSlackMessage(
|
|
97
|
+
client: SlackChatClient,
|
|
98
|
+
opts: {
|
|
99
|
+
channel: string;
|
|
100
|
+
threadTs?: string;
|
|
101
|
+
blocks: Record<string, unknown>[];
|
|
102
|
+
attachments: Record<string, unknown>[];
|
|
103
|
+
fallbackText: string;
|
|
104
|
+
},
|
|
105
|
+
): Promise<SlackOutboundResult> {
|
|
106
|
+
const { channel, blocks, attachments, fallbackText } = opts;
|
|
107
|
+
let threadTs = opts.threadTs;
|
|
108
|
+
let firstTs = '';
|
|
109
|
+
|
|
110
|
+
if (blocks.length === 0) {
|
|
111
|
+
const result = await client.chat.postMessage({
|
|
112
|
+
channel,
|
|
113
|
+
text: fallbackText || 'Message',
|
|
114
|
+
...(threadTs ? { thread_ts: threadTs } : {}),
|
|
115
|
+
...(attachments.length > 0 ? { attachments } : {}),
|
|
116
|
+
});
|
|
117
|
+
return { ts: requireMessageTimestamp(result) };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
for (let offset = 0; offset < blocks.length; offset += SLACK_MAX_BLOCKS_PER_MESSAGE) {
|
|
121
|
+
const chunk = blocks.slice(offset, offset + SLACK_MAX_BLOCKS_PER_MESSAGE);
|
|
122
|
+
const result = await client.chat.postMessage({
|
|
123
|
+
channel,
|
|
124
|
+
text: offset === 0 ? (fallbackText || ' ') : ' ',
|
|
125
|
+
blocks: chunk,
|
|
126
|
+
...(threadTs ? { thread_ts: threadTs } : {}),
|
|
127
|
+
...(offset === 0 && attachments.length > 0 ? { attachments } : {}),
|
|
128
|
+
});
|
|
129
|
+
const ts = requireMessageTimestamp(result);
|
|
130
|
+
if (!firstTs) firstTs = ts;
|
|
131
|
+
if (!threadTs) threadTs = ts;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return { ts: firstTs };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function requireMessageTimestamp(result: { ts?: string } | null | undefined): string {
|
|
138
|
+
if (typeof result?.ts !== 'string' || !result.ts.trim()) {
|
|
139
|
+
throw new Error('Slack chat.postMessage returned no valid ts; delivery is unconfirmed');
|
|
140
|
+
}
|
|
141
|
+
return result.ts;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async function uploadFile(
|
|
145
|
+
client: SlackChatClient,
|
|
146
|
+
channel: string,
|
|
147
|
+
file: { buffer?: Buffer; url?: string; path?: string; name?: string },
|
|
148
|
+
threadTs?: string,
|
|
149
|
+
): Promise<void> {
|
|
150
|
+
if (!client.filesUploadV2) throw new Error('Slack client does not support file uploads');
|
|
151
|
+
let buffer = file.buffer;
|
|
152
|
+
if (!buffer && file.path) {
|
|
153
|
+
const { readFile } = await import('node:fs/promises');
|
|
154
|
+
buffer = await readFile(file.path);
|
|
155
|
+
}
|
|
156
|
+
if (!buffer && file.url) {
|
|
157
|
+
const res = await fetch(file.url);
|
|
158
|
+
if (!res.ok) throw new Error(`fetch ${file.url}: ${res.status}`);
|
|
159
|
+
buffer = Buffer.from(await res.arrayBuffer());
|
|
160
|
+
}
|
|
161
|
+
if (!buffer) throw new Error('Slack file contains no uploadable content');
|
|
162
|
+
|
|
163
|
+
await client.filesUploadV2(
|
|
164
|
+
threadTs
|
|
165
|
+
? { channel_id: channel, file: buffer, filename: file.name ?? 'file', thread_ts: threadTs }
|
|
166
|
+
: { channel_id: channel, file: buffer, filename: file.name ?? 'file' },
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export { keyboardToBlockKitBlocks };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** 将 activity-feedback / 工具入参规范为 Slack reactions.add 的 name(不含冒号) */
|
|
2
|
+
const UNICODE_TO_SLACK: Record<string, string> = {
|
|
3
|
+
'⏳': 'hourglass_flowing_sand',
|
|
4
|
+
'✅': 'white_check_mark',
|
|
5
|
+
'❌': 'x',
|
|
6
|
+
'⏰': 'alarm_clock',
|
|
7
|
+
'🤔': 'thinking_face',
|
|
8
|
+
'👀': 'eyes',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export function normalizeSlackReactionName(emoji: string): string {
|
|
12
|
+
const trimmed = emoji.trim();
|
|
13
|
+
if (!trimmed) return 'hourglass_flowing_sand';
|
|
14
|
+
if (UNICODE_TO_SLACK[trimmed]) return UNICODE_TO_SLACK[trimmed]!;
|
|
15
|
+
if (trimmed.startsWith(':') && trimmed.endsWith(':') && trimmed.length > 2) {
|
|
16
|
+
return trimmed.slice(1, -1);
|
|
17
|
+
}
|
|
18
|
+
let start = 0;
|
|
19
|
+
let end = trimmed.length;
|
|
20
|
+
while (start < end && trimmed[start] === ':') start++;
|
|
21
|
+
while (end > start && trimmed[end - 1] === ':') end--;
|
|
22
|
+
return trimmed.slice(start, end);
|
|
23
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack response_url 即时 ephemeral 反馈(斜杠命令 / 按钮交互)
|
|
3
|
+
*/
|
|
4
|
+
import type { Logger } from '@zhin.js/logger';
|
|
5
|
+
|
|
6
|
+
export function postSlackEphemeral(
|
|
7
|
+
responseUrl: string,
|
|
8
|
+
text: string,
|
|
9
|
+
logger?: Logger,
|
|
10
|
+
): void {
|
|
11
|
+
if (!responseUrl?.trim()) return;
|
|
12
|
+
|
|
13
|
+
const body = JSON.stringify({
|
|
14
|
+
response_type: 'ephemeral',
|
|
15
|
+
text,
|
|
16
|
+
replace_original: false,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
fetch(responseUrl, {
|
|
20
|
+
method: 'POST',
|
|
21
|
+
headers: { 'Content-Type': 'application/json' },
|
|
22
|
+
body,
|
|
23
|
+
}).catch((err) => {
|
|
24
|
+
logger?.debug(`Slack response_url failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack 插件实例的运行时状态:adapter create() 注册的 endpoint 列表。
|
|
3
|
+
* 由 plugin.ts setup() provide,adapter create 与 `slack.endpoint` 命令共享(同一 owner generation)。
|
|
4
|
+
*/
|
|
5
|
+
import { defineEndpointRuntimeStateToken } from 'zhin.js/adapter';
|
|
6
|
+
|
|
7
|
+
export const slackRuntimeStateToken = defineEndpointRuntimeStateToken('slack');
|
package/src/webhook.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack webhook HTTP: signature → parse → admit.
|
|
3
|
+
*/
|
|
4
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
5
|
+
import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
|
|
6
|
+
import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
7
|
+
import {
|
|
8
|
+
headerValue,
|
|
9
|
+
readTextBody,
|
|
10
|
+
verifySlackSignature,
|
|
11
|
+
type ResolvedSlackConfig,
|
|
12
|
+
type SlackInteractionPayload,
|
|
13
|
+
type SlackSlashCommand,
|
|
14
|
+
type SlackUrlVerification,
|
|
15
|
+
} from './protocol.js';
|
|
16
|
+
|
|
17
|
+
const logger = getLogger('slack');
|
|
18
|
+
|
|
19
|
+
export interface SlackWebhookHandler {
|
|
20
|
+
readonly config: ResolvedSlackConfig;
|
|
21
|
+
handleEnvelope(body: unknown): void;
|
|
22
|
+
admitInteraction(payload: SlackInteractionPayload): void;
|
|
23
|
+
admitSlashCommand(cmd: SlackSlashCommand): void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function registerSlackWebhookRoutes(
|
|
27
|
+
http: HttpHost,
|
|
28
|
+
handler: SlackWebhookHandler,
|
|
29
|
+
): HttpRouteRegistration[] {
|
|
30
|
+
const path = handler.config.webhookPath;
|
|
31
|
+
return [
|
|
32
|
+
http.route('POST', path, async (request, response) => {
|
|
33
|
+
await handleSlackWebhookRequest(request, response, handler);
|
|
34
|
+
}, { summary: 'Slack Events API / Interactivity', tags: ['slack'] }),
|
|
35
|
+
];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export async function handleSlackWebhookRequest(
|
|
39
|
+
request: IncomingMessage,
|
|
40
|
+
response: ServerResponse,
|
|
41
|
+
handler: SlackWebhookHandler,
|
|
42
|
+
): Promise<void> {
|
|
43
|
+
try {
|
|
44
|
+
const rawBody = await readTextBody(request);
|
|
45
|
+
const timestamp = headerValue(request.headers, 'x-slack-request-timestamp');
|
|
46
|
+
const signature = headerValue(request.headers, 'x-slack-signature');
|
|
47
|
+
|
|
48
|
+
if (!verifySlackSignature(handler.config.signingSecret, rawBody, timestamp, signature)) {
|
|
49
|
+
response.writeHead(401, { 'Content-Type': 'text/plain' });
|
|
50
|
+
response.end('Invalid signature');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const contentType = headerValue(request.headers, 'content-type');
|
|
55
|
+
if (contentType.includes('application/x-www-form-urlencoded')) {
|
|
56
|
+
const params = new URLSearchParams(rawBody);
|
|
57
|
+
const payloadStr = params.get('payload');
|
|
58
|
+
if (payloadStr) {
|
|
59
|
+
const payload = JSON.parse(payloadStr) as SlackInteractionPayload;
|
|
60
|
+
response.writeHead(200);
|
|
61
|
+
response.end('');
|
|
62
|
+
handler.admitInteraction(payload);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const body = Object.fromEntries(params) as unknown as SlackSlashCommand;
|
|
66
|
+
if (body.command) {
|
|
67
|
+
response.writeHead(200);
|
|
68
|
+
response.end('');
|
|
69
|
+
handler.admitSlashCommand(body);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let envelope: Record<string, unknown>;
|
|
75
|
+
try {
|
|
76
|
+
envelope = JSON.parse(rawBody) as Record<string, unknown>;
|
|
77
|
+
} catch {
|
|
78
|
+
response.writeHead(200);
|
|
79
|
+
response.end('');
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (envelope.type === 'url_verification') {
|
|
84
|
+
const challenge = (envelope as unknown as SlackUrlVerification).challenge;
|
|
85
|
+
response.writeHead(200, { 'Content-Type': 'application/json' });
|
|
86
|
+
response.end(JSON.stringify({ challenge }));
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (envelope.type === 'event_callback' && envelope.event) {
|
|
91
|
+
response.writeHead(200);
|
|
92
|
+
response.end('');
|
|
93
|
+
handler.handleEnvelope(envelope);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
response.writeHead(200);
|
|
98
|
+
response.end('');
|
|
99
|
+
} catch (error) {
|
|
100
|
+
logger.error('Slack webhook error:', error);
|
|
101
|
+
if (!response.headersSent) {
|
|
102
|
+
response.writeHead(200);
|
|
103
|
+
response.end('');
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
package/lib/adapter.d.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Slack 适配器
|
|
3
|
-
*/
|
|
4
|
-
import { Adapter, Plugin } from "zhin.js";
|
|
5
|
-
import { SlackBot } from "./bot.js";
|
|
6
|
-
import type { SlackBotConfig } from "./types.js";
|
|
7
|
-
export declare class SlackAdapter extends Adapter<SlackBot> {
|
|
8
|
-
constructor(plugin: Plugin);
|
|
9
|
-
createBot(config: SlackBotConfig): SlackBot;
|
|
10
|
-
kickMember(botId: string, sceneId: string, userId: string): Promise<boolean>;
|
|
11
|
-
setGroupName(botId: string, sceneId: string, name: string): Promise<boolean>;
|
|
12
|
-
listMembers(botId: string, sceneId: string): Promise<string[]>;
|
|
13
|
-
getGroupInfo(botId: string, sceneId: string): Promise<any>;
|
|
14
|
-
start(): Promise<void>;
|
|
15
|
-
}
|
|
16
|
-
//# sourceMappingURL=adapter.d.ts.map
|
package/lib/adapter.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EACL,OAAO,EACP,MAAM,EACP,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,qBAAa,YAAa,SAAQ,OAAO,CAAC,QAAQ,CAAC;gBACrC,MAAM,EAAE,MAAM;IAI1B,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,QAAQ;IAMrC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAMzD,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAMzD,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAM1C,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAQ3C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAI7B"}
|
package/lib/adapter.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Slack 适配器
|
|
3
|
-
*/
|
|
4
|
-
import { Adapter, } from "zhin.js";
|
|
5
|
-
import { SlackBot } from "./bot.js";
|
|
6
|
-
export class SlackAdapter extends Adapter {
|
|
7
|
-
constructor(plugin) {
|
|
8
|
-
super(plugin, "slack", []);
|
|
9
|
-
}
|
|
10
|
-
createBot(config) {
|
|
11
|
-
return new SlackBot(this, config);
|
|
12
|
-
}
|
|
13
|
-
// ── IGroupManagement 标准群管方法 ──────────────────────────────────
|
|
14
|
-
async kickMember(botId, sceneId, userId) {
|
|
15
|
-
const bot = this.bots.get(botId);
|
|
16
|
-
if (!bot)
|
|
17
|
-
throw new Error(`Bot ${botId} 不存在`);
|
|
18
|
-
return bot.kickFromChannel(sceneId, userId);
|
|
19
|
-
}
|
|
20
|
-
async setGroupName(botId, sceneId, name) {
|
|
21
|
-
const bot = this.bots.get(botId);
|
|
22
|
-
if (!bot)
|
|
23
|
-
throw new Error(`Bot ${botId} 不存在`);
|
|
24
|
-
return bot.renameChannel(sceneId, name);
|
|
25
|
-
}
|
|
26
|
-
async listMembers(botId, sceneId) {
|
|
27
|
-
const bot = this.bots.get(botId);
|
|
28
|
-
if (!bot)
|
|
29
|
-
throw new Error(`Bot ${botId} 不存在`);
|
|
30
|
-
return bot.getChannelMembers(sceneId);
|
|
31
|
-
}
|
|
32
|
-
async getGroupInfo(botId, sceneId) {
|
|
33
|
-
const bot = this.bots.get(botId);
|
|
34
|
-
if (!bot)
|
|
35
|
-
throw new Error(`Bot ${botId} 不存在`);
|
|
36
|
-
return bot.getChannelInfo(sceneId);
|
|
37
|
-
}
|
|
38
|
-
// ── 生命周期 ───────────────────────────────────────────────────────
|
|
39
|
-
async start() {
|
|
40
|
-
await super.start();
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
//# sourceMappingURL=adapter.js.map
|
package/lib/adapter.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EACL,OAAO,GAER,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAGpC,MAAM,OAAO,YAAa,SAAQ,OAAiB;IACjD,YAAY,MAAc;QACxB,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IAC7B,CAAC;IAED,SAAS,CAAC,MAAsB;QAC9B,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACpC,CAAC;IAED,gEAAgE;IAEhE,KAAK,CAAC,UAAU,CAAC,KAAa,EAAE,OAAe,EAAE,MAAc;QAC7D,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC;QAC9C,OAAO,GAAG,CAAC,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,KAAa,EAAE,OAAe,EAAE,IAAY;QAC7D,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC;QAC9C,OAAO,GAAG,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAa,EAAE,OAAe;QAC9C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC;QAC9C,OAAO,GAAG,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,KAAa,EAAE,OAAe;QAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC;QAC9C,OAAO,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IAED,kEAAkE;IAElE,KAAK,CAAC,KAAK;QACT,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;CAEF"}
|
package/lib/bot.d.ts
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { Bot, Message, SendOptions } from 'zhin.js';
|
|
2
|
-
import type { SlackBotConfig, SlackMessageEvent } from "./types.js";
|
|
3
|
-
import type { SlackAdapter } from "./adapter.js";
|
|
4
|
-
export declare class SlackBot implements Bot<SlackBotConfig, SlackMessageEvent> {
|
|
5
|
-
#private;
|
|
6
|
-
adapter: SlackAdapter;
|
|
7
|
-
$config: SlackBotConfig;
|
|
8
|
-
$connected: boolean;
|
|
9
|
-
/** 延迟到 `$connect`,避免子类 mock `$connect` 时仍在构造函数里创建 Bolt/WebClient(会在后台触发 Slack API) */
|
|
10
|
-
private app?;
|
|
11
|
-
private client?;
|
|
12
|
-
get logger(): import("zhin.js").Logger;
|
|
13
|
-
get $id(): string;
|
|
14
|
-
constructor(adapter: SlackAdapter, $config: SlackBotConfig);
|
|
15
|
-
$connect(): Promise<void>;
|
|
16
|
-
$disconnect(): Promise<void>;
|
|
17
|
-
private handleSlackMessage;
|
|
18
|
-
$formatMessage(msg: SlackMessageEvent): Message<SlackMessageEvent>;
|
|
19
|
-
private parseMessageContent;
|
|
20
|
-
private parseSlackText;
|
|
21
|
-
$sendMessage(options: SendOptions): Promise<string>;
|
|
22
|
-
private sendContentToChannel;
|
|
23
|
-
$recallMessage(id: string): Promise<void>;
|
|
24
|
-
/**
|
|
25
|
-
* 邀请用户到频道
|
|
26
|
-
* @param channel 频道 ID
|
|
27
|
-
* @param users 用户 ID 列表
|
|
28
|
-
*/
|
|
29
|
-
inviteToChannel(channel: string, users: string[]): Promise<boolean>;
|
|
30
|
-
/**
|
|
31
|
-
* 从频道踢出用户
|
|
32
|
-
* @param channel 频道 ID
|
|
33
|
-
* @param user 用户 ID
|
|
34
|
-
*/
|
|
35
|
-
kickFromChannel(channel: string, user: string): Promise<boolean>;
|
|
36
|
-
/**
|
|
37
|
-
* 设置频道话题
|
|
38
|
-
* @param channel 频道 ID
|
|
39
|
-
* @param topic 话题
|
|
40
|
-
*/
|
|
41
|
-
setChannelTopic(channel: string, topic: string): Promise<boolean>;
|
|
42
|
-
/**
|
|
43
|
-
* 设置频道目的
|
|
44
|
-
* @param channel 频道 ID
|
|
45
|
-
* @param purpose 目的
|
|
46
|
-
*/
|
|
47
|
-
setChannelPurpose(channel: string, purpose: string): Promise<boolean>;
|
|
48
|
-
/**
|
|
49
|
-
* 归档频道
|
|
50
|
-
* @param channel 频道 ID
|
|
51
|
-
*/
|
|
52
|
-
archiveChannel(channel: string): Promise<boolean>;
|
|
53
|
-
/**
|
|
54
|
-
* 取消归档频道
|
|
55
|
-
* @param channel 频道 ID
|
|
56
|
-
*/
|
|
57
|
-
unarchiveChannel(channel: string): Promise<boolean>;
|
|
58
|
-
/**
|
|
59
|
-
* 重命名频道
|
|
60
|
-
* @param channel 频道 ID
|
|
61
|
-
* @param name 新名称
|
|
62
|
-
*/
|
|
63
|
-
renameChannel(channel: string, name: string): Promise<boolean>;
|
|
64
|
-
/**
|
|
65
|
-
* 获取频道成员列表
|
|
66
|
-
* @param channel 频道 ID
|
|
67
|
-
*/
|
|
68
|
-
getChannelMembers(channel: string): Promise<string[]>;
|
|
69
|
-
/**
|
|
70
|
-
* 获取频道信息
|
|
71
|
-
* @param channel 频道 ID
|
|
72
|
-
*/
|
|
73
|
-
getChannelInfo(channel: string): Promise<any>;
|
|
74
|
-
/**
|
|
75
|
-
* 获取用户信息
|
|
76
|
-
* @param user 用户 ID
|
|
77
|
-
*/
|
|
78
|
-
getUserInfo(user: string): Promise<any>;
|
|
79
|
-
/**
|
|
80
|
-
* 添加消息反应
|
|
81
|
-
* @param channel 频道 ID
|
|
82
|
-
* @param timestamp 消息时间戳
|
|
83
|
-
* @param name 表情名称
|
|
84
|
-
*/
|
|
85
|
-
addReaction(channel: string, timestamp: string, name: string): Promise<boolean>;
|
|
86
|
-
/**
|
|
87
|
-
* 移除消息反应
|
|
88
|
-
* @param channel 频道 ID
|
|
89
|
-
* @param timestamp 消息时间戳
|
|
90
|
-
* @param name 表情名称
|
|
91
|
-
*/
|
|
92
|
-
removeReaction(channel: string, timestamp: string, name: string): Promise<boolean>;
|
|
93
|
-
/**
|
|
94
|
-
* 置顶消息
|
|
95
|
-
* @param channel 频道 ID
|
|
96
|
-
* @param timestamp 消息时间戳
|
|
97
|
-
*/
|
|
98
|
-
pinMessage(channel: string, timestamp: string): Promise<boolean>;
|
|
99
|
-
/**
|
|
100
|
-
* 取消置顶消息
|
|
101
|
-
* @param channel 频道 ID
|
|
102
|
-
* @param timestamp 消息时间戳
|
|
103
|
-
*/
|
|
104
|
-
unpinMessage(channel: string, timestamp: string): Promise<boolean>;
|
|
105
|
-
}
|
|
106
|
-
//# sourceMappingURL=bot.d.ts.map
|
package/lib/bot.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bot.d.ts","sourceRoot":"","sources":["../src/bot.ts"],"names":[],"mappings":"AAKA,OAAO,EAAiB,GAAG,EAAE,OAAO,EAAwC,WAAW,EAAE,MAAM,SAAS,CAAC;AACzG,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGjD,qBAAa,QAAS,YAAW,GAAG,CAAC,cAAc,EAAE,iBAAiB,CAAC;;IAclD,OAAO,EAAE,YAAY;IAAS,OAAO,EAAE,cAAc;IAbxE,UAAU,EAAE,OAAO,CAAC;IACpB,sFAAsF;IACtF,OAAO,CAAC,GAAG,CAAC,CAAW;IACvB,OAAO,CAAC,MAAM,CAAC,CAAY;IAE3B,IAAI,MAAM,6BAET;IAED,IAAI,GAAG,WAEN;gBAEkB,OAAO,EAAE,YAAY,EAAS,OAAO,EAAE,cAAc;IA0BlE,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAqCzB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;YAepB,kBAAkB;IAahC,cAAc,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAoElE,OAAO,CAAC,mBAAmB;IAiF3B,OAAO,CAAC,cAAc;IA+FhB,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;YAgB3C,oBAAoB;IAmF5B,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY/C;;;;OAIG;IACG,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAWzE;;;;OAIG;IACG,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWtE;;;;OAIG;IACG,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWvE;;;;OAIG;IACG,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAW3E;;;OAGG;IACG,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWvD;;;OAGG;IACG,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWzD;;;;OAIG;IACG,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWpE;;;OAGG;IACG,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAU3D;;;OAGG;IACG,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAUnD;;;OAGG;IACG,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAU7C;;;;;OAKG;IACG,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWrF;;;;;OAKG;IACG,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWxF;;;;OAIG;IACG,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWtE;;;;OAIG;IACG,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAUzE"}
|