@xmanrui/dsh-im 4.34.1 → 4.35.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 (33) hide show
  1. package/README.en.md +5 -1
  2. package/README.md +5 -1
  3. package/lib/client.js +306 -201
  4. package/lib/index.js +291 -290
  5. package/locale/en.json +1 -0
  6. package/locale/zh.json +1 -0
  7. package/package.json +1 -1
  8. package/plugin-src/client/bot-settings-tabs.js +114 -0
  9. package/plugin-src/client/delivery-settings.js +2 -16
  10. package/plugin-src/client/i18n.js +2 -0
  11. package/plugin-src/client/styles.js +8 -3
  12. package/plugin-src/host/channels/feishu/production.mjs +2 -1
  13. package/plugin-src/host/channels/qq/production.mjs +2 -1
  14. package/plugin-src/host/channels/shared/access-policy-production.mjs +13 -0
  15. package/plugin-src/host/delivery-adapter.mjs +2 -2
  16. package/plugin-src/host/delivery-service.mjs +13 -4
  17. package/plugin-src/host/index.mjs +1 -0
  18. package/plugin-src/host/modern-harness-api.mjs +2 -1
  19. package/src/channels/feishu/bridge.mjs +34 -18
  20. package/src/channels/feishu/feishu-cards.mjs +58 -6
  21. package/src/channels/feishu/feishu-channel.mjs +11 -3
  22. package/src/channels/feishu/feishu-runtime.mjs +19 -4
  23. package/src/channels/feishu/multi-bot-controller.mjs +1 -1
  24. package/src/channels/qq/qq-bridge.mjs +8 -8
  25. package/src/channels/qq/qq-mention.mjs +37 -0
  26. package/src/channels/qq/qq-runtime.mjs +11 -3
  27. package/src/channels/shared/bot-workspace-store.mjs +1 -0
  28. package/src/channels/shared/connection-error.mjs +10 -4
  29. package/src/channels/shared/harness-client.mjs +9 -3
  30. package/src/channels/shared/i18n-en/shared-a.mjs +4 -0
  31. package/src/channels/shared/message-failure.mjs +26 -4
  32. package/src/channels/shared/text-harness-bridge.mjs +2 -2
  33. package/src/channels/shared/workspace-command.mjs +28 -16
package/lib/client.js CHANGED
@@ -590,12 +590,12 @@ async function callManagementRpc(connection, channel7, method, payload, signal)
590
590
  }
591
591
 
592
592
  // plugin-src/client/index.js
593
- var React38 = __toESM(require("react"), 1);
593
+ var React39 = __toESM(require("react"), 1);
594
594
 
595
595
  // package.json
