@xmanrui/dsh-im 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.en.md +15 -0
  2. package/README.md +15 -0
  3. package/lib/client.js +1653 -333
  4. package/lib/index.js +235 -223
  5. package/package.json +5 -1
  6. package/plugin-src/client/channels/dingtalk/api.js +3 -0
  7. package/plugin-src/client/channels/dingtalk/index.js +18 -5
  8. package/plugin-src/client/channels/feishu/api.js +3 -0
  9. package/plugin-src/client/channels/feishu/index.js +18 -5
  10. package/plugin-src/client/channels/qq/api.js +3 -0
  11. package/plugin-src/client/channels/qq/index.js +13 -0
  12. package/plugin-src/client/channels/shared/token-api.js +3 -0
  13. package/plugin-src/client/channels/shared/token-channel.js +13 -1
  14. package/plugin-src/client/channels/wecom/api.js +3 -0
  15. package/plugin-src/client/channels/wecom/index.js +13 -0
  16. package/plugin-src/client/channels/weixin/api.js +3 -0
  17. package/plugin-src/client/channels/weixin/index.js +19 -5
  18. package/plugin-src/client/channels/whatsapp/api.js +3 -0
  19. package/plugin-src/client/channels/whatsapp/index.js +13 -0
  20. package/plugin-src/client/context-enhancement.js +275 -0
  21. package/plugin-src/client/i18n.js +54 -3
  22. package/plugin-src/client/styles.js +78 -0
  23. package/plugin-src/client/update-panel.js +108 -7
  24. package/plugin-src/host/channels/dingtalk/production.mjs +1 -0
  25. package/plugin-src/host/channels/dingtalk/rpc.mjs +11 -0
  26. package/plugin-src/host/channels/feishu/production.mjs +3 -0
  27. package/plugin-src/host/channels/feishu/rpc.mjs +13 -0
  28. package/plugin-src/host/channels/qq/production.mjs +1 -0
  29. package/plugin-src/host/channels/qq/rpc.mjs +11 -0
  30. package/plugin-src/host/channels/shared/context-enhancement-rpc.mjs +17 -0
  31. package/plugin-src/host/channels/shared/production.mjs +1 -0
  32. package/plugin-src/host/channels/shared/rpc.mjs +9 -0
  33. package/plugin-src/host/channels/shared/workspace-rpc.mjs +1 -0
  34. package/plugin-src/host/channels/slack/production.mjs +1 -0
  35. package/plugin-src/host/channels/slack/rpc.mjs +10 -0
  36. package/plugin-src/host/channels/wecom/production.mjs +1 -0
  37. package/plugin-src/host/channels/wecom/rpc.mjs +11 -0
  38. package/plugin-src/host/channels/weixin/production.mjs +1 -0
  39. package/plugin-src/host/channels/weixin/rpc.mjs +11 -0
  40. package/plugin-src/host/channels/whatsapp/production.mjs +1 -0
  41. package/plugin-src/host/channels/whatsapp/rpc.mjs +11 -0
  42. package/plugin-src/host/update-runtime.mjs +3 -2
  43. package/plugin-src/host/update-service.mjs +2 -0
  44. package/scripts/verify-package.mjs +15 -2
  45. package/src/channels/dingtalk/dingtalk-api.mjs +39 -16
  46. package/src/channels/dingtalk/dingtalk-bridge.mjs +52 -23
  47. package/src/channels/dingtalk/dingtalk-runtime.mjs +20 -1
  48. package/src/channels/discord/discord-runtime.mjs +18 -4
  49. package/src/channels/feishu/bridge.mjs +20 -4
  50. package/src/channels/feishu/feishu-channel.mjs +100 -44
  51. package/src/channels/feishu/feishu-runtime.mjs +4 -0
  52. package/src/channels/qq/qq-bridge.mjs +20 -4
  53. package/src/channels/qq/qq-runtime.mjs +4 -0
  54. package/src/channels/shared/bot-workspace-store.mjs +103 -6
  55. package/src/channels/shared/context-enhancement.mjs +135 -0
  56. package/src/channels/shared/i18n-en/feishu.mjs +2 -0
  57. package/src/channels/shared/text-harness-bridge.mjs +19 -4
  58. package/src/channels/slack/slack-runtime.mjs +4 -0
  59. package/src/channels/telegram/telegram-runtime.mjs +24 -2
  60. package/src/channels/wecom/wecom-bridge.mjs +18 -3
  61. package/src/channels/wecom/wecom-runtime.mjs +4 -0
  62. package/src/channels/weixin/weixin-bridge.mjs +19 -4
  63. package/src/channels/weixin/weixin-runtime.mjs +4 -0
  64. package/src/channels/whatsapp/whatsapp-runtime.mjs +5 -0
package/lib/client.js CHANGED
@@ -9,6 +9,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
9
9
  var __getOwnPropNames = Object.getOwnPropertyNames;
10
10
  var __getProtoOf = Object.getPrototypeOf;
11
11
  var __hasOwnProp = Object.prototype.hasOwnProperty;
12
+ var __commonJS = (cb, mod) => function __require() {
13
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
14
+ };
12
15
  var __export = (target, all) => {
13
16
  for (var name2 in all)
14
17
  __defProp(target, name2, { get: all[name2], enumerable: true });
@@ -31,6 +34,527 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
31
34
  ));
32
35
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
33
36
 
37
+ // node_modules/semver/internal/debug.js
38
+ var require_debug = __commonJS({
39
+ "node_modules/semver/internal/debug.js"(exports, module2) {
40
+ "use strict";
41
+ var debug = typeof process === "object" && process.env && process.env.NODE_DEBUG && /\bsemver\b/i.test(process.env.NODE_DEBUG) ? (...args) => console.error("SEMVER", ...args) : () => {
42
+ };
43
+ module2.exports = debug;
44
+ }
45
+ });
46
+
47
+ // node_modules/semver/internal/constants.js
48
+ var require_constants = __commonJS({
49
+ "node_modules/semver/internal/constants.js"(exports, module2) {
50
+ "use strict";
51
+ var SEMVER_SPEC_VERSION = "2.0.0";
52
+ var MAX_LENGTH = 256;
53
+ var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || /* istanbul ignore next */
54
+ 9007199254740991;
55
+ var MAX_SAFE_COMPONENT_LENGTH = 16;
56
+ var MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6;
57
+ var RELEASE_TYPES = [
58
+ "major",
59
+ "premajor",
60
+ "minor",
61
+ "preminor",
62
+ "patch",
63
+ "prepatch",
64
+ "prerelease"
65
+ ];
66
+ module2.exports = {
67
+ MAX_LENGTH,
68
+ MAX_SAFE_COMPONENT_LENGTH,
69
+ MAX_SAFE_BUILD_LENGTH,
70
+ MAX_SAFE_INTEGER,
71
+ RELEASE_TYPES,
72
+ SEMVER_SPEC_VERSION,
73
+ FLAG_INCLUDE_PRERELEASE: 1,
74
+ FLAG_LOOSE: 2
75
+ };
76
+ }
77
+ });
78
+
79
+ // node_modules/semver/internal/re.js
80
+ var require_re = __commonJS({
81
+ "node_modules/semver/internal/re.js"(exports, module2) {
82
+ "use strict";
83
+ var {
84
+ MAX_SAFE_COMPONENT_LENGTH,
85
+ MAX_SAFE_BUILD_LENGTH,
86
+ MAX_LENGTH
87
+ } = require_constants();
88
+ var debug = require_debug();
89
+ exports = module2.exports = {};
90
+ var re = exports.re = [];
91
+ var safeRe = exports.safeRe = [];
92
+ var src = exports.src = [];
93
+ var safeSrc = exports.safeSrc = [];
94
+ var t = exports.t = {};
95
+ var R = 0;
96
+ var LETTERDASHNUMBER = "[a-zA-Z0-9-]";
97
+ var safeRegexReplacements = [
98
+ ["\\s", 1],
99
+ ["\\d", MAX_LENGTH],
100
+ [LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH]
101
+ ];
102
+ var makeSafeRegex = (value) => {
103
+ for (const [token, max] of safeRegexReplacements) {
104
+ value = value.split(`${token}*`).join(`${token}{0,${max}}`).split(`${token}+`).join(`${token}{1,${max}}`);
105
+ }
106
+ return value;
107
+ };
108
+ var createToken = (name2, value, isGlobal) => {
109
+ const safe = makeSafeRegex(value);
110
+ const index = R++;
111
+ debug(name2, index, value);
112
+ t[name2] = index;
113
+ src[index] = value;
114
+ safeSrc[index] = safe;
115
+ re[index] = new RegExp(value, isGlobal ? "g" : void 0);
116
+ safeRe[index] = new RegExp(safe, isGlobal ? "g" : void 0);
117
+ };
118
+ createToken("NUMERICIDENTIFIER", "0|[1-9]\\d*");
119
+ createToken("NUMERICIDENTIFIERLOOSE", "\\d+");
120
+ createToken("NONNUMERICIDENTIFIER", `\\d*[a-zA-Z-]${LETTERDASHNUMBER}*`);
121
+ createToken("MAINVERSION", `(${src[t.NUMERICIDENTIFIER]})\\.(${src[t.NUMERICIDENTIFIER]})\\.(${src[t.NUMERICIDENTIFIER]})`);
122
+ createToken("MAINVERSIONLOOSE", `(${src[t.NUMERICIDENTIFIERLOOSE]})\\.(${src[t.NUMERICIDENTIFIERLOOSE]})\\.(${src[t.NUMERICIDENTIFIERLOOSE]})`);
123
+ createToken("PRERELEASEIDENTIFIER", `(?:${src[t.NONNUMERICIDENTIFIER]}|${src[t.NUMERICIDENTIFIER]})`);
124
+ createToken("PRERELEASEIDENTIFIERLOOSE", `(?:${src[t.NONNUMERICIDENTIFIER]}|${src[t.NUMERICIDENTIFIERLOOSE]})`);
125
+ createToken("PRERELEASE", `(?:-(${src[t.PRERELEASEIDENTIFIER]}(?:\\.${src[t.PRERELEASEIDENTIFIER]})*))`);
126
+ createToken("PRERELEASELOOSE", `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE]}(?:\\.${src[t.PRERELEASEIDENTIFIERLOOSE]})*))`);
127
+ createToken("BUILDIDENTIFIER", `${LETTERDASHNUMBER}+`);
128
+ createToken("BUILD", `(?:\\+(${src[t.BUILDIDENTIFIER]}(?:\\.${src[t.BUILDIDENTIFIER]})*))`);
129
+ createToken("FULLPLAIN", `v?${src[t.MAINVERSION]}${src[t.PRERELEASE]}?${src[t.BUILD]}?`);
130
+ createToken("FULL", `^${src[t.FULLPLAIN]}$`);
131
+ createToken("LOOSEPLAIN", `[v=\\s]*${src[t.MAINVERSIONLOOSE]}${src[t.PRERELEASELOOSE]}?${src[t.BUILD]}?`);
132
+ createToken("LOOSE", `^${src[t.LOOSEPLAIN]}$`);
133
+ createToken("GTLT", "((?:<|>)?=?)");
134
+ createToken("XRANGEIDENTIFIERLOOSE", `${src[t.NUMERICIDENTIFIERLOOSE]}|x|X|\\*`);
135
+ createToken("XRANGEIDENTIFIER", `${src[t.NUMERICIDENTIFIER]}|x|X|\\*`);
136
+ createToken("XRANGEPLAIN", `[v=\\s]*(${src[t.XRANGEIDENTIFIER]})(?:\\.(${src[t.XRANGEIDENTIFIER]})(?:\\.(${src[t.XRANGEIDENTIFIER]})(?:${src[t.PRERELEASE]})?${src[t.BUILD]}?)?)?`);
137
+ createToken("XRANGEPLAINLOOSE", `[v=\\s]*(${src[t.XRANGEIDENTIFIERLOOSE]})(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})(?:${src[t.PRERELEASELOOSE]})?${src[t.BUILD]}?)?)?`);
138
+ createToken("XRANGE", `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAIN]}$`);
139
+ createToken("XRANGELOOSE", `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAINLOOSE]}$`);
140
+ createToken("COERCEPLAIN", `${"(^|[^\\d])(\\d{1,"}${MAX_SAFE_COMPONENT_LENGTH}})(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?`);
141
+ createToken("COERCE", `${src[t.COERCEPLAIN]}(?:$|[^\\d])`);
142
+ createToken("COERCEFULL", src[t.COERCEPLAIN] + `(?:${src[t.PRERELEASE]})?(?:${src[t.BUILD]})?(?:$|[^\\d])`);
143
+ createToken("COERCERTL", src[t.COERCE], true);
144
+ createToken("COERCERTLFULL", src[t.COERCEFULL], true);
145
+ createToken("LONETILDE", "(?:~>?)");
146
+ createToken("TILDETRIM", `(\\s*)${src[t.LONETILDE]}\\s+`, true);
147
+ exports.tildeTrimReplace = "$1~";
148
+ createToken("TILDE", `^${src[t.LONETILDE]}${src[t.XRANGEPLAIN]}$`);
149
+ createToken("TILDELOOSE", `^${src[t.LONETILDE]}${src[t.XRANGEPLAINLOOSE]}$`);
150
+ createToken("LONECARET", "(?:\\^)");
151
+ createToken("CARETTRIM", `(\\s*)${src[t.LONECARET]}\\s+`, true);
152
+ exports.caretTrimReplace = "$1^";
153
+ createToken("CARET", `^${src[t.LONECARET]}${src[t.XRANGEPLAIN]}$`);
154
+ createToken("CARETLOOSE", `^${src[t.LONECARET]}${src[t.XRANGEPLAINLOOSE]}$`);
155
+ createToken("COMPARATORLOOSE", `^${src[t.GTLT]}\\s*(${src[t.LOOSEPLAIN]})$|^$`);
156
+ createToken("COMPARATOR", `^${src[t.GTLT]}\\s*(${src[t.FULLPLAIN]})$|^$`);
157
+ createToken("COMPARATORTRIM", `(\\s*)${src[t.GTLT]}\\s*(${src[t.LOOSEPLAIN]}|${src[t.XRANGEPLAIN]})`, true);
158
+ exports.comparatorTrimReplace = "$1$2$3";
159
+ createToken("HYPHENRANGE", `^\\s*(${src[t.XRANGEPLAIN]})\\s+-\\s+(${src[t.XRANGEPLAIN]})\\s*$`);
160
+ createToken("HYPHENRANGELOOSE", `^\\s*(${src[t.XRANGEPLAINLOOSE]})\\s+-\\s+(${src[t.XRANGEPLAINLOOSE]})\\s*$`);
161
+ createToken("STAR", "(<|>)?=?\\s*\\*");
162
+ createToken("GTE0", "^\\s*>=\\s*0\\.0\\.0\\s*$");
163
+ createToken("GTE0PRE", "^\\s*>=\\s*0\\.0\\.0-0\\s*$");
164
+ }
165
+ });
166
+
167
+ // node_modules/semver/internal/parse-options.js
168
+ var require_parse_options = __commonJS({
169
+ "node_modules/semver/internal/parse-options.js"(exports, module2) {
170
+ "use strict";
171
+ var looseOption = Object.freeze({ loose: true });
172
+ var emptyOpts = Object.freeze({});
173
+ var parseOptions = (options) => {
174
+ if (!options) {
175
+ return emptyOpts;
176
+ }
177
+ if (typeof options !== "object") {
178
+ return looseOption;
179
+ }
180
+ return options;
181
+ };
182
+ module2.exports = parseOptions;
183
+ }
184
+ });
185
+
186
+ // node_modules/semver/internal/identifiers.js
187
+ var require_identifiers = __commonJS({
188
+ "node_modules/semver/internal/identifiers.js"(exports, module2) {
189
+ "use strict";
190
+ var numeric = /^[0-9]+$/;
191
+ var compareIdentifiers = (a, b) => {
192
+ if (typeof a === "number" && typeof b === "number") {
193
+ return a === b ? 0 : a < b ? -1 : 1;
194
+ }
195
+ const anum = numeric.test(a);
196
+ const bnum = numeric.test(b);
197
+ if (anum && bnum) {
198
+ a = +a;
199
+ b = +b;
200
+ }
201
+ return a === b ? 0 : anum && !bnum ? -1 : bnum && !anum ? 1 : a < b ? -1 : 1;
202
+ };
203
+ var rcompareIdentifiers = (a, b) => compareIdentifiers(b, a);
204
+ module2.exports = {
205
+ compareIdentifiers,
206
+ rcompareIdentifiers
207
+ };
208
+ }
209
+ });
210
+
211
+ // node_modules/semver/classes/semver.js
212
+ var require_semver = __commonJS({
213
+ "node_modules/semver/classes/semver.js"(exports, module2) {
214
+ "use strict";
215
+ var debug = require_debug();
216
+ var { MAX_LENGTH, MAX_SAFE_INTEGER } = require_constants();
217
+ var { safeRe: re, t } = require_re();
218
+ var parseOptions = require_parse_options();
219
+ var { compareIdentifiers } = require_identifiers();
220
+ var isPrereleaseIdentifier = (prerelease, identifier) => {
221
+ const identifiers = identifier.split(".");
222
+ if (identifiers.length > prerelease.length) {
223
+ return false;
224
+ }
225
+ for (let i = 0; i < identifiers.length; i++) {
226
+ if (compareIdentifiers(prerelease[i], identifiers[i]) !== 0) {
227
+ return false;
228
+ }
229
+ }
230
+ return true;
231
+ };
232
+ var SemVer = class _SemVer {
233
+ constructor(version, options) {
234
+ options = parseOptions(options);
235
+ if (version instanceof _SemVer) {
236
+ if (version.loose === !!options.loose && version.includePrerelease === !!options.includePrerelease) {
237
+ return version;
238
+ } else {
239
+ version = version.version;
240
+ }
241
+ } else if (typeof version !== "string") {
242
+ throw new TypeError(`Invalid version. Must be a string. Got type "${typeof version}".`);
243
+ }
244
+ if (version.length > MAX_LENGTH) {
245
+ throw new TypeError(
246
+ `version is longer than ${MAX_LENGTH} characters`
247
+ );
248
+ }
249
+ debug("SemVer", version, options);
250
+ this.options = options;
251
+ this.loose = !!options.loose;
252
+ this.includePrerelease = !!options.includePrerelease;
253
+ const m = version.trim().match(options.loose ? re[t.LOOSE] : re[t.FULL]);
254
+ if (!m) {
255
+ throw new TypeError(`Invalid Version: ${version}`);
256
+ }
257
+ this.raw = version;
258
+ this.major = +m[1];
259
+ this.minor = +m[2];
260
+ this.patch = +m[3];
261
+ if (this.major > MAX_SAFE_INTEGER || this.major < 0) {
262
+ throw new TypeError("Invalid major version");
263
+ }
264
+ if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) {
265
+ throw new TypeError("Invalid minor version");
266
+ }
267
+ if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) {
268
+ throw new TypeError("Invalid patch version");
269
+ }
270
+ if (!m[4]) {
271
+ this.prerelease = [];
272
+ } else {
273
+ this.prerelease = m[4].split(".").map((id5) => {
274
+ if (/^[0-9]+$/.test(id5)) {
275
+ const num = +id5;
276
+ if (num >= 0 && num < MAX_SAFE_INTEGER) {
277
+ return num;
278
+ }
279
+ }
280
+ return id5;
281
+ });
282
+ }
283
+ this.build = m[5] ? m[5].split(".") : [];
284
+ this.format();
285
+ }
286
+ format() {
287
+ this.version = `${this.major}.${this.minor}.${this.patch}`;
288
+ if (this.prerelease.length) {
289
+ this.version += `-${this.prerelease.join(".")}`;
290
+ }
291
+ return this.version;
292
+ }
293
+ toString() {
294
+ return this.version;
295
+ }
296
+ compare(other) {
297
+ debug("SemVer.compare", this.version, this.options, other);
298
+ if (!(other instanceof _SemVer)) {
299
+ if (typeof other === "string" && other === this.version) {
300
+ return 0;
301
+ }
302
+ other = new _SemVer(other, this.options);
303
+ }
304
+ if (other.version === this.version) {
305
+ return 0;
306
+ }
307
+ return this.compareMain(other) || this.comparePre(other);
308
+ }
309
+ compareMain(other) {
310
+ if (!(other instanceof _SemVer)) {
311
+ other = new _SemVer(other, this.options);
312
+ }
313
+ if (this.major < other.major) {
314
+ return -1;
315
+ }
316
+ if (this.major > other.major) {
317
+ return 1;
318
+ }
319
+ if (this.minor < other.minor) {
320
+ return -1;
321
+ }
322
+ if (this.minor > other.minor) {
323
+ return 1;
324
+ }
325
+ if (this.patch < other.patch) {
326
+ return -1;
327
+ }
328
+ if (this.patch > other.patch) {
329
+ return 1;
330
+ }
331
+ return 0;
332
+ }
333
+ comparePre(other) {
334
+ if (!(other instanceof _SemVer)) {
335
+ other = new _SemVer(other, this.options);
336
+ }
337
+ if (this.prerelease.length && !other.prerelease.length) {
338
+ return -1;
339
+ } else if (!this.prerelease.length && other.prerelease.length) {
340
+ return 1;
341
+ } else if (!this.prerelease.length && !other.prerelease.length) {
342
+ return 0;
343
+ }
344
+ let i = 0;
345
+ do {
346
+ const a = this.prerelease[i];
347
+ const b = other.prerelease[i];
348
+ debug("prerelease compare", i, a, b);
349
+ if (a === void 0 && b === void 0) {
350
+ return 0;
351
+ } else if (b === void 0) {
352
+ return 1;
353
+ } else if (a === void 0) {
354
+ return -1;
355
+ } else if (a === b) {
356
+ continue;
357
+ } else {
358
+ return compareIdentifiers(a, b);
359
+ }
360
+ } while (++i);
361
+ }
362
+ compareBuild(other) {
363
+ if (!(other instanceof _SemVer)) {
364
+ other = new _SemVer(other, this.options);
365
+ }
366
+ let i = 0;
367
+ do {
368
+ const a = this.build[i];
369
+ const b = other.build[i];
370
+ debug("build compare", i, a, b);
371
+ if (a === void 0 && b === void 0) {
372
+ return 0;
373
+ } else if (b === void 0) {
374
+ return 1;
375
+ } else if (a === void 0) {
376
+ return -1;
377
+ } else if (a === b) {
378
+ continue;
379
+ } else {
380
+ return compareIdentifiers(a, b);
381
+ }
382
+ } while (++i);
383
+ }
384
+ // preminor will bump the version up to the next minor release, and immediately
385
+ // down to pre-release. premajor and prepatch work the same way.
386
+ inc(release, identifier, identifierBase) {
387
+ if (release.startsWith("pre")) {
388
+ if (!identifier && identifierBase === false) {
389
+ throw new Error("invalid increment argument: identifier is empty");
390
+ }
391
+ if (identifier) {
392
+ const match = `-${identifier}`.match(this.options.loose ? re[t.PRERELEASELOOSE] : re[t.PRERELEASE]);
393
+ if (!match || match[1] !== identifier) {
394
+ throw new Error(`invalid identifier: ${identifier}`);
395
+ }
396
+ }
397
+ }
398
+ switch (release) {
399
+ case "premajor":
400
+ this.prerelease.length = 0;
401
+ this.patch = 0;
402
+ this.minor = 0;
403
+ this.major++;
404
+ this.inc("pre", identifier, identifierBase);
405
+ break;
406
+ case "preminor":
407
+ this.prerelease.length = 0;
408
+ this.patch = 0;
409
+ this.minor++;
410
+ this.inc("pre", identifier, identifierBase);
411
+ break;
412
+ case "prepatch":
413
+ this.prerelease.length = 0;
414
+ this.inc("patch", identifier, identifierBase);
415
+ this.inc("pre", identifier, identifierBase);
416
+ break;
417
+ // If the input is a non-prerelease version, this acts the same as
418
+ // prepatch.
419
+ case "prerelease":
420
+ if (this.prerelease.length === 0) {
421
+ this.inc("patch", identifier, identifierBase);
422
+ }
423
+ this.inc("pre", identifier, identifierBase);
424
+ break;
425
+ case "release":
426
+ if (this.prerelease.length === 0) {
427
+ throw new Error(`version ${this.raw} is not a prerelease`);
428
+ }
429
+ this.prerelease.length = 0;
430
+ break;
431
+ case "major":
432
+ if (this.minor !== 0 || this.patch !== 0 || this.prerelease.length === 0) {
433
+ this.major++;
434
+ }
435
+ this.minor = 0;
436
+ this.patch = 0;
437
+ this.prerelease = [];
438
+ break;
439
+ case "minor":
440
+ if (this.patch !== 0 || this.prerelease.length === 0) {
441
+ this.minor++;
442
+ }
443
+ this.patch = 0;
444
+ this.prerelease = [];
445
+ break;
446
+ case "patch":
447
+ if (this.prerelease.length === 0) {
448
+ this.patch++;
449
+ }
450
+ this.prerelease = [];
451
+ break;
452
+ // This probably shouldn't be used publicly.
453
+ // 1.0.0 'pre' would become 1.0.0-0 which is the wrong direction.
454
+ case "pre": {
455
+ const base = Number(identifierBase) ? 1 : 0;
456
+ if (this.prerelease.length === 0) {
457
+ this.prerelease = [base];
458
+ } else {
459
+ let i = this.prerelease.length;
460
+ while (--i >= 0) {
461
+ if (typeof this.prerelease[i] === "number") {
462
+ this.prerelease[i]++;
463
+ i = -2;
464
+ }
465
+ }
466
+ if (i === -1) {
467
+ if (identifier === this.prerelease.join(".") && identifierBase === false) {
468
+ throw new Error("invalid increment argument: identifier already exists");
469
+ }
470
+ this.prerelease.push(base);
471
+ }
472
+ }
473
+ if (identifier) {
474
+ let prerelease = [identifier, base];
475
+ if (identifierBase === false) {
476
+ prerelease = [identifier];
477
+ }
478
+ if (isPrereleaseIdentifier(this.prerelease, identifier)) {
479
+ const prereleaseBase = this.prerelease[identifier.split(".").length];
480
+ if (isNaN(prereleaseBase)) {
481
+ this.prerelease = prerelease;
482
+ }
483
+ } else {
484
+ this.prerelease = prerelease;
485
+ }
486
+ }
487
+ break;
488
+ }
489
+ default:
490
+ throw new Error(`invalid increment argument: ${release}`);
491
+ }
492
+ this.raw = this.format();
493
+ if (this.build.length) {
494
+ this.raw += `+${this.build.join(".")}`;
495
+ }
496
+ return this;
497
+ }
498
+ };
499
+ module2.exports = SemVer;
500
+ }
501
+ });
502
+
503
+ // node_modules/semver/functions/parse.js
504
+ var require_parse = __commonJS({
505
+ "node_modules/semver/functions/parse.js"(exports, module2) {
506
+ "use strict";
507
+ var SemVer = require_semver();
508
+ var parse = (version, options, throwErrors = false) => {
509
+ if (version instanceof SemVer) {
510
+ return version;
511
+ }
512
+ try {
513
+ return new SemVer(version, options);
514
+ } catch (er) {
515
+ if (!throwErrors) {
516
+ return null;
517
+ }
518
+ throw er;
519
+ }
520
+ };
521
+ module2.exports = parse;
522
+ }
523
+ });
524
+
525
+ // node_modules/semver/functions/valid.js
526
+ var require_valid = __commonJS({
527
+ "node_modules/semver/functions/valid.js"(exports, module2) {
528
+ "use strict";
529
+ var parse = require_parse();
530
+ var valid = (version, options) => {
531
+ const v = parse(version, options);
532
+ return v ? v.version : null;
533
+ };
534
+ module2.exports = valid;
535
+ }
536
+ });
537
+
538
+ // node_modules/semver/functions/compare.js
539
+ var require_compare = __commonJS({
540
+ "node_modules/semver/functions/compare.js"(exports, module2) {
541
+ "use strict";
542
+ var SemVer = require_semver();
543
+ var compare = (a, b, loose) => new SemVer(a, loose).compare(new SemVer(b, loose));
544
+ module2.exports = compare;
545
+ }
546
+ });
547
+
548
+ // node_modules/semver/functions/rcompare.js
549
+ var require_rcompare = __commonJS({
550
+ "node_modules/semver/functions/rcompare.js"(exports, module2) {
551
+ "use strict";
552
+ var compare = require_compare();
553
+ var rcompare = (a, b, loose) => compare(b, a, loose);
554
+ module2.exports = rcompare;
555
+ }
556
+ });
557
+
34
558
  // plugin-src/client/index.js
