@xmanrui/dsh-im 4.29.1 → 4.31.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.31.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: [
@@ -685,6 +685,10 @@ var package_default = {
685
685
  {
686
686
  name: "Biertolovisk",
687
687
  url: "https://github.com/rosalynthompson32-a11y"
688
+ },
689
+ {
690
+ name: "Tianjun Cai",
691
+ url: "https://github.com/Pegasus02"
688
692
  }
689
693
  ],
690
694
  license: "MIT",
@@ -773,7 +777,7 @@ var package_default = {
773
777
  mailparser: "^3.9.28",
774
778
  nodemailer: "^10.0.10",
775
779
  qrcode: "1.5.4",
776
- undici: "7.29.0"
780
+ undici: "7.29.1"
777
781
  },
778
782
  devDependencies: {
779
783
  "@deepseek-ai/cordis": "4.0.1",
@@ -1472,12 +1476,42 @@ var EN = Object.freeze({
1472
1476
  "\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
1477
  "\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
1478
  "\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)",
1479
+ "\u88AB @ \u65F6\u4EE5\u8BDD\u9898\u65B9\u5F0F\u56DE\u590D": "Reply as a Feishu topic when mentioned",
1480
+ "\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.",
1481
+ "\u5173\u95ED\uFF08\u5728\u4F1A\u8BDD\u4E3B\u7A97\u53E3\u56DE\u590D\uFF09": "Off (reply in the chat feed)",
1478
1482
  "\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.",
1483
+ "\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
1484
  "\u5206\u6B65\u76F4\u63A8": "Step push",
1485
+ "\u6307\u4EE4\u9762\u677F": "Command panel",
1486
+ "\u4E2A\u5931\u8D25\u3002": "failed.",
1487
+ "\u4E2A\u673A\u5668\u4EBA\uFF0C": "bots,",
1488
+ "\u4E2A\u673A\u5668\u4EBA\u3002": "bots.",
1489
+ "\u5DF2\u540C\u6B65\u5230": "Copied to",
1490
+ "\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.",
1491
+ "\u6B63\u5728\u540C\u6B65\u2026": "Copying\u2026",
1492
+ "\u786E\u8BA4\u540C\u6B65": "Copy to all",
1493
+ "\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.",
1494
+ "\u5C06\u628A\u8FD9\u5957\u9762\u677F\u8BBE\u7F6E\u5199\u5165\u53E6\u5916": "This copies the panel to",
1495
+ "\u4FDD\u5B58\u5E76\u540C\u6B65\u5230\u5176\u4ED6\u673A\u5668\u4EBA": "Save and copy to the other bots",
1496
+ "\u6307\u4EE4\u9762\u677F\u8BBE\u7F6E": "Command panel settings",
1497
+ "\u6307\u4EE4\u9762\u677F\u6A21\u5F0F": "Command panel mode",
1498
+ "\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.',
1499
+ "\u8DDF\u968F\u9ED8\u8BA4\uFF08\u968F\u63D2\u4EF6\u7248\u672C\u66F4\u65B0\uFF09": "Follow the default (updated with the plugin)",
1500
+ "\u81EA\u5B9A\u4E49\uFF08\u81EA\u5DF1\u6311\u6307\u4EE4\u548C\u987A\u5E8F\uFF09": "Custom (choose the commands and their order)",
1501
+ "\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.',
1502
+ "\u6DFB\u52A0\u6307\u4EE4": "Add command",
1503
+ "\u9009\u62E9\u8981\u52A0\u5165\u7684\u6307\u4EE4": "Choose a command to add",
1504
+ "\u6307\u4EE4\u90FD\u5DF2\u52A0\u5165": "Every command is already listed",
1505
+ "\u52A0\u5165": "Add",
1506
+ "\u6062\u590D\u5168\u90E8": "Restore all",
1507
+ "\u5168\u90E8\u79FB\u9664": "Remove all",
1508
+ "\u79FB\u9664": "Remove",
1509
+ "\u4E0A\u79FB": "Move up",
1510
+ "\u4E0B\u79FB": "Move down",
1511
+ "\u4FDD\u5B58": "Save",
1512
+ "\u5DF2\u4FDD\u5B58\uFF0C\u9762\u677F\u7A0D\u540E\u540C\u6B65": "Saved; the panel syncs shortly",
1513
+ "\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.",
1514
+ "\u98DE\u4E66\u6307\u4EE4\u9762\u677F\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002": "The Feishu command panel settings are unavailable right now.",
1481
1515
  "\u67E5\u770B\u5206\u6B65\u76F4\u63A8\u8BF4\u660E": "View step push help",
1482
1516
  "\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
1517
  "\u4EFB\u52A1\u8FC7\u7A0B\u5C55\u793A": "Task progress display",
@@ -1561,7 +1595,6 @@ var EN = Object.freeze({
1561
1595
  "\u5DE5\u4F5C\u533A\u7EDD\u5BF9\u8DEF\u5F84": "Absolute workspace path",
1562
1596
  "/\u7EDD\u5BF9\u8DEF\u5F84/\u5230/\u5DE5\u4F5C\u533A": "/absolute/path/to/workspace",
1563
1597
  "\u4FEE\u6539": "Change",
1564
- "\u4FDD\u5B58": "Save",
1565
1598
  "\u4E0A\u4E0B\u6587\u589E\u5F3A": "Context enhancement",
1566
1599
  "\u672A\u5F00\u542F": "Not enabled",
1567
1600
  "\u4EC5\u7FA4\u804A": "Groups only",
@@ -1598,6 +1631,10 @@ var EN = Object.freeze({
1598
1631
  "\u67E5\u770B\u79C1\u804A\u8BDD\u9898\u6807\u8BC6\u5B57\u6BB5\u8BF4\u660E": "View direct topic ID field details",
1599
1632
  "\u8BE5\u5B57\u6BB5\u4E0D\u662F\u6BCF\u4E2A\u6E20\u9053\u90FD\u80FD\u63D0\u4F9B\u3002\u98DE\u4E66\u8BDD\u9898\u7FA4\u7684\u6D88\u606F\u4F1A\u5E26\u4E0A\u8BDD\u9898 ID\uFF0C\u7528\u4E8E\u533A\u5206\u540C\u4E00\u7FA4\u7EC4\u5185\u7684\u4E0D\u540C\u8BDD\u9898\uFF1B\u5F53\u524D\u6D88\u606F\u4E0D\u5728\u8BDD\u9898\u4E2D\u65F6\uFF0C\u5373\u4F7F\u5DF2\u9009\u62E9\u8BE5\u5B57\u6BB5\uFF0C<dsh_im_source> \u4E2D\u4E5F\u4F1A\u7701\u7565 threadId\u3002": "This field is not available on every channel. Messages in a Feishu topic chat carry the topic ID, which distinguishes different topics inside the same group. If the current message is not inside a topic, <dsh_im_source> omits threadId even when the field is selected.",
1600
1633
  "\u673A\u5668\u4EBA\u6807\u8BC6": "Bot ID",
1634
+ "\u53D1\u9001\u65F6\u95F4": "Sent at",
1635
+ "\u67E5\u770B\u7FA4\u804A\u53D1\u9001\u65F6\u95F4\u5B57\u6BB5\u8BF4\u660E": "View group sent-at field details",
1636
+ "\u67E5\u770B\u79C1\u804A\u53D1\u9001\u65F6\u95F4\u5B57\u6BB5\u8BF4\u660E": "View direct sent-at field details",
1637
+ "\u5F53\u524D\u6D88\u606F\u7684\u53D1\u9001\u65F6\u95F4\uFF0C\u683C\u5F0F\u4E3A YYYY-MM-DD HH:mm:ss\uFF08\u672C\u673A\u65F6\u533A\uFF09\u3002\u4F18\u5148\u4F7F\u7528\u5E73\u53F0\u7ED9\u51FA\u7684\u53D1\u9001\u65F6\u95F4\uFF1B\u5E73\u53F0\u672A\u63D0\u4F9B\u65F6\uFF0C\u4ECE\u5FAE\u4FE1\u6D88\u606F ID \u4E2D\u89E3\u6790\u51FA\u53D1\u9001\u65F6\u95F4\uFF1B\u4E24\u8005\u90FD\u4E0D\u53EF\u7528\u65F6\uFF0C\u5373\u4F7F\u5DF2\u9009\u62E9\u8BE5\u5B57\u6BB5\uFF0C<dsh_im_source> \u4E2D\u4E5F\u4F1A\u7701\u7565 sentAt\u3002\u76EE\u524D\u4EC5\u5FAE\u4FE1\u6E20\u9053\u63D0\u4F9B\uFF1B\u628A\u672C\u673A\u65F6\u533A\u5199\u8FDB\u589E\u5F3A\u63D0\u793A\u8BCD\uFF0C\u6A21\u578B\u5224\u65AD\u5148\u540E\u987A\u5E8F\u65F6\u66F4\u51C6\u786E\u3002": "When the current message was sent, as YYYY-MM-DD HH:mm:ss in the local time zone. The platform send time is used when available; otherwise the send time is decoded from the WeChat message ID. If neither is available, <dsh_im_source> omits sentAt even when the field is selected. WeChat is the only channel that provides it today. Naming your time zone in the guidance makes ordering judgements more accurate.",
1601
1638
  "\u589E\u5F3A\u63D0\u793A\u8BCD": "Guidance",
1602
1639
  "\u67E5\u770B\u589E\u5F3A\u63D0\u793A\u8BCD\u4F7F\u7528\u8BF4\u660E": "View guidance instructions",
1603
1640
  "\u67E5\u770B\u7FA4\u804A\u589E\u5F3A\u63D0\u793A\u8BCD\u4F7F\u7528\u8BF4\u660E": "View group guidance instructions",
@@ -1624,7 +1661,7 @@ var EN = Object.freeze({
1624
1661
  "\u4E0A\u4E0B\u6587\u589E\u5F3A\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002": "Could not save context enhancement. Try again.",
1625
1662
  "\u8BF7\u63D0\u4EA4\u5B8C\u6574\u7684\u4E0A\u4E0B\u6587\u589E\u5F3A\u8BBE\u7F6E\u3002": "Submit the complete context enhancement settings.",
1626
1663
  "\u7FA4\u804A\u548C\u79C1\u804A\u5F00\u5173\u5FC5\u987B\u662F\u5E03\u5C14\u503C\u3002": "Group and direct switches must be booleans.",
1627
- "\u6765\u6E90\u5B57\u6BB5\u53EA\u80FD\u9009\u62E9\u5DF2\u5B9A\u4E49\u7684\u516B\u4E2A\u5B57\u6BB5\u3002": "Source fields must be chosen from the eight defined fields.",
1664
+ "\u6765\u6E90\u5B57\u6BB5\u53EA\u80FD\u9009\u62E9\u5DF2\u5B9A\u4E49\u7684\u5B57\u6BB5\u3002": "Source fields must be chosen from the defined fields.",
1628
1665
  "\u4FDD\u5B58\u4E2D\u2026": "Saving\u2026",
1629
1666
  "\u672A\u8BBE\u7F6E": "Not set",
1630
1667
  "\u5DE5\u4F5C\u533A\u4FEE\u6539\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002": "Could not update the workspace. Try again.",
@@ -3447,7 +3484,8 @@ var CONTEXT_ENHANCEMENT_FIELDS = Object.freeze([
3447
3484
  "conversationTitle",
3448
3485
  "chatId",
3449
3486
  "threadId",
3450
- "botId"
3487
+ "botId",
3488
+ "sentAt"
3451
3489
  ]);
3452
3490
  var INJECTED_CONTEXT_TAGS = Object.freeze({
3453
3491
  sourceOpen: "<dsh_im_source>",
@@ -3494,7 +3532,7 @@ function validateContextEnhancementScope(input) {
3494
3532
  throw invalidConfig("\u7FA4\u804A\u548C\u79C1\u804A\u5F00\u5173\u5FC5\u987B\u662F\u5E03\u5C14\u503C\u3002");
3495
3533
  }
3496
3534
  if (!Array.isArray(fields) || ![...fields].every((field2) => CONTEXT_ENHANCEMENT_FIELDS.includes(field2))) {
3497
- throw invalidConfig("\u6765\u6E90\u5B57\u6BB5\u53EA\u80FD\u9009\u62E9\u5DF2\u5B9A\u4E49\u7684\u516B\u4E2A\u5B57\u6BB5\u3002");
3535
+ throw invalidConfig("\u6765\u6E90\u5B57\u6BB5\u53EA\u80FD\u9009\u62E9\u5DF2\u5B9A\u4E49\u7684\u5B57\u6BB5\u3002");
3498
3536
  }
3499
3537
  if (typeof guidance !== "string" || guidance.length > CONTEXT_ENHANCEMENT_GUIDANCE_MAX_LENGTH) {
3500
3538
  throw invalidConfig(`\u589E\u5F3A\u63D0\u793A\u8BCD\u4E0D\u5F97\u8D85\u8FC7 ${CONTEXT_ENHANCEMENT_GUIDANCE_MAX_LENGTH} \u4E2A\u5B57\u7B26\u3002`);
@@ -4828,7 +4866,8 @@ var FIELD_LABELS = Object.freeze({
4828
4866
  conversationTitle: "\u4F1A\u8BDD\u6807\u9898",
4829
4867
  chatId: "\u4F1A\u8BDD\u6807\u8BC6",
4830
4868
  threadId: "\u8BDD\u9898\u6807\u8BC6",
4831
- botId: "\u673A\u5668\u4EBA\u6807\u8BC6"
4869
+ botId: "\u673A\u5668\u4EBA\u6807\u8BC6",
4870
+ sentAt: "\u53D1\u9001\u65F6\u95F4"
4832
4871
  });
4833
4872
  var FIELD_HELP = Object.freeze({
4834
4873
  senderName: Object.freeze({
@@ -4846,6 +4885,10 @@ var FIELD_HELP = Object.freeze({
4846
4885
  threadId: Object.freeze({
4847
4886
  labelKey: "threadIdHelpLabel",
4848
4887
  text: "\u8BE5\u5B57\u6BB5\u4E0D\u662F\u6BCF\u4E2A\u6E20\u9053\u90FD\u80FD\u63D0\u4F9B\u3002\u98DE\u4E66\u8BDD\u9898\u7FA4\u7684\u6D88\u606F\u4F1A\u5E26\u4E0A\u8BDD\u9898 ID\uFF0C\u7528\u4E8E\u533A\u5206\u540C\u4E00\u7FA4\u7EC4\u5185\u7684\u4E0D\u540C\u8BDD\u9898\uFF1B\u5F53\u524D\u6D88\u606F\u4E0D\u5728\u8BDD\u9898\u4E2D\u65F6\uFF0C\u5373\u4F7F\u5DF2\u9009\u62E9\u8BE5\u5B57\u6BB5\uFF0C<dsh_im_source> \u4E2D\u4E5F\u4F1A\u7701\u7565 threadId\u3002"
4888
+ }),
4889
+ sentAt: Object.freeze({
4890
+ labelKey: "sentAtHelpLabel",
4891
+ text: "\u5F53\u524D\u6D88\u606F\u7684\u53D1\u9001\u65F6\u95F4\uFF0C\u683C\u5F0F\u4E3A YYYY-MM-DD HH:mm:ss\uFF08\u672C\u673A\u65F6\u533A\uFF09\u3002\u4F18\u5148\u4F7F\u7528\u5E73\u53F0\u7ED9\u51FA\u7684\u53D1\u9001\u65F6\u95F4\uFF1B\u5E73\u53F0\u672A\u63D0\u4F9B\u65F6\uFF0C\u4ECE\u5FAE\u4FE1\u6D88\u606F ID \u4E2D\u89E3\u6790\u51FA\u53D1\u9001\u65F6\u95F4\uFF1B\u4E24\u8005\u90FD\u4E0D\u53EF\u7528\u65F6\uFF0C\u5373\u4F7F\u5DF2\u9009\u62E9\u8BE5\u5B57\u6BB5\uFF0C<dsh_im_source> \u4E2D\u4E5F\u4F1A\u7701\u7565 sentAt\u3002\u76EE\u524D\u4EC5\u5FAE\u4FE1\u6E20\u9053\u63D0\u4F9B\uFF1B\u628A\u672C\u673A\u65F6\u533A\u5199\u8FDB\u589E\u5F3A\u63D0\u793A\u8BCD\uFF0C\u6A21\u578B\u5224\u65AD\u5148\u540E\u987A\u5E8F\u65F6\u66F4\u51C6\u786E\u3002"
4849
4892
  })
4850
4893
  });
4851
4894
  var SCOPE_COPY = Object.freeze({
@@ -4857,6 +4900,7 @@ var SCOPE_COPY = Object.freeze({
4857
4900
  conversationTitleHelpLabel: "\u67E5\u770B\u7FA4\u804A\u4F1A\u8BDD\u6807\u9898\u5B57\u6BB5\u8BF4\u660E",
4858
4901
  chatIdHelpLabel: "\u67E5\u770B\u7FA4\u804A\u4F1A\u8BDD\u6807\u8BC6\u5B57\u6BB5\u8BF4\u660E",
4859
4902
  threadIdHelpLabel: "\u67E5\u770B\u7FA4\u804A\u8BDD\u9898\u6807\u8BC6\u5B57\u6BB5\u8BF4\u660E",
4903
+ sentAtHelpLabel: "\u67E5\u770B\u7FA4\u804A\u53D1\u9001\u65F6\u95F4\u5B57\u6BB5\u8BF4\u660E",
4860
4904
  guidanceLabel: "\u589E\u5F3A\u63D0\u793A\u8BCD",
4861
4905
  guidanceHelpLabel: "\u67E5\u770B\u7FA4\u804A\u589E\u5F3A\u63D0\u793A\u8BCD\u4F7F\u7528\u8BF4\u660E",
4862
4906
  guidanceUsage: "\u7528\u4E8E\u544A\u8BC9\u6A21\u578B\u5982\u4F55\u4F7F\u7528\u5F53\u524D\u7FA4\u804A\u6D88\u606F\u7684 <dsh_im_source> \u6765\u6E90\u5B57\u6BB5\u3002\u53EA\u586B\u5199\u6B63\u6587\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u6DFB\u52A0 <dsh_im_source_guidance> \u6210\u5BF9\u6807\u7B7E\u3002",
@@ -4870,6 +4914,7 @@ var SCOPE_COPY = Object.freeze({
4870
4914
  conversationTitleHelpLabel: "\u67E5\u770B\u79C1\u804A\u4F1A\u8BDD\u6807\u9898\u5B57\u6BB5\u8BF4\u660E",
4871
4915
  chatIdHelpLabel: "\u67E5\u770B\u79C1\u804A\u4F1A\u8BDD\u6807\u8BC6\u5B57\u6BB5\u8BF4\u660E",
4872
4916
  threadIdHelpLabel: "\u67E5\u770B\u79C1\u804A\u8BDD\u9898\u6807\u8BC6\u5B57\u6BB5\u8BF4\u660E",
4917
+ sentAtHelpLabel: "\u67E5\u770B\u79C1\u804A\u53D1\u9001\u65F6\u95F4\u5B57\u6BB5\u8BF4\u660E",
4873
4918
  guidanceLabel: "\u589E\u5F3A\u63D0\u793A\u8BCD",
4874
4919
  guidanceHelpLabel: "\u67E5\u770B\u79C1\u804A\u589E\u5F3A\u63D0\u793A\u8BCD\u4F7F\u7528\u8BF4\u660E",
4875
4920
  guidanceUsage: "\u7528\u4E8E\u544A\u8BC9\u6A21\u578B\u5982\u4F55\u4F7F\u7528\u5F53\u524D\u79C1\u804A\u6D88\u606F\u7684 <dsh_im_source> \u6765\u6E90\u5B57\u6BB5\u3002\u53EA\u586B\u5199\u6B63\u6587\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u6DFB\u52A0 <dsh_im_source_guidance> \u6210\u5BF9\u6807\u7B7E\u3002",
@@ -7242,6 +7287,74 @@ function normalizeFeishuVoiceConfig(value) {
7242
7287
  });
7243
7288
  }
7244
7289
 
7290
+ // src/channels/feishu/slash-command-panel.mjs
7291
+ var SLASH_COMMAND_MANIFEST = Object.freeze([
7292
+ { command: "menu", icon: "skill_outlined", default: "\u6253\u5F00\u529F\u80FD\u83DC\u5355", en_us: "Open the feature menu" },
7293
+ { command: "new", icon: "ai-deepthink_outlined", default: "\u5F00\u542F\u5168\u65B0\u4F1A\u8BDD", en_us: "Start a fresh session" },
7294
+ { command: "help", icon: "promptword_outlined", default: "\u67E5\u770B\u5E2E\u52A9", en_us: "Show help" },
7295
+ { command: "status", icon: "ai-functions_outlined", default: "\u67E5\u770B\u673A\u5668\u4EBA\u72B6\u6001", en_us: "Show bot status" },
7296
+ { command: "compact", icon: "ai-block_outlined", default: "\u538B\u7F29\u5F53\u524D\u4F1A\u8BDD\u4E0A\u4E0B\u6587", en_us: "Compact the current session" },
7297
+ { command: "sessionlist", icon: "chat-ai_outlined", default: "\u5217\u51FA\u4F1A\u8BDD", en_us: "List sessions" },
7298
+ { command: "workspacelist", icon: "folder_outlined", default: "\u5217\u51FA\u5DE5\u4F5C\u533A", en_us: "List workspaces" },
7299
+ { command: "workspaces", icon: "folder_outlined", default: "\u5217\u51FA\u5DE5\u4F5C\u533A", en_us: "List workspaces" },
7300
+ { command: "wsl", icon: "folder_outlined", default: "\u5217\u51FA\u5DE5\u4F5C\u533A", en_us: "List workspaces" },
7301
+ { command: "ws", icon: "folder_outlined", default: "\u5207\u6362\u5DE5\u4F5C\u533A", en_us: "Switch workspace" },
7302
+ { command: "watch", icon: "flag_outlined", default: "\u5173\u6CE8\u4E00\u4E2A\u4F1A\u8BDD", en_us: "Watch a session" },
7303
+ { command: "unwatch", icon: "clear_outlined", default: "\u53D6\u6D88\u5173\u6CE8\u4F1A\u8BDD", en_us: "Unwatch a session" },
7304
+ { command: "watchlist", icon: "flag_outlined", default: "\u67E5\u770B\u5173\u6CE8\u5217\u8868", en_us: "List watched sessions" },
7305
+ { 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)" },
7306
+ { 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)" },
7307
+ { command: "workspace", icon: "folder_outlined", default: "\u5207\u6362\u5DE5\u4F5C\u533A", en_us: "Switch workspace" },
7308
+ { 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" },
7309
+ { command: "session", icon: "chat-ai_outlined", default: "\u7ED1\u5B9A\u5DF2\u6709\u4F1A\u8BDD", en_us: "Bind an existing session" },
7310
+ { command: "models", icon: "ai-functions_outlined", default: "\u5217\u51FA\u53EF\u7528\u6A21\u578B", en_us: "List available models" },
7311
+ { command: "model", icon: "ai-agent_outlined", default: "\u67E5\u770B\u6216\u5207\u6362\u5F53\u524D\u6A21\u578B", en_us: "Show or switch the current model" },
7312
+ { command: "reasoninglist", icon: "ai-deepthink_outlined", default: "\u5217\u51FA\u53EF\u7528\u63A8\u7406\u7B49\u7EA7", en_us: "List available reasoning efforts" },
7313
+ { command: "reasoning", icon: "ai-deepthink_outlined", default: "\u67E5\u770B\u6216\u5207\u6362\u63A8\u7406\u7B49\u7EA7", en_us: "Show or switch the reasoning effort" },
7314
+ { command: "presetlist", icon: "skill_outlined", default: "\u5217\u51FA\u53EF\u7528 Agent \u9884\u8BBE", en_us: "List available Agent Presets" },
7315
+ { command: "preset", icon: "skill_outlined", default: "\u67E5\u770B\u6216\u5207\u6362 Agent \u9884\u8BBE", en_us: "Show or switch the Agent Preset" },
7316
+ { command: "stop", icon: "clear_outlined", default: "\u505C\u6B62\u5F53\u524D\u4EFB\u52A1", en_us: "Stop the current task" },
7317
+ { command: "steer", icon: "promptword_outlined", default: "\u7ED9\u5F53\u524D\u4EFB\u52A1\u8865\u5145\u6307\u4EE4", en_us: "Send additional instructions to the current task" },
7318
+ { 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)" },
7319
+ { 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)" },
7320
+ { 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)" },
7321
+ { command: "version", icon: "ai-functions_outlined", default: "\u67E5\u770B\u63D2\u4EF6\u7248\u672C", en_us: "Show the plugin version" },
7322
+ { 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)" }
7323
+ ]);
7324
+ var SLASH_PANEL_MODES = Object.freeze({
7325
+ DEFAULT: "default",
7326
+ CUSTOM: "custom"
7327
+ });
7328
+ var DEFAULT_SLASH_PANEL_CONFIG = Object.freeze({
7329
+ mode: SLASH_PANEL_MODES.DEFAULT,
7330
+ order: Object.freeze([])
7331
+ });
7332
+ var MAX_SLASH_PANEL_COMMANDS = 100;
7333
+ function normalizeCommandName(value) {
7334
+ if (typeof value !== "string") return null;
7335
+ const name2 = value.trim().replace(/^\//u, "").toLowerCase();
7336
+ return name2 || null;
7337
+ }
7338
+ function manifestHas(name2) {
7339
+ return SLASH_COMMAND_MANIFEST.some((entry) => entry.command === name2);
7340
+ }
7341
+ function normalizeSlashPanelConfig(value) {
7342
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
7343
+ return DEFAULT_SLASH_PANEL_CONFIG;
7344
+ }
7345
+ if (value.mode !== SLASH_PANEL_MODES.CUSTOM) return DEFAULT_SLASH_PANEL_CONFIG;
7346
+ const order = [];
7347
+ const seen = /* @__PURE__ */ new Set();
7348
+ for (const candidate of Array.isArray(value.order) ? value.order : []) {
7349
+ const name2 = normalizeCommandName(candidate);
7350
+ if (!name2 || seen.has(name2) || !manifestHas(name2)) continue;
7351
+ seen.add(name2);
7352
+ order.push(name2);
7353
+ if (order.length >= MAX_SLASH_PANEL_COMMANDS) break;
7354
+ }
7355
+ return Object.freeze({ mode: SLASH_PANEL_MODES.CUSTOM, order: Object.freeze(order) });
7356
+ }
7357
+
7245
7358
  // plugin-src/client/channels/feishu/api.js
7246
7359
  var FEISHU_RPC_CHANNEL = "/feishu";
7247
7360
  var FEISHU_ENDPOINTS = Object.freeze({
@@ -7262,10 +7375,11 @@ var FEISHU_ENDPOINTS = Object.freeze({
7262
7375
  setAccessPolicy: "bot.access-policy.set",
7263
7376
  setAlias: "bot.alias.set",
7264
7377
  setGroupResponseMode: "bot.group-response-mode.set",
7265
- setGroupTopicReply: "bot.group-topic-reply.set",
7378
+ setMentionTopicReply: "bot.mention-topic-reply.set",
7266
7379
  setStepPush: "bot.step-push.set",
7267
7380
  setStepPushMode: "bot.step-push-mode.set",
7268
7381
  setVoice: "bot.voice.set",
7382
+ setSlashPanel: "bot.slash-panel.set",
7269
7383
  // Kept for rolling upgrades. The multi-bot UI never calls these endpoints.
7270
7384
  testConnection: "connection.test",
7271
7385
  disconnect: "connection.disconnect"
@@ -7419,10 +7533,11 @@ function normalizeBotConnection(value, fallbackBotId) {
7419
7533
  contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
7420
7534
  ...Object.hasOwn(value, "accessPolicy") ? { accessPolicy: normalizeAccessPolicy(value.accessPolicy) } : {},
7421
7535
  groupResponseMode: normalizeGroupResponseMode(value.groupResponseMode),
7422
- groupTopicReply: value.groupTopicReply === true,
7536
+ mentionTopicReply: value.mentionTopicReply !== false,
7423
7537
  stepPush: value.stepPush === true,
7424
7538
  stepPushMode: normalizeFeishuStepPushMode(value.stepPushMode),
7425
7539
  voice: normalizeFeishuVoiceConfig(value.voice),
7540
+ slashPanel: normalizeSlashPanelConfig(value.slashPanel),
7426
7541
  groupMessagePermissionGranted: value.groupMessagePermissionGranted === true,
7427
7542
  bot: normalizeBot2(value.bot),
7428
7543
  health: normalizeHealth(value.health, connected),
@@ -8130,7 +8245,8 @@ function BotCard({
8130
8245
  accessPolicy: connection.accessPolicy,
8131
8246
  channelSettings: {
8132
8247
  groupResponseMode: connection.groupResponseMode,
8133
- groupTopicReply: connection.groupTopicReply,
8248
+ mentionTopicReply: connection.mentionTopicReply,
8249
+ slashPanel: connection.slashPanel,
8134
8250
  groupMessagePermissionGranted: connection.groupMessagePermissionGranted
8135
8251
  }
8136
8252
  }),
@@ -16121,7 +16237,7 @@ function installInterfaceLanguageMirror(ctx, {
16121
16237
  }
16122
16238
 
16123
16239
  // plugin-src/client/delivery-settings.js
16124
- var React32 = __toESM(require("react"), 1);
16240
+ var React33 = __toESM(require("react"), 1);
16125
16241
 
16126
16242
  // plugin-src/client/access-policy-settings.js
16127
16243
  var React28 = __toESM(require("react"), 1);
@@ -16544,7 +16660,7 @@ function SettingsButton({ children, kind = "secondary", className = "", ...props
16544
16660
  function groupSettingsFrom(value) {
16545
16661
  return {
16546
16662
  groupResponseMode: normalizeGroupResponseMode(value?.groupResponseMode),
16547
- groupTopicReply: value?.groupTopicReply === true,
16663
+ mentionTopicReply: value?.mentionTopicReply !== false,
16548
16664
  groupMessagePermissionGranted: value?.groupMessagePermissionGranted === true
16549
16665
  };
16550
16666
  }
@@ -16673,7 +16789,7 @@ function GroupResponseModeEditor({
16673
16789
  }, error) : null
16674
16790
  );
16675
16791
  }
16676
- function GroupTopicReplyEditor({ value = false, disabled = false, onSave }) {
16792
+ function MentionTopicReplyEditor({ value = true, disabled = false, onSave }) {
16677
16793
  const current = value === true ? "on" : "off";
16678
16794
  const [saving, setSaving] = React29.useState(false);
16679
16795
  const [error, setError] = React29.useState(null);
@@ -16685,7 +16801,7 @@ function GroupTopicReplyEditor({ value = false, disabled = false, onSave }) {
16685
16801
  try {
16686
16802
  await onSave?.(next);
16687
16803
  } 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");
16804
+ setError(cause?.message ?? "\u4EE5\u8BDD\u9898\u65B9\u5F0F\u56DE\u590D\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002");
16689
16805
  } finally {
16690
16806
  setSaving(false);
16691
16807
  }
@@ -16694,12 +16810,12 @@ function GroupTopicReplyEditor({ value = false, disabled = false, onSave }) {
16694
16810
  "section",
16695
16811
  {
16696
16812
  className: "dim-feishuGroupControl",
16697
- "aria-labelledby": "dim-feishu-group-topic-title"
16813
+ "aria-labelledby": "dim-feishu-mention-topic-title"
16698
16814
  },
16699
16815
  h2(
16700
16816
  "div",
16701
16817
  { className: "dim-feishuGroupControlHeader" },
16702
- h2("h3", { id: "dim-feishu-group-topic-title" }, "\u7FA4\u804A\u4EE5\u8BDD\u9898\u65B9\u5F0F\u56DE\u590D"),
16818
+ h2("h3", { id: "dim-feishu-mention-topic-title" }, "\u88AB @ \u65F6\u4EE5\u8BDD\u9898\u65B9\u5F0F\u56DE\u590D"),
16703
16819
  saving ? h2("span", { className: "dim-feishuGroupControlStatus", role: "status" }, "\u4FDD\u5B58\u4E2D\u2026") : null
16704
16820
  ),
16705
16821
  h2(
@@ -16708,18 +16824,18 @@ function GroupTopicReplyEditor({ value = false, disabled = false, onSave }) {
16708
16824
  className: "dim-feishuGroupSelect",
16709
16825
  value: current,
16710
16826
  disabled: disabled || saving,
16711
- "aria-label": "\u7FA4\u804A\u4EE5\u8BDD\u9898\u65B9\u5F0F\u56DE\u590D",
16827
+ "aria-label": "\u88AB @ \u65F6\u4EE5\u8BDD\u9898\u65B9\u5F0F\u56DE\u590D",
16712
16828
  onChange: (event) => {
16713
16829
  void change(event);
16714
16830
  }
16715
16831
  },
16716
- h2("option", { value: "off" }, "\u5173\u95ED\uFF08\u7FA4\u5185\u76F4\u63A5\u56DE\u590D\uFF09"),
16832
+ h2("option", { value: "off" }, "\u5173\u95ED\uFF08\u5728\u4F1A\u8BDD\u4E3B\u7A97\u53E3\u56DE\u590D\uFF09"),
16717
16833
  h2("option", { value: "on" }, "\u5F00\u542F\uFF08\u81EA\u52A8\u5F00\u542F\u72EC\u7ACB\u98DE\u4E66\u8BDD\u9898\uFF09")
16718
16834
  ),
16719
16835
  h2(
16720
16836
  "p",
16721
16837
  { 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"
16838
+ "\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
16839
  ),
16724
16840
  error ? h2("p", {
16725
16841
  className: "dim-feishuGroupError",
@@ -16875,7 +16991,7 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
16875
16991
  }, [
16876
16992
  account.botId,
16877
16993
  account.groupResponseMode,
16878
- account.groupTopicReply,
16994
+ account.mentionTopicReply,
16879
16995
  account.groupMessagePermissionGranted
16880
16996
  ]);
16881
16997
  React29.useEffect(() => {
@@ -17096,12 +17212,12 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
17096
17212
  },
17097
17213
  onAuthorize: () => startAuthorization()
17098
17214
  }),
17099
- h2(GroupTopicReplyEditor, {
17100
- value: settings.groupTopicReply,
17215
+ h2(MentionTopicReplyEditor, {
17216
+ value: settings.mentionTopicReply,
17101
17217
  disabled,
17102
- onSave: (groupTopicReply) => saveSetting(
17103
- FEISHU_ENDPOINTS.setGroupTopicReply,
17104
- { groupTopicReply }
17218
+ onSave: (mentionTopicReply) => saveSetting(
17219
+ FEISHU_ENDPOINTS.setMentionTopicReply,
17220
+ { mentionTopicReply }
17105
17221
  )
17106
17222
  })
17107
17223
  ),
@@ -17318,6 +17434,309 @@ function FeishuVoiceSettingsPage({ account, rpcCall }) {
17318
17434
  return h2(VoiceEditor, { value: voice, onSave: saveVoice });
17319
17435
  }
17320
17436
 
17437
+ // plugin-src/client/channels/feishu/slash-panel-settings.js
17438
+ var React32 = __toESM(require("react"), 1);
17439
+ var MANIFEST_BY_NAME = new Map(SLASH_COMMAND_MANIFEST.map((entry) => [entry.command, entry]));
17440
+ var ALL_COMMANDS = Object.freeze(SLASH_COMMAND_MANIFEST.map((entry) => entry.command));
17441
+ function PanelButton({ children, disabled = false, onClick, ...props }) {
17442
+ return h2("button", {
17443
+ ...props,
17444
+ type: "button",
17445
+ className: "dim-deliveryButton",
17446
+ disabled,
17447
+ onClick
17448
+ }, children);
17449
+ }
17450
+ function panelSignature(panel) {
17451
+ const normalized = normalizeSlashPanelConfig(panel);
17452
+ return `${normalized.mode}:${normalized.order.join(",")}`;
17453
+ }
17454
+ function commandText(name2) {
17455
+ const entry = MANIFEST_BY_NAME.get(name2);
17456
+ return `/${name2} \u2014 ${entry?.default ?? name2}`;
17457
+ }
17458
+ function FeishuSlashPanelSettingsPage({ account, rpcCall, onSaved }) {
17459
+ const incoming = React32.useMemo(() => normalizeSlashPanelConfig(account.slashPanel), [account.botId, panelSignature(account.slashPanel)]);
17460
+ const [mode, setMode] = React32.useState(incoming.mode);
17461
+ const [order, setOrder] = React32.useState(() => [...incoming.order]);
17462
+ const [pending, setPending] = React32.useState("");
17463
+ const [dirty, setDirty] = React32.useState(false);
17464
+ const [saving, setSaving] = React32.useState(false);
17465
+ const [saved, setSaved] = React32.useState(false);
17466
+ const [syncing, setSyncing] = React32.useState(false);
17467
+ const [syncTargets, setSyncTargets] = React32.useState(null);
17468
+ const [syncNotice, setSyncNotice] = React32.useState(null);
17469
+ const [error, setError] = React32.useState(null);
17470
+ const mounted = React32.useRef(true);
17471
+ React32.useEffect(() => {
17472
+ mounted.current = true;
17473
+ return () => {
17474
+ mounted.current = false;
17475
+ };
17476
+ }, []);
17477
+ React32.useEffect(() => {
17478
+ if (dirty) return;
17479
+ setMode(incoming.mode);
17480
+ setOrder([...incoming.order]);
17481
+ }, [incoming.mode, incoming.order, dirty]);
17482
+ const edit = React32.useCallback((update) => {
17483
+ setSaved(false);
17484
+ setDirty(true);
17485
+ update();
17486
+ }, []);
17487
+ const move = (index, offset) => edit(() => {
17488
+ const next = [...order];
17489
+ const target = index + offset;
17490
+ if (target < 0 || target >= next.length) return;
17491
+ [next[index], next[target]] = [next[target], next[index]];
17492
+ setOrder(next);
17493
+ });
17494
+ const remove = (index) => edit(() => setOrder(order.filter((_, at) => at !== index)));
17495
+ const add = () => {
17496
+ if (!pending || order.includes(pending)) return;
17497
+ edit(() => setOrder([...order, pending]));
17498
+ setPending("");
17499
+ };
17500
+ const draftPanel = () => mode === SLASH_PANEL_MODES.CUSTOM ? { mode: SLASH_PANEL_MODES.CUSTOM, order: [...order] } : { mode: SLASH_PANEL_MODES.DEFAULT, order: [] };
17501
+ const applySnapshot = (value) => {
17502
+ const snapshot = normalizeBotsSnapshot(value);
17503
+ const bot = snapshot.bots.find((entry) => entry.botId === account.botId);
17504
+ const stored = normalizeSlashPanelConfig(bot?.slashPanel);
17505
+ setMode(stored.mode);
17506
+ setOrder([...stored.order]);
17507
+ onSaved?.(stored);
17508
+ setDirty(false);
17509
+ setSaved(true);
17510
+ return snapshot;
17511
+ };
17512
+ const save = async () => {
17513
+ if (saving) return;
17514
+ setSaving(true);
17515
+ setError(null);
17516
+ try {
17517
+ if (typeof rpcCall !== "function") throw new Error("\u98DE\u4E66\u6307\u4EE4\u9762\u677F\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
17518
+ const value = unwrapRpcResult3(await rpcCall(
17519
+ FEISHU_ENDPOINTS.setSlashPanel,
17520
+ { botId: account.botId, slashPanel: draftPanel() }
17521
+ ));
17522
+ if (!mounted.current) return;
17523
+ applySnapshot(value);
17524
+ } catch (cause) {
17525
+ if (!mounted.current) return;
17526
+ setError(presentError3(cause));
17527
+ } finally {
17528
+ if (mounted.current) setSaving(false);
17529
+ }
17530
+ };
17531
+ const startSyncAll = async () => {
17532
+ if (saving || syncing || typeof rpcCall !== "function") return;
17533
+ setSyncing(true);
17534
+ setError(null);
17535
+ setSyncNotice(null);
17536
+ try {
17537
+ const snapshot = normalizeBotsSnapshot(unwrapRpcResult3(
17538
+ await rpcCall(FEISHU_ENDPOINTS.status, {})
17539
+ ));
17540
+ const others = snapshot.bots.map((entry) => entry.botId).filter((botId) => botId && botId !== account.botId);
17541
+ if (!mounted.current) return;
17542
+ if (others.length === 0) {
17543
+ setSyncNotice({ scope: "none" });
17544
+ return;
17545
+ }
17546
+ setSyncTargets(others);
17547
+ } catch (cause) {
17548
+ if (mounted.current) setError(presentError3(cause));
17549
+ } finally {
17550
+ if (mounted.current) setSyncing(false);
17551
+ }
17552
+ };
17553
+ const confirmSyncAll = async () => {
17554
+ const targets = syncTargets;
17555
+ if (!targets || syncing || typeof rpcCall !== "function") return;
17556
+ setSyncing(true);
17557
+ setError(null);
17558
+ setSyncTargets(null);
17559
+ const payload = draftPanel();
17560
+ let done = 0;
17561
+ let failed = 0;
17562
+ for (const botId of [account.botId, ...targets]) {
17563
+ try {
17564
+ const value = unwrapRpcResult3(await rpcCall(
17565
+ FEISHU_ENDPOINTS.setSlashPanel,
17566
+ { botId, slashPanel: payload }
17567
+ ));
17568
+ if (botId === account.botId && mounted.current) applySnapshot(value);
17569
+ done += 1;
17570
+ } catch {
17571
+ failed += 1;
17572
+ }
17573
+ }
17574
+ if (!mounted.current) return;
17575
+ setSyncing(false);
17576
+ setSyncNotice({ scope: "done", done, failed });
17577
+ };
17578
+ const available = ALL_COMMANDS.filter((name2) => !order.includes(name2));
17579
+ return h2(
17580
+ "section",
17581
+ {
17582
+ className: "dim-feishuGroupSettings",
17583
+ "aria-label": "\u6307\u4EE4\u9762\u677F\u8BBE\u7F6E"
17584
+ },
17585
+ h2(
17586
+ "section",
17587
+ {
17588
+ className: "dim-feishuGroupControl",
17589
+ "aria-labelledby": "dim-feishu-slash-panel-title"
17590
+ },
17591
+ h2(
17592
+ "div",
17593
+ { className: "dim-feishuGroupControlHeader" },
17594
+ h2("h3", { id: "dim-feishu-slash-panel-title" }, "\u6307\u4EE4\u9762\u677F"),
17595
+ 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
17596
+ ),
17597
+ h2(
17598
+ "p",
17599
+ { className: "dim-feishuGroupHelp" },
17600
+ "\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"
17601
+ ),
17602
+ h2(
17603
+ "select",
17604
+ {
17605
+ className: "dim-feishuGroupSelect",
17606
+ value: mode,
17607
+ "aria-label": "\u6307\u4EE4\u9762\u677F\u6A21\u5F0F",
17608
+ disabled: saving || syncing,
17609
+ onChange: (event) => edit(() => {
17610
+ const next = event.target.value;
17611
+ setMode(next);
17612
+ if (next === SLASH_PANEL_MODES.CUSTOM && order.length === 0) setOrder([...ALL_COMMANDS]);
17613
+ })
17614
+ },
17615
+ h2("option", { value: SLASH_PANEL_MODES.DEFAULT }, "\u8DDF\u968F\u9ED8\u8BA4\uFF08\u968F\u63D2\u4EF6\u7248\u672C\u66F4\u65B0\uFF09"),
17616
+ h2("option", { value: SLASH_PANEL_MODES.CUSTOM }, "\u81EA\u5B9A\u4E49\uFF08\u81EA\u5DF1\u6311\u6307\u4EE4\u548C\u987A\u5E8F\uFF09")
17617
+ ),
17618
+ mode === SLASH_PANEL_MODES.CUSTOM ? h2(
17619
+ React32.Fragment,
17620
+ null,
17621
+ 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(
17622
+ "ul",
17623
+ { className: "dim-feishuPanelList" },
17624
+ order.map((name2, index) => h2(
17625
+ "li",
17626
+ {
17627
+ key: name2,
17628
+ className: "dim-feishuPanelRow"
17629
+ },
17630
+ h2("span", { className: "dim-feishuPanelIndex" }, String(index + 1)),
17631
+ h2("span", { className: "dim-feishuPanelCommand" }, commandText(name2)),
17632
+ h2(
17633
+ "span",
17634
+ { className: "dim-feishuPanelRowActions" },
17635
+ h2(PanelButton, {
17636
+ "aria-label": [localizeText("\u4E0A\u79FB"), `/${name2}`].join(" "),
17637
+ disabled: saving || syncing || index === 0,
17638
+ onClick: () => move(index, -1)
17639
+ }, "\u2191"),
17640
+ h2(PanelButton, {
17641
+ "aria-label": [localizeText("\u4E0B\u79FB"), `/${name2}`].join(" "),
17642
+ disabled: saving || syncing || index === order.length - 1,
17643
+ onClick: () => move(index, 1)
17644
+ }, "\u2193"),
17645
+ h2(PanelButton, {
17646
+ "aria-label": [localizeText("\u79FB\u9664"), `/${name2}`].join(" "),
17647
+ disabled: saving || syncing,
17648
+ onClick: () => remove(index)
17649
+ }, "\u79FB\u9664")
17650
+ )
17651
+ ))
17652
+ ),
17653
+ h2(
17654
+ "div",
17655
+ { className: "dim-feishuPanelAdd" },
17656
+ h2(
17657
+ "select",
17658
+ {
17659
+ className: "dim-feishuGroupSelect",
17660
+ value: pending,
17661
+ "aria-label": "\u6DFB\u52A0\u6307\u4EE4",
17662
+ disabled: saving || syncing || available.length === 0,
17663
+ onChange: (event) => setPending(event.target.value)
17664
+ },
17665
+ h2("option", { value: "" }, available.length === 0 ? "\u6307\u4EE4\u90FD\u5DF2\u52A0\u5165" : "\u9009\u62E9\u8981\u52A0\u5165\u7684\u6307\u4EE4"),
17666
+ available.map((name2) => h2("option", { key: name2, value: name2 }, commandText(name2)))
17667
+ ),
17668
+ h2(PanelButton, {
17669
+ disabled: saving || syncing || !pending,
17670
+ onClick: add
17671
+ }, "\u52A0\u5165"),
17672
+ h2(PanelButton, {
17673
+ disabled: saving || syncing || available.length === 0,
17674
+ onClick: () => edit(() => setOrder([...ALL_COMMANDS]))
17675
+ }, "\u6062\u590D\u5168\u90E8"),
17676
+ h2(PanelButton, {
17677
+ disabled: saving || syncing || order.length === 0,
17678
+ onClick: () => edit(() => setOrder([]))
17679
+ }, "\u5168\u90E8\u79FB\u9664")
17680
+ )
17681
+ ) : null,
17682
+ h2(
17683
+ "div",
17684
+ { className: "dim-feishuPanelFooter" },
17685
+ h2(PanelButton, {
17686
+ "data-kind": "primary",
17687
+ disabled: saving || syncing || !dirty,
17688
+ onClick: () => {
17689
+ void save();
17690
+ }
17691
+ }, "\u4FDD\u5B58"),
17692
+ h2(PanelButton, {
17693
+ disabled: saving || syncing,
17694
+ onClick: () => {
17695
+ void startSyncAll();
17696
+ }
17697
+ }, "\u4FDD\u5B58\u5E76\u540C\u6B65\u5230\u5176\u4ED6\u673A\u5668\u4EBA")
17698
+ ),
17699
+ syncTargets ? h2(
17700
+ "div",
17701
+ { className: "dim-feishuPanelFooter" },
17702
+ h2(
17703
+ "span",
17704
+ { className: "dim-feishuGroupHelp" },
17705
+ [
17706
+ localizeText("\u5C06\u628A\u8FD9\u5957\u9762\u677F\u8BBE\u7F6E\u5199\u5165\u53E6\u5916"),
17707
+ ` ${syncTargets.length} `,
17708
+ localizeText("\u4E2A\u98DE\u4E66\u673A\u5668\u4EBA\uFF0C\u5B83\u4EEC\u5404\u81EA\u7684\u9762\u677F\u8BBE\u7F6E\u4F1A\u88AB\u8986\u76D6\u3002")
17709
+ ].join("")
17710
+ ),
17711
+ h2(PanelButton, {
17712
+ disabled: syncing,
17713
+ onClick: () => {
17714
+ void confirmSyncAll();
17715
+ }
17716
+ }, "\u786E\u8BA4\u540C\u6B65"),
17717
+ h2(PanelButton, {
17718
+ disabled: syncing,
17719
+ onClick: () => setSyncTargets(null)
17720
+ }, "\u53D6\u6D88")
17721
+ ) : null,
17722
+ syncing ? h2("p", { className: "dim-feishuGroupHelp", role: "status" }, "\u6B63\u5728\u540C\u6B65\u2026") : null,
17723
+ 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,
17724
+ syncNotice?.scope === "done" ? h2(
17725
+ "p",
17726
+ { className: "dim-feishuGroupHelp", role: "status" },
17727
+ syncNotice.failed > 0 ? [
17728
+ localizeText("\u5DF2\u540C\u6B65\u5230"),
17729
+ ` ${syncNotice.done} `,
17730
+ localizeText("\u4E2A\u673A\u5668\u4EBA\uFF0C"),
17731
+ ` ${syncNotice.failed} `,
17732
+ localizeText("\u4E2A\u5931\u8D25\u3002")
17733
+ ].join("") : [localizeText("\u5DF2\u540C\u6B65\u5230"), ` ${syncNotice.done} `, localizeText("\u4E2A\u673A\u5668\u4EBA\u3002")].join("")
17734
+ ) : null,
17735
+ error ? h2("p", { className: "dim-feishuGroupError", role: "alert" }, error) : null
17736
+ )
17737
+ );
17738
+ }
17739
+
17321
17740
  // plugin-src/client/delivery-settings.js
17322
17741
  var DELIVERY_RPC_CHANNEL = "/dsh-im-delivery";
17323
17742
  var DELIVERY_DOCS_URL = Object.freeze({
@@ -17340,6 +17759,7 @@ var BOT_SETTINGS_TABS = Object.freeze([
17340
17759
  var FEISHU_BOT_SETTINGS_TABS = Object.freeze([
17341
17760
  ...BOT_SETTINGS_TABS,
17342
17761
  Object.freeze({ id: "group", label: "\u7FA4\u804A" }),
17762
+ Object.freeze({ id: "slash", label: "\u6307\u4EE4\u9762\u677F" }),
17343
17763
  Object.freeze({ id: "voice", label: "\u8BED\u97F3\u4EA4\u4E92" })
17344
17764
  ]);
17345
17765
  function botSettingsTabsForChannel(channel7) {
@@ -17552,13 +17972,13 @@ function TargetForm({
17552
17972
  }) {
17553
17973
  const editing = mode === "edit";
17554
17974
  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);
17975
+ const [targetId, setTargetId] = React33.useState(initialValue?.targetId ?? "");
17976
+ const [name2, setName] = React33.useState(initialValue?.name ?? "");
17977
+ const [kind, setKind] = React33.useState(initialKind);
17978
+ const [route, setRoute] = React33.useState(initialValue?.route ?? {});
17979
+ const [error, setError] = React33.useState(null);
17980
+ const [testing, setTesting] = React33.useState(false);
17981
+ const [testState, setTestState] = React33.useState(null);
17562
17982
  const currentTarget = () => {
17563
17983
  const normalizedRoute = Object.fromEntries(fieldsFor(definition, kind).map((field2) => {
17564
17984
  const raw = String(route[field2.key] ?? "").trim();
@@ -17775,7 +18195,7 @@ function TargetSuggestionPicker({
17775
18195
  suggestions.map((suggestion, index) => {
17776
18196
  const identity = routeIdentity(definition, suggestion);
17777
18197
  const added = configured.has(identity);
17778
- return React32.createElement("option", {
18198
+ return React33.createElement("option", {
17779
18199
  key: suggestion.id ?? suggestion.suggestionId ?? `${identity}:${index}`,
17780
18200
  value: String(index),
17781
18201
  disabled: added
@@ -17792,11 +18212,11 @@ function TargetSuggestionPicker({
17792
18212
  );
17793
18213
  }
17794
18214
  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);
18215
+ const [action, setAction] = React33.useState(null);
18216
+ const [testState, setTestState] = React33.useState(null);
18217
+ const [syncFeedback, setSyncFeedback] = React33.useState(null);
18218
+ const [copyState, setCopyState] = React33.useState(null);
18219
+ const [confirmDelete, setConfirmDelete] = React33.useState(false);
17800
18220
  const sessionSync = target.sessionSync ?? { enabled: false, state: "unavailable" };
17801
18221
  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
18222
  const testTarget = async () => {
@@ -17859,7 +18279,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
17859
18279
  h2(
17860
18280
  "div",
17861
18281
  { className: "dim-targetTitle" },
17862
- React32.createElement("strong", null, target.name || target.targetId),
18282
+ React33.createElement("strong", null, target.name || target.targetId),
17863
18283
  h2("span", null, kindLabel(definition, target.kind))
17864
18284
  ),
17865
18285
  h2("code", null, `targetId: ${target.targetId}`)
@@ -17945,26 +18365,30 @@ function DeliveryTargetSettingsPage({
17945
18365
  onBack
17946
18366
  }) {
17947
18367
  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(() => {
18368
+ const [activeTabId, setActiveTabId] = React33.useState(BOT_SETTINGS_TABS[0].id);
18369
+ const [phase, setPhase] = React33.useState("loading");
18370
+ const [targets, setTargets] = React33.useState([]);
18371
+ const [suggestionPhase, setSuggestionPhase] = React33.useState("idle");
18372
+ const [suggestions, setSuggestions] = React33.useState([]);
18373
+ const [suggestionError, setSuggestionError] = React33.useState(null);
18374
+ const [error, setError] = React33.useState(null);
18375
+ const [editor, setEditor] = React33.useState(null);
18376
+ const [saving, setSaving] = React33.useState(false);
18377
+ const [botCopyState, setBotCopyState] = React33.useState(null);
18378
+ const [accessPolicy, setAccessPolicy] = React33.useState(account.accessPolicy);
18379
+ const [slashPanel, setSlashPanel] = React33.useState(account.slashPanel);
18380
+ const mounted = React33.useRef(true);
18381
+ React33.useEffect(() => {
17961
18382
  setAccessPolicy(account.accessPolicy);
17962
18383
  }, [account.botId, account.accessPolicy]);
17963
- const invoke = React32.useCallback(async (endpoint, payload = {}, signal) => {
18384
+ React33.useEffect(() => {
18385
+ setSlashPanel(account.slashPanel);
18386
+ }, [account.botId, account.slashPanel]);
18387
+ const invoke = React33.useCallback(async (endpoint, payload = {}, signal) => {
17964
18388
  if (typeof rpcCall !== "function") throw new Error("\u6295\u9012\u76EE\u6807\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
17965
18389
  return unwrapRpcResult15(await rpcCall(endpoint, payload, signal));
17966
18390
  }, [rpcCall]);
17967
- const loadTargets = React32.useCallback(async ({ signal, silent = false } = {}) => {
18391
+ const loadTargets = React33.useCallback(async ({ signal, silent = false } = {}) => {
17968
18392
  if (!silent) setPhase("loading");
17969
18393
  setError(null);
17970
18394
  try {
@@ -17978,7 +18402,7 @@ function DeliveryTargetSettingsPage({
17978
18402
  setPhase("error");
17979
18403
  }
17980
18404
  }, [account.botId, invoke]);
17981
- const loadSuggestions = React32.useCallback(async () => {
18405
+ const loadSuggestions = React33.useCallback(async () => {
17982
18406
  setSuggestionPhase("loading");
17983
18407
  setSuggestionError(null);
17984
18408
  try {
@@ -17992,7 +18416,7 @@ function DeliveryTargetSettingsPage({
17992
18416
  setSuggestionPhase("error");
17993
18417
  }
17994
18418
  }, [account.botId, definition, invoke]);
17995
- React32.useEffect(() => {
18419
+ React33.useEffect(() => {
17996
18420
  mounted.current = true;
17997
18421
  const controller = new AbortController();
17998
18422
  void loadTargets({ signal: controller.signal });
@@ -18113,12 +18537,16 @@ function DeliveryTargetSettingsPage({
18113
18537
  }) : activeTab.id === "group" && channel7 === "feishu" ? h2(FeishuGroupSettingsPage, {
18114
18538
  account,
18115
18539
  rpcCall: accessRpcCall
18540
+ }) : activeTab.id === "slash" && channel7 === "feishu" ? h2(FeishuSlashPanelSettingsPage, {
18541
+ account: { ...account, slashPanel },
18542
+ rpcCall: accessRpcCall,
18543
+ onSaved: setSlashPanel
18116
18544
  }) : activeTab.id === "voice" && channel7 === "feishu" ? h2(FeishuVoiceSettingsPage, {
18117
18545
  key: account.botId,
18118
18546
  account,
18119
18547
  rpcCall: accessRpcCall
18120
18548
  }) : h2(
18121
- React32.Fragment,
18549
+ React33.Fragment,
18122
18550
  null,
18123
18551
  h2(
18124
18552
  "section",
@@ -18229,7 +18657,7 @@ function DeliveryTargetSettingsPage({
18229
18657
  }
18230
18658
 
18231
18659
  // plugin-src/client/global-settings.js
18232
- var React33 = __toESM(require("react"), 1);
18660
+ var React34 = __toESM(require("react"), 1);
18233
18661
 
18234
18662
  // src/channels/shared/inbound-ttl.mjs
18235
18663
  var DEFAULT_INBOUND_TTL_HOURS = 168;
@@ -18314,14 +18742,14 @@ function GlobalButton({ children, kind = "secondary", className = "", ...props }
18314
18742
  }, children);
18315
18743
  }
18316
18744
  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) => {
18745
+ const [values, setValues] = React34.useState(DEFAULT_IMAGE_INPUT_SETTINGS);
18746
+ const [phase, setPhase] = React34.useState("loading");
18747
+ const [error, setError] = React34.useState(null);
18748
+ const [saved, setSaved] = React34.useState(false);
18749
+ const mounted = React34.useRef(false);
18750
+ const saving = React34.useRef(false);
18751
+ const id6 = React34.useId();
18752
+ const load = React34.useCallback(async (signal) => {
18325
18753
  setPhase("loading");
18326
18754
  setError(null);
18327
18755
  try {
@@ -18337,7 +18765,7 @@ function ImageInputSettings({ rpcCall }) {
18337
18765
  setPhase("error");
18338
18766
  }
18339
18767
  }, [rpcCall]);
18340
- React33.useEffect(() => {
18768
+ React34.useEffect(() => {
18341
18769
  mounted.current = true;
18342
18770
  const controller = new AbortController();
18343
18771
  void load(controller.signal);
@@ -18444,29 +18872,29 @@ function ImageInputSettings({ rpcCall }) {
18444
18872
  );
18445
18873
  }
18446
18874
  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) => {
18875
+ const [phase, setPhase] = React34.useState("loading");
18876
+ const [loadError, setLoadError] = React34.useState(null);
18877
+ const [ttlInput, setTtlInput] = React34.useState("");
18878
+ const [savedTtl, setSavedTtl] = React34.useState(null);
18879
+ const [ttlError, setTtlError] = React34.useState(false);
18880
+ const [saveError, setSaveError] = React34.useState(null);
18881
+ const [saveSucceeded, setSaveSucceeded] = React34.useState(false);
18882
+ const [isSaving, setIsSaving] = React34.useState(false);
18883
+ const [sweepConfirming, setSweepConfirming] = React34.useState(false);
18884
+ const [sweeping, setSweeping] = React34.useState(false);
18885
+ const ttlErrorId = React34.useId();
18886
+ const ttlHintsId = React34.useId();
18887
+ const sweepTriggerId = React34.useId();
18888
+ const sweepConfirmId = React34.useId();
18889
+ const sweepConfirmTextId = React34.useId();
18890
+ const sweepConfirmButtonId = React34.useId();
18891
+ const mounted = React34.useRef(true);
18892
+ const saving = React34.useRef(false);
18893
+ const invoke = React34.useCallback(async (endpoint, payload = {}, signal) => {
18466
18894
  if (typeof rpcCall !== "function") throw new Error("\u901A\u7528\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
18467
18895
  return unwrapRpcResult16(await rpcCall(endpoint, payload, signal));
18468
18896
  }, [rpcCall]);
18469
- const loadSettings = React33.useCallback(async ({ signal } = {}) => {
18897
+ const loadSettings = React34.useCallback(async ({ signal } = {}) => {
18470
18898
  setPhase("loading");
18471
18899
  setLoadError(null);
18472
18900
  try {
@@ -18490,7 +18918,7 @@ function GlobalSettingsPanel({ rpcCall }) {
18490
18918
  setPhase("error");
18491
18919
  }
18492
18920
  }, [invoke]);
18493
- React33.useEffect(() => {
18921
+ React34.useEffect(() => {
18494
18922
  mounted.current = true;
18495
18923
  const controller = new AbortController();
18496
18924
  void loadSettings({ signal: controller.signal });
@@ -18499,7 +18927,7 @@ function GlobalSettingsPanel({ rpcCall }) {
18499
18927
  controller.abort();
18500
18928
  };
18501
18929
  }, [loadSettings]);
18502
- React33.useEffect(() => {
18930
+ React34.useEffect(() => {
18503
18931
  if (!sweepConfirming) return;
18504
18932
  globalThis.document?.getElementById(sweepConfirmButtonId)?.focus();
18505
18933
  }, [sweepConfirmButtonId, sweepConfirming]);
@@ -19301,6 +19729,15 @@ var CSS15 = String.raw`
19301
19729
  .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
19730
  .dim-feishuGroupError, .dim-feishuGroupRefreshError { margin: 0; padding: 9px 11px; border-radius: 8px; font-size: 12px; line-height: 18px; }
19303
19731
  .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)); }
19732
+ .dim-feishuPanelList { display: grid; gap: 7px; margin: 0; padding: 0; list-style: none; }
19733
+ .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); }
19734
+ .dim-feishuPanelIndex { min-width: 18px; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 11px; line-height: 17px; text-align: right; }
19735
+ .dim-feishuPanelCommand { min-width: 0; color: var(--dsw-alias-label-primary, #1f2329); font-size: 12px; line-height: 18px; overflow-wrap: anywhere; }
19736
+ .dim-feishuPanelRowActions, .dim-feishuPanelAdd { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
19737
+ .dim-feishuPanelRow .dim-deliveryButton { min-height: 28px; padding: 0 9px; font-size: 12px; }
19738
+ .dim-feishuPanelAdd { margin-top: 2px; }
19739
+ .dim-feishuPanelAdd .dim-feishuGroupSelect { flex: 1 1 220px; width: auto; }
19740
+ .dim-feishuPanelFooter { display: flex; justify-content: flex-start; }
19304
19741
  .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
19742
  .dim-feishuGroupAuthorizationState { min-height: 126px; grid-template-columns: 32px minmax(0, 1fr); align-items: center; }
19306
19743
  .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 +20248,7 @@ function installSessionChannelLogos(document2 = globalThis.document) {
19811
20248
  }
19812
20249
 
19813
20250
  // plugin-src/client/update-panel.js
19814
- var React34 = __toESM(require("react"), 1);
20251
+ var React35 = __toESM(require("react"), 1);
19815
20252
  var import_react_dom4 = require("react-dom");
19816
20253
  var import_valid = __toESM(require_valid(), 1);
19817
20254
  var import_rcompare = __toESM(require_rcompare(), 1);
@@ -19904,11 +20341,11 @@ function manualUpdateCommand(snapshot) {
19904
20341
  return `dsh plugin --profile ${profileArgument} add -w @xmanrui/dsh-im@${version}`;
19905
20342
  }
19906
20343
  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(() => {
20344
+ const [copyState, setCopyState] = React35.useState("idle");
20345
+ const commandRef = React35.useRef(null);
20346
+ const mounted = React35.useRef(false);
20347
+ const copying = React35.useRef(false);
20348
+ React35.useEffect(() => {
19912
20349
  mounted.current = true;
19913
20350
  return () => {
19914
20351
  mounted.current = false;
@@ -19940,7 +20377,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
19940
20377
  { className: "dim-updateManual", "aria-label": "\u624B\u5DE5\u66F4\u65B0" },
19941
20378
  h2("h4", { className: "dim-updateManualHeading" }, "\u624B\u5DE5\u66F4\u65B0"),
19942
20379
  command ? h2(
19943
- React34.Fragment,
20380
+ React35.Fragment,
19944
20381
  null,
19945
20382
  h2("p", { className: "dim-updateManualHint" }, "\u81EA\u52A8\u66F4\u65B0\u5931\u8D25\u53EF\u4EE5\u4F7F\u7528\u547D\u4EE4\u66F4\u65B0\uFF1A"),
19946
20383
  h2(
@@ -19976,7 +20413,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
19976
20413
  "aria-hidden": "true",
19977
20414
  focusable: "false"
19978
20415
  }, copyState === "copied" ? h2("path", { d: "m4 10 4 4 8-8" }) : h2(
19979
- React34.Fragment,
20416
+ React35.Fragment,
19980
20417
  null,
19981
20418
  h2("rect", { x: 7, y: 7, width: 10, height: 11, rx: 1.5 }),
19982
20419
  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 +20438,10 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
20001
20438
  );
20002
20439
  }
20003
20440
  function UpdateDialog({ children, onClose }) {
20004
- const dialogRef = React34.useRef(null);
20005
- const titleId = React34.useId();
20006
- const descriptionId = React34.useId();
20007
- React34.useEffect(() => {
20441
+ const dialogRef = React35.useRef(null);
20442
+ const titleId = React35.useId();
20443
+ const descriptionId = React35.useId();
20444
+ React35.useEffect(() => {
20008
20445
  const previous = globalThis.document?.activeElement;
20009
20446
  dialogRef.current?.focus?.();
20010
20447
  return () => {
@@ -20062,20 +20499,20 @@ function UpdateDialog({ children, onClose }) {
20062
20499
  return typeof document !== "undefined" && document.body ? (0, import_react_dom4.createPortal)(content, document.body) : content;
20063
20500
  }
20064
20501
  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);
20502
+ const tooltipId = React35.useId();
20503
+ const [snapshot, setSnapshot] = React35.useState(null);
20504
+ const [action, setAction] = React35.useState("status");
20505
+ const [error, setError] = React35.useState(null);
20506
+ const [open, setOpen] = React35.useState(false);
20507
+ const [uncertainInstall, setUncertainInstall] = React35.useState(false);
20508
+ const mounted = React35.useRef(false);
20509
+ const busy = React35.useRef(false);
20510
+ const readController = React35.useRef(null);
20511
+ const pollReadController = React35.useRef(null);
20512
+ const installRequest = React35.useRef(null);
20513
+ const onStatusRef = React35.useRef(onStatus);
20077
20514
  onStatusRef.current = onStatus;
20078
- const accept = React34.useCallback((next) => {
20515
+ const accept = React35.useCallback((next) => {
20079
20516
  setSnapshot(next);
20080
20517
  onStatusRef.current?.(next);
20081
20518
  }, []);
@@ -20084,7 +20521,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20084
20521
  setUncertainInstall(false);
20085
20522
  accept(next);
20086
20523
  };
20087
- const invoke = React34.useCallback(async (endpoint, payload = {}, signal) => {
20524
+ const invoke = React35.useCallback(async (endpoint, payload = {}, signal) => {
20088
20525
  if (typeof rpcCall !== "function") {
20089
20526
  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
20527
  unavailable.code = "update-unavailable";
@@ -20092,7 +20529,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20092
20529
  }
20093
20530
  return unwrapSnapshot(await rpcCall(endpoint, payload, signal));
20094
20531
  }, [rpcCall]);
20095
- React34.useEffect(() => {
20532
+ React35.useEffect(() => {
20096
20533
  mounted.current = true;
20097
20534
  busy.current = true;
20098
20535
  const controller = new AbortController();
@@ -20115,7 +20552,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20115
20552
  const activeJob = ACTIVE_STATES4.has(snapshot?.job?.state);
20116
20553
  const restartRequired = snapshot?.job?.state === "restart-required" || snapshot?.blockedReason === "pending-restart";
20117
20554
  const shouldPoll = activeJob || uncertainInstall;
20118
- React34.useEffect(() => {
20555
+ React35.useEffect(() => {
20119
20556
  if (!shouldPoll) return void 0;
20120
20557
  let controller;
20121
20558
  const scheduler = createPollScheduler({
@@ -20216,7 +20653,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20216
20653
  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
20654
  const buttonDescription = localizeText(buttonLabel) + (buttonLabel === "\u66F4\u65B0\u81F3" ? ` v${snapshot.latestVersion}` : "");
20218
20655
  return h2(
20219
- React34.Fragment,
20656
+ React35.Fragment,
20220
20657
  null,
20221
20658
  h2(
20222
20659
  "span",
@@ -20266,25 +20703,25 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20266
20703
  h2("dt", null, "\u8FD0\u884C\u7248\u672C"),
20267
20704
  h2("dd", null, `v${snapshot?.runningVersion ?? clientVersion}`),
20268
20705
  snapshot?.installedVersion && snapshot.installedVersion !== snapshot.runningVersion ? h2(
20269
- React34.Fragment,
20706
+ React35.Fragment,
20270
20707
  null,
20271
20708
  h2("dt", null, "\u5DF2\u5B89\u88C5\u7248\u672C"),
20272
20709
  h2("dd", null, `v${snapshot.installedVersion}`)
20273
20710
  ) : null,
20274
20711
  targetVersion ? h2(
20275
- React34.Fragment,
20712
+ React35.Fragment,
20276
20713
  null,
20277
20714
  h2("dt", null, "\u76EE\u6807\u7248\u672C"),
20278
20715
  h2("dd", null, `v${targetVersion}`)
20279
20716
  ) : null,
20280
20717
  latestVersion ? h2(
20281
- React34.Fragment,
20718
+ React35.Fragment,
20282
20719
  null,
20283
20720
  h2("dt", null, "\u6700\u65B0\u7248\u672C"),
20284
20721
  h2("dd", null, `v${latestVersion}`)
20285
20722
  ) : null,
20286
20723
  historicalTargetVersion ? h2(
20287
- React34.Fragment,
20724
+ React35.Fragment,
20288
20725
  null,
20289
20726
  h2("dt", null, "\u4E0A\u6B21\u66F4\u65B0\u76EE\u6807"),
20290
20727
  h2("dd", null, `v${historicalTargetVersion}`)
@@ -20366,8 +20803,8 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
20366
20803
  }
20367
20804
 
20368
20805
  // plugin-src/client/panel-error-boundary.js
20369
- var React35 = __toESM(require("react"), 1);
20370
- var IMPanelErrorBoundary = class extends React35.Component {
20806
+ var React36 = __toESM(require("react"), 1);
20807
+ var IMPanelErrorBoundary = class extends React36.Component {
20371
20808
  state = { failed: false };
20372
20809
  static getDerivedStateFromError() {
20373
20810
  return { failed: true };
@@ -20560,28 +20997,28 @@ function IMSettingsTab({
20560
20997
  browserLocation = globalThis.location,
20561
20998
  navigateToRecoveryUrl = replacePageLocation
20562
20999
  }) {
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);
21000
+ const [selected, setSelected] = React37.useState(() => preferredSectionId === GLOBAL_SETTINGS_TAB_ID || CHANNELS.some((channel7) => channel7.id === preferredSectionId) ? preferredSectionId : "weixin");
21001
+ const [loopbackRecovery, setLoopbackRecovery] = React37.useState(null);
21002
+ const [runningVersion, setRunningVersion] = React37.useState(IM_PLUGIN_VERSION);
21003
+ const [deliverySettings, setDeliverySettings] = React37.useState(null);
20567
21004
  const emailEnabled = useEmailChannelEnabled(emailRpcCall);
20568
- const visibleChannels = React36.useMemo(
21005
+ const visibleChannels = React37.useMemo(
20569
21006
  () => CHANNELS.filter((channel7) => channel7.id !== "email" || emailEnabled),
20570
21007
  [emailEnabled]
20571
21008
  );
20572
- const githubTooltipId = React36.useId();
20573
- const generalSettingsTooltipId = React36.useId();
21009
+ const githubTooltipId = React37.useId();
21010
+ const generalSettingsTooltipId = React37.useId();
20574
21011
  const globalSettingsSelected = selected === GLOBAL_SETTINGS_TAB_ID;
20575
21012
  const active = visibleChannels.find((channel7) => channel7.id === selected) ?? visibleChannels[0];
20576
21013
  const activeTabId = globalSettingsSelected ? "dim-general-settings-trigger" : `dim-tab-${active.id}`;
20577
21014
  const activePanelId = globalSettingsSelected ? `dim-panel-${GLOBAL_SETTINGS_TAB_ID}` : `dim-panel-${active.id}`;
20578
- const reportLoopbackRecovery = React36.useCallback((recovery) => {
21015
+ const reportLoopbackRecovery = React37.useCallback((recovery) => {
20579
21016
  setLoopbackRecovery((current) => current?.url === recovery.url ? current : recovery);
20580
21017
  }, []);
20581
- const reportUpdateStatus = React36.useCallback((snapshot) => {
21018
+ const reportUpdateStatus = React37.useCallback((snapshot) => {
20582
21019
  setRunningVersion(snapshot.runningVersion);
20583
21020
  }, []);
20584
- const rpcCalls = React36.useMemo(() => createLoopbackAwareRpcCalls({
21021
+ const rpcCalls = React37.useMemo(() => createLoopbackAwareRpcCalls({
20585
21022
  dingtalkRpcCall,
20586
21023
  discordRpcCall,
20587
21024
  feishuRpcCall,
@@ -20623,7 +21060,7 @@ function IMSettingsTab({
20623
21060
  weixinRpcCall,
20624
21061
  whatsappRpcCall
20625
21062
  ]);
20626
- const botSettingsContext = React36.useMemo(() => Object.freeze({
21063
+ const botSettingsContext = React37.useMemo(() => Object.freeze({
20627
21064
  openBotSettings: setDeliverySettings
20628
21065
  }), []);
20629
21066
  return h2(
@@ -20847,7 +21284,7 @@ function apply(ctx) {
20847
21284
  };
20848
21285
  const localeSnapshot = () => ctx.locale.getLocale?.()?.active ?? "";
20849
21286
  function IMPanel({ preferredSectionId }) {
20850
- React36.useSyncExternalStore(subscribeLocale, localeSnapshot, localeSnapshot);
21287
+ React37.useSyncExternalStore(subscribeLocale, localeSnapshot, localeSnapshot);
20851
21288
  return h2(
20852
21289
  IMPanelErrorBoundary,
20853
21290
  null,