@xmanrui/dsh-im 1.0.2 → 1.1.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 (47) hide show
  1. package/README.en.md +18 -0
  2. package/README.md +18 -0
  3. package/assets/logo-dsh-im-chinese-readme-3x2.png +0 -0
  4. package/assets/logo_cn.png +0 -0
  5. package/lib/client.js +603 -560
  6. package/lib/index.js +163 -163
  7. package/package.json +1 -1
  8. package/plugin-src/client/agent-preset.js +15 -6
  9. package/plugin-src/client/channel-card-meta.js +48 -0
  10. package/plugin-src/client/channels/dingtalk/index.js +25 -19
  11. package/plugin-src/client/channels/dingtalk/styles.js +0 -6
  12. package/plugin-src/client/channels/feishu/index.js +41 -35
  13. package/plugin-src/client/channels/feishu/styles.js +0 -5
  14. package/plugin-src/client/channels/qq/index.js +24 -16
  15. package/plugin-src/client/channels/shared/token-channel.js +32 -24
  16. package/plugin-src/client/channels/wecom/index.js +24 -16
  17. package/plugin-src/client/channels/weixin/index.js +29 -23
  18. package/plugin-src/client/channels/weixin/styles.js +0 -5
  19. package/plugin-src/client/channels/whatsapp/index.js +27 -23
  20. package/plugin-src/client/i18n.js +2 -0
  21. package/plugin-src/client/styles.js +23 -8
  22. package/plugin-src/host/index.mjs +14 -1
  23. package/src/channels/dingtalk/dingtalk-api.mjs +215 -2
  24. package/src/channels/dingtalk/dingtalk-bridge.mjs +155 -4
  25. package/src/channels/discord/discord-api.mjs +134 -6
  26. package/src/channels/discord/discord-runtime.mjs +15 -4
  27. package/src/channels/feishu/bridge.mjs +223 -15
  28. package/src/channels/feishu/feishu-channel.mjs +227 -1
  29. package/src/channels/feishu/plugin-controller.mjs +1 -0
  30. package/src/channels/qq/qq-bridge.mjs +217 -10
  31. package/src/channels/shared/editable-message-stream.mjs +18 -1
  32. package/src/channels/shared/harness-client.mjs +99 -7
  33. package/src/channels/shared/semantic/artifact.mjs +748 -0
  34. package/src/channels/shared/semantic/delivery.mjs +153 -0
  35. package/src/channels/shared/text-harness-bridge.mjs +149 -3
  36. package/src/channels/shared/workspace-session.mjs +15 -1
  37. package/src/channels/slack/manifest.mjs +1 -0
  38. package/src/channels/slack/slack-api.mjs +167 -4
  39. package/src/channels/slack/slack-runtime.mjs +21 -5
  40. package/src/channels/telegram/telegram-api.mjs +111 -5
  41. package/src/channels/telegram/telegram-runtime.mjs +18 -4
  42. package/src/channels/wecom/wecom-bridge.mjs +260 -12
  43. package/src/channels/weixin/weixin-api.mjs +268 -2
  44. package/src/channels/weixin/weixin-bridge.mjs +134 -3
  45. package/src/channels/weixin/weixin-controller.mjs +5 -1
  46. package/src/channels/weixin/weixin-runtime.mjs +5 -1
  47. package/src/channels/whatsapp/whatsapp-runtime.mjs +108 -5
package/lib/client.js CHANGED
@@ -40,7 +40,7 @@ __export(index_exports, {
40
40
  name: () => name
41
41
  });
42
42
  module.exports = __toCommonJS(index_exports);
43
- var React19 = __toESM(require("react"), 1);
43
+ var React20 = __toESM(require("react"), 1);
44
44
 
45
45
  // plugin-src/client/channel-logos.js
46
46
  var React = __toESM(require("react"), 1);
