@xmanrui/dsh-im 4.24.1 → 4.26.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 (49) hide show
  1. package/PROACTIVE_DELIVERY.en.md +12 -4
  2. package/PROACTIVE_DELIVERY.md +12 -4
  3. package/README.en.md +11 -3
  4. package/README.md +11 -3
  5. package/THIRD_PARTY_NOTICES.md +2 -0
  6. package/lib/client.js +654 -311
  7. package/lib/index.js +298 -289
  8. package/package.json +7 -8
  9. package/plugin-src/client/channel-logos.js +11 -0
  10. package/plugin-src/client/channels/matrix/api.js +11 -0
  11. package/plugin-src/client/channels/matrix/index.js +151 -0
  12. package/plugin-src/client/channels/matrix/styles.js +36 -0
  13. package/plugin-src/client/global-settings.js +26 -14
  14. package/plugin-src/client/i18n.js +20 -0
  15. package/plugin-src/client/index.js +20 -0
  16. package/plugin-src/client/session-channel-logos.js +2 -1
  17. package/plugin-src/client/styles.js +19 -3
  18. package/plugin-src/client/update-panel.js +31 -11
  19. package/plugin-src/host/channels/matrix/index.mjs +31 -0
  20. package/plugin-src/host/channels/matrix/production.mjs +227 -0
  21. package/plugin-src/host/channels/matrix/rpc.mjs +228 -0
  22. package/plugin-src/host/channels/shared/access-policy-production.mjs +1 -1
  23. package/plugin-src/host/channels/shared/startup-error.mjs +2 -1
  24. package/plugin-src/host/delivery-adapter.mjs +18 -0
  25. package/plugin-src/host/delivery-rpc.mjs +7 -2
  26. package/plugin-src/host/delivery-service.mjs +8 -2
  27. package/plugin-src/host/delivery-suggestions.mjs +13 -0
  28. package/plugin-src/host/index.mjs +3 -0
  29. package/scripts/verify-injected-context.mjs +120 -0
  30. package/scripts/verify-lan-management.mjs +1 -1
  31. package/scripts/verify-package.mjs +6 -1
  32. package/src/channels/feishu/feishu-runtime.mjs +13 -3
  33. package/src/channels/matrix/matrix-api.mjs +696 -0
  34. package/src/channels/matrix/matrix-bridge.mjs +20 -0
  35. package/src/channels/matrix/matrix-config-store.mjs +356 -0
  36. package/src/channels/matrix/matrix-controller.mjs +404 -0
  37. package/src/channels/matrix/matrix-crypto-store.mjs +279 -0
  38. package/src/channels/matrix/matrix-crypto.mjs +1014 -0
  39. package/src/channels/matrix/matrix-harness-client.mjs +11 -0
  40. package/src/channels/matrix/matrix-normalize.mjs +357 -0
  41. package/src/channels/matrix/matrix-rich-text.mjs +313 -0
  42. package/src/channels/matrix/matrix-runtime.mjs +900 -0
  43. package/src/channels/shared/command-catalog.mjs +1 -1
  44. package/src/channels/shared/i18n-en/image-input.mjs +1 -0
  45. package/src/channels/shared/i18n-en/matrix.mjs +75 -0
  46. package/src/channels/shared/i18n-en.mjs +2 -0
  47. package/src/channels/shared/injected-context.mjs +3 -3
  48. package/src/channels/shared/session-channel-labels.mjs +1 -0
  49. package/src/channels/shared/text-harness-bridge.mjs +3 -0
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.1",
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.26.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)",
@@ -710,6 +711,7 @@ var package_default = {
710
711
  "lib",
711
712
  "plugin-src",
712
713
  "scripts/verify-interface-language.mjs",
714
+ "scripts/verify-injected-context.mjs",
713
715
  "scripts/verify-lan-management.mjs",
714
716
  "scripts/verify-model-setting.mjs",
715
717
  "scripts/verify-package.mjs",
@@ -739,13 +741,9 @@ var package_default = {
739
741
  platform: "web"
740
742
  },
741
743
  compatibility: {
742
- dsh: "0.1.2-alpha.4 || 0.1.2-alpha.5 || 0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.5-alpha.1",
744
+ dsh: "0.1.7-alpha.1",
743
745
  dshReleases: {
744
- "0.1.2-alpha.4": "compatible",
745
- "0.1.2-alpha.5": "compatible",
746
- "0.1.2-rc.1": "compatible",
747
- "0.1.3-alpha.1": "compatible",
748
- "0.1.5-alpha.1": "compatible"
746
+ "0.1.7-alpha.1": "compatible"
749
747
  },
750
748
  profiles: [
751
749
  "web"
@@ -761,6 +759,7 @@ var package_default = {
761
759
  node: ">=22.19"
762
760
  },
763
761
  dependencies: {
762
+ "@matrix-org/olm": "3.2.15",
764
763
  "@tencent-connect/qqbot-connector": "1.2.0",
765
764
  "@tencent-connect/qqbot-nodejs": "1.0.4",
766
765
  "@wecom/aibot-node-sdk": "1.0.7",
@@ -950,6 +949,19 @@ function IMessageLogoGlyph({ size } = {}) {
950
949
  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"
951
950
  }));
952
951
  }
952
+ function MatrixLogoGlyph({ size } = {}) {
953
+ return h("svg", {
954
+ ...dimensions(size),
955
+ viewBox: "0 0 24 24",
956
+ focusable: "false",
957
+ "aria-hidden": "true",
958
+ "data-im-channel-logo": "matrix"
959
+ }, h("path", {
960
+ fill: "currentColor",
961
+ "fill-rule": "evenodd",
962
+ 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"
963
+ }));
964
+ }
953
965
  function OfficeLogoGlyph({ size } = {}) {
954
966
  return h(
955
967
  "svg",
@@ -995,6 +1007,7 @@ var image_input_default = {
995
1007
  "\u6A21\u578B\u56FE\u7247\u603B\u91CF\u4E0A\u9650 (MB)": "Model total image limit (MB)",
996
1008
  "\u6BCF\u6761\u6D88\u606F\u6700\u591A\u56FE\u7247\u6570": "Maximum images per message",
997
1009
  "\u56FE\u7247\u8F93\u5165": "Image input",
1010
+ "\u67E5\u770B\u56FE\u7247\u8F93\u5165\u8BF4\u660E": "View image input details",
998
1011
  "\u9002\u7528\u4E8E\u652F\u6301\u56FE\u7247\u7684\u804A\u5929\u6E20\u9053\u3002\u539F\u56FE\u6309\u9644\u4EF6\u4FDD\u7559\u65F6\u957F\u4FDD\u5B58\uFF0C\u53D1\u9001\u7ED9\u6A21\u578B\u7684\u526F\u672C\u4F1A\u81EA\u52A8\u7F29\u653E\u6216\u538B\u7F29\uFF1B\u65E0\u6CD5\u76F4\u63A5\u53D1\u9001\u65F6\u4EA4\u7ED9\u6A21\u578B\u6309\u6587\u4EF6\u5904\u7406\u3002": "Applies to chat channels that support images. Originals follow attachment retention settings. Model copies are resized or compressed automatically; images that cannot be sent directly are provided as files.",
999
1012
  "\u4FDD\u5B58\u56FE\u7247\u8BBE\u7F6E": "Save image settings",
1000
1013
  "\u6B63\u5728\u8BFB\u53D6\u56FE\u7247\u8BBE\u7F6E\u2026": "Loading image settings\u2026"
@@ -1299,6 +1312,10 @@ var EN = Object.freeze({
1299
1312
  "\u5F53\u524D\u7248\u672C": "Current version",
1300
1313
  "DSH-IM \u66F4\u65B0": "DSH-IM update",
1301
1314
  "\u68C0\u67E5\u66F4\u65B0": "Check for updates",
1315
+ "DSH \u7248\u672C\u517C\u5BB9\u8BF4\u660E": "DSH version compatibility",
1316
+ "dsh-im 4.25.0 \u652F\u6301\u5230 DSH v0.1.6-alpha.2\u3002": "dsh-im 4.25.0 supports DSH up to v0.1.6-alpha.2.",
1317
+ "dsh-im 4.26.0 \u4EC5\u652F\u6301 DSH v0.1.7-alpha.1\u3002": "dsh-im 4.26.0 only supports DSH v0.1.7-alpha.1.",
1318
+ "\u5347\u7EA7\u5230 dsh-im 4.26.0 \u524D\uFF0C\u8BF7\u5148\u5C06 DSH \u5347\u7EA7\u5230 v0.1.7-alpha.1\uFF1B\u4F7F\u7528\u65E7\u7248 DSH \u8BF7\u4FDD\u7559 dsh-im 4.25.0\u3002": "Before updating to dsh-im 4.26.0, upgrade DSH to v0.1.7-alpha.1. If you use an older DSH version, stay on dsh-im 4.25.0.",
1302
1319
  "\u91CD\u65B0\u68C0\u67E5": "Check again",
1303
1320
  "\u5237\u65B0\u72B6\u6001": "Refresh status",
1304
1321
  "\u624B\u5DE5\u66F4\u65B0": "Manual update",
@@ -1860,6 +1877,19 @@ var EN = Object.freeze({
1860
1877
  "Gateway \u957F\u8FDE\u63A5": "Gateway persistent connection",
1861
1878
  " Socket Mode \u957F\u8FDE\u63A5": " Socket Mode persistent connection",
1862
1879
  "Socket Mode \u957F\u8FDE\u63A5": "Socket Mode persistent connection",
1880
+ " CS API \u957F\u8F6E\u8BE2": " CS API long polling",
1881
+ "CS API \u957F\u8F6E\u8BE2": "CS API long polling",
1882
+ "\u63A5\u5165 Matrix \u673A\u5668\u4EBA": "Connect a Matrix bot",
1883
+ "\u8FDE\u63A5\u4F60\u7684 Matrix homeserver": "Connect your Matrix homeserver",
1884
+ "\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.",
1885
+ "Homeserver \u5730\u5740": "Homeserver URL",
1886
+ "\u8BBF\u95EE\u4EE4\u724C\uFF08\u4E0E\u7528\u6237 ID\u3001\u5BC6\u7801\u4E8C\u9009\u4E00\uFF09": "Access token (or user id + password)",
1887
+ "\u7528\u6237 ID\uFF08\u53EF\u9009\uFF09": "User id (optional)",
1888
+ "\u5BC6\u7801\uFF08\u53EF\u9009\uFF09": "Password (optional)",
1889
+ "\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.",
1890
+ "\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.",
1891
+ "\u4F7F\u7528 homeserver \u4E0E\u51ED\u636E\u63A5\u5165 Matrix \u673A\u5668\u4EBA": "Connect a Matrix bot with the homeserver and credentials",
1892
+ "\u8BBF\u95EE\u4EE4\u724C\u6216\u7528\u6237 ID \u4E0E\u5BC6\u7801": "access token or user id with password",
1863
1893
  "\u63A5\u5165 Telegram \u673A\u5668\u4EBA": "Connect a Telegram bot",
1864
1894
  "\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.",
1865
1895
  "\u586B\u5199 @BotFather \u751F\u6210\u7684 Bot Token": "Enter the Bot Token from @BotFather",
@@ -4033,7 +4063,7 @@ function CredentialActionIcon() {
4033
4063
  );
4034
4064
  }
4035
4065
  function CredentialBindingPanel({
4036
- channel: channel6,
4066
+ channel: channel7,
4037
4067
  identityLabel,
4038
4068
  identityPlaceholder,
4039
4069
  secretLabel,
@@ -4061,7 +4091,7 @@ function CredentialBindingPanel({
4061
4091
  className: "ddt-card dim-surfaceCard dim-credentialPanel",
4062
4092
  "aria-labelledby": headingId
4063
4093
  },
4064
- h2("h3", { id: headingId, className: "dim-credentialTitle" }, `\u624B\u52A8\u63A5\u5165${channel6}\u673A\u5668\u4EBA`),
4094
+ h2("h3", { id: headingId, className: "dim-credentialTitle" }, `\u624B\u52A8\u63A5\u5165${channel7}\u673A\u5668\u4EBA`),
4065
4095
  children,
4066
4096
  h2(
4067
4097
  "form",
@@ -4153,7 +4183,7 @@ function SettingsGlyph() {
4153
4183
  );
4154
4184
  }
4155
4185
  function BotSettingsButton({
4156
- channel: channel6,
4186
+ channel: channel7,
4157
4187
  botId,
4158
4188
  botName,
4159
4189
  connected,
@@ -4169,11 +4199,11 @@ function BotSettingsButton({
4169
4199
  {
4170
4200
  type: "button",
4171
4201
  className: "dim-botSettingsButton",
4172
- "data-delivery-channel": channel6,
4202
+ "data-delivery-channel": channel7,
4173
4203
  "aria-label": "\u66F4\u591A\u673A\u5668\u4EBA\u8BBE\u7F6E",
4174
4204
  onClick: () => openBotSettings?.({
4175
4205
  ...channelSettings && typeof channelSettings === "object" ? channelSettings : {},
4176
- channel: channel6,
4206
+ channel: channel7,
4177
4207
  botId,
4178
4208
  botName,
4179
4209
  connected: Boolean(connected),
@@ -6478,16 +6508,16 @@ var TOKEN_BOT_ENDPOINTS = Object.freeze({
6478
6508
  setAlias: "bot.alias.set",
6479
6509
  setThinkingTraces: "bot.thinking-traces.set"
6480
6510
  });
6481
- function createTokenChannelApi(channel6, connectionSummary, {
6511
+ function createTokenChannelApi(channel7, connectionSummary, {
6482
6512
  normalizeBotExtension = () => ({})
6483
6513
  } = {}) {
6484
- const unwrapRpcResult16 = (result) => {
6514
+ const unwrapRpcResult17 = (result) => {
6485
6515
  if (!isRecord2(result) || typeof result.ok !== "boolean") {
6486
- throw new Error(`${channel6} \u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94`);
6516
+ throw new Error(`${channel7} \u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94`);
6487
6517
  }
6488
6518
  if (!result.ok) {
6489
- const error = new Error(text2(result.error?.message, `${channel6} \u64CD\u4F5C\u5931\u8D25`));
6490
- error.code = text2(result.error?.code, `${channel6.toUpperCase()}_RPC_ERROR`, 80);
6519
+ const error = new Error(text2(result.error?.message, `${channel7} \u64CD\u4F5C\u5931\u8D25`));
6520
+ error.code = text2(result.error?.code, `${channel7.toUpperCase()}_RPC_ERROR`, 80);
6491
6521
  Object.assign(error, diagnosticFields(result.error));
6492
6522
  throw error;
6493
6523
  }
@@ -6511,30 +6541,30 @@ function createTokenChannelApi(channel6, connectionSummary, {
6511
6541
  ...Object.hasOwn(value, "accessPolicy") ? { accessPolicy: normalizeAccessPolicy(value.accessPolicy) } : {},
6512
6542
  bot: {
6513
6543
  ...normalizeBotAlias(value.bot),
6514
- name: text2(value.bot?.name, `${channel6}\u673A\u5668\u4EBA`, 100),
6544
+ name: text2(value.bot?.name, `${channel7}\u673A\u5668\u4EBA`, 100),
6515
6545
  username: text2(value.bot?.username, "", 100),
6516
6546
  idMasked: text2(value.bot?.idMasked, "\u673A\u5668\u4EBA\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58", 140)
6517
6547
  },
6518
6548
  health: {
6519
6549
  summary: text2(
6520
6550
  value.health?.summary,
6521
- connected ? `${channel6}${connectionSummary}\u8FD0\u884C\u6B63\u5E38` : `${channel6}\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA`
6551
+ connected ? `${channel7}${connectionSummary}\u8FD0\u884C\u6B63\u5E38` : `${channel7}\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA`
6522
6552
  ),
6523
6553
  lastCheckedAt: timestamp2(value.health?.lastCheckedAt)
6524
6554
  },
6525
6555
  lastMessageError: normalizeLastMessageError(value.lastMessageError),
6526
6556
  error: isRecord2(value.error) ? {
6527
6557
  ...diagnosticFields(value.error),
6528
- code: text2(value.error.code, `${channel6.toUpperCase()}_ACCOUNT_ERROR`, 80),
6529
- message: text2(value.error.message, `${channel6}\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA`)
6558
+ code: text2(value.error.code, `${channel7.toUpperCase()}_ACCOUNT_ERROR`, 80),
6559
+ message: text2(value.error.message, `${channel7}\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA`)
6530
6560
  } : null,
6531
6561
  ...isRecord2(extension) ? extension : {}
6532
6562
  };
6533
6563
  };
6534
- const normalizeSnapshot12 = (value) => {
6564
+ const normalizeSnapshot13 = (value) => {
6535
6565
  const source = isRecord2(value?.snapshot) ? value.snapshot : value;
6536
6566
  if (!isRecord2(source) || !Array.isArray(source.bots)) {
6537
- throw new Error(`${channel6} \u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u673A\u5668\u4EBA\u5217\u8868`);
6567
+ throw new Error(`${channel7} \u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u673A\u5668\u4EBA\u5217\u8868`);
6538
6568
  }
6539
6569
  const bots = source.bots.map(normalizeBot8).filter(Boolean);
6540
6570
  return {
@@ -6546,12 +6576,12 @@ function createTokenChannelApi(channel6, connectionSummary, {
6546
6576
  ...isRecord2(source.permissions) ? { permissions: source.permissions } : {}
6547
6577
  };
6548
6578
  };
6549
- const presentError16 = (error) => ({
6579
+ const presentError17 = (error) => ({
6550
6580
  ...diagnosticFields(error),
6551
- code: text2(error?.code, `${channel6.toUpperCase()}_ERROR`, 80),
6552
- message: text2(error?.message, `${channel6}\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`)
6581
+ code: text2(error?.code, `${channel7.toUpperCase()}_ERROR`, 80),
6582
+ message: text2(error?.message, `${channel7}\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`)
6553
6583
  });
6554
- return Object.freeze({ unwrapRpcResult: unwrapRpcResult16, normalizeSnapshot: normalizeSnapshot12, presentError: presentError16 });
6584
+ return Object.freeze({ unwrapRpcResult: unwrapRpcResult17, normalizeSnapshot: normalizeSnapshot13, presentError: presentError17 });
6555
6585
  }
6556
6586
 
6557
6587
  // plugin-src/client/channels/discord/api.js
@@ -6594,9 +6624,9 @@ function connectionTestNotice(value) {
6594
6624
  }
6595
6625
  function createTokenChannelSettings(definition) {
6596
6626
  const {
6597
- channel: channel6,
6627
+ channel: channel7,
6598
6628
  endpoints,
6599
- api: api6,
6629
+ api: api7,
6600
6630
  LogoGlyph,
6601
6631
  installStyles,
6602
6632
  pageClass,
@@ -6608,7 +6638,7 @@ function createTokenChannelSettings(definition) {
6608
6638
  platformLabel,
6609
6639
  CredentialPanel = null,
6610
6640
  credentialPayload = ({ secret }) => ({ token: secret }),
6611
- credentialAriaLabel = `\u4F7F\u7528 Bot Token \u63A5\u5165 ${channel6} \u673A\u5668\u4EBA`,
6641
+ credentialAriaLabel = `\u4F7F\u7528 Bot Token \u63A5\u5165 ${channel7} \u673A\u5668\u4EBA`,
6612
6642
  credentialOpenLabel = "\u624B\u52A8\u63A5\u5165",
6613
6643
  credentialCloseLabel = "\u6536\u8D77\u51ED\u636E",
6614
6644
  credentialNoun = "Bot Token",
@@ -6632,7 +6662,7 @@ function createTokenChannelSettings(definition) {
6632
6662
  CollapsibleAccountSection,
6633
6663
  {
6634
6664
  settings: h2(BotSettingsButton, {
6635
- channel: channel6.toLowerCase(),
6665
+ channel: channel7.toLowerCase(),
6636
6666
  botId: account.botId,
6637
6667
  botName: account.bot.name,
6638
6668
  connected: account.connected,
@@ -6794,11 +6824,11 @@ function createTokenChannelSettings(definition) {
6794
6824
  };
6795
6825
  }, []);
6796
6826
  const invoke = React15.useCallback(async (endpoint, payload = {}, signal) => {
6797
- if (typeof rpcCall !== "function") throw new TypeError(`${channel6} \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5`);
6827
+ if (typeof rpcCall !== "function") throw new TypeError(`${channel7} \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5`);
6798
6828
  const operation = !["connection.status", "provision.poll", "provision.begin", "provision.cancel"].includes(endpoint);
6799
6829
  if (operation && mounted.current) setOperationError(null);
6800
6830
  try {
6801
- const value = api6.unwrapRpcResult(await rpcCall(endpoint, payload, signal));
6831
+ const value = api7.unwrapRpcResult(await rpcCall(endpoint, payload, signal));
6802
6832
  if (operation && mounted.current) setOperationError(value?.testMessage?.error ?? value?.warnings?.[0] ?? null);
6803
6833
  return value;
6804
6834
  } catch (error) {
@@ -6811,7 +6841,7 @@ function createTokenChannelSettings(definition) {
6811
6841
  if (workspaceVersion === null) return;
6812
6842
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
6813
6843
  try {
6814
- const snapshot = api6.normalizeSnapshot(await invoke(endpoints.status, {}, signal));
6844
+ const snapshot = api7.normalizeSnapshot(await invoke(endpoints.status, {}, signal));
6815
6845
  if (!mounted.current || signal?.aborted || !workspaceFence.canCommitStatus(workspaceVersion)) return;
6816
6846
  setModel({
6817
6847
  phase: "ready",
@@ -6827,7 +6857,7 @@ function createTokenChannelSettings(definition) {
6827
6857
  setModel((current) => ({
6828
6858
  ...current,
6829
6859
  phase: silent ? current.phase : "error",
6830
- error: api6.presentError(error)
6860
+ error: api7.presentError(error)
6831
6861
  }));
6832
6862
  }
6833
6863
  }
@@ -6854,7 +6884,7 @@ function createTokenChannelSettings(definition) {
6854
6884
  setBusy(true);
6855
6885
  setCredentialError(null);
6856
6886
  try {
6857
- const snapshot = api6.normalizeSnapshot(await invoke(
6887
+ const snapshot = api7.normalizeSnapshot(await invoke(
6858
6888
  endpoints.bindCredentials,
6859
6889
  credentialPayload(values)
6860
6890
  ));
@@ -6872,7 +6902,7 @@ function createTokenChannelSettings(definition) {
6872
6902
  }
6873
6903
  setCredentialOpen(false);
6874
6904
  } catch (error) {
6875
- if (mounted.current) setCredentialError(api6.presentError(error));
6905
+ if (mounted.current) setCredentialError(api7.presentError(error));
6876
6906
  } finally {
6877
6907
  const shouldRefresh = workspaceFence.endMutation();
6878
6908
  if (shouldRefresh && mounted.current) void loadStatus({ silent: true });
@@ -6884,7 +6914,7 @@ function createTokenChannelSettings(definition) {
6884
6914
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
6885
6915
  try {
6886
6916
  const value = await invoke(endpoint, payload);
6887
- const snapshot = api6.normalizeSnapshot(value);
6917
+ const snapshot = api7.normalizeSnapshot(value);
6888
6918
  if (mounted.current && workspaceFence.canCommitMutation(snapshotVersion)) {
6889
6919
  setModel({
6890
6920
  phase: "ready",
@@ -6924,7 +6954,7 @@ function createTokenChannelSettings(definition) {
6924
6954
  { className: "dim-listSection" },
6925
6955
  h2(ChannelListHeading, {
6926
6956
  className: "ddt-listHeading",
6927
- title: `\u5DF2\u63A5\u5165\u7684 ${channel6} \u673A\u5668\u4EBA`,
6957
+ title: `\u5DF2\u63A5\u5165\u7684 ${channel7} \u673A\u5668\u4EBA`,
6928
6958
  connectionLabel
6929
6959
  }),
6930
6960
  h2("ul", { className: "ddt-list dim-botList" }, model.bots.map((account) => h2("li", { key: account.botId }, h2(AccountCard6, {
@@ -6995,7 +7025,7 @@ function createTokenChannelSettings(definition) {
6995
7025
  "section",
6996
7026
  {
6997
7027
  className: `ddt-page ${pageClass} dim-channelPage`,
6998
- "aria-label": `${channel6} \u8BBE\u7F6E`
7028
+ "aria-label": `${channel7} \u8BBE\u7F6E`
6999
7029
  },
7000
7030
  operationError ? h2(ConnectionError, { error: operationError }) : null,
7001
7031
  h2(
@@ -7029,13 +7059,13 @@ function createTokenChannelSettings(definition) {
7029
7059
  model.phase === "loading" ? h2("div", {
7030
7060
  className: "ddt-card ddt-loading dim-surfaceCard dim-loadingView",
7031
7061
  "aria-busy": "true"
7032
- }, h2("div", { className: "ddt-spinner dim-spinner" }), `\u6B63\u5728\u8BFB\u53D6 ${channel6} \u673A\u5668\u4EBA\u72B6\u6001\u2026`) : model.phase === "error" ? h2(
7062
+ }, h2("div", { className: "ddt-spinner dim-spinner" }), `\u6B63\u5728\u8BFB\u53D6 ${channel7} \u673A\u5668\u4EBA\u72B6\u6001\u2026`) : model.phase === "error" ? h2(
7033
7063
  "div",
7034
7064
  { className: "ddt-card dim-surfaceCard" },
7035
7065
  h2(
7036
7066
  "div",
7037
7067
  { className: "ddt-inlineError dim-inlineError" },
7038
- h2("h3", null, `\u65E0\u6CD5\u8BFB\u53D6 ${channel6} \u673A\u5668\u4EBA\u72B6\u6001`),
7068
+ h2("h3", null, `\u65E0\u6CD5\u8BFB\u53D6 ${channel7} \u673A\u5668\u4EBA\u72B6\u6001`),
7039
7069
  h2(ConnectionError, { error: model.error }),
7040
7070
  h2(Button3, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
7041
7071
  )
@@ -7043,7 +7073,7 @@ function createTokenChannelSettings(definition) {
7043
7073
  React15.Fragment,
7044
7074
  null,
7045
7075
  credentialOpen ? CredentialPanel ? h2(CredentialPanel, {
7046
- channel: channel6,
7076
+ channel: channel7,
7047
7077
  permissions: model.permissions,
7048
7078
  busy,
7049
7079
  error: credentialError,
@@ -7058,7 +7088,7 @@ function createTokenChannelSettings(definition) {
7058
7088
  endpoints,
7059
7089
  onAuthorized: bindCredentials
7060
7090
  }) : h2(CredentialBindingPanel, {
7061
- channel: channel6,
7091
+ channel: channel7,
7062
7092
  secretLabel: "Bot Token",
7063
7093
  secretPlaceholder: tokenPlaceholder,
7064
7094
  busy,
@@ -7082,7 +7112,7 @@ function createTokenChannelSettings(definition) {
7082
7112
  "div",
7083
7113
  { className: "ddt-stateLabel dim-stateLabel" },
7084
7114
  h2("span", { className: "ddt-dot dim-stateDot" }),
7085
- h2("span", null, `\u5C1A\u672A\u63A5\u5165 ${channel6} \u673A\u5668\u4EBA`)
7115
+ h2("span", null, `\u5C1A\u672A\u63A5\u5165 ${channel7} \u673A\u5668\u4EBA`)
7086
7116
  ),
7087
7117
  h2("h3", null, emptyTitle),
7088
7118
  h2("p", null, emptyDescription),
@@ -15770,6 +15800,217 @@ function useEmailChannelEnabled(rpcCall) {
15770
15800
  return enabled === true;
15771
15801
  }
15772
15802
 
15803
+ // plugin-src/client/channels/matrix/api.js
15804
+ var MATRIX_RPC_CHANNEL = "/matrix";
15805
+ var MATRIX_ENDPOINTS = TOKEN_BOT_ENDPOINTS;
15806
+ var api6 = createTokenChannelApi("Matrix", " CS API \u957F\u8F6E\u8BE2");
15807
+ var unwrapRpcResult13 = api6.unwrapRpcResult;
15808
+ var normalizeSnapshot12 = api6.normalizeSnapshot;
15809
+ var presentError13 = api6.presentError;
15810
+
15811
+ // plugin-src/client/channels/matrix/index.js
15812
+ var React27 = __toESM(require("react"), 1);
15813
+
15814
+ // plugin-src/client/channels/matrix/styles.js
15815
+ var MATRIX_STYLE_ID = "xmanrui-dsh-im-matrix-settings";
15816
+ var CSS14 = String.raw`
15817
+ .dmt-page { --ddt-accent: #1a8f6f; --ddt-accent-deep: #12654f; --ddt-accent-wash: #eef8f4; }
15818
+ .dmt-avatar { background: linear-gradient(145deg, #fff, #f6faf8); border: 1px solid #e2eae7; }
15819
+ .dmt-avatar svg { display: block; }
15820
+ .dim-logoMatrix { color: white; background: #0dbd8b; }
15821
+ .dim-logoMatrix svg { width: 22px; height: 22px; }
15822
+ .dmt-setup { display: grid; gap: 18px; }
15823
+ .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)); }
15824
+ .dmt-guideCopy { min-width: 0; }
15825
+ .dmt-guideCopy strong { display: block; margin-bottom: 5px; color: var(--dsw-alias-label-primary, #1f2329); font-size: 13px; }
15826
+ .dmt-guideCopy p { margin: 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: 1.6; }
15827
+ .dmt-guideActions { display: flex; align-items: center; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }
15828
+ .dmt-guideActions .ddt-button { white-space: nowrap; }
15829
+ .dmt-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
15830
+ .dmt-fields .dmt-fieldWide { grid-column: 1 / -1; }
15831
+ .dmt-tokenHint { grid-column: 1 / -1; margin: -4px 0 0; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 11px; line-height: 1.55; }
15832
+ @container (max-width: 680px) {
15833
+ .dmt-guide { grid-template-columns: minmax(0, 1fr); }
15834
+ .dmt-guideActions { justify-content: flex-start; }
15835
+ .dmt-fields { grid-template-columns: minmax(0, 1fr); }
15836
+ }
15837
+ `;
15838
+ function installMatrixStyles() {
15839
+ if (typeof document === "undefined") return () => {
15840
+ };
15841
+ const existing = document.querySelector(`style[data-plugin-css="${MATRIX_STYLE_ID}"]`);
15842
+ if (existing) return () => {
15843
+ };
15844
+ const style = document.createElement("style");
15845
+ style.dataset.plugin = "@xmanrui/dsh-im";
15846
+ style.dataset.pluginCss = MATRIX_STYLE_ID;
15847
+ style.textContent = CSS14;
15848
+ document.head.appendChild(style);
15849
+ return () => style.remove();
15850
+ }
15851
+
15852
+ // plugin-src/client/channels/matrix/index.js
15853
+ var MATRIX_USER_ID_PATTERN = /^@[^:@\s]+:[^:@\s]+(?::\d{1,5})?$/u;
15854
+ function validHomeserver(value) {
15855
+ if (!value || value.length > 2048) return false;
15856
+ try {
15857
+ const url = new URL(value);
15858
+ return (url.protocol === "https:" || url.protocol === "http:") && !url.username && !url.password && !url.hash;
15859
+ } catch {
15860
+ return false;
15861
+ }
15862
+ }
15863
+ function MatrixCredentialPanel({ busy, error, onSubmit, onCancel }) {
15864
+ const [homeserver, setHomeserver] = React27.useState("");
15865
+ const [accessToken, setAccessToken] = React27.useState("");
15866
+ const [userId, setUserId] = React27.useState("");
15867
+ const [password, setPassword] = React27.useState("");
15868
+ const headingId = React27.useId();
15869
+ const normalizedHomeserver = homeserver.trim();
15870
+ const normalizedUserId = userId.trim();
15871
+ const tokenMode = Boolean(accessToken.trim());
15872
+ const loginMode = Boolean(normalizedUserId) && Boolean(password);
15873
+ const canSubmit = validHomeserver(normalizedHomeserver) && (tokenMode ? !normalizedUserId && !password && accessToken.trim().length >= 8 : !accessToken.trim() && MATRIX_USER_ID_PATTERN.test(normalizedUserId) && password.length >= 1);
15874
+ const submit = (event) => {
15875
+ event.preventDefault();
15876
+ if (!canSubmit || busy) return;
15877
+ void onSubmit?.(tokenMode ? { homeserver: normalizedHomeserver, accessToken: accessToken.trim() } : {
15878
+ homeserver: normalizedHomeserver,
15879
+ userId: normalizedUserId,
15880
+ password
15881
+ });
15882
+ };
15883
+ return h2(
15884
+ "section",
15885
+ {
15886
+ className: "ddt-card dim-surfaceCard dim-credentialPanel dmt-setup",
15887
+ "aria-labelledby": headingId
15888
+ },
15889
+ h2("h3", { id: headingId, className: "dim-credentialTitle" }, "\u63A5\u5165 Matrix \u673A\u5668\u4EBA"),
15890
+ h2(
15891
+ "div",
15892
+ { className: "dmt-guide" },
15893
+ h2(
15894
+ "div",
15895
+ { className: "dmt-guideCopy" },
15896
+ h2("strong", null, "\u8FDE\u63A5\u4F60\u7684 Matrix homeserver"),
15897
+ 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")
15898
+ )
15899
+ ),
15900
+ h2(
15901
+ "form",
15902
+ { className: "dim-credentialForm dim-credentialFormSingle", onSubmit: submit },
15903
+ h2(
15904
+ "div",
15905
+ { className: "dmt-fields" },
15906
+ h2(
15907
+ "label",
15908
+ { className: "dim-credentialField dmt-fieldWide" },
15909
+ h2("span", null, "Homeserver \u5730\u5740"),
15910
+ h2("input", {
15911
+ type: "url",
15912
+ value: homeserver,
15913
+ onChange: (event) => setHomeserver(event.target.value),
15914
+ placeholder: "https://matrix.example.org",
15915
+ maxLength: 2048,
15916
+ autoCapitalize: "none",
15917
+ autoCorrect: "off",
15918
+ spellCheck: false,
15919
+ disabled: busy,
15920
+ required: true
15921
+ })
15922
+ ),
15923
+ h2(
15924
+ "label",
15925
+ { className: "dim-credentialField dmt-fieldWide" },
15926
+ h2("span", null, "\u8BBF\u95EE\u4EE4\u724C\uFF08\u4E0E\u7528\u6237 ID\u3001\u5BC6\u7801\u4E8C\u9009\u4E00\uFF09"),
15927
+ h2("input", {
15928
+ type: "password",
15929
+ value: accessToken,
15930
+ onChange: (event) => setAccessToken(event.target.value),
15931
+ placeholder: "syt_\u2026",
15932
+ maxLength: 4096,
15933
+ autoCapitalize: "none",
15934
+ autoCorrect: "off",
15935
+ spellCheck: false,
15936
+ autoComplete: "new-password",
15937
+ disabled: busy
15938
+ })
15939
+ ),
15940
+ h2(
15941
+ "label",
15942
+ { className: "dim-credentialField" },
15943
+ h2("span", null, "\u7528\u6237 ID\uFF08\u53EF\u9009\uFF09"),
15944
+ h2("input", {
15945
+ type: "text",
15946
+ value: userId,
15947
+ onChange: (event) => setUserId(event.target.value),
15948
+ placeholder: "@bot:example.org",
15949
+ maxLength: 512,
15950
+ autoCapitalize: "none",
15951
+ autoCorrect: "off",
15952
+ spellCheck: false,
15953
+ disabled: busy
15954
+ })
15955
+ ),
15956
+ h2(
15957
+ "label",
15958
+ { className: "dim-credentialField" },
15959
+ h2("span", null, "\u5BC6\u7801\uFF08\u53EF\u9009\uFF09"),
15960
+ h2("input", {
15961
+ type: "password",
15962
+ value: password,
15963
+ onChange: (event) => setPassword(event.target.value),
15964
+ maxLength: 1024,
15965
+ autoComplete: "new-password",
15966
+ disabled: busy
15967
+ })
15968
+ ),
15969
+ 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")
15970
+ ),
15971
+ error ? h2("p", { className: "dim-credentialError", role: "alert" }, error.message ?? String(error)) : null,
15972
+ h2(
15973
+ "div",
15974
+ { className: "ddt-actions dim-viewActions dim-credentialActions" },
15975
+ h2("button", {
15976
+ type: "submit",
15977
+ className: "ddt-button",
15978
+ "data-kind": "primary",
15979
+ disabled: busy || !canSubmit
15980
+ }, busy ? "\u6B63\u5728\u9A8C\u8BC1\u5E76\u8FDE\u63A5\u2026" : "\u9A8C\u8BC1\u5E76\u8FDE\u63A5"),
15981
+ h2("button", {
15982
+ type: "button",
15983
+ className: "ddt-button",
15984
+ onClick: onCancel,
15985
+ disabled: busy
15986
+ }, "\u53D6\u6D88")
15987
+ )
15988
+ )
15989
+ );
15990
+ }
15991
+ var channel6 = createTokenChannelSettings({
15992
+ channel: "Matrix",
15993
+ endpoints: MATRIX_ENDPOINTS,
15994
+ api: api6,
15995
+ LogoGlyph: MatrixLogoGlyph,
15996
+ installStyles: installMatrixStyles,
15997
+ pageClass: "dmt-page",
15998
+ avatarClass: "dmt-avatar",
15999
+ connectionLabel: "CS API \u957F\u8F6E\u8BE2",
16000
+ emptyTitle: "\u63A5\u5165 Matrix \u673A\u5668\u4EBA",
16001
+ 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",
16002
+ platformLabel: "Matrix homeserver",
16003
+ CredentialPanel: MatrixCredentialPanel,
16004
+ credentialPayload: ({ homeserver, accessToken, userId, password }) => ({ homeserver, accessToken, userId, password }),
16005
+ credentialAriaLabel: "\u4F7F\u7528 homeserver \u4E0E\u51ED\u636E\u63A5\u5165 Matrix \u673A\u5668\u4EBA",
16006
+ credentialOpenLabel: "\u63A5\u5165\u673A\u5668\u4EBA",
16007
+ credentialCloseLabel: "\u6536\u8D77\u63A5\u5165",
16008
+ credentialNoun: "\u8BBF\u95EE\u4EE4\u724C\u6216\u7528\u6237 ID \u4E0E\u5BC6\u7801",
16009
+ emptyActionLabel: "\u5F00\u59CB\u63A5\u5165"
16010
+ });
16011
+ var MatrixSettingsTab = channel6.SettingsTab;
16012
+ var MatrixAccountCard = channel6.AccountCard;
16013
+
15773
16014
  // src/channels/shared/interface-language.mjs
15774
16015
  var LANGUAGE_TAG = /^[A-Za-z]{2,8}(?:-[A-Za-z0-9]{1,8})*$/u;
15775
16016
  var HOST_LANGUAGE_SOURCES = Object.freeze(["config", "settings", "mirror"]);
@@ -15833,10 +16074,10 @@ function installInterfaceLanguageMirror(ctx, {
15833
16074
  }
15834
16075
 
15835
16076
  // plugin-src/client/delivery-settings.js
15836
- var React29 = __toESM(require("react"), 1);
16077
+ var React30 = __toESM(require("react"), 1);
15837
16078
 
15838
16079
  // plugin-src/client/access-policy-settings.js
15839
- var React27 = __toESM(require("react"), 1);
16080
+ var React28 = __toESM(require("react"), 1);
15840
16081
  var ACCESS_POLICY_ENDPOINT = "bot.access-policy.set";
15841
16082
  var ACCESS_CHANNEL_DEFINITIONS = Object.freeze({
15842
16083
  weixin: Object.freeze({
@@ -15922,7 +16163,7 @@ function clonePolicy(policy) {
15922
16163
  group: cloneScope(policy.group)
15923
16164
  };
15924
16165
  }
15925
- function unwrapRpcResult13(result) {
16166
+ function unwrapRpcResult14(result) {
15926
16167
  if (result?.ok === true) return result.value;
15927
16168
  if (result?.ok === false) {
15928
16169
  const error = new Error(result.error?.message || "\u8BBF\u95EE\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
@@ -15949,8 +16190,8 @@ function ScenePolicyEditor({
15949
16190
  unsupported = false,
15950
16191
  onChange
15951
16192
  }) {
15952
- const ownerHelpId = React27.useId();
15953
- const emptyAllowlistHelpId = React27.useId();
16193
+ const ownerHelpId = React28.useId();
16194
+ const emptyAllowlistHelpId = React28.useId();
15954
16195
  const allowlist = policy.mode === "allowlist";
15955
16196
  const collectionKey = allowlist ? "users" : "commandPermissionOverrides";
15956
16197
  const branchKey = allowlist ? "allowlist" : "open";
@@ -16002,7 +16243,7 @@ function ScenePolicyEditor({
16002
16243
  h2("strong", null, "\u5F53\u524D\u6E20\u9053\u4E0D\u652F\u6301\u7FA4\u804A"),
16003
16244
  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")
16004
16245
  ) : h2(
16005
- React27.Fragment,
16246
+ React28.Fragment,
16006
16247
  null,
16007
16248
  h2(
16008
16249
  "div",
@@ -16139,20 +16380,20 @@ function ScenePolicyEditor({
16139
16380
  )
16140
16381
  );
16141
16382
  }
16142
- function AccessPolicySettingsPage({ channel: channel6, account, rpcCall, onSaved }) {
16143
- const definition = ACCESS_CHANNEL_DEFINITIONS[channel6];
16383
+ function AccessPolicySettingsPage({ channel: channel7, account, rpcCall, onSaved }) {
16384
+ const definition = ACCESS_CHANNEL_DEFINITIONS[channel7];
16144
16385
  const initialPolicy = normalizeAccessPolicy(account?.accessPolicy);
16145
16386
  const initialKey = JSON.stringify(initialPolicy);
16146
- const [draft, setDraft] = React27.useState(() => clonePolicy(
16387
+ const [draft, setDraft] = React28.useState(() => clonePolicy(
16147
16388
  initialPolicy ?? DEFAULT_ACCESS_POLICY
16148
16389
  ));
16149
- const [saving, setSaving] = React27.useState(false);
16150
- const [feedback, setFeedback] = React27.useState(null);
16151
- React27.useEffect(() => {
16390
+ const [saving, setSaving] = React28.useState(false);
16391
+ const [feedback, setFeedback] = React28.useState(null);
16392
+ React28.useEffect(() => {
16152
16393
  const next = normalizeAccessPolicy(account?.accessPolicy);
16153
16394
  setDraft(clonePolicy(next ?? DEFAULT_ACCESS_POLICY));
16154
16395
  }, [account?.botId, initialKey]);
16155
- React27.useEffect(() => {
16396
+ React28.useEffect(() => {
16156
16397
  setFeedback(null);
16157
16398
  }, [account?.botId]);
16158
16399
  if (!definition) {
@@ -16169,7 +16410,7 @@ function AccessPolicySettingsPage({ channel: channel6, account, rpcCall, onSaved
16169
16410
  try {
16170
16411
  const policy = validateAccessPolicy(draft);
16171
16412
  if (typeof rpcCall !== "function") throw new Error("\u8BBF\u95EE\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
16172
- const value = unwrapRpcResult13(await rpcCall(ACCESS_POLICY_ENDPOINT, {
16413
+ const value = unwrapRpcResult14(await rpcCall(ACCESS_POLICY_ENDPOINT, {
16173
16414
  botId: account.botId,
16174
16415
  policy
16175
16416
  }));
@@ -16243,7 +16484,7 @@ function AccessPolicySettingsPage({ channel: channel6, account, rpcCall, onSaved
16243
16484
  }
16244
16485
 
16245
16486
  // plugin-src/client/channels/feishu/group-settings.js
16246
- var React28 = __toESM(require("react"), 1);
16487
+ var React29 = __toESM(require("react"), 1);
16247
16488
  var GROUP_MESSAGE_PERMISSION_OPERATION2 = FEISHU_REGISTRATION_OPERATIONS.GROUP_MESSAGE_PERMISSION;
16248
16489
  function SettingsButton({ children, kind = "secondary", className = "", ...props }) {
16249
16490
  return h2("button", {
@@ -16304,9 +16545,9 @@ function GroupResponseModeEditor({
16304
16545
  onAuthorize
16305
16546
  }) {
16306
16547
  const current = normalizeGroupResponseMode(value);
16307
- const [saving, setSaving] = React28.useState(false);
16308
- const [authorizing, setAuthorizing] = React28.useState(false);
16309
- const [error, setError] = React28.useState(null);
16548
+ const [saving, setSaving] = React29.useState(false);
16549
+ const [authorizing, setAuthorizing] = React29.useState(false);
16550
+ const [error, setError] = React29.useState(null);
16310
16551
  const change = async (event) => {
16311
16552
  const next = normalizeGroupResponseMode(event.target.value);
16312
16553
  if (next === current || saving || disabled) return;
@@ -16387,8 +16628,8 @@ function GroupResponseModeEditor({
16387
16628
  }
16388
16629
  function GroupTopicReplyEditor({ value = false, disabled = false, onSave }) {
16389
16630
  const current = value === true ? "on" : "off";
16390
- const [saving, setSaving] = React28.useState(false);
16391
- const [error, setError] = React28.useState(null);
16631
+ const [saving, setSaving] = React29.useState(false);
16632
+ const [error, setError] = React29.useState(null);
16392
16633
  const change = async (event) => {
16393
16634
  const next = event.target.value === "on";
16394
16635
  if ((next ? "on" : "off") === current || saving || disabled) return;
@@ -16575,14 +16816,14 @@ function PermissionFlow({ provision, now, busy, botName, onRetry, onCancel, onCl
16575
16816
  );
16576
16817
  }
16577
16818
  function FeishuGroupSettingsPage({ account, rpcCall }) {
16578
- const [settings, setSettings] = React28.useState(() => groupSettingsFrom(account));
16579
- const [refreshing, setRefreshing] = React28.useState(false);
16580
- const [refreshError, setRefreshError] = React28.useState(null);
16581
- const [provision, setProvision] = React28.useState(null);
16582
- const [provisionBusy, setProvisionBusy] = React28.useState(false);
16583
- const [now, setNow] = React28.useState(() => Date.now());
16584
- const mounted = React28.useRef(true);
16585
- React28.useEffect(() => {
16819
+ const [settings, setSettings] = React29.useState(() => groupSettingsFrom(account));
16820
+ const [refreshing, setRefreshing] = React29.useState(false);
16821
+ const [refreshError, setRefreshError] = React29.useState(null);
16822
+ const [provision, setProvision] = React29.useState(null);
16823
+ const [provisionBusy, setProvisionBusy] = React29.useState(false);
16824
+ const [now, setNow] = React29.useState(() => Date.now());
16825
+ const mounted = React29.useRef(true);
16826
+ React29.useEffect(() => {
16586
16827
  setSettings(groupSettingsFrom(account));
16587
16828
  }, [
16588
16829
  account.botId,
@@ -16590,22 +16831,22 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
16590
16831
  account.groupTopicReply,
16591
16832
  account.groupMessagePermissionGranted
16592
16833
  ]);
16593
- React28.useEffect(() => {
16834
+ React29.useEffect(() => {
16594
16835
  mounted.current = true;
16595
16836
  return () => {
16596
16837
  mounted.current = false;
16597
16838
  };
16598
16839
  }, []);
16599
- const invoke = React28.useCallback(async (endpoint, payload = {}, signal) => {
16840
+ const invoke = React29.useCallback(async (endpoint, payload = {}, signal) => {
16600
16841
  if (typeof rpcCall !== "function") throw new Error("\u98DE\u4E66\u7FA4\u804A\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
16601
16842
  return unwrapRpcResult3(await rpcCall(endpoint, payload, signal));
16602
16843
  }, [rpcCall]);
16603
- const applySnapshot = React28.useCallback((value) => {
16844
+ const applySnapshot = React29.useCallback((value) => {
16604
16845
  const result = targetBotFromSnapshot(value, account.botId);
16605
16846
  if (mounted.current) setSettings(groupSettingsFrom(result.bot));
16606
16847
  return result;
16607
16848
  }, [account.botId]);
16608
- const loadSettings = React28.useCallback(async ({ signal, restoreProvisioning = false } = {}) => {
16849
+ const loadSettings = React29.useCallback(async ({ signal, restoreProvisioning = false } = {}) => {
16609
16850
  setRefreshing(true);
16610
16851
  setRefreshError(null);
16611
16852
  try {
@@ -16634,16 +16875,16 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
16634
16875
  if (!signal?.aborted && mounted.current) setRefreshing(false);
16635
16876
  }
16636
16877
  }, [account.botId, applySnapshot, invoke]);
16637
- React28.useEffect(() => {
16878
+ React29.useEffect(() => {
16638
16879
  const controller = new AbortController();
16639
16880
  void loadSettings({ signal: controller.signal, restoreProvisioning: true });
16640
16881
  return () => controller.abort();
16641
16882
  }, [loadSettings]);
16642
- const saveSetting = React28.useCallback(async (endpoint, payload) => {
16883
+ const saveSetting = React29.useCallback(async (endpoint, payload) => {
16643
16884
  const value = await invoke(endpoint, { botId: account.botId, ...payload });
16644
16885
  applySnapshot(value);
16645
16886
  }, [account.botId, applySnapshot, invoke]);
16646
- const startAuthorization = React28.useCallback(async ({ replace = false } = {}) => {
16887
+ const startAuthorization = React29.useCallback(async ({ replace = false } = {}) => {
16647
16888
  if (provisionBusy) return;
16648
16889
  const previousAttemptId = provision?.attemptId;
16649
16890
  setProvisionBusy(true);
@@ -16684,13 +16925,13 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
16684
16925
  if (mounted.current) setProvisionBusy(false);
16685
16926
  }
16686
16927
  }, [account.botId, invoke, provision?.attemptId, provisionBusy]);
16687
- const finishAuthorization = React28.useCallback(async (signal) => {
16928
+ const finishAuthorization = React29.useCallback(async (signal) => {
16688
16929
  const bot = await loadSettings({ signal, restoreProvisioning: false });
16689
16930
  if (signal?.aborted || !mounted.current) return;
16690
16931
  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");
16691
16932
  setProvision(null);
16692
16933
  }, [loadSettings]);
16693
- React28.useEffect(() => {
16934
+ React29.useEffect(() => {
16694
16935
  if (!provision?.attemptId || !["qr", "connecting"].includes(provision.phase) || provision.expired) return void 0;
16695
16936
  const timerHost = globalThis.window ?? globalThis;
16696
16937
  const controller = new AbortController();
@@ -16734,7 +16975,7 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
16734
16975
  timerHost.clearTimeout(timer);
16735
16976
  };
16736
16977
  }, [account.botId, finishAuthorization, invoke, provision]);
16737
- React28.useEffect(() => {
16978
+ React29.useEffect(() => {
16738
16979
  if (!provision?.attemptId || provision.phase !== "qr" || provision.expired) return void 0;
16739
16980
  const timerHost = globalThis.window ?? globalThis;
16740
16981
  const tick = () => {
@@ -16748,7 +16989,7 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
16748
16989
  const timer = timerHost.setInterval(tick, 1e3);
16749
16990
  return () => timerHost.clearInterval(timer);
16750
16991
  }, [provision?.attemptId, provision?.expired, provision?.expiresAt, provision?.phase]);
16751
- const cancelAuthorization = React28.useCallback(async () => {
16992
+ const cancelAuthorization = React29.useCallback(async () => {
16752
16993
  if (!provision?.attemptId || provisionBusy) {
16753
16994
  setProvision(null);
16754
16995
  return;
@@ -16859,8 +17100,8 @@ var FEISHU_BOT_SETTINGS_TABS = Object.freeze([
16859
17100
  ...BOT_SETTINGS_TABS,
16860
17101
  Object.freeze({ id: "group", label: "\u7FA4\u804A" })
16861
17102
  ]);
16862
- function botSettingsTabsForChannel(channel6) {
16863
- return channel6 === "feishu" ? FEISHU_BOT_SETTINGS_TABS : BOT_SETTINGS_TABS;
17103
+ function botSettingsTabsForChannel(channel7) {
17104
+ return channel7 === "feishu" ? FEISHU_BOT_SETTINGS_TABS : BOT_SETTINGS_TABS;
16864
17105
  }
16865
17106
  var CHANNEL_DEFINITIONS = Object.freeze({
16866
17107
  weixin: {
@@ -16948,10 +17189,10 @@ var CHANNEL_DEFINITIONS = Object.freeze({
16948
17189
  fields: { user: [{ key: "chatGuid", label: "Chat GUID", placeholder: "iMessage;+;chat123" }] }
16949
17190
  }
16950
17191
  });
16951
- function presentError13(error, fallback) {
17192
+ function presentError14(error, fallback) {
16952
17193
  return error?.message || fallback;
16953
17194
  }
16954
- function unwrapRpcResult14(result) {
17195
+ function unwrapRpcResult15(result) {
16955
17196
  if (result?.ok === true) return result.value;
16956
17197
  if (result?.ok === false) {
16957
17198
  const error = new Error(result.error?.message || "\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
@@ -17069,13 +17310,13 @@ function TargetForm({
17069
17310
  }) {
17070
17311
  const editing = mode === "edit";
17071
17312
  const initialKind = initialValue?.kind && definition.fields[initialValue.kind] ? initialValue.kind : definition.kinds[0].value;
17072
- const [targetId, setTargetId] = React29.useState(initialValue?.targetId ?? "");
17073
- const [name2, setName] = React29.useState(initialValue?.name ?? "");
17074
- const [kind, setKind] = React29.useState(initialKind);
17075
- const [route, setRoute] = React29.useState(initialValue?.route ?? {});
17076
- const [error, setError] = React29.useState(null);
17077
- const [testing, setTesting] = React29.useState(false);
17078
- const [testState, setTestState] = React29.useState(null);
17313
+ const [targetId, setTargetId] = React30.useState(initialValue?.targetId ?? "");
17314
+ const [name2, setName] = React30.useState(initialValue?.name ?? "");
17315
+ const [kind, setKind] = React30.useState(initialKind);
17316
+ const [route, setRoute] = React30.useState(initialValue?.route ?? {});
17317
+ const [error, setError] = React30.useState(null);
17318
+ const [testing, setTesting] = React30.useState(false);
17319
+ const [testState, setTestState] = React30.useState(null);
17079
17320
  const currentTarget = () => {
17080
17321
  const normalizedRoute = Object.fromEntries(fieldsFor(definition, kind).map((field2) => {
17081
17322
  const raw = String(route[field2.key] ?? "").trim();
@@ -17096,7 +17337,7 @@ function TargetForm({
17096
17337
  ...currentTarget()
17097
17338
  });
17098
17339
  } catch (caught) {
17099
- setError(presentError13(caught, "\u76EE\u6807\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5\u3002"));
17340
+ setError(presentError14(caught, "\u76EE\u6807\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5\u3002"));
17100
17341
  }
17101
17342
  };
17102
17343
  const testTarget = async () => {
@@ -17108,7 +17349,7 @@ function TargetForm({
17108
17349
  await onTest({ kind: target.kind, route: target.route });
17109
17350
  setTestState({ tone: "success", message: "\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\uFF0C\u8BF7\u5230\u76EE\u6807\u4F1A\u8BDD\u786E\u8BA4\u3002" });
17110
17351
  } catch (caught) {
17111
- setTestState({ tone: "error", message: presentError13(caught, "\u6D4B\u8BD5\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
17352
+ setTestState({ tone: "error", message: presentError14(caught, "\u6D4B\u8BD5\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
17112
17353
  } finally {
17113
17354
  setTesting(false);
17114
17355
  }
@@ -17292,7 +17533,7 @@ function TargetSuggestionPicker({
17292
17533
  suggestions.map((suggestion, index) => {
17293
17534
  const identity = routeIdentity(definition, suggestion);
17294
17535
  const added = configured.has(identity);
17295
- return React29.createElement("option", {
17536
+ return React30.createElement("option", {
17296
17537
  key: suggestion.id ?? suggestion.suggestionId ?? `${identity}:${index}`,
17297
17538
  value: String(index),
17298
17539
  disabled: added
@@ -17309,11 +17550,11 @@ function TargetSuggestionPicker({
17309
17550
  );
17310
17551
  }
17311
17552
  function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, onEdit }) {
17312
- const [action, setAction] = React29.useState(null);
17313
- const [testState, setTestState] = React29.useState(null);
17314
- const [syncFeedback, setSyncFeedback] = React29.useState(null);
17315
- const [copyState, setCopyState] = React29.useState(null);
17316
- const [confirmDelete, setConfirmDelete] = React29.useState(false);
17553
+ const [action, setAction] = React30.useState(null);
17554
+ const [testState, setTestState] = React30.useState(null);
17555
+ const [syncFeedback, setSyncFeedback] = React30.useState(null);
17556
+ const [copyState, setCopyState] = React30.useState(null);
17557
+ const [confirmDelete, setConfirmDelete] = React30.useState(false);
17317
17558
  const sessionSync = target.sessionSync ?? { enabled: false, state: "unavailable" };
17318
17559
  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";
17319
17560
  const testTarget = async () => {
@@ -17323,7 +17564,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
17323
17564
  await rpcCall(DELIVERY_ENDPOINTS.test, { botId, targetId: target.targetId });
17324
17565
  setTestState({ tone: "success", message: "\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\uFF0C\u8BF7\u5230\u76EE\u6807\u4F1A\u8BDD\u786E\u8BA4\u3002" });
17325
17566
  } catch (error) {
17326
- setTestState({ tone: "error", message: presentError13(error, "\u6D4B\u8BD5\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
17567
+ setTestState({ tone: "error", message: presentError14(error, "\u6D4B\u8BD5\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
17327
17568
  } finally {
17328
17569
  setAction(null);
17329
17570
  }
@@ -17334,7 +17575,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
17334
17575
  await copyText(JSON.stringify({ botId, targetId: target.targetId }));
17335
17576
  setCopyState("\u5DF2\u590D\u5236\u8C03\u7528\u53C2\u6570");
17336
17577
  } catch (error) {
17337
- setCopyState(presentError13(error, "\u590D\u5236\u5931\u8D25\u3002"));
17578
+ setCopyState(presentError14(error, "\u590D\u5236\u5931\u8D25\u3002"));
17338
17579
  }
17339
17580
  };
17340
17581
  const deleteTarget = async () => {
@@ -17343,7 +17584,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
17343
17584
  await rpcCall(DELIVERY_ENDPOINTS.delete, { botId, targetId: target.targetId });
17344
17585
  await onChanged();
17345
17586
  } catch (error) {
17346
- setTestState({ tone: "error", message: presentError13(error, "\u5220\u9664\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
17587
+ setTestState({ tone: "error", message: presentError14(error, "\u5220\u9664\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002") });
17347
17588
  setAction(null);
17348
17589
  setConfirmDelete(false);
17349
17590
  }
@@ -17361,7 +17602,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
17361
17602
  } catch (error) {
17362
17603
  setSyncFeedback({
17363
17604
  tone: "error",
17364
- 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")
17605
+ 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")
17365
17606
  });
17366
17607
  } finally {
17367
17608
  setAction(null);
@@ -17376,7 +17617,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
17376
17617
  h2(
17377
17618
  "div",
17378
17619
  { className: "dim-targetTitle" },
17379
- React29.createElement("strong", null, target.name || target.targetId),
17620
+ React30.createElement("strong", null, target.name || target.targetId),
17380
17621
  h2("span", null, kindLabel(definition, target.kind))
17381
17622
  ),
17382
17623
  h2("code", null, `targetId: ${target.targetId}`)
@@ -17455,33 +17696,33 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
17455
17696
  );
17456
17697
  }
17457
17698
  function DeliveryTargetSettingsPage({
17458
- channel: channel6,
17699
+ channel: channel7,
17459
17700
  account,
17460
17701
  rpcCall,
17461
17702
  accessRpcCall,
17462
17703
  onBack
17463
17704
  }) {
17464
- const definition = CHANNEL_DEFINITIONS[channel6];
17465
- const [activeTabId, setActiveTabId] = React29.useState(BOT_SETTINGS_TABS[0].id);
17466
- const [phase, setPhase] = React29.useState("loading");
17467
- const [targets, setTargets] = React29.useState([]);
17468
- const [suggestionPhase, setSuggestionPhase] = React29.useState("idle");
17469
- const [suggestions, setSuggestions] = React29.useState([]);
17470
- const [suggestionError, setSuggestionError] = React29.useState(null);
17471
- const [error, setError] = React29.useState(null);
17472
- const [editor, setEditor] = React29.useState(null);
17473
- const [saving, setSaving] = React29.useState(false);
17474
- const [botCopyState, setBotCopyState] = React29.useState(null);
17475
- const [accessPolicy, setAccessPolicy] = React29.useState(account.accessPolicy);
17476
- const mounted = React29.useRef(true);
17477
- React29.useEffect(() => {
17705
+ const definition = CHANNEL_DEFINITIONS[channel7];
17706
+ const [activeTabId, setActiveTabId] = React30.useState(BOT_SETTINGS_TABS[0].id);
17707
+ const [phase, setPhase] = React30.useState("loading");
17708
+ const [targets, setTargets] = React30.useState([]);
17709
+ const [suggestionPhase, setSuggestionPhase] = React30.useState("idle");
17710
+ const [suggestions, setSuggestions] = React30.useState([]);
17711
+ const [suggestionError, setSuggestionError] = React30.useState(null);
17712
+ const [error, setError] = React30.useState(null);
17713
+ const [editor, setEditor] = React30.useState(null);
17714
+ const [saving, setSaving] = React30.useState(false);
17715
+ const [botCopyState, setBotCopyState] = React30.useState(null);
17716
+ const [accessPolicy, setAccessPolicy] = React30.useState(account.accessPolicy);
17717
+ const mounted = React30.useRef(true);
17718
+ React30.useEffect(() => {
17478
17719
  setAccessPolicy(account.accessPolicy);
17479
17720
  }, [account.botId, account.accessPolicy]);
17480
- const invoke = React29.useCallback(async (endpoint, payload = {}, signal) => {
17721
+ const invoke = React30.useCallback(async (endpoint, payload = {}, signal) => {
17481
17722
  if (typeof rpcCall !== "function") throw new Error("\u6295\u9012\u76EE\u6807\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
17482
- return unwrapRpcResult14(await rpcCall(endpoint, payload, signal));
17723
+ return unwrapRpcResult15(await rpcCall(endpoint, payload, signal));
17483
17724
  }, [rpcCall]);
17484
- const loadTargets = React29.useCallback(async ({ signal, silent = false } = {}) => {
17725
+ const loadTargets = React30.useCallback(async ({ signal, silent = false } = {}) => {
17485
17726
  if (!silent) setPhase("loading");
17486
17727
  setError(null);
17487
17728
  try {
@@ -17491,11 +17732,11 @@ function DeliveryTargetSettingsPage({
17491
17732
  setPhase("ready");
17492
17733
  } catch (caught) {
17493
17734
  if (signal?.aborted || caught?.name === "AbortError" || !mounted.current) return;
17494
- setError(presentError13(caught, "\u65E0\u6CD5\u8BFB\u53D6\u6295\u9012\u76EE\u6807\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
17735
+ setError(presentError14(caught, "\u65E0\u6CD5\u8BFB\u53D6\u6295\u9012\u76EE\u6807\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
17495
17736
  setPhase("error");
17496
17737
  }
17497
17738
  }, [account.botId, invoke]);
17498
- const loadSuggestions = React29.useCallback(async () => {
17739
+ const loadSuggestions = React30.useCallback(async () => {
17499
17740
  setSuggestionPhase("loading");
17500
17741
  setSuggestionError(null);
17501
17742
  try {
@@ -17505,11 +17746,11 @@ function DeliveryTargetSettingsPage({
17505
17746
  setSuggestionPhase("ready");
17506
17747
  } catch (caught) {
17507
17748
  if (caught?.name === "AbortError" || !mounted.current) return;
17508
- setSuggestionError(presentError13(caught, "\u65E0\u6CD5\u8BFB\u53D6\u5DF2\u804A\u4F1A\u8BDD\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
17749
+ setSuggestionError(presentError14(caught, "\u65E0\u6CD5\u8BFB\u53D6\u5DF2\u804A\u4F1A\u8BDD\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
17509
17750
  setSuggestionPhase("error");
17510
17751
  }
17511
17752
  }, [account.botId, definition, invoke]);
17512
- React29.useEffect(() => {
17753
+ React30.useEffect(() => {
17513
17754
  mounted.current = true;
17514
17755
  const controller = new AbortController();
17515
17756
  void loadTargets({ signal: controller.signal });
@@ -17577,10 +17818,10 @@ function DeliveryTargetSettingsPage({
17577
17818
  await copyText(account.botId);
17578
17819
  setBotCopyState("\u5DF2\u590D\u5236 Bot ID");
17579
17820
  } catch (caught) {
17580
- setBotCopyState(presentError13(caught, "\u590D\u5236\u5931\u8D25\u3002"));
17821
+ setBotCopyState(presentError14(caught, "\u590D\u5236\u5931\u8D25\u3002"));
17581
17822
  }
17582
17823
  };
17583
- const settingsTabs = botSettingsTabsForChannel(channel6);
17824
+ const settingsTabs = botSettingsTabsForChannel(channel7);
17584
17825
  const activeTab = settingsTabs.find((tab) => tab.id === activeTabId) ?? settingsTabs[0];
17585
17826
  const activeTabDomId = `dim-bot-settings-${activeTab.id}-tab`;
17586
17827
  const activePanelId = `dim-bot-settings-${activeTab.id}-panel`;
@@ -17623,15 +17864,15 @@ function DeliveryTargetSettingsPage({
17623
17864
  "aria-labelledby": activeTabDomId
17624
17865
  },
17625
17866
  activeTab.id === "access" ? h2(AccessPolicySettingsPage, {
17626
- channel: channel6,
17867
+ channel: channel7,
17627
17868
  account: { ...account, accessPolicy },
17628
17869
  rpcCall: accessRpcCall,
17629
17870
  onSaved: setAccessPolicy
17630
- }) : activeTab.id === "group" && channel6 === "feishu" ? h2(FeishuGroupSettingsPage, {
17871
+ }) : activeTab.id === "group" && channel7 === "feishu" ? h2(FeishuGroupSettingsPage, {
17631
17872
  account,
17632
17873
  rpcCall: accessRpcCall
17633
17874
  }) : h2(
17634
- React29.Fragment,
17875
+ React30.Fragment,
17635
17876
  null,
17636
17877
  h2(
17637
17878
  "section",
@@ -17742,7 +17983,7 @@ function DeliveryTargetSettingsPage({
17742
17983
  }
17743
17984
 
17744
17985
  // plugin-src/client/global-settings.js
17745
- var React30 = __toESM(require("react"), 1);
17986
+ var React31 = __toESM(require("react"), 1);
17746
17987
 
17747
17988
  // src/channels/shared/inbound-ttl.mjs
17748
17989
  var DEFAULT_INBOUND_TTL_HOURS = 168;
@@ -17794,10 +18035,10 @@ var GLOBAL_SETTINGS_ENDPOINTS = Object.freeze({
17794
18035
  getImages: "settings.image-input.get",
17795
18036
  setImages: "settings.image-input.set"
17796
18037
  });
17797
- function presentError14(error, fallback) {
18038
+ function presentError15(error, fallback) {
17798
18039
  return error?.message || fallback;
17799
18040
  }
17800
- function unwrapRpcResult15(result) {
18041
+ function unwrapRpcResult16(result) {
17801
18042
  if (result?.ok === true) return result.value;
17802
18043
  if (result?.ok === false) {
17803
18044
  const error = new Error(result.error?.message || "\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
@@ -17827,18 +18068,18 @@ function GlobalButton({ children, kind = "secondary", className = "", ...props }
17827
18068
  }, children);
17828
18069
  }
17829
18070
  function ImageInputSettings({ rpcCall }) {
17830
- const [values, setValues] = React30.useState(DEFAULT_IMAGE_INPUT_SETTINGS);
17831
- const [phase, setPhase] = React30.useState("loading");
17832
- const [error, setError] = React30.useState(null);
17833
- const [saved, setSaved] = React30.useState(false);
17834
- const mounted = React30.useRef(false);
17835
- const saving = React30.useRef(false);
17836
- const id6 = React30.useId();
17837
- const load = React30.useCallback(async (signal) => {
18071
+ const [values, setValues] = React31.useState(DEFAULT_IMAGE_INPUT_SETTINGS);
18072
+ const [phase, setPhase] = React31.useState("loading");
18073
+ const [error, setError] = React31.useState(null);
18074
+ const [saved, setSaved] = React31.useState(false);
18075
+ const mounted = React31.useRef(false);
18076
+ const saving = React31.useRef(false);
18077
+ const id6 = React31.useId();
18078
+ const load = React31.useCallback(async (signal) => {
17838
18079
  setPhase("loading");
17839
18080
  setError(null);
17840
18081
  try {
17841
- const result = unwrapRpcResult15(await rpcCall(GLOBAL_SETTINGS_ENDPOINTS.getImages, {}, signal));
18082
+ const result = unwrapRpcResult16(await rpcCall(GLOBAL_SETTINGS_ENDPOINTS.getImages, {}, signal));
17842
18083
  if (signal?.aborted || !mounted.current) return;
17843
18084
  const settings = normalizeImageInputSettings(result);
17844
18085
  if (!settings) throw new Error("\u901A\u7528\u8BBE\u7F6E\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94\u3002");
@@ -17846,11 +18087,11 @@ function ImageInputSettings({ rpcCall }) {
17846
18087
  setPhase("ready");
17847
18088
  } catch (caught) {
17848
18089
  if (signal?.aborted || !mounted.current) return;
17849
- setError(presentError14(caught, "\u65E0\u6CD5\u8BFB\u53D6\u6216\u4FDD\u5B58\u56FE\u7247\u8BBE\u7F6E\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
18090
+ setError(presentError15(caught, "\u65E0\u6CD5\u8BFB\u53D6\u6216\u4FDD\u5B58\u56FE\u7247\u8BBE\u7F6E\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
17850
18091
  setPhase("error");
17851
18092
  }
17852
18093
  }, [rpcCall]);
17853
- React30.useEffect(() => {
18094
+ React31.useEffect(() => {
17854
18095
  mounted.current = true;
17855
18096
  const controller = new AbortController();
17856
18097
  void load(controller.signal);
@@ -17872,14 +18113,14 @@ function ImageInputSettings({ rpcCall }) {
17872
18113
  setPhase("saving");
17873
18114
  setError(null);
17874
18115
  try {
17875
- const result = unwrapRpcResult15(await rpcCall(GLOBAL_SETTINGS_ENDPOINTS.setImages, settings));
18116
+ const result = unwrapRpcResult16(await rpcCall(GLOBAL_SETTINGS_ENDPOINTS.setImages, settings));
17876
18117
  if (!normalizeImageInputSettings(result)) throw new Error("\u901A\u7528\u8BBE\u7F6E\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94\u3002");
17877
18118
  if (mounted.current) {
17878
18119
  setValues(result);
17879
18120
  setSaved(true);
17880
18121
  }
17881
18122
  } catch (caught) {
17882
- if (mounted.current) setError(presentError14(caught, "\u65E0\u6CD5\u8BFB\u53D6\u6216\u4FDD\u5B58\u56FE\u7247\u8BBE\u7F6E\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
18123
+ if (mounted.current) setError(presentError15(caught, "\u65E0\u6CD5\u8BFB\u53D6\u6216\u4FDD\u5B58\u56FE\u7247\u8BBE\u7F6E\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
17883
18124
  } finally {
17884
18125
  saving.current = false;
17885
18126
  if (mounted.current) setPhase("ready");
@@ -17893,63 +18134,93 @@ function ImageInputSettings({ rpcCall }) {
17893
18134
  ];
17894
18135
  return h2(
17895
18136
  "section",
17896
- { className: "dim-globalSection", "aria-label": "\u56FE\u7247\u8F93\u5165", "aria-busy": phase === "loading" || phase === "saving" },
17897
- h2("h3", null, "\u56FE\u7247\u8F93\u5165"),
17898
- h2("p", null, "\u9002\u7528\u4E8E\u652F\u6301\u56FE\u7247\u7684\u804A\u5929\u6E20\u9053\u3002\u539F\u56FE\u6309\u9644\u4EF6\u4FDD\u7559\u65F6\u957F\u4FDD\u5B58\uFF0C\u53D1\u9001\u7ED9\u6A21\u578B\u7684\u526F\u672C\u4F1A\u81EA\u52A8\u7F29\u653E\u6216\u538B\u7F29\uFF1B\u65E0\u6CD5\u76F4\u63A5\u53D1\u9001\u65F6\u4EA4\u7ED9\u6A21\u578B\u6309\u6587\u4EF6\u5904\u7406\u3002"),
18137
+ { className: "dim-globalSection dim-imageSettings", "aria-label": "\u56FE\u7247\u8F93\u5165", "aria-busy": phase === "loading" || phase === "saving" },
18138
+ h2(
18139
+ "div",
18140
+ { className: "dim-globalHead" },
18141
+ h2(
18142
+ "div",
18143
+ { className: "dim-globalHeadTitle" },
18144
+ h2("h3", null, "\u56FE\u7247\u8F93\u5165"),
18145
+ h2(
18146
+ "div",
18147
+ { className: "dim-globalTtlHelp" },
18148
+ h2("button", {
18149
+ type: "button",
18150
+ className: "dim-channelHelpButton dim-globalTtlHelpButton",
18151
+ "aria-label": "\u67E5\u770B\u56FE\u7247\u8F93\u5165\u8BF4\u660E",
18152
+ "aria-describedby": `${id6}-help`
18153
+ }, h2("span", { "aria-hidden": "true" }, "?")),
18154
+ h2(
18155
+ "div",
18156
+ { id: `${id6}-help`, className: "dim-globalTtlTooltip dim-imageSettingsTooltip", role: "tooltip" },
18157
+ "\u9002\u7528\u4E8E\u652F\u6301\u56FE\u7247\u7684\u804A\u5929\u6E20\u9053\u3002\u539F\u56FE\u6309\u9644\u4EF6\u4FDD\u7559\u65F6\u957F\u4FDD\u5B58\uFF0C\u53D1\u9001\u7ED9\u6A21\u578B\u7684\u526F\u672C\u4F1A\u81EA\u52A8\u7F29\u653E\u6216\u538B\u7F29\uFF1B\u65E0\u6CD5\u76F4\u63A5\u53D1\u9001\u65F6\u4EA4\u7ED9\u6A21\u578B\u6309\u6587\u4EF6\u5904\u7406\u3002"
18158
+ )
18159
+ )
18160
+ )
18161
+ ),
17899
18162
  h2(
17900
18163
  "form",
17901
18164
  { onSubmit: save },
17902
- ...fields.map(([key, label]) => h2(
18165
+ h2(
17903
18166
  "div",
17904
- { className: "dim-globalTtlRow", key },
17905
- h2("label", { htmlFor: `${id6}-${key}` }, label),
17906
- h2("input", {
17907
- id: `${id6}-${key}`,
17908
- className: "dim-globalTtlInput",
17909
- type: "number",
17910
- min: 1,
17911
- step: 1,
17912
- value: values[key],
17913
- disabled: phase !== "ready",
17914
- onChange: (event) => {
17915
- setValues((current) => ({ ...current, [key]: event.target.value }));
17916
- setSaved(false);
17917
- setError(null);
17918
- }
17919
- })
17920
- )),
17921
- h2(GlobalButton, { type: "submit", kind: "primary", disabled: phase !== "ready" }, phase === "saving" ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58\u56FE\u7247\u8BBE\u7F6E"),
17922
- phase === "error" ? h2(GlobalButton, { onClick: () => void load() }, "\u91CD\u8BD5") : null
18167
+ { className: "dim-imageSettingsFields" },
18168
+ ...fields.map(([key, label]) => h2(
18169
+ "div",
18170
+ { className: "dim-imageSettingsField", key },
18171
+ h2("label", { htmlFor: `${id6}-${key}` }, label),
18172
+ h2("input", {
18173
+ id: `${id6}-${key}`,
18174
+ className: "dim-globalTtlInput",
18175
+ type: "number",
18176
+ min: 1,
18177
+ step: 1,
18178
+ value: values[key],
18179
+ disabled: phase !== "ready",
18180
+ onChange: (event) => {
18181
+ setValues((current) => ({ ...current, [key]: event.target.value }));
18182
+ setSaved(false);
18183
+ setError(null);
18184
+ }
18185
+ })
18186
+ ))
18187
+ ),
18188
+ h2(
18189
+ "div",
18190
+ { className: "dim-imageSettingsActions" },
18191
+ h2(GlobalButton, { type: "submit", kind: "primary", className: "dim-globalSaveButton", disabled: phase !== "ready" }, phase === "saving" ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58\u56FE\u7247\u8BBE\u7F6E"),
18192
+ phase === "error" ? h2(GlobalButton, { className: "dim-globalSaveButton", onClick: () => void load() }, "\u91CD\u8BD5") : null
18193
+ )
17923
18194
  ),
17924
- error ? h2("p", { role: "alert" }, error) : null,
17925
- saved ? h2("p", { role: "status" }, "\u5DF2\u4FDD\u5B58") : null,
17926
- phase === "loading" ? h2("p", { role: "status" }, "\u6B63\u5728\u8BFB\u53D6\u56FE\u7247\u8BBE\u7F6E\u2026") : null
18195
+ error ? h2("p", { className: "dim-globalInline dim-imageSettingsFeedback", "data-tone": "error", role: "alert" }, error) : null,
18196
+ saved ? h2("p", { className: "dim-globalInline dim-imageSettingsFeedback", role: "status" }, "\u5DF2\u4FDD\u5B58") : null,
18197
+ phase === "loading" ? h2("p", { className: "dim-globalInline dim-imageSettingsFeedback", role: "status" }, "\u6B63\u5728\u8BFB\u53D6\u56FE\u7247\u8BBE\u7F6E\u2026") : null
17927
18198
  );
17928
18199
  }
17929
18200
  function GlobalSettingsPanel({ rpcCall }) {
17930
- const [phase, setPhase] = React30.useState("loading");
17931
- const [loadError, setLoadError] = React30.useState(null);
17932
- const [ttlInput, setTtlInput] = React30.useState("");
17933
- const [savedTtl, setSavedTtl] = React30.useState(null);
17934
- const [ttlError, setTtlError] = React30.useState(false);
17935
- const [saveError, setSaveError] = React30.useState(null);
17936
- const [saveSucceeded, setSaveSucceeded] = React30.useState(false);
17937
- const [isSaving, setIsSaving] = React30.useState(false);
17938
- const [sweepConfirming, setSweepConfirming] = React30.useState(false);
17939
- const [sweeping, setSweeping] = React30.useState(false);
17940
- const ttlErrorId = React30.useId();
17941
- const ttlHintsId = React30.useId();
17942
- const sweepTriggerId = React30.useId();
17943
- const sweepConfirmId = React30.useId();
17944
- const sweepConfirmTextId = React30.useId();
17945
- const sweepConfirmButtonId = React30.useId();
17946
- const mounted = React30.useRef(true);
17947
- const saving = React30.useRef(false);
17948
- const invoke = React30.useCallback(async (endpoint, payload = {}, signal) => {
18201
+ const [phase, setPhase] = React31.useState("loading");
18202
+ const [loadError, setLoadError] = React31.useState(null);
18203
+ const [ttlInput, setTtlInput] = React31.useState("");
18204
+ const [savedTtl, setSavedTtl] = React31.useState(null);
18205
+ const [ttlError, setTtlError] = React31.useState(false);
18206
+ const [saveError, setSaveError] = React31.useState(null);
18207
+ const [saveSucceeded, setSaveSucceeded] = React31.useState(false);
18208
+ const [isSaving, setIsSaving] = React31.useState(false);
18209
+ const [sweepConfirming, setSweepConfirming] = React31.useState(false);
18210
+ const [sweeping, setSweeping] = React31.useState(false);
18211
+ const ttlErrorId = React31.useId();
18212
+ const ttlHintsId = React31.useId();
18213
+ const sweepTriggerId = React31.useId();
18214
+ const sweepConfirmId = React31.useId();
18215
+ const sweepConfirmTextId = React31.useId();
18216
+ const sweepConfirmButtonId = React31.useId();
18217
+ const mounted = React31.useRef(true);
18218
+ const saving = React31.useRef(false);
18219
+ const invoke = React31.useCallback(async (endpoint, payload = {}, signal) => {
17949
18220
  if (typeof rpcCall !== "function") throw new Error("\u901A\u7528\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
17950
- return unwrapRpcResult15(await rpcCall(endpoint, payload, signal));
18221
+ return unwrapRpcResult16(await rpcCall(endpoint, payload, signal));
17951
18222
  }, [rpcCall]);
17952
- const loadSettings = React30.useCallback(async ({ signal } = {}) => {
18223
+ const loadSettings = React31.useCallback(async ({ signal } = {}) => {
17953
18224
  setPhase("loading");
17954
18225
  setLoadError(null);
17955
18226
  try {
@@ -17969,11 +18240,11 @@ function GlobalSettingsPanel({ rpcCall }) {
17969
18240
  setPhase("ready");
17970
18241
  } catch (caught) {
17971
18242
  if (signal?.aborted || caught?.name === "AbortError" || !mounted.current) return;
17972
- setLoadError(presentError14(caught, "\u65E0\u6CD5\u8BFB\u53D6\u901A\u7528\u8BBE\u7F6E\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
18243
+ setLoadError(presentError15(caught, "\u65E0\u6CD5\u8BFB\u53D6\u901A\u7528\u8BBE\u7F6E\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
17973
18244
  setPhase("error");
17974
18245
  }
17975
18246
  }, [invoke]);
17976
- React30.useEffect(() => {
18247
+ React31.useEffect(() => {
17977
18248
  mounted.current = true;
17978
18249
  const controller = new AbortController();
17979
18250
  void loadSettings({ signal: controller.signal });
@@ -17982,7 +18253,7 @@ function GlobalSettingsPanel({ rpcCall }) {
17982
18253
  controller.abort();
17983
18254
  };
17984
18255
  }, [loadSettings]);
17985
- React30.useEffect(() => {
18256
+ React31.useEffect(() => {
17986
18257
  if (!sweepConfirming) return;
17987
18258
  globalThis.document?.getElementById(sweepConfirmButtonId)?.focus();
17988
18259
  }, [sweepConfirmButtonId, sweepConfirming]);
@@ -18013,7 +18284,7 @@ function GlobalSettingsPanel({ rpcCall }) {
18013
18284
  setPhase("ready");
18014
18285
  } catch (caught) {
18015
18286
  if (mounted.current) {
18016
- setSaveError(presentError14(caught, "\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
18287
+ setSaveError(presentError15(caught, "\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"));
18017
18288
  }
18018
18289
  } finally {
18019
18290
  saving.current = false;
@@ -18290,7 +18561,7 @@ function replacePageLocation(url, location = globalThis.location) {
18290
18561
 
18291
18562
  // plugin-src/client/styles.js
18292
18563
  var IM_STYLE_ID = "xmanrui-dsh-im-settings";
18293
- var CSS14 = String.raw`
18564
+ var CSS15 = String.raw`
18294
18565
  .dim-connectionDiagnostic { min-width: 0; width: 100%; color: var(--dsw-alias-label-secondary, #646a73); overflow-wrap: anywhere; font-size: 13px; line-height: 1.6; }
18295
18566
  .dim-connectionDiagnostic[data-warning="true"] { color: var(--dsw-alias-state-warn-primary, #d97706); }
18296
18567
  .dim-connectionDiagnostic p { margin: 4px 0; }
@@ -18350,7 +18621,9 @@ var CSS14 = String.raw`
18350
18621
  .dim-updateButton:hover:not(:disabled) { border-color: #aeb3bb; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
18351
18622
  .dim-updateButton:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: 2px; }
18352
18623
  .dim-updateButton:disabled { opacity: .55; cursor: default; }
18353
- .dim-updateTrigger { white-space: nowrap; }
18624
+ .dim-updateAction { position: relative; display: inline-flex; flex: none; }
18625
+ .dim-updateTrigger { width: 30px; height: 30px; flex: none; padding: 0; }
18626
+ .dim-updateTrigger svg { display: block; }
18354
18627
  .dim-updateBackdrop { position: fixed; inset: 0; z-index: 1000; display: grid; place-items: center; padding: 24px; background: rgb(15 17 21 / 42%); }
18355
18628
  .dim-updateBackdrop, .dim-updateBackdrop * { box-sizing: border-box; }
18356
18629
  .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; }
@@ -18387,8 +18660,8 @@ var CSS14 = String.raw`
18387
18660
  .dim-githubLink svg { display: block; }
18388
18661
  .dim-githubLink:hover { border-color: #aeb3bb; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
18389
18662
  .dim-githubLink:focus-visible { outline: 2px solid color-mix(in srgb, var(--dim-blue) 70%, white); outline-offset: 2px; }
18390
- .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; }
18391
- .dim-githubAction:hover .dim-githubTooltip, .dim-githubAction:focus-within .dim-githubTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
18663
+ .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; }
18664
+ .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); }
18392
18665
  .dim-generalSettingsAction { position: relative; display: inline-flex; flex: none; }
18393
18666
  .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; }
18394
18667
  .dim-generalSettingsButton svg { display: block; }
@@ -18901,6 +19174,20 @@ var CSS14 = String.raw`
18901
19174
  .dim-generalSettingsTab:focus-visible { outline: 2px solid var(--dim-blue); outline-offset: -2px; border-radius: 5px; }
18902
19175
  .dim-generalSettingsTabPanel { min-width: 0; padding-top: 14px; }
18903
19176
  .dim-globalSection { min-width: 0; padding: 14px 16px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 12px; background: var(--dsw-alias-bg-layer-3, #fff); }
19177
+ .dim-globalSection + .dim-globalSection { margin-top: 12px; }
19178
+ .dim-imageSettings { container-type: inline-size; }
19179
+ .dim-imageSettings .dim-globalHead { position: relative; }
19180
+ .dim-imageSettings .dim-globalTtlHelp { position: static; }
19181
+ .dim-globalTtlTooltip.dim-imageSettingsTooltip { width: min(320px, 100%); max-width: none; color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 17px; white-space: normal; overflow-wrap: anywhere; }
19182
+ .dim-imageSettingsFields { min-width: 0; display: grid; gap: 12px; margin-top: 12px; }
19183
+ .dim-imageSettingsField { min-width: 0; display: grid; grid-template-columns: minmax(0, 220px) minmax(0, 160px); align-items: center; gap: 6px 16px; }
19184
+ .dim-imageSettingsField label { min-width: 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 13px; line-height: 20px; overflow-wrap: anywhere; }
19185
+ .dim-imageSettingsField .dim-globalTtlInput { width: 100%; min-width: 0; }
19186
+ .dim-imageSettingsActions { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
19187
+ .dim-globalInline.dim-imageSettingsFeedback { margin: 10px 0 0; }
19188
+ @container (max-width: 380px) {
19189
+ .dim-imageSettingsField { grid-template-columns: minmax(0, 1fr); }
19190
+ }
18904
19191
  .dim-globalHead { min-width: 0; display: flex; align-items: center; }
18905
19192
  .dim-globalHeadTitle { min-width: 0; display: inline-flex; align-items: center; gap: 6px; }
18906
19193
  .dim-globalHead h3 { min-width: 0; overflow: hidden; margin: 0; color: var(--dsw-alias-label-primary, #1f2329); font-size: 15px; line-height: 22px; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; }
@@ -19010,7 +19297,7 @@ function installImStyles() {
19010
19297
  const style = document.createElement("style");
19011
19298
  style.dataset.plugin = "@xmanrui/dsh-im";
19012
19299
  style.dataset.pluginCss = IM_STYLE_ID;
19013
- style.textContent = CSS14;
19300
+ style.textContent = CSS15;
19014
19301
  document.head.appendChild(style);
19015
19302
  return () => style.remove();
19016
19303
  }
@@ -19027,15 +19314,16 @@ var SESSION_CHANNEL_LABELS = Object.freeze(Object.fromEntries(Object.entries({
19027
19314
  discord: ["Discord", "Discord"],
19028
19315
  whatsapp: ["WhatsApp", "WhatsApp"],
19029
19316
  imessage: ["iMessage", "iMessage"],
19317
+ matrix: ["Matrix", "Matrix"],
19030
19318
  office: ["AI Office", "AI Office"]
19031
- }).map(([channel6, labels]) => [channel6, Object.freeze(labels)])));
19319
+ }).map(([channel7, labels]) => [channel7, Object.freeze(labels)])));
19032
19320
  function parseSessionChannelTitle(title) {
19033
19321
  if (typeof title !== "string") return null;
19034
- for (const [channel6, labels] of Object.entries(SESSION_CHANNEL_LABELS)) {
19322
+ for (const [channel7, labels] of Object.entries(SESSION_CHANNEL_LABELS)) {
19035
19323
  for (const label of labels) {
19036
19324
  const prefix = `${label} \xB7 `;
19037
19325
  if (title.startsWith(prefix) && title.slice(prefix.length).trim()) {
19038
- return { channel: channel6, title: title.slice(prefix.length) };
19326
+ return { channel: channel7, title: title.slice(prefix.length) };
19039
19327
  }
19040
19328
  }
19041
19329
  }
@@ -19054,6 +19342,7 @@ var GLYPHS = Object.freeze({
19054
19342
  discord: [DiscordLogoGlyph, "#5865f2"],
19055
19343
  whatsapp: [WhatsappLogoGlyph, "#25d366"],
19056
19344
  imessage: [IMessageLogoGlyph, "#3478f6"],
19345
+ matrix: [MatrixLogoGlyph, "#1a8f6f"],
19057
19346
  office: [OfficeLogoGlyph, "#f97316"]
19058
19347
  });
19059
19348
  var CHANNEL_ATTR = "data-dsh-im-session-channel";
@@ -19076,8 +19365,8 @@ function titleOf(row) {
19076
19365
  }
19077
19366
  return title?.childNodes.length === 1 && title.firstChild.nodeType === 3 ? title : null;
19078
19367
  }
19079
- function logoUri(document2, channel6) {
19080
- const [Glyph, color] = GLYPHS[channel6];
19368
+ function logoUri(document2, channel7) {
19369
+ const [Glyph, color] = GLYPHS[channel7];
19081
19370
  const render = (node) => {
19082
19371
  if (!["svg", "path"].includes(node.type)) throw new Error("Unsupported channel logo element");
19083
19372
  const element = document2.createElementNS(SVG_NS, node.type);
@@ -19104,7 +19393,7 @@ function createInstallation(document2) {
19104
19393
  let scheduled = false;
19105
19394
  const style = document2.createElement("style");
19106
19395
  style.dataset.pluginCss = "dsh-im-session-channel-logos";
19107
- const uris = Object.fromEntries(Object.keys(GLYPHS).map((channel6) => [channel6, logoUri(document2, channel6)]));
19396
+ const uris = Object.fromEntries(Object.keys(GLYPHS).map((channel7) => [channel7, logoUri(document2, channel7)]));
19108
19397
  style.textContent = `
19109
19398
  ${MARKED}[${TITLE_ATTR}] {
19110
19399
  position: relative;
@@ -19136,7 +19425,7 @@ ${MARKED}[${TITLE_ATTR}]::after {
19136
19425
  text-overflow: ellipsis;
19137
19426
  pointer-events: none;
19138
19427
  }
19139
- ${Object.entries(uris).map(([channel6, uri]) => `[${CHANNEL_ATTR}="${channel6}"] { --dsh-im-session-logo: url("${uri}"); }`).join("\n")}
19428
+ ${Object.entries(uris).map(([channel7, uri]) => `[${CHANNEL_ATTR}="${channel7}"] { --dsh-im-session-logo: url("${uri}"); }`).join("\n")}
19140
19429
  `;
19141
19430
  document2.head.appendChild(style);
19142
19431
  const restore = (title) => {
@@ -19219,12 +19508,12 @@ ${Object.entries(uris).map(([channel6, uri]) => `[${CHANNEL_ATTR}="${channel6}"]
19219
19508
  attributes: true,
19220
19509
  attributeFilter: ["class", "role", "aria-selected", "contenteditable"]
19221
19510
  });
19222
- for (const [channel6, uri] of Object.entries(uris)) {
19511
+ for (const [channel7, uri] of Object.entries(uris)) {
19223
19512
  const image = new view.Image();
19224
19513
  images.push(image);
19225
19514
  image.onload = () => {
19226
19515
  if (closed) return;
19227
- ready.add(channel6);
19516
+ ready.add(channel7);
19228
19517
  collect(document2.body, true);
19229
19518
  };
19230
19519
  image.src = uri;
@@ -19265,7 +19554,7 @@ function installSessionChannelLogos(document2 = globalThis.document) {
19265
19554
  }
19266
19555
 
19267
19556
  // plugin-src/client/update-panel.js
19268
- var React31 = __toESM(require("react"), 1);
19557
+ var React32 = __toESM(require("react"), 1);
19269
19558
  var import_react_dom4 = require("react-dom");
19270
19559
  var import_valid = __toESM(require_valid(), 1);
19271
19560
  var import_rcompare = __toESM(require_rcompare(), 1);
@@ -19312,7 +19601,7 @@ function unwrapSnapshot(result) {
19312
19601
  }
19313
19602
  return value;
19314
19603
  }
19315
- function presentError15(error) {
19604
+ function presentError16(error) {
19316
19605
  const code = error?.rpcError?.code ?? error?.code ?? "";
19317
19606
  const message = error?.rpcError?.message ?? error?.message ?? "";
19318
19607
  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)) {
@@ -19358,11 +19647,11 @@ function manualUpdateCommand(snapshot) {
19358
19647
  return `dsh plugin --profile ${profileArgument} add -w @xmanrui/dsh-im@${version}`;
19359
19648
  }
19360
19649
  function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
19361
- const [copyState, setCopyState] = React31.useState("idle");
19362
- const commandRef = React31.useRef(null);
19363
- const mounted = React31.useRef(false);
19364
- const copying = React31.useRef(false);
19365
- React31.useEffect(() => {
19650
+ const [copyState, setCopyState] = React32.useState("idle");
19651
+ const commandRef = React32.useRef(null);
19652
+ const mounted = React32.useRef(false);
19653
+ const copying = React32.useRef(false);
19654
+ React32.useEffect(() => {
19366
19655
  mounted.current = true;
19367
19656
  return () => {
19368
19657
  mounted.current = false;
@@ -19394,7 +19683,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
19394
19683
  { className: "dim-updateManual", "aria-label": "\u624B\u5DE5\u66F4\u65B0" },
19395
19684
  h2("h4", { className: "dim-updateManualHeading" }, "\u624B\u5DE5\u66F4\u65B0"),
19396
19685
  command ? h2(
19397
- React31.Fragment,
19686
+ React32.Fragment,
19398
19687
  null,
19399
19688
  h2("p", { className: "dim-updateManualHint" }, "\u81EA\u52A8\u66F4\u65B0\u5931\u8D25\u53EF\u4EE5\u4F7F\u7528\u547D\u4EE4\u66F4\u65B0\uFF1A"),
19400
19689
  h2(
@@ -19430,7 +19719,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
19430
19719
  "aria-hidden": "true",
19431
19720
  focusable: "false"
19432
19721
  }, copyState === "copied" ? h2("path", { d: "m4 10 4 4 8-8" }) : h2(
19433
- React31.Fragment,
19722
+ React32.Fragment,
19434
19723
  null,
19435
19724
  h2("rect", { x: 7, y: 7, width: 10, height: 11, rx: 1.5 }),
19436
19725
  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" })
@@ -19455,10 +19744,10 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
19455
19744
  );
19456
19745
  }
19457
19746
  function UpdateDialog({ children, onClose }) {
19458
- const dialogRef = React31.useRef(null);
19459
- const titleId = React31.useId();
19460
- const descriptionId = React31.useId();
19461
- React31.useEffect(() => {
19747
+ const dialogRef = React32.useRef(null);
19748
+ const titleId = React32.useId();
19749
+ const descriptionId = React32.useId();
19750
+ React32.useEffect(() => {
19462
19751
  const previous = globalThis.document?.activeElement;
19463
19752
  dialogRef.current?.focus?.();
19464
19753
  return () => {
@@ -19516,19 +19805,20 @@ function UpdateDialog({ children, onClose }) {
19516
19805
  return typeof document !== "undefined" && document.body ? (0, import_react_dom4.createPortal)(content, document.body) : content;
19517
19806
  }
19518
19807
  function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19519
- const [snapshot, setSnapshot] = React31.useState(null);
19520
- const [action, setAction] = React31.useState("status");
19521
- const [error, setError] = React31.useState(null);
19522
- const [open, setOpen] = React31.useState(false);
19523
- const [uncertainInstall, setUncertainInstall] = React31.useState(false);
19524
- const mounted = React31.useRef(false);
19525
- const busy = React31.useRef(false);
19526
- const readController = React31.useRef(null);
19527
- const pollReadController = React31.useRef(null);
19528
- const installRequest = React31.useRef(null);
19529
- const onStatusRef = React31.useRef(onStatus);
19808
+ const tooltipId = React32.useId();
19809
+ const [snapshot, setSnapshot] = React32.useState(null);
19810
+ const [action, setAction] = React32.useState("status");
19811
+ const [error, setError] = React32.useState(null);
19812
+ const [open, setOpen] = React32.useState(false);
19813
+ const [uncertainInstall, setUncertainInstall] = React32.useState(false);
19814
+ const mounted = React32.useRef(false);
19815
+ const busy = React32.useRef(false);
19816
+ const readController = React32.useRef(null);
19817
+ const pollReadController = React32.useRef(null);
19818
+ const installRequest = React32.useRef(null);
19819
+ const onStatusRef = React32.useRef(onStatus);
19530
19820
  onStatusRef.current = onStatus;
19531
- const accept = React31.useCallback((next) => {
19821
+ const accept = React32.useCallback((next) => {
19532
19822
  setSnapshot(next);
19533
19823
  onStatusRef.current?.(next);
19534
19824
  }, []);
@@ -19537,7 +19827,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19537
19827
  setUncertainInstall(false);
19538
19828
  accept(next);
19539
19829
  };
19540
- const invoke = React31.useCallback(async (endpoint, payload = {}, signal) => {
19830
+ const invoke = React32.useCallback(async (endpoint, payload = {}, signal) => {
19541
19831
  if (typeof rpcCall !== "function") {
19542
19832
  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");
19543
19833
  unavailable.code = "update-unavailable";
@@ -19545,14 +19835,14 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19545
19835
  }
19546
19836
  return unwrapSnapshot(await rpcCall(endpoint, payload, signal));
19547
19837
  }, [rpcCall]);
19548
- React31.useEffect(() => {
19838
+ React32.useEffect(() => {
19549
19839
  mounted.current = true;
19550
19840
  busy.current = true;
19551
19841
  const controller = new AbortController();
19552
19842
  void invoke("update.status", {}, controller.signal).then((next) => {
19553
19843
  if (!controller.signal.aborted) accept(next);
19554
19844
  }).catch((cause) => {
19555
- if (!controller.signal.aborted) setError(presentError15(cause));
19845
+ if (!controller.signal.aborted) setError(presentError16(cause));
19556
19846
  }).finally(() => {
19557
19847
  if (!controller.signal.aborted) {
19558
19848
  busy.current = false;
@@ -19568,7 +19858,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19568
19858
  const activeJob = ACTIVE_STATES4.has(snapshot?.job?.state);
19569
19859
  const restartRequired = snapshot?.job?.state === "restart-required" || snapshot?.blockedReason === "pending-restart";
19570
19860
  const shouldPoll = activeJob || uncertainInstall;
19571
- React31.useEffect(() => {
19861
+ React32.useEffect(() => {
19572
19862
  if (!shouldPoll) return void 0;
19573
19863
  let controller;
19574
19864
  const scheduler = createPollScheduler({
@@ -19589,7 +19879,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19589
19879
  keepPolling = ACTIVE_STATES4.has(next.job?.state);
19590
19880
  }
19591
19881
  } catch (cause) {
19592
- if (!pendingController.signal.aborted) setError(presentError15(cause));
19882
+ if (!pendingController.signal.aborted) setError(presentError16(cause));
19593
19883
  } finally {
19594
19884
  if (pollReadController.current === pendingController) pollReadController.current = null;
19595
19885
  }
@@ -19620,7 +19910,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19620
19910
  else acceptAuthoritative(next);
19621
19911
  }
19622
19912
  } catch (cause) {
19623
- if (!controller.signal.aborted && mounted.current) setError(presentError15(cause));
19913
+ if (!controller.signal.aborted && mounted.current) setError(presentError16(cause));
19624
19914
  } finally {
19625
19915
  if (!controller.signal.aborted && mounted.current) {
19626
19916
  busy.current = false;
@@ -19646,7 +19936,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19646
19936
  if (mounted.current) acceptAuthoritative(next);
19647
19937
  } catch (cause) {
19648
19938
  if (mounted.current) {
19649
- setError(presentError15(cause));
19939
+ setError(presentError16(cause));
19650
19940
  setUncertainInstall(true);
19651
19941
  }
19652
19942
  } finally {
@@ -19667,20 +19957,46 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19667
19957
  const latestVersion = !activeJob && !restartRequired && !error && snapshot?.checkedAt ? snapshot.latestVersion : null;
19668
19958
  const manualCommand = manualUpdateCommand(snapshot);
19669
19959
  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";
19960
+ const buttonDescription = localizeText(buttonLabel) + (buttonLabel === "\u66F4\u65B0\u81F3" ? ` v${snapshot.latestVersion}` : "");
19670
19961
  return h2(
19671
- React31.Fragment,
19962
+ React32.Fragment,
19672
19963
  null,
19673
- h2("button", {
19674
- type: "button",
19675
- className: "dim-updateButton dim-updateTrigger",
19676
- disabled: busyAction,
19677
- "aria-haspopup": "dialog",
19678
- onClick: () => {
19679
- setOpen(true);
19680
- if (restartRequired) void refreshStatus();
19681
- else if (!snapshot?.canInstall && !activeJob && !uncertainInstall) void check();
19682
- }
19683
- }, buttonLabel, buttonLabel === "\u66F4\u65B0\u81F3" ? ` v${snapshot.latestVersion}` : null),
19964
+ h2(
19965
+ "span",
19966
+ { className: "dim-updateAction" },
19967
+ h2("button", {
19968
+ type: "button",
19969
+ className: "dim-updateButton dim-updateTrigger",
19970
+ disabled: busyAction,
19971
+ "aria-label": buttonDescription,
19972
+ "aria-describedby": tooltipId,
19973
+ "aria-haspopup": "dialog",
19974
+ onClick: () => {
19975
+ setOpen(true);
19976
+ if (restartRequired) void refreshStatus();
19977
+ else if (!snapshot?.canInstall && !activeJob && !uncertainInstall) void check();
19978
+ }
19979
+ }, h2(
19980
+ "svg",
19981
+ {
19982
+ width: 18,
19983
+ height: 18,
19984
+ viewBox: "0 0 24 24",
19985
+ fill: "none",
19986
+ stroke: "currentColor",
19987
+ strokeWidth: 2.3,
19988
+ strokeLinecap: "round",
19989
+ strokeLinejoin: "round",
19990
+ focusable: "false",
19991
+ "aria-hidden": "true"
19992
+ },
19993
+ h2("path", { d: "M3 12a9 9 0 0 1 15.36-6.36L21 8" }),
19994
+ h2("path", { d: "M21 3v5h-5" }),
19995
+ h2("path", { d: "M21 12a9 9 0 0 1-15.36 6.36L3 16" }),
19996
+ h2("path", { d: "M8 16H3v5" })
19997
+ )),
19998
+ h2("span", { id: tooltipId, className: "dim-updateTooltip", role: "tooltip" }, buttonDescription)
19999
+ ),
19684
20000
  open ? h2(
19685
20001
  UpdateDialog,
19686
20002
  { onClose: () => setOpen(false) },
@@ -19693,25 +20009,25 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19693
20009
  h2("dt", null, "\u8FD0\u884C\u7248\u672C"),
19694
20010
  h2("dd", null, `v${snapshot?.runningVersion ?? clientVersion}`),
19695
20011
  snapshot?.installedVersion && snapshot.installedVersion !== snapshot.runningVersion ? h2(
19696
- React31.Fragment,
20012
+ React32.Fragment,
19697
20013
  null,
19698
20014
  h2("dt", null, "\u5DF2\u5B89\u88C5\u7248\u672C"),
19699
20015
  h2("dd", null, `v${snapshot.installedVersion}`)
19700
20016
  ) : null,
19701
20017
  targetVersion ? h2(
19702
- React31.Fragment,
20018
+ React32.Fragment,
19703
20019
  null,
19704
20020
  h2("dt", null, "\u76EE\u6807\u7248\u672C"),
19705
20021
  h2("dd", null, `v${targetVersion}`)
19706
20022
  ) : null,
19707
20023
  latestVersion ? h2(
19708
- React31.Fragment,
20024
+ React32.Fragment,
19709
20025
  null,
19710
20026
  h2("dt", null, "\u6700\u65B0\u7248\u672C"),
19711
20027
  h2("dd", null, `v${latestVersion}`)
19712
20028
  ) : null,
19713
20029
  historicalTargetVersion ? h2(
19714
- React31.Fragment,
20030
+ React32.Fragment,
19715
20031
  null,
19716
20032
  h2("dt", null, "\u4E0A\u6B21\u66F4\u65B0\u76EE\u6807"),
19717
20033
  h2("dd", null, `v${historicalTargetVersion}`)
@@ -19744,6 +20060,18 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19744
20060
  { className: "dim-updateHint" },
19745
20061
  "\u8BF7\u5728\u673A\u5668\u4EBA\u7A7A\u95F2\u65F6\u5B89\u88C5\uFF1B\u5B89\u88C5\u4F1A\u4FEE\u6539\u5F53\u524D profile \u7684\u4F9D\u8D56\uFF0C\u5B8C\u6210\u540E\u9700\u624B\u52A8\u91CD\u542F\u3002"
19746
20062
  ) : null,
20063
+ h2(
20064
+ "aside",
20065
+ { className: "dim-updateHint", "aria-label": "DSH \u7248\u672C\u517C\u5BB9\u8BF4\u660E" },
20066
+ h2("strong", null, "DSH \u7248\u672C\u517C\u5BB9\u8BF4\u660E"),
20067
+ h2("p", { className: "dim-updateManualHint" }, "dsh-im 4.25.0 \u652F\u6301\u5230 DSH v0.1.6-alpha.2\u3002"),
20068
+ h2("p", { className: "dim-updateManualHint" }, "dsh-im 4.26.0 \u4EC5\u652F\u6301 DSH v0.1.7-alpha.1\u3002"),
20069
+ h2(
20070
+ "p",
20071
+ { className: "dim-updateManualHint" },
20072
+ "\u5347\u7EA7\u5230 dsh-im 4.26.0 \u524D\uFF0C\u8BF7\u5148\u5C06 DSH \u5347\u7EA7\u5230 v0.1.7-alpha.1\uFF1B\u4F7F\u7528\u65E7\u7248 DSH \u8BF7\u4FDD\u7559 dsh-im 4.25.0\u3002"
20073
+ )
20074
+ ),
19747
20075
  h2(ManualUpdateCommand, {
19748
20076
  key: manualCommand ?? "unavailable",
19749
20077
  command: manualCommand,
@@ -19780,8 +20108,8 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19780
20108
  }
19781
20109
 
19782
20110
  // plugin-src/client/panel-error-boundary.js
19783
- var React32 = __toESM(require("react"), 1);
19784
- var IMPanelErrorBoundary = class extends React32.Component {
20111
+ var React33 = __toESM(require("react"), 1);
20112
+ var IMPanelErrorBoundary = class extends React33.Component {
19785
20113
  state = { failed: false };
19786
20114
  static getDerivedStateFromError() {
19787
20115
  return { failed: true };
@@ -19825,6 +20153,7 @@ var CHANNELS = Object.freeze([
19825
20153
  { id: "wecomApp", label: "\u4F01\u4E1A\u5FAE\u4FE1\u5E94\u7528", note: "\uFF08\u5B9E\u9A8C\u529F\u80FD\uFF09" },
19826
20154
  { id: "imessage", label: "iMessage", note: "\uFF08\u5B9E\u9A8C\u529F\u80FD\uFF09" },
19827
20155
  { id: "email", label: "\u90AE\u7BB1", note: "\uFF08\u5B9E\u9A8C\u529F\u80FD\uFF09" },
20156
+ { id: "matrix", label: "Matrix", note: "\uFF08\u5B9E\u9A8C\u529F\u80FD\uFF09" },
19828
20157
  { id: "office", label: "AI Office", note: "\uFF08\u5B9E\u9A8C\u529F\u80FD\uFF09" }
19829
20158
  ]);
19830
20159
  function WeixinLogo() {
@@ -19899,6 +20228,13 @@ function EmailLogo() {
19899
20228
  h2(EmailLogoGlyph)
19900
20229
  );
19901
20230
  }
20231
+ function MatrixLogo() {
20232
+ return h2(
20233
+ "span",
20234
+ { className: "dim-logo dim-logoMatrix", "aria-hidden": "true" },
20235
+ h2(MatrixLogoGlyph)
20236
+ );
20237
+ }
19902
20238
  function OfficeLogo() {
19903
20239
  return h2(
19904
20240
  "span",
@@ -19906,19 +20242,20 @@ function OfficeLogo() {
19906
20242
  h2(OfficeLogoGlyph)
19907
20243
  );
19908
20244
  }
19909
- function ChannelLogo({ channel: channel6 }) {
19910
- if (channel6 === "weixin") return h2(WeixinLogo);
19911
- if (channel6 === "feishu") return h2(FeishuLogo);
19912
- if (channel6 === "dingtalk") return h2(DingtalkLogo);
19913
- if (channel6 === "wecom") return h2(WecomLogo);
19914
- if (channel6 === "wecomApp") return h2(WecomAppLogo);
19915
- if (channel6 === "qq") return h2(QqLogo);
19916
- if (channel6 === "slack") return h2(SlackLogo);
19917
- if (channel6 === "telegram") return h2(TelegramLogo);
19918
- if (channel6 === "discord") return h2(DiscordLogo);
19919
- if (channel6 === "whatsapp") return h2(WhatsappLogo);
19920
- if (channel6 === "imessage") return h2(IMessageLogo);
19921
- if (channel6 === "email") return h2(EmailLogo);
20245
+ function ChannelLogo({ channel: channel7 }) {
20246
+ if (channel7 === "weixin") return h2(WeixinLogo);
20247
+ if (channel7 === "feishu") return h2(FeishuLogo);
20248
+ if (channel7 === "dingtalk") return h2(DingtalkLogo);
20249
+ if (channel7 === "wecom") return h2(WecomLogo);
20250
+ if (channel7 === "wecomApp") return h2(WecomAppLogo);
20251
+ if (channel7 === "qq") return h2(QqLogo);
20252
+ if (channel7 === "slack") return h2(SlackLogo);
20253
+ if (channel7 === "telegram") return h2(TelegramLogo);
20254
+ if (channel7 === "discord") return h2(DiscordLogo);
20255
+ if (channel7 === "whatsapp") return h2(WhatsappLogo);
20256
+ if (channel7 === "imessage") return h2(IMessageLogo);
20257
+ if (channel7 === "email") return h2(EmailLogo);
20258
+ if (channel7 === "matrix") return h2(MatrixLogo);
19922
20259
  return h2(OfficeLogo);
19923
20260
  }
19924
20261
  function LoopbackRecoveryNotice({ recovery, onNavigate = replacePageLocation }) {
@@ -19948,6 +20285,7 @@ function IMSettingsTab({
19948
20285
  feishuRpcCall,
19949
20286
  imessageRpcCall,
19950
20287
  emailRpcCall,
20288
+ matrixRpcCall,
19951
20289
  qqRpcCall,
19952
20290
  slackRpcCall,
19953
20291
  telegramRpcCall,
@@ -19964,28 +20302,28 @@ function IMSettingsTab({
19964
20302
  browserLocation = globalThis.location,
19965
20303
  navigateToRecoveryUrl = replacePageLocation
19966
20304
  }) {
19967
- const [selected, setSelected] = React33.useState(() => preferredSectionId === GLOBAL_SETTINGS_TAB_ID || CHANNELS.some((channel6) => channel6.id === preferredSectionId) ? preferredSectionId : "weixin");
19968
- const [loopbackRecovery, setLoopbackRecovery] = React33.useState(null);
19969
- const [runningVersion, setRunningVersion] = React33.useState(IM_PLUGIN_VERSION);
19970
- const [deliverySettings, setDeliverySettings] = React33.useState(null);
20305
+ const [selected, setSelected] = React34.useState(() => preferredSectionId === GLOBAL_SETTINGS_TAB_ID || CHANNELS.some((channel7) => channel7.id === preferredSectionId) ? preferredSectionId : "weixin");
20306
+ const [loopbackRecovery, setLoopbackRecovery] = React34.useState(null);
20307
+ const [runningVersion, setRunningVersion] = React34.useState(IM_PLUGIN_VERSION);
20308
+ const [deliverySettings, setDeliverySettings] = React34.useState(null);
19971
20309
  const emailEnabled = useEmailChannelEnabled(emailRpcCall);
19972
- const visibleChannels = React33.useMemo(
19973
- () => CHANNELS.filter((channel6) => channel6.id !== "email" || emailEnabled),
20310
+ const visibleChannels = React34.useMemo(
20311
+ () => CHANNELS.filter((channel7) => channel7.id !== "email" || emailEnabled),
19974
20312
  [emailEnabled]
19975
20313
  );
19976
- const githubTooltipId = React33.useId();
19977
- const generalSettingsTooltipId = React33.useId();
20314
+ const githubTooltipId = React34.useId();
20315
+ const generalSettingsTooltipId = React34.useId();
19978
20316
  const globalSettingsSelected = selected === GLOBAL_SETTINGS_TAB_ID;
19979
- const active = visibleChannels.find((channel6) => channel6.id === selected) ?? visibleChannels[0];
20317
+ const active = visibleChannels.find((channel7) => channel7.id === selected) ?? visibleChannels[0];
19980
20318
  const activeTabId = globalSettingsSelected ? "dim-general-settings-trigger" : `dim-tab-${active.id}`;
19981
20319
  const activePanelId = globalSettingsSelected ? `dim-panel-${GLOBAL_SETTINGS_TAB_ID}` : `dim-panel-${active.id}`;
19982
- const reportLoopbackRecovery = React33.useCallback((recovery) => {
20320
+ const reportLoopbackRecovery = React34.useCallback((recovery) => {
19983
20321
  setLoopbackRecovery((current) => current?.url === recovery.url ? current : recovery);
19984
20322
  }, []);
19985
- const reportUpdateStatus = React33.useCallback((snapshot) => {
20323
+ const reportUpdateStatus = React34.useCallback((snapshot) => {
19986
20324
  setRunningVersion(snapshot.runningVersion);
19987
20325
  }, []);
19988
- const rpcCalls = React33.useMemo(() => createLoopbackAwareRpcCalls({
20326
+ const rpcCalls = React34.useMemo(() => createLoopbackAwareRpcCalls({
19989
20327
  dingtalkRpcCall,
19990
20328
  discordRpcCall,
19991
20329
  feishuRpcCall,
@@ -20001,7 +20339,8 @@ function IMSettingsTab({
20001
20339
  deliveryRpcCall,
20002
20340
  globalSettingsRpcCall,
20003
20341
  imessageRpcCall,
20004
- emailRpcCall
20342
+ emailRpcCall,
20343
+ matrixRpcCall
20005
20344
  }, {
20006
20345
  location: browserLocation,
20007
20346
  onRecovery: reportLoopbackRecovery
@@ -20014,6 +20353,7 @@ function IMSettingsTab({
20014
20353
  globalSettingsRpcCall,
20015
20354
  imessageRpcCall,
20016
20355
  emailRpcCall,
20356
+ matrixRpcCall,
20017
20357
  officeRpcCall,
20018
20358
  qqRpcCall,
20019
20359
  reportLoopbackRecovery,
@@ -20025,7 +20365,7 @@ function IMSettingsTab({
20025
20365
  weixinRpcCall,
20026
20366
  whatsappRpcCall
20027
20367
  ]);
20028
- const botSettingsContext = React33.useMemo(() => Object.freeze({
20368
+ const botSettingsContext = React34.useMemo(() => Object.freeze({
20029
20369
  openBotSettings: setDeliverySettings
20030
20370
  }), []);
20031
20371
  return h2(
@@ -20116,27 +20456,27 @@ function IMSettingsTab({
20116
20456
  h2(
20117
20457
  "nav",
20118
20458
  { className: "dim-rail", role: "tablist", "aria-label": "IM \u8BBE\u7F6E\u5BFC\u822A" },
20119
- visibleChannels.map((channel6) => h2(
20459
+ visibleChannels.map((channel7) => h2(
20120
20460
  "button",
20121
20461
  {
20122
- key: channel6.id,
20462
+ key: channel7.id,
20123
20463
  type: "button",
20124
20464
  role: "tab",
20125
- id: `dim-tab-${channel6.id}`,
20465
+ id: `dim-tab-${channel7.id}`,
20126
20466
  className: "dim-channel",
20127
- "aria-selected": !globalSettingsSelected && channel6.id === active.id,
20128
- "aria-controls": `dim-panel-${channel6.id}`,
20467
+ "aria-selected": !globalSettingsSelected && channel7.id === active.id,
20468
+ "aria-controls": `dim-panel-${channel7.id}`,
20129
20469
  onClick: () => {
20130
- setSelected(channel6.id);
20470
+ setSelected(channel7.id);
20131
20471
  setDeliverySettings(null);
20132
20472
  }
20133
20473
  },
20134
- h2(ChannelLogo, { channel: channel6.id }),
20474
+ h2(ChannelLogo, { channel: channel7.id }),
20135
20475
  h2(
20136
20476
  "span",
20137
20477
  { className: "dim-channelCopy" },
20138
- h2("strong", null, channel6.label),
20139
- channel6.note ? h2("small", { className: "dim-channelNote" }, channel6.note) : null
20478
+ h2("strong", null, channel7.label),
20479
+ channel7.note ? h2("small", { className: "dim-channelNote" }, channel7.note) : null
20140
20480
  )
20141
20481
  ))
20142
20482
  ),
@@ -20162,7 +20502,7 @@ function IMSettingsTab({
20162
20502
  rpcCall: rpcCalls.deliveryRpcCall,
20163
20503
  accessRpcCall: rpcCalls[`${active.id}RpcCall`],
20164
20504
  onBack: () => setDeliverySettings(null)
20165
- }) : 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 })
20505
+ }) : 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 })
20166
20506
  )
20167
20507
  )
20168
20508
  )
@@ -20196,6 +20536,7 @@ function apply(ctx) {
20196
20536
  installWhatsappStyles(),
20197
20537
  installIMessageStyles(),
20198
20538
  installEmailStyles(),
20539
+ installMatrixStyles(),
20199
20540
  installOfficeStyles(),
20200
20541
  installImStyles()
20201
20542
  ];
@@ -20214,6 +20555,7 @@ function apply(ctx) {
20214
20555
  const whatsappRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, WHATSAPP_RPC_CHANNEL, endpoint, payload, signal);
20215
20556
  const imessageRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, IMESSAGE_RPC_CHANNEL, endpoint, payload, signal);
20216
20557
  const emailRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, EMAIL_RPC_CHANNEL, endpoint, payload, signal);
20558
+ const matrixRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, MATRIX_RPC_CHANNEL, endpoint, payload, signal);
20217
20559
  const slackRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, SLACK_RPC_CHANNEL, endpoint, payload, signal);
20218
20560
  const officeRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, OFFICE_RPC_CHANNEL, endpoint, payload, signal);
20219
20561
  const updateRpcCall = (endpoint, payload, signal) => callManagementRpc(ctx.connection, UPDATE_RPC_CHANNEL, endpoint, payload, signal);
@@ -20237,6 +20579,7 @@ function apply(ctx) {
20237
20579
  imessageRpcCall,
20238
20580
  officeRpcCall,
20239
20581
  emailRpcCall,
20582
+ matrixRpcCall,
20240
20583
  updateRpcCall,
20241
20584
  deliveryRpcCall,
20242
20585
  globalSettingsRpcCall,
@@ -20246,7 +20589,7 @@ function apply(ctx) {
20246
20589
  };
20247
20590
  const localeSnapshot = () => ctx.locale.getLocale?.()?.active ?? "";
20248
20591
  function IMPanel({ preferredSectionId }) {
20249
- React33.useSyncExternalStore(subscribeLocale, localeSnapshot, localeSnapshot);
20592
+ React34.useSyncExternalStore(subscribeLocale, localeSnapshot, localeSnapshot);
20250
20593
  return h2(
20251
20594
  IMPanelErrorBoundary,
20252
20595
  null,