@xmanrui/dsh-im 4.3.0 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.en.md +2 -2
  2. package/README.md +2 -2
  3. package/lib/client.js +976 -634
  4. package/lib/index.js +241 -238
  5. package/package.json +1 -1
  6. package/plugin-src/client/access-policy-settings.js +351 -0
  7. package/plugin-src/client/channel-card-meta.js +2 -1
  8. package/plugin-src/client/channels/dingtalk/api.js +5 -0
  9. package/plugin-src/client/channels/dingtalk/index.js +1 -0
  10. package/plugin-src/client/channels/feishu/api.js +5 -0
  11. package/plugin-src/client/channels/feishu/index.js +1 -0
  12. package/plugin-src/client/channels/qq/api.js +5 -0
  13. package/plugin-src/client/channels/qq/index.js +1 -0
  14. package/plugin-src/client/channels/shared/token-api.js +5 -0
  15. package/plugin-src/client/channels/shared/token-channel.js +1 -0
  16. package/plugin-src/client/channels/telegram/api.js +2 -17
  17. package/plugin-src/client/channels/telegram/index.js +0 -112
  18. package/plugin-src/client/channels/telegram/styles.js +0 -28
  19. package/plugin-src/client/channels/wecom/api.js +5 -0
  20. package/plugin-src/client/channels/wecom/index.js +1 -0
  21. package/plugin-src/client/channels/weixin/api.js +5 -0
  22. package/plugin-src/client/channels/weixin/index.js +1 -0
  23. package/plugin-src/client/channels/whatsapp/api.js +4 -10
  24. package/plugin-src/client/channels/whatsapp/index.js +1 -125
  25. package/plugin-src/client/channels/whatsapp/styles.js +0 -25
  26. package/plugin-src/client/context-enhancement.js +19 -5
  27. package/plugin-src/client/delivery-settings.js +61 -9
  28. package/plugin-src/client/i18n.js +61 -2
  29. package/plugin-src/client/index.js +1 -0
  30. package/plugin-src/client/styles.js +50 -4
  31. package/plugin-src/host/channels/dingtalk/production.mjs +12 -1
  32. package/plugin-src/host/channels/dingtalk/rpc.mjs +11 -0
  33. package/plugin-src/host/channels/feishu/production.mjs +39 -1
  34. package/plugin-src/host/channels/feishu/rpc.mjs +19 -2
  35. package/plugin-src/host/channels/qq/production.mjs +12 -1
  36. package/plugin-src/host/channels/qq/rpc.mjs +11 -0
  37. package/plugin-src/host/channels/shared/access-policy-production.mjs +137 -0
  38. package/plugin-src/host/channels/shared/access-policy-rpc.mjs +17 -0
  39. package/plugin-src/host/channels/shared/production.mjs +15 -1
  40. package/plugin-src/host/channels/shared/rpc.mjs +9 -0
  41. package/plugin-src/host/channels/slack/production.mjs +12 -1
  42. package/plugin-src/host/channels/slack/rpc.mjs +10 -0
  43. package/plugin-src/host/channels/telegram/rpc.mjs +2 -49
  44. package/plugin-src/host/channels/wecom/production.mjs +12 -1
  45. package/plugin-src/host/channels/wecom/rpc.mjs +11 -0
  46. package/plugin-src/host/channels/weixin/production.mjs +12 -1
  47. package/plugin-src/host/channels/weixin/rpc.mjs +11 -0
  48. package/plugin-src/host/channels/whatsapp/production.mjs +16 -2
  49. package/plugin-src/host/channels/whatsapp/rpc.mjs +10 -15
  50. package/plugin-src/host/modern-harness-api.mjs +3 -0
  51. package/src/channels/dingtalk/dingtalk-bridge.mjs +70 -12
  52. package/src/channels/dingtalk/dingtalk-runtime.mjs +4 -0
  53. package/src/channels/discord/discord-runtime.mjs +29 -1
  54. package/src/channels/feishu/bridge.mjs +207 -82
  55. package/src/channels/feishu/feishu-cards.mjs +2 -2
  56. package/src/channels/feishu/feishu-channel.mjs +36 -6
  57. package/src/channels/feishu/feishu-runtime.mjs +4 -0
  58. package/src/channels/qq/qq-bridge.mjs +67 -20
  59. package/src/channels/qq/qq-runtime.mjs +20 -2
  60. package/src/channels/shared/access-policy.mjs +210 -0
  61. package/src/channels/shared/bot-workspace-store.mjs +181 -33
  62. package/src/channels/shared/command-permission.mjs +32 -0
  63. package/src/channels/shared/compact-command.mjs +5 -2
  64. package/src/channels/shared/context-enhancement.mjs +9 -4
  65. package/src/channels/shared/harness-client.mjs +6 -0
  66. package/src/channels/shared/i18n-en/feishu.mjs +3 -3
  67. package/src/channels/shared/i18n-en/shared-a.mjs +2 -1
  68. package/src/channels/shared/i18n-en/shared-b.mjs +6 -3
  69. package/src/channels/shared/i18n-en/shared-c.mjs +2 -0
  70. package/src/channels/shared/inbound-access.mjs +43 -0
  71. package/src/channels/shared/session-title.mjs +74 -0
  72. package/src/channels/shared/text-harness-bridge.mjs +54 -6
  73. package/src/channels/shared/workspace-command.mjs +26 -5
  74. package/src/channels/shared/workspace-session.mjs +28 -2
  75. package/src/channels/slack/slack-runtime.mjs +4 -0
  76. package/src/channels/telegram/telegram-runtime.mjs +6 -13
  77. package/src/channels/wecom/wecom-bridge.mjs +57 -6
  78. package/src/channels/wecom/wecom-runtime.mjs +4 -0
  79. package/src/channels/weixin/weixin-bridge.mjs +67 -19
  80. package/src/channels/weixin/weixin-runtime.mjs +4 -0
  81. package/src/channels/whatsapp/whatsapp-runtime.mjs +42 -20
package/lib/client.js CHANGED
@@ -571,7 +571,7 @@ var React23 = __toESM(require("react"), 1);
571
571
  // package.json