596
596
  var package_default = {
597
597
  name: "@xmanrui/dsh-im",
598
- version: "4.34.1",
598
+ version: "4.35.0",
599
599
  icon: "./assets/logo-plugin-message-link-gradient.webp",
600
600
  description: "\u628A\u5FAE\u4FE1\u3001\u98DE\u4E66\u3001\u4F01\u5FAE\u3001\u9489\u9489\u3001QQ\u3001Telegram\u3001WhatsApp\u3001Slack\u3001Discord\u3001Matrix\u63A5\u5165DSH\u3002 Connect Telegram, WhatsApp, Slack, Discord, Matrix, WeChat, Feishu, WeCom, DingTalk, and QQ to DSH.",
601
601
  keywords: [
@@ -1193,6 +1193,8 @@ var EN = Object.freeze({
1193
1193
  "IM \u9762\u677F\u52A0\u8F7D\u5931\u8D25": "Could not load the IM panel",
1194
1194
  "\u66F4\u591A\u673A\u5668\u4EBA\u8BBE\u7F6E": "More bot settings",
1195
1195
  "\u66F4\u591A\u8BBE\u7F6E": "More settings",
1196
+ "\u5411\u5DE6\u6EDA\u52A8\u8BBE\u7F6E\u9875\u7B7E": "Scroll settings tabs left",
1197
+ "\u5411\u53F3\u6EDA\u52A8\u8BBE\u7F6E\u9875\u7B7E": "Scroll settings tabs right",
1196
1198
  "\u5E38\u7528\u914D\u7F6E": "Common settings",
1197
1199
  "\u673A\u5668\u4EBA\u8BBE\u7F6E": "Bot settings",
1198
1200
  "\u673A\u5668\u4EBA\u8BBE\u7F6E\u9875\u7B7E": "Bot settings tabs",
@@ -16178,7 +16180,7 @@ function installInterfaceLanguageMirror(ctx, {
16178
16180
  }
16179
16181
 
16180
16182
  // plugin-src/client/delivery-settings.js
16181
- var React33 = __toESM(require("react"), 1);
16183
+ var React34 = __toESM(require("react"), 1);
16182
16184
 
16183
16185
  // plugin-src/client/access-policy-settings.js
16184
16186
  var React28 = __toESM(require("react"), 1);
@@ -16596,8 +16598,124 @@ function AccessPolicySettingsPage({ channel: channel7, account, rpcCall, onSaved
16596
16598
  );
16597
16599
  }
16598
16600
 
16599
- // plugin-src/client/channels/feishu/group-settings.js
16601
+ // plugin-src/client/bot-settings-tabs.js
16600
16602
  var React29 = __toESM(require("react"), 1);
16603
+ function revealTab(strip, tab) {
16604
+ if (!strip || !tab) return;
16605
+ const viewport = strip.getBoundingClientRect();
16606
+ const bounds = tab.getBoundingClientRect();
16607
+ if (bounds.left < viewport.left) strip.scrollLeft += bounds.left - viewport.left;
16608
+ else if (bounds.right > viewport.right) strip.scrollLeft += bounds.right - viewport.right;
16609
+ }
16610
+ function BotSettingsTabs({ tabs, activeTabId, onChange }) {
16611
+ const barRef = React29.useRef(null);
16612
+ const stripRef = React29.useRef(null);
16613
+ const listRef = React29.useRef(null);
16614
+ const [scroll, setScroll] = React29.useState({ overflow: false, left: false, right: false });
16615
+ const measure = React29.useCallback(() => {
16616
+ const bar = barRef.current;
16617
+ const strip = stripRef.current;
16618
+ const list = listRef.current;
16619
+ if (!bar || !strip || !list) return;
16620
+ const next = {
16621
+ // Compare against the whole bar, so arrows disappear as soon as all tabs fit.
16622
+ overflow: list.scrollWidth > bar.clientWidth + 1,
16623
+ left: strip.scrollLeft > 1,
16624
+ right: strip.scrollWidth - strip.clientWidth - strip.scrollLeft > 1
16625
+ };
16626
+ setScroll((previous) => Object.keys(next).every((key) => next[key] === previous[key]) ? previous : next);
16627
+ }, []);
16628
+ React29.useEffect(() => {
16629
+ const strip = stripRef.current;
16630
+ if (!strip) return void 0;
16631
+ const refresh = () => {
16632
+ revealTab(strip, strip.querySelector('[aria-selected="true"]'));
16633
+ measure();
16634
+ };
16635
+ refresh();
16636
+ const view = strip.ownerDocument.defaultView;
16637
+ const observer = view.ResizeObserver ? new view.ResizeObserver(refresh) : null;
16638
+ for (const node of [barRef.current, strip, listRef.current]) observer?.observe(node);
16639
+ view.addEventListener("resize", refresh);
16640
+ return () => {
16641
+ observer?.disconnect();
16642
+ view.removeEventListener("resize", refresh);
16643
+ };
16644
+ }, [tabs, activeTabId, scroll.overflow, measure]);
16645
+ const scrollTabs = (direction) => {
16646
+ const strip = stripRef.current;
16647
+ if (!strip) return;
16648
+ strip.scrollLeft += direction * Math.max(80, strip.clientWidth * 0.75);
16649
+ measure();
16650
+ };
16651
+ const handleKeyDown = (event, index) => {
16652
+ let next;
16653
+ if (event.key === "Home") next = 0;
16654
+ else if (event.key === "End") next = tabs.length - 1;
16655
+ else if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
16656
+ next = (index + (event.key === "ArrowRight" ? 1 : -1) + tabs.length) % tabs.length;
16657
+ }
16658
+ if (next === void 0) return;
16659
+ event.preventDefault();
16660
+ onChange(tabs[next].id);
16661
+ const target = stripRef.current?.querySelectorAll('[role="tab"]')[next];
16662
+ target?.focus({ preventScroll: true });
16663
+ revealTab(stripRef.current, target);
16664
+ };
16665
+ const arrow = (direction, label, enabled) => scroll.overflow ? h2("button", {
16666
+ type: "button",
16667
+ className: "dim-botSettingsScroll",
16668
+ "aria-label": label,
16669
+ title: label,
16670
+ disabled: !enabled,
16671
+ onClick: () => scrollTabs(direction)
16672
+ }, h2(
16673
+ "svg",
16674
+ { width: 16, height: 16, viewBox: "0 0 16 16", "aria-hidden": "true" },
16675
+ h2("path", {
16676
+ d: direction < 0 ? "M10 3 5 8l5 5" : "m6 3 5 5-5 5",
16677
+ fill: "none",
16678
+ stroke: "currentColor",
16679
+ strokeWidth: 1.5,
16680
+ strokeLinecap: "round",
16681
+ strokeLinejoin: "round"
16682
+ })
16683
+ )) : null;
16684
+ return h2(
16685
+ "div",
16686
+ { ref: barRef, className: "dim-botSettingsTabsBar" },
16687
+ arrow(-1, "\u5411\u5DE6\u6EDA\u52A8\u8BBE\u7F6E\u9875\u7B7E", scroll.left),
16688
+ h2("nav", {
16689
+ ref: stripRef,
16690
+ className: "dim-botSettingsTabs",
16691
+ role: "tablist",
16692
+ "aria-label": "\u673A\u5668\u4EBA\u8BBE\u7F6E\u9875\u7B7E",
16693
+ onScroll: measure
16694
+ }, h2(
16695
+ "div",
16696
+ { ref: listRef, className: "dim-botSettingsTabsList", role: "presentation" },
16697
+ tabs.map((tab, index) => h2("button", {
16698
+ key: tab.id,
16699
+ id: `dim-bot-settings-${tab.id}-tab`,
16700
+ type: "button",
16701
+ role: "tab",
16702
+ className: "dim-botSettingsTab",
16703
+ "aria-selected": tab.id === activeTabId,
16704
+ "aria-controls": `dim-bot-settings-${tab.id}-panel`,
16705
+ tabIndex: tab.id === activeTabId ? 0 : -1,
16706
+ onClick: (event) => {
16707
+ onChange(tab.id);
16708
+ revealTab(stripRef.current, event?.currentTarget);
16709
+ },
16710
+ onKeyDown: (event) => handleKeyDown(event, index)
16711
+ }, tab.label))
16712
+ )),
16713
+ arrow(1, "\u5411\u53F3\u6EDA\u52A8\u8BBE\u7F6E\u9875\u7B7E", scroll.right)
16714
+ );
16715
+ }
16716
+
16717
+ // plugin-src/client/channels/feishu/group-settings.js
16718
+ var React30 = __toESM(require("react"), 1);
16601
16719
  var GROUP_MESSAGE_PERMISSION_OPERATION2 = FEISHU_REGISTRATION_OPERATIONS.GROUP_MESSAGE_PERMISSION;
16602
16720
  function SettingsButton({ children, kind = "secondary", className = "", ...props }) {
16603
16721
  return h2("button", {
@@ -16658,9 +16776,9 @@ function GroupResponseModeEditor({
16658
16776
  onAuthorize
16659
16777
  }) {
16660
16778
  const current = normalizeGroupResponseMode(value);
16661
- const [saving, setSaving] = React29.useState(false);
16662
- const [authorizing, setAuthorizing] = React29.useState(false);
16663
- const [error, setError] = React29.useState(null);
16779
+ const [saving, setSaving] = React30.useState(false);
16780
+ const [authorizing, setAuthorizing] = React30.useState(false);
16781
+ const [error, setError] = React30.useState(null);
16664
16782
  const change = async (event) => {
16665
16783
  const next = normalizeGroupResponseMode(event.target.value);
16666
16784
  if (next === current || saving || disabled) return;
@@ -16741,8 +16859,8 @@ function GroupResponseModeEditor({
16741
16859
  }
16742
16860
  function MentionTopicReplyEditor({ value = true, disabled = false, onSave }) {
16743
16861
  const current = value === true ? "on" : "off";
16744
- const [saving, setSaving] = React29.useState(false);
16745
- const [error, setError] = React29.useState(null);
16862
+ const [saving, setSaving] = React30.useState(false);
16863
+ const [error, setError] = React30.useState(null);
16746
16864
  const change = async (event) => {
16747
16865
  const next = event.target.value === "on";
16748
16866
  if ((next ? "on" : "off") === current || saving || disabled) return;
@@ -16929,14 +17047,14 @@ function PermissionFlow({ provision, now, busy, botName, onRetry, onCancel, onCl
16929
17047
  );
16930
17048
  }
16931
17049
  function FeishuGroupSettingsPage({ account, rpcCall }) {
16932
- const [settings, setSettings] = React29.useState(() => groupSettingsFrom(account));
16933
- const [refreshing, setRefreshing] = React29.useState(false);
16934
- const [refreshError, setRefreshError] = React29.useState(null);
16935
- const [provision, setProvision] = React29.useState(null);
16936
- const [provisionBusy, setProvisionBusy] = React29.useState(false);
16937
- const [now, setNow] = React29.useState(() => Date.now());
16938
- const mounted = React29.useRef(true);
16939
- React29.useEffect(() => {
17050
+ const [settings, setSettings] = React30.useState(() => groupSettingsFrom(account));
17051
+ const [refreshing, setRefreshing] = React30.useState(false);
17052
+ const [refreshError, setRefreshError] = React30.useState(null);
17053
+ const [provision, setProvision] = React30.useState(null);
17054
+ const [provisionBusy, setProvisionBusy] = React30.useState(false);
17055
+ const [now, setNow] = React30.useState(() => Date.now());
17056
+ const mounted = React30.useRef(true);
17057
+ React30.useEffect(() => {
16940
17058
  setSettings(groupSettingsFrom(account));
16941
17059
  }, [
16942
17060
  account.botId,
@@ -16944,22 +17062,22 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
16944
17062
  account.mentionTopicReply,
16945
17063
  account.groupMessagePermissionGranted
16946
17064
  ]);
16947
- React29.useEffect(() => {
17065
+ React30.useEffect(() => {
16948
17066
  mounted.current = true;
16949
17067
  return () => {
16950
17068
  mounted.current = false;
16951
17069
  };
16952
17070
  }, []);
16953
- const invoke = React29.useCallback(async (endpoint, payload = {}, signal) => {
17071
+ const invoke = React30.useCallback(async (endpoint, payload = {}, signal) => {
16954
17072
  if (typeof rpcCall !== "function") throw new Error("\u98DE\u4E66\u7FA4\u804A\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
16955
17073
  return unwrapRpcResult3(await rpcCall(endpoint, payload, signal));
16956
17074
  }, [rpcCall]);
16957
- const applySnapshot = React29.useCallback((value) => {
17075
+ const applySnapshot = React30.useCallback((value) => {
16958
17076
  const result = targetBotFromSnapshot(value, account.botId);
16959
17077
  if (mounted.current) setSettings(groupSettingsFrom(result.bot));
16960
17078
  return result;
16961
17079
  }, [account.botId]);
16962
- const loadSettings = React29.useCallback(async ({ signal, restoreProvisioning = false } = {}) => {
17080
+ const loadSettings = React30.useCallback(async ({ signal, restoreProvisioning = false } = {}) => {
16963
17081
  setRefreshing(true);
16964
17082
  setRefreshError(null);
16965
17083
  try {
@@ -16988,16 +17106,16 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
16988
17106
  if (!signal?.aborted && mounted.current) setRefreshing(false);
16989
17107
  }
16990
17108
  }, [account.botId, applySnapshot, invoke]);
16991
- React29.useEffect(() => {
17109
+ React30.useEffect(() => {
16992
17110
  const controller = new AbortController();
16993
17111
  void loadSettings({ signal: controller.signal, restoreProvisioning: true });
16994
17112
  return () => controller.abort();
16995
17113
  }, [loadSettings]);
16996
- const saveSetting = React29.useCallback(async (endpoint, payload) => {
17114
+ const saveSetting = React30.useCallback(async (endpoint, payload) => {
16997
17115
  const value = await invoke(endpoint, { botId: account.botId, ...payload });
16998
17116
  applySnapshot(value);
16999
17117
  }, [account.botId, applySnapshot, invoke]);
17000
- const startAuthorization = React29.useCallback(async ({ replace = false } = {}) => {
17118
+ const startAuthorization = React30.useCallback(async ({ replace = false } = {}) => {
17001
17119
  if (provisionBusy) return;
17002
17120
  const previousAttemptId = provision?.attemptId;
17003
17121
  setProvisionBusy(true);
@@ -17038,13 +17156,13 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
17038
17156
  if (mounted.current) setProvisionBusy(false);
17039
17157
  }
17040
17158
  }, [account.botId, invoke, provision?.attemptId, provisionBusy]);
17041
- const finishAuthorization = React29.useCallback(async (signal) => {
17159
+ const finishAuthorization = React30.useCallback(async (signal) => {
17042
17160
  const bot = await loadSettings({ signal, restoreProvisioning: false });
17043
17161
  if (signal?.aborted || !mounted.current) return;
17044
17162
  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");
17045
17163
  setProvision(null);
17046
17164
  }, [loadSettings]);
17047
- React29.useEffect(() => {
17165
+ React30.useEffect(() => {
17048
17166
  if (!provision?.attemptId || !["qr", "connecting"].includes(provision.phase) || provision.expired) return void 0;
17049
17167
  const timerHost = globalThis.window ?? globalThis;
17050
17168
  const controller = new AbortController();
@@ -17088,7 +17206,7 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
17088
17206
  timerHost.clearTimeout(timer);
17089
17207
  };
17090
17208
  }, [account.botId, finishAuthorization, invoke, provision]);
17091
- React29.useEffect(() => {
17209
+ React30.useEffect(() => {
17092
17210
  if (!provision?.attemptId || provision.phase !== "qr" || provision.expired) return void 0;
17093
17211
  const timerHost = globalThis.window ?? globalThis;
17094
17212
  const tick = () => {
@@ -17102,7 +17220,7 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
17102
17220
  const timer = timerHost.setInterval(tick, 1e3);
17103
17221
  return () => timerHost.clearInterval(timer);
17104
17222
  }, [provision?.attemptId, provision?.expired, provision?.expiresAt, provision?.phase]);
17105
- const cancelAuthorization = React29.useCallback(async () => {
17223
+ const cancelAuthorization = React30.useCallback(async () => {
17106
17224
  if (!provision?.attemptId || provisionBusy) {
17107
17225
  setProvision(null);
17108
17226
  return;
@@ -17191,21 +17309,21 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
17191
17309
  }
17192
17310
 
17193
17311
  // plugin-src/client/channels/feishu/voice-settings.js
17194
- var React31 = __toESM(require("react"), 1);
17312
+ var React32 = __toESM(require("react"), 1);
17195
17313
 
17196
17314
  // plugin-src/client/channels/feishu/voice-editor.js
17197
- var React30 = __toESM(require("react"), 1);
17315
+ var React31 = __toESM(require("react"), 1);
17198
17316
  function VoiceEditor({ value = null, disabled = false, onSave }) {
17199
- const [enabled, setEnabled] = React30.useState(value != null);
17200
- const [secretRef, setSecretRef] = React30.useState(value?.secretRef ?? "DASHSCOPE_API_KEY");
17201
- const [asrModel, setAsrModel] = React30.useState(value?.asrModel ?? "qwen3-asr-flash");
17202
- const [ttsModel, setTtsModel] = React30.useState(value?.ttsModel ?? "qwen3-tts-flash");
17203
- const [ttsVoice, setTtsVoice] = React30.useState(value?.ttsVoice ?? "Momo");
17204
- const [saving, setSaving] = React30.useState(false);
17205
- const [error, setError] = React30.useState(null);
17206
- const titleId = React30.useId();
17317
+ const [enabled, setEnabled] = React31.useState(value != null);
17318
+ const [secretRef, setSecretRef] = React31.useState(value?.secretRef ?? "DASHSCOPE_API_KEY");
17319
+ const [asrModel, setAsrModel] = React31.useState(value?.asrModel ?? "qwen3-asr-flash");
17320
+ const [ttsModel, setTtsModel] = React31.useState(value?.ttsModel ?? "qwen3-tts-flash");
17321
+ const [ttsVoice, setTtsVoice] = React31.useState(value?.ttsVoice ?? "Momo");
17322
+ const [saving, setSaving] = React31.useState(false);
17323
+ const [error, setError] = React31.useState(null);
17324
+ const titleId = React31.useId();
17207
17325
  const helpId = `${titleId}-help`;
17208
- React30.useEffect(() => {
17326
+ React31.useEffect(() => {
17209
17327
  setEnabled(value != null);
17210
17328
  if (value) {
17211
17329
  setSecretRef(value.secretRef ?? "DASHSCOPE_API_KEY");
@@ -17319,20 +17437,20 @@ function VoiceEditor({ value = null, disabled = false, onSave }) {
17319
17437
 
17320
17438
  // plugin-src/client/channels/feishu/voice-settings.js
17321
17439
  function FeishuVoiceSettingsPage({ account, rpcCall }) {
17322
- const [voice, setVoice] = React31.useState(null);
17323
- const [phase, setPhase] = React31.useState("loading");
17324
- const [error, setError] = React31.useState(null);
17325
- const mounted = React31.useRef(true);
17326
- const invoke = React31.useCallback(async (endpoint, payload, signal) => {
17440
+ const [voice, setVoice] = React32.useState(null);
17441
+ const [phase, setPhase] = React32.useState("loading");
17442
+ const [error, setError] = React32.useState(null);
17443
+ const mounted = React32.useRef(true);
17444
+ const invoke = React32.useCallback(async (endpoint, payload, signal) => {
17327
17445
  if (typeof rpcCall !== "function") throw new Error("\u98DE\u4E66\u8BED\u97F3\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
17328
17446
  return unwrapRpcResult3(await rpcCall(endpoint, payload, signal));
17329
17447
  }, [rpcCall]);
17330
- const applySnapshot = React31.useCallback((value) => {
17448
+ const applySnapshot = React32.useCallback((value) => {
17331
17449
  const bot = normalizeBotsSnapshot(value).bots.find((entry) => entry.botId === account.botId);
17332
17450
  if (!bot) throw new Error("\u672A\u627E\u5230\u5F53\u524D\u98DE\u4E66\u673A\u5668\u4EBA\uFF0C\u8BF7\u8FD4\u56DE\u5217\u8868\u540E\u91CD\u8BD5\u3002");
17333
17451
  if (mounted.current) setVoice(bot.voice);
17334
17452
  }, [account.botId]);
17335
- const loadSettings = React31.useCallback(async (signal) => {
17453
+ const loadSettings = React32.useCallback(async (signal) => {
17336
17454
  setPhase("loading");
17337
17455
  setError(null);
17338
17456
  try {
@@ -17346,7 +17464,7 @@ function FeishuVoiceSettingsPage({ account, rpcCall }) {
17346
17464
  setPhase("error");
17347
17465
  }
17348
17466
  }, [applySnapshot, invoke]);
17349
- React31.useEffect(() => {
17467
+ React32.useEffect(() => {
17350
17468
  mounted.current = true;
17351
17469
  const controller = new AbortController();
17352
17470
  void loadSettings(controller.signal);
@@ -17385,7 +17503,7 @@ function FeishuVoiceSettingsPage({ account, rpcCall }) {
17385
17503
  }
17386
17504
 
17387
17505
  // plugin-src/client/channels/feishu/slash-panel-settings.js
17388
- var React32 = __toESM(require("react"), 1);
17506
+ var React33 = __toESM(require("react"), 1);
17389
17507
  var MANIFEST_BY_NAME = new Map(SLASH_COMMAND_MANIFEST.map((entry) => [entry.command, entry]));
17390
17508
  var ALL_COMMANDS = Object.freeze(SLASH_COMMAND_MANIFEST.map((entry) => entry.command));
17391
17509
  function PanelButton({ children, disabled = false, onClick, ...props }) {
@@ -17406,30 +17524,30 @@ function commandText(name2) {
17406
17524
  return `/${name2} \u2014 ${entry?.default ?? name2}`;
17407
17525
  }
17408
17526
  function FeishuSlashPanelSettingsPage({ account, rpcCall, onSaved }) {
17409
- const incoming = React32.useMemo(() => normalizeSlashPanelConfig(account.slashPanel), [account.botId, panelSignature(account.slashPanel)]);
17410
- const [mode, setMode] = React32.useState(incoming.mode);
17411
- const [order, setOrder] = React32.useState(() => [...incoming.order]);
17412
- const [pending, setPending] = React32.useState("");
17413
- const [dirty, setDirty] = React32.useState(false);
17414
- const [saving, setSaving] = React32.useState(false);
17415
- const [saved, setSaved] = React32.useState(false);
17416
- const [syncing, setSyncing] = React32.useState(false);
17417
- const [syncTargets, setSyncTargets] = React32.useState(null);
17418
- const [syncNotice, setSyncNotice] = React32.useState(null);
17419
- const [error, setError] = React32.useState(null);
17420
- const mounted = React32.useRef(true);
17421
- React32.useEffect(() => {
17527
+ const incoming = React33.useMemo(() => normalizeSlashPanelConfig(account.slashPanel), [account.botId, panelSignature(account.slashPanel)]);
17528
+ const [mode, setMode] = React33.useState(incoming.mode);
17529
+ const [order, setOrder] = React33.useState(() => [...incoming.order]);
17530
+ const [pending, setPending] = React33.useState("");
17531
+ const [dirty, setDirty] = React33.useState(false);
17532
+ const [saving, setSaving] = React33.useState(false);
17533
+ const [saved, setSaved] = React33.useState(false);
17534
+ const [syncing, setSyncing] = React33.useState(false);
17535
+ const [syncTargets, setSyncTargets] = React33.useState(null);
17536
+ const [syncNotice, setSyncNotice] = React33.useState(null);
17537
+ const [error, setError] = React33.useState(null);
17538
+ const mounted = React33.useRef(true);
17539
+ React33.useEffect(() => {
17422
17540
  mounted.current = true;
17423
17541
  return () => {
17424
17542
  mounted.current = false;
17425
17543
  };
17426
17544
  }, []);
17427
- React32.useEffect(() => {
17545
+ React33.useEffect(() => {
17428
17546
  if (dirty) return;
17429
17547
  setMode(incoming.mode);
17430
17548
  setOrder([...incoming.order]);
17431
17549
  }, [incoming.mode, incoming.order, dirty]);
17432
- const edit = React32.useCallback((update) => {
17550
+ const edit = React33.useCallback((update) => {
17433
17551
  setSaved(false);
17434
17552
  setDirty(true);
17435
17553
  update();
@@ -17566,7 +17684,7 @@ function FeishuSlashPanelSettingsPage({ account, rpcCall, onSaved }) {
17566
17684
  h2("option", { value: SLASH_PANEL_MODES.CUSTOM }, "\u81EA\u5B9A\u4E49\uFF08\u81EA\u5DF1\u6311\u6307\u4EE4\u548C\u987A\u5E8F\uFF09")
17567
17685
  ),
17568
17686
  mode === SLASH_PANEL_MODES.CUSTOM ? h2(
17569
- React32.Fragment,
17687
+ React33.Fragment,
17570
17688
  null,
17571
17689
  order.length === 0 ? h2("p", { className: "dim-feishuGroupHelp" }, "\u5F53\u524D\u6CA1\u6709\u9009\u62E9\u4EFB\u4F55\u6307\u4EE4\uFF0C\u4FDD\u5B58\u540E\u300C/\u300D\u9762\u677F\u4F1A\u53D8\u6210\u7A7A\u7684\u3002") : h2(
17572
17690
  "ul",
@@ -17922,13 +18040,13 @@ function TargetForm({
17922
18040
  }) {
17923
18041
  const editing = mode === "edit";
17924
18042
  const initialKind = initialValue?.kind && definition.fields[initialValue.kind] ? initialValue.kind : definition.kinds[0].value;
17925
- const [targetId, setTargetId] = React33.useState(initialValue?.targetId ?? "");
17926
- const [name2, setName] = React33.useState(initialValue?.name ?? "");
17927
- const [kind, setKind] = React33.useState(initialKind);
17928
- const [route, setRoute] = React33.useState(initialValue?.route ?? {});
17929
- const [error, setError] = React33.useState(null);
17930
- const [testing, setTesting] = React33.useState(false);
17931
- const [testState, setTestState] = React33.useState(null);
18043
+ const [targetId, setTargetId] = React34.useState(initialValue?.targetId ?? "");
18044
+ const [name2, setName] = React34.useState(initialValue?.name ?? "");
18045
+ const [kind, setKind] = React34.useState(initialKind);
18046
+ const [route, setRoute] = React34.useState(initialValue?.route ?? {});
18047
+ const [error, setError] = React34.useState(null);
18048
+ const [testing, setTesting] = React34.useState(false);
18049
+ const [testState, setTestState] = React34.useState(null);
17932
18050
  const currentTarget = () => {
17933
18051
  const normalizedRoute = Object.fromEntries(fieldsFor(definition, kind).map((field2) => {
17934
18052
  const raw = String(route[field2.key] ?? "").trim();
@@ -18145,7 +18263,7 @@ function TargetSuggestionPicker({
18145
18263
  suggestions.map((suggestion, index) => {
18146
18264
  const identity = routeIdentity(definition, suggestion);
18147
18265
  const added = configured.has(identity);
18148
- return React33.createElement("option", {
18266
+ return React34.createElement("option", {
18149
18267
  key: suggestion.id ?? suggestion.suggestionId ?? `${identity}:${index}`,
18150
18268
  value: String(index),
18151
18269
  disabled: added
@@ -18162,11 +18280,11 @@ function TargetSuggestionPicker({
18162
18280
  );
18163
18281
  }
18164
18282
  function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, onEdit }) {
18165
- const [action, setAction] = React33.useState(null);
18166
- const [testState, setTestState] = React33.useState(null);
18167
- const [syncFeedback, setSyncFeedback] = React33.useState(null);
18168
- const [copyState, setCopyState] = React33.useState(null);
18169
- const [confirmDelete, setConfirmDelete] = React33.useState(false);
18283
+ const [action, setAction] = React34.useState(null);
18284
+ const [testState, setTestState] = React34.useState(null);
18285
+ const [syncFeedback, setSyncFeedback] = React34.useState(null);
18286
+ const [copyState, setCopyState] = React34.useState(null);
18287
+ const [confirmDelete, setConfirmDelete] = React34.useState(false);
18170
18288
  const sessionSync = target.sessionSync ?? { enabled: false, state: "unavailable" };
18171
18289
  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";
18172
18290
  const testTarget = async () => {
@@ -18229,7 +18347,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
18229
18347
  h2(
18230
18348
  "div",
18231
18349
  { className: "dim-targetTitle" },
18232
- React33.createElement("strong", null, target.name || target.targetId),
18350
+ React34.createElement("strong", null, target.name || target.targetId),
18233
18351
  h2("span", null, kindLabel(definition, target.kind))
18234
18352
  ),
18235
18353
  h2("code", null, `targetId: ${target.targetId}`)
@@ -18315,30 +18433,30 @@ function DeliveryTargetSettingsPage({
18315
18433
  onBack
18316
18434
  }) {
18317
18435
  const definition = CHANNEL_DEFINITIONS[channel7];
18318
- const [activeTabId, setActiveTabId] = React33.useState(BOT_SETTINGS_TABS[0].id);
18319
- const [phase, setPhase] = React33.useState("loading");
18320
- const [targets, setTargets] = React33.useState([]);
18321
- const [suggestionPhase, setSuggestionPhase] = React33.useState("idle");
18322
- const [suggestions, setSuggestions] = React33.useState([]);
18323
- const [suggestionError, setSuggestionError] = React33.useState(null);
18324
- const [error, setError] = React33.useState(null);
18325
- const [editor, setEditor] = React33.useState(null);
18326
- const [saving, setSaving] = React33.useState(false);
18327
- const [botCopyState, setBotCopyState] = React33.useState(null);
18328
- const [accessPolicy, setAccessPolicy] = React33.useState(account.accessPolicy);
18329
- const [slashPanel, setSlashPanel] = React33.useState(account.slashPanel);
18330
- const mounted = React33.useRef(true);
18331
- React33.useEffect(() => {
18436
+ const [activeTabId, setActiveTabId] = React34.useState(BOT_SETTINGS_TABS[0].id);
18437
+ const [phase, setPhase] = React34.useState("loading");
18438
+ const [targets, setTargets] = React34.useState([]);
18439
+ const [suggestionPhase, setSuggestionPhase] = React34.useState("idle");
18440
+ const [suggestions, setSuggestions] = React34.useState([]);
18441
+ const [suggestionError, setSuggestionError] = React34.useState(null);
18442
+ const [error, setError] = React34.useState(null);
18443
+ const [editor, setEditor] = React34.useState(null);
18444
+ const [saving, setSaving] = React34.useState(false);
18445
+ const [botCopyState, setBotCopyState] = React34.useState(null);
18446
+ const [accessPolicy, setAccessPolicy] = React34.useState(account.accessPolicy);
18447
+ const [slashPanel, setSlashPanel] = React34.useState(account.slashPanel);
18448
+ const mounted = React34.useRef(true);
18449
+ React34.useEffect(() => {
18332
18450
  setAccessPolicy(account.accessPolicy);
18333
18451
  }, [account.botId, account.accessPolicy]);
18334
- React33.useEffect(() => {
18452
+ React34.useEffect(() => {
18335
18453
  setSlashPanel(account.slashPanel);
18336
18454
  }, [account.botId, account.slashPanel]);
18337
- const invoke = React33.useCallback(async (endpoint, payload = {}, signal) => {
18455
+ const invoke = React34.useCallback(async (endpoint, payload = {}, signal) => {
18338
18456
  if (typeof rpcCall !== "function") throw new Error("\u6295\u9012\u76EE\u6807\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
18339
18457
  return unwrapRpcResult15(await rpcCall(endpoint, payload, signal));
18340
18458
  }, [rpcCall]);
18341
- const loadTargets = React33.useCallback(async ({ signal, silent = false } = {}) => {
18459
+ const loadTargets = React34.useCallback(async ({ signal, silent = false } = {}) => {
18342
18460
  if (!silent) setPhase("loading");
18343
18461
  setError(null);
18344
18462
  try {
@@ -18352,7 +18470,7 @@ function DeliveryTargetSettingsPage({
18352
18470
  setPhase("error");
18353
18471
  }
18354
18472
  }, [account.botId, invoke]);
18355
- const loadSuggestions = React33.useCallback(async () => {
18473
+ const loadSuggestions = React34.useCallback(async () => {
18356
18474
  setSuggestionPhase("loading");
18357
18475
  setSuggestionError(null);
18358
18476
  try {
@@ -18366,7 +18484,7 @@ function DeliveryTargetSettingsPage({
18366
18484
  setSuggestionPhase("error");
18367
18485
  }
18368
18486
  }, [account.botId, definition, invoke]);
18369
- React33.useEffect(() => {
18487
+ React34.useEffect(() => {
18370
18488
  mounted.current = true;
18371
18489
  const controller = new AbortController();
18372
18490
  void loadTargets({ signal: controller.signal });
@@ -18452,25 +18570,7 @@ function DeliveryTargetSettingsPage({
18452
18570
  { className: "dim-deliveryHeader" },
18453
18571
  h2(DeliveryButton, { className: "dim-deliveryBack", onClick: onBack }, "\u2190 \u8FD4\u56DE\u673A\u5668\u4EBA\u5217\u8868")
18454
18572
  ),
18455
- h2(
18456
- "div",
18457
- { className: "dim-botSettingsTabsBar" },
18458
- h2("nav", {
18459
- className: "dim-botSettingsTabs",
18460
- role: "tablist",
18461
- "aria-label": "\u673A\u5668\u4EBA\u8BBE\u7F6E\u9875\u7B7E"
18462
- }, settingsTabs.map((tab) => h2("button", {
18463
- key: tab.id,
18464
- id: `dim-bot-settings-${tab.id}-tab`,
18465
- type: "button",
18466
- role: "tab",
18467
- className: "dim-botSettingsTab",
18468
- "aria-selected": tab.id === activeTab.id,
18469
- "aria-controls": `dim-bot-settings-${tab.id}-panel`,
18470
- tabIndex: tab.id === activeTab.id ? 0 : -1,
18471
- onClick: () => setActiveTabId(tab.id)
18472
- }, tab.label)))
18473
- ),
18573
+ h2(BotSettingsTabs, { tabs: settingsTabs, activeTabId: activeTab.id, onChange: setActiveTabId }),
18474
18574
  h2(
18475
18575
  "div",
18476
18576
  {
@@ -18496,7 +18596,7 @@ function DeliveryTargetSettingsPage({
18496
18596
  account,
18497
18597
  rpcCall: accessRpcCall
18498
18598
  }) : h2(
18499
- React33.Fragment,
18599
+ React34.Fragment,
18500
18600
  null,
18501
18601
  h2(
18502
18602
  "section",
@@ -18607,7 +18707,7 @@ function DeliveryTargetSettingsPage({
18607
18707
  }
18608
18708
 
18609
18709
  // plugin-src/client/global-settings.js
18610
- var React34 = __toESM(require("react"), 1);
18710
+ var React35 = __toESM(require("react"), 1);
18611
18711
 
18612
18712
  // src/channels/shared/inbound-ttl.mjs
18613
18713
  var DEFAULT_INBOUND_TTL_HOURS = 168;
@@ -18692,14 +18792,14 @@ function GlobalButton({ children, kind = "secondary", className = "", ...props }
18692
18792
  }, children);
18693
18793
  }
18694
18794
  function ImageInputSettings({ rpcCall }) {
18695
- const [values, setValues] = React34.useState(DEFAULT_IMAGE_INPUT_SETTINGS);
18696
- const [phase, setPhase] = React34.useState("loading");
18697
- const [error, setError] = React34.useState(null);
18698
- const [saved, setSaved] = React34.useState(false);
18699
- const mounted = React34.useRef(false);
18700
- const saving = React34.useRef(false);
18701
- const id6 = React34.useId();
18702
- const load = React34.useCallback(async (signal) => {
18795
+ const [values, setValues] = React35.useState(DEFAULT_IMAGE_INPUT_SETTINGS);
18796
+ const [phase, setPhase] = React35.useState("loading");
18797
+ const [error, setError] = React35.useState(null);
18798
+ const [saved, setSaved] = React35.useState(false);
18799
+ const mounted = React35.useRef(false);
18800
+ const saving = React35.useRef(false);
18801
+ const id6 = React35.useId();
18802
+ const load = React35.useCallback(async (signal) => {
18703
18803
  setPhase("loading");
18704
18804
  setError(null);
18705
18805
  try {
@@ -18715,7 +18815,7 @@ function ImageInputSettings({ rpcCall }) {
18715
18815
  setPhase("error");
18716
18816
  }
18717
18817
  }, [rpcCall]);
18718
- React34.useEffect(() => {
18818
+ React35.useEffect(() => {
18719
18819
  mounted.current = true;
18720
18820
  const controller = new AbortController();
18721
18821
  void load(controller.signal);
@@ -18822,29 +18922,29 @@ function ImageInputSettings({ rpcCall }) {
18822
18922
  );
18823
18923
  }
18824
18924
  function GlobalSettingsPanel({ rpcCall }) {
18825
- const [phase, setPhase] = React34.useState("loading");
18826
- const [loadError, setLoadError] = React34.useState(null);
18827
- const [ttlInput, setTtlInput] = React34.useState("");
18828
- const [savedTtl, setSavedTtl] = React34.useState(null);
18829
- const [ttlError, setTtlError] = React34.useState(false);
18830
- const [saveError, setSaveError] = React34.useState(null);
18831
- const [saveSucceeded, setSaveSucceeded] = React34.useState(false);
18832
- const [isSaving, setIsSaving] = React34.useState(false);
18833
- const [sweepConfirming, setSweepConfirming] = React34.useState(false);
18834
- const [sweeping, setSweeping] = React34.useState(false);
18835
- const ttlErrorId = React34.useId();
18836
- const ttlHintsId = React34.useId();
18837
- const sweepTriggerId = React34.useId();
18838
- const sweepConfirmId = React34.useId();
18839
- const sweepConfirmTextId = React34.useId();
18840
- const sweepConfirmButtonId = React34.useId();
18841
- const mounted = React34.useRef(true);
18842
- const saving = React34.useRef(false);
18843
- const invoke = React34.useCallback(async (endpoint, payload = {}, signal) => {
18925
+ const [phase, setPhase] = React35.useState("loading");
18926
+ const [loadError, setLoadError] = React35.useState(null);
18927
+ const [ttlInput, setTtlInput] = React35.useState("");
18928
+ const [savedTtl, setSavedTtl] = React35.useState(null);
18929
+ const [ttlError, setTtlError] = React35.useState(false);
18930
+ const [saveError, setSaveError] = React35.useState(null);
18931
+ const [saveSucceeded, setSaveSucceeded] = React35.useState(false);
18932
+ const [isSaving, setIsSaving] = React35.useState(false);
18933
+ const [sweepConfirming, setSweepConfirming] = React35.useState(false);
18934
+ const [sweeping, setSweeping] = React35.useState(false);
18935
+ const ttlErrorId = React35.useId();
18936
+ const ttlHintsId = React35.useId();
18937
+ const sweepTriggerId = React35.useId();
18938
+ const sweepConfirmId = React35.useId();
18939
+ const sweepConfirmTextId = React35.useId();
18940
+ const sweepConfirmButtonId = React35.useId();
18941
+ const mounted = React35.useRef(true);
18942
+ const saving = React35.useRef(false);
18943
+ const invoke = React35.useCallback(async (endpoint, payload = {}, signal) => {
18844
18944
  if (typeof rpcCall !== "function") throw new Error("\u901A\u7528\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
18845
18945
  return unwrapRpcResult16(await rpcCall(endpoint, payload, signal));
18846
18946
  }, [rpcCall]);
18847
- const loadSettings = React34.useCallback(async ({ signal } = {}) => {
18947
+ const loadSettings = React35.useCallback(async ({ signal } = {}) => {
18848
18948
  setPhase("loading");
18849
18949
  setLoadError(null);
18850
18950
  try {
@@ -18868,7 +18968,7 @@ function GlobalSettingsPanel({ rpcCall }) {
18868
18968
  setPhase("error");
18869
18969
  }
18870
18970
  }, [invoke]);
18871
- React34.useEffect(() => {
18971
+ React35.useEffect(() => {
18872
18972
  mounted.current = true;
18873
18973
  const controller = new AbortController();
18874
18974
  void loadSettings({ signal: controller.signal });
@@ -18877,7 +18977,7 @@ function GlobalSettingsPanel({ rpcCall }) {
18877
18977
  controller.abort();
18878
18978
  };
18879
18979
  }, [loadSettings]);
18880
- React34.useEffect(() => {
18980
+ React35.useEffect(() => {
18881
18981
  if (!sweepConfirming) return;
18882
18982
  globalThis.document?.getElementById(sweepConfirmButtonId)?.focus();
18883
18983
  }, [sweepConfirmButtonId, sweepConfirming]);
@@ -19652,9 +19752,14 @@ var CSS15 = String.raw`
19652
19752
  .dim-moreSettingsChevron { width: 6px; height: 6px; margin-right: 2px; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(-45deg); }
19653
19753
  .dim-deliveryPage { min-width: 0; display: grid; }
19654
19754
  .dim-deliveryHeader { min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 16px; }
19655
- .dim-botSettingsTabsBar { min-width: 0; margin-top: 10px; border-bottom: 1px solid var(--dsw-alias-border-l2, #dfe1e5); }
19656
- .dim-botSettingsTabs { min-width: 0; display: flex; align-items: flex-end; gap: 24px; overflow-x: auto; scrollbar-width: none; }
19755
+ .dim-botSettingsTabsBar { min-width: 0; display: flex; align-items: center; gap: 4px; margin-top: 10px; border-bottom: 1px solid var(--dsw-alias-border-l2, #dfe1e5); }
19756
+ .dim-botSettingsTabs { min-width: 0; flex: 1; overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none; }
19657
19757
  .dim-botSettingsTabs::-webkit-scrollbar { display: none; }
19758
+ .dim-botSettingsTabsList { width: max-content; min-width: 100%; display: flex; align-items: flex-end; gap: 24px; }
19759
+ .dim-botSettingsScroll { flex: 0 0 30px; width: 30px; height: 32px; display: inline-flex; align-items: center; justify-content: center; padding: 0; border: 0; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #646a73); cursor: pointer; }
19760
+ .dim-botSettingsScroll:hover:not(:disabled) { color: var(--dsw-alias-state-business-primary, #3370ff); background: var(--dsw-alias-interactive-bg-hover, #eef0f3); }
19761
+ .dim-botSettingsScroll:disabled { opacity: .3; cursor: default; }
19762
+ .dim-botSettingsScroll:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: -2px; }
19658
19763
  .dim-botSettingsTab { position: relative; min-height: 38px; flex: none; display: inline-flex; align-items: center; justify-content: center; padding: 6px 2px 9px; border: 0; color: var(--dsw-alias-label-secondary, #646a73); background: transparent; font: inherit; font-size: 13px; line-height: 20px; font-weight: 560; white-space: nowrap; cursor: pointer; transition: color .15s ease; }
19659
19764
  .dim-botSettingsTab::after { content: ''; position: absolute; right: 0; bottom: -1px; left: 0; height: 2px; border-radius: 2px 2px 0 0; background: transparent; transform: scaleX(.45); transition: background .15s ease, transform .15s ease; }
19660
19765
  .dim-botSettingsTab:hover:not([aria-selected="true"]) { color: var(--dsw-alias-label-primary, #1f2329); }
@@ -19920,7 +20025,7 @@ var CSS15 = String.raw`
19920
20025
  .dim-loopbackRecovery { align-items: stretch; flex-direction: column; gap: 12px; }
19921
20026
  .dim-loopbackRecoveryAction { width: 100%; }
19922
20027
  .dim-deliverySectionHeading { align-items: stretch; flex-direction: column; }
19923
- .dim-botSettingsTabs { gap: 18px; }
20028
+ .dim-botSettingsTabsList { gap: 18px; }
19924
20029
  .dim-deliveryBotId { grid-template-columns: minmax(0, 1fr) max-content; }
19925
20030
  .dim-deliveryBotId > span { grid-column: 1 / -1; }
19926
20031
  .dim-targetActions .dim-deliveryButton { flex: 1 1 auto; }
@@ -20207,7 +20312,7 @@ function installSessionChannelLogos(document2 = globalThis.document) {
20207
20312
  }
20208
20313
 
20209
20314
  // plugin-src/client/update-panel.js
20210
- var React35 = __toESM(require("react"), 1);
20315
+ var React36 = __toESM(require("react"), 1);
20211
20316
  var import_react_dom4 = require("react-dom");
20212
20317
  var import_valid = __toESM(require_valid(), 1);
20213
20318
  var import_rcompare = __toESM(require_rcompare(), 1);
@@ -20300,11 +20405,11 @@ function manualUpdateCommand(snapshot) {
20300
20405
  return `dsh plugin --profile ${profileArgument} add -w @xmanrui/dsh-im@${version}`;
20301
20406
  }
20302
20407
  function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
20303
- const [copyState, setCopyState] = React35.useState("idle");
20304
- const commandRef = React35.useRef(null);
20305
- const mounted = React35.useRef(false);
20306
- const copying = React35.useRef(false);
20307
- React35.useEffect(() => {
20408
+ const [copyState, setCopyState] = React36.useState("idle");
20409
+ const commandRef = React36.useRef(null);
20410
+ const mounted = React36.useRef(false);
20411
+ const copying = React36.useRef(false);
20412
+ React36.useEffect(() => {
20308
20413
  mounted.current = true;
20309
20414
  return () => {
20310
20415
  mounted.current = false;
@@ -20336,7 +20441,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
20336
20441
  { className: "dim-updateManual", "aria-label": "\u624B\u5DE5\u66F4\u65B0" },
20337
20442
  h2("h4", { className: "dim-updateManualHeading" }, "\u624B\u5DE5\u66F4\u65B0"),
20338
20443
  command ? h2(
20339
- React35.Fragment,
20444
+ React36.Fragment,
20340
20445
  null,
20341
20446
  h2("p", { className: "dim-updateManualHint" }, "\u81EA\u52A8\u66F4\u65B0\u5931\u8D25\u53EF\u4EE5\u4F7F\u7528\u547D\u4EE4\u66F4\u65B0\uFF1A"),
20342
20447
  h2(
@@ -20372,7 +20477,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
20372
20477
  "aria-hidden": "true",
20373
20478
  focusable: "false"
20374
20479
  }, copyState === "copied" ? h2("path", { d: "m4 10 4 4 8-8" }) : h2(
20375
- React35.Fragment,
20480
+ React36.Fragment,
20376
20481
  null,
20377
20482
  h2("rect", { x: 7, y: 7, width: 10, height: 11, rx: 1.5 }),
20378
20483
  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" })
@@ -20397,10 +20502,10 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
20397
20502
  );
20398
20503
  }
20399
20504
  function UpdateDialog({ children, onClose }) {
20400
- const dialogRef = React35.useRef(null);
20401
- const titleId = React35.useId();
20402
- const descriptionId = React35.useId();
20403
- React35.useEffect(() => {
20505
+ const dialogRef = React36.useRef(null);
20506
+ const titleId = React36.useId();
20507
+ const descriptionId = React36.useId();
20508
+ React36.useEffect(() => {
20404
20509
  const previous = globalThis.document?.activeElement;
20405
20510
  dialogRef.current?.focus?.();
20406
20511
  return () => {
@@ -20458,20 +20563,20 @@ function UpdateDialog({ children, onClose }) {
20458
20563
  return typeof document !== "undefined" && document.body ? (0, import_react_dom4.createPortal)(content, document.body) : content;
20459
20564
  }
20460
20565
  function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20461
- const tooltipId = React35.useId();
20462
- const [snapshot, setSnapshot] = React35.useState(null);
20463
- const [action, setAction] = React35.useState("status");
20464
- const [error, setError] = React35.useState(null);
20465
- const [open, setOpen] = React35.useState(false);
20466
- const [uncertainInstall, setUncertainInstall] = React35.useState(false);
20467
- const mounted = React35.useRef(false);
20468
- const busy = React35.useRef(false);
20469
- const readController = React35.useRef(null);
20470
- const pollReadController = React35.useRef(null);
20471
- const installRequest = React35.useRef(null);
20472
- const onStatusRef = React35.useRef(onStatus);
20566
+ const tooltipId = React36.useId();
20567
+ const [snapshot, setSnapshot] = React36.useState(null);
20568
+ const [action, setAction] = React36.useState("status");
20569
+ const [error, setError] = React36.useState(null);
20570
+ const [open, setOpen] = React36.useState(false);
20571
+ const [uncertainInstall, setUncertainInstall] = React36.useState(false);
20572
+ const mounted = React36.useRef(false);
20573
+ const busy = React36.useRef(false);
20574
+ const readController = React36.useRef(null);
20575
+ const pollReadController = React36.useRef(null);
20576
+ const installRequest = React36.useRef(null);
20577
+ const onStatusRef = React36.useRef(onStatus);
20473
20578
  onStatusRef.current = onStatus;
20474
- const accept = React35.useCallback((next) => {
20579
+ const accept = React36.useCallback((next) => {
20475
20580
  setSnapshot(next);
20476
20581
  onStatusRef.current?.(next);
20477
20582
  }, []);
@@ -20480,7 +20585,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20480
20585
  setUncertainInstall(false);
20481
20586
  accept(next);
20482
20587
  };
20483
- const invoke = React35.useCallback(async (endpoint, payload = {}, signal) => {
20588
+ const invoke = React36.useCallback(async (endpoint, payload = {}, signal) => {
20484
20589
  if (typeof rpcCall !== "function") {
20485
20590
  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");
20486
20591
  unavailable.code = "update-unavailable";
@@ -20488,7 +20593,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20488
20593
  }
20489
20594
  return unwrapSnapshot(await rpcCall(endpoint, payload, signal));
20490
20595
  }, [rpcCall]);
20491
- React35.useEffect(() => {
20596
+ React36.useEffect(() => {
20492
20597
  mounted.current = true;
20493
20598
  busy.current = true;
20494
20599
  const controller = new AbortController();
@@ -20511,7 +20616,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20511
20616
  const activeJob = ACTIVE_STATES4.has(snapshot?.job?.state);
20512
20617
  const restartRequired = snapshot?.job?.state === "restart-required" || snapshot?.blockedReason === "pending-restart";
20513
20618
  const shouldPoll = activeJob || uncertainInstall;
20514
- React35.useEffect(() => {
20619
+ React36.useEffect(() => {
20515
20620
  if (!shouldPoll) return void 0;
20516
20621
  let controller;
20517
20622
  const scheduler = createPollScheduler({
@@ -20612,7 +20717,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20612
20717
  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";
20613
20718
  const buttonDescription = localizeText(buttonLabel) + (buttonLabel === "\u66F4\u65B0\u81F3" ? ` v${snapshot.latestVersion}` : "");
20614
20719
  return h2(
20615
- React35.Fragment,
20720
+ React36.Fragment,
20616
20721
  null,
20617
20722
  h2(
20618
20723
  "span",
@@ -20662,25 +20767,25 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20662
20767
  h2("dt", null, "\u8FD0\u884C\u7248\u672C"),
20663
20768
  h2("dd", null, `v${snapshot?.runningVersion ?? clientVersion}`),
20664
20769
  snapshot?.installedVersion && snapshot.installedVersion !== snapshot.runningVersion ? h2(
20665
- React35.Fragment,
20770
+ React36.Fragment,
20666
20771
  null,
20667
20772
  h2("dt", null, "\u5DF2\u5B89\u88C5\u7248\u672C"),
20668
20773
  h2("dd", null, `v${snapshot.installedVersion}`)
20669
20774
  ) : null,
20670
20775
  targetVersion ? h2(
20671
- React35.Fragment,
20776
+ React36.Fragment,
20672
20777
  null,
20673
20778
  h2("dt", null, "\u76EE\u6807\u7248\u672C"),
20674
20779
  h2("dd", null, `v${targetVersion}`)
20675
20780
  ) : null,
20676
20781
  latestVersion ? h2(
20677
- React35.Fragment,
20782
+ React36.Fragment,
20678
20783
  null,
20679
20784
  h2("dt", null, "\u6700\u65B0\u7248\u672C"),
20680
20785
  h2("dd", null, `v${latestVersion}`)
20681
20786
  ) : null,
20682
20787
  historicalTargetVersion ? h2(
20683
- React35.Fragment,
20788
+ React36.Fragment,
20684
20789
  null,
20685
20790
  h2("dt", null, "\u4E0A\u6B21\u66F4\u65B0\u76EE\u6807"),
20686
20791
  h2("dd", null, `v${historicalTargetVersion}`)
@@ -20762,8 +20867,8 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20762
20867
  }
20763
20868
 
20764
20869
  // plugin-src/client/panel-error-boundary.js
20765
- var React36 = __toESM(require("react"), 1);
20766
- var IMPanelErrorBoundary = class extends React36.Component {
20870
+ var React37 = __toESM(require("react"), 1);
20871
+ var IMPanelErrorBoundary = class extends React37.Component {
20767
20872
  state = { failed: false };
20768
20873
  static getDerivedStateFromError() {
20769
20874
  return { failed: true };
@@ -20783,9 +20888,9 @@ var IMPanelErrorBoundary = class extends React36.Component {
20783
20888
  };
20784
20889
 
20785
20890
  // plugin-src/client/plugin-page.js
20786
- var React37 = __toESM(require("react"), 1);
20891
+ var React38 = __toESM(require("react"), 1);
20787
20892
  var IM_MAIN_PANEL_ID = "xmanrui-dsh-im";
20788
- var h3 = React37.createElement;
20893
+ var h3 = React38.createElement;
20789
20894
  function OpenImAction({ subject, packageName, onOpen, t }) {
20790
20895
  if (subject?.kind !== "bundle" && subject?.kind !== "row") return null;
20791
20896
  if (subject.pkg?.name !== packageName) return null;
@@ -21016,28 +21121,28 @@ function IMSettingsTab({
21016
21121
  browserLocation = globalThis.location,
21017
21122
  navigateToRecoveryUrl = replacePageLocation
21018
21123
  }) {
21019
- const [selected, setSelected] = React38.useState(() => preferredSectionId === GLOBAL_SETTINGS_TAB_ID || CHANNELS.some((channel7) => channel7.id === preferredSectionId) ? preferredSectionId : "weixin");
21020
- const [loopbackRecovery, setLoopbackRecovery] = React38.useState(null);
21021
- const [runningVersion, setRunningVersion] = React38.useState(IM_PLUGIN_VERSION);
21022
- const [deliverySettings, setDeliverySettings] = React38.useState(null);
21124
+ const [selected, setSelected] = React39.useState(() => preferredSectionId === GLOBAL_SETTINGS_TAB_ID || CHANNELS.some((channel7) => channel7.id === preferredSectionId) ? preferredSectionId : "weixin");
21125
+ const [loopbackRecovery, setLoopbackRecovery] = React39.useState(null);
21126
+ const [runningVersion, setRunningVersion] = React39.useState(IM_PLUGIN_VERSION);
21127
+ const [deliverySettings, setDeliverySettings] = React39.useState(null);
21023
21128
  const emailEnabled = useEmailChannelEnabled(emailRpcCall);
21024
- const visibleChannels = React38.useMemo(
21129
+ const visibleChannels = React39.useMemo(
21025
21130
  () => CHANNELS.filter((channel7) => channel7.id !== "email" || emailEnabled),
21026
21131
  [emailEnabled]
21027
21132
  );
21028
- const githubTooltipId = React38.useId();
21029
- const generalSettingsTooltipId = React38.useId();
21133
+ const githubTooltipId = React39.useId();
21134
+ const generalSettingsTooltipId = React39.useId();
21030
21135
  const globalSettingsSelected = selected === GLOBAL_SETTINGS_TAB_ID;
21031
21136
  const active = visibleChannels.find((channel7) => channel7.id === selected) ?? visibleChannels[0];
21032
21137
  const activeTabId = globalSettingsSelected ? "dim-general-settings-trigger" : `dim-tab-${active.id}`;
21033
21138
  const activePanelId = globalSettingsSelected ? `dim-panel-${GLOBAL_SETTINGS_TAB_ID}` : `dim-panel-${active.id}`;
21034
- const reportLoopbackRecovery = React38.useCallback((recovery) => {
21139
+ const reportLoopbackRecovery = React39.useCallback((recovery) => {
21035
21140
  setLoopbackRecovery((current) => current?.url === recovery.url ? current : recovery);
21036
21141
  }, []);
21037
- const reportUpdateStatus = React38.useCallback((snapshot) => {
21142
+ const reportUpdateStatus = React39.useCallback((snapshot) => {
21038
21143
  setRunningVersion(snapshot.runningVersion);
21039
21144
  }, []);
21040
- const rpcCalls = React38.useMemo(() => createLoopbackAwareRpcCalls({
21145
+ const rpcCalls = React39.useMemo(() => createLoopbackAwareRpcCalls({
21041
21146
  dingtalkRpcCall,
21042
21147
  discordRpcCall,
21043
21148
  feishuRpcCall,
@@ -21079,7 +21184,7 @@ function IMSettingsTab({
21079
21184
  weixinRpcCall,
21080
21185
  whatsappRpcCall
21081
21186
  ]);
21082
- const botSettingsContext = React38.useMemo(() => Object.freeze({
21187
+ const botSettingsContext = React39.useMemo(() => Object.freeze({
21083
21188
  openBotSettings: setDeliverySettings
21084
21189
  }), []);
21085
21190
  return h2(
@@ -21303,7 +21408,7 @@ function apply(ctx) {
21303
21408
  };
21304
21409
  const localeSnapshot = () => ctx.locale.getLocale?.()?.active ?? "";
21305
21410
  function IMPanel({ preferredSectionId }) {
21306
- React38.useSyncExternalStore(subscribeLocale, localeSnapshot, localeSnapshot);
21411
+ React39.useSyncExternalStore(subscribeLocale, localeSnapshot, localeSnapshot);
21307
21412
  return h2(
21308
21413
  IMPanelErrorBoundary,
21309
21414
  null,