@xmanrui/dsh-im 0.2.1 → 0.3.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.
Files changed (39) hide show
  1. package/README.md +19 -11
  2. package/lib/client.js +1847 -1145
  3. package/lib/index.js +116 -115
  4. package/package.json +2 -2
  5. package/plugin-src/client/channel-logos.js +13 -0
  6. package/plugin-src/client/channels/dingtalk/index.js +1 -1
  7. package/plugin-src/client/channels/dingtalk/styles.js +8 -8
  8. package/plugin-src/client/channels/feishu/index.js +1 -2
  9. package/plugin-src/client/channels/feishu/styles.js +3 -3
  10. package/plugin-src/client/channels/qq/index.js +1 -1
  11. package/plugin-src/client/channels/shared/token-channel.js +1 -2
  12. package/plugin-src/client/channels/slack/api.js +11 -0
  13. package/plugin-src/client/channels/slack/index.js +130 -0
  14. package/plugin-src/client/channels/slack/styles.js +34 -0
  15. package/plugin-src/client/channels/wecom/index.js +1 -1
  16. package/plugin-src/client/channels/wecom/styles.js +1 -1
  17. package/plugin-src/client/channels/weixin/index.js +1 -2
  18. package/plugin-src/client/channels/weixin/styles.js +9 -9
  19. package/plugin-src/client/channels/whatsapp/index.js +1 -1
  20. package/plugin-src/client/credential-binding.js +1 -2
  21. package/plugin-src/client/i18n.js +443 -0
  22. package/plugin-src/client/index.js +29 -4
  23. package/plugin-src/client/styles.js +46 -38
  24. package/plugin-src/host/channels/shared/production.mjs +2 -2
  25. package/plugin-src/host/channels/slack/index.mjs +28 -0
  26. package/plugin-src/host/channels/slack/production.mjs +91 -0
  27. package/plugin-src/host/channels/slack/rpc.mjs +127 -0
  28. package/plugin-src/host/index.mjs +3 -0
  29. package/scripts/verify-package.mjs +10 -3
  30. package/src/channels/discord/discord-api.mjs +1 -1
  31. package/src/channels/slack/config-store.mjs +173 -0
  32. package/src/channels/slack/harness-client.mjs +3 -0
  33. package/src/channels/slack/manifest.mjs +31 -0
  34. package/src/channels/slack/slack-api.mjs +259 -0
  35. package/src/channels/slack/slack-bridge.mjs +15 -0
  36. package/src/channels/slack/slack-controller.mjs +318 -0
  37. package/src/channels/slack/slack-runtime.mjs +462 -0
  38. package/src/channels/slack/state-store.mjs +3 -0
  39. package/src/channels/weixin/weixin-api.mjs +1 -1
