@xmanrui/dsh-im 2.4.0 → 2.5.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 (47) hide show
  1. package/README.en.md +1 -1
  2. package/README.md +1 -1
  3. package/lib/client.js +321 -109
  4. package/lib/index.js +214 -207
  5. package/package.json +1 -1
  6. package/plugin-src/client/channel-card-meta.js +36 -1
  7. package/plugin-src/client/channels/dingtalk/api.js +2 -0
  8. package/plugin-src/client/channels/dingtalk/index.js +9 -1
  9. package/plugin-src/client/channels/feishu/api.js +3 -0
  10. package/plugin-src/client/channels/feishu/index.js +9 -1
  11. package/plugin-src/client/channels/qq/api.js +2 -0
  12. package/plugin-src/client/channels/qq/index.js +9 -1
  13. package/plugin-src/client/channels/shared/token-api.js +2 -0
  14. package/plugin-src/client/channels/shared/token-channel.js +9 -1
  15. package/plugin-src/client/channels/wecom/api.js +2 -0
  16. package/plugin-src/client/channels/wecom/index.js +9 -1
  17. package/plugin-src/client/channels/weixin/api.js +2 -10
  18. package/plugin-src/client/channels/weixin/index.js +9 -5
  19. package/plugin-src/client/channels/whatsapp/api.js +2 -0
  20. package/plugin-src/client/channels/whatsapp/index.js +9 -1
  21. package/plugin-src/client/i18n.js +4 -0
  22. package/plugin-src/client/index.js +16 -2
  23. package/plugin-src/client/last-message-error.js +17 -0
  24. package/plugin-src/client/styles.js +5 -1
  25. package/plugin-src/host/channels/feishu/rpc.mjs +3 -0
  26. package/src/channels/dingtalk/dingtalk-api.mjs +1 -1
  27. package/src/channels/dingtalk/dingtalk-bridge.mjs +49 -16
  28. package/src/channels/dingtalk/dingtalk-card-stream.mjs +2 -2
  29. package/src/channels/dingtalk/dingtalk-controller.mjs +2 -0
  30. package/src/channels/feishu/bridge.mjs +99 -43
  31. package/src/channels/feishu/multi-bot-controller.mjs +2 -0
  32. package/src/channels/qq/qq-bridge.mjs +83 -28
  33. package/src/channels/qq/qq-controller.mjs +2 -0
  34. package/src/channels/shared/harness-client.mjs +40 -4
  35. package/src/channels/shared/i18n-en/shared-a.mjs +77 -0
  36. package/src/channels/shared/message-failure.mjs +244 -0
  37. package/src/channels/shared/semantic/artifact-delivery.mjs +9 -2
  38. package/src/channels/shared/text-harness-bridge.mjs +65 -60
  39. package/src/channels/shared/token-bot-controller.mjs +2 -0
  40. package/src/channels/slack/slack-controller.mjs +2 -0
  41. package/src/channels/wecom/wecom-bridge.mjs +49 -15
  42. package/src/channels/wecom/wecom-controller.mjs +2 -0
  43. package/src/channels/weixin/weixin-api.mjs +47 -0
  44. package/src/channels/weixin/weixin-bridge.mjs +261 -43
  45. package/src/channels/weixin/weixin-controller.mjs +2 -15
  46. package/src/channels/weixin/weixin-runtime.mjs +1 -0
  47. package/src/channels/whatsapp/whatsapp-controller.mjs +2 -0
package/lib/client.js CHANGED
@@ -35,6 +35,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
35
35
  var index_exports = {};
