@xmanrui/dsh-im 4.15.0 → 4.16.1

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 (64) hide show
  1. package/README.en.md +2 -1
  2. package/README.md +9 -5
  3. package/lib/client.js +1731 -612
  4. package/lib/index.js +303 -293
  5. package/package.json +10 -2
  6. package/plugin-src/client/access-policy-settings.js +6 -0
  7. package/plugin-src/client/channels/feishu/index.js +15 -3
  8. package/plugin-src/client/channels/wecom-app/api.js +124 -0
  9. package/plugin-src/client/channels/wecom-app/index.js +612 -0
  10. package/plugin-src/client/channels/wecom-app/styles.js +25 -0
  11. package/plugin-src/client/delivery-settings.js +7 -0
  12. package/plugin-src/client/i18n.js +63 -0
  13. package/plugin-src/client/index.js +18 -0
  14. package/plugin-src/client/model-setting.js +135 -69
  15. package/plugin-src/client/styles.js +22 -7
  16. package/plugin-src/host/channels/dingtalk/index.mjs +8 -15
  17. package/plugin-src/host/channels/discord/index.mjs +8 -10
  18. package/plugin-src/host/channels/feishu/index.mjs +8 -15
  19. package/plugin-src/host/channels/office/index.mjs +9 -5
  20. package/plugin-src/host/channels/qq/index.mjs +8 -15
  21. package/plugin-src/host/channels/shared/access-policy-production.mjs +1 -1
  22. package/plugin-src/host/channels/shared/model-setting-rpc.mjs +1 -2
  23. package/plugin-src/host/channels/shared/startup-error.mjs +53 -0
  24. package/plugin-src/host/channels/shared/startup.mjs +47 -0
  25. package/plugin-src/host/channels/shared/workspace-rpc.mjs +1 -0
  26. package/plugin-src/host/channels/slack/index.mjs +8 -10
  27. package/plugin-src/host/channels/telegram/index.mjs +8 -10
  28. package/plugin-src/host/channels/wecom/index.mjs +8 -15
  29. package/plugin-src/host/channels/wecom/rpc.mjs +6 -1
  30. package/plugin-src/host/channels/wecom-app/index.mjs +33 -0
  31. package/plugin-src/host/channels/wecom-app/production.mjs +217 -0
  32. package/plugin-src/host/channels/wecom-app/rpc.mjs +225 -0
  33. package/plugin-src/host/channels/weixin/index.mjs +8 -15
  34. package/plugin-src/host/channels/whatsapp/index.mjs +8 -15
  35. package/plugin-src/host/delivery-adapter.mjs +4 -0
  36. package/plugin-src/host/delivery-suggestions.mjs +4 -0
  37. package/plugin-src/host/index.mjs +7 -2
  38. package/scripts/verify-model-setting.mjs +54 -0
  39. package/src/channels/dingtalk/dingtalk-api.mjs +41 -48
  40. package/src/channels/dingtalk/dingtalk-bridge.mjs +5 -1
  41. package/src/channels/feishu/bridge.mjs +295 -9
  42. package/src/channels/feishu/feishu-cards.mjs +38 -0
  43. package/src/channels/feishu/feishu-channel.mjs +88 -20
  44. package/src/channels/shared/bot-workspace-store.mjs +11 -3
  45. package/src/channels/shared/command-catalog.mjs +102 -0
  46. package/src/channels/shared/i18n-en/feishu.mjs +12 -0
  47. package/src/channels/shared/i18n-en/shared-a.mjs +3 -0
  48. package/src/channels/shared/i18n-en/shared-c.mjs +9 -0
  49. package/src/channels/shared/i18n-en/wecom-app.mjs +33 -0
  50. package/src/channels/shared/i18n-en.mjs +2 -0
  51. package/src/channels/shared/model-setting.mjs +43 -8
  52. package/src/channels/shared/text-harness-bridge.mjs +2 -26
  53. package/src/channels/telegram/telegram-api.mjs +18 -6
  54. package/src/channels/telegram/telegram-runtime.mjs +34 -32
  55. package/src/channels/wecom/send-error.mjs +31 -0
  56. package/src/channels/wecom/wecom-bridge.mjs +59 -17
  57. package/src/channels/wecom-app/callback-server.mjs +471 -0
  58. package/src/channels/wecom-app/config-store.mjs +240 -0
  59. package/src/channels/wecom-app/harness-client.mjs +11 -0
  60. package/src/channels/wecom-app/state-store.mjs +107 -0
  61. package/src/channels/wecom-app/wecom-app-api.mjs +432 -0
  62. package/src/channels/wecom-app/wecom-app-bridge.mjs +1059 -0
  63. package/src/channels/wecom-app/wecom-app-controller.mjs +440 -0
  64. package/src/channels/wecom-app/wecom-app-runtime.mjs +221 -0
