dsh-slack 0.3.2 → 0.3.4
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 +29 -0
- package/README.en.md +23 -185
- package/README.md +21 -187
- package/docs/CHANGELOG.en.md +21 -0
- package/docs/USAGE.en.md +185 -0
- package/docs/USAGE.md +189 -0
- package/docs/VALIDATION.md +20 -0
- package/lib/inbox.d.ts +1 -1
- package/lib/inbox.js +4 -8
- package/lib/slack-client.js +7 -9
- package/lib/tools.js +5 -4
- package/package.json +9 -5
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# 更新记录
|
|
2
|
+
|
|
3
|
+
[返回简介](README.md) · [使用说明](docs/USAGE.md) · [验证记录](docs/VALIDATION.md)
|
|
4
|
+
|
|
5
|
+
[历史英文记录](docs/CHANGELOG.en.md)
|
|
6
|
+
|
|
7
|
+
## 0.3.4 (2026-10-05)
|
|
8
|
+
|
|
9
|
+
- 标记已读只移除本次展示的消息,保留剩余未读与已读重投去重;发送不隐式重试,缺少消息回执时提示先检查频道。
|
|
10
|
+
|
|
11
|
+
## 0.3.3 (2026-10-01)
|
|
12
|
+
|
|
13
|
+
- 更新并对齐 Socket Mode 的传输依赖,修复依赖解析问题。
|
|
14
|
+
|
|
15
|
+
## 0.3.0 (2026-08-26)
|
|
16
|
+
|
|
17
|
+
- 新增 `slack_health` 自检(令牌/Socket Mode 配置一键体检);修复只配置部分字段(如只有 token 没有 appToken)时可选链导致的启动崩溃。
|
|
18
|
+
|
|
19
|
+
## 0.2.3 (2026-08-15)
|
|
20
|
+
|
|
21
|
+
- `slack_channels` 自动分页:频道很多时不再只返回第一页。
|
|
22
|
+
- `slack_inbox` 去重 + `drain` 原子消费:Slack 重投的事件不会重复入队,`markRead` 期间新到的消息也不会被误清。
|
|
23
|
+
- WebClient 复用:同一 `token + slackApiUrl` 只创建一个客户端,减少重复初始化。
|
|
24
|
+
- 分页增加页数上限,防止异常 `next_cursor` 导致死循环。
|
|
25
|
+
- 错误映射补充 `not_authed` / `is_archived` / `msg_too_long` / `ratelimited`。
|
|
26
|
+
|
|
27
|
+
## 更早的改动
|
|
28
|
+
|
|
29
|
+
完整历史可查阅 [GitHub 提交记录](https://github.com/STARDUSTLC666/dsh-slack/commits/main)。
|
package/README.en.md
CHANGED
|
@@ -1,208 +1,46 @@
|
|
|
1
|
-
[中文](README.md)
|
|
2
|
-
|
|
3
|
-
   
|
|
4
|
-
|
|
5
1
|
# dsh-slack
|
|
6
2
|
|
|
7
|
-
[
|
|
8
|
-
|
|
9
|
-
DSH (DeepSeek Harness) community plugin: lets the agent communicate with Slack bidirectionally.
|
|
10
|
-
|
|
11
|
-
> **v0.2 scope (two-way)**: v0.1 only did one-way "agent → Slack" notifications; v0.2 adds Socket Mode,
|
|
12
|
-
> enabling "Slack message → agent": `slack_inbox` receives messages, `slack_reply` replies in threads.
|
|
13
|
-
> RTM and interactive components (buttons/modals/slash command replies) are out of scope for v0.2 — see
|
|
14
|
-
> [Known limitations and roadmap](#known-limitations-and-roadmap) below.
|
|
15
|
-
|
|
16
|
-
## Features
|
|
17
|
-
|
|
18
|
-
- `slack_notify`: send a Markdown text message to a channel (or thread), returning the message `ts`.
|
|
19
|
-
- `slack_channels`: list the channels currently visible to the bot (`conversations.list`, paginating through `next_cursor` until complete).
|
|
20
|
-
- `slack_inbox`: read messages received via Socket Mode (in-memory queue, keeps up to 200; deduplicates retries and consumes atomically with `markRead=true`).
|
|
21
|
-
- `slack_reply`: reply to an inbox message as a thread (`chat.postMessage` with `thread_ts`).
|
|
22
|
-
- WebClient instances are cached by `token + slackApiUrl` and rebuilt automatically when configuration changes.
|
|
23
|
-
- Configuration via `cordis.patch.yml`; tokens support environment-variable fallback (`DSH_SLACK_TOKEN` / `DSH_SLACK_APP_TOKEN`).
|
|
24
|
-
|
|
25
|
-
## Changelog
|
|
26
|
-
|
|
27
|
-
- **0.3.0**: new `slack_health` self-check (one-call token / Socket Mode config health); fixed a startup crash from optional chaining when only some config fields are set (e.g. token without appToken).
|
|
28
|
-
- **0.2.3**:
|
|
29
|
-
- `slack_channels` paginates automatically so large workspaces no longer lose channels after the first page.
|
|
30
|
-
- `slack_inbox` deduplicates Slack's at-least-once event deliveries and drains atomically on `markRead`.
|
|
31
|
-
- WebClient reuse avoids rebuilding clients on every tool call.
|
|
32
|
-
- Pagination has a page cap to prevent loops from a misbehaving `next_cursor`.
|
|
33
|
-
- Error mapping adds `not_authed` / `is_archived` / `msg_too_long` / `ratelimited`.
|
|
34
|
-
|
|
3
|
+
[中文](README.md)
|
|
35
4
|
|
|
36
|
-
|
|
5
|
+

|
|
37
6
|
|
|
38
|
-
|
|
7
|
+
Connect Slack for notifications, a Socket Mode inbox and thread replies.
|
|
39
8
|
|
|
40
|
-
|
|
9
|
+
[](https://www.npmjs.com/package/dsh-slack) [](https://www.npmjs.com/package/dsh-slack)
|
|
41
10
|
|
|
42
|
-
|
|
11
|
+
## What it does
|
|
43
12
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
13
|
+
- Send Markdown notifications to channels or threads.
|
|
14
|
+
- List visible channels and read the Socket Mode inbox.
|
|
15
|
+
- Reply in threads and check connection or token configuration.
|
|
47
16
|
|
|
48
|
-
|
|
17
|
+
## Install
|
|
49
18
|
|
|
50
|
-
|
|
19
|
+
In DSH Desktop, install `dsh-slack` from the Plugins panel. If the bundled dsh command is available:
|
|
51
20
|
|
|
52
21
|
```bash
|
|
53
|
-
dsh plugin --profile
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
Then restart the web service. To clean up fully, also remove the plugin entry from your profile `cordis.patch.yml` if you overrode it.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
## Configuration
|
|
60
|
-
|
|
61
|
-
Configuration lives in the profile's `cordis.patch.yml`; override this plugin's line by `id: slack` (overriding replaces that line's `config` wholesale — it does not merge). Available options:
|
|
62
|
-
|
|
63
|
-
| Key | Type | Required | Description |
|
|
64
|
-
| --- | --- | --- | --- |
|
|
65
|
-
| `token` | string | yes* | Slack token: bot token (`xoxb-`) or user token (`xoxp-`). When empty, falls back to the `DSH_SLACK_TOKEN` env var. |
|
|
66
|
-
| `appToken` | string | no* | App-Level Token (starts with `xapp-`); used to receive messages after enabling Socket Mode. When empty, falls back to the `DSH_SLACK_APP_TOKEN` env var. |
|
|
67
|
-
| `defaultChannel` | string | no | Default channel (e.g. `#general`). The default target when the model doesn't specify a channel; written into the `channel` parameter description. |
|
|
68
|
-
|
|
69
|
-
`*` `token` may be left empty at the "config layer", in which case it falls back to the env var; when both are empty the plugin still loads, but calling the send/list/reply tools returns a Chinese error. An empty `appToken` only warns — no crash — and `slack_inbox` returns an empty queue (one-way mode).
|
|
70
|
-
|
|
71
|
-
**Method 1: environment variables (recommended, no hard-coded tokens)**
|
|
72
|
-
|
|
73
|
-
```sh
|
|
74
|
-
# 在启动 dsh 的进程里设置
|
|
75
|
-
export DSH_SLACK_TOKEN=xoxb-你的机器人令牌
|
|
76
|
-
export DSH_SLACK_APP_TOKEN=xapp-你的App级令牌
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
**Method 2: override in the profile's cordis.patch.yml**
|
|
80
|
-
|
|
81
|
-
In your profile directory (`$DSH_HOME/profiles/web/cordis.patch.yml`) append:
|
|
82
|
-
|
|
83
|
-
```yaml
|
|
84
|
-
# 覆盖 dsh-slack 的 slack 行配置(整体替换)
|
|
85
|
-
- id: slack
|
|
86
|
-
config:
|
|
87
|
-
token: 'xoxb-你的机器人令牌'
|
|
88
|
-
appToken: 'xapp-你的App级令牌'
|
|
89
|
-
defaultChannel: '#general'
|
|
22
|
+
dsh plugin --profile desktop add dsh-slack
|
|
90
23
|
```
|
|
91
24
|
|
|
92
|
-
|
|
93
|
-
> `DSH_SLACK_APP_TOKEN`.
|
|
94
|
-
|
|
95
|
-
### Create a Slack App and get a token
|
|
25
|
+
For the web version, replace `desktop` with `web`. Restart DSH after installation.
|
|
96
26
|
|
|
97
|
-
|
|
98
|
-
2. On the **OAuth & Permissions** page, under **Scopes → Bot Token Scopes** check:
|
|
99
|
-
- `chat:write` (required to send messages)
|
|
100
|
-
- `channels:read` (required to list channels)
|
|
101
|
-
3. Back at the top, click **Install to Workspace** (authorize).
|
|
102
|
-
4. Grab the **Bot User OAuth Token** (starts with `xoxb-`).
|
|
103
|
-
5. Add the bot (App) to the channels it should post in: `/invite @your-bot` in the channel (required for private channels).
|
|
104
|
-
|
|
105
|
-
### Enable Socket Mode (two-way message receiving)
|
|
106
|
-
|
|
107
|
-
To receive Slack messages (`slack_inbox` / `slack_reply`), enable Socket Mode and generate an App-Level Token:
|
|
108
|
-
|
|
109
|
-
1. Open <https://api.slack.com/apps> and open your App.
|
|
110
|
-
2. Open the **Socket Mode** page → turn on the toggle (**Enable Socket Mode**).
|
|
111
|
-
3. Click **Generate Token and Scopes** to create an App-Level Token: name the token, check the `connections:write` scope.
|
|
112
|
-
Copy the `xapp-` App-Level Token (shown only once — save it immediately).
|
|
113
|
-
4. Open the **Event Subscriptions** page, enable events, and under **Subscribe to bot events → Add Bot User Event** add:
|
|
114
|
-
- `message.channels` (public channel messages)
|
|
115
|
-
- `message.im` (bot DMs)
|
|
116
|
-
5. Put the App-Level Token into `appToken` (or the `DSH_SLACK_APP_TOKEN` env var).
|
|
117
|
-
6. Restart the dsh Web service; the plugin connects automatically via Socket Mode and starts receiving messages.
|
|
118
|
-
|
|
119
|
-
> Without `appToken` the plugin **won't crash**: it only prints a warning and `slack_inbox` returns an empty queue (with a Chinese hint).
|
|
120
|
-
> Socket Mode network errors are auto-reconnected by the SDK; the plugin only logs a warning and never throws.
|
|
121
|
-
|
|
122
|
-
## Tool reference
|
|
123
|
-
|
|
124
|
-
### `slack_notify`
|
|
125
|
-
|
|
126
|
-
Send Markdown text to a channel/thread (underlying `chat.postMessage`).
|
|
127
|
-
|
|
128
|
-
| Param | Type | Required | Description |
|
|
129
|
-
| --- | --- | --- | --- |
|
|
130
|
-
| `channel` | string | yes | Channel name (e.g. `#general`) or channel ID. |
|
|
131
|
-
| `text` | string | yes | The Markdown text to send. |
|
|
132
|
-
| `thread_ts` | string | no | The `ts` of the thread to reply to. |
|
|
133
|
-
|
|
134
|
-
Returns: `{ "ts": "...", "channel": "#general" }` (`ts` for later `thread_ts` reference).
|
|
135
|
-
|
|
136
|
-
### `slack_channels`
|
|
137
|
-
|
|
138
|
-
List channels visible to the bot (underlying `conversations.list`).
|
|
139
|
-
|
|
140
|
-
No parameters. Returns: `{ "channels": [{ "id": "...", "name": "..." }, ...] }`.
|
|
141
|
-
|
|
142
|
-
### `slack_inbox`
|
|
143
|
-
|
|
144
|
-
Read messages received via Socket Mode (in-memory queue, keeps up to 200, newest first).
|
|
145
|
-
|
|
146
|
-
| Param | Type | Required | Description |
|
|
147
|
-
| --- | --- | --- | --- |
|
|
148
|
-
| `limit` | integer | no | Maximum number of messages to return (default 10, range 1-50). |
|
|
149
|
-
| `markRead` | boolean | no | When `true`, clears the inbox queue after returning (mark as read). |
|
|
150
|
-
|
|
151
|
-
Returns: `{ "messages": [{ "ts": "...", "channel": "...", "user": "...", "text": "..." }, ...] }`.
|
|
152
|
-
|
|
153
|
-
### `slack_reply`
|
|
154
|
-
|
|
155
|
-
Reply to an inbox message as a thread (underlying `chat.postMessage` with `thread_ts`).
|
|
156
|
-
|
|
157
|
-
| Param | Type | Required | Description |
|
|
158
|
-
| --- | --- | --- | --- |
|
|
159
|
-
| `channel` | string | yes | Channel name (e.g. `#general`) or channel ID. |
|
|
160
|
-
| `text` | string | yes | Reply content (Markdown text). |
|
|
161
|
-
| `thread_ts` | string | yes | The `ts` of the message to reply to (from `slack_inbox`). |
|
|
162
|
-
|
|
163
|
-
Returns: `{ "ts": "...", "channel": "#general" }`.
|
|
164
|
-
|
|
165
|
-
## Error handling
|
|
166
|
-
|
|
167
|
-
All error messages are in Chinese, readable by both the model and the user:
|
|
168
|
-
|
|
169
|
-
- Unconfigured token: `token 未配置:缺少 Slack 机器人令牌(xoxb-)…请在 profile 的 cordis.patch.yml 覆盖 slack 行的 config.token 并重启,或设置环境变量 DSH_SLACK_TOKEN。`
|
|
170
|
-
- Unconfigured App-Level Token: only a warning; `slack_inbox` returns an empty queue (with a Chinese hint) and other tools are unaffected.
|
|
171
|
-
- `invalid_auth`: hints to check/regenerate the token.
|
|
172
|
-
- `channel_not_found`: hints the channel name or ID is wrong.
|
|
173
|
-
- `not_in_channel`: hints to invite the bot App into the channel first.
|
|
174
|
-
- `token_revoked` / `account_inactive` / `missing_scope` / `not_authed`: hints permission or token expiry, reinstall the App.
|
|
175
|
-
- `is_archived`: hints the channel is archived and cannot receive messages.
|
|
176
|
-
- `msg_too_long`: hints the message exceeds Slack's 40,000-character limit.
|
|
177
|
-
- `ratelimited`: hints to retry after a short wait.
|
|
178
|
-
|
|
179
|
-
## Development and testing
|
|
180
|
-
|
|
181
|
-
```sh
|
|
182
|
-
pnpm install # 安装依赖并触发 prepare(tsc 构建)
|
|
183
|
-
pnpm build # tsc 编译 src → lib
|
|
184
|
-
pnpm test # 先 build,再用 node:test 跑 test/*.test.mjs
|
|
185
|
-
```
|
|
27
|
+
## Start using it
|
|
186
28
|
|
|
187
|
-
|
|
188
|
-
injecting a fake client to assert `postMessage` arguments (incl. `thread_ts`), output schema pure-JSON validation,
|
|
189
|
-
inbox queue capacity/clear/deduplication/atomic drain, Socket Mode event parsing (fake event objects), and no-crash on missing appToken.
|
|
29
|
+
Configure your Slack App and tokens, then ask to review the inbox and identify messages that need a reply.
|
|
190
30
|
|
|
191
|
-
##
|
|
31
|
+
## Requirements and configuration
|
|
192
32
|
|
|
193
|
-
|
|
194
|
-
- **No** RTM or interactive components (buttons/modals/slash command replies).
|
|
195
|
-
- `slack_inbox` is an in-process memory queue: cleared on restart, not persisted; keeps up to 200, dropping the oldest when full.
|
|
196
|
-
- `channel` is a required parameter; `defaultChannel` is currently only written into the `channel` parameter description as a hint — it does not replace the required `channel`.
|
|
197
|
-
- With a missing token the plugin still loads (lazy loading); the error is only thrown when the tool is called; a missing appToken only warns.
|
|
33
|
+
Requires a bot token. Socket Mode also needs an app token and permissions; the inbox is stored in memory.
|
|
198
34
|
|
|
199
|
-
|
|
35
|
+
Detailed configuration, tool arguments and troubleshooting are in the [usage guide](docs/USAGE.en.md). For standalone development, follow the Node requirement in [package.json](package.json).
|
|
200
36
|
|
|
201
|
-
##
|
|
37
|
+
## Documentation
|
|
202
38
|
|
|
203
|
-
-
|
|
204
|
-
-
|
|
39
|
+
- [Usage and troubleshooting](docs/USAGE.en.md)
|
|
40
|
+
- [Changelog](CHANGELOG.md)
|
|
41
|
+
- [Validation scope and history](docs/VALIDATION.md)
|
|
42
|
+
- [Report a problem or suggest a feature](https://github.com/STARDUSTLC666/dsh-slack/issues)
|
|
205
43
|
|
|
206
44
|
## License
|
|
207
45
|
|
|
208
|
-
MIT
|
|
46
|
+
[MIT](LICENSE)
|
package/README.md
CHANGED
|
@@ -1,212 +1,46 @@
|
|
|
1
|
-
[English](README.en.md)
|
|
2
|
-
|
|
3
1
|
# dsh-slack
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
   
|
|
8
|
-
|
|
9
|
-
[](https://awesome-dsh-plugin.com)
|
|
10
|
-
|
|
11
|
-
DSH(DeepSeek Harness)社区插件:让 agent 与 Slack 双向通信。
|
|
3
|
+
[English](README.en.md)
|
|
12
4
|
|
|
13
|
-
|
|
5
|
+

|
|
14
6
|
|
|
15
|
-
|
|
7
|
+
连接 Slack,发送通知并处理 Socket Mode 收件箱与线程回复。
|
|
16
8
|
|
|
17
|
-
|
|
18
|
-
> 支持「Slack 消息 → agent」:`slack_inbox` 收取消息、`slack_reply` 线程回复。
|
|
19
|
-
> RTM、交互组件(按钮/弹窗/slash command 回复)不在 v0.2,见下方
|
|
20
|
-
> [已知限制与路线图](#已知限制与路线图)。
|
|
9
|
+
[](https://www.npmjs.com/package/dsh-slack) [](https://www.npmjs.com/package/dsh-slack)
|
|
21
10
|
|
|
22
11
|
## 功能
|
|
23
12
|
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
- `slack_reply`:以线程回复形式回复某条收件箱消息(`chat.postMessage` 带 `thread_ts`)。
|
|
28
|
-
- WebClient 按 `token + slackApiUrl` 缓存复用,配置变更时自动重建。
|
|
29
|
-
- 配置走 `cordis.patch.yml`,令牌支持环境变量回退(`DSH_SLACK_TOKEN` / `DSH_SLACK_APP_TOKEN`)。
|
|
30
|
-
|
|
31
|
-
## 版本记录
|
|
32
|
-
|
|
33
|
-
- **0.3.0**:新增 `slack_health` 自检(令牌/Socket Mode 配置一键体检);修复只配置部分字段(如只有 token 没有 appToken)时可选链导致的启动崩溃。
|
|
34
|
-
- **0.2.3**:
|
|
35
|
-
- `slack_channels` 自动分页:频道很多时不再只返回第一页。
|
|
36
|
-
- `slack_inbox` 去重 + `drain` 原子消费:Slack 重投的事件不会重复入队,`markRead` 期间新到的消息也不会被误清。
|
|
37
|
-
- WebClient 复用:同一 `token + slackApiUrl` 只创建一个客户端,减少重复初始化。
|
|
38
|
-
- 分页增加页数上限,防止异常 `next_cursor` 导致死循环。
|
|
39
|
-
- 错误映射补充 `not_authed` / `is_archived` / `msg_too_long` / `ratelimited`。
|
|
13
|
+
- 向频道或线程发送 Markdown 通知。
|
|
14
|
+
- 读取机器人可见频道和 Socket Mode 收件箱。
|
|
15
|
+
- 回复线程,按配置检查连接与令牌。
|
|
40
16
|
|
|
41
17
|
## 安装
|
|
42
18
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
```sh
|
|
46
|
-
dsh plugin --profile web add dsh-slack
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
安装后重启你的 dsh Web 服务,`slack_notify` / `slack_channels` / `slack_inbox` / `slack_reply`
|
|
50
|
-
四个工具即对模型可见。
|
|
51
|
-
|
|
52
|
-
## 配置
|
|
53
|
-
|
|
54
|
-
配置在 profile 的 `cordis.patch.yml` 里按 `id: slack` 覆盖本插件的行(覆盖会整体替换该行的
|
|
55
|
-
`config`,不会合并)。可用配置项:
|
|
56
|
-
|
|
57
|
-
| 键 | 类型 | 必填 | 说明 |
|
|
58
|
-
| --- | --- | --- | --- |
|
|
59
|
-
| `token` | string | 是* | Slack 令牌:机器人令牌(`xoxb-`)或用户令牌(`xoxp-`)。留空时回退到环境变量 `DSH_SLACK_TOKEN`。 |
|
|
60
|
-
| `appToken` | string | 否* | App-Level Token(`xapp-` 开头),开启 Socket Mode 后用于接收消息。留空时回退到环境变量 `DSH_SLACK_APP_TOKEN`。 |
|
|
61
|
-
| `defaultChannel` | string | 否 | 默认频道(如 `#general`)。模型未特别指定频道时的默认目标,写进 `channel` 参数说明里。 |
|
|
62
|
-
|
|
63
|
-
`*` `token` 在「配置层」可留空,此时回退环境变量;两者都为空时插件照常加载,但调用发消息/列频道/
|
|
64
|
-
回复工具时会返回中文报错。`appToken` 留空则只告警、不崩溃,`slack_inbox` 返回空队列(单向模式)。
|
|
65
|
-
|
|
66
|
-
**方式一:环境变量(推荐,不写死令牌)**
|
|
67
|
-
|
|
68
|
-
```sh
|
|
69
|
-
# 在启动 dsh 的进程里设置
|
|
70
|
-
export DSH_SLACK_TOKEN=xoxb-你的机器人令牌
|
|
71
|
-
export DSH_SLACK_APP_TOKEN=xapp-你的App级令牌
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
**方式二:profile 的 cordis.patch.yml 直接覆盖**
|
|
75
|
-
|
|
76
|
-
在你的 profile 目录(`$DSH_HOME/profiles/web/cordis.patch.yml`)追加:
|
|
77
|
-
|
|
78
|
-
```yaml
|
|
79
|
-
# 覆盖 dsh-slack 的 slack 行配置(整体替换)
|
|
80
|
-
- id: slack
|
|
81
|
-
config:
|
|
82
|
-
token: 'xoxb-你的机器人令牌'
|
|
83
|
-
appToken: 'xapp-你的App级令牌'
|
|
84
|
-
defaultChannel: '#general'
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
> 优先级:`config.token` > 环境变量 `DSH_SLACK_TOKEN`;`config.appToken` > 环境变量
|
|
88
|
-
> `DSH_SLACK_APP_TOKEN`。
|
|
89
|
-
|
|
90
|
-
### 创建 Slack App 并拿令牌
|
|
91
|
-
|
|
92
|
-
1. 打开 <https://api.slack.com/apps>,点 **Create New App**(选 `From scratch`,给 App 起名、选工作区)。
|
|
93
|
-
2. 进入 **OAuth & Permissions** 页,在 **Scopes → Bot Token Scopes** 下勾选:
|
|
94
|
-
- `chat:write`(发消息必需)
|
|
95
|
-
- `channels:read`(列频道必需)
|
|
96
|
-
3. 回到顶部点 **Install to Workspace**(授权)。
|
|
97
|
-
4. 拿到 **Bot User OAuth Token**(以 `xoxb-` 开头)。
|
|
98
|
-
5. 把机器人(App)加进它要发消息的频道:在频道里 `/invite @你的机器人`(私有频道必需)。
|
|
99
|
-
|
|
100
|
-
### 开启 Socket Mode(双向收消息)
|
|
101
|
-
|
|
102
|
-
要接收 Slack 消息(`slack_inbox` / `slack_reply`),需要开启 Socket Mode 并生成 App-Level Token:
|
|
103
|
-
|
|
104
|
-
1. 打开 <https://api.slack.com/apps>,进入你的 App。
|
|
105
|
-
2. 左侧 **Socket Mode** 页 → 打开开关(**Enable Socket Mode**)。
|
|
106
|
-
3. 点 **Generate Token and Scopes** 生成 App-Level Token:给 Token 起名,勾选 `connections:write` scope。
|
|
107
|
-
生成后拿到以 `xapp-` 开头的 App-Level Token(只显示一次,请立即保存)。
|
|
108
|
-
4. 进入 **Event Subscriptions** 页,开启事件订阅,在 **Subscribe to bot events → Add Bot User Event** 添加:
|
|
109
|
-
- `message.channels`(公开频道消息)
|
|
110
|
-
- `message.im`(机器人私信)
|
|
111
|
-
5. 把 App-Level Token 配进 `appToken`(或环境变量 `DSH_SLACK_APP_TOKEN`)。
|
|
112
|
-
6. 重启 dsh Web 服务,插件自动通过 Socket Mode 建立连接并开始收消息。
|
|
113
|
-
|
|
114
|
-
> 未配置 `appToken` 时插件**不会崩溃**:只打印告警,`slack_inbox` 返回空队列(中文提示)。
|
|
115
|
-
> Socket Mode 网络错误由 SDK 自动重连,插件只记录告警、不抛崩。
|
|
116
|
-
|
|
117
|
-
## 卸载
|
|
19
|
+
桌面版可在「插件」面板按包名 `dsh-slack` 安装。已配置 dsh 命令时也可使用:
|
|
118
20
|
|
|
119
21
|
```bash
|
|
120
|
-
dsh plugin --profile
|
|
22
|
+
dsh plugin --profile desktop add dsh-slack
|
|
121
23
|
```
|
|
122
24
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
## 工具清单
|
|
126
|
-
|
|
127
|
-
### `slack_notify`
|
|
128
|
-
|
|
129
|
-
向指定频道/线程发送 Markdown 文本(底层 `chat.postMessage`)。
|
|
130
|
-
|
|
131
|
-
| 参数 | 类型 | 必填 | 说明 |
|
|
132
|
-
| --- | --- | --- | --- |
|
|
133
|
-
| `channel` | string | 是 | 频道名(如 `#general`)或频道 ID。 |
|
|
134
|
-
| `text` | string | 是 | 要发送的 Markdown 文本。 |
|
|
135
|
-
| `thread_ts` | string | 否 | 回复某条消息所在线程的 `ts`。 |
|
|
136
|
-
|
|
137
|
-
返回:`{ "ts": "...", "channel": "#general" }`(`ts` 供后续 `thread_ts` 引用)。
|
|
138
|
-
|
|
139
|
-
### `slack_channels`
|
|
140
|
-
|
|
141
|
-
列出机器人可见频道(底层 `conversations.list`)。
|
|
142
|
-
|
|
143
|
-
无参数。返回:`{ "channels": [{ "id": "...", "name": "..." }, ...] }`。
|
|
144
|
-
|
|
145
|
-
### `slack_inbox`
|
|
25
|
+
网页版把命令中的 `desktop` 改为 `web`。安装后重启 DSH。
|
|
146
26
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
| 参数 | 类型 | 必填 | 说明 |
|
|
150
|
-
| --- | --- | --- | --- |
|
|
151
|
-
| `limit` | integer | 否 | 最多返回的消息数(默认 10,范围 1-50)。 |
|
|
152
|
-
| `markRead` | boolean | 否 | 为 `true` 时,返回后清空收件箱队列(标记已读)。 |
|
|
153
|
-
|
|
154
|
-
返回:`{ "messages": [{ "ts": "...", "channel": "...", "user": "...", "text": "..." }, ...] }`。
|
|
155
|
-
|
|
156
|
-
### `slack_reply`
|
|
157
|
-
|
|
158
|
-
以线程回复形式回复某条收件箱消息(底层 `chat.postMessage` 带 `thread_ts`)。
|
|
159
|
-
|
|
160
|
-
| 参数 | 类型 | 必填 | 说明 |
|
|
161
|
-
| --- | --- | --- | --- |
|
|
162
|
-
| `channel` | string | 是 | 频道名(如 `#general`)或频道 ID。 |
|
|
163
|
-
| `text` | string | 是 | 回复内容(Markdown 文本)。 |
|
|
164
|
-
| `thread_ts` | string | 是 | 要回复消息的 `ts`(来自 `slack_inbox` 返回的 `ts`)。 |
|
|
165
|
-
|
|
166
|
-
返回:`{ "ts": "...", "channel": "#general" }`。
|
|
167
|
-
|
|
168
|
-
## 错误处理
|
|
169
|
-
|
|
170
|
-
所有错误信息均为中文,模型与用户都能直接读懂:
|
|
171
|
-
|
|
172
|
-
- 未配置令牌:`token 未配置:缺少 Slack 机器人令牌(xoxb-)…请在 profile 的 cordis.patch.yml 覆盖 slack 行的 config.token 并重启,或设置环境变量 DSH_SLACK_TOKEN。`
|
|
173
|
-
- 未配置 App-Level Token:只告警,`slack_inbox` 返回空队列(含中文提示),不影响其它工具。
|
|
174
|
-
- `invalid_auth`:提示检查/重新生成 token。
|
|
175
|
-
- `channel_not_found`:提示频道名或频道 ID 错误。
|
|
176
|
-
- `not_in_channel`:提示先把机器人 App 邀请进频道。
|
|
177
|
-
- `token_revoked` / `account_inactive` / `missing_scope` / `not_authed`:提示权限或令牌失效,需重新安装 App。
|
|
178
|
-
- `is_archived`:提示频道已归档,不能发消息。
|
|
179
|
-
- `msg_too_long`:提示 Slack 单条消息超过 40,000 字符。
|
|
180
|
-
- `ratelimited`:提示请求太频繁,稍后重试。
|
|
181
|
-
|
|
182
|
-
## 开发与测试
|
|
183
|
-
|
|
184
|
-
```sh
|
|
185
|
-
pnpm install # 安装依赖并触发 prepare(tsc 构建)
|
|
186
|
-
pnpm build # tsc 编译 src → lib
|
|
187
|
-
pnpm test # 先 build,再用 node:test 跑 test/*.test.mjs
|
|
188
|
-
```
|
|
27
|
+
## 开始使用
|
|
189
28
|
|
|
190
|
-
|
|
191
|
-
注入 fake client 断言 `postMessage` 参数(含 `thread_ts`)、输出 schema 纯 JSON 校验、
|
|
192
|
-
收件箱队列容量/清空/去重/原子 drain、Socket Mode 事件解析(fake event 对象)、appToken 缺失不崩。
|
|
29
|
+
配置 Slack App 和令牌后,可说:“查看 Slack 收件箱,整理需要回复的消息。”
|
|
193
30
|
|
|
194
|
-
##
|
|
31
|
+
## 依赖与配置
|
|
195
32
|
|
|
196
|
-
|
|
197
|
-
- **不支持** RTM、交互组件(按钮/弹窗/slash command 回复)。
|
|
198
|
-
- `slack_inbox` 为进程内存队列:重启即清空,且不持久化;最多保留 200 条,满则丢最旧。
|
|
199
|
-
- `channel` 为必填参数,`defaultChannel` 目前只作为说明提示写入 `channel` 参数描述,不替代
|
|
200
|
-
必填的 `channel`。
|
|
201
|
-
- 令牌缺失时插件仍会加载(懒加载),错误在工具被调用时才抛出;appToken 缺失则仅告警。
|
|
33
|
+
需要 Bot Token。Socket Mode 收消息还需要 App Token 与相应权限;收件箱在内存中保存。
|
|
202
34
|
|
|
203
|
-
|
|
35
|
+
详细配置、工具参数与排错见[使用说明](docs/USAGE.md)。从源码独立开发时,Node 要求以 [package.json](package.json) 为准。
|
|
204
36
|
|
|
205
|
-
##
|
|
37
|
+
## 文档
|
|
206
38
|
|
|
207
|
-
-
|
|
208
|
-
-
|
|
39
|
+
- [使用与排错](docs/USAGE.md)
|
|
40
|
+
- [更新记录](CHANGELOG.md)
|
|
41
|
+
- [验证范围与历史记录](docs/VALIDATION.md)
|
|
42
|
+
- [问题反馈与功能建议](https://github.com/STARDUSTLC666/dsh-slack/issues)
|
|
209
43
|
|
|
210
44
|
## License
|
|
211
45
|
|
|
212
|
-
MIT
|
|
46
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Historical release notes
|
|
2
|
+
|
|
3
|
+
[Current changelog](../CHANGELOG.md) · [Overview](../README.en.md)
|
|
4
|
+
|
|
5
|
+
These English notes preserve the earlier translations. The main changelog contains the consolidated version history.
|
|
6
|
+
|
|
7
|
+
## 0.3.4 (2026-10-05)
|
|
8
|
+
|
|
9
|
+
- Mark only displayed inbox messages as read, preserving unread entries and retry deduplication. Disable implicit send retries; missing receipts prompt channel inspection.
|
|
10
|
+
|
|
11
|
+
## 0.3.0 (2026-08-26)
|
|
12
|
+
|
|
13
|
+
- new `slack_health` self-check (one-call token / Socket Mode config health); fixed a startup crash from optional chaining when only some config fields are set (e.g. token without appToken).
|
|
14
|
+
|
|
15
|
+
## 0.2.3 (2026-08-15)
|
|
16
|
+
|
|
17
|
+
- `slack_channels` paginates automatically so large workspaces no longer lose channels after the first page.
|
|
18
|
+
- `slack_inbox` deduplicates Slack's at-least-once event deliveries and drains atomically on `markRead`.
|
|
19
|
+
- WebClient reuse avoids rebuilding clients on every tool call.
|
|
20
|
+
- Pagination has a page cap to prevent loops from a misbehaving `next_cursor`.
|
|
21
|
+
- Error mapping adds `not_authed` / `is_archived` / `msg_too_long` / `ratelimited`.
|
package/docs/USAGE.en.md
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# dsh-slack usage guide
|
|
2
|
+
|
|
3
|
+
[Overview](../README.en.md) · [Changelog](../CHANGELOG.md) · [Validation](VALIDATION.md)
|
|
4
|
+
|
|
5
|
+
## Current improvements
|
|
6
|
+
|
|
7
|
+
slack_inbox with limit=10 and markRead=true returns remaining; call again for unread messages. After a timeout or missing ts, inspect the channel before retrying to avoid duplicate notifications.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- `slack_notify`: send a Markdown text message to a channel (or thread), returning the message `ts`.
|
|
12
|
+
- `slack_channels`: list the channels currently visible to the bot (`conversations.list`, paginating through `next_cursor` until complete).
|
|
13
|
+
- `slack_inbox`: read messages received via Socket Mode (in-memory queue, keeps up to 200; deduplicates retries and consumes atomically with `markRead=true`).
|
|
14
|
+
- `slack_reply`: reply to an inbox message as a thread (`chat.postMessage` with `thread_ts`).
|
|
15
|
+
- WebClient instances are cached by `token + slackApiUrl` and rebuilt automatically when configuration changes.
|
|
16
|
+
- Configuration via `cordis.patch.yml`; tokens support environment-variable fallback (`DSH_SLACK_TOKEN` / `DSH_SLACK_APP_TOKEN`).
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
The plugin runs inside the host process, is installed into the profile via `dsh plugin`, and takes effect after a restart:
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
dsh plugin --profile web add dsh-slack
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
After installing, restart your dsh Web service; the four tools `slack_notify` / `slack_channels` / `slack_inbox` / `slack_reply` become visible to the model.
|
|
27
|
+
|
|
28
|
+
## Uninstall
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
dsh plugin --profile web remove dsh-slack
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Then restart the web service. To clean up fully, also remove the plugin entry from your profile `cordis.patch.yml` if you overrode it.
|
|
35
|
+
|
|
36
|
+
## Configuration
|
|
37
|
+
|
|
38
|
+
Configuration lives in the profile's `cordis.patch.yml`; override this plugin's line by `id: slack` (overriding replaces that line's `config` wholesale — it does not merge). Available options:
|
|
39
|
+
|
|
40
|
+
| Key | Type | Required | Description |
|
|
41
|
+
| --- | --- | --- | --- |
|
|
42
|
+
| `token` | string | yes* | Slack token: bot token (`xoxb-`) or user token (`xoxp-`). When empty, falls back to the `DSH_SLACK_TOKEN` env var. |
|
|
43
|
+
| `appToken` | string | no* | App-Level Token (starts with `xapp-`); used to receive messages after enabling Socket Mode. When empty, falls back to the `DSH_SLACK_APP_TOKEN` env var. |
|
|
44
|
+
| `defaultChannel` | string | no | Default channel (e.g. `#general`). The default target when the model doesn't specify a channel; written into the `channel` parameter description. |
|
|
45
|
+
|
|
46
|
+
`*` `token` may be left empty at the "config layer", in which case it falls back to the env var; when both are empty the plugin still loads, but calling the send/list/reply tools returns a Chinese error. An empty `appToken` only warns — no crash — and `slack_inbox` returns an empty queue (one-way mode).
|
|
47
|
+
|
|
48
|
+
**Method 1: environment variables (recommended, no hard-coded tokens)**
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
# 在启动 dsh 的进程里设置
|
|
52
|
+
export DSH_SLACK_TOKEN=xoxb-你的机器人令牌
|
|
53
|
+
export DSH_SLACK_APP_TOKEN=xapp-你的App级令牌
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Method 2: override in the profile's cordis.patch.yml**
|
|
57
|
+
|
|
58
|
+
In your profile directory (`$DSH_HOME/profiles/web/cordis.patch.yml`) append:
|
|
59
|
+
|
|
60
|
+
```yaml
|
|
61
|
+
# 覆盖 dsh-slack 的 slack 行配置(整体替换)
|
|
62
|
+
- id: slack
|
|
63
|
+
config:
|
|
64
|
+
token: 'xoxb-你的机器人令牌'
|
|
65
|
+
appToken: 'xapp-你的App级令牌'
|
|
66
|
+
defaultChannel: '#general'
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
> Priority: `config.token` > env var `DSH_SLACK_TOKEN`; `config.appToken` > env var
|
|
70
|
+
> `DSH_SLACK_APP_TOKEN`.
|
|
71
|
+
|
|
72
|
+
### Create a Slack App and get a token
|
|
73
|
+
|
|
74
|
+
1. Open <https://api.slack.com/apps>, click **Create New App** (choose `From scratch`, name the app, select the workspace).
|
|
75
|
+
2. On the **OAuth & Permissions** page, under **Scopes → Bot Token Scopes** check:
|
|
76
|
+
- `chat:write` (required to send messages)
|
|
77
|
+
- `channels:read` (required to list channels)
|
|
78
|
+
3. Back at the top, click **Install to Workspace** (authorize).
|
|
79
|
+
4. Grab the **Bot User OAuth Token** (starts with `xoxb-`).
|
|
80
|
+
5. Add the bot (App) to the channels it should post in: `/invite @your-bot` in the channel (required for private channels).
|
|
81
|
+
|
|
82
|
+
### Enable Socket Mode (two-way message receiving)
|
|
83
|
+
|
|
84
|
+
To receive Slack messages (`slack_inbox` / `slack_reply`), enable Socket Mode and generate an App-Level Token:
|
|
85
|
+
|
|
86
|
+
1. Open <https://api.slack.com/apps> and open your App.
|
|
87
|
+
2. Open the **Socket Mode** page → turn on the toggle (**Enable Socket Mode**).
|
|
88
|
+
3. Click **Generate Token and Scopes** to create an App-Level Token: name the token, check the `connections:write` scope.
|
|
89
|
+
Copy the `xapp-` App-Level Token (shown only once — save it immediately).
|
|
90
|
+
4. Open the **Event Subscriptions** page, enable events, and under **Subscribe to bot events → Add Bot User Event** add:
|
|
91
|
+
- `message.channels` (public channel messages)
|
|
92
|
+
- `message.im` (bot DMs)
|
|
93
|
+
5. Put the App-Level Token into `appToken` (or the `DSH_SLACK_APP_TOKEN` env var).
|
|
94
|
+
6. Restart the dsh Web service; the plugin connects automatically via Socket Mode and starts receiving messages.
|
|
95
|
+
|
|
96
|
+
> Without `appToken` the plugin **won't crash**: it only prints a warning and `slack_inbox` returns an empty queue (with a Chinese hint).
|
|
97
|
+
> Socket Mode network errors are auto-reconnected by the SDK; the plugin only logs a warning and never throws.
|
|
98
|
+
|
|
99
|
+
## Tool reference
|
|
100
|
+
|
|
101
|
+
### `slack_notify`
|
|
102
|
+
|
|
103
|
+
Send Markdown text to a channel/thread (underlying `chat.postMessage`).
|
|
104
|
+
|
|
105
|
+
| Param | Type | Required | Description |
|
|
106
|
+
| --- | --- | --- | --- |
|
|
107
|
+
| `channel` | string | yes | Channel name (e.g. `#general`) or channel ID. |
|
|
108
|
+
| `text` | string | yes | The Markdown text to send. |
|
|
109
|
+
| `thread_ts` | string | no | The `ts` of the thread to reply to. |
|
|
110
|
+
|
|
111
|
+
Returns: `{ "ts": "...", "channel": "#general" }` (`ts` for later `thread_ts` reference).
|
|
112
|
+
|
|
113
|
+
### `slack_channels`
|
|
114
|
+
|
|
115
|
+
List channels visible to the bot (underlying `conversations.list`).
|
|
116
|
+
|
|
117
|
+
No parameters. Returns: `{ "channels": [{ "id": "...", "name": "..." }, ...] }`.
|
|
118
|
+
|
|
119
|
+
### `slack_inbox`
|
|
120
|
+
|
|
121
|
+
Read messages received via Socket Mode (in-memory queue, keeps up to 200, newest first).
|
|
122
|
+
|
|
123
|
+
| Param | Type | Required | Description |
|
|
124
|
+
| --- | --- | --- | --- |
|
|
125
|
+
| `limit` | integer | no | Maximum number of messages to return (default 10, range 1-50). |
|
|
126
|
+
| `markRead` | boolean | no | When `true`, clears the inbox queue after returning (mark as read). |
|
|
127
|
+
|
|
128
|
+
Returns: `{ "messages": [{ "ts": "...", "channel": "...", "user": "...", "text": "..." }, ...] }`.
|
|
129
|
+
|
|
130
|
+
### `slack_reply`
|
|
131
|
+
|
|
132
|
+
Reply to an inbox message as a thread (underlying `chat.postMessage` with `thread_ts`).
|
|
133
|
+
|
|
134
|
+
| Param | Type | Required | Description |
|
|
135
|
+
| --- | --- | --- | --- |
|
|
136
|
+
| `channel` | string | yes | Channel name (e.g. `#general`) or channel ID. |
|
|
137
|
+
| `text` | string | yes | Reply content (Markdown text). |
|
|
138
|
+
| `thread_ts` | string | yes | The `ts` of the message to reply to (from `slack_inbox`). |
|
|
139
|
+
|
|
140
|
+
Returns: `{ "ts": "...", "channel": "#general" }`.
|
|
141
|
+
|
|
142
|
+
## Error handling
|
|
143
|
+
|
|
144
|
+
All error messages are in Chinese, readable by both the model and the user:
|
|
145
|
+
|
|
146
|
+
- Unconfigured token: `token 未配置:缺少 Slack 机器人令牌(xoxb-)…请在 profile 的 cordis.patch.yml 覆盖 slack 行的 config.token 并重启,或设置环境变量 DSH_SLACK_TOKEN。`
|
|
147
|
+
- Unconfigured App-Level Token: only a warning; `slack_inbox` returns an empty queue (with a Chinese hint) and other tools are unaffected.
|
|
148
|
+
- `invalid_auth`: hints to check/regenerate the token.
|
|
149
|
+
- `channel_not_found`: hints the channel name or ID is wrong.
|
|
150
|
+
- `not_in_channel`: hints to invite the bot App into the channel first.
|
|
151
|
+
- `token_revoked` / `account_inactive` / `missing_scope` / `not_authed`: hints permission or token expiry, reinstall the App.
|
|
152
|
+
- `is_archived`: hints the channel is archived and cannot receive messages.
|
|
153
|
+
- `msg_too_long`: hints the message exceeds Slack's 40,000-character limit.
|
|
154
|
+
- `ratelimited`: hints to retry after a short wait.
|
|
155
|
+
|
|
156
|
+
## Development and testing
|
|
157
|
+
|
|
158
|
+
```sh
|
|
159
|
+
pnpm install # 安装依赖并触发 prepare(tsc 构建)
|
|
160
|
+
pnpm build # tsc 编译 src → lib
|
|
161
|
+
pnpm test # 先 build,再用 node:test 跑 test/*.test.mjs
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Tests need no real token: parameter compilation, config parsing (incl. env fallback), tool registration (4 tools + Chinese error on missing config),
|
|
165
|
+
injecting a fake client to assert `postMessage` arguments (incl. `thread_ts`), output schema pure-JSON validation,
|
|
166
|
+
inbox queue capacity/clear/deduplication/atomic drain, Socket Mode event parsing (fake event objects), and no-crash on missing appToken.
|
|
167
|
+
|
|
168
|
+
## Known limitations and roadmap
|
|
169
|
+
|
|
170
|
+
- **v0.1 is one-way notification (agent→Slack)**; **v0.2 is two-way via Socket Mode** (`slack_inbox` / `slack_reply`).
|
|
171
|
+
- **No** RTM or interactive components (buttons/modals/slash command replies).
|
|
172
|
+
- `slack_inbox` is an in-process memory queue: cleared on restart, not persisted; keeps up to 200, dropping the oldest when full.
|
|
173
|
+
- `channel` is a required parameter; `defaultChannel` is currently only written into the `channel` parameter description as a hint — it does not replace the required `channel`.
|
|
174
|
+
- With a missing token the plugin still loads (lazy loading); the error is only thrown when the tool is called; a missing appToken only warns.
|
|
175
|
+
|
|
176
|
+
Roadmap: v0.3 plans to introduce interactive components (buttons/modals) and a persisted inbox.
|
|
177
|
+
|
|
178
|
+
## Dependencies
|
|
179
|
+
|
|
180
|
+
- Runtime: `@slack/web-api` (official WebClient), `@slack/socket-mode` (Socket Mode client)
|
|
181
|
+
- peer (provided by the host; not imported directly by the plugin at runtime): `@deepseek-ai/cordis`, `@deepseek-ai/dsh-tools`
|
|
182
|
+
|
|
183
|
+
## License
|
|
184
|
+
|
|
185
|
+
MIT
|
package/docs/USAGE.md
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# dsh-slack 使用说明
|
|
2
|
+
|
|
3
|
+
[返回简介](../README.md) · [更新记录](../CHANGELOG.md) · [验证记录](VALIDATION.md)
|
|
4
|
+
|
|
5
|
+
## 本次改进
|
|
6
|
+
|
|
7
|
+
slack_inbox { limit: 10, markRead: true } 返回 remaining,继续调用可查看余下消息。遇到超时或缺少 ts 时先检查频道,确认未发送后再重试,避免重复通知。
|
|
8
|
+
|
|
9
|
+
## 功能
|
|
10
|
+
|
|
11
|
+
- `slack_notify`:向指定频道(或线程)发送一条 Markdown 文本消息,返回消息 `ts`。
|
|
12
|
+
- `slack_channels`:列出机器人当前可见的频道(`conversations.list`,自动沿 `next_cursor` 翻页拉全)。
|
|
13
|
+
- `slack_inbox`:读取通过 Socket Mode 收到的消息(内存队列,最多保留 200 条;自动去重,`markRead=true` 原子消费)。
|
|
14
|
+
- `slack_reply`:以线程回复形式回复某条收件箱消息(`chat.postMessage` 带 `thread_ts`)。
|
|
15
|
+
- WebClient 按 `token + slackApiUrl` 缓存复用,配置变更时自动重建。
|
|
16
|
+
- 配置走 `cordis.patch.yml`,令牌支持环境变量回退(`DSH_SLACK_TOKEN` / `DSH_SLACK_APP_TOKEN`)。
|
|
17
|
+
|
|
18
|
+
## 安装
|
|
19
|
+
|
|
20
|
+
插件运行在宿主进程内,通过 `dsh plugin` 安装进 profile,重启后生效:
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
dsh plugin --profile web add dsh-slack
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
安装后重启你的 dsh Web 服务,`slack_notify` / `slack_channels` / `slack_inbox` / `slack_reply`
|
|
27
|
+
四个工具即对模型可见。
|
|
28
|
+
|
|
29
|
+
## 配置
|
|
30
|
+
|
|
31
|
+
配置在 profile 的 `cordis.patch.yml` 里按 `id: slack` 覆盖本插件的行(覆盖会整体替换该行的
|
|
32
|
+
`config`,不会合并)。可用配置项:
|
|
33
|
+
|
|
34
|
+
| 键 | 类型 | 必填 | 说明 |
|
|
35
|
+
| --- | --- | --- | --- |
|
|
36
|
+
| `token` | string | 是* | Slack 令牌:机器人令牌(`xoxb-`)或用户令牌(`xoxp-`)。留空时回退到环境变量 `DSH_SLACK_TOKEN`。 |
|
|
37
|
+
| `appToken` | string | 否* | App-Level Token(`xapp-` 开头),开启 Socket Mode 后用于接收消息。留空时回退到环境变量 `DSH_SLACK_APP_TOKEN`。 |
|
|
38
|
+
| `defaultChannel` | string | 否 | 默认频道(如 `#general`)。模型未特别指定频道时的默认目标,写进 `channel` 参数说明里。 |
|
|
39
|
+
|
|
40
|
+
`*` `token` 在「配置层」可留空,此时回退环境变量;两者都为空时插件照常加载,但调用发消息/列频道/
|
|
41
|
+
回复工具时会返回中文报错。`appToken` 留空则只告警、不崩溃,`slack_inbox` 返回空队列(单向模式)。
|
|
42
|
+
|
|
43
|
+
**方式一:环境变量(推荐,不写死令牌)**
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
# 在启动 dsh 的进程里设置
|
|
47
|
+
export DSH_SLACK_TOKEN=xoxb-你的机器人令牌
|
|
48
|
+
export DSH_SLACK_APP_TOKEN=xapp-你的App级令牌
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**方式二:profile 的 cordis.patch.yml 直接覆盖**
|
|
52
|
+
|
|
53
|
+
在你的 profile 目录(`$DSH_HOME/profiles/web/cordis.patch.yml`)追加:
|
|
54
|
+
|
|
55
|
+
```yaml
|
|
56
|
+
# 覆盖 dsh-slack 的 slack 行配置(整体替换)
|
|
57
|
+
- id: slack
|
|
58
|
+
config:
|
|
59
|
+
token: 'xoxb-你的机器人令牌'
|
|
60
|
+
appToken: 'xapp-你的App级令牌'
|
|
61
|
+
defaultChannel: '#general'
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
> 优先级:`config.token` > 环境变量 `DSH_SLACK_TOKEN`;`config.appToken` > 环境变量
|
|
65
|
+
> `DSH_SLACK_APP_TOKEN`。
|
|
66
|
+
|
|
67
|
+
### 创建 Slack App 并拿令牌
|
|
68
|
+
|
|
69
|
+
1. 打开 <https://api.slack.com/apps>,点 **Create New App**(选 `From scratch`,给 App 起名、选工作区)。
|
|
70
|
+
2. 进入 **OAuth & Permissions** 页,在 **Scopes → Bot Token Scopes** 下勾选:
|
|
71
|
+
- `chat:write`(发消息必需)
|
|
72
|
+
- `channels:read`(列频道必需)
|
|
73
|
+
3. 回到顶部点 **Install to Workspace**(授权)。
|
|
74
|
+
4. 拿到 **Bot User OAuth Token**(以 `xoxb-` 开头)。
|
|
75
|
+
5. 把机器人(App)加进它要发消息的频道:在频道里 `/invite @你的机器人`(私有频道必需)。
|
|
76
|
+
|
|
77
|
+
### 开启 Socket Mode(双向收消息)
|
|
78
|
+
|
|
79
|
+
要接收 Slack 消息(`slack_inbox` / `slack_reply`),需要开启 Socket Mode 并生成 App-Level Token:
|
|
80
|
+
|
|
81
|
+
1. 打开 <https://api.slack.com/apps>,进入你的 App。
|
|
82
|
+
2. 左侧 **Socket Mode** 页 → 打开开关(**Enable Socket Mode**)。
|
|
83
|
+
3. 点 **Generate Token and Scopes** 生成 App-Level Token:给 Token 起名,勾选 `connections:write` scope。
|
|
84
|
+
生成后拿到以 `xapp-` 开头的 App-Level Token(只显示一次,请立即保存)。
|
|
85
|
+
4. 进入 **Event Subscriptions** 页,开启事件订阅,在 **Subscribe to bot events → Add Bot User Event** 添加:
|
|
86
|
+
- `message.channels`(公开频道消息)
|
|
87
|
+
- `message.im`(机器人私信)
|
|
88
|
+
5. 把 App-Level Token 配进 `appToken`(或环境变量 `DSH_SLACK_APP_TOKEN`)。
|
|
89
|
+
6. 重启 dsh Web 服务,插件自动通过 Socket Mode 建立连接并开始收消息。
|
|
90
|
+
|
|
91
|
+
> 未配置 `appToken` 时插件**不会崩溃**:只打印告警,`slack_inbox` 返回空队列(中文提示)。
|
|
92
|
+
> Socket Mode 网络错误由 SDK 自动重连,插件只记录告警、不抛崩。
|
|
93
|
+
|
|
94
|
+
## 卸载
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
dsh plugin --profile web remove dsh-slack
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
卸载后重启 Web 服务。如需彻底清理,可再手动删除自己 profile `cordis.patch.yml` 中的对应插件行。
|
|
101
|
+
|
|
102
|
+
## 工具清单
|
|
103
|
+
|
|
104
|
+
### `slack_notify`
|
|
105
|
+
|
|
106
|
+
向指定频道/线程发送 Markdown 文本(底层 `chat.postMessage`)。
|
|
107
|
+
|
|
108
|
+
| 参数 | 类型 | 必填 | 说明 |
|
|
109
|
+
| --- | --- | --- | --- |
|
|
110
|
+
| `channel` | string | 是 | 频道名(如 `#general`)或频道 ID。 |
|
|
111
|
+
| `text` | string | 是 | 要发送的 Markdown 文本。 |
|
|
112
|
+
| `thread_ts` | string | 否 | 回复某条消息所在线程的 `ts`。 |
|
|
113
|
+
|
|
114
|
+
返回:`{ "ts": "...", "channel": "#general" }`(`ts` 供后续 `thread_ts` 引用)。
|
|
115
|
+
|
|
116
|
+
### `slack_channels`
|
|
117
|
+
|
|
118
|
+
列出机器人可见频道(底层 `conversations.list`)。
|
|
119
|
+
|
|
120
|
+
无参数。返回:`{ "channels": [{ "id": "...", "name": "..." }, ...] }`。
|
|
121
|
+
|
|
122
|
+
### `slack_inbox`
|
|
123
|
+
|
|
124
|
+
读取通过 Socket Mode 收到的消息(内存队列,最多保留 200 条,新的在前)。
|
|
125
|
+
|
|
126
|
+
| 参数 | 类型 | 必填 | 说明 |
|
|
127
|
+
| --- | --- | --- | --- |
|
|
128
|
+
| `limit` | integer | 否 | 最多返回的消息数(默认 10,范围 1-50)。 |
|
|
129
|
+
| `markRead` | boolean | 否 | 为 `true` 时,返回后清空收件箱队列(标记已读)。 |
|
|
130
|
+
|
|
131
|
+
返回:`{ "messages": [{ "ts": "...", "channel": "...", "user": "...", "text": "..." }, ...] }`。
|
|
132
|
+
|
|
133
|
+
### `slack_reply`
|
|
134
|
+
|
|
135
|
+
以线程回复形式回复某条收件箱消息(底层 `chat.postMessage` 带 `thread_ts`)。
|
|
136
|
+
|
|
137
|
+
| 参数 | 类型 | 必填 | 说明 |
|
|
138
|
+
| --- | --- | --- | --- |
|
|
139
|
+
| `channel` | string | 是 | 频道名(如 `#general`)或频道 ID。 |
|
|
140
|
+
| `text` | string | 是 | 回复内容(Markdown 文本)。 |
|
|
141
|
+
| `thread_ts` | string | 是 | 要回复消息的 `ts`(来自 `slack_inbox` 返回的 `ts`)。 |
|
|
142
|
+
|
|
143
|
+
返回:`{ "ts": "...", "channel": "#general" }`。
|
|
144
|
+
|
|
145
|
+
## 错误处理
|
|
146
|
+
|
|
147
|
+
所有错误信息均为中文,模型与用户都能直接读懂:
|
|
148
|
+
|
|
149
|
+
- 未配置令牌:`token 未配置:缺少 Slack 机器人令牌(xoxb-)…请在 profile 的 cordis.patch.yml 覆盖 slack 行的 config.token 并重启,或设置环境变量 DSH_SLACK_TOKEN。`
|
|
150
|
+
- 未配置 App-Level Token:只告警,`slack_inbox` 返回空队列(含中文提示),不影响其它工具。
|
|
151
|
+
- `invalid_auth`:提示检查/重新生成 token。
|
|
152
|
+
- `channel_not_found`:提示频道名或频道 ID 错误。
|
|
153
|
+
- `not_in_channel`:提示先把机器人 App 邀请进频道。
|
|
154
|
+
- `token_revoked` / `account_inactive` / `missing_scope` / `not_authed`:提示权限或令牌失效,需重新安装 App。
|
|
155
|
+
- `is_archived`:提示频道已归档,不能发消息。
|
|
156
|
+
- `msg_too_long`:提示 Slack 单条消息超过 40,000 字符。
|
|
157
|
+
- `ratelimited`:提示请求太频繁,稍后重试。
|
|
158
|
+
|
|
159
|
+
## 开发与测试
|
|
160
|
+
|
|
161
|
+
```sh
|
|
162
|
+
pnpm install # 安装依赖并触发 prepare(tsc 构建)
|
|
163
|
+
pnpm build # tsc 编译 src → lib
|
|
164
|
+
pnpm test # 先 build,再用 node:test 跑 test/*.test.mjs
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
测试无需真实 token:参数编译、配置解析(含 env 回退)、工具注册(4 个工具 + 缺配置中文报错)、
|
|
168
|
+
注入 fake client 断言 `postMessage` 参数(含 `thread_ts`)、输出 schema 纯 JSON 校验、
|
|
169
|
+
收件箱队列容量/清空/去重/原子 drain、Socket Mode 事件解析(fake event 对象)、appToken 缺失不崩。
|
|
170
|
+
|
|
171
|
+
## 已知限制与路线图
|
|
172
|
+
|
|
173
|
+
- **v0.1 是单向通知(agent→Slack)**;**v0.2 通过 Socket Mode 实现双向**(`slack_inbox` / `slack_reply`)。
|
|
174
|
+
- **不支持** RTM、交互组件(按钮/弹窗/slash command 回复)。
|
|
175
|
+
- `slack_inbox` 为进程内存队列:重启即清空,且不持久化;最多保留 200 条,满则丢最旧。
|
|
176
|
+
- `channel` 为必填参数,`defaultChannel` 目前只作为说明提示写入 `channel` 参数描述,不替代
|
|
177
|
+
必填的 `channel`。
|
|
178
|
+
- 令牌缺失时插件仍会加载(懒加载),错误在工具被调用时才抛出;appToken 缺失则仅告警。
|
|
179
|
+
|
|
180
|
+
路线图:v0.3 计划引入交互组件(按钮/弹窗)与持久化收件箱。
|
|
181
|
+
|
|
182
|
+
## 依赖
|
|
183
|
+
|
|
184
|
+
- 运行时:`@slack/web-api`(官方 WebClient)、`@slack/socket-mode`(Socket Mode 客户端)
|
|
185
|
+
- peer(由宿主提供,插件运行时不直接 import):`@deepseek-ai/cordis`、`@deepseek-ai/dsh-tools`
|
|
186
|
+
|
|
187
|
+
## License
|
|
188
|
+
|
|
189
|
+
MIT
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# dsh-slack 验证记录
|
|
2
|
+
|
|
3
|
+
本页整理原 README 的历史验证说明,保留当时的版本、日期与范围。自动测试、启动检查、浏览器操作和真实服务验收分别记录,不能相互替代。更详细的版本验收文件仍保留在仓库中。
|
|
4
|
+
|
|
5
|
+
## 原中文记录
|
|
6
|
+
|
|
7
|
+
验证宿主:官方发布标签源码构建的 Harness `0.2.0-rc.2`(commit `639ed01539`)+ Windows / Node `24.16.0`。43 项插件测试通过;同一个宿主里 18 个插件共同加载,本插件的 5 个工具全部注册,工具 schema 与健康检查契约通过。真实 Slack 登录、Socket Mode 收件和发送尚未验收。
|
|
8
|
+
|
|
9
|
+
0.3.3 使用支持 Undici 7/8 的官方 Socket Mode SDK 3.1 或更新版本,并显式声明匹配的传输依赖,修复组合安装中旧 SDK 与宿主 Undici 8 的依赖不匹配;npm 包同时包含中英文说明。
|
|
10
|
+
|
|
11
|
+
> **v0.2 范围(双向)**:v0.1 只做「agent → Slack」单向通知;v0.2 新增 Socket Mode,
|
|
12
|
+
> 支持「Slack 消息 → agent」:`slack_inbox` 收取消息、`slack_reply` 线程回复。
|
|
13
|
+
> RTM、交互组件(按钮/弹窗/slash command 回复)不在 v0.2,见下方
|
|
14
|
+
> [已知限制与路线图](USAGE.md#已知限制与路线图)。
|
|
15
|
+
|
|
16
|
+
## Original English record
|
|
17
|
+
|
|
18
|
+
Validation host: Harness `0.2.0-rc.2` built from its official release tag (commit `639ed01539`), Windows and Node `24.16.0`. All 43 plugin tests pass; all 18 plugins mount together and this plugin registers all five tools, with tool schemas and health-check contracts passing. Real Slack authorization, Socket Mode delivery and sending have not been verified.
|
|
19
|
+
|
|
20
|
+
Version 0.3.3 requires the official Socket Mode SDK 3.1 or newer, which supports Undici 7/8, and explicitly declares its transport dependency. This fixes combined installations that paired an older SDK with the host's Undici 8. Both language versions of this README are included in the npm package.
|
package/lib/inbox.d.ts
CHANGED
package/lib/inbox.js
CHANGED
|
@@ -27,11 +27,11 @@ export class InboxQueue {
|
|
|
27
27
|
if (this.seen.has(key))
|
|
28
28
|
return;
|
|
29
29
|
this.seen.add(key);
|
|
30
|
+
while (this.seen.size > Math.max(200, this.capacity * 4))
|
|
31
|
+
this.seen.delete(this.seen.values().next().value);
|
|
30
32
|
this.items.push(message);
|
|
31
33
|
if (this.items.length > this.capacity) {
|
|
32
|
-
|
|
33
|
-
for (const item of removed)
|
|
34
|
-
this.seen.delete(this.key(item));
|
|
34
|
+
this.items.splice(0, this.items.length - this.capacity);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
/** 返回最近 limit 条消息(新的在前)。 */
|
|
@@ -42,24 +42,20 @@ export class InboxQueue {
|
|
|
42
42
|
return this.items.slice(-n).reverse();
|
|
43
43
|
}
|
|
44
44
|
/**
|
|
45
|
-
* 原子地取出最近 limit
|
|
45
|
+
* 原子地取出最近 limit 条,只将返回的消息标记为已读。
|
|
46
46
|
* 避免“先 list 再 clear”之间新到的消息被误清掉。
|
|
47
47
|
*/
|
|
48
48
|
drain(limit) {
|
|
49
49
|
const n = Math.max(0, Math.trunc(limit));
|
|
50
50
|
if (n === 0) {
|
|
51
|
-
this.clear();
|
|
52
51
|
return [];
|
|
53
52
|
}
|
|
54
53
|
const out = this.items.splice(-n).reverse();
|
|
55
|
-
this.items = [];
|
|
56
|
-
this.seen.clear();
|
|
57
54
|
return out;
|
|
58
55
|
}
|
|
59
56
|
/** 清空队列。 */
|
|
60
57
|
clear() {
|
|
61
58
|
this.items = [];
|
|
62
|
-
this.seen.clear();
|
|
63
59
|
}
|
|
64
60
|
/** 当前队列长度。 */
|
|
65
61
|
get size() {
|
package/lib/slack-client.js
CHANGED
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
import { WebClient } from '@slack/web-api';
|
|
6
6
|
/** 用官方 WebClient 实现。 */
|
|
7
7
|
export function createWebSlackClient(token, slackApiUrl) {
|
|
8
|
-
const client = new WebClient(token, {
|
|
8
|
+
const client = new WebClient(token, {
|
|
9
|
+
timeout: 25000, retryConfig: { retries: 0 }, rejectRateLimitedCalls: true,
|
|
10
|
+
...(slackApiUrl !== undefined && slackApiUrl !== '' ? { slackApiUrl } : {})
|
|
11
|
+
});
|
|
9
12
|
return {
|
|
10
13
|
async postMessage(params) {
|
|
11
14
|
const result = await client.chat.postMessage({
|
|
@@ -14,6 +17,8 @@ export function createWebSlackClient(token, slackApiUrl) {
|
|
|
14
17
|
...(params.thread_ts !== undefined ? { thread_ts: params.thread_ts } : {}),
|
|
15
18
|
});
|
|
16
19
|
const ts = typeof result.ts === 'string' ? result.ts : '';
|
|
20
|
+
if (!ts)
|
|
21
|
+
throw new Error('Slack 未返回消息回执,无法确认提交结果;请先检查频道,避免直接重发。');
|
|
17
22
|
return { ts };
|
|
18
23
|
},
|
|
19
24
|
async listChannels() {
|
|
@@ -21,8 +26,7 @@ export function createWebSlackClient(token, slackApiUrl) {
|
|
|
21
26
|
let pages = 0;
|
|
22
27
|
const allChannels = [];
|
|
23
28
|
const seen = new Set();
|
|
24
|
-
//
|
|
25
|
-
// 必须沿 next_cursor 翻完,否则模型会漏掉后面的频道。
|
|
29
|
+
// Follow the official pagination cursor, with the existing 20-page cap.
|
|
26
30
|
do {
|
|
27
31
|
pages += 1;
|
|
28
32
|
if (pages > 20)
|
|
@@ -41,12 +45,6 @@ export function createWebSlackClient(token, slackApiUrl) {
|
|
|
41
45
|
cursor = typeof next === 'string' && next !== cursor ? next : '';
|
|
42
46
|
} while (cursor !== '');
|
|
43
47
|
return allChannels;
|
|
44
|
-
/*
|
|
45
|
-
// if (typeof ch.id === 'string' && typeof ch.name === 'string') {
|
|
46
|
-
// allChannels.push({ id: ch.id, name: ch.name })
|
|
47
|
-
*/
|
|
48
|
-
// }
|
|
49
|
-
// removed duplicate return
|
|
50
48
|
},
|
|
51
49
|
};
|
|
52
50
|
}
|
package/lib/tools.js
CHANGED
|
@@ -32,6 +32,7 @@ const CHANNELS_OUTPUT_SCHEMA = {
|
|
|
32
32
|
const INBOX_OUTPUT_SCHEMA = {
|
|
33
33
|
type: 'object',
|
|
34
34
|
properties: {
|
|
35
|
+
remaining: { type: 'integer' },
|
|
35
36
|
messages: {
|
|
36
37
|
type: 'array',
|
|
37
38
|
items: {
|
|
@@ -47,7 +48,7 @@ const INBOX_OUTPUT_SCHEMA = {
|
|
|
47
48
|
},
|
|
48
49
|
},
|
|
49
50
|
},
|
|
50
|
-
required: ['messages'],
|
|
51
|
+
required: ['messages', 'remaining'],
|
|
51
52
|
additionalProperties: true,
|
|
52
53
|
};
|
|
53
54
|
function textBlock(text) {
|
|
@@ -170,7 +171,7 @@ export function buildChannelsTool(deps) {
|
|
|
170
171
|
export function buildInboxTool(deps) {
|
|
171
172
|
const parameters = compileParameters({
|
|
172
173
|
limit: { type: 'integer', description: '最多返回的消息数(默认 10,范围 1-50)。' },
|
|
173
|
-
markRead: { type: 'boolean', description: '为 true
|
|
174
|
+
markRead: { type: 'boolean', description: '为 true 时,只将本次返回的消息标记已读;未返回的消息继续保留。' },
|
|
174
175
|
});
|
|
175
176
|
const output = {
|
|
176
177
|
schema: INBOX_OUTPUT_SCHEMA,
|
|
@@ -180,7 +181,7 @@ export function buildInboxTool(deps) {
|
|
|
180
181
|
return [textBlock('收件箱为空:尚未开启 Socket Mode(缺少 appToken),或暂未收到新的 Slack 消息。请确认已配置 appToken 并订阅 message.channels / message.im 事件。')];
|
|
181
182
|
}
|
|
182
183
|
const lines = v.messages.map((m) => '[' + m.channel + '] ' + m.user + '(ts: ' + m.ts + '):' + m.text);
|
|
183
|
-
return [textBlock('收件箱(' + v.messages.length + '
|
|
184
|
+
return [textBlock('收件箱(' + v.messages.length + ' 条,新的在前;剩余未读 ' + (v.remaining ?? 0) + ' 条):\n' + lines.join('\n'))];
|
|
184
185
|
},
|
|
185
186
|
};
|
|
186
187
|
return {
|
|
@@ -194,7 +195,7 @@ export function buildInboxTool(deps) {
|
|
|
194
195
|
const markRead = raw.markRead === true;
|
|
195
196
|
const queue = deps.inboxProvider();
|
|
196
197
|
const messages = markRead ? queue.drain(limit) : queue.list(limit);
|
|
197
|
-
return { messages: messages.map((m) => ({ ts: m.ts, channel: m.channel, user: m.user, text: m.text })) };
|
|
198
|
+
return { messages: messages.map((m) => ({ ts: m.ts, channel: m.channel, user: m.user, text: m.text })), remaining: queue.size };
|
|
198
199
|
},
|
|
199
200
|
};
|
|
200
201
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-slack",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.3.4",
|
|
4
|
+
"description": "连接 Slack,发送通知并处理 Socket Mode 收件箱与线程回复。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
7
7
|
"types": "./lib/index.d.ts",
|
|
@@ -16,7 +16,10 @@
|
|
|
16
16
|
"files": [
|
|
17
17
|
"lib",
|
|
18
18
|
"cordis.patch.yml",
|
|
19
|
-
"README.md"
|
|
19
|
+
"README.md",
|
|
20
|
+
"README.en.md",
|
|
21
|
+
"docs",
|
|
22
|
+
"CHANGELOG.md"
|
|
20
23
|
],
|
|
21
24
|
"license": "MIT",
|
|
22
25
|
"dsh": {
|
|
@@ -31,8 +34,9 @@
|
|
|
31
34
|
"test:protocol": "node test/protocol-acceptance.mjs"
|
|
32
35
|
},
|
|
33
36
|
"dependencies": {
|
|
34
|
-
"@slack/socket-mode": "^3.
|
|
35
|
-
"@slack/web-api": "^8.0.0"
|
|
37
|
+
"@slack/socket-mode": "^3.1.0",
|
|
38
|
+
"@slack/web-api": "^8.0.0",
|
|
39
|
+
"undici": "^7.0.0 || ^8.0.0"
|
|
36
40
|
},
|
|
37
41
|
"devDependencies": {
|
|
38
42
|
"@types/node": "^24.0.0",
|