@@ -0,0 +1,443 @@
1
+ import * as React from 'react';
2
+
3
+ export const IM_LOCALE_NAMESPACE = 'dsh-im';
4
+
5
+ const EN = Object.freeze({
6
+ '$locale': 'en',
7
+ 'IM机器人': 'IM bots',
8
+ 'IM机器人设置': 'IM bot settings',
9
+ 'IM 渠道': 'IM channels',
10
+ '把机器人接入 DeepSeek Harness': 'Connect bots to DeepSeek Harness',
11
+ '微信': 'WeChat',
12
+ '飞书': 'Feishu',
13
+ '钉钉': 'DingTalk',
14
+ '企业微信': 'WeCom',
15
+ '微信机器人': 'WeChat bot',
16
+ '飞书机器人': 'Feishu bot',
17
+ '钉钉机器人': 'DingTalk bot',
18
+ '企业微信机器人': 'WeCom bot',
19
+ 'QQ机器人': 'QQ bot',
20
+ 'WhatsApp机器人': 'WhatsApp bot',
21
+ 'WhatsApp账号': 'WhatsApp account',
22
+ '微信设置': 'WeChat settings',
23
+ '飞书机器人设置': 'Feishu bot settings',
24
+ '钉钉设置': 'DingTalk settings',
25
+ '企业微信设置': 'WeCom settings',
26
+ '扫码接入机器人': 'Scan QR code',
27
+ '正在接入': 'Connecting',
28
+ '手动接入': 'Manual setup',
29
+ '收起凭据': 'Hide credentials',
30
+ '收起接入': 'Hide setup',
31
+ '接入机器人': 'Connect bot',
32
+ '开始接入': 'Start setup',
33
+ '在线': 'online',
34
+ '运行正常': 'Connected',
35
+ '正在连接': 'Connecting',
36
+ '正在连接…': 'Connecting…',
37
+ '连接未就绪': 'Not connected',
38
+ '连接中': 'Connecting',
39
+ '连接中断': 'Disconnected',
40
+ '需要处理': 'Needs attention',
41
+ '状态未知': 'Unknown status',
42
+ '离线': 'Offline',
43
+ '已断开': 'Disconnected',
44
+ '消息通道': 'Message channel',
45
+ '最近检查': 'Last checked',
46
+ '尚未检查': 'Not checked yet',
47
+ '刚刚': 'Just now',
48
+ '检查连接': 'Check connection',
49
+ '检查中…': 'Checking…',
50
+ '重试连接': 'Reconnect',
51
+ '重试中…': 'Retrying…',
52
+ '移除接入': 'Remove connection',
53
+ '确认移除接入': 'Remove connection',
54
+ '确认移除': 'Remove',
55
+ '正在移除…': 'Removing…',
56
+ '保留机器人': 'Keep bot',
57
+ '保留账号': 'Keep account',
58
+ '取消': 'Cancel',
59
+ '关闭': 'Close',
60
+ '立即重试': 'Retry now',
61
+ '重新读取': 'Reload',
62
+ '重新生成二维码': 'Generate a new QR code',
63
+ '重新生成二维码后继续': 'Generate a new QR code',
64
+ '刷新二维码': 'Refresh QR code',
65
+ '刷新中…': 'Refreshing…',
66
+ '换一个二维码': 'Get another QR code',
67
+ '继续连接': 'Continue connecting',
68
+ '绑定并连接': 'Connect',
69
+ '正在绑定…': 'Connecting…',
70
+ '验证并连接': 'Verify and connect',
71
+ '正在验证并连接…': 'Verifying and connecting…',
72
+ '正在验证…': 'Verifying…',
73
+ '操作失败,请稍后重试': 'The operation failed. Try again later.',
74
+ '请稍后重试': 'Try again later.',
75
+ '当前二维码有效时间': 'QR code expires in',
76
+ '二维码有效时间': 'QR code expires in',
77
+ '二维码已过期': 'QR code expired',
78
+ '二维码已失效': 'QR code expired',
79
+ '二维码已过期\n请重新生成': 'QR code expired\nGenerate a new one',
80
+ '二维码图片正在生成…': 'Generating QR code…',
81
+ '二维码正在生成…': 'Generating QR code…',
82
+ '二维码正在自动刷新…': 'Refreshing QR code…',
83
+ '二维码未就绪,请打开授权链接': 'The QR code is not ready. Open the authorization link.',
84
+ '二维码图片未就绪,请使用备用链接。': 'The QR code is not ready. Use the alternate link.',
85
+ '二维码图片未就绪,请重新生成。': 'The QR code is not ready. Generate a new one.',
86
+ '等待刷新': 'Waiting to refresh',
87
+ '正在刷新二维码': 'Refreshing QR code',
88
+ '打开备用链接': 'Open alternate link',
89
+ '生成二维码': 'Generate QR code',
90
+ '生成微信二维码': 'Generate WeChat QR code',
91
+ '生成飞书二维码': 'Generate Feishu QR code',
92
+ '生成钉钉二维码': 'Generate DingTalk QR code',
93
+ '生成企业微信二维码': 'Generate WeCom QR code',
94
+ '生成 QQ 二维码': 'Generate QQ QR code',
95
+ '正在生成二维码…': 'Generating QR code…',
96
+ '正在准备授权二维码': 'Preparing authorization QR code',
97
+ '正在准备微信二维码': 'Preparing WeChat QR code',
98
+ '正在添加新机器人': 'Adding a new bot',
99
+ '正在申请钉钉授权二维码…': 'Requesting DingTalk authorization QR code…',
100
+ '正在申请企业微信二维码…': 'Requesting WeCom QR code…',
101
+ '正在申请 QQ 二维码…': 'Requesting QQ QR code…',
102
+ '正在生成 WhatsApp 二维码': 'Generating WhatsApp QR code',
103
+ '扫码,创建第一个飞书入口': 'Scan to create your first Feishu bot',
104
+ '扫码只会新增一个机器人,已接入的机器人会继续正常收发消息。': 'Scanning adds one bot. Existing bots will continue to send and receive messages.',
105
+ '无需手动填写 App ID。以后还可以继续添加机器人,分别服务不同团队或飞书租户。': 'No App ID is required. You can add more bots later for different teams or Feishu tenants.',
106
+ '使用飞书扫码创建机器人': 'Scan with Feishu to create a bot',
107
+ '刷新二维码后继续': 'Refresh the QR code to continue',
108
+ '打开飞书移动端,使用扫一扫读取二维码': 'Open Feishu on your phone and scan the QR code',
109
+ '核对应用名称与权限范围,并确认创建': 'Review the app name and permissions, then confirm',
110
+ '保持本页打开,等待新机器人的长连接就绪': 'Keep this page open until the bot connection is ready',
111
+ '在飞书中打开': 'Open in Feishu',
112
+ '取消添加': 'Cancel',
113
+ '已确认,正在连接新机器人': 'Confirmed. Connecting the new bot',
114
+ '正在安全保存凭据并检查新机器人的消息通道,其他机器人不会中断。': 'Saving credentials and checking the new bot connection. Existing bots will not be interrupted.',
115
+ '正在向飞书申请一次性授权二维码,请稍候。': 'Requesting a one-time authorization QR code from Feishu…',
116
+ '新机器人没有添加完成': 'The new bot was not added',
117
+ '新飞书机器人已连接,可以开始聊天。': 'The new Feishu bot is connected and ready to chat.',
118
+ '飞书应用创建失败': 'Could not create the Feishu app',
119
+ '机器人已经创建,但暂时无法确认连接状态': 'The bot was created, but its connection could not be confirmed yet',
120
+ '机器人仍未连接': 'The bot is still offline',
121
+ '机器人尚未连接': 'The bot is not connected yet',
122
+ '长连接运行正常': 'Persistent connection is healthy',
123
+ '长连接': 'Persistent connection',
124
+ '应用标识已安全保存': 'App identifier stored securely',
125
+ '机器人标识已安全保存': 'Bot identifier stored securely',
126
+ '已安全保存': 'Stored securely',
127
+ '已接入的微信账号': 'Connected WeChat accounts',
128
+ '已接入的机器人': 'Connected bots',
129
+ '已接入的钉钉机器人': 'Connected DingTalk bots',
130
+ '已绑定的企业微信机器人': 'Connected WeCom bots',
131
+ '已绑定的 QQ 机器人': 'Connected QQ bots',
132
+ '已接入的 WhatsApp 机器人': 'Connected WhatsApp accounts',
133
+ '使用手机微信扫描二维码': 'Scan with WeChat on your phone',
134
+ '扫一次码,就能在微信里使用 Harness': 'Scan once to use Harness in WeChat',
135
+ '打开手机微信并扫描左侧二维码': 'Open WeChat on your phone and scan the QR code',
136
+ '在微信中确认连接该机器人': 'Confirm the bot connection in WeChat',
137
+ '保持本页打开,等待机器人自动连接': 'Keep this page open while the bot connects',
138
+ '等待微信扫码': 'Waiting for WeChat scan',
139
+ '需要配对码': 'Pairing code required',
140
+ '输入手机微信显示的数字': 'Enter the number shown in WeChat',
141
+ '微信配对码': 'WeChat pairing code',
142
+ '已扫码,请在手机上确认': 'Scanned. Confirm on your phone',
143
+ '配对码已提交,正在等待微信确认。': 'Pairing code submitted. Waiting for WeChat confirmation.',
144
+ '这是微信附加的安全确认步骤。配对码只用于本次扫码轮询,不会写入配置或日志。': 'This is an additional WeChat confirmation step. The pairing code is used only for this connection and is never stored.',
145
+ '正在保存凭据并验证 Harness 与微信长轮询。': 'Saving credentials and verifying the WeChat connection.',
146
+ '微信已确认,正在启动消息连接': 'Confirmed in WeChat. Starting the message connection',
147
+ '微信已绑定,可以开始向已绑定的机器人发消息。': 'WeChat is connected and ready for messages.',
148
+ '这个微信账号已经绑定并保持在线。': 'This WeChat account is connected and online.',
149
+ '微信账号及本机凭据已移除。': 'The WeChat account and local credentials were removed.',
150
+ '已取消微信绑定。': 'WeChat setup was cancelled.',
151
+ '正在联系腾讯微信 iLink 服务。': 'Contacting the WeChat iLink service.',
152
+ 'iLink 长轮询': 'iLink long polling',
153
+ '扫一次码,自动创建并连接机器人': 'Scan once to create and connect a bot',
154
+ '使用钉钉 App 完成机器人授权': 'Authorize the bot with the DingTalk app',
155
+ '使用已加入企业/组织的钉钉账号扫描左侧二维码': 'Scan the QR code with a DingTalk account that belongs to an organization',
156
+ '在授权页点击“一键创建新机器人”': 'Select “Create new bot” on the authorization page',
157
+ '请勿关闭本页,钉钉完成授权后将自动继续。': 'Keep this page open. Setup will continue after DingTalk authorization.',
158
+ '等待钉钉扫码授权': 'Waiting for DingTalk authorization',
159
+ '授权已确认,正在创建钉钉机器人': 'Authorized. Creating the DingTalk bot',
160
+ '正在确认钉钉授权': 'Confirming DingTalk authorization',
161
+ '正在检查钉钉 Stream 长连接,成功后会自动显示为在线。': 'Checking the DingTalk Stream connection. It will appear online when ready.',
162
+ '钉钉机器人已接入,可以开始发送消息。': 'The DingTalk bot is connected and ready for messages.',
163
+ '这个钉钉机器人已经接入并保持在线。': 'This DingTalk bot is connected and online.',
164
+ 'Stream 长连接': 'Stream persistent connection',
165
+ '使用企业微信 App 扫码创建智能机器人': 'Scan with WeCom to create an AI bot',
166
+ '使用企业微信 App 完成智能机器人授权': 'Authorize the AI bot with WeCom',
167
+ '打开企业微信 App,扫描左侧二维码': 'Open WeCom and scan the QR code',
168
+ '在腾讯授权页面确认创建智能机器人': 'Confirm bot creation on the Tencent authorization page',
169
+ '返回这里等待连接完成': 'Return here and wait for the connection to complete',
170
+ '等待企业微信 App 扫码': 'Waiting for WeCom scan',
171
+ '企业微信已授权,正在连接机器人': 'Authorized in WeCom. Connecting the bot',
172
+ '凭据正在写入本机,并启动企业微信 WebSocket 消息连接。': 'Saving credentials locally and starting the WeCom WebSocket connection.',
173
+ 'WebSocket 长连接': 'WebSocket persistent connection',
174
+ '使用手机 QQ 扫码创建并绑定机器人': 'Scan with mobile QQ to create and connect a bot',
175
+ '使用手机 QQ 完成机器人绑定': 'Complete bot setup with mobile QQ',
176
+ '打开手机 QQ,扫描左侧二维码': 'Open mobile QQ and scan the QR code',
177
+ '在腾讯授权页面确认创建或绑定机器人': 'Confirm bot creation or connection on the Tencent authorization page',
178
+ '等待手机 QQ 扫码': 'Waiting for mobile QQ scan',
179
+ 'QQ 已授权,正在连接机器人': 'Authorized in QQ. Connecting the bot',
180
+ '凭据正在写入本机,并启动 QQ WebSocket 消息连接。': 'Saving credentials locally and starting the QQ WebSocket connection.',
181
+ '使用手机 WhatsApp 扫描二维码即可接入。': 'Scan the QR code with WhatsApp to connect.',
182
+ '用手机 WhatsApp 扫描二维码': 'Scan with WhatsApp on your phone',
183
+ '打开 WhatsApp → 设置 → 已关联设备': 'Open WhatsApp → Settings → Linked devices',
184
+ '点击“关联设备”并扫描左侧二维码': 'Select “Link a device” and scan the QR code',
185
+ '等待 WhatsApp 扫码': 'Waiting for WhatsApp scan',
186
+ '已扫码,正在连接 WhatsApp': 'Scanned. Connecting WhatsApp',
187
+ '正在建立安全的关联设备会话。': 'Creating a secure linked-device session.',
188
+ '关联设备正在接入 DeepSeek Harness。': 'Linking the device to DeepSeek Harness.',
189
+ 'WhatsApp Web 关联设备运行正常': 'WhatsApp linked device is healthy',
190
+ 'Bot API 长轮询': 'Bot API long polling',
191
+ ' Gateway 长连接': ' Gateway persistent connection',
192
+ 'Gateway 长连接': 'Gateway persistent connection',
193
+ ' Socket Mode 长连接': ' Socket Mode persistent connection',
194
+ 'Socket Mode 长连接': 'Socket Mode persistent connection',
195
+ '接入 Telegram 机器人': 'Connect a Telegram bot',
196
+ '先通过 @BotFather 获取 Bot Token,再在这里完成接入。': 'Get a Bot Token from @BotFather, then connect it here.',
197
+ '填写 @BotFather 生成的 Bot Token': 'Enter the Bot Token from @BotFather',
198
+ '接入 Discord 机器人': 'Connect a Discord bot',
199
+ '先在 Developer Portal 创建 Bot 并邀请到服务器,再在这里完成接入。': 'Create a bot in the Developer Portal and invite it to your server, then connect it here.',
200
+ '填写 Discord Developer Portal 的 Bot Token': 'Enter the Bot Token from the Discord Developer Portal',
201
+ '接入 Slack 机器人': 'Connect a Slack bot',
202
+ '先用 Manifest 创建并配置 Slack App': 'Create and configure a Slack app with the manifest',
203
+ '复制配置后,在 Slack 选择 From a manifest;创建完成后生成 connections:write App Token,并将应用安装到工作区。': 'Copy the manifest and choose “From a manifest” in Slack. Then create a connections:write App Token and install the app to your workspace.',
204
+ '复制 Manifest': 'Copy manifest',
205
+ '已复制 Manifest': 'Manifest copied',
206
+ '打开 Slack 创建页': 'Open Slack app creation',
207
+ 'Bot Token 来自 OAuth & Permissions;App Token 来自 Basic Information,并且必须包含 connections:write。': 'Get the Bot Token from OAuth & Permissions and the App Token from Basic Information. The App Token must include connections:write.',
208
+ '使用官方 App Manifest 快速配置机器人,再填写 Bot Token 与 App Token 建立本地 Socket Mode 连接。': 'Configure the bot with the official app manifest, then enter the Bot Token and App Token to start a local Socket Mode connection.',
209
+ 'Slack 工作区': 'Slack workspace',
210
+ 'Bot Token 与 App Token': 'Bot Token and App Token',
211
+ '填写 Bot Token': 'Enter Bot Token',
212
+ '手动接入飞书机器人': 'Connect Feishu bot manually',
213
+ '手动接入钉钉机器人': 'Connect DingTalk bot manually',
214
+ '手动接入企业微信机器人': 'Connect WeCom bot manually',
215
+ '手动接入QQ机器人': 'Connect QQ bot manually',
216
+ '填写飞书开放平台 App ID': 'Enter the Feishu Open Platform App ID',
217
+ '填写飞书开放平台 App Secret': 'Enter the Feishu Open Platform App Secret',
218
+ '填写钉钉应用 Client ID': 'Enter the DingTalk Client ID',
219
+ '填写钉钉应用 Client Secret': 'Enter the DingTalk Client Secret',
220
+ '填写企业微信智能机器人 Bot ID': 'Enter the WeCom AI Bot ID',
221
+ '填写企业微信智能机器人 Secret': 'Enter the WeCom AI Bot Secret',
222
+ '填写 QQ 开放平台 AppID': 'Enter the QQ Open Platform AppID',
223
+ '填写 QQ 开放平台 AppSecret': 'Enter the QQ Open Platform AppSecret',
224
+ '扫码接入微信机器人': 'Connect WeChat bot by QR code',
225
+ '扫码接入飞书机器人': 'Connect Feishu bot by QR code',
226
+ '扫码接入钉钉机器人': 'Connect DingTalk bot by QR code',
227
+ '扫码接入企业微信机器人': 'Connect WeCom bot by QR code',
228
+ '扫码接入 QQ 机器人': 'Connect QQ bot by QR code',
229
+ '扫码接入 WhatsApp 机器人': 'Connect WhatsApp by QR code',
230
+ '扫码绑定 WhatsApp 机器人': 'Connect WhatsApp by QR code',
231
+ '使用 App ID 和 App Secret 绑定飞书机器人': 'Connect a Feishu bot with App ID and App Secret',
232
+ '使用 Client ID 和 Client Secret 绑定钉钉机器人': 'Connect a DingTalk bot with Client ID and Client Secret',
233
+ '使用 Bot ID 和 Secret 绑定企业微信机器人': 'Connect a WeCom bot with Bot ID and Secret',
234
+ '使用 AppID 和 AppSecret 绑定 QQ 机器人': 'Connect a QQ bot with AppID and AppSecret',
235
+ '使用 Manifest 和双 Token 接入 Slack 机器人': 'Connect a Slack bot with a manifest and two tokens',
236
+ '使用 Bot Token 接入 Telegram 机器人': 'Connect a Telegram bot with a Bot Token',
237
+ '使用 Bot Token 接入 Discord 机器人': 'Connect a Discord bot with a Bot Token',
238
+ '取消绑定': 'Cancel setup',
239
+ '取消接入': 'Cancel setup',
240
+ '二维码由腾讯微信 iLink 服务签发。用手机微信扫描并确认后,账号凭据会直接写入 Harness Host,浏览器不会收到 bot_token。': 'The QR code is issued by Tencent WeChat iLink. After you scan and confirm, account credentials are written directly to the Harness Host and are never exposed to the browser.',
241
+ '扫码账号必须已加入企业/组织。如果钉钉提示尚未加入组织,请在提示页创建组织,或换用已加入组织的账号。': 'The DingTalk account must belong to an organization. If prompted, create an organization or use an account that already belongs to one.',
242
+ '请在手机上核对并确认授权。部分账号会额外显示一个配对数字,页面会在需要时提示输入。': 'Review and confirm authorization on your phone. Some accounts may also require a pairing number.',
243
+ '授权由钉钉官方页面完成。扫码账号必须已加入一个企业/组织并有权创建机器人;创建成功后,应用凭据会直接写入 Harness Host。': 'Authorization is completed on DingTalk’s official page. The account must belong to an organization and be allowed to create bots. Credentials are written directly to the Harness Host.',
244
+ '扫码由腾讯官方页面完成,不需要手动填写 AppID 或 AppSecret。扫码成功后,机器人会自动连接 DeepSeek Harness。': 'Scanning is completed on Tencent’s official page. No AppID or AppSecret is required, and the bot connects automatically.',
245
+ '扫码由腾讯官方页面完成,不需要手动填写 Bot ID 或 Secret。创建成功后,机器人会自动连接 DeepSeek Harness。': 'Scanning is completed on Tencent’s official page. No Bot ID or Secret is required, and the bot connects automatically.',
246
+ '腾讯页面会创建或绑定一个 QQ 机器人,并把连接凭据安全交给本机 Harness Host。': 'Tencent will create or connect a QQ bot and securely deliver its credentials to the local Harness Host.',
247
+ '企业微信官方页面会创建一个智能机器人,并把连接凭据安全交给本机 Harness Host。': 'WeCom will create an AI bot and securely deliver its credentials to the local Harness Host.',
248
+ '从此 Harness 移除这个微信账号?': 'Remove this WeChat account from Harness?',
249
+ '这会停止消息连接,并删除本机保存的 bot_token、账号配置和会话映射。其他微信账号不受影响。': 'This stops the message connection and removes the locally stored bot_token, account configuration, and session mappings. Other WeChat accounts are not affected.',
250
+ '此操作会停止这个机器人的连接,并删除保存在本机的接入配置和凭据。飞书开放平台中的应用不会被自动删除,其他机器人也不受影响。': 'This stops the bot connection and removes the locally stored configuration and credentials. The app in Feishu Open Platform is not deleted, and other bots are not affected.',
251
+ '这会停止消息连接,并删除本机保存的应用凭据、机器人配置及会话映射。钉钉开放平台中的机器人不会被自动删除。': 'This stops the message connection and removes the locally stored app credentials, bot configuration, and session mappings. The bot in DingTalk Open Platform is not deleted.',
252
+ '这会停止消息连接,并删除本机保存的应用凭据、机器人配置及会话映射。企业微信平台中的机器人不会被自动删除。': 'This stops the message connection and removes the locally stored app credentials, bot configuration, and session mappings. The bot in WeCom is not deleted.',
253
+ '这会停止消息连接,并删除本机保存的应用凭据、机器人配置及会话映射。腾讯平台中的机器人不会被自动删除。': 'This stops the message connection and removes the locally stored app credentials, bot configuration, and session mappings. The bot on Tencent’s platform is not deleted.',
254
+ '这会停止消息连接,并删除本机保存的 WhatsApp 关联设备和会话映射。': 'This stops the message connection and removes the locally stored WhatsApp linked device and session mappings.',
255
+ '正在读取飞书机器人列表': 'Loading Feishu bots',
256
+ '正在读取飞书连接状态…': 'Loading Feishu connection status…',
257
+ '正在读取微信连接状态…': 'Loading WeChat connection status…',
258
+ '正在读取钉钉连接状态…': 'Loading DingTalk connection status…',
259
+ '通过扫码把钉钉机器人接入 DeepSeek Harness': 'Connect a DingTalk bot to DeepSeek Harness by QR code',
260
+ '钉钉服务没有返回扫码绑定进度': 'DingTalk did not return QR setup progress',
261
+ '钉钉扫码服务没有返回有效的绑定任务': 'DingTalk did not return a valid setup attempt',
262
+ '钉钉 Stream 长连接运行正常': 'DingTalk Stream connection is healthy',
263
+ '钉钉服务没有返回有效的机器人列表': 'DingTalk did not return a valid bot list',
264
+ '${totals.connected} / ${totals.configured} 在线': '${totals.connected} / ${totals.configured} online',
265
+ '用于把钉钉机器人接入 DeepSeek Harness 的一次性二维码': 'One-time QR code for connecting a DingTalk bot to DeepSeek Harness',
266
+ '二维码已过期\\n请重新生成': 'QR code expired\\nGenerate a new one',
267
+ '机器人已创建,正在建立消息连接': 'Bot created. Starting the message connection',
268
+ '钉钉扫码服务没有返回安全的二维码': 'DingTalk did not return a secure QR code',
269
+ '钉钉二维码已生成,请使用钉钉 App 扫描。': 'DingTalk QR code generated. Scan it with the DingTalk app.',
270
+ '钉钉机器人凭据已绑定。': 'DingTalk bot credentials connected.',
271
+ '已取消钉钉机器人接入。': 'DingTalk bot setup cancelled.',
272
+ '钉钉机器人及本机凭据已移除。': 'DingTalk bot and local credentials removed.',
273
+ '飞书服务没有返回二维码信息': 'Feishu did not return QR code information',
274
+ '飞书服务返回的二维码信息不完整': 'Feishu returned incomplete QR code information',
275
+ '飞书服务返回了无效的机器人状态': 'Feishu returned an invalid bot status',
276
+ '飞书服务返回的机器人缺少 botId': 'The Feishu bot is missing botId',
277
+ '飞书服务没有返回连接状态': 'Feishu did not return connection status',
278
+ '飞书服务没有返回创建进度': 'Feishu did not return creation progress',
279
+ '飞书服务返回了未知的创建状态': 'Feishu returned an unknown creation status',
280
+ '已接入 ${totals.configured} 个机器人,其中 ${totals.connected} 个在线': '${totals.connected} of ${totals.configured} bots online',
281
+ '尚未接入机器人': 'No bot connected yet',
282
+ '用于新增 DeepSeek Harness 飞书机器人的一次性授权二维码': 'One-time authorization QR code for adding a Feishu bot to DeepSeek Harness',
283
+ '请刷新后重新扫码': 'Refresh and scan again',
284
+ '${connected ? "检查连接" : "重试连接"}${bot.name}': '${connected ? "Check connection" : "Reconnect"} ${bot.name}',
285
+ '无法读取飞书机器人': 'Could not load Feishu bots',
286
+ '授权二维码已生成,请使用飞书扫码。': 'Authorization QR code generated. Scan it with Feishu.',
287
+ '飞书机器人凭据已绑定。': 'Feishu bot credentials connected.',
288
+ '已取消添加机器人。': 'Adding the bot was cancelled.',
289
+ '${newBot.bot.name}已连接,可以在飞书中开始聊天。': '${newBot.bot.name} is connected and ready to chat in Feishu.',
290
+ '${bot.name}操作失败,请查看机器人状态。': '${bot.name} operation failed. Check the bot status.',
291
+ '${bot.name}已从此 DeepSeek Harness 移除;飞书开放平台中的应用未被删除。': '${bot.name} was removed from this DeepSeek Harness. The app in Feishu Open Platform was not deleted.',
292
+ '无法读取连接状态': 'Could not load connection status',
293
+ 'QQ 服务没有返回扫码绑定进度': 'QQ did not return QR setup progress',
294
+ 'QQ 扫码服务没有返回有效的绑定任务': 'QQ did not return a valid setup attempt',
295
+ 'QQ WebSocket 长连接运行正常': 'QQ WebSocket connection is healthy',
296
+ 'QQ 服务没有返回有效的机器人列表': 'QQ did not return a valid bot list',
297
+ '尚未绑定 QQ 机器人': 'No QQ bot connected yet',
298
+ '用于绑定 QQ 机器人的一次性二维码': 'One-time QR code for connecting a QQ bot',
299
+ '${channel}${connectionSummary}运行正常': '${channel}${connectionSummary} is healthy',
300
+ '${channel} 服务没有返回有效的机器人列表': '${channel} did not return a valid bot list',
301
+ '使用 Bot Token 接入 ${channel} 机器人': 'Connect a ${channel} bot with a Bot Token',
302
+ '${model.totals.connected} / ${model.totals.configured} 在线': '${model.totals.connected}/${model.totals.configured} online',
303
+ ' Bot API 长轮询': ' Bot API long polling',
304
+ '企业微信服务没有返回扫码绑定进度': 'WeCom did not return QR setup progress',
305
+ '企业微信扫码服务没有返回有效的绑定任务': 'WeCom did not return a valid setup attempt',
306
+ '企业微信 WebSocket 长连接运行正常': 'WeCom WebSocket connection is healthy',
307
+ '企业微信服务没有返回有效的机器人列表': 'WeCom did not return a valid bot list',
308
+ '尚未绑定企业微信机器人': 'No WeCom bot connected yet',
309
+ '用于绑定企业微信机器人的一次性二维码': 'One-time QR code for connecting a WeCom bot',
310
+ '微信扫码服务没有返回有效的绑定任务': 'WeChat did not return a valid setup attempt',
311
+ '微信绑定没有完成': 'WeChat setup did not complete',
312
+ '微信连接正常': 'WeChat connection is healthy',
313
+ '微信连接未就绪': 'WeChat connection is not ready',
314
+ '微信服务没有返回有效的账号列表': 'WeChat did not return a valid account list',
315
+ '尚未绑定微信': 'No WeChat account connected yet',
316
+ '用于把微信机器人绑定到 DeepSeek Harness 的一次性二维码': 'One-time QR code for connecting a WeChat bot to DeepSeek Harness',
317
+ '保持本页打开,等待消息长轮询变为在线': 'Keep this page open until long polling is online',
318
+ '微信二维码已生成,请使用手机微信扫描。': 'WeChat QR code generated. Scan it with WeChat on your phone.',
319
+ '移除失败:${presentError(error).message}': 'Removal failed: ${presentError(error).message}',
320
+ '无法读取微信状态': 'Could not load WeChat status',
321
+ 'WhatsApp 服务没有返回扫码进度': 'WhatsApp did not return QR setup progress',
322
+ 'WhatsApp 服务没有返回有效的扫码任务': 'WhatsApp did not return a valid setup attempt',
323
+ 'WhatsApp 服务没有返回有效的机器人列表': 'WhatsApp did not return a valid account list',
324
+ '用于关联 WhatsApp 设备的一次性二维码': 'One-time QR code for linking a WhatsApp device',
325
+ });
326
+
327
+ export const en = EN;
328
+ export const zh = Object.freeze(Object.fromEntries(
329
+ Object.keys(EN).map((key) => [key, key === '$locale' ? 'zh' : key]),
330
+ ));
331
+
332
+ let translate = (key) => key;
333
+
334
+ export function setImTranslator(next) {
335
+ translate = typeof next === 'function' ? next : (key) => key;
336
+ }
337
+
338
+ export function isEnglish() {
339
+ return translate('$locale') === 'en';
340
+ }
341
+
342
+ function channelName(value) {
343
+ return localizeText(value);
344
+ }
345
+
346
+ function translateDynamic(text) {
347
+ let match = /^(\d+) \/ (\d+) 在线$/.exec(text);
348
+ if (match) return `${match[1]}/${match[2]} online`;
349
+ match = /^已接入 (\d+) 个机器人,其中 (\d+) 个在线$/.exec(text);
350
+ if (match) return `${match[2]} of ${match[1]} bots online`;
351
+ match = /^正在读取\s*(.+?)\s*机器人状态…$/.exec(text);
352
+ if (match) return `Loading ${channelName(match[1])} bot status…`;
353
+ match = /^无法读取\s*(.+?)\s*机器人状态$/.exec(text);
354
+ if (match) return `Could not load ${channelName(match[1])} bot status`;
355
+ match = /^尚未接入\s*(.+?)\s*机器人$/.exec(text);
356
+ if (match) return `No ${channelName(match[1])} bot connected yet`;
357
+ match = /^已接入的\s*(.+?)\s*机器人$/.exec(text);
358
+ if (match) return `Connected ${channelName(match[1])} bots`;
359
+ match = /^手动接入(.+)机器人$/.exec(text);
360
+ if (match) return `Connect ${channelName(match[1])} bot manually`;
361
+ match = /^(.+) 设置$/.exec(text);
362
+ if (match) return `${channelName(match[1])} settings`;
363
+ match = /^从 DeepSeek Harness 移除“(.+)”?$/.exec(text);
364
+ if (match) return `Remove “${match[1]}” from DeepSeek Harness?`;
365
+ match = /^从 DeepSeek Harness 移除(.+)$/.exec(text);
366
+ if (match) return `Remove ${match[1]} from DeepSeek Harness`;
367
+ match = /^(检查连接|重试连接)(.+)$/.exec(text);
368
+ if (match) return `${localizeText(match[1])} ${match[2]}`;
369
+ match = /^移除(.+)$/.exec(text);
370
+ if (match) return `Remove ${match[1]}`;
371
+ match = /^这会停止消息连接,并删除本机保存的 (.+)、机器人配置及会话映射。(.+)中的机器人不会被自动删除。$/.exec(text);
372
+ if (match) {
373
+ return `This stops the message connection and removes the locally stored ${localizeText(match[1])}, bot configuration, and session mappings. The bot in ${localizeText(match[2])} is not deleted.`;
374
+ }
375
+ match = /^二维码剩余 (.+)$/.exec(text);
376
+ if (match) return `QR code expires in ${match[1]}`;
377
+ match = /^状态刷新失败:(.+)$/.exec(text);
378
+ if (match) return `Status refresh failed: ${match[1]}`;
379
+ match = /^状态自动刷新失败:(.+)$/.exec(text);
380
+ if (match) return `Automatic status refresh failed: ${match[1]}`;
381
+ match = /^操作失败:(.+)$/.exec(text);
382
+ if (match) return `Operation failed: ${match[1]}`;
383
+ match = /^连接检查失败:(.+)$/.exec(text);
384
+ if (match) return `Connection check failed: ${match[1]}`;
385
+ match = /^移除失败:(.+)$/.exec(text);
386
+ if (match) return `Removal failed: ${match[1]}`;
387
+
388
+ const phrases = [
389
+ ['企业微信', 'WeCom'], ['DeepSeek Harness', 'DeepSeek Harness'],
390
+ ['WhatsApp', 'WhatsApp'], ['Telegram', 'Telegram'], ['Discord', 'Discord'],
391
+ ['Slack', 'Slack'], ['飞书', 'Feishu'], ['钉钉', 'DingTalk'], ['微信', 'WeChat'],
392
+ ['机器人', 'bot'], ['账号', 'account'], ['应用', 'app'], ['凭据', 'credentials'],
393
+ ['服务返回了无法识别的响应', 'service returned an unrecognized response'],
394
+ ['服务没有返回有效的机器人列表', 'service did not return a valid bot list'],
395
+ ['操作失败,请稍后重试', 'operation failed; try again later'],
396
+ ['操作失败', 'operation failed'], ['连接尚未就绪', 'connection is not ready'],
397
+ ['没有接入完成', 'was not connected'], ['没有绑定完成', 'was not connected'],
398
+ ['设置页缺少 RPC 连接', 'settings are missing an RPC connection'],
399
+ ['设置', 'settings'], ['连接检查完成', 'connection check completed'],
400
+ ['仍未连接,插件会继续自动重试', 'is still offline; the plugin will keep retrying'],
401
+ ['已重新连接', 'reconnected'], ['移除失败,请重试', 'could not be removed; try again'],
402
+ ['已连接,可以开始聊天', 'is connected and ready to chat'],
403
+ ['已连接,可以开始发送消息', 'is connected and ready for messages'],
404
+ ['服务请求失败', 'service request failed'], ['连接遇到问题', 'connection encountered a problem'],
405
+ ['正在读取', 'Loading '], ['连接状态', 'connection status'], ['二维码', 'QR code'],
406
+ ];
407
+ let output = text;
408
+ for (const [source, target] of phrases) output = output.replaceAll(source, target);
409
+ return output;
410
+ }
411
+
412
+ export function localizeText(value) {
413
+ if (typeof value !== 'string') return value;
414
+ const exact = translate(value);
415
+ if (exact !== value || !isEnglish()) return exact;
416
+ return translateDynamic(value);
417
+ }
418
+
419
+ const LOCALIZED_PROPS = Object.freeze([
420
+ 'aria-label',
421
+ 'alt',
422
+ 'placeholder',
423
+ 'title',
424
+ ]);
425
+
426
+ function localizeChild(child) {
427
+ if (typeof child === 'string') return localizeText(child);
428
+ if (Array.isArray(child)) return child.map(localizeChild);
429
+ return child;
430
+ }
431
+
432
+ export function h(type, props, ...children) {
433
+ let localizedProps = props;
434
+ if (props) {
435
+ for (const key of LOCALIZED_PROPS) {
436
+ if (typeof props[key] === 'string') {
437
+ localizedProps = localizedProps === props ? { ...props } : localizedProps;
438
+ localizedProps[key] = localizeText(props[key]);
439
+ }
440
+ }
441
+ }
442
+ return React.createElement(type, localizedProps, ...children.map(localizeChild));
443
+ }
@@ -5,6 +5,7 @@ import {
5
5
  DiscordLogoGlyph,
6
6
  FeishuLogoGlyph,
7
7
  QqLogoGlyph,
8
+ SlackLogoGlyph,
8
9
  TelegramLogoGlyph,
9
10
  WecomLogoGlyph,
10
11
  WeixinLogoGlyph,
@@ -21,6 +22,9 @@ import { installFeishuStyles } from './channels/feishu/styles.js';
21
22
  import { QQ_RPC_CHANNEL } from './channels/qq/api.js';
22
23
  import { QqSettingsTab } from './channels/qq/index.js';
23
24
  import { installQqStyles } from './channels/qq/styles.js';
25
+ import { SLACK_RPC_CHANNEL } from './channels/slack/api.js';
26
+ import { SlackSettingsTab } from './channels/slack/index.js';
27
+ import { installSlackStyles } from './channels/slack/styles.js';
24
28
  import { TELEGRAM_RPC_CHANNEL } from './channels/telegram/api.js';
25
29
  import { TelegramSettingsTab } from './channels/telegram/index.js';
26
30
  import { installTelegramStyles } from './channels/telegram/styles.js';
@@ -33,12 +37,11 @@ import { installWeixinStyles } from './channels/weixin/styles.js';
33
37
  import { WHATSAPP_RPC_CHANNEL } from './channels/whatsapp/api.js';
34
38
  import { WhatsappSettingsTab } from './channels/whatsapp/index.js';
35
39
  import { installWhatsappStyles } from './channels/whatsapp/styles.js';
40
+ import { en, h, IM_LOCALE_NAMESPACE, setImTranslator, zh } from './i18n.js';
36
41
  import { installImStyles } from './styles.js';
37
42
 
38
- const h = React.createElement;
39
-
40
43
  export const name = 'im-settings';
41
- export const inject = ['slots', 'connection'];
44
+ export const inject = ['slots', 'connection', 'locale'];
42
45
 
43
46
  const CHANNELS = Object.freeze([
44
47
  { id: 'weixin', label: '微信' },
@@ -46,6 +49,7 @@ const CHANNELS = Object.freeze([
46
49
  { id: 'dingtalk', label: '钉钉' },
47
50
  { id: 'wecom', label: '企业微信' },
48
51
  { id: 'qq', label: 'QQ' },
52
+ { id: 'slack', label: 'Slack' },
49
53
  { id: 'telegram', label: 'Telegram' },
50
54
  { id: 'discord', label: 'Discord' },
51
55
  { id: 'whatsapp', label: 'WhatsApp' },
@@ -79,6 +83,11 @@ function TelegramLogo() {
79
83
  h(TelegramLogoGlyph));
80
84
  }
81
85
 
86
+ function SlackLogo() {
87
+ return h('span', { className: 'dim-logo dim-logoSlack', 'aria-hidden': 'true' },
88
+ h(SlackLogoGlyph));
89
+ }
90
+
82
91
  function DiscordLogo() {
83
92
  return h('span', { className: 'dim-logo dim-logoDiscord', 'aria-hidden': 'true' },
84
93
  h(DiscordLogoGlyph));
@@ -95,6 +104,7 @@ function ChannelLogo({ channel }) {
95
104
  if (channel === 'dingtalk') return h(DingtalkLogo);
96
105
  if (channel === 'wecom') return h(WecomLogo);
97
106
  if (channel === 'qq') return h(QqLogo);
107
+ if (channel === 'slack') return h(SlackLogo);
98
108
  if (channel === 'telegram') return h(TelegramLogo);
99
109
  if (channel === 'discord') return h(DiscordLogo);
100
110
  return h(WhatsappLogo);
@@ -105,6 +115,7 @@ export function IMSettingsTab({
105
115
  discordRpcCall,
106
116
  feishuRpcCall,
107
117
  qqRpcCall,
118
+ slackRpcCall,
108
119
  telegramRpcCall,
109
120
  wecomRpcCall,
110
121
  weixinRpcCall,
@@ -148,6 +159,8 @@ export function IMSettingsTab({
148
159
  ? h(WecomSettingsTab, { rpcCall: wecomRpcCall })
149
160
  : active.id === 'qq'
150
161
  ? h(QqSettingsTab, { rpcCall: qqRpcCall })
162
+ : active.id === 'slack'
163
+ ? h(SlackSettingsTab, { rpcCall: slackRpcCall })
151
164
  : active.id === 'telegram'
152
165
  ? h(TelegramSettingsTab, { rpcCall: telegramRpcCall })
153
166
  : active.id === 'discord'
@@ -158,12 +171,20 @@ export function IMSettingsTab({
158
171
  }
159
172
 
160
173
  export function apply(ctx) {
174
+ ctx.effect(
175
+ () => ctx.locale.register(IM_LOCALE_NAMESPACE, { zh, en }),
176
+ 'im-settings: bilingual dictionaries',
177
+ );
178
+ const t = ctx.locale.bind(IM_LOCALE_NAMESPACE);
179
+ setImTranslator(t);
180
+
161
181
  ctx.effect(() => {
162
182
  const disposers = [
163
183
  installFeishuStyles(),
164
184
  installWeixinStyles(),
165
185
  installWecomStyles(),
166
186
  installQqStyles(),
187
+ installSlackStyles(),
167
188
  installTelegramStyles(),
168
189
  installDiscordStyles(),
169
190
  installWhatsappStyles(),
@@ -190,17 +211,21 @@ export function apply(ctx) {
190
211
  ctx.connection.rpc.call(DISCORD_RPC_CHANNEL, endpoint, payload, signal);
191
212
  const whatsappRpcCall = (endpoint, payload, signal) =>
192
213
  ctx.connection.rpc.call(WHATSAPP_RPC_CHANNEL, endpoint, payload, signal);
214
+ const slackRpcCall = (endpoint, payload, signal) =>
215
+ ctx.connection.rpc.call(SLACK_RPC_CHANNEL, endpoint, payload, signal);
193
216
 
194
217
  ctx.slots.inject('settings.plugins.tab', () => ctx.slots.register({
195
218
  name: 'settings.plugins.tab',
196
219
  id: 'im',
197
220
  order: 20,
198
- label: 'IM机器人',
221
+ label: () => t('IM机器人'),
222
+ locale: IM_LOCALE_NAMESPACE,
199
223
  inject: () => ({
200
224
  dingtalkRpcCall,
201
225
  discordRpcCall,
202
226
  feishuRpcCall,
203
227
  qqRpcCall,
228
+ slackRpcCall,
204
229
  telegramRpcCall,
205
230
  wecomRpcCall,
206
231
  weixinRpcCall,