35
559
  var index_exports = {};
36
560
  __export(index_exports, {
@@ -42,12 +566,12 @@ __export(index_exports, {
42
566
  name: () => name
43
567
  });
44
568
  module.exports = __toCommonJS(index_exports);
45
- var React21 = __toESM(require("react"), 1);
569
+ var React22 = __toESM(require("react"), 1);
46
570
 
47
571
  // package.json
48
572
  var package_default = {
49
573
  name: "@xmanrui/dsh-im",
50
- version: "3.1.0",
574
+ version: "3.2.0",
51
575
  description: "\u628A\u4E5D\u79CD IM \u673A\u5668\u4EBA\u548C\u516C\u7F51 AI Office \u63A5\u5165\u672C\u673A DeepSeek Harness\u3002 Connect nine IM channels and a public AI Office to a local DeepSeek Harness.",
52
576
  keywords: [
53
577
  "deepseek-harness",
@@ -77,6 +601,10 @@ var package_default = {
77
601
  {
78
602
  name: "C3H3-AI",
79
603
  url: "https://github.com/C3H3-AI"
604
+ },
605
+ {
606
+ name: "divingleee",
607
+ url: "https://github.com/divingleee"
80
608
  }
81
609
  ],
82
610
  license: "MIT",
@@ -315,17 +843,28 @@ var EN = Object.freeze({
315
843
  "\u68C0\u67E5\u66F4\u65B0": "Check for updates",
316
844
  "\u91CD\u65B0\u68C0\u67E5": "Check again",
317
845
  "\u5237\u65B0\u72B6\u6001": "Refresh status",
846
+ "\u624B\u5DE5\u66F4\u65B0": "Manual update",
847
+ "\u624B\u5DE5\u66F4\u65B0\u547D\u4EE4": "Manual update command",
848
+ "\u590D\u5236\u547D\u4EE4": "Copy command",
849
+ "\u590D\u5236\u4E2D\u2026": "Copying\u2026",
850
+ "\u5DF2\u590D\u5236": "Copied",
851
+ "\u547D\u4EE4\u5DF2\u590D\u5236\u3002": "Command copied.",
852
+ "\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u9009\u4E2D\u547D\u4EE4\u540E\u6309 Ctrl+C \u6216 \u2318C \u590D\u5236\u3002": "Copy failed. Select the command and press Ctrl+C or \u2318C to copy it.",
853
+ "\u81EA\u52A8\u66F4\u65B0\u5931\u8D25\u53EF\u4EE5\u4F7F\u7528\u547D\u4EE4\u66F4\u65B0\uFF1A": "If the automatic update fails, update with this command:",
854
+ "\u5C1A\u672A\u786E\u8BA4\u76EE\u6807\u7248\u672C\uFF0C\u6B64\u547D\u4EE4\u5B89\u88C5\u6267\u884C\u65F6 npm \u7684 latest \u7248\u672C\u3002": "No target version has been confirmed. This command installs the npm latest version available when you run it.",
855
+ "\u8BF7\u5728\u5F53\u524D Desktop \u7684\u5185\u7F6E\u7EC8\u7AEF\u6267\u884C\uFF0C\u5B8C\u6210\u540E\u624B\u52A8\u91CD\u542F\u3002": "Run this in the current Desktop\u2019s built-in terminal, then restart manually.",
856
+ "\u8BF7\u5728\u8FD0\u884C\u5F53\u524D Harness \u7684\u540C\u4E00\u73AF\u5883\u6267\u884C\uFF0C\u4FDD\u6301 DSH_HOME \u4E00\u81F4\uFF0C\u5B8C\u6210\u540E\u624B\u52A8\u91CD\u542F\u3002": "Run this in the same environment as the current Harness, with the same DSH_HOME, then restart manually.",
857
+ "\u8BF7\u7B49\u5F85\u5F53\u524D\u64CD\u4F5C\u7ED3\u675F\uFF0C\u786E\u8BA4\u6CA1\u6709\u5B89\u88C5\u8FDB\u7A0B\u8FD0\u884C\u540E\u518D\u6267\u884C\u547D\u4EE4\u3002": "Wait for the current operation to finish and confirm no installer is running before using this command.",
858
+ "\u6E90\u7801\u6216\u94FE\u63A5\u5B89\u88C5\u8BF7\u6309\u539F\u5B89\u88C5\u65B9\u5F0F\u66F4\u65B0\uFF0C\u4E0D\u63D0\u4F9B\u8986\u76D6\u6E90\u7801\u7684 npm \u547D\u4EE4\u3002": "Update source or linked installations using their original method. No npm command is provided to overwrite the source.",
859
+ "\u65E0\u6CD5\u5B89\u5168\u751F\u6210\u5F53\u524D profile \u7684\u547D\u4EE4\uFF0C\u8BF7\u5728\u7EC8\u7AEF\u4E2D\u624B\u52A8\u786E\u8BA4 profile \u540E\u66F4\u65B0\u3002": "A safe command cannot be generated for this profile. Confirm the profile in your terminal before updating manually.",
318
860
  "\u66F4\u65B0\u81F3": "Update to",
319
861
  "\u5B89\u88C5\u66F4\u65B0": "Install update",
320
862
  "\u6B63\u5728\u66F4\u65B0\u2026": "Updating\u2026",
321
863
  "\u5F85\u624B\u52A8\u91CD\u542F": "Restart needed",
322
864
  "\u8FD0\u884C\u7248\u672C": "Running version",
323
865
  "\u5DF2\u5B89\u88C5\u7248\u672C": "Installed version",
324
- "npm \u6700\u65B0\u7248\u672C": "Latest on npm",
325
866
  "\u76EE\u6807 profile": "Target profile",
326
867
  "\u76EE\u6807\u7248\u672C": "Target version",
327
- "\u66F4\u65B0\u6765\u6E90": "Update source",
328
- "\u9875\u9762\u7248\u672C": "Page version",
329
868
  "\u65E0\u6CD5\u786E\u8BA4": "Unknown",
330
869
  "\u53D1\u73B0\u65B0\u7248\u672C": "Update available",
331
870
  "\u5DF2\u662F\u6700\u65B0\u7248\u672C": "Up to date",
@@ -499,6 +1038,44 @@ var EN = Object.freeze({
499
1038
  "/\u7EDD\u5BF9\u8DEF\u5F84/\u5230/\u5DE5\u4F5C\u533A": "/absolute/path/to/workspace",
500
1039
  "\u4FEE\u6539": "Change",
501
1040
  "\u4FDD\u5B58": "Save",
1041
+ "\u4E0A\u4E0B\u6587\u589E\u5F3A": "Context enhancement",
1042
+ "\u672A\u5F00\u542F": "Not enabled",
1043
+ "\u4EC5\u7FA4\u804A": "Groups only",
1044
+ "\u4EC5\u79C1\u804A": "Direct only",
1045
+ "\u7FA4\u804A\u548C\u79C1\u804A": "Groups and direct",
1046
+ "\u5173\u95ED\u5F39\u7A97": "Close dialog",
1047
+ "\u67E5\u770B\u4E0A\u4E0B\u6587\u589E\u5F3A\u8BF4\u660E": "View context enhancement details",
1048
+ "\u542F\u7528\u8303\u56F4": "Enable in",
1049
+ "\u7FA4\u804A\u4E2D\u542F\u7528": "Enable in group chats",
1050
+ "\u79C1\u804A\u4E2D\u542F\u7528": "Enable in direct chats",
1051
+ "\uFF08\u5F53\u524D\u6E20\u9053\u4E0D\u652F\u6301\u7FA4\u804A\uFF09": "(This channel does not support group chats)",
1052
+ "\u6765\u6E90\u5B57\u6BB5": "Source fields",
1053
+ "\u67E5\u770B\u6765\u6E90\u5B57\u6BB5\u8BF4\u660E": "View source field details",
1054
+ "\u6E20\u9053": "Channel",
1055
+ "\u4F1A\u8BDD\u7C7B\u578B": "Conversation type",
1056
+ "\u53D1\u9001\u8005\u6807\u8BC6": "Sender ID",
1057
+ "\u53D1\u9001\u8005\u6635\u79F0": "Sender name",
1058
+ "\u67E5\u770B\u53D1\u9001\u8005\u6635\u79F0\u5B57\u6BB5\u8BF4\u660E": "View sender name field details",
1059
+ "\u8BE5\u5B57\u6BB5\u4E0D\u662F\u6BCF\u4E2A\u6E20\u9053\u90FD\u80FD\u63D0\u4F9B\u3002\u5F53\u524D\u6D88\u606F\u6CA1\u6709\u53D1\u9001\u8005\u6635\u79F0\u65F6\uFF0C\u5373\u4F7F\u5DF2\u9009\u62E9\u8BE5\u5B57\u6BB5\uFF0C<dsh_im_source> \u4E2D\u4E5F\u4F1A\u7701\u7565 senderName\u3002": "This field is not available on every channel. If the current message has no sender name, <dsh_im_source> omits senderName even when the field is selected.",
1060
+ "\u673A\u5668\u4EBA\u6807\u8BC6": "Bot ID",
1061
+ "\u589E\u5F3A\u63D0\u793A\u8BCD": "Guidance",
1062
+ "\u67E5\u770B\u589E\u5F3A\u63D0\u793A\u8BCD\u4F7F\u7528\u8BF4\u660E": "View guidance instructions",
1063
+ "\u4F7F\u7528\u8BF4\u660E": "How to use",
1064
+ "\u7528\u4E8E\u544A\u8BC9\u6A21\u578B\u5982\u4F55\u4F7F\u7528 <dsh_im_source> \u4E2D\u5DF2\u9009\u62E9\u7684\u6765\u6E90\u5B57\u6BB5\u3002\u53EA\u586B\u5199\u6B63\u6587\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u6DFB\u52A0 <dsh_im_source_guidance> \u6210\u5BF9\u6807\u7B7E\u3002": "Tell the model how to use the selected fields in <dsh_im_source>. Enter only the body; the plugin adds paired <dsh_im_source_guidance> tags.",
1065
+ "\u751F\u6548\u89C4\u5219": "Behavior",
1066
+ "\u9690\u79C1\u63D0\u793A": "Privacy",
1067
+ "\u4F7F\u7528\u793A\u4F8B": "Example",
1068
+ "\u4EC5\u4F9D\u636E\u5F53\u524D\u6D88\u606F\u7684 <dsh_im_source> \u4E2D\u5B9E\u9645\u63D0\u4F9B\u7684\u5B57\u6BB5\u7406\u89E3\u6765\u6E90\uFF1B\u6CA1\u6709\u63D0\u4F9B\u7684\u5B57\u6BB5\u4E0D\u8981\u731C\u6D4B\u6216\u8865\u5168\u3002\nconversationType\u662F\u7FA4\u804A\u65F6\u56DE\u590D\u4E25\u8083\u4E00\u70B9\uFF0CconversationType\u662F\u79C1\u804A\u65F6\u56DE\u590D\u4E00\u5B9A\u8981\u5E7D\u9ED8\u641E\u7B11\uFF0C\u50CF\u5468\u661F\u9A70\u7684\u7535\u5F71\u4E00\u6837\u641E\u7B11": "Understand the source only from fields actually present in <dsh_im_source> for the current message; do not guess or fill in missing fields.\nWhen conversationType is group, reply more seriously. When conversationType is direct, make the reply humorous and funny.",
1069
+ "\u586B\u5165\u793A\u4F8B": "Use example",
1070
+ "\u6E05\u7A7A": "Clear",
1071
+ "\u9009\u62E9\u5728\u54EA\u4E9B\u4F1A\u8BDD\u4E2D\u542F\u7528\u3001\u63D0\u4F9B\u54EA\u4E9B\u6765\u6E90\u5B57\u6BB5\uFF0C\u4EE5\u53CA\u5982\u4F55\u4F7F\u7528\u8FD9\u4E9B\u4FE1\u606F\u3002\u4EC5\u4F7F\u7528\u5DF2\u6709\u6D88\u606F\u5143\u6570\u636E\uFF0C\u4E0D\u67E5\u8BE2\u5E73\u53F0 API\u3002": "Choose which conversations to enhance, which source fields to include, and how to use them. Only existing message metadata is used; no platform APIs are queried.",
1072
+ "\u589E\u5F3A\u63D0\u793A\u8BCD\u4E2D\u8BF7\u4F7F\u7528\u5B57\u6BB5\u540D\uFF08\u5982 senderId\u3001conversationType\uFF09\u5F15\u7528\u8FD9\u4E9B\u4FE1\u606F\u3002\u53EA\u53D1\u9001\u52FE\u9009\u4E14\u5F53\u524D\u6D88\u606F\u4E2D\u53EF\u7528\u7684\u5B57\u6BB5\uFF0C\u4E0D\u4F1A\u989D\u5916\u67E5\u8BE2\u6216\u8865\u5168\u3002": "Reference these values by field name (such as senderId or conversationType) in the guidance. Only selected fields available in the current message are sent; no extra lookups are made.",
1073
+ "\u53EA\u9700\u586B\u5199\u6B63\u6587\uFF0C\u63D2\u4EF6\u81EA\u52A8\u6DFB\u52A0 <dsh_im_source_guidance> \u6210\u5BF9\u6807\u7B7E\u3002\u6E05\u7A7A\u5E76\u4FDD\u5B58\u540E\uFF0C\u4E0D\u518D\u9644\u52A0\u589E\u5F3A\u63D0\u793A\u8BCD\uFF0C\u5DF2\u9009\u6765\u6E90\u5B57\u6BB5\u4ECD\u6309\u5F00\u5173\u8BBE\u7F6E\u53D1\u9001\u3002": "Enter only the body; the plugin adds paired <dsh_im_source_guidance> tags. Clear and save to omit guidance. Selected source fields still follow the conversation switches.",
1074
+ "\u53D1\u9001\u8005\u6807\u8BC6\u53EF\u80FD\u5305\u542B\u5E73\u53F0\u7528\u6237 ID \u6216\u7535\u8BDD\u53F7\u7801\u5F62\u5F0F\u7684\u6807\u8BC6\u3002\u5173\u95ED\u5F00\u5173\u4E0D\u4F1A\u5220\u9664\u5DF2\u7ECF\u5199\u5165\u4F1A\u8BDD\u5386\u53F2\u7684\u4FE1\u606F\u3002": "Sender IDs may contain platform user IDs or phone-number-like identifiers. Turning this off does not remove information already saved in conversation history.",
1075
+ "\u4E0A\u4E0B\u6587\u589E\u5F3A\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002": "Could not save context enhancement. Try again.",
1076
+ "\u8BF7\u63D0\u4EA4\u5B8C\u6574\u7684\u4E0A\u4E0B\u6587\u589E\u5F3A\u8BBE\u7F6E\u3002": "Submit the complete context enhancement settings.",
1077
+ "\u7FA4\u804A\u548C\u79C1\u804A\u5F00\u5173\u5FC5\u987B\u662F\u5E03\u5C14\u503C\u3002": "Group and direct switches must be booleans.",
1078
+ "\u6765\u6E90\u5B57\u6BB5\u53EA\u80FD\u9009\u62E9\u5DF2\u5B9A\u4E49\u7684\u4E94\u4E2A\u5B57\u6BB5\u3002": "Source fields must be chosen from the five defined fields.",
502
1079
  "\u4FDD\u5B58\u4E2D\u2026": "Saving\u2026",
503
1080
  "\u672A\u8BBE\u7F6E": "Not set",
504
1081
  "\u5DE5\u4F5C\u533A\u4FEE\u6539\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002": "Could not update the workspace. Try again.",
@@ -942,6 +1519,8 @@ function channelName(value) {
942
1519
  return localizeText(value);
943
1520
  }
944
1521
  function translateDynamic(text6) {
1522
+ const guidanceLimit = /^增强提示词不得超过 (\d+) 个字符。$/.exec(text6);
1523
+ if (guidanceLimit) return `Guidance must not exceed ${guidanceLimit[1]} characters.`;
945
1524
  let match = /^(\d+) \/ (\d+) 在线$/.exec(text6);
946
1525
  if (match) return `${match[1]}/${match[2]} online`;
947
1526
  match = /^已接入 (\d+) 个机器人,其中 (\d+) 个在线$/.exec(text6);
@@ -1207,6 +1786,58 @@ function normalizeLastMessageError(value) {
1207
1786
  return code && reason && message && referenceId && at !== null ? { code, reason, message, referenceId, at } : null;
1208
1787
  }
1209
1788
 
1789
+ // src/channels/shared/context-enhancement.mjs
1790
+ var CONTEXT_ENHANCEMENT_FIELDS = Object.freeze([
1791
+ "channel",
1792
+ "conversationType",
1793
+ "senderId",
1794
+ "senderName",
1795
+ "botId"
1796
+ ]);
1797
+ var CONTEXT_ENHANCEMENT_GUIDANCE_MAX_LENGTH = 8e3;
1798
+ var CONTEXT_GUIDANCE_EXAMPLE = `\u4EC5\u4F9D\u636E\u5F53\u524D\u6D88\u606F\u7684 <dsh_im_source> \u4E2D\u5B9E\u9645\u63D0\u4F9B\u7684\u5B57\u6BB5\u7406\u89E3\u6765\u6E90\uFF1B\u6CA1\u6709\u63D0\u4F9B\u7684\u5B57\u6BB5\u4E0D\u8981\u731C\u6D4B\u6216\u8865\u5168\u3002
1799
+ conversationType\u662F\u7FA4\u804A\u65F6\u56DE\u590D\u4E25\u8083\u4E00\u70B9\uFF0CconversationType\u662F\u79C1\u804A\u65F6\u56DE\u590D\u4E00\u5B9A\u8981\u5E7D\u9ED8\u641E\u7B11\uFF0C\u50CF\u5468\u661F\u9A70\u7684\u7535\u5F71\u4E00\u6837\u641E\u7B11`;
1800
+ var DEFAULT_CONTEXT_ENHANCEMENT_CONFIG = Object.freeze({
1801
+ groupEnabled: false,
1802
+ directEnabled: false,
1803
+ fields: Object.freeze(["senderId"]),
1804
+ guidance: ""
1805
+ });
1806
+ var CONFIG_KEYS = ["groupEnabled", "directEnabled", "fields", "guidance"];
1807
+ function invalidConfig(message) {
1808
+ const error = new TypeError(message);
1809
+ error.code = "context-enhancement-invalid";
1810
+ return error;
1811
+ }
1812
+ function validateContextEnhancementConfig(input) {
1813
+ if (!input || typeof input !== "object" || Array.isArray(input) || ![Object.prototype, null].includes(Object.getPrototypeOf(input)) || Reflect.ownKeys(input).length !== CONFIG_KEYS.length || !CONFIG_KEYS.every((key) => Object.hasOwn(input, key))) {
1814
+ throw invalidConfig("\u8BF7\u63D0\u4EA4\u5B8C\u6574\u7684\u4E0A\u4E0B\u6587\u589E\u5F3A\u8BBE\u7F6E\u3002");
1815
+ }
1816
+ const { groupEnabled, directEnabled, fields, guidance } = input;
1817
+ if (typeof groupEnabled !== "boolean" || typeof directEnabled !== "boolean") {
1818
+ throw invalidConfig("\u7FA4\u804A\u548C\u79C1\u804A\u5F00\u5173\u5FC5\u987B\u662F\u5E03\u5C14\u503C\u3002");
1819
+ }
1820
+ if (!Array.isArray(fields) || ![...fields].every((field) => CONTEXT_ENHANCEMENT_FIELDS.includes(field))) {
1821
+ throw invalidConfig("\u6765\u6E90\u5B57\u6BB5\u53EA\u80FD\u9009\u62E9\u5DF2\u5B9A\u4E49\u7684\u4E94\u4E2A\u5B57\u6BB5\u3002");
1822
+ }
1823
+ if (typeof guidance !== "string" || guidance.length > CONTEXT_ENHANCEMENT_GUIDANCE_MAX_LENGTH) {
1824
+ throw invalidConfig(`\u589E\u5F3A\u63D0\u793A\u8BCD\u4E0D\u5F97\u8D85\u8FC7 ${CONTEXT_ENHANCEMENT_GUIDANCE_MAX_LENGTH} \u4E2A\u5B57\u7B26\u3002`);
1825
+ }
1826
+ return Object.freeze({
1827
+ groupEnabled,
1828
+ directEnabled,
1829
+ fields: Object.freeze(CONTEXT_ENHANCEMENT_FIELDS.filter((field) => fields.includes(field))),
1830
+ guidance: guidance.trim() ? guidance : ""
1831
+ });
1832
+ }
1833
+ function normalizeContextEnhancementConfig(input) {
1834
+ try {
1835
+ return validateContextEnhancementConfig(input);
1836
+ } catch {
1837
+ return DEFAULT_CONTEXT_ENHANCEMENT_CONFIG;
1838
+ }
1839
+ }
1840
+
1210
1841
  // plugin-src/client/channels/dingtalk/api.js
1211
1842
  var DINGTALK_RPC_CHANNEL = "/dingtalk";
1212
1843
  var DINGTALK_ENDPOINTS = Object.freeze({
@@ -1218,7 +1849,8 @@ var DINGTALK_ENDPOINTS = Object.freeze({
1218
1849
  reconnectBot: "bot.reconnect",
1219
1850
  deleteBot: "bot.delete",
1220
1851
  setWorkspace: "bot.workspace.set",
1221
- setAgentPreset: SET_AGENT_PRESET_ENDPOINT
1852
+ setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
1853
+ setContextEnhancement: "bot.context-enhancement.set"
1222
1854
  });
1223
1855
  var ACCOUNT_STATES = /* @__PURE__ */ new Set(["connected", "connecting", "offline", "error"]);
1224
1856
  var SNAPSHOT_STATES = /* @__PURE__ */ new Set(["disconnected", "offline", "provisioning", "connected", "degraded"]);
@@ -1347,6 +1979,7 @@ function normalizeBot(value) {
1347
1979
  configured: value.configured !== false,
1348
1980
  workspace: optionalString(value.workspace, 4096) ?? "",
1349
1981
  agentPreset: normalizeAgentPresetId(value.agentPreset),
1982
+ contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
1350
1983
  bot: {
1351
1984
  name: optionalString(bot.name, 100) ?? "\u9489\u9489\u673A\u5668\u4EBA",
1352
1985
  clientIdMasked: optionalString(bot.clientIdMasked, 140) ?? "\u5DF2\u5B89\u5168\u4FDD\u5B58"
@@ -1409,7 +2042,7 @@ function formatRemaining(milliseconds) {
1409
2042
  }
1410
2043
 
1411
2044
  // plugin-src/client/channels/dingtalk/index.js
1412
- var React9 = __toESM(require("react"), 1);
2045
+ var React10 = __toESM(require("react"), 1);
1413
2046
 
1414
2047
  // plugin-src/client/credential-binding.js
1415
2048
  var React4 = __toESM(require("react"), 1);
@@ -1927,11 +2560,395 @@ function WorkspaceEditor({ workspace, directoryPicker, disabled = false, onSave
1927
2560
  );
1928
2561
  }
1929
2562
 
1930
- // plugin-src/client/workspace-snapshot-fence.js
2563
+ // plugin-src/client/context-enhancement.js
1931
2564
  var React7 = __toESM(require("react"), 1);
2565
+ var import_react_dom2 = require("react-dom");
2566
+ var FIELD_LABELS = Object.freeze({
2567
+ channel: "\u6E20\u9053",
2568
+ conversationType: "\u4F1A\u8BDD\u7C7B\u578B",
2569
+ senderId: "\u53D1\u9001\u8005\u6807\u8BC6",
2570
+ senderName: "\u53D1\u9001\u8005\u6635\u79F0",
2571
+ botId: "\u673A\u5668\u4EBA\u6807\u8BC6"
2572
+ });
2573
+ function contextEnhancementLabel(config) {
2574
+ const { groupEnabled, directEnabled } = normalizeContextEnhancementConfig(config);
2575
+ if (groupEnabled && directEnabled) return "\u7FA4\u804A\u548C\u79C1\u804A";
2576
+ if (groupEnabled) return "\u4EC5\u7FA4\u804A";
2577
+ if (directEnabled) return "\u4EC5\u79C1\u804A";
2578
+ return "\u672A\u5F00\u542F";
2579
+ }
2580
+ function ContextIcon({ kind = "sliders" }) {
2581
+ const path = kind === "close" ? "M6 6l12 12M6 18 18 6" : kind === "chevron" ? "m9 5 7 7-7 7" : "M21 4h-7M10 4H3M21 12h-9M8 12H3M21 20h-3M14 20H3M14 2v4M8 10v4M18 18v4";
2582
+ return h2("svg", {
2583
+ width: 16,
2584
+ height: 16,
2585
+ viewBox: "0 0 24 24",
2586
+ fill: "none",
2587
+ stroke: "currentColor",
2588
+ strokeWidth: 1.8,
2589
+ strokeLinecap: "round",
2590
+ strokeLinejoin: "round",
2591
+ "aria-hidden": "true",
2592
+ focusable: "false"
2593
+ }, h2("path", { d: path }));
2594
+ }
2595
+ function ContextEnhancementDialog({ config, groupSupported, disabled, onSave, onClose, returnFocusRef, id: id5 }) {
2596
+ const [draft, setDraft] = React7.useState(() => ({
2597
+ ...normalizeContextEnhancementConfig(config),
2598
+ ...!groupSupported ? { groupEnabled: false } : {}
2599
+ }));
2600
+ const [saving, setSaving] = React7.useState(false);
2601
+ const [error, setError] = React7.useState(null);
2602
+ const savingRef = React7.useRef(false);
2603
+ const dialogRef = React7.useRef(null);
2604
+ const mountedRef = React7.useRef(true);
2605
+ const titleId = React7.useId();
2606
+ const descriptionId = React7.useId();
2607
+ const groupNoticeId = React7.useId();
2608
+ const guidanceId = React7.useId();
2609
+ const guidanceHelpId = React7.useId();
2610
+ const fieldIdPrefix = React7.useId();
2611
+ const fieldsHelpId = React7.useId();
2612
+ const senderNameHelpId = React7.useId();
2613
+ const guidanceExample = localizeText(CONTEXT_GUIDANCE_EXAMPLE);
2614
+ const busy = disabled || saving;
2615
+ React7.useEffect(() => {
2616
+ mountedRef.current = true;
2617
+ dialogRef.current?.focus?.();
2618
+ const keepFocus = (event) => {
2619
+ if (dialogRef.current && !dialogRef.current.contains(event.target)) dialogRef.current.focus();
2620
+ };
2621
+ globalThis.document?.addEventListener?.("focusin", keepFocus);
2622
+ return () => {
2623
+ mountedRef.current = false;
2624
+ globalThis.document?.removeEventListener?.("focusin", keepFocus);
2625
+ queueMicrotask(() => returnFocusRef.current?.focus?.());
2626
+ };
2627
+ }, [returnFocusRef]);
2628
+ const change = (key, value) => {
2629
+ if (busy || savingRef.current) return;
2630
+ setDraft((current) => ({ ...current, [key]: value }));
2631
+ setError(null);
2632
+ };
2633
+ const cancel = () => {
2634
+ if (!savingRef.current) onClose();
2635
+ };
2636
+ const save = async () => {
2637
+ if (busy || savingRef.current) return;
2638
+ savingRef.current = true;
2639
+ setSaving(true);
2640
+ setError(null);
2641
+ dialogRef.current?.focus?.();
2642
+ try {
2643
+ const next = validateContextEnhancementConfig(draft);
2644
+ await onSave(next);
2645
+ if (mountedRef.current) onClose();
2646
+ } catch (cause) {
2647
+ if (mountedRef.current) setError(cause?.message ?? "\u4E0A\u4E0B\u6587\u589E\u5F3A\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002");
2648
+ } finally {
2649
+ savingRef.current = false;
2650
+ if (mountedRef.current) setSaving(false);
2651
+ }
2652
+ };
2653
+ const content = h2("div", {
2654
+ className: "dim-contextBackdrop",
2655
+ onMouseDown: (event) => {
2656
+ if (event.target === event.currentTarget) cancel();
2657
+ }
2658
+ }, h2(
2659
+ "section",
2660
+ {
2661
+ id: id5,
2662
+ ref: dialogRef,
2663
+ className: "dim-contextDialog",
2664
+ role: "dialog",
2665
+ "aria-modal": "true",
2666
+ "aria-labelledby": titleId,
2667
+ "aria-describedby": descriptionId,
2668
+ "aria-busy": saving,
2669
+ tabIndex: -1,
2670
+ onKeyDown: (event) => {
2671
+ if (event.key === "Escape") {
2672
+ event.preventDefault();
2673
+ event.stopPropagation();
2674
+ cancel();
2675
+ }
2676
+ if (event.key !== "Tab") return;
2677
+ const controls = dialogRef.current?.querySelectorAll?.(
2678
+ "button:not(:disabled), input:not(:disabled), textarea:not(:disabled)"
2679
+ );
2680
+ if (!controls?.length) {
2681
+ event.preventDefault();
2682
+ dialogRef.current?.focus?.();
2683
+ return;
2684
+ }
2685
+ const first = controls[0];
2686
+ const last = controls[controls.length - 1];
2687
+ const active = globalThis.document?.activeElement;
2688
+ if (event.shiftKey && (active === first || active === dialogRef.current)) {
2689
+ event.preventDefault();
2690
+ last.focus();
2691
+ } else if (!event.shiftKey && (active === last || active === dialogRef.current)) {
2692
+ event.preventDefault();
2693
+ first.focus();
2694
+ }
2695
+ }
2696
+ },
2697
+ h2(
2698
+ "header",
2699
+ { className: "dim-contextHeader" },
2700
+ h2(
2701
+ "div",
2702
+ { className: "dim-contextHeaderTitle" },
2703
+ h2("h3", { id: titleId }, "\u4E0A\u4E0B\u6587\u589E\u5F3A"),
2704
+ h2(
2705
+ "span",
2706
+ { className: "dim-contextHelp dim-contextHeaderHelp" },
2707
+ h2("button", {
2708
+ type: "button",
2709
+ className: "dim-contextHelpButton",
2710
+ disabled: busy,
2711
+ "aria-label": "\u67E5\u770B\u4E0A\u4E0B\u6587\u589E\u5F3A\u8BF4\u660E",
2712
+ "aria-describedby": descriptionId
2713
+ }, h2("span", { "aria-hidden": "true" }, "?")),
2714
+ h2(
2715
+ "span",
2716
+ { id: descriptionId, className: "dim-contextTooltip dim-contextHeaderTooltip", role: "tooltip" },
2717
+ "\u9009\u62E9\u5728\u54EA\u4E9B\u4F1A\u8BDD\u4E2D\u542F\u7528\u3001\u63D0\u4F9B\u54EA\u4E9B\u6765\u6E90\u5B57\u6BB5\uFF0C\u4EE5\u53CA\u5982\u4F55\u4F7F\u7528\u8FD9\u4E9B\u4FE1\u606F\u3002\u4EC5\u4F7F\u7528\u5DF2\u6709\u6D88\u606F\u5143\u6570\u636E\uFF0C\u4E0D\u67E5\u8BE2\u5E73\u53F0 API\u3002"
2718
+ )
2719
+ )
2720
+ ),
2721
+ h2("button", {
2722
+ type: "button",
2723
+ className: "dim-contextClose",
2724
+ "aria-label": "\u5173\u95ED\u5F39\u7A97",
2725
+ disabled: saving,
2726
+ onClick: cancel
2727
+ }, h2(ContextIcon, { kind: "close" }))
2728
+ ),
2729
+ h2(
2730
+ "fieldset",
2731
+ { className: "dim-contextSection", disabled: busy },
2732
+ h2("legend", null, "\u542F\u7528\u8303\u56F4"),
2733
+ h2(
2734
+ "div",
2735
+ { className: "dim-contextSwitches" },
2736
+ h2(
2737
+ "label",
2738
+ { className: "dim-contextSwitchRow" },
2739
+ h2(
2740
+ "span",
2741
+ { className: "dim-contextSwitchLabel" },
2742
+ h2("span", null, "\u7FA4\u804A\u4E2D\u542F\u7528"),
2743
+ !groupSupported ? h2("span", {
2744
+ id: groupNoticeId,
2745
+ className: "dim-contextUnavailable"
2746
+ }, "\uFF08\u5F53\u524D\u6E20\u9053\u4E0D\u652F\u6301\u7FA4\u804A\uFF09") : null
2747
+ ),
2748
+ h2("input", {
2749
+ type: "checkbox",
2750
+ role: "switch",
2751
+ className: "dim-contextSwitch",
2752
+ checked: groupSupported && draft.groupEnabled,
2753
+ disabled: busy || !groupSupported,
2754
+ "aria-describedby": !groupSupported ? groupNoticeId : void 0,
2755
+ onChange: (event) => {
2756
+ if (groupSupported) change("groupEnabled", event.target.checked);
2757
+ }
2758
+ })
2759
+ ),
2760
+ h2(
2761
+ "label",
2762
+ { className: "dim-contextSwitchRow" },
2763
+ h2("span", null, "\u79C1\u804A\u4E2D\u542F\u7528"),
2764
+ h2("input", {
2765
+ type: "checkbox",
2766
+ role: "switch",
2767
+ className: "dim-contextSwitch",
2768
+ checked: draft.directEnabled,
2769
+ disabled: busy,
2770
+ onChange: (event) => change("directEnabled", event.target.checked)
2771
+ })
2772
+ )
2773
+ )
2774
+ ),
2775
+ h2(
2776
+ "fieldset",
2777
+ { className: "dim-contextSection", disabled: busy },
2778
+ h2(
2779
+ "legend",
2780
+ { className: "dim-contextLegend" },
2781
+ h2("span", null, "\u6765\u6E90\u5B57\u6BB5"),
2782
+ h2(
2783
+ "span",
2784
+ { className: "dim-contextHelp dim-contextLegendHelp" },
2785
+ h2("button", {
2786
+ type: "button",
2787
+ className: "dim-contextHelpButton",
2788
+ disabled: busy,
2789
+ "aria-label": "\u67E5\u770B\u6765\u6E90\u5B57\u6BB5\u8BF4\u660E",
2790
+ "aria-describedby": fieldsHelpId
2791
+ }, h2("span", { "aria-hidden": "true" }, "?")),
2792
+ h2(
2793
+ "span",
2794
+ { id: fieldsHelpId, className: "dim-contextTooltip dim-contextLegendTooltip", role: "tooltip" },
2795
+ "\u589E\u5F3A\u63D0\u793A\u8BCD\u4E2D\u8BF7\u4F7F\u7528\u5B57\u6BB5\u540D\uFF08\u5982 senderId\u3001conversationType\uFF09\u5F15\u7528\u8FD9\u4E9B\u4FE1\u606F\u3002\u53EA\u53D1\u9001\u52FE\u9009\u4E14\u5F53\u524D\u6D88\u606F\u4E2D\u53EF\u7528\u7684\u5B57\u6BB5\uFF0C\u4E0D\u4F1A\u989D\u5916\u67E5\u8BE2\u6216\u8865\u5168\u3002"
2796
+ )
2797
+ )
2798
+ ),
2799
+ h2("div", { className: "dim-contextFields" }, CONTEXT_ENHANCEMENT_FIELDS.map((field) => {
2800
+ const fieldId = `${fieldIdPrefix}-${field}`;
2801
+ return h2(
2802
+ "div",
2803
+ { key: field, className: "dim-contextField" },
2804
+ h2("input", {
2805
+ id: fieldId,
2806
+ type: "checkbox",
2807
+ name: field,
2808
+ checked: draft.fields.includes(field),
2809
+ disabled: busy,
2810
+ onChange: (event) => change("fields", event.target.checked ? [...draft.fields, field] : draft.fields.filter((value) => value !== field))
2811
+ }),
2812
+ h2(
2813
+ "span",
2814
+ { className: "dim-contextFieldText" },
2815
+ h2("label", { className: "dim-contextFieldName", htmlFor: fieldId }, FIELD_LABELS[field]),
2816
+ field === "senderName" ? h2(
2817
+ "span",
2818
+ { className: "dim-contextHelp dim-contextFieldHelp" },
2819
+ h2("button", {
2820
+ type: "button",
2821
+ className: "dim-contextHelpButton dim-contextFieldHelpButton",
2822
+ disabled: busy,
2823
+ "aria-label": "\u67E5\u770B\u53D1\u9001\u8005\u6635\u79F0\u5B57\u6BB5\u8BF4\u660E",
2824
+ "aria-describedby": senderNameHelpId
2825
+ }, h2("span", { "aria-hidden": "true" }, "?")),
2826
+ h2("span", {
2827
+ id: senderNameHelpId,
2828
+ className: "dim-contextTooltip dim-contextFieldTooltip",
2829
+ role: "tooltip"
2830
+ }, "\u8BE5\u5B57\u6BB5\u4E0D\u662F\u6BCF\u4E2A\u6E20\u9053\u90FD\u80FD\u63D0\u4F9B\u3002\u5F53\u524D\u6D88\u606F\u6CA1\u6709\u53D1\u9001\u8005\u6635\u79F0\u65F6\uFF0C\u5373\u4F7F\u5DF2\u9009\u62E9\u8BE5\u5B57\u6BB5\uFF0C<dsh_im_source> \u4E2D\u4E5F\u4F1A\u7701\u7565 senderName\u3002")
2831
+ ) : null,
2832
+ h2("label", { className: "dim-contextFieldKey", htmlFor: fieldId }, field)
2833
+ )
2834
+ );
2835
+ }))
2836
+ ),
2837
+ h2(
2838
+ "div",
2839
+ { className: "dim-contextGuidance" },
2840
+ h2(
2841
+ "div",
2842
+ { className: "dim-contextEditorHeader" },
2843
+ h2(
2844
+ "span",
2845
+ { className: "dim-contextEditorTitle" },
2846
+ h2("label", { htmlFor: guidanceId }, "\u589E\u5F3A\u63D0\u793A\u8BCD"),
2847
+ h2(
2848
+ "span",
2849
+ { className: "dim-contextHelp" },
2850
+ h2("button", {
2851
+ type: "button",
2852
+ className: "dim-contextHelpButton",
2853
+ disabled: busy,
2854
+ "aria-label": "\u67E5\u770B\u589E\u5F3A\u63D0\u793A\u8BCD\u4F7F\u7528\u8BF4\u660E",
2855
+ "aria-describedby": guidanceHelpId
2856
+ }, h2("span", { "aria-hidden": "true" }, "?")),
2857
+ h2(
2858
+ "span",
2859
+ { id: guidanceHelpId, className: "dim-contextTooltip dim-contextGuidanceTooltip", role: "tooltip" },
2860
+ h2("strong", null, "\u4F7F\u7528\u8BF4\u660E"),
2861
+ h2("span", null, "\u7528\u4E8E\u544A\u8BC9\u6A21\u578B\u5982\u4F55\u4F7F\u7528 <dsh_im_source> \u4E2D\u5DF2\u9009\u62E9\u7684\u6765\u6E90\u5B57\u6BB5\u3002\u53EA\u586B\u5199\u6B63\u6587\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u6DFB\u52A0 <dsh_im_source_guidance> \u6210\u5BF9\u6807\u7B7E\u3002"),
2862
+ h2("strong", null, "\u751F\u6548\u89C4\u5219"),
2863
+ h2("span", null, "\u53EA\u9700\u586B\u5199\u6B63\u6587\uFF0C\u63D2\u4EF6\u81EA\u52A8\u6DFB\u52A0 <dsh_im_source_guidance> \u6210\u5BF9\u6807\u7B7E\u3002\u6E05\u7A7A\u5E76\u4FDD\u5B58\u540E\uFF0C\u4E0D\u518D\u9644\u52A0\u589E\u5F3A\u63D0\u793A\u8BCD\uFF0C\u5DF2\u9009\u6765\u6E90\u5B57\u6BB5\u4ECD\u6309\u5F00\u5173\u8BBE\u7F6E\u53D1\u9001\u3002"),
2864
+ h2("strong", null, "\u9690\u79C1\u63D0\u793A"),
2865
+ h2("span", null, "\u53D1\u9001\u8005\u6807\u8BC6\u53EF\u80FD\u5305\u542B\u5E73\u53F0\u7528\u6237 ID \u6216\u7535\u8BDD\u53F7\u7801\u5F62\u5F0F\u7684\u6807\u8BC6\u3002\u5173\u95ED\u5F00\u5173\u4E0D\u4F1A\u5220\u9664\u5DF2\u7ECF\u5199\u5165\u4F1A\u8BDD\u5386\u53F2\u7684\u4FE1\u606F\u3002"),
2866
+ h2("strong", null, "\u4F7F\u7528\u793A\u4F8B"),
2867
+ h2("span", { className: "dim-contextTooltipExample" }, guidanceExample)
2868
+ )
2869
+ )
2870
+ ),
2871
+ h2(
2872
+ "div",
2873
+ { className: "dim-contextTextActions" },
2874
+ h2("button", { type: "button", disabled: busy, onClick: () => change("guidance", guidanceExample) }, "\u586B\u5165\u793A\u4F8B"),
2875
+ h2("button", { type: "button", disabled: busy, onClick: () => change("guidance", "") }, "\u6E05\u7A7A")
2876
+ )
2877
+ ),
2878
+ h2("textarea", {
2879
+ id: guidanceId,
2880
+ value: draft.guidance,
2881
+ placeholder: guidanceExample,
2882
+ rows: 4,
2883
+ disabled: busy,
2884
+ maxLength: CONTEXT_ENHANCEMENT_GUIDANCE_MAX_LENGTH,
2885
+ "aria-describedby": guidanceHelpId,
2886
+ onChange: (event) => change("guidance", event.target.value)
2887
+ })
2888
+ ),
2889
+ error ? h2("p", { className: "dim-contextError", role: "alert" }, error) : null,
2890
+ h2(
2891
+ "footer",
2892
+ { className: "dim-contextFooter" },
2893
+ h2("button", { type: "button", disabled: saving, onClick: cancel }, "\u53D6\u6D88"),
2894
+ h2("button", {
2895
+ type: "button",
2896
+ className: "dim-contextSave",
2897
+ disabled: busy,
2898
+ onClick: () => {
2899
+ void save();
2900
+ }
2901
+ }, saving ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58")
2902
+ )
2903
+ ));
2904
+ return globalThis.document?.body ? (0, import_react_dom2.createPortal)(content, document.body) : content;
2905
+ }
2906
+ function ContextEnhancementEditor({ config, groupSupported = true, disabled = false, onSave }) {
2907
+ const [open, setOpen] = React7.useState(false);
2908
+ const entryRef = React7.useRef(null);
2909
+ const dialogId = React7.useId();
2910
+ const statusId = React7.useId();
2911
+ const saved = normalizeContextEnhancementConfig(config);
2912
+ const label = contextEnhancementLabel(groupSupported ? saved : { ...saved, groupEnabled: false });
2913
+ return h2(
2914
+ React7.Fragment,
2915
+ null,
2916
+ h2(
2917
+ "button",
2918
+ {
2919
+ type: "button",
2920
+ ref: entryRef,
2921
+ className: "dim-contextEntry",
2922
+ disabled,
2923
+ "aria-label": "\u4E0A\u4E0B\u6587\u589E\u5F3A",
2924
+ "aria-describedby": statusId,
2925
+ "aria-haspopup": "dialog",
2926
+ "aria-expanded": open,
2927
+ "aria-controls": open ? dialogId : void 0,
2928
+ onClick: () => setOpen(true)
2929
+ },
2930
+ h2(ContextIcon),
2931
+ h2("span", { className: "dim-contextLabel" }, "\u4E0A\u4E0B\u6587\u589E\u5F3A"),
2932
+ h2("span", { id: statusId, className: "dim-contextStatus", "data-active": label !== "\u672A\u5F00\u542F", "aria-live": "polite" }, label),
2933
+ h2(ContextIcon, { kind: "chevron" })
2934
+ ),
2935
+ open ? h2(ContextEnhancementDialog, {
2936
+ id: dialogId,
2937
+ config,
2938
+ groupSupported,
2939
+ disabled,
2940
+ onSave,
2941
+ onClose: () => setOpen(false),
2942
+ returnFocusRef: entryRef
2943
+ }) : null
2944
+ );
2945
+ }
2946
+
2947
+ // plugin-src/client/workspace-snapshot-fence.js
2948
+ var React8 = __toESM(require("react"), 1);
1932
2949
  function useWorkspaceSnapshotFence() {
1933
- const state = React7.useRef({ version: 0, pendingMutations: 0 });
1934
- return React7.useMemo(() => Object.freeze({
2950
+ const state = React8.useRef({ version: 0, pendingMutations: 0 });
2951
+ return React8.useMemo(() => Object.freeze({
1935
2952
  beginStatus() {
1936
2953
  return state.current.pendingMutations === 0 ? state.current.version : null;
1937
2954
  },
@@ -1954,7 +2971,7 @@ function useWorkspaceSnapshotFence() {
1954
2971
  }
1955
2972
 
1956
2973
  // plugin-src/client/channel-card-meta.js
1957
- var React8 = __toESM(require("react"), 1);
2974
+ var React9 = __toESM(require("react"), 1);
1958
2975
  function messageErrorTime(value) {
1959
2976
  try {
1960
2977
  return new Intl.DateTimeFormat(isEnglish() ? "en-US" : "zh-CN", {
@@ -1969,7 +2986,7 @@ function messageErrorTime(value) {
1969
2986
  }
1970
2987
  }
1971
2988
  function ChannelListHeading({ className = "", id: id5, title, connectionLabel }) {
1972
- const helpId = React8.useId();
2989
+ const helpId = React9.useId();
1973
2990
  return h2(
1974
2991
  "div",
1975
2992
  { className: `${className} dim-listHeading`.trim() },
@@ -2050,7 +3067,7 @@ function LastMessageErrorSummary({ className = "", error }) {
2050
3067
  h2("span", null, "\u53C2\u8003\u53F7"),
2051
3068
  ` ${error.referenceId}`,
2052
3069
  occurredAt ? h2(
2053
- React8.Fragment,
3070
+ React9.Fragment,
2054
3071
  null,
2055
3072
  " \xB7 ",
2056
3073
  h2("time", { dateTime: new Date(error.at).toISOString() }, occurredAt)
@@ -2211,7 +3228,7 @@ function DingtalkIcon({ size = 28 }) {
2211
3228
  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"
2212
3229
  }));
2213
3230
  }
2214
- var Button = React9.forwardRef(function Button2({ children, kind = "secondary", className = "", ...props }, ref) {
3231
+ var Button = React10.forwardRef(function Button2({ children, kind = "secondary", className = "", ...props }, ref) {
2215
3232
  return h2("button", {
2216
3233
  ...props,
2217
3234
  ref,
@@ -2307,13 +3324,13 @@ function EmptyView({ busy, onStart }) {
2307
3324
  );
2308
3325
  }
2309
3326
  function QrPanel({ provision, now, busy, onRefresh, onCancel }) {
2310
- const [imageFailed, setImageFailed] = React9.useState(false);
3327
+ const [imageFailed, setImageFailed] = React10.useState(false);
2311
3328
  const source = safeQrSource(provision.qrCodeDataUrl);
2312
3329
  const remaining = Math.max(0, provision.expiresAt - now);
2313
3330
  const expired = remaining === 0 || provision.status === "expired";
2314
3331
  const duration = Math.max(1, provision.durationMs ?? 10 * 6e4);
2315
3332
  const progress = Math.round(Math.min(1, remaining / duration) * 100);
2316
- React9.useEffect(() => setImageFailed(false), [source]);
3333
+ React10.useEffect(() => setImageFailed(false), [source]);
2317
3334
  return h2(
2318
3335
  "div",
2319
3336
  { className: "ddt-card dim-surfaceCard" },
@@ -2430,8 +3447,8 @@ function checkedTime(value) {
2430
3447
  }
2431
3448
  }
2432
3449
  function RemoveConfirmation({ account, busy, onConfirm, onCancel }) {
2433
- const cancelRef = React9.useRef(null);
2434
- React9.useEffect(() => cancelRef.current?.focus(), []);
3450
+ const cancelRef = React10.useRef(null);
3451
+ React10.useEffect(() => cancelRef.current?.focus(), []);
2435
3452
  return h2(
2436
3453
  "div",
2437
3454
  {
@@ -2464,6 +3481,7 @@ function AccountCard({
2464
3481
  onReconnect,
2465
3482
  onWorkspaceSave,
2466
3483
  onAgentPresetSave,
3484
+ onContextEnhancementSave,
2467
3485
  onRequestRemove,
2468
3486
  onConfirmRemove,
2469
3487
  onCancelRemove
@@ -2511,6 +3529,11 @@ function AccountCard({
2511
3529
  disabled: Boolean(busy),
2512
3530
  onSave: onAgentPresetSave
2513
3531
  }),
3532
+ h2(ContextEnhancementEditor, {
3533
+ config: account.contextEnhancement,
3534
+ disabled: Boolean(busy),
3535
+ onSave: onContextEnhancementSave
3536
+ }),
2514
3537
  h2(
2515
3538
  "div",
2516
3539
  { className: "ddt-accountFooter dim-cardFooter" },
@@ -2571,6 +3594,7 @@ function AccountList(props) {
2571
3594
  onReconnect: () => props.onReconnect(account),
2572
3595
  onWorkspaceSave: (workspace) => props.onWorkspaceSave(account, workspace),
2573
3596
  onAgentPresetSave: (agentPreset) => props.onAgentPresetSave(account, agentPreset),
3597
+ onContextEnhancementSave: (config) => props.onContextEnhancementSave(account, config),
2574
3598
  onRequestRemove: () => props.onRequestRemove(account),
2575
3599
  onConfirmRemove: () => props.onConfirmRemove(account),
2576
3600
  onCancelRemove: props.onCancelRemove
@@ -2580,7 +3604,7 @@ function AccountList(props) {
2580
3604
  }
2581
3605
  var EMPTY_TOTALS = Object.freeze({ configured: 0, connected: 0 });
2582
3606
  function DingtalkSettingsTab({ rpcCall }) {
2583
- const [model, setModel] = React9.useState({
3607
+ const [model, setModel] = React10.useState({
2584
3608
  phase: "loading",
2585
3609
  bots: [],
2586
3610
  totals: EMPTY_TOTALS,
@@ -2588,22 +3612,22 @@ function DingtalkSettingsTab({ rpcCall }) {
2588
3612
  error: null,
2589
3613
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
2590
3614
  });
2591
- const [provision, setProvision] = React9.useState(null);
2592
- const [busy, setBusy] = React9.useState(false);
2593
- const [busyByBot, setBusyByBot] = React9.useState({});
2594
- const [feedbackByBot, setFeedbackByBot] = React9.useState({});
2595
- const [removeTarget, setRemoveTarget] = React9.useState(null);
2596
- const [credentialOpen, setCredentialOpen] = React9.useState(false);
2597
- const [credentialError, setCredentialError] = React9.useState(null);
2598
- const [notice, setNotice] = React9.useState("");
2599
- const [now, setNow] = React9.useState(() => Date.now());
2600
- const addButtonRef = React9.useRef(null);
2601
- const mountedRef = React9.useRef(true);
2602
- const statusRequestRef = React9.useRef(0);
3615
+ const [provision, setProvision] = React10.useState(null);
3616
+ const [busy, setBusy] = React10.useState(false);
3617
+ const [busyByBot, setBusyByBot] = React10.useState({});
3618
+ const [feedbackByBot, setFeedbackByBot] = React10.useState({});
3619
+ const [removeTarget, setRemoveTarget] = React10.useState(null);
3620
+ const [credentialOpen, setCredentialOpen] = React10.useState(false);
3621
+ const [credentialError, setCredentialError] = React10.useState(null);
3622
+ const [notice, setNotice] = React10.useState("");
3623
+ const [now, setNow] = React10.useState(() => Date.now());
3624
+ const addButtonRef = React10.useRef(null);
3625
+ const mountedRef = React10.useRef(true);
3626
+ const statusRequestRef = React10.useRef(0);
2603
3627
  const workspaceFence = useWorkspaceSnapshotFence();
2604
- const noticeFrameRef = React9.useRef(null);
2605
- const focusFrameRef = React9.useRef(null);
2606
- React9.useEffect(() => {
3628
+ const noticeFrameRef = React10.useRef(null);
3629
+ const focusFrameRef = React10.useRef(null);
3630
+ React10.useEffect(() => {
2607
3631
  mountedRef.current = true;
2608
3632
  return () => {
2609
3633
  mountedRef.current = false;
@@ -2618,8 +3642,8 @@ function DingtalkSettingsTab({ rpcCall }) {
2618
3642
  }
2619
3643
  };
2620
3644
  }, []);
2621
- React9.useEffect(() => installDingtalkStyles(), []);
2622
- const announce = React9.useCallback((message) => {
3645
+ React10.useEffect(() => installDingtalkStyles(), []);
3646
+ const announce = React10.useCallback((message) => {
2623
3647
  if (!mountedRef.current) return;
2624
3648
  if (noticeFrameRef.current !== null) {
2625
3649
  window.cancelAnimationFrame(noticeFrameRef.current);
@@ -2633,7 +3657,7 @@ function DingtalkSettingsTab({ rpcCall }) {
2633
3657
  });
2634
3658
  }
2635
3659
  }, []);
2636
- const discardStaleFeedback = React9.useCallback((snapshot) => {
3660
+ const discardStaleFeedback = React10.useCallback((snapshot) => {
2637
3661
  const botsById = new Map(snapshot.bots.map((bot) => [bot.botId, bot]));
2638
3662
  setFeedbackByBot((current) => {
2639
3663
  let changed = false;
@@ -2648,7 +3672,7 @@ function DingtalkSettingsTab({ rpcCall }) {
2648
3672
  return changed ? next : current;
2649
3673
  });
2650
3674
  }, []);
2651
- const focusAddButton = React9.useCallback(() => {
3675
+ const focusAddButton = React10.useCallback(() => {
2652
3676
  if (!mountedRef.current) return;
2653
3677
  if (focusFrameRef.current !== null) window.cancelAnimationFrame(focusFrameRef.current);
2654
3678
  focusFrameRef.current = window.requestAnimationFrame(() => {
@@ -2656,11 +3680,11 @@ function DingtalkSettingsTab({ rpcCall }) {
2656
3680
  if (mountedRef.current) addButtonRef.current?.focus();
2657
3681
  });
2658
3682
  }, []);
2659
- const invoke = React9.useCallback(async (endpoint, payload = {}, signal) => {
3683
+ const invoke = React10.useCallback(async (endpoint, payload = {}, signal) => {
2660
3684
  if (typeof rpcCall !== "function") throw new TypeError("\u9489\u9489\u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
2661
3685
  return unwrapRpcResult(await rpcCall(endpoint, payload, signal));
2662
3686
  }, [rpcCall]);
2663
- const loadStatus = React9.useCallback(async ({
3687
+ const loadStatus = React10.useCallback(async ({
2664
3688
  signal,
2665
3689
  silent = false,
2666
3690
  restoreProvisioning = false
@@ -2704,12 +3728,12 @@ function DingtalkSettingsTab({ rpcCall }) {
2704
3728
  return void 0;
2705
3729
  }
2706
3730
  }, [discardStaleFeedback, invoke, workspaceFence]);
2707
- React9.useEffect(() => {
3731
+ React10.useEffect(() => {
2708
3732
  const controller = new AbortController();
2709
3733
  void loadStatus({ signal: controller.signal, restoreProvisioning: true });
2710
3734
  return () => controller.abort();
2711
3735
  }, [loadStatus]);
2712
- React9.useEffect(() => {
3736
+ React10.useEffect(() => {
2713
3737
  if (model.phase !== "ready") return void 0;
2714
3738
  const controller = new AbortController();
2715
3739
  let running = false;
@@ -2728,14 +3752,14 @@ function DingtalkSettingsTab({ rpcCall }) {
2728
3752
  window.clearInterval(timer);
2729
3753
  };
2730
3754
  }, [loadStatus, model.phase]);
2731
- React9.useEffect(() => {
3755
+ React10.useEffect(() => {
2732
3756
  if (!provision || !ACTIVE_PROVISION_STATES.has(provision.status)) return void 0;
2733
3757
  const timer = window.setInterval(() => {
2734
3758
  if (mountedRef.current) setNow(Date.now());
2735
3759
  }, 1e3);
2736
3760
  return () => window.clearInterval(timer);
2737
3761
  }, [provision?.attemptId, provision?.status]);
2738
- const startProvisioning = React9.useCallback(async ({ replace = false } = {}) => {
3762
+ const startProvisioning = React10.useCallback(async ({ replace = false } = {}) => {
2739
3763
  if (!mountedRef.current) return;
2740
3764
  setCredentialOpen(false);
2741
3765
  setCredentialError(null);
@@ -2773,7 +3797,7 @@ function DingtalkSettingsTab({ rpcCall }) {
2773
3797
  if (mountedRef.current) setBusy(false);
2774
3798
  }
2775
3799
  }, [announce, invoke, provision?.attemptId]);
2776
- const bindCredentials = React9.useCallback(async ({ identity, secret }) => {
3800
+ const bindCredentials = React10.useCallback(async ({ identity, secret }) => {
2777
3801
  if (!mountedRef.current) return;
2778
3802
  const snapshotVersion = workspaceFence.beginMutation();
2779
3803
  setBusy(true);
@@ -2805,7 +3829,7 @@ function DingtalkSettingsTab({ rpcCall }) {
2805
3829
  if (mountedRef.current) setBusy(false);
2806
3830
  }
2807
3831
  }, [announce, discardStaleFeedback, invoke, loadStatus, workspaceFence]);
2808
- const cancelProvisioning = React9.useCallback(async () => {
3832
+ const cancelProvisioning = React10.useCallback(async () => {
2809
3833
  if (!mountedRef.current) return;
2810
3834
  setBusy(true);
2811
3835
  try {
@@ -2823,7 +3847,7 @@ function DingtalkSettingsTab({ rpcCall }) {
2823
3847
  if (mountedRef.current) setBusy(false);
2824
3848
  }
2825
3849
  }, [announce, focusAddButton, invoke, provision?.attemptId, provision?.status]);
2826
- React9.useEffect(() => {
3850
+ React10.useEffect(() => {
2827
3851
  const attemptId = provision?.attemptId;
2828
3852
  if (!attemptId || !ACTIVE_PROVISION_STATES.has(provision.status)) return void 0;
2829
3853
  const controller = new AbortController();
@@ -2882,7 +3906,7 @@ function DingtalkSettingsTab({ rpcCall }) {
2882
3906
  timer = null;
2883
3907
  };
2884
3908
  }, [announce, invoke, loadStatus, provision?.attemptId, provision?.pollIntervalMs, provision?.status]);
2885
- const setBotBusy = React9.useCallback((botId, operation) => {
3909
+ const setBotBusy = React10.useCallback((botId, operation) => {
2886
3910
  if (!mountedRef.current) return;
2887
3911
  setBusyByBot((current) => {
2888
3912
  const next = { ...current };
@@ -2891,7 +3915,7 @@ function DingtalkSettingsTab({ rpcCall }) {
2891
3915
  return next;
2892
3916
  });
2893
3917
  }, []);
2894
- const runBotAction = React9.useCallback(async ({ account, operation, endpoint, payload, success }) => {
3918
+ const runBotAction = React10.useCallback(async ({ account, operation, endpoint, payload, success }) => {
2895
3919
  if (!mountedRef.current) return void 0;
2896
3920
  const snapshotVersion = workspaceFence.beginMutation();
2897
3921
  setBotBusy(account.botId, operation);
@@ -2945,7 +3969,7 @@ function DingtalkSettingsTab({ rpcCall }) {
2945
3969
  if (mountedRef.current) setBotBusy(account.botId, null);
2946
3970
  }
2947
3971
  }, [announce, discardStaleFeedback, invoke, loadStatus, setBotBusy, workspaceFence]);
2948
- const reconnect = React9.useCallback((account) => runBotAction({
3972
+ const reconnect = React10.useCallback((account) => runBotAction({
2949
3973
  account,
2950
3974
  operation: "reconnect",
2951
3975
  endpoint: DINGTALK_ENDPOINTS.reconnectBot,
@@ -2956,7 +3980,7 @@ function DingtalkSettingsTab({ rpcCall }) {
2956
3980
  return connectionTestFeedback(snapshot.testMessage) ?? "\u9489\u9489\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\u3002";
2957
3981
  }
2958
3982
  }), [runBotAction]);
2959
- const saveWorkspace = React9.useCallback(async (account, workspace) => {
3983
+ const saveWorkspace = React10.useCallback(async (account, workspace) => {
2960
3984
  const workspaceVersion = workspaceFence.beginMutation();
2961
3985
  setBotBusy(account.botId, "workspace");
2962
3986
  try {
@@ -2981,13 +4005,13 @@ function DingtalkSettingsTab({ rpcCall }) {
2981
4005
  if (mountedRef.current) setBotBusy(account.botId, null);
2982
4006
  }
2983
4007
  }, [discardStaleFeedback, invoke, loadStatus, setBotBusy, workspaceFence]);
2984
- const saveAgentPreset = React9.useCallback(async (account, agentPreset) => {
4008
+ const saveBotSetting = React10.useCallback(async (account, operation, endpoint, payload) => {
2985
4009
  const snapshotVersion = workspaceFence.beginMutation();
2986
- setBotBusy(account.botId, "preset");
4010
+ setBotBusy(account.botId, operation);
2987
4011
  try {
2988
4012
  const snapshot = normalizeSnapshot(await invoke(
2989
- DINGTALK_ENDPOINTS.setAgentPreset,
2990
- { botId: account.botId, agentPreset }
4013
+ endpoint,
4014
+ { botId: account.botId, ...payload }
2991
4015
  ));
2992
4016
  if (mountedRef.current && workspaceFence.canCommitMutation(snapshotVersion)) {
2993
4017
  setModel({
@@ -3006,7 +4030,7 @@ function DingtalkSettingsTab({ rpcCall }) {
3006
4030
  if (mountedRef.current) setBotBusy(account.botId, null);
3007
4031
  }
3008
4032
  }, [discardStaleFeedback, invoke, loadStatus, setBotBusy, workspaceFence]);
3009
- const remove = React9.useCallback(async (account) => {
4033
+ const remove = React10.useCallback(async (account) => {
3010
4034
  const snapshot = await runBotAction({
3011
4035
  account,
3012
4036
  operation: "delete",
@@ -3090,7 +4114,7 @@ function DingtalkSettingsTab({ rpcCall }) {
3090
4114
  h2(Button, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
3091
4115
  )
3092
4116
  ) : h2(
3093
- React9.Fragment,
4117
+ React10.Fragment,
3094
4118
  null,
3095
4119
  credentialView,
3096
4120
  provisionView,
@@ -3102,7 +4126,18 @@ function DingtalkSettingsTab({ rpcCall }) {
3102
4126
  removeTarget,
3103
4127
  onReconnect: (account) => void reconnect(account),
3104
4128
  onWorkspaceSave: saveWorkspace,
3105
- onAgentPresetSave: saveAgentPreset,
4129
+ onAgentPresetSave: (account, agentPreset) => saveBotSetting(
4130
+ account,
4131
+ "preset",
4132
+ DINGTALK_ENDPOINTS.setAgentPreset,
4133
+ { agentPreset }
4134
+ ),
4135
+ onContextEnhancementSave: (account, config) => saveBotSetting(
4136
+ account,
4137
+ "context-enhancement",
4138
+ DINGTALK_ENDPOINTS.setContextEnhancement,
4139
+ { config }
4140
+ ),
3106
4141
  onRequestRemove: (account) => setRemoveTarget(account.botId),
3107
4142
  onConfirmRemove: (account) => void remove(account),
3108
4143
  onCancelRemove: () => setRemoveTarget(null)
@@ -3134,7 +4169,8 @@ var TOKEN_BOT_ENDPOINTS = Object.freeze({
3134
4169
  reconnectBot: "bot.reconnect",
3135
4170
  deleteBot: "bot.delete",
3136
4171
  setWorkspace: "bot.workspace.set",
3137
- setAgentPreset: SET_AGENT_PRESET_ENDPOINT
4172
+ setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
4173
+ setContextEnhancement: "bot.context-enhancement.set"
3138
4174
  });
3139
4175
  function createTokenChannelApi(channel4, connectionSummary, {
3140
4176
  normalizeBotExtension = () => ({})
@@ -3161,6 +4197,7 @@ function createTokenChannelApi(channel4, connectionSummary, {
3161
4197
  state: connected ? "connected" : state,
3162
4198
  workspace: text2(value.workspace, "", 4096),
3163
4199
  agentPreset: normalizeAgentPresetId(value.agentPreset),
4200
+ contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
3164
4201
  bot: {
3165
4202
  name: text2(value.bot?.name, `${channel4}\u673A\u5668\u4EBA`, 100),
3166
4203
  username: text2(value.bot?.username, "", 100),
@@ -3210,8 +4247,8 @@ var normalizeSnapshot2 = api.normalizeSnapshot;
3210
4247
  var presentError2 = api.presentError;
3211
4248
 
3212
4249
  // plugin-src/client/channels/shared/token-channel.js
3213
- var React10 = __toESM(require("react"), 1);
3214
- var Button3 = React10.forwardRef(function Button4({ children, kind = "secondary", className = "", ...props }, ref) {
4250
+ var React11 = __toESM(require("react"), 1);
4251
+ var Button3 = React11.forwardRef(function Button4({ children, kind = "secondary", className = "", ...props }, ref) {
3215
4252
  return h2("button", {
3216
4253
  ...props,
3217
4254
  ref,
@@ -3263,7 +4300,7 @@ function createTokenChannelSettings(definition) {
3263
4300
  AccountSettings = null,
3264
4301
  accountSettingsEndpoint = null
3265
4302
  } = definition;
3266
- function AccountCard5({ account, busy, testNotice, removing, onReconnect, onWorkspaceSave, onAgentPresetSave, onAccountSettingsSave, onRequestRemove, onConfirmRemove, onCancelRemove }) {
4303
+ function AccountCard5({ account, busy, testNotice, removing, onReconnect, onWorkspaceSave, onAgentPresetSave, onContextEnhancementSave, onAccountSettingsSave, onRequestRemove, onConfirmRemove, onCancelRemove }) {
3267
4304
  const state = busy === "reconnect" ? "connecting" : account.state;
3268
4305
  const tone = account.connected ? "success" : state === "error" ? "error" : "warning";
3269
4306
  const stateLabel2 = account.connected ? "\u8FD0\u884C\u6B63\u5E38" : state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA";
@@ -3312,6 +4349,11 @@ function createTokenChannelSettings(definition) {
3312
4349
  disabled: Boolean(busy),
3313
4350
  onSave: onAgentPresetSave
3314
4351
  }),
4352
+ h2(ContextEnhancementEditor, {
4353
+ config: account.contextEnhancement,
4354
+ disabled: Boolean(busy),
4355
+ onSave: onContextEnhancementSave
4356
+ }),
3315
4357
  AccountSettings ? h2(AccountSettings, {
3316
4358
  account,
3317
4359
  busy: Boolean(busy),
@@ -3369,22 +4411,22 @@ function createTokenChannelSettings(definition) {
3369
4411
  );
3370
4412
  }
3371
4413
  function SettingsTab({ rpcCall }) {
3372
- const [model, setModel] = React10.useState({
4414
+ const [model, setModel] = React11.useState({
3373
4415
  phase: "loading",
3374
4416
  bots: [],
3375
4417
  totals: { configured: 0, connected: 0 },
3376
4418
  error: null,
3377
4419
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
3378
4420
  });
3379
- const [credentialOpen, setCredentialOpen] = React10.useState(false);
3380
- const [credentialError, setCredentialError] = React10.useState(null);
3381
- const [busy, setBusy] = React10.useState(false);
3382
- const [busyByBot, setBusyByBot] = React10.useState({});
3383
- const [testNoticeByBot, setTestNoticeByBot] = React10.useState({});
3384
- const [removeTarget, setRemoveTarget] = React10.useState(null);
3385
- const mounted = React10.useRef(true);
4421
+ const [credentialOpen, setCredentialOpen] = React11.useState(false);
4422
+ const [credentialError, setCredentialError] = React11.useState(null);
4423
+ const [busy, setBusy] = React11.useState(false);
4424
+ const [busyByBot, setBusyByBot] = React11.useState({});
4425
+ const [testNoticeByBot, setTestNoticeByBot] = React11.useState({});
4426
+ const [removeTarget, setRemoveTarget] = React11.useState(null);
4427
+ const mounted = React11.useRef(true);
3386
4428
  const workspaceFence = useWorkspaceSnapshotFence();
3387
- React10.useEffect(() => {
4429
+ React11.useEffect(() => {
3388
4430
  const disposeDingtalk = installDingtalkStyles();
3389
4431
  const disposeChannel = installStyles();
3390
4432
  mounted.current = true;
@@ -3394,11 +4436,11 @@ function createTokenChannelSettings(definition) {
3394
4436
  disposeDingtalk();
3395
4437
  };
3396
4438
  }, []);
3397
- const invoke = React10.useCallback(async (endpoint, payload = {}, signal) => {
4439
+ const invoke = React11.useCallback(async (endpoint, payload = {}, signal) => {
3398
4440
  if (typeof rpcCall !== "function") throw new TypeError(`${channel4} \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5`);
3399
4441
  return api4.unwrapRpcResult(await rpcCall(endpoint, payload, signal));
3400
4442
  }, [rpcCall]);
3401
- const loadStatus = React10.useCallback(async ({ signal, silent = false } = {}) => {
4443
+ const loadStatus = React11.useCallback(async ({ signal, silent = false } = {}) => {
3402
4444
  const workspaceVersion = workspaceFence.beginStatus();
3403
4445
  if (workspaceVersion === null) return;
3404
4446
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
@@ -3422,12 +4464,12 @@ function createTokenChannelSettings(definition) {
3422
4464
  }
3423
4465
  }
3424
4466
  }, [invoke, workspaceFence]);
3425
- React10.useEffect(() => {
4467
+ React11.useEffect(() => {
3426
4468
  const controller = new AbortController();
3427
4469
  void loadStatus({ signal: controller.signal });
3428
4470
  return () => controller.abort();
3429
4471
  }, [loadStatus]);
3430
- React10.useEffect(() => {
4472
+ React11.useEffect(() => {
3431
4473
  if (model.phase !== "ready") return void 0;
3432
4474
  const controller = new AbortController();
3433
4475
  const timer = window.setInterval(
@@ -3439,7 +4481,7 @@ function createTokenChannelSettings(definition) {
3439
4481
  window.clearInterval(timer);
3440
4482
  };
3441
4483
  }, [loadStatus, model.phase]);
3442
- const bindCredentials = React10.useCallback(async (values) => {
4484
+ const bindCredentials = React11.useCallback(async (values) => {
3443
4485
  const snapshotVersion = workspaceFence.beginMutation();
3444
4486
  setBusy(true);
3445
4487
  setCredentialError(null);
@@ -3467,7 +4509,7 @@ function createTokenChannelSettings(definition) {
3467
4509
  if (mounted.current) setBusy(false);
3468
4510
  }
3469
4511
  }, [invoke, loadStatus, workspaceFence]);
3470
- const botAction = React10.useCallback(async (account, operation, endpoint, payload) => {
4512
+ const botAction = React11.useCallback(async (account, operation, endpoint, payload) => {
3471
4513
  const snapshotVersion = workspaceFence.beginMutation();
3472
4514
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
3473
4515
  try {
@@ -3537,6 +4579,12 @@ function createTokenChannelSettings(definition) {
3537
4579
  endpoints.setAgentPreset,
3538
4580
  { botId: account.botId, agentPreset }
3539
4581
  ),
4582
+ onContextEnhancementSave: (config) => botAction(
4583
+ account,
4584
+ "context-enhancement",
4585
+ endpoints.setContextEnhancement,
4586
+ { botId: account.botId, config }
4587
+ ),
3540
4588
  onAccountSettingsSave: AccountSettings && accountSettingsEndpoint ? (payload) => botAction(
3541
4589
  account,
3542
4590
  "settings",
@@ -3604,7 +4652,7 @@ function createTokenChannelSettings(definition) {
3604
4652
  h2(Button3, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
3605
4653
  )
3606
4654
  ) : h2(
3607
- React10.Fragment,
4655
+ React11.Fragment,
3608
4656
  null,
3609
4657
  credentialOpen ? CredentialPanel ? h2(CredentialPanel, {
3610
4658
  busy,
@@ -3705,7 +4753,7 @@ var DiscordSettingsTab = channel.SettingsTab;
3705
4753
  var DiscordAccountCard = channel.AccountCard;
3706
4754
 
3707
4755
  // plugin-src/client/channels/feishu/index.js
3708
- var React12 = __toESM(require("react"), 1);
4756
+ var React13 = __toESM(require("react"), 1);
3709
4757
 
3710
4758
  // plugin-src/client/channels/feishu/api.js
3711
4759
  var FEISHU_RPC_CHANNEL = "/feishu";
@@ -3722,6 +4770,7 @@ var FEISHU_ENDPOINTS = Object.freeze({
3722
4770
  deleteBot: "bot.delete",
3723
4771
  setWorkspace: "bot.workspace.set",
3724
4772
  setAgentPreset: "bot.preset.set",
4773
+ setContextEnhancement: "bot.context-enhancement.set",
3725
4774
  setGroupResponseMode: "bot.group-response-mode.set",
3726
4775
  // Kept for rolling upgrades. The multi-bot UI never calls these endpoints.
3727
4776
  testConnection: "connection.test",
@@ -3870,6 +4919,7 @@ function normalizeBotConnection(value, fallbackBotId) {
3870
4919
  configured: value.configured !== false,
3871
4920
  workspace: optionalString2(value.workspace)?.slice(0, 4096) ?? "",
3872
4921
  agentPreset: normalizeAgentPresetId(value.agentPreset),
4922
+ contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
3873
4923
  groupResponseMode: normalizeGroupResponseMode(value.groupResponseMode),
3874
4924
  groupMessagePermissionGranted: value.groupMessagePermissionGranted === true,
3875
4925
  bot: normalizeBot2(value.bot),
@@ -3965,7 +5015,7 @@ function formatRemaining2(milliseconds) {
3965
5015
  }
3966
5016
 
3967
5017
  // plugin-src/client/lifecycle.js
3968
- var React11 = __toESM(require("react"), 1);
5018
+ var React12 = __toESM(require("react"), 1);
3969
5019
  function createPollScheduler({ setTimeoutFn, clearTimeoutFn }) {
3970
5020
  let disposed = false;
3971
5021
  let timer;
@@ -4027,8 +5077,8 @@ function createAnimationFrameScheduler({ requestFrame, cancelFrame }) {
4027
5077
  };
4028
5078
  }
4029
5079
  function useAnimationFrameScheduler() {
4030
- const schedulerRef = React11.useRef(null);
4031
- React11.useEffect(() => {
5080
+ const schedulerRef = React12.useRef(null);
5081
+ React12.useEffect(() => {
4032
5082
  const scheduler = createAnimationFrameScheduler({
4033
5083
  requestFrame: (callback) => window.requestAnimationFrame(callback),
4034
5084
  cancelFrame: (frame) => window.cancelAnimationFrame(frame)
@@ -4039,7 +5089,7 @@ function useAnimationFrameScheduler() {
4039
5089
  if (schedulerRef.current === scheduler) schedulerRef.current = null;
4040
5090
  };
4041
5091
  }, []);
4042
- return React11.useCallback(
5092
+ return React12.useCallback(
4043
5093
  (callback, key) => schedulerRef.current?.schedule(callback, key) ?? false,
4044
5094
  []
4045
5095
  );
@@ -4114,7 +5164,7 @@ function QrIcon({ size = 58 }) {
4114
5164
  fill: "currentColor"
4115
5165
  }));
4116
5166
  }
4117
- var Button5 = React12.forwardRef(function Button6({ children, kind = "secondary", size, icon, className = "", ...props }, ref) {
5167
+ var Button5 = React13.forwardRef(function Button6({ children, kind = "secondary", size, icon, className = "", ...props }, ref) {
4118
5168
  return h2("button", {
4119
5169
  ...props,
4120
5170
  ref,
@@ -4231,7 +5281,7 @@ function safeQrSource2(value) {
4231
5281
  return /^data:image\/(?:png|webp|svg\+xml)(?:;charset=[^;,]+)?;base64,/i.test(value) ? value : void 0;
4232
5282
  }
4233
5283
  function QrPane({ provision, now, onRefresh, onCancel, busy }) {
4234
- const [imageFailed, setImageFailed] = React12.useState(false);
5284
+ const [imageFailed, setImageFailed] = React13.useState(false);
4235
5285
  const qrSource = safeQrSource2(provision.qrCodeDataUrl);
4236
5286
  const href = safeVerificationHref(provision.verificationUrl);
4237
5287
  const remaining = Math.max(0, provision.expiresAt - now);
@@ -4240,7 +5290,7 @@ function QrPane({ provision, now, onRefresh, onCancel, busy }) {
4240
5290
  const repairing = isCallbackRepair(provision);
4241
5291
  const grantingGroupMessages = isGroupMessagePermission(provision);
4242
5292
  const botName = provision.botName ?? "\u6B64\u673A\u5668\u4EBA";
4243
- React12.useEffect(() => setImageFailed(false), [qrSource]);
5293
+ React13.useEffect(() => setImageFailed(false), [qrSource]);
4244
5294
  return h2(
4245
5295
  "div",
4246
5296
  { className: "bxf-card bxf-provisionCard dim-surfaceCard" },
@@ -4403,11 +5453,11 @@ function connectionTestNotice2(value) {
4403
5453
  return value?.testMessage ? "\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002" : null;
4404
5454
  }
4405
5455
  function RemoveConfirmation2({ bot, busy, onConfirm, onCancel }) {
4406
- const cancelRef = React12.useRef(null);
5456
+ const cancelRef = React13.useRef(null);
4407
5457
  const idPart = bot.botId.replace(/[^a-zA-Z0-9_-]/g, "-");
4408
5458
  const titleId = `bxf-remove-title-${idPart}`;
4409
5459
  const descriptionId = `bxf-remove-description-${idPart}`;
4410
- React12.useEffect(() => cancelRef.current?.focus(), []);
5460
+ React13.useEffect(() => cancelRef.current?.focus(), []);
4411
5461
  return h2(
4412
5462
  "div",
4413
5463
  {
@@ -4449,9 +5499,9 @@ function GroupResponseModeEditor({
4449
5499
  onAuthorize
4450
5500
  }) {
4451
5501
  const current = normalizeGroupResponseMode(value);
4452
- const [saving, setSaving] = React12.useState(false);
4453
- const [authorizing, setAuthorizing] = React12.useState(false);
4454
- const [error, setError] = React12.useState(null);
5502
+ const [saving, setSaving] = React13.useState(false);
5503
+ const [authorizing, setAuthorizing] = React13.useState(false);
5504
+ const [error, setError] = React13.useState(null);
4455
5505
  const change = async (event) => {
4456
5506
  const next = normalizeGroupResponseMode(event.target.value);
4457
5507
  if (next === current || saving || disabled) return;
@@ -4542,6 +5592,7 @@ function BotCard({
4542
5592
  onRepairCallback,
4543
5593
  onWorkspaceSave,
4544
5594
  onAgentPresetSave,
5595
+ onContextEnhancementSave,
4545
5596
  onGroupResponseModeSave,
4546
5597
  onGroupMessagePermissionAuthorize,
4547
5598
  onRequestRemove,
@@ -4551,7 +5602,7 @@ function BotCard({
4551
5602
  removeButtonRef
4552
5603
  }) {
4553
5604
  const { bot, health, state, connected } = connection;
4554
- const repairTooltipId = React12.useId();
5605
+ const repairTooltipId = React13.useId();
4555
5606
  const stateForDisplay = busy === "reconnect" ? "connecting" : state;
4556
5607
  const tone = stateForDisplay === "connected" ? "success" : stateForDisplay === "connecting" ? "warning" : "error";
4557
5608
  const summary2 = actionError?.message ?? connection.error?.message ?? (connected ? null : health.summary);
@@ -4606,6 +5657,11 @@ function BotCard({
4606
5657
  disabled: Boolean(busy),
4607
5658
  onSave: onAgentPresetSave
4608
5659
  }),
5660
+ h2(ContextEnhancementEditor, {
5661
+ config: connection.contextEnhancement,
5662
+ disabled: Boolean(busy),
5663
+ onSave: onContextEnhancementSave
5664
+ }),
4609
5665
  h2(GroupResponseModeEditor, {
4610
5666
  value: connection.groupResponseMode,
4611
5667
  permissionGranted: connection.groupMessagePermissionGranted,
@@ -4721,6 +5777,7 @@ function BotList(props) {
4721
5777
  onRepairCallback: () => props.onRepairCallback(bot),
4722
5778
  onWorkspaceSave: (workspace) => props.onWorkspaceSave(bot, workspace),
4723
5779
  onAgentPresetSave: (agentPreset) => props.onAgentPresetSave(bot, agentPreset),
5780
+ onContextEnhancementSave: (config) => props.onContextEnhancementSave(bot, config),
4724
5781
  onGroupResponseModeSave: (groupResponseMode) => props.onGroupResponseModeSave(bot, groupResponseMode),
4725
5782
  onGroupMessagePermissionAuthorize: () => props.onGroupMessagePermissionAuthorize(bot),
4726
5783
  onRequestRemove: () => props.onRequestRemove(bot),
@@ -4785,7 +5842,7 @@ function mergeFeishuSnapshotState(current, snapshot, { restoreProvisioning = fal
4785
5842
  };
4786
5843
  }
4787
5844
  function FeishuSettingsTab({ rpcCall }) {
4788
- const [model, setModel] = React12.useState({
5845
+ const [model, setModel] = React13.useState({
4789
5846
  phase: "loading",
4790
5847
  revision: 0,
4791
5848
  bots: [],
@@ -4795,41 +5852,41 @@ function FeishuSettingsTab({ rpcCall }) {
4795
5852
  statusError: null,
4796
5853
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
4797
5854
  });
4798
- const [pageBusy, setPageBusy] = React12.useState(false);
4799
- const [provisionBusy, setProvisionBusy] = React12.useState(false);
4800
- const [credentialOpen, setCredentialOpen] = React12.useState(false);
4801
- const [credentialBusy, setCredentialBusy] = React12.useState(false);
4802
- const [credentialError, setCredentialError] = React12.useState(null);
4803
- const [busyByBot, setBusyByBot] = React12.useState({});
4804
- const [errorsByBot, setErrorsByBot] = React12.useState({});
4805
- const [testNoticesByBot, setTestNoticesByBot] = React12.useState({});
4806
- const [removeTargetId, setRemoveTargetId] = React12.useState(null);
4807
- const [announcement, setAnnouncement] = React12.useState("");
4808
- const [now, setNow] = React12.useState(() => Date.now());
4809
- const [focusBotId, setFocusBotId] = React12.useState(null);
4810
- const cardRefs = React12.useRef(/* @__PURE__ */ new Map());
4811
- const removeButtonRefs = React12.useRef(/* @__PURE__ */ new Map());
4812
- const targetedProvisionRef = React12.useRef(null);
4813
- const addButtonRef = React12.useRef(null);
4814
- const mountedRef = React12.useRef(true);
5855
+ const [pageBusy, setPageBusy] = React13.useState(false);
5856
+ const [provisionBusy, setProvisionBusy] = React13.useState(false);
5857
+ const [credentialOpen, setCredentialOpen] = React13.useState(false);
5858
+ const [credentialBusy, setCredentialBusy] = React13.useState(false);
5859
+ const [credentialError, setCredentialError] = React13.useState(null);
5860
+ const [busyByBot, setBusyByBot] = React13.useState({});
5861
+ const [errorsByBot, setErrorsByBot] = React13.useState({});
5862
+ const [testNoticesByBot, setTestNoticesByBot] = React13.useState({});
5863
+ const [removeTargetId, setRemoveTargetId] = React13.useState(null);
5864
+ const [announcement, setAnnouncement] = React13.useState("");
5865
+ const [now, setNow] = React13.useState(() => Date.now());
5866
+ const [focusBotId, setFocusBotId] = React13.useState(null);
5867
+ const cardRefs = React13.useRef(/* @__PURE__ */ new Map());
5868
+ const removeButtonRefs = React13.useRef(/* @__PURE__ */ new Map());
5869
+ const targetedProvisionRef = React13.useRef(null);
5870
+ const addButtonRef = React13.useRef(null);
5871
+ const mountedRef = React13.useRef(true);
4815
5872
  const workspaceFence = useWorkspaceSnapshotFence();
4816
5873
  const scheduleAnimationFrame = useAnimationFrameScheduler();
4817
- React12.useEffect(() => {
5874
+ React13.useEffect(() => {
4818
5875
  mountedRef.current = true;
4819
5876
  return () => {
4820
5877
  mountedRef.current = false;
4821
5878
  };
4822
5879
  }, []);
4823
- const announce = React12.useCallback((message) => {
5880
+ const announce = React13.useCallback((message) => {
4824
5881
  setAnnouncement("");
4825
5882
  scheduleAnimationFrame(() => {
4826
5883
  if (message) setAnnouncement(message);
4827
5884
  }, "announcement");
4828
5885
  }, [scheduleAnimationFrame]);
4829
- const invoke = React12.useCallback(async (endpoint, payload = {}, signal) => {
5886
+ const invoke = React13.useCallback(async (endpoint, payload = {}, signal) => {
4830
5887
  return unwrapRpcResult3(await rpcCall(endpoint, payload, signal));
4831
5888
  }, [rpcCall]);
4832
- const mergeSnapshot = React12.useCallback((snapshot, { restoreProvisioning = false } = {}) => {
5889
+ const mergeSnapshot = React13.useCallback((snapshot, { restoreProvisioning = false } = {}) => {
4833
5890
  const now2 = Date.now();
4834
5891
  setModel((current) => mergeFeishuSnapshotState(
4835
5892
  current,
@@ -4837,7 +5894,7 @@ function FeishuSettingsTab({ rpcCall }) {
4837
5894
  { restoreProvisioning, now: now2 }
4838
5895
  ));
4839
5896
  }, []);
4840
- const loadStatus = React12.useCallback(async ({ signal, silent = false, restoreProvisioning = false } = {}) => {
5897
+ const loadStatus = React13.useCallback(async ({ signal, silent = false, restoreProvisioning = false } = {}) => {
4841
5898
  const workspaceVersion = workspaceFence.beginStatus();
4842
5899
  if (workspaceVersion === null || !mountedRef.current) return void 0;
4843
5900
  if (!silent) setPageBusy(true);
@@ -4855,12 +5912,12 @@ function FeishuSettingsTab({ rpcCall }) {
4855
5912
  if (!silent && !signal?.aborted && mountedRef.current) setPageBusy(false);
4856
5913
  }
4857
5914
  }, [invoke, mergeSnapshot, workspaceFence]);
4858
- React12.useEffect(() => {
5915
+ React13.useEffect(() => {
4859
5916
  const controller = new AbortController();
4860
5917
  void loadStatus({ signal: controller.signal, restoreProvisioning: true });
4861
5918
  return () => controller.abort();
4862
5919
  }, [loadStatus]);
4863
- React12.useEffect(() => {
5920
+ React13.useEffect(() => {
4864
5921
  if (model.phase !== "ready") return void 0;
4865
5922
  const controller = new AbortController();
4866
5923
  let inFlight = false;
@@ -4879,7 +5936,7 @@ function FeishuSettingsTab({ rpcCall }) {
4879
5936
  window.clearInterval(timer);
4880
5937
  };
4881
5938
  }, [loadStatus, model.phase]);
4882
- React12.useEffect(() => {
5939
+ React13.useEffect(() => {
4883
5940
  if (!focusBotId) return;
4884
5941
  const node = cardRefs.current.get(focusBotId);
4885
5942
  if (!node) return;
@@ -4888,7 +5945,7 @@ function FeishuSettingsTab({ rpcCall }) {
4888
5945
  setFocusBotId(null);
4889
5946
  }, [focusBotId, model.bots]);
4890
5947
  const targetedProvisionFocusKey = isTargetedAppUpdate2(model.provisioning) ? `${model.provisioning.botId}:${model.provisioning.attemptId ?? "preparing"}:${model.provisioning.phase}` : null;
4891
- React12.useEffect(() => {
5948
+ React13.useEffect(() => {
4892
5949
  if (!targetedProvisionFocusKey) return;
4893
5950
  scheduleAnimationFrame(() => {
4894
5951
  const node = targetedProvisionRef.current;
@@ -4897,7 +5954,7 @@ function FeishuSettingsTab({ rpcCall }) {
4897
5954
  node.focus?.({ preventScroll: true });
4898
5955
  }, "targeted-provision-focus");
4899
5956
  }, [scheduleAnimationFrame, targetedProvisionFocusKey]);
4900
- const startProvisioning = React12.useCallback(async ({
5957
+ const startProvisioning = React13.useCallback(async ({
4901
5958
  replace = false,
4902
5959
  operation = FEISHU_REGISTRATION_OPERATIONS.PROVISION,
4903
5960
  bot
@@ -4973,7 +6030,7 @@ function FeishuSettingsTab({ rpcCall }) {
4973
6030
  model.provisioning?.botId,
4974
6031
  model.provisioning?.botName
4975
6032
  ]);
4976
- const bindCredentials = React12.useCallback(async ({ identity, secret }) => {
6033
+ const bindCredentials = React13.useCallback(async ({ identity, secret }) => {
4977
6034
  const snapshotVersion = workspaceFence.beginMutation();
4978
6035
  setCredentialBusy(true);
4979
6036
  setCredentialError(null);
@@ -4995,7 +6052,7 @@ function FeishuSettingsTab({ rpcCall }) {
4995
6052
  setCredentialBusy(false);
4996
6053
  }
4997
6054
  }, [announce, invoke, loadStatus, mergeSnapshot, workspaceFence]);
4998
- const cancelProvisioning = React12.useCallback(async () => {
6055
+ const cancelProvisioning = React13.useCallback(async () => {
4999
6056
  const activeProvision = model.provisioning;
5000
6057
  const attemptId = activeProvision?.attemptId;
5001
6058
  const repairing = isCallbackRepair(activeProvision);
@@ -5060,7 +6117,7 @@ function FeishuSettingsTab({ rpcCall }) {
5060
6117
  const countdownPhase = model.provisioning?.phase;
5061
6118
  const countdownExpiresAt = model.provisioning?.expiresAt;
5062
6119
  const countdownExpired = model.provisioning?.expired;
5063
- React12.useEffect(() => {
6120
+ React13.useEffect(() => {
5064
6121
  if (!countdownAttemptId || countdownPhase !== "qr" || countdownExpired) return void 0;
5065
6122
  const tick = () => {
5066
6123
  const timestamp7 = Date.now();
@@ -5073,7 +6130,7 @@ function FeishuSettingsTab({ rpcCall }) {
5073
6130
  const timer = window.setInterval(tick, 1e3);
5074
6131
  return () => window.clearInterval(timer);
5075
6132
  }, [countdownAttemptId, countdownPhase, countdownExpiresAt, countdownExpired]);
5076
- React12.useEffect(() => {
6133
+ React13.useEffect(() => {
5077
6134
  const provision2 = model.provisioning;
5078
6135
  if (!provision2 || !["qr", "connecting"].includes(provision2.phase) || !provision2.attemptId || provision2.expired) return void 0;
5079
6136
  const controller = new AbortController();
@@ -5141,7 +6198,7 @@ function FeishuSettingsTab({ rpcCall }) {
5141
6198
  window.clearTimeout(timer);
5142
6199
  };
5143
6200
  }, [announce, invoke, loadStatus, model.provisioning]);
5144
- const setBotBusy = React12.useCallback((botId, value) => {
6201
+ const setBotBusy = React13.useCallback((botId, value) => {
5145
6202
  setBusyByBot((current) => {
5146
6203
  const next = { ...current };
5147
6204
  if (value) next[botId] = value;
@@ -5149,7 +6206,7 @@ function FeishuSettingsTab({ rpcCall }) {
5149
6206
  return next;
5150
6207
  });
5151
6208
  }, []);
5152
- const setBotError = React12.useCallback((botId, error) => {
6209
+ const setBotError = React13.useCallback((botId, error) => {
5153
6210
  setErrorsByBot((current) => {
5154
6211
  const next = { ...current };
5155
6212
  if (error) next[botId] = presentError3(error);
@@ -5157,7 +6214,7 @@ function FeishuSettingsTab({ rpcCall }) {
5157
6214
  return next;
5158
6215
  });
5159
6216
  }, []);
5160
- const repairCallback = React12.useCallback((connection) => {
6217
+ const repairCallback = React13.useCallback((connection) => {
5161
6218
  if (model.provisioning) return;
5162
6219
  setRemoveTargetId(null);
5163
6220
  setBotError(connection.botId, null);
@@ -5171,7 +6228,7 @@ function FeishuSettingsTab({ rpcCall }) {
5171
6228
  bot: connection
5172
6229
  });
5173
6230
  }, [model.provisioning, setBotError, startProvisioning]);
5174
- const reconnectOneBot = React12.useCallback(async (connection) => {
6231
+ const reconnectOneBot = React13.useCallback(async (connection) => {
5175
6232
  const { botId, bot } = connection;
5176
6233
  const snapshotVersion = workspaceFence.beginMutation();
5177
6234
  setBotBusy(botId, "reconnect");
@@ -5211,7 +6268,7 @@ function FeishuSettingsTab({ rpcCall }) {
5211
6268
  setBotBusy(botId, null);
5212
6269
  }
5213
6270
  }, [announce, invoke, loadStatus, mergeSnapshot, setBotBusy, setBotError, workspaceFence]);
5214
- const saveWorkspace = React12.useCallback(async (connection, workspace) => {
6271
+ const saveWorkspace = React13.useCallback(async (connection, workspace) => {
5215
6272
  const { botId } = connection;
5216
6273
  const workspaceVersion = workspaceFence.beginMutation();
5217
6274
  setBotBusy(botId, "workspace");
@@ -5230,15 +6287,15 @@ function FeishuSettingsTab({ rpcCall }) {
5230
6287
  if (mountedRef.current) setBotBusy(botId, null);
5231
6288
  }
5232
6289
  }, [invoke, loadStatus, mergeSnapshot, setBotBusy, setBotError, workspaceFence]);
5233
- const saveAgentPreset = React12.useCallback(async (connection, agentPreset) => {
6290
+ const saveBotSetting = React13.useCallback(async (connection, operation, endpoint, payload) => {
5234
6291
  const { botId } = connection;
5235
6292
  const snapshotVersion = workspaceFence.beginMutation();
5236
- setBotBusy(botId, "preset");
6293
+ setBotBusy(botId, operation);
5237
6294
  setBotError(botId, null);
5238
6295
  try {
5239
6296
  const snapshot = normalizeBotsSnapshot(await invoke(
5240
- FEISHU_ENDPOINTS.setAgentPreset,
5241
- { botId, agentPreset }
6297
+ endpoint,
6298
+ { botId, ...payload }
5242
6299
  ));
5243
6300
  if (mountedRef.current && workspaceFence.canCommitMutation(snapshotVersion)) {
5244
6301
  mergeSnapshot(snapshot);
@@ -5249,7 +6306,7 @@ function FeishuSettingsTab({ rpcCall }) {
5249
6306
  if (mountedRef.current) setBotBusy(botId, null);
5250
6307
  }
5251
6308
  }, [invoke, loadStatus, mergeSnapshot, setBotBusy, setBotError, workspaceFence]);
5252
- const authorizeGroupMessages = React12.useCallback(async (connection) => {
6309
+ const authorizeGroupMessages = React13.useCallback(async (connection) => {
5253
6310
  const { botId } = connection;
5254
6311
  if (model.provisioning) {
5255
6312
  throw new Error("\u8BF7\u5148\u5B8C\u6210\u5F53\u524D\u98DE\u4E66\u6388\u6743\u64CD\u4F5C\uFF0C\u518D\u5F00\u901A\u7FA4\u6D88\u606F\u6743\u9650\u3002");
@@ -5266,7 +6323,7 @@ function FeishuSettingsTab({ rpcCall }) {
5266
6323
  bot: connection
5267
6324
  });
5268
6325
  }, [model.provisioning, setBotError, startProvisioning]);
5269
- const saveGroupResponseMode = React12.useCallback(async (connection, groupResponseMode) => {
6326
+ const saveGroupResponseMode = React13.useCallback(async (connection, groupResponseMode) => {
5270
6327
  const { botId } = connection;
5271
6328
  if (groupResponseMode === "all" && connection.groupMessagePermissionGranted !== true) {
5272
6329
  await authorizeGroupMessages(connection);
@@ -5297,15 +6354,15 @@ function FeishuSettingsTab({ rpcCall }) {
5297
6354
  setBotError,
5298
6355
  workspaceFence
5299
6356
  ]);
5300
- const requestRemove = React12.useCallback((connection) => {
6357
+ const requestRemove = React13.useCallback((connection) => {
5301
6358
  setRemoveTargetId(connection.botId);
5302
6359
  }, []);
5303
- const cancelRemove = React12.useCallback(() => {
6360
+ const cancelRemove = React13.useCallback(() => {
5304
6361
  const botId = removeTargetId;
5305
6362
  setRemoveTargetId(null);
5306
6363
  scheduleAnimationFrame(() => removeButtonRefs.current.get(botId)?.focus(), "focus");
5307
6364
  }, [removeTargetId, scheduleAnimationFrame]);
5308
- const confirmRemove = React12.useCallback(async (connection) => {
6365
+ const confirmRemove = React13.useCallback(async (connection) => {
5309
6366
  const { botId, bot } = connection;
5310
6367
  const snapshotVersion = workspaceFence.beginMutation();
5311
6368
  setBotBusy(botId, "delete");
@@ -5391,11 +6448,11 @@ function FeishuSettingsTab({ rpcCall }) {
5391
6448
  setCredentialError(null);
5392
6449
  }
5393
6450
  }) : null;
5394
- const setCardRef = React12.useCallback((botId, node) => {
6451
+ const setCardRef = React13.useCallback((botId, node) => {
5395
6452
  if (node) cardRefs.current.set(botId, node);
5396
6453
  else cardRefs.current.delete(botId);
5397
6454
  }, []);
5398
- const setRemoveButtonRef = React12.useCallback((botId, node) => {
6455
+ const setRemoveButtonRef = React13.useCallback((botId, node) => {
5399
6456
  if (node) removeButtonRefs.current.set(botId, node);
5400
6457
  else removeButtonRefs.current.delete(botId);
5401
6458
  }, []);
@@ -5434,7 +6491,7 @@ function FeishuSettingsTab({ rpcCall }) {
5434
6491
  onRetry: () => void loadStatus(),
5435
6492
  busy: pageBusy
5436
6493
  }) : h2(
5437
- React12.Fragment,
6494
+ React13.Fragment,
5438
6495
  null,
5439
6496
  credentialContent,
5440
6497
  targetedProvisioning ? null : provisionContent,
@@ -5451,7 +6508,18 @@ function FeishuSettingsTab({ rpcCall }) {
5451
6508
  onReconnect: (bot) => void reconnectOneBot(bot),
5452
6509
  onRepairCallback: repairCallback,
5453
6510
  onWorkspaceSave: saveWorkspace,
5454
- onAgentPresetSave: saveAgentPreset,
6511
+ onAgentPresetSave: (connection, agentPreset) => saveBotSetting(
6512
+ connection,
6513
+ "preset",
6514
+ FEISHU_ENDPOINTS.setAgentPreset,
6515
+ { agentPreset }
6516
+ ),
6517
+ onContextEnhancementSave: (connection, config) => saveBotSetting(
6518
+ connection,
6519
+ "context-enhancement",
6520
+ FEISHU_ENDPOINTS.setContextEnhancement,
6521
+ { config }
6522
+ ),
5455
6523
  onGroupResponseModeSave: saveGroupResponseMode,
5456
6524
  onGroupMessagePermissionAuthorize: authorizeGroupMessages,
5457
6525
  onRequestRemove: requestRemove,
@@ -6047,7 +7115,8 @@ var QQ_ENDPOINTS = Object.freeze({
6047
7115
  reconnectBot: "bot.reconnect",
6048
7116
  deleteBot: "bot.delete",
6049
7117
  setWorkspace: "bot.workspace.set",
6050
- setAgentPreset: SET_AGENT_PRESET_ENDPOINT
7118
+ setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
7119
+ setContextEnhancement: "bot.context-enhancement.set"
6051
7120
  });
6052
7121
  var PROVISION_STATES2 = /* @__PURE__ */ new Set(["starting", "pending", "refreshing", "connecting", "connected", "failed", "cancelled"]);
6053
7122
  var ACCOUNT_STATES3 = /* @__PURE__ */ new Set(["connected", "connecting", "offline", "error"]);
@@ -6112,6 +7181,7 @@ function normalizeBot3(value) {
6112
7181
  state: connected ? "connected" : state,
6113
7182
  workspace: text3(value.workspace, "", 4096),
6114
7183
  agentPreset: normalizeAgentPresetId(value.agentPreset),
7184
+ contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
6115
7185
  bot: {
6116
7186
  name: text3(value.bot?.name, "QQ\u673A\u5668\u4EBA", 100),
6117
7187
  appIdMasked: text3(value.bot?.appIdMasked, "\u5E94\u7528\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58", 140)
@@ -6169,7 +7239,7 @@ function formatRemaining3(milliseconds) {
6169
7239
  }
6170
7240
 
6171
7241
  // plugin-src/client/channels/qq/index.js
6172
- var React13 = __toESM(require("react"), 1);
7242
+ var React14 = __toESM(require("react"), 1);
6173
7243
 
6174
7244
  // plugin-src/client/channels/qq/styles.js
6175
7245
  var QQ_STYLE_ID = "xmanrui-dsh-im-qq-settings";
@@ -6194,7 +7264,7 @@ function installQqStyles() {
6194
7264
 
6195
7265
  // plugin-src/client/channels/qq/index.js
6196
7266
  var ACTIVE_STATES = /* @__PURE__ */ new Set(["pending", "refreshing", "connecting"]);
6197
- var Button7 = React13.forwardRef(function Button8({ children, kind = "secondary", className = "", ...props }, ref) {
7267
+ var Button7 = React14.forwardRef(function Button8({ children, kind = "secondary", className = "", ...props }, ref) {
6198
7268
  return h2("button", {
6199
7269
  ...props,
6200
7270
  ref,
@@ -6409,6 +7479,7 @@ function AccountCard2({
6409
7479
  onReconnect,
6410
7480
  onWorkspaceSave,
6411
7481
  onAgentPresetSave,
7482
+ onContextEnhancementSave,
6412
7483
  onRequestRemove,
6413
7484
  onConfirmRemove,
6414
7485
  onCancelRemove
@@ -6455,6 +7526,11 @@ function AccountCard2({
6455
7526
  disabled: Boolean(busy),
6456
7527
  onSave: onAgentPresetSave
6457
7528
  }),
7529
+ h2(ContextEnhancementEditor, {
7530
+ config: account.contextEnhancement,
7531
+ disabled: Boolean(busy),
7532
+ onSave: onContextEnhancementSave
7533
+ }),
6458
7534
  h2(
6459
7535
  "div",
6460
7536
  { className: "ddt-accountFooter dim-cardFooter" },
@@ -6489,25 +7565,25 @@ function AccountCard2({
6489
7565
  );
6490
7566
  }
6491
7567
  function QqSettingsTab({ rpcCall }) {
6492
- const [model, setModel] = React13.useState({
7568
+ const [model, setModel] = React14.useState({
6493
7569
  phase: "loading",
6494
7570
  bots: [],
6495
7571
  totals: { configured: 0, connected: 0 },
6496
7572
  error: null,
6497
7573
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
6498
7574
  });
6499
- const [provision, setProvision] = React13.useState(null);
6500
- const [busy, setBusy] = React13.useState(false);
6501
- const [busyByBot, setBusyByBot] = React13.useState({});
6502
- const [feedbackByBot, setFeedbackByBot] = React13.useState({});
6503
- const [removeTarget, setRemoveTarget] = React13.useState(null);
6504
- const [credentialOpen, setCredentialOpen] = React13.useState(false);
6505
- const [credentialError, setCredentialError] = React13.useState(null);
6506
- const [now, setNow] = React13.useState(Date.now());
6507
- const mounted = React13.useRef(true);
7575
+ const [provision, setProvision] = React14.useState(null);
7576
+ const [busy, setBusy] = React14.useState(false);
7577
+ const [busyByBot, setBusyByBot] = React14.useState({});
7578
+ const [feedbackByBot, setFeedbackByBot] = React14.useState({});
7579
+ const [removeTarget, setRemoveTarget] = React14.useState(null);
7580
+ const [credentialOpen, setCredentialOpen] = React14.useState(false);
7581
+ const [credentialError, setCredentialError] = React14.useState(null);
7582
+ const [now, setNow] = React14.useState(Date.now());
7583
+ const mounted = React14.useRef(true);
6508
7584
  const workspaceFence = useWorkspaceSnapshotFence();
6509
- const addButtonRef = React13.useRef(null);
6510
- React13.useEffect(() => {
7585
+ const addButtonRef = React14.useRef(null);
7586
+ React14.useEffect(() => {
6511
7587
  const disposeDingtalk = installDingtalkStyles();
6512
7588
  const disposeQq = installQqStyles();
6513
7589
  mounted.current = true;
@@ -6517,11 +7593,11 @@ function QqSettingsTab({ rpcCall }) {
6517
7593
  disposeDingtalk();
6518
7594
  };
6519
7595
  }, []);
6520
- const invoke = React13.useCallback(async (endpoint, payload = {}, signal) => {
7596
+ const invoke = React14.useCallback(async (endpoint, payload = {}, signal) => {
6521
7597
  if (typeof rpcCall !== "function") throw new TypeError("QQ \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
6522
7598
  return unwrapRpcResult4(await rpcCall(endpoint, payload, signal));
6523
7599
  }, [rpcCall]);
6524
- const loadStatus = React13.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
7600
+ const loadStatus = React14.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
6525
7601
  const workspaceVersion = workspaceFence.beginStatus();
6526
7602
  if (workspaceVersion === null) return void 0;
6527
7603
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
@@ -6547,12 +7623,12 @@ function QqSettingsTab({ rpcCall }) {
6547
7623
  return void 0;
6548
7624
  }
6549
7625
  }, [invoke, workspaceFence]);
6550
- React13.useEffect(() => {
7626
+ React14.useEffect(() => {
6551
7627
  const controller = new AbortController();
6552
7628
  void loadStatus({ signal: controller.signal, restore: true });
6553
7629
  return () => controller.abort();
6554
7630
  }, [loadStatus]);
6555
- React13.useEffect(() => {
7631
+ React14.useEffect(() => {
6556
7632
  if (model.phase !== "ready") return void 0;
6557
7633
  const controller = new AbortController();
6558
7634
  const timer = window.setInterval(() => void loadStatus({ signal: controller.signal, silent: true }), 15e3);
@@ -6561,12 +7637,12 @@ function QqSettingsTab({ rpcCall }) {
6561
7637
  window.clearInterval(timer);
6562
7638
  };
6563
7639
  }, [loadStatus, model.phase]);
6564
- React13.useEffect(() => {
7640
+ React14.useEffect(() => {
6565
7641
  if (!provision || !ACTIVE_STATES.has(provision.status)) return void 0;
6566
7642
  const timer = window.setInterval(() => mounted.current && setNow(Date.now()), 1e3);
6567
7643
  return () => window.clearInterval(timer);
6568
7644
  }, [provision?.attemptId, provision?.status]);
6569
- const startProvisioning = React13.useCallback(async (replace = false) => {
7645
+ const startProvisioning = React14.useCallback(async (replace = false) => {
6570
7646
  setCredentialOpen(false);
6571
7647
  setCredentialError(null);
6572
7648
  setBusy(true);
@@ -6584,7 +7660,7 @@ function QqSettingsTab({ rpcCall }) {
6584
7660
  if (mounted.current) setBusy(false);
6585
7661
  }
6586
7662
  }, [invoke, provision?.attemptId]);
6587
- const bindCredentials = React13.useCallback(async ({ identity, secret }) => {
7663
+ const bindCredentials = React14.useCallback(async ({ identity, secret }) => {
6588
7664
  const snapshotVersion = workspaceFence.beginMutation();
6589
7665
  setBusy(true);
6590
7666
  setCredentialError(null);
@@ -6612,7 +7688,7 @@ function QqSettingsTab({ rpcCall }) {
6612
7688
  if (mounted.current) setBusy(false);
6613
7689
  }
6614
7690
  }, [invoke, loadStatus, workspaceFence]);
6615
- const closeProvision = React13.useCallback(async () => {
7691
+ const closeProvision = React14.useCallback(async () => {
6616
7692
  setBusy(true);
6617
7693
  try {
6618
7694
  if (provision?.attemptId && ACTIVE_STATES.has(provision.status)) {
@@ -6623,7 +7699,7 @@ function QqSettingsTab({ rpcCall }) {
6623
7699
  if (mounted.current) setBusy(false);
6624
7700
  }
6625
7701
  }, [invoke, provision?.attemptId, provision?.status]);
6626
- React13.useEffect(() => {
7702
+ React14.useEffect(() => {
6627
7703
  const attemptId = provision?.attemptId;
6628
7704
  if (!attemptId || !ACTIVE_STATES.has(provision.status)) return void 0;
6629
7705
  const controller = new AbortController();
@@ -6653,7 +7729,7 @@ function QqSettingsTab({ rpcCall }) {
6653
7729
  window.clearTimeout(timer);
6654
7730
  };
6655
7731
  }, [invoke, loadStatus, provision?.attemptId, provision?.pollIntervalMs, provision?.status]);
6656
- const botAction = React13.useCallback(async (account, operation, endpoint, payload) => {
7732
+ const botAction = React14.useCallback(async (account, operation, endpoint, payload) => {
6657
7733
  const snapshotVersion = workspaceFence.beginMutation();
6658
7734
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
6659
7735
  try {
@@ -6678,7 +7754,7 @@ function QqSettingsTab({ rpcCall }) {
6678
7754
  });
6679
7755
  }
6680
7756
  }, [invoke, loadStatus, workspaceFence]);
6681
- const reconnect = React13.useCallback(async (account) => {
7757
+ const reconnect = React14.useCallback(async (account) => {
6682
7758
  setFeedbackByBot((current) => {
6683
7759
  const next = { ...current };
6684
7760
  delete next[account.botId];
@@ -6747,6 +7823,12 @@ function QqSettingsTab({ rpcCall }) {
6747
7823
  QQ_ENDPOINTS.setAgentPreset,
6748
7824
  { botId: account.botId, agentPreset }
6749
7825
  ),
7826
+ onContextEnhancementSave: (config) => botAction(
7827
+ account,
7828
+ "context-enhancement",
7829
+ QQ_ENDPOINTS.setContextEnhancement,
7830
+ { botId: account.botId, config }
7831
+ ),
6750
7832
  onRequestRemove: () => setRemoveTarget(account.botId),
6751
7833
  onCancelRemove: () => setRemoveTarget(null),
6752
7834
  onConfirmRemove: async () => {
@@ -6787,7 +7869,7 @@ function QqSettingsTab({ rpcCall }) {
6787
7869
  addButtonRef
6788
7870
  }),
6789
7871
  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(
6790
- React13.Fragment,
7872
+ React14.Fragment,
6791
7873
  null,
6792
7874
  credentialView,
6793
7875
  provisionView,
@@ -6876,7 +7958,7 @@ function normalizeOfficeStatus(value) {
6876
7958
  }
6877
7959
 
6878
7960
  // plugin-src/client/channels/office/index.js
6879
- var React14 = __toESM(require("react"), 1);
7961
+ var React15 = __toESM(require("react"), 1);
6880
7962
  function Button9({ children, kind = "secondary", ...props }) {
6881
7963
  return h2("button", { ...props, type: "button", className: "ddt-button", "data-kind": kind }, children);
6882
7964
  }
@@ -6905,12 +7987,12 @@ function stateLabel(model) {
6905
7987
  return "\u5DF2\u914D\u7F6E";
6906
7988
  }
6907
7989
  function OfficeSettingsTab({ rpcCall, initialStatus }) {
6908
- const [model, setModel] = React14.useState(normalizeOfficeStatus(initialStatus));
6909
- const [phase, setPhase] = React14.useState(initialStatus === void 0 ? "loading" : "ready");
6910
- const [busy, setBusy] = React14.useState("");
6911
- const [error, setError] = React14.useState("");
6912
- const [notice, setNotice] = React14.useState("");
6913
- const [form, setForm] = React14.useState({
7990
+ const [model, setModel] = React15.useState(normalizeOfficeStatus(initialStatus));
7991
+ const [phase, setPhase] = React15.useState(initialStatus === void 0 ? "loading" : "ready");
7992
+ const [busy, setBusy] = React15.useState("");
7993
+ const [error, setError] = React15.useState("");
7994
+ const [notice, setNotice] = React15.useState("");
7995
+ const [form, setForm] = React15.useState({
6914
7996
  baseUrl: "",
6915
7997
  deviceId: "local-harness",
6916
7998
  deviceToken: "",
@@ -6919,11 +8001,11 @@ function OfficeSettingsTab({ rpcCall, initialStatus }) {
6919
8001
  workspaces: "",
6920
8002
  instructionPresets: ""
6921
8003
  });
6922
- const invoke = React14.useCallback(async (endpoint, payload = {}) => {
8004
+ const invoke = React15.useCallback(async (endpoint, payload = {}) => {
6923
8005
  if (typeof rpcCall !== "function") throw new Error("AI Office \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
6924
8006
  return unwrapOfficeRpc(await rpcCall(endpoint, payload));
6925
8007
  }, [rpcCall]);
6926
- const adopt = React14.useCallback((value) => {
8008
+ const adopt = React15.useCallback((value) => {
6927
8009
  const next = normalizeOfficeStatus(value?.snapshot ?? value);
6928
8010
  setModel(next);
6929
8011
  if (next.config) setForm((current) => ({
@@ -6938,7 +8020,7 @@ function OfficeSettingsTab({ rpcCall, initialStatus }) {
6938
8020
  }));
6939
8021
  return next;
6940
8022
  }, []);
6941
- const load = React14.useCallback(async () => {
8023
+ const load = React15.useCallback(async () => {
6942
8024
  try {
6943
8025
  adopt(await invoke(OFFICE_RPC_ENDPOINTS.status));
6944
8026
  setPhase("ready");
@@ -6948,7 +8030,7 @@ function OfficeSettingsTab({ rpcCall, initialStatus }) {
6948
8030
  setError(caught.message);
6949
8031
  }
6950
8032
  }, [adopt, invoke]);
6951
- React14.useEffect(() => {
8033
+ React15.useEffect(() => {
6952
8034
  void load();
6953
8035
  }, [load]);
6954
8036
  const run = async (name2, operation) => {
@@ -6965,7 +8047,7 @@ function OfficeSettingsTab({ rpcCall, initialStatus }) {
6965
8047
  setBusy("");
6966
8048
  }
6967
8049
  };
6968
- const hooks = React14.useMemo(() => {
8050
+ const hooks = React15.useMemo(() => {
6969
8051
  try {
6970
8052
  return officeHookUrls(form.baseUrl);
6971
8053
  } catch {
@@ -7150,7 +8232,7 @@ var normalizeSnapshot4 = api2.normalizeSnapshot;
7150
8232
  var presentError5 = api2.presentError;
7151
8233
 
7152
8234
  // plugin-src/client/channels/slack/index.js
7153
- var React15 = __toESM(require("react"), 1);
8235
+ var React16 = __toESM(require("react"), 1);
7154
8236
 
7155
8237
  // src/channels/slack/manifest.mjs
7156
8238
  var SLACK_APP_MANIFEST_YAML = `_metadata:
@@ -7225,10 +8307,10 @@ function installSlackStyles() {
7225
8307
 
7226
8308
  // plugin-src/client/channels/slack/index.js
7227
8309
  function SlackCredentialPanel({ busy, error, onSubmit, onCancel }) {
7228
- const [botToken, setBotToken] = React15.useState("");
7229
- const [appToken, setAppToken] = React15.useState("");
7230
- const [copied, setCopied] = React15.useState(false);
7231
- const headingId = React15.useId();
8310
+ const [botToken, setBotToken] = React16.useState("");
8311
+ const [appToken, setAppToken] = React16.useState("");
8312
+ const [copied, setCopied] = React16.useState(false);
8313
+ const headingId = React16.useId();
7232
8314
  const copyManifest = async () => {
7233
8315
  try {
7234
8316
  await navigator.clipboard.writeText(SLACK_APP_MANIFEST_YAML);
@@ -7384,7 +8466,7 @@ var normalizeSnapshot5 = api3.normalizeSnapshot;
7384
8466
  var presentError6 = api3.presentError;
7385
8467
 
7386
8468
  // plugin-src/client/channels/telegram/index.js
7387
- var React16 = __toESM(require("react"), 1);
8469
+ var React17 = __toESM(require("react"), 1);
7388
8470
 
7389
8471
  // plugin-src/client/channels/telegram/styles.js
7390
8472
  var TELEGRAM_STYLE_ID = "xmanrui-dsh-im-telegram-settings";
@@ -7452,11 +8534,11 @@ function allowedUsersFromText(value) {
7452
8534
  function TelegramAccessSettings({ account, busy = false, onSave }) {
7453
8535
  const policy = policyFor(account);
7454
8536
  const sourceUsers = policy.allowedUsers.join("\n");
7455
- const accessHelpId = React16.useId();
7456
- const [accessMode, setAccessMode] = React16.useState(policy.accessMode);
7457
- const [allowedUsers, setAllowedUsers] = React16.useState(sourceUsers);
7458
- const [error, setError] = React16.useState(null);
7459
- React16.useEffect(() => {
8537
+ const accessHelpId = React17.useId();
8538
+ const [accessMode, setAccessMode] = React17.useState(policy.accessMode);
8539
+ const [allowedUsers, setAllowedUsers] = React17.useState(sourceUsers);
8540
+ const [error, setError] = React17.useState(null);
8541
+ React17.useEffect(() => {
7460
8542
  setAccessMode(policy.accessMode);
7461
8543
  setAllowedUsers(sourceUsers);
7462
8544
  setError(null);
@@ -7606,7 +8688,8 @@ var WECOM_ENDPOINTS = Object.freeze({
7606
8688
  reconnectBot: "bot.reconnect",
7607
8689
  deleteBot: "bot.delete",
7608
8690
  setWorkspace: "bot.workspace.set",
7609
- setAgentPreset: SET_AGENT_PRESET_ENDPOINT
8691
+ setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
8692
+ setContextEnhancement: "bot.context-enhancement.set"
7610
8693
  });
7611
8694
  var PROVISION_STATES3 = /* @__PURE__ */ new Set(["starting", "pending", "refreshing", "connecting", "connected", "failed", "cancelled"]);
7612
8695
  var ACCOUNT_STATES4 = /* @__PURE__ */ new Set(["connected", "connecting", "offline", "error"]);
@@ -7677,6 +8760,7 @@ function normalizeBot4(value) {
7677
8760
  state: connected ? "connected" : state,
7678
8761
  workspace: text4(value.workspace, "", 4096),
7679
8762
  agentPreset: normalizeAgentPresetId(value.agentPreset),
8763
+ contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
7680
8764
  bot: {
7681
8765
  name: text4(value.bot?.name, "\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA", 100),
7682
8766
  appIdMasked: text4(value.bot?.appIdMasked, "\u5E94\u7528\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58", 140)
@@ -7717,7 +8801,7 @@ function formatRemaining4(milliseconds) {
7717
8801
  }
7718
8802
 
7719
8803
  // plugin-src/client/channels/wecom/index.js
7720
- var React17 = __toESM(require("react"), 1);
8804
+ var React18 = __toESM(require("react"), 1);
7721
8805
 
7722
8806
  // plugin-src/client/channels/wecom/styles.js
7723
8807
  var WECOM_STYLE_ID = "xmanrui-dsh-im-wecom-settings";
@@ -7742,7 +8826,7 @@ function installWecomStyles() {
7742
8826
 
7743
8827
  // plugin-src/client/channels/wecom/index.js
7744
8828
  var ACTIVE_STATES2 = /* @__PURE__ */ new Set(["pending", "refreshing", "connecting"]);
7745
- var Button10 = React17.forwardRef(function Button11({ children, kind = "secondary", className = "", ...props }, ref) {
8829
+ var Button10 = React18.forwardRef(function Button11({ children, kind = "secondary", className = "", ...props }, ref) {
7746
8830
  return h2("button", {
7747
8831
  ...props,
7748
8832
  ref,
@@ -7957,6 +9041,7 @@ function AccountCard3({
7957
9041
  onReconnect,
7958
9042
  onWorkspaceSave,
7959
9043
  onAgentPresetSave,
9044
+ onContextEnhancementSave,
7960
9045
  onRequestRemove,
7961
9046
  onConfirmRemove,
7962
9047
  onCancelRemove
@@ -8003,6 +9088,11 @@ function AccountCard3({
8003
9088
  disabled: Boolean(busy),
8004
9089
  onSave: onAgentPresetSave
8005
9090
  }),
9091
+ h2(ContextEnhancementEditor, {
9092
+ config: account.contextEnhancement,
9093
+ disabled: Boolean(busy),
9094
+ onSave: onContextEnhancementSave
9095
+ }),
8006
9096
  h2(
8007
9097
  "div",
8008
9098
  { className: "ddt-accountFooter dim-cardFooter" },
@@ -8037,27 +9127,27 @@ function AccountCard3({
8037
9127
  );
8038
9128
  }
8039
9129
  function WecomSettingsTab({ rpcCall }) {
8040
- const [model, setModel] = React17.useState({
9130
+ const [model, setModel] = React18.useState({
8041
9131
  phase: "loading",
8042
9132
  bots: [],
8043
9133
  totals: { configured: 0, connected: 0 },
8044
9134
  error: null,
8045
9135
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
8046
9136
  });
8047
- const [provision, setProvision] = React17.useState(null);
8048
- const [busy, setBusy] = React17.useState(false);
8049
- const [busyByBot, setBusyByBot] = React17.useState({});
8050
- const [feedbackByBot, setFeedbackByBot] = React17.useState({});
8051
- const [removeTarget, setRemoveTarget] = React17.useState(null);
8052
- const [credentialOpen, setCredentialOpen] = React17.useState(false);
8053
- const [credentialError, setCredentialError] = React17.useState(null);
8054
- const [notice, setNotice] = React17.useState("");
8055
- const [now, setNow] = React17.useState(Date.now());
8056
- const mounted = React17.useRef(true);
9137
+ const [provision, setProvision] = React18.useState(null);
9138
+ const [busy, setBusy] = React18.useState(false);
9139
+ const [busyByBot, setBusyByBot] = React18.useState({});
9140
+ const [feedbackByBot, setFeedbackByBot] = React18.useState({});
9141
+ const [removeTarget, setRemoveTarget] = React18.useState(null);
9142
+ const [credentialOpen, setCredentialOpen] = React18.useState(false);
9143
+ const [credentialError, setCredentialError] = React18.useState(null);
9144
+ const [notice, setNotice] = React18.useState("");
9145
+ const [now, setNow] = React18.useState(Date.now());
9146
+ const mounted = React18.useRef(true);
8057
9147
  const workspaceFence = useWorkspaceSnapshotFence();
8058
- const addButtonRef = React17.useRef(null);
8059
- const noticeFrameRef = React17.useRef(null);
8060
- const announce = React17.useCallback((message) => {
9148
+ const addButtonRef = React18.useRef(null);
9149
+ const noticeFrameRef = React18.useRef(null);
9150
+ const announce = React18.useCallback((message) => {
8061
9151
  if (!mounted.current) return;
8062
9152
  if (noticeFrameRef.current !== null) {
8063
9153
  window.cancelAnimationFrame(noticeFrameRef.current);
@@ -8071,7 +9161,7 @@ function WecomSettingsTab({ rpcCall }) {
8071
9161
  });
8072
9162
  }
8073
9163
  }, []);
8074
- React17.useEffect(() => {
9164
+ React18.useEffect(() => {
8075
9165
  const disposeDingtalk = installDingtalkStyles();
8076
9166
  const disposeWecom = installWecomStyles();
8077
9167
  mounted.current = true;
@@ -8085,11 +9175,11 @@ function WecomSettingsTab({ rpcCall }) {
8085
9175
  disposeDingtalk();
8086
9176
  };
8087
9177
  }, []);
8088
- const invoke = React17.useCallback(async (endpoint, payload = {}, signal) => {
9178
+ const invoke = React18.useCallback(async (endpoint, payload = {}, signal) => {
8089
9179
  if (typeof rpcCall !== "function") throw new TypeError("\u4F01\u4E1A\u5FAE\u4FE1\u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
8090
9180
  return unwrapRpcResult7(await rpcCall(endpoint, payload, signal));
8091
9181
  }, [rpcCall]);
8092
- const loadStatus = React17.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
9182
+ const loadStatus = React18.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
8093
9183
  const workspaceVersion = workspaceFence.beginStatus();
8094
9184
  if (workspaceVersion === null) return void 0;
8095
9185
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
@@ -8115,12 +9205,12 @@ function WecomSettingsTab({ rpcCall }) {
8115
9205
  return void 0;
8116
9206
  }
8117
9207
  }, [invoke, workspaceFence]);
8118
- React17.useEffect(() => {
9208
+ React18.useEffect(() => {
8119
9209
  const controller = new AbortController();
8120
9210
  void loadStatus({ signal: controller.signal, restore: true });
8121
9211
  return () => controller.abort();
8122
9212
  }, [loadStatus]);
8123
- React17.useEffect(() => {
9213
+ React18.useEffect(() => {
8124
9214
  if (model.phase !== "ready") return void 0;
8125
9215
  const controller = new AbortController();
8126
9216
  const timer = window.setInterval(() => void loadStatus({ signal: controller.signal, silent: true }), 15e3);
@@ -8129,12 +9219,12 @@ function WecomSettingsTab({ rpcCall }) {
8129
9219
  window.clearInterval(timer);
8130
9220
  };
8131
9221
  }, [loadStatus, model.phase]);
8132
- React17.useEffect(() => {
9222
+ React18.useEffect(() => {
8133
9223
  if (!provision || !ACTIVE_STATES2.has(provision.status)) return void 0;
8134
9224
  const timer = window.setInterval(() => mounted.current && setNow(Date.now()), 1e3);
8135
9225
  return () => window.clearInterval(timer);
8136
9226
  }, [provision?.attemptId, provision?.status]);
8137
- const startProvisioning = React17.useCallback(async (replace = false) => {
9227
+ const startProvisioning = React18.useCallback(async (replace = false) => {
8138
9228
  setCredentialOpen(false);
8139
9229
  setCredentialError(null);
8140
9230
  setBusy(true);
@@ -8152,7 +9242,7 @@ function WecomSettingsTab({ rpcCall }) {
8152
9242
  if (mounted.current) setBusy(false);
8153
9243
  }
8154
9244
  }, [invoke, provision?.attemptId]);
8155
- const bindCredentials = React17.useCallback(async ({ identity, secret }) => {
9245
+ const bindCredentials = React18.useCallback(async ({ identity, secret }) => {
8156
9246
  const snapshotVersion = workspaceFence.beginMutation();
8157
9247
  setBusy(true);
8158
9248
  setCredentialError(null);
@@ -8180,7 +9270,7 @@ function WecomSettingsTab({ rpcCall }) {
8180
9270
  if (mounted.current) setBusy(false);
8181
9271
  }
8182
9272
  }, [invoke, loadStatus, workspaceFence]);
8183
- const closeProvision = React17.useCallback(async () => {
9273
+ const closeProvision = React18.useCallback(async () => {
8184
9274
  setBusy(true);
8185
9275
  try {
8186
9276
  if (provision?.attemptId && ACTIVE_STATES2.has(provision.status)) {
@@ -8191,7 +9281,7 @@ function WecomSettingsTab({ rpcCall }) {
8191
9281
  if (mounted.current) setBusy(false);
8192
9282
  }
8193
9283
  }, [invoke, provision?.attemptId, provision?.status]);
8194
- React17.useEffect(() => {
9284
+ React18.useEffect(() => {
8195
9285
  const attemptId = provision?.attemptId;
8196
9286
  if (!attemptId || !ACTIVE_STATES2.has(provision.status)) return void 0;
8197
9287
  const controller = new AbortController();
@@ -8221,7 +9311,7 @@ function WecomSettingsTab({ rpcCall }) {
8221
9311
  window.clearTimeout(timer);
8222
9312
  };
8223
9313
  }, [invoke, loadStatus, provision?.attemptId, provision?.pollIntervalMs, provision?.status]);
8224
- const botAction = React17.useCallback(async (account, operation, endpoint, payload) => {
9314
+ const botAction = React18.useCallback(async (account, operation, endpoint, payload) => {
8225
9315
  const snapshotVersion = workspaceFence.beginMutation();
8226
9316
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
8227
9317
  try {
@@ -8246,7 +9336,7 @@ function WecomSettingsTab({ rpcCall }) {
8246
9336
  });
8247
9337
  }
8248
9338
  }, [invoke, loadStatus, workspaceFence]);
8249
- const reconnect = React17.useCallback(async (account) => {
9339
+ const reconnect = React18.useCallback(async (account) => {
8250
9340
  setFeedbackByBot((current) => {
8251
9341
  const next = { ...current };
8252
9342
  delete next[account.botId];
@@ -8326,6 +9416,12 @@ function WecomSettingsTab({ rpcCall }) {
8326
9416
  WECOM_ENDPOINTS.setAgentPreset,
8327
9417
  { botId: account.botId, agentPreset }
8328
9418
  ),
9419
+ onContextEnhancementSave: (config) => botAction(
9420
+ account,
9421
+ "context-enhancement",
9422
+ WECOM_ENDPOINTS.setContextEnhancement,
9423
+ { botId: account.botId, config }
9424
+ ),
8329
9425
  onRequestRemove: () => setRemoveTarget(account.botId),
8330
9426
  onCancelRemove: () => setRemoveTarget(null),
8331
9427
  onConfirmRemove: async () => {
@@ -8367,7 +9463,7 @@ function WecomSettingsTab({ rpcCall }) {
8367
9463
  }),
8368
9464
  h2("div", { className: "ddt-visuallyHidden", role: "status", "aria-live": "polite" }, notice),
8369
9465
  model.phase === "loading" ? h2(LoadingView4) : model.phase === "error" ? h2("div", { className: "ddt-card dim-surfaceCard" }, h2("div", { className: "ddt-inlineError dim-inlineError" }, h2("h3", null, "\u65E0\u6CD5\u8BFB\u53D6\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA\u72B6\u6001"), h2("p", null, model.error?.message), h2(Button10, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6"))) : h2(
8370
- React17.Fragment,
9466
+ React18.Fragment,
8371
9467
  null,
8372
9468
  credentialView,
8373
9469
  provisionView,
@@ -8378,7 +9474,7 @@ function WecomSettingsTab({ rpcCall }) {
8378
9474
  }
8379
9475
 
8380
9476
  // plugin-src/client/channels/weixin/index.js
8381
- var React18 = __toESM(require("react"), 1);
9477
+ var React19 = __toESM(require("react"), 1);
8382
9478
 
8383
9479
  // plugin-src/client/channels/weixin/api.js
8384
9480
  var WEIXIN_RPC_CHANNEL = "/weixin";
@@ -8391,7 +9487,8 @@ var WEIXIN_ENDPOINTS = Object.freeze({
8391
9487
  reconnectBot: "bot.reconnect",
8392
9488
  deleteBot: "bot.delete",
8393
9489
  setWorkspace: "bot.workspace.set",
8394
- setAgentPreset: SET_AGENT_PRESET_ENDPOINT
9490
+ setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
9491
+ setContextEnhancement: "bot.context-enhancement.set"
8395
9492
  });
8396
9493
  var ACCOUNT_STATES5 = /* @__PURE__ */ new Set(["connected", "connecting", "offline", "error"]);
8397
9494
  var PROVISION_STATES4 = /* @__PURE__ */ new Set([
@@ -8482,6 +9579,7 @@ function normalizeBot5(value) {
8482
9579
  configured: value.configured === true,
8483
9580
  workspace: string(value.workspace).slice(0, 4096),
8484
9581
  agentPreset: normalizeAgentPresetId(value.agentPreset),
9582
+ contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
8485
9583
  bot: {
8486
9584
  name: string(value.bot.name, "\u5FAE\u4FE1\u673A\u5668\u4EBA"),
8487
9585
  accountIdMasked: string(value.bot.accountIdMasked, "\u5DF2\u5B89\u5168\u4FDD\u5B58")
@@ -8533,7 +9631,7 @@ function formatRemaining5(milliseconds) {
8533
9631
  }
8534
9632
 
8535
9633
  // plugin-src/client/channels/weixin/index.js
8536
- var Button12 = React18.forwardRef(function Button13({ children, kind = "secondary", className = "", ...props }, ref) {
9634
+ var Button12 = React19.forwardRef(function Button13({ children, kind = "secondary", className = "", ...props }, ref) {
8537
9635
  return h2("button", {
8538
9636
  ...props,
8539
9637
  ref,
@@ -8606,14 +9704,14 @@ function EmptyView5({ onStart, busy }) {
8606
9704
  );
8607
9705
  }
8608
9706
  function QrPanel4({ provision, now, busy, onRefresh, onCancel }) {
8609
- const [imageFailed, setImageFailed] = React18.useState(false);
9707
+ const [imageFailed, setImageFailed] = React19.useState(false);
8610
9708
  const source = safeQrSource5(provision.qrCodeDataUrl);
8611
9709
  const href = safeVerificationUrl(provision.verificationUrl);
8612
9710
  const remaining = Math.max(0, provision.expiresAt - now);
8613
9711
  const expired = remaining === 0 || provision.status === "expired";
8614
9712
  const duration = Math.max(1, provision.durationMs ?? 5 * 6e4);
8615
9713
  const progress = Math.round(Math.min(1, remaining / duration) * 100);
8616
- React18.useEffect(() => setImageFailed(false), [source]);
9714
+ React19.useEffect(() => setImageFailed(false), [source]);
8617
9715
  return h2(
8618
9716
  "div",
8619
9717
  { className: "dxw-card dim-surfaceCard" },
@@ -8680,9 +9778,9 @@ function QrPanel4({ provision, now, busy, onRefresh, onCancel }) {
8680
9778
  );
8681
9779
  }
8682
9780
  function VerificationPanel({ provision, busy, onSubmit, onCancel }) {
8683
- const [code, setCode] = React18.useState("");
9781
+ const [code, setCode] = React19.useState("");
8684
9782
  const valid = /^\d{4,8}$/.test(code);
8685
- React18.useEffect(() => setCode(""), [provision.attemptId]);
9783
+ React19.useEffect(() => setCode(""), [provision.attemptId]);
8686
9784
  return h2(
8687
9785
  "div",
8688
9786
  { className: "dxw-card dim-surfaceCard" },
@@ -8781,6 +9879,7 @@ function AccountCard4({
8781
9879
  onReconnect,
8782
9880
  onWorkspaceSave,
8783
9881
  onAgentPresetSave,
9882
+ onContextEnhancementSave,
8784
9883
  onRequestRemove,
8785
9884
  onConfirmRemove,
8786
9885
  onCancelRemove
@@ -8822,6 +9921,12 @@ function AccountCard4({
8822
9921
  disabled: Boolean(busy),
8823
9922
  onSave: onAgentPresetSave
8824
9923
  }),
9924
+ h2(ContextEnhancementEditor, {
9925
+ config: account.contextEnhancement,
9926
+ groupSupported: false,
9927
+ disabled: Boolean(busy),
9928
+ onSave: onContextEnhancementSave
9929
+ }),
8825
9930
  h2(
8826
9931
  "div",
8827
9932
  { className: "dxw-accountFooter dim-cardFooter" },
@@ -8889,6 +9994,7 @@ function AccountList2(props) {
8889
9994
  onReconnect: () => props.onReconnect(account),
8890
9995
  onWorkspaceSave: (workspace) => props.onWorkspaceSave(account, workspace),
8891
9996
  onAgentPresetSave: (agentPreset) => props.onAgentPresetSave(account, agentPreset),
9997
+ onContextEnhancementSave: (config) => props.onContextEnhancementSave(account, config),
8892
9998
  onRequestRemove: () => props.onRequestRemove(account),
8893
9999
  onConfirmRemove: () => props.onConfirmRemove(account),
8894
10000
  onCancelRemove: props.onCancelRemove
@@ -8907,7 +10013,7 @@ function mergeWeixinProvisioningSnapshot(current, incoming, { restoreProvisionin
8907
10013
  };
8908
10014
  }
8909
10015
  function WeixinSettingsTab({ rpcCall }) {
8910
- const [model, setModel] = React18.useState({
10016
+ const [model, setModel] = React19.useState({
8911
10017
  phase: "loading",
8912
10018
  bots: [],
8913
10019
  totals: EMPTY_TOTALS3,
@@ -8915,33 +10021,33 @@ function WeixinSettingsTab({ rpcCall }) {
8915
10021
  error: null,
8916
10022
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
8917
10023
  });
8918
- const [provision, setProvision] = React18.useState(null);
8919
- const [busy, setBusy] = React18.useState(false);
8920
- const [busyByBot, setBusyByBot] = React18.useState({});
8921
- const [feedbackByBot, setFeedbackByBot] = React18.useState({});
8922
- const [removeTarget, setRemoveTarget] = React18.useState(null);
8923
- const [notice, setNotice] = React18.useState("");
8924
- const [now, setNow] = React18.useState(() => Date.now());
8925
- const addButtonRef = React18.useRef(null);
8926
- const mountedRef = React18.useRef(true);
10024
+ const [provision, setProvision] = React19.useState(null);
10025
+ const [busy, setBusy] = React19.useState(false);
10026
+ const [busyByBot, setBusyByBot] = React19.useState({});
10027
+ const [feedbackByBot, setFeedbackByBot] = React19.useState({});
10028
+ const [removeTarget, setRemoveTarget] = React19.useState(null);
10029
+ const [notice, setNotice] = React19.useState("");
10030
+ const [now, setNow] = React19.useState(() => Date.now());
10031
+ const addButtonRef = React19.useRef(null);
10032
+ const mountedRef = React19.useRef(true);
8927
10033
  const workspaceFence = useWorkspaceSnapshotFence();
8928
10034
  const scheduleAnimationFrame = useAnimationFrameScheduler();
8929
- React18.useEffect(() => {
10035
+ React19.useEffect(() => {
8930
10036
  mountedRef.current = true;
8931
10037
  return () => {
8932
10038
  mountedRef.current = false;
8933
10039
  };
8934
10040
  }, []);
8935
- const announce = React18.useCallback((value) => {
10041
+ const announce = React19.useCallback((value) => {
8936
10042
  setNotice("");
8937
10043
  scheduleAnimationFrame(() => {
8938
10044
  if (value) setNotice(value);
8939
10045
  }, "announcement");
8940
10046
  }, [scheduleAnimationFrame]);
8941
- const invoke = React18.useCallback(async (endpoint, payload = {}, signal) => {
10047
+ const invoke = React19.useCallback(async (endpoint, payload = {}, signal) => {
8942
10048
  return unwrapRpcResult8(await rpcCall(endpoint, payload, signal));
8943
10049
  }, [rpcCall]);
8944
- const loadStatus = React18.useCallback(async ({
10050
+ const loadStatus = React19.useCallback(async ({
8945
10051
  signal,
8946
10052
  silent = false,
8947
10053
  restoreProvisioning = false
@@ -8978,12 +10084,12 @@ function WeixinSettingsTab({ rpcCall }) {
8978
10084
  return void 0;
8979
10085
  }
8980
10086
  }, [invoke, workspaceFence]);
8981
- React18.useEffect(() => {
10087
+ React19.useEffect(() => {
8982
10088
  const controller = new AbortController();
8983
10089
  void loadStatus({ signal: controller.signal, restoreProvisioning: true });
8984
10090
  return () => controller.abort();
8985
10091
  }, [loadStatus]);
8986
- React18.useEffect(() => {
10092
+ React19.useEffect(() => {
8987
10093
  if (model.phase !== "ready") return void 0;
8988
10094
  const controller = new AbortController();
8989
10095
  let running = false;
@@ -9002,12 +10108,12 @@ function WeixinSettingsTab({ rpcCall }) {
9002
10108
  window.clearInterval(timer);
9003
10109
  };
9004
10110
  }, [loadStatus, model.phase]);
9005
- React18.useEffect(() => {
10111
+ React19.useEffect(() => {
9006
10112
  if (!provision || !["pending", "scanned"].includes(provision.status)) return void 0;
9007
10113
  const timer = window.setInterval(() => setNow(Date.now()), 1e3);
9008
10114
  return () => window.clearInterval(timer);
9009
10115
  }, [provision?.attemptId, provision?.status]);
9010
- const startProvisioning = React18.useCallback(async ({ replace = false } = {}) => {
10116
+ const startProvisioning = React19.useCallback(async ({ replace = false } = {}) => {
9011
10117
  setBusy(true);
9012
10118
  try {
9013
10119
  if (replace && provision?.attemptId) {
@@ -9028,7 +10134,7 @@ function WeixinSettingsTab({ rpcCall }) {
9028
10134
  setBusy(false);
9029
10135
  }
9030
10136
  }, [announce, invoke, provision?.attemptId]);
9031
- const cancelProvisioning = React18.useCallback(async () => {
10137
+ const cancelProvisioning = React19.useCallback(async () => {
9032
10138
  setBusy(true);
9033
10139
  try {
9034
10140
  if (provision?.attemptId && !["failed", "expired", "cancelled"].includes(provision.status)) {
@@ -9043,7 +10149,7 @@ function WeixinSettingsTab({ rpcCall }) {
9043
10149
  setBusy(false);
9044
10150
  }
9045
10151
  }, [announce, invoke, provision?.attemptId, provision?.status, scheduleAnimationFrame]);
9046
- const submitVerification = React18.useCallback(async (verifyCode) => {
10152
+ const submitVerification = React19.useCallback(async (verifyCode) => {
9047
10153
  if (!provision?.attemptId) return;
9048
10154
  setBusy(true);
9049
10155
  try {
@@ -9059,7 +10165,7 @@ function WeixinSettingsTab({ rpcCall }) {
9059
10165
  setBusy(false);
9060
10166
  }
9061
10167
  }, [announce, invoke, provision?.attemptId]);
9062
- React18.useEffect(() => {
10168
+ React19.useEffect(() => {
9063
10169
  const attemptId = provision?.attemptId;
9064
10170
  if (!attemptId || !["pending", "scanned", "connecting"].includes(provision.status)) return void 0;
9065
10171
  const controller = new AbortController();
@@ -9107,7 +10213,7 @@ function WeixinSettingsTab({ rpcCall }) {
9107
10213
  controller.abort();
9108
10214
  };
9109
10215
  }, [announce, invoke, loadStatus, provision?.attemptId, provision?.status, provision?.pollIntervalMs]);
9110
- const setBotBusy = React18.useCallback((botId, value) => {
10216
+ const setBotBusy = React19.useCallback((botId, value) => {
9111
10217
  setBusyByBot((current) => {
9112
10218
  const next = { ...current };
9113
10219
  if (value) next[botId] = value;
@@ -9115,7 +10221,7 @@ function WeixinSettingsTab({ rpcCall }) {
9115
10221
  return next;
9116
10222
  });
9117
10223
  }, []);
9118
- const reconnect = React18.useCallback(async (account) => {
10224
+ const reconnect = React19.useCallback(async (account) => {
9119
10225
  const snapshotVersion = workspaceFence.beginMutation();
9120
10226
  setBotBusy(account.botId, "reconnect");
9121
10227
  setFeedbackByBot((current) => {
@@ -9166,7 +10272,7 @@ function WeixinSettingsTab({ rpcCall }) {
9166
10272
  setBotBusy(account.botId, null);
9167
10273
  }
9168
10274
  }, [announce, invoke, loadStatus, setBotBusy, workspaceFence]);
9169
- const saveWorkspace = React18.useCallback(async (account, workspace) => {
10275
+ const saveWorkspace = React19.useCallback(async (account, workspace) => {
9170
10276
  const workspaceVersion = workspaceFence.beginMutation();
9171
10277
  setBotBusy(account.botId, "workspace");
9172
10278
  try {
@@ -9190,13 +10296,13 @@ function WeixinSettingsTab({ rpcCall }) {
9190
10296
  if (mountedRef.current) setBotBusy(account.botId, null);
9191
10297
  }
9192
10298
  }, [invoke, loadStatus, setBotBusy, workspaceFence]);
9193
- const saveAgentPreset = React18.useCallback(async (account, agentPreset) => {
10299
+ const saveBotSetting = React19.useCallback(async (account, operation, endpoint, payload) => {
9194
10300
  const snapshotVersion = workspaceFence.beginMutation();
9195
- setBotBusy(account.botId, "preset");
10301
+ setBotBusy(account.botId, operation);
9196
10302
  try {
9197
10303
  const snapshot = normalizeSnapshot7(await invoke(
9198
- WEIXIN_ENDPOINTS.setAgentPreset,
9199
- { botId: account.botId, agentPreset }
10304
+ endpoint,
10305
+ { botId: account.botId, ...payload }
9200
10306
  ));
9201
10307
  if (mountedRef.current && workspaceFence.canCommitMutation(snapshotVersion)) {
9202
10308
  setModel({
@@ -9214,7 +10320,7 @@ function WeixinSettingsTab({ rpcCall }) {
9214
10320
  if (mountedRef.current) setBotBusy(account.botId, null);
9215
10321
  }
9216
10322
  }, [invoke, loadStatus, setBotBusy, workspaceFence]);
9217
- const remove = React18.useCallback(async (account) => {
10323
+ const remove = React19.useCallback(async (account) => {
9218
10324
  const snapshotVersion = workspaceFence.beginMutation();
9219
10325
  setBotBusy(account.botId, "delete");
9220
10326
  try {
@@ -9298,7 +10404,7 @@ function WeixinSettingsTab({ rpcCall }) {
9298
10404
  h2(Button12, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
9299
10405
  )
9300
10406
  ) : h2(
9301
- React18.Fragment,
10407
+ React19.Fragment,
9302
10408
  null,
9303
10409
  provisionView,
9304
10410
  model.bots.length === 0 && !provision ? h2(EmptyView5, { onStart: () => void startProvisioning(), busy }) : null,
@@ -9309,7 +10415,18 @@ function WeixinSettingsTab({ rpcCall }) {
9309
10415
  removeTarget,
9310
10416
  onReconnect: (account) => void reconnect(account),
9311
10417
  onWorkspaceSave: saveWorkspace,
9312
- onAgentPresetSave: saveAgentPreset,
10418
+ onAgentPresetSave: (account, agentPreset) => saveBotSetting(
10419
+ account,
10420
+ "preset",
10421
+ WEIXIN_ENDPOINTS.setAgentPreset,
10422
+ { agentPreset }
10423
+ ),
10424
+ onContextEnhancementSave: (account, config) => saveBotSetting(
10425
+ account,
10426
+ "context-enhancement",
10427
+ WEIXIN_ENDPOINTS.setContextEnhancement,
10428
+ { config }
10429
+ ),
9313
10430
  onRequestRemove: (account) => setRemoveTarget(account.botId),
9314
10431
  onConfirmRemove: (account) => void remove(account),
9315
10432
  onCancelRemove: () => setRemoveTarget(null)
@@ -9446,7 +10563,8 @@ var WHATSAPP_ENDPOINTS = Object.freeze({
9446
10563
  deleteBot: "bot.delete",
9447
10564
  setAccessPolicy: "bot.access-policy.set",
9448
10565
  setWorkspace: "bot.workspace.set",
9449
- setAgentPreset: SET_AGENT_PRESET_ENDPOINT
10566
+ setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
10567
+ setContextEnhancement: "bot.context-enhancement.set"
9450
10568
  });
9451
10569
  var PROVISION_STATES5 = /* @__PURE__ */ new Set(["starting", "pending", "connecting", "connected", "failed", "cancelled"]);
9452
10570
  var BOT_STATES = /* @__PURE__ */ new Set(["connected", "connecting", "offline", "error"]);
@@ -9512,6 +10630,7 @@ function normalizeBot6(value) {
9512
10630
  state: connected ? "connected" : state,
9513
10631
  workspace: text5(value.workspace, "", 4096),
9514
10632
  agentPreset: normalizeAgentPresetId(value.agentPreset),
10633
+ contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
9515
10634
  accessPolicy: {
9516
10635
  accessMode: ["self-only", "private-allowlist", "open"].includes(
9517
10636
  value.accessPolicy?.accessMode
@@ -9559,7 +10678,7 @@ function formatRemaining6(milliseconds) {
9559
10678
  }
9560
10679
 
9561
10680
  // plugin-src/client/channels/whatsapp/index.js
9562
- var React19 = __toESM(require("react"), 1);
10681
+ var React20 = __toESM(require("react"), 1);
9563
10682
 
9564
10683
  // plugin-src/client/channels/whatsapp/styles.js
9565
10684
  var WHATSAPP_STYLE_ID = "xmanrui-dsh-im-whatsapp-settings";
@@ -9629,11 +10748,11 @@ function allowedNumbersFromText(value) {
9629
10748
  function WhatsappAccessSettings({ account, busy = false, onSave }) {
9630
10749
  const policy = accessPolicyFor(account);
9631
10750
  const sourceNumbers = policy.allowedNumbers.join("\n");
9632
- const helpId = React19.useId();
9633
- const [accessMode, setAccessMode] = React19.useState(policy.accessMode);
9634
- const [allowedNumbers, setAllowedNumbers] = React19.useState(sourceNumbers);
9635
- const [error, setError] = React19.useState(null);
9636
- React19.useEffect(() => {
10751
+ const helpId = React20.useId();
10752
+ const [accessMode, setAccessMode] = React20.useState(policy.accessMode);
10753
+ const [allowedNumbers, setAllowedNumbers] = React20.useState(sourceNumbers);
10754
+ const [error, setError] = React20.useState(null);
10755
+ React20.useEffect(() => {
9637
10756
  setAccessMode(policy.accessMode);
9638
10757
  setAllowedNumbers(sourceNumbers);
9639
10758
  setError(null);
@@ -9759,7 +10878,7 @@ function WhatsappAccessSettings({ account, busy = false, onSave }) {
9759
10878
  )
9760
10879
  );
9761
10880
  }
9762
- var Button14 = React19.forwardRef(function Button15({ children, kind = "secondary", className = "", ...props }, ref) {
10881
+ var Button14 = React20.forwardRef(function Button15({ children, kind = "secondary", className = "", ...props }, ref) {
9763
10882
  return h2("button", {
9764
10883
  ...props,
9765
10884
  ref,
@@ -9982,6 +11101,7 @@ function WhatsappAccountCard({
9982
11101
  onReconnect,
9983
11102
  onWorkspaceSave,
9984
11103
  onAgentPresetSave,
11104
+ onContextEnhancementSave,
9985
11105
  onAccessPolicySave,
9986
11106
  onRequestRemove,
9987
11107
  onConfirmRemove,
@@ -10033,6 +11153,11 @@ function WhatsappAccountCard({
10033
11153
  disabled: Boolean(busy),
10034
11154
  onSave: onAgentPresetSave
10035
11155
  }),
11156
+ h2(ContextEnhancementEditor, {
11157
+ config: account.contextEnhancement,
11158
+ disabled: Boolean(busy),
11159
+ onSave: onContextEnhancementSave
11160
+ }),
10036
11161
  h2(WhatsappAccessSettings, {
10037
11162
  account,
10038
11163
  busy: Boolean(busy),
@@ -10080,23 +11205,23 @@ function WhatsappAccountCard({
10080
11205
  );
10081
11206
  }
10082
11207
  function WhatsappSettingsTab({ rpcCall }) {
10083
- const [model, setModel] = React19.useState({
11208
+ const [model, setModel] = React20.useState({
10084
11209
  phase: "loading",
10085
11210
  bots: [],
10086
11211
  totals: { configured: 0, connected: 0 },
10087
11212
  error: null,
10088
11213
  agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
10089
11214
  });
10090
- const [provision, setProvision] = React19.useState(null);
10091
- const [busy, setBusy] = React19.useState(false);
10092
- const [busyByBot, setBusyByBot] = React19.useState({});
10093
- const [testNoticeByBot, setTestNoticeByBot] = React19.useState({});
10094
- const [removeTarget, setRemoveTarget] = React19.useState(null);
10095
- const [now, setNow] = React19.useState(Date.now());
10096
- const mounted = React19.useRef(true);
11215
+ const [provision, setProvision] = React20.useState(null);
11216
+ const [busy, setBusy] = React20.useState(false);
11217
+ const [busyByBot, setBusyByBot] = React20.useState({});
11218
+ const [testNoticeByBot, setTestNoticeByBot] = React20.useState({});
11219
+ const [removeTarget, setRemoveTarget] = React20.useState(null);
11220
+ const [now, setNow] = React20.useState(Date.now());
11221
+ const mounted = React20.useRef(true);
10097
11222
  const workspaceFence = useWorkspaceSnapshotFence();
10098
- const addButtonRef = React19.useRef(null);
10099
- React19.useEffect(() => {
11223
+ const addButtonRef = React20.useRef(null);
11224
+ React20.useEffect(() => {
10100
11225
  const disposeDingtalk = installDingtalkStyles();
10101
11226
  const disposeWhatsapp = installWhatsappStyles();
10102
11227
  mounted.current = true;
@@ -10106,11 +11231,11 @@ function WhatsappSettingsTab({ rpcCall }) {
10106
11231
  disposeDingtalk();
10107
11232
  };
10108
11233
  }, []);
10109
- const invoke = React19.useCallback(async (endpoint, payload = {}, signal) => {
11234
+ const invoke = React20.useCallback(async (endpoint, payload = {}, signal) => {
10110
11235
  if (typeof rpcCall !== "function") throw new TypeError("WhatsApp \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
10111
11236
  return unwrapRpcResult9(await rpcCall(endpoint, payload, signal));
10112
11237
  }, [rpcCall]);
10113
- const loadStatus = React19.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
11238
+ const loadStatus = React20.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
10114
11239
  const workspaceVersion = workspaceFence.beginStatus();
10115
11240
  if (workspaceVersion === null) return void 0;
10116
11241
  if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
@@ -10140,12 +11265,12 @@ function WhatsappSettingsTab({ rpcCall }) {
10140
11265
  return void 0;
10141
11266
  }
10142
11267
  }, [invoke, workspaceFence]);
10143
- React19.useEffect(() => {
11268
+ React20.useEffect(() => {
10144
11269
  const controller = new AbortController();
10145
11270
  void loadStatus({ signal: controller.signal, restore: true });
10146
11271
  return () => controller.abort();
10147
11272
  }, [loadStatus]);
10148
- React19.useEffect(() => {
11273
+ React20.useEffect(() => {
10149
11274
  if (model.phase !== "ready") return void 0;
10150
11275
  const controller = new AbortController();
10151
11276
  const timer = window.setInterval(
@@ -10157,12 +11282,12 @@ function WhatsappSettingsTab({ rpcCall }) {
10157
11282
  window.clearInterval(timer);
10158
11283
  };
10159
11284
  }, [loadStatus, model.phase]);
10160
- React19.useEffect(() => {
11285
+ React20.useEffect(() => {
10161
11286
  if (!provision || !ACTIVE_STATES3.has(provision.status)) return void 0;
10162
11287
  const timer = window.setInterval(() => mounted.current && setNow(Date.now()), 1e3);
10163
11288
  return () => window.clearInterval(timer);
10164
11289
  }, [provision?.attemptId, provision?.status]);
10165
- const startProvisioning = React19.useCallback(async (replace = false) => {
11290
+ const startProvisioning = React20.useCallback(async (replace = false) => {
10166
11291
  setBusy(true);
10167
11292
  try {
10168
11293
  if (replace && provision?.attemptId) {
@@ -10180,7 +11305,7 @@ function WhatsappSettingsTab({ rpcCall }) {
10180
11305
  if (mounted.current) setBusy(false);
10181
11306
  }
10182
11307
  }, [invoke, provision?.attemptId]);
10183
- const closeProvision = React19.useCallback(async () => {
11308
+ const closeProvision = React20.useCallback(async () => {
10184
11309
  setBusy(true);
10185
11310
  try {
10186
11311
  if (provision?.attemptId && ACTIVE_STATES3.has(provision.status)) {
@@ -10191,7 +11316,7 @@ function WhatsappSettingsTab({ rpcCall }) {
10191
11316
  if (mounted.current) setBusy(false);
10192
11317
  }
10193
11318
  }, [invoke, provision?.attemptId, provision?.status]);
10194
- React19.useEffect(() => {
11319
+ React20.useEffect(() => {
10195
11320
  const attemptId = provision?.attemptId;
10196
11321
  if (!attemptId || !ACTIVE_STATES3.has(provision.status)) return void 0;
10197
11322
  const controller = new AbortController();
@@ -10232,7 +11357,7 @@ function WhatsappSettingsTab({ rpcCall }) {
10232
11357
  if (timer) window.clearTimeout(timer);
10233
11358
  };
10234
11359
  }, [invoke, loadStatus, provision?.attemptId, provision?.status]);
10235
- const botAction = React19.useCallback(async (account, operation, endpoint, payload) => {
11360
+ const botAction = React20.useCallback(async (account, operation, endpoint, payload) => {
10236
11361
  const snapshotVersion = workspaceFence.beginMutation();
10237
11362
  setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
10238
11363
  if (operation === "reconnect") {
@@ -10309,6 +11434,12 @@ function WhatsappSettingsTab({ rpcCall }) {
10309
11434
  WHATSAPP_ENDPOINTS.setAgentPreset,
10310
11435
  { botId: account.botId, agentPreset }
10311
11436
  ),
11437
+ onContextEnhancementSave: (config) => botAction(
11438
+ account,
11439
+ "context-enhancement",
11440
+ WHATSAPP_ENDPOINTS.setContextEnhancement,
11441
+ { botId: account.botId, config }
11442
+ ),
10312
11443
  onAccessPolicySave: (accessPolicy) => botAction(
10313
11444
  account,
10314
11445
  "access",
@@ -10351,7 +11482,7 @@ function WhatsappSettingsTab({ rpcCall }) {
10351
11482
  h2(Button14, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
10352
11483
  )
10353
11484
  ) : h2(
10354
- React19.Fragment,
11485
+ React20.Fragment,
10355
11486
  null,
10356
11487
  provision?.status === "pending" ? h2(QrPanel5, {
10357
11488
  provision,
@@ -10467,6 +11598,17 @@ var CSS11 = String.raw`
10467
11598
  .dim-updateHint, .dim-updateError { margin: 12px 0 0; font-size: 12px; line-height: 19px; overflow-wrap: anywhere; }
10468
11599
  .dim-updateHint { color: var(--dsw-alias-label-secondary, #646a73); }
10469
11600
  .dim-updateError { color: var(--dsw-alias-state-danger-primary, #d92d20); }
11601
+ .dim-updateManual { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--dsw-alias-border-l1, #eef0f3); }
11602
+ .dim-updateManualHeading { margin: 0; font-size: 13px; line-height: 20px; font-weight: 600; }
11603
+ .dim-updateManualHint { margin: 8px 0 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: 19px; }
11604
+ .dim-updateCommandRow { display: flex; align-items: center; gap: 8px; margin-top: 10px; padding: 10px 12px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; background: var(--dsw-alias-bg-layer-1, #f7f8fa); }
11605
+ .dim-updateCommand { display: block; flex: 1; width: 100%; min-width: 0; padding: 0; resize: none; border: 0; color: var(--dsw-alias-label-primary, #1f2329); background: transparent; font: 12px/19px ui-monospace, SFMono-Regular, Menlo, monospace; overflow-wrap: anywhere; }
11606
+ .dim-updateCommand:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: 2px; }
11607
+ .dim-updateCopy { display: inline-flex; flex: 0 0 28px; align-items: center; justify-content: center; width: 28px; height: 28px; padding: 0; border: 0; border-radius: 6px; color: var(--dsw-alias-label-secondary, #646a73); background: transparent; cursor: pointer; }
11608
+ .dim-updateCopy:hover:not(:disabled) { color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-interactive-bg-hover, #eef0f3); }
11609
+ .dim-updateCopy:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: 2px; }
11610
+ .dim-updateCopy:disabled { opacity: .55; cursor: default; }
11611
+ .dim-updateCopyCopied { color: var(--dsw-alias-state-success-primary, #20a162); }
10470
11612
  .dim-updateFooter { display: flex; align-items: center; justify-content: flex-end; flex-wrap: wrap; gap: 8px; padding: 14px 24px; border-top: 1px solid var(--dsw-alias-border-l1, #eef0f3); }
10471
11613
  .dim-updateFooter .dim-updateButton:first-child { margin-right: auto; }
10472
11614
  .dim-updatePrimary, .dim-updatePrimary:hover:not(:disabled) { border-color: var(--dsw-alias-state-business-primary, #3370ff); color: #fff; background: var(--dsw-alias-state-business-primary, #3370ff); }
@@ -10627,6 +11769,73 @@ var CSS11 = String.raw`
10627
11769
  .dim-panel .dim-presetSelect { min-width: 0; max-width: 100%; grid-column: 1 / -1; grid-row: 2; height: 30px; padding: 0 8px; 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; }
10628
11770
  .dim-panel .dim-presetSelect:disabled { cursor: not-allowed; opacity: .55; }
10629
11771
  .dim-panel .dim-presetError { grid-column: 1 / -1; grid-row: 3; margin: 0; color: var(--dsw-alias-state-error-primary, #d54941); font-size: 12px; line-height: 1.4; }
11772
+ .dim-contextEntry { width: 100%; min-height: 40px; display: grid; grid-template-columns: 16px minmax(0, 1fr) max-content 16px; align-items: center; gap: 9px; margin: 10px 0; padding: 8px 11px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-module-platform, #f7f8fa); font: inherit; font-size: 13px; line-height: 20px; text-align: left; cursor: pointer; }
11773
+ .dim-contextEntry:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, #eef0f3); }
11774
+ .dim-contextEntry > svg { color: var(--dsw-alias-label-secondary, #646a73); }
11775
+ .dim-contextLabel { min-width: 0; font-weight: 500; overflow-wrap: anywhere; }
11776
+ .dim-contextStatus { padding: 2px 7px; border-radius: 5px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-layer-1, #fff); font-size: 11px; line-height: 16px; font-weight: 400; white-space: nowrap; }
11777
+ .dim-contextStatus[data-active="true"] { color: var(--dsw-alias-state-business-primary, #3370ff); background: color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 10%, var(--dsw-alias-bg-layer-1, #fff)); }
11778
+ .dim-contextBackdrop { position: fixed; inset: 0; z-index: 1000; display: grid; place-items: center; padding: 12px; background: rgb(15 17 21 / 42%); }
11779
+ .dim-contextBackdrop, .dim-contextBackdrop *, .dim-contextBackdrop *::before, .dim-contextBackdrop *::after { box-sizing: border-box; }
11780
+ .dim-contextDialog { width: min(450px, 100%); min-width: 0; max-height: calc(100vh - 24px); max-height: calc(100dvh - 24px); overflow-y: auto; padding: 16px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 12px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 20px 70px rgb(0 0 0 / 20%); font-size: 13px; line-height: 1.5; text-align: left; }
11781
+ .dim-contextDialog:focus { outline: none; }
11782
+ .dim-contextHeader, .dim-contextEditorHeader { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
11783
+ .dim-contextHeader { position: relative; }
11784
+ .dim-contextHeaderTitle { min-width: 0; display: inline-flex; align-items: center; gap: 6px; }
11785
+ .dim-contextHeader h3 { margin: 0; font-size: 15px; line-height: 22px; font-weight: 500; }
11786
+ .dim-contextHeaderTooltip { width: min(340px, calc(100vw - 72px)); }
11787
+ .dim-contextClose { width: 30px; height: 30px; flex: none; display: grid; place-items: center; padding: 0; border: 0; border-radius: 6px; color: var(--dsw-alias-label-secondary, #646a73); background: transparent; cursor: pointer; }
11788
+ .dim-contextClose:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, #eef0f3); }
11789
+ .dim-contextSection { min-width: 0; margin: 14px 0; padding: 0; border: 0; }
11790
+ .dim-contextSection legend { margin-bottom: 8px; padding: 0; font-weight: 500; }
11791
+ .dim-contextLegend { position: relative; display: inline-flex; align-items: center; gap: 6px; }
11792
+ .dim-contextSwitches { display: grid; grid-template-columns: 1fr; gap: 2px; }
11793
+ .dim-contextSwitchRow { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 34px; cursor: pointer; }
11794
+ .dim-contextSwitchLabel { min-width: 0; display: inline-flex; align-items: baseline; gap: 5px; flex-wrap: wrap; }
11795
+ .dim-contextUnavailable { color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 11px; line-height: 16px; font-weight: 400; }
11796
+ .dim-contextSwitch { appearance: none; flex: none; width: 32px; height: 19px; margin: 0; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 12px; background: var(--dsw-alias-interactive-bg-hover, #eef0f3); cursor: pointer; }
11797
+ .dim-contextSwitch::before { content: ""; display: block; width: 13px; height: 13px; margin: 2px; border-radius: 50%; background: var(--dsw-alias-label-secondary, #646a73); }
11798
+ .dim-contextSwitch:checked { border-color: var(--dsw-alias-state-business-primary, #3370ff); background: var(--dsw-alias-state-business-primary, #3370ff); }
11799
+ .dim-contextSwitch:checked::before { transform: translateX(13px); background: #fff; }
11800
+ .dim-contextFields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 3px 12px; }
11801
+ .dim-contextField { min-width: 0; min-height: 30px; display: flex; align-items: center; gap: 6px; }
11802
+ .dim-contextField input { flex: none; width: 14px; height: 14px; margin: 0; accent-color: var(--dsw-alias-state-business-primary, #3370ff); }
11803
+ .dim-contextFieldText { min-width: 0; display: grid; grid-template-columns: max-content max-content; align-items: center; column-gap: 5px; overflow-wrap: anywhere; }
11804
+ .dim-contextFieldName { min-width: 0; line-height: 17px; cursor: pointer; }
11805
+ .dim-contextFieldKey { min-width: 0; grid-column: 1 / -1; color: var(--dsw-alias-label-tertiary, #8f959e); font: 10px/14px ui-monospace, SFMono-Regular, Menlo, monospace; overflow-wrap: anywhere; cursor: pointer; }
11806
+ .dim-contextFieldHelp { position: relative; }
11807
+ .dim-contextFieldHelpButton { width: 16px; height: 16px; font-size: 10px; }
11808
+ .dim-contextTooltip.dim-contextFieldTooltip { top: calc(100% + 6px); right: 0; left: auto; width: min(280px, calc(100vw - 72px)); }
11809
+ .dim-contextEditorHeader { position: relative; flex-wrap: wrap; }
11810
+ .dim-contextEditorTitle { min-width: 0; display: inline-flex; align-items: center; gap: 6px; }
11811
+ .dim-contextEditorTitle > label { font-weight: 500; }
11812
+ .dim-contextHelp { display: inline-flex; align-items: center; flex: none; }
11813
+ .dim-contextHelpButton { width: 18px; height: 18px; display: grid; place-items: center; padding: 0; border: 1px solid color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 30%, var(--dsw-alias-border-l2, #dfe1e5)); border-radius: 50%; color: var(--dsw-alias-state-business-primary, #3370ff); background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 11px; line-height: 1; font-weight: 700; cursor: help; transition: border-color .15s ease, color .15s ease, background .15s ease, box-shadow .15s ease; }
11814
+ .dim-contextHelpButton:hover:not(:disabled) { border-color: var(--dsw-alias-state-business-primary, #3370ff); background: color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 8%, var(--dsw-alias-bg-layer-1, #fff)); }
11815
+ .dim-contextTooltip { position: absolute; top: calc(100% + 7px); left: 0; z-index: 30; width: min(330px, calc(100vw - 72px)); display: grid; gap: 5px; padding: 10px 11px; 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-3, #fff); box-shadow: 0 10px 28px rgb(31 35 41 / 16%); font-size: 11px; line-height: 16px; font-weight: 400; overflow-wrap: anywhere; white-space: normal; opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
11816
+ .dim-contextTooltip strong { font-weight: 600; }
11817
+ .dim-contextTooltipExample { padding: 7px 8px; border-radius: 6px; background: var(--dsw-alias-bg-module-platform, #f7f8fa); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; white-space: pre-wrap; }
11818
+ .dim-contextTooltip.dim-contextLegendTooltip { width: min(350px, calc(100vw - 72px)); }
11819
+ .dim-contextTooltip.dim-contextGuidanceTooltip { top: auto; bottom: calc(100% + 7px); width: min(380px, calc(100vw - 72px)); max-height: calc(100dvh - 48px); overflow-y: auto; }
11820
+ .dim-contextHelp:hover .dim-contextTooltip, .dim-contextHelp:focus-within .dim-contextTooltip { opacity: 1; visibility: visible; transform: translateY(0); pointer-events: auto; }
11821
+ .dim-contextTextActions { display: flex; gap: 10px; margin-left: auto; }
11822
+ .dim-contextTextActions button { min-height: 30px; padding: 4px 0; border: 0; border-radius: 4px; color: var(--dsw-alias-state-business-primary, #3370ff); background: transparent; font: inherit; font-size: 12px; cursor: pointer; }
11823
+ .dim-contextTextActions button:hover:not(:disabled) { text-decoration: underline; }
11824
+ .dim-contextGuidance textarea { display: block; width: 100%; min-height: 88px; margin-top: 7px; padding: 9px 10px; resize: vertical; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 7px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-module-platform, #f7f8fa); font: inherit; font-size: 12px; line-height: 1.6; }
11825
+ .dim-contextGuidance textarea::placeholder { color: var(--dsw-alias-label-tertiary, #8f959e); opacity: 1; }
11826
+ .dim-contextHint { margin: 5px 0 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 1.5; overflow-wrap: anywhere; }
11827
+ .dim-contextError { margin: 12px 0 0; color: var(--dsw-alias-state-error-primary, #d54941); font-size: 12px; line-height: 1.5; overflow-wrap: anywhere; }
11828
+ .dim-contextFooter { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; }
11829
+ .dim-contextFooter button { min-height: 34px; padding: 6px 15px; 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; cursor: pointer; }
11830
+ .dim-contextFooter button:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, #eef0f3); }
11831
+ .dim-contextFooter .dim-contextSave, .dim-contextFooter .dim-contextSave:hover:not(:disabled) { border-color: var(--dsw-alias-state-business-primary, #3370ff); color: #fff; background: var(--dsw-alias-state-business-primary, #3370ff); }
11832
+ .dim-contextEntry:focus-visible, .dim-contextDialog button:focus-visible, .dim-contextDialog input:focus-visible, .dim-contextDialog textarea:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: 2px; }
11833
+ .dim-contextEntry:disabled, .dim-contextDialog button:disabled, .dim-contextDialog input:disabled, .dim-contextDialog textarea:disabled { opacity: .55; cursor: not-allowed; }
11834
+ @media (pointer: coarse) {
11835
+ .dim-contextEntry, .dim-contextClose, .dim-contextFooter button, .dim-contextTextActions button, .dim-contextField, .dim-contextSwitchRow { min-height: 44px; }
11836
+ .dim-contextClose, .dim-contextTextActions button { min-width: 44px; }
11837
+ .dim-contextGuidance textarea { font-size: 16px; }
11838
+ }
10630
11839
  .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); }
10631
11840
  .dim-directoryPickerBackdrop, .dim-directoryPickerBackdrop *, .dim-directoryPickerBackdrop *::before, .dim-directoryPickerBackdrop *::after { box-sizing: border-box; }
10632
11841
  .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%); }
@@ -10777,8 +11986,10 @@ function installImStyles() {
10777
11986
  }
10778
11987
 
10779
11988
  // plugin-src/client/update-panel.js
10780
- var React20 = __toESM(require("react"), 1);
10781
- var import_react_dom2 = require("react-dom");
11989
+ var React21 = __toESM(require("react"), 1);
11990
+ var import_react_dom3 = require("react-dom");
11991
+ var import_valid = __toESM(require_valid(), 1);
11992
+ var import_rcompare = __toESM(require_rcompare(), 1);
10782
11993
  var UPDATE_RPC_CHANNEL = "/dsh-im";
10783
11994
  var ACTIVE_STATES4 = /* @__PURE__ */ new Set(["installing", "verifying"]);
10784
11995
  var BLOCKED_REASONS = Object.freeze({
@@ -10850,11 +12061,122 @@ function summary(snapshot, action, error) {
10850
12061
  function retainDialogFocus(event) {
10851
12062
  event?.currentTarget?.closest?.(".dim-updateDialog")?.focus?.({ preventScroll: true });
10852
12063
  }
12064
+ function manualUpdateCommand(snapshot) {
12065
+ const profile = snapshot?.profileName;
12066
+ if (snapshot?.sourceInstall || ["source-install", "unknown-profile"].includes(snapshot?.blockedReason) || typeof profile !== "string" || !profile.trim() || profile.length > 255 || profile.startsWith("-") || [".", "..", "node_modules"].includes(profile) || !/^[\p{L}\p{N}_. -]+$/u.test(profile)) return null;
12067
+ const profileArgument = /^[A-Za-z0-9_.-]+$/.test(profile) ? profile : `"${profile}"`;
12068
+ const validVersion = (version2) => typeof version2 === "string" && (0, import_valid.default)(version2) === version2;
12069
+ const pendingRestart = snapshot.blockedReason === "pending-restart" || snapshot.job?.state === "restart-required";
12070
+ const targets = [
12071
+ snapshot.latestVersion,
12072
+ pendingRestart ? snapshot.installedVersion : null,
12073
+ snapshot.job?.state !== "completed" ? snapshot.job?.targetVersion : null
12074
+ ].filter(validVersion);
12075
+ const version = targets.length ? [...targets, snapshot.runningVersion, snapshot.installedVersion].filter(validVersion).sort(import_rcompare.default)[0] : "latest";
12076
+ return `dsh plugin --profile ${profileArgument} add -w @xmanrui/dsh-im@${version}`;
12077
+ }
12078
+ function ManualUpdateCommand({ command, disabled, sourceInstall, desktop }) {
12079
+ const [copyState, setCopyState] = React21.useState("idle");
12080
+ const commandRef = React21.useRef(null);
12081
+ const mounted = React21.useRef(false);
12082
+ const copying = React21.useRef(false);
12083
+ React21.useEffect(() => {
12084
+ mounted.current = true;
12085
+ return () => {
12086
+ mounted.current = false;
12087
+ };
12088
+ }, []);
12089
+ const copy = async (event) => {
12090
+ if (!command || disabled || copying.current) return;
12091
+ retainDialogFocus(event);
12092
+ copying.current = true;
12093
+ setCopyState("copying");
12094
+ try {
12095
+ const clipboard = globalThis.navigator?.clipboard;
12096
+ if (typeof clipboard?.writeText !== "function") throw new Error("Clipboard unavailable");
12097
+ await clipboard.writeText(command);
12098
+ if (mounted.current) setCopyState("copied");
12099
+ } catch {
12100
+ if (mounted.current) {
12101
+ setCopyState("failed");
12102
+ commandRef.current?.focus?.({ preventScroll: true });
12103
+ commandRef.current?.select?.();
12104
+ }
12105
+ } finally {
12106
+ copying.current = false;
12107
+ }
12108
+ };
12109
+ const copyLabel = copyState === "copying" ? "\u590D\u5236\u4E2D\u2026" : copyState === "copied" ? "\u5DF2\u590D\u5236" : "\u590D\u5236\u547D\u4EE4";
12110
+ return h2(
12111
+ "section",
12112
+ { className: "dim-updateManual", "aria-label": "\u624B\u5DE5\u66F4\u65B0" },
12113
+ h2("h4", { className: "dim-updateManualHeading" }, "\u624B\u5DE5\u66F4\u65B0"),
12114
+ command ? h2(
12115
+ React21.Fragment,
12116
+ null,
12117
+ h2("p", { className: "dim-updateManualHint" }, "\u81EA\u52A8\u66F4\u65B0\u5931\u8D25\u53EF\u4EE5\u4F7F\u7528\u547D\u4EE4\u66F4\u65B0\uFF1A"),
12118
+ h2(
12119
+ "div",
12120
+ { className: "dim-updateCommandRow" },
12121
+ h2("textarea", {
12122
+ ref: commandRef,
12123
+ className: "dim-updateCommand",
12124
+ "aria-label": "\u624B\u5DE5\u66F4\u65B0\u547D\u4EE4",
12125
+ value: command,
12126
+ readOnly: true,
12127
+ spellCheck: false,
12128
+ rows: 2,
12129
+ dir: "ltr"
12130
+ }),
12131
+ h2("button", {
12132
+ type: "button",
12133
+ className: `dim-updateCopy${copyState === "copied" ? " dim-updateCopyCopied" : ""}`,
12134
+ "aria-label": copyLabel,
12135
+ title: copyLabel,
12136
+ "aria-busy": copyState === "copying",
12137
+ disabled: disabled || copyState === "copying",
12138
+ onClick: (event) => void copy(event)
12139
+ }, h2("svg", {
12140
+ width: 16,
12141
+ height: 16,
12142
+ viewBox: "0 0 20 20",
12143
+ fill: "none",
12144
+ stroke: "currentColor",
12145
+ strokeWidth: 1.6,
12146
+ strokeLinecap: "round",
12147
+ strokeLinejoin: "round",
12148
+ "aria-hidden": "true",
12149
+ focusable: "false"
12150
+ }, copyState === "copied" ? h2("path", { d: "m4 10 4 4 8-8" }) : h2(
12151
+ React21.Fragment,
12152
+ null,
12153
+ h2("rect", { x: 7, y: 7, width: 10, height: 11, rx: 1.5 }),
12154
+ h2("path", { d: "M5 13H3.5A1.5 1.5 0 0 1 2 11.5v-8A1.5 1.5 0 0 1 3.5 2h8A1.5 1.5 0 0 1 13 3.5V5" })
12155
+ )))
12156
+ ),
12157
+ command.endsWith("@xmanrui/dsh-im@latest") ? h2(
12158
+ "p",
12159
+ { className: "dim-updateManualHint" },
12160
+ "\u5C1A\u672A\u786E\u8BA4\u76EE\u6807\u7248\u672C\uFF0C\u6B64\u547D\u4EE4\u5B89\u88C5\u6267\u884C\u65F6 npm \u7684 latest \u7248\u672C\u3002"
12161
+ ) : null,
12162
+ h2("p", { className: "dim-updateManualHint" }, desktop ? "\u8BF7\u5728\u5F53\u524D Desktop \u7684\u5185\u7F6E\u7EC8\u7AEF\u6267\u884C\uFF0C\u5B8C\u6210\u540E\u624B\u52A8\u91CD\u542F\u3002" : "\u8BF7\u5728\u8FD0\u884C\u5F53\u524D Harness \u7684\u540C\u4E00\u73AF\u5883\u6267\u884C\uFF0C\u4FDD\u6301 DSH_HOME \u4E00\u81F4\uFF0C\u5B8C\u6210\u540E\u624B\u52A8\u91CD\u542F\u3002"),
12163
+ disabled ? h2(
12164
+ "p",
12165
+ { className: "dim-updateManualHint" },
12166
+ "\u8BF7\u7B49\u5F85\u5F53\u524D\u64CD\u4F5C\u7ED3\u675F\uFF0C\u786E\u8BA4\u6CA1\u6709\u5B89\u88C5\u8FDB\u7A0B\u8FD0\u884C\u540E\u518D\u6267\u884C\u547D\u4EE4\u3002"
12167
+ ) : null,
12168
+ copyState === "failed" || copyState === "copied" ? h2("p", {
12169
+ className: copyState === "failed" ? "dim-updateError" : "dim-updateManualHint",
12170
+ role: copyState === "failed" ? "alert" : "status"
12171
+ }, copyState === "failed" ? "\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u9009\u4E2D\u547D\u4EE4\u540E\u6309 Ctrl+C \u6216 \u2318C \u590D\u5236\u3002" : "\u547D\u4EE4\u5DF2\u590D\u5236\u3002") : null
12172
+ ) : h2("p", { className: "dim-updateManualHint" }, sourceInstall ? "\u6E90\u7801\u6216\u94FE\u63A5\u5B89\u88C5\u8BF7\u6309\u539F\u5B89\u88C5\u65B9\u5F0F\u66F4\u65B0\uFF0C\u4E0D\u63D0\u4F9B\u8986\u76D6\u6E90\u7801\u7684 npm \u547D\u4EE4\u3002" : "\u65E0\u6CD5\u5B89\u5168\u751F\u6210\u5F53\u524D profile \u7684\u547D\u4EE4\uFF0C\u8BF7\u5728\u7EC8\u7AEF\u4E2D\u624B\u52A8\u786E\u8BA4 profile \u540E\u66F4\u65B0\u3002")
12173
+ );
12174
+ }
10853
12175
  function UpdateDialog({ children, onClose }) {
10854
- const dialogRef = React20.useRef(null);
10855
- const titleId = React20.useId();
10856
- const descriptionId = React20.useId();
10857
- React20.useEffect(() => {
12176
+ const dialogRef = React21.useRef(null);
12177
+ const titleId = React21.useId();
12178
+ const descriptionId = React21.useId();
12179
+ React21.useEffect(() => {
10858
12180
  const previous = globalThis.document?.activeElement;
10859
12181
  dialogRef.current?.focus?.();
10860
12182
  return () => {
@@ -10886,7 +12208,7 @@ function UpdateDialog({ children, onClose }) {
10886
12208
  onClose();
10887
12209
  }
10888
12210
  if (event.key !== "Tab") return;
10889
- const buttons = dialogRef.current?.querySelectorAll?.("button:not(:disabled)");
12211
+ const buttons = dialogRef.current?.querySelectorAll?.("button:not(:disabled), textarea:not(:disabled)");
10890
12212
  if (!buttons?.length) return;
10891
12213
  const first = buttons[0];
10892
12214
  const last = buttons[buttons.length - 1];
@@ -10909,22 +12231,22 @@ function UpdateDialog({ children, onClose }) {
10909
12231
  children
10910
12232
  )
10911
12233
  );
10912
- return typeof document !== "undefined" && document.body ? (0, import_react_dom2.createPortal)(content, document.body) : content;
12234
+ return typeof document !== "undefined" && document.body ? (0, import_react_dom3.createPortal)(content, document.body) : content;
10913
12235
  }
10914
12236
  function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
10915
- const [snapshot, setSnapshot] = React20.useState(null);
10916
- const [action, setAction] = React20.useState("status");
10917
- const [error, setError] = React20.useState(null);
10918
- const [open, setOpen] = React20.useState(false);
10919
- const [uncertainInstall, setUncertainInstall] = React20.useState(false);
10920
- const mounted = React20.useRef(false);
10921
- const busy = React20.useRef(false);
10922
- const readController = React20.useRef(null);
10923
- const pollReadController = React20.useRef(null);
10924
- const installRequest = React20.useRef(null);
10925
- const onStatusRef = React20.useRef(onStatus);
12237
+ const [snapshot, setSnapshot] = React21.useState(null);
12238
+ const [action, setAction] = React21.useState("status");
12239
+ const [error, setError] = React21.useState(null);
12240
+ const [open, setOpen] = React21.useState(false);
12241
+ const [uncertainInstall, setUncertainInstall] = React21.useState(false);
12242
+ const mounted = React21.useRef(false);
12243
+ const busy = React21.useRef(false);
12244
+ const readController = React21.useRef(null);
12245
+ const pollReadController = React21.useRef(null);
12246
+ const installRequest = React21.useRef(null);
12247
+ const onStatusRef = React21.useRef(onStatus);
10926
12248
  onStatusRef.current = onStatus;
10927
- const accept = React20.useCallback((next) => {
12249
+ const accept = React21.useCallback((next) => {
10928
12250
  setSnapshot(next);
10929
12251
  onStatusRef.current?.(next);
10930
12252
  }, []);
@@ -10933,7 +12255,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
10933
12255
  setUncertainInstall(false);
10934
12256
  accept(next);
10935
12257
  };
10936
- const invoke = React20.useCallback(async (endpoint, payload = {}, signal) => {
12258
+ const invoke = React21.useCallback(async (endpoint, payload = {}, signal) => {
10937
12259
  if (typeof rpcCall !== "function") {
10938
12260
  const unavailable = new Error("\u5F53\u524D Host \u4E0D\u652F\u6301\u66F4\u65B0\u63A5\u53E3\uFF0C\u8BF7\u5148\u624B\u52A8\u66F4\u65B0\u63D2\u4EF6\u5E76\u91CD\u542F\u3002");
10939
12261
  unavailable.code = "update-unavailable";
@@ -10941,7 +12263,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
10941
12263
  }
10942
12264
  return unwrapSnapshot(await rpcCall(endpoint, payload, signal));
10943
12265
  }, [rpcCall]);
10944
- React20.useEffect(() => {
12266
+ React21.useEffect(() => {
10945
12267
  mounted.current = true;
10946
12268
  busy.current = true;
10947
12269
  const controller = new AbortController();
@@ -10964,7 +12286,7 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
10964
12286
  const activeJob = ACTIVE_STATES4.has(snapshot?.job?.state);
10965
12287
  const restartRequired = snapshot?.job?.state === "restart-required" || snapshot?.blockedReason === "pending-restart";
10966
12288
  const shouldPoll = activeJob || uncertainInstall;
10967
- React20.useEffect(() => {
12289
+ React21.useEffect(() => {
10968
12290
  if (!shouldPoll) return void 0;
10969
12291
  let controller;
10970
12292
  const scheduler = createPollScheduler({
@@ -11059,9 +12381,10 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
11059
12381
  const failedJob = ["failed", "interrupted"].includes(snapshot?.job?.state);
11060
12382
  const jobMessage = snapshot?.job?.message;
11061
12383
  const targetVersion = snapshot?.job?.targetVersion;
12384
+ const manualCommand = manualUpdateCommand(snapshot);
11062
12385
  const buttonLabel = action === "checking" ? "\u68C0\u67E5\u4E2D\u2026" : action === "starting" || activeJob ? "\u6B63\u5728\u66F4\u65B0\u2026" : restartRequired ? "\u5F85\u624B\u52A8\u91CD\u542F" : snapshot?.canInstall ? "\u66F4\u65B0\u81F3" : "\u68C0\u67E5\u66F4\u65B0";
11063
12386
  return h2(
11064
- React20.Fragment,
12387
+ React21.Fragment,
11065
12388
  null,
11066
12389
  h2("button", {
11067
12390
  type: "button",
@@ -11086,29 +12409,19 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
11086
12409
  h2("dt", null, "\u8FD0\u884C\u7248\u672C"),
11087
12410
  h2("dd", null, `v${snapshot?.runningVersion ?? clientVersion}`),
11088
12411
  snapshot?.installedVersion && snapshot.installedVersion !== snapshot.runningVersion ? h2(
11089
- React20.Fragment,
12412
+ React21.Fragment,
11090
12413
  null,
11091
12414
  h2("dt", null, "\u5DF2\u5B89\u88C5\u7248\u672C"),
11092
12415
  h2("dd", null, `v${snapshot.installedVersion}`)
11093
12416
  ) : null,
11094
- h2("dt", null, "npm \u6700\u65B0\u7248\u672C"),
11095
- h2("dd", null, snapshot?.latestVersion ? `v${snapshot.latestVersion}` : "\u5C1A\u672A\u68C0\u67E5"),
11096
12417
  targetVersion ? h2(
11097
- React20.Fragment,
12418
+ React21.Fragment,
11098
12419
  null,
11099
12420
  h2("dt", null, "\u76EE\u6807\u7248\u672C"),
11100
12421
  h2("dd", null, `v${targetVersion}`)
11101
12422
  ) : null,
11102
12423
  h2("dt", null, "\u76EE\u6807 profile"),
11103
- h2("dd", null, snapshot?.profileName ?? "\u65E0\u6CD5\u786E\u8BA4"),
11104
- h2("dt", null, "\u66F4\u65B0\u6765\u6E90"),
11105
- h2("dd", null, "registry.npmjs.org"),
11106
- versionsDiffer ? h2(
11107
- React20.Fragment,
11108
- null,
11109
- h2("dt", null, "\u9875\u9762\u7248\u672C"),
11110
- h2("dd", null, `v${clientVersion}`)
11111
- ) : null
12424
+ h2("dd", null, snapshot?.profileName ?? "\u65E0\u6CD5\u786E\u8BA4")
11112
12425
  ),
11113
12426
  h2(
11114
12427
  "div",
@@ -11134,7 +12447,14 @@ function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
11134
12447
  "p",
11135
12448
  { className: "dim-updateHint" },
11136
12449
  "\u8BF7\u5728\u673A\u5668\u4EBA\u7A7A\u95F2\u65F6\u5B89\u88C5\uFF1B\u5B89\u88C5\u4F1A\u4FEE\u6539\u5F53\u524D profile \u7684\u4F9D\u8D56\uFF0C\u5B8C\u6210\u540E\u9700\u624B\u52A8\u91CD\u542F\u3002"
11137
- ) : null
12450
+ ) : null,
12451
+ h2(ManualUpdateCommand, {
12452
+ key: manualCommand ?? "unavailable",
12453
+ command: manualCommand,
12454
+ disabled: busyAction || activeJob || uncertainInstall,
12455
+ sourceInstall: snapshot?.sourceInstall || snapshot?.blockedReason === "source-install",
12456
+ desktop: snapshot?.environmentKind === "desktop"
12457
+ })
11138
12458
  ),
11139
12459
  h2(
11140
12460
  "footer",
@@ -11290,18 +12610,18 @@ function IMSettingsTab({
11290
12610
  browserLocation = globalThis.location,
11291
12611
  navigateToRecoveryUrl = replacePageLocation
11292
12612
  }) {
11293
- const [selected, setSelected] = React21.useState("weixin");
11294
- const [loopbackRecovery, setLoopbackRecovery] = React21.useState(null);
11295
- const [runningVersion, setRunningVersion] = React21.useState(IM_PLUGIN_VERSION);
11296
- const githubTooltipId = React21.useId();
12613
+ const [selected, setSelected] = React22.useState("weixin");
12614
+ const [loopbackRecovery, setLoopbackRecovery] = React22.useState(null);
12615
+ const [runningVersion, setRunningVersion] = React22.useState(IM_PLUGIN_VERSION);
12616
+ const githubTooltipId = React22.useId();
11297
12617
  const active = CHANNELS.find((channel4) => channel4.id === selected) ?? CHANNELS[0];
11298
- const reportLoopbackRecovery = React21.useCallback((recovery) => {
12618
+ const reportLoopbackRecovery = React22.useCallback((recovery) => {
11299
12619
  setLoopbackRecovery((current) => current?.url === recovery.url ? current : recovery);
11300
12620
  }, []);
11301
- const reportUpdateStatus = React21.useCallback((snapshot) => {
12621
+ const reportUpdateStatus = React22.useCallback((snapshot) => {
11302
12622
  setRunningVersion(snapshot.runningVersion);
11303
12623
  }, []);
11304
- const rpcCalls = React21.useMemo(() => createLoopbackAwareRpcCalls({
12624
+ const rpcCalls = React22.useMemo(() => createLoopbackAwareRpcCalls({
11305
12625
  dingtalkRpcCall,
11306
12626
  discordRpcCall,
11307
12627
  feishuRpcCall,