@xmanrui/dsh-im 4.24.0 → 4.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.en.md +11 -3
  2. package/README.md +11 -3
  3. package/THIRD_PARTY_NOTICES.md +2 -0
  4. package/lib/client.js +965 -607
  5. package/lib/index.js +296 -287
  6. package/package.json +8 -2
  7. package/plugin-src/client/channel-card-meta.js +3 -9
  8. package/plugin-src/client/channel-logos.js +11 -0
  9. package/plugin-src/client/channels/dingtalk/index.js +9 -8
  10. package/plugin-src/client/channels/feishu/index.js +14 -13
  11. package/plugin-src/client/channels/matrix/api.js +11 -0
  12. package/plugin-src/client/channels/matrix/index.js +151 -0
  13. package/plugin-src/client/channels/matrix/styles.js +36 -0
  14. package/plugin-src/client/channels/qq/index.js +9 -8
  15. package/plugin-src/client/channels/shared/collapsible-account.js +49 -26
  16. package/plugin-src/client/channels/shared/token-channel.js +9 -8
  17. package/plugin-src/client/channels/wecom/index.js +9 -8
  18. package/plugin-src/client/channels/wecom-app/index.js +9 -8
  19. package/plugin-src/client/channels/weixin/index.js +9 -8
  20. package/plugin-src/client/channels/whatsapp/index.js +9 -8
  21. package/plugin-src/client/i18n.js +21 -0
  22. package/plugin-src/client/index.js +20 -0
  23. package/plugin-src/client/session-channel-logos.js +2 -1
  24. package/plugin-src/client/styles.js +15 -9
  25. package/plugin-src/client/update-panel.js +42 -18
  26. package/plugin-src/host/channels/matrix/index.mjs +31 -0
  27. package/plugin-src/host/channels/matrix/production.mjs +227 -0
  28. package/plugin-src/host/channels/matrix/rpc.mjs +228 -0
  29. package/plugin-src/host/channels/shared/access-policy-production.mjs +1 -1
  30. package/plugin-src/host/channels/shared/startup-error.mjs +2 -1
  31. package/plugin-src/host/delivery-adapter.mjs +18 -0
  32. package/plugin-src/host/delivery-suggestions.mjs +13 -0
  33. package/plugin-src/host/index.mjs +3 -0
  34. package/plugin-src/host/update-service.mjs +19 -14
  35. package/scripts/verify-lan-management.mjs +1 -1
  36. package/scripts/verify-package.mjs +5 -1
  37. package/src/channels/feishu/bridge.mjs +91 -42
  38. package/src/channels/matrix/matrix-api.mjs +696 -0
  39. package/src/channels/matrix/matrix-bridge.mjs +20 -0
  40. package/src/channels/matrix/matrix-config-store.mjs +356 -0
  41. package/src/channels/matrix/matrix-controller.mjs +404 -0
  42. package/src/channels/matrix/matrix-crypto-store.mjs +279 -0
  43. package/src/channels/matrix/matrix-crypto.mjs +1014 -0
  44. package/src/channels/matrix/matrix-harness-client.mjs +11 -0
  45. package/src/channels/matrix/matrix-normalize.mjs +357 -0
  46. package/src/channels/matrix/matrix-rich-text.mjs +313 -0
  47. package/src/channels/matrix/matrix-runtime.mjs +900 -0
  48. package/src/channels/shared/command-catalog.mjs +1 -1
  49. package/src/channels/shared/i18n-en/matrix.mjs +75 -0
  50. package/src/channels/shared/i18n-en.mjs +2 -0
  51. package/src/channels/shared/session-channel-labels.mjs +1 -0
  52. package/src/channels/shared/text-harness-bridge.mjs +3 -0
  53. package/src/channels/shared/workspace-session.mjs +7 -1