572
572
  var package_default = {
573
573
  name: "@xmanrui/dsh-im",
574
- version: "4.3.0",
574
+ version: "4.5.0",
575
575
  description: "\u628A\u4E5D\u79CD IM \u673A\u5668\u4EBA\u548C\u516C\u7F51 AI Office \u63A5\u5165\u672C\u673A DeepSeek Harness\u3002 Connect nine IM channels and a public AI Office to a local DeepSeek Harness.",
576
576
  keywords: [
577
577
  "deepseek-harness",
@@ -841,6 +841,62 @@ var EN = Object.freeze({
841
841
  "IM\u673A\u5668\u4EBA": "IM bots",
842
842
  "IM\u673A\u5668\u4EBA\u8BBE\u7F6E": "IM bot settings",
843
843
  "\u66F4\u591A\u673A\u5668\u4EBA\u8BBE\u7F6E": "More bot settings",
844
+ "\u673A\u5668\u4EBA\u8BBE\u7F6E": "Bot settings",
845
+ "\u673A\u5668\u4EBA\u8BBE\u7F6E\u9875\u7B7E": "Bot settings tabs",
846
+ "\u6295\u9012\u8BBE\u7F6E": "Delivery settings",
847
+ "\u8BBF\u95EE\u8BBE\u7F6E": "Access settings",
848
+ "\u67E5\u770B\u8BBF\u95EE\u6743\u9650\u8BF4\u660E": "View access permission details",
849
+ "\u5141\u8BB8\u6240\u6709\u7528\u6237": "Allow all users",
850
+ "\u4EC5\u767D\u540D\u5355\u7528\u6237": "Allowlisted users only",
851
+ "\u9ED8\u8BA4\u547D\u4EE4\u6743\u9650": "Default command permission",
852
+ "\u547D\u4EE4\u6743\u9650": "Command permission",
853
+ "\u53EF\u4EE5\u6267\u884C\u547D\u4EE4": "Can run commands",
854
+ "\u4E0D\u53EF\u4EE5\u6267\u884C\u547D\u4EE4": "Cannot run commands",
855
+ "\u767D\u540D\u5355\u7528\u6237": "Allowlisted users",
856
+ "\u67E5\u770B\u767D\u540D\u5355\u8BF4\u660E": "View allowlist details",
857
+ "\u547D\u4EE4\u6743\u9650\u4F8B\u5916": "Command permission exceptions",
858
+ "\u5F53\u524D\u6CA1\u6709\u767D\u540D\u5355\u7528\u6237\uFF0C\u4FDD\u5B58\u540E\u666E\u901A\u7528\u6237\u5C06\u65E0\u6CD5\u4F7F\u7528\u673A\u5668\u4EBA\u3002": "There are currently no allowlisted users. After saving, regular users will not be able to use the bot.",
859
+ "\u65B0\u589E\u7528\u6237": "Add user",
860
+ "\u5C1A\u672A\u6DFB\u52A0\u7528\u6237": "No users added",
861
+ "\u5F53\u524D\u6E20\u9053\u4E0D\u652F\u6301\u7FA4\u804A": "Group chat is not supported by this channel",
862
+ "\u539F\u6240\u6709\u8005\u6216\u626B\u7801\u63A5\u5165\u8005\u59CB\u7EC8\u53EF\u4EE5\u8BBF\u95EE\u5E76\u6267\u884C\u547D\u4EE4\uFF1B\u4EE5\u4E0B\u8BBE\u7F6E\u4EC5\u7EA6\u675F\u5176\u4ED6\u7528\u6237\u3002": "The original owner or QR-code operator can always access the bot and run commands; the settings below apply only to other users.",
863
+ "\u6B64\u533A\u57DF\u65E0\u9700\u914D\u7F6E\uFF0C\u4FDD\u5B58\u79C1\u804A\u8BBE\u7F6E\u65F6\u4F1A\u4FDD\u7559\u73B0\u6709\u7FA4\u804A\u7B56\u7565\u3002": "No setup is needed here. Saving direct-message settings keeps the existing group policy.",
864
+ "\u8BBF\u95EE\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002": "Access settings saved.",
865
+ "\u8BBF\u95EE\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002": "Access settings are currently unavailable.",
866
+ "\u8BBF\u95EE\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002": "Could not save access settings. Try again later.",
867
+ "\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u5DF2\u4FDD\u5B58\u7684\u8BBF\u95EE\u7B56\u7565\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5\u3002": "The service did not return the saved access policy. Refresh and try again.",
868
+ "\u8BBF\u95EE\u7B56\u7565\u5C1A\u672A\u5C31\u7EEA\uFF0C\u8BF7\u8FD4\u56DE\u673A\u5668\u4EBA\u5217\u8868\u5237\u65B0\u540E\u91CD\u8BD5\u3002": "The access policy is not ready. Return to the bot list, refresh, and try again.",
869
+ "\u5F53\u524D\u6E20\u9053\u6682\u4E0D\u652F\u6301\u8BBF\u95EE\u8BBE\u7F6E\u3002": "Access settings are not supported by this channel yet.",
870
+ "\u7528\u6237\u6807\u8BC6\u65E0\u6548\u3002": "The user ID is invalid.",
871
+ "\u7528\u6237\u6807\u8BC6\u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u3002": "The user ID must be a string.",
872
+ "\u7528\u6237\u6807\u8BC6\u4E0D\u80FD\u4E3A\u7A7A\u3001\u5305\u542B\u63A7\u5236\u5B57\u7B26\u6216\u8D85\u8FC7 256 \u4E2A\u5B57\u7B26\u3002": "The user ID cannot be empty, contain control characters, or exceed 256 characters.",
873
+ "\u7528\u6237\u6761\u76EE\u5FC5\u987B\u5305\u542B\u7528\u6237\u6807\u8BC6\u548C\u547D\u4EE4\u6743\u9650\u3002": "Each user entry must include a user ID and command permission.",
874
+ "\u547D\u4EE4\u6743\u9650\u5FC5\u987B\u662F\u5E03\u5C14\u503C\u3002": "Command permission must be a boolean.",
875
+ "\u8BBF\u95EE\u6A21\u5F0F\u53EA\u80FD\u662F open \u6216 allowlist\u3002": "Access mode must be open or allowlist.",
876
+ "\u5F00\u653E\u6A21\u5F0F\u8BBE\u7F6E\u5FC5\u987B\u5B8C\u6574\u3002": "Open-mode settings must be complete.",
877
+ "\u5F00\u653E\u6A21\u5F0F\u9ED8\u8BA4\u547D\u4EE4\u6743\u9650\u5FC5\u987B\u662F\u5E03\u5C14\u503C\u3002": "The open-mode default command permission must be a boolean.",
878
+ "\u5F00\u653E\u6A21\u5F0F\u547D\u4EE4\u6743\u9650\u8986\u76D6\u7528\u6237\u5FC5\u987B\u662F\u6570\u7EC4\u3002": "Open-mode command permission overrides must be an array.",
879
+ "\u5F00\u653E\u6A21\u5F0F\u547D\u4EE4\u6743\u9650\u8986\u76D6\u7528\u6237\u4E0D\u80FD\u5305\u542B\u91CD\u590D\u7684\u7528\u6237\u6807\u8BC6\u3002": "Open-mode command permission overrides cannot contain duplicate user IDs.",
880
+ "\u767D\u540D\u5355\u6A21\u5F0F\u8BBE\u7F6E\u5FC5\u987B\u5B8C\u6574\u3002": "Allowlist-mode settings must be complete.",
881
+ "\u767D\u540D\u5355\u6A21\u5F0F\u7528\u6237\u5FC5\u987B\u662F\u6570\u7EC4\u3002": "Allowlist-mode users must be an array.",
882
+ "\u767D\u540D\u5355\u6A21\u5F0F\u7528\u6237\u4E0D\u80FD\u5305\u542B\u91CD\u590D\u7684\u7528\u6237\u6807\u8BC6\u3002": "Allowlist-mode users cannot contain duplicate user IDs.",
883
+ "\u8BBF\u95EE\u573A\u666F\u8BBE\u7F6E\u5FC5\u987B\u540C\u65F6\u5305\u542B\u6A21\u5F0F\u3001\u5F00\u653E\u6A21\u5F0F\u8BBE\u7F6E\u548C\u767D\u540D\u5355\u6A21\u5F0F\u8BBE\u7F6E\u3002": "Each access context must include its mode, open-mode settings, and allowlist-mode settings.",
884
+ "\u8BF7\u540C\u65F6\u63D0\u4EA4\u5B8C\u6574\u7684\u79C1\u804A\u548C\u7FA4\u804A\u8BBF\u95EE\u8BBE\u7F6E\u3002": "Submit complete direct-message and group access settings together.",
885
+ "\u586B\u5199\u5FAE\u4FE1\u7528\u6237 ID": "Enter a WeChat user ID",
886
+ "\u98DE\u4E66 Open ID": "Feishu Open ID",
887
+ "\u7FA4\u6210\u5458 Open ID": "Group member Open ID",
888
+ "\u9489\u9489\u7528\u6237 ID": "DingTalk user ID",
889
+ "\u586B\u5199 senderStaffId \u6216 senderId": "Enter senderStaffId or senderId",
890
+ "\u7FA4\u6210\u5458\u7528\u6237 ID": "Group member user ID",
891
+ "\u4F01\u4E1A\u5FAE\u4FE1\u7528\u6237 ID": "WeCom user ID",
892
+ "\u586B\u5199 userid": "Enter userid",
893
+ "\u586B\u5199 member_openid": "Enter member_openid",
894
+ "QQ User Open ID": "QQ User Open ID",
895
+ "\u7FA4\u6210\u5458 User ID": "Group member User ID",
896
+ "\u586B\u5199\u6570\u5B57 User ID": "Enter a numeric user ID",
897
+ "WhatsApp \u7535\u8BDD\u53F7\u7801\u6216 JID": "WhatsApp phone number or JID",
898
+ "\u7FA4\u6210\u5458\u7535\u8BDD\u53F7\u7801\u6216 JID": "Group member phone number or JID",
899
+ "8613800000000 \u6216\u5B8C\u6574 JID": "8613800000000 or a full JID",
844
900
  "IM \u6E20\u9053": "IM channels",
845
901
  "\u8BA9 DeepSeek Harness \u89E6\u624B\u53EF\u53CA": "Connecting DeepSeek Harness",
846
902
  "\u5F53\u524D\u7248\u672C": "Current version",
@@ -1066,6 +1122,10 @@ var EN = Object.freeze({
1066
1122
  "\u67E5\u770B\u7FA4\u804A\u53D1\u9001\u8005\u6635\u79F0\u5B57\u6BB5\u8BF4\u660E": "View group sender name field details",
1067
1123
  "\u67E5\u770B\u79C1\u804A\u53D1\u9001\u8005\u6635\u79F0\u5B57\u6BB5\u8BF4\u660E": "View direct sender name field details",
1068
1124
  "\u8BE5\u5B57\u6BB5\u4E0D\u662F\u6BCF\u4E2A\u6E20\u9053\u90FD\u80FD\u63D0\u4F9B\u3002\u5F53\u524D\u6D88\u606F\u6CA1\u6709\u53D1\u9001\u8005\u6635\u79F0\u65F6\uFF0C\u5373\u4F7F\u5DF2\u9009\u62E9\u8BE5\u5B57\u6BB5\uFF0C<dsh_im_source> \u4E2D\u4E5F\u4F1A\u7701\u7565 senderName\u3002": "This field is not available on every channel. If the current message has no sender name, <dsh_im_source> omits senderName even when the field is selected.",
1125
+ "\u4F1A\u8BDD\u6807\u9898": "Conversation title",
1126
+ "\u67E5\u770B\u7FA4\u804A\u4F1A\u8BDD\u6807\u9898\u5B57\u6BB5\u8BF4\u660E": "View group conversation title field details",
1127
+ "\u67E5\u770B\u79C1\u804A\u4F1A\u8BDD\u6807\u9898\u5B57\u6BB5\u8BF4\u660E": "View direct conversation title field details",
1128
+ "\u8BE5\u5B57\u6BB5\u4E0D\u662F\u6BCF\u4E2A\u6E20\u9053\u90FD\u80FD\u63D0\u4F9B\u3002\u9489\u9489\u7FA4\u804A\u4F1A\u5E26\u4E0A\u7FA4\u540D\u3002\u5F53\u524D\u6D88\u606F\u6CA1\u6709\u4F1A\u8BDD\u6807\u9898\u65F6\uFF0C\u5373\u4F7F\u5DF2\u9009\u62E9\u8BE5\u5B57\u6BB5\uFF0C<dsh_im_source> \u4E2D\u4E5F\u4F1A\u7701\u7565 conversationTitle\u3002": "This field is not available on every channel. DingTalk group chats include the group name. If the current message has no conversation title, <dsh_im_source> omits conversationTitle even when the field is selected.",
1069
1129
  "\u673A\u5668\u4EBA\u6807\u8BC6": "Bot ID",
1070
1130
  "\u589E\u5F3A\u63D0\u793A\u8BCD": "Guidance",
1071
1131
  "\u67E5\u770B\u589E\u5F3A\u63D0\u793A\u8BCD\u4F7F\u7528\u8BF4\u660E": "View guidance instructions",
@@ -1093,7 +1153,7 @@ var EN = Object.freeze({
1093
1153
  "\u4E0A\u4E0B\u6587\u589E\u5F3A\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002": "Could not save context enhancement. Try again.",
1094
1154
  "\u8BF7\u63D0\u4EA4\u5B8C\u6574\u7684\u4E0A\u4E0B\u6587\u589E\u5F3A\u8BBE\u7F6E\u3002": "Submit the complete context enhancement settings.",
1095
1155
  "\u7FA4\u804A\u548C\u79C1\u804A\u5F00\u5173\u5FC5\u987B\u662F\u5E03\u5C14\u503C\u3002": "Group and direct switches must be booleans.",
1096
- "\u6765\u6E90\u5B57\u6BB5\u53EA\u80FD\u9009\u62E9\u5DF2\u5B9A\u4E49\u7684\u4E94\u4E2A\u5B57\u6BB5\u3002": "Source fields must be chosen from the five defined fields.",
1156
+ "\u6765\u6E90\u5B57\u6BB5\u53EA\u80FD\u9009\u62E9\u5DF2\u5B9A\u4E49\u7684\u516D\u4E2A\u5B57\u6BB5\u3002": "Source fields must be chosen from the six defined fields.",
1097
1157
  "\u4FDD\u5B58\u4E2D\u2026": "Saving\u2026",
1098
1158
  "\u672A\u8BBE\u7F6E": "Not set",
1099
1159
  "\u5DE5\u4F5C\u533A\u4FEE\u6539\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002": "Could not update the workspace. Try again.",
@@ -1355,7 +1415,6 @@ var EN = Object.freeze({
1355
1415
  "\u5148\u901A\u8FC7 @BotFather \u83B7\u53D6 Bot Token\uFF0C\u518D\u5728\u8FD9\u91CC\u5B8C\u6210\u63A5\u5165\u3002": "Get a Bot Token from @BotFather, then connect it here.",
1356
1416
  "\u586B\u5199 @BotFather \u751F\u6210\u7684 Bot Token": "Enter the Bot Token from @BotFather",
1357
1417
  "\u8BBF\u95EE\u6A21\u5F0F": "Access mode",
1358
- "\u8BBF\u95EE\u8BBE\u7F6E": "Access settings",
1359
1418
  "Telegram \u8BBF\u95EE\u6A21\u5F0F": "Telegram access mode",
1360
1419
  "\u67E5\u770B Telegram \u8BBF\u95EE\u6A21\u5F0F\u8BF4\u660E": "View Telegram access mode details",
1361
1420
  "\u7FA4\u804A\u5168\u90E8\u5FFD\u7565\uFF0C\u79C1\u804A\u4EC5\u5141\u8BB8\u767D\u540D\u5355\u7528\u6237\u3002": "All group messages are ignored; only allowlisted users may send DMs.",
@@ -1885,12 +1944,142 @@ function normalizeLastMessageError(value) {
1885
1944
  return code && reason && message && referenceId && at !== null ? { code, reason, message, referenceId, at } : null;
1886
1945
  }
1887
1946
 
1947
+ // src/channels/shared/access-policy.mjs
1948
+ var ACCESS_POLICY_MODES = Object.freeze(["open", "allowlist"]);
1949
+ var ACCESS_POLICY_CONVERSATION_TYPES = Object.freeze(["direct", "group"]);
1950
+ var ACCESS_POLICY_USER_ID_MAX_LENGTH = 256;
1951
+ var POLICY_KEYS = ["direct", "group"];
1952
+ var SCOPE_KEYS = ["mode", "open", "allowlist"];
1953
+ var OPEN_KEYS = ["defaultCanExecuteCommands", "commandPermissionOverrides"];
1954
+ var ALLOWLIST_KEYS = ["users"];
1955
+ var USER_KEYS = ["id", "canExecuteCommands"];
1956
+ var CONTROL_CHARACTERS = /[\u0000-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/;
1957
+ function invalidAccessPolicy(message) {
1958
+ const error = new TypeError(message);
1959
+ error.code = "access-policy-invalid";
1960
+ return error;
1961
+ }
1962
+ function hasExactKeys(input, keys) {
1963
+ return input && typeof input === "object" && !Array.isArray(input) && [Object.prototype, null].includes(Object.getPrototypeOf(input)) && Reflect.ownKeys(input).length === keys.length && keys.every((key) => Object.hasOwn(input, key));
1964
+ }
1965
+ function normalizeAccessPolicyUserId(value) {
1966
+ if (typeof value === "number") {
1967
+ if (!Number.isFinite(value)) throw invalidAccessPolicy("\u7528\u6237\u6807\u8BC6\u65E0\u6548\u3002");
1968
+ value = String(value);
1969
+ } else if (typeof value === "bigint") {
1970
+ value = String(value);
1971
+ }
1972
+ if (typeof value !== "string") throw invalidAccessPolicy("\u7528\u6237\u6807\u8BC6\u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u3002");
1973
+ const id5 = value.trim();
1974
+ if (!id5 || id5.length > ACCESS_POLICY_USER_ID_MAX_LENGTH || CONTROL_CHARACTERS.test(id5)) {
1975
+ throw invalidAccessPolicy(`\u7528\u6237\u6807\u8BC6\u4E0D\u80FD\u4E3A\u7A7A\u3001\u5305\u542B\u63A7\u5236\u5B57\u7B26\u6216\u8D85\u8FC7 ${ACCESS_POLICY_USER_ID_MAX_LENGTH} \u4E2A\u5B57\u7B26\u3002`);
1976
+ }
1977
+ return id5;
1978
+ }
1979
+ function validateAccessPolicyUser(input) {
1980
+ if (!hasExactKeys(input, USER_KEYS)) {
1981
+ throw invalidAccessPolicy("\u7528\u6237\u6761\u76EE\u5FC5\u987B\u5305\u542B\u7528\u6237\u6807\u8BC6\u548C\u547D\u4EE4\u6743\u9650\u3002");
1982
+ }
1983
+ if (typeof input.canExecuteCommands !== "boolean") {
1984
+ throw invalidAccessPolicy("\u547D\u4EE4\u6743\u9650\u5FC5\u987B\u662F\u5E03\u5C14\u503C\u3002");
1985
+ }
1986
+ return Object.freeze({
1987
+ id: normalizeAccessPolicyUserId(input.id),
1988
+ canExecuteCommands: input.canExecuteCommands
1989
+ });
1990
+ }
1991
+ function validateUsers(input, { listMessage, duplicateMessage }) {
1992
+ if (!Array.isArray(input)) throw invalidAccessPolicy(listMessage);
1993
+ const users = input.map(validateAccessPolicyUser);
1994
+ if (new Set(users.map(({ id: id5 }) => id5)).size !== users.length) {
1995
+ throw invalidAccessPolicy(duplicateMessage);
1996
+ }
1997
+ return Object.freeze(users);
1998
+ }
1999
+ function validateOpenSettings(input) {
2000
+ if (!hasExactKeys(input, OPEN_KEYS)) {
2001
+ throw invalidAccessPolicy("\u5F00\u653E\u6A21\u5F0F\u8BBE\u7F6E\u5FC5\u987B\u5B8C\u6574\u3002");
2002
+ }
2003
+ if (typeof input.defaultCanExecuteCommands !== "boolean") {
2004
+ throw invalidAccessPolicy("\u5F00\u653E\u6A21\u5F0F\u9ED8\u8BA4\u547D\u4EE4\u6743\u9650\u5FC5\u987B\u662F\u5E03\u5C14\u503C\u3002");
2005
+ }
2006
+ return Object.freeze({
2007
+ defaultCanExecuteCommands: input.defaultCanExecuteCommands,
2008
+ commandPermissionOverrides: validateUsers(input.commandPermissionOverrides, {
2009
+ listMessage: "\u5F00\u653E\u6A21\u5F0F\u547D\u4EE4\u6743\u9650\u8986\u76D6\u7528\u6237\u5FC5\u987B\u662F\u6570\u7EC4\u3002",
2010
+ duplicateMessage: "\u5F00\u653E\u6A21\u5F0F\u547D\u4EE4\u6743\u9650\u8986\u76D6\u7528\u6237\u4E0D\u80FD\u5305\u542B\u91CD\u590D\u7684\u7528\u6237\u6807\u8BC6\u3002"
2011
+ })
2012
+ });
2013
+ }
2014
+ function validateAllowlistSettings(input) {
2015
+ if (!hasExactKeys(input, ALLOWLIST_KEYS)) {
2016
+ throw invalidAccessPolicy("\u767D\u540D\u5355\u6A21\u5F0F\u8BBE\u7F6E\u5FC5\u987B\u5B8C\u6574\u3002");
2017
+ }
2018
+ return Object.freeze({
2019
+ users: validateUsers(input.users, {
2020
+ listMessage: "\u767D\u540D\u5355\u6A21\u5F0F\u7528\u6237\u5FC5\u987B\u662F\u6570\u7EC4\u3002",
2021
+ duplicateMessage: "\u767D\u540D\u5355\u6A21\u5F0F\u7528\u6237\u4E0D\u80FD\u5305\u542B\u91CD\u590D\u7684\u7528\u6237\u6807\u8BC6\u3002"
2022
+ })
2023
+ });
2024
+ }
2025
+ function validateAccessPolicyScope(input) {
2026
+ if (!hasExactKeys(input, SCOPE_KEYS)) {
2027
+ throw invalidAccessPolicy("\u8BBF\u95EE\u573A\u666F\u8BBE\u7F6E\u5FC5\u987B\u540C\u65F6\u5305\u542B\u6A21\u5F0F\u3001\u5F00\u653E\u6A21\u5F0F\u8BBE\u7F6E\u548C\u767D\u540D\u5355\u6A21\u5F0F\u8BBE\u7F6E\u3002");
2028
+ }
2029
+ if (!ACCESS_POLICY_MODES.includes(input.mode)) {
2030
+ throw invalidAccessPolicy("\u8BBF\u95EE\u6A21\u5F0F\u53EA\u80FD\u662F open \u6216 allowlist\u3002");
2031
+ }
2032
+ return Object.freeze({
2033
+ mode: input.mode,
2034
+ open: validateOpenSettings(input.open),
2035
+ allowlist: validateAllowlistSettings(input.allowlist)
2036
+ });
2037
+ }
2038
+ function validateAccessPolicy(input) {
2039
+ if (!hasExactKeys(input, POLICY_KEYS)) {
2040
+ throw invalidAccessPolicy("\u8BF7\u540C\u65F6\u63D0\u4EA4\u5B8C\u6574\u7684\u79C1\u804A\u548C\u7FA4\u804A\u8BBF\u95EE\u8BBE\u7F6E\u3002");
2041
+ }
2042
+ return Object.freeze({
2043
+ direct: validateAccessPolicyScope(input.direct),
2044
+ group: validateAccessPolicyScope(input.group)
2045
+ });
2046
+ }
2047
+ function normalizeAccessPolicy(input) {
2048
+ try {
2049
+ return validateAccessPolicy(input);
2050
+ } catch {
2051
+ return null;
2052
+ }
2053
+ }
2054
+ function createAccessPolicyScope(options) {
2055
+ return validateAccessPolicyScope(options === void 0 ? {
2056
+ mode: "allowlist",
2057
+ open: {
2058
+ defaultCanExecuteCommands: false,
2059
+ commandPermissionOverrides: []
2060
+ },
2061
+ allowlist: { users: [] }
2062
+ } : options);
2063
+ }
2064
+ var DENY_SCOPE = createAccessPolicyScope();
2065
+ var DEFAULT_ACCESS_POLICY = Object.freeze({
2066
+ direct: DENY_SCOPE,
2067
+ group: DENY_SCOPE
2068
+ });
2069
+ var ALLOWED = Object.freeze({ allowed: true, reason: "allowed" });
2070
+ var POLICY_UNAVAILABLE = Object.freeze({ allowed: false, reason: "policy-unavailable" });
2071
+ var INVALID_CONTEXT = Object.freeze({ allowed: false, reason: "invalid-context" });
2072
+ var SENDER_UNAVAILABLE = Object.freeze({ allowed: false, reason: "sender-unavailable" });
2073
+ var SENDER_NOT_ALLOWED = Object.freeze({ allowed: false, reason: "sender-not-allowed" });
2074
+ var COMMAND_NOT_ALLOWED = Object.freeze({ allowed: false, reason: "command-not-allowed" });
2075
+
1888
2076
  // src/channels/shared/context-enhancement.mjs
1889
2077
  var CONTEXT_ENHANCEMENT_FIELDS = Object.freeze([
1890
2078
  "channel",
1891
2079
  "conversationType",
1892
2080
  "senderId",
1893
2081
  "senderName",
2082
+ "conversationTitle",
1894
2083
  "botId"
1895
2084
  ]);
1896
2085
  var CONTEXT_ENHANCEMENT_GUIDANCE_MAX_LENGTH = 8e3;
@@ -1911,18 +2100,18 @@ var DEFAULT_CONTEXT_ENHANCEMENT_CONFIG = Object.freeze({
1911
2100
  })
1912
2101
  });
1913
2102
  var CONFIG_KEYS = ["group", "direct"];
1914
- var SCOPE_KEYS = ["enabled", "fields", "guidance"];
2103
+ var SCOPE_KEYS2 = ["enabled", "fields", "guidance"];
1915
2104
  var LEGACY_CONFIG_KEYS = ["groupEnabled", "directEnabled", "fields", "guidance"];
1916
2105
  function invalidConfig(message) {
1917
2106
  const error = new TypeError(message);
1918
2107
  error.code = "context-enhancement-invalid";
1919
2108
  return error;
1920
2109
  }
1921
- function hasExactKeys(input, keys) {
2110
+ function hasExactKeys2(input, keys) {
1922
2111
  return input && typeof input === "object" && !Array.isArray(input) && [Object.prototype, null].includes(Object.getPrototypeOf(input)) && Reflect.ownKeys(input).length === keys.length && keys.every((key) => Object.hasOwn(input, key));
1923
2112
  }
1924
2113
  function validateContextEnhancementScope(input) {
1925
- if (!hasExactKeys(input, SCOPE_KEYS)) {
2114
+ if (!hasExactKeys2(input, SCOPE_KEYS2)) {
1926
2115
  throw invalidConfig("\u8BF7\u63D0\u4EA4\u5B8C\u6574\u7684\u4E0A\u4E0B\u6587\u589E\u5F3A\u8BBE\u7F6E\u3002");
1927
2116
  }
1928
2117
  const { enabled, fields, guidance } = input;
@@ -1930,7 +2119,7 @@ function validateContextEnhancementScope(input) {
1930
2119
  throw invalidConfig("\u7FA4\u804A\u548C\u79C1\u804A\u5F00\u5173\u5FC5\u987B\u662F\u5E03\u5C14\u503C\u3002");
1931
2120
  }
1932
2121
  if (!Array.isArray(fields) || ![...fields].every((field) => CONTEXT_ENHANCEMENT_FIELDS.includes(field))) {
1933
- throw invalidConfig("\u6765\u6E90\u5B57\u6BB5\u53EA\u80FD\u9009\u62E9\u5DF2\u5B9A\u4E49\u7684\u4E94\u4E2A\u5B57\u6BB5\u3002");
2122
+ throw invalidConfig("\u6765\u6E90\u5B57\u6BB5\u53EA\u80FD\u9009\u62E9\u5DF2\u5B9A\u4E49\u7684\u516D\u4E2A\u5B57\u6BB5\u3002");
1934
2123
  }
1935
2124
  if (typeof guidance !== "string" || guidance.length > CONTEXT_ENHANCEMENT_GUIDANCE_MAX_LENGTH) {
1936
2125
  throw invalidConfig(`\u589E\u5F3A\u63D0\u793A\u8BCD\u4E0D\u5F97\u8D85\u8FC7 ${CONTEXT_ENHANCEMENT_GUIDANCE_MAX_LENGTH} \u4E2A\u5B57\u7B26\u3002`);
@@ -1942,7 +2131,7 @@ function validateContextEnhancementScope(input) {
1942
2131
  });
1943
2132
  }
1944
2133
  function validateContextEnhancementConfig(input) {
1945
- if (!hasExactKeys(input, CONFIG_KEYS)) {
2134
+ if (!hasExactKeys2(input, CONFIG_KEYS)) {
1946
2135
  throw invalidConfig("\u8BF7\u63D0\u4EA4\u5B8C\u6574\u7684\u4E0A\u4E0B\u6587\u589E\u5F3A\u8BBE\u7F6E\u3002");
1947
2136
  }
1948
2137
  return Object.freeze({
@@ -1951,7 +2140,7 @@ function validateContextEnhancementConfig(input) {
1951
2140
  });
1952
2141
  }
1953
2142
  function migrateLegacyContextEnhancementConfig(input) {
1954
- if (!hasExactKeys(input, LEGACY_CONFIG_KEYS)) {
2143
+ if (!hasExactKeys2(input, LEGACY_CONFIG_KEYS)) {
1955
2144
  throw invalidConfig("\u8BF7\u63D0\u4EA4\u5B8C\u6574\u7684\u4E0A\u4E0B\u6587\u589E\u5F3A\u8BBE\u7F6E\u3002");
1956
2145
  }
1957
2146
  return validateContextEnhancementConfig({
@@ -1991,7 +2180,8 @@ var DINGTALK_ENDPOINTS = Object.freeze({
1991
2180
  deleteBot: "bot.delete",
1992
2181
  setWorkspace: "bot.workspace.set",
1993
2182
  setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
1994
- setContextEnhancement: "bot.context-enhancement.set"
2183
+ setContextEnhancement: "bot.context-enhancement.set",
2184
+ setAccessPolicy: "bot.access-policy.set"
1995
2185
  });
1996
2186
  var ACCOUNT_STATES = /* @__PURE__ */ new Set(["connected", "connecting", "offline", "error"]);
1997
2187
  var SNAPSHOT_STATES = /* @__PURE__ */ new Set(["disconnected", "offline", "provisioning", "connected", "degraded"]);
@@ -2121,6 +2311,7 @@ function normalizeBot(value) {
2121
2311
  workspace: optionalString(value.workspace, 4096) ?? "",
2122
2312
  agentPreset: normalizeAgentPresetId(value.agentPreset),
2123
2313
  contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
2314
+ ...Object.hasOwn(value, "accessPolicy") ? { accessPolicy: normalizeAccessPolicy(value.accessPolicy) } : {},
2124
2315
  bot: {
2125
2316
  name: optionalString(bot.name, 100) ?? "\u9489\u9489\u673A\u5668\u4EBA",
2126
2317
  clientIdMasked: optionalString(bot.clientIdMasked, 140) ?? "\u5DF2\u5B89\u5168\u4FDD\u5B58"
@@ -2709,14 +2900,26 @@ var FIELD_LABELS = Object.freeze({
2709
2900
  conversationType: "\u4F1A\u8BDD\u7C7B\u578B",
2710
2901
  senderId: "\u53D1\u9001\u8005\u6807\u8BC6",
2711
2902
  senderName: "\u53D1\u9001\u8005\u6635\u79F0",
2903
+ conversationTitle: "\u4F1A\u8BDD\u6807\u9898",
2712
2904
  botId: "\u673A\u5668\u4EBA\u6807\u8BC6"
2713
2905
  });
2906
+ var FIELD_HELP = Object.freeze({
2907
+ senderName: Object.freeze({
2908
+ labelKey: "senderNameHelpLabel",
2909
+ text: "\u8BE5\u5B57\u6BB5\u4E0D\u662F\u6BCF\u4E2A\u6E20\u9053\u90FD\u80FD\u63D0\u4F9B\u3002\u5F53\u524D\u6D88\u606F\u6CA1\u6709\u53D1\u9001\u8005\u6635\u79F0\u65F6\uFF0C\u5373\u4F7F\u5DF2\u9009\u62E9\u8BE5\u5B57\u6BB5\uFF0C<dsh_im_source> \u4E2D\u4E5F\u4F1A\u7701\u7565 senderName\u3002"
2910
+ }),
2911
+ conversationTitle: Object.freeze({
2912
+ labelKey: "conversationTitleHelpLabel",
2913
+ text: "\u8BE5\u5B57\u6BB5\u4E0D\u662F\u6BCF\u4E2A\u6E20\u9053\u90FD\u80FD\u63D0\u4F9B\u3002\u9489\u9489\u7FA4\u804A\u4F1A\u5E26\u4E0A\u7FA4\u540D\u3002\u5F53\u524D\u6D88\u606F\u6CA1\u6709\u4F1A\u8BDD\u6807\u9898\u65F6\uFF0C\u5373\u4F7F\u5DF2\u9009\u62E9\u8BE5\u5B57\u6BB5\uFF0C<dsh_im_source> \u4E2D\u4E5F\u4F1A\u7701\u7565 conversationTitle\u3002"
2914
+ })
2915
+ });
2714
2916
  var SCOPE_COPY = Object.freeze({
2715
2917
  group: Object.freeze({
2716
2918
  title: "\u7FA4\u804A",
2717
2919
  enable: "\u542F\u7528",
2718
2920
  fieldsHelpLabel: "\u67E5\u770B\u7FA4\u804A\u6765\u6E90\u5B57\u6BB5\u8BF4\u660E",
2719
2921
  senderNameHelpLabel: "\u67E5\u770B\u7FA4\u804A\u53D1\u9001\u8005\u6635\u79F0\u5B57\u6BB5\u8BF4\u660E",
2922
+ conversationTitleHelpLabel: "\u67E5\u770B\u7FA4\u804A\u4F1A\u8BDD\u6807\u9898\u5B57\u6BB5\u8BF4\u660E",
2720
2923
  guidanceLabel: "\u589E\u5F3A\u63D0\u793A\u8BCD",
2721
2924
  guidanceHelpLabel: "\u67E5\u770B\u7FA4\u804A\u589E\u5F3A\u63D0\u793A\u8BCD\u4F7F\u7528\u8BF4\u660E",
2722
2925
  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",
@@ -2727,6 +2930,7 @@ var SCOPE_COPY = Object.freeze({
2727
2930
  enable: "\u542F\u7528",
2728
2931
  fieldsHelpLabel: "\u67E5\u770B\u79C1\u804A\u6765\u6E90\u5B57\u6BB5\u8BF4\u660E",
2729
2932
  senderNameHelpLabel: "\u67E5\u770B\u79C1\u804A\u53D1\u9001\u8005\u6635\u79F0\u5B57\u6BB5\u8BF4\u660E",
2933
+ conversationTitleHelpLabel: "\u67E5\u770B\u79C1\u804A\u4F1A\u8BDD\u6807\u9898\u5B57\u6BB5\u8BF4\u660E",
2730
2934
  guidanceLabel: "\u589E\u5F3A\u63D0\u793A\u8BCD",
2731
2935
  guidanceHelpLabel: "\u67E5\u770B\u79C1\u804A\u589E\u5F3A\u63D0\u793A\u8BCD\u4F7F\u7528\u8BF4\u660E",
2732
2936
  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",
@@ -2767,7 +2971,6 @@ function ContextEnhancementScopeEditor({
2767
2971
  const copy = SCOPE_COPY[kind];
2768
2972
  const unavailableId = `${idPrefix}-${kind}-unavailable`;
2769
2973
  const fieldsHelpId = `${idPrefix}-${kind}-fields-help`;
2770
- const senderNameHelpId = `${idPrefix}-${kind}-sender-name-help`;
2771
2974
  const guidanceId = `${idPrefix}-${kind}-guidance`;
2772
2975
  const guidanceHelpId = `${idPrefix}-${kind}-guidance-help`;
2773
2976
  const disabled = busy || !supported;
@@ -2844,21 +3047,21 @@ function ContextEnhancementScopeEditor({
2844
3047
  "span",
2845
3048
  { className: "dim-contextFieldText" },
2846
3049
  h2("label", { className: "dim-contextFieldName", htmlFor: fieldId }, FIELD_LABELS[field]),
2847
- field === "senderName" ? h2(
3050
+ FIELD_HELP[field] ? h2(
2848
3051
  "span",
2849
3052
  { className: "dim-contextHelp dim-contextFieldHelp" },
2850
3053
  h2("button", {
2851
3054
  type: "button",
2852
3055
  className: "dim-contextHelpButton dim-contextFieldHelpButton",
2853
3056
  disabled,
2854
- "aria-label": copy.senderNameHelpLabel,
2855
- "aria-describedby": senderNameHelpId
3057
+ "aria-label": copy[FIELD_HELP[field].labelKey],
3058
+ "aria-describedby": `${idPrefix}-${kind}-${field}-help`
2856
3059
  }, h2("span", { "aria-hidden": "true" }, "?")),
2857
3060
  h2("span", {
2858
- id: senderNameHelpId,
3061
+ id: `${idPrefix}-${kind}-${field}-help`,
2859
3062
  className: "dim-contextTooltip dim-contextFieldTooltip",
2860
3063
  role: "tooltip"
2861
- }, "\u8BE5\u5B57\u6BB5\u4E0D\u662F\u6BCF\u4E2A\u6E20\u9053\u90FD\u80FD\u63D0\u4F9B\u3002\u5F53\u524D\u6D88\u606F\u6CA1\u6709\u53D1\u9001\u8005\u6635\u79F0\u65F6\uFF0C\u5373\u4F7F\u5DF2\u9009\u62E9\u8BE5\u5B57\u6BB5\uFF0C<dsh_im_source> \u4E2D\u4E5F\u4F1A\u7701\u7565 senderName\u3002")
3064
+ }, FIELD_HELP[field].text)
2862
3065
  ) : null,
2863
3066
  h2("label", { className: "dim-contextFieldKey", htmlFor: fieldId }, field)
2864
3067
  )
@@ -3230,7 +3433,7 @@ function SettingsGlyph() {
3230
3433
  h2("path", { d: "M19.4 15a1.7 1.7 0 0 0 .34 1.88l.06.06-2.83 2.83-.06-.06a1.7 1.7 0 0 0-1.88-.34 1.7 1.7 0 0 0-1.03 1.55V21h-4v-.08A1.7 1.7 0 0 0 8.97 19.4a1.7 1.7 0 0 0-1.88.34l-.06.06-2.83-2.83.06-.06A1.7 1.7 0 0 0 4.6 15a1.7 1.7 0 0 0-1.52-1.03H3v-4h.08A1.7 1.7 0 0 0 4.6 8.97a1.7 1.7 0 0 0-.34-1.88l-.06-.06L7.03 4.2l.06.06a1.7 1.7 0 0 0 1.88.34A1.7 1.7 0 0 0 10 3.08V3h4v.08a1.7 1.7 0 0 0 1.03 1.52 1.7 1.7 0 0 0 1.88-.34l.06-.06 2.83 2.83-.06.06a1.7 1.7 0 0 0-.34 1.88A1.7 1.7 0 0 0 20.92 10H21v4h-.08A1.7 1.7 0 0 0 19.4 15Z" })
3231
3434
  );
3232
3435
  }
3233
- function BotSettingsButton({ channel: channel4, botId, botName, connected }) {
3436
+ function BotSettingsButton({ channel: channel4, botId, botName, connected, accessPolicy }) {
3234
3437
  const { openBotSettings } = React9.useContext(BotSettingsContext);
3235
3438
  const tooltipId = React9.useId();
3236
3439
  return h2(
@@ -3246,7 +3449,8 @@ function BotSettingsButton({ channel: channel4, botId, botName, connected }) {
3246
3449
  channel: channel4,
3247
3450
  botId,
3248
3451
  botName,
3249
- connected: Boolean(connected)
3452
+ connected: Boolean(connected),
3453
+ accessPolicy
3250
3454
  })
3251
3455
  }, h2(SettingsGlyph)),
3252
3456
  h2("span", {
@@ -3809,7 +4013,8 @@ function AccountCard({
3809
4013
  channel: "dingtalk",
3810
4014
  botId: account.botId,
3811
4015
  botName: account.bot.name,
3812
- connected: account.connected
4016
+ connected: account.connected,
4017
+ accessPolicy: account.accessPolicy
3813
4018
  })
3814
4019
  )
3815
4020
  ),
@@ -4464,12 +4669,13 @@ var TOKEN_BOT_ENDPOINTS = Object.freeze({
4464
4669
  deleteBot: "bot.delete",
4465
4670
  setWorkspace: "bot.workspace.set",
4466
4671
  setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
4467
- setContextEnhancement: "bot.context-enhancement.set"
4672
+ setContextEnhancement: "bot.context-enhancement.set",
4673
+ setAccessPolicy: "bot.access-policy.set"
4468
4674
  });
4469
4675
  function createTokenChannelApi(channel4, connectionSummary, {
4470
4676
  normalizeBotExtension = () => ({})
4471
4677
  } = {}) {
4472
- const unwrapRpcResult11 = (result) => {
4678
+ const unwrapRpcResult12 = (result) => {
4473
4679
  if (!isRecord2(result) || typeof result.ok !== "boolean") {
4474
4680
  throw new Error(`${channel4} \u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94`);
4475
4681
  }
@@ -4492,6 +4698,7 @@ function createTokenChannelApi(channel4, connectionSummary, {
4492
4698
  workspace: text2(value.workspace, "", 4096),
4493
4699
  agentPreset: normalizeAgentPresetId(value.agentPreset),
4494
4700
  contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
4701
+ ...Object.hasOwn(value, "accessPolicy") ? { accessPolicy: normalizeAccessPolicy(value.accessPolicy) } : {},
4495
4702
  bot: {
4496
4703
  name: text2(value.bot?.name, `${channel4}\u673A\u5668\u4EBA`, 100),
4497
4704
  username: text2(value.bot?.username, "", 100),
@@ -4529,7 +4736,7 @@ function createTokenChannelApi(channel4, connectionSummary, {
4529
4736
  code: text2(error?.code, `${channel4.toUpperCase()}_ERROR`, 80),
4530
4737
  message: text2(error?.message, `${channel4}\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`)
4531
4738
  });
4532
- return Object.freeze({ unwrapRpcResult: unwrapRpcResult11, normalizeSnapshot: normalizeSnapshot9, presentError: presentError12 });
4739
+ return Object.freeze({ unwrapRpcResult: unwrapRpcResult12, normalizeSnapshot: normalizeSnapshot9, presentError: presentError12 });
4533
4740
  }
4534
4741
 
4535
4742
  // plugin-src/client/channels/discord/api.js
@@ -4639,7 +4846,8 @@ function createTokenChannelSettings(definition) {
4639
4846
  channel: channel4.toLowerCase(),
4640
4847
  botId: account.botId,
4641
4848
  botName: account.bot.name,
4642
- connected: account.connected
4849
+ connected: account.connected,
4850
+ accessPolicy: account.accessPolicy
4643
4851
  })
4644
4852
  )
4645
4853
  ),
@@ -5075,6 +5283,7 @@ var FEISHU_ENDPOINTS = Object.freeze({
5075
5283
  setWorkspace: "bot.workspace.set",
5076
5284
  setAgentPreset: "bot.preset.set",
5077
5285
  setContextEnhancement: "bot.context-enhancement.set",
5286
+ setAccessPolicy: "bot.access-policy.set",
5078
5287
  setGroupResponseMode: "bot.group-response-mode.set",
5079
5288
  // Kept for rolling upgrades. The multi-bot UI never calls these endpoints.
5080
5289
  testConnection: "connection.test",
@@ -5224,6 +5433,7 @@ function normalizeBotConnection(value, fallbackBotId) {
5224
5433
  workspace: optionalString2(value.workspace)?.slice(0, 4096) ?? "",
5225
5434
  agentPreset: normalizeAgentPresetId(value.agentPreset),
5226
5435
  contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
5436
+ ...Object.hasOwn(value, "accessPolicy") ? { accessPolicy: normalizeAccessPolicy(value.accessPolicy) } : {},
5227
5437
  groupResponseMode: normalizeGroupResponseMode(value.groupResponseMode),
5228
5438
  groupMessagePermissionGranted: value.groupMessagePermissionGranted === true,
5229
5439
  bot: normalizeBot2(value.bot),
@@ -5957,7 +6167,8 @@ function BotCard({
5957
6167
  channel: "feishu",
5958
6168
  botId: connection.botId,
5959
6169
  botName: bot.name,
5960
- connected
6170
+ connected,
6171
+ accessPolicy: connection.accessPolicy
5961
6172
  })
5962
6173
  )
5963
6174
  ),
@@ -7430,7 +7641,8 @@ var QQ_ENDPOINTS = Object.freeze({
7430
7641
  deleteBot: "bot.delete",
7431
7642
  setWorkspace: "bot.workspace.set",
7432
7643
  setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
7433
- setContextEnhancement: "bot.context-enhancement.set"
7644
+ setContextEnhancement: "bot.context-enhancement.set",
7645
+ setAccessPolicy: "bot.access-policy.set"
7434
7646
  });
7435
7647
  var PROVISION_STATES2 = /* @__PURE__ */ new Set(["starting", "pending", "refreshing", "connecting", "connected", "failed", "cancelled"]);
7436
7648
  var ACCOUNT_STATES3 = /* @__PURE__ */ new Set(["connected", "connecting", "offline", "error"]);
@@ -7496,6 +7708,7 @@ function normalizeBot3(value) {
7496
7708
  workspace: text3(value.workspace, "", 4096),
7497
7709
  agentPreset: normalizeAgentPresetId(value.agentPreset),
7498
7710
  contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
7711
+ ...Object.hasOwn(value, "accessPolicy") ? { accessPolicy: normalizeAccessPolicy(value.accessPolicy) } : {},
7499
7712
  bot: {
7500
7713
  name: text3(value.bot?.name, "QQ\u673A\u5668\u4EBA", 100),
7501
7714
  appIdMasked: text3(value.bot?.appIdMasked, "\u5E94\u7528\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58", 140)
@@ -7836,7 +8049,8 @@ function AccountCard2({
7836
8049
  channel: "qq",
7837
8050
  botId: account.botId,
7838
8051
  botName: account.bot.name,
7839
- connected: account.connected
8052
+ connected: account.connected,
8053
+ accessPolicy: account.accessPolicy
7840
8054
  })
7841
8055
  )
7842
8056
  ),
@@ -8773,59 +8987,18 @@ var SlackAccountCard = channel2.AccountCard;
8773
8987
 
8774
8988
  // plugin-src/client/channels/telegram/api.js
8775
8989
  var TELEGRAM_RPC_CHANNEL = "/telegram";
8776
- var TELEGRAM_ENDPOINTS = Object.freeze({
8777
- ...TOKEN_BOT_ENDPOINTS,
8778
- setAccessPolicy: "bot.access-policy.set"
8779
- });
8780
- var api3 = createTokenChannelApi("Telegram", " Bot API \u957F\u8F6E\u8BE2", {
8781
- normalizeBotExtension: (value) => {
8782
- const source = value?.accessPolicy;
8783
- const accessMode = source?.accessMode === "private-allowlist" ? "private-allowlist" : "compatible";
8784
- const allowedUsers = Array.isArray(source?.allowedUsers) ? [...new Set(source.allowedUsers.filter((entry) => typeof entry === "string" && /^[1-9]\d{0,15}$/.test(entry)))] : [];
8785
- return { accessPolicy: { accessMode, allowedUsers } };
8786
- }
8787
- });
8990
+ var TELEGRAM_ENDPOINTS = TOKEN_BOT_ENDPOINTS;
8991
+ var api3 = createTokenChannelApi("Telegram", " Bot API \u957F\u8F6E\u8BE2");
8788
8992
  var unwrapRpcResult6 = api3.unwrapRpcResult;
8789
8993
  var normalizeSnapshot5 = api3.normalizeSnapshot;
8790
8994
  var presentError6 = api3.presentError;
8791
8995
 
8792
- // plugin-src/client/channels/telegram/index.js
8793
- var React17 = __toESM(require("react"), 1);
8794
-
8795
8996
  // plugin-src/client/channels/telegram/styles.js
8796
8997
  var TELEGRAM_STYLE_ID = "xmanrui-dsh-im-telegram-settings";
8797
8998
  var CSS7 = String.raw`
8798
8999
  .dtg-page { --ddt-accent: #229ed9; --ddt-accent-deep: #1687bd; --ddt-accent-wash: #eaf7fd; }
8799
9000
  .dtg-avatar { color: #fff; background: #229ed9; }
8800
9001
  .dtg-avatar svg { display: block; }
8801
- .dtg-access { min-width: 0; width: 100%; max-width: 100%; display: grid; gap: 10px; padding: 12px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 10px; background: var(--dsw-alias-bg-layer-2, #f7f8fa); }
8802
- .dtg-accessHeading { position: relative; min-width: 0; max-width: 100%; display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px 12px; }
8803
- .dtg-accessHeading > strong { min-width: 0; font-size: 13px; overflow-wrap: anywhere; }
8804
- .dtg-accessStatus { min-width: 0; max-width: 100%; flex: 0 1 auto; display: inline-flex; align-items: center; justify-content: flex-end; flex-wrap: wrap; gap: 6px; }
8805
- .dtg-accessBadge { min-width: 0; max-width: 100%; flex: 0 1 auto; padding: 3px 8px; border-radius: 999px; color: #1687bd; background: #eaf7fd; font-size: 11px; font-weight: 700; overflow-wrap: anywhere; text-align: center; }
8806
- .dtg-accessBadge[data-mode="private-allowlist"] { color: #a15c00; background: #fff3d6; }
8807
- .dtg-accessHelp { position: static; display: inline-flex; flex: none; }
8808
- .dtg-accessHelpButton { width: 20px; height: 20px; display: grid; place-items: center; padding: 0; border: 1px solid color-mix(in srgb, #229ed9 28%, var(--dsw-alias-border-l2, #dfe1e5)); border-radius: 50%; color: #1687bd; background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 12px; line-height: 1; font-weight: 750; cursor: help; transition: border-color .15s ease, color .15s ease, background .15s ease, box-shadow .15s ease; }
8809
- .dtg-accessHelpButton:hover { border-color: #229ed9; color: #1178a8; background: #eaf7fd; }
8810
- .dtg-accessHelpButton:focus-visible { outline: none; border-color: #229ed9; box-shadow: 0 0 0 3px color-mix(in srgb, #229ed9 18%, transparent); }
8811
- .dtg-accessTooltip { position: absolute; top: calc(100% + 8px); right: 0; z-index: 30; width: min(300px, 100%); max-width: 100%; display: grid; gap: 8px; padding: 10px 11px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 9px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 10px 28px rgb(31 35 41 / 16%); opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
8812
- .dtg-accessTooltipItem { display: grid; gap: 2px; }
8813
- .dtg-accessTooltipItem + .dtg-accessTooltipItem { padding-top: 8px; border-top: 1px solid var(--dsw-alias-border-l2, #eef0f3); }
8814
- .dtg-accessTooltipItem strong { color: var(--dsw-alias-label-primary, #1f2329); font-size: 12px; line-height: 17px; font-weight: 700; }
8815
- .dtg-accessTooltipItem > span { color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 16px; font-weight: 400; }
8816
- .dtg-accessHelp:hover .dtg-accessTooltip, .dtg-accessHelp:focus-within .dtg-accessTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
8817
- .dtg-accessField { min-width: 0; max-width: 100%; display: grid; gap: 5px; color: var(--dsw-alias-label-primary, #1f2329); font-size: 12px; font-weight: 600; }
8818
- .dtg-accessField select, .dtg-accessField textarea { min-width: 0; width: 100%; max-width: 100%; box-sizing: border-box; border: 1px solid var(--dsw-alias-border-l1, #c9cdd4); border-radius: 7px; color: inherit; background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-weight: 400; }
8819
- .dtg-accessField select { height: 34px; padding: 0 9px; }
8820
- .dtg-accessField textarea { min-height: 68px; padding: 8px 9px; resize: vertical; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
8821
- .dtg-accessField textarea:disabled { color: var(--dsw-alias-label-tertiary, #8f959e); background: var(--dsw-alias-bg-module-platform, #f2f3f5); cursor: not-allowed; resize: none; opacity: 1; }
8822
- .dtg-accessField > span, .dtg-accessField small { overflow-wrap: anywhere; }
8823
- .dtg-accessField small { color: var(--dsw-alias-label-secondary, #646a73); font-weight: 400; }
8824
- .dtg-accessWarning, .dtg-accessError { margin: 0; font-size: 12px; line-height: 1.5; }
8825
- .dtg-accessWarning { color: #a15c00; }
8826
- .dtg-accessError { color: var(--dsw-alias-state-error-primary, #d83931); }
8827
- .dtg-accessActions { min-width: 0; max-width: 100%; display: flex; justify-content: flex-end; flex-wrap: wrap; }
8828
- .dtg-accessActions .ddt-button { max-width: 100%; white-space: normal; }
8829
9002
  `;
8830
9003
  function installTelegramStyles() {
8831
9004
  if (typeof document === "undefined") return () => {
@@ -8842,146 +9015,6 @@ function installTelegramStyles() {
8842
9015
  }
8843
9016
 
8844
9017
  // plugin-src/client/channels/telegram/index.js
8845
- function policyFor(account) {
8846
- return {
8847
- accessMode: account?.accessPolicy?.accessMode === "private-allowlist" ? "private-allowlist" : "compatible",
8848
- allowedUsers: Array.isArray(account?.accessPolicy?.allowedUsers) ? account.accessPolicy.allowedUsers : []
8849
- };
8850
- }
8851
- function allowedUsersFromText(value) {
8852
- const entries = value.split(/\r?\n/).map((entry) => entry.trim()).filter(Boolean);
8853
- if (entries.some((entry) => !/^[1-9]\d{0,15}$/.test(entry))) {
8854
- throw new TypeError("User ID \u5FC5\u987B\u662F 1\u201316 \u4F4D\u6B63\u6574\u6570\uFF0C\u6BCF\u884C\u4E00\u4E2A\u3002");
8855
- }
8856
- return [...new Set(entries)];
8857
- }
8858
- function TelegramAccessSettings({ account, busy = false, onSave }) {
8859
- const policy = policyFor(account);
8860
- const sourceUsers = policy.allowedUsers.join("\n");
8861
- const accessHelpId = React17.useId();
8862
- const [accessMode, setAccessMode] = React17.useState(policy.accessMode);
8863
- const [allowedUsers, setAllowedUsers] = React17.useState(sourceUsers);
8864
- const [error, setError] = React17.useState(null);
8865
- React17.useEffect(() => {
8866
- setAccessMode(policy.accessMode);
8867
- setAllowedUsers(sourceUsers);
8868
- setError(null);
8869
- }, [policy.accessMode, sourceUsers]);
8870
- const save = async (event) => {
8871
- event.preventDefault();
8872
- setError(null);
8873
- try {
8874
- const normalized = allowedUsersFromText(allowedUsers);
8875
- if (typeof onSave !== "function") throw new Error("Telegram \u8BBF\u95EE\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
8876
- await onSave({ accessMode, allowedUsers: normalized });
8877
- } catch (caught) {
8878
- setError(caught?.message ?? "Telegram \u8BBF\u95EE\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\u3002");
8879
- }
8880
- };
8881
- const privateAllowlist = accessMode === "private-allowlist";
8882
- const savedPrivateAllowlist = policy.accessMode === "private-allowlist";
8883
- const emptyAllowlist = privateAllowlist && allowedUsers.trim() === "";
8884
- return h2(
8885
- "form",
8886
- { className: "dtg-access", onSubmit: save },
8887
- h2(
8888
- "div",
8889
- { className: "dtg-accessHeading" },
8890
- h2("strong", null, "\u8BBF\u95EE\u8BBE\u7F6E"),
8891
- h2(
8892
- "span",
8893
- { className: "dtg-accessStatus" },
8894
- h2(
8895
- "span",
8896
- { className: "dtg-accessBadge", "data-mode": policy.accessMode },
8897
- savedPrivateAllowlist ? "\u5DF2\u751F\u6548\uFF1A\u5B89\u5168\u6A21\u5F0F" : "\u5DF2\u751F\u6548\uFF1A\u517C\u5BB9\u6A21\u5F0F"
8898
- ),
8899
- h2(
8900
- "span",
8901
- { className: "dtg-accessHelp" },
8902
- h2("button", {
8903
- type: "button",
8904
- className: "dtg-accessHelpButton",
8905
- "aria-label": "\u67E5\u770B Telegram \u8BBF\u95EE\u6A21\u5F0F\u8BF4\u660E",
8906
- "aria-describedby": accessHelpId
8907
- }, h2("span", { "aria-hidden": "true" }, "?")),
8908
- h2(
8909
- "span",
8910
- {
8911
- id: accessHelpId,
8912
- className: "dtg-accessTooltip",
8913
- role: "tooltip"
8914
- },
8915
- h2(
8916
- "span",
8917
- { className: "dtg-accessTooltipItem" },
8918
- h2("strong", null, "\u517C\u5BB9\u6A21\u5F0F"),
8919
- h2("span", null, "\u4FDD\u6301\u539F\u6709\u884C\u4E3A\uFF1A\u79C1\u804A\u76F4\u63A5\u54CD\u5E94\uFF0C\u7FA4\u804A\u5728\u88AB\u63D0\u53CA\u6216\u56DE\u590D\u65F6\u54CD\u5E94\u3002")
8920
- ),
8921
- h2(
8922
- "span",
8923
- { className: "dtg-accessTooltipItem" },
8924
- h2("strong", null, "\u5B89\u5168\u6A21\u5F0F"),
8925
- h2("span", null, "\u7FA4\u804A\u5168\u90E8\u5FFD\u7565\uFF0C\u79C1\u804A\u4EC5\u5141\u8BB8\u767D\u540D\u5355\u7528\u6237\u3002")
8926
- )
8927
- )
8928
- )
8929
- )
8930
- ),
8931
- h2(
8932
- "label",
8933
- { className: "dtg-accessField" },
8934
- h2("span", null, "\u6A21\u5F0F"),
8935
- h2(
8936
- "select",
8937
- {
8938
- value: accessMode,
8939
- disabled: busy,
8940
- "aria-label": "Telegram \u8BBF\u95EE\u6A21\u5F0F",
8941
- onChange: (event) => {
8942
- setAccessMode(event.target.value);
8943
- setError(null);
8944
- }
8945
- },
8946
- h2("option", { value: "compatible" }, "\u517C\u5BB9\u6A21\u5F0F\uFF08\u9ED8\u8BA4\uFF09"),
8947
- h2("option", { value: "private-allowlist" }, "\u5B89\u5168\u6A21\u5F0F\uFF08\u79C1\u804A\u767D\u540D\u5355\uFF09")
8948
- )
8949
- ),
8950
- h2(
8951
- "label",
8952
- { className: "dtg-accessField" },
8953
- h2("span", null, "\u5141\u8BB8\u79C1\u804A\u7684 Telegram User ID"),
8954
- h2("textarea", {
8955
- value: allowedUsers,
8956
- disabled: busy || !privateAllowlist,
8957
- rows: 3,
8958
- placeholder: "\u6BCF\u884C\u4E00\u4E2A\u6570\u5B57 User ID",
8959
- "aria-label": "\u5141\u8BB8\u79C1\u804A\u7684 Telegram User ID",
8960
- onChange: (event) => {
8961
- setAllowedUsers(event.target.value);
8962
- setError(null);
8963
- }
8964
- }),
8965
- h2("small", null, privateAllowlist ? "\u767D\u540D\u5355\u4EC5\u5C5E\u4E8E\u5F53\u524D\u673A\u5668\u4EBA\u3002" : "\u517C\u5BB9\u6A21\u5F0F\u4E0B\u6682\u4E0D\u4F7F\u7528\u767D\u540D\u5355\uFF0C\u5207\u6362\u6A21\u5F0F\u65F6\u4F1A\u4FDD\u7559\u3002")
8966
- ),
8967
- emptyAllowlist ? h2(
8968
- "p",
8969
- { className: "dtg-accessWarning", role: "status" },
8970
- "\u767D\u540D\u5355\u4E3A\u7A7A\uFF1B\u4FDD\u5B58\u540E\u8BE5\u673A\u5668\u4EBA\u4F1A\u62D2\u7EDD\u6240\u6709\u5165\u7AD9\u6D88\u606F\u3002"
8971
- ) : null,
8972
- error ? h2("p", { className: "dtg-accessError", role: "alert" }, error) : null,
8973
- h2(
8974
- "div",
8975
- { className: "dtg-accessActions" },
8976
- h2("button", {
8977
- type: "submit",
8978
- className: "ddt-button",
8979
- "data-kind": "secondary",
8980
- disabled: busy
8981
- }, busy ? "\u6B63\u5728\u4FDD\u5B58\u2026" : "\u4FDD\u5B58\u8BBF\u95EE\u8BBE\u7F6E")
8982
- )
8983
- );
8984
- }
8985
9018
  var channel3 = createTokenChannelSettings({
8986
9019
  channel: "Telegram",
8987
9020
  endpoints: TELEGRAM_ENDPOINTS,
@@ -8994,9 +9027,7 @@ var channel3 = createTokenChannelSettings({
8994
9027
  tokenPlaceholder: "\u586B\u5199 @BotFather \u751F\u6210\u7684 Bot Token",
8995
9028
  emptyTitle: "\u63A5\u5165 Telegram \u673A\u5668\u4EBA",
8996
9029
  emptyDescription: "\u5148\u901A\u8FC7 @BotFather \u83B7\u53D6 Bot Token\uFF0C\u518D\u5728\u8FD9\u91CC\u5B8C\u6210\u63A5\u5165\u3002",
8997
- platformLabel: "Telegram",
8998
- AccountSettings: TelegramAccessSettings,
8999
- accountSettingsEndpoint: TELEGRAM_ENDPOINTS.setAccessPolicy
9030
+ platformLabel: "Telegram"
9000
9031
  });
9001
9032
  var TelegramSettingsTab = channel3.SettingsTab;
9002
9033
  var TelegramAccountCard = channel3.AccountCard;
@@ -9013,7 +9044,8 @@ var WECOM_ENDPOINTS = Object.freeze({
9013
9044
  deleteBot: "bot.delete",
9014
9045
  setWorkspace: "bot.workspace.set",
9015
9046
  setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
9016
- setContextEnhancement: "bot.context-enhancement.set"
9047
+ setContextEnhancement: "bot.context-enhancement.set",
9048
+ setAccessPolicy: "bot.access-policy.set"
9017
9049
  });
9018
9050
  var PROVISION_STATES3 = /* @__PURE__ */ new Set(["starting", "pending", "refreshing", "connecting", "connected", "failed", "cancelled"]);
9019
9051
  var ACCOUNT_STATES4 = /* @__PURE__ */ new Set(["connected", "connecting", "offline", "error"]);
@@ -9085,6 +9117,7 @@ function normalizeBot4(value) {
9085
9117
  workspace: text4(value.workspace, "", 4096),
9086
9118
  agentPreset: normalizeAgentPresetId(value.agentPreset),
9087
9119
  contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
9120
+ ...Object.hasOwn(value, "accessPolicy") ? { accessPolicy: normalizeAccessPolicy(value.accessPolicy) } : {},
9088
9121
  bot: {
9089
9122
  name: text4(value.bot?.name, "\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA", 100),
9090
9123
  appIdMasked: text4(value.bot?.appIdMasked, "\u5E94\u7528\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58", 140)
@@ -9125,7 +9158,7 @@ function formatRemaining4(milliseconds) {
9125
9158
  }
9126
9159
 
9127
9160
  // plugin-src/client/channels/wecom/index.js
9128
- var React18 = __toESM(require("react"), 1);
9161
+ var React17 = __toESM(require("react"), 1);
9129
9162
 
9130
9163
  // plugin-src/client/channels/wecom/styles.js
9131
9164
  var WECOM_STYLE_ID = "xmanrui-dsh-im-wecom-settings";
@@ -9150,7 +9183,7 @@ function installWecomStyles() {
9150
9183
 
9151
9184
  // plugin-src/client/channels/wecom/index.js
9152
9185
  var ACTIVE_STATES2 = /* @__PURE__ */ new Set(["pending", "refreshing", "connecting"]);
9153
- var Button10 = React18.forwardRef(function Button11({ children, kind = "secondary", className = "", ...props }, ref) {
9186
+ var Button10 = React17.forwardRef(function Button11({ children, kind = "secondary", className = "", ...props }, ref) {
9154
9187
  return h2("button", {
9155
9188
  ...props,
9156
9189
  ref,
@@ -9408,7 +9441,8 @@ function AccountCard3({
9408
9441
  channel: "wecom",
9409
9442
  botId: account.botId,
9410
9443
  botName: account.bot.name,
9411
- connected: account.connected
9444
+ connected: account.connected,
9445
+ accessPolicy: account.accessPolicy
9412
9446
  })
9413
9447
  )
9414
9448
  ),
@@ -9461,27 +9495,27 @@ function AccountCard3({
9461
9495
  );
9462
9496
  }
9463
9497
  function WecomSettingsTab({ rpcCall }) {
9464
- const [model, setModel] = React18.useState({
9498
+ const [model, setModel] = React17.useState({
9465
9499
  phase: "loading",
9466
9500
  bots: [],
9467
9501
  totals: { configured: 0, connected: 0 },
9468
9502
  error: null,
9469
9503
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
9470
9504
  });
9471
- const [provision, setProvision] = React18.useState(null);
9472
- const [busy, setBusy] = React18.useState(false);
9473
- const [busyByBot, setBusyByBot] = React18.useState({});
9474
- const [feedbackByBot, setFeedbackByBot] = React18.useState({});
9475
- const [removeTarget, setRemoveTarget] = React18.useState(null);
9476
- const [credentialOpen, setCredentialOpen] = React18.useState(false);
9477
- const [credentialError, setCredentialError] = React18.useState(null);
9478
- const [notice, setNotice] = React18.useState("");
9479
- const [now, setNow] = React18.useState(Date.now());
9480
- const mounted = React18.useRef(true);
9505
+ const [provision, setProvision] = React17.useState(null);
9506
+ const [busy, setBusy] = React17.useState(false);
9507
+ const [busyByBot, setBusyByBot] = React17.useState({});
9508
+ const [feedbackByBot, setFeedbackByBot] = React17.useState({});
9509
+ const [removeTarget, setRemoveTarget] = React17.useState(null);
9510
+ const [credentialOpen, setCredentialOpen] = React17.useState(false);
9511
+ const [credentialError, setCredentialError] = React17.useState(null);
9512
+ const [notice, setNotice] = React17.useState("");
9513
+ const [now, setNow] = React17.useState(Date.now());
9514
+ const mounted = React17.useRef(true);
9481
9515
  const workspaceFence = useWorkspaceSnapshotFence();
9482
- const addButtonRef = React18.useRef(null);
9483
- const noticeFrameRef = React18.useRef(null);
9484
- const announce = React18.useCallback((message) => {
9516
+ const addButtonRef = React17.useRef(null);
9517
+ const noticeFrameRef = React17.useRef(null);
9518
+ const announce = React17.useCallback((message) => {
9485
9519
  if (!mounted.current) return;
9486
9520
  if (noticeFrameRef.current !== null) {
9487
9521
  window.cancelAnimationFrame(noticeFrameRef.current);
@@ -9495,7 +9529,7 @@ function WecomSettingsTab({ rpcCall }) {
9495
9529
  });
9496
9530
  }
9497
9531
  }, []);
9498
- React18.useEffect(() => {
9532
+ React17.useEffect(() => {
9499
9533
  const disposeDingtalk = installDingtalkStyles();
9500
9534
  const disposeWecom = installWecomStyles();
9501
9535
  mounted.current = true;
@@ -9509,11 +9543,11 @@ function WecomSettingsTab({ rpcCall }) {
9509
9543
  disposeDingtalk();
9510
9544
  };
9511
9545
  }, []);
9512
- const invoke = React18.useCallback(async (endpoint, payload = {}, signal) => {
9546
+ const invoke = React17.useCallback(async (endpoint, payload = {}, signal) => {
9513
9547
  if (typeof rpcCall !== "function") throw new TypeError("\u4F01\u4E1A\u5FAE\u4FE1\u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
9514
9548
  return unwrapRpcResult7(await rpcCall(endpoint, payload, signal));
9515
9549
  }, [rpcCall]);
9516
- const loadStatus = React18.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
9550
+ const loadStatus = React17.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
9517
9551
  const workspaceVersion = workspaceFence.beginStatus();
9518
9552
  if (workspaceVersion === null) return void 0;
9519
9553
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
@@ -9539,12 +9573,12 @@ function WecomSettingsTab({ rpcCall }) {
9539
9573
  return void 0;
9540
9574
  }
9541
9575
  }, [invoke, workspaceFence]);
9542
- React18.useEffect(() => {
9576
+ React17.useEffect(() => {
9543
9577
  const controller = new AbortController();
9544
9578
  void loadStatus({ signal: controller.signal, restore: true });
9545
9579
  return () => controller.abort();
9546
9580
  }, [loadStatus]);
9547
- React18.useEffect(() => {
9581
+ React17.useEffect(() => {
9548
9582
  if (model.phase !== "ready") return void 0;
9549
9583
  const controller = new AbortController();
9550
9584
  const timer = window.setInterval(() => void loadStatus({ signal: controller.signal, silent: true }), 15e3);
@@ -9553,12 +9587,12 @@ function WecomSettingsTab({ rpcCall }) {
9553
9587
  window.clearInterval(timer);
9554
9588
  };
9555
9589
  }, [loadStatus, model.phase]);
9556
- React18.useEffect(() => {
9590
+ React17.useEffect(() => {
9557
9591
  if (!provision || !ACTIVE_STATES2.has(provision.status)) return void 0;
9558
9592
  const timer = window.setInterval(() => mounted.current && setNow(Date.now()), 1e3);
9559
9593
  return () => window.clearInterval(timer);
9560
9594
  }, [provision?.attemptId, provision?.status]);
9561
- const startProvisioning = React18.useCallback(async (replace = false) => {
9595
+ const startProvisioning = React17.useCallback(async (replace = false) => {
9562
9596
  setCredentialOpen(false);
9563
9597
  setCredentialError(null);
9564
9598
  setBusy(true);
@@ -9576,7 +9610,7 @@ function WecomSettingsTab({ rpcCall }) {
9576
9610
  if (mounted.current) setBusy(false);
9577
9611
  }
9578
9612
  }, [invoke, provision?.attemptId]);
9579
- const bindCredentials = React18.useCallback(async ({ identity, secret }) => {
9613
+ const bindCredentials = React17.useCallback(async ({ identity, secret }) => {
9580
9614
  const snapshotVersion = workspaceFence.beginMutation();
9581
9615
  setBusy(true);
9582
9616
  setCredentialError(null);
@@ -9604,7 +9638,7 @@ function WecomSettingsTab({ rpcCall }) {
9604
9638
  if (mounted.current) setBusy(false);
9605
9639
  }
9606
9640
  }, [invoke, loadStatus, workspaceFence]);
9607
- const closeProvision = React18.useCallback(async () => {
9641
+ const closeProvision = React17.useCallback(async () => {
9608
9642
  setBusy(true);
9609
9643
  try {
9610
9644
  if (provision?.attemptId && ACTIVE_STATES2.has(provision.status)) {
@@ -9615,7 +9649,7 @@ function WecomSettingsTab({ rpcCall }) {
9615
9649
  if (mounted.current) setBusy(false);
9616
9650
  }
9617
9651
  }, [invoke, provision?.attemptId, provision?.status]);
9618
- React18.useEffect(() => {
9652
+ React17.useEffect(() => {
9619
9653
  const attemptId = provision?.attemptId;
9620
9654
  if (!attemptId || !ACTIVE_STATES2.has(provision.status)) return void 0;
9621
9655
  const controller = new AbortController();
@@ -9645,7 +9679,7 @@ function WecomSettingsTab({ rpcCall }) {
9645
9679
  window.clearTimeout(timer);
9646
9680
  };
9647
9681
  }, [invoke, loadStatus, provision?.attemptId, provision?.pollIntervalMs, provision?.status]);
9648
- const botAction = React18.useCallback(async (account, operation, endpoint, payload) => {
9682
+ const botAction = React17.useCallback(async (account, operation, endpoint, payload) => {
9649
9683
  const snapshotVersion = workspaceFence.beginMutation();
9650
9684
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
9651
9685
  try {
@@ -9670,7 +9704,7 @@ function WecomSettingsTab({ rpcCall }) {
9670
9704
  });
9671
9705
  }
9672
9706
  }, [invoke, loadStatus, workspaceFence]);
9673
- const reconnect = React18.useCallback(async (account) => {
9707
+ const reconnect = React17.useCallback(async (account) => {
9674
9708
  setFeedbackByBot((current) => {
9675
9709
  const next = { ...current };
9676
9710
  delete next[account.botId];
@@ -9797,7 +9831,7 @@ function WecomSettingsTab({ rpcCall }) {
9797
9831
  }),
9798
9832
  h2("div", { className: "ddt-visuallyHidden", role: "status", "aria-live": "polite" }, notice),
9799
9833
  model.phase === "loading" ? h2(LoadingView4) : model.phase === "error" ? h2("div", { className: "ddt-card dim-surfaceCard" }, h2("div", { className: "ddt-inlineError dim-inlineError" }, h2("h3", null, "\u65E0\u6CD5\u8BFB\u53D6\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA\u72B6\u6001"), h2("p", null, model.error?.message), h2(Button10, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6"))) : h2(
9800
- React18.Fragment,
9834
+ React17.Fragment,
9801
9835
  null,
9802
9836
  credentialView,
9803
9837
  provisionView,
@@ -9808,7 +9842,7 @@ function WecomSettingsTab({ rpcCall }) {
9808
9842
  }
9809
9843
 
9810
9844
  // plugin-src/client/channels/weixin/index.js
9811
- var React19 = __toESM(require("react"), 1);
9845
+ var React18 = __toESM(require("react"), 1);
9812
9846
 
9813
9847
  // plugin-src/client/channels/weixin/api.js
9814
9848
  var WEIXIN_RPC_CHANNEL = "/weixin";
@@ -9822,7 +9856,8 @@ var WEIXIN_ENDPOINTS = Object.freeze({
9822
9856
  deleteBot: "bot.delete",
9823
9857
  setWorkspace: "bot.workspace.set",
9824
9858
  setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
9825
- setContextEnhancement: "bot.context-enhancement.set"
9859
+ setContextEnhancement: "bot.context-enhancement.set",
9860
+ setAccessPolicy: "bot.access-policy.set"
9826
9861
  });
9827
9862
  var ACCOUNT_STATES5 = /* @__PURE__ */ new Set(["connected", "connecting", "offline", "error"]);
9828
9863
  var PROVISION_STATES4 = /* @__PURE__ */ new Set([
@@ -9914,6 +9949,7 @@ function normalizeBot5(value) {
9914
9949
  workspace: string(value.workspace).slice(0, 4096),
9915
9950
  agentPreset: normalizeAgentPresetId(value.agentPreset),
9916
9951
  contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
9952
+ ...Object.hasOwn(value, "accessPolicy") ? { accessPolicy: normalizeAccessPolicy(value.accessPolicy) } : {},
9917
9953
  bot: {
9918
9954
  name: string(value.bot.name, "\u5FAE\u4FE1\u673A\u5668\u4EBA"),
9919
9955
  accountIdMasked: string(value.bot.accountIdMasked, "\u5DF2\u5B89\u5168\u4FDD\u5B58")
@@ -9965,7 +10001,7 @@ function formatRemaining5(milliseconds) {
9965
10001
  }
9966
10002
 
9967
10003
  // plugin-src/client/channels/weixin/index.js
9968
- var Button12 = React19.forwardRef(function Button13({ children, kind = "secondary", className = "", ...props }, ref) {
10004
+ var Button12 = React18.forwardRef(function Button13({ children, kind = "secondary", className = "", ...props }, ref) {
9969
10005
  return h2("button", {
9970
10006
  ...props,
9971
10007
  ref,
@@ -10038,14 +10074,14 @@ function EmptyView5({ onStart, busy }) {
10038
10074
  );
10039
10075
  }
10040
10076
  function QrPanel4({ provision, now, busy, onRefresh, onCancel }) {
10041
- const [imageFailed, setImageFailed] = React19.useState(false);
10077
+ const [imageFailed, setImageFailed] = React18.useState(false);
10042
10078
  const source = safeQrSource5(provision.qrCodeDataUrl);
10043
10079
  const href = safeVerificationUrl(provision.verificationUrl);
10044
10080
  const remaining = Math.max(0, provision.expiresAt - now);
10045
10081
  const expired = remaining === 0 || provision.status === "expired";
10046
10082
  const duration = Math.max(1, provision.durationMs ?? 5 * 6e4);
10047
10083
  const progress = Math.round(Math.min(1, remaining / duration) * 100);
10048
- React19.useEffect(() => setImageFailed(false), [source]);
10084
+ React18.useEffect(() => setImageFailed(false), [source]);
10049
10085
  return h2(
10050
10086
  "div",
10051
10087
  { className: "dxw-card dim-surfaceCard" },
@@ -10112,9 +10148,9 @@ function QrPanel4({ provision, now, busy, onRefresh, onCancel }) {
10112
10148
  );
10113
10149
  }
10114
10150
  function VerificationPanel({ provision, busy, onSubmit, onCancel }) {
10115
- const [code, setCode] = React19.useState("");
10151
+ const [code, setCode] = React18.useState("");
10116
10152
  const valid = /^\d{4,8}$/.test(code);
10117
- React19.useEffect(() => setCode(""), [provision.attemptId]);
10153
+ React18.useEffect(() => setCode(""), [provision.attemptId]);
10118
10154
  return h2(
10119
10155
  "div",
10120
10156
  { className: "dxw-card dim-surfaceCard" },
@@ -10251,7 +10287,8 @@ function AccountCard4({
10251
10287
  channel: "weixin",
10252
10288
  botId: account.botId,
10253
10289
  botName: account.bot.name,
10254
- connected: account.connected
10290
+ connected: account.connected,
10291
+ accessPolicy: account.accessPolicy
10255
10292
  })
10256
10293
  )
10257
10294
  ),
@@ -10357,7 +10394,7 @@ function mergeWeixinProvisioningSnapshot(current, incoming, { restoreProvisionin
10357
10394
  };
10358
10395
  }
10359
10396
  function WeixinSettingsTab({ rpcCall }) {
10360
- const [model, setModel] = React19.useState({
10397
+ const [model, setModel] = React18.useState({
10361
10398
  phase: "loading",
10362
10399
  bots: [],
10363
10400
  totals: EMPTY_TOTALS3,
@@ -10365,33 +10402,33 @@ function WeixinSettingsTab({ rpcCall }) {
10365
10402
  error: null,
10366
10403
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
10367
10404
  });
10368
- const [provision, setProvision] = React19.useState(null);
10369
- const [busy, setBusy] = React19.useState(false);
10370
- const [busyByBot, setBusyByBot] = React19.useState({});
10371
- const [feedbackByBot, setFeedbackByBot] = React19.useState({});
10372
- const [removeTarget, setRemoveTarget] = React19.useState(null);
10373
- const [notice, setNotice] = React19.useState("");
10374
- const [now, setNow] = React19.useState(() => Date.now());
10375
- const addButtonRef = React19.useRef(null);
10376
- const mountedRef = React19.useRef(true);
10405
+ const [provision, setProvision] = React18.useState(null);
10406
+ const [busy, setBusy] = React18.useState(false);
10407
+ const [busyByBot, setBusyByBot] = React18.useState({});
10408
+ const [feedbackByBot, setFeedbackByBot] = React18.useState({});
10409
+ const [removeTarget, setRemoveTarget] = React18.useState(null);
10410
+ const [notice, setNotice] = React18.useState("");
10411
+ const [now, setNow] = React18.useState(() => Date.now());
10412
+ const addButtonRef = React18.useRef(null);
10413
+ const mountedRef = React18.useRef(true);
10377
10414
  const workspaceFence = useWorkspaceSnapshotFence();
10378
10415
  const scheduleAnimationFrame = useAnimationFrameScheduler();
10379
- React19.useEffect(() => {
10416
+ React18.useEffect(() => {
10380
10417
  mountedRef.current = true;
10381
10418
  return () => {
10382
10419
  mountedRef.current = false;
10383
10420
  };
10384
10421
  }, []);
10385
- const announce = React19.useCallback((value) => {
10422
+ const announce = React18.useCallback((value) => {
10386
10423
  setNotice("");
10387
10424
  scheduleAnimationFrame(() => {
10388
10425
  if (value) setNotice(value);
10389
10426
  }, "announcement");
10390
10427
  }, [scheduleAnimationFrame]);
10391
- const invoke = React19.useCallback(async (endpoint, payload = {}, signal) => {
10428
+ const invoke = React18.useCallback(async (endpoint, payload = {}, signal) => {
10392
10429
  return unwrapRpcResult8(await rpcCall(endpoint, payload, signal));
10393
10430
  }, [rpcCall]);
10394
- const loadStatus = React19.useCallback(async ({
10431
+ const loadStatus = React18.useCallback(async ({
10395
10432
  signal,
10396
10433
  silent = false,
10397
10434
  restoreProvisioning = false
@@ -10428,12 +10465,12 @@ function WeixinSettingsTab({ rpcCall }) {
10428
10465
  return void 0;
10429
10466
  }
10430
10467
  }, [invoke, workspaceFence]);
10431
- React19.useEffect(() => {
10468
+ React18.useEffect(() => {
10432
10469
  const controller = new AbortController();
10433
10470
  void loadStatus({ signal: controller.signal, restoreProvisioning: true });
10434
10471
  return () => controller.abort();
10435
10472
  }, [loadStatus]);
10436
- React19.useEffect(() => {
10473
+ React18.useEffect(() => {
10437
10474
  if (model.phase !== "ready") return void 0;
10438
10475
  const controller = new AbortController();
10439
10476
  let running = false;
@@ -10452,12 +10489,12 @@ function WeixinSettingsTab({ rpcCall }) {
10452
10489
  window.clearInterval(timer);
10453
10490
  };
10454
10491
  }, [loadStatus, model.phase]);
10455
- React19.useEffect(() => {
10492
+ React18.useEffect(() => {
10456
10493
  if (!provision || !["pending", "scanned"].includes(provision.status)) return void 0;
10457
10494
  const timer = window.setInterval(() => setNow(Date.now()), 1e3);
10458
10495
  return () => window.clearInterval(timer);
10459
10496
  }, [provision?.attemptId, provision?.status]);
10460
- const startProvisioning = React19.useCallback(async ({ replace = false } = {}) => {
10497
+ const startProvisioning = React18.useCallback(async ({ replace = false } = {}) => {
10461
10498
  setBusy(true);
10462
10499
  try {
10463
10500
  if (replace && provision?.attemptId) {
@@ -10478,7 +10515,7 @@ function WeixinSettingsTab({ rpcCall }) {
10478
10515
  setBusy(false);
10479
10516
  }
10480
10517
  }, [announce, invoke, provision?.attemptId]);
10481
- const cancelProvisioning = React19.useCallback(async () => {
10518
+ const cancelProvisioning = React18.useCallback(async () => {
10482
10519
  setBusy(true);
10483
10520
  try {
10484
10521
  if (provision?.attemptId && !["failed", "expired", "cancelled"].includes(provision.status)) {
@@ -10493,7 +10530,7 @@ function WeixinSettingsTab({ rpcCall }) {
10493
10530
  setBusy(false);
10494
10531
  }
10495
10532
  }, [announce, invoke, provision?.attemptId, provision?.status, scheduleAnimationFrame]);
10496
- const submitVerification = React19.useCallback(async (verifyCode) => {
10533
+ const submitVerification = React18.useCallback(async (verifyCode) => {
10497
10534
  if (!provision?.attemptId) return;
10498
10535
  setBusy(true);
10499
10536
  try {
@@ -10509,7 +10546,7 @@ function WeixinSettingsTab({ rpcCall }) {
10509
10546
  setBusy(false);
10510
10547
  }
10511
10548
  }, [announce, invoke, provision?.attemptId]);
10512
- React19.useEffect(() => {
10549
+ React18.useEffect(() => {
10513
10550
  const attemptId = provision?.attemptId;
10514
10551
  if (!attemptId || !["pending", "scanned", "connecting"].includes(provision.status)) return void 0;
10515
10552
  const controller = new AbortController();
@@ -10557,7 +10594,7 @@ function WeixinSettingsTab({ rpcCall }) {
10557
10594
  controller.abort();
10558
10595
  };
10559
10596
  }, [announce, invoke, loadStatus, provision?.attemptId, provision?.status, provision?.pollIntervalMs]);
10560
- const setBotBusy = React19.useCallback((botId, value) => {
10597
+ const setBotBusy = React18.useCallback((botId, value) => {
10561
10598
  setBusyByBot((current) => {
10562
10599
  const next = { ...current };
10563
10600
  if (value) next[botId] = value;
@@ -10565,7 +10602,7 @@ function WeixinSettingsTab({ rpcCall }) {
10565
10602
  return next;
10566
10603
  });
10567
10604
  }, []);
10568
- const reconnect = React19.useCallback(async (account) => {
10605
+ const reconnect = React18.useCallback(async (account) => {
10569
10606
  const snapshotVersion = workspaceFence.beginMutation();
10570
10607
  setBotBusy(account.botId, "reconnect");
10571
10608
  setFeedbackByBot((current) => {
@@ -10616,7 +10653,7 @@ function WeixinSettingsTab({ rpcCall }) {
10616
10653
  setBotBusy(account.botId, null);
10617
10654
  }
10618
10655
  }, [announce, invoke, loadStatus, setBotBusy, workspaceFence]);
10619
- const saveWorkspace = React19.useCallback(async (account, workspace) => {
10656
+ const saveWorkspace = React18.useCallback(async (account, workspace) => {
10620
10657
  const workspaceVersion = workspaceFence.beginMutation();
10621
10658
  setBotBusy(account.botId, "workspace");
10622
10659
  try {
@@ -10640,7 +10677,7 @@ function WeixinSettingsTab({ rpcCall }) {
10640
10677
  if (mountedRef.current) setBotBusy(account.botId, null);
10641
10678
  }
10642
10679
  }, [invoke, loadStatus, setBotBusy, workspaceFence]);
10643
- const saveBotSetting = React19.useCallback(async (account, operation, endpoint, payload) => {
10680
+ const saveBotSetting = React18.useCallback(async (account, operation, endpoint, payload) => {
10644
10681
  const snapshotVersion = workspaceFence.beginMutation();
10645
10682
  setBotBusy(account.botId, operation);
10646
10683
  try {
@@ -10664,7 +10701,7 @@ function WeixinSettingsTab({ rpcCall }) {
10664
10701
  if (mountedRef.current) setBotBusy(account.botId, null);
10665
10702
  }
10666
10703
  }, [invoke, loadStatus, setBotBusy, workspaceFence]);
10667
- const remove = React19.useCallback(async (account) => {
10704
+ const remove = React18.useCallback(async (account) => {
10668
10705
  const snapshotVersion = workspaceFence.beginMutation();
10669
10706
  setBotBusy(account.botId, "delete");
10670
10707
  try {
@@ -10748,7 +10785,7 @@ function WeixinSettingsTab({ rpcCall }) {
10748
10785
  h2(Button12, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
10749
10786
  )
10750
10787
  ) : h2(
10751
- React19.Fragment,
10788
+ React18.Fragment,
10752
10789
  null,
10753
10790
  provisionView,
10754
10791
  model.bots.length === 0 && !provision ? h2(EmptyView5, { onStart: () => void startProvisioning(), busy }) : null,
@@ -10975,12 +11012,7 @@ function normalizeBot6(value) {
10975
11012
  workspace: text5(value.workspace, "", 4096),
10976
11013
  agentPreset: normalizeAgentPresetId(value.agentPreset),
10977
11014
  contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
10978
- accessPolicy: {
10979
- accessMode: ["self-only", "private-allowlist", "open"].includes(
10980
- value.accessPolicy?.accessMode
10981
- ) ? value.accessPolicy.accessMode : "self-only",
10982
- allowedNumbers: Array.isArray(value.accessPolicy?.allowedNumbers) ? [...new Set(value.accessPolicy.allowedNumbers.filter((entry) => typeof entry === "string" && /^[1-9]\d{4,14}$/.test(entry)))] : []
10983
- },
11015
+ ...Object.hasOwn(value, "accessPolicy") ? { accessPolicy: normalizeAccessPolicy(value.accessPolicy) } : {},
10984
11016
  bot: {
10985
11017
  name: text5(value.bot?.name, "WhatsApp\u673A\u5668\u4EBA", 100),
10986
11018
  idMasked: text5(value.bot?.idMasked, "WhatsApp\u8D26\u53F7", 140)
@@ -11022,7 +11054,7 @@ function formatRemaining6(milliseconds) {
11022
11054
  }
11023
11055
 
11024
11056
  // plugin-src/client/channels/whatsapp/index.js
11025
- var React20 = __toESM(require("react"), 1);
11057
+ var React19 = __toESM(require("react"), 1);
11026
11058
 
11027
11059
  // plugin-src/client/channels/whatsapp/styles.js
11028
11060
  var WHATSAPP_STYLE_ID = "xmanrui-dsh-im-whatsapp-settings";
@@ -11030,31 +11062,6 @@ var CSS10 = String.raw`
11030
11062
  .dwa-page { --ddt-accent: #25d366; --ddt-accent-deep: #128c7e; --ddt-accent-wash: #eafbf0; }
11031
11063
  .dwa-avatar { color: #fff; background: #25d366; }
11032
11064
  .dwa-avatar svg { display: block; }
11033
- .dwa-access { display: grid; gap: 10px; padding: 12px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 10px; background: var(--dsw-alias-bg-layer-2, #f7f8fa); }
11034
- .dwa-accessHeading { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
11035
- .dwa-accessHeading > strong { font-size: 13px; }
11036
- .dwa-accessStatus { min-width: 0; display: inline-flex; align-items: center; justify-content: flex-end; gap: 6px; }
11037
- .dwa-accessBadge { flex: none; padding: 3px 8px; border-radius: 999px; color: #08785f; background: #eafbf0; font-size: 11px; font-weight: 700; }
11038
- .dwa-accessBadge[data-mode="private-allowlist"] { color: #0f6f8f; background: #eaf7fd; }
11039
- .dwa-accessBadge[data-mode="open"] { color: #a15c00; background: #fff3d6; }
11040
- .dwa-accessHelp { position: relative; display: inline-flex; flex: none; }
11041
- .dwa-accessHelpButton { width: 20px; height: 20px; display: grid; place-items: center; padding: 0; border: 1px solid color-mix(in srgb, #25d366 34%, var(--dsw-alias-border-l2, #dfe1e5)); border-radius: 50%; color: #128c7e; background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 12px; line-height: 1; font-weight: 750; cursor: help; }
11042
- .dwa-accessTooltip { position: absolute; top: calc(100% + 8px); right: 0; z-index: 30; width: 270px; max-width: min(290px, calc(100vw - 48px)); display: grid; gap: 8px; padding: 10px 11px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 9px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 10px 28px rgb(31 35 41 / 16%); opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
11043
- .dwa-accessTooltipItem { display: grid; gap: 2px; }
11044
- .dwa-accessTooltipItem + .dwa-accessTooltipItem { padding-top: 8px; border-top: 1px solid var(--dsw-alias-border-l2, #eef0f3); }
11045
- .dwa-accessTooltipItem strong { font-size: 12px; line-height: 17px; }
11046
- .dwa-accessTooltipItem > span { color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 16px; }
11047
- .dwa-accessHelp:hover .dwa-accessTooltip, .dwa-accessHelp:focus-within .dwa-accessTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
11048
- .dwa-accessField { display: grid; gap: 5px; color: var(--dsw-alias-label-primary, #1f2329); font-size: 12px; font-weight: 600; }
11049
- .dwa-accessField select, .dwa-accessField textarea { width: 100%; box-sizing: border-box; border: 1px solid var(--dsw-alias-border-l1, #c9cdd4); border-radius: 7px; color: inherit; background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-weight: 400; }
11050
- .dwa-accessField select { height: 34px; padding: 0 9px; }
11051
- .dwa-accessField textarea { min-height: 68px; padding: 8px 9px; resize: vertical; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
11052
- .dwa-accessField textarea:disabled { color: var(--dsw-alias-label-tertiary, #8f959e); background: var(--dsw-alias-bg-module-platform, #f2f3f5); cursor: not-allowed; resize: none; opacity: 1; }
11053
- .dwa-accessField small { color: var(--dsw-alias-label-secondary, #646a73); font-weight: 400; }
11054
- .dwa-accessWarning, .dwa-accessError { margin: 0; font-size: 12px; line-height: 1.5; }
11055
- .dwa-accessWarning { color: #a15c00; }
11056
- .dwa-accessError { color: var(--dsw-alias-state-error-primary, #d83931); }
11057
- .dwa-accessActions { display: flex; justify-content: flex-end; }
11058
11065
  `;
11059
11066
  function installWhatsappStyles() {
11060
11067
  if (typeof document === "undefined") return () => {
@@ -11072,193 +11079,43 @@ function installWhatsappStyles() {
11072
11079
 
11073
11080
  // plugin-src/client/channels/whatsapp/index.js
11074
11081
  var ACTIVE_STATES3 = /* @__PURE__ */ new Set(["pending", "connecting"]);
11075
- function accessPolicyFor(account) {
11076
- const accessMode = ["self-only", "private-allowlist", "open"].includes(
11077
- account?.accessPolicy?.accessMode
11078
- ) ? account.accessPolicy.accessMode : "self-only";
11079
- return {
11080
- accessMode,
11081
- allowedNumbers: Array.isArray(account?.accessPolicy?.allowedNumbers) ? account.accessPolicy.allowedNumbers : []
11082
- };
11082
+ var Button14 = React19.forwardRef(function Button15({ children, kind = "secondary", className = "", ...props }, ref) {
11083
+ return h2("button", {
11084
+ ...props,
11085
+ ref,
11086
+ type: "button",
11087
+ className: `ddt-button ${className}`.trim(),
11088
+ "data-kind": kind
11089
+ }, children);
11090
+ });
11091
+ function checkedTime6(value) {
11092
+ if (!value) return "\u5C1A\u672A\u68C0\u67E5";
11093
+ try {
11094
+ return new Intl.DateTimeFormat("zh-CN", {
11095
+ hour: "2-digit",
11096
+ minute: "2-digit",
11097
+ second: "2-digit"
11098
+ }).format(new Date(value));
11099
+ } catch {
11100
+ return "\u521A\u521A";
11101
+ }
11083
11102
  }
11084
- function allowedNumbersFromText(value) {
11085
- const entries = value.split(/\r?\n/).map((entry) => entry.trim()).filter(Boolean);
11086
- const normalized = entries.map((entry) => entry.replace(/^\+/, ""));
11087
- if (normalized.some((entry) => !/^[1-9]\d{4,14}$/.test(entry))) {
11088
- throw new TypeError("\u7535\u8BDD\u53F7\u7801\u5FC5\u987B\u5305\u542B\u56FD\u5BB6\u6216\u5730\u533A\u4EE3\u7801\uFF0C\u6BCF\u884C\u4E00\u4E2A\u3002");
11103
+ function connectionTestNotice3(value) {
11104
+ if (value?.testMessage?.sent === true) {
11105
+ return "\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\uFF0C\u8BF7\u5230 WhatsApp \u81EA\u804A\u4F1A\u8BDD\u4E2D\u786E\u8BA4\u3002";
11089
11106
  }
11090
- return [...new Set(normalized)];
11091
- }
11092
- function WhatsappAccessSettings({ account, busy = false, onSave }) {
11093
- const policy = accessPolicyFor(account);
11094
- const sourceNumbers = policy.allowedNumbers.join("\n");
11095
- const helpId = React20.useId();
11096
- const [accessMode, setAccessMode] = React20.useState(policy.accessMode);
11097
- const [allowedNumbers, setAllowedNumbers] = React20.useState(sourceNumbers);
11098
- const [error, setError] = React20.useState(null);
11099
- React20.useEffect(() => {
11100
- setAccessMode(policy.accessMode);
11101
- setAllowedNumbers(sourceNumbers);
11102
- setError(null);
11103
- }, [policy.accessMode, sourceNumbers]);
11104
- const save = async (event) => {
11105
- event.preventDefault();
11106
- setError(null);
11107
- try {
11108
- const normalized = allowedNumbersFromText(allowedNumbers);
11109
- if (typeof onSave !== "function") throw new Error("WhatsApp \u8BBF\u95EE\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
11110
- await onSave({ accessMode, allowedNumbers: normalized });
11111
- } catch (caught) {
11112
- setError(caught?.message ?? "WhatsApp \u8BBF\u95EE\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\u3002");
11113
- }
11114
- };
11115
- const allowlistEnabled = accessMode === "private-allowlist";
11116
- const labels = {
11117
- "self-only": "\u4EC5\u81EA\u5DF1\u6A21\u5F0F",
11118
- "private-allowlist": "\u6307\u5B9A\u8054\u7CFB\u4EBA\u6A21\u5F0F",
11119
- open: "\u5F00\u653E\u54CD\u5E94\u6A21\u5F0F"
11120
- };
11107
+ if (value?.testMessage?.code === "test-target-unavailable") {
11108
+ return "\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u5F53\u524D\u6CA1\u6709\u53EF\u7528\u7684 WhatsApp \u81EA\u804A\u76EE\u6807\u3002";
11109
+ }
11110
+ return value?.testMessage ? "\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002" : null;
11111
+ }
11112
+ function Heading6({ totals, busy, onAdd, addButtonRef }) {
11121
11113
  return h2(
11122
- "form",
11123
- { className: "dwa-access", onSubmit: save },
11114
+ "div",
11115
+ { className: "ddt-heading" },
11124
11116
  h2(
11125
11117
  "div",
11126
- { className: "dwa-accessHeading" },
11127
- h2("strong", null, "\u8BBF\u95EE\u8BBE\u7F6E"),
11128
- h2(
11129
- "span",
11130
- { className: "dwa-accessStatus" },
11131
- h2(
11132
- "span",
11133
- { className: "dwa-accessBadge", "data-mode": policy.accessMode },
11134
- ["\u5DF2\u751F\u6548\uFF1A", labels[policy.accessMode]]
11135
- ),
11136
- h2(
11137
- "span",
11138
- { className: "dwa-accessHelp" },
11139
- h2("button", {
11140
- type: "button",
11141
- className: "dwa-accessHelpButton",
11142
- "aria-label": "\u67E5\u770B WhatsApp \u8BBF\u95EE\u6A21\u5F0F\u8BF4\u660E",
11143
- "aria-describedby": helpId
11144
- }, h2("span", { "aria-hidden": "true" }, "?")),
11145
- h2(
11146
- "span",
11147
- { id: helpId, className: "dwa-accessTooltip", role: "tooltip" },
11148
- h2(
11149
- "span",
11150
- { className: "dwa-accessTooltipItem" },
11151
- h2("strong", null, "\u4EC5\u81EA\u5DF1\u6A21\u5F0F"),
11152
- h2("span", null, "\u53EA\u54CD\u5E94\u5DF2\u7ED1\u5B9A WhatsApp \u8D26\u53F7\u7684\u81EA\u804A\u6D88\u606F\u3002")
11153
- ),
11154
- h2(
11155
- "span",
11156
- { className: "dwa-accessTooltipItem" },
11157
- h2("strong", null, "\u6307\u5B9A\u8054\u7CFB\u4EBA\u6A21\u5F0F"),
11158
- h2("span", null, "\u54CD\u5E94\u81EA\u804A\u548C\u767D\u540D\u5355\u8054\u7CFB\u4EBA\u7684\u79C1\u804A\uFF0C\u5FFD\u7565\u7FA4\u804A\u3002")
11159
- ),
11160
- h2(
11161
- "span",
11162
- { className: "dwa-accessTooltipItem" },
11163
- h2("strong", null, "\u5F00\u653E\u54CD\u5E94\u6A21\u5F0F"),
11164
- h2("span", null, "\u54CD\u5E94\u6240\u6709\u79C1\u804A\u3001\u5DF2\u7ED1\u5B9A\u8D26\u53F7\u81EA\u5DF1\u53D1\u51FA\u7684\u7FA4\u804A\u6D88\u606F\uFF0C\u4EE5\u53CA\u5176\u4ED6\u7FA4\u6210\u5458\u7684\u63D0\u53CA\u6216\u56DE\u590D\u3002")
11165
- )
11166
- )
11167
- )
11168
- )
11169
- ),
11170
- h2(
11171
- "label",
11172
- { className: "dwa-accessField" },
11173
- h2("span", null, "\u6A21\u5F0F"),
11174
- h2(
11175
- "select",
11176
- {
11177
- value: accessMode,
11178
- disabled: busy,
11179
- "aria-label": "WhatsApp \u8BBF\u95EE\u6A21\u5F0F",
11180
- onChange: (event) => {
11181
- setAccessMode(event.target.value);
11182
- setError(null);
11183
- }
11184
- },
11185
- h2("option", { value: "self-only" }, "\u4EC5\u81EA\u5DF1\u6A21\u5F0F\uFF08\u9ED8\u8BA4\uFF09"),
11186
- h2("option", { value: "private-allowlist" }, "\u6307\u5B9A\u8054\u7CFB\u4EBA\u6A21\u5F0F"),
11187
- h2("option", { value: "open" }, "\u5F00\u653E\u54CD\u5E94\u6A21\u5F0F")
11188
- )
11189
- ),
11190
- allowlistEnabled ? h2(
11191
- "label",
11192
- { className: "dwa-accessField" },
11193
- h2("span", null, "\u5141\u8BB8\u79C1\u804A\u7684 WhatsApp \u7535\u8BDD\u53F7\u7801"),
11194
- h2("textarea", {
11195
- value: allowedNumbers,
11196
- disabled: busy,
11197
- rows: 3,
11198
- placeholder: "\u6BCF\u884C\u4E00\u4E2A\u542B\u56FD\u5BB6\u6216\u5730\u533A\u4EE3\u7801\u7684\u53F7\u7801",
11199
- "aria-label": "\u5141\u8BB8\u79C1\u804A\u7684 WhatsApp \u7535\u8BDD\u53F7\u7801",
11200
- onChange: (event) => {
11201
- setAllowedNumbers(event.target.value);
11202
- setError(null);
11203
- }
11204
- }),
11205
- h2("small", null, "\u53EF\u4EE5\u5305\u542B\u5F00\u5934\u7684 +\uFF0C\u4FDD\u5B58\u65F6\u4F1A\u81EA\u52A8\u79FB\u9664\u3002")
11206
- ) : null,
11207
- allowlistEnabled && allowedNumbers.trim() === "" ? h2(
11208
- "p",
11209
- { className: "dwa-accessWarning", role: "status" },
11210
- "\u767D\u540D\u5355\u4E3A\u7A7A\uFF1B\u4FDD\u5B58\u540E\u5C06\u53EA\u63A5\u53D7\u81EA\u804A\u6D88\u606F\u3002"
11211
- ) : null,
11212
- error ? h2("p", { className: "dwa-accessError", role: "alert" }, error) : null,
11213
- h2(
11214
- "div",
11215
- { className: "dwa-accessActions" },
11216
- h2("button", {
11217
- type: "submit",
11218
- className: "ddt-button",
11219
- "data-kind": "secondary",
11220
- disabled: busy
11221
- }, busy ? "\u6B63\u5728\u4FDD\u5B58\u2026" : "\u4FDD\u5B58\u8BBF\u95EE\u8BBE\u7F6E")
11222
- )
11223
- );
11224
- }
11225
- var Button14 = React20.forwardRef(function Button15({ children, kind = "secondary", className = "", ...props }, ref) {
11226
- return h2("button", {
11227
- ...props,
11228
- ref,
11229
- type: "button",
11230
- className: `ddt-button ${className}`.trim(),
11231
- "data-kind": kind
11232
- }, children);
11233
- });
11234
- function checkedTime6(value) {
11235
- if (!value) return "\u5C1A\u672A\u68C0\u67E5";
11236
- try {
11237
- return new Intl.DateTimeFormat("zh-CN", {
11238
- hour: "2-digit",
11239
- minute: "2-digit",
11240
- second: "2-digit"
11241
- }).format(new Date(value));
11242
- } catch {
11243
- return "\u521A\u521A";
11244
- }
11245
- }
11246
- function connectionTestNotice3(value) {
11247
- if (value?.testMessage?.sent === true) {
11248
- return "\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\uFF0C\u8BF7\u5230 WhatsApp \u81EA\u804A\u4F1A\u8BDD\u4E2D\u786E\u8BA4\u3002";
11249
- }
11250
- if (value?.testMessage?.code === "test-target-unavailable") {
11251
- return "\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u5F53\u524D\u6CA1\u6709\u53EF\u7528\u7684 WhatsApp \u81EA\u804A\u76EE\u6807\u3002";
11252
- }
11253
- return value?.testMessage ? "\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002" : null;
11254
- }
11255
- function Heading6({ totals, busy, onAdd, addButtonRef }) {
11256
- return h2(
11257
- "div",
11258
- { className: "ddt-heading" },
11259
- h2(
11260
- "div",
11261
- { className: "ddt-tools" },
11118
+ { className: "ddt-tools" },
11262
11119
  h2(
11263
11120
  "div",
11264
11121
  { className: "dim-bindActions" },
@@ -11446,7 +11303,6 @@ function WhatsappAccountCard({
11446
11303
  onWorkspaceSave,
11447
11304
  onAgentPresetSave,
11448
11305
  onContextEnhancementSave,
11449
- onAccessPolicySave,
11450
11306
  onRequestRemove,
11451
11307
  onConfirmRemove,
11452
11308
  onCancelRemove
@@ -11493,7 +11349,8 @@ function WhatsappAccountCard({
11493
11349
  channel: "whatsapp",
11494
11350
  botId: account.botId,
11495
11351
  botName: account.bot.name,
11496
- connected: account.connected
11352
+ connected: account.connected,
11353
+ accessPolicy: account.accessPolicy
11497
11354
  })
11498
11355
  )
11499
11356
  ),
@@ -11512,11 +11369,6 @@ function WhatsappAccountCard({
11512
11369
  disabled: Boolean(busy),
11513
11370
  onSave: onContextEnhancementSave
11514
11371
  }),
11515
- h2(WhatsappAccessSettings, {
11516
- account,
11517
- busy: Boolean(busy),
11518
- onSave: onAccessPolicySave
11519
- }),
11520
11372
  h2(
11521
11373
  "div",
11522
11374
  { className: "ddt-accountFooter dim-cardFooter" },
@@ -11559,23 +11411,23 @@ function WhatsappAccountCard({
11559
11411
  );
11560
11412
  }
11561
11413
  function WhatsappSettingsTab({ rpcCall }) {
11562
- const [model, setModel] = React20.useState({
11414
+ const [model, setModel] = React19.useState({
11563
11415
  phase: "loading",
11564
11416
  bots: [],
11565
11417
  totals: { configured: 0, connected: 0 },
11566
11418
  error: null,
11567
11419
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
11568
11420
  });
11569
- const [provision, setProvision] = React20.useState(null);
11570
- const [busy, setBusy] = React20.useState(false);
11571
- const [busyByBot, setBusyByBot] = React20.useState({});
11572
- const [testNoticeByBot, setTestNoticeByBot] = React20.useState({});
11573
- const [removeTarget, setRemoveTarget] = React20.useState(null);
11574
- const [now, setNow] = React20.useState(Date.now());
11575
- const mounted = React20.useRef(true);
11421
+ const [provision, setProvision] = React19.useState(null);
11422
+ const [busy, setBusy] = React19.useState(false);
11423
+ const [busyByBot, setBusyByBot] = React19.useState({});
11424
+ const [testNoticeByBot, setTestNoticeByBot] = React19.useState({});
11425
+ const [removeTarget, setRemoveTarget] = React19.useState(null);
11426
+ const [now, setNow] = React19.useState(Date.now());
11427
+ const mounted = React19.useRef(true);
11576
11428
  const workspaceFence = useWorkspaceSnapshotFence();
11577
- const addButtonRef = React20.useRef(null);
11578
- React20.useEffect(() => {
11429
+ const addButtonRef = React19.useRef(null);
11430
+ React19.useEffect(() => {
11579
11431
  const disposeDingtalk = installDingtalkStyles();
11580
11432
  const disposeWhatsapp = installWhatsappStyles();
11581
11433
  mounted.current = true;
@@ -11585,11 +11437,11 @@ function WhatsappSettingsTab({ rpcCall }) {
11585
11437
  disposeDingtalk();
11586
11438
  };
11587
11439
  }, []);
11588
- const invoke = React20.useCallback(async (endpoint, payload = {}, signal) => {
11440
+ const invoke = React19.useCallback(async (endpoint, payload = {}, signal) => {
11589
11441
  if (typeof rpcCall !== "function") throw new TypeError("WhatsApp \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
11590
11442
  return unwrapRpcResult9(await rpcCall(endpoint, payload, signal));
11591
11443
  }, [rpcCall]);
11592
- const loadStatus = React20.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
11444
+ const loadStatus = React19.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
11593
11445
  const workspaceVersion = workspaceFence.beginStatus();
11594
11446
  if (workspaceVersion === null) return void 0;
11595
11447
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
@@ -11619,12 +11471,12 @@ function WhatsappSettingsTab({ rpcCall }) {
11619
11471
  return void 0;
11620
11472
  }
11621
11473
  }, [invoke, workspaceFence]);
11622
- React20.useEffect(() => {
11474
+ React19.useEffect(() => {
11623
11475
  const controller = new AbortController();
11624
11476
  void loadStatus({ signal: controller.signal, restore: true });
11625
11477
  return () => controller.abort();
11626
11478
  }, [loadStatus]);
11627
- React20.useEffect(() => {
11479
+ React19.useEffect(() => {
11628
11480
  if (model.phase !== "ready") return void 0;
11629
11481
  const controller = new AbortController();
11630
11482
  const timer = window.setInterval(
@@ -11636,12 +11488,12 @@ function WhatsappSettingsTab({ rpcCall }) {
11636
11488
  window.clearInterval(timer);
11637
11489
  };
11638
11490
  }, [loadStatus, model.phase]);
11639
- React20.useEffect(() => {
11491
+ React19.useEffect(() => {
11640
11492
  if (!provision || !ACTIVE_STATES3.has(provision.status)) return void 0;
11641
11493
  const timer = window.setInterval(() => mounted.current && setNow(Date.now()), 1e3);
11642
11494
  return () => window.clearInterval(timer);
11643
11495
  }, [provision?.attemptId, provision?.status]);
11644
- const startProvisioning = React20.useCallback(async (replace = false) => {
11496
+ const startProvisioning = React19.useCallback(async (replace = false) => {
11645
11497
  setBusy(true);
11646
11498
  try {
11647
11499
  if (replace && provision?.attemptId) {
@@ -11659,7 +11511,7 @@ function WhatsappSettingsTab({ rpcCall }) {
11659
11511
  if (mounted.current) setBusy(false);
11660
11512
  }
11661
11513
  }, [invoke, provision?.attemptId]);
11662
- const closeProvision = React20.useCallback(async () => {
11514
+ const closeProvision = React19.useCallback(async () => {
11663
11515
  setBusy(true);
11664
11516
  try {
11665
11517
  if (provision?.attemptId && ACTIVE_STATES3.has(provision.status)) {
@@ -11670,7 +11522,7 @@ function WhatsappSettingsTab({ rpcCall }) {
11670
11522
  if (mounted.current) setBusy(false);
11671
11523
  }
11672
11524
  }, [invoke, provision?.attemptId, provision?.status]);
11673
- React20.useEffect(() => {
11525
+ React19.useEffect(() => {
11674
11526
  const attemptId = provision?.attemptId;
11675
11527
  if (!attemptId || !ACTIVE_STATES3.has(provision.status)) return void 0;
11676
11528
  const controller = new AbortController();
@@ -11711,7 +11563,7 @@ function WhatsappSettingsTab({ rpcCall }) {
11711
11563
  if (timer) window.clearTimeout(timer);
11712
11564
  };
11713
11565
  }, [invoke, loadStatus, provision?.attemptId, provision?.status]);
11714
- const botAction = React20.useCallback(async (account, operation, endpoint, payload) => {
11566
+ const botAction = React19.useCallback(async (account, operation, endpoint, payload) => {
11715
11567
  const snapshotVersion = workspaceFence.beginMutation();
11716
11568
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
11717
11569
  if (operation === "reconnect") {
@@ -11794,12 +11646,6 @@ function WhatsappSettingsTab({ rpcCall }) {
11794
11646
  WHATSAPP_ENDPOINTS.setContextEnhancement,
11795
11647
  { botId: account.botId, config }
11796
11648
  ),
11797
- onAccessPolicySave: (accessPolicy) => botAction(
11798
- account,
11799
- "access",
11800
- WHATSAPP_ENDPOINTS.setAccessPolicy,
11801
- { botId: account.botId, ...accessPolicy }
11802
- ),
11803
11649
  onRequestRemove: () => setRemoveTarget(account.botId),
11804
11650
  onCancelRemove: () => setRemoveTarget(null),
11805
11651
  onConfirmRemove: async () => {
@@ -11836,7 +11682,7 @@ function WhatsappSettingsTab({ rpcCall }) {
11836
11682
  h2(Button14, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
11837
11683
  )
11838
11684
  ) : h2(
11839
- React20.Fragment,
11685
+ React19.Fragment,
11840
11686
  null,
11841
11687
  provision?.status === "pending" ? h2(QrPanel5, {
11842
11688
  provision,
@@ -11857,6 +11703,404 @@ function WhatsappSettingsTab({ rpcCall }) {
11857
11703
 
11858
11704
  // plugin-src/client/delivery-settings.js
11859
11705
  var React21 = __toESM(require("react"), 1);
11706
+
11707
+ // plugin-src/client/access-policy-settings.js
11708
+ var React20 = __toESM(require("react"), 1);
11709
+ var ACCESS_POLICY_ENDPOINT = "bot.access-policy.set";
11710
+ var ACCESS_CHANNEL_DEFINITIONS = Object.freeze({
11711
+ weixin: Object.freeze({
11712
+ directUserLabel: "\u5FAE\u4FE1\u7528\u6237 ID",
11713
+ directPlaceholder: "\u586B\u5199\u5FAE\u4FE1\u7528\u6237 ID",
11714
+ groupSupported: false
11715
+ }),
11716
+ feishu: Object.freeze({
11717
+ directUserLabel: "\u98DE\u4E66 Open ID",
11718
+ directPlaceholder: "ou_xxx",
11719
+ groupUserLabel: "\u7FA4\u6210\u5458 Open ID",
11720
+ groupPlaceholder: "ou_xxx"
11721
+ }),
11722
+ dingtalk: Object.freeze({
11723
+ directUserLabel: "\u9489\u9489\u7528\u6237 ID",
11724
+ directPlaceholder: "\u586B\u5199 senderStaffId \u6216 senderId",
11725
+ groupUserLabel: "\u7FA4\u6210\u5458\u7528\u6237 ID",
11726
+ groupPlaceholder: "\u586B\u5199 senderStaffId \u6216 senderId"
11727
+ }),
11728
+ wecom: Object.freeze({
11729
+ directUserLabel: "\u4F01\u4E1A\u5FAE\u4FE1\u7528\u6237 ID",
11730
+ directPlaceholder: "\u586B\u5199 userid",
11731
+ groupUserLabel: "\u7FA4\u6210\u5458\u7528\u6237 ID",
11732
+ groupPlaceholder: "\u586B\u5199 userid"
11733
+ }),
11734
+ qq: Object.freeze({
11735
+ directUserLabel: "QQ User Open ID",
11736
+ directPlaceholder: "\u586B\u5199 user_openid",
11737
+ groupUserLabel: "\u7FA4\u6210\u5458 Open ID",
11738
+ groupPlaceholder: "\u586B\u5199 member_openid"
11739
+ }),
11740
+ slack: Object.freeze({
11741
+ directUserLabel: "Slack User ID",
11742
+ directPlaceholder: "U0123456789",
11743
+ groupUserLabel: "\u7FA4\u6210\u5458 User ID",
11744
+ groupPlaceholder: "U0123456789"
11745
+ }),
11746
+ telegram: Object.freeze({
11747
+ directUserLabel: "Telegram User ID",
11748
+ directPlaceholder: "\u586B\u5199\u6570\u5B57 User ID",
11749
+ groupUserLabel: "\u7FA4\u6210\u5458 User ID",
11750
+ groupPlaceholder: "\u586B\u5199\u6570\u5B57 User ID"
11751
+ }),
11752
+ discord: Object.freeze({
11753
+ directUserLabel: "Discord User ID",
11754
+ directPlaceholder: "\u586B\u5199\u6570\u5B57 User ID",
11755
+ groupUserLabel: "\u7FA4\u6210\u5458 User ID",
11756
+ groupPlaceholder: "\u586B\u5199\u6570\u5B57 User ID"
11757
+ }),
11758
+ whatsapp: Object.freeze({
11759
+ directUserLabel: "WhatsApp \u7535\u8BDD\u53F7\u7801\u6216 JID",
11760
+ directPlaceholder: "8613800000000 \u6216\u5B8C\u6574 JID",
11761
+ groupUserLabel: "\u7FA4\u6210\u5458\u7535\u8BDD\u53F7\u7801\u6216 JID",
11762
+ groupPlaceholder: "8613800000000 \u6216\u5B8C\u6574 JID"
11763
+ })
11764
+ });
11765
+ function clonePolicy(policy) {
11766
+ const cloneScope = (scope) => ({
11767
+ mode: scope.mode,
11768
+ open: {
11769
+ defaultCanExecuteCommands: scope.open.defaultCanExecuteCommands,
11770
+ commandPermissionOverrides: scope.open.commandPermissionOverrides.map((user) => ({
11771
+ ...user
11772
+ }))
11773
+ },
11774
+ allowlist: {
11775
+ users: scope.allowlist.users.map((user) => ({ ...user }))
11776
+ }
11777
+ });
11778
+ return {
11779
+ direct: cloneScope(policy.direct),
11780
+ group: cloneScope(policy.group)
11781
+ };
11782
+ }
11783
+ function unwrapRpcResult10(result) {
11784
+ if (result?.ok === true) return result.value;
11785
+ if (result?.ok === false) {
11786
+ const error = new Error(result.error?.message || "\u8BBF\u95EE\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
11787
+ error.code = result.error?.code;
11788
+ throw error;
11789
+ }
11790
+ return result;
11791
+ }
11792
+ function policyFromSnapshot(value, botId) {
11793
+ const source = value?.snapshot ?? value;
11794
+ const bot = Array.isArray(source?.bots) ? source.bots.find((entry) => entry?.botId === botId) : null;
11795
+ return normalizeAccessPolicy(bot?.accessPolicy ?? source?.accessPolicy ?? source?.policy);
11796
+ }
11797
+ function commandValue(value) {
11798
+ return value === "allow";
11799
+ }
11800
+ function ScenePolicyEditor({
11801
+ scene,
11802
+ title,
11803
+ policy,
11804
+ userLabel,
11805
+ placeholder,
11806
+ disabled = false,
11807
+ unsupported = false,
11808
+ onChange
11809
+ }) {
11810
+ const ownerHelpId = React20.useId();
11811
+ const emptyAllowlistHelpId = React20.useId();
11812
+ const allowlist = policy.mode === "allowlist";
11813
+ const collectionKey = allowlist ? "users" : "commandPermissionOverrides";
11814
+ const branchKey = allowlist ? "allowlist" : "open";
11815
+ const users = policy[branchKey][collectionKey];
11816
+ const emptyAllowlist = allowlist && users.length === 0;
11817
+ const updateUsers = (nextUsers) => onChange({
11818
+ ...policy,
11819
+ [branchKey]: {
11820
+ ...policy[branchKey],
11821
+ [collectionKey]: nextUsers
11822
+ }
11823
+ });
11824
+ const updateUser = (index, patch) => updateUsers(users.map((user, userIndex) => userIndex === index ? { ...user, ...patch } : user));
11825
+ return h2(
11826
+ "fieldset",
11827
+ {
11828
+ className: "dim-accessScene",
11829
+ disabled,
11830
+ "data-scene": scene,
11831
+ "aria-label": localizeText(title)
11832
+ },
11833
+ h2(
11834
+ "legend",
11835
+ null,
11836
+ h2(
11837
+ "span",
11838
+ { className: "dim-accessLegendContent" },
11839
+ h2("span", null, title),
11840
+ h2(
11841
+ "span",
11842
+ { className: "dim-channelHelp dim-accessLegendHelp" },
11843
+ h2("button", {
11844
+ type: "button",
11845
+ className: "dim-channelHelpButton",
11846
+ "aria-label": [localizeText(title), localizeText("\u67E5\u770B\u8BBF\u95EE\u6743\u9650\u8BF4\u660E")].join(" "),
11847
+ "aria-describedby": ownerHelpId
11848
+ }, h2("span", { "aria-hidden": true }, "?")),
11849
+ h2("span", {
11850
+ id: ownerHelpId,
11851
+ className: "dim-channelTooltip dim-accessHelpTooltip",
11852
+ role: "tooltip"
11853
+ }, "\u539F\u6240\u6709\u8005\u6216\u626B\u7801\u63A5\u5165\u8005\u59CB\u7EC8\u53EF\u4EE5\u8BBF\u95EE\u5E76\u6267\u884C\u547D\u4EE4\uFF1B\u4EE5\u4E0B\u8BBE\u7F6E\u4EC5\u7EA6\u675F\u5176\u4ED6\u7528\u6237\u3002")
11854
+ )
11855
+ )
11856
+ ),
11857
+ unsupported ? h2(
11858
+ "div",
11859
+ { className: "dim-accessUnsupported", role: "note" },
11860
+ h2("strong", null, "\u5F53\u524D\u6E20\u9053\u4E0D\u652F\u6301\u7FA4\u804A"),
11861
+ h2("p", null, "\u6B64\u533A\u57DF\u65E0\u9700\u914D\u7F6E\uFF0C\u4FDD\u5B58\u79C1\u804A\u8BBE\u7F6E\u65F6\u4F1A\u4FDD\u7559\u73B0\u6709\u7FA4\u804A\u7B56\u7565\u3002")
11862
+ ) : h2(
11863
+ React20.Fragment,
11864
+ null,
11865
+ h2(
11866
+ "div",
11867
+ { className: "dim-accessControls", "data-mode": policy.mode },
11868
+ h2(
11869
+ "label",
11870
+ { className: "dim-accessField" },
11871
+ h2("span", null, "\u8BBF\u95EE\u6A21\u5F0F"),
11872
+ h2(
11873
+ "select",
11874
+ {
11875
+ value: policy.mode,
11876
+ "aria-label": [localizeText(title), localizeText("\u8BBF\u95EE\u6A21\u5F0F")].join(" "),
11877
+ onChange: (event) => onChange({ ...policy, mode: event.target.value })
11878
+ },
11879
+ h2("option", { value: "open" }, "\u5141\u8BB8\u6240\u6709\u7528\u6237"),
11880
+ h2("option", { value: "allowlist" }, "\u4EC5\u767D\u540D\u5355\u7528\u6237")
11881
+ )
11882
+ ),
11883
+ allowlist ? null : h2(
11884
+ "label",
11885
+ { className: "dim-accessField" },
11886
+ h2("span", null, "\u9ED8\u8BA4\u547D\u4EE4\u6743\u9650"),
11887
+ h2(
11888
+ "select",
11889
+ {
11890
+ value: policy.open.defaultCanExecuteCommands ? "allow" : "deny",
11891
+ "aria-label": [localizeText(title), localizeText("\u9ED8\u8BA4\u547D\u4EE4\u6743\u9650")].join(" "),
11892
+ onChange: (event) => onChange({
11893
+ ...policy,
11894
+ open: {
11895
+ ...policy.open,
11896
+ defaultCanExecuteCommands: commandValue(event.target.value)
11897
+ }
11898
+ })
11899
+ },
11900
+ h2("option", { value: "allow" }, "\u53EF\u4EE5\u6267\u884C\u547D\u4EE4"),
11901
+ h2("option", { value: "deny" }, "\u4E0D\u53EF\u4EE5\u6267\u884C\u547D\u4EE4")
11902
+ )
11903
+ )
11904
+ ),
11905
+ h2(
11906
+ "div",
11907
+ { className: "dim-accessUsers" },
11908
+ h2(
11909
+ "div",
11910
+ { className: "dim-accessUsersHeading" },
11911
+ h2(
11912
+ "div",
11913
+ { className: "dim-accessUsersTitle" },
11914
+ h2("strong", null, allowlist ? "\u767D\u540D\u5355\u7528\u6237" : "\u547D\u4EE4\u6743\u9650\u4F8B\u5916"),
11915
+ emptyAllowlist ? h2(
11916
+ "span",
11917
+ { className: "dim-channelHelp dim-accessUsersHelp" },
11918
+ h2("button", {
11919
+ type: "button",
11920
+ className: "dim-channelHelpButton",
11921
+ "aria-label": [localizeText(title), localizeText("\u67E5\u770B\u767D\u540D\u5355\u8BF4\u660E")].join(" "),
11922
+ "aria-describedby": emptyAllowlistHelpId
11923
+ }, h2("span", { "aria-hidden": true }, "?")),
11924
+ h2("span", {
11925
+ id: emptyAllowlistHelpId,
11926
+ className: "dim-channelTooltip dim-accessEmptyAllowlistTooltip",
11927
+ role: "tooltip"
11928
+ }, "\u5F53\u524D\u6CA1\u6709\u767D\u540D\u5355\u7528\u6237\uFF0C\u4FDD\u5B58\u540E\u666E\u901A\u7528\u6237\u5C06\u65E0\u6CD5\u4F7F\u7528\u673A\u5668\u4EBA\u3002")
11929
+ ) : null
11930
+ ),
11931
+ h2("button", {
11932
+ type: "button",
11933
+ className: "dim-deliveryButton dim-accessAddUser",
11934
+ "aria-label": [localizeText(title), localizeText("\u65B0\u589E\u7528\u6237")].join(" "),
11935
+ title: localizeText("\u65B0\u589E\u7528\u6237"),
11936
+ onClick: () => updateUsers([...users, {
11937
+ id: "",
11938
+ canExecuteCommands: allowlist ? false : !policy.open.defaultCanExecuteCommands
11939
+ }])
11940
+ }, h2("span", { "aria-hidden": true }, "+"))
11941
+ ),
11942
+ users.length === 0 ? h2("div", { className: "dim-accessUsersEmpty" }, "\u5C1A\u672A\u6DFB\u52A0\u7528\u6237") : h2("ul", { className: "dim-accessUserList" }, users.map((user, index) => h2(
11943
+ "li",
11944
+ { key: `${scene}-${policy.mode}-${index}`, className: "dim-accessUserRow" },
11945
+ h2(
11946
+ "label",
11947
+ { className: "dim-accessField dim-accessUserId" },
11948
+ h2("span", null, userLabel),
11949
+ h2("input", {
11950
+ value: user.id,
11951
+ maxLength: 256,
11952
+ required: true,
11953
+ autoCapitalize: "none",
11954
+ autoCorrect: "off",
11955
+ spellCheck: false,
11956
+ placeholder,
11957
+ "aria-label": [localizeText(title), localizeText(userLabel), index + 1].join(" "),
11958
+ onChange: (event) => updateUser(index, { id: event.target.value })
11959
+ })
11960
+ ),
11961
+ h2(
11962
+ "label",
11963
+ { className: "dim-accessField dim-accessUserCommand" },
11964
+ h2("span", null, "\u547D\u4EE4\u6743\u9650"),
11965
+ h2(
11966
+ "select",
11967
+ {
11968
+ value: user.canExecuteCommands ? "allow" : "deny",
11969
+ "aria-label": [
11970
+ localizeText(title),
11971
+ localizeText("\u7528\u6237"),
11972
+ index + 1,
11973
+ localizeText("\u547D\u4EE4\u6743\u9650")
11974
+ ].join(" "),
11975
+ onChange: (event) => updateUser(index, {
11976
+ canExecuteCommands: commandValue(event.target.value)
11977
+ })
11978
+ },
11979
+ h2("option", { value: "allow" }, "\u53EF\u4EE5\u6267\u884C\u547D\u4EE4"),
11980
+ h2("option", { value: "deny" }, "\u4E0D\u53EF\u4EE5\u6267\u884C\u547D\u4EE4")
11981
+ )
11982
+ ),
11983
+ h2("button", {
11984
+ type: "button",
11985
+ className: "dim-deliveryButton dim-accessDeleteUser",
11986
+ "data-kind": "danger",
11987
+ "aria-label": [
11988
+ localizeText(title),
11989
+ localizeText("\u5220\u9664"),
11990
+ localizeText("\u7528\u6237"),
11991
+ index + 1
11992
+ ].join(" "),
11993
+ onClick: () => updateUsers(users.filter((_, userIndex) => userIndex !== index))
11994
+ }, "\u5220\u9664")
11995
+ )))
11996
+ )
11997
+ )
11998
+ );
11999
+ }
12000
+ function AccessPolicySettingsPage({ channel: channel4, account, rpcCall, onSaved }) {
12001
+ const definition = ACCESS_CHANNEL_DEFINITIONS[channel4];
12002
+ const initialPolicy = normalizeAccessPolicy(account?.accessPolicy);
12003
+ const initialKey = JSON.stringify(initialPolicy);
12004
+ const [draft, setDraft] = React20.useState(() => clonePolicy(
12005
+ initialPolicy ?? DEFAULT_ACCESS_POLICY
12006
+ ));
12007
+ const [saving, setSaving] = React20.useState(false);
12008
+ const [feedback, setFeedback] = React20.useState(null);
12009
+ React20.useEffect(() => {
12010
+ const next = normalizeAccessPolicy(account?.accessPolicy);
12011
+ setDraft(clonePolicy(next ?? DEFAULT_ACCESS_POLICY));
12012
+ }, [account?.botId, initialKey]);
12013
+ React20.useEffect(() => {
12014
+ setFeedback(null);
12015
+ }, [account?.botId]);
12016
+ if (!definition) {
12017
+ return h2(
12018
+ "div",
12019
+ { className: "dim-accessState", role: "alert" },
12020
+ "\u5F53\u524D\u6E20\u9053\u6682\u4E0D\u652F\u6301\u8BBF\u95EE\u8BBE\u7F6E\u3002"
12021
+ );
12022
+ }
12023
+ const save = async (event) => {
12024
+ event.preventDefault();
12025
+ setFeedback(null);
12026
+ setSaving(true);
12027
+ try {
12028
+ const policy = validateAccessPolicy(draft);
12029
+ if (typeof rpcCall !== "function") throw new Error("\u8BBF\u95EE\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
12030
+ const value = unwrapRpcResult10(await rpcCall(ACCESS_POLICY_ENDPOINT, {
12031
+ botId: account.botId,
12032
+ policy
12033
+ }));
12034
+ const saved = policyFromSnapshot(value, account.botId);
12035
+ if (!saved) throw new Error("\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u5DF2\u4FDD\u5B58\u7684\u8BBF\u95EE\u7B56\u7565\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5\u3002");
12036
+ setDraft(clonePolicy(saved));
12037
+ onSaved?.(saved);
12038
+ setFeedback({ tone: "success", message: "\u8BBF\u95EE\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002" });
12039
+ } catch (error) {
12040
+ setFeedback({
12041
+ tone: "error",
12042
+ message: error?.message || "\u8BBF\u95EE\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"
12043
+ });
12044
+ } finally {
12045
+ setSaving(false);
12046
+ }
12047
+ };
12048
+ return h2(
12049
+ "form",
12050
+ {
12051
+ className: "dim-accessPage",
12052
+ onSubmit: (event) => void save(event)
12053
+ },
12054
+ initialPolicy ? null : h2(
12055
+ "div",
12056
+ { className: "dim-accessState", role: "alert" },
12057
+ "\u8BBF\u95EE\u7B56\u7565\u5C1A\u672A\u5C31\u7EEA\uFF0C\u8BF7\u8FD4\u56DE\u673A\u5668\u4EBA\u5217\u8868\u5237\u65B0\u540E\u91CD\u8BD5\u3002"
12058
+ ),
12059
+ h2(ScenePolicyEditor, {
12060
+ scene: "direct",
12061
+ title: "\u79C1\u804A",
12062
+ policy: draft.direct,
12063
+ userLabel: definition.directUserLabel,
12064
+ placeholder: definition.directPlaceholder,
12065
+ disabled: saving,
12066
+ onChange: (direct) => {
12067
+ setDraft((current) => ({ ...current, direct }));
12068
+ setFeedback(null);
12069
+ }
12070
+ }),
12071
+ h2(ScenePolicyEditor, {
12072
+ scene: "group",
12073
+ title: "\u7FA4\u804A",
12074
+ policy: draft.group,
12075
+ userLabel: definition.groupUserLabel ?? definition.directUserLabel,
12076
+ placeholder: definition.groupPlaceholder ?? definition.directPlaceholder,
12077
+ disabled: saving || definition.groupSupported === false,
12078
+ unsupported: definition.groupSupported === false,
12079
+ onChange: (group) => {
12080
+ setDraft((current) => ({ ...current, group }));
12081
+ setFeedback(null);
12082
+ }
12083
+ }),
12084
+ feedback ? h2("p", {
12085
+ className: "dim-accessFeedback",
12086
+ "data-tone": feedback.tone,
12087
+ role: feedback.tone === "error" ? "alert" : "status",
12088
+ "aria-live": "polite"
12089
+ }, feedback.message) : null,
12090
+ h2(
12091
+ "div",
12092
+ { className: "dim-accessActions" },
12093
+ h2("button", {
12094
+ type: "submit",
12095
+ className: "dim-deliveryButton",
12096
+ "data-kind": "primary",
12097
+ disabled: saving || !initialPolicy
12098
+ }, saving ? "\u6B63\u5728\u4FDD\u5B58\u2026" : "\u4FDD\u5B58\u8BBF\u95EE\u8BBE\u7F6E")
12099
+ )
12100
+ );
12101
+ }
12102
+
12103
+ // plugin-src/client/delivery-settings.js
11860
12104
  var DELIVERY_RPC_CHANNEL = "/dsh-im-delivery";
11861
12105
  var DELIVERY_DOCS_URL = Object.freeze({
11862
12106
  zh: "https://github.com/xmanrui/dsh-im/blob/main/PROACTIVE_DELIVERY.md",
@@ -11870,6 +12114,10 @@ var DELIVERY_ENDPOINTS = Object.freeze({
11870
12114
  delete: "target.delete",
11871
12115
  test: "target.test"
11872
12116
  });
12117
+ var BOT_SETTINGS_TABS = Object.freeze([
12118
+ Object.freeze({ id: "delivery", label: "\u6295\u9012\u8BBE\u7F6E" }),
12119
+ Object.freeze({ id: "access", label: "\u8BBF\u95EE\u8BBE\u7F6E" })
12120
+ ]);
11873
12121
  var CHANNEL_DEFINITIONS = Object.freeze({
11874
12122
  weixin: {
11875
12123
  label: "\u5FAE\u4FE1",
@@ -11947,7 +12195,7 @@ var CHANNEL_DEFINITIONS = Object.freeze({
11947
12195
  function presentError10(error, fallback) {
11948
12196
  return error?.message || fallback;
11949
12197
  }
11950
- function unwrapRpcResult10(result) {
12198
+ function unwrapRpcResult11(result) {
11951
12199
  if (result?.ok === true) return result.value;
11952
12200
  if (result?.ok === false) {
11953
12201
  const error = new Error(result.error?.message || "\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
@@ -12405,8 +12653,15 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
12405
12653
  ) : null
12406
12654
  );
12407
12655
  }
12408
- function DeliveryTargetSettingsPage({ channel: channel4, account, rpcCall, onBack }) {
12656
+ function DeliveryTargetSettingsPage({
12657
+ channel: channel4,
12658
+ account,
12659
+ rpcCall,
12660
+ accessRpcCall,
12661
+ onBack
12662
+ }) {
12409
12663
  const definition = CHANNEL_DEFINITIONS[channel4];
12664
+ const [activeTabId, setActiveTabId] = React21.useState(BOT_SETTINGS_TABS[0].id);
12410
12665
  const [phase, setPhase] = React21.useState("loading");
12411
12666
  const [targets, setTargets] = React21.useState([]);
12412
12667
  const [suggestionPhase, setSuggestionPhase] = React21.useState("idle");
@@ -12416,10 +12671,14 @@ function DeliveryTargetSettingsPage({ channel: channel4, account, rpcCall, onBac
12416
12671
  const [editor, setEditor] = React21.useState(null);
12417
12672
  const [saving, setSaving] = React21.useState(false);
12418
12673
  const [botCopyState, setBotCopyState] = React21.useState(null);
12674
+ const [accessPolicy, setAccessPolicy] = React21.useState(account.accessPolicy);
12419
12675
  const mounted = React21.useRef(true);
12676
+ React21.useEffect(() => {
12677
+ setAccessPolicy(account.accessPolicy);
12678
+ }, [account.botId, account.accessPolicy]);
12420
12679
  const invoke = React21.useCallback(async (endpoint, payload = {}, signal) => {
12421
12680
  if (typeof rpcCall !== "function") throw new Error("\u6295\u9012\u76EE\u6807\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
12422
- return unwrapRpcResult10(await rpcCall(endpoint, payload, signal));
12681
+ return unwrapRpcResult11(await rpcCall(endpoint, payload, signal));
12423
12682
  }, [rpcCall]);
12424
12683
  const loadTargets = React21.useCallback(async ({ signal, silent = false } = {}) => {
12425
12684
  if (!silent) setPhase("loading");
@@ -12520,6 +12779,9 @@ function DeliveryTargetSettingsPage({ channel: channel4, account, rpcCall, onBac
12520
12779
  setBotCopyState(presentError10(caught, "\u590D\u5236\u5931\u8D25\u3002"));
12521
12780
  }
12522
12781
  };
12782
+ const activeTab = BOT_SETTINGS_TABS.find((tab) => tab.id === activeTabId) ?? BOT_SETTINGS_TABS[0];
12783
+ const activeTabDomId = `dim-bot-settings-${activeTab.id}-tab`;
12784
+ const activePanelId = `dim-bot-settings-${activeTab.id}-panel`;
12523
12785
  return h2(
12524
12786
  "section",
12525
12787
  {
@@ -12529,114 +12791,147 @@ function DeliveryTargetSettingsPage({ channel: channel4, account, rpcCall, onBac
12529
12791
  h2(
12530
12792
  "header",
12531
12793
  { className: "dim-deliveryHeader" },
12532
- h2(DeliveryButton, { className: "dim-deliveryBack", onClick: onBack }, "\u2190 \u8FD4\u56DE\u673A\u5668\u4EBA\u5217\u8868"),
12533
- h2(
12534
- "div",
12535
- { className: "dim-deliveryHeaderMeta" },
12536
- h2(
12537
- "a",
12538
- {
12539
- className: "dim-deliveryDocsLink",
12540
- href: isEnglish() ? DELIVERY_DOCS_URL.en : DELIVERY_DOCS_URL.zh,
12541
- target: "_blank",
12542
- rel: "noopener noreferrer",
12543
- "aria-label": "\u6253\u5F00\u4E3B\u52A8\u6295\u9012\u4F7F\u7528\u6587\u6863"
12544
- },
12545
- h2("span", null, "\u4F7F\u7528\u6587\u6863"),
12546
- h2("span", { "aria-hidden": "true" }, "\u2197")
12547
- )
12548
- )
12794
+ h2(DeliveryButton, { className: "dim-deliveryBack", onClick: onBack }, "\u2190 \u8FD4\u56DE\u673A\u5668\u4EBA\u5217\u8868")
12549
12795
  ),
12550
12796
  h2(
12551
- "section",
12552
- { className: "dim-deliveryIdentity", "aria-labelledby": "dim-delivery-bot-title" },
12553
- h2(
12554
- "div",
12555
- null,
12556
- h2(
12557
- "h2",
12558
- { id: "dim-delivery-bot-title", className: "dim-deliveryBotName" },
12559
- account.botName || "\u673A\u5668\u4EBA\u8BBE\u7F6E"
12560
- )
12561
- ),
12562
- h2(
12563
- "div",
12564
- { className: "dim-deliveryBotId" },
12565
- h2("span", null, "Bot ID"),
12566
- h2("code", { title: account.botId }, account.botId),
12567
- h2(DeliveryButton, { onClick: () => void copyBotId() }, "\u590D\u5236")
12568
- ),
12569
- botCopyState ? h2("p", { className: "dim-targetFeedback", role: "status" }, botCopyState) : null
12797
+ "div",
12798
+ { className: "dim-botSettingsTabsBar" },
12799
+ h2("nav", {
12800
+ className: "dim-botSettingsTabs",
12801
+ role: "tablist",
12802
+ "aria-label": "\u673A\u5668\u4EBA\u8BBE\u7F6E\u9875\u7B7E"
12803
+ }, BOT_SETTINGS_TABS.map((tab) => h2("button", {
12804
+ key: tab.id,
12805
+ id: `dim-bot-settings-${tab.id}-tab`,
12806
+ type: "button",
12807
+ role: "tab",
12808
+ className: "dim-botSettingsTab",
12809
+ "aria-selected": tab.id === activeTab.id,
12810
+ "aria-controls": `dim-bot-settings-${tab.id}-panel`,
12811
+ tabIndex: tab.id === activeTab.id ? 0 : -1,
12812
+ onClick: () => setActiveTabId(tab.id)
12813
+ }, tab.label)))
12570
12814
  ),
12571
12815
  h2(
12572
- "section",
12573
- { className: "dim-deliveryTargets", "aria-labelledby": "dim-delivery-targets-title" },
12574
- h2(
12575
- "div",
12576
- { className: "dim-deliverySectionHeading" },
12816
+ "div",
12817
+ {
12818
+ id: activePanelId,
12819
+ className: "dim-botSettingsTabPanel",
12820
+ role: "tabpanel",
12821
+ "aria-labelledby": activeTabDomId
12822
+ },
12823
+ activeTab.id === "access" ? h2(AccessPolicySettingsPage, {
12824
+ channel: channel4,
12825
+ account: { ...account, accessPolicy },
12826
+ rpcCall: accessRpcCall,
12827
+ onSaved: setAccessPolicy
12828
+ }) : h2(
12829
+ React21.Fragment,
12830
+ null,
12577
12831
  h2(
12578
- "div",
12579
- null,
12580
- h2("h3", { id: "dim-delivery-targets-title" }, "\u6295\u9012\u76EE\u6807"),
12581
- account.connected ? null : h2("p", null, "\u673A\u5668\u4EBA\u5F53\u524D\u79BB\u7EBF\uFF1B\u4ECD\u53EF\u914D\u7F6E\u76EE\u6807\uFF0C\u6062\u590D\u8FDE\u63A5\u540E\u518D\u6D4B\u8BD5\u3002")
12832
+ "section",
12833
+ { className: "dim-deliveryIdentity", "aria-labelledby": "dim-delivery-bot-title" },
12834
+ h2(
12835
+ "div",
12836
+ { className: "dim-deliveryIdentityHeading" },
12837
+ h2(
12838
+ "h2",
12839
+ { id: "dim-delivery-bot-title", className: "dim-deliveryBotName" },
12840
+ account.botName || "\u673A\u5668\u4EBA\u8BBE\u7F6E"
12841
+ ),
12842
+ h2(
12843
+ "a",
12844
+ {
12845
+ className: "dim-deliveryDocsLink",
12846
+ href: isEnglish() ? DELIVERY_DOCS_URL.en : DELIVERY_DOCS_URL.zh,
12847
+ target: "_blank",
12848
+ rel: "noopener noreferrer",
12849
+ "aria-label": "\u6253\u5F00\u4E3B\u52A8\u6295\u9012\u4F7F\u7528\u6587\u6863"
12850
+ },
12851
+ h2("span", null, "\u4F7F\u7528\u6587\u6863"),
12852
+ h2("span", { "aria-hidden": "true" }, "\u2197")
12853
+ )
12854
+ ),
12855
+ h2(
12856
+ "div",
12857
+ { className: "dim-deliveryBotId" },
12858
+ h2("span", null, "Bot ID"),
12859
+ h2("code", { title: account.botId }, account.botId),
12860
+ h2(DeliveryButton, { onClick: () => void copyBotId() }, "\u590D\u5236")
12861
+ ),
12862
+ botCopyState ? h2("p", { className: "dim-targetFeedback", role: "status" }, botCopyState) : null
12582
12863
  ),
12583
- h2(DeliveryButton, {
12584
- kind: "primary",
12585
- onClick: openSuggestionPicker,
12586
- disabled: Boolean(editor) || phase !== "ready",
12587
- title: phase === "ready" ? void 0 : "\u8BF7\u5148\u5B8C\u6210\u6295\u9012\u76EE\u6807\u8BFB\u53D6"
12588
- }, "\u65B0\u5EFA\u76EE\u6807")
12589
- ),
12590
- editor?.mode === "suggestions" ? h2(TargetSuggestionPicker, {
12591
- definition,
12592
- phase: suggestionPhase,
12593
- suggestions,
12594
- error: suggestionError,
12595
- targets,
12596
- onRefresh: loadSuggestions,
12597
- onSelect: selectSuggestion,
12598
- onManual: () => setEditor({
12599
- mode: "create",
12600
- source: "manual",
12601
- draftKey: "manual",
12602
- initialValue: { targetId: randomTargetId(targets) }
12603
- }),
12604
- onCancel: () => setEditor(null)
12605
- }) : editor ? h2(TargetForm, {
12606
- key: editor.mode === "edit" ? editor.target.targetId : editor.draftKey,
12607
- definition,
12608
- mode: editor.mode,
12609
- initialValue: editor.mode === "edit" ? editor.target : editor.initialValue,
12610
- source: editor.source,
12611
- busy: saving,
12612
- connected: account.connected,
12613
- onCancel: () => setEditor(editor.source === "suggestion" ? { mode: "suggestions" } : null),
12614
- onSave: saveTarget,
12615
- onTest: (target) => invoke(DELIVERY_ENDPOINTS.test, {
12616
- botId: account.botId,
12617
- target
12618
- })
12619
- }) : null,
12620
- phase === "loading" ? h2("div", { className: "dim-deliveryState", "aria-busy": "true" }, "\u6B63\u5728\u8BFB\u53D6\u6295\u9012\u76EE\u6807\u2026") : phase === "error" ? h2(
12621
- "div",
12622
- { className: "dim-deliveryState", role: "alert" },
12623
- h2("p", null, error),
12624
- h2(DeliveryButton, { onClick: () => void loadTargets() }, "\u91CD\u65B0\u8BFB\u53D6")
12625
- ) : targets.length === 0 ? h2(
12626
- "div",
12627
- { className: "dim-deliveryState dim-deliveryEmpty" },
12628
- h2("strong", null, "\u5C1A\u672A\u914D\u7F6E\u6295\u9012\u76EE\u6807"),
12629
- h2("p", null, "\u70B9\u51FB\u201C\u65B0\u5EFA\u76EE\u6807\u201D\u53EF\u4ECE\u5DF2\u804A\u8FC7\u7684\u4F1A\u8BDD\u9009\u62E9\uFF0C\u4E5F\u53EF\u624B\u52A8\u586B\u5199\u3002")
12630
- ) : h2("ul", { className: "dim-targetList" }, targets.map((target) => h2(TargetRow, {
12631
- key: target.targetId,
12632
- definition,
12633
- target,
12634
- botId: account.botId,
12635
- connected: account.connected,
12636
- rpcCall: invoke,
12637
- onChanged: () => loadTargets({ silent: true }),
12638
- onEdit: () => setEditor({ mode: "edit", target, source: "edit" })
12639
- })))
12864
+ h2(
12865
+ "section",
12866
+ { className: "dim-deliveryTargets", "aria-labelledby": "dim-delivery-targets-title" },
12867
+ h2(
12868
+ "div",
12869
+ { className: "dim-deliverySectionHeading" },
12870
+ h2(
12871
+ "div",
12872
+ null,
12873
+ h2("h3", { id: "dim-delivery-targets-title" }, "\u6295\u9012\u76EE\u6807"),
12874
+ account.connected ? null : h2("p", null, "\u673A\u5668\u4EBA\u5F53\u524D\u79BB\u7EBF\uFF1B\u4ECD\u53EF\u914D\u7F6E\u76EE\u6807\uFF0C\u6062\u590D\u8FDE\u63A5\u540E\u518D\u6D4B\u8BD5\u3002")
12875
+ ),
12876
+ h2(DeliveryButton, {
12877
+ kind: "primary",
12878
+ onClick: openSuggestionPicker,
12879
+ disabled: Boolean(editor) || phase !== "ready",
12880
+ title: phase === "ready" ? void 0 : "\u8BF7\u5148\u5B8C\u6210\u6295\u9012\u76EE\u6807\u8BFB\u53D6"
12881
+ }, "\u65B0\u5EFA\u76EE\u6807")
12882
+ ),
12883
+ editor?.mode === "suggestions" ? h2(TargetSuggestionPicker, {
12884
+ definition,
12885
+ phase: suggestionPhase,
12886
+ suggestions,
12887
+ error: suggestionError,
12888
+ targets,
12889
+ onRefresh: loadSuggestions,
12890
+ onSelect: selectSuggestion,
12891
+ onManual: () => setEditor({
12892
+ mode: "create",
12893
+ source: "manual",
12894
+ draftKey: "manual",
12895
+ initialValue: { targetId: randomTargetId(targets) }
12896
+ }),
12897
+ onCancel: () => setEditor(null)
12898
+ }) : editor ? h2(TargetForm, {
12899
+ key: editor.mode === "edit" ? editor.target.targetId : editor.draftKey,
12900
+ definition,
12901
+ mode: editor.mode,
12902
+ initialValue: editor.mode === "edit" ? editor.target : editor.initialValue,
12903
+ source: editor.source,
12904
+ busy: saving,
12905
+ connected: account.connected,
12906
+ onCancel: () => setEditor(editor.source === "suggestion" ? { mode: "suggestions" } : null),
12907
+ onSave: saveTarget,
12908
+ onTest: (target) => invoke(DELIVERY_ENDPOINTS.test, {
12909
+ botId: account.botId,
12910
+ target
12911
+ })
12912
+ }) : null,
12913
+ phase === "loading" ? h2("div", { className: "dim-deliveryState", "aria-busy": "true" }, "\u6B63\u5728\u8BFB\u53D6\u6295\u9012\u76EE\u6807\u2026") : phase === "error" ? h2(
12914
+ "div",
12915
+ { className: "dim-deliveryState", role: "alert" },
12916
+ h2("p", null, error),
12917
+ h2(DeliveryButton, { onClick: () => void loadTargets() }, "\u91CD\u65B0\u8BFB\u53D6")
12918
+ ) : targets.length === 0 ? h2(
12919
+ "div",
12920
+ { className: "dim-deliveryState dim-deliveryEmpty" },
12921
+ h2("strong", null, "\u5C1A\u672A\u914D\u7F6E\u6295\u9012\u76EE\u6807"),
12922
+ h2("p", null, "\u70B9\u51FB\u201C\u65B0\u5EFA\u76EE\u6807\u201D\u53EF\u4ECE\u5DF2\u804A\u8FC7\u7684\u4F1A\u8BDD\u9009\u62E9\uFF0C\u4E5F\u53EF\u624B\u52A8\u586B\u5199\u3002")
12923
+ ) : h2("ul", { className: "dim-targetList" }, targets.map((target) => h2(TargetRow, {
12924
+ key: target.targetId,
12925
+ definition,
12926
+ target,
12927
+ botId: account.botId,
12928
+ connected: account.connected,
12929
+ rpcCall: invoke,
12930
+ onChanged: () => loadTargets({ silent: true }),
12931
+ onEdit: () => setEditor({ mode: "edit", target, source: "edit" })
12932
+ })))
12933
+ )
12934
+ )
12640
12935
  )
12641
12936
  );
12642
12937
  }
@@ -13067,9 +13362,18 @@ var CSS11 = String.raw`
13067
13362
  .dim-botSettingsButton:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: 2px; }
13068
13363
  .dim-botSettingsTooltip { position: absolute; top: calc(100% + 6px); right: 0; z-index: 30; width: max-content; padding: 6px 9px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 7px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 8px 24px rgb(31 35 41 / 14%); font-size: 11px; line-height: 16px; opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
13069
13364
  .dim-botSettingsAction:hover .dim-botSettingsTooltip, .dim-botSettingsAction:focus-within .dim-botSettingsTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
13070
- .dim-deliveryPage { min-width: 0; display: grid; gap: 14px; }
13365
+ .dim-deliveryPage { min-width: 0; display: grid; }
13071
13366
  .dim-deliveryHeader { min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 16px; }
13072
- .dim-deliveryHeaderMeta { min-width: 0; display: flex; align-items: center; justify-content: flex-end; gap: 10px; text-align: right; }
13367
+ .dim-botSettingsTabsBar { min-width: 0; margin-top: 10px; border-bottom: 1px solid var(--dsw-alias-border-l2, #dfe1e5); }
13368
+ .dim-botSettingsTabs { min-width: 0; display: flex; align-items: flex-end; gap: 24px; overflow-x: auto; scrollbar-width: none; }
13369
+ .dim-botSettingsTabs::-webkit-scrollbar { display: none; }
13370
+ .dim-botSettingsTab { position: relative; min-height: 38px; flex: none; display: inline-flex; align-items: center; justify-content: center; padding: 6px 2px 9px; border: 0; color: var(--dsw-alias-label-secondary, #646a73); background: transparent; font: inherit; font-size: 13px; line-height: 20px; font-weight: 560; white-space: nowrap; cursor: pointer; transition: color .15s ease; }
13371
+ .dim-botSettingsTab::after { content: ''; position: absolute; right: 0; bottom: -1px; left: 0; height: 2px; border-radius: 2px 2px 0 0; background: transparent; transform: scaleX(.45); transition: background .15s ease, transform .15s ease; }
13372
+ .dim-botSettingsTab:hover:not([aria-selected="true"]) { color: var(--dsw-alias-label-primary, #1f2329); }
13373
+ .dim-botSettingsTab[aria-selected="true"] { color: var(--dsw-alias-state-business-primary, #3370ff); font-weight: 650; }
13374
+ .dim-botSettingsTab[aria-selected="true"]::after { background: var(--dsw-alias-state-business-primary, #3370ff); transform: scaleX(1); }
13375
+ .dim-botSettingsTab:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: -2px; border-radius: 5px; }
13376
+ .dim-botSettingsTabPanel { min-width: 0; display: grid; gap: 14px; padding-top: 14px; }
13073
13377
  .dim-deliveryDocsLink { min-height: 30px; flex: none; display: inline-flex; align-items: center; gap: 4px; padding: 5px 8px; border-radius: 7px; color: var(--dsw-alias-state-business-primary, #3370ff); font-size: 12px; line-height: 18px; text-decoration: none; white-space: nowrap; }
13074
13378
  .dim-deliveryDocsLink:hover { background: color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 8%, transparent); }
13075
13379
  .dim-deliveryDocsLink:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: 2px; }
@@ -13081,6 +13385,7 @@ var CSS11 = String.raw`
13081
13385
  .dim-deliveryButton[data-kind="danger"] { color: var(--dsw-alias-state-error-primary, #d54941); }
13082
13386
  .dim-deliveryBack { flex: none; border-color: transparent; background: transparent; }
13083
13387
  .dim-deliveryIdentity, .dim-deliveryTargets { min-width: 0; padding: 16px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 12px; background: var(--dsw-alias-bg-layer-3, #fff); }
13388
+ .dim-deliveryIdentityHeading { min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 12px; }
13084
13389
  .dim-deliveryBotName, .dim-deliverySectionHeading h3 { min-width: 0; overflow: hidden; margin: 0; font-size: 15px; line-height: 22px; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; }
13085
13390
  .dim-deliveryIdentity > div:first-child p, .dim-deliverySectionHeading p { margin: 2px 0 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: 18px; }
13086
13391
  .dim-deliveryBotId { min-width: 0; display: grid; grid-template-columns: max-content minmax(0, 1fr) max-content; align-items: center; gap: 10px; margin-top: 12px; padding: 10px 12px; border-radius: 9px; background: var(--dsw-alias-bg-module-platform, #f7f8fa); }
@@ -13123,6 +13428,38 @@ var CSS11 = String.raw`
13123
13428
  .dim-targetField input[readonly] { color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-module-platform, #f7f8fa); }
13124
13429
  .dim-targetFormError { margin: 10px 0 0; font-size: 12px; line-height: 18px; }
13125
13430
  .dim-targetFormActions { display: flex; justify-content: flex-end; gap: 7px; margin-top: 12px; }
13431
+ .dim-accessPage { min-width: 0; display: grid; gap: 14px; }
13432
+ .dim-accessScene { position: relative; min-width: 0; margin: 0; padding: 16px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 12px; background: var(--dsw-alias-bg-layer-3, #fff); }
13433
+ .dim-accessScene > legend { padding: 0 6px; color: var(--dsw-alias-label-primary, #1f2329); font-size: 15px; line-height: 22px; font-weight: 650; }
13434
+ .dim-accessLegendContent { display: inline-flex; align-items: center; gap: 6px; }
13435
+ .dim-panel .dim-accessLegendHelp { position: static; }
13436
+ .dim-accessLegendHelp .dim-channelTooltip { top: 20px; right: auto; left: 16px; width: min(320px, calc(100% - 32px)); max-width: none; }
13437
+ .dim-accessControls { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
13438
+ .dim-accessControls[data-mode="allowlist"] { grid-template-columns: minmax(0, 1fr); }
13439
+ .dim-accessField { min-width: 0; display: grid; align-content: start; gap: 5px; color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 16px; }
13440
+ .dim-accessField input, .dim-accessField select { width: 100%; min-width: 0; height: 36px; padding: 0 9px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 7px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 12px; }
13441
+ .dim-accessField input:focus, .dim-accessField select:focus { outline: 2px solid color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 28%, transparent); border-color: var(--dsw-alias-state-business-primary, #3370ff); }
13442
+ .dim-accessUsers { min-width: 0; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--dsw-alias-border-l1, #eef0f3); }
13443
+ .dim-accessUsersHeading { position: relative; min-width: 0; display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
13444
+ .dim-accessUsersHeading > div { min-width: 0; }
13445
+ .dim-accessUsersTitle { display: inline-flex; align-items: center; gap: 6px; }
13446
+ .dim-accessUsersHeading strong { color: var(--dsw-alias-label-primary, #1f2329); font-size: 13px; line-height: 20px; font-weight: 620; }
13447
+ .dim-accessUsersHeading p { margin: 2px 0 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 17px; }
13448
+ .dim-panel .dim-accessUsersHelp { position: static; }
13449
+ .dim-accessUsersHelp .dim-channelTooltip { top: calc(100% + 7px); right: auto; left: 0; width: min(320px, 100%); max-width: none; }
13450
+ .dim-accessAddUser { width: 32px; height: 32px; min-height: 32px; flex: 0 0 32px; padding: 0; font-size: 20px; line-height: 1; }
13451
+ .dim-accessUsersEmpty { margin-top: 10px; padding: 15px 12px; border: 1px dashed var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 12px; line-height: 18px; text-align: center; }
13452
+ .dim-accessUserList { display: grid; gap: 9px; margin: 10px 0 0; padding: 0; list-style: none; }
13453
+ .dim-accessUserRow { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr) minmax(145px, 180px) max-content; align-items: end; gap: 10px; padding: 11px; border: 1px solid var(--dsw-alias-border-l1, #eef0f3); border-radius: 9px; background: var(--dsw-alias-bg-module-platform, #f7f8fa); }
13454
+ .dim-accessDeleteUser { margin-bottom: 1px; }
13455
+ .dim-accessUnsupported { padding: 18px 14px; border: 1px dashed var(--dsw-alias-border-l2, #dfe1e5); border-radius: 9px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-module-platform, #f7f8fa); text-align: center; }
13456
+ .dim-accessUnsupported strong { color: var(--dsw-alias-label-primary, #1f2329); font-size: 13px; line-height: 20px; }
13457
+ .dim-accessUnsupported p { margin: 4px 0 0; font-size: 12px; line-height: 18px; }
13458
+ .dim-accessState { padding: 11px 13px; border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary, #d97706) 24%, var(--dsw-alias-border-l2, #dfe1e5)); border-radius: 9px; color: var(--dsw-alias-state-warn-primary, #d97706); background: color-mix(in srgb, var(--dsw-alias-state-warn-primary, #d97706) 7%, var(--dsw-alias-bg-layer-1, #fff)); font-size: 12px; line-height: 18px; }
13459
+ .dim-accessFeedback { margin: 0; padding: 10px 12px; border-radius: 8px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-module-platform, #f7f8fa); font-size: 12px; line-height: 18px; }
13460
+ .dim-accessFeedback[data-tone="success"] { color: var(--dsw-alias-state-success-primary, #20a162); }
13461
+ .dim-accessFeedback[data-tone="error"] { color: var(--dsw-alias-state-error-primary, #d54941); }
13462
+ .dim-accessActions { display: flex; justify-content: flex-end; }
13126
13463
  .dim-panel .dim-botCard .dim-cardFooter { margin-top: 0; }
13127
13464
  .dim-panel .ddt-headingCopy { display: none; }
13128
13465
  .dim-panel .ddt-qrFrame, .dim-panel .ddt-countdown { width: min(270px, 100%); }
@@ -13146,6 +13483,9 @@ var CSS11 = String.raw`
13146
13483
  .dim-targetActions { justify-content: flex-start; }
13147
13484
  .dim-targetFormGrid { grid-template-columns: minmax(0, 1fr); }
13148
13485
  .dim-targetSuggestionHeading { align-items: stretch; flex-direction: column; }
13486
+ .dim-accessControls { grid-template-columns: minmax(0, 1fr); }
13487
+ .dim-accessUserRow { grid-template-columns: minmax(0, 1fr); }
13488
+ .dim-accessDeleteUser { justify-self: start; }
13149
13489
  }
13150
13490
  @media (max-width: 840px) {
13151
13491
  .dim-title { align-items: flex-start; }
@@ -13169,11 +13509,12 @@ var CSS11 = String.raw`
13169
13509
  .dim-rail { grid-template-columns: minmax(0, 1fr); }
13170
13510
  .dim-loopbackRecovery { align-items: stretch; flex-direction: column; gap: 12px; }
13171
13511
  .dim-loopbackRecoveryAction { width: 100%; }
13172
- .dim-deliveryHeader, .dim-deliverySectionHeading { align-items: stretch; flex-direction: column; }
13173
- .dim-deliveryHeaderMeta { justify-content: space-between; text-align: left; }
13512
+ .dim-deliverySectionHeading { align-items: stretch; flex-direction: column; }
13513
+ .dim-botSettingsTabs { gap: 18px; }
13174
13514
  .dim-deliveryBotId { grid-template-columns: minmax(0, 1fr) max-content; }
13175
13515
  .dim-deliveryBotId > span { grid-column: 1 / -1; }
13176
13516
  .dim-targetActions .dim-deliveryButton { flex: 1 1 auto; }
13517
+ .dim-accessActions .dim-deliveryButton { width: 100%; }
13177
13518
  .dim-directoryPickerBackdrop { padding: 10px; }
13178
13519
  .dim-directoryPicker { height: calc(100vh - 20px); min-height: 0; border-radius: 14px; }
13179
13520
  .dim-directoryPickerHeader { padding: 18px 17px 14px; }
@@ -13985,6 +14326,7 @@ function IMSettingsTab({
13985
14326
  channel: active.id,
13986
14327
  account: deliverySettings,
13987
14328
  rpcCall: rpcCalls.deliveryRpcCall,
14329
+ accessRpcCall: rpcCalls[`${active.id}RpcCall`],
13988
14330
  onBack: () => setDeliverySettings(null)
13989
14331
  }) : active.id === "weixin" ? h2(WeixinSettingsTab, { rpcCall: rpcCalls.weixinRpcCall }) : active.id === "feishu" ? h2(FeishuSettingsTab, { rpcCall: rpcCalls.feishuRpcCall }) : active.id === "dingtalk" ? h2(DingtalkSettingsTab, { rpcCall: rpcCalls.dingtalkRpcCall }) : active.id === "wecom" ? h2(WecomSettingsTab, { rpcCall: rpcCalls.wecomRpcCall }) : active.id === "qq" ? h2(QqSettingsTab, { rpcCall: rpcCalls.qqRpcCall }) : active.id === "slack" ? h2(SlackSettingsTab, { rpcCall: rpcCalls.slackRpcCall }) : active.id === "telegram" ? h2(TelegramSettingsTab, { rpcCall: rpcCalls.telegramRpcCall }) : active.id === "discord" ? h2(DiscordSettingsTab, { rpcCall: rpcCalls.discordRpcCall }) : active.id === "whatsapp" ? h2(WhatsappSettingsTab, { rpcCall: rpcCalls.whatsappRpcCall }) : h2(OfficeSettingsTab, { rpcCall: rpcCalls.officeRpcCall })
13990
14332
  )