@xmanrui/dsh-im 4.11.0 → 4.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -566,12 +566,12 @@ __export(index_exports, {
566
566
  name: () => name
567
567
  });
568
568
  module.exports = __toCommonJS(index_exports);
569
- var React26 = __toESM(require("react"), 1);
569
+ var React27 = __toESM(require("react"), 1);
570
570
 
571
571
  // package.json
572
572
  var package_default = {
573
573
  name: "@xmanrui/dsh-im",
574
- version: "4.11.0",
574
+ version: "4.12.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",
@@ -1081,6 +1081,8 @@ var EN = Object.freeze({
1081
1081
  "\u624B\u52A8\u63A5\u5165": "Manual setup",
1082
1082
  "\u6536\u8D77\u51ED\u636E": "Hide credentials",
1083
1083
  "\u6536\u8D77\u63A5\u5165": "Hide setup",
1084
+ "\u5C55\u5F00\u8BE5\u8D26\u53F7\u7684\u8BBE\u7F6E": "Expand this account's settings",
1085
+ "\u6536\u8D77\u8BE5\u8D26\u53F7\u7684\u8BBE\u7F6E": "Collapse this account's settings",
1084
1086
  "\u63A5\u5165\u673A\u5668\u4EBA": "Connect bot",
1085
1087
  "\u5F00\u59CB\u63A5\u5165": "Start setup",
1086
1088
  "\u5728\u7EBF": "online",
@@ -2656,7 +2658,7 @@ function formatRemaining(milliseconds) {
2656
2658
  }
2657
2659
 
2658
2660
  // plugin-src/client/channels/dingtalk/index.js
2659
- var React11 = __toESM(require("react"), 1);
2661
+ var React12 = __toESM(require("react"), 1);
2660
2662
 
2661
2663
  // plugin-src/client/credential-binding.js
2662
2664
  var React5 = __toESM(require("react"), 1);
@@ -2799,11 +2801,68 @@ function CredentialBindingPanel({
2799
2801
  );
2800
2802
  }
2801
2803
 
2804
+ // plugin-src/client/channels/shared/collapsible-account.js
2805
+ var React6 = __toESM(require("react"), 1);
2806
+ function CollapsibleAccountSection({
2807
+ header,
2808
+ defaultOpen = false,
2809
+ open: controlledOpen,
2810
+ onToggle,
2811
+ id: id5,
2812
+ className = "",
2813
+ children
2814
+ }) {
2815
+ const [uncontrolledOpen, setUncontrolledOpen] = React6.useState(defaultOpen);
2816
+ const open = controlledOpen ?? uncontrolledOpen;
2817
+ const contentId = id5 ? `${id5}-content` : void 0;
2818
+ const toggle = () => {
2819
+ if (controlledOpen === void 0) setUncontrolledOpen((value) => !value);
2820
+ onToggle?.(!open);
2821
+ };
2822
+ const onKeyDown = (event) => {
2823
+ if (event.key === "Enter" || event.key === " " || event.key === "Spacebar") {
2824
+ event.preventDefault();
2825
+ toggle();
2826
+ }
2827
+ };
2828
+ return h2(
2829
+ "div",
2830
+ {
2831
+ className: `dim-collapsibleAccount ${open ? "is-open" : ""} ${className}`.trim(),
2832
+ "data-open": open ? "true" : "false"
2833
+ },
2834
+ h2(
2835
+ "div",
2836
+ {
2837
+ className: "dim-collapsibleHead",
2838
+ role: "button",
2839
+ tabIndex: 0,
2840
+ onClick: toggle,
2841
+ onKeyDown,
2842
+ "aria-expanded": open ? "true" : "false",
2843
+ "aria-controls": contentId,
2844
+ "aria-label": open ? "\u6536\u8D77\u8BE5\u8D26\u53F7\u7684\u8BBE\u7F6E" : "\u5C55\u5F00\u8BE5\u8D26\u53F7\u7684\u8BBE\u7F6E"
2845
+ },
2846
+ h2("div", { className: "dim-collapsibleHeaderContent" }, header),
2847
+ h2("span", { className: "dim-collapsibleChevron", "aria-hidden": "true" })
2848
+ ),
2849
+ h2(
2850
+ "div",
2851
+ {
2852
+ id: contentId,
2853
+ className: "dim-collapsibleBody",
2854
+ role: "region"
2855
+ },
2856
+ h2("div", { className: "dim-collapsibleBodyInner" }, children)
2857
+ )
2858
+ );
2859
+ }
2860
+
2802
2861
  // plugin-src/client/workspace-editor.js
2803
- var React7 = __toESM(require("react"), 1);
2862
+ var React8 = __toESM(require("react"), 1);
2804
2863
 
2805
2864
  // plugin-src/client/workspace-directory-picker.js
2806
- var React6 = __toESM(require("react"), 1);
2865
+ var React7 = __toESM(require("react"), 1);
2807
2866
  var import_react_dom = require("react-dom");
2808
2867
  function pickerErrorCode(error) {
2809
2868
  return error?.rpcError?.code ?? error?.code;
@@ -2824,7 +2883,7 @@ function pickerErrorMessage(error) {
2824
2883
  return error?.rpcError?.message ?? error?.message ?? "\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\uFF0C\u8BF7\u91CD\u8BD5\u3002";
2825
2884
  }
2826
2885
  function FolderIcon() {
2827
- return React6.createElement(
2886
+ return React7.createElement(
2828
2887
  "svg",
2829
2888
  {
2830
2889
  viewBox: "0 0 24 24",
@@ -2835,11 +2894,11 @@ function FolderIcon() {
2835
2894
  strokeLinejoin: "round",
2836
2895
  "aria-hidden": "true"
2837
2896
  },
2838
- React6.createElement("path", { d: "M3.5 7.25A2.25 2.25 0 0 1 5.75 5h4.1l1.8 2h6.6a2.25 2.25 0 0 1 2.25 2.25v7A2.75 2.75 0 0 1 17.75 19h-12A2.25 2.25 0 0 1 3.5 16.75v-9.5Z" })
2897
+ React7.createElement("path", { d: "M3.5 7.25A2.25 2.25 0 0 1 5.75 5h4.1l1.8 2h6.6a2.25 2.25 0 0 1 2.25 2.25v7A2.75 2.75 0 0 1 17.75 19h-12A2.25 2.25 0 0 1 3.5 16.75v-9.5Z" })
2839
2898
  );
2840
2899
  }
2841
2900
  function ChevronIcon() {
2842
- return React6.createElement("svg", {
2901
+ return React7.createElement("svg", {
2843
2902
  viewBox: "0 0 20 20",
2844
2903
  fill: "none",
2845
2904
  stroke: "currentColor",
@@ -2847,7 +2906,7 @@ function ChevronIcon() {
2847
2906
  strokeLinecap: "round",
2848
2907
  strokeLinejoin: "round",
2849
2908
  "aria-hidden": "true"
2850
- }, React6.createElement("path", { d: "m7.5 4.5 5 5.5-5 5.5" }));
2909
+ }, React7.createElement("path", { d: "m7.5 4.5 5 5.5-5 5.5" }));
2851
2910
  }
2852
2911
  function displayCrumbs(listing) {
2853
2912
  const homeIndex = listing.crumbs.findIndex((crumb) => crumb.path === listing.home);
@@ -2863,28 +2922,28 @@ function WorkspaceDirectoryPicker({
2863
2922
  onPicked,
2864
2923
  onCancel
2865
2924
  }) {
2866
- const [listing, setListing] = React6.useState(null);
2867
- const [loading, setLoading] = React6.useState(false);
2868
- const [error, setError] = React6.useState(null);
2869
- const [pathDraft, setPathDraft] = React6.useState(startPath ?? "");
2870
- const [showHidden, setShowHidden] = React6.useState(false);
2871
- const [retryKey, setRetryKey] = React6.useState(0);
2872
- const requestRef = React6.useRef(0);
2873
- const controllerRef = React6.useRef(null);
2874
- const dialogRef = React6.useRef(null);
2875
- const bodyRef = React6.useRef(null);
2876
- const titleId = React6.useId();
2877
- const noticeId = React6.useId();
2878
- const pathInputId = React6.useId();
2879
- const errorId = React6.useId();
2880
- const initialPathRef = React6.useRef(startPath);
2881
- const onPickedRef = React6.useRef(onPicked);
2882
- const onCancelRef = React6.useRef(onCancel);
2883
- const busyRef = React6.useRef(busy);
2925
+ const [listing, setListing] = React7.useState(null);
2926
+ const [loading, setLoading] = React7.useState(false);
2927
+ const [error, setError] = React7.useState(null);
2928
+ const [pathDraft, setPathDraft] = React7.useState(startPath ?? "");
2929
+ const [showHidden, setShowHidden] = React7.useState(false);
2930
+ const [retryKey, setRetryKey] = React7.useState(0);
2931
+ const requestRef = React7.useRef(0);
2932
+ const controllerRef = React7.useRef(null);
2933
+ const dialogRef = React7.useRef(null);
2934
+ const bodyRef = React7.useRef(null);
2935
+ const titleId = React7.useId();
2936
+ const noticeId = React7.useId();
2937
+ const pathInputId = React7.useId();
2938
+ const errorId = React7.useId();
2939
+ const initialPathRef = React7.useRef(startPath);
2940
+ const onPickedRef = React7.useRef(onPicked);
2941
+ const onCancelRef = React7.useRef(onCancel);
2942
+ const busyRef = React7.useRef(busy);
2884
2943
  onPickedRef.current = onPicked;
2885
2944
  onCancelRef.current = onCancel;
2886
2945
  busyRef.current = busy;
2887
- const loadDirectory = React6.useCallback(async (path, { reportError = true } = {}) => {
2946
+ const loadDirectory = React7.useCallback(async (path, { reportError = true } = {}) => {
2888
2947
  const request = requestRef.current + 1;
2889
2948
  requestRef.current = request;
2890
2949
  controllerRef.current?.abort();
@@ -2908,7 +2967,7 @@ function WorkspaceDirectoryPicker({
2908
2967
  if (request === requestRef.current) setLoading(false);
2909
2968
  }
2910
2969
  }, [picker]);
2911
- React6.useEffect(() => {
2970
+ React7.useEffect(() => {
2912
2971
  if (!open) return void 0;
2913
2972
  let active = true;
2914
2973
  setListing(null);
@@ -2988,10 +3047,10 @@ function WorkspaceDirectoryPicker({
2988
3047
  "nav",
2989
3048
  { className: "dim-directoryCrumbs", "aria-label": "\u5F53\u524D\u76EE\u5F55" },
2990
3049
  crumbs.map((crumb, index) => h2(
2991
- React6.Fragment,
3050
+ React7.Fragment,
2992
3051
  { key: crumb.path },
2993
3052
  index > 0 ? h2("span", { className: "dim-directoryCrumbSeparator", "aria-hidden": "true" }, "\u203A") : null,
2994
- React6.createElement("button", {
3053
+ React7.createElement("button", {
2995
3054
  type: "button",
2996
3055
  title: crumb.path,
2997
3056
  disabled: loading || busy,
@@ -3054,7 +3113,7 @@ function WorkspaceDirectoryPicker({
3054
3113
  ) : listing ? entries.length > 0 ? h2("ul", { className: "dim-directoryList" }, entries.map((entry) => h2(
3055
3114
  "li",
3056
3115
  { key: entry.path },
3057
- React6.createElement(
3116
+ React7.createElement(
3058
3117
  "button",
3059
3118
  {
3060
3119
  type: "button",
@@ -3063,7 +3122,7 @@ function WorkspaceDirectoryPicker({
3063
3122
  onClick: () => void loadDirectory(entry.path)
3064
3123
  },
3065
3124
  h2("span", { className: "dim-directoryFolder" }, h2(FolderIcon)),
3066
- React6.createElement("span", { className: "dim-directoryName" }, entry.name),
3125
+ React7.createElement("span", { className: "dim-directoryName" }, entry.name),
3067
3126
  h2("span", { className: "dim-directoryChevron" }, h2(ChevronIcon))
3068
3127
  )
3069
3128
  ))) : h2(
@@ -3116,21 +3175,21 @@ function WorkspaceDirectoryPicker({
3116
3175
  }
3117
3176
 
3118
3177
  // plugin-src/client/workspace-editor.js
3119
- var WorkspaceDirectoryPickerContext = React7.createContext(null);
3178
+ var WorkspaceDirectoryPickerContext = React8.createContext(null);
3120
3179
  function WorkspaceEditor({ workspace, directoryPicker, disabled = false, onSave }) {
3121
- const sharedDirectoryPicker = React7.useContext(WorkspaceDirectoryPickerContext);
3180
+ const sharedDirectoryPicker = React8.useContext(WorkspaceDirectoryPickerContext);
3122
3181
  const activeDirectoryPicker = directoryPicker ?? sharedDirectoryPicker;
3123
- const [open, setOpen] = React7.useState(false);
3124
- const [saving, setSaving] = React7.useState(false);
3125
- const [error, setError] = React7.useState(null);
3126
- const editButtonRef = React7.useRef(null);
3127
- const savingRef = React7.useRef(false);
3128
- const close = React7.useCallback(() => {
3182
+ const [open, setOpen] = React8.useState(false);
3183
+ const [saving, setSaving] = React8.useState(false);
3184
+ const [error, setError] = React8.useState(null);
3185
+ const editButtonRef = React8.useRef(null);
3186
+ const savingRef = React8.useRef(false);
3187
+ const close = React8.useCallback(() => {
3129
3188
  setOpen(false);
3130
3189
  setError(null);
3131
3190
  queueMicrotask(() => editButtonRef.current?.focus?.());
3132
3191
  }, []);
3133
- const pick = React7.useCallback(async (value) => {
3192
+ const pick = React8.useCallback(async (value) => {
3134
3193
  if (!value || savingRef.current || disabled) return;
3135
3194
  if (value === workspace) {
3136
3195
  close();
@@ -3167,7 +3226,7 @@ function WorkspaceEditor({ workspace, directoryPicker, disabled = false, onSave
3167
3226
  disabled: disabled || !activeDirectoryPicker
3168
3227
  }, "\u9009\u62E9\u76EE\u5F55")
3169
3228
  ),
3170
- workspace ? React7.createElement("code", {
3229
+ workspace ? React8.createElement("code", {
3171
3230
  className: "dim-workspacePath",
3172
3231
  title: workspace
3173
3232
  }, workspace) : h2("code", { className: "dim-workspacePath" }, "\u672A\u8BBE\u7F6E"),
@@ -3184,7 +3243,7 @@ function WorkspaceEditor({ workspace, directoryPicker, disabled = false, onSave
3184
3243
  }
3185
3244
 
3186
3245
  // plugin-src/client/context-enhancement.js
3187
- var React8 = __toESM(require("react"), 1);
3246
+ var React9 = __toESM(require("react"), 1);
3188
3247
  var import_react_dom2 = require("react-dom");
3189
3248
  var FIELD_LABELS = Object.freeze({
3190
3249
  channel: "\u6E20\u9053",
@@ -3429,7 +3488,7 @@ function ContextEnhancementScopeEditor({
3429
3488
  );
3430
3489
  }
3431
3490
  function ContextEnhancementDialog({ config, groupSupported, disabled, onSave, onClose, returnFocusRef, id: id5 }) {
3432
- const [draft, setDraft] = React8.useState(() => {
3491
+ const [draft, setDraft] = React9.useState(() => {
3433
3492
  const normalized = normalizeContextEnhancementConfig(config);
3434
3493
  return {
3435
3494
  ...normalized,
@@ -3438,23 +3497,23 @@ function ContextEnhancementDialog({ config, groupSupported, disabled, onSave, on
3438
3497
  } : {}
3439
3498
  };
3440
3499
  });
3441
- const [saving, setSaving] = React8.useState(false);
3442
- const [error, setError] = React8.useState(null);
3443
- const [activeScope, setActiveScope] = React8.useState("direct");
3444
- const savingRef = React8.useRef(false);
3445
- const dialogRef = React8.useRef(null);
3446
- const mountedRef = React8.useRef(true);
3447
- const groupTabRef = React8.useRef(null);
3448
- const directTabRef = React8.useRef(null);
3449
- const titleId = React8.useId();
3450
- const descriptionId = React8.useId();
3451
- const scopeIdPrefix = React8.useId();
3500
+ const [saving, setSaving] = React9.useState(false);
3501
+ const [error, setError] = React9.useState(null);
3502
+ const [activeScope, setActiveScope] = React9.useState("direct");
3503
+ const savingRef = React9.useRef(false);
3504
+ const dialogRef = React9.useRef(null);
3505
+ const mountedRef = React9.useRef(true);
3506
+ const groupTabRef = React9.useRef(null);
3507
+ const directTabRef = React9.useRef(null);
3508
+ const titleId = React9.useId();
3509
+ const descriptionId = React9.useId();
3510
+ const scopeIdPrefix = React9.useId();
3452
3511
  const groupGuidanceExample = localizeText(CONTEXT_GROUP_GUIDANCE_EXAMPLE);
3453
3512
  const directGuidanceExample = localizeText(CONTEXT_DIRECT_GUIDANCE_EXAMPLE);
3454
3513
  const busy = disabled || saving;
3455
3514
  const scopeKinds = ["direct", "group"];
3456
3515
  const tabRefs = { group: groupTabRef, direct: directTabRef };
3457
- React8.useEffect(() => {
3516
+ React9.useEffect(() => {
3458
3517
  mountedRef.current = true;
3459
3518
  dialogRef.current?.focus?.();
3460
3519
  const keepFocus = (event) => {
@@ -3645,17 +3704,17 @@ function ContextEnhancementDialog({ config, groupSupported, disabled, onSave, on
3645
3704
  return globalThis.document?.body ? (0, import_react_dom2.createPortal)(content, document.body) : content;
3646
3705
  }
3647
3706
  function ContextEnhancementEditor({ config, groupSupported = true, disabled = false, onSave }) {
3648
- const [open, setOpen] = React8.useState(false);
3649
- const entryRef = React8.useRef(null);
3650
- const dialogId = React8.useId();
3651
- const statusId = React8.useId();
3707
+ const [open, setOpen] = React9.useState(false);
3708
+ const entryRef = React9.useRef(null);
3709
+ const dialogId = React9.useId();
3710
+ const statusId = React9.useId();
3652
3711
  const saved = normalizeContextEnhancementConfig(config);
3653
3712
  const label = contextEnhancementLabel(groupSupported ? saved : {
3654
3713
  ...saved,
3655
3714
  group: { ...saved.group, enabled: false }
3656
3715
  });
3657
3716
  return h2(
3658
- React8.Fragment,
3717
+ React9.Fragment,
3659
3718
  null,
3660
3719
  h2(
3661
3720
  "button",
@@ -3689,10 +3748,10 @@ function ContextEnhancementEditor({ config, groupSupported = true, disabled = fa
3689
3748
  }
3690
3749
 
3691
3750
  // plugin-src/client/workspace-snapshot-fence.js
3692
- var React9 = __toESM(require("react"), 1);
3751
+ var React10 = __toESM(require("react"), 1);
3693
3752
  function useWorkspaceSnapshotFence() {
3694
- const state = React9.useRef({ version: 0, pendingMutations: 0 });
3695
- return React9.useMemo(() => Object.freeze({
3753
+ const state = React10.useRef({ version: 0, pendingMutations: 0 });
3754
+ return React10.useMemo(() => Object.freeze({
3696
3755
  beginStatus() {
3697
3756
  return state.current.pendingMutations === 0 ? state.current.version : null;
3698
3757
  },
@@ -3715,8 +3774,8 @@ function useWorkspaceSnapshotFence() {
3715
3774
  }
3716
3775
 
3717
3776
  // plugin-src/client/channel-card-meta.js
3718
- var React10 = __toESM(require("react"), 1);
3719
- var BotSettingsContext = React10.createContext(Object.freeze({
3777
+ var React11 = __toESM(require("react"), 1);
3778
+ var BotSettingsContext = React11.createContext(Object.freeze({
3720
3779
  openBotSettings() {
3721
3780
  }
3722
3781
  }));
@@ -3746,8 +3805,8 @@ function BotSettingsButton({
3746
3805
  accessPolicy,
3747
3806
  channelSettings
3748
3807
  }) {
3749
- const { openBotSettings } = React10.useContext(BotSettingsContext);
3750
- const tooltipId = React10.useId();
3808
+ const { openBotSettings } = React11.useContext(BotSettingsContext);
3809
+ const tooltipId = React11.useId();
3751
3810
  return h2(
3752
3811
  "span",
3753
3812
  { className: "dim-botSettingsAction" },
@@ -3787,7 +3846,7 @@ function messageErrorTime(value) {
3787
3846
  }
3788
3847
  }
3789
3848
  function ChannelListHeading({ className = "", id: id5, title, connectionLabel }) {
3790
- const helpId = React10.useId();
3849
+ const helpId = React11.useId();
3791
3850
  return h2(
3792
3851
  "div",
3793
3852
  { className: `${className} dim-listHeading`.trim() },
@@ -3868,7 +3927,7 @@ function LastMessageErrorSummary({ className = "", error }) {
3868
3927
  h2("span", null, "\u53C2\u8003\u53F7"),
3869
3928
  ` ${error.referenceId}`,
3870
3929
  occurredAt ? h2(
3871
- React10.Fragment,
3930
+ React11.Fragment,
3872
3931
  null,
3873
3932
  " \xB7 ",
3874
3933
  h2("time", { dateTime: new Date(error.at).toISOString() }, occurredAt)
@@ -4031,7 +4090,7 @@ function DingtalkIcon({ size = 28 }) {
4031
4090
  d: "M37.05 22.783c-6.758-5.216-14.378-12.128-22.73-19.538-.655-.585-1.242-.354-1.536.42-1.88 4.973-.058 9.386 2.889 11.932s7.368 4.912 10.058 6.155c.105.049.013.203-.093.163-4.953-2.182-8.397-3.765-13.07-7.368-.497-.388-1.01-.242-1.07.521-.384 4.748 2.657 8.483 6.058 9.745 2.1.781 4.398 1.212 6.53 1.474.109.015.084.178-.027.178-2.747.01-6.058-.654-8.935-1.751-.606-.233-.818.25-.722.633.491 2.008 2.974 5.076 6.926 5.73a12 12 0 0 0 2.228.115c.164 0 .208.089.154.217q-2.685 4.6-2.803 4.797c-.091.152-.036.275.156.275h3.543c.164 0 .264.106.18.246l-4.958 8.196c-.191.328.035.565.395.301s15.212-11.133 15.636-11.448c.195-.142.148-.327-.124-.327h-3.18c-.206 0-.252-.14-.111-.28.14-.141 3.602-3.594 4.837-4.888 1.283-1.35 1.938-3.825-.231-5.498"
4032
4091
  }));
4033
4092
  }
4034
- var Button = React11.forwardRef(function Button2({ children, kind = "secondary", className = "", ...props }, ref) {
4093
+ var Button = React12.forwardRef(function Button2({ children, kind = "secondary", className = "", ...props }, ref) {
4035
4094
  return h2("button", {
4036
4095
  ...props,
4037
4096
  ref,
@@ -4127,13 +4186,13 @@ function EmptyView({ busy, onStart }) {
4127
4186
  );
4128
4187
  }
4129
4188
  function QrPanel({ provision, now, busy, onRefresh, onCancel }) {
4130
- const [imageFailed, setImageFailed] = React11.useState(false);
4189
+ const [imageFailed, setImageFailed] = React12.useState(false);
4131
4190
  const source = safeQrSource(provision.qrCodeDataUrl);
4132
4191
  const remaining = Math.max(0, provision.expiresAt - now);
4133
4192
  const expired = remaining === 0 || provision.status === "expired";
4134
4193
  const duration = Math.max(1, provision.durationMs ?? 10 * 6e4);
4135
4194
  const progress = Math.round(Math.min(1, remaining / duration) * 100);
4136
- React11.useEffect(() => setImageFailed(false), [source]);
4195
+ React12.useEffect(() => setImageFailed(false), [source]);
4137
4196
  return h2(
4138
4197
  "div",
4139
4198
  { className: "ddt-card dim-surfaceCard" },
@@ -4225,7 +4284,7 @@ function ConnectionErrorDiagnostic({ error }) {
4225
4284
  { className: "ddt-errorCode" },
4226
4285
  h2("span", null, "\u9519\u8BEF\u7801"),
4227
4286
  `: ${error.code}`,
4228
- error.referenceId ? h2(React11.Fragment, null, " \xB7 ", h2("span", null, "\u53C2\u8003\u53F7"), `: ${error.referenceId}`) : null
4287
+ error.referenceId ? h2(React12.Fragment, null, " \xB7 ", h2("span", null, "\u53C2\u8003\u53F7"), `: ${error.referenceId}`) : null
4229
4288
  )
4230
4289
  );
4231
4290
  }
@@ -4248,7 +4307,7 @@ function ProvisionError({ provision, busy, onRetry, onClose }) {
4248
4307
  "div",
4249
4308
  { className: "ddt-actions dim-viewActions" },
4250
4309
  connectionFailed ? h2(Button, { kind: "primary", onClick: onClose, disabled: busy }, "\u67E5\u770B\u5DF2\u4FDD\u5B58\u7684\u673A\u5668\u4EBA") : h2(
4251
- React11.Fragment,
4310
+ React12.Fragment,
4252
4311
  null,
4253
4312
  h2(Button, { kind: "primary", onClick: onRetry, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801"),
4254
4313
  h2(Button, { onClick: onClose, disabled: busy }, "\u5173\u95ED")
@@ -4270,8 +4329,8 @@ function checkedTime(value) {
4270
4329
  }
4271
4330
  }
4272
4331
  function RemoveConfirmation({ account, busy, onConfirm, onCancel }) {
4273
- const cancelRef = React11.useRef(null);
4274
- React11.useEffect(() => cancelRef.current?.focus(), []);
4332
+ const cancelRef = React12.useRef(null);
4333
+ React12.useEffect(() => cancelRef.current?.focus(), []);
4275
4334
  return h2(
4276
4335
  "div",
4277
4336
  {
@@ -4321,89 +4380,104 @@ function AccountCard({
4321
4380
  "div",
4322
4381
  { className: "ddt-cardBody dim-botCardBody" },
4323
4382
  h2(
4324
- "div",
4325
- { className: "ddt-accountTop dim-botCardTop" },
4326
- h2(
4327
- "div",
4328
- { className: "ddt-accountIdentity dim-botIdentity" },
4329
- h2("div", { className: "ddt-avatar dim-botAvatar", "aria-hidden": "true" }, h2(DingtalkIcon, { size: 29 })),
4330
- h2(
4383
+ CollapsibleAccountSection,
4384
+ {
4385
+ id: `ddt-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, "-")}`,
4386
+ header: h2(
4331
4387
  "div",
4332
- { className: "dim-botName" },
4333
- h2("h3", { title: account.bot.name }, account.bot.name),
4334
- h2("p", { title: account.bot.clientIdMasked }, account.bot.clientIdMasked)
4388
+ { className: "ddt-accountTop dim-botCardTop" },
4389
+ h2(
4390
+ "div",
4391
+ { className: "ddt-accountIdentity dim-botIdentity" },
4392
+ h2("div", { className: "ddt-avatar dim-botAvatar", "aria-hidden": "true" }, h2(DingtalkIcon, { size: 29 })),
4393
+ h2(
4394
+ "div",
4395
+ { className: "dim-botName" },
4396
+ h2("h3", { title: account.bot.name }, account.bot.name),
4397
+ h2("p", { title: account.bot.clientIdMasked }, account.bot.clientIdMasked)
4398
+ )
4399
+ ),
4400
+ h2(
4401
+ "div",
4402
+ {
4403
+ className: "dim-botCardTools",
4404
+ // The header is the collapse toggle; keep inner controls clickable.
4405
+ onClick: (event) => {
4406
+ event.stopPropagation();
4407
+ },
4408
+ onKeyDown: (event) => {
4409
+ if (event.key === "Enter" || event.key === " ") event.stopPropagation();
4410
+ }
4411
+ },
4412
+ h2(BotStatusMeta, {
4413
+ className: "ddt-health",
4414
+ dotClassName: "ddt-dot",
4415
+ tone,
4416
+ stateLabel: stateLabel2,
4417
+ lastCheckedAt: account.health.lastCheckedAt,
4418
+ formatCheckedTime: checkedTime
4419
+ }),
4420
+ h2(BotSettingsButton, {
4421
+ channel: "dingtalk",
4422
+ botId: account.botId,
4423
+ botName: account.bot.name,
4424
+ connected: account.connected,
4425
+ accessPolicy: account.accessPolicy
4426
+ })
4427
+ )
4335
4428
  )
4336
- ),
4337
- h2(
4338
- "div",
4339
- { className: "dim-botCardTools" },
4340
- h2(BotStatusMeta, {
4341
- className: "ddt-health",
4342
- dotClassName: "ddt-dot",
4343
- tone,
4344
- stateLabel: stateLabel2,
4345
- lastCheckedAt: account.health.lastCheckedAt,
4346
- formatCheckedTime: checkedTime
4347
- }),
4348
- h2(BotSettingsButton, {
4349
- channel: "dingtalk",
4350
- botId: account.botId,
4351
- botName: account.bot.name,
4352
- connected: account.connected,
4353
- accessPolicy: account.accessPolicy
4354
- })
4355
- )
4356
- ),
4357
- h2(WorkspaceEditor, {
4358
- workspace: account.workspace,
4359
- disabled: Boolean(busy),
4360
- onSave: onWorkspaceSave
4361
- }),
4362
- h2(ModelEditor, {
4363
- model: account.model,
4364
- disabled: Boolean(busy),
4365
- onSave: onModelSave
4366
- }),
4367
- h2(AgentPresetEditor, {
4368
- agentPreset: account.agentPreset,
4369
- disabled: Boolean(busy),
4370
- onSave: onAgentPresetSave
4371
- }),
4372
- h2(ContextEnhancementEditor, {
4373
- config: account.contextEnhancement,
4374
- disabled: Boolean(busy),
4375
- onSave: onContextEnhancementSave
4376
- }),
4377
- h2(
4378
- "div",
4379
- { className: "ddt-accountFooter dim-cardFooter" },
4429
+ },
4430
+ h2(WorkspaceEditor, {
4431
+ workspace: account.workspace,
4432
+ disabled: Boolean(busy),
4433
+ onSave: onWorkspaceSave
4434
+ }),
4435
+ h2(ModelEditor, {
4436
+ model: account.model,
4437
+ disabled: Boolean(busy),
4438
+ onSave: onModelSave
4439
+ }),
4440
+ h2(AgentPresetEditor, {
4441
+ agentPreset: account.agentPreset,
4442
+ disabled: Boolean(busy),
4443
+ onSave: onAgentPresetSave
4444
+ }),
4445
+ h2(ContextEnhancementEditor, {
4446
+ config: account.contextEnhancement,
4447
+ disabled: Boolean(busy),
4448
+ onSave: onContextEnhancementSave
4449
+ }),
4380
4450
  h2(
4381
4451
  "div",
4382
- { className: "dim-cardFooterLayout" },
4452
+ { className: "ddt-accountFooter dim-cardFooter" },
4383
4453
  h2(
4384
4454
  "div",
4385
- { className: "ddt-actions dim-cardActions" },
4455
+ { className: "dim-cardFooterLayout" },
4386
4456
  h2(
4387
- Button,
4388
- { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) },
4389
- busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"
4457
+ "div",
4458
+ { className: "ddt-actions dim-cardActions" },
4459
+ h2(
4460
+ Button,
4461
+ { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) },
4462
+ busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"
4463
+ ),
4464
+ h2(
4465
+ Button,
4466
+ { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) },
4467
+ "\u79FB\u9664\u63A5\u5165"
4468
+ )
4390
4469
  ),
4391
- h2(
4392
- Button,
4393
- { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) },
4394
- "\u79FB\u9664\u63A5\u5165"
4395
- )
4396
- ),
4397
- summary2 ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary2) : null,
4398
- account.error ? h2(ConnectionErrorDiagnostic, { error: account.error }) : null,
4399
- account.lastMessageError ? h2(LastMessageErrorSummary, {
4400
- className: "ddt-summary",
4401
- error: account.lastMessageError
4402
- }) : null,
4403
- feedback ? h2("div", {
4404
- className: "ddt-summary dim-cardFeedback",
4405
- role: "status"
4406
- }, feedback) : null
4470
+ summary2 ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary2) : null,
4471
+ account.error ? h2(ConnectionErrorDiagnostic, { error: account.error }) : null,
4472
+ account.lastMessageError ? h2(LastMessageErrorSummary, {
4473
+ className: "ddt-summary",
4474
+ error: account.lastMessageError
4475
+ }) : null,
4476
+ feedback ? h2("div", {
4477
+ className: "ddt-summary dim-cardFeedback",
4478
+ role: "status"
4479
+ }, feedback) : null
4480
+ )
4407
4481
  )
4408
4482
  )
4409
4483
  ),
@@ -4446,7 +4520,7 @@ function AccountList(props) {
4446
4520
  }
4447
4521
  var EMPTY_TOTALS = Object.freeze({ configured: 0, connected: 0 });
4448
4522
  function DingtalkSettingsTab({ rpcCall }) {
4449
- const [model, setModel] = React11.useState({
4523
+ const [model, setModel] = React12.useState({
4450
4524
  phase: "loading",
4451
4525
  bots: [],
4452
4526
  totals: EMPTY_TOTALS,
@@ -4455,22 +4529,22 @@ function DingtalkSettingsTab({ rpcCall }) {
4455
4529
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG,
4456
4530
  modelCatalog: EMPTY_MODEL_CATALOG
4457
4531
  });
4458
- const [provision, setProvision] = React11.useState(null);
4459
- const [busy, setBusy] = React11.useState(false);
4460
- const [busyByBot, setBusyByBot] = React11.useState({});
4461
- const [feedbackByBot, setFeedbackByBot] = React11.useState({});
4462
- const [removeTarget, setRemoveTarget] = React11.useState(null);
4463
- const [credentialOpen, setCredentialOpen] = React11.useState(false);
4464
- const [credentialError, setCredentialError] = React11.useState(null);
4465
- const [notice, setNotice] = React11.useState("");
4466
- const [now, setNow] = React11.useState(() => Date.now());
4467
- const addButtonRef = React11.useRef(null);
4468
- const mountedRef = React11.useRef(true);
4469
- const statusRequestRef = React11.useRef(0);
4532
+ const [provision, setProvision] = React12.useState(null);
4533
+ const [busy, setBusy] = React12.useState(false);
4534
+ const [busyByBot, setBusyByBot] = React12.useState({});
4535
+ const [feedbackByBot, setFeedbackByBot] = React12.useState({});
4536
+ const [removeTarget, setRemoveTarget] = React12.useState(null);
4537
+ const [credentialOpen, setCredentialOpen] = React12.useState(false);
4538
+ const [credentialError, setCredentialError] = React12.useState(null);
4539
+ const [notice, setNotice] = React12.useState("");
4540
+ const [now, setNow] = React12.useState(() => Date.now());
4541
+ const addButtonRef = React12.useRef(null);
4542
+ const mountedRef = React12.useRef(true);
4543
+ const statusRequestRef = React12.useRef(0);
4470
4544
  const workspaceFence = useWorkspaceSnapshotFence();
4471
- const noticeFrameRef = React11.useRef(null);
4472
- const focusFrameRef = React11.useRef(null);
4473
- React11.useEffect(() => {
4545
+ const noticeFrameRef = React12.useRef(null);
4546
+ const focusFrameRef = React12.useRef(null);
4547
+ React12.useEffect(() => {
4474
4548
  mountedRef.current = true;
4475
4549
  return () => {
4476
4550
  mountedRef.current = false;
@@ -4485,8 +4559,8 @@ function DingtalkSettingsTab({ rpcCall }) {
4485
4559
  }
4486
4560
  };
4487
4561
  }, []);
4488
- React11.useEffect(() => installDingtalkStyles(), []);
4489
- const announce = React11.useCallback((message) => {
4562
+ React12.useEffect(() => installDingtalkStyles(), []);
4563
+ const announce = React12.useCallback((message) => {
4490
4564
  if (!mountedRef.current) return;
4491
4565
  if (noticeFrameRef.current !== null) {
4492
4566
  window.cancelAnimationFrame(noticeFrameRef.current);
@@ -4500,7 +4574,7 @@ function DingtalkSettingsTab({ rpcCall }) {
4500
4574
  });
4501
4575
  }
4502
4576
  }, []);
4503
- const discardStaleFeedback = React11.useCallback((snapshot) => {
4577
+ const discardStaleFeedback = React12.useCallback((snapshot) => {
4504
4578
  const botsById = new Map(snapshot.bots.map((bot) => [bot.botId, bot]));
4505
4579
  setFeedbackByBot((current) => {
4506
4580
  let changed = false;
@@ -4515,7 +4589,7 @@ function DingtalkSettingsTab({ rpcCall }) {
4515
4589
  return changed ? next : current;
4516
4590
  });
4517
4591
  }, []);
4518
- const focusAddButton = React11.useCallback(() => {
4592
+ const focusAddButton = React12.useCallback(() => {
4519
4593
  if (!mountedRef.current) return;
4520
4594
  if (focusFrameRef.current !== null) window.cancelAnimationFrame(focusFrameRef.current);
4521
4595
  focusFrameRef.current = window.requestAnimationFrame(() => {
@@ -4523,11 +4597,11 @@ function DingtalkSettingsTab({ rpcCall }) {
4523
4597
  if (mountedRef.current) addButtonRef.current?.focus();
4524
4598
  });
4525
4599
  }, []);
4526
- const invoke = React11.useCallback(async (endpoint, payload = {}, signal) => {
4600
+ const invoke = React12.useCallback(async (endpoint, payload = {}, signal) => {
4527
4601
  if (typeof rpcCall !== "function") throw new TypeError("\u9489\u9489\u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
4528
4602
  return unwrapRpcResult(await rpcCall(endpoint, payload, signal));
4529
4603
  }, [rpcCall]);
4530
- const loadStatus = React11.useCallback(async ({
4604
+ const loadStatus = React12.useCallback(async ({
4531
4605
  signal,
4532
4606
  silent = false,
4533
4607
  restoreProvisioning = false
@@ -4572,12 +4646,12 @@ function DingtalkSettingsTab({ rpcCall }) {
4572
4646
  return void 0;
4573
4647
  }
4574
4648
  }, [discardStaleFeedback, invoke, workspaceFence]);
4575
- React11.useEffect(() => {
4649
+ React12.useEffect(() => {
4576
4650
  const controller = new AbortController();
4577
4651
  void loadStatus({ signal: controller.signal, restoreProvisioning: true });
4578
4652
  return () => controller.abort();
4579
4653
  }, [loadStatus]);
4580
- React11.useEffect(() => {
4654
+ React12.useEffect(() => {
4581
4655
  if (model.phase !== "ready") return void 0;
4582
4656
  const controller = new AbortController();
4583
4657
  let running = false;
@@ -4596,14 +4670,14 @@ function DingtalkSettingsTab({ rpcCall }) {
4596
4670
  window.clearInterval(timer);
4597
4671
  };
4598
4672
  }, [loadStatus, model.phase]);
4599
- React11.useEffect(() => {
4673
+ React12.useEffect(() => {
4600
4674
  if (!provision || !ACTIVE_PROVISION_STATES.has(provision.status)) return void 0;
4601
4675
  const timer = window.setInterval(() => {
4602
4676
  if (mountedRef.current) setNow(Date.now());
4603
4677
  }, 1e3);
4604
4678
  return () => window.clearInterval(timer);
4605
4679
  }, [provision?.attemptId, provision?.status]);
4606
- const startProvisioning = React11.useCallback(async ({ replace = false } = {}) => {
4680
+ const startProvisioning = React12.useCallback(async ({ replace = false } = {}) => {
4607
4681
  if (!mountedRef.current) return;
4608
4682
  setCredentialOpen(false);
4609
4683
  setCredentialError(null);
@@ -4641,7 +4715,7 @@ function DingtalkSettingsTab({ rpcCall }) {
4641
4715
  if (mountedRef.current) setBusy(false);
4642
4716
  }
4643
4717
  }, [announce, invoke, provision?.attemptId]);
4644
- const bindCredentials = React11.useCallback(async ({ identity, secret }) => {
4718
+ const bindCredentials = React12.useCallback(async ({ identity, secret }) => {
4645
4719
  if (!mountedRef.current) return;
4646
4720
  const snapshotVersion = workspaceFence.beginMutation();
4647
4721
  setBusy(true);
@@ -4674,7 +4748,7 @@ function DingtalkSettingsTab({ rpcCall }) {
4674
4748
  if (mountedRef.current) setBusy(false);
4675
4749
  }
4676
4750
  }, [announce, discardStaleFeedback, invoke, loadStatus, workspaceFence]);
4677
- const cancelProvisioning = React11.useCallback(async () => {
4751
+ const cancelProvisioning = React12.useCallback(async () => {
4678
4752
  if (!mountedRef.current) return;
4679
4753
  setBusy(true);
4680
4754
  try {
@@ -4692,7 +4766,7 @@ function DingtalkSettingsTab({ rpcCall }) {
4692
4766
  if (mountedRef.current) setBusy(false);
4693
4767
  }
4694
4768
  }, [announce, focusAddButton, invoke, provision?.attemptId, provision?.status]);
4695
- React11.useEffect(() => {
4769
+ React12.useEffect(() => {
4696
4770
  const attemptId = provision?.attemptId;
4697
4771
  if (!attemptId || !ACTIVE_PROVISION_STATES.has(provision.status)) return void 0;
4698
4772
  const controller = new AbortController();
@@ -4755,7 +4829,7 @@ function DingtalkSettingsTab({ rpcCall }) {
4755
4829
  timer = null;
4756
4830
  };
4757
4831
  }, [announce, invoke, loadStatus, provision?.attemptId, provision?.pollIntervalMs, provision?.status]);
4758
- const setBotBusy = React11.useCallback((botId, operation) => {
4832
+ const setBotBusy = React12.useCallback((botId, operation) => {
4759
4833
  if (!mountedRef.current) return;
4760
4834
  setBusyByBot((current) => {
4761
4835
  const next = { ...current };
@@ -4764,7 +4838,7 @@ function DingtalkSettingsTab({ rpcCall }) {
4764
4838
  return next;
4765
4839
  });
4766
4840
  }, []);
4767
- const runBotAction = React11.useCallback(async ({ account, operation, endpoint, payload, success }) => {
4841
+ const runBotAction = React12.useCallback(async ({ account, operation, endpoint, payload, success }) => {
4768
4842
  if (!mountedRef.current) return void 0;
4769
4843
  const snapshotVersion = workspaceFence.beginMutation();
4770
4844
  setBotBusy(account.botId, operation);
@@ -4820,7 +4894,7 @@ function DingtalkSettingsTab({ rpcCall }) {
4820
4894
  if (mountedRef.current) setBotBusy(account.botId, null);
4821
4895
  }
4822
4896
  }, [announce, discardStaleFeedback, invoke, loadStatus, setBotBusy, workspaceFence]);
4823
- const reconnect = React11.useCallback((account) => runBotAction({
4897
+ const reconnect = React12.useCallback((account) => runBotAction({
4824
4898
  account,
4825
4899
  operation: "reconnect",
4826
4900
  endpoint: DINGTALK_ENDPOINTS.reconnectBot,
@@ -4831,7 +4905,7 @@ function DingtalkSettingsTab({ rpcCall }) {
4831
4905
  return connectionTestFeedback(snapshot.testMessage) ?? "\u9489\u9489\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\u3002";
4832
4906
  }
4833
4907
  }), [runBotAction]);
4834
- const saveWorkspace = React11.useCallback(async (account, workspace) => {
4908
+ const saveWorkspace = React12.useCallback(async (account, workspace) => {
4835
4909
  const workspaceVersion = workspaceFence.beginMutation();
4836
4910
  setBotBusy(account.botId, "workspace");
4837
4911
  try {
@@ -4857,7 +4931,7 @@ function DingtalkSettingsTab({ rpcCall }) {
4857
4931
  if (mountedRef.current) setBotBusy(account.botId, null);
4858
4932
  }
4859
4933
  }, [discardStaleFeedback, invoke, loadStatus, setBotBusy, workspaceFence]);
4860
- const saveBotSetting = React11.useCallback(async (account, operation, endpoint, payload) => {
4934
+ const saveBotSetting = React12.useCallback(async (account, operation, endpoint, payload) => {
4861
4935
  const snapshotVersion = workspaceFence.beginMutation();
4862
4936
  setBotBusy(account.botId, operation);
4863
4937
  try {
@@ -4883,7 +4957,7 @@ function DingtalkSettingsTab({ rpcCall }) {
4883
4957
  if (mountedRef.current) setBotBusy(account.botId, null);
4884
4958
  }
4885
4959
  }, [discardStaleFeedback, invoke, loadStatus, setBotBusy, workspaceFence]);
4886
- const remove = React11.useCallback(async (account) => {
4960
+ const remove = React12.useCallback(async (account) => {
4887
4961
  const snapshot = await runBotAction({
4888
4962
  account,
4889
4963
  operation: "delete",
@@ -4969,7 +5043,7 @@ function DingtalkSettingsTab({ rpcCall }) {
4969
5043
  h2(Button, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
4970
5044
  )
4971
5045
  ) : h2(
4972
- React11.Fragment,
5046
+ React12.Fragment,
4973
5047
  null,
4974
5048
  credentialView,
4975
5049
  provisionView,
@@ -5113,8 +5187,8 @@ var normalizeSnapshot2 = api.normalizeSnapshot;
5113
5187
  var presentError2 = api.presentError;
5114
5188
 
5115
5189
  // plugin-src/client/channels/shared/token-channel.js
5116
- var React12 = __toESM(require("react"), 1);
5117
- var Button3 = React12.forwardRef(function Button4({ children, kind = "secondary", className = "", ...props }, ref) {
5190
+ var React13 = __toESM(require("react"), 1);
5191
+ var Button3 = React13.forwardRef(function Button4({ children, kind = "secondary", className = "", ...props }, ref) {
5118
5192
  return h2("button", {
5119
5193
  ...props,
5120
5194
  ref,
@@ -5179,98 +5253,113 @@ function createTokenChannelSettings(definition) {
5179
5253
  "div",
5180
5254
  { className: "ddt-cardBody dim-botCardBody" },
5181
5255
  h2(
5182
- "div",
5183
- { className: "ddt-accountTop dim-botCardTop" },
5184
- h2(
5185
- "div",
5186
- { className: "ddt-accountIdentity dim-botIdentity" },
5187
- h2(
5188
- "div",
5189
- { className: `ddt-avatar dim-botAvatar ${avatarClass}`, "aria-hidden": "true" },
5190
- h2(LogoGlyph, { size: 29 })
5191
- ),
5192
- h2(
5256
+ CollapsibleAccountSection,
5257
+ {
5258
+ id: `tok-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, "-")}`,
5259
+ header: h2(
5193
5260
  "div",
5194
- { className: "dim-botName" },
5195
- h2("h3", null, account.bot.name),
5196
- h2("p", null, identity)
5261
+ { className: "ddt-accountTop dim-botCardTop" },
5262
+ h2(
5263
+ "div",
5264
+ { className: "ddt-accountIdentity dim-botIdentity" },
5265
+ h2(
5266
+ "div",
5267
+ { className: `ddt-avatar dim-botAvatar ${avatarClass}`, "aria-hidden": "true" },
5268
+ h2(LogoGlyph, { size: 29 })
5269
+ ),
5270
+ h2(
5271
+ "div",
5272
+ { className: "dim-botName" },
5273
+ h2("h3", null, account.bot.name),
5274
+ h2("p", null, identity)
5275
+ )
5276
+ ),
5277
+ h2(
5278
+ "div",
5279
+ {
5280
+ className: "dim-botCardTools",
5281
+ // The header is the collapse toggle; keep inner controls clickable.
5282
+ onClick: (event) => {
5283
+ event.stopPropagation();
5284
+ },
5285
+ onKeyDown: (event) => {
5286
+ if (event.key === "Enter" || event.key === " ") event.stopPropagation();
5287
+ }
5288
+ },
5289
+ h2(BotStatusMeta, {
5290
+ className: "ddt-health",
5291
+ dotClassName: "ddt-dot",
5292
+ tone,
5293
+ stateLabel: stateLabel2,
5294
+ lastCheckedAt: account.health.lastCheckedAt,
5295
+ formatCheckedTime: checkedTime2
5296
+ }),
5297
+ h2(BotSettingsButton, {
5298
+ channel: channel4.toLowerCase(),
5299
+ botId: account.botId,
5300
+ botName: account.bot.name,
5301
+ connected: account.connected,
5302
+ accessPolicy: account.accessPolicy
5303
+ })
5304
+ )
5197
5305
  )
5198
- ),
5199
- h2(
5200
- "div",
5201
- { className: "dim-botCardTools" },
5202
- h2(BotStatusMeta, {
5203
- className: "ddt-health",
5204
- dotClassName: "ddt-dot",
5205
- tone,
5206
- stateLabel: stateLabel2,
5207
- lastCheckedAt: account.health.lastCheckedAt,
5208
- formatCheckedTime: checkedTime2
5209
- }),
5210
- h2(BotSettingsButton, {
5211
- channel: channel4.toLowerCase(),
5212
- botId: account.botId,
5213
- botName: account.bot.name,
5214
- connected: account.connected,
5215
- accessPolicy: account.accessPolicy
5216
- })
5217
- )
5218
- ),
5219
- h2(WorkspaceEditor, {
5220
- workspace: account.workspace,
5221
- disabled: Boolean(busy),
5222
- onSave: onWorkspaceSave
5223
- }),
5224
- h2(ModelEditor, {
5225
- model: account.model,
5226
- disabled: Boolean(busy),
5227
- onSave: onModelSave
5228
- }),
5229
- h2(AgentPresetEditor, {
5230
- agentPreset: account.agentPreset,
5231
- disabled: Boolean(busy),
5232
- onSave: onAgentPresetSave
5233
- }),
5234
- h2(ContextEnhancementEditor, {
5235
- config: account.contextEnhancement,
5236
- disabled: Boolean(busy),
5237
- onSave: onContextEnhancementSave
5238
- }),
5239
- AccountSettings ? h2(AccountSettings, {
5240
- account,
5241
- busy: Boolean(busy),
5242
- onSave: onAccountSettingsSave
5243
- }) : null,
5244
- h2(
5245
- "div",
5246
- { className: "ddt-accountFooter dim-cardFooter" },
5306
+ },
5307
+ h2(WorkspaceEditor, {
5308
+ workspace: account.workspace,
5309
+ disabled: Boolean(busy),
5310
+ onSave: onWorkspaceSave
5311
+ }),
5312
+ h2(ModelEditor, {
5313
+ model: account.model,
5314
+ disabled: Boolean(busy),
5315
+ onSave: onModelSave
5316
+ }),
5317
+ h2(AgentPresetEditor, {
5318
+ agentPreset: account.agentPreset,
5319
+ disabled: Boolean(busy),
5320
+ onSave: onAgentPresetSave
5321
+ }),
5322
+ h2(ContextEnhancementEditor, {
5323
+ config: account.contextEnhancement,
5324
+ disabled: Boolean(busy),
5325
+ onSave: onContextEnhancementSave
5326
+ }),
5327
+ AccountSettings ? h2(AccountSettings, {
5328
+ account,
5329
+ busy: Boolean(busy),
5330
+ onSave: onAccountSettingsSave
5331
+ }) : null,
5247
5332
  h2(
5248
5333
  "div",
5249
- { className: "dim-cardFooterLayout" },
5334
+ { className: "ddt-accountFooter dim-cardFooter" },
5250
5335
  h2(
5251
5336
  "div",
5252
- { className: "ddt-actions dim-cardActions" },
5253
- h2(Button3, {
5254
- className: "dim-cardAction",
5255
- onClick: onReconnect,
5256
- disabled: Boolean(busy)
5257
- }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
5258
- h2(Button3, {
5259
- className: "dim-cardAction",
5260
- kind: "danger",
5261
- onClick: onRequestRemove,
5262
- disabled: Boolean(busy)
5263
- }, "\u79FB\u9664\u63A5\u5165")
5264
- ),
5265
- summary2 ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary2) : null,
5266
- account.lastMessageError ? h2(LastMessageErrorSummary, {
5267
- className: "ddt-summary",
5268
- error: account.lastMessageError
5269
- }) : null,
5270
- testNotice ? h2("div", {
5271
- className: "ddt-summary dim-cardFeedback",
5272
- role: "status"
5273
- }, testNotice) : null
5337
+ { className: "dim-cardFooterLayout" },
5338
+ h2(
5339
+ "div",
5340
+ { className: "ddt-actions dim-cardActions" },
5341
+ h2(Button3, {
5342
+ className: "dim-cardAction",
5343
+ onClick: onReconnect,
5344
+ disabled: Boolean(busy)
5345
+ }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
5346
+ h2(Button3, {
5347
+ className: "dim-cardAction",
5348
+ kind: "danger",
5349
+ onClick: onRequestRemove,
5350
+ disabled: Boolean(busy)
5351
+ }, "\u79FB\u9664\u63A5\u5165")
5352
+ ),
5353
+ summary2 ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary2) : null,
5354
+ account.lastMessageError ? h2(LastMessageErrorSummary, {
5355
+ className: "ddt-summary",
5356
+ error: account.lastMessageError
5357
+ }) : null,
5358
+ testNotice ? h2("div", {
5359
+ className: "ddt-summary dim-cardFeedback",
5360
+ role: "status"
5361
+ }, testNotice) : null
5362
+ )
5274
5363
  )
5275
5364
  )
5276
5365
  ),
@@ -5293,7 +5382,7 @@ function createTokenChannelSettings(definition) {
5293
5382
  );
5294
5383
  }
5295
5384
  function SettingsTab({ rpcCall }) {
5296
- const [model, setModel] = React12.useState({
5385
+ const [model, setModel] = React13.useState({
5297
5386
  phase: "loading",
5298
5387
  bots: [],
5299
5388
  totals: { configured: 0, connected: 0 },
@@ -5301,15 +5390,15 @@ function createTokenChannelSettings(definition) {
5301
5390
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG,
5302
5391
  modelCatalog: EMPTY_MODEL_CATALOG
5303
5392
  });
5304
- const [credentialOpen, setCredentialOpen] = React12.useState(false);
5305
- const [credentialError, setCredentialError] = React12.useState(null);
5306
- const [busy, setBusy] = React12.useState(false);
5307
- const [busyByBot, setBusyByBot] = React12.useState({});
5308
- const [testNoticeByBot, setTestNoticeByBot] = React12.useState({});
5309
- const [removeTarget, setRemoveTarget] = React12.useState(null);
5310
- const mounted = React12.useRef(true);
5393
+ const [credentialOpen, setCredentialOpen] = React13.useState(false);
5394
+ const [credentialError, setCredentialError] = React13.useState(null);
5395
+ const [busy, setBusy] = React13.useState(false);
5396
+ const [busyByBot, setBusyByBot] = React13.useState({});
5397
+ const [testNoticeByBot, setTestNoticeByBot] = React13.useState({});
5398
+ const [removeTarget, setRemoveTarget] = React13.useState(null);
5399
+ const mounted = React13.useRef(true);
5311
5400
  const workspaceFence = useWorkspaceSnapshotFence();
5312
- React12.useEffect(() => {
5401
+ React13.useEffect(() => {
5313
5402
  const disposeDingtalk = installDingtalkStyles();
5314
5403
  const disposeChannel = installStyles();
5315
5404
  mounted.current = true;
@@ -5319,11 +5408,11 @@ function createTokenChannelSettings(definition) {
5319
5408
  disposeDingtalk();
5320
5409
  };
5321
5410
  }, []);
5322
- const invoke = React12.useCallback(async (endpoint, payload = {}, signal) => {
5411
+ const invoke = React13.useCallback(async (endpoint, payload = {}, signal) => {
5323
5412
  if (typeof rpcCall !== "function") throw new TypeError(`${channel4} \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5`);
5324
5413
  return api4.unwrapRpcResult(await rpcCall(endpoint, payload, signal));
5325
5414
  }, [rpcCall]);
5326
- const loadStatus = React12.useCallback(async ({ signal, silent = false } = {}) => {
5415
+ const loadStatus = React13.useCallback(async ({ signal, silent = false } = {}) => {
5327
5416
  const workspaceVersion = workspaceFence.beginStatus();
5328
5417
  if (workspaceVersion === null) return;
5329
5418
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
@@ -5348,12 +5437,12 @@ function createTokenChannelSettings(definition) {
5348
5437
  }
5349
5438
  }
5350
5439
  }, [invoke, workspaceFence]);
5351
- React12.useEffect(() => {
5440
+ React13.useEffect(() => {
5352
5441
  const controller = new AbortController();
5353
5442
  void loadStatus({ signal: controller.signal });
5354
5443
  return () => controller.abort();
5355
5444
  }, [loadStatus]);
5356
- React12.useEffect(() => {
5445
+ React13.useEffect(() => {
5357
5446
  if (model.phase !== "ready") return void 0;
5358
5447
  const controller = new AbortController();
5359
5448
  const timer = window.setInterval(
@@ -5365,7 +5454,7 @@ function createTokenChannelSettings(definition) {
5365
5454
  window.clearInterval(timer);
5366
5455
  };
5367
5456
  }, [loadStatus, model.phase]);
5368
- const bindCredentials = React12.useCallback(async (values) => {
5457
+ const bindCredentials = React13.useCallback(async (values) => {
5369
5458
  const snapshotVersion = workspaceFence.beginMutation();
5370
5459
  setBusy(true);
5371
5460
  setCredentialError(null);
@@ -5394,7 +5483,7 @@ function createTokenChannelSettings(definition) {
5394
5483
  if (mounted.current) setBusy(false);
5395
5484
  }
5396
5485
  }, [invoke, loadStatus, workspaceFence]);
5397
- const botAction = React12.useCallback(async (account, operation, endpoint, payload) => {
5486
+ const botAction = React13.useCallback(async (account, operation, endpoint, payload) => {
5398
5487
  const snapshotVersion = workspaceFence.beginMutation();
5399
5488
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
5400
5489
  try {
@@ -5546,7 +5635,7 @@ function createTokenChannelSettings(definition) {
5546
5635
  h2(Button3, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
5547
5636
  )
5548
5637
  ) : h2(
5549
- React12.Fragment,
5638
+ React13.Fragment,
5550
5639
  null,
5551
5640
  credentialOpen ? CredentialPanel ? h2(CredentialPanel, {
5552
5641
  busy,
@@ -5647,7 +5736,7 @@ var DiscordSettingsTab = channel.SettingsTab;
5647
5736
  var DiscordAccountCard = channel.AccountCard;
5648
5737
 
5649
5738
  // plugin-src/client/channels/feishu/index.js
5650
- var React14 = __toESM(require("react"), 1);
5739
+ var React15 = __toESM(require("react"), 1);
5651
5740
 
5652
5741
  // plugin-src/client/channels/feishu/api.js
5653
5742
  var FEISHU_RPC_CHANNEL = "/feishu";
@@ -5916,7 +6005,7 @@ function formatRemaining2(milliseconds) {
5916
6005
  }
5917
6006
 
5918
6007
  // plugin-src/client/lifecycle.js
5919
- var React13 = __toESM(require("react"), 1);
6008
+ var React14 = __toESM(require("react"), 1);
5920
6009
  function createPollScheduler({ setTimeoutFn, clearTimeoutFn }) {
5921
6010
  let disposed = false;
5922
6011
  let timer;
@@ -5978,8 +6067,8 @@ function createAnimationFrameScheduler({ requestFrame, cancelFrame }) {
5978
6067
  };
5979
6068
  }
5980
6069
  function useAnimationFrameScheduler() {
5981
- const schedulerRef = React13.useRef(null);
5982
- React13.useEffect(() => {
6070
+ const schedulerRef = React14.useRef(null);
6071
+ React14.useEffect(() => {
5983
6072
  const scheduler = createAnimationFrameScheduler({
5984
6073
  requestFrame: (callback) => window.requestAnimationFrame(callback),
5985
6074
  cancelFrame: (frame) => window.cancelAnimationFrame(frame)
@@ -5990,7 +6079,7 @@ function useAnimationFrameScheduler() {
5990
6079
  if (schedulerRef.current === scheduler) schedulerRef.current = null;
5991
6080
  };
5992
6081
  }, []);
5993
- return React13.useCallback(
6082
+ return React14.useCallback(
5994
6083
  (callback, key) => schedulerRef.current?.schedule(callback, key) ?? false,
5995
6084
  []
5996
6085
  );
@@ -6065,7 +6154,7 @@ function QrIcon({ size = 58 }) {
6065
6154
  fill: "currentColor"
6066
6155
  }));
6067
6156
  }
6068
- var Button5 = React14.forwardRef(function Button6({ children, kind = "secondary", size, icon, className = "", ...props }, ref) {
6157
+ var Button5 = React15.forwardRef(function Button6({ children, kind = "secondary", size, icon, className = "", ...props }, ref) {
6069
6158
  return h2("button", {
6070
6159
  ...props,
6071
6160
  ref,
@@ -6182,7 +6271,7 @@ function safeQrSource2(value) {
6182
6271
  return /^data:image\/(?:png|webp|svg\+xml)(?:;charset=[^;,]+)?;base64,/i.test(value) ? value : void 0;
6183
6272
  }
6184
6273
  function QrPane({ provision, now, onRefresh, onCancel, busy }) {
6185
- const [imageFailed, setImageFailed] = React14.useState(false);
6274
+ const [imageFailed, setImageFailed] = React15.useState(false);
6186
6275
  const qrSource = safeQrSource2(provision.qrCodeDataUrl);
6187
6276
  const href = safeVerificationHref(provision.verificationUrl);
6188
6277
  const remaining = Math.max(0, provision.expiresAt - now);
@@ -6191,7 +6280,7 @@ function QrPane({ provision, now, onRefresh, onCancel, busy }) {
6191
6280
  const repairing = isCallbackRepair(provision);
6192
6281
  const grantingGroupMessages = isGroupMessagePermission(provision);
6193
6282
  const botName = provision.botName ?? "\u6B64\u673A\u5668\u4EBA";
6194
- React14.useEffect(() => setImageFailed(false), [qrSource]);
6283
+ React15.useEffect(() => setImageFailed(false), [qrSource]);
6195
6284
  return h2(
6196
6285
  "div",
6197
6286
  { className: "bxf-card bxf-provisionCard dim-surfaceCard" },
@@ -6354,11 +6443,11 @@ function connectionTestNotice2(value) {
6354
6443
  return value?.testMessage ? "\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002" : null;
6355
6444
  }
6356
6445
  function RemoveConfirmation2({ bot, busy, onConfirm, onCancel }) {
6357
- const cancelRef = React14.useRef(null);
6446
+ const cancelRef = React15.useRef(null);
6358
6447
  const idPart = bot.botId.replace(/[^a-zA-Z0-9_-]/g, "-");
6359
6448
  const titleId = `bxf-remove-title-${idPart}`;
6360
6449
  const descriptionId = `bxf-remove-description-${idPart}`;
6361
- React14.useEffect(() => cancelRef.current?.focus(), []);
6450
+ React15.useEffect(() => cancelRef.current?.focus(), []);
6362
6451
  return h2(
6363
6452
  "div",
6364
6453
  {
@@ -6413,7 +6502,7 @@ function BotCard({
6413
6502
  removeButtonRef
6414
6503
  }) {
6415
6504
  const { bot, health, state, connected } = connection;
6416
- const repairTooltipId = React14.useId();
6505
+ const repairTooltipId = React15.useId();
6417
6506
  const stateForDisplay = busy === "reconnect" ? "connecting" : state;
6418
6507
  const tone = stateForDisplay === "connected" ? "success" : stateForDisplay === "connecting" ? "warning" : "error";
6419
6508
  const summary2 = actionError?.message ?? connection.error?.message ?? (connected ? null : health.summary);
@@ -6431,136 +6520,151 @@ function BotCard({
6431
6520
  "div",
6432
6521
  { className: "bxf-cardBody dim-botCardBody" },
6433
6522
  h2(
6434
- "div",
6435
- { className: "bxf-connectedTop dim-botCardTop" },
6436
- h2(
6437
- "div",
6438
- { className: "bxf-botIdentity dim-botIdentity" },
6439
- h2(
6440
- "div",
6441
- { className: "bxf-avatar dim-botAvatar", "aria-hidden": "true" },
6442
- h2(FeishuLogoGlyph, { size: 34 })
6443
- ),
6444
- h2(
6445
- "div",
6446
- { className: "bxf-botName dim-botName" },
6447
- h2("h3", { id: titleId, title: bot.name }, bot.name),
6448
- h2("p", { title: bot.appIdMasked }, bot.appIdMasked ?? "\u5E94\u7528\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58")
6449
- )
6450
- ),
6451
- h2(
6452
- "div",
6453
- { className: "dim-botCardTools" },
6454
- h2(BotStatusMeta, {
6455
- className: "bxf-healthPill",
6456
- dotClassName: "bxf-dot",
6457
- tone,
6458
- stateLabel: HEALTH_LABELS[stateForDisplay] ?? "\u72B6\u6001\u672A\u77E5",
6459
- lastCheckedAt: health.lastCheckedAt,
6460
- formatCheckedTime,
6461
- healthState: stateForDisplay
6462
- }),
6463
- h2(BotSettingsButton, {
6464
- channel: "feishu",
6465
- botId: connection.botId,
6466
- botName: bot.name,
6467
- connected,
6468
- accessPolicy: connection.accessPolicy,
6469
- channelSettings: {
6470
- groupResponseMode: connection.groupResponseMode,
6471
- groupTopicReply: connection.groupTopicReply,
6472
- groupMessagePermissionGranted: connection.groupMessagePermissionGranted
6473
- }
6474
- })
6475
- )
6476
- ),
6477
- h2(WorkspaceEditor, {
6478
- workspace: connection.workspace,
6479
- disabled: Boolean(busy),
6480
- onSave: onWorkspaceSave
6481
- }),
6482
- h2(ModelEditor, {
6483
- model: connection.model,
6484
- disabled: Boolean(busy),
6485
- onSave: onModelSave
6486
- }),
6487
- h2(AgentPresetEditor, {
6488
- agentPreset: connection.agentPreset,
6489
- disabled: Boolean(busy),
6490
- onSave: onAgentPresetSave
6491
- }),
6492
- h2(ContextEnhancementEditor, {
6493
- config: connection.contextEnhancement,
6494
- disabled: Boolean(busy),
6495
- onSave: onContextEnhancementSave
6496
- }),
6497
- provisionContent ? h2("section", {
6498
- className: "bxf-botProvision dim-botProvision",
6499
- "aria-label": `${bot.name}\u7684\u98DE\u4E66\u6388\u6743\u6D41\u7A0B`,
6500
- "data-provision-for": connection.botId,
6501
- ref: provisionRef,
6502
- tabIndex: -1
6503
- }, provisionContent) : null,
6504
- h2(
6505
- "div",
6506
- { className: "bxf-connectedFooter dim-cardFooter" },
6507
- h2(
6508
- "div",
6509
- { className: "dim-cardFooterLayout" },
6510
- h2(
6523
+ CollapsibleAccountSection,
6524
+ {
6525
+ id: `bxf-settings-${connection.botId.replace(/[^a-zA-Z0-9_-]/g, "-")}`,
6526
+ header: h2(
6511
6527
  "div",
6512
- { className: "bxf-actions bxf-botActions dim-cardActions" },
6513
- h2(Button5, {
6514
- className: "dim-cardAction",
6515
- onClick: onReconnect,
6516
- disabled: Boolean(busy),
6517
- "aria-busy": busy === "reconnect" ? "true" : void 0,
6518
- "aria-label": `${connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"}${bot.name}`
6519
- }, busy === "reconnect" ? connected ? "\u68C0\u67E5\u4E2D\u2026" : "\u6B63\u5728\u8FDE\u63A5\u2026" : connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
6528
+ { className: "bxf-connectedTop dim-botCardTop" },
6520
6529
  h2(
6521
- "span",
6522
- { className: "bxf-repairAction" },
6523
- h2(Button5, {
6524
- className: "bxf-repairButton dim-cardAction",
6525
- onClick: onRepairCallback,
6526
- disabled: Boolean(busy) || repairDisabled,
6527
- "aria-busy": busy === "callback-repair" ? "true" : void 0,
6528
- "aria-label": `\u4E3A${bot.name}\u8865\u5168\u6743\u9650\u4E0E\u56DE\u8C03`,
6529
- "aria-describedby": repairTooltipId
6530
- }, busy === "callback-repair" ? "\u7B49\u5F85\u626B\u7801\u2026" : "\u8865\u5168\u6743\u9650"),
6530
+ "div",
6531
+ { className: "bxf-botIdentity dim-botIdentity" },
6531
6532
  h2(
6532
- "span",
6533
- {
6534
- id: repairTooltipId,
6535
- className: "bxf-repairTooltip",
6536
- role: "tooltip"
6537
- },
6538
- h2("strong", null, "\u8865\u5168\u8303\u56F4"),
6539
- h2("span", null, "\u589E\u91CF\u6DFB\u52A0\u5F53\u524D\u7F3A\u5C11\u7684\u5361\u7247\u56DE\u8C03 card.action.trigger\u3001\u8BFB\u53D6\u6D88\u606F\u5185\u56FE\u7247\u6216\u6587\u4EF6\u6240\u9700\u7684 im:message:readonly\uFF08\u98DE\u4E66\u663E\u793A\u4E3A\u201C\u83B7\u53D6\u5355\u804A\u3001\u7FA4\u7EC4\u6D88\u606F\u201D\uFF09\u3001\u4E0A\u4F20\u673A\u5668\u4EBA\u56FE\u7247\u6216\u6587\u4EF6\u6240\u9700\u7684 im:resource\uFF0C\u4EE5\u53CA\u539F\u751F\u547D\u4EE4\u9762\u677F\u6240\u9700\u7684 application:app_slash_command:read / write\uFF1B\u786E\u8BA4\u9875\u53EA\u663E\u793A\u5F53\u524D\u7F3A\u5C11\u9879\uFF0C\u4E0D\u4F1A\u521B\u5EFA\u65B0\u5E94\u7528\u3002")
6540
- )
6541
- ),
6542
- h2(Button5, {
6543
- className: "dim-cardAction",
6544
- kind: "danger",
6545
- onClick: onRequestRemove,
6546
- disabled: Boolean(busy),
6547
- ref: removeButtonRef,
6548
- "aria-label": `\u4ECE DeepSeek Harness \u79FB\u9664${bot.name}`
6549
- }, "\u79FB\u9664\u63A5\u5165")
6550
- ),
6551
- summary2 ? h2(
6533
+ "div",
6534
+ { className: "bxf-avatar dim-botAvatar", "aria-hidden": "true" },
6535
+ h2(FeishuLogoGlyph, { size: 34 })
6536
+ ),
6537
+ h2(
6538
+ "div",
6539
+ { className: "bxf-botName dim-botName" },
6540
+ h2("h3", { id: titleId, title: bot.name }, bot.name),
6541
+ h2("p", { title: bot.appIdMasked }, bot.appIdMasked ?? "\u5E94\u7528\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58")
6542
+ )
6543
+ ),
6544
+ h2(
6545
+ "div",
6546
+ {
6547
+ className: "dim-botCardTools",
6548
+ // The header is the collapse toggle; keep inner controls clickable.
6549
+ onClick: (event) => {
6550
+ event.stopPropagation();
6551
+ },
6552
+ onKeyDown: (event) => {
6553
+ if (event.key === "Enter" || event.key === " ") event.stopPropagation();
6554
+ }
6555
+ },
6556
+ h2(BotStatusMeta, {
6557
+ className: "bxf-healthPill",
6558
+ dotClassName: "bxf-dot",
6559
+ tone,
6560
+ stateLabel: HEALTH_LABELS[stateForDisplay] ?? "\u72B6\u6001\u672A\u77E5",
6561
+ lastCheckedAt: health.lastCheckedAt,
6562
+ formatCheckedTime,
6563
+ healthState: stateForDisplay
6564
+ }),
6565
+ h2(BotSettingsButton, {
6566
+ channel: "feishu",
6567
+ botId: connection.botId,
6568
+ botName: bot.name,
6569
+ connected,
6570
+ accessPolicy: connection.accessPolicy,
6571
+ channelSettings: {
6572
+ groupResponseMode: connection.groupResponseMode,
6573
+ groupTopicReply: connection.groupTopicReply,
6574
+ groupMessagePermissionGranted: connection.groupMessagePermissionGranted
6575
+ }
6576
+ })
6577
+ )
6578
+ )
6579
+ },
6580
+ h2(WorkspaceEditor, {
6581
+ workspace: connection.workspace,
6582
+ disabled: Boolean(busy),
6583
+ onSave: onWorkspaceSave
6584
+ }),
6585
+ h2(ModelEditor, {
6586
+ model: connection.model,
6587
+ disabled: Boolean(busy),
6588
+ onSave: onModelSave
6589
+ }),
6590
+ h2(AgentPresetEditor, {
6591
+ agentPreset: connection.agentPreset,
6592
+ disabled: Boolean(busy),
6593
+ onSave: onAgentPresetSave
6594
+ }),
6595
+ h2(ContextEnhancementEditor, {
6596
+ config: connection.contextEnhancement,
6597
+ disabled: Boolean(busy),
6598
+ onSave: onContextEnhancementSave
6599
+ }),
6600
+ provisionContent ? h2("section", {
6601
+ className: "bxf-botProvision dim-botProvision",
6602
+ "aria-label": `${bot.name}\u7684\u98DE\u4E66\u6388\u6743\u6D41\u7A0B`,
6603
+ "data-provision-for": connection.botId,
6604
+ ref: provisionRef,
6605
+ tabIndex: -1
6606
+ }, provisionContent) : null,
6607
+ h2(
6608
+ "div",
6609
+ { className: "bxf-connectedFooter dim-cardFooter" },
6610
+ h2(
6552
6611
  "div",
6553
- { className: "bxf-healthSummary dim-cardSummary", "data-error": actionError || connection.error ? "true" : void 0 },
6554
- summary2
6555
- ) : null,
6556
- connection.lastMessageError ? h2(LastMessageErrorSummary, {
6557
- className: "bxf-healthSummary",
6558
- error: connection.lastMessageError
6559
- }) : null,
6560
- testNotice ? h2("div", {
6561
- className: "bxf-healthSummary dim-cardFeedback",
6562
- role: "status"
6563
- }, testNotice) : null
6612
+ { className: "dim-cardFooterLayout" },
6613
+ h2(
6614
+ "div",
6615
+ { className: "bxf-actions bxf-botActions dim-cardActions" },
6616
+ h2(Button5, {
6617
+ className: "dim-cardAction",
6618
+ onClick: onReconnect,
6619
+ disabled: Boolean(busy),
6620
+ "aria-busy": busy === "reconnect" ? "true" : void 0,
6621
+ "aria-label": `${connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"}${bot.name}`
6622
+ }, busy === "reconnect" ? connected ? "\u68C0\u67E5\u4E2D\u2026" : "\u6B63\u5728\u8FDE\u63A5\u2026" : connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
6623
+ h2(
6624
+ "span",
6625
+ { className: "bxf-repairAction" },
6626
+ h2(Button5, {
6627
+ className: "bxf-repairButton dim-cardAction",
6628
+ onClick: onRepairCallback,
6629
+ disabled: Boolean(busy) || repairDisabled,
6630
+ "aria-busy": busy === "callback-repair" ? "true" : void 0,
6631
+ "aria-label": `\u4E3A${bot.name}\u8865\u5168\u6743\u9650\u4E0E\u56DE\u8C03`,
6632
+ "aria-describedby": repairTooltipId
6633
+ }, busy === "callback-repair" ? "\u7B49\u5F85\u626B\u7801\u2026" : "\u8865\u5168\u6743\u9650"),
6634
+ h2(
6635
+ "span",
6636
+ {
6637
+ id: repairTooltipId,
6638
+ className: "bxf-repairTooltip",
6639
+ role: "tooltip"
6640
+ },
6641
+ h2("strong", null, "\u8865\u5168\u8303\u56F4"),
6642
+ h2("span", null, "\u589E\u91CF\u6DFB\u52A0\u5F53\u524D\u7F3A\u5C11\u7684\u5361\u7247\u56DE\u8C03 card.action.trigger\u3001\u8BFB\u53D6\u6D88\u606F\u5185\u56FE\u7247\u6216\u6587\u4EF6\u6240\u9700\u7684 im:message:readonly\uFF08\u98DE\u4E66\u663E\u793A\u4E3A\u201C\u83B7\u53D6\u5355\u804A\u3001\u7FA4\u7EC4\u6D88\u606F\u201D\uFF09\u3001\u4E0A\u4F20\u673A\u5668\u4EBA\u56FE\u7247\u6216\u6587\u4EF6\u6240\u9700\u7684 im:resource\uFF0C\u4EE5\u53CA\u539F\u751F\u547D\u4EE4\u9762\u677F\u6240\u9700\u7684 application:app_slash_command:read / write\uFF1B\u786E\u8BA4\u9875\u53EA\u663E\u793A\u5F53\u524D\u7F3A\u5C11\u9879\uFF0C\u4E0D\u4F1A\u521B\u5EFA\u65B0\u5E94\u7528\u3002")
6643
+ )
6644
+ ),
6645
+ h2(Button5, {
6646
+ className: "dim-cardAction",
6647
+ kind: "danger",
6648
+ onClick: onRequestRemove,
6649
+ disabled: Boolean(busy),
6650
+ ref: removeButtonRef,
6651
+ "aria-label": `\u4ECE DeepSeek Harness \u79FB\u9664${bot.name}`
6652
+ }, "\u79FB\u9664\u63A5\u5165")
6653
+ ),
6654
+ summary2 ? h2(
6655
+ "div",
6656
+ { className: "bxf-healthSummary dim-cardSummary", "data-error": actionError || connection.error ? "true" : void 0 },
6657
+ summary2
6658
+ ) : null,
6659
+ connection.lastMessageError ? h2(LastMessageErrorSummary, {
6660
+ className: "bxf-healthSummary",
6661
+ error: connection.lastMessageError
6662
+ }) : null,
6663
+ testNotice ? h2("div", {
6664
+ className: "bxf-healthSummary dim-cardFeedback",
6665
+ role: "status"
6666
+ }, testNotice) : null
6667
+ )
6564
6668
  )
6565
6669
  )
6566
6670
  ),
@@ -6666,7 +6770,7 @@ function mergeFeishuSnapshotState(current, snapshot, { restoreProvisioning = fal
6666
6770
  };
6667
6771
  }
6668
6772
  function FeishuSettingsTab({ rpcCall }) {
6669
- const [model, setModel] = React14.useState({
6773
+ const [model, setModel] = React15.useState({
6670
6774
  phase: "loading",
6671
6775
  revision: 0,
6672
6776
  bots: [],
@@ -6677,41 +6781,41 @@ function FeishuSettingsTab({ rpcCall }) {
6677
6781
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG,
6678
6782
  modelCatalog: EMPTY_MODEL_CATALOG
6679
6783
  });
6680
- const [pageBusy, setPageBusy] = React14.useState(false);
6681
- const [provisionBusy, setProvisionBusy] = React14.useState(false);
6682
- const [credentialOpen, setCredentialOpen] = React14.useState(false);
6683
- const [credentialBusy, setCredentialBusy] = React14.useState(false);
6684
- const [credentialError, setCredentialError] = React14.useState(null);
6685
- const [busyByBot, setBusyByBot] = React14.useState({});
6686
- const [errorsByBot, setErrorsByBot] = React14.useState({});
6687
- const [testNoticesByBot, setTestNoticesByBot] = React14.useState({});
6688
- const [removeTargetId, setRemoveTargetId] = React14.useState(null);
6689
- const [announcement, setAnnouncement] = React14.useState("");
6690
- const [now, setNow] = React14.useState(() => Date.now());
6691
- const [focusBotId, setFocusBotId] = React14.useState(null);
6692
- const cardRefs = React14.useRef(/* @__PURE__ */ new Map());
6693
- const removeButtonRefs = React14.useRef(/* @__PURE__ */ new Map());
6694
- const targetedProvisionRef = React14.useRef(null);
6695
- const addButtonRef = React14.useRef(null);
6696
- const mountedRef = React14.useRef(true);
6784
+ const [pageBusy, setPageBusy] = React15.useState(false);
6785
+ const [provisionBusy, setProvisionBusy] = React15.useState(false);
6786
+ const [credentialOpen, setCredentialOpen] = React15.useState(false);
6787
+ const [credentialBusy, setCredentialBusy] = React15.useState(false);
6788
+ const [credentialError, setCredentialError] = React15.useState(null);
6789
+ const [busyByBot, setBusyByBot] = React15.useState({});
6790
+ const [errorsByBot, setErrorsByBot] = React15.useState({});
6791
+ const [testNoticesByBot, setTestNoticesByBot] = React15.useState({});
6792
+ const [removeTargetId, setRemoveTargetId] = React15.useState(null);
6793
+ const [announcement, setAnnouncement] = React15.useState("");
6794
+ const [now, setNow] = React15.useState(() => Date.now());
6795
+ const [focusBotId, setFocusBotId] = React15.useState(null);
6796
+ const cardRefs = React15.useRef(/* @__PURE__ */ new Map());
6797
+ const removeButtonRefs = React15.useRef(/* @__PURE__ */ new Map());
6798
+ const targetedProvisionRef = React15.useRef(null);
6799
+ const addButtonRef = React15.useRef(null);
6800
+ const mountedRef = React15.useRef(true);
6697
6801
  const workspaceFence = useWorkspaceSnapshotFence();
6698
6802
  const scheduleAnimationFrame = useAnimationFrameScheduler();
6699
- React14.useEffect(() => {
6803
+ React15.useEffect(() => {
6700
6804
  mountedRef.current = true;
6701
6805
  return () => {
6702
6806
  mountedRef.current = false;
6703
6807
  };
6704
6808
  }, []);
6705
- const announce = React14.useCallback((message) => {
6809
+ const announce = React15.useCallback((message) => {
6706
6810
  setAnnouncement("");
6707
6811
  scheduleAnimationFrame(() => {
6708
6812
  if (message) setAnnouncement(message);
6709
6813
  }, "announcement");
6710
6814
  }, [scheduleAnimationFrame]);
6711
- const invoke = React14.useCallback(async (endpoint, payload = {}, signal) => {
6815
+ const invoke = React15.useCallback(async (endpoint, payload = {}, signal) => {
6712
6816
  return unwrapRpcResult3(await rpcCall(endpoint, payload, signal));
6713
6817
  }, [rpcCall]);
6714
- const mergeSnapshot = React14.useCallback((snapshot, { restoreProvisioning = false } = {}) => {
6818
+ const mergeSnapshot = React15.useCallback((snapshot, { restoreProvisioning = false } = {}) => {
6715
6819
  const now2 = Date.now();
6716
6820
  setModel((current) => mergeFeishuSnapshotState(
6717
6821
  current,
@@ -6719,7 +6823,7 @@ function FeishuSettingsTab({ rpcCall }) {
6719
6823
  { restoreProvisioning, now: now2 }
6720
6824
  ));
6721
6825
  }, []);
6722
- const loadStatus = React14.useCallback(async ({ signal, silent = false, restoreProvisioning = false } = {}) => {
6826
+ const loadStatus = React15.useCallback(async ({ signal, silent = false, restoreProvisioning = false } = {}) => {
6723
6827
  const workspaceVersion = workspaceFence.beginStatus();
6724
6828
  if (workspaceVersion === null || !mountedRef.current) return void 0;
6725
6829
  if (!silent) setPageBusy(true);
@@ -6737,12 +6841,12 @@ function FeishuSettingsTab({ rpcCall }) {
6737
6841
  if (!silent && !signal?.aborted && mountedRef.current) setPageBusy(false);
6738
6842
  }
6739
6843
  }, [invoke, mergeSnapshot, workspaceFence]);
6740
- React14.useEffect(() => {
6844
+ React15.useEffect(() => {
6741
6845
  const controller = new AbortController();
6742
6846
  void loadStatus({ signal: controller.signal, restoreProvisioning: true });
6743
6847
  return () => controller.abort();
6744
6848
  }, [loadStatus]);
6745
- React14.useEffect(() => {
6849
+ React15.useEffect(() => {
6746
6850
  if (model.phase !== "ready") return void 0;
6747
6851
  const controller = new AbortController();
6748
6852
  let inFlight = false;
@@ -6761,7 +6865,7 @@ function FeishuSettingsTab({ rpcCall }) {
6761
6865
  window.clearInterval(timer);
6762
6866
  };
6763
6867
  }, [loadStatus, model.phase]);
6764
- React14.useEffect(() => {
6868
+ React15.useEffect(() => {
6765
6869
  if (!focusBotId) return;
6766
6870
  const node = cardRefs.current.get(focusBotId);
6767
6871
  if (!node) return;
@@ -6770,7 +6874,7 @@ function FeishuSettingsTab({ rpcCall }) {
6770
6874
  setFocusBotId(null);
6771
6875
  }, [focusBotId, model.bots]);
6772
6876
  const targetedProvisionFocusKey = isTargetedAppUpdate2(model.provisioning) ? `${model.provisioning.botId}:${model.provisioning.attemptId ?? "preparing"}:${model.provisioning.phase}` : null;
6773
- React14.useEffect(() => {
6877
+ React15.useEffect(() => {
6774
6878
  if (!targetedProvisionFocusKey) return;
6775
6879
  scheduleAnimationFrame(() => {
6776
6880
  const node = targetedProvisionRef.current;
@@ -6779,7 +6883,7 @@ function FeishuSettingsTab({ rpcCall }) {
6779
6883
  node.focus?.({ preventScroll: true });
6780
6884
  }, "targeted-provision-focus");
6781
6885
  }, [scheduleAnimationFrame, targetedProvisionFocusKey]);
6782
- const startProvisioning = React14.useCallback(async ({
6886
+ const startProvisioning = React15.useCallback(async ({
6783
6887
  replace = false,
6784
6888
  operation = FEISHU_REGISTRATION_OPERATIONS.PROVISION,
6785
6889
  bot
@@ -6855,7 +6959,7 @@ function FeishuSettingsTab({ rpcCall }) {
6855
6959
  model.provisioning?.botId,
6856
6960
  model.provisioning?.botName
6857
6961
  ]);
6858
- const bindCredentials = React14.useCallback(async ({ identity, secret }) => {
6962
+ const bindCredentials = React15.useCallback(async ({ identity, secret }) => {
6859
6963
  const snapshotVersion = workspaceFence.beginMutation();
6860
6964
  setCredentialBusy(true);
6861
6965
  setCredentialError(null);
@@ -6877,7 +6981,7 @@ function FeishuSettingsTab({ rpcCall }) {
6877
6981
  setCredentialBusy(false);
6878
6982
  }
6879
6983
  }, [announce, invoke, loadStatus, mergeSnapshot, workspaceFence]);
6880
- const cancelProvisioning = React14.useCallback(async () => {
6984
+ const cancelProvisioning = React15.useCallback(async () => {
6881
6985
  const activeProvision = model.provisioning;
6882
6986
  const attemptId = activeProvision?.attemptId;
6883
6987
  const repairing = isCallbackRepair(activeProvision);
@@ -6942,7 +7046,7 @@ function FeishuSettingsTab({ rpcCall }) {
6942
7046
  const countdownPhase = model.provisioning?.phase;
6943
7047
  const countdownExpiresAt = model.provisioning?.expiresAt;
6944
7048
  const countdownExpired = model.provisioning?.expired;
6945
- React14.useEffect(() => {
7049
+ React15.useEffect(() => {
6946
7050
  if (!countdownAttemptId || countdownPhase !== "qr" || countdownExpired) return void 0;
6947
7051
  const tick = () => {
6948
7052
  const timestamp7 = Date.now();
@@ -6955,7 +7059,7 @@ function FeishuSettingsTab({ rpcCall }) {
6955
7059
  const timer = window.setInterval(tick, 1e3);
6956
7060
  return () => window.clearInterval(timer);
6957
7061
  }, [countdownAttemptId, countdownPhase, countdownExpiresAt, countdownExpired]);
6958
- React14.useEffect(() => {
7062
+ React15.useEffect(() => {
6959
7063
  const provision2 = model.provisioning;
6960
7064
  if (!provision2 || !["qr", "connecting"].includes(provision2.phase) || !provision2.attemptId || provision2.expired) return void 0;
6961
7065
  const controller = new AbortController();
@@ -7023,7 +7127,7 @@ function FeishuSettingsTab({ rpcCall }) {
7023
7127
  window.clearTimeout(timer);
7024
7128
  };
7025
7129
  }, [announce, invoke, loadStatus, model.provisioning]);
7026
- const setBotBusy = React14.useCallback((botId, value) => {
7130
+ const setBotBusy = React15.useCallback((botId, value) => {
7027
7131
  setBusyByBot((current) => {
7028
7132
  const next = { ...current };
7029
7133
  if (value) next[botId] = value;
@@ -7031,7 +7135,7 @@ function FeishuSettingsTab({ rpcCall }) {
7031
7135
  return next;
7032
7136
  });
7033
7137
  }, []);
7034
- const setBotError = React14.useCallback((botId, error) => {
7138
+ const setBotError = React15.useCallback((botId, error) => {
7035
7139
  setErrorsByBot((current) => {
7036
7140
  const next = { ...current };
7037
7141
  if (error) next[botId] = presentError3(error);
@@ -7039,7 +7143,7 @@ function FeishuSettingsTab({ rpcCall }) {
7039
7143
  return next;
7040
7144
  });
7041
7145
  }, []);
7042
- const repairCallback = React14.useCallback((connection) => {
7146
+ const repairCallback = React15.useCallback((connection) => {
7043
7147
  if (model.provisioning) return;
7044
7148
  setRemoveTargetId(null);
7045
7149
  setBotError(connection.botId, null);
@@ -7053,7 +7157,7 @@ function FeishuSettingsTab({ rpcCall }) {
7053
7157
  bot: connection
7054
7158
  });
7055
7159
  }, [model.provisioning, setBotError, startProvisioning]);
7056
- const reconnectOneBot = React14.useCallback(async (connection) => {
7160
+ const reconnectOneBot = React15.useCallback(async (connection) => {
7057
7161
  const { botId, bot } = connection;
7058
7162
  const snapshotVersion = workspaceFence.beginMutation();
7059
7163
  setBotBusy(botId, "reconnect");
@@ -7093,7 +7197,7 @@ function FeishuSettingsTab({ rpcCall }) {
7093
7197
  setBotBusy(botId, null);
7094
7198
  }
7095
7199
  }, [announce, invoke, loadStatus, mergeSnapshot, setBotBusy, setBotError, workspaceFence]);
7096
- const saveWorkspace = React14.useCallback(async (connection, workspace) => {
7200
+ const saveWorkspace = React15.useCallback(async (connection, workspace) => {
7097
7201
  const { botId } = connection;
7098
7202
  const workspaceVersion = workspaceFence.beginMutation();
7099
7203
  setBotBusy(botId, "workspace");
@@ -7112,7 +7216,7 @@ function FeishuSettingsTab({ rpcCall }) {
7112
7216
  if (mountedRef.current) setBotBusy(botId, null);
7113
7217
  }
7114
7218
  }, [invoke, loadStatus, mergeSnapshot, setBotBusy, setBotError, workspaceFence]);
7115
- const saveBotSetting = React14.useCallback(async (connection, operation, endpoint, payload) => {
7219
+ const saveBotSetting = React15.useCallback(async (connection, operation, endpoint, payload) => {
7116
7220
  const { botId } = connection;
7117
7221
  const snapshotVersion = workspaceFence.beginMutation();
7118
7222
  setBotBusy(botId, operation);
@@ -7131,15 +7235,15 @@ function FeishuSettingsTab({ rpcCall }) {
7131
7235
  if (mountedRef.current) setBotBusy(botId, null);
7132
7236
  }
7133
7237
  }, [invoke, loadStatus, mergeSnapshot, setBotBusy, setBotError, workspaceFence]);
7134
- const requestRemove = React14.useCallback((connection) => {
7238
+ const requestRemove = React15.useCallback((connection) => {
7135
7239
  setRemoveTargetId(connection.botId);
7136
7240
  }, []);
7137
- const cancelRemove = React14.useCallback(() => {
7241
+ const cancelRemove = React15.useCallback(() => {
7138
7242
  const botId = removeTargetId;
7139
7243
  setRemoveTargetId(null);
7140
7244
  scheduleAnimationFrame(() => removeButtonRefs.current.get(botId)?.focus(), "focus");
7141
7245
  }, [removeTargetId, scheduleAnimationFrame]);
7142
- const confirmRemove = React14.useCallback(async (connection) => {
7246
+ const confirmRemove = React15.useCallback(async (connection) => {
7143
7247
  const { botId, bot } = connection;
7144
7248
  const snapshotVersion = workspaceFence.beginMutation();
7145
7249
  setBotBusy(botId, "delete");
@@ -7225,11 +7329,11 @@ function FeishuSettingsTab({ rpcCall }) {
7225
7329
  setCredentialError(null);
7226
7330
  }
7227
7331
  }) : null;
7228
- const setCardRef = React14.useCallback((botId, node) => {
7332
+ const setCardRef = React15.useCallback((botId, node) => {
7229
7333
  if (node) cardRefs.current.set(botId, node);
7230
7334
  else cardRefs.current.delete(botId);
7231
7335
  }, []);
7232
- const setRemoveButtonRef = React14.useCallback((botId, node) => {
7336
+ const setRemoveButtonRef = React15.useCallback((botId, node) => {
7233
7337
  if (node) removeButtonRefs.current.set(botId, node);
7234
7338
  else removeButtonRefs.current.delete(botId);
7235
7339
  }, []);
@@ -7270,7 +7374,7 @@ function FeishuSettingsTab({ rpcCall }) {
7270
7374
  onRetry: () => void loadStatus(),
7271
7375
  busy: pageBusy
7272
7376
  }) : h2(
7273
- React14.Fragment,
7377
+ React15.Fragment,
7274
7378
  null,
7275
7379
  credentialContent,
7276
7380
  targetedProvisioning ? null : provisionContent,
@@ -8027,7 +8131,7 @@ function formatRemaining3(milliseconds) {
8027
8131
  }
8028
8132
 
8029
8133
  // plugin-src/client/channels/qq/index.js
8030
- var React15 = __toESM(require("react"), 1);
8134
+ var React16 = __toESM(require("react"), 1);
8031
8135
 
8032
8136
  // plugin-src/client/channels/qq/styles.js
8033
8137
  var QQ_STYLE_ID = "xmanrui-dsh-im-qq-settings";
@@ -8052,7 +8156,7 @@ function installQqStyles() {
8052
8156
 
8053
8157
  // plugin-src/client/channels/qq/index.js
8054
8158
  var ACTIVE_STATES = /* @__PURE__ */ new Set(["pending", "refreshing", "connecting"]);
8055
- var Button7 = React15.forwardRef(function Button8({ children, kind = "secondary", className = "", ...props }, ref) {
8159
+ var Button7 = React16.forwardRef(function Button8({ children, kind = "secondary", className = "", ...props }, ref) {
8056
8160
  return h2("button", {
8057
8161
  ...props,
8058
8162
  ref,
@@ -8283,81 +8387,96 @@ function AccountCard2({
8283
8387
  "div",
8284
8388
  { className: "ddt-cardBody dim-botCardBody" },
8285
8389
  h2(
8286
- "div",
8287
- { className: "ddt-accountTop dim-botCardTop" },
8288
- h2(
8289
- "div",
8290
- { className: "ddt-accountIdentity dim-botIdentity" },
8291
- h2("div", { className: "ddt-avatar dim-botAvatar dqq-avatar", "aria-hidden": "true" }, h2(QqLogoGlyph, { size: 29 })),
8292
- h2(
8390
+ CollapsibleAccountSection,
8391
+ {
8392
+ id: `qq-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, "-")}`,
8393
+ header: h2(
8293
8394
  "div",
8294
- { className: "dim-botName" },
8295
- h2("h3", null, account.bot.name),
8296
- h2("p", null, account.bot.appIdMasked)
8395
+ { className: "ddt-accountTop dim-botCardTop" },
8396
+ h2(
8397
+ "div",
8398
+ { className: "ddt-accountIdentity dim-botIdentity" },
8399
+ h2("div", { className: "ddt-avatar dim-botAvatar dqq-avatar", "aria-hidden": "true" }, h2(QqLogoGlyph, { size: 29 })),
8400
+ h2(
8401
+ "div",
8402
+ { className: "dim-botName" },
8403
+ h2("h3", null, account.bot.name),
8404
+ h2("p", null, account.bot.appIdMasked)
8405
+ )
8406
+ ),
8407
+ h2(
8408
+ "div",
8409
+ {
8410
+ className: "dim-botCardTools",
8411
+ // The header is the collapse toggle; keep inner controls clickable.
8412
+ onClick: (event) => {
8413
+ event.stopPropagation();
8414
+ },
8415
+ onKeyDown: (event) => {
8416
+ if (event.key === "Enter" || event.key === " ") event.stopPropagation();
8417
+ }
8418
+ },
8419
+ h2(BotStatusMeta, {
8420
+ className: "ddt-health",
8421
+ dotClassName: "ddt-dot",
8422
+ tone,
8423
+ stateLabel: stateLabel2,
8424
+ lastCheckedAt: account.health.lastCheckedAt,
8425
+ formatCheckedTime: checkedTime3
8426
+ }),
8427
+ h2(BotSettingsButton, {
8428
+ channel: "qq",
8429
+ botId: account.botId,
8430
+ botName: account.bot.name,
8431
+ connected: account.connected,
8432
+ accessPolicy: account.accessPolicy
8433
+ })
8434
+ )
8297
8435
  )
8298
- ),
8299
- h2(
8300
- "div",
8301
- { className: "dim-botCardTools" },
8302
- h2(BotStatusMeta, {
8303
- className: "ddt-health",
8304
- dotClassName: "ddt-dot",
8305
- tone,
8306
- stateLabel: stateLabel2,
8307
- lastCheckedAt: account.health.lastCheckedAt,
8308
- formatCheckedTime: checkedTime3
8309
- }),
8310
- h2(BotSettingsButton, {
8311
- channel: "qq",
8312
- botId: account.botId,
8313
- botName: account.bot.name,
8314
- connected: account.connected,
8315
- accessPolicy: account.accessPolicy
8316
- })
8317
- )
8318
- ),
8319
- h2(WorkspaceEditor, {
8320
- workspace: account.workspace,
8321
- disabled: Boolean(busy),
8322
- onSave: onWorkspaceSave
8323
- }),
8324
- h2(ModelEditor, {
8325
- model: account.model,
8326
- disabled: Boolean(busy),
8327
- onSave: onModelSave
8328
- }),
8329
- h2(AgentPresetEditor, {
8330
- agentPreset: account.agentPreset,
8331
- disabled: Boolean(busy),
8332
- onSave: onAgentPresetSave
8333
- }),
8334
- h2(ContextEnhancementEditor, {
8335
- config: account.contextEnhancement,
8336
- disabled: Boolean(busy),
8337
- onSave: onContextEnhancementSave
8338
- }),
8339
- h2(
8340
- "div",
8341
- { className: "ddt-accountFooter dim-cardFooter" },
8436
+ },
8437
+ h2(WorkspaceEditor, {
8438
+ workspace: account.workspace,
8439
+ disabled: Boolean(busy),
8440
+ onSave: onWorkspaceSave
8441
+ }),
8442
+ h2(ModelEditor, {
8443
+ model: account.model,
8444
+ disabled: Boolean(busy),
8445
+ onSave: onModelSave
8446
+ }),
8447
+ h2(AgentPresetEditor, {
8448
+ agentPreset: account.agentPreset,
8449
+ disabled: Boolean(busy),
8450
+ onSave: onAgentPresetSave
8451
+ }),
8452
+ h2(ContextEnhancementEditor, {
8453
+ config: account.contextEnhancement,
8454
+ disabled: Boolean(busy),
8455
+ onSave: onContextEnhancementSave
8456
+ }),
8342
8457
  h2(
8343
8458
  "div",
8344
- { className: "dim-cardFooterLayout" },
8459
+ { className: "ddt-accountFooter dim-cardFooter" },
8345
8460
  h2(
8346
8461
  "div",
8347
- { className: "ddt-actions dim-cardActions" },
8348
- h2(Button7, { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
8349
- h2(Button7, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
8350
- ),
8351
- summary2 ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary2) : null,
8352
- account.lastMessageError ? h2(LastMessageErrorSummary, {
8353
- className: "ddt-summary",
8354
- error: account.lastMessageError
8355
- }) : null,
8356
- feedback ? h2("div", {
8357
- className: "ddt-summary dim-cardFeedback",
8358
- role: "status",
8359
- "aria-live": "polite"
8360
- }, feedback) : null
8462
+ { className: "dim-cardFooterLayout" },
8463
+ h2(
8464
+ "div",
8465
+ { className: "ddt-actions dim-cardActions" },
8466
+ h2(Button7, { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
8467
+ h2(Button7, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
8468
+ ),
8469
+ summary2 ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary2) : null,
8470
+ account.lastMessageError ? h2(LastMessageErrorSummary, {
8471
+ className: "ddt-summary",
8472
+ error: account.lastMessageError
8473
+ }) : null,
8474
+ feedback ? h2("div", {
8475
+ className: "ddt-summary dim-cardFeedback",
8476
+ role: "status",
8477
+ "aria-live": "polite"
8478
+ }, feedback) : null
8479
+ )
8361
8480
  )
8362
8481
  )
8363
8482
  ),
@@ -8370,7 +8489,7 @@ function AccountCard2({
8370
8489
  );
8371
8490
  }
8372
8491
  function QqSettingsTab({ rpcCall }) {
8373
- const [model, setModel] = React15.useState({
8492
+ const [model, setModel] = React16.useState({
8374
8493
  phase: "loading",
8375
8494
  bots: [],
8376
8495
  totals: { configured: 0, connected: 0 },
@@ -8378,18 +8497,18 @@ function QqSettingsTab({ rpcCall }) {
8378
8497
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG,
8379
8498
  modelCatalog: EMPTY_MODEL_CATALOG
8380
8499
  });
8381
- const [provision, setProvision] = React15.useState(null);
8382
- const [busy, setBusy] = React15.useState(false);
8383
- const [busyByBot, setBusyByBot] = React15.useState({});
8384
- const [feedbackByBot, setFeedbackByBot] = React15.useState({});
8385
- const [removeTarget, setRemoveTarget] = React15.useState(null);
8386
- const [credentialOpen, setCredentialOpen] = React15.useState(false);
8387
- const [credentialError, setCredentialError] = React15.useState(null);
8388
- const [now, setNow] = React15.useState(Date.now());
8389
- const mounted = React15.useRef(true);
8500
+ const [provision, setProvision] = React16.useState(null);
8501
+ const [busy, setBusy] = React16.useState(false);
8502
+ const [busyByBot, setBusyByBot] = React16.useState({});
8503
+ const [feedbackByBot, setFeedbackByBot] = React16.useState({});
8504
+ const [removeTarget, setRemoveTarget] = React16.useState(null);
8505
+ const [credentialOpen, setCredentialOpen] = React16.useState(false);
8506
+ const [credentialError, setCredentialError] = React16.useState(null);
8507
+ const [now, setNow] = React16.useState(Date.now());
8508
+ const mounted = React16.useRef(true);
8390
8509
  const workspaceFence = useWorkspaceSnapshotFence();
8391
- const addButtonRef = React15.useRef(null);
8392
- React15.useEffect(() => {
8510
+ const addButtonRef = React16.useRef(null);
8511
+ React16.useEffect(() => {
8393
8512
  const disposeDingtalk = installDingtalkStyles();
8394
8513
  const disposeQq = installQqStyles();
8395
8514
  mounted.current = true;
@@ -8399,11 +8518,11 @@ function QqSettingsTab({ rpcCall }) {
8399
8518
  disposeDingtalk();
8400
8519
  };
8401
8520
  }, []);
8402
- const invoke = React15.useCallback(async (endpoint, payload = {}, signal) => {
8521
+ const invoke = React16.useCallback(async (endpoint, payload = {}, signal) => {
8403
8522
  if (typeof rpcCall !== "function") throw new TypeError("QQ \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
8404
8523
  return unwrapRpcResult4(await rpcCall(endpoint, payload, signal));
8405
8524
  }, [rpcCall]);
8406
- const loadStatus = React15.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
8525
+ const loadStatus = React16.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
8407
8526
  const workspaceVersion = workspaceFence.beginStatus();
8408
8527
  if (workspaceVersion === null) return void 0;
8409
8528
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
@@ -8430,12 +8549,12 @@ function QqSettingsTab({ rpcCall }) {
8430
8549
  return void 0;
8431
8550
  }
8432
8551
  }, [invoke, workspaceFence]);
8433
- React15.useEffect(() => {
8552
+ React16.useEffect(() => {
8434
8553
  const controller = new AbortController();
8435
8554
  void loadStatus({ signal: controller.signal, restore: true });
8436
8555
  return () => controller.abort();
8437
8556
  }, [loadStatus]);
8438
- React15.useEffect(() => {
8557
+ React16.useEffect(() => {
8439
8558
  if (model.phase !== "ready") return void 0;
8440
8559
  const controller = new AbortController();
8441
8560
  const timer = window.setInterval(() => void loadStatus({ signal: controller.signal, silent: true }), 15e3);
@@ -8444,12 +8563,12 @@ function QqSettingsTab({ rpcCall }) {
8444
8563
  window.clearInterval(timer);
8445
8564
  };
8446
8565
  }, [loadStatus, model.phase]);
8447
- React15.useEffect(() => {
8566
+ React16.useEffect(() => {
8448
8567
  if (!provision || !ACTIVE_STATES.has(provision.status)) return void 0;
8449
8568
  const timer = window.setInterval(() => mounted.current && setNow(Date.now()), 1e3);
8450
8569
  return () => window.clearInterval(timer);
8451
8570
  }, [provision?.attemptId, provision?.status]);
8452
- const startProvisioning = React15.useCallback(async (replace = false) => {
8571
+ const startProvisioning = React16.useCallback(async (replace = false) => {
8453
8572
  setCredentialOpen(false);
8454
8573
  setCredentialError(null);
8455
8574
  setBusy(true);
@@ -8467,7 +8586,7 @@ function QqSettingsTab({ rpcCall }) {
8467
8586
  if (mounted.current) setBusy(false);
8468
8587
  }
8469
8588
  }, [invoke, provision?.attemptId]);
8470
- const bindCredentials = React15.useCallback(async ({ identity, secret }) => {
8589
+ const bindCredentials = React16.useCallback(async ({ identity, secret }) => {
8471
8590
  const snapshotVersion = workspaceFence.beginMutation();
8472
8591
  setBusy(true);
8473
8592
  setCredentialError(null);
@@ -8496,7 +8615,7 @@ function QqSettingsTab({ rpcCall }) {
8496
8615
  if (mounted.current) setBusy(false);
8497
8616
  }
8498
8617
  }, [invoke, loadStatus, workspaceFence]);
8499
- const closeProvision = React15.useCallback(async () => {
8618
+ const closeProvision = React16.useCallback(async () => {
8500
8619
  setBusy(true);
8501
8620
  try {
8502
8621
  if (provision?.attemptId && ACTIVE_STATES.has(provision.status)) {
@@ -8507,7 +8626,7 @@ function QqSettingsTab({ rpcCall }) {
8507
8626
  if (mounted.current) setBusy(false);
8508
8627
  }
8509
8628
  }, [invoke, provision?.attemptId, provision?.status]);
8510
- React15.useEffect(() => {
8629
+ React16.useEffect(() => {
8511
8630
  const attemptId = provision?.attemptId;
8512
8631
  if (!attemptId || !ACTIVE_STATES.has(provision.status)) return void 0;
8513
8632
  const controller = new AbortController();
@@ -8537,7 +8656,7 @@ function QqSettingsTab({ rpcCall }) {
8537
8656
  window.clearTimeout(timer);
8538
8657
  };
8539
8658
  }, [invoke, loadStatus, provision?.attemptId, provision?.pollIntervalMs, provision?.status]);
8540
- const botAction = React15.useCallback(async (account, operation, endpoint, payload) => {
8659
+ const botAction = React16.useCallback(async (account, operation, endpoint, payload) => {
8541
8660
  const snapshotVersion = workspaceFence.beginMutation();
8542
8661
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
8543
8662
  try {
@@ -8563,7 +8682,7 @@ function QqSettingsTab({ rpcCall }) {
8563
8682
  });
8564
8683
  }
8565
8684
  }, [invoke, loadStatus, workspaceFence]);
8566
- const reconnect = React15.useCallback(async (account) => {
8685
+ const reconnect = React16.useCallback(async (account) => {
8567
8686
  setFeedbackByBot((current) => {
8568
8687
  const next = { ...current };
8569
8688
  delete next[account.botId];
@@ -8686,7 +8805,7 @@ function QqSettingsTab({ rpcCall }) {
8686
8805
  addButtonRef
8687
8806
  }),
8688
8807
  model.phase === "loading" ? h2(LoadingView3) : model.phase === "error" ? h2("div", { className: "ddt-card dim-surfaceCard" }, h2("div", { className: "ddt-inlineError dim-inlineError" }, h2("h3", null, "\u65E0\u6CD5\u8BFB\u53D6 QQ \u673A\u5668\u4EBA\u72B6\u6001"), h2("p", null, model.error?.message), h2(Button7, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6"))) : h2(
8689
- React15.Fragment,
8808
+ React16.Fragment,
8690
8809
  null,
8691
8810
  credentialView,
8692
8811
  provisionView,
@@ -8775,7 +8894,7 @@ function normalizeOfficeStatus(value) {
8775
8894
  }
8776
8895
 
8777
8896
  // plugin-src/client/channels/office/index.js
8778
- var React16 = __toESM(require("react"), 1);
8897
+ var React17 = __toESM(require("react"), 1);
8779
8898
  function Button9({ children, kind = "secondary", ...props }) {
8780
8899
  return h2("button", { ...props, type: "button", className: "ddt-button", "data-kind": kind }, children);
8781
8900
  }
@@ -8804,12 +8923,12 @@ function stateLabel(model) {
8804
8923
  return "\u5DF2\u914D\u7F6E";
8805
8924
  }
8806
8925
  function OfficeSettingsTab({ rpcCall, initialStatus }) {
8807
- const [model, setModel] = React16.useState(normalizeOfficeStatus(initialStatus));
8808
- const [phase, setPhase] = React16.useState(initialStatus === void 0 ? "loading" : "ready");
8809
- const [busy, setBusy] = React16.useState("");
8810
- const [error, setError] = React16.useState("");
8811
- const [notice, setNotice] = React16.useState("");
8812
- const [form, setForm] = React16.useState({
8926
+ const [model, setModel] = React17.useState(normalizeOfficeStatus(initialStatus));
8927
+ const [phase, setPhase] = React17.useState(initialStatus === void 0 ? "loading" : "ready");
8928
+ const [busy, setBusy] = React17.useState("");
8929
+ const [error, setError] = React17.useState("");
8930
+ const [notice, setNotice] = React17.useState("");
8931
+ const [form, setForm] = React17.useState({
8813
8932
  baseUrl: "",
8814
8933
  deviceId: "local-harness",
8815
8934
  deviceToken: "",
@@ -8818,11 +8937,11 @@ function OfficeSettingsTab({ rpcCall, initialStatus }) {
8818
8937
  workspaces: "",
8819
8938
  instructionPresets: ""
8820
8939
  });
8821
- const invoke = React16.useCallback(async (endpoint, payload = {}) => {
8940
+ const invoke = React17.useCallback(async (endpoint, payload = {}) => {
8822
8941
  if (typeof rpcCall !== "function") throw new Error("AI Office \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
8823
8942
  return unwrapOfficeRpc(await rpcCall(endpoint, payload));
8824
8943
  }, [rpcCall]);
8825
- const adopt = React16.useCallback((value) => {
8944
+ const adopt = React17.useCallback((value) => {
8826
8945
  const next = normalizeOfficeStatus(value?.snapshot ?? value);
8827
8946
  setModel(next);
8828
8947
  if (next.config) setForm((current) => ({
@@ -8837,7 +8956,7 @@ function OfficeSettingsTab({ rpcCall, initialStatus }) {
8837
8956
  }));
8838
8957
  return next;
8839
8958
  }, []);
8840
- const load = React16.useCallback(async () => {
8959
+ const load = React17.useCallback(async () => {
8841
8960
  try {
8842
8961
  adopt(await invoke(OFFICE_RPC_ENDPOINTS.status));
8843
8962
  setPhase("ready");
@@ -8847,7 +8966,7 @@ function OfficeSettingsTab({ rpcCall, initialStatus }) {
8847
8966
  setError(caught.message);
8848
8967
  }
8849
8968
  }, [adopt, invoke]);
8850
- React16.useEffect(() => {
8969
+ React17.useEffect(() => {
8851
8970
  void load();
8852
8971
  }, [load]);
8853
8972
  const run = async (name2, operation) => {
@@ -8864,7 +8983,7 @@ function OfficeSettingsTab({ rpcCall, initialStatus }) {
8864
8983
  setBusy("");
8865
8984
  }
8866
8985
  };
8867
- const hooks = React16.useMemo(() => {
8986
+ const hooks = React17.useMemo(() => {
8868
8987
  try {
8869
8988
  return officeHookUrls(form.baseUrl);
8870
8989
  } catch {
@@ -9049,7 +9168,7 @@ var normalizeSnapshot4 = api2.normalizeSnapshot;
9049
9168
  var presentError5 = api2.presentError;
9050
9169
 
9051
9170
  // plugin-src/client/channels/slack/index.js
9052
- var React17 = __toESM(require("react"), 1);
9171
+ var React18 = __toESM(require("react"), 1);
9053
9172
 
9054
9173
  // src/channels/slack/manifest.mjs
9055
9174
  var SLACK_APP_MANIFEST_YAML = `_metadata:
@@ -9127,10 +9246,10 @@ function installSlackStyles() {
9127
9246
 
9128
9247
  // plugin-src/client/channels/slack/index.js
9129
9248
  function SlackCredentialPanel({ busy, error, onSubmit, onCancel }) {
9130
- const [botToken, setBotToken] = React17.useState("");
9131
- const [appToken, setAppToken] = React17.useState("");
9132
- const [copied, setCopied] = React17.useState(false);
9133
- const headingId = React17.useId();
9249
+ const [botToken, setBotToken] = React18.useState("");
9250
+ const [appToken, setAppToken] = React18.useState("");
9251
+ const [copied, setCopied] = React18.useState(false);
9252
+ const headingId = React18.useId();
9134
9253
  const copyManifest = async () => {
9135
9254
  try {
9136
9255
  await navigator.clipboard.writeText(SLACK_APP_MANIFEST_YAML);
@@ -9443,7 +9562,7 @@ function formatRemaining4(milliseconds) {
9443
9562
  }
9444
9563
 
9445
9564
  // plugin-src/client/channels/wecom/index.js
9446
- var React18 = __toESM(require("react"), 1);
9565
+ var React19 = __toESM(require("react"), 1);
9447
9566
 
9448
9567
  // plugin-src/client/channels/wecom/styles.js
9449
9568
  var WECOM_STYLE_ID = "xmanrui-dsh-im-wecom-settings";
@@ -9468,7 +9587,7 @@ function installWecomStyles() {
9468
9587
 
9469
9588
  // plugin-src/client/channels/wecom/index.js
9470
9589
  var ACTIVE_STATES2 = /* @__PURE__ */ new Set(["pending", "refreshing", "connecting"]);
9471
- var Button10 = React18.forwardRef(function Button11({ children, kind = "secondary", className = "", ...props }, ref) {
9590
+ var Button10 = React19.forwardRef(function Button11({ children, kind = "secondary", className = "", ...props }, ref) {
9472
9591
  return h2("button", {
9473
9592
  ...props,
9474
9593
  ref,
@@ -9699,81 +9818,96 @@ function AccountCard3({
9699
9818
  "div",
9700
9819
  { className: "ddt-cardBody dim-botCardBody" },
9701
9820
  h2(
9702
- "div",
9703
- { className: "ddt-accountTop dim-botCardTop" },
9704
- h2(
9705
- "div",
9706
- { className: "ddt-accountIdentity dim-botIdentity" },
9707
- h2("div", { className: "ddt-avatar dim-botAvatar dwecom-avatar", "aria-hidden": "true" }, h2(WecomLogoGlyph, { size: 29 })),
9708
- h2(
9821
+ CollapsibleAccountSection,
9822
+ {
9823
+ id: `wec-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, "-")}`,
9824
+ header: h2(
9709
9825
  "div",
9710
- { className: "dim-botName" },
9711
- h2("h3", null, account.bot.name),
9712
- h2("p", null, account.bot.appIdMasked)
9826
+ { className: "ddt-accountTop dim-botCardTop" },
9827
+ h2(
9828
+ "div",
9829
+ { className: "ddt-accountIdentity dim-botIdentity" },
9830
+ h2("div", { className: "ddt-avatar dim-botAvatar dwecom-avatar", "aria-hidden": "true" }, h2(WecomLogoGlyph, { size: 29 })),
9831
+ h2(
9832
+ "div",
9833
+ { className: "dim-botName" },
9834
+ h2("h3", null, account.bot.name),
9835
+ h2("p", null, account.bot.appIdMasked)
9836
+ )
9837
+ ),
9838
+ h2(
9839
+ "div",
9840
+ {
9841
+ className: "dim-botCardTools",
9842
+ // The header is the collapse toggle; keep inner controls clickable.
9843
+ onClick: (event) => {
9844
+ event.stopPropagation();
9845
+ },
9846
+ onKeyDown: (event) => {
9847
+ if (event.key === "Enter" || event.key === " ") event.stopPropagation();
9848
+ }
9849
+ },
9850
+ h2(BotStatusMeta, {
9851
+ className: "ddt-health",
9852
+ dotClassName: "ddt-dot",
9853
+ tone,
9854
+ stateLabel: stateLabel2,
9855
+ lastCheckedAt: account.health.lastCheckedAt,
9856
+ formatCheckedTime: checkedTime4
9857
+ }),
9858
+ h2(BotSettingsButton, {
9859
+ channel: "wecom",
9860
+ botId: account.botId,
9861
+ botName: account.bot.name,
9862
+ connected: account.connected,
9863
+ accessPolicy: account.accessPolicy
9864
+ })
9865
+ )
9713
9866
  )
9714
- ),
9715
- h2(
9716
- "div",
9717
- { className: "dim-botCardTools" },
9718
- h2(BotStatusMeta, {
9719
- className: "ddt-health",
9720
- dotClassName: "ddt-dot",
9721
- tone,
9722
- stateLabel: stateLabel2,
9723
- lastCheckedAt: account.health.lastCheckedAt,
9724
- formatCheckedTime: checkedTime4
9725
- }),
9726
- h2(BotSettingsButton, {
9727
- channel: "wecom",
9728
- botId: account.botId,
9729
- botName: account.bot.name,
9730
- connected: account.connected,
9731
- accessPolicy: account.accessPolicy
9732
- })
9733
- )
9734
- ),
9735
- h2(WorkspaceEditor, {
9736
- workspace: account.workspace,
9737
- disabled: Boolean(busy),
9738
- onSave: onWorkspaceSave
9739
- }),
9740
- h2(ModelEditor, {
9741
- model: account.model,
9742
- disabled: Boolean(busy),
9743
- onSave: onModelSave
9744
- }),
9745
- h2(AgentPresetEditor, {
9746
- agentPreset: account.agentPreset,
9747
- disabled: Boolean(busy),
9748
- onSave: onAgentPresetSave
9749
- }),
9750
- h2(ContextEnhancementEditor, {
9751
- config: account.contextEnhancement,
9752
- disabled: Boolean(busy),
9753
- onSave: onContextEnhancementSave
9754
- }),
9755
- h2(
9756
- "div",
9757
- { className: "ddt-accountFooter dim-cardFooter" },
9867
+ },
9868
+ h2(WorkspaceEditor, {
9869
+ workspace: account.workspace,
9870
+ disabled: Boolean(busy),
9871
+ onSave: onWorkspaceSave
9872
+ }),
9873
+ h2(ModelEditor, {
9874
+ model: account.model,
9875
+ disabled: Boolean(busy),
9876
+ onSave: onModelSave
9877
+ }),
9878
+ h2(AgentPresetEditor, {
9879
+ agentPreset: account.agentPreset,
9880
+ disabled: Boolean(busy),
9881
+ onSave: onAgentPresetSave
9882
+ }),
9883
+ h2(ContextEnhancementEditor, {
9884
+ config: account.contextEnhancement,
9885
+ disabled: Boolean(busy),
9886
+ onSave: onContextEnhancementSave
9887
+ }),
9758
9888
  h2(
9759
9889
  "div",
9760
- { className: "dim-cardFooterLayout" },
9890
+ { className: "ddt-accountFooter dim-cardFooter" },
9761
9891
  h2(
9762
9892
  "div",
9763
- { className: "ddt-actions dim-cardActions" },
9764
- h2(Button10, { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
9765
- h2(Button10, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
9766
- ),
9767
- summary2 ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary2) : null,
9768
- account.lastMessageError ? h2(LastMessageErrorSummary, {
9769
- className: "ddt-summary",
9770
- error: account.lastMessageError
9771
- }) : null,
9772
- feedback ? h2("div", {
9773
- className: "ddt-summary dim-cardFeedback",
9774
- role: "status",
9775
- "aria-live": "polite"
9776
- }, feedback) : null
9893
+ { className: "dim-cardFooterLayout" },
9894
+ h2(
9895
+ "div",
9896
+ { className: "ddt-actions dim-cardActions" },
9897
+ h2(Button10, { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
9898
+ h2(Button10, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
9899
+ ),
9900
+ summary2 ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary2) : null,
9901
+ account.lastMessageError ? h2(LastMessageErrorSummary, {
9902
+ className: "ddt-summary",
9903
+ error: account.lastMessageError
9904
+ }) : null,
9905
+ feedback ? h2("div", {
9906
+ className: "ddt-summary dim-cardFeedback",
9907
+ role: "status",
9908
+ "aria-live": "polite"
9909
+ }, feedback) : null
9910
+ )
9777
9911
  )
9778
9912
  )
9779
9913
  ),
@@ -9786,7 +9920,7 @@ function AccountCard3({
9786
9920
  );
9787
9921
  }
9788
9922
  function WecomSettingsTab({ rpcCall }) {
9789
- const [model, setModel] = React18.useState({
9923
+ const [model, setModel] = React19.useState({
9790
9924
  phase: "loading",
9791
9925
  bots: [],
9792
9926
  totals: { configured: 0, connected: 0 },
@@ -9794,20 +9928,20 @@ function WecomSettingsTab({ rpcCall }) {
9794
9928
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG,
9795
9929
  modelCatalog: EMPTY_MODEL_CATALOG
9796
9930
  });
9797
- const [provision, setProvision] = React18.useState(null);
9798
- const [busy, setBusy] = React18.useState(false);
9799
- const [busyByBot, setBusyByBot] = React18.useState({});
9800
- const [feedbackByBot, setFeedbackByBot] = React18.useState({});
9801
- const [removeTarget, setRemoveTarget] = React18.useState(null);
9802
- const [credentialOpen, setCredentialOpen] = React18.useState(false);
9803
- const [credentialError, setCredentialError] = React18.useState(null);
9804
- const [notice, setNotice] = React18.useState("");
9805
- const [now, setNow] = React18.useState(Date.now());
9806
- const mounted = React18.useRef(true);
9931
+ const [provision, setProvision] = React19.useState(null);
9932
+ const [busy, setBusy] = React19.useState(false);
9933
+ const [busyByBot, setBusyByBot] = React19.useState({});
9934
+ const [feedbackByBot, setFeedbackByBot] = React19.useState({});
9935
+ const [removeTarget, setRemoveTarget] = React19.useState(null);
9936
+ const [credentialOpen, setCredentialOpen] = React19.useState(false);
9937
+ const [credentialError, setCredentialError] = React19.useState(null);
9938
+ const [notice, setNotice] = React19.useState("");
9939
+ const [now, setNow] = React19.useState(Date.now());
9940
+ const mounted = React19.useRef(true);
9807
9941
  const workspaceFence = useWorkspaceSnapshotFence();
9808
- const addButtonRef = React18.useRef(null);
9809
- const noticeFrameRef = React18.useRef(null);
9810
- const announce = React18.useCallback((message) => {
9942
+ const addButtonRef = React19.useRef(null);
9943
+ const noticeFrameRef = React19.useRef(null);
9944
+ const announce = React19.useCallback((message) => {
9811
9945
  if (!mounted.current) return;
9812
9946
  if (noticeFrameRef.current !== null) {
9813
9947
  window.cancelAnimationFrame(noticeFrameRef.current);
@@ -9821,7 +9955,7 @@ function WecomSettingsTab({ rpcCall }) {
9821
9955
  });
9822
9956
  }
9823
9957
  }, []);
9824
- React18.useEffect(() => {
9958
+ React19.useEffect(() => {
9825
9959
  const disposeDingtalk = installDingtalkStyles();
9826
9960
  const disposeWecom = installWecomStyles();
9827
9961
  mounted.current = true;
@@ -9835,11 +9969,11 @@ function WecomSettingsTab({ rpcCall }) {
9835
9969
  disposeDingtalk();
9836
9970
  };
9837
9971
  }, []);
9838
- const invoke = React18.useCallback(async (endpoint, payload = {}, signal) => {
9972
+ const invoke = React19.useCallback(async (endpoint, payload = {}, signal) => {
9839
9973
  if (typeof rpcCall !== "function") throw new TypeError("\u4F01\u4E1A\u5FAE\u4FE1\u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
9840
9974
  return unwrapRpcResult7(await rpcCall(endpoint, payload, signal));
9841
9975
  }, [rpcCall]);
9842
- const loadStatus = React18.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
9976
+ const loadStatus = React19.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
9843
9977
  const workspaceVersion = workspaceFence.beginStatus();
9844
9978
  if (workspaceVersion === null) return void 0;
9845
9979
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
@@ -9866,12 +10000,12 @@ function WecomSettingsTab({ rpcCall }) {
9866
10000
  return void 0;
9867
10001
  }
9868
10002
  }, [invoke, workspaceFence]);
9869
- React18.useEffect(() => {
10003
+ React19.useEffect(() => {
9870
10004
  const controller = new AbortController();
9871
10005
  void loadStatus({ signal: controller.signal, restore: true });
9872
10006
  return () => controller.abort();
9873
10007
  }, [loadStatus]);
9874
- React18.useEffect(() => {
10008
+ React19.useEffect(() => {
9875
10009
  if (model.phase !== "ready") return void 0;
9876
10010
  const controller = new AbortController();
9877
10011
  const timer = window.setInterval(() => void loadStatus({ signal: controller.signal, silent: true }), 15e3);
@@ -9880,12 +10014,12 @@ function WecomSettingsTab({ rpcCall }) {
9880
10014
  window.clearInterval(timer);
9881
10015
  };
9882
10016
  }, [loadStatus, model.phase]);
9883
- React18.useEffect(() => {
10017
+ React19.useEffect(() => {
9884
10018
  if (!provision || !ACTIVE_STATES2.has(provision.status)) return void 0;
9885
10019
  const timer = window.setInterval(() => mounted.current && setNow(Date.now()), 1e3);
9886
10020
  return () => window.clearInterval(timer);
9887
10021
  }, [provision?.attemptId, provision?.status]);
9888
- const startProvisioning = React18.useCallback(async (replace = false) => {
10022
+ const startProvisioning = React19.useCallback(async (replace = false) => {
9889
10023
  setCredentialOpen(false);
9890
10024
  setCredentialError(null);
9891
10025
  setBusy(true);
@@ -9903,7 +10037,7 @@ function WecomSettingsTab({ rpcCall }) {
9903
10037
  if (mounted.current) setBusy(false);
9904
10038
  }
9905
10039
  }, [invoke, provision?.attemptId]);
9906
- const bindCredentials = React18.useCallback(async ({ identity, secret }) => {
10040
+ const bindCredentials = React19.useCallback(async ({ identity, secret }) => {
9907
10041
  const snapshotVersion = workspaceFence.beginMutation();
9908
10042
  setBusy(true);
9909
10043
  setCredentialError(null);
@@ -9932,7 +10066,7 @@ function WecomSettingsTab({ rpcCall }) {
9932
10066
  if (mounted.current) setBusy(false);
9933
10067
  }
9934
10068
  }, [invoke, loadStatus, workspaceFence]);
9935
- const closeProvision = React18.useCallback(async () => {
10069
+ const closeProvision = React19.useCallback(async () => {
9936
10070
  setBusy(true);
9937
10071
  try {
9938
10072
  if (provision?.attemptId && ACTIVE_STATES2.has(provision.status)) {
@@ -9943,7 +10077,7 @@ function WecomSettingsTab({ rpcCall }) {
9943
10077
  if (mounted.current) setBusy(false);
9944
10078
  }
9945
10079
  }, [invoke, provision?.attemptId, provision?.status]);
9946
- React18.useEffect(() => {
10080
+ React19.useEffect(() => {
9947
10081
  const attemptId = provision?.attemptId;
9948
10082
  if (!attemptId || !ACTIVE_STATES2.has(provision.status)) return void 0;
9949
10083
  const controller = new AbortController();
@@ -9973,7 +10107,7 @@ function WecomSettingsTab({ rpcCall }) {
9973
10107
  window.clearTimeout(timer);
9974
10108
  };
9975
10109
  }, [invoke, loadStatus, provision?.attemptId, provision?.pollIntervalMs, provision?.status]);
9976
- const botAction = React18.useCallback(async (account, operation, endpoint, payload) => {
10110
+ const botAction = React19.useCallback(async (account, operation, endpoint, payload) => {
9977
10111
  const snapshotVersion = workspaceFence.beginMutation();
9978
10112
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
9979
10113
  try {
@@ -9999,7 +10133,7 @@ function WecomSettingsTab({ rpcCall }) {
9999
10133
  });
10000
10134
  }
10001
10135
  }, [invoke, loadStatus, workspaceFence]);
10002
- const reconnect = React18.useCallback(async (account) => {
10136
+ const reconnect = React19.useCallback(async (account) => {
10003
10137
  setFeedbackByBot((current) => {
10004
10138
  const next = { ...current };
10005
10139
  delete next[account.botId];
@@ -10134,7 +10268,7 @@ function WecomSettingsTab({ rpcCall }) {
10134
10268
  }),
10135
10269
  h2("div", { className: "ddt-visuallyHidden", role: "status", "aria-live": "polite" }, notice),
10136
10270
  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(
10137
- React18.Fragment,
10271
+ React19.Fragment,
10138
10272
  null,
10139
10273
  credentialView,
10140
10274
  provisionView,
@@ -10145,7 +10279,7 @@ function WecomSettingsTab({ rpcCall }) {
10145
10279
  }
10146
10280
 
10147
10281
  // plugin-src/client/channels/weixin/index.js
10148
- var React19 = __toESM(require("react"), 1);
10282
+ var React20 = __toESM(require("react"), 1);
10149
10283
 
10150
10284
  // plugin-src/client/channels/weixin/api.js
10151
10285
  var WEIXIN_RPC_CHANNEL = "/weixin";
@@ -10307,7 +10441,7 @@ function formatRemaining5(milliseconds) {
10307
10441
  }
10308
10442
 
10309
10443
  // plugin-src/client/channels/weixin/index.js
10310
- var Button12 = React19.forwardRef(function Button13({ children, kind = "secondary", className = "", ...props }, ref) {
10444
+ var Button12 = React20.forwardRef(function Button13({ children, kind = "secondary", className = "", ...props }, ref) {
10311
10445
  return h2("button", {
10312
10446
  ...props,
10313
10447
  ref,
@@ -10380,14 +10514,14 @@ function EmptyView5({ onStart, busy }) {
10380
10514
  );
10381
10515
  }
10382
10516
  function QrPanel4({ provision, now, busy, onRefresh, onCancel }) {
10383
- const [imageFailed, setImageFailed] = React19.useState(false);
10517
+ const [imageFailed, setImageFailed] = React20.useState(false);
10384
10518
  const source = safeQrSource5(provision.qrCodeDataUrl);
10385
10519
  const href = safeVerificationUrl(provision.verificationUrl);
10386
10520
  const remaining = Math.max(0, provision.expiresAt - now);
10387
10521
  const expired = remaining === 0 || provision.status === "expired";
10388
10522
  const duration = Math.max(1, provision.durationMs ?? 5 * 6e4);
10389
10523
  const progress = Math.round(Math.min(1, remaining / duration) * 100);
10390
- React19.useEffect(() => setImageFailed(false), [source]);
10524
+ React20.useEffect(() => setImageFailed(false), [source]);
10391
10525
  return h2(
10392
10526
  "div",
10393
10527
  { className: "dxw-card dim-surfaceCard" },
@@ -10454,9 +10588,9 @@ function QrPanel4({ provision, now, busy, onRefresh, onCancel }) {
10454
10588
  );
10455
10589
  }
10456
10590
  function VerificationPanel({ provision, busy, onSubmit, onCancel }) {
10457
- const [code, setCode] = React19.useState("");
10591
+ const [code, setCode] = React20.useState("");
10458
10592
  const valid = /^\d{4,8}$/.test(code);
10459
- React19.useEffect(() => setCode(""), [provision.attemptId]);
10593
+ React20.useEffect(() => setCode(""), [provision.attemptId]);
10460
10594
  return h2(
10461
10595
  "div",
10462
10596
  { className: "dxw-card dim-surfaceCard" },
@@ -10555,97 +10689,112 @@ function AccountCard4({
10555
10689
  onReconnect,
10556
10690
  onWorkspaceSave,
10557
10691
  onModelSave,
10558
- onAgentPresetSave,
10559
- onContextEnhancementSave,
10560
- onRequestRemove,
10561
- onConfirmRemove,
10562
- onCancelRemove
10563
- }) {
10564
- const state = busy === "reconnect" ? "connecting" : account.state;
10565
- const tone = account.connected ? "success" : state === "error" ? "error" : "warning";
10566
- const summary2 = account.error?.message ?? (account.connected ? null : account.health.summary);
10567
- return h2(
10568
- "article",
10569
- { className: "dxw-card dim-botCard", tabIndex: -1, "data-bot-id": account.botId },
10570
- h2(
10571
- "div",
10572
- { className: "dxw-cardBody dim-botCardBody" },
10573
- h2(
10574
- "div",
10575
- { className: "dxw-accountTop dim-botCardTop" },
10576
- h2(
10577
- "div",
10578
- { className: "dxw-accountIdentity dim-botIdentity" },
10579
- h2("div", { className: "dxw-avatar dim-botAvatar", "aria-hidden": "true" }, h2(WeixinLogoGlyph, { size: 27 })),
10580
- h2("div", { className: "dim-botName" }, h2("h3", null, account.bot.name), h2("p", null, account.bot.accountIdMasked))
10581
- ),
10582
- h2(
10583
- "div",
10584
- { className: "dim-botCardTools" },
10585
- h2(BotStatusMeta, {
10586
- className: "dxw-health",
10587
- dotClassName: "dxw-dot",
10588
- tone,
10589
- stateLabel: account.connected ? "\u8FD0\u884C\u6B63\u5E38" : state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA",
10590
- lastCheckedAt: account.health.lastCheckedAt,
10591
- formatCheckedTime: checkedTime5
10592
- }),
10593
- h2(BotSettingsButton, {
10594
- channel: "weixin",
10595
- botId: account.botId,
10596
- botName: account.bot.name,
10597
- connected: account.connected,
10598
- accessPolicy: account.accessPolicy
10599
- })
10600
- )
10601
- ),
10602
- h2(WorkspaceEditor, {
10603
- workspace: account.workspace,
10604
- disabled: Boolean(busy),
10605
- onSave: onWorkspaceSave
10606
- }),
10607
- h2(ModelEditor, {
10608
- model: account.model,
10609
- disabled: Boolean(busy),
10610
- onSave: onModelSave
10611
- }),
10612
- h2(AgentPresetEditor, {
10613
- agentPreset: account.agentPreset,
10614
- disabled: Boolean(busy),
10615
- onSave: onAgentPresetSave
10616
- }),
10617
- h2(ContextEnhancementEditor, {
10618
- config: account.contextEnhancement,
10619
- groupSupported: false,
10620
- disabled: Boolean(busy),
10621
- onSave: onContextEnhancementSave
10622
- }),
10692
+ onAgentPresetSave,
10693
+ onContextEnhancementSave,
10694
+ onRequestRemove,
10695
+ onConfirmRemove,
10696
+ onCancelRemove
10697
+ }) {
10698
+ const state = busy === "reconnect" ? "connecting" : account.state;
10699
+ const tone = account.connected ? "success" : state === "error" ? "error" : "warning";
10700
+ const summary2 = account.error?.message ?? (account.connected ? null : account.health.summary);
10701
+ return h2(
10702
+ "article",
10703
+ { className: "dxw-card dim-botCard", tabIndex: -1, "data-bot-id": account.botId },
10704
+ h2(
10705
+ "div",
10706
+ { className: "dxw-cardBody dim-botCardBody" },
10623
10707
  h2(
10624
- "div",
10625
- { className: "dxw-accountFooter dim-cardFooter" },
10708
+ CollapsibleAccountSection,
10709
+ {
10710
+ id: `dxw-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, "-")}`,
10711
+ header: h2(
10712
+ "div",
10713
+ { className: "dxw-accountTop dim-botCardTop" },
10714
+ h2(
10715
+ "div",
10716
+ { className: "dxw-accountIdentity dim-botIdentity" },
10717
+ h2("div", { className: "dxw-avatar dim-botAvatar", "aria-hidden": "true" }, h2(WeixinLogoGlyph, { size: 27 })),
10718
+ h2("div", { className: "dim-botName" }, h2("h3", null, account.bot.name), h2("p", null, account.bot.accountIdMasked))
10719
+ ),
10720
+ h2(
10721
+ "div",
10722
+ {
10723
+ className: "dim-botCardTools",
10724
+ // The header is the collapse toggle; keep inner controls clickable.
10725
+ onClick: (event) => {
10726
+ event.stopPropagation();
10727
+ },
10728
+ onKeyDown: (event) => {
10729
+ if (event.key === "Enter" || event.key === " ") event.stopPropagation();
10730
+ }
10731
+ },
10732
+ h2(BotStatusMeta, {
10733
+ className: "dxw-health",
10734
+ dotClassName: "dxw-dot",
10735
+ tone,
10736
+ stateLabel: account.connected ? "\u8FD0\u884C\u6B63\u5E38" : state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA",
10737
+ lastCheckedAt: account.health.lastCheckedAt,
10738
+ formatCheckedTime: checkedTime5
10739
+ }),
10740
+ h2(BotSettingsButton, {
10741
+ channel: "weixin",
10742
+ botId: account.botId,
10743
+ botName: account.bot.name,
10744
+ connected: account.connected,
10745
+ accessPolicy: account.accessPolicy
10746
+ })
10747
+ )
10748
+ )
10749
+ },
10750
+ h2(WorkspaceEditor, {
10751
+ workspace: account.workspace,
10752
+ disabled: Boolean(busy),
10753
+ onSave: onWorkspaceSave
10754
+ }),
10755
+ h2(ModelEditor, {
10756
+ model: account.model,
10757
+ disabled: Boolean(busy),
10758
+ onSave: onModelSave
10759
+ }),
10760
+ h2(AgentPresetEditor, {
10761
+ agentPreset: account.agentPreset,
10762
+ disabled: Boolean(busy),
10763
+ onSave: onAgentPresetSave
10764
+ }),
10765
+ h2(ContextEnhancementEditor, {
10766
+ config: account.contextEnhancement,
10767
+ groupSupported: false,
10768
+ disabled: Boolean(busy),
10769
+ onSave: onContextEnhancementSave
10770
+ }),
10626
10771
  h2(
10627
10772
  "div",
10628
- { className: "dim-cardFooterLayout" },
10773
+ { className: "dxw-accountFooter dim-cardFooter" },
10629
10774
  h2(
10630
10775
  "div",
10631
- { className: "dxw-actions dim-cardActions" },
10776
+ { className: "dim-cardFooterLayout" },
10632
10777
  h2(
10633
- Button12,
10634
- { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) },
10635
- busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"
10778
+ "div",
10779
+ { className: "dxw-actions dim-cardActions" },
10780
+ h2(
10781
+ Button12,
10782
+ { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) },
10783
+ busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"
10784
+ ),
10785
+ h2(Button12, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
10636
10786
  ),
10637
- h2(Button12, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
10638
- ),
10639
- summary2 ? h2("div", { className: "dxw-summary dim-cardSummary" }, summary2) : null,
10640
- account.lastMessageError ? h2(LastMessageErrorSummary, {
10641
- className: "dxw-summary",
10642
- error: account.lastMessageError
10643
- }) : null,
10644
- feedback ? h2("div", {
10645
- className: "dxw-summary dim-cardFeedback",
10646
- role: "status",
10647
- "aria-live": "polite"
10648
- }, feedback) : null
10787
+ summary2 ? h2("div", { className: "dxw-summary dim-cardSummary" }, summary2) : null,
10788
+ account.lastMessageError ? h2(LastMessageErrorSummary, {
10789
+ className: "dxw-summary",
10790
+ error: account.lastMessageError
10791
+ }) : null,
10792
+ feedback ? h2("div", {
10793
+ className: "dxw-summary dim-cardFeedback",
10794
+ role: "status",
10795
+ "aria-live": "polite"
10796
+ }, feedback) : null
10797
+ )
10649
10798
  )
10650
10799
  )
10651
10800
  ),
@@ -10707,7 +10856,7 @@ function mergeWeixinProvisioningSnapshot(current, incoming, { restoreProvisionin
10707
10856
  };
10708
10857
  }
10709
10858
  function WeixinSettingsTab({ rpcCall }) {
10710
- const [model, setModel] = React19.useState({
10859
+ const [model, setModel] = React20.useState({
10711
10860
  phase: "loading",
10712
10861
  bots: [],
10713
10862
  totals: EMPTY_TOTALS3,
@@ -10716,33 +10865,33 @@ function WeixinSettingsTab({ rpcCall }) {
10716
10865
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG,
10717
10866
  modelCatalog: EMPTY_MODEL_CATALOG
10718
10867
  });
10719
- const [provision, setProvision] = React19.useState(null);
10720
- const [busy, setBusy] = React19.useState(false);
10721
- const [busyByBot, setBusyByBot] = React19.useState({});
10722
- const [feedbackByBot, setFeedbackByBot] = React19.useState({});
10723
- const [removeTarget, setRemoveTarget] = React19.useState(null);
10724
- const [notice, setNotice] = React19.useState("");
10725
- const [now, setNow] = React19.useState(() => Date.now());
10726
- const addButtonRef = React19.useRef(null);
10727
- const mountedRef = React19.useRef(true);
10868
+ const [provision, setProvision] = React20.useState(null);
10869
+ const [busy, setBusy] = React20.useState(false);
10870
+ const [busyByBot, setBusyByBot] = React20.useState({});
10871
+ const [feedbackByBot, setFeedbackByBot] = React20.useState({});
10872
+ const [removeTarget, setRemoveTarget] = React20.useState(null);
10873
+ const [notice, setNotice] = React20.useState("");
10874
+ const [now, setNow] = React20.useState(() => Date.now());
10875
+ const addButtonRef = React20.useRef(null);
10876
+ const mountedRef = React20.useRef(true);
10728
10877
  const workspaceFence = useWorkspaceSnapshotFence();
10729
10878
  const scheduleAnimationFrame = useAnimationFrameScheduler();
10730
- React19.useEffect(() => {
10879
+ React20.useEffect(() => {
10731
10880
  mountedRef.current = true;
10732
10881
  return () => {
10733
10882
  mountedRef.current = false;
10734
10883
  };
10735
10884
  }, []);
10736
- const announce = React19.useCallback((value) => {
10885
+ const announce = React20.useCallback((value) => {
10737
10886
  setNotice("");
10738
10887
  scheduleAnimationFrame(() => {
10739
10888
  if (value) setNotice(value);
10740
10889
  }, "announcement");
10741
10890
  }, [scheduleAnimationFrame]);
10742
- const invoke = React19.useCallback(async (endpoint, payload = {}, signal) => {
10891
+ const invoke = React20.useCallback(async (endpoint, payload = {}, signal) => {
10743
10892
  return unwrapRpcResult8(await rpcCall(endpoint, payload, signal));
10744
10893
  }, [rpcCall]);
10745
- const loadStatus = React19.useCallback(async ({
10894
+ const loadStatus = React20.useCallback(async ({
10746
10895
  signal,
10747
10896
  silent = false,
10748
10897
  restoreProvisioning = false
@@ -10780,12 +10929,12 @@ function WeixinSettingsTab({ rpcCall }) {
10780
10929
  return void 0;
10781
10930
  }
10782
10931
  }, [invoke, workspaceFence]);
10783
- React19.useEffect(() => {
10932
+ React20.useEffect(() => {
10784
10933
  const controller = new AbortController();
10785
10934
  void loadStatus({ signal: controller.signal, restoreProvisioning: true });
10786
10935
  return () => controller.abort();
10787
10936
  }, [loadStatus]);
10788
- React19.useEffect(() => {
10937
+ React20.useEffect(() => {
10789
10938
  if (model.phase !== "ready") return void 0;
10790
10939
  const controller = new AbortController();
10791
10940
  let running = false;
@@ -10804,12 +10953,12 @@ function WeixinSettingsTab({ rpcCall }) {
10804
10953
  window.clearInterval(timer);
10805
10954
  };
10806
10955
  }, [loadStatus, model.phase]);
10807
- React19.useEffect(() => {
10956
+ React20.useEffect(() => {
10808
10957
  if (!provision || !["pending", "scanned"].includes(provision.status)) return void 0;
10809
10958
  const timer = window.setInterval(() => setNow(Date.now()), 1e3);
10810
10959
  return () => window.clearInterval(timer);
10811
10960
  }, [provision?.attemptId, provision?.status]);
10812
- const startProvisioning = React19.useCallback(async ({ replace = false } = {}) => {
10961
+ const startProvisioning = React20.useCallback(async ({ replace = false } = {}) => {
10813
10962
  setBusy(true);
10814
10963
  try {
10815
10964
  if (replace && provision?.attemptId) {
@@ -10830,7 +10979,7 @@ function WeixinSettingsTab({ rpcCall }) {
10830
10979
  setBusy(false);
10831
10980
  }
10832
10981
  }, [announce, invoke, provision?.attemptId]);
10833
- const cancelProvisioning = React19.useCallback(async () => {
10982
+ const cancelProvisioning = React20.useCallback(async () => {
10834
10983
  setBusy(true);
10835
10984
  try {
10836
10985
  if (provision?.attemptId && !["failed", "expired", "cancelled"].includes(provision.status)) {
@@ -10845,7 +10994,7 @@ function WeixinSettingsTab({ rpcCall }) {
10845
10994
  setBusy(false);
10846
10995
  }
10847
10996
  }, [announce, invoke, provision?.attemptId, provision?.status, scheduleAnimationFrame]);
10848
- const submitVerification = React19.useCallback(async (verifyCode) => {
10997
+ const submitVerification = React20.useCallback(async (verifyCode) => {
10849
10998
  if (!provision?.attemptId) return;
10850
10999
  setBusy(true);
10851
11000
  try {
@@ -10861,7 +11010,7 @@ function WeixinSettingsTab({ rpcCall }) {
10861
11010
  setBusy(false);
10862
11011
  }
10863
11012
  }, [announce, invoke, provision?.attemptId]);
10864
- React19.useEffect(() => {
11013
+ React20.useEffect(() => {
10865
11014
  const attemptId = provision?.attemptId;
10866
11015
  if (!attemptId || !["pending", "scanned", "connecting"].includes(provision.status)) return void 0;
10867
11016
  const controller = new AbortController();
@@ -10909,7 +11058,7 @@ function WeixinSettingsTab({ rpcCall }) {
10909
11058
  controller.abort();
10910
11059
  };
10911
11060
  }, [announce, invoke, loadStatus, provision?.attemptId, provision?.status, provision?.pollIntervalMs]);
10912
- const setBotBusy = React19.useCallback((botId, value) => {
11061
+ const setBotBusy = React20.useCallback((botId, value) => {
10913
11062
  setBusyByBot((current) => {
10914
11063
  const next = { ...current };
10915
11064
  if (value) next[botId] = value;
@@ -10917,7 +11066,7 @@ function WeixinSettingsTab({ rpcCall }) {
10917
11066
  return next;
10918
11067
  });
10919
11068
  }, []);
10920
- const reconnect = React19.useCallback(async (account) => {
11069
+ const reconnect = React20.useCallback(async (account) => {
10921
11070
  const snapshotVersion = workspaceFence.beginMutation();
10922
11071
  setBotBusy(account.botId, "reconnect");
10923
11072
  setFeedbackByBot((current) => {
@@ -10969,7 +11118,7 @@ function WeixinSettingsTab({ rpcCall }) {
10969
11118
  setBotBusy(account.botId, null);
10970
11119
  }
10971
11120
  }, [announce, invoke, loadStatus, setBotBusy, workspaceFence]);
10972
- const saveWorkspace = React19.useCallback(async (account, workspace) => {
11121
+ const saveWorkspace = React20.useCallback(async (account, workspace) => {
10973
11122
  const workspaceVersion = workspaceFence.beginMutation();
10974
11123
  setBotBusy(account.botId, "workspace");
10975
11124
  try {
@@ -10994,7 +11143,7 @@ function WeixinSettingsTab({ rpcCall }) {
10994
11143
  if (mountedRef.current) setBotBusy(account.botId, null);
10995
11144
  }
10996
11145
  }, [invoke, loadStatus, setBotBusy, workspaceFence]);
10997
- const saveBotSetting = React19.useCallback(async (account, operation, endpoint, payload) => {
11146
+ const saveBotSetting = React20.useCallback(async (account, operation, endpoint, payload) => {
10998
11147
  const snapshotVersion = workspaceFence.beginMutation();
10999
11148
  setBotBusy(account.botId, operation);
11000
11149
  try {
@@ -11019,7 +11168,7 @@ function WeixinSettingsTab({ rpcCall }) {
11019
11168
  if (mountedRef.current) setBotBusy(account.botId, null);
11020
11169
  }
11021
11170
  }, [invoke, loadStatus, setBotBusy, workspaceFence]);
11022
- const remove = React19.useCallback(async (account) => {
11171
+ const remove = React20.useCallback(async (account) => {
11023
11172
  const snapshotVersion = workspaceFence.beginMutation();
11024
11173
  setBotBusy(account.botId, "delete");
11025
11174
  try {
@@ -11106,7 +11255,7 @@ function WeixinSettingsTab({ rpcCall }) {
11106
11255
  h2(Button12, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
11107
11256
  )
11108
11257
  ) : h2(
11109
- React19.Fragment,
11258
+ React20.Fragment,
11110
11259
  null,
11111
11260
  provisionView,
11112
11261
  model.bots.length === 0 && !provision ? h2(EmptyView5, { onStart: () => void startProvisioning(), busy }) : null,
@@ -11384,7 +11533,7 @@ function formatRemaining6(milliseconds) {
11384
11533
  }
11385
11534
 
11386
11535
  // plugin-src/client/channels/whatsapp/index.js
11387
- var React20 = __toESM(require("react"), 1);
11536
+ var React21 = __toESM(require("react"), 1);
11388
11537
 
11389
11538
  // plugin-src/client/channels/whatsapp/styles.js
11390
11539
  var WHATSAPP_STYLE_ID = "xmanrui-dsh-im-whatsapp-settings";
@@ -11409,7 +11558,7 @@ function installWhatsappStyles() {
11409
11558
 
11410
11559
  // plugin-src/client/channels/whatsapp/index.js
11411
11560
  var ACTIVE_STATES3 = /* @__PURE__ */ new Set(["pending", "connecting"]);
11412
- var Button14 = React20.forwardRef(function Button15({ children, kind = "secondary", className = "", ...props }, ref) {
11561
+ var Button14 = React21.forwardRef(function Button15({ children, kind = "secondary", className = "", ...props }, ref) {
11413
11562
  return h2("button", {
11414
11563
  ...props,
11415
11564
  ref,
@@ -11649,92 +11798,107 @@ function WhatsappAccountCard({
11649
11798
  "div",
11650
11799
  { className: "ddt-cardBody dim-botCardBody" },
11651
11800
  h2(
11652
- "div",
11653
- { className: "ddt-accountTop dim-botCardTop" },
11654
- h2(
11655
- "div",
11656
- { className: "ddt-accountIdentity dim-botIdentity" },
11657
- h2("div", {
11658
- className: "ddt-avatar dim-botAvatar dwa-avatar",
11659
- "aria-hidden": "true"
11660
- }, h2(WhatsappLogoGlyph, { size: 29 })),
11661
- h2(
11801
+ CollapsibleAccountSection,
11802
+ {
11803
+ id: `wsp-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, "-")}`,
11804
+ header: h2(
11662
11805
  "div",
11663
- { className: "dim-botName" },
11664
- h2("h3", null, account.bot.name),
11665
- h2("p", null, account.bot.idMasked)
11806
+ { className: "ddt-accountTop dim-botCardTop" },
11807
+ h2(
11808
+ "div",
11809
+ { className: "ddt-accountIdentity dim-botIdentity" },
11810
+ h2("div", {
11811
+ className: "ddt-avatar dim-botAvatar dwa-avatar",
11812
+ "aria-hidden": "true"
11813
+ }, h2(WhatsappLogoGlyph, { size: 29 })),
11814
+ h2(
11815
+ "div",
11816
+ { className: "dim-botName" },
11817
+ h2("h3", null, account.bot.name),
11818
+ h2("p", null, account.bot.idMasked)
11819
+ )
11820
+ ),
11821
+ h2(
11822
+ "div",
11823
+ {
11824
+ className: "dim-botCardTools",
11825
+ // The header is the collapse toggle; keep inner controls clickable.
11826
+ onClick: (event) => {
11827
+ event.stopPropagation();
11828
+ },
11829
+ onKeyDown: (event) => {
11830
+ if (event.key === "Enter" || event.key === " ") event.stopPropagation();
11831
+ }
11832
+ },
11833
+ h2(BotStatusMeta, {
11834
+ className: "ddt-health",
11835
+ dotClassName: "ddt-dot",
11836
+ tone,
11837
+ stateLabel: stateLabel2,
11838
+ lastCheckedAt: account.health.lastCheckedAt,
11839
+ formatCheckedTime: checkedTime6
11840
+ }),
11841
+ h2(BotSettingsButton, {
11842
+ channel: "whatsapp",
11843
+ botId: account.botId,
11844
+ botName: account.bot.name,
11845
+ connected: account.connected,
11846
+ accessPolicy: account.accessPolicy
11847
+ })
11848
+ )
11666
11849
  )
11667
- ),
11668
- h2(
11669
- "div",
11670
- { className: "dim-botCardTools" },
11671
- h2(BotStatusMeta, {
11672
- className: "ddt-health",
11673
- dotClassName: "ddt-dot",
11674
- tone,
11675
- stateLabel: stateLabel2,
11676
- lastCheckedAt: account.health.lastCheckedAt,
11677
- formatCheckedTime: checkedTime6
11678
- }),
11679
- h2(BotSettingsButton, {
11680
- channel: "whatsapp",
11681
- botId: account.botId,
11682
- botName: account.bot.name,
11683
- connected: account.connected,
11684
- accessPolicy: account.accessPolicy
11685
- })
11686
- )
11687
- ),
11688
- h2(WorkspaceEditor, {
11689
- workspace: account.workspace,
11690
- disabled: Boolean(busy),
11691
- onSave: onWorkspaceSave
11692
- }),
11693
- h2(ModelEditor, {
11694
- model: account.model,
11695
- disabled: Boolean(busy),
11696
- onSave: onModelSave
11697
- }),
11698
- h2(AgentPresetEditor, {
11699
- agentPreset: account.agentPreset,
11700
- disabled: Boolean(busy),
11701
- onSave: onAgentPresetSave
11702
- }),
11703
- h2(ContextEnhancementEditor, {
11704
- config: account.contextEnhancement,
11705
- disabled: Boolean(busy),
11706
- onSave: onContextEnhancementSave
11707
- }),
11708
- h2(
11709
- "div",
11710
- { className: "ddt-accountFooter dim-cardFooter" },
11850
+ },
11851
+ h2(WorkspaceEditor, {
11852
+ workspace: account.workspace,
11853
+ disabled: Boolean(busy),
11854
+ onSave: onWorkspaceSave
11855
+ }),
11856
+ h2(ModelEditor, {
11857
+ model: account.model,
11858
+ disabled: Boolean(busy),
11859
+ onSave: onModelSave
11860
+ }),
11861
+ h2(AgentPresetEditor, {
11862
+ agentPreset: account.agentPreset,
11863
+ disabled: Boolean(busy),
11864
+ onSave: onAgentPresetSave
11865
+ }),
11866
+ h2(ContextEnhancementEditor, {
11867
+ config: account.contextEnhancement,
11868
+ disabled: Boolean(busy),
11869
+ onSave: onContextEnhancementSave
11870
+ }),
11711
11871
  h2(
11712
11872
  "div",
11713
- { className: "dim-cardFooterLayout" },
11873
+ { className: "ddt-accountFooter dim-cardFooter" },
11714
11874
  h2(
11715
11875
  "div",
11716
- { className: "ddt-actions dim-cardActions" },
11717
- h2(Button14, {
11718
- className: "dim-cardAction",
11719
- onClick: onReconnect,
11720
- disabled: Boolean(busy)
11721
- }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
11722
- h2(Button14, {
11723
- className: "dim-cardAction",
11724
- kind: "danger",
11725
- onClick: onRequestRemove,
11726
- disabled: Boolean(busy)
11727
- }, "\u79FB\u9664\u63A5\u5165")
11728
- ),
11729
- summary2 ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary2) : null,
11730
- account.lastMessageError ? h2(LastMessageErrorSummary, {
11731
- className: "ddt-summary",
11732
- error: account.lastMessageError
11733
- }) : null,
11734
- testNotice ? h2("div", {
11735
- className: "ddt-summary dim-cardFeedback",
11736
- role: "status"
11737
- }, testNotice) : null
11876
+ { className: "dim-cardFooterLayout" },
11877
+ h2(
11878
+ "div",
11879
+ { className: "ddt-actions dim-cardActions" },
11880
+ h2(Button14, {
11881
+ className: "dim-cardAction",
11882
+ onClick: onReconnect,
11883
+ disabled: Boolean(busy)
11884
+ }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"),
11885
+ h2(Button14, {
11886
+ className: "dim-cardAction",
11887
+ kind: "danger",
11888
+ onClick: onRequestRemove,
11889
+ disabled: Boolean(busy)
11890
+ }, "\u79FB\u9664\u63A5\u5165")
11891
+ ),
11892
+ summary2 ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary2) : null,
11893
+ account.lastMessageError ? h2(LastMessageErrorSummary, {
11894
+ className: "ddt-summary",
11895
+ error: account.lastMessageError
11896
+ }) : null,
11897
+ testNotice ? h2("div", {
11898
+ className: "ddt-summary dim-cardFeedback",
11899
+ role: "status"
11900
+ }, testNotice) : null
11901
+ )
11738
11902
  )
11739
11903
  )
11740
11904
  ),
@@ -11747,7 +11911,7 @@ function WhatsappAccountCard({
11747
11911
  );
11748
11912
  }
11749
11913
  function WhatsappSettingsTab({ rpcCall }) {
11750
- const [model, setModel] = React20.useState({
11914
+ const [model, setModel] = React21.useState({
11751
11915
  phase: "loading",
11752
11916
  bots: [],
11753
11917
  totals: { configured: 0, connected: 0 },
@@ -11755,16 +11919,16 @@ function WhatsappSettingsTab({ rpcCall }) {
11755
11919
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG,
11756
11920
  modelCatalog: EMPTY_MODEL_CATALOG
11757
11921
  });
11758
- const [provision, setProvision] = React20.useState(null);
11759
- const [busy, setBusy] = React20.useState(false);
11760
- const [busyByBot, setBusyByBot] = React20.useState({});
11761
- const [testNoticeByBot, setTestNoticeByBot] = React20.useState({});
11762
- const [removeTarget, setRemoveTarget] = React20.useState(null);
11763
- const [now, setNow] = React20.useState(Date.now());
11764
- const mounted = React20.useRef(true);
11922
+ const [provision, setProvision] = React21.useState(null);
11923
+ const [busy, setBusy] = React21.useState(false);
11924
+ const [busyByBot, setBusyByBot] = React21.useState({});
11925
+ const [testNoticeByBot, setTestNoticeByBot] = React21.useState({});
11926
+ const [removeTarget, setRemoveTarget] = React21.useState(null);
11927
+ const [now, setNow] = React21.useState(Date.now());
11928
+ const mounted = React21.useRef(true);
11765
11929
  const workspaceFence = useWorkspaceSnapshotFence();
11766
- const addButtonRef = React20.useRef(null);
11767
- React20.useEffect(() => {
11930
+ const addButtonRef = React21.useRef(null);
11931
+ React21.useEffect(() => {
11768
11932
  const disposeDingtalk = installDingtalkStyles();
11769
11933
  const disposeWhatsapp = installWhatsappStyles();
11770
11934
  mounted.current = true;
@@ -11774,11 +11938,11 @@ function WhatsappSettingsTab({ rpcCall }) {
11774
11938
  disposeDingtalk();
11775
11939
  };
11776
11940
  }, []);
11777
- const invoke = React20.useCallback(async (endpoint, payload = {}, signal) => {
11941
+ const invoke = React21.useCallback(async (endpoint, payload = {}, signal) => {
11778
11942
  if (typeof rpcCall !== "function") throw new TypeError("WhatsApp \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
11779
11943
  return unwrapRpcResult9(await rpcCall(endpoint, payload, signal));
11780
11944
  }, [rpcCall]);
11781
- const loadStatus = React20.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
11945
+ const loadStatus = React21.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
11782
11946
  const workspaceVersion = workspaceFence.beginStatus();
11783
11947
  if (workspaceVersion === null) return void 0;
11784
11948
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
@@ -11809,12 +11973,12 @@ function WhatsappSettingsTab({ rpcCall }) {
11809
11973
  return void 0;
11810
11974
  }
11811
11975
  }, [invoke, workspaceFence]);
11812
- React20.useEffect(() => {
11976
+ React21.useEffect(() => {
11813
11977
  const controller = new AbortController();
11814
11978
  void loadStatus({ signal: controller.signal, restore: true });
11815
11979
  return () => controller.abort();
11816
11980
  }, [loadStatus]);
11817
- React20.useEffect(() => {
11981
+ React21.useEffect(() => {
11818
11982
  if (model.phase !== "ready") return void 0;
11819
11983
  const controller = new AbortController();
11820
11984
  const timer = window.setInterval(
@@ -11826,12 +11990,12 @@ function WhatsappSettingsTab({ rpcCall }) {
11826
11990
  window.clearInterval(timer);
11827
11991
  };
11828
11992
  }, [loadStatus, model.phase]);
11829
- React20.useEffect(() => {
11993
+ React21.useEffect(() => {
11830
11994
  if (!provision || !ACTIVE_STATES3.has(provision.status)) return void 0;
11831
11995
  const timer = window.setInterval(() => mounted.current && setNow(Date.now()), 1e3);
11832
11996
  return () => window.clearInterval(timer);
11833
11997
  }, [provision?.attemptId, provision?.status]);
11834
- const startProvisioning = React20.useCallback(async (replace = false) => {
11998
+ const startProvisioning = React21.useCallback(async (replace = false) => {
11835
11999
  setBusy(true);
11836
12000
  try {
11837
12001
  if (replace && provision?.attemptId) {
@@ -11849,7 +12013,7 @@ function WhatsappSettingsTab({ rpcCall }) {
11849
12013
  if (mounted.current) setBusy(false);
11850
12014
  }
11851
12015
  }, [invoke, provision?.attemptId]);
11852
- const closeProvision = React20.useCallback(async () => {
12016
+ const closeProvision = React21.useCallback(async () => {
11853
12017
  setBusy(true);
11854
12018
  try {
11855
12019
  if (provision?.attemptId && ACTIVE_STATES3.has(provision.status)) {
@@ -11860,7 +12024,7 @@ function WhatsappSettingsTab({ rpcCall }) {
11860
12024
  if (mounted.current) setBusy(false);
11861
12025
  }
11862
12026
  }, [invoke, provision?.attemptId, provision?.status]);
11863
- React20.useEffect(() => {
12027
+ React21.useEffect(() => {
11864
12028
  const attemptId = provision?.attemptId;
11865
12029
  if (!attemptId || !ACTIVE_STATES3.has(provision.status)) return void 0;
11866
12030
  const controller = new AbortController();
@@ -11901,7 +12065,7 @@ function WhatsappSettingsTab({ rpcCall }) {
11901
12065
  if (timer) window.clearTimeout(timer);
11902
12066
  };
11903
12067
  }, [invoke, loadStatus, provision?.attemptId, provision?.status]);
11904
- const botAction = React20.useCallback(async (account, operation, endpoint, payload) => {
12068
+ const botAction = React21.useCallback(async (account, operation, endpoint, payload) => {
11905
12069
  const snapshotVersion = workspaceFence.beginMutation();
11906
12070
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
11907
12071
  if (operation === "reconnect") {
@@ -12029,7 +12193,7 @@ function WhatsappSettingsTab({ rpcCall }) {
12029
12193
  h2(Button14, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
12030
12194
  )
12031
12195
  ) : h2(
12032
- React20.Fragment,
12196
+ React21.Fragment,
12033
12197
  null,
12034
12198
  provision?.status === "pending" ? h2(QrPanel5, {
12035
12199
  provision,
@@ -12049,10 +12213,10 @@ function WhatsappSettingsTab({ rpcCall }) {
12049
12213
  }
12050
12214
 
12051
12215
  // plugin-src/client/delivery-settings.js
12052
- var React23 = __toESM(require("react"), 1);
12216
+ var React24 = __toESM(require("react"), 1);
12053
12217
 
12054
12218
  // plugin-src/client/access-policy-settings.js
12055
- var React21 = __toESM(require("react"), 1);
12219
+ var React22 = __toESM(require("react"), 1);
12056
12220
  var ACCESS_POLICY_ENDPOINT = "bot.access-policy.set";
12057
12221
  var ACCESS_CHANNEL_DEFINITIONS = Object.freeze({
12058
12222
  weixin: Object.freeze({
@@ -12154,8 +12318,8 @@ function ScenePolicyEditor({
12154
12318
  unsupported = false,
12155
12319
  onChange
12156
12320
  }) {
12157
- const ownerHelpId = React21.useId();
12158
- const emptyAllowlistHelpId = React21.useId();
12321
+ const ownerHelpId = React22.useId();
12322
+ const emptyAllowlistHelpId = React22.useId();
12159
12323
  const allowlist = policy.mode === "allowlist";
12160
12324
  const collectionKey = allowlist ? "users" : "commandPermissionOverrides";
12161
12325
  const branchKey = allowlist ? "allowlist" : "open";
@@ -12207,7 +12371,7 @@ function ScenePolicyEditor({
12207
12371
  h2("strong", null, "\u5F53\u524D\u6E20\u9053\u4E0D\u652F\u6301\u7FA4\u804A"),
12208
12372
  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")
12209
12373
  ) : h2(
12210
- React21.Fragment,
12374
+ React22.Fragment,
12211
12375
  null,
12212
12376
  h2(
12213
12377
  "div",
@@ -12348,16 +12512,16 @@ function AccessPolicySettingsPage({ channel: channel4, account, rpcCall, onSaved
12348
12512
  const definition = ACCESS_CHANNEL_DEFINITIONS[channel4];
12349
12513
  const initialPolicy = normalizeAccessPolicy(account?.accessPolicy);
12350
12514
  const initialKey = JSON.stringify(initialPolicy);
12351
- const [draft, setDraft] = React21.useState(() => clonePolicy(
12515
+ const [draft, setDraft] = React22.useState(() => clonePolicy(
12352
12516
  initialPolicy ?? DEFAULT_ACCESS_POLICY
12353
12517
  ));
12354
- const [saving, setSaving] = React21.useState(false);
12355
- const [feedback, setFeedback] = React21.useState(null);
12356
- React21.useEffect(() => {
12518
+ const [saving, setSaving] = React22.useState(false);
12519
+ const [feedback, setFeedback] = React22.useState(null);
12520
+ React22.useEffect(() => {
12357
12521
  const next = normalizeAccessPolicy(account?.accessPolicy);
12358
12522
  setDraft(clonePolicy(next ?? DEFAULT_ACCESS_POLICY));
12359
12523
  }, [account?.botId, initialKey]);
12360
- React21.useEffect(() => {
12524
+ React22.useEffect(() => {
12361
12525
  setFeedback(null);
12362
12526
  }, [account?.botId]);
12363
12527
  if (!definition) {
@@ -12448,7 +12612,7 @@ function AccessPolicySettingsPage({ channel: channel4, account, rpcCall, onSaved
12448
12612
  }
12449
12613
 
12450
12614
  // plugin-src/client/channels/feishu/group-settings.js
12451
- var React22 = __toESM(require("react"), 1);
12615
+ var React23 = __toESM(require("react"), 1);
12452
12616
  var GROUP_MESSAGE_PERMISSION_OPERATION2 = FEISHU_REGISTRATION_OPERATIONS.GROUP_MESSAGE_PERMISSION;
12453
12617
  function SettingsButton({ children, kind = "secondary", className = "", ...props }) {
12454
12618
  return h2("button", {
@@ -12509,9 +12673,9 @@ function GroupResponseModeEditor({
12509
12673
  onAuthorize
12510
12674
  }) {
12511
12675
  const current = normalizeGroupResponseMode(value);
12512
- const [saving, setSaving] = React22.useState(false);
12513
- const [authorizing, setAuthorizing] = React22.useState(false);
12514
- const [error, setError] = React22.useState(null);
12676
+ const [saving, setSaving] = React23.useState(false);
12677
+ const [authorizing, setAuthorizing] = React23.useState(false);
12678
+ const [error, setError] = React23.useState(null);
12515
12679
  const change = async (event) => {
12516
12680
  const next = normalizeGroupResponseMode(event.target.value);
12517
12681
  if (next === current || saving || disabled) return;
@@ -12592,8 +12756,8 @@ function GroupResponseModeEditor({
12592
12756
  }
12593
12757
  function GroupTopicReplyEditor({ value = false, disabled = false, onSave }) {
12594
12758
  const current = value === true ? "on" : "off";
12595
- const [saving, setSaving] = React22.useState(false);
12596
- const [error, setError] = React22.useState(null);
12759
+ const [saving, setSaving] = React23.useState(false);
12760
+ const [error, setError] = React23.useState(null);
12597
12761
  const change = async (event) => {
12598
12762
  const next = event.target.value === "on";
12599
12763
  if ((next ? "on" : "off") === current || saving || disabled) return;
@@ -12780,14 +12944,14 @@ function PermissionFlow({ provision, now, busy, botName, onRetry, onCancel, onCl
12780
12944
  );
12781
12945
  }
12782
12946
  function FeishuGroupSettingsPage({ account, rpcCall }) {
12783
- const [settings, setSettings] = React22.useState(() => groupSettingsFrom(account));
12784
- const [refreshing, setRefreshing] = React22.useState(false);
12785
- const [refreshError, setRefreshError] = React22.useState(null);
12786
- const [provision, setProvision] = React22.useState(null);
12787
- const [provisionBusy, setProvisionBusy] = React22.useState(false);
12788
- const [now, setNow] = React22.useState(() => Date.now());
12789
- const mounted = React22.useRef(true);
12790
- React22.useEffect(() => {
12947
+ const [settings, setSettings] = React23.useState(() => groupSettingsFrom(account));
12948
+ const [refreshing, setRefreshing] = React23.useState(false);
12949
+ const [refreshError, setRefreshError] = React23.useState(null);
12950
+ const [provision, setProvision] = React23.useState(null);
12951
+ const [provisionBusy, setProvisionBusy] = React23.useState(false);
12952
+ const [now, setNow] = React23.useState(() => Date.now());
12953
+ const mounted = React23.useRef(true);
12954
+ React23.useEffect(() => {
12791
12955
  setSettings(groupSettingsFrom(account));
12792
12956
  }, [
12793
12957
  account.botId,
@@ -12795,22 +12959,22 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
12795
12959
  account.groupTopicReply,
12796
12960
  account.groupMessagePermissionGranted
12797
12961
  ]);
12798
- React22.useEffect(() => {
12962
+ React23.useEffect(() => {
12799
12963
  mounted.current = true;
12800
12964
  return () => {
12801
12965
  mounted.current = false;
12802
12966
  };
12803
12967
  }, []);
12804
- const invoke = React22.useCallback(async (endpoint, payload = {}, signal) => {
12968
+ const invoke = React23.useCallback(async (endpoint, payload = {}, signal) => {
12805
12969
  if (typeof rpcCall !== "function") throw new Error("\u98DE\u4E66\u7FA4\u804A\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
12806
12970
  return unwrapRpcResult3(await rpcCall(endpoint, payload, signal));
12807
12971
  }, [rpcCall]);
12808
- const applySnapshot = React22.useCallback((value) => {
12972
+ const applySnapshot = React23.useCallback((value) => {
12809
12973
  const result = targetBotFromSnapshot(value, account.botId);
12810
12974
  if (mounted.current) setSettings(groupSettingsFrom(result.bot));
12811
12975
  return result;
12812
12976
  }, [account.botId]);
12813
- const loadSettings = React22.useCallback(async ({ signal, restoreProvisioning = false } = {}) => {
12977
+ const loadSettings = React23.useCallback(async ({ signal, restoreProvisioning = false } = {}) => {
12814
12978
  setRefreshing(true);
12815
12979
  setRefreshError(null);
12816
12980
  try {
@@ -12839,16 +13003,16 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
12839
13003
  if (!signal?.aborted && mounted.current) setRefreshing(false);
12840
13004
  }
12841
13005
  }, [account.botId, applySnapshot, invoke]);
12842
- React22.useEffect(() => {
13006
+ React23.useEffect(() => {
12843
13007
  const controller = new AbortController();
12844
13008
  void loadSettings({ signal: controller.signal, restoreProvisioning: true });
12845
13009
  return () => controller.abort();
12846
13010
  }, [loadSettings]);
12847
- const saveSetting = React22.useCallback(async (endpoint, payload) => {
13011
+ const saveSetting = React23.useCallback(async (endpoint, payload) => {
12848
13012
  const value = await invoke(endpoint, { botId: account.botId, ...payload });
12849
13013
  applySnapshot(value);
12850
13014
  }, [account.botId, applySnapshot, invoke]);
12851
- const startAuthorization = React22.useCallback(async ({ replace = false } = {}) => {
13015
+ const startAuthorization = React23.useCallback(async ({ replace = false } = {}) => {
12852
13016
  if (provisionBusy) return;
12853
13017
  const previousAttemptId = provision?.attemptId;
12854
13018
  setProvisionBusy(true);
@@ -12889,13 +13053,13 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
12889
13053
  if (mounted.current) setProvisionBusy(false);
12890
13054
  }
12891
13055
  }, [account.botId, invoke, provision?.attemptId, provisionBusy]);
12892
- const finishAuthorization = React22.useCallback(async (signal) => {
13056
+ const finishAuthorization = React23.useCallback(async (signal) => {
12893
13057
  const bot = await loadSettings({ signal, restoreProvisioning: false });
12894
13058
  if (signal?.aborted || !mounted.current) return;
12895
13059
  if (!bot) throw new Error("\u7FA4\u6D88\u606F\u6743\u9650\u5DF2\u66F4\u65B0\uFF0C\u4F46\u6682\u65F6\u65E0\u6CD5\u786E\u8BA4\u673A\u5668\u4EBA\u8FDE\u63A5\u72B6\u6001");
12896
13060
  setProvision(null);
12897
13061
  }, [loadSettings]);
12898
- React22.useEffect(() => {
13062
+ React23.useEffect(() => {
12899
13063
  if (!provision?.attemptId || !["qr", "connecting"].includes(provision.phase) || provision.expired) return void 0;
12900
13064
  const timerHost = globalThis.window ?? globalThis;
12901
13065
  const controller = new AbortController();
@@ -12939,7 +13103,7 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
12939
13103
  timerHost.clearTimeout(timer);
12940
13104
  };
12941
13105
  }, [account.botId, finishAuthorization, invoke, provision]);
12942
- React22.useEffect(() => {
13106
+ React23.useEffect(() => {
12943
13107
  if (!provision?.attemptId || provision.phase !== "qr" || provision.expired) return void 0;
12944
13108
  const timerHost = globalThis.window ?? globalThis;
12945
13109
  const tick = () => {
@@ -12953,7 +13117,7 @@ function FeishuGroupSettingsPage({ account, rpcCall }) {
12953
13117
  const timer = timerHost.setInterval(tick, 1e3);
12954
13118
  return () => timerHost.clearInterval(timer);
12955
13119
  }, [provision?.attemptId, provision?.expired, provision?.expiresAt, provision?.phase]);
12956
- const cancelAuthorization = React22.useCallback(async () => {
13120
+ const cancelAuthorization = React23.useCallback(async () => {
12957
13121
  if (!provision?.attemptId || provisionBusy) {
12958
13122
  setProvision(null);
12959
13123
  return;
@@ -13262,13 +13426,13 @@ function TargetForm({
13262
13426
  }) {
13263
13427
  const editing = mode === "edit";
13264
13428
  const initialKind = initialValue?.kind && definition.fields[initialValue.kind] ? initialValue.kind : definition.kinds[0].value;
13265
- const [targetId, setTargetId] = React23.useState(initialValue?.targetId ?? "");
13266
- const [name2, setName] = React23.useState(initialValue?.name ?? "");
13267
- const [kind, setKind] = React23.useState(initialKind);
13268
- const [route, setRoute] = React23.useState(initialValue?.route ?? {});
13269
- const [error, setError] = React23.useState(null);
13270
- const [testing, setTesting] = React23.useState(false);
13271
- const [testState, setTestState] = React23.useState(null);
13429
+ const [targetId, setTargetId] = React24.useState(initialValue?.targetId ?? "");
13430
+ const [name2, setName] = React24.useState(initialValue?.name ?? "");
13431
+ const [kind, setKind] = React24.useState(initialKind);
13432
+ const [route, setRoute] = React24.useState(initialValue?.route ?? {});
13433
+ const [error, setError] = React24.useState(null);
13434
+ const [testing, setTesting] = React24.useState(false);
13435
+ const [testState, setTestState] = React24.useState(null);
13272
13436
  const currentTarget = () => {
13273
13437
  const normalizedRoute = Object.fromEntries(fieldsFor(definition, kind).map((field) => {
13274
13438
  const raw = String(route[field.key] ?? "").trim();
@@ -13485,7 +13649,7 @@ function TargetSuggestionPicker({
13485
13649
  suggestions.map((suggestion, index) => {
13486
13650
  const identity = routeIdentity(definition, suggestion);
13487
13651
  const added = configured.has(identity);
13488
- return React23.createElement("option", {
13652
+ return React24.createElement("option", {
13489
13653
  key: suggestion.id ?? suggestion.suggestionId ?? `${identity}:${index}`,
13490
13654
  value: String(index),
13491
13655
  disabled: added
@@ -13502,11 +13666,11 @@ function TargetSuggestionPicker({
13502
13666
  );
13503
13667
  }
13504
13668
  function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, onEdit }) {
13505
- const [action, setAction] = React23.useState(null);
13506
- const [testState, setTestState] = React23.useState(null);
13507
- const [syncFeedback, setSyncFeedback] = React23.useState(null);
13508
- const [copyState, setCopyState] = React23.useState(null);
13509
- const [confirmDelete, setConfirmDelete] = React23.useState(false);
13669
+ const [action, setAction] = React24.useState(null);
13670
+ const [testState, setTestState] = React24.useState(null);
13671
+ const [syncFeedback, setSyncFeedback] = React24.useState(null);
13672
+ const [copyState, setCopyState] = React24.useState(null);
13673
+ const [confirmDelete, setConfirmDelete] = React24.useState(false);
13510
13674
  const sessionSync = target.sessionSync ?? { enabled: false, state: "unavailable" };
13511
13675
  const syncDescription = sessionSync.state === "active" ? "\u81EA\u52A8\u8DDF\u968F\u8BE5\u79C1\u804A\u7684\u5F53\u524D\u4F1A\u8BDD" : sessionSync.state === "waiting" ? "\u7B49\u5F85\u8BE5\u79C1\u804A\u5EFA\u7ACB\u65B0\u4F1A\u8BDD" : sessionSync.state === "unavailable" ? "\u4EC5\u652F\u6301\u5DF2\u7ECF\u804A\u8FC7\u3001\u5DF2\u5EFA\u7ACB\u5F53\u524D\u4F1A\u8BDD\u4E14\u4F7F\u7528\u5F53\u524D Host Harness \u7684\u79C1\u804A\u76EE\u6807" : "\u5173\u95ED\u65F6\u4E0D\u53D1\u9001 DSH \u4F1A\u8BDD\u6D88\u606F";
13512
13676
  const testTarget = async () => {
@@ -13569,7 +13733,7 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
13569
13733
  h2(
13570
13734
  "div",
13571
13735
  { className: "dim-targetTitle" },
13572
- React23.createElement("strong", null, target.name || target.targetId),
13736
+ React24.createElement("strong", null, target.name || target.targetId),
13573
13737
  h2("span", null, kindLabel(definition, target.kind))
13574
13738
  ),
13575
13739
  h2("code", null, `targetId: ${target.targetId}`)
@@ -13655,26 +13819,26 @@ function DeliveryTargetSettingsPage({
13655
13819
  onBack
13656
13820
  }) {
13657
13821
  const definition = CHANNEL_DEFINITIONS[channel4];
13658
- const [activeTabId, setActiveTabId] = React23.useState(BOT_SETTINGS_TABS[0].id);
13659
- const [phase, setPhase] = React23.useState("loading");
13660
- const [targets, setTargets] = React23.useState([]);
13661
- const [suggestionPhase, setSuggestionPhase] = React23.useState("idle");
13662
- const [suggestions, setSuggestions] = React23.useState([]);
13663
- const [suggestionError, setSuggestionError] = React23.useState(null);
13664
- const [error, setError] = React23.useState(null);
13665
- const [editor, setEditor] = React23.useState(null);
13666
- const [saving, setSaving] = React23.useState(false);
13667
- const [botCopyState, setBotCopyState] = React23.useState(null);
13668
- const [accessPolicy, setAccessPolicy] = React23.useState(account.accessPolicy);
13669
- const mounted = React23.useRef(true);
13670
- React23.useEffect(() => {
13822
+ const [activeTabId, setActiveTabId] = React24.useState(BOT_SETTINGS_TABS[0].id);
13823
+ const [phase, setPhase] = React24.useState("loading");
13824
+ const [targets, setTargets] = React24.useState([]);
13825
+ const [suggestionPhase, setSuggestionPhase] = React24.useState("idle");
13826
+ const [suggestions, setSuggestions] = React24.useState([]);
13827
+ const [suggestionError, setSuggestionError] = React24.useState(null);
13828
+ const [error, setError] = React24.useState(null);
13829
+ const [editor, setEditor] = React24.useState(null);
13830
+ const [saving, setSaving] = React24.useState(false);
13831
+ const [botCopyState, setBotCopyState] = React24.useState(null);
13832
+ const [accessPolicy, setAccessPolicy] = React24.useState(account.accessPolicy);
13833
+ const mounted = React24.useRef(true);
13834
+ React24.useEffect(() => {
13671
13835
  setAccessPolicy(account.accessPolicy);
13672
13836
  }, [account.botId, account.accessPolicy]);
13673
- const invoke = React23.useCallback(async (endpoint, payload = {}, signal) => {
13837
+ const invoke = React24.useCallback(async (endpoint, payload = {}, signal) => {
13674
13838
  if (typeof rpcCall !== "function") throw new Error("\u6295\u9012\u76EE\u6807\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
13675
13839
  return unwrapRpcResult11(await rpcCall(endpoint, payload, signal));
13676
13840
  }, [rpcCall]);
13677
- const loadTargets = React23.useCallback(async ({ signal, silent = false } = {}) => {
13841
+ const loadTargets = React24.useCallback(async ({ signal, silent = false } = {}) => {
13678
13842
  if (!silent) setPhase("loading");
13679
13843
  setError(null);
13680
13844
  try {
@@ -13688,7 +13852,7 @@ function DeliveryTargetSettingsPage({
13688
13852
  setPhase("error");
13689
13853
  }
13690
13854
  }, [account.botId, invoke]);
13691
- const loadSuggestions = React23.useCallback(async () => {
13855
+ const loadSuggestions = React24.useCallback(async () => {
13692
13856
  setSuggestionPhase("loading");
13693
13857
  setSuggestionError(null);
13694
13858
  try {
@@ -13702,7 +13866,7 @@ function DeliveryTargetSettingsPage({
13702
13866
  setSuggestionPhase("error");
13703
13867
  }
13704
13868
  }, [account.botId, definition, invoke]);
13705
- React23.useEffect(() => {
13869
+ React24.useEffect(() => {
13706
13870
  mounted.current = true;
13707
13871
  const controller = new AbortController();
13708
13872
  void loadTargets({ signal: controller.signal });
@@ -13824,7 +13988,7 @@ function DeliveryTargetSettingsPage({
13824
13988
  account,
13825
13989
  rpcCall: accessRpcCall
13826
13990
  }) : h2(
13827
- React23.Fragment,
13991
+ React24.Fragment,
13828
13992
  null,
13829
13993
  h2(
13830
13994
  "section",
@@ -13935,7 +14099,7 @@ function DeliveryTargetSettingsPage({
13935
14099
  }
13936
14100
 
13937
14101
  // plugin-src/client/global-settings.js
13938
- var React24 = __toESM(require("react"), 1);
14102
+ var React25 = __toESM(require("react"), 1);
13939
14103
 
13940
14104
  // src/channels/shared/inbound-ttl.mjs
13941
14105
  var DEFAULT_INBOUND_TTL_HOURS = 168;
@@ -13997,29 +14161,29 @@ function GlobalButton({ children, kind = "secondary", className = "", ...props }
13997
14161
  }, children);
13998
14162
  }
13999
14163
  function GlobalSettingsPanel({ rpcCall }) {
14000
- const [phase, setPhase] = React24.useState("loading");
14001
- const [loadError, setLoadError] = React24.useState(null);
14002
- const [ttlInput, setTtlInput] = React24.useState("");
14003
- const [savedTtl, setSavedTtl] = React24.useState(null);
14004
- const [ttlError, setTtlError] = React24.useState(false);
14005
- const [saveError, setSaveError] = React24.useState(null);
14006
- const [saveSucceeded, setSaveSucceeded] = React24.useState(false);
14007
- const [isSaving, setIsSaving] = React24.useState(false);
14008
- const [sweepConfirming, setSweepConfirming] = React24.useState(false);
14009
- const [sweeping, setSweeping] = React24.useState(false);
14010
- const ttlErrorId = React24.useId();
14011
- const ttlHintsId = React24.useId();
14012
- const sweepTriggerId = React24.useId();
14013
- const sweepConfirmId = React24.useId();
14014
- const sweepConfirmTextId = React24.useId();
14015
- const sweepConfirmButtonId = React24.useId();
14016
- const mounted = React24.useRef(true);
14017
- const saving = React24.useRef(false);
14018
- const invoke = React24.useCallback(async (endpoint, payload = {}, signal) => {
14164
+ const [phase, setPhase] = React25.useState("loading");
14165
+ const [loadError, setLoadError] = React25.useState(null);
14166
+ const [ttlInput, setTtlInput] = React25.useState("");
14167
+ const [savedTtl, setSavedTtl] = React25.useState(null);
14168
+ const [ttlError, setTtlError] = React25.useState(false);
14169
+ const [saveError, setSaveError] = React25.useState(null);
14170
+ const [saveSucceeded, setSaveSucceeded] = React25.useState(false);
14171
+ const [isSaving, setIsSaving] = React25.useState(false);
14172
+ const [sweepConfirming, setSweepConfirming] = React25.useState(false);
14173
+ const [sweeping, setSweeping] = React25.useState(false);
14174
+ const ttlErrorId = React25.useId();
14175
+ const ttlHintsId = React25.useId();
14176
+ const sweepTriggerId = React25.useId();
14177
+ const sweepConfirmId = React25.useId();
14178
+ const sweepConfirmTextId = React25.useId();
14179
+ const sweepConfirmButtonId = React25.useId();
14180
+ const mounted = React25.useRef(true);
14181
+ const saving = React25.useRef(false);
14182
+ const invoke = React25.useCallback(async (endpoint, payload = {}, signal) => {
14019
14183
  if (typeof rpcCall !== "function") throw new Error("\u901A\u7528\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
14020
14184
  return unwrapRpcResult12(await rpcCall(endpoint, payload, signal));
14021
14185
  }, [rpcCall]);
14022
- const loadSettings = React24.useCallback(async ({ signal } = {}) => {
14186
+ const loadSettings = React25.useCallback(async ({ signal } = {}) => {
14023
14187
  setPhase("loading");
14024
14188
  setLoadError(null);
14025
14189
  try {
@@ -14043,7 +14207,7 @@ function GlobalSettingsPanel({ rpcCall }) {
14043
14207
  setPhase("error");
14044
14208
  }
14045
14209
  }, [invoke]);
14046
- React24.useEffect(() => {
14210
+ React25.useEffect(() => {
14047
14211
  mounted.current = true;
14048
14212
  const controller = new AbortController();
14049
14213
  void loadSettings({ signal: controller.signal });
@@ -14052,7 +14216,7 @@ function GlobalSettingsPanel({ rpcCall }) {
14052
14216
  controller.abort();
14053
14217
  };
14054
14218
  }, [loadSettings]);
14055
- React24.useEffect(() => {
14219
+ React25.useEffect(() => {
14056
14220
  if (!sweepConfirming) return;
14057
14221
  globalThis.document?.getElementById(sweepConfirmButtonId)?.focus();
14058
14222
  }, [sweepConfirmButtonId, sweepConfirming]);
@@ -14717,6 +14881,17 @@ var CSS11 = String.raw`
14717
14881
  .dim-panel .dim-botCard { position: relative; min-width: 0; width: 100%; max-width: 100%; overflow: hidden; border: 1px solid var(--dsw-alias-border-l2, #e5e6eb); border-radius: 14px; background: var(--dsw-alias-bg-layer-1, #fff); box-shadow: 0 1px 2px rgb(31 35 41 / 3%); }
14718
14882
  .dim-panel .dim-botCard::before { display: none; }
14719
14883
  .dim-panel .dim-botCardBody { position: relative; min-width: 0; width: 100%; max-width: 100%; padding: 12px; }
14884
+ .dim-collapsibleAccount { min-width: 0; display: flex; flex-direction: column; }
14885
+ .dim-collapsibleHead { min-width: 0; display: flex; align-items: center; gap: 10px; cursor: pointer; user-select: none; -webkit-user-select: none; }
14886
+ .dim-collapsibleHead:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: 2px; border-radius: 8px; }
14887
+ .dim-collapsibleHeaderContent { min-width: 0; flex: 1 1 auto; display: flex; align-items: center; }
14888
+ .dim-collapsibleChevron { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; width: 9px; height: 9px; border-right: 1.6px solid var(--dsw-alias-label-tertiary, #8f959e); border-bottom: 1.6px solid var(--dsw-alias-label-tertiary, #8f959e); transform: rotate(-45deg); transition: transform .22s cubic-bezier(.4, 0, .2, 1); transform-origin: 50% 50%; }
14889
+ .dim-collapsibleAccount.is-open .dim-collapsibleChevron { transform: rotate(45deg); }
14890
+ /* Animate height without measuring content; hide collapsed controls from focus and accessibility. */
14891
+ .dim-collapsibleBody { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .22s cubic-bezier(.4, 0, .2, 1); }
14892
+ .dim-collapsibleAccount.is-open > .dim-collapsibleBody { grid-template-rows: 1fr; }
14893
+ .dim-collapsibleBodyInner { min-height: 0; overflow: hidden; }
14894
+ .dim-collapsibleAccount:not(.is-open) .dim-collapsibleBodyInner { visibility: hidden; }
14720
14895
  .dim-panel .dim-botCardTop { min-width: 0; max-width: 100%; display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
14721
14896
  .dim-panel .dim-botIdentity { min-width: 0; flex: 1 1 0; display: flex; align-items: center; gap: 10px; }
14722
14897
  .dim-panel .dim-botAvatar { flex: none; width: 38px; height: 38px; display: grid; place-items: center; overflow: hidden; border-radius: 11px; box-shadow: none; }
@@ -14993,6 +15168,7 @@ var CSS11 = String.raw`
14993
15168
  @media (prefers-reduced-motion: reduce) {
14994
15169
  .dim-page * { transition-duration: .01ms !important; }
14995
15170
  .dim-directoryPickerSpinner { animation-duration: 1.8s; }
15171
+ .dim-collapsibleBody, .dim-collapsibleChevron { transition: none !important; }
14996
15172
  }
14997
15173
  `;
14998
15174
  function installImStyles() {
@@ -15010,7 +15186,7 @@ function installImStyles() {
15010
15186
  }
15011
15187
 
15012
15188
  // plugin-src/client/update-panel.js
15013
- var React25 = __toESM(require("react"), 1);
15189
+ var React26 = __toESM(require("react"), 1);
15014
15190
  var import_react_dom3 = require("react-dom");
15015
15191
  var import_valid = __toESM(require_valid(), 1);
15016
15192
  var import_rcompare = __toESM(require_rcompare(), 1);
@@ -15100,11 +15276,11 @@ function manualUpdateCommand(snapshot) {
15100
15276
  return `dsh plugin --profile ${profileArgument} add -w @xmanrui/dsh-im@${version}`;
15101
15277
  }
15102
15278
  function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
15103
- const [copyState, setCopyState] = React25.useState("idle");
15104
- const commandRef = React25.useRef(null);
15105
- const mounted = React25.useRef(false);
15106
- const copying = React25.useRef(false);
15107
- React25.useEffect(() => {
15279
+ const [copyState, setCopyState] = React26.useState("idle");
15280
+ const commandRef = React26.useRef(null);
15281
+ const mounted = React26.useRef(false);
15282
+ const copying = React26.useRef(false);
15283
+ React26.useEffect(() => {
15108
15284
  mounted.current = true;
15109
15285
  return () => {
15110
15286
  mounted.current = false;
@@ -15136,7 +15312,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
15136
15312
  { className: "dim-updateManual", "aria-label": "\u624B\u5DE5\u66F4\u65B0" },
15137
15313
  h2("h4", { className: "dim-updateManualHeading" }, "\u624B\u5DE5\u66F4\u65B0"),
15138
15314
  command ? h2(
15139
- React25.Fragment,
15315
+ React26.Fragment,
15140
15316
  null,
15141
15317
  h2("p", { className: "dim-updateManualHint" }, "\u81EA\u52A8\u66F4\u65B0\u5931\u8D25\u53EF\u4EE5\u4F7F\u7528\u547D\u4EE4\u66F4\u65B0\uFF1A"),
15142
15318
  h2(
@@ -15172,7 +15348,7 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
15172
15348
  "aria-hidden": "true",
15173
15349
  focusable: "false"
15174
15350
  }, copyState === "copied" ? h2("path", { d: "m4 10 4 4 8-8" }) : h2(
15175
- React25.Fragment,
15351
+ React26.Fragment,
15176
15352
  null,
15177
15353
  h2("rect", { x: 7, y: 7, width: 10, height: 11, rx: 1.5 }),
15178
15354
  h2("path", { d: "M5 13H3.5A1.5 1.5 0 0 1 2 11.5v-8A1.5 1.5 0 0 1 3.5 2h8A1.5 1.5 0 0 1 13 3.5V5" })
@@ -15197,10 +15373,10 @@ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
15197
15373
  );
15198
15374
  }
15199
15375
  function UpdateDialog({ children, onClose }) {
15200
- const dialogRef = React25.useRef(null);
15201
- const titleId = React25.useId();
15202
- const descriptionId = React25.useId();
15203
- React25.useEffect(() => {
15376
+ const dialogRef = React26.useRef(null);
15377
+ const titleId = React26.useId();
15378
+ const descriptionId = React26.useId();
15379
+ React26.useEffect(() => {
15204
15380
  const previous = globalThis.document?.activeElement;
15205
15381
  dialogRef.current?.focus?.();
15206
15382
  return () => {
@@ -15258,19 +15434,19 @@ function UpdateDialog({ children, onClose }) {
15258
15434
  return typeof document !== "undefined" && document.body ? (0, import_react_dom3.createPortal)(content, document.body) : content;
15259
15435
  }
15260
15436
  function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
15261
- const [snapshot, setSnapshot] = React25.useState(null);
15262
- const [action, setAction] = React25.useState("status");
15263
- const [error, setError] = React25.useState(null);
15264
- const [open, setOpen] = React25.useState(false);
15265
- const [uncertainInstall, setUncertainInstall] = React25.useState(false);
15266
- const mounted = React25.useRef(false);
15267
- const busy = React25.useRef(false);
15268
- const readController = React25.useRef(null);
15269
- const pollReadController = React25.useRef(null);
15270
- const installRequest = React25.useRef(null);
15271
- const onStatusRef = React25.useRef(onStatus);
15437
+ const [snapshot, setSnapshot] = React26.useState(null);
15438
+ const [action, setAction] = React26.useState("status");
15439
+ const [error, setError] = React26.useState(null);
15440
+ const [open, setOpen] = React26.useState(false);
15441
+ const [uncertainInstall, setUncertainInstall] = React26.useState(false);
15442
+ const mounted = React26.useRef(false);
15443
+ const busy = React26.useRef(false);
15444
+ const readController = React26.useRef(null);
15445
+ const pollReadController = React26.useRef(null);
15446
+ const installRequest = React26.useRef(null);
15447
+ const onStatusRef = React26.useRef(onStatus);
15272
15448
  onStatusRef.current = onStatus;
15273
- const accept = React25.useCallback((next) => {
15449
+ const accept = React26.useCallback((next) => {
15274
15450
  setSnapshot(next);
15275
15451
  onStatusRef.current?.(next);
15276
15452
  }, []);
@@ -15279,7 +15455,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
15279
15455
  setUncertainInstall(false);
15280
15456
  accept(next);
15281
15457
  };
15282
- const invoke = React25.useCallback(async (endpoint, payload = {}, signal) => {
15458
+ const invoke = React26.useCallback(async (endpoint, payload = {}, signal) => {
15283
15459
  if (typeof rpcCall !== "function") {
15284
15460
  const unavailable = new Error("\u5F53\u524D Host \u4E0D\u652F\u6301\u66F4\u65B0\u63A5\u53E3\uFF0C\u8BF7\u5148\u624B\u52A8\u66F4\u65B0\u63D2\u4EF6\u5E76\u91CD\u542F\u3002");
15285
15461
  unavailable.code = "update-unavailable";
@@ -15287,7 +15463,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
15287
15463
  }
15288
15464
  return unwrapSnapshot(await rpcCall(endpoint, payload, signal));
15289
15465
  }, [rpcCall]);
15290
- React25.useEffect(() => {
15466
+ React26.useEffect(() => {
15291
15467
  mounted.current = true;
15292
15468
  busy.current = true;
15293
15469
  const controller = new AbortController();
@@ -15310,7 +15486,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
15310
15486
  const activeJob = ACTIVE_STATES4.has(snapshot?.job?.state);
15311
15487
  const restartRequired = snapshot?.job?.state === "restart-required" || snapshot?.blockedReason === "pending-restart";
15312
15488
  const shouldPoll = activeJob || uncertainInstall;
15313
- React25.useEffect(() => {
15489
+ React26.useEffect(() => {
15314
15490
  if (!shouldPoll) return void 0;
15315
15491
  let controller;
15316
15492
  const scheduler = createPollScheduler({
@@ -15408,7 +15584,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
15408
15584
  const manualCommand = manualUpdateCommand(snapshot);
15409
15585
  const buttonLabel = action === "checking" ? "\u68C0\u67E5\u4E2D\u2026" : action === "starting" || activeJob ? "\u6B63\u5728\u66F4\u65B0\u2026" : restartRequired ? "\u5F85\u624B\u52A8\u91CD\u542F" : snapshot?.canInstall ? "\u66F4\u65B0\u81F3" : "\u68C0\u67E5\u66F4\u65B0";
15410
15586
  return h2(
15411
- React25.Fragment,
15587
+ React26.Fragment,
15412
15588
  null,
15413
15589
  h2("button", {
15414
15590
  type: "button",
@@ -15433,13 +15609,13 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
15433
15609
  h2("dt", null, "\u8FD0\u884C\u7248\u672C"),
15434
15610
  h2("dd", null, `v${snapshot?.runningVersion ?? clientVersion}`),
15435
15611
  snapshot?.installedVersion && snapshot.installedVersion !== snapshot.runningVersion ? h2(
15436
- React25.Fragment,
15612
+ React26.Fragment,
15437
15613
  null,
15438
15614
  h2("dt", null, "\u5DF2\u5B89\u88C5\u7248\u672C"),
15439
15615
  h2("dd", null, `v${snapshot.installedVersion}`)
15440
15616
  ) : null,
15441
15617
  targetVersion ? h2(
15442
- React25.Fragment,
15618
+ React26.Fragment,
15443
15619
  null,
15444
15620
  h2("dt", null, "\u76EE\u6807\u7248\u672C"),
15445
15621
  h2("dd", null, `v${targetVersion}`)
@@ -15644,23 +15820,23 @@ function IMSettingsTab({
15644
15820
  browserLocation = globalThis.location,
15645
15821
  navigateToRecoveryUrl = replacePageLocation
15646
15822
  }) {
15647
- const [selected, setSelected] = React26.useState("weixin");
15648
- const [loopbackRecovery, setLoopbackRecovery] = React26.useState(null);
15649
- const [runningVersion, setRunningVersion] = React26.useState(IM_PLUGIN_VERSION);
15650
- const [deliverySettings, setDeliverySettings] = React26.useState(null);
15651
- const githubTooltipId = React26.useId();
15652
- const generalSettingsTooltipId = React26.useId();
15823
+ const [selected, setSelected] = React27.useState("weixin");
15824
+ const [loopbackRecovery, setLoopbackRecovery] = React27.useState(null);
15825
+ const [runningVersion, setRunningVersion] = React27.useState(IM_PLUGIN_VERSION);
15826
+ const [deliverySettings, setDeliverySettings] = React27.useState(null);
15827
+ const githubTooltipId = React27.useId();
15828
+ const generalSettingsTooltipId = React27.useId();
15653
15829
  const globalSettingsSelected = selected === GLOBAL_SETTINGS_TAB_ID;
15654
15830
  const active = CHANNELS.find((channel4) => channel4.id === selected) ?? CHANNELS[0];
15655
15831
  const activeTabId = globalSettingsSelected ? "dim-general-settings-trigger" : `dim-tab-${active.id}`;
15656
15832
  const activePanelId = globalSettingsSelected ? `dim-panel-${GLOBAL_SETTINGS_TAB_ID}` : `dim-panel-${active.id}`;
15657
- const reportLoopbackRecovery = React26.useCallback((recovery) => {
15833
+ const reportLoopbackRecovery = React27.useCallback((recovery) => {
15658
15834
  setLoopbackRecovery((current) => current?.url === recovery.url ? current : recovery);
15659
15835
  }, []);
15660
- const reportUpdateStatus = React26.useCallback((snapshot) => {
15836
+ const reportUpdateStatus = React27.useCallback((snapshot) => {
15661
15837
  setRunningVersion(snapshot.runningVersion);
15662
15838
  }, []);
15663
- const rpcCalls = React26.useMemo(() => createLoopbackAwareRpcCalls({
15839
+ const rpcCalls = React27.useMemo(() => createLoopbackAwareRpcCalls({
15664
15840
  dingtalkRpcCall,
15665
15841
  discordRpcCall,
15666
15842
  feishuRpcCall,
@@ -15694,7 +15870,7 @@ function IMSettingsTab({
15694
15870
  weixinRpcCall,
15695
15871
  whatsappRpcCall
15696
15872
  ]);
15697
- const botSettingsContext = React26.useMemo(() => Object.freeze({
15873
+ const botSettingsContext = React27.useMemo(() => Object.freeze({
15698
15874
  openBotSettings: setDeliverySettings
15699
15875
  }), []);
15700
15876
  return h2(