package/lib/client.js CHANGED
@@ -568,13 +568,13 @@ __export(index_exports, {
568
568
  module.exports = __toCommonJS(index_exports);
569
569
 
570
570
  // plugin-src/management-rpc.mjs
571
- function rpcEndpoint(channel6) {
572
- if (!/^\/[A-Za-z0-9._~-]+$/.test(channel6)) throw new TypeError("Invalid IM RPC channel");
573
- return `dsh-im${channel6}`;
571
+ function rpcEndpoint(channel7) {
572
+ if (!/^\/[A-Za-z0-9._~-]+$/.test(channel7)) throw new TypeError("Invalid IM RPC channel");
573
+ return `dsh-im${channel7}`;
574
574
  }
575
- async function callManagementRpc(connection, channel6, method, payload, signal) {
575
+ async function callManagementRpc(connection, channel7, method, payload, signal) {
576
576
  try {
577
- return await connection.rpc.call("/api", rpcEndpoint(channel6), { method, payload }, signal);
577
+ return await connection.rpc.call("/api", rpcEndpoint(channel7), { method, payload }, signal);
578
578
  } catch (cause) {
579
579
  if (signal?.aborted || cause?.name === "AbortError") throw cause;
580
580
  const error = new Error("\u65E0\u6CD5\u8BBF\u95EE DSH \u7BA1\u7406\u63A5\u53E3\uFF0C\u8BF7\u68C0\u67E5 DSH \u8FDE\u63A5\u6216\u91CD\u65B0\u767B\u5F55\u540E\u91CD\u8BD5\u3002", { cause });
@@ -590,13 +590,13 @@ async function callManagementRpc(connection, channel6, method, payload, signal)
590
590
  }
591
591
 
592
592
  // plugin-src/client/index.js
593
- var React33 = __toESM(require("react"), 1);
593
+ var React34 = __toESM(require("react"), 1);
594
594
 
595
595
  // package.json
596
596
  var package_default = {
597
597
  name: "@xmanrui/dsh-im",
598
- version: "4.24.0",
599
- description: "\u628A\u5341\u4E00\u79CD IM \u6E20\u9053\u548C\u516C\u7F51 AI Office \u63A5\u5165\u672C\u673A DeepSeek Harness\u3002 Connect eleven IM channels and a public AI Office to a local DeepSeek Harness.",
598
+ version: "4.25.0",
599
+ description: "\u628A\u5341\u4E8C\u79CD IM \u6E20\u9053\u548C\u516C\u7F51 AI Office \u63A5\u5165\u672C\u673A DeepSeek Harness\u3002 Connect twelve IM channels and a public AI Office to a local DeepSeek Harness.",
600
600
  keywords: [
601
601
  "deepseek-harness",
602
602
  "dsh",
@@ -616,6 +616,7 @@ var package_default = {
616
616
  "discord",
617
617
  "whatsapp",
618
618
  "imessage",
619
+ "matrix",
619
620
  "ai-office"
620
621
  ],
621
622
  author: "xmanrui (https://github.com/xmanrui)",
@@ -675,6 +676,10 @@ var package_default = {
675
676
  {
676
677
  name: "wings1848",
677
678
  url: "https://github.com/wings1848"
679
+ },
680
+ {
681
+ name: "Zhe (Phil) Yang",
682
+ url: "https://github.com/yangzhe1991"
678
683
  }
679
684
  ],
680
685
  license: "MIT",
@@ -757,6 +762,7 @@ var package_default = {
757
762
  node: ">=22.19"
758
763
  },
759
764
  dependencies: {
765
+ "@matrix-org/olm": "3.2.15",
760
766
  "@tencent-connect/qqbot-connector": "1.2.0",
761
767
  "@tencent-connect/qqbot-nodejs": "1.0.4",
762
768
  "@wecom/aibot-node-sdk": "1.0.7",
@@ -946,6 +952,19 @@ function IMessageLogoGlyph({ size } = {}) {
946
952
  d: "M12 2.5C5.65 2.5.5 6.66.5 11.8c0 2.76 1.49 5.24 3.85 6.94.28 1.34-.35 2.76-1.6 4.01 2.1-.2 3.87-.86 5.26-1.85 1.25.4 2.6.62 3.99.62 6.35 0 11.5-4.35 11.5-9.72S18.35 2.5 12 2.5Z"
947
953
  }));
948
954
  }
955
+ function MatrixLogoGlyph({ size } = {}) {
956
+ return h("svg", {
957
+ ...dimensions(size),
958
+ viewBox: "0 0 24 24",
959
+ focusable: "false",
960
+ "aria-hidden": "true",
961
+ "data-im-channel-logo": "matrix"
962
+ }, h("path", {
963
+ fill: "currentColor",
964
+ "fill-rule": "evenodd",
965
+ d: "M4 4h16a2.4 2.4 0 0 1 2.4 2.4v8.2A2.4 2.4 0 0 1 20 17h-7.55l-4.2 3.3a.6.6 0 0 1-.98-.47V17H4A2.4 2.4 0 0 1 1.6 14.6V6.4A2.4 2.4 0 0 1 4 4Zm3 4.1a1.45 1.45 0 1 0 0 2.9 1.45 1.45 0 0 0 0-2.9Zm5.6 0a1.45 1.45 0 1 0 0 2.9 1.45 1.45 0 0 0 0-2.9Zm5.6 0a1.45 1.45 0 1 0 0 2.9 1.45 1.45 0 0 0 0-2.9Z"
966
+ }));
967
+ }
949
968
  function OfficeLogoGlyph({ size } = {}) {
950
969
  return h(
951
970
  "svg",
@@ -1232,6 +1251,8 @@ var EN = Object.freeze({
1232
1251
  "IM\u673A\u5668\u4EBA\u8BBE\u7F6E": "IM bot settings",
1233
1252
  "IM \u9762\u677F\u52A0\u8F7D\u5931\u8D25": "Could not load the IM panel",
1234
1253
  "\u66F4\u591A\u673A\u5668\u4EBA\u8BBE\u7F6E": "More bot settings",
1254
+ "\u66F4\u591A\u8BBE\u7F6E": "More settings",
1255
+ "\u5E38\u7528\u914D\u7F6E": "Common settings",
1235
1256
  "\u673A\u5668\u4EBA\u8BBE\u7F6E": "Bot settings",
1236
1257
  "\u673A\u5668\u4EBA\u8BBE\u7F6E\u9875\u7B7E": "Bot settings tabs",
1237
1258
  "\u6295\u9012\u8BBE\u7F6E": "Delivery settings",
@@ -1317,6 +1338,8 @@ var EN = Object.freeze({
1317
1338
  "\u5DF2\u5B89\u88C5\u7248\u672C": "Installed version",
1318
1339
  "\u76EE\u6807 profile": "Target profile",
1319
1340
  "\u76EE\u6807\u7248\u672C": "Target version",
1341
+ "\u6700\u65B0\u7248\u672C": "Latest version",
1342
+ "\u4E0A\u6B21\u66F4\u65B0\u76EE\u6807": "Previous update target",
1320
1343
  "\u65E0\u6CD5\u786E\u8BA4": "Unknown",
1321
1344
  "\u53D1\u73B0\u65B0\u7248\u672C": "Update available",
1322
1345
  "\u5DF2\u662F\u6700\u65B0\u7248\u672C": "Up to date",
@@ -1330,6 +1353,7 @@ var EN = Object.freeze({
1330
1353
  "\u66F4\u65B0\u5DF2\u751F\u6548": "Updated version is active",
1331
1354
  "\u66F4\u65B0\u5931\u8D25": "Update failed",
1332
1355
  "\u66F4\u65B0\u8BF7\u6C42\u5931\u8D25": "Update request failed",
1356
+ "\u6682\u65F6\u65E0\u6CD5\u5B89\u88C5\u66F4\u65B0": "Update installation is unavailable",
1333
1357
  "\u4EC5\u66F4\u65B0 DSH-IM\u3002\u5B89\u88C5\u5B8C\u6210\u540E\u9700\u624B\u52A8\u91CD\u542F\u540E\u53F0\uFF1B\u672C\u529F\u80FD\u4E0D\u4F1A\u81EA\u52A8\u91CD\u542F\u6216\u4E3B\u52A8\u5237\u65B0\u9875\u9762\u3002": "Only DSH-IM will be updated. Restart the backend manually after installation. This feature does not automatically restart it or initiate a page refresh.",
1334
1358
  "\u5F53\u524D\u662F\u6E90\u7801\u6216\u94FE\u63A5\u5B89\u88C5\uFF0C\u53EA\u80FD\u68C0\u67E5\u7248\u672C\uFF1B\u8BF7\u624B\u52A8\u66F4\u65B0\u6E90\u7801\uFF0C\u6216\u8FC1\u79FB\u5230 npm \u5B89\u88C5\u3002": "This is a source or linked installation. You can check versions, but must update the source manually or migrate to an npm installation.",
1335
1359
  "\u65E0\u6CD5\u786E\u8BA4\u5F53\u524D profile\uFF0C\u8BF7\u5728\u5BF9\u5E94\u7684 Harness \u73AF\u5883\u4E2D\u624B\u52A8\u66F4\u65B0\u3002": "The current profile could not be identified. Update manually in the corresponding Harness environment.",
@@ -1851,6 +1875,19 @@ var EN = Object.freeze({
1851
1875
  "Gateway \u957F\u8FDE\u63A5": "Gateway persistent connection",
1852
1876
  " Socket Mode \u957F\u8FDE\u63A5": " Socket Mode persistent connection",
1853
1877
  "Socket Mode \u957F\u8FDE\u63A5": "Socket Mode persistent connection",
1878
+ " CS API \u957F\u8F6E\u8BE2": " CS API long polling",
1879
+ "CS API \u957F\u8F6E\u8BE2": "CS API long polling",
1880
+ "\u63A5\u5165 Matrix \u673A\u5668\u4EBA": "Connect a Matrix bot",
1881
+ "\u8FDE\u63A5\u4F60\u7684 Matrix homeserver": "Connect your Matrix homeserver",
1882
+ "\u586B\u5199 homeserver \u5730\u5740\uFF0C\u5E76\u63D0\u4F9B\u8BBF\u95EE\u4EE4\u724C\uFF0C\u6216\u8005\u7528\u6237 ID \u4E0E\u5BC6\u7801\u7684\u7EC4\u5408\u3002\u673A\u5668\u4EBA\u53EA\u8BBF\u95EE\u8BE5 homeserver\uFF0C\u4E0D\u8FDE\u63A5\u7B2C\u4E09\u65B9\u670D\u52A1\u5668\u3002": "Enter the homeserver URL plus an access token, or a user id with a password. The bot only talks to that homeserver and never to third-party servers.",
1883
+ "Homeserver \u5730\u5740": "Homeserver URL",
1884
+ "\u8BBF\u95EE\u4EE4\u724C\uFF08\u4E0E\u7528\u6237 ID\u3001\u5BC6\u7801\u4E8C\u9009\u4E00\uFF09": "Access token (or user id + password)",
1885
+ "\u7528\u6237 ID\uFF08\u53EF\u9009\uFF09": "User id (optional)",
1886
+ "\u5BC6\u7801\uFF08\u53EF\u9009\uFF09": "Password (optional)",
1887
+ "\u8BBF\u95EE\u4EE4\u724C\u6765\u81EA Element \u8BBE\u7F6E \u2192 \u5E2E\u52A9 \u2192 \u7F16\u8F91\u8BBE\u7F6E\uFF0C\u6216 homeserver \u7684\u767B\u5F55\u63A5\u53E3\uFF1B\u7528\u6237 ID \u4E0E\u5BC6\u7801\u65B9\u5F0F\u4F1A\u4E3A\u672C\u5B89\u88C5\u6D3E\u751F\u7A33\u5B9A\u8BBE\u5907\u4F1A\u8BDD\u3002": "The access token comes from Element settings \u2192 Help \u2192 Advanced settings, or from the homeserver login API; the user id and password flow derives a stable device session for this installation.",
1888
+ "\u586B\u5199 homeserver \u5730\u5740\u4E0E\u8BBF\u95EE\u4EE4\u724C\uFF0C\u6216\u8005\u7528\u6237 ID \u4E0E\u5BC6\u7801\uFF0C\u5373\u53EF\u8BA9\u673A\u5668\u4EBA\u4EE5 CS API \u957F\u8F6E\u8BE2\u63A5\u6536\u6D88\u606F\u5E76\u4EE5\u5BCC\u6587\u672C\u56DE\u590D\u3002": "Enter the homeserver URL with an access token, or a user id with a password, and the bot receives messages over the CS API long poll and replies with rich text.",
1889
+ "\u4F7F\u7528 homeserver \u4E0E\u51ED\u636E\u63A5\u5165 Matrix \u673A\u5668\u4EBA": "Connect a Matrix bot with the homeserver and credentials",
1890
+ "\u8BBF\u95EE\u4EE4\u724C\u6216\u7528\u6237 ID \u4E0E\u5BC6\u7801": "access token or user id with password",
1854
1891
  "\u63A5\u5165 Telegram \u673A\u5668\u4EBA": "Connect a Telegram bot",
1855
1892
  "\u5148\u901A\u8FC7 @BotFather \u83B7\u53D6 Bot Token\uFF0C\u518D\u5728\u8FD9\u91CC\u5B8C\u6210\u63A5\u5165\u3002": "Get a Bot Token from @BotFather, then connect it here.",
1856
1893
  "\u586B\u5199 @BotFather \u751F\u6210\u7684 Bot Token": "Enter the Bot Token from @BotFather",
@@ -4024,7 +4061,7 @@ function CredentialActionIcon() {
4024
4061
  );
4025
4062
  }
4026
4063
  function CredentialBindingPanel({
4027
- channel: channel6,
4064
+ channel: channel7,
4028
4065
  identityLabel,
4029
4066
  identityPlaceholder,
4030
4067
  secretLabel,
@@ -4052,7 +4089,7 @@ function CredentialBindingPanel({
4052
4089
  className: "ddt-card dim-surfaceCard dim-credentialPanel",
4053
4090
  "aria-labelledby": headingId
4054
4091
  },
4055
- h2("h3", { id: headingId, className: "dim-credentialTitle" }, `\u624B\u52A8\u63A5\u5165${channel6}\u673A\u5668\u4EBA`),
4092
+ h2("h3", { id: headingId, className: "dim-credentialTitle" }, `\u624B\u52A8\u63A5\u5165${channel7}\u673A\u5668\u4EBA`),
4056
4093
  children,
4057
4094
  h2(
4058
4095
  "form",
@@ -4117,9 +4154,206 @@ function CredentialBindingPanel({
4117
4154
  }
4118
4155
 
4119
4156
  // plugin-src/client/channels/shared/collapsible-account.js
4157
+ var React9 = __toESM(require("react"), 1);
4158
+
4159
+ // plugin-src/client/channel-card-meta.js
4120
4160
  var React8 = __toESM(require("react"), 1);
4161
+ var BotSettingsContext = React8.createContext(Object.freeze({
4162
+ openBotSettings() {
4163
+ }
4164
+ }));
4165
+ function SettingsGlyph() {
4166
+ return h2(
4167
+ "svg",
4168
+ {
4169
+ viewBox: "0 0 24 24",
4170
+ width: 16,
4171
+ height: 16,
4172
+ fill: "none",
4173
+ stroke: "currentColor",
4174
+ strokeWidth: 1.8,
4175
+ strokeLinecap: "round",
4176
+ strokeLinejoin: "round",
4177
+ "aria-hidden": "true"
4178
+ },
4179
+ h2("circle", { cx: 12, cy: 12, r: 3 }),
4180
+ h2("path", { d: "M19.4 15a1.7 1.7 0 0 0 .34 1.88l.06.06-2.83 2.83-.06-.06a1.7 1.7 0 0 0-1.88-.34 1.7 1.7 0 0 0-1.03 1.55V21h-4v-.08A1.7 1.7 0 0 0 8.97 19.4a1.7 1.7 0 0 0-1.88.34l-.06.06-2.83-2.83.06-.06A1.7 1.7 0 0 0 4.6 15a1.7 1.7 0 0 0-1.52-1.03H3v-4h.08A1.7 1.7 0 0 0 4.6 8.97a1.7 1.7 0 0 0-.34-1.88l-.06-.06L7.03 4.2l.06.06a1.7 1.7 0 0 0 1.88.34A1.7 1.7 0 0 0 10 3.08V3h4v.08a1.7 1.7 0 0 0 1.03 1.52 1.7 1.7 0 0 0 1.88-.34l.06-.06 2.83 2.83-.06.06a1.7 1.7 0 0 0-.34 1.88A1.7 1.7 0 0 0 20.92 10H21v4h-.08A1.7 1.7 0 0 0 19.4 15Z" })
4181
+ );
4182
+ }
4183
+ function BotSettingsButton({
4184
+ channel: channel7,
4185
+ botId,
4186
+ botName,
4187
+ connected,
4188
+ accessPolicy,
4189
+ channelSettings
4190
+ }) {
4191
+ const { openBotSettings } = React8.useContext(BotSettingsContext);
4192
+ return h2(
4193
+ "span",
4194
+ { className: "dim-botSettingsAction" },
4195
+ h2(
4196
+ "button",
4197
+ {
4198
+ type: "button",
4199
+ className: "dim-botSettingsButton",
4200
+ "data-delivery-channel": channel7,
4201
+ "aria-label": "\u66F4\u591A\u673A\u5668\u4EBA\u8BBE\u7F6E",
4202
+ onClick: () => openBotSettings?.({
4203
+ ...channelSettings && typeof channelSettings === "object" ? channelSettings : {},
4204
+ channel: channel7,
4205
+ botId,
4206
+ botName,
4207
+ connected: Boolean(connected),
4208
+ accessPolicy
4209
+ })
4210
+ },
4211
+ h2(SettingsGlyph),
4212
+ h2("span", null, "\u66F4\u591A\u8BBE\u7F6E"),
4213
+ h2("span", { className: "dim-moreSettingsChevron", "aria-hidden": "true" })
4214
+ )
4215
+ );
4216
+ }
4217
+ function messageErrorTime(value) {
4218
+ try {
4219
+ return new Intl.DateTimeFormat(isEnglish() ? "en-US" : "zh-CN", {
4220
+ year: "numeric",
4221
+ month: "2-digit",
4222
+ day: "2-digit",
4223
+ hour: "2-digit",
4224
+ minute: "2-digit"
4225
+ }).format(new Date(value));
4226
+ } catch {
4227
+ return null;
4228
+ }
4229
+ }
4230
+ function ChannelListHeading({ className = "", id: id6, title, connectionLabel }) {
4231
+ const helpId = React8.useId();
4232
+ return h2(
4233
+ "div",
4234
+ { className: `${className} dim-listHeading`.trim() },
4235
+ h2(
4236
+ "div",
4237
+ { className: "dim-listTitle" },
4238
+ h2("h3", id6 ? { id: id6 } : null, title),
4239
+ h2(
4240
+ "span",
4241
+ { className: "dim-channelHelp" },
4242
+ h2("button", {
4243
+ type: "button",
4244
+ className: "dim-channelHelpButton",
4245
+ "aria-label": "\u67E5\u770B\u6D88\u606F\u901A\u9053\u8BF4\u660E",
4246
+ "aria-describedby": helpId
4247
+ }, h2("span", { "aria-hidden": "true" }, "?")),
4248
+ h2(
4249
+ "span",
4250
+ {
4251
+ id: helpId,
4252
+ className: "dim-channelTooltip",
4253
+ role: "tooltip"
4254
+ },
4255
+ h2("span", null, "\u6D88\u606F\u901A\u9053"),
4256
+ h2("strong", null, connectionLabel)
4257
+ )
4258
+ )
4259
+ )
4260
+ );
4261
+ }
4262
+ function BotStatusMeta({
4263
+ className = "",
4264
+ dotClassName = "",
4265
+ tone,
4266
+ stateLabel: stateLabel2,
4267
+ lastCheckedAt,
4268
+ formatCheckedTime: formatCheckedTime2,
4269
+ healthState
4270
+ }) {
4271
+ return h2(
4272
+ "div",
4273
+ { className: "dim-botHealthGroup" },
4274
+ h2(
4275
+ "div",
4276
+ {
4277
+ className: `${className} dim-botHealth`.trim(),
4278
+ ...healthState ? { "data-health": healthState } : {}
4279
+ },
4280
+ h2("span", {
4281
+ className: `${dotClassName} dim-healthDot`.trim(),
4282
+ "data-tone": tone
4283
+ }),
4284
+ h2("span", null, stateLabel2)
4285
+ ),
4286
+ h2(
4287
+ "div",
4288
+ { className: "dim-lastChecked" },
4289
+ h2("span", null, "\u6700\u8FD1\u68C0\u67E5"),
4290
+ h2("span", null, formatCheckedTime2(lastCheckedAt))
4291
+ )
4292
+ );
4293
+ }
4294
+ function LastMessageErrorSummary({ className = "", error }) {
4295
+ if (!error) return null;
4296
+ const occurredAt = messageErrorTime(error.at);
4297
+ return h2(
4298
+ "div",
4299
+ {
4300
+ className: `${className} dim-cardSummary`.trim(),
4301
+ role: "status"
4302
+ },
4303
+ h2("strong", null, "\u6700\u8FD1\u4E00\u6761\u6D88\u606F\u5904\u7406\u5931\u8D25"),
4304
+ "\uFF1A",
4305
+ h2("span", null, error.message),
4306
+ error.details ? h2(ConnectionError, { error, showMessage: false }) : null,
4307
+ "\uFF08",
4308
+ h2("span", null, "\u9519\u8BEF\u7801"),
4309
+ ` ${error.code} \xB7 `,
4310
+ h2("span", null, "\u53C2\u8003\u53F7"),
4311
+ ` ${error.referenceId}`,
4312
+ occurredAt ? h2(
4313
+ React8.Fragment,
4314
+ null,
4315
+ " \xB7 ",
4316
+ h2("time", { dateTime: new Date(error.at).toISOString() }, occurredAt)
4317
+ ) : null,
4318
+ "\uFF09"
4319
+ );
4320
+ }
4321
+
4322
+ // plugin-src/client/channels/shared/collapsible-account.js
4323
+ var AccountSectionContext = React9.createContext(null);
4324
+ function AccountSettingsToggle() {
4325
+ const { open, toggle, contentId } = React9.useContext(AccountSectionContext);
4326
+ return h2(
4327
+ "button",
4328
+ {
4329
+ type: "button",
4330
+ className: "dim-accountSettingsToggle",
4331
+ "aria-label": open ? "\u6536\u8D77\u8BE5\u8D26\u53F7\u7684\u8BBE\u7F6E" : "\u5C55\u5F00\u8BE5\u8D26\u53F7\u7684\u8BBE\u7F6E",
4332
+ "aria-expanded": open ? "true" : "false",
4333
+ "aria-controls": contentId,
4334
+ onClick: (event) => {
4335
+ event.stopPropagation();
4336
+ toggle();
4337
+ }
4338
+ },
4339
+ h2(SettingsGlyph),
4340
+ h2("svg", {
4341
+ className: "dim-collapsibleChevron",
4342
+ viewBox: "0 0 12 16",
4343
+ width: 12,
4344
+ height: 16,
4345
+ fill: "none",
4346
+ stroke: "currentColor",
4347
+ strokeWidth: 1.8,
4348
+ strokeLinecap: "round",
4349
+ strokeLinejoin: "round",
4350
+ "aria-hidden": "true"
4351
+ }, h2("path", { d: "M2 6 6 10 10 6" }))
4352
+ );
4353
+ }
4121
4354
  function CollapsibleAccountSection({
4122
4355
  header,
4356
+ settings,
4123
4357
  defaultOpen = false,
4124
4358
  open: controlledOpen,
4125
4359
  onToggle,
@@ -4127,57 +4361,59 @@ function CollapsibleAccountSection({
4127
4361
  className = "",
4128
4362
  children
4129
4363
  }) {
4130
- const [uncontrolledOpen, setUncontrolledOpen] = React8.useState(defaultOpen);
4364
+ const [uncontrolledOpen, setUncontrolledOpen] = React9.useState(defaultOpen);
4365
+ const generatedId = React9.useId();
4131
4366
  const open = controlledOpen ?? uncontrolledOpen;
4132
- const contentId = id6 ? `${id6}-content` : void 0;
4367
+ const contentId = `${id6 ?? generatedId}-content`;
4133
4368
  const toggle = () => {
4134
4369
  if (controlledOpen === void 0) setUncontrolledOpen((value) => !value);
4135
4370
  onToggle?.(!open);
4136
4371
  };
4137
- const onKeyDown = (event) => {
4138
- if (event.key === "Enter" || event.key === " " || event.key === "Spacebar") {
4139
- event.preventDefault();
4140
- toggle();
4141
- }
4142
- };
4143
4372
  return h2(
4144
- "div",
4145
- {
4146
- className: `dim-collapsibleAccount ${open ? "is-open" : ""} ${className}`.trim(),
4147
- "data-open": open ? "true" : "false"
4148
- },
4149
- h2(
4150
- "div",
4151
- {
4152
- className: "dim-collapsibleHead",
4153
- role: "button",
4154
- tabIndex: 0,
4155
- onClick: toggle,
4156
- onKeyDown,
4157
- "aria-expanded": open ? "true" : "false",
4158
- "aria-controls": contentId,
4159
- "aria-label": open ? "\u6536\u8D77\u8BE5\u8D26\u53F7\u7684\u8BBE\u7F6E" : "\u5C55\u5F00\u8BE5\u8D26\u53F7\u7684\u8BBE\u7F6E"
4160
- },
4161
- h2("div", { className: "dim-collapsibleHeaderContent" }, header),
4162
- h2("span", { className: "dim-collapsibleChevron", "aria-hidden": "true" })
4163
- ),
4373
+ AccountSectionContext.Provider,
4374
+ { value: { open, toggle, contentId } },
4164
4375
  h2(
4165
4376
  "div",
4166
4377
  {
4167
- id: contentId,
4168
- className: "dim-collapsibleBody",
4169
- role: "region"
4378
+ className: `dim-collapsibleAccount ${open ? "is-open" : ""} ${className}`.trim(),
4379
+ "data-open": open ? "true" : "false"
4170
4380
  },
4171
- h2("div", { className: "dim-collapsibleBodyInner" }, children)
4381
+ h2(
4382
+ "div",
4383
+ {
4384
+ className: "dim-collapsibleHead",
4385
+ onClick: toggle
4386
+ },
4387
+ h2("div", { className: "dim-collapsibleHeaderContent" }, header)
4388
+ ),
4389
+ h2(
4390
+ "div",
4391
+ {
4392
+ id: contentId,
4393
+ className: "dim-collapsibleBody",
4394
+ role: "region"
4395
+ },
4396
+ h2(
4397
+ "div",
4398
+ { className: "dim-collapsibleBodyInner" },
4399
+ settings ? h2(
4400
+ "div",
4401
+ { className: "dim-accountSettingsHeader" },
4402
+ h2("span", null, "\u5E38\u7528\u914D\u7F6E"),
4403
+ settings
4404
+ ) : null,
4405
+ children
4406
+ )
4407
+ )
4172
4408
  )
4173
4409
  );
4174
4410
  }
4175
4411
 
4176
4412
  // plugin-src/client/workspace-editor.js
4177
- var React10 = __toESM(require("react"), 1);
4413
+ var React11 = __toESM(require("react"), 1);
4178
4414
 
4179
4415
  // plugin-src/client/workspace-directory-picker.js
4180
- var React9 = __toESM(require("react"), 1);
4416
+ var React10 = __toESM(require("react"), 1);
4181
4417
  var import_react_dom2 = require("react-dom");
4182
4418
  function pickerErrorCode(error) {
4183
4419
  return error?.rpcError?.code ?? error?.code;
@@ -4198,7 +4434,7 @@ function pickerErrorMessage(error) {
4198
4434
  return error?.rpcError?.message ?? error?.message ?? "\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\uFF0C\u8BF7\u91CD\u8BD5\u3002";
4199
4435
  }
4200
4436
  function FolderIcon() {
4201
- return React9.createElement(
4437
+ return React10.createElement(
4202
4438
  "svg",
4203
4439
  {
4204
4440
  viewBox: "0 0 24 24",
@@ -4209,11 +4445,11 @@ function FolderIcon() {
4209
4445
  strokeLinejoin: "round",
4210
4446
  "aria-hidden": "true"
4211
4447
  },
4212
- React9.createElement("path", { d: "M3.5 7.25A2.25 2.25 0 0 1 5.75 5h4.1l1.8 2h6.6a2.25 2.25 0 0 1 2.25 2.25v7A2.75 2.75 0 0 1 17.75 19h-12A2.25 2.25 0 0 1 3.5 16.75v-9.5Z" })
4448
+ React10.createElement("path", { d: "M3.5 7.25A2.25 2.25 0 0 1 5.75 5h4.1l1.8 2h6.6a2.25 2.25 0 0 1 2.25 2.25v7A2.75 2.75 0 0 1 17.75 19h-12A2.25 2.25 0 0 1 3.5 16.75v-9.5Z" })
4213
4449
  );
4214
4450
  }
4215
4451
  function ChevronIcon() {
4216
- return React9.createElement("svg", {
4452
+ return React10.createElement("svg", {
4217
4453
  viewBox: "0 0 20 20",
4218
4454
  fill: "none",
4219
4455
  stroke: "currentColor",
@@ -4221,7 +4457,7 @@ function ChevronIcon() {
4221
4457
  strokeLinecap: "round",
4222
4458
  strokeLinejoin: "round",
4223
4459
  "aria-hidden": "true"
4224
- }, React9.createElement("path", { d: "m7.5 4.5 5 5.5-5 5.5" }));
4460
+ }, React10.createElement("path", { d: "m7.5 4.5 5 5.5-5 5.5" }));
4225
4461
  }
4226
4462
  function displayCrumbs(listing) {
4227
4463
  const homeIndex = listing.crumbs.findIndex((crumb) => crumb.path === listing.home);
@@ -4237,28 +4473,28 @@ function WorkspaceDirectoryPicker({
4237
4473
  onPicked,
4238
4474
  onCancel
4239
4475
  }) {
4240
- const [listing, setListing] = React9.useState(null);
4241
- const [loading, setLoading] = React9.useState(false);
4242
- const [error, setError] = React9.useState(null);
4243
- const [pathDraft, setPathDraft] = React9.useState(startPath ?? "");
4244
- const [showHidden, setShowHidden] = React9.useState(false);
4245
- const [retryKey, setRetryKey] = React9.useState(0);
4246
- const requestRef = React9.useRef(0);
4247
- const controllerRef = React9.useRef(null);
4248
- const dialogRef = React9.useRef(null);
4249
- const bodyRef = React9.useRef(null);
4250
- const titleId = React9.useId();
4251
- const noticeId = React9.useId();
4252
- const pathInputId = React9.useId();
4253
- const errorId = React9.useId();
4254
- const initialPathRef = React9.useRef(startPath);
4255
- const onPickedRef = React9.useRef(onPicked);
4256
- const onCancelRef = React9.useRef(onCancel);
4257
- const busyRef = React9.useRef(busy);
4476
+ const [listing, setListing] = React10.useState(null);
4477
+ const [loading, setLoading] = React10.useState(false);
4478
+ const [error, setError] = React10.useState(null);
4479
+ const [pathDraft, setPathDraft] = React10.useState(startPath ?? "");
4480
+ const [showHidden, setShowHidden] = React10.useState(false);
4481
+ const [retryKey, setRetryKey] = React10.useState(0);
4482
+ const requestRef = React10.useRef(0);
4483
+ const controllerRef = React10.useRef(null);
4484
+ const dialogRef = React10.useRef(null);
4485
+ const bodyRef = React10.useRef(null);
4486
+ const titleId = React10.useId();
4487
+ const noticeId = React10.useId();
4488
+ const pathInputId = React10.useId();
4489
+ const errorId = React10.useId();
4490
+ const initialPathRef = React10.useRef(startPath);
4491
+ const onPickedRef = React10.useRef(onPicked);
4492
+ const onCancelRef = React10.useRef(onCancel);
4493
+ const busyRef = React10.useRef(busy);
4258
4494
  onPickedRef.current = onPicked;
4259
4495
  onCancelRef.current = onCancel;
4260
4496
  busyRef.current = busy;
4261
- const loadDirectory = React9.useCallback(async (path, { reportError = true } = {}) => {
4497
+ const loadDirectory = React10.useCallback(async (path, { reportError = true } = {}) => {
4262
4498
  const request = requestRef.current + 1;
4263
4499
  requestRef.current = request;
4264
4500
  controllerRef.current?.abort();
@@ -4282,7 +4518,7 @@ function WorkspaceDirectoryPicker({
4282
4518
  if (request === requestRef.current) setLoading(false);
4283
4519
  }
4284
4520
  }, [picker]);
4285
- React9.useEffect(() => {
4521
+ React10.useEffect(() => {
4286
4522
  if (!open) return void 0;
4287
4523
  let active = true;
4288
4524
  setListing(null);
@@ -4362,10 +4598,10 @@ function WorkspaceDirectoryPicker({
4362
4598
  "nav",
4363
4599
  { className: "dim-directoryCrumbs", "aria-label": "\u5F53\u524D\u76EE\u5F55" },
4364
4600
  crumbs.map((crumb, index) => h2(
4365
- React9.Fragment,
4601
+ React10.Fragment,
4366
4602
  { key: crumb.path },
4367
4603
  index > 0 ? h2("span", { className: "dim-directoryCrumbSeparator", "aria-hidden": "true" }, "\u203A") : null,
4368
- React9.createElement("button", {
4604
+ React10.createElement("button", {
4369
4605
  type: "button",
4370
4606
  title: crumb.path,
4371
4607
  disabled: loading || busy,
@@ -4428,7 +4664,7 @@ function WorkspaceDirectoryPicker({
4428
4664
  ) : listing ? entries.length > 0 ? h2("ul", { className: "dim-directoryList" }, entries.map((entry) => h2(
4429
4665
  "li",
4430
4666
  { key: entry.path },
4431
- React9.createElement(
4667
+ React10.createElement(
4432
4668
  "button",
4433
4669
  {
4434
4670
  type: "button",
@@ -4437,7 +4673,7 @@ function WorkspaceDirectoryPicker({
4437
4673
  onClick: () => void loadDirectory(entry.path)
4438
4674
  },
4439
4675
  h2("span", { className: "dim-directoryFolder" }, h2(FolderIcon)),
4440
- React9.createElement("span", { className: "dim-directoryName" }, entry.name),
4676
+ React10.createElement("span", { className: "dim-directoryName" }, entry.name),
4441
4677
  h2("span", { className: "dim-directoryChevron" }, h2(ChevronIcon))
4442
4678
  )
4443
4679
  ))) : h2(
@@ -4490,21 +4726,21 @@ function WorkspaceDirectoryPicker({
4490
4726
  }
4491
4727
 
4492
4728
  // plugin-src/client/workspace-editor.js
4493
- var WorkspaceDirectoryPickerContext = React10.createContext(null);
4729
+ var WorkspaceDirectoryPickerContext = React11.createContext(null);
4494
4730
  function WorkspaceEditor({ workspace, directoryPicker, disabled = false, onSave }) {
4495
- const sharedDirectoryPicker = React10.useContext(WorkspaceDirectoryPickerContext);
4731
+ const sharedDirectoryPicker = React11.useContext(WorkspaceDirectoryPickerContext);
4496
4732
  const activeDirectoryPicker = directoryPicker ?? sharedDirectoryPicker;
4497
- const [open, setOpen] = React10.useState(false);
4498
- const [saving, setSaving] = React10.useState(false);
4499
- const [error, setError] = React10.useState(null);
4500
- const editButtonRef = React10.useRef(null);
4501
- const savingRef = React10.useRef(false);
4502
- const close = React10.useCallback(() => {
4733
+ const [open, setOpen] = React11.useState(false);
4734
+ const [saving, setSaving] = React11.useState(false);
4735
+ const [error, setError] = React11.useState(null);
4736
+ const editButtonRef = React11.useRef(null);
4737
+ const savingRef = React11.useRef(false);
4738
+ const close = React11.useCallback(() => {
4503
4739
  setOpen(false);
4504
4740
  setError(null);
4505
4741
  queueMicrotask(() => editButtonRef.current?.focus?.());
4506
4742
  }, []);
4507
- const pick = React10.useCallback(async (value) => {
4743
+ const pick = React11.useCallback(async (value) => {
4508
4744
  if (!value || savingRef.current || disabled) return;
4509
4745
  if (value === workspace) {
4510
4746
  close();
@@ -4541,7 +4777,7 @@ function WorkspaceEditor({ workspace, directoryPicker, disabled = false, onSave
4541
4777
  disabled: disabled || !activeDirectoryPicker
4542
4778
  }, "\u9009\u62E9\u76EE\u5F55")
4543
4779
  ),
4544
- workspace ? React10.createElement("code", {
4780
+ workspace ? React11.createElement("code", {
4545
4781
  className: "dim-workspacePath",
4546
4782
  title: workspace
4547
4783
  }, workspace) : h2("code", { className: "dim-workspacePath" }, "\u672A\u8BBE\u7F6E"),
@@ -4558,7 +4794,7 @@ function WorkspaceEditor({ workspace, directoryPicker, disabled = false, onSave
4558
4794
  }
4559
4795
 
4560
4796
  // plugin-src/client/context-enhancement.js
4561
- var React11 = __toESM(require("react"), 1);
4797
+ var React12 = __toESM(require("react"), 1);
4562
4798
  var import_react_dom3 = require("react-dom");
4563
4799
  var FIELD_LABELS = Object.freeze({
4564
4800
  channel: "\u6E20\u9053",
@@ -4803,7 +5039,7 @@ function ContextEnhancementScopeEditor({
4803
5039
  );
4804
5040
  }
4805
5041
  function ContextEnhancementDialog({ config, groupSupported, disabled, onSave, onClose, returnFocusRef, id: id6 }) {
4806
- const [draft, setDraft] = React11.useState(() => {
5042
+ const [draft, setDraft] = React12.useState(() => {
4807
5043
  const normalized = normalizeContextEnhancementConfig(config);
4808
5044
  return {
4809
5045
  ...normalized,
@@ -4812,23 +5048,23 @@ function ContextEnhancementDialog({ config, groupSupported, disabled, onSave, on
4812
5048
  } : {}
4813
5049
  };
4814
5050
  });
4815
- const [saving, setSaving] = React11.useState(false);
4816
- const [error, setError] = React11.useState(null);
4817
- const [activeScope, setActiveScope] = React11.useState("direct");
4818
- const savingRef = React11.useRef(false);
4819
- const dialogRef = React11.useRef(null);
4820
- const mountedRef = React11.useRef(true);
4821
- const groupTabRef = React11.useRef(null);
4822
- const directTabRef = React11.useRef(null);
4823
- const titleId = React11.useId();
4824
- const descriptionId = React11.useId();
4825
- const scopeIdPrefix = React11.useId();
5051
+ const [saving, setSaving] = React12.useState(false);
5052
+ const [error, setError] = React12.useState(null);
5053
+ const [activeScope, setActiveScope] = React12.useState("direct");
5054
+ const savingRef = React12.useRef(false);
5055
+ const dialogRef = React12.useRef(null);
5056
+ const mountedRef = React12.useRef(true);
5057
+ const groupTabRef = React12.useRef(null);
5058
+ const directTabRef = React12.useRef(null);
5059
+ const titleId = React12.useId();
5060
+ const descriptionId = React12.useId();
5061
+ const scopeIdPrefix = React12.useId();
4826
5062
  const groupGuidanceExample = localizeText(CONTEXT_GROUP_GUIDANCE_EXAMPLE);
4827
5063
  const directGuidanceExample = localizeText(CONTEXT_DIRECT_GUIDANCE_EXAMPLE);
4828
5064
  const busy = disabled || saving;
4829
5065
  const scopeKinds = ["direct", "group"];
4830
5066
  const tabRefs = { group: groupTabRef, direct: directTabRef };
4831
- React11.useEffect(() => {
5067
+ React12.useEffect(() => {
4832
5068
  mountedRef.current = true;
4833
5069
  dialogRef.current?.focus?.();
4834
5070
  const keepFocus = (event) => {
@@ -5019,17 +5255,17 @@ function ContextEnhancementDialog({ config, groupSupported, disabled, onSave, on
5019
5255
  return globalThis.document?.body ? (0, import_react_dom3.createPortal)(content, document.body) : content;
5020
5256
  }
5021
5257
  function ContextEnhancementEditor({ config, groupSupported = true, disabled = false, onSave }) {
5022
- const [open, setOpen] = React11.useState(false);
5023
- const entryRef = React11.useRef(null);
5024
- const dialogId = React11.useId();
5025
- const statusId = React11.useId();
5258
+ const [open, setOpen] = React12.useState(false);
5259
+ const entryRef = React12.useRef(null);
5260
+ const dialogId = React12.useId();
5261
+ const statusId = React12.useId();
5026
5262
  const saved = normalizeContextEnhancementConfig(config);
5027
5263
  const label = contextEnhancementLabel(groupSupported ? saved : {
5028
5264
  ...saved,
5029
5265
  group: { ...saved.group, enabled: false }
5030
5266
  });
5031
5267
  return h2(
5032
- React11.Fragment,
5268
+ React12.Fragment,
5033
5269
  null,
5034
5270
  h2(
5035
5271
  "button",
@@ -5063,10 +5299,10 @@ function ContextEnhancementEditor({ config, groupSupported = true, disabled = fa
5063
5299
  }
5064
5300
 
5065
5301
  // plugin-src/client/workspace-snapshot-fence.js
5066
- var React12 = __toESM(require("react"), 1);
5302
+ var React13 = __toESM(require("react"), 1);
5067
5303
  function useWorkspaceSnapshotFence() {
5068
- const state = React12.useRef({ version: 0, pendingMutations: 0 });
5069
- return React12.useMemo(() => Object.freeze({
5304
+ const state = React13.useRef({ version: 0, pendingMutations: 0 });
5305
+ return React13.useMemo(() => Object.freeze({
5070
5306
  beginStatus() {
5071
5307
  return state.current.pendingMutations === 0 ? state.current.version : null;
5072
5308
  },
@@ -5084,172 +5320,8 @@ function useWorkspaceSnapshotFence() {
5084
5320
  endMutation() {
5085
5321
  state.current.pendingMutations = Math.max(0, state.current.pendingMutations - 1);
5086
5322
  return state.current.pendingMutations === 0;
5087
- }
5088
- }), []);
5089
- }
5090
-
5091
- // plugin-src/client/channel-card-meta.js
5092
- var React13 = __toESM(require("react"), 1);
5093
- var BotSettingsContext = React13.createContext(Object.freeze({
5094
- openBotSettings() {
5095
- }
5096
- }));
5097
- function SettingsGlyph() {
5098
- return h2(
5099
- "svg",
5100
- {
5101
- viewBox: "0 0 24 24",
5102
- width: 16,
5103
- height: 16,
5104
- fill: "none",
5105
- stroke: "currentColor",
5106
- strokeWidth: 1.8,
5107
- strokeLinecap: "round",
5108
- strokeLinejoin: "round",
5109
- "aria-hidden": "true"
5110
- },
5111
- h2("circle", { cx: 12, cy: 12, r: 3 }),
5112
- h2("path", { d: "M19.4 15a1.7 1.7 0 0 0 .34 1.88l.06.06-2.83 2.83-.06-.06a1.7 1.7 0 0 0-1.88-.34 1.7 1.7 0 0 0-1.03 1.55V21h-4v-.08A1.7 1.7 0 0 0 8.97 19.4a1.7 1.7 0 0 0-1.88.34l-.06.06-2.83-2.83.06-.06A1.7 1.7 0 0 0 4.6 15a1.7 1.7 0 0 0-1.52-1.03H3v-4h.08A1.7 1.7 0 0 0 4.6 8.97a1.7 1.7 0 0 0-.34-1.88l-.06-.06L7.03 4.2l.06.06a1.7 1.7 0 0 0 1.88.34A1.7 1.7 0 0 0 10 3.08V3h4v.08a1.7 1.7 0 0 0 1.03 1.52 1.7 1.7 0 0 0 1.88-.34l.06-.06 2.83 2.83-.06.06a1.7 1.7 0 0 0-.34 1.88A1.7 1.7 0 0 0 20.92 10H21v4h-.08A1.7 1.7 0 0 0 19.4 15Z" })
5113
- );
5114
- }
5115
- function BotSettingsButton({
5116
- channel: channel6,
5117
- botId,
5118
- botName,
5119
- connected,
5120
- accessPolicy,
5121
- channelSettings
5122
- }) {
5123
- const { openBotSettings } = React13.useContext(BotSettingsContext);
5124
- const tooltipId = React13.useId();
5125
- return h2(
5126
- "span",
5127
- { className: "dim-botSettingsAction" },
5128
- h2("button", {
5129
- type: "button",
5130
- className: "dim-botSettingsButton",
5131
- "data-delivery-channel": channel6,
5132
- "aria-label": "\u66F4\u591A\u673A\u5668\u4EBA\u8BBE\u7F6E",
5133
- "aria-describedby": tooltipId,
5134
- onClick: () => openBotSettings?.({
5135
- ...channelSettings && typeof channelSettings === "object" ? channelSettings : {},
5136
- channel: channel6,
5137
- botId,
5138
- botName,
5139
- connected: Boolean(connected),
5140
- accessPolicy
5141
- })
5142
- }, h2(SettingsGlyph)),
5143
- h2("span", {
5144
- id: tooltipId,
5145
- className: "dim-botSettingsTooltip",
5146
- role: "tooltip"
5147
- }, "\u66F4\u591A\u673A\u5668\u4EBA\u8BBE\u7F6E")
5148
- );
5149
- }
5150
- function messageErrorTime(value) {
5151
- try {
5152
- return new Intl.DateTimeFormat(isEnglish() ? "en-US" : "zh-CN", {
5153
- year: "numeric",
5154
- month: "2-digit",
5155
- day: "2-digit",
5156
- hour: "2-digit",
5157
- minute: "2-digit"
5158
- }).format(new Date(value));
5159
- } catch {
5160
- return null;
5161
- }
5162
- }
5163
- function ChannelListHeading({ className = "", id: id6, title, connectionLabel }) {
5164
- const helpId = React13.useId();
5165
- return h2(
5166
- "div",
5167
- { className: `${className} dim-listHeading`.trim() },
5168
- h2(
5169
- "div",
5170
- { className: "dim-listTitle" },
5171
- h2("h3", id6 ? { id: id6 } : null, title),
5172
- h2(
5173
- "span",
5174
- { className: "dim-channelHelp" },
5175
- h2("button", {
5176
- type: "button",
5177
- className: "dim-channelHelpButton",
5178
- "aria-label": "\u67E5\u770B\u6D88\u606F\u901A\u9053\u8BF4\u660E",
5179
- "aria-describedby": helpId
5180
- }, h2("span", { "aria-hidden": "true" }, "?")),
5181
- h2(
5182
- "span",
5183
- {
5184
- id: helpId,
5185
- className: "dim-channelTooltip",
5186
- role: "tooltip"
5187
- },
5188
- h2("span", null, "\u6D88\u606F\u901A\u9053"),
5189
- h2("strong", null, connectionLabel)
5190
- )
5191
- )
5192
- )
5193
- );
5194
- }
5195
- function BotStatusMeta({
5196
- className = "",
5197
- dotClassName = "",
5198
- tone,
5199
- stateLabel: stateLabel2,
5200
- lastCheckedAt,
5201
- formatCheckedTime: formatCheckedTime2,
5202
- healthState
5203
- }) {
5204
- return h2(
5205
- "div",
5206
- { className: "dim-botHealthGroup" },
5207
- h2(
5208
- "div",
5209
- {
5210
- className: `${className} dim-botHealth`.trim(),
5211
- ...healthState ? { "data-health": healthState } : {}
5212
- },
5213
- h2("span", {
5214
- className: `${dotClassName} dim-healthDot`.trim(),
5215
- "data-tone": tone
5216
- }),
5217
- h2("span", null, stateLabel2)
5218
- ),
5219
- h2(
5220
- "div",
5221
- { className: "dim-lastChecked" },
5222
- h2("span", null, "\u6700\u8FD1\u68C0\u67E5"),
5223
- h2("span", null, formatCheckedTime2(lastCheckedAt))
5224
- )
5225
- );
5226
- }
5227
- function LastMessageErrorSummary({ className = "", error }) {
5228
- if (!error) return null;
5229
- const occurredAt = messageErrorTime(error.at);
5230
- return h2(
5231
- "div",
5232
- {
5233
- className: `${className} dim-cardSummary`.trim(),
5234
- role: "status"
5235
- },
5236
- h2("strong", null, "\u6700\u8FD1\u4E00\u6761\u6D88\u606F\u5904\u7406\u5931\u8D25"),
5237
- "\uFF1A",
5238
- h2("span", null, error.message),
5239
- error.details ? h2(ConnectionError, { error, showMessage: false }) : null,
5240
- "\uFF08",
5241
- h2("span", null, "\u9519\u8BEF\u7801"),
5242
- ` ${error.code} \xB7 `,
5243
- h2("span", null, "\u53C2\u8003\u53F7"),
5244
- ` ${error.referenceId}`,
5245
- occurredAt ? h2(
5246
- React13.Fragment,
5247
- null,
5248
- " \xB7 ",
5249
- h2("time", { dateTime: new Date(error.at).toISOString() }, occurredAt)
5250
- ) : null,
5251
- "\uFF09"
5252
- );
5323
+ }
5324
+ }), []);
5253
5325
  }
5254
5326
 
5255
5327
  // plugin-src/client/channels/dingtalk/styles.js
@@ -5686,6 +5758,13 @@ function AccountCard({
5686
5758
  h2(
5687
5759
  CollapsibleAccountSection,
5688
5760
  {
5761
+ settings: h2(BotSettingsButton, {
5762
+ channel: "dingtalk",
5763
+ botId: account.botId,
5764
+ botName: account.bot.name,
5765
+ connected: account.connected,
5766
+ accessPolicy: account.accessPolicy
5767
+ }),
5689
5768
  id: `ddt-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, "-")}`,
5690
5769
  header: h2(
5691
5770
  "div",
@@ -5721,13 +5800,7 @@ function AccountCard({
5721
5800
  lastCheckedAt: account.health.lastCheckedAt,
5722
5801
  formatCheckedTime: checkedTime
5723
5802
  }),
5724
- h2(BotSettingsButton, {
5725
- channel: "dingtalk",
5726
- botId: account.botId,
5727
- botName: account.bot.name,
5728
- connected: account.connected,
5729
- accessPolicy: account.accessPolicy
5730
- })
5803
+ h2(AccountSettingsToggle)
5731
5804
  )
5732
5805
  )
5733
5806
  },
@@ -6433,16 +6506,16 @@ var TOKEN_BOT_ENDPOINTS = Object.freeze({
6433
6506
  setAlias: "bot.alias.set",
6434
6507
  setThinkingTraces: "bot.thinking-traces.set"
6435
6508
  });
6436
- function createTokenChannelApi(channel6, connectionSummary, {
6509
+ function createTokenChannelApi(channel7, connectionSummary, {
6437
6510
  normalizeBotExtension = () => ({})
6438
6511
  } = {}) {
6439
- const unwrapRpcResult16 = (result) => {
6512
+ const unwrapRpcResult17 = (result) => {
6440
6513
  if (!isRecord2(result) || typeof result.ok !== "boolean") {
6441
- throw new Error(`${channel6} \u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94`);
6514
+ throw new Error(`${channel7} \u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94`);
6442
6515
  }
6443
6516
  if (!result.ok) {
6444
- const error = new Error(text2(result.error?.message, `${channel6} \u64CD\u4F5C\u5931\u8D25`));
6445
- error.code = text2(result.error?.code, `${channel6.toUpperCase()}_RPC_ERROR`, 80);
6517
+ const error = new Error(text2(result.error?.message, `${channel7} \u64CD\u4F5C\u5931\u8D25`));
6518
+ error.code = text2(result.error?.code, `${channel7.toUpperCase()}_RPC_ERROR`, 80);
6446
6519
  Object.assign(error, diagnosticFields(result.error));
6447
6520
  throw error;
6448
6521
  }
@@ -6466,30 +6539,30 @@ function createTokenChannelApi(channel6, connectionSummary, {
6466
6539
  ...Object.hasOwn(value, "accessPolicy") ? { accessPolicy: normalizeAccessPolicy(value.accessPolicy) } : {},
6467
6540
  bot: {
6468
6541
  ...normalizeBotAlias(value.bot),
6469
- name: text2(value.bot?.name, `${channel6}\u673A\u5668\u4EBA`, 100),
6542
+ name: text2(value.bot?.name, `${channel7}\u673A\u5668\u4EBA`, 100),
6470
6543
  username: text2(value.bot?.username, "", 100),
6471
6544
  idMasked: text2(value.bot?.idMasked, "\u673A\u5668\u4EBA\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58", 140)
6472
6545
  },
6473
6546
  health: {
6474
6547
  summary: text2(
6475
6548
  value.health?.summary,
6476
- connected ? `${channel6}${connectionSummary}\u8FD0\u884C\u6B63\u5E38` : `${channel6}\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA`
6549
+ connected ? `${channel7}${connectionSummary}\u8FD0\u884C\u6B63\u5E38` : `${channel7}\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA`
6477
6550
  ),
6478
6551
  lastCheckedAt: timestamp2(value.health?.lastCheckedAt)
6479
6552
  },
6480
6553
  lastMessageError: normalizeLastMessageError(value.lastMessageError),
6481
6554
  error: isRecord2(value.error) ? {
6482
6555
  ...diagnosticFields(value.error),
6483
- code: text2(value.error.code, `${channel6.toUpperCase()}_ACCOUNT_ERROR`, 80),
6484
- message: text2(value.error.message, `${channel6}\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA`)
6556
+ code: text2(value.error.code, `${channel7.toUpperCase()}_ACCOUNT_ERROR`, 80),
6557
+ message: text2(value.error.message, `${channel7}\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA`)
6485
6558
  } : null,
6486
6559
  ...isRecord2(extension) ? extension : {}
6487
6560
  };
6488
6561
  };
6489
- const normalizeSnapshot12 = (value) => {
6562
+ const normalizeSnapshot13 = (value) => {
6490
6563
  const source = isRecord2(value?.snapshot) ? value.snapshot : value;
6491
6564
  if (!isRecord2(source) || !Array.isArray(source.bots)) {
6492
- throw new Error(`${channel6} \u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u673A\u5668\u4EBA\u5217\u8868`);
6565
+ throw new Error(`${channel7} \u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u673A\u5668\u4EBA\u5217\u8868`);
6493
6566
  }
6494
6567
  const bots = source.bots.map(normalizeBot8).filter(Boolean);
6495
6568
  return {
@@ -6501,12 +6574,12 @@ function createTokenChannelApi(channel6, connectionSummary, {
6501
6574
  ...isRecord2(source.permissions) ? { permissions: source.permissions } : {}
6502
6575
  };
6503
6576
  };
6504
- const presentError16 = (error) => ({
6577
+ const presentError17 = (error) => ({
6505
6578
  ...diagnosticFields(error),
6506
- code: text2(error?.code, `${channel6.toUpperCase()}_ERROR`, 80),
6507
- message: text2(error?.message, `${channel6}\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`)
6579
+ code: text2(error?.code, `${channel7.toUpperCase()}_ERROR`, 80),
6580
+ message: text2(error?.message, `${channel7}\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`)
6508
6581
  });
6509
- return Object.freeze({ unwrapRpcResult: unwrapRpcResult16, normalizeSnapshot: normalizeSnapshot12, presentError: presentError16 });
6582
+ return Object.freeze({ unwrapRpcResult: unwrapRpcResult17, normalizeSnapshot: normalizeSnapshot13, presentError: presentError17 });
6510
6583
  }
6511
6584
 
6512
6585
  // plugin-src/client/channels/discord/api.js
@@ -6549,9 +6622,9 @@ function connectionTestNotice(value) {
6549
6622
  }
6550
6623
  function createTokenChannelSettings(definition) {
6551
6624
  const {
6552
- channel: channel6,
6625
+ channel: channel7,
6553
6626
  endpoints,
6554
- api: api6,
6627
+ api: api7,
6555
6628
  LogoGlyph,
6556
6629
  installStyles,
6557
6630
  pageClass,
@@ -6563,7 +6636,7 @@ function createTokenChannelSettings(definition) {
6563
6636
  platformLabel,
6564
6637
  CredentialPanel = null,
6565
6638
  credentialPayload = ({ secret }) => ({ token: secret }),
6566
- credentialAriaLabel = `\u4F7F\u7528 Bot Token \u63A5\u5165 ${channel6} \u673A\u5668\u4EBA`,
6639
+ credentialAriaLabel = `\u4F7F\u7528 Bot Token \u63A5\u5165 ${channel7} \u673A\u5668\u4EBA`,
6567
6640
  credentialOpenLabel = "\u624B\u52A8\u63A5\u5165",
6568
6641
  credentialCloseLabel = "\u6536\u8D77\u51ED\u636E",
6569
6642
  credentialNoun = "Bot Token",
@@ -6586,6 +6659,13 @@ function createTokenChannelSettings(definition) {
6586
6659
  h2(
6587
6660
  CollapsibleAccountSection,
6588
6661
  {
6662
+ settings: h2(BotSettingsButton, {
6663
+ channel: channel7.toLowerCase(),
6664
+ botId: account.botId,
6665
+ botName: account.bot.name,
6666
+ connected: account.connected,
6667
+ accessPolicy: account.accessPolicy
6668
+ }),
6589
6669
  id: `tok-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, "-")}`,
6590
6670
  header: h2(
6591
6671
  "div",
@@ -6625,13 +6705,7 @@ function createTokenChannelSettings(definition) {
6625
6705
  lastCheckedAt: account.health.lastCheckedAt,
6626
6706
  formatCheckedTime: checkedTime2
6627
6707
  }),
6628
- h2(BotSettingsButton, {
6629
- channel: channel6.toLowerCase(),
6630
- botId: account.botId,
6631
- botName: account.bot.name,
6632
- connected: account.connected,
6633
- accessPolicy: account.accessPolicy
6634
- })
6708
+ h2(AccountSettingsToggle)
6635
6709
  )
6636
6710
  )
6637
6711
  },
@@ -6748,11 +6822,11 @@ function createTokenChannelSettings(definition) {
6748
6822
  };
6749
6823
  }, []);
6750
6824
  const invoke = React15.useCallback(async (endpoint, payload = {}, signal) => {
6751
- if (typeof rpcCall !== "function") throw new TypeError(`${channel6} \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5`);
6825
+ if (typeof rpcCall !== "function") throw new TypeError(`${channel7} \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5`);
6752
6826
  const operation = !["connection.status", "provision.poll", "provision.begin", "provision.cancel"].includes(endpoint);
6753
6827
  if (operation && mounted.current) setOperationError(null);
6754
6828
  try {
6755
- const value = api6.unwrapRpcResult(await rpcCall(endpoint, payload, signal));
6829
+ const value = api7.unwrapRpcResult(await rpcCall(endpoint, payload, signal));
6756
6830
  if (operation && mounted.current) setOperationError(value?.testMessage?.error ?? value?.warnings?.[0] ?? null);
6757
6831
  return value;
6758
6832
  } catch (error) {
@@ -6765,7 +6839,7 @@ function createTokenChannelSettings(definition) {
6765
6839
  if (workspaceVersion === null) return;
6766
6840
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
6767
6841
  try {
6768
- const snapshot = api6.normalizeSnapshot(await invoke(endpoints.status, {}, signal));
6842
+ const snapshot = api7.normalizeSnapshot(await invoke(endpoints.status, {}, signal));
6769
6843
  if (!mounted.current || signal?.aborted || !workspaceFence.canCommitStatus(workspaceVersion)) return;
6770
6844
  setModel({
6771
6845
  phase: "ready",
@@ -6781,7 +6855,7 @@ function createTokenChannelSettings(definition) {
6781
6855
  setModel((current) => ({
6782
6856
  ...current,
6783
6857
  phase: silent ? current.phase : "error",
6784
- error: api6.presentError(error)
6858
+ error: api7.presentError(error)
6785
6859
  }));
6786
6860
  }
6787
6861
  }
@@ -6808,7 +6882,7 @@ function createTokenChannelSettings(definition) {
6808
6882
  setBusy(true);
6809
6883
  setCredentialError(null);
6810
6884
  try {
6811
- const snapshot = api6.normalizeSnapshot(await invoke(
6885
+ const snapshot = api7.normalizeSnapshot(await invoke(
6812
6886
  endpoints.bindCredentials,
6813
6887
  credentialPayload(values)
6814
6888
  ));
@@ -6826,7 +6900,7 @@ function createTokenChannelSettings(definition) {
6826
6900
  }
6827
6901
  setCredentialOpen(false);
6828
6902
  } catch (error) {
6829
- if (mounted.current) setCredentialError(api6.presentError(error));
6903
+ if (mounted.current) setCredentialError(api7.presentError(error));
6830
6904
  } finally {
6831
6905
  const shouldRefresh = workspaceFence.endMutation();
6832
6906
  if (shouldRefresh && mounted.current) void loadStatus({ silent: true });
@@ -6838,7 +6912,7 @@ function createTokenChannelSettings(definition) {
6838
6912
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
6839
6913
  try {
6840
6914
  const value = await invoke(endpoint, payload);
6841
- const snapshot = api6.normalizeSnapshot(value);
6915
+ const snapshot = api7.normalizeSnapshot(value);
6842
6916
  if (mounted.current && workspaceFence.canCommitMutation(snapshotVersion)) {
6843
6917
  setModel({
6844
6918
  phase: "ready",
@@ -6878,7 +6952,7 @@ function createTokenChannelSettings(definition) {
6878
6952
  { className: "dim-listSection" },
6879
6953
  h2(ChannelListHeading, {
6880
6954
  className: "ddt-listHeading",
6881
- title: `\u5DF2\u63A5\u5165\u7684 ${channel6} \u673A\u5668\u4EBA`,
6955
+ title: `\u5DF2\u63A5\u5165\u7684 ${channel7} \u673A\u5668\u4EBA`,
6882
6956
  connectionLabel
6883
6957
  }),
6884
6958
  h2("ul", { className: "ddt-list dim-botList" }, model.bots.map((account) => h2("li", { key: account.botId }, h2(AccountCard6, {
@@ -6949,7 +7023,7 @@ function createTokenChannelSettings(definition) {
6949
7023
  "section",
6950
7024
  {
6951
7025
  className: `ddt-page ${pageClass} dim-channelPage`,
6952
- "aria-label": `${channel6} \u8BBE\u7F6E`
7026
+ "aria-label": `${channel7} \u8BBE\u7F6E`
6953
7027
  },
6954
7028
  operationError ? h2(ConnectionError, { error: operationError }) : null,
6955
7029
  h2(
@@ -6983,13 +7057,13 @@ function createTokenChannelSettings(definition) {
6983
7057
  model.phase === "loading" ? h2("div", {
6984
7058
  className: "ddt-card ddt-loading dim-surfaceCard dim-loadingView",
6985
7059
  "aria-busy": "true"
6986
- }, h2("div", { className: "ddt-spinner dim-spinner" }), `\u6B63\u5728\u8BFB\u53D6 ${channel6} \u673A\u5668\u4EBA\u72B6\u6001\u2026`) : model.phase === "error" ? h2(
7060
+ }, h2("div", { className: "ddt-spinner dim-spinner" }), `\u6B63\u5728\u8BFB\u53D6 ${channel7} \u673A\u5668\u4EBA\u72B6\u6001\u2026`) : model.phase === "error" ? h2(
6987
7061
  "div",
6988
7062
  { className: "ddt-card dim-surfaceCard" },
6989
7063
  h2(
6990
7064
  "div",
6991
7065
  { className: "ddt-inlineError dim-inlineError" },
6992
- h2("h3", null, `\u65E0\u6CD5\u8BFB\u53D6 ${channel6} \u673A\u5668\u4EBA\u72B6\u6001`),
7066
+ h2("h3", null, `\u65E0\u6CD5\u8BFB\u53D6 ${channel7} \u673A\u5668\u4EBA\u72B6\u6001`),
6993
7067
  h2(ConnectionError, { error: model.error }),
6994
7068
  h2(Button3, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
6995
7069
  )
@@ -6997,7 +7071,7 @@ function createTokenChannelSettings(definition) {
6997
7071
  React15.Fragment,
6998
7072
  null,
6999
7073
  credentialOpen ? CredentialPanel ? h2(CredentialPanel, {
7000
- channel: channel6,
7074
+ channel: channel7,
7001
7075
  permissions: model.permissions,
7002
7076
  busy,
7003
7077
  error: credentialError,
@@ -7012,7 +7086,7 @@ function createTokenChannelSettings(definition) {
7012
7086
  endpoints,
7013
7087
  onAuthorized: bindCredentials
7014
7088
  }) : h2(CredentialBindingPanel, {
7015
- channel: channel6,
7089
+ channel: channel7,
7016
7090
  secretLabel: "Bot Token",
7017
7091
  secretPlaceholder: tokenPlaceholder,
7018
7092
  busy,
@@ -7036,7 +7110,7 @@ function createTokenChannelSettings(definition) {
7036
7110
  "div",
7037
7111
  { className: "ddt-stateLabel dim-stateLabel" },
7038
7112
  h2("span", { className: "ddt-dot dim-stateDot" }),
7039
- h2("span", null, `\u5C1A\u672A\u63A5\u5165 ${channel6} \u673A\u5668\u4EBA`)
7113
+ h2("span", null, `\u5C1A\u672A\u63A5\u5165 ${channel7} \u673A\u5668\u4EBA`)
7040
7114
  ),
7041
7115
  h2("h3", null, emptyTitle),
7042
7116
  h2("p", null, emptyDescription),
@@ -7999,6 +8073,18 @@ function BotCard({
7999
8073
  h2(
8000
8074
  CollapsibleAccountSection,
8001
8075
  {
8076
+ settings: h2(BotSettingsButton, {
8077
+ channel: "feishu",
8078
+ botId: connection.botId,
8079
+ botName: bot.name,
8080
+ connected,
8081
+ accessPolicy: connection.accessPolicy,
8082
+ channelSettings: {
8083
+ groupResponseMode: connection.groupResponseMode,
8084
+ groupTopicReply: connection.groupTopicReply,
8085
+ groupMessagePermissionGranted: connection.groupMessagePermissionGranted
8086
+ }
8087
+ }),
8002
8088
  id: `bxf-settings-${connection.botId.replace(/[^a-zA-Z0-9_-]/g, "-")}`,
8003
8089
  header: h2(
8004
8090
  "div",
@@ -8039,18 +8125,7 @@ function BotCard({
8039
8125
  formatCheckedTime,
8040
8126
  healthState: stateForDisplay
8041
8127
  }),
8042
- h2(BotSettingsButton, {
8043
- channel: "feishu",
8044
- botId: connection.botId,
8045
- botName: bot.name,
8046
- connected,
8047
- accessPolicy: connection.accessPolicy,
8048
- channelSettings: {
8049
- groupResponseMode: connection.groupResponseMode,
8050
- groupTopicReply: connection.groupTopicReply,
8051
- groupMessagePermissionGranted: connection.groupMessagePermissionGranted
8052
- }
8053
- })
8128
+ h2(AccountSettingsToggle)
8054
8129
  )
8055
8130
  )
8056
8131
  },
@@ -9935,6 +10010,13 @@ function AccountCard2({
9935
10010
  h2(
9936
10011
  CollapsibleAccountSection,
9937
10012
  {
10013
+ settings: h2(BotSettingsButton, {
10014
+ channel: "qq",
10015
+ botId: account.botId,
10016
+ botName: account.bot.name,
10017
+ connected: account.connected,
10018
+ accessPolicy: account.accessPolicy
10019
+ }),
9938
10020
  id: `qq-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, "-")}`,
9939
10021
  header: h2(
9940
10022
  "div",
@@ -9970,13 +10052,7 @@ function AccountCard2({
9970
10052
  lastCheckedAt: account.health.lastCheckedAt,
9971
10053
  formatCheckedTime: checkedTime3
9972
10054
  }),
9973
- h2(BotSettingsButton, {
9974
- channel: "qq",
9975
- botId: account.botId,
9976
- botName: account.bot.name,
9977
- connected: account.connected,
9978
- accessPolicy: account.accessPolicy
9979
- })
10055
+ h2(AccountSettingsToggle)
9980
10056
  )
9981
10057
  )
9982
10058
  },
@@ -11440,6 +11516,13 @@ function AccountCard3({
11440
11516
  h2(
11441
11517
  CollapsibleAccountSection,
11442
11518
  {
11519
+ settings: h2(BotSettingsButton, {
11520
+ channel: "wecom",
11521
+ botId: account.botId,
11522
+ botName: account.bot.name,
11523
+ connected: account.connected,
11524
+ accessPolicy: account.accessPolicy
11525
+ }),
11443
11526
  id: `wec-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, "-")}`,
11444
11527
  header: h2(
11445
11528
  "div",
@@ -11475,13 +11558,7 @@ function AccountCard3({
11475
11558
  lastCheckedAt: account.health.lastCheckedAt,
11476
11559
  formatCheckedTime: checkedTime4
11477
11560
  }),
11478
- h2(BotSettingsButton, {
11479
- channel: "wecom",
11480
- botId: account.botId,
11481
- botName: account.bot.name,
11482
- connected: account.connected,
11483
- accessPolicy: account.accessPolicy
11484
- })
11561
+ h2(AccountSettingsToggle)
11485
11562
  )
11486
11563
  )
11487
11564
  },
@@ -12368,6 +12445,13 @@ function AccountCard4({
12368
12445
  h2(
12369
12446
  CollapsibleAccountSection,
12370
12447
  {
12448
+ settings: h2(BotSettingsButton, {
12449
+ channel: "wecomApp",
12450
+ botId: account.botId,
12451
+ botName: account.bot.name,
12452
+ connected: account.connected,
12453
+ accessPolicy: account.accessPolicy
12454
+ }),
12371
12455
  id: elementId,
12372
12456
  header: h2(
12373
12457
  "div",
@@ -12402,13 +12486,7 @@ function AccountCard4({
12402
12486
  lastCheckedAt: account.health.lastCheckedAt,
12403
12487
  formatCheckedTime: checkedTime5
12404
12488
  }),
12405
- h2(BotSettingsButton, {
12406
- channel: "wecomApp",
12407
- botId: account.botId,
12408
- botName: account.bot.name,
12409
- connected: account.connected,
12410
- accessPolicy: account.accessPolicy
12411
- })
12489
+ h2(AccountSettingsToggle)
12412
12490
  )
12413
12491
  )
12414
12492
  },
@@ -13219,6 +13297,13 @@ function AccountCard5({
13219
13297
  h2(
13220
13298
  CollapsibleAccountSection,
13221
13299
  {
13300
+ settings: h2(BotSettingsButton, {
13301
+ channel: "weixin",
13302
+ botId: account.botId,
13303
+ botName: account.bot.name,
13304
+ connected: account.connected,
13305
+ accessPolicy: account.accessPolicy
13306
+ }),
13222
13307
  id: `dxw-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, "-")}`,
13223
13308
  header: h2(
13224
13309
  "div",
@@ -13249,13 +13334,7 @@ function AccountCard5({
13249
13334
  lastCheckedAt: account.health.lastCheckedAt,
13250
13335
  formatCheckedTime: checkedTime6
13251
13336
  }),
13252
- h2(BotSettingsButton, {
13253
- channel: "weixin",
13254
- botId: account.botId,
13255
- botName: account.bot.name,
13256
- connected: account.connected,
13257
- accessPolicy: account.accessPolicy
13258
- })
13337
+ h2(AccountSettingsToggle)
13259
13338
  )
13260
13339
  )
13261
13340
  },
@@ -14353,6 +14432,13 @@ function WhatsappAccountCard({
14353
14432
  h2(
14354
14433
  CollapsibleAccountSection,
14355
14434
  {
14435
+ settings: h2(BotSettingsButton, {
14436
+ channel: "whatsapp",
14437
+ botId: account.botId,
14438
+ botName: account.bot.name,
14439
+ connected: account.connected,
14440
+ accessPolicy: account.accessPolicy
14441
+ }),
14356
14442
  id: `wsp-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, "-")}`,
14357
14443
  header: h2(
14358
14444
  "div",
@@ -14391,13 +14477,7 @@ function WhatsappAccountCard({
14391
14477
  lastCheckedAt: account.health.lastCheckedAt,
14392
14478
  formatCheckedTime: checkedTime7
14393
14479
  }),
14394
- h2(BotSettingsButton, {
14395
- channel: "whatsapp",
14396
- botId: account.botId,
14397
- botName: account.bot.name,
14398
- connected: account.connected,
14399
- accessPolicy: account.accessPolicy
14400
- })
14480
+ h2(AccountSettingsToggle)
14401
14481
  )
14402
14482
  )
14403
14483
  },
@@ -15718,6 +15798,217 @@ function useEmailChannelEnabled(rpcCall) {
15718
15798
  return enabled === true;
15719
15799
  }
15720
15800
 
15801
+ // plugin-src/client/channels/matrix/api.js
15802
+ var MATRIX_RPC_CHANNEL = "/matrix";
15803
+ var MATRIX_ENDPOINTS = TOKEN_BOT_ENDPOINTS;
15804
+ var api6 = createTokenChannelApi("Matrix", " CS API \u957F\u8F6E\u8BE2");
15805
+ var unwrapRpcResult13 = api6.unwrapRpcResult;
15806
+ var normalizeSnapshot12 = api6.normalizeSnapshot;
15807
+ var presentError13 = api6.presentError;
15808
+
15809
+ // plugin-src/client/channels/matrix/index.js
15810
+ var React27 = __toESM(require("react"), 1);
15811
+
15812
+ // plugin-src/client/channels/matrix/styles.js
15813
+ var MATRIX_STYLE_ID = "xmanrui-dsh-im-matrix-settings";
15814
+ var CSS14 = String.raw`
15815
+ .dmt-page { --ddt-accent: #1a8f6f; --ddt-accent-deep: #12654f; --ddt-accent-wash: #eef8f4; }
15816
+ .dmt-avatar { background: linear-gradient(145deg, #fff, #f6faf8); border: 1px solid #e2eae7; }
15817
+ .dmt-avatar svg { display: block; }
15818
+ .dim-logoMatrix { color: white; background: #0dbd8b; }
15819
+ .dim-logoMatrix svg { width: 22px; height: 22px; }
15820
+ .dmt-setup { display: grid; gap: 18px; }
15821
+ .dmt-guide { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: start; gap: 18px; padding: 16px; border: 1px solid color-mix(in srgb, #1a8f6f 18%, var(--dsw-alias-border-l2, #e5e6eb)); border-radius: 11px; background: color-mix(in srgb, #1a8f6f 4%, var(--dsw-alias-bg-layer-1, #fff)); }
15822
+ .dmt-guideCopy { min-width: 0; }
15823
+ .dmt-guideCopy strong { display: block; margin-bottom: 5px; color: var(--dsw-alias-label-primary, #1f2329); font-size: 13px; }
15824
+ .dmt-guideCopy p { margin: 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: 1.6; }
15825
+ .dmt-guideActions { display: flex; align-items: center; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }
15826
+ .dmt-guideActions .ddt-button { white-space: nowrap; }
15827
+ .dmt-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
15828
+ .dmt-fields .dmt-fieldWide { grid-column: 1 / -1; }
15829
+ .dmt-tokenHint { grid-column: 1 / -1; margin: -4px 0 0; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 11px; line-height: 1.55; }
15830
+ @container (max-width: 680px) {
15831
+ .dmt-guide { grid-template-columns: minmax(0, 1fr); }
15832
+ .dmt-guideActions { justify-content: flex-start; }
15833
+ .dmt-fields { grid-template-columns: minmax(0, 1fr); }
15834
+ }
15835
+ `;
15836
+ function installMatrixStyles() {
15837
+ if (typeof document === "undefined") return () => {
15838
+ };
15839
+ const existing = document.querySelector(`style[data-plugin-css="${MATRIX_STYLE_ID}"]`);
15840
+ if (existing) return () => {
15841
+ };
15842
+ const style = document.createElement("style");
15843
+ style.dataset.plugin = "@xmanrui/dsh-im";
15844
+ style.dataset.pluginCss = MATRIX_STYLE_ID;
15845
+ style.textContent = CSS14;
15846
+ document.head.appendChild(style);
15847
+ return () => style.remove();
15848
+ }
15849
+
15850
+ // plugin-src/client/channels/matrix/index.js
15851
+ var MATRIX_USER_ID_PATTERN = /^@[^:@\s]+:[^:@\s]+(?::\d{1,5})?$/u;
15852
+ function validHomeserver(value) {
15853
+ if (!value || value.length > 2048) return false;
15854
+ try {
15855
+ const url = new URL(value);
15856
+ return (url.protocol === "https:" || url.protocol === "http:") && !url.username && !url.password && !url.hash;
15857
+ } catch {
15858
+ return false;
15859
+ }
15860
+ }
15861
+ function MatrixCredentialPanel({ busy, error, onSubmit, onCancel }) {
15862
+ const [homeserver, setHomeserver] = React27.useState("");
15863
+ const [accessToken, setAccessToken] = React27.useState("");
15864
+ const [userId, setUserId] = React27.useState("");
15865
+ const [password, setPassword] = React27.useState("");
15866
+ const headingId = React27.useId();
15867
+ const normalizedHomeserver = homeserver.trim();
15868
+ const normalizedUserId = userId.trim();
15869
+ const tokenMode = Boolean(accessToken.trim());
15870
+ const loginMode = Boolean(normalizedUserId) && Boolean(password);
15871
+ const canSubmit = validHomeserver(normalizedHomeserver) && (tokenMode ? !normalizedUserId && !password && accessToken.trim().length >= 8 : !accessToken.trim() && MATRIX_USER_ID_PATTERN.test(normalizedUserId) && password.length >= 1);
15872
+ const submit = (event) => {
15873
+ event.preventDefault();
15874
+ if (!canSubmit || busy) return;
15875
+ void onSubmit?.(tokenMode ? { homeserver: normalizedHomeserver, accessToken: accessToken.trim() } : {
15876
+ homeserver: normalizedHomeserver,
15877
+ userId: normalizedUserId,
15878
+ password
15879
+ });
15880
+ };
15881
+ return h2(
15882
+ "section",
15883
+ {
15884
+ className: "ddt-card dim-surfaceCard dim-credentialPanel dmt-setup",
15885
+ "aria-labelledby": headingId
15886
+ },
15887
+ h2("h3", { id: headingId, className: "dim-credentialTitle" }, "\u63A5\u5165 Matrix \u673A\u5668\u4EBA"),
15888
+ h2(
15889
+ "div",
15890
+ { className: "dmt-guide" },
15891
+ h2(
15892
+ "div",
15893
+ { className: "dmt-guideCopy" },
15894
+ h2("strong", null, "\u8FDE\u63A5\u4F60\u7684 Matrix homeserver"),
15895
+ h2("p", null, "\u586B\u5199 homeserver \u5730\u5740\uFF0C\u5E76\u63D0\u4F9B\u8BBF\u95EE\u4EE4\u724C\uFF0C\u6216\u8005\u7528\u6237 ID \u4E0E\u5BC6\u7801\u7684\u7EC4\u5408\u3002\u673A\u5668\u4EBA\u53EA\u8BBF\u95EE\u8BE5 homeserver\uFF0C\u4E0D\u8FDE\u63A5\u7B2C\u4E09\u65B9\u670D\u52A1\u5668\u3002")
15896
+ )
15897
+ ),
15898
+ h2(
15899
+ "form",
15900
+ { className: "dim-credentialForm dim-credentialFormSingle", onSubmit: submit },
15901
+ h2(
15902
+ "div",
15903
+ { className: "dmt-fields" },
15904
+ h2(
15905
+ "label",
15906
+ { className: "dim-credentialField dmt-fieldWide" },
15907
+ h2("span", null, "Homeserver \u5730\u5740"),
15908
+ h2("input", {
15909
+ type: "url",
15910
+ value: homeserver,
15911
+ onChange: (event) => setHomeserver(event.target.value),
15912
+ placeholder: "https://matrix.example.org",
15913
+ maxLength: 2048,
15914
+ autoCapitalize: "none",
15915
+ autoCorrect: "off",
15916
+ spellCheck: false,
15917
+ disabled: busy,
15918
+ required: true
15919
+ })
15920
+ ),
15921
+ h2(
15922
+ "label",
15923
+ { className: "dim-credentialField dmt-fieldWide" },
15924
+ h2("span", null, "\u8BBF\u95EE\u4EE4\u724C\uFF08\u4E0E\u7528\u6237 ID\u3001\u5BC6\u7801\u4E8C\u9009\u4E00\uFF09"),
15925
+ h2("input", {
15926
+ type: "password",
15927
+ value: accessToken,
15928
+ onChange: (event) => setAccessToken(event.target.value),
15929
+ placeholder: "syt_\u2026",
15930
+ maxLength: 4096,
15931
+ autoCapitalize: "none",
15932
+ autoCorrect: "off",
15933
+ spellCheck: false,
15934
+ autoComplete: "new-password",
15935
+ disabled: busy
15936
+ })
15937
+ ),
15938
+ h2(
15939
+ "label",
15940
+ { className: "dim-credentialField" },
15941
+ h2("span", null, "\u7528\u6237 ID\uFF08\u53EF\u9009\uFF09"),
15942
+ h2("input", {
15943
+ type: "text",
15944
+ value: userId,
15945
+ onChange: (event) => setUserId(event.target.value),
15946
+ placeholder: "@bot:example.org",
15947
+ maxLength: 512,
15948
+ autoCapitalize: "none",
15949
+ autoCorrect: "off",
15950
+ spellCheck: false,
15951
+ disabled: busy
15952
+ })
15953
+ ),
15954
+ h2(
15955
+ "label",
15956
+ { className: "dim-credentialField" },
15957
+ h2("span", null, "\u5BC6\u7801\uFF08\u53EF\u9009\uFF09"),
15958
+ h2("input", {
15959
+ type: "password",
15960
+ value: password,
15961
+ onChange: (event) => setPassword(event.target.value),
15962
+ maxLength: 1024,
15963
+ autoComplete: "new-password",
15964
+ disabled: busy
15965
+ })
15966
+ ),
15967
+ h2("p", { className: "dmt-tokenHint" }, "\u8BBF\u95EE\u4EE4\u724C\u6765\u81EA Element \u8BBE\u7F6E \u2192 \u5E2E\u52A9 \u2192 \u7F16\u8F91\u8BBE\u7F6E\uFF0C\u6216 homeserver \u7684\u767B\u5F55\u63A5\u53E3\uFF1B\u7528\u6237 ID \u4E0E\u5BC6\u7801\u65B9\u5F0F\u4F1A\u4E3A\u672C\u5B89\u88C5\u6D3E\u751F\u7A33\u5B9A\u8BBE\u5907\u4F1A\u8BDD\u3002")
15968
+ ),
15969
+ error ? h2("p", { className: "dim-credentialError", role: "alert" }, error.message ?? String(error)) : null,
15970
+ h2(
15971
+ "div",
15972
+ { className: "ddt-actions dim-viewActions dim-credentialActions" },
15973
+ h2("button", {
15974
+ type: "submit",
15975
+ className: "ddt-button",
15976
+ "data-kind": "primary",
15977
+ disabled: busy || !canSubmit
15978
+ }, busy ? "\u6B63\u5728\u9A8C\u8BC1\u5E76\u8FDE\u63A5\u2026" : "\u9A8C\u8BC1\u5E76\u8FDE\u63A5"),
15979
+ h2("button", {
15980
+ type: "button",
15981
+ className: "ddt-button",
15982
+ onClick: onCancel,
15983
+ disabled: busy
15984
+ }, "\u53D6\u6D88")
15985
+ )
15986
+ )
15987
+ );
15988
+ }
15989
+ var channel6 = createTokenChannelSettings({
15990
+ channel: "Matrix",
15991
+ endpoints: MATRIX_ENDPOINTS,
15992
+ api: api6,
15993
+ LogoGlyph: MatrixLogoGlyph,
15994
+ installStyles: installMatrixStyles,
15995
+ pageClass: "dmt-page",
15996
+ avatarClass: "dmt-avatar",
15997
+ connectionLabel: "CS API \u957F\u8F6E\u8BE2",
15998
+ emptyTitle: "\u63A5\u5165 Matrix \u673A\u5668\u4EBA",
15999
+ emptyDescription: "\u586B\u5199 homeserver \u5730\u5740\u4E0E\u8BBF\u95EE\u4EE4\u724C\uFF0C\u6216\u8005\u7528\u6237 ID \u4E0E\u5BC6\u7801\uFF0C\u5373\u53EF\u8BA9\u673A\u5668\u4EBA\u4EE5 CS API \u957F\u8F6E\u8BE2\u63A5\u6536\u6D88\u606F\u5E76\u4EE5\u5BCC\u6587\u672C\u56DE\u590D\u3002",
16000
+ platformLabel: "Matrix homeserver",
16001
+ CredentialPanel: MatrixCredentialPanel,
16002
+ credentialPayload: ({ homeserver, accessToken, userId, password }) => ({ homeserver, accessToken, userId, password }),
16003
+ credentialAriaLabel: "\u4F7F\u7528 homeserver \u4E0E\u51ED\u636E\u63A5\u5165 Matrix \u673A\u5668\u4EBA",
16004
+ credentialOpenLabel: "\u63A5\u5165\u673A\u5668\u4EBA",
16005
+ credentialCloseLabel: "\u6536\u8D77\u63A5\u5165",
16006
+ credentialNoun: "\u8BBF\u95EE\u4EE4\u724C\u6216\u7528\u6237 ID \u4E0E\u5BC6\u7801",
16007
+ emptyActionLabel: "\u5F00\u59CB\u63A5\u5165"
16008
+ });
16009
+ var MatrixSettingsTab = channel6.SettingsTab;
16010
+ var MatrixAccountCard = channel6.AccountCard;
16011
+
15721
16012
  // src/channels/shared/interface-language.mjs
15722
16013
  var LANGUAGE_TAG = /^[A-Za-z]{2,8}(?:-[A-Za-z0-9]{1,8})*$/u;
15723
16014
  var HOST_LANGUAGE_SOURCES = Object.freeze(["config", "settings", "mirror"]);
@@ -15781,10 +16072,10 @@ function installInterfaceLanguageMirror(ctx, {
15781
16072
  }
15782
16073
 
15783
16074
  // plugin-src/client/delivery-settings.js
15784
- var React29 = __toESM(require("react"), 1);
16075
+ var React30 = __toESM(require("react"), 1);
15785
16076
 
15786
16077
  // plugin-src/client/access-policy-settings.js
15787
- var React27 = __toESM(require("react"), 1);
16078
+ var React28 = __toESM(require("react"), 1);
15788
16079
  var ACCESS_POLICY_ENDPOINT = "bot.access-policy.set";
15789
16080
  var ACCESS_CHANNEL_DEFINITIONS = Object.freeze({
15790
16081
  weixin: Object.freeze({
@@ -15870,7 +16161,7 @@ function clonePolicy(policy) {
15870
16161
  group: cloneScope(policy.group)
15871
16162
  };
15872
16163
  }
15873
- function unwrapRpcResult13(result) {
16164
+ function unwrapRpcResult14(result) {
15874
16165
  if (result?.ok === true) return result.value;
15875
16166
  if (result?.ok === false) {
15876
16167
  const error = new Error(result.error?.message || "\u8BBF\u95EE\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
@@ -15897,8 +16188,8 @@ function ScenePolicyEditor({
15897
16188
  unsupported = false,
15898
16189
  onChange
15899
16190
  }) {
15900
- const ownerHelpId = React27.useId();
15901
- const emptyAllowlistHelpId = React27.useId();
16191
+ const ownerHelpId = React28.useId();
16192
+ const emptyAllowlistHelpId = React28.useId();
15902
16193
  const allowlist = policy.mode === "allowlist";
15903
16194
  const collectionKey = allowlist ? "users" : "commandPermissionOverrides";
15904
16195
  const branchKey = allowlist ? "allowlist" : "open";
@@ -15950,7 +16241,7 @@ function ScenePolicyEditor({
15950
16241
  h2("strong", null, "\u5F53\u524D\u6E20\u9053\u4E0D\u652F\u6301\u7FA4\u804A"),
15951
16242
  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")
15952
16243
  ) : h2(
15953
- React27.Fragment,
16244
+ React28.Fragment,
15954
16245
  null,
15955
16246
  h2(
15956
16247
  "div",
@@ -16087,20 +16378,20 @@ function ScenePolicyEditor({
16087
16378
  )
16088
16379
  );
16089
16380
  }
16090
- function AccessPolicySettingsPage({ channel: channel6, account, rpcCall, onSaved }) {
16091
- const definition = ACCESS_CHANNEL_DEFINITIONS[channel6];
16381
+ function AccessPolicySettingsPage({ channel: channel7, account, rpcCall, onSaved }) {
16382
+ const definition = ACCESS_CHANNEL_DEFINITIONS[channel7];
16092
16383
  const initialPolicy = normalizeAccessPolicy(account?.accessPolicy);
16093
16384
  const initialKey = JSON.stringify(initialPolicy);
16094
- const [draft, setDraft] = React27.useState(() => clonePolicy(
16385
+ const [draft, setDraft] = React28.useState(() => clonePolicy(
16095
16386
  initialPolicy ?? DEFAULT_ACCESS_POLICY
16096
16387
  ));
16097
- const [saving, setSaving] = React27.useState(false);
16098
- const [feedback, setFeedback] = React27.useState(null);
16099
- React27.useEffect(() => {
16388
+ const [saving, setSaving] = React28.useState(false);
16389
+ const [feedback, setFeedback] = React28.useState(null);
16390
+ React28.useEffect(() => {
16100
16391
  const next = normalizeAccessPolicy(account?.accessPolicy);
16101
16392
  setDraft(clonePolicy(next ?? DEFAULT_ACCESS_POLICY));
16102
16393
  }, [account?.botId, initialKey]);
16103
- React27.useEffect(() => {
16394
+ React28.useEffect(() => {
16104
16395
  setFeedback(null);
16105
16396
  }, [account?.botId]);
16106
16397
  if (!definition) {
@@ -16117,7 +16408,7 @@ function AccessPolicySettingsPage({ channel: channel6, account, rpcCall, onSaved
16117
16408
  try {
16118
16409
  const policy = validateAccessPolicy(draft);
16119
16410
  if (typeof rpcCall !== "function") throw new Error("\u8BBF\u95EE\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
16120
- const value = unwrapRpcResult13(await rpcCall(ACCESS_POLICY_ENDPOINT, {
16411
+ const value = unwrapRpcResult14(await rpcCall(ACCESS_POLICY_ENDPOINT, {
16121
16412
  botId: account.botId,
16122
16413
  policy
16123
16414
  }));
@@ -16191,7 +16482,7 @@ function AccessPolicySettingsPage({ channel: channel6, account, rpcCall, onSaved
16191
16482
  }
16192
16483
 
16193
16484
  // plugin-src/client/channels/feishu/group-settings.js
16194
- var React28 = __toESM(require("react"), 1);
16485
+ var React29 = __toESM(require("react"), 1);
16195
16486
  var GROUP_MESSAGE_PERMISSION_OPERATION2 = FEISHU_REGISTRATION_OPERATIONS.GROUP_MESSAGE_PERMISSION;
16196
16487
  function SettingsButton({ children, kind = "secondary", className = "", ...props }) {
16197
16488
  return h2("button", {
@@ -16252,9 +16543,9 @@ function GroupResponseModeEditor({
16252
16543
  onAuthorize
16253
16544
  }) {
16254
16545
  const current = normalizeGroupResponseMode(value);
16255
- const [saving, setSaving] = React28.useState(false);
16256
- const [authorizing, setAuthorizing] = React28.useState(false);
16257
- const [error, setError] = React28.useState(null);
16546
+ const [saving, setSaving] = React29.useState(false);
16547
+ const [authorizing, setAuthorizing] = React29.useState(false);
16548
+ const [error, setError] = React29.useState(null);
16258
16549
  const change = async (event) => {
16259
16550
  const next = normalizeGroupResponseMode(event.target.value);
16260
16551
  if (next === current || saving || disabled) return;
@@ -16335,8 +16626,8 @@ function GroupResponseModeEditor({
16335
16626
  }
16336
16627
  function GroupTopicReplyEditor({ value = false, disabled = false, onSave }) {
16337
16628
  const current = value === true ? "on" : "off";
16338
- const [saving, setSaving] = React28.useState(false);
16339
- const [error, setError] = React28.useState(null);
16629
+ const [saving, setSaving] = React29.useState(false);
16630
+ const [error, setError] = React29.useState(null);
16340
16631
  const change = async (event) => {
16341
16632
  const next = event.target.value === "on";
16342
16633
  if ((next ? "on" : "off") === current || saving || disabled) return;
@@ -16523,14 +16814,14 @@ function PermissionFlow({ provision, now, busy, botName, onRetry, onCancel, onCl
16523
16814
  );
16524
16815
  }
16525
16816
  function FeishuGroupSettingsPage({ account, rpcCall }) {
16526
- const [settings, setSettings] = React28.useState(() => groupSettingsFrom(account));
16527
- const [refreshing, setRefreshing] = React28.useState(false);
16528
- const [refreshError, setRefreshError] = React28.useState(null);
16529
- const [provision, setProvision] = React28.useState(null);
16530
- const [provisionBusy, setProvisionBusy] = React28.useState(false);
16531
- const [now, setNow] = React28.useState(() => Date.now());
16532
- const mounted = React28.useRef(true);
16533
- React28.useEffect(() => {
16817
+ const [settings, setSettings] = React29.useState(() => groupSettingsFrom(account));
16818
+ const [refreshing, setRefreshing] = React29.useState(false);
16819
+ const [refreshError, setRefreshError] = React29.useState(null);
16820
+ const [provision, setProvision] = React29.useState(null);
16821
+ const [provisionBusy, setProvisionBusy] = React29.useState(false);
16822
+ const [now, setNow] = React29.useState(() => Date.now());
16823
+ const mounted = React29.useRef(true);
16824
+ React29.useEffect(() => {
16534
16825
  setSettings(groupSettingsFrom(account));
16535
16826
  }, [
16536
16827
  account.botId,
@@ -16538,22 +16829,22 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
16538
16829
  account.groupTopicReply,
16539
16830
  account.groupMessagePermissionGranted
16540
16831
  ]);
16541
- React28.useEffect(() => {
16832
+ React29.useEffect(() => {
16542
16833
  mounted.current = true;
16543
16834
  return () => {
16544
16835
  mounted.current = false;
16545
16836
  };
16546
16837
  }, []);
16547
- const invoke = React28.useCallback(async (endpoint, payload = {}, signal) => {
16838
+ const invoke = React29.useCallback(async (endpoint, payload = {}, signal) => {
16548
16839
  if (typeof rpcCall !== "function") throw new Error("\u98DE\u4E66\u7FA4\u804A\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
16549
16840
  return unwrapRpcResult3(await rpcCall(endpoint, payload, signal));
16550
16841
  }, [rpcCall]);
16551
- const applySnapshot = React28.useCallback((value) => {
16842
+ const applySnapshot = React29.useCallback((value) => {
16552
16843
  const result = targetBotFromSnapshot(value, account.botId);
16553
16844
  if (mounted.current) setSettings(groupSettingsFrom(result.bot));
16554
16845
  return result;
16555
16846
  }, [account.botId]);
16556
- const loadSettings = React28.useCallback(async ({ signal, restoreProvisioning = false } = {}) => {
16847
+ const loadSettings = React29.useCallback(async ({ signal, restoreProvisioning = false } = {}) => {
16557
16848
  setRefreshing(true);
16558
16849
  setRefreshError(null);
16559
16850
  try {
@@ -16582,16 +16873,16 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
16582
16873
  if (!signal?.aborted && mounted.current) setRefreshing(false);
16583
16874
  }
16584
16875
  }, [account.botId, applySnapshot, invoke]);
16585
- React28.useEffect(() => {
16876
+ React29.useEffect(() => {
16586
16877
  const controller = new AbortController();
16587
16878
  void loadSettings({ signal: controller.signal, restoreProvisioning: true });
16588
16879
  return () => controller.abort();
16589
16880
  }, [loadSettings]);
16590
- const saveSetting = React28.useCallback(async (endpoint, payload) => {
16881
+ const saveSetting = React29.useCallback(async (endpoint, payload) => {
16591
16882
  const value = await invoke(endpoint, { botId: account.botId, ...payload });
16592
16883
  applySnapshot(value);
16593
16884
  }, [account.botId, applySnapshot, invoke]);
16594
- const startAuthorization = React28.useCallback(async ({ replace = false } = {}) => {
16885
+ const startAuthorization = React29.useCallback(async ({ replace = false } = {}) => {
16595
16886
  if (provisionBusy) return;
16596
16887
  const previousAttemptId = provision?.attemptId;
16597
16888
  setProvisionBusy(true);
@@ -16632,13 +16923,13 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
16632
16923
  if (mounted.current) setProvisionBusy(false);
16633
16924
  }
16634
16925
  }, [account.botId, invoke, provision?.attemptId, provisionBusy]);
16635
- const finishAuthorization = React28.useCallback(async (signal) => {
16926
+ const finishAuthorization = React29.useCallback(async (signal) => {
16636
16927
  const bot = await loadSettings({ signal, restoreProvisioning: false });
16637
16928
  if (signal?.aborted || !mounted.current) return;
16638
16929
  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");
16639
16930
  setProvision(null);
16640
16931
  }, [loadSettings]);
16641
- React28.useEffect(() => {
16932
+ React29.useEffect(() => {
16642
16933
  if (!provision?.attemptId || !["qr", "connecting"].includes(provision.phase) || provision.expired) return void 0;
16643
16934
  const timerHost = globalThis.window ?? globalThis;
16644
16935
  const controller = new AbortController();
@@ -16682,7 +16973,7 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
16682
16973
  timerHost.clearTimeout(timer);
16683
16974
  };
16684
16975
  }, [account.botId, finishAuthorization, invoke, provision]);
16685
- React28.useEffect(() => {
16976
+ React29.useEffect(() => {
16686
16977
  if (!provision?.attemptId || provision.phase !== "qr" || provision.expired) return void 0;
16687
16978
  const timerHost = globalThis.window ?? globalThis;
16688
16979
  const tick = () => {
@@ -16696,7 +16987,7 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
16696
16987
  const timer = timerHost.setInterval(tick, 1e3);
16697
16988
  return () => timerHost.clearInterval(timer);
16698
16989
  }, [provision?.attemptId, provision?.expired, provision?.expiresAt, provision?.phase]);
16699
- const cancelAuthorization = React28.useCallback(async () => {
16990
+ const cancelAuthorization = React29.useCallback(async () => {
16700
16991
  if (!provision?.attemptId || provisionBusy) {
16701
16992
  setProvision(null);
16702
16993
  return;
@@ -16807,8 +17098,8 @@ var FEISHU_BOT_SETTINGS_TABS = Object.freeze([
16807
17098
  ...BOT_SETTINGS_TABS,
16808
17099
  Object.freeze({ id: "group", label: "\u7FA4\u804A" })
16809
17100
  ]);
16810
- function botSettingsTabsForChannel(channel6) {
16811
- return channel6 === "feishu" ? FEISHU_BOT_SETTINGS_TABS : BOT_SETTINGS_TABS;
17101
+ function botSettingsTabsForChannel(channel7) {
17102
+ return channel7 === "feishu" ? FEISHU_BOT_SETTINGS_TABS : BOT_SETTINGS_TABS;
16812
17103
  }
16813
17104
  var CHANNEL_DEFINITIONS = Object.freeze({
16814
17105
  weixin: {
@@ -16896,10 +17187,10 @@ var CHANNEL_DEFINITIONS = Object.freeze({
16896
17187
  fields: { user: [{ key: "chatGuid", label: "Chat GUID", placeholder: "iMessage;+;chat123" }] }
16897
17188
  }
16898
17189
  });
16899
- function presentError13(error, fallback) {
17190
+ function presentError14(error, fallback) {
16900
17191
  return error?.message || fallback;
16901
17192
  }
16902
- function unwrapRpcResult14(result) {
17193
+ function unwrapRpcResult15(result) {
16903
17194
  if (result?.ok === true) return result.value;
16904
17195
  if (result?.ok === false) {
16905
17196
  const error = new Error(result.error?.message || "\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
@@ -17017,13 +17308,13 @@ function TargetForm({
17017
17308
  }) {
17018
17309
  const editing = mode === "edit";
17019
17310
  const initialKind = initialValue?.kind && definition.fields[initialValue.kind] ? initialValue.kind : definition.kinds[0].value;
17020
- const [targetId, setTargetId] = React29.useState(initialValue?.targetId ?? "");
17021
- const [name2, setName] = React29.useState(initialValue?.name ?? "");
17022
- const [kind, setKind] = React29.useState(initialKind);
17023
- const [route, setRoute] = React29.useState(initialValue?.route ?? {});
17024
- const [error, setError] = React29.useState(null);
17025
- const [testing, setTesting] = React29.useState(false);
17026
- const [testState, setTestState] = React29.useState(null);
17311
+ const [targetId, setTargetId] = React30.useState(initialValue?.targetId ?? "");
17312
+ const [name2, setName] = React30.useState(initialValue?.name ?? "");
17313
+ const [kind, setKind] = React30.useState(initialKind);
17314
+ const [route, setRoute] = React30.useState(initialValue?.route ?? {});
17315
+ const [error, setError] = React30.useState(null);
17316
+ const [testing, setTesting] = React30.useState(false);
17317
+ const [testState, setTestState] = React30.useState(null);
17027
17318
  const currentTarget = () => {
17028
17319
  const normalizedRoute = Object.fromEntries(fieldsFor(definition, kind).map((field2) => {
17029
17320
  const raw = String(route[field2.key] ?? "").trim();
@@ -17044,7 +17335,7 @@ function TargetForm({
17044
17335
  ...currentTarget()
17045
17336
  });
17046
17337
  } catch (caught) {
17047
- setError(presentError13(caught, "\u76EE\u6807\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5\u3002"));
17338
+ setError(presentError14(caught, "\u76EE\u6807\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5\u3002"));
17048
17339
  }
17049
17340
  };
17050
17341
  const testTarget = async () => {
@@ -17056,7 +17347,7 @@ function TargetForm({
17056
17347
  await onTest({ kind: target.kind, route: target.route });
17057
17348
  setTestState({ tone: "success", message: "\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\uFF0C\u8BF7\u5230\u76EE\u6807\u4F1A\u8BDD\u786E\u8BA4\u3002" });
17058
17349
  } catch (caught) {
17059
- setTestState({ tone: "error", message: presentError13(caught, "\u6D4B\u8BD5\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
17350
+ setTestState({ tone: "error", message: presentError14(caught, "\u6D4B\u8BD5\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
17060
17351
  } finally {
17061
17352
  setTesting(false);
17062
17353
  }
@@ -17240,7 +17531,7 @@ function TargetSuggestionPicker({
17240
17531
  suggestions.map((suggestion, index) => {
17241
17532
  const identity = routeIdentity(definition, suggestion);
17242
17533
  const added = configured.has(identity);
17243
- return React29.createElement("option", {
17534
+ return React30.createElement("option", {
17244
17535
  key: suggestion.id ?? suggestion.suggestionId ?? `${identity}:${index}`,
17245
17536
  value: String(index),
17246
17537
  disabled: added
@@ -17257,11 +17548,11 @@ function TargetSuggestionPicker({
17257
17548
  );
17258
17549
  }
17259
17550
  function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, onEdit }) {
17260
- const [action, setAction] = React29.useState(null);
17261
- const [testState, setTestState] = React29.useState(null);
17262
- const [syncFeedback, setSyncFeedback] = React29.useState(null);
17263
- const [copyState, setCopyState] = React29.useState(null);
17264
- const [confirmDelete, setConfirmDelete] = React29.useState(false);
17551
+ const [action, setAction] = React30.useState(null);
17552
+ const [testState, setTestState] = React30.useState(null);
17553
+ const [syncFeedback, setSyncFeedback] = React30.useState(null);
17554
+ const [copyState, setCopyState] = React30.useState(null);
17555
+ const [confirmDelete, setConfirmDelete] = React30.useState(false);
17265
17556
  const sessionSync = target.sessionSync ?? { enabled: false, state: "unavailable" };
17266
17557
  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";
17267
17558
  const testTarget = async () => {
@@ -17271,7 +17562,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
17271
17562
  await rpcCall(DELIVERY_ENDPOINTS.test, { botId, targetId: target.targetId });
17272
17563
  setTestState({ tone: "success", message: "\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\uFF0C\u8BF7\u5230\u76EE\u6807\u4F1A\u8BDD\u786E\u8BA4\u3002" });
17273
17564
  } catch (error) {
17274
- setTestState({ tone: "error", message: presentError13(error, "\u6D4B\u8BD5\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
17565
+ setTestState({ tone: "error", message: presentError14(error, "\u6D4B\u8BD5\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
17275
17566
  } finally {
17276
17567
  setAction(null);
17277
17568
  }
@@ -17282,7 +17573,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
17282
17573
  await copyText(JSON.stringify({ botId, targetId: target.targetId }));
17283
17574
  setCopyState("\u5DF2\u590D\u5236\u8C03\u7528\u53C2\u6570");
17284
17575
  } catch (error) {
17285
- setCopyState(presentError13(error, "\u590D\u5236\u5931\u8D25\u3002"));
17576
+ setCopyState(presentError14(error, "\u590D\u5236\u5931\u8D25\u3002"));
17286
17577
  }
17287
17578
  };
17288
17579
  const deleteTarget = async () => {
@@ -17291,7 +17582,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
17291
17582
  await rpcCall(DELIVERY_ENDPOINTS.delete, { botId, targetId: target.targetId });
17292
17583
  await onChanged();
17293
17584
  } catch (error) {
17294
- setTestState({ tone: "error", message: presentError13(error, "\u5220\u9664\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
17585
+ setTestState({ tone: "error", message: presentError14(error, "\u5220\u9664\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
17295
17586
  setAction(null);
17296
17587
  setConfirmDelete(false);
17297
17588
  }
@@ -17309,7 +17600,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
17309
17600
  } catch (error) {
17310
17601
  setSyncFeedback({
17311
17602
  tone: "error",
17312
- 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" : presentError13(error, "\u4F1A\u8BDD\u540C\u6B65\u8BBE\u7F6E\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002")
17603
+ 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" : presentError14(error, "\u4F1A\u8BDD\u540C\u6B65\u8BBE\u7F6E\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002")
17313
17604
  });
17314
17605
  } finally {
17315
17606
  setAction(null);
@@ -17324,7 +17615,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
17324
17615
  h2(
17325
17616
  "div",
17326
17617
  { className: "dim-targetTitle" },
17327
- React29.createElement("strong", null, target.name || target.targetId),
17618
+ React30.createElement("strong", null, target.name || target.targetId),
17328
17619
  h2("span", null, kindLabel(definition, target.kind))
17329
17620
  ),
17330
17621
  h2("code", null, `targetId: ${target.targetId}`)
@@ -17403,33 +17694,33 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
17403
17694
  );
17404
17695
  }
17405
17696
  function DeliveryTargetSettingsPage({
17406
- channel: channel6,
17697
+ channel: channel7,
17407
17698
  account,
17408
17699
  rpcCall,
17409
17700
  accessRpcCall,
17410
17701
  onBack
17411
17702
  }) {
17412
- const definition = CHANNEL_DEFINITIONS[channel6];
17413
- const [activeTabId, setActiveTabId] = React29.useState(BOT_SETTINGS_TABS[0].id);
17414
- const [phase, setPhase] = React29.useState("loading");
17415
- const [targets, setTargets] = React29.useState([]);
17416
- const [suggestionPhase, setSuggestionPhase] = React29.useState("idle");
17417
- const [suggestions, setSuggestions] = React29.useState([]);
17418
- const [suggestionError, setSuggestionError] = React29.useState(null);
17419
- const [error, setError] = React29.useState(null);
17420
- const [editor, setEditor] = React29.useState(null);
17421
- const [saving, setSaving] = React29.useState(false);
17422
- const [botCopyState, setBotCopyState] = React29.useState(null);
17423
- const [accessPolicy, setAccessPolicy] = React29.useState(account.accessPolicy);
17424
- const mounted = React29.useRef(true);
17425
- React29.useEffect(() => {
17703
+ const definition = CHANNEL_DEFINITIONS[channel7];
17704
+ const [activeTabId, setActiveTabId] = React30.useState(BOT_SETTINGS_TABS[0].id);
17705
+ const [phase, setPhase] = React30.useState("loading");
17706
+ const [targets, setTargets] = React30.useState([]);
17707
+ const [suggestionPhase, setSuggestionPhase] = React30.useState("idle");
17708
+ const [suggestions, setSuggestions] = React30.useState([]);
17709
+ const [suggestionError, setSuggestionError] = React30.useState(null);
17710
+ const [error, setError] = React30.useState(null);
17711
+ const [editor, setEditor] = React30.useState(null);
17712
+ const [saving, setSaving] = React30.useState(false);
17713
+ const [botCopyState, setBotCopyState] = React30.useState(null);
17714
+ const [accessPolicy, setAccessPolicy] = React30.useState(account.accessPolicy);
17715
+ const mounted = React30.useRef(true);
17716
+ React30.useEffect(() => {
17426
17717
  setAccessPolicy(account.accessPolicy);
17427
17718
  }, [account.botId, account.accessPolicy]);
17428
- const invoke = React29.useCallback(async (endpoint, payload = {}, signal) => {
17719
+ const invoke = React30.useCallback(async (endpoint, payload = {}, signal) => {
17429
17720
  if (typeof rpcCall !== "function") throw new Error("\u6295\u9012\u76EE\u6807\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
17430
- return unwrapRpcResult14(await rpcCall(endpoint, payload, signal));
17721
+ return unwrapRpcResult15(await rpcCall(endpoint, payload, signal));
17431
17722
  }, [rpcCall]);
17432
- const loadTargets = React29.useCallback(async ({ signal, silent = false } = {}) => {
17723
+ const loadTargets = React30.useCallback(async ({ signal, silent = false } = {}) => {
17433
17724
  if (!silent) setPhase("loading");
17434
17725
  setError(null);
17435
17726
  try {
@@ -17439,11 +17730,11 @@ function DeliveryTargetSettingsPage({
17439
17730
  setPhase("ready");
17440
17731
  } catch (caught) {
17441
17732
  if (signal?.aborted || caught?.name === "AbortError" || !mounted.current) return;
17442
- setError(presentError13(caught, "\u65E0\u6CD5\u8BFB\u53D6\u6295\u9012\u76EE\u6807\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
17733
+ setError(presentError14(caught, "\u65E0\u6CD5\u8BFB\u53D6\u6295\u9012\u76EE\u6807\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
17443
17734
  setPhase("error");
17444
17735
  }
17445
17736
  }, [account.botId, invoke]);
17446
- const loadSuggestions = React29.useCallback(async () => {
17737
+ const loadSuggestions = React30.useCallback(async () => {
17447
17738
  setSuggestionPhase("loading");
17448
17739
  setSuggestionError(null);
17449
17740
  try {
@@ -17453,11 +17744,11 @@ function DeliveryTargetSettingsPage({
17453
17744
  setSuggestionPhase("ready");
17454
17745
  } catch (caught) {
17455
17746
  if (caught?.name === "AbortError" || !mounted.current) return;
17456
- setSuggestionError(presentError13(caught, "\u65E0\u6CD5\u8BFB\u53D6\u5DF2\u804A\u4F1A\u8BDD\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
17747
+ setSuggestionError(presentError14(caught, "\u65E0\u6CD5\u8BFB\u53D6\u5DF2\u804A\u4F1A\u8BDD\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
17457
17748
  setSuggestionPhase("error");
17458
17749
  }
17459
17750
  }, [account.botId, definition, invoke]);
17460
- React29.useEffect(() => {
17751
+ React30.useEffect(() => {
17461
17752
  mounted.current = true;
17462
17753
  const controller = new AbortController();
17463
17754
  void loadTargets({ signal: controller.signal });
@@ -17525,10 +17816,10 @@ function DeliveryTargetSettingsPage({
17525
17816
  await copyText(account.botId);
17526
17817
  setBotCopyState("\u5DF2\u590D\u5236 Bot ID");
17527
17818
  } catch (caught) {
17528
- setBotCopyState(presentError13(caught, "\u590D\u5236\u5931\u8D25\u3002"));
17819
+ setBotCopyState(presentError14(caught, "\u590D\u5236\u5931\u8D25\u3002"));
17529
17820
  }
17530
17821
  };
17531
- const settingsTabs = botSettingsTabsForChannel(channel6);
17822
+ const settingsTabs = botSettingsTabsForChannel(channel7);
17532
17823
  const activeTab = settingsTabs.find((tab) => tab.id === activeTabId) ?? settingsTabs[0];
17533
17824
  const activeTabDomId = `dim-bot-settings-${activeTab.id}-tab`;
17534
17825
  const activePanelId = `dim-bot-settings-${activeTab.id}-panel`;
@@ -17571,15 +17862,15 @@ function DeliveryTargetSettingsPage({
17571
17862
  "aria-labelledby": activeTabDomId
17572
17863
  },
17573
17864
  activeTab.id === "access" ? h2(AccessPolicySettingsPage, {
17574
- channel: channel6,
17865
+ channel: channel7,
17575
17866
  account: { ...account, accessPolicy },
17576
17867
  rpcCall: accessRpcCall,
17577
17868
  onSaved: setAccessPolicy
17578
- }) : activeTab.id === "group" && channel6 === "feishu" ? h2(FeishuGroupSettingsPage, {
17869
+ }) : activeTab.id === "group" && channel7 === "feishu" ? h2(FeishuGroupSettingsPage, {
17579
17870
  account,
17580
17871
  rpcCall: accessRpcCall
17581
17872
  }) : h2(
17582
- React29.Fragment,
17873
+ React30.Fragment,
17583
17874
  null,
17584
17875
  h2(
17585
17876
  "section",
@@ -17690,7 +17981,7 @@ function DeliveryTargetSettingsPage({
17690
17981
  }
17691
17982
 
17692
17983
  // plugin-src/client/global-settings.js
17693
- var React30 = __toESM(require("react"), 1);
17984
+ var React31 = __toESM(require("react"), 1);
17694
17985
 
17695
17986
  // src/channels/shared/inbound-ttl.mjs
17696
17987
  var DEFAULT_INBOUND_TTL_HOURS = 168;
@@ -17742,10 +18033,10 @@ var GLOBAL_SETTINGS_ENDPOINTS = Object.freeze({
17742
18033
  getImages: "settings.image-input.get",
17743
18034
  setImages: "settings.image-input.set"
17744
18035
  });
17745
- function presentError14(error, fallback) {
18036
+ function presentError15(error, fallback) {
17746
18037
  return error?.message || fallback;
17747
18038
  }
17748
- function unwrapRpcResult15(result) {
18039
+ function unwrapRpcResult16(result) {
17749
18040
  if (result?.ok === true) return result.value;
17750
18041
  if (result?.ok === false) {
17751
18042
  const error = new Error(result.error?.message || "\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
@@ -17775,18 +18066,18 @@ function GlobalButton({ children, kind = "secondary", className = "", ...props }
17775
18066
  }, children);
17776
18067
  }
17777
18068
  function ImageInputSettings({ rpcCall }) {
17778
- const [values, setValues] = React30.useState(DEFAULT_IMAGE_INPUT_SETTINGS);
17779
- const [phase, setPhase] = React30.useState("loading");
17780
- const [error, setError] = React30.useState(null);
17781
- const [saved, setSaved] = React30.useState(false);
17782
- const mounted = React30.useRef(false);
17783
- const saving = React30.useRef(false);
17784
- const id6 = React30.useId();
17785
- const load = React30.useCallback(async (signal) => {
18069
+ const [values, setValues] = React31.useState(DEFAULT_IMAGE_INPUT_SETTINGS);
18070
+ const [phase, setPhase] = React31.useState("loading");
18071
+ const [error, setError] = React31.useState(null);
18072
+ const [saved, setSaved] = React31.useState(false);
18073
+ const mounted = React31.useRef(false);
18074
+ const saving = React31.useRef(false);
18075
+ const id6 = React31.useId();
18076
+ const load = React31.useCallback(async (signal) => {
17786
18077
  setPhase("loading");
17787
18078
  setError(null);
17788
18079
  try {
17789
- const result = unwrapRpcResult15(await rpcCall(GLOBAL_SETTINGS_ENDPOINTS.getImages, {}, signal));
18080
+ const result = unwrapRpcResult16(await rpcCall(GLOBAL_SETTINGS_ENDPOINTS.getImages, {}, signal));
17790
18081
  if (signal?.aborted || !mounted.current) return;
17791
18082
  const settings = normalizeImageInputSettings(result);
17792
18083
  if (!settings) throw new Error("\u901A\u7528\u8BBE\u7F6E\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94\u3002");
@@ -17794,11 +18085,11 @@ function ImageInputSettings({ rpcCall }) {
17794
18085
  setPhase("ready");
17795
18086
  } catch (caught) {
17796
18087
  if (signal?.aborted || !mounted.current) return;
17797
- setError(presentError14(caught, "\u65E0\u6CD5\u8BFB\u53D6\u6216\u4FDD\u5B58\u56FE\u7247\u8BBE\u7F6E\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
18088
+ setError(presentError15(caught, "\u65E0\u6CD5\u8BFB\u53D6\u6216\u4FDD\u5B58\u56FE\u7247\u8BBE\u7F6E\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
17798
18089
  setPhase("error");
17799
18090
  }
17800
18091
  }, [rpcCall]);
17801
- React30.useEffect(() => {
18092
+ React31.useEffect(() => {
17802
18093
  mounted.current = true;
17803
18094
  const controller = new AbortController();
17804
18095
  void load(controller.signal);
@@ -17820,14 +18111,14 @@ function ImageInputSettings({ rpcCall }) {
17820
18111
  setPhase("saving");
17821
18112
  setError(null);
17822
18113
  try {
17823
- const result = unwrapRpcResult15(await rpcCall(GLOBAL_SETTINGS_ENDPOINTS.setImages, settings));
18114
+ const result = unwrapRpcResult16(await rpcCall(GLOBAL_SETTINGS_ENDPOINTS.setImages, settings));
17824
18115
  if (!normalizeImageInputSettings(result)) throw new Error("\u901A\u7528\u8BBE\u7F6E\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94\u3002");
17825
18116
  if (mounted.current) {
17826
18117
  setValues(result);
17827
18118
  setSaved(true);
17828
18119
  }
17829
18120
  } catch (caught) {
17830
- if (mounted.current) setError(presentError14(caught, "\u65E0\u6CD5\u8BFB\u53D6\u6216\u4FDD\u5B58\u56FE\u7247\u8BBE\u7F6E\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
18121
+ if (mounted.current) setError(presentError15(caught, "\u65E0\u6CD5\u8BFB\u53D6\u6216\u4FDD\u5B58\u56FE\u7247\u8BBE\u7F6E\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
17831
18122
  } finally {
17832
18123
  saving.current = false;
17833
18124
  if (mounted.current) setPhase("ready");
@@ -17875,29 +18166,29 @@ function ImageInputSettings({ rpcCall }) {
17875
18166
  );
17876
18167
  }
17877
18168
  function GlobalSettingsPanel({ rpcCall }) {
17878
- const [phase, setPhase] = React30.useState("loading");
17879
- const [loadError, setLoadError] = React30.useState(null);
17880
- const [ttlInput, setTtlInput] = React30.useState("");
17881
- const [savedTtl, setSavedTtl] = React30.useState(null);
17882
- const [ttlError, setTtlError] = React30.useState(false);
17883
- const [saveError, setSaveError] = React30.useState(null);
17884
- const [saveSucceeded, setSaveSucceeded] = React30.useState(false);
17885
- const [isSaving, setIsSaving] = React30.useState(false);
17886
- const [sweepConfirming, setSweepConfirming] = React30.useState(false);
17887
- const [sweeping, setSweeping] = React30.useState(false);
17888
- const ttlErrorId = React30.useId();
17889
- const ttlHintsId = React30.useId();
17890
- const sweepTriggerId = React30.useId();
17891
- const sweepConfirmId = React30.useId();
17892
- const sweepConfirmTextId = React30.useId();
17893
- const sweepConfirmButtonId = React30.useId();
17894
- const mounted = React30.useRef(true);
17895
- const saving = React30.useRef(false);
17896
- const invoke = React30.useCallback(async (endpoint, payload = {}, signal) => {
18169
+ const [phase, setPhase] = React31.useState("loading");
18170
+ const [loadError, setLoadError] = React31.useState(null);
18171
+ const [ttlInput, setTtlInput] = React31.useState("");
18172
+ const [savedTtl, setSavedTtl] = React31.useState(null);
18173
+ const [ttlError, setTtlError] = React31.useState(false);
18174
+ const [saveError, setSaveError] = React31.useState(null);
18175
+ const [saveSucceeded, setSaveSucceeded] = React31.useState(false);
18176
+ const [isSaving, setIsSaving] = React31.useState(false);
18177
+ const [sweepConfirming, setSweepConfirming] = React31.useState(false);
18178
+ const [sweeping, setSweeping] = React31.useState(false);
18179
+ const ttlErrorId = React31.useId();
18180
+ const ttlHintsId = React31.useId();
18181
+ const sweepTriggerId = React31.useId();
18182
+ const sweepConfirmId = React31.useId();
18183
+ const sweepConfirmTextId = React31.useId();
18184
+ const sweepConfirmButtonId = React31.useId();
18185
+ const mounted = React31.useRef(true);
18186
+ const saving = React31.useRef(false);
18187
+ const invoke = React31.useCallback(async (endpoint, payload = {}, signal) => {
17897
18188
  if (typeof rpcCall !== "function") throw new Error("\u901A\u7528\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
17898
- return unwrapRpcResult15(await rpcCall(endpoint, payload, signal));
18189
+ return unwrapRpcResult16(await rpcCall(endpoint, payload, signal));
17899
18190
  }, [rpcCall]);
17900
- const loadSettings = React30.useCallback(async ({ signal } = {}) => {
18191
+ const loadSettings = React31.useCallback(async ({ signal } = {}) => {
17901
18192
  setPhase("loading");
17902
18193
  setLoadError(null);
17903
18194
  try {
@@ -17917,11 +18208,11 @@ function GlobalSettingsPanel({ rpcCall }) {
17917
18208
  setPhase("ready");
17918
18209
  } catch (caught) {
17919
18210
  if (signal?.aborted || caught?.name === "AbortError" || !mounted.current) return;
17920
- setLoadError(presentError14(caught, "\u65E0\u6CD5\u8BFB\u53D6\u901A\u7528\u8BBE\u7F6E\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
18211
+ setLoadError(presentError15(caught, "\u65E0\u6CD5\u8BFB\u53D6\u901A\u7528\u8BBE\u7F6E\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
17921
18212
  setPhase("error");
17922
18213
  }
17923
18214
  }, [invoke]);
17924
- React30.useEffect(() => {
18215
+ React31.useEffect(() => {
17925
18216
  mounted.current = true;
17926
18217
  const controller = new AbortController();
17927
18218
  void loadSettings({ signal: controller.signal });
@@ -17930,7 +18221,7 @@ function GlobalSettingsPanel({ rpcCall }) {
17930
18221
  controller.abort();
17931
18222
  };
17932
18223
  }, [loadSettings]);
17933
- React30.useEffect(() => {
18224
+ React31.useEffect(() => {
17934
18225
  if (!sweepConfirming) return;
17935
18226
  globalThis.document?.getElementById(sweepConfirmButtonId)?.focus();
17936
18227
  }, [sweepConfirmButtonId, sweepConfirming]);
@@ -17961,7 +18252,7 @@ function GlobalSettingsPanel({ rpcCall }) {
17961
18252
  setPhase("ready");
17962
18253
  } catch (caught) {
17963
18254
  if (mounted.current) {
17964
- setSaveError(presentError14(caught, "\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
18255
+ setSaveError(presentError15(caught, "\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
17965
18256
  }
17966
18257
  } finally {
17967
18258
  saving.current = false;
@@ -18238,7 +18529,7 @@ function replacePageLocation(url, location = globalThis.location) {
18238
18529
 
18239
18530
  // plugin-src/client/styles.js
18240
18531
  var IM_STYLE_ID = "xmanrui-dsh-im-settings";
18241
- var CSS14 = String.raw`
18532
+ var CSS15 = String.raw`
18242
18533
  .dim-connectionDiagnostic { min-width: 0; width: 100%; color: var(--dsw-alias-label-secondary, #646a73); overflow-wrap: anywhere; font-size: 13px; line-height: 1.6; }
18243
18534
  .dim-connectionDiagnostic[data-warning="true"] { color: var(--dsw-alias-state-warn-primary, #d97706); }
18244
18535
  .dim-connectionDiagnostic p { margin: 4px 0; }
@@ -18298,7 +18589,9 @@ var CSS14 = String.raw`
18298
18589
  .dim-updateButton:hover:not(:disabled) { border-color: #aeb3bb; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
18299
18590
  .dim-updateButton:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: 2px; }
18300
18591
  .dim-updateButton:disabled { opacity: .55; cursor: default; }
18301
- .dim-updateTrigger { white-space: nowrap; }
18592
+ .dim-updateAction { position: relative; display: inline-flex; flex: none; }
18593
+ .dim-updateTrigger { width: 30px; height: 30px; flex: none; padding: 0; }
18594
+ .dim-updateTrigger svg { display: block; }
18302
18595
  .dim-updateBackdrop { position: fixed; inset: 0; z-index: 1000; display: grid; place-items: center; padding: 24px; background: rgb(15 17 21 / 42%); }
18303
18596
  .dim-updateBackdrop, .dim-updateBackdrop * { box-sizing: border-box; }
18304
18597
  .dim-updateDialog { width: min(480px, 100%); max-height: calc(100vh - 48px); overflow-y: auto; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 16px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 20px 70px rgb(0 0 0 / 20%); text-align: left; }
@@ -18335,8 +18628,8 @@ var CSS14 = String.raw`
18335
18628
  .dim-githubLink svg { display: block; }
18336
18629
  .dim-githubLink:hover { border-color: #aeb3bb; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
18337
18630
  .dim-githubLink:focus-visible { outline: 2px solid color-mix(in srgb, var(--dim-blue) 70%, white); outline-offset: 2px; }
18338
- .dim-githubTooltip { position: absolute; top: calc(100% + 8px); right: 0; z-index: 20; width: max-content; max-width: min(220px, 80vw); padding: 6px 9px; 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-3, #fff); box-shadow: 0 8px 24px rgb(31 35 41 / 14%); font-size: 11px; line-height: 16px; font-weight: 500; white-space: nowrap; opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
18339
- .dim-githubAction:hover .dim-githubTooltip, .dim-githubAction:focus-within .dim-githubTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
18631
+ .dim-updateTooltip, .dim-githubTooltip { position: absolute; top: calc(100% + 8px); right: 0; z-index: 20; width: max-content; max-width: min(220px, 80vw); padding: 6px 9px; 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-3, #fff); box-shadow: 0 8px 24px rgb(31 35 41 / 14%); font-size: 11px; line-height: 16px; font-weight: 500; white-space: nowrap; opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
18632
+ .dim-updateAction:hover .dim-updateTooltip, .dim-updateTrigger:focus-visible + .dim-updateTooltip, .dim-githubAction:hover .dim-githubTooltip, .dim-githubAction:focus-within .dim-githubTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
18340
18633
  .dim-generalSettingsAction { position: relative; display: inline-flex; flex: none; }
18341
18634
  .dim-generalSettingsButton { width: 30px; height: 30px; display: grid; place-items: center; flex: none; padding: 0; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-layer-1, #fff); cursor: pointer; transition: border-color .15s ease, color .15s ease, background .15s ease, box-shadow .15s ease; }
18342
18635
  .dim-generalSettingsButton svg { display: block; }
@@ -18655,10 +18948,15 @@ var CSS14 = String.raw`
18655
18948
  .dim-panel .dim-botCardBody { position: relative; min-width: 0; width: 100%; max-width: 100%; padding: 12px 8px; }
18656
18949
  .dim-collapsibleAccount { min-width: 0; display: flex; flex-direction: column; }
18657
18950
  .dim-collapsibleHead { min-width: 0; display: flex; align-items: center; gap: 4px; cursor: pointer; user-select: none; -webkit-user-select: none; }
18658
- .dim-collapsibleHead:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: 2px; border-radius: 8px; }
18659
18951
  .dim-collapsibleHeaderContent { min-width: 0; flex: 1 1 auto; display: flex; align-items: center; }
18660
- .dim-collapsibleChevron { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; width: 9px; height: 9px; border-right: 1.6px solid var(--dsw-alias-label-tertiary, #8f959e); border-bottom: 1.6px solid var(--dsw-alias-label-tertiary, #8f959e); transform: rotate(-45deg); transition: transform .22s cubic-bezier(.4, 0, .2, 1); transform-origin: 50% 50%; }
18661
- .dim-collapsibleAccount.is-open .dim-collapsibleChevron { transform: rotate(45deg); }
18952
+ /* Keep the original header footprint; center both icons with equal side space. */
18953
+ .dim-accountSettingsToggle { flex: none; width: 45px; height: 32px; display: inline-flex; gap: 5px; align-items: center; justify-content: center; padding: 0; border: 0; border-radius: 8px; color: var(--dsw-alias-state-business-primary, #3370ff); background: color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 8%, var(--dsw-alias-bg-layer-1, #fff)); cursor: pointer; }
18954
+ .dim-accountSettingsToggle > svg { flex: none; display: block; }
18955
+ .dim-accountSettingsToggle:hover { background: color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 14%, var(--dsw-alias-bg-layer-1, #fff)); }
18956
+ .dim-accountSettingsToggle:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: 2px; }
18957
+ .dim-collapsibleChevron { width: 12px; height: 16px; transition: transform .22s cubic-bezier(.4, 0, .2, 1); transform-origin: 50% 50%; }
18958
+ .dim-accountSettingsToggle[aria-expanded="true"] .dim-collapsibleChevron { transform: rotate(180deg); }
18959
+ .dim-accountSettingsHeader { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 12px; padding-top: 8px; border-top: 1px solid var(--dsw-alias-border-l2, #e5e6eb); color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; }
18662
18960
  /* Animate height without measuring content; hide collapsed controls from focus and accessibility. */
18663
18961
  .dim-collapsibleBody { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .22s cubic-bezier(.4, 0, .2, 1); }
18664
18962
  .dim-collapsibleAccount.is-open > .dim-collapsibleBody { grid-template-rows: 1fr; }
@@ -18683,11 +18981,10 @@ var CSS14 = String.raw`
18683
18981
  .dim-panel .dim-botCard .dim-healthDot[data-tone="warning"] { background: var(--dsw-alias-state-warn-primary, #d97706); }
18684
18982
  .dim-panel .dim-botCard .dim-healthDot[data-tone="error"] { background: var(--dsw-alias-state-error-primary, #d54941); }
18685
18983
  .dim-botSettingsAction { position: relative; flex: none; display: inline-flex; }
18686
- .dim-botSettingsButton { width: 32px; height: 32px; display: grid; place-items: center; padding: 0; border: 0; border-radius: 8px; color: var(--dsw-alias-label-secondary, #646a73); background: transparent; cursor: pointer; transition: color .15s ease, background .15s ease; }
18984
+ .dim-botSettingsButton { min-height: 32px; display: inline-flex; align-items: center; gap: 6px; padding: 0 6px; border: 0; border-radius: 8px; color: var(--dsw-alias-state-business-primary, #3370ff); background: transparent; font: inherit; font-size: 12px; white-space: nowrap; cursor: pointer; transition: color .15s ease, background .15s ease; }
18687
18985
  .dim-botSettingsButton:hover { color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-interactive-bg-hover, #eef0f3); }
18688
18986
  .dim-botSettingsButton:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: 2px; }
18689
- .dim-botSettingsTooltip { position: absolute; top: calc(100% + 6px); right: 0; z-index: 30; width: max-content; padding: 6px 9px; 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-3, #fff); box-shadow: 0 8px 24px rgb(31 35 41 / 14%); font-size: 11px; line-height: 16px; opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
18690
- .dim-botSettingsAction:hover .dim-botSettingsTooltip, .dim-botSettingsAction:focus-within .dim-botSettingsTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
18987
+ .dim-moreSettingsChevron { width: 6px; height: 6px; margin-right: 2px; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(-45deg); }
18691
18988
  .dim-deliveryPage { min-width: 0; display: grid; }
18692
18989
  .dim-deliveryHeader { min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 16px; }
18693
18990
  .dim-botSettingsTabsBar { min-width: 0; margin-top: 10px; border-bottom: 1px solid var(--dsw-alias-border-l2, #dfe1e5); }
@@ -18954,7 +19251,7 @@ function installImStyles() {
18954
19251
  const style = document.createElement("style");
18955
19252
  style.dataset.plugin = "@xmanrui/dsh-im";
18956
19253
  style.dataset.pluginCss = IM_STYLE_ID;
18957
- style.textContent = CSS14;
19254
+ style.textContent = CSS15;
18958
19255
  document.head.appendChild(style);
18959
19256
  return () => style.remove();
18960
19257
  }
@@ -18971,15 +19268,16 @@ var SESSION_CHANNEL_LABELS = Object.freeze(Object.fromEntries(Object.entries({
18971
19268
  discord: ["Discord", "Discord"],
18972
19269
  whatsapp: ["WhatsApp", "WhatsApp"],
18973
19270
  imessage: ["iMessage", "iMessage"],
19271
+ matrix: ["Matrix", "Matrix"],
18974
19272
  office: ["AI Office", "AI Office"]
18975
- }).map(([channel6, labels]) => [channel6, Object.freeze(labels)])));
19273
+ }).map(([channel7, labels]) => [channel7, Object.freeze(labels)])));
18976
19274
  function parseSessionChannelTitle(title) {
18977
19275
  if (typeof title !== "string") return null;
18978
- for (const [channel6, labels] of Object.entries(SESSION_CHANNEL_LABELS)) {
19276
+ for (const [channel7, labels] of Object.entries(SESSION_CHANNEL_LABELS)) {
18979
19277
  for (const label of labels) {
18980
19278
  const prefix = `${label} \xB7 `;
18981
19279
  if (title.startsWith(prefix) && title.slice(prefix.length).trim()) {
18982
- return { channel: channel6, title: title.slice(prefix.length) };
19280
+ return { channel: channel7, title: title.slice(prefix.length) };
18983
19281
  }
18984
19282
  }
18985
19283
  }
@@ -18998,6 +19296,7 @@ var GLYPHS = Object.freeze({
18998
19296
  discord: [DiscordLogoGlyph, "#5865f2"],
18999
19297
  whatsapp: [WhatsappLogoGlyph, "#25d366"],
19000
19298
  imessage: [IMessageLogoGlyph, "#3478f6"],
19299
+ matrix: [MatrixLogoGlyph, "#1a8f6f"],
19001
19300
  office: [OfficeLogoGlyph, "#f97316"]
19002
19301
  });
19003
19302
  var CHANNEL_ATTR = "data-dsh-im-session-channel";
@@ -19020,8 +19319,8 @@ function titleOf(row) {
19020
19319
  }
19021
19320
  return title?.childNodes.length === 1 && title.firstChild.nodeType === 3 ? title : null;
19022
19321
  }
19023
- function logoUri(document2, channel6) {
19024
- const [Glyph, color] = GLYPHS[channel6];
19322
+ function logoUri(document2, channel7) {
19323
+ const [Glyph, color] = GLYPHS[channel7];
19025
19324
  const render = (node) => {
19026
19325
  if (!["svg", "path"].includes(node.type)) throw new Error("Unsupported channel logo element");
19027
19326
  const element = document2.createElementNS(SVG_NS, node.type);
@@ -19048,7 +19347,7 @@ function createInstallation(document2) {
19048
19347
  let scheduled = false;
19049
19348
  const style = document2.createElement("style");
19050
19349
  style.dataset.pluginCss = "dsh-im-session-channel-logos";
19051
- const uris = Object.fromEntries(Object.keys(GLYPHS).map((channel6) => [channel6, logoUri(document2, channel6)]));
19350
+ const uris = Object.fromEntries(Object.keys(GLYPHS).map((channel7) => [channel7, logoUri(document2, channel7)]));
19052
19351
  style.textContent = `
19053
19352
  ${MARKED}[${TITLE_ATTR}] {
19054
19353
  position: relative;
@@ -19080,7 +19379,7 @@ ${MARKED}[${TITLE_ATTR}]::after {
19080
19379
  text-overflow: ellipsis;
19081
19380
  pointer-events: none;
19082
19381
  }
19083
- ${Object.entries(uris).map(([channel6, uri]) => `[${CHANNEL_ATTR}="${channel6}"] { --dsh-im-session-logo: url("${uri}"); }`).join("\n")}
19382
+ ${Object.entries(uris).map(([channel7, uri]) => `[${CHANNEL_ATTR}="${channel7}"] { --dsh-im-session-logo: url("${uri}"); }`).join("\n")}
19084
19383
  `;
19085
19384
  document2.head.appendChild(style);
19086
19385
  const restore = (title) => {
@@ -19163,12 +19462,12 @@ ${Object.entries(uris).map(([channel6, uri]) => `[${CHANNEL_ATTR}="${channel6}"]
19163
19462
  attributes: true,
19164
19463
  attributeFilter: ["class", "role", "aria-selected", "contenteditable"]
19165
19464
  });
19166
- for (const [channel6, uri] of Object.entries(uris)) {
19465
+ for (const [channel7, uri] of Object.entries(uris)) {
19167
19466
  const image = new view.Image();
19168
19467
  images.push(image);
19169
19468
  image.onload = () => {
19170
19469
  if (closed) return;
19171
- ready.add(channel6);
19470
+ ready.add(channel7);
19172
19471
  collect(document2.body, true);
19173
19472
  };
19174
19473
  image.src = uri;
@@ -19209,7 +19508,7 @@ function installSessionChannelLogos(document2 = globalThis.document) {
19209
19508
  }
19210
19509
 
19211
19510
  // plugin-src/client/update-panel.js
19212
- var React31 = __toESM(require("react"), 1);
19511
+ var React32 = __toESM(require("react"), 1);
19213
19512
  var import_react_dom4 = require("react-dom");
19214
19513
  var import_valid = __toESM(require_valid(), 1);
19215
19514
  var import_rcompare = __toESM(require_rcompare(), 1);
@@ -19256,7 +19555,7 @@ function unwrapSnapshot(result) {
19256
19555
  }
19257
19556
  return value;
19258
19557
  }
19259
- function presentError15(error) {
19558
+ function presentError16(error) {
19260
19559
  const code = error?.rpcError?.code ?? error?.code ?? "";
19261
19560
  const message = error?.rpcError?.message ?? error?.message ?? "";
19262
19561
  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)) {
@@ -19271,14 +19570,17 @@ function summary(snapshot, action, error) {
19271
19570
  if (snapshot?.job?.state === "restart-required" || snapshot?.blockedReason === "pending-restart") {
19272
19571
  return "\u5DF2\u5B89\u88C5\uFF0C\u5F85\u624B\u52A8\u91CD\u542F";
19273
19572
  }
19274
- if (snapshot?.job?.state === "completed") return "\u66F4\u65B0\u5DF2\u751F\u6548";
19275
- if (snapshot?.job?.state === "failed") return "\u66F4\u65B0\u5931\u8D25";
19276
- if (snapshot?.job?.state === "interrupted") return "\u4E0A\u6B21\u66F4\u65B0\u5DF2\u4E2D\u65AD\uFF0C\u8BF7\u68C0\u67E5\u5B89\u88C5\u72B6\u6001\u540E\u91CD\u8BD5\u3002";
19277
19573
  if (error) return "\u66F4\u65B0\u8BF7\u6C42\u5931\u8D25";
19574
+ if (!snapshot?.job?.recoverable) {
19575
+ if (snapshot?.job?.state === "failed") return "\u66F4\u65B0\u5931\u8D25";
19576
+ if (snapshot?.job?.state === "interrupted") return "\u4E0A\u6B21\u66F4\u65B0\u5DF2\u4E2D\u65AD\uFF0C\u8BF7\u68C0\u67E5\u5B89\u88C5\u72B6\u6001\u540E\u91CD\u8BD5\u3002";
19577
+ }
19578
+ if (snapshot?.blockedReason === "no-update") return "\u5F53\u524D\u7248\u672C\u65E0\u9700\u66F4\u65B0";
19579
+ if (snapshot?.blockedReason) return "\u6682\u65F6\u65E0\u6CD5\u5B89\u88C5\u66F4\u65B0";
19278
19580
  if (snapshot?.canInstall) return "\u53D1\u73B0\u65B0\u7248\u672C";
19279
19581
  if (snapshot?.checkedAt && snapshot.latestVersion === snapshot.runningVersion) return "\u5DF2\u662F\u6700\u65B0\u7248\u672C";
19280
- if (snapshot?.blockedReason === "no-update") return "\u5F53\u524D\u7248\u672C\u65E0\u9700\u66F4\u65B0";
19281
19582
  if (snapshot?.checkedAt) return "\u5DF2\u83B7\u53D6 npm \u6700\u65B0\u7248\u672C";
19583
+ if (snapshot?.job?.state === "completed") return "\u66F4\u65B0\u5DF2\u751F\u6548";
19282
19584
  return "\u68C0\u67E5 npm \u6700\u65B0\u7248\u672C\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u5B89\u88C5\u3002";
19283
19585
  }
19284
19586
  function retainDialogFocus(event) {
@@ -19293,17 +19595,17 @@ function manualUpdateCommand(snapshot) {
19293
19595
  const targets = [
19294
19596
  snapshot.latestVersion,
19295
19597
  pendingRestart ? snapshot.installedVersion : null,
19296
- snapshot.job?.state !== "completed" ? snapshot.job?.targetVersion : null
19598
+ snapshot.job?.state !== "completed" && !snapshot.job?.recoverable ? snapshot.job?.targetVersion : null
19297
19599
  ].filter(validVersion);
19298
19600
  const version = targets.length ? [...targets, snapshot.runningVersion, snapshot.installedVersion].filter(validVersion).sort(import_rcompare.default)[0] : "latest";
19299
19601
  return `dsh plugin --profile ${profileArgument} add -w @xmanrui/dsh-im@${version}`;
19300
19602
  }
19301
19603
  function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
19302
- const [copyState, setCopyState] = React31.useState("idle");
19303
- const commandRef = React31.useRef(null);
19304
- const mounted = React31.useRef(false);
19305
- const copying = React31.useRef(false);
19306
- React31.useEffect(() => {
19604
+ const [copyState, setCopyState] = React32.useState("idle");
19605
+ const commandRef = React32.useRef(null);
19606
+ const mounted = React32.useRef(false);
19607
+ const copying = React32.useRef(false);
19608
+ React32.useEffect(() => {
19307
19609
  mounted.current = true;
19308
19610
  return () => {
19309
19611
  mounted.current = false;
@@ -19335,7 +19637,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
19335
19637
  { className: "dim-updateManual", "aria-label": "\u624B\u5DE5\u66F4\u65B0" },
19336
19638
  h2("h4", { className: "dim-updateManualHeading" }, "\u624B\u5DE5\u66F4\u65B0"),
19337
19639
  command ? h2(
19338
- React31.Fragment,
19640
+ React32.Fragment,
19339
19641
  null,
19340
19642
  h2("p", { className: "dim-updateManualHint" }, "\u81EA\u52A8\u66F4\u65B0\u5931\u8D25\u53EF\u4EE5\u4F7F\u7528\u547D\u4EE4\u66F4\u65B0\uFF1A"),
19341
19643
  h2(
@@ -19371,7 +19673,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
19371
19673
  "aria-hidden": "true",
19372
19674
  focusable: "false"
19373
19675
  }, copyState === "copied" ? h2("path", { d: "m4 10 4 4 8-8" }) : h2(
19374
- React31.Fragment,
19676
+ React32.Fragment,
19375
19677
  null,
19376
19678
  h2("rect", { x: 7, y: 7, width: 10, height: 11, rx: 1.5 }),
19377
19679
  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" })
@@ -19396,10 +19698,10 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
19396
19698
  );
19397
19699
  }
19398
19700
  function UpdateDialog({ children, onClose }) {
19399
- const dialogRef = React31.useRef(null);
19400
- const titleId = React31.useId();
19401
- const descriptionId = React31.useId();
19402
- React31.useEffect(() => {
19701
+ const dialogRef = React32.useRef(null);
19702
+ const titleId = React32.useId();
19703
+ const descriptionId = React32.useId();
19704
+ React32.useEffect(() => {
19403
19705
  const previous = globalThis.document?.activeElement;
19404
19706
  dialogRef.current?.focus?.();
19405
19707
  return () => {
@@ -19457,19 +19759,20 @@ function UpdateDialog({ children, onClose }) {
19457
19759
  return typeof document !== "undefined" && document.body ? (0, import_react_dom4.createPortal)(content, document.body) : content;
19458
19760
  }
19459
19761
  function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19460
- const [snapshot, setSnapshot] = React31.useState(null);
19461
- const [action, setAction] = React31.useState("status");
19462
- const [error, setError] = React31.useState(null);
19463
- const [open, setOpen] = React31.useState(false);
19464
- const [uncertainInstall, setUncertainInstall] = React31.useState(false);
19465
- const mounted = React31.useRef(false);
19466
- const busy = React31.useRef(false);
19467
- const readController = React31.useRef(null);
19468
- const pollReadController = React31.useRef(null);
19469
- const installRequest = React31.useRef(null);
19470
- const onStatusRef = React31.useRef(onStatus);
19762
+ const tooltipId = React32.useId();
19763
+ const [snapshot, setSnapshot] = React32.useState(null);
19764
+ const [action, setAction] = React32.useState("status");
19765
+ const [error, setError] = React32.useState(null);
19766
+ const [open, setOpen] = React32.useState(false);
19767
+ const [uncertainInstall, setUncertainInstall] = React32.useState(false);
19768
+ const mounted = React32.useRef(false);
19769
+ const busy = React32.useRef(false);
19770
+ const readController = React32.useRef(null);
19771
+ const pollReadController = React32.useRef(null);
19772
+ const installRequest = React32.useRef(null);
19773
+ const onStatusRef = React32.useRef(onStatus);
19471
19774
  onStatusRef.current = onStatus;
19472
- const accept = React31.useCallback((next) => {
19775
+ const accept = React32.useCallback((next) => {
19473
19776
  setSnapshot(next);
19474
19777
  onStatusRef.current?.(next);
19475
19778
  }, []);
@@ -19478,7 +19781,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19478
19781
  setUncertainInstall(false);
19479
19782
  accept(next);
19480
19783
  };
19481
- const invoke = React31.useCallback(async (endpoint, payload = {}, signal) => {
19784
+ const invoke = React32.useCallback(async (endpoint, payload = {}, signal) => {
19482
19785
  if (typeof rpcCall !== "function") {
19483
19786
  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");
19484
19787
  unavailable.code = "update-unavailable";
@@ -19486,14 +19789,14 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19486
19789
  }
19487
19790
  return unwrapSnapshot(await rpcCall(endpoint, payload, signal));
19488
19791
  }, [rpcCall]);
19489
- React31.useEffect(() => {
19792
+ React32.useEffect(() => {
19490
19793
  mounted.current = true;
19491
19794
  busy.current = true;
19492
19795
  const controller = new AbortController();
19493
19796
  void invoke("update.status", {}, controller.signal).then((next) => {
19494
19797
  if (!controller.signal.aborted) accept(next);
19495
19798
  }).catch((cause) => {
19496
- if (!controller.signal.aborted) setError(presentError15(cause));
19799
+ if (!controller.signal.aborted) setError(presentError16(cause));
19497
19800
  }).finally(() => {
19498
19801
  if (!controller.signal.aborted) {
19499
19802
  busy.current = false;
@@ -19509,7 +19812,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19509
19812
  const activeJob = ACTIVE_STATES4.has(snapshot?.job?.state);
19510
19813
  const restartRequired = snapshot?.job?.state === "restart-required" || snapshot?.blockedReason === "pending-restart";
19511
19814
  const shouldPoll = activeJob || uncertainInstall;
19512
- React31.useEffect(() => {
19815
+ React32.useEffect(() => {
19513
19816
  if (!shouldPoll) return void 0;
19514
19817
  let controller;
19515
19818
  const scheduler = createPollScheduler({
@@ -19530,7 +19833,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19530
19833
  keepPolling = ACTIVE_STATES4.has(next.job?.state);
19531
19834
  }
19532
19835
  } catch (cause) {
19533
- if (!pendingController.signal.aborted) setError(presentError15(cause));
19836
+ if (!pendingController.signal.aborted) setError(presentError16(cause));
19534
19837
  } finally {
19535
19838
  if (pollReadController.current === pendingController) pollReadController.current = null;
19536
19839
  }
@@ -19561,7 +19864,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19561
19864
  else acceptAuthoritative(next);
19562
19865
  }
19563
19866
  } catch (cause) {
19564
- if (!controller.signal.aborted && mounted.current) setError(presentError15(cause));
19867
+ if (!controller.signal.aborted && mounted.current) setError(presentError16(cause));
19565
19868
  } finally {
19566
19869
  if (!controller.signal.aborted && mounted.current) {
19567
19870
  busy.current = false;
@@ -19587,7 +19890,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19587
19890
  if (mounted.current) acceptAuthoritative(next);
19588
19891
  } catch (cause) {
19589
19892
  if (mounted.current) {
19590
- setError(presentError15(cause));
19893
+ setError(presentError16(cause));
19591
19894
  setUncertainInstall(true);
19592
19895
  }
19593
19896
  } finally {
@@ -19601,25 +19904,53 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19601
19904
  const blocked = BLOCKED_REASONS[snapshot?.blockedReason] ?? ERROR_MESSAGES[snapshot?.blockedReason];
19602
19905
  const canConfirm = snapshot?.canInstall && snapshot.checkId && !activeJob && !restartRequired;
19603
19906
  const versionsDiffer = snapshot && clientVersion && snapshot.runningVersion !== clientVersion;
19604
- const failedJob = ["failed", "interrupted"].includes(snapshot?.job?.state);
19907
+ const failedJob = ["failed", "interrupted"].includes(snapshot?.job?.state) && !snapshot.job.recoverable;
19605
19908
  const jobMessage = snapshot?.job?.message;
19606
- const targetVersion = snapshot?.job?.targetVersion;
19909
+ const targetVersion = activeJob || restartRequired ? snapshot?.job?.targetVersion : null;
19910
+ const historicalTargetVersion = !activeJob && !restartRequired ? snapshot?.job?.targetVersion : null;
19911
+ const latestVersion = !activeJob && !restartRequired && !error && snapshot?.checkedAt ? snapshot.latestVersion : null;
19607
19912
  const manualCommand = manualUpdateCommand(snapshot);
19608
19913
  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";
19914
+ const buttonDescription = localizeText(buttonLabel) + (buttonLabel === "\u66F4\u65B0\u81F3" ? ` v${snapshot.latestVersion}` : "");
19609
19915
  return h2(
19610
- React31.Fragment,
19916
+ React32.Fragment,
19611
19917
  null,
19612
- h2("button", {
19613
- type: "button",
19614
- className: "dim-updateButton dim-updateTrigger",
19615
- disabled: busyAction,
19616
- "aria-haspopup": "dialog",
19617
- onClick: () => {
19618
- setOpen(true);
19619
- if (restartRequired) void refreshStatus();
19620
- else if (!snapshot?.canInstall && !snapshot?.job) void check();
19621
- }
19622
- }, buttonLabel, buttonLabel === "\u66F4\u65B0\u81F3" ? ` v${snapshot.latestVersion}` : null),
19918
+ h2(
19919
+ "span",
19920
+ { className: "dim-updateAction" },
19921
+ h2("button", {
19922
+ type: "button",
19923
+ className: "dim-updateButton dim-updateTrigger",
19924
+ disabled: busyAction,
19925
+ "aria-label": buttonDescription,
19926
+ "aria-describedby": tooltipId,
19927
+ "aria-haspopup": "dialog",
19928
+ onClick: () => {
19929
+ setOpen(true);
19930
+ if (restartRequired) void refreshStatus();
19931
+ else if (!snapshot?.canInstall && !activeJob && !uncertainInstall) void check();
19932
+ }
19933
+ }, h2(
19934
+ "svg",
19935
+ {
19936
+ width: 18,
19937
+ height: 18,
19938
+ viewBox: "0 0 24 24",
19939
+ fill: "none",
19940
+ stroke: "currentColor",
19941
+ strokeWidth: 2.3,
19942
+ strokeLinecap: "round",
19943
+ strokeLinejoin: "round",
19944
+ focusable: "false",
19945
+ "aria-hidden": "true"
19946
+ },
19947
+ h2("path", { d: "M3 12a9 9 0 0 1 15.36-6.36L21 8" }),
19948
+ h2("path", { d: "M21 3v5h-5" }),
19949
+ h2("path", { d: "M21 12a9 9 0 0 1-15.36 6.36L3 16" }),
19950
+ h2("path", { d: "M8 16H3v5" })
19951
+ )),
19952
+ h2("span", { id: tooltipId, className: "dim-updateTooltip", role: "tooltip" }, buttonDescription)
19953
+ ),
19623
19954
  open ? h2(
19624
19955
  UpdateDialog,
19625
19956
  { onClose: () => setOpen(false) },
@@ -19632,17 +19963,29 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19632
19963
  h2("dt", null, "\u8FD0\u884C\u7248\u672C"),
19633
19964
  h2("dd", null, `v${snapshot?.runningVersion ?? clientVersion}`),
19634
19965
  snapshot?.installedVersion && snapshot.installedVersion !== snapshot.runningVersion ? h2(
19635
- React31.Fragment,
19966
+ React32.Fragment,
19636
19967
  null,
19637
19968
  h2("dt", null, "\u5DF2\u5B89\u88C5\u7248\u672C"),
19638
19969
  h2("dd", null, `v${snapshot.installedVersion}`)
19639
19970
  ) : null,
19640
19971
  targetVersion ? h2(
19641
- React31.Fragment,
19972
+ React32.Fragment,
19642
19973
  null,
19643
19974
  h2("dt", null, "\u76EE\u6807\u7248\u672C"),
19644
19975
  h2("dd", null, `v${targetVersion}`)
19645
19976
  ) : null,
19977
+ latestVersion ? h2(
19978
+ React32.Fragment,
19979
+ null,
19980
+ h2("dt", null, "\u6700\u65B0\u7248\u672C"),
19981
+ h2("dd", null, `v${latestVersion}`)
19982
+ ) : null,
19983
+ historicalTargetVersion ? h2(
19984
+ React32.Fragment,
19985
+ null,
19986
+ h2("dt", null, "\u4E0A\u6B21\u66F4\u65B0\u76EE\u6807"),
19987
+ h2("dd", null, `v${historicalTargetVersion}`)
19988
+ ) : null,
19646
19989
  h2("dt", null, "\u76EE\u6807 profile"),
19647
19990
  h2("dd", null, snapshot?.profileName ?? "\u65E0\u6CD5\u786E\u8BA4")
19648
19991
  ),
@@ -19707,8 +20050,8 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19707
20050
  }
19708
20051
 
19709
20052
  // plugin-src/client/panel-error-boundary.js
19710
- var React32 = __toESM(require("react"), 1);
19711
- var IMPanelErrorBoundary = class extends React32.Component {
20053
+ var React33 = __toESM(require("react"), 1);
20054
+ var IMPanelErrorBoundary = class extends React33.Component {
19712
20055
  state = { failed: false };
19713
20056
  static getDerivedStateFromError() {
19714
20057
  return { failed: true };
@@ -19752,6 +20095,7 @@ var CHANNELS = Object.freeze([
19752
20095
  { id: "wecomApp", label: "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528", note: "\uFF08\u5B9E\u9A8C\u529F\u80FD\uFF09" },
19753
20096
  { id: "imessage", label: "iMessage", note: "\uFF08\u5B9E\u9A8C\u529F\u80FD\uFF09" },
19754
20097
  { id: "email", label: "\u90AE\u7BB1", note: "\uFF08\u5B9E\u9A8C\u529F\u80FD\uFF09" },
20098
+ { id: "matrix", label: "Matrix", note: "\uFF08\u5B9E\u9A8C\u529F\u80FD\uFF09" },
19755
20099
  { id: "office", label: "AI Office", note: "\uFF08\u5B9E\u9A8C\u529F\u80FD\uFF09" }
19756
20100
  ]);
19757
20101
  function WeixinLogo() {
@@ -19826,6 +20170,13 @@ function EmailLogo() {
19826
20170
  h2(EmailLogoGlyph)
19827
20171
  );
19828
20172
  }
20173
+ function MatrixLogo() {
20174
+ return h2(
20175
+ "span",
20176
+ { className: "dim-logo dim-logoMatrix", "aria-hidden": "true" },
20177
+ h2(MatrixLogoGlyph)
20178
+ );
20179
+ }
19829
20180
  function OfficeLogo() {
19830
20181
  return h2(
19831
20182
  "span",
@@ -19833,19 +20184,20 @@ function OfficeLogo() {
19833
20184
  h2(OfficeLogoGlyph)
19834
20185
  );
19835
20186
  }
19836
- function ChannelLogo({ channel: channel6 }) {
19837
- if (channel6 === "weixin") return h2(WeixinLogo);
19838
- if (channel6 === "feishu") return h2(FeishuLogo);
19839
- if (channel6 === "dingtalk") return h2(DingtalkLogo);
19840
- if (channel6 === "wecom") return h2(WecomLogo);
19841
- if (channel6 === "wecomApp") return h2(WecomAppLogo);
19842
- if (channel6 === "qq") return h2(QqLogo);
19843
- if (channel6 === "slack") return h2(SlackLogo);
19844
- if (channel6 === "telegram") return h2(TelegramLogo);
19845
- if (channel6 === "discord") return h2(DiscordLogo);
19846
- if (channel6 === "whatsapp") return h2(WhatsappLogo);
19847
- if (channel6 === "imessage") return h2(IMessageLogo);
19848
- if (channel6 === "email") return h2(EmailLogo);
20187
+ function ChannelLogo({ channel: channel7 }) {
20188
+ if (channel7 === "weixin") return h2(WeixinLogo);
20189
+ if (channel7 === "feishu") return h2(FeishuLogo);
20190
+ if (channel7 === "dingtalk") return h2(DingtalkLogo);
20191
+ if (channel7 === "wecom") return h2(WecomLogo);
20192
+ if (channel7 === "wecomApp") return h2(WecomAppLogo);
20193
+ if (channel7 === "qq") return h2(QqLogo);
20194
+ if (channel7 === "slack") return h2(SlackLogo);
20195
+ if (channel7 === "telegram") return h2(TelegramLogo);
20196
+ if (channel7 === "discord") return h2(DiscordLogo);
20197
+ if (channel7 === "whatsapp") return h2(WhatsappLogo);
20198
+ if (channel7 === "imessage") return h2(IMessageLogo);
20199
+ if (channel7 === "email") return h2(EmailLogo);
20200
+ if (channel7 === "matrix") return h2(MatrixLogo);
19849
20201
  return h2(OfficeLogo);
19850
20202
  }
19851
20203
  function LoopbackRecoveryNotice({ recovery, onNavigate = replacePageLocation }) {
@@ -19875,6 +20227,7 @@ function IMSettingsTab({
19875
20227
  feishuRpcCall,
19876
20228
  imessageRpcCall,
19877
20229
  emailRpcCall,
20230
+ matrixRpcCall,
19878
20231
  qqRpcCall,
19879
20232
  slackRpcCall,
19880
20233
  telegramRpcCall,
@@ -19891,28 +20244,28 @@ function IMSettingsTab({
19891
20244
  browserLocation = globalThis.location,
19892
20245
  navigateToRecoveryUrl = replacePageLocation
19893
20246
  }) {
19894
- const [selected, setSelected] = React33.useState(() => preferredSectionId === GLOBAL_SETTINGS_TAB_ID || CHANNELS.some((channel6) => channel6.id === preferredSectionId) ? preferredSectionId : "weixin");
19895
- const [loopbackRecovery, setLoopbackRecovery] = React33.useState(null);
19896
- const [runningVersion, setRunningVersion] = React33.useState(IM_PLUGIN_VERSION);
19897
- const [deliverySettings, setDeliverySettings] = React33.useState(null);
20247
+ const [selected, setSelected] = React34.useState(() => preferredSectionId === GLOBAL_SETTINGS_TAB_ID || CHANNELS.some((channel7) => channel7.id === preferredSectionId) ? preferredSectionId : "weixin");
20248
+ const [loopbackRecovery, setLoopbackRecovery] = React34.useState(null);
20249
+ const [runningVersion, setRunningVersion] = React34.useState(IM_PLUGIN_VERSION);
20250
+ const [deliverySettings, setDeliverySettings] = React34.useState(null);
19898
20251
  const emailEnabled = useEmailChannelEnabled(emailRpcCall);
19899
- const visibleChannels = React33.useMemo(
19900
- () => CHANNELS.filter((channel6) => channel6.id !== "email" || emailEnabled),
20252
+ const visibleChannels = React34.useMemo(
20253
+ () => CHANNELS.filter((channel7) => channel7.id !== "email" || emailEnabled),
19901
20254
  [emailEnabled]
19902
20255
  );
19903
- const githubTooltipId = React33.useId();
19904
- const generalSettingsTooltipId = React33.useId();
20256
+ const githubTooltipId = React34.useId();
20257
+ const generalSettingsTooltipId = React34.useId();
19905
20258
  const globalSettingsSelected = selected === GLOBAL_SETTINGS_TAB_ID;
19906
- const active = visibleChannels.find((channel6) => channel6.id === selected) ?? visibleChannels[0];
20259
+ const active = visibleChannels.find((channel7) => channel7.id === selected) ?? visibleChannels[0];
19907
20260
  const activeTabId = globalSettingsSelected ? "dim-general-settings-trigger" : `dim-tab-${active.id}`;
19908
20261
  const activePanelId = globalSettingsSelected ? `dim-panel-${GLOBAL_SETTINGS_TAB_ID}` : `dim-panel-${active.id}`;
19909
- const reportLoopbackRecovery = React33.useCallback((recovery) => {
20262
+ const reportLoopbackRecovery = React34.useCallback((recovery) => {
19910
20263
  setLoopbackRecovery((current) => current?.url === recovery.url ? current : recovery);
19911
20264
  }, []);
19912
- const reportUpdateStatus = React33.useCallback((snapshot) => {
20265
+ const reportUpdateStatus = React34.useCallback((snapshot) => {
19913
20266
  setRunningVersion(snapshot.runningVersion);
19914
20267
  }, []);
19915
- const rpcCalls = React33.useMemo(() => createLoopbackAwareRpcCalls({
20268
+ const rpcCalls = React34.useMemo(() => createLoopbackAwareRpcCalls({
19916
20269
  dingtalkRpcCall,
19917
20270
  discordRpcCall,
19918
20271
  feishuRpcCall,
@@ -19928,7 +20281,8 @@ function IMSettingsTab({
19928
20281
  deliveryRpcCall,
19929
20282
  globalSettingsRpcCall,
19930
20283
  imessageRpcCall,
19931
- emailRpcCall
20284
+ emailRpcCall,
20285
+ matrixRpcCall
19932
20286
  }, {
19933
20287
  location: browserLocation,
19934
20288
  onRecovery: reportLoopbackRecovery
@@ -19941,6 +20295,7 @@ function IMSettingsTab({
19941
20295
  globalSettingsRpcCall,
19942
20296
  imessageRpcCall,
19943
20297
  emailRpcCall,
20298
+ matrixRpcCall,
19944
20299
  officeRpcCall,
19945
20300
  qqRpcCall,
19946
20301
  reportLoopbackRecovery,
@@ -19952,7 +20307,7 @@ function IMSettingsTab({
19952
20307
  weixinRpcCall,
19953
20308
  whatsappRpcCall
19954
20309
  ]);
19955
- const botSettingsContext = React33.useMemo(() => Object.freeze({
20310
+ const botSettingsContext = React34.useMemo(() => Object.freeze({
19956
20311
  openBotSettings: setDeliverySettings
19957
20312
  }), []);
19958
20313
  return h2(
@@ -20043,27 +20398,27 @@ function IMSettingsTab({
20043
20398
  h2(
20044
20399
  "nav",
20045
20400
  { className: "dim-rail", role: "tablist", "aria-label": "IM \u8BBE\u7F6E\u5BFC\u822A" },
20046
- visibleChannels.map((channel6) => h2(
20401
+ visibleChannels.map((channel7) => h2(
20047
20402
  "button",
20048
20403
  {
20049
- key: channel6.id,
20404
+ key: channel7.id,
20050
20405
  type: "button",
20051
20406
  role: "tab",
20052
- id: `dim-tab-${channel6.id}`,
20407
+ id: `dim-tab-${channel7.id}`,
20053
20408
  className: "dim-channel",
20054
- "aria-selected": !globalSettingsSelected && channel6.id === active.id,
20055
- "aria-controls": `dim-panel-${channel6.id}`,
20409
+ "aria-selected": !globalSettingsSelected && channel7.id === active.id,
20410
+ "aria-controls": `dim-panel-${channel7.id}`,
20056
20411
  onClick: () => {
20057
- setSelected(channel6.id);
20412
+ setSelected(channel7.id);
20058
20413
  setDeliverySettings(null);
20059
20414
  }
20060
20415
  },
20061
- h2(ChannelLogo, { channel: channel6.id }),
20416
+ h2(ChannelLogo, { channel: channel7.id }),
20062
20417
  h2(
20063
20418
  "span",
20064
20419
  { className: "dim-channelCopy" },
20065
- h2("strong", null, channel6.label),
20066
- channel6.note ? h2("small", { className: "dim-channelNote" }, channel6.note) : null
20420
+ h2("strong", null, channel7.label),
20421
+ channel7.note ? h2("small", { className: "dim-channelNote" }, channel7.note) : null
20067
20422
  )
20068
20423
  ))
20069
20424
  ),
@@ -20089,7 +20444,7 @@ function IMSettingsTab({
20089
20444
  rpcCall: rpcCalls.deliveryRpcCall,
20090
20445
  accessRpcCall: rpcCalls[`${active.id}RpcCall`],
20091
20446
  onBack: () => setDeliverySettings(null)
20092
- }) : 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 }) : active.id === "imessage" ? h2(IMessageSettingsTab, { rpcCall: rpcCalls.imessageRpcCall }) : active.id === "email" ? h2(EmailSettingsTab, { rpcCall: rpcCalls.emailRpcCall }) : h2(OfficeSettingsTab, { rpcCall: rpcCalls.officeRpcCall })
20447
+ }) : 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 }) : active.id === "imessage" ? h2(IMessageSettingsTab, { rpcCall: rpcCalls.imessageRpcCall }) : active.id === "email" ? h2(EmailSettingsTab, { rpcCall: rpcCalls.emailRpcCall }) : active.id === "matrix" ? h2(MatrixSettingsTab, { rpcCall: rpcCalls.matrixRpcCall }) : h2(OfficeSettingsTab, { rpcCall: rpcCalls.officeRpcCall })
20093
20448
  )
20094
20449
  )
20095
20450
  )
@@ -20123,6 +20478,7 @@ function apply(ctx) {
20123
20478
  installWhatsappStyles(),
20124
20479
  installIMessageStyles(),
20125
20480
  installEmailStyles(),
20481
+ installMatrixStyles(),
20126
20482
  installOfficeStyles(),
20127
20483
  installImStyles()
20128
20484
  ];
@@ -20141,6 +20497,7 @@ function apply(ctx) {
20141
20497
  const whatsappRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, WHATSAPP_RPC_CHANNEL, endpoint, payload, signal);
20142
20498
  const imessageRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, IMESSAGE_RPC_CHANNEL, endpoint, payload, signal);
20143
20499
  const emailRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, EMAIL_RPC_CHANNEL, endpoint, payload, signal);
20500
+ const matrixRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, MATRIX_RPC_CHANNEL, endpoint, payload, signal);
20144
20501
  const slackRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, SLACK_RPC_CHANNEL, endpoint, payload, signal);
20145
20502
  const officeRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, OFFICE_RPC_CHANNEL, endpoint, payload, signal);
20146
20503
  const updateRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, UPDATE_RPC_CHANNEL, endpoint, payload, signal);
@@ -20164,6 +20521,7 @@ function apply(ctx) {
20164
20521
  imessageRpcCall,
20165
20522
  officeRpcCall,
20166
20523
  emailRpcCall,
20524
+ matrixRpcCall,
20167
20525
  updateRpcCall,
20168
20526
  deliveryRpcCall,
20169
20527
  globalSettingsRpcCall,
@@ -20173,7 +20531,7 @@ function apply(ctx) {
20173
20531
  };
20174
20532
  const localeSnapshot = () => ctx.locale.getLocale?.()?.active ?? "";
20175
20533
  function IMPanel({ preferredSectionId }) {
20176
- React33.useSyncExternalStore(subscribeLocale, localeSnapshot, localeSnapshot);
20534
+ React34.useSyncExternalStore(subscribeLocale, localeSnapshot, localeSnapshot);
20177
20535
  return h2(
20178
20536
  IMPanelErrorBoundary,
20179
20537
  null,