@xmanrui/dsh-im 2.4.0 → 2.6.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 (60) hide show
  1. package/README.en.md +2 -2
  2. package/README.md +2 -2
  3. package/lib/client.js +322 -109
  4. package/lib/index.js +218 -211
  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 +102 -6
  27. package/src/channels/dingtalk/dingtalk-bridge.mjs +247 -38
  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/discord/discord-api.mjs +35 -0
  31. package/src/channels/discord/discord-bridge.mjs +1 -0
  32. package/src/channels/discord/discord-runtime.mjs +26 -0
  33. package/src/channels/feishu/bridge.mjs +115 -69
  34. package/src/channels/feishu/multi-bot-controller.mjs +2 -0
  35. package/src/channels/qq/qq-bridge.mjs +83 -28
  36. package/src/channels/qq/qq-controller.mjs +2 -0
  37. package/src/channels/shared/harness-client.mjs +40 -4
  38. package/src/channels/shared/i18n-en/shared-a.mjs +77 -0
  39. package/src/channels/shared/message-failure.mjs +244 -0
  40. package/src/channels/shared/semantic/artifact-delivery.mjs +9 -2
  41. package/src/channels/shared/status-reaction.mjs +107 -0
  42. package/src/channels/shared/text-harness-bridge.mjs +123 -66
  43. package/src/channels/shared/token-bot-controller.mjs +2 -0
  44. package/src/channels/slack/manifest.mjs +1 -0
  45. package/src/channels/slack/slack-api.mjs +28 -0
  46. package/src/channels/slack/slack-bridge.mjs +5 -0
  47. package/src/channels/slack/slack-controller.mjs +2 -0
  48. package/src/channels/slack/slack-runtime.mjs +24 -0
  49. package/src/channels/telegram/telegram-api.mjs +9 -0
  50. package/src/channels/telegram/telegram-bridge.mjs +1 -0
  51. package/src/channels/telegram/telegram-runtime.mjs +20 -0
  52. package/src/channels/wecom/wecom-bridge.mjs +49 -15
  53. package/src/channels/wecom/wecom-controller.mjs +2 -0
  54. package/src/channels/weixin/weixin-api.mjs +47 -0
  55. package/src/channels/weixin/weixin-bridge.mjs +261 -43
  56. package/src/channels/weixin/weixin-controller.mjs +2 -15
  57. package/src/channels/weixin/weixin-runtime.mjs +1 -0
  58. package/src/channels/whatsapp/whatsapp-bridge.mjs +1 -0
  59. package/src/channels/whatsapp/whatsapp-controller.mjs +2 -0
  60. package/src/channels/whatsapp/whatsapp-runtime.mjs +36 -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.6.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",
@@ -6872,6 +7062,7 @@ oauth_config:
6872
7062
  - files:read
6873
7063
  - files:write
6874
7064
  - im:history
7065
+ - reactions:write
6875
7066
  settings:
6876
7067
  event_subscriptions:
6877
7068
  bot_events:
@@ -7308,11 +7499,11 @@ var QR_DATA_URL3 = /^data:image\/(?:png|webp);base64,[a-z\d+/]+={0,2}$/i;
7308
7499
  function isRecord5(value) {
7309
7500
  return value !== null && typeof value === "object" && !Array.isArray(value);
7310
7501
  }
