@xmanrui/dsh-im 4.29.0 → 4.30.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.
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 React36 = __toESM(require("react"), 1);
593
+ var React37 = __toESM(require("react"), 1);
594
594
 
595
595
  // package.json
596
596
  var package_default = {
597
597
  name: "@xmanrui/dsh-im",
598
- version: "4.29.0",
598
+ version: "4.30.0",
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",
@@ -1471,12 +1472,42 @@ var EN = Object.freeze({
1471
1472
  "\u9700\u5728\u98DE\u4E66\u4E3A\u8BE5\u673A\u5668\u4EBA\u5F00\u901A\u201C\u83B7\u53D6\u7FA4\u7EC4\u4E2D\u6240\u6709\u6D88\u606F\u201D\u6743\u9650\uFF08im:message.group_msg\uFF09\uFF1B\u5F00\u901A\u540E\uFF0C\u673A\u5668\u4EBA\u4F1A\u5904\u7406\u7FA4\u804A\u4E2D\u7684\u6240\u6709\u53EF\u89C1\u6D88\u606F\u3002": "Grant this bot the \u201CRead all messages in associated group chat\u201D Feishu scope (im:message.group_msg); once granted, it will process every visible group message.",
1472
1473
  "\u7FA4\u804A\u54CD\u5E94\u65B9\u5F0F\u4FEE\u6539\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002": "Could not update the group response mode. Try again.",
1473
1474
  "\u7FA4\u6D88\u606F\u6743\u9650\u6388\u6743\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002": "Could not authorize group-message permission. Try again.",
1474
- "\u7FA4\u804A\u4EE5\u8BDD\u9898\u65B9\u5F0F\u56DE\u590D": "Reply to group chats as Feishu topics",
1475
- "\u7FA4\u804A\u4EE5\u8BDD\u9898\u65B9\u5F0F\u56DE\u590D\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002": "Could not save the topic reply setting. Try again.",
1476
- "\u5173\u95ED\uFF08\u7FA4\u5185\u76F4\u63A5\u56DE\u590D\uFF09": "Off (reply in the group feed)",
1475
+ "\u88AB @ \u65F6\u4EE5\u8BDD\u9898\u65B9\u5F0F\u56DE\u590D": "Reply as a Feishu topic when mentioned",
1476
+ "\u4EE5\u8BDD\u9898\u65B9\u5F0F\u56DE\u590D\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002": "Could not save the topic reply setting. Try again.",
1477
+ "\u5173\u95ED\uFF08\u5728\u4F1A\u8BDD\u4E3B\u7A97\u53E3\u56DE\u590D\uFF09": "Off (reply in the chat feed)",
1477
1478
  "\u5F00\u542F\uFF08\u81EA\u52A8\u5F00\u542F\u72EC\u7ACB\u98DE\u4E66\u8BDD\u9898\uFF09": "On (auto-open a dedicated Feishu topic)",
1478
- "\u5F00\u542F\u540E\uFF0C\u7FA4\u804A\u4E2D\u5411\u673A\u5668\u4EBA\u63D0\u95EE\u4F1A\u81EA\u52A8\u5F00\u542F\u72EC\u7ACB\u98DE\u4E66\u8BDD\u9898\uFF0C\u56DE\u590D\u843D\u5728\u8BDD\u9898\u5185\uFF1B\u6BCF\u4E2A\u8BDD\u9898\u662F dsh \u4F1A\u8BDD\u5217\u8868\u91CC\u4E00\u6761\u72EC\u7ACB\u4F1A\u8BDD\uFF0C\u4E0A\u4E0B\u6587\u4E92\u4E0D\u4E32\u3002\u79C1\u804A\u4E0D\u53D7\u5F71\u54CD\u3002": "When enabled, questions to the bot in a group auto-open a dedicated Feishu topic and replies stay inside it. Each topic is an independent conversation in dsh with its own context. Private chats are unaffected.",
1479
+ "\u5F00\u542F\u540E\uFF0C\u5728\u7FA4\u804A\u6216\u79C1\u804A\u91CC @\u673A\u5668\u4EBA \u63D0\u95EE\uFF0C\u673A\u5668\u4EBA\u4F1A\u5728\u90A3\u6761\u6D88\u606F\u4E0B\u65B0\u5EFA\u4E00\u4E2A\u98DE\u4E66\u8BDD\u9898\u5E76\u5728\u8BDD\u9898\u5185\u56DE\u7B54\uFF1B\u8BE5\u8BDD\u9898\u662F\u4E00\u6761\u72EC\u7ACB\u4F1A\u8BDD\uFF0C\u8BDD\u9898\u91CC\u7684\u540E\u7EED\u6D88\u606F\u90FD\u5C5E\u4E8E\u540C\u4E00\u4E2A\u4F1A\u8BDD\u3002\u53EA\u53D1\u4E00\u4E2A @\u673A\u5668\u4EBA\uFF08\u6253\u5F00\u83DC\u5355\uFF09\u4E0D\u4F1A\u65B0\u5EFA\u8BDD\u9898\uFF0C\u6CA1\u6709 @\u673A\u5668\u4EBA \u7684\u6D88\u606F\u4E5F\u7559\u5728\u539F\u6765\u7684\u4F1A\u8BDD\u91CC\u3002": `When enabled, mentioning the bot in a group or a private chat opens a dedicated Feishu topic under that message and the answer stays inside it. That topic is an independent conversation in dsh, and later messages in the topic belong to the same conversation. A bare "@bot" (which opens the menu) opens no topic, and messages without a mention stay in the chat's own conversation.`,
1479
1480
  "\u5206\u6B65\u76F4\u63A8": "Step push",
1481
+ "\u6307\u4EE4\u9762\u677F": "Command panel",
1482
+ "\u4E2A\u5931\u8D25\u3002": "failed.",
1483
+ "\u4E2A\u673A\u5668\u4EBA\uFF0C": "bots,",
1484
+ "\u4E2A\u673A\u5668\u4EBA\u3002": "bots.",
1485
+ "\u5DF2\u540C\u6B65\u5230": "Copied to",
1486
+ "\u8FD9\u4E2A\u6E20\u9053\u6CA1\u6709\u5176\u4ED6\u98DE\u4E66\u673A\u5668\u4EBA\uFF0C\u4E0D\u7528\u540C\u6B65\u3002": "This channel has no other Feishu bots to copy to.",
1487
+ "\u6B63\u5728\u540C\u6B65\u2026": "Copying\u2026",
1488
+ "\u786E\u8BA4\u540C\u6B65": "Copy to all",
1489
+ "\u4E2A\u98DE\u4E66\u673A\u5668\u4EBA\uFF0C\u5B83\u4EEC\u5404\u81EA\u7684\u9762\u677F\u8BBE\u7F6E\u4F1A\u88AB\u8986\u76D6\u3002": "other Feishu bots, overwriting their own panel settings.",
1490
+ "\u5C06\u628A\u8FD9\u5957\u9762\u677F\u8BBE\u7F6E\u5199\u5165\u53E6\u5916": "This copies the panel to",
1491
+ "\u4FDD\u5B58\u5E76\u540C\u6B65\u5230\u5176\u4ED6\u673A\u5668\u4EBA": "Save and copy to the other bots",
1492
+ "\u6307\u4EE4\u9762\u677F\u8BBE\u7F6E": "Command panel settings",
1493
+ "\u6307\u4EE4\u9762\u677F\u6A21\u5F0F": "Command panel mode",
1494
+ "\u9762\u677F\u53EA\u51B3\u5B9A\u804A\u5929\u8F93\u5165\u6846\u91CC\u6253\u300C/\u300D\u65F6\u5217\u51FA\u7684\u6307\u4EE4\u548C\u987A\u5E8F\uFF1B\u88AB\u79FB\u9664\u7684\u6307\u4EE4\u4ECD\u53EF\u624B\u52A8\u8F93\u5165\uFF0C\u529F\u80FD\u4E0D\u53D7\u5F71\u54CD\u3002\u540C\u6B65\u7531\u673A\u5668\u4EBA\u540E\u53F0\u5B8C\u6210\uFF0C\u6307\u4EE4\u8F83\u591A\u65F6\u9700\u8981\u4E00\u70B9\u65F6\u95F4\u3002": 'The panel only decides which commands the "/" list in the chat input offers, and in which order. A removed command can still be typed by hand and keeps working. The bot syncs the panel in the background; many commands take a moment.',
1495
+ "\u8DDF\u968F\u9ED8\u8BA4\uFF08\u968F\u63D2\u4EF6\u7248\u672C\u66F4\u65B0\uFF09": "Follow the default (updated with the plugin)",
1496
+ "\u81EA\u5B9A\u4E49\uFF08\u81EA\u5DF1\u6311\u6307\u4EE4\u548C\u987A\u5E8F\uFF09": "Custom (choose the commands and their order)",
1497
+ "\u5F53\u524D\u6CA1\u6709\u9009\u62E9\u4EFB\u4F55\u6307\u4EE4\uFF0C\u4FDD\u5B58\u540E\u300C/\u300D\u9762\u677F\u4F1A\u53D8\u6210\u7A7A\u7684\u3002": 'No commands are selected; saving leaves the "/" panel empty.',
1498
+ "\u6DFB\u52A0\u6307\u4EE4": "Add command",
1499
+ "\u9009\u62E9\u8981\u52A0\u5165\u7684\u6307\u4EE4": "Choose a command to add",
1500
+ "\u6307\u4EE4\u90FD\u5DF2\u52A0\u5165": "Every command is already listed",
1501
+ "\u52A0\u5165": "Add",
1502
+ "\u6062\u590D\u5168\u90E8": "Restore all",
1503
+ "\u5168\u90E8\u79FB\u9664": "Remove all",
1504
+ "\u79FB\u9664": "Remove",
1505
+ "\u4E0A\u79FB": "Move up",
1506
+ "\u4E0B\u79FB": "Move down",
1507
+ "\u4FDD\u5B58": "Save",
1508
+ "\u5DF2\u4FDD\u5B58\uFF0C\u9762\u677F\u7A0D\u540E\u540C\u6B65": "Saved; the panel syncs shortly",
1509
+ "\u8BF7\u9009\u62E9\u9762\u677F\u8981\u663E\u793A\u7684\u6307\u4EE4\u4E0E\u987A\u5E8F\u3002": "Choose which commands the panel shows, and in what order.",
1510
+ "\u98DE\u4E66\u6307\u4EE4\u9762\u677F\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002": "The Feishu command panel settings are unavailable right now.",
1480
1511
  "\u67E5\u770B\u5206\u6B65\u76F4\u63A8\u8BF4\u660E": "View step push help",
1481
1512
  "\u5F00\u542F\u540E\u9010\u6B65\u63A8\u9001\u5DE5\u5177\u8C03\u7528\u4E0E\u8FC7\u7A0B\u8BF4\u660E": "Push tool calls and process notes step by step",
1482
1513
  "\u4EFB\u52A1\u8FC7\u7A0B\u5C55\u793A": "Task progress display",
@@ -1560,7 +1591,6 @@ var EN = Object.freeze({
1560
1591
  "\u5DE5\u4F5C\u533A\u7EDD\u5BF9\u8DEF\u5F84": "Absolute workspace path",
1561
1592
  "/\u7EDD\u5BF9\u8DEF\u5F84/\u5230/\u5DE5\u4F5C\u533A": "/absolute/path/to/workspace",
1562
1593
  "\u4FEE\u6539": "Change",
1563
- "\u4FDD\u5B58": "Save",
1564
1594
  "\u4E0A\u4E0B\u6587\u589E\u5F3A": "Context enhancement",
1565
1595
  "\u672A\u5F00\u542F": "Not enabled",
1566
1596
  "\u4EC5\u7FA4\u804A": "Groups only",
@@ -7241,6 +7271,74 @@ function normalizeFeishuVoiceConfig(value) {
7241
7271
  });
7242
7272
  }
7243
7273
 
7274
+ // src/channels/feishu/slash-command-panel.mjs
7275
+ var SLASH_COMMAND_MANIFEST = Object.freeze([
7276
+ { command: "menu", icon: "skill_outlined", default: "\u6253\u5F00\u529F\u80FD\u83DC\u5355", en_us: "Open the feature menu" },
7277
+ { command: "new", icon: "ai-deepthink_outlined", default: "\u5F00\u542F\u5168\u65B0\u4F1A\u8BDD", en_us: "Start a fresh session" },
7278
+ { command: "help", icon: "promptword_outlined", default: "\u67E5\u770B\u5E2E\u52A9", en_us: "Show help" },
7279
+ { command: "status", icon: "ai-functions_outlined", default: "\u67E5\u770B\u673A\u5668\u4EBA\u72B6\u6001", en_us: "Show bot status" },
7280
+ { command: "compact", icon: "ai-block_outlined", default: "\u538B\u7F29\u5F53\u524D\u4F1A\u8BDD\u4E0A\u4E0B\u6587", en_us: "Compact the current session" },
7281
+ { command: "sessionlist", icon: "chat-ai_outlined", default: "\u5217\u51FA\u4F1A\u8BDD", en_us: "List sessions" },
7282
+ { command: "workspacelist", icon: "folder_outlined", default: "\u5217\u51FA\u5DE5\u4F5C\u533A", en_us: "List workspaces" },
7283
+ { command: "workspaces", icon: "folder_outlined", default: "\u5217\u51FA\u5DE5\u4F5C\u533A", en_us: "List workspaces" },
7284
+ { command: "wsl", icon: "folder_outlined", default: "\u5217\u51FA\u5DE5\u4F5C\u533A", en_us: "List workspaces" },
7285
+ { command: "ws", icon: "folder_outlined", default: "\u5207\u6362\u5DE5\u4F5C\u533A", en_us: "Switch workspace" },
7286
+ { command: "watch", icon: "flag_outlined", default: "\u5173\u6CE8\u4E00\u4E2A\u4F1A\u8BDD", en_us: "Watch a session" },
7287
+ { command: "unwatch", icon: "clear_outlined", default: "\u53D6\u6D88\u5173\u6CE8\u4F1A\u8BDD", en_us: "Unwatch a session" },
7288
+ { command: "watchlist", icon: "flag_outlined", default: "\u67E5\u770B\u5173\u6CE8\u5217\u8868", en_us: "List watched sessions" },
7289
+ { command: "archived", icon: "folder_outlined", default: "\u8BBE\u7F6E\u5F52\u6863\u4F1A\u8BDD\u663E\u9690\uFF08on/off\uFF09", en_us: "Show or hide archived sessions (on/off)" },
7290
+ { command: "history", icon: "chat-ai_outlined", default: "\u67E5\u770B\u6700\u8FD1\u5386\u53F2\u6D88\u606F\uFF08\u4EC5\u79C1\u804A\uFF09", en_us: "Show recent history (private chats only)" },
7291
+ { command: "workspace", icon: "folder_outlined", default: "\u5207\u6362\u5DE5\u4F5C\u533A", en_us: "Switch workspace" },
7292
+ { command: "conv", icon: "folder_outlined", default: "\u8BBE\u7F6E\u5F53\u524D\u5BF9\u8BDD\u4E13\u5C5E\u5DE5\u4F5C\u533A", en_us: "Set the workspace for this conversation" },
7293
+ { command: "session", icon: "chat-ai_outlined", default: "\u7ED1\u5B9A\u5DF2\u6709\u4F1A\u8BDD", en_us: "Bind an existing session" },
7294
+ { command: "models", icon: "ai-functions_outlined", default: "\u5217\u51FA\u53EF\u7528\u6A21\u578B", en_us: "List available models" },
7295
+ { command: "model", icon: "ai-agent_outlined", default: "\u67E5\u770B\u6216\u5207\u6362\u5F53\u524D\u6A21\u578B", en_us: "Show or switch the current model" },
7296
+ { command: "reasoninglist", icon: "ai-deepthink_outlined", default: "\u5217\u51FA\u53EF\u7528\u63A8\u7406\u7B49\u7EA7", en_us: "List available reasoning efforts" },
7297
+ { command: "reasoning", icon: "ai-deepthink_outlined", default: "\u67E5\u770B\u6216\u5207\u6362\u63A8\u7406\u7B49\u7EA7", en_us: "Show or switch the reasoning effort" },
7298
+ { command: "presetlist", icon: "skill_outlined", default: "\u5217\u51FA\u53EF\u7528 Agent \u9884\u8BBE", en_us: "List available Agent Presets" },
7299
+ { command: "preset", icon: "skill_outlined", default: "\u67E5\u770B\u6216\u5207\u6362 Agent \u9884\u8BBE", en_us: "Show or switch the Agent Preset" },
7300
+ { command: "stop", icon: "clear_outlined", default: "\u505C\u6B62\u5F53\u524D\u4EFB\u52A1", en_us: "Stop the current task" },
7301
+ { command: "steer", icon: "promptword_outlined", default: "\u7ED9\u5F53\u524D\u4EFB\u52A1\u8865\u5145\u6307\u4EE4", en_us: "Send additional instructions to the current task" },
7302
+ { command: "batch", icon: "chat-ai_outlined", default: "\u5F00\u59CB\u6279\u91CF\u8F93\u5165\uFF08\u4EC5\u79C1\u804A\uFF09", en_us: "Start batch input (private chats only)" },
7303
+ { command: "send", icon: "chat-ai_outlined", default: "\u63D0\u4EA4\u5F53\u524D\u6279\u6B21\uFF08\u4EC5\u79C1\u804A\uFF09", en_us: "Submit the current batch (private chats only)" },
7304
+ { command: "cancel", icon: "clear_outlined", default: "\u53D6\u6D88\u5F53\u524D\u6279\u6B21\uFF08\u4EC5\u79C1\u804A\uFF09", en_us: "Cancel the current batch (private chats only)" },
7305
+ { command: "version", icon: "ai-functions_outlined", default: "\u67E5\u770B\u63D2\u4EF6\u7248\u672C", en_us: "Show the plugin version" },
7306
+ { command: "repair", icon: "ai-functions_outlined", default: "\u8865\u5168\u98DE\u4E66\u6743\u9650\u4E0E\u5361\u7247\u56DE\u8C03\uFF08\u4EC5\u79C1\u804A\uFF09", en_us: "Complete Feishu permissions and card callbacks (private chats only)" }
7307
+ ]);
7308
+ var SLASH_PANEL_MODES = Object.freeze({
7309
+ DEFAULT: "default",
7310
+ CUSTOM: "custom"
7311
+ });
7312
+ var DEFAULT_SLASH_PANEL_CONFIG = Object.freeze({
7313
+ mode: SLASH_PANEL_MODES.DEFAULT,
7314
+ order: Object.freeze([])
7315
+ });
7316
+ var MAX_SLASH_PANEL_COMMANDS = 100;
7317
+ function normalizeCommandName(value) {
7318
+ if (typeof value !== "string") return null;
7319
+ const name2 = value.trim().replace(/^\//u, "").toLowerCase();
7320
+ return name2 || null;
7321
+ }
7322
+ function manifestHas(name2) {
7323
+ return SLASH_COMMAND_MANIFEST.some((entry) => entry.command === name2);
7324
+ }
7325
+ function normalizeSlashPanelConfig(value) {
7326
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
7327
+ return DEFAULT_SLASH_PANEL_CONFIG;
7328
+ }
7329
+ if (value.mode !== SLASH_PANEL_MODES.CUSTOM) return DEFAULT_SLASH_PANEL_CONFIG;
7330
+ const order = [];
7331
+ const seen = /* @__PURE__ */ new Set();
7332
+ for (const candidate of Array.isArray(value.order) ? value.order : []) {
7333
+ const name2 = normalizeCommandName(candidate);
7334
+ if (!name2 || seen.has(name2) || !manifestHas(name2)) continue;
7335
+ seen.add(name2);
7336
+ order.push(name2);
7337
+ if (order.length >= MAX_SLASH_PANEL_COMMANDS) break;
7338
+ }
7339
+ return Object.freeze({ mode: SLASH_PANEL_MODES.CUSTOM, order: Object.freeze(order) });
7340
+ }
7341
+
7244
7342
  // plugin-src/client/channels/feishu/api.js
7245
7343
  var FEISHU_RPC_CHANNEL = "/feishu";
7246
7344
  var FEISHU_ENDPOINTS = Object.freeze({
@@ -7261,10 +7359,11 @@ var FEISHU_ENDPOINTS = Object.freeze({
7261
7359
  setAccessPolicy: "bot.access-policy.set",
7262
7360
  setAlias: "bot.alias.set",
7263
7361
  setGroupResponseMode: "bot.group-response-mode.set",
7264
- setGroupTopicReply: "bot.group-topic-reply.set",
7362
+ setMentionTopicReply: "bot.mention-topic-reply.set",
7265
7363
  setStepPush: "bot.step-push.set",
7266
7364
  setStepPushMode: "bot.step-push-mode.set",
7267
7365
  setVoice: "bot.voice.set",
7366
+ setSlashPanel: "bot.slash-panel.set",
7268
7367
  // Kept for rolling upgrades. The multi-bot UI never calls these endpoints.
7269
7368
  testConnection: "connection.test",
7270
7369
  disconnect: "connection.disconnect"
@@ -7418,10 +7517,11 @@ function normalizeBotConnection(value, fallbackBotId) {
7418
7517
  contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
7419
7518
  ...Object.hasOwn(value, "accessPolicy") ? { accessPolicy: normalizeAccessPolicy(value.accessPolicy) } : {},
7420
7519
  groupResponseMode: normalizeGroupResponseMode(value.groupResponseMode),
7421
- groupTopicReply: value.groupTopicReply === true,
7520
+ mentionTopicReply: value.mentionTopicReply !== false,
7422
7521
  stepPush: value.stepPush === true,
7423
7522
  stepPushMode: normalizeFeishuStepPushMode(value.stepPushMode),
7424
7523
  voice: normalizeFeishuVoiceConfig(value.voice),
7524
+ slashPanel: normalizeSlashPanelConfig(value.slashPanel),
7425
7525
  groupMessagePermissionGranted: value.groupMessagePermissionGranted === true,
7426
7526
  bot: normalizeBot2(value.bot),
7427
7527
  health: normalizeHealth(value.health, connected),
@@ -8129,7 +8229,8 @@ function BotCard({
8129
8229
  accessPolicy: connection.accessPolicy,
8130
8230
  channelSettings: {
8131
8231
  groupResponseMode: connection.groupResponseMode,
8132
- groupTopicReply: connection.groupTopicReply,
8232
+ mentionTopicReply: connection.mentionTopicReply,
8233
+ slashPanel: connection.slashPanel,
8133
8234
  groupMessagePermissionGranted: connection.groupMessagePermissionGranted
8134
8235
  }
8135
8236
  }),
@@ -16120,7 +16221,7 @@ function installInterfaceLanguageMirror(ctx, {
16120
16221
  }
16121
16222
 
16122
16223
  // plugin-src/client/delivery-settings.js
16123
- var React32 = __toESM(require("react"), 1);
16224
+ var React33 = __toESM(require("react"), 1);
16124
16225
 
16125
16226
  // plugin-src/client/access-policy-settings.js
16126
16227
  var React28 = __toESM(require("react"), 1);
@@ -16543,7 +16644,7 @@ function SettingsButton({ children, kind = "secondary", className = "", ...props
16543
16644
  function groupSettingsFrom(value) {
16544
16645
  return {
16545
16646
  groupResponseMode: normalizeGroupResponseMode(value?.groupResponseMode),
16546
- groupTopicReply: value?.groupTopicReply === true,
16647
+ mentionTopicReply: value?.mentionTopicReply !== false,
16547
16648
  groupMessagePermissionGranted: value?.groupMessagePermissionGranted === true
16548
16649
  };
16549
16650
  }
@@ -16672,7 +16773,7 @@ function GroupResponseModeEditor({
16672
16773
  }, error) : null
16673
16774
  );
16674
16775
  }
16675
- function GroupTopicReplyEditor({ value = false, disabled = false, onSave }) {
16776
+ function MentionTopicReplyEditor({ value = true, disabled = false, onSave }) {
16676
16777
  const current = value === true ? "on" : "off";
16677
16778
  const [saving, setSaving] = React29.useState(false);
16678
16779
  const [error, setError] = React29.useState(null);
@@ -16684,7 +16785,7 @@ function GroupTopicReplyEditor({ value = false, disabled = false, onSave }) {
16684
16785
  try {
16685
16786
  await onSave?.(next);
16686
16787
  } catch (cause) {
16687
- setError(cause?.message ?? "\u7FA4\u804A\u4EE5\u8BDD\u9898\u65B9\u5F0F\u56DE\u590D\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002");
16788
+ setError(cause?.message ?? "\u4EE5\u8BDD\u9898\u65B9\u5F0F\u56DE\u590D\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002");
16688
16789
  } finally {
16689
16790
  setSaving(false);
16690
16791
  }
@@ -16693,12 +16794,12 @@ function GroupTopicReplyEditor({ value = false, disabled = false, onSave }) {
16693
16794
  "section",
16694
16795
  {
16695
16796
  className: "dim-feishuGroupControl",
16696
- "aria-labelledby": "dim-feishu-group-topic-title"
16797
+ "aria-labelledby": "dim-feishu-mention-topic-title"
16697
16798
  },
16698
16799
  h2(
16699
16800
  "div",
16700
16801
  { className: "dim-feishuGroupControlHeader" },
16701
- h2("h3", { id: "dim-feishu-group-topic-title" }, "\u7FA4\u804A\u4EE5\u8BDD\u9898\u65B9\u5F0F\u56DE\u590D"),
16802
+ h2("h3", { id: "dim-feishu-mention-topic-title" }, "\u88AB @ \u65F6\u4EE5\u8BDD\u9898\u65B9\u5F0F\u56DE\u590D"),
16702
16803
  saving ? h2("span", { className: "dim-feishuGroupControlStatus", role: "status" }, "\u4FDD\u5B58\u4E2D\u2026") : null
16703
16804
  ),
16704
16805
  h2(
@@ -16707,18 +16808,18 @@ function GroupTopicReplyEditor({ value = false, disabled = false, onSave }) {
16707
16808
  className: "dim-feishuGroupSelect",
16708
16809
  value: current,
16709
16810
  disabled: disabled || saving,
16710
- "aria-label": "\u7FA4\u804A\u4EE5\u8BDD\u9898\u65B9\u5F0F\u56DE\u590D",
16811
+ "aria-label": "\u88AB @ \u65F6\u4EE5\u8BDD\u9898\u65B9\u5F0F\u56DE\u590D",
16711
16812
  onChange: (event) => {
16712
16813
  void change(event);
16713
16814
  }
16714
16815
  },
16715
- h2("option", { value: "off" }, "\u5173\u95ED\uFF08\u7FA4\u5185\u76F4\u63A5\u56DE\u590D\uFF09"),
16816
+ h2("option", { value: "off" }, "\u5173\u95ED\uFF08\u5728\u4F1A\u8BDD\u4E3B\u7A97\u53E3\u56DE\u590D\uFF09"),
16716
16817
  h2("option", { value: "on" }, "\u5F00\u542F\uFF08\u81EA\u52A8\u5F00\u542F\u72EC\u7ACB\u98DE\u4E66\u8BDD\u9898\uFF09")
16717
16818
  ),
16718
16819
  h2(
16719
16820
  "p",
16720
16821
  { className: "dim-feishuGroupHelp" },
16721
- "\u5F00\u542F\u540E\uFF0C\u7FA4\u804A\u4E2D\u5411\u673A\u5668\u4EBA\u63D0\u95EE\u4F1A\u81EA\u52A8\u5F00\u542F\u72EC\u7ACB\u98DE\u4E66\u8BDD\u9898\uFF0C\u56DE\u590D\u843D\u5728\u8BDD\u9898\u5185\uFF1B\u6BCF\u4E2A\u8BDD\u9898\u662F dsh \u4F1A\u8BDD\u5217\u8868\u91CC\u4E00\u6761\u72EC\u7ACB\u4F1A\u8BDD\uFF0C\u4E0A\u4E0B\u6587\u4E92\u4E0D\u4E32\u3002\u79C1\u804A\u4E0D\u53D7\u5F71\u54CD\u3002"
16822
+ "\u5F00\u542F\u540E\uFF0C\u5728\u7FA4\u804A\u6216\u79C1\u804A\u91CC @\u673A\u5668\u4EBA \u63D0\u95EE\uFF0C\u673A\u5668\u4EBA\u4F1A\u5728\u90A3\u6761\u6D88\u606F\u4E0B\u65B0\u5EFA\u4E00\u4E2A\u98DE\u4E66\u8BDD\u9898\u5E76\u5728\u8BDD\u9898\u5185\u56DE\u7B54\uFF1B\u8BE5\u8BDD\u9898\u662F\u4E00\u6761\u72EC\u7ACB\u4F1A\u8BDD\uFF0C\u8BDD\u9898\u91CC\u7684\u540E\u7EED\u6D88\u606F\u90FD\u5C5E\u4E8E\u540C\u4E00\u4E2A\u4F1A\u8BDD\u3002\u53EA\u53D1\u4E00\u4E2A @\u673A\u5668\u4EBA\uFF08\u6253\u5F00\u83DC\u5355\uFF09\u4E0D\u4F1A\u65B0\u5EFA\u8BDD\u9898\uFF0C\u6CA1\u6709 @\u673A\u5668\u4EBA \u7684\u6D88\u606F\u4E5F\u7559\u5728\u539F\u6765\u7684\u4F1A\u8BDD\u91CC\u3002"
16722
16823
  ),
16723
16824
  error ? h2("p", {
16724
16825
  className: "dim-feishuGroupError",
@@ -16874,7 +16975,7 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
16874
16975
  }, [
16875
16976
  account.botId,
16876
16977
  account.groupResponseMode,
16877
- account.groupTopicReply,
16978
+ account.mentionTopicReply,
16878
16979
  account.groupMessagePermissionGranted
16879
16980
  ]);
16880
16981
  React29.useEffect(() => {
@@ -17095,12 +17196,12 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
17095
17196
  },
17096
17197
  onAuthorize: () => startAuthorization()
17097
17198
  }),
17098
- h2(GroupTopicReplyEditor, {
17099
- value: settings.groupTopicReply,
17199
+ h2(MentionTopicReplyEditor, {
17200
+ value: settings.mentionTopicReply,
17100
17201
  disabled,
17101
- onSave: (groupTopicReply) => saveSetting(
17102
- FEISHU_ENDPOINTS.setGroupTopicReply,
17103
- { groupTopicReply }
17202
+ onSave: (mentionTopicReply) => saveSetting(
17203
+ FEISHU_ENDPOINTS.setMentionTopicReply,
17204
+ { mentionTopicReply }
17104
17205
  )
17105
17206
  })
17106
17207
  ),
@@ -17317,6 +17418,309 @@ function FeishuVoiceSettingsPage({ account, rpcCall }) {
17317
17418
  return h2(VoiceEditor, { value: voice, onSave: saveVoice });
17318
17419
  }
17319
17420
 
17421
+ // plugin-src/client/channels/feishu/slash-panel-settings.js
17422
+ var React32 = __toESM(require("react"), 1);
17423
+ var MANIFEST_BY_NAME = new Map(SLASH_COMMAND_MANIFEST.map((entry) => [entry.command, entry]));
17424
+ var ALL_COMMANDS = Object.freeze(SLASH_COMMAND_MANIFEST.map((entry) => entry.command));
17425
+ function PanelButton({ children, disabled = false, onClick, ...props }) {
17426
+ return h2("button", {
17427
+ ...props,
17428
+ type: "button",
17429
+ className: "dim-deliveryButton",
17430
+ disabled,
17431
+ onClick
17432
+ }, children);
17433
+ }
17434
+ function panelSignature(panel) {
17435
+ const normalized = normalizeSlashPanelConfig(panel);
17436
+ return `${normalized.mode}:${normalized.order.join(",")}`;
17437
+ }
17438
+ function commandText(name2) {
17439
+ const entry = MANIFEST_BY_NAME.get(name2);
17440
+ return `/${name2} \u2014 ${entry?.default ?? name2}`;
17441
+ }
17442
+ function FeishuSlashPanelSettingsPage({ account, rpcCall, onSaved }) {
17443
+ const incoming = React32.useMemo(() => normalizeSlashPanelConfig(account.slashPanel), [account.botId, panelSignature(account.slashPanel)]);
17444
+ const [mode, setMode] = React32.useState(incoming.mode);
17445
+ const [order, setOrder] = React32.useState(() => [...incoming.order]);
17446
+ const [pending, setPending] = React32.useState("");
17447
+ const [dirty, setDirty] = React32.useState(false);
17448
+ const [saving, setSaving] = React32.useState(false);
17449
+ const [saved, setSaved] = React32.useState(false);
17450
+ const [syncing, setSyncing] = React32.useState(false);
17451
+ const [syncTargets, setSyncTargets] = React32.useState(null);
17452
+ const [syncNotice, setSyncNotice] = React32.useState(null);
17453
+ const [error, setError] = React32.useState(null);
17454
+ const mounted = React32.useRef(true);
17455
+ React32.useEffect(() => {
17456
+ mounted.current = true;
17457
+ return () => {
17458
+ mounted.current = false;
17459
+ };
17460
+ }, []);
17461
+ React32.useEffect(() => {
17462
+ if (dirty) return;
17463
+ setMode(incoming.mode);
17464
+ setOrder([...incoming.order]);
17465
+ }, [incoming.mode, incoming.order, dirty]);
17466
+ const edit = React32.useCallback((update) => {
17467
+ setSaved(false);
17468
+ setDirty(true);
17469
+ update();
17470
+ }, []);
17471
+ const move = (index, offset) => edit(() => {
17472
+ const next = [...order];
17473
+ const target = index + offset;
17474
+ if (target < 0 || target >= next.length) return;
17475
+ [next[index], next[target]] = [next[target], next[index]];
17476
+ setOrder(next);
17477
+ });
17478
+ const remove = (index) => edit(() => setOrder(order.filter((_, at) => at !== index)));
17479
+ const add = () => {
17480
+ if (!pending || order.includes(pending)) return;
17481
+ edit(() => setOrder([...order, pending]));
17482
+ setPending("");
17483
+ };
17484
+ const draftPanel = () => mode === SLASH_PANEL_MODES.CUSTOM ? { mode: SLASH_PANEL_MODES.CUSTOM, order: [...order] } : { mode: SLASH_PANEL_MODES.DEFAULT, order: [] };
17485
+ const applySnapshot = (value) => {
17486
+ const snapshot = normalizeBotsSnapshot(value);
17487
+ const bot = snapshot.bots.find((entry) => entry.botId === account.botId);
17488
+ const stored = normalizeSlashPanelConfig(bot?.slashPanel);
17489
+ setMode(stored.mode);
17490
+ setOrder([...stored.order]);
17491
+ onSaved?.(stored);
17492
+ setDirty(false);
17493
+ setSaved(true);
17494
+ return snapshot;
17495
+ };
17496
+ const save = async () => {
17497
+ if (saving) return;
17498
+ setSaving(true);
17499
+ setError(null);
17500
+ try {
17501
+ if (typeof rpcCall !== "function") throw new Error("\u98DE\u4E66\u6307\u4EE4\u9762\u677F\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
17502
+ const value = unwrapRpcResult3(await rpcCall(
17503
+ FEISHU_ENDPOINTS.setSlashPanel,
17504
+ { botId: account.botId, slashPanel: draftPanel() }
17505
+ ));
17506
+ if (!mounted.current) return;
17507
+ applySnapshot(value);
17508
+ } catch (cause) {
17509
+ if (!mounted.current) return;
17510
+ setError(presentError3(cause));
17511
+ } finally {
17512
+ if (mounted.current) setSaving(false);
17513
+ }
17514
+ };
17515
+ const startSyncAll = async () => {
17516
+ if (saving || syncing || typeof rpcCall !== "function") return;
17517
+ setSyncing(true);
17518
+ setError(null);
17519
+ setSyncNotice(null);
17520
+ try {
17521
+ const snapshot = normalizeBotsSnapshot(unwrapRpcResult3(
17522
+ await rpcCall(FEISHU_ENDPOINTS.status, {})
17523
+ ));
17524
+ const others = snapshot.bots.map((entry) => entry.botId).filter((botId) => botId && botId !== account.botId);
17525
+ if (!mounted.current) return;
17526
+ if (others.length === 0) {
17527
+ setSyncNotice({ scope: "none" });
17528
+ return;
17529
+ }
17530
+ setSyncTargets(others);
17531
+ } catch (cause) {
17532
+ if (mounted.current) setError(presentError3(cause));
17533
+ } finally {
17534
+ if (mounted.current) setSyncing(false);
17535
+ }
17536
+ };
17537
+ const confirmSyncAll = async () => {
17538
+ const targets = syncTargets;
17539
+ if (!targets || syncing || typeof rpcCall !== "function") return;
17540
+ setSyncing(true);
17541
+ setError(null);
17542
+ setSyncTargets(null);
17543
+ const payload = draftPanel();
17544
+ let done = 0;
17545
+ let failed = 0;
17546
+ for (const botId of [account.botId, ...targets]) {
17547
+ try {
17548
+ const value = unwrapRpcResult3(await rpcCall(
17549
+ FEISHU_ENDPOINTS.setSlashPanel,
17550
+ { botId, slashPanel: payload }
17551
+ ));
17552
+ if (botId === account.botId && mounted.current) applySnapshot(value);
17553
+ done += 1;
17554
+ } catch {
17555
+ failed += 1;
17556
+ }
17557
+ }
17558
+ if (!mounted.current) return;
17559
+ setSyncing(false);
17560
+ setSyncNotice({ scope: "done", done, failed });
17561
+ };
17562
+ const available = ALL_COMMANDS.filter((name2) => !order.includes(name2));
17563
+ return h2(
17564
+ "section",
17565
+ {
17566
+ className: "dim-feishuGroupSettings",
17567
+ "aria-label": "\u6307\u4EE4\u9762\u677F\u8BBE\u7F6E"
17568
+ },
17569
+ h2(
17570
+ "section",
17571
+ {
17572
+ className: "dim-feishuGroupControl",
17573
+ "aria-labelledby": "dim-feishu-slash-panel-title"
17574
+ },
17575
+ h2(
17576
+ "div",
17577
+ { className: "dim-feishuGroupControlHeader" },
17578
+ h2("h3", { id: "dim-feishu-slash-panel-title" }, "\u6307\u4EE4\u9762\u677F"),
17579
+ saving ? h2("span", { className: "dim-feishuGroupControlStatus", role: "status" }, "\u4FDD\u5B58\u4E2D\u2026") : saved ? h2("span", { className: "dim-feishuGroupControlStatus", role: "status" }, "\u5DF2\u4FDD\u5B58\uFF0C\u9762\u677F\u7A0D\u540E\u540C\u6B65") : null
17580
+ ),
17581
+ h2(
17582
+ "p",
17583
+ { className: "dim-feishuGroupHelp" },
17584
+ "\u9762\u677F\u53EA\u51B3\u5B9A\u804A\u5929\u8F93\u5165\u6846\u91CC\u6253\u300C/\u300D\u65F6\u5217\u51FA\u7684\u6307\u4EE4\u548C\u987A\u5E8F\uFF1B\u88AB\u79FB\u9664\u7684\u6307\u4EE4\u4ECD\u53EF\u624B\u52A8\u8F93\u5165\uFF0C\u529F\u80FD\u4E0D\u53D7\u5F71\u54CD\u3002\u540C\u6B65\u7531\u673A\u5668\u4EBA\u540E\u53F0\u5B8C\u6210\uFF0C\u6307\u4EE4\u8F83\u591A\u65F6\u9700\u8981\u4E00\u70B9\u65F6\u95F4\u3002"
17585
+ ),
17586
+ h2(
17587
+ "select",
17588
+ {
17589
+ className: "dim-feishuGroupSelect",
17590
+ value: mode,
17591
+ "aria-label": "\u6307\u4EE4\u9762\u677F\u6A21\u5F0F",
17592
+ disabled: saving || syncing,
17593
+ onChange: (event) => edit(() => {
17594
+ const next = event.target.value;
17595
+ setMode(next);
17596
+ if (next === SLASH_PANEL_MODES.CUSTOM && order.length === 0) setOrder([...ALL_COMMANDS]);
17597
+ })
17598
+ },
17599
+ h2("option", { value: SLASH_PANEL_MODES.DEFAULT }, "\u8DDF\u968F\u9ED8\u8BA4\uFF08\u968F\u63D2\u4EF6\u7248\u672C\u66F4\u65B0\uFF09"),
17600
+ h2("option", { value: SLASH_PANEL_MODES.CUSTOM }, "\u81EA\u5B9A\u4E49\uFF08\u81EA\u5DF1\u6311\u6307\u4EE4\u548C\u987A\u5E8F\uFF09")
17601
+ ),
17602
+ mode === SLASH_PANEL_MODES.CUSTOM ? h2(
17603
+ React32.Fragment,
17604
+ null,
17605
+ order.length === 0 ? h2("p", { className: "dim-feishuGroupHelp" }, "\u5F53\u524D\u6CA1\u6709\u9009\u62E9\u4EFB\u4F55\u6307\u4EE4\uFF0C\u4FDD\u5B58\u540E\u300C/\u300D\u9762\u677F\u4F1A\u53D8\u6210\u7A7A\u7684\u3002") : h2(
17606
+ "ul",
17607
+ { className: "dim-feishuPanelList" },
17608
+ order.map((name2, index) => h2(
17609
+ "li",
17610
+ {
17611
+ key: name2,
17612
+ className: "dim-feishuPanelRow"
17613
+ },
17614
+ h2("span", { className: "dim-feishuPanelIndex" }, String(index + 1)),
17615
+ h2("span", { className: "dim-feishuPanelCommand" }, commandText(name2)),
17616
+ h2(
17617
+ "span",
17618
+ { className: "dim-feishuPanelRowActions" },
17619
+ h2(PanelButton, {
17620
+ "aria-label": [localizeText("\u4E0A\u79FB"), `/${name2}`].join(" "),
17621
+ disabled: saving || syncing || index === 0,
17622
+ onClick: () => move(index, -1)
17623
+ }, "\u2191"),
17624
+ h2(PanelButton, {
17625
+ "aria-label": [localizeText("\u4E0B\u79FB"), `/${name2}`].join(" "),
17626
+ disabled: saving || syncing || index === order.length - 1,
17627
+ onClick: () => move(index, 1)
17628
+ }, "\u2193"),
17629
+ h2(PanelButton, {
17630
+ "aria-label": [localizeText("\u79FB\u9664"), `/${name2}`].join(" "),
17631
+ disabled: saving || syncing,
17632
+ onClick: () => remove(index)
17633
+ }, "\u79FB\u9664")
17634
+ )
17635
+ ))
17636
+ ),
17637
+ h2(
17638
+ "div",
17639
+ { className: "dim-feishuPanelAdd" },
17640
+ h2(
17641
+ "select",
17642
+ {
17643
+ className: "dim-feishuGroupSelect",
17644
+ value: pending,
17645
+ "aria-label": "\u6DFB\u52A0\u6307\u4EE4",
17646
+ disabled: saving || syncing || available.length === 0,
17647
+ onChange: (event) => setPending(event.target.value)
17648
+ },
17649
+ h2("option", { value: "" }, available.length === 0 ? "\u6307\u4EE4\u90FD\u5DF2\u52A0\u5165" : "\u9009\u62E9\u8981\u52A0\u5165\u7684\u6307\u4EE4"),
17650
+ available.map((name2) => h2("option", { key: name2, value: name2 }, commandText(name2)))
17651
+ ),
17652
+ h2(PanelButton, {
17653
+ disabled: saving || syncing || !pending,
17654
+ onClick: add
17655
+ }, "\u52A0\u5165"),
17656
+ h2(PanelButton, {
17657
+ disabled: saving || syncing || available.length === 0,
17658
+ onClick: () => edit(() => setOrder([...ALL_COMMANDS]))
17659
+ }, "\u6062\u590D\u5168\u90E8"),
17660
+ h2(PanelButton, {
17661
+ disabled: saving || syncing || order.length === 0,
17662
+ onClick: () => edit(() => setOrder([]))
17663
+ }, "\u5168\u90E8\u79FB\u9664")
17664
+ )
17665
+ ) : null,
17666
+ h2(
17667
+ "div",
17668
+ { className: "dim-feishuPanelFooter" },
17669
+ h2(PanelButton, {
17670
+ "data-kind": "primary",
17671
+ disabled: saving || syncing || !dirty,
17672
+ onClick: () => {
17673
+ void save();
17674
+ }
17675
+ }, "\u4FDD\u5B58"),
17676
+ h2(PanelButton, {
17677
+ disabled: saving || syncing,
17678
+ onClick: () => {
17679
+ void startSyncAll();
17680
+ }
17681
+ }, "\u4FDD\u5B58\u5E76\u540C\u6B65\u5230\u5176\u4ED6\u673A\u5668\u4EBA")
17682
+ ),
17683
+ syncTargets ? h2(
17684
+ "div",
17685
+ { className: "dim-feishuPanelFooter" },
17686
+ h2(
17687
+ "span",
17688
+ { className: "dim-feishuGroupHelp" },
17689
+ [
17690
+ localizeText("\u5C06\u628A\u8FD9\u5957\u9762\u677F\u8BBE\u7F6E\u5199\u5165\u53E6\u5916"),
17691
+ ` ${syncTargets.length} `,
17692
+ localizeText("\u4E2A\u98DE\u4E66\u673A\u5668\u4EBA\uFF0C\u5B83\u4EEC\u5404\u81EA\u7684\u9762\u677F\u8BBE\u7F6E\u4F1A\u88AB\u8986\u76D6\u3002")
17693
+ ].join("")
17694
+ ),
17695
+ h2(PanelButton, {
17696
+ disabled: syncing,
17697
+ onClick: () => {
17698
+ void confirmSyncAll();
17699
+ }
17700
+ }, "\u786E\u8BA4\u540C\u6B65"),
17701
+ h2(PanelButton, {
17702
+ disabled: syncing,
17703
+ onClick: () => setSyncTargets(null)
17704
+ }, "\u53D6\u6D88")
17705
+ ) : null,
17706
+ syncing ? h2("p", { className: "dim-feishuGroupHelp", role: "status" }, "\u6B63\u5728\u540C\u6B65\u2026") : null,
17707
+ syncNotice?.scope === "none" ? h2("p", { className: "dim-feishuGroupHelp", role: "status" }, "\u8FD9\u4E2A\u6E20\u9053\u6CA1\u6709\u5176\u4ED6\u98DE\u4E66\u673A\u5668\u4EBA\uFF0C\u4E0D\u7528\u540C\u6B65\u3002") : null,
17708
+ syncNotice?.scope === "done" ? h2(
17709
+ "p",
17710
+ { className: "dim-feishuGroupHelp", role: "status" },
17711
+ syncNotice.failed > 0 ? [
17712
+ localizeText("\u5DF2\u540C\u6B65\u5230"),
17713
+ ` ${syncNotice.done} `,
17714
+ localizeText("\u4E2A\u673A\u5668\u4EBA\uFF0C"),
17715
+ ` ${syncNotice.failed} `,
17716
+ localizeText("\u4E2A\u5931\u8D25\u3002")
17717
+ ].join("") : [localizeText("\u5DF2\u540C\u6B65\u5230"), ` ${syncNotice.done} `, localizeText("\u4E2A\u673A\u5668\u4EBA\u3002")].join("")
17718
+ ) : null,
17719
+ error ? h2("p", { className: "dim-feishuGroupError", role: "alert" }, error) : null
17720
+ )
17721
+ );
17722
+ }
17723
+
17320
17724
  // plugin-src/client/delivery-settings.js
17321
17725
  var DELIVERY_RPC_CHANNEL = "/dsh-im-delivery";
17322
17726
  var DELIVERY_DOCS_URL = Object.freeze({
@@ -17339,6 +17743,7 @@ var BOT_SETTINGS_TABS = Object.freeze([
17339
17743
  var FEISHU_BOT_SETTINGS_TABS = Object.freeze([
17340
17744
  ...BOT_SETTINGS_TABS,
17341
17745
  Object.freeze({ id: "group", label: "\u7FA4\u804A" }),
17746
+ Object.freeze({ id: "slash", label: "\u6307\u4EE4\u9762\u677F" }),
17342
17747
  Object.freeze({ id: "voice", label: "\u8BED\u97F3\u4EA4\u4E92" })
17343
17748
  ]);
17344
17749
  function botSettingsTabsForChannel(channel7) {
@@ -17551,13 +17956,13 @@ function TargetForm({
17551
17956
  }) {
17552
17957
  const editing = mode === "edit";
17553
17958
  const initialKind = initialValue?.kind && definition.fields[initialValue.kind] ? initialValue.kind : definition.kinds[0].value;
17554
- const [targetId, setTargetId] = React32.useState(initialValue?.targetId ?? "");
17555
- const [name2, setName] = React32.useState(initialValue?.name ?? "");
17556
- const [kind, setKind] = React32.useState(initialKind);
17557
- const [route, setRoute] = React32.useState(initialValue?.route ?? {});
17558
- const [error, setError] = React32.useState(null);
17559
- const [testing, setTesting] = React32.useState(false);
17560
- const [testState, setTestState] = React32.useState(null);
17959
+ const [targetId, setTargetId] = React33.useState(initialValue?.targetId ?? "");
17960
+ const [name2, setName] = React33.useState(initialValue?.name ?? "");
17961
+ const [kind, setKind] = React33.useState(initialKind);
17962
+ const [route, setRoute] = React33.useState(initialValue?.route ?? {});
17963
+ const [error, setError] = React33.useState(null);
17964
+ const [testing, setTesting] = React33.useState(false);
17965
+ const [testState, setTestState] = React33.useState(null);
17561
17966
  const currentTarget = () => {
17562
17967
  const normalizedRoute = Object.fromEntries(fieldsFor(definition, kind).map((field2) => {
17563
17968
  const raw = String(route[field2.key] ?? "").trim();
@@ -17774,7 +18179,7 @@ function TargetSuggestionPicker({
17774
18179
  suggestions.map((suggestion, index) => {
17775
18180
  const identity = routeIdentity(definition, suggestion);
17776
18181
  const added = configured.has(identity);
17777
- return React32.createElement("option", {
18182
+ return React33.createElement("option", {
17778
18183
  key: suggestion.id ?? suggestion.suggestionId ?? `${identity}:${index}`,
17779
18184
  value: String(index),
17780
18185
  disabled: added
@@ -17791,11 +18196,11 @@ function TargetSuggestionPicker({
17791
18196
  );
17792
18197
  }
17793
18198
  function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, onEdit }) {
17794
- const [action, setAction] = React32.useState(null);
17795
- const [testState, setTestState] = React32.useState(null);
17796
- const [syncFeedback, setSyncFeedback] = React32.useState(null);
17797
- const [copyState, setCopyState] = React32.useState(null);
17798
- const [confirmDelete, setConfirmDelete] = React32.useState(false);
18199
+ const [action, setAction] = React33.useState(null);
18200
+ const [testState, setTestState] = React33.useState(null);
18201
+ const [syncFeedback, setSyncFeedback] = React33.useState(null);
18202
+ const [copyState, setCopyState] = React33.useState(null);
18203
+ const [confirmDelete, setConfirmDelete] = React33.useState(false);
17799
18204
  const sessionSync = target.sessionSync ?? { enabled: false, state: "unavailable" };
17800
18205
  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";
17801
18206
  const testTarget = async () => {
@@ -17858,7 +18263,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
17858
18263
  h2(
17859
18264
  "div",
17860
18265
  { className: "dim-targetTitle" },
17861
- React32.createElement("strong", null, target.name || target.targetId),
18266
+ React33.createElement("strong", null, target.name || target.targetId),
17862
18267
  h2("span", null, kindLabel(definition, target.kind))
17863
18268
  ),
17864
18269
  h2("code", null, `targetId: ${target.targetId}`)
@@ -17944,26 +18349,30 @@ function DeliveryTargetSettingsPage({
17944
18349
  onBack
17945
18350
  }) {
17946
18351
  const definition = CHANNEL_DEFINITIONS[channel7];
17947
- const [activeTabId, setActiveTabId] = React32.useState(BOT_SETTINGS_TABS[0].id);
17948
- const [phase, setPhase] = React32.useState("loading");
17949
- const [targets, setTargets] = React32.useState([]);
17950
- const [suggestionPhase, setSuggestionPhase] = React32.useState("idle");
17951
- const [suggestions, setSuggestions] = React32.useState([]);
17952
- const [suggestionError, setSuggestionError] = React32.useState(null);
17953
- const [error, setError] = React32.useState(null);
17954
- const [editor, setEditor] = React32.useState(null);
17955
- const [saving, setSaving] = React32.useState(false);
17956
- const [botCopyState, setBotCopyState] = React32.useState(null);
17957
- const [accessPolicy, setAccessPolicy] = React32.useState(account.accessPolicy);
17958
- const mounted = React32.useRef(true);
17959
- React32.useEffect(() => {
18352
+ const [activeTabId, setActiveTabId] = React33.useState(BOT_SETTINGS_TABS[0].id);
18353
+ const [phase, setPhase] = React33.useState("loading");
18354
+ const [targets, setTargets] = React33.useState([]);
18355
+ const [suggestionPhase, setSuggestionPhase] = React33.useState("idle");
18356
+ const [suggestions, setSuggestions] = React33.useState([]);
18357
+ const [suggestionError, setSuggestionError] = React33.useState(null);
18358
+ const [error, setError] = React33.useState(null);
18359
+ const [editor, setEditor] = React33.useState(null);
18360
+ const [saving, setSaving] = React33.useState(false);
18361
+ const [botCopyState, setBotCopyState] = React33.useState(null);
18362
+ const [accessPolicy, setAccessPolicy] = React33.useState(account.accessPolicy);
18363
+ const [slashPanel, setSlashPanel] = React33.useState(account.slashPanel);
18364
+ const mounted = React33.useRef(true);
18365
+ React33.useEffect(() => {
17960
18366
  setAccessPolicy(account.accessPolicy);
17961
18367
  }, [account.botId, account.accessPolicy]);
17962
- const invoke = React32.useCallback(async (endpoint, payload = {}, signal) => {
18368
+ React33.useEffect(() => {
18369
+ setSlashPanel(account.slashPanel);
18370
+ }, [account.botId, account.slashPanel]);
18371
+ const invoke = React33.useCallback(async (endpoint, payload = {}, signal) => {
17963
18372
  if (typeof rpcCall !== "function") throw new Error("\u6295\u9012\u76EE\u6807\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
17964
18373
  return unwrapRpcResult15(await rpcCall(endpoint, payload, signal));
17965
18374
  }, [rpcCall]);
17966
- const loadTargets = React32.useCallback(async ({ signal, silent = false } = {}) => {
18375
+ const loadTargets = React33.useCallback(async ({ signal, silent = false } = {}) => {
17967
18376
  if (!silent) setPhase("loading");
17968
18377
  setError(null);
17969
18378
  try {
@@ -17977,7 +18386,7 @@ function DeliveryTargetSettingsPage({
17977
18386
  setPhase("error");
17978
18387
  }
17979
18388
  }, [account.botId, invoke]);
17980
- const loadSuggestions = React32.useCallback(async () => {
18389
+ const loadSuggestions = React33.useCallback(async () => {
17981
18390
  setSuggestionPhase("loading");
17982
18391
  setSuggestionError(null);
17983
18392
  try {
@@ -17991,7 +18400,7 @@ function DeliveryTargetSettingsPage({
17991
18400
  setSuggestionPhase("error");
17992
18401
  }
17993
18402
  }, [account.botId, definition, invoke]);
17994
- React32.useEffect(() => {
18403
+ React33.useEffect(() => {
17995
18404
  mounted.current = true;
17996
18405
  const controller = new AbortController();
17997
18406
  void loadTargets({ signal: controller.signal });
@@ -18112,12 +18521,16 @@ function DeliveryTargetSettingsPage({
18112
18521
  }) : activeTab.id === "group" && channel7 === "feishu" ? h2(FeishuGroupSettingsPage, {
18113
18522
  account,
18114
18523
  rpcCall: accessRpcCall
18524
+ }) : activeTab.id === "slash" && channel7 === "feishu" ? h2(FeishuSlashPanelSettingsPage, {
18525
+ account: { ...account, slashPanel },
18526
+ rpcCall: accessRpcCall,
18527
+ onSaved: setSlashPanel
18115
18528
  }) : activeTab.id === "voice" && channel7 === "feishu" ? h2(FeishuVoiceSettingsPage, {
18116
18529
  key: account.botId,
18117
18530
  account,
18118
18531
  rpcCall: accessRpcCall
18119
18532
  }) : h2(
18120
- React32.Fragment,
18533
+ React33.Fragment,
18121
18534
  null,
18122
18535
  h2(
18123
18536
  "section",
@@ -18228,7 +18641,7 @@ function DeliveryTargetSettingsPage({
18228
18641
  }
18229
18642
 
18230
18643
  // plugin-src/client/global-settings.js
18231
- var React33 = __toESM(require("react"), 1);
18644
+ var React34 = __toESM(require("react"), 1);
18232
18645
 
18233
18646
  // src/channels/shared/inbound-ttl.mjs
18234
18647
  var DEFAULT_INBOUND_TTL_HOURS = 168;
@@ -18313,14 +18726,14 @@ function GlobalButton({ children, kind = "secondary", className = "", ...props }
18313
18726
  }, children);
18314
18727
  }
18315
18728
  function ImageInputSettings({ rpcCall }) {
18316
- const [values, setValues] = React33.useState(DEFAULT_IMAGE_INPUT_SETTINGS);
18317
- const [phase, setPhase] = React33.useState("loading");
18318
- const [error, setError] = React33.useState(null);
18319
- const [saved, setSaved] = React33.useState(false);
18320
- const mounted = React33.useRef(false);
18321
- const saving = React33.useRef(false);
18322
- const id6 = React33.useId();
18323
- const load = React33.useCallback(async (signal) => {
18729
+ const [values, setValues] = React34.useState(DEFAULT_IMAGE_INPUT_SETTINGS);
18730
+ const [phase, setPhase] = React34.useState("loading");
18731
+ const [error, setError] = React34.useState(null);
18732
+ const [saved, setSaved] = React34.useState(false);
18733
+ const mounted = React34.useRef(false);
18734
+ const saving = React34.useRef(false);
18735
+ const id6 = React34.useId();
18736
+ const load = React34.useCallback(async (signal) => {
18324
18737
  setPhase("loading");
18325
18738
  setError(null);
18326
18739
  try {
@@ -18336,7 +18749,7 @@ function ImageInputSettings({ rpcCall }) {
18336
18749
  setPhase("error");
18337
18750
  }
18338
18751
  }, [rpcCall]);
18339
- React33.useEffect(() => {
18752
+ React34.useEffect(() => {
18340
18753
  mounted.current = true;
18341
18754
  const controller = new AbortController();
18342
18755
  void load(controller.signal);
@@ -18443,29 +18856,29 @@ function ImageInputSettings({ rpcCall }) {
18443
18856
  );
18444
18857
  }
18445
18858
  function GlobalSettingsPanel({ rpcCall }) {
18446
- const [phase, setPhase] = React33.useState("loading");
18447
- const [loadError, setLoadError] = React33.useState(null);
18448
- const [ttlInput, setTtlInput] = React33.useState("");
18449
- const [savedTtl, setSavedTtl] = React33.useState(null);
18450
- const [ttlError, setTtlError] = React33.useState(false);
18451
- const [saveError, setSaveError] = React33.useState(null);
18452
- const [saveSucceeded, setSaveSucceeded] = React33.useState(false);
18453
- const [isSaving, setIsSaving] = React33.useState(false);
18454
- const [sweepConfirming, setSweepConfirming] = React33.useState(false);
18455
- const [sweeping, setSweeping] = React33.useState(false);
18456
- const ttlErrorId = React33.useId();
18457
- const ttlHintsId = React33.useId();
18458
- const sweepTriggerId = React33.useId();
18459
- const sweepConfirmId = React33.useId();
18460
- const sweepConfirmTextId = React33.useId();
18461
- const sweepConfirmButtonId = React33.useId();
18462
- const mounted = React33.useRef(true);
18463
- const saving = React33.useRef(false);
18464
- const invoke = React33.useCallback(async (endpoint, payload = {}, signal) => {
18859
+ const [phase, setPhase] = React34.useState("loading");
18860
+ const [loadError, setLoadError] = React34.useState(null);
18861
+ const [ttlInput, setTtlInput] = React34.useState("");
18862
+ const [savedTtl, setSavedTtl] = React34.useState(null);
18863
+ const [ttlError, setTtlError] = React34.useState(false);
18864
+ const [saveError, setSaveError] = React34.useState(null);
18865
+ const [saveSucceeded, setSaveSucceeded] = React34.useState(false);
18866
+ const [isSaving, setIsSaving] = React34.useState(false);
18867
+ const [sweepConfirming, setSweepConfirming] = React34.useState(false);
18868
+ const [sweeping, setSweeping] = React34.useState(false);
18869
+ const ttlErrorId = React34.useId();
18870
+ const ttlHintsId = React34.useId();
18871
+ const sweepTriggerId = React34.useId();
18872
+ const sweepConfirmId = React34.useId();
18873
+ const sweepConfirmTextId = React34.useId();
18874
+ const sweepConfirmButtonId = React34.useId();
18875
+ const mounted = React34.useRef(true);
18876
+ const saving = React34.useRef(false);
18877
+ const invoke = React34.useCallback(async (endpoint, payload = {}, signal) => {
18465
18878
  if (typeof rpcCall !== "function") throw new Error("\u901A\u7528\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
18466
18879
  return unwrapRpcResult16(await rpcCall(endpoint, payload, signal));
18467
18880
  }, [rpcCall]);
18468
- const loadSettings = React33.useCallback(async ({ signal } = {}) => {
18881
+ const loadSettings = React34.useCallback(async ({ signal } = {}) => {
18469
18882
  setPhase("loading");
18470
18883
  setLoadError(null);
18471
18884
  try {
@@ -18489,7 +18902,7 @@ function GlobalSettingsPanel({ rpcCall }) {
18489
18902
  setPhase("error");
18490
18903
  }
18491
18904
  }, [invoke]);
18492
- React33.useEffect(() => {
18905
+ React34.useEffect(() => {
18493
18906
  mounted.current = true;
18494
18907
  const controller = new AbortController();
18495
18908
  void loadSettings({ signal: controller.signal });
@@ -18498,7 +18911,7 @@ function GlobalSettingsPanel({ rpcCall }) {
18498
18911
  controller.abort();
18499
18912
  };
18500
18913
  }, [loadSettings]);
18501
- React33.useEffect(() => {
18914
+ React34.useEffect(() => {
18502
18915
  if (!sweepConfirming) return;
18503
18916
  globalThis.document?.getElementById(sweepConfirmButtonId)?.focus();
18504
18917
  }, [sweepConfirmButtonId, sweepConfirming]);
@@ -19300,6 +19713,15 @@ var CSS15 = String.raw`
19300
19713
  .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)); }
19301
19714
  .dim-feishuGroupError, .dim-feishuGroupRefreshError { margin: 0; padding: 9px 11px; border-radius: 8px; font-size: 12px; line-height: 18px; }
19302
19715
  .dim-feishuGroupError, .dim-feishuGroupRefreshError { color: var(--dsw-alias-state-error-primary, #d54941); background: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d54941) 7%, var(--dsw-alias-bg-layer-1, #fff)); }
19716
+ .dim-feishuPanelList { display: grid; gap: 7px; margin: 0; padding: 0; list-style: none; }
19717
+ .dim-feishuPanelRow { min-width: 0; display: grid; grid-template-columns: max-content minmax(0, 1fr) max-content; align-items: center; gap: 10px; padding: 8px 10px; border: 1px solid var(--dsw-alias-border-l1, #eef0f3); border-radius: 9px; background: var(--dsw-alias-bg-module-platform, #f7f8fa); }
19718
+ .dim-feishuPanelIndex { min-width: 18px; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 11px; line-height: 17px; text-align: right; }
19719
+ .dim-feishuPanelCommand { min-width: 0; color: var(--dsw-alias-label-primary, #1f2329); font-size: 12px; line-height: 18px; overflow-wrap: anywhere; }
19720
+ .dim-feishuPanelRowActions, .dim-feishuPanelAdd { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
19721
+ .dim-feishuPanelRow .dim-deliveryButton { min-height: 28px; padding: 0 9px; font-size: 12px; }
19722
+ .dim-feishuPanelAdd { margin-top: 2px; }
19723
+ .dim-feishuPanelAdd .dim-feishuGroupSelect { flex: 1 1 220px; width: auto; }
19724
+ .dim-feishuPanelFooter { display: flex; justify-content: flex-start; }
19303
19725
  .dim-feishuGroupAuthorization { min-width: 0; display: grid; grid-template-columns: 184px minmax(0, 1fr); align-items: start; gap: 24px; padding: 18px; border: 1px solid color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 30%, var(--dsw-alias-border-l2, #dfe1e5)); border-radius: 12px; background: color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 2.5%, var(--dsw-alias-bg-layer-3, #fff)); }
19304
19726
  .dim-feishuGroupAuthorizationState { min-height: 126px; grid-template-columns: 32px minmax(0, 1fr); align-items: center; }
19305
19727
  .dim-feishuGroupAuthorizationState h3, .dim-feishuGroupAuthorizationError h3, .dim-feishuGroupAuthorizationCopy h3 { margin: 0; color: var(--dsw-alias-label-primary, #1f2329); font-size: 16px; line-height: 24px; font-weight: 650; }
@@ -19810,7 +20232,7 @@ function installSessionChannelLogos(document2 = globalThis.document) {
19810
20232
  }
19811
20233
 
19812
20234
  // plugin-src/client/update-panel.js
19813
- var React34 = __toESM(require("react"), 1);
20235
+ var React35 = __toESM(require("react"), 1);
19814
20236
  var import_react_dom4 = require("react-dom");
19815
20237
  var import_valid = __toESM(require_valid(), 1);
19816
20238
  var import_rcompare = __toESM(require_rcompare(), 1);
@@ -19903,11 +20325,11 @@ function manualUpdateCommand(snapshot) {
19903
20325
  return `dsh plugin --profile ${profileArgument} add -w @xmanrui/dsh-im@${version}`;
19904
20326
  }
19905
20327
  function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
19906
- const [copyState, setCopyState] = React34.useState("idle");
19907
- const commandRef = React34.useRef(null);
19908
- const mounted = React34.useRef(false);
19909
- const copying = React34.useRef(false);
19910
- React34.useEffect(() => {
20328
+ const [copyState, setCopyState] = React35.useState("idle");
20329
+ const commandRef = React35.useRef(null);
20330
+ const mounted = React35.useRef(false);
20331
+ const copying = React35.useRef(false);
20332
+ React35.useEffect(() => {
19911
20333
  mounted.current = true;
19912
20334
  return () => {
19913
20335
  mounted.current = false;
@@ -19939,7 +20361,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
19939
20361
  { className: "dim-updateManual", "aria-label": "\u624B\u5DE5\u66F4\u65B0" },
19940
20362
  h2("h4", { className: "dim-updateManualHeading" }, "\u624B\u5DE5\u66F4\u65B0"),
19941
20363
  command ? h2(
19942
- React34.Fragment,
20364
+ React35.Fragment,
19943
20365
  null,
19944
20366
  h2("p", { className: "dim-updateManualHint" }, "\u81EA\u52A8\u66F4\u65B0\u5931\u8D25\u53EF\u4EE5\u4F7F\u7528\u547D\u4EE4\u66F4\u65B0\uFF1A"),
19945
20367
  h2(
@@ -19975,7 +20397,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
19975
20397
  "aria-hidden": "true",
19976
20398
  focusable: "false"
19977
20399
  }, copyState === "copied" ? h2("path", { d: "m4 10 4 4 8-8" }) : h2(
19978
- React34.Fragment,
20400
+ React35.Fragment,
19979
20401
  null,
19980
20402
  h2("rect", { x: 7, y: 7, width: 10, height: 11, rx: 1.5 }),
19981
20403
  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" })
@@ -20000,10 +20422,10 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
20000
20422
  );
20001
20423
  }
20002
20424
  function UpdateDialog({ children, onClose }) {
20003
- const dialogRef = React34.useRef(null);
20004
- const titleId = React34.useId();
20005
- const descriptionId = React34.useId();
20006
- React34.useEffect(() => {
20425
+ const dialogRef = React35.useRef(null);
20426
+ const titleId = React35.useId();
20427
+ const descriptionId = React35.useId();
20428
+ React35.useEffect(() => {
20007
20429
  const previous = globalThis.document?.activeElement;
20008
20430
  dialogRef.current?.focus?.();
20009
20431
  return () => {
@@ -20061,20 +20483,20 @@ function UpdateDialog({ children, onClose }) {
20061
20483
  return typeof document !== "undefined" && document.body ? (0, import_react_dom4.createPortal)(content, document.body) : content;
20062
20484
  }
20063
20485
  function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20064
- const tooltipId = React34.useId();
20065
- const [snapshot, setSnapshot] = React34.useState(null);
20066
- const [action, setAction] = React34.useState("status");
20067
- const [error, setError] = React34.useState(null);
20068
- const [open, setOpen] = React34.useState(false);
20069
- const [uncertainInstall, setUncertainInstall] = React34.useState(false);
20070
- const mounted = React34.useRef(false);
20071
- const busy = React34.useRef(false);
20072
- const readController = React34.useRef(null);
20073
- const pollReadController = React34.useRef(null);
20074
- const installRequest = React34.useRef(null);
20075
- const onStatusRef = React34.useRef(onStatus);
20486
+ const tooltipId = React35.useId();
20487
+ const [snapshot, setSnapshot] = React35.useState(null);
20488
+ const [action, setAction] = React35.useState("status");
20489
+ const [error, setError] = React35.useState(null);
20490
+ const [open, setOpen] = React35.useState(false);
20491
+ const [uncertainInstall, setUncertainInstall] = React35.useState(false);
20492
+ const mounted = React35.useRef(false);
20493
+ const busy = React35.useRef(false);
20494
+ const readController = React35.useRef(null);
20495
+ const pollReadController = React35.useRef(null);
20496
+ const installRequest = React35.useRef(null);
20497
+ const onStatusRef = React35.useRef(onStatus);
20076
20498
  onStatusRef.current = onStatus;
20077
- const accept = React34.useCallback((next) => {
20499
+ const accept = React35.useCallback((next) => {
20078
20500
  setSnapshot(next);
20079
20501
  onStatusRef.current?.(next);
20080
20502
  }, []);
@@ -20083,7 +20505,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20083
20505
  setUncertainInstall(false);
20084
20506
  accept(next);
20085
20507
  };
20086
- const invoke = React34.useCallback(async (endpoint, payload = {}, signal) => {
20508
+ const invoke = React35.useCallback(async (endpoint, payload = {}, signal) => {
20087
20509
  if (typeof rpcCall !== "function") {
20088
20510
  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");
20089
20511
  unavailable.code = "update-unavailable";
@@ -20091,7 +20513,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20091
20513
  }
20092
20514
  return unwrapSnapshot(await rpcCall(endpoint, payload, signal));
20093
20515
  }, [rpcCall]);
20094
- React34.useEffect(() => {
20516
+ React35.useEffect(() => {
20095
20517
  mounted.current = true;
20096
20518
  busy.current = true;
20097
20519
  const controller = new AbortController();
@@ -20114,7 +20536,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20114
20536
  const activeJob = ACTIVE_STATES4.has(snapshot?.job?.state);
20115
20537
  const restartRequired = snapshot?.job?.state === "restart-required" || snapshot?.blockedReason === "pending-restart";
20116
20538
  const shouldPoll = activeJob || uncertainInstall;
20117
- React34.useEffect(() => {
20539
+ React35.useEffect(() => {
20118
20540
  if (!shouldPoll) return void 0;
20119
20541
  let controller;
20120
20542
  const scheduler = createPollScheduler({
@@ -20215,7 +20637,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20215
20637
  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";
20216
20638
  const buttonDescription = localizeText(buttonLabel) + (buttonLabel === "\u66F4\u65B0\u81F3" ? ` v${snapshot.latestVersion}` : "");
20217
20639
  return h2(
20218
- React34.Fragment,
20640
+ React35.Fragment,
20219
20641
  null,
20220
20642
  h2(
20221
20643
  "span",
@@ -20265,25 +20687,25 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20265
20687
  h2("dt", null, "\u8FD0\u884C\u7248\u672C"),
20266
20688
  h2("dd", null, `v${snapshot?.runningVersion ?? clientVersion}`),
20267
20689
  snapshot?.installedVersion && snapshot.installedVersion !== snapshot.runningVersion ? h2(
20268
- React34.Fragment,
20690
+ React35.Fragment,
20269
20691
  null,
20270
20692
  h2("dt", null, "\u5DF2\u5B89\u88C5\u7248\u672C"),
20271
20693
  h2("dd", null, `v${snapshot.installedVersion}`)
20272
20694
  ) : null,
20273
20695
  targetVersion ? h2(
20274
- React34.Fragment,
20696
+ React35.Fragment,
20275
20697
  null,
20276
20698
  h2("dt", null, "\u76EE\u6807\u7248\u672C"),
20277
20699
  h2("dd", null, `v${targetVersion}`)
20278
20700
  ) : null,
20279
20701
  latestVersion ? h2(
20280
- React34.Fragment,
20702
+ React35.Fragment,
20281
20703
  null,
20282
20704
  h2("dt", null, "\u6700\u65B0\u7248\u672C"),
20283
20705
  h2("dd", null, `v${latestVersion}`)
20284
20706
  ) : null,
20285
20707
  historicalTargetVersion ? h2(
20286
- React34.Fragment,
20708
+ React35.Fragment,
20287
20709
  null,
20288
20710
  h2("dt", null, "\u4E0A\u6B21\u66F4\u65B0\u76EE\u6807"),
20289
20711
  h2("dd", null, `v${historicalTargetVersion}`)
@@ -20365,8 +20787,8 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20365
20787
  }
20366
20788
 
20367
20789
  // plugin-src/client/panel-error-boundary.js
20368
- var React35 = __toESM(require("react"), 1);
20369
- var IMPanelErrorBoundary = class extends React35.Component {
20790
+ var React36 = __toESM(require("react"), 1);
20791
+ var IMPanelErrorBoundary = class extends React36.Component {
20370
20792
  state = { failed: false };
20371
20793
  static getDerivedStateFromError() {
20372
20794
  return { failed: true };
@@ -20559,28 +20981,28 @@ function IMSettingsTab({
20559
20981
  browserLocation = globalThis.location,
20560
20982
  navigateToRecoveryUrl = replacePageLocation
20561
20983
  }) {
20562
- const [selected, setSelected] = React36.useState(() => preferredSectionId === GLOBAL_SETTINGS_TAB_ID || CHANNELS.some((channel7) => channel7.id === preferredSectionId) ? preferredSectionId : "weixin");
20563
- const [loopbackRecovery, setLoopbackRecovery] = React36.useState(null);
20564
- const [runningVersion, setRunningVersion] = React36.useState(IM_PLUGIN_VERSION);
20565
- const [deliverySettings, setDeliverySettings] = React36.useState(null);
20984
+ const [selected, setSelected] = React37.useState(() => preferredSectionId === GLOBAL_SETTINGS_TAB_ID || CHANNELS.some((channel7) => channel7.id === preferredSectionId) ? preferredSectionId : "weixin");
20985
+ const [loopbackRecovery, setLoopbackRecovery] = React37.useState(null);
20986
+ const [runningVersion, setRunningVersion] = React37.useState(IM_PLUGIN_VERSION);
20987
+ const [deliverySettings, setDeliverySettings] = React37.useState(null);
20566
20988
  const emailEnabled = useEmailChannelEnabled(emailRpcCall);
20567
- const visibleChannels = React36.useMemo(
20989
+ const visibleChannels = React37.useMemo(
20568
20990
  () => CHANNELS.filter((channel7) => channel7.id !== "email" || emailEnabled),
20569
20991
  [emailEnabled]
20570
20992
  );
20571
- const githubTooltipId = React36.useId();
20572
- const generalSettingsTooltipId = React36.useId();
20993
+ const githubTooltipId = React37.useId();
20994
+ const generalSettingsTooltipId = React37.useId();
20573
20995
  const globalSettingsSelected = selected === GLOBAL_SETTINGS_TAB_ID;
20574
20996
  const active = visibleChannels.find((channel7) => channel7.id === selected) ?? visibleChannels[0];
20575
20997
  const activeTabId = globalSettingsSelected ? "dim-general-settings-trigger" : `dim-tab-${active.id}`;
20576
20998
  const activePanelId = globalSettingsSelected ? `dim-panel-${GLOBAL_SETTINGS_TAB_ID}` : `dim-panel-${active.id}`;
20577
- const reportLoopbackRecovery = React36.useCallback((recovery) => {
20999
+ const reportLoopbackRecovery = React37.useCallback((recovery) => {
20578
21000
  setLoopbackRecovery((current) => current?.url === recovery.url ? current : recovery);
20579
21001
  }, []);
20580
- const reportUpdateStatus = React36.useCallback((snapshot) => {
21002
+ const reportUpdateStatus = React37.useCallback((snapshot) => {
20581
21003
  setRunningVersion(snapshot.runningVersion);
20582
21004
  }, []);
20583
- const rpcCalls = React36.useMemo(() => createLoopbackAwareRpcCalls({
21005
+ const rpcCalls = React37.useMemo(() => createLoopbackAwareRpcCalls({
20584
21006
  dingtalkRpcCall,
20585
21007
  discordRpcCall,
20586
21008
  feishuRpcCall,
@@ -20622,7 +21044,7 @@ function IMSettingsTab({
20622
21044
  weixinRpcCall,
20623
21045
  whatsappRpcCall
20624
21046
  ]);
20625
- const botSettingsContext = React36.useMemo(() => Object.freeze({
21047
+ const botSettingsContext = React37.useMemo(() => Object.freeze({
20626
21048
  openBotSettings: setDeliverySettings
20627
21049
  }), []);
20628
21050
  return h2(
@@ -20846,7 +21268,7 @@ function apply(ctx) {
20846
21268
  };
20847
21269
  const localeSnapshot = () => ctx.locale.getLocale?.()?.active ?? "";
20848
21270
  function IMPanel({ preferredSectionId }) {
20849
- React36.useSyncExternalStore(subscribeLocale, localeSnapshot, localeSnapshot);
21271
+ React37.useSyncExternalStore(subscribeLocale, localeSnapshot, localeSnapshot);
20850
21272
  return h2(
20851
21273
  IMPanelErrorBoundary,
20852
21274
  null,