@zhin.js/adapter-slack 1.1.0 → 1.1.3
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 +108 -0
- package/README.md +13 -14
- package/adapters/{slack.js → slack/index.js} +6 -6
- package/adapters/{slack.ts → slack/index.ts} +9 -9
- package/agents/slack/agent.json +20 -0
- package/agents/slack/boundaries.md +3 -0
- package/agents/slack/conventions.md +3 -0
- package/agents/slack/skills/slack-channels/SKILL.md +24 -0
- package/agents/slack/skills/slack-channels/tools/archive_channel/index.js +19 -0
- package/{agent/tools/archive_channel.ts → agents/slack/skills/slack-channels/tools/archive_channel/index.ts} +3 -3
- package/agents/slack/skills/slack-channels/tools/invite_to_channel/index.js +20 -0
- package/{agent/tools/invite_to_channel.ts → agents/slack/skills/slack-channels/tools/invite_to_channel/index.ts} +3 -3
- package/agents/slack/skills/slack-channels/tools/set_purpose/index.js +20 -0
- package/{agent/tools/set_purpose.ts → agents/slack/skills/slack-channels/tools/set_purpose/index.ts} +3 -3
- package/agents/slack/skills/slack-channels/tools/set_topic/index.js +20 -0
- package/{agent/tools/set_topic.ts → agents/slack/skills/slack-channels/tools/set_topic/index.ts} +3 -3
- package/agents/slack/skills/slack-channels/tools/unarchive/index.js +19 -0
- package/{agent/tools/unarchive.ts → agents/slack/skills/slack-channels/tools/unarchive/index.ts} +3 -3
- package/agents/slack/skills/slack-channels/tools/user_info/index.js +27 -0
- package/{agent/tools/user_info.ts → agents/slack/skills/slack-channels/tools/user_info/index.ts} +2 -2
- package/agents/slack/skills/slack-messages/SKILL.md +22 -0
- package/agents/slack/skills/slack-messages/tools/add_reaction/index.js +27 -0
- package/{agent/tools/add_reaction.ts → agents/slack/skills/slack-messages/tools/add_reaction/index.ts} +2 -2
- package/agents/slack/skills/slack-messages/tools/edit_message/index.js +21 -0
- package/{agent/tools/edit_message.ts → agents/slack/skills/slack-messages/tools/edit_message/index.ts} +2 -2
- package/agents/slack/skills/slack-messages/tools/pin_message/index.js +20 -0
- package/{agent/tools/pin_message.ts → agents/slack/skills/slack-messages/tools/pin_message/index.ts} +3 -3
- package/agents/slack/skills/slack-messages/tools/remove_reaction/index.js +30 -0
- package/{agent/tools/remove_reaction.ts → agents/slack/skills/slack-messages/tools/remove_reaction/index.ts} +2 -2
- package/agents/slack/skills/slack-messages/tools/unpin_message/index.js +20 -0
- package/{agent/tools/unpin_message.ts → agents/slack/skills/slack-messages/tools/unpin_message/index.ts} +3 -3
- package/agents/slack/system.md +3 -0
- package/commands/{endpoint/add/[id].js → slack/endpoint/add/[id]/index.js} +1 -1
- package/commands/slack/endpoint/add/[id]/index.ts +3 -0
- package/{lib/slack-endpoint-commands.js → commands/slack/endpoint/definition.js} +4 -3
- package/{src/slack-endpoint-commands.ts → commands/slack/endpoint/definition.ts} +3 -3
- package/commands/{endpoint/list.js → slack/endpoint/list/index.js} +1 -1
- package/commands/slack/endpoint/list/index.ts +3 -0
- package/commands/{endpoint/remove/[id].js → slack/endpoint/remove/[id]/index.js} +1 -1
- package/commands/slack/endpoint/remove/[id]/index.ts +3 -0
- package/lib/index.d.ts +1 -1
- package/lib/protocol.d.ts +6 -15
- package/lib/protocol.js +19 -33
- package/lib/slack-runtime-state.js +1 -1
- package/package.json +33 -21
- package/schema.json +14 -1
- package/src/index.ts +1 -1
- package/src/protocol.ts +27 -56
- package/src/slack-runtime-state.ts +1 -1
- package/agent/skills/slack.md +0 -93
- package/commands/endpoint/add/[id].ts +0 -3
- package/commands/endpoint/list.ts +0 -3
- package/commands/endpoint/remove/[id].ts +0 -3
- package/lib/slack-endpoint-commands.d.ts +0 -1
- /package/{agent/PERMITS.md → PERMITS.md} +0 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { platformPermission } from '@zhin.js/permission';
|
|
5
|
+
export default defineAgentTool({
|
|
6
|
+
description: '置顶 Slack 消息',
|
|
7
|
+
inputSchema: z.object({
|
|
8
|
+
channel: z.string().describe('频道 ID'),
|
|
9
|
+
timestamp: z.string().describe('消息时间戳'),
|
|
10
|
+
}),
|
|
11
|
+
adapter: 'slack',
|
|
12
|
+
tags: ['slack'],
|
|
13
|
+
permissions: [platformPermission('slack', 'channel_manager')],
|
|
14
|
+
async execute({ channel, timestamp }, context) {
|
|
15
|
+
const client = context.$client;
|
|
16
|
+
await client.pins.add({ channel, timestamp });
|
|
17
|
+
const success = true;
|
|
18
|
+
return { success, message: success ? '已置顶消息' : '操作失败' };
|
|
19
|
+
},
|
|
20
|
+
});
|
package/{agent/tools/pin_message.ts → agents/slack/skills/slack-messages/tools/pin_message/index.ts}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { defineAgentTool } from '@zhin.js/
|
|
1
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import {
|
|
3
|
+
import { platformPermission } from '@zhin.js/permission';
|
|
4
4
|
|
|
5
5
|
export default defineAgentTool<{
|
|
6
6
|
channel: string;
|
|
@@ -13,7 +13,7 @@ export default defineAgentTool<{
|
|
|
13
13
|
}),
|
|
14
14
|
adapter: 'slack',
|
|
15
15
|
tags: ['slack'],
|
|
16
|
-
permissions: [
|
|
16
|
+
permissions: [platformPermission('slack', 'channel_manager')],
|
|
17
17
|
async execute({ channel, timestamp }, context) {
|
|
18
18
|
const client = context.$client;
|
|
19
19
|
await client.pins.add({ channel, timestamp });
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { normalizeSlackReactionName } from '@zhin.js/adapter-slack';
|
|
5
|
+
export default defineAgentTool({
|
|
6
|
+
description: '移除 Slack 消息上的表情反应',
|
|
7
|
+
inputSchema: z.object({
|
|
8
|
+
channel_id: z.string().describe('频道 ID'),
|
|
9
|
+
timestamp: z.string().describe('消息时间戳'),
|
|
10
|
+
name: z.string().describe('表情名称(如 thumbsup、heart)'),
|
|
11
|
+
}),
|
|
12
|
+
adapter: 'slack',
|
|
13
|
+
tags: ['slack'],
|
|
14
|
+
async execute({ channel_id, timestamp, name }, context) {
|
|
15
|
+
const client = context.$client;
|
|
16
|
+
try {
|
|
17
|
+
await client.reactions.remove({
|
|
18
|
+
channel: channel_id,
|
|
19
|
+
timestamp,
|
|
20
|
+
name: normalizeSlackReactionName(name),
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
if (error?.data?.error !== 'no_reaction')
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
const success = true;
|
|
28
|
+
return { success, message: success ? `已移除反应 :${name}:` : '操作失败' };
|
|
29
|
+
},
|
|
30
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { defineAgentTool } from '@zhin.js/
|
|
1
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { normalizeSlackReactionName } from '
|
|
3
|
+
import { normalizeSlackReactionName } from '@zhin.js/adapter-slack';
|
|
4
4
|
|
|
5
5
|
export default defineAgentTool<{
|
|
6
6
|
channel_id: string;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { platformPermission } from '@zhin.js/permission';
|
|
5
|
+
export default defineAgentTool({
|
|
6
|
+
description: '取消 Slack 频道中消息的置顶',
|
|
7
|
+
inputSchema: z.object({
|
|
8
|
+
channel_id: z.string().describe('频道 ID'),
|
|
9
|
+
timestamp: z.string().describe('消息时间戳'),
|
|
10
|
+
}),
|
|
11
|
+
adapter: 'slack',
|
|
12
|
+
tags: ['slack'],
|
|
13
|
+
permissions: [platformPermission('slack', 'channel_manager')],
|
|
14
|
+
async execute({ channel_id, timestamp }, context) {
|
|
15
|
+
const client = context.$client;
|
|
16
|
+
await client.pins.remove({ channel: channel_id, timestamp });
|
|
17
|
+
const success = true;
|
|
18
|
+
return { success, message: success ? '已取消置顶' : '操作失败' };
|
|
19
|
+
},
|
|
20
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { defineAgentTool } from '@zhin.js/
|
|
1
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import {
|
|
3
|
+
import { platformPermission } from '@zhin.js/permission';
|
|
4
4
|
|
|
5
5
|
export default defineAgentTool<{
|
|
6
6
|
channel_id: string;
|
|
@@ -13,7 +13,7 @@ export default defineAgentTool<{
|
|
|
13
13
|
}),
|
|
14
14
|
adapter: 'slack',
|
|
15
15
|
tags: ['slack'],
|
|
16
|
-
permissions: [
|
|
16
|
+
permissions: [platformPermission('slack', 'channel_manager')],
|
|
17
17
|
async execute({ channel_id, timestamp }, context) {
|
|
18
18
|
const client = context.$client;
|
|
19
19
|
await client.pins.remove({ channel: channel_id, timestamp });
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
1
2
|
/**
|
|
2
|
-
* `slack
|
|
3
|
-
* commands/endpoint/ 下的 list / add / remove 直接默认导出这三项。
|
|
3
|
+
* `slack endpoint` 命令族:由 @zhin.js/adapter 的 createEndpointCommands 套件生成。
|
|
4
|
+
* commands/slack/endpoint/ 下的 list / add / remove 直接默认导出这三项。
|
|
4
5
|
*/
|
|
5
6
|
import { createEndpointCommands } from 'zhin.js/adapter';
|
|
6
7
|
import { defineCommand } from 'zhin.js/command';
|
|
7
|
-
import { slackRuntimeStateToken } from
|
|
8
|
+
import { slackRuntimeStateToken } from "../../../lib/slack-runtime-state.js";
|
|
8
9
|
export const slackEndpointCommands = createEndpointCommands({
|
|
9
10
|
adapterKey: 'slack',
|
|
10
11
|
adapterDisplayName: 'Slack',
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `slack
|
|
3
|
-
* commands/endpoint/ 下的 list / add / remove 直接默认导出这三项。
|
|
2
|
+
* `slack endpoint` 命令族:由 @zhin.js/adapter 的 createEndpointCommands 套件生成。
|
|
3
|
+
* commands/slack/endpoint/ 下的 list / add / remove 直接默认导出这三项。
|
|
4
4
|
*/
|
|
5
5
|
import { createEndpointCommands } from 'zhin.js/adapter';
|
|
6
6
|
import { defineCommand } from 'zhin.js/command';
|
|
7
|
-
import { slackRuntimeStateToken } from '
|
|
7
|
+
import { slackRuntimeStateToken } from '../../../src/slack-runtime-state.js';
|
|
8
8
|
|
|
9
9
|
export const slackEndpointCommands = createEndpointCommands({
|
|
10
10
|
adapterKey: 'slack',
|
package/lib/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { formatInboundContent, formatInteractionContent, formatOutboundWire, formatSlashContent, headerValue, keyboardToBlockKitBlocks, normalizeWebhookPath, readTextBody, resolveSlackChannelType, resolveSlackConfig, slackInboundConversation, verifySlackSignature, type ResolvedSlackConfig, type
|
|
1
|
+
export { formatInboundContent, formatInteractionContent, formatOutboundWire, formatSlashContent, headerValue, keyboardToBlockKitBlocks, normalizeWebhookPath, readTextBody, resolveSlackChannelType, resolveSlackConfig, slackInboundConversation, verifySlackSignature, type ResolvedSlackConfig, type SlackEndpointConfig, type SlackBlockAction, type SlackEvent, type SlackEventEnvelope, type SlackInteractionPayload, type SlackMessageEvent, type SlackSlashCommand, type SlackUrlVerification, type SlackWireSegment, } from './protocol.js';
|
|
2
2
|
export { SlackEndpoint, type SlackEndpointOptions, type SlackSocketLike, type SlackWebClientLike, } from './endpoint.js';
|
|
3
3
|
export { registerSlackWebhookRoutes, handleSlackWebhookRequest, type SlackWebhookHandler, } from './webhook.js';
|
|
4
4
|
export { slackClient, type SlackClientEventMap, type SlackUserInfo, } from './client.js';
|
package/lib/protocol.d.ts
CHANGED
|
@@ -1,24 +1,15 @@
|
|
|
1
1
|
import type { IncomingMessage } from 'node:http';
|
|
2
|
-
import type
|
|
3
|
-
/**
|
|
4
|
-
export interface
|
|
5
|
-
readonly id
|
|
6
|
-
readonly token
|
|
2
|
+
import { type ConversationRef } from '@zhin.js/im-contract';
|
|
3
|
+
/** One endpoint config after AdapterIndex expands `plugins.<instanceKey>.endpoints`. */
|
|
4
|
+
export interface SlackEndpointConfig {
|
|
5
|
+
readonly id: string;
|
|
6
|
+
readonly token: string;
|
|
7
7
|
readonly signingSecret?: string;
|
|
8
8
|
readonly appToken?: string;
|
|
9
9
|
/** Default true (Socket Mode). Set false for HTTP Events API via httpHostToken. */
|
|
10
10
|
readonly socketMode?: boolean;
|
|
11
11
|
readonly webhookPath?: string;
|
|
12
12
|
readonly clientPingTimeout?: number;
|
|
13
|
-
/** Transitional: legacy root `endpoints[]` with `context: slack`. */
|
|
14
|
-
readonly endpoints?: ReadonlyArray<Partial<ResolvedSlackConfig> & {
|
|
15
|
-
readonly context?: string;
|
|
16
|
-
readonly socketMode?: boolean;
|
|
17
|
-
readonly signingSecret?: string;
|
|
18
|
-
readonly appToken?: string;
|
|
19
|
-
readonly webhookPath?: string;
|
|
20
|
-
readonly clientPingTimeout?: number;
|
|
21
|
-
}>;
|
|
22
13
|
}
|
|
23
14
|
export interface ResolvedSlackConfig {
|
|
24
15
|
readonly context: 'slack';
|
|
@@ -113,7 +104,7 @@ export interface SlackWireSegment {
|
|
|
113
104
|
readonly type: string;
|
|
114
105
|
readonly data?: Record<string, unknown>;
|
|
115
106
|
}
|
|
116
|
-
export declare function resolveSlackConfig(config
|
|
107
|
+
export declare function resolveSlackConfig(config: SlackEndpointConfig): ResolvedSlackConfig;
|
|
117
108
|
export declare function normalizeWebhookPath(path: string): string;
|
|
118
109
|
export declare function resolveSlackChannelType(event: Pick<SlackEvent, 'channel_type'>): 'private' | 'group';
|
|
119
110
|
/**
|
package/lib/protocol.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Canonicalization is owned by gateway/core before endpoint.send.
|
|
4
4
|
*/
|
|
5
5
|
import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
6
|
-
import { isMediaRef } from '@zhin.js/
|
|
6
|
+
import { isMediaRef } from '@zhin.js/im-contract';
|
|
7
7
|
import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
8
8
|
import { mrkdwnToMarkdown } from './mrkdwn-to-markdown.js';
|
|
9
9
|
const logger = getLogger('slack');
|
|
@@ -13,36 +13,18 @@ function dropOutboundMedia(type, reason) {
|
|
|
13
13
|
}
|
|
14
14
|
const SLACK_SIG_VERSION = 'v0';
|
|
15
15
|
const MAX_TIMESTAMP_DRIFT_SECONDS = 300;
|
|
16
|
-
export function resolveSlackConfig(config
|
|
17
|
-
const
|
|
18
|
-
const token = config.token
|
|
19
|
-
|
|
20
|
-
?? process.env.SLACK_BOT_TOKEN
|
|
21
|
-
?? process.env.SLACK_TOKEN;
|
|
22
|
-
if (!token) {
|
|
23
|
-
throw new TypeError('Slack adapter requires token (plugins.<key>.token or endpoints with context: slack)');
|
|
24
|
-
}
|
|
25
|
-
const id = (typeof config.id === 'string' && config.id)
|
|
26
|
-
|| (typeof entry?.id === 'string' && entry.id)
|
|
27
|
-
|| process.env.SLACK_BOT_NAME
|
|
28
|
-
|| 'slack-bot';
|
|
29
|
-
const socketMode = config.socketMode ?? entry?.socketMode;
|
|
16
|
+
export function resolveSlackConfig(config) {
|
|
17
|
+
const id = requiredEndpointField(config.id, 'id');
|
|
18
|
+
const token = requiredEndpointField(config.token, 'token');
|
|
19
|
+
const socketMode = config.socketMode;
|
|
30
20
|
// Prefer Socket Mode (default true) — no public URL required.
|
|
31
21
|
const mode = socketMode === false ? 'http' : 'socket';
|
|
32
|
-
const signingSecret =
|
|
33
|
-
|
|
34
|
-
??
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
?? process.env.SLACK_APP_TOKEN
|
|
39
|
-
?? undefined;
|
|
40
|
-
if (mode === 'socket' && !appToken) {
|
|
41
|
-
throw new TypeError('Slack Socket Mode requires appToken (xapp-...); set socketMode: false for HTTP Events API');
|
|
42
|
-
}
|
|
43
|
-
if (mode === 'http' && !signingSecret) {
|
|
44
|
-
throw new TypeError('Slack HTTP Events API requires signingSecret');
|
|
45
|
-
}
|
|
22
|
+
const signingSecret = mode === 'http'
|
|
23
|
+
? requiredEndpointField(config.signingSecret, 'signingSecret')
|
|
24
|
+
: config.signingSecret?.trim() ?? '';
|
|
25
|
+
const appToken = mode === 'socket'
|
|
26
|
+
? requiredEndpointField(config.appToken, 'appToken')
|
|
27
|
+
: config.appToken?.trim();
|
|
46
28
|
return {
|
|
47
29
|
context: 'slack',
|
|
48
30
|
id,
|
|
@@ -50,12 +32,16 @@ export function resolveSlackConfig(config = {}) {
|
|
|
50
32
|
mode,
|
|
51
33
|
signingSecret,
|
|
52
34
|
appToken,
|
|
53
|
-
webhookPath: normalizeWebhookPath(config.webhookPath ??
|
|
54
|
-
clientPingTimeout: config.clientPingTimeout
|
|
55
|
-
?? entry?.clientPingTimeout
|
|
56
|
-
?? 15_000,
|
|
35
|
+
webhookPath: normalizeWebhookPath(config.webhookPath ?? '/slack/events'),
|
|
36
|
+
clientPingTimeout: config.clientPingTimeout ?? 15_000,
|
|
57
37
|
};
|
|
58
38
|
}
|
|
39
|
+
function requiredEndpointField(value, field) {
|
|
40
|
+
if (typeof value !== 'string' || !value.trim()) {
|
|
41
|
+
throw new TypeError(`Slack endpoint requires a non-empty ${field}`);
|
|
42
|
+
}
|
|
43
|
+
return value.trim();
|
|
44
|
+
}
|
|
59
45
|
export function normalizeWebhookPath(path) {
|
|
60
46
|
const trimmed = path.trim() || '/slack/events';
|
|
61
47
|
return trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Slack 插件实例的运行时状态:adapter create() 注册的 endpoint 列表。
|
|
3
|
-
* 由 plugin.ts setup() provide,adapter create 与 `slack
|
|
3
|
+
* 由 plugin.ts setup() provide,adapter create 与 `slack endpoint` 命令共享(同一 owner generation)。
|
|
4
4
|
*/
|
|
5
5
|
import { defineEndpointRuntimeStateToken } from 'zhin.js/adapter';
|
|
6
6
|
export const slackRuntimeStateToken = defineEndpointRuntimeStateToken('slack');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-slack",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"description": "Zhin.js Slack adapter for Plugin Runtime (Socket Mode / HTTP Events)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -34,27 +34,26 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@slack/socket-mode": "^2.0.7",
|
|
36
36
|
"@slack/web-api": "^7.19.0",
|
|
37
|
-
"@zhin.js/adapter": "1.1.
|
|
38
|
-
"@zhin.js/
|
|
39
|
-
"@zhin.js/
|
|
40
|
-
"@zhin.js/
|
|
41
|
-
"@zhin.js/
|
|
42
|
-
"@zhin.js/
|
|
37
|
+
"@zhin.js/adapter": "1.1.15",
|
|
38
|
+
"@zhin.js/agent-feature": "1.1.2",
|
|
39
|
+
"@zhin.js/core": "1.1.38",
|
|
40
|
+
"@zhin.js/feature-kit": "1.1.2",
|
|
41
|
+
"@zhin.js/host-http": "1.1.2",
|
|
42
|
+
"@zhin.js/im-contract": "1.1.2",
|
|
43
|
+
"@zhin.js/logger": "1.1.1",
|
|
44
|
+
"@zhin.js/skill": "1.1.2",
|
|
45
|
+
"@zhin.js/tool": "1.1.2"
|
|
43
46
|
},
|
|
44
47
|
"peerDependencies": {
|
|
45
48
|
"zod": "^4.0.0",
|
|
46
|
-
"@zhin.js/adapter": "^1.1.
|
|
47
|
-
"@zhin.js/
|
|
48
|
-
"@zhin.js/
|
|
49
|
-
"@zhin.js/
|
|
50
|
-
"@zhin.js/
|
|
51
|
-
"
|
|
52
|
-
"zhin.js": "^1.1.0"
|
|
49
|
+
"@zhin.js/adapter": "^1.1.15",
|
|
50
|
+
"@zhin.js/command": "^1.1.2",
|
|
51
|
+
"@zhin.js/core": "^1.1.38",
|
|
52
|
+
"@zhin.js/host-http": "^1.1.2",
|
|
53
|
+
"@zhin.js/permission": "^1.1.2",
|
|
54
|
+
"zhin.js": "^1.1.3"
|
|
53
55
|
},
|
|
54
56
|
"peerDependenciesMeta": {
|
|
55
|
-
"@zhin.js/agent": {
|
|
56
|
-
"optional": true
|
|
57
|
-
},
|
|
58
57
|
"@zhin.js/command": {
|
|
59
58
|
"optional": true
|
|
60
59
|
},
|
|
@@ -70,8 +69,7 @@
|
|
|
70
69
|
"typescript": "^6.0.3",
|
|
71
70
|
"vitest": "^4.1.10",
|
|
72
71
|
"zod": "^4.4.3",
|
|
73
|
-
"
|
|
74
|
-
"zhin.js": "1.1.0"
|
|
72
|
+
"zhin.js": "1.1.3"
|
|
75
73
|
},
|
|
76
74
|
"files": [
|
|
77
75
|
"adapters",
|
|
@@ -80,9 +78,11 @@
|
|
|
80
78
|
"schema.json",
|
|
81
79
|
"src",
|
|
82
80
|
"lib",
|
|
83
|
-
"
|
|
81
|
+
"tools",
|
|
82
|
+
"agents",
|
|
84
83
|
"README.md",
|
|
85
|
-
"CHANGELOG.md"
|
|
84
|
+
"CHANGELOG.md",
|
|
85
|
+
"PERMITS.md"
|
|
86
86
|
],
|
|
87
87
|
"publishConfig": {
|
|
88
88
|
"access": "public",
|
|
@@ -105,6 +105,18 @@
|
|
|
105
105
|
{
|
|
106
106
|
"package": "@zhin.js/command",
|
|
107
107
|
"api": "^1.0.0"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"package": "@zhin.js/tool",
|
|
111
|
+
"api": "^1.0.0"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"package": "@zhin.js/skill",
|
|
115
|
+
"api": "^1.0.0"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"package": "@zhin.js/agent-feature",
|
|
119
|
+
"api": "^1.0.0"
|
|
108
120
|
}
|
|
109
121
|
],
|
|
110
122
|
"plugins": []
|
package/schema.json
CHANGED
|
@@ -37,10 +37,11 @@
|
|
|
37
37
|
},
|
|
38
38
|
"endpoints": {
|
|
39
39
|
"type": "array",
|
|
40
|
+
"minItems": 1,
|
|
40
41
|
"description": "多账号:一个插件实例挂多个 endpoint。每项与顶层字段同构(id 必填,其余覆盖顶层)",
|
|
41
42
|
"items": {
|
|
42
43
|
"type": "object",
|
|
43
|
-
"additionalProperties":
|
|
44
|
+
"additionalProperties": false,
|
|
44
45
|
"properties": {
|
|
45
46
|
"master": {
|
|
46
47
|
"type": [
|
|
@@ -72,6 +73,18 @@
|
|
|
72
73
|
"type": "string",
|
|
73
74
|
"description": "App-Level Token (xapp-...) for Socket Mode"
|
|
74
75
|
},
|
|
76
|
+
"socketMode": {
|
|
77
|
+
"type": "boolean"
|
|
78
|
+
},
|
|
79
|
+
"webhookPath": {
|
|
80
|
+
"type": "string"
|
|
81
|
+
},
|
|
82
|
+
"clientPingTimeout": {
|
|
83
|
+
"type": "number"
|
|
84
|
+
},
|
|
85
|
+
"commandPrefix": {
|
|
86
|
+
"type": "string"
|
|
87
|
+
},
|
|
75
88
|
"id": {
|
|
76
89
|
"type": "string",
|
|
77
90
|
"description": "Slack bot name"
|
package/src/index.ts
CHANGED
package/src/protocol.ts
CHANGED
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
6
6
|
import type { IncomingMessage } from 'node:http';
|
|
7
|
-
import { isMediaRef, type MediaRef } from '@zhin.js/
|
|
8
|
-
import type { ConversationKind, ConversationRef } from '@zhin.js/im-contract';
|
|
7
|
+
import { isMediaRef, type MediaRef, type ConversationKind, type ConversationRef } from '@zhin.js/im-contract';
|
|
9
8
|
import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
10
9
|
import { mrkdwnToMarkdown } from './mrkdwn-to-markdown.js';
|
|
11
10
|
|
|
@@ -19,25 +18,16 @@ function dropOutboundMedia(type: string, reason: string): void {
|
|
|
19
18
|
const SLACK_SIG_VERSION = 'v0';
|
|
20
19
|
const MAX_TIMESTAMP_DRIFT_SECONDS = 300;
|
|
21
20
|
|
|
22
|
-
/**
|
|
23
|
-
export interface
|
|
24
|
-
readonly id
|
|
25
|
-
readonly token
|
|
21
|
+
/** One endpoint config after AdapterIndex expands `plugins.<instanceKey>.endpoints`. */
|
|
22
|
+
export interface SlackEndpointConfig {
|
|
23
|
+
readonly id: string;
|
|
24
|
+
readonly token: string;
|
|
26
25
|
readonly signingSecret?: string;
|
|
27
26
|
readonly appToken?: string;
|
|
28
27
|
/** Default true (Socket Mode). Set false for HTTP Events API via httpHostToken. */
|
|
29
28
|
readonly socketMode?: boolean;
|
|
30
29
|
readonly webhookPath?: string;
|
|
31
30
|
readonly clientPingTimeout?: number;
|
|
32
|
-
/** Transitional: legacy root `endpoints[]` with `context: slack`. */
|
|
33
|
-
readonly endpoints?: ReadonlyArray<Partial<ResolvedSlackConfig> & {
|
|
34
|
-
readonly context?: string;
|
|
35
|
-
readonly socketMode?: boolean;
|
|
36
|
-
readonly signingSecret?: string;
|
|
37
|
-
readonly appToken?: string;
|
|
38
|
-
readonly webhookPath?: string;
|
|
39
|
-
readonly clientPingTimeout?: number;
|
|
40
|
-
}>;
|
|
41
31
|
}
|
|
42
32
|
|
|
43
33
|
export interface ResolvedSlackConfig {
|
|
@@ -127,46 +117,19 @@ export interface SlackWireSegment {
|
|
|
127
117
|
readonly data?: Record<string, unknown>;
|
|
128
118
|
}
|
|
129
119
|
|
|
130
|
-
export function resolveSlackConfig(config:
|
|
131
|
-
const
|
|
132
|
-
const token = config.token
|
|
133
|
-
|
|
134
|
-
?? process.env.SLACK_BOT_TOKEN
|
|
135
|
-
?? process.env.SLACK_TOKEN;
|
|
136
|
-
if (!token) {
|
|
137
|
-
throw new TypeError(
|
|
138
|
-
'Slack adapter requires token (plugins.<key>.token or endpoints with context: slack)',
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const id = (typeof config.id === 'string' && config.id)
|
|
143
|
-
|| (typeof entry?.id === 'string' && entry.id)
|
|
144
|
-
|| process.env.SLACK_BOT_NAME
|
|
145
|
-
|| 'slack-bot';
|
|
146
|
-
|
|
147
|
-
const socketMode = config.socketMode ?? entry?.socketMode;
|
|
120
|
+
export function resolveSlackConfig(config: SlackEndpointConfig): ResolvedSlackConfig {
|
|
121
|
+
const id = requiredEndpointField(config.id, 'id');
|
|
122
|
+
const token = requiredEndpointField(config.token, 'token');
|
|
123
|
+
const socketMode = config.socketMode;
|
|
148
124
|
// Prefer Socket Mode (default true) — no public URL required.
|
|
149
125
|
const mode: 'socket' | 'http' = socketMode === false ? 'http' : 'socket';
|
|
150
126
|
|
|
151
|
-
const signingSecret =
|
|
152
|
-
|
|
153
|
-
??
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
?? process.env.SLACK_APP_TOKEN
|
|
158
|
-
?? undefined;
|
|
159
|
-
|
|
160
|
-
if (mode === 'socket' && !appToken) {
|
|
161
|
-
throw new TypeError(
|
|
162
|
-
'Slack Socket Mode requires appToken (xapp-...); set socketMode: false for HTTP Events API',
|
|
163
|
-
);
|
|
164
|
-
}
|
|
165
|
-
if (mode === 'http' && !signingSecret) {
|
|
166
|
-
throw new TypeError(
|
|
167
|
-
'Slack HTTP Events API requires signingSecret',
|
|
168
|
-
);
|
|
169
|
-
}
|
|
127
|
+
const signingSecret = mode === 'http'
|
|
128
|
+
? requiredEndpointField(config.signingSecret, 'signingSecret')
|
|
129
|
+
: config.signingSecret?.trim() ?? '';
|
|
130
|
+
const appToken = mode === 'socket'
|
|
131
|
+
? requiredEndpointField(config.appToken, 'appToken')
|
|
132
|
+
: config.appToken?.trim();
|
|
170
133
|
|
|
171
134
|
return {
|
|
172
135
|
context: 'slack',
|
|
@@ -176,14 +139,22 @@ export function resolveSlackConfig(config: SlackAdapterConfig = {}): ResolvedSla
|
|
|
176
139
|
signingSecret,
|
|
177
140
|
appToken,
|
|
178
141
|
webhookPath: normalizeWebhookPath(
|
|
179
|
-
config.webhookPath ??
|
|
142
|
+
config.webhookPath ?? '/slack/events',
|
|
180
143
|
),
|
|
181
|
-
clientPingTimeout: config.clientPingTimeout
|
|
182
|
-
?? entry?.clientPingTimeout
|
|
183
|
-
?? 15_000,
|
|
144
|
+
clientPingTimeout: config.clientPingTimeout ?? 15_000,
|
|
184
145
|
};
|
|
185
146
|
}
|
|
186
147
|
|
|
148
|
+
function requiredEndpointField(
|
|
149
|
+
value: unknown,
|
|
150
|
+
field: 'id' | 'token' | 'signingSecret' | 'appToken',
|
|
151
|
+
): string {
|
|
152
|
+
if (typeof value !== 'string' || !value.trim()) {
|
|
153
|
+
throw new TypeError(`Slack endpoint requires a non-empty ${field}`);
|
|
154
|
+
}
|
|
155
|
+
return value.trim();
|
|
156
|
+
}
|
|
157
|
+
|
|
187
158
|
export function normalizeWebhookPath(path: string): string {
|
|
188
159
|
const trimmed = path.trim() || '/slack/events';
|
|
189
160
|
return trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Slack 插件实例的运行时状态:adapter create() 注册的 endpoint 列表。
|
|
3
|
-
* 由 plugin.ts setup() provide,adapter create 与 `slack
|
|
3
|
+
* 由 plugin.ts setup() provide,adapter create 与 `slack endpoint` 命令共享(同一 owner generation)。
|
|
4
4
|
*/
|
|
5
5
|
import { defineEndpointRuntimeStateToken } from 'zhin.js/adapter';
|
|
6
6
|
|