7311
- function text3(value, fallback, max = 240) {
7502
+ function text4(value, fallback, max = 240) {
7312
7503
  return typeof value === "string" && value.trim() ? value.trim().slice(0, max) : fallback;
7313
7504
  }
7314
7505
  function id3(value) {
7315
- const result = text3(value, "", 128);
7506
+ const result = text4(value, "", 128);
7316
7507
  return /^[a-z\d_-]+$/i.test(result) ? result : void 0;
7317
7508
  }
7318
7509
  function timestamp4(value) {
@@ -7330,8 +7521,8 @@ function normalizeTestMessage3(value) {
7330
7521
  function unwrapRpcResult7(result) {
7331
7522
  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
7523
  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);
7524
+ const error = new Error(text4(result.error?.message, "\u4F01\u4E1A\u5FAE\u4FE1\u64CD\u4F5C\u5931\u8D25"));
7525
+ error.code = text4(result.error?.code, "WECOM_RPC_ERROR", 80);
7335
7526
  throw error;
7336
7527
  }
7337
7528
  return result.value;
@@ -7344,7 +7535,7 @@ function normalizeProvisioning4(value, now = Date.now()) {
7344
7535
  if (!isRecord5(source)) throw new Error("\u4F01\u4E1A\u5FAE\u4FE1\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u626B\u7801\u7ED1\u5B9A\u8FDB\u5EA6");
7345
7536
  const attemptId = id3(source.attemptId);
7346
7537
  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);
7538
+ const reported = text4(source.status, "failed", 32);
7348
7539
  const result = {
7349
7540
  attemptId,
7350
7541
  status: PROVISION_STATES3.has(reported) ? reported : "failed",
@@ -7356,8 +7547,8 @@ function normalizeProvisioning4(value, now = Date.now()) {
7356
7547
  if (qrCodeDataUrl) result.qrCodeDataUrl = qrCodeDataUrl;
7357
7548
  if (id3(source.botId)) result.botId = id3(source.botId);
7358
7549
  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")
7550
+ code: text4(source.error.code, "WECOM_PROVISION_FAILED", 80),
7551
+ message: text4(source.error.message, "\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA\u6CA1\u6709\u63A5\u5165\u5B8C\u6210")
7361
7552
  };
7362
7553
  return result;
7363
7554
  }
@@ -7369,19 +7560,20 @@ function normalizeBot4(value) {
7369
7560
  botId: id3(value.botId),
7370
7561
  connected,
7371
7562
  state: connected ? "connected" : state,
7372
- workspace: text3(value.workspace, "", 4096),
7563
+ workspace: text4(value.workspace, "", 4096),
7373
7564
  agentPreset: normalizeAgentPresetId(value.agentPreset),
7374
7565
  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)
7566
+ name: text4(value.bot?.name, "\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA", 100),
7567
+ appIdMasked: text4(value.bot?.appIdMasked, "\u5E94\u7528\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58", 140)
7377
7568
  },
7378
7569
  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"),
7570
+ 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
7571
  lastCheckedAt: timestamp4(value.health?.lastCheckedAt)
7381
7572
  },
7573
+ lastMessageError: normalizeLastMessageError(value.lastMessageError),
7382
7574
  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")
7575
+ code: text4(value.error.code, "WECOM_ACCOUNT_ERROR", 80),
7576
+ message: text4(value.error.message, "\u4F01\u4E1A\u5FAE\u4FE1\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA")
7385
7577
  } : null
7386
7578
  };
7387
7579
  }
@@ -7400,8 +7592,8 @@ function normalizeSnapshot6(value) {
7400
7592
  }
7401
7593
  function presentError7(error) {
7402
7594
  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")
7595
+ code: text4(error?.code, "WECOM_ERROR", 80),
7596
+ message: text4(error?.message, "\u4F01\u4E1A\u5FAE\u4FE1\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")
7405
7597
  };
7406
7598
  }
