@sidleo3/dsh-chat 0.0.4

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 (47) hide show
  1. package/client/bot-list.js +243 -0
  2. package/client/bot-settings.js +175 -0
  3. package/client/bot-shared-settings.js +561 -0
  4. package/client/chat-ui.js +134 -0
  5. package/client/context-enhancement.js +435 -0
  6. package/client/delivery-targets.js +334 -0
  7. package/client/diagnostics.js +160 -0
  8. package/client/i18n.js +371 -0
  9. package/client/index.js +77 -0
  10. package/client/list-order.js +144 -0
  11. package/client/rpc.js +52 -0
  12. package/client/scoped-mode-editor.js +111 -0
  13. package/client/section.js +250 -0
  14. package/client/session-badges.js +263 -0
  15. package/client/styles.js +960 -0
  16. package/client/version-panel.js +97 -0
  17. package/cordis.patch.yml +5 -0
  18. package/host/bot-model.mjs +53 -0
  19. package/host/bot-settings.mjs +247 -0
  20. package/host/channel-registry.mjs +237 -0
  21. package/host/commands.mjs +857 -0
  22. package/host/deferred.mjs +291 -0
  23. package/host/delivery.mjs +377 -0
  24. package/host/file-log.mjs +169 -0
  25. package/host/guidance.mjs +73 -0
  26. package/host/index.mjs +7 -0
  27. package/host/interactions.mjs +330 -0
  28. package/host/json-store.mjs +144 -0
  29. package/host/log-tail.mjs +63 -0
  30. package/host/panel.mjs +1012 -0
  31. package/host/paths.mjs +50 -0
  32. package/host/plugin.mjs +873 -0
  33. package/host/prompt-context.mjs +70 -0
  34. package/host/rpc.mjs +147 -0
  35. package/host/session-keys.mjs +25 -0
  36. package/host/session-store.mjs +187 -0
  37. package/host/sessions.mjs +1348 -0
  38. package/host/tools.mjs +283 -0
  39. package/lib/client.js +4431 -0
  40. package/lib/index.js +5676 -0
  41. package/package.json +63 -0
  42. package/shared/access-policy.mjs +263 -0
  43. package/shared/channel-rail.mjs +156 -0
  44. package/shared/context-enhancement.mjs +415 -0
  45. package/shared/contract.mjs +120 -0
  46. package/shared/panel-sections.mjs +76 -0
  47. package/shared/reply-reference.mjs +115 -0