36
36
  __export(index_exports, {
37
37
  IMSettingsTab: () => IMSettingsTab,
38
+ IM_PLUGIN_VERSION: () => IM_PLUGIN_VERSION,
38
39
  LoopbackRecoveryNotice: () => LoopbackRecoveryNotice,
39
40
  apply: () => apply,
40
41
  inject: () => inject,
@@ -43,6 +44,115 @@ __export(index_exports, {
43
44
  module.exports = __toCommonJS(index_exports);
44
45
  var React20 = __toESM(require("react"), 1);
45
46
 
47
+ // package.json
48
+ var package_default = {
49
+ name: "@xmanrui/dsh-im",
50
+ version: "2.5.0",
51
+ description: "\u628A\u4E5D\u79CD IM \u673A\u5668\u4EBA\u548C\u516C\u7F51 AI Office \u63A5\u5165\u672C\u673A DeepSeek Harness\u3002 Connect nine IM channels and a public AI Office to a local DeepSeek Harness.",
52
+ keywords: [
53
+ "deepseek-harness",
54
+ "dsh",
55
+ "dsh-plugin",
56
+ "ai-agent",
57
+ "im",
58
+ "instant-messaging",
59
+ "chatbot",
60
+ "feishu",
61
+ "lark",
62
+ "wechat",
63
+ "wecom",
64
+ "dingtalk",
65
+ "qq",
66
+ "slack",
67
+ "telegram",
68
+ "discord",
69
+ "whatsapp",
70
+ "ai-office"
71
+ ],
72
+ author: {
73
+ name: "xmanrui",
74
+ url: "https://github.com/xmanrui"
75
+ },
76
+ contributors: [
77
+ {
78
+ name: "C3H3-AI",
79
+ url: "https://github.com/C3H3-AI"
80
+ }
81
+ ],
82
+ license: "MIT",
83
+ type: "module",
84
+ repository: {
85
+ type: "git",
86
+ url: "git+https://github.com/xmanrui/dsh-im.git"
87
+ },
88
+ homepage: "https://github.com/xmanrui/dsh-im#readme",
89
+ bugs: "https://github.com/xmanrui/dsh-im/issues",
90
+ publishConfig: {
91
+ access: "public"
92
+ },
93
+ bin: {
94
+ "dsh-im": "bin/dsh-im.mjs"
95
+ },
96
+ main: "./lib/index.js",
97
+ exports: {
98
+ ".": "./lib/index.js",
99
+ "./client": "./lib/client.js",
100
+ "./package.json": "./package.json"
101
+ },
102
+ files: [
103
+ "assets",
104
+ "bin",
105
+ "cordis.patch.yml",
106
+ "lib",
107
+ "plugin-src",
108
+ "scripts",
109
+ "src",
110
+ "LICENSE",
111
+ "README.md",
112
+ "README.en.md",
113
+ "THIRD_PARTY_NOTICES.md"
114
+ ],
115
+ dsh: {
116
+ bundle: {
117
+ patch: "./cordis.patch.yml"
118
+ },
119
+ client: {
120
+ inject: [
121
+ "@deepseek-ai/dsh-client-connection",
122
+ "@deepseek-ai/dsh-client-runtime",
123
+ "@deepseek-ai/dsh-client-ui-settings",
124
+ "@deepseek-ai/dsh-client-ui-slots",
125
+ "@deepseek-ai/dsh-client-locale"
126
+ ],
127
+ platform: "web"
128
+ }
129
+ },
130
+ scripts: {
131
+ build: "node plugin-src/client/build.mjs && node plugin-src/host/build.mjs",
132
+ test: "node --test test/*.test.mjs test/channels/*/*.test.mjs",
133
+ check: "npm test && npm run build && node scripts/verify-package.mjs"
134
+ },
135
+ engines: {
136
+ node: ">=22.19"
137
+ },
138
+ dependencies: {
139
+ "@tencent-connect/qqbot-connector": "1.2.0",
140
+ "@tencent-connect/qqbot-nodejs": "1.0.4",
141
+ "@wecom/aibot-node-sdk": "1.0.7",
142
+ "dingtalk-stream": "2.1.4",
143
+ qrcode: "1.5.4"
144
+ },
145
+ devDependencies: {
146
+ "@larksuiteoapi/node-sdk": "1.73.0",
147
+ "@whiskeysockets/baileys": "7.0.0-rc14",
148
+ esbuild: "0.25.9",
149
+ "https-proxy-agent": "5.0.1",
150
+ react: "18.3.1",
151
+ "react-dom": "18.3.1",
152
+ "react-test-renderer": "18.3.1"
153
+ }
154
+ };
155
+
46
156
  // plugin-src/client/channel-logos.js
47
157
  var React = __toESM(require("react"), 1);
48
158
  var h = React.createElement;
@@ -199,6 +309,7 @@ var EN = Object.freeze({
199
309
  "IM\u673A\u5668\u4EBA\u8BBE\u7F6E": "IM bot settings",
200
310
  "IM \u6E20\u9053": "IM channels",
201
311
  "\u8BA9 DeepSeek Harness \u89E6\u624B\u53EF\u53CA": "DeepSeek Harness, always within reach",
312
+ "\u5F53\u524D\u7248\u672C": "Current version",
202
313
  "AI Office": "AI Office",
203
314
  "\uFF08\u5B9E\u9A8C\u529F\u80FD\uFF09": "(Experimental)",
204
315
  "AI Office \u8BBE\u7F6E": "AI Office settings",
@@ -304,6 +415,9 @@ var EN = Object.freeze({
304
415
  "\u6D88\u606F\u901A\u9053": "Message channel",
305
416
  "\u67E5\u770B\u6D88\u606F\u901A\u9053\u8BF4\u660E": "View message channel details",
306
417
  "\u6700\u8FD1\u68C0\u67E5": "Last checked",
418
+ "\u6700\u8FD1\u4E00\u6761\u6D88\u606F\u5904\u7406\u5931\u8D25": "Latest message failed",
419
+ "\u9519\u8BEF\u7801": "Code",
420
+ "\u53C2\u8003\u53F7": "Reference",
307
421
  "\u5F53\u524D\u5DE5\u4F5C\u533A": "Current workspace",
308
422
  "\u9009\u62E9\u76EE\u5F55": "Choose folder",
309
423
  "\u9009\u62E9\u673A\u5668\u4EBA\u5DE5\u4F5C\u533A\u76EE\u5F55": "Select bot workspace folder",
@@ -762,72 +876,72 @@ function isEnglish() {
762
876
  function channelName(value) {
763
877
  return localizeText(value);
764
878
  }
765
- function translateDynamic(text5) {
766
- let match = /^(\d+) \/ (\d+) 在线$/.exec(text5);
879
+ function translateDynamic(text6) {
880
+ let match = /^(\d+) \/ (\d+) 在线$/.exec(text6);
767
881
  if (match) return `${match[1]}/${match[2]} online`;
768
- match = /^已接入 (\d+) 个机器人,其中 (\d+) 个在线$/.exec(text5);
882
+ match = /^已接入 (\d+) 个机器人,其中 (\d+) 个在线$/.exec(text6);
769
883
  if (match) return `${match[2]} of ${match[1]} bots online`;
770
- match = /^正在读取\s*(.+?)\s*机器人状态…$/.exec(text5);
884
+ match = /^正在读取\s*(.+?)\s*机器人状态…$/.exec(text6);
771
885
  if (match) return `Loading ${channelName(match[1])} bot status\u2026`;
772
- match = /^无法读取\s*(.+?)\s*机器人状态$/.exec(text5);
886
+ match = /^无法读取\s*(.+?)\s*机器人状态$/.exec(text6);
773
887
  if (match) return `Could not load ${channelName(match[1])} bot status`;
774
- match = /^尚未接入\s*(.+?)\s*机器人$/.exec(text5);
888
+ match = /^尚未接入\s*(.+?)\s*机器人$/.exec(text6);
775
889
  if (match) return `No ${channelName(match[1])} bot connected yet`;
776
- match = /^已接入的\s*(.+?)\s*机器人$/.exec(text5);
890
+ match = /^已接入的\s*(.+?)\s*机器人$/.exec(text6);
777
891
  if (match) return `Connected ${channelName(match[1])} bots`;
778
- match = /^手动接入(.+)机器人$/.exec(text5);
892
+ match = /^手动接入(.+)机器人$/.exec(text6);
779
893
  if (match) return `Connect ${channelName(match[1])} bot manually`;
780
- match = /^(.+) 设置$/.exec(text5);
894
+ match = /^(.+) 设置$/.exec(text6);
781
895
  if (match) return `${channelName(match[1])} settings`;
782
- match = /^从 DeepSeek Harness 移除“(.+)”?$/.exec(text5);
896
+ match = /^从 DeepSeek Harness 移除“(.+)”?$/.exec(text6);
783
897
  if (match) return `Remove \u201C${match[1]}\u201D from DeepSeek Harness?`;
784
- match = /^从 DeepSeek Harness 移除(.+)$/.exec(text5);
898
+ match = /^从 DeepSeek Harness 移除(.+)$/.exec(text6);
785
899
  if (match) return `Remove ${match[1]} from DeepSeek Harness`;
786
- match = /^(.+)的飞书授权流程$/.exec(text5);
900
+ match = /^(.+)的飞书授权流程$/.exec(text6);
787
901
  if (match) return `Feishu authorization flow for ${match[1]}`;
788
- match = /^用于为(.+)补全权限与回调的一次性授权二维码$/.exec(text5);
902
+ match = /^用于为(.+)补全权限与回调的一次性授权二维码$/.exec(text6);
789
903
  if (match) return `One-time QR code for completing permissions and the callback for ${match[1]}`;
790
- match = /^用于为(.+)开通群消息权限的一次性授权二维码$/.exec(text5);
904
+ match = /^用于为(.+)开通群消息权限的一次性授权二维码$/.exec(text6);
791
905
  if (match) return `One-time QR code for granting group-message permission to ${match[1]}`;
792
- match = /^正在为「(.+)」补全权限与回调$/.exec(text5);
906
+ match = /^正在为「(.+)」补全权限与回调$/.exec(text6);
793
907
  if (match) return `Completing permissions and the callback for \u201C${match[1]}\u201D`;
794
- match = /^正在为「(.+)」开通群消息权限$/.exec(text5);
908
+ match = /^正在为「(.+)」开通群消息权限$/.exec(text6);
795
909
  if (match) return `Granting group-message permission to \u201C${match[1]}\u201D`;
796
- match = /^为(.+)补全权限与回调$/.exec(text5);
910
+ match = /^为(.+)补全权限与回调$/.exec(text6);
797
911
  if (match) return `Complete permissions and the callback for ${match[1]}`;
798
- match = /^(.+)的权限补全二维码已生成,请使用飞书扫码。$/.exec(text5);
912
+ match = /^(.+)的权限补全二维码已生成,请使用飞书扫码。$/.exec(text6);
799
913
  if (match) return `Permission-completion QR code generated for ${match[1]}. Scan it with Feishu.`;
800
- match = /^(.+)的群消息权限二维码已生成,请使用飞书确认。$/.exec(text5);
914
+ match = /^(.+)的群消息权限二维码已生成,请使用飞书确认。$/.exec(text6);
801
915
  if (match) return `Group-message permission QR code generated for ${match[1]}. Confirm it with Feishu.`;
802
- match = /^(.+)的权限与回调已补全。$/.exec(text5);
916
+ match = /^(.+)的权限与回调已补全。$/.exec(text6);
803
917
  if (match) return `Permissions and the callback completed for ${match[1]}.`;
804
- match = /^(.+)已开通群消息权限,并启用“响应所有群消息”。$/.exec(text5);
918
+ match = /^(.+)已开通群消息权限,并启用“响应所有群消息”。$/.exec(text6);
805
919
  if (match) return `${match[1]} now has group-message permission and \u201CRespond to all group messages\u201D is enabled.`;
806
- match = /^(检查连接|重试连接)(.+)$/.exec(text5);
920
+ match = /^(检查连接|重试连接)(.+)$/.exec(text6);
807
921
  if (match) return `${localizeText(match[1])} ${match[2]}`;
808
- match = /^移除(.+)$/.exec(text5);
922
+ match = /^移除(.+)$/.exec(text6);
809
923
  if (match) return `Remove ${match[1]}`;
810
- match = /^这会停止消息连接,并删除本机保存的 (.+)、机器人配置及会话映射。(.+)中的机器人不会被自动删除。$/.exec(text5);
924
+ match = /^这会停止消息连接,并删除本机保存的 (.+)、机器人配置及会话映射。(.+)中的机器人不会被自动删除。$/.exec(text6);
811
925
  if (match) {
812
926
  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.`;
813
927
  }
814
- match = /^二维码剩余 (.+)$/.exec(text5);
928
+ match = /^二维码剩余 (.+)$/.exec(text6);
815
929
  if (match) return `QR code expires in ${match[1]}`;
816
- match = /^最近一条消息处理失败:(.+)$/.exec(text5);
930
+ match = /^最近一条消息处理失败:(.+)$/.exec(text6);
817
931
  if (match) return `Latest message failed: ${localizeText(match[1])}`;
818
- match = /^图片下载失败(HTTP (.+)),请重新发送后再试。$/.exec(text5);
932
+ match = /^图片下载失败(HTTP (.+)),请重新发送后再试。$/.exec(text6);
819
933
  if (match) return `The image download failed (HTTP ${match[1]}). Send it again.`;
820
- match = /^一次最多只能处理 (\d+) 张图片。$/.exec(text5);
934
+ match = /^一次最多只能处理 (\d+) 张图片。$/.exec(text6);
821
935
  if (match) return `A message can contain at most ${match[1]} images.`;
822
- match = /^状态刷新失败:(.+)$/.exec(text5);
936
+ match = /^状态刷新失败:(.+)$/.exec(text6);
823
937
  if (match) return `Status refresh failed: ${match[1]}`;
824
- match = /^状态自动刷新失败:(.+)$/.exec(text5);
938
+ match = /^状态自动刷新失败:(.+)$/.exec(text6);
825
939
  if (match) return `Automatic status refresh failed: ${match[1]}`;
826
- match = /^操作失败:(.+)$/.exec(text5);
940
+ match = /^操作失败:(.+)$/.exec(text6);
827
941
  if (match) return `Operation failed: ${match[1]}`;
828
- match = /^连接检查失败:(.+)$/.exec(text5);
942
+ match = /^连接检查失败:(.+)$/.exec(text6);
829
943
  if (match) return `Connection check failed: ${match[1]}`;
830
- match = /^移除失败:(.+)$/.exec(text5);
944
+ match = /^移除失败:(.+)$/.exec(text6);
831
945
  if (match) return `Removal failed: ${match[1]}`;
832
946
  const phrases = [
833
947
  ["\u4F01\u4E1A\u5FAE\u4FE1", "WeCom"],
@@ -864,7 +978,7 @@ function translateDynamic(text5) {
864
978
  ["\u8FDE\u63A5\u72B6\u6001", "connection status"],
865
979
  ["\u4E8C\u7EF4\u7801", "QR code"]
866
980
  ];
867
- let output = text5;
981
+ let output = text6;
868
982
  for (const [source, target] of phrases) output = output.replaceAll(source, target);
869
983
  return output;
870
984
  }
@@ -1012,6 +1126,22 @@ function AgentPresetEditor({ agentPreset = "", disabled = false, onSave }) {
1012
1126
  );
1013
1127
  }
1014
1128
 
1129
+ // plugin-src/client/last-message-error.js
1130
+ function text(value, maxLength) {
1131
+ if (typeof value !== "string") return null;
1132
+ const trimmed = value.trim();
1133
+ return trimmed ? trimmed.slice(0, maxLength) : null;
1134
+ }
1135
+ function normalizeLastMessageError(value) {
1136
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
1137
+ const code = text(value.code, 64);
1138
+ const reason = text(value.reason, 64);
1139
+ const message = text(value.message, 500);
1140
+ const referenceId = text(value.referenceId, 40);
1141
+ const at = Number.isFinite(value.at) ? value.at : null;
1142
+ return code && reason && message && referenceId && at !== null ? { code, reason, message, referenceId, at } : null;
1143
+ }
1144
+
1015
1145
  // plugin-src/client/channels/dingtalk/api.js
1016
1146
  var DINGTALK_RPC_CHANNEL = "/dingtalk";
1017
1147
  var DINGTALK_ENDPOINTS = Object.freeze({
@@ -1166,6 +1296,7 @@ function normalizeBot(value) {
1166
1296
  messagesReceived: nonNegativeInteger(stats.messagesReceived),
1167
1297
  messagesReplied: nonNegativeInteger(stats.messagesReplied)
1168
1298
  },
1299
+ lastMessageError: normalizeLastMessageError(value.lastMessageError),
1169
1300
  error: normalizeError(value.error, "DINGTALK_ACCOUNT_ERROR", "\u9489\u9489\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA") ?? null
1170
1301
  };
1171
1302
  }
@@ -1711,6 +1842,19 @@ function useWorkspaceSnapshotFence() {
1711
1842
 
1712
1843
  // plugin-src/client/channel-card-meta.js
1713
1844
  var React8 = __toESM(require("react"), 1);
1845
+ function messageErrorTime(value) {
1846
+ try {
1847
+ return new Intl.DateTimeFormat(isEnglish() ? "en-US" : "zh-CN", {
1848
+ year: "numeric",
1849
+ month: "2-digit",
1850
+ day: "2-digit",
1851
+ hour: "2-digit",
1852
+ minute: "2-digit"
1853
+ }).format(new Date(value));
1854
+ } catch {
1855
+ return null;
1856
+ }
1857
+ }
1714
1858
  function ChannelListHeading({ className = "", id: id5, title, connectionLabel }) {
1715
1859
  const helpId = React8.useId();
1716
1860
  return h2(
@@ -1775,6 +1919,32 @@ function BotStatusMeta({
1775
1919
  )
1776
1920
  );
1777
1921
  }
1922
+ function LastMessageErrorSummary({ className = "", error }) {
1923
+ if (!error) return null;
1924
+ const occurredAt = messageErrorTime(error.at);
1925
+ return h2(
1926
+ "div",
1927
+ {
1928
+ className: `${className} dim-cardSummary`.trim(),
1929
+ role: "status"
1930
+ },
1931
+ h2("strong", null, "\u6700\u8FD1\u4E00\u6761\u6D88\u606F\u5904\u7406\u5931\u8D25"),
1932
+ "\uFF1A",
1933
+ h2("span", null, error.message),
1934
+ "\uFF08",
1935
+ h2("span", null, "\u9519\u8BEF\u7801"),
1936
+ ` ${error.code} \xB7 `,
1937
+ h2("span", null, "\u53C2\u8003\u53F7"),
1938
+ ` ${error.referenceId}`,
1939
+ occurredAt ? h2(
1940
+ React8.Fragment,
1941
+ null,
1942
+ " \xB7 ",
1943
+ h2("time", { dateTime: new Date(error.at).toISOString() }, occurredAt)
1944
+ ) : null,
1945
+ "\uFF09"
1946
+ );
1947
+ }
1778
1948
 
1779
1949
  // plugin-src/client/channels/dingtalk/styles.js
1780
1950
  var DINGTALK_STYLE_ID = "xmanrui-dsh-dingtalk-settings";
@@ -2249,6 +2419,10 @@ function AccountCard({
2249
2419
  )
2250
2420
  ),
2251
2421
  summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
2422
+ account.lastMessageError ? h2(LastMessageErrorSummary, {
2423
+ className: "ddt-summary",
2424
+ error: account.lastMessageError
2425
+ }) : null,
2252
2426
  feedback ? h2("div", {
2253
2427
  className: "ddt-summary dim-cardFeedback",
2254
2428
  role: "status"
@@ -2829,11 +3003,11 @@ var ACCOUNT_STATES2 = /* @__PURE__ */ new Set(["connected", "connecting", "offli
2829
3003
  function isRecord2(value) {
2830
3004
  return value !== null && typeof value === "object" && !Array.isArray(value);
2831
3005
  }
2832
- function text(value, fallback, max = 240) {
3006
+ function text2(value, fallback, max = 240) {
2833
3007
  return typeof value === "string" && value.trim() ? value.trim().slice(0, max) : fallback;
2834
3008
  }
2835
3009
  function id(value) {
2836
- const result = text(value, "", 128);
3010
+ const result = text2(value, "", 128);
2837
3011
  return /^[a-z\d_-]+$/i.test(result) ? result : void 0;
2838
3012
  }
2839
3013
  function timestamp2(value) {
@@ -2857,8 +3031,8 @@ function createTokenChannelApi(channel4, connectionSummary, {
2857
3031
  throw new Error(`${channel4} \u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94`);
2858
3032
  }
2859
3033
  if (!result.ok) {
2860
- const error = new Error(text(result.error?.message, `${channel4} \u64CD\u4F5C\u5931\u8D25`));
2861
- error.code = text(result.error?.code, `${channel4.toUpperCase()}_RPC_ERROR`, 80);
3034
+ const error = new Error(text2(result.error?.message, `${channel4} \u64CD\u4F5C\u5931\u8D25`));
3035
+ error.code = text2(result.error?.code, `${channel4.toUpperCase()}_RPC_ERROR`, 80);
2862
3036
  throw error;
2863
3037
  }
2864
3038
  return result.value;
@@ -2872,23 +3046,24 @@ function createTokenChannelApi(channel4, connectionSummary, {
2872
3046
  botId: id(value.botId),
2873
3047
  connected,
2874
3048
  state: connected ? "connected" : state,
2875
- workspace: text(value.workspace, "", 4096),
3049
+ workspace: text2(value.workspace, "", 4096),
2876
3050
  agentPreset: normalizeAgentPresetId(value.agentPreset),
2877
3051
  bot: {
2878
- name: text(value.bot?.name, `${channel4}\u673A\u5668\u4EBA`, 100),
2879
- username: text(value.bot?.username, "", 100),
2880
- idMasked: text(value.bot?.idMasked, "\u673A\u5668\u4EBA\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58", 140)
3052
+ name: text2(value.bot?.name, `${channel4}\u673A\u5668\u4EBA`, 100),
3053
+ username: text2(value.bot?.username, "", 100),
3054
+ idMasked: text2(value.bot?.idMasked, "\u673A\u5668\u4EBA\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58", 140)
2881
3055
  },
2882
3056
  health: {
2883
- summary: text(
3057
+ summary: text2(
2884
3058
  value.health?.summary,
2885
3059
  connected ? `${channel4}${connectionSummary}\u8FD0\u884C\u6B63\u5E38` : `${channel4}\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA`
2886
3060
  ),
2887
3061
  lastCheckedAt: timestamp2(value.health?.lastCheckedAt)
2888
3062
  },
3063
+ lastMessageError: normalizeLastMessageError(value.lastMessageError),
2889
3064
  error: isRecord2(value.error) ? {
2890
- code: text(value.error.code, `${channel4.toUpperCase()}_ACCOUNT_ERROR`, 80),
2891
- message: text(value.error.message, `${channel4}\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA`)
3065
+ code: text2(value.error.code, `${channel4.toUpperCase()}_ACCOUNT_ERROR`, 80),
3066
+ message: text2(value.error.message, `${channel4}\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA`)
2892
3067
  } : null,
2893
3068
  ...isRecord2(extension) ? extension : {}
2894
3069
  };
@@ -2907,8 +3082,8 @@ function createTokenChannelApi(channel4, connectionSummary, {
2907
3082
  };
2908
3083
  };
2909
3084
  const presentError10 = (error) => ({
2910
- code: text(error?.code, `${channel4.toUpperCase()}_ERROR`, 80),
2911
- message: text(error?.message, `${channel4}\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`)
3085
+ code: text2(error?.code, `${channel4.toUpperCase()}_ERROR`, 80),
3086
+ message: text2(error?.message, `${channel4}\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`)
2912
3087
  });
2913
3088
  return Object.freeze({ unwrapRpcResult: unwrapRpcResult10, normalizeSnapshot: normalizeSnapshot9, presentError: presentError10 });
2914
3089
  }
@@ -3051,6 +3226,10 @@ function createTokenChannelSettings(definition) {
3051
3226
  }, "\u79FB\u9664\u63A5\u5165")
3052
3227
  ),
3053
3228
  summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
3229
+ account.lastMessageError ? h2(LastMessageErrorSummary, {
3230
+ className: "ddt-summary",
3231
+ error: account.lastMessageError
3232
+ }) : null,
3054
3233
  testNotice ? h2("div", {
3055
3234
  className: "ddt-summary dim-cardFeedback",
3056
3235
  role: "status"
@@ -3582,6 +3761,7 @@ function normalizeBotConnection(value, fallbackBotId) {
3582
3761
  groupMessagePermissionGranted: value.groupMessagePermissionGranted === true,
3583
3762
  bot: normalizeBot2(value.bot),
3584
3763
  health: normalizeHealth(value.health, connected),
3764
+ lastMessageError: normalizeLastMessageError(value.lastMessageError),
3585
3765
  error: normalizeError2(value.error)
3586
3766
  };
3587
3767
  }
@@ -3596,6 +3776,7 @@ function normalizeBotsSnapshot(value) {
3596
3776
  configured: true,
3597
3777
  bot: value.bot,
3598
3778
  health: value.health,
3779
+ lastMessageError: value.lastMessageError,
3599
3780
  error: value.error
3600
3781
  }];
3601
3782
  }
@@ -4951,6 +5132,10 @@ function BotCard({
4951
5132
  { className: "bxf-healthSummary dim-cardSummary", "data-error": actionError || connection.error ? "true" : void 0 },
4952
5133
  summary
4953
5134
  ) : null,
5135
+ connection.lastMessageError ? h2(LastMessageErrorSummary, {
5136
+ className: "bxf-healthSummary",
5137
+ error: connection.lastMessageError
5138
+ }) : null,
4954
5139
  testNotice ? h2("div", {
4955
5140
  className: "bxf-healthSummary dim-cardFeedback",
4956
5141
  role: "status"
@@ -5758,11 +5943,11 @@ var QR_DATA_URL2 = /^data:image\/(?:png|webp);base64,[a-z\d+/]+={0,2}$/i;
5758
5943
  function isRecord4(value) {
5759
5944
  return value !== null && typeof value === "object" && !Array.isArray(value);
5760
5945
  }
5761
- function text2(value, fallback, max = 240) {
5946
+ function text3(value, fallback, max = 240) {
5762
5947
  return typeof value === "string" && value.trim() ? value.trim().slice(0, max) : fallback;
5763
5948
  }
5764
5949
  function id2(value) {
5765
- const result = text2(value, "", 128);
5950
+ const result = text3(value, "", 128);
5766
5951
  return /^[a-z\d_-]+$/i.test(result) ? result : void 0;
5767
5952
  }
5768
5953
  function timestamp3(value) {
@@ -5773,8 +5958,8 @@ function timestamp3(value) {
5773
5958
  function unwrapRpcResult4(result) {
5774
5959
  if (!isRecord4(result) || typeof result.ok !== "boolean") throw new Error("QQ \u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94");
5775
5960
  if (!result.ok) {
5776
- const error = new Error(text2(result.error?.message, "QQ \u64CD\u4F5C\u5931\u8D25"));
5777
- error.code = text2(result.error?.code, "QQ_RPC_ERROR", 80);
5961
+ const error = new Error(text3(result.error?.message, "QQ \u64CD\u4F5C\u5931\u8D25"));
5962
+ error.code = text3(result.error?.code, "QQ_RPC_ERROR", 80);
5778
5963
  throw error;
5779
5964
  }
5780
5965
  return result.value;
@@ -5787,7 +5972,7 @@ function normalizeProvisioning3(value, now = Date.now()) {
5787
5972
  if (!isRecord4(source)) throw new Error("QQ \u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u626B\u7801\u7ED1\u5B9A\u8FDB\u5EA6");
5788
5973
  const attemptId = id2(source.attemptId);
5789
5974
  if (!attemptId) throw new Error("QQ \u626B\u7801\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u7ED1\u5B9A\u4EFB\u52A1");
5790
- const reported = text2(source.status, "failed", 32);
5975
+ const reported = text3(source.status, "failed", 32);
5791
5976
  const result = {
5792
5977
  attemptId,
5793
5978
  status: PROVISION_STATES2.has(reported) ? reported : "failed",
@@ -5799,8 +5984,8 @@ function normalizeProvisioning3(value, now = Date.now()) {
5799
5984
  if (qrCodeDataUrl) result.qrCodeDataUrl = qrCodeDataUrl;
5800
5985
  if (id2(source.botId)) result.botId = id2(source.botId);
5801
5986
  if (isRecord4(source.error)) result.error = {
5802
- code: text2(source.error.code, "QQ_PROVISION_FAILED", 80),
5803
- message: text2(source.error.message, "QQ \u673A\u5668\u4EBA\u6CA1\u6709\u63A5\u5165\u5B8C\u6210")
5987
+ code: text3(source.error.code, "QQ_PROVISION_FAILED", 80),
5988
+ message: text3(source.error.message, "QQ \u673A\u5668\u4EBA\u6CA1\u6709\u63A5\u5165\u5B8C\u6210")
5804
5989
  };
5805
5990
  return result;
5806
5991
  }
@@ -5812,26 +5997,27 @@ function normalizeBot3(value) {
5812
5997
  botId: id2(value.botId),
5813
5998
  connected,
5814
5999
  state: connected ? "connected" : state,
5815
- workspace: text2(value.workspace, "", 4096),
6000
+ workspace: text3(value.workspace, "", 4096),
5816
6001
  agentPreset: normalizeAgentPresetId(value.agentPreset),
5817
6002
  bot: {
5818
- name: text2(value.bot?.name, "QQ\u673A\u5668\u4EBA", 100),
5819
- appIdMasked: text2(value.bot?.appIdMasked, "\u5E94\u7528\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58", 140)
6003
+ name: text3(value.bot?.name, "QQ\u673A\u5668\u4EBA", 100),
6004
+ appIdMasked: text3(value.bot?.appIdMasked, "\u5E94\u7528\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58", 140)
5820
6005
  },
5821
6006
  health: {
5822
- summary: text2(value.health?.summary, connected ? "QQ WebSocket \u957F\u8FDE\u63A5\u8FD0\u884C\u6B63\u5E38" : "QQ \u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA"),
6007
+ summary: text3(value.health?.summary, connected ? "QQ WebSocket \u957F\u8FDE\u63A5\u8FD0\u884C\u6B63\u5E38" : "QQ \u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA"),
5823
6008
  lastCheckedAt: timestamp3(value.health?.lastCheckedAt)
5824
6009
  },
6010
+ lastMessageError: normalizeLastMessageError(value.lastMessageError),
5825
6011
  error: isRecord4(value.error) ? {
5826
- code: text2(value.error.code, "QQ_ACCOUNT_ERROR", 80),
5827
- message: text2(value.error.message, "QQ \u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA")
6012
+ code: text3(value.error.code, "QQ_ACCOUNT_ERROR", 80),
6013
+ message: text3(value.error.message, "QQ \u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA")
5828
6014
  } : null
5829
6015
  };
5830
6016
  }
5831
6017
  function normalizeTestMessage2(value) {
5832
6018
  if (!isRecord4(value) || typeof value.sent !== "boolean") return void 0;
5833
6019
  if (value.sent) return { sent: true };
5834
- const code = text2(value.code, "test-message-failed", 80);
6020
+ const code = text3(value.code, "test-message-failed", 80);
5835
6021
  return {
5836
6022
  sent: false,
5837
6023
  code: TEST_MESSAGE_CODES.has(code) ? code : "test-message-failed"
@@ -5860,8 +6046,8 @@ function connectionTestFeedback2(result) {
5860
6046
  }
5861
6047
  function presentError4(error) {
5862
6048
  return {
5863
- code: text2(error?.code, "QQ_ERROR", 80),
5864
- message: text2(error?.message, "QQ \u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")
6049
+ code: text3(error?.code, "QQ_ERROR", 80),
6050
+ message: text3(error?.message, "QQ \u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")
5865
6051
  };
5866
6052
  }
5867
6053
  function formatRemaining3(milliseconds) {
@@ -6169,6 +6355,10 @@ function AccountCard2({
6169
6355
  h2(Button7, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
6170
6356
  ),
6171
6357
  summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
6358
+ account.lastMessageError ? h2(LastMessageErrorSummary, {
6359
+ className: "ddt-summary",
6360
+ error: account.lastMessageError
6361
+ }) : null,
6172
6362
  feedback ? h2("div", {
6173
6363
  className: "ddt-summary dim-cardFeedback",
6174
6364
  role: "status",
@@ -7308,11 +7498,11 @@ var QR_DATA_URL3 = /^data:image\/(?:png|webp);base64,[a-z\d+/]+={0,2}$/i;
7308
7498
  function isRecord5(value) {
7309
7499
  return value !== null && typeof value === "object" && !Array.isArray(value);
7310
7500
  }
7311
- function text3(value, fallback, max = 240) {
7501
+ function text4(value, fallback, max = 240) {
7312
7502
  return typeof value === "string" && value.trim() ? value.trim().slice(0, max) : fallback;
7313
7503
  }
7314
7504
  function id3(value) {
7315
- const result = text3(value, "", 128);
7505
+ const result = text4(value, "", 128);
7316
7506
  return /^[a-z\d_-]+$/i.test(result) ? result : void 0;
7317
7507
  }
7318
7508
  function timestamp4(value) {
@@ -7330,8 +7520,8 @@ function normalizeTestMessage3(value) {
7330
7520
  function unwrapRpcResult7(result) {
7331
7521
  if (!isRecord5(result) || typeof result.ok !== "boolean") throw new Error("\u4F01\u4E1A\u5FAE\u4FE1\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94");
7332
7522
  if (!result.ok) {
7333
- const error = new Error(text3(result.error?.message, "\u4F01\u4E1A\u5FAE\u4FE1\u64CD\u4F5C\u5931\u8D25"));
7334
- error.code = text3(result.error?.code, "WECOM_RPC_ERROR", 80);
7523
+ const error = new Error(text4(result.error?.message, "\u4F01\u4E1A\u5FAE\u4FE1\u64CD\u4F5C\u5931\u8D25"));
7524
+ error.code = text4(result.error?.code, "WECOM_RPC_ERROR", 80);
7335
7525
  throw error;
7336
7526
  }
7337
7527
  return result.value;
@@ -7344,7 +7534,7 @@ function normalizeProvisioning4(value, now = Date.now()) {
7344
7534
  if (!isRecord5(source)) throw new Error("\u4F01\u4E1A\u5FAE\u4FE1\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u626B\u7801\u7ED1\u5B9A\u8FDB\u5EA6");
7345
7535
  const attemptId = id3(source.attemptId);
7346
7536
  if (!attemptId) throw new Error("\u4F01\u4E1A\u5FAE\u4FE1\u626B\u7801\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u7ED1\u5B9A\u4EFB\u52A1");
7347
- const reported = text3(source.status, "failed", 32);
7537
+ const reported = text4(source.status, "failed", 32);
7348
7538
  const result = {
7349
7539
  attemptId,
7350
7540
  status: PROVISION_STATES3.has(reported) ? reported : "failed",
@@ -7356,8 +7546,8 @@ function normalizeProvisioning4(value, now = Date.now()) {
7356
7546
  if (qrCodeDataUrl) result.qrCodeDataUrl = qrCodeDataUrl;
7357
7547
  if (id3(source.botId)) result.botId = id3(source.botId);
7358
7548
  if (isRecord5(source.error)) result.error = {
7359
- code: text3(source.error.code, "WECOM_PROVISION_FAILED", 80),
7360
- message: text3(source.error.message, "\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA\u6CA1\u6709\u63A5\u5165\u5B8C\u6210")
7549
+ code: text4(source.error.code, "WECOM_PROVISION_FAILED", 80),
7550
+ message: text4(source.error.message, "\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA\u6CA1\u6709\u63A5\u5165\u5B8C\u6210")
7361
7551
  };
7362
7552
  return result;
7363
7553
  }
@@ -7369,19 +7559,20 @@ function normalizeBot4(value) {
7369
7559
  botId: id3(value.botId),
7370
7560
  connected,
7371
7561
  state: connected ? "connected" : state,
7372
- workspace: text3(value.workspace, "", 4096),
7562
+ workspace: text4(value.workspace, "", 4096),
7373
7563
  agentPreset: normalizeAgentPresetId(value.agentPreset),
7374
7564
  bot: {
7375
- name: text3(value.bot?.name, "\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA", 100),
7376
- appIdMasked: text3(value.bot?.appIdMasked, "\u5E94\u7528\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58", 140)
7565
+ name: text4(value.bot?.name, "\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA", 100),
7566
+ appIdMasked: text4(value.bot?.appIdMasked, "\u5E94\u7528\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58", 140)
7377
7567
  },
7378
7568
  health: {
7379
- summary: text3(value.health?.summary, connected ? "\u4F01\u4E1A\u5FAE\u4FE1 WebSocket \u957F\u8FDE\u63A5\u8FD0\u884C\u6B63\u5E38" : "\u4F01\u4E1A\u5FAE\u4FE1\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA"),
7569
+ summary: text4(value.health?.summary, connected ? "\u4F01\u4E1A\u5FAE\u4FE1 WebSocket \u957F\u8FDE\u63A5\u8FD0\u884C\u6B63\u5E38" : "\u4F01\u4E1A\u5FAE\u4FE1\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA"),
7380
7570
  lastCheckedAt: timestamp4(value.health?.lastCheckedAt)
7381
7571
  },
7572
+ lastMessageError: normalizeLastMessageError(value.lastMessageError),
7382
7573
  error: isRecord5(value.error) ? {
7383
- code: text3(value.error.code, "WECOM_ACCOUNT_ERROR", 80),
7384
- message: text3(value.error.message, "\u4F01\u4E1A\u5FAE\u4FE1\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA")
7574
+ code: text4(value.error.code, "WECOM_ACCOUNT_ERROR", 80),
7575
+ message: text4(value.error.message, "\u4F01\u4E1A\u5FAE\u4FE1\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA")
7385
7576
  } : null
7386
7577
  };
7387
7578
  }
@@ -7400,8 +7591,8 @@ function normalizeSnapshot6(value) {
7400
7591
  }
7401
7592
  function presentError7(error) {
7402
7593
  return {
7403
- code: text3(error?.code, "WECOM_ERROR", 80),
7404
- message: text3(error?.message, "\u4F01\u4E1A\u5FAE\u4FE1\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")
7594
+ code: text4(error?.code, "WECOM_ERROR", 80),
7595
+ message: text4(error?.message, "\u4F01\u4E1A\u5FAE\u4FE1\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")
7405
7596
  };
7406
7597
  }
7407
7598
  function formatRemaining4(milliseconds) {
@@ -7709,6 +7900,10 @@ function AccountCard3({
7709
7900
  h2(Button10, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
7710
7901
  ),
7711
7902
  summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
7903
+ account.lastMessageError ? h2(LastMessageErrorSummary, {
7904
+ className: "ddt-summary",
7905
+ error: account.lastMessageError
7906
+ }) : null,
7712
7907
  feedback ? h2("div", {
7713
7908
  className: "ddt-summary dim-cardFeedback",
7714
7909
  role: "status",
@@ -8110,14 +8305,6 @@ function normalizeTestMessage4(value) {
8110
8305
  const code = value.code === "test-target-unavailable" ? "test-target-unavailable" : "test-message-failed";
8111
8306
  return { sent: false, code };
8112
8307
  }
8113
- function normalizeMessageError(value) {
8114
- if (!isRecord6(value)) return null;
8115
- const code = string(value.code).slice(0, 64);
8116
- const reason = string(value.reason).slice(0, 128);
8117
- const message = string(value.message).slice(0, 500);
8118
- const at = timestamp5(value.at);
8119
- return code && reason && message && at !== null ? { code, reason, message, at } : null;
8120
- }
8121
8308
  function unwrapRpcResult8(result) {
8122
8309
  if (!isRecord6(result) || typeof result.ok !== "boolean") {
8123
8310
  throw new Error("\u5FAE\u4FE1\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94");
@@ -8192,7 +8379,7 @@ function normalizeBot5(value) {
8192
8379
  messagesReceived: Math.max(0, Number(value.stats?.messagesReceived) || 0),
8193
8380
  messagesReplied: Math.max(0, Number(value.stats?.messagesReplied) || 0)
8194
8381
  },
8195
- lastMessageError: normalizeMessageError(value.lastMessageError),
8382
+ lastMessageError: normalizeLastMessageError(value.lastMessageError),
8196
8383
  error: isRecord6(value.error) ? {
8197
8384
  code: string(value.error.code, "WEIXIN_ACCOUNT_ERROR"),
8198
8385
  message: string(value.error.message, "\u5FAE\u4FE1\u8FDE\u63A5\u672A\u5C31\u7EEA")
@@ -8653,10 +8840,10 @@ function AccountCard4({
8653
8840
  h2(Button12, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
8654
8841
  ),
8655
8842
  summary ? h2("div", { className: "dxw-summary dim-cardSummary" }, summary) : null,
8656
- account.lastMessageError ? h2("div", {
8657
- className: "dxw-summary dim-cardSummary",
8658
- role: "status"
8659
- }, `\u6700\u8FD1\u4E00\u6761\u6D88\u606F\u5904\u7406\u5931\u8D25\uFF1A${account.lastMessageError.message}`) : null,
8843
+ account.lastMessageError ? h2(LastMessageErrorSummary, {
8844
+ className: "dxw-summary",
8845
+ error: account.lastMessageError
8846
+ }) : null,
8660
8847
  feedback ? h2("div", {
8661
8848
  className: "dxw-summary dim-cardFeedback",
8662
8849
  role: "status",
@@ -9151,11 +9338,11 @@ var QR_DATA_URL4 = /^data:image\/(?:png|webp);base64,[a-z\d+/]+={0,2}$/i;
9151
9338
  function isRecord7(value) {
9152
9339
  return value !== null && typeof value === "object" && !Array.isArray(value);
9153
9340
  }
9154
- function text4(value, fallback, max = 240) {
9341
+ function text5(value, fallback, max = 240) {
9155
9342
  return typeof value === "string" && value.trim() ? value.trim().slice(0, max) : fallback;
9156
9343
  }
9157
9344
  function id4(value) {
9158
- const result = text4(value, "", 128);
9345
+ const result = text5(value, "", 128);
9159
9346
  return /^[a-z\d_-]+$/i.test(result) ? result : void 0;
9160
9347
  }
9161
9348
  function timestamp6(value) {
@@ -9168,8 +9355,8 @@ function unwrapRpcResult9(result) {
9168
9355
  throw new Error("WhatsApp \u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94");
9169
9356
  }
9170
9357
  if (!result.ok) {
9171
- const error = new Error(text4(result.error?.message, "WhatsApp \u64CD\u4F5C\u5931\u8D25"));
9172
- error.code = text4(result.error?.code, "WHATSAPP_RPC_ERROR", 80);
9358
+ const error = new Error(text5(result.error?.message, "WhatsApp \u64CD\u4F5C\u5931\u8D25"));
9359
+ error.code = text5(result.error?.code, "WHATSAPP_RPC_ERROR", 80);
9173
9360
  throw error;
9174
9361
  }
9175
9362
  return result.value;
@@ -9182,7 +9369,7 @@ function normalizeProvisioning6(value, now = Date.now()) {
9182
9369
  if (!isRecord7(source)) throw new Error("WhatsApp \u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u626B\u7801\u8FDB\u5EA6");
9183
9370
  const attemptId = id4(source.attemptId);
9184
9371
  if (!attemptId) throw new Error("WhatsApp \u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u626B\u7801\u4EFB\u52A1");
9185
- const reported = text4(source.status, "failed", 32);
9372
+ const reported = text5(source.status, "failed", 32);
9186
9373
  const result = {
9187
9374
  attemptId,
9188
9375
  status: PROVISION_STATES5.has(reported) ? reported : "failed",
@@ -9194,8 +9381,8 @@ function normalizeProvisioning6(value, now = Date.now()) {
9194
9381
  if (qrCodeDataUrl) result.qrCodeDataUrl = qrCodeDataUrl;
9195
9382
  if (id4(source.botId)) result.botId = id4(source.botId);
9196
9383
  if (isRecord7(source.error)) result.error = {
9197
- code: text4(source.error.code, "WHATSAPP_PROVISION_FAILED", 80),
9198
- message: text4(source.error.message, "WhatsApp \u6CA1\u6709\u63A5\u5165\u5B8C\u6210")
9384
+ code: text5(source.error.code, "WHATSAPP_PROVISION_FAILED", 80),
9385
+ message: text5(source.error.message, "WhatsApp \u6CA1\u6709\u63A5\u5165\u5B8C\u6210")
9199
9386
  };
9200
9387
  return result;
9201
9388
  }
@@ -9207,7 +9394,7 @@ function normalizeBot6(value) {
9207
9394
  botId: id4(value.botId),
9208
9395
  connected,
9209
9396
  state: connected ? "connected" : state,
9210
- workspace: text4(value.workspace, "", 4096),
9397
+ workspace: text5(value.workspace, "", 4096),
9211
9398
  agentPreset: normalizeAgentPresetId(value.agentPreset),
9212
9399
  accessPolicy: {
9213
9400
  accessMode: ["self-only", "private-allowlist", "open"].includes(
@@ -9216,16 +9403,17 @@ function normalizeBot6(value) {
9216
9403
  allowedNumbers: Array.isArray(value.accessPolicy?.allowedNumbers) ? [...new Set(value.accessPolicy.allowedNumbers.filter((entry) => typeof entry === "string" && /^[1-9]\d{4,14}$/.test(entry)))] : []
9217
9404
  },
9218
9405
  bot: {
9219
- name: text4(value.bot?.name, "WhatsApp\u673A\u5668\u4EBA", 100),
9220
- idMasked: text4(value.bot?.idMasked, "WhatsApp\u8D26\u53F7", 140)
9406
+ name: text5(value.bot?.name, "WhatsApp\u673A\u5668\u4EBA", 100),
9407
+ idMasked: text5(value.bot?.idMasked, "WhatsApp\u8D26\u53F7", 140)
9221
9408
  },
9222
9409
  health: {
9223
- summary: text4(value.health?.summary, connected ? "WhatsApp Web \u5173\u8054\u8BBE\u5907\u8FD0\u884C\u6B63\u5E38" : "WhatsApp \u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA"),
9410
+ summary: text5(value.health?.summary, connected ? "WhatsApp Web \u5173\u8054\u8BBE\u5907\u8FD0\u884C\u6B63\u5E38" : "WhatsApp \u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA"),
9224
9411
  lastCheckedAt: timestamp6(value.health?.lastCheckedAt)
9225
9412
  },
9413
+ lastMessageError: normalizeLastMessageError(value.lastMessageError),
9226
9414
  error: isRecord7(value.error) ? {
9227
- code: text4(value.error.code, "WHATSAPP_ACCOUNT_ERROR", 80),
9228
- message: text4(value.error.message, "WhatsApp \u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA")
9415
+ code: text5(value.error.code, "WHATSAPP_ACCOUNT_ERROR", 80),
9416
+ message: text5(value.error.message, "WhatsApp \u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA")
9229
9417
  } : null
9230
9418
  };
9231
9419
  }
@@ -9245,8 +9433,8 @@ function normalizeSnapshot8(value) {
9245
9433
  }
9246
9434
  function presentError9(error) {
9247
9435
  return {
9248
- code: text4(error?.code, "WHATSAPP_ERROR", 80),
9249
- message: text4(error?.message, "WhatsApp \u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")
9436
+ code: text5(error?.code, "WHATSAPP_ERROR", 80),
9437
+ message: text5(error?.message, "WhatsApp \u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")
9250
9438
  };
9251
9439
  }
9252
9440
  function formatRemaining6(milliseconds) {
@@ -9756,6 +9944,10 @@ function WhatsappAccountCard({
9756
9944
  }, "\u79FB\u9664\u63A5\u5165")
9757
9945
  ),
9758
9946
  summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
9947
+ account.lastMessageError ? h2(LastMessageErrorSummary, {
9948
+ className: "ddt-summary",
9949
+ error: account.lastMessageError
9950
+ }) : null,
9759
9951
  testNotice ? h2("div", {
9760
9952
  className: "ddt-summary dim-cardFeedback",
9761
9953
  role: "status"
@@ -10131,9 +10323,13 @@ var CSS11 = String.raw`
10131
10323
  }
10132
10324
  .dim-page *, .dim-page *::before, .dim-page *::after { box-sizing: border-box; }
10133
10325
  .dim-title { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin: 0 0 18px; }
10134
- .dim-brand { min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 1px; }
10326
+ .dim-brand { position: relative; min-width: 0; width: max-content; max-width: 100%; display: flex; flex-direction: column; align-items: flex-start; gap: 1px; margin: -2px -6px; padding: 2px 6px; border-radius: 8px; cursor: help; }
10327
+ .dim-brand:focus-visible { outline: 2px solid color-mix(in srgb, var(--dim-blue) 70%, white); outline-offset: 2px; }
10135
10328
  .dim-brandName { color: var(--dsw-alias-label-primary, #1f2329); font-size: 20px; line-height: 24px; font-weight: 800; letter-spacing: .04em; }
10136
10329
  .dim-title p { margin: 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: 18px; font-weight: 500; white-space: nowrap; }
10330
+ .dim-versionTooltip { position: absolute; left: 0; bottom: calc(100% + 8px); z-index: 20; width: max-content; max-width: min(220px, 80vw); display: inline-flex; align-items: center; gap: 6px; padding: 6px 9px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 7px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 8px 24px rgb(31 35 41 / 14%); font-size: 11px; line-height: 16px; font-weight: 500; white-space: nowrap; opacity: 0; visibility: hidden; transform: translateY(3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
10331
+ .dim-versionTooltip strong { color: var(--dsw-alias-label-primary, #1f2329); font: 600 11px/16px ui-monospace, SFMono-Regular, Menlo, monospace; }
10332
+ .dim-brand:hover .dim-versionTooltip, .dim-brand:focus .dim-versionTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
10137
10333
  .dim-githubAction { position: relative; display: inline-flex; flex: none; }
10138
10334
  .dim-githubLink { min-height: 30px; display: inline-flex; align-items: center; gap: 5px; flex: none; padding: 0 10px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-layer-1, #fff); font-size: 12px; line-height: normal; font-weight: 560; text-decoration: none; transition: border-color .15s ease, color .15s ease, background .15s ease; }
10139
10335
  .dim-githubLink:hover { border-color: #aeb3bb; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
@@ -10425,6 +10621,7 @@ function installImStyles() {
10425
10621
  // plugin-src/client/index.js
10426
10622
  var name = "im-settings";
10427
10623
  var inject = ["slots", "connection", "locale", "workspaces"];
10624
+ var IM_PLUGIN_VERSION = package_default.version;
10428
10625
  var CHANNELS = Object.freeze([
10429
10626
  { id: "weixin", label: "\u5FAE\u4FE1" },
10430
10627
  { id: "feishu", label: "\u98DE\u4E66" },
@@ -10549,6 +10746,7 @@ function IMSettingsTab({
10549
10746
  }) {
10550
10747
  const [selected, setSelected] = React20.useState("weixin");
10551
10748
  const [loopbackRecovery, setLoopbackRecovery] = React20.useState(null);
10749
+ const versionTooltipId = React20.useId();
10552
10750
  const githubTooltipId = React20.useId();
10553
10751
  const active = CHANNELS.find((channel4) => channel4.id === selected) ?? CHANNELS[0];
10554
10752
  const reportLoopbackRecovery = React20.useCallback((recovery) => {
@@ -10593,9 +10791,23 @@ function IMSettingsTab({
10593
10791
  { className: "dim-title" },
10594
10792
  h2(
10595
10793
  "div",
10596
- { className: "dim-brand" },
10794
+ {
10795
+ className: "dim-brand",
10796
+ tabIndex: 0,
10797
+ "aria-describedby": versionTooltipId
10798
+ },
10597
10799
  h2("strong", { className: "dim-brandName" }, "DSH-IM"),
10598
- h2("p", null, "\u8BA9 DeepSeek Harness \u89E6\u624B\u53EF\u53CA")
10800
+ h2("p", null, "\u8BA9 DeepSeek Harness \u89E6\u624B\u53EF\u53CA"),
10801
+ h2(
10802
+ "span",
10803
+ {
10804
+ id: versionTooltipId,
10805
+ className: "dim-versionTooltip",
10806
+ role: "tooltip"
10807
+ },
10808
+ h2("span", null, "\u5F53\u524D\u7248\u672C"),
10809
+ h2("strong", null, `v${IM_PLUGIN_VERSION}`)
10810
+ )
10599
10811
  ),
10600
10812
  h2(
10601
10813
  "span",