7407
7599
  function formatRemaining4(milliseconds) {
@@ -7709,6 +7901,10 @@ function AccountCard3({
7709
7901
  h2(Button10, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
7710
7902
  ),
7711
7903
  summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
7904
+ account.lastMessageError ? h2(LastMessageErrorSummary, {
7905
+ className: "ddt-summary",
7906
+ error: account.lastMessageError
7907
+ }) : null,
7712
7908
  feedback ? h2("div", {
7713
7909
  className: "ddt-summary dim-cardFeedback",
7714
7910
  role: "status",
@@ -8110,14 +8306,6 @@ function normalizeTestMessage4(value) {
8110
8306
  const code = value.code === "test-target-unavailable" ? "test-target-unavailable" : "test-message-failed";
8111
8307
  return { sent: false, code };
8112
8308
  }
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
8309
  function unwrapRpcResult8(result) {
8122
8310
  if (!isRecord6(result) || typeof result.ok !== "boolean") {
8123
8311
  throw new Error("\u5FAE\u4FE1\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94");
@@ -8192,7 +8380,7 @@ function normalizeBot5(value) {
8192
8380
  messagesReceived: Math.max(0, Number(value.stats?.messagesReceived) || 0),
8193
8381
  messagesReplied: Math.max(0, Number(value.stats?.messagesReplied) || 0)
8194
8382
  },
8195
- lastMessageError: normalizeMessageError(value.lastMessageError),
8383
+ lastMessageError: normalizeLastMessageError(value.lastMessageError),
8196
8384
  error: isRecord6(value.error) ? {
8197
8385
  code: string(value.error.code, "WEIXIN_ACCOUNT_ERROR"),
8198
8386
  message: string(value.error.message, "\u5FAE\u4FE1\u8FDE\u63A5\u672A\u5C31\u7EEA")
@@ -8653,10 +8841,10 @@ function AccountCard4({
8653
8841
  h2(Button12, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
8654
8842
  ),
8655
8843
  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,
8844
+ account.lastMessageError ? h2(LastMessageErrorSummary, {
8845
+ className: "dxw-summary",
8846
+ error: account.lastMessageError
8847
+ }) : null,
8660
8848
  feedback ? h2("div", {
8661
8849
  className: "dxw-summary dim-cardFeedback",
8662
8850
  role: "status",
@@ -9151,11 +9339,11 @@ var QR_DATA_URL4 = /^data:image\/(?:png|webp);base64,[a-z\d+/]+={0,2}$/i;
9151
9339
  function isRecord7(value) {
9152
9340
  return value !== null && typeof value === "object" && !Array.isArray(value);
9153
9341
  }
9154
- function text4(value, fallback, max = 240) {
9342
+ function text5(value, fallback, max = 240) {
9155
9343
  return typeof value === "string" && value.trim() ? value.trim().slice(0, max) : fallback;
9156
9344
  }
9157
9345
  function id4(value) {
9158
- const result = text4(value, "", 128);
9346
+ const result = text5(value, "", 128);
9159
9347
  return /^[a-z\d_-]+$/i.test(result) ? result : void 0;
9160
9348
  }
9161
9349
  function timestamp6(value) {
@@ -9168,8 +9356,8 @@ function unwrapRpcResult9(result) {
9168
9356
  throw new Error("WhatsApp \u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94");
9169
9357
  }
9170
9358
  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);
9359
+ const error = new Error(text5(result.error?.message, "WhatsApp \u64CD\u4F5C\u5931\u8D25"));
9360
+ error.code = text5(result.error?.code, "WHATSAPP_RPC_ERROR", 80);
9173
9361
  throw error;
9174
9362
  }
9175
9363
  return result.value;
@@ -9182,7 +9370,7 @@ function normalizeProvisioning6(value, now = Date.now()) {
9182
9370
  if (!isRecord7(source)) throw new Error("WhatsApp \u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u626B\u7801\u8FDB\u5EA6");
9183
9371
  const attemptId = id4(source.attemptId);
9184
9372
  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);
9373
+ const reported = text5(source.status, "failed", 32);
9186
9374
  const result = {
9187
9375
  attemptId,
9188
9376
  status: PROVISION_STATES5.has(reported) ? reported : "failed",
@@ -9194,8 +9382,8 @@ function normalizeProvisioning6(value, now = Date.now()) {
9194
9382
  if (qrCodeDataUrl) result.qrCodeDataUrl = qrCodeDataUrl;
9195
9383
  if (id4(source.botId)) result.botId = id4(source.botId);
9196
9384
  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")
9385
+ code: text5(source.error.code, "WHATSAPP_PROVISION_FAILED", 80),
9386
+ message: text5(source.error.message, "WhatsApp \u6CA1\u6709\u63A5\u5165\u5B8C\u6210")
9199
9387
  };
9200
9388
  return result;
9201
9389
  }
@@ -9207,7 +9395,7 @@ function normalizeBot6(value) {
9207
9395
  botId: id4(value.botId),
9208
9396
  connected,
9209
9397
  state: connected ? "connected" : state,
9210
- workspace: text4(value.workspace, "", 4096),
9398
+ workspace: text5(value.workspace, "", 4096),
9211
9399
  agentPreset: normalizeAgentPresetId(value.agentPreset),
9212
9400
  accessPolicy: {
9213
9401
  accessMode: ["self-only", "private-allowlist", "open"].includes(
@@ -9216,16 +9404,17 @@ function normalizeBot6(value) {
9216
9404
  allowedNumbers: Array.isArray(value.accessPolicy?.allowedNumbers) ? [...new Set(value.accessPolicy.allowedNumbers.filter((entry) => typeof entry === "string" && /^[1-9]\d{4,14}$/.test(entry)))] : []
9217
9405
  },
9218
9406
  bot: {
9219
- name: text4(value.bot?.name, "WhatsApp\u673A\u5668\u4EBA", 100),
9220
- idMasked: text4(value.bot?.idMasked, "WhatsApp\u8D26\u53F7", 140)
9407
+ name: text5(value.bot?.name, "WhatsApp\u673A\u5668\u4EBA", 100),
9408
+ idMasked: text5(value.bot?.idMasked, "WhatsApp\u8D26\u53F7", 140)
9221
9409
  },
9222
9410
  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"),
9411
+ summary: text5(value.health?.summary, connected ? "WhatsApp Web \u5173\u8054\u8BBE\u5907\u8FD0\u884C\u6B63\u5E38" : "WhatsApp \u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA"),
9224
9412
  lastCheckedAt: timestamp6(value.health?.lastCheckedAt)
9225
9413
  },
9414
+ lastMessageError: normalizeLastMessageError(value.lastMessageError),
9226
9415
  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")
9416
+ code: text5(value.error.code, "WHATSAPP_ACCOUNT_ERROR", 80),
9417
+ message: text5(value.error.message, "WhatsApp \u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA")
9229
9418
  } : null
9230
9419
  };
9231
9420
  }
@@ -9245,8 +9434,8 @@ function normalizeSnapshot8(value) {
9245
9434
  }
9246
9435
  function presentError9(error) {
9247
9436
  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")
9437
+ code: text5(error?.code, "WHATSAPP_ERROR", 80),
9438
+ message: text5(error?.message, "WhatsApp \u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")
9250
9439
  };
9251
9440
  }
9252
9441
  function formatRemaining6(milliseconds) {
@@ -9756,6 +9945,10 @@ function WhatsappAccountCard({
9756
9945
  }, "\u79FB\u9664\u63A5\u5165")
9757
9946
  ),
9758
9947
  summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
9948
+ account.lastMessageError ? h2(LastMessageErrorSummary, {
9949
+ className: "ddt-summary",
9950
+ error: account.lastMessageError
9951
+ }) : null,
9759
9952
  testNotice ? h2("div", {
9760
9953
  className: "ddt-summary dim-cardFeedback",
9761
9954
  role: "status"
@@ -10131,9 +10324,13 @@ var CSS11 = String.raw`
10131
10324
  }
10132
10325
  .dim-page *, .dim-page *::before, .dim-page *::after { box-sizing: border-box; }
10133
10326
  .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; }
10327
+ .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; }
10328
+ .dim-brand:focus-visible { outline: 2px solid color-mix(in srgb, var(--dim-blue) 70%, white); outline-offset: 2px; }
10135
10329
  .dim-brandName { color: var(--dsw-alias-label-primary, #1f2329); font-size: 20px; line-height: 24px; font-weight: 800; letter-spacing: .04em; }
10136
10330
  .dim-title p { margin: 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: 18px; font-weight: 500; white-space: nowrap; }
10331
+ .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; }
10332
+ .dim-versionTooltip strong { color: var(--dsw-alias-label-primary, #1f2329); font: 600 11px/16px ui-monospace, SFMono-Regular, Menlo, monospace; }
10333
+ .dim-brand:hover .dim-versionTooltip, .dim-brand:focus .dim-versionTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
10137
10334
  .dim-githubAction { position: relative; display: inline-flex; flex: none; }
10138
10335
  .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
10336
  .dim-githubLink:hover { border-color: #aeb3bb; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
@@ -10425,6 +10622,7 @@ function installImStyles() {
10425
10622
  // plugin-src/client/index.js
10426
10623
  var name = "im-settings";
10427
10624
  var inject = ["slots", "connection", "locale", "workspaces"];
10625
+ var IM_PLUGIN_VERSION = package_default.version;
10428
10626
  var CHANNELS = Object.freeze([
10429
10627
  { id: "weixin", label: "\u5FAE\u4FE1" },
10430
10628
  { id: "feishu", label: "\u98DE\u4E66" },
@@ -10549,6 +10747,7 @@ function IMSettingsTab({
10549
10747
  }) {
10550
10748
  const [selected, setSelected] = React20.useState("weixin");
10551
10749
  const [loopbackRecovery, setLoopbackRecovery] = React20.useState(null);
10750
+ const versionTooltipId = React20.useId();
10552
10751
  const githubTooltipId = React20.useId();
10553
10752
  const active = CHANNELS.find((channel4) => channel4.id === selected) ?? CHANNELS[0];
10554
10753
  const reportLoopbackRecovery = React20.useCallback((recovery) => {
@@ -10593,9 +10792,23 @@ function IMSettingsTab({
10593
10792
  { className: "dim-title" },
10594
10793
  h2(
10595
10794
  "div",
10596
- { className: "dim-brand" },
10795
+ {
10796
+ className: "dim-brand",
10797
+ tabIndex: 0,
10798
+ "aria-describedby": versionTooltipId
10799
+ },
10597
10800
  h2("strong", { className: "dim-brandName" }, "DSH-IM"),
10598
- h2("p", null, "\u8BA9 DeepSeek Harness \u89E6\u624B\u53EF\u53CA")
10801
+ h2("p", null, "\u8BA9 DeepSeek Harness \u89E6\u624B\u53EF\u53CA"),
10802
+ h2(
10803
+ "span",
10804
+ {
10805
+ id: versionTooltipId,
10806
+ className: "dim-versionTooltip",
10807
+ role: "tooltip"
10808
+ },
10809
+ h2("span", null, "\u5F53\u524D\u7248\u672C"),
10810
+ h2("strong", null, `v${IM_PLUGIN_VERSION}`)
10811
+ )
10599
10812
  ),
10600
10813
  h2(
10601
10814
  "span",