package/lib/client.js CHANGED
@@ -270,14 +270,14 @@ var require_semver = __commonJS({
270
270
  if (!m[4]) {
271
271
  this.prerelease = [];
272
272
  } else {
273
- this.prerelease = m[4].split(".").map((id5) => {
274
- if (/^[0-9]+$/.test(id5)) {
275
- const num = +id5;
273
+ this.prerelease = m[4].split(".").map((id6) => {
274
+ if (/^[0-9]+$/.test(id6)) {
275
+ const num = +id6;
276
276
  if (num >= 0 && num < MAX_SAFE_INTEGER) {
277
277
  return num;
278
278
  }
279
279
  }
280
- return id5;
280
+ return id6;
281
281
  });
282
282
  }
283
283
  this.build = m[5] ? m[5].split(".") : [];
@@ -566,13 +566,13 @@ __export(index_exports, {
566
566
  name: () => name
567
567
  });
568
568
  module.exports = __toCommonJS(index_exports);
569
- var React27 = __toESM(require("react"), 1);
569
+ var React28 = __toESM(require("react"), 1);
570
570
 
571
571
  // package.json
572
572
  var package_default = {
573
573
  name: "@xmanrui/dsh-im",
574
- version: "4.15.0",
575
- 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.",
574
+ version: "4.16.1",
575
+ description: "\u628A\u5341\u79CD IM \u673A\u5668\u4EBA\u548C\u516C\u7F51 AI Office \u63A5\u5165\u672C\u673A DeepSeek Harness\u3002 Connect ten IM channels and a public AI Office to a local DeepSeek Harness.",
576
576
  keywords: [
577
577
  "deepseek-harness",
578
578
  "dsh",
@@ -606,6 +606,14 @@ var package_default = {
606
606
  {
607
607
  name: "Chan-0312",
608
608
  url: "https://github.com/Chan-0312"
609
+ },
610
+ {
611
+ name: "BuvkB",
612
+ url: "https://github.com/BuvkB"
613
+ },
614
+ {
615
+ name: "masucc",
616
+ url: "https://github.com/masucc"
609
617
  }
610
618
  ],
611
619
  license: "MIT",
@@ -1075,6 +1083,7 @@ var EN = Object.freeze({
1075
1083
  "\u5F00\u542F\uFF08\u81EA\u52A8\u5F00\u542F\u72EC\u7ACB\u98DE\u4E66\u8BDD\u9898\uFF09": "On (auto-open a dedicated Feishu topic)",
1076
1084
  "\u5F00\u542F\u540E\uFF0C\u7FA4\u804A\u4E2D\u5411\u673A\u5668\u4EBA\u63D0\u95EE\u4F1A\u81EA\u52A8\u5F00\u542F\u72EC\u7ACB\u98DE\u4E66\u8BDD\u9898\uFF0C\u56DE\u590D\u843D\u5728\u8BDD\u9898\u5185\uFF1B\u6BCF\u4E2A\u8BDD\u9898\u662F dsh \u4F1A\u8BDD\u5217\u8868\u91CC\u4E00\u6761\u72EC\u7ACB\u4F1A\u8BDD\uFF0C\u4E0A\u4E0B\u6587\u4E92\u4E0D\u4E32\u3002\u79C1\u804A\u4E0D\u53D7\u5F71\u54CD\u3002": "When enabled, questions to the bot in a group auto-open a dedicated Feishu topic and replies stay inside it. Each topic is an independent conversation in dsh with its own context. Private chats are unaffected.",
1077
1085
  "\u5206\u6B65\u76F4\u63A8": "Step push",
1086
+ "\u67E5\u770B\u5206\u6B65\u76F4\u63A8\u8BF4\u660E": "View step push help",
1078
1087
  "\u5F00\u542F\u540E\u9010\u6B65\u63A8\u9001\u5DE5\u5177\u8C03\u7528\u4E0E\u8FC7\u7A0B\u8BF4\u660E": "Push tool calls and process notes step by step",
1079
1088
  "\u5173\u95ED\uFF08\u4FDD\u6301\u6D41\u5F0F\u5361\u6A21\u5F0F\uFF09": "Off (keep the streaming card)",
1080
1089
  "\u5F00\u542F\uFF08\u9010\u6B65\u63A8\u9001\u5DE5\u5177\u8C03\u7528\u4E0E\u8FC7\u7A0B\u8BF4\u660E\uFF09": "On (push tool calls and process notes step by step)",
@@ -1213,6 +1222,14 @@ var EN = Object.freeze({
1213
1222
  "Agent Preset \u65E0\u6548\u3002": "The Agent Preset is invalid.",
1214
1223
  "Agent Preset \u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u7528\u3002": "The Agent Preset does not exist or is unavailable.",
1215
1224
  "\u6A21\u578B": "Model",
1225
+ "\u6A21\u578B\u4E0E\u601D\u8003\u5F3A\u5EA6": "Model and reasoning effort",
1226
+ "\u601D\u8003\u5F3A\u5EA6": "Reasoning effort",
1227
+ "\u8DDF\u968F\u6A21\u578B\u9ED8\u8BA4": "Model default",
1228
+ "\u5148\u9009\u62E9\u6A21\u578B\uFF0C\u518D\u8BBE\u7F6E\u601D\u8003\u5F3A\u5EA6\u3002": "Select a model to configure its reasoning effort.",
1229
+ "\u8BE5\u6A21\u578B\u672A\u63D0\u4F9B\u53EF\u8C03\u8282\u7684\u601D\u8003\u5F3A\u5EA6\u3002": "This model does not provide adjustable reasoning effort.",
1230
+ "\u5DF2\u4FDD\u5B58\u7684\u601D\u8003\u5F3A\u5EA6\u5DF2\u4E0D\u53EF\u7528\uFF0C\u8BF7\u9009\u62E9\u5176\u4ED6\u5F3A\u5EA6\u6216\u6062\u590D\u9ED8\u8BA4\u3002": "The saved reasoning effort is unavailable. Choose another effort or restore the default.",
1231
+ "\u4F7F\u7528\u6A21\u578B\u6216\u670D\u52A1\u63D0\u4F9B\u65B9\u7684\u9ED8\u8BA4\u601D\u8003\u5F3A\u5EA6\u3002": "Use the default reasoning effort from the model or provider.",
1232
+ "\u5F53\u524D\u6A21\u578B\u4E0D\u652F\u6301\u6240\u9009\u601D\u8003\u5F3A\u5EA6\uFF0C\u8BF7\u91CD\u65B0\u9009\u62E9\u3002": "This model does not support the selected reasoning effort. Choose another effort.",
1216
1233
  "\u67E5\u770B\u6A21\u578B\u8BBE\u7F6E\u8BF4\u660E": "View model setting help",
1217
1234
  "\u8DDF\u968F\u9ED8\u8BA4\u6A21\u578B": "Follow the default model",
1218
1235
  "\u6A21\u578B\u4FEE\u6539\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002": "Could not update the model. Try again.",
@@ -1744,7 +1761,61 @@ var EN = Object.freeze({
1744
1761
  "\u786E\u8BA4\u6E05\u7406\u8FC7\u671F\u9644\u4EF6": "Confirm expired attachment cleanup",
1745
1762
  "\u786E\u8BA4\u6E05\u7406\u5F53\u524D\u5DF2\u8FC7\u671F\u7684\u9644\u4EF6\uFF1F": "Clean up the attachments that are currently expired?",
1746
1763
  "\u786E\u8BA4\u6E05\u7406": "Confirm cleanup",
1747
- "\u6B63\u5728\u6E05\u7406\u2026": "Cleaning up\u2026"
1764
+ "\u6B63\u5728\u6E05\u7406\u2026": "Cleaning up\u2026",
1765
+ "\u6B63\u5728\u8BFB\u53D6\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u72B6\u6001\u2026": "Loading WeCom app status\u2026",
1766
+ "\u6DFB\u52A0\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528": "Add WeCom app",
1767
+ "\u6536\u8D77\u8868\u5355": "Collapse form",
1768
+ "\u6DFB\u52A0\u4F01\u4E1A\u5FAE\u4FE1\u81EA\u5EFA\u5E94\u7528": "Add a WeCom self-built app",
1769
+ "\u6B63\u5728\u586B\u5199": "Filling in details",
1770
+ "\u5C1A\u672A\u7ED1\u5B9A\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528": "No WeCom app connected yet",
1771
+ "\u5728\u4F01\u4E1A\u5FAE\u4FE1\u4E2D\u521B\u5EFA\u81EA\u5EFA\u5E94\u7528\uFF0C\u5373\u53EF\u5728\u5FAE\u4FE1\u91CC\u4F7F\u7528": "Create a self-built app in WeCom to use it inside WeChat",
1772
+ "\u5728\u5E94\u7528\u7BA1\u7406\u540E\u53F0\u521B\u5EFA\u81EA\u5EFA\u5E94\u7528\uFF0C\u5F00\u542F\u300C\u63A5\u6536\u6D88\u606F\u300D\u5E76\u586B\u5165\u4E0B\u9762\u7684\u53C2\u6570\u3002\u6210\u5458\u7684\u5FAE\u4FE1\u5173\u6CE8\u8BE5\u4F01\u4E1A\u7684\u5FAE\u4FE1\u63D2\u4EF6\u540E\uFF0C\u5C31\u80FD\u5728\u5FAE\u4FE1\u4E2D\u4E0E\u672C\u5E94\u7528\u53CC\u5411\u5BF9\u8BDD\u3002": "Create the self-built app in the WeCom admin console, enable receive-messages, and fill in the parameters below. Once members follow the enterprise WeChat plugin, they can chat with this app directly inside WeChat.",
1773
+ "\u586B\u5199\u5E94\u7528\u53C2\u6570": "Fill in app parameters",
1774
+ "\u4F01\u4E1A ID\uFF08CorpID\uFF09": "Corp ID",
1775
+ "\u4F8B\u5982 ww1234567890abcdef": "for example ww1234567890abcdef",
1776
+ "\u5E94\u7528 AgentId": "AgentId",
1777
+ "\u4F8B\u5982 1000002": "for example 1000002",
1778
+ "\u5E94\u7528 Secret": "App Secret",
1779
+ "\u5E94\u7528\u8BE6\u60C5\u9875\u7684 Secret": "The Secret from the app details page",
1780
+ "\u56DE\u8C03 Token": "Callback Token",
1781
+ "\u63A5\u6536\u6D88\u606F \u2192 API \u63A5\u6536\u4E2D\u7684 Token": "The Token from Receive messages \u2192 API receive",
1782
+ "43 \u4F4D\u5B57\u6BCD\u6216\u6570\u5B57": "43 alphanumeric characters",
1783
+ "\u4EE3\u7406\u5730\u5740\uFF08\u53EF\u9009\uFF09": "API proxy (optional)",
1784
+ "\u7559\u7A7A\u76F4\u8FDE qyapi.weixin.qq.com": "leave empty to reach qyapi.weixin.qq.com directly",
1785
+ "\u516C\u7F51\u56DE\u8C03\u57FA\u5740\uFF08\u53EF\u9009\uFF09": "Public callback base URL (optional)",
1786
+ "\u4F8B\u5982 https://im.example.com": "for example https://im.example.com",
1787
+ "\u6D41\u5F0F\u56DE\u590D\uFF1A\u5F00": "Streaming replies: on",
1788
+ "\u6D41\u5F0F\u56DE\u590D\uFF1A\u5173": "Streaming replies: off",
1789
+ "\u4F01\u4E1A\u5FAE\u4FE1\u5BA2\u6237\u7AEF\u5B9E\u65F6\u51FA\u5B57\uFF1B\u5FAE\u4FE1\u7AEF\u4E0D\u652F\u6301\u65F6\u81EA\u52A8\u6539\u4E3A\u6574\u6BB5\u53D1\u9001": "Streams replies in the WeCom client; falls back to segmented text messages when the WeChat side does not support it",
1790
+ "\u7ED1\u5B9A\u4F01\u4E1A\u5FAE\u4FE1\u81EA\u5EFA\u5E94\u7528": "Bind a WeCom self-built app",
1791
+ "\u56DE\u8C03 URL\uFF08\u586B\u5165\u4F01\u4E1A\u5FAE\u4FE1\u540E\u53F0\u300C\u63A5\u6536\u6D88\u606F \u2192 \u8BBE\u7F6EAPI\u63A5\u6536\u300D\uFF09": "Callback URL (paste into the WeCom console under Receive messages \u2192 API receive)",
1792
+ "\u672A\u914D\u7F6E\u516C\u7F51\u56DE\u8C03\u57FA\u5740\uFF1A\u8BF7\u5728\u672C\u9875\u300C\u8BBE\u7F6E\u300D\u4E2D\u586B\u5199\u56DE\u8C03\u57FA\u5740\uFF0C\u6216\u624B\u52A8\u62FC\u63A5 \u56DE\u8C03\u57FA\u5740 + \u8DEF\u5F84": "No public callback base URL configured: fill it in under Settings on this page, or manually combine the base URL and the path",
1793
+ "\u91CD\u7F6E\u5BC6\u94A5": "Reset secret",
1794
+ "\u91CD\u7F6E\u4E2D\u2026": "Resetting\u2026",
1795
+ "\u91CD\u7F6E\u5BC6\u94A5\u540E\u56DE\u8C03 URL \u4F1A\u53D8\u5316\uFF0C\u9700\u8981\u540C\u6B65\u66F4\u65B0\u4F01\u4E1A\u5FAE\u4FE1\u540E\u53F0\u3002\u82E5\u516C\u7F51\u53CD\u4EE3\u672A\u5C31\u7EEA\uFF0C\u53EF\u4E34\u65F6\u4F7F\u7528 http://\u670D\u52A1\u5668IP:\u7AEF\u53E3 \u5F62\u5F0F\u7684\u56DE\u8C03\u5730\u5740\u3002": "Resetting the secret changes the callback URL; update the WeCom console accordingly. If the public reverse proxy is not ready yet, a http://server-ip:port callback address works temporarily.",
1796
+ "\u4FDD\u5B58\u8BBE\u7F6E": "Save settings",
1797
+ "\u8FD9\u4F1A\u5220\u9664\u672C\u673A\u4FDD\u5B58\u7684\u5E94\u7528\u51ED\u636E\u3001\u56DE\u8C03\u914D\u7F6E\u53CA\u4F1A\u8BDD\u6620\u5C04\u3002\u4F01\u4E1A\u5FAE\u4FE1\u540E\u53F0\u7684\u5E94\u7528\u4E0D\u4F1A\u88AB\u5220\u9664\u3002": "This removes the locally stored app credentials, callback configuration, and session mappings. The app in the WeCom console is not deleted.",
1798
+ "\u4FDD\u7559\u5E94\u7528": "Keep app",
1799
+ "\u5DF2\u7ED1\u5B9A\u7684\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528": "Connected WeCom apps",
1800
+ "HTTP \u56DE\u8C03\u901A\u9053": "HTTP callback channel",
1801
+ "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528": "WeCom app",
1802
+ "\u4F01\u4E1A ID \u5DF2\u4FDD\u5B58": "Corp ID saved securely",
1803
+ "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u56DE\u8C03\u901A\u9053\u5C31\u7EEA": "WeCom app callback channel is ready",
1804
+ "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA": "WeCom app connection is not ready",
1805
+ "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u4ECD\u672A\u5C31\u7EEA\uFF0C\u63D2\u4EF6\u4F1A\u7EE7\u7EED\u81EA\u52A8\u91CD\u8BD5\u3002": "The WeCom app is still not ready; the plugin keeps retrying automatically.",
1806
+ "\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\u3002": "Connection check finished.",
1807
+ "\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\u3002": "Connection check finished; the test message was sent.",
1808
+ "\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\u3002\u5E94\u7528\u5C1A\u672A\u6536\u5230\u53EF\u7528\u4E8E\u6D4B\u8BD5\u7684\u79C1\u804A\u6D88\u606F\u3002": "Connection check finished. The app has not received a private chat usable for testing yet.",
1809
+ "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u5DF2\u7ED1\u5B9A\u3002\u8BF7\u628A\u56DE\u8C03 URL \u586B\u5165\u4F01\u4E1A\u5FAE\u4FE1\u540E\u53F0\u5E76\u4FDD\u5B58\u3002": "The WeCom app is bound. Paste the callback URL into the WeCom console and save.",
1810
+ "\u56DE\u8C03\u5BC6\u94A5\u5DF2\u91CD\u7F6E\uFF0C\u8BF7\u628A\u65B0\u7684\u56DE\u8C03 URL \u66F4\u65B0\u5230\u4F01\u4E1A\u5FAE\u4FE1\u540E\u53F0\u3002": "The callback secret was reset; update the new callback URL in the WeCom console.",
1811
+ "\u56DE\u8C03\u5BC6\u94A5\u91CD\u7F6E\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002": "The callback secret reset failed; try again later.",
1812
+ "\u65E0\u6CD5\u8BFB\u53D6\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u72B6\u6001": "Could not load WeCom app status",
1813
+ "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u8BBE\u7F6E": "WeCom app settings",
1814
+ "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5": "The WeCom app settings page is missing the RPC connection",
1815
+ "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u64CD\u4F5C\u5931\u8D25": "The WeCom app operation failed",
1816
+ "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5": "The WeCom app operation failed; try again later",
1817
+ "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94": "The WeCom app service returned an unrecognized response",
1818
+ "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u673A\u5668\u4EBA\u5217\u8868": "The WeCom app service did not return a valid bot list"
1748
1819
  });
1749
1820
  var en = EN;
1750
1821
  var zh = Object.freeze(Object.fromEntries(
@@ -1760,78 +1831,78 @@ function isEnglish() {
1760
1831
  function channelName(value) {
1761
1832
  return localizeText(value);
1762
1833
  }
1763
- function translateDynamic(text6) {
1764
- const guidanceLimit = /^增强提示词不得超过 (\d+) 个字符。$/.exec(text6);
1834
+ function translateDynamic(text7) {
1835
+ const guidanceLimit = /^增强提示词不得超过 (\d+) 个字符。$/.exec(text7);
1765
1836
  if (guidanceLimit) return `Guidance must not exceed ${guidanceLimit[1]} characters.`;
1766
- let match = /^(\d+) \/ (\d+) 在线$/.exec(text6);
1837
+ let match = /^(\d+) \/ (\d+) 在线$/.exec(text7);
1767
1838
  if (match) return `${match[1]}/${match[2]} online`;
1768
- match = /^已接入 (\d+) 个机器人,其中 (\d+) 个在线$/.exec(text6);
1839
+ match = /^已接入 (\d+) 个机器人,其中 (\d+) 个在线$/.exec(text7);
1769
1840
  if (match) return `${match[2]} of ${match[1]} bots online`;
1770
- match = /^请输入 -1、0 或 1~(\d+) 之间的整数。$/.exec(text6);
1841
+ match = /^请输入 -1、0 或 1~(\d+) 之间的整数。$/.exec(text7);
1771
1842
  if (match) return `Enter -1, 0, or an integer from 1 to ${match[1]}.`;
1772
- match = /^正在读取\s*(.+?)\s*机器人状态…$/.exec(text6);
1843
+ match = /^正在读取\s*(.+?)\s*机器人状态…$/.exec(text7);
1773
1844
  if (match) return `Loading ${channelName(match[1])} bot status\u2026`;
1774
- match = /^无法读取\s*(.+?)\s*机器人状态$/.exec(text6);
1845
+ match = /^无法读取\s*(.+?)\s*机器人状态$/.exec(text7);
1775
1846
  if (match) return `Could not load ${channelName(match[1])} bot status`;
1776
- match = /^尚未接入\s*(.+?)\s*机器人$/.exec(text6);
1847
+ match = /^尚未接入\s*(.+?)\s*机器人$/.exec(text7);
1777
1848
  if (match) return `No ${channelName(match[1])} bot connected yet`;
1778
- match = /^已接入的\s*(.+?)\s*机器人$/.exec(text6);
1849
+ match = /^已接入的\s*(.+?)\s*机器人$/.exec(text7);
1779
1850
  if (match) return `Connected ${channelName(match[1])} bots`;
1780
- match = /^手动接入(.+)机器人$/.exec(text6);
1851
+ match = /^手动接入(.+)机器人$/.exec(text7);
1781
1852
  if (match) return `Connect ${channelName(match[1])} bot manually`;
1782
- match = /^(.+) 设置$/.exec(text6);
1853
+ match = /^(.+) 设置$/.exec(text7);
1783
1854
  if (match) return `${channelName(match[1])} settings`;
1784
- match = /^从 DeepSeek Harness 移除“(.+)”?$/.exec(text6);
1855
+ match = /^从 DeepSeek Harness 移除“(.+)”?$/.exec(text7);
1785
1856
  if (match) return `Remove \u201C${match[1]}\u201D from DeepSeek Harness?`;
1786
- match = /^从 DeepSeek Harness 移除(.+)$/.exec(text6);
1857
+ match = /^从 DeepSeek Harness 移除(.+)$/.exec(text7);
1787
1858
  if (match) return `Remove ${match[1]} from DeepSeek Harness`;
1788
- match = /^(.+)的飞书授权流程$/.exec(text6);
1859
+ match = /^(.+)的飞书授权流程$/.exec(text7);
1789
1860
  if (match) return `Feishu authorization flow for ${match[1]}`;
1790
- match = /^用于为(.+)补全权限与回调的一次性授权二维码$/.exec(text6);
1861
+ match = /^用于为(.+)补全权限与回调的一次性授权二维码$/.exec(text7);
1791
1862
  if (match) return `One-time QR code for completing permissions and the callback for ${match[1]}`;
1792
- match = /^用于为(.+)开通群消息权限的一次性授权二维码$/.exec(text6);
1863
+ match = /^用于为(.+)开通群消息权限的一次性授权二维码$/.exec(text7);
1793
1864
  if (match) return `One-time QR code for granting group-message permission to ${match[1]}`;
1794
- match = /^正在为「(.+)」补全权限与回调$/.exec(text6);
1865
+ match = /^正在为「(.+)」补全权限与回调$/.exec(text7);
1795
1866
  if (match) return `Completing permissions and the callback for \u201C${match[1]}\u201D`;
1796
- match = /^正在为「(.+)」开通群消息权限$/.exec(text6);
1867
+ match = /^正在为「(.+)」开通群消息权限$/.exec(text7);
1797
1868
  if (match) return `Granting group-message permission to \u201C${match[1]}\u201D`;
1798
- match = /^为(.+)补全权限与回调$/.exec(text6);
1869
+ match = /^为(.+)补全权限与回调$/.exec(text7);
1799
1870
  if (match) return `Complete permissions and the callback for ${match[1]}`;
1800
- match = /^(.+)的权限补全二维码已生成,请使用飞书扫码。$/.exec(text6);
1871
+ match = /^(.+)的权限补全二维码已生成,请使用飞书扫码。$/.exec(text7);
1801
1872
  if (match) return `Permission-completion QR code generated for ${match[1]}. Scan it with Feishu.`;
1802
- match = /^(.+)的群消息权限二维码已生成,请使用飞书确认。$/.exec(text6);
1873
+ match = /^(.+)的群消息权限二维码已生成,请使用飞书确认。$/.exec(text7);
1803
1874
  if (match) return `Group-message permission QR code generated for ${match[1]}. Confirm it with Feishu.`;
1804
- match = /^(.+)的权限与回调已补全。$/.exec(text6);
1875
+ match = /^(.+)的权限与回调已补全。$/.exec(text7);
1805
1876
  if (match) return `Permissions and the callback completed for ${match[1]}.`;
1806
- match = /^(.+)已开通群消息权限,并启用“响应所有群消息”。$/.exec(text6);
1877
+ match = /^(.+)已开通群消息权限,并启用“响应所有群消息”。$/.exec(text7);
1807
1878
  if (match) return `${match[1]} now has group-message permission and \u201CRespond to all group messages\u201D is enabled.`;
1808
- match = /^(检查连接|重试连接)(.+)$/.exec(text6);
1879
+ match = /^(检查连接|重试连接)(.+)$/.exec(text7);
1809
1880
  if (match) return `${localizeText(match[1])} ${match[2]}`;
1810
- match = /^移除(.+)$/.exec(text6);
1881
+ match = /^移除(.+)$/.exec(text7);
1811
1882
  if (match) return `Remove ${match[1]}`;
1812
- match = /^这会停止消息连接,并删除本机保存的 (.+)、机器人配置及会话映射。(.+)中的机器人不会被自动删除。$/.exec(text6);
1883
+ match = /^这会停止消息连接,并删除本机保存的 (.+)、机器人配置及会话映射。(.+)中的机器人不会被自动删除。$/.exec(text7);
1813
1884
  if (match) {
1814
1885
  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.`;
1815
1886
  }
1816
- match = /^二维码剩余 (.+)$/.exec(text6);
1887
+ match = /^二维码剩余 (.+)$/.exec(text7);
1817
1888
  if (match) return `QR code expires in ${match[1]}`;
1818
- match = /^最近一条消息处理失败:(.+)$/.exec(text6);
1889
+ match = /^最近一条消息处理失败:(.+)$/.exec(text7);
1819
1890
  if (match) return `Latest message failed: ${localizeText(match[1])}`;
1820
- match = /^图片下载失败(HTTP (.+)),请重新发送后再试。$/.exec(text6);
1891
+ match = /^图片下载失败(HTTP (.+)),请重新发送后再试。$/.exec(text7);
1821
1892
  if (match) return `The image download failed (HTTP ${match[1]}). Send it again.`;
1822
- match = /^一次最多只能处理 (\d+) 张图片。$/.exec(text6);
1893
+ match = /^一次最多只能处理 (\d+) 张图片。$/.exec(text7);
1823
1894
  if (match) return `A message can contain at most ${match[1]} images.`;
1824
- match = /^状态刷新失败:(.+)$/.exec(text6);
1895
+ match = /^状态刷新失败:(.+)$/.exec(text7);
1825
1896
  if (match) return `Status refresh failed: ${match[1]}`;
1826
- match = /^状态自动刷新失败:(.+)$/.exec(text6);
1897
+ match = /^状态自动刷新失败:(.+)$/.exec(text7);
1827
1898
  if (match) return `Automatic status refresh failed: ${match[1]}`;
1828
- match = /^操作失败:(.+)$/.exec(text6);
1899
+ match = /^操作失败:(.+)$/.exec(text7);
1829
1900
  if (match) return `Operation failed: ${match[1]}`;
1830
- match = /^连接检查失败:(.+)(参考号:(.+))$/.exec(text6);
1901
+ match = /^连接检查失败:(.+)(参考号:(.+))$/.exec(text7);
1831
1902
  if (match) return `Connection check failed: ${localizeText(match[1])} (reference: ${match[2]})`;
1832
- match = /^连接检查失败:(.+)$/.exec(text6);
1903
+ match = /^连接检查失败:(.+)$/.exec(text7);
1833
1904
  if (match) return `Connection check failed: ${match[1]}`;
1834
- match = /^移除失败:(.+)$/.exec(text6);
1905
+ match = /^移除失败:(.+)$/.exec(text7);
1835
1906
  if (match) return `Removal failed: ${match[1]}`;
1836
1907
  const phrases = [
1837
1908
  ["\u4F01\u4E1A\u5FAE\u4FE1", "WeCom"],
@@ -1868,7 +1939,7 @@ function translateDynamic(text6) {
1868
1939
  ["\u8FDE\u63A5\u72B6\u6001", "connection status"],
1869
1940
  ["\u4E8C\u7EF4\u7801", "QR code"]
1870
1941
  ];
1871
- let output = text6;
1942
+ let output = text7;
1872
1943
  for (const [source, target] of phrases) output = output.replaceAll(source, target);
1873
1944
  return output;
1874
1945
  }
@@ -1912,8 +1983,8 @@ var EMPTY_AGENT_PRESET_CATALOG = Object.freeze({
1912
1983
  var AgentPresetCatalogContext = React3.createContext(EMPTY_AGENT_PRESET_CATALOG);
1913
1984
  function normalizeAgentPresetId(value) {
1914
1985
  if (typeof value !== "string") return "";
1915
- const id5 = value.trim();
1916
- return PRESET_ID.test(id5) ? id5 : "";
1986
+ const id6 = value.trim();
1987
+ return PRESET_ID.test(id6) ? id6 : "";
1917
1988
  }
1918
1989
  function normalizeAgentPresetCatalog(value) {
1919
1990
  if (!value || typeof value !== "object" || Array.isArray(value)) {
@@ -1922,11 +1993,11 @@ function normalizeAgentPresetCatalog(value) {
1922
1993
  const items = [];
1923
1994
  const seen = /* @__PURE__ */ new Set();
1924
1995
  for (const entry of Array.isArray(value.items) ? value.items : []) {
1925
- const id5 = typeof entry === "string" ? normalizeAgentPresetId(entry) : normalizeAgentPresetId(entry?.id);
1926
- if (!id5 || seen.has(id5)) continue;
1927
- seen.add(id5);
1928
- const label = typeof entry?.label === "string" && entry.label.trim() ? entry.label.trim().slice(0, 128) : typeof entry?.name === "string" && entry.name.trim() ? entry.name.trim().slice(0, 128) : id5;
1929
- items.push({ id: id5, label });
1996
+ const id6 = typeof entry === "string" ? normalizeAgentPresetId(entry) : normalizeAgentPresetId(entry?.id);
1997
+ if (!id6 || seen.has(id6)) continue;
1998
+ seen.add(id6);
1999
+ const label = typeof entry?.label === "string" && entry.label.trim() ? entry.label.trim().slice(0, 128) : typeof entry?.name === "string" && entry.name.trim() ? entry.name.trim().slice(0, 128) : id6;
2000
+ items.push({ id: id6, label });
1930
2001
  }
1931
2002
  return {
1932
2003
  defaultId: normalizeAgentPresetId(value.defaultId),
@@ -2022,14 +2093,15 @@ var React4 = __toESM(require("react"), 1);
2022
2093
  // src/channels/shared/model-setting.mjs
2023
2094
  var MAX_PROVIDER_ID_LENGTH = 256;
2024
2095
  var MAX_MODEL_ID_LENGTH = 1024;
2096
+ var MAX_EFFORT_ID_LENGTH = 256;
2025
2097
  var MAX_LABEL_LENGTH = 256;
2026
2098
  var UNSAFE_DISPLAY_TEXT = /[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]+/gu;
2027
2099
  var UNSAFE_ID_TEXT = /[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/u;
2028
2100
  function cleanId(value, maxLength) {
2029
2101
  if (typeof value !== "string") return "";
2030
- const id5 = value.trim();
2031
- if (!id5 || id5.length > maxLength || UNSAFE_ID_TEXT.test(id5)) return "";
2032
- return id5;
2102
+ const id6 = value.trim();
2103
+ if (!id6 || id6.length > maxLength || UNSAFE_ID_TEXT.test(id6)) return "";
2104
+ return id6;
2033
2105
  }
2034
2106
  function cleanLabel(value, fallback) {
2035
2107
  if (typeof value !== "string") return fallback;
@@ -2045,7 +2117,27 @@ function normalizeModelSelection(value) {
2045
2117
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
2046
2118
  const provider = cleanId(value.provider, MAX_PROVIDER_ID_LENGTH);
2047
2119
  const model = cleanId(value.model, MAX_MODEL_ID_LENGTH);
2048
- return provider && model ? { provider, model } : null;
2120
+ const reasoningEffort = value.reasoningEffort === void 0 ? void 0 : cleanId(value.reasoningEffort, MAX_EFFORT_ID_LENGTH);
2121
+ if (!provider || !model || reasoningEffort === "") return null;
2122
+ return { provider, model, ...reasoningEffort === void 0 ? {} : { reasoningEffort } };
2123
+ }
2124
+ function sameModelSelection(left, right) {
2125
+ return left?.provider === right?.provider && left?.model === right?.model && left?.reasoningEffort === right?.reasoningEffort;
2126
+ }
2127
+ function normalizeReasoning(value) {
2128
+ if (!value || typeof value !== "object" || !Array.isArray(value.efforts)) return void 0;
2129
+ const efforts = [];
2130
+ const seen = /* @__PURE__ */ new Set();
2131
+ for (const entry of value.efforts) {
2132
+ const id6 = cleanId(entry?.id, MAX_EFFORT_ID_LENGTH);
2133
+ if (!id6 || seen.has(id6)) continue;
2134
+ seen.add(id6);
2135
+ const description = cleanLabel(entry.description, "");
2136
+ efforts.push({ id: id6, name: cleanLabel(entry.name, id6), ...description ? { description } : {} });
2137
+ }
2138
+ if (!efforts.length) return void 0;
2139
+ const defaultEffort = cleanId(value.defaultEffort, MAX_EFFORT_ID_LENGTH);
2140
+ return { efforts, ...seen.has(defaultEffort) ? { defaultEffort } : {} };
2049
2141
  }
2050
2142
  function modelSelectionId(value) {
2051
2143
  const selection = normalizeModelSelection(value);
@@ -2069,9 +2161,13 @@ function normalizeModelCatalog(value) {
2069
2161
  const key = `${provider}\0${model}`;
2070
2162
  if (seen.has(key)) continue;
2071
2163
  seen.add(key);
2164
+ const description = cleanLabel(entry.description, "");
2165
+ const reasoning = normalizeReasoning(entry.reasoning);
2072
2166
  models.push({
2073
2167
  id: model,
2074
- name: cleanLabel(entry.name, model)
2168
+ name: cleanLabel(entry.name, model),
2169
+ ...description ? { description } : {},
2170
+ ...reasoning ? { reasoning } : {}
2075
2171
  });
2076
2172
  }
2077
2173
  if (models.length > 0) {
@@ -2085,109 +2181,244 @@ function normalizeModelCatalog(value) {
2085
2181
  const failures = [];
2086
2182
  for (const candidate of Array.isArray(value.failures) ? value.failures : []) {
2087
2183
  if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) continue;
2088
- const id5 = cleanId(candidate.id, MAX_PROVIDER_ID_LENGTH);
2089
- if (!id5) continue;
2090
- failures.push({ id: id5, name: cleanLabel(candidate.name, id5) });
2184
+ const id6 = cleanId(candidate.id, MAX_PROVIDER_ID_LENGTH);
2185
+ if (!id6) continue;
2186
+ failures.push({ id: id6, name: cleanLabel(candidate.name, id6) });
2091
2187
  }
2092
2188
  return { groups, failures };
2093
2189
  }
2190
+ function modelCatalogEntry(catalog, selection) {
2191
+ const normalized = normalizeModelSelection(selection);
2192
+ if (!normalized) return void 0;
2193
+ return normalizeModelCatalog(catalog).groups.filter((group) => group.id === normalized.provider).flatMap((group) => group.models).find((model) => model.id === normalized.model);
2194
+ }
2094
2195
 
2095
2196
  // plugin-src/client/model-setting.js
2096
2197
  var SET_MODEL_ENDPOINT = "bot.model.set";
2097
2198
  var ModelCatalogContext = React4.createContext(EMPTY_MODEL_CATALOG);
2098
- function optionValue(selection) {
2099
- return JSON.stringify([selection.provider, selection.model]);
2199
+ function chevron(open = false) {
2200
+ return h2(
2201
+ "svg",
2202
+ {
2203
+ width: 14,
2204
+ height: 14,
2205
+ viewBox: "0 0 16 16",
2206
+ "aria-hidden": true,
2207
+ className: "dim-modelChevron",
2208
+ style: open ? { transform: "rotate(90deg)" } : void 0
2209
+ },
2210
+ h2("path", { d: "m6 4 4 4-4 4", fill: "none", stroke: "currentColor", strokeWidth: 1.5 })
2211
+ );
2100
2212
  }
2101
2213
  function ModelEditor({ model = null, disabled = false, onSave }) {
2102
- const catalog = normalizeModelCatalog(
2103
- React4.useContext(ModelCatalogContext) ?? EMPTY_MODEL_CATALOG
2104
- );
2105
- const helpId = React4.useId();
2106
- const current = normalizeModelSelection(model);
2214
+ const catalog = normalizeModelCatalog(React4.useContext(ModelCatalogContext));
2215
+ const id6 = React4.useId();
2216
+ const rootRef = React4.useRef(null);
2217
+ const menuRef = React4.useRef(null);
2218
+ const triggerRef = React4.useRef(null);
2219
+ const restoreFocusRef = React4.useRef(false);
2220
+ const savingRef = React4.useRef(false);
2221
+ const [pane, setPane] = React4.useState(null);
2107
2222
  const [saving, setSaving] = React4.useState(false);
2108
2223
  const [error, setError] = React4.useState(null);
2109
- const currentValue = current ? optionValue(current) : "";
2110
- const currentAvailable = !current || catalog.groups.some(
2111
- (group) => group.id === current.provider && group.models.some((entry) => entry.id === current.model)
2112
- );
2113
- const selections = /* @__PURE__ */ new Map();
2114
- for (const group of catalog.groups) {
2115
- for (const entry of group.models) {
2116
- const selection = { provider: group.id, model: entry.id };
2117
- selections.set(optionValue(selection), selection);
2224
+ const current = normalizeModelSelection(model);
2225
+ const entry = modelCatalogEntry(catalog, current);
2226
+ const currentAvailable = !current || Boolean(entry);
2227
+ const reasoning = entry?.reasoning;
2228
+ const effort = current?.reasoningEffort;
2229
+ const effectiveEffort = effort ?? reasoning?.defaultEffort;
2230
+ const effortEntry = reasoning?.efforts.find((level) => level.id === effectiveEffort);
2231
+ const effortUnavailable = effort !== void 0 && !reasoning?.efforts.some((level) => level.id === effort);
2232
+ const defaultName = reasoning?.efforts.find((level) => level.id === reasoning.defaultEffort)?.name;
2233
+ const defaultLabel = localizeText("\u8DDF\u968F\u6A21\u578B\u9ED8\u8BA4") + (defaultName ? ` \xB7 ${defaultName}` : "");
2234
+ const effortLabel = !current ? localizeText("\u8DDF\u968F\u9ED8\u8BA4\u6A21\u578B") : effort === void 0 ? defaultLabel : effortEntry?.name ?? effort;
2235
+ const effortHint = !current ? "\u5148\u9009\u62E9\u6A21\u578B\uFF0C\u518D\u8BBE\u7F6E\u601D\u8003\u5F3A\u5EA6\u3002" : !currentAvailable ? null : effortUnavailable ? "\u5DF2\u4FDD\u5B58\u7684\u601D\u8003\u5F3A\u5EA6\u5DF2\u4E0D\u53EF\u7528\uFF0C\u8BF7\u9009\u62E9\u5176\u4ED6\u5F3A\u5EA6\u6216\u6062\u590D\u9ED8\u8BA4\u3002" : !reasoning ? "\u8BE5\u6A21\u578B\u672A\u63D0\u4F9B\u53EF\u8C03\u8282\u7684\u601D\u8003\u5F3A\u5EA6\u3002" : null;
2236
+ const effortDisabled = !current || !currentAvailable || !reasoning && effort === void 0;
2237
+ const close = (restoreFocus = false) => {
2238
+ restoreFocusRef.current = restoreFocus;
2239
+ setPane(null);
2240
+ };
2241
+ React4.useEffect(() => {
2242
+ if (!pane && !saving && !disabled && restoreFocusRef.current) {
2243
+ restoreFocusRef.current = false;
2244
+ triggerRef.current?.focus();
2118
2245
  }
2119
- }
2120
- if (current && !currentAvailable) selections.set(currentValue, current);
2121
- const change = async (event) => {
2122
- const nextValue = event.target.value;
2123
- if (nextValue === currentValue || saving || disabled) return;
2124
- const next = nextValue ? selections.get(nextValue) : null;
2125
- if (nextValue && !next) return;
2246
+ }, [pane, saving, disabled]);
2247
+ React4.useEffect(() => {
2248
+ if (!pane) return void 0;
2249
+ const options = menuRef.current?.querySelectorAll('[role="menuitemradio"]');
2250
+ const selected = menuRef.current?.querySelector('[aria-checked="true"]');
2251
+ (selected ?? options?.[0])?.focus();
2252
+ const outside = (event) => {
2253
+ if (!rootRef.current?.contains(event.target)) setPane(null);
2254
+ };
2255
+ globalThis.document?.addEventListener("mousedown", outside);
2256
+ return () => globalThis.document?.removeEventListener("mousedown", outside);
2257
+ }, [pane]);
2258
+ const save = async (next) => {
2259
+ if (savingRef.current || disabled) return;
2260
+ if (sameModelSelection(current, next)) {
2261
+ close(true);
2262
+ return;
2263
+ }
2264
+ savingRef.current = true;
2126
2265
  setSaving(true);
2127
2266
  setError(null);
2128
2267
  try {
2129
2268
  await onSave?.(next);
2269
+ close(true);
2130
2270
  } catch (cause) {
2131
2271
  setError(cause?.message ?? "\u6A21\u578B\u4FEE\u6539\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002");
2132
2272
  } finally {
2273
+ savingRef.current = false;
2133
2274
  setSaving(false);
2134
2275
  }
2135
2276
  };
2277
+ const option = (key, label, description, selected, next) => h2(
2278
+ "button",
2279
+ {
2280
+ key,
2281
+ type: "button",
2282
+ role: "menuitemradio",
2283
+ "aria-checked": selected,
2284
+ className: "dim-modelOption",
2285
+ disabled: disabled || saving,
2286
+ onClick: () => {
2287
+ void save(next);
2288
+ }
2289
+ },
2290
+ h2(
2291
+ "span",
2292
+ { className: "dim-modelOptionCopy" },
2293
+ h2("span", { className: "dim-modelOptionName" }, label),
2294
+ description ? h2("span", { className: "dim-modelDescription" }, description) : null
2295
+ ),
2296
+ h2("span", { className: "dim-modelCheck", "aria-hidden": true }, selected ? "\u2713" : "")
2297
+ );
2298
+ const row = (key, label, value, blocked = false) => h2(
2299
+ "button",
2300
+ {
2301
+ type: "button",
2302
+ className: "dim-modelRow",
2303
+ disabled: disabled || saving || blocked,
2304
+ "aria-label": label,
2305
+ "aria-haspopup": "menu",
2306
+ "aria-expanded": pane === key,
2307
+ "aria-controls": pane === key ? `${id6}-menu` : void 0,
2308
+ "aria-describedby": key === "effort" && effortHint ? `${id6}-hint` : void 0,
2309
+ onClick: (event) => {
2310
+ triggerRef.current = event.currentTarget;
2311
+ setPane(pane === key ? null : key);
2312
+ }
2313
+ },
2314
+ h2("span", { className: "dim-modelRowLabel" }, label),
2315
+ h2("span", { className: "dim-modelValue", title: value }, value),
2316
+ chevron(pane === key)
2317
+ );
2136
2318
  return h2(
2137
2319
  "div",
2138
- { className: "dim-preset dim-modelSetting" },
2320
+ {
2321
+ ref: rootRef,
2322
+ className: "dim-preset dim-modelSetting",
2323
+ onBlur: (event) => {
2324
+ if (event.relatedTarget && !event.currentTarget.contains(event.relatedTarget)) close();
2325
+ },
2326
+ onKeyDown: (event) => {
2327
+ if (!pane) return;
2328
+ if (event.key === "Escape") {
2329
+ event.preventDefault();
2330
+ event.stopPropagation();
2331
+ close(true);
2332
+ }
2333
+ if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) return;
2334
+ const items = [...menuRef.current?.querySelectorAll('[role="menuitemradio"]:not(:disabled)') ?? []];
2335
+ if (!items.length) return;
2336
+ event.preventDefault();
2337
+ const at = items.indexOf(globalThis.document?.activeElement);
2338
+ const next = event.key === "Home" ? 0 : event.key === "End" ? items.length - 1 : (at + (event.key === "ArrowDown" ? 1 : -1) + items.length) % items.length;
2339
+ items[next]?.focus();
2340
+ }
2341
+ },
2139
2342
  h2(
2140
2343
  "div",
2141
2344
  { className: "dim-presetHeader" },
2142
2345
  h2(
2143
2346
  "span",
2144
2347
  { className: "dim-presetTitle" },
2145
- h2("span", null, "\u6A21\u578B"),
2348
+ "\u6A21\u578B\u4E0E\u601D\u8003\u5F3A\u5EA6",
2146
2349
  h2(
2147
2350
  "span",
2148
2351
  { className: "dim-presetHelp" },
2149
- h2("button", {
2150
- type: "button",
2151
- className: "dim-presetHelpButton",
2152
- "aria-label": "\u67E5\u770B\u6A21\u578B\u8BBE\u7F6E\u8BF4\u660E",
2153
- "aria-describedby": helpId
2154
- }, h2("span", { "aria-hidden": "true" }, "?")),
2155
- h2("span", {
2156
- id: helpId,
2157
- className: "dim-presetTooltip",
2158
- role: "tooltip"
2159
- }, "\u53EA\u5F71\u54CD\u65B0\u5EFA\u4F1A\u8BDD\uFF1B\u82E5\u5F53\u524D\u804A\u5929\u5DF2\u6709\u4F1A\u8BDD\uFF0C\u5148\u53D1\u9001 /new\uFF0C\u518D\u53D1\u9001\u666E\u901A\u6D88\u606F\u751F\u6548\u3002")
2352
+ h2(
2353
+ "button",
2354
+ {
2355
+ type: "button",
2356
+ className: "dim-presetHelpButton",
2357
+ "aria-label": "\u67E5\u770B\u6A21\u578B\u8BBE\u7F6E\u8BF4\u660E",
2358
+ "aria-describedby": `${id6}-help`
2359
+ },
2360
+ h2("span", { "aria-hidden": true }, "?")
2361
+ ),
2362
+ h2(
2363
+ "span",
2364
+ { id: `${id6}-help`, className: "dim-presetTooltip", role: "tooltip" },
2365
+ "\u53EA\u5F71\u54CD\u65B0\u5EFA\u4F1A\u8BDD\uFF1B\u82E5\u5F53\u524D\u804A\u5929\u5DF2\u6709\u4F1A\u8BDD\uFF0C\u5148\u53D1\u9001 /new\uFF0C\u518D\u53D1\u9001\u666E\u901A\u6D88\u606F\u751F\u6548\u3002"
2366
+ )
2160
2367
  )
2161
2368
  ),
2162
- saving ? h2("span", { className: "dim-presetStatus" }, "\u4FDD\u5B58\u4E2D\u2026") : null
2369
+ saving ? h2("span", { className: "dim-presetStatus", role: "status" }, "\u4FDD\u5B58\u4E2D\u2026") : null
2163
2370
  ),
2164
- h2(
2165
- "select",
2371
+ row("model", "\u6A21\u578B", entry?.name ?? (current ? modelSelectionId(current) : localizeText("\u8DDF\u968F\u9ED8\u8BA4\u6A21\u578B"))),
2372
+ row("effort", "\u601D\u8003\u5F3A\u5EA6", effortLabel, effortDisabled),
2373
+ pane ? h2(
2374
+ "div",
2166
2375
  {
2167
- className: "dim-presetSelect dim-modelSelect",
2168
- value: currentValue,
2169
- disabled: disabled || saving,
2170
- "aria-label": "\u6A21\u578B",
2171
- onChange: (event) => {
2172
- void change(event);
2173
- }
2376
+ ref: menuRef,
2377
+ id: `${id6}-menu`,
2378
+ role: "menu",
2379
+ "aria-label": pane === "model" ? "\u6A21\u578B" : "\u601D\u8003\u5F3A\u5EA6",
2380
+ "aria-busy": saving,
2381
+ className: "dim-modelMenu"
2174
2382
  },
2175
- h2("option", { value: "" }, "\u8DDF\u968F\u9ED8\u8BA4\u6A21\u578B"),
2176
- ...catalog.groups.map((group) => h2(
2177
- "optgroup",
2178
- { key: group.id, label: group.name },
2179
- ...group.models.map((entry) => {
2180
- const selection = { provider: group.id, model: entry.id };
2181
- const id5 = modelSelectionId(selection);
2182
- return h2(
2183
- "option",
2184
- { key: id5, value: optionValue(selection) },
2185
- entry.name && entry.name !== entry.id ? `${entry.name}\uFF08${id5}\uFF09` : id5
2186
- );
2187
- })
2188
- )),
2189
- current && !currentAvailable ? h2("option", { value: currentValue }, [modelSelectionId(current), "\uFF08\u5DF2\u4E0D\u53EF\u7528\uFF09"]) : null
2190
- ),
2383
+ pane === "model" ? [
2384
+ option("default", "\u8DDF\u968F\u9ED8\u8BA4\u6A21\u578B", null, !current, null),
2385
+ ...catalog.groups.map((group) => h2(
2386
+ "section",
2387
+ { key: group.id, role: "group", "aria-label": group.name },
2388
+ h2("div", { className: "dim-modelGroupTitle" }, group.name),
2389
+ ...group.models.map((choice) => {
2390
+ const selected = current?.provider === group.id && current?.model === choice.id;
2391
+ return option(
2392
+ choice.id,
2393
+ choice.name,
2394
+ choice.description ?? `${group.id}/${choice.id}`,
2395
+ selected,
2396
+ selected ? current : { provider: group.id, model: choice.id }
2397
+ );
2398
+ })
2399
+ ))
2400
+ ] : [
2401
+ option(
2402
+ "provider-default",
2403
+ defaultLabel,
2404
+ "\u4F7F\u7528\u6A21\u578B\u6216\u670D\u52A1\u63D0\u4F9B\u65B9\u7684\u9ED8\u8BA4\u601D\u8003\u5F3A\u5EA6\u3002",
2405
+ effort === void 0,
2406
+ current ? { provider: current.provider, model: current.model } : null
2407
+ ),
2408
+ ...(reasoning?.efforts ?? []).map((level) => option(
2409
+ `effort:${level.id}`,
2410
+ level.name,
2411
+ level.description,
2412
+ effort === level.id,
2413
+ { ...current, reasoningEffort: level.id }
2414
+ ))
2415
+ ]
2416
+ ) : null,
2417
+ effortHint ? h2("p", {
2418
+ id: `${id6}-hint`,
2419
+ className: "dim-modelHint",
2420
+ role: effortUnavailable ? "status" : void 0
2421
+ }, effortHint) : null,
2191
2422
  error || !currentAvailable ? h2(
2192
2423
  "p",
2193
2424
  { className: "dim-presetError", role: error ? "alert" : "status" },
@@ -2238,11 +2469,11 @@ function normalizeAccessPolicyUserId(value) {
2238
2469
  value = String(value);
2239
2470
  }
2240
2471
  if (typeof value !== "string") throw invalidAccessPolicy("\u7528\u6237\u6807\u8BC6\u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u3002");
2241
- const id5 = value.trim();
2242
- if (!id5 || id5.length > ACCESS_POLICY_USER_ID_MAX_LENGTH || CONTROL_CHARACTERS.test(id5)) {
2472
+ const id6 = value.trim();
2473
+ if (!id6 || id6.length > ACCESS_POLICY_USER_ID_MAX_LENGTH || CONTROL_CHARACTERS.test(id6)) {
2243
2474
  throw invalidAccessPolicy(`\u7528\u6237\u6807\u8BC6\u4E0D\u80FD\u4E3A\u7A7A\u3001\u5305\u542B\u63A7\u5236\u5B57\u7B26\u6216\u8D85\u8FC7 ${ACCESS_POLICY_USER_ID_MAX_LENGTH} \u4E2A\u5B57\u7B26\u3002`);
2244
2475
  }
2245
- return id5;
2476
+ return id6;
2246
2477
  }
2247
2478
  function validateAccessPolicyUser(input) {
2248
2479
  if (!hasExactKeys(input, USER_KEYS)) {
@@ -2259,7 +2490,7 @@ function validateAccessPolicyUser(input) {
2259
2490
  function validateUsers(input, { listMessage, duplicateMessage }) {
2260
2491
  if (!Array.isArray(input)) throw invalidAccessPolicy(listMessage);
2261
2492
  const users = input.map(validateAccessPolicyUser);
2262
- if (new Set(users.map(({ id: id5 }) => id5)).size !== users.length) {
2493
+ if (new Set(users.map(({ id: id6 }) => id6)).size !== users.length) {
2263
2494
  throw invalidAccessPolicy(duplicateMessage);
2264
2495
  }
2265
2496
  return Object.freeze(users);
@@ -2481,8 +2712,8 @@ function optionalString(value, maxLength = 240) {
2481
2712
  return trimmed ? trimmed.slice(0, maxLength) : void 0;
2482
2713
  }
2483
2714
  function opaqueId(value) {
2484
- const id5 = optionalString(value, 128);
2485
- return id5 && /^[a-z\d_-]+$/i.test(id5) ? id5 : void 0;
2715
+ const id6 = optionalString(value, 128);
2716
+ return id6 && /^[a-z\d_-]+$/i.test(id6) ? id6 : void 0;
2486
2717
  }
2487
2718
  function timestamp(value) {
2488
2719
  if (typeof value === "number" && Number.isFinite(value)) return value;
@@ -2813,13 +3044,13 @@ function CollapsibleAccountSection({
2813
3044
  defaultOpen = false,
2814
3045
  open: controlledOpen,
2815
3046
  onToggle,
2816
- id: id5,
3047
+ id: id6,
2817
3048
  className = "",
2818
3049
  children
2819
3050
  }) {
2820
3051
  const [uncontrolledOpen, setUncontrolledOpen] = React6.useState(defaultOpen);
2821
3052
  const open = controlledOpen ?? uncontrolledOpen;
2822
- const contentId = id5 ? `${id5}-content` : void 0;
3053
+ const contentId = id6 ? `${id6}-content` : void 0;
2823
3054
  const toggle = () => {
2824
3055
  if (controlledOpen === void 0) setUncontrolledOpen((value) => !value);
2825
3056
  onToggle?.(!open);
@@ -3492,7 +3723,7 @@ function ContextEnhancementScopeEditor({
3492
3723
  )
3493
3724
  );
3494
3725
  }
3495
- function ContextEnhancementDialog({ config, groupSupported, disabled, onSave, onClose, returnFocusRef, id: id5 }) {
3726
+ function ContextEnhancementDialog({ config, groupSupported, disabled, onSave, onClose, returnFocusRef, id: id6 }) {
3496
3727
  const [draft, setDraft] = React9.useState(() => {
3497
3728
  const normalized = normalizeContextEnhancementConfig(config);
3498
3729
  return {
@@ -3584,7 +3815,7 @@ function ContextEnhancementDialog({ config, groupSupported, disabled, onSave, on
3584
3815
  }, h2(
3585
3816
  "section",
3586
3817
  {
3587
- id: id5,
3818
+ id: id6,
3588
3819
  ref: dialogRef,
3589
3820
  className: "dim-contextDialog",
3590
3821
  role: "dialog",
@@ -3850,7 +4081,7 @@ function messageErrorTime(value) {
3850
4081
  return null;
3851
4082
  }
3852
4083
  }
3853
- function ChannelListHeading({ className = "", id: id5, title, connectionLabel }) {
4084
+ function ChannelListHeading({ className = "", id: id6, title, connectionLabel }) {
3854
4085
  const helpId = React11.useId();
3855
4086
  return h2(
3856
4087
  "div",
@@ -3858,7 +4089,7 @@ function ChannelListHeading({ className = "", id: id5, title, connectionLabel })
3858
4089
  h2(
3859
4090
  "div",
3860
4091
  { className: "dim-listTitle" },
3861
- h2("h3", id5 ? { id: id5 } : null, title),
4092
+ h2("h3", id6 ? { id: id6 } : null, title),
3862
4093
  h2(
3863
4094
  "span",
3864
4095
  { className: "dim-channelHelp" },
@@ -5117,7 +5348,7 @@ var TOKEN_BOT_ENDPOINTS = Object.freeze({
5117
5348
  function createTokenChannelApi(channel4, connectionSummary, {
5118
5349
  normalizeBotExtension = () => ({})
5119
5350
  } = {}) {
5120
- const unwrapRpcResult13 = (result) => {
5351
+ const unwrapRpcResult14 = (result) => {
5121
5352
  if (!isRecord2(result) || typeof result.ok !== "boolean") {
5122
5353
  throw new Error(`${channel4} \u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94`);
5123
5354
  }
@@ -5128,7 +5359,7 @@ function createTokenChannelApi(channel4, connectionSummary, {
5128
5359
  }
5129
5360
  return result.value;
5130
5361
  };
5131
- const normalizeBot7 = (value) => {
5362
+ const normalizeBot8 = (value) => {
5132
5363
  if (!isRecord2(value) || !id(value.botId)) return void 0;
5133
5364
  const connected = value.connected === true;
5134
5365
  const state = ACCOUNT_STATES2.has(value.state) ? value.state : "offline";
@@ -5162,12 +5393,12 @@ function createTokenChannelApi(channel4, connectionSummary, {
5162
5393
  ...isRecord2(extension) ? extension : {}
5163
5394
  };
5164
5395
  };
5165
- const normalizeSnapshot9 = (value) => {
5396
+ const normalizeSnapshot10 = (value) => {
5166
5397
  const source = isRecord2(value?.snapshot) ? value.snapshot : value;
5167
5398
  if (!isRecord2(source) || !Array.isArray(source.bots)) {
5168
5399
  throw new Error(`${channel4} \u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u673A\u5668\u4EBA\u5217\u8868`);
5169
5400
  }
5170
- const bots = source.bots.map(normalizeBot7).filter(Boolean);
5401
+ const bots = source.bots.map(normalizeBot8).filter(Boolean);
5171
5402
  return {
5172
5403
  revision: Number.isSafeInteger(source.revision) ? source.revision : 0,
5173
5404
  bots,
@@ -5176,11 +5407,11 @@ function createTokenChannelApi(channel4, connectionSummary, {
5176
5407
  modelCatalog: normalizeModelCatalog(source.modelCatalog)
5177
5408
  };
5178
5409
  };
5179
- const presentError13 = (error) => ({
5410
+ const presentError14 = (error) => ({
5180
5411
  code: text2(error?.code, `${channel4.toUpperCase()}_ERROR`, 80),
5181
5412
  message: text2(error?.message, `${channel4}\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`)
5182
5413
  });
5183
- return Object.freeze({ unwrapRpcResult: unwrapRpcResult13, normalizeSnapshot: normalizeSnapshot9, presentError: presentError13 });
5414
+ return Object.freeze({ unwrapRpcResult: unwrapRpcResult14, normalizeSnapshot: normalizeSnapshot10, presentError: presentError14 });
5184
5415
  }
5185
5416
 
5186
5417
  // plugin-src/client/channels/discord/api.js
@@ -5245,7 +5476,7 @@ function createTokenChannelSettings(definition) {
5245
5476
  AccountSettings = null,
5246
5477
  accountSettingsEndpoint = null
5247
5478
  } = definition;
5248
- function AccountCard5({ account, busy, testNotice, removing, onReconnect, onWorkspaceSave, onModelSave, onAgentPresetSave, onContextEnhancementSave, onAccountSettingsSave, onRequestRemove, onConfirmRemove, onCancelRemove }) {
5479
+ function AccountCard6({ account, busy, testNotice, removing, onReconnect, onWorkspaceSave, onModelSave, onAgentPresetSave, onContextEnhancementSave, onAccountSettingsSave, onRequestRemove, onConfirmRemove, onCancelRemove }) {
5249
5480
  const state = busy === "reconnect" ? "connecting" : account.state;
5250
5481
  const tone = account.connected ? "success" : state === "error" ? "error" : "warning";
5251
5482
  const stateLabel2 = account.connected ? "\u8FD0\u884C\u6B63\u5E38" : state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA";
@@ -5536,7 +5767,7 @@ function createTokenChannelSettings(definition) {
5536
5767
  title: `\u5DF2\u63A5\u5165\u7684 ${channel4} \u673A\u5668\u4EBA`,
5537
5768
  connectionLabel
5538
5769
  }),
5539
- h2("ul", { className: "ddt-list dim-botList" }, model.bots.map((account) => h2("li", { key: account.botId }, h2(AccountCard5, {
5770
+ h2("ul", { className: "ddt-list dim-botList" }, model.bots.map((account) => h2("li", { key: account.botId }, h2(AccountCard6, {
5540
5771
  account,
5541
5772
  busy: busyByBot[account.botId],
5542
5773
  testNotice: testNoticeByBot[account.botId],
@@ -5698,7 +5929,7 @@ function createTokenChannelSettings(definition) {
5698
5929
  )
5699
5930
  )));
5700
5931
  }
5701
- return { SettingsTab, AccountCard: AccountCard5 };
5932
+ return { SettingsTab, AccountCard: AccountCard6 };
5702
5933
  }
5703
5934
 
5704
5935
  // plugin-src/client/channels/discord/styles.js
@@ -6428,14 +6659,14 @@ var HEALTH_LABELS = {
6428
6659
  offline: "\u8FDE\u63A5\u4E2D\u65AD",
6429
6660
  error: "\u9700\u8981\u5904\u7406"
6430
6661
  };
6431
- function formatCheckedTime(timestamp7) {
6432
- if (!timestamp7) return "\u5C1A\u672A\u68C0\u67E5";
6662
+ function formatCheckedTime(timestamp8) {
6663
+ if (!timestamp8) return "\u5C1A\u672A\u68C0\u67E5";
6433
6664
  try {
6434
6665
  return new Intl.DateTimeFormat("zh-CN", {
6435
6666
  hour: "2-digit",
6436
6667
  minute: "2-digit",
6437
6668
  second: "2-digit"
6438
- }).format(new Date(timestamp7));
6669
+ }).format(new Date(timestamp8));
6439
6670
  } catch {
6440
6671
  return "\u521A\u521A";
6441
6672
  }
@@ -6489,6 +6720,7 @@ function RemoveConfirmation2({ bot, busy, onConfirm, onCancel }) {
6489
6720
  }
6490
6721
  function StepPushEditor({ value = false, disabled = false, onSave }) {
6491
6722
  const titleId = React15.useId();
6723
+ const helpId = `${titleId}-help`;
6492
6724
  const current = value === true ? "on" : "off";
6493
6725
  const [saving, setSaving] = React15.useState(false);
6494
6726
  const [error, setError] = React15.useState(null);
@@ -6514,7 +6746,26 @@ function StepPushEditor({ value = false, disabled = false, onSave }) {
6514
6746
  h2(
6515
6747
  "div",
6516
6748
  { className: "dim-feishuGroupControlHeader" },
6517
- h2("h3", { id: titleId }, "\u5206\u6B65\u76F4\u63A8"),
6749
+ h2(
6750
+ "div",
6751
+ { className: "dim-presetTitle" },
6752
+ h2("h3", { id: titleId }, "\u5206\u6B65\u76F4\u63A8"),
6753
+ h2(
6754
+ "span",
6755
+ { className: "dim-presetHelp" },
6756
+ h2("button", {
6757
+ type: "button",
6758
+ className: "dim-presetHelpButton",
6759
+ "aria-label": "\u67E5\u770B\u5206\u6B65\u76F4\u63A8\u8BF4\u660E",
6760
+ "aria-describedby": helpId
6761
+ }, h2("span", { "aria-hidden": "true" }, "?")),
6762
+ h2("span", {
6763
+ id: helpId,
6764
+ className: "dim-presetTooltip",
6765
+ role: "tooltip"
6766
+ }, "\u5F00\u542F\u540E\u9010\u6B65\u63A8\u9001\u5DE5\u5177\u8C03\u7528\u4E0E\u8FC7\u7A0B\u8BF4\u660E")
6767
+ )
6768
+ ),
6518
6769
  saving ? h2("span", { className: "dim-feishuGroupControlStatus", role: "status" }, "\u4FDD\u5B58\u4E2D\u2026") : null
6519
6770
  ),
6520
6771
  h2(
@@ -6531,11 +6782,6 @@ function StepPushEditor({ value = false, disabled = false, onSave }) {
6531
6782
  h2("option", { value: "off" }, "\u5173\u95ED\uFF08\u4FDD\u6301\u6D41\u5F0F\u5361\u6A21\u5F0F\uFF09"),
6532
6783
  h2("option", { value: "on" }, "\u5F00\u542F\uFF08\u9010\u6B65\u63A8\u9001\u5DE5\u5177\u8C03\u7528\u4E0E\u8FC7\u7A0B\u8BF4\u660E\uFF09")
6533
6784
  ),
6534
- h2(
6535
- "p",
6536
- { className: "dim-feishuGroupHelp" },
6537
- "\u5F00\u542F\u540E\u9010\u6B65\u63A8\u9001\u5DE5\u5177\u8C03\u7528\u4E0E\u8FC7\u7A0B\u8BF4\u660E"
6538
- ),
6539
6785
  error ? h2("p", {
6540
6786
  className: "dim-feishuGroupError",
6541
6787
  role: "alert"
@@ -6993,15 +7239,15 @@ function FeishuSettingsTab({ rpcCall }) {
6993
7239
  if (targetedUpdate && (provision2.operation !== operation || provision2.botId !== botId)) {
6994
7240
  throw new Error(grantingGroupMessages ? "\u98DE\u4E66\u670D\u52A1\u8FD4\u56DE\u4E86\u4E0D\u5339\u914D\u7684\u7FA4\u6D88\u606F\u6743\u9650\u4E8C\u7EF4\u7801" : "\u98DE\u4E66\u670D\u52A1\u8FD4\u56DE\u4E86\u4E0D\u5339\u914D\u7684\u6743\u9650\u8865\u5168\u4E8C\u7EF4\u7801");
6995
7241
  }
6996
- const timestamp7 = Date.now();
6997
- setNow(timestamp7);
7242
+ const timestamp8 = Date.now();
7243
+ setNow(timestamp8);
6998
7244
  setModel((current) => ({
6999
7245
  ...current,
7000
7246
  provisioning: {
7001
7247
  phase: "qr",
7002
7248
  ...provision2,
7003
7249
  ...botName ? { botName } : {},
7004
- durationMs: Math.max(1, provision2.expiresAt - timestamp7),
7250
+ durationMs: Math.max(1, provision2.expiresAt - timestamp8),
7005
7251
  expired: false
7006
7252
  }
7007
7253
  }));
@@ -7118,9 +7364,9 @@ function FeishuSettingsTab({ rpcCall }) {
7118
7364
  React15.useEffect(() => {
7119
7365
  if (!countdownAttemptId || countdownPhase !== "qr" || countdownExpired) return void 0;
7120
7366
  const tick = () => {
7121
- const timestamp7 = Date.now();
7122
- setNow(timestamp7);
7123
- if (timestamp7 >= countdownExpiresAt) {
7367
+ const timestamp8 = Date.now();
7368
+ setNow(timestamp8);
7369
+ if (timestamp8 >= countdownExpiresAt) {
7124
7370
  setModel((current) => current.provisioning?.attemptId === countdownAttemptId ? { ...current, provisioning: { ...current.provisioning, expired: true } } : current);
7125
7371
  }
7126
7372
  };
@@ -10353,17 +10599,13 @@ function WecomSettingsTab({ rpcCall }) {
10353
10599
  )));
10354
10600
  }
10355
10601
 
10356
- // plugin-src/client/channels/weixin/index.js
10357
- var React20 = __toESM(require("react"), 1);
10358
-
10359
- // plugin-src/client/channels/weixin/api.js
10360
- var WEIXIN_RPC_CHANNEL = "/weixin";
10361
- var WEIXIN_ENDPOINTS = Object.freeze({
10602
+ // plugin-src/client/channels/wecom-app/api.js
10603
+ var WECOM_APP_RPC_CHANNEL = "/wecom-app";
10604
+ var WECOM_APP_ENDPOINTS = Object.freeze({
10362
10605
  status: "connection.status",
10363
- beginProvisioning: "provision.begin",
10364
- pollProvisioning: "provision.poll",
10365
- submitVerification: "provision.verify",
10366
- cancelProvisioning: "provision.cancel",
10606
+ bindApp: "bot.bind",
10607
+ updateSettings: "bot.settings.update",
10608
+ resetCallbackSecret: "bot.callback-secret.reset",
10367
10609
  reconnectBot: "bot.reconnect",
10368
10610
  deleteBot: "bot.delete",
10369
10611
  setWorkspace: "bot.workspace.set",
@@ -10373,25 +10615,24 @@ var WEIXIN_ENDPOINTS = Object.freeze({
10373
10615
  setAccessPolicy: "bot.access-policy.set"
10374
10616
  });
10375
10617
  var ACCOUNT_STATES5 = /* @__PURE__ */ new Set(["connected", "connecting", "offline", "error"]);
10376
- var PROVISION_STATES4 = /* @__PURE__ */ new Set([
10377
- "starting",
10378
- "pending",
10379
- "scanned",
10380
- "needs_verification",
10381
- "connecting",
10382
- "connected",
10383
- "expired",
10384
- "failed",
10385
- "cancelled"
10386
- ]);
10387
10618
  function isRecord6(value) {
10388
10619
  return value !== null && typeof value === "object" && !Array.isArray(value);
10389
10620
  }
10390
- function string(value, fallback = "") {
10391
- return typeof value === "string" && value.trim() ? value.trim() : fallback;
10621
+ function text5(value, fallback, max = 240) {
10622
+ return typeof value === "string" && value.trim() ? value.trim().slice(0, max) : fallback;
10623
+ }
10624
+ function id4(value) {
10625
+ const result = text5(value, "", 128);
10626
+ return /^[a-z\d_-]+$/i.test(result) ? result : void 0;
10627
+ }
10628
+ function optionalUrl(value) {
10629
+ const raw = text5(value, "", 512);
10630
+ return /^https?:\/\//iu.test(raw) ? raw : null;
10392
10631
  }
10393
10632
  function timestamp5(value) {
10394
- return typeof value === "number" && Number.isFinite(value) ? value : null;
10633
+ if (typeof value === "number" && Number.isFinite(value)) return value;
10634
+ const parsed = typeof value === "string" ? Date.parse(value) : Number.NaN;
10635
+ return Number.isNaN(parsed) ? void 0 : parsed;
10395
10636
  }
10396
10637
  function normalizeTestMessage4(value) {
10397
10638
  if (!isRecord6(value)) return null;
@@ -10401,145 +10642,984 @@ function normalizeTestMessage4(value) {
10401
10642
  return { sent: false, code };
10402
10643
  }
10403
10644
  function unwrapRpcResult8(result) {
10404
- if (!isRecord6(result) || typeof result.ok !== "boolean") {
10405
- throw new Error("\u5FAE\u4FE1\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94");
10406
- }
10645
+ if (!isRecord6(result) || typeof result.ok !== "boolean") throw new Error("\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94");
10407
10646
  if (!result.ok) {
10408
- const error = new Error(string(result.error?.message, "\u5FAE\u4FE1\u64CD\u4F5C\u5931\u8D25"));
10409
- error.code = string(result.error?.code, "WEIXIN_RPC_ERROR");
10647
+ const error = new Error(text5(result.error?.message, "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u64CD\u4F5C\u5931\u8D25"));
10648
+ error.code = text5(result.error?.code, "WECOM_APP_RPC_ERROR", 80);
10410
10649
  throw error;
10411
10650
  }
10412
10651
  return result.value;
10413
10652
  }
10414
- function safeQrSource5(value) {
10415
- return typeof value === "string" && /^data:image\/(?:png|webp|svg\+xml)(?:;charset=[^;,]+)?;base64,/i.test(value) ? value : void 0;
10416
- }
10417
- function safeVerificationUrl(value) {
10418
- if (typeof value !== "string") return void 0;
10419
- try {
10420
- const url = new URL(value);
10421
- const host = url.hostname.toLowerCase();
10422
- return url.protocol === "https:" && (host === "weixin.qq.com" || host.endsWith(".weixin.qq.com") || host === "wechat.com" || host.endsWith(".wechat.com")) ? url.toString() : void 0;
10423
- } catch {
10424
- return void 0;
10425
- }
10426
- }
10427
- function normalizeProvisioning5(value) {
10428
- if (!isRecord6(value) || !string(value.attemptId)) {
10429
- throw new Error("\u5FAE\u4FE1\u626B\u7801\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u7ED1\u5B9A\u4EFB\u52A1");
10430
- }
10431
- const status = PROVISION_STATES4.has(value.status) ? value.status : "failed";
10432
- const result = {
10433
- attemptId: string(value.attemptId),
10434
- status,
10435
- expiresAt: timestamp5(value.expiresAt) ?? Date.now(),
10436
- pollIntervalMs: Math.min(5e3, Math.max(500, Number(value.pollIntervalMs) || 1e3)),
10437
- verificationRequired: value.verificationRequired === true || status === "needs_verification"
10438
- };
10439
- const verificationUrl = safeVerificationUrl(value.verificationUrl);
10440
- const qrCodeDataUrl = safeQrSource5(value.qrCodeDataUrl);
10441
- if (verificationUrl) result.verificationUrl = verificationUrl;
10442
- if (qrCodeDataUrl) result.qrCodeDataUrl = qrCodeDataUrl;
10443
- if (string(value.botId)) result.botId = string(value.botId);
10444
- if (value.alreadyConnected === true) result.alreadyConnected = true;
10445
- if (isRecord6(value.error)) {
10446
- result.error = {
10447
- code: string(value.error.code, "WEIXIN_PROVISION_FAILED"),
10448
- message: string(value.error.message, "\u5FAE\u4FE1\u7ED1\u5B9A\u6CA1\u6709\u5B8C\u6210")
10449
- };
10450
- }
10451
- return result;
10452
- }
10453
10653
  function normalizeBot5(value) {
10454
- if (!isRecord6(value) || !string(value.botId) || !isRecord6(value.bot)) return null;
10455
- const state = ACCOUNT_STATES5.has(value.state) ? value.state : "error";
10654
+ if (!isRecord6(value) || !id4(value.botId)) return void 0;
10456
10655
  const connected = value.connected === true;
10656
+ const state = ACCOUNT_STATES5.has(value.state) ? value.state : "offline";
10457
10657
  return {
10458
- botId: string(value.botId),
10459
- state: connected ? "connected" : state,
10658
+ botId: id4(value.botId),
10460
10659
  connected,
10461
- configured: value.configured === true,
10462
- workspace: string(value.workspace).slice(0, 4096),
10660
+ state: connected ? "connected" : state,
10661
+ workspace: text5(value.workspace, "", 4096),
10463
10662
  model: normalizeModelSelection(value.model),
10464
10663
  agentPreset: normalizeAgentPresetId(value.agentPreset),
10465
10664
  contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
10466
10665
  ...Object.hasOwn(value, "accessPolicy") ? { accessPolicy: normalizeAccessPolicy(value.accessPolicy) } : {},
10467
10666
  bot: {
10468
- name: string(value.bot.name, "\u5FAE\u4FE1\u673A\u5668\u4EBA"),
10469
- accountIdMasked: string(value.bot.accountIdMasked, "\u5DF2\u5B89\u5168\u4FDD\u5B58")
10667
+ name: text5(value.bot?.name, "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528", 100),
10668
+ corpIdMasked: text5(value.bot?.corpIdMasked, "\u4F01\u4E1A ID \u5DF2\u4FDD\u5B58", 140),
10669
+ agentId: text5(value.bot?.agentId, "", 32),
10670
+ apiBaseUrl: optionalUrl(value.bot?.apiBaseUrl) ?? "",
10671
+ callbackBaseUrl: optionalUrl(value.bot?.callbackBaseUrl) ?? "",
10672
+ streamEnabled: value.bot?.streamEnabled !== false,
10673
+ callbackUrl: optionalUrl(value.bot?.callbackUrl) ?? ""
10470
10674
  },
10471
10675
  health: {
10472
- status: string(value.health?.status, connected ? "healthy" : "offline"),
10473
- summary: string(value.health?.summary, connected ? "\u5FAE\u4FE1\u8FDE\u63A5\u6B63\u5E38" : "\u5FAE\u4FE1\u8FDE\u63A5\u672A\u5C31\u7EEA"),
10676
+ summary: text5(value.health?.summary, connected ? "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u56DE\u8C03\u901A\u9053\u5C31\u7EEA" : "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA"),
10474
10677
  lastCheckedAt: timestamp5(value.health?.lastCheckedAt)
10475
10678
  },
10476
- stats: {
10477
- messagesReceived: Math.max(0, Number(value.stats?.messagesReceived) || 0),
10478
- messagesReplied: Math.max(0, Number(value.stats?.messagesReplied) || 0)
10479
- },
10480
10679
  lastMessageError: normalizeLastMessageError(value.lastMessageError),
10481
10680
  error: isRecord6(value.error) ? {
10482
- code: string(value.error.code, "WEIXIN_ACCOUNT_ERROR"),
10483
- message: string(value.error.message, "\u5FAE\u4FE1\u8FDE\u63A5\u672A\u5C31\u7EEA")
10681
+ code: text5(value.error.code, "WECOM_APP_ACCOUNT_ERROR", 80),
10682
+ message: text5(value.error.message, "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA")
10484
10683
  } : null
10485
10684
  };
10486
10685
  }
10487
10686
  function normalizeSnapshot7(value) {
10488
- if (!isRecord6(value) || !Array.isArray(value.bots)) {
10489
- throw new Error("\u5FAE\u4FE1\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u8D26\u53F7\u5217\u8868");
10490
- }
10491
- const bots = value.bots.map(normalizeBot5).filter(Boolean);
10687
+ const source = isRecord6(value?.snapshot) ? value.snapshot : value;
10688
+ if (!isRecord6(source) || !Array.isArray(source.bots)) throw new Error("\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u673A\u5668\u4EBA\u5217\u8868");
10689
+ const bots = source.bots.map(normalizeBot5).filter(Boolean);
10492
10690
  return {
10493
- schemaVersion: Number(value.schemaVersion) || 1,
10494
- revision: Number(value.revision) || 0,
10495
- state: string(value.state, "offline"),
10691
+ revision: Number.isSafeInteger(source.revision) ? source.revision : 0,
10496
10692
  bots,
10497
- totals: {
10498
- configured: bots.length,
10499
- connected: bots.filter((bot) => bot.connected).length
10500
- },
10501
- provisioning: value.provisioning ? normalizeProvisioning5(value.provisioning) : null,
10502
- testMessage: normalizeTestMessage4(value.testMessage),
10503
- agentPresetCatalog: normalizeAgentPresetCatalog(value.agentPresetCatalog),
10504
- modelCatalog: normalizeModelCatalog(value.modelCatalog)
10693
+ totals: { configured: bots.length, connected: bots.filter((bot) => bot.connected).length },
10694
+ testMessage: normalizeTestMessage4(source.testMessage),
10695
+ agentPresetCatalog: normalizeAgentPresetCatalog(source.agentPresetCatalog),
10696
+ modelCatalog: normalizeModelCatalog(source.modelCatalog)
10505
10697
  };
10506
10698
  }
10507
10699
  function presentError8(error) {
10508
10700
  return {
10509
- code: string(error?.code, "WEIXIN_ERROR"),
10510
- message: string(error?.message, "\u5FAE\u4FE1\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")
10701
+ code: text5(error?.code, "WECOM_APP_ERROR", 80),
10702
+ message: text5(error?.message, "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")
10511
10703
  };
10512
10704
  }
10513
- function formatRemaining5(milliseconds) {
10514
- const seconds = Math.max(0, Math.ceil(milliseconds / 1e3));
10515
- return `${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, "0")}`;
10705
+
10706
+ // plugin-src/client/channels/wecom-app/index.js
10707
+ var React20 = __toESM(require("react"), 1);
10708
+
10709
+ // plugin-src/client/channels/wecom-app/styles.js
10710
+ var WECOM_APP_STYLE_ID = "xmanrui-dsh-im-wecom-app-settings";
10711
+ var CSS9 = String.raw`
10712
+ .dwecomapp-page { --ddt-accent: #07c160; --ddt-accent-deep: #059a4c; --ddt-accent-wash: #eefaf3; }
10713
+ .dwecomapp-avatar, .dwecomapp-brand { color: #07c160; background: #fff; border: 1px solid var(--dsw-alias-border-l2, #e5e6eb); }
10714
+ .dwecomapp-avatar svg, .dwecomapp-brand svg { display: block; }
10715
+ .dim-appFieldGrid { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
10716
+ .dim-callbackBox { display: flex; flex-direction: column; gap: 6px; padding: 10px 12px; border: 1px dashed var(--dsw-alias-border-l2, #e5e6eb); border-radius: 8px; }
10717
+ .dim-callbackBox strong { font-size: 12px; color: var(--dsw-alias-text-secondary, #646a73); }
10718
+ .dim-callbackRow { display: flex; gap: 8px; align-items: center; }
10719
+ .dim-callbackRow input { flex: 1 1 auto; min-width: 0; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; }
10720
+ .dim-appSwitchRow { display: flex; align-items: center; gap: 8px; font-size: 13px; }
10721
+ `;
10722
+ function installWecomAppStyles() {
10723
+ if (typeof document === "undefined") return () => {
10724
+ };
10725
+ const existing = document.querySelector(`style[data-plugin-css="${WECOM_APP_STYLE_ID}"]`);
10726
+ if (existing) return () => {
10727
+ };
10728
+ const style = document.createElement("style");
10729
+ style.dataset.plugin = "@xmanrui/dsh-im";
10730
+ style.dataset.pluginCss = WECOM_APP_STYLE_ID;
10731
+ style.textContent = CSS9;
10732
+ document.head.appendChild(style);
10733
+ return () => style.remove();
10516
10734
  }
10517
10735
 
10518
- // plugin-src/client/channels/weixin/index.js
10736
+ // plugin-src/client/channels/wecom-app/index.js
10519
10737
  var Button12 = React20.forwardRef(function Button13({ children, kind = "secondary", className = "", ...props }, ref) {
10520
10738
  return h2("button", {
10521
10739
  ...props,
10522
10740
  ref,
10523
10741
  type: "button",
10524
- className: `dxw-button ${className}`.trim(),
10742
+ className: `ddt-button ${className}`.trim(),
10525
10743
  "data-kind": kind
10526
10744
  }, children);
10527
10745
  });
10746
+ function checkedTime5(value) {
10747
+ if (!value) return "\u5C1A\u672A\u68C0\u67E5";
10748
+ try {
10749
+ return new Intl.DateTimeFormat("zh-CN", {
10750
+ hour: "2-digit",
10751
+ minute: "2-digit",
10752
+ second: "2-digit"
10753
+ }).format(new Date(value));
10754
+ } catch {
10755
+ return "\u521A\u521A";
10756
+ }
10757
+ }
10528
10758
  function Heading5({ totals, adding, busy, onAdd, addButtonRef }) {
10529
10759
  return h2(
10530
10760
  "div",
10531
- { className: "dxw-heading" },
10761
+ { className: "ddt-heading" },
10532
10762
  h2(
10533
10763
  "div",
10534
- { className: "dxw-tools" },
10535
- h2(Button12, {
10536
- kind: "primary",
10537
- className: "dim-scanButton",
10538
- onClick: onAdd,
10539
- disabled: adding || busy,
10540
- ref: addButtonRef,
10541
- "aria-label": "\u626B\u7801\u63A5\u5165\u5FAE\u4FE1\u673A\u5668\u4EBA"
10542
- }, h2(QrActionIcon), adding ? "\u6B63\u5728\u63A5\u5165" : "\u626B\u7801\u63A5\u5165\u673A\u5668\u4EBA"),
10764
+ { className: "ddt-tools" },
10765
+ h2(
10766
+ "div",
10767
+ { className: "dim-bindActions" },
10768
+ h2(Button12, {
10769
+ kind: "primary",
10770
+ className: "dim-scanButton",
10771
+ onClick: onAdd,
10772
+ disabled: adding || busy,
10773
+ ref: addButtonRef,
10774
+ "aria-label": "\u6DFB\u52A0\u4F01\u4E1A\u5FAE\u4FE1\u81EA\u5EFA\u5E94\u7528"
10775
+ }, adding ? "\u6536\u8D77\u8868\u5355" : "\u6DFB\u52A0\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528")
10776
+ ),
10777
+ totals.configured > 0 ? h2(
10778
+ "div",
10779
+ { className: "ddt-badge dim-onlineBadge" },
10780
+ h2("span", null, `${totals.connected} / ${totals.configured} \u5728\u7EBF`)
10781
+ ) : null
10782
+ )
10783
+ );
10784
+ }
10785
+ function LoadingView5() {
10786
+ return h2(
10787
+ "div",
10788
+ { className: "ddt-card ddt-loading dim-surfaceCard dim-loadingView", "aria-busy": "true" },
10789
+ h2("div", { className: "ddt-spinner dim-spinner" }),
10790
+ h2("span", null, "\u6B63\u5728\u8BFB\u53D6\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u72B6\u6001\u2026")
10791
+ );
10792
+ }
10793
+ function EmptyView5({ busy, onStart }) {
10794
+ return h2(
10795
+ "div",
10796
+ { className: "ddt-card dim-surfaceCard" },
10797
+ h2(
10798
+ "div",
10799
+ { className: "ddt-cardBody ddt-empty dim-surfaceBody dim-emptyView" },
10800
+ h2(
10801
+ "div",
10802
+ { className: "dim-emptyCopy" },
10803
+ h2(
10804
+ "div",
10805
+ { className: "ddt-stateLabel dim-stateLabel" },
10806
+ h2("span", { className: "ddt-dot dim-stateDot" }),
10807
+ h2("span", null, "\u5C1A\u672A\u7ED1\u5B9A\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528")
10808
+ ),
10809
+ h2("h3", null, "\u5728\u4F01\u4E1A\u5FAE\u4FE1\u4E2D\u521B\u5EFA\u81EA\u5EFA\u5E94\u7528\uFF0C\u5373\u53EF\u5728\u5FAE\u4FE1\u91CC\u4F7F\u7528"),
10810
+ h2("p", null, "\u5728\u5E94\u7528\u7BA1\u7406\u540E\u53F0\u521B\u5EFA\u81EA\u5EFA\u5E94\u7528\uFF0C\u5F00\u542F\u300C\u63A5\u6536\u6D88\u606F\u300D\u5E76\u586B\u5165\u4E0B\u9762\u7684\u53C2\u6570\u3002\u6210\u5458\u7684\u5FAE\u4FE1\u5173\u6CE8\u8BE5\u4F01\u4E1A\u7684\u5FAE\u4FE1\u63D2\u4EF6\u540E\uFF0C\u5C31\u80FD\u5728\u5FAE\u4FE1\u4E2D\u4E0E\u672C\u5E94\u7528\u53CC\u5411\u5BF9\u8BDD\u3002"),
10811
+ h2(
10812
+ "div",
10813
+ { className: "ddt-actions dim-viewActions" },
10814
+ h2(Button12, { kind: "primary", onClick: onStart, disabled: busy }, "\u586B\u5199\u5E94\u7528\u53C2\u6570")
10815
+ )
10816
+ ),
10817
+ h2(
10818
+ "div",
10819
+ { className: "ddt-brandMark dim-emptyBrand dwecomapp-brand", "aria-hidden": "true" },
10820
+ h2(WecomLogoGlyph, { size: 64 })
10821
+ )
10822
+ )
10823
+ );
10824
+ }
10825
+ function Field({ label, value, onChange, placeholder, busy, required = false, type = "text" }) {
10826
+ return h2(
10827
+ "label",
10828
+ { className: "dim-credentialField" },
10829
+ h2("span", null, label),
10830
+ h2("input", {
10831
+ value,
10832
+ onChange: (event) => onChange(event.target.value),
10833
+ placeholder,
10834
+ type,
10835
+ autoCapitalize: "none",
10836
+ autoCorrect: "off",
10837
+ spellCheck: false,
10838
+ autoComplete: "off",
10839
+ disabled: busy,
10840
+ required
10841
+ })
10842
+ );
10843
+ }
10844
+ function BindForm({ busy, error, onSubmit, onCancel }) {
10845
+ const [corpId, setCorpId] = React20.useState("");
10846
+ const [agentId, setAgentId] = React20.useState("");
10847
+ const [secret, setSecret] = React20.useState("");
10848
+ const [token, setToken] = React20.useState("");
10849
+ const [aesKey, setAesKey] = React20.useState("");
10850
+ const [apiBaseUrl, setApiBaseUrl] = React20.useState("");
10851
+ const [callbackBaseUrl, setCallbackBaseUrl] = React20.useState("");
10852
+ const [streamEnabled, setStreamEnabled] = React20.useState(true);
10853
+ const headingId = React20.useId();
10854
+ const formRef = React20.useRef(null);
10855
+ const submit = (event) => {
10856
+ event.preventDefault();
10857
+ if (busy) return;
10858
+ void onSubmit?.({
10859
+ corpId: corpId.trim(),
10860
+ agentId: agentId.trim(),
10861
+ secret: secret.trim(),
10862
+ token: token.trim(),
10863
+ encodingAESKey: aesKey.trim(),
10864
+ apiBaseUrl: apiBaseUrl.trim() || void 0,
10865
+ callbackBaseUrl: callbackBaseUrl.trim() || void 0,
10866
+ streamEnabled
10867
+ });
10868
+ };
10869
+ return h2(
10870
+ "section",
10871
+ {
10872
+ className: "ddt-card dim-surfaceCard dim-credentialPanel",
10873
+ "aria-labelledby": headingId
10874
+ },
10875
+ h2("h3", { id: headingId, className: "dim-credentialTitle" }, "\u7ED1\u5B9A\u4F01\u4E1A\u5FAE\u4FE1\u81EA\u5EFA\u5E94\u7528"),
10876
+ h2(
10877
+ "form",
10878
+ { ref: formRef, className: "dim-credentialForm", onSubmit: submit },
10879
+ h2(
10880
+ "div",
10881
+ { className: "dim-appFieldGrid" },
10882
+ h2(Field, { label: "\u4F01\u4E1A ID\uFF08CorpID\uFF09", value: corpId, onChange: setCorpId, placeholder: "\u4F8B\u5982 ww1234567890abcdef", busy, required: true }),
10883
+ h2(Field, { label: "\u5E94\u7528 AgentId", value: agentId, onChange: setAgentId, placeholder: "\u4F8B\u5982 1000002", busy, required: true }),
10884
+ h2(Field, { label: "\u5E94\u7528 Secret", value: secret, onChange: setSecret, placeholder: "\u5E94\u7528\u8BE6\u60C5\u9875\u7684 Secret", busy, required: true, type: "password" }),
10885
+ h2(Field, { label: "\u56DE\u8C03 Token", value: token, onChange: setToken, placeholder: "\u63A5\u6536\u6D88\u606F \u2192 API \u63A5\u6536\u4E2D\u7684 Token", busy, required: true, type: "password" }),
10886
+ h2(Field, { label: "EncodingAESKey", value: aesKey, onChange: setAesKey, placeholder: "43 \u4F4D\u5B57\u6BCD\u6216\u6570\u5B57", busy, required: true, type: "password" }),
10887
+ h2(Field, { label: "\u4EE3\u7406\u5730\u5740\uFF08\u53EF\u9009\uFF09", value: apiBaseUrl, onChange: setApiBaseUrl, placeholder: "\u7559\u7A7A\u76F4\u8FDE qyapi.weixin.qq.com", busy })
10888
+ ),
10889
+ h2(
10890
+ "div",
10891
+ { className: "dim-appFieldGrid" },
10892
+ h2(Field, { label: "\u516C\u7F51\u56DE\u8C03\u57FA\u5740\uFF08\u53EF\u9009\uFF09", value: callbackBaseUrl, onChange: setCallbackBaseUrl, placeholder: "\u4F8B\u5982 https://im.example.com", busy }),
10893
+ h2(
10894
+ "div",
10895
+ { className: "dim-appSwitchRow" },
10896
+ h2("button", {
10897
+ type: "button",
10898
+ className: "ddt-button dim-streamToggle",
10899
+ "aria-pressed": streamEnabled ? "true" : "false",
10900
+ onClick: () => setStreamEnabled((value) => !value),
10901
+ disabled: busy
10902
+ }, streamEnabled ? "\u6D41\u5F0F\u56DE\u590D\uFF1A\u5F00" : "\u6D41\u5F0F\u56DE\u590D\uFF1A\u5173"),
10903
+ h2("span", { className: "dim-switchHint" }, "\u4F01\u4E1A\u5FAE\u4FE1\u5BA2\u6237\u7AEF\u5B9E\u65F6\u51FA\u5B57\uFF1B\u5FAE\u4FE1\u7AEF\u4E0D\u652F\u6301\u65F6\u81EA\u52A8\u6539\u4E3A\u6574\u6BB5\u53D1\u9001")
10904
+ )
10905
+ ),
10906
+ error ? h2("div", { className: "ddt-inlineError dim-inlineError", role: "alert" }, h2("p", null, error.message)) : null,
10907
+ h2(
10908
+ "div",
10909
+ { className: "ddt-actions dim-viewActions" },
10910
+ h2(Button12, { kind: "primary", onClick: () => formRef.current?.requestSubmit(), disabled: busy }, busy ? "\u6B63\u5728\u7ED1\u5B9A\u2026" : "\u4FDD\u5B58\u5E76\u8FDE\u63A5"),
10911
+ h2(Button12, { kind: "quiet", onClick: onCancel, disabled: busy }, "\u53D6\u6D88")
10912
+ )
10913
+ )
10914
+ );
10915
+ }
10916
+ function CallbackUrlBox({ url, busy, resetBusy, onCopy, onReset }) {
10917
+ const [copied, setCopied] = React20.useState(false);
10918
+ const copy = async () => {
10919
+ try {
10920
+ await navigator.clipboard.writeText(url);
10921
+ setCopied(true);
10922
+ window.setTimeout(() => setCopied(false), 2e3);
10923
+ } catch {
10924
+ setCopied(false);
10925
+ }
10926
+ onCopy?.();
10927
+ };
10928
+ return h2(
10929
+ "div",
10930
+ { className: "dim-callbackBox" },
10931
+ h2("strong", null, "\u56DE\u8C03 URL\uFF08\u586B\u5165\u4F01\u4E1A\u5FAE\u4FE1\u540E\u53F0\u300C\u63A5\u6536\u6D88\u606F \u2192 \u8BBE\u7F6EAPI\u63A5\u6536\u300D\uFF09"),
10932
+ h2(
10933
+ "div",
10934
+ { className: "dim-callbackRow" },
10935
+ h2("input", {
10936
+ value: url || "\u672A\u914D\u7F6E\u516C\u7F51\u56DE\u8C03\u57FA\u5740\uFF1A\u8BF7\u5728\u672C\u9875\u300C\u8BBE\u7F6E\u300D\u4E2D\u586B\u5199\u56DE\u8C03\u57FA\u5740\uFF0C\u6216\u624B\u52A8\u62FC\u63A5 \u56DE\u8C03\u57FA\u5740 + \u8DEF\u5F84",
10937
+ readOnly: true,
10938
+ onFocus: (event) => event.target.select?.()
10939
+ }),
10940
+ url ? h2(Button12, { onClick: copy, disabled: busy, small: true }, copied ? "\u5DF2\u590D\u5236" : "\u590D\u5236") : null,
10941
+ h2(Button12, { kind: "danger", onClick: onReset, disabled: busy || resetBusy }, resetBusy ? "\u91CD\u7F6E\u4E2D\u2026" : "\u91CD\u7F6E\u5BC6\u94A5")
10942
+ ),
10943
+ h2(
10944
+ "span",
10945
+ { className: "dim-callbackHint" },
10946
+ "\u91CD\u7F6E\u5BC6\u94A5\u540E\u56DE\u8C03 URL \u4F1A\u53D8\u5316\uFF0C\u9700\u8981\u540C\u6B65\u66F4\u65B0\u4F01\u4E1A\u5FAE\u4FE1\u540E\u53F0\u3002\u82E5\u516C\u7F51\u53CD\u4EE3\u672A\u5C31\u7EEA\uFF0C\u53EF\u4E34\u65F6\u4F7F\u7528 http://\u670D\u52A1\u5668IP:\u7AEF\u53E3 \u5F62\u5F0F\u7684\u56DE\u8C03\u5730\u5740\u3002"
10947
+ )
10948
+ );
10949
+ }
10950
+ function AppSettingsEditor({ bot, busy, onSave }) {
10951
+ const [apiBaseUrl, setApiBaseUrl] = React20.useState(bot.apiBaseUrl ?? "");
10952
+ const [callbackBaseUrl, setCallbackBaseUrl] = React20.useState(bot.callbackBaseUrl ?? "");
10953
+ const [streamEnabled, setStreamEnabled] = React20.useState(bot.streamEnabled !== false);
10954
+ const [dirty, setDirty] = React20.useState(false);
10955
+ const formRef = React20.useRef(null);
10956
+ React20.useEffect(() => {
10957
+ setApiBaseUrl(bot.apiBaseUrl ?? "");
10958
+ setCallbackBaseUrl(bot.callbackBaseUrl ?? "");
10959
+ setStreamEnabled(bot.streamEnabled !== false);
10960
+ setDirty(false);
10961
+ }, [bot.apiBaseUrl, bot.callbackBaseUrl, bot.streamEnabled]);
10962
+ const touch = () => setDirty(true);
10963
+ const save = (event) => {
10964
+ event.preventDefault();
10965
+ if (!dirty || busy) return;
10966
+ void onSave({
10967
+ apiBaseUrl: apiBaseUrl.trim() || null,
10968
+ callbackBaseUrl: callbackBaseUrl.trim() || null,
10969
+ streamEnabled
10970
+ });
10971
+ setDirty(false);
10972
+ };
10973
+ return h2(
10974
+ "form",
10975
+ { ref: formRef, className: "dim-appFieldGrid", onSubmit: save },
10976
+ h2(Field, { label: "\u4EE3\u7406\u5730\u5740\uFF08\u53EF\u9009\uFF09", value: apiBaseUrl, onChange: (value) => {
10977
+ setApiBaseUrl(value);
10978
+ touch();
10979
+ }, placeholder: "\u7559\u7A7A\u76F4\u8FDE qyapi.weixin.qq.com", busy }),
10980
+ h2(Field, { label: "\u516C\u7F51\u56DE\u8C03\u57FA\u5740\uFF08\u53EF\u9009\uFF09", value: callbackBaseUrl, onChange: (value) => {
10981
+ setCallbackBaseUrl(value);
10982
+ touch();
10983
+ }, placeholder: "\u4F8B\u5982 https://im.example.com", busy }),
10984
+ h2(
10985
+ "div",
10986
+ { className: "dim-appSwitchRow" },
10987
+ h2("button", {
10988
+ type: "button",
10989
+ className: "ddt-button dim-streamToggle",
10990
+ "aria-pressed": streamEnabled ? "true" : "false",
10991
+ onClick: () => {
10992
+ setStreamEnabled((value) => !value);
10993
+ touch();
10994
+ },
10995
+ disabled: busy
10996
+ }, streamEnabled ? "\u6D41\u5F0F\u56DE\u590D\uFF1A\u5F00" : "\u6D41\u5F0F\u56DE\u590D\uFF1A\u5173")
10997
+ ),
10998
+ h2(
10999
+ "div",
11000
+ { className: "ddt-actions dim-viewActions" },
11001
+ h2(Button12, { onClick: () => formRef.current?.requestSubmit(), disabled: busy || !dirty }, busy ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58\u8BBE\u7F6E")
11002
+ )
11003
+ );
11004
+ }
11005
+ function RemoveConfirmation5({ account, busy, onConfirm, onCancel }) {
11006
+ return h2(
11007
+ "div",
11008
+ { className: "ddt-confirm dim-confirm", role: "alertdialog" },
11009
+ h2("strong", null, `\u4ECE DeepSeek Harness \u79FB\u9664\u201C${account.bot.name}\u201D\uFF1F`),
11010
+ h2("p", null, "\u8FD9\u4F1A\u5220\u9664\u672C\u673A\u4FDD\u5B58\u7684\u5E94\u7528\u51ED\u636E\u3001\u56DE\u8C03\u914D\u7F6E\u53CA\u4F1A\u8BDD\u6620\u5C04\u3002\u4F01\u4E1A\u5FAE\u4FE1\u540E\u53F0\u7684\u5E94\u7528\u4E0D\u4F1A\u88AB\u5220\u9664\u3002"),
11011
+ h2(
11012
+ "div",
11013
+ { className: "ddt-actions dim-viewActions" },
11014
+ h2(Button12, { onClick: onCancel, disabled: busy }, "\u4FDD\u7559\u5E94\u7528"),
11015
+ h2(Button12, { kind: "danger", onClick: onConfirm, disabled: busy }, busy ? "\u6B63\u5728\u79FB\u9664\u2026" : "\u786E\u8BA4\u79FB\u9664\u63A5\u5165")
11016
+ )
11017
+ );
11018
+ }
11019
+ function AccountCard4({
11020
+ account,
11021
+ busy,
11022
+ feedback,
11023
+ removing,
11024
+ onReconnect,
11025
+ onSettingsSave,
11026
+ onSecretReset,
11027
+ onWorkspaceSave,
11028
+ onModelSave,
11029
+ onAgentPresetSave,
11030
+ onContextEnhancementSave,
11031
+ onRequestRemove,
11032
+ onConfirmRemove,
11033
+ onCancelRemove
11034
+ }) {
11035
+ const tone = account.connected ? "success" : account.state === "error" ? "error" : "warning";
11036
+ const stateLabel2 = account.connected ? "\u8FD0\u884C\u6B63\u5E38" : account.state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA";
11037
+ const summary2 = account.error?.message ?? (account.connected ? null : account.health.summary);
11038
+ const elementId = `wecomapp-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, "-")}`;
11039
+ return h2(
11040
+ "article",
11041
+ { className: "ddt-card dim-botCard", "data-bot-id": account.botId },
11042
+ h2(
11043
+ "div",
11044
+ { className: "ddt-cardBody dim-botCardBody" },
11045
+ h2(
11046
+ CollapsibleAccountSection,
11047
+ {
11048
+ id: elementId,
11049
+ header: h2(
11050
+ "div",
11051
+ { className: "ddt-accountTop dim-botCardTop" },
11052
+ h2(
11053
+ "div",
11054
+ { className: "ddt-accountIdentity dim-botIdentity" },
11055
+ h2("div", { className: "ddt-avatar dim-botAvatar dwecomapp-avatar", "aria-hidden": "true" }, h2(WecomLogoGlyph, { size: 29 })),
11056
+ h2(
11057
+ "div",
11058
+ { className: "dim-botName" },
11059
+ h2("h3", null, account.bot.name),
11060
+ h2("p", null, `${account.bot.corpIdMasked} \xB7 AgentId ${account.bot.agentId}`)
11061
+ )
11062
+ ),
11063
+ h2(
11064
+ "div",
11065
+ {
11066
+ className: "dim-botCardTools",
11067
+ onClick: (event) => {
11068
+ event.stopPropagation();
11069
+ },
11070
+ onKeyDown: (event) => {
11071
+ if (event.key === "Enter" || event.key === " ") event.stopPropagation();
11072
+ }
11073
+ },
11074
+ h2(BotStatusMeta, {
11075
+ className: "ddt-health",
11076
+ dotClassName: "ddt-dot",
11077
+ tone,
11078
+ stateLabel: stateLabel2,
11079
+ lastCheckedAt: account.health.lastCheckedAt,
11080
+ formatCheckedTime: checkedTime5
11081
+ }),
11082
+ h2(BotSettingsButton, {
11083
+ channel: "wecomApp",
11084
+ botId: account.botId,
11085
+ botName: account.bot.name,
11086
+ connected: account.connected,
11087
+ accessPolicy: account.accessPolicy
11088
+ })
11089
+ )
11090
+ )
11091
+ },
11092
+ h2(CallbackUrlBox, {
11093
+ url: account.bot.callbackUrl,
11094
+ busy: Boolean(busy),
11095
+ resetBusy: busy === "reset",
11096
+ onReset: onSecretReset
11097
+ }),
11098
+ h2(AppSettingsEditor, {
11099
+ bot: account.bot,
11100
+ busy: Boolean(busy),
11101
+ onSave: onSettingsSave
11102
+ }),
11103
+ h2(WorkspaceEditor, {
11104
+ workspace: account.workspace,
11105
+ disabled: Boolean(busy),
11106
+ onSave: onWorkspaceSave
11107
+ }),
11108
+ h2(ModelEditor, {
11109
+ model: account.model,
11110
+ disabled: Boolean(busy),
11111
+ onSave: onModelSave
11112
+ }),
11113
+ h2(AgentPresetEditor, {
11114
+ agentPreset: account.agentPreset,
11115
+ disabled: Boolean(busy),
11116
+ onSave: onAgentPresetSave
11117
+ }),
11118
+ h2(ContextEnhancementEditor, {
11119
+ config: account.contextEnhancement,
11120
+ disabled: Boolean(busy),
11121
+ onSave: onContextEnhancementSave
11122
+ }),
11123
+ h2(
11124
+ "div",
11125
+ { className: "ddt-accountFooter dim-cardFooter" },
11126
+ h2(
11127
+ "div",
11128
+ { className: "dim-cardFooterLayout" },
11129
+ h2(
11130
+ "div",
11131
+ { className: "ddt-actions dim-cardActions" },
11132
+ h2(Button12, { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
11133
+ h2(Button12, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
11134
+ ),
11135
+ summary2 ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary2) : null,
11136
+ account.lastMessageError ? h2(LastMessageErrorSummary, {
11137
+ className: "ddt-summary",
11138
+ error: account.lastMessageError
11139
+ }) : null,
11140
+ feedback ? h2("div", {
11141
+ className: "ddt-summary dim-cardFeedback",
11142
+ role: "status",
11143
+ "aria-live": "polite"
11144
+ }, feedback) : null
11145
+ )
11146
+ )
11147
+ )
11148
+ ),
11149
+ removing ? h2(RemoveConfirmation5, {
11150
+ account,
11151
+ busy: busy === "delete",
11152
+ onConfirm: onConfirmRemove,
11153
+ onCancel: onCancelRemove
11154
+ }) : null
11155
+ );
11156
+ }
11157
+ function WecomAppSettingsTab({ rpcCall }) {
11158
+ const [model, setModel] = React20.useState({
11159
+ phase: "loading",
11160
+ bots: [],
11161
+ totals: { configured: 0, connected: 0 },
11162
+ error: null,
11163
+ agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG,
11164
+ modelCatalog: EMPTY_MODEL_CATALOG
11165
+ });
11166
+ const [bindOpen, setBindOpen] = React20.useState(false);
11167
+ const [bindError, setBindError] = React20.useState(null);
11168
+ const [busy, setBusy] = React20.useState(false);
11169
+ const [busyByBot, setBusyByBot] = React20.useState({});
11170
+ const [feedbackByBot, setFeedbackByBot] = React20.useState({});
11171
+ const [removeTarget, setRemoveTarget] = React20.useState(null);
11172
+ const [notice, setNotice] = React20.useState("");
11173
+ const mounted = React20.useRef(true);
11174
+ const workspaceFence = useWorkspaceSnapshotFence();
11175
+ const addButtonRef = React20.useRef(null);
11176
+ const noticeFrameRef = React20.useRef(null);
11177
+ const announce = React20.useCallback((message) => {
11178
+ if (!mounted.current) return;
11179
+ if (noticeFrameRef.current !== null) {
11180
+ window.cancelAnimationFrame(noticeFrameRef.current);
11181
+ noticeFrameRef.current = null;
11182
+ }
11183
+ setNotice("");
11184
+ if (message) {
11185
+ noticeFrameRef.current = window.requestAnimationFrame(() => {
11186
+ noticeFrameRef.current = null;
11187
+ if (mounted.current) setNotice(message);
11188
+ });
11189
+ }
11190
+ }, []);
11191
+ React20.useEffect(() => {
11192
+ const disposeDingtalk = installDingtalkStyles();
11193
+ const disposeWecomApp = installWecomAppStyles();
11194
+ mounted.current = true;
11195
+ return () => {
11196
+ mounted.current = false;
11197
+ if (noticeFrameRef.current !== null) {
11198
+ window.cancelAnimationFrame(noticeFrameRef.current);
11199
+ noticeFrameRef.current = null;
11200
+ }
11201
+ disposeWecomApp();
11202
+ disposeDingtalk();
11203
+ };
11204
+ }, []);
11205
+ const invoke = React20.useCallback(async (endpoint, payload = {}, signal) => {
11206
+ if (typeof rpcCall !== "function") throw new TypeError("\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
11207
+ return unwrapRpcResult8(await rpcCall(endpoint, payload, signal));
11208
+ }, [rpcCall]);
11209
+ const loadStatus = React20.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
11210
+ const workspaceVersion = workspaceFence.beginStatus();
11211
+ if (workspaceVersion === null) return void 0;
11212
+ if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
11213
+ try {
11214
+ const snapshot = normalizeSnapshot7(await invoke(WECOM_APP_ENDPOINTS.status, {}, signal));
11215
+ if (!mounted.current || signal?.aborted || !workspaceFence.canCommitStatus(workspaceVersion)) return void 0;
11216
+ setModel({
11217
+ phase: "ready",
11218
+ bots: snapshot.bots,
11219
+ totals: snapshot.totals,
11220
+ error: null,
11221
+ agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
11222
+ modelCatalog: snapshot.modelCatalog ?? EMPTY_MODEL_CATALOG
11223
+ });
11224
+ if (restore && snapshot.bots.length > 0) setBindOpen(false);
11225
+ return snapshot;
11226
+ } catch (error) {
11227
+ if (error?.name !== "AbortError" && mounted.current && !signal?.aborted && workspaceFence.canCommitStatus(workspaceVersion)) {
11228
+ setModel((current) => ({ ...current, phase: silent ? current.phase : "error", error: presentError8(error) }));
11229
+ }
11230
+ return void 0;
11231
+ }
11232
+ }, [invoke, workspaceFence]);
11233
+ React20.useEffect(() => {
11234
+ const controller = new AbortController();
11235
+ void loadStatus({ signal: controller.signal, restore: true });
11236
+ return () => controller.abort();
11237
+ }, [loadStatus]);
11238
+ React20.useEffect(() => {
11239
+ if (model.phase !== "ready") return void 0;
11240
+ const controller = new AbortController();
11241
+ const timer = window.setInterval(() => void loadStatus({ signal: controller.signal, silent: true }), 15e3);
11242
+ return () => {
11243
+ controller.abort();
11244
+ window.clearInterval(timer);
11245
+ };
11246
+ }, [loadStatus, model.phase]);
11247
+ const bindApp = React20.useCallback(async (payload) => {
11248
+ const snapshotVersion = workspaceFence.beginMutation();
11249
+ setBusy(true);
11250
+ setBindError(null);
11251
+ try {
11252
+ const snapshot = normalizeSnapshot7(await invoke(WECOM_APP_ENDPOINTS.bindApp, payload));
11253
+ if (!mounted.current) return;
11254
+ if (workspaceFence.canCommitMutation(snapshotVersion)) {
11255
+ setModel({
11256
+ phase: "ready",
11257
+ bots: snapshot.bots,
11258
+ totals: snapshot.totals,
11259
+ error: null,
11260
+ agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
11261
+ modelCatalog: snapshot.modelCatalog ?? EMPTY_MODEL_CATALOG
11262
+ });
11263
+ }
11264
+ setBindOpen(false);
11265
+ announce("\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u5DF2\u7ED1\u5B9A\u3002\u8BF7\u628A\u56DE\u8C03 URL \u586B\u5165\u4F01\u4E1A\u5FAE\u4FE1\u540E\u53F0\u5E76\u4FDD\u5B58\u3002");
11266
+ } catch (error) {
11267
+ if (mounted.current) setBindError(presentError8(error));
11268
+ } finally {
11269
+ const shouldRefresh = workspaceFence.endMutation();
11270
+ if (shouldRefresh && mounted.current) void loadStatus({ silent: true });
11271
+ if (mounted.current) setBusy(false);
11272
+ }
11273
+ }, [announce, invoke, loadStatus, workspaceFence]);
11274
+ const botAction = React20.useCallback(async (account, operation, endpoint, payload) => {
11275
+ const snapshotVersion = workspaceFence.beginMutation();
11276
+ setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
11277
+ try {
11278
+ const snapshot = normalizeSnapshot7(await invoke(endpoint, payload));
11279
+ if (mounted.current && workspaceFence.canCommitMutation(snapshotVersion)) {
11280
+ setModel({
11281
+ phase: "ready",
11282
+ bots: snapshot.bots,
11283
+ totals: snapshot.totals,
11284
+ error: null,
11285
+ agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
11286
+ modelCatalog: snapshot.modelCatalog ?? EMPTY_MODEL_CATALOG
11287
+ });
11288
+ }
11289
+ return snapshot;
11290
+ } finally {
11291
+ const shouldRefresh = workspaceFence.endMutation();
11292
+ if (shouldRefresh && mounted.current) void loadStatus({ silent: true });
11293
+ if (mounted.current) setBusyByBot((current) => {
11294
+ const next = { ...current };
11295
+ delete next[account.botId];
11296
+ return next;
11297
+ });
11298
+ }
11299
+ }, [invoke, loadStatus, workspaceFence]);
11300
+ const reconnect = React20.useCallback(async (account) => {
11301
+ setFeedbackByBot((current) => {
11302
+ const next = { ...current };
11303
+ delete next[account.botId];
11304
+ return next;
11305
+ });
11306
+ try {
11307
+ const snapshot = await botAction(
11308
+ account,
11309
+ "reconnect",
11310
+ WECOM_APP_ENDPOINTS.reconnectBot,
11311
+ { botId: account.botId, sendTest: true }
11312
+ );
11313
+ if (!snapshot) return;
11314
+ const refreshed = snapshot.bots.find((bot) => bot.botId === account.botId);
11315
+ let feedback;
11316
+ if (!refreshed?.connected) {
11317
+ feedback = "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u4ECD\u672A\u5C31\u7EEA\uFF0C\u63D2\u4EF6\u4F1A\u7EE7\u7EED\u81EA\u52A8\u91CD\u8BD5\u3002";
11318
+ } else if (snapshot.testMessage?.sent) {
11319
+ feedback = "\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\u3002";
11320
+ } else if (snapshot.testMessage?.code === "test-target-unavailable") {
11321
+ feedback = "\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\u3002\u5E94\u7528\u5C1A\u672A\u6536\u5230\u53EF\u7528\u4E8E\u6D4B\u8BD5\u7684\u79C1\u804A\u6D88\u606F\u3002";
11322
+ } else if (snapshot.testMessage) {
11323
+ feedback = "\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002";
11324
+ } else {
11325
+ feedback = "\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\u3002";
11326
+ }
11327
+ if (mounted.current) {
11328
+ setFeedbackByBot((current) => ({ ...current, [account.botId]: feedback }));
11329
+ }
11330
+ announce(feedback);
11331
+ } catch {
11332
+ const feedback = "\u8FDE\u63A5\u68C0\u67E5\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002";
11333
+ if (mounted.current) {
11334
+ setFeedbackByBot((current) => ({ ...current, [account.botId]: feedback }));
11335
+ }
11336
+ announce(feedback);
11337
+ }
11338
+ }, [announce, botAction]);
11339
+ const botList = model.bots.length > 0 ? h2(
11340
+ "section",
11341
+ { className: "dim-listSection" },
11342
+ h2(ChannelListHeading, {
11343
+ className: "ddt-listHeading",
11344
+ title: "\u5DF2\u7ED1\u5B9A\u7684\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528",
11345
+ connectionLabel: "HTTP \u56DE\u8C03\u901A\u9053"
11346
+ }),
11347
+ h2("ul", { className: "ddt-list dim-botList" }, model.bots.map((account) => h2("li", { key: account.botId }, h2(AccountCard4, {
11348
+ account,
11349
+ busy: busyByBot[account.botId],
11350
+ feedback: feedbackByBot[account.botId],
11351
+ removing: removeTarget === account.botId,
11352
+ onReconnect: () => void reconnect(account),
11353
+ onSettingsSave: (settings) => botAction(
11354
+ account,
11355
+ "settings",
11356
+ WECOM_APP_ENDPOINTS.updateSettings,
11357
+ { botId: account.botId, ...settings }
11358
+ ),
11359
+ onSecretReset: async () => {
11360
+ try {
11361
+ await botAction(account, "reset", WECOM_APP_ENDPOINTS.resetCallbackSecret, { botId: account.botId });
11362
+ announce("\u56DE\u8C03\u5BC6\u94A5\u5DF2\u91CD\u7F6E\uFF0C\u8BF7\u628A\u65B0\u7684\u56DE\u8C03 URL \u66F4\u65B0\u5230\u4F01\u4E1A\u5FAE\u4FE1\u540E\u53F0\u3002");
11363
+ } catch {
11364
+ announce("\u56DE\u8C03\u5BC6\u94A5\u91CD\u7F6E\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
11365
+ }
11366
+ },
11367
+ onWorkspaceSave: (workspace) => botAction(
11368
+ account,
11369
+ "workspace",
11370
+ WECOM_APP_ENDPOINTS.setWorkspace,
11371
+ { botId: account.botId, workspace }
11372
+ ),
11373
+ onModelSave: (selectedModel) => botAction(
11374
+ account,
11375
+ "model",
11376
+ WECOM_APP_ENDPOINTS.setModel,
11377
+ { botId: account.botId, model: selectedModel }
11378
+ ),
11379
+ onAgentPresetSave: (agentPreset) => botAction(
11380
+ account,
11381
+ "preset",
11382
+ WECOM_APP_ENDPOINTS.setAgentPreset,
11383
+ { botId: account.botId, agentPreset }
11384
+ ),
11385
+ onContextEnhancementSave: (config) => botAction(
11386
+ account,
11387
+ "context-enhancement",
11388
+ WECOM_APP_ENDPOINTS.setContextEnhancement,
11389
+ { botId: account.botId, config }
11390
+ ),
11391
+ onRequestRemove: () => setRemoveTarget(account.botId),
11392
+ onCancelRemove: () => setRemoveTarget(null),
11393
+ onConfirmRemove: async () => {
11394
+ await botAction(account, "delete", WECOM_APP_ENDPOINTS.deleteBot, { botId: account.botId, confirm: true });
11395
+ if (mounted.current) setRemoveTarget(null);
11396
+ }
11397
+ }))))
11398
+ ) : null;
11399
+ const bindView = bindOpen ? h2(BindForm, {
11400
+ busy,
11401
+ error: bindError,
11402
+ onSubmit: bindApp,
11403
+ onCancel: () => {
11404
+ setBindOpen(false);
11405
+ setBindError(null);
11406
+ }
11407
+ }) : null;
11408
+ return h2(ModelCatalogContext.Provider, {
11409
+ value: model.modelCatalog ?? EMPTY_MODEL_CATALOG
11410
+ }, h2(AgentPresetCatalogContext.Provider, {
11411
+ value: model.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
11412
+ }, h2(
11413
+ "section",
11414
+ { className: "ddt-page dwecomapp-page dim-channelPage", "aria-label": "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u8BBE\u7F6E" },
11415
+ h2(Heading5, {
11416
+ totals: model.totals,
11417
+ adding: bindOpen,
11418
+ busy,
11419
+ onAdd: () => {
11420
+ setBindOpen((value) => !value);
11421
+ setBindError(null);
11422
+ },
11423
+ addButtonRef
11424
+ }),
11425
+ h2("div", { className: "ddt-visuallyHidden", role: "status", "aria-live": "polite" }, notice),
11426
+ model.phase === "loading" ? h2(LoadingView5) : model.phase === "error" ? h2("div", { className: "ddt-card dim-surfaceCard" }, h2("div", { className: "ddt-inlineError dim-inlineError" }, h2("h3", null, "\u65E0\u6CD5\u8BFB\u53D6\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528\u72B6\u6001"), h2("p", null, model.error?.message), h2(Button12, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6"))) : h2(
11427
+ React20.Fragment,
11428
+ null,
11429
+ bindView,
11430
+ model.bots.length === 0 && !bindOpen ? h2(EmptyView5, { busy, onStart: () => setBindOpen(true) }) : null,
11431
+ botList
11432
+ )
11433
+ )));
11434
+ }
11435
+
11436
+ // plugin-src/client/channels/weixin/index.js
11437
+ var React21 = __toESM(require("react"), 1);
11438
+
11439
+ // plugin-src/client/channels/weixin/api.js
11440
+ var WEIXIN_RPC_CHANNEL = "/weixin";
11441
+ var WEIXIN_ENDPOINTS = Object.freeze({
11442
+ status: "connection.status",
11443
+ beginProvisioning: "provision.begin",
11444
+ pollProvisioning: "provision.poll",
11445
+ submitVerification: "provision.verify",
11446
+ cancelProvisioning: "provision.cancel",
11447
+ reconnectBot: "bot.reconnect",
11448
+ deleteBot: "bot.delete",
11449
+ setWorkspace: "bot.workspace.set",
11450
+ setModel: SET_MODEL_ENDPOINT,
11451
+ setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
11452
+ setContextEnhancement: "bot.context-enhancement.set",
11453
+ setAccessPolicy: "bot.access-policy.set"
11454
+ });
11455
+ var ACCOUNT_STATES6 = /* @__PURE__ */ new Set(["connected", "connecting", "offline", "error"]);
11456
+ var PROVISION_STATES4 = /* @__PURE__ */ new Set([
11457
+ "starting",
11458
+ "pending",
11459
+ "scanned",
11460
+ "needs_verification",
11461
+ "connecting",
11462
+ "connected",
11463
+ "expired",
11464
+ "failed",
11465
+ "cancelled"
11466
+ ]);
11467
+ function isRecord7(value) {
11468
+ return value !== null && typeof value === "object" && !Array.isArray(value);
11469
+ }
11470
+ function string(value, fallback = "") {
11471
+ return typeof value === "string" && value.trim() ? value.trim() : fallback;
11472
+ }
11473
+ function timestamp6(value) {
11474
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
11475
+ }
11476
+ function normalizeTestMessage5(value) {
11477
+ if (!isRecord7(value)) return null;
11478
+ if (value.sent === true) return { sent: true };
11479
+ if (value.sent !== false) return null;
11480
+ const code = value.code === "test-target-unavailable" ? "test-target-unavailable" : "test-message-failed";
11481
+ return { sent: false, code };
11482
+ }
11483
+ function unwrapRpcResult9(result) {
11484
+ if (!isRecord7(result) || typeof result.ok !== "boolean") {
11485
+ throw new Error("\u5FAE\u4FE1\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94");
11486
+ }
11487
+ if (!result.ok) {
11488
+ const error = new Error(string(result.error?.message, "\u5FAE\u4FE1\u64CD\u4F5C\u5931\u8D25"));
11489
+ error.code = string(result.error?.code, "WEIXIN_RPC_ERROR");
11490
+ throw error;
11491
+ }
11492
+ return result.value;
11493
+ }
11494
+ function safeQrSource5(value) {
11495
+ return typeof value === "string" && /^data:image\/(?:png|webp|svg\+xml)(?:;charset=[^;,]+)?;base64,/i.test(value) ? value : void 0;
11496
+ }
11497
+ function safeVerificationUrl(value) {
11498
+ if (typeof value !== "string") return void 0;
11499
+ try {
11500
+ const url = new URL(value);
11501
+ const host = url.hostname.toLowerCase();
11502
+ return url.protocol === "https:" && (host === "weixin.qq.com" || host.endsWith(".weixin.qq.com") || host === "wechat.com" || host.endsWith(".wechat.com")) ? url.toString() : void 0;
11503
+ } catch {
11504
+ return void 0;
11505
+ }
11506
+ }
11507
+ function normalizeProvisioning5(value) {
11508
+ if (!isRecord7(value) || !string(value.attemptId)) {
11509
+ throw new Error("\u5FAE\u4FE1\u626B\u7801\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u7ED1\u5B9A\u4EFB\u52A1");
11510
+ }
11511
+ const status = PROVISION_STATES4.has(value.status) ? value.status : "failed";
11512
+ const result = {
11513
+ attemptId: string(value.attemptId),
11514
+ status,
11515
+ expiresAt: timestamp6(value.expiresAt) ?? Date.now(),
11516
+ pollIntervalMs: Math.min(5e3, Math.max(500, Number(value.pollIntervalMs) || 1e3)),
11517
+ verificationRequired: value.verificationRequired === true || status === "needs_verification"
11518
+ };
11519
+ const verificationUrl = safeVerificationUrl(value.verificationUrl);
11520
+ const qrCodeDataUrl = safeQrSource5(value.qrCodeDataUrl);
11521
+ if (verificationUrl) result.verificationUrl = verificationUrl;
11522
+ if (qrCodeDataUrl) result.qrCodeDataUrl = qrCodeDataUrl;
11523
+ if (string(value.botId)) result.botId = string(value.botId);
11524
+ if (value.alreadyConnected === true) result.alreadyConnected = true;
11525
+ if (isRecord7(value.error)) {
11526
+ result.error = {
11527
+ code: string(value.error.code, "WEIXIN_PROVISION_FAILED"),
11528
+ message: string(value.error.message, "\u5FAE\u4FE1\u7ED1\u5B9A\u6CA1\u6709\u5B8C\u6210")
11529
+ };
11530
+ }
11531
+ return result;
11532
+ }
11533
+ function normalizeBot6(value) {
11534
+ if (!isRecord7(value) || !string(value.botId) || !isRecord7(value.bot)) return null;
11535
+ const state = ACCOUNT_STATES6.has(value.state) ? value.state : "error";
11536
+ const connected = value.connected === true;
11537
+ return {
11538
+ botId: string(value.botId),
11539
+ state: connected ? "connected" : state,
11540
+ connected,
11541
+ configured: value.configured === true,
11542
+ workspace: string(value.workspace).slice(0, 4096),
11543
+ model: normalizeModelSelection(value.model),
11544
+ agentPreset: normalizeAgentPresetId(value.agentPreset),
11545
+ contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
11546
+ ...Object.hasOwn(value, "accessPolicy") ? { accessPolicy: normalizeAccessPolicy(value.accessPolicy) } : {},
11547
+ bot: {
11548
+ name: string(value.bot.name, "\u5FAE\u4FE1\u673A\u5668\u4EBA"),
11549
+ accountIdMasked: string(value.bot.accountIdMasked, "\u5DF2\u5B89\u5168\u4FDD\u5B58")
11550
+ },
11551
+ health: {
11552
+ status: string(value.health?.status, connected ? "healthy" : "offline"),
11553
+ summary: string(value.health?.summary, connected ? "\u5FAE\u4FE1\u8FDE\u63A5\u6B63\u5E38" : "\u5FAE\u4FE1\u8FDE\u63A5\u672A\u5C31\u7EEA"),
11554
+ lastCheckedAt: timestamp6(value.health?.lastCheckedAt)
11555
+ },
11556
+ stats: {
11557
+ messagesReceived: Math.max(0, Number(value.stats?.messagesReceived) || 0),
11558
+ messagesReplied: Math.max(0, Number(value.stats?.messagesReplied) || 0)
11559
+ },
11560
+ lastMessageError: normalizeLastMessageError(value.lastMessageError),
11561
+ error: isRecord7(value.error) ? {
11562
+ code: string(value.error.code, "WEIXIN_ACCOUNT_ERROR"),
11563
+ message: string(value.error.message, "\u5FAE\u4FE1\u8FDE\u63A5\u672A\u5C31\u7EEA")
11564
+ } : null
11565
+ };
11566
+ }
11567
+ function normalizeSnapshot8(value) {
11568
+ if (!isRecord7(value) || !Array.isArray(value.bots)) {
11569
+ throw new Error("\u5FAE\u4FE1\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u8D26\u53F7\u5217\u8868");
11570
+ }
11571
+ const bots = value.bots.map(normalizeBot6).filter(Boolean);
11572
+ return {
11573
+ schemaVersion: Number(value.schemaVersion) || 1,
11574
+ revision: Number(value.revision) || 0,
11575
+ state: string(value.state, "offline"),
11576
+ bots,
11577
+ totals: {
11578
+ configured: bots.length,
11579
+ connected: bots.filter((bot) => bot.connected).length
11580
+ },
11581
+ provisioning: value.provisioning ? normalizeProvisioning5(value.provisioning) : null,
11582
+ testMessage: normalizeTestMessage5(value.testMessage),
11583
+ agentPresetCatalog: normalizeAgentPresetCatalog(value.agentPresetCatalog),
11584
+ modelCatalog: normalizeModelCatalog(value.modelCatalog)
11585
+ };
11586
+ }
11587
+ function presentError9(error) {
11588
+ return {
11589
+ code: string(error?.code, "WEIXIN_ERROR"),
11590
+ message: string(error?.message, "\u5FAE\u4FE1\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")
11591
+ };
11592
+ }
11593
+ function formatRemaining5(milliseconds) {
11594
+ const seconds = Math.max(0, Math.ceil(milliseconds / 1e3));
11595
+ return `${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, "0")}`;
11596
+ }
11597
+
11598
+ // plugin-src/client/channels/weixin/index.js
11599
+ var Button14 = React21.forwardRef(function Button15({ children, kind = "secondary", className = "", ...props }, ref) {
11600
+ return h2("button", {
11601
+ ...props,
11602
+ ref,
11603
+ type: "button",
11604
+ className: `dxw-button ${className}`.trim(),
11605
+ "data-kind": kind
11606
+ }, children);
11607
+ });
11608
+ function Heading6({ totals, adding, busy, onAdd, addButtonRef }) {
11609
+ return h2(
11610
+ "div",
11611
+ { className: "dxw-heading" },
11612
+ h2(
11613
+ "div",
11614
+ { className: "dxw-tools" },
11615
+ h2(Button14, {
11616
+ kind: "primary",
11617
+ className: "dim-scanButton",
11618
+ onClick: onAdd,
11619
+ disabled: adding || busy,
11620
+ ref: addButtonRef,
11621
+ "aria-label": "\u626B\u7801\u63A5\u5165\u5FAE\u4FE1\u673A\u5668\u4EBA"
11622
+ }, h2(QrActionIcon), adding ? "\u6B63\u5728\u63A5\u5165" : "\u626B\u7801\u63A5\u5165\u673A\u5668\u4EBA"),
10543
11623
  totals.configured > 0 ? h2(
10544
11624
  "div",
10545
11625
  { className: "dxw-badge dim-onlineBadge" },
@@ -10548,7 +11628,7 @@ function Heading5({ totals, adding, busy, onAdd, addButtonRef }) {
10548
11628
  )
10549
11629
  );
10550
11630
  }
10551
- function LoadingView5() {
11631
+ function LoadingView6() {
10552
11632
  return h2(
10553
11633
  "div",
10554
11634
  { className: "dxw-card dxw-loading dim-surfaceCard dim-loadingView", "aria-busy": "true" },
@@ -10556,7 +11636,7 @@ function LoadingView5() {
10556
11636
  h2("span", null, "\u6B63\u5728\u8BFB\u53D6\u5FAE\u4FE1\u8FDE\u63A5\u72B6\u6001\u2026")
10557
11637
  );
10558
11638
  }
10559
- function EmptyView5({ onStart, busy }) {
11639
+ function EmptyView6({ onStart, busy }) {
10560
11640
  return h2(
10561
11641
  "div",
10562
11642
  { className: "dxw-card dim-surfaceCard" },
@@ -10578,7 +11658,7 @@ function EmptyView5({ onStart, busy }) {
10578
11658
  "div",
10579
11659
  { className: "dxw-actions dim-viewActions" },
10580
11660
  h2(
10581
- Button12,
11661
+ Button14,
10582
11662
  { kind: "primary", onClick: onStart, disabled: busy },
10583
11663
  busy ? "\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801\u2026" : "\u751F\u6210\u5FAE\u4FE1\u4E8C\u7EF4\u7801"
10584
11664
  )
@@ -10589,14 +11669,14 @@ function EmptyView5({ onStart, busy }) {
10589
11669
  );
10590
11670
  }
10591
11671
  function QrPanel4({ provision, now, busy, onRefresh, onCancel }) {
10592
- const [imageFailed, setImageFailed] = React20.useState(false);
11672
+ const [imageFailed, setImageFailed] = React21.useState(false);
10593
11673
  const source = safeQrSource5(provision.qrCodeDataUrl);
10594
11674
  const href = safeVerificationUrl(provision.verificationUrl);
10595
11675
  const remaining = Math.max(0, provision.expiresAt - now);
10596
11676
  const expired = remaining === 0 || provision.status === "expired";
10597
11677
  const duration = Math.max(1, provision.durationMs ?? 5 * 6e4);
10598
11678
  const progress = Math.round(Math.min(1, remaining / duration) * 100);
10599
- React20.useEffect(() => setImageFailed(false), [source]);
11679
+ React21.useEffect(() => setImageFailed(false), [source]);
10600
11680
  return h2(
10601
11681
  "div",
10602
11682
  { className: "dxw-card dim-surfaceCard" },
@@ -10648,24 +11728,24 @@ function QrPanel4({ provision, now, busy, onRefresh, onCancel }) {
10648
11728
  h2(
10649
11729
  "div",
10650
11730
  { className: "dxw-actions dim-viewActions" },
10651
- expired ? h2(Button12, { kind: "primary", onClick: onRefresh, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801") : null,
11731
+ expired ? h2(Button14, { kind: "primary", onClick: onRefresh, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801") : null,
10652
11732
  href ? h2("a", {
10653
11733
  className: "dxw-button",
10654
11734
  href,
10655
11735
  target: "_blank",
10656
11736
  rel: "noopener noreferrer"
10657
11737
  }, "\u6253\u5F00\u5907\u7528\u94FE\u63A5") : null,
10658
- !expired ? h2(Button12, { onClick: onRefresh, disabled: busy }, "\u6362\u4E00\u4E2A\u4E8C\u7EF4\u7801") : null,
10659
- h2(Button12, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88")
11738
+ !expired ? h2(Button14, { onClick: onRefresh, disabled: busy }, "\u6362\u4E00\u4E2A\u4E8C\u7EF4\u7801") : null,
11739
+ h2(Button14, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88")
10660
11740
  )
10661
11741
  )
10662
11742
  )
10663
11743
  );
10664
11744
  }
10665
11745
  function VerificationPanel({ provision, busy, onSubmit, onCancel }) {
10666
- const [code, setCode] = React20.useState("");
11746
+ const [code, setCode] = React21.useState("");
10667
11747
  const valid = /^\d{4,8}$/.test(code);
10668
- React20.useEffect(() => setCode(""), [provision.attemptId]);
11748
+ React21.useEffect(() => setCode(""), [provision.attemptId]);
10669
11749
  return h2(
10670
11750
  "div",
10671
11751
  { className: "dxw-card dim-surfaceCard" },
@@ -10706,7 +11786,7 @@ function VerificationPanel({ provision, busy, onSubmit, onCancel }) {
10706
11786
  disabled: !valid || busy
10707
11787
  }, busy ? "\u6B63\u5728\u9A8C\u8BC1\u2026" : "\u7EE7\u7EED\u8FDE\u63A5")
10708
11788
  ),
10709
- h2(Button12, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88\u7ED1\u5B9A")
11789
+ h2(Button14, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88\u7ED1\u5B9A")
10710
11790
  )
10711
11791
  );
10712
11792
  }
@@ -10720,7 +11800,7 @@ function ProgressPanel2({ scanned, onCancel, busy }) {
10720
11800
  onCancel ? h2(
10721
11801
  "div",
10722
11802
  { className: "dxw-actions dim-viewActions", style: { justifyContent: "center", marginTop: 14 } },
10723
- h2(Button12, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88")
11803
+ h2(Button14, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88")
10724
11804
  ) : null
10725
11805
  );
10726
11806
  }
@@ -10738,25 +11818,25 @@ function ProvisionError3({ provision, busy, onRetry, onClose }) {
10738
11818
  h2(
10739
11819
  "div",
10740
11820
  { className: "dxw-actions dim-viewActions" },
10741
- h2(Button12, { kind: "primary", onClick: onRetry, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801"),
10742
- h2(Button12, { onClick: onClose, disabled: busy }, "\u5173\u95ED")
11821
+ h2(Button14, { kind: "primary", onClick: onRetry, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801"),
11822
+ h2(Button14, { onClick: onClose, disabled: busy }, "\u5173\u95ED")
10743
11823
  )
10744
11824
  )
10745
11825
  );
10746
11826
  }
10747
- function checkedTime5(timestamp7) {
10748
- if (!timestamp7) return "\u5C1A\u672A\u68C0\u67E5";
11827
+ function checkedTime6(timestamp8) {
11828
+ if (!timestamp8) return "\u5C1A\u672A\u68C0\u67E5";
10749
11829
  try {
10750
11830
  return new Intl.DateTimeFormat("zh-CN", {
10751
11831
  hour: "2-digit",
10752
11832
  minute: "2-digit",
10753
11833
  second: "2-digit"
10754
- }).format(new Date(timestamp7));
11834
+ }).format(new Date(timestamp8));
10755
11835
  } catch {
10756
11836
  return "\u521A\u521A";
10757
11837
  }
10758
11838
  }
10759
- function AccountCard4({
11839
+ function AccountCard5({
10760
11840
  account,
10761
11841
  busy,
10762
11842
  feedback,
@@ -10810,7 +11890,7 @@ function AccountCard4({
10810
11890
  tone,
10811
11891
  stateLabel: account.connected ? "\u8FD0\u884C\u6B63\u5E38" : state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA",
10812
11892
  lastCheckedAt: account.health.lastCheckedAt,
10813
- formatCheckedTime: checkedTime5
11893
+ formatCheckedTime: checkedTime6
10814
11894
  }),
10815
11895
  h2(BotSettingsButton, {
10816
11896
  channel: "weixin",
@@ -10853,11 +11933,11 @@ function AccountCard4({
10853
11933
  "div",
10854
11934
  { className: "dxw-actions dim-cardActions" },
10855
11935
  h2(
10856
- Button12,
11936
+ Button14,
10857
11937
  { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) },
10858
11938
  busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"
10859
11939
  ),
10860
- h2(Button12, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
11940
+ h2(Button14, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
10861
11941
  ),
10862
11942
  summary2 ? h2("div", { className: "dxw-summary dim-cardSummary" }, summary2) : null,
10863
11943
  account.lastMessageError ? h2(LastMessageErrorSummary, {
@@ -10881,9 +11961,9 @@ function AccountCard4({
10881
11961
  h2(
10882
11962
  "div",
10883
11963
  { className: "dxw-actions dim-viewActions" },
10884
- h2(Button12, { onClick: onCancelRemove, disabled: busy === "delete" }, "\u4FDD\u7559\u8D26\u53F7"),
11964
+ h2(Button14, { onClick: onCancelRemove, disabled: busy === "delete" }, "\u4FDD\u7559\u8D26\u53F7"),
10885
11965
  h2(
10886
- Button12,
11966
+ Button14,
10887
11967
  { kind: "danger", onClick: onConfirmRemove, disabled: busy === "delete" },
10888
11968
  busy === "delete" ? "\u6B63\u5728\u79FB\u9664\u2026" : "\u786E\u8BA4\u79FB\u9664"
10889
11969
  )
@@ -10903,7 +11983,7 @@ function AccountList2(props) {
10903
11983
  h2("ul", { className: "dxw-list dim-botList" }, props.bots.map((account) => h2(
10904
11984
  "li",
10905
11985
  { key: account.botId },
10906
- h2(AccountCard4, {
11986
+ h2(AccountCard5, {
10907
11987
  account,
10908
11988
  busy: props.busyByBot[account.botId],
10909
11989
  feedback: props.feedbackByBot[account.botId],
@@ -10931,7 +12011,7 @@ function mergeWeixinProvisioningSnapshot(current, incoming, { restoreProvisionin
10931
12011
  };
10932
12012
  }
10933
12013
  function WeixinSettingsTab({ rpcCall }) {
10934
- const [model, setModel] = React20.useState({
12014
+ const [model, setModel] = React21.useState({
10935
12015
  phase: "loading",
10936
12016
  bots: [],
10937
12017
  totals: EMPTY_TOTALS3,
@@ -10940,33 +12020,33 @@ function WeixinSettingsTab({ rpcCall }) {
10940
12020
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG,
10941
12021
  modelCatalog: EMPTY_MODEL_CATALOG
10942
12022
  });
10943
- const [provision, setProvision] = React20.useState(null);
10944
- const [busy, setBusy] = React20.useState(false);
10945
- const [busyByBot, setBusyByBot] = React20.useState({});
10946
- const [feedbackByBot, setFeedbackByBot] = React20.useState({});
10947
- const [removeTarget, setRemoveTarget] = React20.useState(null);
10948
- const [notice, setNotice] = React20.useState("");
10949
- const [now, setNow] = React20.useState(() => Date.now());
10950
- const addButtonRef = React20.useRef(null);
10951
- const mountedRef = React20.useRef(true);
12023
+ const [provision, setProvision] = React21.useState(null);
12024
+ const [busy, setBusy] = React21.useState(false);
12025
+ const [busyByBot, setBusyByBot] = React21.useState({});
12026
+ const [feedbackByBot, setFeedbackByBot] = React21.useState({});
12027
+ const [removeTarget, setRemoveTarget] = React21.useState(null);
12028
+ const [notice, setNotice] = React21.useState("");
12029
+ const [now, setNow] = React21.useState(() => Date.now());
12030
+ const addButtonRef = React21.useRef(null);
12031
+ const mountedRef = React21.useRef(true);
10952
12032
  const workspaceFence = useWorkspaceSnapshotFence();
10953
12033
  const scheduleAnimationFrame = useAnimationFrameScheduler();
10954
- React20.useEffect(() => {
12034
+ React21.useEffect(() => {
10955
12035
  mountedRef.current = true;
10956
12036
  return () => {
10957
12037
  mountedRef.current = false;
10958
12038
  };
10959
12039
  }, []);
10960
- const announce = React20.useCallback((value) => {
12040
+ const announce = React21.useCallback((value) => {
10961
12041
  setNotice("");
10962
12042
  scheduleAnimationFrame(() => {
10963
12043
  if (value) setNotice(value);
10964
12044
  }, "announcement");
10965
12045
  }, [scheduleAnimationFrame]);
10966
- const invoke = React20.useCallback(async (endpoint, payload = {}, signal) => {
10967
- return unwrapRpcResult8(await rpcCall(endpoint, payload, signal));
12046
+ const invoke = React21.useCallback(async (endpoint, payload = {}, signal) => {
12047
+ return unwrapRpcResult9(await rpcCall(endpoint, payload, signal));
10968
12048
  }, [rpcCall]);
10969
- const loadStatus = React20.useCallback(async ({
12049
+ const loadStatus = React21.useCallback(async ({
10970
12050
  signal,
10971
12051
  silent = false,
10972
12052
  restoreProvisioning = false
@@ -10975,7 +12055,7 @@ function WeixinSettingsTab({ rpcCall }) {
10975
12055
  if (workspaceVersion === null || !mountedRef.current) return void 0;
10976
12056
  if (!silent) setModel((current) => ({ ...current, phase: "loading", error: null }));
10977
12057
  try {
10978
- const snapshot = normalizeSnapshot7(await invoke(WEIXIN_ENDPOINTS.status, {}, signal));
12058
+ const snapshot = normalizeSnapshot8(await invoke(WEIXIN_ENDPOINTS.status, {}, signal));
10979
12059
  if (signal?.aborted || !mountedRef.current || !workspaceFence.canCommitStatus(workspaceVersion)) return void 0;
10980
12060
  setModel({
10981
12061
  phase: "ready",
@@ -10999,17 +12079,17 @@ function WeixinSettingsTab({ rpcCall }) {
10999
12079
  setModel((current) => ({
11000
12080
  ...current,
11001
12081
  phase: silent && current.phase === "ready" ? "ready" : "error",
11002
- error: presentError8(error)
12082
+ error: presentError9(error)
11003
12083
  }));
11004
12084
  return void 0;
11005
12085
  }
11006
12086
  }, [invoke, workspaceFence]);
11007
- React20.useEffect(() => {
12087
+ React21.useEffect(() => {
11008
12088
  const controller = new AbortController();
11009
12089
  void loadStatus({ signal: controller.signal, restoreProvisioning: true });
11010
12090
  return () => controller.abort();
11011
12091
  }, [loadStatus]);
11012
- React20.useEffect(() => {
12092
+ React21.useEffect(() => {
11013
12093
  if (model.phase !== "ready") return void 0;
11014
12094
  const controller = new AbortController();
11015
12095
  let running = false;
@@ -11028,12 +12108,12 @@ function WeixinSettingsTab({ rpcCall }) {
11028
12108
  window.clearInterval(timer);
11029
12109
  };
11030
12110
  }, [loadStatus, model.phase]);
11031
- React20.useEffect(() => {
12111
+ React21.useEffect(() => {
11032
12112
  if (!provision || !["pending", "scanned"].includes(provision.status)) return void 0;
11033
12113
  const timer = window.setInterval(() => setNow(Date.now()), 1e3);
11034
12114
  return () => window.clearInterval(timer);
11035
12115
  }, [provision?.attemptId, provision?.status]);
11036
- const startProvisioning = React20.useCallback(async ({ replace = false } = {}) => {
12116
+ const startProvisioning = React21.useCallback(async ({ replace = false } = {}) => {
11037
12117
  setBusy(true);
11038
12118
  try {
11039
12119
  if (replace && provision?.attemptId) {
@@ -11047,14 +12127,14 @@ function WeixinSettingsTab({ rpcCall }) {
11047
12127
  } catch (error) {
11048
12128
  setProvision({
11049
12129
  status: "failed",
11050
- error: presentError8(error),
12130
+ error: presentError9(error),
11051
12131
  ...provision?.attemptId ? { attemptId: provision.attemptId } : {}
11052
12132
  });
11053
12133
  } finally {
11054
12134
  setBusy(false);
11055
12135
  }
11056
12136
  }, [announce, invoke, provision?.attemptId]);
11057
- const cancelProvisioning = React20.useCallback(async () => {
12137
+ const cancelProvisioning = React21.useCallback(async () => {
11058
12138
  setBusy(true);
11059
12139
  try {
11060
12140
  if (provision?.attemptId && !["failed", "expired", "cancelled"].includes(provision.status)) {
@@ -11064,12 +12144,12 @@ function WeixinSettingsTab({ rpcCall }) {
11064
12144
  announce("\u5DF2\u53D6\u6D88\u5FAE\u4FE1\u7ED1\u5B9A\u3002");
11065
12145
  scheduleAnimationFrame(() => addButtonRef.current?.focus(), "focus");
11066
12146
  } catch (error) {
11067
- setProvision((current) => ({ ...current, status: "failed", error: presentError8(error) }));
12147
+ setProvision((current) => ({ ...current, status: "failed", error: presentError9(error) }));
11068
12148
  } finally {
11069
12149
  setBusy(false);
11070
12150
  }
11071
12151
  }, [announce, invoke, provision?.attemptId, provision?.status, scheduleAnimationFrame]);
11072
- const submitVerification = React20.useCallback(async (verifyCode) => {
12152
+ const submitVerification = React21.useCallback(async (verifyCode) => {
11073
12153
  if (!provision?.attemptId) return;
11074
12154
  setBusy(true);
11075
12155
  try {
@@ -11080,12 +12160,12 @@ function WeixinSettingsTab({ rpcCall }) {
11080
12160
  setProvision((current) => ({ ...current, ...next }));
11081
12161
  announce("\u914D\u5BF9\u7801\u5DF2\u63D0\u4EA4\uFF0C\u6B63\u5728\u7B49\u5F85\u5FAE\u4FE1\u786E\u8BA4\u3002");
11082
12162
  } catch (error) {
11083
- setProvision((current) => ({ ...current, status: "failed", error: presentError8(error) }));
12163
+ setProvision((current) => ({ ...current, status: "failed", error: presentError9(error) }));
11084
12164
  } finally {
11085
12165
  setBusy(false);
11086
12166
  }
11087
12167
  }, [announce, invoke, provision?.attemptId]);
11088
- React20.useEffect(() => {
12168
+ React21.useEffect(() => {
11089
12169
  const attemptId = provision?.attemptId;
11090
12170
  if (!attemptId || !["pending", "scanned", "connecting"].includes(provision.status)) return void 0;
11091
12171
  const controller = new AbortController();
@@ -11124,7 +12204,7 @@ function WeixinSettingsTab({ rpcCall }) {
11124
12204
  }
11125
12205
  } catch (error) {
11126
12206
  if (scheduler.disposed || error?.name === "AbortError") return;
11127
- setProvision((current) => current?.attemptId === attemptId ? { ...current, status: "failed", error: presentError8(error) } : current);
12207
+ setProvision((current) => current?.attemptId === attemptId ? { ...current, status: "failed", error: presentError9(error) } : current);
11128
12208
  }
11129
12209
  };
11130
12210
  scheduler.schedule(poll, provision.pollIntervalMs ?? 1e3);
@@ -11133,7 +12213,7 @@ function WeixinSettingsTab({ rpcCall }) {
11133
12213
  controller.abort();
11134
12214
  };
11135
12215
  }, [announce, invoke, loadStatus, provision?.attemptId, provision?.status, provision?.pollIntervalMs]);
11136
- const setBotBusy = React20.useCallback((botId, value) => {
12216
+ const setBotBusy = React21.useCallback((botId, value) => {
11137
12217
  setBusyByBot((current) => {
11138
12218
  const next = { ...current };
11139
12219
  if (value) next[botId] = value;
@@ -11141,7 +12221,7 @@ function WeixinSettingsTab({ rpcCall }) {
11141
12221
  return next;
11142
12222
  });
11143
12223
  }, []);
11144
- const reconnect = React20.useCallback(async (account) => {
12224
+ const reconnect = React21.useCallback(async (account) => {
11145
12225
  const snapshotVersion = workspaceFence.beginMutation();
11146
12226
  setBotBusy(account.botId, "reconnect");
11147
12227
  setFeedbackByBot((current) => {
@@ -11150,7 +12230,7 @@ function WeixinSettingsTab({ rpcCall }) {
11150
12230
  return next;
11151
12231
  });
11152
12232
  try {
11153
- const snapshot = normalizeSnapshot7(await invoke(
12233
+ const snapshot = normalizeSnapshot8(await invoke(
11154
12234
  WEIXIN_ENDPOINTS.reconnectBot,
11155
12235
  { botId: account.botId, sendTest: true }
11156
12236
  ));
@@ -11193,11 +12273,11 @@ function WeixinSettingsTab({ rpcCall }) {
11193
12273
  setBotBusy(account.botId, null);
11194
12274
  }
11195
12275
  }, [announce, invoke, loadStatus, setBotBusy, workspaceFence]);
11196
- const saveWorkspace = React20.useCallback(async (account, workspace) => {
12276
+ const saveWorkspace = React21.useCallback(async (account, workspace) => {
11197
12277
  const workspaceVersion = workspaceFence.beginMutation();
11198
12278
  setBotBusy(account.botId, "workspace");
11199
12279
  try {
11200
- const snapshot = normalizeSnapshot7(await invoke(
12280
+ const snapshot = normalizeSnapshot8(await invoke(
11201
12281
  WEIXIN_ENDPOINTS.setWorkspace,
11202
12282
  { botId: account.botId, workspace }
11203
12283
  ));
@@ -11218,11 +12298,11 @@ function WeixinSettingsTab({ rpcCall }) {
11218
12298
  if (mountedRef.current) setBotBusy(account.botId, null);
11219
12299
  }
11220
12300
  }, [invoke, loadStatus, setBotBusy, workspaceFence]);
11221
- const saveBotSetting = React20.useCallback(async (account, operation, endpoint, payload) => {
12301
+ const saveBotSetting = React21.useCallback(async (account, operation, endpoint, payload) => {
11222
12302
  const snapshotVersion = workspaceFence.beginMutation();
11223
12303
  setBotBusy(account.botId, operation);
11224
12304
  try {
11225
- const snapshot = normalizeSnapshot7(await invoke(
12305
+ const snapshot = normalizeSnapshot8(await invoke(
11226
12306
  endpoint,
11227
12307
  { botId: account.botId, ...payload }
11228
12308
  ));
@@ -11243,11 +12323,11 @@ function WeixinSettingsTab({ rpcCall }) {
11243
12323
  if (mountedRef.current) setBotBusy(account.botId, null);
11244
12324
  }
11245
12325
  }, [invoke, loadStatus, setBotBusy, workspaceFence]);
11246
- const remove = React20.useCallback(async (account) => {
12326
+ const remove = React21.useCallback(async (account) => {
11247
12327
  const snapshotVersion = workspaceFence.beginMutation();
11248
12328
  setBotBusy(account.botId, "delete");
11249
12329
  try {
11250
- const snapshot = normalizeSnapshot7(await invoke(WEIXIN_ENDPOINTS.deleteBot, {
12330
+ const snapshot = normalizeSnapshot8(await invoke(WEIXIN_ENDPOINTS.deleteBot, {
11251
12331
  botId: account.botId,
11252
12332
  confirm: true
11253
12333
  }));
@@ -11264,7 +12344,7 @@ function WeixinSettingsTab({ rpcCall }) {
11264
12344
  setRemoveTarget(null);
11265
12345
  announce("\u5FAE\u4FE1\u8D26\u53F7\u53CA\u672C\u673A\u51ED\u636E\u5DF2\u79FB\u9664\u3002");
11266
12346
  } catch (error) {
11267
- announce(`\u79FB\u9664\u5931\u8D25\uFF1A${presentError8(error).message}`);
12347
+ announce(`\u79FB\u9664\u5931\u8D25\uFF1A${presentError9(error).message}`);
11268
12348
  } finally {
11269
12349
  const shouldRefresh = workspaceFence.endMutation();
11270
12350
  if (shouldRefresh && mountedRef.current) void loadStatus({ silent: true });
@@ -11310,7 +12390,7 @@ function WeixinSettingsTab({ rpcCall }) {
11310
12390
  }, h2(
11311
12391
  "section",
11312
12392
  { className: "dxw-page dim-channelPage", "aria-label": "\u5FAE\u4FE1\u8BBE\u7F6E" },
11313
- h2(Heading5, {
12393
+ h2(Heading6, {
11314
12394
  totals: model.totals,
11315
12395
  adding: Boolean(provision),
11316
12396
  busy,
@@ -11319,7 +12399,7 @@ function WeixinSettingsTab({ rpcCall }) {
11319
12399
  }),
11320
12400
  h2("div", { className: "dxw-visuallyHidden", role: "status", "aria-live": "polite" }, notice),
11321
12401
  model.error && model.phase === "ready" ? h2("div", { className: "dxw-statusNotice dim-statusNotice" }, `\u72B6\u6001\u5237\u65B0\u5931\u8D25\uFF1A${model.error.message}`) : null,
11322
- model.phase === "loading" ? h2(LoadingView5) : model.phase === "error" ? h2(
12402
+ model.phase === "loading" ? h2(LoadingView6) : model.phase === "error" ? h2(
11323
12403
  "div",
11324
12404
  { className: "dxw-card dim-surfaceCard" },
11325
12405
  h2(
@@ -11327,13 +12407,13 @@ function WeixinSettingsTab({ rpcCall }) {
11327
12407
  { className: "dxw-error dim-inlineError" },
11328
12408
  h2("h3", null, "\u65E0\u6CD5\u8BFB\u53D6\u5FAE\u4FE1\u72B6\u6001"),
11329
12409
  h2("p", null, model.error?.message ?? "\u8BF7\u7A0D\u540E\u91CD\u8BD5"),
11330
- h2(Button12, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
12410
+ h2(Button14, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
11331
12411
  )
11332
12412
  ) : h2(
11333
- React20.Fragment,
12413
+ React21.Fragment,
11334
12414
  null,
11335
12415
  provisionView,
11336
- model.bots.length === 0 && !provision ? h2(EmptyView5, { onStart: () => void startProvisioning(), busy }) : null,
12416
+ model.bots.length === 0 && !provision ? h2(EmptyView6, { onStart: () => void startProvisioning(), busy }) : null,
11337
12417
  model.bots.length > 0 ? h2(AccountList2, {
11338
12418
  bots: model.bots,
11339
12419
  busyByBot,
@@ -11369,7 +12449,7 @@ function WeixinSettingsTab({ rpcCall }) {
11369
12449
 
11370
12450
  // plugin-src/client/channels/weixin/styles.js
11371
12451
  var WEIXIN_STYLE_ID = "xmanrui-dsh-im-weixin-settings";
11372
- var CSS9 = String.raw`
12452
+ var CSS10 = String.raw`
11373
12453
  .dxw-page {
11374
12454
  --dxw-accent: #07c160;
11375
12455
  --dxw-accent-dark: #05994c;
@@ -11479,7 +12559,7 @@ function installWeixinStyles() {
11479
12559
  const style = document.createElement("style");
11480
12560
  style.dataset.plugin = "@xmanrui/dsh-im";
11481
12561
  style.dataset.pluginCss = WEIXIN_STYLE_ID;
11482
- style.textContent = CSS9;
12562
+ style.textContent = CSS10;
11483
12563
  document.head.appendChild(style);
11484
12564
  return () => style.remove();
11485
12565
  }
@@ -11502,28 +12582,28 @@ var WHATSAPP_ENDPOINTS = Object.freeze({
11502
12582
  var PROVISION_STATES5 = /* @__PURE__ */ new Set(["starting", "pending", "connecting", "connected", "failed", "cancelled"]);
11503
12583
  var BOT_STATES = /* @__PURE__ */ new Set(["connected", "connecting", "offline", "error"]);
11504
12584
  var QR_DATA_URL4 = /^data:image\/(?:png|webp);base64,[a-z\d+/]+={0,2}$/i;
11505
- function isRecord7(value) {
12585
+ function isRecord8(value) {
11506
12586
  return value !== null && typeof value === "object" && !Array.isArray(value);
11507
12587
  }
11508
- function text5(value, fallback, max = 240) {
12588
+ function text6(value, fallback, max = 240) {
11509
12589
  return typeof value === "string" && value.trim() ? value.trim().slice(0, max) : fallback;
11510
12590
  }
11511
- function id4(value) {
11512
- const result = text5(value, "", 128);
12591
+ function id5(value) {
12592
+ const result = text6(value, "", 128);
11513
12593
  return /^[a-z\d_-]+$/i.test(result) ? result : void 0;
11514
12594
  }
11515
- function timestamp6(value) {
12595
+ function timestamp7(value) {
11516
12596
  if (typeof value === "number" && Number.isFinite(value)) return value;
11517
12597
  const parsed = typeof value === "string" ? Date.parse(value) : Number.NaN;
11518
12598
  return Number.isNaN(parsed) ? void 0 : parsed;
11519
12599
  }
11520
- function unwrapRpcResult9(result) {
11521
- if (!isRecord7(result) || typeof result.ok !== "boolean") {
12600
+ function unwrapRpcResult10(result) {
12601
+ if (!isRecord8(result) || typeof result.ok !== "boolean") {
11522
12602
  throw new Error("WhatsApp \u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94");
11523
12603
  }
11524
12604
  if (!result.ok) {
11525
- const error = new Error(text5(result.error?.message, "WhatsApp \u64CD\u4F5C\u5931\u8D25"));
11526
- error.code = text5(result.error?.code, "WHATSAPP_RPC_ERROR", 80);
12605
+ const error = new Error(text6(result.error?.message, "WhatsApp \u64CD\u4F5C\u5931\u8D25"));
12606
+ error.code = text6(result.error?.code, "WHATSAPP_RPC_ERROR", 80);
11527
12607
  throw error;
11528
12608
  }
11529
12609
  return result.value;
@@ -11532,61 +12612,61 @@ function safeQrSource6(value) {
11532
12612
  return typeof value === "string" && value.length <= 2 * 1024 * 1024 && QR_DATA_URL4.test(value) ? value : void 0;
11533
12613
  }
11534
12614
  function normalizeProvisioning6(value, now = Date.now()) {
11535
- const source = isRecord7(value?.provisioning) ? value.provisioning : value;
11536
- if (!isRecord7(source)) throw new Error("WhatsApp \u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u626B\u7801\u8FDB\u5EA6");
11537
- const attemptId = id4(source.attemptId);
12615
+ const source = isRecord8(value?.provisioning) ? value.provisioning : value;
12616
+ if (!isRecord8(source)) throw new Error("WhatsApp \u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u626B\u7801\u8FDB\u5EA6");
12617
+ const attemptId = id5(source.attemptId);
11538
12618
  if (!attemptId) throw new Error("WhatsApp \u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u626B\u7801\u4EFB\u52A1");
11539
- const reported = text5(source.status, "failed", 32);
12619
+ const reported = text6(source.status, "failed", 32);
11540
12620
  const result = {
11541
12621
  attemptId,
11542
12622
  status: PROVISION_STATES5.has(reported) ? reported : "failed",
11543
- expiresAt: timestamp6(source.expiresAt) ?? now + 6e4,
12623
+ expiresAt: timestamp7(source.expiresAt) ?? now + 6e4,
11544
12624
  pollIntervalMs: Math.min(5e3, Math.max(500, Number(source.pollIntervalMs) || 1e3)),
11545
12625
  qrRevision: Number.isSafeInteger(source.qrRevision) ? source.qrRevision : 0
11546
12626
  };
11547
12627
  const qrCodeDataUrl = safeQrSource6(source.qrCodeDataUrl);
11548
12628
  if (qrCodeDataUrl) result.qrCodeDataUrl = qrCodeDataUrl;
11549
- if (id4(source.botId)) result.botId = id4(source.botId);
11550
- if (isRecord7(source.error)) result.error = {
11551
- code: text5(source.error.code, "WHATSAPP_PROVISION_FAILED", 80),
11552
- message: text5(source.error.message, "WhatsApp \u6CA1\u6709\u63A5\u5165\u5B8C\u6210")
12629
+ if (id5(source.botId)) result.botId = id5(source.botId);
12630
+ if (isRecord8(source.error)) result.error = {
12631
+ code: text6(source.error.code, "WHATSAPP_PROVISION_FAILED", 80),
12632
+ message: text6(source.error.message, "WhatsApp \u6CA1\u6709\u63A5\u5165\u5B8C\u6210")
11553
12633
  };
11554
12634
  return result;
11555
12635
  }
11556
- function normalizeBot6(value) {
11557
- if (!isRecord7(value) || !id4(value.botId)) return void 0;
12636
+ function normalizeBot7(value) {
12637
+ if (!isRecord8(value) || !id5(value.botId)) return void 0;
11558
12638
  const connected = value.connected === true;
11559
12639
  const state = BOT_STATES.has(value.state) ? value.state : "offline";
11560
12640
  return {
11561
- botId: id4(value.botId),
12641
+ botId: id5(value.botId),
11562
12642
  connected,
11563
12643
  state: connected ? "connected" : state,
11564
- workspace: text5(value.workspace, "", 4096),
12644
+ workspace: text6(value.workspace, "", 4096),
11565
12645
  model: normalizeModelSelection(value.model),
11566
12646
  agentPreset: normalizeAgentPresetId(value.agentPreset),
11567
12647
  contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
11568
12648
  ...Object.hasOwn(value, "accessPolicy") ? { accessPolicy: normalizeAccessPolicy(value.accessPolicy) } : {},
11569
12649
  bot: {
11570
- name: text5(value.bot?.name, "WhatsApp\u673A\u5668\u4EBA", 100),
11571
- idMasked: text5(value.bot?.idMasked, "WhatsApp\u8D26\u53F7", 140)
12650
+ name: text6(value.bot?.name, "WhatsApp\u673A\u5668\u4EBA", 100),
12651
+ idMasked: text6(value.bot?.idMasked, "WhatsApp\u8D26\u53F7", 140)
11572
12652
  },
11573
12653
  health: {
11574
- summary: text5(value.health?.summary, connected ? "WhatsApp Web \u5173\u8054\u8BBE\u5907\u8FD0\u884C\u6B63\u5E38" : "WhatsApp \u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA"),
11575
- lastCheckedAt: timestamp6(value.health?.lastCheckedAt)
12654
+ summary: text6(value.health?.summary, connected ? "WhatsApp Web \u5173\u8054\u8BBE\u5907\u8FD0\u884C\u6B63\u5E38" : "WhatsApp \u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA"),
12655
+ lastCheckedAt: timestamp7(value.health?.lastCheckedAt)
11576
12656
  },
11577
12657
  lastMessageError: normalizeLastMessageError(value.lastMessageError),
11578
- error: isRecord7(value.error) ? {
11579
- code: text5(value.error.code, "WHATSAPP_ACCOUNT_ERROR", 80),
11580
- message: text5(value.error.message, "WhatsApp \u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA")
12658
+ error: isRecord8(value.error) ? {
12659
+ code: text6(value.error.code, "WHATSAPP_ACCOUNT_ERROR", 80),
12660
+ message: text6(value.error.message, "WhatsApp \u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA")
11581
12661
  } : null
11582
12662
  };
11583
12663
  }
11584
- function normalizeSnapshot8(value) {
11585
- const source = isRecord7(value?.snapshot) ? value.snapshot : value;
11586
- if (!isRecord7(source) || !Array.isArray(source.bots)) {
12664
+ function normalizeSnapshot9(value) {
12665
+ const source = isRecord8(value?.snapshot) ? value.snapshot : value;
12666
+ if (!isRecord8(source) || !Array.isArray(source.bots)) {
11587
12667
  throw new Error("WhatsApp \u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u673A\u5668\u4EBA\u5217\u8868");
11588
12668
  }
11589
- const bots = source.bots.map(normalizeBot6).filter(Boolean);
12669
+ const bots = source.bots.map(normalizeBot7).filter(Boolean);
11590
12670
  return {
11591
12671
  revision: Number.isSafeInteger(source.revision) ? source.revision : 0,
11592
12672
  bots,
@@ -11596,10 +12676,10 @@ function normalizeSnapshot8(value) {
11596
12676
  modelCatalog: normalizeModelCatalog(source.modelCatalog)
11597
12677
  };
11598
12678
  }
11599
- function presentError9(error) {
12679
+ function presentError10(error) {
11600
12680
  return {
11601
- code: text5(error?.code, "WHATSAPP_ERROR", 80),
11602
- message: text5(error?.message, "WhatsApp \u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")
12681
+ code: text6(error?.code, "WHATSAPP_ERROR", 80),
12682
+ message: text6(error?.message, "WhatsApp \u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")
11603
12683
  };
11604
12684
  }
11605
12685
  function formatRemaining6(milliseconds) {
@@ -11608,11 +12688,11 @@ function formatRemaining6(milliseconds) {
11608
12688
  }
11609
12689
 
11610
12690
  // plugin-src/client/channels/whatsapp/index.js
11611
- var React21 = __toESM(require("react"), 1);
12691
+ var React22 = __toESM(require("react"), 1);
11612
12692
 
11613
12693
  // plugin-src/client/channels/whatsapp/styles.js
11614
12694
  var WHATSAPP_STYLE_ID = "xmanrui-dsh-im-whatsapp-settings";
11615
- var CSS10 = String.raw`
12695
+ var CSS11 = String.raw`
11616
12696
  .dwa-page { --ddt-accent: #25d366; --ddt-accent-deep: #128c7e; --ddt-accent-wash: #eafbf0; }
11617
12697
  .dwa-avatar { color: #fff; background: #25d366; }
11618
12698
  .dwa-avatar svg { display: block; }
@@ -11626,14 +12706,14 @@ function installWhatsappStyles() {
11626
12706
  const style = document.createElement("style");
11627
12707
  style.dataset.plugin = "@xmanrui/dsh-im";
11628
12708
  style.dataset.pluginCss = WHATSAPP_STYLE_ID;
11629
- style.textContent = CSS10;
12709
+ style.textContent = CSS11;
11630
12710
  document.head.appendChild(style);
11631
12711
  return () => style.remove();
11632
12712
  }
11633
12713
 
11634
12714
  // plugin-src/client/channels/whatsapp/index.js
11635
12715
  var ACTIVE_STATES3 = /* @__PURE__ */ new Set(["pending", "connecting"]);
11636
- var Button14 = React21.forwardRef(function Button15({ children, kind = "secondary", className = "", ...props }, ref) {
12716
+ var Button16 = React22.forwardRef(function Button17({ children, kind = "secondary", className = "", ...props }, ref) {
11637
12717
  return h2("button", {
11638
12718
  ...props,
11639
12719
  ref,
@@ -11642,7 +12722,7 @@ var Button14 = React21.forwardRef(function Button15({ children, kind = "secondar
11642
12722
  "data-kind": kind
11643
12723
  }, children);
11644
12724
  });
11645
- function checkedTime6(value) {
12725
+ function checkedTime7(value) {
11646
12726
  if (!value) return "\u5C1A\u672A\u68C0\u67E5";
11647
12727
  try {
11648
12728
  return new Intl.DateTimeFormat("zh-CN", {
@@ -11663,7 +12743,7 @@ function connectionTestNotice3(value) {
11663
12743
  }
11664
12744
  return value?.testMessage ? "\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002" : null;
11665
12745
  }
11666
- function Heading6({ totals, busy, onAdd, addButtonRef }) {
12746
+ function Heading7({ totals, busy, onAdd, addButtonRef }) {
11667
12747
  return h2(
11668
12748
  "div",
11669
12749
  { className: "ddt-heading" },
@@ -11673,7 +12753,7 @@ function Heading6({ totals, busy, onAdd, addButtonRef }) {
11673
12753
  h2(
11674
12754
  "div",
11675
12755
  { className: "dim-bindActions" },
11676
- h2(Button14, {
12756
+ h2(Button16, {
11677
12757
  kind: "primary",
11678
12758
  className: "dim-scanButton",
11679
12759
  onClick: onAdd,
@@ -11690,13 +12770,13 @@ function Heading6({ totals, busy, onAdd, addButtonRef }) {
11690
12770
  )
11691
12771
  );
11692
12772
  }
11693
- function LoadingView6() {
12773
+ function LoadingView7() {
11694
12774
  return h2("div", {
11695
12775
  className: "ddt-card ddt-loading dim-surfaceCard dim-loadingView",
11696
12776
  "aria-busy": "true"
11697
12777
  }, h2("div", { className: "ddt-spinner dim-spinner" }), "\u6B63\u5728\u8BFB\u53D6 WhatsApp \u673A\u5668\u4EBA\u72B6\u6001\u2026");
11698
12778
  }
11699
- function EmptyView6({ busy, onStart }) {
12779
+ function EmptyView7({ busy, onStart }) {
11700
12780
  return h2(
11701
12781
  "div",
11702
12782
  { className: "ddt-card dim-surfaceCard" },
@@ -11718,7 +12798,7 @@ function EmptyView6({ busy, onStart }) {
11718
12798
  "div",
11719
12799
  { className: "ddt-actions dim-viewActions" },
11720
12800
  h2(
11721
- Button14,
12801
+ Button16,
11722
12802
  { kind: "primary", onClick: onStart, disabled: busy },
11723
12803
  busy ? "\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801\u2026" : "\u751F\u6210\u4E8C\u7EF4\u7801"
11724
12804
  )
@@ -11787,8 +12867,8 @@ function QrPanel5({ provision, now, busy, onRefresh, onCancel }) {
11787
12867
  h2(
11788
12868
  "div",
11789
12869
  { className: "ddt-actions dim-viewActions" },
11790
- h2(Button14, { onClick: onRefresh, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801"),
11791
- h2(Button14, { kind: "quiet", onClick: onCancel, disabled: busy }, "\u53D6\u6D88")
12870
+ h2(Button16, { onClick: onRefresh, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801"),
12871
+ h2(Button16, { kind: "quiet", onClick: onCancel, disabled: busy }, "\u53D6\u6D88")
11792
12872
  )
11793
12873
  )
11794
12874
  )
@@ -11824,13 +12904,13 @@ function ProvisionView3({ provision, busy, onRetry, onClose }) {
11824
12904
  h2(
11825
12905
  "div",
11826
12906
  { className: "ddt-actions dim-viewActions" },
11827
- h2(Button14, { kind: "primary", onClick: onRetry, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801"),
11828
- h2(Button14, { onClick: onClose, disabled: busy }, "\u5173\u95ED")
12907
+ h2(Button16, { kind: "primary", onClick: onRetry, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801"),
12908
+ h2(Button16, { onClick: onClose, disabled: busy }, "\u5173\u95ED")
11829
12909
  )
11830
12910
  )
11831
12911
  );
11832
12912
  }
11833
- function RemoveConfirmation5({ account, busy, onConfirm, onCancel }) {
12913
+ function RemoveConfirmation6({ account, busy, onConfirm, onCancel }) {
11834
12914
  return h2(
11835
12915
  "div",
11836
12916
  { className: "ddt-confirm dim-confirm", role: "alertdialog" },
@@ -11839,9 +12919,9 @@ function RemoveConfirmation5({ account, busy, onConfirm, onCancel }) {
11839
12919
  h2(
11840
12920
  "div",
11841
12921
  { className: "ddt-actions dim-viewActions" },
11842
- h2(Button14, { onClick: onCancel, disabled: busy }, "\u4FDD\u7559\u673A\u5668\u4EBA"),
12922
+ h2(Button16, { onClick: onCancel, disabled: busy }, "\u4FDD\u7559\u673A\u5668\u4EBA"),
11843
12923
  h2(
11844
- Button14,
12924
+ Button16,
11845
12925
  { kind: "danger", onClick: onConfirm, disabled: busy },
11846
12926
  busy ? "\u6B63\u5728\u79FB\u9664\u2026" : "\u786E\u8BA4\u79FB\u9664\u63A5\u5165"
11847
12927
  )
@@ -11911,7 +12991,7 @@ function WhatsappAccountCard({
11911
12991
  tone,
11912
12992
  stateLabel: stateLabel2,
11913
12993
  lastCheckedAt: account.health.lastCheckedAt,
11914
- formatCheckedTime: checkedTime6
12994
+ formatCheckedTime: checkedTime7
11915
12995
  }),
11916
12996
  h2(BotSettingsButton, {
11917
12997
  channel: "whatsapp",
@@ -11952,12 +13032,12 @@ function WhatsappAccountCard({
11952
13032
  h2(
11953
13033
  "div",
11954
13034
  { className: "ddt-actions dim-cardActions" },
11955
- h2(Button14, {
13035
+ h2(Button16, {
11956
13036
  className: "dim-cardAction",
11957
13037
  onClick: onReconnect,
11958
13038
  disabled: Boolean(busy)
11959
13039
  }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
11960
- h2(Button14, {
13040
+ h2(Button16, {
11961
13041
  className: "dim-cardAction",
11962
13042
  kind: "danger",
11963
13043
  onClick: onRequestRemove,
@@ -11977,7 +13057,7 @@ function WhatsappAccountCard({
11977
13057
  )
11978
13058
  )
11979
13059
  ),
11980
- removing ? h2(RemoveConfirmation5, {
13060
+ removing ? h2(RemoveConfirmation6, {
11981
13061
  account,
11982
13062
  busy: busy === "delete",
11983
13063
  onConfirm: onConfirmRemove,
@@ -11986,7 +13066,7 @@ function WhatsappAccountCard({
11986
13066
  );
11987
13067
  }
11988
13068
  function WhatsappSettingsTab({ rpcCall }) {
11989
- const [model, setModel] = React21.useState({
13069
+ const [model, setModel] = React22.useState({
11990
13070
  phase: "loading",
11991
13071
  bots: [],
11992
13072
  totals: { configured: 0, connected: 0 },
@@ -11994,16 +13074,16 @@ function WhatsappSettingsTab({ rpcCall }) {
11994
13074
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG,
11995
13075
  modelCatalog: EMPTY_MODEL_CATALOG
11996
13076
  });
11997
- const [provision, setProvision] = React21.useState(null);
11998
- const [busy, setBusy] = React21.useState(false);
11999
- const [busyByBot, setBusyByBot] = React21.useState({});
12000
- const [testNoticeByBot, setTestNoticeByBot] = React21.useState({});
12001
- const [removeTarget, setRemoveTarget] = React21.useState(null);
12002
- const [now, setNow] = React21.useState(Date.now());
12003
- const mounted = React21.useRef(true);
13077
+ const [provision, setProvision] = React22.useState(null);
13078
+ const [busy, setBusy] = React22.useState(false);
13079
+ const [busyByBot, setBusyByBot] = React22.useState({});
13080
+ const [testNoticeByBot, setTestNoticeByBot] = React22.useState({});
13081
+ const [removeTarget, setRemoveTarget] = React22.useState(null);
13082
+ const [now, setNow] = React22.useState(Date.now());
13083
+ const mounted = React22.useRef(true);
12004
13084
  const workspaceFence = useWorkspaceSnapshotFence();
12005
- const addButtonRef = React21.useRef(null);
12006
- React21.useEffect(() => {
13085
+ const addButtonRef = React22.useRef(null);
13086
+ React22.useEffect(() => {
12007
13087
  const disposeDingtalk = installDingtalkStyles();
12008
13088
  const disposeWhatsapp = installWhatsappStyles();
12009
13089
  mounted.current = true;
@@ -12013,16 +13093,16 @@ function WhatsappSettingsTab({ rpcCall }) {
12013
13093
  disposeDingtalk();
12014
13094
  };
12015
13095
  }, []);
12016
- const invoke = React21.useCallback(async (endpoint, payload = {}, signal) => {
13096
+ const invoke = React22.useCallback(async (endpoint, payload = {}, signal) => {
12017
13097
  if (typeof rpcCall !== "function") throw new TypeError("WhatsApp \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
12018
- return unwrapRpcResult9(await rpcCall(endpoint, payload, signal));
13098
+ return unwrapRpcResult10(await rpcCall(endpoint, payload, signal));
12019
13099
  }, [rpcCall]);
12020
- const loadStatus = React21.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
13100
+ const loadStatus = React22.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
12021
13101
  const workspaceVersion = workspaceFence.beginStatus();
12022
13102
  if (workspaceVersion === null) return void 0;
12023
13103
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
12024
13104
  try {
12025
- const snapshot = normalizeSnapshot8(await invoke(WHATSAPP_ENDPOINTS.status, {}, signal));
13105
+ const snapshot = normalizeSnapshot9(await invoke(WHATSAPP_ENDPOINTS.status, {}, signal));
12026
13106
  if (!mounted.current || signal?.aborted || !workspaceFence.canCommitStatus(workspaceVersion)) return void 0;
12027
13107
  setModel({
12028
13108
  phase: "ready",
@@ -12042,18 +13122,18 @@ function WhatsappSettingsTab({ rpcCall }) {
12042
13122
  setModel((current) => ({
12043
13123
  ...current,
12044
13124
  phase: silent ? current.phase : "error",
12045
- error: presentError9(error)
13125
+ error: presentError10(error)
12046
13126
  }));
12047
13127
  }
12048
13128
  return void 0;
12049
13129
  }
12050
13130
  }, [invoke, workspaceFence]);
12051
- React21.useEffect(() => {
13131
+ React22.useEffect(() => {
12052
13132
  const controller = new AbortController();
12053
13133
  void loadStatus({ signal: controller.signal, restore: true });
12054
13134
  return () => controller.abort();
12055
13135
  }, [loadStatus]);
12056
- React21.useEffect(() => {
13136
+ React22.useEffect(() => {
12057
13137
  if (model.phase !== "ready") return void 0;
12058
13138
  const controller = new AbortController();
12059
13139
  const timer = window.setInterval(
@@ -12065,12 +13145,12 @@ function WhatsappSettingsTab({ rpcCall }) {
12065
13145
  window.clearInterval(timer);
12066
13146
  };
12067
13147
  }, [loadStatus, model.phase]);
12068
- React21.useEffect(() => {
13148
+ React22.useEffect(() => {
12069
13149
  if (!provision || !ACTIVE_STATES3.has(provision.status)) return void 0;
12070
13150
  const timer = window.setInterval(() => mounted.current && setNow(Date.now()), 1e3);
12071
13151
  return () => window.clearInterval(timer);
12072
13152
  }, [provision?.attemptId, provision?.status]);
12073
- const startProvisioning = React21.useCallback(async (replace = false) => {
13153
+ const startProvisioning = React22.useCallback(async (replace = false) => {
12074
13154
  setBusy(true);
12075
13155
  try {
12076
13156
  if (replace && provision?.attemptId) {
@@ -12083,12 +13163,12 @@ function WhatsappSettingsTab({ rpcCall }) {
12083
13163
  setNow(Date.now());
12084
13164
  setProvision({ ...started, durationMs: Math.max(1, started.expiresAt - Date.now()) });
12085
13165
  } catch (error) {
12086
- if (mounted.current) setProvision({ status: "failed", error: presentError9(error) });
13166
+ if (mounted.current) setProvision({ status: "failed", error: presentError10(error) });
12087
13167
  } finally {
12088
13168
  if (mounted.current) setBusy(false);
12089
13169
  }
12090
13170
  }, [invoke, provision?.attemptId]);
12091
- const closeProvision = React21.useCallback(async () => {
13171
+ const closeProvision = React22.useCallback(async () => {
12092
13172
  setBusy(true);
12093
13173
  try {
12094
13174
  if (provision?.attemptId && ACTIVE_STATES3.has(provision.status)) {
@@ -12099,7 +13179,7 @@ function WhatsappSettingsTab({ rpcCall }) {
12099
13179
  if (mounted.current) setBusy(false);
12100
13180
  }
12101
13181
  }, [invoke, provision?.attemptId, provision?.status]);
12102
- React21.useEffect(() => {
13182
+ React22.useEffect(() => {
12103
13183
  const attemptId = provision?.attemptId;
12104
13184
  if (!attemptId || !ACTIVE_STATES3.has(provision.status)) return void 0;
12105
13185
  const controller = new AbortController();
@@ -12129,7 +13209,7 @@ function WhatsappSettingsTab({ rpcCall }) {
12129
13209
  if (ACTIVE_STATES3.has(current.status)) schedule(current.pollIntervalMs);
12130
13210
  } catch (error) {
12131
13211
  if (!disposed && !controller.signal.aborted && mounted.current) {
12132
- setProvision({ status: "failed", error: presentError9(error) });
13212
+ setProvision({ status: "failed", error: presentError10(error) });
12133
13213
  }
12134
13214
  }
12135
13215
  };
@@ -12140,7 +13220,7 @@ function WhatsappSettingsTab({ rpcCall }) {
12140
13220
  if (timer) window.clearTimeout(timer);
12141
13221
  };
12142
13222
  }, [invoke, loadStatus, provision?.attemptId, provision?.status]);
12143
- const botAction = React21.useCallback(async (account, operation, endpoint, payload) => {
13223
+ const botAction = React22.useCallback(async (account, operation, endpoint, payload) => {
12144
13224
  const snapshotVersion = workspaceFence.beginMutation();
12145
13225
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
12146
13226
  if (operation === "reconnect") {
@@ -12152,7 +13232,7 @@ function WhatsappSettingsTab({ rpcCall }) {
12152
13232
  }
12153
13233
  try {
12154
13234
  const value = await invoke(endpoint, payload);
12155
- const snapshot = normalizeSnapshot8(value);
13235
+ const snapshot = normalizeSnapshot9(value);
12156
13236
  if (mounted.current && workspaceFence.canCommitMutation(snapshotVersion)) {
12157
13237
  setModel({
12158
13238
  phase: "ready",
@@ -12251,13 +13331,13 @@ function WhatsappSettingsTab({ rpcCall }) {
12251
13331
  className: "ddt-page dwa-page dim-channelPage",
12252
13332
  "aria-label": "WhatsApp \u8BBE\u7F6E"
12253
13333
  },
12254
- h2(Heading6, {
13334
+ h2(Heading7, {
12255
13335
  totals: model.totals,
12256
13336
  busy,
12257
13337
  onAdd: () => void startProvisioning(false),
12258
13338
  addButtonRef
12259
13339
  }),
12260
- model.phase === "loading" ? h2(LoadingView6) : model.phase === "error" ? h2(
13340
+ model.phase === "loading" ? h2(LoadingView7) : model.phase === "error" ? h2(
12261
13341
  "div",
12262
13342
  { className: "ddt-card dim-surfaceCard" },
12263
13343
  h2(
@@ -12265,10 +13345,10 @@ function WhatsappSettingsTab({ rpcCall }) {
12265
13345
  { className: "ddt-inlineError dim-inlineError" },
12266
13346
  h2("h3", null, "\u65E0\u6CD5\u8BFB\u53D6 WhatsApp \u673A\u5668\u4EBA\u72B6\u6001"),
12267
13347
  h2("p", null, model.error?.message),
12268
- h2(Button14, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
13348
+ h2(Button16, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
12269
13349
  )
12270
13350
  ) : h2(
12271
- React21.Fragment,
13351
+ React22.Fragment,
12272
13352
  null,
12273
13353
  provision?.status === "pending" ? h2(QrPanel5, {
12274
13354
  provision,
@@ -12281,17 +13361,17 @@ function WhatsappSettingsTab({ rpcCall }) {
12281
13361
  busy,
12282
13362
  onRetry: () => void startProvisioning(true),
12283
13363
  onClose: () => void closeProvision()
12284
- }) : model.bots.length === 0 ? h2(EmptyView6, { busy, onStart: () => void startProvisioning(false) }) : null,
13364
+ }) : model.bots.length === 0 ? h2(EmptyView7, { busy, onStart: () => void startProvisioning(false) }) : null,
12285
13365
  botList
12286
13366
  )
12287
13367
  )));
12288
13368
  }
12289
13369
 
12290
13370
  // plugin-src/client/delivery-settings.js
12291
- var React24 = __toESM(require("react"), 1);
13371
+ var React25 = __toESM(require("react"), 1);
12292
13372
 
12293
13373
  // plugin-src/client/access-policy-settings.js
12294
- var React22 = __toESM(require("react"), 1);
13374
+ var React23 = __toESM(require("react"), 1);
12295
13375
  var ACCESS_POLICY_ENDPOINT = "bot.access-policy.set";
12296
13376
  var ACCESS_CHANNEL_DEFINITIONS = Object.freeze({
12297
13377
  weixin: Object.freeze({
@@ -12317,6 +13397,12 @@ var ACCESS_CHANNEL_DEFINITIONS = Object.freeze({
12317
13397
  groupUserLabel: "\u7FA4\u6210\u5458\u7528\u6237 ID",
12318
13398
  groupPlaceholder: "\u586B\u5199 userid"
12319
13399
  }),
13400
+ wecomApp: Object.freeze({
13401
+ directUserLabel: "\u4F01\u4E1A\u5FAE\u4FE1\u7528\u6237 ID",
13402
+ directPlaceholder: "\u586B\u5199 userid",
13403
+ groupUserLabel: "\u7FA4\u6210\u5458\u7528\u6237 ID",
13404
+ groupPlaceholder: "\u586B\u5199 userid"
13405
+ }),
12320
13406
  qq: Object.freeze({
12321
13407
  directUserLabel: "QQ User Open ID",
12322
13408
  directPlaceholder: "\u586B\u5199 user_openid",
@@ -12366,7 +13452,7 @@ function clonePolicy(policy) {
12366
13452
  group: cloneScope(policy.group)
12367
13453
  };
12368
13454
  }
12369
- function unwrapRpcResult10(result) {
13455
+ function unwrapRpcResult11(result) {
12370
13456
  if (result?.ok === true) return result.value;
12371
13457
  if (result?.ok === false) {
12372
13458
  const error = new Error(result.error?.message || "\u8BBF\u95EE\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
@@ -12393,8 +13479,8 @@ function ScenePolicyEditor({
12393
13479
  unsupported = false,
12394
13480
  onChange
12395
13481
  }) {
12396
- const ownerHelpId = React22.useId();
12397
- const emptyAllowlistHelpId = React22.useId();
13482
+ const ownerHelpId = React23.useId();
13483
+ const emptyAllowlistHelpId = React23.useId();
12398
13484
  const allowlist = policy.mode === "allowlist";
12399
13485
  const collectionKey = allowlist ? "users" : "commandPermissionOverrides";
12400
13486
  const branchKey = allowlist ? "allowlist" : "open";
@@ -12446,7 +13532,7 @@ function ScenePolicyEditor({
12446
13532
  h2("strong", null, "\u5F53\u524D\u6E20\u9053\u4E0D\u652F\u6301\u7FA4\u804A"),
12447
13533
  h2("p", null, "\u6B64\u533A\u57DF\u65E0\u9700\u914D\u7F6E\uFF0C\u4FDD\u5B58\u79C1\u804A\u8BBE\u7F6E\u65F6\u4F1A\u4FDD\u7559\u73B0\u6709\u7FA4\u804A\u7B56\u7565\u3002")
12448
13534
  ) : h2(
12449
- React22.Fragment,
13535
+ React23.Fragment,
12450
13536
  null,
12451
13537
  h2(
12452
13538
  "div",
@@ -12587,16 +13673,16 @@ function AccessPolicySettingsPage({ channel: channel4, account, rpcCall, onSaved
12587
13673
  const definition = ACCESS_CHANNEL_DEFINITIONS[channel4];
12588
13674
  const initialPolicy = normalizeAccessPolicy(account?.accessPolicy);
12589
13675
  const initialKey = JSON.stringify(initialPolicy);
12590
- const [draft, setDraft] = React22.useState(() => clonePolicy(
13676
+ const [draft, setDraft] = React23.useState(() => clonePolicy(
12591
13677
  initialPolicy ?? DEFAULT_ACCESS_POLICY
12592
13678
  ));
12593
- const [saving, setSaving] = React22.useState(false);
12594
- const [feedback, setFeedback] = React22.useState(null);
12595
- React22.useEffect(() => {
13679
+ const [saving, setSaving] = React23.useState(false);
13680
+ const [feedback, setFeedback] = React23.useState(null);
13681
+ React23.useEffect(() => {
12596
13682
  const next = normalizeAccessPolicy(account?.accessPolicy);
12597
13683
  setDraft(clonePolicy(next ?? DEFAULT_ACCESS_POLICY));
12598
13684
  }, [account?.botId, initialKey]);
12599
- React22.useEffect(() => {
13685
+ React23.useEffect(() => {
12600
13686
  setFeedback(null);
12601
13687
  }, [account?.botId]);
12602
13688
  if (!definition) {
@@ -12613,7 +13699,7 @@ function AccessPolicySettingsPage({ channel: channel4, account, rpcCall, onSaved
12613
13699
  try {
12614
13700
  const policy = validateAccessPolicy(draft);
12615
13701
  if (typeof rpcCall !== "function") throw new Error("\u8BBF\u95EE\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
12616
- const value = unwrapRpcResult10(await rpcCall(ACCESS_POLICY_ENDPOINT, {
13702
+ const value = unwrapRpcResult11(await rpcCall(ACCESS_POLICY_ENDPOINT, {
12617
13703
  botId: account.botId,
12618
13704
  policy
12619
13705
  }));
@@ -12687,7 +13773,7 @@ function AccessPolicySettingsPage({ channel: channel4, account, rpcCall, onSaved
12687
13773
  }
12688
13774
 
12689
13775
  // plugin-src/client/channels/feishu/group-settings.js
12690
- var React23 = __toESM(require("react"), 1);
13776
+ var React24 = __toESM(require("react"), 1);
12691
13777
  var GROUP_MESSAGE_PERMISSION_OPERATION2 = FEISHU_REGISTRATION_OPERATIONS.GROUP_MESSAGE_PERMISSION;
12692
13778
  function SettingsButton({ children, kind = "secondary", className = "", ...props }) {
12693
13779
  return h2("button", {
@@ -12748,9 +13834,9 @@ function GroupResponseModeEditor({
12748
13834
  onAuthorize
12749
13835
  }) {
12750
13836
  const current = normalizeGroupResponseMode(value);
12751
- const [saving, setSaving] = React23.useState(false);
12752
- const [authorizing, setAuthorizing] = React23.useState(false);
12753
- const [error, setError] = React23.useState(null);
13837
+ const [saving, setSaving] = React24.useState(false);
13838
+ const [authorizing, setAuthorizing] = React24.useState(false);
13839
+ const [error, setError] = React24.useState(null);
12754
13840
  const change = async (event) => {
12755
13841
  const next = normalizeGroupResponseMode(event.target.value);
12756
13842
  if (next === current || saving || disabled) return;
@@ -12831,8 +13917,8 @@ function GroupResponseModeEditor({
12831
13917
  }
12832
13918
  function GroupTopicReplyEditor({ value = false, disabled = false, onSave }) {
12833
13919
  const current = value === true ? "on" : "off";
12834
- const [saving, setSaving] = React23.useState(false);
12835
- const [error, setError] = React23.useState(null);
13920
+ const [saving, setSaving] = React24.useState(false);
13921
+ const [error, setError] = React24.useState(null);
12836
13922
  const change = async (event) => {
12837
13923
  const next = event.target.value === "on";
12838
13924
  if ((next ? "on" : "off") === current || saving || disabled) return;
@@ -13019,14 +14105,14 @@ function PermissionFlow({ provision, now, busy, botName, onRetry, onCancel, onCl
13019
14105
  );
13020
14106
  }
13021
14107
  function FeishuGroupSettingsPage({ account, rpcCall }) {
13022
- const [settings, setSettings] = React23.useState(() => groupSettingsFrom(account));
13023
- const [refreshing, setRefreshing] = React23.useState(false);
13024
- const [refreshError, setRefreshError] = React23.useState(null);
13025
- const [provision, setProvision] = React23.useState(null);
13026
- const [provisionBusy, setProvisionBusy] = React23.useState(false);
13027
- const [now, setNow] = React23.useState(() => Date.now());
13028
- const mounted = React23.useRef(true);
13029
- React23.useEffect(() => {
14108
+ const [settings, setSettings] = React24.useState(() => groupSettingsFrom(account));
14109
+ const [refreshing, setRefreshing] = React24.useState(false);
14110
+ const [refreshError, setRefreshError] = React24.useState(null);
14111
+ const [provision, setProvision] = React24.useState(null);
14112
+ const [provisionBusy, setProvisionBusy] = React24.useState(false);
14113
+ const [now, setNow] = React24.useState(() => Date.now());
14114
+ const mounted = React24.useRef(true);
14115
+ React24.useEffect(() => {
13030
14116
  setSettings(groupSettingsFrom(account));
13031
14117
  }, [
13032
14118
  account.botId,
@@ -13034,22 +14120,22 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
13034
14120
  account.groupTopicReply,
13035
14121
  account.groupMessagePermissionGranted
13036
14122
  ]);
13037
- React23.useEffect(() => {
14123
+ React24.useEffect(() => {
13038
14124
  mounted.current = true;
13039
14125
  return () => {
13040
14126
  mounted.current = false;
13041
14127
  };
13042
14128
  }, []);
13043
- const invoke = React23.useCallback(async (endpoint, payload = {}, signal) => {
14129
+ const invoke = React24.useCallback(async (endpoint, payload = {}, signal) => {
13044
14130
  if (typeof rpcCall !== "function") throw new Error("\u98DE\u4E66\u7FA4\u804A\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
13045
14131
  return unwrapRpcResult3(await rpcCall(endpoint, payload, signal));
13046
14132
  }, [rpcCall]);
13047
- const applySnapshot = React23.useCallback((value) => {
14133
+ const applySnapshot = React24.useCallback((value) => {
13048
14134
  const result = targetBotFromSnapshot(value, account.botId);
13049
14135
  if (mounted.current) setSettings(groupSettingsFrom(result.bot));
13050
14136
  return result;
13051
14137
  }, [account.botId]);
13052
- const loadSettings = React23.useCallback(async ({ signal, restoreProvisioning = false } = {}) => {
14138
+ const loadSettings = React24.useCallback(async ({ signal, restoreProvisioning = false } = {}) => {
13053
14139
  setRefreshing(true);
13054
14140
  setRefreshError(null);
13055
14141
  try {
@@ -13059,13 +14145,13 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
13059
14145
  if (restoreProvisioning) {
13060
14146
  const active = result.snapshot.provisioning;
13061
14147
  if (active?.operation === GROUP_MESSAGE_PERMISSION_OPERATION2 && active.botId === account.botId) {
13062
- const timestamp7 = Date.now();
13063
- setNow(timestamp7);
14148
+ const timestamp8 = Date.now();
14149
+ setNow(timestamp8);
13064
14150
  setProvision({
13065
14151
  phase: active.submitted ? "connecting" : "qr",
13066
14152
  ...active,
13067
- durationMs: Math.max(1, active.expiresAt - timestamp7),
13068
- expired: !active.submitted && active.expiresAt <= timestamp7
14153
+ durationMs: Math.max(1, active.expiresAt - timestamp8),
14154
+ expired: !active.submitted && active.expiresAt <= timestamp8
13069
14155
  });
13070
14156
  }
13071
14157
  }
@@ -13078,16 +14164,16 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
13078
14164
  if (!signal?.aborted && mounted.current) setRefreshing(false);
13079
14165
  }
13080
14166
  }, [account.botId, applySnapshot, invoke]);
13081
- React23.useEffect(() => {
14167
+ React24.useEffect(() => {
13082
14168
  const controller = new AbortController();
13083
14169
  void loadSettings({ signal: controller.signal, restoreProvisioning: true });
13084
14170
  return () => controller.abort();
13085
14171
  }, [loadSettings]);
13086
- const saveSetting = React23.useCallback(async (endpoint, payload) => {
14172
+ const saveSetting = React24.useCallback(async (endpoint, payload) => {
13087
14173
  const value = await invoke(endpoint, { botId: account.botId, ...payload });
13088
14174
  applySnapshot(value);
13089
14175
  }, [account.botId, applySnapshot, invoke]);
13090
- const startAuthorization = React23.useCallback(async ({ replace = false } = {}) => {
14176
+ const startAuthorization = React24.useCallback(async ({ replace = false } = {}) => {
13091
14177
  if (provisionBusy) return;
13092
14178
  const previousAttemptId = provision?.attemptId;
13093
14179
  setProvisionBusy(true);
@@ -13106,13 +14192,13 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
13106
14192
  if (normalized.operation !== GROUP_MESSAGE_PERMISSION_OPERATION2 || normalized.botId !== account.botId) {
13107
14193
  throw new Error("\u98DE\u4E66\u670D\u52A1\u8FD4\u56DE\u4E86\u4E0D\u5339\u914D\u7684\u7FA4\u6D88\u606F\u6743\u9650\u4E8C\u7EF4\u7801");
13108
14194
  }
13109
- const timestamp7 = Date.now();
14195
+ const timestamp8 = Date.now();
13110
14196
  if (!mounted.current) return;
13111
- setNow(timestamp7);
14197
+ setNow(timestamp8);
13112
14198
  setProvision({
13113
14199
  phase: normalized.submitted ? "connecting" : "qr",
13114
14200
  ...normalized,
13115
- durationMs: Math.max(1, normalized.expiresAt - timestamp7),
14201
+ durationMs: Math.max(1, normalized.expiresAt - timestamp8),
13116
14202
  expired: false
13117
14203
  });
13118
14204
  } catch (cause) {
@@ -13128,13 +14214,13 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
13128
14214
  if (mounted.current) setProvisionBusy(false);
13129
14215
  }
13130
14216
  }, [account.botId, invoke, provision?.attemptId, provisionBusy]);
13131
- const finishAuthorization = React23.useCallback(async (signal) => {
14217
+ const finishAuthorization = React24.useCallback(async (signal) => {
13132
14218
  const bot = await loadSettings({ signal, restoreProvisioning: false });
13133
14219
  if (signal?.aborted || !mounted.current) return;
13134
14220
  if (!bot) throw new Error("\u7FA4\u6D88\u606F\u6743\u9650\u5DF2\u66F4\u65B0\uFF0C\u4F46\u6682\u65F6\u65E0\u6CD5\u786E\u8BA4\u673A\u5668\u4EBA\u8FDE\u63A5\u72B6\u6001");
13135
14221
  setProvision(null);
13136
14222
  }, [loadSettings]);
13137
- React23.useEffect(() => {
14223
+ React24.useEffect(() => {
13138
14224
  if (!provision?.attemptId || !["qr", "connecting"].includes(provision.phase) || provision.expired) return void 0;
13139
14225
  const timerHost = globalThis.window ?? globalThis;
13140
14226
  const controller = new AbortController();
@@ -13178,13 +14264,13 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
13178
14264
  timerHost.clearTimeout(timer);
13179
14265
  };
13180
14266
  }, [account.botId, finishAuthorization, invoke, provision]);
13181
- React23.useEffect(() => {
14267
+ React24.useEffect(() => {
13182
14268
  if (!provision?.attemptId || provision.phase !== "qr" || provision.expired) return void 0;
13183
14269
  const timerHost = globalThis.window ?? globalThis;
13184
14270
  const tick = () => {
13185
- const timestamp7 = Date.now();
13186
- setNow(timestamp7);
13187
- if (timestamp7 >= provision.expiresAt) {
14271
+ const timestamp8 = Date.now();
14272
+ setNow(timestamp8);
14273
+ if (timestamp8 >= provision.expiresAt) {
13188
14274
  setProvision((current) => current?.attemptId === provision.attemptId ? { ...current, expired: true } : current);
13189
14275
  }
13190
14276
  };
@@ -13192,7 +14278,7 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
13192
14278
  const timer = timerHost.setInterval(tick, 1e3);
13193
14279
  return () => timerHost.clearInterval(timer);
13194
14280
  }, [provision?.attemptId, provision?.expired, provision?.expiresAt, provision?.phase]);
13195
- const cancelAuthorization = React23.useCallback(async () => {
14281
+ const cancelAuthorization = React24.useCallback(async () => {
13196
14282
  if (!provision?.attemptId || provisionBusy) {
13197
14283
  setProvision(null);
13198
14284
  return;
@@ -13336,6 +14422,13 @@ var CHANNEL_DEFINITIONS = Object.freeze({
13336
14422
  group: [{ key: "chatId", label: "\u7FA4 Chat ID", placeholder: "\u586B\u5199\u7FA4 chatid" }]
13337
14423
  }
13338
14424
  },
14425
+ wecomApp: {
14426
+ label: "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528",
14427
+ kinds: [{ value: "user", label: "\u79C1\u804A" }],
14428
+ fields: {
14429
+ user: [{ key: "chatId", label: "\u7528\u6237 ID", placeholder: "\u586B\u5199\u4F01\u4E1A\u5FAE\u4FE1\u7528\u6237 ID" }]
14430
+ }
14431
+ },
13339
14432
  qq: {
13340
14433
  label: "QQ",
13341
14434
  kinds: [{ value: "user", label: "\u5355\u804A" }, { value: "group", label: "\u7FA4\u804A" }],
@@ -13380,10 +14473,10 @@ var CHANNEL_DEFINITIONS = Object.freeze({
13380
14473
  }
13381
14474
  }
13382
14475
  });
13383
- function presentError10(error, fallback) {
14476
+ function presentError11(error, fallback) {
13384
14477
  return error?.message || fallback;
13385
14478
  }
13386
- function unwrapRpcResult11(result) {
14479
+ function unwrapRpcResult12(result) {
13387
14480
  if (result?.ok === true) return result.value;
13388
14481
  if (result?.ok === false) {
13389
14482
  const error = new Error(result.error?.message || "\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
@@ -13435,18 +14528,18 @@ function validSuggestions(definition, value) {
13435
14528
  });
13436
14529
  }
13437
14530
  function maskRouteValue(value) {
13438
- const text6 = String(value ?? "").trim();
13439
- if (!text6) return "";
13440
- const at = text6.indexOf("@");
14531
+ const text7 = String(value ?? "").trim();
14532
+ if (!text7) return "";
14533
+ const at = text7.indexOf("@");
13441
14534
  if (at > 0) {
13442
- const local = text6.slice(0, at);
13443
- const domain = text6.slice(at);
14535
+ const local = text7.slice(0, at);
14536
+ const domain = text7.slice(at);
13444
14537
  const visible = local.length <= 4 ? `${local.slice(0, 1)}\u2022\u2022${local.slice(-1)}` : `${local.slice(0, 3)}\u2026${local.slice(-2)}`;
13445
14538
  return `${visible}${domain}`;
13446
14539
  }
13447
- if (text6.length <= 6) return `${text6.slice(0, 2)}\u2026${text6.slice(-1)}`;
13448
- if (text6.length <= 12) return `${text6.slice(0, 3)}\u2026${text6.slice(-3)}`;
13449
- return `${text6.slice(0, 5)}\u2026${text6.slice(-4)}`;
14540
+ if (text7.length <= 6) return `${text7.slice(0, 2)}\u2026${text7.slice(-1)}`;
14541
+ if (text7.length <= 12) return `${text7.slice(0, 3)}\u2026${text7.slice(-3)}`;
14542
+ return `${text7.slice(0, 5)}\u2026${text7.slice(-4)}`;
13450
14543
  }
13451
14544
  function suggestionFallbackName(definition, suggestion) {
13452
14545
  const displayName = suggestionDisplayName(suggestion);
@@ -13501,13 +14594,13 @@ function TargetForm({
13501
14594
  }) {
13502
14595
  const editing = mode === "edit";
13503
14596
  const initialKind = initialValue?.kind && definition.fields[initialValue.kind] ? initialValue.kind : definition.kinds[0].value;
13504
- const [targetId, setTargetId] = React24.useState(initialValue?.targetId ?? "");
13505
- const [name2, setName] = React24.useState(initialValue?.name ?? "");
13506
- const [kind, setKind] = React24.useState(initialKind);
13507
- const [route, setRoute] = React24.useState(initialValue?.route ?? {});
13508
- const [error, setError] = React24.useState(null);
13509
- const [testing, setTesting] = React24.useState(false);
13510
- const [testState, setTestState] = React24.useState(null);
14597
+ const [targetId, setTargetId] = React25.useState(initialValue?.targetId ?? "");
14598
+ const [name2, setName] = React25.useState(initialValue?.name ?? "");
14599
+ const [kind, setKind] = React25.useState(initialKind);
14600
+ const [route, setRoute] = React25.useState(initialValue?.route ?? {});
14601
+ const [error, setError] = React25.useState(null);
14602
+ const [testing, setTesting] = React25.useState(false);
14603
+ const [testState, setTestState] = React25.useState(null);
13511
14604
  const currentTarget = () => {
13512
14605
  const normalizedRoute = Object.fromEntries(fieldsFor(definition, kind).map((field) => {
13513
14606
  const raw = String(route[field.key] ?? "").trim();
@@ -13528,7 +14621,7 @@ function TargetForm({
13528
14621
  ...currentTarget()
13529
14622
  });
13530
14623
  } catch (caught) {
13531
- setError(presentError10(caught, "\u76EE\u6807\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5\u3002"));
14624
+ setError(presentError11(caught, "\u76EE\u6807\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5\u3002"));
13532
14625
  }
13533
14626
  };
13534
14627
  const testTarget = async () => {
@@ -13540,7 +14633,7 @@ function TargetForm({
13540
14633
  await onTest({ kind: target.kind, route: target.route });
13541
14634
  setTestState({ tone: "success", message: "\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\uFF0C\u8BF7\u5230\u76EE\u6807\u4F1A\u8BDD\u786E\u8BA4\u3002" });
13542
14635
  } catch (caught) {
13543
- setTestState({ tone: "error", message: presentError10(caught, "\u6D4B\u8BD5\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
14636
+ setTestState({ tone: "error", message: presentError11(caught, "\u6D4B\u8BD5\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
13544
14637
  } finally {
13545
14638
  setTesting(false);
13546
14639
  }
@@ -13724,7 +14817,7 @@ function TargetSuggestionPicker({
13724
14817
  suggestions.map((suggestion, index) => {
13725
14818
  const identity = routeIdentity(definition, suggestion);
13726
14819
  const added = configured.has(identity);
13727
- return React24.createElement("option", {
14820
+ return React25.createElement("option", {
13728
14821
  key: suggestion.id ?? suggestion.suggestionId ?? `${identity}:${index}`,
13729
14822
  value: String(index),
13730
14823
  disabled: added
@@ -13741,11 +14834,11 @@ function TargetSuggestionPicker({
13741
14834
  );
13742
14835
  }
13743
14836
  function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, onEdit }) {
13744
- const [action, setAction] = React24.useState(null);
13745
- const [testState, setTestState] = React24.useState(null);
13746
- const [syncFeedback, setSyncFeedback] = React24.useState(null);
13747
- const [copyState, setCopyState] = React24.useState(null);
13748
- const [confirmDelete, setConfirmDelete] = React24.useState(false);
14837
+ const [action, setAction] = React25.useState(null);
14838
+ const [testState, setTestState] = React25.useState(null);
14839
+ const [syncFeedback, setSyncFeedback] = React25.useState(null);
14840
+ const [copyState, setCopyState] = React25.useState(null);
14841
+ const [confirmDelete, setConfirmDelete] = React25.useState(false);
13749
14842
  const sessionSync = target.sessionSync ?? { enabled: false, state: "unavailable" };
13750
14843
  const syncDescription = sessionSync.state === "active" ? "\u81EA\u52A8\u8DDF\u968F\u8BE5\u79C1\u804A\u7684\u5F53\u524D\u4F1A\u8BDD" : sessionSync.state === "waiting" ? "\u7B49\u5F85\u8BE5\u79C1\u804A\u5EFA\u7ACB\u65B0\u4F1A\u8BDD" : sessionSync.state === "unavailable" ? "\u4EC5\u652F\u6301\u5DF2\u7ECF\u804A\u8FC7\u3001\u5DF2\u5EFA\u7ACB\u5F53\u524D\u4F1A\u8BDD\u4E14\u4F7F\u7528\u5F53\u524D Host Harness \u7684\u79C1\u804A\u76EE\u6807" : "\u5173\u95ED\u65F6\u4E0D\u53D1\u9001 DSH \u4F1A\u8BDD\u6D88\u606F";
13751
14844
  const testTarget = async () => {
@@ -13755,7 +14848,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
13755
14848
  await rpcCall(DELIVERY_ENDPOINTS.test, { botId, targetId: target.targetId });
13756
14849
  setTestState({ tone: "success", message: "\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\uFF0C\u8BF7\u5230\u76EE\u6807\u4F1A\u8BDD\u786E\u8BA4\u3002" });
13757
14850
  } catch (error) {
13758
- setTestState({ tone: "error", message: presentError10(error, "\u6D4B\u8BD5\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
14851
+ setTestState({ tone: "error", message: presentError11(error, "\u6D4B\u8BD5\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
13759
14852
  } finally {
13760
14853
  setAction(null);
13761
14854
  }
@@ -13766,7 +14859,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
13766
14859
  await copyText(JSON.stringify({ botId, targetId: target.targetId }));
13767
14860
  setCopyState("\u5DF2\u590D\u5236\u8C03\u7528\u53C2\u6570");
13768
14861
  } catch (error) {
13769
- setCopyState(presentError10(error, "\u590D\u5236\u5931\u8D25\u3002"));
14862
+ setCopyState(presentError11(error, "\u590D\u5236\u5931\u8D25\u3002"));
13770
14863
  }
13771
14864
  };
13772
14865
  const deleteTarget = async () => {
@@ -13775,7 +14868,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
13775
14868
  await rpcCall(DELIVERY_ENDPOINTS.delete, { botId, targetId: target.targetId });
13776
14869
  await onChanged();
13777
14870
  } catch (error) {
13778
- setTestState({ tone: "error", message: presentError10(error, "\u5220\u9664\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
14871
+ setTestState({ tone: "error", message: presentError11(error, "\u5220\u9664\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
13779
14872
  setAction(null);
13780
14873
  setConfirmDelete(false);
13781
14874
  }
@@ -13793,7 +14886,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
13793
14886
  } catch (error) {
13794
14887
  setSyncFeedback({
13795
14888
  tone: "error",
13796
- message: error?.code === "session-sync-unavailable" ? "\u4F1A\u8BDD\u540C\u6B65\u4EC5\u652F\u6301\u5DF2\u7ECF\u804A\u8FC7\u3001\u5DF2\u5EFA\u7ACB\u5F53\u524D\u4F1A\u8BDD\u4E14\u4F7F\u7528\u5F53\u524D Host Harness \u7684\u79C1\u804A\u76EE\u6807\u3002" : presentError10(error, "\u4F1A\u8BDD\u540C\u6B65\u8BBE\u7F6E\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002")
14889
+ message: error?.code === "session-sync-unavailable" ? "\u4F1A\u8BDD\u540C\u6B65\u4EC5\u652F\u6301\u5DF2\u7ECF\u804A\u8FC7\u3001\u5DF2\u5EFA\u7ACB\u5F53\u524D\u4F1A\u8BDD\u4E14\u4F7F\u7528\u5F53\u524D Host Harness \u7684\u79C1\u804A\u76EE\u6807\u3002" : presentError11(error, "\u4F1A\u8BDD\u540C\u6B65\u8BBE\u7F6E\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002")
13797
14890
  });
13798
14891
  } finally {
13799
14892
  setAction(null);
@@ -13808,7 +14901,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
13808
14901
  h2(
13809
14902
  "div",
13810
14903
  { className: "dim-targetTitle" },
13811
- React24.createElement("strong", null, target.name || target.targetId),
14904
+ React25.createElement("strong", null, target.name || target.targetId),
13812
14905
  h2("span", null, kindLabel(definition, target.kind))
13813
14906
  ),
13814
14907
  h2("code", null, `targetId: ${target.targetId}`)
@@ -13894,26 +14987,26 @@ function DeliveryTargetSettingsPage({
13894
14987
  onBack
13895
14988
  }) {
13896
14989
  const definition = CHANNEL_DEFINITIONS[channel4];
13897
- const [activeTabId, setActiveTabId] = React24.useState(BOT_SETTINGS_TABS[0].id);
13898
- const [phase, setPhase] = React24.useState("loading");
13899
- const [targets, setTargets] = React24.useState([]);
13900
- const [suggestionPhase, setSuggestionPhase] = React24.useState("idle");
13901
- const [suggestions, setSuggestions] = React24.useState([]);
13902
- const [suggestionError, setSuggestionError] = React24.useState(null);
13903
- const [error, setError] = React24.useState(null);
13904
- const [editor, setEditor] = React24.useState(null);
13905
- const [saving, setSaving] = React24.useState(false);
13906
- const [botCopyState, setBotCopyState] = React24.useState(null);
13907
- const [accessPolicy, setAccessPolicy] = React24.useState(account.accessPolicy);
13908
- const mounted = React24.useRef(true);
13909
- React24.useEffect(() => {
14990
+ const [activeTabId, setActiveTabId] = React25.useState(BOT_SETTINGS_TABS[0].id);
14991
+ const [phase, setPhase] = React25.useState("loading");
14992
+ const [targets, setTargets] = React25.useState([]);
14993
+ const [suggestionPhase, setSuggestionPhase] = React25.useState("idle");
14994
+ const [suggestions, setSuggestions] = React25.useState([]);
14995
+ const [suggestionError, setSuggestionError] = React25.useState(null);
14996
+ const [error, setError] = React25.useState(null);
14997
+ const [editor, setEditor] = React25.useState(null);
14998
+ const [saving, setSaving] = React25.useState(false);
14999
+ const [botCopyState, setBotCopyState] = React25.useState(null);
15000
+ const [accessPolicy, setAccessPolicy] = React25.useState(account.accessPolicy);
15001
+ const mounted = React25.useRef(true);
15002
+ React25.useEffect(() => {
13910
15003
  setAccessPolicy(account.accessPolicy);
13911
15004
  }, [account.botId, account.accessPolicy]);
13912
- const invoke = React24.useCallback(async (endpoint, payload = {}, signal) => {
15005
+ const invoke = React25.useCallback(async (endpoint, payload = {}, signal) => {
13913
15006
  if (typeof rpcCall !== "function") throw new Error("\u6295\u9012\u76EE\u6807\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
13914
- return unwrapRpcResult11(await rpcCall(endpoint, payload, signal));
15007
+ return unwrapRpcResult12(await rpcCall(endpoint, payload, signal));
13915
15008
  }, [rpcCall]);
13916
- const loadTargets = React24.useCallback(async ({ signal, silent = false } = {}) => {
15009
+ const loadTargets = React25.useCallback(async ({ signal, silent = false } = {}) => {
13917
15010
  if (!silent) setPhase("loading");
13918
15011
  setError(null);
13919
15012
  try {
@@ -13923,11 +15016,11 @@ function DeliveryTargetSettingsPage({
13923
15016
  setPhase("ready");
13924
15017
  } catch (caught) {
13925
15018
  if (signal?.aborted || caught?.name === "AbortError" || !mounted.current) return;
13926
- setError(presentError10(caught, "\u65E0\u6CD5\u8BFB\u53D6\u6295\u9012\u76EE\u6807\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
15019
+ setError(presentError11(caught, "\u65E0\u6CD5\u8BFB\u53D6\u6295\u9012\u76EE\u6807\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
13927
15020
  setPhase("error");
13928
15021
  }
13929
15022
  }, [account.botId, invoke]);
13930
- const loadSuggestions = React24.useCallback(async () => {
15023
+ const loadSuggestions = React25.useCallback(async () => {
13931
15024
  setSuggestionPhase("loading");
13932
15025
  setSuggestionError(null);
13933
15026
  try {
@@ -13937,11 +15030,11 @@ function DeliveryTargetSettingsPage({
13937
15030
  setSuggestionPhase("ready");
13938
15031
  } catch (caught) {
13939
15032
  if (caught?.name === "AbortError" || !mounted.current) return;
13940
- setSuggestionError(presentError10(caught, "\u65E0\u6CD5\u8BFB\u53D6\u5DF2\u804A\u4F1A\u8BDD\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
15033
+ setSuggestionError(presentError11(caught, "\u65E0\u6CD5\u8BFB\u53D6\u5DF2\u804A\u4F1A\u8BDD\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
13941
15034
  setSuggestionPhase("error");
13942
15035
  }
13943
15036
  }, [account.botId, definition, invoke]);
13944
- React24.useEffect(() => {
15037
+ React25.useEffect(() => {
13945
15038
  mounted.current = true;
13946
15039
  const controller = new AbortController();
13947
15040
  void loadTargets({ signal: controller.signal });
@@ -14009,7 +15102,7 @@ function DeliveryTargetSettingsPage({
14009
15102
  await copyText(account.botId);
14010
15103
  setBotCopyState("\u5DF2\u590D\u5236 Bot ID");
14011
15104
  } catch (caught) {
14012
- setBotCopyState(presentError10(caught, "\u590D\u5236\u5931\u8D25\u3002"));
15105
+ setBotCopyState(presentError11(caught, "\u590D\u5236\u5931\u8D25\u3002"));
14013
15106
  }
14014
15107
  };
14015
15108
  const settingsTabs = botSettingsTabsForChannel(channel4);
@@ -14063,7 +15156,7 @@ function DeliveryTargetSettingsPage({
14063
15156
  account,
14064
15157
  rpcCall: accessRpcCall
14065
15158
  }) : h2(
14066
- React24.Fragment,
15159
+ React25.Fragment,
14067
15160
  null,
14068
15161
  h2(
14069
15162
  "section",
@@ -14174,7 +15267,7 @@ function DeliveryTargetSettingsPage({
14174
15267
  }
14175
15268
 
14176
15269
  // plugin-src/client/global-settings.js
14177
- var React25 = __toESM(require("react"), 1);
15270
+ var React26 = __toESM(require("react"), 1);
14178
15271
 
14179
15272
  // src/channels/shared/inbound-ttl.mjs
14180
15273
  var DEFAULT_INBOUND_TTL_HOURS = 168;
@@ -14203,10 +15296,10 @@ var GLOBAL_SETTINGS_ENDPOINTS = Object.freeze({
14203
15296
  setTtl: "settings.inbound-ttl.set",
14204
15297
  sweep: "settings.inbound-ttl.sweep"
14205
15298
  });
14206
- function presentError11(error, fallback) {
15299
+ function presentError12(error, fallback) {
14207
15300
  return error?.message || fallback;
14208
15301
  }
14209
- function unwrapRpcResult12(result) {
15302
+ function unwrapRpcResult13(result) {
14210
15303
  if (result?.ok === true) return result.value;
14211
15304
  if (result?.ok === false) {
14212
15305
  const error = new Error(result.error?.message || "\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
@@ -14236,29 +15329,29 @@ function GlobalButton({ children, kind = "secondary", className = "", ...props }
14236
15329
  }, children);
14237
15330
  }
14238
15331
  function GlobalSettingsPanel({ rpcCall }) {
14239
- const [phase, setPhase] = React25.useState("loading");
14240
- const [loadError, setLoadError] = React25.useState(null);
14241
- const [ttlInput, setTtlInput] = React25.useState("");
14242
- const [savedTtl, setSavedTtl] = React25.useState(null);
14243
- const [ttlError, setTtlError] = React25.useState(false);
14244
- const [saveError, setSaveError] = React25.useState(null);
14245
- const [saveSucceeded, setSaveSucceeded] = React25.useState(false);
14246
- const [isSaving, setIsSaving] = React25.useState(false);
14247
- const [sweepConfirming, setSweepConfirming] = React25.useState(false);
14248
- const [sweeping, setSweeping] = React25.useState(false);
14249
- const ttlErrorId = React25.useId();
14250
- const ttlHintsId = React25.useId();
14251
- const sweepTriggerId = React25.useId();
14252
- const sweepConfirmId = React25.useId();
14253
- const sweepConfirmTextId = React25.useId();
14254
- const sweepConfirmButtonId = React25.useId();
14255
- const mounted = React25.useRef(true);
14256
- const saving = React25.useRef(false);
14257
- const invoke = React25.useCallback(async (endpoint, payload = {}, signal) => {
15332
+ const [phase, setPhase] = React26.useState("loading");
15333
+ const [loadError, setLoadError] = React26.useState(null);
15334
+ const [ttlInput, setTtlInput] = React26.useState("");
15335
+ const [savedTtl, setSavedTtl] = React26.useState(null);
15336
+ const [ttlError, setTtlError] = React26.useState(false);
15337
+ const [saveError, setSaveError] = React26.useState(null);
15338
+ const [saveSucceeded, setSaveSucceeded] = React26.useState(false);
15339
+ const [isSaving, setIsSaving] = React26.useState(false);
15340
+ const [sweepConfirming, setSweepConfirming] = React26.useState(false);
15341
+ const [sweeping, setSweeping] = React26.useState(false);
15342
+ const ttlErrorId = React26.useId();
15343
+ const ttlHintsId = React26.useId();
15344
+ const sweepTriggerId = React26.useId();
15345
+ const sweepConfirmId = React26.useId();
15346
+ const sweepConfirmTextId = React26.useId();
15347
+ const sweepConfirmButtonId = React26.useId();
15348
+ const mounted = React26.useRef(true);
15349
+ const saving = React26.useRef(false);
15350
+ const invoke = React26.useCallback(async (endpoint, payload = {}, signal) => {
14258
15351
  if (typeof rpcCall !== "function") throw new Error("\u901A\u7528\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
14259
- return unwrapRpcResult12(await rpcCall(endpoint, payload, signal));
15352
+ return unwrapRpcResult13(await rpcCall(endpoint, payload, signal));
14260
15353
  }, [rpcCall]);
14261
- const loadSettings = React25.useCallback(async ({ signal } = {}) => {
15354
+ const loadSettings = React26.useCallback(async ({ signal } = {}) => {
14262
15355
  setPhase("loading");
14263
15356
  setLoadError(null);
14264
15357
  try {
@@ -14278,11 +15371,11 @@ function GlobalSettingsPanel({ rpcCall }) {
14278
15371
  setPhase("ready");
14279
15372
  } catch (caught) {
14280
15373
  if (signal?.aborted || caught?.name === "AbortError" || !mounted.current) return;
14281
- setLoadError(presentError11(caught, "\u65E0\u6CD5\u8BFB\u53D6\u901A\u7528\u8BBE\u7F6E\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
15374
+ setLoadError(presentError12(caught, "\u65E0\u6CD5\u8BFB\u53D6\u901A\u7528\u8BBE\u7F6E\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
14282
15375
  setPhase("error");
14283
15376
  }
14284
15377
  }, [invoke]);
14285
- React25.useEffect(() => {
15378
+ React26.useEffect(() => {
14286
15379
  mounted.current = true;
14287
15380
  const controller = new AbortController();
14288
15381
  void loadSettings({ signal: controller.signal });
@@ -14291,7 +15384,7 @@ function GlobalSettingsPanel({ rpcCall }) {
14291
15384
  controller.abort();
14292
15385
  };
14293
15386
  }, [loadSettings]);
14294
- React25.useEffect(() => {
15387
+ React26.useEffect(() => {
14295
15388
  if (!sweepConfirming) return;
14296
15389
  globalThis.document?.getElementById(sweepConfirmButtonId)?.focus();
14297
15390
  }, [sweepConfirmButtonId, sweepConfirming]);
@@ -14322,7 +15415,7 @@ function GlobalSettingsPanel({ rpcCall }) {
14322
15415
  setPhase("ready");
14323
15416
  } catch (caught) {
14324
15417
  if (mounted.current) {
14325
- setSaveError(presentError11(caught, "\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
15418
+ setSaveError(presentError12(caught, "\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
14326
15419
  }
14327
15420
  } finally {
14328
15421
  saving.current = false;
@@ -14598,7 +15691,7 @@ function replacePageLocation(url, location = globalThis.location) {
14598
15691
 
14599
15692
  // plugin-src/client/styles.js
14600
15693
  var IM_STYLE_ID = "xmanrui-dsh-im-settings";
14601
- var CSS11 = String.raw`
15694
+ var CSS12 = String.raw`
14602
15695
  .dim-page {
14603
15696
  --dim-blue: var(--dsw-alias-state-business-primary, #3370ff);
14604
15697
  --dim-blue-soft: color-mix(in srgb, var(--dim-blue) 9%, transparent);
@@ -14669,9 +15762,7 @@ var CSS11 = String.raw`
14669
15762
  .dim-generalSettingsAction:hover .dim-generalSettingsTooltip, .dim-generalSettingsButton:focus-visible + .dim-generalSettingsTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
14670
15763
  .dim-generalSettingsButton[aria-current="page"] + .dim-generalSettingsTooltip { opacity: 0; visibility: hidden; transform: translateY(-3px); }
14671
15764
  .dim-layout { display: grid; grid-template-columns: 174px 1px minmax(0, 1fr); gap: 24px; align-items: start; }
14672
- .dim-rail { max-height: 520px; display: grid; align-content: start; gap: 8px; overflow-y: auto; padding: 0 4px 1px 1px; scrollbar-width: thin; scrollbar-color: var(--dsw-alias-border-l2, #dfe1e5) transparent; }
14673
- .dim-rail::-webkit-scrollbar { width: 4px; }
14674
- .dim-rail::-webkit-scrollbar-thumb { border-radius: 99px; background: var(--dsw-alias-border-l2, #dfe1e5); }
15765
+ .dim-rail { display: grid; align-content: start; gap: 8px; padding: 0 4px 1px 1px; }
14675
15766
  .dim-channel { width: 100%; min-height: 48px; display: grid; grid-template-columns: 30px minmax(0, 1fr); align-items: center; gap: 10px; padding: 8px 12px; border: 1px solid var(--dsw-alias-border-l2, #eef0f3); border-radius: 14px; color: inherit; background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 2px 8px rgb(31 35 41 / 3%); font: inherit; text-align: left; cursor: pointer; transition: border-color .16s ease, background .16s ease, box-shadow .16s ease; }
14676
15767
  .dim-channel:hover { border-color: color-mix(in srgb, var(--dim-blue) 25%, var(--dsw-alias-border-l2, #eef0f3)); background: color-mix(in srgb, var(--dim-blue) 2%, var(--dsw-alias-bg-layer-3, #fff)); box-shadow: 0 5px 16px rgb(31 35 41 / 5%); }
14677
15768
  .dim-channel[aria-selected="true"] { border-color: color-mix(in srgb, var(--dim-blue) 43%, var(--dsw-alias-border-l2, #dfe1e5)); color: var(--dim-blue); background: color-mix(in srgb, var(--dim-blue) 12%, var(--dsw-alias-bg-layer-3, #fff)); box-shadow: 0 3px 12px rgb(51 112 255 / 7%); }
@@ -14701,7 +15792,7 @@ var CSS11 = String.raw`
14701
15792
  .dim-channelCopy { min-width: 0; display: grid; }
14702
15793
  .dim-channelCopy strong { overflow: hidden; color: inherit; font-size: 14px; line-height: 20px; font-weight: 680; text-overflow: ellipsis; white-space: nowrap; }
14703
15794
  .dim-channelNote { overflow: hidden; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 10px; line-height: 13px; font-weight: 500; text-overflow: ellipsis; white-space: nowrap; }
14704
- .dim-divider { width: 1px; min-height: 520px; background: var(--dsw-alias-border-l1, #eef0f3); }
15795
+ .dim-divider { width: 1px; align-self: stretch; background: var(--dsw-alias-border-l1, #eef0f3); }
14705
15796
  .dim-panel { min-width: 0; container-type: inline-size; }
14706
15797
  .dim-loopbackRecovery { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin: 0 0 14px; padding: 14px 16px; border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary, #d97706) 30%, var(--dsw-alias-border-l2, #dfe1e5)); border-radius: 12px; color: var(--dsw-alias-label-primary, #1f2329); background: color-mix(in srgb, var(--dsw-alias-state-warn-primary, #d97706) 8%, var(--dsw-alias-bg-layer-1, #fff)); }
14707
15798
  .dim-loopbackRecoveryCopy { min-width: 0; }
@@ -14817,6 +15908,24 @@ var CSS11 = String.raw`
14817
15908
  .dim-panel .dim-presetStatus { grid-column: 2; grid-row: 1; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 12px; white-space: nowrap; }
14818
15909
  .dim-panel .dim-presetSelect { min-width: 0; max-width: 100%; grid-column: 1 / -1; grid-row: 2; height: 30px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 7px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 12px; }
14819
15910
  .dim-panel .dim-presetSelect:disabled { cursor: not-allowed; opacity: .55; }
15911
+ .dim-panel .dim-modelSetting { display: block; padding: 8px 4px 4px; }
15912
+ .dim-modelSetting > .dim-presetHeader { padding: 0 6px 6px; }
15913
+ .dim-modelRow { display: flex; align-items: center; gap: 8px; width: 100%; min-height: 40px; padding: 6px 10px; border: 0; border-radius: 10px; background: transparent; color: var(--dsw-alias-label-primary, #1f2329); font: inherit; font-size: 14px; line-height: 22px; text-align: left; cursor: pointer; }
15914
+ .dim-modelRowLabel { flex: none; }
15915
+ .dim-modelValue { flex: 1; min-width: 0; overflow: hidden; color: var(--dsw-alias-label-tertiary, #81858c); text-overflow: ellipsis; white-space: nowrap; text-align: right; }
15916
+ .dim-modelChevron { flex: none; color: var(--dsw-alias-label-tertiary, #81858c); }
15917
+ .dim-modelRow:hover:not(:disabled), .dim-modelOption:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, #eceef1); }
15918
+ .dim-modelRow:focus-visible, .dim-modelOption:focus-visible { outline: 2px solid var(--dsw-alias-border-l3, #1677ff); outline-offset: -2px; }
15919
+ .dim-modelRow:disabled, .dim-modelOption:disabled { opacity: .55; cursor: default; }
15920
+ /* In-flow lists avoid clipping by collapsed-card and settings scroll containers. */
15921
+ .dim-modelMenu { max-height: 280px; overflow-y: auto; margin: 4px; padding: 4px; border: 1px solid var(--dsw-alias-border-l2, #e5e6eb); border-radius: 12px; background: var(--dsw-specific-menu, var(--dsw-alias-bg-layer-3, #fff)); color: var(--dsw-alias-label-primary, #1f2329); scrollbar-width: thin; }
15922
+ .dim-modelGroupTitle { padding: 7px 8px 3px; color: var(--dsw-alias-label-tertiary, #81858c); font-size: 12px; line-height: 18px; font-weight: 500; }
15923
+ .dim-modelOption { display: flex; align-items: center; gap: 8px; width: 100%; min-height: 38px; padding: 6px 8px; border: 0; border-radius: 10px; background: transparent; color: inherit; text-align: left; font: inherit; cursor: pointer; }
15924
+ .dim-modelOptionCopy { display: flex; flex: 1; min-width: 0; flex-direction: column; gap: 2px; }
15925
+ .dim-modelOptionName { font-size: 14px; line-height: 20px; font-weight: 500; overflow-wrap: anywhere; }
15926
+ .dim-modelDescription { color: var(--dsw-alias-label-tertiary, #81858c); font-size: 12px; line-height: 18px; overflow-wrap: anywhere; }
15927
+ .dim-modelCheck { flex: 0 0 18px; text-align: center; }
15928
+ .dim-modelHint { margin: 4px 10px 6px; color: var(--dsw-alias-label-tertiary, #81858c); font-size: 11px; line-height: 17px; }
14820
15929
  .dim-panel .dim-presetError { grid-column: 1 / -1; grid-row: 3; margin: 0; color: var(--dsw-alias-state-error-primary, #d54941); font-size: 12px; line-height: 1.4; }
14821
15930
  .dim-contextEntry { width: 100%; min-height: 40px; display: grid; grid-template-columns: 16px minmax(0, 1fr) max-content 16px; align-items: center; gap: 9px; margin: 10px 0; padding: 8px 11px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-module-platform, #f7f8fa); font: inherit; font-size: 13px; line-height: 20px; text-align: left; cursor: pointer; }
14822
15931
  .dim-contextEntry:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, #eef0f3); }
@@ -15004,7 +16113,7 @@ var CSS11 = String.raw`
15004
16113
  .dim-feishuGroupSettings { min-width: 0; display: grid; gap: 14px; }
15005
16114
  .dim-feishuGroupControls { min-width: 0; display: grid; gap: 12px; }
15006
16115
  .dim-feishuGroupControl { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; padding: 16px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 12px; background: var(--dsw-alias-bg-layer-3, #fff); }
15007
- .dim-feishuGroupControlHeader { min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 12px; }
16116
+ .dim-feishuGroupControlHeader { position: relative; min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 12px; }
15008
16117
  .dim-feishuGroupControlHeader h3 { min-width: 0; margin: 0; color: var(--dsw-alias-label-primary, #1f2329); font-size: 14px; line-height: 21px; font-weight: 650; }
15009
16118
  .dim-feishuGroupControlStatus { flex: none; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 11px; line-height: 17px; }
15010
16119
  .dim-feishuGroupSelect { min-width: 0; width: 100%; height: 38px; padding: 0 34px 0 11px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 13px; line-height: 38px; cursor: pointer; transition: border-color .15s ease, box-shadow .15s ease; }
@@ -15206,9 +16315,8 @@ var CSS11 = String.raw`
15206
16315
  @media (max-width: 840px) {
15207
16316
  .dim-title { align-items: flex-start; }
15208
16317
  .dim-layout { grid-template-columns: minmax(0, 1fr); gap: 18px; }
15209
- .dim-rail { grid-template-columns: repeat(2, minmax(0, 1fr)); }
16318
+ .dim-rail { grid-template-columns: repeat(2, minmax(0, 1fr)); padding-right: 1px; }
15210
16319
  .dim-divider { display: none; }
15211
- .dim-rail { max-height: none; overflow: visible; padding-right: 1px; }
15212
16320
  .dim-channel { min-height: 48px; }
15213
16321
  }
15214
16322
  @media (max-width: 560px) {
@@ -15256,7 +16364,7 @@ function installImStyles() {
15256
16364
  const style = document.createElement("style");
15257
16365
  style.dataset.plugin = "@xmanrui/dsh-im";
15258
16366
  style.dataset.pluginCss = IM_STYLE_ID;
15259
- style.textContent = CSS11;
16367
+ style.textContent = CSS12;
15260
16368
  document.head.appendChild(style);
15261
16369
  return () => style.remove();
15262
16370
  }
@@ -15510,7 +16618,7 @@ function installSessionChannelLogos(document2 = globalThis.document) {
15510
16618
  }
15511
16619
 
15512
16620
  // plugin-src/client/update-panel.js
15513
- var React26 = __toESM(require("react"), 1);
16621
+ var React27 = __toESM(require("react"), 1);
15514
16622
  var import_react_dom3 = require("react-dom");
15515
16623
  var import_valid = __toESM(require_valid(), 1);
15516
16624
  var import_rcompare = __toESM(require_rcompare(), 1);
@@ -15557,7 +16665,7 @@ function unwrapSnapshot(result) {
15557
16665
  }
15558
16666
  return value;
15559
16667
  }
15560
- function presentError12(error) {
16668
+ function presentError13(error) {
15561
16669
  const code = error?.rpcError?.code ?? error?.code ?? "";
15562
16670
  const message = error?.rpcError?.message ?? error?.message ?? "";
15563
16671
  if (code === "update-unavailable" || /(?:not[-_ ]found|unimplemented|unknown[-_ ](?:endpoint|channel)|no[-_ ]handler)/i.test(code) || /(?:not found|unknown (?:endpoint|channel)|not registered|no .*handler|HTTP 404)/i.test(message)) {
@@ -15600,11 +16708,11 @@ function manualUpdateCommand(snapshot) {
15600
16708
  return `dsh plugin --profile ${profileArgument} add -w @xmanrui/dsh-im@${version}`;
15601
16709
  }
15602
16710
  function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
15603
- const [copyState, setCopyState] = React26.useState("idle");
15604
- const commandRef = React26.useRef(null);
15605
- const mounted = React26.useRef(false);
15606
- const copying = React26.useRef(false);
15607
- React26.useEffect(() => {
16711
+ const [copyState, setCopyState] = React27.useState("idle");
16712
+ const commandRef = React27.useRef(null);
16713
+ const mounted = React27.useRef(false);
16714
+ const copying = React27.useRef(false);
16715
+ React27.useEffect(() => {
15608
16716
  mounted.current = true;
15609
16717
  return () => {
15610
16718
  mounted.current = false;
@@ -15636,7 +16744,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
15636
16744
  { className: "dim-updateManual", "aria-label": "\u624B\u5DE5\u66F4\u65B0" },
15637
16745
  h2("h4", { className: "dim-updateManualHeading" }, "\u624B\u5DE5\u66F4\u65B0"),
15638
16746
  command ? h2(
15639
- React26.Fragment,
16747
+ React27.Fragment,
15640
16748
  null,
15641
16749
  h2("p", { className: "dim-updateManualHint" }, "\u81EA\u52A8\u66F4\u65B0\u5931\u8D25\u53EF\u4EE5\u4F7F\u7528\u547D\u4EE4\u66F4\u65B0\uFF1A"),
15642
16750
  h2(
@@ -15672,7 +16780,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
15672
16780
  "aria-hidden": "true",
15673
16781
  focusable: "false"
15674
16782
  }, copyState === "copied" ? h2("path", { d: "m4 10 4 4 8-8" }) : h2(
15675
- React26.Fragment,
16783
+ React27.Fragment,
15676
16784
  null,
15677
16785
  h2("rect", { x: 7, y: 7, width: 10, height: 11, rx: 1.5 }),
15678
16786
  h2("path", { d: "M5 13H3.5A1.5 1.5 0 0 1 2 11.5v-8A1.5 1.5 0 0 1 3.5 2h8A1.5 1.5 0 0 1 13 3.5V5" })
@@ -15697,10 +16805,10 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
15697
16805
  );
15698
16806
  }
15699
16807
  function UpdateDialog({ children, onClose }) {
15700
- const dialogRef = React26.useRef(null);
15701
- const titleId = React26.useId();
15702
- const descriptionId = React26.useId();
15703
- React26.useEffect(() => {
16808
+ const dialogRef = React27.useRef(null);
16809
+ const titleId = React27.useId();
16810
+ const descriptionId = React27.useId();
16811
+ React27.useEffect(() => {
15704
16812
  const previous = globalThis.document?.activeElement;
15705
16813
  dialogRef.current?.focus?.();
15706
16814
  return () => {
@@ -15758,19 +16866,19 @@ function UpdateDialog({ children, onClose }) {
15758
16866
  return typeof document !== "undefined" && document.body ? (0, import_react_dom3.createPortal)(content, document.body) : content;
15759
16867
  }
15760
16868
  function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
15761
- const [snapshot, setSnapshot] = React26.useState(null);
15762
- const [action, setAction] = React26.useState("status");
15763
- const [error, setError] = React26.useState(null);
15764
- const [open, setOpen] = React26.useState(false);
15765
- const [uncertainInstall, setUncertainInstall] = React26.useState(false);
15766
- const mounted = React26.useRef(false);
15767
- const busy = React26.useRef(false);
15768
- const readController = React26.useRef(null);
15769
- const pollReadController = React26.useRef(null);
15770
- const installRequest = React26.useRef(null);
15771
- const onStatusRef = React26.useRef(onStatus);
16869
+ const [snapshot, setSnapshot] = React27.useState(null);
16870
+ const [action, setAction] = React27.useState("status");
16871
+ const [error, setError] = React27.useState(null);
16872
+ const [open, setOpen] = React27.useState(false);
16873
+ const [uncertainInstall, setUncertainInstall] = React27.useState(false);
16874
+ const mounted = React27.useRef(false);
16875
+ const busy = React27.useRef(false);
16876
+ const readController = React27.useRef(null);
16877
+ const pollReadController = React27.useRef(null);
16878
+ const installRequest = React27.useRef(null);
16879
+ const onStatusRef = React27.useRef(onStatus);
15772
16880
  onStatusRef.current = onStatus;
15773
- const accept = React26.useCallback((next) => {
16881
+ const accept = React27.useCallback((next) => {
15774
16882
  setSnapshot(next);
15775
16883
  onStatusRef.current?.(next);
15776
16884
  }, []);
@@ -15779,7 +16887,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
15779
16887
  setUncertainInstall(false);
15780
16888
  accept(next);
15781
16889
  };
15782
- const invoke = React26.useCallback(async (endpoint, payload = {}, signal) => {
16890
+ const invoke = React27.useCallback(async (endpoint, payload = {}, signal) => {
15783
16891
  if (typeof rpcCall !== "function") {
15784
16892
  const unavailable = new Error("\u5F53\u524D Host \u4E0D\u652F\u6301\u66F4\u65B0\u63A5\u53E3\uFF0C\u8BF7\u5148\u624B\u52A8\u66F4\u65B0\u63D2\u4EF6\u5E76\u91CD\u542F\u3002");
15785
16893
  unavailable.code = "update-unavailable";
@@ -15787,14 +16895,14 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
15787
16895
  }
15788
16896
  return unwrapSnapshot(await rpcCall(endpoint, payload, signal));
15789
16897
  }, [rpcCall]);
15790
- React26.useEffect(() => {
16898
+ React27.useEffect(() => {
15791
16899
  mounted.current = true;
15792
16900
  busy.current = true;
15793
16901
  const controller = new AbortController();
15794
16902
  void invoke("update.status", {}, controller.signal).then((next) => {
15795
16903
  if (!controller.signal.aborted) accept(next);
15796
16904
  }).catch((cause) => {
15797
- if (!controller.signal.aborted) setError(presentError12(cause));
16905
+ if (!controller.signal.aborted) setError(presentError13(cause));
15798
16906
  }).finally(() => {
15799
16907
  if (!controller.signal.aborted) {
15800
16908
  busy.current = false;
@@ -15810,7 +16918,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
15810
16918
  const activeJob = ACTIVE_STATES4.has(snapshot?.job?.state);
15811
16919
  const restartRequired = snapshot?.job?.state === "restart-required" || snapshot?.blockedReason === "pending-restart";
15812
16920
  const shouldPoll = activeJob || uncertainInstall;
15813
- React26.useEffect(() => {
16921
+ React27.useEffect(() => {
15814
16922
  if (!shouldPoll) return void 0;
15815
16923
  let controller;
15816
16924
  const scheduler = createPollScheduler({
@@ -15831,7 +16939,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
15831
16939
  keepPolling = ACTIVE_STATES4.has(next.job?.state);
15832
16940
  }
15833
16941
  } catch (cause) {
15834
- if (!pendingController.signal.aborted) setError(presentError12(cause));
16942
+ if (!pendingController.signal.aborted) setError(presentError13(cause));
15835
16943
  } finally {
15836
16944
  if (pollReadController.current === pendingController) pollReadController.current = null;
15837
16945
  }
@@ -15862,7 +16970,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
15862
16970
  else acceptAuthoritative(next);
15863
16971
  }
15864
16972
  } catch (cause) {
15865
- if (!controller.signal.aborted && mounted.current) setError(presentError12(cause));
16973
+ if (!controller.signal.aborted && mounted.current) setError(presentError13(cause));
15866
16974
  } finally {
15867
16975
  if (!controller.signal.aborted && mounted.current) {
15868
16976
  busy.current = false;
@@ -15888,7 +16996,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
15888
16996
  if (mounted.current) acceptAuthoritative(next);
15889
16997
  } catch (cause) {
15890
16998
  if (mounted.current) {
15891
- setError(presentError12(cause));
16999
+ setError(presentError13(cause));
15892
17000
  setUncertainInstall(true);
15893
17001
  }
15894
17002
  } finally {
@@ -15908,7 +17016,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
15908
17016
  const manualCommand = manualUpdateCommand(snapshot);
15909
17017
  const buttonLabel = action === "checking" ? "\u68C0\u67E5\u4E2D\u2026" : action === "starting" || activeJob ? "\u6B63\u5728\u66F4\u65B0\u2026" : restartRequired ? "\u5F85\u624B\u52A8\u91CD\u542F" : snapshot?.canInstall ? "\u66F4\u65B0\u81F3" : "\u68C0\u67E5\u66F4\u65B0";
15910
17018
  return h2(
15911
- React26.Fragment,
17019
+ React27.Fragment,
15912
17020
  null,
15913
17021
  h2("button", {
15914
17022
  type: "button",
@@ -15933,13 +17041,13 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
15933
17041
  h2("dt", null, "\u8FD0\u884C\u7248\u672C"),
15934
17042
  h2("dd", null, `v${snapshot?.runningVersion ?? clientVersion}`),
15935
17043
  snapshot?.installedVersion && snapshot.installedVersion !== snapshot.runningVersion ? h2(
15936
- React26.Fragment,
17044
+ React27.Fragment,
15937
17045
  null,
15938
17046
  h2("dt", null, "\u5DF2\u5B89\u88C5\u7248\u672C"),
15939
17047
  h2("dd", null, `v${snapshot.installedVersion}`)
15940
17048
  ) : null,
15941
17049
  targetVersion ? h2(
15942
- React26.Fragment,
17050
+ React27.Fragment,
15943
17051
  null,
15944
17052
  h2("dt", null, "\u76EE\u6807\u7248\u672C"),
15945
17053
  h2("dd", null, `v${targetVersion}`)
@@ -16029,6 +17137,7 @@ var CHANNELS = Object.freeze([
16029
17137
  { id: "telegram", label: "Telegram" },
16030
17138
  { id: "discord", label: "Discord" },
16031
17139
  { id: "whatsapp", label: "WhatsApp" },
17140
+ { id: "wecomApp", label: "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528", note: "\uFF08\u5B9E\u9A8C\u529F\u80FD\uFF09" },
16032
17141
  { id: "office", label: "AI Office", note: "\uFF08\u5B9E\u9A8C\u529F\u80FD\uFF09" }
16033
17142
  ]);
16034
17143
  function WeixinLogo() {
@@ -16058,6 +17167,9 @@ function QqLogo() {
16058
17167
  function WecomLogo() {
16059
17168
  return h2("span", { className: "dim-logo dim-logoWecom", "aria-hidden": "true" }, h2(WecomLogoGlyph));
16060
17169
  }
17170
+ function WecomAppLogo() {
17171
+ return h2("span", { className: "dim-logo dim-logoWecomApp", "aria-hidden": "true" }, h2(WecomLogoGlyph));
17172
+ }
16061
17173
  function TelegramLogo() {
16062
17174
  return h2(
16063
17175
  "span",
@@ -16098,6 +17210,7 @@ function ChannelLogo({ channel: channel4 }) {
16098
17210
  if (channel4 === "feishu") return h2(FeishuLogo);
16099
17211
  if (channel4 === "dingtalk") return h2(DingtalkLogo);
16100
17212
  if (channel4 === "wecom") return h2(WecomLogo);
17213
+ if (channel4 === "wecomApp") return h2(WecomAppLogo);
16101
17214
  if (channel4 === "qq") return h2(QqLogo);
16102
17215
  if (channel4 === "slack") return h2(SlackLogo);
16103
17216
  if (channel4 === "telegram") return h2(TelegramLogo);
@@ -16134,6 +17247,7 @@ function IMSettingsTab({
16134
17247
  slackRpcCall,
16135
17248
  telegramRpcCall,
16136
17249
  wecomRpcCall,
17250
+ wecomAppRpcCall,
16137
17251
  weixinRpcCall,
16138
17252
  whatsappRpcCall,
16139
17253
  officeRpcCall,
@@ -16144,23 +17258,23 @@ function IMSettingsTab({
16144
17258
  browserLocation = globalThis.location,
16145
17259
  navigateToRecoveryUrl = replacePageLocation
16146
17260
  }) {
16147
- const [selected, setSelected] = React27.useState("weixin");
16148
- const [loopbackRecovery, setLoopbackRecovery] = React27.useState(null);
16149
- const [runningVersion, setRunningVersion] = React27.useState(IM_PLUGIN_VERSION);
16150
- const [deliverySettings, setDeliverySettings] = React27.useState(null);
16151
- const githubTooltipId = React27.useId();
16152
- const generalSettingsTooltipId = React27.useId();
17261
+ const [selected, setSelected] = React28.useState("weixin");
17262
+ const [loopbackRecovery, setLoopbackRecovery] = React28.useState(null);
17263
+ const [runningVersion, setRunningVersion] = React28.useState(IM_PLUGIN_VERSION);
17264
+ const [deliverySettings, setDeliverySettings] = React28.useState(null);
17265
+ const githubTooltipId = React28.useId();
17266
+ const generalSettingsTooltipId = React28.useId();
16153
17267
  const globalSettingsSelected = selected === GLOBAL_SETTINGS_TAB_ID;
16154
17268
  const active = CHANNELS.find((channel4) => channel4.id === selected) ?? CHANNELS[0];
16155
17269
  const activeTabId = globalSettingsSelected ? "dim-general-settings-trigger" : `dim-tab-${active.id}`;
16156
17270
  const activePanelId = globalSettingsSelected ? `dim-panel-${GLOBAL_SETTINGS_TAB_ID}` : `dim-panel-${active.id}`;
16157
- const reportLoopbackRecovery = React27.useCallback((recovery) => {
17271
+ const reportLoopbackRecovery = React28.useCallback((recovery) => {
16158
17272
  setLoopbackRecovery((current) => current?.url === recovery.url ? current : recovery);
16159
17273
  }, []);
16160
- const reportUpdateStatus = React27.useCallback((snapshot) => {
17274
+ const reportUpdateStatus = React28.useCallback((snapshot) => {
16161
17275
  setRunningVersion(snapshot.runningVersion);
16162
17276
  }, []);
16163
- const rpcCalls = React27.useMemo(() => createLoopbackAwareRpcCalls({
17277
+ const rpcCalls = React28.useMemo(() => createLoopbackAwareRpcCalls({
16164
17278
  dingtalkRpcCall,
16165
17279
  discordRpcCall,
16166
17280
  feishuRpcCall,
@@ -16168,6 +17282,7 @@ function IMSettingsTab({
16168
17282
  slackRpcCall,
16169
17283
  telegramRpcCall,
16170
17284
  wecomRpcCall,
17285
+ wecomAppRpcCall,
16171
17286
  weixinRpcCall,
16172
17287
  whatsappRpcCall,
16173
17288
  officeRpcCall,
@@ -16191,10 +17306,11 @@ function IMSettingsTab({
16191
17306
  telegramRpcCall,
16192
17307
  updateRpcCall,
16193
17308
  wecomRpcCall,
17309
+ wecomAppRpcCall,
16194
17310
  weixinRpcCall,
16195
17311
  whatsappRpcCall
16196
17312
  ]);
16197
- const botSettingsContext = React27.useMemo(() => Object.freeze({
17313
+ const botSettingsContext = React28.useMemo(() => Object.freeze({
16198
17314
  openBotSettings: setDeliverySettings
16199
17315
  }), []);
16200
17316
  return h2(
@@ -16323,7 +17439,7 @@ function IMSettingsTab({
16323
17439
  rpcCall: rpcCalls.deliveryRpcCall,
16324
17440
  accessRpcCall: rpcCalls[`${active.id}RpcCall`],
16325
17441
  onBack: () => setDeliverySettings(null)
16326
- }) : active.id === "weixin" ? h2(WeixinSettingsTab, { rpcCall: rpcCalls.weixinRpcCall }) : active.id === "feishu" ? h2(FeishuSettingsTab, { rpcCall: rpcCalls.feishuRpcCall }) : active.id === "dingtalk" ? h2(DingtalkSettingsTab, { rpcCall: rpcCalls.dingtalkRpcCall }) : active.id === "wecom" ? h2(WecomSettingsTab, { rpcCall: rpcCalls.wecomRpcCall }) : active.id === "qq" ? h2(QqSettingsTab, { rpcCall: rpcCalls.qqRpcCall }) : active.id === "slack" ? h2(SlackSettingsTab, { rpcCall: rpcCalls.slackRpcCall }) : active.id === "telegram" ? h2(TelegramSettingsTab, { rpcCall: rpcCalls.telegramRpcCall }) : active.id === "discord" ? h2(DiscordSettingsTab, { rpcCall: rpcCalls.discordRpcCall }) : active.id === "whatsapp" ? h2(WhatsappSettingsTab, { rpcCall: rpcCalls.whatsappRpcCall }) : h2(OfficeSettingsTab, { rpcCall: rpcCalls.officeRpcCall })
17442
+ }) : active.id === "weixin" ? h2(WeixinSettingsTab, { rpcCall: rpcCalls.weixinRpcCall }) : active.id === "feishu" ? h2(FeishuSettingsTab, { rpcCall: rpcCalls.feishuRpcCall }) : active.id === "dingtalk" ? h2(DingtalkSettingsTab, { rpcCall: rpcCalls.dingtalkRpcCall }) : active.id === "wecom" ? h2(WecomSettingsTab, { rpcCall: rpcCalls.wecomRpcCall }) : active.id === "wecomApp" ? h2(WecomAppSettingsTab, { rpcCall: rpcCalls.wecomAppRpcCall }) : active.id === "qq" ? h2(QqSettingsTab, { rpcCall: rpcCalls.qqRpcCall }) : active.id === "slack" ? h2(SlackSettingsTab, { rpcCall: rpcCalls.slackRpcCall }) : active.id === "telegram" ? h2(TelegramSettingsTab, { rpcCall: rpcCalls.telegramRpcCall }) : active.id === "discord" ? h2(DiscordSettingsTab, { rpcCall: rpcCalls.discordRpcCall }) : active.id === "whatsapp" ? h2(WhatsappSettingsTab, { rpcCall: rpcCalls.whatsappRpcCall }) : h2(OfficeSettingsTab, { rpcCall: rpcCalls.officeRpcCall })
16327
17443
  )
16328
17444
  )
16329
17445
  )
@@ -16343,6 +17459,7 @@ function apply(ctx) {
16343
17459
  installFeishuStyles(),
16344
17460
  installWeixinStyles(),
16345
17461
  installWecomStyles(),
17462
+ installWecomAppStyles(),
16346
17463
  installQqStyles(),
16347
17464
  installSlackStyles(),
16348
17465
  installTelegramStyles(),
@@ -16360,6 +17477,7 @@ function apply(ctx) {
16360
17477
  const dingtalkRpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(DINGTALK_RPC_CHANNEL, endpoint, payload, signal);
16361
17478
  const qqRpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(QQ_RPC_CHANNEL, endpoint, payload, signal);
16362
17479
  const wecomRpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(WECOM_RPC_CHANNEL, endpoint, payload, signal);
17480
+ const wecomAppRpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(WECOM_APP_RPC_CHANNEL, endpoint, payload, signal);
16363
17481
  const telegramRpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(TELEGRAM_RPC_CHANNEL, endpoint, payload, signal);
16364
17482
  const discordRpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(DISCORD_RPC_CHANNEL, endpoint, payload, signal);
16365
17483
  const whatsappRpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(WHATSAPP_RPC_CHANNEL, endpoint, payload, signal);
@@ -16386,6 +17504,7 @@ function apply(ctx) {
16386
17504
  slackRpcCall,
16387
17505
  telegramRpcCall,
16388
17506
  wecomRpcCall,
17507
+ wecomAppRpcCall,
16389
17508
  weixinRpcCall,
16390
17509
  whatsappRpcCall,
16391
17510
  officeRpcCall,