@xmanrui/dsh-im 1.5.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +16 -4
- package/README.md +16 -4
- package/lib/index.js +208 -178
- package/package.json +1 -1
- package/plugin-src/host/index.mjs +2 -0
- package/src/channels/dingtalk/config-store.mjs +5 -3
- package/src/channels/dingtalk/dingtalk-api.mjs +2 -1
- package/src/channels/dingtalk/dingtalk-bridge.mjs +45 -40
- package/src/channels/dingtalk/dingtalk-card-stream.mjs +3 -1
- package/src/channels/dingtalk/dingtalk-controller.mjs +24 -23
- package/src/channels/dingtalk/dingtalk-runtime.mjs +4 -3
- package/src/channels/dingtalk/state-store.mjs +3 -1
- package/src/channels/discord/config-store.mjs +2 -1
- package/src/channels/discord/discord-api.mjs +25 -1
- package/src/channels/discord/discord-runtime.mjs +237 -11
- package/src/channels/feishu/bridge.mjs +131 -123
- package/src/channels/feishu/feishu-cards.mjs +62 -54
- package/src/channels/feishu/feishu-channel.mjs +5 -4
- package/src/channels/feishu/feishu-runtime.mjs +10 -9
- package/src/channels/feishu/message-utils.mjs +4 -3
- package/src/channels/office/office-job-executor.mjs +15 -14
- package/src/channels/office/office-runtime.mjs +6 -5
- package/src/channels/qq/config-store.mjs +3 -1
- package/src/channels/qq/markdown-reply.mjs +4 -2
- package/src/channels/qq/qq-bridge.mjs +57 -52
- package/src/channels/qq/qq-controller.mjs +17 -16
- package/src/channels/qq/qq-runtime.mjs +3 -2
- package/src/channels/shared/agent-preset.mjs +3 -1
- package/src/channels/shared/compact-command.mjs +15 -14
- package/src/channels/shared/connection-test.mjs +6 -4
- package/src/channels/shared/control-command.mjs +13 -11
- package/src/channels/shared/editable-message-stream.mjs +4 -2
- package/src/channels/shared/harness-approval.mjs +23 -21
- package/src/channels/shared/harness-client.mjs +3 -2
- package/src/channels/shared/harness-question.mjs +8 -6
- package/src/channels/shared/i18n-en/dingtalk.mjs +52 -0
- package/src/channels/shared/i18n-en/discord.mjs +8 -0
- package/src/channels/shared/i18n-en/feishu.mjs +217 -0
- package/src/channels/shared/i18n-en/office.mjs +23 -0
- package/src/channels/shared/i18n-en/qq.mjs +54 -0
- package/src/channels/shared/i18n-en/shared-a.mjs +91 -0
- package/src/channels/shared/i18n-en/shared-b.mjs +215 -0
- package/src/channels/shared/i18n-en/shared-c.mjs +99 -0
- package/src/channels/shared/i18n-en/slack.mjs +27 -0
- package/src/channels/shared/i18n-en/telegram.mjs +21 -0
- package/src/channels/shared/i18n-en/wecom.mjs +38 -0
- package/src/channels/shared/i18n-en/weixin.mjs +80 -0
- package/src/channels/shared/i18n-en/whatsapp.mjs +17 -0
- package/src/channels/shared/i18n-en.mjs +35 -0
- package/src/channels/shared/i18n.mjs +35 -0
- package/src/channels/shared/image-prompt.mjs +17 -15
- package/src/channels/shared/inbound-file.mjs +5 -3
- package/src/channels/shared/model-command.mjs +35 -31
- package/src/channels/shared/preset-command.mjs +41 -38
- package/src/channels/shared/semantic/artifact-delivery.mjs +1 -1
- package/src/channels/shared/semantic/delivery.mjs +38 -0
- package/src/channels/shared/text-harness-bridge.mjs +130 -63
- package/src/channels/shared/token-bot-controller.mjs +32 -11
- package/src/channels/shared/workspace-command.mjs +69 -58
- package/src/channels/slack/config-store.mjs +3 -1
- package/src/channels/slack/slack-api.mjs +6 -5
- package/src/channels/slack/slack-controller.mjs +10 -9
- package/src/channels/slack/slack-runtime.mjs +16 -4
- package/src/channels/telegram/config-store.mjs +2 -1
- package/src/channels/telegram/telegram-api.mjs +72 -6
- package/src/channels/telegram/telegram-rich-message.mjs +147 -0
- package/src/channels/telegram/telegram-runtime.mjs +373 -5
- package/src/channels/wecom/config-store.mjs +3 -1
- package/src/channels/wecom/wecom-bridge.mjs +59 -55
- package/src/channels/wecom/wecom-controller.mjs +20 -19
- package/src/channels/wecom/wecom-runtime.mjs +2 -1
- package/src/channels/weixin/config-store.mjs +2 -1
- package/src/channels/weixin/weixin-bridge.mjs +50 -49
- package/src/channels/weixin/weixin-controller.mjs +22 -21
- package/src/channels/weixin/weixin-runtime.mjs +3 -2
- package/src/channels/whatsapp/config-store.mjs +3 -1
- package/src/channels/whatsapp/whatsapp-bridge.mjs +3 -1
- package/src/channels/whatsapp/whatsapp-controller.mjs +15 -14
- package/src/channels/whatsapp/whatsapp-runtime.mjs +5 -4
- package/src/channels/whatsapp/whatsapp-web-session.mjs +3 -1
|
@@ -51,13 +51,15 @@ import {
|
|
|
51
51
|
watchListCard,
|
|
52
52
|
workspaceListCard,
|
|
53
53
|
} from './feishu-cards.mjs';
|
|
54
|
+
import { t } from '../shared/i18n.mjs';
|
|
54
55
|
import { MAX_WATCHES_PER_KEY } from './state-store.mjs';
|
|
55
56
|
import {
|
|
56
57
|
FEISHU_GROUP_RESPONSE_MODES,
|
|
57
58
|
normalizeFeishuGroupResponseMode,
|
|
58
59
|
} from './group-response-mode.mjs';
|
|
59
60
|
|
|
60
|
-
|
|
61
|
+
// Lazily evaluated: t() must run after setImHostLanguage, not at import time.
|
|
62
|
+
const INTERACTION_RESOLVED_TEXT = () => t('这个问题已在其他客户端处理,无需再次回答。');
|
|
61
63
|
const RESOLVED_REPLY_TTL_MS = 30 * 60_000;
|
|
62
64
|
|
|
63
65
|
const MENU_COMMAND = /^\/m(?:enu)?$/i;
|
|
@@ -87,34 +89,37 @@ const REPAIR_URL_HOSTS = new Set([
|
|
|
87
89
|
'open.larksuite.com',
|
|
88
90
|
]);
|
|
89
91
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
92
|
+
// Built lazily: t() must run after setImHostLanguage, not at import time.
|
|
93
|
+
function helpText() {
|
|
94
|
+
return [
|
|
95
|
+
t('北汇星河 AIOS 已连接 DeepSeek Harness。'),
|
|
96
|
+
'',
|
|
97
|
+
t('直接发送文字、图片或文件即可继续当前会话。'),
|
|
98
|
+
t('/new 开启一个全新会话'),
|
|
99
|
+
t('/compact 压缩当前会话的较早上下文'),
|
|
100
|
+
t('/workspace 工作区绝对路径 切换工作区'),
|
|
101
|
+
t('/workspacelist 列出工作区绝对路径'),
|
|
102
|
+
t('/sessionlist [工作区序号或绝对路径] 列出会话 ID 和标题'),
|
|
103
|
+
t('/session Session ID 或当前工作区序号 将当前聊天绑定到指定会话'),
|
|
104
|
+
t('/models 按序号列出所有可用模型'),
|
|
105
|
+
t('/model [序号或完整模型ID] 查看或切换当前会话模型'),
|
|
106
|
+
t('示例:先发 /models,再发 /model 2'),
|
|
107
|
+
t('/presetlist 按序号列出可用 Agent Preset'),
|
|
108
|
+
t('/preset [序号或完整ID] 查看或设置当前机器人 Agent Preset'),
|
|
109
|
+
t('纯数字 ID:/preset id:<ID>'),
|
|
110
|
+
t('/preset --default 跟随 Host 默认'),
|
|
111
|
+
t('/stop 停止当前任务'),
|
|
112
|
+
t('/steer 补充指令 纠偏当前任务'),
|
|
113
|
+
t('/status 检查连接状态'),
|
|
114
|
+
t('/repair 修复卡片按钮回调'),
|
|
115
|
+
t('/m(或 /menu) 打开交互卡片菜单'),
|
|
116
|
+
t('/watch [Session ID 或序号] 关注会话,任务完成自动推送'),
|
|
117
|
+
t('/unwatch [Session ID 或序号] 取消关注'),
|
|
118
|
+
t('/watchlist 查看关注列表'),
|
|
119
|
+
t('/archived on|off 会话列表是否包含归档会话'),
|
|
120
|
+
t('/help 显示本帮助'),
|
|
121
|
+
].join('\n');
|
|
122
|
+
}
|
|
118
123
|
|
|
119
124
|
const ARCHIVED_COMMAND = /^\/archived(?:\s+(on|off))?$/i;
|
|
120
125
|
|
|
@@ -122,43 +127,43 @@ const ARCHIVED_COMMAND = /^\/archived(?:\s+(on|off))?$/i;
|
|
|
122
127
|
function safeErrorText(error) {
|
|
123
128
|
switch (error?.code) {
|
|
124
129
|
case 'workspace-not-absolute':
|
|
125
|
-
return '工作区必须是绝对路径。';
|
|
130
|
+
return t('工作区必须是绝对路径。');
|
|
126
131
|
case 'workspace-not-found':
|
|
127
|
-
return '工作区路径不存在。';
|
|
132
|
+
return t('工作区路径不存在。');
|
|
128
133
|
case 'workspace-not-directory':
|
|
129
|
-
return '工作区路径必须指向一个目录。';
|
|
134
|
+
return t('工作区路径必须指向一个目录。');
|
|
130
135
|
case 'workspace-bot-not-found':
|
|
131
|
-
return '机器人正在移除或已重新接入,无法操作原会话的工作区。';
|
|
136
|
+
return t('机器人正在移除或已重新接入,无法操作原会话的工作区。');
|
|
132
137
|
default:
|
|
133
|
-
return '操作失败,请稍后重试。';
|
|
138
|
+
return t('操作失败,请稍后重试。');
|
|
134
139
|
}
|
|
135
140
|
}
|
|
136
141
|
|
|
137
142
|
function artifactFailureText(fileName, error) {
|
|
138
|
-
const name = String(fileName ?? '结果文件').replace(/[\r\n]+/g, ' ').trim() || '结果文件';
|
|
143
|
+
const name = String(fileName ?? t('结果文件')).replace(/[\r\n]+/g, ' ').trim() || t('结果文件');
|
|
139
144
|
switch (error?.code) {
|
|
140
145
|
case 'artifact-permission-required':
|
|
141
|
-
return
|
|
146
|
+
return t('结果文件「{name}」已生成,但机器人缺少飞书文件上传权限。请为应用添加 im:resource 并完成必要审批后重试。', { name });
|
|
142
147
|
case 'artifact-too-large':
|
|
143
|
-
return
|
|
148
|
+
return t('结果文件「{name}」超过飞书 30 MB 上限,未发送。', { name });
|
|
144
149
|
case 'artifact-empty':
|
|
145
|
-
return
|
|
150
|
+
return t('结果文件「{name}」为空,飞书不允许发送空文件。', { name });
|
|
146
151
|
case 'artifact-changed':
|
|
147
152
|
case 'artifact-invalid':
|
|
148
153
|
case 'artifact-unavailable':
|
|
149
|
-
return
|
|
154
|
+
return t('结果文件「{name}」暂时无法读取或准备发送,请确认文件仍可访问后重试。', { name });
|
|
150
155
|
case 'artifact-rate-limited':
|
|
151
|
-
return
|
|
156
|
+
return t('结果文件「{name}」暂时被飞书限流,未能发送,请稍后重试。', { name });
|
|
152
157
|
case 'artifact-delivery-uncertain':
|
|
153
|
-
return
|
|
158
|
+
return t('结果文件「{name}」发送结果未能确认,请先检查聊天内是否已收到,不要立即重试。', { name });
|
|
154
159
|
default:
|
|
155
|
-
return
|
|
160
|
+
return t('结果文件「{name}」已生成,但暂时未能发送,请稍后重试。', { name });
|
|
156
161
|
}
|
|
157
162
|
}
|
|
158
163
|
|
|
159
164
|
function answerTextForDelivery(answer, artifacts) {
|
|
160
165
|
if (typeof answer === 'string' && answer.trim()) return answer;
|
|
161
|
-
return artifacts.length > 0 ? '结果文件已生成。' : answer;
|
|
166
|
+
return artifacts.length > 0 ? t('结果文件已生成。') : answer;
|
|
162
167
|
}
|
|
163
168
|
|
|
164
169
|
function nonEmptyString(value) {
|
|
@@ -611,7 +616,7 @@ export class FeishuHarnessBridge {
|
|
|
611
616
|
event.message.chat_id,
|
|
612
617
|
inboundFileUserMessage(error)
|
|
613
618
|
?? imagePromptUserMessage(error)
|
|
614
|
-
?? '处理失败,请稍后重试。如果问题持续,请在 DeepSeek Harness 的飞书插件页面检查连接状态。',
|
|
619
|
+
?? t('处理失败,请稍后重试。如果问题持续,请在 DeepSeek Harness 的飞书插件页面检查连接状态。'),
|
|
615
620
|
).catch(() => undefined);
|
|
616
621
|
}
|
|
617
622
|
|
|
@@ -675,7 +680,7 @@ export class FeishuHarnessBridge {
|
|
|
675
680
|
const hasFiles = hasInboundFiles(message);
|
|
676
681
|
const commandText = event.message.message_type === 'text' && !hasImages && !hasFiles ? text : null;
|
|
677
682
|
if (!text && !hasImages && !hasFiles) {
|
|
678
|
-
await this.#send(event.message.chat_id, '目前支持文字、图片和文件消息。');
|
|
683
|
+
await this.#send(event.message.chat_id, t('目前支持文字、图片和文件消息。'));
|
|
679
684
|
return;
|
|
680
685
|
}
|
|
681
686
|
|
|
@@ -684,7 +689,7 @@ export class FeishuHarnessBridge {
|
|
|
684
689
|
return;
|
|
685
690
|
}
|
|
686
691
|
if (commandText === '/help') {
|
|
687
|
-
await this.#send(event.message.chat_id,
|
|
692
|
+
await this.#send(event.message.chat_id, helpText());
|
|
688
693
|
return;
|
|
689
694
|
}
|
|
690
695
|
if (MENU_COMMAND.test(commandText)) {
|
|
@@ -694,12 +699,12 @@ export class FeishuHarnessBridge {
|
|
|
694
699
|
}
|
|
695
700
|
if (commandText === '/new') {
|
|
696
701
|
await this.#state.clearSession(key);
|
|
697
|
-
await this.#send(event.message.chat_id, '已开启全新 Harness 会话。');
|
|
702
|
+
await this.#send(event.message.chat_id, t('已开启全新 Harness 会话。'));
|
|
698
703
|
return;
|
|
699
704
|
}
|
|
700
705
|
if (commandText === '/status') {
|
|
701
706
|
await this.#harness.ensureRunning({ signal: this.#signal });
|
|
702
|
-
await this.#send(event.message.chat_id, '飞书机器人与 DeepSeek Harness 连接正常。');
|
|
707
|
+
await this.#send(event.message.chat_id, t('飞书机器人与 DeepSeek Harness 连接正常。'));
|
|
703
708
|
return;
|
|
704
709
|
}
|
|
705
710
|
if (SESSION_LIST_PREFIX.test(commandText)) {
|
|
@@ -729,7 +734,7 @@ export class FeishuHarnessBridge {
|
|
|
729
734
|
const match = ARCHIVED_COMMAND.exec(commandText);
|
|
730
735
|
const value = match[1]?.toLowerCase();
|
|
731
736
|
if (value !== 'on' && value !== 'off') {
|
|
732
|
-
await this.#send(event.message.chat_id, '用法:/archived on(包含归档会话)或 /archived off(隐藏归档会话)');
|
|
737
|
+
await this.#send(event.message.chat_id, t('用法:/archived on(包含归档会话)或 /archived off(隐藏归档会话)'));
|
|
733
738
|
return;
|
|
734
739
|
}
|
|
735
740
|
if (typeof this.#state?.setIncludeArchivedSessions === 'function') {
|
|
@@ -737,7 +742,7 @@ export class FeishuHarnessBridge {
|
|
|
737
742
|
}
|
|
738
743
|
await this.#send(
|
|
739
744
|
event.message.chat_id,
|
|
740
|
-
value === 'on' ? '已开启:会话列表包含归档会话。' : '已关闭:会话列表隐藏归档会话。',
|
|
745
|
+
value === 'on' ? t('已开启:会话列表包含归档会话。') : t('已关闭:会话列表隐藏归档会话。'),
|
|
741
746
|
);
|
|
742
747
|
return;
|
|
743
748
|
}
|
|
@@ -794,7 +799,7 @@ export class FeishuHarnessBridge {
|
|
|
794
799
|
// and number replies because callback buttons are the capability being fixed.
|
|
795
800
|
async #handleRepairCommand(event, commandText) {
|
|
796
801
|
if (event?.message?.chat_type !== 'p2p') {
|
|
797
|
-
await this.#send(event.message.chat_id, '为避免授权链接暴露,请私聊机器人发送 /repair。');
|
|
802
|
+
await this.#send(event.message.chat_id, t('为避免授权链接暴露,请私聊机器人发送 /repair。'));
|
|
798
803
|
return;
|
|
799
804
|
}
|
|
800
805
|
const actorOpenId = strictSenderOpenId(event);
|
|
@@ -802,19 +807,19 @@ export class FeishuHarnessBridge {
|
|
|
802
807
|
await this.#send(
|
|
803
808
|
event.message.chat_id,
|
|
804
809
|
this.#repairOwnerOpenIds.size === 0
|
|
805
|
-
? '当前机器人没有可验证的接入者身份,不能从聊天发起修复;请先在插件页设置管理员。'
|
|
806
|
-
: '此操作只能由机器人接入者在私聊中发起,未进行任何修改。',
|
|
810
|
+
? t('当前机器人没有可验证的接入者身份,不能从聊天发起修复;请先在插件页设置管理员。')
|
|
811
|
+
: t('此操作只能由机器人接入者在私聊中发起,未进行任何修改。'),
|
|
807
812
|
);
|
|
808
813
|
return;
|
|
809
814
|
}
|
|
810
815
|
if (!this.#repair) {
|
|
811
|
-
await this.#send(event.message.chat_id, '当前 Host 版本暂不支持聊天内修复,请先更新插件。');
|
|
816
|
+
await this.#send(event.message.chat_id, t('当前 Host 版本暂不支持聊天内修复,请先更新插件。'));
|
|
812
817
|
return;
|
|
813
818
|
}
|
|
814
819
|
|
|
815
820
|
const parsed = REPAIR_COMMAND.exec(commandText);
|
|
816
821
|
if (!parsed) {
|
|
817
|
-
await this.#send(event.message.chat_id, '用法:/repair、/repair qr、/repair status、/repair cancel 或 /repair verify');
|
|
822
|
+
await this.#send(event.message.chat_id, t('用法:/repair、/repair qr、/repair status、/repair cancel 或 /repair verify'));
|
|
818
823
|
return;
|
|
819
824
|
}
|
|
820
825
|
const operation = parsed[1]?.toLowerCase() ?? 'start';
|
|
@@ -828,12 +833,12 @@ export class FeishuHarnessBridge {
|
|
|
828
833
|
if (!attempt) {
|
|
829
834
|
await this.#send(
|
|
830
835
|
chatId,
|
|
831
|
-
'当前 Runtime 没有可恢复的修复任务记录(机器人可能刚完成密钥更新并重启)。本命令不会启动新的授权;请查看机器人发送的验证结果,确认上一次任务已结束后再发送 /repair。',
|
|
836
|
+
t('当前 Runtime 没有可恢复的修复任务记录(机器人可能刚完成密钥更新并重启)。本命令不会启动新的授权;请查看机器人发送的验证结果,确认上一次任务已结束后再发送 /repair。'),
|
|
832
837
|
);
|
|
833
838
|
return;
|
|
834
839
|
}
|
|
835
840
|
if (attempt.actorOpenId !== actorOpenId) {
|
|
836
|
-
await this.#send(chatId, '另一位管理员正在修复该机器人,本次不会显示其授权信息。');
|
|
841
|
+
await this.#send(chatId, t('另一位管理员正在修复该机器人,本次不会显示其授权信息。'));
|
|
837
842
|
return;
|
|
838
843
|
}
|
|
839
844
|
if (operation === 'cancel') {
|
|
@@ -843,7 +848,7 @@ export class FeishuHarnessBridge {
|
|
|
843
848
|
snapshot = repairSnapshot(result, { botId: this.#botId });
|
|
844
849
|
attempt.snapshot = snapshot;
|
|
845
850
|
} catch {
|
|
846
|
-
await this.#send(chatId, '暂时无法取消修复任务,请稍后重试。');
|
|
851
|
+
await this.#send(chatId, t('暂时无法取消修复任务,请稍后重试。'));
|
|
847
852
|
return;
|
|
848
853
|
}
|
|
849
854
|
if (snapshot.state === 'cancelled') {
|
|
@@ -858,7 +863,7 @@ export class FeishuHarnessBridge {
|
|
|
858
863
|
try {
|
|
859
864
|
snapshot = await this.#refreshRepairAttempt(attempt);
|
|
860
865
|
} catch {
|
|
861
|
-
await this.#send(chatId, '暂时无法查询修复状态,请稍后重试。');
|
|
866
|
+
await this.#send(chatId, t('暂时无法查询修复状态,请稍后重试。'));
|
|
862
867
|
return;
|
|
863
868
|
}
|
|
864
869
|
if (operation === 'qr') {
|
|
@@ -887,7 +892,7 @@ export class FeishuHarnessBridge {
|
|
|
887
892
|
const previous = this.#repairAttempt;
|
|
888
893
|
if (previous && REPAIR_ACTIVE_STATES.has(previous.snapshot.state)) {
|
|
889
894
|
if (previous.actorOpenId !== actorOpenId) {
|
|
890
|
-
await this.#send(chatId, '另一位管理员正在修复该机器人,本次不会显示其授权信息。');
|
|
895
|
+
await this.#send(chatId, t('另一位管理员正在修复该机器人,本次不会显示其授权信息。'));
|
|
891
896
|
return;
|
|
892
897
|
}
|
|
893
898
|
try {
|
|
@@ -897,7 +902,7 @@ export class FeishuHarnessBridge {
|
|
|
897
902
|
return;
|
|
898
903
|
}
|
|
899
904
|
} catch {
|
|
900
|
-
await this.#send(chatId, '暂时无法查询修复状态,请稍后重试。');
|
|
905
|
+
await this.#send(chatId, t('暂时无法查询修复状态,请稍后重试。'));
|
|
901
906
|
return;
|
|
902
907
|
}
|
|
903
908
|
}
|
|
@@ -911,7 +916,7 @@ export class FeishuHarnessBridge {
|
|
|
911
916
|
}), { botId: this.#botId });
|
|
912
917
|
snapshot = await this.#waitForRepairLink(snapshot, { actorOpenId, chatId });
|
|
913
918
|
} catch {
|
|
914
|
-
await this.#send(chatId, '修复流程暂时失败,现有机器人连接不受影响;请稍后发送 /repair 重试。');
|
|
919
|
+
await this.#send(chatId, t('修复流程暂时失败,现有机器人连接不受影响;请稍后发送 /repair 重试。'));
|
|
915
920
|
return;
|
|
916
921
|
}
|
|
917
922
|
const attempt = {
|
|
@@ -932,7 +937,7 @@ export class FeishuHarnessBridge {
|
|
|
932
937
|
} catch {
|
|
933
938
|
attempt.stopped = true;
|
|
934
939
|
await this.#repair.cancel(this.#repairArgs(attempt)).catch(() => undefined);
|
|
935
|
-
await this.#send(chatId, '飞书返回了无法安全验证的授权链接,已中止本次修复。');
|
|
940
|
+
await this.#send(chatId, t('飞书返回了无法安全验证的授权链接,已中止本次修复。'));
|
|
936
941
|
return;
|
|
937
942
|
}
|
|
938
943
|
}
|
|
@@ -945,7 +950,7 @@ export class FeishuHarnessBridge {
|
|
|
945
950
|
}
|
|
946
951
|
if (!attempt.verificationUrl) {
|
|
947
952
|
attempt.stopped = true;
|
|
948
|
-
await this.#send(chatId, '飞书未返回授权链接,已中止本次修复。');
|
|
953
|
+
await this.#send(chatId, t('飞书未返回授权链接,已中止本次修复。'));
|
|
949
954
|
return;
|
|
950
955
|
}
|
|
951
956
|
await this.#sendRepairLink(chatId, attempt.verificationUrl, snapshot);
|
|
@@ -1000,7 +1005,7 @@ export class FeishuHarnessBridge {
|
|
|
1000
1005
|
attempt.announcedSaving = true;
|
|
1001
1006
|
await this.#send(
|
|
1002
1007
|
attempt.chatId,
|
|
1003
|
-
'授权已确认,正在发送并等待测试按钮回调;收到真实回调后才会完成。',
|
|
1008
|
+
t('授权已确认,正在发送并等待测试按钮回调;收到真实回调后才会完成。'),
|
|
1004
1009
|
);
|
|
1005
1010
|
}
|
|
1006
1011
|
if (REPAIR_TERMINAL_STATES.has(snapshot.state)) {
|
|
@@ -1021,7 +1026,7 @@ export class FeishuHarnessBridge {
|
|
|
1021
1026
|
this.#logger.warn?.('[dsh-feishu] callback repair status monitoring failed');
|
|
1022
1027
|
await this.#send(
|
|
1023
1028
|
attempt.chatId,
|
|
1024
|
-
'修复状态查询中断,现有机器人连接不受影响;发送 /repair status 重试查询。',
|
|
1029
|
+
t('修复状态查询中断,现有机器人连接不受影响;发送 /repair status 重试查询。'),
|
|
1025
1030
|
).catch(() => undefined);
|
|
1026
1031
|
});
|
|
1027
1032
|
}
|
|
@@ -1030,16 +1035,16 @@ export class FeishuHarnessBridge {
|
|
|
1030
1035
|
const remaining = snapshot.remainingSeconds
|
|
1031
1036
|
?? (snapshot.expiresAt ? Math.max(0, Math.ceil((snapshot.expiresAt - Date.now()) / 1000)) : null);
|
|
1032
1037
|
const expiry = remaining === null
|
|
1033
|
-
? '链接为短期有效'
|
|
1034
|
-
:
|
|
1038
|
+
? t('链接为短期有效')
|
|
1039
|
+
: t('链接约 {minutes} 分钟后过期', { minutes: Math.max(1, Math.ceil(remaining / 60)) });
|
|
1035
1040
|
await this.#send(chatId, [
|
|
1036
|
-
existing ? '已有一个修复任务在等待授权。' : '🔧 准备修复卡片按钮。',
|
|
1037
|
-
'本次只会增量添加 card.action.trigger。请核对确认页只显示这一项;若出现其他权限或事件,请取消。',
|
|
1041
|
+
existing ? t('已有一个修复任务在等待授权。') : t('🔧 准备修复卡片按钮。'),
|
|
1042
|
+
t('本次只会增量添加 card.action.trigger。请核对确认页只显示这一项;若出现其他权限或事件,请取消。'),
|
|
1038
1043
|
'',
|
|
1039
|
-
'当前设备直接打开:',
|
|
1044
|
+
t('当前设备直接打开:'),
|
|
1040
1045
|
url,
|
|
1041
1046
|
'',
|
|
1042
|
-
|
|
1047
|
+
t('若要用另一台设备扫码,发送 /repair qr。{expiry}。', { expiry }),
|
|
1043
1048
|
].join('\n'));
|
|
1044
1049
|
}
|
|
1045
1050
|
|
|
@@ -1055,9 +1060,12 @@ export class FeishuHarnessBridge {
|
|
|
1055
1060
|
if (!imageKey) throw new Error('Feishu QR upload returned no image key');
|
|
1056
1061
|
const remaining = snapshot.remainingSeconds
|
|
1057
1062
|
?? (snapshot.expiresAt ? Math.max(0, Math.ceil((snapshot.expiresAt - Date.now()) / 1000)) : null);
|
|
1063
|
+
const remainingText = remaining === null
|
|
1064
|
+
? ''
|
|
1065
|
+
: t('(剩余约 {minutes} 分钟)', { minutes: Math.max(1, Math.ceil(remaining / 60)) });
|
|
1058
1066
|
await this.#send(
|
|
1059
1067
|
chatId,
|
|
1060
|
-
|
|
1068
|
+
t('请用另一台设备扫码完成授权{remaining}。', { remaining: remainingText }),
|
|
1061
1069
|
);
|
|
1062
1070
|
const response = await this.#client.im.v1.message.create({
|
|
1063
1071
|
params: { receive_id_type: 'chat_id' },
|
|
@@ -1069,40 +1077,40 @@ export class FeishuHarnessBridge {
|
|
|
1069
1077
|
});
|
|
1070
1078
|
if (response?.code && response.code !== 0) throw new Error('Feishu QR message send failed');
|
|
1071
1079
|
} catch {
|
|
1072
|
-
await this.#send(chatId,
|
|
1080
|
+
await this.#send(chatId, t('二维码暂时无法发送,请直接打开授权链接:\n{url}', { url }));
|
|
1073
1081
|
}
|
|
1074
1082
|
}
|
|
1075
1083
|
|
|
1076
1084
|
#repairStatusText(snapshot, { verificationFocused = false } = {}) {
|
|
1077
1085
|
if (snapshot.state === 'succeeded') {
|
|
1078
|
-
return '✅ 修复完成:已实测收到 card.action.trigger,菜单按钮现在可用。';
|
|
1086
|
+
return t('✅ 修复完成:已实测收到 card.action.trigger,菜单按钮现在可用。');
|
|
1079
1087
|
}
|
|
1080
1088
|
if (snapshot.state === 'expired' || snapshot.error?.code === 'expired_token') {
|
|
1081
|
-
return '授权链接已过期;平台未返回成功结果,无法确认已修复。发送 /repair 生成新链接。';
|
|
1089
|
+
return t('授权链接已过期;平台未返回成功结果,无法确认已修复。发送 /repair 生成新链接。');
|
|
1082
1090
|
}
|
|
1083
1091
|
if (snapshot.state === 'cancelled' || snapshot.error?.code === 'abort') {
|
|
1084
|
-
return '已取消本次修复授权,未确认完成修复。';
|
|
1092
|
+
return t('已取消本次修复授权,未确认完成修复。');
|
|
1085
1093
|
}
|
|
1086
1094
|
if (snapshot.error?.code === 'access_denied') {
|
|
1087
|
-
return '你已取消或拒绝授权,没有确认修复;发送 /repair 可重试。';
|
|
1095
|
+
return t('你已取消或拒绝授权,没有确认修复;发送 /repair 可重试。');
|
|
1088
1096
|
}
|
|
1089
1097
|
if (snapshot.error?.code === 'card_action_probe_timeout'
|
|
1090
1098
|
|| snapshot.error?.code === 'card-action-probe-timeout') {
|
|
1091
|
-
return '授权已提交,但未收到测试按钮回调。可能尚未点击或配置仍在传播;稍后发送 /repair verify 查询,不要盲目重复授权。';
|
|
1099
|
+
return t('授权已提交,但未收到测试按钮回调。可能尚未点击或配置仍在传播;稍后发送 /repair verify 查询,不要盲目重复授权。');
|
|
1092
1100
|
}
|
|
1093
1101
|
if (snapshot.state === 'error') {
|
|
1094
|
-
return '修复流程暂时失败,现有机器人连接不受影响;发送 /repair 可重试。';
|
|
1102
|
+
return t('修复流程暂时失败,现有机器人连接不受影响;发送 /repair 可重试。');
|
|
1095
1103
|
}
|
|
1096
1104
|
if (snapshot.state === 'saving') {
|
|
1097
|
-
return '授权已确认,正在等待专用测试按钮的真实回调;回调到达前不会宣告成功。';
|
|
1105
|
+
return t('授权已确认,正在等待专用测试按钮的真实回调;回调到达前不会宣告成功。');
|
|
1098
1106
|
}
|
|
1099
1107
|
if (verificationFocused) {
|
|
1100
|
-
return '授权尚未完成,暂时不能验证卡片按钮。请先打开授权链接并确认。';
|
|
1108
|
+
return t('授权尚未完成,暂时不能验证卡片按钮。请先打开授权链接并确认。');
|
|
1101
1109
|
}
|
|
1102
1110
|
const remaining = snapshot.remainingSeconds === null
|
|
1103
1111
|
? ''
|
|
1104
|
-
:
|
|
1105
|
-
return
|
|
1112
|
+
: t(',剩余约 {minutes} 分钟', { minutes: Math.max(1, Math.ceil(snapshot.remainingSeconds / 60)) });
|
|
1113
|
+
return t('修复任务正在等待授权{remaining}。发送 /repair qr 可获取二维码,/repair cancel 可取消。', { remaining });
|
|
1106
1114
|
}
|
|
1107
1115
|
|
|
1108
1116
|
/**
|
|
@@ -1134,7 +1142,7 @@ export class FeishuHarnessBridge {
|
|
|
1134
1142
|
// restart) or never came from us: nudge instead of staying silent.
|
|
1135
1143
|
const chatId = nonEmptyString(event?.context?.open_chat_id);
|
|
1136
1144
|
if (chatId) {
|
|
1137
|
-
this.#send(chatId, '这个菜单已过期,请回复 /m 重新打开。').catch(() => undefined);
|
|
1145
|
+
this.#send(chatId, t('这个菜单已过期,请回复 /m 重新打开。')).catch(() => undefined);
|
|
1138
1146
|
}
|
|
1139
1147
|
return Promise.resolve();
|
|
1140
1148
|
}
|
|
@@ -1161,12 +1169,12 @@ export class FeishuHarnessBridge {
|
|
|
1161
1169
|
}
|
|
1162
1170
|
if (action === 'new') {
|
|
1163
1171
|
await this.#state.clearSession(key);
|
|
1164
|
-
await this.#send(chatId, '已开启全新 Harness 会话。');
|
|
1172
|
+
await this.#send(chatId, t('已开启全新 Harness 会话。'));
|
|
1165
1173
|
return;
|
|
1166
1174
|
}
|
|
1167
1175
|
if (action === 'status') {
|
|
1168
1176
|
await this.#harness.ensureRunning({ signal: this.#signal });
|
|
1169
|
-
await this.#send(chatId, '飞书机器人与 DeepSeek Harness 连接正常。');
|
|
1177
|
+
await this.#send(chatId, t('飞书机器人与 DeepSeek Harness 连接正常。'));
|
|
1170
1178
|
return;
|
|
1171
1179
|
}
|
|
1172
1180
|
if (action === 'help') {
|
|
@@ -1213,7 +1221,7 @@ export class FeishuHarnessBridge {
|
|
|
1213
1221
|
if (menu.kind === 'menu') {
|
|
1214
1222
|
const action = ['sessions', 'workspaces', 'new', 'status', 'help', 'repair', 'watchlist'][number - 1];
|
|
1215
1223
|
if (!action) {
|
|
1216
|
-
await this.#send(chatId, '菜单没有这个编号,回复 /m 重新打开。');
|
|
1224
|
+
await this.#send(chatId, t('菜单没有这个编号,回复 /m 重新打开。'));
|
|
1217
1225
|
return;
|
|
1218
1226
|
}
|
|
1219
1227
|
if (action === 'repair') {
|
|
@@ -1226,7 +1234,7 @@ export class FeishuHarnessBridge {
|
|
|
1226
1234
|
if (menu.kind === 'sessions') {
|
|
1227
1235
|
const session = menu.sessions[number - 1];
|
|
1228
1236
|
if (!session?.sessionId) {
|
|
1229
|
-
await this.#send(chatId,
|
|
1237
|
+
await this.#send(chatId, t('本页只有 {count} 个会话,回复 /sessionlist 重新查看。', { count: menu.sessions.length }));
|
|
1230
1238
|
return;
|
|
1231
1239
|
}
|
|
1232
1240
|
// The number label sits on the session (bind) button of the row.
|
|
@@ -1236,7 +1244,7 @@ export class FeishuHarnessBridge {
|
|
|
1236
1244
|
if (menu.kind === 'workspaces') {
|
|
1237
1245
|
const workspace = menu.paths[number - 1];
|
|
1238
1246
|
if (!workspace) {
|
|
1239
|
-
await this.#send(chatId,
|
|
1247
|
+
await this.#send(chatId, t('只有 {count} 个工作区,回复 /workspacelist 重新查看。', { count: menu.paths.length }));
|
|
1240
1248
|
return;
|
|
1241
1249
|
}
|
|
1242
1250
|
await this.#handleCardAction(`workspace:${workspace}`, { chatId, key });
|
|
@@ -1245,7 +1253,7 @@ export class FeishuHarnessBridge {
|
|
|
1245
1253
|
if (menu.kind === 'watches') {
|
|
1246
1254
|
const entry = menu.entries[number - 1];
|
|
1247
1255
|
if (!entry?.sessionId) {
|
|
1248
|
-
await this.#send(chatId,
|
|
1256
|
+
await this.#send(chatId, t('关注列表只有 {count} 个会话。', { count: menu.entries.length }));
|
|
1249
1257
|
return;
|
|
1250
1258
|
}
|
|
1251
1259
|
await this.#handleCardAction(`unwatch:${entry.sessionId}`, { chatId, key });
|
|
@@ -1271,7 +1279,7 @@ export class FeishuHarnessBridge {
|
|
|
1271
1279
|
const sessions = this.#visibleSessions(Array.isArray(listed?.sessions) ? listed.sessions : []);
|
|
1272
1280
|
const workspace = listed?.workspace ?? resolved.workspace;
|
|
1273
1281
|
if (sessions.length === 0) {
|
|
1274
|
-
await this.#send(chatId,
|
|
1282
|
+
await this.#send(chatId, t('工作区:{workspace}\n该工作区暂无会话。', { workspace }));
|
|
1275
1283
|
return;
|
|
1276
1284
|
}
|
|
1277
1285
|
const pageCount = Math.ceil(sessions.length / MENU_PAGE_SIZE);
|
|
@@ -1296,7 +1304,7 @@ export class FeishuHarnessBridge {
|
|
|
1296
1304
|
);
|
|
1297
1305
|
} catch (error) {
|
|
1298
1306
|
this.#logger.warn?.('[dsh-feishu] session list failed:', error.message);
|
|
1299
|
-
await this.#send(chatId, '暂时无法获取会话列表,请稍后重试。');
|
|
1307
|
+
await this.#send(chatId, t('暂时无法获取会话列表,请稍后重试。'));
|
|
1300
1308
|
}
|
|
1301
1309
|
}
|
|
1302
1310
|
|
|
@@ -1307,26 +1315,26 @@ export class FeishuHarnessBridge {
|
|
|
1307
1315
|
await this.#sendCard(chatId, workspaceListCard(paths, current), { key });
|
|
1308
1316
|
} catch (error) {
|
|
1309
1317
|
this.#logger.warn?.('[dsh-feishu] workspace list failed:', error.message);
|
|
1310
|
-
await this.#send(chatId, '暂时无法获取工作区列表,请稍后重试。');
|
|
1318
|
+
await this.#send(chatId, t('暂时无法获取工作区列表,请稍后重试。'));
|
|
1311
1319
|
}
|
|
1312
1320
|
}
|
|
1313
1321
|
|
|
1314
1322
|
async #bindSession(key, chatId, sessionId) {
|
|
1315
1323
|
try {
|
|
1316
1324
|
const bound = await this.#harness.bindWorkspaceSession(key, sessionId);
|
|
1317
|
-
const title = String(bound?.title ?? '').replace(/\s+/gu, ' ').trim() || '暂无标题';
|
|
1318
|
-
await this.#send(chatId,
|
|
1325
|
+
const title = String(bound?.title ?? '').replace(/\s+/gu, ' ').trim() || t('暂无标题');
|
|
1326
|
+
await this.#send(chatId, t('已绑定会话「{title}」\nID:{id}', { title, id: bound?.sessionId ?? sessionId }));
|
|
1319
1327
|
} catch (error) {
|
|
1320
|
-
await this.#send(chatId,
|
|
1328
|
+
await this.#send(chatId, t('绑定失败:{message}', { message: safeErrorText(error) }));
|
|
1321
1329
|
}
|
|
1322
1330
|
}
|
|
1323
1331
|
|
|
1324
1332
|
async #switchWorkspace(key, chatId, workspace) {
|
|
1325
1333
|
try {
|
|
1326
1334
|
const current = await this.#harness.switchWorkspace(workspace);
|
|
1327
|
-
await this.#send(chatId,
|
|
1335
|
+
await this.#send(chatId, t('工作区已切换为:{workspace}', { workspace: current }));
|
|
1328
1336
|
} catch (error) {
|
|
1329
|
-
await this.#send(chatId,
|
|
1337
|
+
await this.#send(chatId, t('切换失败:{message}', { message: safeErrorText(error) }));
|
|
1330
1338
|
}
|
|
1331
1339
|
}
|
|
1332
1340
|
|
|
@@ -1398,7 +1406,7 @@ export class FeishuHarnessBridge {
|
|
|
1398
1406
|
*/
|
|
1399
1407
|
async #resolveWatchTarget(target) {
|
|
1400
1408
|
if (typeof target !== 'string' || target === '') {
|
|
1401
|
-
return { error: '用法:/watch <Session ID 或当前工作区序号>' };
|
|
1409
|
+
return { error: t('用法:/watch <Session ID 或当前工作区序号>') };
|
|
1402
1410
|
}
|
|
1403
1411
|
const numeric = /^\d{1,4}$/.test(target) ? Number(target) : null;
|
|
1404
1412
|
const currentPath = typeof this.#harness?.currentWorkspace === 'function'
|
|
@@ -1409,13 +1417,13 @@ export class FeishuHarnessBridge {
|
|
|
1409
1417
|
return Array.isArray(listed?.sessions) ? listed.sessions : [];
|
|
1410
1418
|
};
|
|
1411
1419
|
if (numeric !== null) {
|
|
1412
|
-
if (!currentPath) return { error: '当前机器人没有可用的工作区,无法按序号解析会话。' };
|
|
1420
|
+
if (!currentPath) return { error: t('当前机器人没有可用的工作区,无法按序号解析会话。') };
|
|
1413
1421
|
const sessions = this.#visibleSessions(await listSessions(currentPath));
|
|
1414
1422
|
const session = sessions[numeric - 1];
|
|
1415
1423
|
if (!session?.sessionId) {
|
|
1416
|
-
return { error:
|
|
1424
|
+
return { error: t('当前工作区只有 {count} 个会话。', { count: sessions.length }) };
|
|
1417
1425
|
}
|
|
1418
|
-
return { sessionId: session.sessionId, title: session.title ?? '暂无标题' };
|
|
1426
|
+
return { sessionId: session.sessionId, title: session.title ?? t('暂无标题') };
|
|
1419
1427
|
}
|
|
1420
1428
|
const extraPaths = typeof this.#harness?.listWorkspaces === 'function'
|
|
1421
1429
|
? (await this.#harness.listWorkspaces()).filter((path) => path !== currentPath)
|
|
@@ -1424,9 +1432,9 @@ export class FeishuHarnessBridge {
|
|
|
1424
1432
|
for (const workspace of paths) {
|
|
1425
1433
|
const sessions = await listSessions(workspace);
|
|
1426
1434
|
const session = sessions.find((candidate) => candidate.sessionId === target);
|
|
1427
|
-
if (session) return { sessionId: target, title: session.title ?? '暂无标题' };
|
|
1435
|
+
if (session) return { sessionId: target, title: session.title ?? t('暂无标题') };
|
|
1428
1436
|
}
|
|
1429
|
-
return { error: '没有找到这个会话,请用 /sessionlist 查看可用会话。' };
|
|
1437
|
+
return { error: t('没有找到这个会话,请用 /sessionlist 查看可用会话。') };
|
|
1430
1438
|
}
|
|
1431
1439
|
|
|
1432
1440
|
async #latestSessionSeq(sessionId) {
|
|
@@ -1443,14 +1451,14 @@ export class FeishuHarnessBridge {
|
|
|
1443
1451
|
async #runWatch(key, chatId, target) {
|
|
1444
1452
|
this.#ensureEventWatcher();
|
|
1445
1453
|
if (typeof this.#state?.setWatch !== 'function') {
|
|
1446
|
-
await this.#send(chatId, '当前状态存储不支持关注。');
|
|
1454
|
+
await this.#send(chatId, t('当前状态存储不支持关注。'));
|
|
1447
1455
|
return;
|
|
1448
1456
|
}
|
|
1449
1457
|
let resolved;
|
|
1450
1458
|
try {
|
|
1451
1459
|
resolved = await this.#resolveWatchTarget(target);
|
|
1452
1460
|
} catch (error) {
|
|
1453
|
-
await this.#send(chatId,
|
|
1461
|
+
await this.#send(chatId, t('无法解析会话:{message}', { message: safeErrorText(error) }));
|
|
1454
1462
|
return;
|
|
1455
1463
|
}
|
|
1456
1464
|
if (resolved.error) {
|
|
@@ -1460,7 +1468,7 @@ export class FeishuHarnessBridge {
|
|
|
1460
1468
|
const existing = this.#state.watchEntries?.(key) ?? [];
|
|
1461
1469
|
const existingEntry = existing.find((entry) => entry.sessionId === resolved.sessionId);
|
|
1462
1470
|
if (!existingEntry && existing.length >= MAX_WATCHES_PER_KEY) {
|
|
1463
|
-
await this.#send(chatId,
|
|
1471
|
+
await this.#send(chatId, t('每个聊天最多关注 {count} 个会话。', { count: MAX_WATCHES_PER_KEY }));
|
|
1464
1472
|
return;
|
|
1465
1473
|
}
|
|
1466
1474
|
try {
|
|
@@ -1473,10 +1481,10 @@ export class FeishuHarnessBridge {
|
|
|
1473
1481
|
chatId,
|
|
1474
1482
|
lastSeq,
|
|
1475
1483
|
});
|
|
1476
|
-
await this.#send(chatId,
|
|
1484
|
+
await this.#send(chatId, t('已关注会话「{title}」,任务完成会推送结果。', { title: String(resolved.title).replace(/\s+/gu, ' ') }));
|
|
1477
1485
|
await this.#queueEventTask(() => this.#compensateSession(resolved.sessionId));
|
|
1478
1486
|
} catch (error) {
|
|
1479
|
-
await this.#send(chatId,
|
|
1487
|
+
await this.#send(chatId, t('关注失败:{message}', { message: safeErrorText(error) }));
|
|
1480
1488
|
}
|
|
1481
1489
|
}
|
|
1482
1490
|
|
|
@@ -1487,15 +1495,15 @@ export class FeishuHarnessBridge {
|
|
|
1487
1495
|
? entries[Number(target) - 1]
|
|
1488
1496
|
: entries.find((candidate) => candidate.sessionId === target);
|
|
1489
1497
|
if (!entry) {
|
|
1490
|
-
await this.#send(chatId, '关注列表里没有这个会话,回复 /watchlist 查看。');
|
|
1498
|
+
await this.#send(chatId, t('关注列表里没有这个会话,回复 /watchlist 查看。'));
|
|
1491
1499
|
return;
|
|
1492
1500
|
}
|
|
1493
1501
|
try {
|
|
1494
1502
|
await this.#state.removeWatch(key, entry.sessionId);
|
|
1495
1503
|
this.#failedWatchSeqs.delete(`${key}\0${entry.sessionId}`);
|
|
1496
|
-
await this.#send(chatId,
|
|
1504
|
+
await this.#send(chatId, t('已取消关注「{title}」。', { title: String(entry.title ?? '').replace(/\s+/gu, ' ') }));
|
|
1497
1505
|
} catch (error) {
|
|
1498
|
-
await this.#send(chatId,
|
|
1506
|
+
await this.#send(chatId, t('取消失败:{message}', { message: safeErrorText(error) }));
|
|
1499
1507
|
}
|
|
1500
1508
|
}
|
|
1501
1509
|
|
|
@@ -1877,18 +1885,18 @@ export class FeishuHarnessBridge {
|
|
|
1877
1885
|
|
|
1878
1886
|
const text = extractText(event);
|
|
1879
1887
|
if (!text) {
|
|
1880
|
-
await this.#send(event.message.chat_id, '请用文字回答当前问题。');
|
|
1888
|
+
await this.#send(event.message.chat_id, t('请用文字回答当前问题。'));
|
|
1881
1889
|
return;
|
|
1882
1890
|
}
|
|
1883
1891
|
|
|
1884
1892
|
const pending = this.#pendingInteractions.get(key);
|
|
1885
1893
|
if (!pending || pending !== expected || pending.submitting) {
|
|
1886
1894
|
if (this.#isResolvedQuestionReply(event, key)) {
|
|
1887
|
-
await this.#send(event.message.chat_id, INTERACTION_RESOLVED_TEXT).catch(() => undefined);
|
|
1895
|
+
await this.#send(event.message.chat_id, INTERACTION_RESOLVED_TEXT()).catch(() => undefined);
|
|
1888
1896
|
return;
|
|
1889
1897
|
}
|
|
1890
1898
|
if (claimed && (!pending || pending !== expected)) {
|
|
1891
|
-
await this.#send(event.message.chat_id, INTERACTION_RESOLVED_TEXT);
|
|
1899
|
+
await this.#send(event.message.chat_id, INTERACTION_RESOLVED_TEXT());
|
|
1892
1900
|
return;
|
|
1893
1901
|
}
|
|
1894
1902
|
return this.#enqueueMessage(event, messageId, key, processingReaction, {
|
|
@@ -1946,7 +1954,7 @@ export class FeishuHarnessBridge {
|
|
|
1946
1954
|
if (error?.code === 'interaction-not-pending') {
|
|
1947
1955
|
this.#rememberResolvedInteraction(key, pending);
|
|
1948
1956
|
this.#clearPendingInteraction(key, pending.interactionId);
|
|
1949
|
-
await this.#send(event.message.chat_id, INTERACTION_RESOLVED_TEXT).catch(() => undefined);
|
|
1957
|
+
await this.#send(event.message.chat_id, INTERACTION_RESOLVED_TEXT()).catch(() => undefined);
|
|
1950
1958
|
return;
|
|
1951
1959
|
}
|
|
1952
1960
|
pending.submitting = false;
|
|
@@ -1954,7 +1962,7 @@ export class FeishuHarnessBridge {
|
|
|
1954
1962
|
pending.index -= 1;
|
|
1955
1963
|
this.#status.lastError = '回答提交失败。';
|
|
1956
1964
|
this.#logger.error?.('[dsh-feishu] failed to answer a Harness interaction');
|
|
1957
|
-
await this.#send(event.message.chat_id, '回答提交失败,请重新发送当前问题的答案。')
|
|
1965
|
+
await this.#send(event.message.chat_id, t('回答提交失败,请重新发送当前问题的答案。'))
|
|
1958
1966
|
.catch(() => undefined);
|
|
1959
1967
|
}
|
|
1960
1968
|
}
|
|
@@ -1999,7 +2007,7 @@ export class FeishuHarnessBridge {
|
|
|
1999
2007
|
});
|
|
2000
2008
|
await this.#send(
|
|
2001
2009
|
chatId,
|
|
2002
|
-
'检测到这个 Session 中遗留的待回答问题,已安全取消并继续处理你刚才的消息。',
|
|
2010
|
+
t('检测到这个 Session 中遗留的待回答问题,已安全取消并继续处理你刚才的消息。'),
|
|
2003
2011
|
).catch(() => undefined);
|
|
2004
2012
|
return;
|
|
2005
2013
|
}
|
|
@@ -2101,7 +2109,7 @@ export class FeishuHarnessBridge {
|
|
|
2101
2109
|
await this.#state.markSeen(messageId);
|
|
2102
2110
|
this.#status.lastMessageAt = new Date().toISOString();
|
|
2103
2111
|
this.#status.messagesReceived += 1;
|
|
2104
|
-
await this.#send(event.message.chat_id, INTERACTION_RESOLVED_TEXT).catch(() => undefined);
|
|
2112
|
+
await this.#send(event.message.chat_id, INTERACTION_RESOLVED_TEXT()).catch(() => undefined);
|
|
2105
2113
|
}
|
|
2106
2114
|
|
|
2107
2115
|
#takePendingInteraction(key, interactionId) {
|
|
@@ -2141,10 +2149,10 @@ export class FeishuHarnessBridge {
|
|
|
2141
2149
|
#progressText(update) {
|
|
2142
2150
|
if (update.type === 'text' && update.text) return update.text;
|
|
2143
2151
|
if (update.type === 'tool') {
|
|
2144
|
-
if (update.name === 'web_search') return '_正在搜索网络并整理信息…_';
|
|
2145
|
-
return
|
|
2152
|
+
if (update.name === 'web_search') return t('_正在搜索网络并整理信息…_');
|
|
2153
|
+
return t('_正在使用 {name}…_', { name: update.name || t('工具') });
|
|
2146
2154
|
}
|
|
2147
|
-
return
|
|
2155
|
+
return t('_{text}_', { text: update.text || t('正在处理…') });
|
|
2148
2156
|
}
|
|
2149
2157
|
|
|
2150
2158
|
async #addReaction(messageId, emojiType) {
|