@xmanrui/dsh-im 0.5.0 → 0.7.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
@@ -40,7 +40,7 @@ __export(index_exports, {
40
40
  name: () => name
41
41
  });
42
42
  module.exports = __toCommonJS(index_exports);
43
- var React15 = __toESM(require("react"), 1);
43
+ var React16 = __toESM(require("react"), 1);
44
44
 
45
45
  // plugin-src/client/channel-logos.js
46
46
  var React = __toESM(require("react"), 1);
@@ -355,7 +355,7 @@ function formatRemaining(milliseconds) {
355
355
  }
356
356
 
357
357
  // plugin-src/client/channels/dingtalk/index.js
358
- var React6 = __toESM(require("react"), 1);
358
+ var React7 = __toESM(require("react"), 1);
359
359
 
360
360
  // plugin-src/client/credential-binding.js
361
361
  var React3 = __toESM(require("react"), 1);
@@ -406,6 +406,20 @@ var EN = Object.freeze({
406
406
  "\u6D88\u606F\u901A\u9053": "Message channel",
407
407
  "\u6700\u8FD1\u68C0\u67E5": "Last checked",
408
408
  "\u5F53\u524D\u5DE5\u4F5C\u533A": "Current workspace",
409
+ "\u9009\u62E9\u76EE\u5F55": "Choose folder",
410
+ "\u9009\u62E9\u673A\u5668\u4EBA\u5DE5\u4F5C\u533A\u76EE\u5F55": "Select bot workspace folder",
411
+ "\u5F53\u524D\u76EE\u5F55": "Current folder",
412
+ "\u4E3B\u76EE\u5F55": "Home",
413
+ "\u6B63\u5728\u51C6\u5907\u76EE\u5F55\u9009\u62E9\u5668\u2026": "Preparing folder picker\u2026",
414
+ "\u6B63\u5728\u8BFB\u53D6\u76EE\u5F55\u2026": "Loading folders\u2026",
415
+ "\u8FD9\u4E2A\u76EE\u5F55\u4E2D\u6CA1\u6709\u5B50\u6587\u4EF6\u5939\u3002": "This folder has no subfolders.",
416
+ "\u6B64\u76EE\u5F55\u7684\u5B50\u6587\u4EF6\u5939\u8FC7\u591A\uFF0C\u4EC5\u663E\u793A\u524D\u4E00\u90E8\u5206\u3002": "This folder has too many subfolders; only the first group is shown.",
417
+ "\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\uFF0C\u8BF7\u91CD\u8BD5\u3002": "Could not load the folder. Try again.",
418
+ "\u91CD\u8BD5": "Retry",
419
+ "\u663E\u793A\u9690\u85CF\u6587\u4EF6\u5939": "Show hidden folders",
420
+ "\u5207\u6362\u540E\u4F1A\u6E05\u9664\u8FD9\u4E2A\u673A\u5668\u4EBA\u7684\u65E7\u4F1A\u8BDD\u6620\u5C04\u3002": "Switching clears this bot\u2019s previous session mappings.",
421
+ "\u5207\u6362\u4E2D\u2026": "Switching\u2026",
422
+ "\u9009\u62E9\u6B64\u76EE\u5F55": "Select this folder",
409
423
  "\u5DE5\u4F5C\u533A\u7EDD\u5BF9\u8DEF\u5F84": "Absolute workspace path",
410
424
  "/\u7EDD\u5BF9\u8DEF\u5F84/\u5230/\u5DE5\u4F5C\u533A": "/absolute/path/to/workspace",
411
425
  "\u4FEE\u6539": "Change",
@@ -963,54 +977,298 @@ function CredentialBindingPanel({
963
977
  }
964
978
 
965
979
  // plugin-src/client/workspace-editor.js
980
+ var React5 = __toESM(require("react"), 1);
981
+
982
+ // plugin-src/client/workspace-directory-picker.js
966
983
  var React4 = __toESM(require("react"), 1);
967
- function looksLikeAbsolutePath(value) {
968
- return value.startsWith("/") || /^[A-Za-z]:[\\/]/.test(value) || /^\\\\/.test(value);
984
+ var import_react_dom = require("react-dom");
985
+ function pickerErrorCode(error) {
986
+ return error?.rpcError?.code ?? error?.code;
987
+ }
988
+ function pickerErrorDetails(error) {
989
+ return error?.rpcError?.details ?? error?.details;
990
+ }
991
+ function pickerErrorMessage(error) {
992
+ return error?.rpcError?.message ?? error?.message ?? "\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\uFF0C\u8BF7\u91CD\u8BD5\u3002";
969
993
  }
970
- function WorkspaceEditor({ workspace, disabled = false, onSave }) {
971
- const [editing, setEditing] = React4.useState(false);
972
- const [draft, setDraft] = React4.useState(workspace ?? "");
973
- const [saving, setSaving] = React4.useState(false);
994
+ function FolderIcon() {
995
+ return React4.createElement(
996
+ "svg",
997
+ {
998
+ viewBox: "0 0 24 24",
999
+ fill: "none",
1000
+ stroke: "currentColor",
1001
+ strokeWidth: 1.8,
1002
+ strokeLinecap: "round",
1003
+ strokeLinejoin: "round",
1004
+ "aria-hidden": "true"
1005
+ },
1006
+ React4.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" })
1007
+ );
1008
+ }
1009
+ function ChevronIcon() {
1010
+ return React4.createElement("svg", {
1011
+ viewBox: "0 0 20 20",
1012
+ fill: "none",
1013
+ stroke: "currentColor",
1014
+ strokeWidth: 1.7,
1015
+ strokeLinecap: "round",
1016
+ strokeLinejoin: "round",
1017
+ "aria-hidden": "true"
1018
+ }, React4.createElement("path", { d: "m7.5 4.5 5 5.5-5 5.5" }));
1019
+ }
1020
+ function displayCrumbs(listing) {
1021
+ const homeIndex = listing.crumbs.findIndex((crumb) => crumb.path === listing.home);
1022
+ if (homeIndex < 0) return listing.crumbs;
1023
+ return listing.crumbs.slice(homeIndex);
1024
+ }
1025
+ function WorkspaceDirectoryPicker({
1026
+ open,
1027
+ startPath,
1028
+ picker,
1029
+ busy = false,
1030
+ saveError = null,
1031
+ onPicked,
1032
+ onCancel
1033
+ }) {
1034
+ const [listing, setListing] = React4.useState(null);
1035
+ const [loading, setLoading] = React4.useState(false);
974
1036
  const [error, setError] = React4.useState(null);
975
- const inputRef = React4.useRef(null);
976
- const editButtonRef = React4.useRef(null);
977
- const restoreFocus = React4.useRef(false);
978
- React4.useEffect(() => {
979
- if (!editing) setDraft(workspace ?? "");
980
- }, [workspace, editing]);
981
- React4.useEffect(() => {
982
- if (editing) inputRef.current?.focus();
983
- else if (restoreFocus.current) {
984
- restoreFocus.current = false;
985
- editButtonRef.current?.focus();
1037
+ const [showHidden, setShowHidden] = React4.useState(false);
1038
+ const [retryKey, setRetryKey] = React4.useState(0);
1039
+ const requestRef = React4.useRef(0);
1040
+ const controllerRef = React4.useRef(null);
1041
+ const dialogRef = React4.useRef(null);
1042
+ const bodyRef = React4.useRef(null);
1043
+ const titleId = React4.useId();
1044
+ const noticeId = React4.useId();
1045
+ const initialPathRef = React4.useRef(startPath);
1046
+ const onPickedRef = React4.useRef(onPicked);
1047
+ const onCancelRef = React4.useRef(onCancel);
1048
+ const busyRef = React4.useRef(busy);
1049
+ onPickedRef.current = onPicked;
1050
+ onCancelRef.current = onCancel;
1051
+ busyRef.current = busy;
1052
+ const loadDirectory = React4.useCallback(async (path, { reportError = true } = {}) => {
1053
+ const request = requestRef.current + 1;
1054
+ requestRef.current = request;
1055
+ controllerRef.current?.abort();
1056
+ const controller = new AbortController();
1057
+ controllerRef.current = controller;
1058
+ setLoading(true);
1059
+ if (reportError) setError(null);
1060
+ try {
1061
+ const next = await picker.listDirectory(path, controller.signal);
1062
+ if (request !== requestRef.current || controller.signal.aborted) return { aborted: true };
1063
+ if (bodyRef.current) bodyRef.current.scrollTop = 0;
1064
+ setListing(next);
1065
+ setError(null);
1066
+ return { value: next };
1067
+ } catch (cause) {
1068
+ if (request !== requestRef.current || controller.signal.aborted) return { aborted: true };
1069
+ if (reportError) setError(pickerErrorMessage(cause));
1070
+ return { error: cause };
1071
+ } finally {
1072
+ if (request === requestRef.current) setLoading(false);
986
1073
  }
987
- }, [editing]);
988
- const cancel = () => {
989
- setDraft(workspace ?? "");
1074
+ }, [picker]);
1075
+ React4.useEffect(() => {
1076
+ if (!open) return void 0;
1077
+ let active = true;
1078
+ setListing(null);
990
1079
  setError(null);
991
- restoreFocus.current = true;
992
- setEditing(false);
993
- };
994
- const submit = async (event) => {
995
- event.preventDefault();
996
- const value = draft.trim();
997
- if (!value || saving || disabled) return;
998
- if (!looksLikeAbsolutePath(value)) {
999
- setError("\u5DE5\u4F5C\u533A\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84\u3002");
1080
+ setShowHidden(false);
1081
+ dialogRef.current?.focus?.();
1082
+ const handleKeyDown = (event) => {
1083
+ if (event.key === "Escape" && !busyRef.current) onCancelRef.current?.();
1084
+ };
1085
+ if (typeof document !== "undefined") document.addEventListener("keydown", handleKeyDown);
1086
+ const start = async () => {
1087
+ const initialPath = initialPathRef.current;
1088
+ const initial = await loadDirectory(initialPath || void 0, { reportError: false });
1089
+ if (!active || initial.aborted || initial.value) return;
1090
+ const code = pickerErrorCode(initial.error);
1091
+ const details = pickerErrorDetails(initial.error);
1092
+ if (code === "directory-picker-unavailable" && details?.capability === "native" && typeof picker.pickDirectory === "function") {
1093
+ setLoading(true);
1094
+ try {
1095
+ const selected = await picker.pickDirectory();
1096
+ if (!active) return;
1097
+ if (selected !== null) await onPickedRef.current?.(selected);
1098
+ else onCancelRef.current?.();
1099
+ } catch (cause) {
1100
+ if (active) setError(pickerErrorMessage(cause));
1101
+ } finally {
1102
+ if (active) setLoading(false);
1103
+ }
1104
+ return;
1105
+ }
1106
+ if (initialPath && code === "directory-unreadable") {
1107
+ const home = await loadDirectory(void 0, { reportError: false });
1108
+ if (!active || home.aborted || home.value) return;
1109
+ setError(pickerErrorMessage(home.error));
1110
+ return;
1111
+ }
1112
+ setError(pickerErrorMessage(initial.error));
1113
+ };
1114
+ void start();
1115
+ return () => {
1116
+ active = false;
1117
+ if (typeof document !== "undefined") document.removeEventListener("keydown", handleKeyDown);
1118
+ requestRef.current += 1;
1119
+ controllerRef.current?.abort();
1120
+ };
1121
+ }, [loadDirectory, open, picker, retryKey]);
1122
+ if (!open) return null;
1123
+ const entries = (listing?.entries ?? []).filter((entry) => showHidden || !entry.hidden);
1124
+ const crumbs = listing ? displayCrumbs(listing) : [];
1125
+ const presentedError = saveError ?? error;
1126
+ const content = h2(
1127
+ "div",
1128
+ {
1129
+ className: "dim-directoryPickerBackdrop",
1130
+ onMouseDown: (event) => {
1131
+ if (event.target === event.currentTarget && !busy) onCancel();
1132
+ }
1133
+ },
1134
+ h2(
1135
+ "section",
1136
+ {
1137
+ ref: dialogRef,
1138
+ className: "dim-directoryPicker",
1139
+ role: "dialog",
1140
+ "aria-modal": "true",
1141
+ "aria-labelledby": titleId,
1142
+ "aria-describedby": noticeId,
1143
+ tabIndex: -1
1144
+ },
1145
+ h2(
1146
+ "header",
1147
+ { className: "dim-directoryPickerHeader" },
1148
+ h2("h3", { id: titleId }, "\u9009\u62E9\u673A\u5668\u4EBA\u5DE5\u4F5C\u533A\u76EE\u5F55"),
1149
+ listing ? h2(
1150
+ "nav",
1151
+ { className: "dim-directoryCrumbs", "aria-label": "\u5F53\u524D\u76EE\u5F55" },
1152
+ crumbs.map((crumb, index) => h2(
1153
+ React4.Fragment,
1154
+ { key: crumb.path },
1155
+ index > 0 ? h2("span", { className: "dim-directoryCrumbSeparator", "aria-hidden": "true" }, "\u203A") : null,
1156
+ React4.createElement("button", {
1157
+ type: "button",
1158
+ title: crumb.path,
1159
+ disabled: loading || busy,
1160
+ "aria-current": index === crumbs.length - 1 ? "page" : void 0,
1161
+ onClick: () => void loadDirectory(crumb.path)
1162
+ }, crumb.path === listing.home ? h2("span", null, "\u4E3B\u76EE\u5F55") : crumb.name || crumb.path)
1163
+ ))
1164
+ ) : h2("p", null, "\u6B63\u5728\u51C6\u5907\u76EE\u5F55\u9009\u62E9\u5668\u2026")
1165
+ ),
1166
+ h2(
1167
+ "div",
1168
+ { ref: bodyRef, className: "dim-directoryPickerBody", "aria-busy": loading },
1169
+ loading && !listing ? h2(
1170
+ "div",
1171
+ { className: "dim-directoryPickerState" },
1172
+ h2("span", { className: "dim-directoryPickerSpinner", "aria-hidden": "true" }),
1173
+ h2("p", null, "\u6B63\u5728\u8BFB\u53D6\u76EE\u5F55\u2026")
1174
+ ) : listing ? entries.length > 0 ? h2("ul", { className: "dim-directoryList" }, entries.map((entry) => h2(
1175
+ "li",
1176
+ { key: entry.path },
1177
+ React4.createElement(
1178
+ "button",
1179
+ {
1180
+ type: "button",
1181
+ title: entry.path,
1182
+ disabled: loading || busy,
1183
+ onClick: () => void loadDirectory(entry.path)
1184
+ },
1185
+ h2("span", { className: "dim-directoryFolder" }, h2(FolderIcon)),
1186
+ React4.createElement("span", { className: "dim-directoryName" }, entry.name),
1187
+ h2("span", { className: "dim-directoryChevron" }, h2(ChevronIcon))
1188
+ )
1189
+ ))) : h2(
1190
+ "div",
1191
+ { className: "dim-directoryPickerState" },
1192
+ h2("p", null, "\u8FD9\u4E2A\u76EE\u5F55\u4E2D\u6CA1\u6709\u5B50\u6587\u4EF6\u5939\u3002")
1193
+ ) : null,
1194
+ listing?.truncated ? h2("p", { className: "dim-directoryPickerTruncated" }, "\u6B64\u76EE\u5F55\u7684\u5B50\u6587\u4EF6\u5939\u8FC7\u591A\uFF0C\u4EC5\u663E\u793A\u524D\u4E00\u90E8\u5206\u3002") : null,
1195
+ presentedError ? h2(
1196
+ "div",
1197
+ { className: "dim-directoryPickerError", role: "alert" },
1198
+ h2("span", null, presentedError),
1199
+ !listing && !busy ? h2("button", {
1200
+ type: "button",
1201
+ onClick: () => setRetryKey((value) => value + 1)
1202
+ }, "\u91CD\u8BD5") : null
1203
+ ) : null
1204
+ ),
1205
+ h2(
1206
+ "footer",
1207
+ { className: "dim-directoryPickerFooter" },
1208
+ h2(
1209
+ "button",
1210
+ {
1211
+ type: "button",
1212
+ className: "dim-directoryHidden",
1213
+ "aria-pressed": showHidden,
1214
+ onClick: () => setShowHidden((value) => !value),
1215
+ disabled: busy || !listing
1216
+ },
1217
+ h2("span", { className: "dim-directoryHiddenBox", "aria-hidden": "true" }),
1218
+ h2("span", null, "\u663E\u793A\u9690\u85CF\u6587\u4EF6\u5939")
1219
+ ),
1220
+ h2("p", { id: noticeId, className: "dim-directoryPickerNotice" }, "\u5207\u6362\u540E\u4F1A\u6E05\u9664\u8FD9\u4E2A\u673A\u5668\u4EBA\u7684\u65E7\u4F1A\u8BDD\u6620\u5C04\u3002"),
1221
+ h2(
1222
+ "div",
1223
+ { className: "dim-directoryPickerActions" },
1224
+ h2("button", { type: "button", onClick: onCancel, disabled: busy }, "\u53D6\u6D88"),
1225
+ h2("button", {
1226
+ type: "button",
1227
+ className: "dim-directoryPickerPrimary",
1228
+ disabled: busy || loading || !listing,
1229
+ onClick: () => listing && void onPicked(listing.path)
1230
+ }, busy ? "\u5207\u6362\u4E2D\u2026" : "\u9009\u62E9\u6B64\u76EE\u5F55")
1231
+ )
1232
+ )
1233
+ )
1234
+ );
1235
+ return typeof document === "undefined" ? content : (0, import_react_dom.createPortal)(content, document.body);
1236
+ }
1237
+
1238
+ // plugin-src/client/workspace-editor.js
1239
+ var WorkspaceDirectoryPickerContext = React5.createContext(null);
1240
+ function WorkspaceEditor({ workspace, directoryPicker, disabled = false, onSave }) {
1241
+ const sharedDirectoryPicker = React5.useContext(WorkspaceDirectoryPickerContext);
1242
+ const activeDirectoryPicker = directoryPicker ?? sharedDirectoryPicker;
1243
+ const [open, setOpen] = React5.useState(false);
1244
+ const [saving, setSaving] = React5.useState(false);
1245
+ const [error, setError] = React5.useState(null);
1246
+ const editButtonRef = React5.useRef(null);
1247
+ const savingRef = React5.useRef(false);
1248
+ const close = React5.useCallback(() => {
1249
+ setOpen(false);
1250
+ setError(null);
1251
+ queueMicrotask(() => editButtonRef.current?.focus?.());
1252
+ }, []);
1253
+ const pick = React5.useCallback(async (value) => {
1254
+ if (!value || savingRef.current || disabled) return;
1255
+ if (value === workspace) {
1256
+ close();
1000
1257
  return;
1001
1258
  }
1259
+ savingRef.current = true;
1002
1260
  setSaving(true);
1003
1261
  setError(null);
1004
1262
  try {
1005
1263
  await onSave?.(value);
1006
- restoreFocus.current = true;
1007
- setEditing(false);
1264
+ close();
1008
1265
  } catch (cause) {
1009
1266
  setError(cause?.message ?? "\u5DE5\u4F5C\u533A\u4FEE\u6539\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002");
1010
1267
  } finally {
1268
+ savingRef.current = false;
1011
1269
  setSaving(false);
1012
1270
  }
1013
- };
1271
+ }, [close, disabled, onSave, workspace]);
1014
1272
  return h2(
1015
1273
  "div",
1016
1274
  { className: "dim-workspace" },
@@ -1018,55 +1276,38 @@ function WorkspaceEditor({ workspace, disabled = false, onSave }) {
1018
1276
  "div",
1019
1277
  { className: "dim-workspaceHeader" },
1020
1278
  h2("span", null, "\u5F53\u524D\u5DE5\u4F5C\u533A"),
1021
- editing ? null : h2("button", {
1279
+ h2("button", {
1022
1280
  type: "button",
1023
1281
  ref: editButtonRef,
1024
1282
  className: "dim-workspaceEdit",
1025
1283
  onClick: () => {
1026
- setEditing(true);
1284
+ setOpen(true);
1027
1285
  setError(null);
1028
1286
  },
1029
- disabled
1030
- }, "\u4FEE\u6539")
1287
+ disabled: disabled || !activeDirectoryPicker
1288
+ }, "\u9009\u62E9\u76EE\u5F55")
1031
1289
  ),
1032
- editing ? h2(
1033
- "form",
1034
- { className: "dim-workspaceForm", onSubmit: submit },
1035
- h2("input", {
1036
- ref: inputRef,
1037
- value: draft,
1038
- onChange: (event) => setDraft(event.target.value),
1039
- placeholder: "/\u7EDD\u5BF9\u8DEF\u5F84/\u5230/\u5DE5\u4F5C\u533A",
1040
- "aria-label": "\u5DE5\u4F5C\u533A\u7EDD\u5BF9\u8DEF\u5F84",
1041
- autoCapitalize: "none",
1042
- autoCorrect: "off",
1043
- spellCheck: false,
1044
- maxLength: 4096,
1045
- required: true,
1046
- disabled: saving || disabled
1047
- }),
1048
- h2(
1049
- "div",
1050
- { className: "dim-workspaceActions" },
1051
- h2("button", {
1052
- type: "submit",
1053
- disabled: saving || disabled || !draft.trim()
1054
- }, saving ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58"),
1055
- h2("button", { type: "button", onClick: cancel, disabled: saving || disabled }, "\u53D6\u6D88")
1056
- ),
1057
- error ? h2("p", { className: "dim-workspaceError", role: "alert" }, error) : null
1058
- ) : workspace ? React4.createElement("code", {
1290
+ workspace ? React5.createElement("code", {
1059
1291
  className: "dim-workspacePath",
1060
1292
  title: workspace
1061
- }, workspace) : h2("code", { className: "dim-workspacePath" }, "\u672A\u8BBE\u7F6E")
1293
+ }, workspace) : h2("code", { className: "dim-workspacePath" }, "\u672A\u8BBE\u7F6E"),
1294
+ open ? h2(WorkspaceDirectoryPicker, {
1295
+ open,
1296
+ startPath: workspace,
1297
+ picker: activeDirectoryPicker,
1298
+ busy: saving || disabled,
1299
+ saveError: error,
1300
+ onPicked: pick,
1301
+ onCancel: close
1302
+ }) : null
1062
1303
  );
1063
1304
  }
1064
1305
 
1065
1306
  // plugin-src/client/workspace-snapshot-fence.js
1066
- var React5 = __toESM(require("react"), 1);
1307
+ var React6 = __toESM(require("react"), 1);
1067
1308
  function useWorkspaceSnapshotFence() {
1068
- const state = React5.useRef({ version: 0, pendingMutations: 0 });
1069
- return React5.useMemo(() => Object.freeze({
1309
+ const state = React6.useRef({ version: 0, pendingMutations: 0 });
1310
+ return React6.useMemo(() => Object.freeze({
1070
1311
  beginStatus() {
1071
1312
  return state.current.pendingMutations === 0 ? state.current.version : null;
1072
1313
  },
@@ -1246,7 +1487,7 @@ function DingtalkIcon({ size = 28 }) {
1246
1487
  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"
1247
1488
  }));
1248
1489
  }
1249
- var Button = React6.forwardRef(function Button2({ children, kind = "secondary", className = "", ...props }, ref) {
1490
+ var Button = React7.forwardRef(function Button2({ children, kind = "secondary", className = "", ...props }, ref) {
1250
1491
  return h2("button", {
1251
1492
  ...props,
1252
1493
  ref,
@@ -1342,13 +1583,13 @@ function EmptyView({ busy, onStart }) {
1342
1583
  );
1343
1584
  }
1344
1585
  function QrPanel({ provision, now, busy, onRefresh, onCancel }) {
1345
- const [imageFailed, setImageFailed] = React6.useState(false);
1586
+ const [imageFailed, setImageFailed] = React7.useState(false);
1346
1587
  const source = safeQrSource(provision.qrCodeDataUrl);
1347
1588
  const remaining = Math.max(0, provision.expiresAt - now);
1348
1589
  const expired = remaining === 0 || provision.status === "expired";
1349
1590
  const duration = Math.max(1, provision.durationMs ?? 10 * 6e4);
1350
1591
  const progress = Math.round(Math.min(1, remaining / duration) * 100);
1351
- React6.useEffect(() => setImageFailed(false), [source]);
1592
+ React7.useEffect(() => setImageFailed(false), [source]);
1352
1593
  return h2(
1353
1594
  "div",
1354
1595
  { className: "ddt-card dim-surfaceCard" },
@@ -1465,8 +1706,8 @@ function checkedTime(value) {
1465
1706
  }
1466
1707
  }
1467
1708
  function RemoveConfirmation({ account, busy, onConfirm, onCancel }) {
1468
- const cancelRef = React6.useRef(null);
1469
- React6.useEffect(() => cancelRef.current?.focus(), []);
1709
+ const cancelRef = React7.useRef(null);
1710
+ React7.useEffect(() => cancelRef.current?.focus(), []);
1470
1711
  return h2(
1471
1712
  "div",
1472
1713
  {
@@ -1608,28 +1849,28 @@ function AccountList(props) {
1608
1849
  }
1609
1850
  var EMPTY_TOTALS = Object.freeze({ configured: 0, connected: 0 });
1610
1851
  function DingtalkSettingsTab({ rpcCall }) {
1611
- const [model, setModel] = React6.useState({
1852
+ const [model, setModel] = React7.useState({
1612
1853
  phase: "loading",
1613
1854
  bots: [],
1614
1855
  totals: EMPTY_TOTALS,
1615
1856
  revision: 0,
1616
1857
  error: null
1617
1858
  });
1618
- const [provision, setProvision] = React6.useState(null);
1619
- const [busy, setBusy] = React6.useState(false);
1620
- const [busyByBot, setBusyByBot] = React6.useState({});
1621
- const [removeTarget, setRemoveTarget] = React6.useState(null);
1622
- const [credentialOpen, setCredentialOpen] = React6.useState(false);
1623
- const [credentialError, setCredentialError] = React6.useState(null);
1624
- const [notice, setNotice] = React6.useState("");
1625
- const [now, setNow] = React6.useState(() => Date.now());
1626
- const addButtonRef = React6.useRef(null);
1627
- const mountedRef = React6.useRef(true);
1628
- const statusRequestRef = React6.useRef(0);
1859
+ const [provision, setProvision] = React7.useState(null);
1860
+ const [busy, setBusy] = React7.useState(false);
1861
+ const [busyByBot, setBusyByBot] = React7.useState({});
1862
+ const [removeTarget, setRemoveTarget] = React7.useState(null);
1863
+ const [credentialOpen, setCredentialOpen] = React7.useState(false);
1864
+ const [credentialError, setCredentialError] = React7.useState(null);
1865
+ const [notice, setNotice] = React7.useState("");
1866
+ const [now, setNow] = React7.useState(() => Date.now());
1867
+ const addButtonRef = React7.useRef(null);
1868
+ const mountedRef = React7.useRef(true);
1869
+ const statusRequestRef = React7.useRef(0);
1629
1870
  const workspaceFence = useWorkspaceSnapshotFence();
1630
- const noticeFrameRef = React6.useRef(null);
1631
- const focusFrameRef = React6.useRef(null);
1632
- React6.useEffect(() => {
1871
+ const noticeFrameRef = React7.useRef(null);
1872
+ const focusFrameRef = React7.useRef(null);
1873
+ React7.useEffect(() => {
1633
1874
  mountedRef.current = true;
1634
1875
  return () => {
1635
1876
  mountedRef.current = false;
@@ -1644,8 +1885,8 @@ function DingtalkSettingsTab({ rpcCall }) {
1644
1885
  }
1645
1886
  };
1646
1887
  }, []);
1647
- React6.useEffect(() => installDingtalkStyles(), []);
1648
- const announce = React6.useCallback((message) => {
1888
+ React7.useEffect(() => installDingtalkStyles(), []);
1889
+ const announce = React7.useCallback((message) => {
1649
1890
  if (!mountedRef.current) return;
1650
1891
  if (noticeFrameRef.current !== null) {
1651
1892
  window.cancelAnimationFrame(noticeFrameRef.current);
@@ -1659,7 +1900,7 @@ function DingtalkSettingsTab({ rpcCall }) {
1659
1900
  });
1660
1901
  }
1661
1902
  }, []);
1662
- const focusAddButton = React6.useCallback(() => {
1903
+ const focusAddButton = React7.useCallback(() => {
1663
1904
  if (!mountedRef.current) return;
1664
1905
  if (focusFrameRef.current !== null) window.cancelAnimationFrame(focusFrameRef.current);
1665
1906
  focusFrameRef.current = window.requestAnimationFrame(() => {
@@ -1667,11 +1908,11 @@ function DingtalkSettingsTab({ rpcCall }) {
1667
1908
  if (mountedRef.current) addButtonRef.current?.focus();
1668
1909
  });
1669
1910
  }, []);
1670
- const invoke = React6.useCallback(async (endpoint, payload = {}, signal) => {
1911
+ const invoke = React7.useCallback(async (endpoint, payload = {}, signal) => {
1671
1912
  if (typeof rpcCall !== "function") throw new TypeError("\u9489\u9489\u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
1672
1913
  return unwrapRpcResult(await rpcCall(endpoint, payload, signal));
1673
1914
  }, [rpcCall]);
1674
- const loadStatus = React6.useCallback(async ({
1915
+ const loadStatus = React7.useCallback(async ({
1675
1916
  signal,
1676
1917
  silent = false,
1677
1918
  restoreProvisioning = false
@@ -1713,12 +1954,12 @@ function DingtalkSettingsTab({ rpcCall }) {
1713
1954
  return void 0;
1714
1955
  }
1715
1956
  }, [invoke, workspaceFence]);
1716
- React6.useEffect(() => {
1957
+ React7.useEffect(() => {
1717
1958
  const controller = new AbortController();
1718
1959
  void loadStatus({ signal: controller.signal, restoreProvisioning: true });
1719
1960
  return () => controller.abort();
1720
1961
  }, [loadStatus]);
1721
- React6.useEffect(() => {
1962
+ React7.useEffect(() => {
1722
1963
  if (model.phase !== "ready") return void 0;
1723
1964
  const controller = new AbortController();
1724
1965
  let running = false;
@@ -1737,14 +1978,14 @@ function DingtalkSettingsTab({ rpcCall }) {
1737
1978
  window.clearInterval(timer);
1738
1979
  };
1739
1980
  }, [loadStatus, model.phase]);
1740
- React6.useEffect(() => {
1981
+ React7.useEffect(() => {
1741
1982
  if (!provision || !ACTIVE_PROVISION_STATES.has(provision.status)) return void 0;
1742
1983
  const timer = window.setInterval(() => {
1743
1984
  if (mountedRef.current) setNow(Date.now());
1744
1985
  }, 1e3);
1745
1986
  return () => window.clearInterval(timer);
1746
1987
  }, [provision?.attemptId, provision?.status]);
1747
- const startProvisioning = React6.useCallback(async ({ replace = false } = {}) => {
1988
+ const startProvisioning = React7.useCallback(async ({ replace = false } = {}) => {
1748
1989
  if (!mountedRef.current) return;
1749
1990
  setCredentialOpen(false);
1750
1991
  setCredentialError(null);
@@ -1782,7 +2023,7 @@ function DingtalkSettingsTab({ rpcCall }) {
1782
2023
  if (mountedRef.current) setBusy(false);
1783
2024
  }
1784
2025
  }, [announce, invoke, provision?.attemptId]);
1785
- const bindCredentials = React6.useCallback(async ({ identity, secret }) => {
2026
+ const bindCredentials = React7.useCallback(async ({ identity, secret }) => {
1786
2027
  if (!mountedRef.current) return;
1787
2028
  const snapshotVersion = workspaceFence.beginMutation();
1788
2029
  setBusy(true);
@@ -1812,7 +2053,7 @@ function DingtalkSettingsTab({ rpcCall }) {
1812
2053
  if (mountedRef.current) setBusy(false);
1813
2054
  }
1814
2055
  }, [announce, invoke, loadStatus, workspaceFence]);
1815
- const cancelProvisioning = React6.useCallback(async () => {
2056
+ const cancelProvisioning = React7.useCallback(async () => {
1816
2057
  if (!mountedRef.current) return;
1817
2058
  setBusy(true);
1818
2059
  try {
@@ -1830,7 +2071,7 @@ function DingtalkSettingsTab({ rpcCall }) {
1830
2071
  if (mountedRef.current) setBusy(false);
1831
2072
  }
1832
2073
  }, [announce, focusAddButton, invoke, provision?.attemptId, provision?.status]);
1833
- React6.useEffect(() => {
2074
+ React7.useEffect(() => {
1834
2075
  const attemptId = provision?.attemptId;
1835
2076
  if (!attemptId || !ACTIVE_PROVISION_STATES.has(provision.status)) return void 0;
1836
2077
  const controller = new AbortController();
@@ -1889,7 +2130,7 @@ function DingtalkSettingsTab({ rpcCall }) {
1889
2130
  timer = null;
1890
2131
  };
1891
2132
  }, [announce, invoke, loadStatus, provision?.attemptId, provision?.pollIntervalMs, provision?.status]);
1892
- const setBotBusy = React6.useCallback((botId, operation) => {
2133
+ const setBotBusy = React7.useCallback((botId, operation) => {
1893
2134
  if (!mountedRef.current) return;
1894
2135
  setBusyByBot((current) => {
1895
2136
  const next = { ...current };
@@ -1898,7 +2139,7 @@ function DingtalkSettingsTab({ rpcCall }) {
1898
2139
  return next;
1899
2140
  });
1900
2141
  }, []);
1901
- const runBotAction = React6.useCallback(async ({ account, operation, endpoint, payload, success }) => {
2142
+ const runBotAction = React7.useCallback(async ({ account, operation, endpoint, payload, success }) => {
1902
2143
  if (!mountedRef.current) return void 0;
1903
2144
  const snapshotVersion = workspaceFence.beginMutation();
1904
2145
  setBotBusy(account.botId, operation);
@@ -1926,14 +2167,14 @@ function DingtalkSettingsTab({ rpcCall }) {
1926
2167
  if (mountedRef.current) setBotBusy(account.botId, null);
1927
2168
  }
1928
2169
  }, [announce, invoke, loadStatus, setBotBusy, workspaceFence]);
1929
- const reconnect = React6.useCallback((account) => runBotAction({
2170
+ const reconnect = React7.useCallback((account) => runBotAction({
1930
2171
  account,
1931
2172
  operation: "reconnect",
1932
2173
  endpoint: DINGTALK_ENDPOINTS.reconnectBot,
1933
2174
  payload: { botId: account.botId },
1934
2175
  success: (snapshot) => snapshot?.bots.find((bot) => bot.botId === account.botId)?.connected ? "\u9489\u9489\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\u3002" : "\u9489\u9489\u4ECD\u672A\u8FDE\u63A5\uFF0C\u63D2\u4EF6\u4F1A\u7EE7\u7EED\u81EA\u52A8\u91CD\u8BD5\u3002"
1935
2176
  }), [runBotAction]);
1936
- const saveWorkspace = React6.useCallback(async (account, workspace) => {
2177
+ const saveWorkspace = React7.useCallback(async (account, workspace) => {
1937
2178
  const workspaceVersion = workspaceFence.beginMutation();
1938
2179
  setBotBusy(account.botId, "workspace");
1939
2180
  try {
@@ -1956,7 +2197,7 @@ function DingtalkSettingsTab({ rpcCall }) {
1956
2197
  if (mountedRef.current) setBotBusy(account.botId, null);
1957
2198
  }
1958
2199
  }, [invoke, loadStatus, setBotBusy, workspaceFence]);
1959
- const remove = React6.useCallback(async (account) => {
2200
+ const remove = React7.useCallback(async (account) => {
1960
2201
  const snapshot = await runBotAction({
1961
2202
  account,
1962
2203
  operation: "delete",
@@ -2038,7 +2279,7 @@ function DingtalkSettingsTab({ rpcCall }) {
2038
2279
  h2(Button, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
2039
2280
  )
2040
2281
  ) : h2(
2041
- React6.Fragment,
2282
+ React7.Fragment,
2042
2283
  null,
2043
2284
  credentialView,
2044
2285
  provisionView,
@@ -2148,8 +2389,8 @@ var normalizeSnapshot2 = api.normalizeSnapshot;
2148
2389
  var presentError2 = api.presentError;
2149
2390
 
2150
2391
  // plugin-src/client/channels/shared/token-channel.js
2151
- var React7 = __toESM(require("react"), 1);
2152
- var Button3 = React7.forwardRef(function Button4({ children, kind = "secondary", className = "", ...props }, ref) {
2392
+ var React8 = __toESM(require("react"), 1);
2393
+ var Button3 = React8.forwardRef(function Button4({ children, kind = "secondary", className = "", ...props }, ref) {
2153
2394
  return h2("button", {
2154
2395
  ...props,
2155
2396
  ref,
@@ -2290,20 +2531,20 @@ function createTokenChannelSettings(definition) {
2290
2531
  );
2291
2532
  }
2292
2533
  function SettingsTab({ rpcCall }) {
2293
- const [model, setModel] = React7.useState({
2534
+ const [model, setModel] = React8.useState({
2294
2535
  phase: "loading",
2295
2536
  bots: [],
2296
2537
  totals: { configured: 0, connected: 0 },
2297
2538
  error: null
2298
2539
  });
2299
- const [credentialOpen, setCredentialOpen] = React7.useState(false);
2300
- const [credentialError, setCredentialError] = React7.useState(null);
2301
- const [busy, setBusy] = React7.useState(false);
2302
- const [busyByBot, setBusyByBot] = React7.useState({});
2303
- const [removeTarget, setRemoveTarget] = React7.useState(null);
2304
- const mounted = React7.useRef(true);
2540
+ const [credentialOpen, setCredentialOpen] = React8.useState(false);
2541
+ const [credentialError, setCredentialError] = React8.useState(null);
2542
+ const [busy, setBusy] = React8.useState(false);
2543
+ const [busyByBot, setBusyByBot] = React8.useState({});
2544
+ const [removeTarget, setRemoveTarget] = React8.useState(null);
2545
+ const mounted = React8.useRef(true);
2305
2546
  const workspaceFence = useWorkspaceSnapshotFence();
2306
- React7.useEffect(() => {
2547
+ React8.useEffect(() => {
2307
2548
  const disposeDingtalk = installDingtalkStyles();
2308
2549
  const disposeChannel = installStyles();
2309
2550
  mounted.current = true;
@@ -2313,11 +2554,11 @@ function createTokenChannelSettings(definition) {
2313
2554
  disposeDingtalk();
2314
2555
  };
2315
2556
  }, []);
2316
- const invoke = React7.useCallback(async (endpoint, payload = {}, signal) => {
2557
+ const invoke = React8.useCallback(async (endpoint, payload = {}, signal) => {
2317
2558
  if (typeof rpcCall !== "function") throw new TypeError(`${channel4} \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5`);
2318
2559
  return api4.unwrapRpcResult(await rpcCall(endpoint, payload, signal));
2319
2560
  }, [rpcCall]);
2320
- const loadStatus = React7.useCallback(async ({ signal, silent = false } = {}) => {
2561
+ const loadStatus = React8.useCallback(async ({ signal, silent = false } = {}) => {
2321
2562
  const workspaceVersion = workspaceFence.beginStatus();
2322
2563
  if (workspaceVersion === null) return;
2323
2564
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
@@ -2335,12 +2576,12 @@ function createTokenChannelSettings(definition) {
2335
2576
  }
2336
2577
  }
2337
2578
  }, [invoke, workspaceFence]);
2338
- React7.useEffect(() => {
2579
+ React8.useEffect(() => {
2339
2580
  const controller = new AbortController();
2340
2581
  void loadStatus({ signal: controller.signal });
2341
2582
  return () => controller.abort();
2342
2583
  }, [loadStatus]);
2343
- React7.useEffect(() => {
2584
+ React8.useEffect(() => {
2344
2585
  if (model.phase !== "ready") return void 0;
2345
2586
  const controller = new AbortController();
2346
2587
  const timer = window.setInterval(
@@ -2352,7 +2593,7 @@ function createTokenChannelSettings(definition) {
2352
2593
  window.clearInterval(timer);
2353
2594
  };
2354
2595
  }, [loadStatus, model.phase]);
2355
- const bindCredentials = React7.useCallback(async (values) => {
2596
+ const bindCredentials = React8.useCallback(async (values) => {
2356
2597
  const snapshotVersion = workspaceFence.beginMutation();
2357
2598
  setBusy(true);
2358
2599
  setCredentialError(null);
@@ -2374,7 +2615,7 @@ function createTokenChannelSettings(definition) {
2374
2615
  if (mounted.current) setBusy(false);
2375
2616
  }
2376
2617
  }, [invoke, loadStatus, workspaceFence]);
2377
- const botAction = React7.useCallback(async (account, operation, endpoint, payload) => {
2618
+ const botAction = React8.useCallback(async (account, operation, endpoint, payload) => {
2378
2619
  const snapshotVersion = workspaceFence.beginMutation();
2379
2620
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
2380
2621
  try {
@@ -2475,7 +2716,7 @@ function createTokenChannelSettings(definition) {
2475
2716
  h2(Button3, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
2476
2717
  )
2477
2718
  ) : h2(
2478
- React7.Fragment,
2719
+ React8.Fragment,
2479
2720
  null,
2480
2721
  credentialOpen ? CredentialPanel ? h2(CredentialPanel, {
2481
2722
  busy,
@@ -2576,7 +2817,7 @@ var DiscordSettingsTab = channel.SettingsTab;
2576
2817
  var DiscordAccountCard = channel.AccountCard;
2577
2818
 
2578
2819
  // plugin-src/client/channels/feishu/index.js
2579
- var React9 = __toESM(require("react"), 1);
2820
+ var React10 = __toESM(require("react"), 1);
2580
2821
 
2581
2822
  // plugin-src/client/channels/feishu/api.js
2582
2823
  var FEISHU_RPC_CHANNEL = "/feishu";
@@ -2796,7 +3037,7 @@ function formatRemaining2(milliseconds) {
2796
3037
  }
2797
3038
 
2798
3039
  // plugin-src/client/lifecycle.js
2799
- var React8 = __toESM(require("react"), 1);
3040
+ var React9 = __toESM(require("react"), 1);
2800
3041
  function createPollScheduler({ setTimeoutFn, clearTimeoutFn }) {
2801
3042
  let disposed = false;
2802
3043
  let timer;
@@ -2858,8 +3099,8 @@ function createAnimationFrameScheduler({ requestFrame, cancelFrame }) {
2858
3099
  };
2859
3100
  }
2860
3101
  function useAnimationFrameScheduler() {
2861
- const schedulerRef = React8.useRef(null);
2862
- React8.useEffect(() => {
3102
+ const schedulerRef = React9.useRef(null);
3103
+ React9.useEffect(() => {
2863
3104
  const scheduler = createAnimationFrameScheduler({
2864
3105
  requestFrame: (callback) => window.requestAnimationFrame(callback),
2865
3106
  cancelFrame: (frame) => window.cancelAnimationFrame(frame)
@@ -2870,7 +3111,7 @@ function useAnimationFrameScheduler() {
2870
3111
  if (schedulerRef.current === scheduler) schedulerRef.current = null;
2871
3112
  };
2872
3113
  }, []);
2873
- return React8.useCallback(
3114
+ return React9.useCallback(
2874
3115
  (callback, key) => schedulerRef.current?.schedule(callback, key) ?? false,
2875
3116
  []
2876
3117
  );
@@ -3438,7 +3679,7 @@ function QrIcon({ size = 58 }) {
3438
3679
  fill: "currentColor"
3439
3680
  }));
3440
3681
  }
3441
- var Button5 = React9.forwardRef(function Button6({ children, kind = "secondary", size, icon, className = "", ...props }, ref) {
3682
+ var Button5 = React10.forwardRef(function Button6({ children, kind = "secondary", size, icon, className = "", ...props }, ref) {
3442
3683
  return h2("button", {
3443
3684
  ...props,
3444
3685
  ref,
@@ -3550,13 +3791,13 @@ function safeQrSource2(value) {
3550
3791
  return /^data:image\/(?:png|webp|svg\+xml)(?:;charset=[^;,]+)?;base64,/i.test(value) ? value : void 0;
3551
3792
  }
3552
3793
  function QrPane({ provision, now, onRefresh, onCancel, busy }) {
3553
- const [imageFailed, setImageFailed] = React9.useState(false);
3794
+ const [imageFailed, setImageFailed] = React10.useState(false);
3554
3795
  const qrSource = safeQrSource2(provision.qrCodeDataUrl);
3555
3796
  const href = safeVerificationHref(provision.verificationUrl);
3556
3797
  const remaining = Math.max(0, provision.expiresAt - now);
3557
3798
  const expired = provision.expired === true || remaining === 0;
3558
3799
  const progress = Math.min(1, remaining / Math.max(1, provision.durationMs ?? remaining));
3559
- React9.useEffect(() => setImageFailed(false), [qrSource]);
3800
+ React10.useEffect(() => setImageFailed(false), [qrSource]);
3560
3801
  return h2(
3561
3802
  "div",
3562
3803
  { className: "bxf-card bxf-provisionCard dim-surfaceCard" },
@@ -3706,11 +3947,11 @@ function formatCheckedTime(timestamp7) {
3706
3947
  }
3707
3948
  }
3708
3949
  function RemoveConfirmation2({ bot, busy, onConfirm, onCancel }) {
3709
- const cancelRef = React9.useRef(null);
3950
+ const cancelRef = React10.useRef(null);
3710
3951
  const idPart = bot.botId.replace(/[^a-zA-Z0-9_-]/g, "-");
3711
3952
  const titleId = `bxf-remove-title-${idPart}`;
3712
3953
  const descriptionId = `bxf-remove-description-${idPart}`;
3713
- React9.useEffect(() => cancelRef.current?.focus(), []);
3954
+ React10.useEffect(() => cancelRef.current?.focus(), []);
3714
3955
  return h2(
3715
3956
  "div",
3716
3957
  {
@@ -3938,7 +4179,7 @@ function mergeFeishuSnapshotState(current, snapshot, { restoreProvisioning = fal
3938
4179
  };
3939
4180
  }
3940
4181
  function FeishuSettingsTab({ rpcCall }) {
3941
- const [model, setModel] = React9.useState({
4182
+ const [model, setModel] = React10.useState({
3942
4183
  phase: "loading",
3943
4184
  revision: 0,
3944
4185
  bots: [],
@@ -3947,39 +4188,39 @@ function FeishuSettingsTab({ rpcCall }) {
3947
4188
  pageError: null,
3948
4189
  statusError: null
3949
4190
  });
3950
- const [pageBusy, setPageBusy] = React9.useState(false);
3951
- const [provisionBusy, setProvisionBusy] = React9.useState(false);
3952
- const [credentialOpen, setCredentialOpen] = React9.useState(false);
3953
- const [credentialBusy, setCredentialBusy] = React9.useState(false);
3954
- const [credentialError, setCredentialError] = React9.useState(null);
3955
- const [busyByBot, setBusyByBot] = React9.useState({});
3956
- const [errorsByBot, setErrorsByBot] = React9.useState({});
3957
- const [removeTargetId, setRemoveTargetId] = React9.useState(null);
3958
- const [announcement, setAnnouncement] = React9.useState("");
3959
- const [now, setNow] = React9.useState(() => Date.now());
3960
- const [focusBotId, setFocusBotId] = React9.useState(null);
3961
- const cardRefs = React9.useRef(/* @__PURE__ */ new Map());
3962
- const removeButtonRefs = React9.useRef(/* @__PURE__ */ new Map());
3963
- const addButtonRef = React9.useRef(null);
3964
- const mountedRef = React9.useRef(true);
4191
+ const [pageBusy, setPageBusy] = React10.useState(false);
4192
+ const [provisionBusy, setProvisionBusy] = React10.useState(false);
4193
+ const [credentialOpen, setCredentialOpen] = React10.useState(false);
4194
+ const [credentialBusy, setCredentialBusy] = React10.useState(false);
4195
+ const [credentialError, setCredentialError] = React10.useState(null);
4196
+ const [busyByBot, setBusyByBot] = React10.useState({});
4197
+ const [errorsByBot, setErrorsByBot] = React10.useState({});
4198
+ const [removeTargetId, setRemoveTargetId] = React10.useState(null);
4199
+ const [announcement, setAnnouncement] = React10.useState("");
4200
+ const [now, setNow] = React10.useState(() => Date.now());
4201
+ const [focusBotId, setFocusBotId] = React10.useState(null);
4202
+ const cardRefs = React10.useRef(/* @__PURE__ */ new Map());
4203
+ const removeButtonRefs = React10.useRef(/* @__PURE__ */ new Map());
4204
+ const addButtonRef = React10.useRef(null);
4205
+ const mountedRef = React10.useRef(true);
3965
4206
  const workspaceFence = useWorkspaceSnapshotFence();
3966
4207
  const scheduleAnimationFrame = useAnimationFrameScheduler();
3967
- React9.useEffect(() => {
4208
+ React10.useEffect(() => {
3968
4209
  mountedRef.current = true;
3969
4210
  return () => {
3970
4211
  mountedRef.current = false;
3971
4212
  };
3972
4213
  }, []);
3973
- const announce = React9.useCallback((message) => {
4214
+ const announce = React10.useCallback((message) => {
3974
4215
  setAnnouncement("");
3975
4216
  scheduleAnimationFrame(() => {
3976
4217
  if (message) setAnnouncement(message);
3977
4218
  }, "announcement");
3978
4219
  }, [scheduleAnimationFrame]);
3979
- const invoke = React9.useCallback(async (endpoint, payload = {}, signal) => {
4220
+ const invoke = React10.useCallback(async (endpoint, payload = {}, signal) => {
3980
4221
  return unwrapRpcResult3(await rpcCall(endpoint, payload, signal));
3981
4222
  }, [rpcCall]);
3982
- const mergeSnapshot = React9.useCallback((snapshot, { restoreProvisioning = false } = {}) => {
4223
+ const mergeSnapshot = React10.useCallback((snapshot, { restoreProvisioning = false } = {}) => {
3983
4224
  const now2 = Date.now();
3984
4225
  setModel((current) => mergeFeishuSnapshotState(
3985
4226
  current,
@@ -3987,7 +4228,7 @@ function FeishuSettingsTab({ rpcCall }) {
3987
4228
  { restoreProvisioning, now: now2 }
3988
4229
  ));
3989
4230
  }, []);
3990
- const loadStatus = React9.useCallback(async ({ signal, silent = false, restoreProvisioning = false } = {}) => {
4231
+ const loadStatus = React10.useCallback(async ({ signal, silent = false, restoreProvisioning = false } = {}) => {
3991
4232
  const workspaceVersion = workspaceFence.beginStatus();
3992
4233
  if (workspaceVersion === null || !mountedRef.current) return void 0;
3993
4234
  if (!silent) setPageBusy(true);
@@ -4005,12 +4246,12 @@ function FeishuSettingsTab({ rpcCall }) {
4005
4246
  if (!silent && !signal?.aborted && mountedRef.current) setPageBusy(false);
4006
4247
  }
4007
4248
  }, [invoke, mergeSnapshot, workspaceFence]);
4008
- React9.useEffect(() => {
4249
+ React10.useEffect(() => {
4009
4250
  const controller = new AbortController();
4010
4251
  void loadStatus({ signal: controller.signal, restoreProvisioning: true });
4011
4252
  return () => controller.abort();
4012
4253
  }, [loadStatus]);
4013
- React9.useEffect(() => {
4254
+ React10.useEffect(() => {
4014
4255
  if (model.phase !== "ready") return void 0;
4015
4256
  const controller = new AbortController();
4016
4257
  let inFlight = false;
@@ -4029,7 +4270,7 @@ function FeishuSettingsTab({ rpcCall }) {
4029
4270
  window.clearInterval(timer);
4030
4271
  };
4031
4272
  }, [loadStatus, model.phase]);
4032
- React9.useEffect(() => {
4273
+ React10.useEffect(() => {
4033
4274
  if (!focusBotId) return;
4034
4275
  const node = cardRefs.current.get(focusBotId);
4035
4276
  if (!node) return;
@@ -4037,7 +4278,7 @@ function FeishuSettingsTab({ rpcCall }) {
4037
4278
  node.focus({ preventScroll: true });
4038
4279
  setFocusBotId(null);
4039
4280
  }, [focusBotId, model.bots]);
4040
- const startProvisioning = React9.useCallback(async ({ replace = false } = {}) => {
4281
+ const startProvisioning = React10.useCallback(async ({ replace = false } = {}) => {
4041
4282
  setCredentialOpen(false);
4042
4283
  setCredentialError(null);
4043
4284
  setProvisionBusy(true);
@@ -4077,7 +4318,7 @@ function FeishuSettingsTab({ rpcCall }) {
4077
4318
  setProvisionBusy(false);
4078
4319
  }
4079
4320
  }, [announce, invoke, model.provisioning?.attemptId]);
4080
- const bindCredentials = React9.useCallback(async ({ identity, secret }) => {
4321
+ const bindCredentials = React10.useCallback(async ({ identity, secret }) => {
4081
4322
  const snapshotVersion = workspaceFence.beginMutation();
4082
4323
  setCredentialBusy(true);
4083
4324
  setCredentialError(null);
@@ -4099,7 +4340,7 @@ function FeishuSettingsTab({ rpcCall }) {
4099
4340
  setCredentialBusy(false);
4100
4341
  }
4101
4342
  }, [announce, invoke, loadStatus, mergeSnapshot, workspaceFence]);
4102
- const cancelProvisioning = React9.useCallback(async () => {
4343
+ const cancelProvisioning = React10.useCallback(async () => {
4103
4344
  const attemptId = model.provisioning?.attemptId;
4104
4345
  setProvisionBusy(true);
4105
4346
  try {
@@ -4121,7 +4362,7 @@ function FeishuSettingsTab({ rpcCall }) {
4121
4362
  const countdownPhase = model.provisioning?.phase;
4122
4363
  const countdownExpiresAt = model.provisioning?.expiresAt;
4123
4364
  const countdownExpired = model.provisioning?.expired;
4124
- React9.useEffect(() => {
4365
+ React10.useEffect(() => {
4125
4366
  if (!countdownAttemptId || countdownPhase !== "qr" || countdownExpired) return void 0;
4126
4367
  const tick = () => {
4127
4368
  const timestamp7 = Date.now();
@@ -4134,7 +4375,7 @@ function FeishuSettingsTab({ rpcCall }) {
4134
4375
  const timer = window.setInterval(tick, 1e3);
4135
4376
  return () => window.clearInterval(timer);
4136
4377
  }, [countdownAttemptId, countdownPhase, countdownExpiresAt, countdownExpired]);
4137
- React9.useEffect(() => {
4378
+ React10.useEffect(() => {
4138
4379
  const provision2 = model.provisioning;
4139
4380
  if (!provision2 || !["qr", "connecting"].includes(provision2.phase) || !provision2.attemptId || provision2.expired) return void 0;
4140
4381
  const controller = new AbortController();
@@ -4198,7 +4439,7 @@ function FeishuSettingsTab({ rpcCall }) {
4198
4439
  window.clearTimeout(timer);
4199
4440
  };
4200
4441
  }, [announce, invoke, loadStatus, model.provisioning]);
4201
- const setBotBusy = React9.useCallback((botId, value) => {
4442
+ const setBotBusy = React10.useCallback((botId, value) => {
4202
4443
  setBusyByBot((current) => {
4203
4444
  const next = { ...current };
4204
4445
  if (value) next[botId] = value;
@@ -4206,7 +4447,7 @@ function FeishuSettingsTab({ rpcCall }) {
4206
4447
  return next;
4207
4448
  });
4208
4449
  }, []);
4209
- const setBotError = React9.useCallback((botId, error) => {
4450
+ const setBotError = React10.useCallback((botId, error) => {
4210
4451
  setErrorsByBot((current) => {
4211
4452
  const next = { ...current };
4212
4453
  if (error) next[botId] = presentError3(error);
@@ -4214,7 +4455,7 @@ function FeishuSettingsTab({ rpcCall }) {
4214
4455
  return next;
4215
4456
  });
4216
4457
  }, []);
4217
- const reconnectOneBot = React9.useCallback(async (connection) => {
4458
+ const reconnectOneBot = React10.useCallback(async (connection) => {
4218
4459
  const { botId, bot } = connection;
4219
4460
  const snapshotVersion = workspaceFence.beginMutation();
4220
4461
  setBotBusy(botId, "reconnect");
@@ -4242,7 +4483,7 @@ function FeishuSettingsTab({ rpcCall }) {
4242
4483
  setBotBusy(botId, null);
4243
4484
  }
4244
4485
  }, [announce, invoke, loadStatus, mergeSnapshot, setBotBusy, setBotError, workspaceFence]);
4245
- const saveWorkspace = React9.useCallback(async (connection, workspace) => {
4486
+ const saveWorkspace = React10.useCallback(async (connection, workspace) => {
4246
4487
  const { botId } = connection;
4247
4488
  const workspaceVersion = workspaceFence.beginMutation();
4248
4489
  setBotBusy(botId, "workspace");
@@ -4261,15 +4502,15 @@ function FeishuSettingsTab({ rpcCall }) {
4261
4502
  if (mountedRef.current) setBotBusy(botId, null);
4262
4503
  }
4263
4504
  }, [invoke, loadStatus, mergeSnapshot, setBotBusy, setBotError, workspaceFence]);
4264
- const requestRemove = React9.useCallback((connection) => {
4505
+ const requestRemove = React10.useCallback((connection) => {
4265
4506
  setRemoveTargetId(connection.botId);
4266
4507
  }, []);
4267
- const cancelRemove = React9.useCallback(() => {
4508
+ const cancelRemove = React10.useCallback(() => {
4268
4509
  const botId = removeTargetId;
4269
4510
  setRemoveTargetId(null);
4270
4511
  scheduleAnimationFrame(() => removeButtonRefs.current.get(botId)?.focus(), "focus");
4271
4512
  }, [removeTargetId, scheduleAnimationFrame]);
4272
- const confirmRemove = React9.useCallback(async (connection) => {
4513
+ const confirmRemove = React10.useCallback(async (connection) => {
4273
4514
  const { botId, bot } = connection;
4274
4515
  const snapshotVersion = workspaceFence.beginMutation();
4275
4516
  setBotBusy(botId, "delete");
@@ -4334,11 +4575,11 @@ function FeishuSettingsTab({ rpcCall }) {
4334
4575
  setCredentialError(null);
4335
4576
  }
4336
4577
  }) : null;
4337
- const setCardRef = React9.useCallback((botId, node) => {
4578
+ const setCardRef = React10.useCallback((botId, node) => {
4338
4579
  if (node) cardRefs.current.set(botId, node);
4339
4580
  else cardRefs.current.delete(botId);
4340
4581
  }, []);
4341
- const setRemoveButtonRef = React9.useCallback((botId, node) => {
4582
+ const setRemoveButtonRef = React10.useCallback((botId, node) => {
4342
4583
  if (node) removeButtonRefs.current.set(botId, node);
4343
4584
  else removeButtonRefs.current.delete(botId);
4344
4585
  }, []);
@@ -4375,7 +4616,7 @@ function FeishuSettingsTab({ rpcCall }) {
4375
4616
  onRetry: () => void loadStatus(),
4376
4617
  busy: pageBusy
4377
4618
  }) : h2(
4378
- React9.Fragment,
4619
+ React10.Fragment,
4379
4620
  null,
4380
4621
  credentialContent,
4381
4622
  provisionContent,
@@ -4507,7 +4748,7 @@ function formatRemaining3(milliseconds) {
4507
4748
  }
4508
4749
 
4509
4750
  // plugin-src/client/channels/qq/index.js
4510
- var React10 = __toESM(require("react"), 1);
4751
+ var React11 = __toESM(require("react"), 1);
4511
4752
 
4512
4753
  // plugin-src/client/channels/qq/styles.js
4513
4754
  var QQ_STYLE_ID = "xmanrui-dsh-im-qq-settings";
@@ -4532,7 +4773,7 @@ function installQqStyles() {
4532
4773
 
4533
4774
  // plugin-src/client/channels/qq/index.js
4534
4775
  var ACTIVE_STATES = /* @__PURE__ */ new Set(["pending", "refreshing", "connecting"]);
4535
- var Button7 = React10.forwardRef(function Button8({ children, kind = "secondary", className = "", ...props }, ref) {
4776
+ var Button7 = React11.forwardRef(function Button8({ children, kind = "secondary", className = "", ...props }, ref) {
4536
4777
  return h2("button", {
4537
4778
  ...props,
4538
4779
  ref,
@@ -4811,18 +5052,18 @@ function AccountCard2({
4811
5052
  );
4812
5053
  }
4813
5054
  function QqSettingsTab({ rpcCall }) {
4814
- const [model, setModel] = React10.useState({ phase: "loading", bots: [], totals: { configured: 0, connected: 0 }, error: null });
4815
- const [provision, setProvision] = React10.useState(null);
4816
- const [busy, setBusy] = React10.useState(false);
4817
- const [busyByBot, setBusyByBot] = React10.useState({});
4818
- const [removeTarget, setRemoveTarget] = React10.useState(null);
4819
- const [credentialOpen, setCredentialOpen] = React10.useState(false);
4820
- const [credentialError, setCredentialError] = React10.useState(null);
4821
- const [now, setNow] = React10.useState(Date.now());
4822
- const mounted = React10.useRef(true);
5055
+ const [model, setModel] = React11.useState({ phase: "loading", bots: [], totals: { configured: 0, connected: 0 }, error: null });
5056
+ const [provision, setProvision] = React11.useState(null);
5057
+ const [busy, setBusy] = React11.useState(false);
5058
+ const [busyByBot, setBusyByBot] = React11.useState({});
5059
+ const [removeTarget, setRemoveTarget] = React11.useState(null);
5060
+ const [credentialOpen, setCredentialOpen] = React11.useState(false);
5061
+ const [credentialError, setCredentialError] = React11.useState(null);
5062
+ const [now, setNow] = React11.useState(Date.now());
5063
+ const mounted = React11.useRef(true);
4823
5064
  const workspaceFence = useWorkspaceSnapshotFence();
4824
- const addButtonRef = React10.useRef(null);
4825
- React10.useEffect(() => {
5065
+ const addButtonRef = React11.useRef(null);
5066
+ React11.useEffect(() => {
4826
5067
  const disposeDingtalk = installDingtalkStyles();
4827
5068
  const disposeQq = installQqStyles();
4828
5069
  mounted.current = true;
@@ -4832,11 +5073,11 @@ function QqSettingsTab({ rpcCall }) {
4832
5073
  disposeDingtalk();
4833
5074
  };
4834
5075
  }, []);
4835
- const invoke = React10.useCallback(async (endpoint, payload = {}, signal) => {
5076
+ const invoke = React11.useCallback(async (endpoint, payload = {}, signal) => {
4836
5077
  if (typeof rpcCall !== "function") throw new TypeError("QQ \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
4837
5078
  return unwrapRpcResult4(await rpcCall(endpoint, payload, signal));
4838
5079
  }, [rpcCall]);
4839
- const loadStatus = React10.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
5080
+ const loadStatus = React11.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
4840
5081
  const workspaceVersion = workspaceFence.beginStatus();
4841
5082
  if (workspaceVersion === null) return void 0;
4842
5083
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
@@ -4856,12 +5097,12 @@ function QqSettingsTab({ rpcCall }) {
4856
5097
  return void 0;
4857
5098
  }
4858
5099
  }, [invoke, workspaceFence]);
4859
- React10.useEffect(() => {
5100
+ React11.useEffect(() => {
4860
5101
  const controller = new AbortController();
4861
5102
  void loadStatus({ signal: controller.signal, restore: true });
4862
5103
  return () => controller.abort();
4863
5104
  }, [loadStatus]);
4864
- React10.useEffect(() => {
5105
+ React11.useEffect(() => {
4865
5106
  if (model.phase !== "ready") return void 0;
4866
5107
  const controller = new AbortController();
4867
5108
  const timer = window.setInterval(() => void loadStatus({ signal: controller.signal, silent: true }), 15e3);
@@ -4870,12 +5111,12 @@ function QqSettingsTab({ rpcCall }) {
4870
5111
  window.clearInterval(timer);
4871
5112
  };
4872
5113
  }, [loadStatus, model.phase]);
4873
- React10.useEffect(() => {
5114
+ React11.useEffect(() => {
4874
5115
  if (!provision || !ACTIVE_STATES.has(provision.status)) return void 0;
4875
5116
  const timer = window.setInterval(() => mounted.current && setNow(Date.now()), 1e3);
4876
5117
  return () => window.clearInterval(timer);
4877
5118
  }, [provision?.attemptId, provision?.status]);
4878
- const startProvisioning = React10.useCallback(async (replace = false) => {
5119
+ const startProvisioning = React11.useCallback(async (replace = false) => {
4879
5120
  setCredentialOpen(false);
4880
5121
  setCredentialError(null);
4881
5122
  setBusy(true);
@@ -4893,7 +5134,7 @@ function QqSettingsTab({ rpcCall }) {
4893
5134
  if (mounted.current) setBusy(false);
4894
5135
  }
4895
5136
  }, [invoke, provision?.attemptId]);
4896
- const bindCredentials = React10.useCallback(async ({ identity, secret }) => {
5137
+ const bindCredentials = React11.useCallback(async ({ identity, secret }) => {
4897
5138
  const snapshotVersion = workspaceFence.beginMutation();
4898
5139
  setBusy(true);
4899
5140
  setCredentialError(null);
@@ -4915,7 +5156,7 @@ function QqSettingsTab({ rpcCall }) {
4915
5156
  if (mounted.current) setBusy(false);
4916
5157
  }
4917
5158
  }, [invoke, loadStatus, workspaceFence]);
4918
- const closeProvision = React10.useCallback(async () => {
5159
+ const closeProvision = React11.useCallback(async () => {
4919
5160
  setBusy(true);
4920
5161
  try {
4921
5162
  if (provision?.attemptId && ACTIVE_STATES.has(provision.status)) {
@@ -4926,7 +5167,7 @@ function QqSettingsTab({ rpcCall }) {
4926
5167
  if (mounted.current) setBusy(false);
4927
5168
  }
4928
5169
  }, [invoke, provision?.attemptId, provision?.status]);
4929
- React10.useEffect(() => {
5170
+ React11.useEffect(() => {
4930
5171
  const attemptId = provision?.attemptId;
4931
5172
  if (!attemptId || !ACTIVE_STATES.has(provision.status)) return void 0;
4932
5173
  const controller = new AbortController();
@@ -4956,7 +5197,7 @@ function QqSettingsTab({ rpcCall }) {
4956
5197
  window.clearTimeout(timer);
4957
5198
  };
4958
5199
  }, [invoke, loadStatus, provision?.attemptId, provision?.pollIntervalMs, provision?.status]);
4959
- const botAction = React10.useCallback(async (account, operation, endpoint, payload) => {
5200
+ const botAction = React11.useCallback(async (account, operation, endpoint, payload) => {
4960
5201
  const snapshotVersion = workspaceFence.beginMutation();
4961
5202
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
4962
5203
  try {
@@ -5047,7 +5288,7 @@ function QqSettingsTab({ rpcCall }) {
5047
5288
  addButtonRef
5048
5289
  }),
5049
5290
  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(
5050
- React10.Fragment,
5291
+ React11.Fragment,
5051
5292
  null,
5052
5293
  credentialView,
5053
5294
  provisionView,
@@ -5066,7 +5307,7 @@ var normalizeSnapshot4 = api2.normalizeSnapshot;
5066
5307
  var presentError5 = api2.presentError;
5067
5308
 
5068
5309
  // plugin-src/client/channels/slack/index.js
5069
- var React11 = __toESM(require("react"), 1);
5310
+ var React12 = __toESM(require("react"), 1);
5070
5311
 
5071
5312
  // src/channels/slack/manifest.mjs
5072
5313
  var SLACK_APP_MANIFEST_YAML = `_metadata:
@@ -5138,10 +5379,10 @@ function installSlackStyles() {
5138
5379
 
5139
5380
  // plugin-src/client/channels/slack/index.js
5140
5381
  function SlackCredentialPanel({ busy, error, onSubmit, onCancel }) {
5141
- const [botToken, setBotToken] = React11.useState("");
5142
- const [appToken, setAppToken] = React11.useState("");
5143
- const [copied, setCopied] = React11.useState(false);
5144
- const headingId = React11.useId();
5382
+ const [botToken, setBotToken] = React12.useState("");
5383
+ const [appToken, setAppToken] = React12.useState("");
5384
+ const [copied, setCopied] = React12.useState(false);
5385
+ const headingId = React12.useId();
5145
5386
  const copyManifest = async () => {
5146
5387
  try {
5147
5388
  await navigator.clipboard.writeText(SLACK_APP_MANIFEST_YAML);
@@ -5435,7 +5676,7 @@ function formatRemaining4(milliseconds) {
5435
5676
  }
5436
5677
 
5437
5678
  // plugin-src/client/channels/wecom/index.js
5438
- var React12 = __toESM(require("react"), 1);
5679
+ var React13 = __toESM(require("react"), 1);
5439
5680
 
5440
5681
  // plugin-src/client/channels/wecom/styles.js
5441
5682
  var WECOM_STYLE_ID = "xmanrui-dsh-im-wecom-settings";
@@ -5460,7 +5701,7 @@ function installWecomStyles() {
5460
5701
 
5461
5702
  // plugin-src/client/channels/wecom/index.js
5462
5703
  var ACTIVE_STATES2 = /* @__PURE__ */ new Set(["pending", "refreshing", "connecting"]);
5463
- var Button9 = React12.forwardRef(function Button10({ children, kind = "secondary", className = "", ...props }, ref) {
5704
+ var Button9 = React13.forwardRef(function Button10({ children, kind = "secondary", className = "", ...props }, ref) {
5464
5705
  return h2("button", {
5465
5706
  ...props,
5466
5707
  ref,
@@ -5739,18 +5980,18 @@ function AccountCard3({
5739
5980
  );
5740
5981
  }
5741
5982
  function WecomSettingsTab({ rpcCall }) {
5742
- const [model, setModel] = React12.useState({ phase: "loading", bots: [], totals: { configured: 0, connected: 0 }, error: null });
5743
- const [provision, setProvision] = React12.useState(null);
5744
- const [busy, setBusy] = React12.useState(false);
5745
- const [busyByBot, setBusyByBot] = React12.useState({});
5746
- const [removeTarget, setRemoveTarget] = React12.useState(null);
5747
- const [credentialOpen, setCredentialOpen] = React12.useState(false);
5748
- const [credentialError, setCredentialError] = React12.useState(null);
5749
- const [now, setNow] = React12.useState(Date.now());
5750
- const mounted = React12.useRef(true);
5983
+ const [model, setModel] = React13.useState({ phase: "loading", bots: [], totals: { configured: 0, connected: 0 }, error: null });
5984
+ const [provision, setProvision] = React13.useState(null);
5985
+ const [busy, setBusy] = React13.useState(false);
5986
+ const [busyByBot, setBusyByBot] = React13.useState({});
5987
+ const [removeTarget, setRemoveTarget] = React13.useState(null);
5988
+ const [credentialOpen, setCredentialOpen] = React13.useState(false);
5989
+ const [credentialError, setCredentialError] = React13.useState(null);
5990
+ const [now, setNow] = React13.useState(Date.now());
5991
+ const mounted = React13.useRef(true);
5751
5992
  const workspaceFence = useWorkspaceSnapshotFence();
5752
- const addButtonRef = React12.useRef(null);
5753
- React12.useEffect(() => {
5993
+ const addButtonRef = React13.useRef(null);
5994
+ React13.useEffect(() => {
5754
5995
  const disposeDingtalk = installDingtalkStyles();
5755
5996
  const disposeWecom = installWecomStyles();
5756
5997
  mounted.current = true;
@@ -5760,11 +6001,11 @@ function WecomSettingsTab({ rpcCall }) {
5760
6001
  disposeDingtalk();
5761
6002
  };
5762
6003
  }, []);
5763
- const invoke = React12.useCallback(async (endpoint, payload = {}, signal) => {
6004
+ const invoke = React13.useCallback(async (endpoint, payload = {}, signal) => {
5764
6005
  if (typeof rpcCall !== "function") throw new TypeError("\u4F01\u4E1A\u5FAE\u4FE1\u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
5765
6006
  return unwrapRpcResult7(await rpcCall(endpoint, payload, signal));
5766
6007
  }, [rpcCall]);
5767
- const loadStatus = React12.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
6008
+ const loadStatus = React13.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
5768
6009
  const workspaceVersion = workspaceFence.beginStatus();
5769
6010
  if (workspaceVersion === null) return void 0;
5770
6011
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
@@ -5784,12 +6025,12 @@ function WecomSettingsTab({ rpcCall }) {
5784
6025
  return void 0;
5785
6026
  }
5786
6027
  }, [invoke, workspaceFence]);
5787
- React12.useEffect(() => {
6028
+ React13.useEffect(() => {
5788
6029
  const controller = new AbortController();
5789
6030
  void loadStatus({ signal: controller.signal, restore: true });
5790
6031
  return () => controller.abort();
5791
6032
  }, [loadStatus]);
5792
- React12.useEffect(() => {
6033
+ React13.useEffect(() => {
5793
6034
  if (model.phase !== "ready") return void 0;
5794
6035
  const controller = new AbortController();
5795
6036
  const timer = window.setInterval(() => void loadStatus({ signal: controller.signal, silent: true }), 15e3);
@@ -5798,12 +6039,12 @@ function WecomSettingsTab({ rpcCall }) {
5798
6039
  window.clearInterval(timer);
5799
6040
  };
5800
6041
  }, [loadStatus, model.phase]);
5801
- React12.useEffect(() => {
6042
+ React13.useEffect(() => {
5802
6043
  if (!provision || !ACTIVE_STATES2.has(provision.status)) return void 0;
5803
6044
  const timer = window.setInterval(() => mounted.current && setNow(Date.now()), 1e3);
5804
6045
  return () => window.clearInterval(timer);
5805
6046
  }, [provision?.attemptId, provision?.status]);
5806
- const startProvisioning = React12.useCallback(async (replace = false) => {
6047
+ const startProvisioning = React13.useCallback(async (replace = false) => {
5807
6048
  setCredentialOpen(false);
5808
6049
  setCredentialError(null);
5809
6050
  setBusy(true);
@@ -5821,7 +6062,7 @@ function WecomSettingsTab({ rpcCall }) {
5821
6062
  if (mounted.current) setBusy(false);
5822
6063
  }
5823
6064
  }, [invoke, provision?.attemptId]);
5824
- const bindCredentials = React12.useCallback(async ({ identity, secret }) => {
6065
+ const bindCredentials = React13.useCallback(async ({ identity, secret }) => {
5825
6066
  const snapshotVersion = workspaceFence.beginMutation();
5826
6067
  setBusy(true);
5827
6068
  setCredentialError(null);
@@ -5843,7 +6084,7 @@ function WecomSettingsTab({ rpcCall }) {
5843
6084
  if (mounted.current) setBusy(false);
5844
6085
  }
5845
6086
  }, [invoke, loadStatus, workspaceFence]);
5846
- const closeProvision = React12.useCallback(async () => {
6087
+ const closeProvision = React13.useCallback(async () => {
5847
6088
  setBusy(true);
5848
6089
  try {
5849
6090
  if (provision?.attemptId && ACTIVE_STATES2.has(provision.status)) {
@@ -5854,7 +6095,7 @@ function WecomSettingsTab({ rpcCall }) {
5854
6095
  if (mounted.current) setBusy(false);
5855
6096
  }
5856
6097
  }, [invoke, provision?.attemptId, provision?.status]);
5857
- React12.useEffect(() => {
6098
+ React13.useEffect(() => {
5858
6099
  const attemptId = provision?.attemptId;
5859
6100
  if (!attemptId || !ACTIVE_STATES2.has(provision.status)) return void 0;
5860
6101
  const controller = new AbortController();
@@ -5884,7 +6125,7 @@ function WecomSettingsTab({ rpcCall }) {
5884
6125
  window.clearTimeout(timer);
5885
6126
  };
5886
6127
  }, [invoke, loadStatus, provision?.attemptId, provision?.pollIntervalMs, provision?.status]);
5887
- const botAction = React12.useCallback(async (account, operation, endpoint, payload) => {
6128
+ const botAction = React13.useCallback(async (account, operation, endpoint, payload) => {
5888
6129
  const snapshotVersion = workspaceFence.beginMutation();
5889
6130
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
5890
6131
  try {
@@ -5975,7 +6216,7 @@ function WecomSettingsTab({ rpcCall }) {
5975
6216
  addButtonRef
5976
6217
  }),
5977
6218
  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(Button9, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6"))) : h2(
5978
- React12.Fragment,
6219
+ React13.Fragment,
5979
6220
  null,
5980
6221
  credentialView,
5981
6222
  provisionView,
@@ -5986,7 +6227,7 @@ function WecomSettingsTab({ rpcCall }) {
5986
6227
  }
5987
6228
 
5988
6229
  // plugin-src/client/channels/weixin/index.js
5989
- var React13 = __toESM(require("react"), 1);
6230
+ var React14 = __toESM(require("react"), 1);
5990
6231
 
5991
6232
  // plugin-src/client/channels/weixin/api.js
5992
6233
  var WEIXIN_RPC_CHANNEL = "/weixin";
@@ -6251,7 +6492,7 @@ function installWeixinStyles() {
6251
6492
  }
6252
6493
 
6253
6494
  // plugin-src/client/channels/weixin/index.js
6254
- var Button11 = React13.forwardRef(function Button12({ children, kind = "secondary", className = "", ...props }, ref) {
6495
+ var Button11 = React14.forwardRef(function Button12({ children, kind = "secondary", className = "", ...props }, ref) {
6255
6496
  return h2("button", {
6256
6497
  ...props,
6257
6498
  ref,
@@ -6324,14 +6565,14 @@ function EmptyView5({ onStart, busy }) {
6324
6565
  );
6325
6566
  }
6326
6567
  function QrPanel4({ provision, now, busy, onRefresh, onCancel }) {
6327
- const [imageFailed, setImageFailed] = React13.useState(false);
6568
+ const [imageFailed, setImageFailed] = React14.useState(false);
6328
6569
  const source = safeQrSource5(provision.qrCodeDataUrl);
6329
6570
  const href = safeVerificationUrl(provision.verificationUrl);
6330
6571
  const remaining = Math.max(0, provision.expiresAt - now);
6331
6572
  const expired = remaining === 0 || provision.status === "expired";
6332
6573
  const duration = Math.max(1, provision.durationMs ?? 5 * 6e4);
6333
6574
  const progress = Math.round(Math.min(1, remaining / duration) * 100);
6334
- React13.useEffect(() => setImageFailed(false), [source]);
6575
+ React14.useEffect(() => setImageFailed(false), [source]);
6335
6576
  return h2(
6336
6577
  "div",
6337
6578
  { className: "dxw-card dim-surfaceCard" },
@@ -6398,9 +6639,9 @@ function QrPanel4({ provision, now, busy, onRefresh, onCancel }) {
6398
6639
  );
6399
6640
  }
6400
6641
  function VerificationPanel({ provision, busy, onSubmit, onCancel }) {
6401
- const [code, setCode] = React13.useState("");
6642
+ const [code, setCode] = React14.useState("");
6402
6643
  const valid = /^\d{4,8}$/.test(code);
6403
- React13.useEffect(() => setCode(""), [provision.attemptId]);
6644
+ React14.useEffect(() => setCode(""), [provision.attemptId]);
6404
6645
  return h2(
6405
6646
  "div",
6406
6647
  { className: "dxw-card dim-surfaceCard" },
@@ -6613,39 +6854,39 @@ function mergeWeixinProvisioningSnapshot(current, incoming, { restoreProvisionin
6613
6854
  };
6614
6855
  }
6615
6856
  function WeixinSettingsTab({ rpcCall }) {
6616
- const [model, setModel] = React13.useState({
6857
+ const [model, setModel] = React14.useState({
6617
6858
  phase: "loading",
6618
6859
  bots: [],
6619
6860
  totals: EMPTY_TOTALS3,
6620
6861
  revision: 0,
6621
6862
  error: null
6622
6863
  });
6623
- const [provision, setProvision] = React13.useState(null);
6624
- const [busy, setBusy] = React13.useState(false);
6625
- const [busyByBot, setBusyByBot] = React13.useState({});
6626
- const [removeTarget, setRemoveTarget] = React13.useState(null);
6627
- const [notice, setNotice] = React13.useState("");
6628
- const [now, setNow] = React13.useState(() => Date.now());
6629
- const addButtonRef = React13.useRef(null);
6630
- const mountedRef = React13.useRef(true);
6864
+ const [provision, setProvision] = React14.useState(null);
6865
+ const [busy, setBusy] = React14.useState(false);
6866
+ const [busyByBot, setBusyByBot] = React14.useState({});
6867
+ const [removeTarget, setRemoveTarget] = React14.useState(null);
6868
+ const [notice, setNotice] = React14.useState("");
6869
+ const [now, setNow] = React14.useState(() => Date.now());
6870
+ const addButtonRef = React14.useRef(null);
6871
+ const mountedRef = React14.useRef(true);
6631
6872
  const workspaceFence = useWorkspaceSnapshotFence();
6632
6873
  const scheduleAnimationFrame = useAnimationFrameScheduler();
6633
- React13.useEffect(() => {
6874
+ React14.useEffect(() => {
6634
6875
  mountedRef.current = true;
6635
6876
  return () => {
6636
6877
  mountedRef.current = false;
6637
6878
  };
6638
6879
  }, []);
6639
- const announce = React13.useCallback((value) => {
6880
+ const announce = React14.useCallback((value) => {
6640
6881
  setNotice("");
6641
6882
  scheduleAnimationFrame(() => {
6642
6883
  if (value) setNotice(value);
6643
6884
  }, "announcement");
6644
6885
  }, [scheduleAnimationFrame]);
6645
- const invoke = React13.useCallback(async (endpoint, payload = {}, signal) => {
6886
+ const invoke = React14.useCallback(async (endpoint, payload = {}, signal) => {
6646
6887
  return unwrapRpcResult8(await rpcCall(endpoint, payload, signal));
6647
6888
  }, [rpcCall]);
6648
- const loadStatus = React13.useCallback(async ({
6889
+ const loadStatus = React14.useCallback(async ({
6649
6890
  signal,
6650
6891
  silent = false,
6651
6892
  restoreProvisioning = false
@@ -6681,12 +6922,12 @@ function WeixinSettingsTab({ rpcCall }) {
6681
6922
  return void 0;
6682
6923
  }
6683
6924
  }, [invoke, workspaceFence]);
6684
- React13.useEffect(() => {
6925
+ React14.useEffect(() => {
6685
6926
  const controller = new AbortController();
6686
6927
  void loadStatus({ signal: controller.signal, restoreProvisioning: true });
6687
6928
  return () => controller.abort();
6688
6929
  }, [loadStatus]);
6689
- React13.useEffect(() => {
6930
+ React14.useEffect(() => {
6690
6931
  if (model.phase !== "ready") return void 0;
6691
6932
  const controller = new AbortController();
6692
6933
  let running = false;
@@ -6705,12 +6946,12 @@ function WeixinSettingsTab({ rpcCall }) {
6705
6946
  window.clearInterval(timer);
6706
6947
  };
6707
6948
  }, [loadStatus, model.phase]);
6708
- React13.useEffect(() => {
6949
+ React14.useEffect(() => {
6709
6950
  if (!provision || !["pending", "scanned"].includes(provision.status)) return void 0;
6710
6951
  const timer = window.setInterval(() => setNow(Date.now()), 1e3);
6711
6952
  return () => window.clearInterval(timer);
6712
6953
  }, [provision?.attemptId, provision?.status]);
6713
- const startProvisioning = React13.useCallback(async ({ replace = false } = {}) => {
6954
+ const startProvisioning = React14.useCallback(async ({ replace = false } = {}) => {
6714
6955
  setBusy(true);
6715
6956
  try {
6716
6957
  if (replace && provision?.attemptId) {
@@ -6731,7 +6972,7 @@ function WeixinSettingsTab({ rpcCall }) {
6731
6972
  setBusy(false);
6732
6973
  }
6733
6974
  }, [announce, invoke, provision?.attemptId]);
6734
- const cancelProvisioning = React13.useCallback(async () => {
6975
+ const cancelProvisioning = React14.useCallback(async () => {
6735
6976
  setBusy(true);
6736
6977
  try {
6737
6978
  if (provision?.attemptId && !["failed", "expired", "cancelled"].includes(provision.status)) {
@@ -6746,7 +6987,7 @@ function WeixinSettingsTab({ rpcCall }) {
6746
6987
  setBusy(false);
6747
6988
  }
6748
6989
  }, [announce, invoke, provision?.attemptId, provision?.status, scheduleAnimationFrame]);
6749
- const submitVerification = React13.useCallback(async (verifyCode) => {
6990
+ const submitVerification = React14.useCallback(async (verifyCode) => {
6750
6991
  if (!provision?.attemptId) return;
6751
6992
  setBusy(true);
6752
6993
  try {
@@ -6762,7 +7003,7 @@ function WeixinSettingsTab({ rpcCall }) {
6762
7003
  setBusy(false);
6763
7004
  }
6764
7005
  }, [announce, invoke, provision?.attemptId]);
6765
- React13.useEffect(() => {
7006
+ React14.useEffect(() => {
6766
7007
  const attemptId = provision?.attemptId;
6767
7008
  if (!attemptId || !["pending", "scanned", "connecting"].includes(provision.status)) return void 0;
6768
7009
  const controller = new AbortController();
@@ -6810,7 +7051,7 @@ function WeixinSettingsTab({ rpcCall }) {
6810
7051
  controller.abort();
6811
7052
  };
6812
7053
  }, [announce, invoke, loadStatus, provision?.attemptId, provision?.status, provision?.pollIntervalMs]);
6813
- const setBotBusy = React13.useCallback((botId, value) => {
7054
+ const setBotBusy = React14.useCallback((botId, value) => {
6814
7055
  setBusyByBot((current) => {
6815
7056
  const next = { ...current };
6816
7057
  if (value) next[botId] = value;
@@ -6818,7 +7059,7 @@ function WeixinSettingsTab({ rpcCall }) {
6818
7059
  return next;
6819
7060
  });
6820
7061
  }, []);
6821
- const reconnect = React13.useCallback(async (account) => {
7062
+ const reconnect = React14.useCallback(async (account) => {
6822
7063
  const snapshotVersion = workspaceFence.beginMutation();
6823
7064
  setBotBusy(account.botId, "reconnect");
6824
7065
  try {
@@ -6836,7 +7077,7 @@ function WeixinSettingsTab({ rpcCall }) {
6836
7077
  setBotBusy(account.botId, null);
6837
7078
  }
6838
7079
  }, [announce, invoke, loadStatus, setBotBusy, workspaceFence]);
6839
- const saveWorkspace = React13.useCallback(async (account, workspace) => {
7080
+ const saveWorkspace = React14.useCallback(async (account, workspace) => {
6840
7081
  const workspaceVersion = workspaceFence.beginMutation();
6841
7082
  setBotBusy(account.botId, "workspace");
6842
7083
  try {
@@ -6859,7 +7100,7 @@ function WeixinSettingsTab({ rpcCall }) {
6859
7100
  if (mountedRef.current) setBotBusy(account.botId, null);
6860
7101
  }
6861
7102
  }, [invoke, loadStatus, setBotBusy, workspaceFence]);
6862
- const remove = React13.useCallback(async (account) => {
7103
+ const remove = React14.useCallback(async (account) => {
6863
7104
  const snapshotVersion = workspaceFence.beginMutation();
6864
7105
  setBotBusy(account.botId, "delete");
6865
7106
  try {
@@ -6935,7 +7176,7 @@ function WeixinSettingsTab({ rpcCall }) {
6935
7176
  h2(Button11, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
6936
7177
  )
6937
7178
  ) : h2(
6938
- React13.Fragment,
7179
+ React14.Fragment,
6939
7180
  null,
6940
7181
  provisionView,
6941
7182
  model.bots.length === 0 && !provision ? h2(EmptyView5, { onStart: () => void startProvisioning(), busy }) : null,
@@ -7066,7 +7307,7 @@ function formatRemaining6(milliseconds) {
7066
7307
  }
7067
7308
 
7068
7309
  // plugin-src/client/channels/whatsapp/index.js
7069
- var React14 = __toESM(require("react"), 1);
7310
+ var React15 = __toESM(require("react"), 1);
7070
7311
 
7071
7312
  // plugin-src/client/channels/whatsapp/styles.js
7072
7313
  var WHATSAPP_STYLE_ID = "xmanrui-dsh-im-whatsapp-settings";
@@ -7091,7 +7332,7 @@ function installWhatsappStyles() {
7091
7332
 
7092
7333
  // plugin-src/client/channels/whatsapp/index.js
7093
7334
  var ACTIVE_STATES3 = /* @__PURE__ */ new Set(["pending", "connecting"]);
7094
- var Button13 = React14.forwardRef(function Button14({ children, kind = "secondary", className = "", ...props }, ref) {
7335
+ var Button13 = React15.forwardRef(function Button14({ children, kind = "secondary", className = "", ...props }, ref) {
7095
7336
  return h2("button", {
7096
7337
  ...props,
7097
7338
  ref,
@@ -7392,21 +7633,21 @@ function WhatsappAccountCard({
7392
7633
  );
7393
7634
  }
7394
7635
  function WhatsappSettingsTab({ rpcCall }) {
7395
- const [model, setModel] = React14.useState({
7636
+ const [model, setModel] = React15.useState({
7396
7637
  phase: "loading",
7397
7638
  bots: [],
7398
7639
  totals: { configured: 0, connected: 0 },
7399
7640
  error: null
7400
7641
  });
7401
- const [provision, setProvision] = React14.useState(null);
7402
- const [busy, setBusy] = React14.useState(false);
7403
- const [busyByBot, setBusyByBot] = React14.useState({});
7404
- const [removeTarget, setRemoveTarget] = React14.useState(null);
7405
- const [now, setNow] = React14.useState(Date.now());
7406
- const mounted = React14.useRef(true);
7642
+ const [provision, setProvision] = React15.useState(null);
7643
+ const [busy, setBusy] = React15.useState(false);
7644
+ const [busyByBot, setBusyByBot] = React15.useState({});
7645
+ const [removeTarget, setRemoveTarget] = React15.useState(null);
7646
+ const [now, setNow] = React15.useState(Date.now());
7647
+ const mounted = React15.useRef(true);
7407
7648
  const workspaceFence = useWorkspaceSnapshotFence();
7408
- const addButtonRef = React14.useRef(null);
7409
- React14.useEffect(() => {
7649
+ const addButtonRef = React15.useRef(null);
7650
+ React15.useEffect(() => {
7410
7651
  const disposeDingtalk = installDingtalkStyles();
7411
7652
  const disposeWhatsapp = installWhatsappStyles();
7412
7653
  mounted.current = true;
@@ -7416,11 +7657,11 @@ function WhatsappSettingsTab({ rpcCall }) {
7416
7657
  disposeDingtalk();
7417
7658
  };
7418
7659
  }, []);
7419
- const invoke = React14.useCallback(async (endpoint, payload = {}, signal) => {
7660
+ const invoke = React15.useCallback(async (endpoint, payload = {}, signal) => {
7420
7661
  if (typeof rpcCall !== "function") throw new TypeError("WhatsApp \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
7421
7662
  return unwrapRpcResult9(await rpcCall(endpoint, payload, signal));
7422
7663
  }, [rpcCall]);
7423
- const loadStatus = React14.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
7664
+ const loadStatus = React15.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
7424
7665
  const workspaceVersion = workspaceFence.beginStatus();
7425
7666
  if (workspaceVersion === null) return void 0;
7426
7667
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
@@ -7444,12 +7685,12 @@ function WhatsappSettingsTab({ rpcCall }) {
7444
7685
  return void 0;
7445
7686
  }
7446
7687
  }, [invoke, workspaceFence]);
7447
- React14.useEffect(() => {
7688
+ React15.useEffect(() => {
7448
7689
  const controller = new AbortController();
7449
7690
  void loadStatus({ signal: controller.signal, restore: true });
7450
7691
  return () => controller.abort();
7451
7692
  }, [loadStatus]);
7452
- React14.useEffect(() => {
7693
+ React15.useEffect(() => {
7453
7694
  if (model.phase !== "ready") return void 0;
7454
7695
  const controller = new AbortController();
7455
7696
  const timer = window.setInterval(
@@ -7461,12 +7702,12 @@ function WhatsappSettingsTab({ rpcCall }) {
7461
7702
  window.clearInterval(timer);
7462
7703
  };
7463
7704
  }, [loadStatus, model.phase]);
7464
- React14.useEffect(() => {
7705
+ React15.useEffect(() => {
7465
7706
  if (!provision || !ACTIVE_STATES3.has(provision.status)) return void 0;
7466
7707
  const timer = window.setInterval(() => mounted.current && setNow(Date.now()), 1e3);
7467
7708
  return () => window.clearInterval(timer);
7468
7709
  }, [provision?.attemptId, provision?.status]);
7469
- const startProvisioning = React14.useCallback(async (replace = false) => {
7710
+ const startProvisioning = React15.useCallback(async (replace = false) => {
7470
7711
  setBusy(true);
7471
7712
  try {
7472
7713
  if (replace && provision?.attemptId) {
@@ -7484,7 +7725,7 @@ function WhatsappSettingsTab({ rpcCall }) {
7484
7725
  if (mounted.current) setBusy(false);
7485
7726
  }
7486
7727
  }, [invoke, provision?.attemptId]);
7487
- const closeProvision = React14.useCallback(async () => {
7728
+ const closeProvision = React15.useCallback(async () => {
7488
7729
  setBusy(true);
7489
7730
  try {
7490
7731
  if (provision?.attemptId && ACTIVE_STATES3.has(provision.status)) {
@@ -7495,7 +7736,7 @@ function WhatsappSettingsTab({ rpcCall }) {
7495
7736
  if (mounted.current) setBusy(false);
7496
7737
  }
7497
7738
  }, [invoke, provision?.attemptId, provision?.status]);
7498
- React14.useEffect(() => {
7739
+ React15.useEffect(() => {
7499
7740
  const attemptId = provision?.attemptId;
7500
7741
  if (!attemptId || !ACTIVE_STATES3.has(provision.status)) return void 0;
7501
7742
  const controller = new AbortController();
@@ -7536,7 +7777,7 @@ function WhatsappSettingsTab({ rpcCall }) {
7536
7777
  if (timer) window.clearTimeout(timer);
7537
7778
  };
7538
7779
  }, [invoke, loadStatus, provision?.attemptId, provision?.status]);
7539
- const botAction = React14.useCallback(async (account, operation, endpoint, payload) => {
7780
+ const botAction = React15.useCallback(async (account, operation, endpoint, payload) => {
7540
7781
  const snapshotVersion = workspaceFence.beginMutation();
7541
7782
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
7542
7783
  try {
@@ -7612,7 +7853,7 @@ function WhatsappSettingsTab({ rpcCall }) {
7612
7853
  h2(Button13, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
7613
7854
  )
7614
7855
  ) : h2(
7615
- React14.Fragment,
7856
+ React15.Fragment,
7616
7857
  null,
7617
7858
  provision?.status === "pending" ? h2(QrPanel5, {
7618
7859
  provision,
@@ -7771,14 +8012,47 @@ var CSS10 = String.raw`
7771
8012
  .dim-panel .dim-workspaceEdit { padding: 0; border: 0; color: #1677ff; background: transparent; font: inherit; font-weight: 560; cursor: pointer; }
7772
8013
  .dim-panel .dim-workspaceEdit:disabled { cursor: not-allowed; opacity: .55; }
7773
8014
  .dim-panel .dim-workspacePath { min-width: 0; display: block; overflow: hidden; color: var(--dsw-alias-label-primary, #1f2329); font: 12px/1.55 ui-monospace, SFMono-Regular, Menlo, monospace; text-overflow: ellipsis; white-space: nowrap; }
7774
- .dim-panel .dim-workspaceForm { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr) max-content; gap: 8px; }
7775
- .dim-panel .dim-workspaceForm input { width: 100%; min-width: 0; height: 34px; padding: 0 10px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 7px; outline: none; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-1, #fff); font: 12px ui-monospace, SFMono-Regular, Menlo, monospace; }
7776
- .dim-panel .dim-workspaceForm input:focus { border-color: #1677ff; box-shadow: 0 0 0 2px rgb(22 119 255 / 10%); }
7777
- .dim-panel .dim-workspaceActions { display: flex; gap: 6px; }
7778
- .dim-panel .dim-workspaceActions button { min-height: 34px; padding: 0 10px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 7px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 12px; cursor: pointer; }
7779
- .dim-panel .dim-workspaceActions button[type="submit"] { border-color: #1677ff; color: white; background: #1677ff; }
7780
- .dim-panel .dim-workspaceActions button:disabled { cursor: not-allowed; opacity: .55; }
7781
- .dim-panel .dim-workspaceError { grid-column: 1 / -1; margin: 0; color: var(--dsw-alias-state-error-primary, #d54941); font-size: 12px; line-height: 1.5; }
8015
+ .dim-directoryPickerBackdrop { --dim-blue: var(--dsw-alias-state-business-primary, #3370ff); --dim-blue-soft: color-mix(in srgb, var(--dim-blue) 9%, transparent); position: fixed; inset: 0; z-index: 1000; display: grid; place-items: center; padding: 24px; background: rgb(15 17 21 / 42%); backdrop-filter: blur(3px); }
8016
+ .dim-directoryPickerBackdrop, .dim-directoryPickerBackdrop *, .dim-directoryPickerBackdrop *::before, .dim-directoryPickerBackdrop *::after { box-sizing: border-box; }
8017
+ .dim-directoryPicker { width: min(720px, 100%); height: min(620px, calc(100vh - 48px)); min-height: 420px; display: grid; grid-template-rows: auto minmax(0, 1fr) auto; overflow: hidden; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 18px; outline: none; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-1, #fff); box-shadow: 0 24px 72px rgb(15 17 21 / 24%); }
8018
+ .dim-directoryPickerHeader { min-width: 0; padding: 22px 24px 17px; border-bottom: 1px solid var(--dsw-alias-border-l1, #eef0f3); }
8019
+ .dim-directoryPickerHeader h3 { margin: 0 0 14px; color: var(--dsw-alias-label-primary, #1f2329); font-size: 20px; line-height: 1.35; font-weight: 680; }
8020
+ .dim-directoryPickerHeader > p { margin: 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 13px; }
8021
+ .dim-directoryCrumbs { min-width: 0; display: flex; align-items: center; flex-wrap: wrap; gap: 4px; color: var(--dsw-alias-label-tertiary, #8f959e); }
8022
+ .dim-directoryCrumbs button { max-width: 210px; overflow: hidden; padding: 3px 5px; border: 0; border-radius: 6px; color: var(--dsw-alias-label-secondary, #646a73); background: transparent; font: inherit; font-size: 12px; line-height: 18px; text-overflow: ellipsis; white-space: nowrap; cursor: pointer; }
8023
+ .dim-directoryCrumbs button:hover:not(:disabled) { color: var(--dim-blue); background: var(--dim-blue-soft); }
8024
+ .dim-directoryCrumbs button[aria-current="page"] { color: var(--dsw-alias-label-primary, #1f2329); font-weight: 650; }
8025
+ .dim-directoryCrumbs button:focus-visible, .dim-directoryList button:focus-visible, .dim-directoryPickerActions button:focus-visible { outline: 2px solid color-mix(in srgb, var(--dim-blue) 65%, white); outline-offset: 1px; }
8026
+ .dim-directoryCrumbSeparator { flex: none; font-size: 12px; }
8027
+ .dim-directoryPickerBody { min-height: 0; overflow-y: auto; padding: 14px 16px; scrollbar-width: thin; scrollbar-color: var(--dsw-alias-border-l2, #dfe1e5) transparent; }
8028
+ .dim-directoryList { display: grid; gap: 3px; margin: 0; padding: 0; list-style: none; }
8029
+ .dim-directoryList button { width: 100%; min-height: 46px; display: grid; grid-template-columns: 24px minmax(0, 1fr) 18px; align-items: center; gap: 10px; padding: 7px 11px; border: 0; border-radius: 9px; color: var(--dsw-alias-label-primary, #1f2329); background: transparent; font: inherit; text-align: left; cursor: pointer; }
8030
+ .dim-directoryList button:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
8031
+ .dim-directoryList button:disabled, .dim-directoryCrumbs button:disabled { cursor: wait; opacity: .55; }
8032
+ .dim-directoryFolder { width: 24px; height: 24px; display: grid; place-items: center; color: var(--dsw-alias-label-secondary, #646a73); }
8033
+ .dim-directoryFolder svg { width: 22px; height: 22px; }
8034
+ .dim-directoryName { min-width: 0; overflow: hidden; font-size: 14px; line-height: 20px; text-overflow: ellipsis; white-space: nowrap; }
8035
+ .dim-directoryChevron { width: 18px; height: 18px; display: grid; place-items: center; color: var(--dsw-alias-label-tertiary, #8f959e); }
8036
+ .dim-directoryChevron svg { width: 17px; height: 17px; }
8037
+ .dim-directoryPickerState { min-height: 210px; display: grid; place-content: center; justify-items: center; gap: 10px; color: var(--dsw-alias-label-secondary, #646a73); text-align: center; }
8038
+ .dim-directoryPickerState p { margin: 0; font-size: 13px; line-height: 1.6; }
8039
+ .dim-directoryPickerSpinner { width: 24px; height: 24px; border: 3px solid var(--dsw-alias-border-l2, #e6e8eb); border-top-color: var(--dim-blue); border-radius: 50%; animation: dim-spin .8s linear infinite; }
8040
+ .dim-directoryPickerError { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 8px 0 0; padding: 10px 12px; border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary, #d54941) 22%, var(--dsw-alias-border-l2, #dfe1e5)); border-radius: 8px; color: var(--dsw-alias-state-error-primary, #d54941); background: color-mix(in srgb, var(--dsw-alias-state-error-primary, #d54941) 7%, var(--dsw-alias-bg-layer-1, #fff)); font-size: 12px; line-height: 1.5; }
8041
+ .dim-directoryPickerError button { flex: none; padding: 4px 8px; border: 0; border-radius: 6px; color: inherit; background: transparent; font: inherit; font-weight: 650; cursor: pointer; }
8042
+ .dim-directoryPickerTruncated { margin: 10px 4px 0; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 12px; line-height: 1.5; }
8043
+ .dim-directoryPickerFooter { display: grid; grid-template-columns: max-content minmax(0, 1fr) max-content; align-items: center; gap: 14px; padding: 16px 20px; border-top: 1px solid var(--dsw-alias-border-l1, #eef0f3); background: var(--dsw-alias-bg-layer-1, #fff); }
8044
+ .dim-directoryHidden { display: inline-flex; align-items: center; gap: 7px; padding: 2px 0; border: 0; color: var(--dsw-alias-label-secondary, #646a73); background: transparent; font: inherit; font-size: 12px; white-space: nowrap; cursor: pointer; }
8045
+ .dim-directoryHidden:focus-visible { outline: 2px solid color-mix(in srgb, var(--dim-blue) 65%, white); outline-offset: 2px; }
8046
+ .dim-directoryHidden:disabled { cursor: not-allowed; opacity: .52; }
8047
+ .dim-directoryHiddenBox { position: relative; width: 15px; height: 15px; flex: 0 0 15px; border: 1px solid var(--dsw-alias-border-l2, #c9cdd4); border-radius: 4px; background: var(--dsw-alias-bg-layer-1, #fff); }
8048
+ .dim-directoryHidden[aria-pressed="true"] .dim-directoryHiddenBox { border-color: var(--dim-blue); background: var(--dim-blue); }
8049
+ .dim-directoryHidden[aria-pressed="true"] .dim-directoryHiddenBox::after { content: ""; position: absolute; left: 4px; top: 1px; width: 4px; height: 8px; border: solid white; border-width: 0 2px 2px 0; transform: rotate(45deg); }
8050
+ .dim-directoryPickerNotice { min-width: 0; margin: 0; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 11px; line-height: 1.45; text-align: right; }
8051
+ .dim-directoryPickerActions { display: flex; gap: 8px; }
8052
+ .dim-directoryPickerActions button { min-height: 36px; padding: 0 14px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 13px; font-weight: 560; white-space: nowrap; cursor: pointer; }
8053
+ .dim-directoryPickerActions .dim-directoryPickerPrimary { border-color: var(--dim-blue); color: #fff; background: var(--dim-blue); }
8054
+ .dim-directoryPickerActions button:hover:not(:disabled) { filter: brightness(.97); }
8055
+ .dim-directoryPickerActions button:disabled { cursor: not-allowed; opacity: .52; }
7782
8056
  .dim-panel .dim-cardSummary { min-width: 0; color: var(--dsw-alias-label-secondary, #646a73); font: inherit; font-size: 12px; font-weight: 400; line-height: normal; }
7783
8057
  .dim-panel .dim-cardActions { flex: none; display: flex; align-items: center; flex-wrap: nowrap; gap: 8px; margin: 0 0 0 auto; }
7784
8058
  .dim-panel .dim-cardActions .dim-cardAction { flex: none; min-height: 34px; padding: 0 13px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 13px; font-weight: 560; line-height: normal; white-space: nowrap; }
@@ -7839,9 +8113,17 @@ var CSS10 = String.raw`
7839
8113
  .dim-title p { white-space: normal; }
7840
8114
  .dim-githubTooltip { right: auto; left: 0; }
7841
8115
  .dim-rail { grid-template-columns: minmax(0, 1fr); }
8116
+ .dim-directoryPickerBackdrop { padding: 10px; }
8117
+ .dim-directoryPicker { height: calc(100vh - 20px); min-height: 0; border-radius: 14px; }
8118
+ .dim-directoryPickerHeader { padding: 18px 17px 14px; }
8119
+ .dim-directoryPickerHeader h3 { font-size: 18px; }
8120
+ .dim-directoryPickerBody { padding: 10px; }
8121
+ .dim-directoryPickerFooter { grid-template-columns: minmax(0, 1fr) max-content; gap: 10px; padding: 13px 14px; }
8122
+ .dim-directoryPickerNotice { grid-column: 1 / -1; grid-row: 1; text-align: left; }
7842
8123
  }
7843
8124
  @media (prefers-reduced-motion: reduce) {
7844
8125
  .dim-page * { transition-duration: .01ms !important; }
8126
+ .dim-directoryPickerSpinner { animation-duration: 1.8s; }
7845
8127
  }
7846
8128
  `;
7847
8129
  function installImStyles() {
@@ -7860,7 +8142,7 @@ function installImStyles() {
7860
8142
 
7861
8143
  // plugin-src/client/index.js
7862
8144
  var name = "im-settings";
7863
- var inject = ["slots", "connection", "locale"];
8145
+ var inject = ["slots", "connection", "locale", "workspaces"];
7864
8146
  var IM_PLUGIN_LOGO_URL = "data:image/png;base64,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";
7865
8147
  var CHANNELS = Object.freeze([
7866
8148
  { id: "weixin", label: "\u5FAE\u4FE1" },
@@ -7948,85 +8230,90 @@ function IMSettingsTab({
7948
8230
  telegramRpcCall,
7949
8231
  wecomRpcCall,
7950
8232
  weixinRpcCall,
7951
- whatsappRpcCall
8233
+ whatsappRpcCall,
8234
+ workspaceDirectoryPicker
7952
8235
  }) {
7953
- const [selected, setSelected] = React15.useState("weixin");
7954
- const githubTooltipId = React15.useId();
8236
+ const [selected, setSelected] = React16.useState("weixin");
8237
+ const githubTooltipId = React16.useId();
7955
8238
  const active = CHANNELS.find((channel4) => channel4.id === selected) ?? CHANNELS[0];
7956
8239
  return h2(
7957
- "section",
7958
- { className: "dim-page", "aria-label": "IM\u673A\u5668\u4EBA\u8BBE\u7F6E" },
8240
+ WorkspaceDirectoryPickerContext.Provider,
8241
+ { value: workspaceDirectoryPicker },
7959
8242
  h2(
7960
- "header",
7961
- { className: "dim-title" },
8243
+ "section",
8244
+ { className: "dim-page", "aria-label": "IM\u673A\u5668\u4EBA\u8BBE\u7F6E" },
7962
8245
  h2(
7963
- "div",
7964
- { className: "dim-brand" },
7965
- h2("img", {
7966
- className: "dim-brandLogo",
7967
- src: IM_PLUGIN_LOGO_URL,
7968
- alt: "dsh-im",
7969
- width: 48,
7970
- height: 48
7971
- }),
7972
- h2("p", null, "\u8BA9\u804A\u5929\u673A\u5668\u4EBA\u8F7B\u677E\u63A5\u5165 DeepSeek Harness")
8246
+ "header",
8247
+ { className: "dim-title" },
8248
+ h2(
8249
+ "div",
8250
+ { className: "dim-brand" },
8251
+ h2("img", {
8252
+ className: "dim-brandLogo",
8253
+ src: IM_PLUGIN_LOGO_URL,
8254
+ alt: "dsh-im",
8255
+ width: 48,
8256
+ height: 48
8257
+ }),
8258
+ h2("p", null, "\u8BA9\u804A\u5929\u673A\u5668\u4EBA\u8F7B\u677E\u63A5\u5165 DeepSeek Harness")
8259
+ ),
8260
+ h2(
8261
+ "span",
8262
+ { className: "dim-githubAction" },
8263
+ h2(
8264
+ "a",
8265
+ {
8266
+ className: "dim-githubLink",
8267
+ href: "https://github.com/xmanrui/dsh-im",
8268
+ target: "_blank",
8269
+ rel: "noopener noreferrer",
8270
+ "aria-label": "dsh-im GitHub",
8271
+ "aria-describedby": githubTooltipId
8272
+ },
8273
+ h2("span", null, "GitHub"),
8274
+ h2("span", { className: "dim-githubArrow", "aria-hidden": "true" }, "\u2197")
8275
+ ),
8276
+ h2("span", {
8277
+ id: githubTooltipId,
8278
+ className: "dim-githubTooltip",
8279
+ role: "tooltip"
8280
+ }, "\u5E2E\u52A9\u4E0E\u53CD\u9988 \xB7 \u524D\u5F80 GitHub")
8281
+ )
7973
8282
  ),
7974
8283
  h2(
7975
- "span",
7976
- { className: "dim-githubAction" },
8284
+ "div",
8285
+ { className: "dim-layout" },
7977
8286
  h2(
7978
- "a",
7979
- {
7980
- className: "dim-githubLink",
7981
- href: "https://github.com/xmanrui/dsh-im",
7982
- target: "_blank",
7983
- rel: "noopener noreferrer",
7984
- "aria-label": "dsh-im GitHub",
7985
- "aria-describedby": githubTooltipId
7986
- },
7987
- h2("span", null, "GitHub"),
7988
- h2("span", { className: "dim-githubArrow", "aria-hidden": "true" }, "\u2197")
8287
+ "nav",
8288
+ { className: "dim-rail", role: "tablist", "aria-label": "IM \u6E20\u9053" },
8289
+ CHANNELS.map((channel4) => h2(
8290
+ "button",
8291
+ {
8292
+ key: channel4.id,
8293
+ type: "button",
8294
+ role: "tab",
8295
+ id: `dim-tab-${channel4.id}`,
8296
+ className: "dim-channel",
8297
+ "aria-selected": channel4.id === active.id,
8298
+ "aria-controls": `dim-panel-${channel4.id}`,
8299
+ onClick: () => setSelected(channel4.id)
8300
+ },
8301
+ h2(ChannelLogo, { channel: channel4.id }),
8302
+ h2(
8303
+ "span",
8304
+ { className: "dim-channelCopy" },
8305
+ h2("strong", null, channel4.label)
8306
+ )
8307
+ ))
7989
8308
  ),
7990
- h2("span", {
7991
- id: githubTooltipId,
7992
- className: "dim-githubTooltip",
7993
- role: "tooltip"
7994
- }, "\u5E2E\u52A9\u4E0E\u53CD\u9988 \xB7 \u524D\u5F80 GitHub")
8309
+ h2("div", { className: "dim-divider", "aria-hidden": "true" }),
8310
+ h2("main", {
8311
+ className: "dim-panel",
8312
+ role: "tabpanel",
8313
+ id: `dim-panel-${active.id}`,
8314
+ "aria-labelledby": `dim-tab-${active.id}`
8315
+ }, active.id === "weixin" ? h2(WeixinSettingsTab, { rpcCall: weixinRpcCall }) : active.id === "feishu" ? h2(FeishuSettingsTab, { rpcCall: feishuRpcCall }) : active.id === "dingtalk" ? h2(DingtalkSettingsTab, { rpcCall: dingtalkRpcCall }) : active.id === "wecom" ? h2(WecomSettingsTab, { rpcCall: wecomRpcCall }) : active.id === "qq" ? h2(QqSettingsTab, { rpcCall: qqRpcCall }) : active.id === "slack" ? h2(SlackSettingsTab, { rpcCall: slackRpcCall }) : active.id === "telegram" ? h2(TelegramSettingsTab, { rpcCall: telegramRpcCall }) : active.id === "discord" ? h2(DiscordSettingsTab, { rpcCall: discordRpcCall }) : h2(WhatsappSettingsTab, { rpcCall: whatsappRpcCall }))
7995
8316
  )
7996
- ),
7997
- h2(
7998
- "div",
7999
- { className: "dim-layout" },
8000
- h2(
8001
- "nav",
8002
- { className: "dim-rail", role: "tablist", "aria-label": "IM \u6E20\u9053" },
8003
- CHANNELS.map((channel4) => h2(
8004
- "button",
8005
- {
8006
- key: channel4.id,
8007
- type: "button",
8008
- role: "tab",
8009
- id: `dim-tab-${channel4.id}`,
8010
- className: "dim-channel",
8011
- "aria-selected": channel4.id === active.id,
8012
- "aria-controls": `dim-panel-${channel4.id}`,
8013
- onClick: () => setSelected(channel4.id)
8014
- },
8015
- h2(ChannelLogo, { channel: channel4.id }),
8016
- h2(
8017
- "span",
8018
- { className: "dim-channelCopy" },
8019
- h2("strong", null, channel4.label)
8020
- )
8021
- ))
8022
- ),
8023
- h2("div", { className: "dim-divider", "aria-hidden": "true" }),
8024
- h2("main", {
8025
- className: "dim-panel",
8026
- role: "tabpanel",
8027
- id: `dim-panel-${active.id}`,
8028
- "aria-labelledby": `dim-tab-${active.id}`
8029
- }, active.id === "weixin" ? h2(WeixinSettingsTab, { rpcCall: weixinRpcCall }) : active.id === "feishu" ? h2(FeishuSettingsTab, { rpcCall: feishuRpcCall }) : active.id === "dingtalk" ? h2(DingtalkSettingsTab, { rpcCall: dingtalkRpcCall }) : active.id === "wecom" ? h2(WecomSettingsTab, { rpcCall: wecomRpcCall }) : active.id === "qq" ? h2(QqSettingsTab, { rpcCall: qqRpcCall }) : active.id === "slack" ? h2(SlackSettingsTab, { rpcCall: slackRpcCall }) : active.id === "telegram" ? h2(TelegramSettingsTab, { rpcCall: telegramRpcCall }) : active.id === "discord" ? h2(DiscordSettingsTab, { rpcCall: discordRpcCall }) : h2(WhatsappSettingsTab, { rpcCall: whatsappRpcCall }))
8030
8317
  )
8031
8318
  );
8032
8319
  }
@@ -8062,6 +8349,10 @@ function apply(ctx) {
8062
8349
  const discordRpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(DISCORD_RPC_CHANNEL, endpoint, payload, signal);
8063
8350
  const whatsappRpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(WHATSAPP_RPC_CHANNEL, endpoint, payload, signal);
8064
8351
  const slackRpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(SLACK_RPC_CHANNEL, endpoint, payload, signal);
8352
+ const workspaceDirectoryPicker = Object.freeze({
8353
+ listDirectory: (path, signal) => ctx.workspaces.listDirectory(path, signal),
8354
+ pickDirectory: () => ctx.workspaces.pickDirectory()
8355
+ });
8065
8356
  ctx.slots.inject("settings.plugins.tab", () => ctx.slots.register({
8066
8357
  name: "settings.plugins.tab",
8067
8358
  id: "im",
@@ -8077,7 +8368,8 @@ function apply(ctx) {
8077
8368
  telegramRpcCall,
8078
8369
  wecomRpcCall,
8079
8370
  weixinRpcCall,
8080
- whatsappRpcCall
8371
+ whatsappRpcCall,
8372
+ workspaceDirectoryPicker
8081
8373
  })
8082
8374
  }, IMSettingsTab));
8083
8375
  }