@@ -297,6 +297,7 @@ var EN = Object.freeze({
297
297
  "\u79BB\u7EBF": "Offline",
298
298
  "\u5DF2\u65AD\u5F00": "Disconnected",
299
299
  "\u6D88\u606F\u901A\u9053": "Message channel",
300
+ "\u67E5\u770B\u6D88\u606F\u901A\u9053\u8BF4\u660E": "View message channel details",
300
301
  "\u6700\u8FD1\u68C0\u67E5": "Last checked",
301
302
  "\u5F53\u524D\u5DE5\u4F5C\u533A": "Current workspace",
302
303
  "\u9009\u62E9\u76EE\u5F55": "Choose folder",
@@ -326,6 +327,7 @@ var EN = Object.freeze({
326
327
  "\u5DE5\u4F5C\u533A\u8DEF\u5F84\u5FC5\u987B\u6307\u5411\u4E00\u4E2A\u76EE\u5F55\u3002": "The workspace path must point to a directory.",
327
328
  "\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002": "The bot could not be found.",
328
329
  "Agent Preset": "Agent Preset",
330
+ "\u67E5\u770B Agent Preset \u8BF4\u660E": "View Agent Preset help",
329
331
  "\u8DDF\u968F Host \u9ED8\u8BA4": "Follow the Host default",
330
332
  "\uFF08\u5DF2\u4E0D\u53EF\u7528\uFF09": " (unavailable)",
331
333
  "\u53EA\u5F71\u54CD\u65B0\u5EFA\u4F1A\u8BDD\uFF1B\u82E5\u5F53\u524D\u804A\u5929\u5DF2\u6709\u4F1A\u8BDD\uFF0C\u5148\u53D1\u9001 /new\uFF0C\u518D\u53D1\u9001\u666E\u901A\u6D88\u606F\u751F\u6548\u3002": "This affects only new sessions. If the current chat already has a session, send /new, then send a regular message to apply it.",
@@ -904,6 +906,7 @@ function normalizeAgentPresetCatalog(value) {
904
906
  }
905
907
  function AgentPresetEditor({ agentPreset = "", disabled = false, onSave }) {
906
908
  const catalog = React3.useContext(AgentPresetCatalogContext) ?? EMPTY_AGENT_PRESET_CATALOG;
909
+ const helpId = React3.useId();
907
910
  const current = normalizeAgentPresetId(agentPreset);
908
911
  const [saving, setSaving] = React3.useState(false);
909
912
  const [error, setError] = React3.useState(null);
@@ -936,7 +939,26 @@ function AgentPresetEditor({ agentPreset = "", disabled = false, onSave }) {
936
939
  h2(
937
940
  "div",
938
941
  { className: "dim-presetHeader" },
939
- h2("span", null, "Agent Preset"),
942
+ h2(
943
+ "span",
944
+ { className: "dim-presetTitle" },
945
+ h2("span", null, "Agent Preset"),
946
+ h2(
947
+ "span",
948
+ { className: "dim-presetHelp" },
949
+ h2("button", {
950
+ type: "button",
951
+ className: "dim-presetHelpButton",
952
+ "aria-label": "\u67E5\u770B Agent Preset \u8BF4\u660E",
953
+ "aria-describedby": helpId
954
+ }, h2("span", { "aria-hidden": "true" }, "?")),
955
+ h2("span", {
956
+ id: helpId,
957
+ className: "dim-presetTooltip",
958
+ role: "tooltip"
959
+ }, "\u53EA\u5F71\u54CD\u65B0\u5EFA\u4F1A\u8BDD\uFF1B\u82E5\u5F53\u524D\u804A\u5929\u5DF2\u6709\u4F1A\u8BDD\uFF0C\u5148\u53D1\u9001 /new\uFF0C\u518D\u53D1\u9001\u666E\u901A\u6D88\u606F\u751F\u6548\u3002")
960
+ )
961
+ ),
940
962
  saving ? h2("span", { className: "dim-presetStatus" }, "\u4FDD\u5B58\u4E2D\u2026") : null
941
963
  ),
942
964
  React3.createElement(
@@ -957,11 +979,6 @@ function AgentPresetEditor({ agentPreset = "", disabled = false, onSave }) {
957
979
  item.unavailable ? [item.id, "\uFF08\u5DF2\u4E0D\u53EF\u7528\uFF09"] : item.label && item.label !== item.id ? `${item.label}\uFF08${item.id}\uFF09` : item.id
958
980
  ))
959
981
  ),
960
- h2(
961
- "small",
962
- { className: "dim-presetHelp" },
963
- "\u53EA\u5F71\u54CD\u65B0\u5EFA\u4F1A\u8BDD\uFF1B\u82E5\u5F53\u524D\u804A\u5929\u5DF2\u6709\u4F1A\u8BDD\uFF0C\u5148\u53D1\u9001 /new\uFF0C\u518D\u53D1\u9001\u666E\u901A\u6D88\u606F\u751F\u6548\u3002"
964
- ),
965
982
  error || currentUnavailable ? h2(
966
983
  "p",
967
984
  { className: "dim-presetError", role: error ? "alert" : "status" },
@@ -1171,7 +1188,7 @@ function formatRemaining(milliseconds) {
1171
1188
  }
1172
1189
 
1173
1190
  // plugin-src/client/channels/dingtalk/index.js
1174
- var React8 = __toESM(require("react"), 1);
1191
+ var React9 = __toESM(require("react"), 1);
1175
1192
 
1176
1193
  // plugin-src/client/credential-binding.js
1177
1194
  var React4 = __toESM(require("react"), 1);
@@ -1667,6 +1684,73 @@ function useWorkspaceSnapshotFence() {
1667
1684
  }), []);
1668
1685
  }
1669
1686
 
1687
+ // plugin-src/client/channel-card-meta.js
1688
+ var React8 = __toESM(require("react"), 1);
1689
+ function ChannelListHeading({ className = "", id: id5, title, connectionLabel }) {
1690
+ const helpId = React8.useId();
1691
+ return h2(
1692
+ "div",
1693
+ { className: `${className} dim-listHeading`.trim() },
1694
+ h2(
1695
+ "div",
1696
+ { className: "dim-listTitle" },
1697
+ h2("h3", id5 ? { id: id5 } : null, title),
1698
+ h2(
1699
+ "span",
1700
+ { className: "dim-channelHelp" },
1701
+ h2("button", {
1702
+ type: "button",
1703
+ className: "dim-channelHelpButton",
1704
+ "aria-label": "\u67E5\u770B\u6D88\u606F\u901A\u9053\u8BF4\u660E",
1705
+ "aria-describedby": helpId
1706
+ }, h2("span", { "aria-hidden": "true" }, "?")),
1707
+ h2(
1708
+ "span",
1709
+ {
1710
+ id: helpId,
1711
+ className: "dim-channelTooltip",
1712
+ role: "tooltip"
1713
+ },
1714
+ h2("span", null, "\u6D88\u606F\u901A\u9053"),
1715
+ h2("strong", null, connectionLabel)
1716
+ )
1717
+ )
1718
+ )
1719
+ );
1720
+ }
1721
+ function BotStatusMeta({
1722
+ className = "",
1723
+ dotClassName = "",
1724
+ tone,
1725
+ stateLabel: stateLabel2,
1726
+ lastCheckedAt,
1727
+ formatCheckedTime: formatCheckedTime2,
1728
+ healthState
1729
+ }) {
1730
+ return h2(
1731
+ "div",
1732
+ { className: "dim-botHealthGroup" },
1733
+ h2(
1734
+ "div",
1735
+ {
1736
+ className: `${className} dim-botHealth`.trim(),
1737
+ ...healthState ? { "data-health": healthState } : {}
1738
+ },
1739
+ h2("span", {
1740
+ className: `${dotClassName} dim-healthDot`.trim(),
1741
+ "data-tone": tone
1742
+ }),
1743
+ h2("span", null, stateLabel2)
1744
+ ),
1745
+ h2(
1746
+ "div",
1747
+ { className: "dim-lastChecked" },
1748
+ h2("span", null, "\u6700\u8FD1\u68C0\u67E5"),
1749
+ h2("span", null, formatCheckedTime2(lastCheckedAt))
1750
+ )
1751
+ );
1752
+ }
1753
+
1670
1754
  // plugin-src/client/channels/dingtalk/styles.js
1671
1755
  var DINGTALK_STYLE_ID = "xmanrui-dsh-dingtalk-settings";
1672
1756
  var CSS = String.raw`
@@ -1755,10 +1839,6 @@ var CSS = String.raw`
1755
1839
  .ddt-accountIdentity h3 { overflow: hidden; font-size: 15px; text-overflow: ellipsis; white-space: nowrap; }
1756
1840
  .ddt-accountIdentity p { margin-top: 4px; color: var(--dsw-alias-label-secondary, #646a73); font: 12px ui-monospace, SFMono-Regular, monospace; }
1757
1841
  .ddt-health { display: inline-flex; align-items: center; gap: 7px; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; white-space: nowrap; }
1758
- .ddt-metrics { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin: 20px 0; }
1759
- .ddt-metric { min-width: 0; padding: 12px; border-radius: 9px; background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
1760
- .ddt-metric dt { color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 11px; }
1761
- .ddt-metric dd { overflow: hidden; margin: 5px 0 0; font-size: 13px; text-overflow: ellipsis; white-space: nowrap; }
1762
1842
  .ddt-accountFooter { display: flex; align-items: center; justify-content: space-between; gap: 15px; padding-top: 16px; border-top: 1px solid var(--dsw-alias-border-l1, #eef0f3); }
1763
1843
  .ddt-accountFooter .ddt-actions { flex: none; flex-wrap: nowrap; gap: 8px; margin-top: 0; }
1764
1844
  .ddt-accountFooter .ddt-button { flex: none; white-space: nowrap; }
@@ -1779,8 +1859,6 @@ var CSS = String.raw`
1779
1859
  .ddt-qrLayout { grid-template-columns: minmax(0, 1fr); justify-items: center; gap: 24px; }
1780
1860
  .ddt-qrColumn { width: 100%; min-width: 0; }
1781
1861
  .ddt-qrCopy { width: 100%; }
1782
- .ddt-metrics { gap: 8px; }
1783
- .ddt-metric { padding: 10px; }
1784
1862
  }
1785
1863
  @media (max-width: 720px) {
1786
1864
  .ddt-heading, .ddt-accountTop { flex-direction: column; align-items: stretch; }
@@ -1825,7 +1903,7 @@ function DingtalkIcon({ size = 28 }) {
1825
1903
  d: "M37.05 22.783c-6.758-5.216-14.378-12.128-22.73-19.538-.655-.585-1.242-.354-1.536.42-1.88 4.973-.058 9.386 2.889 11.932s7.368 4.912 10.058 6.155c.105.049.013.203-.093.163-4.953-2.182-8.397-3.765-13.07-7.368-.497-.388-1.01-.242-1.07.521-.384 4.748 2.657 8.483 6.058 9.745 2.1.781 4.398 1.212 6.53 1.474.109.015.084.178-.027.178-2.747.01-6.058-.654-8.935-1.751-.606-.233-.818.25-.722.633.491 2.008 2.974 5.076 6.926 5.73a12 12 0 0 0 2.228.115c.164 0 .208.089.154.217q-2.685 4.6-2.803 4.797c-.091.152-.036.275.156.275h3.543c.164 0 .264.106.18.246l-4.958 8.196c-.191.328.035.565.395.301s15.212-11.133 15.636-11.448c.195-.142.148-.327-.124-.327h-3.18c-.206 0-.252-.14-.111-.28.14-.141 3.602-3.594 4.837-4.888 1.283-1.35 1.938-3.825-.231-5.498"
1826
1904
  }));
1827
1905
  }
1828
- var Button = React8.forwardRef(function Button2({ children, kind = "secondary", className = "", ...props }, ref) {
1906
+ var Button = React9.forwardRef(function Button2({ children, kind = "secondary", className = "", ...props }, ref) {
1829
1907
  return h2("button", {
1830
1908
  ...props,
1831
1909
  ref,
@@ -1921,13 +1999,13 @@ function EmptyView({ busy, onStart }) {
1921
1999
  );
1922
2000
  }
1923
2001
  function QrPanel({ provision, now, busy, onRefresh, onCancel }) {
1924
- const [imageFailed, setImageFailed] = React8.useState(false);
2002
+ const [imageFailed, setImageFailed] = React9.useState(false);
1925
2003
  const source = safeQrSource(provision.qrCodeDataUrl);
1926
2004
  const remaining = Math.max(0, provision.expiresAt - now);
1927
2005
  const expired = remaining === 0 || provision.status === "expired";
1928
2006
  const duration = Math.max(1, provision.durationMs ?? 10 * 6e4);
1929
2007
  const progress = Math.round(Math.min(1, remaining / duration) * 100);
1930
- React8.useEffect(() => setImageFailed(false), [source]);
2008
+ React9.useEffect(() => setImageFailed(false), [source]);
1931
2009
  return h2(
1932
2010
  "div",
1933
2011
  { className: "ddt-card dim-surfaceCard" },
@@ -2044,8 +2122,8 @@ function checkedTime(value) {
2044
2122
  }
2045
2123
  }
2046
2124
  function RemoveConfirmation({ account, busy, onConfirm, onCancel }) {
2047
- const cancelRef = React8.useRef(null);
2048
- React8.useEffect(() => cancelRef.current?.focus(), []);
2125
+ const cancelRef = React9.useRef(null);
2126
+ React9.useEffect(() => cancelRef.current?.focus(), []);
2049
2127
  return h2(
2050
2128
  "div",
2051
2129
  {
@@ -2106,28 +2184,14 @@ function AccountCard({
2106
2184
  h2("p", { title: account.bot.clientIdMasked }, account.bot.clientIdMasked)
2107
2185
  )
2108
2186
  ),
2109
- h2(
2110
- "div",
2111
- { className: "ddt-health dim-botHealth" },
2112
- h2("span", { className: "ddt-dot dim-healthDot", "data-tone": tone }),
2113
- h2("span", null, stateLabel2)
2114
- )
2115
- ),
2116
- h2(
2117
- "dl",
2118
- { className: "ddt-metrics dim-botMetrics" },
2119
- h2(
2120
- "div",
2121
- { className: "ddt-metric dim-botMetric" },
2122
- h2("dt", null, "\u6D88\u606F\u901A\u9053"),
2123
- h2("dd", null, account.connected ? "Stream \u957F\u8FDE\u63A5" : "\u79BB\u7EBF")
2124
- ),
2125
- h2(
2126
- "div",
2127
- { className: "ddt-metric dim-botMetric" },
2128
- h2("dt", null, "\u6700\u8FD1\u68C0\u67E5"),
2129
- h2("dd", null, checkedTime(account.health.lastCheckedAt))
2130
- )
2187
+ h2(BotStatusMeta, {
2188
+ className: "ddt-health",
2189
+ dotClassName: "ddt-dot",
2190
+ tone,
2191
+ stateLabel: stateLabel2,
2192
+ lastCheckedAt: account.health.lastCheckedAt,
2193
+ formatCheckedTime: checkedTime
2194
+ })
2131
2195
  ),
2132
2196
  h2(WorkspaceEditor, {
2133
2197
  workspace: account.workspace,
@@ -2142,24 +2206,28 @@ function AccountCard({
2142
2206
  h2(
2143
2207
  "div",
2144
2208
  { className: "ddt-accountFooter dim-cardFooter" },
2145
- summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
2146
- feedback ? h2("div", {
2147
- className: "ddt-summary dim-cardSummary",
2148
- role: "status"
2149
- }, feedback) : null,
2150
2209
  h2(
2151
2210
  "div",
2152
- { className: "ddt-actions dim-cardActions" },
2211
+ { className: "dim-cardFooterLayout" },
2153
2212
  h2(
2154
- Button,
2155
- { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) },
2156
- busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"
2213
+ "div",
2214
+ { className: "ddt-actions dim-cardActions" },
2215
+ h2(
2216
+ Button,
2217
+ { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) },
2218
+ busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"
2219
+ ),
2220
+ h2(
2221
+ Button,
2222
+ { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) },
2223
+ "\u79FB\u9664\u63A5\u5165"
2224
+ )
2157
2225
  ),
2158
- h2(
2159
- Button,
2160
- { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) },
2161
- "\u79FB\u9664\u63A5\u5165"
2162
- )
2226
+ summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
2227
+ feedback ? h2("div", {
2228
+ className: "ddt-summary dim-cardFeedback",
2229
+ role: "status"
2230
+ }, feedback) : null
2163
2231
  )
2164
2232
  )
2165
2233
  ),
@@ -2175,11 +2243,11 @@ function AccountList(props) {
2175
2243
  return h2(
2176
2244
  "section",
2177
2245
  { className: "dim-listSection" },
2178
- h2(
2179
- "div",
2180
- { className: "ddt-listHeading dim-listHeading" },
2181
- h2("h3", null, "\u5DF2\u63A5\u5165\u7684\u9489\u9489\u673A\u5668\u4EBA")
2182
- ),
2246
+ h2(ChannelListHeading, {
2247
+ className: "ddt-listHeading",
2248
+ title: "\u5DF2\u63A5\u5165\u7684\u9489\u9489\u673A\u5668\u4EBA",
2249
+ connectionLabel: "Stream \u957F\u8FDE\u63A5"
2250
+ }),
2183
2251
  h2("ul", { className: "ddt-list dim-botList" }, props.bots.map((account) => h2(
2184
2252
  "li",
2185
2253
  { key: account.botId },
@@ -2200,7 +2268,7 @@ function AccountList(props) {
2200
2268
  }
2201
2269
  var EMPTY_TOTALS = Object.freeze({ configured: 0, connected: 0 });
2202
2270
  function DingtalkSettingsTab({ rpcCall }) {
2203
- const [model, setModel] = React8.useState({
2271
+ const [model, setModel] = React9.useState({
2204
2272
  phase: "loading",
2205
2273
  bots: [],
2206
2274
  totals: EMPTY_TOTALS,
@@ -2208,22 +2276,22 @@ function DingtalkSettingsTab({ rpcCall }) {
2208
2276
  error: null,
2209
2277
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
2210
2278
  });
2211
- const [provision, setProvision] = React8.useState(null);
2212
- const [busy, setBusy] = React8.useState(false);
2213
- const [busyByBot, setBusyByBot] = React8.useState({});
2214
- const [feedbackByBot, setFeedbackByBot] = React8.useState({});
2215
- const [removeTarget, setRemoveTarget] = React8.useState(null);
2216
- const [credentialOpen, setCredentialOpen] = React8.useState(false);
2217
- const [credentialError, setCredentialError] = React8.useState(null);
2218
- const [notice, setNotice] = React8.useState("");
2219
- const [now, setNow] = React8.useState(() => Date.now());
2220
- const addButtonRef = React8.useRef(null);
2221
- const mountedRef = React8.useRef(true);
2222
- const statusRequestRef = React8.useRef(0);
2279
+ const [provision, setProvision] = React9.useState(null);
2280
+ const [busy, setBusy] = React9.useState(false);
2281
+ const [busyByBot, setBusyByBot] = React9.useState({});
2282
+ const [feedbackByBot, setFeedbackByBot] = React9.useState({});
2283
+ const [removeTarget, setRemoveTarget] = React9.useState(null);
2284
+ const [credentialOpen, setCredentialOpen] = React9.useState(false);
2285
+ const [credentialError, setCredentialError] = React9.useState(null);
2286
+ const [notice, setNotice] = React9.useState("");
2287
+ const [now, setNow] = React9.useState(() => Date.now());
2288
+ const addButtonRef = React9.useRef(null);
2289
+ const mountedRef = React9.useRef(true);
2290
+ const statusRequestRef = React9.useRef(0);
2223
2291
  const workspaceFence = useWorkspaceSnapshotFence();
2224
- const noticeFrameRef = React8.useRef(null);
2225
- const focusFrameRef = React8.useRef(null);
2226
- React8.useEffect(() => {
2292
+ const noticeFrameRef = React9.useRef(null);
2293
+ const focusFrameRef = React9.useRef(null);
2294
+ React9.useEffect(() => {
2227
2295
  mountedRef.current = true;
2228
2296
  return () => {
2229
2297
  mountedRef.current = false;
@@ -2238,8 +2306,8 @@ function DingtalkSettingsTab({ rpcCall }) {
2238
2306
  }
2239
2307
  };
2240
2308
  }, []);
2241
- React8.useEffect(() => installDingtalkStyles(), []);
2242
- const announce = React8.useCallback((message) => {
2309
+ React9.useEffect(() => installDingtalkStyles(), []);
2310
+ const announce = React9.useCallback((message) => {
2243
2311
  if (!mountedRef.current) return;
2244
2312
  if (noticeFrameRef.current !== null) {
2245
2313
  window.cancelAnimationFrame(noticeFrameRef.current);
@@ -2253,7 +2321,7 @@ function DingtalkSettingsTab({ rpcCall }) {
2253
2321
  });
2254
2322
  }
2255
2323
  }, []);
2256
- const discardStaleFeedback = React8.useCallback((snapshot) => {
2324
+ const discardStaleFeedback = React9.useCallback((snapshot) => {
2257
2325
  const botsById = new Map(snapshot.bots.map((bot) => [bot.botId, bot]));
2258
2326
  setFeedbackByBot((current) => {
2259
2327
  let changed = false;
@@ -2268,7 +2336,7 @@ function DingtalkSettingsTab({ rpcCall }) {
2268
2336
  return changed ? next : current;
2269
2337
  });
2270
2338
  }, []);
2271
- const focusAddButton = React8.useCallback(() => {
2339
+ const focusAddButton = React9.useCallback(() => {
2272
2340
  if (!mountedRef.current) return;
2273
2341
  if (focusFrameRef.current !== null) window.cancelAnimationFrame(focusFrameRef.current);
2274
2342
  focusFrameRef.current = window.requestAnimationFrame(() => {
@@ -2276,11 +2344,11 @@ function DingtalkSettingsTab({ rpcCall }) {
2276
2344
  if (mountedRef.current) addButtonRef.current?.focus();
2277
2345
  });
2278
2346
  }, []);
2279
- const invoke = React8.useCallback(async (endpoint, payload = {}, signal) => {
2347
+ const invoke = React9.useCallback(async (endpoint, payload = {}, signal) => {
2280
2348
  if (typeof rpcCall !== "function") throw new TypeError("\u9489\u9489\u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
2281
2349
  return unwrapRpcResult(await rpcCall(endpoint, payload, signal));
2282
2350
  }, [rpcCall]);
2283
- const loadStatus = React8.useCallback(async ({
2351
+ const loadStatus = React9.useCallback(async ({
2284
2352
  signal,
2285
2353
  silent = false,
2286
2354
  restoreProvisioning = false
@@ -2324,12 +2392,12 @@ function DingtalkSettingsTab({ rpcCall }) {
2324
2392
  return void 0;
2325
2393
  }
2326
2394
  }, [discardStaleFeedback, invoke, workspaceFence]);
2327
- React8.useEffect(() => {
2395
+ React9.useEffect(() => {
2328
2396
  const controller = new AbortController();
2329
2397
  void loadStatus({ signal: controller.signal, restoreProvisioning: true });
2330
2398
  return () => controller.abort();
2331
2399
  }, [loadStatus]);
2332
- React8.useEffect(() => {
2400
+ React9.useEffect(() => {
2333
2401
  if (model.phase !== "ready") return void 0;
2334
2402
  const controller = new AbortController();
2335
2403
  let running = false;
@@ -2348,14 +2416,14 @@ function DingtalkSettingsTab({ rpcCall }) {
2348
2416
  window.clearInterval(timer);
2349
2417
  };
2350
2418
  }, [loadStatus, model.phase]);
2351
- React8.useEffect(() => {
2419
+ React9.useEffect(() => {
2352
2420
  if (!provision || !ACTIVE_PROVISION_STATES.has(provision.status)) return void 0;
2353
2421
  const timer = window.setInterval(() => {
2354
2422
  if (mountedRef.current) setNow(Date.now());
2355
2423
  }, 1e3);
2356
2424
  return () => window.clearInterval(timer);
2357
2425
  }, [provision?.attemptId, provision?.status]);
2358
- const startProvisioning = React8.useCallback(async ({ replace = false } = {}) => {
2426
+ const startProvisioning = React9.useCallback(async ({ replace = false } = {}) => {
2359
2427
  if (!mountedRef.current) return;
2360
2428
  setCredentialOpen(false);
2361
2429
  setCredentialError(null);
@@ -2393,7 +2461,7 @@ function DingtalkSettingsTab({ rpcCall }) {
2393
2461
  if (mountedRef.current) setBusy(false);
2394
2462
  }
2395
2463
  }, [announce, invoke, provision?.attemptId]);
2396
- const bindCredentials = React8.useCallback(async ({ identity, secret }) => {
2464
+ const bindCredentials = React9.useCallback(async ({ identity, secret }) => {
2397
2465
  if (!mountedRef.current) return;
2398
2466
  const snapshotVersion = workspaceFence.beginMutation();
2399
2467
  setBusy(true);
@@ -2425,7 +2493,7 @@ function DingtalkSettingsTab({ rpcCall }) {
2425
2493
  if (mountedRef.current) setBusy(false);
2426
2494
  }
2427
2495
  }, [announce, discardStaleFeedback, invoke, loadStatus, workspaceFence]);
2428
- const cancelProvisioning = React8.useCallback(async () => {
2496
+ const cancelProvisioning = React9.useCallback(async () => {
2429
2497
  if (!mountedRef.current) return;
2430
2498
  setBusy(true);
2431
2499
  try {
@@ -2443,7 +2511,7 @@ function DingtalkSettingsTab({ rpcCall }) {
2443
2511
  if (mountedRef.current) setBusy(false);
2444
2512
  }
2445
2513
  }, [announce, focusAddButton, invoke, provision?.attemptId, provision?.status]);
2446
- React8.useEffect(() => {
2514
+ React9.useEffect(() => {
2447
2515
  const attemptId = provision?.attemptId;
2448
2516
  if (!attemptId || !ACTIVE_PROVISION_STATES.has(provision.status)) return void 0;
2449
2517
  const controller = new AbortController();
@@ -2502,7 +2570,7 @@ function DingtalkSettingsTab({ rpcCall }) {
2502
2570
  timer = null;
2503
2571
  };
2504
2572
  }, [announce, invoke, loadStatus, provision?.attemptId, provision?.pollIntervalMs, provision?.status]);
2505
- const setBotBusy = React8.useCallback((botId, operation) => {
2573
+ const setBotBusy = React9.useCallback((botId, operation) => {
2506
2574
  if (!mountedRef.current) return;
2507
2575
  setBusyByBot((current) => {
2508
2576
  const next = { ...current };
@@ -2511,7 +2579,7 @@ function DingtalkSettingsTab({ rpcCall }) {
2511
2579
  return next;
2512
2580
  });
2513
2581
  }, []);
2514
- const runBotAction = React8.useCallback(async ({ account, operation, endpoint, payload, success }) => {
2582
+ const runBotAction = React9.useCallback(async ({ account, operation, endpoint, payload, success }) => {
2515
2583
  if (!mountedRef.current) return void 0;
2516
2584
  const snapshotVersion = workspaceFence.beginMutation();
2517
2585
  setBotBusy(account.botId, operation);
@@ -2565,7 +2633,7 @@ function DingtalkSettingsTab({ rpcCall }) {
2565
2633
  if (mountedRef.current) setBotBusy(account.botId, null);
2566
2634
  }
2567
2635
  }, [announce, discardStaleFeedback, invoke, loadStatus, setBotBusy, workspaceFence]);
2568
- const reconnect = React8.useCallback((account) => runBotAction({
2636
+ const reconnect = React9.useCallback((account) => runBotAction({
2569
2637
  account,
2570
2638
  operation: "reconnect",
2571
2639
  endpoint: DINGTALK_ENDPOINTS.reconnectBot,
@@ -2576,7 +2644,7 @@ function DingtalkSettingsTab({ rpcCall }) {
2576
2644
  return connectionTestFeedback(snapshot.testMessage) ?? "\u9489\u9489\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\u3002";
2577
2645
  }
2578
2646
  }), [runBotAction]);
2579
- const saveWorkspace = React8.useCallback(async (account, workspace) => {
2647
+ const saveWorkspace = React9.useCallback(async (account, workspace) => {
2580
2648
  const workspaceVersion = workspaceFence.beginMutation();
2581
2649
  setBotBusy(account.botId, "workspace");
2582
2650
  try {
@@ -2601,7 +2669,7 @@ function DingtalkSettingsTab({ rpcCall }) {
2601
2669
  if (mountedRef.current) setBotBusy(account.botId, null);
2602
2670
  }
2603
2671
  }, [discardStaleFeedback, invoke, loadStatus, setBotBusy, workspaceFence]);
2604
- const saveAgentPreset = React8.useCallback(async (account, agentPreset) => {
2672
+ const saveAgentPreset = React9.useCallback(async (account, agentPreset) => {
2605
2673
  const snapshotVersion = workspaceFence.beginMutation();
2606
2674
  setBotBusy(account.botId, "preset");
2607
2675
  try {
@@ -2626,7 +2694,7 @@ function DingtalkSettingsTab({ rpcCall }) {
2626
2694
  if (mountedRef.current) setBotBusy(account.botId, null);
2627
2695
  }
2628
2696
  }, [discardStaleFeedback, invoke, loadStatus, setBotBusy, workspaceFence]);
2629
- const remove = React8.useCallback(async (account) => {
2697
+ const remove = React9.useCallback(async (account) => {
2630
2698
  const snapshot = await runBotAction({
2631
2699
  account,
2632
2700
  operation: "delete",
@@ -2710,7 +2778,7 @@ function DingtalkSettingsTab({ rpcCall }) {
2710
2778
  h2(Button, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
2711
2779
  )
2712
2780
  ) : h2(
2713
- React8.Fragment,
2781
+ React9.Fragment,
2714
2782
  null,
2715
2783
  credentialView,
2716
2784
  provisionView,
@@ -2829,8 +2897,8 @@ var normalizeSnapshot2 = api.normalizeSnapshot;
2829
2897
  var presentError2 = api.presentError;
2830
2898
 
2831
2899
  // plugin-src/client/channels/shared/token-channel.js
2832
- var React9 = __toESM(require("react"), 1);
2833
- var Button3 = React9.forwardRef(function Button4({ children, kind = "secondary", className = "", ...props }, ref) {
2900
+ var React10 = __toESM(require("react"), 1);
2901
+ var Button3 = React10.forwardRef(function Button4({ children, kind = "secondary", className = "", ...props }, ref) {
2834
2902
  return h2("button", {
2835
2903
  ...props,
2836
2904
  ref,
@@ -2912,28 +2980,14 @@ function createTokenChannelSettings(definition) {
2912
2980
  h2("p", null, identity)
2913
2981
  )
2914
2982
  ),
2915
- h2(
2916
- "div",
2917
- { className: "ddt-health dim-botHealth" },
2918
- h2("span", { className: "ddt-dot dim-healthDot", "data-tone": tone }),
2919
- h2("span", null, stateLabel2)
2920
- )
2921
- ),
2922
- h2(
2923
- "dl",
2924
- { className: "ddt-metrics dim-botMetrics" },
2925
- h2(
2926
- "div",
2927
- { className: "ddt-metric dim-botMetric" },
2928
- h2("dt", null, "\u6D88\u606F\u901A\u9053"),
2929
- h2("dd", null, account.connected ? connectionLabel : "\u79BB\u7EBF")
2930
- ),
2931
- h2(
2932
- "div",
2933
- { className: "ddt-metric dim-botMetric" },
2934
- h2("dt", null, "\u6700\u8FD1\u68C0\u67E5"),
2935
- h2("dd", null, checkedTime2(account.health.lastCheckedAt))
2936
- )
2983
+ h2(BotStatusMeta, {
2984
+ className: "ddt-health",
2985
+ dotClassName: "ddt-dot",
2986
+ tone,
2987
+ stateLabel: stateLabel2,
2988
+ lastCheckedAt: account.health.lastCheckedAt,
2989
+ formatCheckedTime: checkedTime2
2990
+ })
2937
2991
  ),
2938
2992
  h2(WorkspaceEditor, {
2939
2993
  workspace: account.workspace,
@@ -2953,22 +3007,29 @@ function createTokenChannelSettings(definition) {
2953
3007
  h2(
2954
3008
  "div",
2955
3009
  { className: "ddt-accountFooter dim-cardFooter" },
2956
- summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
2957
- testNotice ? h2("div", { className: "ddt-summary dim-cardSummary", role: "status" }, testNotice) : null,
2958
3010
  h2(
2959
3011
  "div",
2960
- { className: "ddt-actions dim-cardActions" },
2961
- h2(Button3, {
2962
- className: "dim-cardAction",
2963
- onClick: onReconnect,
2964
- disabled: Boolean(busy)
2965
- }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
2966
- h2(Button3, {
2967
- className: "dim-cardAction",
2968
- kind: "danger",
2969
- onClick: onRequestRemove,
2970
- disabled: Boolean(busy)
2971
- }, "\u79FB\u9664\u63A5\u5165")
3012
+ { className: "dim-cardFooterLayout" },
3013
+ h2(
3014
+ "div",
3015
+ { className: "ddt-actions dim-cardActions" },
3016
+ h2(Button3, {
3017
+ className: "dim-cardAction",
3018
+ onClick: onReconnect,
3019
+ disabled: Boolean(busy)
3020
+ }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
3021
+ h2(Button3, {
3022
+ className: "dim-cardAction",
3023
+ kind: "danger",
3024
+ onClick: onRequestRemove,
3025
+ disabled: Boolean(busy)
3026
+ }, "\u79FB\u9664\u63A5\u5165")
3027
+ ),
3028
+ summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
3029
+ testNotice ? h2("div", {
3030
+ className: "ddt-summary dim-cardFeedback",
3031
+ role: "status"
3032
+ }, testNotice) : null
2972
3033
  )
2973
3034
  )
2974
3035
  ),
@@ -2991,22 +3052,22 @@ function createTokenChannelSettings(definition) {
2991
3052
  );
2992
3053
  }
2993
3054
  function SettingsTab({ rpcCall }) {
2994
- const [model, setModel] = React9.useState({
3055
+ const [model, setModel] = React10.useState({
2995
3056
  phase: "loading",
2996
3057
  bots: [],
2997
3058
  totals: { configured: 0, connected: 0 },
2998
3059
  error: null,
2999
3060
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
3000
3061
  });
3001
- const [credentialOpen, setCredentialOpen] = React9.useState(false);
3002
- const [credentialError, setCredentialError] = React9.useState(null);
3003
- const [busy, setBusy] = React9.useState(false);
3004
- const [busyByBot, setBusyByBot] = React9.useState({});
3005
- const [testNoticeByBot, setTestNoticeByBot] = React9.useState({});
3006
- const [removeTarget, setRemoveTarget] = React9.useState(null);
3007
- const mounted = React9.useRef(true);
3062
+ const [credentialOpen, setCredentialOpen] = React10.useState(false);
3063
+ const [credentialError, setCredentialError] = React10.useState(null);
3064
+ const [busy, setBusy] = React10.useState(false);
3065
+ const [busyByBot, setBusyByBot] = React10.useState({});
3066
+ const [testNoticeByBot, setTestNoticeByBot] = React10.useState({});
3067
+ const [removeTarget, setRemoveTarget] = React10.useState(null);
3068
+ const mounted = React10.useRef(true);
3008
3069
  const workspaceFence = useWorkspaceSnapshotFence();
3009
- React9.useEffect(() => {
3070
+ React10.useEffect(() => {
3010
3071
  const disposeDingtalk = installDingtalkStyles();
3011
3072
  const disposeChannel = installStyles();
3012
3073
  mounted.current = true;
@@ -3016,11 +3077,11 @@ function createTokenChannelSettings(definition) {
3016
3077
  disposeDingtalk();
3017
3078
  };
3018
3079
  }, []);
3019
- const invoke = React9.useCallback(async (endpoint, payload = {}, signal) => {
3080
+ const invoke = React10.useCallback(async (endpoint, payload = {}, signal) => {
3020
3081
  if (typeof rpcCall !== "function") throw new TypeError(`${channel4} \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5`);
3021
3082
  return api4.unwrapRpcResult(await rpcCall(endpoint, payload, signal));
3022
3083
  }, [rpcCall]);
3023
- const loadStatus = React9.useCallback(async ({ signal, silent = false } = {}) => {
3084
+ const loadStatus = React10.useCallback(async ({ signal, silent = false } = {}) => {
3024
3085
  const workspaceVersion = workspaceFence.beginStatus();
3025
3086
  if (workspaceVersion === null) return;
3026
3087
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
@@ -3044,12 +3105,12 @@ function createTokenChannelSettings(definition) {
3044
3105
  }
3045
3106
  }
3046
3107
  }, [invoke, workspaceFence]);
3047
- React9.useEffect(() => {
3108
+ React10.useEffect(() => {
3048
3109
  const controller = new AbortController();
3049
3110
  void loadStatus({ signal: controller.signal });
3050
3111
  return () => controller.abort();
3051
3112
  }, [loadStatus]);
3052
- React9.useEffect(() => {
3113
+ React10.useEffect(() => {
3053
3114
  if (model.phase !== "ready") return void 0;
3054
3115
  const controller = new AbortController();
3055
3116
  const timer = window.setInterval(
@@ -3061,7 +3122,7 @@ function createTokenChannelSettings(definition) {
3061
3122
  window.clearInterval(timer);
3062
3123
  };
3063
3124
  }, [loadStatus, model.phase]);
3064
- const bindCredentials = React9.useCallback(async (values) => {
3125
+ const bindCredentials = React10.useCallback(async (values) => {
3065
3126
  const snapshotVersion = workspaceFence.beginMutation();
3066
3127
  setBusy(true);
3067
3128
  setCredentialError(null);
@@ -3089,7 +3150,7 @@ function createTokenChannelSettings(definition) {
3089
3150
  if (mounted.current) setBusy(false);
3090
3151
  }
3091
3152
  }, [invoke, loadStatus, workspaceFence]);
3092
- const botAction = React9.useCallback(async (account, operation, endpoint, payload) => {
3153
+ const botAction = React10.useCallback(async (account, operation, endpoint, payload) => {
3093
3154
  const snapshotVersion = workspaceFence.beginMutation();
3094
3155
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
3095
3156
  try {
@@ -3131,11 +3192,11 @@ function createTokenChannelSettings(definition) {
3131
3192
  const botList = model.bots.length > 0 ? h2(
3132
3193
  "section",
3133
3194
  { className: "dim-listSection" },
3134
- h2(
3135
- "div",
3136
- { className: "ddt-listHeading dim-listHeading" },
3137
- h2("h3", null, `\u5DF2\u63A5\u5165\u7684 ${channel4} \u673A\u5668\u4EBA`)
3138
- ),
3195
+ h2(ChannelListHeading, {
3196
+ className: "ddt-listHeading",
3197
+ title: `\u5DF2\u63A5\u5165\u7684 ${channel4} \u673A\u5668\u4EBA`,
3198
+ connectionLabel
3199
+ }),
3139
3200
  h2("ul", { className: "ddt-list dim-botList" }, model.bots.map((account) => h2("li", { key: account.botId }, h2(AccountCard5, {
3140
3201
  account,
3141
3202
  busy: busyByBot[account.botId],
@@ -3226,7 +3287,7 @@ function createTokenChannelSettings(definition) {
3226
3287
  h2(Button3, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
3227
3288
  )
3228
3289
  ) : h2(
3229
- React9.Fragment,
3290
+ React10.Fragment,
3230
3291
  null,
3231
3292
  credentialOpen ? CredentialPanel ? h2(CredentialPanel, {
3232
3293
  busy,
@@ -3327,7 +3388,7 @@ var DiscordSettingsTab = channel.SettingsTab;
3327
3388
  var DiscordAccountCard = channel.AccountCard;
3328
3389
 
3329
3390
  // plugin-src/client/channels/feishu/index.js
3330
- var React11 = __toESM(require("react"), 1);
3391
+ var React12 = __toESM(require("react"), 1);
3331
3392
 
3332
3393
  // plugin-src/client/channels/feishu/api.js
3333
3394
  var FEISHU_RPC_CHANNEL = "/feishu";
@@ -3585,7 +3646,7 @@ function formatRemaining2(milliseconds) {
3585
3646
  }
3586
3647
 
3587
3648
  // plugin-src/client/lifecycle.js
3588
- var React10 = __toESM(require("react"), 1);
3649
+ var React11 = __toESM(require("react"), 1);
3589
3650
  function createPollScheduler({ setTimeoutFn, clearTimeoutFn }) {
3590
3651
  let disposed = false;
3591
3652
  let timer;
@@ -3647,8 +3708,8 @@ function createAnimationFrameScheduler({ requestFrame, cancelFrame }) {
3647
3708
  };
3648
3709
  }
3649
3710
  function useAnimationFrameScheduler() {
3650
- const schedulerRef = React10.useRef(null);
3651
- React10.useEffect(() => {
3711
+ const schedulerRef = React11.useRef(null);
3712
+ React11.useEffect(() => {
3652
3713
  const scheduler = createAnimationFrameScheduler({
3653
3714
  requestFrame: (callback) => window.requestAnimationFrame(callback),
3654
3715
  cancelFrame: (frame) => window.cancelAnimationFrame(frame)
@@ -3659,7 +3720,7 @@ function useAnimationFrameScheduler() {
3659
3720
  if (schedulerRef.current === scheduler) schedulerRef.current = null;
3660
3721
  };
3661
3722
  }, []);
3662
- return React10.useCallback(
3723
+ return React11.useCallback(
3663
3724
  (callback, key) => schedulerRef.current?.schedule(callback, key) ?? false,
3664
3725
  []
3665
3726
  );
@@ -4069,10 +4130,6 @@ var CSS3 = String.raw`
4069
4130
  .bxf-healthPill[data-health="degraded"], .bxf-healthPill[data-health="checking"], .bxf-healthPill[data-health="connecting"] { color: var(--bxf-warning); background: color-mix(in srgb, var(--bxf-warning) 10%, transparent); }
4070
4131
  .bxf-healthPill[data-health="offline"], .bxf-healthPill[data-health="error"] { color: var(--bxf-error); background: color-mix(in srgb, var(--bxf-error) 10%, transparent); }
4071
4132
 
4072
- .bxf-statusGrid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin-top: 22px; }
4073
- .bxf-metric { min-width: 0; border: 1px solid var(--dsw-alias-border-l2, #dee0e3); border-radius: 9px; padding: 12px 13px; background: var(--dsw-alias-bg-module-platform, #f7f8fa); }
4074
- .bxf-metric dt { color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 11px; line-height: 17px; }
4075
- .bxf-metric dd { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-primary, #1f2329); font-size: 12px; line-height: 18px; font-weight: 550; margin: 3px 0 0; }
4076
4133
 
4077
4134
  .bxf-responseMode { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr) max-content; align-items: center; column-gap: 10px; row-gap: 5px; margin-top: 6px; padding: 8px 10px; border: 1px solid var(--dsw-alias-border-l1, #eef0f3); border-radius: 9px; background: var(--dsw-alias-bg-module-platform, #f7f8fa); }
4078
4135
  .bxf-responseModeHeader { display: contents; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: normal; }
@@ -4184,7 +4241,6 @@ var CSS3 = String.raw`
4184
4241
  .bxf-qrLayout { grid-template-columns: minmax(0, 1fr); justify-items: center; }
4185
4242
  .bxf-botProvision .bxf-qrLayout { grid-template-columns: minmax(0, 1fr); }
4186
4243
  .bxf-qrCopy { width: 100%; }
4187
- .bxf-statusGrid { grid-template-columns: minmax(0, 1fr); }
4188
4244
  .bxf-connectedTop { align-items: flex-start; flex-direction: column; }
4189
4245
  .bxf-inlineError { grid-template-columns: minmax(0, 1fr); padding: 20px; }
4190
4246
  .bxf-statusNotice { align-items: flex-start; flex-wrap: wrap; }
@@ -4286,7 +4342,7 @@ function QrIcon({ size = 58 }) {
4286
4342
  fill: "currentColor"
4287
4343
  }));
4288
4344
  }
4289
- var Button5 = React11.forwardRef(function Button6({ children, kind = "secondary", size, icon, className = "", ...props }, ref) {
4345
+ var Button5 = React12.forwardRef(function Button6({ children, kind = "secondary", size, icon, className = "", ...props }, ref) {
4290
4346
  return h2("button", {
4291
4347
  ...props,
4292
4348
  ref,
@@ -4403,7 +4459,7 @@ function safeQrSource2(value) {
4403
4459
  return /^data:image\/(?:png|webp|svg\+xml)(?:;charset=[^;,]+)?;base64,/i.test(value) ? value : void 0;
4404
4460
  }
4405
4461
  function QrPane({ provision, now, onRefresh, onCancel, busy }) {
4406
- const [imageFailed, setImageFailed] = React11.useState(false);
4462
+ const [imageFailed, setImageFailed] = React12.useState(false);
4407
4463
  const qrSource = safeQrSource2(provision.qrCodeDataUrl);
4408
4464
  const href = safeVerificationHref(provision.verificationUrl);
4409
4465
  const remaining = Math.max(0, provision.expiresAt - now);
@@ -4412,7 +4468,7 @@ function QrPane({ provision, now, onRefresh, onCancel, busy }) {
4412
4468
  const repairing = isCallbackRepair(provision);
4413
4469
  const grantingGroupMessages = isGroupMessagePermission(provision);
4414
4470
  const botName = provision.botName ?? "\u6B64\u673A\u5668\u4EBA";
4415
- React11.useEffect(() => setImageFailed(false), [qrSource]);
4471
+ React12.useEffect(() => setImageFailed(false), [qrSource]);
4416
4472
  return h2(
4417
4473
  "div",
4418
4474
  { className: "bxf-card bxf-provisionCard dim-surfaceCard" },
@@ -4575,11 +4631,11 @@ function connectionTestNotice2(value) {
4575
4631
  return value?.testMessage ? "\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002" : null;
4576
4632
  }
4577
4633
  function RemoveConfirmation2({ bot, busy, onConfirm, onCancel }) {
4578
- const cancelRef = React11.useRef(null);
4634
+ const cancelRef = React12.useRef(null);
4579
4635
  const idPart = bot.botId.replace(/[^a-zA-Z0-9_-]/g, "-");
4580
4636
  const titleId = `bxf-remove-title-${idPart}`;
4581
4637
  const descriptionId = `bxf-remove-description-${idPart}`;
4582
- React11.useEffect(() => cancelRef.current?.focus(), []);
4638
+ React12.useEffect(() => cancelRef.current?.focus(), []);
4583
4639
  return h2(
4584
4640
  "div",
4585
4641
  {
@@ -4621,9 +4677,9 @@ function GroupResponseModeEditor({
4621
4677
  onAuthorize
4622
4678
  }) {
4623
4679
  const current = normalizeGroupResponseMode(value);
4624
- const [saving, setSaving] = React11.useState(false);
4625
- const [authorizing, setAuthorizing] = React11.useState(false);
4626
- const [error, setError] = React11.useState(null);
4680
+ const [saving, setSaving] = React12.useState(false);
4681
+ const [authorizing, setAuthorizing] = React12.useState(false);
4682
+ const [error, setError] = React12.useState(null);
4627
4683
  const change = async (event) => {
4628
4684
  const next = normalizeGroupResponseMode(event.target.value);
4629
4685
  if (next === current || saving || disabled) return;
@@ -4757,28 +4813,15 @@ function BotCard({
4757
4813
  h2("p", { title: bot.appIdMasked }, bot.appIdMasked ?? "\u5E94\u7528\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58")
4758
4814
  )
4759
4815
  ),
4760
- h2(
4761
- "div",
4762
- { className: "bxf-healthPill dim-botHealth", "data-health": stateForDisplay },
4763
- h2("span", { className: "bxf-dot dim-healthDot", "data-tone": tone }),
4764
- h2("span", null, HEALTH_LABELS[stateForDisplay] ?? "\u72B6\u6001\u672A\u77E5")
4765
- )
4766
- ),
4767
- h2(
4768
- "dl",
4769
- { className: "bxf-statusGrid dim-botMetrics" },
4770
- h2(
4771
- "div",
4772
- { className: "bxf-metric dim-botMetric" },
4773
- h2("dt", null, "\u6D88\u606F\u901A\u9053"),
4774
- h2("dd", null, connected ? "\u957F\u8FDE\u63A5" : stateForDisplay === "connecting" ? "\u8FDE\u63A5\u4E2D" : "\u5DF2\u65AD\u5F00")
4775
- ),
4776
- h2(
4777
- "div",
4778
- { className: "bxf-metric dim-botMetric" },
4779
- h2("dt", null, "\u6700\u8FD1\u68C0\u67E5"),
4780
- h2("dd", null, formatCheckedTime(health.lastCheckedAt))
4781
- )
4816
+ h2(BotStatusMeta, {
4817
+ className: "bxf-healthPill",
4818
+ dotClassName: "bxf-dot",
4819
+ tone,
4820
+ stateLabel: HEALTH_LABELS[stateForDisplay] ?? "\u72B6\u6001\u672A\u77E5",
4821
+ lastCheckedAt: health.lastCheckedAt,
4822
+ formatCheckedTime,
4823
+ healthState: stateForDisplay
4824
+ })
4782
4825
  ),
4783
4826
  h2(WorkspaceEditor, {
4784
4827
  workspace: connection.workspace,
@@ -4808,40 +4851,44 @@ function BotCard({
4808
4851
  h2(
4809
4852
  "div",
4810
4853
  { className: "bxf-connectedFooter dim-cardFooter" },
4811
- summary ? h2(
4812
- "div",
4813
- { className: "bxf-healthSummary dim-cardSummary", "data-error": actionError || connection.error ? "true" : void 0 },
4814
- summary
4815
- ) : null,
4816
- testNotice ? h2("div", {
4817
- className: "bxf-healthSummary dim-cardSummary",
4818
- role: "status"
4819
- }, testNotice) : null,
4820
4854
  h2(
4821
4855
  "div",
4822
- { className: "bxf-actions bxf-botActions dim-cardActions" },
4823
- h2(Button5, {
4824
- className: "dim-cardAction",
4825
- onClick: onReconnect,
4826
- disabled: Boolean(busy),
4827
- "aria-busy": busy === "reconnect" ? "true" : void 0,
4828
- "aria-label": `${connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"}${bot.name}`
4829
- }, busy === "reconnect" ? connected ? "\u68C0\u67E5\u4E2D\u2026" : "\u6B63\u5728\u8FDE\u63A5\u2026" : connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
4830
- h2(Button5, {
4831
- className: "bxf-repairButton dim-cardAction",
4832
- onClick: onRepairCallback,
4833
- disabled: Boolean(busy) || repairDisabled,
4834
- "aria-busy": busy === "callback-repair" ? "true" : void 0,
4835
- "aria-label": `\u4FEE\u590D${bot.name}\u7684\u5361\u7247\u6309\u94AE`
4836
- }, busy === "callback-repair" ? "\u7B49\u5F85\u626B\u7801\u2026" : "\u4FEE\u590D\u5361\u7247\u6309\u94AE"),
4837
- h2(Button5, {
4838
- className: "dim-cardAction",
4839
- kind: "danger",
4840
- onClick: onRequestRemove,
4841
- disabled: Boolean(busy),
4842
- ref: removeButtonRef,
4843
- "aria-label": `\u4ECE DeepSeek Harness \u79FB\u9664${bot.name}`
4844
- }, "\u79FB\u9664\u63A5\u5165")
4856
+ { className: "dim-cardFooterLayout" },
4857
+ h2(
4858
+ "div",
4859
+ { className: "bxf-actions bxf-botActions dim-cardActions" },
4860
+ h2(Button5, {
4861
+ className: "dim-cardAction",
4862
+ onClick: onReconnect,
4863
+ disabled: Boolean(busy),
4864
+ "aria-busy": busy === "reconnect" ? "true" : void 0,
4865
+ "aria-label": `${connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"}${bot.name}`
4866
+ }, busy === "reconnect" ? connected ? "\u68C0\u67E5\u4E2D\u2026" : "\u6B63\u5728\u8FDE\u63A5\u2026" : connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
4867
+ h2(Button5, {
4868
+ className: "bxf-repairButton dim-cardAction",
4869
+ onClick: onRepairCallback,
4870
+ disabled: Boolean(busy) || repairDisabled,
4871
+ "aria-busy": busy === "callback-repair" ? "true" : void 0,
4872
+ "aria-label": `\u4FEE\u590D${bot.name}\u7684\u5361\u7247\u6309\u94AE`
4873
+ }, busy === "callback-repair" ? "\u7B49\u5F85\u626B\u7801\u2026" : "\u4FEE\u590D\u5361\u7247\u6309\u94AE"),
4874
+ h2(Button5, {
4875
+ className: "dim-cardAction",
4876
+ kind: "danger",
4877
+ onClick: onRequestRemove,
4878
+ disabled: Boolean(busy),
4879
+ ref: removeButtonRef,
4880
+ "aria-label": `\u4ECE DeepSeek Harness \u79FB\u9664${bot.name}`
4881
+ }, "\u79FB\u9664\u63A5\u5165")
4882
+ ),
4883
+ summary ? h2(
4884
+ "div",
4885
+ { className: "bxf-healthSummary dim-cardSummary", "data-error": actionError || connection.error ? "true" : void 0 },
4886
+ summary
4887
+ ) : null,
4888
+ testNotice ? h2("div", {
4889
+ className: "bxf-healthSummary dim-cardFeedback",
4890
+ role: "status"
4891
+ }, testNotice) : null
4845
4892
  )
4846
4893
  )
4847
4894
  ),
@@ -4857,11 +4904,12 @@ function BotList(props) {
4857
4904
  return h2(
4858
4905
  "section",
4859
4906
  { className: "bxf-listSection dim-listSection", "aria-labelledby": "bxf-bot-list-title" },
4860
- h2(
4861
- "div",
4862
- { className: "bxf-listHeading dim-listHeading" },
4863
- h2("h3", { id: "bxf-bot-list-title" }, "\u5DF2\u63A5\u5165\u7684\u673A\u5668\u4EBA")
4864
- ),
4907
+ h2(ChannelListHeading, {
4908
+ className: "bxf-listHeading",
4909
+ id: "bxf-bot-list-title",
4910
+ title: "\u5DF2\u63A5\u5165\u7684\u673A\u5668\u4EBA",
4911
+ connectionLabel: "\u957F\u8FDE\u63A5"
4912
+ }),
4865
4913
  h2(
4866
4914
  "ul",
4867
4915
  { className: "bxf-botList dim-botList", role: "list" },
@@ -4945,7 +4993,7 @@ function mergeFeishuSnapshotState(current, snapshot, { restoreProvisioning = fal
4945
4993
  };
4946
4994
  }
4947
4995
  function FeishuSettingsTab({ rpcCall }) {
4948
- const [model, setModel] = React11.useState({
4996
+ const [model, setModel] = React12.useState({
4949
4997
  phase: "loading",
4950
4998
  revision: 0,
4951
4999
  bots: [],
@@ -4955,41 +5003,41 @@ function FeishuSettingsTab({ rpcCall }) {
4955
5003
  statusError: null,
4956
5004
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
4957
5005
  });
4958
- const [pageBusy, setPageBusy] = React11.useState(false);
4959
- const [provisionBusy, setProvisionBusy] = React11.useState(false);
4960
- const [credentialOpen, setCredentialOpen] = React11.useState(false);
4961
- const [credentialBusy, setCredentialBusy] = React11.useState(false);
4962
- const [credentialError, setCredentialError] = React11.useState(null);
4963
- const [busyByBot, setBusyByBot] = React11.useState({});
4964
- const [errorsByBot, setErrorsByBot] = React11.useState({});
4965
- const [testNoticesByBot, setTestNoticesByBot] = React11.useState({});
4966
- const [removeTargetId, setRemoveTargetId] = React11.useState(null);
4967
- const [announcement, setAnnouncement] = React11.useState("");
4968
- const [now, setNow] = React11.useState(() => Date.now());
4969
- const [focusBotId, setFocusBotId] = React11.useState(null);
4970
- const cardRefs = React11.useRef(/* @__PURE__ */ new Map());
4971
- const removeButtonRefs = React11.useRef(/* @__PURE__ */ new Map());
4972
- const targetedProvisionRef = React11.useRef(null);
4973
- const addButtonRef = React11.useRef(null);
4974
- const mountedRef = React11.useRef(true);
5006
+ const [pageBusy, setPageBusy] = React12.useState(false);
5007
+ const [provisionBusy, setProvisionBusy] = React12.useState(false);
5008
+ const [credentialOpen, setCredentialOpen] = React12.useState(false);
5009
+ const [credentialBusy, setCredentialBusy] = React12.useState(false);
5010
+ const [credentialError, setCredentialError] = React12.useState(null);
5011
+ const [busyByBot, setBusyByBot] = React12.useState({});
5012
+ const [errorsByBot, setErrorsByBot] = React12.useState({});
5013
+ const [testNoticesByBot, setTestNoticesByBot] = React12.useState({});
5014
+ const [removeTargetId, setRemoveTargetId] = React12.useState(null);
5015
+ const [announcement, setAnnouncement] = React12.useState("");
5016
+ const [now, setNow] = React12.useState(() => Date.now());
5017
+ const [focusBotId, setFocusBotId] = React12.useState(null);
5018
+ const cardRefs = React12.useRef(/* @__PURE__ */ new Map());
5019
+ const removeButtonRefs = React12.useRef(/* @__PURE__ */ new Map());
5020
+ const targetedProvisionRef = React12.useRef(null);
5021
+ const addButtonRef = React12.useRef(null);
5022
+ const mountedRef = React12.useRef(true);
4975
5023
  const workspaceFence = useWorkspaceSnapshotFence();
4976
5024
  const scheduleAnimationFrame = useAnimationFrameScheduler();
4977
- React11.useEffect(() => {
5025
+ React12.useEffect(() => {
4978
5026
  mountedRef.current = true;
4979
5027
  return () => {
4980
5028
  mountedRef.current = false;
4981
5029
  };
4982
5030
  }, []);
4983
- const announce = React11.useCallback((message) => {
5031
+ const announce = React12.useCallback((message) => {
4984
5032
  setAnnouncement("");
4985
5033
  scheduleAnimationFrame(() => {
4986
5034
  if (message) setAnnouncement(message);
4987
5035
  }, "announcement");
4988
5036
  }, [scheduleAnimationFrame]);
4989
- const invoke = React11.useCallback(async (endpoint, payload = {}, signal) => {
5037
+ const invoke = React12.useCallback(async (endpoint, payload = {}, signal) => {
4990
5038
  return unwrapRpcResult3(await rpcCall(endpoint, payload, signal));
4991
5039
  }, [rpcCall]);
4992
- const mergeSnapshot = React11.useCallback((snapshot, { restoreProvisioning = false } = {}) => {
5040
+ const mergeSnapshot = React12.useCallback((snapshot, { restoreProvisioning = false } = {}) => {
4993
5041
  const now2 = Date.now();
4994
5042
  setModel((current) => mergeFeishuSnapshotState(
4995
5043
  current,
@@ -4997,7 +5045,7 @@ function FeishuSettingsTab({ rpcCall }) {
4997
5045
  { restoreProvisioning, now: now2 }
4998
5046
  ));
4999
5047
  }, []);
5000
- const loadStatus = React11.useCallback(async ({ signal, silent = false, restoreProvisioning = false } = {}) => {
5048
+ const loadStatus = React12.useCallback(async ({ signal, silent = false, restoreProvisioning = false } = {}) => {
5001
5049
  const workspaceVersion = workspaceFence.beginStatus();
5002
5050
  if (workspaceVersion === null || !mountedRef.current) return void 0;
5003
5051
  if (!silent) setPageBusy(true);
@@ -5015,12 +5063,12 @@ function FeishuSettingsTab({ rpcCall }) {
5015
5063
  if (!silent && !signal?.aborted && mountedRef.current) setPageBusy(false);
5016
5064
  }
5017
5065
  }, [invoke, mergeSnapshot, workspaceFence]);
5018
- React11.useEffect(() => {
5066
+ React12.useEffect(() => {
5019
5067
  const controller = new AbortController();
5020
5068
  void loadStatus({ signal: controller.signal, restoreProvisioning: true });
5021
5069
  return () => controller.abort();
5022
5070
  }, [loadStatus]);
5023
- React11.useEffect(() => {
5071
+ React12.useEffect(() => {
5024
5072
  if (model.phase !== "ready") return void 0;
5025
5073
  const controller = new AbortController();
5026
5074
  let inFlight = false;
@@ -5039,7 +5087,7 @@ function FeishuSettingsTab({ rpcCall }) {
5039
5087
  window.clearInterval(timer);
5040
5088
  };
5041
5089
  }, [loadStatus, model.phase]);
5042
- React11.useEffect(() => {
5090
+ React12.useEffect(() => {
5043
5091
  if (!focusBotId) return;
5044
5092
  const node = cardRefs.current.get(focusBotId);
5045
5093
  if (!node) return;
@@ -5048,7 +5096,7 @@ function FeishuSettingsTab({ rpcCall }) {
5048
5096
  setFocusBotId(null);
5049
5097
  }, [focusBotId, model.bots]);
5050
5098
  const targetedProvisionFocusKey = isTargetedAppUpdate2(model.provisioning) ? `${model.provisioning.botId}:${model.provisioning.attemptId ?? "preparing"}:${model.provisioning.phase}` : null;
5051
- React11.useEffect(() => {
5099
+ React12.useEffect(() => {
5052
5100
  if (!targetedProvisionFocusKey) return;
5053
5101
  scheduleAnimationFrame(() => {
5054
5102
  const node = targetedProvisionRef.current;
@@ -5057,7 +5105,7 @@ function FeishuSettingsTab({ rpcCall }) {
5057
5105
  node.focus?.({ preventScroll: true });
5058
5106
  }, "targeted-provision-focus");
5059
5107
  }, [scheduleAnimationFrame, targetedProvisionFocusKey]);
5060
- const startProvisioning = React11.useCallback(async ({
5108
+ const startProvisioning = React12.useCallback(async ({
5061
5109
  replace = false,
5062
5110
  operation = FEISHU_REGISTRATION_OPERATIONS.PROVISION,
5063
5111
  bot
@@ -5133,7 +5181,7 @@ function FeishuSettingsTab({ rpcCall }) {
5133
5181
  model.provisioning?.botId,
5134
5182
  model.provisioning?.botName
5135
5183
  ]);
5136
- const bindCredentials = React11.useCallback(async ({ identity, secret }) => {
5184
+ const bindCredentials = React12.useCallback(async ({ identity, secret }) => {
5137
5185
  const snapshotVersion = workspaceFence.beginMutation();
5138
5186
  setCredentialBusy(true);
5139
5187
  setCredentialError(null);
@@ -5155,7 +5203,7 @@ function FeishuSettingsTab({ rpcCall }) {
5155
5203
  setCredentialBusy(false);
5156
5204
  }
5157
5205
  }, [announce, invoke, loadStatus, mergeSnapshot, workspaceFence]);
5158
- const cancelProvisioning = React11.useCallback(async () => {
5206
+ const cancelProvisioning = React12.useCallback(async () => {
5159
5207
  const activeProvision = model.provisioning;
5160
5208
  const attemptId = activeProvision?.attemptId;
5161
5209
  const repairing = isCallbackRepair(activeProvision);
@@ -5220,7 +5268,7 @@ function FeishuSettingsTab({ rpcCall }) {
5220
5268
  const countdownPhase = model.provisioning?.phase;
5221
5269
  const countdownExpiresAt = model.provisioning?.expiresAt;
5222
5270
  const countdownExpired = model.provisioning?.expired;
5223
- React11.useEffect(() => {
5271
+ React12.useEffect(() => {
5224
5272
  if (!countdownAttemptId || countdownPhase !== "qr" || countdownExpired) return void 0;
5225
5273
  const tick = () => {
5226
5274
  const timestamp7 = Date.now();
@@ -5233,7 +5281,7 @@ function FeishuSettingsTab({ rpcCall }) {
5233
5281
  const timer = window.setInterval(tick, 1e3);
5234
5282
  return () => window.clearInterval(timer);
5235
5283
  }, [countdownAttemptId, countdownPhase, countdownExpiresAt, countdownExpired]);
5236
- React11.useEffect(() => {
5284
+ React12.useEffect(() => {
5237
5285
  const provision2 = model.provisioning;
5238
5286
  if (!provision2 || !["qr", "connecting"].includes(provision2.phase) || !provision2.attemptId || provision2.expired) return void 0;
5239
5287
  const controller = new AbortController();
@@ -5301,7 +5349,7 @@ function FeishuSettingsTab({ rpcCall }) {
5301
5349
  window.clearTimeout(timer);
5302
5350
  };
5303
5351
  }, [announce, invoke, loadStatus, model.provisioning]);
5304
- const setBotBusy = React11.useCallback((botId, value) => {
5352
+ const setBotBusy = React12.useCallback((botId, value) => {
5305
5353
  setBusyByBot((current) => {
5306
5354
  const next = { ...current };
5307
5355
  if (value) next[botId] = value;
@@ -5309,7 +5357,7 @@ function FeishuSettingsTab({ rpcCall }) {
5309
5357
  return next;
5310
5358
  });
5311
5359
  }, []);
5312
- const setBotError = React11.useCallback((botId, error) => {
5360
+ const setBotError = React12.useCallback((botId, error) => {
5313
5361
  setErrorsByBot((current) => {
5314
5362
  const next = { ...current };
5315
5363
  if (error) next[botId] = presentError3(error);
@@ -5317,7 +5365,7 @@ function FeishuSettingsTab({ rpcCall }) {
5317
5365
  return next;
5318
5366
  });
5319
5367
  }, []);
5320
- const repairCallback = React11.useCallback((connection) => {
5368
+ const repairCallback = React12.useCallback((connection) => {
5321
5369
  if (model.provisioning) return;
5322
5370
  setRemoveTargetId(null);
5323
5371
  setBotError(connection.botId, null);
@@ -5331,7 +5379,7 @@ function FeishuSettingsTab({ rpcCall }) {
5331
5379
  bot: connection
5332
5380
  });
5333
5381
  }, [model.provisioning, setBotError, startProvisioning]);
5334
- const reconnectOneBot = React11.useCallback(async (connection) => {
5382
+ const reconnectOneBot = React12.useCallback(async (connection) => {
5335
5383
  const { botId, bot } = connection;
5336
5384
  const snapshotVersion = workspaceFence.beginMutation();
5337
5385
  setBotBusy(botId, "reconnect");
@@ -5371,7 +5419,7 @@ function FeishuSettingsTab({ rpcCall }) {
5371
5419
  setBotBusy(botId, null);
5372
5420
  }
5373
5421
  }, [announce, invoke, loadStatus, mergeSnapshot, setBotBusy, setBotError, workspaceFence]);
5374
- const saveWorkspace = React11.useCallback(async (connection, workspace) => {
5422
+ const saveWorkspace = React12.useCallback(async (connection, workspace) => {
5375
5423
  const { botId } = connection;
5376
5424
  const workspaceVersion = workspaceFence.beginMutation();
5377
5425
  setBotBusy(botId, "workspace");
@@ -5390,7 +5438,7 @@ function FeishuSettingsTab({ rpcCall }) {
5390
5438
  if (mountedRef.current) setBotBusy(botId, null);
5391
5439
  }
5392
5440
  }, [invoke, loadStatus, mergeSnapshot, setBotBusy, setBotError, workspaceFence]);
5393
- const saveAgentPreset = React11.useCallback(async (connection, agentPreset) => {
5441
+ const saveAgentPreset = React12.useCallback(async (connection, agentPreset) => {
5394
5442
  const { botId } = connection;
5395
5443
  const snapshotVersion = workspaceFence.beginMutation();
5396
5444
  setBotBusy(botId, "preset");
@@ -5409,7 +5457,7 @@ function FeishuSettingsTab({ rpcCall }) {
5409
5457
  if (mountedRef.current) setBotBusy(botId, null);
5410
5458
  }
5411
5459
  }, [invoke, loadStatus, mergeSnapshot, setBotBusy, setBotError, workspaceFence]);
5412
- const authorizeGroupMessages = React11.useCallback(async (connection) => {
5460
+ const authorizeGroupMessages = React12.useCallback(async (connection) => {
5413
5461
  const { botId } = connection;
5414
5462
  if (model.provisioning) {
5415
5463
  throw new Error("\u8BF7\u5148\u5B8C\u6210\u5F53\u524D\u98DE\u4E66\u6388\u6743\u64CD\u4F5C\uFF0C\u518D\u5F00\u901A\u7FA4\u6D88\u606F\u6743\u9650\u3002");
@@ -5426,7 +5474,7 @@ function FeishuSettingsTab({ rpcCall }) {
5426
5474
  bot: connection
5427
5475
  });
5428
5476
  }, [model.provisioning, setBotError, startProvisioning]);
5429
- const saveGroupResponseMode = React11.useCallback(async (connection, groupResponseMode) => {
5477
+ const saveGroupResponseMode = React12.useCallback(async (connection, groupResponseMode) => {
5430
5478
  const { botId } = connection;
5431
5479
  if (groupResponseMode === "all" && connection.groupMessagePermissionGranted !== true) {
5432
5480
  await authorizeGroupMessages(connection);
@@ -5457,15 +5505,15 @@ function FeishuSettingsTab({ rpcCall }) {
5457
5505
  setBotError,
5458
5506
  workspaceFence
5459
5507
  ]);
5460
- const requestRemove = React11.useCallback((connection) => {
5508
+ const requestRemove = React12.useCallback((connection) => {
5461
5509
  setRemoveTargetId(connection.botId);
5462
5510
  }, []);
5463
- const cancelRemove = React11.useCallback(() => {
5511
+ const cancelRemove = React12.useCallback(() => {
5464
5512
  const botId = removeTargetId;
5465
5513
  setRemoveTargetId(null);
5466
5514
  scheduleAnimationFrame(() => removeButtonRefs.current.get(botId)?.focus(), "focus");
5467
5515
  }, [removeTargetId, scheduleAnimationFrame]);
5468
- const confirmRemove = React11.useCallback(async (connection) => {
5516
+ const confirmRemove = React12.useCallback(async (connection) => {
5469
5517
  const { botId, bot } = connection;
5470
5518
  const snapshotVersion = workspaceFence.beginMutation();
5471
5519
  setBotBusy(botId, "delete");
@@ -5551,11 +5599,11 @@ function FeishuSettingsTab({ rpcCall }) {
5551
5599
  setCredentialError(null);
5552
5600
  }
5553
5601
  }) : null;
5554
- const setCardRef = React11.useCallback((botId, node) => {
5602
+ const setCardRef = React12.useCallback((botId, node) => {
5555
5603
  if (node) cardRefs.current.set(botId, node);
5556
5604
  else cardRefs.current.delete(botId);
5557
5605
  }, []);
5558
- const setRemoveButtonRef = React11.useCallback((botId, node) => {
5606
+ const setRemoveButtonRef = React12.useCallback((botId, node) => {
5559
5607
  if (node) removeButtonRefs.current.set(botId, node);
5560
5608
  else removeButtonRefs.current.delete(botId);
5561
5609
  }, []);
@@ -5594,7 +5642,7 @@ function FeishuSettingsTab({ rpcCall }) {
5594
5642
  onRetry: () => void loadStatus(),
5595
5643
  busy: pageBusy
5596
5644
  }) : h2(
5597
- React11.Fragment,
5645
+ React12.Fragment,
5598
5646
  null,
5599
5647
  credentialContent,
5600
5648
  targetedProvisioning ? null : provisionContent,
@@ -5756,7 +5804,7 @@ function formatRemaining3(milliseconds) {
5756
5804
  }
5757
5805
 
5758
5806
  // plugin-src/client/channels/qq/index.js
5759
- var React12 = __toESM(require("react"), 1);
5807
+ var React13 = __toESM(require("react"), 1);
5760
5808
 
5761
5809
  // plugin-src/client/channels/qq/styles.js
5762
5810
  var QQ_STYLE_ID = "xmanrui-dsh-im-qq-settings";
@@ -5781,7 +5829,7 @@ function installQqStyles() {
5781
5829
 
5782
5830
  // plugin-src/client/channels/qq/index.js
5783
5831
  var ACTIVE_STATES = /* @__PURE__ */ new Set(["pending", "refreshing", "connecting"]);
5784
- var Button7 = React12.forwardRef(function Button8({ children, kind = "secondary", className = "", ...props }, ref) {
5832
+ var Button7 = React13.forwardRef(function Button8({ children, kind = "secondary", className = "", ...props }, ref) {
5785
5833
  return h2("button", {
5786
5834
  ...props,
5787
5835
  ref,
@@ -6023,18 +6071,14 @@ function AccountCard2({
6023
6071
  h2("p", null, account.bot.appIdMasked)
6024
6072
  )
6025
6073
  ),
6026
- h2(
6027
- "div",
6028
- { className: "ddt-health dim-botHealth" },
6029
- h2("span", { className: "ddt-dot dim-healthDot", "data-tone": tone }),
6030
- h2("span", null, stateLabel2)
6031
- )
6032
- ),
6033
- h2(
6034
- "dl",
6035
- { className: "ddt-metrics dim-botMetrics" },
6036
- h2("div", { className: "ddt-metric dim-botMetric" }, h2("dt", null, "\u6D88\u606F\u901A\u9053"), h2("dd", null, account.connected ? "WebSocket \u957F\u8FDE\u63A5" : "\u79BB\u7EBF")),
6037
- h2("div", { className: "ddt-metric dim-botMetric" }, h2("dt", null, "\u6700\u8FD1\u68C0\u67E5"), h2("dd", null, checkedTime3(account.health.lastCheckedAt)))
6074
+ h2(BotStatusMeta, {
6075
+ className: "ddt-health",
6076
+ dotClassName: "ddt-dot",
6077
+ tone,
6078
+ stateLabel: stateLabel2,
6079
+ lastCheckedAt: account.health.lastCheckedAt,
6080
+ formatCheckedTime: checkedTime3
6081
+ })
6038
6082
  ),
6039
6083
  h2(WorkspaceEditor, {
6040
6084
  workspace: account.workspace,
@@ -6049,17 +6093,21 @@ function AccountCard2({
6049
6093
  h2(
6050
6094
  "div",
6051
6095
  { className: "ddt-accountFooter dim-cardFooter" },
6052
- summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
6053
- feedback ? h2("div", {
6054
- className: "ddt-summary dim-cardSummary",
6055
- role: "status",
6056
- "aria-live": "polite"
6057
- }, feedback) : null,
6058
6096
  h2(
6059
6097
  "div",
6060
- { className: "ddt-actions dim-cardActions" },
6061
- h2(Button7, { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
6062
- h2(Button7, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
6098
+ { className: "dim-cardFooterLayout" },
6099
+ h2(
6100
+ "div",
6101
+ { className: "ddt-actions dim-cardActions" },
6102
+ h2(Button7, { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
6103
+ h2(Button7, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
6104
+ ),
6105
+ summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
6106
+ feedback ? h2("div", {
6107
+ className: "ddt-summary dim-cardFeedback",
6108
+ role: "status",
6109
+ "aria-live": "polite"
6110
+ }, feedback) : null
6063
6111
  )
6064
6112
  )
6065
6113
  ),
@@ -6072,25 +6120,25 @@ function AccountCard2({
6072
6120
  );
6073
6121
  }
6074
6122
  function QqSettingsTab({ rpcCall }) {
6075
- const [model, setModel] = React12.useState({
6123
+ const [model, setModel] = React13.useState({
6076
6124
  phase: "loading",
6077
6125
  bots: [],
6078
6126
  totals: { configured: 0, connected: 0 },
6079
6127
  error: null,
6080
6128
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
6081
6129
  });
6082
- const [provision, setProvision] = React12.useState(null);
6083
- const [busy, setBusy] = React12.useState(false);
6084
- const [busyByBot, setBusyByBot] = React12.useState({});
6085
- const [feedbackByBot, setFeedbackByBot] = React12.useState({});
6086
- const [removeTarget, setRemoveTarget] = React12.useState(null);
6087
- const [credentialOpen, setCredentialOpen] = React12.useState(false);
6088
- const [credentialError, setCredentialError] = React12.useState(null);
6089
- const [now, setNow] = React12.useState(Date.now());
6090
- const mounted = React12.useRef(true);
6130
+ const [provision, setProvision] = React13.useState(null);
6131
+ const [busy, setBusy] = React13.useState(false);
6132
+ const [busyByBot, setBusyByBot] = React13.useState({});
6133
+ const [feedbackByBot, setFeedbackByBot] = React13.useState({});
6134
+ const [removeTarget, setRemoveTarget] = React13.useState(null);
6135
+ const [credentialOpen, setCredentialOpen] = React13.useState(false);
6136
+ const [credentialError, setCredentialError] = React13.useState(null);
6137
+ const [now, setNow] = React13.useState(Date.now());
6138
+ const mounted = React13.useRef(true);
6091
6139
  const workspaceFence = useWorkspaceSnapshotFence();
6092
- const addButtonRef = React12.useRef(null);
6093
- React12.useEffect(() => {
6140
+ const addButtonRef = React13.useRef(null);
6141
+ React13.useEffect(() => {
6094
6142
  const disposeDingtalk = installDingtalkStyles();
6095
6143
  const disposeQq = installQqStyles();
6096
6144
  mounted.current = true;
@@ -6100,11 +6148,11 @@ function QqSettingsTab({ rpcCall }) {
6100
6148
  disposeDingtalk();
6101
6149
  };
6102
6150
  }, []);
6103
- const invoke = React12.useCallback(async (endpoint, payload = {}, signal) => {
6151
+ const invoke = React13.useCallback(async (endpoint, payload = {}, signal) => {
6104
6152
  if (typeof rpcCall !== "function") throw new TypeError("QQ \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
6105
6153
  return unwrapRpcResult4(await rpcCall(endpoint, payload, signal));
6106
6154
  }, [rpcCall]);
6107
- const loadStatus = React12.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
6155
+ const loadStatus = React13.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
6108
6156
  const workspaceVersion = workspaceFence.beginStatus();
6109
6157
  if (workspaceVersion === null) return void 0;
6110
6158
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
@@ -6130,12 +6178,12 @@ function QqSettingsTab({ rpcCall }) {
6130
6178
  return void 0;
6131
6179
  }
6132
6180
  }, [invoke, workspaceFence]);
6133
- React12.useEffect(() => {
6181
+ React13.useEffect(() => {
6134
6182
  const controller = new AbortController();
6135
6183
  void loadStatus({ signal: controller.signal, restore: true });
6136
6184
  return () => controller.abort();
6137
6185
  }, [loadStatus]);
6138
- React12.useEffect(() => {
6186
+ React13.useEffect(() => {
6139
6187
  if (model.phase !== "ready") return void 0;
6140
6188
  const controller = new AbortController();
6141
6189
  const timer = window.setInterval(() => void loadStatus({ signal: controller.signal, silent: true }), 15e3);
@@ -6144,12 +6192,12 @@ function QqSettingsTab({ rpcCall }) {
6144
6192
  window.clearInterval(timer);
6145
6193
  };
6146
6194
  }, [loadStatus, model.phase]);
6147
- React12.useEffect(() => {
6195
+ React13.useEffect(() => {
6148
6196
  if (!provision || !ACTIVE_STATES.has(provision.status)) return void 0;
6149
6197
  const timer = window.setInterval(() => mounted.current && setNow(Date.now()), 1e3);
6150
6198
  return () => window.clearInterval(timer);
6151
6199
  }, [provision?.attemptId, provision?.status]);
6152
- const startProvisioning = React12.useCallback(async (replace = false) => {
6200
+ const startProvisioning = React13.useCallback(async (replace = false) => {
6153
6201
  setCredentialOpen(false);
6154
6202
  setCredentialError(null);
6155
6203
  setBusy(true);
@@ -6167,7 +6215,7 @@ function QqSettingsTab({ rpcCall }) {
6167
6215
  if (mounted.current) setBusy(false);
6168
6216
  }
6169
6217
  }, [invoke, provision?.attemptId]);
6170
- const bindCredentials = React12.useCallback(async ({ identity, secret }) => {
6218
+ const bindCredentials = React13.useCallback(async ({ identity, secret }) => {
6171
6219
  const snapshotVersion = workspaceFence.beginMutation();
6172
6220
  setBusy(true);
6173
6221
  setCredentialError(null);
@@ -6195,7 +6243,7 @@ function QqSettingsTab({ rpcCall }) {
6195
6243
  if (mounted.current) setBusy(false);
6196
6244
  }
6197
6245
  }, [invoke, loadStatus, workspaceFence]);
6198
- const closeProvision = React12.useCallback(async () => {
6246
+ const closeProvision = React13.useCallback(async () => {
6199
6247
  setBusy(true);
6200
6248
  try {
6201
6249
  if (provision?.attemptId && ACTIVE_STATES.has(provision.status)) {
@@ -6206,7 +6254,7 @@ function QqSettingsTab({ rpcCall }) {
6206
6254
  if (mounted.current) setBusy(false);
6207
6255
  }
6208
6256
  }, [invoke, provision?.attemptId, provision?.status]);
6209
- React12.useEffect(() => {
6257
+ React13.useEffect(() => {
6210
6258
  const attemptId = provision?.attemptId;
6211
6259
  if (!attemptId || !ACTIVE_STATES.has(provision.status)) return void 0;
6212
6260
  const controller = new AbortController();
@@ -6236,7 +6284,7 @@ function QqSettingsTab({ rpcCall }) {
6236
6284
  window.clearTimeout(timer);
6237
6285
  };
6238
6286
  }, [invoke, loadStatus, provision?.attemptId, provision?.pollIntervalMs, provision?.status]);
6239
- const botAction = React12.useCallback(async (account, operation, endpoint, payload) => {
6287
+ const botAction = React13.useCallback(async (account, operation, endpoint, payload) => {
6240
6288
  const snapshotVersion = workspaceFence.beginMutation();
6241
6289
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
6242
6290
  try {
@@ -6261,7 +6309,7 @@ function QqSettingsTab({ rpcCall }) {
6261
6309
  });
6262
6310
  }
6263
6311
  }, [invoke, loadStatus, workspaceFence]);
6264
- const reconnect = React12.useCallback(async (account) => {
6312
+ const reconnect = React13.useCallback(async (account) => {
6265
6313
  setFeedbackByBot((current) => {
6266
6314
  const next = { ...current };
6267
6315
  delete next[account.botId];
@@ -6307,11 +6355,11 @@ function QqSettingsTab({ rpcCall }) {
6307
6355
  const botList = model.bots.length > 0 ? h2(
6308
6356
  "section",
6309
6357
  { className: "dim-listSection" },
6310
- h2(
6311
- "div",
6312
- { className: "ddt-listHeading dim-listHeading" },
6313
- h2("h3", null, "\u5DF2\u7ED1\u5B9A\u7684 QQ \u673A\u5668\u4EBA")
6314
- ),
6358
+ h2(ChannelListHeading, {
6359
+ className: "ddt-listHeading",
6360
+ title: "\u5DF2\u7ED1\u5B9A\u7684 QQ \u673A\u5668\u4EBA",
6361
+ connectionLabel: "WebSocket \u957F\u8FDE\u63A5"
6362
+ }),
6315
6363
  h2("ul", { className: "ddt-list dim-botList" }, model.bots.map((account) => h2("li", { key: account.botId }, h2(AccountCard2, {
6316
6364
  account,
6317
6365
  busy: busyByBot[account.botId],
@@ -6370,7 +6418,7 @@ function QqSettingsTab({ rpcCall }) {
6370
6418
  addButtonRef
6371
6419
  }),
6372
6420
  model.phase === "loading" ? h2(LoadingView3) : model.phase === "error" ? h2("div", { className: "ddt-card dim-surfaceCard" }, h2("div", { className: "ddt-inlineError dim-inlineError" }, h2("h3", null, "\u65E0\u6CD5\u8BFB\u53D6 QQ \u673A\u5668\u4EBA\u72B6\u6001"), h2("p", null, model.error?.message), h2(Button7, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6"))) : h2(
6373
- React12.Fragment,
6421
+ React13.Fragment,
6374
6422
  null,
6375
6423
  credentialView,
6376
6424
  provisionView,
@@ -6459,7 +6507,7 @@ function normalizeOfficeStatus(value) {
6459
6507
  }
6460
6508
 
6461
6509
  // plugin-src/client/channels/office/index.js
6462
- var React13 = __toESM(require("react"), 1);
6510
+ var React14 = __toESM(require("react"), 1);
6463
6511
  function Button9({ children, kind = "secondary", ...props }) {
6464
6512
  return h2("button", { ...props, type: "button", className: "ddt-button", "data-kind": kind }, children);
6465
6513
  }
@@ -6488,12 +6536,12 @@ function stateLabel(model) {
6488
6536
  return "\u5DF2\u914D\u7F6E";
6489
6537
  }
6490
6538
  function OfficeSettingsTab({ rpcCall, initialStatus }) {
6491
- const [model, setModel] = React13.useState(normalizeOfficeStatus(initialStatus));
6492
- const [phase, setPhase] = React13.useState(initialStatus === void 0 ? "loading" : "ready");
6493
- const [busy, setBusy] = React13.useState("");
6494
- const [error, setError] = React13.useState("");
6495
- const [notice, setNotice] = React13.useState("");
6496
- const [form, setForm] = React13.useState({
6539
+ const [model, setModel] = React14.useState(normalizeOfficeStatus(initialStatus));
6540
+ const [phase, setPhase] = React14.useState(initialStatus === void 0 ? "loading" : "ready");
6541
+ const [busy, setBusy] = React14.useState("");
6542
+ const [error, setError] = React14.useState("");
6543
+ const [notice, setNotice] = React14.useState("");
6544
+ const [form, setForm] = React14.useState({
6497
6545
  baseUrl: "",
6498
6546
  deviceId: "local-harness",
6499
6547
  deviceToken: "",
@@ -6502,11 +6550,11 @@ function OfficeSettingsTab({ rpcCall, initialStatus }) {
6502
6550
  workspaces: "",
6503
6551
  instructionPresets: ""
6504
6552
  });
6505
- const invoke = React13.useCallback(async (endpoint, payload = {}) => {
6553
+ const invoke = React14.useCallback(async (endpoint, payload = {}) => {
6506
6554
  if (typeof rpcCall !== "function") throw new Error("AI Office \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
6507
6555
  return unwrapOfficeRpc(await rpcCall(endpoint, payload));
6508
6556
  }, [rpcCall]);
6509
- const adopt = React13.useCallback((value) => {
6557
+ const adopt = React14.useCallback((value) => {
6510
6558
  const next = normalizeOfficeStatus(value?.snapshot ?? value);
6511
6559
  setModel(next);
6512
6560
  if (next.config) setForm((current) => ({
@@ -6521,7 +6569,7 @@ function OfficeSettingsTab({ rpcCall, initialStatus }) {
6521
6569
  }));
6522
6570
  return next;
6523
6571
  }, []);
6524
- const load = React13.useCallback(async () => {
6572
+ const load = React14.useCallback(async () => {
6525
6573
  try {
6526
6574
  adopt(await invoke(OFFICE_RPC_ENDPOINTS.status));
6527
6575
  setPhase("ready");
@@ -6531,7 +6579,7 @@ function OfficeSettingsTab({ rpcCall, initialStatus }) {
6531
6579
  setError(caught.message);
6532
6580
  }
6533
6581
  }, [adopt, invoke]);
6534
- React13.useEffect(() => {
6582
+ React14.useEffect(() => {
6535
6583
  void load();
6536
6584
  }, [load]);
6537
6585
  const run = async (name2, operation) => {
@@ -6548,7 +6596,7 @@ function OfficeSettingsTab({ rpcCall, initialStatus }) {
6548
6596
  setBusy("");
6549
6597
  }
6550
6598
  };
6551
- const hooks = React13.useMemo(() => {
6599
+ const hooks = React14.useMemo(() => {
6552
6600
  try {
6553
6601
  return officeHookUrls(form.baseUrl);
6554
6602
  } catch {
@@ -6733,7 +6781,7 @@ var normalizeSnapshot4 = api2.normalizeSnapshot;
6733
6781
  var presentError5 = api2.presentError;
6734
6782
 
6735
6783
  // plugin-src/client/channels/slack/index.js
6736
- var React14 = __toESM(require("react"), 1);
6784
+ var React15 = __toESM(require("react"), 1);
6737
6785
 
6738
6786
  // src/channels/slack/manifest.mjs
6739
6787
  var SLACK_APP_MANIFEST_YAML = `_metadata:
@@ -6756,6 +6804,7 @@ oauth_config:
6756
6804
  - app_mentions:read
6757
6805
  - chat:write
6758
6806
  - files:read
6807
+ - files:write
6759
6808
  - im:history
6760
6809
  settings:
6761
6810
  event_subscriptions:
@@ -6806,10 +6855,10 @@ function installSlackStyles() {
6806
6855
 
6807
6856
  // plugin-src/client/channels/slack/index.js
6808
6857
  function SlackCredentialPanel({ busy, error, onSubmit, onCancel }) {
6809
- const [botToken, setBotToken] = React14.useState("");
6810
- const [appToken, setAppToken] = React14.useState("");
6811
- const [copied, setCopied] = React14.useState(false);
6812
- const headingId = React14.useId();
6858
+ const [botToken, setBotToken] = React15.useState("");
6859
+ const [appToken, setAppToken] = React15.useState("");
6860
+ const [copied, setCopied] = React15.useState(false);
6861
+ const headingId = React15.useId();
6813
6862
  const copyManifest = async () => {
6814
6863
  try {
6815
6864
  await navigator.clipboard.writeText(SLACK_APP_MANIFEST_YAML);
@@ -6965,7 +7014,7 @@ var normalizeSnapshot5 = api3.normalizeSnapshot;
6965
7014
  var presentError6 = api3.presentError;
6966
7015
 
6967
7016
  // plugin-src/client/channels/telegram/index.js
6968
- var React15 = __toESM(require("react"), 1);
7017
+ var React16 = __toESM(require("react"), 1);
6969
7018
 
6970
7019
  // plugin-src/client/channels/telegram/styles.js
6971
7020
  var TELEGRAM_STYLE_ID = "xmanrui-dsh-im-telegram-settings";
@@ -7031,11 +7080,11 @@ function allowedUsersFromText(value) {
7031
7080
  function TelegramAccessSettings({ account, busy = false, onSave }) {
7032
7081
  const policy = policyFor(account);
7033
7082
  const sourceUsers = policy.allowedUsers.join("\n");
7034
- const accessHelpId = React15.useId();
7035
- const [accessMode, setAccessMode] = React15.useState(policy.accessMode);
7036
- const [allowedUsers, setAllowedUsers] = React15.useState(sourceUsers);
7037
- const [error, setError] = React15.useState(null);
7038
- React15.useEffect(() => {
7083
+ const accessHelpId = React16.useId();
7084
+ const [accessMode, setAccessMode] = React16.useState(policy.accessMode);
7085
+ const [allowedUsers, setAllowedUsers] = React16.useState(sourceUsers);
7086
+ const [error, setError] = React16.useState(null);
7087
+ React16.useEffect(() => {
7039
7088
  setAccessMode(policy.accessMode);
7040
7089
  setAllowedUsers(sourceUsers);
7041
7090
  setError(null);
@@ -7295,7 +7344,7 @@ function formatRemaining4(milliseconds) {
7295
7344
  }
7296
7345
 
7297
7346
  // plugin-src/client/channels/wecom/index.js
7298
- var React16 = __toESM(require("react"), 1);
7347
+ var React17 = __toESM(require("react"), 1);
7299
7348
 
7300
7349
  // plugin-src/client/channels/wecom/styles.js
7301
7350
  var WECOM_STYLE_ID = "xmanrui-dsh-im-wecom-settings";
@@ -7320,7 +7369,7 @@ function installWecomStyles() {
7320
7369
 
7321
7370
  // plugin-src/client/channels/wecom/index.js
7322
7371
  var ACTIVE_STATES2 = /* @__PURE__ */ new Set(["pending", "refreshing", "connecting"]);
7323
- var Button10 = React16.forwardRef(function Button11({ children, kind = "secondary", className = "", ...props }, ref) {
7372
+ var Button10 = React17.forwardRef(function Button11({ children, kind = "secondary", className = "", ...props }, ref) {
7324
7373
  return h2("button", {
7325
7374
  ...props,
7326
7375
  ref,
@@ -7562,18 +7611,14 @@ function AccountCard3({
7562
7611
  h2("p", null, account.bot.appIdMasked)
7563
7612
  )
7564
7613
  ),
7565
- h2(
7566
- "div",
7567
- { className: "ddt-health dim-botHealth" },
7568
- h2("span", { className: "ddt-dot dim-healthDot", "data-tone": tone }),
7569
- h2("span", null, stateLabel2)
7570
- )
7571
- ),
7572
- h2(
7573
- "dl",
7574
- { className: "ddt-metrics dim-botMetrics" },
7575
- h2("div", { className: "ddt-metric dim-botMetric" }, h2("dt", null, "\u6D88\u606F\u901A\u9053"), h2("dd", null, account.connected ? "WebSocket \u957F\u8FDE\u63A5" : "\u79BB\u7EBF")),
7576
- h2("div", { className: "ddt-metric dim-botMetric" }, h2("dt", null, "\u6700\u8FD1\u68C0\u67E5"), h2("dd", null, checkedTime4(account.health.lastCheckedAt)))
7614
+ h2(BotStatusMeta, {
7615
+ className: "ddt-health",
7616
+ dotClassName: "ddt-dot",
7617
+ tone,
7618
+ stateLabel: stateLabel2,
7619
+ lastCheckedAt: account.health.lastCheckedAt,
7620
+ formatCheckedTime: checkedTime4
7621
+ })
7577
7622
  ),
7578
7623
  h2(WorkspaceEditor, {
7579
7624
  workspace: account.workspace,
@@ -7588,17 +7633,21 @@ function AccountCard3({
7588
7633
  h2(
7589
7634
  "div",
7590
7635
  { className: "ddt-accountFooter dim-cardFooter" },
7591
- summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
7592
- feedback ? h2("div", {
7593
- className: "ddt-summary dim-cardSummary",
7594
- role: "status",
7595
- "aria-live": "polite"
7596
- }, feedback) : null,
7597
7636
  h2(
7598
7637
  "div",
7599
- { className: "ddt-actions dim-cardActions" },
7600
- h2(Button10, { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
7601
- h2(Button10, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
7638
+ { className: "dim-cardFooterLayout" },
7639
+ h2(
7640
+ "div",
7641
+ { className: "ddt-actions dim-cardActions" },
7642
+ h2(Button10, { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
7643
+ h2(Button10, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
7644
+ ),
7645
+ summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
7646
+ feedback ? h2("div", {
7647
+ className: "ddt-summary dim-cardFeedback",
7648
+ role: "status",
7649
+ "aria-live": "polite"
7650
+ }, feedback) : null
7602
7651
  )
7603
7652
  )
7604
7653
  ),
@@ -7611,27 +7660,27 @@ function AccountCard3({
7611
7660
  );
7612
7661
  }
7613
7662
  function WecomSettingsTab({ rpcCall }) {
7614
- const [model, setModel] = React16.useState({
7663
+ const [model, setModel] = React17.useState({
7615
7664
  phase: "loading",
7616
7665
  bots: [],
7617
7666
  totals: { configured: 0, connected: 0 },
7618
7667
  error: null,
7619
7668
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
7620
7669
  });
7621
- const [provision, setProvision] = React16.useState(null);
7622
- const [busy, setBusy] = React16.useState(false);
7623
- const [busyByBot, setBusyByBot] = React16.useState({});
7624
- const [feedbackByBot, setFeedbackByBot] = React16.useState({});
7625
- const [removeTarget, setRemoveTarget] = React16.useState(null);
7626
- const [credentialOpen, setCredentialOpen] = React16.useState(false);
7627
- const [credentialError, setCredentialError] = React16.useState(null);
7628
- const [notice, setNotice] = React16.useState("");
7629
- const [now, setNow] = React16.useState(Date.now());
7630
- const mounted = React16.useRef(true);
7670
+ const [provision, setProvision] = React17.useState(null);
7671
+ const [busy, setBusy] = React17.useState(false);
7672
+ const [busyByBot, setBusyByBot] = React17.useState({});
7673
+ const [feedbackByBot, setFeedbackByBot] = React17.useState({});
7674
+ const [removeTarget, setRemoveTarget] = React17.useState(null);
7675
+ const [credentialOpen, setCredentialOpen] = React17.useState(false);
7676
+ const [credentialError, setCredentialError] = React17.useState(null);
7677
+ const [notice, setNotice] = React17.useState("");
7678
+ const [now, setNow] = React17.useState(Date.now());
7679
+ const mounted = React17.useRef(true);
7631
7680
  const workspaceFence = useWorkspaceSnapshotFence();
7632
- const addButtonRef = React16.useRef(null);
7633
- const noticeFrameRef = React16.useRef(null);
7634
- const announce = React16.useCallback((message) => {
7681
+ const addButtonRef = React17.useRef(null);
7682
+ const noticeFrameRef = React17.useRef(null);
7683
+ const announce = React17.useCallback((message) => {
7635
7684
  if (!mounted.current) return;
7636
7685
  if (noticeFrameRef.current !== null) {
7637
7686
  window.cancelAnimationFrame(noticeFrameRef.current);
@@ -7645,7 +7694,7 @@ function WecomSettingsTab({ rpcCall }) {
7645
7694
  });
7646
7695
  }
7647
7696
  }, []);
7648
- React16.useEffect(() => {
7697
+ React17.useEffect(() => {
7649
7698
  const disposeDingtalk = installDingtalkStyles();
7650
7699
  const disposeWecom = installWecomStyles();
7651
7700
  mounted.current = true;
@@ -7659,11 +7708,11 @@ function WecomSettingsTab({ rpcCall }) {
7659
7708
  disposeDingtalk();
7660
7709
  };
7661
7710
  }, []);
7662
- const invoke = React16.useCallback(async (endpoint, payload = {}, signal) => {
7711
+ const invoke = React17.useCallback(async (endpoint, payload = {}, signal) => {
7663
7712
  if (typeof rpcCall !== "function") throw new TypeError("\u4F01\u4E1A\u5FAE\u4FE1\u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
7664
7713
  return unwrapRpcResult7(await rpcCall(endpoint, payload, signal));
7665
7714
  }, [rpcCall]);
7666
- const loadStatus = React16.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
7715
+ const loadStatus = React17.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
7667
7716
  const workspaceVersion = workspaceFence.beginStatus();
7668
7717
  if (workspaceVersion === null) return void 0;
7669
7718
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
@@ -7689,12 +7738,12 @@ function WecomSettingsTab({ rpcCall }) {
7689
7738
  return void 0;
7690
7739
  }
7691
7740
  }, [invoke, workspaceFence]);
7692
- React16.useEffect(() => {
7741
+ React17.useEffect(() => {
7693
7742
  const controller = new AbortController();
7694
7743
  void loadStatus({ signal: controller.signal, restore: true });
7695
7744
  return () => controller.abort();
7696
7745
  }, [loadStatus]);
7697
- React16.useEffect(() => {
7746
+ React17.useEffect(() => {
7698
7747
  if (model.phase !== "ready") return void 0;
7699
7748
  const controller = new AbortController();
7700
7749
  const timer = window.setInterval(() => void loadStatus({ signal: controller.signal, silent: true }), 15e3);
@@ -7703,12 +7752,12 @@ function WecomSettingsTab({ rpcCall }) {
7703
7752
  window.clearInterval(timer);
7704
7753
  };
7705
7754
  }, [loadStatus, model.phase]);
7706
- React16.useEffect(() => {
7755
+ React17.useEffect(() => {
7707
7756
  if (!provision || !ACTIVE_STATES2.has(provision.status)) return void 0;
7708
7757
  const timer = window.setInterval(() => mounted.current && setNow(Date.now()), 1e3);
7709
7758
  return () => window.clearInterval(timer);
7710
7759
  }, [provision?.attemptId, provision?.status]);
7711
- const startProvisioning = React16.useCallback(async (replace = false) => {
7760
+ const startProvisioning = React17.useCallback(async (replace = false) => {
7712
7761
  setCredentialOpen(false);
7713
7762
  setCredentialError(null);
7714
7763
  setBusy(true);
@@ -7726,7 +7775,7 @@ function WecomSettingsTab({ rpcCall }) {
7726
7775
  if (mounted.current) setBusy(false);
7727
7776
  }
7728
7777
  }, [invoke, provision?.attemptId]);
7729
- const bindCredentials = React16.useCallback(async ({ identity, secret }) => {
7778
+ const bindCredentials = React17.useCallback(async ({ identity, secret }) => {
7730
7779
  const snapshotVersion = workspaceFence.beginMutation();
7731
7780
  setBusy(true);
7732
7781
  setCredentialError(null);
@@ -7754,7 +7803,7 @@ function WecomSettingsTab({ rpcCall }) {
7754
7803
  if (mounted.current) setBusy(false);
7755
7804
  }
7756
7805
  }, [invoke, loadStatus, workspaceFence]);
7757
- const closeProvision = React16.useCallback(async () => {
7806
+ const closeProvision = React17.useCallback(async () => {
7758
7807
  setBusy(true);
7759
7808
  try {
7760
7809
  if (provision?.attemptId && ACTIVE_STATES2.has(provision.status)) {
@@ -7765,7 +7814,7 @@ function WecomSettingsTab({ rpcCall }) {
7765
7814
  if (mounted.current) setBusy(false);
7766
7815
  }
7767
7816
  }, [invoke, provision?.attemptId, provision?.status]);
7768
- React16.useEffect(() => {
7817
+ React17.useEffect(() => {
7769
7818
  const attemptId = provision?.attemptId;
7770
7819
  if (!attemptId || !ACTIVE_STATES2.has(provision.status)) return void 0;
7771
7820
  const controller = new AbortController();
@@ -7795,7 +7844,7 @@ function WecomSettingsTab({ rpcCall }) {
7795
7844
  window.clearTimeout(timer);
7796
7845
  };
7797
7846
  }, [invoke, loadStatus, provision?.attemptId, provision?.pollIntervalMs, provision?.status]);
7798
- const botAction = React16.useCallback(async (account, operation, endpoint, payload) => {
7847
+ const botAction = React17.useCallback(async (account, operation, endpoint, payload) => {
7799
7848
  const snapshotVersion = workspaceFence.beginMutation();
7800
7849
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
7801
7850
  try {
@@ -7820,7 +7869,7 @@ function WecomSettingsTab({ rpcCall }) {
7820
7869
  });
7821
7870
  }
7822
7871
  }, [invoke, loadStatus, workspaceFence]);
7823
- const reconnect = React16.useCallback(async (account) => {
7872
+ const reconnect = React17.useCallback(async (account) => {
7824
7873
  setFeedbackByBot((current) => {
7825
7874
  const next = { ...current };
7826
7875
  delete next[account.botId];
@@ -7877,11 +7926,11 @@ function WecomSettingsTab({ rpcCall }) {
7877
7926
  const botList = model.bots.length > 0 ? h2(
7878
7927
  "section",
7879
7928
  { className: "dim-listSection" },
7880
- h2(
7881
- "div",
7882
- { className: "ddt-listHeading dim-listHeading" },
7883
- h2("h3", null, "\u5DF2\u7ED1\u5B9A\u7684\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA")
7884
- ),
7929
+ h2(ChannelListHeading, {
7930
+ className: "ddt-listHeading",
7931
+ title: "\u5DF2\u7ED1\u5B9A\u7684\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA",
7932
+ connectionLabel: "WebSocket \u957F\u8FDE\u63A5"
7933
+ }),
7885
7934
  h2("ul", { className: "ddt-list dim-botList" }, model.bots.map((account) => h2("li", { key: account.botId }, h2(AccountCard3, {
7886
7935
  account,
7887
7936
  busy: busyByBot[account.botId],
@@ -7941,7 +7990,7 @@ function WecomSettingsTab({ rpcCall }) {
7941
7990
  }),
7942
7991
  h2("div", { className: "ddt-visuallyHidden", role: "status", "aria-live": "polite" }, notice),
7943
7992
  model.phase === "loading" ? h2(LoadingView4) : model.phase === "error" ? h2("div", { className: "ddt-card dim-surfaceCard" }, h2("div", { className: "ddt-inlineError dim-inlineError" }, h2("h3", null, "\u65E0\u6CD5\u8BFB\u53D6\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA\u72B6\u6001"), h2("p", null, model.error?.message), h2(Button10, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6"))) : h2(
7944
- React16.Fragment,
7993
+ React17.Fragment,
7945
7994
  null,
7946
7995
  credentialView,
7947
7996
  provisionView,
@@ -7952,7 +8001,7 @@ function WecomSettingsTab({ rpcCall }) {
7952
8001
  }
7953
8002
 
7954
8003
  // plugin-src/client/channels/weixin/index.js
7955
- var React17 = __toESM(require("react"), 1);
8004
+ var React18 = __toESM(require("react"), 1);
7956
8005
 
7957
8006
  // plugin-src/client/channels/weixin/api.js
7958
8007
  var WEIXIN_RPC_CHANNEL = "/weixin";
@@ -8193,10 +8242,6 @@ var CSS9 = String.raw`
8193
8242
  .dxw-accountIdentity h3 { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 15px; }
8194
8243
  .dxw-accountIdentity p { color: var(--dsw-alias-label-secondary, #646a73); font: 12px ui-monospace, SFMono-Regular, monospace; margin-top: 4px; }
8195
8244
  .dxw-health { display: inline-flex; align-items: center; gap: 7px; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; white-space: nowrap; }
8196
- .dxw-metrics { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin: 20px 0; }
8197
- .dxw-metric { padding: 12px 14px; border-radius: 9px; background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
8198
- .dxw-metric dt { color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 11px; }
8199
- .dxw-metric dd { overflow: hidden; margin: 5px 0 0; font-size: 13px; text-overflow: ellipsis; white-space: nowrap; }
8200
8245
  .dxw-accountFooter { display: flex; align-items: center; justify-content: space-between; gap: 15px; padding-top: 16px; border-top: 1px solid var(--dsw-alias-border-l1, #eef0f3); }
8201
8246
  .dxw-accountFooter .dxw-actions { flex: none; flex-wrap: nowrap; gap: 8px; margin-top: 0; }
8202
8247
  .dxw-accountFooter .dxw-button { flex: none; white-space: nowrap; }
@@ -8215,7 +8260,6 @@ var CSS9 = String.raw`
8215
8260
  .dxw-logo { display: none; }
8216
8261
  .dxw-qrLayout { grid-template-columns: minmax(0, 1fr); justify-items: center; }
8217
8262
  .dxw-qrCopy { width: 100%; }
8218
- .dxw-metrics { grid-template-columns: minmax(0, 1fr); }
8219
8263
  .dxw-cardBody { padding: 20px; }
8220
8264
  }
8221
8265
  @media (prefers-reduced-motion: reduce) {
@@ -8237,7 +8281,7 @@ function installWeixinStyles() {
8237
8281
  }
8238
8282
 
8239
8283
  // plugin-src/client/channels/weixin/index.js
8240
- var Button12 = React17.forwardRef(function Button13({ children, kind = "secondary", className = "", ...props }, ref) {
8284
+ var Button12 = React18.forwardRef(function Button13({ children, kind = "secondary", className = "", ...props }, ref) {
8241
8285
  return h2("button", {
8242
8286
  ...props,
8243
8287
  ref,
@@ -8310,14 +8354,14 @@ function EmptyView5({ onStart, busy }) {
8310
8354
  );
8311
8355
  }
8312
8356
  function QrPanel4({ provision, now, busy, onRefresh, onCancel }) {
8313
- const [imageFailed, setImageFailed] = React17.useState(false);
8357
+ const [imageFailed, setImageFailed] = React18.useState(false);
8314
8358
  const source = safeQrSource5(provision.qrCodeDataUrl);
8315
8359
  const href = safeVerificationUrl(provision.verificationUrl);
8316
8360
  const remaining = Math.max(0, provision.expiresAt - now);
8317
8361
  const expired = remaining === 0 || provision.status === "expired";
8318
8362
  const duration = Math.max(1, provision.durationMs ?? 5 * 6e4);
8319
8363
  const progress = Math.round(Math.min(1, remaining / duration) * 100);
8320
- React17.useEffect(() => setImageFailed(false), [source]);
8364
+ React18.useEffect(() => setImageFailed(false), [source]);
8321
8365
  return h2(
8322
8366
  "div",
8323
8367
  { className: "dxw-card dim-surfaceCard" },
@@ -8384,9 +8428,9 @@ function QrPanel4({ provision, now, busy, onRefresh, onCancel }) {
8384
8428
  );
8385
8429
  }
8386
8430
  function VerificationPanel({ provision, busy, onSubmit, onCancel }) {
8387
- const [code, setCode] = React17.useState("");
8431
+ const [code, setCode] = React18.useState("");
8388
8432
  const valid = /^\d{4,8}$/.test(code);
8389
- React17.useEffect(() => setCode(""), [provision.attemptId]);
8433
+ React18.useEffect(() => setCode(""), [provision.attemptId]);
8390
8434
  return h2(
8391
8435
  "div",
8392
8436
  { className: "dxw-card dim-surfaceCard" },
@@ -8507,28 +8551,14 @@ function AccountCard4({
8507
8551
  h2("div", { className: "dxw-avatar dim-botAvatar", "aria-hidden": "true" }, h2(WeixinLogoGlyph, { size: 27 })),
8508
8552
  h2("div", { className: "dim-botName" }, h2("h3", null, account.bot.name), h2("p", null, account.bot.accountIdMasked))
8509
8553
  ),
8510
- h2(
8511
- "div",
8512
- { className: "dxw-health dim-botHealth" },
8513
- h2("span", { className: "dxw-dot dim-healthDot", "data-tone": tone }),
8514
- h2("span", null, account.connected ? "\u8FD0\u884C\u6B63\u5E38" : state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA")
8515
- )
8516
- ),
8517
- h2(
8518
- "dl",
8519
- { className: "dxw-metrics dim-botMetrics" },
8520
- h2(
8521
- "div",
8522
- { className: "dxw-metric dim-botMetric" },
8523
- h2("dt", null, "\u6D88\u606F\u901A\u9053"),
8524
- h2("dd", null, account.connected ? "iLink \u957F\u8F6E\u8BE2" : "\u79BB\u7EBF")
8525
- ),
8526
- h2(
8527
- "div",
8528
- { className: "dxw-metric dim-botMetric" },
8529
- h2("dt", null, "\u6700\u8FD1\u68C0\u67E5"),
8530
- h2("dd", null, checkedTime5(account.health.lastCheckedAt))
8531
- )
8554
+ h2(BotStatusMeta, {
8555
+ className: "dxw-health",
8556
+ dotClassName: "dxw-dot",
8557
+ tone,
8558
+ stateLabel: account.connected ? "\u8FD0\u884C\u6B63\u5E38" : state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA",
8559
+ lastCheckedAt: account.health.lastCheckedAt,
8560
+ formatCheckedTime: checkedTime5
8561
+ })
8532
8562
  ),
8533
8563
  h2(WorkspaceEditor, {
8534
8564
  workspace: account.workspace,
@@ -8543,25 +8573,29 @@ function AccountCard4({
8543
8573
  h2(
8544
8574
  "div",
8545
8575
  { className: "dxw-accountFooter dim-cardFooter" },
8546
- summary ? h2("div", { className: "dxw-summary dim-cardSummary" }, summary) : null,
8547
- account.lastMessageError ? h2("div", {
8548
- className: "dxw-summary dim-cardSummary",
8549
- role: "status"
8550
- }, `\u6700\u8FD1\u4E00\u6761\u6D88\u606F\u5904\u7406\u5931\u8D25\uFF1A${account.lastMessageError.message}`) : null,
8551
- feedback ? h2("div", {
8552
- className: "dxw-summary dim-cardSummary",
8553
- role: "status",
8554
- "aria-live": "polite"
8555
- }, feedback) : null,
8556
8576
  h2(
8557
8577
  "div",
8558
- { className: "dxw-actions dim-cardActions" },
8578
+ { className: "dim-cardFooterLayout" },
8559
8579
  h2(
8560
- Button12,
8561
- { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) },
8562
- busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"
8580
+ "div",
8581
+ { className: "dxw-actions dim-cardActions" },
8582
+ h2(
8583
+ Button12,
8584
+ { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) },
8585
+ busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"
8586
+ ),
8587
+ h2(Button12, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
8563
8588
  ),
8564
- h2(Button12, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
8589
+ summary ? h2("div", { className: "dxw-summary dim-cardSummary" }, summary) : null,
8590
+ account.lastMessageError ? h2("div", {
8591
+ className: "dxw-summary dim-cardSummary",
8592
+ role: "status"
8593
+ }, `\u6700\u8FD1\u4E00\u6761\u6D88\u606F\u5904\u7406\u5931\u8D25\uFF1A${account.lastMessageError.message}`) : null,
8594
+ feedback ? h2("div", {
8595
+ className: "dxw-summary dim-cardFeedback",
8596
+ role: "status",
8597
+ "aria-live": "polite"
8598
+ }, feedback) : null
8565
8599
  )
8566
8600
  )
8567
8601
  ),
@@ -8587,7 +8621,11 @@ function AccountList2(props) {
8587
8621
  return h2(
8588
8622
  "section",
8589
8623
  { className: "dim-listSection" },
8590
- h2("div", { className: "dxw-listHeading dim-listHeading" }, h2("h3", null, "\u5DF2\u63A5\u5165\u7684\u5FAE\u4FE1\u8D26\u53F7")),
8624
+ h2(ChannelListHeading, {
8625
+ className: "dxw-listHeading",
8626
+ title: "\u5DF2\u63A5\u5165\u7684\u5FAE\u4FE1\u8D26\u53F7",
8627
+ connectionLabel: "iLink \u957F\u8F6E\u8BE2"
8628
+ }),
8591
8629
  h2("ul", { className: "dxw-list dim-botList" }, props.bots.map((account) => h2(
8592
8630
  "li",
8593
8631
  { key: account.botId },
@@ -8617,7 +8655,7 @@ function mergeWeixinProvisioningSnapshot(current, incoming, { restoreProvisionin
8617
8655
  };
8618
8656
  }
8619
8657
  function WeixinSettingsTab({ rpcCall }) {
8620
- const [model, setModel] = React17.useState({
8658
+ const [model, setModel] = React18.useState({
8621
8659
  phase: "loading",
8622
8660
  bots: [],
8623
8661
  totals: EMPTY_TOTALS3,
@@ -8625,33 +8663,33 @@ function WeixinSettingsTab({ rpcCall }) {
8625
8663
  error: null,
8626
8664
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
8627
8665
  });
8628
- const [provision, setProvision] = React17.useState(null);
8629
- const [busy, setBusy] = React17.useState(false);
8630
- const [busyByBot, setBusyByBot] = React17.useState({});
8631
- const [feedbackByBot, setFeedbackByBot] = React17.useState({});
8632
- const [removeTarget, setRemoveTarget] = React17.useState(null);
8633
- const [notice, setNotice] = React17.useState("");
8634
- const [now, setNow] = React17.useState(() => Date.now());
8635
- const addButtonRef = React17.useRef(null);
8636
- const mountedRef = React17.useRef(true);
8666
+ const [provision, setProvision] = React18.useState(null);
8667
+ const [busy, setBusy] = React18.useState(false);
8668
+ const [busyByBot, setBusyByBot] = React18.useState({});
8669
+ const [feedbackByBot, setFeedbackByBot] = React18.useState({});
8670
+ const [removeTarget, setRemoveTarget] = React18.useState(null);
8671
+ const [notice, setNotice] = React18.useState("");
8672
+ const [now, setNow] = React18.useState(() => Date.now());
8673
+ const addButtonRef = React18.useRef(null);
8674
+ const mountedRef = React18.useRef(true);
8637
8675
  const workspaceFence = useWorkspaceSnapshotFence();
8638
8676
  const scheduleAnimationFrame = useAnimationFrameScheduler();
8639
- React17.useEffect(() => {
8677
+ React18.useEffect(() => {
8640
8678
  mountedRef.current = true;
8641
8679
  return () => {
8642
8680
  mountedRef.current = false;
8643
8681
  };
8644
8682
  }, []);
8645
- const announce = React17.useCallback((value) => {
8683
+ const announce = React18.useCallback((value) => {
8646
8684
  setNotice("");
8647
8685
  scheduleAnimationFrame(() => {
8648
8686
  if (value) setNotice(value);
8649
8687
  }, "announcement");
8650
8688
  }, [scheduleAnimationFrame]);
8651
- const invoke = React17.useCallback(async (endpoint, payload = {}, signal) => {
8689
+ const invoke = React18.useCallback(async (endpoint, payload = {}, signal) => {
8652
8690
  return unwrapRpcResult8(await rpcCall(endpoint, payload, signal));
8653
8691
  }, [rpcCall]);
8654
- const loadStatus = React17.useCallback(async ({
8692
+ const loadStatus = React18.useCallback(async ({
8655
8693
  signal,
8656
8694
  silent = false,
8657
8695
  restoreProvisioning = false
@@ -8688,12 +8726,12 @@ function WeixinSettingsTab({ rpcCall }) {
8688
8726
  return void 0;
8689
8727
  }
8690
8728
  }, [invoke, workspaceFence]);
8691
- React17.useEffect(() => {
8729
+ React18.useEffect(() => {
8692
8730
  const controller = new AbortController();
8693
8731
  void loadStatus({ signal: controller.signal, restoreProvisioning: true });
8694
8732
  return () => controller.abort();
8695
8733
  }, [loadStatus]);
8696
- React17.useEffect(() => {
8734
+ React18.useEffect(() => {
8697
8735
  if (model.phase !== "ready") return void 0;
8698
8736
  const controller = new AbortController();
8699
8737
  let running = false;
@@ -8712,12 +8750,12 @@ function WeixinSettingsTab({ rpcCall }) {
8712
8750
  window.clearInterval(timer);
8713
8751
  };
8714
8752
  }, [loadStatus, model.phase]);
8715
- React17.useEffect(() => {
8753
+ React18.useEffect(() => {
8716
8754
  if (!provision || !["pending", "scanned"].includes(provision.status)) return void 0;
8717
8755
  const timer = window.setInterval(() => setNow(Date.now()), 1e3);
8718
8756
  return () => window.clearInterval(timer);
8719
8757
  }, [provision?.attemptId, provision?.status]);
8720
- const startProvisioning = React17.useCallback(async ({ replace = false } = {}) => {
8758
+ const startProvisioning = React18.useCallback(async ({ replace = false } = {}) => {
8721
8759
  setBusy(true);
8722
8760
  try {
8723
8761
  if (replace && provision?.attemptId) {
@@ -8738,7 +8776,7 @@ function WeixinSettingsTab({ rpcCall }) {
8738
8776
  setBusy(false);
8739
8777
  }
8740
8778
  }, [announce, invoke, provision?.attemptId]);
8741
- const cancelProvisioning = React17.useCallback(async () => {
8779
+ const cancelProvisioning = React18.useCallback(async () => {
8742
8780
  setBusy(true);
8743
8781
  try {
8744
8782
  if (provision?.attemptId && !["failed", "expired", "cancelled"].includes(provision.status)) {
@@ -8753,7 +8791,7 @@ function WeixinSettingsTab({ rpcCall }) {
8753
8791
  setBusy(false);
8754
8792
  }
8755
8793
  }, [announce, invoke, provision?.attemptId, provision?.status, scheduleAnimationFrame]);
8756
- const submitVerification = React17.useCallback(async (verifyCode) => {
8794
+ const submitVerification = React18.useCallback(async (verifyCode) => {
8757
8795
  if (!provision?.attemptId) return;
8758
8796
  setBusy(true);
8759
8797
  try {
@@ -8769,7 +8807,7 @@ function WeixinSettingsTab({ rpcCall }) {
8769
8807
  setBusy(false);
8770
8808
  }
8771
8809
  }, [announce, invoke, provision?.attemptId]);
8772
- React17.useEffect(() => {
8810
+ React18.useEffect(() => {
8773
8811
  const attemptId = provision?.attemptId;
8774
8812
  if (!attemptId || !["pending", "scanned", "connecting"].includes(provision.status)) return void 0;
8775
8813
  const controller = new AbortController();
@@ -8817,7 +8855,7 @@ function WeixinSettingsTab({ rpcCall }) {
8817
8855
  controller.abort();
8818
8856
  };
8819
8857
  }, [announce, invoke, loadStatus, provision?.attemptId, provision?.status, provision?.pollIntervalMs]);
8820
- const setBotBusy = React17.useCallback((botId, value) => {
8858
+ const setBotBusy = React18.useCallback((botId, value) => {
8821
8859
  setBusyByBot((current) => {
8822
8860
  const next = { ...current };
8823
8861
  if (value) next[botId] = value;
@@ -8825,7 +8863,7 @@ function WeixinSettingsTab({ rpcCall }) {
8825
8863
  return next;
8826
8864
  });
8827
8865
  }, []);
8828
- const reconnect = React17.useCallback(async (account) => {
8866
+ const reconnect = React18.useCallback(async (account) => {
8829
8867
  const snapshotVersion = workspaceFence.beginMutation();
8830
8868
  setBotBusy(account.botId, "reconnect");
8831
8869
  setFeedbackByBot((current) => {
@@ -8876,7 +8914,7 @@ function WeixinSettingsTab({ rpcCall }) {
8876
8914
  setBotBusy(account.botId, null);
8877
8915
  }
8878
8916
  }, [announce, invoke, loadStatus, setBotBusy, workspaceFence]);
8879
- const saveWorkspace = React17.useCallback(async (account, workspace) => {
8917
+ const saveWorkspace = React18.useCallback(async (account, workspace) => {
8880
8918
  const workspaceVersion = workspaceFence.beginMutation();
8881
8919
  setBotBusy(account.botId, "workspace");
8882
8920
  try {
@@ -8900,7 +8938,7 @@ function WeixinSettingsTab({ rpcCall }) {
8900
8938
  if (mountedRef.current) setBotBusy(account.botId, null);
8901
8939
  }
8902
8940
  }, [invoke, loadStatus, setBotBusy, workspaceFence]);
8903
- const saveAgentPreset = React17.useCallback(async (account, agentPreset) => {
8941
+ const saveAgentPreset = React18.useCallback(async (account, agentPreset) => {
8904
8942
  const snapshotVersion = workspaceFence.beginMutation();
8905
8943
  setBotBusy(account.botId, "preset");
8906
8944
  try {
@@ -8924,7 +8962,7 @@ function WeixinSettingsTab({ rpcCall }) {
8924
8962
  if (mountedRef.current) setBotBusy(account.botId, null);
8925
8963
  }
8926
8964
  }, [invoke, loadStatus, setBotBusy, workspaceFence]);
8927
- const remove = React17.useCallback(async (account) => {
8965
+ const remove = React18.useCallback(async (account) => {
8928
8966
  const snapshotVersion = workspaceFence.beginMutation();
8929
8967
  setBotBusy(account.botId, "delete");
8930
8968
  try {
@@ -9008,7 +9046,7 @@ function WeixinSettingsTab({ rpcCall }) {
9008
9046
  h2(Button12, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
9009
9047
  )
9010
9048
  ) : h2(
9011
- React17.Fragment,
9049
+ React18.Fragment,
9012
9050
  null,
9013
9051
  provisionView,
9014
9052
  model.bots.length === 0 && !provision ? h2(EmptyView5, { onStart: () => void startProvisioning(), busy }) : null,
@@ -9144,7 +9182,7 @@ function formatRemaining6(milliseconds) {
9144
9182
  }
9145
9183
 
9146
9184
  // plugin-src/client/channels/whatsapp/index.js
9147
- var React18 = __toESM(require("react"), 1);
9185
+ var React19 = __toESM(require("react"), 1);
9148
9186
 
9149
9187
  // plugin-src/client/channels/whatsapp/styles.js
9150
9188
  var WHATSAPP_STYLE_ID = "xmanrui-dsh-im-whatsapp-settings";
@@ -9169,7 +9207,7 @@ function installWhatsappStyles() {
9169
9207
 
9170
9208
  // plugin-src/client/channels/whatsapp/index.js
9171
9209
  var ACTIVE_STATES3 = /* @__PURE__ */ new Set(["pending", "connecting"]);
9172
- var Button14 = React18.forwardRef(function Button15({ children, kind = "secondary", className = "", ...props }, ref) {
9210
+ var Button14 = React19.forwardRef(function Button15({ children, kind = "secondary", className = "", ...props }, ref) {
9173
9211
  return h2("button", {
9174
9212
  ...props,
9175
9213
  ref,
@@ -9423,28 +9461,14 @@ function WhatsappAccountCard({
9423
9461
  h2("p", null, account.bot.idMasked)
9424
9462
  )
9425
9463
  ),
9426
- h2(
9427
- "div",
9428
- { className: "ddt-health dim-botHealth" },
9429
- h2("span", { className: "ddt-dot dim-healthDot", "data-tone": tone }),
9430
- h2("span", null, stateLabel2)
9431
- )
9432
- ),
9433
- h2(
9434
- "dl",
9435
- { className: "ddt-metrics dim-botMetrics" },
9436
- h2(
9437
- "div",
9438
- { className: "ddt-metric dim-botMetric" },
9439
- h2("dt", null, "\u6D88\u606F\u901A\u9053"),
9440
- h2("dd", null, account.connected ? "WhatsApp Web" : "\u79BB\u7EBF")
9441
- ),
9442
- h2(
9443
- "div",
9444
- { className: "ddt-metric dim-botMetric" },
9445
- h2("dt", null, "\u6700\u8FD1\u68C0\u67E5"),
9446
- h2("dd", null, checkedTime6(account.health.lastCheckedAt))
9447
- )
9464
+ h2(BotStatusMeta, {
9465
+ className: "ddt-health",
9466
+ dotClassName: "ddt-dot",
9467
+ tone,
9468
+ stateLabel: stateLabel2,
9469
+ lastCheckedAt: account.health.lastCheckedAt,
9470
+ formatCheckedTime: checkedTime6
9471
+ })
9448
9472
  ),
9449
9473
  h2(WorkspaceEditor, {
9450
9474
  workspace: account.workspace,
@@ -9459,25 +9483,29 @@ function WhatsappAccountCard({
9459
9483
  h2(
9460
9484
  "div",
9461
9485
  { className: "ddt-accountFooter dim-cardFooter" },
9462
- summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
9463
- testNotice ? h2("div", {
9464
- className: "ddt-summary dim-cardSummary",
9465
- role: "status"
9466
- }, testNotice) : null,
9467
9486
  h2(
9468
9487
  "div",
9469
- { className: "ddt-actions dim-cardActions" },
9470
- h2(Button14, {
9471
- className: "dim-cardAction",
9472
- onClick: onReconnect,
9473
- disabled: Boolean(busy)
9474
- }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
9475
- h2(Button14, {
9476
- className: "dim-cardAction",
9477
- kind: "danger",
9478
- onClick: onRequestRemove,
9479
- disabled: Boolean(busy)
9480
- }, "\u79FB\u9664\u63A5\u5165")
9488
+ { className: "dim-cardFooterLayout" },
9489
+ h2(
9490
+ "div",
9491
+ { className: "ddt-actions dim-cardActions" },
9492
+ h2(Button14, {
9493
+ className: "dim-cardAction",
9494
+ onClick: onReconnect,
9495
+ disabled: Boolean(busy)
9496
+ }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
9497
+ h2(Button14, {
9498
+ className: "dim-cardAction",
9499
+ kind: "danger",
9500
+ onClick: onRequestRemove,
9501
+ disabled: Boolean(busy)
9502
+ }, "\u79FB\u9664\u63A5\u5165")
9503
+ ),
9504
+ summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
9505
+ testNotice ? h2("div", {
9506
+ className: "ddt-summary dim-cardFeedback",
9507
+ role: "status"
9508
+ }, testNotice) : null
9481
9509
  )
9482
9510
  )
9483
9511
  ),
@@ -9490,23 +9518,23 @@ function WhatsappAccountCard({
9490
9518
  );
9491
9519
  }
9492
9520
  function WhatsappSettingsTab({ rpcCall }) {
9493
- const [model, setModel] = React18.useState({
9521
+ const [model, setModel] = React19.useState({
9494
9522
  phase: "loading",
9495
9523
  bots: [],
9496
9524
  totals: { configured: 0, connected: 0 },
9497
9525
  error: null,
9498
9526
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
9499
9527
  });
9500
- const [provision, setProvision] = React18.useState(null);
9501
- const [busy, setBusy] = React18.useState(false);
9502
- const [busyByBot, setBusyByBot] = React18.useState({});
9503
- const [testNoticeByBot, setTestNoticeByBot] = React18.useState({});
9504
- const [removeTarget, setRemoveTarget] = React18.useState(null);
9505
- const [now, setNow] = React18.useState(Date.now());
9506
- const mounted = React18.useRef(true);
9528
+ const [provision, setProvision] = React19.useState(null);
9529
+ const [busy, setBusy] = React19.useState(false);
9530
+ const [busyByBot, setBusyByBot] = React19.useState({});
9531
+ const [testNoticeByBot, setTestNoticeByBot] = React19.useState({});
9532
+ const [removeTarget, setRemoveTarget] = React19.useState(null);
9533
+ const [now, setNow] = React19.useState(Date.now());
9534
+ const mounted = React19.useRef(true);
9507
9535
  const workspaceFence = useWorkspaceSnapshotFence();
9508
- const addButtonRef = React18.useRef(null);
9509
- React18.useEffect(() => {
9536
+ const addButtonRef = React19.useRef(null);
9537
+ React19.useEffect(() => {
9510
9538
  const disposeDingtalk = installDingtalkStyles();
9511
9539
  const disposeWhatsapp = installWhatsappStyles();
9512
9540
  mounted.current = true;
@@ -9516,11 +9544,11 @@ function WhatsappSettingsTab({ rpcCall }) {
9516
9544
  disposeDingtalk();
9517
9545
  };
9518
9546
  }, []);
9519
- const invoke = React18.useCallback(async (endpoint, payload = {}, signal) => {
9547
+ const invoke = React19.useCallback(async (endpoint, payload = {}, signal) => {
9520
9548
  if (typeof rpcCall !== "function") throw new TypeError("WhatsApp \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
9521
9549
  return unwrapRpcResult9(await rpcCall(endpoint, payload, signal));
9522
9550
  }, [rpcCall]);
9523
- const loadStatus = React18.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
9551
+ const loadStatus = React19.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
9524
9552
  const workspaceVersion = workspaceFence.beginStatus();
9525
9553
  if (workspaceVersion === null) return void 0;
9526
9554
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
@@ -9550,12 +9578,12 @@ function WhatsappSettingsTab({ rpcCall }) {
9550
9578
  return void 0;
9551
9579
  }
9552
9580
  }, [invoke, workspaceFence]);
9553
- React18.useEffect(() => {
9581
+ React19.useEffect(() => {
9554
9582
  const controller = new AbortController();
9555
9583
  void loadStatus({ signal: controller.signal, restore: true });
9556
9584
  return () => controller.abort();
9557
9585
  }, [loadStatus]);
9558
- React18.useEffect(() => {
9586
+ React19.useEffect(() => {
9559
9587
  if (model.phase !== "ready") return void 0;
9560
9588
  const controller = new AbortController();
9561
9589
  const timer = window.setInterval(
@@ -9567,12 +9595,12 @@ function WhatsappSettingsTab({ rpcCall }) {
9567
9595
  window.clearInterval(timer);
9568
9596
  };
9569
9597
  }, [loadStatus, model.phase]);
9570
- React18.useEffect(() => {
9598
+ React19.useEffect(() => {
9571
9599
  if (!provision || !ACTIVE_STATES3.has(provision.status)) return void 0;
9572
9600
  const timer = window.setInterval(() => mounted.current && setNow(Date.now()), 1e3);
9573
9601
  return () => window.clearInterval(timer);
9574
9602
  }, [provision?.attemptId, provision?.status]);
9575
- const startProvisioning = React18.useCallback(async (replace = false) => {
9603
+ const startProvisioning = React19.useCallback(async (replace = false) => {
9576
9604
  setBusy(true);
9577
9605
  try {
9578
9606
  if (replace && provision?.attemptId) {
@@ -9590,7 +9618,7 @@ function WhatsappSettingsTab({ rpcCall }) {
9590
9618
  if (mounted.current) setBusy(false);
9591
9619
  }
9592
9620
  }, [invoke, provision?.attemptId]);
9593
- const closeProvision = React18.useCallback(async () => {
9621
+ const closeProvision = React19.useCallback(async () => {
9594
9622
  setBusy(true);
9595
9623
  try {
9596
9624
  if (provision?.attemptId && ACTIVE_STATES3.has(provision.status)) {
@@ -9601,7 +9629,7 @@ function WhatsappSettingsTab({ rpcCall }) {
9601
9629
  if (mounted.current) setBusy(false);
9602
9630
  }
9603
9631
  }, [invoke, provision?.attemptId, provision?.status]);
9604
- React18.useEffect(() => {
9632
+ React19.useEffect(() => {
9605
9633
  const attemptId = provision?.attemptId;
9606
9634
  if (!attemptId || !ACTIVE_STATES3.has(provision.status)) return void 0;
9607
9635
  const controller = new AbortController();
@@ -9642,7 +9670,7 @@ function WhatsappSettingsTab({ rpcCall }) {
9642
9670
  if (timer) window.clearTimeout(timer);
9643
9671
  };
9644
9672
  }, [invoke, loadStatus, provision?.attemptId, provision?.status]);
9645
- const botAction = React18.useCallback(async (account, operation, endpoint, payload) => {
9673
+ const botAction = React19.useCallback(async (account, operation, endpoint, payload) => {
9646
9674
  const snapshotVersion = workspaceFence.beginMutation();
9647
9675
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
9648
9676
  if (operation === "reconnect") {
@@ -9691,11 +9719,11 @@ function WhatsappSettingsTab({ rpcCall }) {
9691
9719
  const botList = model.bots.length > 0 ? h2(
9692
9720
  "section",
9693
9721
  { className: "dim-listSection" },
9694
- h2(
9695
- "div",
9696
- { className: "ddt-listHeading dim-listHeading" },
9697
- h2("h3", null, "\u5DF2\u63A5\u5165\u7684 WhatsApp \u673A\u5668\u4EBA")
9698
- ),
9722
+ h2(ChannelListHeading, {
9723
+ className: "ddt-listHeading",
9724
+ title: "\u5DF2\u63A5\u5165\u7684 WhatsApp \u673A\u5668\u4EBA",
9725
+ connectionLabel: "WhatsApp Web"
9726
+ }),
9699
9727
  h2("ul", { className: "ddt-list dim-botList" }, model.bots.map((account) => h2("li", { key: account.botId }, h2(WhatsappAccountCard, {
9700
9728
  account,
9701
9729
  busy: busyByBot[account.botId],
@@ -9755,7 +9783,7 @@ function WhatsappSettingsTab({ rpcCall }) {
9755
9783
  h2(Button14, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
9756
9784
  )
9757
9785
  ) : h2(
9758
- React18.Fragment,
9786
+ React19.Fragment,
9759
9787
  null,
9760
9788
  provision?.status === "pending" ? h2(QrPanel5, {
9761
9789
  provision,
@@ -9863,6 +9891,14 @@ var CSS11 = String.raw`
9863
9891
  .dim-panel .dim-listSection { display: flex; flex-direction: column; gap: 0; }
9864
9892
  .dim-panel .dim-listHeading { min-height: 0; display: flex; align-items: center; justify-content: space-between; gap: 16px; margin: 0 0 6px; padding: 0; }
9865
9893
  .dim-panel .dim-listHeading h3 { margin: 0; color: var(--dsw-alias-label-primary, #1f2329); font-size: 14px; line-height: normal; font-weight: 650; }
9894
+ .dim-panel .dim-listTitle { min-width: 0; display: inline-flex; align-items: center; gap: 6px; }
9895
+ .dim-panel .dim-channelHelp { position: relative; display: inline-flex; flex: none; }
9896
+ .dim-panel .dim-channelHelpButton { width: 17px; height: 17px; display: grid; place-items: center; padding: 0; border: 1px solid color-mix(in srgb, #1677ff 28%, var(--dsw-alias-border-l2, #dfe1e5)); border-radius: 50%; color: #1677ff; background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 11px; line-height: 1; font-weight: 700; cursor: help; transition: border-color .15s ease, color .15s ease, background .15s ease, box-shadow .15s ease; }
9897
+ .dim-panel .dim-channelHelpButton:hover { border-color: #1677ff; color: #0f5fce; background: color-mix(in srgb, #1677ff 8%, var(--dsw-alias-bg-layer-1, #fff)); }
9898
+ .dim-panel .dim-channelHelpButton:focus-visible { outline: none; border-color: #1677ff; box-shadow: 0 0 0 3px color-mix(in srgb, #1677ff 16%, transparent); }
9899
+ .dim-panel .dim-channelTooltip { position: absolute; top: calc(100% + 7px); left: 0; z-index: 30; width: max-content; max-width: min(280px, calc(100vw - 48px)); display: flex; align-items: baseline; gap: 5px; padding: 8px 10px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 10px 28px rgb(31 35 41 / 16%); font-size: 11px; line-height: 16px; font-weight: 400; white-space: normal; opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
9900
+ .dim-panel .dim-channelTooltip strong { color: var(--dsw-alias-label-primary, #1f2329); font-weight: 600; white-space: nowrap; }
9901
+ .dim-panel .dim-channelHelp:hover .dim-channelTooltip, .dim-panel .dim-channelHelp:focus-within .dim-channelTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
9866
9902
  .dim-panel .dim-botList { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
9867
9903
  .dim-panel .dim-loadingView { padding: 38px; color: var(--dsw-alias-label-secondary, #646a73); text-align: center; }
9868
9904
  .dim-panel .dim-loadingView h3 { margin: 0 0 7px; color: var(--dsw-alias-label-primary, #1f2329); font-size: 17px; line-height: normal; font-weight: 650; }
@@ -9919,13 +9955,18 @@ var CSS11 = String.raw`
9919
9955
  .dim-panel .dim-workspaceEdit:disabled { cursor: not-allowed; opacity: .55; }
9920
9956
  .dim-panel .dim-workspacePath { min-width: 0; max-width: 100%; grid-column: 1 / -1; grid-row: 2; display: block; overflow-x: auto; overflow-y: hidden; color: var(--dsw-alias-label-primary, #1f2329); font: 12px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace; white-space: nowrap; }
9921
9957
  .dim-panel .dim-preset { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr) max-content; align-items: center; column-gap: 10px; row-gap: 4px; margin-top: 6px; padding: 6px 10px; border: 1px solid var(--dsw-alias-border-l1, #eef0f3); border-radius: 9px; background: var(--dsw-alias-bg-module-platform, #f7f8fa); }
9922
- .dim-panel .dim-presetHeader { display: contents; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: normal; }
9923
- .dim-panel .dim-presetHeader > span { grid-column: 1; grid-row: 1; white-space: nowrap; }
9958
+ .dim-panel .dim-presetHeader { position: relative; min-width: 0; grid-column: 1 / -1; grid-row: 1; display: flex; align-items: center; justify-content: space-between; gap: 10px; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: normal; }
9959
+ .dim-panel .dim-presetTitle { min-width: 0; display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
9960
+ .dim-panel .dim-presetHelp { display: inline-flex; align-items: center; flex: none; }
9961
+ .dim-panel .dim-presetHelpButton { width: 17px; height: 17px; display: grid; place-items: center; padding: 0; border: 1px solid color-mix(in srgb, #1677ff 28%, var(--dsw-alias-border-l2, #dfe1e5)); border-radius: 50%; color: #1677ff; background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 11px; line-height: 1; font-weight: 700; cursor: help; transition: border-color .15s ease, color .15s ease, background .15s ease, box-shadow .15s ease; }
9962
+ .dim-panel .dim-presetHelpButton:hover { border-color: #1677ff; color: #0f5fce; background: color-mix(in srgb, #1677ff 8%, var(--dsw-alias-bg-layer-1, #fff)); }
9963
+ .dim-panel .dim-presetHelpButton:focus-visible { outline: none; border-color: #1677ff; box-shadow: 0 0 0 3px color-mix(in srgb, #1677ff 16%, transparent); }
9964
+ .dim-panel .dim-presetTooltip { position: absolute; top: calc(100% + 7px); left: 0; z-index: 30; width: min(320px, 100%); padding: 9px 10px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 10px 28px rgb(31 35 41 / 16%); font-size: 11px; line-height: 16px; font-weight: 400; overflow-wrap: anywhere; white-space: normal; opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
9965
+ .dim-panel .dim-presetHelp:hover .dim-presetTooltip, .dim-panel .dim-presetHelp:focus-within .dim-presetTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
9924
9966
  .dim-panel .dim-presetStatus { grid-column: 2; grid-row: 1; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 12px; white-space: nowrap; }
9925
9967
  .dim-panel .dim-presetSelect { min-width: 0; max-width: 100%; grid-column: 1 / -1; grid-row: 2; height: 30px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 7px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 12px; }
9926
9968
  .dim-panel .dim-presetSelect:disabled { cursor: not-allowed; opacity: .55; }
9927
- .dim-panel .dim-presetHelp { grid-column: 1 / -1; grid-row: 3; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 11px; line-height: 1.4; }
9928
- .dim-panel .dim-presetError { grid-column: 1 / -1; grid-row: 4; margin: 0; color: var(--dsw-alias-state-error-primary, #d54941); font-size: 12px; line-height: 1.4; }
9969
+ .dim-panel .dim-presetError { grid-column: 1 / -1; grid-row: 3; margin: 0; color: var(--dsw-alias-state-error-primary, #d54941); font-size: 12px; line-height: 1.4; }
9929
9970
  .dim-directoryPickerBackdrop { --dim-blue: var(--dsw-alias-state-business-primary, #3370ff); --dim-blue-soft: color-mix(in srgb, var(--dim-blue) 9%, transparent); position: fixed; inset: 0; z-index: 1000; display: grid; place-items: center; padding: 24px; background: rgb(15 17 21 / 42%); backdrop-filter: blur(3px); }
9930
9971
  .dim-directoryPickerBackdrop, .dim-directoryPickerBackdrop *, .dim-directoryPickerBackdrop *::before, .dim-directoryPickerBackdrop *::after { box-sizing: border-box; }
9931
9972
  .dim-directoryPicker { width: min(720px, 100%); height: min(620px, calc(100vh - 48px)); min-height: 420px; display: grid; grid-template-rows: auto minmax(0, 1fr) auto; overflow: hidden; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 18px; outline: none; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-1, #fff); box-shadow: 0 24px 72px rgb(15 17 21 / 24%); }
@@ -9968,6 +10009,9 @@ var CSS11 = String.raw`
9968
10009
  .dim-directoryPickerActions button:hover:not(:disabled) { filter: brightness(.97); }
9969
10010
  .dim-directoryPickerActions button:disabled { cursor: not-allowed; opacity: .52; }
9970
10011
  .dim-panel .dim-cardSummary { min-width: 0; color: var(--dsw-alias-label-secondary, #646a73); font: inherit; font-size: 12px; font-weight: 400; line-height: normal; }
10012
+ .dim-panel .dim-cardFooterLayout { min-width: 0; width: 100%; display: flex; flex-direction: column; align-items: stretch; gap: 9px; }
10013
+ .dim-panel .dim-cardFooterLayout > .dim-cardActions { align-self: flex-end; }
10014
+ .dim-panel .dim-cardFeedback { width: 100%; padding: 8px 10px; border-radius: 8px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-module-platform, #f7f8fa); font: inherit; font-size: 12px; font-weight: 400; line-height: 18px; overflow-wrap: anywhere; white-space: normal; }
9971
10015
  .dim-panel .dim-cardActions { flex: none; display: flex; align-items: center; flex-wrap: nowrap; gap: 8px; margin: 0 0 0 auto; }
9972
10016
  .dim-panel .dim-cardActions .dim-cardAction { flex: none; min-height: 32px; padding: 0 11px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 13px; font-weight: 560; line-height: normal; white-space: nowrap; }
9973
10017
  .dim-panel .dim-cardActions .dim-cardAction:hover:not(:disabled) { border-color: #aeb3bb; background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
@@ -9982,15 +10026,13 @@ var CSS11 = String.raw`
9982
10026
  .dim-panel .dim-botName { min-width: 0; }
9983
10027
  .dim-panel .dim-botName h3 { overflow: hidden; margin: 0; color: var(--dsw-alias-label-primary, #1f2329); font-size: 15px; font-weight: 650; line-height: normal; text-overflow: ellipsis; white-space: nowrap; }
9984
10028
  .dim-panel .dim-botName p { overflow: hidden; margin: 4px 0 0; color: var(--dsw-alias-label-secondary, #646a73); font: 12px ui-monospace, SFMono-Regular, monospace; line-height: normal; text-overflow: ellipsis; white-space: nowrap; }
10029
+ .dim-panel .dim-botHealthGroup { flex: none; display: grid; justify-items: end; gap: 5px; }
9985
10030
  .dim-panel .dim-botCard .dim-botHealth { flex: none; min-height: 0; display: inline-flex; align-items: center; gap: 7px; padding: 0; border: 0; border-radius: 0; color: var(--dsw-alias-label-secondary, #646a73); background: transparent; font: inherit; font-size: 12px; font-weight: 400; line-height: normal; white-space: nowrap; }
10031
+ .dim-panel .dim-lastChecked { display: inline-flex; align-items: baseline; gap: 4px; color: var(--dsw-alias-label-tertiary, #8f959e); font: inherit; font-size: 11px; font-weight: 400; line-height: normal; white-space: nowrap; }
9986
10032
  .dim-panel .dim-botCard .dim-healthDot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: #aeb3bb; box-shadow: none; }
9987
10033
  .dim-panel .dim-botCard .dim-healthDot[data-tone="success"] { background: var(--dsw-alias-state-success-primary, #20a162); box-shadow: 0 0 0 3px color-mix(in srgb, var(--dsw-alias-state-success-primary, #20a162) 14%, transparent); }
9988
10034
  .dim-panel .dim-botCard .dim-healthDot[data-tone="warning"] { background: var(--dsw-alias-state-warn-primary, #d97706); }
9989
10035
  .dim-panel .dim-botCard .dim-healthDot[data-tone="error"] { background: var(--dsw-alias-state-error-primary, #d54941); }
9990
- .dim-panel .dim-botMetrics { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin: 6px 0; }
9991
- .dim-panel .dim-botMetric { min-width: 0; padding: 6px 8px; border: 0; border-radius: 9px; background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
9992
- .dim-panel .dim-botMetric dt { margin: 0; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 11px; font-weight: 400; line-height: normal; }
9993
- .dim-panel .dim-botMetric dd { overflow: hidden; margin: 3px 0 0; color: var(--dsw-alias-label-primary, #1f2329); font-size: 12px; font-weight: 400; line-height: normal; text-overflow: ellipsis; white-space: nowrap; }
9994
10036
  .dim-panel .dim-botCard .dim-cardFooter { margin-top: 0; }
9995
10037
  .dim-panel .ddt-headingCopy { display: none; }
9996
10038
  .dim-panel .ddt-qrFrame, .dim-panel .ddt-countdown { width: min(270px, 100%); }
@@ -10021,6 +10063,7 @@ var CSS11 = String.raw`
10021
10063
  }
10022
10064
  @media (max-width: 720px) {
10023
10065
  .dim-panel .dim-botCardTop { flex-direction: column; align-items: stretch; }
10066
+ .dim-panel .dim-botHealthGroup { justify-items: start; }
10024
10067
  }
10025
10068
  @media (max-width: 560px) {
10026
10069
  .dim-title { flex-direction: column; gap: 10px; }
@@ -10156,8 +10199,8 @@ function IMSettingsTab({
10156
10199
  officeRpcCall,
10157
10200
  workspaceDirectoryPicker
10158
10201
  }) {
10159
- const [selected, setSelected] = React19.useState("weixin");
10160
- const githubTooltipId = React19.useId();
10202
+ const [selected, setSelected] = React20.useState("weixin");
10203
+ const githubTooltipId = React20.useId();
10161
10204
  const active = CHANNELS.find((channel4) => channel4.id === selected) ?? CHANNELS[0];
10162
10205
  return h2(
10163
10206
  WorkspaceDirectoryPickerContext.Provider,