package/lib/client.js ADDED
@@ -0,0 +1,4431 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "@sidleo3/dsh-chat",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ var __create = Object.create;
7
+ var __defProp = Object.defineProperty;
8
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
9
+ var __getOwnPropNames = Object.getOwnPropertyNames;
10
+ var __getProtoOf = Object.getPrototypeOf;
11
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
12
+ var __export = (target, all) => {
13
+ for (var name2 in all)
14
+ __defProp(target, name2, { get: all[name2], enumerable: true });
15
+ };
16
+ var __copyProps = (to, from, except, desc) => {
17
+ if (from && typeof from === "object" || typeof from === "function") {
18
+ for (let key of __getOwnPropNames(from))
19
+ if (!__hasOwnProp.call(to, key) && key !== except)
20
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
25
+ // If the importer is in node compatibility mode or this is not an ESM
26
+ // file that has been converted to a CommonJS file using a Babel-
27
+ // compatible transform (i.e. "__esModule" has not been set), then set
28
+ // "default" to the CommonJS "module.exports" for node compatibility.
29
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
30
+ mod
31
+ ));
32
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
33
+
34
+ // packages/dsh-chat/client/index.js
35
+ var index_exports = {};
36
+ __export(index_exports, {
37
+ apply: () => apply,
38
+ inject: () => inject,
39
+ name: () => name
40
+ });
41
+ module.exports = __toCommonJS(index_exports);
42
+
43
+ // packages/dsh-chat/shared/contract.mjs
44
+ var CONTRACT_VERSION = 1;
45
+ var CLIENT_CHANNEL_SERVICE = "chatChannels";
46
+ var CLIENT_UI_SERVICE = "chatUi";
47
+ var SETTINGS_SECTION_SLOT = "settings.section";
48
+ var SETTINGS_SECTION_ID = "dsh-chat";
49
+ var SETTINGS_SECTION_ORDER = 21;
50
+ var SETTINGS_LABEL_KEY = "Chat\u673A\u5668\u4EBA";
51
+ var CHANNEL_PAGE_SLOT = "chat.channel.page";
52
+ var RPC_PREFIX = "dsh-chat";
53
+ var CONTROL_CHANNEL_ID = "control";
54
+ var CHANNEL_ID_PATTERN = /^[a-z][a-z0-9-]{1,31}$/;
55
+
56
+ // packages/dsh-chat/shared/channel-rail.mjs
57
+ function isPlainObject(value) {
58
+ return value !== null && typeof value === "object" && !Array.isArray(value);
59
+ }
60
+ function channelIconUri(icon) {
61
+ if (!isPlainObject(icon)) return null;
62
+ if (typeof icon.uri === "string" && icon.uri.startsWith("data:image/")) return icon.uri;
63
+ if (typeof icon.svg === "string" && icon.svg.trim().startsWith("<svg")) {
64
+ return `data:image/svg+xml,${encodeURIComponent(icon.svg)}`;
65
+ }
66
+ return null;
67
+ }
68
+ function createChannelRail() {
69
+ const byId = /* @__PURE__ */ new Map();
70
+ const listeners = /* @__PURE__ */ new Set();
71
+ let snapshot = Object.freeze([]);
72
+ function refresh() {
73
+ snapshot = Object.freeze(
74
+ [...byId.values()].sort((left, right) => left.order === right.order ? left.id.localeCompare(right.id) : left.order - right.order)
75
+ );
76
+ for (const listener of [...listeners]) {
77
+ try {
78
+ listener();
79
+ } catch {
80
+ }
81
+ }
82
+ }
83
+ return {
84
+ /**
85
+ * 注册一个渠道的显示元数据。
86
+ *
87
+ * @param definition - { id, order, label, logo, icon, sessionBadge, capabilities }。
88
+ * `icon` = `{ svg }` 或 `{ uri }`:渠道图标(设置页卡片与侧边栏会话行共用同一份)。
89
+ * `sessionBadge` = `{ text, color }`:侧边栏会话行里显示的渠道徽标
90
+ * (没有会话行插槽,只能靠 hub 的 DOM 增强渲染,见 client/session-badges.js)。
91
+ * @returns 注销函数。
92
+ */
93
+ register(definition) {
94
+ if (!isPlainObject(definition)) throw new TypeError("chatChannels.register \u9700\u8981\u4E00\u4EFD\u6E20\u9053\u5143\u6570\u636E\u5BF9\u8C61\u3002");
95
+ const { id, order, label, logo, icon, sessionBadge, capabilities } = definition;
96
+ if (typeof id !== "string" || !CHANNEL_ID_PATTERN.test(id)) {
97
+ throw new TypeError("\u6E20\u9053 id \u5FC5\u987B\u662F 2\u201332 \u4F4D\u5C0F\u5199\u5B57\u6BCD/\u6570\u5B57/\u8FDE\u5B57\u7B26\uFF0C\u4E14\u4EE5\u5B57\u6BCD\u5F00\u5934\u3002");
98
+ }
99
+ if (typeof label !== "string" && typeof label !== "function") {
100
+ throw new TypeError("\u6E20\u9053 label \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6216\u8FD4\u56DE\u5B57\u7B26\u4E32\u7684\u51FD\u6570\u3002");
101
+ }
102
+ if (!Number.isFinite(order)) throw new TypeError("\u6E20\u9053 order \u5FC5\u987B\u662F\u6709\u9650\u6570\u5B57\u3002");
103
+ if (capabilities !== void 0 && !isPlainObject(capabilities)) {
104
+ throw new TypeError("\u6E20\u9053 capabilities \u5FC5\u987B\u662F\u5BF9\u8C61\u3002");
105
+ }
106
+ if (icon !== void 0) {
107
+ const hasSvg = isPlainObject(icon) && typeof icon.svg === "string" && icon.svg.trim().startsWith("<svg");
108
+ const hasUri = isPlainObject(icon) && typeof icon.uri === "string" && icon.uri.startsWith("data:image/");
109
+ if (!hasSvg && !hasUri) {
110
+ throw new TypeError('\u6E20\u9053 icon \u9700\u8981 { svg: "<svg \u2026>" } \u6216 { uri: "data:image/\u2026" }\u3002');
111
+ }
112
+ }
113
+ if (sessionBadge !== void 0) {
114
+ if (!isPlainObject(sessionBadge) || typeof sessionBadge.text !== "string" || !sessionBadge.text) {
115
+ throw new TypeError("\u6E20\u9053 sessionBadge \u9700\u8981 { text, color? }\u3002");
116
+ }
117
+ }
118
+ if (byId.has(id)) throw new Error(`\u6E20\u9053 ${id} \u5DF2\u6CE8\u518C\uFF0C\u4E0D\u80FD\u91CD\u590D\u6CE8\u518C\u3002`);
119
+ const entry = Object.freeze({
120
+ id,
121
+ order,
122
+ label: typeof label === "function" ? label : () => label,
123
+ logo: logo ?? null,
124
+ // 渠道图标:设置页左栏卡片与侧边栏会话行徽标共用。
125
+ // 官方标志常常是位图(favicon 提取),所以既支持 svg 字符串也支持 data URI。
126
+ icon: icon === void 0 ? null : Object.freeze({
127
+ ...typeof icon.svg === "string" ? { svg: icon.svg } : {},
128
+ ...typeof icon.uri === "string" ? { uri: icon.uri } : {}
129
+ }),
130
+ sessionBadge: sessionBadge === void 0 ? null : Object.freeze({ text: sessionBadge.text, color: sessionBadge.color ?? null }),
131
+ capabilities: Object.freeze({ ...capabilities ?? {} })
132
+ });
133
+ byId.set(id, entry);
134
+ refresh();
135
+ return () => {
136
+ if (byId.get(id) !== entry) return;
137
+ byId.delete(id);
138
+ refresh();
139
+ };
140
+ },
141
+ /** @returns 当前渠道列表(按 order 排序的冻结数组)。 */
142
+ entries() {
143
+ return snapshot;
144
+ },
145
+ /** @returns 快照,供 useSyncExternalStore 使用。 */
146
+ getSnapshot() {
147
+ return snapshot;
148
+ },
149
+ /**
150
+ * 订阅渠道列表变化。
151
+ *
152
+ * @param listener - 无参回调。
153
+ * @returns 取消订阅函数。
154
+ */
155
+ subscribe(listener) {
156
+ if (typeof listener !== "function") throw new TypeError("chatChannels.subscribe \u9700\u8981\u51FD\u6570\u3002");
157
+ listeners.add(listener);
158
+ return () => listeners.delete(listener);
159
+ },
160
+ /**
161
+ * @param id - 渠道 id。
162
+ * @returns 该渠道的元数据,未注册时为 undefined。
163
+ */
164
+ get(id) {
165
+ return byId.get(id);
166
+ },
167
+ /** @returns 已注册渠道数量。 */
168
+ get size() {
169
+ return byId.size;
170
+ }
171
+ };
172
+ }
173
+
174
+ // packages/dsh-chat/client/chat-ui.js
175
+ var React6 = __toESM(require("react"), 1);
176
+
177
+ // packages/dsh-chat/client/bot-settings.js
178
+ var React = __toESM(require("react"), 1);
179
+
180
+ // packages/dsh-chat/client/rpc.js
181
+ function chatEndpoint(channelId) {
182
+ return `${RPC_PREFIX}/${channelId}`;
183
+ }
184
+ function callChatRpc(connection, channelId, method, payload = {}, signal) {
185
+ if (typeof connection?.rpc?.call !== "function") {
186
+ throw new TypeError("\u5F53\u524D\u9875\u9762\u7F3A\u5C11 DSH Connection RPC \u80FD\u529B\u3002");
187
+ }
188
+ return connection.rpc.call("/api", chatEndpoint(channelId), { method, payload }, signal);
189
+ }
190
+ function callControlRpc(connection, method, payload, signal) {
191
+ return callChatRpc(connection, CONTROL_CHANNEL_ID, method, payload, signal);
192
+ }
193
+ function unwrapRpc(result) {
194
+ if (result?.ok === true) return result.value;
195
+ const error = new Error(result?.error?.message ?? "\u804A\u5929\u63D2\u4EF6\u8C03\u7528\u5931\u8D25\u3002");
196
+ error.code = result?.error?.code ?? "chat/rpc-failed";
197
+ error.details = result?.error?.details ?? {};
198
+ throw error;
199
+ }
200
+
201
+ // packages/dsh-chat/client/bot-settings.js
202
+ function useBotSettings({ connection, channelId, botId, enabled = true }) {
203
+ const [state, setState] = React.useState({ phase: "idle", record: null, error: null });
204
+ const [options, setOptions] = React.useState(null);
205
+ const aliveRef = React.useRef(true);
206
+ React.useEffect(() => {
207
+ aliveRef.current = true;
208
+ return () => {
209
+ aliveRef.current = false;
210
+ };
211
+ }, []);
212
+ const load = React.useCallback(async () => {
213
+ if (!enabled || !connection || !channelId || !botId) return;
214
+ setState((current) => ({ ...current, phase: "loading", error: null }));
215
+ try {
216
+ const result = await callControlRpc(connection, "bot.settings.get", { channelId, botId });
217
+ const value = unwrapRpc(result);
218
+ if (aliveRef.current) setState({ phase: "ready", record: value.settings, error: null });
219
+ } catch (error) {
220
+ if (aliveRef.current) setState({ phase: "error", record: null, error });
221
+ }
222
+ }, [connection, channelId, botId, enabled]);
223
+ React.useEffect(() => {
224
+ void load();
225
+ }, [load]);
226
+ const loadOptions = React.useCallback(async () => {
227
+ if (!enabled || !connection || !channelId || !botId) return null;
228
+ try {
229
+ const result = await callControlRpc(connection, "bot.settings.options", { channelId, botId });
230
+ const value = unwrapRpc(result);
231
+ if (aliveRef.current) setOptions(value);
232
+ return value;
233
+ } catch {
234
+ if (aliveRef.current) setOptions({ workspacePaths: [], presets: [] });
235
+ return null;
236
+ }
237
+ }, [connection, channelId, botId, enabled]);
238
+ const saveContextEnhancement = React.useCallback(async (config) => {
239
+ const result = await callControlRpc(connection, "bot.context-enhancement.set", {
240
+ channelId,
241
+ botId,
242
+ config
243
+ });
244
+ const value = unwrapRpc(result);
245
+ if (aliveRef.current) {
246
+ setState((current) => ({
247
+ ...current,
248
+ phase: "ready",
249
+ record: { ...current.record ?? {}, contextEnhancement: value.contextEnhancement }
250
+ }));
251
+ }
252
+ return value.contextEnhancement;
253
+ }, [connection, channelId, botId]);
254
+ const saveField = React.useCallback(async (method, body, key) => {
255
+ const result = await callControlRpc(connection, method, { channelId, botId, ...body });
256
+ const value = unwrapRpc(result);
257
+ if (aliveRef.current) {
258
+ setState((current) => ({
259
+ ...current,
260
+ phase: "ready",
261
+ record: { ...current.record ?? {}, [key]: value[key] ?? null }
262
+ }));
263
+ }
264
+ return value[key] ?? null;
265
+ }, [connection, channelId, botId]);
266
+ const saveWorkspace = React.useCallback(
267
+ (workspace) => saveField("bot.workspace.set", { workspace }, "workspace"),
268
+ [saveField]
269
+ );
270
+ const saveAgentPreset = React.useCallback(
271
+ (agentPreset) => saveField("bot.agent-preset.set", { agentPreset }, "agentPreset"),
272
+ [saveField]
273
+ );
274
+ const saveAccessPolicy = React.useCallback(
275
+ (policy) => saveField("bot.access-policy.set", { policy }, "accessPolicy"),
276
+ [saveField]
277
+ );
278
+ const saveModel = React.useCallback(
279
+ (model) => saveField("bot.model.set", { model }, "model"),
280
+ [saveField]
281
+ );
282
+ const savePanelSections = React.useCallback(
283
+ (sections) => saveField("bot.panel-sections.set", { sections }, "panelSections"),
284
+ [saveField]
285
+ );
286
+ return {
287
+ record: state.record,
288
+ phase: state.phase,
289
+ error: state.error,
290
+ options,
291
+ loadOptions,
292
+ reload: load,
293
+ saveContextEnhancement,
294
+ saveWorkspace,
295
+ saveAgentPreset,
296
+ saveAccessPolicy,
297
+ saveModel,
298
+ savePanelSections
299
+ };
300
+ }
301
+ function useConversations({ connection, channelId, botId, enabled = true }) {
302
+ const [state, setState] = React.useState({ phase: "idle", conversations: [], error: null });
303
+ const aliveRef = React.useRef(true);
304
+ React.useEffect(() => {
305
+ aliveRef.current = true;
306
+ return () => {
307
+ aliveRef.current = false;
308
+ };
309
+ }, []);
310
+ const load = React.useCallback(async () => {
311
+ if (!enabled || !connection || !channelId || !botId) return;
312
+ setState((current) => ({ ...current, phase: "loading" }));
313
+ try {
314
+ const result = await callControlRpc(connection, "bot.conversations", { channelId, botId });
315
+ const value = unwrapRpc(result);
316
+ if (aliveRef.current) {
317
+ setState({ phase: "ready", conversations: value.conversations ?? [], error: null });
318
+ }
319
+ } catch (error) {
320
+ if (aliveRef.current) setState({ phase: "error", conversations: [], error });
321
+ }
322
+ }, [connection, channelId, botId, enabled]);
323
+ React.useEffect(() => {
324
+ void load();
325
+ }, [load]);
326
+ return { ...state, reload: load };
327
+ }
328
+
329
+ // packages/dsh-chat/client/bot-shared-settings.js
330
+ var React2 = __toESM(require("react"), 1);
331
+
332
+ // packages/dsh-chat/shared/access-policy.mjs
333
+ var ACCESS_POLICY_MODES = Object.freeze(["open", "allowlist"]);
334
+ var ACCESS_CONVERSATION_TYPES = Object.freeze(["direct", "group"]);
335
+ var USER_ID_MAX_LENGTH = 256;
336
+ var CONTROL_CHARACTERS = /[\u0000-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/g;
337
+ var ACCESS_RESULTS = Object.freeze({
338
+ OWNER: "owner",
339
+ OPEN: "open",
340
+ ALLOWLIST: "allowlist",
341
+ NOT_LISTED: "sender-not-allowed",
342
+ COMMAND_DENIED: "command-not-allowed",
343
+ NO_POLICY: "no-policy",
344
+ INVALID: "invalid-context"
345
+ });
346
+ function invalid(message) {
347
+ const error = new TypeError(message);
348
+ error.code = "access-policy-invalid";
349
+ return error;
350
+ }
351
+ function isPlainObject2(value) {
352
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
353
+ const prototype = Object.getPrototypeOf(value);
354
+ return prototype === Object.prototype || prototype === null;
355
+ }
356
+ function hasExactKeys(input, keys) {
357
+ return isPlainObject2(input) && Reflect.ownKeys(input).length === keys.length && keys.every((key) => Object.hasOwn(input, key));
358
+ }
359
+ function normalizeUserId(value) {
360
+ if (typeof value === "number" && Number.isFinite(value)) value = String(value);
361
+ if (typeof value !== "string") throw invalid("\u7528\u6237\u6807\u8BC6\u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u3002");
362
+ const normalized = value.replace(CONTROL_CHARACTERS, "").trim();
363
+ if (!normalized || normalized.length > USER_ID_MAX_LENGTH) throw invalid("\u7528\u6237\u6807\u8BC6\u65E0\u6548\u3002");
364
+ return normalized;
365
+ }
366
+ function validateUser(input) {
367
+ if (!hasExactKeys(input, ["id", "canExecuteCommands"])) throw invalid("\u767D\u540D\u5355\u6761\u76EE\u683C\u5F0F\u4E0D\u6B63\u786E\u3002");
368
+ if (typeof input.canExecuteCommands !== "boolean") throw invalid("\u547D\u4EE4\u6743\u9650\u5FC5\u987B\u662F\u5E03\u5C14\u503C\u3002");
369
+ return Object.freeze({
370
+ id: normalizeUserId(input.id),
371
+ canExecuteCommands: input.canExecuteCommands
372
+ });
373
+ }
374
+ function validateScope(input) {
375
+ if (!hasExactKeys(input, ["mode", "open", "allowlist"])) throw invalid("\u8BBF\u95EE\u7B56\u7565\u7F3A\u5C11\u5B57\u6BB5\u3002");
376
+ if (!ACCESS_POLICY_MODES.includes(input.mode)) throw invalid("\u8BBF\u95EE\u6A21\u5F0F\u53EA\u80FD\u662F open \u6216 allowlist\u3002");
377
+ if (!hasExactKeys(input.open, ["defaultCanExecuteCommands", "commandPermissionOverrides"])) {
378
+ throw invalid("open \u6BB5\u683C\u5F0F\u4E0D\u6B63\u786E\u3002");
379
+ }
380
+ if (typeof input.open.defaultCanExecuteCommands !== "boolean") {
381
+ throw invalid("\u9ED8\u8BA4\u547D\u4EE4\u6743\u9650\u5FC5\u987B\u662F\u5E03\u5C14\u503C\u3002");
382
+ }
383
+ if (!Array.isArray(input.open.commandPermissionOverrides) || !Array.isArray(input.allowlist?.users)) {
384
+ throw invalid("\u8BBF\u95EE\u7B56\u7565\u7684\u540D\u5355\u5FC5\u987B\u662F\u6570\u7EC4\u3002");
385
+ }
386
+ return Object.freeze({
387
+ mode: input.mode,
388
+ open: Object.freeze({
389
+ defaultCanExecuteCommands: input.open.defaultCanExecuteCommands,
390
+ commandPermissionOverrides: Object.freeze(input.open.commandPermissionOverrides.map(validateUser))
391
+ }),
392
+ allowlist: Object.freeze({ users: Object.freeze(input.allowlist.users.map(validateUser)) })
393
+ });
394
+ }
395
+ function validateAccessPolicy(input) {
396
+ if (!hasExactKeys(input, ["direct", "group"])) throw invalid("\u8BF7\u63D0\u4EA4\u5B8C\u6574\u7684\u8BBF\u95EE\u7B56\u7565\u3002");
397
+ return Object.freeze({
398
+ direct: validateScope(input.direct),
399
+ group: validateScope(input.group)
400
+ });
401
+ }
402
+ function defaultAccessPolicy() {
403
+ const scope = () => ({
404
+ mode: "allowlist",
405
+ open: { defaultCanExecuteCommands: false, commandPermissionOverrides: [] },
406
+ allowlist: { users: [] }
407
+ });
408
+ return validateAccessPolicy({ direct: scope(), group: scope() });
409
+ }
410
+
411
+ // packages/dsh-chat/shared/panel-sections.mjs
412
+ var PANEL_SECTIONS = Object.freeze([
413
+ "model",
414
+ "session",
415
+ "preset",
416
+ "context",
417
+ "policy",
418
+ "fields",
419
+ "actions",
420
+ "commands"
421
+ ]);
422
+ var PANEL_SCOPES = Object.freeze(["direct", "group"]);
423
+ function normalizePanelSections(input) {
424
+ const source = input && typeof input === "object" && !Array.isArray(input) ? input : {};
425
+ const scopeOf = (value) => {
426
+ const raw = value && typeof value === "object" && !Array.isArray(value) ? value : {};
427
+ return Object.fromEntries(
428
+ PANEL_SECTIONS.map((id) => [id, raw[id] !== false])
429
+ );
430
+ };
431
+ return { direct: scopeOf(source.direct), group: scopeOf(source.group) };
432
+ }
433
+
434
+ // packages/dsh-chat/client/bot-shared-settings.js
435
+ var h = React2.createElement;
436
+ function translatorOf(translate) {
437
+ return typeof translate === "function" ? translate : (key) => key;
438
+ }
439
+ function Card({ title, description, actions, children }) {
440
+ return h(
441
+ "section",
442
+ { className: "dchat-card" },
443
+ h(
444
+ "div",
445
+ { className: "dchat-cardHeader" },
446
+ h(
447
+ "div",
448
+ { className: "dchat-cardHeading" },
449
+ h("h3", { className: "dchat-cardTitle" }, title),
450
+ description ? h("p", { className: "dchat-cardDescription" }, description) : null
451
+ ),
452
+ actions ? h("div", { className: "dchat-actions" }, actions) : null
453
+ ),
454
+ children
455
+ );
456
+ }
457
+ function useSaver(onSave) {
458
+ const [busy, setBusy] = React2.useState(false);
459
+ const [failed, setFailed] = React2.useState(null);
460
+ const run = React2.useCallback(async (next) => {
461
+ setBusy(true);
462
+ setFailed(null);
463
+ try {
464
+ await onSave(next);
465
+ return true;
466
+ } catch (error) {
467
+ setFailed(error?.message ?? String(error));
468
+ return false;
469
+ } finally {
470
+ setBusy(false);
471
+ }
472
+ }, [onSave]);
473
+ return { busy, failed, run };
474
+ }
475
+ function WorkspaceEditor({ value, options = [], translate, onSave }) {
476
+ const t = translatorOf(translate);
477
+ const [draft, setDraft] = React2.useState(value ?? "");
478
+ const { busy, failed, run } = useSaver(onSave);
479
+ const fieldId = React2.useId?.() ?? "dchat-workspace";
480
+ React2.useEffect(() => {
481
+ setDraft(value ?? "");
482
+ }, [value]);
483
+ const dirty = (draft ?? "").trim() !== (value ?? "");
484
+ return h(
485
+ Card,
486
+ {
487
+ title: t("\u5DE5\u4F5C\u533A"),
488
+ description: t("\u673A\u5668\u4EBA\u8DD1\u5728\u54EA\u4E2A\u76EE\u5F55\uFF1A\u80FD\u8BFB\u5199\u54EA\u4E9B\u6587\u4EF6\u3001\u7528\u54EA\u4EFD AGENTS.md\u3002\u53EA\u5BF9\u65B0\u5EFA\u4F1A\u8BDD\u751F\u6548\u3002"),
489
+ actions: h("button", {
490
+ type: "button",
491
+ className: "dchat-button",
492
+ disabled: busy || !dirty,
493
+ onClick: () => {
494
+ void run(draft.trim());
495
+ }
496
+ }, busy ? t("\u4FDD\u5B58\u4E2D\u2026") : t("\u4FDD\u5B58"))
497
+ },
498
+ h(
499
+ "div",
500
+ { className: "dchat-scopeGrid" },
501
+ h(
502
+ "div",
503
+ { className: "dchat-scopeRow" },
504
+ h("label", { className: "dchat-scopeLabel", htmlFor: fieldId }, t("\u76EE\u5F55")),
505
+ h("input", {
506
+ id: fieldId,
507
+ className: "dchat-input",
508
+ list: `${fieldId}-options`,
509
+ value: draft,
510
+ disabled: busy,
511
+ placeholder: "/Users/me/project",
512
+ autoComplete: "off",
513
+ spellCheck: false,
514
+ onChange: (event) => setDraft(event.target.value)
515
+ }),
516
+ h(
517
+ "datalist",
518
+ { id: `${fieldId}-options` },
519
+ options.map((path) => h("option", { key: path, value: path }))
520
+ ),
521
+ options.length > 0 ? h("p", { className: "dchat-cardDescription" }, t("\u4E0B\u62C9\u91CC\u662F\u8FD9\u53F0\u673A\u5668\u4EBA\u7528\u8FC7\u7684\u76EE\u5F55\u3002")) : null
522
+ )
523
+ ),
524
+ failed ? h("p", { className: "dchat-error", role: "alert" }, failed) : null
525
+ );
526
+ }
527
+ function PresetEditor({ value, options = [], translate, onSave }) {
528
+ const t = translatorOf(translate);
529
+ const { busy, failed, run } = useSaver(onSave);
530
+ return h(
531
+ Card,
532
+ {
533
+ title: t("Agent \u9884\u8BBE"),
534
+ description: t("\u8FD9\u4E2A\u673A\u5668\u4EBA\u7528\u54EA\u5957 Agent \u9884\u8BBE\uFF08\u4EBA\u8BBE\u4E0E\u5DE5\u5177\u96C6\uFF09\u3002\u53EA\u5BF9\u65B0\u5EFA\u4F1A\u8BDD\u751F\u6548\u3002"),
535
+ actions: busy ? h("span", { className: "dchat-status" }, t("\u4FDD\u5B58\u4E2D\u2026")) : null
536
+ },
537
+ options.length === 0 ? h("p", { className: "dchat-cardDescription" }, t("\u5F53\u524D Host \u8BFB\u4E0D\u5230 Agent Preset \u5217\u8868\u3002")) : h(
538
+ "div",
539
+ { className: "dchat-scopeGrid" },
540
+ h(
541
+ "div",
542
+ { className: "dchat-scopeRow" },
543
+ h(
544
+ "select",
545
+ {
546
+ className: "dchat-select",
547
+ value: value ?? "",
548
+ disabled: busy,
549
+ "aria-label": t("Agent \u9884\u8BBE"),
550
+ onChange: (event) => {
551
+ void run(event.target.value || null);
552
+ }
553
+ },
554
+ h("option", { value: "" }, t("\u8DDF\u968F Host \u9ED8\u8BA4")),
555
+ options.map((row) => h(
556
+ "option",
557
+ { key: row.id, value: row.id },
558
+ `${row.id}${row.name && row.name !== row.id ? ` \xB7 ${row.name}` : ""}`
559
+ ))
560
+ )
561
+ )
562
+ ),
563
+ failed ? h("p", { className: "dchat-error", role: "alert" }, failed) : null
564
+ );
565
+ }
566
+ function ModelEditor({ value, options = [], hostDefault = null, failures = [], translate, onSave }) {
567
+ const t = translatorOf(translate);
568
+ const { busy, failed, run } = useSaver(onSave);
569
+ const current = value ?? null;
570
+ const selected = current ? options.find((item) => item.provider === current.provider && item.model === current.model) ?? null : null;
571
+ const effortOptions = selected?.efforts ?? [];
572
+ const hostText = hostDefault ? `${hostDefault.provider}/${hostDefault.model}` : null;
573
+ const save = (patch) => {
574
+ if (patch === null) {
575
+ void run(null);
576
+ return;
577
+ }
578
+ const provider = patch.provider ?? current?.provider ?? "";
579
+ const model = patch.model ?? current?.model ?? "";
580
+ const reasoningEffort = Object.hasOwn(patch, "reasoningEffort") ? patch.reasoningEffort : current?.reasoningEffort ?? null;
581
+ void run({ provider, model, reasoningEffort: reasoningEffort || null });
582
+ };
583
+ const modelSelect = h(
584
+ "div",
585
+ { className: "dchat-scopeRow" },
586
+ h("label", { className: "dchat-scopeLabel" }, t("\u6A21\u578B")),
587
+ h(
588
+ "select",
589
+ {
590
+ className: "dchat-select",
591
+ value: selected?.value ?? "",
592
+ disabled: busy,
593
+ "aria-label": t("\u9ED8\u8BA4\u6A21\u578B"),
594
+ onChange: (event) => {
595
+ const next = options.find((item) => item.value === event.target.value);
596
+ if (!next) {
597
+ save(null);
598
+ return;
599
+ }
600
+ save({ provider: next.provider, model: next.model, reasoningEffort: null });
601
+ }
602
+ },
603
+ h("option", { value: "" }, hostText ? `${t("\u8DDF\u968F Host \u9ED8\u8BA4")}\uFF08${hostText}\uFF09` : t("\u8DDF\u968F Host \u9ED8\u8BA4")),
604
+ options.map((item) => h(
605
+ "option",
606
+ { key: item.value, value: item.value },
607
+ `${item.value}${item.name && item.name !== item.model ? ` \xB7 ${item.name}` : ""}`
608
+ ))
609
+ )
610
+ );
611
+ const effortSelect = h(
612
+ "div",
613
+ { className: "dchat-scopeRow" },
614
+ h("label", { className: "dchat-scopeLabel" }, t("\u63A8\u7406\u7B49\u7EA7")),
615
+ effortOptions.length === 0 ? h(
616
+ "p",
617
+ { className: "dchat-cardDescription" },
618
+ current ? t("\u8FD9\u4E2A\u6A21\u578B\u6CA1\u6709\u53EF\u9009\u7684\u63A8\u7406\u7B49\u7EA7\u3002") : t("\u5148\u9009\u4E00\u4E2A\u6A21\u578B\u3002")
619
+ ) : h(
620
+ "select",
621
+ {
622
+ className: "dchat-select",
623
+ value: current?.reasoningEffort ?? "",
624
+ disabled: busy,
625
+ "aria-label": t("\u63A8\u7406\u7B49\u7EA7"),
626
+ onChange: (event) => {
627
+ save({ reasoningEffort: event.target.value || null });
628
+ }
629
+ },
630
+ h("option", { value: "" }, t("\u6A21\u578B\u9ED8\u8BA4")),
631
+ effortOptions.map((effort) => h(
632
+ "option",
633
+ { key: effort.id, value: effort.id },
634
+ `${effort.id}${effort.label && effort.label !== effort.id ? ` \xB7 ${effort.label}` : ""}`
635
+ ))
636
+ )
637
+ );
638
+ const failureNote = failures.length > 0 ? h("p", { className: "dchat-cardDescription" }, t("\u90E8\u5206 provider \u8BFB\u53D6\u5931\u8D25\uFF1A") + failures.map((item) => `${item.id || item.name}\uFF08${item.message}\uFF09`).join("\uFF1B")) : null;
639
+ const body = options.length === 0 ? h("p", { className: "dchat-cardDescription" }, t("\u5F53\u524D Host \u8BFB\u4E0D\u5230\u6A21\u578B\u76EE\u5F55\u3002")) : h("div", { className: "dchat-scopeGrid" }, modelSelect, effortSelect);
640
+ return h(
641
+ Card,
642
+ {
643
+ title: t("\u9ED8\u8BA4\u6A21\u578B"),
644
+ description: t("\u8FD8\u6CA1\u6709\u4F1A\u8BDD\u65F6\u7528\u54EA\u4E2A\u6A21\u578B\uFF1A\u9009\u5B8C\u5BF9\u4E0B\u4E00\u6761\u6D88\u606F\u65B0\u5EFA\u7684\u4F1A\u8BDD\u751F\u6548\u3002\u4F1A\u8BDD\u5185\u8FD8\u80FD\u5355\u72EC\u6539\uFF08\u9762\u677F\u7684\u6A21\u578B\u4E0B\u62C9\uFF09\u3002"),
645
+ actions: busy ? h("span", { className: "dchat-status" }, t("\u4FDD\u5B58\u4E2D\u2026")) : null
646
+ },
647
+ failureNote,
648
+ body,
649
+ failed ? h("p", { className: "dchat-error", role: "alert" }, failed) : null
650
+ );
651
+ }
652
+ function toDraft(value) {
653
+ const base = value ?? defaultAccessPolicy();
654
+ const scopeOf = (scope) => ({
655
+ mode: scope?.mode === "open" ? "open" : "allowlist",
656
+ defaultCanExecuteCommands: scope?.open?.defaultCanExecuteCommands === true,
657
+ // 不在界面上编辑,但必须原样带回去,否则保存一次就把已有例外清空了。
658
+ commandPermissionOverrides: Array.isArray(scope?.open?.commandPermissionOverrides) ? scope.open.commandPermissionOverrides : [],
659
+ users: Array.isArray(scope?.allowlist?.users) ? scope.allowlist.users : []
660
+ });
661
+ return { direct: scopeOf(base.direct), group: scopeOf(base.group) };
662
+ }
663
+ function fromDraft(draft) {
664
+ const scopeOf = (scope) => ({
665
+ mode: scope.mode,
666
+ open: {
667
+ defaultCanExecuteCommands: scope.defaultCanExecuteCommands,
668
+ commandPermissionOverrides: scope.commandPermissionOverrides
669
+ },
670
+ allowlist: { users: scope.users }
671
+ });
672
+ return { direct: scopeOf(draft.direct), group: scopeOf(draft.group) };
673
+ }
674
+ function ScopeBlock({ scopeKey, label, scope, busy, t, onChange, names = null }) {
675
+ const [entry, setEntry] = React2.useState("");
676
+ const inputId = `dchat-policy-${scopeKey}`;
677
+ const nameOf = (id) => names?.[id] ?? null;
678
+ const update = (patch) => onChange({ ...scope, ...patch });
679
+ const addUser = () => {
680
+ const id = entry.trim();
681
+ if (!id) return;
682
+ setEntry("");
683
+ if (scope.users.some((user) => user.id === id)) return;
684
+ update({ users: [...scope.users, { id, canExecuteCommands: false }] });
685
+ };
686
+ const allowlist = h(
687
+ React2.Fragment,
688
+ null,
689
+ scope.users.length > 0 ? h("ul", { className: "dchat-list" }, scope.users.map((user) => h(
690
+ "li",
691
+ {
692
+ key: user.id,
693
+ className: "dchat-listItem"
694
+ },
695
+ // 名字 + id:只显示 id 时,"这条是谁"在设置页上根本认不出来(真机反馈);
696
+ // 但 id 才是判定用的那个值,所以两个都留(与「属主」那一行同一个形态)。
697
+ h(
698
+ "span",
699
+ { className: "dchat-policyEntry" },
700
+ nameOf(user.id) ? h("span", { className: "dchat-policyName" }, nameOf(user.id)) : null,
701
+ h("code", { className: "dchat-code" }, user.id)
702
+ ),
703
+ h(
704
+ "span",
705
+ { className: "dchat-actions" },
706
+ h(
707
+ "label",
708
+ { className: "dchat-check" },
709
+ h("input", {
710
+ type: "checkbox",
711
+ checked: user.canExecuteCommands === true,
712
+ disabled: busy,
713
+ onChange: (event) => update({
714
+ users: scope.users.map((item) => item.id === user.id ? { ...item, canExecuteCommands: event.target.checked } : item)
715
+ })
716
+ }),
717
+ h("span", null, t("\u53EF\u6267\u884C\u547D\u4EE4"))
718
+ ),
719
+ h("button", {
720
+ type: "button",
721
+ className: "dchat-button dchat-buttonDanger",
722
+ disabled: busy,
723
+ onClick: () => update({ users: scope.users.filter((item) => item.id !== user.id) })
724
+ }, t("\u79FB\u9664"))
725
+ )
726
+ ))) : h("p", { className: "dchat-cardDescription" }, t("\u540D\u5355\u4E3A\u7A7A\u65F6\u53EA\u6709\u5C5E\u4E3B\u53EF\u7528\u3002")),
727
+ h(
728
+ "div",
729
+ { className: "dchat-actions" },
730
+ h("input", {
731
+ id: inputId,
732
+ className: "dchat-input",
733
+ value: entry,
734
+ disabled: busy,
735
+ placeholder: t("\u5BF9\u65B9\u7684\u5E73\u53F0 id\uFF0C\u56DE\u8F66\u6DFB\u52A0"),
736
+ autoComplete: "off",
737
+ spellCheck: false,
738
+ onChange: (event) => setEntry(event.target.value),
739
+ onKeyDown: (event) => {
740
+ if (event.key !== "Enter") return;
741
+ event.preventDefault();
742
+ addUser();
743
+ }
744
+ }),
745
+ h("button", {
746
+ type: "button",
747
+ className: "dchat-button",
748
+ disabled: busy || !entry.trim(),
749
+ onClick: addUser
750
+ }, t("\u6DFB\u52A0"))
751
+ )
752
+ );
753
+ const openScope = h(
754
+ "label",
755
+ { className: "dchat-check" },
756
+ h("input", {
757
+ type: "checkbox",
758
+ checked: scope.defaultCanExecuteCommands,
759
+ disabled: busy,
760
+ onChange: (event) => update({ defaultCanExecuteCommands: event.target.checked })
761
+ }),
762
+ h("span", null, t("\u5141\u8BB8\u6267\u884C\u547D\u4EE4"))
763
+ );
764
+ return h(
765
+ "div",
766
+ { className: "dchat-scopeRow" },
767
+ h(
768
+ "div",
769
+ { className: "dchat-policyHead" },
770
+ h("label", { className: "dchat-scopeLabel", htmlFor: inputId }, label),
771
+ h(
772
+ "select",
773
+ {
774
+ className: "dchat-select",
775
+ value: scope.mode,
776
+ disabled: busy,
777
+ "aria-label": `${label} ${t("\u8BBF\u95EE\u6A21\u5F0F")}`,
778
+ onChange: (event) => update({ mode: event.target.value })
779
+ },
780
+ h("option", { value: "allowlist" }, t("\u4EC5\u540D\u5355\u5185\u53EF\u7528")),
781
+ h("option", { value: "open" }, t("\u4EFB\u4F55\u4EBA\u53EF\u7528"))
782
+ )
783
+ ),
784
+ scope.mode === "open" ? openScope : allowlist
785
+ );
786
+ }
787
+ function AccessPolicyEditor({ value, translate, onSave, names = null, namesHint = null }) {
788
+ const t = translatorOf(translate);
789
+ const [draft, setDraft] = React2.useState(() => toDraft(value));
790
+ const { busy, failed, run } = useSaver(onSave);
791
+ React2.useEffect(() => {
792
+ setDraft(toDraft(value));
793
+ }, [value]);
794
+ const commit = React2.useCallback(async (next) => {
795
+ setDraft(next);
796
+ const saved = await run(fromDraft(next));
797
+ if (!saved) setDraft(toDraft(value));
798
+ }, [run, value]);
799
+ return h(
800
+ Card,
801
+ {
802
+ title: t("\u8BBF\u95EE\u7B56\u7565"),
803
+ description: t("\u8C01\u80FD\u8DDF\u673A\u5668\u4EBA\u8BF4\u8BDD\u3001\u8C01\u80FD\u6267\u884C\u547D\u4EE4\u3002\u6539\u52A8\u7ACB\u5373\u751F\u6548\uFF1B\u5C5E\u4E3B\u59CB\u7EC8\u53EF\u7528\u3002"),
804
+ actions: busy ? h("span", { className: "dchat-status" }, t("\u4FDD\u5B58\u4E2D\u2026")) : null
805
+ },
806
+ h(
807
+ "div",
808
+ { className: "dchat-policyGrid" },
809
+ h(ScopeBlock, {
810
+ scopeKey: "direct",
811
+ label: t("\u79C1\u804A"),
812
+ scope: draft.direct,
813
+ busy,
814
+ t,
815
+ names,
816
+ onChange: (next) => {
817
+ void commit({ ...draft, direct: next });
818
+ }
819
+ }),
820
+ h(ScopeBlock, {
821
+ scopeKey: "group",
822
+ label: t("\u7FA4\u804A"),
823
+ scope: draft.group,
824
+ busy,
825
+ t,
826
+ names,
827
+ onChange: (next) => {
828
+ void commit({ ...draft, group: next });
829
+ }
830
+ })
831
+ ),
832
+ namesHint ? h("p", { className: "dchat-cardDescription" }, namesHint.message ?? String(namesHint)) : null,
833
+ failed ? h("p", { className: "dchat-error", role: "alert" }, failed) : null
834
+ );
835
+ }
836
+ function OwnerEditor({ owners = [], wildcard = false, candidates = [], translate, onSave }) {
837
+ const t = translatorOf(translate);
838
+ const [picked, setPicked] = React2.useState("");
839
+ const { busy, failed, run } = useSaver(onSave);
840
+ const nameOf = (id) => candidates.find((item) => item.id === id)?.name ?? null;
841
+ const people = candidates.filter((item) => !owners.includes(item.id));
842
+ return h(
843
+ Card,
844
+ {
845
+ title: t("\u5C5E\u4E3B"),
846
+ description: t("\u5C5E\u4E3B\u4E0D\u9700\u8981\u8FDB\u767D\u540D\u5355\uFF1A\u6D88\u606F\u4E0E\u547D\u4EE4\u90FD\u76F4\u63A5\u653E\u884C\u3002\u8FD9\u91CC\u6539\u5B8C\u4F1A\u91CD\u8FDE\u4E00\u6B21\uFF0C\u7ACB\u523B\u751F\u6548\u3002"),
847
+ actions: busy ? h("span", { className: "dchat-status" }, t("\u4FDD\u5B58\u4E2D\u2026")) : null
848
+ },
849
+ h(
850
+ "div",
851
+ { className: "dchat-scopeGrid" },
852
+ wildcard || owners.length === 0 ? h("p", { className: "dchat-cardDescription" }, t("\u5F53\u524D\u6CA1\u6709\u5C5E\u4E3B\uFF1A\u6CA1\u6709\u4EBA\u7ED5\u8FC7\u8BBF\u95EE\u7B56\u7565\uFF0C\u8C01\u80FD\u7528\u5B8C\u5168\u7531\u4E0B\u9762\u7684\u300C\u8BBF\u95EE\u7B56\u7565\u300D\u51B3\u5B9A\u3002")) : h("ul", { className: "dchat-list" }, owners.map((id) => h(
853
+ "li",
854
+ {
855
+ key: id,
856
+ className: "dchat-listItem"
857
+ },
858
+ // 名字 + id:id 用等宽块(可省略号),避免一行被 35 字符的 open_id 撑爆。
859
+ h(
860
+ "span",
861
+ null,
862
+ nameOf(id) ? `${nameOf(id)} ` : null,
863
+ h("code", { className: "dchat-code" }, id)
864
+ ),
865
+ h(
866
+ "span",
867
+ { className: "dchat-actions" },
868
+ h("button", {
869
+ type: "button",
870
+ className: "dchat-button dchat-buttonDanger",
871
+ disabled: busy,
872
+ onClick: () => {
873
+ void run([...owners.filter((item) => item !== id)]);
874
+ }
875
+ }, t("\u79FB\u9664"))
876
+ )
877
+ ))),
878
+ h(
879
+ "div",
880
+ { className: "dchat-actions" },
881
+ h(
882
+ "select",
883
+ {
884
+ className: "dchat-select",
885
+ value: picked,
886
+ disabled: busy || people.length === 0,
887
+ "aria-label": t("\u4ECE\u4F1A\u8BDD\u91CC\u9009\u4E00\u4E2A\u4EBA\u8BBE\u4E3A\u5C5E\u4E3B"),
888
+ onChange: (event) => setPicked(event.target.value)
889
+ },
890
+ h(
891
+ "option",
892
+ { value: "" },
893
+ people.length === 0 ? t("\u6CA1\u6709\u53EF\u9009\u7684\u4F1A\u8BDD\uFF08\u5148\u548C\u673A\u5668\u4EBA\u804A\u4E00\u6B21\uFF09") : t("\u4ECE\u4F1A\u8BDD\u91CC\u9009\u4E00\u4E2A\u4EBA\u8BBE\u4E3A\u5C5E\u4E3B")
894
+ ),
895
+ people.map((item) => h("option", { key: item.id, value: item.id }, item.name))
896
+ ),
897
+ h("button", {
898
+ type: "button",
899
+ className: "dchat-button",
900
+ disabled: busy || !picked,
901
+ onClick: () => {
902
+ setPicked("");
903
+ void run([...owners.filter((item) => item !== "*"), picked]);
904
+ }
905
+ }, t("\u8BBE\u4E3A\u5C5E\u4E3B")),
906
+ h("button", {
907
+ type: "button",
908
+ className: "dchat-button",
909
+ disabled: busy || wildcard && owners.length === 1,
910
+ title: t("\u6E05\u7A7A\u540E\u6CA1\u6709\u4EBA\u7ED5\u8FC7\u8BBF\u95EE\u7B56\u7565"),
911
+ onClick: () => {
912
+ void run(["*"]);
913
+ }
914
+ }, t("\u6E05\u7A7A\uFF08\u65E0\u5C5E\u4E3B\uFF09"))
915
+ )
916
+ ),
917
+ failed ? h("p", { className: "dchat-error", role: "alert" }, failed) : null
918
+ );
919
+ }
920
+ var PANEL_SECTION_LABELS = Object.freeze({
921
+ model: "\u6A21\u578B\u4E0E\u63A8\u7406\u7B49\u7EA7",
922
+ session: "\u4F1A\u8BDD",
923
+ preset: "Agent \u9884\u8BBE\u4E0E\u5DE5\u4F5C\u533A",
924
+ context: "\u4E0A\u4E0B\u6587\u589E\u5F3A\uFF08\u672C\u4F1A\u8BDD\uFF09",
925
+ policy: "\u8BBF\u95EE\u7B56\u7565\uFF08\u672C\u4F1A\u8BDD\uFF09",
926
+ fields: "\u6E20\u9053\u8BBE\u7F6E\uFF08\u4EFB\u52A1\u8FC7\u7A0B\u5C55\u793A\u7B49\uFF09",
927
+ actions: "\u6E20\u9053\u52A8\u4F5C\u6309\u94AE\uFF08\u91CD\u8FDE\u7B49\uFF09",
928
+ commands: "\u547D\u4EE4\u6309\u94AE\uFF08\u65B0\u4F1A\u8BDD/\u72B6\u6001/\u8BCA\u65AD\u2026\uFF09"
929
+ });
930
+ function PanelSectionsEditor({
931
+ value = null,
932
+ disabled = false,
933
+ saving = false,
934
+ error = null,
935
+ translate,
936
+ onSave
937
+ }) {
938
+ const t = translatorOf(translate);
939
+ const sections = PANEL_SECTIONS;
940
+ const scopes = [{ key: "direct", label: "\u79C1\u804A" }, { key: "group", label: "\u7FA4\u804A" }];
941
+ const [draft, setDraft] = React2.useState(() => normalizePanelSections(value));
942
+ const [pending, setPending] = React2.useState(null);
943
+ const [failed, setFailed] = React2.useState(null);
944
+ const locked = disabled || saving || pending !== null;
945
+ React2.useEffect(() => {
946
+ if (pending !== null) return;
947
+ setDraft((current) => JSON.stringify(current) === JSON.stringify(normalizePanelSections(value)) ? current : normalizePanelSections(value));
948
+ }, [value, pending]);
949
+ const toggle = async (scopeKey, sectionId, nextChecked) => {
950
+ if (locked) return;
951
+ const next = {
952
+ ...draft,
953
+ [scopeKey]: { ...draft[scopeKey], [sectionId]: nextChecked }
954
+ };
955
+ setDraft(next);
956
+ setFailed(null);
957
+ setPending(`${scopeKey}:${sectionId}`);
958
+ try {
959
+ await onSave(next);
960
+ } catch (cause) {
961
+ setDraft(normalizePanelSections(value));
962
+ setFailed(cause?.message ?? String(cause));
963
+ } finally {
964
+ setPending(null);
965
+ }
966
+ };
967
+ const header = h(
968
+ "div",
969
+ { className: "dchat-panelSectionsHead" },
970
+ h("span", { className: "dchat-scopeLabel" }, t("\u663E\u793A\u9879")),
971
+ scopes.map((scope) => h("span", {
972
+ key: scope.key,
973
+ className: "dchat-scopeLabel"
974
+ }, t(scope.label)))
975
+ );
976
+ const rows = sections.map((sectionId) => h(
977
+ "div",
978
+ {
979
+ key: sectionId,
980
+ className: "dchat-panelSectionsRow"
981
+ },
982
+ h("span", { className: "dchat-panelSectionsName" }, t(PANEL_SECTION_LABELS[sectionId])),
983
+ scopes.map((scope) => h("label", {
984
+ key: scope.key,
985
+ className: "dchat-panelSectionsCheck",
986
+ title: `${t(PANEL_SECTION_LABELS[sectionId])} \xB7 ${t(scope.label)}`
987
+ }, h("input", {
988
+ type: "checkbox",
989
+ checked: draft[scope.key]?.[sectionId] !== false,
990
+ disabled: locked,
991
+ "aria-label": `${t(PANEL_SECTION_LABELS[sectionId])} \xB7 ${t(scope.label)}`,
992
+ onChange: (event) => {
993
+ void toggle(scope.key, sectionId, event.target.checked);
994
+ }
995
+ })))
996
+ ));
997
+ return h(
998
+ Card,
999
+ {
1000
+ title: t("\u63A7\u5236\u9762\u677F\u663E\u793A\u9879"),
1001
+ description: t("\u53EA\u5F71\u54CD /menu \u53D1\u51FA\u6765\u7684\u90A3\u5F20\u5361\u7247\uFF1A\u5173\u6389\u7684\u9879\u4E0D\u663E\u793A\uFF0C\u529F\u80FD\u7167\u65E7\uFF08\u79C1\u804A\u4E0E\u7FA4\u804A\u5206\u522B\u8BBE\u7F6E\uFF09\u3002"),
1002
+ actions: pending !== null ? h("span", { className: "dchat-status" }, t("\u4FDD\u5B58\u4E2D\u2026")) : null
1003
+ },
1004
+ h("div", { className: "dchat-panelSections" }, header, rows),
1005
+ failed || error ? h("p", { className: "dchat-error", role: "alert" }, failed ?? error) : null
1006
+ );
1007
+ }
1008
+
1009
+ // packages/dsh-chat/client/context-enhancement.js
1010
+ var React3 = __toESM(require("react"), 1);
1011
+ var import_react_dom = require("react-dom");
1012
+
1013
+ // packages/dsh-chat/shared/context-enhancement.mjs
1014
+ var CONTEXT_FIELDS = Object.freeze([
1015
+ "channel",
1016
+ "conversationType",
1017
+ "senderId",
1018
+ "senderName",
1019
+ "conversationTitle",
1020
+ "chatId",
1021
+ "threadId",
1022
+ "botId"
1023
+ ]);
1024
+ var CONTEXT_TAGS = Object.freeze({
1025
+ sourceOpen: "<dsh_im_source>",
1026
+ sourceClose: "</dsh_im_source>",
1027
+ guidanceOpen: "<dsh_im_source_guidance>",
1028
+ guidanceClose: "</dsh_im_source_guidance>"
1029
+ });
1030
+ var GUIDANCE_MAX_LENGTH = 8e3;
1031
+ var TARGET_LIMIT = 50;
1032
+ var TARGET_LABEL_MAX_LENGTH = 80;
1033
+ var TARGET_ID_MAX_LENGTH = 256;
1034
+ var TARGET_KINDS = Object.freeze(["user", "group"]);
1035
+ var TARGET_MERGES = Object.freeze(["append", "replace"]);
1036
+ var GROUP_GUIDANCE_EXAMPLE = `\u4EC5\u4F9D\u636E\u5F53\u524D\u6D88\u606F\u7684 ${CONTEXT_TAGS.sourceOpen} \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
1037
+ \u5F53\u524D\u6D88\u606F\u6765\u81EA\u7FA4\u804A\uFF0C\u8BF7\u4F7F\u7528\u4E25\u8083\u3001\u514B\u5236\u3001\u7B80\u6D01\u7684\u8868\u8FBE\u65B9\u5F0F\u3002`;
1038
+ var DIRECT_GUIDANCE_EXAMPLE = `\u4EC5\u4F9D\u636E\u5F53\u524D\u6D88\u606F\u7684 ${CONTEXT_TAGS.sourceOpen} \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
1039
+ \u5F53\u524D\u6D88\u606F\u6765\u81EA\u79C1\u804A\uFF0C\u53EF\u4EE5\u4F7F\u7528\u66F4\u8F7B\u677E\u3001\u5E7D\u9ED8\u3001\u8BE6\u7EC6\u7684\u8868\u8FBE\u65B9\u5F0F\u3002`;
1040
+ var DEFAULT_SCOPE = Object.freeze({
1041
+ enabled: false,
1042
+ fields: Object.freeze(["senderId"]),
1043
+ guidance: ""
1044
+ });
1045
+ var DEFAULT_CONTEXT_CONFIG = Object.freeze({
1046
+ group: DEFAULT_SCOPE,
1047
+ direct: DEFAULT_SCOPE,
1048
+ targets: Object.freeze([])
1049
+ });
1050
+ var CONFIG_KEYS = Object.freeze(["group", "direct", "targets"]);
1051
+ var SCOPE_KEYS = Object.freeze(["enabled", "fields", "guidance"]);
1052
+ var TARGET_KEYS = Object.freeze([
1053
+ "kind",
1054
+ "id",
1055
+ "label",
1056
+ "enabled",
1057
+ "fields",
1058
+ "guidance",
1059
+ "merge"
1060
+ ]);
1061
+ var LEGACY_KEYS = Object.freeze(["groupEnabled", "directEnabled", "fields", "guidance"]);
1062
+ var SOURCE_LIMITS = Object.freeze({
1063
+ channel: 16,
1064
+ conversationType: 6,
1065
+ senderId: 256,
1066
+ senderName: 256,
1067
+ conversationTitle: 256,
1068
+ chatId: 256,
1069
+ threadId: 256,
1070
+ botId: 128
1071
+ });
1072
+ var CONTROL_CHARACTERS2 = /[\u0000-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/g;
1073
+ var CONTROL_CHARACTER_TEST = /[\u0000-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/;
1074
+ function invalid2(message) {
1075
+ const error = new TypeError(message);
1076
+ error.code = "context-enhancement-invalid";
1077
+ return error;
1078
+ }
1079
+ function isPlainObject3(value) {
1080
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
1081
+ const prototype = Object.getPrototypeOf(value);
1082
+ return prototype === Object.prototype || prototype === null;
1083
+ }
1084
+ function hasExactKeys2(input, keys) {
1085
+ return isPlainObject3(input) && Reflect.ownKeys(input).length === keys.length && keys.every((key) => Object.hasOwn(input, key));
1086
+ }
1087
+ function offlineText(value, maxLength) {
1088
+ return typeof value === "string" ? value.replace(CONTROL_CHARACTERS2, "").slice(0, maxLength) : "";
1089
+ }
1090
+ function validateScope2(input, where) {
1091
+ if (!hasExactKeys2(input, SCOPE_KEYS)) throw invalid2(`${where}\u8BBE\u7F6E\u4E0D\u5B8C\u6574\uFF0C\u8BF7\u91CD\u65B0\u4FDD\u5B58\u3002`);
1092
+ const { enabled, fields, guidance } = input;
1093
+ if (typeof enabled !== "boolean") throw invalid2(`${where}\u7684\u542F\u7528\u5F00\u5173\u5FC5\u987B\u662F\u5E03\u5C14\u503C\u3002`);
1094
+ if (!Array.isArray(fields) || !fields.every((field) => CONTEXT_FIELDS.includes(field))) {
1095
+ throw invalid2(`${where}\u7684\u6765\u6E90\u5B57\u6BB5\u53EA\u80FD\u4ECE\u5DF2\u5B9A\u4E49\u7684\u516B\u4E2A\u5B57\u6BB5\u4E2D\u9009\u62E9\u3002`);
1096
+ }
1097
+ if (typeof guidance !== "string" || guidance.length > GUIDANCE_MAX_LENGTH) {
1098
+ throw invalid2(`${where}\u7684\u589E\u5F3A\u63D0\u793A\u8BCD\u4E0D\u5F97\u8D85\u8FC7 ${GUIDANCE_MAX_LENGTH} \u4E2A\u5B57\u7B26\u3002`);
1099
+ }
1100
+ return Object.freeze({
1101
+ enabled,
1102
+ fields: Object.freeze(CONTEXT_FIELDS.filter((field) => fields.includes(field))),
1103
+ guidance: guidance.trim() ? guidance : ""
1104
+ });
1105
+ }
1106
+ function validateTarget(input) {
1107
+ if (!hasExactKeys2(input, TARGET_KEYS)) throw invalid2("\u6307\u5B9A\u8BBE\u7F6E\u4E0D\u5B8C\u6574\uFF0C\u8BF7\u91CD\u65B0\u4FDD\u5B58\u3002");
1108
+ const {
1109
+ kind,
1110
+ id,
1111
+ label,
1112
+ enabled,
1113
+ fields,
1114
+ guidance,
1115
+ merge
1116
+ } = input;
1117
+ if (!TARGET_KINDS.includes(kind)) throw invalid2('\u6307\u5B9A\u8BBE\u7F6E\u7684\u7C7B\u578B\u53EA\u80FD\u662F"\u6307\u5B9A\u7528\u6237"\u6216"\u6307\u5B9A\u7FA4"\u3002');
1118
+ const targetId = typeof id === "string" ? id.trim() : "";
1119
+ if (!targetId || targetId.length > TARGET_ID_MAX_LENGTH || CONTROL_CHARACTER_TEST.test(targetId) || /\s/.test(targetId)) {
1120
+ throw invalid2("\u6307\u5B9A\u8BBE\u7F6E\u7684\u6807\u8BC6\u4E0D\u80FD\u4E3A\u7A7A\u3001\u4E0D\u80FD\u5305\u542B\u7A7A\u767D\u6216\u63A7\u5236\u5B57\u7B26\uFF0C\u4E14\u4E0D\u5F97\u8D85\u8FC7 256 \u4E2A\u5B57\u7B26\u3002");
1121
+ }
1122
+ if (/^(p2p|group)_/.test(targetId)) {
1123
+ throw invalid2("\u8FD9\u91CC\u8981\u586B\u5E73\u53F0 id\uFF08\u5982 ou_\u2026 / oc_\u2026\uFF09\uFF0C\u4E0D\u662F\u6295\u9012\u76EE\u6807\u7684 id\uFF08p2p_\u2026 / group_\u2026\uFF09\u3002");
1124
+ }
1125
+ if (typeof label !== "string" || label.length > TARGET_LABEL_MAX_LENGTH) {
1126
+ throw invalid2(`\u6307\u5B9A\u8BBE\u7F6E\u7684\u5907\u6CE8\u540D\u4E0D\u5F97\u8D85\u8FC7 ${TARGET_LABEL_MAX_LENGTH} \u4E2A\u5B57\u7B26\u3002`);
1127
+ }
1128
+ if (typeof enabled !== "boolean") throw invalid2("\u6307\u5B9A\u8BBE\u7F6E\u7684\u542F\u7528\u5F00\u5173\u5FC5\u987B\u662F\u5E03\u5C14\u503C\u3002");
1129
+ if (!Array.isArray(fields) || !fields.every((field) => CONTEXT_FIELDS.includes(field))) {
1130
+ throw invalid2("\u6307\u5B9A\u8BBE\u7F6E\u7684\u6765\u6E90\u5B57\u6BB5\u53EA\u80FD\u4ECE\u5DF2\u5B9A\u4E49\u7684\u516B\u4E2A\u5B57\u6BB5\u4E2D\u9009\u62E9\u3002");
1131
+ }
1132
+ if (typeof guidance !== "string" || guidance.length > GUIDANCE_MAX_LENGTH) {
1133
+ throw invalid2(`\u6307\u5B9A\u8BBE\u7F6E\u7684\u589E\u5F3A\u63D0\u793A\u8BCD\u4E0D\u5F97\u8D85\u8FC7 ${GUIDANCE_MAX_LENGTH} \u4E2A\u5B57\u7B26\u3002`);
1134
+ }
1135
+ if (!TARGET_MERGES.includes(merge)) throw invalid2('\u6307\u5B9A\u8BBE\u7F6E\u7684\u63D0\u793A\u8BCD\u53E0\u52A0\u65B9\u5F0F\u53EA\u652F\u6301"\u53E0\u52A0"\u6216"\u8986\u76D6"\u3002');
1136
+ return Object.freeze({
1137
+ kind,
1138
+ id: targetId,
1139
+ label: offlineText(label, TARGET_LABEL_MAX_LENGTH).trim(),
1140
+ enabled,
1141
+ fields: Object.freeze(CONTEXT_FIELDS.filter((field) => fields.includes(field))),
1142
+ guidance: guidance.trim() ? guidance : "",
1143
+ merge
1144
+ });
1145
+ }
1146
+ function validateContextConfig(input) {
1147
+ if (!hasExactKeys2(input, CONFIG_KEYS)) throw invalid2("\u8BF7\u63D0\u4EA4\u5B8C\u6574\u7684\u4E0A\u4E0B\u6587\u589E\u5F3A\u8BBE\u7F6E\u3002");
1148
+ if (!Array.isArray(input.targets)) throw invalid2("\u6307\u5B9A\u8BBE\u7F6E\u5FC5\u987B\u662F\u5217\u8868\u3002");
1149
+ if (input.targets.length > TARGET_LIMIT) {
1150
+ throw invalid2(`\u6307\u5B9A\u8BBE\u7F6E\u6700\u591A ${TARGET_LIMIT} \u6761\u3002`);
1151
+ }
1152
+ const targets = input.targets.map(validateTarget);
1153
+ const seen = /* @__PURE__ */ new Set();
1154
+ for (const target of targets) {
1155
+ const key = `${target.kind}:${target.id}`;
1156
+ if (seen.has(key)) throw invalid2(`\u6307\u5B9A\u8BBE\u7F6E\u4E2D\u300C${target.id}\u300D\u91CD\u590D\uFF0C\u8BF7\u5408\u5E76\u540E\u518D\u4FDD\u5B58\u3002`);
1157
+ seen.add(key);
1158
+ }
1159
+ return Object.freeze({
1160
+ group: validateScope2(input.group, "\u7FA4\u804A"),
1161
+ direct: validateScope2(input.direct, "\u79C1\u804A"),
1162
+ targets: Object.freeze(targets)
1163
+ });
1164
+ }
1165
+ function migrateLegacyConfig(input) {
1166
+ if (!hasExactKeys2(input, LEGACY_KEYS)) throw invalid2("\u8BF7\u63D0\u4EA4\u5B8C\u6574\u7684\u4E0A\u4E0B\u6587\u589E\u5F3A\u8BBE\u7F6E\u3002");
1167
+ return validateContextConfig({
1168
+ group: { enabled: input.groupEnabled, fields: input.fields, guidance: input.guidance },
1169
+ direct: { enabled: input.directEnabled, fields: input.fields, guidance: input.guidance },
1170
+ targets: []
1171
+ });
1172
+ }
1173
+ function normalizeContextConfig(input) {
1174
+ try {
1175
+ return validateContextConfig(input);
1176
+ } catch {
1177
+ try {
1178
+ return migrateLegacyConfig(input);
1179
+ } catch {
1180
+ try {
1181
+ if (isPlainObject3(input)) {
1182
+ return validateContextConfig({ ...input, targets: input.targets ?? [] });
1183
+ }
1184
+ } catch {
1185
+ }
1186
+ return DEFAULT_CONTEXT_CONFIG;
1187
+ }
1188
+ }
1189
+ }
1190
+ function contextStatusLabel(config) {
1191
+ const { group, direct, targets } = normalizeContextConfig(config);
1192
+ const parts = [];
1193
+ if (group.enabled) parts.push("\u7FA4\u804A");
1194
+ if (direct.enabled) parts.push("\u79C1\u804A");
1195
+ const active = targets.filter((target) => target.enabled).length;
1196
+ if (parts.length === 0 && active === 0) return "\u672A\u5F00\u542F";
1197
+ const scopeText = parts.length === 0 ? "\u672A\u5F00\u542F\u5168\u5C40" : `${parts.join("\u548C")}\u5168\u5C40`;
1198
+ return active === 0 ? scopeText : `${scopeText} \xB7 ${active} \u9879\u6307\u5B9A`;
1199
+ }
1200
+
1201
+ // packages/dsh-chat/client/context-enhancement.js
1202
+ var h2 = React3.createElement;
1203
+ var FIELD_LABELS = Object.freeze({
1204
+ channel: "\u6E20\u9053",
1205
+ conversationType: "\u4F1A\u8BDD\u7C7B\u578B",
1206
+ senderId: "\u53D1\u9001\u8005\u6807\u8BC6",
1207
+ senderName: "\u53D1\u9001\u8005\u6635\u79F0",
1208
+ conversationTitle: "\u4F1A\u8BDD\u6807\u9898",
1209
+ chatId: "\u4F1A\u8BDD\u6807\u8BC6",
1210
+ threadId: "\u8BDD\u9898\u6807\u8BC6",
1211
+ botId: "\u673A\u5668\u4EBA\u6807\u8BC6"
1212
+ });
1213
+ var FIELD_HELP = Object.freeze({
1214
+ senderName: "\u4E0D\u662F\u6BCF\u4E2A\u6E20\u9053\u90FD\u80FD\u63D0\u4F9B\uFF1B\u5F53\u524D\u6D88\u606F\u6CA1\u6709\u53D1\u9001\u8005\u6635\u79F0\u65F6\u4F1A\u7701\u7565\u8BE5\u5B57\u6BB5\u3002",
1215
+ conversationTitle: "\u4E0D\u662F\u6BCF\u4E2A\u6E20\u9053\u90FD\u80FD\u63D0\u4F9B\uFF1B\u5F53\u524D\u6D88\u606F\u6CA1\u6709\u4F1A\u8BDD\u6807\u9898\u65F6\u4F1A\u7701\u7565\u8BE5\u5B57\u6BB5\u3002",
1216
+ chatId: "\u7528\u4E8E\u533A\u5206\u4E0D\u540C\u7FA4\u7EC4\u6216\u79C1\u804A\uFF1B\u5F53\u524D\u6D88\u606F\u6CA1\u6709\u4F1A\u8BDD\u6807\u8BC6\u65F6\u4F1A\u7701\u7565\u8BE5\u5B57\u6BB5\u3002",
1217
+ threadId: "\u98DE\u4E66\u8BDD\u9898\u7FA4\u7684\u6D88\u606F\u4F1A\u5E26\u4E0A\u8BDD\u9898\u6807\u8BC6\uFF0C\u7528\u4E8E\u533A\u5206\u540C\u4E00\u7FA4\u7EC4\u5185\u7684\u4E0D\u540C\u8BDD\u9898\u3002"
1218
+ });
1219
+ var SCOPE_TEXT = Object.freeze({
1220
+ direct: Object.freeze({
1221
+ title: "\u79C1\u804A",
1222
+ targetTitle: "\u6307\u5B9A\u7528\u6237",
1223
+ targetHint: "\u53EA\u5728\u8BE5\u7528\u6237\u4E0E\u673A\u5668\u4EBA\u7684\u79C1\u804A\u4E2D\u751F\u6548\uFF08\u6309\u53D1\u9001\u8005\u6807\u8BC6\u5339\u914D\uFF09\u3002",
1224
+ idPlaceholder: "ou_xxx\uFF08\u53D1\u9001\u8005\u6807\u8BC6\uFF09",
1225
+ idLabel: "\u7528\u6237\u6807\u8BC6"
1226
+ }),
1227
+ group: Object.freeze({
1228
+ title: "\u7FA4\u804A",
1229
+ targetTitle: "\u6307\u5B9A\u7FA4",
1230
+ targetHint: "\u53EA\u5728\u8BE5\u7FA4\u4E2D\u751F\u6548\uFF08\u6309\u4F1A\u8BDD\u6807\u8BC6\u5339\u914D\uFF09\u3002",
1231
+ idPlaceholder: "oc_xxx\uFF08\u4F1A\u8BDD\u6807\u8BC6\uFF09",
1232
+ idLabel: "\u7FA4\u6807\u8BC6"
1233
+ })
1234
+ });
1235
+ function t_of(translate) {
1236
+ return typeof translate === "function" ? translate : (key) => key;
1237
+ }
1238
+ function FieldPicker({ scopeKey, scope, disabled, onChange, t }) {
1239
+ return h2("div", { className: "dchat-contextFields" }, CONTEXT_FIELDS.map((field) => {
1240
+ const inputId = `dchat-field-${scopeKey}-${field}`;
1241
+ return h2(
1242
+ "div",
1243
+ { key: field, className: "dchat-contextField" },
1244
+ h2("input", {
1245
+ id: inputId,
1246
+ type: "checkbox",
1247
+ checked: scope.fields.includes(field),
1248
+ disabled,
1249
+ onChange: (event) => onChange(event.target.checked ? [...scope.fields, field] : scope.fields.filter((value) => value !== field))
1250
+ }),
1251
+ h2(
1252
+ "label",
1253
+ { htmlFor: inputId, title: FIELD_HELP[field] ? t(FIELD_HELP[field]) : "" },
1254
+ h2("span", null, t(FIELD_LABELS[field])),
1255
+ h2("code", null, field)
1256
+ )
1257
+ );
1258
+ }));
1259
+ }
1260
+ function GuidanceEditor({ idPrefix, value, example, disabled, onChange, t }) {
1261
+ const id = `${idPrefix}-guidance`;
1262
+ return h2(
1263
+ "div",
1264
+ { className: "dchat-contextGuidance" },
1265
+ h2(
1266
+ "div",
1267
+ { className: "dchat-contextGuidanceHeader" },
1268
+ h2("label", { htmlFor: id, className: "dchat-contextLegend" }, t("\u589E\u5F3A\u63D0\u793A\u8BCD")),
1269
+ h2(
1270
+ "div",
1271
+ { className: "dchat-actions" },
1272
+ h2("button", {
1273
+ type: "button",
1274
+ className: "dchat-button",
1275
+ disabled,
1276
+ onClick: () => onChange(example)
1277
+ }, t("\u586B\u5165\u793A\u4F8B")),
1278
+ h2("button", {
1279
+ type: "button",
1280
+ className: "dchat-button",
1281
+ disabled,
1282
+ onClick: () => onChange("")
1283
+ }, t("\u6E05\u7A7A"))
1284
+ )
1285
+ ),
1286
+ h2(
1287
+ "p",
1288
+ { className: "dchat-cardDescription" },
1289
+ t("\u544A\u8BC9\u6A21\u578B\u5982\u4F55\u4F7F\u7528\u6765\u6E90\u5B57\u6BB5\u3002\u53EA\u586B\u6B63\u6587\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u5305\u6210\u6765\u6E90\u589E\u5F3A\u5757\u3002")
1290
+ ),
1291
+ h2("textarea", {
1292
+ id,
1293
+ className: "dchat-textarea",
1294
+ rows: 4,
1295
+ value,
1296
+ placeholder: example,
1297
+ maxLength: GUIDANCE_MAX_LENGTH,
1298
+ disabled,
1299
+ onChange: (event) => onChange(event.target.value)
1300
+ })
1301
+ );
1302
+ }
1303
+ function GlobalScopePanel({ kind, scope, disabled, onChange, t }) {
1304
+ const text = SCOPE_TEXT[kind];
1305
+ const example = kind === "group" ? GROUP_GUIDANCE_EXAMPLE : DIRECT_GUIDANCE_EXAMPLE;
1306
+ const switchId = `dchat-enable-${kind}`;
1307
+ return h2(
1308
+ "div",
1309
+ { className: "dchat-contextGlobal" },
1310
+ h2(
1311
+ "div",
1312
+ { className: "dchat-contextSwitchRow" },
1313
+ h2(
1314
+ "label",
1315
+ { htmlFor: switchId, className: "dchat-contextSwitchLabel" },
1316
+ `\u542F\u7528${text.title}\u5168\u5C40\u589E\u5F3A`
1317
+ ),
1318
+ h2("input", {
1319
+ id: switchId,
1320
+ type: "checkbox",
1321
+ role: "switch",
1322
+ checked: scope.enabled,
1323
+ disabled,
1324
+ onChange: (event) => onChange({ ...scope, enabled: event.target.checked })
1325
+ })
1326
+ ),
1327
+ h2("div", { className: "dchat-contextLegendRow" }, t("\u6765\u6E90\u5B57\u6BB5")),
1328
+ h2(FieldPicker, {
1329
+ scopeKey: `${kind}-global`,
1330
+ scope,
1331
+ disabled,
1332
+ onChange: (fields) => onChange({ ...scope, fields }),
1333
+ t
1334
+ }),
1335
+ h2(GuidanceEditor, {
1336
+ idPrefix: `dchat-${kind}-global`,
1337
+ value: scope.guidance,
1338
+ example,
1339
+ disabled,
1340
+ onChange: (guidance) => onChange({ ...scope, guidance }),
1341
+ t
1342
+ })
1343
+ );
1344
+ }
1345
+ function targetKindOf(scope) {
1346
+ return scope === "direct" ? "user" : "group";
1347
+ }
1348
+ function TargetRow({ scope, target, index, disabled, onChange, onRemove, t, conversations }) {
1349
+ const text = SCOPE_TEXT[scope];
1350
+ const prefix = `dchat-target-${scope}-${index}`;
1351
+ return h2(
1352
+ "li",
1353
+ { className: "dchat-targetRow" },
1354
+ h2(
1355
+ "div",
1356
+ { className: "dchat-targetHead" },
1357
+ h2(
1358
+ "label",
1359
+ { className: "dchat-targetEnable" },
1360
+ h2("input", {
1361
+ type: "checkbox",
1362
+ checked: target.enabled,
1363
+ disabled,
1364
+ "aria-label": `\u542F\u7528\u7B2C ${index + 1} \u6761${text.targetTitle}`,
1365
+ onChange: (event) => onChange({ ...target, enabled: event.target.checked })
1366
+ }),
1367
+ t("\u542F\u7528")
1368
+ ),
1369
+ h2("button", {
1370
+ type: "button",
1371
+ className: "dchat-button",
1372
+ disabled,
1373
+ "aria-label": `\u5220\u9664\u7B2C ${index + 1} \u6761${text.targetTitle}`,
1374
+ onClick: onRemove
1375
+ }, t("\u5220\u9664"))
1376
+ ),
1377
+ h2(
1378
+ "div",
1379
+ { className: "dchat-targetGrid" },
1380
+ h2(
1381
+ "label",
1382
+ { className: "dchat-targetField" },
1383
+ h2("span", null, text.idLabel),
1384
+ // 能选就别让人填 id:下拉里是这台机器人聊过的会话(带群名/人名),
1385
+ // 手填输入框仍然保留,兼容还没聊过的会话与直接粘贴 id 的场合。
1386
+ (conversations ?? []).length > 0 ? h2(
1387
+ "select",
1388
+ {
1389
+ className: "dchat-select",
1390
+ value: (conversations ?? []).some((item) => item.id === target.id) ? target.id : "",
1391
+ disabled,
1392
+ "aria-label": text.idLabel,
1393
+ onChange: (event) => {
1394
+ if (event.target.value) onChange({ ...target, id: event.target.value });
1395
+ }
1396
+ },
1397
+ h2("option", { value: "" }, t("\u4ECE\u4F1A\u8BDD\u91CC\u9009\u2026")),
1398
+ (conversations ?? []).map((item) => h2("option", { key: item.id, value: item.id }, item.name))
1399
+ ) : null,
1400
+ h2("input", {
1401
+ type: "text",
1402
+ value: target.id,
1403
+ maxLength: TARGET_ID_MAX_LENGTH,
1404
+ placeholder: text.idPlaceholder,
1405
+ disabled,
1406
+ onChange: (event) => onChange({ ...target, id: event.target.value })
1407
+ })
1408
+ ),
1409
+ h2(
1410
+ "label",
1411
+ { className: "dchat-targetField" },
1412
+ h2("span", null, t("\u5907\u6CE8\u540D\uFF08\u53EF\u9009\uFF09")),
1413
+ h2("input", {
1414
+ type: "text",
1415
+ value: target.label,
1416
+ maxLength: TARGET_LABEL_MAX_LENGTH,
1417
+ placeholder: t("\u5F20\u4E09"),
1418
+ disabled,
1419
+ onChange: (event) => onChange({ ...target, label: event.target.value })
1420
+ })
1421
+ )
1422
+ ),
1423
+ h2("div", { className: "dchat-contextLegendRow" }, t("\u6765\u6E90\u5B57\u6BB5")),
1424
+ h2(FieldPicker, {
1425
+ scopeKey: `${prefix}`,
1426
+ scope: target,
1427
+ disabled,
1428
+ onChange: (fields) => onChange({ ...target, fields }),
1429
+ t
1430
+ }),
1431
+ h2(GuidanceEditor, {
1432
+ idPrefix: prefix,
1433
+ value: target.guidance,
1434
+ example: scope === "group" ? GROUP_GUIDANCE_EXAMPLE : DIRECT_GUIDANCE_EXAMPLE,
1435
+ disabled,
1436
+ onChange: (guidance) => onChange({ ...target, guidance }),
1437
+ t
1438
+ }),
1439
+ h2(
1440
+ "label",
1441
+ { className: "dchat-targetMerge" },
1442
+ h2("input", {
1443
+ type: "checkbox",
1444
+ checked: target.merge === "append",
1445
+ disabled,
1446
+ onChange: (event) => onChange({
1447
+ ...target,
1448
+ merge: event.target.checked ? "append" : "replace"
1449
+ })
1450
+ }),
1451
+ t("\u53E0\u52A0\u5168\u5C40\u63D0\u793A\u8BCD\uFF08\u4E0D\u52FE\u9009\u5219\u53EA\u4F7F\u7528\u4E0A\u9762\u7684\u4E13\u5C5E\u63D0\u793A\u8BCD\uFF09")
1452
+ )
1453
+ );
1454
+ }
1455
+ function TargetPanel({ scope, targets, disabled, onChange, t, conversations }) {
1456
+ const kind = targetKindOf(scope);
1457
+ const text = SCOPE_TEXT[scope];
1458
+ const rows = targets.map((target, index) => ({ target, index })).filter((entry) => entry.target.kind === kind);
1459
+ const add = () => onChange([...targets, {
1460
+ kind,
1461
+ id: "",
1462
+ label: "",
1463
+ enabled: true,
1464
+ fields: ["senderId"],
1465
+ guidance: "",
1466
+ merge: "append"
1467
+ }]);
1468
+ const replace = (index, next) => onChange(targets.map((item, at) => at === index ? next : item));
1469
+ const remove = (index) => onChange(targets.filter((_, at) => at !== index));
1470
+ return h2(
1471
+ "div",
1472
+ { className: "dchat-contextTargets" },
1473
+ h2(
1474
+ "div",
1475
+ { className: "dchat-cardHeader" },
1476
+ h2(
1477
+ "div",
1478
+ null,
1479
+ h2("h4", { className: "dchat-cardTitle" }, text.targetTitle),
1480
+ h2("p", { className: "dchat-cardDescription" }, text.targetHint)
1481
+ ),
1482
+ h2("button", {
1483
+ type: "button",
1484
+ className: "dchat-button",
1485
+ disabled: disabled || targets.length >= TARGET_LIMIT,
1486
+ onClick: add
1487
+ }, t("\u65B0\u589E"))
1488
+ ),
1489
+ rows.length === 0 ? h2("p", { className: "dchat-cardDescription" }, t("\u8FD8\u6CA1\u6709\u6307\u5B9A\u8BBE\u7F6E\u3002")) : h2("ul", { className: "dchat-targetList" }, rows.map(({ target, index }) => h2(TargetRow, {
1490
+ key: index,
1491
+ scope,
1492
+ target,
1493
+ index,
1494
+ disabled,
1495
+ onChange: (next) => replace(index, next),
1496
+ onRemove: () => remove(index),
1497
+ t,
1498
+ // 只给这一类作用域挑:私聊给"人",群聊给"群"。
1499
+ conversations: (conversations ?? []).filter((item) => kind === "group" ? item.kind === "group" : item.kind === "direct")
1500
+ })))
1501
+ );
1502
+ ;
1503
+ }
1504
+ function ContextEnhancementDialog({ config, disabled, translate, onSave, onClose, conversations }) {
1505
+ const t = t_of(translate);
1506
+ const [draft, setDraft] = React3.useState(() => normalizeContextConfig(config));
1507
+ const [activeScope, setActiveScope] = React3.useState("direct");
1508
+ const [saving, setSaving] = React3.useState(false);
1509
+ const [error, setError] = React3.useState(null);
1510
+ const dialogRef = React3.useRef(null);
1511
+ const titleId = React3.useId();
1512
+ React3.useEffect(() => {
1513
+ dialogRef.current?.focus?.();
1514
+ }, []);
1515
+ const busy = disabled || saving;
1516
+ const save = async () => {
1517
+ if (busy) return;
1518
+ setSaving(true);
1519
+ setError(null);
1520
+ try {
1521
+ const next = validateContextConfig(draft);
1522
+ await onSave(next);
1523
+ onClose();
1524
+ } catch (cause) {
1525
+ setError(cause?.message ?? t("\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002"));
1526
+ } finally {
1527
+ setSaving(false);
1528
+ }
1529
+ };
1530
+ const content = h2("div", {
1531
+ className: "dchat-backdrop",
1532
+ onMouseDown: (event) => {
1533
+ if (event.target === event.currentTarget && !saving) onClose();
1534
+ }
1535
+ }, h2(
1536
+ "section",
1537
+ {
1538
+ ref: dialogRef,
1539
+ className: "dchat-dialog",
1540
+ role: "dialog",
1541
+ "aria-modal": "true",
1542
+ "aria-labelledby": titleId,
1543
+ tabIndex: -1,
1544
+ onKeyDown: (event) => {
1545
+ if (event.key === "Escape" && !saving) {
1546
+ event.preventDefault();
1547
+ onClose();
1548
+ }
1549
+ }
1550
+ },
1551
+ h2(
1552
+ "header",
1553
+ { className: "dchat-dialogHeader" },
1554
+ h2("h3", { id: titleId, className: "dchat-cardTitle" }, t("\u4E0A\u4E0B\u6587\u589E\u5F3A")),
1555
+ h2("button", {
1556
+ type: "button",
1557
+ className: "dchat-button",
1558
+ disabled: saving,
1559
+ "aria-label": t("\u5173\u95ED"),
1560
+ onClick: onClose
1561
+ }, t("\u5173\u95ED"))
1562
+ ),
1563
+ h2(
1564
+ "p",
1565
+ { className: "dchat-cardDescription" },
1566
+ t("\u6765\u6E90\u5B57\u6BB5\u53EA\u5728\u5F53\u524D\u6D88\u606F\u5DF2\u63D0\u4F9B\u65F6\u624D\u4F1A\u53D1\u9001\uFF0C\u4E0D\u4F1A\u989D\u5916\u67E5\u8BE2\u5E73\u53F0\u63A5\u53E3\u3002")
1567
+ ),
1568
+ h2(
1569
+ "div",
1570
+ { className: "dchat-tabs", role: "tablist", "aria-label": t("\u4E0A\u4E0B\u6587\u589E\u5F3A\u8303\u56F4") },
1571
+ ["direct", "group"].map((kind) => h2("button", {
1572
+ key: kind,
1573
+ type: "button",
1574
+ role: "tab",
1575
+ className: "dchat-tab",
1576
+ "aria-selected": activeScope === kind,
1577
+ "data-scope": kind,
1578
+ onClick: () => setActiveScope(kind)
1579
+ }, t(SCOPE_TEXT[kind].title)))
1580
+ ),
1581
+ ["direct", "group"].map((kind) => h2(
1582
+ "div",
1583
+ {
1584
+ key: kind,
1585
+ role: "tabpanel",
1586
+ className: "dchat-tabPanel",
1587
+ hidden: activeScope !== kind,
1588
+ "data-scope": kind
1589
+ },
1590
+ h2(GlobalScopePanel, {
1591
+ kind,
1592
+ scope: draft[kind],
1593
+ disabled: busy,
1594
+ t,
1595
+ onChange: (scope) => setDraft((current) => ({ ...current, [kind]: scope }))
1596
+ }),
1597
+ h2(TargetPanel, {
1598
+ scope: kind,
1599
+ targets: draft.targets,
1600
+ disabled: busy,
1601
+ t,
1602
+ conversations,
1603
+ onChange: (targets) => setDraft((current) => ({ ...current, targets }))
1604
+ })
1605
+ )),
1606
+ error ? h2("p", { className: "dchat-error", role: "alert" }, error) : null,
1607
+ h2(
1608
+ "footer",
1609
+ { className: "dchat-dialogFooter" },
1610
+ h2("button", {
1611
+ type: "button",
1612
+ className: "dchat-button",
1613
+ disabled: saving,
1614
+ onClick: onClose
1615
+ }, t("\u53D6\u6D88")),
1616
+ h2("button", {
1617
+ type: "button",
1618
+ className: "dchat-button dchat-buttonPrimary",
1619
+ disabled: busy,
1620
+ onClick: () => {
1621
+ void save();
1622
+ }
1623
+ }, saving ? t("\u4FDD\u5B58\u4E2D\u2026") : t("\u4FDD\u5B58"))
1624
+ )
1625
+ ));
1626
+ return globalThis.document?.body ? (0, import_react_dom.createPortal)(content, globalThis.document.body) : content;
1627
+ }
1628
+ function ContextEnhancementEditor({
1629
+ config,
1630
+ disabled = false,
1631
+ translate,
1632
+ onSave,
1633
+ conversations = []
1634
+ }) {
1635
+ const t = t_of(translate);
1636
+ const [open, setOpen] = React3.useState(false);
1637
+ const status = contextStatusLabel(config);
1638
+ return h2(
1639
+ React3.Fragment,
1640
+ null,
1641
+ h2(
1642
+ "button",
1643
+ {
1644
+ type: "button",
1645
+ className: "dchat-entry",
1646
+ disabled,
1647
+ "aria-haspopup": "dialog",
1648
+ "aria-expanded": open,
1649
+ onClick: () => setOpen(true)
1650
+ },
1651
+ h2("span", { className: "dchat-entryLabel" }, t("\u4E0A\u4E0B\u6587\u589E\u5F3A")),
1652
+ h2("span", { className: "dchat-entryStatus", "data-active": status !== "\u672A\u5F00\u542F" }, t(status)),
1653
+ h2("span", { className: "dchat-entryArrow", "aria-hidden": "true" }, "\u203A")
1654
+ ),
1655
+ open ? h2(ContextEnhancementDialog, {
1656
+ config,
1657
+ disabled,
1658
+ translate: t,
1659
+ onSave,
1660
+ conversations,
1661
+ onClose: () => setOpen(false)
1662
+ }) : null
1663
+ );
1664
+ }
1665
+
1666
+ // packages/dsh-chat/client/delivery-targets.js
1667
+ var React4 = __toESM(require("react"), 1);
1668
+ var h3 = React4.createElement;
1669
+ var CANDIDATE_PREVIEW = 5;
1670
+ var FILTER_THRESHOLD = 6;
1671
+ function translatorOf2(translate, chatUi) {
1672
+ if (typeof translate === "function") return translate;
1673
+ if (typeof chatUi?.translate === "function") return chatUi.translate;
1674
+ return (key) => key;
1675
+ }
1676
+ function TargetRow2({
1677
+ target,
1678
+ busy,
1679
+ confirming,
1680
+ renaming,
1681
+ renameDraft,
1682
+ translate,
1683
+ onSave,
1684
+ onAskRemove,
1685
+ onCancel,
1686
+ onRemove,
1687
+ onStartRename,
1688
+ onRenameDraft,
1689
+ onSubmitRename,
1690
+ onCancelRename
1691
+ }) {
1692
+ const t = translate;
1693
+ const route = Object.entries(target.route ?? {}).map(([key, value]) => `${key}=${value}`).join(" \xB7 ");
1694
+ const kindLabel = target.kind === "group" ? t("\u7FA4\u804A") : t("\u79C1\u804A");
1695
+ if (renaming) {
1696
+ return h3(
1697
+ "div",
1698
+ { className: "dchat-listItem dchat-deliveryRow" },
1699
+ h3(
1700
+ "div",
1701
+ { className: "dchat-deliveryMeta" },
1702
+ h3("input", {
1703
+ className: "dchat-input",
1704
+ value: renameDraft,
1705
+ placeholder: t("\u7559\u7A7A\u5219\u7528\u81EA\u52A8\u8BC6\u522B\u7684\u540D\u5B57"),
1706
+ autoComplete: "off",
1707
+ spellCheck: false,
1708
+ "aria-label": t("\u81EA\u5B9A\u4E49\u540D\u79F0"),
1709
+ onChange: (event) => onRenameDraft(event.target.value),
1710
+ onKeyDown: (event) => {
1711
+ if (event.key === "Enter") onSubmitRename();
1712
+ if (event.key === "Escape") onCancelRename();
1713
+ }
1714
+ }),
1715
+ h3("small", null, `${kindLabel} \xB7 ${route}`)
1716
+ ),
1717
+ h3(
1718
+ "div",
1719
+ { className: "dchat-actions" },
1720
+ h3("button", {
1721
+ key: "submit",
1722
+ type: "button",
1723
+ className: "dchat-button dchat-buttonPrimary",
1724
+ disabled: busy,
1725
+ onClick: onSubmitRename
1726
+ }, busy ? t("\u4FDD\u5B58\u4E2D\u2026") : t("\u4FDD\u5B58")),
1727
+ h3("button", {
1728
+ key: "cancel",
1729
+ type: "button",
1730
+ className: "dchat-button",
1731
+ disabled: busy,
1732
+ onClick: onCancelRename
1733
+ }, t("\u53D6\u6D88"))
1734
+ )
1735
+ );
1736
+ }
1737
+ const actions = target.discovered ? [h3("button", {
1738
+ key: "save",
1739
+ type: "button",
1740
+ className: "dchat-button",
1741
+ disabled: busy,
1742
+ onClick: () => onSave(target)
1743
+ }, t("\u4FDD\u5B58\u4E3A\u6295\u9012\u76EE\u6807"))] : confirming ? [
1744
+ h3("button", {
1745
+ key: "confirm",
1746
+ type: "button",
1747
+ className: "dchat-button dchat-buttonDangerSolid",
1748
+ disabled: busy,
1749
+ onClick: () => onRemove(target)
1750
+ }, t("\u786E\u8BA4\u5220\u9664")),
1751
+ h3("button", {
1752
+ key: "cancel",
1753
+ type: "button",
1754
+ className: "dchat-button",
1755
+ disabled: busy,
1756
+ onClick: onCancel
1757
+ }, t("\u53D6\u6D88"))
1758
+ ] : [
1759
+ h3("button", {
1760
+ key: "rename",
1761
+ type: "button",
1762
+ className: "dchat-button",
1763
+ disabled: busy,
1764
+ onClick: () => onStartRename(target)
1765
+ }, t("\u91CD\u547D\u540D")),
1766
+ h3("button", {
1767
+ key: "remove",
1768
+ type: "button",
1769
+ className: "dchat-button dchat-buttonDanger",
1770
+ disabled: busy,
1771
+ onClick: onAskRemove
1772
+ }, t("\u5220\u9664"))
1773
+ ];
1774
+ return h3(
1775
+ "div",
1776
+ { className: "dchat-listItem dchat-deliveryRow" },
1777
+ h3(
1778
+ "div",
1779
+ { className: "dchat-deliveryMeta" },
1780
+ h3("strong", null, target.name || target.id),
1781
+ // 只留一行身份:`route` 里已经带了 openId/chatId,再挂一个 `p2p_…` 原始 id
1782
+ // 就是同一个东西的第二种写法,只会让人怀疑"这是两个不同的目标"。
1783
+ h3("small", null, `${kindLabel} \xB7 ${route}`)
1784
+ ),
1785
+ h3(
1786
+ "div",
1787
+ { className: "dchat-actions" },
1788
+ target.discovered ? h3("span", { className: "dchat-status" }, t("\u5019\u9009")) : null,
1789
+ ...actions
1790
+ )
1791
+ );
1792
+ }
1793
+ function DeliveryTargetsEditor({ chatUi, connection, channelId, botId, translate }) {
1794
+ const t = translatorOf2(translate, chatUi);
1795
+ const { Panel: Panel2 } = chatUi.components;
1796
+ const [state, setState] = React4.useState({ phase: "loading", targets: [], canSend: false });
1797
+ const [error, setError] = React4.useState(null);
1798
+ const [notice, setNotice] = React4.useState(null);
1799
+ const [busyId, setBusyId] = React4.useState(null);
1800
+ const [confirmingId, setConfirmingId] = React4.useState(null);
1801
+ const [renamingId, setRenamingId] = React4.useState(null);
1802
+ const [renameDraft, setRenameDraft] = React4.useState("");
1803
+ const [draft, setDraft] = React4.useState("");
1804
+ const [sendTo, setSendTo] = React4.useState("");
1805
+ const [filter, setFilter] = React4.useState("");
1806
+ const [showAllCandidates, setShowAllCandidates] = React4.useState(false);
1807
+ const call = React4.useCallback(async (method, payload) => {
1808
+ const result = await chatUi.callControlRpc(connection, method, payload);
1809
+ return chatUi.unwrapRpc(result);
1810
+ }, [chatUi, connection]);
1811
+ const load = React4.useCallback(async () => {
1812
+ try {
1813
+ const value = await call("delivery.list", { channelId, botId });
1814
+ const targets = value.targets ?? [];
1815
+ setState({ phase: "ready", targets, canSend: value.canSend === true });
1816
+ setSendTo((current) => {
1817
+ const savedIds = targets.filter((target) => !target.discovered).map((target) => target.id);
1818
+ return savedIds.includes(current) ? current : savedIds[0] ?? "";
1819
+ });
1820
+ } catch (cause) {
1821
+ setState((current) => ({ ...current, phase: "error" }));
1822
+ setError(cause.message);
1823
+ }
1824
+ }, [call, channelId, botId]);
1825
+ React4.useEffect(() => {
1826
+ void load();
1827
+ }, [load]);
1828
+ const run = React4.useCallback(async (key, method, payload, message) => {
1829
+ setBusyId(key);
1830
+ setError(null);
1831
+ setNotice(null);
1832
+ try {
1833
+ const value = await call(method, payload);
1834
+ await load();
1835
+ setNotice(typeof message === "function" ? message(value) : message);
1836
+ return value;
1837
+ } catch (cause) {
1838
+ setError(cause.message);
1839
+ return null;
1840
+ } finally {
1841
+ setBusyId(null);
1842
+ }
1843
+ }, [call, load]);
1844
+ const saved = state.targets.filter((target) => !target.discovered);
1845
+ const candidates = state.targets.filter((target) => target.discovered);
1846
+ const ready = state.phase === "ready" && state.canSend === true;
1847
+ const query = filter.trim().toLowerCase();
1848
+ const matches = (target) => !query || `${target.name ?? ""} ${target.id} ${JSON.stringify(target.route ?? {})}`.toLowerCase().includes(query);
1849
+ const savedShown = saved.filter(matches);
1850
+ const candidatesShown = candidates.filter(matches);
1851
+ const visibleCandidates = showAllCandidates ? candidatesShown : candidatesShown.slice(0, CANDIDATE_PREVIEW);
1852
+ const renderRow = (target) => h3(TargetRow2, {
1853
+ key: target.id,
1854
+ target,
1855
+ busy: busyId === target.id,
1856
+ confirming: confirmingId === target.id,
1857
+ renaming: renamingId === target.id,
1858
+ renameDraft: renamingId === target.id ? renameDraft : "",
1859
+ translate: t,
1860
+ onSave: (item) => {
1861
+ void run(item.id, "delivery.save", {
1862
+ channelId,
1863
+ botId,
1864
+ target: { id: item.id, name: item.name, kind: item.kind, route: item.route }
1865
+ }, () => t("\u5DF2\u4FDD\u5B58\uFF0C\u73B0\u5728\u53EF\u4EE5\u4E3B\u52A8\u53D1\u6D88\u606F\u4E86\u3002"));
1866
+ },
1867
+ onStartRename: (item) => {
1868
+ setConfirmingId(null);
1869
+ setRenamingId(item.id);
1870
+ setRenameDraft(item.renamed ? item.name : "");
1871
+ },
1872
+ onRenameDraft: setRenameDraft,
1873
+ onCancelRename: () => setRenamingId(null),
1874
+ onSubmitRename: () => {
1875
+ const id = renamingId;
1876
+ setRenamingId(null);
1877
+ void run(id, "delivery.target.rename", {
1878
+ channelId,
1879
+ botId,
1880
+ targetId: id,
1881
+ name: renameDraft.trim()
1882
+ }, () => renameDraft.trim() ? t("\u5DF2\u6539\u540D\u3002") : t("\u5DF2\u6062\u590D\u81EA\u52A8\u540D\u5B57\u3002"));
1883
+ },
1884
+ onAskRemove: () => setConfirmingId(target.id),
1885
+ onCancel: () => setConfirmingId(null),
1886
+ onRemove: (item) => {
1887
+ setConfirmingId(null);
1888
+ void run(
1889
+ item.id,
1890
+ "delivery.remove",
1891
+ { channelId, botId, targetId: item.id },
1892
+ () => t("\u5DF2\u5220\u9664\u3002")
1893
+ );
1894
+ }
1895
+ });
1896
+ const groupTitle = (text) => h3("p", { className: "dchat-groupTitle" }, text);
1897
+ return h3(
1898
+ Panel2,
1899
+ {
1900
+ title: t("\u4E3B\u52A8\u6295\u9012"),
1901
+ description: t("\u8BA9\u5B9A\u65F6\u4EFB\u52A1\u6216 agent \u628A\u7ED3\u679C\u76F4\u63A5\u53D1\u5230\u6307\u5B9A\u4F1A\u8BDD\u3002")
1902
+ },
1903
+ error ? h3("p", { className: "dchat-error", role: "alert" }, error) : null,
1904
+ notice ? h3("p", { className: "dchat-notice", role: "status" }, notice) : null,
1905
+ state.phase === "loading" ? h3("p", { className: "dchat-cardDescription" }, t("\u8BFB\u53D6\u4E2D\u2026")) : null,
1906
+ state.phase === "ready" && state.canSend === false ? h3("p", { className: "dchat-cardDescription" }, t("\u5F53\u524D\u6E20\u9053\u4E0D\u652F\u6301\u4E3B\u52A8\u6295\u9012\u3002")) : null,
1907
+ // 目标多到需要找的时候才出现过滤框,平时不占地方。
1908
+ state.targets.length > FILTER_THRESHOLD ? h3(
1909
+ "div",
1910
+ { className: "dchat-actions" },
1911
+ h3("input", {
1912
+ className: "dchat-input",
1913
+ value: filter,
1914
+ placeholder: t("\u6309\u540D\u5B57\u6216 id \u8FC7\u6EE4"),
1915
+ autoComplete: "off",
1916
+ spellCheck: false,
1917
+ onChange: (event) => setFilter(event.target.value)
1918
+ })
1919
+ ) : null,
1920
+ savedShown.length > 0 ? h3(
1921
+ React4.Fragment,
1922
+ null,
1923
+ groupTitle(t("\u5DF2\u4FDD\u5B58")),
1924
+ h3("div", { className: "dchat-list" }, savedShown.map(renderRow))
1925
+ ) : null,
1926
+ candidatesShown.length > 0 ? h3(
1927
+ React4.Fragment,
1928
+ null,
1929
+ groupTitle(`${t("\u53EF\u6DFB\u52A0\u7684\u5019\u9009")}\uFF08${candidatesShown.length}\uFF09`),
1930
+ h3("div", { className: "dchat-list" }, visibleCandidates.map(renderRow)),
1931
+ candidatesShown.length > CANDIDATE_PREVIEW ? h3("button", {
1932
+ type: "button",
1933
+ className: "dchat-button dchat-buttonLink",
1934
+ onClick: () => setShowAllCandidates((value) => !value)
1935
+ }, showAllCandidates ? t("\u6536\u8D77") : `${t("\u5C55\u5F00\u5168\u90E8")}\uFF08${candidatesShown.length}\uFF09`) : null
1936
+ ) : null,
1937
+ state.targets.length > 0 && savedShown.length === 0 && candidatesShown.length === 0 ? h3("p", { className: "dchat-cardDescription" }, t("\u6CA1\u6709\u5339\u914D\u7684\u76EE\u6807\u3002")) : null,
1938
+ /**
1939
+ * 「怎么添加」常驻说明:**只要没有候选就显示**。
1940
+ * 之前只在"一个目标都没有"时显示,于是有 1 个已保存目标、又没有候选时,
1941
+ * 整张卡既看不到可添加项、也看不到为什么——用户只能说"没有添加入口"。
1942
+ */
1943
+ ready && candidates.length === 0 ? h3(
1944
+ "p",
1945
+ { className: "dchat-cardDescription" },
1946
+ saved.length === 0 ? t("\u8FD8\u6CA1\u6709\u53EF\u6DFB\u52A0\u7684\u4F1A\u8BDD\uFF1A\u5728\u7FA4\u91CC @ \u4E00\u6B21\u673A\u5668\u4EBA\uFF0C\u6216\u4E0E\u5B83\u79C1\u804A\u4E00\u6B21\uFF0C\u4F1A\u8BDD\u5C31\u4F1A\u51FA\u73B0\u5728\u8FD9\u91CC\uFF0C\u4FDD\u5B58\u540E\u5373\u53EF\u4E3B\u52A8\u6295\u9012\u3002") : t("\u6CA1\u6709\u53EF\u6DFB\u52A0\u7684\u4F1A\u8BDD\uFF1A\u5728\u7FA4\u91CC @ \u4E00\u6B21\u673A\u5668\u4EBA\uFF0C\u6216\u4E0E\u5B83\u79C1\u804A\u4E00\u6B21\uFF0C\u8BE5\u4F1A\u8BDD\u5C31\u4F1A\u51FA\u73B0\u5728\u8FD9\u91CC\u3002")
1947
+ ) : null,
1948
+ candidates.length > 0 ? h3(
1949
+ "p",
1950
+ { className: "dchat-cardDescription" },
1951
+ t("\u4E0A\u9762\u6807\u300C\u5019\u9009\u300D\u7684\u4F1A\u8BDD\u8FD8\u4E0D\u80FD\u4E3B\u52A8\u6295\u9012\uFF0C\u70B9\u300C\u4FDD\u5B58\u4E3A\u6295\u9012\u76EE\u6807\u300D\u540E\u624D\u884C\u3002")
1952
+ ) : null,
1953
+ saved.length > 0 ? h3(
1954
+ "div",
1955
+ { className: "dchat-deliverySend" },
1956
+ h3(
1957
+ "label",
1958
+ { className: "dchat-scopeLabel", htmlFor: `dchat-delivery-${botId}` },
1959
+ t("\u53D1\u4E00\u6761\u6D4B\u8BD5\u6D88\u606F")
1960
+ ),
1961
+ h3(
1962
+ "div",
1963
+ { className: "dchat-actions" },
1964
+ h3("select", {
1965
+ className: "dchat-select",
1966
+ value: sendTo,
1967
+ "aria-label": t("\u9009\u62E9\u76EE\u6807"),
1968
+ onChange: (event) => setSendTo(event.target.value)
1969
+ }, saved.map((target) => h3("option", {
1970
+ key: target.id,
1971
+ value: target.id
1972
+ }, `${target.name || target.id}\uFF08${target.kind === "group" ? t("\u7FA4\u804A") : t("\u79C1\u804A")}\uFF09`))),
1973
+ h3("button", {
1974
+ type: "button",
1975
+ className: "dchat-button dchat-buttonPrimary",
1976
+ disabled: busyId === "send" || !draft.trim() || !sendTo,
1977
+ onClick: () => {
1978
+ void run("send", "delivery.send", { channelId, botId, targetId: sendTo, text: draft }).then((value) => {
1979
+ if (value !== null) setDraft("");
1980
+ });
1981
+ }
1982
+ }, busyId === "send" ? t("\u53D1\u9001\u4E2D\u2026") : t("\u53D1\u9001"))
1983
+ ),
1984
+ h3("textarea", {
1985
+ id: `dchat-delivery-${botId}`,
1986
+ className: "dchat-textarea",
1987
+ rows: 2,
1988
+ placeholder: t("\u6D4B\u8BD5\u6D88\u606F\u5185\u5BB9"),
1989
+ value: draft,
1990
+ onChange: (event) => setDraft(event.target.value)
1991
+ })
1992
+ ) : null
1993
+ );
1994
+ }
1995
+
1996
+ // packages/dsh-chat/client/scoped-mode-editor.js
1997
+ var React5 = __toESM(require("react"), 1);
1998
+ var h4 = React5.createElement;
1999
+ function ScopedModeEditor({
2000
+ title,
2001
+ description,
2002
+ scopes,
2003
+ options,
2004
+ value = {},
2005
+ disabled = false,
2006
+ saving = false,
2007
+ error = null,
2008
+ translate,
2009
+ onSave
2010
+ }) {
2011
+ const t = typeof translate === "function" ? translate : (key) => key;
2012
+ const [draft, setDraft] = React5.useState(() => ({ ...value }));
2013
+ const [pending, setPending] = React5.useState(null);
2014
+ const [failed, setFailed] = React5.useState(null);
2015
+ const [helpFor, setHelpFor] = React5.useState(scopes[0]?.key ?? null);
2016
+ const same = (a, b) => scopes.every((scope) => (a[scope.key] ?? null) === (b[scope.key] ?? null));
2017
+ const locked = disabled || saving || pending !== null;
2018
+ React5.useEffect(() => {
2019
+ if (pending !== null) return;
2020
+ setDraft((current) => same(current, value) ? current : { ...value });
2021
+ }, [value, pending]);
2022
+ const choose = async (scopeKey, nextValue) => {
2023
+ if (locked) return;
2024
+ const next = { ...draft, [scopeKey]: nextValue };
2025
+ setDraft(next);
2026
+ setFailed(null);
2027
+ setPending(scopeKey);
2028
+ try {
2029
+ await onSave({ ...next });
2030
+ } catch (cause) {
2031
+ setDraft({ ...value });
2032
+ setFailed(cause?.message ?? String(cause));
2033
+ } finally {
2034
+ setPending(null);
2035
+ }
2036
+ };
2037
+ const savingHint = pending !== null ? h4("span", { className: "dchat-status" }, t("\u4FDD\u5B58\u4E2D\u2026")) : null;
2038
+ const help = options.find((option) => option.value === (draft[helpFor] ?? options[0]?.value))?.help;
2039
+ return h4(
2040
+ "section",
2041
+ { className: "dchat-card" },
2042
+ h4(
2043
+ "div",
2044
+ { className: "dchat-cardHeader" },
2045
+ h4(
2046
+ "div",
2047
+ { className: "dchat-cardHeading" },
2048
+ h4("h3", { className: "dchat-cardTitle" }, title),
2049
+ description ? h4("p", { className: "dchat-cardDescription" }, description) : null
2050
+ ),
2051
+ savingHint ? h4("div", { className: "dchat-actions" }, savingHint) : null
2052
+ ),
2053
+ h4("div", { className: "dchat-scopeGrid" }, scopes.map((scope) => {
2054
+ const selected = draft[scope.key] ?? options[0]?.value;
2055
+ const selectId = `dchat-mode-${scope.key}`;
2056
+ return h4(
2057
+ "div",
2058
+ { key: scope.key, className: "dchat-scopeRow" },
2059
+ h4("label", { className: "dchat-scopeLabel", htmlFor: selectId }, scope.label),
2060
+ h4(
2061
+ "select",
2062
+ {
2063
+ id: selectId,
2064
+ className: "dchat-select",
2065
+ value: selected,
2066
+ disabled: locked,
2067
+ "aria-label": `${title} \xB7 ${scope.label}`,
2068
+ onFocus: () => setHelpFor(scope.key),
2069
+ onChange: (event) => {
2070
+ setHelpFor(scope.key);
2071
+ void choose(scope.key, event.target.value);
2072
+ }
2073
+ },
2074
+ options.map((option) => h4("option", {
2075
+ key: option.value,
2076
+ value: option.value
2077
+ }, t(option.label))),
2078
+ scope.key === helpFor && help ? h4("p", { className: "dchat-cardDescription" }, t(help)) : null
2079
+ )
2080
+ );
2081
+ })),
2082
+ failed || error ? h4("p", { className: "dchat-error", role: "alert" }, failed ?? error) : null
2083
+ );
2084
+ }
2085
+
2086
+ // packages/dsh-chat/client/styles.js
2087
+ var STYLE_ID = "dsh-chat-styles";
2088
+ var CSS = `
2089
+ .dchat-page {
2090
+ display: flex;
2091
+ flex-direction: column;
2092
+ gap: 16px;
2093
+ height: 100%;
2094
+ min-height: 0;
2095
+ color: var(--dsw-alias-label-primary);
2096
+ font-family: var(--dsw-font-family);
2097
+ }
2098
+ .dchat-header {
2099
+ display: flex;
2100
+ align-items: baseline;
2101
+ justify-content: space-between;
2102
+ gap: 12px;
2103
+ /* \u7A84\u680F\u4E0B\u5165\u53E3\u6362\u884C\uFF0C\u800C\u4E0D\u662F\u628A\u54C1\u724C\u540D\u6324\u51FA\u5BB9\u5668\u3002 */
2104
+ flex-wrap: wrap;
2105
+ }
2106
+ /* \u53F3\u4E0A\u89D2\u5165\u53E3\u7EC4\uFF08\u8BCA\u65AD / \u7248\u672C\u4E0E\u66F4\u65B0\uFF09\uFF1A\u5F62\u6001\u4E00\u81F4\u3001\u653E\u4E0D\u4E0B\u5C31\u6362\u884C\u3002 */
2107
+ .dchat-headerActions {
2108
+ display: flex;
2109
+ align-items: baseline;
2110
+ gap: 8px;
2111
+ flex-wrap: wrap;
2112
+ }
2113
+ .dchat-brand {
2114
+ display: flex;
2115
+ align-items: baseline;
2116
+ gap: 8px;
2117
+ }
2118
+ .dchat-brandName {
2119
+ font-size: 16px;
2120
+ font-weight: 600;
2121
+ }
2122
+ .dchat-brandHint {
2123
+ font-size: 12px;
2124
+ color: var(--dsw-alias-label-tertiary);
2125
+ }
2126
+ .dchat-layout {
2127
+ display: flex;
2128
+ gap: 16px;
2129
+ align-items: flex-start;
2130
+ min-height: 0;
2131
+ flex: 1;
2132
+ }
2133
+ .dchat-rail {
2134
+ display: flex;
2135
+ flex-direction: column;
2136
+ gap: 4px;
2137
+ /* \u53EA\u6709\u300C\u56FE\u6807 + \u6E20\u9053\u540D\u300D\uFF0C\u526F\u6807\u9898\u5728\u53F3\u680F\u6807\u9898\u4E0B\uFF0C\u6240\u4EE5\u8FD9\u91CC\u53EF\u4EE5\u7A84\u4E00\u70B9\uFF0C\u628A\u5BBD\u5EA6\u8BA9\u7ED9\u53F3\u680F\u3002 */
2138
+ width: 148px;
2139
+ flex: none;
2140
+ }
2141
+ .dchat-channel {
2142
+ display: flex;
2143
+ align-items: center;
2144
+ gap: 8px;
2145
+ padding: 8px 10px;
2146
+ /* \u8FB9\u6846\u59CB\u7EC8\u5360\u4F4D\uFF08\u672A\u9009\u4E2D\u662F\u900F\u660E\u7684\uFF09\uFF0C\u9009\u4E2D/\u672A\u9009\u4E2D\u7684\u5916\u6846\u4E00\u6837\u5927\uFF0C\u5217\u8868\u624D\u4E0D\u4F1A"\u4E00\u5361\u7247 + \u4E00\u88F8\u884C"\u3002 */
2147
+ border: 1px solid transparent;
2148
+ border-radius: 8px;
2149
+ background: transparent;
2150
+ color: inherit;
2151
+ font: inherit;
2152
+ text-align: left;
2153
+ cursor: pointer;
2154
+ }
2155
+ .dchat-channel:hover {
2156
+ background: var(--dsw-alias-interactive-bg-hover);
2157
+ }
2158
+ .dchat-channel[aria-selected='true'] {
2159
+ background: var(--dsw-alias-bg-layer-2);
2160
+ border-color: var(--dsw-alias-border-l2);
2161
+ /* \u9009\u4E2D\u7684\u7B2C\u4E8C\u4E2A\u4FE1\u53F7\uFF1A\u5DE6\u4FA7\u54C1\u724C\u8272\u7AD6\u6761\uFF08\u53EA\u9760\u5E95\u8272\u5728\u6D45\u8272\u4E3B\u9898\u4E0B\u4E0D\u591F\u660E\u663E\uFF09\u3002 */
2162
+ box-shadow: inset 2px 0 0 0 var(--dsw-alias-brand-primary);
2163
+ }
2164
+ .dchat-channelMark {
2165
+ display: inline-flex;
2166
+ align-items: center;
2167
+ justify-content: center;
2168
+ width: 22px;
2169
+ height: 22px;
2170
+ border-radius: 6px;
2171
+ background: var(--dsw-alias-bg-layer-2);
2172
+ border: 1px solid var(--dsw-alias-border-l2);
2173
+ font-size: 12px;
2174
+ font-weight: 600;
2175
+ flex: none;
2176
+ }
2177
+ .dchat-channelMarkIcon {
2178
+ width: auto;
2179
+ height: auto;
2180
+ border: 0;
2181
+ background: none;
2182
+ }
2183
+ .dchat-channelMarkIcon svg {
2184
+ width: 20px;
2185
+ height: 20px;
2186
+ display: block;
2187
+ }
2188
+ .dchat-channelLabel {
2189
+ min-width: 0;
2190
+ }
2191
+ .dchat-channelLabel strong {
2192
+ display: block;
2193
+ font-size: 13px;
2194
+ font-weight: 500;
2195
+ overflow: hidden;
2196
+ text-overflow: ellipsis;
2197
+ white-space: nowrap;
2198
+ }
2199
+ .dchat-panel {
2200
+ flex: 1;
2201
+ min-width: 0;
2202
+ display: flex;
2203
+ flex-direction: column;
2204
+ gap: 12px;
2205
+ }
2206
+ .dchat-card {
2207
+ border: 1px solid var(--dsw-alias-border-l2);
2208
+ border-radius: 10px;
2209
+ background: var(--dsw-alias-bg-layer-1);
2210
+ padding: 14px 16px;
2211
+ display: flex;
2212
+ flex-direction: column;
2213
+ gap: 10px;
2214
+ }
2215
+ .dchat-groupTitle {
2216
+ margin: 0;
2217
+ font-size: 12px;
2218
+ font-weight: 600;
2219
+ color: var(--dsw-alias-label-secondary);
2220
+ }
2221
+ .dchat-check {
2222
+ display: inline-flex;
2223
+ align-items: center;
2224
+ gap: 6px;
2225
+ font-size: 12px;
2226
+ color: var(--dsw-alias-label-secondary);
2227
+ white-space: nowrap;
2228
+ }
2229
+ .dchat-check input {
2230
+ margin: 0;
2231
+ }
2232
+ .dchat-policyGrid {
2233
+ display: flex;
2234
+ flex-direction: column;
2235
+ gap: 14px;
2236
+ }
2237
+ .dchat-policyGrid > * + * {
2238
+ border-top: 1px solid var(--dsw-alias-separator-primary);
2239
+ padding-top: 14px;
2240
+ }
2241
+ /* \u4F5C\u7528\u57DF\u6807\u9898\u884C\uFF1A\u6A21\u5F0F\u4E0B\u62C9\u6309\u5185\u5BB9\u5BBD\u5EA6\uFF0C\u4E0D\u8981\u50CF\u64CD\u4F5C\u884C\u91CC\u7684\u4E0B\u62C9\u90A3\u6837\u5403\u6389\u6574\u884C\u3002 */
2242
+ .dchat-policyHead {
2243
+ display: flex;
2244
+ align-items: center;
2245
+ gap: 8px;
2246
+ }
2247
+ .dchat-policyHead > select {
2248
+ width: auto;
2249
+ flex: none;
2250
+ }
2251
+ .dchat-actions > .dchat-check {
2252
+ flex: none;
2253
+ }
2254
+ /* \u5361\u7247\u5957\u5361\u7247\uFF08\u673A\u5668\u4EBA\u5361\u91CC\u653E\u6E20\u9053/\u673A\u5668\u4EBA\u7EA7\u8BBE\u7F6E\u5757\uFF09\u65F6\uFF0C\u5185\u5C42\u53BB\u8FB9\u6846\u3001\u6539\u6210\u5206\u9694\u7EBF\uFF1A
2255
+ \u4E24\u5C42\u8FB9\u6846 + \u4E24\u5C42 padding \u4F1A\u8BA9\u7F29\u8FDB\u548C\u89C6\u89C9\u91CD\u91CF\u90FD\u4E71\u6389\u3002 */
2256
+ .dchat-card .dchat-card {
2257
+ border: 0;
2258
+ border-radius: 0;
2259
+ background: transparent;
2260
+ padding: 12px 0 0;
2261
+ border-top: 1px solid var(--dsw-alias-separator-primary);
2262
+ }
2263
+ .dchat-cardHeader {
2264
+ display: flex;
2265
+ align-items: center;
2266
+ justify-content: space-between;
2267
+ gap: 8px 12px;
2268
+ /* \u653E\u4E0D\u4E0B\u65F6\u628A\u64CD\u4F5C\u6574\u5757\u6298\u5230\u4E0B\u4E00\u884C\uFF0C\u800C\u4E0D\u662F\u628A\u6807\u9898/\u63CF\u8FF0\u538B\u5230\u4E00\u5B57\u4E00\u884C\uFF1A
2269
+ \u4E2D\u6587\u7684 min-content \u53EA\u6709 1 \u4E2A\u5B57\uFF0Cflex \u4E00\u65E6\u538B\u7F29\u5C31\u4F1A\u9010\u5B57\u7AD6\u6392\uFF08\u89C1 .dchat-botRow \u540C\u6B3E\u5904\u7406\uFF09\u3002 */
2270
+ flex-wrap: wrap;
2271
+ }
2272
+ .dchat-cardHeading {
2273
+ /* \u957F\u6807\u9898\u9760\u7701\u7565\u53F7\u6536\uFF0C\u4E0D\u62A2\u64CD\u4F5C\u7684\u5BBD\u5EA6\u3002 */
2274
+ min-width: 0;
2275
+ }
2276
+ .dchat-cardTitle {
2277
+ font-size: 14px;
2278
+ font-weight: 600;
2279
+ overflow: hidden;
2280
+ text-overflow: ellipsis;
2281
+ white-space: nowrap;
2282
+ }
2283
+ .dchat-cardDescription {
2284
+ margin: 0;
2285
+ font-size: 12px;
2286
+ line-height: 1.6;
2287
+ color: var(--dsw-alias-label-secondary);
2288
+ }
2289
+ .dchat-list {
2290
+ display: flex;
2291
+ flex-direction: column;
2292
+ gap: 6px;
2293
+ margin: 0;
2294
+ padding: 0;
2295
+ list-style: none;
2296
+ }
2297
+ .dchat-listItem {
2298
+ display: flex;
2299
+ align-items: center;
2300
+ justify-content: space-between;
2301
+ gap: 10px;
2302
+ font-size: 12px;
2303
+ color: var(--dsw-alias-label-secondary);
2304
+ }
2305
+ /* \u540D\u5355/\u5C5E\u4E3B\u884C\u91CC\u7684 id \u53EF\u80FD\u5F88\u957F\uFF08open_id \u6709 35 \u5B57\u7B26\uFF09\u3002\u5B83\u662F flex \u9879\uFF0C\u9ED8\u8BA4 min-width:auto
2306
+ \u4E0D\u80AF\u7F29\uFF0C\u5C31\u4F1A\u628A\u540C\u6392\u7684\u6309\u94AE\u6324\u51FA\u5BB9\u5668\uFF08\u7A84\u680F\u76F4\u63A5\u6A2A\u5411\u6EA2\u51FA\uFF09\u3002 */
2307
+ .dchat-listItem .dchat-code {
2308
+ min-width: 0;
2309
+ max-width: 100%;
2310
+ overflow: hidden;
2311
+ text-overflow: ellipsis;
2312
+ white-space: nowrap;
2313
+ }
2314
+ /* \u5DE6\u4FA7\u7684\u6587\u5B57\uFF08\u540D\u5B57\u3001\u8BF4\u660E\uFF09\u5141\u8BB8\u6362\u884C\u3001\u5141\u8BB8\u6536\u7F29\u2014\u2014\u4E0D\u8BB8\u628A\u53F3\u4FA7\u7684\u64CD\u4F5C\u9876\u51FA\u53BB\u3002 */
2315
+ .dchat-listItem > :not(.dchat-actions) {
2316
+ min-width: 0;
2317
+ overflow-wrap: anywhere;
2318
+ }
2319
+ /* \u767D\u540D\u5355\u884C\uFF1A\u540D\u5B57 + id \u653E\u540C\u4E00\u4E2A\u5757\u91CC\uFF08id \u624D\u662F\u5224\u5B9A\u7528\u7684\u503C\uFF0C\u540D\u5B57\u53EA\u662F\u7ED9\u4EBA\u770B\u7684\uFF09\u3002
2320
+ \u4E24\u4E2A\u90FD\u5141\u8BB8\u6536\u7F29\u5E76\u7701\u7565\u53F7\uFF0C\u8C01\u957F\u8C01\u8BA9\u4F4D\u2014\u2014\u540D\u5B57\u5F88\u957F\u65F6\u4E0D\u8BB8\u628A id \u9876\u51FA\u5BB9\u5668\u3002 */
2321
+ .dchat-policyEntry {
2322
+ display: flex;
2323
+ align-items: baseline;
2324
+ gap: 6px;
2325
+ min-width: 0;
2326
+ }
2327
+ .dchat-policyEntry > * {
2328
+ min-width: 0;
2329
+ overflow: hidden;
2330
+ text-overflow: ellipsis;
2331
+ white-space: nowrap;
2332
+ }
2333
+ .dchat-policyName {
2334
+ color: var(--dsw-alias-label-primary);
2335
+ }
2336
+ .dchat-code {
2337
+ font-family: var(--dsw-font-markdown-code-block-small, ui-monospace, SFMono-Regular, monospace);
2338
+ font-size: 12px;
2339
+ padding: 1px 5px;
2340
+ border-radius: 4px;
2341
+ background: var(--dsw-alias-markdown-code-block);
2342
+ color: var(--dsw-alias-label-primary);
2343
+ }
2344
+ .dchat-solo {
2345
+ display: flex;
2346
+ flex-direction: column;
2347
+ gap: 12px;
2348
+ flex: 1;
2349
+ min-height: 0;
2350
+ overflow-y: auto;
2351
+ /* \u8FDB\u4E86\u673A\u5668\u4EBA\u8BBE\u7F6E\u5C31\u5360\u6EE1\u6574\u5BBD\uFF1A\u5DE6\u680F\u6E20\u9053\u5217\u8868\u6B64\u65F6\u6CA1\u6709\u610F\u4E49\u3002 */
2352
+ width: 100%;
2353
+ }
2354
+ .dchat-panelBar {
2355
+ display: flex;
2356
+ align-items: center;
2357
+ gap: 8px;
2358
+ }
2359
+ .dchat-botList {
2360
+ display: flex;
2361
+ flex-direction: column;
2362
+ gap: 8px;
2363
+ margin: 0;
2364
+ padding: 0;
2365
+ list-style: none;
2366
+ }
2367
+ .dchat-botRow {
2368
+ display: flex;
2369
+ align-items: center;
2370
+ justify-content: space-between;
2371
+ gap: 12px;
2372
+ border: 1px solid var(--dsw-alias-border-l2);
2373
+ border-radius: 8px;
2374
+ padding: 10px 12px;
2375
+ }
2376
+ /* \u300C\u8BBE\u7F6E\u300D\u6309\u94AE\u6C38\u8FDC\u662F\u5185\u5BB9\u5BBD\u5EA6\uFF1Aflex \u9ED8\u8BA4\u7684 min-width:auto \u4F1A\u8BA9\u5B83\u5728\u7A84\u680F\u91CC\u88AB\u538B\u6210\u4E00\u4E2A\u5B57\u5BBD\u3002 */
2377
+ .dchat-grip {
2378
+ /*
2379
+ * \u62D6\u52A8\u628A\u624B\uFF1A\u53EA\u80FD\u62D6\u5B83\uFF0C\u4E0D\u8BA9\u6574\u884C\u53EF\u62D6\u2014\u2014\u6574\u884C\u53EF\u62D6\u4F1A\u4E0E"\u70B9\u4E00\u4E0B\u5207\u6362\u6E20\u9053/\u673A\u5668\u4EBA"\u62A2\u624B\u52BF\uFF0C
2380
+ * \u800C\u4E14 button \u5143\u7D20\u5728\u90E8\u5206\u6D4F\u89C8\u5668\u4E0A draggable \u4E0D\u751F\u6548\u3002\u79FB\u52A8\u7AEF\u4E0D\u652F\u6301 HTML5 \u62D6\u653E\uFF0C
2381
+ * \u6240\u4EE5\u5B83\u53EA\u662F\u684C\u9762\u7AEF\u7684\u4FBF\u5229\u529F\u80FD\uFF08\u987A\u5E8F\u672C\u8EAB\u4E0D\u5F71\u54CD\u4EFB\u4F55\u884C\u4E3A\uFF09\u3002
2382
+ */
2383
+ flex: none;
2384
+ cursor: grab;
2385
+ color: var(--dsw-alias-label-tertiary);
2386
+ font-size: 12px;
2387
+ line-height: 1;
2388
+ letter-spacing: -1px;
2389
+ user-select: none;
2390
+ }
2391
+ .dchat-grip:active {
2392
+ cursor: grabbing;
2393
+ }
2394
+ /* \u62D6\u52A8\u7ECF\u8FC7\u7684\u53EF\u843D\u70B9\uFF1A\u53EA\u505A\u9AD8\u4EAE\uFF0C\u4E0D\u6539\u5E03\u5C40\uFF08\u6539\u52A8\u5E03\u5C40\u4F1A\u8BA9\u62D6\u52A8\u624B\u611F\u6296\uFF09\u3002 */
2395
+ .dchat-dropTarget {
2396
+ border-color: var(--dsw-alias-brand-primary) !important;
2397
+ box-shadow: inset 0 0 0 1px var(--dsw-alias-brand-primary);
2398
+ }
2399
+ .dchat-botRow > .dchat-button {
2400
+ flex: none;
2401
+ }
2402
+ .dchat-botMain {
2403
+ display: flex;
2404
+ flex-direction: column;
2405
+ gap: 4px;
2406
+ flex: 1 1 auto;
2407
+ min-width: 0;
2408
+ }
2409
+ .dchat-botTitle {
2410
+ display: flex;
2411
+ align-items: center;
2412
+ gap: 8px;
2413
+ font-size: 13px;
2414
+ min-width: 0;
2415
+ }
2416
+ /* \u540D\u79F0\uFF08\u53EF\u80FD\u662F\u5F88\u957F\u7684 botId\uFF09\u8D1F\u8D23\u622A\u65AD\uFF0C\u72B6\u6001\u70B9\u4FDD\u6301\u81EA\u8EAB\u5BBD\u5EA6\u4E0D\u88AB\u538B\u7F29\u3002 */
2417
+ .dchat-botTitle > strong {
2418
+ min-width: 0;
2419
+ overflow: hidden;
2420
+ text-overflow: ellipsis;
2421
+ white-space: nowrap;
2422
+ }
2423
+ .dchat-botTitle > :not(strong) {
2424
+ flex: none;
2425
+ white-space: nowrap;
2426
+ }
2427
+ .dchat-botMeta {
2428
+ display: flex;
2429
+ align-items: center;
2430
+ gap: 10px;
2431
+ font-size: 12px;
2432
+ color: var(--dsw-alias-label-tertiary);
2433
+ /* \u653E\u4E0D\u4E0B\u5C31\u6574\u9879\u6362\u884C\uFF0C\u7EDD\u4E0D\u8BA9\u4E2D\u6587\u6309\u5B57\u6298\u884C\uFF08\u6BCF\u4E2A\u6C49\u5B57\u90FD\u662F\u65AD\u884C\u70B9\uFF0C\u4F1A\u88AB\u538B\u6210\u7AD6\u6392\uFF09\u3002 */
2434
+ flex-wrap: wrap;
2435
+ }
2436
+ .dchat-botMeta > * {
2437
+ white-space: nowrap;
2438
+ /*
2439
+ * \u52A0\u62D6\u52A8\u628A\u624B\u4E4B\u540E\u7A84\u680F\uFF08320px\uFF09\u4F1A\u5DEE\u51E0\u4E2A\u50CF\u7D20\uFF1Aflex \u9879\u9ED8\u8BA4 min-width:auto \u4E0D\u4F1A\u7F29\uFF0C
2440
+ * \u4E8E\u662F\u300C\u6700\u8FD1 09-19 10:21\u300D\u6574\u5757\u9876\u51FA\u53BB\u3002\u5141\u8BB8\u8FD9\u4E9B\u7247\u6BB5\u81EA\u5DF1\u6536\u6210\u7701\u7565\u53F7\uFF0C
2441
+ * \u800C\u4E0D\u662F\u628A\u6574\u884C\u6491\u7834\u2014\u2014\u6807\u9898\u4E0E\u540D\u79F0\u5728\u4E0A\u9762\u4E00\u884C\uFF0C\u4ECD\u7136\u8BFB\u5F97\u5230\u3002
2442
+ */
2443
+ min-width: 0;
2444
+ overflow: hidden;
2445
+ text-overflow: ellipsis;
2446
+ }
2447
+ /* \u8D26\u53F7\u53EF\u80FD\u5F88\u957F\uFF1A\u8BA9\u5B83\u7701\u7565\u53F7\u622A\u65AD\uFF0C\u522B\u628A\u5361\u7247\u6491\u7834\uFF08flex \u9879\u9ED8\u8BA4 min-width:auto \u4E0D\u4F1A\u7F29\uFF09\u3002 */
2448
+ .dchat-botMeta > .dchat-code {
2449
+ min-width: 0;
2450
+ max-width: 100%;
2451
+ overflow: hidden;
2452
+ text-overflow: ellipsis;
2453
+ }
2454
+ .dchat-botError {
2455
+ font-size: 12px;
2456
+ color: var(--dsw-alias-state-error-primary);
2457
+ word-break: break-word;
2458
+ }
2459
+ .dchat-versionMeta {
2460
+ display: inline-flex;
2461
+ align-items: center;
2462
+ gap: 8px;
2463
+ }
2464
+ /* \u8BCA\u65AD\u9762\u677F\u91CC\u7684\u6E20\u9053\u5757\u5934\uFF1A\u6807\u9898\u4E0E\u72B6\u6001\u70B9\u5728\u4E24\u4FA7\uFF0C\u653E\u4E0D\u4E0B\u5C31\u6574\u5757\u6362\u884C\u3002 */
2465
+ .dchat-diagHead {
2466
+ display: flex;
2467
+ align-items: center;
2468
+ justify-content: space-between;
2469
+ gap: 8px;
2470
+ flex-wrap: wrap;
2471
+ }
2472
+ /* \u6807\u9898\u4E0D\u6298\u884C\uFF08\u6298\u4E86\u5C31\u662F"\u9010\u5B57\u7AD6\u6392"\uFF09\u2014\u2014\u5B83\u6574\u5757\u6362\u884C\u9760\u4E0A\u9762\u90A3\u6761 wrap\u3002 */
2473
+ .dchat-diagHead > .dchat-groupTitle {
2474
+ white-space: nowrap;
2475
+ }
2476
+ /* \u8BCA\u65AD\u9762\u677F\u91CC\u6BCF\u4E2A\u6E20\u9053/\u6BCF\u4E2A\u65E5\u5FD7\u5404\u4E00\u5757\uFF1A\u7AD6\u6392\u3002
2477
+ .dchat-entry \u662F"\u53EF\u70B9\u51FB\u7684\u6298\u53E0\u884C"\uFF08\u6A2A\u6392\uFF09\uFF0C\u62FF\u6765\u88C5\u8FD9\u4E9B\u5757\u4F1A\u628A\u5B83\u4EEC\u6324\u6210\u4E00\u6761\u6761\u7EC6\u6761\u3002 */
2478
+ .dchat-diagSection {
2479
+ display: flex;
2480
+ flex-direction: column;
2481
+ gap: 6px;
2482
+ width: 100%;
2483
+ }
2484
+ .dchat-diagSection > .dchat-list {
2485
+ min-width: 0;
2486
+ }
2487
+ /* \u673A\u5668\u4EBA\u5757\uFF1A\u72B6\u6001\u884C + \u82E5\u5E72\u884C\u9519\u8BEF/\u63D0\u793A\uFF0C\u7AD6\u76F4\u6392\u5217\u3002 */
2488
+ .dchat-diagBot {
2489
+ display: flex;
2490
+ flex-direction: column;
2491
+ gap: 4px;
2492
+ min-width: 0;
2493
+ }
2494
+ /* \u8BCA\u65AD\u9762\u677F\u91CC\u7684\u673A\u5668\u4EBA\u884C\uFF1A\u4E00\u884C\u653E\u4E0D\u4E0B\u65F6\u6574\u4F53\u6362\u884C\uFF0C\u800C\u4E0D\u662F\u628A id \u9876\u51FA\u5BB9\u5668\u3002
2495
+ min-width: 0 \u662F\u5FC5\u987B\u7684\uFF1A\u8FD9\u4E9B\u5757\u7684\u5185\u5BB9\uFF0835 \u5B57\u7B26\u7684 open_id\uFF09\u4F1A\u628A flex \u9879\u7684
2496
+ min-width: auto \u6491\u6210 min-content\uFF0C\u4E8E\u662F\u6574\u5757\u6BD4\u5361\u7247\u8FD8\u5BBD\u3001\u628A\u9875\u9762\u9876\u51FA\u6EDA\u52A8\u6761\uFF08\u771F\u673A\u6D4B\u5230\u8FC7\uFF09\u3002 */
2497
+ .dchat-diagRow {
2498
+ flex-wrap: wrap;
2499
+ min-width: 0;
2500
+ }
2501
+ .dchat-diagRow > .dchat-code {
2502
+ flex: 1 1 auto;
2503
+ min-width: 0;
2504
+ }
2505
+ .dchat-diagRow > .dchat-diagMeta {
2506
+ flex: 0 1 auto;
2507
+ min-width: 0;
2508
+ }
2509
+ /* \u8BCA\u65AD\u9762\u677F\u91CC\u673A\u5668\u4EBA\u884C\u7684\u53F3\u4FA7\u5143\u4FE1\u606F\uFF08\u72B6\u6001 \xB7 \u5DF2\u5904\u7406 \xB7 \u65F6\u95F4\uFF09\u3002
2510
+ \u6574\u5757\u4E0D\u6298\u884C\uFF08\u6298\u4E86\u5C31\u6210\u4E86"\u9010\u5B57\u7AD6\u6392"\uFF09\uFF0C\u653E\u4E0D\u4E0B\u65F6\u9760 .dchat-diagRow \u6362\u884C\u3002 */
2511
+ .dchat-diagMeta {
2512
+ font-size: 12px;
2513
+ color: var(--dsw-alias-label-secondary);
2514
+ white-space: nowrap;
2515
+ }
2516
+ /* \u65E5\u5FD7\u5C3E\u90E8\uFF1A\u7B49\u5BBD\u3001\u9650\u9AD8\u3001\u53CC\u5411\u53EF\u6EDA\uFF08\u6EDA\u52A8\u53D1\u751F\u5728\u5757\u5185\uFF0C\u4E0D\u4F1A\u628A\u6574\u9875\u6491\u5BBD\uFF09\u3002 */
2517
+ .dchat-logTail {
2518
+ white-space: pre;
2519
+ max-height: 220px;
2520
+ overflow: auto;
2521
+ font-size: 11px;
2522
+ line-height: 1.5;
2523
+ }
2524
+ .dchat-updateHint {
2525
+ display: flex;
2526
+ flex-direction: column;
2527
+ gap: 6px;
2528
+ margin: 0;
2529
+ }
2530
+ .dchat-codeBlock {
2531
+ display: block;
2532
+ padding: 6px 8px;
2533
+ overflow-x: auto;
2534
+ white-space: nowrap;
2535
+ }
2536
+ .dchat-empty {
2537
+ display: flex;
2538
+ flex-direction: column;
2539
+ gap: 8px;
2540
+ align-items: flex-start;
2541
+ border: 1px dashed var(--dsw-alias-border-l3);
2542
+ border-radius: 10px;
2543
+ padding: 18px;
2544
+ color: var(--dsw-alias-label-secondary);
2545
+ }
2546
+ .dchat-emptyTitle {
2547
+ font-size: 14px;
2548
+ font-weight: 600;
2549
+ color: var(--dsw-alias-label-primary);
2550
+ }
2551
+ .dchat-actions {
2552
+ display: flex;
2553
+ gap: 8px;
2554
+ align-items: center;
2555
+ /* \u64CD\u4F5C\u5757\u53EF\u4EE5\u7F29\u5230"\u6700\u5BBD\u7684\u90A3\u4E2A\u6309\u94AE"\uFF0C\u8FD9\u6837\u4E0B\u9762\u90A3\u6761 flex-wrap \u624D\u4F1A\u771F\u7684\u751F\u6548\u3002
2556
+ \u66FE\u7ECF\u5199\u7684\u662F flex: none\uFF1A\u5185\u5BB9\u518D\u5BBD\u4E5F\u4E0D\u7F29\uFF0C\u4E8E\u662F\u7A84\u680F\u91CC\uFF08320px \u7684 hub \u9875\u5934\uFF09
2557
+ \u6574\u5757\u76F4\u63A5\u9876\u51FA\u5BB9\u5668 15px \u2014\u2014 \u6B63\u662F\u5E03\u5C40\u5B88\u95E8\u91CF\u51FA\u6765\u7684\u90A3\u4E00\u6761\u3002
2558
+ \u6309\u94AE\u81EA\u8EAB\u4ECD\u662F flex: none\uFF0C\u4E0D\u4F1A\u51FA\u73B0"\u9010\u5B57\u7AD6\u6392"\u3002 */
2559
+ flex: 0 1 auto;
2560
+ min-width: 0;
2561
+ /* \u653E\u4E0D\u4E0B\u65F6\u6309\u94AE\u81EA\u5DF1\u6362\u884C\uFF0C\u800C\u4E0D\u662F\u628A\u6574\u5757\u9876\u51FA\u5BB9\u5668\uFF08\u7A84\u680F\u91CC"\u4E0B\u62C9+\u4E24\u4E2A\u6309\u94AE"\u5C31\u4F1A\u6EA2\u51FA\uFF09\u3002 */
2562
+ flex-wrap: wrap;
2563
+ }
2564
+ /* \u53EA\u7ED9\u5361\u7247\u5934\u7528\uFF1A\u6298\u5230\u7B2C\u4E8C\u884C\u65F6\u4ECD\u7136\u9760\u53F3\u3002
2565
+ \u4E0D\u80FD\u5199\u5728 .dchat-actions \u4E0A\u2014\u2014auto \u5916\u8FB9\u8DDD\u4F1A\u53D6\u6D88\u4EA4\u53C9\u8F74\u7684 stretch\uFF0C
2566
+ \u8BA9"\u7AD6\u6392\u5BB9\u5668\u91CC\u7684\u64CD\u4F5C\u884C"\u9000\u5316\u6210\u5185\u5BB9\u5BBD\u5EA6\uFF08\u53D1\u9001\u884C\u7684\u4E0B\u62C9\u6846\u5C31\u7F29\u6210\u4E00\u5C0F\u622A\uFF09\u3002 */
2567
+ .dchat-cardHeader > .dchat-actions {
2568
+ margin-left: auto;
2569
+ }
2570
+ .dchat-actions > * {
2571
+ white-space: nowrap;
2572
+ }
2573
+ /* \u53EA\u6709\u6309\u94AE\u548C\u72B6\u6001\u70B9"\u6C38\u4E0D\u538B\u7F29"\uFF1B\u8F93\u5165\u7C7B\u5FC5\u987B\u80FD\u7F29\uFF0C\u5426\u5219\u4F1A\u6491\u51FA\u6A2A\u5411\u6EDA\u52A8\uFF1A
2574
+ .dchat-select \u662F width:100%\uFF0C\u914D flex:none \u4F1A\u5148\u5360\u6EE1\u6574\u884C\uFF0C\u518D\u628A\u540C\u6392\u7684\u6309\u94AE\u6324\u51FA\u5BB9\u5668\u3002 */
2575
+ .dchat-actions > .dchat-button,
2576
+ .dchat-actions > .dchat-status {
2577
+ flex: none;
2578
+ }
2579
+ .dchat-actions > select,
2580
+ .dchat-actions > input {
2581
+ flex: 1 1 0;
2582
+ min-width: 0;
2583
+ width: auto;
2584
+ }
2585
+ .dchat-button {
2586
+ border: 1px solid var(--dsw-alias-border-l2);
2587
+ border-radius: 6px;
2588
+ background: transparent;
2589
+ color: inherit;
2590
+ font: inherit;
2591
+ font-size: 12px;
2592
+ padding: 4px 10px;
2593
+ cursor: pointer;
2594
+ /* \u4E2D\u6587\u6309\u94AE\u88AB\u538B\u7A84\u65F6\u4F1A\u4E8C\u5B57\u7AD6\u6392\uFF0C\u4EFB\u4F55\u6309\u94AE\u90FD\u4E0D\u5141\u8BB8\u6298\u884C\u3002 */
2595
+ white-space: nowrap;
2596
+ }
2597
+ .dchat-button:hover:not(:disabled) {
2598
+ background: var(--dsw-alias-interactive-bg-hover);
2599
+ }
2600
+ .dchat-button:disabled {
2601
+ opacity: 0.5;
2602
+ cursor: not-allowed;
2603
+ }
2604
+ /* \u6B21\u8981\u5165\u53E3\uFF08\u5982\u300C\u7248\u672C\u4E0E\u66F4\u65B0\u300D\uFF09\uFF1A\u6587\u5B57\u94FE\u63A5\u5F62\u6001\uFF0C\u4E0D\u548C DSH \u81EA\u5DF1\u7684\u5B9E\u5FC3\u6309\u94AE\u62A2\u6CE8\u610F\u529B\u3002 */
2605
+ .dchat-buttonLink {
2606
+ border-color: transparent;
2607
+ background: transparent;
2608
+ color: var(--dsw-alias-link);
2609
+ padding-left: 4px;
2610
+ padding-right: 4px;
2611
+ }
2612
+ .dchat-buttonLink:hover:not(:disabled) {
2613
+ background: transparent;
2614
+ text-decoration: underline;
2615
+ }
2616
+ /* \u4E0D\u53EF\u9006\u64CD\u4F5C\uFF1A\u89E6\u53D1\u6309\u94AE\u53EA\u67D3\u6587\u5B57\uFF0C\u786E\u8BA4\u6309\u94AE\u624D\u7528\u5B9E\u5E95\uFF0C\u907F\u514D\u4E24\u4E2A\u540C\u7EA7\u7070\u6309\u94AE\u91CC\u85CF\u7740\u5220\u9664\u3002 */
2617
+ .dchat-buttonDanger {
2618
+ color: var(--dsw-alias-state-error-primary);
2619
+ }
2620
+ .dchat-buttonDangerSolid {
2621
+ background: var(--dsw-alias-state-error-primary);
2622
+ border-color: transparent;
2623
+ color: #fff;
2624
+ }
2625
+ .dchat-buttonDangerSolid:hover:not(:disabled) {
2626
+ background: var(--dsw-alias-state-error-primary);
2627
+ opacity: 0.88;
2628
+ }
2629
+ .dchat-status {
2630
+ display: inline-flex;
2631
+ align-items: center;
2632
+ gap: 5px;
2633
+ font-size: 11px;
2634
+ color: var(--dsw-alias-label-tertiary);
2635
+ /* \u72B6\u6001\u70B9\u81EA\u5DF1\u6C38\u8FDC\u4E0D\u6298\u884C\u4E5F\u4E0D\u538B\u7F29\uFF08\u7A84\u680F\u91CC\u66FE\u88AB\u538B\u6210\u300C\u8FD0\u884C\u6B63/\u5E38\u300D\uFF09\u3002 */
2636
+ flex: none;
2637
+ white-space: nowrap;
2638
+ }
2639
+ .dchat-status::before {
2640
+ content: '';
2641
+ width: 6px;
2642
+ height: 6px;
2643
+ border-radius: 50%;
2644
+ background: currentColor;
2645
+ }
2646
+ .dchat-status[data-tone='success'] { color: var(--dsw-alias-state-success-primary); }
2647
+ .dchat-status[data-tone='warning'] { color: var(--dsw-alias-state-warn-primary); }
2648
+ .dchat-status[data-tone='error'] { color: var(--dsw-alias-state-error-primary); }
2649
+ .dchat-error {
2650
+ font-size: 12px;
2651
+ color: var(--dsw-alias-state-error-primary);
2652
+ }
2653
+ /* \u90E8\u5206\u6210\u529F\u7684\u544A\u8B66\uFF08\u4F8B\uFF1A\u673A\u5668\u4EBA\u52A0\u4E0A\u4E86\u3001\u4F46\u987A\u5E26\u90A3\u6B65\u6CA1\u505A\u6210\uFF09\uFF1A\u4E0D\u662F\u5931\u8D25\uFF0C\u4F46\u7EDD\u4E0D\u80FD\u4E0D\u8BF4\u3002 */
2654
+ .dchat-warning {
2655
+ font-size: 12px;
2656
+ color: var(--dsw-alias-state-warn-primary);
2657
+ }
2658
+ .dchat-buttonPrimary {
2659
+ background: var(--dsw-alias-brand-primary);
2660
+ border-color: transparent;
2661
+ color: #fff;
2662
+ }
2663
+ /* \u63A5\u5165\u8868\u5355\uFF1A\u4E24\u6761\u8DEF\uFF08\u626B\u7801\u65B0\u5EFA / \u624B\u52A8\u63A5\u5165\uFF09\u5404\u5360\u4E00\u6BB5\uFF0C\u6BB5\u95F4\u4E00\u6761\u7EC6\u7EBF\u3002 */
2664
+ .dchat-onboardSection {
2665
+ display: flex;
2666
+ flex-direction: column;
2667
+ gap: 8px;
2668
+ min-width: 0;
2669
+ }
2670
+ .dchat-onboardTitle {
2671
+ margin: 0;
2672
+ font-size: 13px;
2673
+ font-weight: 600;
2674
+ color: var(--dsw-alias-label-primary);
2675
+ }
2676
+ .dchat-onboardDivider {
2677
+ width: 100%;
2678
+ margin: 14px 0;
2679
+ border: 0;
2680
+ border-top: 1px solid var(--dsw-alias-border-l2);
2681
+ }
2682
+ /* \u4E8C\u7EF4\u7801\uFF1A\u56FA\u5B9A\u5C3A\u5BF8\u3001\u522B\u88AB flex \u538B\u6241\uFF08\u7A84\u680F\u91CC width:100% \u7684\u56FE\u7247\u4F1A\u53D8\u5F62\uFF09\u3002 */
2683
+ .dchat-onboardQr {
2684
+ flex: none;
2685
+ align-self: flex-start;
2686
+ border-radius: 6px;
2687
+ background: #fff;
2688
+ }
2689
+ .dchat-onboardLink {
2690
+ color: var(--dsw-alias-brand-primary);
2691
+ font-size: 12px;
2692
+ overflow-wrap: anywhere;
2693
+ }
2694
+ .dchat-entry {
2695
+ display: flex;
2696
+ align-items: center;
2697
+ gap: 10px;
2698
+ width: 100%;
2699
+ padding: 10px 12px;
2700
+ border: 1px solid var(--dsw-alias-border-l2);
2701
+ border-radius: 8px;
2702
+ background: var(--dsw-alias-bg-layer-1);
2703
+ color: inherit;
2704
+ font: inherit;
2705
+ text-align: left;
2706
+ cursor: pointer;
2707
+ }
2708
+ .dchat-entry:hover:not(:disabled) {
2709
+ background: var(--dsw-alias-interactive-bg-hover);
2710
+ }
2711
+ .dchat-entry:disabled {
2712
+ opacity: 0.6;
2713
+ cursor: not-allowed;
2714
+ }
2715
+ .dchat-entryLabel {
2716
+ font-size: 13px;
2717
+ font-weight: 500;
2718
+ }
2719
+ .dchat-entryStatus {
2720
+ font-size: 12px;
2721
+ color: var(--dsw-alias-label-tertiary);
2722
+ margin-left: auto;
2723
+ }
2724
+ .dchat-entryStatus[data-active='true'] {
2725
+ color: var(--dsw-alias-state-success-primary);
2726
+ }
2727
+ .dchat-entryArrow {
2728
+ color: var(--dsw-alias-label-tertiary);
2729
+ }
2730
+ /* \u6298\u53E0\u6001\u7684\u5165\u53E3\u884C\u653E\u5728\u5361\u7247\u91CC\u65F6\uFF0C\u8DDF\u5185\u5C42\u8BBE\u7F6E\u5757\u7528\u540C\u4E00\u79CD\u5F62\u6001\uFF08\u5206\u9694\u7EBF + \u6574\u5BBD + \u540C\u5B57\u53F7\u6807\u9898\uFF09\uFF0C
2731
+ \u5426\u5219\u5B83 40px \u9AD8\u7684\u5706\u89D2\u5C0F\u76D2\u5B50\u5939\u5728\u4E24\u5F20\u5C55\u5F00\u5361\u7247\u4E2D\u95F4\uFF0C\u770B\u8D77\u6765\u50CF\u6839\u5206\u9694\u7EBF\u3002 */
2732
+ .dchat-card .dchat-entry {
2733
+ width: 100%;
2734
+ border: 0;
2735
+ border-top: 1px solid var(--dsw-alias-separator-primary);
2736
+ border-radius: 0;
2737
+ background: transparent;
2738
+ padding: 12px 0 0;
2739
+ }
2740
+ .dchat-card .dchat-entry .dchat-entryLabel {
2741
+ font-size: 14px;
2742
+ font-weight: 600;
2743
+ }
2744
+ .dchat-backdrop {
2745
+ position: fixed;
2746
+ inset: 0;
2747
+ background: rgba(0, 0, 0, 0.45);
2748
+ display: flex;
2749
+ align-items: flex-start;
2750
+ justify-content: center;
2751
+ padding: 40px 16px;
2752
+ overflow: auto;
2753
+ /* \u8BBE\u7F6E\u5F39\u5C42\u81EA\u8EAB\u662F fixed + z-index:1000\uFF0C\u6E20\u9053\u5F39\u7A97\u5FC5\u987B\u538B\u5728\u5176\u4E0A\u3002 */
2754
+ z-index: 1100;
2755
+ }
2756
+ .dchat-dialog {
2757
+ width: min(640px, 100%);
2758
+ /* \u81EA\u5DF1\u6EDA\uFF0C\u800C\u4E0D\u662F\u8BA9\u5916\u5C42\u6EDA\u52A8\uFF1A\u5426\u5219\u5185\u5BB9\u53D8\u9AD8\u65F6\u5E95\u90E8\u6309\u94AE\u4F1A\u6389\u51FA\u89C6\u53E3\u3002 */
2759
+ max-height: calc(100vh - 80px);
2760
+ box-sizing: border-box;
2761
+ overflow: auto;
2762
+ background: var(--dsw-alias-bg-base);
2763
+ border: 1px solid var(--dsw-alias-border-l2);
2764
+ border-radius: 12px;
2765
+ padding: 16px 18px;
2766
+ display: flex;
2767
+ flex-direction: column;
2768
+ gap: 12px;
2769
+ }
2770
+ .dchat-dialogHeader {
2771
+ display: flex;
2772
+ align-items: center;
2773
+ justify-content: space-between;
2774
+ gap: 10px;
2775
+ }
2776
+ .dchat-dialogFooter {
2777
+ display: flex;
2778
+ justify-content: flex-end;
2779
+ gap: 8px;
2780
+ /* \u5185\u5BB9\u5F88\u957F\u65F6\u6309\u94AE\u59CB\u7EC8\u7C98\u5728\u5F39\u7A97\u5E95\u90E8\u3002 */
2781
+ position: sticky;
2782
+ bottom: -16px;
2783
+ margin: 0 -18px -16px;
2784
+ padding: 10px 18px 14px;
2785
+ background: var(--dsw-alias-bg-base);
2786
+ border-top: 1px solid var(--dsw-alias-border-l2);
2787
+ }
2788
+ .dchat-tabs {
2789
+ display: flex;
2790
+ gap: 6px;
2791
+ border-bottom: 1px solid var(--dsw-alias-border-l2);
2792
+ }
2793
+ .dchat-tab {
2794
+ border: none;
2795
+ background: transparent;
2796
+ color: var(--dsw-alias-label-secondary);
2797
+ font: inherit;
2798
+ font-size: 13px;
2799
+ padding: 6px 10px;
2800
+ border-bottom: 2px solid transparent;
2801
+ cursor: pointer;
2802
+ }
2803
+ .dchat-tab[aria-selected='true'] {
2804
+ color: var(--dsw-alias-label-primary);
2805
+ border-bottom-color: var(--dsw-alias-brand-primary);
2806
+ }
2807
+ .dchat-tabPanel {
2808
+ display: flex;
2809
+ flex-direction: column;
2810
+ gap: 14px;
2811
+ }
2812
+ .dchat-tabPanel[hidden] {
2813
+ display: none;
2814
+ }
2815
+ /*
2816
+ * hidden \u5C5E\u6027\u9760 UA \u6837\u5F0F\u91CC\u7684 [hidden]{display:none} \u751F\u6548\uFF0C\u800C\u4E0A\u9762\u90A3\u6761 display:flex \u662F\u4F5C\u8005\u6837\u5F0F
2817
+ * \u2014\u2014\u4F18\u5148\u7EA7\u66F4\u9AD8\uFF0C\u4E8E\u662F"\u9690\u85CF"\u7684\u9875\u7B7E\u7167\u6837\u663E\u793A\uFF1A\u79C1\u804A\u4E0E\u7FA4\u804A\u4E24\u4E2A\u9875\u7B7E\u770B\u8D77\u6765\u4E00\u6A21\u4E00\u6837\uFF08\u771F\u673A\u622A\u56FE\u5C31\u662F
2818
+ * \u4E24\u5F20\u5185\u5BB9\u5B8C\u5168\u76F8\u540C\u7684\u9875\u7B7E\uFF09\u3002\u4EFB\u4F55\u7ED9\u5143\u7D20\u5199\u4E86 display \u7684\u5730\u65B9\uFF0C\u7528 hidden \u90FD\u8981\u8865\u8FD9\u6761\u3002
2819
+ * \u6CE8\u610F\uFF1A\u672C\u6587\u4EF6\u662F\u6A21\u677F\u5B57\u7B26\u4E32\uFF0C\u6CE8\u91CA\u91CC**\u4E0D\u80FD\u51FA\u73B0\u53CD\u5F15\u53F7**\uFF08\u4F1A\u628A\u6A21\u677F\u63D0\u524D\u95ED\u5408\uFF0C\u5386\u53F2\u4E0A\u683D\u8FC7\u4E00\u6B21\uFF09\u3002
2820
+ */
2821
+
2822
+ .dchat-contextGlobal,
2823
+ .dchat-contextTargets {
2824
+ display: flex;
2825
+ flex-direction: column;
2826
+ gap: 8px;
2827
+ }
2828
+ .dchat-contextSwitchRow {
2829
+ display: flex;
2830
+ align-items: center;
2831
+ justify-content: space-between;
2832
+ gap: 10px;
2833
+ }
2834
+ .dchat-contextSwitchLabel {
2835
+ font-size: 13px;
2836
+ }
2837
+ .dchat-contextLegendRow,
2838
+ .dchat-contextLegend {
2839
+ font-size: 12px;
2840
+ color: var(--dsw-alias-label-secondary);
2841
+ }
2842
+ .dchat-contextFields {
2843
+ display: grid;
2844
+ grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
2845
+ gap: 4px 12px;
2846
+ }
2847
+ .dchat-contextField {
2848
+ display: flex;
2849
+ align-items: center;
2850
+ gap: 6px;
2851
+ font-size: 12px;
2852
+ }
2853
+ .dchat-contextField code {
2854
+ font-size: 11px;
2855
+ color: var(--dsw-alias-label-tertiary);
2856
+ }
2857
+ .dchat-contextGuidance {
2858
+ display: flex;
2859
+ flex-direction: column;
2860
+ gap: 6px;
2861
+ }
2862
+ .dchat-contextGuidanceHeader {
2863
+ display: flex;
2864
+ align-items: center;
2865
+ justify-content: space-between;
2866
+ gap: 10px;
2867
+ }
2868
+ .dchat-textarea,
2869
+ .dchat-targetField input,
2870
+ .dchat-input,
2871
+ .dchat-select {
2872
+ width: 100%;
2873
+ box-sizing: border-box;
2874
+ border: 1px solid var(--dsw-alias-border-l2);
2875
+ border-radius: 6px;
2876
+ background: var(--dsw-alias-bg-layer-1);
2877
+ color: inherit;
2878
+ font: inherit;
2879
+ font-size: 12px;
2880
+ padding: 6px 8px;
2881
+ }
2882
+ .dchat-textarea {
2883
+ resize: vertical;
2884
+ min-height: 72px;
2885
+ }
2886
+ .dchat-targetList {
2887
+ display: flex;
2888
+ flex-direction: column;
2889
+ gap: 10px;
2890
+ margin: 0;
2891
+ padding: 0;
2892
+ list-style: none;
2893
+ }
2894
+ .dchat-targetRow {
2895
+ border: 1px solid var(--dsw-alias-border-l2);
2896
+ border-radius: 8px;
2897
+ padding: 10px 12px;
2898
+ display: flex;
2899
+ flex-direction: column;
2900
+ gap: 8px;
2901
+ background: var(--dsw-alias-bg-layer-1);
2902
+ }
2903
+ .dchat-targetHead {
2904
+ display: flex;
2905
+ align-items: center;
2906
+ justify-content: space-between;
2907
+ gap: 10px;
2908
+ }
2909
+ .dchat-targetEnable,
2910
+ .dchat-targetMerge {
2911
+ display: flex;
2912
+ align-items: center;
2913
+ gap: 6px;
2914
+ font-size: 12px;
2915
+ color: var(--dsw-alias-label-secondary);
2916
+ }
2917
+ .dchat-targetGrid {
2918
+ display: grid;
2919
+ grid-template-columns: 1fr 1fr;
2920
+ gap: 8px;
2921
+ }
2922
+ .dchat-targetField {
2923
+ display: flex;
2924
+ flex-direction: column;
2925
+ gap: 3px;
2926
+ font-size: 12px;
2927
+ }
2928
+ .dchat-scopeGrid {
2929
+ display: flex;
2930
+ flex-direction: column;
2931
+ gap: 12px;
2932
+ }
2933
+ .dchat-scopeRow {
2934
+ display: flex;
2935
+ flex-direction: column;
2936
+ gap: 4px;
2937
+ }
2938
+ .dchat-scopeLabel {
2939
+ font-size: 12px;
2940
+ color: var(--dsw-alias-label-secondary);
2941
+ }
2942
+ .dchat-panelSections {
2943
+ display: flex;
2944
+ flex-direction: column;
2945
+ gap: 8px;
2946
+ }
2947
+ .dchat-panelSectionsHead,
2948
+ .dchat-panelSectionsRow {
2949
+ display: flex;
2950
+ align-items: center;
2951
+ gap: 12px;
2952
+ }
2953
+ /* \u540D\u79F0\u5360\u6EE1\u5269\u4F59\u5BBD\u5EA6\uFF0C\u4E24\u4E2A\u52FE\u9009\u6846\u56FA\u5B9A\u9760\u53F3\uFF1A\u7A84\u680F\u4E0B\u4E5F\u4E0D\u4F1A\u628A\u540D\u79F0\u538B\u6210\u7AD6\u6392\u3002 */
2954
+ .dchat-panelSectionsName {
2955
+ flex: 1 1 auto;
2956
+ min-width: 0;
2957
+ font-size: 13px;
2958
+ overflow-wrap: anywhere;
2959
+ }
2960
+ .dchat-panelSectionsHead > .dchat-scopeLabel:first-child {
2961
+ flex: 1 1 auto;
2962
+ min-width: 0;
2963
+ }
2964
+ .dchat-panelSectionsHead > .dchat-scopeLabel:not(:first-child),
2965
+ .dchat-panelSectionsCheck {
2966
+ flex: none;
2967
+ width: 48px;
2968
+ text-align: center;
2969
+ }
2970
+ .dchat-panelSectionsCheck {
2971
+ display: flex;
2972
+ justify-content: center;
2973
+ }
2974
+ .dchat-panelSectionsCheck input {
2975
+ margin: 0;
2976
+ }
2977
+ .dchat-notice {
2978
+ margin: 0;
2979
+ font-size: 12px;
2980
+ color: var(--dsw-alias-state-success-primary);
2981
+ }
2982
+ .dchat-deliveryRow {
2983
+ display: flex;
2984
+ align-items: center;
2985
+ justify-content: space-between;
2986
+ gap: 12px;
2987
+ }
2988
+ .dchat-deliveryMeta {
2989
+ display: flex;
2990
+ flex-direction: column;
2991
+ gap: 2px;
2992
+ min-width: 0;
2993
+ }
2994
+ .dchat-deliveryMeta small {
2995
+ font-size: 12px;
2996
+ color: var(--dsw-alias-label-secondary);
2997
+ /* anywhere \u800C\u4E0D\u662F break-all\uFF1A\u53EA\u5728\u771F\u7684\u653E\u4E0D\u4E0B\u65F6\u624D\u65AD\u957F\u4E32\uFF0C\u4E0D\u4F1A\u628A\u666E\u901A\u8BCD\u4E5F\u5207\u788E\u3002 */
2998
+ overflow-wrap: anywhere;
2999
+ }
3000
+ .dchat-deliverySend {
3001
+ display: flex;
3002
+ flex-direction: column;
3003
+ gap: 8px;
3004
+ }
3005
+ `;
3006
+ var installations = 0;
3007
+ var styleElement = null;
3008
+ function installChatStyles(doc = globalThis.document) {
3009
+ if (!doc?.head) return () => {
3010
+ };
3011
+ installations += 1;
3012
+ if (!styleElement) {
3013
+ styleElement = doc.createElement("style");
3014
+ styleElement.id = STYLE_ID;
3015
+ styleElement.textContent = CSS;
3016
+ doc.head.appendChild(styleElement);
3017
+ }
3018
+ let released = false;
3019
+ return () => {
3020
+ if (released) return;
3021
+ released = true;
3022
+ installations -= 1;
3023
+ if (installations > 0) return;
3024
+ try {
3025
+ styleElement?.remove();
3026
+ } finally {
3027
+ styleElement = null;
3028
+ }
3029
+ };
3030
+ }
3031
+
3032
+ // packages/dsh-chat/client/chat-ui.js
3033
+ var h5 = React6.createElement;
3034
+ function Panel({ title, description, actions, children }) {
3035
+ return h5(
3036
+ "section",
3037
+ { className: "dchat-card" },
3038
+ title || description || actions ? h5(
3039
+ "div",
3040
+ { className: "dchat-cardHeader" },
3041
+ h5(
3042
+ "div",
3043
+ { className: "dchat-cardHeading" },
3044
+ title ? h5("h3", { className: "dchat-cardTitle" }, title) : null,
3045
+ description ? h5("p", { className: "dchat-cardDescription" }, description) : null
3046
+ ),
3047
+ actions ? h5("div", { className: "dchat-actions" }, actions) : null
3048
+ ) : null,
3049
+ children
3050
+ );
3051
+ }
3052
+ function EmptyState({ title, description, children }) {
3053
+ return h5(
3054
+ "div",
3055
+ { className: "dchat-empty" },
3056
+ h5("span", { className: "dchat-emptyTitle" }, title),
3057
+ description ? h5("span", null, description) : null,
3058
+ children
3059
+ );
3060
+ }
3061
+ var TONES = Object.freeze({
3062
+ starting: "warning",
3063
+ running: "success",
3064
+ failed: "error",
3065
+ stopped: ""
3066
+ });
3067
+ function StatusPill({ status, label }) {
3068
+ return h5("span", {
3069
+ className: "dchat-status",
3070
+ "data-tone": TONES[status] ?? "",
3071
+ "data-status": status
3072
+ }, label ?? status);
3073
+ }
3074
+ function createChatUi({ ctx, translate } = {}) {
3075
+ const t = typeof translate === "function" ? translate : (key) => key;
3076
+ return Object.freeze({
3077
+ version: CONTRACT_VERSION,
3078
+ components: Object.freeze({
3079
+ Panel,
3080
+ EmptyState,
3081
+ StatusPill,
3082
+ /** 上下文增强(群聊/私聊全局 + 指定用户/指定群 + 是否叠加全局提示词)。 */
3083
+ ContextEnhancementEditor,
3084
+ /** 通用"两作用域 × 多选项"设置块(如飞书任务过程展示)。 */
3085
+ ScopedModeEditor,
3086
+ /** 机器人跑在哪个目录(只对新建会话生效)。 */
3087
+ WorkspaceEditor,
3088
+ /** 用哪套 Agent 预设(只对新建会话生效)。 */
3089
+ PresetEditor,
3090
+ /** 机器人默认模型(还没有会话时用它,只对新建会话生效)。 */
3091
+ ModelEditor,
3092
+ /** 谁能跟机器人说话、谁能执行命令(立即生效)。 */
3093
+ AccessPolicyEditor,
3094
+ /** 控制面板卡片显示哪些项(私聊/群聊分开)。 */
3095
+ PanelSectionsEditor,
3096
+ /** 属主:绕过所有策略的人(改完渠道会重连一次)。 */
3097
+ OwnerEditor,
3098
+ /** 主动投递目标:清单、候选收编、测试发送(数据经 hub 控制端点)。 */
3099
+ DeliveryTargetsEditor
3100
+ }),
3101
+ hooks: Object.freeze({
3102
+ /** 读取/保存 hub 持有的每机器人共享设置。 */
3103
+ useBotSettings,
3104
+ /** 该机器人聊过的会话(带名字),给"指定用户/指定群"这类选择器用。 */
3105
+ useConversations
3106
+ }),
3107
+ installStyles: () => installChatStyles(),
3108
+ /** 调用本渠道自己的 RPC。 */
3109
+ callChannelRpc: (connection, channelId, method, payload, signal) => callChatRpc(connection, channelId, method, payload, signal),
3110
+ /** 调用 hub 控制端点(渠道无关设置,如上下文增强)。 */
3111
+ callControlRpc: (connection, method, payload, signal) => callControlRpc(connection, method, payload, signal),
3112
+ unwrapRpc,
3113
+ translate: t,
3114
+ /** 供渠道页复用的 React 运行时(渠道包只 external react/react-dom,无需各写一份)。 */
3115
+ react: React6,
3116
+ createElement: h5,
3117
+ /** hub 当前提供的契约版本,渠道页可据此显示兼容信息。 */
3118
+ contractVersion: CONTRACT_VERSION,
3119
+ context: Object.freeze({ has: () => typeof ctx === "object" })
3120
+ });
3121
+ }
3122
+
3123
+ // packages/dsh-chat/client/i18n.js
3124
+ var LOCALE_NAMESPACE = "dsh-chat";
3125
+ var zh = {
3126
+ "Chat\u673A\u5668\u4EBA": "Chat\u673A\u5668\u4EBA",
3127
+ "\u6A21\u578B": "\u6A21\u578B",
3128
+ "\u9ED8\u8BA4\u6A21\u578B": "\u9ED8\u8BA4\u6A21\u578B",
3129
+ "\u63A8\u7406\u7B49\u7EA7": "\u63A8\u7406\u7B49\u7EA7",
3130
+ "\u8FD9\u4E2A\u6A21\u578B\u6CA1\u6709\u53EF\u9009\u7684\u63A8\u7406\u7B49\u7EA7\u3002": "\u8FD9\u4E2A\u6A21\u578B\u6CA1\u6709\u53EF\u9009\u7684\u63A8\u7406\u7B49\u7EA7\u3002",
3131
+ "\u5148\u9009\u4E00\u4E2A\u6A21\u578B\u3002": "\u5148\u9009\u4E00\u4E2A\u6A21\u578B\u3002",
3132
+ "\u6A21\u578B\u9ED8\u8BA4": "\u6A21\u578B\u9ED8\u8BA4",
3133
+ "\u90E8\u5206 provider \u8BFB\u53D6\u5931\u8D25\uFF1A": "\u90E8\u5206 provider \u8BFB\u53D6\u5931\u8D25\uFF1A",
3134
+ "\u5F53\u524D Host \u8BFB\u4E0D\u5230\u6A21\u578B\u76EE\u5F55\u3002": "\u5F53\u524D Host \u8BFB\u4E0D\u5230\u6A21\u578B\u76EE\u5F55\u3002",
3135
+ "\u8FD8\u6CA1\u6709\u4F1A\u8BDD\u65F6\u7528\u54EA\u4E2A\u6A21\u578B\uFF1A\u9009\u5B8C\u5BF9\u4E0B\u4E00\u6761\u6D88\u606F\u65B0\u5EFA\u7684\u4F1A\u8BDD\u751F\u6548\u3002\u4F1A\u8BDD\u5185\u8FD8\u80FD\u5355\u72EC\u6539\uFF08\u9762\u677F\u7684\u6A21\u578B\u4E0B\u62C9\uFF09\u3002": "\u8FD8\u6CA1\u6709\u4F1A\u8BDD\u65F6\u7528\u54EA\u4E2A\u6A21\u578B\uFF1A\u9009\u5B8C\u5BF9\u4E0B\u4E00\u6761\u6D88\u606F\u65B0\u5EFA\u7684\u4F1A\u8BDD\u751F\u6548\u3002\u4F1A\u8BDD\u5185\u8FD8\u80FD\u5355\u72EC\u6539\uFF08\u9762\u677F\u7684\u6A21\u578B\u4E0B\u62C9\uFF09\u3002",
3136
+ "Chat\u673A\u5668\u4EBA\u8BBE\u7F6E": "Chat\u673A\u5668\u4EBA\u8BBE\u7F6E",
3137
+ "\u6E20\u9053\u5BFC\u822A": "\u6E20\u9053\u5BFC\u822A",
3138
+ "\u672A\u5B89\u88C5\u4EFB\u4F55\u804A\u5929\u8F6F\u4EF6\u63D2\u4EF6": "\u672A\u5B89\u88C5\u4EFB\u4F55\u804A\u5929\u8F6F\u4EF6\u63D2\u4EF6",
3139
+ "\u5B89\u88C5\u6E20\u9053\u63D2\u4EF6\u540E\uFF0C\u8FD9\u91CC\u4F1A\u51FA\u73B0\u5BF9\u5E94\u7684\u804A\u5929\u8F6F\u4EF6\u3002": "\u5B89\u88C5\u6E20\u9053\u63D2\u4EF6\u540E\uFF0C\u8FD9\u91CC\u4F1A\u51FA\u73B0\u5BF9\u5E94\u7684\u804A\u5929\u8F6F\u4EF6\u3002",
3140
+ "\u5DF2\u77E5\u6E20\u9053\u63D2\u4EF6": "\u5DF2\u77E5\u6E20\u9053\u63D2\u4EF6",
3141
+ "\u6E20\u9053\u6B63\u5728\u542F\u52A8": "\u6B63\u5728\u542F\u52A8",
3142
+ "\u6E20\u9053\u5DF2\u5C31\u7EEA": "\u5DF2\u5C31\u7EEA",
3143
+ "\u6E20\u9053\u542F\u52A8\u5931\u8D25": "\u542F\u52A8\u5931\u8D25",
3144
+ "\u6E20\u9053\u5DF2\u505C\u6B62": "\u5DF2\u505C\u6B62",
3145
+ "\u91CD\u65B0\u8BFB\u53D6": "\u91CD\u65B0\u8BFB\u53D6",
3146
+ "\u8BFB\u53D6\u4E2D\u2026": "\u8BFB\u53D6\u4E2D\u2026",
3147
+ "\u4E0A\u4E0B\u6587\u589E\u5F3A": "\u4E0A\u4E0B\u6587\u589E\u5F3A",
3148
+ "\u4EFB\u52A1\u8FC7\u7A0B\u5C55\u793A": "\u4EFB\u52A1\u8FC7\u7A0B\u5C55\u793A",
3149
+ "\u4FDD\u5B58": "\u4FDD\u5B58",
3150
+ "\u4FDD\u5B58\u4E2D\u2026": "\u4FDD\u5B58\u4E2D\u2026",
3151
+ "\u53D6\u6D88": "\u53D6\u6D88",
3152
+ "\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002": "\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002",
3153
+ // 主动投递(共享组件 delivery-targets.js)
3154
+ "\u4E3B\u52A8\u6295\u9012": "\u4E3B\u52A8\u6295\u9012",
3155
+ "\u8BA9\u5B9A\u65F6\u4EFB\u52A1\u6216 agent \u628A\u7ED3\u679C\u76F4\u63A5\u53D1\u5230\u6307\u5B9A\u4F1A\u8BDD\u3002": "\u8BA9\u5B9A\u65F6\u4EFB\u52A1\u6216 agent \u628A\u7ED3\u679C\u76F4\u63A5\u53D1\u5230\u6307\u5B9A\u4F1A\u8BDD\u3002",
3156
+ "\u663E\u793A\u9879": "\u663E\u793A\u9879",
3157
+ "\u63A7\u5236\u9762\u677F\u663E\u793A\u9879": "\u63A7\u5236\u9762\u677F\u663E\u793A\u9879",
3158
+ "\u53EA\u5F71\u54CD /menu \u53D1\u51FA\u6765\u7684\u90A3\u5F20\u5361\u7247\uFF1A\u5173\u6389\u7684\u9879\u4E0D\u663E\u793A\uFF0C\u529F\u80FD\u7167\u65E7\uFF08\u79C1\u804A\u4E0E\u7FA4\u804A\u5206\u522B\u8BBE\u7F6E\uFF09\u3002": "\u53EA\u5F71\u54CD /menu \u53D1\u51FA\u6765\u7684\u90A3\u5F20\u5361\u7247\uFF1A\u5173\u6389\u7684\u9879\u4E0D\u663E\u793A\uFF0C\u529F\u80FD\u7167\u65E7\uFF08\u79C1\u804A\u4E0E\u7FA4\u804A\u5206\u522B\u8BBE\u7F6E\uFF09\u3002",
3159
+ "\u6A21\u578B\u4E0E\u63A8\u7406\u7B49\u7EA7": "\u6A21\u578B\u4E0E\u63A8\u7406\u7B49\u7EA7",
3160
+ "\u4F1A\u8BDD": "\u4F1A\u8BDD",
3161
+ "Agent \u9884\u8BBE\u4E0E\u5DE5\u4F5C\u533A": "Agent \u9884\u8BBE\u4E0E\u5DE5\u4F5C\u533A",
3162
+ "\u4E0A\u4E0B\u6587\u589E\u5F3A\uFF08\u672C\u4F1A\u8BDD\uFF09": "\u4E0A\u4E0B\u6587\u589E\u5F3A\uFF08\u672C\u4F1A\u8BDD\uFF09",
3163
+ "\u8BBF\u95EE\u7B56\u7565\uFF08\u672C\u4F1A\u8BDD\uFF09": "\u8BBF\u95EE\u7B56\u7565\uFF08\u672C\u4F1A\u8BDD\uFF09",
3164
+ "\u6E20\u9053\u8BBE\u7F6E\uFF08\u4EFB\u52A1\u8FC7\u7A0B\u5C55\u793A\u7B49\uFF09": "\u6E20\u9053\u8BBE\u7F6E\uFF08\u4EFB\u52A1\u8FC7\u7A0B\u5C55\u793A\u7B49\uFF09",
3165
+ "\u6E20\u9053\u52A8\u4F5C\u6309\u94AE\uFF08\u91CD\u8FDE\u7B49\uFF09": "\u6E20\u9053\u52A8\u4F5C\u6309\u94AE\uFF08\u91CD\u8FDE\u7B49\uFF09",
3166
+ "\u547D\u4EE4\u6309\u94AE\uFF08\u65B0\u4F1A\u8BDD/\u72B6\u6001/\u8BCA\u65AD\u2026\uFF09": "\u547D\u4EE4\u6309\u94AE\uFF08\u65B0\u4F1A\u8BDD/\u72B6\u6001/\u8BCA\u65AD\u2026\uFF09",
3167
+ "\u62D6\u52A8\u53EF\u8C03\u6574\u987A\u5E8F": "\u62D6\u52A8\u53EF\u8C03\u6574\u987A\u5E8F",
3168
+ "\u5728\u6E20\u9053\u81EA\u5DF1\u7684\u914D\u7F6E\u91CC\u5B8C\u6210\u63A5\u5165\u540E\uFF0C\u673A\u5668\u4EBA\u4F1A\u51FA\u73B0\u5728\u8FD9\u91CC\u3002": "\u5728\u6E20\u9053\u81EA\u5DF1\u7684\u914D\u7F6E\u91CC\u5B8C\u6210\u63A5\u5165\u540E\uFF0C\u673A\u5668\u4EBA\u4F1A\u51FA\u73B0\u5728\u8FD9\u91CC\u3002",
3169
+ "\u79C1\u804A": "\u79C1\u804A",
3170
+ "\u7FA4\u804A": "\u7FA4\u804A",
3171
+ "\u5019\u9009": "\u5019\u9009",
3172
+ "\u4FDD\u5B58\u4E3A\u6295\u9012\u76EE\u6807": "\u4FDD\u5B58\u4E3A\u6295\u9012\u76EE\u6807",
3173
+ "\u91CD\u547D\u540D": "\u91CD\u547D\u540D",
3174
+ "\u81EA\u5B9A\u4E49\u540D\u79F0": "\u81EA\u5B9A\u4E49\u540D\u79F0",
3175
+ "\u7559\u7A7A\u5219\u7528\u81EA\u52A8\u8BC6\u522B\u7684\u540D\u5B57": "\u7559\u7A7A\u5219\u7528\u81EA\u52A8\u8BC6\u522B\u7684\u540D\u5B57",
3176
+ "\u5DF2\u6539\u540D\u3002": "\u5DF2\u6539\u540D\u3002",
3177
+ "\u5DF2\u6062\u590D\u81EA\u52A8\u540D\u5B57\u3002": "\u5DF2\u6062\u590D\u81EA\u52A8\u540D\u5B57\u3002",
3178
+ "\u5220\u9664": "\u5220\u9664",
3179
+ "\u786E\u8BA4\u5220\u9664": "\u786E\u8BA4\u5220\u9664",
3180
+ "\u5F53\u524D\u6E20\u9053\u4E0D\u652F\u6301\u4E3B\u52A8\u6295\u9012\u3002": "\u5F53\u524D\u6E20\u9053\u4E0D\u652F\u6301\u4E3B\u52A8\u6295\u9012\u3002",
3181
+ "\u5DF2\u4FDD\u5B58\uFF0C\u73B0\u5728\u53EF\u4EE5\u4E3B\u52A8\u53D1\u6D88\u606F\u4E86\u3002": "\u5DF2\u4FDD\u5B58\uFF0C\u73B0\u5728\u53EF\u4EE5\u4E3B\u52A8\u53D1\u6D88\u606F\u4E86\u3002",
3182
+ "\u5DF2\u5220\u9664\u3002": "\u5DF2\u5220\u9664\u3002",
3183
+ "\u8FD8\u6CA1\u6709\u53EF\u6DFB\u52A0\u7684\u4F1A\u8BDD\uFF1A\u5728\u7FA4\u91CC @ \u4E00\u6B21\u673A\u5668\u4EBA\uFF0C\u6216\u4E0E\u5B83\u79C1\u804A\u4E00\u6B21\uFF0C\u4F1A\u8BDD\u5C31\u4F1A\u51FA\u73B0\u5728\u8FD9\u91CC\uFF0C\u4FDD\u5B58\u540E\u5373\u53EF\u4E3B\u52A8\u6295\u9012\u3002": "\u8FD8\u6CA1\u6709\u53EF\u6DFB\u52A0\u7684\u4F1A\u8BDD\uFF1A\u5728\u7FA4\u91CC @ \u4E00\u6B21\u673A\u5668\u4EBA\uFF0C\u6216\u4E0E\u5B83\u79C1\u804A\u4E00\u6B21\uFF0C\u4F1A\u8BDD\u5C31\u4F1A\u51FA\u73B0\u5728\u8FD9\u91CC\uFF0C\u4FDD\u5B58\u540E\u5373\u53EF\u4E3B\u52A8\u6295\u9012\u3002",
3184
+ "\u6CA1\u6709\u53EF\u6DFB\u52A0\u7684\u4F1A\u8BDD\uFF1A\u5728\u7FA4\u91CC @ \u4E00\u6B21\u673A\u5668\u4EBA\uFF0C\u6216\u4E0E\u5B83\u79C1\u804A\u4E00\u6B21\uFF0C\u8BE5\u4F1A\u8BDD\u5C31\u4F1A\u51FA\u73B0\u5728\u8FD9\u91CC\u3002": "\u6CA1\u6709\u53EF\u6DFB\u52A0\u7684\u4F1A\u8BDD\uFF1A\u5728\u7FA4\u91CC @ \u4E00\u6B21\u673A\u5668\u4EBA\uFF0C\u6216\u4E0E\u5B83\u79C1\u804A\u4E00\u6B21\uFF0C\u8BE5\u4F1A\u8BDD\u5C31\u4F1A\u51FA\u73B0\u5728\u8FD9\u91CC\u3002",
3185
+ "\u4E0A\u9762\u6807\u300C\u5019\u9009\u300D\u7684\u4F1A\u8BDD\u8FD8\u4E0D\u80FD\u4E3B\u52A8\u6295\u9012\uFF0C\u70B9\u300C\u4FDD\u5B58\u4E3A\u6295\u9012\u76EE\u6807\u300D\u540E\u624D\u884C\u3002": "\u4E0A\u9762\u6807\u300C\u5019\u9009\u300D\u7684\u4F1A\u8BDD\u8FD8\u4E0D\u80FD\u4E3B\u52A8\u6295\u9012\uFF0C\u70B9\u300C\u4FDD\u5B58\u4E3A\u6295\u9012\u76EE\u6807\u300D\u540E\u624D\u884C\u3002",
3186
+ "\u5DF2\u4FDD\u5B58": "\u5DF2\u4FDD\u5B58",
3187
+ "\u53EF\u6DFB\u52A0\u7684\u5019\u9009": "\u53EF\u6DFB\u52A0\u7684\u5019\u9009",
3188
+ "\u5C55\u5F00\u5168\u90E8": "\u5C55\u5F00\u5168\u90E8",
3189
+ "\u6536\u8D77": "\u6536\u8D77",
3190
+ "\u6309\u540D\u5B57\u6216 id \u8FC7\u6EE4": "\u6309\u540D\u5B57\u6216 id \u8FC7\u6EE4",
3191
+ "\u6CA1\u6709\u5339\u914D\u7684\u76EE\u6807\u3002": "\u6CA1\u6709\u5339\u914D\u7684\u76EE\u6807\u3002",
3192
+ "\u586B\u5165\u793A\u4F8B": "\u586B\u5165\u793A\u4F8B",
3193
+ "\u6E05\u7A7A": "\u6E05\u7A7A",
3194
+ "\u6765\u6E90\u5B57\u6BB5": "\u6765\u6E90\u5B57\u6BB5",
3195
+ "\u542F\u7528": "\u542F\u7528",
3196
+ "\u5907\u6CE8\u540D\uFF08\u53EF\u9009\uFF09": "\u5907\u6CE8\u540D\uFF08\u53EF\u9009\uFF09",
3197
+ "\u5F20\u4E09": "\u5F20\u4E09",
3198
+ "\u65B0\u589E": "\u65B0\u589E",
3199
+ "\u8FD8\u6CA1\u6709\u6307\u5B9A\u8BBE\u7F6E\u3002": "\u8FD8\u6CA1\u6709\u6307\u5B9A\u8BBE\u7F6E\u3002",
3200
+ "\u5173\u95ED": "\u5173\u95ED",
3201
+ "\u589E\u5F3A\u63D0\u793A\u8BCD": "\u589E\u5F3A\u63D0\u793A\u8BCD",
3202
+ "\u544A\u8BC9\u6A21\u578B\u5982\u4F55\u4F7F\u7528\u6765\u6E90\u5B57\u6BB5\u3002\u53EA\u586B\u6B63\u6587\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u5305\u6210\u6765\u6E90\u589E\u5F3A\u5757\u3002": "\u544A\u8BC9\u6A21\u578B\u5982\u4F55\u4F7F\u7528\u6765\u6E90\u5B57\u6BB5\u3002\u53EA\u586B\u6B63\u6587\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u5305\u6210\u6765\u6E90\u589E\u5F3A\u5757\u3002",
3203
+ "\u53E0\u52A0\u5168\u5C40\u63D0\u793A\u8BCD\uFF08\u4E0D\u52FE\u9009\u5219\u53EA\u4F7F\u7528\u4E0A\u9762\u7684\u4E13\u5C5E\u63D0\u793A\u8BCD\uFF09": "\u53E0\u52A0\u5168\u5C40\u63D0\u793A\u8BCD\uFF08\u4E0D\u52FE\u9009\u5219\u53EA\u4F7F\u7528\u4E0A\u9762\u7684\u4E13\u5C5E\u63D0\u793A\u8BCD\uFF09",
3204
+ "\u4E0A\u4E0B\u6587\u589E\u5F3A": "\u4E0A\u4E0B\u6587\u589E\u5F3A",
3205
+ "\u672A\u5F00\u542F": "\u672A\u5F00\u542F",
3206
+ "\u6765\u6E90\u5B57\u6BB5\u53EA\u5728\u5F53\u524D\u6D88\u606F\u5DF2\u63D0\u4F9B\u65F6\u624D\u4F1A\u53D1\u9001\uFF0C\u4E0D\u4F1A\u989D\u5916\u67E5\u8BE2\u5E73\u53F0\u63A5\u53E3\u3002": "\u6765\u6E90\u5B57\u6BB5\u53EA\u5728\u5F53\u524D\u6D88\u606F\u5DF2\u63D0\u4F9B\u65F6\u624D\u4F1A\u53D1\u9001\uFF0C\u4E0D\u4F1A\u989D\u5916\u67E5\u8BE2\u5E73\u53F0\u63A5\u53E3\u3002",
3207
+ "\u4E0A\u4E0B\u6587\u589E\u5F3A\u8303\u56F4": "\u4E0A\u4E0B\u6587\u589E\u5F3A\u8303\u56F4",
3208
+ "\u5DF2\u5F00\u542F": "\u5DF2\u5F00\u542F",
3209
+ "\u4ECE\u4F1A\u8BDD\u91CC\u9009\u2026": "\u4ECE\u4F1A\u8BDD\u91CC\u9009\u2026",
3210
+ "\u5C5E\u4E3B": "\u5C5E\u4E3B",
3211
+ "\u5C5E\u4E3B\u4E0D\u9700\u8981\u8FDB\u767D\u540D\u5355\uFF1A\u6D88\u606F\u4E0E\u547D\u4EE4\u90FD\u76F4\u63A5\u653E\u884C\u3002\u8FD9\u91CC\u6539\u5B8C\u4F1A\u91CD\u8FDE\u4E00\u6B21\uFF0C\u7ACB\u523B\u751F\u6548\u3002": "\u5C5E\u4E3B\u4E0D\u9700\u8981\u8FDB\u767D\u540D\u5355\uFF1A\u6D88\u606F\u4E0E\u547D\u4EE4\u90FD\u76F4\u63A5\u653E\u884C\u3002\u8FD9\u91CC\u6539\u5B8C\u4F1A\u91CD\u8FDE\u4E00\u6B21\uFF0C\u7ACB\u523B\u751F\u6548\u3002",
3212
+ "\u5F53\u524D\u6CA1\u6709\u5C5E\u4E3B\uFF1A\u6CA1\u6709\u4EBA\u7ED5\u8FC7\u8BBF\u95EE\u7B56\u7565\uFF0C\u8C01\u80FD\u7528\u5B8C\u5168\u7531\u4E0B\u9762\u7684\u300C\u8BBF\u95EE\u7B56\u7565\u300D\u51B3\u5B9A\u3002": "\u5F53\u524D\u6CA1\u6709\u5C5E\u4E3B\uFF1A\u6CA1\u6709\u4EBA\u7ED5\u8FC7\u8BBF\u95EE\u7B56\u7565\uFF0C\u8C01\u80FD\u7528\u5B8C\u5168\u7531\u4E0B\u9762\u7684\u300C\u8BBF\u95EE\u7B56\u7565\u300D\u51B3\u5B9A\u3002",
3213
+ "\u4ECE\u4F1A\u8BDD\u91CC\u9009\u4E00\u4E2A\u4EBA\u8BBE\u4E3A\u5C5E\u4E3B": "\u4ECE\u4F1A\u8BDD\u91CC\u9009\u4E00\u4E2A\u4EBA\u8BBE\u4E3A\u5C5E\u4E3B",
3214
+ "\u8BBE\u4E3A\u5C5E\u4E3B": "\u8BBE\u4E3A\u5C5E\u4E3B",
3215
+ "\u6CA1\u6709\u53EF\u9009\u7684\u4F1A\u8BDD\uFF08\u5148\u548C\u673A\u5668\u4EBA\u804A\u4E00\u6B21\uFF09": "\u6CA1\u6709\u53EF\u9009\u7684\u4F1A\u8BDD\uFF08\u5148\u548C\u673A\u5668\u4EBA\u804A\u4E00\u6B21\uFF09",
3216
+ "\u6E05\u7A7A\uFF08\u65E0\u5C5E\u4E3B\uFF09": "\u6E05\u7A7A\uFF08\u65E0\u5C5E\u4E3B\uFF09",
3217
+ "\u6E05\u7A7A\u540E\u6CA1\u6709\u4EBA\u7ED5\u8FC7\u8BBF\u95EE\u7B56\u7565": "\u6E05\u7A7A\u540E\u6CA1\u6709\u4EBA\u7ED5\u8FC7\u8BBF\u95EE\u7B56\u7565",
3218
+ // 机器人设置页的共享编辑块(bot-shared-settings.js)
3219
+ "\u5DE5\u4F5C\u533A": "\u5DE5\u4F5C\u533A",
3220
+ "\u673A\u5668\u4EBA\u8DD1\u5728\u54EA\u4E2A\u76EE\u5F55\uFF1A\u80FD\u8BFB\u5199\u54EA\u4E9B\u6587\u4EF6\u3001\u7528\u54EA\u4EFD AGENTS.md\u3002\u53EA\u5BF9\u65B0\u5EFA\u4F1A\u8BDD\u751F\u6548\u3002": "\u673A\u5668\u4EBA\u8DD1\u5728\u54EA\u4E2A\u76EE\u5F55\uFF1A\u80FD\u8BFB\u5199\u54EA\u4E9B\u6587\u4EF6\u3001\u7528\u54EA\u4EFD AGENTS.md\u3002\u53EA\u5BF9\u65B0\u5EFA\u4F1A\u8BDD\u751F\u6548\u3002",
3221
+ "\u76EE\u5F55": "\u76EE\u5F55",
3222
+ "\u4E0B\u62C9\u91CC\u662F\u8FD9\u53F0\u673A\u5668\u4EBA\u7528\u8FC7\u7684\u76EE\u5F55\u3002": "\u4E0B\u62C9\u91CC\u662F\u8FD9\u53F0\u673A\u5668\u4EBA\u7528\u8FC7\u7684\u76EE\u5F55\u3002",
3223
+ "Agent \u9884\u8BBE": "Agent \u9884\u8BBE",
3224
+ "\u8FD9\u4E2A\u673A\u5668\u4EBA\u7528\u54EA\u5957 Agent \u9884\u8BBE\uFF08\u4EBA\u8BBE\u4E0E\u5DE5\u5177\u96C6\uFF09\u3002\u53EA\u5BF9\u65B0\u5EFA\u4F1A\u8BDD\u751F\u6548\u3002": "\u8FD9\u4E2A\u673A\u5668\u4EBA\u7528\u54EA\u5957 Agent \u9884\u8BBE\uFF08\u4EBA\u8BBE\u4E0E\u5DE5\u5177\u96C6\uFF09\u3002\u53EA\u5BF9\u65B0\u5EFA\u4F1A\u8BDD\u751F\u6548\u3002",
3225
+ "\u5F53\u524D Host \u8BFB\u4E0D\u5230 Agent Preset \u5217\u8868\u3002": "\u5F53\u524D Host \u8BFB\u4E0D\u5230 Agent Preset \u5217\u8868\u3002",
3226
+ "\u8DDF\u968F Host \u9ED8\u8BA4": "\u8DDF\u968F Host \u9ED8\u8BA4",
3227
+ "\u8BBF\u95EE\u7B56\u7565": "\u8BBF\u95EE\u7B56\u7565",
3228
+ "\u8C01\u80FD\u8DDF\u673A\u5668\u4EBA\u8BF4\u8BDD\u3001\u8C01\u80FD\u6267\u884C\u547D\u4EE4\u3002\u6539\u52A8\u7ACB\u5373\u751F\u6548\uFF1B\u5C5E\u4E3B\u59CB\u7EC8\u53EF\u7528\u3002": "\u8C01\u80FD\u8DDF\u673A\u5668\u4EBA\u8BF4\u8BDD\u3001\u8C01\u80FD\u6267\u884C\u547D\u4EE4\u3002\u6539\u52A8\u7ACB\u5373\u751F\u6548\uFF1B\u5C5E\u4E3B\u59CB\u7EC8\u53EF\u7528\u3002",
3229
+ "\u8BBF\u95EE\u6A21\u5F0F": "\u8BBF\u95EE\u6A21\u5F0F",
3230
+ "\u4EC5\u540D\u5355\u5185\u53EF\u7528": "\u4EC5\u540D\u5355\u5185\u53EF\u7528",
3231
+ "\u4EFB\u4F55\u4EBA\u53EF\u7528": "\u4EFB\u4F55\u4EBA\u53EF\u7528",
3232
+ "\u5141\u8BB8\u6267\u884C\u547D\u4EE4": "\u5141\u8BB8\u6267\u884C\u547D\u4EE4",
3233
+ "\u53EF\u6267\u884C\u547D\u4EE4": "\u53EF\u6267\u884C\u547D\u4EE4",
3234
+ "\u79FB\u9664": "\u79FB\u9664",
3235
+ "\u6DFB\u52A0": "\u6DFB\u52A0",
3236
+ "\u540D\u5355\u4E3A\u7A7A\u65F6\u53EA\u6709\u5C5E\u4E3B\u53EF\u7528\u3002": "\u540D\u5355\u4E3A\u7A7A\u65F6\u53EA\u6709\u5C5E\u4E3B\u53EF\u7528\u3002",
3237
+ "\u5BF9\u65B9\u7684\u5E73\u53F0 id\uFF0C\u56DE\u8F66\u6DFB\u52A0": "\u5BF9\u65B9\u7684\u5E73\u53F0 id\uFF0C\u56DE\u8F66\u6DFB\u52A0",
3238
+ // 版本与更新(version-panel.js)
3239
+ "\u5F53\u524D\u9875\u9762\u4E0D\u652F\u6301\u6E20\u9053\u5B50\u69FD\u3002": "\u5F53\u524D\u9875\u9762\u4E0D\u652F\u6301\u6E20\u9053\u5B50\u69FD\u3002",
3240
+ "\u8BBE\u7F6E": "\u8BBE\u7F6E",
3241
+ "\u673A\u5668\u4EBA": "\u673A\u5668\u4EBA",
3242
+ "\u6BCF\u4E2A\u673A\u5668\u4EBA\u4E00\u884C\uFF1B\u70B9\u300C\u8BBE\u7F6E\u300D\u8FDB\u5165\u5B83\u7684\u8BBE\u7F6E\u9875\uFF08\u4E0A\u4E0B\u6587\u589E\u5F3A\u3001\u4E3B\u52A8\u6295\u9012\u3001\u5DE5\u4F5C\u533A\u2026\uFF09\u3002": "\u6BCF\u4E2A\u673A\u5668\u4EBA\u4E00\u884C\uFF1B\u70B9\u300C\u8BBE\u7F6E\u300D\u8FDB\u5165\u5B83\u7684\u8BBE\u7F6E\u9875\uFF08\u4E0A\u4E0B\u6587\u589E\u5F3A\u3001\u4E3B\u52A8\u6295\u9012\u3001\u5DE5\u4F5C\u533A\u2026\uFF09\u3002",
3243
+ "\u8FD9\u4E2A\u6E20\u9053\u8FD8\u6CA1\u6709\u673A\u5668\u4EBA": "\u8FD9\u4E2A\u6E20\u9053\u8FD8\u6CA1\u6709\u673A\u5668\u4EBA",
3244
+ "\u5728\u6E20\u9053\u8BBE\u7F6E\u9875\u5B8C\u6210\u63A5\u5165\uFF08\u98DE\u4E66\u586B\u5E94\u7528\u51ED\u636E\u3001\u5FAE\u4FE1\u626B\u7801\uFF09\u540E\uFF0C\u673A\u5668\u4EBA\u4F1A\u51FA\u73B0\u5728\u8FD9\u91CC\u3002": "\u5728\u6E20\u9053\u8BBE\u7F6E\u9875\u5B8C\u6210\u63A5\u5165\uFF08\u98DE\u4E66\u586B\u5E94\u7528\u51ED\u636E\u3001\u5FAE\u4FE1\u626B\u7801\uFF09\u540E\uFF0C\u673A\u5668\u4EBA\u4F1A\u51FA\u73B0\u5728\u8FD9\u91CC\u3002",
3245
+ "\u672A\u547D\u540D\u673A\u5668\u4EBA": "\u672A\u547D\u540D\u673A\u5668\u4EBA",
3246
+ "\u8FD9\u53F0\u673A\u5668\u4EBA\u6CA1\u6709\u53EF\u7528\u7684\u8EAB\u4EFD\u6807\u8BC6\uFF0C\u65E0\u6CD5\u5355\u72EC\u914D\u7F6E": "\u8FD9\u53F0\u673A\u5668\u4EBA\u6CA1\u6709\u53EF\u7528\u7684\u8EAB\u4EFD\u6807\u8BC6\uFF0C\u65E0\u6CD5\u5355\u72EC\u914D\u7F6E",
3247
+ "\u6E20\u9053\u8BBE\u7F6E": "\u6E20\u9053\u8BBE\u7F6E",
3248
+ "\u6253\u5F00\u6E20\u9053\u8BBE\u7F6E\u9875": "\u6253\u5F00\u6E20\u9053\u8BBE\u7F6E\u9875",
3249
+ "\u2190 \u673A\u5668\u4EBA\u5217\u8868": "\u2190 \u673A\u5668\u4EBA\u5217\u8868",
3250
+ "\u5DF2\u5904\u7406": "\u5DF2\u5904\u7406",
3251
+ "\u6700\u8FD1": "\u6700\u8FD1",
3252
+ "\u8FD0\u884C\u6B63\u5E38": "\u8FD0\u884C\u6B63\u5E38",
3253
+ "\u6B63\u5728\u542F\u52A8": "\u6B63\u5728\u542F\u52A8",
3254
+ "\u91CD\u8FDE\u4E2D": "\u91CD\u8FDE\u4E2D",
3255
+ "\u5DF2\u505C\u6B62": "\u5DF2\u505C\u6B62",
3256
+ // 诊断面板(client/diagnostics.js):出故障时的自助现场。
3257
+ "\u8BCA\u65AD": "\u8BCA\u65AD",
3258
+ "\u6536\u8D77\u8BCA\u65AD": "\u6536\u8D77\u8BCA\u65AD",
3259
+ "\u51FA\u6545\u969C\u65F6\u5148\u770B\u8FD9\u91CC\uFF1A\u8FDE\u63A5\u72B6\u6001\u3001\u6700\u8FD1\u9519\u8BEF\u3001\u65E5\u5FD7\u5C3E\u90E8\u3002": "\u51FA\u6545\u969C\u65F6\u5148\u770B\u8FD9\u91CC\uFF1A\u8FDE\u63A5\u72B6\u6001\u3001\u6700\u8FD1\u9519\u8BEF\u3001\u65E5\u5FD7\u5C3E\u90E8\u3002",
3260
+ "\u8FD0\u884C\u4E2D": "\u8FD0\u884C\u4E2D",
3261
+ "\u542F\u52A8\u4E2D": "\u542F\u52A8\u4E2D",
3262
+ "\u5DF2\u8FDE\u63A5": "\u5DF2\u8FDE\u63A5",
3263
+ "\u672A\u8FDE\u63A5": "\u672A\u8FDE\u63A5",
3264
+ "\u5DF2\u5904\u7406": "\u5DF2\u5904\u7406",
3265
+ "\u53BB\u5F00\u901A\u6743\u9650": "\u53BB\u5F00\u901A\u6743\u9650",
3266
+ "\u6700\u8FD1\u4E00\u6B21\u9519\u8BEF": "\u6700\u8FD1\u4E00\u6B21\u9519\u8BEF",
3267
+ "\u8FD9\u53F0\u6E20\u9053\u4E0B\u8FD8\u6CA1\u6709\u673A\u5668\u4EBA\u3002": "\u8FD9\u53F0\u6E20\u9053\u4E0B\u8FD8\u6CA1\u6709\u673A\u5668\u4EBA\u3002",
3268
+ "\u8FD8\u6CA1\u6709\u65E5\u5FD7": "\u8FD8\u6CA1\u6709\u65E5\u5FD7",
3269
+ "\u770B\u6700\u540E 40 \u884C": "\u770B\u6700\u540E 40 \u884C",
3270
+ "\u6536\u8D77": "\u6536\u8D77",
3271
+ "\u7248\u672C\u4E0E\u66F4\u65B0": "\u7248\u672C\u4E0E\u66F4\u65B0",
3272
+ "\u6536\u8D77\u7248\u672C\u4E0E\u66F4\u65B0": "\u6536\u8D77\u7248\u672C\u4E0E\u66F4\u65B0",
3273
+ "\u5347\u7EA7\u63D2\u4EF6\u540E\u9700\u8981\u91CD\u542F dsh\uFF1B\u53EA\u6539\u8BBE\u7F6E\u9875\u4EE3\u7801\u5219\u5237\u65B0\u9875\u9762\u5373\u53EF\u3002": "\u5347\u7EA7\u63D2\u4EF6\u540E\u9700\u8981\u91CD\u542F dsh\uFF1B\u53EA\u6539\u8BBE\u7F6E\u9875\u4EE3\u7801\u5219\u5237\u65B0\u9875\u9762\u5373\u53EF\u3002",
3274
+ "Chat\u673A\u5668\u4EBA\u5185\u6838": "Chat\u673A\u5668\u4EBA\u5185\u6838",
3275
+ "\u6E20\u9053\u5951\u7EA6\u7248\u672C": "\u6E20\u9053\u5951\u7EA6\u7248\u672C",
3276
+ "\u6570\u636E\u76EE\u5F55": "\u6570\u636E\u76EE\u5F55",
3277
+ "\u65E5\u5FD7\u76EE\u5F55": "\u65E5\u5FD7\u76EE\u5F55",
3278
+ "\u8BFB\u53D6\u5931\u8D25": "\u8BFB\u53D6\u5931\u8D25",
3279
+ "\u66F4\u65B0\u65B9\u5F0F\uFF1A\u5728\u4ED3\u5E93\u91CC\u62C9\u53D6\u65B0\u4EE3\u7801\u540E\u91CD\u65B0\u6253\u5305\uFF0C\u518D\u8BA9 DSH \u91CD\u65B0\u52A0\u8F7D\u63D2\u4EF6\u3002": "\u66F4\u65B0\u65B9\u5F0F\uFF1A\u5728\u4ED3\u5E93\u91CC\u62C9\u53D6\u65B0\u4EE3\u7801\u540E\u91CD\u65B0\u6253\u5305\uFF0C\u518D\u8BA9 DSH \u91CD\u65B0\u52A0\u8F7D\u63D2\u4EF6\u3002",
3280
+ "\u53D1\u4E00\u6761\u6D4B\u8BD5\u6D88\u606F": "\u53D1\u4E00\u6761\u6D4B\u8BD5\u6D88\u606F",
3281
+ "\u9009\u62E9\u76EE\u6807": "\u9009\u62E9\u76EE\u6807",
3282
+ "\u53D1\u9001": "\u53D1\u9001",
3283
+ "\u53D1\u9001\u4E2D\u2026": "\u53D1\u9001\u4E2D\u2026",
3284
+ "\u6D4B\u8BD5\u6D88\u606F\u5185\u5BB9": "\u6D4B\u8BD5\u6D88\u606F\u5185\u5BB9"
3285
+ };
3286
+ var en = {
3287
+ "\u663E\u793A\u9879": "Section",
3288
+ "\u63A7\u5236\u9762\u677F\u663E\u793A\u9879": "Control panel sections",
3289
+ "\u53EA\u5F71\u54CD /menu \u53D1\u51FA\u6765\u7684\u90A3\u5F20\u5361\u7247\uFF1A\u5173\u6389\u7684\u9879\u4E0D\u663E\u793A\uFF0C\u529F\u80FD\u7167\u65E7\uFF08\u79C1\u804A\u4E0E\u7FA4\u804A\u5206\u522B\u8BBE\u7F6E\uFF09\u3002": "Only affects the card sent by /menu: hidden items are not drawn, everything keeps working (direct and group are configured separately).",
3290
+ "\u6A21\u578B\u4E0E\u63A8\u7406\u7B49\u7EA7": "Model & reasoning",
3291
+ "\u4F1A\u8BDD": "Session",
3292
+ "Agent \u9884\u8BBE\u4E0E\u5DE5\u4F5C\u533A": "Agent preset & workspace",
3293
+ "\u4E0A\u4E0B\u6587\u589E\u5F3A\uFF08\u672C\u4F1A\u8BDD\uFF09": "Context enhancement (this chat)",
3294
+ "\u8BBF\u95EE\u7B56\u7565\uFF08\u672C\u4F1A\u8BDD\uFF09": "Access policy (this chat)",
3295
+ "\u6E20\u9053\u8BBE\u7F6E\uFF08\u4EFB\u52A1\u8FC7\u7A0B\u5C55\u793A\u7B49\uFF09": "Channel settings (step display etc.)",
3296
+ "\u6E20\u9053\u52A8\u4F5C\u6309\u94AE\uFF08\u91CD\u8FDE\u7B49\uFF09": "Channel actions (reconnect etc.)",
3297
+ "\u547D\u4EE4\u6309\u94AE\uFF08\u65B0\u4F1A\u8BDD/\u72B6\u6001/\u8BCA\u65AD\u2026\uFF09": "Command buttons (new session/status/diagnostics\u2026)",
3298
+ "Chat\u673A\u5668\u4EBA": "Chat bot",
3299
+ "\u6A21\u578B": "Model",
3300
+ "\u9ED8\u8BA4\u6A21\u578B": "Default model",
3301
+ "\u63A8\u7406\u7B49\u7EA7": "Reasoning effort",
3302
+ "\u8FD9\u4E2A\u6A21\u578B\u6CA1\u6709\u53EF\u9009\u7684\u63A8\u7406\u7B49\u7EA7\u3002": "This model has no reasoning efforts to choose from.",
3303
+ "\u5148\u9009\u4E00\u4E2A\u6A21\u578B\u3002": "Pick a model first.",
3304
+ "\u6A21\u578B\u9ED8\u8BA4": "Model default",
3305
+ "\u90E8\u5206 provider \u8BFB\u53D6\u5931\u8D25\uFF1A": "Some providers failed to load: ",
3306
+ "\u5F53\u524D Host \u8BFB\u4E0D\u5230\u6A21\u578B\u76EE\u5F55\u3002": "The model catalog is unavailable right now.",
3307
+ "\u8FD8\u6CA1\u6709\u4F1A\u8BDD\u65F6\u7528\u54EA\u4E2A\u6A21\u578B\uFF1A\u9009\u5B8C\u5BF9\u4E0B\u4E00\u6761\u6D88\u606F\u65B0\u5EFA\u7684\u4F1A\u8BDD\u751F\u6548\u3002\u4F1A\u8BDD\u5185\u8FD8\u80FD\u5355\u72EC\u6539\uFF08\u9762\u677F\u7684\u6A21\u578B\u4E0B\u62C9\uFF09\u3002": "Model used before a conversation exists; it applies to the session created by your next message. You can still change it per conversation from the panel.",
3308
+ "Chat\u673A\u5668\u4EBA\u8BBE\u7F6E": "Chat bot settings",
3309
+ "\u6E20\u9053\u5BFC\u822A": "Channel navigation",
3310
+ "\u672A\u5B89\u88C5\u4EFB\u4F55\u804A\u5929\u8F6F\u4EF6\u63D2\u4EF6": "No chat channel plugin installed",
3311
+ "\u5B89\u88C5\u6E20\u9053\u63D2\u4EF6\u540E\uFF0C\u8FD9\u91CC\u4F1A\u51FA\u73B0\u5BF9\u5E94\u7684\u804A\u5929\u8F6F\u4EF6\u3002": "Install a channel plugin and its chat service appears here.",
3312
+ "\u5DF2\u77E5\u6E20\u9053\u63D2\u4EF6": "Known channel plugins",
3313
+ "\u6E20\u9053\u6B63\u5728\u542F\u52A8": "Starting",
3314
+ "\u6E20\u9053\u5DF2\u5C31\u7EEA": "Ready",
3315
+ "\u6E20\u9053\u542F\u52A8\u5931\u8D25": "Failed to start",
3316
+ "\u6E20\u9053\u5DF2\u505C\u6B62": "Stopped",
3317
+ "\u91CD\u65B0\u8BFB\u53D6": "Reload",
3318
+ "\u8BFB\u53D6\u4E2D\u2026": "Loading\u2026",
3319
+ "\u4E0A\u4E0B\u6587\u589E\u5F3A": "Context enhancement",
3320
+ "\u4EFB\u52A1\u8FC7\u7A0B\u5C55\u793A": "Task progress display",
3321
+ "\u4FDD\u5B58": "Save",
3322
+ "\u4FDD\u5B58\u4E2D\u2026": "Saving\u2026",
3323
+ "\u53D6\u6D88": "Cancel",
3324
+ "\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002": "Could not save. Try again.",
3325
+ // 主动投递
3326
+ "\u4E3B\u52A8\u6295\u9012": "Proactive delivery",
3327
+ "\u8BA9\u5B9A\u65F6\u4EFB\u52A1\u6216 agent \u628A\u7ED3\u679C\u76F4\u63A5\u53D1\u5230\u6307\u5B9A\u4F1A\u8BDD\u3002": "Let a scheduled job or an agent push results straight into a conversation.",
3328
+ "\u62D6\u52A8\u53EF\u8C03\u6574\u987A\u5E8F": "Drag to reorder",
3329
+ "\u5728\u6E20\u9053\u81EA\u5DF1\u7684\u914D\u7F6E\u91CC\u5B8C\u6210\u63A5\u5165\u540E\uFF0C\u673A\u5668\u4EBA\u4F1A\u51FA\u73B0\u5728\u8FD9\u91CC\u3002": "Once the channel is configured, its bots show up here.",
3330
+ "\u79C1\u804A": "Direct",
3331
+ "\u7FA4\u804A": "Group",
3332
+ "\u5019\u9009": "Candidate",
3333
+ "\u4FDD\u5B58\u4E3A\u6295\u9012\u76EE\u6807": "Save as target",
3334
+ "\u91CD\u547D\u540D": "Rename",
3335
+ "\u81EA\u5B9A\u4E49\u540D\u79F0": "Custom name",
3336
+ "\u7559\u7A7A\u5219\u7528\u81EA\u52A8\u8BC6\u522B\u7684\u540D\u5B57": "Leave empty to use the detected name",
3337
+ "\u5DF2\u6539\u540D\u3002": "Renamed.",
3338
+ "\u5DF2\u6062\u590D\u81EA\u52A8\u540D\u5B57\u3002": "Restored the detected name.",
3339
+ "\u5220\u9664": "Delete",
3340
+ "\u786E\u8BA4\u5220\u9664": "Confirm delete",
3341
+ "\u5F53\u524D\u6E20\u9053\u4E0D\u652F\u6301\u4E3B\u52A8\u6295\u9012\u3002": "This channel does not support proactive delivery.",
3342
+ "\u5DF2\u4FDD\u5B58\uFF0C\u73B0\u5728\u53EF\u4EE5\u4E3B\u52A8\u53D1\u6D88\u606F\u4E86\u3002": "Saved. You can now send proactively.",
3343
+ "\u5DF2\u5220\u9664\u3002": "Deleted.",
3344
+ "\u8FD8\u6CA1\u6709\u53EF\u6DFB\u52A0\u7684\u4F1A\u8BDD\uFF1A\u5728\u7FA4\u91CC @ \u4E00\u6B21\u673A\u5668\u4EBA\uFF0C\u6216\u4E0E\u5B83\u79C1\u804A\u4E00\u6B21\uFF0C\u4F1A\u8BDD\u5C31\u4F1A\u51FA\u73B0\u5728\u8FD9\u91CC\uFF0C\u4FDD\u5B58\u540E\u5373\u53EF\u4E3B\u52A8\u6295\u9012\u3002": "No conversation to add yet: mention the bot once in a group, or send it a direct message \u2014 the conversation then shows up here and can be saved for proactive delivery.",
3345
+ "\u6CA1\u6709\u53EF\u6DFB\u52A0\u7684\u4F1A\u8BDD\uFF1A\u5728\u7FA4\u91CC @ \u4E00\u6B21\u673A\u5668\u4EBA\uFF0C\u6216\u4E0E\u5B83\u79C1\u804A\u4E00\u6B21\uFF0C\u8BE5\u4F1A\u8BDD\u5C31\u4F1A\u51FA\u73B0\u5728\u8FD9\u91CC\u3002": "No conversation to add: mention the bot once in a group, or send it a direct message, and that conversation shows up here.",
3346
+ "\u4E0A\u9762\u6807\u300C\u5019\u9009\u300D\u7684\u4F1A\u8BDD\u8FD8\u4E0D\u80FD\u4E3B\u52A8\u6295\u9012\uFF0C\u70B9\u300C\u4FDD\u5B58\u4E3A\u6295\u9012\u76EE\u6807\u300D\u540E\u624D\u884C\u3002": 'A conversation marked "Candidate" cannot receive proactive messages yet \u2014 press "Save as target" first.',
3347
+ "\u5DF2\u4FDD\u5B58": "Saved",
3348
+ "\u53EF\u6DFB\u52A0\u7684\u5019\u9009": "Candidates",
3349
+ "\u5C55\u5F00\u5168\u90E8": "Show all",
3350
+ "\u6536\u8D77": "Collapse",
3351
+ "\u6309\u540D\u5B57\u6216 id \u8FC7\u6EE4": "Filter by name or id",
3352
+ "\u6CA1\u6709\u5339\u914D\u7684\u76EE\u6807\u3002": "No target matches the filter.",
3353
+ "\u586B\u5165\u793A\u4F8B": "Fill with example",
3354
+ "\u6E05\u7A7A": "Clear",
3355
+ "\u6765\u6E90\u5B57\u6BB5": "Source fields",
3356
+ "\u542F\u7528": "Enabled",
3357
+ "\u5907\u6CE8\u540D\uFF08\u53EF\u9009\uFF09": "Display name (optional)",
3358
+ "\u5F20\u4E09": "Alice",
3359
+ "\u65B0\u589E": "Add",
3360
+ "\u8FD8\u6CA1\u6709\u6307\u5B9A\u8BBE\u7F6E\u3002": "Nothing configured yet.",
3361
+ "\u5173\u95ED": "Close",
3362
+ "\u589E\u5F3A\u63D0\u793A\u8BCD": "Prepended prompt",
3363
+ "\u544A\u8BC9\u6A21\u578B\u5982\u4F55\u4F7F\u7528\u6765\u6E90\u5B57\u6BB5\u3002\u53EA\u586B\u6B63\u6587\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u5305\u6210\u6765\u6E90\u589E\u5F3A\u5757\u3002": "Tell the model how to use the source fields. Write the body only \u2014 the plugin wraps it into a source block.",
3364
+ "\u53E0\u52A0\u5168\u5C40\u63D0\u793A\u8BCD\uFF08\u4E0D\u52FE\u9009\u5219\u53EA\u4F7F\u7528\u4E0A\u9762\u7684\u4E13\u5C5E\u63D0\u793A\u8BCD\uFF09": "Also stack the global prompt (unchecked: use only the prompt above)",
3365
+ "\u4E0A\u4E0B\u6587\u589E\u5F3A": "Context enhancement",
3366
+ "\u672A\u5F00\u542F": "Off",
3367
+ "\u6765\u6E90\u5B57\u6BB5\u53EA\u5728\u5F53\u524D\u6D88\u606F\u5DF2\u63D0\u4F9B\u65F6\u624D\u4F1A\u53D1\u9001\uFF0C\u4E0D\u4F1A\u989D\u5916\u67E5\u8BE2\u5E73\u53F0\u63A5\u53E3\u3002": "Source fields are sent only when the incoming message already carries them; no extra platform calls are made.",
3368
+ "\u4E0A\u4E0B\u6587\u589E\u5F3A\u8303\u56F4": "Context enhancement scope",
3369
+ "\u5DF2\u5F00\u542F": "On",
3370
+ "\u4ECE\u4F1A\u8BDD\u91CC\u9009\u2026": "Pick a conversation\u2026",
3371
+ "\u5C5E\u4E3B": "Owner",
3372
+ "\u5C5E\u4E3B\u4E0D\u9700\u8981\u8FDB\u767D\u540D\u5355\uFF1A\u6D88\u606F\u4E0E\u547D\u4EE4\u90FD\u76F4\u63A5\u653E\u884C\u3002\u8FD9\u91CC\u6539\u5B8C\u4F1A\u91CD\u8FDE\u4E00\u6B21\uFF0C\u7ACB\u523B\u751F\u6548\u3002": "An owner does not need to be on the allowlist: their messages and commands always pass. Saving reconnects this bot once so the change takes effect immediately.",
3373
+ "\u5F53\u524D\u6CA1\u6709\u5C5E\u4E3B\uFF1A\u6CA1\u6709\u4EBA\u7ED5\u8FC7\u8BBF\u95EE\u7B56\u7565\uFF0C\u8C01\u80FD\u7528\u5B8C\u5168\u7531\u4E0B\u9762\u7684\u300C\u8BBF\u95EE\u7B56\u7565\u300D\u51B3\u5B9A\u3002": "No owner right now: nobody bypasses the access policy, so who may use this bot is decided entirely by the access policy below.",
3374
+ "\u4ECE\u4F1A\u8BDD\u91CC\u9009\u4E00\u4E2A\u4EBA\u8BBE\u4E3A\u5C5E\u4E3B": "Pick a person from a conversation to make them the owner",
3375
+ "\u8BBE\u4E3A\u5C5E\u4E3B": "Make owner",
3376
+ "\u6CA1\u6709\u53EF\u9009\u7684\u4F1A\u8BDD\uFF08\u5148\u548C\u673A\u5668\u4EBA\u804A\u4E00\u6B21\uFF09": "No conversation to pick yet (talk to the bot once first)",
3377
+ "\u6E05\u7A7A\uFF08\u65E0\u5C5E\u4E3B\uFF09": "Clear (no owner)",
3378
+ "\u6E05\u7A7A\u540E\u6CA1\u6709\u4EBA\u7ED5\u8FC7\u8BBF\u95EE\u7B56\u7565": "After clearing, nobody bypasses the access policy",
3379
+ // 机器人设置页的共享编辑块(bot-shared-settings.js)
3380
+ "\u5DE5\u4F5C\u533A": "Workspace",
3381
+ "\u673A\u5668\u4EBA\u8DD1\u5728\u54EA\u4E2A\u76EE\u5F55\uFF1A\u80FD\u8BFB\u5199\u54EA\u4E9B\u6587\u4EF6\u3001\u7528\u54EA\u4EFD AGENTS.md\u3002\u53EA\u5BF9\u65B0\u5EFA\u4F1A\u8BDD\u751F\u6548\u3002": "Which directory the bot runs in: which files it may read and write, and which AGENTS.mdapplies. Applies to new conversations only.",
3382
+ "\u76EE\u5F55": "Directory",
3383
+ "\u4E0B\u62C9\u91CC\u662F\u8FD9\u53F0\u673A\u5668\u4EBA\u7528\u8FC7\u7684\u76EE\u5F55\u3002": "The suggestions are directories this bot has used before.",
3384
+ "Agent \u9884\u8BBE": "Agent preset",
3385
+ "\u8FD9\u4E2A\u673A\u5668\u4EBA\u7528\u54EA\u5957 Agent \u9884\u8BBE\uFF08\u4EBA\u8BBE\u4E0E\u5DE5\u5177\u96C6\uFF09\u3002\u53EA\u5BF9\u65B0\u5EFA\u4F1A\u8BDD\u751F\u6548\u3002": "Which agent preset this bot uses (persona and tool set). Applies to new conversations only.",
3386
+ "\u5F53\u524D Host \u8BFB\u4E0D\u5230 Agent Preset \u5217\u8868\u3002": "This Host does not expose an agent preset list.",
3387
+ "\u8DDF\u968F Host \u9ED8\u8BA4": "Follow the Host default",
3388
+ "\u8BBF\u95EE\u7B56\u7565": "Access policy",
3389
+ "\u8C01\u80FD\u8DDF\u673A\u5668\u4EBA\u8BF4\u8BDD\u3001\u8C01\u80FD\u6267\u884C\u547D\u4EE4\u3002\u6539\u52A8\u7ACB\u5373\u751F\u6548\uFF1B\u5C5E\u4E3B\u59CB\u7EC8\u53EF\u7528\u3002": "Who may talk to the bot and who may run commands. Changes apply immediately;the owner always has access.",
3390
+ "\u8BBF\u95EE\u6A21\u5F0F": "Access mode",
3391
+ "\u4EC5\u540D\u5355\u5185\u53EF\u7528": "Allowlist only",
3392
+ "\u4EFB\u4F55\u4EBA\u53EF\u7528": "Anyone",
3393
+ "\u5141\u8BB8\u6267\u884C\u547D\u4EE4": "Allow commands",
3394
+ "\u53EF\u6267\u884C\u547D\u4EE4": "Allow commands",
3395
+ "\u79FB\u9664": "Remove",
3396
+ "\u6DFB\u52A0": "Add",
3397
+ "\u540D\u5355\u4E3A\u7A7A\u65F6\u53EA\u6709\u5C5E\u4E3B\u53EF\u7528\u3002": "An empty allowlist means only the owner can use it.",
3398
+ "\u5BF9\u65B9\u7684\u5E73\u53F0 id\uFF0C\u56DE\u8F66\u6DFB\u52A0": "Their platform id \u2014 press Enter to add",
3399
+ "\u5F53\u524D\u9875\u9762\u4E0D\u652F\u6301\u6E20\u9053\u5B50\u69FD\u3002": "This page does not support channel sub-slots.",
3400
+ "\u8BBE\u7F6E": "Settings",
3401
+ "\u673A\u5668\u4EBA": "Bots",
3402
+ "\u6BCF\u4E2A\u673A\u5668\u4EBA\u4E00\u884C\uFF1B\u70B9\u300C\u8BBE\u7F6E\u300D\u8FDB\u5165\u5B83\u7684\u8BBE\u7F6E\u9875\uFF08\u4E0A\u4E0B\u6587\u589E\u5F3A\u3001\u4E3B\u52A8\u6295\u9012\u3001\u5DE5\u4F5C\u533A\u2026\uFF09\u3002": "One row per bot; click Settings to open its page (context enhancement, proactive delivery, workspace\u2026).",
3403
+ "\u8FD9\u4E2A\u6E20\u9053\u8FD8\u6CA1\u6709\u673A\u5668\u4EBA": "No bot on this channel yet",
3404
+ "\u5728\u6E20\u9053\u8BBE\u7F6E\u9875\u5B8C\u6210\u63A5\u5165\uFF08\u98DE\u4E66\u586B\u5E94\u7528\u51ED\u636E\u3001\u5FAE\u4FE1\u626B\u7801\uFF09\u540E\uFF0C\u673A\u5668\u4EBA\u4F1A\u51FA\u73B0\u5728\u8FD9\u91CC\u3002": "Finish onboarding on the channel page (Feishu app credentials, WeChat QR scan) and the bot shows up here.",
3405
+ "\u672A\u547D\u540D\u673A\u5668\u4EBA": "Unnamed bot",
3406
+ "\u8FD9\u53F0\u673A\u5668\u4EBA\u6CA1\u6709\u53EF\u7528\u7684\u8EAB\u4EFD\u6807\u8BC6\uFF0C\u65E0\u6CD5\u5355\u72EC\u914D\u7F6E": "This bot has no usable identity, so it cannot be configured separately",
3407
+ "\u6E20\u9053\u8BBE\u7F6E": "Channel settings",
3408
+ "\u6253\u5F00\u6E20\u9053\u8BBE\u7F6E\u9875": "Open channel settings",
3409
+ "\u2190 \u673A\u5668\u4EBA\u5217\u8868": "\u2190 Bot list",
3410
+ "\u5DF2\u5904\u7406": "Handled",
3411
+ "\u6700\u8FD1": "Last",
3412
+ "\u8FD0\u884C\u6B63\u5E38": "Running",
3413
+ "\u6B63\u5728\u542F\u52A8": "Starting",
3414
+ "\u91CD\u8FDE\u4E2D": "Reconnecting",
3415
+ "\u5DF2\u505C\u6B62": "Stopped",
3416
+ // 诊断面板(client/diagnostics.js)
3417
+ "\u8BCA\u65AD": "Diagnostics",
3418
+ "\u6536\u8D77\u8BCA\u65AD": "Hide diagnostics",
3419
+ "\u51FA\u6545\u969C\u65F6\u5148\u770B\u8FD9\u91CC\uFF1A\u8FDE\u63A5\u72B6\u6001\u3001\u6700\u8FD1\u9519\u8BEF\u3001\u65E5\u5FD7\u5C3E\u90E8\u3002": "Start here when something breaks: connection state, latest errors, log tail.",
3420
+ "\u8FD0\u884C\u4E2D": "Running",
3421
+ "\u542F\u52A8\u4E2D": "Starting",
3422
+ "\u5DF2\u8FDE\u63A5": "Connected",
3423
+ "\u672A\u8FDE\u63A5": "Disconnected",
3424
+ "\u5DF2\u5904\u7406": "Handled",
3425
+ "\u53BB\u5F00\u901A\u6743\u9650": "Grant the scope",
3426
+ "\u6700\u8FD1\u4E00\u6B21\u9519\u8BEF": "Last error",
3427
+ "\u8FD9\u53F0\u6E20\u9053\u4E0B\u8FD8\u6CA1\u6709\u673A\u5668\u4EBA\u3002": "No bots on this channel yet.",
3428
+ "\u8FD8\u6CA1\u6709\u65E5\u5FD7": "No log yet",
3429
+ "\u770B\u6700\u540E 40 \u884C": "Show last 40 lines",
3430
+ "\u6536\u8D77": "Hide",
3431
+ "\u7248\u672C\u4E0E\u66F4\u65B0": "Version & updates",
3432
+ "\u6536\u8D77\u7248\u672C\u4E0E\u66F4\u65B0": "Hide version & updates",
3433
+ "\u5347\u7EA7\u63D2\u4EF6\u540E\u9700\u8981\u91CD\u542F dsh\uFF1B\u53EA\u6539\u8BBE\u7F6E\u9875\u4EE3\u7801\u5219\u5237\u65B0\u9875\u9762\u5373\u53EF\u3002": "Upgrading the plugin needs a dsh restart; settings-only changes just need a page refresh.",
3434
+ "Chat\u673A\u5668\u4EBA\u5185\u6838": "Chat bot core",
3435
+ "\u6E20\u9053\u5951\u7EA6\u7248\u672C": "Channel contract version",
3436
+ "\u6570\u636E\u76EE\u5F55": "Data directory",
3437
+ "\u65E5\u5FD7\u76EE\u5F55": "Log directory",
3438
+ "\u8BFB\u53D6\u5931\u8D25": "Failed to read",
3439
+ "\u66F4\u65B0\u65B9\u5F0F\uFF1A\u5728\u4ED3\u5E93\u91CC\u62C9\u53D6\u65B0\u4EE3\u7801\u540E\u91CD\u65B0\u6253\u5305\uFF0C\u518D\u8BA9 DSH \u91CD\u65B0\u52A0\u8F7D\u63D2\u4EF6\u3002": "To update: pull the repo, rebuild, then let DSH reload the plugin.",
3440
+ "\u53D1\u4E00\u6761\u6D4B\u8BD5\u6D88\u606F": "Send a test message",
3441
+ "\u9009\u62E9\u76EE\u6807": "Choose a target",
3442
+ "\u53D1\u9001": "Send",
3443
+ "\u53D1\u9001\u4E2D\u2026": "Sending\u2026",
3444
+ "\u6D4B\u8BD5\u6D88\u606F\u5185\u5BB9": "Test message"
3445
+ };
3446
+ function bindTranslator(locale) {
3447
+ const dictionary = { zh, en };
3448
+ return (key) => {
3449
+ const language = locale?.getSnapshot?.()?.locale ?? "zh";
3450
+ const table = dictionary[language] ?? zh;
3451
+ return table[key] ?? zh[key] ?? key;
3452
+ };
3453
+ }
3454
+
3455
+ // packages/dsh-chat/client/session-badges.js
3456
+ var STYLE_ID2 = "dsh-chat-session-badges";
3457
+ var CHANNEL_ATTR = "data-dsh-chat-channel";
3458
+ var TITLE_ATTR = "data-dsh-chat-title";
3459
+ var ROW_SELECTOR = '[role="treeitem"][aria-selected]';
3460
+ function badgeUri({ text, color }, size = 16) {
3461
+ const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 ${size} ${size}"><rect x="0.5" y="0.5" width="${size - 1}" height="${size - 1}" rx="4" fill="${color}"/><text x="${size / 2}" y="${size / 2 + 3.4}" text-anchor="middle" font-family="-apple-system, BlinkMacSystemFont, 'PingFang SC', sans-serif" font-size="9.5" font-weight="600" fill="#ffffff">${text}</text></svg>`;
3462
+ return `data:image/svg+xml,${encodeURIComponent(svg)}`;
3463
+ }
3464
+ function stylesheet(uris) {
3465
+ const mapping = Object.entries(uris).map(([channel, uri]) => `[${CHANNEL_ATTR}="${channel}"] { --dchat-session-badge: url("${uri}"); }`).join("\n");
3466
+ return `
3467
+ [${CHANNEL_ATTR}][${TITLE_ATTR}] {
3468
+ position: relative;
3469
+ -webkit-text-fill-color: transparent;
3470
+ text-overflow: clip !important;
3471
+ overflow: hidden;
3472
+ }
3473
+ [${CHANNEL_ATTR}][${TITLE_ATTR}]::before {
3474
+ content: "";
3475
+ position: absolute;
3476
+ inset-inline-start: 0;
3477
+ top: 50%;
3478
+ transform: translateY(-50%);
3479
+ width: 16px;
3480
+ height: 16px;
3481
+ background: var(--dchat-session-badge) center / contain no-repeat;
3482
+ pointer-events: none;
3483
+ }
3484
+ [${CHANNEL_ATTR}][${TITLE_ATTR}]::after {
3485
+ content: attr(${TITLE_ATTR}) / "";
3486
+ position: absolute;
3487
+ inset: 0;
3488
+ inset-inline-start: 22px;
3489
+ -webkit-text-fill-color: currentColor;
3490
+ text-indent: 0;
3491
+ overflow: hidden;
3492
+ white-space: nowrap;
3493
+ text-overflow: ellipsis;
3494
+ pointer-events: none;
3495
+ }
3496
+ ${mapping}
3497
+ `;
3498
+ }
3499
+ function findChannelTitle(row, known) {
3500
+ if (!row || typeof row.querySelectorAll !== "function" || known.length === 0) return null;
3501
+ let found = null;
3502
+ for (const element of row.querySelectorAll("*")) {
3503
+ if (element.children?.length > 0) continue;
3504
+ const text = element.textContent;
3505
+ if (!text) continue;
3506
+ for (const [channel, label] of known) {
3507
+ if (text.startsWith(`${label} \xB7 `)) {
3508
+ found = { element, channel, text: text.slice(label.length + 3).trim() };
3509
+ }
3510
+ }
3511
+ }
3512
+ return found;
3513
+ }
3514
+ function installSessionBadges({
3515
+ channels,
3516
+ doc = globalThis.document,
3517
+ win = globalThis.window
3518
+ } = {}) {
3519
+ if (!doc?.body || typeof win?.MutationObserver !== "function") return () => {
3520
+ };
3521
+ const badges = /* @__PURE__ */ new Map();
3522
+ const ready = /* @__PURE__ */ new Set();
3523
+ const owned = /* @__PURE__ */ new Map();
3524
+ const queued = /* @__PURE__ */ new Set();
3525
+ const images = [];
3526
+ let closed = false;
3527
+ let scheduled = false;
3528
+ const style = doc.createElement("style");
3529
+ style.id = STYLE_ID2;
3530
+ doc.head?.appendChild(style);
3531
+ function labels() {
3532
+ return [...badges.values()].filter((entry) => ready.has(entry.channel)).map((entry) => [entry.channel, entry.label]);
3533
+ }
3534
+ function titleOf(row) {
3535
+ return findChannelTitle(row, labels());
3536
+ }
3537
+ function restore(element) {
3538
+ const previous = owned.get(element);
3539
+ if (!previous) return;
3540
+ owned.delete(element);
3541
+ for (const [attribute, value] of previous) {
3542
+ if (value === null) element.removeAttribute(attribute);
3543
+ else element.setAttribute(attribute, value);
3544
+ }
3545
+ }
3546
+ function update(row) {
3547
+ const found = row.isConnected ? titleOf(row) : null;
3548
+ for (const marked of row.querySelectorAll(`[${CHANNEL_ATTR}]`)) {
3549
+ if (marked !== found?.element) restore(marked);
3550
+ }
3551
+ if (!found) return;
3552
+ if (!owned.has(found.element)) {
3553
+ owned.set(found.element, [CHANNEL_ATTR, TITLE_ATTR].map((attribute) => [attribute, found.element.getAttribute(attribute)]));
3554
+ }
3555
+ found.element.setAttribute(CHANNEL_ATTR, found.channel);
3556
+ found.element.setAttribute(TITLE_ATTR, found.text);
3557
+ }
3558
+ function schedule() {
3559
+ if (closed || scheduled || queued.size === 0) return;
3560
+ scheduled = true;
3561
+ win.queueMicrotask(() => {
3562
+ scheduled = false;
3563
+ if (closed) return;
3564
+ const rows = [...queued];
3565
+ queued.clear();
3566
+ for (const row of rows) {
3567
+ try {
3568
+ update(row);
3569
+ } catch {
3570
+ for (const marked of row.querySelectorAll(`[${CHANNEL_ATTR}]`)) restore(marked);
3571
+ }
3572
+ }
3573
+ });
3574
+ }
3575
+ function collect(node, descendants = false) {
3576
+ const element = node?.nodeType === 1 ? node : node?.parentElement;
3577
+ if (!element) return;
3578
+ const row = element.closest(ROW_SELECTOR);
3579
+ if (row) queued.add(row);
3580
+ if (descendants) for (const child of element.querySelectorAll(ROW_SELECTOR)) queued.add(child);
3581
+ if (owned.has(element)) {
3582
+ const owner = element.closest(ROW_SELECTOR);
3583
+ if (owner) queued.add(owner);
3584
+ else restore(element);
3585
+ }
3586
+ schedule();
3587
+ }
3588
+ function applyBadges() {
3589
+ if (closed) return;
3590
+ badges.clear();
3591
+ for (const entry of channels?.getSnapshot?.() ?? []) {
3592
+ const badge = entry.sessionBadge;
3593
+ if (!badge || typeof badge.text !== "string" || !badge.text) continue;
3594
+ const label = typeof entry.label === "function" ? entry.label() : entry.label;
3595
+ badges.set(entry.id, {
3596
+ channel: entry.id,
3597
+ label: String(label ?? entry.id),
3598
+ // 优先用渠道自己的图标(和设置页左栏同一份);没给图标才退回字徽标。
3599
+ uri: channelIconUri(entry.icon) ?? badgeUri({ text: badge.text, color: badge.color ?? "#3370ff" })
3600
+ });
3601
+ }
3602
+ style.textContent = stylesheet(Object.fromEntries(
3603
+ [...badges].map(([id, badge]) => [id, badge.uri])
3604
+ ));
3605
+ for (const [id, badge] of badges) {
3606
+ if (ready.has(id)) continue;
3607
+ const image = new win.Image();
3608
+ images.push(image);
3609
+ image.onload = () => {
3610
+ ready.add(id);
3611
+ for (const row of doc.querySelectorAll(ROW_SELECTOR)) queued.add(row);
3612
+ schedule();
3613
+ };
3614
+ image.src = badge.uri;
3615
+ }
3616
+ for (const row of doc.querySelectorAll(ROW_SELECTOR)) queued.add(row);
3617
+ schedule();
3618
+ }
3619
+ const observer = new win.MutationObserver((records) => {
3620
+ if (closed) return;
3621
+ for (const record of records) {
3622
+ collect(record.target, record.type === "attributes");
3623
+ if (record.type !== "childList") continue;
3624
+ for (const node of record.addedNodes) collect(node, true);
3625
+ for (const node of record.removedNodes) {
3626
+ if (node.nodeType !== 1 || node.isConnected) continue;
3627
+ if (owned.has(node)) restore(node);
3628
+ for (const marked of node.querySelectorAll(`[${CHANNEL_ATTR}]`)) restore(marked);
3629
+ }
3630
+ }
3631
+ });
3632
+ observer.observe(doc.body, {
3633
+ subtree: true,
3634
+ childList: true,
3635
+ characterData: true,
3636
+ attributes: true,
3637
+ attributeFilter: ["class", "role", "aria-selected"]
3638
+ });
3639
+ const unsubscribe = channels?.subscribe?.(applyBadges);
3640
+ applyBadges();
3641
+ return () => {
3642
+ closed = true;
3643
+ observer.disconnect();
3644
+ unsubscribe?.();
3645
+ for (const image of images) {
3646
+ image.onload = null;
3647
+ image.src = "";
3648
+ }
3649
+ for (const element of [...owned.keys()]) restore(element);
3650
+ style.remove();
3651
+ };
3652
+ }
3653
+
3654
+ // packages/dsh-chat/client/section.js
3655
+ var React11 = __toESM(require("react"), 1);
3656
+
3657
+ // packages/dsh-chat/client/bot-list.js
3658
+ var React8 = __toESM(require("react"), 1);
3659
+
3660
+ // packages/dsh-chat/client/list-order.js
3661
+ var React7 = __toESM(require("react"), 1);
3662
+ var PREFIX = "dsh-chat:order:";
3663
+ var CHANNEL_ORDER_KEY = `${PREFIX}channels`;
3664
+ function botOrderKey(channelId) {
3665
+ return `${PREFIX}bots:${channelId}`;
3666
+ }
3667
+ function storageOf(storage) {
3668
+ if (storage) return storage;
3669
+ try {
3670
+ return globalThis.localStorage ?? null;
3671
+ } catch {
3672
+ return null;
3673
+ }
3674
+ }
3675
+ function readOrder(key, storage = null) {
3676
+ const store = storageOf(storage);
3677
+ if (!store || typeof store.getItem !== "function") return [];
3678
+ try {
3679
+ const raw = store.getItem(key);
3680
+ if (!raw) return [];
3681
+ const parsed = JSON.parse(raw);
3682
+ return Array.isArray(parsed) ? parsed.filter((item) => typeof item === "string" && item) : [];
3683
+ } catch {
3684
+ return [];
3685
+ }
3686
+ }
3687
+ function writeOrder(key, keys, storage = null) {
3688
+ const store = storageOf(storage);
3689
+ if (!store || typeof store.setItem !== "function") return false;
3690
+ try {
3691
+ store.setItem(key, JSON.stringify([...keys]));
3692
+ return true;
3693
+ } catch {
3694
+ return false;
3695
+ }
3696
+ }
3697
+ function orderedItems(items, order, keyOf) {
3698
+ const list = Array.isArray(items) ? items : [];
3699
+ if (!Array.isArray(order) || order.length === 0) return [...list];
3700
+ const rank = /* @__PURE__ */ new Map();
3701
+ order.forEach((key, index) => rank.set(key, index));
3702
+ return [...list].sort((left, right) => {
3703
+ const a = rank.has(keyOf(left)) ? rank.get(keyOf(left)) : Number.MAX_SAFE_INTEGER;
3704
+ const b = rank.has(keyOf(right)) ? rank.get(keyOf(right)) : Number.MAX_SAFE_INTEGER;
3705
+ return a - b;
3706
+ });
3707
+ }
3708
+ function moveKey(keys, fromKey, toKey) {
3709
+ const list = Array.isArray(keys) ? [...keys] : [];
3710
+ const from = list.indexOf(fromKey);
3711
+ const to = list.indexOf(toKey);
3712
+ if (from < 0 || to < 0 || from === to) return list;
3713
+ list.splice(from, 1);
3714
+ list.splice(to, 0, fromKey);
3715
+ return list;
3716
+ }
3717
+ function useListOrder(key, keyOf) {
3718
+ const [order, setOrder] = React7.useState(() => readOrder(key));
3719
+ React7.useEffect(() => {
3720
+ setOrder(readOrder(key));
3721
+ }, [key]);
3722
+ const move = React7.useCallback((items, fromKey, toKey) => {
3723
+ const current = (Array.isArray(items) ? items : []).map(keyOf);
3724
+ const next = moveKey(current, fromKey, toKey);
3725
+ setOrder(next);
3726
+ writeOrder(key, next);
3727
+ return next;
3728
+ }, [key, keyOf]);
3729
+ const reset = React7.useCallback(() => {
3730
+ setOrder([]);
3731
+ writeOrder(key, []);
3732
+ }, [key]);
3733
+ return { order, move, reset };
3734
+ }
3735
+
3736
+ // packages/dsh-chat/client/bot-list.js
3737
+ var h6 = React8.createElement;
3738
+ var STATE_TEXT = Object.freeze({
3739
+ running: "\u8FD0\u884C\u6B63\u5E38",
3740
+ starting: "\u6B63\u5728\u542F\u52A8",
3741
+ reconnecting: "\u91CD\u8FDE\u4E2D",
3742
+ failed: "\u542F\u52A8\u5931\u8D25",
3743
+ stopped: "\u5DF2\u505C\u6B62"
3744
+ });
3745
+ var TONES2 = Object.freeze({
3746
+ running: "success",
3747
+ starting: "warning",
3748
+ reconnecting: "warning",
3749
+ failed: "error"
3750
+ });
3751
+ function normalizeBots(value) {
3752
+ if (Array.isArray(value?.bots)) return value.bots;
3753
+ if (Array.isArray(value?.accounts)) return value.accounts;
3754
+ return [];
3755
+ }
3756
+ function botKeyOf(bot) {
3757
+ if (!bot || typeof bot !== "object") return null;
3758
+ const key = bot.botId ?? bot.id ?? null;
3759
+ return typeof key === "string" && key.length > 0 ? key : null;
3760
+ }
3761
+ function formatTime(value) {
3762
+ if (!value) return "\u2014";
3763
+ const time = new Date(value);
3764
+ if (Number.isNaN(time.getTime())) return "\u2014";
3765
+ const pad = (number) => String(number).padStart(2, "0");
3766
+ return `${pad(time.getMonth() + 1)}-${pad(time.getDate())} ${pad(time.getHours())}:${pad(time.getMinutes())}`;
3767
+ }
3768
+ function BotList(props) {
3769
+ const {
3770
+ channelId,
3771
+ label,
3772
+ note,
3773
+ connection,
3774
+ chatUi,
3775
+ translate,
3776
+ t: frameworkT,
3777
+ onOpenSettings,
3778
+ setup = null
3779
+ } = props;
3780
+ const t = typeof translate === "function" ? translate : typeof frameworkT === "function" ? frameworkT : (key) => key;
3781
+ const setupLabel = typeof setup?.label === "string" && setup.label.trim() ? setup.label.trim() : null;
3782
+ const setupHint = typeof setup?.hint === "string" && setup.hint.trim() ? setup.hint.trim() : t("\u5728\u6E20\u9053\u81EA\u5DF1\u7684\u914D\u7F6E\u91CC\u5B8C\u6210\u63A5\u5165\u540E\uFF0C\u673A\u5668\u4EBA\u4F1A\u51FA\u73B0\u5728\u8FD9\u91CC\u3002");
3783
+ const [state, setState] = React8.useState({ phase: "loading", bots: [], error: null });
3784
+ const load = React8.useCallback(() => {
3785
+ setState((current) => ({ ...current, phase: "loading", error: null }));
3786
+ chatUi.callChannelRpc(connection, channelId, "connection.status", {}).then((result) => {
3787
+ setState({ phase: "ready", bots: normalizeBots(chatUi.unwrapRpc(result)), error: null });
3788
+ }).catch((error) => {
3789
+ setState({ phase: "error", bots: [], error: error?.message ?? String(error) });
3790
+ });
3791
+ }, [channelId, chatUi, connection]);
3792
+ React8.useEffect(() => {
3793
+ load();
3794
+ }, [load]);
3795
+ const { Panel: Panel2, EmptyState: EmptyState2, StatusPill: StatusPill2 } = chatUi.components;
3796
+ const botOrder = useListOrder(botOrderKey(channelId), (row) => botKeyOf(row.bot));
3797
+ const rows = React8.useMemo(
3798
+ () => orderedItems(
3799
+ state.bots.map((bot, index) => ({ bot, fallback: `row-${index}` })),
3800
+ botOrder.order,
3801
+ (row) => botKeyOf(row.bot) ?? row.fallback
3802
+ ),
3803
+ [state.bots, botOrder.order]
3804
+ );
3805
+ const dragBotRef = React8.useRef(null);
3806
+ const [dragBot, setDragBot] = React8.useState(null);
3807
+ const [dropBot, setDropBot] = React8.useState(null);
3808
+ return h6(
3809
+ Panel2,
3810
+ {
3811
+ title: `${label()} \xB7 ${t("\u673A\u5668\u4EBA")}`,
3812
+ description: note || null,
3813
+ actions: h6(
3814
+ "div",
3815
+ { className: "dchat-actions" },
3816
+ /**
3817
+ * 渠道设置入口**只在渠道声明了名称时**显示。
3818
+ *
3819
+ * 真机反馈:飞书那个入口点进去跟"机器人设置"几乎一样(渠道级只有一行 dataDir,
3820
+ * 而 dataDir 在诊断/版本面板里、读取状态就是右边的「重新读取」)——那就不该有它。
3821
+ * 微信的入口就是「扫码接入」,名称与说明都由渠道给(hub 不认识这些语义)。
3822
+ */
3823
+ setupLabel ? h6("button", {
3824
+ type: "button",
3825
+ className: "dchat-button dchat-buttonLink",
3826
+ onClick: () => onOpenSettings(null)
3827
+ }, t(setupLabel)) : null,
3828
+ h6("button", {
3829
+ type: "button",
3830
+ className: "dchat-button",
3831
+ onClick: load,
3832
+ disabled: state.phase === "loading"
3833
+ }, state.phase === "loading" ? t("\u8BFB\u53D6\u4E2D\u2026") : t("\u91CD\u65B0\u8BFB\u53D6"))
3834
+ )
3835
+ },
3836
+ state.error ? h6("p", { className: "dchat-error" }, `${t("\u8BFB\u53D6\u5931\u8D25")}\uFF1A${state.error}`) : null,
3837
+ state.phase !== "loading" && state.bots.length === 0 ? h6(EmptyState2, {
3838
+ title: t("\u8FD9\u4E2A\u6E20\u9053\u8FD8\u6CA1\u6709\u673A\u5668\u4EBA"),
3839
+ description: t(setupHint)
3840
+ }, setupLabel ? h6("button", {
3841
+ type: "button",
3842
+ className: "dchat-button",
3843
+ onClick: () => onOpenSettings(null)
3844
+ }, t(setupLabel)) : null) : null,
3845
+ state.bots.length > 0 ? h6("ul", { className: "dchat-botList" }, rows.map((row) => {
3846
+ const { bot } = row;
3847
+ const identity = botKeyOf(bot);
3848
+ const rowKey = identity ?? row.fallback;
3849
+ const title = bot.name || identity || t("\u672A\u547D\u540D\u673A\u5668\u4EBA");
3850
+ const showIdentity = Boolean(identity) && identity !== title;
3851
+ return h6(
3852
+ "li",
3853
+ {
3854
+ key: rowKey,
3855
+ className: `dchat-botRow${dropBot === rowKey && dragBot !== rowKey ? " dchat-dropTarget" : ""}`,
3856
+ onDragOver: (event) => {
3857
+ const from = dragBotRef.current;
3858
+ if (!from || from === rowKey) return;
3859
+ event.preventDefault();
3860
+ setDropBot(rowKey);
3861
+ },
3862
+ onDrop: (event) => {
3863
+ event.preventDefault();
3864
+ const from = dragBotRef.current;
3865
+ if (from && from !== rowKey) botOrder.move(rows, from, rowKey);
3866
+ dragBotRef.current = null;
3867
+ setDropBot(null);
3868
+ setDragBot(null);
3869
+ }
3870
+ },
3871
+ h6("span", {
3872
+ className: "dchat-grip",
3873
+ draggable: true,
3874
+ title: t("\u62D6\u52A8\u53EF\u8C03\u6574\u987A\u5E8F"),
3875
+ "aria-hidden": "true",
3876
+ onDragStart: (event) => {
3877
+ dragBotRef.current = rowKey;
3878
+ setDragBot(rowKey);
3879
+ event.dataTransfer?.setData("text/plain", rowKey);
3880
+ if (event.dataTransfer) event.dataTransfer.effectAllowed = "move";
3881
+ },
3882
+ onDragEnd: () => {
3883
+ dragBotRef.current = null;
3884
+ setDragBot(null);
3885
+ setDropBot(null);
3886
+ }
3887
+ }, "\u22EE\u22EE"),
3888
+ h6(
3889
+ "div",
3890
+ { className: "dchat-botMain" },
3891
+ h6(
3892
+ "div",
3893
+ { className: "dchat-botTitle" },
3894
+ h6("strong", { title }, title),
3895
+ h6(StatusPill2, { status: bot.state, label: t(STATE_TEXT[bot.state] ?? "\u5DF2\u505C\u6B62") })
3896
+ ),
3897
+ h6(
3898
+ "div",
3899
+ { className: "dchat-botMeta" },
3900
+ showIdentity ? h6("span", { className: "dchat-code" }, identity) : null,
3901
+ h6("span", null, `${t("\u5DF2\u5904\u7406")} ${bot.handled ?? 0}`),
3902
+ h6("span", null, `${t("\u6700\u8FD1")} ${formatTime(bot.lastHandledAt)}`)
3903
+ ),
3904
+ bot.errorMessage || bot.lastError ? h6("div", { className: "dchat-botError" }, bot.errorMessage ?? bot.lastError) : null
3905
+ ),
3906
+ h6("button", {
3907
+ type: "button",
3908
+ className: "dchat-button",
3909
+ // 身份取不到就不能进"这台机器人的设置"——那会静默变成"整个渠道的设置"。
3910
+ disabled: identity === null,
3911
+ title: identity ?? t("\u8FD9\u53F0\u673A\u5668\u4EBA\u6CA1\u6709\u53EF\u7528\u7684\u8EAB\u4EFD\u6807\u8BC6\uFF0C\u65E0\u6CD5\u5355\u72EC\u914D\u7F6E"),
3912
+ onClick: () => onOpenSettings(identity)
3913
+ }, t("\u8BBE\u7F6E"))
3914
+ );
3915
+ })) : null
3916
+ );
3917
+ }
3918
+
3919
+ // packages/dsh-chat/client/diagnostics.js
3920
+ var React9 = __toESM(require("react"), 1);
3921
+ var h7 = React9.createElement;
3922
+ var STATE_TEXT2 = Object.freeze({
3923
+ running: "\u8FD0\u884C\u4E2D",
3924
+ starting: "\u542F\u52A8\u4E2D",
3925
+ stopped: "\u5DF2\u505C\u6B62",
3926
+ failed: "\u542F\u52A8\u5931\u8D25"
3927
+ });
3928
+ function formatSize(bytes) {
3929
+ if (typeof bytes !== "number" || bytes <= 0) return "0 B";
3930
+ if (bytes < 1024) return `${bytes} B`;
3931
+ return `${(bytes / 1024).toFixed(1)} KB`;
3932
+ }
3933
+ function formatTime2(iso) {
3934
+ if (typeof iso !== "string" || !iso) return "\u2014";
3935
+ const date = new Date(iso);
3936
+ if (Number.isNaN(date.getTime())) return iso;
3937
+ const pad = (value) => String(value).padStart(2, "0");
3938
+ return `${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;
3939
+ }
3940
+ function DiagnosticsPanel(props) {
3941
+ const { connection, chatUi, translate, t: frameworkT } = props;
3942
+ const t = typeof translate === "function" ? translate : typeof frameworkT === "function" ? frameworkT : (key) => key;
3943
+ const [state, setState] = React9.useState({ loading: true, error: null, info: null });
3944
+ const [openLog, setOpenLog] = React9.useState(null);
3945
+ const load = React9.useCallback(() => {
3946
+ setState((current) => ({ ...current, loading: true, error: null }));
3947
+ chatUi.callControlRpc(connection, "diagnostics.read", {}).then((result) => {
3948
+ setState({ loading: false, error: null, info: chatUi.unwrapRpc(result) });
3949
+ }).catch((error) => {
3950
+ setState({ loading: false, error: error?.message ?? String(error), info: null });
3951
+ });
3952
+ }, [chatUi, connection]);
3953
+ React9.useEffect(() => {
3954
+ load();
3955
+ }, [load]);
3956
+ const Panel2 = chatUi.components.Panel;
3957
+ const StatusPill2 = chatUi.components.StatusPill;
3958
+ const info = state.info;
3959
+ const statusLabel = (channel) => {
3960
+ if (channel.status === "running") return t("\u6E20\u9053\u5DF2\u5C31\u7EEA");
3961
+ if (channel.status === "failed") return t("\u6E20\u9053\u542F\u52A8\u5931\u8D25");
3962
+ if (channel.status === "stopped") return t("\u6E20\u9053\u5DF2\u505C\u6B62");
3963
+ return t("\u6E20\u9053\u6B63\u5728\u542F\u52A8");
3964
+ };
3965
+ const botRow = (bot) => h7(
3966
+ "li",
3967
+ { key: bot.id, className: "dchat-diagBot" },
3968
+ // 一行放不下就整块换行:id 会省略号收缩,右侧元信息不拆字。
3969
+ h7(
3970
+ "div",
3971
+ { className: "dchat-listItem dchat-diagRow" },
3972
+ h7("span", { className: "dchat-code" }, bot.id),
3973
+ h7(
3974
+ "span",
3975
+ { className: "dchat-diagMeta" },
3976
+ `${STATE_TEXT2[bot.state] ? t(STATE_TEXT2[bot.state]) : bot.state ?? "\u2014"} \xB7 ${bot.connected ? t("\u5DF2\u8FDE\u63A5") : t("\u672A\u8FDE\u63A5")} \xB7 ${t("\u5DF2\u5904\u7406")} ${bot.handled ?? 0}` + (bot.lastHandledAt ? ` \xB7 ${formatTime2(bot.lastHandledAt)}` : "")
3977
+ )
3978
+ ),
3979
+ // 失败必须可见:连接错误、最近一次处理错误、名字拿不到(多为缺权限,带开通链接)。
3980
+ bot.errorMessage ? h7("p", { className: "dchat-error", role: "alert" }, bot.errorMessage) : null,
3981
+ bot.lastError ? h7("p", { className: "dchat-error", role: "alert" }, `${t("\u6700\u8FD1\u4E00\u6B21\u9519\u8BEF")}\uFF1A${bot.lastError}`) : null,
3982
+ bot.nameHint ? h7(
3983
+ "p",
3984
+ { className: "dchat-cardDescription" },
3985
+ `${bot.nameHint.message} `,
3986
+ bot.nameHint.url ? h7("a", { href: bot.nameHint.url, target: "_blank", rel: "noreferrer" }, t("\u53BB\u5F00\u901A\u6743\u9650")) : null
3987
+ ) : null
3988
+ );
3989
+ return h7(
3990
+ Panel2,
3991
+ {
3992
+ title: t("\u8BCA\u65AD"),
3993
+ description: t("\u51FA\u6545\u969C\u65F6\u5148\u770B\u8FD9\u91CC\uFF1A\u8FDE\u63A5\u72B6\u6001\u3001\u6700\u8FD1\u9519\u8BEF\u3001\u65E5\u5FD7\u5C3E\u90E8\u3002"),
3994
+ actions: h7("button", {
3995
+ type: "button",
3996
+ className: "dchat-button",
3997
+ onClick: load,
3998
+ disabled: state.loading
3999
+ }, state.loading ? t("\u8BFB\u53D6\u4E2D\u2026") : t("\u91CD\u65B0\u8BFB\u53D6"))
4000
+ },
4001
+ state.error ? h7("p", { className: "dchat-error" }, `${t("\u8BFB\u53D6\u5931\u8D25")}\uFF1A${state.error}`) : null,
4002
+ ...(info?.channels ?? []).map((channel) => h7(
4003
+ "div",
4004
+ {
4005
+ key: channel.id,
4006
+ className: "dchat-diagSection"
4007
+ },
4008
+ h7(
4009
+ "div",
4010
+ { className: "dchat-diagHead" },
4011
+ h7("span", { className: "dchat-groupTitle" }, `${channel.label} \xB7 ${channel.version ?? "\u2014"}`),
4012
+ h7(StatusPill2, { status: channel.status, label: statusLabel(channel) })
4013
+ ),
4014
+ channel.statusError ? h7("p", { className: "dchat-error", role: "alert" }, channel.statusError) : null,
4015
+ channel.bots.length === 0 ? h7("p", { className: "dchat-cardDescription" }, t("\u8FD9\u53F0\u6E20\u9053\u4E0B\u8FD8\u6CA1\u6709\u673A\u5668\u4EBA\u3002")) : h7("ul", { className: "dchat-list" }, ...channel.bots.map(botRow))
4016
+ )),
4017
+ info ? h7(
4018
+ "ul",
4019
+ { className: "dchat-list" },
4020
+ h7(
4021
+ "li",
4022
+ { className: "dchat-listItem" },
4023
+ h7("span", null, t("\u6570\u636E\u76EE\u5F55")),
4024
+ h7("code", { className: "dchat-code" }, info.dataDir ?? "\u2014")
4025
+ ),
4026
+ h7(
4027
+ "li",
4028
+ { className: "dchat-listItem" },
4029
+ h7("span", null, t("\u65E5\u5FD7\u76EE\u5F55")),
4030
+ h7("code", { className: "dchat-code" }, info.logDir ?? "\u2014")
4031
+ )
4032
+ ) : null,
4033
+ ...(info?.logs ?? []).map((log) => {
4034
+ const name2 = String(log.path ?? "").split("/").pop();
4035
+ const open = openLog === log.path;
4036
+ return h7(
4037
+ "div",
4038
+ { key: log.path, className: "dchat-diagSection" },
4039
+ // 与机器人行同构:文件名 + 大小时间一行,展开按钮单独一行(窄栏下挤不下)。
4040
+ h7(
4041
+ "div",
4042
+ { className: "dchat-diagBot" },
4043
+ h7(
4044
+ "div",
4045
+ { className: "dchat-listItem dchat-diagRow" },
4046
+ h7("span", { className: "dchat-code" }, name2),
4047
+ h7(
4048
+ "span",
4049
+ { className: "dchat-diagMeta" },
4050
+ log.exists ? `${formatSize(log.size)} \xB7 ${formatTime2(log.modifiedAt)}` : t("\u8FD8\u6CA1\u6709\u65E5\u5FD7")
4051
+ )
4052
+ ),
4053
+ h7(
4054
+ "div",
4055
+ { className: "dchat-actions" },
4056
+ h7("button", {
4057
+ type: "button",
4058
+ className: "dchat-button dchat-buttonLink",
4059
+ disabled: !log.exists,
4060
+ "aria-expanded": open,
4061
+ onClick: () => setOpenLog(open ? null : log.path)
4062
+ }, open ? t("\u6536\u8D77") : t("\u770B\u6700\u540E 40 \u884C"))
4063
+ )
4064
+ ),
4065
+ open ? h7("pre", { className: "dchat-code dchat-codeBlock dchat-logTail" }, log.lines.join("\n")) : null
4066
+ );
4067
+ })
4068
+ );
4069
+ }
4070
+
4071
+ // packages/dsh-chat/client/version-panel.js
4072
+ var React10 = __toESM(require("react"), 1);
4073
+ var h8 = React10.createElement;
4074
+ var CHANNEL_PACKAGE_HINTS = Object.freeze({
4075
+ feishu: "dsh-chat-feishu",
4076
+ weixin: "dsh-chat-weixin"
4077
+ });
4078
+ function VersionPanel(props) {
4079
+ const { connection, chatUi, translate, t: frameworkT } = props;
4080
+ const t = typeof translate === "function" ? translate : typeof frameworkT === "function" ? frameworkT : (key) => key;
4081
+ const [state, setState] = React10.useState({ loading: true, error: null, info: null });
4082
+ const load = React10.useCallback(() => {
4083
+ setState((current) => ({ ...current, loading: true, error: null }));
4084
+ chatUi.callControlRpc(connection, "channel.list", {}).then((result) => {
4085
+ setState({ loading: false, error: null, info: chatUi.unwrapRpc(result) });
4086
+ }).catch((error) => {
4087
+ setState({ loading: false, error: error?.message ?? String(error), info: null });
4088
+ });
4089
+ }, [chatUi, connection]);
4090
+ React10.useEffect(() => {
4091
+ load();
4092
+ }, [load]);
4093
+ const Panel2 = chatUi.components.Panel;
4094
+ const StatusPill2 = chatUi.components.StatusPill;
4095
+ const info = state.info;
4096
+ return h8(
4097
+ Panel2,
4098
+ {
4099
+ title: t("\u7248\u672C\u4E0E\u66F4\u65B0"),
4100
+ description: t("\u5347\u7EA7\u63D2\u4EF6\u540E\u9700\u8981\u91CD\u542F dsh\uFF1B\u53EA\u6539\u8BBE\u7F6E\u9875\u4EE3\u7801\u5219\u5237\u65B0\u9875\u9762\u5373\u53EF\u3002"),
4101
+ actions: h8("button", {
4102
+ type: "button",
4103
+ className: "dchat-button",
4104
+ onClick: load,
4105
+ disabled: state.loading
4106
+ }, state.loading ? t("\u8BFB\u53D6\u4E2D\u2026") : t("\u91CD\u65B0\u8BFB\u53D6"))
4107
+ },
4108
+ state.error ? h8("p", { className: "dchat-error" }, `${t("\u8BFB\u53D6\u5931\u8D25")}\uFF1A${state.error}`) : null,
4109
+ h8(
4110
+ "ul",
4111
+ { className: "dchat-list" },
4112
+ h8(
4113
+ "li",
4114
+ { className: "dchat-listItem" },
4115
+ h8("span", null, t("Chat\u673A\u5668\u4EBA\u5185\u6838")),
4116
+ h8(
4117
+ "code",
4118
+ { className: "dchat-code" },
4119
+ `${info?.hubPackage ?? "dsh-chat"} ${info?.hubVersion ?? "\u2026"}`
4120
+ )
4121
+ ),
4122
+ h8(
4123
+ "li",
4124
+ { className: "dchat-listItem" },
4125
+ h8("span", null, t("\u6E20\u9053\u5951\u7EA6\u7248\u672C")),
4126
+ h8("code", { className: "dchat-code" }, `v${info?.contractVersion ?? "\u2026"}`)
4127
+ ),
4128
+ ...(info?.channels ?? []).map((channel) => h8(
4129
+ "li",
4130
+ {
4131
+ key: channel.id,
4132
+ className: "dchat-listItem"
4133
+ },
4134
+ h8("span", null, `${channel.label} \xB7 ${CHANNEL_PACKAGE_HINTS[channel.id] ?? channel.id}`),
4135
+ h8(
4136
+ "span",
4137
+ { className: "dchat-versionMeta" },
4138
+ h8("code", { className: "dchat-code" }, channel.version ?? "\u2014"),
4139
+ h8(StatusPill2, {
4140
+ status: channel.status,
4141
+ label: channel.status === "running" ? t("\u6E20\u9053\u5DF2\u5C31\u7EEA") : channel.error ? t("\u6E20\u9053\u542F\u52A8\u5931\u8D25") : t("\u6E20\u9053\u6B63\u5728\u542F\u52A8")
4142
+ })
4143
+ )
4144
+ ))
4145
+ ),
4146
+ info?.dataDir ? h8(
4147
+ "ul",
4148
+ { className: "dchat-list" },
4149
+ h8(
4150
+ "li",
4151
+ { className: "dchat-listItem" },
4152
+ h8("span", null, t("\u6570\u636E\u76EE\u5F55")),
4153
+ h8("code", { className: "dchat-code" }, info.dataDir)
4154
+ ),
4155
+ h8(
4156
+ "li",
4157
+ { className: "dchat-listItem" },
4158
+ h8("span", null, t("\u65E5\u5FD7\u76EE\u5F55")),
4159
+ h8("code", { className: "dchat-code" }, info.logDir)
4160
+ )
4161
+ ) : null,
4162
+ h8(
4163
+ "div",
4164
+ { className: "dchat-updateHint" },
4165
+ h8("p", { className: "dchat-cardDescription" }, t("\u66F4\u65B0\u65B9\u5F0F\uFF1A\u5728\u4ED3\u5E93\u91CC\u62C9\u53D6\u65B0\u4EE3\u7801\u540E\u91CD\u65B0\u6253\u5305\uFF0C\u518D\u8BA9 DSH \u91CD\u65B0\u52A0\u8F7D\u63D2\u4EF6\u3002")),
4166
+ h8("code", { className: "dchat-code dchat-codeBlock" }, "npm run check"),
4167
+ h8(
4168
+ "code",
4169
+ { className: "dchat-code dchat-codeBlock" },
4170
+ "dsh plugin --profile web add <\u672C\u4ED3\u5E93 packages/dsh-chat \u7684\u7EDD\u5BF9\u8DEF\u5F84>"
4171
+ )
4172
+ )
4173
+ );
4174
+ }
4175
+
4176
+ // packages/dsh-chat/client/section.js
4177
+ var h9 = React11.createElement;
4178
+ var KNOWN_CHANNEL_PACKAGES = Object.freeze([
4179
+ "dsh-chat-feishu",
4180
+ "dsh-chat-weixin"
4181
+ ]);
4182
+ function ChannelMark({ entry }) {
4183
+ const iconUri = channelIconUri(entry.icon);
4184
+ if (iconUri) {
4185
+ return h9("span", {
4186
+ // 有真图标就不套那个"字母块"的边框与底色,让它看起来就是应用图标。
4187
+ className: "dchat-channelMark dchat-channelMarkIcon",
4188
+ "aria-hidden": "true"
4189
+ }, h9("img", { src: iconUri, alt: "", width: 20, height: 20 }));
4190
+ }
4191
+ if (typeof entry.logo === "function") {
4192
+ return h9("span", { className: "dchat-channelMark", "aria-hidden": "true" }, h9(entry.logo));
4193
+ }
4194
+ const initial = entry.id.slice(0, 1).toUpperCase();
4195
+ return h9("span", { className: "dchat-channelMark", "aria-hidden": "true" }, initial);
4196
+ }
4197
+ function ChatSettingsSection(props) {
4198
+ const { channels, chatUi, translate, t: frameworkT, renderSlot, connection } = props;
4199
+ const [showVersions, setShowVersions] = React11.useState(false);
4200
+ const [showDiagnostics, setShowDiagnostics] = React11.useState(false);
4201
+ const [view, setView] = React11.useState({ kind: "bots", botId: null });
4202
+ const t = typeof translate === "function" ? translate : typeof frameworkT === "function" ? frameworkT : (key) => key;
4203
+ const entries = React11.useSyncExternalStore(
4204
+ (onChange) => channels.subscribe(onChange),
4205
+ () => channels.getSnapshot(),
4206
+ () => channels.getSnapshot()
4207
+ );
4208
+ const channelOrder = useListOrder(CHANNEL_ORDER_KEY, (entry) => entry?.id);
4209
+ const orderedEntries = React11.useMemo(
4210
+ () => orderedItems(entries, channelOrder.order, (entry) => entry?.id),
4211
+ [entries, channelOrder.order]
4212
+ );
4213
+ const dragChannelRef = React11.useRef(null);
4214
+ const [dragChannel, setDragChannel] = React11.useState(null);
4215
+ const [dropChannel, setDropChannel] = React11.useState(null);
4216
+ const [selected, setSelected] = React11.useState(null);
4217
+ const activeId = entries.some((entry) => entry.id === selected) ? selected : orderedEntries[0]?.id ?? null;
4218
+ const activeEntry = entries.find((entry) => entry.id === activeId) ?? null;
4219
+ const openSettings = (botId) => setView({ kind: "channel", botId });
4220
+ const backToBots = () => setView({ kind: "bots", botId: null });
4221
+ const EmptyState2 = chatUi?.components?.EmptyState;
4222
+ function botListView() {
4223
+ if (!activeEntry) return null;
4224
+ return h9(BotList, {
4225
+ key: activeEntry.id,
4226
+ channelId: activeEntry.id,
4227
+ label: activeEntry.label,
4228
+ // 渠道能力说明(如「仅私聊」)放右栏标题下:左栏只留"图标 + 渠道名",形态才整齐。
4229
+ note: activeEntry.capabilities?.note ?? null,
4230
+ // 渠道级设置入口:`setup.label` 有才显示(飞书没有渠道级表单,微信是「扫码接入」)。
4231
+ setup: activeEntry.capabilities?.setup ?? null,
4232
+ connection,
4233
+ chatUi,
4234
+ translate: t,
4235
+ onOpenSettings: openSettings
4236
+ });
4237
+ }
4238
+ function channelView() {
4239
+ return h9(
4240
+ React11.Fragment,
4241
+ null,
4242
+ typeof renderSlot === "function" ? renderSlot(
4243
+ CHANNEL_PAGE_SLOT,
4244
+ { channelId: activeId, botId: view.botId },
4245
+ { entryKey: activeId }
4246
+ ) : h9("p", { className: "dchat-cardDescription" }, t("\u5F53\u524D\u9875\u9762\u4E0D\u652F\u6301\u6E20\u9053\u5B50\u69FD\u3002"))
4247
+ );
4248
+ }
4249
+ function backBar() {
4250
+ return h9(
4251
+ "div",
4252
+ { className: "dchat-panelBar" },
4253
+ h9("button", {
4254
+ type: "button",
4255
+ className: "dchat-button",
4256
+ onClick: backToBots
4257
+ }, t("\u2190 \u673A\u5668\u4EBA\u5217\u8868"))
4258
+ );
4259
+ }
4260
+ let body = null;
4261
+ if (entries.length === 0) {
4262
+ body = EmptyState2 ? h9(EmptyState2, {
4263
+ title: t("\u672A\u5B89\u88C5\u4EFB\u4F55\u804A\u5929\u8F6F\u4EF6\u63D2\u4EF6"),
4264
+ description: t("\u5B89\u88C5\u6E20\u9053\u63D2\u4EF6\u540E\uFF0C\u8FD9\u91CC\u4F1A\u51FA\u73B0\u5BF9\u5E94\u7684\u804A\u5929\u8F6F\u4EF6\u3002")
4265
+ }, h9(
4266
+ "ul",
4267
+ { className: "dchat-list" },
4268
+ h9("li", { className: "dchat-listItem" }, t("\u5DF2\u77E5\u6E20\u9053\u63D2\u4EF6")),
4269
+ ...KNOWN_CHANNEL_PACKAGES.map((name2) => h9("li", {
4270
+ key: name2,
4271
+ className: "dchat-listItem"
4272
+ }, h9("code", { className: "dchat-code" }, `dsh plugin --profile web add ${name2}`)))
4273
+ )) : null;
4274
+ } else if (view.kind !== "bots") {
4275
+ body = h9("div", { className: "dchat-solo" }, backBar(), channelView());
4276
+ } else {
4277
+ body = h9(
4278
+ "div",
4279
+ { className: "dchat-layout" },
4280
+ h9(
4281
+ "nav",
4282
+ { className: "dchat-rail", role: "tablist", "aria-label": t("\u6E20\u9053\u5BFC\u822A") },
4283
+ orderedEntries.map((entry) => h9(
4284
+ "button",
4285
+ {
4286
+ key: entry.id,
4287
+ type: "button",
4288
+ role: "tab",
4289
+ id: `dchat-tab-${entry.id}`,
4290
+ className: `dchat-channel${dropChannel === entry.id && dragChannel !== entry.id ? " dchat-dropTarget" : ""}`,
4291
+ "aria-selected": entry.id === activeId,
4292
+ "aria-controls": `dchat-panel-${entry.id}`,
4293
+ onClick: () => {
4294
+ setSelected(entry.id);
4295
+ backToBots();
4296
+ },
4297
+ // 拖动排序:把手是那个 grip(button 自己 draggable 在部分浏览器上不灵,
4298
+ // 而且整行可拖会与"点一下切换渠道"抢手势)。
4299
+ onDragOver: (event) => {
4300
+ const from = dragChannelRef.current;
4301
+ if (!from || from === entry.id) return;
4302
+ event.preventDefault();
4303
+ setDropChannel(entry.id);
4304
+ },
4305
+ onDrop: (event) => {
4306
+ event.preventDefault();
4307
+ const from = dragChannelRef.current;
4308
+ if (from && from !== entry.id) channelOrder.move(orderedEntries, from, entry.id);
4309
+ dragChannelRef.current = null;
4310
+ setDropChannel(null);
4311
+ setDragChannel(null);
4312
+ }
4313
+ },
4314
+ h9("span", {
4315
+ className: "dchat-grip",
4316
+ draggable: true,
4317
+ title: t("\u62D6\u52A8\u53EF\u8C03\u6574\u987A\u5E8F"),
4318
+ "aria-hidden": "true",
4319
+ onDragStart: (event) => {
4320
+ dragChannelRef.current = entry.id;
4321
+ setDragChannel(entry.id);
4322
+ event.dataTransfer?.setData("text/plain", entry.id);
4323
+ if (event.dataTransfer) event.dataTransfer.effectAllowed = "move";
4324
+ },
4325
+ onDragEnd: () => {
4326
+ dragChannelRef.current = null;
4327
+ setDragChannel(null);
4328
+ setDropChannel(null);
4329
+ }
4330
+ }, "\u22EE\u22EE"),
4331
+ h9(ChannelMark, { entry }),
4332
+ h9(
4333
+ "span",
4334
+ { className: "dchat-channelLabel" },
4335
+ h9("strong", null, entry.label())
4336
+ )
4337
+ ))
4338
+ ),
4339
+ h9("main", {
4340
+ className: "dchat-panel",
4341
+ role: "tabpanel",
4342
+ id: `dchat-panel-${activeId}`,
4343
+ "aria-labelledby": `dchat-tab-${activeId}`
4344
+ }, botListView())
4345
+ );
4346
+ }
4347
+ return h9(
4348
+ "section",
4349
+ { className: "dchat-page", "aria-label": t("Chat\u673A\u5668\u4EBA\u8BBE\u7F6E") },
4350
+ h9(
4351
+ "header",
4352
+ { className: "dchat-header" },
4353
+ h9(
4354
+ "div",
4355
+ { className: "dchat-brand" },
4356
+ h9("strong", { className: "dchat-brandName" }, "DSH-Chat"),
4357
+ h9("span", { className: "dchat-brandHint" }, t("Chat\u673A\u5668\u4EBA"))
4358
+ ),
4359
+ // 右上角入口:版本与更新 / 诊断(展开后是同一块面板,收起时不请求数据)。
4360
+ // 用文字链接形态,避免和 DSH 自己的实心按钮(打开配置文件)平级抢注意力。
4361
+ h9(
4362
+ "div",
4363
+ { className: "dchat-headerActions" },
4364
+ h9("button", {
4365
+ type: "button",
4366
+ className: "dchat-button dchat-buttonLink",
4367
+ "aria-expanded": showDiagnostics,
4368
+ onClick: () => setShowDiagnostics((open) => !open)
4369
+ }, showDiagnostics ? t("\u6536\u8D77\u8BCA\u65AD") : t("\u8BCA\u65AD")),
4370
+ h9("button", {
4371
+ type: "button",
4372
+ className: "dchat-button dchat-buttonLink",
4373
+ "aria-expanded": showVersions,
4374
+ onClick: () => setShowVersions((open) => !open)
4375
+ }, showVersions ? t("\u6536\u8D77\u7248\u672C\u4E0E\u66F4\u65B0") : t("\u7248\u672C\u4E0E\u66F4\u65B0"))
4376
+ )
4377
+ ),
4378
+ showDiagnostics ? h9(DiagnosticsPanel, { connection, chatUi, translate: t }) : null,
4379
+ showVersions ? h9(VersionPanel, { connection, chatUi, translate: t }) : null,
4380
+ body
4381
+ );
4382
+ }
4383
+
4384
+ // packages/dsh-chat/client/index.js
4385
+ var name = "dsh-chat-client";
4386
+ var inject = ["slots", "connection", "locale"];
4387
+ function provideService(ctx, serviceName, value) {
4388
+ if (typeof ctx?.reflect?.provide === "function") return ctx.reflect.provide(serviceName, value);
4389
+ if (typeof ctx?.provide === "function") return ctx.provide(serviceName, value);
4390
+ throw new TypeError(`dsh-chat \u9700\u8981 Cordis \u7684 provide \u80FD\u529B\u6765\u53D1\u5E03 ${serviceName} \u670D\u52A1\u3002`);
4391
+ }
4392
+ function apply(ctx) {
4393
+ ctx.effect(
4394
+ () => ctx.locale.register(LOCALE_NAMESPACE, { zh, en }),
4395
+ "dsh-chat: \u53CC\u8BED\u6587\u6848"
4396
+ );
4397
+ const t = typeof ctx.locale?.bind === "function" ? ctx.locale.bind(LOCALE_NAMESPACE) : bindTranslator(ctx.locale);
4398
+ const channels = createChannelRail();
4399
+ const chatUi = createChatUi({ ctx, translate: t });
4400
+ ctx.effect(
4401
+ () => provideService(ctx, CLIENT_CHANNEL_SERVICE, channels),
4402
+ "dsh-chat: \u6E20\u9053 rail \u670D\u52A1"
4403
+ );
4404
+ ctx.effect(
4405
+ () => provideService(ctx, CLIENT_UI_SERVICE, chatUi),
4406
+ "dsh-chat: \u5171\u4EAB UI \u5957\u4EF6"
4407
+ );
4408
+ ctx.effect(() => installChatStyles(), "dsh-chat: \u5171\u4EAB\u6837\u5F0F");
4409
+ ctx.effect(() => installSessionBadges({ channels }), "dsh-chat: \u4F1A\u8BDD\u6E20\u9053\u5FBD\u6807");
4410
+ ctx.slots.inject(SETTINGS_SECTION_SLOT, () => ctx.slots.register({
4411
+ name: SETTINGS_SECTION_SLOT,
4412
+ id: SETTINGS_SECTION_ID,
4413
+ order: SETTINGS_SECTION_ORDER,
4414
+ label: () => t(SETTINGS_LABEL_KEY),
4415
+ locale: LOCALE_NAMESPACE,
4416
+ inject: () => ({
4417
+ channels,
4418
+ chatUi,
4419
+ translate: t,
4420
+ contractVersion: CONTRACT_VERSION,
4421
+ connection: ctx.connection
4422
+ }),
4423
+ children: {
4424
+ [CHANNEL_PAGE_SLOT]: { kind: "keyed", scope: "root" }
4425
+ }
4426
+ }, ChatSettingsSection));
4427
+ }
4428
+
4429
+ return module.exports;
4430
+ }
4431
+ });