@xmanrui/dsh-im 4.28.1 → 4.29.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -590,12 +590,13 @@ async function callManagementRpc(connection, channel7, method, payload, signal)
590
590
  }
591
591
 
592
592
  // plugin-src/client/index.js
593
- var React34 = __toESM(require("react"), 1);
593
+ var React36 = __toESM(require("react"), 1);
594
594
 
595
595
  // package.json
596
596
  var package_default = {
597
597
  name: "@xmanrui/dsh-im",
598
- version: "4.28.1",
598
+ version: "4.29.1",
599
+ icon: "./assets/logo-plugin-message-link-gradient.webp",
599
600
  description: "\u628A\u5341\u4E8C\u79CD IM \u6E20\u9053\u548C\u516C\u7F51 AI Office \u63A5\u5165\u672C\u673A DeepSeek Harness\u3002 Connect twelve IM channels and a public AI Office to a local DeepSeek Harness.",
600
601
  keywords: [
601
602
  "deepseek-harness",
@@ -680,6 +681,10 @@ var package_default = {
680
681
  {
681
682
  name: "Zhe (Phil) Yang",
682
683
  url: "https://github.com/yangzhe1991"
684
+ },
685
+ {
686
+ name: "Biertolovisk",
687
+ url: "https://github.com/rosalynthompson32-a11y"
683
688
  }
684
689
  ],
685
690
  license: "MIT",
@@ -1486,6 +1491,22 @@ var EN = Object.freeze({
1486
1491
  "\u63A8\u8350\u957F\u4EFB\u52A1\u4F7F\u7528\uFF1A\u8FC7\u7A0B\u4E0E\u6700\u7EC8\u7B54\u6848\u90FD\u5728\u540C\u4E00\u5F20\u5361\u7247\u91CC\u5B9E\u65F6\u66F4\u65B0\uFF0C\u4E0D\u5237\u5C4F": "Recommended for long tasks: the process and the final answer update live in one card without flooding the chat",
1487
1492
  "\u6BCF\u4E00\u6B65\u90FD\u5355\u72EC\u53D1\u4E00\u6761\u6D88\u606F\uFF08\u542B\u5DE5\u5177\u8C03\u7528\u548C\u8FC7\u7A0B\u8BF4\u660E\uFF09\uFF1B\u6CE8\u610F\u957F\u4EFB\u52A1\u4F1A\u8FDE\u7EED\u53D1\u9001\u8F83\u591A\u6D88\u606F": "Every step is sent as its own message (including tool calls and notes); long tasks may send many messages in a row",
1488
1493
  "\u5206\u6B65\u76F4\u63A8\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002": "Could not save the step push setting. Try again.",
1494
+ "\u8BED\u97F3\u4EA4\u4E92": "Voice",
1495
+ "\u6B63\u5728\u8BFB\u53D6\u8BED\u97F3\u8BBE\u7F6E\u2026": "Loading voice settings\u2026",
1496
+ "\u98DE\u4E66\u8BED\u97F3\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002": "Feishu voice settings are unavailable.",
1497
+ "\u672A\u627E\u5230\u5F53\u524D\u98DE\u4E66\u673A\u5668\u4EBA\uFF0C\u8BF7\u8FD4\u56DE\u5217\u8868\u540E\u91CD\u8BD5\u3002": "This Feishu bot was not found. Return to the bot list and try again.",
1498
+ "\u67E5\u770B\u8BED\u97F3\u4EA4\u4E92\u8BF4\u660E": "View voice help",
1499
+ "\u8BED\u97F3\u4EA4\u4E92\u5F00\u5173": "Voice on/off",
1500
+ "\u5F00\u542F(\u8BED\u97F3\u63D0\u95EE\u4E0E\u8BED\u97F3\u56DE\u590D)": "On (voice questions and voice replies)",
1501
+ "\u6536\u5230\u8BED\u97F3\u6D88\u606F\u65F6\u8F6C\u5199\u4E3A\u6587\u5B57\u5E76\u6309\u6587\u5B57\u6D41\u6C34\u7EBF\u5904\u7406,\u7B54\u6848\u540C\u65F6\u4EE5\u8BED\u97F3\u56DE\u590D;\u8F6C\u5199\u5931\u8D25\u65F6\u964D\u7EA7\u4E3A\u4EC5\u652F\u6301\u6587\u5B57/\u56FE\u7247/\u6587\u4EF6\u7684\u63D0\u793A\u3002\u51ED\u636E\u503C\u5728\u63D2\u4EF6\u51ED\u636E\u5E93\u91CC\u7BA1\u7406,\u8FD9\u91CC\u53EA\u5F15\u7528\u73AF\u5883\u53D8\u91CF\u540D\u3002": "Voice messages are transcribed to text and processed by the normal text pipeline; the answer is also sent as a voice reply. If transcription fails, the bot falls back to the text/image/file-only notice. The credential value lives in the plugin credential store; only the environment variable name is referenced here.",
1502
+ "\u51ED\u636E\u5F15\u7528(\u73AF\u5883\u53D8\u91CF\u540D)": "Credential reference (environment variable name)",
1503
+ "\u8F6C\u5199\u6A21\u578B(ASR)": "Transcription model (ASR)",
1504
+ "\u5408\u6210\u6A21\u578B(TTS)": "Synthesis model (TTS)",
1505
+ "\u56DE\u590D\u97F3\u8272": "Reply voice",
1506
+ '\u9700\u8981 DashScope \u5BC6\u94A5(\u51ED\u636E\u5E93\u4E2D\u4EE5"\u51ED\u636E\u5F15\u7528"\u4E3A\u540D\u7684\u73AF\u5883\u53D8\u91CF)\u4E0E\u53EF\u7528 ffmpeg;\u97F3\u8272\u652F\u6301 Cherry/Serena/Bella/Chelsie/Momo/Katerina \u7B49 qwen3-tts-flash \u5B98\u65B9\u97F3\u8272\u3002': "Requires a DashScope API key (the credential-store environment variable named by the credential reference above) and a working ffmpeg. Supported voices include the official qwen3-tts-flash voices Cherry/Serena/Bella/Chelsie/Momo/Katerina.",
1507
+ "\u4FDD\u5B58\u8BED\u97F3\u8BBE\u7F6E": "Save voice settings",
1508
+ "\u9ED8\u8BA4\u5173\u95ED;\u5F00\u542F\u540E\u673A\u5668\u4EBA\u53EF\u542C\u61C2\u8BED\u97F3\u6D88\u606F\u5E76\u4EE5\u8BED\u97F3\u56DE\u590D\u3002": "Off by default. When enabled, the bot understands voice messages and replies by voice.",
1509
+ "\u8BED\u97F3\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002": "Could not save the voice settings. Try again.",
1489
1510
  "zcode\u8FC7\u7A0B\u5361\u6A21\u5F0F": "ZCode process-card mode",
1490
1511
  "\u8FC7\u7A0B\u8BF4\u660E\u3001\u5DE5\u5177\u6458\u8981\u4E0E\u6700\u7EC8\u7B54\u6848\u90FD\u5728\u540C\u4E00\u5F20\u5361\u7247\u4E2D\u539F\u5730\u5237\u65B0": "Process notes, the tool summary, and the final answer refresh in place inside one card",
1491
1512
  "\u601D\u8003\u4E0E\u5DE5\u5177\u6458\u8981\u6298\u53E0\u5C55\u793A\uFF0C\u6700\u7EC8\u7B54\u6848\u5728\u540C\u4E00\u5F20\u5361\u7247\u4E2D\u539F\u5730\u5237\u65B0": "Thinking and the tool summary stay folded; the final answer refreshes in place inside one card",
@@ -7198,6 +7219,29 @@ function normalizeFeishuStepPushMode(value) {
7198
7219
  return FEISHU_STEP_PUSH_MODES.POST;
7199
7220
  }
7200
7221
 
7222
+ // src/channels/feishu/voice-config.mjs
7223
+ var DEFAULT_ASR_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1";
7224
+ var DEFAULT_ASR_MODEL = "qwen3-asr-flash";
7225
+ var DEFAULT_TTS_MODEL = "qwen3-tts-flash";
7226
+ var DEFAULT_TTS_VOICE = "Momo";
7227
+ function cleanString(value) {
7228
+ return typeof value === "string" && value.trim() ? value.trim() : null;
7229
+ }
7230
+ function normalizeFeishuVoiceConfig(value) {
7231
+ if (value == null || typeof value !== "object" || value.enabled !== true) return null;
7232
+ const secretRef = cleanString(value.secretRef);
7233
+ if (!secretRef || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(secretRef)) return null;
7234
+ return Object.freeze({
7235
+ enabled: true,
7236
+ secretRef,
7237
+ asrModel: cleanString(value.asrModel) ?? DEFAULT_ASR_MODEL,
7238
+ ttsModel: cleanString(value.ttsModel) ?? DEFAULT_TTS_MODEL,
7239
+ ttsVoice: cleanString(value.ttsVoice) ?? DEFAULT_TTS_VOICE,
7240
+ asrBaseUrl: cleanString(value.asrBaseUrl) ?? DEFAULT_ASR_BASE_URL,
7241
+ ffmpeg: cleanString(value.ffmpeg)
7242
+ });
7243
+ }
7244
+
7201
7245
  // plugin-src/client/channels/feishu/api.js
7202
7246
  var FEISHU_RPC_CHANNEL = "/feishu";
7203
7247
  var FEISHU_ENDPOINTS = Object.freeze({
@@ -7221,6 +7265,7 @@ var FEISHU_ENDPOINTS = Object.freeze({
7221
7265
  setGroupTopicReply: "bot.group-topic-reply.set",
7222
7266
  setStepPush: "bot.step-push.set",
7223
7267
  setStepPushMode: "bot.step-push-mode.set",
7268
+ setVoice: "bot.voice.set",
7224
7269
  // Kept for rolling upgrades. The multi-bot UI never calls these endpoints.
7225
7270
  testConnection: "connection.test",
7226
7271
  disconnect: "connection.disconnect"
@@ -7377,6 +7422,7 @@ function normalizeBotConnection(value, fallbackBotId) {
7377
7422
  groupTopicReply: value.groupTopicReply === true,
7378
7423
  stepPush: value.stepPush === true,
7379
7424
  stepPushMode: normalizeFeishuStepPushMode(value.stepPushMode),
7425
+ voice: normalizeFeishuVoiceConfig(value.voice),
7380
7426
  groupMessagePermissionGranted: value.groupMessagePermissionGranted === true,
7381
7427
  bot: normalizeBot2(value.bot),
7382
7428
  health: normalizeHealth(value.health, connected),
@@ -16075,7 +16121,7 @@ function installInterfaceLanguageMirror(ctx, {
16075
16121
  }
16076
16122
 
16077
16123
  // plugin-src/client/delivery-settings.js
16078
- var React30 = __toESM(require("react"), 1);
16124
+ var React32 = __toESM(require("react"), 1);
16079
16125
 
16080
16126
  // plugin-src/client/access-policy-settings.js
16081
16127
  var React28 = __toESM(require("react"), 1);
@@ -17078,6 +17124,200 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
17078
17124
  );
17079
17125
  }
17080
17126
 
17127
+ // plugin-src/client/channels/feishu/voice-settings.js
17128
+ var React31 = __toESM(require("react"), 1);
17129
+
17130
+ // plugin-src/client/channels/feishu/voice-editor.js
17131
+ var React30 = __toESM(require("react"), 1);
17132
+ function VoiceEditor({ value = null, disabled = false, onSave }) {
17133
+ const [enabled, setEnabled] = React30.useState(value != null);
17134
+ const [secretRef, setSecretRef] = React30.useState(value?.secretRef ?? "DASHSCOPE_API_KEY");
17135
+ const [asrModel, setAsrModel] = React30.useState(value?.asrModel ?? "qwen3-asr-flash");
17136
+ const [ttsModel, setTtsModel] = React30.useState(value?.ttsModel ?? "qwen3-tts-flash");
17137
+ const [ttsVoice, setTtsVoice] = React30.useState(value?.ttsVoice ?? "Momo");
17138
+ const [saving, setSaving] = React30.useState(false);
17139
+ const [error, setError] = React30.useState(null);
17140
+ const titleId = React30.useId();
17141
+ const helpId = `${titleId}-help`;
17142
+ React30.useEffect(() => {
17143
+ setEnabled(value != null);
17144
+ if (value) {
17145
+ setSecretRef(value.secretRef ?? "DASHSCOPE_API_KEY");
17146
+ setAsrModel(value.asrModel ?? "qwen3-asr-flash");
17147
+ setTtsModel(value.ttsModel ?? "qwen3-tts-flash");
17148
+ setTtsVoice(value.ttsVoice ?? "Momo");
17149
+ }
17150
+ }, [value]);
17151
+ const persist = async (payload) => {
17152
+ if (saving || disabled) return;
17153
+ setSaving(true);
17154
+ setError(null);
17155
+ try {
17156
+ await onSave?.(payload);
17157
+ } catch (cause) {
17158
+ setError(cause?.message ?? "\u8BED\u97F3\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002");
17159
+ } finally {
17160
+ setSaving(false);
17161
+ }
17162
+ };
17163
+ const save = () => persist(enabled ? { enabled: true, secretRef, asrModel, ttsModel, ttsVoice } : null);
17164
+ const toggle = (next) => {
17165
+ setEnabled(next);
17166
+ if (!next) void persist(null);
17167
+ };
17168
+ const input = (label, state, setState, placeholder) => h2(
17169
+ "label",
17170
+ { className: "dim-feishuVoiceField" },
17171
+ h2("span", { className: "dim-feishuVoiceLabel" }, label),
17172
+ h2("input", {
17173
+ type: "text",
17174
+ className: "dim-feishuVoiceInput",
17175
+ value: state,
17176
+ placeholder,
17177
+ disabled: disabled || saving,
17178
+ onChange: (event) => setState(event.target.value)
17179
+ })
17180
+ );
17181
+ return h2(
17182
+ "section",
17183
+ {
17184
+ className: "dim-feishuGroupControl",
17185
+ "aria-labelledby": titleId
17186
+ },
17187
+ h2(
17188
+ "div",
17189
+ { className: "dim-feishuGroupControlHeader" },
17190
+ h2(
17191
+ "div",
17192
+ { className: "dim-presetTitle" },
17193
+ h2("h3", { id: titleId }, "\u8BED\u97F3\u4EA4\u4E92"),
17194
+ h2(
17195
+ "span",
17196
+ { className: "dim-presetHelp" },
17197
+ h2("button", {
17198
+ type: "button",
17199
+ className: "dim-presetHelpButton",
17200
+ "aria-label": "\u67E5\u770B\u8BED\u97F3\u4EA4\u4E92\u8BF4\u660E",
17201
+ "aria-describedby": helpId
17202
+ }, h2("span", { "aria-hidden": "true" }, "?")),
17203
+ h2("span", {
17204
+ id: helpId,
17205
+ className: "dim-presetTooltip",
17206
+ role: "tooltip"
17207
+ }, "\u6536\u5230\u8BED\u97F3\u6D88\u606F\u65F6\u8F6C\u5199\u4E3A\u6587\u5B57\u5E76\u6309\u6587\u5B57\u6D41\u6C34\u7EBF\u5904\u7406,\u7B54\u6848\u540C\u65F6\u4EE5\u8BED\u97F3\u56DE\u590D;\u8F6C\u5199\u5931\u8D25\u65F6\u964D\u7EA7\u4E3A\u4EC5\u652F\u6301\u6587\u5B57/\u56FE\u7247/\u6587\u4EF6\u7684\u63D0\u793A\u3002\u51ED\u636E\u503C\u5728\u63D2\u4EF6\u51ED\u636E\u5E93\u91CC\u7BA1\u7406,\u8FD9\u91CC\u53EA\u5F15\u7528\u73AF\u5883\u53D8\u91CF\u540D\u3002")
17208
+ )
17209
+ ),
17210
+ saving ? h2("span", { className: "dim-feishuGroupControlStatus", role: "status" }, "\u4FDD\u5B58\u4E2D\u2026") : null
17211
+ ),
17212
+ h2(
17213
+ "select",
17214
+ {
17215
+ className: "dim-feishuGroupSelect",
17216
+ value: enabled ? "on" : "off",
17217
+ disabled: disabled || saving,
17218
+ "aria-label": "\u8BED\u97F3\u4EA4\u4E92\u5F00\u5173",
17219
+ onChange: (event) => toggle(event.target.value === "on")
17220
+ },
17221
+ h2("option", { value: "off" }, "\u5173\u95ED"),
17222
+ h2("option", { value: "on" }, "\u5F00\u542F(\u8BED\u97F3\u63D0\u95EE\u4E0E\u8BED\u97F3\u56DE\u590D)")
17223
+ ),
17224
+ enabled ? h2(
17225
+ "div",
17226
+ { className: "dim-feishuVoiceForm" },
17227
+ input("\u51ED\u636E\u5F15\u7528(\u73AF\u5883\u53D8\u91CF\u540D)", secretRef, setSecretRef, "DASHSCOPE_API_KEY"),
17228
+ input("\u8F6C\u5199\u6A21\u578B(ASR)", asrModel, setAsrModel, "qwen3-asr-flash"),
17229
+ input("\u5408\u6210\u6A21\u578B(TTS)", ttsModel, setTtsModel, "qwen3-tts-flash"),
17230
+ input("\u56DE\u590D\u97F3\u8272", ttsVoice, setTtsVoice, "Momo"),
17231
+ h2(
17232
+ "p",
17233
+ { className: "dim-feishuGroupHelp" },
17234
+ '\u9700\u8981 DashScope \u5BC6\u94A5(\u51ED\u636E\u5E93\u4E2D\u4EE5"\u51ED\u636E\u5F15\u7528"\u4E3A\u540D\u7684\u73AF\u5883\u53D8\u91CF)\u4E0E\u53EF\u7528 ffmpeg;\u97F3\u8272\u652F\u6301 Cherry/Serena/Bella/Chelsie/Momo/Katerina \u7B49 qwen3-tts-flash \u5B98\u65B9\u97F3\u8272\u3002'
17235
+ ),
17236
+ h2(
17237
+ "div",
17238
+ { className: "dim-feishuVoiceActions" },
17239
+ h2("button", {
17240
+ type: "button",
17241
+ className: "dim-feishuVoiceSave",
17242
+ onClick: () => void save(),
17243
+ disabled: disabled || saving || !secretRef.trim()
17244
+ }, "\u4FDD\u5B58\u8BED\u97F3\u8BBE\u7F6E")
17245
+ )
17246
+ ) : h2("p", { className: "dim-feishuGroupHelp" }, "\u9ED8\u8BA4\u5173\u95ED;\u5F00\u542F\u540E\u673A\u5668\u4EBA\u53EF\u542C\u61C2\u8BED\u97F3\u6D88\u606F\u5E76\u4EE5\u8BED\u97F3\u56DE\u590D\u3002"),
17247
+ error ? h2("p", {
17248
+ className: "dim-feishuGroupError",
17249
+ role: "alert"
17250
+ }, error) : null
17251
+ );
17252
+ }
17253
+
17254
+ // plugin-src/client/channels/feishu/voice-settings.js
17255
+ function FeishuVoiceSettingsPage({ account, rpcCall }) {
17256
+ const [voice, setVoice] = React31.useState(null);
17257
+ const [phase, setPhase] = React31.useState("loading");
17258
+ const [error, setError] = React31.useState(null);
17259
+ const mounted = React31.useRef(true);
17260
+ const invoke = React31.useCallback(async (endpoint, payload, signal) => {
17261
+ if (typeof rpcCall !== "function") throw new Error("\u98DE\u4E66\u8BED\u97F3\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
17262
+ return unwrapRpcResult3(await rpcCall(endpoint, payload, signal));
17263
+ }, [rpcCall]);
17264
+ const applySnapshot = React31.useCallback((value) => {
17265
+ const bot = normalizeBotsSnapshot(value).bots.find((entry) => entry.botId === account.botId);
17266
+ if (!bot) throw new Error("\u672A\u627E\u5230\u5F53\u524D\u98DE\u4E66\u673A\u5668\u4EBA\uFF0C\u8BF7\u8FD4\u56DE\u5217\u8868\u540E\u91CD\u8BD5\u3002");
17267
+ if (mounted.current) setVoice(bot.voice);
17268
+ }, [account.botId]);
17269
+ const loadSettings = React31.useCallback(async (signal) => {
17270
+ setPhase("loading");
17271
+ setError(null);
17272
+ try {
17273
+ const value = await invoke(FEISHU_ENDPOINTS.status, {}, signal);
17274
+ if (signal?.aborted || !mounted.current) return;
17275
+ applySnapshot(value);
17276
+ setPhase("ready");
17277
+ } catch (cause) {
17278
+ if (signal?.aborted || !mounted.current) return;
17279
+ setError(cause?.message ?? "\u98DE\u4E66\u8BED\u97F3\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
17280
+ setPhase("error");
17281
+ }
17282
+ }, [applySnapshot, invoke]);
17283
+ React31.useEffect(() => {
17284
+ mounted.current = true;
17285
+ const controller = new AbortController();
17286
+ void loadSettings(controller.signal);
17287
+ return () => {
17288
+ mounted.current = false;
17289
+ controller.abort();
17290
+ };
17291
+ }, [loadSettings]);
17292
+ const saveVoice = async (settings) => {
17293
+ const value = await invoke(FEISHU_ENDPOINTS.setVoice, {
17294
+ botId: account.botId,
17295
+ voice: settings === null ? null : { ...voice, ...settings }
17296
+ });
17297
+ if (mounted.current) applySnapshot(value);
17298
+ };
17299
+ if (phase === "loading") {
17300
+ return h2(
17301
+ "div",
17302
+ { className: "dim-deliveryState", role: "status", "aria-busy": "true" },
17303
+ "\u6B63\u5728\u8BFB\u53D6\u8BED\u97F3\u8BBE\u7F6E\u2026"
17304
+ );
17305
+ }
17306
+ if (phase === "error") {
17307
+ return h2(
17308
+ "div",
17309
+ { className: "dim-deliveryState", role: "alert" },
17310
+ h2("p", null, error),
17311
+ h2("button", {
17312
+ type: "button",
17313
+ className: "dim-deliveryButton",
17314
+ onClick: () => void loadSettings()
17315
+ }, "\u91CD\u65B0\u8BFB\u53D6")
17316
+ );
17317
+ }
17318
+ return h2(VoiceEditor, { value: voice, onSave: saveVoice });
17319
+ }
17320
+
17081
17321
  // plugin-src/client/delivery-settings.js
17082
17322
  var DELIVERY_RPC_CHANNEL = "/dsh-im-delivery";
17083
17323
  var DELIVERY_DOCS_URL = Object.freeze({
@@ -17099,7 +17339,8 @@ var BOT_SETTINGS_TABS = Object.freeze([
17099
17339
  ]);
17100
17340
  var FEISHU_BOT_SETTINGS_TABS = Object.freeze([
17101
17341
  ...BOT_SETTINGS_TABS,
17102
- Object.freeze({ id: "group", label: "\u7FA4\u804A" })
17342
+ Object.freeze({ id: "group", label: "\u7FA4\u804A" }),
17343
+ Object.freeze({ id: "voice", label: "\u8BED\u97F3\u4EA4\u4E92" })
17103
17344
  ]);
17104
17345
  function botSettingsTabsForChannel(channel7) {
17105
17346
  return channel7 === "feishu" ? FEISHU_BOT_SETTINGS_TABS : BOT_SETTINGS_TABS;
@@ -17311,13 +17552,13 @@ function TargetForm({
17311
17552
  }) {
17312
17553
  const editing = mode === "edit";
17313
17554
  const initialKind = initialValue?.kind && definition.fields[initialValue.kind] ? initialValue.kind : definition.kinds[0].value;
17314
- const [targetId, setTargetId] = React30.useState(initialValue?.targetId ?? "");
17315
- const [name2, setName] = React30.useState(initialValue?.name ?? "");
17316
- const [kind, setKind] = React30.useState(initialKind);
17317
- const [route, setRoute] = React30.useState(initialValue?.route ?? {});
17318
- const [error, setError] = React30.useState(null);
17319
- const [testing, setTesting] = React30.useState(false);
17320
- const [testState, setTestState] = React30.useState(null);
17555
+ const [targetId, setTargetId] = React32.useState(initialValue?.targetId ?? "");
17556
+ const [name2, setName] = React32.useState(initialValue?.name ?? "");
17557
+ const [kind, setKind] = React32.useState(initialKind);
17558
+ const [route, setRoute] = React32.useState(initialValue?.route ?? {});
17559
+ const [error, setError] = React32.useState(null);
17560
+ const [testing, setTesting] = React32.useState(false);
17561
+ const [testState, setTestState] = React32.useState(null);
17321
17562
  const currentTarget = () => {
17322
17563
  const normalizedRoute = Object.fromEntries(fieldsFor(definition, kind).map((field2) => {
17323
17564
  const raw = String(route[field2.key] ?? "").trim();
@@ -17534,7 +17775,7 @@ function TargetSuggestionPicker({
17534
17775
  suggestions.map((suggestion, index) => {
17535
17776
  const identity = routeIdentity(definition, suggestion);
17536
17777
  const added = configured.has(identity);
17537
- return React30.createElement("option", {
17778
+ return React32.createElement("option", {
17538
17779
  key: suggestion.id ?? suggestion.suggestionId ?? `${identity}:${index}`,
17539
17780
  value: String(index),
17540
17781
  disabled: added
@@ -17551,11 +17792,11 @@ function TargetSuggestionPicker({
17551
17792
  );
17552
17793
  }
17553
17794
  function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, onEdit }) {
17554
- const [action, setAction] = React30.useState(null);
17555
- const [testState, setTestState] = React30.useState(null);
17556
- const [syncFeedback, setSyncFeedback] = React30.useState(null);
17557
- const [copyState, setCopyState] = React30.useState(null);
17558
- const [confirmDelete, setConfirmDelete] = React30.useState(false);
17795
+ const [action, setAction] = React32.useState(null);
17796
+ const [testState, setTestState] = React32.useState(null);
17797
+ const [syncFeedback, setSyncFeedback] = React32.useState(null);
17798
+ const [copyState, setCopyState] = React32.useState(null);
17799
+ const [confirmDelete, setConfirmDelete] = React32.useState(false);
17559
17800
  const sessionSync = target.sessionSync ?? { enabled: false, state: "unavailable" };
17560
17801
  const syncDescription = sessionSync.state === "active" ? "\u81EA\u52A8\u8DDF\u968F\u8BE5\u79C1\u804A\u7684\u5F53\u524D\u4F1A\u8BDD" : sessionSync.state === "waiting" ? "\u7B49\u5F85\u8BE5\u79C1\u804A\u5EFA\u7ACB\u65B0\u4F1A\u8BDD" : sessionSync.state === "unavailable" ? "\u4EC5\u652F\u6301\u5DF2\u7ECF\u804A\u8FC7\u3001\u5DF2\u5EFA\u7ACB\u5F53\u524D\u4F1A\u8BDD\u4E14\u4F7F\u7528\u5F53\u524D Host Harness \u7684\u79C1\u804A\u76EE\u6807" : "\u5173\u95ED\u65F6\u4E0D\u53D1\u9001 DSH \u4F1A\u8BDD\u6D88\u606F";
17561
17802
  const testTarget = async () => {
@@ -17618,7 +17859,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
17618
17859
  h2(
17619
17860
  "div",
17620
17861
  { className: "dim-targetTitle" },
17621
- React30.createElement("strong", null, target.name || target.targetId),
17862
+ React32.createElement("strong", null, target.name || target.targetId),
17622
17863
  h2("span", null, kindLabel(definition, target.kind))
17623
17864
  ),
17624
17865
  h2("code", null, `targetId: ${target.targetId}`)
@@ -17704,26 +17945,26 @@ function DeliveryTargetSettingsPage({
17704
17945
  onBack
17705
17946
  }) {
17706
17947
  const definition = CHANNEL_DEFINITIONS[channel7];
17707
- const [activeTabId, setActiveTabId] = React30.useState(BOT_SETTINGS_TABS[0].id);
17708
- const [phase, setPhase] = React30.useState("loading");
17709
- const [targets, setTargets] = React30.useState([]);
17710
- const [suggestionPhase, setSuggestionPhase] = React30.useState("idle");
17711
- const [suggestions, setSuggestions] = React30.useState([]);
17712
- const [suggestionError, setSuggestionError] = React30.useState(null);
17713
- const [error, setError] = React30.useState(null);
17714
- const [editor, setEditor] = React30.useState(null);
17715
- const [saving, setSaving] = React30.useState(false);
17716
- const [botCopyState, setBotCopyState] = React30.useState(null);
17717
- const [accessPolicy, setAccessPolicy] = React30.useState(account.accessPolicy);
17718
- const mounted = React30.useRef(true);
17719
- React30.useEffect(() => {
17948
+ const [activeTabId, setActiveTabId] = React32.useState(BOT_SETTINGS_TABS[0].id);
17949
+ const [phase, setPhase] = React32.useState("loading");
17950
+ const [targets, setTargets] = React32.useState([]);
17951
+ const [suggestionPhase, setSuggestionPhase] = React32.useState("idle");
17952
+ const [suggestions, setSuggestions] = React32.useState([]);
17953
+ const [suggestionError, setSuggestionError] = React32.useState(null);
17954
+ const [error, setError] = React32.useState(null);
17955
+ const [editor, setEditor] = React32.useState(null);
17956
+ const [saving, setSaving] = React32.useState(false);
17957
+ const [botCopyState, setBotCopyState] = React32.useState(null);
17958
+ const [accessPolicy, setAccessPolicy] = React32.useState(account.accessPolicy);
17959
+ const mounted = React32.useRef(true);
17960
+ React32.useEffect(() => {
17720
17961
  setAccessPolicy(account.accessPolicy);
17721
17962
  }, [account.botId, account.accessPolicy]);
17722
- const invoke = React30.useCallback(async (endpoint, payload = {}, signal) => {
17963
+ const invoke = React32.useCallback(async (endpoint, payload = {}, signal) => {
17723
17964
  if (typeof rpcCall !== "function") throw new Error("\u6295\u9012\u76EE\u6807\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
17724
17965
  return unwrapRpcResult15(await rpcCall(endpoint, payload, signal));
17725
17966
  }, [rpcCall]);
17726
- const loadTargets = React30.useCallback(async ({ signal, silent = false } = {}) => {
17967
+ const loadTargets = React32.useCallback(async ({ signal, silent = false } = {}) => {
17727
17968
  if (!silent) setPhase("loading");
17728
17969
  setError(null);
17729
17970
  try {
@@ -17737,7 +17978,7 @@ function DeliveryTargetSettingsPage({
17737
17978
  setPhase("error");
17738
17979
  }
17739
17980
  }, [account.botId, invoke]);
17740
- const loadSuggestions = React30.useCallback(async () => {
17981
+ const loadSuggestions = React32.useCallback(async () => {
17741
17982
  setSuggestionPhase("loading");
17742
17983
  setSuggestionError(null);
17743
17984
  try {
@@ -17751,7 +17992,7 @@ function DeliveryTargetSettingsPage({
17751
17992
  setSuggestionPhase("error");
17752
17993
  }
17753
17994
  }, [account.botId, definition, invoke]);
17754
- React30.useEffect(() => {
17995
+ React32.useEffect(() => {
17755
17996
  mounted.current = true;
17756
17997
  const controller = new AbortController();
17757
17998
  void loadTargets({ signal: controller.signal });
@@ -17872,8 +18113,12 @@ function DeliveryTargetSettingsPage({
17872
18113
  }) : activeTab.id === "group" && channel7 === "feishu" ? h2(FeishuGroupSettingsPage, {
17873
18114
  account,
17874
18115
  rpcCall: accessRpcCall
18116
+ }) : activeTab.id === "voice" && channel7 === "feishu" ? h2(FeishuVoiceSettingsPage, {
18117
+ key: account.botId,
18118
+ account,
18119
+ rpcCall: accessRpcCall
17875
18120
  }) : h2(
17876
- React30.Fragment,
18121
+ React32.Fragment,
17877
18122
  null,
17878
18123
  h2(
17879
18124
  "section",
@@ -17984,7 +18229,7 @@ function DeliveryTargetSettingsPage({
17984
18229
  }
17985
18230
 
17986
18231
  // plugin-src/client/global-settings.js
17987
- var React31 = __toESM(require("react"), 1);
18232
+ var React33 = __toESM(require("react"), 1);
17988
18233
 
17989
18234
  // src/channels/shared/inbound-ttl.mjs
17990
18235
  var DEFAULT_INBOUND_TTL_HOURS = 168;
@@ -18069,14 +18314,14 @@ function GlobalButton({ children, kind = "secondary", className = "", ...props }
18069
18314
  }, children);
18070
18315
  }
18071
18316
  function ImageInputSettings({ rpcCall }) {
18072
- const [values, setValues] = React31.useState(DEFAULT_IMAGE_INPUT_SETTINGS);
18073
- const [phase, setPhase] = React31.useState("loading");
18074
- const [error, setError] = React31.useState(null);
18075
- const [saved, setSaved] = React31.useState(false);
18076
- const mounted = React31.useRef(false);
18077
- const saving = React31.useRef(false);
18078
- const id6 = React31.useId();
18079
- const load = React31.useCallback(async (signal) => {
18317
+ const [values, setValues] = React33.useState(DEFAULT_IMAGE_INPUT_SETTINGS);
18318
+ const [phase, setPhase] = React33.useState("loading");
18319
+ const [error, setError] = React33.useState(null);
18320
+ const [saved, setSaved] = React33.useState(false);
18321
+ const mounted = React33.useRef(false);
18322
+ const saving = React33.useRef(false);
18323
+ const id6 = React33.useId();
18324
+ const load = React33.useCallback(async (signal) => {
18080
18325
  setPhase("loading");
18081
18326
  setError(null);
18082
18327
  try {
@@ -18092,7 +18337,7 @@ function ImageInputSettings({ rpcCall }) {
18092
18337
  setPhase("error");
18093
18338
  }
18094
18339
  }, [rpcCall]);
18095
- React31.useEffect(() => {
18340
+ React33.useEffect(() => {
18096
18341
  mounted.current = true;
18097
18342
  const controller = new AbortController();
18098
18343
  void load(controller.signal);
@@ -18199,29 +18444,29 @@ function ImageInputSettings({ rpcCall }) {
18199
18444
  );
18200
18445
  }
18201
18446
  function GlobalSettingsPanel({ rpcCall }) {
18202
- const [phase, setPhase] = React31.useState("loading");
18203
- const [loadError, setLoadError] = React31.useState(null);
18204
- const [ttlInput, setTtlInput] = React31.useState("");
18205
- const [savedTtl, setSavedTtl] = React31.useState(null);
18206
- const [ttlError, setTtlError] = React31.useState(false);
18207
- const [saveError, setSaveError] = React31.useState(null);
18208
- const [saveSucceeded, setSaveSucceeded] = React31.useState(false);
18209
- const [isSaving, setIsSaving] = React31.useState(false);
18210
- const [sweepConfirming, setSweepConfirming] = React31.useState(false);
18211
- const [sweeping, setSweeping] = React31.useState(false);
18212
- const ttlErrorId = React31.useId();
18213
- const ttlHintsId = React31.useId();
18214
- const sweepTriggerId = React31.useId();
18215
- const sweepConfirmId = React31.useId();
18216
- const sweepConfirmTextId = React31.useId();
18217
- const sweepConfirmButtonId = React31.useId();
18218
- const mounted = React31.useRef(true);
18219
- const saving = React31.useRef(false);
18220
- const invoke = React31.useCallback(async (endpoint, payload = {}, signal) => {
18447
+ const [phase, setPhase] = React33.useState("loading");
18448
+ const [loadError, setLoadError] = React33.useState(null);
18449
+ const [ttlInput, setTtlInput] = React33.useState("");
18450
+ const [savedTtl, setSavedTtl] = React33.useState(null);
18451
+ const [ttlError, setTtlError] = React33.useState(false);
18452
+ const [saveError, setSaveError] = React33.useState(null);
18453
+ const [saveSucceeded, setSaveSucceeded] = React33.useState(false);
18454
+ const [isSaving, setIsSaving] = React33.useState(false);
18455
+ const [sweepConfirming, setSweepConfirming] = React33.useState(false);
18456
+ const [sweeping, setSweeping] = React33.useState(false);
18457
+ const ttlErrorId = React33.useId();
18458
+ const ttlHintsId = React33.useId();
18459
+ const sweepTriggerId = React33.useId();
18460
+ const sweepConfirmId = React33.useId();
18461
+ const sweepConfirmTextId = React33.useId();
18462
+ const sweepConfirmButtonId = React33.useId();
18463
+ const mounted = React33.useRef(true);
18464
+ const saving = React33.useRef(false);
18465
+ const invoke = React33.useCallback(async (endpoint, payload = {}, signal) => {
18221
18466
  if (typeof rpcCall !== "function") throw new Error("\u901A\u7528\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
18222
18467
  return unwrapRpcResult16(await rpcCall(endpoint, payload, signal));
18223
18468
  }, [rpcCall]);
18224
- const loadSettings = React31.useCallback(async ({ signal } = {}) => {
18469
+ const loadSettings = React33.useCallback(async ({ signal } = {}) => {
18225
18470
  setPhase("loading");
18226
18471
  setLoadError(null);
18227
18472
  try {
@@ -18245,7 +18490,7 @@ function GlobalSettingsPanel({ rpcCall }) {
18245
18490
  setPhase("error");
18246
18491
  }
18247
18492
  }, [invoke]);
18248
- React31.useEffect(() => {
18493
+ React33.useEffect(() => {
18249
18494
  mounted.current = true;
18250
18495
  const controller = new AbortController();
18251
18496
  void loadSettings({ signal: controller.signal });
@@ -18254,7 +18499,7 @@ function GlobalSettingsPanel({ rpcCall }) {
18254
18499
  controller.abort();
18255
18500
  };
18256
18501
  }, [loadSettings]);
18257
- React31.useEffect(() => {
18502
+ React33.useEffect(() => {
18258
18503
  if (!sweepConfirming) return;
18259
18504
  globalThis.document?.getElementById(sweepConfirmButtonId)?.focus();
18260
18505
  }, [sweepConfirmButtonId, sweepConfirming]);
@@ -19041,6 +19286,17 @@ var CSS15 = String.raw`
19041
19286
  .dim-feishuGroupSelect:focus-visible { outline: none; border-color: var(--dsw-alias-state-business-primary, #3370ff); box-shadow: 0 0 0 2px color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 15%, transparent); }
19042
19287
  .dim-feishuGroupSelect:disabled { cursor: not-allowed; opacity: .55; }
19043
19288
  .dim-feishuGroupHelp { margin: -2px 0 0; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 12px; line-height: 19px; }
19289
+ .dim-feishuVoiceForm { min-width: 0; display: grid; gap: 10px; }
19290
+ .dim-feishuVoiceField { min-width: 0; display: grid; gap: 5px; }
19291
+ .dim-feishuVoiceLabel { color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: 18px; }
19292
+ .dim-feishuVoiceInput { min-width: 0; width: 100%; height: 36px; 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; line-height: 36px; transition: border-color .15s ease, box-shadow .15s ease; }
19293
+ .dim-feishuVoiceInput:hover:not(:disabled) { border-color: color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 42%, var(--dsw-alias-border-l2, #dfe1e5)); }
19294
+ .dim-feishuVoiceInput:focus-visible { outline: none; border-color: var(--dsw-alias-state-business-primary, #3370ff); box-shadow: 0 0 0 2px color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 15%, transparent); }
19295
+ .dim-feishuVoiceInput:disabled { cursor: not-allowed; opacity: .55; }
19296
+ .dim-feishuVoiceActions { display: flex; justify-content: flex-start; }
19297
+ .dim-feishuVoiceSave { height: 34px; padding: 0 15px; border: 1px solid var(--dsw-alias-state-business-primary, #3370ff); border-radius: 8px; color: var(--dsw-alias-state-business-primary, #3370ff); background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 13px; line-height: 32px; cursor: pointer; transition: border-color .15s ease, color .15s ease, background .15s ease; }
19298
+ .dim-feishuVoiceSave:hover:not(:disabled) { color: #0f5fce; border-color: #0f5fce; background: color-mix(in srgb, #3370ff 6%, var(--dsw-alias-bg-layer-1, #fff)); }
19299
+ .dim-feishuVoiceSave:disabled { cursor: not-allowed; opacity: .55; }
19044
19300
  .dim-feishuGroupPermissionAction { display: flex; justify-content: flex-start; }
19045
19301
  .dim-feishuGroupPermissionAction .dim-deliveryButton { color: var(--dsw-alias-state-business-primary, #3370ff); border-color: color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 30%, var(--dsw-alias-border-l2, #dfe1e5)); }
19046
19302
  .dim-feishuGroupError, .dim-feishuGroupRefreshError { margin: 0; padding: 9px 11px; border-radius: 8px; font-size: 12px; line-height: 18px; }
@@ -19555,7 +19811,7 @@ function installSessionChannelLogos(document2 = globalThis.document) {
19555
19811
  }
19556
19812
 
19557
19813
  // plugin-src/client/update-panel.js
19558
- var React32 = __toESM(require("react"), 1);
19814
+ var React34 = __toESM(require("react"), 1);
19559
19815
  var import_react_dom4 = require("react-dom");
19560
19816
  var import_valid = __toESM(require_valid(), 1);
19561
19817
  var import_rcompare = __toESM(require_rcompare(), 1);
@@ -19648,11 +19904,11 @@ function manualUpdateCommand(snapshot) {
19648
19904
  return `dsh plugin --profile ${profileArgument} add -w @xmanrui/dsh-im@${version}`;
19649
19905
  }
19650
19906
  function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
19651
- const [copyState, setCopyState] = React32.useState("idle");
19652
- const commandRef = React32.useRef(null);
19653
- const mounted = React32.useRef(false);
19654
- const copying = React32.useRef(false);
19655
- React32.useEffect(() => {
19907
+ const [copyState, setCopyState] = React34.useState("idle");
19908
+ const commandRef = React34.useRef(null);
19909
+ const mounted = React34.useRef(false);
19910
+ const copying = React34.useRef(false);
19911
+ React34.useEffect(() => {
19656
19912
  mounted.current = true;
19657
19913
  return () => {
19658
19914
  mounted.current = false;
@@ -19684,7 +19940,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
19684
19940
  { className: "dim-updateManual", "aria-label": "\u624B\u5DE5\u66F4\u65B0" },
19685
19941
  h2("h4", { className: "dim-updateManualHeading" }, "\u624B\u5DE5\u66F4\u65B0"),
19686
19942
  command ? h2(
19687
- React32.Fragment,
19943
+ React34.Fragment,
19688
19944
  null,
19689
19945
  h2("p", { className: "dim-updateManualHint" }, "\u81EA\u52A8\u66F4\u65B0\u5931\u8D25\u53EF\u4EE5\u4F7F\u7528\u547D\u4EE4\u66F4\u65B0\uFF1A"),
19690
19946
  h2(
@@ -19720,7 +19976,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
19720
19976
  "aria-hidden": "true",
19721
19977
  focusable: "false"
19722
19978
  }, copyState === "copied" ? h2("path", { d: "m4 10 4 4 8-8" }) : h2(
19723
- React32.Fragment,
19979
+ React34.Fragment,
19724
19980
  null,
19725
19981
  h2("rect", { x: 7, y: 7, width: 10, height: 11, rx: 1.5 }),
19726
19982
  h2("path", { d: "M5 13H3.5A1.5 1.5 0 0 1 2 11.5v-8A1.5 1.5 0 0 1 3.5 2h8A1.5 1.5 0 0 1 13 3.5V5" })
@@ -19745,10 +20001,10 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
19745
20001
  );
19746
20002
  }
19747
20003
  function UpdateDialog({ children, onClose }) {
19748
- const dialogRef = React32.useRef(null);
19749
- const titleId = React32.useId();
19750
- const descriptionId = React32.useId();
19751
- React32.useEffect(() => {
20004
+ const dialogRef = React34.useRef(null);
20005
+ const titleId = React34.useId();
20006
+ const descriptionId = React34.useId();
20007
+ React34.useEffect(() => {
19752
20008
  const previous = globalThis.document?.activeElement;
19753
20009
  dialogRef.current?.focus?.();
19754
20010
  return () => {
@@ -19806,20 +20062,20 @@ function UpdateDialog({ children, onClose }) {
19806
20062
  return typeof document !== "undefined" && document.body ? (0, import_react_dom4.createPortal)(content, document.body) : content;
19807
20063
  }
19808
20064
  function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19809
- const tooltipId = React32.useId();
19810
- const [snapshot, setSnapshot] = React32.useState(null);
19811
- const [action, setAction] = React32.useState("status");
19812
- const [error, setError] = React32.useState(null);
19813
- const [open, setOpen] = React32.useState(false);
19814
- const [uncertainInstall, setUncertainInstall] = React32.useState(false);
19815
- const mounted = React32.useRef(false);
19816
- const busy = React32.useRef(false);
19817
- const readController = React32.useRef(null);
19818
- const pollReadController = React32.useRef(null);
19819
- const installRequest = React32.useRef(null);
19820
- const onStatusRef = React32.useRef(onStatus);
20065
+ const tooltipId = React34.useId();
20066
+ const [snapshot, setSnapshot] = React34.useState(null);
20067
+ const [action, setAction] = React34.useState("status");
20068
+ const [error, setError] = React34.useState(null);
20069
+ const [open, setOpen] = React34.useState(false);
20070
+ const [uncertainInstall, setUncertainInstall] = React34.useState(false);
20071
+ const mounted = React34.useRef(false);
20072
+ const busy = React34.useRef(false);
20073
+ const readController = React34.useRef(null);
20074
+ const pollReadController = React34.useRef(null);
20075
+ const installRequest = React34.useRef(null);
20076
+ const onStatusRef = React34.useRef(onStatus);
19821
20077
  onStatusRef.current = onStatus;
19822
- const accept = React32.useCallback((next) => {
20078
+ const accept = React34.useCallback((next) => {
19823
20079
  setSnapshot(next);
19824
20080
  onStatusRef.current?.(next);
19825
20081
  }, []);
@@ -19828,7 +20084,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19828
20084
  setUncertainInstall(false);
19829
20085
  accept(next);
19830
20086
  };
19831
- const invoke = React32.useCallback(async (endpoint, payload = {}, signal) => {
20087
+ const invoke = React34.useCallback(async (endpoint, payload = {}, signal) => {
19832
20088
  if (typeof rpcCall !== "function") {
19833
20089
  const unavailable = new Error("\u5F53\u524D Host \u4E0D\u652F\u6301\u66F4\u65B0\u63A5\u53E3\uFF0C\u8BF7\u5148\u624B\u52A8\u66F4\u65B0\u63D2\u4EF6\u5E76\u91CD\u542F\u3002");
19834
20090
  unavailable.code = "update-unavailable";
@@ -19836,7 +20092,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19836
20092
  }
19837
20093
  return unwrapSnapshot(await rpcCall(endpoint, payload, signal));
19838
20094
  }, [rpcCall]);
19839
- React32.useEffect(() => {
20095
+ React34.useEffect(() => {
19840
20096
  mounted.current = true;
19841
20097
  busy.current = true;
19842
20098
  const controller = new AbortController();
@@ -19859,7 +20115,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19859
20115
  const activeJob = ACTIVE_STATES4.has(snapshot?.job?.state);
19860
20116
  const restartRequired = snapshot?.job?.state === "restart-required" || snapshot?.blockedReason === "pending-restart";
19861
20117
  const shouldPoll = activeJob || uncertainInstall;
19862
- React32.useEffect(() => {
20118
+ React34.useEffect(() => {
19863
20119
  if (!shouldPoll) return void 0;
19864
20120
  let controller;
19865
20121
  const scheduler = createPollScheduler({
@@ -19960,7 +20216,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
19960
20216
  const buttonLabel = action === "checking" ? "\u68C0\u67E5\u4E2D\u2026" : action === "starting" || activeJob ? "\u6B63\u5728\u66F4\u65B0\u2026" : restartRequired ? "\u5F85\u624B\u52A8\u91CD\u542F" : snapshot?.canInstall ? "\u66F4\u65B0\u81F3" : "\u68C0\u67E5\u66F4\u65B0";
19961
20217
  const buttonDescription = localizeText(buttonLabel) + (buttonLabel === "\u66F4\u65B0\u81F3" ? ` v${snapshot.latestVersion}` : "");
19962
20218
  return h2(
19963
- React32.Fragment,
20219
+ React34.Fragment,
19964
20220
  null,
19965
20221
  h2(
19966
20222
  "span",
@@ -20010,25 +20266,25 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20010
20266
  h2("dt", null, "\u8FD0\u884C\u7248\u672C"),
20011
20267
  h2("dd", null, `v${snapshot?.runningVersion ?? clientVersion}`),
20012
20268
  snapshot?.installedVersion && snapshot.installedVersion !== snapshot.runningVersion ? h2(
20013
- React32.Fragment,
20269
+ React34.Fragment,
20014
20270
  null,
20015
20271
  h2("dt", null, "\u5DF2\u5B89\u88C5\u7248\u672C"),
20016
20272
  h2("dd", null, `v${snapshot.installedVersion}`)
20017
20273
  ) : null,
20018
20274
  targetVersion ? h2(
20019
- React32.Fragment,
20275
+ React34.Fragment,
20020
20276
  null,
20021
20277
  h2("dt", null, "\u76EE\u6807\u7248\u672C"),
20022
20278
  h2("dd", null, `v${targetVersion}`)
20023
20279
  ) : null,
20024
20280
  latestVersion ? h2(
20025
- React32.Fragment,
20281
+ React34.Fragment,
20026
20282
  null,
20027
20283
  h2("dt", null, "\u6700\u65B0\u7248\u672C"),
20028
20284
  h2("dd", null, `v${latestVersion}`)
20029
20285
  ) : null,
20030
20286
  historicalTargetVersion ? h2(
20031
- React32.Fragment,
20287
+ React34.Fragment,
20032
20288
  null,
20033
20289
  h2("dt", null, "\u4E0A\u6B21\u66F4\u65B0\u76EE\u6807"),
20034
20290
  h2("dd", null, `v${historicalTargetVersion}`)
@@ -20110,8 +20366,8 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20110
20366
  }
20111
20367
 
20112
20368
  // plugin-src/client/panel-error-boundary.js
20113
- var React33 = __toESM(require("react"), 1);
20114
- var IMPanelErrorBoundary = class extends React33.Component {
20369
+ var React35 = __toESM(require("react"), 1);
20370
+ var IMPanelErrorBoundary = class extends React35.Component {
20115
20371
  state = { failed: false };
20116
20372
  static getDerivedStateFromError() {
20117
20373
  return { failed: true };
@@ -20304,28 +20560,28 @@ function IMSettingsTab({
20304
20560
  browserLocation = globalThis.location,
20305
20561
  navigateToRecoveryUrl = replacePageLocation
20306
20562
  }) {
20307
- const [selected, setSelected] = React34.useState(() => preferredSectionId === GLOBAL_SETTINGS_TAB_ID || CHANNELS.some((channel7) => channel7.id === preferredSectionId) ? preferredSectionId : "weixin");
20308
- const [loopbackRecovery, setLoopbackRecovery] = React34.useState(null);
20309
- const [runningVersion, setRunningVersion] = React34.useState(IM_PLUGIN_VERSION);
20310
- const [deliverySettings, setDeliverySettings] = React34.useState(null);
20563
+ const [selected, setSelected] = React36.useState(() => preferredSectionId === GLOBAL_SETTINGS_TAB_ID || CHANNELS.some((channel7) => channel7.id === preferredSectionId) ? preferredSectionId : "weixin");
20564
+ const [loopbackRecovery, setLoopbackRecovery] = React36.useState(null);
20565
+ const [runningVersion, setRunningVersion] = React36.useState(IM_PLUGIN_VERSION);
20566
+ const [deliverySettings, setDeliverySettings] = React36.useState(null);
20311
20567
  const emailEnabled = useEmailChannelEnabled(emailRpcCall);
20312
- const visibleChannels = React34.useMemo(
20568
+ const visibleChannels = React36.useMemo(
20313
20569
  () => CHANNELS.filter((channel7) => channel7.id !== "email" || emailEnabled),
20314
20570
  [emailEnabled]
20315
20571
  );
20316
- const githubTooltipId = React34.useId();
20317
- const generalSettingsTooltipId = React34.useId();
20572
+ const githubTooltipId = React36.useId();
20573
+ const generalSettingsTooltipId = React36.useId();
20318
20574
  const globalSettingsSelected = selected === GLOBAL_SETTINGS_TAB_ID;
20319
20575
  const active = visibleChannels.find((channel7) => channel7.id === selected) ?? visibleChannels[0];
20320
20576
  const activeTabId = globalSettingsSelected ? "dim-general-settings-trigger" : `dim-tab-${active.id}`;
20321
20577
  const activePanelId = globalSettingsSelected ? `dim-panel-${GLOBAL_SETTINGS_TAB_ID}` : `dim-panel-${active.id}`;
20322
- const reportLoopbackRecovery = React34.useCallback((recovery) => {
20578
+ const reportLoopbackRecovery = React36.useCallback((recovery) => {
20323
20579
  setLoopbackRecovery((current) => current?.url === recovery.url ? current : recovery);
20324
20580
  }, []);
20325
- const reportUpdateStatus = React34.useCallback((snapshot) => {
20581
+ const reportUpdateStatus = React36.useCallback((snapshot) => {
20326
20582
  setRunningVersion(snapshot.runningVersion);
20327
20583
  }, []);
20328
- const rpcCalls = React34.useMemo(() => createLoopbackAwareRpcCalls({
20584
+ const rpcCalls = React36.useMemo(() => createLoopbackAwareRpcCalls({
20329
20585
  dingtalkRpcCall,
20330
20586
  discordRpcCall,
20331
20587
  feishuRpcCall,
@@ -20367,7 +20623,7 @@ function IMSettingsTab({
20367
20623
  weixinRpcCall,
20368
20624
  whatsappRpcCall
20369
20625
  ]);
20370
- const botSettingsContext = React34.useMemo(() => Object.freeze({
20626
+ const botSettingsContext = React36.useMemo(() => Object.freeze({
20371
20627
  openBotSettings: setDeliverySettings
20372
20628
  }), []);
20373
20629
  return h2(
@@ -20591,7 +20847,7 @@ function apply(ctx) {
20591
20847
  };
20592
20848
  const localeSnapshot = () => ctx.locale.getLocale?.()?.active ?? "";
20593
20849
  function IMPanel({ preferredSectionId }) {
20594
- React34.useSyncExternalStore(subscribeLocale, localeSnapshot, localeSnapshot);
20850
+ React36.useSyncExternalStore(subscribeLocale, localeSnapshot, localeSnapshot);
20595
20851
  return h2(
20596
20852
  IMPanelErrorBoundary,
20597
20853
  null,