@xmanrui/dsh-im 4.29.1 → 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,12 @@ 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.1",
598
+ version: "4.30.0",
599
599
  icon: "./assets/logo-plugin-message-link-gradient.webp",
600
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.",
601
601
  keywords: [
@@ -1472,12 +1472,42 @@ var EN = Object.freeze({
1472
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.",
1473
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.",
1474
1474
  "\u7FA4\u6D88\u606F\u6743\u9650\u6388\u6743\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002": "Could not authorize group-message permission. Try again.",
1475
- "\u7FA4\u804A\u4EE5\u8BDD\u9898\u65B9\u5F0F\u56DE\u590D": "Reply to group chats as Feishu topics",
1476
- "\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.",
1477
- "\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)",
1478
1478
  "\u5F00\u542F\uFF08\u81EA\u52A8\u5F00\u542F\u72EC\u7ACB\u98DE\u4E66\u8BDD\u9898\uFF09": "On (auto-open a dedicated Feishu topic)",
1479
- "\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.`,
1480
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.",
1481
1511
  "\u67E5\u770B\u5206\u6B65\u76F4\u63A8\u8BF4\u660E": "View step push help",
1482
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",
1483
1513
  "\u4EFB\u52A1\u8FC7\u7A0B\u5C55\u793A": "Task progress display",
@@ -1561,7 +1591,6 @@ var EN = Object.freeze({
1561
1591
  "\u5DE5\u4F5C\u533A\u7EDD\u5BF9\u8DEF\u5F84": "Absolute workspace path",
1562
1592
  "/\u7EDD\u5BF9\u8DEF\u5F84/\u5230/\u5DE5\u4F5C\u533A": "/absolute/path/to/workspace",
1563
1593
  "\u4FEE\u6539": "Change",
1564
- "\u4FDD\u5B58": "Save",
1565
1594
  "\u4E0A\u4E0B\u6587\u589E\u5F3A": "Context enhancement",
1566
1595
  "\u672A\u5F00\u542F": "Not enabled",
1567
1596
  "\u4EC5\u7FA4\u804A": "Groups only",
@@ -7242,6 +7271,74 @@ function normalizeFeishuVoiceConfig(value) {
7242
7271
  });
7243
7272
  }
7244
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
+
7245
7342
  // plugin-src/client/channels/feishu/api.js
7246
7343
  var FEISHU_RPC_CHANNEL = "/feishu";
7247
7344
  var FEISHU_ENDPOINTS = Object.freeze({
@@ -7262,10 +7359,11 @@ var FEISHU_ENDPOINTS = Object.freeze({
7262
7359
  setAccessPolicy: "bot.access-policy.set",
7263
7360
  setAlias: "bot.alias.set",
7264
7361
  setGroupResponseMode: "bot.group-response-mode.set",
7265
- setGroupTopicReply: "bot.group-topic-reply.set",
7362
+ setMentionTopicReply: "bot.mention-topic-reply.set",
7266
7363
  setStepPush: "bot.step-push.set",
7267
7364
  setStepPushMode: "bot.step-push-mode.set",
7268
7365
  setVoice: "bot.voice.set",
7366
+ setSlashPanel: "bot.slash-panel.set",
7269
7367
  // Kept for rolling upgrades. The multi-bot UI never calls these endpoints.
7270
7368
  testConnection: "connection.test",
7271
7369
  disconnect: "connection.disconnect"
@@ -7419,10 +7517,11 @@ function normalizeBotConnection(value, fallbackBotId) {
7419
7517
  contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
7420
7518
  ...Object.hasOwn(value, "accessPolicy") ? { accessPolicy: normalizeAccessPolicy(value.accessPolicy) } : {},
7421
7519
  groupResponseMode: normalizeGroupResponseMode(value.groupResponseMode),
7422
- groupTopicReply: value.groupTopicReply === true,
7520
+ mentionTopicReply: value.mentionTopicReply !== false,
7423
7521
  stepPush: value.stepPush === true,
7424
7522
  stepPushMode: normalizeFeishuStepPushMode(value.stepPushMode),
7425
7523
  voice: normalizeFeishuVoiceConfig(value.voice),
7524
+ slashPanel: normalizeSlashPanelConfig(value.slashPanel),
7426
7525
  groupMessagePermissionGranted: value.groupMessagePermissionGranted === true,
7427
7526
  bot: normalizeBot2(value.bot),
7428
7527
  health: normalizeHealth(value.health, connected),
@@ -8130,7 +8229,8 @@ function BotCard({
8130
8229
  accessPolicy: connection.accessPolicy,
8131
8230
  channelSettings: {
8132
8231
  groupResponseMode: connection.groupResponseMode,
8133
- groupTopicReply: connection.groupTopicReply,
8232
+ mentionTopicReply: connection.mentionTopicReply,
8233
+ slashPanel: connection.slashPanel,
8134
8234
  groupMessagePermissionGranted: connection.groupMessagePermissionGranted
8135
8235
  }
8136
8236
  }),
@@ -16121,7 +16221,7 @@ function installInterfaceLanguageMirror(ctx, {
16121
16221
  }
16122
16222
 
16123
16223
  // plugin-src/client/delivery-settings.js
16124
- var React32 = __toESM(require("react"), 1);
16224
+ var React33 = __toESM(require("react"), 1);
16125
16225
 
16126
16226
  // plugin-src/client/access-policy-settings.js
16127
16227
  var React28 = __toESM(require("react"), 1);
@@ -16544,7 +16644,7 @@ function SettingsButton({ children, kind = "secondary", className = "", ...props
16544
16644
  function groupSettingsFrom(value) {
16545
16645
  return {
16546
16646
  groupResponseMode: normalizeGroupResponseMode(value?.groupResponseMode),
16547
- groupTopicReply: value?.groupTopicReply === true,
16647
+ mentionTopicReply: value?.mentionTopicReply !== false,
16548
16648
  groupMessagePermissionGranted: value?.groupMessagePermissionGranted === true
16549
16649
  };
16550
16650
  }
@@ -16673,7 +16773,7 @@ function GroupResponseModeEditor({
16673
16773
  }, error) : null
16674
16774
  );
16675
16775
  }
16676
- function GroupTopicReplyEditor({ value = false, disabled = false, onSave }) {
16776
+ function MentionTopicReplyEditor({ value = true, disabled = false, onSave }) {
16677
16777
  const current = value === true ? "on" : "off";
16678
16778
  const [saving, setSaving] = React29.useState(false);
16679
16779
  const [error, setError] = React29.useState(null);
@@ -16685,7 +16785,7 @@ function GroupTopicReplyEditor({ value = false, disabled = false, onSave }) {
16685
16785
  try {
16686
16786
  await onSave?.(next);
16687
16787
  } catch (cause) {
16688
- 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");
16689
16789
  } finally {
16690
16790
  setSaving(false);
16691
16791
  }
@@ -16694,12 +16794,12 @@ function GroupTopicReplyEditor({ value = false, disabled = false, onSave }) {
16694
16794
  "section",
16695
16795
  {
16696
16796
  className: "dim-feishuGroupControl",
16697
- "aria-labelledby": "dim-feishu-group-topic-title"
16797
+ "aria-labelledby": "dim-feishu-mention-topic-title"
16698
16798
  },
16699
16799
  h2(
16700
16800
  "div",
16701
16801
  { className: "dim-feishuGroupControlHeader" },
16702
- 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"),
16703
16803
  saving ? h2("span", { className: "dim-feishuGroupControlStatus", role: "status" }, "\u4FDD\u5B58\u4E2D\u2026") : null
16704
16804
  ),
16705
16805
  h2(
@@ -16708,18 +16808,18 @@ function GroupTopicReplyEditor({ value = false, disabled = false, onSave }) {
16708
16808
  className: "dim-feishuGroupSelect",
16709
16809
  value: current,
16710
16810
  disabled: disabled || saving,
16711
- "aria-label": "\u7FA4\u804A\u4EE5\u8BDD\u9898\u65B9\u5F0F\u56DE\u590D",
16811
+ "aria-label": "\u88AB @ \u65F6\u4EE5\u8BDD\u9898\u65B9\u5F0F\u56DE\u590D",
16712
16812
  onChange: (event) => {
16713
16813
  void change(event);
16714
16814
  }
16715
16815
  },
16716
- 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"),
16717
16817
  h2("option", { value: "on" }, "\u5F00\u542F\uFF08\u81EA\u52A8\u5F00\u542F\u72EC\u7ACB\u98DE\u4E66\u8BDD\u9898\uFF09")
16718
16818
  ),
16719
16819
  h2(
16720
16820
  "p",
16721
16821
  { className: "dim-feishuGroupHelp" },
16722
- "\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"
16723
16823
  ),
16724
16824
  error ? h2("p", {
16725
16825
  className: "dim-feishuGroupError",
@@ -16875,7 +16975,7 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
16875
16975
  }, [
16876
16976
  account.botId,
16877
16977
  account.groupResponseMode,
16878
- account.groupTopicReply,
16978
+ account.mentionTopicReply,
16879
16979
  account.groupMessagePermissionGranted
16880
16980
  ]);
16881
16981
  React29.useEffect(() => {
@@ -17096,12 +17196,12 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
17096
17196
  },
17097
17197
  onAuthorize: () => startAuthorization()
17098
17198
  }),
17099
- h2(GroupTopicReplyEditor, {
17100
- value: settings.groupTopicReply,
17199
+ h2(MentionTopicReplyEditor, {
17200
+ value: settings.mentionTopicReply,
17101
17201
  disabled,
17102
- onSave: (groupTopicReply) => saveSetting(
17103
- FEISHU_ENDPOINTS.setGroupTopicReply,
17104
- { groupTopicReply }
17202
+ onSave: (mentionTopicReply) => saveSetting(
17203
+ FEISHU_ENDPOINTS.setMentionTopicReply,
17204
+ { mentionTopicReply }
17105
17205
  )
17106
17206
  })
17107
17207
  ),
@@ -17318,6 +17418,309 @@ function FeishuVoiceSettingsPage({ account, rpcCall }) {
17318
17418
  return h2(VoiceEditor, { value: voice, onSave: saveVoice });
17319
17419
  }
17320
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
+
17321
17724
  // plugin-src/client/delivery-settings.js
17322
17725
  var DELIVERY_RPC_CHANNEL = "/dsh-im-delivery";
17323
17726
  var DELIVERY_DOCS_URL = Object.freeze({
@@ -17340,6 +17743,7 @@ var BOT_SETTINGS_TABS = Object.freeze([
17340
17743
  var FEISHU_BOT_SETTINGS_TABS = Object.freeze([
17341
17744
  ...BOT_SETTINGS_TABS,
17342
17745
  Object.freeze({ id: "group", label: "\u7FA4\u804A" }),
17746
+ Object.freeze({ id: "slash", label: "\u6307\u4EE4\u9762\u677F" }),
17343
17747
  Object.freeze({ id: "voice", label: "\u8BED\u97F3\u4EA4\u4E92" })
17344
17748
  ]);
17345
17749
  function botSettingsTabsForChannel(channel7) {
@@ -17552,13 +17956,13 @@ function TargetForm({
17552
17956
  }) {
17553
17957
  const editing = mode === "edit";
17554
17958
  const initialKind = initialValue?.kind && definition.fields[initialValue.kind] ? initialValue.kind : definition.kinds[0].value;
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);
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);
17562
17966
  const currentTarget = () => {
17563
17967
  const normalizedRoute = Object.fromEntries(fieldsFor(definition, kind).map((field2) => {
17564
17968
  const raw = String(route[field2.key] ?? "").trim();
@@ -17775,7 +18179,7 @@ function TargetSuggestionPicker({
17775
18179
  suggestions.map((suggestion, index) => {
17776
18180
  const identity = routeIdentity(definition, suggestion);
17777
18181
  const added = configured.has(identity);
17778
- return React32.createElement("option", {
18182
+ return React33.createElement("option", {
17779
18183
  key: suggestion.id ?? suggestion.suggestionId ?? `${identity}:${index}`,
17780
18184
  value: String(index),
17781
18185
  disabled: added
@@ -17792,11 +18196,11 @@ function TargetSuggestionPicker({
17792
18196
  );
17793
18197
  }
17794
18198
  function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, onEdit }) {
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);
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);
17800
18204
  const sessionSync = target.sessionSync ?? { enabled: false, state: "unavailable" };
17801
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";
17802
18206
  const testTarget = async () => {
@@ -17859,7 +18263,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
17859
18263
  h2(
17860
18264
  "div",
17861
18265
  { className: "dim-targetTitle" },
17862
- React32.createElement("strong", null, target.name || target.targetId),
18266
+ React33.createElement("strong", null, target.name || target.targetId),
17863
18267
  h2("span", null, kindLabel(definition, target.kind))
17864
18268
  ),
17865
18269
  h2("code", null, `targetId: ${target.targetId}`)
@@ -17945,26 +18349,30 @@ function DeliveryTargetSettingsPage({
17945
18349
  onBack
17946
18350
  }) {
17947
18351
  const definition = CHANNEL_DEFINITIONS[channel7];
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(() => {
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(() => {
17961
18366
  setAccessPolicy(account.accessPolicy);
17962
18367
  }, [account.botId, account.accessPolicy]);
17963
- 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) => {
17964
18372
  if (typeof rpcCall !== "function") throw new Error("\u6295\u9012\u76EE\u6807\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
17965
18373
  return unwrapRpcResult15(await rpcCall(endpoint, payload, signal));
17966
18374
  }, [rpcCall]);
17967
- const loadTargets = React32.useCallback(async ({ signal, silent = false } = {}) => {
18375
+ const loadTargets = React33.useCallback(async ({ signal, silent = false } = {}) => {
17968
18376
  if (!silent) setPhase("loading");
17969
18377
  setError(null);
17970
18378
  try {
@@ -17978,7 +18386,7 @@ function DeliveryTargetSettingsPage({
17978
18386
  setPhase("error");
17979
18387
  }
17980
18388
  }, [account.botId, invoke]);
17981
- const loadSuggestions = React32.useCallback(async () => {
18389
+ const loadSuggestions = React33.useCallback(async () => {
17982
18390
  setSuggestionPhase("loading");
17983
18391
  setSuggestionError(null);
17984
18392
  try {
@@ -17992,7 +18400,7 @@ function DeliveryTargetSettingsPage({
17992
18400
  setSuggestionPhase("error");
17993
18401
  }
17994
18402
  }, [account.botId, definition, invoke]);
17995
- React32.useEffect(() => {
18403
+ React33.useEffect(() => {
17996
18404
  mounted.current = true;
17997
18405
  const controller = new AbortController();
17998
18406
  void loadTargets({ signal: controller.signal });
@@ -18113,12 +18521,16 @@ function DeliveryTargetSettingsPage({
18113
18521
  }) : activeTab.id === "group" && channel7 === "feishu" ? h2(FeishuGroupSettingsPage, {
18114
18522
  account,
18115
18523
  rpcCall: accessRpcCall
18524
+ }) : activeTab.id === "slash" && channel7 === "feishu" ? h2(FeishuSlashPanelSettingsPage, {
18525
+ account: { ...account, slashPanel },
18526
+ rpcCall: accessRpcCall,
18527
+ onSaved: setSlashPanel
18116
18528
  }) : activeTab.id === "voice" && channel7 === "feishu" ? h2(FeishuVoiceSettingsPage, {
18117
18529
  key: account.botId,
18118
18530
  account,
18119
18531
  rpcCall: accessRpcCall
18120
18532
  }) : h2(
18121
- React32.Fragment,
18533
+ React33.Fragment,
18122
18534
  null,
18123
18535
  h2(
18124
18536
  "section",
@@ -18229,7 +18641,7 @@ function DeliveryTargetSettingsPage({
18229
18641
  }
18230
18642
 
18231
18643
  // plugin-src/client/global-settings.js
18232
- var React33 = __toESM(require("react"), 1);
18644
+ var React34 = __toESM(require("react"), 1);
18233
18645
 
18234
18646
  // src/channels/shared/inbound-ttl.mjs
18235
18647
  var DEFAULT_INBOUND_TTL_HOURS = 168;
@@ -18314,14 +18726,14 @@ function GlobalButton({ children, kind = "secondary", className = "", ...props }
18314
18726
  }, children);
18315
18727
  }
18316
18728
  function ImageInputSettings({ rpcCall }) {
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) => {
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) => {
18325
18737
  setPhase("loading");
18326
18738
  setError(null);
18327
18739
  try {
@@ -18337,7 +18749,7 @@ function ImageInputSettings({ rpcCall }) {
18337
18749
  setPhase("error");
18338
18750
  }
18339
18751
  }, [rpcCall]);
18340
- React33.useEffect(() => {
18752
+ React34.useEffect(() => {
18341
18753
  mounted.current = true;
18342
18754
  const controller = new AbortController();
18343
18755
  void load(controller.signal);
@@ -18444,29 +18856,29 @@ function ImageInputSettings({ rpcCall }) {
18444
18856
  );
18445
18857
  }
18446
18858
  function GlobalSettingsPanel({ rpcCall }) {
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) => {
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) => {
18466
18878
  if (typeof rpcCall !== "function") throw new Error("\u901A\u7528\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
18467
18879
  return unwrapRpcResult16(await rpcCall(endpoint, payload, signal));
18468
18880
  }, [rpcCall]);
18469
- const loadSettings = React33.useCallback(async ({ signal } = {}) => {
18881
+ const loadSettings = React34.useCallback(async ({ signal } = {}) => {
18470
18882
  setPhase("loading");
18471
18883
  setLoadError(null);
18472
18884
  try {
@@ -18490,7 +18902,7 @@ function GlobalSettingsPanel({ rpcCall }) {
18490
18902
  setPhase("error");
18491
18903
  }
18492
18904
  }, [invoke]);
18493
- React33.useEffect(() => {
18905
+ React34.useEffect(() => {
18494
18906
  mounted.current = true;
18495
18907
  const controller = new AbortController();
18496
18908
  void loadSettings({ signal: controller.signal });
@@ -18499,7 +18911,7 @@ function GlobalSettingsPanel({ rpcCall }) {
18499
18911
  controller.abort();
18500
18912
  };
18501
18913
  }, [loadSettings]);
18502
- React33.useEffect(() => {
18914
+ React34.useEffect(() => {
18503
18915
  if (!sweepConfirming) return;
18504
18916
  globalThis.document?.getElementById(sweepConfirmButtonId)?.focus();
18505
18917
  }, [sweepConfirmButtonId, sweepConfirming]);
@@ -19301,6 +19713,15 @@ var CSS15 = String.raw`
19301
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)); }
19302
19714
  .dim-feishuGroupError, .dim-feishuGroupRefreshError { margin: 0; padding: 9px 11px; border-radius: 8px; font-size: 12px; line-height: 18px; }
19303
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; }
19304
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)); }
19305
19726
  .dim-feishuGroupAuthorizationState { min-height: 126px; grid-template-columns: 32px minmax(0, 1fr); align-items: center; }
19306
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; }
@@ -19811,7 +20232,7 @@ function installSessionChannelLogos(document2 = globalThis.document) {
19811
20232
  }
19812
20233
 
19813
20234
  // plugin-src/client/update-panel.js
19814
- var React34 = __toESM(require("react"), 1);
20235
+ var React35 = __toESM(require("react"), 1);
19815
20236
  var import_react_dom4 = require("react-dom");
19816
20237
  var import_valid = __toESM(require_valid(), 1);
19817
20238
  var import_rcompare = __toESM(require_rcompare(), 1);
@@ -19904,11 +20325,11 @@ function manualUpdateCommand(snapshot) {
19904
20325
  return `dsh plugin --profile ${profileArgument} add -w @xmanrui/dsh-im@${version}`;
19905
20326
  }
19906
20327
  function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
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(() => {
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(() => {
19912
20333
  mounted.current = true;
19913
20334
  return () => {
19914
20335
  mounted.current = false;
@@ -19940,7 +20361,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
19940
20361
  { className: "dim-updateManual", "aria-label": "\u624B\u5DE5\u66F4\u65B0" },
19941
20362
  h2("h4", { className: "dim-updateManualHeading" }, "\u624B\u5DE5\u66F4\u65B0"),
19942
20363
  command ? h2(
19943
- React34.Fragment,
20364
+ React35.Fragment,
19944
20365
  null,
19945
20366
  h2("p", { className: "dim-updateManualHint" }, "\u81EA\u52A8\u66F4\u65B0\u5931\u8D25\u53EF\u4EE5\u4F7F\u7528\u547D\u4EE4\u66F4\u65B0\uFF1A"),
19946
20367
  h2(
@@ -19976,7 +20397,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
19976
20397
  "aria-hidden": "true",
19977
20398
  focusable: "false"
19978
20399
  }, copyState === "copied" ? h2("path", { d: "m4 10 4 4 8-8" }) : h2(
19979
- React34.Fragment,
20400
+ React35.Fragment,
19980
20401
  null,
19981
20402
  h2("rect", { x: 7, y: 7, width: 10, height: 11, rx: 1.5 }),
19982
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" })
@@ -20001,10 +20422,10 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
20001
20422
  );
20002
20423
  }
20003
20424
  function UpdateDialog({ children, onClose }) {
20004
- const dialogRef = React34.useRef(null);
20005
- const titleId = React34.useId();
20006
- const descriptionId = React34.useId();
20007
- React34.useEffect(() => {
20425
+ const dialogRef = React35.useRef(null);
20426
+ const titleId = React35.useId();
20427
+ const descriptionId = React35.useId();
20428
+ React35.useEffect(() => {
20008
20429
  const previous = globalThis.document?.activeElement;
20009
20430
  dialogRef.current?.focus?.();
20010
20431
  return () => {
@@ -20062,20 +20483,20 @@ function UpdateDialog({ children, onClose }) {
20062
20483
  return typeof document !== "undefined" && document.body ? (0, import_react_dom4.createPortal)(content, document.body) : content;
20063
20484
  }
20064
20485
  function UpdatePanel({ rpcCall, clientVersion, 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);
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);
20077
20498
  onStatusRef.current = onStatus;
20078
- const accept = React34.useCallback((next) => {
20499
+ const accept = React35.useCallback((next) => {
20079
20500
  setSnapshot(next);
20080
20501
  onStatusRef.current?.(next);
20081
20502
  }, []);
@@ -20084,7 +20505,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20084
20505
  setUncertainInstall(false);
20085
20506
  accept(next);
20086
20507
  };
20087
- const invoke = React34.useCallback(async (endpoint, payload = {}, signal) => {
20508
+ const invoke = React35.useCallback(async (endpoint, payload = {}, signal) => {
20088
20509
  if (typeof rpcCall !== "function") {
20089
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");
20090
20511
  unavailable.code = "update-unavailable";
@@ -20092,7 +20513,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20092
20513
  }
20093
20514
  return unwrapSnapshot(await rpcCall(endpoint, payload, signal));
20094
20515
  }, [rpcCall]);
20095
- React34.useEffect(() => {
20516
+ React35.useEffect(() => {
20096
20517
  mounted.current = true;
20097
20518
  busy.current = true;
20098
20519
  const controller = new AbortController();
@@ -20115,7 +20536,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20115
20536
  const activeJob = ACTIVE_STATES4.has(snapshot?.job?.state);
20116
20537
  const restartRequired = snapshot?.job?.state === "restart-required" || snapshot?.blockedReason === "pending-restart";
20117
20538
  const shouldPoll = activeJob || uncertainInstall;
20118
- React34.useEffect(() => {
20539
+ React35.useEffect(() => {
20119
20540
  if (!shouldPoll) return void 0;
20120
20541
  let controller;
20121
20542
  const scheduler = createPollScheduler({
@@ -20216,7 +20637,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20216
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";
20217
20638
  const buttonDescription = localizeText(buttonLabel) + (buttonLabel === "\u66F4\u65B0\u81F3" ? ` v${snapshot.latestVersion}` : "");
20218
20639
  return h2(
20219
- React34.Fragment,
20640
+ React35.Fragment,
20220
20641
  null,
20221
20642
  h2(
20222
20643
  "span",
@@ -20266,25 +20687,25 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20266
20687
  h2("dt", null, "\u8FD0\u884C\u7248\u672C"),
20267
20688
  h2("dd", null, `v${snapshot?.runningVersion ?? clientVersion}`),
20268
20689
  snapshot?.installedVersion && snapshot.installedVersion !== snapshot.runningVersion ? h2(
20269
- React34.Fragment,
20690
+ React35.Fragment,
20270
20691
  null,
20271
20692
  h2("dt", null, "\u5DF2\u5B89\u88C5\u7248\u672C"),
20272
20693
  h2("dd", null, `v${snapshot.installedVersion}`)
20273
20694
  ) : null,
20274
20695
  targetVersion ? h2(
20275
- React34.Fragment,
20696
+ React35.Fragment,
20276
20697
  null,
20277
20698
  h2("dt", null, "\u76EE\u6807\u7248\u672C"),
20278
20699
  h2("dd", null, `v${targetVersion}`)
20279
20700
  ) : null,
20280
20701
  latestVersion ? h2(
20281
- React34.Fragment,
20702
+ React35.Fragment,
20282
20703
  null,
20283
20704
  h2("dt", null, "\u6700\u65B0\u7248\u672C"),
20284
20705
  h2("dd", null, `v${latestVersion}`)
20285
20706
  ) : null,
20286
20707
  historicalTargetVersion ? h2(
20287
- React34.Fragment,
20708
+ React35.Fragment,
20288
20709
  null,
20289
20710
  h2("dt", null, "\u4E0A\u6B21\u66F4\u65B0\u76EE\u6807"),
20290
20711
  h2("dd", null, `v${historicalTargetVersion}`)
@@ -20366,8 +20787,8 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20366
20787
  }
20367
20788
 
20368
20789
  // plugin-src/client/panel-error-boundary.js
20369
- var React35 = __toESM(require("react"), 1);
20370
- var IMPanelErrorBoundary = class extends React35.Component {
20790
+ var React36 = __toESM(require("react"), 1);
20791
+ var IMPanelErrorBoundary = class extends React36.Component {
20371
20792
  state = { failed: false };
20372
20793
  static getDerivedStateFromError() {
20373
20794
  return { failed: true };
@@ -20560,28 +20981,28 @@ function IMSettingsTab({
20560
20981
  browserLocation = globalThis.location,
20561
20982
  navigateToRecoveryUrl = replacePageLocation
20562
20983
  }) {
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);
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);
20567
20988
  const emailEnabled = useEmailChannelEnabled(emailRpcCall);
20568
- const visibleChannels = React36.useMemo(
20989
+ const visibleChannels = React37.useMemo(
20569
20990
  () => CHANNELS.filter((channel7) => channel7.id !== "email" || emailEnabled),
20570
20991
  [emailEnabled]
20571
20992
  );
20572
- const githubTooltipId = React36.useId();
20573
- const generalSettingsTooltipId = React36.useId();
20993
+ const githubTooltipId = React37.useId();
20994
+ const generalSettingsTooltipId = React37.useId();
20574
20995
  const globalSettingsSelected = selected === GLOBAL_SETTINGS_TAB_ID;
20575
20996
  const active = visibleChannels.find((channel7) => channel7.id === selected) ?? visibleChannels[0];
20576
20997
  const activeTabId = globalSettingsSelected ? "dim-general-settings-trigger" : `dim-tab-${active.id}`;
20577
20998
  const activePanelId = globalSettingsSelected ? `dim-panel-${GLOBAL_SETTINGS_TAB_ID}` : `dim-panel-${active.id}`;
20578
- const reportLoopbackRecovery = React36.useCallback((recovery) => {
20999
+ const reportLoopbackRecovery = React37.useCallback((recovery) => {
20579
21000
  setLoopbackRecovery((current) => current?.url === recovery.url ? current : recovery);
20580
21001
  }, []);
20581
- const reportUpdateStatus = React36.useCallback((snapshot) => {
21002
+ const reportUpdateStatus = React37.useCallback((snapshot) => {
20582
21003
  setRunningVersion(snapshot.runningVersion);
20583
21004
  }, []);
20584
- const rpcCalls = React36.useMemo(() => createLoopbackAwareRpcCalls({
21005
+ const rpcCalls = React37.useMemo(() => createLoopbackAwareRpcCalls({
20585
21006
  dingtalkRpcCall,
20586
21007
  discordRpcCall,
20587
21008
  feishuRpcCall,
@@ -20623,7 +21044,7 @@ function IMSettingsTab({
20623
21044
  weixinRpcCall,
20624
21045
  whatsappRpcCall
20625
21046
  ]);
20626
- const botSettingsContext = React36.useMemo(() => Object.freeze({
21047
+ const botSettingsContext = React37.useMemo(() => Object.freeze({
20627
21048
  openBotSettings: setDeliverySettings
20628
21049
  }), []);
20629
21050
  return h2(
@@ -20847,7 +21268,7 @@ function apply(ctx) {
20847
21268
  };
20848
21269
  const localeSnapshot = () => ctx.locale.getLocale?.()?.active ?? "";
20849
21270
  function IMPanel({ preferredSectionId }) {
20850
- React36.useSyncExternalStore(subscribeLocale, localeSnapshot, localeSnapshot);
21271
+ React37.useSyncExternalStore(subscribeLocale, localeSnapshot, localeSnapshot);
20851
21272
  return h2(
20852
21273
  IMPanelErrorBoundary,
20853
21274
  null,